gsd-pi 2.23.0 → 2.25.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 (212) hide show
  1. package/README.md +2 -1
  2. package/dist/cli.js +12 -3
  3. package/dist/headless.d.ts +4 -0
  4. package/dist/headless.js +118 -10
  5. package/dist/help-text.js +22 -7
  6. package/dist/models-resolver.d.ts +0 -11
  7. package/dist/models-resolver.js +0 -15
  8. package/dist/resource-loader.d.ts +0 -1
  9. package/dist/resource-loader.js +64 -18
  10. package/dist/resources/GSD-WORKFLOW.md +12 -9
  11. package/dist/resources/extensions/bg-shell/overlay.ts +18 -17
  12. package/dist/resources/extensions/get-secrets-from-user.ts +5 -23
  13. package/dist/resources/extensions/gsd/activity-log.ts +5 -3
  14. package/dist/resources/extensions/gsd/auto-dispatch.ts +51 -2
  15. package/dist/resources/extensions/gsd/auto-prompts.ts +87 -0
  16. package/dist/resources/extensions/gsd/auto-recovery.ts +41 -2
  17. package/dist/resources/extensions/gsd/auto-worktree.ts +134 -4
  18. package/dist/resources/extensions/gsd/auto.ts +307 -77
  19. package/dist/resources/extensions/gsd/cache.ts +3 -1
  20. package/dist/resources/extensions/gsd/commands.ts +176 -10
  21. package/dist/resources/extensions/gsd/complexity.ts +1 -0
  22. package/dist/resources/extensions/gsd/dashboard-overlay.ts +38 -0
  23. package/dist/resources/extensions/gsd/doctor.ts +58 -11
  24. package/dist/resources/extensions/gsd/exit-command.ts +2 -2
  25. package/dist/resources/extensions/gsd/git-service.ts +74 -14
  26. package/dist/resources/extensions/gsd/gitignore.ts +1 -0
  27. package/dist/resources/extensions/gsd/gsd-db.ts +78 -1
  28. package/dist/resources/extensions/gsd/guided-flow.ts +109 -12
  29. package/dist/resources/extensions/gsd/index.ts +48 -2
  30. package/dist/resources/extensions/gsd/memory-extractor.ts +352 -0
  31. package/dist/resources/extensions/gsd/memory-store.ts +441 -0
  32. package/dist/resources/extensions/gsd/migrate/command.ts +2 -2
  33. package/dist/resources/extensions/gsd/parallel-eligibility.ts +233 -0
  34. package/dist/resources/extensions/gsd/parallel-merge.ts +156 -0
  35. package/dist/resources/extensions/gsd/parallel-orchestrator.ts +496 -0
  36. package/dist/resources/extensions/gsd/preferences.ts +65 -1
  37. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  38. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +86 -0
  39. package/dist/resources/extensions/gsd/prompts/discuss.md +4 -4
  40. package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
  41. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  42. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  43. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  44. package/dist/resources/extensions/gsd/prompts/queue.md +1 -1
  45. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  46. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  47. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +40 -61
  48. package/dist/resources/extensions/gsd/provider-error-pause.ts +29 -2
  49. package/dist/resources/extensions/gsd/session-status-io.ts +197 -0
  50. package/dist/resources/extensions/gsd/state.ts +72 -30
  51. package/dist/resources/extensions/gsd/tests/agent-end-provider-error.test.ts +81 -0
  52. package/dist/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +20 -3
  53. package/dist/resources/extensions/gsd/tests/auto-preflight.test.ts +1 -0
  54. package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +256 -2
  55. package/dist/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +34 -0
  56. package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
  57. package/dist/resources/extensions/gsd/tests/complete-milestone.test.ts +8 -1
  58. package/dist/resources/extensions/gsd/tests/derive-state-db.test.ts +9 -15
  59. package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +9 -0
  60. package/dist/resources/extensions/gsd/tests/derive-state-draft.test.ts +8 -0
  61. package/dist/resources/extensions/gsd/tests/derive-state.test.ts +14 -0
  62. package/dist/resources/extensions/gsd/tests/git-service.test.ts +70 -4
  63. package/dist/resources/extensions/gsd/tests/gsd-db.test.ts +2 -2
  64. package/dist/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +8 -0
  65. package/dist/resources/extensions/gsd/tests/md-importer.test.ts +2 -3
  66. package/dist/resources/extensions/gsd/tests/memory-extractor.test.ts +180 -0
  67. package/dist/resources/extensions/gsd/tests/memory-store.test.ts +345 -0
  68. package/dist/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +5 -5
  69. package/dist/resources/extensions/gsd/tests/parallel-orchestration.test.ts +656 -0
  70. package/dist/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +354 -0
  71. package/dist/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +1 -0
  72. package/dist/resources/extensions/gsd/tests/smart-entry-draft.test.ts +1 -1
  73. package/dist/resources/extensions/gsd/tests/validate-milestone.test.ts +316 -0
  74. package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +147 -2
  75. package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +88 -10
  76. package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +314 -87
  77. package/dist/resources/extensions/gsd/tests/worker-registry.test.ts +148 -0
  78. package/dist/resources/extensions/gsd/triage-ui.ts +1 -1
  79. package/dist/resources/extensions/gsd/types.ts +15 -1
  80. package/dist/resources/extensions/gsd/visualizer-data.ts +291 -10
  81. package/dist/resources/extensions/gsd/visualizer-overlay.ts +237 -28
  82. package/dist/resources/extensions/gsd/visualizer-views.ts +462 -48
  83. package/dist/resources/extensions/gsd/worktree.ts +9 -2
  84. package/dist/resources/extensions/search-the-web/native-search.ts +15 -5
  85. package/dist/resources/extensions/subagent/index.ts +5 -0
  86. package/dist/resources/extensions/subagent/worker-registry.ts +99 -0
  87. package/dist/update-check.d.ts +9 -0
  88. package/dist/update-check.js +97 -0
  89. package/package.json +6 -1
  90. package/packages/pi-agent-core/dist/agent-loop.js +2 -0
  91. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  92. package/packages/pi-agent-core/src/agent-loop.ts +2 -0
  93. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  94. package/packages/pi-ai/dist/providers/anthropic.js +55 -7
  95. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  96. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  97. package/packages/pi-ai/dist/providers/azure-openai-responses.js +12 -4
  98. package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  99. package/packages/pi-ai/dist/providers/google-vertex.d.ts.map +1 -1
  100. package/packages/pi-ai/dist/providers/google-vertex.js +21 -9
  101. package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
  102. package/packages/pi-ai/dist/providers/mistral.js +3 -0
  103. package/packages/pi-ai/dist/providers/mistral.js.map +1 -1
  104. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  105. package/packages/pi-ai/dist/providers/openai-completions.js +12 -4
  106. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  107. package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  108. package/packages/pi-ai/dist/providers/openai-responses.js +12 -4
  109. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  110. package/packages/pi-ai/dist/types.d.ts +23 -1
  111. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  112. package/packages/pi-ai/dist/types.js.map +1 -1
  113. package/packages/pi-ai/src/providers/anthropic.ts +59 -9
  114. package/packages/pi-ai/src/providers/azure-openai-responses.ts +16 -4
  115. package/packages/pi-ai/src/providers/google-vertex.ts +32 -17
  116. package/packages/pi-ai/src/providers/mistral.ts +3 -0
  117. package/packages/pi-ai/src/providers/openai-completions.ts +16 -4
  118. package/packages/pi-ai/src/providers/openai-responses.ts +16 -4
  119. package/packages/pi-ai/src/types.ts +19 -1
  120. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  121. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  122. package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
  123. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  124. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  125. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +17 -0
  126. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  128. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  129. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +72 -0
  130. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  131. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  132. package/packages/pi-coding-agent/src/core/settings-manager.ts +2 -2
  133. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +18 -0
  134. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +84 -0
  135. package/scripts/postinstall.js +7 -109
  136. package/src/resources/GSD-WORKFLOW.md +12 -9
  137. package/src/resources/extensions/bg-shell/overlay.ts +18 -17
  138. package/src/resources/extensions/get-secrets-from-user.ts +5 -23
  139. package/src/resources/extensions/gsd/activity-log.ts +5 -3
  140. package/src/resources/extensions/gsd/auto-dispatch.ts +51 -2
  141. package/src/resources/extensions/gsd/auto-prompts.ts +87 -0
  142. package/src/resources/extensions/gsd/auto-recovery.ts +41 -2
  143. package/src/resources/extensions/gsd/auto-worktree.ts +134 -4
  144. package/src/resources/extensions/gsd/auto.ts +307 -77
  145. package/src/resources/extensions/gsd/cache.ts +3 -1
  146. package/src/resources/extensions/gsd/commands.ts +176 -10
  147. package/src/resources/extensions/gsd/complexity.ts +1 -0
  148. package/src/resources/extensions/gsd/dashboard-overlay.ts +38 -0
  149. package/src/resources/extensions/gsd/doctor.ts +58 -11
  150. package/src/resources/extensions/gsd/exit-command.ts +2 -2
  151. package/src/resources/extensions/gsd/git-service.ts +74 -14
  152. package/src/resources/extensions/gsd/gitignore.ts +1 -0
  153. package/src/resources/extensions/gsd/gsd-db.ts +78 -1
  154. package/src/resources/extensions/gsd/guided-flow.ts +109 -12
  155. package/src/resources/extensions/gsd/index.ts +48 -2
  156. package/src/resources/extensions/gsd/memory-extractor.ts +352 -0
  157. package/src/resources/extensions/gsd/memory-store.ts +441 -0
  158. package/src/resources/extensions/gsd/migrate/command.ts +2 -2
  159. package/src/resources/extensions/gsd/parallel-eligibility.ts +233 -0
  160. package/src/resources/extensions/gsd/parallel-merge.ts +156 -0
  161. package/src/resources/extensions/gsd/parallel-orchestrator.ts +496 -0
  162. package/src/resources/extensions/gsd/preferences.ts +65 -1
  163. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  164. package/src/resources/extensions/gsd/prompts/discuss-headless.md +86 -0
  165. package/src/resources/extensions/gsd/prompts/discuss.md +4 -4
  166. package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
  167. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  168. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  169. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  170. package/src/resources/extensions/gsd/prompts/queue.md +1 -1
  171. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  172. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  173. package/src/resources/extensions/gsd/prompts/validate-milestone.md +40 -61
  174. package/src/resources/extensions/gsd/provider-error-pause.ts +29 -2
  175. package/src/resources/extensions/gsd/session-status-io.ts +197 -0
  176. package/src/resources/extensions/gsd/state.ts +72 -30
  177. package/src/resources/extensions/gsd/tests/agent-end-provider-error.test.ts +81 -0
  178. package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +20 -3
  179. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +1 -0
  180. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +256 -2
  181. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +34 -0
  182. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
  183. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +8 -1
  184. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +9 -15
  185. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +9 -0
  186. package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +8 -0
  187. package/src/resources/extensions/gsd/tests/derive-state.test.ts +14 -0
  188. package/src/resources/extensions/gsd/tests/git-service.test.ts +70 -4
  189. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +2 -2
  190. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +8 -0
  191. package/src/resources/extensions/gsd/tests/md-importer.test.ts +2 -3
  192. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +180 -0
  193. package/src/resources/extensions/gsd/tests/memory-store.test.ts +345 -0
  194. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +5 -5
  195. package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +656 -0
  196. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +354 -0
  197. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +1 -0
  198. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +1 -1
  199. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +316 -0
  200. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +147 -2
  201. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +88 -10
  202. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +314 -87
  203. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +148 -0
  204. package/src/resources/extensions/gsd/triage-ui.ts +1 -1
  205. package/src/resources/extensions/gsd/types.ts +15 -1
  206. package/src/resources/extensions/gsd/visualizer-data.ts +291 -10
  207. package/src/resources/extensions/gsd/visualizer-overlay.ts +237 -28
  208. package/src/resources/extensions/gsd/visualizer-views.ts +462 -48
  209. package/src/resources/extensions/gsd/worktree.ts +9 -2
  210. package/src/resources/extensions/search-the-web/native-search.ts +15 -5
  211. package/src/resources/extensions/subagent/index.ts +5 -0
  212. package/src/resources/extensions/subagent/worker-registry.ts +99 -0
