@code-yeongyu/senpi 2026.5.15 → 2026.5.18

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 (242) hide show
  1. package/CHANGELOG.md +1170 -1161
  2. package/README.md +1 -2
  3. package/dist/cli/config-selector.d.ts.map +1 -1
  4. package/dist/cli/config-selector.js +1 -1
  5. package/dist/cli/config-selector.js.map +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +5 -1
  8. package/dist/cli.js.map +1 -1
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/config.js +12 -3
  11. package/dist/config.js.map +1 -1
  12. package/dist/core/agent-session.d.ts +11 -0
  13. package/dist/core/agent-session.d.ts.map +1 -1
  14. package/dist/core/agent-session.js +160 -13
  15. package/dist/core/agent-session.js.map +1 -1
  16. package/dist/core/compaction/compaction.d.ts +5 -3
  17. package/dist/core/compaction/compaction.d.ts.map +1 -1
  18. package/dist/core/compaction/compaction.js +22 -14
  19. package/dist/core/compaction/compaction.js.map +1 -1
  20. package/dist/core/dynamic-prompt/verification.d.ts +31 -0
  21. package/dist/core/dynamic-prompt/verification.d.ts.map +1 -1
  22. package/dist/core/dynamic-prompt/verification.js +41 -0
  23. package/dist/core/dynamic-prompt/verification.js.map +1 -1
  24. package/dist/core/extensions/builtin/compaction/context-reduction.d.ts +97 -0
  25. package/dist/core/extensions/builtin/compaction/context-reduction.d.ts.map +1 -0
  26. package/dist/core/extensions/builtin/compaction/context-reduction.js +420 -0
  27. package/dist/core/extensions/builtin/compaction/context-reduction.js.map +1 -0
  28. package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
  29. package/dist/core/extensions/builtin/compaction/index.js +168 -31
  30. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  31. package/dist/core/extensions/builtin/compaction/openai-remote.d.ts +197 -0
  32. package/dist/core/extensions/builtin/compaction/openai-remote.d.ts.map +1 -0
  33. package/dist/core/extensions/builtin/compaction/openai-remote.js +690 -0
  34. package/dist/core/extensions/builtin/compaction/openai-remote.js.map +1 -0
  35. package/dist/core/extensions/builtin/compaction/prompts.d.ts +3 -3
  36. package/dist/core/extensions/builtin/compaction/prompts.d.ts.map +1 -1
  37. package/dist/core/extensions/builtin/compaction/prompts.js +0 -22
  38. package/dist/core/extensions/builtin/compaction/prompts.js.map +1 -1
  39. package/dist/core/extensions/builtin/compaction/repair-tool-pairs.d.ts +4 -0
  40. package/dist/core/extensions/builtin/compaction/repair-tool-pairs.d.ts.map +1 -0
  41. package/dist/core/extensions/builtin/compaction/repair-tool-pairs.js +48 -0
  42. package/dist/core/extensions/builtin/compaction/repair-tool-pairs.js.map +1 -0
  43. package/dist/core/extensions/builtin/compaction/speculative.d.ts +3 -1
  44. package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
  45. package/dist/core/extensions/builtin/compaction/speculative.js +80 -33
  46. package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
  47. package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts +8 -0
  48. package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts.map +1 -1
  49. package/dist/core/extensions/builtin/compaction/todo-bridge.js +12 -6
  50. package/dist/core/extensions/builtin/compaction/todo-bridge.js.map +1 -1
  51. package/dist/core/extensions/builtin/diff.d.ts.map +1 -1
  52. package/dist/core/extensions/builtin/diff.js +1 -1
  53. package/dist/core/extensions/builtin/diff.js.map +1 -1
  54. package/dist/core/extensions/builtin/gpt-apply-patch/preview-format.d.ts.map +1 -1
  55. package/dist/core/extensions/builtin/gpt-apply-patch/preview-format.js +5 -128
  56. package/dist/core/extensions/builtin/gpt-apply-patch/preview-format.js.map +1 -1
  57. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  58. package/dist/core/extensions/builtin/index.js +0 -2
  59. package/dist/core/extensions/builtin/index.js.map +1 -1
  60. package/dist/core/extensions/builtin/openai-web-search/index.d.ts +6 -2
  61. package/dist/core/extensions/builtin/openai-web-search/index.d.ts.map +1 -1
  62. package/dist/core/extensions/builtin/openai-web-search/index.js +82 -10
  63. package/dist/core/extensions/builtin/openai-web-search/index.js.map +1 -1
  64. package/dist/core/extensions/builtin/permission-system/prompt.d.ts.map +1 -1
  65. package/dist/core/extensions/builtin/permission-system/prompt.js +0 -5
  66. package/dist/core/extensions/builtin/permission-system/prompt.js.map +1 -1
  67. package/dist/core/extensions/builtin/system-messages.d.ts +1 -1
  68. package/dist/core/extensions/builtin/system-messages.d.ts.map +1 -1
  69. package/dist/core/extensions/builtin/system-messages.js.map +1 -1
  70. package/dist/core/extensions/builtin/tool-pair-guard/index.d.ts +1 -1
  71. package/dist/core/extensions/builtin/tool-pair-guard/index.d.ts.map +1 -1
  72. package/dist/core/extensions/builtin/tool-pair-guard/index.js +8 -4
  73. package/dist/core/extensions/builtin/tool-pair-guard/index.js.map +1 -1
  74. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.d.ts +3 -0
  75. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.d.ts.map +1 -0
  76. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.js +89 -0
  77. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.js.map +1 -0
  78. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.d.ts +3 -0
  79. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.d.ts.map +1 -0
  80. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.js +122 -0
  81. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.js.map +1 -0
  82. package/dist/core/extensions/loader.d.ts.map +1 -1
  83. package/dist/core/extensions/loader.js +2 -0
  84. package/dist/core/extensions/loader.js.map +1 -1
  85. package/dist/core/extensions/runner.d.ts +3 -0
  86. package/dist/core/extensions/runner.d.ts.map +1 -1
  87. package/dist/core/extensions/runner.js +18 -0
  88. package/dist/core/extensions/runner.js.map +1 -1
  89. package/dist/core/extensions/types.d.ts +22 -0
  90. package/dist/core/extensions/types.d.ts.map +1 -1
  91. package/dist/core/extensions/types.js.map +1 -1
  92. package/dist/core/messages.d.ts +3 -3
  93. package/dist/core/messages.d.ts.map +1 -1
  94. package/dist/core/messages.js +5 -10
  95. package/dist/core/messages.js.map +1 -1
  96. package/dist/core/model-registry.d.ts +1 -0
  97. package/dist/core/model-registry.d.ts.map +1 -1
  98. package/dist/core/model-registry.js +66 -9
  99. package/dist/core/model-registry.js.map +1 -1
  100. package/dist/core/package-manager.d.ts +5 -0
  101. package/dist/core/package-manager.d.ts.map +1 -1
  102. package/dist/core/package-manager.js +72 -31
  103. package/dist/core/package-manager.js.map +1 -1
  104. package/dist/core/prompt-templates.d.ts.map +1 -1
  105. package/dist/core/prompt-templates.js +6 -4
  106. package/dist/core/prompt-templates.js.map +1 -1
  107. package/dist/core/sdk.d.ts +1 -1
  108. package/dist/core/sdk.d.ts.map +1 -1
  109. package/dist/core/sdk.js +7 -22
  110. package/dist/core/sdk.js.map +1 -1
  111. package/dist/core/session-manager.d.ts.map +1 -1
  112. package/dist/core/session-manager.js +39 -9
  113. package/dist/core/session-manager.js.map +1 -1
  114. package/dist/core/settings-manager.d.ts +0 -5
  115. package/dist/core/settings-manager.d.ts.map +1 -1
  116. package/dist/core/settings-manager.js.map +1 -1
  117. package/dist/core/skills.d.ts.map +1 -1
  118. package/dist/core/skills.js +2 -5
  119. package/dist/core/skills.js.map +1 -1
  120. package/dist/core/system-prompt.d.ts.map +1 -1
  121. package/dist/core/system-prompt.js +3 -2
  122. package/dist/core/system-prompt.js.map +1 -1
  123. package/dist/core/thinking-levels.d.ts +6 -0
  124. package/dist/core/thinking-levels.d.ts.map +1 -0
  125. package/dist/core/thinking-levels.js +36 -0
  126. package/dist/core/thinking-levels.js.map +1 -0
  127. package/dist/core/tools/bash.d.ts.map +1 -1
  128. package/dist/core/tools/bash.js +15 -1
  129. package/dist/core/tools/bash.js.map +1 -1
  130. package/dist/core/tools/diff-render.d.ts +13 -0
  131. package/dist/core/tools/diff-render.d.ts.map +1 -0
  132. package/dist/core/tools/diff-render.js +130 -0
  133. package/dist/core/tools/diff-render.js.map +1 -0
  134. package/dist/core/tools/edit.d.ts.map +1 -1
  135. package/dist/core/tools/edit.js +8 -3
  136. package/dist/core/tools/edit.js.map +1 -1
  137. package/dist/core/tools/write.d.ts.map +1 -1
  138. package/dist/core/tools/write.js +28 -7
  139. package/dist/core/tools/write.js.map +1 -1
  140. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  141. package/dist/modes/interactive/components/compaction-summary-message.js +20 -2
  142. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  143. package/dist/modes/interactive/components/config-selector.d.ts +2 -2
  144. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  145. package/dist/modes/interactive/components/config-selector.js +7 -4
  146. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  147. package/dist/modes/interactive/components/footer.d.ts +0 -1
  148. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  149. package/dist/modes/interactive/components/footer.js +42 -44
  150. package/dist/modes/interactive/components/footer.js.map +1 -1
  151. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  152. package/dist/modes/interactive/components/keybinding-hints.js +3 -1
  153. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  154. package/dist/modes/interactive/interactive-mode.d.ts +9 -0
  155. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  156. package/dist/modes/interactive/interactive-mode.js +177 -82
  157. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  158. package/dist/modes/interactive/session-info-format.d.ts +3 -0
  159. package/dist/modes/interactive/session-info-format.d.ts.map +1 -0
  160. package/dist/modes/interactive/session-info-format.js +44 -0
  161. package/dist/modes/interactive/session-info-format.js.map +1 -0
  162. package/dist/modes/interactive/working-status.d.ts +21 -0
  163. package/dist/modes/interactive/working-status.d.ts.map +1 -0
  164. package/dist/modes/interactive/working-status.js +71 -0
  165. package/dist/modes/interactive/working-status.js.map +1 -0
  166. package/dist/package-manager-cli.d.ts.map +1 -1
  167. package/dist/package-manager-cli.js +3 -4
  168. package/dist/package-manager-cli.js.map +1 -1
  169. package/dist/senpi +5 -1
  170. package/dist/utils/child-process.d.ts +7 -1
  171. package/dist/utils/child-process.d.ts.map +1 -1
  172. package/dist/utils/child-process.js +60 -7
  173. package/dist/utils/child-process.js.map +1 -1
  174. package/dist/utils/clipboard-image.d.ts.map +1 -1
  175. package/dist/utils/clipboard-image.js +1 -1
  176. package/dist/utils/clipboard-image.js.map +1 -1
  177. package/dist/utils/tools-manager.d.ts.map +1 -1
  178. package/dist/utils/tools-manager.js +4 -1
  179. package/dist/utils/tools-manager.js.map +1 -1
  180. package/docs/custom-provider.md +55 -0
  181. package/docs/extensions.md +1 -2
  182. package/docs/index.md +0 -1
  183. package/docs/models.md +9 -0
  184. package/docs/sdk.md +0 -1
  185. package/docs/settings.md +2 -32
  186. package/docs/skills.md +3 -4
  187. package/docs/termux.md +2 -2
  188. package/docs/usage.md +1 -1
  189. package/examples/README.md +1 -1
  190. package/examples/extensions/README.md +0 -1
  191. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  192. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  193. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  194. package/examples/extensions/overlay-qa-tests.ts +1 -1
  195. package/examples/extensions/sandbox/package-lock.json +2 -2
  196. package/examples/extensions/sandbox/package.json +1 -1
  197. package/examples/extensions/with-deps/package-lock.json +2 -2
  198. package/examples/extensions/with-deps/package.json +1 -1
  199. package/package.json +6 -6
  200. package/dist/core/extensions/builtin/background-task/cancel-tool.d.ts +0 -10
  201. package/dist/core/extensions/builtin/background-task/cancel-tool.d.ts.map +0 -1
  202. package/dist/core/extensions/builtin/background-task/cancel-tool.js +0 -109
  203. package/dist/core/extensions/builtin/background-task/cancel-tool.js.map +0 -1
  204. package/dist/core/extensions/builtin/background-task/index.d.ts +0 -3
  205. package/dist/core/extensions/builtin/background-task/index.d.ts.map +0 -1
  206. package/dist/core/extensions/builtin/background-task/index.js +0 -207
  207. package/dist/core/extensions/builtin/background-task/index.js.map +0 -1
  208. package/dist/core/extensions/builtin/background-task/manager.d.ts +0 -17
  209. package/dist/core/extensions/builtin/background-task/manager.d.ts.map +0 -1
  210. package/dist/core/extensions/builtin/background-task/manager.js +0 -114
  211. package/dist/core/extensions/builtin/background-task/manager.js.map +0 -1
  212. package/dist/core/extensions/builtin/background-task/notification.d.ts +0 -22
  213. package/dist/core/extensions/builtin/background-task/notification.d.ts.map +0 -1
  214. package/dist/core/extensions/builtin/background-task/notification.js +0 -105
  215. package/dist/core/extensions/builtin/background-task/notification.js.map +0 -1
  216. package/dist/core/extensions/builtin/background-task/output-tool.d.ts +0 -11
  217. package/dist/core/extensions/builtin/background-task/output-tool.d.ts.map +0 -1
  218. package/dist/core/extensions/builtin/background-task/output-tool.js +0 -127
  219. package/dist/core/extensions/builtin/background-task/output-tool.js.map +0 -1
  220. package/dist/core/extensions/builtin/background-task/spawner.d.ts +0 -8
  221. package/dist/core/extensions/builtin/background-task/spawner.d.ts.map +0 -1
  222. package/dist/core/extensions/builtin/background-task/spawner.js +0 -207
  223. package/dist/core/extensions/builtin/background-task/spawner.js.map +0 -1
  224. package/dist/core/extensions/builtin/background-task/task-tool.d.ts +0 -20
  225. package/dist/core/extensions/builtin/background-task/task-tool.d.ts.map +0 -1
  226. package/dist/core/extensions/builtin/background-task/task-tool.js +0 -302
  227. package/dist/core/extensions/builtin/background-task/task-tool.js.map +0 -1
  228. package/dist/core/extensions/builtin/background-task/types.d.ts +0 -72
  229. package/dist/core/extensions/builtin/background-task/types.d.ts.map +0 -1
  230. package/dist/core/extensions/builtin/background-task/types.js +0 -32
  231. package/dist/core/extensions/builtin/background-task/types.js.map +0 -1
  232. package/docs/agents.md +0 -348
  233. package/examples/extensions/subagent/README.md +0 -172
  234. package/examples/extensions/subagent/agents/planner.md +0 -37
  235. package/examples/extensions/subagent/agents/reviewer.md +0 -35
  236. package/examples/extensions/subagent/agents/scout.md +0 -50
  237. package/examples/extensions/subagent/agents/worker.md +0 -24
  238. package/examples/extensions/subagent/agents.ts +0 -126
  239. package/examples/extensions/subagent/index.ts +0 -987
  240. package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
  241. package/examples/extensions/subagent/prompts/implement.md +0 -10
  242. package/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/openai-web-search/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Api } from \"@earendil-works/pi-ai\";\nimport type { ExtensionAPI, ExtensionContext } from \"../../types.js\";\n\ntype ToolDefinition = Record<string, unknown>;\n\nconst OPENAI_RESPONSES_APIS: ReadonlySet<Api> = new Set([\"openai-responses\", \"azure-openai-responses\"]);\nconst ENABLE_ENV = \"PI_OPENAI_WEB_SEARCH\";\nconst NATIVE_OPENAI_WEB_SEARCH_TYPE = \"web_search_preview\";\nconst WEB_SEARCH_SOURCES_INCLUDE = \"web_search_call.action.sources\";\nconst STATUS_KEY = \"openai-web-search\";\nconst WIDGET_KEY = \"openai-web-search\";\n\nfunction parseEnableEnv(envVar: string): boolean {\n\tconst envValue = process.env[envVar];\n\tif (!envValue) {\n\t\treturn true;\n\t}\n\n\tconst normalized = envValue.trim().toLowerCase();\n\tif (normalized === \"0\" || normalized === \"false\" || normalized === \"no\" || normalized === \"off\") {\n\t\treturn false;\n\t}\n\n\tif (normalized === \"1\" || normalized === \"true\" || normalized === \"yes\" || normalized === \"on\") {\n\t\treturn true;\n\t}\n\n\t// Unknown values fall back to default-on behavior.\n\treturn true;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction isOpenAiResponsesApi(api: Api | undefined): api is \"openai-responses\" | \"azure-openai-responses\" {\n\treturn api !== undefined && OPENAI_RESPONSES_APIS.has(api);\n}\n\nfunction isNativeOpenAiWebSearchType(value: unknown): value is \"web_search_preview\" | \"web_search_preview_2025_03_11\" {\n\treturn value === \"web_search_preview\" || value === \"web_search_preview_2025_03_11\";\n}\n\nfunction isUnsupportedWebSearchType(value: unknown): boolean {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\t(value === \"web_search\" || value.startsWith(\"web_search_\")) &&\n\t\t!isNativeOpenAiWebSearchType(value)\n\t);\n}\n\nfunction isAnthropicWebFetchType(value: unknown): boolean {\n\treturn typeof value === \"string\" && value.startsWith(\"web_fetch_\");\n}\n\ntype SanitizedTools = {\n\tchanged: boolean;\n\ttools: ToolDefinition[];\n};\n\ntype SanitizeToolsOptions = {\n\tstripFunctionWebSearch: boolean;\n};\n\nfunction sanitizeTools(tools: unknown[], options: SanitizeToolsOptions): SanitizedTools {\n\tconst sanitized: ToolDefinition[] = [];\n\tlet changed = false;\n\tfor (const tool of tools) {\n\t\tif (!isRecord(tool)) {\n\t\t\tchanged = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst type = tool.type;\n\t\tconst shouldStripFunctionVariant =\n\t\t\toptions.stripFunctionWebSearch && tool.name === \"web_search\" && !isNativeOpenAiWebSearchType(type);\n\t\tconst shouldStripProviderNativeVariant = isUnsupportedWebSearchType(type) || isAnthropicWebFetchType(type);\n\t\tif (shouldStripFunctionVariant || shouldStripProviderNativeVariant) {\n\t\t\tchanged = true;\n\t\t} else {\n\t\t\tsanitized.push(tool);\n\t\t}\n\t}\n\n\treturn { changed, tools: sanitized };\n}\n\nfunction includeWebSearchSources(payload: Record<string, unknown>): string[] {\n\tconst include = Array.isArray(payload.include)\n\t\t? payload.include.filter((value): value is string => typeof value === \"string\")\n\t\t: [];\n\treturn include.includes(WEB_SEARCH_SOURCES_INCLUDE) ? include : [...include, WEB_SEARCH_SOURCES_INCLUDE];\n}\n\nexport function addOpenAiWebSearchToPayload(api: Api | undefined, payload: unknown): unknown {\n\tif (!isOpenAiResponsesApi(api)) {\n\t\treturn payload;\n\t}\n\n\tif (!isRecord(payload)) {\n\t\treturn payload;\n\t}\n\n\tconst tools = Array.isArray(payload.tools) ? payload.tools : [];\n\tconst shouldInjectWebSearch = isOpenaiWebSearchEnabled();\n\tconst sanitized = sanitizeTools(tools, { stripFunctionWebSearch: shouldInjectWebSearch });\n\tconst sanitizedTools = sanitized.tools;\n\tif (!shouldInjectWebSearch) {\n\t\tif (!sanitized.changed) {\n\t\t\treturn payload;\n\t\t}\n\n\t\treturn {\n\t\t\t...payload,\n\t\t\ttools: sanitizedTools,\n\t\t};\n\t}\n\n\tconst hasNativeWebSearch = sanitizedTools.some((tool) => isNativeOpenAiWebSearchType(tool.type));\n\n\tif (!hasNativeWebSearch) {\n\t\tsanitizedTools.push({ type: NATIVE_OPENAI_WEB_SEARCH_TYPE });\n\t}\n\n\treturn {\n\t\t...payload,\n\t\ttools: sanitizedTools,\n\t\tinclude: includeWebSearchSources(payload),\n\t};\n}\n\nexport function isOpenaiWebSearchEnabled(): boolean {\n\treturn parseEnableEnv(ENABLE_ENV);\n}\n\nfunction clearUi(ctx: ExtensionContext): void {\n\tif (!ctx.hasUI) return;\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\tctx.ui.setWidget(WIDGET_KEY, undefined);\n}\n\nfunction syncUi(ctx: ExtensionContext): void {\n\tclearUi(ctx);\n}\n\nexport const OPENAI_WEB_SEARCH_SECTION = `\n## Web Search\n\nNative web search is available in this session.\nUse web search when the user asks for current or online information.\nPrefer web search over guessing when freshness matters.\n`;\n\nexport default function openaiWebSearchExtension(pi: ExtensionAPI): void {\n\tpi.on(\"before_provider_request\", (event, ctx) => {\n\t\treturn addOpenAiWebSearchToPayload(ctx.model?.api, event.payload);\n\t});\n\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\tsyncUi(ctx);\n\t});\n\n\tpi.on(\"model_select\", async (_event, ctx) => {\n\t\tsyncUi(ctx);\n\t});\n\n\tpi.on(\"session_shutdown\", async (_event, ctx) => {\n\t\tclearUi(ctx);\n\t});\n\n\tpi.on(\"before_agent_start\", async (event, ctx) => {\n\t\tif (!isOpenAiResponsesApi(ctx.model?.api)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!isOpenaiWebSearchEnabled()) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n${OPENAI_WEB_SEARCH_SECTION}`,\n\t\t};\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/openai-web-search/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Api, Model, OpenAIResponsesCompat } from \"@earendil-works/pi-ai\";\nimport type { ExtensionAPI, ExtensionContext } from \"../../types.js\";\n\ntype ToolDefinition = Record<string, unknown>;\ntype OpenAiWebSearchModel = Pick<Model<Api>, \"api\" | \"baseUrl\" | \"compat\">;\ntype OpenAiWebSearchTarget = Api | OpenAiWebSearchModel | undefined;\n\nconst OPENAI_RESPONSES_APIS: ReadonlySet<Api> = new Set([\"openai-responses\", \"azure-openai-responses\"]);\nconst ENABLE_ENV = \"PI_OPENAI_WEB_SEARCH\";\nconst NATIVE_OPENAI_WEB_SEARCH_TYPE = \"web_search_preview\";\nconst WEB_SEARCH_SOURCES_INCLUDE = \"web_search_call.action.sources\";\nconst STATUS_KEY = \"openai-web-search\";\nconst WIDGET_KEY = \"openai-web-search\";\n\nfunction parseEnableEnv(envVar: string): boolean {\n\tconst envValue = process.env[envVar];\n\tif (!envValue) {\n\t\treturn true;\n\t}\n\n\tconst normalized = envValue.trim().toLowerCase();\n\tif (normalized === \"0\" || normalized === \"false\" || normalized === \"no\" || normalized === \"off\") {\n\t\treturn false;\n\t}\n\n\tif (normalized === \"1\" || normalized === \"true\" || normalized === \"yes\" || normalized === \"on\") {\n\t\treturn true;\n\t}\n\n\t// Unknown values fall back to default-on behavior.\n\treturn true;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction isOpenAiResponsesApi(api: Api | undefined): api is \"openai-responses\" | \"azure-openai-responses\" {\n\treturn api !== undefined && OPENAI_RESPONSES_APIS.has(api);\n}\n\nfunction resolveTarget(target: OpenAiWebSearchTarget): OpenAiWebSearchModel | undefined {\n\tif (target === undefined) {\n\t\treturn undefined;\n\t}\n\tif (typeof target === \"string\") {\n\t\treturn { api: target, baseUrl: target === \"openai-responses\" ? \"https://api.openai.com/v1\" : \"\" };\n\t}\n\treturn target;\n}\n\nfunction isOpenAiResponsesNativeEndpoint(model: OpenAiWebSearchModel): boolean {\n\ttry {\n\t\treturn new URL(model.baseUrl || \"https://api.openai.com/v1\").hostname === \"api.openai.com\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport function supportsNativeOpenAiWebSearch(target: OpenAiWebSearchTarget): boolean {\n\tconst model = resolveTarget(target);\n\tif (!isOpenAiResponsesApi(model?.api)) {\n\t\treturn false;\n\t}\n\tif (model.api === \"azure-openai-responses\") {\n\t\treturn true;\n\t}\n\n\tconst compat = model.compat as OpenAIResponsesCompat | undefined;\n\treturn compat?.supportsWebSearchPreview ?? isOpenAiResponsesNativeEndpoint(model);\n}\n\nfunction isNativeOpenAiWebSearchType(value: unknown): value is \"web_search_preview\" | \"web_search_preview_2025_03_11\" {\n\treturn value === \"web_search_preview\" || value === \"web_search_preview_2025_03_11\";\n}\n\nfunction isUnsupportedWebSearchType(value: unknown): boolean {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\t(value === \"web_search\" || value.startsWith(\"web_search_\")) &&\n\t\t!isNativeOpenAiWebSearchType(value)\n\t);\n}\n\nfunction isAnthropicWebFetchType(value: unknown): boolean {\n\treturn typeof value === \"string\" && value.startsWith(\"web_fetch_\");\n}\n\ntype SanitizedTools = {\n\tchanged: boolean;\n\ttools: ToolDefinition[];\n};\n\ntype SanitizeToolsOptions = {\n\tstripFunctionWebSearch: boolean;\n};\n\nfunction stripNativeOpenAiWebSearch(payload: unknown): unknown {\n\tif (!isRecord(payload)) {\n\t\treturn payload;\n\t}\n\n\tlet changed = false;\n\tconst sanitized: Record<string, unknown> = { ...payload };\n\n\tconst tools = payload.tools;\n\tif (Array.isArray(tools)) {\n\t\tconst sanitizedTools = tools.filter((tool) => !(isRecord(tool) && isNativeOpenAiWebSearchType(tool.type)));\n\t\tif (sanitizedTools.length !== tools.length) {\n\t\t\tchanged = true;\n\t\t\tsanitized.tools = sanitizedTools;\n\t\t}\n\t}\n\n\tconst include = payload.include;\n\tif (Array.isArray(include)) {\n\t\tconst sanitizedInclude = include.filter((value) => value !== WEB_SEARCH_SOURCES_INCLUDE);\n\t\tif (sanitizedInclude.length !== include.length) {\n\t\t\tchanged = true;\n\t\t\tsanitized.include = sanitizedInclude;\n\t\t}\n\t}\n\n\tif (isRecord(payload.tool_choice) && isNativeOpenAiWebSearchType(payload.tool_choice.type)) {\n\t\tchanged = true;\n\t\tdelete sanitized.tool_choice;\n\t}\n\n\treturn changed ? sanitized : payload;\n}\n\nfunction sanitizeTools(tools: unknown[], options: SanitizeToolsOptions): SanitizedTools {\n\tconst sanitized: ToolDefinition[] = [];\n\tlet changed = false;\n\tfor (const tool of tools) {\n\t\tif (!isRecord(tool)) {\n\t\t\tchanged = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst type = tool.type;\n\t\tconst shouldStripFunctionVariant =\n\t\t\toptions.stripFunctionWebSearch && tool.name === \"web_search\" && !isNativeOpenAiWebSearchType(type);\n\t\tconst shouldStripProviderNativeVariant = isUnsupportedWebSearchType(type) || isAnthropicWebFetchType(type);\n\t\tif (shouldStripFunctionVariant || shouldStripProviderNativeVariant) {\n\t\t\tchanged = true;\n\t\t} else {\n\t\t\tsanitized.push(tool);\n\t\t}\n\t}\n\n\treturn { changed, tools: sanitized };\n}\n\nfunction includeWebSearchSources(payload: Record<string, unknown>): string[] {\n\tconst include = Array.isArray(payload.include)\n\t\t? payload.include.filter((value): value is string => typeof value === \"string\")\n\t\t: [];\n\treturn include.includes(WEB_SEARCH_SOURCES_INCLUDE) ? include : [...include, WEB_SEARCH_SOURCES_INCLUDE];\n}\n\nexport function addOpenAiWebSearchToPayload(target: OpenAiWebSearchTarget, payload: unknown): unknown {\n\tconst model = resolveTarget(target);\n\tif (!isOpenAiResponsesApi(model?.api)) {\n\t\t// Defense in depth. `web_search_preview` is an OpenAI Responses-only tool\n\t\t// type, but proxies that translate openai-responses → anthropic-messages\n\t\t// (e.g., ccapi/quotio for Claude models) can forward it verbatim, which\n\t\t// Anthropic rejects with `tools.N: Input tag 'web_search_preview'...`.\n\t\t// Strip the OpenAI-native variants for any non-openai-responses payload\n\t\t// so they never leak to Anthropic or Chat Completions backends.\n\t\treturn stripNativeOpenAiWebSearch(payload);\n\t}\n\n\tif (!isRecord(payload)) {\n\t\treturn payload;\n\t}\n\n\tconst supportsNativeWebSearch = supportsNativeOpenAiWebSearch(model);\n\tconst tools = Array.isArray(payload.tools) ? payload.tools : [];\n\tconst shouldInjectWebSearch = supportsNativeWebSearch && isOpenaiWebSearchEnabled();\n\tconst strippedPayload = supportsNativeWebSearch ? payload : stripNativeOpenAiWebSearch(payload);\n\tif (!isRecord(strippedPayload)) {\n\t\treturn strippedPayload;\n\t}\n\n\tconst strippedTools = Array.isArray(strippedPayload.tools) ? strippedPayload.tools : [];\n\tconst activeTools = supportsNativeWebSearch ? tools : strippedTools;\n\tconst sanitized = sanitizeTools(tools, { stripFunctionWebSearch: shouldInjectWebSearch });\n\tconst sanitizedTools = sanitized.tools;\n\tif (!shouldInjectWebSearch) {\n\t\tconst nativeStripped = strippedPayload !== payload;\n\t\tconst passiveSanitized = sanitizeTools(activeTools, { stripFunctionWebSearch: false });\n\t\tif (!nativeStripped && !passiveSanitized.changed) {\n\t\t\treturn strippedPayload;\n\t\t}\n\n\t\treturn {\n\t\t\t...strippedPayload,\n\t\t\ttools: passiveSanitized.tools,\n\t\t};\n\t}\n\n\tconst hasNativeWebSearch = sanitizedTools.some((tool) => isNativeOpenAiWebSearchType(tool.type));\n\n\tif (!hasNativeWebSearch) {\n\t\tsanitizedTools.push({ type: NATIVE_OPENAI_WEB_SEARCH_TYPE });\n\t}\n\n\treturn {\n\t\t...payload,\n\t\ttools: sanitizedTools,\n\t\tinclude: includeWebSearchSources(payload),\n\t};\n}\n\nexport function isOpenaiWebSearchEnabled(): boolean {\n\treturn parseEnableEnv(ENABLE_ENV);\n}\n\nfunction clearUi(ctx: ExtensionContext): void {\n\tif (!ctx.hasUI) return;\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\tctx.ui.setWidget(WIDGET_KEY, undefined);\n}\n\nfunction syncUi(ctx: ExtensionContext): void {\n\tclearUi(ctx);\n}\n\nexport const OPENAI_WEB_SEARCH_SECTION = `\n## Web Search\n\nNative web search is available in this session.\nUse web search when the user asks for current or online information.\nPrefer web search over guessing when freshness matters.\n`;\n\nexport default function openaiWebSearchExtension(pi: ExtensionAPI): void {\n\tpi.on(\"before_provider_request\", (event, ctx) => {\n\t\treturn addOpenAiWebSearchToPayload(ctx.model, event.payload);\n\t});\n\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\tsyncUi(ctx);\n\t});\n\n\tpi.on(\"model_select\", async (_event, ctx) => {\n\t\tsyncUi(ctx);\n\t});\n\n\tpi.on(\"session_shutdown\", async (_event, ctx) => {\n\t\tclearUi(ctx);\n\t});\n\n\tpi.on(\"before_agent_start\", async (event, ctx) => {\n\t\tif (!supportsNativeOpenAiWebSearch(ctx.model)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!isOpenaiWebSearchEnabled()) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n${OPENAI_WEB_SEARCH_SECTION}`,\n\t\t};\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/permission-system/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAS,UAAU,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE7D,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CA6BvG","sourcesContent":["import type { ExtensionContext } from \"../../types.js\";\nimport type { Reply, ReplyInput, Request } from \"./types.js\";\n\nexport async function showPermissionPrompt(ctx: ExtensionContext, request: Request): Promise<ReplyInput> {\n\tconst title = `Permission required: ${request.permission}`;\n\tconst message = formatRequestForDisplay(request);\n\n\tconst displayTitle = `${title}\\n\\n${message}`;\n\n\tconst options = [\"Allow once\", \"Allow always\", \"Deny\", \"Deny with feedback\"];\n\n\tconst choice = await ctx.ui.select(displayTitle, options);\n\n\tif (choice === \"Deny with feedback\") {\n\t\tconst feedback = await ctx.ui.input(\"Feedback\", \"Why are you denying this permission? (optional)\");\n\t\treturn {\n\t\t\trequestID: request.id,\n\t\t\treply: \"reject\",\n\t\t\tmessage: feedback || undefined,\n\t\t};\n\t}\n\n\tconst replyMap: Record<string, Reply> = {\n\t\t\"Allow once\": \"once\",\n\t\t\"Allow always\": \"always\",\n\t\tDeny: \"reject\",\n\t};\n\n\treturn {\n\t\trequestID: request.id,\n\t\treply: choice ? replyMap[choice] : \"reject\",\n\t};\n}\n\nfunction formatRequestForDisplay(request: Request): string {\n\tconst parts: string[] = [];\n\tconst meta = request.metadata || {};\n\n\tswitch (request.permission) {\n\t\tcase \"edit\":\n\t\t\tparts.push(`File: ${meta.filepath || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"read\":\n\t\t\tparts.push(`Path: ${meta.filePath || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"glob\":\n\t\tcase \"grep\":\n\t\t\tparts.push(`Pattern: ${meta.pattern || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"list\":\n\t\t\tparts.push(`Path: ${meta.path || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"bash\":\n\t\t\tif (meta.description) parts.push(`Description: ${meta.description}`);\n\t\t\tparts.push(`Command: $ ${meta.command || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"task\":\n\t\t\tparts.push(`Type: ${meta.subagent_type || \"Unknown\"}`);\n\t\t\tif (meta.description) parts.push(`Description: ${meta.description}`);\n\t\t\tbreak;\n\t\tcase \"websearch\":\n\t\tcase \"codesearch\":\n\t\t\tparts.push(`Query: ${meta.query || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"external_directory\": {\n\t\t\tconst parent = typeof meta.parentDir === \"string\" ? meta.parentDir : undefined;\n\t\t\tconst filepath = typeof meta.filepath === \"string\" ? meta.filepath : undefined;\n\t\t\tconst pattern = request.patterns?.[0];\n\t\t\tconst derived =\n\t\t\t\ttypeof pattern === \"string\" ? (pattern.includes(\"*\") ? pattern.split(\"*\")[0] : pattern) : undefined;\n\t\t\tconst dir = parent ?? filepath ?? derived ?? \"Unknown\";\n\t\t\tparts.push(`Directory: ${dir}`);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tparts.push(`Tool: ${request.permission}`);\n\t\t\tbreak;\n\t}\n\n\tif (request.patterns && request.patterns.length > 0) {\n\t\tparts.push(`\\nPatterns:\\n${request.patterns.map((p) => ` - ${p}`).join(\"\\n\")}`);\n\t}\n\n\treturn parts.join(\"\\n\");\n}\n"]}
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/permission-system/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAS,UAAU,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE7D,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CA6BvG","sourcesContent":["import type { ExtensionContext } from \"../../types.js\";\nimport type { Reply, ReplyInput, Request } from \"./types.js\";\n\nexport async function showPermissionPrompt(ctx: ExtensionContext, request: Request): Promise<ReplyInput> {\n\tconst title = `Permission required: ${request.permission}`;\n\tconst message = formatRequestForDisplay(request);\n\n\tconst displayTitle = `${title}\\n\\n${message}`;\n\n\tconst options = [\"Allow once\", \"Allow always\", \"Deny\", \"Deny with feedback\"];\n\n\tconst choice = await ctx.ui.select(displayTitle, options);\n\n\tif (choice === \"Deny with feedback\") {\n\t\tconst feedback = await ctx.ui.input(\"Feedback\", \"Why are you denying this permission? (optional)\");\n\t\treturn {\n\t\t\trequestID: request.id,\n\t\t\treply: \"reject\",\n\t\t\tmessage: feedback || undefined,\n\t\t};\n\t}\n\n\tconst replyMap: Record<string, Reply> = {\n\t\t\"Allow once\": \"once\",\n\t\t\"Allow always\": \"always\",\n\t\tDeny: \"reject\",\n\t};\n\n\treturn {\n\t\trequestID: request.id,\n\t\treply: choice ? replyMap[choice] : \"reject\",\n\t};\n}\n\nfunction formatRequestForDisplay(request: Request): string {\n\tconst parts: string[] = [];\n\tconst meta = request.metadata || {};\n\n\tswitch (request.permission) {\n\t\tcase \"edit\":\n\t\t\tparts.push(`File: ${meta.filepath || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"read\":\n\t\t\tparts.push(`Path: ${meta.filePath || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"glob\":\n\t\tcase \"grep\":\n\t\t\tparts.push(`Pattern: ${meta.pattern || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"list\":\n\t\t\tparts.push(`Path: ${meta.path || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"bash\":\n\t\t\tif (meta.description) parts.push(`Description: ${meta.description}`);\n\t\t\tparts.push(`Command: $ ${meta.command || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"websearch\":\n\t\tcase \"codesearch\":\n\t\t\tparts.push(`Query: ${meta.query || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"external_directory\": {\n\t\t\tconst parent = typeof meta.parentDir === \"string\" ? meta.parentDir : undefined;\n\t\t\tconst filepath = typeof meta.filepath === \"string\" ? meta.filepath : undefined;\n\t\t\tconst pattern = request.patterns?.[0];\n\t\t\tconst derived =\n\t\t\t\ttypeof pattern === \"string\" ? (pattern.includes(\"*\") ? pattern.split(\"*\")[0] : pattern) : undefined;\n\t\t\tconst dir = parent ?? filepath ?? derived ?? \"Unknown\";\n\t\t\tparts.push(`Directory: ${dir}`);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tparts.push(`Tool: ${request.permission}`);\n\t\t\tbreak;\n\t}\n\n\tif (request.patterns && request.patterns.length > 0) {\n\t\tparts.push(`\\nPatterns:\\n${request.patterns.map((p) => ` - ${p}`).join(\"\\n\")}`);\n\t}\n\n\treturn parts.join(\"\\n\");\n}\n"]}
@@ -44,11 +44,6 @@ function formatRequestForDisplay(request) {
44
44
  parts.push(`Description: ${meta.description}`);
45
45
  parts.push(`Command: $ ${meta.command || "Unknown"}`);
46
46
  break;
47
- case "task":
48
- parts.push(`Type: ${meta.subagent_type || "Unknown"}`);
49
- if (meta.description)
50
- parts.push(`Description: ${meta.description}`);
51
- break;
52
47
  case "websearch":
53
48
  case "codesearch":
54
49
  parts.push(`Query: ${meta.query || "Unknown"}`);
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/permission-system/prompt.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtensionContext } from \"../../types.js\";\nimport type { Reply, ReplyInput, Request } from \"./types.js\";\n\nexport async function showPermissionPrompt(ctx: ExtensionContext, request: Request): Promise<ReplyInput> {\n\tconst title = `Permission required: ${request.permission}`;\n\tconst message = formatRequestForDisplay(request);\n\n\tconst displayTitle = `${title}\\n\\n${message}`;\n\n\tconst options = [\"Allow once\", \"Allow always\", \"Deny\", \"Deny with feedback\"];\n\n\tconst choice = await ctx.ui.select(displayTitle, options);\n\n\tif (choice === \"Deny with feedback\") {\n\t\tconst feedback = await ctx.ui.input(\"Feedback\", \"Why are you denying this permission? (optional)\");\n\t\treturn {\n\t\t\trequestID: request.id,\n\t\t\treply: \"reject\",\n\t\t\tmessage: feedback || undefined,\n\t\t};\n\t}\n\n\tconst replyMap: Record<string, Reply> = {\n\t\t\"Allow once\": \"once\",\n\t\t\"Allow always\": \"always\",\n\t\tDeny: \"reject\",\n\t};\n\n\treturn {\n\t\trequestID: request.id,\n\t\treply: choice ? replyMap[choice] : \"reject\",\n\t};\n}\n\nfunction formatRequestForDisplay(request: Request): string {\n\tconst parts: string[] = [];\n\tconst meta = request.metadata || {};\n\n\tswitch (request.permission) {\n\t\tcase \"edit\":\n\t\t\tparts.push(`File: ${meta.filepath || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"read\":\n\t\t\tparts.push(`Path: ${meta.filePath || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"glob\":\n\t\tcase \"grep\":\n\t\t\tparts.push(`Pattern: ${meta.pattern || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"list\":\n\t\t\tparts.push(`Path: ${meta.path || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"bash\":\n\t\t\tif (meta.description) parts.push(`Description: ${meta.description}`);\n\t\t\tparts.push(`Command: $ ${meta.command || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"task\":\n\t\t\tparts.push(`Type: ${meta.subagent_type || \"Unknown\"}`);\n\t\t\tif (meta.description) parts.push(`Description: ${meta.description}`);\n\t\t\tbreak;\n\t\tcase \"websearch\":\n\t\tcase \"codesearch\":\n\t\t\tparts.push(`Query: ${meta.query || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"external_directory\": {\n\t\t\tconst parent = typeof meta.parentDir === \"string\" ? meta.parentDir : undefined;\n\t\t\tconst filepath = typeof meta.filepath === \"string\" ? meta.filepath : undefined;\n\t\t\tconst pattern = request.patterns?.[0];\n\t\t\tconst derived =\n\t\t\t\ttypeof pattern === \"string\" ? (pattern.includes(\"*\") ? pattern.split(\"*\")[0] : pattern) : undefined;\n\t\t\tconst dir = parent ?? filepath ?? derived ?? \"Unknown\";\n\t\t\tparts.push(`Directory: ${dir}`);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tparts.push(`Tool: ${request.permission}`);\n\t\t\tbreak;\n\t}\n\n\tif (request.patterns && request.patterns.length > 0) {\n\t\tparts.push(`\\nPatterns:\\n${request.patterns.map((p) => ` - ${p}`).join(\"\\n\")}`);\n\t}\n\n\treturn parts.join(\"\\n\");\n}\n"]}
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/permission-system/prompt.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtensionContext } from \"../../types.js\";\nimport type { Reply, ReplyInput, Request } from \"./types.js\";\n\nexport async function showPermissionPrompt(ctx: ExtensionContext, request: Request): Promise<ReplyInput> {\n\tconst title = `Permission required: ${request.permission}`;\n\tconst message = formatRequestForDisplay(request);\n\n\tconst displayTitle = `${title}\\n\\n${message}`;\n\n\tconst options = [\"Allow once\", \"Allow always\", \"Deny\", \"Deny with feedback\"];\n\n\tconst choice = await ctx.ui.select(displayTitle, options);\n\n\tif (choice === \"Deny with feedback\") {\n\t\tconst feedback = await ctx.ui.input(\"Feedback\", \"Why are you denying this permission? (optional)\");\n\t\treturn {\n\t\t\trequestID: request.id,\n\t\t\treply: \"reject\",\n\t\t\tmessage: feedback || undefined,\n\t\t};\n\t}\n\n\tconst replyMap: Record<string, Reply> = {\n\t\t\"Allow once\": \"once\",\n\t\t\"Allow always\": \"always\",\n\t\tDeny: \"reject\",\n\t};\n\n\treturn {\n\t\trequestID: request.id,\n\t\treply: choice ? replyMap[choice] : \"reject\",\n\t};\n}\n\nfunction formatRequestForDisplay(request: Request): string {\n\tconst parts: string[] = [];\n\tconst meta = request.metadata || {};\n\n\tswitch (request.permission) {\n\t\tcase \"edit\":\n\t\t\tparts.push(`File: ${meta.filepath || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"read\":\n\t\t\tparts.push(`Path: ${meta.filePath || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"glob\":\n\t\tcase \"grep\":\n\t\t\tparts.push(`Pattern: ${meta.pattern || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"list\":\n\t\t\tparts.push(`Path: ${meta.path || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"bash\":\n\t\t\tif (meta.description) parts.push(`Description: ${meta.description}`);\n\t\t\tparts.push(`Command: $ ${meta.command || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"websearch\":\n\t\tcase \"codesearch\":\n\t\t\tparts.push(`Query: ${meta.query || \"Unknown\"}`);\n\t\t\tbreak;\n\t\tcase \"external_directory\": {\n\t\t\tconst parent = typeof meta.parentDir === \"string\" ? meta.parentDir : undefined;\n\t\t\tconst filepath = typeof meta.filepath === \"string\" ? meta.filepath : undefined;\n\t\t\tconst pattern = request.patterns?.[0];\n\t\t\tconst derived =\n\t\t\t\ttypeof pattern === \"string\" ? (pattern.includes(\"*\") ? pattern.split(\"*\")[0] : pattern) : undefined;\n\t\t\tconst dir = parent ?? filepath ?? derived ?? \"Unknown\";\n\t\t\tparts.push(`Directory: ${dir}`);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tparts.push(`Tool: ${request.permission}`);\n\t\t\tbreak;\n\t}\n\n\tif (request.patterns && request.patterns.length > 0) {\n\t\tparts.push(`\\nPatterns:\\n${request.patterns.map((p) => ` - ${p}`).join(\"\\n\")}`);\n\t}\n\n\treturn parts.join(\"\\n\");\n}\n"]}
@@ -3,7 +3,7 @@ import type { CustomMessage } from "../../messages.js";
3
3
  import type { ExtensionAPI } from "../types.js";
