@ebowwa/coder 0.7.63 → 0.7.64
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 +32 -52192
- 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 +159 -52768
- 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/index.d.ts +480 -0
- package/dist/native/index.d.ts.map +1 -0
- package/dist/native/index.js +1625 -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/package.json +4 -2
- package/packages/src/core/__tests__/permissions.test.ts +1091 -0
- package/packages/src/core/agent-loop/__tests__/compaction.test.ts +280 -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 +88 -0
- package/packages/src/core/agent-loop/formatters.ts +50 -0
- package/packages/src/core/agent-loop/index.ts +135 -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 +222 -0
- package/packages/src/core/agent-loop/types.ts +148 -0
- package/packages/src/core/agent-loop.ts +18 -0
- package/packages/src/core/api-client-impl.ts +619 -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 +590 -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-loader.ts +324 -0
- package/packages/src/core/context-compaction.ts +578 -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 +430 -0
- package/packages/src/core/normalizers/todo +4 -0
- package/packages/src/core/permissions.ts +431 -0
- package/packages/src/core/retry.ts +170 -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 +1877 -0
- package/packages/src/index.ts +120 -0
- package/packages/src/interfaces/mcp/client.ts +389 -0
- package/packages/src/interfaces/ui/Screenshot 2026-03-02 at 9.23.10/342/200/257PM.png +0 -0
- package/packages/src/interfaces/ui/Screenshot 2026-03-03 at 10.55.11/342/200/257AM.png +0 -0
- package/packages/src/interfaces/ui/index.ts +161 -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/cli/index.ts +228 -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 +71 -0
- package/packages/src/interfaces/ui/terminal/shared/loading-state.ts +322 -0
- package/packages/src/interfaces/ui/terminal/shared/query.ts +146 -0
- package/packages/src/interfaces/ui/terminal/shared/setup.ts +295 -0
- package/packages/src/interfaces/ui/terminal/shared/status-line.ts +358 -0
- package/packages/src/interfaces/ui/terminal/shared/system-prompt.ts +146 -0
- package/packages/src/interfaces/ui/terminal/tui/HelpPanel.tsx +262 -0
- package/packages/src/interfaces/ui/terminal/tui/InputContext.tsx +232 -0
- package/packages/src/interfaces/ui/terminal/tui/InputField.tsx +62 -0
- package/packages/src/interfaces/ui/terminal/tui/InteractiveTUI.tsx +537 -0
- package/packages/src/interfaces/ui/terminal/tui/MessageArea.tsx +107 -0
- package/packages/src/interfaces/ui/terminal/tui/MessageStore.tsx +240 -0
- package/packages/src/interfaces/ui/terminal/tui/StatusBar.tsx +54 -0
- package/packages/src/interfaces/ui/terminal/tui/commands.ts +438 -0
- package/packages/src/interfaces/ui/terminal/tui/components/InteractiveElements.tsx +584 -0
- package/packages/src/interfaces/ui/terminal/tui/components/MultilineInput.tsx +614 -0
- package/packages/src/interfaces/ui/terminal/tui/components/PaneManager.tsx +333 -0
- package/packages/src/interfaces/ui/terminal/tui/components/Sidebar.tsx +604 -0
- package/packages/src/interfaces/ui/terminal/tui/components/index.ts +118 -0
- package/packages/src/interfaces/ui/terminal/tui/console.ts +49 -0
- package/packages/src/interfaces/ui/terminal/tui/index.ts +90 -0
- package/packages/src/interfaces/ui/terminal/tui/run.tsx +42 -0
- package/packages/src/interfaces/ui/terminal/tui/spinner.ts +69 -0
- package/packages/src/interfaces/ui/terminal/tui/tui-app.tsx +390 -0
- package/packages/src/interfaces/ui/terminal/tui/tui-footer.ts +422 -0
- package/packages/src/interfaces/ui/terminal/tui/types.ts +186 -0
- package/packages/src/interfaces/ui/terminal/tui/useInputHandler.ts +104 -0
- package/packages/src/interfaces/ui/terminal/tui/useNativeInput.ts +239 -0
- package/packages/src/lmdb.db +0 -0
- package/packages/src/lmdb.db-lock +0 -0
- package/packages/src/native/index.ts +2345 -0
- package/packages/src/teammates/index.ts +982 -0
- package/packages/src/types/index.ts +722 -0
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Client - SSE streaming for LLM APIs
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
Message,
|
|
7
|
+
ContentBlock,
|
|
8
|
+
ToolUseBlock,
|
|
9
|
+
UsageMetrics,
|
|
10
|
+
APIRequest,
|
|
11
|
+
APIResponse,
|
|
12
|
+
APITool,
|
|
13
|
+
JSONSchema,
|
|
14
|
+
CacheConfig,
|
|
15
|
+
CacheControl,
|
|
16
|
+
CacheMetrics,
|
|
17
|
+
SystemBlock,
|
|
18
|
+
ThinkingConfig,
|
|
19
|
+
ExtendedThinkingConfig,
|
|
20
|
+
EffortLevel,
|
|
21
|
+
RedactedThinkingBlock,
|
|
22
|
+
StopReason,
|
|
23
|
+
} from "../types/index.js";
|
|
24
|
+
import {
|
|
25
|
+
DEFAULT_CACHE_CONFIG,
|
|
26
|
+
calculateBudgetTokens,
|
|
27
|
+
supportsExtendedThinking as supportsThinkingType,
|
|
28
|
+
EFFORT_TO_BUDGET,
|
|
29
|
+
} from "../types/index.js";
|
|
30
|
+
import { withRetry, parseRetryAfter, type RetryOptions } from "./retry.js";
|
|
31
|
+
import {
|
|
32
|
+
calculateCost as calculateModelCost,
|
|
33
|
+
DEFAULT_MODEL,
|
|
34
|
+
supportsExtendedThinking,
|
|
35
|
+
} from "./models.js";
|
|
36
|
+
|
|
37
|
+
export interface StreamOptions {
|
|
38
|
+
apiKey: string;
|
|
39
|
+
model?: string;
|
|
40
|
+
maxTokens?: number;
|
|
41
|
+
tools?: APITool[];
|
|
42
|
+
systemPrompt?: string | SystemBlock[];
|
|
43
|
+
cacheConfig?: CacheConfig;
|
|
44
|
+
/** Legacy thinking config (budget_tokens) */
|
|
45
|
+
thinking?: ThinkingConfig;
|
|
46
|
+
/** Extended thinking config (effort levels) */
|
|
47
|
+
extendedThinking?: ExtendedThinkingConfig;
|
|
48
|
+
onToken?: (text: string) => void;
|
|
49
|
+
onThinking?: (thinking: string) => void;
|
|
50
|
+
/** Called when redacted thinking is received (data is base64) */
|
|
51
|
+
onRedactedThinking?: (data: string) => void;
|
|
52
|
+
onToolUse?: (toolUse: { id: string; name: string; input: unknown }) => void;
|
|
53
|
+
signal?: AbortSignal;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface StreamResult {
|
|
57
|
+
message: APIResponse;
|
|
58
|
+
usage: UsageMetrics;
|
|
59
|
+
cacheMetrics?: CacheMetrics;
|
|
60
|
+
costUSD: number;
|
|
61
|
+
durationMs: number;
|
|
62
|
+
ttftMs: number;
|
|
63
|
+
/** Thinking tokens used (if extended thinking was enabled) */
|
|
64
|
+
thinkingTokens?: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Calculate cost for API usage including cache metrics
|
|
69
|
+
* Delegates to models.ts for centralized pricing
|
|
70
|
+
*/
|
|
71
|
+
export function calculateCost(
|
|
72
|
+
model: string,
|
|
73
|
+
usage: UsageMetrics
|
|
74
|
+
): { costUSD: number; estimatedSavingsUSD: number } {
|
|
75
|
+
return calculateModelCost(model, usage);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Build system prompt with cache control
|
|
80
|
+
*/
|
|
81
|
+
export function buildSystemPrompt(
|
|
82
|
+
systemPrompt: string | SystemBlock[] | undefined,
|
|
83
|
+
cacheConfig: CacheConfig
|
|
84
|
+
): string | SystemBlock[] | undefined {
|
|
85
|
+
if (!systemPrompt || !cacheConfig.enabled || !cacheConfig.cacheSystemPrompt) {
|
|
86
|
+
return typeof systemPrompt === "string" ? systemPrompt : undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// If already in block format, add cache_control to the last block
|
|
90
|
+
if (Array.isArray(systemPrompt)) {
|
|
91
|
+
const blocks = [...systemPrompt];
|
|
92
|
+
if (blocks.length > 0) {
|
|
93
|
+
const lastBlock = blocks[blocks.length - 1];
|
|
94
|
+
if (lastBlock && lastBlock.type === "text") {
|
|
95
|
+
blocks[blocks.length - 1] = {
|
|
96
|
+
type: "text" as const,
|
|
97
|
+
text: lastBlock.text,
|
|
98
|
+
cache_control: { type: "ephemeral" as const, ttl: cacheConfig.ttl },
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return blocks;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Convert string to block format with cache_control
|
|
106
|
+
return [
|
|
107
|
+
{
|
|
108
|
+
type: "text",
|
|
109
|
+
text: systemPrompt,
|
|
110
|
+
cache_control: { type: "ephemeral", ttl: cacheConfig.ttl },
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Build messages with cache control for long context blocks
|
|
117
|
+
*/
|
|
118
|
+
export function buildCachedMessages(
|
|
119
|
+
messages: Message[],
|
|
120
|
+
cacheConfig: CacheConfig
|
|
121
|
+
): Message[] {
|
|
122
|
+
if (!cacheConfig.enabled) {
|
|
123
|
+
return messages;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const result: Message[] = [];
|
|
127
|
+
|
|
128
|
+
for (let i = 0; i < messages.length; i++) {
|
|
129
|
+
const msg = messages[i]!;
|
|
130
|
+
|
|
131
|
+
// Convert string content to content blocks array
|
|
132
|
+
const contentBlocks: ContentBlock[] = typeof msg.content === "string"
|
|
133
|
+
? [{ type: "text", text: msg.content }]
|
|
134
|
+
: msg.content;
|
|
135
|
+
|
|
136
|
+
const cachedContent: ContentBlock[] = [];
|
|
137
|
+
|
|
138
|
+
for (let j = 0; j < contentBlocks.length; j++) {
|
|
139
|
+
const block = contentBlocks[j]!;
|
|
140
|
+
const isLastBlock = j === contentBlocks.length - 1;
|
|
141
|
+
const isLastMessage = i === messages.length - 1;
|
|
142
|
+
|
|
143
|
+
// Add cache_control to large text blocks (especially in user messages)
|
|
144
|
+
if (
|
|
145
|
+
block.type === "text" &&
|
|
146
|
+
block.text.length >= cacheConfig.minTokensForCache * 4 && // Approximate chars per token
|
|
147
|
+
!block.cache_control &&
|
|
148
|
+
(isLastBlock || isLastMessage)
|
|
149
|
+
) {
|
|
150
|
+
cachedContent.push({
|
|
151
|
+
...block,
|
|
152
|
+
cache_control: { type: "ephemeral", ttl: cacheConfig.ttl },
|
|
153
|
+
});
|
|
154
|
+
} else {
|
|
155
|
+
cachedContent.push(block);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
result.push({ ...msg, content: cachedContent });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Ensure the last message has cache_control on its last content block
|
|
163
|
+
if (result.length > 0 && cacheConfig.enabled) {
|
|
164
|
+
const lastMsg = result[result.length - 1]!;
|
|
165
|
+
const lastBlock = lastMsg.content[lastMsg.content.length - 1];
|
|
166
|
+
if (lastBlock && !("cache_control" in lastBlock)) {
|
|
167
|
+
lastMsg.content[lastMsg.content.length - 1] = {
|
|
168
|
+
...lastBlock,
|
|
169
|
+
cache_control: { type: "ephemeral", ttl: cacheConfig.ttl },
|
|
170
|
+
} as ContentBlock;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Calculate cache metrics from usage
|
|
179
|
+
*/
|
|
180
|
+
export function calculateCacheMetrics(usage: UsageMetrics): CacheMetrics {
|
|
181
|
+
const cacheReadTokens = usage.cache_read_input_tokens ?? 0;
|
|
182
|
+
const cacheWriteTokens = usage.cache_creation_input_tokens ?? 0;
|
|
183
|
+
const totalCacheTokens = cacheReadTokens + cacheWriteTokens;
|
|
184
|
+
|
|
185
|
+
const cacheHits = cacheReadTokens > 0 ? 1 : 0;
|
|
186
|
+
const cacheMisses = cacheWriteTokens > 0 ? 1 : 0;
|
|
187
|
+
const total = cacheHits + cacheMisses;
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
cacheHits,
|
|
191
|
+
cacheMisses,
|
|
192
|
+
totalCacheReadTokens: cacheReadTokens,
|
|
193
|
+
totalCacheWriteTokens: cacheWriteTokens,
|
|
194
|
+
cacheHitRate: total > 0 ? cacheHits / total : 0,
|
|
195
|
+
estimatedSavingsUSD: 0, // Will be calculated after pricing lookup
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Create a streaming message request to Anthropic API
|
|
201
|
+
*/
|
|
202
|
+
export async function createMessageStream(
|
|
203
|
+
messages: Message[],
|
|
204
|
+
options: StreamOptions
|
|
205
|
+
): Promise<StreamResult> {
|
|
206
|
+
const {
|
|
207
|
+
apiKey,
|
|
208
|
+
model = "claude-sonnet-4-6",
|
|
209
|
+
maxTokens = 4096,
|
|
210
|
+
tools,
|
|
211
|
+
systemPrompt,
|
|
212
|
+
cacheConfig = DEFAULT_CACHE_CONFIG,
|
|
213
|
+
thinking,
|
|
214
|
+
extendedThinking,
|
|
215
|
+
onToken,
|
|
216
|
+
onThinking,
|
|
217
|
+
onRedactedThinking,
|
|
218
|
+
onToolUse,
|
|
219
|
+
signal,
|
|
220
|
+
} = options;
|
|
221
|
+
|
|
222
|
+
const startTime = Date.now();
|
|
223
|
+
let ttft = 0;
|
|
224
|
+
let firstToken = true;
|
|
225
|
+
let totalThinkingTokens = 0;
|
|
226
|
+
|
|
227
|
+
// Build cached messages
|
|
228
|
+
const cachedMessages = buildCachedMessages(messages, cacheConfig);
|
|
229
|
+
|
|
230
|
+
// Build system prompt with cache control
|
|
231
|
+
const cachedSystemPrompt = buildSystemPrompt(systemPrompt, cacheConfig);
|
|
232
|
+
|
|
233
|
+
// Build request
|
|
234
|
+
const request: APIRequest = {
|
|
235
|
+
model,
|
|
236
|
+
max_tokens: maxTokens,
|
|
237
|
+
messages: cachedMessages.map((m) => ({
|
|
238
|
+
role: m.role,
|
|
239
|
+
content: m.content,
|
|
240
|
+
})),
|
|
241
|
+
stream: true,
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Add system prompt if provided
|
|
245
|
+
if (cachedSystemPrompt) {
|
|
246
|
+
request.system = cachedSystemPrompt;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Add tools if provided (with optional caching)
|
|
250
|
+
if (tools && tools.length > 0) {
|
|
251
|
+
request.tools = tools;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Determine API endpoint (support custom base URL for GLM, etc.)
|
|
255
|
+
const baseUrl = process.env.ANTHROPIC_BASE_URL || "https://api.anthropic.com";
|
|
256
|
+
const apiEndpoint = `${baseUrl}/v1/messages`;
|
|
257
|
+
|
|
258
|
+
// Build headers
|
|
259
|
+
const headers: Record<string, string> = {
|
|
260
|
+
"Content-Type": "application/json",
|
|
261
|
+
"x-api-key": apiKey,
|
|
262
|
+
"anthropic-version": "2023-06-01",
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// Determine thinking configuration
|
|
266
|
+
const shouldUseExtendedThinking =
|
|
267
|
+
(extendedThinking?.enabled ?? false) ||
|
|
268
|
+
(thinking && thinking.type !== "disabled");
|
|
269
|
+
|
|
270
|
+
if (shouldUseExtendedThinking && supportsExtendedThinking(model)) {
|
|
271
|
+
// Calculate budget tokens
|
|
272
|
+
let budgetTokens: number;
|
|
273
|
+
|
|
274
|
+
if (extendedThinking?.budgetTokens) {
|
|
275
|
+
budgetTokens = extendedThinking.budgetTokens;
|
|
276
|
+
} else if (thinking?.type === "enabled") {
|
|
277
|
+
budgetTokens = thinking.budget_tokens;
|
|
278
|
+
} else {
|
|
279
|
+
// Use effort level to determine budget
|
|
280
|
+
const effort = extendedThinking?.effort || "medium";
|
|
281
|
+
budgetTokens = calculateBudgetTokens(
|
|
282
|
+
{
|
|
283
|
+
enabled: true,
|
|
284
|
+
effort,
|
|
285
|
+
modelMultiplier: model.includes("opus") ? 2 : 1,
|
|
286
|
+
},
|
|
287
|
+
model
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Clamp budget to valid range
|
|
292
|
+
budgetTokens = Math.max(1024, Math.min(budgetTokens, 100000));
|
|
293
|
+
|
|
294
|
+
request.thinking = {
|
|
295
|
+
type: "enabled",
|
|
296
|
+
budget_tokens: budgetTokens,
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
// Add beta headers for extended thinking features
|
|
300
|
+
const betaFeatures: string[] = ["extended-thinking-2025-01-24"];
|
|
301
|
+
|
|
302
|
+
// Add interleaved thinking support if enabled
|
|
303
|
+
if (extendedThinking?.interleaved !== false) {
|
|
304
|
+
betaFeatures.push("interleaved-thinking-2025-01-24");
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
headers["anthropic-beta"] = betaFeatures.join(",");
|
|
308
|
+
} else {
|
|
309
|
+
// Default beta header
|
|
310
|
+
headers["anthropic-beta"] = "max-tokens-3-5-sonnet-2024-07-15";
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Make API request with retry logic
|
|
314
|
+
const retryOptions: RetryOptions = {
|
|
315
|
+
maxRetries: 3,
|
|
316
|
+
baseDelayMs: 1000,
|
|
317
|
+
maxDelayMs: 30000,
|
|
318
|
+
retryableStatusCodes: [429, 500, 502, 503, 504, 529],
|
|
319
|
+
onRetry: (attempt, error, delayMs) => {
|
|
320
|
+
console.log(`\x1b[33mAPI retry ${attempt}/3 after ${delayMs}ms: ${error.message}\x1b[0m`);
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
const response = await withRetry(
|
|
325
|
+
async () => {
|
|
326
|
+
const res = await fetch(apiEndpoint, {
|
|
327
|
+
method: "POST",
|
|
328
|
+
headers,
|
|
329
|
+
body: JSON.stringify(request),
|
|
330
|
+
signal,
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Throw for retryable status codes so withRetry can handle them
|
|
334
|
+
if (!res.ok && retryOptions.retryableStatusCodes?.includes(res.status)) {
|
|
335
|
+
const errorText = await res.text();
|
|
336
|
+
throw new Error(`API error: ${res.status} - ${errorText}`);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return res;
|
|
340
|
+
},
|
|
341
|
+
retryOptions
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
if (!response.ok) {
|
|
345
|
+
const error = await response.text();
|
|
346
|
+
throw new Error(`API error: ${response.status} - ${error}`);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (!response.body) {
|
|
350
|
+
throw new Error("No response body");
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Parse SSE stream
|
|
354
|
+
const reader = response.body.getReader();
|
|
355
|
+
const decoder = new TextDecoder();
|
|
356
|
+
|
|
357
|
+
let message: APIResponse | null = null;
|
|
358
|
+
let currentContent: ContentBlock[] = [];
|
|
359
|
+
let usage: UsageMetrics = { input_tokens: 0, output_tokens: 0 };
|
|
360
|
+
let currentTextBlock: { type: "text"; text: string } | null = null;
|
|
361
|
+
let currentThinkingBlock: { type: "thinking"; thinking: string } | null = null;
|
|
362
|
+
let currentRedactedThinkingBlock: { type: "redacted_thinking"; data: string } | null = null;
|
|
363
|
+
let currentToolUseBlock: ToolUseBlock | null = null;
|
|
364
|
+
let toolUseInput = "";
|
|
365
|
+
|
|
366
|
+
const buffer = "";
|
|
367
|
+
|
|
368
|
+
try {
|
|
369
|
+
let buffer = "";
|
|
370
|
+
|
|
371
|
+
while (true) {
|
|
372
|
+
const { done, value } = await reader.read();
|
|
373
|
+
if (done) break;
|
|
374
|
+
|
|
375
|
+
buffer += decoder.decode(value, { stream: true });
|
|
376
|
+
const lines = buffer.split("\n");
|
|
377
|
+
buffer = lines.pop() || "";
|
|
378
|
+
|
|
379
|
+
for (const line of lines) {
|
|
380
|
+
if (!line.startsWith("data: ")) continue;
|
|
381
|
+
|
|
382
|
+
const data = line.slice(6);
|
|
383
|
+
if (!data) continue;
|
|
384
|
+
|
|
385
|
+
// Debug: Log all SSE data when debug enabled
|
|
386
|
+
if (process.env.DEBUG_API === '1') {
|
|
387
|
+
console.log('\x1b[90m[DEBUG] SSE data:\x1b[0m', data.substring(0, 200));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
try {
|
|
391
|
+
const event = JSON.parse(data) as Record<string, unknown>;
|
|
392
|
+
|
|
393
|
+
// Debug: Log event types
|
|
394
|
+
if (process.env.DEBUG_API === '1' && event.type) {
|
|
395
|
+
console.log('\x1b[90m[DEBUG] SSE event type:\x1b[0m', event.type);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
switch (event.type) {
|
|
399
|
+
case "error": {
|
|
400
|
+
// API returned an error - surface it
|
|
401
|
+
const errorEvent = event as { error?: { type?: string; message?: string } };
|
|
402
|
+
const errorMsg = errorEvent.error?.message || errorEvent.error?.type || "Unknown API error";
|
|
403
|
+
console.error(`API error: ${errorMsg}`);
|
|
404
|
+
// Include more details in debug mode
|
|
405
|
+
if (process.env.DEBUG_API === '1') {
|
|
406
|
+
console.log('\x1b[91m[DEBUG] API error event:', JSON.stringify(errorEvent, null, 255));
|
|
407
|
+
}
|
|
408
|
+
throw new Error(`API error: ${errorMsg}`);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
case "message_start": {
|
|
412
|
+
const msg = event.message as APIResponse;
|
|
413
|
+
message = msg;
|
|
414
|
+
usage = msg.usage;
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
case "content_block_start": {
|
|
419
|
+
const block = (event as { content_block: Record<string, unknown> }).content_block;
|
|
420
|
+
if (block.type === "text") {
|
|
421
|
+
currentTextBlock = { type: "text", text: "" };
|
|
422
|
+
} else if (block.type === "thinking") {
|
|
423
|
+
currentThinkingBlock = { type: "thinking", thinking: "" };
|
|
424
|
+
} else if (block.type === "redacted_thinking") {
|
|
425
|
+
currentRedactedThinkingBlock = { type: "redacted_thinking", data: "" };
|
|
426
|
+
} else if (block.type === "tool_use") {
|
|
427
|
+
currentToolUseBlock = {
|
|
428
|
+
type: "tool_use",
|
|
429
|
+
id: block.id as string,
|
|
430
|
+
name: block.name as string,
|
|
431
|
+
input: {},
|
|
432
|
+
};
|
|
433
|
+
toolUseInput = "";
|
|
434
|
+
}
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
case "content_block_delta": {
|
|
439
|
+
const delta = (event as { delta: Record<string, unknown> }).delta;
|
|
440
|
+
if (delta.type === "text_delta" && currentTextBlock) {
|
|
441
|
+
const text = delta.text as string;
|
|
442
|
+
currentTextBlock.text += text;
|
|
443
|
+
onToken?.(text);
|
|
444
|
+
|
|
445
|
+
if (firstToken) {
|
|
446
|
+
ttft = Date.now() - startTime;
|
|
447
|
+
firstToken = false;
|
|
448
|
+
}
|
|
449
|
+
} else if (delta.type === "thinking_delta" && currentThinkingBlock) {
|
|
450
|
+
const thinking = delta.thinking as string;
|
|
451
|
+
currentThinkingBlock.thinking += thinking;
|
|
452
|
+
onThinking?.(thinking);
|
|
453
|
+
totalThinkingTokens += Math.ceil(thinking.length / 4); // Rough estimate
|
|
454
|
+
} else if (delta.type === "redacted_thinking_delta" && currentRedactedThinkingBlock) {
|
|
455
|
+
// Handle redacted thinking deltas
|
|
456
|
+
const redactedData = delta.data as string;
|
|
457
|
+
currentRedactedThinkingBlock.data += redactedData;
|
|
458
|
+
onRedactedThinking?.(redactedData);
|
|
459
|
+
totalThinkingTokens += Math.ceil(redactedData.length / 4); // Rough estimate
|
|
460
|
+
} else if (delta.type === "input_json_delta" && currentToolUseBlock) {
|
|
461
|
+
toolUseInput += delta.partial_json as string;
|
|
462
|
+
}
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
case "content_block_stop": {
|
|
467
|
+
// content_block_stop event has { index: number }, not the block itself
|
|
468
|
+
// We need to check which current block is active and push it
|
|
469
|
+
if (currentTextBlock !== null) {
|
|
470
|
+
currentContent.push(currentTextBlock);
|
|
471
|
+
currentTextBlock = null;
|
|
472
|
+
} else if (currentThinkingBlock !== null) {
|
|
473
|
+
currentContent.push(currentThinkingBlock);
|
|
474
|
+
currentThinkingBlock = null;
|
|
475
|
+
} else if (currentRedactedThinkingBlock !== null) {
|
|
476
|
+
currentContent.push(currentRedactedThinkingBlock);
|
|
477
|
+
onRedactedThinking?.(currentRedactedThinkingBlock.data);
|
|
478
|
+
currentRedactedThinkingBlock = null;
|
|
479
|
+
} else if (currentToolUseBlock !== null) {
|
|
480
|
+
try {
|
|
481
|
+
currentToolUseBlock.input = JSON.parse(toolUseInput);
|
|
482
|
+
} catch {
|
|
483
|
+
currentToolUseBlock.input = {};
|
|
484
|
+
}
|
|
485
|
+
currentContent.push(currentToolUseBlock);
|
|
486
|
+
onToolUse?.({
|
|
487
|
+
id: currentToolUseBlock.id,
|
|
488
|
+
name: currentToolUseBlock.name,
|
|
489
|
+
input: currentToolUseBlock.input,
|
|
490
|
+
});
|
|
491
|
+
currentToolUseBlock = null;
|
|
492
|
+
toolUseInput = "";
|
|
493
|
+
}
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
case "message_delta": {
|
|
498
|
+
const evt = event as { usage?: { output_tokens: number }; delta?: { stop_reason: string } };
|
|
499
|
+
if (evt.usage) {
|
|
500
|
+
usage.output_tokens = evt.usage.output_tokens;
|
|
501
|
+
}
|
|
502
|
+
if (message && evt.delta?.stop_reason) {
|
|
503
|
+
message.stop_reason = evt.delta.stop_reason as "end_turn" | "max_tokens" | "stop_sequence" | "tool_use";
|
|
504
|
+
}
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
case "message_stop":
|
|
509
|
+
// Message complete
|
|
510
|
+
break;
|
|
511
|
+
|
|
512
|
+
// OpenAI/Z.AI compatible format (for GLM-5, etc.)
|
|
513
|
+
// OpenAI streaming sends chunks with choices array
|
|
514
|
+
default: {
|
|
515
|
+
// Check for OpenAI format: { choices: [{ delta: { content: "..." } }], usage: {...} }
|
|
516
|
+
if (event.choices && Array.isArray(event.choices)) {
|
|
517
|
+
const choice = event.choices[0] as { delta?: { content?: string }; finish_reason?: string } | undefined;
|
|
518
|
+
if (choice?.delta?.content) {
|
|
519
|
+
const text = choice.delta.content;
|
|
520
|
+
if (currentTextBlock) {
|
|
521
|
+
currentTextBlock.text += text;
|
|
522
|
+
} else {
|
|
523
|
+
currentTextBlock = { type: "text", text };
|
|
524
|
+
}
|
|
525
|
+
onToken?.(text);
|
|
526
|
+
if (firstToken) {
|
|
527
|
+
ttft = Date.now() - startTime;
|
|
528
|
+
firstToken = false;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
// Check for finish
|
|
532
|
+
if (choice?.finish_reason) {
|
|
533
|
+
if (currentTextBlock) {
|
|
534
|
+
currentContent.push(currentTextBlock);
|
|
535
|
+
currentTextBlock = null;
|
|
536
|
+
}
|
|
537
|
+
if (!message) {
|
|
538
|
+
message = {
|
|
539
|
+
id: `msg-${Date.now()}`,
|
|
540
|
+
type: "message",
|
|
541
|
+
role: "assistant",
|
|
542
|
+
content: currentContent,
|
|
543
|
+
model: model,
|
|
544
|
+
stop_reason: (choice.finish_reason === "stop" ? "end_turn" : choice.finish_reason === "length" ? "max_tokens" : "end_turn") as StopReason,
|
|
545
|
+
stop_sequence: null,
|
|
546
|
+
usage: { input_tokens: 0, output_tokens: 0 },
|
|
547
|
+
};
|
|
548
|
+
} else {
|
|
549
|
+
message.stop_reason = (choice.finish_reason === "stop" ? "end_turn" : choice.finish_reason === "length" ? "max_tokens" : "end_turn") as StopReason;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
// OpenAI usage format (often in final chunk)
|
|
554
|
+
if (event.usage) {
|
|
555
|
+
const openaiUsage = event.usage as { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number };
|
|
556
|
+
usage.input_tokens = openaiUsage.prompt_tokens || 0;
|
|
557
|
+
usage.output_tokens = openaiUsage.completion_tokens || 0;
|
|
558
|
+
}
|
|
559
|
+
break;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
} catch (err: unknown) {
|
|
563
|
+
// Log the parse error with more detail
|
|
564
|
+
if (process.env.DEBUG_API === '1') {
|
|
565
|
+
console.error('\x1b[91m[DEBUG] JSON parse error:', err);
|
|
566
|
+
console.error('\x1b[91m[DEBUG] Error parsing SSE data:', data.substring(0, 200));
|
|
567
|
+
console.error('\x1b[91m[DEBUG] Original buffer:', buffer.substring(0, 500));
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
} finally {
|
|
573
|
+
reader.releaseLock();
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if (!message) {
|
|
577
|
+
// If we received content via OpenAI format but no message_start, create a message
|
|
578
|
+
if (currentContent.length > 0) {
|
|
579
|
+
message = {
|
|
580
|
+
id: `msg-${Date.now()}`,
|
|
581
|
+
type: "message",
|
|
582
|
+
role: "assistant",
|
|
583
|
+
content: currentContent,
|
|
584
|
+
model: model,
|
|
585
|
+
stop_reason: "end_turn",
|
|
586
|
+
stop_sequence: null,
|
|
587
|
+
usage: { input_tokens: 0, output_tokens: 0 },
|
|
588
|
+
};
|
|
589
|
+
} else {
|
|
590
|
+
// Debug: Log what we did receive
|
|
591
|
+
if (process.env.DEBUG_API === '1') {
|
|
592
|
+
console.log('\x1b[91m[DEBUG] No message_start event received. Buffer:\x1b[0m', buffer.substring(0, 500));
|
|
593
|
+
}
|
|
594
|
+
throw new Error("No message received from API");
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
message.content = currentContent;
|
|
599
|
+
|
|
600
|
+
// Calculate cost and cache metrics
|
|
601
|
+
const { costUSD, estimatedSavingsUSD } = calculateCost(model, usage);
|
|
602
|
+
const cacheMetrics = calculateCacheMetrics(usage);
|
|
603
|
+
cacheMetrics.estimatedSavingsUSD = estimatedSavingsUSD;
|
|
604
|
+
|
|
605
|
+
const durationMs = Date.now() - startTime;
|
|
606
|
+
|
|
607
|
+
return {
|
|
608
|
+
message,
|
|
609
|
+
usage,
|
|
610
|
+
cacheMetrics,
|
|
611
|
+
costUSD,
|
|
612
|
+
durationMs,
|
|
613
|
+
ttftMs: ttft || durationMs,
|
|
614
|
+
thinkingTokens: totalThinkingTokens,
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// Re-export types
|
|
619
|
+
export type { StreamOptions as StreamOptionsType, StreamResult as StreamResultType };
|