whale-code 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/README.md +95 -0
  2. package/bin/swag-agent.js +9 -0
  3. package/bin/swagmanager-mcp.js +321 -0
  4. package/dist/cli/app.d.ts +26 -0
  5. package/dist/cli/app.js +64 -0
  6. package/dist/cli/chat/AgentSelector.d.ts +14 -0
  7. package/dist/cli/chat/AgentSelector.js +14 -0
  8. package/dist/cli/chat/ChatApp.d.ts +9 -0
  9. package/dist/cli/chat/ChatApp.js +267 -0
  10. package/dist/cli/chat/ChatInput.d.ts +39 -0
  11. package/dist/cli/chat/ChatInput.js +509 -0
  12. package/dist/cli/chat/MarkdownText.d.ts +10 -0
  13. package/dist/cli/chat/MarkdownText.js +20 -0
  14. package/dist/cli/chat/MessageList.d.ts +37 -0
  15. package/dist/cli/chat/MessageList.js +80 -0
  16. package/dist/cli/chat/ModelSelector.d.ts +20 -0
  17. package/dist/cli/chat/ModelSelector.js +73 -0
  18. package/dist/cli/chat/RewindViewer.d.ts +26 -0
  19. package/dist/cli/chat/RewindViewer.js +185 -0
  20. package/dist/cli/chat/StoreSelector.d.ts +14 -0
  21. package/dist/cli/chat/StoreSelector.js +24 -0
  22. package/dist/cli/chat/StreamingText.d.ts +12 -0
  23. package/dist/cli/chat/StreamingText.js +12 -0
  24. package/dist/cli/chat/SubagentPanel.d.ts +45 -0
  25. package/dist/cli/chat/SubagentPanel.js +110 -0
  26. package/dist/cli/chat/TeamPanel.d.ts +21 -0
  27. package/dist/cli/chat/TeamPanel.js +42 -0
  28. package/dist/cli/chat/ToolIndicator.d.ts +25 -0
  29. package/dist/cli/chat/ToolIndicator.js +436 -0
  30. package/dist/cli/chat/hooks/useAgentLoop.d.ts +39 -0
  31. package/dist/cli/chat/hooks/useAgentLoop.js +382 -0
  32. package/dist/cli/chat/hooks/useSlashCommands.d.ts +37 -0
  33. package/dist/cli/chat/hooks/useSlashCommands.js +387 -0
  34. package/dist/cli/commands/config-cmd.d.ts +10 -0
  35. package/dist/cli/commands/config-cmd.js +99 -0
  36. package/dist/cli/commands/doctor.d.ts +14 -0
  37. package/dist/cli/commands/doctor.js +172 -0
  38. package/dist/cli/commands/init.d.ts +16 -0
  39. package/dist/cli/commands/init.js +278 -0
  40. package/dist/cli/commands/mcp.d.ts +12 -0
  41. package/dist/cli/commands/mcp.js +162 -0
  42. package/dist/cli/login/LoginApp.d.ts +7 -0
  43. package/dist/cli/login/LoginApp.js +157 -0
  44. package/dist/cli/print-mode.d.ts +31 -0
  45. package/dist/cli/print-mode.js +202 -0
  46. package/dist/cli/serve-mode.d.ts +37 -0
  47. package/dist/cli/serve-mode.js +636 -0
  48. package/dist/cli/services/agent-definitions.d.ts +25 -0
  49. package/dist/cli/services/agent-definitions.js +91 -0
  50. package/dist/cli/services/agent-events.d.ts +178 -0
  51. package/dist/cli/services/agent-events.js +175 -0
  52. package/dist/cli/services/agent-loop.d.ts +90 -0
  53. package/dist/cli/services/agent-loop.js +762 -0
  54. package/dist/cli/services/agent-worker-base.d.ts +97 -0
  55. package/dist/cli/services/agent-worker-base.js +220 -0
  56. package/dist/cli/services/auth-service.d.ts +30 -0
  57. package/dist/cli/services/auth-service.js +160 -0
  58. package/dist/cli/services/background-processes.d.ts +126 -0
  59. package/dist/cli/services/background-processes.js +318 -0
  60. package/dist/cli/services/browser-auth.d.ts +24 -0
  61. package/dist/cli/services/browser-auth.js +180 -0
  62. package/dist/cli/services/claude-md-loader.d.ts +16 -0
  63. package/dist/cli/services/claude-md-loader.js +58 -0
  64. package/dist/cli/services/config-store.d.ts +47 -0
  65. package/dist/cli/services/config-store.js +79 -0
  66. package/dist/cli/services/debug-log.d.ts +10 -0
  67. package/dist/cli/services/debug-log.js +52 -0
  68. package/dist/cli/services/error-logger.d.ts +58 -0
  69. package/dist/cli/services/error-logger.js +269 -0
  70. package/dist/cli/services/file-history.d.ts +21 -0
  71. package/dist/cli/services/file-history.js +83 -0
  72. package/dist/cli/services/format-server-response.d.ts +16 -0
  73. package/dist/cli/services/format-server-response.js +440 -0
  74. package/dist/cli/services/git-context.d.ts +11 -0
  75. package/dist/cli/services/git-context.js +66 -0
  76. package/dist/cli/services/hooks.d.ts +85 -0
  77. package/dist/cli/services/hooks.js +258 -0
  78. package/dist/cli/services/interactive-tools.d.ts +125 -0
  79. package/dist/cli/services/interactive-tools.js +260 -0
  80. package/dist/cli/services/keybinding-manager.d.ts +52 -0
  81. package/dist/cli/services/keybinding-manager.js +115 -0
  82. package/dist/cli/services/local-tools.d.ts +22 -0
  83. package/dist/cli/services/local-tools.js +697 -0
  84. package/dist/cli/services/lsp-manager.d.ts +18 -0
  85. package/dist/cli/services/lsp-manager.js +717 -0
  86. package/dist/cli/services/mcp-client.d.ts +48 -0
  87. package/dist/cli/services/mcp-client.js +157 -0
  88. package/dist/cli/services/memory-manager.d.ts +16 -0
  89. package/dist/cli/services/memory-manager.js +57 -0
  90. package/dist/cli/services/model-manager.d.ts +18 -0
  91. package/dist/cli/services/model-manager.js +71 -0
  92. package/dist/cli/services/model-router.d.ts +26 -0
  93. package/dist/cli/services/model-router.js +149 -0
  94. package/dist/cli/services/permission-modes.d.ts +13 -0
  95. package/dist/cli/services/permission-modes.js +43 -0
  96. package/dist/cli/services/rewind.d.ts +84 -0
  97. package/dist/cli/services/rewind.js +194 -0
  98. package/dist/cli/services/ripgrep.d.ts +28 -0
  99. package/dist/cli/services/ripgrep.js +138 -0
  100. package/dist/cli/services/sandbox.d.ts +29 -0
  101. package/dist/cli/services/sandbox.js +97 -0
  102. package/dist/cli/services/server-tools.d.ts +61 -0
  103. package/dist/cli/services/server-tools.js +543 -0
  104. package/dist/cli/services/session-persistence.d.ts +23 -0
  105. package/dist/cli/services/session-persistence.js +99 -0
  106. package/dist/cli/services/subagent-worker.d.ts +19 -0
  107. package/dist/cli/services/subagent-worker.js +41 -0
  108. package/dist/cli/services/subagent.d.ts +47 -0
  109. package/dist/cli/services/subagent.js +647 -0
  110. package/dist/cli/services/system-prompt.d.ts +7 -0
  111. package/dist/cli/services/system-prompt.js +198 -0
  112. package/dist/cli/services/team-lead.d.ts +73 -0
  113. package/dist/cli/services/team-lead.js +512 -0
  114. package/dist/cli/services/team-state.d.ts +77 -0
  115. package/dist/cli/services/team-state.js +398 -0
  116. package/dist/cli/services/teammate.d.ts +31 -0
  117. package/dist/cli/services/teammate.js +689 -0
  118. package/dist/cli/services/telemetry.d.ts +61 -0
  119. package/dist/cli/services/telemetry.js +209 -0
  120. package/dist/cli/services/tools/agent-tools.d.ts +14 -0
  121. package/dist/cli/services/tools/agent-tools.js +347 -0
  122. package/dist/cli/services/tools/file-ops.d.ts +15 -0
  123. package/dist/cli/services/tools/file-ops.js +487 -0
  124. package/dist/cli/services/tools/search-tools.d.ts +8 -0
  125. package/dist/cli/services/tools/search-tools.js +186 -0
  126. package/dist/cli/services/tools/shell-exec.d.ts +10 -0
  127. package/dist/cli/services/tools/shell-exec.js +168 -0
  128. package/dist/cli/services/tools/task-manager.d.ts +28 -0
  129. package/dist/cli/services/tools/task-manager.js +209 -0
  130. package/dist/cli/services/tools/web-tools.d.ts +11 -0
  131. package/dist/cli/services/tools/web-tools.js +395 -0
  132. package/dist/cli/setup/SetupApp.d.ts +9 -0
  133. package/dist/cli/setup/SetupApp.js +191 -0
  134. package/dist/cli/shared/MatrixIntro.d.ts +4 -0
  135. package/dist/cli/shared/MatrixIntro.js +83 -0
  136. package/dist/cli/shared/Theme.d.ts +74 -0
  137. package/dist/cli/shared/Theme.js +127 -0
  138. package/dist/cli/shared/WhaleBanner.d.ts +10 -0
  139. package/dist/cli/shared/WhaleBanner.js +12 -0
  140. package/dist/cli/shared/markdown.d.ts +21 -0
  141. package/dist/cli/shared/markdown.js +756 -0
  142. package/dist/cli/status/StatusApp.d.ts +4 -0
  143. package/dist/cli/status/StatusApp.js +105 -0
  144. package/dist/cli/stores/StoreApp.d.ts +7 -0
  145. package/dist/cli/stores/StoreApp.js +81 -0
  146. package/dist/index.d.ts +15 -0
  147. package/dist/index.js +538 -0
  148. package/dist/local-agent/connection.d.ts +48 -0
  149. package/dist/local-agent/connection.js +332 -0
  150. package/dist/local-agent/discovery.d.ts +18 -0
  151. package/dist/local-agent/discovery.js +146 -0
  152. package/dist/local-agent/executor.d.ts +34 -0
  153. package/dist/local-agent/executor.js +241 -0
  154. package/dist/local-agent/index.d.ts +14 -0
  155. package/dist/local-agent/index.js +198 -0
  156. package/dist/node/adapters/base.d.ts +35 -0
  157. package/dist/node/adapters/base.js +10 -0
  158. package/dist/node/adapters/discord.d.ts +29 -0
  159. package/dist/node/adapters/discord.js +299 -0
  160. package/dist/node/adapters/email.d.ts +23 -0
  161. package/dist/node/adapters/email.js +218 -0
  162. package/dist/node/adapters/imessage.d.ts +17 -0
  163. package/dist/node/adapters/imessage.js +118 -0
  164. package/dist/node/adapters/slack.d.ts +26 -0
  165. package/dist/node/adapters/slack.js +259 -0
  166. package/dist/node/adapters/sms.d.ts +23 -0
  167. package/dist/node/adapters/sms.js +161 -0
  168. package/dist/node/adapters/telegram.d.ts +17 -0
  169. package/dist/node/adapters/telegram.js +101 -0
  170. package/dist/node/adapters/webchat.d.ts +27 -0
  171. package/dist/node/adapters/webchat.js +160 -0
  172. package/dist/node/adapters/whatsapp.d.ts +28 -0
  173. package/dist/node/adapters/whatsapp.js +230 -0
  174. package/dist/node/cli.d.ts +2 -0
  175. package/dist/node/cli.js +325 -0
  176. package/dist/node/config.d.ts +17 -0
  177. package/dist/node/config.js +31 -0
  178. package/dist/node/runtime.d.ts +50 -0
  179. package/dist/node/runtime.js +351 -0
  180. package/dist/server/handlers/__test-utils__/mock-supabase.d.ts +11 -0
  181. package/dist/server/handlers/__test-utils__/mock-supabase.js +393 -0
  182. package/dist/server/handlers/analytics.d.ts +17 -0
  183. package/dist/server/handlers/analytics.js +266 -0
  184. package/dist/server/handlers/api-keys.d.ts +6 -0
  185. package/dist/server/handlers/api-keys.js +221 -0
  186. package/dist/server/handlers/billing.d.ts +33 -0
  187. package/dist/server/handlers/billing.js +272 -0
  188. package/dist/server/handlers/browser.d.ts +10 -0
  189. package/dist/server/handlers/browser.js +517 -0
  190. package/dist/server/handlers/catalog.d.ts +99 -0
  191. package/dist/server/handlers/catalog.js +976 -0
  192. package/dist/server/handlers/comms.d.ts +254 -0
  193. package/dist/server/handlers/comms.js +588 -0
  194. package/dist/server/handlers/creations.d.ts +6 -0
  195. package/dist/server/handlers/creations.js +479 -0
  196. package/dist/server/handlers/crm.d.ts +89 -0
  197. package/dist/server/handlers/crm.js +538 -0
  198. package/dist/server/handlers/discovery.d.ts +6 -0
  199. package/dist/server/handlers/discovery.js +288 -0
  200. package/dist/server/handlers/embeddings.d.ts +92 -0
  201. package/dist/server/handlers/embeddings.js +197 -0
  202. package/dist/server/handlers/enrichment.d.ts +8 -0
  203. package/dist/server/handlers/enrichment.js +768 -0
  204. package/dist/server/handlers/image-gen.d.ts +6 -0
  205. package/dist/server/handlers/image-gen.js +409 -0
  206. package/dist/server/handlers/inventory.d.ts +319 -0
  207. package/dist/server/handlers/inventory.js +447 -0
  208. package/dist/server/handlers/kali.d.ts +10 -0
  209. package/dist/server/handlers/kali.js +210 -0
  210. package/dist/server/handlers/llm-providers.d.ts +6 -0
  211. package/dist/server/handlers/llm-providers.js +673 -0
  212. package/dist/server/handlers/local-agent.d.ts +6 -0
  213. package/dist/server/handlers/local-agent.js +118 -0
  214. package/dist/server/handlers/meta-ads.d.ts +111 -0
  215. package/dist/server/handlers/meta-ads.js +2279 -0
  216. package/dist/server/handlers/nodes.d.ts +33 -0
  217. package/dist/server/handlers/nodes.js +699 -0
  218. package/dist/server/handlers/operations.d.ts +138 -0
  219. package/dist/server/handlers/operations.js +131 -0
  220. package/dist/server/handlers/platform.d.ts +23 -0
  221. package/dist/server/handlers/platform.js +227 -0
  222. package/dist/server/handlers/supply-chain.d.ts +19 -0
  223. package/dist/server/handlers/supply-chain.js +327 -0
  224. package/dist/server/handlers/transcription.d.ts +17 -0
  225. package/dist/server/handlers/transcription.js +121 -0
  226. package/dist/server/handlers/video-gen.d.ts +6 -0
  227. package/dist/server/handlers/video-gen.js +466 -0
  228. package/dist/server/handlers/voice.d.ts +8 -0
  229. package/dist/server/handlers/voice.js +1146 -0
  230. package/dist/server/handlers/workflow-steps.d.ts +86 -0
  231. package/dist/server/handlers/workflow-steps.js +2349 -0
  232. package/dist/server/handlers/workflows.d.ts +7 -0
  233. package/dist/server/handlers/workflows.js +989 -0
  234. package/dist/server/index.d.ts +1 -0
  235. package/dist/server/index.js +2427 -0
  236. package/dist/server/lib/batch-client.d.ts +80 -0
  237. package/dist/server/lib/batch-client.js +467 -0
  238. package/dist/server/lib/code-worker-pool.d.ts +31 -0
  239. package/dist/server/lib/code-worker-pool.js +224 -0
  240. package/dist/server/lib/code-worker.d.ts +1 -0
  241. package/dist/server/lib/code-worker.js +188 -0
  242. package/dist/server/lib/compaction-service.d.ts +32 -0
  243. package/dist/server/lib/compaction-service.js +162 -0
  244. package/dist/server/lib/logger.d.ts +19 -0
  245. package/dist/server/lib/logger.js +46 -0
  246. package/dist/server/lib/otel.d.ts +38 -0
  247. package/dist/server/lib/otel.js +126 -0
  248. package/dist/server/lib/pg-rate-limiter.d.ts +21 -0
  249. package/dist/server/lib/pg-rate-limiter.js +86 -0
  250. package/dist/server/lib/prompt-sanitizer.d.ts +37 -0
  251. package/dist/server/lib/prompt-sanitizer.js +177 -0
  252. package/dist/server/lib/provider-capabilities.d.ts +85 -0
  253. package/dist/server/lib/provider-capabilities.js +190 -0
  254. package/dist/server/lib/provider-failover.d.ts +74 -0
  255. package/dist/server/lib/provider-failover.js +210 -0
  256. package/dist/server/lib/rate-limiter.d.ts +39 -0
  257. package/dist/server/lib/rate-limiter.js +147 -0
  258. package/dist/server/lib/server-agent-loop.d.ts +107 -0
  259. package/dist/server/lib/server-agent-loop.js +667 -0
  260. package/dist/server/lib/server-subagent.d.ts +78 -0
  261. package/dist/server/lib/server-subagent.js +203 -0
  262. package/dist/server/lib/session-checkpoint.d.ts +51 -0
  263. package/dist/server/lib/session-checkpoint.js +145 -0
  264. package/dist/server/lib/ssrf-guard.d.ts +13 -0
  265. package/dist/server/lib/ssrf-guard.js +240 -0
  266. package/dist/server/lib/supabase-client.d.ts +7 -0
  267. package/dist/server/lib/supabase-client.js +78 -0
  268. package/dist/server/lib/template-resolver.d.ts +31 -0
  269. package/dist/server/lib/template-resolver.js +215 -0
  270. package/dist/server/lib/utils.d.ts +16 -0
  271. package/dist/server/lib/utils.js +147 -0
  272. package/dist/server/local-agent-gateway.d.ts +82 -0
  273. package/dist/server/local-agent-gateway.js +426 -0
  274. package/dist/server/providers/anthropic.d.ts +20 -0
  275. package/dist/server/providers/anthropic.js +199 -0
  276. package/dist/server/providers/bedrock.d.ts +20 -0
  277. package/dist/server/providers/bedrock.js +194 -0
  278. package/dist/server/providers/gemini.d.ts +24 -0
  279. package/dist/server/providers/gemini.js +486 -0
  280. package/dist/server/providers/openai.d.ts +24 -0
  281. package/dist/server/providers/openai.js +522 -0
  282. package/dist/server/providers/registry.d.ts +32 -0
  283. package/dist/server/providers/registry.js +58 -0
  284. package/dist/server/providers/shared.d.ts +32 -0
  285. package/dist/server/providers/shared.js +124 -0
  286. package/dist/server/providers/types.d.ts +92 -0
  287. package/dist/server/providers/types.js +12 -0
  288. package/dist/server/proxy-handlers.d.ts +6 -0
  289. package/dist/server/proxy-handlers.js +89 -0
  290. package/dist/server/tool-router.d.ts +149 -0
  291. package/dist/server/tool-router.js +803 -0
  292. package/dist/server/validation.d.ts +24 -0
  293. package/dist/server/validation.js +301 -0
  294. package/dist/server/worker.d.ts +19 -0
  295. package/dist/server/worker.js +201 -0
  296. package/dist/setup.d.ts +8 -0
  297. package/dist/setup.js +181 -0
  298. package/dist/shared/agent-core.d.ts +157 -0
  299. package/dist/shared/agent-core.js +534 -0
  300. package/dist/shared/anthropic-types.d.ts +105 -0
  301. package/dist/shared/anthropic-types.js +7 -0
  302. package/dist/shared/api-client.d.ts +90 -0
  303. package/dist/shared/api-client.js +379 -0
  304. package/dist/shared/constants.d.ts +33 -0
  305. package/dist/shared/constants.js +80 -0
  306. package/dist/shared/sse-parser.d.ts +26 -0
  307. package/dist/shared/sse-parser.js +259 -0
  308. package/dist/shared/tool-dispatch.d.ts +52 -0
  309. package/dist/shared/tool-dispatch.js +191 -0
  310. package/dist/shared/types.d.ts +72 -0
  311. package/dist/shared/types.js +7 -0
  312. package/dist/updater.d.ts +25 -0
  313. package/dist/updater.js +140 -0
  314. package/dist/webchat/widget.d.ts +0 -0
  315. package/dist/webchat/widget.js +397 -0
  316. package/package.json +95 -0
  317. package/src/cli/services/builtin-skills/commit.md +19 -0
  318. package/src/cli/services/builtin-skills/review-pr.md +21 -0
  319. package/src/cli/services/builtin-skills/review.md +18 -0
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Unified API Client — ONE server proxy caller with retry and config builder.
3
+ *
4
+ * Replaces proxy+direct call paths in agent-loop, subagent, teammate.
5
+ * CLI-only: always calls through server proxy (no direct Anthropic SDK usage).
6
+ */
7
+ import type { ContextProfile, APIRequestConfig } from "./types.js";
8
+ /**
9
+ * Build all Anthropic API config from a simple profile.
10
+ *
11
+ * Profiles:
12
+ * - 'main': clear at 80K/keep 3, compact at 120K (Opus only)
13
+ * - 'subagent': clear at 60K/keep 2, no compaction, 8192 max tokens
14
+ * - 'teammate': clear at 80K/keep 3, no compaction
15
+ */
16
+ export declare function buildAPIRequest(opts: {
17
+ model: string;
18
+ contextProfile: ContextProfile;
19
+ thinkingEnabled?: boolean;
20
+ maxOutputTokens?: number;
21
+ }): APIRequestConfig;
22
+ export interface CallServerProxyConfig {
23
+ proxyUrl: string;
24
+ token: string;
25
+ model: string;
26
+ system: Array<Record<string, unknown>>;
27
+ messages: Array<Record<string, unknown>>;
28
+ tools: Array<Record<string, unknown>>;
29
+ apiConfig: APIRequestConfig;
30
+ signal?: AbortSignal;
31
+ timeoutMs?: number;
32
+ fallbackModel?: string;
33
+ storeId?: string;
34
+ onFallback?: (fromModel: string, toModel: string) => void;
35
+ onRetry?: (attempt: number, maxRetries: number, error: string) => void;
36
+ /** Called on 401 to refresh the auth token. Returns new token or null. */
37
+ onTokenRefresh?: () => Promise<string | null>;
38
+ }
39
+ /**
40
+ * Call server proxy endpoint and return raw SSE stream.
41
+ * Retries with exponential backoff on 429/500/529.
42
+ */
43
+ export declare function callServerProxy(config: CallServerProxyConfig): Promise<ReadableStream<Uint8Array>>;
44
+ /**
45
+ * Build system blocks with prompt caching.
46
+ * Cached system prompt + optional dynamic cost context (after cache breakpoint).
47
+ */
48
+ export declare function buildSystemBlocks(systemPrompt: string, costContext?: string, enableCaching?: boolean): Array<Record<string, unknown>>;
49
+ /**
50
+ * Prepare messages and tools with prompt caching.
51
+ * Skips cache_control injection for Gemini (uses implicit caching).
52
+ */
53
+ export declare function prepareWithCaching(tools: Array<Record<string, unknown>>, messages: Array<Record<string, unknown>>, model?: string): {
54
+ tools: Array<Record<string, unknown>>;
55
+ messages: Array<Record<string, unknown>>;
56
+ };
57
+ /**
58
+ * Client-side context trimming for Gemini (no server-side context management).
59
+ * When estimated input tokens exceed threshold, replaces old tool result contents
60
+ * with "[trimmed]" to stay within Gemini's 1M context window.
61
+ */
62
+ export declare function trimGeminiContext(messages: Array<Record<string, unknown>>, estimatedTokens: number, threshold?: number, keepRecent?: number): Array<Record<string, unknown>>;
63
+ /**
64
+ * Client-side context trimming for OpenAI (no server-side context management).
65
+ * When estimated input tokens exceed threshold, replaces old tool result contents
66
+ * with "[trimmed]" to stay within OpenAI's 200K context window.
67
+ */
68
+ /**
69
+ * Call server transcription endpoint (OpenAI Whisper via our Fly.io proxy).
70
+ * Used by tool-dispatch when __AUDIO__ marker is detected in tool results.
71
+ */
72
+ export declare function callTranscribe(opts: {
73
+ proxyUrl: string;
74
+ token: string;
75
+ storeId: string;
76
+ audioBase64: string;
77
+ mediaType: string;
78
+ }): Promise<string>;
79
+ export declare function trimOpenAIContext(messages: Array<Record<string, unknown>>, estimatedTokens: number, threshold?: number, keepRecent?: number): Array<Record<string, unknown>>;
80
+ /**
81
+ * Request conversation compaction from the server (Haiku summarization).
82
+ * Used by non-Anthropic providers (OpenAI, Gemini) that lack native compaction.
83
+ * Returns summary string or null on failure (caller keeps unsummarized history).
84
+ */
85
+ export declare function requestProviderCompaction(opts: {
86
+ proxyUrl: string;
87
+ token: string;
88
+ messages: Array<Record<string, unknown>>;
89
+ systemPrompt: string;
90
+ }): Promise<string | null>;
@@ -0,0 +1,379 @@
1
+ /**
2
+ * Unified API Client — ONE server proxy caller with retry and config builder.
3
+ *
4
+ * Replaces proxy+direct call paths in agent-loop, subagent, teammate.
5
+ * CLI-only: always calls through server proxy (no direct Anthropic SDK usage).
6
+ */
7
+ import { getContextManagement, getMaxOutputTokens, getThinkingConfig, isRetryableError, addPromptCaching, } from "./agent-core.js";
8
+ import { getProvider } from "./constants.js";
9
+ // ============================================================================
10
+ // CONSTANTS
11
+ // ============================================================================
12
+ const MAX_RETRIES = 3;
13
+ const RETRY_BASE_DELAY_MS = 1000;
14
+ // ============================================================================
15
+ // API REQUEST CONFIG BUILDER
16
+ // ============================================================================
17
+ /**
18
+ * Build all Anthropic API config from a simple profile.
19
+ *
20
+ * Profiles:
21
+ * - 'main': clear at 80K/keep 3, compact at 120K (Opus only)
22
+ * - 'subagent': clear at 60K/keep 2, no compaction, 8192 max tokens
23
+ * - 'teammate': clear at 80K/keep 3, no compaction
24
+ */
25
+ export function buildAPIRequest(opts) {
26
+ const { model, contextProfile, thinkingEnabled = false, maxOutputTokens } = opts;
27
+ // Context management config per profile
28
+ // Non-Anthropic models (Gemini, OpenAI, etc.) don't support Anthropic betas or context management
29
+ const provider = getProvider(model);
30
+ const isAnthropicModel = provider === "anthropic" || provider === "bedrock";
31
+ let betas = isAnthropicModel ? ["context-management-2025-06-27"] : [];
32
+ let edits = [];
33
+ switch (contextProfile) {
34
+ case "main": {
35
+ const ctxMgmt = getContextManagement(model);
36
+ betas = [...ctxMgmt.betas];
37
+ edits = ctxMgmt.config.edits;
38
+ break;
39
+ }
40
+ case "subagent":
41
+ if (isAnthropicModel) {
42
+ edits = [
43
+ {
44
+ type: "clear_thinking_20251015",
45
+ keep: { type: "thinking_turns", value: 1 },
46
+ },
47
+ {
48
+ type: "clear_tool_uses_20250919",
49
+ trigger: { type: "input_tokens", value: 60_000 },
50
+ keep: { type: "tool_uses", value: 2 },
51
+ },
52
+ ];
53
+ }
54
+ break;
55
+ case "teammate": {
56
+ const ctxMgmt = getContextManagement(model);
57
+ betas = [...ctxMgmt.betas];
58
+ edits = ctxMgmt.config.edits;
59
+ break;
60
+ }
61
+ }
62
+ // Thinking config
63
+ const thinkingCfg = getThinkingConfig(model, thinkingEnabled);
64
+ if (thinkingCfg.beta)
65
+ betas.push(thinkingCfg.beta);
66
+ // Max tokens — caller is responsible for setting appropriate limits per context
67
+ const maxTokens = getMaxOutputTokens(model, maxOutputTokens);
68
+ // Build thinking param (ensure budget < maxTokens)
69
+ // Only include for Anthropic/Bedrock — Gemini/OpenAI handle thinking internally
70
+ let thinking;
71
+ if (isAnthropicModel && thinkingCfg.thinking.type !== "disabled") {
72
+ thinking = thinkingCfg.thinking.budget_tokens
73
+ ? { ...thinkingCfg.thinking, budget_tokens: Math.min(thinkingCfg.thinking.budget_tokens, maxTokens - 1) }
74
+ : thinkingCfg.thinking;
75
+ }
76
+ // Strip clear_thinking edits when thinking is disabled — API requires thinking
77
+ // to be enabled or adaptive for clear_thinking_20251015 to be accepted
78
+ if (!thinking) {
79
+ edits = edits.filter(e => e.type !== "clear_thinking_20251015");
80
+ }
81
+ return {
82
+ betas,
83
+ contextManagement: { edits },
84
+ thinking,
85
+ maxTokens,
86
+ };
87
+ }
88
+ /**
89
+ * Call server proxy endpoint and return raw SSE stream.
90
+ * Retries with exponential backoff on 429/500/529.
91
+ */
92
+ export async function callServerProxy(config) {
93
+ const { proxyUrl, signal, timeoutMs } = config;
94
+ let tokenRefreshed = false;
95
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
96
+ try {
97
+ const body = {
98
+ mode: "proxy",
99
+ messages: config.messages,
100
+ system: config.system,
101
+ tools: config.tools,
102
+ model: config.model,
103
+ max_tokens: config.apiConfig.maxTokens,
104
+ stream: true,
105
+ betas: config.apiConfig.betas,
106
+ ...(config.apiConfig.contextManagement?.edits?.length
107
+ ? { context_management: config.apiConfig.contextManagement }
108
+ : {}),
109
+ };
110
+ if (config.apiConfig.thinking) {
111
+ body.thinking = config.apiConfig.thinking;
112
+ }
113
+ if (config.storeId) {
114
+ body.store_id = config.storeId;
115
+ }
116
+ const fetchOpts = {
117
+ method: "POST",
118
+ headers: {
119
+ "Content-Type": "application/json",
120
+ "Authorization": `Bearer ${config.token}`,
121
+ },
122
+ body: JSON.stringify(body),
123
+ signal,
124
+ };
125
+ // Apply timeout if specified
126
+ let controller;
127
+ let timeout;
128
+ if (timeoutMs && !signal) {
129
+ controller = new AbortController();
130
+ timeout = setTimeout(() => controller.abort(), timeoutMs);
131
+ fetchOpts.signal = controller.signal;
132
+ }
133
+ try {
134
+ const response = await fetch(proxyUrl, fetchOpts);
135
+ if (timeout)
136
+ clearTimeout(timeout);
137
+ if (response.ok && response.body) {
138
+ return response.body;
139
+ }
140
+ const errorBody = await response.text();
141
+ // Auto-refresh on 401 (token invalidated server-side before local expiry)
142
+ if (response.status === 401 && config.onTokenRefresh && !tokenRefreshed) {
143
+ const newToken = await config.onTokenRefresh();
144
+ if (newToken) {
145
+ tokenRefreshed = true;
146
+ config.token = newToken;
147
+ continue; // retry with new token
148
+ }
149
+ }
150
+ throw Object.assign(new Error(`Proxy error (${response.status}): ${errorBody}`), { status: response.status });
151
+ }
152
+ catch (err) {
153
+ if (timeout)
154
+ clearTimeout(timeout);
155
+ throw err;
156
+ }
157
+ }
158
+ catch (err) {
159
+ if (signal?.aborted)
160
+ throw err;
161
+ if (attempt < MAX_RETRIES && isRetryableError(err)) {
162
+ const errMsg = err instanceof Error ? err.message : String(err);
163
+ config.onRetry?.(attempt + 1, MAX_RETRIES, errMsg);
164
+ const delay = RETRY_BASE_DELAY_MS * Math.pow(2, attempt);
165
+ await new Promise((resolve) => setTimeout(resolve, delay));
166
+ // Fallback model on last retry
167
+ if (attempt === MAX_RETRIES - 1 && config.fallbackModel) {
168
+ const fromModel = config.model;
169
+ config.model = config.fallbackModel;
170
+ config.onFallback?.(fromModel, config.model);
171
+ }
172
+ continue;
173
+ }
174
+ throw err;
175
+ }
176
+ }
177
+ throw new Error("Failed to get response after retries");
178
+ }
179
+ // ============================================================================
180
+ // HELPERS — system prompt + caching setup
181
+ // ============================================================================
182
+ /**
183
+ * Build system blocks with prompt caching.
184
+ * Cached system prompt + optional dynamic cost context (after cache breakpoint).
185
+ */
186
+ export function buildSystemBlocks(systemPrompt, costContext, enableCaching = true) {
187
+ const system = [];
188
+ if (enableCaching) {
189
+ system.push({
190
+ type: "text",
191
+ text: systemPrompt,
192
+ cache_control: { type: "ephemeral" },
193
+ });
194
+ }
195
+ else {
196
+ system.push({ type: "text", text: systemPrompt });
197
+ }
198
+ if (costContext) {
199
+ system.push({ type: "text", text: costContext });
200
+ }
201
+ return system;
202
+ }
203
+ /**
204
+ * Prepare messages and tools with prompt caching.
205
+ * Skips cache_control injection for Gemini (uses implicit caching).
206
+ */
207
+ export function prepareWithCaching(tools, messages, model) {
208
+ if (model) {
209
+ const provider = getProvider(model);
210
+ if (provider === "gemini" || provider === "openai") {
211
+ return { tools, messages };
212
+ }
213
+ }
214
+ return addPromptCaching(tools, messages);
215
+ }
216
+ // ============================================================================
217
+ // GEMINI CONTEXT TRIMMING
218
+ // ============================================================================
219
+ /**
220
+ * Client-side context trimming for Gemini (no server-side context management).
221
+ * When estimated input tokens exceed threshold, replaces old tool result contents
222
+ * with "[trimmed]" to stay within Gemini's 1M context window.
223
+ */
224
+ export function trimGeminiContext(messages, estimatedTokens, threshold = 950_000, keepRecent = 5) {
225
+ if (estimatedTokens < threshold)
226
+ return messages;
227
+ // Find all tool_result blocks and trim oldest ones
228
+ let toolResultCount = 0;
229
+ for (const msg of messages) {
230
+ if (Array.isArray(msg.content)) {
231
+ for (const block of msg.content) {
232
+ if (block.type === "tool_result")
233
+ toolResultCount++;
234
+ }
235
+ }
236
+ }
237
+ if (toolResultCount <= keepRecent)
238
+ return messages;
239
+ const trimCount = toolResultCount - keepRecent;
240
+ let trimmed = 0;
241
+ return messages.map((msg) => {
242
+ if (!Array.isArray(msg.content))
243
+ return msg;
244
+ const content = msg.content.map((block) => {
245
+ if (block.type === "tool_result" && trimmed < trimCount) {
246
+ trimmed++;
247
+ if (typeof block.content === "string") {
248
+ return { ...block, content: "[trimmed]" };
249
+ }
250
+ else if (Array.isArray(block.content)) {
251
+ return { ...block, content: [{ type: "text", text: "[trimmed]" }] };
252
+ }
253
+ }
254
+ return block;
255
+ });
256
+ return { ...msg, content };
257
+ });
258
+ }
259
+ // ============================================================================
260
+ // OPENAI CONTEXT TRIMMING
261
+ // ============================================================================
262
+ /**
263
+ * Client-side context trimming for OpenAI (no server-side context management).
264
+ * When estimated input tokens exceed threshold, replaces old tool result contents
265
+ * with "[trimmed]" to stay within OpenAI's 200K context window.
266
+ */
267
+ // ============================================================================
268
+ // AUDIO TRANSCRIPTION CLIENT
269
+ // ============================================================================
270
+ /**
271
+ * Call server transcription endpoint (OpenAI Whisper via our Fly.io proxy).
272
+ * Used by tool-dispatch when __AUDIO__ marker is detected in tool results.
273
+ */
274
+ export async function callTranscribe(opts) {
275
+ const { proxyUrl, token, storeId, audioBase64, mediaType } = opts;
276
+ // Use same server URL as proxy, just different mode
277
+ const response = await fetch(proxyUrl, {
278
+ method: "POST",
279
+ headers: {
280
+ "Content-Type": "application/json",
281
+ Authorization: `Bearer ${token}`,
282
+ },
283
+ body: JSON.stringify({
284
+ mode: "transcribe",
285
+ audio_base64: audioBase64,
286
+ media_type: mediaType,
287
+ store_id: storeId,
288
+ }),
289
+ });
290
+ if (!response.ok) {
291
+ const errText = await response.text();
292
+ throw new Error(`Transcription failed (${response.status}): ${errText}`);
293
+ }
294
+ const data = (await response.json());
295
+ if (!data.success || !data.transcript) {
296
+ throw new Error(data.error || "Transcription returned no transcript");
297
+ }
298
+ return data.transcript;
299
+ }
300
+ // ============================================================================
301
+ // OPENAI CONTEXT TRIMMING
302
+ // ============================================================================
303
+ export function trimOpenAIContext(messages, estimatedTokens, threshold = 190_000, keepRecent = 5) {
304
+ if (estimatedTokens < threshold)
305
+ return messages;
306
+ // Find all tool_result blocks and trim oldest ones
307
+ let toolResultCount = 0;
308
+ for (const msg of messages) {
309
+ if (Array.isArray(msg.content)) {
310
+ for (const block of msg.content) {
311
+ if (block.type === "tool_result")
312
+ toolResultCount++;
313
+ }
314
+ }
315
+ }
316
+ if (toolResultCount <= keepRecent)
317
+ return messages;
318
+ const trimCount = toolResultCount - keepRecent;
319
+ let trimmed = 0;
320
+ return messages.map((msg) => {
321
+ if (!Array.isArray(msg.content))
322
+ return msg;
323
+ const content = msg.content.map((block) => {
324
+ if (block.type === "tool_result" && trimmed < trimCount) {
325
+ trimmed++;
326
+ if (typeof block.content === "string") {
327
+ return { ...block, content: "[trimmed]" };
328
+ }
329
+ else if (Array.isArray(block.content)) {
330
+ return { ...block, content: [{ type: "text", text: "[trimmed]" }] };
331
+ }
332
+ }
333
+ return block;
334
+ });
335
+ return { ...msg, content };
336
+ });
337
+ }
338
+ // ============================================================================
339
+ // PROVIDER COMPACTION CLIENT
340
+ // ============================================================================
341
+ const COMPACTION_TIMEOUT_MS = 30_000;
342
+ /**
343
+ * Request conversation compaction from the server (Haiku summarization).
344
+ * Used by non-Anthropic providers (OpenAI, Gemini) that lack native compaction.
345
+ * Returns summary string or null on failure (caller keeps unsummarized history).
346
+ */
347
+ export async function requestProviderCompaction(opts) {
348
+ const { proxyUrl, token, messages, systemPrompt } = opts;
349
+ try {
350
+ const controller = new AbortController();
351
+ const timeout = setTimeout(() => controller.abort(), COMPACTION_TIMEOUT_MS);
352
+ try {
353
+ const response = await fetch(proxyUrl, {
354
+ method: "POST",
355
+ headers: {
356
+ "Content-Type": "application/json",
357
+ Authorization: `Bearer ${token}`,
358
+ },
359
+ body: JSON.stringify({
360
+ mode: "compact",
361
+ messages,
362
+ system_prompt: systemPrompt,
363
+ }),
364
+ signal: controller.signal,
365
+ });
366
+ clearTimeout(timeout);
367
+ if (!response.ok)
368
+ return null;
369
+ const data = (await response.json());
370
+ return data.success && data.compaction_content ? data.compaction_content : null;
371
+ }
372
+ finally {
373
+ clearTimeout(timeout);
374
+ }
375
+ }
376
+ catch {
377
+ return null; // Graceful failure — caller keeps unsummarized history
378
+ }
379
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Shared constants — single source of truth for model IDs, thresholds, and limits.
3
+ */
4
+ export type ModelProvider = "anthropic" | "bedrock" | "gemini" | "openai";
5
+ export declare const MODELS: {
6
+ readonly OPUS: "claude-opus-4-6";
7
+ readonly SONNET: "claude-sonnet-4-6";
8
+ readonly SONNET_4: "claude-sonnet-4-20250514";
9
+ readonly HAIKU: "claude-haiku-4-5-20251001";
10
+ readonly BEDROCK_SONNET: "anthropic.claude-sonnet-4-6";
11
+ readonly BEDROCK_SONNET_4: "us.anthropic.claude-sonnet-4-20250514-v1:0";
12
+ readonly BEDROCK_SONNET_45: "us.anthropic.claude-sonnet-4-5-20250929-v1:0";
13
+ readonly BEDROCK_HAIKU: "us.anthropic.claude-haiku-4-5-20251001-v1:0";
14
+ readonly GEMINI_3_PRO: "gemini-3-pro-preview";
15
+ readonly GEMINI_3_FLASH: "gemini-3-flash-preview";
16
+ readonly GEMINI_25_PRO: "gemini-2.5-pro";
17
+ readonly GEMINI_25_FLASH: "gemini-2.5-flash";
18
+ readonly GEMINI_25_FLASH_LITE: "gemini-2.5-flash-lite";
19
+ readonly GPT_5: "gpt-5";
20
+ readonly GPT_5_MINI: "gpt-5-mini";
21
+ readonly GPT_5_NANO: "gpt-5-nano";
22
+ readonly O3: "o3";
23
+ readonly O4_MINI: "o4-mini";
24
+ readonly GPT_4O: "gpt-4o";
25
+ };
26
+ /** Maps short model aliases to full model IDs */
27
+ export declare const MODEL_MAP: Record<string, string>;
28
+ /** Allowed model IDs for server validation */
29
+ export declare const ALLOWED_MODELS: string[];
30
+ /** Detect provider from full model ID */
31
+ export declare function getProvider(modelId: string): ModelProvider;
32
+ /** Check if an OpenAI model is a reasoning model (o-series) */
33
+ export declare function isOpenAIReasoningModel(modelId: string): boolean;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Shared constants — single source of truth for model IDs, thresholds, and limits.
3
+ */
4
+ export const MODELS = {
5
+ // Anthropic (direct API)
6
+ OPUS: "claude-opus-4-6",
7
+ SONNET: "claude-sonnet-4-6",
8
+ SONNET_4: "claude-sonnet-4-20250514",
9
+ HAIKU: "claude-haiku-4-5-20251001",
10
+ // Bedrock (Claude on AWS)
11
+ BEDROCK_SONNET: "anthropic.claude-sonnet-4-6",
12
+ BEDROCK_SONNET_4: "us.anthropic.claude-sonnet-4-20250514-v1:0",
13
+ BEDROCK_SONNET_45: "us.anthropic.claude-sonnet-4-5-20250929-v1:0",
14
+ BEDROCK_HAIKU: "us.anthropic.claude-haiku-4-5-20251001-v1:0",
15
+ // Google Gemini
16
+ GEMINI_3_PRO: "gemini-3-pro-preview",
17
+ GEMINI_3_FLASH: "gemini-3-flash-preview",
18
+ GEMINI_25_PRO: "gemini-2.5-pro",
19
+ GEMINI_25_FLASH: "gemini-2.5-flash",
20
+ GEMINI_25_FLASH_LITE: "gemini-2.5-flash-lite",
21
+ // OpenAI
22
+ GPT_5: "gpt-5",
23
+ GPT_5_MINI: "gpt-5-mini",
24
+ GPT_5_NANO: "gpt-5-nano",
25
+ O3: "o3",
26
+ O4_MINI: "o4-mini",
27
+ GPT_4O: "gpt-4o",
28
+ };
29
+ /** Maps short model aliases to full model IDs */
30
+ export const MODEL_MAP = {
31
+ // Auto-routing (resolved at runtime by model-router)
32
+ auto: "auto",
33
+ // Anthropic
34
+ "whale/agent": MODELS.OPUS, // OpenClaw bridge sends this model ID
35
+ opus: MODELS.OPUS,
36
+ sonnet: MODELS.SONNET,
37
+ "sonnet-4.6": MODELS.SONNET,
38
+ "sonnet-4": MODELS.SONNET_4,
39
+ haiku: MODELS.HAIKU,
40
+ // Bedrock
41
+ "bedrock-sonnet": MODELS.BEDROCK_SONNET,
42
+ "bedrock-sonnet-4": MODELS.BEDROCK_SONNET_4,
43
+ "bedrock-sonnet-4.5": MODELS.BEDROCK_SONNET_45,
44
+ "bedrock-haiku": MODELS.BEDROCK_HAIKU,
45
+ // Gemini
46
+ "gemini-3-pro": MODELS.GEMINI_3_PRO,
47
+ "gemini-3-flash": MODELS.GEMINI_3_FLASH,
48
+ "gemini-pro": MODELS.GEMINI_25_PRO,
49
+ "gemini-flash": MODELS.GEMINI_25_FLASH,
50
+ "gemini-flash-lite": MODELS.GEMINI_25_FLASH_LITE,
51
+ // OpenAI
52
+ "gpt-5": MODELS.GPT_5,
53
+ "5": MODELS.GPT_5,
54
+ "gpt-5-mini": MODELS.GPT_5_MINI,
55
+ "5-mini": MODELS.GPT_5_MINI,
56
+ "gpt-5-nano": MODELS.GPT_5_NANO,
57
+ "5-nano": MODELS.GPT_5_NANO,
58
+ "o3": MODELS.O3,
59
+ "o4-mini": MODELS.O4_MINI,
60
+ "gpt-4o": MODELS.GPT_4O,
61
+ "4o": MODELS.GPT_4O,
62
+ };
63
+ /** Allowed model IDs for server validation */
64
+ export const ALLOWED_MODELS = [...Object.values(MODELS), "auto"];
65
+ /** Detect provider from full model ID */
66
+ export function getProvider(modelId) {
67
+ if (modelId === "auto")
68
+ return "anthropic"; // auto resolves to Claude models
69
+ if (modelId.includes(".anthropic.") || modelId.startsWith("anthropic."))
70
+ return "bedrock";
71
+ if (modelId.startsWith("gemini-"))
72
+ return "gemini";
73
+ if (modelId.startsWith("gpt-") || /^o\d/.test(modelId))
74
+ return "openai";
75
+ return "anthropic";
76
+ }
77
+ /** Check if an OpenAI model is a reasoning model (o-series) */
78
+ export function isOpenAIReasoningModel(modelId) {
79
+ return /^o\d/.test(modelId);
80
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Unified SSE Parser — ONE implementation replacing 4 duplicates.
3
+ *
4
+ * Used by:
5
+ * - agent-loop.ts (processStreamWithCallbacks for real-time UI)
6
+ * - subagent.ts (collectStreamResult for batch collection)
7
+ * - teammate.ts (collectStreamResult for batch collection)
8
+ * - server-agent-loop.ts (processStreamWithCallbacks for SSE relay)
9
+ */
10
+ import type { BetaStreamEvent } from "./anthropic-types.js";
11
+ import type { StreamResult, StreamCallbacks } from "./types.js";
12
+ /**
13
+ * Parse SSE stream from proxy HTTP response into typed events.
14
+ * Handles `data: {...}\n\n` format with [DONE] sentinel.
15
+ */
16
+ export declare function parseSSEStream(body: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<BetaStreamEvent>;
17
+ /**
18
+ * Collect all events into a StreamResult. No callbacks — used by
19
+ * subagent and teammate where real-time text isn't needed.
20
+ */
21
+ export declare function collectStreamResult(events: AsyncIterable<BetaStreamEvent>): Promise<StreamResult>;
22
+ /**
23
+ * Process streaming events with optional real-time callbacks.
24
+ * Used by agent-loop (needs onText for UI) and as internal impl for collect.
25
+ */
26
+ export declare function processStreamWithCallbacks(events: AsyncIterable<BetaStreamEvent>, callbacks: StreamCallbacks, signal?: AbortSignal): Promise<StreamResult>;