@leanandmean/coding-agent 0.74.1-scramjet.7 → 0.74.1-scramjet.71

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 (226) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/LICENSE +202 -0
  3. package/README.md +37 -9
  4. package/dist/cli/args.d.ts +2 -0
  5. package/dist/cli/args.d.ts.map +1 -1
  6. package/dist/cli/args.js +45 -1
  7. package/dist/cli/args.js.map +1 -1
  8. package/dist/cli/initial-message.d.ts +1 -0
  9. package/dist/cli/initial-message.d.ts.map +1 -1
  10. package/dist/cli/initial-message.js +3 -0
  11. package/dist/cli/initial-message.js.map +1 -1
  12. package/dist/cli/list-models.d.ts +2 -0
  13. package/dist/cli/list-models.d.ts.map +1 -1
  14. package/dist/cli/list-models.js +4 -1
  15. package/dist/cli/list-models.js.map +1 -1
  16. package/dist/config.d.ts +9 -2
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/config.js +33 -22
  19. package/dist/config.js.map +1 -1
  20. package/dist/core/agent-session-runtime.d.ts +12 -3
  21. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  22. package/dist/core/agent-session-runtime.js +64 -38
  23. package/dist/core/agent-session-runtime.js.map +1 -1
  24. package/dist/core/agent-session-services.d.ts +2 -0
  25. package/dist/core/agent-session-services.d.ts.map +1 -1
  26. package/dist/core/agent-session-services.js +3 -0
  27. package/dist/core/agent-session-services.js.map +1 -1
  28. package/dist/core/agent-session.d.ts +84 -17
  29. package/dist/core/agent-session.d.ts.map +1 -1
  30. package/dist/core/agent-session.js +1082 -209
  31. package/dist/core/agent-session.js.map +1 -1
  32. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  33. package/dist/core/compaction/branch-summarization.js +21 -17
  34. package/dist/core/compaction/branch-summarization.js.map +1 -1
  35. package/dist/core/compaction/compaction.d.ts +3 -5
  36. package/dist/core/compaction/compaction.d.ts.map +1 -1
  37. package/dist/core/compaction/compaction.js +43 -10
  38. package/dist/core/compaction/compaction.js.map +1 -1
  39. package/dist/core/exec.d.ts +12 -0
  40. package/dist/core/exec.d.ts.map +1 -1
  41. package/dist/core/exec.js +74 -28
  42. package/dist/core/exec.js.map +1 -1
  43. package/dist/core/export-html/template.js +4 -0
  44. package/dist/core/extensions/index.d.ts +1 -1
  45. package/dist/core/extensions/index.d.ts.map +1 -1
  46. package/dist/core/extensions/index.js.map +1 -1
  47. package/dist/core/extensions/runner.d.ts +9 -5
  48. package/dist/core/extensions/runner.d.ts.map +1 -1
  49. package/dist/core/extensions/runner.js +160 -3
  50. package/dist/core/extensions/runner.js.map +1 -1
  51. package/dist/core/extensions/types.d.ts +85 -8
  52. package/dist/core/extensions/types.d.ts.map +1 -1
  53. package/dist/core/extensions/types.js.map +1 -1
  54. package/dist/core/keybindings.d.ts +8 -0
  55. package/dist/core/keybindings.d.ts.map +1 -1
  56. package/dist/core/model-registry.d.ts +103 -0
  57. package/dist/core/model-registry.d.ts.map +1 -1
  58. package/dist/core/model-registry.js +272 -28
  59. package/dist/core/model-registry.js.map +1 -1
  60. package/dist/core/model-resolver.d.ts.map +1 -1
  61. package/dist/core/model-resolver.js +24 -6
  62. package/dist/core/model-resolver.js.map +1 -1
  63. package/dist/core/output-throughput-history.d.ts +25 -0
  64. package/dist/core/output-throughput-history.d.ts.map +1 -0
  65. package/dist/core/output-throughput-history.js +240 -0
  66. package/dist/core/output-throughput-history.js.map +1 -0
  67. package/dist/core/output-throughput.d.ts +43 -0
  68. package/dist/core/output-throughput.d.ts.map +1 -0
  69. package/dist/core/output-throughput.js +161 -0
  70. package/dist/core/output-throughput.js.map +1 -0
  71. package/dist/core/resource-loader.d.ts +6 -0
  72. package/dist/core/resource-loader.d.ts.map +1 -1
  73. package/dist/core/resource-loader.js +76 -21
  74. package/dist/core/resource-loader.js.map +1 -1
  75. package/dist/core/scramjet-command-parser.d.ts +4 -0
  76. package/dist/core/scramjet-command-parser.d.ts.map +1 -1
  77. package/dist/core/scramjet-command-parser.js +72 -1
  78. package/dist/core/scramjet-command-parser.js.map +1 -1
  79. package/dist/core/sdk.d.ts +4 -0
  80. package/dist/core/sdk.d.ts.map +1 -1
  81. package/dist/core/sdk.js +70 -11
  82. package/dist/core/sdk.js.map +1 -1
  83. package/dist/core/session-manager.d.ts +11 -3
  84. package/dist/core/session-manager.d.ts.map +1 -1
  85. package/dist/core/session-manager.js +46 -11
  86. package/dist/core/session-manager.js.map +1 -1
  87. package/dist/core/settings-manager.d.ts +19 -6
  88. package/dist/core/settings-manager.d.ts.map +1 -1
  89. package/dist/core/settings-manager.js +131 -17
  90. package/dist/core/settings-manager.js.map +1 -1
  91. package/dist/core/skills.d.ts.map +1 -1
  92. package/dist/core/skills.js +6 -2
  93. package/dist/core/skills.js.map +1 -1
  94. package/dist/core/system-prompt.d.ts +2 -0
  95. package/dist/core/system-prompt.d.ts.map +1 -1
  96. package/dist/core/system-prompt.js +5 -2
  97. package/dist/core/system-prompt.js.map +1 -1
  98. package/dist/core/tools/bash.d.ts.map +1 -1
  99. package/dist/core/tools/bash.js +4 -3
  100. package/dist/core/tools/bash.js.map +1 -1
  101. package/dist/index.d.ts +4 -3
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +3 -2
  104. package/dist/index.js.map +1 -1
  105. package/dist/main.d.ts +119 -0
  106. package/dist/main.d.ts.map +1 -1
  107. package/dist/main.js +113 -11
  108. package/dist/main.js.map +1 -1
  109. package/dist/modes/interactive/components/armin.d.ts +4 -2
  110. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  111. package/dist/modes/interactive/components/armin.js +14 -8
  112. package/dist/modes/interactive/components/armin.js.map +1 -1
  113. package/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  114. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  115. package/dist/modes/interactive/components/assistant-message.js +19 -8
  116. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  117. package/dist/modes/interactive/components/daxnuts.d.ts +4 -1
  118. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  119. package/dist/modes/interactive/components/daxnuts.js +14 -6
  120. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  121. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  122. package/dist/modes/interactive/components/extension-editor.js +5 -3
  123. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  124. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  125. package/dist/modes/interactive/components/extension-selector.js +4 -3
  126. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  127. package/dist/modes/interactive/components/footer.d.ts +4 -0
  128. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  129. package/dist/modes/interactive/components/footer.js +24 -20
  130. package/dist/modes/interactive/components/footer.js.map +1 -1
  131. package/dist/modes/interactive/components/model-selector.d.ts +3 -3
  132. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  133. package/dist/modes/interactive/components/model-selector.js +10 -7
  134. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  135. package/dist/modes/interactive/components/scoped-models-selector.d.ts +3 -1
  136. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  137. package/dist/modes/interactive/components/scoped-models-selector.js +8 -2
  138. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  139. package/dist/modes/interactive/components/settings-selector.d.ts +17 -3
  140. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  141. package/dist/modes/interactive/components/settings-selector.js +87 -16
  142. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  143. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  144. package/dist/modes/interactive/components/thinking-selector.js +2 -1
  145. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  146. package/dist/modes/interactive/components/tool-execution.d.ts +19 -1
  147. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  148. package/dist/modes/interactive/components/tool-execution.js +129 -36
  149. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  150. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  151. package/dist/modes/interactive/components/user-message.js +3 -2
  152. package/dist/modes/interactive/components/user-message.js.map +1 -1
  153. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  154. package/dist/modes/interactive/components/visual-truncate.js +2 -2
  155. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  156. package/dist/modes/interactive/interactive-mode.d.ts +37 -1
  157. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  158. package/dist/modes/interactive/interactive-mode.js +902 -177
  159. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  160. package/dist/modes/interactive/spellcheck.d.ts +26 -0
  161. package/dist/modes/interactive/spellcheck.d.ts.map +1 -0
  162. package/dist/modes/interactive/spellcheck.js +144 -0
  163. package/dist/modes/interactive/spellcheck.js.map +1 -0
  164. package/dist/modes/interactive/theme/{dark.json → pi-dark.json} +3 -2
  165. package/dist/modes/interactive/theme/{light.json → pi-light.json} +27 -26
  166. package/dist/modes/interactive/theme/theme-schema.json +6 -1
  167. package/dist/modes/interactive/theme/theme.d.ts +24 -4
  168. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  169. package/dist/modes/interactive/theme/theme.js +123 -22
  170. package/dist/modes/interactive/theme/theme.js.map +1 -1
  171. package/dist/modes/print-mode.d.ts.map +1 -1
  172. package/dist/modes/print-mode.js +5 -0
  173. package/dist/modes/print-mode.js.map +1 -1
  174. package/dist/modes/rpc/rpc-client.d.ts +3 -1
  175. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  176. package/dist/modes/rpc/rpc-client.js.map +1 -1
  177. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  178. package/dist/modes/rpc/rpc-mode.js +6 -1
  179. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  180. package/dist/package-manager-cli.d.ts.map +1 -1
  181. package/dist/package-manager-cli.js +33 -14
  182. package/dist/package-manager-cli.js.map +1 -1
  183. package/dist/utils/clipboard-native.d.ts +1 -0
  184. package/dist/utils/clipboard-native.d.ts.map +1 -1
  185. package/dist/utils/clipboard-native.js.map +1 -1
  186. package/dist/utils/clipboard.d.ts +6 -0
  187. package/dist/utils/clipboard.d.ts.map +1 -1
  188. package/dist/utils/clipboard.js +278 -10
  189. package/dist/utils/clipboard.js.map +1 -1
  190. package/dist/utils/tools-manager.d.ts +1 -1
  191. package/dist/utils/tools-manager.d.ts.map +1 -1
  192. package/dist/utils/tools-manager.js +7 -6
  193. package/dist/utils/tools-manager.js.map +1 -1
  194. package/dist/utils/version-check.d.ts +17 -5
  195. package/dist/utils/version-check.d.ts.map +1 -1
  196. package/dist/utils/version-check.js +88 -21
  197. package/dist/utils/version-check.js.map +1 -1
  198. package/docs/compaction.md +21 -3
  199. package/docs/custom-provider.md +33 -4
  200. package/docs/extensions.md +150 -24
  201. package/docs/json.md +8 -0
  202. package/docs/keybindings.md +25 -1
  203. package/docs/models.md +103 -4
  204. package/docs/packages.md +2 -0
  205. package/docs/prompt-templates.md +2 -0
  206. package/docs/quickstart.md +1 -4
  207. package/docs/rpc.md +16 -6
  208. package/docs/sdk.md +48 -3
  209. package/docs/session-format.md +5 -1
  210. package/docs/settings.md +19 -5
  211. package/docs/skills.md +7 -5
  212. package/docs/terminal-setup.md +79 -2
  213. package/docs/terminal-verification.md +71 -0
  214. package/docs/themes.md +63 -10
  215. package/docs/tui.md +120 -25
  216. package/docs/usage.md +6 -4
  217. package/examples/extensions/border-status-editor.ts +2 -3
  218. package/examples/extensions/doom-overlay/doom-component.ts +3 -3
  219. package/examples/extensions/mac-system-theme.ts +3 -2
  220. package/examples/extensions/modal-editor.ts +13 -8
  221. package/examples/extensions/overlay-qa-tests.ts +22 -9
  222. package/examples/extensions/overlay-test.ts +5 -3
  223. package/examples/extensions/snake.ts +3 -1
  224. package/examples/extensions/space-invaders.ts +6 -3
  225. package/examples/extensions/subagent/index.ts +20 -17
  226. package/package.json +69 -58