4
4
  export declare const SENPI_SYSTEM_PREFIX = "[system:senpi]";
5
5
  export declare const SENPI_CONVERSATION_EVENT = "senpi:conversation";
6
- export type BuiltinSystemMessageRoute = "background-task.notification" | "todotools.continuation";
6
+ export type BuiltinSystemMessageRoute = "todotools.continuation";
7
7
  export type SenpiConversationAction = "injected" | "failed";
8
8
  export interface SenpiConversationEvent {
9
9
  version: 1;
@@ -1 +1 @@
1
- {"version":3,"file":"system-messages.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/system-messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AACpD,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAE7D,MAAM,MAAM,yBAAyB,GAAG,8BAA8B,GAAG,wBAAwB,CAAC;AAClG,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,uBAAuB,CAAC;IAChC,KAAK,EAAE,yBAAyB,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE;QACb,MAAM,EAAE,OAAO,mBAAmB,CAAC;QACnC,IAAI,EAAE,gBAAgB,GAAG,cAAc,CAAC;QACxC,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;QACjC,WAAW,CAAC,EAAE,OAAO,CAAC;KACtB,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,yBAAyB,GAAG;IAChC,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,2BAA2B,GAAG;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAqFF,wBAAgB,sBAAsB,CACrC,EAAE,EAAE,YAAY,EAChB,KAAK,EAAE,yBAAyB,EAChC,OAAO,EAAE,MAAM,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,EAChD,OAAO,CAAC,EAAE,yBAAyB,GACjC,IAAI,CAqBN;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAChD,EAAE,EAAE,YAAY,EAChB,KAAK,EAAE,yBAAyB,EAChC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,CAAC,EACxF,OAAO,CAAC,EAAE,2BAA2B,GACnC,IAAI,CAgCN;AAED,wBAAgB,+BAA+B,CAC9C,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE;IACL,KAAK,EAAE,yBAAyB,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,gBAAgB,GAAG,cAAc,CAAC;IACxC,OAAO,EAAE,MAAM,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IACjC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACrB,GACC,IAAI,CAiBN","sourcesContent":["import type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport type { CustomMessage } from \"../../messages.js\";\nimport type { ExtensionAPI } from \"../types.js\";\n\nexport const SENPI_SYSTEM_PREFIX = \"[system:senpi]\";\nexport const SENPI_CONVERSATION_EVENT = \"senpi:conversation\";\n\nexport type BuiltinSystemMessageRoute = \"background-task.notification\" | \"todotools.continuation\";\nexport type SenpiConversationAction = \"injected\" | \"failed\";\n\nexport interface SenpiConversationEvent {\n\tversion: 1;\n\tsource: \"builtin\";\n\taction: SenpiConversationAction;\n\troute: BuiltinSystemMessageRoute;\n\tsessionId?: string;\n\ttimestamp: number;\n\tconversation: {\n\t\tprefix: typeof SENPI_SYSTEM_PREFIX;\n\t\tkind: \"custom_message\" | \"user_message\";\n\t\tcustomType?: string;\n\t\tdeliverAs?: \"steer\" | \"followUp\";\n\t\ttriggerTurn?: boolean;\n\t};\n\ttext: string;\n\terrorMessage?: string;\n}\n\ntype BuiltinUserMessageOptions = {\n\tdeliverAs?: \"steer\" | \"followUp\";\n\tsessionId?: string;\n};\n\ntype BuiltinCustomMessageOptions = {\n\ttriggerTurn?: boolean;\n\tdeliverAs?: \"steer\" | \"followUp\" | \"nextTurn\";\n\tsessionId?: string;\n};\n\nfunction prefixText(text: string): string {\n\treturn text.startsWith(SENPI_SYSTEM_PREFIX) ? text : `${SENPI_SYSTEM_PREFIX}\\n${text}`;\n}\n\nfunction prefixContent(content: string | (TextContent | ImageContent)[]): string | (TextContent | ImageContent)[] {\n\tif (typeof content === \"string\") {\n\t\treturn prefixText(content);\n\t}\n\n\tconst firstTextIndex = content.findIndex((part) => part.type === \"text\");\n\tif (firstTextIndex === -1) {\n\t\treturn [{ type: \"text\", text: SENPI_SYSTEM_PREFIX }, ...content];\n\t}\n\n\treturn content.map((part, index) => {\n\t\tif (part.type !== \"text\" || index !== firstTextIndex) {\n\t\t\treturn part;\n\t\t}\n\n\t\treturn {\n\t\t\t...part,\n\t\t\ttext: prefixText(part.text),\n\t\t};\n\t});\n}\n\nfunction extractText(content: string | (TextContent | ImageContent)[]): string {\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\n\treturn content\n\t\t.filter((part): part is TextContent => part.type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction emitSenpiConversationEvent(pi: ExtensionAPI, event: SenpiConversationEvent): void {\n\tpi.events.emit(SENPI_CONVERSATION_EVENT, event);\n}\n\nfunction createBaseEvent(args: {\n\taction: SenpiConversationAction;\n\troute: BuiltinSystemMessageRoute;\n\tsessionId?: string;\n\tkind: \"custom_message\" | \"user_message\";\n\tcustomType?: string;\n\tdeliverAs?: \"steer\" | \"followUp\";\n\ttriggerTurn?: boolean;\n\ttext: string;\n\terrorMessage?: string;\n}): SenpiConversationEvent {\n\treturn {\n\t\tversion: 1,\n\t\tsource: \"builtin\",\n\t\taction: args.action,\n\t\troute: args.route,\n\t\tsessionId: args.sessionId,\n\t\ttimestamp: Date.now(),\n\t\tconversation: {\n\t\t\tprefix: SENPI_SYSTEM_PREFIX,\n\t\t\tkind: args.kind,\n\t\t\tcustomType: args.customType,\n\t\t\tdeliverAs: args.deliverAs,\n\t\t\ttriggerTurn: args.triggerTurn,\n\t\t},\n\t\ttext: args.text,\n\t\terrorMessage: args.errorMessage,\n\t};\n}\n\nfunction hasUserMessageOptions(\n\toptions: BuiltinUserMessageOptions | undefined,\n): options is BuiltinUserMessageOptions & { deliverAs: \"steer\" | \"followUp\" } {\n\treturn options?.deliverAs !== undefined;\n}\n\nfunction hasCustomMessageOptions(\n\toptions: BuiltinCustomMessageOptions | undefined,\n): options is BuiltinCustomMessageOptions & { triggerTurn?: boolean; deliverAs?: \"steer\" | \"followUp\" | \"nextTurn\" } {\n\treturn options?.triggerTurn === true || options?.deliverAs !== undefined;\n}\n\nexport function sendBuiltinUserMessage(\n\tpi: ExtensionAPI,\n\troute: BuiltinSystemMessageRoute,\n\tcontent: string | (TextContent | ImageContent)[],\n\toptions?: BuiltinUserMessageOptions,\n): void {\n\tconst prefixedContent = prefixContent(content);\n\n\temitSenpiConversationEvent(\n\t\tpi,\n\t\tcreateBaseEvent({\n\t\t\taction: \"injected\",\n\t\t\troute,\n\t\t\tsessionId: options?.sessionId,\n\t\t\tkind: \"user_message\",\n\t\t\ttext: extractText(prefixedContent),\n\t\t\tdeliverAs: options?.deliverAs,\n\t\t}),\n\t);\n\n\tif (hasUserMessageOptions(options)) {\n\t\tpi.sendUserMessage(prefixedContent, { deliverAs: options.deliverAs });\n\t\treturn;\n\t}\n\n\tpi.sendUserMessage(prefixedContent);\n}\n\nexport function sendBuiltinCustomMessage<TDetails>(\n\tpi: ExtensionAPI,\n\troute: BuiltinSystemMessageRoute,\n\tmessage: Pick<CustomMessage<TDetails>, \"content\" | \"customType\" | \"details\" | \"display\">,\n\toptions?: BuiltinCustomMessageOptions,\n): void {\n\tconst prefixedContent = prefixContent(message.content);\n\tconst deliverAs = options?.deliverAs === \"nextTurn\" ? undefined : options?.deliverAs;\n\n\temitSenpiConversationEvent(\n\t\tpi,\n\t\tcreateBaseEvent({\n\t\t\taction: \"injected\",\n\t\t\troute,\n\t\t\tsessionId: options?.sessionId,\n\t\t\tkind: \"custom_message\",\n\t\t\tcustomType: message.customType,\n\t\t\ttext: extractText(prefixedContent),\n\t\t\tdeliverAs,\n\t\t\ttriggerTurn: options?.triggerTurn,\n\t\t}),\n\t);\n\n\tconst prefixedMessage = {\n\t\t...message,\n\t\tcontent: prefixedContent,\n\t};\n\n\tif (hasCustomMessageOptions(options)) {\n\t\tpi.sendMessage(prefixedMessage, {\n\t\t\ttriggerTurn: options.triggerTurn,\n\t\t\tdeliverAs: options.deliverAs,\n\t\t});\n\t\treturn;\n\t}\n\n\tpi.sendMessage(prefixedMessage);\n}\n\nexport function emitBuiltinSystemMessageFailure(\n\tpi: ExtensionAPI,\n\targs: {\n\t\troute: BuiltinSystemMessageRoute;\n\t\tsessionId?: string;\n\t\tkind: \"custom_message\" | \"user_message\";\n\t\tcontent: string | (TextContent | ImageContent)[];\n\t\tcustomType?: string;\n\t\tdeliverAs?: \"steer\" | \"followUp\";\n\t\ttriggerTurn?: boolean;\n\t\terrorMessage: string;\n\t},\n): void {\n\tconst prefixedContent = prefixContent(args.content);\n\n\temitSenpiConversationEvent(\n\t\tpi,\n\t\tcreateBaseEvent({\n\t\t\taction: \"failed\",\n\t\t\troute: args.route,\n\t\t\tsessionId: args.sessionId,\n\t\t\tkind: args.kind,\n\t\t\tcustomType: args.customType,\n\t\t\ttext: extractText(prefixedContent),\n\t\t\tdeliverAs: args.deliverAs,\n\t\t\ttriggerTurn: args.triggerTurn,\n\t\t\terrorMessage: args.errorMessage,\n\t\t}),\n\t);\n}\n"]}
1
+ {"version":3,"file":"system-messages.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/system-messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AACpD,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAE7D,MAAM,MAAM,yBAAyB,GAAG,wBAAwB,CAAC;AACjE,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,uBAAuB,CAAC;IAChC,KAAK,EAAE,yBAAyB,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE;QACb,MAAM,EAAE,OAAO,mBAAmB,CAAC;QACnC,IAAI,EAAE,gBAAgB,GAAG,cAAc,CAAC;QACxC,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;QACjC,WAAW,CAAC,EAAE,OAAO,CAAC;KACtB,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,yBAAyB,GAAG;IAChC,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,2BAA2B,GAAG;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAqFF,wBAAgB,sBAAsB,CACrC,EAAE,EAAE,YAAY,EAChB,KAAK,EAAE,yBAAyB,EAChC,OAAO,EAAE,MAAM,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,EAChD,OAAO,CAAC,EAAE,yBAAyB,GACjC,IAAI,CAqBN;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAChD,EAAE,EAAE,YAAY,EAChB,KAAK,EAAE,yBAAyB,EAChC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,CAAC,EACxF,OAAO,CAAC,EAAE,2BAA2B,GACnC,IAAI,CAgCN;AAED,wBAAgB,+BAA+B,CAC9C,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE;IACL,KAAK,EAAE,yBAAyB,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,gBAAgB,GAAG,cAAc,CAAC;IACxC,OAAO,EAAE,MAAM,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IACjC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACrB,GACC,IAAI,CAiBN","sourcesContent":["import type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport type { CustomMessage } from \"../../messages.js\";\nimport type { ExtensionAPI } from \"../types.js\";\n\nexport const SENPI_SYSTEM_PREFIX = \"[system:senpi]\";\nexport const SENPI_CONVERSATION_EVENT = \"senpi:conversation\";\n\nexport type BuiltinSystemMessageRoute = \"todotools.continuation\";\nexport type SenpiConversationAction = \"injected\" | \"failed\";\n\nexport interface SenpiConversationEvent {\n\tversion: 1;\n\tsource: \"builtin\";\n\taction: SenpiConversationAction;\n\troute: BuiltinSystemMessageRoute;\n\tsessionId?: string;\n\ttimestamp: number;\n\tconversation: {\n\t\tprefix: typeof SENPI_SYSTEM_PREFIX;\n\t\tkind: \"custom_message\" | \"user_message\";\n\t\tcustomType?: string;\n\t\tdeliverAs?: \"steer\" | \"followUp\";\n\t\ttriggerTurn?: boolean;\n\t};\n\ttext: string;\n\terrorMessage?: string;\n}\n\ntype BuiltinUserMessageOptions = {\n\tdeliverAs?: \"steer\" | \"followUp\";\n\tsessionId?: string;\n};\n\ntype BuiltinCustomMessageOptions = {\n\ttriggerTurn?: boolean;\n\tdeliverAs?: \"steer\" | \"followUp\" | \"nextTurn\";\n\tsessionId?: string;\n};\n\nfunction prefixText(text: string): string {\n\treturn text.startsWith(SENPI_SYSTEM_PREFIX) ? text : `${SENPI_SYSTEM_PREFIX}\\n${text}`;\n}\n\nfunction prefixContent(content: string | (TextContent | ImageContent)[]): string | (TextContent | ImageContent)[] {\n\tif (typeof content === \"string\") {\n\t\treturn prefixText(content);\n\t}\n\n\tconst firstTextIndex = content.findIndex((part) => part.type === \"text\");\n\tif (firstTextIndex === -1) {\n\t\treturn [{ type: \"text\", text: SENPI_SYSTEM_PREFIX }, ...content];\n\t}\n\n\treturn content.map((part, index) => {\n\t\tif (part.type !== \"text\" || index !== firstTextIndex) {\n\t\t\treturn part;\n\t\t}\n\n\t\treturn {\n\t\t\t...part,\n\t\t\ttext: prefixText(part.text),\n\t\t};\n\t});\n}\n\nfunction extractText(content: string | (TextContent | ImageContent)[]): string {\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\n\treturn content\n\t\t.filter((part): part is TextContent => part.type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction emitSenpiConversationEvent(pi: ExtensionAPI, event: SenpiConversationEvent): void {\n\tpi.events.emit(SENPI_CONVERSATION_EVENT, event);\n}\n\nfunction createBaseEvent(args: {\n\taction: SenpiConversationAction;\n\troute: BuiltinSystemMessageRoute;\n\tsessionId?: string;\n\tkind: \"custom_message\" | \"user_message\";\n\tcustomType?: string;\n\tdeliverAs?: \"steer\" | \"followUp\";\n\ttriggerTurn?: boolean;\n\ttext: string;\n\terrorMessage?: string;\n}): SenpiConversationEvent {\n\treturn {\n\t\tversion: 1,\n\t\tsource: \"builtin\",\n\t\taction: args.action,\n\t\troute: args.route,\n\t\tsessionId: args.sessionId,\n\t\ttimestamp: Date.now(),\n\t\tconversation: {\n\t\t\tprefix: SENPI_SYSTEM_PREFIX,\n\t\t\tkind: args.kind,\n\t\t\tcustomType: args.customType,\n\t\t\tdeliverAs: args.deliverAs,\n\t\t\ttriggerTurn: args.triggerTurn,\n\t\t},\n\t\ttext: args.text,\n\t\terrorMessage: args.errorMessage,\n\t};\n}\n\nfunction hasUserMessageOptions(\n\toptions: BuiltinUserMessageOptions | undefined,\n): options is BuiltinUserMessageOptions & { deliverAs: \"steer\" | \"followUp\" } {\n\treturn options?.deliverAs !== undefined;\n}\n\nfunction hasCustomMessageOptions(\n\toptions: BuiltinCustomMessageOptions | undefined,\n): options is BuiltinCustomMessageOptions & { triggerTurn?: boolean; deliverAs?: \"steer\" | \"followUp\" | \"nextTurn\" } {\n\treturn options?.triggerTurn === true || options?.deliverAs !== undefined;\n}\n\nexport function sendBuiltinUserMessage(\n\tpi: ExtensionAPI,\n\troute: BuiltinSystemMessageRoute,\n\tcontent: string | (TextContent | ImageContent)[],\n\toptions?: BuiltinUserMessageOptions,\n): void {\n\tconst prefixedContent = prefixContent(content);\n\n\temitSenpiConversationEvent(\n\t\tpi,\n\t\tcreateBaseEvent({\n\t\t\taction: \"injected\",\n\t\t\troute,\n\t\t\tsessionId: options?.sessionId,\n\t\t\tkind: \"user_message\",\n\t\t\ttext: extractText(prefixedContent),\n\t\t\tdeliverAs: options?.deliverAs,\n\t\t}),\n\t);\n\n\tif (hasUserMessageOptions(options)) {\n\t\tpi.sendUserMessage(prefixedContent, { deliverAs: options.deliverAs });\n\t\treturn;\n\t}\n\n\tpi.sendUserMessage(prefixedContent);\n}\n\nexport function sendBuiltinCustomMessage<TDetails>(\n\tpi: ExtensionAPI,\n\troute: BuiltinSystemMessageRoute,\n\tmessage: Pick<CustomMessage<TDetails>, \"content\" | \"customType\" | \"details\" | \"display\">,\n\toptions?: BuiltinCustomMessageOptions,\n): void {\n\tconst prefixedContent = prefixContent(message.content);\n\tconst deliverAs = options?.deliverAs === \"nextTurn\" ? undefined : options?.deliverAs;\n\n\temitSenpiConversationEvent(\n\t\tpi,\n\t\tcreateBaseEvent({\n\t\t\taction: \"injected\",\n\t\t\troute,\n\t\t\tsessionId: options?.sessionId,\n\t\t\tkind: \"custom_message\",\n\t\t\tcustomType: message.customType,\n\t\t\ttext: extractText(prefixedContent),\n\t\t\tdeliverAs,\n\t\t\ttriggerTurn: options?.triggerTurn,\n\t\t}),\n\t);\n\n\tconst prefixedMessage = {\n\t\t...message,\n\t\tcontent: prefixedContent,\n\t};\n\n\tif (hasCustomMessageOptions(options)) {\n\t\tpi.sendMessage(prefixedMessage, {\n\t\t\ttriggerTurn: options.triggerTurn,\n\t\t\tdeliverAs: options.deliverAs,\n\t\t});\n\t\treturn;\n\t}\n\n\tpi.sendMessage(prefixedMessage);\n}\n\nexport function emitBuiltinSystemMessageFailure(\n\tpi: ExtensionAPI,\n\targs: {\n\t\troute: BuiltinSystemMessageRoute;\n\t\tsessionId?: string;\n\t\tkind: \"custom_message\" | \"user_message\";\n\t\tcontent: string | (TextContent | ImageContent)[];\n\t\tcustomType?: string;\n\t\tdeliverAs?: \"steer\" | \"followUp\";\n\t\ttriggerTurn?: boolean;\n\t\terrorMessage: string;\n\t},\n): void {\n\tconst prefixedContent = prefixContent(args.content);\n\n\temitSenpiConversationEvent(\n\t\tpi,\n\t\tcreateBaseEvent({\n\t\t\taction: \"failed\",\n\t\t\troute: args.route,\n\t\t\tsessionId: args.sessionId,\n\t\t\tkind: args.kind,\n\t\t\tcustomType: args.customType,\n\t\t\ttext: extractText(prefixedContent),\n\t\t\tdeliverAs: args.deliverAs,\n\t\t\ttriggerTurn: args.triggerTurn,\n\t\t\terrorMessage: args.errorMessage,\n\t\t}),\n\t);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"system-messages.js","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/system-messages.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport type { CustomMessage } from \"../../messages.js\";\nimport type { ExtensionAPI } from \"../types.js\";\n\nexport const SENPI_SYSTEM_PREFIX = \"[system:senpi]\";\nexport const SENPI_CONVERSATION_EVENT = \"senpi:conversation\";\n\nexport type BuiltinSystemMessageRoute = \"background-task.notification\" | \"todotools.continuation\";\nexport type SenpiConversationAction = \"injected\" | \"failed\";\n\nexport interface SenpiConversationEvent {\n\tversion: 1;\n\tsource: \"builtin\";\n\taction: SenpiConversationAction;\n\troute: BuiltinSystemMessageRoute;\n\tsessionId?: string;\n\ttimestamp: number;\n\tconversation: {\n\t\tprefix: typeof SENPI_SYSTEM_PREFIX;\n\t\tkind: \"custom_message\" | \"user_message\";\n\t\tcustomType?: string;\n\t\tdeliverAs?: \"steer\" | \"followUp\";\n\t\ttriggerTurn?: boolean;\n\t};\n\ttext: string;\n\terrorMessage?: string;\n}\n\ntype BuiltinUserMessageOptions = {\n\tdeliverAs?: \"steer\" | \"followUp\";\n\tsessionId?: string;\n};\n\ntype BuiltinCustomMessageOptions = {\n\ttriggerTurn?: boolean;\n\tdeliverAs?: \"steer\" | \"followUp\" | \"nextTurn\";\n\tsessionId?: string;\n};\n\nfunction prefixText(text: string): string {\n\treturn text.startsWith(SENPI_SYSTEM_PREFIX) ? text : `${SENPI_SYSTEM_PREFIX}\\n${text}`;\n}\n\nfunction prefixContent(content: string | (TextContent | ImageContent)[]): string | (TextContent | ImageContent)[] {\n\tif (typeof content === \"string\") {\n\t\treturn prefixText(content);\n\t}\n\n\tconst firstTextIndex = content.findIndex((part) => part.type === \"text\");\n\tif (firstTextIndex === -1) {\n\t\treturn [{ type: \"text\", text: SENPI_SYSTEM_PREFIX }, ...content];\n\t}\n\n\treturn content.map((part, index) => {\n\t\tif (part.type !== \"text\" || index !== firstTextIndex) {\n\t\t\treturn part;\n\t\t}\n\n\t\treturn {\n\t\t\t...part,\n\t\t\ttext: prefixText(part.text),\n\t\t};\n\t});\n}\n\nfunction extractText(content: string | (TextContent | ImageContent)[]): string {\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\n\treturn content\n\t\t.filter((part): part is TextContent => part.type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction emitSenpiConversationEvent(pi: ExtensionAPI, event: SenpiConversationEvent): void {\n\tpi.events.emit(SENPI_CONVERSATION_EVENT, event);\n}\n\nfunction createBaseEvent(args: {\n\taction: SenpiConversationAction;\n\troute: BuiltinSystemMessageRoute;\n\tsessionId?: string;\n\tkind: \"custom_message\" | \"user_message\";\n\tcustomType?: string;\n\tdeliverAs?: \"steer\" | \"followUp\";\n\ttriggerTurn?: boolean;\n\ttext: string;\n\terrorMessage?: string;\n}): SenpiConversationEvent {\n\treturn {\n\t\tversion: 1,\n\t\tsource: \"builtin\",\n\t\taction: args.action,\n\t\troute: args.route,\n\t\tsessionId: args.sessionId,\n\t\ttimestamp: Date.now(),\n\t\tconversation: {\n\t\t\tprefix: SENPI_SYSTEM_PREFIX,\n\t\t\tkind: args.kind,\n\t\t\tcustomType: args.customType,\n\t\t\tdeliverAs: args.deliverAs,\n\t\t\ttriggerTurn: args.triggerTurn,\n\t\t},\n\t\ttext: args.text,\n\t\terrorMessage: args.errorMessage,\n\t};\n}\n\nfunction hasUserMessageOptions(\n\toptions: BuiltinUserMessageOptions | undefined,\n): options is BuiltinUserMessageOptions & { deliverAs: \"steer\" | \"followUp\" } {\n\treturn options?.deliverAs !== undefined;\n}\n\nfunction hasCustomMessageOptions(\n\toptions: BuiltinCustomMessageOptions | undefined,\n): options is BuiltinCustomMessageOptions & { triggerTurn?: boolean; deliverAs?: \"steer\" | \"followUp\" | \"nextTurn\" } {\n\treturn options?.triggerTurn === true || options?.deliverAs !== undefined;\n}\n\nexport function sendBuiltinUserMessage(\n\tpi: ExtensionAPI,\n\troute: BuiltinSystemMessageRoute,\n\tcontent: string | (TextContent | ImageContent)[],\n\toptions?: BuiltinUserMessageOptions,\n): void {\n\tconst prefixedContent = prefixContent(content);\n\n\temitSenpiConversationEvent(\n\t\tpi,\n\t\tcreateBaseEvent({\n\t\t\taction: \"injected\",\n\t\t\troute,\n\t\t\tsessionId: options?.sessionId,\n\t\t\tkind: \"user_message\",\n\t\t\ttext: extractText(prefixedContent),\n\t\t\tdeliverAs: options?.deliverAs,\n\t\t}),\n\t);\n\n\tif (hasUserMessageOptions(options)) {\n\t\tpi.sendUserMessage(prefixedContent, { deliverAs: options.deliverAs });\n\t\treturn;\n\t}\n\n\tpi.sendUserMessage(prefixedContent);\n}\n\nexport function sendBuiltinCustomMessage<TDetails>(\n\tpi: ExtensionAPI,\n\troute: BuiltinSystemMessageRoute,\n\tmessage: Pick<CustomMessage<TDetails>, \"content\" | \"customType\" | \"details\" | \"display\">,\n\toptions?: BuiltinCustomMessageOptions,\n): void {\n\tconst prefixedContent = prefixContent(message.content);\n\tconst deliverAs = options?.deliverAs === \"nextTurn\" ? undefined : options?.deliverAs;\n\n\temitSenpiConversationEvent(\n\t\tpi,\n\t\tcreateBaseEvent({\n\t\t\taction: \"injected\",\n\t\t\troute,\n\t\t\tsessionId: options?.sessionId,\n\t\t\tkind: \"custom_message\",\n\t\t\tcustomType: message.customType,\n\t\t\ttext: extractText(prefixedContent),\n\t\t\tdeliverAs,\n\t\t\ttriggerTurn: options?.triggerTurn,\n\t\t}),\n\t);\n\n\tconst prefixedMessage = {\n\t\t...message,\n\t\tcontent: prefixedContent,\n\t};\n\n\tif (hasCustomMessageOptions(options)) {\n\t\tpi.sendMessage(prefixedMessage, {\n\t\t\ttriggerTurn: options.triggerTurn,\n\t\t\tdeliverAs: options.deliverAs,\n\t\t});\n\t\treturn;\n\t}\n\n\tpi.sendMessage(prefixedMessage);\n}\n\nexport function emitBuiltinSystemMessageFailure(\n\tpi: ExtensionAPI,\n\targs: {\n\t\troute: BuiltinSystemMessageRoute;\n\t\tsessionId?: string;\n\t\tkind: \"custom_message\" | \"user_message\";\n\t\tcontent: string | (TextContent | ImageContent)[];\n\t\tcustomType?: string;\n\t\tdeliverAs?: \"steer\" | \"followUp\";\n\t\ttriggerTurn?: boolean;\n\t\terrorMessage: string;\n\t},\n): void {\n\tconst prefixedContent = prefixContent(args.content);\n\n\temitSenpiConversationEvent(\n\t\tpi,\n\t\tcreateBaseEvent({\n\t\t\taction: \"failed\",\n\t\t\troute: args.route,\n\t\t\tsessionId: args.sessionId,\n\t\t\tkind: args.kind,\n\t\t\tcustomType: args.customType,\n\t\t\ttext: extractText(prefixedContent),\n\t\t\tdeliverAs: args.deliverAs,\n\t\t\ttriggerTurn: args.triggerTurn,\n\t\t\terrorMessage: args.errorMessage,\n\t\t}),\n\t);\n}\n"]}
1
+ {"version":3,"file":"system-messages.js","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/system-messages.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport type { CustomMessage } from \"../../messages.js\";\nimport type { ExtensionAPI } from \"../types.js\";\n\nexport const SENPI_SYSTEM_PREFIX = \"[system:senpi]\";\nexport const SENPI_CONVERSATION_EVENT = \"senpi:conversation\";\n\nexport type BuiltinSystemMessageRoute = \"todotools.continuation\";\nexport type SenpiConversationAction = \"injected\" | \"failed\";\n\nexport interface SenpiConversationEvent {\n\tversion: 1;\n\tsource: \"builtin\";\n\taction: SenpiConversationAction;\n\troute: BuiltinSystemMessageRoute;\n\tsessionId?: string;\n\ttimestamp: number;\n\tconversation: {\n\t\tprefix: typeof SENPI_SYSTEM_PREFIX;\n\t\tkind: \"custom_message\" | \"user_message\";\n\t\tcustomType?: string;\n\t\tdeliverAs?: \"steer\" | \"followUp\";\n\t\ttriggerTurn?: boolean;\n\t};\n\ttext: string;\n\terrorMessage?: string;\n}\n\ntype BuiltinUserMessageOptions = {\n\tdeliverAs?: \"steer\" | \"followUp\";\n\tsessionId?: string;\n};\n\ntype BuiltinCustomMessageOptions = {\n\ttriggerTurn?: boolean;\n\tdeliverAs?: \"steer\" | \"followUp\" | \"nextTurn\";\n\tsessionId?: string;\n};\n\nfunction prefixText(text: string): string {\n\treturn text.startsWith(SENPI_SYSTEM_PREFIX) ? text : `${SENPI_SYSTEM_PREFIX}\\n${text}`;\n}\n\nfunction prefixContent(content: string | (TextContent | ImageContent)[]): string | (TextContent | ImageContent)[] {\n\tif (typeof content === \"string\") {\n\t\treturn prefixText(content);\n\t}\n\n\tconst firstTextIndex = content.findIndex((part) => part.type === \"text\");\n\tif (firstTextIndex === -1) {\n\t\treturn [{ type: \"text\", text: SENPI_SYSTEM_PREFIX }, ...content];\n\t}\n\n\treturn content.map((part, index) => {\n\t\tif (part.type !== \"text\" || index !== firstTextIndex) {\n\t\t\treturn part;\n\t\t}\n\n\t\treturn {\n\t\t\t...part,\n\t\t\ttext: prefixText(part.text),\n\t\t};\n\t});\n}\n\nfunction extractText(content: string | (TextContent | ImageContent)[]): string {\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\n\treturn content\n\t\t.filter((part): part is TextContent => part.type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction emitSenpiConversationEvent(pi: ExtensionAPI, event: SenpiConversationEvent): void {\n\tpi.events.emit(SENPI_CONVERSATION_EVENT, event);\n}\n\nfunction createBaseEvent(args: {\n\taction: SenpiConversationAction;\n\troute: BuiltinSystemMessageRoute;\n\tsessionId?: string;\n\tkind: \"custom_message\" | \"user_message\";\n\tcustomType?: string;\n\tdeliverAs?: \"steer\" | \"followUp\";\n\ttriggerTurn?: boolean;\n\ttext: string;\n\terrorMessage?: string;\n}): SenpiConversationEvent {\n\treturn {\n\t\tversion: 1,\n\t\tsource: \"builtin\",\n\t\taction: args.action,\n\t\troute: args.route,\n\t\tsessionId: args.sessionId,\n\t\ttimestamp: Date.now(),\n\t\tconversation: {\n\t\t\tprefix: SENPI_SYSTEM_PREFIX,\n\t\t\tkind: args.kind,\n\t\t\tcustomType: args.customType,\n\t\t\tdeliverAs: args.deliverAs,\n\t\t\ttriggerTurn: args.triggerTurn,\n\t\t},\n\t\ttext: args.text,\n\t\terrorMessage: args.errorMessage,\n\t};\n}\n\nfunction hasUserMessageOptions(\n\toptions: BuiltinUserMessageOptions | undefined,\n): options is BuiltinUserMessageOptions & { deliverAs: \"steer\" | \"followUp\" } {\n\treturn options?.deliverAs !== undefined;\n}\n\nfunction hasCustomMessageOptions(\n\toptions: BuiltinCustomMessageOptions | undefined,\n): options is BuiltinCustomMessageOptions & { triggerTurn?: boolean; deliverAs?: \"steer\" | \"followUp\" | \"nextTurn\" } {\n\treturn options?.triggerTurn === true || options?.deliverAs !== undefined;\n}\n\nexport function sendBuiltinUserMessage(\n\tpi: ExtensionAPI,\n\troute: BuiltinSystemMessageRoute,\n\tcontent: string | (TextContent | ImageContent)[],\n\toptions?: BuiltinUserMessageOptions,\n): void {\n\tconst prefixedContent = prefixContent(content);\n\n\temitSenpiConversationEvent(\n\t\tpi,\n\t\tcreateBaseEvent({\n\t\t\taction: \"injected\",\n\t\t\troute,\n\t\t\tsessionId: options?.sessionId,\n\t\t\tkind: \"user_message\",\n\t\t\ttext: extractText(prefixedContent),\n\t\t\tdeliverAs: options?.deliverAs,\n\t\t}),\n\t);\n\n\tif (hasUserMessageOptions(options)) {\n\t\tpi.sendUserMessage(prefixedContent, { deliverAs: options.deliverAs });\n\t\treturn;\n\t}\n\n\tpi.sendUserMessage(prefixedContent);\n}\n\nexport function sendBuiltinCustomMessage<TDetails>(\n\tpi: ExtensionAPI,\n\troute: BuiltinSystemMessageRoute,\n\tmessage: Pick<CustomMessage<TDetails>, \"content\" | \"customType\" | \"details\" | \"display\">,\n\toptions?: BuiltinCustomMessageOptions,\n): void {\n\tconst prefixedContent = prefixContent(message.content);\n\tconst deliverAs = options?.deliverAs === \"nextTurn\" ? undefined : options?.deliverAs;\n\n\temitSenpiConversationEvent(\n\t\tpi,\n\t\tcreateBaseEvent({\n\t\t\taction: \"injected\",\n\t\t\troute,\n\t\t\tsessionId: options?.sessionId,\n\t\t\tkind: \"custom_message\",\n\t\t\tcustomType: message.customType,\n\t\t\ttext: extractText(prefixedContent),\n\t\t\tdeliverAs,\n\t\t\ttriggerTurn: options?.triggerTurn,\n\t\t}),\n\t);\n\n\tconst prefixedMessage = {\n\t\t...message,\n\t\tcontent: prefixedContent,\n\t};\n\n\tif (hasCustomMessageOptions(options)) {\n\t\tpi.sendMessage(prefixedMessage, {\n\t\t\ttriggerTurn: options.triggerTurn,\n\t\t\tdeliverAs: options.deliverAs,\n\t\t});\n\t\treturn;\n\t}\n\n\tpi.sendMessage(prefixedMessage);\n}\n\nexport function emitBuiltinSystemMessageFailure(\n\tpi: ExtensionAPI,\n\targs: {\n\t\troute: BuiltinSystemMessageRoute;\n\t\tsessionId?: string;\n\t\tkind: \"custom_message\" | \"user_message\";\n\t\tcontent: string | (TextContent | ImageContent)[];\n\t\tcustomType?: string;\n\t\tdeliverAs?: \"steer\" | \"followUp\";\n\t\ttriggerTurn?: boolean;\n\t\terrorMessage: string;\n\t},\n): void {\n\tconst prefixedContent = prefixContent(args.content);\n\n\temitSenpiConversationEvent(\n\t\tpi,\n\t\tcreateBaseEvent({\n\t\t\taction: \"failed\",\n\t\t\troute: args.route,\n\t\t\tsessionId: args.sessionId,\n\t\t\tkind: args.kind,\n\t\t\tcustomType: args.customType,\n\t\t\ttext: extractText(prefixedContent),\n\t\t\tdeliverAs: args.deliverAs,\n\t\t\ttriggerTurn: args.triggerTurn,\n\t\t\terrorMessage: args.errorMessage,\n\t\t}),\n\t);\n}\n"]}
@@ -1,4 +1,4 @@
1
1
  import type { ExtensionAPI } from "../../types.js";