@@ -1,4 +1,6 @@
1
- import Anthropic from "@anthropic-ai/sdk";
1
+ // Lazy-loaded: Anthropic SDK (~500ms) is imported on first use, not at startup.
2
+ // This avoids penalizing users who don't use Anthropic models.
3
+ import type Anthropic from "@anthropic-ai/sdk";
2
4
  import type {
3
5
  ContentBlockParam,
4
6
  MessageCreateParamsStreaming,
@@ -14,6 +16,7 @@ import type {
14
16
  ImageContent,
15
17
  Message,
16
18
  Model,
19
+ ServerToolUseContent,
17
20
  SimpleStreamOptions,
18
21
  StopReason,
19
22
  StreamFunction,
@@ -23,6 +26,7 @@ import type {
23
26
  Tool,
24
27
  ToolCall,
25
28
  ToolResultMessage,
29
+ WebSearchResultContent,
26
30
  } from "../types.js";
27
31
  import { AssistantMessageEventStream } from "../utils/event-stream.js";
28
32
  import { parseStreamingJson } from "../utils/json-parse.js";
@@ -32,6 +36,15 @@ import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copi
32
36
  import { adjustMaxTokensForThinking, buildBaseOptions } from "./simple-options.js";
33
37
  import { transformMessages } from "./transform-messages.js";
34
38
 
39
+ let _AnthropicClass: typeof Anthropic | undefined;
40
+ async function getAnthropicClass(): Promise<typeof Anthropic> {
41
+ if (!_AnthropicClass) {
42
+ const mod = await import("@anthropic-ai/sdk");
43
+ _AnthropicClass = mod.default;
44
+ }
45
+ return _AnthropicClass;
46
+ }
47
+
35
48
  /**
36
49
  * Resolve cache retention preference.
37
50
  * Defaults to "short" and uses PI_CACHE_RETENTION for backward compatibility.
@@ -265,7 +278,7 @@ export const streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOpti
265
278
  });
266
279
  }
267
280
 
268
- const { client, isOAuthToken } = createClient(
281
+ const { client, isOAuthToken } = await createClient(
269
282
  model,
270
283
  apiKey,
271
284
  options?.interleavedThinking ?? true,
@@ -280,7 +293,7 @@ export const streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOpti
280
293
  const anthropicStream = client.messages.stream({ ...params, stream: true }, { signal: options?.signal });
281
294
  stream.push({ type: "start", partial: output });
282
295
 
283
- type Block = (ThinkingContent | TextContent | (ToolCall & { partialJson: string })) & { index: number };
296
+ type Block = (ThinkingContent | TextContent | (ToolCall & { partialJson: string }) | ServerToolUseContent | WebSearchResultContent) & { index: number };
284
297
  const blocks = output.content as Block[];
285
298
 
286
299
  for await (const event of anthropicStream) {
@@ -336,6 +349,27 @@ export const streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOpti
336
349
  };
337
350
  output.content.push(block);
338
351
  stream.push({ type: "toolcall_start", contentIndex: output.content.length - 1, partial: output });
352
+ } else if ((event.content_block as any).type === "server_tool_use") {
353
+ const serverBlock = event.content_block as any;
354
+ const block: Block = {
355
+ type: "serverToolUse",
356
+ id: serverBlock.id,
357
+ name: serverBlock.name,
358
+ input: serverBlock.input,
359
+ index: event.index,
360
+ };
361
+ output.content.push(block);
362
+ stream.push({ type: "server_tool_use", contentIndex: output.content.length - 1, partial: output });
363
+ } else if ((event.content_block as any).type === "web_search_tool_result") {
364
+ const resultBlock = event.content_block as any;
365
+ const block: Block = {
366
+ type: "webSearchResult",
367
+ toolUseId: resultBlock.tool_use_id,
368
+ content: resultBlock.content,
369
+ index: event.index,
370
+ };
371
+ output.content.push(block);
372
+ stream.push({ type: "web_search_result", contentIndex: output.content.length - 1, partial: output });
339
373
  }
340
374
  } else if (event.type === "content_block_delta") {
341
375
  if (event.delta.type === "text_delta") {
@@ -412,6 +446,7 @@ export const streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOpti
412
446
  partial: output,
413
447
  });
414
448
  }
449
+ // serverToolUse and webSearchResult blocks just need index cleanup (already emitted on start)
415
450
  }
416
451
  } else if (event.type === "message_delta") {
417
452
  if (event.delta.stop_reason) {
@@ -455,7 +490,8 @@ export const streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOpti
455
490
  if (model.provider === "alibaba-coding-plan") {
456
491
  output.errorMessage = `[alibaba-coding-plan] ${output.errorMessage}`;
457
492
  }
458
- if (error instanceof Anthropic.APIError && error.headers) {
493
+ const AnthropicSdk = _AnthropicClass;
494
+ if (AnthropicSdk && error instanceof AnthropicSdk.APIError && error.headers) {
459
495
  const retryAfterMs = extractRetryAfterMs(error.headers, error.message);
460
496
  if (retryAfterMs !== undefined) {
461
497
  output.retryAfterMs = retryAfterMs;
@@ -548,13 +584,14 @@ function isOAuthToken(apiKey: string): boolean {
548
584
  return apiKey.includes("sk-ant-oat");
549
585
  }
550
586
 
551
- function createClient(
587
+ async function createClient(
552
588
  model: Model<"anthropic-messages">,
553
589
  apiKey: string,
554
590
  interleavedThinking: boolean,
555
591
  optionsHeaders?: Record<string, string>,
556
592
  dynamicHeaders?: Record<string, string>,
557
- ): { client: Anthropic; isOAuthToken: boolean } {
593
+ ): Promise<{ client: Anthropic; isOAuthToken: boolean }> {
594
+ const AnthropicClass = await getAnthropicClass();
558
595
  // Adaptive thinking models (Opus 4.6, Sonnet 4.6) have interleaved thinking built-in.
559
596
  // The beta header is deprecated on Opus 4.6 and redundant on Sonnet 4.6, so skip it.
560
597
  const needsInterleavedBeta = interleavedThinking && !supportsAdaptiveThinking(model.id);
@@ -566,7 +603,7 @@ function createClient(
566
603
  betaFeatures.push("interleaved-thinking-2025-05-14");
567
604
  }
568
605
 
569
- const client = new Anthropic({
606
+ const client = new AnthropicClass({
570
607
  apiKey: null,
571
608
  authToken: apiKey,
572
609
  baseURL: model.baseUrl,
@@ -595,7 +632,7 @@ function createClient(
595
632
 
596
633
  // OAuth: Bearer auth, Claude Code identity headers
597
634
  if (isOAuthToken(apiKey)) {
598
- const client = new Anthropic({
635
+ const client = new AnthropicClass({
599
636
  apiKey: null,
600
637
  authToken: apiKey,
601
638
  baseURL: model.baseUrl,
@@ -619,7 +656,7 @@ function createClient(
619
656
  // API key auth
620
657
  // Alibaba Coding Plan uses Bearer token auth instead of x-api-key
621
658
  const isAlibabaProvider = model.provider === "alibaba-coding-plan";
622
- const client = new Anthropic({
659
+ const client = new AnthropicClass({
623
660
  apiKey: isAlibabaProvider ? null : apiKey,
624
661
  authToken: isAlibabaProvider ? apiKey : undefined,
625
662
  baseURL: model.baseUrl,
@@ -827,6 +864,19 @@ function convertMessages(
827
864
  name: isOAuthToken ? toClaudeCodeName(block.name) : block.name,
828
865
  input: block.arguments ?? {},
829
866
  });
867
+ } else if (block.type === "serverToolUse") {
868
+ blocks.push({
869
+ type: "server_tool_use",
870
+ id: block.id,
871
+ name: block.name,
872
+ input: block.input ?? {},
873
+ } as any);
874
+ } else if (block.type === "webSearchResult") {
875
+ blocks.push({
876
+ type: "web_search_tool_result",
877
+ tool_use_id: block.toolUseId,
878
+ content: block.content,
879
+ } as any);
830
880
  }
831
881
  }
832
882
  if (blocks.length === 0) continue;
@@ -1,4 +1,6 @@
1
- import { AzureOpenAI } from "openai";
1
+ // Lazy-loaded: OpenAI SDK (AzureOpenAI) is imported on first use, not at startup.
2
+ // This avoids penalizing users who don't use Azure OpenAI models.
3
+ import type { AzureOpenAI } from "openai";
2
4
  import type { ResponseCreateParamsStreaming } from "openai/resources/responses/responses.js";
3
5
  import { getEnvApiKey } from "../env-api-keys.js";
4
6
  import { supportsXhigh } from "../models.js";
@@ -15,6 +17,15 @@ import { AssistantMessageEventStream } from "../utils/event-stream.js";
15
17
  import { convertResponsesMessages, convertResponsesTools, processResponsesStream } from "./openai-responses-shared.js";
16
18
  import { buildBaseOptions, clampReasoning } from "./simple-options.js";
17
19
 
20
+ let _AzureOpenAIClass: typeof AzureOpenAI | undefined;
21
+ async function getAzureOpenAIClass(): Promise<typeof AzureOpenAI> {
22
+ if (!_AzureOpenAIClass) {
23
+ const mod = await import("openai");
24
+ _AzureOpenAIClass = mod.AzureOpenAI;
25
+ }
26
+ return _AzureOpenAIClass;
27
+ }
28
+
18
29
  /**
19
30
  * Clamp reasoning effort for models that don't support all levels.
20
31
  * gpt-5.x models don't support "minimal" — map to "low".
@@ -94,7 +105,7 @@ export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses"
94
105
  try {
95
106
  // Create Azure OpenAI client
96
107
  const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
97
- const client = createClient(model, apiKey, options);
108
+ const client = await createClient(model, apiKey, options);
98
109
  let params = buildParams(model, context, options, deploymentName);
99
110
  const nextParams = await options?.onPayload?.(params, model);
100
111
  if (nextParams !== undefined) {
@@ -188,7 +199,7 @@ function resolveAzureConfig(
188
199
  };
189
200
  }
190
201
 
191
- function createClient(model: Model<"azure-openai-responses">, apiKey: string, options?: AzureOpenAIResponsesOptions) {
202
+ async function createClient(model: Model<"azure-openai-responses">, apiKey: string, options?: AzureOpenAIResponsesOptions) {
192
203
  if (!apiKey) {
193
204
  if (!process.env.AZURE_OPENAI_API_KEY) {
194
205
  throw new Error(
@@ -205,8 +216,9 @@ function createClient(model: Model<"azure-openai-responses">, apiKey: string, op
205
216
  }
206
217
 
207
218
  const { baseUrl, apiVersion } = resolveAzureConfig(model, options);
219
+ const AzureOpenAIClass = await getAzureOpenAIClass();
208
220
 
209
- return new AzureOpenAI({
221
+ return new AzureOpenAIClass({
210
222
  apiKey,
211
223
  apiVersion,
212
224
  dangerouslyAllowBrowser: true,
@@ -1,9 +1,10 @@
1
- import {
2
- type GenerateContentConfig,
3
- type GenerateContentParameters,
4
- GoogleGenAI,
5
- type ThinkingConfig,
6
- ThinkingLevel,
1
+ // Lazy-loaded: Google GenAI SDK is imported on first use, not at startup.
2
+ // This avoids penalizing users who don't use Google Vertex models.
3
+ import type { GoogleGenAI } from "@google/genai";
4
+ import type {
5
+ GenerateContentConfig,
6
+ GenerateContentParameters,
7
+ ThinkingConfig,
7
8
  } from "@google/genai";
8
9
  import { calculateCost } from "../models.js";
9
10
  import type {
@@ -33,6 +34,15 @@ import {
33
34
  } from "./google-shared.js";
34
35
  import { buildBaseOptions, clampReasoning } from "./simple-options.js";
35
36
 
37
+ let _GoogleVertexClass: typeof GoogleGenAI | undefined;
38
+ async function getGoogleVertexClass(): Promise<typeof GoogleGenAI> {
39
+ if (!_GoogleVertexClass) {
40
+ const mod = await import("@google/genai");
41
+ _GoogleVertexClass = mod.GoogleGenAI;
42
+ }
43
+ return _GoogleVertexClass;
44
+ }
45
+
36
46
  export interface GoogleVertexOptions extends StreamOptions {
37
47
  toolChoice?: "auto" | "none" | "any";
38
48
  thinking?: {
@@ -46,12 +56,14 @@ export interface GoogleVertexOptions extends StreamOptions {
46
56
 
47
57
  const API_VERSION = "v1";
48
58
 
49
- const THINKING_LEVEL_MAP: Record<GoogleThinkingLevel, ThinkingLevel> = {
50
- THINKING_LEVEL_UNSPECIFIED: ThinkingLevel.THINKING_LEVEL_UNSPECIFIED,
51
- MINIMAL: ThinkingLevel.MINIMAL,
52
- LOW: ThinkingLevel.LOW,
53
- MEDIUM: ThinkingLevel.MEDIUM,
54
- HIGH: ThinkingLevel.HIGH,
59
+ // ThinkingLevel is a string enum where each value equals its key name.
60
+ // Using string literals avoids importing the SDK at module load time.
61
+ const THINKING_LEVEL_MAP: Record<GoogleThinkingLevel, string> = {
62
+ THINKING_LEVEL_UNSPECIFIED: "THINKING_LEVEL_UNSPECIFIED",
63
+ MINIMAL: "MINIMAL",
64
+ LOW: "LOW",
65
+ MEDIUM: "MEDIUM",
66
+ HIGH: "HIGH",
55
67
  };
56
68
 
57
69
  // Counter for generating unique tool call IDs
@@ -86,7 +98,7 @@ export const streamGoogleVertex: StreamFunction<"google-vertex", GoogleVertexOpt
86
98
  try {
87
99
  const project = resolveProject(options);
88
100
  const location = resolveLocation(options);
89
- const client = createClient(model, project, location, options?.headers);
101
+ const client = await createClient(model, project, location, options?.headers);
90
102
  let params = buildParams(model, context, options);
91
103
  const nextParams = await options?.onPayload?.(params, model);
92
104
  if (nextParams !== undefined) {
@@ -318,12 +330,12 @@ export const streamSimpleGoogleVertex: StreamFunction<"google-vertex", SimpleStr
318
330
  } satisfies GoogleVertexOptions);
319
331
  };
320
332
 
321
- function createClient(
333
+ async function createClient(
322
334
  model: Model<"google-vertex">,
323
335
  project: string,
324
336
  location: string,
325
337
  optionsHeaders?: Record<string, string>,
326
- ): GoogleGenAI {
338
+ ): Promise<GoogleGenAI> {
327
339
  const httpOptions: { headers?: Record<string, string> } = {};
328
340
 
329
341
  if (model.headers || optionsHeaders) {
@@ -331,8 +343,9 @@ function createClient(
331
343
  }
332
344
 
333
345
  const hasHttpOptions = Object.values(httpOptions).some(Boolean);
346
+ const GoogleGenAIClass = await getGoogleVertexClass();
334
347
 
335
- return new GoogleGenAI({
348
+ return new GoogleGenAIClass({
336
349
  vertexai: true,
337
350
  project,
338
351
  location,
@@ -393,7 +406,9 @@ function buildParams(
393
406
  if (options.thinking?.enabled && model.reasoning) {
394
407
  const thinkingConfig: ThinkingConfig = { includeThoughts: true };
395
408
  if (options.thinking.level !== undefined) {
396
- thinkingConfig.thinkingLevel = THINKING_LEVEL_MAP[options.thinking.level];
409
+ // Cast safe: string values match ThinkingLevel enum values exactly
410
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
411
+ thinkingConfig.thinkingLevel = THINKING_LEVEL_MAP[options.thinking.level] as any;
397
412
  } else if (options.thinking.budgetTokens !== undefined) {
398
413
  thinkingConfig.thinkingBudget = options.thinking.budgetTokens;
399
414
  }
@@ -501,6 +501,9 @@ function toChatMessages(messages: Message[], supportsImages: boolean): ChatCompl
501
501
  }
502
502
  continue;
503
503
  }
504
+ if (block.type !== "toolCall") {
505
+ continue;
506
+ }
504
507
  toolCalls.push({
505
508
  id: block.id,
506
509
  type: "function",
@@ -1,4 +1,6 @@
1
- import OpenAI from "openai";
1
+ // Lazy-loaded: OpenAI SDK is imported on first use, not at startup.
2
+ // This avoids penalizing users who don't use OpenAI models.
3
+ import type OpenAI from "openai";
2
4
  import type {
3
5
  ChatCompletionAssistantMessageParam,
4
6
  ChatCompletionChunk,
@@ -33,6 +35,15 @@ import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copi
33
35
  import { buildBaseOptions, clampReasoning } from "./simple-options.js";
34
36
  import { transformMessages } from "./transform-messages.js";
35
37
 
38
+ let _OpenAICompletionsClass: typeof OpenAI | undefined;
39
+ async function getOpenAICompletionsClass(): Promise<typeof OpenAI> {
40
+ if (!_OpenAICompletionsClass) {
41
+ const mod = await import("openai");
42
+ _OpenAICompletionsClass = mod.default;
43
+ }
44
+ return _OpenAICompletionsClass;
45
+ }
46
+
36
47
  /**
37
48
  * Check if conversation messages contain tool calls or tool results.
38
49
  * This is needed because Anthropic (via proxy) requires the tools param
@@ -85,7 +96,7 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions", OpenA
85
96
 
86
97
  try {
87
98
  const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
88
- const client = createClient(model, context, apiKey, options?.headers);
99
+ const client = await createClient(model, context, apiKey, options?.headers);
89
100
  let params = buildParams(model, context, options);
90
101
  const nextParams = await options?.onPayload?.(params, model);
91
102
  if (nextParams !== undefined) {
@@ -327,7 +338,7 @@ export const streamSimpleOpenAICompletions: StreamFunction<"openai-completions",
327
338
  } satisfies OpenAICompletionsOptions);
328
339
  };
329
340
 
330
- function createClient(
341
+ async function createClient(
331
342
  model: Model<"openai-completions">,
332
343
  context: Context,
333
344
  apiKey?: string,
@@ -358,8 +369,9 @@ function createClient(
358
369
  }
359
370
 
360
371
  const isZai = model.provider === "zai" || model.baseUrl.includes("api.z.ai");
372
+ const OpenAIClass = await getOpenAICompletionsClass();
361
373
 
362
- return new OpenAI({
374
+ return new OpenAIClass({
363
375
  apiKey,
364
376
  baseURL: model.baseUrl,
365
377
  dangerouslyAllowBrowser: true,
@@ -1,4 +1,6 @@
1
- import OpenAI from "openai";
1
+ // Lazy-loaded: OpenAI SDK is imported on first use, not at startup.
2
+ // This avoids penalizing users who don't use OpenAI models.
3
+ import type OpenAI from "openai";
2
4
  import type { ResponseCreateParamsStreaming } from "openai/resources/responses/responses.js";
3
5
  import { getEnvApiKey } from "../env-api-keys.js";
4
6
  import { supportsXhigh } from "../models.js";
@@ -18,6 +20,15 @@ import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copi
18
20
  import { convertResponsesMessages, convertResponsesTools, processResponsesStream } from "./openai-responses-shared.js";
19
21
  import { buildBaseOptions, clampReasoning } from "./simple-options.js";
20
22
 
23
+ let _OpenAIResponsesClass: typeof OpenAI | undefined;
24
+ async function getOpenAIResponsesClass(): Promise<typeof OpenAI> {
25
+ if (!_OpenAIResponsesClass) {
26
+ const mod = await import("openai");
27
+ _OpenAIResponsesClass = mod.default;
28
+ }
29
+ return _OpenAIResponsesClass;
30
+ }
31
+
21
32
  /**
22
33
  * Clamp reasoning effort for models that don't support all levels.
23
34
  * gpt-5.x models don't support "minimal" — map to "low".
@@ -98,7 +109,7 @@ export const streamOpenAIResponses: StreamFunction<"openai-responses", OpenAIRes
98
109
  try {
99
110
  // Create OpenAI client
100
111
  const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
101
- const client = createClient(model, context, apiKey, options?.headers);
112
+ const client = await createClient(model, context, apiKey, options?.headers);
102
113
  let params = buildParams(model, context, options);
103
114
  const nextParams = await options?.onPayload?.(params, model);
104
115
  if (nextParams !== undefined) {
@@ -156,7 +167,7 @@ export const streamSimpleOpenAIResponses: StreamFunction<"openai-responses", Sim
156
167
  } satisfies OpenAIResponsesOptions);
157
168
  };
158
169
 
159
- function createClient(
170
+ async function createClient(
160
171
  model: Model<"openai-responses">,
161
172
  context: Context,
162
173
  apiKey?: string,
@@ -186,7 +197,8 @@ function createClient(
186
197
  Object.assign(headers, optionsHeaders);
187
198
  }
188
199
 
189
- return new OpenAI({
200
+ const OpenAIClass = await getOpenAIResponsesClass();
201
+ return new OpenAIClass({
190
202
  apiKey,
191
203
  baseURL: model.baseUrl,
192
204
  dangerouslyAllowBrowser: true,
@@ -159,6 +159,22 @@ export interface ToolCall {
159
159
  thoughtSignature?: string; // Google-specific: opaque signature for reusing thought context
160
160
  }
161
161
 
162
+ /** Server-side tool use (e.g., Anthropic native web search). Executed by the API, not the client. */
163
+ export interface ServerToolUseContent {
164
+ type: "serverToolUse";
165
+ id: string;
166
+ name: string; // e.g., "web_search"
167
+ input: unknown;
168
+ }
169
+
170
+ /** Result of a server-side tool execution, paired with a ServerToolUseContent by toolUseId. */
171
+ export interface WebSearchResultContent {
172
+ type: "webSearchResult";
173
+ toolUseId: string;
174
+ /** Search results or error from the server. Opaque — stored for API replay. */
175
+ content: unknown;
176
+ }
177
+
162
178
  export interface Usage {
163
179
  input: number;
164
180
  output: number;
@@ -184,7 +200,7 @@ export interface UserMessage {
184
200
 
185
201
  export interface AssistantMessage {
186
202
  role: "assistant";
187
- content: (TextContent | ThinkingContent | ToolCall)[];
203
+ content: (TextContent | ThinkingContent | ToolCall | ServerToolUseContent | WebSearchResultContent)[];
188
204
  api: Api;
189
205
  provider: Provider;
190
206
  model: string;
@@ -233,6 +249,8 @@ export type AssistantMessageEvent =
233
249
  | { type: "toolcall_start"; contentIndex: number; partial: AssistantMessage }
234
250
  | { type: "toolcall_delta"; contentIndex: number; delta: string; partial: AssistantMessage }
235
251
  | { type: "toolcall_end"; contentIndex: number; toolCall: ToolCall; partial: AssistantMessage }
252
+ | { type: "server_tool_use"; contentIndex: number; partial: AssistantMessage }
253
+ | { type: "web_search_result"; contentIndex: number; partial: AssistantMessage }
236
254
  | { type: "done"; reason: Extract<StopReason, "stop" | "length" | "toolUse">; message: AssistantMessage }
237
255
  | { type: "error"; reason: Extract<StopReason, "aborted" | "error">; error: AssistantMessage };
238
256
 
@@ -2041,7 +2041,7 @@ export class AgentSession {
2041
2041
  if (message.retryAfterMs !== undefined) {
2042
2042
  const cap = settings.maxDelayMs > 0 ? settings.maxDelayMs : Infinity;
2043
2043
  if (message.retryAfterMs > cap) {
2044
- // Server wants us to wait longer than our max — give up immediately
2044
+ // Server wants us to wait longer than maxDelayMs — give up to let auto-mode handle recovery
2045
2045
  this._emit({
2046
2046
  type: "auto_retry_end",
2047
2047
  success: false,