@@ -1 +1 @@
1
- {"version":3,"file":"model-resolver.js","sourceRoot":"","sources":["../../src/core/model-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model resolution, scoping, and initial selection\n */\n\nimport type { ThinkingLevel } from \"@leanandmean/agent\";\nimport { type Api, type KnownProvider, type Model, modelsAreEqual } from \"@leanandmean/ai\";\nimport chalk from \"chalk\";\nimport { minimatch } from \"minimatch\";\nimport { isValidThinkingLevel } from \"../cli/args.js\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.js\";\nimport type { ModelRegistry } from \"./model-registry.js\";\n\n/** Default model IDs for each known provider */\nexport const defaultModelPerProvider: Record<KnownProvider, string> = {\n\t\"amazon-bedrock\": \"us.anthropic.claude-opus-4-6-v1\",\n\tanthropic: \"claude-opus-4-7\",\n\topenai: \"gpt-5.4\",\n\t\"azure-openai-responses\": \"gpt-5.4\",\n\t\"openai-codex\": \"gpt-5.5\",\n\tdeepseek: \"deepseek-v4-pro\",\n\tgoogle: \"gemini-3.1-pro-preview\",\n\t\"google-vertex\": \"gemini-3.1-pro-preview\",\n\t\"github-copilot\": \"gpt-5.4\",\n\topenrouter: \"moonshotai/kimi-k2.6\",\n\t\"vercel-ai-gateway\": \"zai/glm-5.1\",\n\txai: \"grok-4.20-0309-reasoning\",\n\tgroq: \"openai/gpt-oss-120b\",\n\tcerebras: \"zai-glm-4.7\",\n\tzai: \"glm-5.1\",\n\tmistral: \"devstral-medium-latest\",\n\tminimax: \"MiniMax-M2.7\",\n\t\"minimax-cn\": \"MiniMax-M2.7\",\n\tmoonshotai: \"kimi-k2.6\",\n\t\"moonshotai-cn\": \"kimi-k2.6\",\n\thuggingface: \"moonshotai/Kimi-K2.6\",\n\tfireworks: \"accounts/fireworks/models/kimi-k2p6\",\n\ttogether: \"moonshotai/Kimi-K2.6\",\n\topencode: \"kimi-k2.6\",\n\t\"opencode-go\": \"kimi-k2.6\",\n\t\"kimi-coding\": \"kimi-for-coding\",\n\t\"cloudflare-workers-ai\": \"@cf/moonshotai/kimi-k2.6\",\n\t\"cloudflare-ai-gateway\": \"workers-ai/@cf/moonshotai/kimi-k2.6\",\n\txiaomi: \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-cn\": \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-ams\": \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-sgp\": \"mimo-v2.5-pro\",\n};\n\nexport interface ScopedModel {\n\tmodel: Model<Api>;\n\t/** Thinking level if explicitly specified in pattern (e.g., \"model:high\"), undefined otherwise */\n\tthinkingLevel?: ThinkingLevel;\n}\n\n/**\n * Helper to check if a model ID looks like an alias (no date suffix)\n * Dates are typically in format: -20241022 or -20250929\n */\nfunction isAlias(id: string): boolean {\n\t// Check if ID ends with -latest\n\tif (id.endsWith(\"-latest\")) return true;\n\n\t// Check if ID ends with a date pattern (-YYYYMMDD)\n\tconst datePattern = /-\\d{8}$/;\n\treturn !datePattern.test(id);\n}\n\n/**\n * Find an exact model reference match.\n * Supports either a bare model id or a canonical provider/modelId reference.\n * When matching by bare id, ambiguous matches across providers are rejected.\n */\nexport function findExactModelReferenceMatch(\n\tmodelReference: string,\n\tavailableModels: Model<Api>[],\n): Model<Api> | undefined {\n\tconst trimmedReference = modelReference.trim();\n\tif (!trimmedReference) {\n\t\treturn undefined;\n\t}\n\n\tconst normalizedReference = trimmedReference.toLowerCase();\n\n\tconst canonicalMatches = availableModels.filter(\n\t\t(model) => `${model.provider}/${model.id}`.toLowerCase() === normalizedReference,\n\t);\n\tif (canonicalMatches.length === 1) {\n\t\treturn canonicalMatches[0];\n\t}\n\tif (canonicalMatches.length > 1) {\n\t\treturn undefined;\n\t}\n\n\tconst slashIndex = trimmedReference.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst provider = trimmedReference.substring(0, slashIndex).trim();\n\t\tconst modelId = trimmedReference.substring(slashIndex + 1).trim();\n\t\tif (provider && modelId) {\n\t\t\tconst providerMatches = availableModels.filter(\n\t\t\t\t(model) =>\n\t\t\t\t\tmodel.provider.toLowerCase() === provider.toLowerCase() &&\n\t\t\t\t\tmodel.id.toLowerCase() === modelId.toLowerCase(),\n\t\t\t);\n\t\t\tif (providerMatches.length === 1) {\n\t\t\t\treturn providerMatches[0];\n\t\t\t}\n\t\t\tif (providerMatches.length > 1) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst idMatches = availableModels.filter((model) => model.id.toLowerCase() === normalizedReference);\n\treturn idMatches.length === 1 ? idMatches[0] : undefined;\n}\n\n/**\n * Try to match a pattern to a model from the available models list.\n * Returns the matched model or undefined if no match found.\n */\nfunction tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Model<Api> | undefined {\n\tconst exactMatch = findExactModelReferenceMatch(modelPattern, availableModels);\n\tif (exactMatch) {\n\t\treturn exactMatch;\n\t}\n\n\t// No exact match - fall back to partial matching\n\tconst matches = availableModels.filter(\n\t\t(m) =>\n\t\t\tm.id.toLowerCase().includes(modelPattern.toLowerCase()) ||\n\t\t\tm.name?.toLowerCase().includes(modelPattern.toLowerCase()),\n\t);\n\n\tif (matches.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// Separate into aliases and dated versions\n\tconst aliases = matches.filter((m) => isAlias(m.id));\n\tconst datedVersions = matches.filter((m) => !isAlias(m.id));\n\n\tif (aliases.length > 0) {\n\t\t// Prefer alias - if multiple aliases, pick the one that sorts highest\n\t\taliases.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn aliases[0];\n\t} else {\n\t\t// No alias found, pick latest dated version\n\t\tdatedVersions.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn datedVersions[0];\n\t}\n}\n\nexport interface ParsedModelResult {\n\tmodel: Model<Api> | undefined;\n\t/** Thinking level if explicitly specified in pattern, undefined otherwise */\n\tthinkingLevel?: ThinkingLevel;\n\twarning: string | undefined;\n}\n\nfunction buildFallbackModel(provider: string, modelId: string, availableModels: Model<Api>[]): Model<Api> | undefined {\n\tconst providerModels = availableModels.filter((m) => m.provider === provider);\n\tif (providerModels.length === 0) return undefined;\n\n\tconst defaultId = defaultModelPerProvider[provider as KnownProvider];\n\tconst baseModel = defaultId\n\t\t? (providerModels.find((m) => m.id === defaultId) ?? providerModels[0])\n\t\t: providerModels[0];\n\n\treturn {\n\t\t...baseModel,\n\t\tid: modelId,\n\t\tname: modelId,\n\t};\n}\n\n/**\n * Parse a pattern to extract model and thinking level.\n * Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).\n *\n * Algorithm:\n * 1. Try to match full pattern as a model\n * 2. If found, return it with \"off\" thinking level\n * 3. If not found and has colons, split on last colon:\n * - If suffix is valid thinking level, use it and recurse on prefix\n * - If suffix is invalid, warn and recurse on prefix with \"off\"\n *\n * @internal Exported for testing\n */\nexport function parseModelPattern(\n\tpattern: string,\n\tavailableModels: Model<Api>[],\n\toptions?: { allowInvalidThinkingLevelFallback?: boolean },\n): ParsedModelResult {\n\t// Try exact match first\n\tconst exactMatch = tryMatchModel(pattern, availableModels);\n\tif (exactMatch) {\n\t\treturn { model: exactMatch, thinkingLevel: undefined, warning: undefined };\n\t}\n\n\t// No match - try splitting on last colon if present\n\tconst lastColonIndex = pattern.lastIndexOf(\":\");\n\tif (lastColonIndex === -1) {\n\t\t// No colons, pattern simply doesn't match any model\n\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\n\t}\n\n\tconst prefix = pattern.substring(0, lastColonIndex);\n\tconst suffix = pattern.substring(lastColonIndex + 1);\n\n\tif (isValidThinkingLevel(suffix)) {\n\t\t// Valid thinking level - recurse on prefix and use this level\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\n\t\tif (result.model) {\n\t\t\t// Only use this thinking level if no warning from inner recursion\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: result.warning ? undefined : suffix,\n\t\t\t\twarning: result.warning,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t} else {\n\t\t// Invalid suffix\n\t\tconst allowFallback = options?.allowInvalidThinkingLevelFallback ?? true;\n\t\tif (!allowFallback) {\n\t\t\t// In strict mode (CLI --model parsing), treat it as part of the model id and fail.\n\t\t\t// This avoids accidentally resolving to a different model.\n\t\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\n\t\t}\n\n\t\t// Scope mode: recurse on prefix and warn\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\n\t\tif (result.model) {\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\twarning: `Invalid thinking level \"${suffix}\" in pattern \"${pattern}\". Using default instead.`,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Resolve model patterns to actual Model objects with optional thinking levels\n * Format: \"pattern:level\" where :level is optional\n * For each pattern, finds all matching models and picks the best version:\n * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929)\n * 2. If no alias, pick the latest dated version\n *\n * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).\n * The algorithm tries to match the full pattern first, then progressively\n * strips colon-suffixes to find a match.\n */\nexport async function resolveModelScope(patterns: string[], modelRegistry: ModelRegistry): Promise<ScopedModel[]> {\n\tconst availableModels = await modelRegistry.getAvailable();\n\tconst scopedModels: ScopedModel[] = [];\n\n\tfor (const pattern of patterns) {\n\t\t// Check if pattern contains glob characters\n\t\tif (pattern.includes(\"*\") || pattern.includes(\"?\") || pattern.includes(\"[\")) {\n\t\t\t// Extract optional thinking level suffix (e.g., \"provider/*:high\")\n\t\t\tconst colonIdx = pattern.lastIndexOf(\":\");\n\t\t\tlet globPattern = pattern;\n\t\t\tlet thinkingLevel: ThinkingLevel | undefined;\n\n\t\t\tif (colonIdx !== -1) {\n\t\t\t\tconst suffix = pattern.substring(colonIdx + 1);\n\t\t\t\tif (isValidThinkingLevel(suffix)) {\n\t\t\t\t\tthinkingLevel = suffix;\n\t\t\t\t\tglobPattern = pattern.substring(0, colonIdx);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Match against \"provider/modelId\" format OR just model ID\n\t\t\t// This allows \"*sonnet*\" to match without requiring \"anthropic/*sonnet*\"\n\t\t\tconst matchingModels = availableModels.filter((m) => {\n\t\t\t\tconst fullId = `${m.provider}/${m.id}`;\n\t\t\t\treturn minimatch(fullId, globPattern, { nocase: true }) || minimatch(m.id, globPattern, { nocase: true });\n\t\t\t});\n\n\t\t\tif (matchingModels.length === 0) {\n\t\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const model of matchingModels) {\n\t\t\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, availableModels);\n\n\t\tif (warning) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: ${warning}`));\n\t\t}\n\n\t\tif (!model) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Avoid duplicates\n\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t}\n\t}\n\n\treturn scopedModels;\n}\n\nexport interface ResolveCliModelResult {\n\tmodel: Model<Api> | undefined;\n\tthinkingLevel?: ThinkingLevel;\n\twarning: string | undefined;\n\t/**\n\t * Error message suitable for CLI display.\n\t * When set, model will be undefined.\n\t */\n\terror: string | undefined;\n}\n\n/**\n * Resolve a single model from CLI flags.\n *\n * Supports:\n * - --provider <provider> --model <pattern>\n * - --model <provider>/<pattern>\n * - Fuzzy matching (same rules as model scoping: exact id, then partial id/name)\n *\n * Note: This does not apply the thinking level by itself, but it may *parse* and\n * return a thinking level from \"<pattern>:<thinking>\" so the caller can apply it.\n */\nexport function resolveCliModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tmodelRegistry: ModelRegistry;\n}): ResolveCliModelResult {\n\tconst { cliProvider, cliModel, modelRegistry } = options;\n\n\tif (!cliModel) {\n\t\treturn { model: undefined, warning: undefined, error: undefined };\n\t}\n\n\t// Important: use *all* models here, not just models with pre-configured auth.\n\t// This allows \"--api-key\" to be used for first-time setup.\n\tconst availableModels = modelRegistry.getAll();\n\tif (availableModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\terror: \"No models available. Check your installation or add models to models.json.\",\n\t\t};\n\t}\n\n\t// Build canonical provider lookup (case-insensitive)\n\tconst providerMap = new Map<string, string>();\n\tfor (const m of availableModels) {\n\t\tproviderMap.set(m.provider.toLowerCase(), m.provider);\n\t}\n\n\tlet provider = cliProvider ? providerMap.get(cliProvider.toLowerCase()) : undefined;\n\tif (cliProvider && !provider) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\terror: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\t// If no explicit --provider, try to interpret \"provider/model\" format first.\n\t// When the prefix before the first slash matches a known provider, prefer that\n\t// interpretation over matching models whose IDs literally contain slashes\n\t// (e.g. \"zai/glm-5\" should resolve to provider=zai, model=glm-5, not to a\n\t// vercel-ai-gateway model with id \"zai/glm-5\").\n\tlet pattern = cliModel;\n\tlet inferredProvider = false;\n\n\tif (!provider) {\n\t\tconst slashIndex = cliModel.indexOf(\"/\");\n\t\tif (slashIndex !== -1) {\n\t\t\tconst maybeProvider = cliModel.substring(0, slashIndex);\n\t\t\tconst canonical = providerMap.get(maybeProvider.toLowerCase());\n\t\t\tif (canonical) {\n\t\t\t\tprovider = canonical;\n\t\t\t\tpattern = cliModel.substring(slashIndex + 1);\n\t\t\t\tinferredProvider = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// If no provider was inferred from the slash, try exact matches without provider inference.\n\t// This handles models whose IDs naturally contain slashes (e.g. OpenRouter-style IDs).\n\tif (!provider) {\n\t\tconst lower = cliModel.toLowerCase();\n\t\tconst exact = availableModels.find(\n\t\t\t(m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower,\n\t\t);\n\t\tif (exact) {\n\t\t\treturn { model: exact, warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t}\n\n\tif (cliProvider && provider) {\n\t\t// If both were provided, tolerate --model <provider>/<pattern> by stripping the provider prefix\n\t\tconst prefix = `${provider}/`;\n\t\tif (cliModel.toLowerCase().startsWith(prefix.toLowerCase())) {\n\t\t\tpattern = cliModel.substring(prefix.length);\n\t\t}\n\t}\n\n\tconst candidates = provider ? availableModels.filter((m) => m.provider === provider) : availableModels;\n\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, candidates, {\n\t\tallowInvalidThinkingLevelFallback: false,\n\t});\n\n\tif (model) {\n\t\treturn { model, thinkingLevel, warning, error: undefined };\n\t}\n\n\t// If we inferred a provider from the slash but found no match within that provider,\n\t// fall back to matching the full input as a raw model id across all models.\n\t// This handles OpenRouter-style IDs like \"openai/gpt-4o:extended\" where \"openai\"\n\t// looks like a provider but the full string is actually a model id on openrouter.\n\tif (inferredProvider) {\n\t\tconst lower = cliModel.toLowerCase();\n\t\tconst exact = availableModels.find(\n\t\t\t(m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower,\n\t\t);\n\t\tif (exact) {\n\t\t\treturn { model: exact, warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\t// Also try parseModelPattern on the full input against all models\n\t\tconst fallback = parseModelPattern(cliModel, availableModels, {\n\t\t\tallowInvalidThinkingLevelFallback: false,\n\t\t});\n\t\tif (fallback.model) {\n\t\t\treturn {\n\t\t\t\tmodel: fallback.model,\n\t\t\t\tthinkingLevel: fallback.thinkingLevel,\n\t\t\t\twarning: fallback.warning,\n\t\t\t\terror: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\tif (provider) {\n\t\tconst fallbackModel = buildFallbackModel(provider, pattern, availableModels);\n\t\tif (fallbackModel) {\n\t\t\tconst fallbackWarning = warning\n\t\t\t\t? `${warning} Model \"${pattern}\" not found for provider \"${provider}\". Using custom model id.`\n\t\t\t\t: `Model \"${pattern}\" not found for provider \"${provider}\". Using custom model id.`;\n\t\t\treturn { model: fallbackModel, thinkingLevel: undefined, warning: fallbackWarning, error: undefined };\n\t\t}\n\t}\n\n\tconst display = provider ? `${provider}/${pattern}` : cliModel;\n\treturn {\n\t\tmodel: undefined,\n\t\tthinkingLevel: undefined,\n\t\twarning,\n\t\terror: `Model \"${display}\" not found. Use --list-models to see available models.`,\n\t};\n}\n\nexport interface InitialModelResult {\n\tmodel: Model<Api> | undefined;\n\tthinkingLevel: ThinkingLevel;\n\tfallbackMessage: string | undefined;\n}\n\n/**\n * Find the initial model to use based on priority:\n * 1. CLI args (provider + model)\n * 2. First model from scoped models (if not continuing/resuming)\n * 3. Restored from session (if continuing/resuming)\n * 4. Saved default from settings\n * 5. First available model with valid API key\n */\nexport async function findInitialModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tscopedModels: ScopedModel[];\n\tisContinuing: boolean;\n\tdefaultProvider?: string;\n\tdefaultModelId?: string;\n\tdefaultThinkingLevel?: ThinkingLevel;\n\tmodelRegistry: ModelRegistry;\n}): Promise<InitialModelResult> {\n\tconst {\n\t\tcliProvider,\n\t\tcliModel,\n\t\tscopedModels,\n\t\tisContinuing,\n\t\tdefaultProvider,\n\t\tdefaultModelId,\n\t\tdefaultThinkingLevel,\n\t\tmodelRegistry,\n\t} = options;\n\n\tlet model: Model<Api> | undefined;\n\tlet thinkingLevel: ThinkingLevel = DEFAULT_THINKING_LEVEL;\n\n\t// 1. CLI args take priority\n\tif (cliProvider && cliModel) {\n\t\tconst resolved = resolveCliModel({\n\t\t\tcliProvider,\n\t\t\tcliModel,\n\t\t\tmodelRegistry,\n\t\t});\n\t\tif (resolved.error) {\n\t\t\tconsole.error(chalk.red(resolved.error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (resolved.model) {\n\t\t\treturn { model: resolved.model, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\n\t\t}\n\t}\n\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\n\tif (scopedModels.length > 0 && !isContinuing) {\n\t\treturn {\n\t\t\tmodel: scopedModels[0].model,\n\t\t\tthinkingLevel: scopedModels[0].thinkingLevel ?? defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,\n\t\t\tfallbackMessage: undefined,\n\t\t};\n\t}\n\n\t// 3. Try saved default from settings\n\tif (defaultProvider && defaultModelId) {\n\t\tconst found = modelRegistry.find(defaultProvider, defaultModelId);\n\t\tif (found) {\n\t\t\tmodel = found;\n\t\t\tif (defaultThinkingLevel) {\n\t\t\t\tthinkingLevel = defaultThinkingLevel;\n\t\t\t}\n\t\t\treturn { model, thinkingLevel, fallbackMessage: undefined };\n\t\t}\n\t}\n\n\t// 4. Try first available model with valid API key\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\treturn { model: match, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\treturn { model: availableModels[0], thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\n\t}\n\n\t// 5. No model found\n\treturn { model: undefined, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\n}\n\n/**\n * Restore model from session, with fallback to available models\n */\nexport async function restoreModelFromSession(\n\tsavedProvider: string,\n\tsavedModelId: string,\n\tcurrentModel: Model<Api> | undefined,\n\tshouldPrintMessages: boolean,\n\tmodelRegistry: ModelRegistry,\n): Promise<{ model: Model<Api> | undefined; fallbackMessage: string | undefined }> {\n\tconst restoredModel = modelRegistry.find(savedProvider, savedModelId);\n\n\t// Check if restored model exists and still has auth configured\n\tconst hasConfiguredAuth = restoredModel ? modelRegistry.hasConfiguredAuth(restoredModel) : false;\n\n\tif (restoredModel && hasConfiguredAuth) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Restored model: ${savedProvider}/${savedModelId}`));\n\t\t}\n\t\treturn { model: restoredModel, fallbackMessage: undefined };\n\t}\n\n\t// Model not found or no API key - fall back\n\tconst reason = !restoredModel ? \"model no longer exists\" : \"no auth configured\";\n\n\tif (shouldPrintMessages) {\n\t\tconsole.error(chalk.yellow(`Warning: Could not restore model ${savedProvider}/${savedModelId} (${reason}).`));\n\t}\n\n\t// If we already have a model, use it as fallback\n\tif (currentModel) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${currentModel.provider}/${currentModel.id}`));\n\t\t}\n\t\treturn {\n\t\t\tmodel: currentModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${currentModel.provider}/${currentModel.id}.`,\n\t\t};\n\t}\n\n\t// Try to find any available model\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tlet fallbackModel: Model<Api> | undefined;\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\tfallbackModel = match;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\tif (!fallbackModel) {\n\t\t\tfallbackModel = availableModels[0];\n\t\t}\n\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${fallbackModel.provider}/${fallbackModel.id}`));\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: fallbackModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${fallbackModel.provider}/${fallbackModel.id}.`,\n\t\t};\n\t}\n\n\t// No models available\n\treturn { model: undefined, fallbackMessage: undefined };\n}\n"]}
1
+ {"version":3,"file":"model-resolver.js","sourceRoot":"","sources":["../../src/core/model-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model resolution, scoping, and initial selection\n */\n\nimport type { ThinkingLevel } from \"@leanandmean/agent\";\nimport { type Api, type KnownProvider, type Model, modelsAreEqual } from \"@leanandmean/ai\";\nimport chalk from \"chalk\";\nimport { minimatch } from \"minimatch\";\nimport { isValidThinkingLevel } from \"../cli/args.js\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.js\";\nimport type { ModelRegistry } from \"./model-registry.js\";\n\n// SCRAMJET-DIVERGENCE: Default models updated to claude-opus-4-8 (upstream parity)\n/** Default model IDs for each known provider */\nexport const defaultModelPerProvider: Record<KnownProvider, string> = {\n\t\"amazon-bedrock\": \"us.anthropic.claude-opus-4-8\",\n\tanthropic: \"claude-opus-4-8\",\n\topenai: \"gpt-5.4\",\n\t\"azure-openai-responses\": \"gpt-5.4\",\n\t\"openai-codex\": \"gpt-5.5\",\n\tdeepseek: \"deepseek-v4-pro\",\n\tgoogle: \"gemini-3.1-pro-preview\",\n\t\"google-vertex\": \"gemini-3.1-pro-preview\",\n\t\"github-copilot\": \"gpt-5.4\",\n\topenrouter: \"moonshotai/kimi-k2.6\",\n\t\"vercel-ai-gateway\": \"zai/glm-5.1\",\n\txai: \"grok-4.20-0309-reasoning\",\n\tgroq: \"openai/gpt-oss-120b\",\n\tcerebras: \"gpt-oss-120b\",\n\tzai: \"glm-5.1\",\n\tmistral: \"devstral-medium-latest\",\n\tminimax: \"MiniMax-M2.7\",\n\t\"minimax-cn\": \"MiniMax-M2.7\",\n\tmoonshotai: \"kimi-k2.6\",\n\t\"moonshotai-cn\": \"kimi-k2.6\",\n\thuggingface: \"moonshotai/Kimi-K2.6\",\n\tfireworks: \"accounts/fireworks/models/kimi-k2p6\",\n\ttogether: \"moonshotai/Kimi-K2.6\",\n\topencode: \"kimi-k2.6\",\n\t\"opencode-go\": \"kimi-k2.6\",\n\t\"kimi-coding\": \"kimi-for-coding\",\n\t\"cloudflare-workers-ai\": \"@cf/moonshotai/kimi-k2.6\",\n\t\"cloudflare-ai-gateway\": \"workers-ai/@cf/moonshotai/kimi-k2.6\",\n\txiaomi: \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-cn\": \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-ams\": \"mimo-v2.5-pro\",\n\t\"xiaomi-token-plan-sgp\": \"mimo-v2.5-pro\",\n};\n\nexport interface ScopedModel {\n\tmodel: Model<Api>;\n\t/** Thinking level if explicitly specified in pattern (e.g., \"model:high\"), undefined otherwise */\n\tthinkingLevel?: ThinkingLevel;\n}\n\n/**\n * Helper to check if a model ID looks like an alias (no date suffix)\n * Dates are typically in format: -20241022 or -20250929\n */\nfunction isAlias(id: string): boolean {\n\t// Check if ID ends with -latest\n\tif (id.endsWith(\"-latest\")) return true;\n\n\t// Check if ID ends with a date pattern (-YYYYMMDD)\n\tconst datePattern = /-\\d{8}$/;\n\treturn !datePattern.test(id);\n}\n\n/**\n * Find an exact model reference match.\n * Supports either a bare model id or a canonical provider/modelId reference.\n * When matching by bare id, ambiguous matches across providers are rejected.\n */\nexport function findExactModelReferenceMatch(\n\tmodelReference: string,\n\tavailableModels: Model<Api>[],\n): Model<Api> | undefined {\n\tconst trimmedReference = modelReference.trim();\n\tif (!trimmedReference) {\n\t\treturn undefined;\n\t}\n\n\tconst normalizedReference = trimmedReference.toLowerCase();\n\n\tconst canonicalMatches = availableModels.filter(\n\t\t(model) => `${model.provider}/${model.id}`.toLowerCase() === normalizedReference,\n\t);\n\tif (canonicalMatches.length === 1) {\n\t\treturn canonicalMatches[0];\n\t}\n\tif (canonicalMatches.length > 1) {\n\t\treturn undefined;\n\t}\n\n\tconst slashIndex = trimmedReference.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst provider = trimmedReference.substring(0, slashIndex).trim();\n\t\tconst modelId = trimmedReference.substring(slashIndex + 1).trim();\n\t\tif (provider && modelId) {\n\t\t\tconst providerMatches = availableModels.filter(\n\t\t\t\t(model) =>\n\t\t\t\t\tmodel.provider.toLowerCase() === provider.toLowerCase() &&\n\t\t\t\t\tmodel.id.toLowerCase() === modelId.toLowerCase(),\n\t\t\t);\n\t\t\tif (providerMatches.length === 1) {\n\t\t\t\treturn providerMatches[0];\n\t\t\t}\n\t\t\tif (providerMatches.length > 1) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst idMatches = availableModels.filter((model) => model.id.toLowerCase() === normalizedReference);\n\treturn idMatches.length === 1 ? idMatches[0] : undefined;\n}\n\n/**\n * Try to match a pattern to a model from the available models list.\n * Returns the matched model or undefined if no match found.\n */\nfunction tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Model<Api> | undefined {\n\tconst exactMatch = findExactModelReferenceMatch(modelPattern, availableModels);\n\tif (exactMatch) {\n\t\treturn exactMatch;\n\t}\n\n\t// No exact match - fall back to partial matching\n\tconst matches = availableModels.filter(\n\t\t(m) =>\n\t\t\tm.id.toLowerCase().includes(modelPattern.toLowerCase()) ||\n\t\t\tm.name?.toLowerCase().includes(modelPattern.toLowerCase()),\n\t);\n\n\tif (matches.length === 0) {\n\t\treturn undefined;\n\t}\n\n\t// Separate into aliases and dated versions\n\tconst aliases = matches.filter((m) => isAlias(m.id));\n\tconst datedVersions = matches.filter((m) => !isAlias(m.id));\n\n\tif (aliases.length > 0) {\n\t\t// Prefer alias - if multiple aliases, pick the one that sorts highest\n\t\taliases.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn aliases[0];\n\t} else {\n\t\t// No alias found, pick latest dated version\n\t\tdatedVersions.sort((a, b) => b.id.localeCompare(a.id));\n\t\treturn datedVersions[0];\n\t}\n}\n\nexport interface ParsedModelResult {\n\tmodel: Model<Api> | undefined;\n\t/** Thinking level if explicitly specified in pattern, undefined otherwise */\n\tthinkingLevel?: ThinkingLevel;\n\twarning: string | undefined;\n}\n\nfunction buildFallbackModel(provider: string, modelId: string, availableModels: Model<Api>[]): Model<Api> | undefined {\n\tconst providerModels = availableModels.filter((m) => m.provider === provider);\n\tif (providerModels.length === 0) return undefined;\n\n\tconst defaultId = defaultModelPerProvider[provider as KnownProvider];\n\tconst baseModel = defaultId\n\t\t? (providerModels.find((m) => m.id === defaultId) ?? providerModels[0])\n\t\t: providerModels[0];\n\n\treturn {\n\t\t...baseModel,\n\t\tid: modelId,\n\t\tname: modelId,\n\t\t// SCRAMJET-DIVERGENCE: Unknown IDs must not inherit another model's constraints or capabilities.\n\t\tmaxInputTokens: undefined,\n\t\trequestLimits: undefined,\n\t\tcompat: undefined,\n\t\tthinkingLevelMap: undefined,\n\t};\n}\n\n/**\n * Parse a pattern to extract model and thinking level.\n * Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).\n *\n * Algorithm:\n * 1. Try to match full pattern as a model\n * 2. If found, return it with \"off\" thinking level\n * 3. If not found and has colons, split on last colon:\n * - If suffix is valid thinking level, use it and recurse on prefix\n * - If suffix is invalid, warn and recurse on prefix with \"off\"\n *\n * @internal Exported for testing\n */\nexport function parseModelPattern(\n\tpattern: string,\n\tavailableModels: Model<Api>[],\n\toptions?: { allowInvalidThinkingLevelFallback?: boolean },\n): ParsedModelResult {\n\t// Try exact match first\n\tconst exactMatch = tryMatchModel(pattern, availableModels);\n\tif (exactMatch) {\n\t\treturn { model: exactMatch, thinkingLevel: undefined, warning: undefined };\n\t}\n\n\t// No match - try splitting on last colon if present\n\tconst lastColonIndex = pattern.lastIndexOf(\":\");\n\tif (lastColonIndex === -1) {\n\t\t// No colons, pattern simply doesn't match any model\n\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\n\t}\n\n\tconst prefix = pattern.substring(0, lastColonIndex);\n\tconst suffix = pattern.substring(lastColonIndex + 1);\n\n\tif (isValidThinkingLevel(suffix)) {\n\t\t// Valid thinking level - recurse on prefix and use this level\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\n\t\tif (result.model) {\n\t\t\t// Only use this thinking level if no warning from inner recursion\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: result.warning ? undefined : suffix,\n\t\t\t\twarning: result.warning,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t} else {\n\t\t// Invalid suffix\n\t\tconst allowFallback = options?.allowInvalidThinkingLevelFallback ?? true;\n\t\tif (!allowFallback) {\n\t\t\t// In strict mode (CLI --model parsing), treat it as part of the model id and fail.\n\t\t\t// This avoids accidentally resolving to a different model.\n\t\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\n\t\t}\n\n\t\t// Scope mode: recurse on prefix and warn\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\n\t\tif (result.model) {\n\t\t\treturn {\n\t\t\t\tmodel: result.model,\n\t\t\t\tthinkingLevel: undefined,\n\t\t\t\twarning: `Invalid thinking level \"${suffix}\" in pattern \"${pattern}\". Using default instead.`,\n\t\t\t};\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Resolve model patterns to actual Model objects with optional thinking levels\n * Format: \"pattern:level\" where :level is optional\n * For each pattern, finds all matching models and picks the best version:\n * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929)\n * 2. If no alias, pick the latest dated version\n *\n * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).\n * The algorithm tries to match the full pattern first, then progressively\n * strips colon-suffixes to find a match.\n */\nexport async function resolveModelScope(patterns: string[], modelRegistry: ModelRegistry): Promise<ScopedModel[]> {\n\tconst availableModels = await modelRegistry.getAvailable();\n\tconst scopedModels: ScopedModel[] = [];\n\n\tfor (const pattern of patterns) {\n\t\t// Check if pattern contains glob characters\n\t\tif (pattern.includes(\"*\") || pattern.includes(\"?\") || pattern.includes(\"[\")) {\n\t\t\t// Extract optional thinking level suffix (e.g., \"provider/*:high\")\n\t\t\tconst colonIdx = pattern.lastIndexOf(\":\");\n\t\t\tlet globPattern = pattern;\n\t\t\tlet thinkingLevel: ThinkingLevel | undefined;\n\n\t\t\tif (colonIdx !== -1) {\n\t\t\t\tconst suffix = pattern.substring(colonIdx + 1);\n\t\t\t\tif (isValidThinkingLevel(suffix)) {\n\t\t\t\t\tthinkingLevel = suffix;\n\t\t\t\t\tglobPattern = pattern.substring(0, colonIdx);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Match against \"provider/modelId\" format OR just model ID\n\t\t\t// This allows \"*sonnet*\" to match without requiring \"anthropic/*sonnet*\"\n\t\t\tconst matchingModels = availableModels.filter((m) => {\n\t\t\t\tconst fullId = `${m.provider}/${m.id}`;\n\t\t\t\treturn minimatch(fullId, globPattern, { nocase: true }) || minimatch(m.id, globPattern, { nocase: true });\n\t\t\t});\n\n\t\t\tif (matchingModels.length === 0) {\n\t\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const model of matchingModels) {\n\t\t\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, availableModels);\n\n\t\tif (warning) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: ${warning}`));\n\t\t}\n\n\t\tif (!model) {\n\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Avoid duplicates\n\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\n\t\t\tscopedModels.push({ model, thinkingLevel });\n\t\t}\n\t}\n\n\treturn scopedModels;\n}\n\nexport interface ResolveCliModelResult {\n\tmodel: Model<Api> | undefined;\n\tthinkingLevel?: ThinkingLevel;\n\twarning: string | undefined;\n\t/**\n\t * Error message suitable for CLI display.\n\t * When set, model will be undefined.\n\t */\n\terror: string | undefined;\n}\n\n/**\n * Resolve a single model from CLI flags.\n *\n * Supports:\n * - --provider <provider> --model <pattern>\n * - --model <provider>/<pattern>\n * - Fuzzy matching (same rules as model scoping: exact id, then partial id/name)\n *\n * Note: This does not apply the thinking level by itself, but it may *parse* and\n * return a thinking level from \"<pattern>:<thinking>\" so the caller can apply it.\n */\nexport function resolveCliModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tmodelRegistry: ModelRegistry;\n}): ResolveCliModelResult {\n\tconst { cliProvider, cliModel, modelRegistry } = options;\n\n\tif (!cliModel) {\n\t\treturn { model: undefined, warning: undefined, error: undefined };\n\t}\n\n\t// Important: use *all* models here, not just models with pre-configured auth.\n\t// This allows \"--api-key\" to be used for first-time setup.\n\tconst availableModels = modelRegistry.getAll();\n\tif (availableModels.length === 0) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\terror: \"No models available. Check your installation or add models to models.json.\",\n\t\t};\n\t}\n\n\t// Build canonical provider lookup (case-insensitive)\n\tconst providerMap = new Map<string, string>();\n\tfor (const m of availableModels) {\n\t\tproviderMap.set(m.provider.toLowerCase(), m.provider);\n\t}\n\n\tlet provider = cliProvider ? providerMap.get(cliProvider.toLowerCase()) : undefined;\n\tif (cliProvider && !provider) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\twarning: undefined,\n\t\t\terror: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`,\n\t\t};\n\t}\n\n\t// If no explicit --provider, try to interpret \"provider/model\" format first.\n\t// When the prefix before the first slash matches a known provider, prefer that\n\t// interpretation over matching models whose IDs literally contain slashes\n\t// (e.g. \"zai/glm-5\" should resolve to provider=zai, model=glm-5, not to a\n\t// vercel-ai-gateway model with id \"zai/glm-5\").\n\tlet pattern = cliModel;\n\tlet inferredProvider = false;\n\n\tif (!provider) {\n\t\tconst slashIndex = cliModel.indexOf(\"/\");\n\t\tif (slashIndex !== -1) {\n\t\t\tconst maybeProvider = cliModel.substring(0, slashIndex);\n\t\t\tconst canonical = providerMap.get(maybeProvider.toLowerCase());\n\t\t\tif (canonical) {\n\t\t\t\tprovider = canonical;\n\t\t\t\tpattern = cliModel.substring(slashIndex + 1);\n\t\t\t\tinferredProvider = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// If no provider was inferred from the slash, try exact matches without provider inference.\n\t// This handles models whose IDs naturally contain slashes (e.g. OpenRouter-style IDs).\n\tif (!provider) {\n\t\tconst lower = cliModel.toLowerCase();\n\t\tconst exact = availableModels.find(\n\t\t\t(m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower,\n\t\t);\n\t\tif (exact) {\n\t\t\treturn { model: exact, warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t}\n\n\tif (cliProvider && provider) {\n\t\t// If both were provided, tolerate --model <provider>/<pattern> by stripping the provider prefix\n\t\tconst prefix = `${provider}/`;\n\t\tif (cliModel.toLowerCase().startsWith(prefix.toLowerCase())) {\n\t\t\tpattern = cliModel.substring(prefix.length);\n\t\t}\n\t}\n\n\tconst candidates = provider ? availableModels.filter((m) => m.provider === provider) : availableModels;\n\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, candidates, {\n\t\tallowInvalidThinkingLevelFallback: false,\n\t});\n\n\tif (model) {\n\t\treturn { model, thinkingLevel, warning, error: undefined };\n\t}\n\n\t// If we inferred a provider from the slash but found no match within that provider,\n\t// fall back to matching the full input as a raw model id across all models.\n\t// This handles OpenRouter-style IDs like \"openai/gpt-4o:extended\" where \"openai\"\n\t// looks like a provider but the full string is actually a model id on openrouter.\n\tif (inferredProvider) {\n\t\tconst lower = cliModel.toLowerCase();\n\t\tconst exact = availableModels.find(\n\t\t\t(m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower,\n\t\t);\n\t\tif (exact) {\n\t\t\treturn { model: exact, warning: undefined, thinkingLevel: undefined, error: undefined };\n\t\t}\n\t\t// Also try parseModelPattern on the full input against all models\n\t\tconst fallback = parseModelPattern(cliModel, availableModels, {\n\t\t\tallowInvalidThinkingLevelFallback: false,\n\t\t});\n\t\tif (fallback.model) {\n\t\t\treturn {\n\t\t\t\tmodel: fallback.model,\n\t\t\t\tthinkingLevel: fallback.thinkingLevel,\n\t\t\t\twarning: fallback.warning,\n\t\t\t\terror: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\tif (provider) {\n\t\tconst fallbackModel = buildFallbackModel(provider, pattern, availableModels);\n\t\tif (fallbackModel) {\n\t\t\tconst fallbackWarning = warning\n\t\t\t\t? `${warning} Model \"${pattern}\" not found for provider \"${provider}\". Using custom model id.`\n\t\t\t\t: `Model \"${pattern}\" not found for provider \"${provider}\". Using custom model id.`;\n\t\t\treturn { model: fallbackModel, thinkingLevel: undefined, warning: fallbackWarning, error: undefined };\n\t\t}\n\t}\n\n\tconst display = provider ? `${provider}/${pattern}` : cliModel;\n\treturn {\n\t\tmodel: undefined,\n\t\tthinkingLevel: undefined,\n\t\twarning,\n\t\terror: `Model \"${display}\" not found. Use --list-models to see available models.`,\n\t};\n}\n\nexport interface InitialModelResult {\n\tmodel: Model<Api> | undefined;\n\tthinkingLevel: ThinkingLevel;\n\tfallbackMessage: string | undefined;\n}\n\n/**\n * Find the initial model to use based on priority:\n * 1. CLI args (provider + model)\n * 2. First model from scoped models (if not continuing/resuming)\n * 3. Restored from session (if continuing/resuming)\n * 4. Saved default from settings\n * 5. First available model with valid API key\n */\nexport async function findInitialModel(options: {\n\tcliProvider?: string;\n\tcliModel?: string;\n\tscopedModels: ScopedModel[];\n\tisContinuing: boolean;\n\tdefaultProvider?: string;\n\tdefaultModelId?: string;\n\tdefaultThinkingLevel?: ThinkingLevel;\n\tmodelRegistry: ModelRegistry;\n}): Promise<InitialModelResult> {\n\tconst {\n\t\tcliProvider,\n\t\tcliModel,\n\t\tscopedModels,\n\t\tisContinuing,\n\t\tdefaultProvider,\n\t\tdefaultModelId,\n\t\tdefaultThinkingLevel,\n\t\tmodelRegistry,\n\t} = options;\n\n\tlet model: Model<Api> | undefined;\n\tlet thinkingLevel: ThinkingLevel = DEFAULT_THINKING_LEVEL;\n\n\t// 1. CLI args take priority\n\tif (cliProvider && cliModel) {\n\t\tconst resolved = resolveCliModel({\n\t\t\tcliProvider,\n\t\t\tcliModel,\n\t\t\tmodelRegistry,\n\t\t});\n\t\tif (resolved.error) {\n\t\t\tconsole.error(chalk.red(resolved.error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (resolved.model) {\n\t\t\treturn { model: resolved.model, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\n\t\t}\n\t}\n\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\n\tif (scopedModels.length > 0 && !isContinuing) {\n\t\treturn {\n\t\t\tmodel: scopedModels[0].model,\n\t\t\tthinkingLevel: scopedModels[0].thinkingLevel ?? defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,\n\t\t\tfallbackMessage: undefined,\n\t\t};\n\t}\n\n\t// 3. Try saved default from settings\n\t// SCRAMJET-DIVERGENCE: A removed configured identity must not silently switch routes at startup.\n\tlet missingDefault: string | undefined;\n\tif (defaultProvider && defaultModelId) {\n\t\tconst found = modelRegistry.find(defaultProvider, defaultModelId);\n\t\tif (found) {\n\t\t\tmodel = found;\n\t\t\tif (defaultThinkingLevel) {\n\t\t\t\tthinkingLevel = defaultThinkingLevel;\n\t\t\t}\n\t\t\treturn { model, thinkingLevel, fallbackMessage: undefined };\n\t\t}\n\t\tmissingDefault = `Configured default model ${defaultProvider}/${defaultModelId} is not in the model registry.`;\n\t}\n\n\t// 4. Try first available model with valid API key\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\treturn {\n\t\t\t\t\tmodel: match,\n\t\t\t\t\tthinkingLevel: DEFAULT_THINKING_LEVEL,\n\t\t\t\t\tfallbackMessage: missingDefault ? `${missingDefault} Using ${match.provider}/${match.id}.` : undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\tconst fallback = availableModels[0];\n\t\treturn {\n\t\t\tmodel: fallback,\n\t\t\tthinkingLevel: DEFAULT_THINKING_LEVEL,\n\t\t\tfallbackMessage: missingDefault ? `${missingDefault} Using ${fallback.provider}/${fallback.id}.` : undefined,\n\t\t};\n\t}\n\n\t// 5. No model found\n\treturn { model: undefined, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: missingDefault };\n}\n\n/**\n * Restore model from session, with fallback to available models\n */\nexport async function restoreModelFromSession(\n\tsavedProvider: string,\n\tsavedModelId: string,\n\tcurrentModel: Model<Api> | undefined,\n\tshouldPrintMessages: boolean,\n\tmodelRegistry: ModelRegistry,\n): Promise<{ model: Model<Api> | undefined; fallbackMessage: string | undefined }> {\n\tconst restoredModel = modelRegistry.find(savedProvider, savedModelId);\n\n\t// Check if restored model exists and still has auth configured\n\tconst hasConfiguredAuth = restoredModel ? modelRegistry.hasConfiguredAuth(restoredModel) : false;\n\n\tif (restoredModel && hasConfiguredAuth) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Restored model: ${savedProvider}/${savedModelId}`));\n\t\t}\n\t\treturn { model: restoredModel, fallbackMessage: undefined };\n\t}\n\n\t// Model not found or no API key - fall back\n\tconst reason = !restoredModel ? \"model no longer exists\" : \"no auth configured\";\n\n\tif (shouldPrintMessages) {\n\t\tconsole.error(chalk.yellow(`Warning: Could not restore model ${savedProvider}/${savedModelId} (${reason}).`));\n\t}\n\n\t// If we already have a model, use it as fallback\n\tif (currentModel) {\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${currentModel.provider}/${currentModel.id}`));\n\t\t}\n\t\treturn {\n\t\t\tmodel: currentModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${currentModel.provider}/${currentModel.id}.`,\n\t\t};\n\t}\n\n\t// Try to find any available model\n\tconst availableModels = await modelRegistry.getAvailable();\n\n\tif (availableModels.length > 0) {\n\t\t// Try to find a default model from known providers\n\t\tlet fallbackModel: Model<Api> | undefined;\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\n\t\t\tif (match) {\n\t\t\t\tfallbackModel = match;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// If no default found, use first available\n\t\tif (!fallbackModel) {\n\t\t\tfallbackModel = availableModels[0];\n\t\t}\n\n\t\tif (shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${fallbackModel.provider}/${fallbackModel.id}`));\n\t\t}\n\n\t\treturn {\n\t\t\tmodel: fallbackModel,\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${fallbackModel.provider}/${fallbackModel.id}.`,\n\t\t};\n\t}\n\n\t// No models available\n\treturn { model: undefined, fallbackMessage: undefined };\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import { OutputThroughputHistory, type OutputThroughputSample } from "./output-throughput.js";
2
+ export interface OutputThroughputHistoryDiagnostic {
3
+ operation: "refresh" | "lock" | "read" | "validate" | "write" | "rename" | "unlink" | "unlock";
4
+ path: string;
5
+ message: string;
6
+ cause?: unknown;
7
+ }
8
+ export declare class OutputThroughputHistoryStore {
9
+ readonly path: string;
10
+ private readonly onDiagnostic?;
11
+ private history;
12
+ private queueKey?;
13
+ private pending;
14
+ private readonly reportedDiagnostics;
15
+ constructor(path: string, onDiagnostic?: ((diagnostic: OutputThroughputHistoryDiagnostic) => void) | undefined);
16
+ snapshot(): OutputThroughputHistory;
17
+ refresh(): Promise<OutputThroughputHistory>;
18
+ submit(sample: OutputThroughputSample): void;
19
+ flush(): Promise<void>;
20
+ private update;
21
+ private readDocument;
22
+ private enqueue;
23
+ private report;
24
+ }
25
+ //# sourceMappingURL=output-throughput-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-throughput-history.d.ts","sourceRoot":"","sources":["../../src/core/output-throughput-history.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAE,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAU9F,MAAM,WAAW,iCAAiC;IACjD,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC/F,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAOD,qBAAa,4BAA4B;IAOvC,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAP/B,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,QAAQ,CAAC,CAAkB;IACnC,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IAEzD,YACU,IAAI,EAAE,MAAM,EACJ,YAAY,CAAC,uEAAyD,EACpF;IAEJ,QAAQ,IAAI,uBAAuB,CAElC;IAEK,OAAO,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAMhD;IAED,MAAM,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAO3C;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;YAEa,MAAM;YAqDN,YAAY;YA2BZ,OAAO;IAwBrB,OAAO,CAAC,MAAM;CAOd","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { mkdir, open, readFile, realpath, rename, unlink, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\nimport { OutputThroughputHistory, type OutputThroughputSample } from \"./output-throughput.js\";\n\n// SCRAMJET-DIVERGENCE: Persist bounded, profile-scoped provider throughput across concurrent processes (#476).\n\nconst HISTORY_VERSION = 1;\nconst MAX_SAMPLES_PER_MODEL = 20;\nconst MAX_HISTORY_SAMPLES = 20000;\nconst MAX_STRING_LENGTH = 512;\nconst queues = new Map<string, Promise<void>>();\n\nexport interface OutputThroughputHistoryDiagnostic {\n\toperation: \"refresh\" | \"lock\" | \"read\" | \"validate\" | \"write\" | \"rename\" | \"unlink\" | \"unlock\";\n\tpath: string;\n\tmessage: string;\n\tcause?: unknown;\n}\n\ninterface HistoryDocument {\n\tversion: 1;\n\tsamples: OutputThroughputSample[];\n}\n\nexport class OutputThroughputHistoryStore {\n\tprivate history = new OutputThroughputHistory();\n\tprivate queueKey?: Promise<string>;\n\tprivate pending: Promise<void> = Promise.resolve();\n\tprivate readonly reportedDiagnostics = new Set<string>();\n\n\tconstructor(\n\t\treadonly path: string,\n\t\tprivate readonly onDiagnostic?: (diagnostic: OutputThroughputHistoryDiagnostic) => void,\n\t) {}\n\n\tsnapshot(): OutputThroughputHistory {\n\t\treturn historyFromSamples(this.history.allSamples());\n\t}\n\n\tasync refresh(): Promise<OutputThroughputHistory> {\n\t\tawait this.enqueue(async () => {\n\t\t\tconst document = await this.readDocument(\"refresh\");\n\t\t\tif (document) this.history = historyFromSamples(document.samples);\n\t\t});\n\t\treturn this.snapshot();\n\t}\n\n\tsubmit(sample: OutputThroughputSample): void {\n\t\tif (!isValidSample(sample)) {\n\t\t\tthis.report(\"validate\", \"Invalid output-throughput sample was not persisted; existing history was preserved\");\n\t\t\treturn;\n\t\t}\n\t\tconst normalized = normalizeSample(sample);\n\t\tthis.pending = this.enqueue(() => this.update(normalized));\n\t}\n\n\tasync flush(): Promise<void> {\n\t\tawait this.pending;\n\t}\n\n\tprivate async update(sample: OutputThroughputSample): Promise<void> {\n\t\tawait mkdir(dirname(this.path), { recursive: true });\n\t\tconst anchorPath = join(dirname(this.path), `${basename(this.path, \".json\")}.lock`);\n\t\ttry {\n\t\t\tawait writeFile(anchorPath, \"\", { flag: \"a\" });\n\t\t} catch (cause) {\n\t\t\tthis.report(\"lock\", \"Could not prepare the throughput-history lock; existing history was preserved\", cause);\n\t\t\treturn;\n\t\t}\n\n\t\tlet release: (() => Promise<void>) | undefined;\n\t\ttry {\n\t\t\trelease = await lockfile.lock(anchorPath, {\n\t\t\t\trealpath: false,\n\t\t\t\tretries: { retries: 8, factor: 2, minTimeout: 25, maxTimeout: 1000, randomize: true },\n\t\t\t\tstale: 30000,\n\t\t\t});\n\t\t\tconst current = await this.readDocument(\"read\");\n\t\t\tif (!current) return;\n\t\t\tconst samples = mergeSamples(current.samples, sample);\n\t\t\tconst document: HistoryDocument = { version: HISTORY_VERSION, samples };\n\t\t\tconst temporaryPath = join(dirname(this.path), `.${basename(this.path)}.${process.pid}.${randomUUID()}.tmp`);\n\t\t\tlet temporaryCreated = false;\n\t\t\ttry {\n\t\t\t\tconst handle = await open(temporaryPath, \"wx\", 0o600);\n\t\t\t\ttemporaryCreated = true;\n\t\t\t\ttry {\n\t\t\t\t\tawait handle.writeFile(`${JSON.stringify(document, null, 2)}\\n`, \"utf8\");\n\t\t\t\t\tawait handle.sync();\n\t\t\t\t} finally {\n\t\t\t\t\tawait handle.close();\n\t\t\t\t}\n\t\t\t\tawait rename(temporaryPath, this.path);\n\t\t\t\ttemporaryCreated = false;\n\t\t\t\tthis.history = historyFromSamples(samples);\n\t\t\t} catch (cause) {\n\t\t\t\tthis.report(\"write\", \"Could not commit output-throughput history; existing history was preserved\", cause);\n\t\t\t} finally {\n\t\t\t\tif (temporaryCreated) {\n\t\t\t\t\tawait unlink(temporaryPath).catch((cause) => {\n\t\t\t\t\t\tthis.report(\"unlink\", \"Could not remove the temporary output-throughput history file\", cause);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (cause) {\n\t\t\tthis.report(\"lock\", \"Could not lock output-throughput history; existing history was preserved\", cause);\n\t\t} finally {\n\t\t\tawait release?.().catch((cause) => {\n\t\t\t\tthis.report(\"unlock\", \"Could not release the output-throughput history lock\", cause);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async readDocument(operation: \"refresh\" | \"read\"): Promise<HistoryDocument | undefined> {\n\t\tlet raw: string;\n\t\ttry {\n\t\t\traw = await readFile(this.path, \"utf8\");\n\t\t} catch (cause) {\n\t\t\tif (isMissingFile(cause)) return { version: HISTORY_VERSION, samples: [] };\n\t\t\tthis.report(\n\t\t\t\toperation,\n\t\t\t\t\"Could not read output-throughput history; the last valid snapshot was preserved\",\n\t\t\t\tcause,\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t\ttry {\n\t\t\tconst value: unknown = JSON.parse(raw);\n\t\t\tif (!isHistoryDocument(value)) throw new Error(\"unsupported version or invalid schema\");\n\t\t\treturn { version: HISTORY_VERSION, samples: value.samples.map(normalizeSample) };\n\t\t} catch (cause) {\n\t\t\tthis.report(\n\t\t\t\t\"validate\",\n\t\t\t\t\"Output-throughput history is malformed or unsupported; original bytes and the last valid snapshot were preserved\",\n\t\t\t\tcause,\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate async enqueue(operation: () => Promise<void>): Promise<void> {\n\t\ttry {\n\t\t\tif (!this.queueKey) this.queueKey = canonicalPath(this.path);\n\t\t\tconst queueKey = this.queueKey;\n\t\t\tlet key: string;\n\t\t\ttry {\n\t\t\t\tkey = await queueKey;\n\t\t\t} catch (cause) {\n\t\t\t\tif (this.queueKey === queueKey) this.queueKey = undefined;\n\t\t\t\tthrow cause;\n\t\t\t}\n\t\t\tconst previous = queues.get(key) ?? Promise.resolve();\n\t\t\tconst current = previous.catch(() => undefined).then(operation);\n\t\t\tqueues.set(key, current);\n\t\t\ttry {\n\t\t\t\tawait current;\n\t\t\t} finally {\n\t\t\t\tif (queues.get(key) === current) queues.delete(key);\n\t\t\t}\n\t\t} catch (cause) {\n\t\t\tthis.report(\"write\", \"Output-throughput history operation failed; existing history was preserved\", cause);\n\t\t}\n\t}\n\n\tprivate report(operation: OutputThroughputHistoryDiagnostic[\"operation\"], message: string, cause?: unknown): void {\n\t\tconst normalizedCause = cause instanceof Error ? cause.message : cause === undefined ? \"\" : String(cause);\n\t\tconst key = `${resolve(this.path)}\\0${operation}\\0${normalizedCause}`;\n\t\tif (this.reportedDiagnostics.has(key)) return;\n\t\tthis.reportedDiagnostics.add(key);\n\t\tthis.onDiagnostic?.({ operation, path: this.path, message, cause });\n\t}\n}\n\nasync function canonicalPath(path: string): Promise<string> {\n\tawait mkdir(dirname(path), { recursive: true });\n\tconst parent = await realpath(dirname(path));\n\treturn join(parent, basename(path));\n}\n\nfunction isHistoryDocument(value: unknown): value is HistoryDocument {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst document = value as { version?: unknown; samples?: unknown };\n\treturn (\n\t\tdocument.version === HISTORY_VERSION &&\n\t\tArray.isArray(document.samples) &&\n\t\tdocument.samples.length <= MAX_HISTORY_SAMPLES &&\n\t\tdocument.samples.every(isValidSample)\n\t);\n}\n\nfunction isValidSample(value: unknown): value is OutputThroughputSample {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst sample = value as Partial<OutputThroughputSample>;\n\treturn (\n\t\tisBoundedString(sample.provider) &&\n\t\tisBoundedString(sample.model) &&\n\t\t(sample.responseModel === undefined || isBoundedString(sample.responseModel)) &&\n\t\tisPositiveFinite(sample.outputTokens) &&\n\t\tisPositiveFinite(sample.durationMs) &&\n\t\tNumber.isFinite(sample.observedAt) &&\n\t\t(sample.observedAt ?? -1) >= 0\n\t);\n}\n\nfunction normalizeSample(sample: OutputThroughputSample): OutputThroughputSample {\n\treturn {\n\t\tprovider: sample.provider,\n\t\tmodel: sample.model,\n\t\t...(sample.responseModel === undefined ? {} : { responseModel: sample.responseModel }),\n\t\toutputTokens: sample.outputTokens,\n\t\tdurationMs: sample.durationMs,\n\t\tobservedAt: sample.observedAt,\n\t};\n}\n\nfunction isBoundedString(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.length > 0 && value.length <= MAX_STRING_LENGTH;\n}\n\nfunction isPositiveFinite(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\nfunction mergeSamples(\n\tsamples: readonly OutputThroughputSample[],\n\tadded: OutputThroughputSample,\n): OutputThroughputSample[] {\n\tconst unique = new Map<string, OutputThroughputSample>();\n\tfor (const sample of [...samples, added]) unique.set(sampleIdentity(sample), normalizeSample(sample));\n\tconst byModel = new Map<string, OutputThroughputSample[]>();\n\tfor (const sample of unique.values()) {\n\t\tconst key = `${sample.provider.length}:${sample.provider}${sample.model}`;\n\t\tconst group = byModel.get(key) ?? [];\n\t\tgroup.push(sample);\n\t\tbyModel.set(key, group);\n\t}\n\treturn [...byModel.values()]\n\t\t.flatMap((group) => group.sort((left, right) => left.observedAt - right.observedAt).slice(-MAX_SAMPLES_PER_MODEL))\n\t\t.sort((left, right) => left.observedAt - right.observedAt)\n\t\t.slice(-MAX_HISTORY_SAMPLES);\n}\n\nfunction sampleIdentity(sample: OutputThroughputSample): string {\n\treturn JSON.stringify([\n\t\tsample.provider,\n\t\tsample.model,\n\t\tsample.responseModel ?? null,\n\t\tsample.outputTokens,\n\t\tsample.durationMs,\n\t\tsample.observedAt,\n\t]);\n}\n\nfunction historyFromSamples(samples: readonly OutputThroughputSample[]): OutputThroughputHistory {\n\tconst history = new OutputThroughputHistory();\n\tfor (const sample of samples) history.add(sample);\n\treturn history;\n}\n\nfunction isMissingFile(cause: unknown): boolean {\n\treturn cause instanceof Error && \"code\" in cause && cause.code === \"ENOENT\";\n}\n"]}
@@ -0,0 +1,240 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdir, open, readFile, realpath, rename, unlink, writeFile } from "node:fs/promises";
3
+ import { basename, dirname, join, resolve } from "node:path";
4
+ import lockfile from "proper-lockfile";
5
+ import { OutputThroughputHistory } from "./output-throughput.js";
6
+ // SCRAMJET-DIVERGENCE: Persist bounded, profile-scoped provider throughput across concurrent processes (#476).
7
+ const HISTORY_VERSION = 1;
8
+ const MAX_SAMPLES_PER_MODEL = 20;
9
+ const MAX_HISTORY_SAMPLES = 20000;
10
+ const MAX_STRING_LENGTH = 512;
11
+ const queues = new Map();
12
+ export class OutputThroughputHistoryStore {
13
+ path;
14
+ onDiagnostic;
15
+ history = new OutputThroughputHistory();
16
+ queueKey;
17
+ pending = Promise.resolve();
18
+ reportedDiagnostics = new Set();
19
+ constructor(path, onDiagnostic) {
20
+ this.path = path;
21
+ this.onDiagnostic = onDiagnostic;
22
+ }
23
+ snapshot() {
24
+ return historyFromSamples(this.history.allSamples());
25
+ }
26
+ async refresh() {
27
+ await this.enqueue(async () => {
28
+ const document = await this.readDocument("refresh");
29
+ if (document)
30
+ this.history = historyFromSamples(document.samples);
31
+ });
32
+ return this.snapshot();
33
+ }
34
+ submit(sample) {
35
+ if (!isValidSample(sample)) {
36
+ this.report("validate", "Invalid output-throughput sample was not persisted; existing history was preserved");
37
+ return;
38
+ }
39
+ const normalized = normalizeSample(sample);
40
+ this.pending = this.enqueue(() => this.update(normalized));
41
+ }
42
+ async flush() {
43
+ await this.pending;
44
+ }
45
+ async update(sample) {
46
+ await mkdir(dirname(this.path), { recursive: true });
47
+ const anchorPath = join(dirname(this.path), `${basename(this.path, ".json")}.lock`);
48
+ try {
49
+ await writeFile(anchorPath, "", { flag: "a" });
50
+ }
51
+ catch (cause) {
52
+ this.report("lock", "Could not prepare the throughput-history lock; existing history was preserved", cause);
53
+ return;
54
+ }
55
+ let release;
56
+ try {
57
+ release = await lockfile.lock(anchorPath, {
58
+ realpath: false,
59
+ retries: { retries: 8, factor: 2, minTimeout: 25, maxTimeout: 1000, randomize: true },
60
+ stale: 30000,
61
+ });
62
+ const current = await this.readDocument("read");
63
+ if (!current)
64
+ return;
65
+ const samples = mergeSamples(current.samples, sample);
66
+ const document = { version: HISTORY_VERSION, samples };
67
+ const temporaryPath = join(dirname(this.path), `.${basename(this.path)}.${process.pid}.${randomUUID()}.tmp`);
68
+ let temporaryCreated = false;
69
+ try {
70
+ const handle = await open(temporaryPath, "wx", 0o600);
71
+ temporaryCreated = true;
72
+ try {
73
+ await handle.writeFile(`${JSON.stringify(document, null, 2)}\n`, "utf8");
74
+ await handle.sync();
75
+ }
76
+ finally {
77
+ await handle.close();
78
+ }
79
+ await rename(temporaryPath, this.path);
80
+ temporaryCreated = false;
81
+ this.history = historyFromSamples(samples);
82
+ }
83
+ catch (cause) {
84
+ this.report("write", "Could not commit output-throughput history; existing history was preserved", cause);
85
+ }
86
+ finally {
87
+ if (temporaryCreated) {
88
+ await unlink(temporaryPath).catch((cause) => {
89
+ this.report("unlink", "Could not remove the temporary output-throughput history file", cause);
90
+ });
91
+ }
92
+ }
93
+ }
94
+ catch (cause) {
95
+ this.report("lock", "Could not lock output-throughput history; existing history was preserved", cause);
96
+ }
97
+ finally {
98
+ await release?.().catch((cause) => {
99
+ this.report("unlock", "Could not release the output-throughput history lock", cause);
100
+ });
101
+ }
102
+ }
103
+ async readDocument(operation) {
104
+ let raw;
105
+ try {
106
+ raw = await readFile(this.path, "utf8");
107
+ }
108
+ catch (cause) {
109
+ if (isMissingFile(cause))
110
+ return { version: HISTORY_VERSION, samples: [] };
111
+ this.report(operation, "Could not read output-throughput history; the last valid snapshot was preserved", cause);
112
+ return undefined;
113
+ }
114
+ try {
115
+ const value = JSON.parse(raw);
116
+ if (!isHistoryDocument(value))
117
+ throw new Error("unsupported version or invalid schema");
118
+ return { version: HISTORY_VERSION, samples: value.samples.map(normalizeSample) };
119
+ }
120
+ catch (cause) {
121
+ this.report("validate", "Output-throughput history is malformed or unsupported; original bytes and the last valid snapshot were preserved", cause);
122
+ return undefined;
123
+ }
124
+ }
125
+ async enqueue(operation) {
126
+ try {
127
+ if (!this.queueKey)
128
+ this.queueKey = canonicalPath(this.path);
129
+ const queueKey = this.queueKey;
130
+ let key;
131
+ try {
132
+ key = await queueKey;
133
+ }
134
+ catch (cause) {
135
+ if (this.queueKey === queueKey)
136
+ this.queueKey = undefined;
137
+ throw cause;
138
+ }
139
+ const previous = queues.get(key) ?? Promise.resolve();
140
+ const current = previous.catch(() => undefined).then(operation);
141
+ queues.set(key, current);
142
+ try {
143
+ await current;
144
+ }
145
+ finally {
146
+ if (queues.get(key) === current)
147
+ queues.delete(key);
148
+ }
149
+ }
150
+ catch (cause) {
151
+ this.report("write", "Output-throughput history operation failed; existing history was preserved", cause);
152
+ }
153
+ }
154
+ report(operation, message, cause) {
155
+ const normalizedCause = cause instanceof Error ? cause.message : cause === undefined ? "" : String(cause);
156
+ const key = `${resolve(this.path)}\0${operation}\0${normalizedCause}`;
157
+ if (this.reportedDiagnostics.has(key))
158
+ return;
159
+ this.reportedDiagnostics.add(key);
160
+ this.onDiagnostic?.({ operation, path: this.path, message, cause });
161
+ }
162
+ }
163
+ async function canonicalPath(path) {
164
+ await mkdir(dirname(path), { recursive: true });
165
+ const parent = await realpath(dirname(path));
166
+ return join(parent, basename(path));
167
+ }
168
+ function isHistoryDocument(value) {
169
+ if (!value || typeof value !== "object")
170
+ return false;
171
+ const document = value;
172
+ return (document.version === HISTORY_VERSION &&
173
+ Array.isArray(document.samples) &&
174
+ document.samples.length <= MAX_HISTORY_SAMPLES &&
175
+ document.samples.every(isValidSample));
176
+ }
177
+ function isValidSample(value) {
178
+ if (!value || typeof value !== "object")
179
+ return false;
180
+ const sample = value;
181
+ return (isBoundedString(sample.provider) &&
182
+ isBoundedString(sample.model) &&
183
+ (sample.responseModel === undefined || isBoundedString(sample.responseModel)) &&
184
+ isPositiveFinite(sample.outputTokens) &&
185
+ isPositiveFinite(sample.durationMs) &&
186
+ Number.isFinite(sample.observedAt) &&
187
+ (sample.observedAt ?? -1) >= 0);
188
+ }
189
+ function normalizeSample(sample) {
190
+ return {
191
+ provider: sample.provider,
192
+ model: sample.model,
193
+ ...(sample.responseModel === undefined ? {} : { responseModel: sample.responseModel }),
194
+ outputTokens: sample.outputTokens,
195
+ durationMs: sample.durationMs,
196
+ observedAt: sample.observedAt,
197
+ };
198
+ }
199
+ function isBoundedString(value) {
200
+ return typeof value === "string" && value.length > 0 && value.length <= MAX_STRING_LENGTH;
201
+ }
202
+ function isPositiveFinite(value) {
203
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
204
+ }
205
+ function mergeSamples(samples, added) {
206
+ const unique = new Map();
207
+ for (const sample of [...samples, added])
208
+ unique.set(sampleIdentity(sample), normalizeSample(sample));
209
+ const byModel = new Map();
210
+ for (const sample of unique.values()) {
211
+ const key = `${sample.provider.length}:${sample.provider}${sample.model}`;
212
+ const group = byModel.get(key) ?? [];
213
+ group.push(sample);
214
+ byModel.set(key, group);
215
+ }
216
+ return [...byModel.values()]
217
+ .flatMap((group) => group.sort((left, right) => left.observedAt - right.observedAt).slice(-MAX_SAMPLES_PER_MODEL))
218
+ .sort((left, right) => left.observedAt - right.observedAt)
219
+ .slice(-MAX_HISTORY_SAMPLES);
220
+ }
221
+ function sampleIdentity(sample) {
222
+ return JSON.stringify([
223
+ sample.provider,
224
+ sample.model,
225
+ sample.responseModel ?? null,
226
+ sample.outputTokens,
227
+ sample.durationMs,
228
+ sample.observedAt,
229
+ ]);
230
+ }
231
+ function historyFromSamples(samples) {
232
+ const history = new OutputThroughputHistory();
233
+ for (const sample of samples)
234
+ history.add(sample);
235
+ return history;
236
+ }
237
+ function isMissingFile(cause) {
238
+ return cause instanceof Error && "code" in cause && cause.code === "ENOENT";
239
+ }
240
+ //# sourceMappingURL=output-throughput-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-throughput-history.js","sourceRoot":"","sources":["../../src/core/output-throughput-history.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { mkdir, open, readFile, realpath, rename, unlink, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\nimport { OutputThroughputHistory, type OutputThroughputSample } from \"./output-throughput.js\";\n\n// SCRAMJET-DIVERGENCE: Persist bounded, profile-scoped provider throughput across concurrent processes (#476).\n\nconst HISTORY_VERSION = 1;\nconst MAX_SAMPLES_PER_MODEL = 20;\nconst MAX_HISTORY_SAMPLES = 20000;\nconst MAX_STRING_LENGTH = 512;\nconst queues = new Map<string, Promise<void>>();\n\nexport interface OutputThroughputHistoryDiagnostic {\n\toperation: \"refresh\" | \"lock\" | \"read\" | \"validate\" | \"write\" | \"rename\" | \"unlink\" | \"unlock\";\n\tpath: string;\n\tmessage: string;\n\tcause?: unknown;\n}\n\ninterface HistoryDocument {\n\tversion: 1;\n\tsamples: OutputThroughputSample[];\n}\n\nexport class OutputThroughputHistoryStore {\n\tprivate history = new OutputThroughputHistory();\n\tprivate queueKey?: Promise<string>;\n\tprivate pending: Promise<void> = Promise.resolve();\n\tprivate readonly reportedDiagnostics = new Set<string>();\n\n\tconstructor(\n\t\treadonly path: string,\n\t\tprivate readonly onDiagnostic?: (diagnostic: OutputThroughputHistoryDiagnostic) => void,\n\t) {}\n\n\tsnapshot(): OutputThroughputHistory {\n\t\treturn historyFromSamples(this.history.allSamples());\n\t}\n\n\tasync refresh(): Promise<OutputThroughputHistory> {\n\t\tawait this.enqueue(async () => {\n\t\t\tconst document = await this.readDocument(\"refresh\");\n\t\t\tif (document) this.history = historyFromSamples(document.samples);\n\t\t});\n\t\treturn this.snapshot();\n\t}\n\n\tsubmit(sample: OutputThroughputSample): void {\n\t\tif (!isValidSample(sample)) {\n\t\t\tthis.report(\"validate\", \"Invalid output-throughput sample was not persisted; existing history was preserved\");\n\t\t\treturn;\n\t\t}\n\t\tconst normalized = normalizeSample(sample);\n\t\tthis.pending = this.enqueue(() => this.update(normalized));\n\t}\n\n\tasync flush(): Promise<void> {\n\t\tawait this.pending;\n\t}\n\n\tprivate async update(sample: OutputThroughputSample): Promise<void> {\n\t\tawait mkdir(dirname(this.path), { recursive: true });\n\t\tconst anchorPath = join(dirname(this.path), `${basename(this.path, \".json\")}.lock`);\n\t\ttry {\n\t\t\tawait writeFile(anchorPath, \"\", { flag: \"a\" });\n\t\t} catch (cause) {\n\t\t\tthis.report(\"lock\", \"Could not prepare the throughput-history lock; existing history was preserved\", cause);\n\t\t\treturn;\n\t\t}\n\n\t\tlet release: (() => Promise<void>) | undefined;\n\t\ttry {\n\t\t\trelease = await lockfile.lock(anchorPath, {\n\t\t\t\trealpath: false,\n\t\t\t\tretries: { retries: 8, factor: 2, minTimeout: 25, maxTimeout: 1000, randomize: true },\n\t\t\t\tstale: 30000,\n\t\t\t});\n\t\t\tconst current = await this.readDocument(\"read\");\n\t\t\tif (!current) return;\n\t\t\tconst samples = mergeSamples(current.samples, sample);\n\t\t\tconst document: HistoryDocument = { version: HISTORY_VERSION, samples };\n\t\t\tconst temporaryPath = join(dirname(this.path), `.${basename(this.path)}.${process.pid}.${randomUUID()}.tmp`);\n\t\t\tlet temporaryCreated = false;\n\t\t\ttry {\n\t\t\t\tconst handle = await open(temporaryPath, \"wx\", 0o600);\n\t\t\t\ttemporaryCreated = true;\n\t\t\t\ttry {\n\t\t\t\t\tawait handle.writeFile(`${JSON.stringify(document, null, 2)}\\n`, \"utf8\");\n\t\t\t\t\tawait handle.sync();\n\t\t\t\t} finally {\n\t\t\t\t\tawait handle.close();\n\t\t\t\t}\n\t\t\t\tawait rename(temporaryPath, this.path);\n\t\t\t\ttemporaryCreated = false;\n\t\t\t\tthis.history = historyFromSamples(samples);\n\t\t\t} catch (cause) {\n\t\t\t\tthis.report(\"write\", \"Could not commit output-throughput history; existing history was preserved\", cause);\n\t\t\t} finally {\n\t\t\t\tif (temporaryCreated) {\n\t\t\t\t\tawait unlink(temporaryPath).catch((cause) => {\n\t\t\t\t\t\tthis.report(\"unlink\", \"Could not remove the temporary output-throughput history file\", cause);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (cause) {\n\t\t\tthis.report(\"lock\", \"Could not lock output-throughput history; existing history was preserved\", cause);\n\t\t} finally {\n\t\t\tawait release?.().catch((cause) => {\n\t\t\t\tthis.report(\"unlock\", \"Could not release the output-throughput history lock\", cause);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async readDocument(operation: \"refresh\" | \"read\"): Promise<HistoryDocument | undefined> {\n\t\tlet raw: string;\n\t\ttry {\n\t\t\traw = await readFile(this.path, \"utf8\");\n\t\t} catch (cause) {\n\t\t\tif (isMissingFile(cause)) return { version: HISTORY_VERSION, samples: [] };\n\t\t\tthis.report(\n\t\t\t\toperation,\n\t\t\t\t\"Could not read output-throughput history; the last valid snapshot was preserved\",\n\t\t\t\tcause,\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t\ttry {\n\t\t\tconst value: unknown = JSON.parse(raw);\n\t\t\tif (!isHistoryDocument(value)) throw new Error(\"unsupported version or invalid schema\");\n\t\t\treturn { version: HISTORY_VERSION, samples: value.samples.map(normalizeSample) };\n\t\t} catch (cause) {\n\t\t\tthis.report(\n\t\t\t\t\"validate\",\n\t\t\t\t\"Output-throughput history is malformed or unsupported; original bytes and the last valid snapshot were preserved\",\n\t\t\t\tcause,\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate async enqueue(operation: () => Promise<void>): Promise<void> {\n\t\ttry {\n\t\t\tif (!this.queueKey) this.queueKey = canonicalPath(this.path);\n\t\t\tconst queueKey = this.queueKey;\n\t\t\tlet key: string;\n\t\t\ttry {\n\t\t\t\tkey = await queueKey;\n\t\t\t} catch (cause) {\n\t\t\t\tif (this.queueKey === queueKey) this.queueKey = undefined;\n\t\t\t\tthrow cause;\n\t\t\t}\n\t\t\tconst previous = queues.get(key) ?? Promise.resolve();\n\t\t\tconst current = previous.catch(() => undefined).then(operation);\n\t\t\tqueues.set(key, current);\n\t\t\ttry {\n\t\t\t\tawait current;\n\t\t\t} finally {\n\t\t\t\tif (queues.get(key) === current) queues.delete(key);\n\t\t\t}\n\t\t} catch (cause) {\n\t\t\tthis.report(\"write\", \"Output-throughput history operation failed; existing history was preserved\", cause);\n\t\t}\n\t}\n\n\tprivate report(operation: OutputThroughputHistoryDiagnostic[\"operation\"], message: string, cause?: unknown): void {\n\t\tconst normalizedCause = cause instanceof Error ? cause.message : cause === undefined ? \"\" : String(cause);\n\t\tconst key = `${resolve(this.path)}\\0${operation}\\0${normalizedCause}`;\n\t\tif (this.reportedDiagnostics.has(key)) return;\n\t\tthis.reportedDiagnostics.add(key);\n\t\tthis.onDiagnostic?.({ operation, path: this.path, message, cause });\n\t}\n}\n\nasync function canonicalPath(path: string): Promise<string> {\n\tawait mkdir(dirname(path), { recursive: true });\n\tconst parent = await realpath(dirname(path));\n\treturn join(parent, basename(path));\n}\n\nfunction isHistoryDocument(value: unknown): value is HistoryDocument {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst document = value as { version?: unknown; samples?: unknown };\n\treturn (\n\t\tdocument.version === HISTORY_VERSION &&\n\t\tArray.isArray(document.samples) &&\n\t\tdocument.samples.length <= MAX_HISTORY_SAMPLES &&\n\t\tdocument.samples.every(isValidSample)\n\t);\n}\n\nfunction isValidSample(value: unknown): value is OutputThroughputSample {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst sample = value as Partial<OutputThroughputSample>;\n\treturn (\n\t\tisBoundedString(sample.provider) &&\n\t\tisBoundedString(sample.model) &&\n\t\t(sample.responseModel === undefined || isBoundedString(sample.responseModel)) &&\n\t\tisPositiveFinite(sample.outputTokens) &&\n\t\tisPositiveFinite(sample.durationMs) &&\n\t\tNumber.isFinite(sample.observedAt) &&\n\t\t(sample.observedAt ?? -1) >= 0\n\t);\n}\n\nfunction normalizeSample(sample: OutputThroughputSample): OutputThroughputSample {\n\treturn {\n\t\tprovider: sample.provider,\n\t\tmodel: sample.model,\n\t\t...(sample.responseModel === undefined ? {} : { responseModel: sample.responseModel }),\n\t\toutputTokens: sample.outputTokens,\n\t\tdurationMs: sample.durationMs,\n\t\tobservedAt: sample.observedAt,\n\t};\n}\n\nfunction isBoundedString(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.length > 0 && value.length <= MAX_STRING_LENGTH;\n}\n\nfunction isPositiveFinite(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\nfunction mergeSamples(\n\tsamples: readonly OutputThroughputSample[],\n\tadded: OutputThroughputSample,\n): OutputThroughputSample[] {\n\tconst unique = new Map<string, OutputThroughputSample>();\n\tfor (const sample of [...samples, added]) unique.set(sampleIdentity(sample), normalizeSample(sample));\n\tconst byModel = new Map<string, OutputThroughputSample[]>();\n\tfor (const sample of unique.values()) {\n\t\tconst key = `${sample.provider.length}:${sample.provider}${sample.model}`;\n\t\tconst group = byModel.get(key) ?? [];\n\t\tgroup.push(sample);\n\t\tbyModel.set(key, group);\n\t}\n\treturn [...byModel.values()]\n\t\t.flatMap((group) => group.sort((left, right) => left.observedAt - right.observedAt).slice(-MAX_SAMPLES_PER_MODEL))\n\t\t.sort((left, right) => left.observedAt - right.observedAt)\n\t\t.slice(-MAX_HISTORY_SAMPLES);\n}\n\nfunction sampleIdentity(sample: OutputThroughputSample): string {\n\treturn JSON.stringify([\n\t\tsample.provider,\n\t\tsample.model,\n\t\tsample.responseModel ?? null,\n\t\tsample.outputTokens,\n\t\tsample.durationMs,\n\t\tsample.observedAt,\n\t]);\n}\n\nfunction historyFromSamples(samples: readonly OutputThroughputSample[]): OutputThroughputHistory {\n\tconst history = new OutputThroughputHistory();\n\tfor (const sample of samples) history.add(sample);\n\treturn history;\n}\n\nfunction isMissingFile(cause: unknown): boolean {\n\treturn cause instanceof Error && \"code\" in cause && cause.code === \"ENOENT\";\n}\n"]}
@@ -0,0 +1,43 @@
1
+ import type { AssistantMessage, AssistantMessageEvent } from "@leanandmean/ai";
2
+ export interface OutputThroughputIdentity {
3
+ provider: string;
4
+ model: string;
5
+ }
6
+ export interface OutputThroughputSample extends OutputThroughputIdentity {
7
+ responseModel?: string;
8
+ outputTokens: number;
9
+ durationMs: number;
10
+ observedAt: number;
11
+ }
12
+ export interface OutputThroughputTrackerOptions {
13
+ monotonicNow?: () => number;
14
+ wallNow?: () => number;
15
+ }
16
+ export declare class OutputThroughputTracker {
17
+ private readonly monotonicNow;
18
+ private readonly wallNow;
19
+ private active?;
20
+ private nextGeneration;
21
+ constructor(options?: OutputThroughputTrackerOptions);
22
+ get generation(): number;
23
+ get outputActive(): boolean;
24
+ get activeIdentity(): OutputThroughputIdentity | undefined;
25
+ start(identity: OutputThroughputIdentity): number;
26
+ reset(): void;
27
+ observe(generation: number, event: AssistantMessageEvent): void;
28
+ liveRate(): number | undefined;
29
+ finalize(generation: number, message: AssistantMessage): OutputThroughputSample | undefined;
30
+ }
31
+ export declare class OutputThroughputHistory {
32
+ private readonly samplesByModel;
33
+ add(sample: OutputThroughputSample): void;
34
+ samples(provider: string, model: string): readonly OutputThroughputSample[];
35
+ allSamples(): readonly OutputThroughputSample[];
36
+ latestSample(provider: string, model: string): OutputThroughputSample | undefined;
37
+ latestRate(provider: string, model: string): number | undefined;
38
+ median(provider: string, model: string): number | undefined;
39
+ }
40
+ export declare function formatLiveOutputRate(rate: number): string | undefined;
41
+ export declare function formatCompletedOutputRate(rate: number): string | undefined;
42
+ export declare function formatHistoricalOutputRate(rate: number): string | undefined;
43
+ //# sourceMappingURL=output-throughput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-throughput.d.ts","sourceRoot":"","sources":["../../src/core/output-throughput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAS/E,MAAM,WAAW,wBAAwB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAuB,SAAQ,wBAAwB;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,8BAA8B;IAC9C,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;CACvB;AAYD,qBAAa,uBAAuB;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,MAAM,CAAC,CAAoB;IACnC,OAAO,CAAC,cAAc,CAAK;IAE3B,YAAY,OAAO,GAAE,8BAAmC,EAGvD;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,IAAI,cAAc,IAAI,wBAAwB,GAAG,SAAS,CAEzD;IAED,KAAK,CAAC,QAAQ,EAAE,wBAAwB,GAAG,MAAM,CAIhD;IAED,KAAK,IAAI,IAAI,CAGZ;IAED,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,IAAI,CAK9D;IAED,QAAQ,IAAI,MAAM,GAAG,SAAS,CAa7B;IAED,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,sBAAsB,GAAG,SAAS,CAgC1F;CACD;AAED,qBAAa,uBAAuB;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA+C;IAE9E,GAAG,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAOxC;IAED,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,sBAAsB,EAAE,CAE1E;IAED,UAAU,IAAI,SAAS,sBAAsB,EAAE,CAE9C;IAED,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,sBAAsB,GAAG,SAAS,CAEhF;IAED,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK9D;IAED,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQ1D;CACD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAErE;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG1E;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE3E","sourcesContent":["import type { AssistantMessage, AssistantMessageEvent } from \"@leanandmean/ai\";\n\n// SCRAMJET-DIVERGENCE: Measure and aggregate qualified provider output throughput by requested model (#476).\n\nconst LIVE_WINDOW_MS = 2000;\nconst BYTES_PER_TOKEN = 4;\nconst MAX_SAMPLES_PER_MODEL = 20;\nconst encoder = new TextEncoder();\n\nexport interface OutputThroughputIdentity {\n\tprovider: string;\n\tmodel: string;\n}\n\nexport interface OutputThroughputSample extends OutputThroughputIdentity {\n\tresponseModel?: string;\n\toutputTokens: number;\n\tdurationMs: number;\n\tobservedAt: number;\n}\n\nexport interface OutputThroughputTrackerOptions {\n\tmonotonicNow?: () => number;\n\twallNow?: () => number;\n}\n\ninterface Observation {\n\ttime: number;\n\ttokens: number;\n}\n\ninterface ActiveMeasurement extends OutputThroughputIdentity {\n\tgeneration: number;\n\tobservations: Observation[];\n}\n\nexport class OutputThroughputTracker {\n\tprivate readonly monotonicNow: () => number;\n\tprivate readonly wallNow: () => number;\n\tprivate active?: ActiveMeasurement;\n\tprivate nextGeneration = 0;\n\n\tconstructor(options: OutputThroughputTrackerOptions = {}) {\n\t\tthis.monotonicNow = options.monotonicNow ?? (() => performance.now());\n\t\tthis.wallNow = options.wallNow ?? (() => Date.now());\n\t}\n\n\tget generation(): number {\n\t\treturn this.nextGeneration;\n\t}\n\n\tget outputActive(): boolean {\n\t\treturn (this.active?.observations.length ?? 0) > 0;\n\t}\n\n\tget activeIdentity(): OutputThroughputIdentity | undefined {\n\t\treturn this.active ? { provider: this.active.provider, model: this.active.model } : undefined;\n\t}\n\n\tstart(identity: OutputThroughputIdentity): number {\n\t\tconst generation = ++this.nextGeneration;\n\t\tthis.active = { ...identity, generation, observations: [] };\n\t\treturn generation;\n\t}\n\n\treset(): void {\n\t\tthis.nextGeneration++;\n\t\tthis.active = undefined;\n\t}\n\n\tobserve(generation: number, event: AssistantMessageEvent): void {\n\t\tif (generation !== this.active?.generation || !isGeneratedDelta(event) || event.delta.length === 0) return;\n\t\tconst time = this.monotonicNow();\n\t\tif (!Number.isFinite(time)) return;\n\t\tthis.active.observations.push({ time, tokens: encoder.encode(event.delta).byteLength / BYTES_PER_TOKEN });\n\t}\n\n\tliveRate(): number | undefined {\n\t\tif (!this.active) return undefined;\n\t\tconst now = this.monotonicNow();\n\t\tif (!Number.isFinite(now)) return undefined;\n\t\tconst cutoff = now - LIVE_WINDOW_MS;\n\t\tconst retained = this.active.observations.filter((observation) => observation.time >= cutoff);\n\t\tconst first = retained[0];\n\t\tif (!first) return undefined;\n\t\tconst elapsedMs = now - first.time;\n\t\tif (!(elapsedMs > 0)) return undefined;\n\t\tconst tokens = retained.reduce((total, observation) => total + observation.tokens, 0);\n\t\tconst rate = (tokens * 1000) / elapsedMs;\n\t\treturn Number.isFinite(rate) && rate > 0 ? rate : undefined;\n\t}\n\n\tfinalize(generation: number, message: AssistantMessage): OutputThroughputSample | undefined {\n\t\tif (generation !== this.active?.generation) return undefined;\n\t\tconst active = this.active;\n\t\tthis.reset();\n\t\tconst first = active.observations[0];\n\t\tconst last = active.observations.at(-1);\n\t\tconst outputTokens = message.usage.output;\n\t\tif (\n\t\t\tmessage.origin !== \"provider\" ||\n\t\t\tmessage.provider !== active.provider ||\n\t\t\tmessage.model !== active.model ||\n\t\t\t!isSuccessfulStop(message.stopReason) ||\n\t\t\t!Number.isFinite(outputTokens) ||\n\t\t\toutputTokens <= 0 ||\n\t\t\tactive.observations.length < 2 ||\n\t\t\t!first ||\n\t\t\t!last\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst durationMs = last.time - first.time;\n\t\tif (!Number.isFinite(durationMs) || durationMs <= 0) return undefined;\n\t\tconst observedAt = this.wallNow();\n\t\tif (!Number.isFinite(observedAt)) return undefined;\n\t\treturn {\n\t\t\tprovider: active.provider,\n\t\t\tmodel: active.model,\n\t\t\t...(message.responseModel ? { responseModel: message.responseModel } : {}),\n\t\t\toutputTokens,\n\t\t\tdurationMs,\n\t\t\tobservedAt,\n\t\t};\n\t}\n}\n\nexport class OutputThroughputHistory {\n\tprivate readonly samplesByModel = new Map<string, OutputThroughputSample[]>();\n\n\tadd(sample: OutputThroughputSample): void {\n\t\tif (!isValidSample(sample)) return;\n\t\tconst key = modelKey(sample.provider, sample.model);\n\t\tconst samples = [...(this.samplesByModel.get(key) ?? []), { ...sample }]\n\t\t\t.sort((left, right) => left.observedAt - right.observedAt)\n\t\t\t.slice(-MAX_SAMPLES_PER_MODEL);\n\t\tthis.samplesByModel.set(key, samples);\n\t}\n\n\tsamples(provider: string, model: string): readonly OutputThroughputSample[] {\n\t\treturn (this.samplesByModel.get(modelKey(provider, model)) ?? []).map((sample) => ({ ...sample }));\n\t}\n\n\tallSamples(): readonly OutputThroughputSample[] {\n\t\treturn [...this.samplesByModel.values()].flat().map((sample) => ({ ...sample }));\n\t}\n\n\tlatestSample(provider: string, model: string): OutputThroughputSample | undefined {\n\t\treturn this.samples(provider, model).at(-1);\n\t}\n\n\tlatestRate(provider: string, model: string): number | undefined {\n\t\tconst sample = this.latestSample(provider, model);\n\t\tif (!sample) return undefined;\n\t\tconst rate = (sample.outputTokens * 1000) / sample.durationMs;\n\t\treturn Number.isFinite(rate) && rate > 0 ? rate : undefined;\n\t}\n\n\tmedian(provider: string, model: string): number | undefined {\n\t\tconst rates = this.samples(provider, model)\n\t\t\t.map((sample) => (sample.outputTokens * 1000) / sample.durationMs)\n\t\t\t.filter((rate) => Number.isFinite(rate) && rate > 0)\n\t\t\t.sort((left, right) => left - right);\n\t\tif (rates.length === 0) return undefined;\n\t\tconst middle = Math.floor(rates.length / 2);\n\t\treturn rates.length % 2 === 0 ? ((rates[middle - 1] ?? 0) + (rates[middle] ?? 0)) / 2 : rates[middle];\n\t}\n}\n\nexport function formatLiveOutputRate(rate: number): string | undefined {\n\treturn formatCompletedOutputRate(rate);\n}\n\nexport function formatCompletedOutputRate(rate: number): string | undefined {\n\tif (!Number.isFinite(rate) || rate <= 0) return undefined;\n\treturn `${Math.round(rate)}tok/s`;\n}\n\nexport function formatHistoricalOutputRate(rate: number): string | undefined {\n\treturn formatCompletedOutputRate(rate);\n}\n\nfunction isGeneratedDelta(\n\tevent: AssistantMessageEvent,\n): event is Extract<AssistantMessageEvent, { type: \"text_delta\" | \"thinking_delta\" | \"toolcall_delta\" }> {\n\treturn event.type === \"text_delta\" || event.type === \"thinking_delta\" || event.type === \"toolcall_delta\";\n}\n\nfunction isSuccessfulStop(stopReason: AssistantMessage[\"stopReason\"]): boolean {\n\treturn stopReason === \"stop\" || stopReason === \"length\" || stopReason === \"toolUse\";\n}\n\nfunction isValidSample(sample: OutputThroughputSample): boolean {\n\treturn (\n\t\tsample.provider.length > 0 &&\n\t\tsample.model.length > 0 &&\n\t\tNumber.isFinite(sample.outputTokens) &&\n\t\tsample.outputTokens > 0 &&\n\t\tNumber.isFinite(sample.durationMs) &&\n\t\tsample.durationMs > 0 &&\n\t\tNumber.isFinite(sample.observedAt)\n\t);\n}\n\nfunction modelKey(provider: string, model: string): string {\n\treturn `${provider.length}:${provider}${model}`;\n}\n"]}