ummaya 0.2.3 → 0.2.5

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 (534) hide show
  1. package/README.md +17 -3
  2. package/bin/ummaya +10 -1
  3. package/npm-shrinkwrap.json +253 -2
  4. package/package.json +5 -1
  5. package/prompts/manifest.yaml +2 -2
  6. package/prompts/session_guidance_v1.md +3 -1
  7. package/prompts/system_v1.md +9 -7
  8. package/pyproject.toml +26 -7
  9. package/specs/2803-document-production-hardening/contracts/document-tools.schema.json +1043 -0
  10. package/src/ummaya/_canonical/__init__.py +2 -0
  11. package/src/ummaya/context/builder.py +17 -11
  12. package/src/ummaya/engine/engine.py +30 -113
  13. package/src/ummaya/engine/query.py +20 -0
  14. package/src/ummaya/evidence/__init__.py +44 -0
  15. package/src/ummaya/evidence/__main__.py +7 -0
  16. package/src/ummaya/evidence/dataset_contract.py +193 -0
  17. package/src/ummaya/evidence/document_authoring_cases.py +33 -0
  18. package/src/ummaya/evidence/document_harness.py +313 -0
  19. package/src/ummaya/evidence/document_viewer_ux.py +391 -0
  20. package/src/ummaya/evidence/gates.py +70 -0
  21. package/src/ummaya/evidence/json_types.py +20 -0
  22. package/src/ummaya/evidence/models.py +145 -0
  23. package/src/ummaya/evidence/output_payload.py +89 -0
  24. package/src/ummaya/evidence/payload_documents.py +233 -0
  25. package/src/ummaya/evidence/route_contracts.py +224 -0
  26. package/src/ummaya/evidence/route_helpers.py +150 -0
  27. package/src/ummaya/evidence/runner.py +177 -0
  28. package/src/ummaya/evidence/source_provenance.py +246 -0
  29. package/src/ummaya/evidence/source_provenance_redaction.py +176 -0
  30. package/src/ummaya/evidence/task_registry.py +264 -0
  31. package/src/ummaya/evidence/tool_layer.py +39 -0
  32. package/src/ummaya/evidence/tool_layer_models.py +151 -0
  33. package/src/ummaya/ipc/adapter_manifest_emitter.py +26 -10
  34. package/src/ummaya/ipc/document_intent_normalization.py +185 -0
  35. package/src/ummaya/ipc/frame_schema.py +52 -5
  36. package/src/ummaya/ipc/route_diagnostics.py +73 -0
  37. package/src/ummaya/ipc/stdio.py +2282 -417
  38. package/src/ummaya/llm/client.py +234 -59
  39. package/src/ummaya/llm/config.py +8 -3
  40. package/src/ummaya/llm/reasoning.py +84 -0
  41. package/src/ummaya/primitives/__init__.py +6 -2
  42. package/src/ummaya/primitives/delegation.py +1 -1
  43. package/src/ummaya/primitives/document.py +28 -0
  44. package/src/ummaya/settings.py +0 -3
  45. package/src/ummaya/tools/discovery_bridge.py +34 -2
  46. package/src/ummaya/tools/documents/__init__.py +297 -0
  47. package/src/ummaya/tools/documents/adapter_registry.py +487 -0
  48. package/src/ummaya/tools/documents/archive_container_probe.py +167 -0
  49. package/src/ummaya/tools/documents/artifact_store.py +454 -0
  50. package/src/ummaya/tools/documents/authoring.py +283 -0
  51. package/src/ummaya/tools/documents/baselines.py +114 -0
  52. package/src/ummaya/tools/documents/capability.py +331 -0
  53. package/src/ummaya/tools/documents/contracts.py +112 -0
  54. package/src/ummaya/tools/documents/conversion.py +521 -0
  55. package/src/ummaya/tools/documents/diff.py +275 -0
  56. package/src/ummaya/tools/documents/engines.py +163 -0
  57. package/src/ummaya/tools/documents/evaluation.py +291 -0
  58. package/src/ummaya/tools/documents/explicit_values.py +108 -0
  59. package/src/ummaya/tools/documents/fixtures.py +174 -0
  60. package/src/ummaya/tools/documents/format_completion_audit.py +471 -0
  61. package/src/ummaya/tools/documents/formats/__init__.py +2 -0
  62. package/src/ummaya/tools/documents/formats/archive.py +528 -0
  63. package/src/ummaya/tools/documents/formats/base.py +41 -0
  64. package/src/ummaya/tools/documents/formats/code_file.py +211 -0
  65. package/src/ummaya/tools/documents/formats/data_file.py +272 -0
  66. package/src/ummaya/tools/documents/formats/hwp.py +284 -0
  67. package/src/ummaya/tools/documents/formats/hwpx.py +1837 -0
  68. package/src/ummaya/tools/documents/formats/odf.py +435 -0
  69. package/src/ummaya/tools/documents/formats/ooxml.py +1030 -0
  70. package/src/ummaya/tools/documents/formats/passive.py +766 -0
  71. package/src/ummaya/tools/documents/formats/pdf.py +702 -0
  72. package/src/ummaya/tools/documents/formats/text_web.py +268 -0
  73. package/src/ummaya/tools/documents/hwp_conversion_probe.py +178 -0
  74. package/src/ummaya/tools/documents/hwp_direct_candidate.py +141 -0
  75. package/src/ummaya/tools/documents/inspection.py +289 -0
  76. package/src/ummaya/tools/documents/intake.py +1079 -0
  77. package/src/ummaya/tools/documents/legacy_office_promotion_probe.py +366 -0
  78. package/src/ummaya/tools/documents/models.py +1598 -0
  79. package/src/ummaya/tools/documents/odf_promotion_probe.py +167 -0
  80. package/src/ummaya/tools/documents/orchestrator.py +96 -0
  81. package/src/ummaya/tools/documents/passive_capability_probe.py +251 -0
  82. package/src/ummaya/tools/documents/patch.py +170 -0
  83. package/src/ummaya/tools/documents/pdfa_conformance.py +284 -0
  84. package/src/ummaya/tools/documents/pdfa_promotion_probe.py +198 -0
  85. package/src/ummaya/tools/documents/permissions.py +110 -0
  86. package/src/ummaya/tools/documents/planner.py +616 -0
  87. package/src/ummaya/tools/documents/registry.py +2733 -0
  88. package/src/ummaya/tools/documents/render.py +978 -0
  89. package/src/ummaya/tools/documents/render_comparison.py +113 -0
  90. package/src/ummaya/tools/documents/render_comparison_models.py +74 -0
  91. package/src/ummaya/tools/documents/render_comparison_regions.py +73 -0
  92. package/src/ummaya/tools/documents/render_comparison_style.py +161 -0
  93. package/src/ummaya/tools/documents/reread.py +157 -0
  94. package/src/ummaya/tools/documents/runtime_authoring.py +244 -0
  95. package/src/ummaya/tools/documents/runtime_authoring_bundle.py +76 -0
  96. package/src/ummaya/tools/documents/scorecard.py +184 -0
  97. package/src/ummaya/tools/documents/socratic_planner.py +193 -0
  98. package/src/ummaya/tools/documents/style.py +48 -0
  99. package/src/ummaya/tools/documents/tool_defs.py +523 -0
  100. package/src/ummaya/tools/documents/validate.py +347 -0
  101. package/src/ummaya/tools/executor.py +61 -12
  102. package/src/ummaya/tools/geocoding/kakao_client.py +1 -2
  103. package/src/ummaya/tools/kma/apihub_catalog.py +984 -1
  104. package/src/ummaya/tools/kma/apihub_structured_adapter.py +86 -6
  105. package/src/ummaya/tools/kma/apihub_url_adapter.py +593 -0
  106. package/src/ummaya/tools/kma/apihub_url_catalog.py +296 -0
  107. package/src/ummaya/tools/live_proxy.py +0 -3
  108. package/src/ummaya/tools/location_adapters.py +8 -6
  109. package/src/ummaya/tools/manifest_metadata.py +16 -3
  110. package/src/ummaya/tools/models.py +5 -1
  111. package/src/ummaya/tools/mvp_surface.py +2 -2
  112. package/src/ummaya/tools/nmc/emergency_search.py +8 -6
  113. package/src/ummaya/tools/register_all.py +17 -0
  114. package/src/ummaya/tools/registry.py +10 -1
  115. package/src/ummaya/tools/resolve_location.py +4 -4
  116. package/src/ummaya/tools/routing/__init__.py +59 -0
  117. package/src/ummaya/tools/routing/builder.py +105 -0
  118. package/src/ummaya/tools/routing/cards.py +29 -0
  119. package/src/ummaya/tools/routing/decision_service.py +534 -0
  120. package/src/ummaya/tools/routing/decision_types.py +74 -0
  121. package/src/ummaya/tools/routing/feasibility.py +122 -0
  122. package/src/ummaya/tools/routing/intent.py +17 -0
  123. package/src/ummaya/tools/routing/intent_extractor.py +207 -0
  124. package/src/ummaya/tools/routing/intent_patterns.py +160 -0
  125. package/src/ummaya/tools/routing/intent_public_data.py +150 -0
  126. package/src/ummaya/tools/routing/intent_types.py +48 -0
  127. package/src/ummaya/tools/routing/lint.py +78 -0
  128. package/src/ummaya/tools/routing/metadata.py +174 -0
  129. package/src/ummaya/tools/routing/projection.py +340 -0
  130. package/src/ummaya/tools/routing/retrieval_policy.py +629 -0
  131. package/src/ummaya/tools/routing/schema.py +81 -0
  132. package/src/ummaya/tools/routing/types.py +96 -0
  133. package/src/ummaya/tools/routing_index.py +2 -2
  134. package/src/ummaya/tools/search.py +40 -106
  135. package/src/ummaya/tools/verified_data_go_kr/_manifest.py +115 -25
  136. package/src/ummaya/tools/verified_data_go_kr/airkorea_air_quality.py +109 -4
  137. package/src/ummaya/tools/verified_data_go_kr/nmc_aed_site.py +108 -2
  138. package/src/ummaya/tools/verified_data_go_kr/pps_bid_public_info.py +174 -9
  139. package/src/ummaya/tools/verified_data_go_kr/tago_bus_arrival.py +66 -3
  140. package/src/ummaya/tools/verified_data_go_kr/tago_bus_location.py +12 -2
  141. package/src/ummaya/tools/verified_data_go_kr/tago_bus_route.py +8 -2
  142. package/src/ummaya/tools/verified_data_go_kr/tago_bus_route_station.py +114 -0
  143. package/src/ummaya/tools/verified_data_go_kr/tago_bus_station.py +14 -3
  144. package/src/ummaya/tools/verify_canonical_map.py +21 -0
  145. package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
  146. package/tui/package.json +1 -2
  147. package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
  148. package/tui/src/QueryEngine.ts +12 -4
  149. package/tui/src/bridge/inboundAttachments.ts +3 -3
  150. package/tui/src/cli/handlers/auth.ts +4 -13
  151. package/tui/src/cli/handlers/mcp.tsx +3 -3
  152. package/tui/src/cli/print.ts +69 -18
  153. package/tui/src/cli/update.ts +13 -13
  154. package/tui/src/commands/copy/index.ts +1 -1
  155. package/tui/src/commands/cost/cost.ts +2 -2
  156. package/tui/src/commands/init-verifiers.ts +5 -5
  157. package/tui/src/commands/init.ts +30 -30
  158. package/tui/src/commands/insights.ts +44 -44
  159. package/tui/src/commands/install-github-app/install-github-app.tsx +2 -2
  160. package/tui/src/commands/install-github-app/setupGitHubActions.ts +3 -3
  161. package/tui/src/commands/install-github-app/types.ts +8 -30
  162. package/tui/src/commands/install.tsx +5 -5
  163. package/tui/src/commands/mcp/addCommand.ts +5 -5
  164. package/tui/src/commands/mcp/xaaIdpCommand.ts +2 -2
  165. package/tui/src/commands/plugin/ManageMarketplaces.tsx +2 -2
  166. package/tui/src/commands/plugin/types.ts +6 -28
  167. package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
  168. package/tui/src/commands/reasoning/index.ts +13 -0
  169. package/tui/src/commands/reasoning/reasoning.tsx +177 -0
  170. package/tui/src/commands/rename/generateSessionName.ts +1 -1
  171. package/tui/src/commands/thinkback/thinkback.tsx +3 -3
  172. package/tui/src/commands.ts +2 -0
  173. package/tui/src/components/Feedback.tsx +1 -1
  174. package/tui/src/components/LogoV2/EmergencyTip.tsx +11 -2
  175. package/tui/src/components/LogoV2/WelcomeV2.tsx +1 -3
  176. package/tui/src/components/Messages.tsx +2 -1
  177. package/tui/src/components/ScrollKeybindingHandler.tsx +6 -6
  178. package/tui/src/components/Spinner/types.ts +6 -28
  179. package/tui/src/components/Spinner.tsx +2 -2
  180. package/tui/src/components/agents/generateAgent.ts +1 -1
  181. package/tui/src/components/agents/new-agent-creation/types.ts +4 -26
  182. package/tui/src/components/config/EnvSecretIsolatedEditor.tsx +1 -1
  183. package/tui/src/components/design-system/LoadingState.tsx +2 -2
  184. package/tui/src/components/mcp/types.ts +16 -38
  185. package/tui/src/components/messages/AssistantToolUseMessage.tsx +3 -2
  186. package/tui/src/components/messages/UserCrossSessionMessage.ts +16 -4
  187. package/tui/src/components/messages/UserForkBoilerplateMessage.ts +16 -4
  188. package/tui/src/components/messages/UserGitHubWebhookMessage.ts +16 -4
  189. package/tui/src/components/messages/UserToolResultMessage/utils.tsx +3 -2
  190. package/tui/src/components/permissions/MonitorPermissionRequest/MonitorPermissionRequest.ts +9 -4
  191. package/tui/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.ts +9 -4
  192. package/tui/src/components/primitive/DocumentSocraticReviewBlock.tsx +129 -0
  193. package/tui/src/components/primitive/DocumentToolResultCard.tsx +224 -0
  194. package/tui/src/components/primitive/documentSocraticReview.ts +215 -0
  195. package/tui/src/components/primitive/index.tsx +43 -1
  196. package/tui/src/components/primitive/types.ts +137 -0
  197. package/tui/src/components/ui/option.ts +4 -26
  198. package/tui/src/constants/common.ts +0 -2
  199. package/tui/src/constants/prompts.ts +4 -3
  200. package/tui/src/constants/querySource.ts +4 -26
  201. package/tui/src/entrypoints/sdk/controlTypes.ts +26 -48
  202. package/tui/src/entrypoints/sdk/coreTypes.generated.ts +3 -25
  203. package/tui/src/entrypoints/sdk/runtimeTypes.ts +38 -60
  204. package/tui/src/entrypoints/sdk/sdkUtilityTypes.ts +4 -26
  205. package/tui/src/entrypoints/sdk/settingsTypes.generated.ts +3 -25
  206. package/tui/src/entrypoints/sdk/toolTypes.ts +3 -25
  207. package/tui/src/hooks/toolPermission/handlers/interactiveHandler.ts +10 -0
  208. package/tui/src/hooks/useApiKeyVerification.ts +1 -1
  209. package/tui/src/hooks/useVirtualScroll.ts +1 -1
  210. package/tui/src/ink/ink.tsx +33 -14
  211. package/tui/src/ink/reconciler.ts +2 -3
  212. package/tui/src/ink/render-to-screen.ts +30 -10
  213. package/tui/src/ipc/bridge.ts +62 -15
  214. package/tui/src/ipc/bridgeSingleton.ts +5 -1
  215. package/tui/src/ipc/codec.ts +29 -3
  216. package/tui/src/ipc/frames.generated.ts +407 -312
  217. package/tui/src/ipc/llmClient.ts +279 -76
  218. package/tui/src/ipc/llmTypes.ts +16 -1
  219. package/tui/src/ipc/schema/frame.schema.json +1 -3475
  220. package/tui/src/keybindings/defaultBindings.ts +4 -0
  221. package/tui/src/main.tsx +32 -11
  222. package/tui/src/native-ts/file-index/index.ts +33 -3
  223. package/tui/src/observability/surface.ts +2 -2
  224. package/tui/src/probes/toolRegistryProbe.tsx +3 -1
  225. package/tui/src/projectOnboardingState.ts +7 -6
  226. package/tui/src/query/chatMessageTypes.ts +18 -0
  227. package/tui/src/query/chatMessagesBuilder.ts +1 -1
  228. package/tui/src/query/deps.ts +1 -1
  229. package/tui/src/query/messageGuards.ts +106 -0
  230. package/tui/src/query/publicDataTerminalRepair.ts +384 -0
  231. package/tui/src/query/run.ts +1075 -0
  232. package/tui/src/query/supportBoundary.ts +168 -0
  233. package/tui/src/query/toolResultErrors.ts +103 -0
  234. package/tui/src/query/toolRunner.ts +687 -0
  235. package/tui/src/query/unavailableToolRepair.ts +118 -0
  236. package/tui/src/query.ts +9 -1721
  237. package/tui/src/screens/REPL.tsx +42 -31
  238. package/tui/src/services/api/adapterManifest.ts +4 -0
  239. package/tui/src/services/api/backendChat/events.ts +117 -0
  240. package/tui/src/services/api/backendChat/finalMessage.ts +40 -0
  241. package/tui/src/services/api/backendChat/frame.ts +9 -0
  242. package/tui/src/services/api/backendChat/streaming.ts +430 -0
  243. package/tui/src/services/api/backendChat/types.ts +62 -0
  244. package/tui/src/services/api/backendChat.ts +1 -0
  245. package/tui/src/services/api/client.ts +98 -14
  246. package/tui/src/services/api/errorUtils.ts +5 -5
  247. package/tui/src/services/api/errors.ts +1 -1
  248. package/tui/src/services/api/logging.ts +1 -1
  249. package/tui/src/services/api/ummaya/evidence.ts +194 -0
  250. package/tui/src/services/api/ummaya/messages.ts +255 -0
  251. package/tui/src/services/api/ummaya/nonStreaming.ts +66 -0
  252. package/tui/src/services/api/ummaya/provider.ts +200 -0
  253. package/tui/src/services/api/ummaya/reasoning.ts +24 -0
  254. package/tui/src/services/api/ummaya/request.ts +200 -0
  255. package/tui/src/services/api/ummaya/selectionContext.ts +240 -0
  256. package/tui/src/services/api/ummaya/streaming.ts +365 -0
  257. package/tui/src/services/api/ummaya/streamingPayload.ts +129 -0
  258. package/tui/src/services/api/ummaya/streamingReader.ts +40 -0
  259. package/tui/src/services/api/ummaya/toolSelection.ts +217 -0
  260. package/tui/src/services/api/ummaya/types.ts +110 -0
  261. package/tui/src/services/api/ummaya/usage.ts +30 -0
  262. package/tui/src/services/api/ummaya.ts +26 -364
  263. package/tui/src/services/api/withRetry.ts +1 -1
  264. package/tui/src/services/awaySummary.ts +2 -2
  265. package/tui/src/services/claudeAiLimits.ts +1 -1
  266. package/tui/src/services/compact/autoCompact.ts +1 -1
  267. package/tui/src/services/compact/compact.ts +1 -1
  268. package/tui/src/services/lsp/types.ts +8 -30
  269. package/tui/src/services/tips/types.ts +6 -28
  270. package/tui/src/services/tokenEstimation.ts +1 -1
  271. package/tui/src/services/toolRegistry/bootGuard.ts +5 -5
  272. package/tui/src/services/toolUseSummary/toolUseSummaryGenerator.ts +1 -1
  273. package/tui/src/services/tools/toolExecution.ts +94 -1
  274. package/tui/src/skills/bundled/stuck.ts +12 -12
  275. package/tui/src/state/AppStateStore.ts +7 -0
  276. package/tui/src/store/pendingPermissionSlot.ts +1 -1
  277. package/tui/src/store/session-store.ts +10 -36
  278. package/tui/src/stubs/any-stub.ts +15 -10
  279. package/tui/src/stubs/color-diff-napi.ts +37 -23
  280. package/tui/src/stubs/globals.d.ts +3 -3
  281. package/tui/src/stubs/macro-preload.ts +23 -12
  282. package/tui/src/tools/AdapterTool/AdapterTool.ts +1239 -163
  283. package/tui/src/tools/AdapterTool/routeDiagnostics.ts +75 -0
  284. package/tui/src/tools/AgentTool/AgentTool.tsx +84 -1371
  285. package/tui/src/tools/AgentTool/agentToolHandoff.ts +114 -0
  286. package/tui/src/tools/AgentTool/agentToolPartialResult.ts +16 -0
  287. package/tui/src/tools/AgentTool/agentToolProgress.ts +32 -0
  288. package/tui/src/tools/AgentTool/agentToolResolver.ts +161 -0
  289. package/tui/src/tools/AgentTool/agentToolResult.ts +163 -0
  290. package/tui/src/tools/AgentTool/agentToolUtils.ts +14 -686
  291. package/tui/src/tools/AgentTool/asyncAgentLifecycle.ts +208 -0
  292. package/tui/src/tools/AgentTool/asyncLifecycle.ts +153 -0
  293. package/tui/src/tools/AgentTool/backgroundedCompletion.ts +126 -0
  294. package/tui/src/tools/AgentTool/backgroundedLifecycle.ts +174 -0
  295. package/tui/src/tools/AgentTool/foregroundBackground.ts +83 -0
  296. package/tui/src/tools/AgentTool/foregroundDrain.tsx +133 -0
  297. package/tui/src/tools/AgentTool/foregroundFinalize.ts +98 -0
  298. package/tui/src/tools/AgentTool/foregroundLifecycle.tsx +237 -0
  299. package/tui/src/tools/AgentTool/foregroundProgress.tsx +169 -0
  300. package/tui/src/tools/AgentTool/foregroundTask.ts +89 -0
  301. package/tui/src/tools/AgentTool/forkSubagent.ts +1 -12
  302. package/tui/src/tools/AgentTool/forkSubagentGate.ts +34 -0
  303. package/tui/src/tools/AgentTool/launchRouting.ts +203 -0
  304. package/tui/src/tools/AgentTool/lifecycle.ts +244 -0
  305. package/tui/src/tools/AgentTool/mcpRouting.ts +73 -0
  306. package/tui/src/tools/AgentTool/orchestrationSupport.ts +70 -0
  307. package/tui/src/tools/AgentTool/permissions.ts +39 -0
  308. package/tui/src/tools/AgentTool/promptSetup.ts +181 -0
  309. package/tui/src/tools/AgentTool/remoteRouting.ts +62 -0
  310. package/tui/src/tools/AgentTool/resultMapping.ts +116 -0
  311. package/tui/src/tools/AgentTool/resumeAgent.ts +39 -107
  312. package/tui/src/tools/AgentTool/resumeAgentHelpers.ts +140 -0
  313. package/tui/src/tools/AgentTool/runAgent.ts +1 -1
  314. package/tui/src/tools/AgentTool/runtimeConfig.ts +57 -0
  315. package/tui/src/tools/AgentTool/schemas.ts +196 -0
  316. package/tui/src/tools/AgentTool/sourceVerificationPropagation.ts +263 -0
  317. package/tui/src/tools/AgentTool/worktreeLifecycle.ts +105 -0
  318. package/tui/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +174 -202
  319. package/tui/src/tools/BashTool/BashTool.tsx +71 -1072
  320. package/tui/src/tools/BashTool/bashCommandHelpers.ts +12 -12
  321. package/tui/src/tools/BashTool/bashPermissions/astPreflight.ts +173 -0
  322. package/tui/src/tools/BashTool/bashPermissions/classifierChecks.ts +199 -0
  323. package/tui/src/tools/BashTool/bashPermissions/compoundGuards.ts +53 -0
  324. package/tui/src/tools/BashTool/bashPermissions/constants.ts +99 -0
  325. package/tui/src/tools/BashTool/bashPermissions/index.ts +38 -0
  326. package/tui/src/tools/BashTool/bashPermissions/legacyMisparsing.ts +62 -0
  327. package/tui/src/tools/BashTool/bashPermissions/main.ts +135 -0
  328. package/tui/src/tools/BashTool/bashPermissions/normalizedCommands.ts +33 -0
  329. package/tui/src/tools/BashTool/bashPermissions/operatorFlow.ts +98 -0
  330. package/tui/src/tools/BashTool/bashPermissions/permissionChecks.ts +200 -0
  331. package/tui/src/tools/BashTool/bashPermissions/prefixSuggestions.ts +88 -0
  332. package/tui/src/tools/BashTool/bashPermissions/promptClassifierRules.ts +125 -0
  333. package/tui/src/tools/BashTool/bashPermissions/ruleDelegates.ts +19 -0
  334. package/tui/src/tools/BashTool/bashPermissions/ruleMatching.ts +145 -0
  335. package/tui/src/tools/BashTool/bashPermissions/sandboxAutoAllow.ts +75 -0
  336. package/tui/src/tools/BashTool/bashPermissions/subcommandFlow.ts +205 -0
  337. package/tui/src/tools/BashTool/bashPermissions/subcommandGuards.ts +73 -0
  338. package/tui/src/tools/BashTool/bashPermissions/subcommandResultHelpers.ts +116 -0
  339. package/tui/src/tools/BashTool/bashPermissions/types.ts +26 -0
  340. package/tui/src/tools/BashTool/bashPermissions/wrapperStripping.ts +139 -0
  341. package/tui/src/tools/BashTool/bashPermissions.ts +26 -2621
  342. package/tui/src/tools/BashTool/call.ts +202 -0
  343. package/tui/src/tools/BashTool/callLoader.ts +35 -0
  344. package/tui/src/tools/BashTool/commandClassification.ts +151 -0
  345. package/tui/src/tools/BashTool/commandClassificationLoader.ts +40 -0
  346. package/tui/src/tools/BashTool/cwdReset.ts +33 -0
  347. package/tui/src/tools/BashTool/lineTruncation.ts +11 -0
  348. package/tui/src/tools/BashTool/modeValidation.ts +13 -1
  349. package/tui/src/tools/BashTool/outputPersistence.ts +42 -0
  350. package/tui/src/tools/BashTool/permissionClassification.ts +66 -0
  351. package/tui/src/tools/BashTool/permissionLoader.ts +44 -0
  352. package/tui/src/tools/BashTool/resultLoader.ts +29 -0
  353. package/tui/src/tools/BashTool/resultMapping.ts +83 -0
  354. package/tui/src/tools/BashTool/sandboxPolicy.ts +79 -0
  355. package/tui/src/tools/BashTool/schemas.ts +65 -0
  356. package/tui/src/tools/BashTool/sedEditExecution.ts +59 -0
  357. package/tui/src/tools/BashTool/shellExecution.tsx +245 -0
  358. package/tui/src/tools/BashTool/shellOutputUtils.ts +85 -0
  359. package/tui/src/tools/BashTool/shellPermissionGauntlet.ts +97 -0
  360. package/tui/src/tools/BashTool/uiLoader.ts +37 -0
  361. package/tui/src/tools/BriefTool/upload.ts +1 -1
  362. package/tui/src/tools/CalculatorTool/parser.ts +2 -2
  363. package/tui/src/tools/DocumentPrimitive/DocumentPrimitive.ts +262 -0
  364. package/tui/src/tools/DocumentPrimitive/dispatchNormalization.ts +270 -0
  365. package/tui/src/tools/DocumentPrimitive/documentDestinationPath.ts +18 -0
  366. package/tui/src/tools/DocumentPrimitive/documentMutationGuard.ts +22 -0
  367. package/tui/src/tools/DocumentPrimitive/documentPatchNormalization.ts +248 -0
  368. package/tui/src/tools/DocumentPrimitive/documentSourceVerification.ts +245 -0
  369. package/tui/src/tools/DocumentPrimitive/documentSourceVerificationFields.ts +103 -0
  370. package/tui/src/tools/DocumentPrimitive/modelVisibleOutput.ts +40 -0
  371. package/tui/src/tools/DocumentPrimitive/prompt.ts +35 -0
  372. package/tui/src/tools/FileEditTool/FileEditTool.ts +9 -507
  373. package/tui/src/tools/FileEditTool/call.ts +228 -0
  374. package/tui/src/tools/FileEditTool/validateInput.ts +196 -0
  375. package/tui/src/tools/FileReadTool/imageProcessor.ts +13 -0
  376. package/tui/src/tools/FileWriteTool/FileWriteTool.ts +7 -300
  377. package/tui/src/tools/FileWriteTool/call.ts +223 -0
  378. package/tui/src/tools/FileWriteTool/validateInput.ts +80 -0
  379. package/tui/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +19 -3
  380. package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +48 -29
  381. package/tui/src/tools/LookupPrimitive/prompt.ts +6 -7
  382. package/tui/src/tools/MCPTool/trustPolicy.ts +118 -0
  383. package/tui/src/tools/McpAuthTool/McpAuthTool.ts +21 -3
  384. package/tui/src/tools/NotebookEditTool/NotebookEditTool.ts +7 -326
  385. package/tui/src/tools/NotebookEditTool/call.ts +254 -0
  386. package/tui/src/tools/NotebookEditTool/notebookModel.ts +51 -0
  387. package/tui/src/tools/NotebookEditTool/validateInput.ts +142 -0
  388. package/tui/src/tools/PowerShellTool/PowerShellTool.tsx +46 -937
  389. package/tui/src/tools/PowerShellTool/acceptEditsCommandValidation.ts +162 -0
  390. package/tui/src/tools/PowerShellTool/call.ts +179 -0
  391. package/tui/src/tools/PowerShellTool/callLoader.ts +37 -0
  392. package/tui/src/tools/PowerShellTool/commandClassification.ts +86 -0
  393. package/tui/src/tools/PowerShellTool/modeValidation.ts +25 -332
  394. package/tui/src/tools/PowerShellTool/outputPersistence.ts +42 -0
  395. package/tui/src/tools/PowerShellTool/permissionClassification.ts +28 -0
  396. package/tui/src/tools/PowerShellTool/resultLoader.ts +31 -0
  397. package/tui/src/tools/PowerShellTool/resultMapping.ts +75 -0
  398. package/tui/src/tools/PowerShellTool/schemas.ts +40 -0
  399. package/tui/src/tools/PowerShellTool/shellExecution.tsx +258 -0
  400. package/tui/src/tools/PowerShellTool/symlinkModeValidation.ts +44 -0
  401. package/tui/src/tools/PowerShellTool/uiLoader.ts +37 -0
  402. package/tui/src/tools/PowerShellTool/validation.ts +39 -0
  403. package/tui/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +19 -3
  404. package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +30 -19
  405. package/tui/src/tools/ResolveLocationPrimitive/prompt.ts +2 -6
  406. package/tui/src/tools/SkillTool/SkillTool.ts +2 -2
  407. package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +51 -18
  408. package/tui/src/tools/TaskCreateTool/TaskCreateTool.ts +16 -2
  409. package/tui/src/tools/TaskGetTool/TaskGetTool.ts +23 -3
  410. package/tui/src/tools/TaskListTool/TaskListTool.ts +22 -4
  411. package/tui/src/tools/TaskOutputTool/TaskOutputTool.tsx +46 -547
  412. package/tui/src/tools/TaskOutputTool/lookup.ts +216 -0
  413. package/tui/src/tools/TaskOutputTool/render.tsx +257 -0
  414. package/tui/src/tools/TaskOutputTool/schemas.ts +55 -0
  415. package/tui/src/tools/TaskOutputTool/serialization.ts +36 -0
  416. package/tui/src/tools/TaskStopTool/TaskStopTool.ts +10 -0
  417. package/tui/src/tools/TaskUpdateTool/TaskUpdateTool.ts +14 -364
  418. package/tui/src/tools/TaskUpdateTool/completion.ts +62 -0
  419. package/tui/src/tools/TaskUpdateTool/schemas.ts +62 -0
  420. package/tui/src/tools/TaskUpdateTool/serialization.ts +46 -0
  421. package/tui/src/tools/TaskUpdateTool/statusUpdate.ts +247 -0
  422. package/tui/src/tools/TodoWriteTool/TodoWriteTool.ts +21 -2
  423. package/tui/src/tools/ToolSearchTool/ToolSearchTool.ts +21 -302
  424. package/tui/src/tools/ToolSearchTool/ccSupportTools.ts +223 -0
  425. package/tui/src/tools/ToolSearchTool/descriptionCache.ts +50 -0
  426. package/tui/src/tools/ToolSearchTool/keywordSearch.ts +216 -0
  427. package/tui/src/tools/ToolSearchTool/prompt.ts +10 -4
  428. package/tui/src/tools/ToolSearchTool/resultMapping.ts +30 -0
  429. package/tui/src/tools/ToolSearchTool/schemas.ts +30 -0
  430. package/tui/src/tools/ToolSearchTool/searchPool.ts +47 -0
  431. package/tui/src/tools/ToolSearchTool/supportIntentHints.ts +140 -0
  432. package/tui/src/tools/TranslateTool/TranslateTool.ts +1 -1
  433. package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +27 -10
  434. package/tui/src/tools/WebFetchTool/WebFetchTool.ts +43 -138
  435. package/tui/src/tools/WebFetchTool/call.ts +227 -0
  436. package/tui/src/tools/WebFetchTool/resolvedAddressSafety.ts +78 -0
  437. package/tui/src/tools/WebFetchTool/sourceVerification.ts +204 -0
  438. package/tui/src/tools/WebFetchTool/types.ts +23 -0
  439. package/tui/src/tools/WebFetchTool/urlSafety.ts +181 -0
  440. package/tui/src/tools/WebFetchTool/utils.ts +1 -1
  441. package/tui/src/tools/WebSearchTool/UI.tsx +0 -1
  442. package/tui/src/tools/WebSearchTool/WebSearchTool.ts +9 -313
  443. package/tui/src/tools/WebSearchTool/call.ts +33 -0
  444. package/tui/src/tools/WebSearchTool/responseMapping.ts +190 -0
  445. package/tui/src/tools/WebSearchTool/resultBlock.ts +47 -0
  446. package/tui/src/tools/WebSearchTool/schemas.ts +47 -0
  447. package/tui/src/tools/WebSearchTool/toolSchema.ts +12 -0
  448. package/tui/src/tools/WorkspaceToolAdapter/WorkspaceToolAdapter.ts +79 -0
  449. package/tui/src/tools/WorkspaceToolAdapter/allowedRootPolicy.ts +85 -0
  450. package/tui/src/tools/WorkspaceToolAdapter/documentFormatGuards.ts +73 -0
  451. package/tui/src/tools/WorkspaceToolAdapter/inputNormalization.ts +105 -0
  452. package/tui/src/tools/WorkspaceToolAdapter/mcpExposurePolicy.ts +64 -0
  453. package/tui/src/tools/WorkspaceToolAdapter/toolDefFactory.ts +215 -0
  454. package/tui/src/tools/WorkspaceToolAdapter/toolNames.ts +6 -0
  455. package/tui/src/tools/WorkspaceToolAdapter/workspacePolicy.ts +15 -0
  456. package/tui/src/tools/_shared/citizenUserText.ts +49 -0
  457. package/tui/src/tools/_shared/dispatchPrimitive.ts +6 -6
  458. package/tui/src/tools/_shared/documentChangeToPatch.ts +125 -0
  459. package/tui/src/tools/_shared/documentDispatchArguments.ts +87 -0
  460. package/tui/src/tools/_shared/documentPrimitiveTimeout.ts +13 -0
  461. package/tui/src/tools/_shared/documentToolResultRender.ts +98 -0
  462. package/tui/src/tools/_shared/locationInputRepair.ts +112 -0
  463. package/tui/src/tools/_shared/pendingCallRegistry.ts +1 -6
  464. package/tui/src/tools/_shared/rootPrimitiveInput.ts +68 -0
  465. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPatterns.ts +58 -0
  466. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPrompt.ts +271 -0
  467. package/tui/src/tools/_shared/toolChoiceRepair/documentRepair.ts +452 -0
  468. package/tui/src/tools/_shared/toolChoiceRepair/messageAccess.ts +80 -0
  469. package/tui/src/tools/_shared/toolChoiceRepair/publicDataRepair.ts +92 -0
  470. package/tui/src/tools/_shared/toolChoiceRepair/supportRepair.ts +135 -0
  471. package/tui/src/tools/_shared/toolChoiceRepair.ts +61 -0
  472. package/tui/src/tools/shared/mockDisclaimer.ts +1 -1
  473. package/tui/src/tools.ts +39 -190
  474. package/tui/src/types/fileSuggestion.ts +4 -26
  475. package/tui/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +186 -148
  476. package/tui/src/types/generated/events_mono/common/v1/auth.ts +25 -11
  477. package/tui/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +47 -30
  478. package/tui/src/types/generated/google/protobuf/timestamp.ts +21 -7
  479. package/tui/src/types/message.ts +80 -102
  480. package/tui/src/types/messageQueueTypes.ts +6 -28
  481. package/tui/src/types/notebook.ts +16 -38
  482. package/tui/src/types/statusLine.ts +4 -26
  483. package/tui/src/types/tools.ts +24 -46
  484. package/tui/src/types/utils.ts +6 -28
  485. package/tui/src/upstreamproxy/relay.ts +7 -3
  486. package/tui/src/upstreamproxy/upstreamproxy.ts +1 -1
  487. package/tui/src/utils/assistantMessageFactories.ts +9 -3
  488. package/tui/src/utils/attachments.ts +1 -1
  489. package/tui/src/utils/auth.ts +129 -139
  490. package/tui/src/utils/bash/ast.ts +23 -23
  491. package/tui/src/utils/bash/bashParser.ts +5 -5
  492. package/tui/src/utils/billing.ts +1 -1
  493. package/tui/src/utils/collapseReadSearch.ts +3 -3
  494. package/tui/src/utils/cronTasks.ts +1 -1
  495. package/tui/src/utils/execFileNoThrow.ts +1 -1
  496. package/tui/src/utils/filePersistence/types.ts +16 -38
  497. package/tui/src/utils/forkedAgent.ts +1 -1
  498. package/tui/src/utils/gracefulShutdown.ts +4 -4
  499. package/tui/src/utils/heapDumpService.ts +12 -8
  500. package/tui/src/utils/hooks/apiQueryHookHelper.ts +1 -1
  501. package/tui/src/utils/hooks/execPromptHook.ts +1 -1
  502. package/tui/src/utils/hooks/skillImprovement.ts +1 -1
  503. package/tui/src/utils/kExaoneReasoning.ts +138 -0
  504. package/tui/src/utils/mcp/dateTimeParser.ts +1 -1
  505. package/tui/src/utils/messages.ts +19 -0
  506. package/tui/src/utils/migrateSessions.ts +3 -3
  507. package/tui/src/utils/model/model.ts +6 -6
  508. package/tui/src/utils/multiToolLayout.ts +13 -0
  509. package/tui/src/utils/permissions/yoloClassifier.ts +1 -1
  510. package/tui/src/utils/plugins/headlessPluginInstall.ts +1 -1
  511. package/tui/src/utils/plugins/mcpPluginIntegration.ts +1 -1
  512. package/tui/src/utils/plugins/mcpbHandler.ts +1 -1
  513. package/tui/src/utils/plugins/pluginLoader.ts +8 -8
  514. package/tui/src/utils/processUserInput/processSlashCommand.tsx +2 -2
  515. package/tui/src/utils/processUserInput/processUserInput.ts +26 -0
  516. package/tui/src/utils/protectedNamespace.ts +5 -3
  517. package/tui/src/utils/rawJsonToolCall.ts +242 -0
  518. package/tui/src/utils/ripgrep.ts +16 -7
  519. package/tui/src/utils/sessionTitle.ts +1 -1
  520. package/tui/src/utils/settings/applySettingsChange.ts +4 -0
  521. package/tui/src/utils/settings/permissionValidation.ts +14 -2
  522. package/tui/src/utils/settings/types.ts +9 -3
  523. package/tui/src/utils/shell/prefix.ts +1 -1
  524. package/tui/src/utils/sideQuery.ts +1 -1
  525. package/tui/src/utils/stats.ts +1 -1
  526. package/tui/src/utils/systemThemeWatcher.ts +13 -3
  527. package/tui/src/utils/teleport.tsx +1 -1
  528. package/uv.lock +394 -22
  529. package/assets/copilot-gate-logo.svg +0 -58
  530. package/assets/govon-logo.svg +0 -40
  531. package/src/ummaya/eval/__init__.py +0 -5
  532. package/src/ummaya/eval/retrieval.py +0 -713
  533. package/tui/src/services/api/claude.ts +0 -3510
  534. package/tui/src/utils/messageStream.ts +0 -186
