diff --git a/Services/ChatService.ts b/Services/ChatService.ts index 5dd6e53..b41ca73 100644 --- a/Services/ChatService.ts +++ b/Services/ChatService.ts @@ -139,7 +139,7 @@ export class ChatService { } public setStatusBarTokens(inputTokens: number, outputTokens: number): void { - this.statusBarService.setStatusBarMessage(`Input Tokens: ${inputTokens} / Output Tokens: ${outputTokens}`); + this.statusBarService.animateTokens(inputTokens, outputTokens); } private async streamRequestResponse( diff --git a/Services/StatusBarService.ts b/Services/StatusBarService.ts index 51282a9..c3612e6 100644 --- a/Services/StatusBarService.ts +++ b/Services/StatusBarService.ts @@ -7,6 +7,9 @@ export class StatusBarService { private readonly plugin: AIAgentPlugin; private statusBarItem: HTMLElement | null; + private currentInputTokens: number = 0; + private currentOutputTokens: number = 0; + private animationFrame: number | null = null; public constructor() { this.plugin = Resolve(Services.AIAgentPlugin); @@ -21,7 +24,52 @@ export class StatusBarService { this.statusBarItem?.createEl("span", { text: message }); } + public animateTokens(targetInputTokens: number, targetOutputTokens: number) { + // Cancel any ongoing animation + if (this.animationFrame !== null) { + cancelAnimationFrame(this.animationFrame); + } + + const startInputTokens = this.currentInputTokens; + const startOutputTokens = this.currentOutputTokens; + const startTime = performance.now(); + const duration = 1000; + + const animate = (currentTime: number) => { + const elapsed = currentTime - startTime; + const progress = Math.min(elapsed / duration, 1); + + // Ease-out cubic for smooth deceleration + const eased = 1 - Math.pow(1 - progress, 3); + + // Calculate current values + this.currentInputTokens = Math.round( + startInputTokens + (targetInputTokens - startInputTokens) * eased + ); + this.currentOutputTokens = Math.round( + startOutputTokens + (targetOutputTokens - startOutputTokens) * eased + ); + + this.setStatusBarMessage( + `Input Tokens: ${this.currentInputTokens} / Output Tokens: ${this.currentOutputTokens}` + ); + + // Continue animation if not complete + if (progress < 1) { + this.animationFrame = requestAnimationFrame(animate); + } else { + this.animationFrame = null; + } + }; + + this.animationFrame = requestAnimationFrame(animate); + } + public removeStatusBarMessage() { + if (this.animationFrame !== null) { + cancelAnimationFrame(this.animationFrame); + this.animationFrame = null; + } this.statusBarItem?.remove(); this.statusBarItem = null; }