@code-yeongyu/senpi 2026.7.16 → 2026.7.17-2

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 (149) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/dist/core/dynamic-prompt/build.d.ts +7 -0
  3. package/dist/core/dynamic-prompt/build.d.ts.map +1 -1
  4. package/dist/core/dynamic-prompt/build.js +5 -0
  5. package/dist/core/dynamic-prompt/build.js.map +1 -1
  6. package/dist/core/dynamic-prompt/workstation.d.ts +35 -0
  7. package/dist/core/dynamic-prompt/workstation.d.ts.map +1 -0
  8. package/dist/core/dynamic-prompt/workstation.js +81 -0
  9. package/dist/core/dynamic-prompt/workstation.js.map +1 -0
  10. package/dist/core/extensions/builtin/anthropic-web-search/index.d.ts +6 -2
  11. package/dist/core/extensions/builtin/anthropic-web-search/index.d.ts.map +1 -1
  12. package/dist/core/extensions/builtin/anthropic-web-search/index.js +73 -5
  13. package/dist/core/extensions/builtin/anthropic-web-search/index.js.map +1 -1
  14. package/dist/core/extensions/builtin/goal/command-registration.d.ts +1 -0
  15. package/dist/core/extensions/builtin/goal/command-registration.d.ts.map +1 -1
  16. package/dist/core/extensions/builtin/goal/command-registration.js +4 -5
  17. package/dist/core/extensions/builtin/goal/command-registration.js.map +1 -1
  18. package/dist/core/extensions/builtin/goal/elapsed-ticker.d.ts +43 -0
  19. package/dist/core/extensions/builtin/goal/elapsed-ticker.d.ts.map +1 -0
  20. package/dist/core/extensions/builtin/goal/elapsed-ticker.js +58 -0
  21. package/dist/core/extensions/builtin/goal/elapsed-ticker.js.map +1 -0
  22. package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
  23. package/dist/core/extensions/builtin/goal/index.js +39 -14
  24. package/dist/core/extensions/builtin/goal/index.js.map +1 -1
  25. package/dist/core/extensions/builtin/goal/tool-registration.d.ts +1 -0
  26. package/dist/core/extensions/builtin/goal/tool-registration.d.ts.map +1 -1
  27. package/dist/core/extensions/builtin/goal/tool-registration.js +3 -4
  28. package/dist/core/extensions/builtin/goal/tool-registration.js.map +1 -1
  29. package/dist/core/extensions/builtin/goal/ui.d.ts +2 -2
  30. package/dist/core/extensions/builtin/goal/ui.d.ts.map +1 -1
  31. package/dist/core/extensions/builtin/goal/ui.js +8 -4
  32. package/dist/core/extensions/builtin/goal/ui.js.map +1 -1
  33. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.d.ts.map +1 -1
  34. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js +5 -1
  35. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js.map +1 -1
  36. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-5.d.ts.map +1 -1
  37. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-5.js +5 -1
  38. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-5.js.map +1 -1
  39. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-6.d.ts.map +1 -1
  40. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-6.js +5 -1
  41. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-6.js.map +1 -1
  42. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-7.d.ts.map +1 -1
  43. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-7.js +5 -1
  44. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-7.js.map +1 -1
  45. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-8.d.ts.map +1 -1
  46. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-8.js +5 -1
  47. package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-8.js.map +1 -1
  48. package/dist/core/extensions/builtin/prompt-preset/glm-5-2.js +1 -1
  49. package/dist/core/extensions/builtin/prompt-preset/glm-5-2.js.map +1 -1
  50. package/dist/core/extensions/builtin/prompt-preset/gpt-5.2.js +1 -1
  51. package/dist/core/extensions/builtin/prompt-preset/gpt-5.2.js.map +1 -1
  52. package/dist/core/extensions/builtin/prompt-preset/gpt-5.3-codex.js +1 -1
  53. package/dist/core/extensions/builtin/prompt-preset/gpt-5.3-codex.js.map +1 -1
  54. package/dist/core/extensions/builtin/prompt-preset/gpt-5.4.js +1 -1
  55. package/dist/core/extensions/builtin/prompt-preset/gpt-5.4.js.map +1 -1
  56. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js +1 -1
  57. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js.map +1 -1
  58. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +1 -1
  59. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js.map +1 -1
  60. package/dist/core/extensions/builtin/prompt-preset/gpt-5.js +1 -1
  61. package/dist/core/extensions/builtin/prompt-preset/gpt-5.js.map +1 -1
  62. package/dist/core/extensions/builtin/prompt-preset/kimi-k2-6.js +1 -1
  63. package/dist/core/extensions/builtin/prompt-preset/kimi-k2-6.js.map +1 -1
  64. package/dist/core/extensions/builtin/prompt-preset/kimi-k2-7.js +1 -1
  65. package/dist/core/extensions/builtin/prompt-preset/kimi-k2-7.js.map +1 -1
  66. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.d.ts +3 -0
  67. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.d.ts.map +1 -0
  68. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js +14 -0
  69. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js.map +1 -0
  70. package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
  71. package/dist/core/extensions/builtin/prompt-preset/presets.js +13 -0
  72. package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
  73. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
  74. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
  75. package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
  76. package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
  77. package/dist/core/extensions/builtin/webfetch/webfetch/renderers.d.ts.map +1 -1
  78. package/dist/core/extensions/builtin/webfetch/webfetch/renderers.js +2 -1
  79. package/dist/core/extensions/builtin/webfetch/webfetch/renderers.js.map +1 -1
  80. package/dist/core/extensions/builtin/webfetch/webfetch/tool.d.ts +27 -0
  81. package/dist/core/extensions/builtin/webfetch/webfetch/tool.d.ts.map +1 -1
  82. package/dist/core/extensions/builtin/webfetch/webfetch/tool.js +60 -1
  83. package/dist/core/extensions/builtin/webfetch/webfetch/tool.js.map +1 -1
  84. package/dist/core/extensions/types.d.ts +5 -0
  85. package/dist/core/extensions/types.d.ts.map +1 -1
  86. package/dist/core/extensions/types.js.map +1 -1
  87. package/dist/core/model-config.d.ts +5 -0
  88. package/dist/core/model-config.d.ts.map +1 -1
  89. package/dist/core/model-config.js +1 -0
  90. package/dist/core/model-config.js.map +1 -1
  91. package/dist/modes/interactive/components/tool-execution-renderer.d.ts.map +1 -1
  92. package/dist/modes/interactive/components/tool-execution-renderer.js +1 -0
  93. package/dist/modes/interactive/components/tool-execution-renderer.js.map +1 -1
  94. package/docs/settings.md +1 -1
  95. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  96. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  97. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  98. package/examples/extensions/gondolin/package-lock.json +2 -2
  99. package/examples/extensions/gondolin/package.json +1 -1
  100. package/examples/extensions/sandbox/package-lock.json +2 -2
  101. package/examples/extensions/sandbox/package.json +1 -1
  102. package/examples/extensions/with-deps/package-lock.json +2 -2
  103. package/examples/extensions/with-deps/package.json +1 -1
  104. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +37 -0
  105. package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
  106. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +59 -19
  107. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +68 -2
  108. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +6 -0
  109. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +6 -0
  110. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  111. package/node_modules/@earendil-works/pi-ai/README.md +1 -1
  112. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  113. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +58 -7
  114. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  115. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts +2 -1
  116. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  117. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +6 -1
  118. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  119. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +70 -110
  120. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  121. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts +26 -0
  122. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts.map +1 -1
  123. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js +6 -0
  124. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js.map +1 -1
  125. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.js +3 -3
  126. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.js.map +1 -1
  127. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.js +3 -3
  128. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.js.map +1 -1
  129. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.d.ts +44 -0
  130. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.d.ts.map +1 -1
  131. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js +36 -0
  132. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js.map +1 -1
  133. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +20 -20
  134. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
  135. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.d.ts +0 -110
  136. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.d.ts.map +1 -1
  137. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.js +0 -90
  138. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.js.map +1 -1
  139. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +14 -0
  140. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  141. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  142. package/node_modules/@earendil-works/pi-ai/dist/utils/tool-schema-compat.d.ts +19 -0
  143. package/node_modules/@earendil-works/pi-ai/dist/utils/tool-schema-compat.d.ts.map +1 -0
  144. package/node_modules/@earendil-works/pi-ai/dist/utils/tool-schema-compat.js +171 -0
  145. package/node_modules/@earendil-works/pi-ai/dist/utils/tool-schema-compat.js.map +1 -0
  146. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  147. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  148. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  149. package/package.json +6 -6