@@ -0,0 +1,1075 @@
1
+ import type { QueryParams, QueryGenerator } from '../query.js'
2
+ import type { AssistantMessage, Message } from '../types/message.js'
3
+ import { productionDeps } from './deps.js'
4
+ import { Terminal } from './transitions.js'
5
+ import { enforceSupportToolBoundary } from './supportBoundary.js'
6
+ import {
7
+ buildPublicDataTerminalRepairPrompt,
8
+ buildStalePriorToolResultFinalAnswerBlockedText,
9
+ buildUnsupportedRouteFinalAnswerBlockedText,
10
+ buildUnavailableToolFinalAnswerBlockedText,
11
+ shouldBlockStalePriorToolResultAnswer,
12
+ shouldBlockFinalAnswerAfterUnsupportedRouteRepair,
13
+ shouldBlockFinalAnswerAfterUnavailableToolRepair,
14
+ shouldBlockUnsupportedRouteDetailAnswer,
15
+ } from './publicDataTerminalRepair.js'
16
+ import {
17
+ contentBlocks,
18
+ isAssistantMessage,
19
+ isUserMessage,
20
+ latestTextUserMessageIndex,
21
+ messageText,
22
+ toolUseBlocks,
23
+ type ToolUseBlock,
24
+ } from './messageGuards.js'
25
+ import { runToolUseBlocks } from './toolRunner.js'
26
+ import {
27
+ buildDocumentCompletionPromptIfNeeded,
28
+ selectRecoveredDocumentToolChoiceNameForMessages,
29
+ selectRecoveredSupportToolChoiceNameForMessages,
30
+ } from '../tools/_shared/toolChoiceRepair.js'
31
+ import {
32
+ extractTextualToolCallProposals,
33
+ parseTrailingRawJsonToolCallProposal,
34
+ textContainsToolCallProposal,
35
+ textContainsMalformedToolCallProposal,
36
+ } from '../utils/rawJsonToolCall.js'
37
+ import {
38
+ buildGenericPendingFinalAnswerToolUseBlockedText,
39
+ shouldBlockToolUseAfterGenericPendingFinalAnswerRepair,
40
+ } from '../tools/_shared/toolChoiceRepair/publicDataRepair.js'
41
+ import {
42
+ parseToolUnavailableError,
43
+ } from './toolResultErrors.js'
44
+ import {
45
+ appendRouteDiagnostic,
46
+ hashRouteDiagnosticText,
47
+ } from '../tools/AdapterTool/routeDiagnostics.js'
48
+ import { createAssistantMessage, createUserMessage } from '../utils/messages.js'
49
+
50
+ const ROOT_FIND_TOOL_NAME = 'find'
51
+ const ROOT_PRIMITIVE_TOOL_NAMES = new Set([
52
+ 'find',
53
+ 'locate',
54
+ 'check',
55
+ 'send',
56
+ 'document',
57
+ ])
58
+ const KAKAO_LOCATION_TOOL_NAMES = new Set([
59
+ 'kakao_address_search',
60
+ 'kakao_keyword_search',
61
+ ])
62
+ const KMA_METAR_TOOL_NAME = 'kma_apihub_url_air_metar_decoded'
63
+ const KMA_ORDINARY_WEATHER_TOOL_NAMES = new Set([
64
+ 'kma_apihub_upp_mtly_info_service_get_max_wind',
65
+ 'kma_current_observation',
66
+ 'kma_forecast_fetch',
67
+ 'kma_short_term_forecast',
68
+ 'kma_ultra_short_term_forecast',
69
+ ])
70
+ const REGISTERED_EMERGENCY_RESULT_TOOL_NAMES = new Set([
71
+ 'nmc_emergency_search',
72
+ 'hira_hospital_search',
73
+ ])
74
+ let recoveredRawJsonToolUseSequence = 0
75
+ const PERMISSION_DENIED_TEXT_RE =
76
+ /(permission_denied|Authentication rejected|permission denied|인증이 거부)/iu
77
+ const ADAPTERLESS_FIND_TEXT_RE =
78
+ /find\(mode='fetch'\) requires a concrete adapter tool_id|No concrete adapter was selected|requires a concrete adapter tool_id|Missing or invalid fields:\s*tool_id/iu
79
+ const PROMPT_INJECTION_USER_RE =
80
+ /(이전\s*지시.*무시|모든\s*지시.*무시|ignore\s+(?:all\s+)?(?:previous|prior|system)\s+instructions|시스템\s*프롬프트|system\s+prompt|토큰|token|secret|credential|api[_\s-]?key|도구를\s*(?:이렇게\s*)?(?:직접\s*)?실행|execute\s+(?:this\s+)?tool|run\s+(?:this\s+)?tool|call\s+(?:this\s+)?tool)/iu
81
+ const SENSITIVE_DISCLOSURE_ACK_RE =
82
+ /(시스템\s*프롬프트.*(출력|공개)|토큰.*(출력|공개)|system\s+prompt.*(?:print|show|reveal)|token.*(?:print|show|reveal)|secret.*(?:print|show|reveal)|도구를.*(?:직접\s*)?실행|execute\s+(?:the\s+)?tool|run\s+(?:the\s+)?tool)/iu
83
+ const EMERGENCY_RESULT_REQUEST_RE =
84
+ /(응급|응급실|야간\s*진료|야간진료|병원|의료|emergency|hospital|\bER\b)/iu
85
+ const EMERGENCY_FACILITY_CLAIM_RE =
86
+ /[가-힣A-Za-z0-9·()]{1,24}(?:병원|의료원|응급의료센터|응급센터|응급실)/u
87
+ const EMERGENCY_STATUS_OR_DISTANCE_CLAIM_RE =
88
+ /(?:\d+(?:\.\d+)?\s*(?:km|킬로미터|m|미터)|병상|가용|진료\s*가능|운영\s*중|24\s*시간|대기\s*시간)/iu
89
+ const EMERGENCY_SEARCH_SUCCESS_CLAIM_RE =
90
+ /(?:응급실|응급의료|병원)[^\n.。]*(?:검색|조회|확인|찾았|추천|결과)|(?:검색|조회)\s*결과[^\n.。]*(?:응급실|응급의료|병원)/iu
91
+ const EMERGENCY_SAFE_LIMITATION_RE =
92
+ /(결과\s*없이|없이는|단정하지|조회하지\s*못|확인하지\s*못|연결된\s*뒤|adapter|handoff|공식\s*(?:채널|응급의료)|119)/iu
93
+ type ToolResultBlock = {
94
+ readonly type: 'tool_result'
95
+ readonly tool_use_id: string
96
+ readonly content?: unknown
97
+ readonly is_error?: boolean
98
+ }
99
+
100
+ function toolResultBlocks(message: Message): readonly ToolResultBlock[] {
101
+ return contentBlocks(message).filter(
102
+ (block): block is ToolResultBlock =>
103
+ block.type === 'tool_result' &&
104
+ 'tool_use_id' in block &&
105
+ typeof block.tool_use_id === 'string',
106
+ )
107
+ }
108
+
109
+ function ccStyleUnavailableToolResultContent(content: unknown): string | undefined {
110
+ const unavailable = parseToolUnavailableError(content)
111
+ if (unavailable === undefined) return undefined
112
+ const toolName = unavailable.error.tool_name
113
+ return JSON.stringify({
114
+ ...unavailable,
115
+ error: {
116
+ ...unavailable.error,
117
+ message: `Tool ${toolName} is unavailable.`,
118
+ },
119
+ })
120
+ }
121
+
122
+ function upgradeUnavailableToolResultMessage(message: Message): Message {
123
+ if (!isUserMessage(message) || !Array.isArray(message.message.content)) {
124
+ return message
125
+ }
126
+ let changed = false
127
+ const content = message.message.content.map(block => {
128
+ if (
129
+ typeof block !== 'object' ||
130
+ block === null ||
131
+ !('type' in block) ||
132
+ block.type !== 'tool_result' ||
133
+ !('content' in block)
134
+ ) {
135
+ return block
136
+ }
137
+ const upgradedContent = ccStyleUnavailableToolResultContent(block.content)
138
+ if (upgradedContent === undefined || upgradedContent === block.content) {
139
+ return block
140
+ }
141
+ changed = true
142
+ return { ...block, content: upgradedContent }
143
+ })
144
+ return changed
145
+ ? { ...message, message: { ...message.message, content } }
146
+ : message
147
+ }
148
+
149
+ function disabledProviderToolNamesForTurn(
150
+ messages: readonly Message[],
151
+ ): readonly string[] {
152
+ const disabled: string[] = []
153
+ disabled.push(...permissionDeniedToolNames(messages))
154
+ if (hasAdapterlessFindFailure(messages)) {
155
+ disabled.push(ROOT_FIND_TOOL_NAME)
156
+ }
157
+ return [...new Set(disabled)]
158
+ }
159
+
160
+ function contentText(value: unknown): string {
161
+ if (typeof value === 'string') return value
162
+ if (value === undefined || value === null) return ''
163
+ try {
164
+ return JSON.stringify(value)
165
+ } catch {
166
+ return String(value)
167
+ }
168
+ }
169
+
170
+ function parseJsonRecord(value: unknown): Record<string, unknown> | undefined {
171
+ if (isRecord(value)) return value
172
+ if (typeof value !== 'string') return undefined
173
+ try {
174
+ const parsed: unknown = JSON.parse(value)
175
+ return isRecord(parsed) ? parsed : undefined
176
+ } catch {
177
+ return undefined
178
+ }
179
+ }
180
+
181
+ function isStructuredFailureToolResult(value: unknown): boolean {
182
+ return parseJsonRecord(value)?.ok === false
183
+ }
184
+
185
+ function stripLeadingTemplateControlTokens(text: string): string {
186
+ return text.replace(/^\s*(?:<%+|%>+)\s*/u, '')
187
+ }
188
+
189
+ function sanitizeVisibleAssistantControlTokens(
190
+ message: AssistantMessage,
191
+ ): AssistantMessage {
192
+ const content = message.message.content
193
+ if (typeof content === 'string') {
194
+ const sanitized = stripLeadingTemplateControlTokens(content)
195
+ return sanitized === content
196
+ ? message
197
+ : { ...message, message: { ...message.message, content: sanitized } }
198
+ }
199
+ if (!Array.isArray(content)) return message
200
+ let changed = false
201
+ const sanitizedContent = content.map(block => {
202
+ if (!isRecord(block) || block.type !== 'text' || typeof block.text !== 'string') {
203
+ return block
204
+ }
205
+ const sanitizedText = stripLeadingTemplateControlTokens(block.text)
206
+ if (sanitizedText === block.text) return block
207
+ changed = true
208
+ return { ...block, text: sanitizedText }
209
+ })
210
+ return changed
211
+ ? { ...message, message: { ...message.message, content: sanitizedContent } }
212
+ : message
213
+ }
214
+
215
+ type PriorToolResult = {
216
+ readonly toolName: string
217
+ readonly content: unknown
218
+ readonly isError: boolean
219
+ }
220
+
221
+ function toolResultsSinceLatestPrompt(
222
+ messages: readonly Message[],
223
+ ): readonly PriorToolResult[] {
224
+ const latestUserIndex = latestTextUserMessageIndex(messages)
225
+ if (latestUserIndex < 0) return []
226
+ const toolNamesByUseId = new Map<string, string>()
227
+ const results: PriorToolResult[] = []
228
+ for (const message of messages.slice(latestUserIndex + 1)) {
229
+ if (isAssistantMessage(message)) {
230
+ for (const block of toolUseBlocks(message)) {
231
+ toolNamesByUseId.set(block.id, block.name)
232
+ }
233
+ continue
234
+ }
235
+ if (!isUserMessage(message)) continue
236
+ for (const block of toolResultBlocks(message)) {
237
+ const toolName = toolNamesByUseId.get(block.tool_use_id)
238
+ if (toolName === undefined) continue
239
+ results.push({
240
+ toolName,
241
+ content: block.content,
242
+ isError: block.is_error === true || isStructuredFailureToolResult(block.content),
243
+ })
244
+ }
245
+ }
246
+ return results
247
+ }
248
+
249
+ function systemPromptForTurn(
250
+ basePrompt: readonly string[],
251
+ messages: readonly Message[],
252
+ ): readonly string[] {
253
+ const priorResults = toolResultsSinceLatestPrompt(messages)
254
+ if (!priorResults.some(result => result.toolName === KMA_METAR_TOOL_NAME)) {
255
+ return basePrompt
256
+ }
257
+ return [
258
+ ...basePrompt,
259
+ [
260
+ 'KMA aviation weather boundary: prior decoded METAR evidence exists for this airport-flight request.',
261
+ 'Do not ask the user for KMA nx/ny grid coordinates.',
262
+ 'Do not call ordinary KMA current or forecast tools as a fallback for airport aviation weather.',
263
+ 'Answer from the aviation evidence or hand off to official airline/airport status channels.',
264
+ ].join(' '),
265
+ ]
266
+ }
267
+
268
+ function hasConcreteFindToolId(input: Record<string, unknown>): boolean {
269
+ const toolId = input.tool_id
270
+ return typeof toolId === 'string' &&
271
+ toolId.trim().length > 0 &&
272
+ !ROOT_PRIMITIVE_TOOL_NAMES.has(toolId)
273
+ }
274
+
275
+ function isAdapterlessFindToolUse(block: ToolUseBlock): boolean {
276
+ return block.name === ROOT_FIND_TOOL_NAME && !hasConcreteFindToolId(block.input)
277
+ }
278
+
279
+ function isRecord(value: unknown): value is Record<string, unknown> {
280
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
281
+ }
282
+
283
+ function createRecoveredRawJsonToolUseId(baseUuid: string): string {
284
+ recoveredRawJsonToolUseSequence += 1
285
+ return `toolu-raw-json-${baseUuid}-${recoveredRawJsonToolUseSequence}`
286
+ }
287
+
288
+ function upgradeRawJsonToolCallAssistant(params: {
289
+ readonly assistantMessage: AssistantMessage
290
+ readonly createToolUseId: () => string
291
+ }): AssistantMessage {
292
+ if (toolUseBlocks(params.assistantMessage).length > 0) {
293
+ return params.assistantMessage
294
+ }
295
+ const blocks = contentBlocks(params.assistantMessage)
296
+ const textualExtraction = extractTextualToolCallProposals({
297
+ text: messageText(params.assistantMessage),
298
+ })
299
+ if (textualExtraction !== undefined) {
300
+ const preservedBlocks = blocks.filter(block => block.type !== 'text')
301
+ const content = textualExtraction.text.length > 0
302
+ ? [
303
+ ...preservedBlocks,
304
+ { type: 'text' as const, text: textualExtraction.text },
305
+ ]
306
+ : preservedBlocks
307
+
308
+ return {
309
+ ...params.assistantMessage,
310
+ message: {
311
+ ...params.assistantMessage.message,
312
+ content: [
313
+ ...content,
314
+ ...textualExtraction.proposals.map(proposal => ({
315
+ type: 'tool_use' as const,
316
+ id: params.createToolUseId(),
317
+ name: proposal.name,
318
+ input: proposal.input,
319
+ })),
320
+ ],
321
+ },
322
+ }
323
+ }
324
+
325
+ const trailingProposal = parseTrailingRawJsonToolCallProposal({
326
+ text: messageText(params.assistantMessage),
327
+ })
328
+ if (trailingProposal === undefined) return params.assistantMessage
329
+
330
+ const preservedBlocks = blocks.filter(block => block.type !== 'text')
331
+ const content = trailingProposal.prelude.length > 0
332
+ ? [
333
+ ...preservedBlocks,
334
+ { type: 'text' as const, text: trailingProposal.prelude },
335
+ ]
336
+ : preservedBlocks
337
+
338
+ return {
339
+ ...params.assistantMessage,
340
+ message: {
341
+ ...params.assistantMessage.message,
342
+ content: [
343
+ ...content,
344
+ {
345
+ type: 'tool_use' as const,
346
+ id: params.createToolUseId(),
347
+ name: trailingProposal.proposal.name,
348
+ input: trailingProposal.proposal.input,
349
+ },
350
+ ],
351
+ },
352
+ }
353
+ }
354
+
355
+ function hasAdapterlessFindFailure(messages: readonly Message[]): boolean {
356
+ const latestUserIndex = latestTextUserMessageIndex(messages)
357
+ if (latestUserIndex < 0) return false
358
+ const toolNamesByUseId = new Map<string, string>()
359
+ for (let index = latestUserIndex + 1; index < messages.length; index += 1) {
360
+ const message = messages[index]
361
+ if (!message) continue
362
+ if (isAssistantMessage(message)) {
363
+ for (const block of toolUseBlocks(message)) {
364
+ toolNamesByUseId.set(block.id, block.name)
365
+ }
366
+ continue
367
+ }
368
+ if (!isUserMessage(message)) continue
369
+ for (const block of toolResultBlocks(message)) {
370
+ if (
371
+ toolNamesByUseId.get(block.tool_use_id) === ROOT_FIND_TOOL_NAME &&
372
+ ADAPTERLESS_FIND_TEXT_RE.test(contentText(block.content))
373
+ ) {
374
+ return true
375
+ }
376
+ }
377
+ }
378
+ return false
379
+ }
380
+
381
+ function shouldBlockRepeatedAdapterlessFind(
382
+ block: ToolUseBlock,
383
+ messages: readonly Message[],
384
+ ): boolean {
385
+ return isAdapterlessFindToolUse(block) && hasAdapterlessFindFailure(messages)
386
+ }
387
+
388
+ function createAdapterlessFindContinuationGuardResult(
389
+ block: ToolUseBlock,
390
+ assistantMessage: AssistantMessage,
391
+ ): Message {
392
+ const message = [
393
+ 'Root find wrapper already failed because no concrete adapter tool_id was selected.',
394
+ 'Do not call find again without tool_id in this citizen turn.',
395
+ 'Call a concrete loaded adapter directly when one is available; otherwise write a stable Korean final, needs-input, or handoff answer that names the missing adapter/credential limitation.',
396
+ ].join(' ')
397
+ return createUserMessage({
398
+ content: [
399
+ {
400
+ type: 'tool_result',
401
+ tool_use_id: block.id,
402
+ content: message,
403
+ is_error: true,
404
+ },
405
+ ],
406
+ toolUseResult: message,
407
+ sourceToolAssistantUUID: assistantMessage.uuid,
408
+ })
409
+ }
410
+
411
+ function createAdapterlessFindHardGuardFinalMessage(): AssistantMessage {
412
+ return createAssistantMessage({
413
+ content: [
414
+ '공공서비스 adapter가 선택되지 않아 이 시민 업무를 계속 진행할 수 없습니다.',
415
+ '로컬 파일/워크스페이스 결과는 이 시민 업무의 근거로 사용하지 않습니다.',
416
+ '요청하신 신청/조회/등록 업무는 공식 공공서비스 adapter와 필요한 인증/위임 credential이 연결된 뒤 이어서 처리해야 합니다. 지금은 공식 신청 채널 확인으로 handoff합니다.',
417
+ ].join('\n\n'),
418
+ })
419
+ }
420
+
421
+ function createPromptInjectionToolRecoveryBlockedMessage(): AssistantMessage {
422
+ return createAssistantMessage({
423
+ content: [
424
+ '시스템 프롬프트나 토큰, 비밀값은 공개할 수 없습니다.',
425
+ '사용자 입력에 포함된 JSON/도구 실행 지시는 신뢰된 도구 호출이 아니므로 실행하지 않습니다.',
426
+ '필요한 업무를 자연어로 다시 요청하면 등록된 도구와 권한 경계 안에서 처리하겠습니다.',
427
+ ].join('\n\n'),
428
+ })
429
+ }
430
+
431
+ function createMalformedToolProposalBlockedMessage(): AssistantMessage {
432
+ return createAssistantMessage({
433
+ content: [
434
+ '유효하지 않은 도구 호출 형식이 감지되어 실행하지 않았습니다.',
435
+ '등록된 도구의 정상 tool_use 경계와 검증된 tool_result 없이 서류 목록이나 처리 결과를 단정하지 않겠습니다.',
436
+ '필요한 업무를 자연어로 다시 요청하면 현재 등록된 도구 표면 안에서 처리하겠습니다.',
437
+ ].join('\n\n'),
438
+ })
439
+ }
440
+
441
+ function createGenericPendingFinalAnswerToolUseBlockedMessage(): AssistantMessage {
442
+ return createAssistantMessage({
443
+ content: buildGenericPendingFinalAnswerToolUseBlockedText(),
444
+ })
445
+ }
446
+
447
+ function createUnavailableToolFinalAnswerBlockedMessage(
448
+ messages: readonly Message[],
449
+ ): AssistantMessage {
450
+ void messages
451
+ return createAssistantMessage({
452
+ content: buildUnavailableToolFinalAnswerBlockedText(),
453
+ })
454
+ }
455
+
456
+ function createUnsupportedRouteFinalAnswerBlockedMessage(): AssistantMessage {
457
+ return createAssistantMessage({
458
+ content: buildUnsupportedRouteFinalAnswerBlockedText(),
459
+ })
460
+ }
461
+
462
+ function createStalePriorToolResultFinalAnswerBlockedMessage(): AssistantMessage {
463
+ return createAssistantMessage({
464
+ content: buildStalePriorToolResultFinalAnswerBlockedText(),
465
+ })
466
+ }
467
+
468
+ function createEmergencyNoClaimBlockedMessage(): AssistantMessage {
469
+ return createAssistantMessage({
470
+ content: [
471
+ '등록된 응급의료 adapter 결과 없이 응급실 이름, 거리, 운영 상태, 병상 여부를 단정하지 않습니다.',
472
+ '최신 사용자 요청 이후 nmc_emergency_search 또는 hira_hospital_search tool_result가 없으므로 공식 검색 결과처럼 안내할 수 없습니다.',
473
+ '긴급하면 119 또는 응급의료포털/병원 공식 채널에서 즉시 확인해야 하며, 해당 adapter가 연결되면 그 결과에 근거해 다시 안내하겠습니다.',
474
+ ].join('\n\n'),
475
+ })
476
+ }
477
+
478
+ function hasSuccessfulRegisteredEmergencyResult(
479
+ messages: readonly Message[],
480
+ ): boolean {
481
+ return toolResultsSinceLatestPrompt(messages).some(result =>
482
+ REGISTERED_EMERGENCY_RESULT_TOOL_NAMES.has(result.toolName) &&
483
+ !result.isError,
484
+ )
485
+ }
486
+
487
+ function isEmergencyResultClaim(text: string): boolean {
488
+ const hasFacilityClaim = EMERGENCY_FACILITY_CLAIM_RE.test(text)
489
+ const hasStatusOrDistanceClaim =
490
+ EMERGENCY_STATUS_OR_DISTANCE_CLAIM_RE.test(text)
491
+ if (
492
+ EMERGENCY_SAFE_LIMITATION_RE.test(text) &&
493
+ !hasFacilityClaim &&
494
+ !hasStatusOrDistanceClaim
495
+ ) {
496
+ return false
497
+ }
498
+ return hasFacilityClaim ||
499
+ hasStatusOrDistanceClaim ||
500
+ EMERGENCY_SEARCH_SUCCESS_CLAIM_RE.test(text)
501
+ }
502
+
503
+ function shouldBlockEmergencyResultClaim(params: {
504
+ readonly messages: readonly Message[]
505
+ readonly candidate: AssistantMessage
506
+ }): boolean {
507
+ if (toolUseBlocks(params.candidate).length > 0) return false
508
+ if (!EMERGENCY_RESULT_REQUEST_RE.test(latestUserText(params.messages))) {
509
+ return false
510
+ }
511
+ if (hasSuccessfulRegisteredEmergencyResult(params.messages)) return false
512
+ return isEmergencyResultClaim(messageText(params.candidate))
513
+ }
514
+
515
+ function domainGuardFinalAnswerForToolResults(
516
+ results: readonly Message[],
517
+ ): AssistantMessage | undefined {
518
+ const text = results
519
+ .flatMap(message =>
520
+ contentBlocks(message).map(block => contentText(block)),
521
+ )
522
+ .join('\n')
523
+ if (text.includes('Hometax lookup already returned')) {
524
+ return createAssistantMessage({
525
+ content:
526
+ '홈택스 조회는 이미 완료되었습니다. 다음 단계는 본인확인, 위임, 동의 확인입니다. verify 도구로 인증/위임 승인을 먼저 진행하거나, 승인 없이는 공식 채널 확인으로 handoff합니다.',
527
+ })
528
+ }
529
+ if (text.includes('KMA aviation lookup already returned')) {
530
+ return createAssistantMessage({
531
+ content:
532
+ '항공기상 확인 결과는 이미 확보했거나 credential 한계가 확인되었습니다. 같은 항공기상 도구를 반복 호출하지 않고, 확보된 근거와 공식 항공사/공항 상태 확인 한계를 기준으로 안내합니다.',
533
+ })
534
+ }
535
+ if (text.includes('as a fallback for airport aviation weather')) {
536
+ return createAssistantMessage({
537
+ content:
538
+ '항공기상 근거를 바탕으로 지연 위험과 일반 날씨 fallback 한계를 안내합니다. 공항/항공편 상태는 항공사와 공항 공식 채널에서 최종 확인해야 합니다.',
539
+ })
540
+ }
541
+ if (text.includes('Do not repeat ordinary KMA current or forecast tools')) {
542
+ return createAssistantMessage({
543
+ content:
544
+ 'KMA 일반 날씨 도구를 반복 호출하지 않습니다. 기존 위치 근거와 격자값 누락 한계를 바탕으로 안전한 이동 판단은 공식 날씨/교통 채널 확인으로 handoff합니다.',
545
+ })
546
+ }
547
+ return undefined
548
+ }
549
+
550
+ function isPermissionDeniedToolResultBlock(block: ToolResultBlock): boolean {
551
+ return PERMISSION_DENIED_TEXT_RE.test(contentText(block.content))
552
+ }
553
+
554
+ function permissionDeniedToolNames(messages: readonly Message[]): readonly string[] {
555
+ const latestUserIndex = latestTextUserMessageIndex(messages)
556
+ if (latestUserIndex < 0) return []
557
+ const toolNamesByUseId = new Map<string, string>()
558
+ const denied = new Set<string>()
559
+ for (let index = latestUserIndex + 1; index < messages.length; index += 1) {
560
+ const message = messages[index]
561
+ if (!message) continue
562
+ if (isAssistantMessage(message)) {
563
+ for (const block of toolUseBlocks(message)) {
564
+ toolNamesByUseId.set(block.id, block.name)
565
+ }
566
+ continue
567
+ }
568
+ if (!isUserMessage(message)) continue
569
+ for (const block of toolResultBlocks(message)) {
570
+ const toolName = toolNamesByUseId.get(block.tool_use_id)
571
+ if (toolName !== undefined && isPermissionDeniedToolResultBlock(block)) {
572
+ denied.add(toolName)
573
+ }
574
+ }
575
+ }
576
+ return [...denied]
577
+ }
578
+
579
+ function shouldBlockRepeatedPermissionDeniedTool(
580
+ block: ToolUseBlock,
581
+ messages: readonly Message[],
582
+ ): boolean {
583
+ return permissionDeniedToolNames(messages).includes(block.name)
584
+ }
585
+
586
+ function createPermissionDeniedContinuationGuardResult(
587
+ block: ToolUseBlock,
588
+ assistantMessage: AssistantMessage,
589
+ ): Message {
590
+ const message = [
591
+ `Permission boundary blocked: ${block.name} was already rejected with permission_denied in this request.`,
592
+ 'Do not retry the same protected check until the user explicitly grants or restarts authentication.',
593
+ 'Write a stable Korean needs-input or handoff answer explaining that authentication approval is required before continuing.',
594
+ ].join(' ')
595
+ return createUserMessage({
596
+ content: [
597
+ {
598
+ type: 'tool_result',
599
+ tool_use_id: block.id,
600
+ content: message,
601
+ is_error: true,
602
+ },
603
+ ],
604
+ toolUseResult: message,
605
+ sourceToolAssistantUUID: assistantMessage.uuid,
606
+ })
607
+ }
608
+
609
+ function latestQueryHash(messages: readonly Message[]): string {
610
+ const latestUserIndex = latestTextUserMessageIndex(messages)
611
+ const latestUserMessage = latestUserIndex >= 0 ? messages[latestUserIndex] : undefined
612
+ return hashRouteDiagnosticText(
613
+ latestUserMessage ? messageText(latestUserMessage) : '',
614
+ )
615
+ }
616
+
617
+ function latestUserText(messages: readonly Message[]): string {
618
+ const latestUserIndex = latestTextUserMessageIndex(messages)
619
+ const latestUserMessage = latestUserIndex >= 0 ? messages[latestUserIndex] : undefined
620
+ return latestUserMessage ? messageText(latestUserMessage) : ''
621
+ }
622
+
623
+ function shouldBlockPromptInjectionToolRecovery(params: {
624
+ readonly messages: readonly Message[]
625
+ readonly candidate: AssistantMessage
626
+ readonly activeToolChoiceName: string | undefined
627
+ }): boolean {
628
+ const userText = latestUserText(params.messages)
629
+ if (!PROMPT_INJECTION_USER_RE.test(userText)) return false
630
+ const candidateToolUses = toolUseBlocks(params.candidate)
631
+ if (
632
+ params.activeToolChoiceName !== undefined &&
633
+ candidateToolUses.some(block => block.name === params.activeToolChoiceName)
634
+ ) {
635
+ return false
636
+ }
637
+ if (candidateToolUses.length > 0) return true
638
+ const candidateText = messageText(params.candidate)
639
+ return textContainsToolCallProposal(candidateText) ||
640
+ SENSITIVE_DISCLOSURE_ACK_RE.test(candidateText)
641
+ }
642
+
643
+ function shouldBlockMalformedUserToolProposal(
644
+ messages: readonly Message[],
645
+ ): boolean {
646
+ return textContainsMalformedToolCallProposal(latestUserText(messages))
647
+ }
648
+
649
+ function appendQueryAssistantDiagnostic(params: {
650
+ readonly event: string
651
+ readonly querySource: string
652
+ readonly messages: readonly Message[]
653
+ readonly assistantMessage: AssistantMessage
654
+ readonly turnCount: number
655
+ readonly boundaryKind: string
656
+ readonly repairPromptChars: number
657
+ readonly continueAfterRepair: boolean
658
+ }): void {
659
+ appendRouteDiagnostic(params.event, {
660
+ query_hash: latestQueryHash(params.messages),
661
+ query_source: params.querySource,
662
+ turn_count: params.turnCount,
663
+ message_count: params.messages.length,
664
+ assistant_text_chars: messageText(params.assistantMessage).length,
665
+ assistant_tool_use_count: toolUseBlocks(params.assistantMessage).length,
666
+ assistant_content_block_count: contentBlocks(params.assistantMessage).length,
667
+ boundary_kind: params.boundaryKind,
668
+ repair_prompt_chars: params.repairPromptChars,
669
+ continue_after_repair: params.continueAfterRepair,
670
+ })
671
+ }
672
+
673
+ function appendQueryCompletedWithoutAssistantDiagnostic(params: {
674
+ readonly querySource: string
675
+ readonly messages: readonly Message[]
676
+ readonly turnCount: number
677
+ }): void {
678
+ appendRouteDiagnostic('query_completed_without_assistant', {
679
+ query_hash: latestQueryHash(params.messages),
680
+ query_source: params.querySource,
681
+ turn_count: params.turnCount,
682
+ message_count: params.messages.length,
683
+ })
684
+ }
685
+
686
+ export async function* query(params: QueryParams): QueryGenerator {
687
+ const deps = params.deps ?? productionDeps()
688
+ const messages: Message[] = [...params.messages]
689
+ let turnCount = 0
690
+
691
+ while (params.maxTurns === undefined || turnCount < params.maxTurns) {
692
+ turnCount += 1
693
+ if (params.toolUseContext.abortController.signal.aborted) {
694
+ return Terminal.aborted_streaming()
695
+ }
696
+ if (shouldBlockMalformedUserToolProposal(messages)) {
697
+ const blockedMessage = createMalformedToolProposalBlockedMessage()
698
+ appendQueryAssistantDiagnostic({
699
+ event: 'query_user_blocked_malformed_tool_proposal',
700
+ querySource: String(params.querySource),
701
+ messages,
702
+ assistantMessage: blockedMessage,
703
+ turnCount,
704
+ boundaryKind: 'block',
705
+ repairPromptChars: 0,
706
+ continueAfterRepair: false,
707
+ })
708
+ yield blockedMessage
709
+ messages.push(blockedMessage)
710
+ return Terminal.completed()
711
+ }
712
+ yield { type: 'stream_request_start' }
713
+
714
+ let assistantMessage: AssistantMessage | undefined
715
+ let shouldContinueAfterRepairPrompt = false
716
+ const disabledProviderToolNames = disabledProviderToolNamesForTurn(
717
+ messages,
718
+ )
719
+ const activeToolChoiceName =
720
+ selectRecoveredSupportToolChoiceNameForMessages(messages) ??
721
+ selectRecoveredDocumentToolChoiceNameForMessages({
722
+ messages,
723
+ tools: params.toolUseContext.options.tools,
724
+ })
725
+ const activeToolChoiceAvailable = activeToolChoiceName
726
+ ? params.toolUseContext.options.tools.some(
727
+ tool => tool.name === activeToolChoiceName,
728
+ )
729
+ : false
730
+
731
+ for await (const event of deps.callModel({
732
+ messages,
733
+ systemPrompt: systemPromptForTurn(params.systemPrompt, messages),
734
+ thinkingConfig: params.toolUseContext.options.thinkingConfig,
735
+ tools: params.toolUseContext.options.tools,
736
+ signal: params.toolUseContext.abortController.signal,
737
+ options: {
738
+ getToolPermissionContext: async () =>
739
+ params.toolUseContext.getAppState().toolPermissionContext,
740
+ model: params.toolUseContext.options.mainLoopModel,
741
+ isNonInteractiveSession:
742
+ params.toolUseContext.options.isNonInteractiveSession,
743
+ querySource: params.querySource,
744
+ agents: params.toolUseContext.options.agentDefinitions.activeAgents,
745
+ allowedAgentTypes:
746
+ params.toolUseContext.options.agentDefinitions.allowedAgentTypes,
747
+ mcpTools: params.toolUseContext.options.mcpClients,
748
+ maxOutputTokensOverride: params.maxOutputTokensOverride,
749
+ taskBudget: params.taskBudget,
750
+ skipCacheWrite: params.skipCacheWrite,
751
+ disabledProviderToolNames,
752
+ },
753
+ })) {
754
+ if (params.toolUseContext.abortController.signal.aborted) {
755
+ return Terminal.aborted_streaming()
756
+ }
757
+ if (!isAssistantMessage(event)) {
758
+ yield event
759
+ continue
760
+ }
761
+ const sanitizedCandidate = sanitizeVisibleAssistantControlTokens(event)
762
+ if (
763
+ shouldBlockPromptInjectionToolRecovery({
764
+ messages,
765
+ candidate: sanitizedCandidate,
766
+ activeToolChoiceName,
767
+ })
768
+ ) {
769
+ appendQueryAssistantDiagnostic({
770
+ event: 'query_assistant_blocked_prompt_injection_tool_recovery',
771
+ querySource: String(params.querySource),
772
+ messages,
773
+ assistantMessage: sanitizedCandidate,
774
+ turnCount,
775
+ boundaryKind: 'block',
776
+ repairPromptChars: 0,
777
+ continueAfterRepair: false,
778
+ })
779
+ const blockedMessage = createPromptInjectionToolRecoveryBlockedMessage()
780
+ yield blockedMessage
781
+ messages.push(blockedMessage)
782
+ return Terminal.completed()
783
+ }
784
+ const assistantCandidate = upgradeRawJsonToolCallAssistant({
785
+ assistantMessage: sanitizedCandidate,
786
+ createToolUseId: () => createRecoveredRawJsonToolUseId(deps.uuid()),
787
+ })
788
+ if (
789
+ toolUseBlocks(assistantCandidate).length === 0 &&
790
+ textContainsMalformedToolCallProposal(messageText(assistantCandidate))
791
+ ) {
792
+ appendQueryAssistantDiagnostic({
793
+ event: 'query_assistant_blocked_malformed_tool_proposal',
794
+ querySource: String(params.querySource),
795
+ messages,
796
+ assistantMessage: assistantCandidate,
797
+ turnCount,
798
+ boundaryKind: 'block',
799
+ repairPromptChars: 0,
800
+ continueAfterRepair: false,
801
+ })
802
+ const blockedMessage = createMalformedToolProposalBlockedMessage()
803
+ yield blockedMessage
804
+ messages.push(blockedMessage)
805
+ return Terminal.completed()
806
+ }
807
+
808
+ const boundary = enforceSupportToolBoundary({
809
+ activeToolChoiceName,
810
+ activeToolChoiceAvailable,
811
+ messagesForQuery: messages,
812
+ assistantMessage: assistantCandidate,
813
+ })
814
+ if (
815
+ boundary.kind === 'pass' &&
816
+ shouldBlockUnsupportedRouteDetailAnswer({
817
+ messages,
818
+ candidate: boundary.message,
819
+ })
820
+ ) {
821
+ appendQueryAssistantDiagnostic({
822
+ event: 'query_assistant_blocked_unsupported_route_detail',
823
+ querySource: String(params.querySource),
824
+ messages,
825
+ assistantMessage: boundary.message,
826
+ turnCount,
827
+ boundaryKind: 'block',
828
+ repairPromptChars: 0,
829
+ continueAfterRepair: false,
830
+ })
831
+ const blockedMessage = createUnsupportedRouteFinalAnswerBlockedMessage()
832
+ yield blockedMessage
833
+ messages.push(blockedMessage)
834
+ return Terminal.completed()
835
+ }
836
+ if (
837
+ boundary.kind === 'pass' &&
838
+ shouldBlockStalePriorToolResultAnswer({
839
+ messages,
840
+ candidate: boundary.message,
841
+ })
842
+ ) {
843
+ appendQueryAssistantDiagnostic({
844
+ event: 'query_assistant_blocked_stale_prior_tool_result',
845
+ querySource: String(params.querySource),
846
+ messages,
847
+ assistantMessage: boundary.message,
848
+ turnCount,
849
+ boundaryKind: 'block',
850
+ repairPromptChars: 0,
851
+ continueAfterRepair: false,
852
+ })
853
+ const blockedMessage = createStalePriorToolResultFinalAnswerBlockedMessage()
854
+ yield blockedMessage
855
+ messages.push(blockedMessage)
856
+ return Terminal.completed()
857
+ }
858
+ const publicDataRepairPrompt = boundary.kind === 'pass'
859
+ ? buildPublicDataTerminalRepairPrompt({
860
+ messages,
861
+ candidate: boundary.message,
862
+ })
863
+ : undefined
864
+ if (publicDataRepairPrompt !== undefined) {
865
+ appendQueryAssistantDiagnostic({
866
+ event: 'query_assistant_withheld_for_repair',
867
+ querySource: String(params.querySource),
868
+ messages,
869
+ assistantMessage: boundary.message,
870
+ turnCount,
871
+ boundaryKind: boundary.kind,
872
+ repairPromptChars: publicDataRepairPrompt.length,
873
+ continueAfterRepair: true,
874
+ })
875
+ messages.push(boundary.message)
876
+ messages.push(
877
+ createUserMessage({
878
+ content: publicDataRepairPrompt,
879
+ isMeta: true,
880
+ }),
881
+ )
882
+ shouldContinueAfterRepairPrompt = true
883
+ break
884
+ }
885
+ if (
886
+ boundary.kind === 'pass' &&
887
+ shouldBlockEmergencyResultClaim({
888
+ messages,
889
+ candidate: boundary.message,
890
+ })
891
+ ) {
892
+ appendQueryAssistantDiagnostic({
893
+ event: 'query_assistant_blocked_emergency_no_claim',
894
+ querySource: String(params.querySource),
895
+ messages,
896
+ assistantMessage: boundary.message,
897
+ turnCount,
898
+ boundaryKind: 'block',
899
+ repairPromptChars: 0,
900
+ continueAfterRepair: false,
901
+ })
902
+ const blockedMessage = createEmergencyNoClaimBlockedMessage()
903
+ yield blockedMessage
904
+ messages.push(blockedMessage)
905
+ return Terminal.completed()
906
+ }
907
+ if (
908
+ boundary.kind === 'pass' &&
909
+ shouldBlockFinalAnswerAfterUnavailableToolRepair({
910
+ messages,
911
+ candidate: boundary.message,
912
+ })
913
+ ) {
914
+ appendQueryAssistantDiagnostic({
915
+ event: 'query_assistant_blocked_after_unavailable_tool_repair',
916
+ querySource: String(params.querySource),
917
+ messages,
918
+ assistantMessage: boundary.message,
919
+ turnCount,
920
+ boundaryKind: 'block',
921
+ repairPromptChars: 0,
922
+ continueAfterRepair: false,
923
+ })
924
+ const blockedMessage = createUnavailableToolFinalAnswerBlockedMessage(messages)
925
+ yield blockedMessage
926
+ messages.push(blockedMessage)
927
+ return Terminal.completed()
928
+ }
929
+ if (
930
+ boundary.kind === 'pass' &&
931
+ shouldBlockFinalAnswerAfterUnsupportedRouteRepair({
932
+ messages,
933
+ candidate: boundary.message,
934
+ })
935
+ ) {
936
+ appendQueryAssistantDiagnostic({
937
+ event: 'query_assistant_blocked_after_unsupported_route_repair',
938
+ querySource: String(params.querySource),
939
+ messages,
940
+ assistantMessage: boundary.message,
941
+ turnCount,
942
+ boundaryKind: 'block',
943
+ repairPromptChars: 0,
944
+ continueAfterRepair: false,
945
+ })
946
+ const blockedMessage = createUnsupportedRouteFinalAnswerBlockedMessage()
947
+ yield blockedMessage
948
+ messages.push(blockedMessage)
949
+ return Terminal.completed()
950
+ }
951
+ if (
952
+ boundary.kind === 'pass' &&
953
+ shouldBlockToolUseAfterGenericPendingFinalAnswerRepair({
954
+ messages,
955
+ candidate: boundary.message,
956
+ })
957
+ ) {
958
+ appendQueryAssistantDiagnostic({
959
+ event: 'query_assistant_blocked_after_final_repair',
960
+ querySource: String(params.querySource),
961
+ messages,
962
+ assistantMessage: boundary.message,
963
+ turnCount,
964
+ boundaryKind: 'block',
965
+ repairPromptChars: 0,
966
+ continueAfterRepair: false,
967
+ })
968
+ const blockedMessage = createGenericPendingFinalAnswerToolUseBlockedMessage()
969
+ yield blockedMessage
970
+ messages.push(blockedMessage)
971
+ return Terminal.completed()
972
+ }
973
+ appendQueryAssistantDiagnostic({
974
+ event: 'query_assistant_yield',
975
+ querySource: String(params.querySource),
976
+ messages,
977
+ assistantMessage: boundary.message,
978
+ turnCount,
979
+ boundaryKind: boundary.kind,
980
+ repairPromptChars: 0,
981
+ continueAfterRepair: false,
982
+ })
983
+ yield boundary.message
984
+ assistantMessage = boundary.message
985
+ messages.push(boundary.message)
986
+ if (boundary.kind === 'block') return Terminal.completed()
987
+ break
988
+ }
989
+
990
+ if (shouldContinueAfterRepairPrompt) continue
991
+ if (!assistantMessage) {
992
+ appendQueryCompletedWithoutAssistantDiagnostic({
993
+ querySource: String(params.querySource),
994
+ messages,
995
+ turnCount,
996
+ })
997
+ return Terminal.completed()
998
+ }
999
+ const toolUses = toolUseBlocks(assistantMessage)
1000
+ if (toolUses.length === 0) return Terminal.completed()
1001
+ if (params.toolUseContext.abortController.signal.aborted) {
1002
+ return Terminal.aborted_tools()
1003
+ }
1004
+
1005
+ const toolResults: Message[] = []
1006
+ let shouldCompleteAfterHardGuard = false
1007
+ for (let blockIndex = 0; blockIndex < toolUses.length; blockIndex += 1) {
1008
+ const block = toolUses[blockIndex]
1009
+ if (!block) continue
1010
+ if (shouldBlockRepeatedPermissionDeniedTool(block, messages)) {
1011
+ toolResults.push(
1012
+ createPermissionDeniedContinuationGuardResult(block, assistantMessage),
1013
+ )
1014
+ } else if (shouldBlockRepeatedAdapterlessFind(block, messages)) {
1015
+ toolResults.push(
1016
+ createAdapterlessFindContinuationGuardResult(block, assistantMessage),
1017
+ )
1018
+ toolResults.push(createAdapterlessFindHardGuardFinalMessage())
1019
+ shouldCompleteAfterHardGuard = true
1020
+ } else {
1021
+ const blockResults = await runToolUseBlocks({
1022
+ blocks: [block],
1023
+ assistantMessage,
1024
+ messages: [...messages, ...toolResults],
1025
+ toolUseContext: params.toolUseContext,
1026
+ canUseTool: params.canUseTool,
1027
+ })
1028
+ toolResults.push(...blockResults.map(upgradeUnavailableToolResultMessage))
1029
+ const nextAdapterlessFind = toolUses
1030
+ .slice(blockIndex + 1)
1031
+ .find(isAdapterlessFindToolUse)
1032
+ if (
1033
+ isAdapterlessFindToolUse(block) &&
1034
+ nextAdapterlessFind !== undefined &&
1035
+ hasAdapterlessFindFailure([...messages, ...toolResults])
1036
+ ) {
1037
+ toolResults.push(
1038
+ createAdapterlessFindContinuationGuardResult(nextAdapterlessFind, assistantMessage),
1039
+ )
1040
+ toolResults.push(createAdapterlessFindHardGuardFinalMessage())
1041
+ shouldCompleteAfterHardGuard = true
1042
+ break
1043
+ }
1044
+ }
1045
+ }
1046
+
1047
+ for (const result of toolResults) {
1048
+ if (params.toolUseContext.abortController.signal.aborted) {
1049
+ return Terminal.aborted_tools()
1050
+ }
1051
+ messages.push(result)
1052
+ yield result
1053
+ }
1054
+ const domainGuardFinalAnswer = domainGuardFinalAnswerForToolResults(toolResults)
1055
+ if (domainGuardFinalAnswer !== undefined) {
1056
+ messages.push(domainGuardFinalAnswer)
1057
+ yield domainGuardFinalAnswer
1058
+ return Terminal.completed()
1059
+ }
1060
+ if (shouldCompleteAfterHardGuard) return Terminal.completed()
1061
+ const documentCompletionPrompt = buildDocumentCompletionPromptIfNeeded({
1062
+ messages,
1063
+ })
1064
+ if (documentCompletionPrompt !== undefined) {
1065
+ messages.push(
1066
+ createUserMessage({
1067
+ content: documentCompletionPrompt,
1068
+ isMeta: true,
1069
+ }),
1070
+ )
1071
+ }
1072
+ }
1073
+
1074
+ return Terminal.max_turns(turnCount)
1075
+ }