@cloudcli-ai/cloudcli 1.32.0 → 1.33.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/README.de.md +1 -1
  2. package/README.ko.md +1 -1
  3. package/README.md +1 -1
  4. package/README.ru.md +1 -1
  5. package/README.tr.md +1 -1
  6. package/README.zh-CN.md +1 -1
  7. package/dist/api-docs.html +6 -7
  8. package/dist/assets/index-BsyL_xmI.js +1348 -0
  9. package/dist/assets/index-FSP9Hz7V.css +32 -0
  10. package/dist/index.html +2 -2
  11. package/dist/modelConstants.js +848 -0
  12. package/dist-server/server/claude-sdk.js +57 -34
  13. package/dist-server/server/claude-sdk.js.map +1 -1
  14. package/dist-server/server/cursor-cli.js +6 -3
  15. package/dist-server/server/cursor-cli.js.map +1 -1
  16. package/dist-server/server/gemini-cli.js +3 -1
  17. package/dist-server/server/gemini-cli.js.map +1 -1
  18. package/dist-server/server/gemini-response-handler.js +34 -0
  19. package/dist-server/server/gemini-response-handler.js.map +1 -1
  20. package/dist-server/server/index.js +234 -67
  21. package/dist-server/server/index.js.map +1 -1
  22. package/dist-server/server/modules/database/index.js +1 -0
  23. package/dist-server/server/modules/database/index.js.map +1 -1
  24. package/dist-server/server/modules/projects/services/project-management.service.js +1 -0
  25. package/dist-server/server/modules/projects/services/project-management.service.js.map +1 -1
  26. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +4 -0
  27. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -1
  28. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +28 -6
  29. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -1
  30. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +146 -0
  31. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -0
  32. package/dist-server/server/modules/providers/list/claude/claude.provider.js +2 -0
  33. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -1
  34. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +84 -0
  35. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -0
  36. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +7 -39
  37. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -1
  38. package/dist-server/server/modules/providers/list/codex/codex.provider.js +2 -0
  39. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -1
  40. package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js +754 -0
  41. package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js.map +1 -0
  42. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +2 -15
  43. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -1
  44. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +2 -0
  45. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -1
  46. package/dist-server/server/modules/providers/list/gemini/gemini-models.provider.js +27 -0
  47. package/dist-server/server/modules/providers/list/gemini/gemini-models.provider.js.map +1 -0
  48. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +3 -9
  49. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -1
  50. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js +2 -0
  51. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +1 -1
  52. package/dist-server/server/modules/providers/list/opencode/opencode-auth.provider.js +92 -0
  53. package/dist-server/server/modules/providers/list/opencode/opencode-auth.provider.js.map +1 -0
  54. package/dist-server/server/modules/providers/list/opencode/opencode-mcp.provider.js +181 -0
  55. package/dist-server/server/modules/providers/list/opencode/opencode-mcp.provider.js.map +1 -0
  56. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +267 -0
  57. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -0
  58. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +115 -0
  59. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js.map +1 -0
  60. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +410 -0
  61. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -0
  62. package/dist-server/server/modules/providers/list/opencode/opencode-skills.provider.js +62 -0
  63. package/dist-server/server/modules/providers/list/opencode/opencode-skills.provider.js.map +1 -0
  64. package/dist-server/server/modules/providers/list/opencode/opencode.provider.js +19 -0
  65. package/dist-server/server/modules/providers/list/opencode/opencode.provider.js.map +1 -0
  66. package/dist-server/server/modules/providers/provider.registry.js +2 -0
  67. package/dist-server/server/modules/providers/provider.registry.js.map +1 -1
  68. package/dist-server/server/modules/providers/provider.routes.js +42 -1
  69. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  70. package/dist-server/server/modules/providers/services/mcp.service.js +1 -9
  71. package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -1
  72. package/dist-server/server/modules/providers/services/provider-models.service.js +226 -0
  73. package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -0
  74. package/dist-server/server/modules/providers/services/session-synchronizer.service.js +1 -0
  75. package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -1
  76. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +7 -0
  77. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
  78. package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -1
  79. package/dist-server/server/modules/providers/tests/mcp.test.js +73 -6
  80. package/dist-server/server/modules/providers/tests/mcp.test.js.map +1 -1
  81. package/dist-server/server/modules/providers/tests/opencode-models.test.js +66 -0
  82. package/dist-server/server/modules/providers/tests/opencode-models.test.js.map +1 -0
  83. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +262 -0
  84. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js.map +1 -0
  85. package/dist-server/server/modules/providers/tests/provider-models.service.test.js +298 -0
  86. package/dist-server/server/modules/providers/tests/provider-models.service.test.js.map +1 -0
  87. package/dist-server/server/modules/providers/tests/skills.test.js +33 -0
  88. package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -1
  89. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +12 -1
  90. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
  91. package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js +4 -4
  92. package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js.map +1 -1
  93. package/dist-server/server/modules/websocket/services/shell-websocket.service.js +18 -3
  94. package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
  95. package/dist-server/server/modules/websocket/services/websocket-auth.service.js +6 -2
  96. package/dist-server/server/modules/websocket/services/websocket-auth.service.js.map +1 -1
  97. package/dist-server/server/modules/websocket/services/websocket-server.service.js +18 -0
  98. package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -1
  99. package/dist-server/server/openai-codex.js +32 -4
  100. package/dist-server/server/openai-codex.js.map +1 -1
  101. package/dist-server/server/opencode-cli.js +287 -0
  102. package/dist-server/server/opencode-cli.js.map +1 -0
  103. package/dist-server/server/opencode-cli.test.js +84 -0
  104. package/dist-server/server/opencode-cli.test.js.map +1 -0
  105. package/dist-server/server/routes/agent.js +21 -8
  106. package/dist-server/server/routes/agent.js.map +1 -1
  107. package/dist-server/server/routes/commands.js +202 -209
  108. package/dist-server/server/routes/commands.js.map +1 -1
  109. package/dist-server/server/routes/cursor.js +2 -2
  110. package/dist-server/server/routes/cursor.js.map +1 -1
  111. package/dist-server/server/routes/settings.js +0 -10
  112. package/dist-server/server/routes/settings.js.map +1 -1
  113. package/dist-server/server/routes/tests/commands.test.js +76 -0
  114. package/dist-server/server/routes/tests/commands.test.js.map +1 -0
  115. package/dist-server/server/shared/utils.js +286 -0
  116. package/dist-server/server/shared/utils.js.map +1 -1
  117. package/package.json +5 -2
  118. package/public/api-docs.html +878 -0
  119. package/public/modelConstants.js +848 -0
  120. package/server/claude-sdk.js +64 -35
  121. package/server/cursor-cli.js +6 -3
  122. package/server/gemini-cli.js +7 -1
  123. package/server/gemini-response-handler.js +38 -0
  124. package/server/index.js +259 -75
  125. package/server/modules/database/index.ts +1 -0
  126. package/server/modules/projects/services/project-management.service.ts +2 -0
  127. package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +7 -1
  128. package/server/modules/providers/README.md +11 -3
  129. package/server/modules/providers/list/claude/claude-auth.provider.ts +34 -6
  130. package/server/modules/providers/list/claude/claude-models.provider.ts +196 -0
  131. package/server/modules/providers/list/claude/claude.provider.ts +3 -0
  132. package/server/modules/providers/list/codex/codex-models.provider.ts +125 -0
  133. package/server/modules/providers/list/codex/codex-skills.provider.ts +10 -50
  134. package/server/modules/providers/list/codex/codex.provider.ts +3 -0
  135. package/server/modules/providers/list/cursor/cursor-models.provider.ts +820 -0
  136. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +7 -20
  137. package/server/modules/providers/list/cursor/cursor.provider.ts +3 -0
  138. package/server/modules/providers/list/gemini/gemini-models.provider.ts +42 -0
  139. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +3 -10
  140. package/server/modules/providers/list/gemini/gemini.provider.ts +3 -0
  141. package/server/modules/providers/list/opencode/opencode-auth.provider.ts +111 -0
  142. package/server/modules/providers/list/opencode/opencode-mcp.provider.ts +228 -0
  143. package/server/modules/providers/list/opencode/opencode-models.provider.ts +339 -0
  144. package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +157 -0
  145. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +506 -0
  146. package/server/modules/providers/list/opencode/opencode-skills.provider.ts +78 -0
  147. package/server/modules/providers/list/opencode/opencode.provider.ts +27 -0
  148. package/server/modules/providers/provider.registry.ts +2 -0
  149. package/server/modules/providers/provider.routes.ts +62 -2
  150. package/server/modules/providers/services/mcp.service.ts +1 -12
  151. package/server/modules/providers/services/provider-models.service.ts +358 -0
  152. package/server/modules/providers/services/session-synchronizer.service.ts +1 -0
  153. package/server/modules/providers/services/sessions-watcher.service.ts +8 -0
  154. package/server/modules/providers/shared/base/abstract.provider.ts +2 -0
  155. package/server/modules/providers/tests/mcp.test.ts +93 -6
  156. package/server/modules/providers/tests/opencode-models.test.ts +73 -0
  157. package/server/modules/providers/tests/opencode-sessions.test.ts +334 -0
  158. package/server/modules/providers/tests/provider-models.service.test.ts +349 -0
  159. package/server/modules/providers/tests/skills.test.ts +66 -0
  160. package/server/modules/websocket/services/chat-websocket.service.ts +15 -1
  161. package/server/modules/websocket/services/plugin-websocket-proxy.service.ts +4 -4
  162. package/server/modules/websocket/services/shell-websocket.service.ts +22 -2
  163. package/server/modules/websocket/services/websocket-auth.service.ts +7 -2
  164. package/server/modules/websocket/services/websocket-server.service.ts +18 -0
  165. package/server/openai-codex.js +41 -4
  166. package/server/opencode-cli.js +336 -0
  167. package/server/opencode-cli.test.js +95 -0
  168. package/server/routes/agent.js +22 -8
  169. package/server/routes/commands.js +254 -233
  170. package/server/routes/cursor.js +2 -2
  171. package/server/routes/settings.js +1 -10
  172. package/server/routes/tests/commands.test.js +82 -0
  173. package/server/shared/interfaces.ts +45 -0
  174. package/server/shared/types.ts +88 -1
  175. package/server/shared/utils.ts +384 -0
  176. package/dist/assets/index-AaSE7-3t.js +0 -1336
  177. package/dist/assets/index-CKaku72N.css +0 -32
  178. package/dist-server/shared/modelConstants.js +0 -99
  179. package/dist-server/shared/modelConstants.js.map +0 -1
  180. package/shared/modelConstants.js +0 -107
