@ebowwa/coder 0.7.63 → 0.7.65
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.
- package/dist/core/__tests__/permissions.test.d.ts +12 -0
- package/dist/core/__tests__/permissions.test.d.ts.map +1 -0
- package/dist/core/__tests__/permissions.test.js +851 -0
- package/dist/core/agent-loop/__tests__/compaction.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/compaction.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/compaction.test.js +209 -0
- package/dist/core/agent-loop/__tests__/formatters.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/formatters.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/formatters.test.js +195 -0
- package/dist/core/agent-loop/__tests__/index.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/index.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/index.test.js +121 -0
- package/dist/core/agent-loop/__tests__/loop-state.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/loop-state.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/loop-state.test.js +340 -0
- package/dist/core/agent-loop/__tests__/message-builder.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/message-builder.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/message-builder.test.js +178 -0
- package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts +5 -0
- package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts.map +1 -0
- package/dist/core/agent-loop/__tests__/tool-executor.test.js +331 -0
- package/dist/core/agent-loop/compaction.d.ts +39 -0
- package/dist/core/agent-loop/compaction.d.ts.map +1 -0
- package/dist/core/agent-loop/compaction.js +51 -0
- package/dist/core/agent-loop/formatters.d.ts +21 -0
- package/dist/core/agent-loop/formatters.d.ts.map +1 -0
- package/dist/core/agent-loop/formatters.js +42 -0
- package/dist/core/agent-loop/index.d.ts +25 -0
- package/dist/core/agent-loop/index.d.ts.map +1 -0
- package/dist/core/agent-loop/index.js +83 -0
- package/dist/core/agent-loop/loop-state.d.ts +74 -0
- package/dist/core/agent-loop/loop-state.d.ts.map +1 -0
- package/dist/core/agent-loop/loop-state.js +147 -0
- package/dist/core/agent-loop/message-builder.d.ts +13 -0
- package/dist/core/agent-loop/message-builder.d.ts.map +1 -0
- package/dist/core/agent-loop/message-builder.js +49 -0
- package/dist/core/agent-loop/tool-executor.d.ts +23 -0
- package/dist/core/agent-loop/tool-executor.d.ts.map +1 -0
- package/dist/core/agent-loop/tool-executor.js +152 -0
- package/dist/core/agent-loop/turn-executor.d.ts +57 -0
- package/dist/core/agent-loop/turn-executor.d.ts.map +1 -0
- package/dist/core/agent-loop/turn-executor.js +124 -0
- package/dist/core/agent-loop/types.d.ts +141 -0
- package/dist/core/agent-loop/types.d.ts.map +1 -0
- package/dist/core/agent-loop/types.js +4 -0
- package/dist/core/agent-loop.d.ts +17 -0
- package/dist/core/agent-loop.d.ts.map +1 -0
- package/dist/core/agent-loop.js +16 -0
- package/dist/core/api-client-impl.d.ts +62 -0
- package/dist/core/api-client-impl.d.ts.map +1 -0
- package/dist/core/api-client-impl.js +479 -0
- package/dist/core/api-client.d.ts +6 -0
- package/dist/core/api-client.d.ts.map +1 -0
- package/dist/core/api-client.js +5 -0
- package/dist/core/checkpoints.d.ts +128 -0
- package/dist/core/checkpoints.d.ts.map +1 -0
- package/dist/core/checkpoints.js +438 -0
- package/dist/core/claude-md.d.ts +71 -0
- package/dist/core/claude-md.d.ts.map +1 -0
- package/dist/core/claude-md.js +198 -0
- package/dist/core/cognitive-security/hooks.d.ts +138 -0
- package/dist/core/cognitive-security/hooks.d.ts.map +1 -0
- package/dist/core/cognitive-security/hooks.js +389 -0
- package/dist/core/cognitive-security/index.d.ts +751 -0
- package/dist/core/cognitive-security/index.d.ts.map +1 -0
- package/dist/core/cognitive-security/index.js +1123 -0
- package/dist/core/cognitive-security/middleware.d.ts +136 -0
- package/dist/core/cognitive-security/middleware.d.ts.map +1 -0
- package/dist/core/cognitive-security/middleware.js +376 -0
- package/dist/core/config-loader.d.ts +127 -0
- package/dist/core/config-loader.d.ts.map +1 -0
- package/dist/core/config-loader.js +219 -0
- package/dist/core/context-compaction.d.ts +87 -0
- package/dist/core/context-compaction.d.ts.map +1 -0
- package/dist/core/context-compaction.js +428 -0
- package/dist/core/git-status.d.ts +25 -0
- package/dist/core/git-status.d.ts.map +1 -0
- package/dist/core/git-status.js +204 -0
- package/dist/core/image.d.ts +69 -0
- package/dist/core/image.d.ts.map +1 -0
- package/dist/core/image.js +290 -0
- package/dist/core/image.test.d.ts +2 -0
- package/dist/core/image.test.d.ts.map +1 -0
- package/dist/core/image.test.js +149 -0
- package/dist/core/models.d.ts +123 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +325 -0
- package/dist/core/permissions.d.ts +81 -0
- package/dist/core/permissions.d.ts.map +1 -0
- package/dist/core/permissions.js +327 -0
- package/dist/core/retry.d.ts +25 -0
- package/dist/core/retry.d.ts.map +1 -0
- package/dist/core/retry.js +121 -0
- package/dist/core/session-store.d.ts +9 -0
- package/dist/core/session-store.d.ts.map +1 -0
- package/dist/core/session-store.js +10 -0
- package/dist/core/sessions/export.d.ts +47 -0
- package/dist/core/sessions/export.d.ts.map +1 -0
- package/dist/core/sessions/export.js +256 -0
- package/dist/core/sessions/index.d.ts +132 -0
- package/dist/core/sessions/index.d.ts.map +1 -0
- package/dist/core/sessions/index.js +442 -0
- package/dist/core/sessions/metadata.d.ts +77 -0
- package/dist/core/sessions/metadata.d.ts.map +1 -0
- package/dist/core/sessions/metadata.js +233 -0
- package/dist/core/sessions/persistence.d.ts +72 -0
- package/dist/core/sessions/persistence.d.ts.map +1 -0
- package/dist/core/sessions/persistence.js +201 -0
- package/dist/core/sessions/types.d.ts +110 -0
- package/dist/core/sessions/types.d.ts.map +1 -0
- package/dist/core/sessions/types.js +4 -0
- package/dist/core/stream-highlighter.d.ts +18 -0
- package/dist/core/stream-highlighter.d.ts.map +1 -0
- package/dist/core/stream-highlighter.js +916 -0
- package/dist/core/system-reminders.d.ts +89 -0
- package/dist/core/system-reminders.d.ts.map +1 -0
- package/dist/core/system-reminders.js +285 -0
- package/dist/ecosystem/hooks/__tests__/index.test.d.ts +5 -0
- package/dist/ecosystem/hooks/__tests__/index.test.d.ts.map +1 -0
- package/dist/ecosystem/hooks/__tests__/index.test.js +458 -0
- package/dist/ecosystem/hooks/index.d.ts +59 -0
- package/dist/ecosystem/hooks/index.d.ts.map +1 -0
- package/dist/ecosystem/hooks/index.js +294 -0
- package/dist/ecosystem/hooks/prompt-evaluator.d.ts +32 -0
- package/dist/ecosystem/hooks/prompt-evaluator.d.ts.map +1 -0
- package/dist/ecosystem/hooks/prompt-evaluator.js +229 -0
- package/dist/ecosystem/skills/index.d.ts +55 -0
- package/dist/ecosystem/skills/index.d.ts.map +1 -0
- package/dist/ecosystem/skills/index.js +258 -0
- package/dist/ecosystem/tools/__tests__/index.test.d.ts +7 -0
- package/dist/ecosystem/tools/__tests__/index.test.d.ts.map +1 -0
- package/dist/ecosystem/tools/__tests__/index.test.js +856 -0
- package/dist/ecosystem/tools/index.d.ts +24 -0
- package/dist/ecosystem/tools/index.d.ts.map +1 -0
- package/dist/ecosystem/tools/index.js +1709 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33688 -49712
- package/dist/interfaces/mcp/client.d.ts +40 -0
- package/dist/interfaces/mcp/client.d.ts.map +1 -0
- package/dist/interfaces/mcp/client.js +309 -0
- package/dist/interfaces/ui/index.d.ts +36 -0
- package/dist/interfaces/ui/index.d.ts.map +1 -0
- package/dist/interfaces/ui/index.js +61 -0
- package/dist/interfaces/ui/spinner.d.ts +140 -0
- package/dist/interfaces/ui/spinner.d.ts.map +1 -0
- package/dist/interfaces/ui/spinner.js +342 -0
- package/dist/interfaces/ui/terminal/cli/index.d.ts +12 -0
- package/dist/interfaces/ui/terminal/cli/index.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/cli/index.js +32012 -50526
- package/dist/interfaces/ui/terminal/native/README.md +53 -0
- package/dist/interfaces/ui/terminal/native/claude_code_native.darwin-x64.node +0 -0
- package/dist/interfaces/ui/terminal/native/claude_code_native.dylib +0 -0
- package/dist/interfaces/ui/terminal/native/index.d.ts +0 -0
- package/dist/interfaces/ui/terminal/native/index.darwin-arm64.node +0 -0
- package/dist/interfaces/ui/terminal/native/index.js +43 -0
- package/dist/interfaces/ui/terminal/native/index.node +0 -0
- package/dist/interfaces/ui/terminal/native/package.json +34 -0
- package/dist/interfaces/ui/terminal/shared/args.d.ts +39 -0
- package/dist/interfaces/ui/terminal/shared/args.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/args.js +176 -0
- package/dist/interfaces/ui/terminal/shared/index.d.ts +11 -0
- package/dist/interfaces/ui/terminal/shared/index.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/index.js +16 -0
- package/dist/interfaces/ui/terminal/shared/loading-state.d.ts +124 -0
- package/dist/interfaces/ui/terminal/shared/loading-state.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/loading-state.js +246 -0
- package/dist/interfaces/ui/terminal/shared/query.d.ts +22 -0
- package/dist/interfaces/ui/terminal/shared/query.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/query.js +100 -0
- package/dist/interfaces/ui/terminal/shared/setup.d.ts +33 -0
- package/dist/interfaces/ui/terminal/shared/setup.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/setup.js +226 -0
- package/dist/interfaces/ui/terminal/shared/status-line.d.ts +117 -0
- package/dist/interfaces/ui/terminal/shared/status-line.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/status-line.js +267 -0
- package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts +38 -0
- package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/shared/system-prompt.js +102 -0
- package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts +39 -0
- package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/HelpPanel.js +215 -0
- package/dist/interfaces/ui/terminal/tui/InputContext.d.ts +91 -0
- package/dist/interfaces/ui/terminal/tui/InputContext.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/InputContext.js +154 -0
- package/dist/interfaces/ui/terminal/tui/InputField.d.ts +18 -0
- package/dist/interfaces/ui/terminal/tui/InputField.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/InputField.js +41 -0
- package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts +16 -0
- package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/InteractiveTUI.js +451 -0
- package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts +10 -0
- package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/MessageArea.js +91 -0
- package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts +48 -0
- package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/MessageStore.js +151 -0
- package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts +9 -0
- package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/StatusBar.js +36 -0
- package/dist/interfaces/ui/terminal/tui/commands.d.ts +21 -0
- package/dist/interfaces/ui/terminal/tui/commands.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/commands.js +359 -0
- package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts +115 -0
- package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.js +306 -0
- package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts +92 -0
- package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/MultilineInput.js +399 -0
- package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts +59 -0
- package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/PaneManager.js +139 -0
- package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts +68 -0
- package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/Sidebar.js +340 -0
- package/dist/interfaces/ui/terminal/tui/components/index.d.ts +23 -0
- package/dist/interfaces/ui/terminal/tui/components/index.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/components/index.js +51 -0
- package/dist/interfaces/ui/terminal/tui/console.d.ts +20 -0
- package/dist/interfaces/ui/terminal/tui/console.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/console.js +46 -0
- package/dist/interfaces/ui/terminal/tui/index.d.ts +20 -0
- package/dist/interfaces/ui/terminal/tui/index.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/index.js +28 -0
- package/dist/interfaces/ui/terminal/tui/run.d.ts +13 -0
- package/dist/interfaces/ui/terminal/tui/run.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/run.js +31 -0
- package/dist/interfaces/ui/terminal/tui/spinner.d.ts +44 -0
- package/dist/interfaces/ui/terminal/tui/spinner.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/spinner.js +59 -0
- package/dist/interfaces/ui/terminal/tui/tui-app.d.ts +39 -0
- package/dist/interfaces/ui/terminal/tui/tui-app.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/tui-app.js +198 -0
- package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts +167 -0
- package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/tui-footer.js +330 -0
- package/dist/interfaces/ui/terminal/tui/types.d.ts +165 -0
- package/dist/interfaces/ui/terminal/tui/types.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/types.js +5 -0
- package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts +23 -0
- package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/useInputHandler.js +72 -0
- package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts +90 -0
- package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts.map +1 -0
- package/dist/interfaces/ui/terminal/tui/useNativeInput.js +188 -0
- package/dist/native/README.md +53 -0
- package/dist/native/claude_code_native.darwin-x64.node +0 -0
- package/dist/native/claude_code_native.dylib +0 -0
- package/dist/native/index.d.ts +0 -0
- package/dist/native/index.d.ts.map +1 -0
- package/dist/native/index.darwin-arm64.node +0 -0
- package/dist/native/index.js +43 -0
- package/dist/native/index.node +0 -0
- package/dist/native/package.json +34 -0
- package/dist/teammates/index.d.ts +161 -0
- package/dist/teammates/index.d.ts.map +1 -0
- package/dist/teammates/index.js +827 -0
- package/dist/types/index.d.ts +482 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +52 -0
- package/native/index.darwin-arm64.node +0 -0
- package/native/index.js +33 -19
- package/package.json +6 -3
- package/packages/src/core/__tests__/permissions.test.ts +1091 -0
- package/packages/src/core/agent-loop/__tests__/compaction.test.ts +283 -0
- package/packages/src/core/agent-loop/__tests__/formatters.test.ts +234 -0
- package/packages/src/core/agent-loop/__tests__/index.test.ts +162 -0
- package/packages/src/core/agent-loop/__tests__/loop-state.test.ts +413 -0
- package/packages/src/core/agent-loop/__tests__/message-builder.test.ts +229 -0
- package/packages/src/core/agent-loop/__tests__/tool-executor.test.ts +457 -0
- package/packages/src/core/agent-loop/compaction.ts +92 -0
- package/packages/src/core/agent-loop/formatters.ts +50 -0
- package/packages/src/core/agent-loop/index.ts +137 -0
- package/packages/src/core/agent-loop/loop-state.ts +187 -0
- package/packages/src/core/agent-loop/message-builder.ts +62 -0
- package/packages/src/core/agent-loop/tool-executor.ts +211 -0
- package/packages/src/core/agent-loop/turn-executor.ts +226 -0
- package/packages/src/core/agent-loop/types.ts +152 -0
- package/packages/src/core/agent-loop.ts +18 -0
- package/packages/src/core/api-client-impl.ts +729 -0
- package/packages/src/core/api-client.ts +6 -0
- package/packages/src/core/checkpoints.ts +606 -0
- package/packages/src/core/claude-md.ts +272 -0
- package/packages/src/core/cognitive-security/hooks.ts +591 -0
- package/packages/src/core/cognitive-security/index.ts +2041 -0
- package/packages/src/core/cognitive-security/middleware.ts +536 -0
- package/packages/src/core/config/todo +7 -0
- package/packages/src/core/config-loader.ts +324 -0
- package/packages/src/core/context/__tests__/integration.test.ts +334 -0
- package/packages/src/core/context/compaction.ts +170 -0
- package/packages/src/core/context/constants.ts +58 -0
- package/packages/src/core/context/extraction.ts +85 -0
- package/packages/src/core/context/index.ts +66 -0
- package/packages/src/core/context/summarization.ts +251 -0
- package/packages/src/core/context/token-estimation.ts +98 -0
- package/packages/src/core/context/types.ts +59 -0
- package/packages/src/core/git-status.ts +262 -0
- package/packages/src/core/image.test.ts +180 -0
- package/packages/src/core/image.ts +350 -0
- package/packages/src/core/lmdb.db +0 -0
- package/packages/src/core/lmdb.db-lock +0 -0
- package/packages/src/core/models.ts +507 -0
- package/packages/src/core/normalizers/todo +8 -0
- package/packages/src/core/permissions.ts +431 -0
- package/packages/src/core/providers/README.md +230 -0
- package/packages/src/core/providers/__tests__/providers.test.ts +135 -0
- package/packages/src/core/providers/index.ts +419 -0
- package/packages/src/core/providers/types.ts +132 -0
- package/packages/src/core/retry.ts +180 -0
- package/packages/src/core/session-store.ts +36 -0
- package/packages/src/core/sessions/export.ts +329 -0
- package/packages/src/core/sessions/index.ts +587 -0
- package/packages/src/core/sessions/metadata.ts +309 -0
- package/packages/src/core/sessions/persistence.ts +244 -0
- package/packages/src/core/sessions/types.ts +169 -0
- package/packages/src/core/stream-highlighter.ts +1123 -0
- package/packages/src/core/system-reminders.ts +402 -0
- package/packages/src/core/todo +8 -0
- package/packages/src/ecosystem/hooks/__tests__/index.test.ts +561 -0
- package/packages/src/ecosystem/hooks/index.ts +341 -0
- package/packages/src/ecosystem/hooks/prompt-evaluator.ts +300 -0
- package/packages/src/ecosystem/skills/index.ts +295 -0
- package/packages/src/ecosystem/tools/__tests__/index.test.ts +1335 -0
- package/packages/src/ecosystem/tools/index.ts +2051 -0
- package/packages/src/index.ts +141 -0
- package/packages/src/interfaces/mcp/client.ts +389 -0
- package/packages/src/interfaces/ui/index.ts +158 -0
- package/packages/src/interfaces/ui/lmdb.db +0 -0
- package/packages/src/interfaces/ui/lmdb.db-lock +0 -0
- package/packages/src/interfaces/ui/spinner.ts +451 -0
- package/packages/src/interfaces/ui/terminal/bridge/index.ts +370 -0
- package/packages/src/interfaces/ui/terminal/bridge/ipc.ts +829 -0
- package/packages/src/interfaces/ui/terminal/bridge/screen-export.ts +968 -0
- package/packages/src/interfaces/ui/terminal/bridge/types.ts +226 -0
- package/packages/src/interfaces/ui/terminal/bridge/useBridge.ts +210 -0
- package/packages/src/interfaces/ui/terminal/cli/bootstrap.ts +132 -0
- package/packages/src/interfaces/ui/terminal/cli/index.ts +415 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/index.ts +110 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/input-handler.ts +393 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/interactive-runner.ts +820 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/message-store.ts +299 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/types.ts +274 -0
- package/packages/src/interfaces/ui/terminal/lmdb.db +0 -0
- package/packages/src/interfaces/ui/terminal/lmdb.db-lock +0 -0
- package/packages/src/interfaces/ui/terminal/shared/args.ts +222 -0
- package/packages/src/interfaces/ui/terminal/shared/index.ts +84 -0
- package/packages/src/interfaces/ui/terminal/shared/loading-state.ts +322 -0
- package/packages/src/interfaces/ui/terminal/shared/query.ts +152 -0
- package/packages/src/interfaces/ui/terminal/shared/setup.ts +299 -0
- package/packages/src/interfaces/ui/terminal/shared/spinner-frames.ts +73 -0
- package/packages/src/interfaces/ui/terminal/shared/status-line.ts +366 -0
- package/packages/src/interfaces/ui/terminal/shared/system-prompt.ts +146 -0
- package/packages/src/lmdb.db +0 -0
- package/packages/src/lmdb.db-lock +0 -0
- package/packages/src/native/index.ts +2722 -0
- package/packages/src/native/tui_v2_types.ts +39 -0
- package/packages/src/teammates/coordination.test.ts +279 -0
- package/packages/src/teammates/coordination.ts +646 -0
- package/packages/src/teammates/index.ts +1052 -0
- package/packages/src/teammates/integration.test.ts +272 -0
- package/packages/src/teammates/runner.test.ts +235 -0
- package/packages/src/teammates/runner.ts +750 -0
- package/packages/src/teammates/schemas.ts +673 -0
- package/packages/src/types/index.ts +723 -0
|
@@ -0,0 +1,729 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Client - SSE streaming for LLM APIs
|
|
3
|
+
*
|
|
4
|
+
* Supports multiple providers:
|
|
5
|
+
* - Zhipu (Z.AI / GLM models) - OpenAI format
|
|
6
|
+
* - MiniMax (M2.5) - Anthropic format
|
|
7
|
+
* - OpenAI (future)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
Message,
|
|
12
|
+
ContentBlock,
|
|
13
|
+
ToolUseBlock,
|
|
14
|
+
UsageMetrics,
|
|
15
|
+
APIRequest,
|
|
16
|
+
APIResponse,
|
|
17
|
+
APITool,
|
|
18
|
+
JSONSchema,
|
|
19
|
+
CacheConfig,
|
|
20
|
+
CacheControl,
|
|
21
|
+
CacheMetrics,
|
|
22
|
+
SystemBlock,
|
|
23
|
+
ThinkingConfig,
|
|
24
|
+
ExtendedThinkingConfig,
|
|
25
|
+
EffortLevel,
|
|
26
|
+
RedactedThinkingBlock,
|
|
27
|
+
StopReason,
|
|
28
|
+
} from "../types/index.js";
|
|
29
|
+
import {
|
|
30
|
+
DEFAULT_CACHE_CONFIG,
|
|
31
|
+
calculateBudgetTokens,
|
|
32
|
+
supportsExtendedThinking as supportsThinkingType,
|
|
33
|
+
EFFORT_TO_BUDGET,
|
|
34
|
+
} from "../types/index.js";
|
|
35
|
+
import { withRetry, parseRetryAfter, type RetryOptions } from "./retry.js";
|
|
36
|
+
import {
|
|
37
|
+
calculateCost as calculateModelCost,
|
|
38
|
+
DEFAULT_MODEL,
|
|
39
|
+
supportsExtendedThinking,
|
|
40
|
+
} from "./models.js";
|
|
41
|
+
import {
|
|
42
|
+
resolveProvider,
|
|
43
|
+
getProviderForModel,
|
|
44
|
+
recordProviderSuccess,
|
|
45
|
+
recordProviderFailure,
|
|
46
|
+
type ProviderName,
|
|
47
|
+
type ProviderConfig,
|
|
48
|
+
} from "./providers/index.js";
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Convert Anthropic-style tools to OpenAI-style tools
|
|
52
|
+
* Anthropic: { name, description, input_schema }
|
|
53
|
+
* OpenAI: { type: "function", function: { name, description, parameters } }
|
|
54
|
+
*/
|
|
55
|
+
function convertToolsToOpenAIFormat(tools: APITool[]): unknown[] {
|
|
56
|
+
return tools.map((tool) => ({
|
|
57
|
+
type: "function",
|
|
58
|
+
function: {
|
|
59
|
+
name: tool.name,
|
|
60
|
+
description: tool.description,
|
|
61
|
+
parameters: tool.input_schema,
|
|
62
|
+
},
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface StreamOptions {
|
|
67
|
+
apiKey: string;
|
|
68
|
+
model?: string;
|
|
69
|
+
maxTokens?: number;
|
|
70
|
+
tools?: APITool[];
|
|
71
|
+
systemPrompt?: string | SystemBlock[];
|
|
72
|
+
cacheConfig?: CacheConfig;
|
|
73
|
+
/** Legacy thinking config (budget_tokens) */
|
|
74
|
+
thinking?: ThinkingConfig;
|
|
75
|
+
/** Extended thinking config (effort levels) */
|
|
76
|
+
extendedThinking?: ExtendedThinkingConfig;
|
|
77
|
+
onToken?: (text: string) => void;
|
|
78
|
+
onThinking?: (thinking: string) => void;
|
|
79
|
+
/** Called when redacted thinking is received (data is base64) */
|
|
80
|
+
onRedactedThinking?: (data: string) => void;
|
|
81
|
+
onToolUse?: (toolUse: { id: string; name: string; input: unknown }) => void;
|
|
82
|
+
/** Called when a retry is about to start - UI should reset streaming state */
|
|
83
|
+
onRetryStart?: () => void;
|
|
84
|
+
signal?: AbortSignal;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface StreamResult {
|
|
88
|
+
message: APIResponse;
|
|
89
|
+
usage: UsageMetrics;
|
|
90
|
+
cacheMetrics?: CacheMetrics;
|
|
91
|
+
costUSD: number;
|
|
92
|
+
durationMs: number;
|
|
93
|
+
ttftMs: number;
|
|
94
|
+
/** Thinking tokens used (if extended thinking was enabled) */
|
|
95
|
+
thinkingTokens?: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Calculate cost for API usage including cache metrics
|
|
100
|
+
* Delegates to models.ts for centralized pricing
|
|
101
|
+
*/
|
|
102
|
+
export function calculateCost(
|
|
103
|
+
model: string,
|
|
104
|
+
usage: UsageMetrics
|
|
105
|
+
): { costUSD: number; estimatedSavingsUSD: number } {
|
|
106
|
+
return calculateModelCost(model, usage);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Build system prompt with cache control
|
|
111
|
+
*/
|
|
112
|
+
export function buildSystemPrompt(
|
|
113
|
+
systemPrompt: string | SystemBlock[] | undefined,
|
|
114
|
+
cacheConfig: CacheConfig
|
|
115
|
+
): string | SystemBlock[] | undefined {
|
|
116
|
+
if (!systemPrompt || !cacheConfig.enabled || !cacheConfig.cacheSystemPrompt) {
|
|
117
|
+
return typeof systemPrompt === "string" ? systemPrompt : undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// If already in block format, add cache_control to the last block
|
|
121
|
+
if (Array.isArray(systemPrompt)) {
|
|
122
|
+
const blocks = [...systemPrompt];
|
|
123
|
+
if (blocks.length > 0) {
|
|
124
|
+
const lastBlock = blocks[blocks.length - 1];
|
|
125
|
+
if (lastBlock && lastBlock.type === "text") {
|
|
126
|
+
blocks[blocks.length - 1] = {
|
|
127
|
+
type: "text" as const,
|
|
128
|
+
text: lastBlock.text,
|
|
129
|
+
cache_control: { type: "ephemeral" as const, ttl: cacheConfig.ttl },
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return blocks;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Convert string to block format with cache_control
|
|
137
|
+
return [
|
|
138
|
+
{
|
|
139
|
+
type: "text",
|
|
140
|
+
text: systemPrompt,
|
|
141
|
+
cache_control: { type: "ephemeral", ttl: cacheConfig.ttl },
|
|
142
|
+
},
|
|
143
|
+
];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Build messages with cache control for long context blocks
|
|
148
|
+
*/
|
|
149
|
+
export function buildCachedMessages(
|
|
150
|
+
messages: Message[],
|
|
151
|
+
cacheConfig: CacheConfig
|
|
152
|
+
): Message[] {
|
|
153
|
+
if (!cacheConfig.enabled) {
|
|
154
|
+
return messages;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const result: Message[] = [];
|
|
158
|
+
|
|
159
|
+
for (let i = 0; i < messages.length; i++) {
|
|
160
|
+
const msg = messages[i]!;
|
|
161
|
+
|
|
162
|
+
// Convert string content to content blocks array
|
|
163
|
+
const contentBlocks: ContentBlock[] = typeof msg.content === "string"
|
|
164
|
+
? [{ type: "text", text: msg.content }]
|
|
165
|
+
: msg.content;
|
|
166
|
+
|
|
167
|
+
const cachedContent: ContentBlock[] = [];
|
|
168
|
+
|
|
169
|
+
for (let j = 0; j < contentBlocks.length; j++) {
|
|
170
|
+
const block = contentBlocks[j]!;
|
|
171
|
+
const isLastBlock = j === contentBlocks.length - 1;
|
|
172
|
+
const isLastMessage = i === messages.length - 1;
|
|
173
|
+
|
|
174
|
+
// Add cache_control to large text blocks (especially in user messages)
|
|
175
|
+
if (
|
|
176
|
+
block.type === "text" &&
|
|
177
|
+
block.text.length >= cacheConfig.minTokensForCache * 4 && // Approximate chars per token
|
|
178
|
+
!block.cache_control &&
|
|
179
|
+
(isLastBlock || isLastMessage)
|
|
180
|
+
) {
|
|
181
|
+
cachedContent.push({
|
|
182
|
+
...block,
|
|
183
|
+
cache_control: { type: "ephemeral", ttl: cacheConfig.ttl },
|
|
184
|
+
});
|
|
185
|
+
} else {
|
|
186
|
+
cachedContent.push(block);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
result.push({ ...msg, content: cachedContent });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Ensure the last message has cache_control on its last content block
|
|
194
|
+
if (result.length > 0 && cacheConfig.enabled) {
|
|
195
|
+
const lastMsg = result[result.length - 1]!;
|
|
196
|
+
const lastBlock = lastMsg.content[lastMsg.content.length - 1];
|
|
197
|
+
if (lastBlock && !("cache_control" in lastBlock)) {
|
|
198
|
+
lastMsg.content[lastMsg.content.length - 1] = {
|
|
199
|
+
...lastBlock,
|
|
200
|
+
cache_control: { type: "ephemeral", ttl: cacheConfig.ttl },
|
|
201
|
+
} as ContentBlock;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Calculate cache metrics from usage
|
|
210
|
+
*/
|
|
211
|
+
export function calculateCacheMetrics(usage: UsageMetrics): CacheMetrics {
|
|
212
|
+
const cacheReadTokens = usage.cache_read_input_tokens ?? 0;
|
|
213
|
+
const cacheWriteTokens = usage.cache_creation_input_tokens ?? 0;
|
|
214
|
+
const totalCacheTokens = cacheReadTokens + cacheWriteTokens;
|
|
215
|
+
|
|
216
|
+
const cacheHits = cacheReadTokens > 0 ? 1 : 0;
|
|
217
|
+
const cacheMisses = cacheWriteTokens > 0 ? 1 : 0;
|
|
218
|
+
const total = cacheHits + cacheMisses;
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
cacheHits,
|
|
222
|
+
cacheMisses,
|
|
223
|
+
totalCacheReadTokens: cacheReadTokens,
|
|
224
|
+
totalCacheWriteTokens: cacheWriteTokens,
|
|
225
|
+
cacheHitRate: total > 0 ? cacheHits / total : 0,
|
|
226
|
+
estimatedSavingsUSD: 0, // Will be calculated after pricing lookup
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Callbacks to emit during streaming (passed in, not buffered)
|
|
232
|
+
*/
|
|
233
|
+
interface StreamCallbacks {
|
|
234
|
+
onToken?: (text: string) => void;
|
|
235
|
+
onThinking?: (thinking: string) => void;
|
|
236
|
+
onRedactedThinking?: (data: string) => void;
|
|
237
|
+
onToolUse?: (toolUse: { id: string; name: string; input: unknown }) => void;
|
|
238
|
+
onRetryStart?: () => void;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Internal result from a single stream attempt
|
|
243
|
+
*/
|
|
244
|
+
interface StreamAttemptResult {
|
|
245
|
+
message: APIResponse | null;
|
|
246
|
+
content: ContentBlock[];
|
|
247
|
+
usage: UsageMetrics;
|
|
248
|
+
thinkingTokens: number;
|
|
249
|
+
ttftMs: number;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Execute a single streaming API attempt
|
|
254
|
+
* Emits callbacks in real-time for streaming display
|
|
255
|
+
*/
|
|
256
|
+
async function executeStreamAttempt(
|
|
257
|
+
request: APIRequest,
|
|
258
|
+
headers: Record<string, string>,
|
|
259
|
+
apiEndpoint: string,
|
|
260
|
+
signal: AbortSignal | undefined,
|
|
261
|
+
model: string,
|
|
262
|
+
retryableStatusCodes: number[],
|
|
263
|
+
startTime: number,
|
|
264
|
+
callbacks: StreamCallbacks
|
|
265
|
+
): Promise<StreamAttemptResult> {
|
|
266
|
+
const response = await fetch(apiEndpoint, {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers,
|
|
269
|
+
body: JSON.stringify(request),
|
|
270
|
+
signal,
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Throw for retryable status codes so withRetry can handle them
|
|
274
|
+
if (!response.ok) {
|
|
275
|
+
const errorText = await response.text();
|
|
276
|
+
if (retryableStatusCodes.includes(response.status)) {
|
|
277
|
+
throw new Error(`API error: ${response.status} - ${errorText}`);
|
|
278
|
+
}
|
|
279
|
+
throw new Error(`API error: ${response.status} - ${errorText}`);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (!response.body) {
|
|
283
|
+
throw new Error("No response body");
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Parse SSE stream
|
|
287
|
+
const reader = response.body.getReader();
|
|
288
|
+
const decoder = new TextDecoder();
|
|
289
|
+
|
|
290
|
+
let message: APIResponse | null = null;
|
|
291
|
+
let currentContent: ContentBlock[] = [];
|
|
292
|
+
let usage: UsageMetrics = { input_tokens: 0, output_tokens: 0 };
|
|
293
|
+
let currentTextBlock: { type: "text"; text: string } | null = null;
|
|
294
|
+
let currentThinkingBlock: { type: "thinking"; thinking: string } | null = null;
|
|
295
|
+
let currentRedactedThinkingBlock: { type: "redacted_thinking"; data: string } | null = null;
|
|
296
|
+
let currentToolUseBlock: ToolUseBlock | null = null;
|
|
297
|
+
let toolUseInput = "";
|
|
298
|
+
|
|
299
|
+
let ttft = 0;
|
|
300
|
+
let firstToken = true;
|
|
301
|
+
let totalThinkingTokens = 0;
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
let buffer = "";
|
|
305
|
+
|
|
306
|
+
while (true) {
|
|
307
|
+
const { done, value } = await reader.read();
|
|
308
|
+
if (done) break;
|
|
309
|
+
|
|
310
|
+
buffer += decoder.decode(value, { stream: true });
|
|
311
|
+
const lines = buffer.split("\n");
|
|
312
|
+
buffer = lines.pop() || "";
|
|
313
|
+
|
|
314
|
+
for (const line of lines) {
|
|
315
|
+
if (!line.startsWith("data: ")) continue;
|
|
316
|
+
|
|
317
|
+
const data = line.slice(6);
|
|
318
|
+
if (!data) continue;
|
|
319
|
+
|
|
320
|
+
// Debug: Log all SSE data when debug enabled
|
|
321
|
+
if (process.env.DEBUG_API === '1') {
|
|
322
|
+
console.log('\x1b[90m[DEBUG] SSE data:\x1b[0m', data.substring(0, 200));
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
const event = JSON.parse(data) as Record<string, unknown>;
|
|
327
|
+
|
|
328
|
+
// Debug: Log event types
|
|
329
|
+
if (process.env.DEBUG_API === '1' && event.type) {
|
|
330
|
+
console.log('\x1b[90m[DEBUG] SSE event type:\x1b[0m', event.type);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
switch (event.type) {
|
|
334
|
+
case "error": {
|
|
335
|
+
// API returned an error - surface it
|
|
336
|
+
const errorEvent = event as { error?: { type?: string; message?: string } };
|
|
337
|
+
const errorMsg = errorEvent.error?.message || errorEvent.error?.type || "Unknown API error";
|
|
338
|
+
console.error(`API error: ${errorMsg}`);
|
|
339
|
+
// Include more details in debug mode
|
|
340
|
+
if (process.env.DEBUG_API === '1') {
|
|
341
|
+
console.log('\x1b[91m[DEBUG] API error event:', JSON.stringify(errorEvent, null, 255));
|
|
342
|
+
}
|
|
343
|
+
throw new Error(`API error: ${errorMsg}`);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
case "message_start": {
|
|
347
|
+
const msg = event.message as APIResponse;
|
|
348
|
+
message = msg;
|
|
349
|
+
usage = msg.usage;
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
case "content_block_start": {
|
|
354
|
+
const block = (event as { content_block: Record<string, unknown> }).content_block;
|
|
355
|
+
if (block.type === "text") {
|
|
356
|
+
currentTextBlock = { type: "text", text: "" };
|
|
357
|
+
} else if (block.type === "thinking") {
|
|
358
|
+
currentThinkingBlock = { type: "thinking", thinking: "" };
|
|
359
|
+
} else if (block.type === "redacted_thinking") {
|
|
360
|
+
currentRedactedThinkingBlock = { type: "redacted_thinking", data: "" };
|
|
361
|
+
} else if (block.type === "tool_use") {
|
|
362
|
+
currentToolUseBlock = {
|
|
363
|
+
type: "tool_use",
|
|
364
|
+
id: block.id as string,
|
|
365
|
+
name: block.name as string,
|
|
366
|
+
input: {},
|
|
367
|
+
};
|
|
368
|
+
toolUseInput = "";
|
|
369
|
+
}
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
case "content_block_delta": {
|
|
374
|
+
const delta = (event as { delta: Record<string, unknown> }).delta;
|
|
375
|
+
if (delta.type === "text_delta" && currentTextBlock) {
|
|
376
|
+
const text = delta.text as string;
|
|
377
|
+
currentTextBlock.text += text;
|
|
378
|
+
callbacks.onToken?.(text); // Emit in real-time
|
|
379
|
+
|
|
380
|
+
if (firstToken) {
|
|
381
|
+
ttft = Date.now() - startTime;
|
|
382
|
+
firstToken = false;
|
|
383
|
+
}
|
|
384
|
+
} else if (delta.type === "thinking_delta" && currentThinkingBlock) {
|
|
385
|
+
const thinking = delta.thinking as string;
|
|
386
|
+
currentThinkingBlock.thinking += thinking;
|
|
387
|
+
callbacks.onThinking?.(thinking); // Emit in real-time
|
|
388
|
+
totalThinkingTokens += Math.ceil(thinking.length / 4);
|
|
389
|
+
} else if (delta.type === "redacted_thinking_delta" && currentRedactedThinkingBlock) {
|
|
390
|
+
const redactedData = delta.data as string;
|
|
391
|
+
currentRedactedThinkingBlock.data += redactedData;
|
|
392
|
+
callbacks.onRedactedThinking?.(redactedData); // Emit in real-time
|
|
393
|
+
totalThinkingTokens += Math.ceil(redactedData.length / 4);
|
|
394
|
+
} else if (delta.type === "input_json_delta" && currentToolUseBlock) {
|
|
395
|
+
toolUseInput += delta.partial_json as string;
|
|
396
|
+
}
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
case "content_block_stop": {
|
|
401
|
+
if (currentTextBlock !== null) {
|
|
402
|
+
currentContent.push(currentTextBlock);
|
|
403
|
+
currentTextBlock = null;
|
|
404
|
+
} else if (currentThinkingBlock !== null) {
|
|
405
|
+
currentContent.push(currentThinkingBlock);
|
|
406
|
+
currentThinkingBlock = null;
|
|
407
|
+
} else if (currentRedactedThinkingBlock !== null) {
|
|
408
|
+
currentContent.push(currentRedactedThinkingBlock);
|
|
409
|
+
currentRedactedThinkingBlock = null;
|
|
410
|
+
} else if (currentToolUseBlock !== null) {
|
|
411
|
+
try {
|
|
412
|
+
currentToolUseBlock.input = JSON.parse(toolUseInput);
|
|
413
|
+
} catch {
|
|
414
|
+
currentToolUseBlock.input = {};
|
|
415
|
+
}
|
|
416
|
+
currentContent.push(currentToolUseBlock);
|
|
417
|
+
callbacks.onToolUse?.({
|
|
418
|
+
id: currentToolUseBlock.id,
|
|
419
|
+
name: currentToolUseBlock.name,
|
|
420
|
+
input: currentToolUseBlock.input,
|
|
421
|
+
}); // Emit in real-time
|
|
422
|
+
currentToolUseBlock = null;
|
|
423
|
+
toolUseInput = "";
|
|
424
|
+
}
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
case "message_delta": {
|
|
429
|
+
const evt = event as { usage?: { output_tokens: number }; delta?: { stop_reason: string } };
|
|
430
|
+
if (evt.usage) {
|
|
431
|
+
usage.output_tokens = evt.usage.output_tokens;
|
|
432
|
+
}
|
|
433
|
+
if (message && evt.delta?.stop_reason) {
|
|
434
|
+
message.stop_reason = evt.delta.stop_reason as "end_turn" | "max_tokens" | "stop_sequence" | "tool_use";
|
|
435
|
+
}
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
case "message_stop":
|
|
440
|
+
break;
|
|
441
|
+
|
|
442
|
+
// OpenAI/Z.AI compatible format (for GLM-5, etc.)
|
|
443
|
+
default: {
|
|
444
|
+
if (event.choices && Array.isArray(event.choices)) {
|
|
445
|
+
const choice = event.choices[0] as { delta?: { content?: string }; finish_reason?: string } | undefined;
|
|
446
|
+
if (choice?.delta?.content) {
|
|
447
|
+
const text = choice.delta.content;
|
|
448
|
+
if (currentTextBlock) {
|
|
449
|
+
currentTextBlock.text += text;
|
|
450
|
+
} else {
|
|
451
|
+
currentTextBlock = { type: "text", text };
|
|
452
|
+
}
|
|
453
|
+
callbacks.onToken?.(text); // Emit in real-time
|
|
454
|
+
if (firstToken) {
|
|
455
|
+
ttft = Date.now() - startTime;
|
|
456
|
+
firstToken = false;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
if (choice?.finish_reason) {
|
|
460
|
+
if (currentTextBlock) {
|
|
461
|
+
currentContent.push(currentTextBlock);
|
|
462
|
+
currentTextBlock = null;
|
|
463
|
+
}
|
|
464
|
+
if (!message) {
|
|
465
|
+
message = {
|
|
466
|
+
id: `msg-${Date.now()}`,
|
|
467
|
+
type: "message",
|
|
468
|
+
role: "assistant",
|
|
469
|
+
content: currentContent,
|
|
470
|
+
model: model,
|
|
471
|
+
stop_reason: (choice.finish_reason === "stop" ? "end_turn" : choice.finish_reason === "length" ? "max_tokens" : "end_turn") as StopReason,
|
|
472
|
+
stop_sequence: null,
|
|
473
|
+
usage: { input_tokens: 0, output_tokens: 0 },
|
|
474
|
+
};
|
|
475
|
+
} else {
|
|
476
|
+
message.stop_reason = (choice.finish_reason === "stop" ? "end_turn" : choice.finish_reason === "length" ? "max_tokens" : "end_turn") as StopReason;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (event.usage) {
|
|
481
|
+
const openaiUsage = event.usage as { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number };
|
|
482
|
+
usage.input_tokens = openaiUsage.prompt_tokens || 0;
|
|
483
|
+
usage.output_tokens = openaiUsage.completion_tokens || 0;
|
|
484
|
+
}
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
} catch (err: unknown) {
|
|
489
|
+
// Only rethrow if it's an API error, not a JSON parse error
|
|
490
|
+
if (err instanceof Error && err.message.startsWith("API error:")) {
|
|
491
|
+
throw err;
|
|
492
|
+
}
|
|
493
|
+
if (process.env.DEBUG_API === '1') {
|
|
494
|
+
console.error('\x1b[91m[DEBUG] JSON parse error:', err);
|
|
495
|
+
console.error('\x1b[91m[DEBUG] Error parsing SSE data:', data.substring(0, 200));
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
} finally {
|
|
501
|
+
reader.releaseLock();
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Handle "No message received" case - this is retryable
|
|
505
|
+
if (!message) {
|
|
506
|
+
if (currentContent.length > 0) {
|
|
507
|
+
message = {
|
|
508
|
+
id: `msg-${Date.now()}`,
|
|
509
|
+
type: "message",
|
|
510
|
+
role: "assistant",
|
|
511
|
+
content: currentContent,
|
|
512
|
+
model: model,
|
|
513
|
+
stop_reason: "end_turn",
|
|
514
|
+
stop_sequence: null,
|
|
515
|
+
usage: { input_tokens: 0, output_tokens: 0 },
|
|
516
|
+
};
|
|
517
|
+
} else {
|
|
518
|
+
// This is a transient error - throw to trigger retry
|
|
519
|
+
throw new Error("No message received from API");
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
return {
|
|
524
|
+
message,
|
|
525
|
+
content: currentContent,
|
|
526
|
+
usage,
|
|
527
|
+
thinkingTokens: totalThinkingTokens,
|
|
528
|
+
ttftMs: ttft,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Create a streaming message request to Anthropic API
|
|
534
|
+
* Full retry support including stream parsing errors
|
|
535
|
+
*/
|
|
536
|
+
export async function createMessageStream(
|
|
537
|
+
messages: Message[],
|
|
538
|
+
options: StreamOptions
|
|
539
|
+
): Promise<StreamResult> {
|
|
540
|
+
const {
|
|
541
|
+
apiKey,
|
|
542
|
+
model = "claude-sonnet-4-6",
|
|
543
|
+
maxTokens = 4096,
|
|
544
|
+
tools,
|
|
545
|
+
systemPrompt,
|
|
546
|
+
cacheConfig = DEFAULT_CACHE_CONFIG,
|
|
547
|
+
thinking,
|
|
548
|
+
extendedThinking,
|
|
549
|
+
onToken,
|
|
550
|
+
onThinking,
|
|
551
|
+
onRedactedThinking,
|
|
552
|
+
onToolUse,
|
|
553
|
+
onRetryStart,
|
|
554
|
+
signal,
|
|
555
|
+
} = options;
|
|
556
|
+
|
|
557
|
+
const startTime = Date.now();
|
|
558
|
+
|
|
559
|
+
// Build cached messages
|
|
560
|
+
const cachedMessages = buildCachedMessages(messages, cacheConfig);
|
|
561
|
+
|
|
562
|
+
// Build system prompt with cache control
|
|
563
|
+
const cachedSystemPrompt = buildSystemPrompt(systemPrompt, cacheConfig);
|
|
564
|
+
|
|
565
|
+
// Build request
|
|
566
|
+
const request: APIRequest = {
|
|
567
|
+
model,
|
|
568
|
+
max_tokens: maxTokens,
|
|
569
|
+
messages: cachedMessages.map((m) => ({
|
|
570
|
+
role: m.role,
|
|
571
|
+
content: m.content,
|
|
572
|
+
})),
|
|
573
|
+
stream: true,
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
if (cachedSystemPrompt) {
|
|
577
|
+
request.system = cachedSystemPrompt;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Tools will be set after determining API format (for format conversion)
|
|
581
|
+
|
|
582
|
+
// Resolve provider based on model name
|
|
583
|
+
const providerInfo = resolveProvider(model);
|
|
584
|
+
|
|
585
|
+
// Determine API endpoint and headers based on provider
|
|
586
|
+
let apiEndpoint: string;
|
|
587
|
+
let headers: Record<string, string>;
|
|
588
|
+
let apiFormat: "anthropic" | "openai";
|
|
589
|
+
|
|
590
|
+
if (providerInfo) {
|
|
591
|
+
// Use provider-specific configuration
|
|
592
|
+
apiEndpoint = providerInfo.endpoint;
|
|
593
|
+
apiFormat = providerInfo.config.format;
|
|
594
|
+
|
|
595
|
+
if (apiFormat === "anthropic") {
|
|
596
|
+
// Anthropic/MiniMax format
|
|
597
|
+
headers = {
|
|
598
|
+
"Content-Type": "application/json",
|
|
599
|
+
[providerInfo.config.authHeader]: providerInfo.apiKey,
|
|
600
|
+
"anthropic-version": "2023-06-01",
|
|
601
|
+
};
|
|
602
|
+
} else {
|
|
603
|
+
// OpenAI/Zhipu format
|
|
604
|
+
headers = {
|
|
605
|
+
"Content-Type": "application/json",
|
|
606
|
+
[providerInfo.config.authHeader]: `Bearer ${providerInfo.apiKey}`,
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
} else {
|
|
610
|
+
// Fallback to environment-based configuration (legacy)
|
|
611
|
+
const baseUrl = process.env.ANTHROPIC_BASE_URL || "https://api.anthropic.com";
|
|
612
|
+
apiEndpoint = `${baseUrl}/v1/messages`;
|
|
613
|
+
apiFormat = "anthropic";
|
|
614
|
+
|
|
615
|
+
headers = {
|
|
616
|
+
"Content-Type": "application/json",
|
|
617
|
+
"x-api-key": apiKey,
|
|
618
|
+
"anthropic-version": "2023-06-01",
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Set tools with format conversion if needed
|
|
623
|
+
if (tools && tools.length > 0) {
|
|
624
|
+
if (apiFormat === "openai") {
|
|
625
|
+
// Convert Anthropic-style tools to OpenAI format
|
|
626
|
+
// Cast needed because OpenAI format differs from APITool
|
|
627
|
+
(request as unknown as Record<string, unknown>).tools = convertToolsToOpenAIFormat(tools);
|
|
628
|
+
} else {
|
|
629
|
+
// Keep Anthropic format as-is
|
|
630
|
+
request.tools = tools;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const shouldUseExtendedThinking =
|
|
635
|
+
(extendedThinking?.enabled ?? false) ||
|
|
636
|
+
(thinking && thinking.type !== "disabled");
|
|
637
|
+
|
|
638
|
+
if (shouldUseExtendedThinking && supportsExtendedThinking(model)) {
|
|
639
|
+
let budgetTokens: number;
|
|
640
|
+
|
|
641
|
+
if (extendedThinking?.budgetTokens) {
|
|
642
|
+
budgetTokens = extendedThinking.budgetTokens;
|
|
643
|
+
} else if (thinking?.type === "enabled") {
|
|
644
|
+
budgetTokens = thinking.budget_tokens;
|
|
645
|
+
} else {
|
|
646
|
+
const effort = extendedThinking?.effort || "medium";
|
|
647
|
+
budgetTokens = calculateBudgetTokens(
|
|
648
|
+
{ enabled: true, effort, modelMultiplier: model.includes("opus") ? 2 : 1 },
|
|
649
|
+
model
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
budgetTokens = Math.max(1024, Math.min(budgetTokens, 100000));
|
|
654
|
+
|
|
655
|
+
request.thinking = { type: "enabled", budget_tokens: budgetTokens };
|
|
656
|
+
|
|
657
|
+
const betaFeatures: string[] = ["extended-thinking-2025-01-24"];
|
|
658
|
+
if (extendedThinking?.interleaved !== false) {
|
|
659
|
+
betaFeatures.push("interleaved-thinking-2025-01-24");
|
|
660
|
+
}
|
|
661
|
+
headers["anthropic-beta"] = betaFeatures.join(",");
|
|
662
|
+
} else if (apiFormat === "anthropic") {
|
|
663
|
+
headers["anthropic-beta"] = "max-tokens-3-5-sonnet-2024-07-15";
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// Retry options - now covers entire stream parsing
|
|
667
|
+
const retryOptions: RetryOptions = {
|
|
668
|
+
maxRetries: 10,
|
|
669
|
+
baseDelayMs: 1000,
|
|
670
|
+
maxDelayMs: 60000,
|
|
671
|
+
retryableStatusCodes: [429, 500, 502, 503, 504, 529],
|
|
672
|
+
onRetry: (attempt, error, delayMs) => {
|
|
673
|
+
console.log(`\x1b[33mAPI retry ${attempt}/10 after ${delayMs}ms: ${error.message}\x1b[0m`);
|
|
674
|
+
// Notify UI to reset streaming state before retry
|
|
675
|
+
onRetryStart?.();
|
|
676
|
+
// Track provider failure on retry
|
|
677
|
+
const providerName = getProviderForModel(model);
|
|
678
|
+
if (providerName) {
|
|
679
|
+
recordProviderFailure(providerName);
|
|
680
|
+
}
|
|
681
|
+
},
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
// Execute with retry - wraps entire fetch + stream parsing
|
|
685
|
+
// Callbacks are emitted in real-time during streaming
|
|
686
|
+
const result = await withRetry(
|
|
687
|
+
() => executeStreamAttempt(
|
|
688
|
+
request,
|
|
689
|
+
headers,
|
|
690
|
+
apiEndpoint,
|
|
691
|
+
signal,
|
|
692
|
+
model,
|
|
693
|
+
retryOptions.retryableStatusCodes ?? [],
|
|
694
|
+
startTime,
|
|
695
|
+
{ onToken, onThinking, onRedactedThinking, onToolUse }
|
|
696
|
+
),
|
|
697
|
+
retryOptions
|
|
698
|
+
);
|
|
699
|
+
|
|
700
|
+
// Build final message
|
|
701
|
+
const message = result.message!;
|
|
702
|
+
message.content = result.content;
|
|
703
|
+
|
|
704
|
+
// Calculate cost and cache metrics
|
|
705
|
+
const { costUSD, estimatedSavingsUSD } = calculateCost(model, result.usage);
|
|
706
|
+
const cacheMetrics = calculateCacheMetrics(result.usage);
|
|
707
|
+
cacheMetrics.estimatedSavingsUSD = estimatedSavingsUSD;
|
|
708
|
+
|
|
709
|
+
const durationMs = Date.now() - startTime;
|
|
710
|
+
|
|
711
|
+
// Track provider health on success
|
|
712
|
+
const providerName = getProviderForModel(model);
|
|
713
|
+
if (providerName) {
|
|
714
|
+
recordProviderSuccess(providerName, durationMs);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
return {
|
|
718
|
+
message,
|
|
719
|
+
usage: result.usage,
|
|
720
|
+
cacheMetrics,
|
|
721
|
+
costUSD,
|
|
722
|
+
durationMs,
|
|
723
|
+
ttftMs: result.ttftMs || durationMs,
|
|
724
|
+
thinkingTokens: result.thinkingTokens,
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// Re-export types
|
|
729
|
+
export type { StreamOptions as StreamOptionsType, StreamResult as StreamResultType };
|