-
Notifications
You must be signed in to change notification settings - Fork 12
Fix assistant "out of credit" messaging due to stale credits data in the host app #4234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,10 +2,13 @@ import type { TemplateOnlyComponent } from '@ember/component/template-only'; | |||||||||||||
| import { registerDestructor } from '@ember/destroyable'; | ||||||||||||||
| import { hash } from '@ember/helper'; | ||||||||||||||
| import { action } from '@ember/object'; | ||||||||||||||
| import { scheduleOnce } from '@ember/runloop'; | ||||||||||||||
| import { service } from '@ember/service'; | ||||||||||||||
| import type { SafeString } from '@ember/template'; | ||||||||||||||
| import Component from '@glimmer/component'; | ||||||||||||||
|
|
||||||||||||||
| import { task } from 'ember-concurrency'; | ||||||||||||||
| import perform from 'ember-concurrency/helpers/perform'; | ||||||||||||||
| import Modifier from 'ember-modifier'; | ||||||||||||||
| import throttle from 'lodash/throttle'; | ||||||||||||||
|
|
||||||||||||||
|
|
@@ -45,6 +48,7 @@ interface Signature { | |||||||||||||
| isFromAssistant: boolean; | ||||||||||||||
| isStreaming: boolean; | ||||||||||||||
| isLastAssistantMessage: boolean; | ||||||||||||||
| isMostRecentMessage?: boolean; | ||||||||||||||
| userMessageThisMessageIsRespondingTo?: Message; | ||||||||||||||
| profileAvatar?: ComponentLike; | ||||||||||||||
| collectionResource?: ReturnType<getCardCollection>; | ||||||||||||||
|
|
@@ -64,6 +68,7 @@ interface Signature { | |||||||||||||
| element: HTMLElement; | ||||||||||||||
| }) => void; | ||||||||||||||
| errorMessage?: string; | ||||||||||||||
| reloadBillingData?: boolean; | ||||||||||||||
| isDebugMessage?: boolean; | ||||||||||||||
| isPending?: boolean; | ||||||||||||||
| retryAction?: () => void; | ||||||||||||||
|
|
@@ -234,6 +239,40 @@ class ScrollPosition extends Modifier<ScrollPositionSignature> { | |||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| interface ReloadBillingOnInsertSignature { | ||||||||||||||
| Args: { | ||||||||||||||
| Named: { | ||||||||||||||
| shouldReloadBillingData: boolean; | ||||||||||||||
| reload: () => void; | ||||||||||||||
| }; | ||||||||||||||
| }; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // In the future if we implement subscription to credit consumption, we can remove this modifier | ||||||||||||||
| // It's currently used to reload the billing data when an out of credits error message is shown so that we can | ||||||||||||||
| // conditionally display the "buy more credits" button, or "credits added" message + retry button | ||||||||||||||
| class ReloadBillingOnInsert extends Modifier<ReloadBillingOnInsertSignature> { | ||||||||||||||
| private hasReloaded = false; | ||||||||||||||
|
|
||||||||||||||
| private runReload(reload: () => void) { | ||||||||||||||
| reload(); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| modify( | ||||||||||||||
| _element: HTMLElement, | ||||||||||||||
| _positional: [], | ||||||||||||||
| { | ||||||||||||||
| shouldReloadBillingData, | ||||||||||||||
| reload, | ||||||||||||||
| }: ReloadBillingOnInsertSignature['Args']['Named'], | ||||||||||||||
| ) { | ||||||||||||||
| if (shouldReloadBillingData && !this.hasReloaded) { | ||||||||||||||
| this.hasReloaded = true; | ||||||||||||||
| scheduleOnce('afterRender', this, this.runReload, reload); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| function isThinkingMessage(s: string | null | undefined) { | ||||||||||||||
| if (!s) { | ||||||||||||||
| return false; | ||||||||||||||
|
|
@@ -328,6 +367,12 @@ export default class AiAssistantMessage extends Component<Signature> { | |||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| private reloadBillingDataTask = task(async () => { | ||||||||||||||
| if (!this.billingService.loadingSubscriptionData) { | ||||||||||||||
| await this.billingService.loadSubscriptionData(); | ||||||||||||||
| } | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
|
Comment on lines
+371
to
+375
|
||||||||||||||
| if (!this.billingService.loadingSubscriptionData) { | |
| await this.billingService.loadSubscriptionData(); | |
| } | |
| }); | |
| await this.billingService.loadSubscriptionData(); | |
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This guard skips the reload entirely whenever a subscription fetch is already in progress, but the in-flight request may have started before the out-of-credits event was emitted (for example during initial panel load or a concurrent billing notification). In that case the request can resolve with stale credits, and because no second fetch is triggered, the message can keep showing the wrong action state. The reload path should ensure a fresh fetch happens after any in-flight load completes instead of returning early.
Useful? React with 👍 / 👎.