@@ -17,7 +17,8 @@ import crypto from 'crypto';
17
17
  import { promises as fs } from 'fs';
18
18
  import path from 'path';
19
19
  import os from 'os';
20
- import { CLAUDE_MODELS } from '../shared/modelConstants.js';
20
+ import { CLAUDE_FALLBACK_MODELS } from './modules/providers/list/claude/claude-models.provider.js';
21
+ import { providerModelsService } from './modules/providers/services/provider-models.service.js';
21
22
  import { resolveClaudeCodeExecutablePath } from './shared/claude-cli-path.js';
22
23
  import {
23
24
  createNotificationEvent,
@@ -204,7 +205,7 @@ function mapCliOptionsToSDK(options = {}) {
204
205
 
205
206
  // Map model (default to sonnet)
206
207
  // Valid models: sonnet, opus, haiku, opusplan, sonnet[1m]
207
- sdkOptions.model = options.model || CLAUDE_MODELS.DEFAULT;
208
+ sdkOptions.model = options.model || CLAUDE_FALLBACK_MODELS.DEFAULT;
208
209
  // Model logged at query start below
209
210
 
210
211
  // Map system prompt configuration
@@ -284,43 +285,68 @@ function transformMessage(sdkMessage) {
284
285
  return sdkMessage;
285
286
  }
286
287
 
288
+ function readNumber(value) {
289
+ const parsed = Number(value);
290
+ return Number.isFinite(parsed) ? parsed : 0;
291
+ }
292
+
287
293
  /**
288
- * Extracts token usage from SDK result messages
289
- * @param {Object} resultMessage - SDK result message
294
+ * Extracts token usage from SDK messages.
295
+ * Prefers per-step `message.usage` (Claude message payload), then falls back
296
+ * to result-level usage/modelUsage for compatibility across SDK versions.
297
+ * @param {Object} sdkMessage - SDK stream message
290
298
  * @returns {Object|null} Token budget object or null
291
299
  */
292
- function extractTokenBudget(resultMessage) {
293
- if (resultMessage.type !== 'result' || !resultMessage.modelUsage) {
300
+ function extractTokenBudget(sdkMessage) {
301
+ if (!sdkMessage || typeof sdkMessage !== 'object') {
294
302
  return null;
295
303
  }
296
304
 
297
- // Get the first model's usage data
298
- const modelKey = Object.keys(resultMessage.modelUsage)[0];
299
- const modelData = resultMessage.modelUsage[modelKey];
305
+ const messageUsage = sdkMessage.message?.usage || sdkMessage.usage;
306
+ if (messageUsage && typeof messageUsage === 'object') {
307
+ const inputTokens = readNumber(messageUsage.input_tokens ?? messageUsage.inputTokens);
308
+ const outputTokens = readNumber(messageUsage.output_tokens ?? messageUsage.outputTokens);
309
+ const totalUsed = inputTokens + outputTokens;
310
+ const contextWindow = parseInt(process.env.CONTEXT_WINDOW, 10) || 160000;
300
311
 
301
- if (!modelData) {
302
- return null;
312
+ return {
313
+ used: totalUsed,
314
+ total: contextWindow,
315
+ inputTokens,
316
+ outputTokens,
317
+ breakdown: {
318
+ input: inputTokens,
319
+ output: outputTokens,
320
+ },
321
+ };
303
322
  }
304
323
 
305
- // Use cumulative tokens if available (tracks total for the session)
306
- // Otherwise fall back to per-request tokens
307
- const inputTokens = modelData.cumulativeInputTokens || modelData.inputTokens || 0;
308
- const outputTokens = modelData.cumulativeOutputTokens || modelData.outputTokens || 0;
309
- const cacheReadTokens = modelData.cumulativeCacheReadInputTokens || modelData.cacheReadInputTokens || 0;
310
- const cacheCreationTokens = modelData.cumulativeCacheCreationInputTokens || modelData.cacheCreationInputTokens || 0;
324
+ if (!sdkMessage.modelUsage || typeof sdkMessage.modelUsage !== 'object') {
325
+ return null;
326
+ }
311
327
 
312
- // Total used = input + output + cache tokens
313
- const totalUsed = inputTokens + outputTokens + cacheReadTokens + cacheCreationTokens;
328
+ // Fallback for older SDK messages with only modelUsage
329
+ const modelKey = Object.keys(sdkMessage.modelUsage)[0];
330
+ const modelData = sdkMessage.modelUsage[modelKey];
314
331
 
315
- // Use configured context window budget from environment (default 160000)
316
- // This is the user's budget limit, not the model's context window
317
- const contextWindow = parseInt(process.env.CONTEXT_WINDOW) || 160000;
332
+ if (!modelData || typeof modelData !== 'object') {
333
+ return null;
334
+ }
318
335
 
319
- // Token calc logged via token-budget WS event
336
+ const inputTokens = readNumber(modelData.cumulativeInputTokens ?? modelData.inputTokens);
337
+ const outputTokens = readNumber(modelData.cumulativeOutputTokens ?? modelData.outputTokens);
338
+ const totalUsed = inputTokens + outputTokens;
339
+ const contextWindow = parseInt(process.env.CONTEXT_WINDOW, 10) || 160000;
320
340
 
321
341
  return {
322
342
  used: totalUsed,
323
- total: contextWindow
343
+ total: contextWindow,
344
+ inputTokens,
345
+ outputTokens,
346
+ breakdown: {
347
+ input: inputTokens,
348
+ output: outputTokens,
349
+ },
324
350
  };
325
351
  }
326
352
 
@@ -491,8 +517,17 @@ async function queryClaudeSDK(command, options = {}, ws) {
491
517
  };
492
518
 
493
519
  try {
520
+ const resolvedModel = await providerModelsService.resolveResumeModel(
521
+ 'claude',
522
+ sessionId,
523
+ options.model,
524
+ );
525
+
494
526
  // Map CLI options to SDK format
495
- const sdkOptions = mapCliOptionsToSDK(options);
527
+ const sdkOptions = mapCliOptionsToSDK({
528
+ ...options,
529
+ model: resolvedModel || options.model,
530
+ });
496
531
 
497
532
  // Load MCP configuration
498
533
  const mcpServers = await loadMcpConfig(options.cwd);
@@ -674,16 +709,10 @@ async function queryClaudeSDK(command, options = {}, ws) {
674
709
  ws.send(msg);
675
710
  }
676
711
 
677
- // Extract and send token budget updates from result messages
678
- if (message.type === 'result') {
679
- const models = Object.keys(message.modelUsage || {});
680
- if (models.length > 0) {
681
- // Model info available in result message
682
- }
683
- const tokenBudgetData = extractTokenBudget(message);
684
- if (tokenBudgetData) {
685
- ws.send(createNormalizedMessage({ kind: 'status', text: 'token_budget', tokenBudget: tokenBudgetData, sessionId: capturedSessionId || sessionId || null, provider: 'claude' }));
686
- }
712
+ // Extract and send token budget updates from assistant/result usage payloads
713
+ const tokenBudgetData = extractTokenBudget(message);
714
+ if (tokenBudgetData) {
715
+ ws.send(createNormalizedMessage({ kind: 'status', text: 'token_budget', tokenBudget: tokenBudgetData, sessionId: capturedSessionId || sessionId || null, provider: 'claude' }));
687
716
  }
688
717
  }
689
718
 
@@ -3,6 +3,7 @@ import crossSpawn from 'cross-spawn';
3
3
  import { notifyRunFailed, notifyRunStopped } from './services/notification-orchestrator.js';
4
4
  import { sessionsService } from './modules/providers/services/sessions.service.js';
5
5
  import { providerAuthService } from './modules/providers/services/provider-auth.service.js';
6
+ import { providerModelsService } from './modules/providers/services/provider-models.service.js';
6
7
  import { createNormalizedMessage } from './shared/utils.js';
7
8
 
8
9
  // Use cross-spawn on Windows for better command execution
@@ -28,6 +29,7 @@ function isWorkspaceTrustPrompt(text = '') {
28
29
  async function spawnCursor(command, options = {}, ws) {
29
30
  return new Promise(async (resolve, reject) => {
30
31
  const { sessionId, projectPath, cwd, resume, toolsSettings, skipPermissions, model, sessionSummary } = options;
32
+ const resolvedModel = await providerModelsService.resolveResumeModel('cursor', sessionId, model);
31
33
  let capturedSessionId = sessionId; // Track session ID throughout the process
32
34
  let sessionCreatedSent = false; // Track if we've already sent session-created event
33
35
  let hasRetriedWithTrust = false;
@@ -52,9 +54,10 @@ async function spawnCursor(command, options = {}, ws) {
52
54
  // Provide a prompt (works for both new and resumed sessions)
53
55
  baseArgs.push('-p', command);
54
56
 
55
- // Add model flag if specified (only meaningful for new sessions; harmless on resume)
56
- if (!sessionId && model) {
57
- baseArgs.push('--model', model);
57
+ // Model overrides are applied to both new and resumed sessions so a
58
+ // session-scoped change request can take effect on the next turn.
59
+ if (resolvedModel) {
60
+ baseArgs.push('--model', resolvedModel);
58
61
  }
59
62
 
60
63
  // Request streaming JSON when we are providing a prompt
@@ -9,6 +9,7 @@ import sessionManager from './sessionManager.js';
9
9
  import GeminiResponseHandler from './gemini-response-handler.js';
10
10
  import { notifyRunFailed, notifyRunStopped } from './services/notification-orchestrator.js';
11
11
  import { providerAuthService } from './modules/providers/services/provider-auth.service.js';
12
+ import { providerModelsService } from './modules/providers/services/provider-models.service.js';
12
13
  import { createNormalizedMessage } from './shared/utils.js';
13
14
 
14
15
  // Use cross-spawn on Windows for correct .cmd resolution (same pattern as cursor-cli.js)
@@ -120,6 +121,11 @@ async function buildGeminiProcessEnv() {
120
121
 
121
122
  async function spawnGemini(command, options = {}, ws) {
122
123
  const { sessionId, projectPath, cwd, toolsSettings, permissionMode, images, sessionSummary } = options;
124
+ const resolvedModel = await providerModelsService.resolveResumeModel(
125
+ 'gemini',
126
+ sessionId,
127
+ options.model
128
+ );
123
129
  let capturedSessionId = sessionId; // Track session ID throughout the process
124
130
  let sessionCreatedSent = false; // Track if we've already sent session-created event
125
131
  let assistantBlocks = []; // Accumulate the full response blocks including tools
@@ -244,7 +250,7 @@ async function spawnGemini(command, options = {}, ws) {
244
250
  }
245
251
 
246
252
  // Add model for all sessions (both new and resumed)
247
- let modelToUse = options.model || 'gemini-2.5-flash';
253
+ let modelToUse = resolvedModel || 'gemini-2.5-flash';
248
254
  args.push('--model', modelToUse);
249
255
  args.push('--output-format', 'stream-json');
250
256
 
@@ -1,5 +1,32 @@
1
1
  // Gemini Response Handler - JSON Stream processing
2
2
  import { sessionsService } from './modules/providers/services/sessions.service.js';
3
+ import { createNormalizedMessage } from './shared/utils.js';
4
+
5
+ function buildGeminiTokenBudget(tokens) {
6
+ if (!tokens || typeof tokens !== 'object') {
7
+ return null;
8
+ }
9
+
10
+ const parsedInputTokens = Number(tokens.input);
11
+ const parsedOutputTokens = Number(tokens.output);
12
+ const inputTokens = Number.isFinite(parsedInputTokens) ? parsedInputTokens : 0;
13
+ const outputTokens = Number.isFinite(parsedOutputTokens) ? parsedOutputTokens : 0;
14
+ const parsedUsed = Number(tokens.total);
15
+ const used = Number.isFinite(parsedUsed) ? parsedUsed : inputTokens + outputTokens;
16
+ if (!Number.isFinite(used) || used <= 0) {
17
+ return null;
18
+ }
19
+
20
+ return {
21
+ used,
22
+ inputTokens,
23
+ outputTokens,
24
+ breakdown: {
25
+ input: inputTokens,
26
+ output: outputTokens,
27
+ },
28
+ };
29
+ }
3
30
 
4
31
  class GeminiResponseHandler {
5
32
  constructor(ws, options = {}) {
@@ -60,6 +87,17 @@ class GeminiResponseHandler {
60
87
  for (const msg of normalized) {
61
88
  this.ws.send(msg);
62
89
  }
90
+
91
+ const tokenBudget = buildGeminiTokenBudget(event.tokens);
92
+ if (tokenBudget) {
93
+ this.ws.send(createNormalizedMessage({
94
+ kind: 'status',
95
+ text: 'token_budget',
96
+ tokenBudget,
97
+ sessionId: sid,
98
+ provider: 'gemini',
99
+ }));
100
+ }
63
101
  }
64
102
 
65
103
  forceFlush() {