2
- /** Guards provider requests by removing orphan tool_result blocks. */
2
+ /** Guards provider requests by keeping tool-call/result pairs balanced. */
3
3
  export default function toolPairGuardExtension(pi: ExtensionAPI): void;
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/tool-pair-guard/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,sEAAsE;AACtE,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAMrE","sourcesContent":["import type { ExtensionAPI } from \"../../types.js\";\nimport { sanitizeAnthropicPayload } from \"./sanitize-anthropic-payload.js\";\n\n/** Guards provider requests by removing orphan tool_result blocks. */\nexport default function toolPairGuardExtension(pi: ExtensionAPI): void {\n\tpi.on(\"before_provider_request\", (event) => {\n\t\tconst sanitized = sanitizeAnthropicPayload(event.payload);\n\t\tif (sanitized === event.payload) return undefined;\n\t\treturn sanitized;\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/tool-pair-guard/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKnD,2EAA2E;AAC3E,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAQrE","sourcesContent":["import type { ExtensionAPI } from \"../../types.js\";\nimport { sanitizeAnthropicPayload } from \"./sanitize-anthropic-payload.js\";\nimport { sanitizeOpenAIChatCompletionsPayload } from \"./sanitize-openai-chat-completions-payload.js\";\nimport { sanitizeOpenAIResponsesPayload } from \"./sanitize-openai-responses-payload.js\";\n\n/** Guards provider requests by keeping tool-call/result pairs balanced. */\nexport default function toolPairGuardExtension(pi: ExtensionAPI): void {\n\tpi.on(\"before_provider_request\", (event) => {\n\t\tconst sanitizedAnthropicPayload = sanitizeAnthropicPayload(event.payload);\n\t\tconst sanitizedResponsesPayload = sanitizeOpenAIResponsesPayload(sanitizedAnthropicPayload);\n\t\tconst sanitizedPayload = sanitizeOpenAIChatCompletionsPayload(sanitizedResponsesPayload);\n\t\tif (sanitizedPayload === event.payload) return undefined;\n\t\treturn sanitizedPayload;\n\t});\n}\n"]}
@@ -1,11 +1,15 @@
1
1
  import { sanitizeAnthropicPayload } from "./sanitize-anthropic-payload.js";