@@ -152,6 +152,12 @@ function getAnthropicCompat(model) {
152
152
  supportsForcedToolChoice: model.compat?.supportsForcedToolChoice ?? !CLAUDE_FABLE_OR_MYTHOS_MODEL_ID.test(model.id),
153
153
  allowEmptySignature: model.compat?.allowEmptySignature ?? false,
154
154
  supportsToolReferences: model.compat?.supportsToolReferences ?? defaultSupportsToolReferences(model),
155
+ // Default: first-party Anthropic only. Anthropic-compatible providers
156
+ // (kimi-coding, fireworks, copilot, gateways) may execute the server-side
157
+ // search but reject the replayed server_tool_use / web_search_tool_result
158
+ // blocks on the next request (kimi-coding 400s with `tool_call_id is not
159
+ // found`).
160
+ supportsWebSearch: model.compat?.supportsWebSearch ?? isAnthropicApiBaseUrl(model.baseUrl),
155
161
  };
156
162
  }
157
163
  /**
@@ -227,6 +233,23 @@ function lastAnthropicFallbackBoundary(content) {
227
233
  function isAnthropicServerToolUseBlock(raw) {
228
234
  return isRecord(raw) && raw.type === "server_tool_use" && typeof raw.id === "string";
229
235
  }
236
+ // Only tool_use-shaped provider-native blocks (server_tool_use, mcp_tool_use)
237
+ // stream their input via input_json_delta. Result-shaped blocks must replay
238
+ // byte-for-byte (encrypted_content), so never merge an `input` into them.
239
+ function isProviderNativeToolUseBlock(raw) {
240
+ return isRecord(raw) && (raw.type === "server_tool_use" || raw.type === "mcp_tool_use");
241
+ }
242
+ // Endpoints without `supportsWebSearch` reject replayed web-search server-tool
243
+ // blocks (kimi-coding 400s with `tool_call_id is not found`), wedging every
244
+ // subsequent request of the session. Dropping the pair loses the searched
245
+ // context but keeps the conversation usable.
246
+ function isAnthropicWebSearchReplayBlock(raw) {
247
+ if (!isRecord(raw))
248
+ return false;
249
+ if (raw.type === "web_search_tool_result")
250
+ return true;
251
+ return raw.type === "server_tool_use" && raw.name === "web_search";
252
+ }
230
253
  // tool_use ids referenced by server-tool result blocks in content[0, boundary).
231
254
  // A pre-boundary `server_tool_use` whose id is absent here is unpaired — the
232
255
  // fallback interrupted the declined attempt before its result arrived — so
@@ -339,27 +362,28 @@ function rejectsComputerUseBeta(model) {
339
362
  return ((model.provider === "cloudflare-ai-gateway" && model.baseUrl.includes("anthropic")) ||
340
363
  matchesModelMarker(model, UNSUPPORTED_NATIVE_COMPUTER_TOOL_MODEL_MARKERS));
341
364
  }
365
+ function isAnthropicWebSearchToolType(toolType) {
366
+ return toolType.startsWith("web_search_");
367
+ }
342
368
  function sanitizeUnsupportedNativeTools(model, params) {
343
369
  const payload = params;
344
370
  const headers = stringRecord(payload.headers);
345
371
  const headerSanitization = rejectsComputerUseBeta(model)
346
372
  ? removeComputerUseBetaHeader(headers)
347
373
  : { changed: false };
374
+ const rejectsNativeWebSearch = !getAnthropicCompat(model).supportsWebSearch;
348
375
  const tools = payload.tools;
349
376
  const sanitized = { ...payload };
350
377
  let changed = false;
351
- const removedToolNames = new Set();
352
378
  if (Array.isArray(tools)) {
353
379
  const supportedTools = [];
354
380
  for (const tool of tools) {
355
381
  const hookTool = tool;
356
382
  if (isRecord(hookTool) &&
357
383
  typeof hookTool.type === "string" &&
358
- rejectsNativeComputerTool(model, hookTool.type)) {
384
+ (rejectsNativeComputerTool(model, hookTool.type) ||
385
+ (rejectsNativeWebSearch && isAnthropicWebSearchToolType(hookTool.type)))) {
359
386
  changed = true;
360
- if (typeof hookTool.name === "string") {
361
- removedToolNames.add(hookTool.name);
362
- }
363
387
  continue;
364
388
  }
365
389
  supportedTools.push(tool);
@@ -384,7 +408,10 @@ function sanitizeUnsupportedNativeTools(model, params) {
384
408
  }
385
409
  if (changed && isRecord(sanitized.tool_choice)) {
386
410
  const toolChoiceName = sanitized.tool_choice.name;
387
- const shouldRemoveToolChoice = (typeof toolChoiceName === "string" && removedToolNames.has(toolChoiceName)) || sanitized.tools === undefined;
411
+ const hasSelectedTool = typeof toolChoiceName === "string" &&
412
+ Array.isArray(sanitized.tools) &&
413
+ sanitized.tools.some((tool) => isRecord(tool) && tool.name === toolChoiceName);
414
+ const shouldRemoveToolChoice = sanitized.tools === undefined || (typeof toolChoiceName === "string" && !hasSelectedTool);
388
415
  if (shouldRemoveToolChoice) {
389
416
  delete sanitized.tool_choice;
390
417
  }
@@ -764,6 +791,12 @@ export const stream = (model, context, options) => {
764
791
  partial: output,
765
792
  });
766
793
  }
794
+ else if (block && block.type === "providerNative" && isProviderNativeToolUseBlock(block.raw)) {
795
+ // Server-side tool blocks (server_tool_use) stream their input
796
+ // the same way tool_use does; the block captured at
797
+ // content_block_start still has `input: {}`.
798
+ block.partialJson = (block.partialJson ?? "") + event.delta.partial_json;
799
+ }
767
800
  }
768
801
  else if (event.delta.type === "signature_delta") {
769
802
  const index = blocks.findIndex((b) => b.index === event.index);
@@ -807,6 +840,13 @@ export const stream = (model, context, options) => {
807
840
  partial: output,
808
841
  });
809
842
  }
843
+ else if (block.type === "providerNative") {
844
+ const partialJson = block.partialJson;
845
+ delete block.partialJson;
846
+ if (partialJson !== undefined && isRecord(block.raw)) {
847
+ block.raw = { ...block.raw, input: parseStreamingJson(partialJson) };
848
+ }
849
+ }
810
850
  }
811
851
  }
812
852
  else if (event.type === "message_delta") {
@@ -859,6 +899,13 @@ export const stream = (model, context, options) => {
859
899
  catch (error) {
860
900
  for (const block of output.content) {
861
901
  delete block.index;
902
+ // An aborted stream never reaches content_block_stop; keep whatever
903
+ // provider-native input accumulated, mirroring toolCall's partial
904
+ // arguments.
905
+ const scratch = block.partialJson;
906
+ if (block.type === "providerNative" && scratch !== undefined && isRecord(block.raw)) {
907
+ block.raw = { ...block.raw, input: parseStreamingJson(scratch) };
908
+ }
862
909
  // partialJson is only a streaming scratch buffer; never persist it.
863
910
  delete block.partialJson;
864
911
  }
@@ -1199,6 +1246,7 @@ function convertMessages(transformedMessages, model, isOAuthToken, cacheControl,
1199
1246
  // Tool calls from a declined pre-fallback attempt are dropped from their
1200
1247
  // assistant turn below; drop their tool_results in lockstep so none dangle.
1201
1248
  const discardedFallbackToolCallIds = collectDiscardedFallbackToolCallIds(transformedMessages, model);
1249
+ const rejectsNativeWebSearchReplay = !getAnthropicCompat(model).supportsWebSearch;
1202
1250
  for (let i = 0; i < transformedMessages.length; i++) {
1203
1251
  const msg = transformedMessages[i];
1204
1252
  if (msg.role === "user") {
@@ -1320,8 +1368,11 @@ function convertMessages(transformedMessages, model, isOAuthToken, cacheControl,
1320
1368
  });
1321
1369
  }
1322
1370
  else if (block.type === "providerNative") {
1323
- if (isSameModel && isReplayableAnthropicProviderNativeBlock(block.raw))
1371
+ if (isSameModel &&
1372
+ isReplayableAnthropicProviderNativeBlock(block.raw) &&
1373
+ !(rejectsNativeWebSearchReplay && isAnthropicWebSearchReplayBlock(block.raw))) {
1324
1374
  blocks.push(block.raw);
1375
+ }
1325
1376
  }
1326
1377
  }
1327
1378
  if (blocks.length === 0)