2
- /** Guards provider requests by removing orphan tool_result blocks. */
2
+ import { sanitizeOpenAIChatCompletionsPayload } from "./sanitize-openai-chat-completions-payload.js";
3
+ import { sanitizeOpenAIResponsesPayload } from "./sanitize-openai-responses-payload.js";
4
+ /** Guards provider requests by keeping tool-call/result pairs balanced. */
3
5
  export default function toolPairGuardExtension(pi) {
4
6
  pi.on("before_provider_request", (event) => {
5
- const sanitized = sanitizeAnthropicPayload(event.payload);
6
- if (sanitized === event.payload)
7
+ const sanitizedAnthropicPayload = sanitizeAnthropicPayload(event.payload);
8
+ const sanitizedResponsesPayload = sanitizeOpenAIResponsesPayload(sanitizedAnthropicPayload);
9
+ const sanitizedPayload = sanitizeOpenAIChatCompletionsPayload(sanitizedResponsesPayload);
10
+ if (sanitizedPayload === event.payload)
7
11
  return undefined;
8
- return sanitized;
12
+ return sanitizedPayload;
9
13
  });
10
14
  }
11
15
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/tool-pair-guard/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,sEAAsE;AACtE,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAAC,EAAgB,EAAQ;IACtE,EAAE,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,wBAAwB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1D,IAAI,SAAS,KAAK,KAAK,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAClD,OAAO,SAAS,CAAC;IAAA,CACjB,CAAC,CAAC;AAAA,CACH","sourcesContent":["import type { ExtensionAPI } from \"../../types.js\";\nimport { sanitizeAnthropicPayload } from \"./sanitize-anthropic-payload.js\";\n\n/** Guards provider requests by removing orphan tool_result blocks. */\nexport default function toolPairGuardExtension(pi: ExtensionAPI): void {\n\tpi.on(\"before_provider_request\", (event) => {\n\t\tconst sanitized = sanitizeAnthropicPayload(event.payload);\n\t\tif (sanitized === event.payload) return undefined;\n\t\treturn sanitized;\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/tool-pair-guard/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,oCAAoC,EAAE,MAAM,+CAA+C,CAAC;AACrG,OAAO,EAAE,8BAA8B,EAAE,MAAM,wCAAwC,CAAC;AAExF,2EAA2E;AAC3E,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAAC,EAAgB,EAAQ;IACtE,EAAE,CAAC,EAAE,CAAC,yBAAyB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC;QAC3C,MAAM,yBAAyB,GAAG,wBAAwB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1E,MAAM,yBAAyB,GAAG,8BAA8B,CAAC,yBAAyB,CAAC,CAAC;QAC5F,MAAM,gBAAgB,GAAG,oCAAoC,CAAC,yBAAyB,CAAC,CAAC;QACzF,IAAI,gBAAgB,KAAK,KAAK,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QACzD,OAAO,gBAAgB,CAAC;IAAA,CACxB,CAAC,CAAC;AAAA,CACH","sourcesContent":["import type { ExtensionAPI } from \"../../types.js\";\nimport { sanitizeAnthropicPayload } from \"./sanitize-anthropic-payload.js\";\nimport { sanitizeOpenAIChatCompletionsPayload } from \"./sanitize-openai-chat-completions-payload.js\";\nimport { sanitizeOpenAIResponsesPayload } from \"./sanitize-openai-responses-payload.js\";\n\n/** Guards provider requests by keeping tool-call/result pairs balanced. */\nexport default function toolPairGuardExtension(pi: ExtensionAPI): void {\n\tpi.on(\"before_provider_request\", (event) => {\n\t\tconst sanitizedAnthropicPayload = sanitizeAnthropicPayload(event.payload);\n\t\tconst sanitizedResponsesPayload = sanitizeOpenAIResponsesPayload(sanitizedAnthropicPayload);\n\t\tconst sanitizedPayload = sanitizeOpenAIChatCompletionsPayload(sanitizedResponsesPayload);\n\t\tif (sanitizedPayload === event.payload) return undefined;\n\t\treturn sanitizedPayload;\n\t});\n}\n"]}
@@ -0,0 +1,3 @@
1
+ /** Repairs OpenAI Chat Completions request messages by keeping tool call/output pairs balanced. */
2
+ export declare function sanitizeOpenAIChatCompletionsPayload(payload: unknown): unknown;
3
+ //# sourceMappingURL=sanitize-openai-chat-completions-payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-openai-chat-completions-payload.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.ts"],"names":[],"mappings":"AAoDA,mGAAmG;AACnG,wBAAgB,oCAAoC,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAmD9E","sourcesContent":["function isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction hasMessagesArray(value: unknown): value is { messages: unknown[] } {\n\treturn isObject(value) && Array.isArray(value.messages);\n}\n\nconst SYNTHETIC_OUTPUT = \"Tool output unavailable (interrupted before result)\";\n\ntype ChatCompletionMessage = Record<string, unknown>;\ntype ChatCompletionToolCall = Record<string, unknown> & { id: string };\n\nfunction isToolCall(value: unknown): value is ChatCompletionToolCall {\n\treturn isObject(value) && typeof value.id === \"string\" && value.id.length > 0;\n}\n\nfunction isMessageWithToolCalls(\n\tvalue: unknown,\n): value is ChatCompletionMessage & { tool_calls: ChatCompletionToolCall[] } {\n\tif (!isObject(value) || value.role !== \"assistant\" || !Array.isArray(value.tool_calls)) return false;\n\tfor (const call of value.tool_calls) {\n\t\tif (!isToolCall(call)) return false;\n\t}\n\treturn true;\n}\n\nfunction isToolRoleMessage(value: unknown): value is ChatCompletionMessage {\n\treturn isObject(value) && value.role === \"tool\";\n}\n\nfunction isToolMessage(value: unknown): value is ChatCompletionMessage & { tool_call_id: string } {\n\treturn isObject(value) && value.role === \"tool\" && typeof value.tool_call_id === \"string\";\n}\n\nfunction createSyntheticToolMessage(toolCallId: string): ChatCompletionMessage {\n\treturn {\n\t\trole: \"tool\",\n\t\ttool_call_id: toolCallId,\n\t\tcontent: SYNTHETIC_OUTPUT,\n\t};\n}\n\nfunction flushMissingToolResults(pendingToolCallIds: string[], sanitizedMessages: unknown[]): boolean {\n\tif (pendingToolCallIds.length === 0) return false;\n\tfor (const toolCallId of pendingToolCallIds) {\n\t\tsanitizedMessages.push(createSyntheticToolMessage(toolCallId));\n\t}\n\tpendingToolCallIds.length = 0;\n\treturn true;\n}\n\n/** Repairs OpenAI Chat Completions request messages by keeping tool call/output pairs balanced. */\nexport function sanitizeOpenAIChatCompletionsPayload(payload: unknown): unknown {\n\tif (!hasMessagesArray(payload)) return payload;\n\n\tlet changed = false;\n\tconst sanitizedMessages: unknown[] = [];\n\tconst pendingToolCallIds: string[] = [];\n\tconst pendingToolCallIdSet = new Set<string>();\n\n\tfor (const message of payload.messages) {\n\t\tif (isMessageWithToolCalls(message)) {\n\t\t\tif (flushMissingToolResults(pendingToolCallIds, sanitizedMessages)) {\n\t\t\t\tpendingToolCallIdSet.clear();\n\t\t\t\tchanged = true;\n\t\t\t}\n\n\t\t\tsanitizedMessages.push(message);\n\t\t\tfor (const call of message.tool_calls) {\n\t\t\t\tpendingToolCallIds.push(call.id);\n\t\t\t\tpendingToolCallIdSet.add(call.id);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isToolRoleMessage(message)) {\n\t\t\tif (\n\t\t\t\t!isToolMessage(message) ||\n\t\t\t\tmessage.tool_call_id.length === 0 ||\n\t\t\t\t!pendingToolCallIdSet.has(message.tool_call_id)\n\t\t\t) {\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tsanitizedMessages.push(message);\n\t\t\tpendingToolCallIdSet.delete(message.tool_call_id);\n\t\t\tconst pendingIndex = pendingToolCallIds.indexOf(message.tool_call_id);\n\t\t\tif (pendingIndex >= 0) pendingToolCallIds.splice(pendingIndex, 1);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (flushMissingToolResults(pendingToolCallIds, sanitizedMessages)) {\n\t\t\tpendingToolCallIdSet.clear();\n\t\t\tchanged = true;\n\t\t}\n\t\tsanitizedMessages.push(message);\n\t}\n\n\tif (flushMissingToolResults(pendingToolCallIds, sanitizedMessages)) changed = true;\n\n\tif (!changed) return payload;\n\treturn { ...payload, messages: sanitizedMessages };\n}\n"]}
@@ -0,0 +1,89 @@
1
+ function isObject(value) {
2
+ return typeof value === "object" && value !== null;
3
+ }
4
+ function hasMessagesArray(value) {
5
+ return isObject(value) && Array.isArray(value.messages);
6
+ }
7
+ const SYNTHETIC_OUTPUT = "Tool output unavailable (interrupted before result)";
8
+ function isToolCall(value) {
9
+ return isObject(value) && typeof value.id === "string" && value.id.length > 0;
10
+ }
11
+ function isMessageWithToolCalls(value) {
12
+ if (!isObject(value) || value.role !== "assistant" || !Array.isArray(value.tool_calls))
13
+ return false;
14
+ for (const call of value.tool_calls) {
15
+ if (!isToolCall(call))
16
+ return false;
17
+ }
18
+ return true;
19
+ }
20
+ function isToolRoleMessage(value) {
21
+ return isObject(value) && value.role === "tool";
22
+ }
23
+ function isToolMessage(value) {
24
+ return isObject(value) && value.role === "tool" && typeof value.tool_call_id === "string";
25
+ }
26
+ function createSyntheticToolMessage(toolCallId) {
27
+ return {
28
+ role: "tool",
29
+ tool_call_id: toolCallId,
30
+ content: SYNTHETIC_OUTPUT,
31
+ };
32
+ }
33
+ function flushMissingToolResults(pendingToolCallIds, sanitizedMessages) {
34
+ if (pendingToolCallIds.length === 0)
35
+ return false;
36
+ for (const toolCallId of pendingToolCallIds) {
37
+ sanitizedMessages.push(createSyntheticToolMessage(toolCallId));
38
+ }
39
+ pendingToolCallIds.length = 0;
40
+ return true;
41
+ }
42
+ /** Repairs OpenAI Chat Completions request messages by keeping tool call/output pairs balanced. */
43
+ export function sanitizeOpenAIChatCompletionsPayload(payload) {
44
+ if (!hasMessagesArray(payload))
45
+ return payload;
46
+ let changed = false;
47
+ const sanitizedMessages = [];
48
+ const pendingToolCallIds = [];
49
+ const pendingToolCallIdSet = new Set();
50
+ for (const message of payload.messages) {
51
+ if (isMessageWithToolCalls(message)) {
52
+ if (flushMissingToolResults(pendingToolCallIds, sanitizedMessages)) {
53
+ pendingToolCallIdSet.clear();
54
+ changed = true;
55
+ }
56
+ sanitizedMessages.push(message);
57
+ for (const call of message.tool_calls) {
58
+ pendingToolCallIds.push(call.id);
59
+ pendingToolCallIdSet.add(call.id);
60
+ }
61
+ continue;
62
+ }
63
+ if (isToolRoleMessage(message)) {
64
+ if (!isToolMessage(message) ||
65
+ message.tool_call_id.length === 0 ||
66
+ !pendingToolCallIdSet.has(message.tool_call_id)) {
67
+ changed = true;
68
+ continue;
69
+ }
70
+ sanitizedMessages.push(message);
71
+ pendingToolCallIdSet.delete(message.tool_call_id);
72
+ const pendingIndex = pendingToolCallIds.indexOf(message.tool_call_id);
73
+ if (pendingIndex >= 0)
74
+ pendingToolCallIds.splice(pendingIndex, 1);
75
+ continue;
76
+ }
77
+ if (flushMissingToolResults(pendingToolCallIds, sanitizedMessages)) {
78
+ pendingToolCallIdSet.clear();
79
+ changed = true;
80
+ }
81
+ sanitizedMessages.push(message);
82
+ }
83
+ if (flushMissingToolResults(pendingToolCallIds, sanitizedMessages))
84
+ changed = true;
85
+ if (!changed)
86
+ return payload;
87
+ return { ...payload, messages: sanitizedMessages };
88
+ }
89
+ //# sourceMappingURL=sanitize-openai-chat-completions-payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-openai-chat-completions-payload.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/tool-pair-guard/sanitize-openai-chat-completions-payload.ts"],"names":[],"mappings":"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","sourcesContent":["function isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction hasMessagesArray(value: unknown): value is { messages: unknown[] } {\n\treturn isObject(value) && Array.isArray(value.messages);\n}\n\nconst SYNTHETIC_OUTPUT = \"Tool output unavailable (interrupted before result)\";\n\ntype ChatCompletionMessage = Record<string, unknown>;\ntype ChatCompletionToolCall = Record<string, unknown> & { id: string };\n\nfunction isToolCall(value: unknown): value is ChatCompletionToolCall {\n\treturn isObject(value) && typeof value.id === \"string\" && value.id.length > 0;\n}\n\nfunction isMessageWithToolCalls(\n\tvalue: unknown,\n): value is ChatCompletionMessage & { tool_calls: ChatCompletionToolCall[] } {\n\tif (!isObject(value) || value.role !== \"assistant\" || !Array.isArray(value.tool_calls)) return false;\n\tfor (const call of value.tool_calls) {\n\t\tif (!isToolCall(call)) return false;\n\t}\n\treturn true;\n}\n\nfunction isToolRoleMessage(value: unknown): value is ChatCompletionMessage {\n\treturn isObject(value) && value.role === \"tool\";\n}\n\nfunction isToolMessage(value: unknown): value is ChatCompletionMessage & { tool_call_id: string } {\n\treturn isObject(value) && value.role === \"tool\" && typeof value.tool_call_id === \"string\";\n}\n\nfunction createSyntheticToolMessage(toolCallId: string): ChatCompletionMessage {\n\treturn {\n\t\trole: \"tool\",\n\t\ttool_call_id: toolCallId,\n\t\tcontent: SYNTHETIC_OUTPUT,\n\t};\n}\n\nfunction flushMissingToolResults(pendingToolCallIds: string[], sanitizedMessages: unknown[]): boolean {\n\tif (pendingToolCallIds.length === 0) return false;\n\tfor (const toolCallId of pendingToolCallIds) {\n\t\tsanitizedMessages.push(createSyntheticToolMessage(toolCallId));\n\t}\n\tpendingToolCallIds.length = 0;\n\treturn true;\n}\n\n/** Repairs OpenAI Chat Completions request messages by keeping tool call/output pairs balanced. */\nexport function sanitizeOpenAIChatCompletionsPayload(payload: unknown): unknown {\n\tif (!hasMessagesArray(payload)) return payload;\n\n\tlet changed = false;\n\tconst sanitizedMessages: unknown[] = [];\n\tconst pendingToolCallIds: string[] = [];\n\tconst pendingToolCallIdSet = new Set<string>();\n\n\tfor (const message of payload.messages) {\n\t\tif (isMessageWithToolCalls(message)) {\n\t\t\tif (flushMissingToolResults(pendingToolCallIds, sanitizedMessages)) {\n\t\t\t\tpendingToolCallIdSet.clear();\n\t\t\t\tchanged = true;\n\t\t\t}\n\n\t\t\tsanitizedMessages.push(message);\n\t\t\tfor (const call of message.tool_calls) {\n\t\t\t\tpendingToolCallIds.push(call.id);\n\t\t\t\tpendingToolCallIdSet.add(call.id);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isToolRoleMessage(message)) {\n\t\t\tif (\n\t\t\t\t!isToolMessage(message) ||\n\t\t\t\tmessage.tool_call_id.length === 0 ||\n\t\t\t\t!pendingToolCallIdSet.has(message.tool_call_id)\n\t\t\t) {\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tsanitizedMessages.push(message);\n\t\t\tpendingToolCallIdSet.delete(message.tool_call_id);\n\t\t\tconst pendingIndex = pendingToolCallIds.indexOf(message.tool_call_id);\n\t\t\tif (pendingIndex >= 0) pendingToolCallIds.splice(pendingIndex, 1);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (flushMissingToolResults(pendingToolCallIds, sanitizedMessages)) {\n\t\t\tpendingToolCallIdSet.clear();\n\t\t\tchanged = true;\n\t\t}\n\t\tsanitizedMessages.push(message);\n\t}\n\n\tif (flushMissingToolResults(pendingToolCallIds, sanitizedMessages)) changed = true;\n\n\tif (!changed) return payload;\n\treturn { ...payload, messages: sanitizedMessages };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ /** Repairs OpenAI Responses request input by keeping tool call/output pairs balanced. */
2
+ export declare function sanitizeOpenAIResponsesPayload(payload: unknown): unknown;
3
+ //# sourceMappingURL=sanitize-openai-responses-payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-openai-responses-payload.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.ts"],"names":[],"mappings":"AAiGA,yFAAyF;AACzF,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAkDxE","sourcesContent":["const SYNTHETIC_OUTPUT = \"Tool output unavailable (interrupted before result)\";\n\ntype ResponsesPayload = Record<string, unknown> & { input: unknown[] };\ntype ResponsesItem = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction hasResponsesInput(value: unknown): value is ResponsesPayload {\n\treturn isObject(value) && Array.isArray(value.input);\n}\n\nfunction getType(item: unknown): string | undefined {\n\treturn isObject(item) && typeof item.type === \"string\" ? item.type : undefined;\n}\n\nfunction getCallId(item: unknown): string | undefined {\n\tif (!isObject(item) || typeof item.call_id !== \"string\" || item.call_id.length === 0) return undefined;\n\treturn item.call_id;\n}\n\nfunction isFunctionCallItem(item: unknown): item is ResponsesItem {\n\tconst type = getType(item);\n\treturn type === \"function_call\" || type === \"local_shell_call\";\n}\n\nfunction isFunctionCallOutputItem(item: unknown): item is ResponsesItem {\n\treturn getType(item) === \"function_call_output\";\n}\n\nfunction isCustomToolCallItem(item: unknown): item is ResponsesItem {\n\treturn getType(item) === \"custom_tool_call\";\n}\n\nfunction isCustomToolCallOutputItem(item: unknown): item is ResponsesItem {\n\treturn getType(item) === \"custom_tool_call_output\";\n}\n\nfunction getCustomToolName(item: ResponsesItem): string | undefined {\n\treturn typeof item.name === \"string\" && item.name.length > 0 ? item.name : undefined;\n}\n\nfunction collectMatchedOutputIds(input: unknown[]): {\n\tfunctionOutputIds: Set<string>;\n\tcustomOutputIds: Set<string>;\n} {\n\tconst seenFunctionCallIds = new Set<string>();\n\tconst seenCustomCallIds = new Set<string>();\n\tconst functionOutputIds = new Set<string>();\n\tconst customOutputIds = new Set<string>();\n\n\tfor (const item of input) {\n\t\tconst callId = getCallId(item);\n\t\tif (!callId) continue;\n\n\t\tif (isFunctionCallItem(item)) {\n\t\t\tseenFunctionCallIds.add(callId);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isCustomToolCallItem(item)) {\n\t\t\tseenCustomCallIds.add(callId);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isFunctionCallOutputItem(item) && seenFunctionCallIds.has(callId) && !functionOutputIds.has(callId)) {\n\t\t\tfunctionOutputIds.add(callId);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isCustomToolCallOutputItem(item) && seenCustomCallIds.has(callId) && !customOutputIds.has(callId)) {\n\t\t\tcustomOutputIds.add(callId);\n\t\t}\n\t}\n\n\treturn { functionOutputIds, customOutputIds };\n}\n\nfunction createSyntheticFunctionOutput(callId: string): ResponsesItem {\n\treturn {\n\t\ttype: \"function_call_output\",\n\t\tcall_id: callId,\n\t\toutput: SYNTHETIC_OUTPUT,\n\t};\n}\n\nfunction createSyntheticCustomToolOutput(callId: string, callItem: ResponsesItem): ResponsesItem {\n\tconst name = getCustomToolName(callItem);\n\treturn {\n\t\ttype: \"custom_tool_call_output\",\n\t\tcall_id: callId,\n\t\t...(name ? { name } : {}),\n\t\toutput: SYNTHETIC_OUTPUT,\n\t};\n}\n\n/** Repairs OpenAI Responses request input by keeping tool call/output pairs balanced. */\nexport function sanitizeOpenAIResponsesPayload(payload: unknown): unknown {\n\tif (!hasResponsesInput(payload)) return payload;\n\t// Output-only deltas are valid when server-side continuation is explicitly referenced.\n\tif (typeof payload.previous_response_id === \"string\" && payload.previous_response_id.length > 0) return payload;\n\n\tconst { functionOutputIds, customOutputIds } = collectMatchedOutputIds(payload.input);\n\tconst sanitizedInput: unknown[] = [];\n\tconst emittedFunctionOutputIds = new Set<string>();\n\tconst emittedCustomOutputIds = new Set<string>();\n\tlet changed = false;\n\n\tfor (const item of payload.input) {\n\t\tconst callId = getCallId(item);\n\n\t\tif (isFunctionCallOutputItem(item)) {\n\t\t\tif (!callId || !functionOutputIds.has(callId) || emittedFunctionOutputIds.has(callId)) {\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\temittedFunctionOutputIds.add(callId);\n\t\t\tsanitizedInput.push(item);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isCustomToolCallOutputItem(item)) {\n\t\t\tif (!callId || !customOutputIds.has(callId) || emittedCustomOutputIds.has(callId)) {\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\temittedCustomOutputIds.add(callId);\n\t\t\tsanitizedInput.push(item);\n\t\t\tcontinue;\n\t\t}\n\n\t\tsanitizedInput.push(item);\n\n\t\tif (callId && isFunctionCallItem(item) && !functionOutputIds.has(callId)) {\n\t\t\tsanitizedInput.push(createSyntheticFunctionOutput(callId));\n\t\t\tchanged = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (callId && isCustomToolCallItem(item) && !customOutputIds.has(callId)) {\n\t\t\tsanitizedInput.push(createSyntheticCustomToolOutput(callId, item));\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\tif (!changed) return payload;\n\treturn { ...payload, input: sanitizedInput };\n}\n"]}
@@ -0,0 +1,122 @@
1
+ const SYNTHETIC_OUTPUT = "Tool output unavailable (interrupted before result)";
2
+ function isObject(value) {
3
+ return typeof value === "object" && value !== null;
4
+ }
5
+ function hasResponsesInput(value) {
6
+ return isObject(value) && Array.isArray(value.input);
7
+ }
8
+ function getType(item) {
9
+ return isObject(item) && typeof item.type === "string" ? item.type : undefined;
10
+ }
11
+ function getCallId(item) {
12
+ if (!isObject(item) || typeof item.call_id !== "string" || item.call_id.length === 0)
13
+ return undefined;
14
+ return item.call_id;
15
+ }
16
+ function isFunctionCallItem(item) {
17
+ const type = getType(item);
18
+ return type === "function_call" || type === "local_shell_call";
19
+ }
20
+ function isFunctionCallOutputItem(item) {
21
+ return getType(item) === "function_call_output";
22
+ }
23
+ function isCustomToolCallItem(item) {
24
+ return getType(item) === "custom_tool_call";
25
+ }
26
+ function isCustomToolCallOutputItem(item) {
27
+ return getType(item) === "custom_tool_call_output";
28
+ }
29
+ function getCustomToolName(item) {
30
+ return typeof item.name === "string" && item.name.length > 0 ? item.name : undefined;
31
+ }
32
+ function collectMatchedOutputIds(input) {
33
+ const seenFunctionCallIds = new Set();
34
+ const seenCustomCallIds = new Set();
35
+ const functionOutputIds = new Set();
36
+ const customOutputIds = new Set();
37
+ for (const item of input) {
38
+ const callId = getCallId(item);
39
+ if (!callId)
40
+ continue;
41
+ if (isFunctionCallItem(item)) {
42
+ seenFunctionCallIds.add(callId);
43
+ continue;
44
+ }
45
+ if (isCustomToolCallItem(item)) {
46
+ seenCustomCallIds.add(callId);
47
+ continue;
48
+ }
49
+ if (isFunctionCallOutputItem(item) && seenFunctionCallIds.has(callId) && !functionOutputIds.has(callId)) {
50
+ functionOutputIds.add(callId);
51
+ continue;
52
+ }
53
+ if (isCustomToolCallOutputItem(item) && seenCustomCallIds.has(callId) && !customOutputIds.has(callId)) {
54
+ customOutputIds.add(callId);
55
+ }
56
+ }
57
+ return { functionOutputIds, customOutputIds };
58
+ }
59
+ function createSyntheticFunctionOutput(callId) {
60
+ return {
61
+ type: "function_call_output",
62
+ call_id: callId,
63
+ output: SYNTHETIC_OUTPUT,
64
+ };
65
+ }
66
+ function createSyntheticCustomToolOutput(callId, callItem) {
67
+ const name = getCustomToolName(callItem);
68
+ return {
69
+ type: "custom_tool_call_output",
70
+ call_id: callId,
71
+ ...(name ? { name } : {}),
72
+ output: SYNTHETIC_OUTPUT,
73
+ };
74
+ }
75
+ /** Repairs OpenAI Responses request input by keeping tool call/output pairs balanced. */
76
+ export function sanitizeOpenAIResponsesPayload(payload) {
77
+ if (!hasResponsesInput(payload))
78
+ return payload;
79
+ // Output-only deltas are valid when server-side continuation is explicitly referenced.
80
+ if (typeof payload.previous_response_id === "string" && payload.previous_response_id.length > 0)
81
+ return payload;
82
+ const { functionOutputIds, customOutputIds } = collectMatchedOutputIds(payload.input);
83
+ const sanitizedInput = [];
84
+ const emittedFunctionOutputIds = new Set();
85
+ const emittedCustomOutputIds = new Set();
86
+ let changed = false;
87
+ for (const item of payload.input) {
88
+ const callId = getCallId(item);
89
+ if (isFunctionCallOutputItem(item)) {
90
+ if (!callId || !functionOutputIds.has(callId) || emittedFunctionOutputIds.has(callId)) {
91
+ changed = true;
92
+ continue;
93
+ }
94
+ emittedFunctionOutputIds.add(callId);
95
+ sanitizedInput.push(item);
96
+ continue;
97
+ }
98
+ if (isCustomToolCallOutputItem(item)) {
99
+ if (!callId || !customOutputIds.has(callId) || emittedCustomOutputIds.has(callId)) {
100
+ changed = true;
101
+ continue;
102
+ }
103
+ emittedCustomOutputIds.add(callId);
104
+ sanitizedInput.push(item);
105
+ continue;
106
+ }
107
+ sanitizedInput.push(item);
108
+ if (callId && isFunctionCallItem(item) && !functionOutputIds.has(callId)) {
109
+ sanitizedInput.push(createSyntheticFunctionOutput(callId));
110
+ changed = true;
111
+ continue;
112
+ }
113
+ if (callId && isCustomToolCallItem(item) && !customOutputIds.has(callId)) {
114
+ sanitizedInput.push(createSyntheticCustomToolOutput(callId, item));
115
+ changed = true;
116
+ }
117
+ }
118
+ if (!changed)
119
+ return payload;
120
+ return { ...payload, input: sanitizedInput };
121
+ }
122
+ //# sourceMappingURL=sanitize-openai-responses-payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-openai-responses-payload.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/tool-pair-guard/sanitize-openai-responses-payload.ts"],"names":[],"mappings":"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","sourcesContent":["const SYNTHETIC_OUTPUT = \"Tool output unavailable (interrupted before result)\";\n\ntype ResponsesPayload = Record<string, unknown> & { input: unknown[] };\ntype ResponsesItem = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction hasResponsesInput(value: unknown): value is ResponsesPayload {\n\treturn isObject(value) && Array.isArray(value.input);\n}\n\nfunction getType(item: unknown): string | undefined {\n\treturn isObject(item) && typeof item.type === \"string\" ? item.type : undefined;\n}\n\nfunction getCallId(item: unknown): string | undefined {\n\tif (!isObject(item) || typeof item.call_id !== \"string\" || item.call_id.length === 0) return undefined;\n\treturn item.call_id;\n}\n\nfunction isFunctionCallItem(item: unknown): item is ResponsesItem {\n\tconst type = getType(item);\n\treturn type === \"function_call\" || type === \"local_shell_call\";\n}\n\nfunction isFunctionCallOutputItem(item: unknown): item is ResponsesItem {\n\treturn getType(item) === \"function_call_output\";\n}\n\nfunction isCustomToolCallItem(item: unknown): item is ResponsesItem {\n\treturn getType(item) === \"custom_tool_call\";\n}\n\nfunction isCustomToolCallOutputItem(item: unknown): item is ResponsesItem {\n\treturn getType(item) === \"custom_tool_call_output\";\n}\n\nfunction getCustomToolName(item: ResponsesItem): string | undefined {\n\treturn typeof item.name === \"string\" && item.name.length > 0 ? item.name : undefined;\n}\n\nfunction collectMatchedOutputIds(input: unknown[]): {\n\tfunctionOutputIds: Set<string>;\n\tcustomOutputIds: Set<string>;\n} {\n\tconst seenFunctionCallIds = new Set<string>();\n\tconst seenCustomCallIds = new Set<string>();\n\tconst functionOutputIds = new Set<string>();\n\tconst customOutputIds = new Set<string>();\n\n\tfor (const item of input) {\n\t\tconst callId = getCallId(item);\n\t\tif (!callId) continue;\n\n\t\tif (isFunctionCallItem(item)) {\n\t\t\tseenFunctionCallIds.add(callId);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isCustomToolCallItem(item)) {\n\t\t\tseenCustomCallIds.add(callId);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isFunctionCallOutputItem(item) && seenFunctionCallIds.has(callId) && !functionOutputIds.has(callId)) {\n\t\t\tfunctionOutputIds.add(callId);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isCustomToolCallOutputItem(item) && seenCustomCallIds.has(callId) && !customOutputIds.has(callId)) {\n\t\t\tcustomOutputIds.add(callId);\n\t\t}\n\t}\n\n\treturn { functionOutputIds, customOutputIds };\n}\n\nfunction createSyntheticFunctionOutput(callId: string): ResponsesItem {\n\treturn {\n\t\ttype: \"function_call_output\",\n\t\tcall_id: callId,\n\t\toutput: SYNTHETIC_OUTPUT,\n\t};\n}\n\nfunction createSyntheticCustomToolOutput(callId: string, callItem: ResponsesItem): ResponsesItem {\n\tconst name = getCustomToolName(callItem);\n\treturn {\n\t\ttype: \"custom_tool_call_output\",\n\t\tcall_id: callId,\n\t\t...(name ? { name } : {}),\n\t\toutput: SYNTHETIC_OUTPUT,\n\t};\n}\n\n/** Repairs OpenAI Responses request input by keeping tool call/output pairs balanced. */\nexport function sanitizeOpenAIResponsesPayload(payload: unknown): unknown {\n\tif (!hasResponsesInput(payload)) return payload;\n\t// Output-only deltas are valid when server-side continuation is explicitly referenced.\n\tif (typeof payload.previous_response_id === \"string\" && payload.previous_response_id.length > 0) return payload;\n\n\tconst { functionOutputIds, customOutputIds } = collectMatchedOutputIds(payload.input);\n\tconst sanitizedInput: unknown[] = [];\n\tconst emittedFunctionOutputIds = new Set<string>();\n\tconst emittedCustomOutputIds = new Set<string>();\n\tlet changed = false;\n\n\tfor (const item of payload.input) {\n\t\tconst callId = getCallId(item);\n\n\t\tif (isFunctionCallOutputItem(item)) {\n\t\t\tif (!callId || !functionOutputIds.has(callId) || emittedFunctionOutputIds.has(callId)) {\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\temittedFunctionOutputIds.add(callId);\n\t\t\tsanitizedInput.push(item);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isCustomToolCallOutputItem(item)) {\n\t\t\tif (!callId || !customOutputIds.has(callId) || emittedCustomOutputIds.has(callId)) {\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\temittedCustomOutputIds.add(callId);\n\t\t\tsanitizedInput.push(item);\n\t\t\tcontinue;\n\t\t}\n\n\t\tsanitizedInput.push(item);\n\n\t\tif (callId && isFunctionCallItem(item) && !functionOutputIds.has(callId)) {\n\t\t\tsanitizedInput.push(createSyntheticFunctionOutput(callId));\n\t\t\tchanged = true;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (callId && isCustomToolCallItem(item) && !customOutputIds.has(callId)) {\n\t\t\tsanitizedInput.push(createSyntheticCustomToolOutput(callId, item));\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\tif (!changed) return payload;\n\treturn { ...payload, input: sanitizedInput };\n}\n"]}