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,452 @@
1
+ import { createHash } from 'node:crypto'
2
+ import type { Tools } from '../../../Tool.js'
3
+ import type { Message } from '../../../types/message.js'
4
+ import type {
5
+ ForcedUmmayaToolUse,
6
+ UmmayaBackendRepairReceipt,
7
+ } from '../toolChoiceRepair.js'
8
+ import {
9
+ buildDocumentCompletionPrompt,
10
+ hasTerminalDocumentCompletion,
11
+ mentionsDocumentWork,
12
+ } from './documentCompletionPrompt.js'
13
+ import {
14
+ DOCUMENT_INTENT_RE,
15
+ DOCUMENT_READ_ONLY_RE,
16
+ DOCUMENT_RENDER_TOOL_NAME,
17
+ DOCUMENT_TOOL_NAME,
18
+ DOCUMENT_WRITE_RE,
19
+ documentExpectedFormatFromPath,
20
+ isExactLocalReadOnlyDocumentPrompt,
21
+ localDocumentPathFromText,
22
+ type DocumentExpectedFormat,
23
+ } from './documentCompletionPatterns.js'
24
+ import {
25
+ isRecord,
26
+ latestUserMessageIndex,
27
+ latestUserText,
28
+ messageContent,
29
+ textFromContent,
30
+ } from './messageAccess.js'
31
+
32
+ const DOCUMENT_EXPLICIT_PATH_SCAN_RE =
33
+ /(?:^|[\s:'"(])((?:~|\/|[A-Za-z]:\\|\.{1,2}\/)[^\s:'"]+\.(hwpx|hwp|docx|pdf|xlsx|pptx))\b/giu
34
+ const DOCUMENT_ARTIFACT_ID_RE =
35
+ /(?:^|[\s"'`(])(?:artifact_id|artifact\s*id|artifact|아티팩트)?\s*((?:source|working|derivative|render|export|viewport)-[A-Za-z0-9][A-Za-z0-9_.-]{0,127})(?=$|[^A-Za-z0-9_.-])/iu
36
+ const DOCUMENT_FORMAT_RE = /\b(?:hwpx|hwp|docx|pdf|xlsx|pptx)\b/iu
37
+ const DOCUMENT_REVIEW_RE =
38
+ /(diff|compact|변경사항|렌더|미리보기|render|viewport|page)/iu
39
+ const DOCUMENT_LOCAL_HINT_RE =
40
+ /(다운로드|downloads?|폴더|파일|양식|서식|활동일지|신청서|등본|증명서)/iu
41
+
42
+ function toolAvailable(tools: Tools, toolName: string): boolean {
43
+ return tools.some(tool => tool.name === toolName)
44
+ }
45
+
46
+ function documentCandidateText(candidate: unknown): string {
47
+ if (typeof candidate === 'string') return candidate
48
+ if (!isRecord(candidate)) return ''
49
+ const message = isRecord(candidate.message) ? candidate.message : candidate
50
+ return textFromContent(messageContent(message))
51
+ }
52
+
53
+ type DocumentDispatchRepair =
54
+ | {
55
+ readonly kind: 'ready'
56
+ readonly input: Record<string, unknown>
57
+ }
58
+ | {
59
+ readonly kind: 'blocked'
60
+ readonly message: string
61
+ }
62
+
63
+ type DocumentPathRef = {
64
+ readonly path: string
65
+ readonly expectedFormat: DocumentExpectedFormat
66
+ }
67
+
68
+ export function repairUmmayaDocumentToolInputForDispatch({
69
+ toolName,
70
+ input,
71
+ messages,
72
+ }: {
73
+ readonly toolName: string
74
+ readonly input: Record<string, unknown>
75
+ readonly messages: readonly Message[]
76
+ }): DocumentDispatchRepair {
77
+ if (toolName !== DOCUMENT_TOOL_NAME) {
78
+ return { kind: 'ready', input }
79
+ }
80
+
81
+ const userText = latestUserText(messages)
82
+ const exactReadOnlyInspect = isExactLocalReadOnlyDocumentPrompt(userText)
83
+ if (hasDocumentDispatchContract(input) && !exactReadOnlyInspect) {
84
+ return { kind: 'ready', input }
85
+ }
86
+
87
+ if (!exactReadOnlyInspect) {
88
+ return {
89
+ kind: 'blocked',
90
+ message:
91
+ 'Document boundary blocked: provider emitted malformed document input, and the latest user request was not an exact local read-only inspect prompt. The document tool was not dispatched.',
92
+ }
93
+ }
94
+
95
+ const path = localDocumentPathFromText(userText)
96
+ if (path === undefined) {
97
+ return {
98
+ kind: 'blocked',
99
+ message:
100
+ 'Document boundary blocked: provider emitted malformed document input, and no exact local document path could be recovered from the latest user request. Provide an exact existing file path.',
101
+ }
102
+ }
103
+
104
+ const expectedFormat = documentExpectedFormatFromPath(path)
105
+ return {
106
+ kind: 'ready',
107
+ input: {
108
+ correlation_id:
109
+ nonEmptyString(input.correlation_id) ??
110
+ `client-repaired-document-${shortHash(`${path}\n${userText}`)}`,
111
+ document: {
112
+ path,
113
+ ...(expectedFormat === undefined ? {} : { expected_format: expectedFormat }),
114
+ },
115
+ operation: 'inspect',
116
+ instruction: documentInstruction(input, userText),
117
+ __ummaya_user_query: userText,
118
+ },
119
+ }
120
+ }
121
+
122
+ function hasDocumentDispatchContract(input: Record<string, unknown>): boolean {
123
+ const document = isRecord(input.document) ? input.document : undefined
124
+ return nonEmptyString(input.correlation_id) !== undefined &&
125
+ document !== undefined &&
126
+ (nonEmptyString(document.path) !== undefined ||
127
+ nonEmptyString(document.artifact_id) !== undefined) &&
128
+ nonEmptyString(input.instruction) !== undefined
129
+ }
130
+
131
+ function documentInstruction(
132
+ input: Record<string, unknown>,
133
+ userText: string,
134
+ ): string {
135
+ const instruction = nonEmptyString(input.instruction)
136
+ if (instruction === undefined) return userText
137
+ if (instruction.includes(userText)) return instruction
138
+ return `${instruction}\n\nOriginal user request:\n${userText}`
139
+ }
140
+
141
+ function nonEmptyString(value: unknown): string | undefined {
142
+ return typeof value === 'string' && value.trim().length > 0
143
+ ? value
144
+ : undefined
145
+ }
146
+
147
+ function shortHash(text: string): string {
148
+ return createHash('sha256').update(text).digest('hex').slice(0, 8)
149
+ }
150
+
151
+ function hasBackendRepairReceipt(
152
+ receipt: UmmayaBackendRepairReceipt | undefined,
153
+ ): boolean {
154
+ return receipt !== undefined &&
155
+ (receipt.source === 'backend_route_decision' ||
156
+ receipt.source === 'backend_validation') &&
157
+ receipt.reason.trim() !== '' &&
158
+ receipt.evidenceEvent.startsWith('ummaya.')
159
+ }
160
+
161
+ function isDocumentHarnessQuery(text: string): boolean {
162
+ return localDocumentPathFromText(text) !== undefined ||
163
+ DOCUMENT_ARTIFACT_ID_RE.test(text) ||
164
+ ((DOCUMENT_FORMAT_RE.test(text) || DOCUMENT_ARTIFACT_ID_RE.test(text)) &&
165
+ DOCUMENT_INTENT_RE.test(text)) ||
166
+ (DOCUMENT_INTENT_RE.test(text) &&
167
+ DOCUMENT_WRITE_RE.test(text) &&
168
+ DOCUMENT_LOCAL_HINT_RE.test(text))
169
+ }
170
+
171
+ function hasExplicitDocumentLocator(text: string): boolean {
172
+ return localDocumentPathFromText(text) !== undefined ||
173
+ DOCUMENT_ARTIFACT_ID_RE.test(text)
174
+ }
175
+
176
+ function explicitDocumentPathRefs(userText: string): readonly DocumentPathRef[] {
177
+ return [...userText.matchAll(DOCUMENT_EXPLICIT_PATH_SCAN_RE)].map(match => ({
178
+ path: match[1]!,
179
+ expectedFormat: match[2]!.toLowerCase() as DocumentExpectedFormat,
180
+ }))
181
+ }
182
+
183
+ function stableDocumentCorrelationId(userText: string): string {
184
+ return `client-forced-document-${shortHash(userText)}`
185
+ }
186
+
187
+ function forcedDocumentInputFromExplicitPath(
188
+ userText: string,
189
+ ): Record<string, unknown> | undefined {
190
+ if (!isDocumentHarnessQuery(userText)) return undefined
191
+ const wantsWrite =
192
+ DOCUMENT_WRITE_RE.test(userText) && !DOCUMENT_READ_ONLY_RE.test(userText)
193
+ const wantsReview = DOCUMENT_REVIEW_RE.test(userText)
194
+ const wantsReadOnly = DOCUMENT_READ_ONLY_RE.test(userText)
195
+ if (!wantsWrite && !wantsReview && !wantsReadOnly) return undefined
196
+
197
+ const paths = explicitDocumentPathRefs(userText)
198
+ const source = paths[0]
199
+ if (!source) return undefined
200
+
201
+ const input: Record<string, unknown> = {
202
+ correlation_id: stableDocumentCorrelationId(userText),
203
+ document: {
204
+ path: source.path,
205
+ expected_format: source.expectedFormat,
206
+ },
207
+ operation: wantsWrite ? 'fill' : 'inspect',
208
+ instruction: userText,
209
+ }
210
+ const destination = paths.find(candidate => candidate.path !== source.path)
211
+ if (destination !== undefined && wantsWrite) {
212
+ input.destination_path = destination.path
213
+ }
214
+ return input
215
+ }
216
+
217
+ function toolAvailableOrSynced(tools: Tools, toolName: string): boolean {
218
+ return toolAvailable(tools, toolName)
219
+ }
220
+
221
+ function hasExplicitMutationPayload(input: Record<string, unknown>): boolean {
222
+ return Array.isArray(input.patches) ||
223
+ Array.isArray(input.styles) ||
224
+ typeof input.destination_path === 'string'
225
+ }
226
+
227
+ function parseJsonRecord(value: string): Record<string, unknown> | undefined {
228
+ try {
229
+ const parsed: unknown = JSON.parse(value)
230
+ return isRecord(parsed) ? parsed : undefined
231
+ } catch {
232
+ return undefined
233
+ }
234
+ }
235
+
236
+ function documentResultPayload(value: unknown): Record<string, unknown> | undefined {
237
+ if (Array.isArray(value)) {
238
+ for (let index = value.length - 1; index >= 0; index -= 1) {
239
+ const nested = documentResultPayload(value[index])
240
+ if (nested !== undefined) return nested
241
+ }
242
+ return undefined
243
+ }
244
+ if (!isRecord(value)) return undefined
245
+ const toolId = typeof value.tool_id === 'string' ? value.tool_id : undefined
246
+ if (toolId === DOCUMENT_TOOL_NAME || toolId === DOCUMENT_RENDER_TOOL_NAME) {
247
+ return value
248
+ }
249
+ return documentResultPayload(value.result)
250
+ }
251
+
252
+ function isSuccessfulDocumentPayload(
253
+ payload: Record<string, unknown>,
254
+ acceptedToolNames: ReadonlySet<string>,
255
+ ): boolean {
256
+ const toolId = typeof payload.tool_id === 'string' ? payload.tool_id : undefined
257
+ if (toolId === undefined || !acceptedToolNames.has(toolId)) return false
258
+ const status = typeof payload.status === 'string'
259
+ ? payload.status.toLowerCase()
260
+ : 'ok'
261
+ const okFlag = typeof payload.ok === 'boolean' ? payload.ok : true
262
+ const hasError =
263
+ payload.kind === 'error' ||
264
+ typeof payload.error === 'string' ||
265
+ isRecord(payload.error)
266
+ return okFlag && !hasError &&
267
+ ['ok', 'succeeded', 'completed', 'ready'].includes(status)
268
+ }
269
+
270
+ function hasSuccessfulDocumentResultAfter(
271
+ messages: readonly Message[],
272
+ afterIndex: number,
273
+ acceptedToolNames: ReadonlySet<string>,
274
+ ): boolean {
275
+ for (let index = Math.max(0, afterIndex + 1); index < messages.length; index += 1) {
276
+ const content = messageContent(messages[index])
277
+ if (!Array.isArray(content)) continue
278
+ for (const block of content) {
279
+ if (!isRecord(block) || block.type !== 'tool_result') continue
280
+ if (block.is_error === true || typeof block.content !== 'string') continue
281
+ const payload = documentResultPayload(parseJsonRecord(block.content))
282
+ if (
283
+ payload !== undefined &&
284
+ isSuccessfulDocumentPayload(payload, acceptedToolNames)
285
+ ) {
286
+ return true
287
+ }
288
+ }
289
+ }
290
+ return false
291
+ }
292
+
293
+ export function repairUmmayaExplicitDocumentToolUseFromUserQuery({
294
+ input,
295
+ toolName,
296
+ messages,
297
+ tools,
298
+ backendRepairReceipt,
299
+ }: {
300
+ readonly toolName: string
301
+ readonly input: Record<string, unknown>
302
+ readonly messages: readonly Message[]
303
+ readonly tools: Tools
304
+ readonly backendRepairReceipt?: UmmayaBackendRepairReceipt
305
+ }): ForcedUmmayaToolUse | undefined {
306
+ if (!hasBackendRepairReceipt(backendRepairReceipt)) return undefined
307
+ if (!toolAvailableOrSynced(tools, DOCUMENT_TOOL_NAME)) return undefined
308
+
309
+ const userText = latestUserText(messages)
310
+ if (!hasExplicitDocumentLocator(userText)) return undefined
311
+ const forced = forcedDocumentInputFromExplicitPath(userText)
312
+ if (forced === undefined) return undefined
313
+
314
+ if (toolName === DOCUMENT_TOOL_NAME) {
315
+ const forcedOperation = typeof forced.operation === 'string'
316
+ ? forced.operation
317
+ : undefined
318
+ const currentOperation = typeof input.operation === 'string'
319
+ ? input.operation
320
+ : undefined
321
+ if (
322
+ forcedOperation === currentOperation ||
323
+ (forcedOperation !== 'inspect' && hasExplicitMutationPayload(input))
324
+ ) {
325
+ return undefined
326
+ }
327
+ }
328
+
329
+ return {
330
+ name: DOCUMENT_TOOL_NAME,
331
+ input: forced,
332
+ }
333
+ }
334
+
335
+ export function backfillUmmayaObservableToolInputFromUserQuery(_params: {
336
+ readonly toolName: string
337
+ readonly input: Record<string, unknown>
338
+ readonly messages: readonly Message[]
339
+ }): void {
340
+ if (_params.toolName !== DOCUMENT_TOOL_NAME) return
341
+ const operation = typeof _params.input.operation === 'string'
342
+ ? _params.input.operation
343
+ : undefined
344
+ if (operation !== 'inspect' && operation !== 'extract') return
345
+
346
+ const userText = latestUserText(_params.messages)
347
+ if (!isDocumentHarnessQuery(userText)) return
348
+ if (!DOCUMENT_WRITE_RE.test(userText) || DOCUMENT_READ_ONLY_RE.test(userText)) {
349
+ return
350
+ }
351
+ if (!hasExplicitDocumentLocator(userText)) return
352
+
353
+ _params.input.__ummaya_display_operation = 'fill'
354
+ }
355
+
356
+ export function selectUmmayaClientForcedToolUse({
357
+ messages,
358
+ tools,
359
+ backendRepairReceipt,
360
+ }: {
361
+ readonly messages: readonly Message[]
362
+ readonly tools: Tools
363
+ readonly backendRepairReceipt?: UmmayaBackendRepairReceipt
364
+ }): ForcedUmmayaToolUse | undefined {
365
+ if (!hasBackendRepairReceipt(backendRepairReceipt)) return undefined
366
+ if (!toolAvailableOrSynced(tools, DOCUMENT_TOOL_NAME)) return undefined
367
+ const input = forcedDocumentInputFromExplicitPath(latestUserText(messages))
368
+ if (input === undefined) return undefined
369
+ return {
370
+ name: DOCUMENT_TOOL_NAME,
371
+ input,
372
+ }
373
+ }
374
+
375
+ export function selectRecoveredDocumentToolChoiceNameForMessages({
376
+ messages,
377
+ tools,
378
+ }: {
379
+ readonly messages: readonly Message[]
380
+ readonly tools: Tools
381
+ }): string | undefined {
382
+ if (!isExactLocalReadOnlyDocumentPrompt(latestUserText(messages))) {
383
+ return undefined
384
+ }
385
+ return toolAvailable(tools, DOCUMENT_TOOL_NAME) ? DOCUMENT_TOOL_NAME : undefined
386
+ }
387
+
388
+ export function shouldWithholdIgnoredDocumentToolChoiceText({
389
+ toolChoiceName,
390
+ candidate,
391
+ }: {
392
+ readonly toolChoiceName: string
393
+ readonly candidate: unknown
394
+ }): boolean {
395
+ return toolChoiceName === DOCUMENT_TOOL_NAME &&
396
+ documentCandidateText(candidate).trim().length > 0
397
+ }
398
+
399
+ export function buildIgnoredDocumentToolChoiceBlockedText(
400
+ toolChoiceAvailable = true,
401
+ ): string {
402
+ const reason = toolChoiceAvailable
403
+ ? 'provider ignored forced document tool_choice.'
404
+ : 'document 도구가 현재 TUI 도구 풀에 없어 로컬 문서 검사를 실행할 수 없습니다.'
405
+ return [
406
+ '문서 도구 호출 차단: document tool_choice를 강제했지만 모델 응답에 document 도구 경계가 포함되지 않았습니다.',
407
+ `이유: ${reason}`,
408
+ '로컬 문서는 검색 또는 추측 답변으로 처리하지 않습니다.',
409
+ ].join(' ')
410
+ }
411
+
412
+ export function shouldCompleteAfterSuccessfulDocumentRender(_params: {
413
+ readonly messages: readonly Message[]
414
+ }): boolean {
415
+ const userText = latestUserText(_params.messages)
416
+ if (!isDocumentHarnessQuery(userText)) return false
417
+ if (!DOCUMENT_REVIEW_RE.test(userText)) return false
418
+ if (!DOCUMENT_ARTIFACT_ID_RE.test(userText)) return false
419
+ return hasSuccessfulDocumentResultAfter(
420
+ _params.messages,
421
+ latestUserMessageIndex(_params.messages),
422
+ new Set([DOCUMENT_TOOL_NAME, DOCUMENT_RENDER_TOOL_NAME]),
423
+ )
424
+ }
425
+
426
+ export function shouldCompleteAfterTerminalDocumentToolResult(_params: {
427
+ readonly messages: readonly Message[]
428
+ }): boolean {
429
+ const userText = latestUserText(_params.messages)
430
+ if (!mentionsDocumentWork(userText)) return false
431
+ return hasTerminalDocumentCompletion({
432
+ messages: _params.messages,
433
+ userText,
434
+ })
435
+ }
436
+
437
+ export function shouldSuppressDocumentToolCallsForAnswerSynthesis(params: {
438
+ readonly messages: readonly Message[]
439
+ }): boolean {
440
+ return shouldCompleteAfterSuccessfulDocumentRender(params) ||
441
+ shouldCompleteAfterTerminalDocumentToolResult(params)
442
+ }
443
+
444
+ export function buildDocumentCompletionPromptIfNeeded({
445
+ messages,
446
+ }: {
447
+ readonly messages: readonly Message[]
448
+ }): string | undefined {
449
+ const userText = latestUserText(messages)
450
+ if (!mentionsDocumentWork(userText)) return undefined
451
+ return buildDocumentCompletionPrompt({ messages, userText })
452
+ }
@@ -0,0 +1,80 @@
1
+ import type { Message } from '../../../types/message.js'
2
+
3
+ export function isRecord(value: unknown): value is Record<string, unknown> {
4
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
5
+ }
6
+
7
+ export function messageRecord(
8
+ message: unknown,
9
+ ): Record<string, unknown> | undefined {
10
+ if (!isRecord(message)) return undefined
11
+ return isRecord(message.message) ? message.message : undefined
12
+ }
13
+
14
+ export function messageRole(message: unknown): string | undefined {
15
+ const outer = isRecord(message) ? message : undefined
16
+ const inner = messageRecord(message)
17
+ if (typeof inner?.role === 'string') return inner.role
18
+ if (typeof outer?.role === 'string') return outer.role
19
+ return typeof outer?.type === 'string' ? outer.type : undefined
20
+ }
21
+
22
+ export function messageContent(message: unknown): unknown {
23
+ return messageRecord(message)?.content ?? (isRecord(message) ? message.content : undefined)
24
+ }
25
+
26
+ export function textFromContent(content: unknown): string {
27
+ if (typeof content === 'string') return content
28
+ if (!Array.isArray(content)) return ''
29
+ return content
30
+ .map(block => {
31
+ if (typeof block === 'string') return block
32
+ if (!isRecord(block)) return ''
33
+ if (block.type !== 'text') return ''
34
+ return typeof block.text === 'string' ? block.text : ''
35
+ })
36
+ .filter(text => text.length > 0)
37
+ .join('\n')
38
+ }
39
+
40
+ export function latestUserText(messages: readonly unknown[]): string {
41
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
42
+ if (messageRole(messages[index]) !== 'user') continue
43
+ const text = textFromContent(messageContent(messages[index])).trim()
44
+ if (text.length > 0) return text
45
+ }
46
+ return ''
47
+ }
48
+
49
+ export function latestUserMessageIndex(messages: readonly unknown[]): number {
50
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
51
+ if (messageRole(messages[index]) !== 'user') continue
52
+ const text = textFromContent(messageContent(messages[index])).trim()
53
+ if (text.length > 0) return index
54
+ }
55
+ return -1
56
+ }
57
+
58
+ export function toolUseNames(messages: readonly unknown[]): ReadonlySet<string> {
59
+ const names = new Set<string>()
60
+ for (const candidate of messages) {
61
+ const content = messageContent(candidate)
62
+ if (!Array.isArray(content)) continue
63
+ for (const block of content) {
64
+ if (isRecord(block) && block.type === 'tool_use' && typeof block.name === 'string') {
65
+ const input = isRecord(block.input) ? block.input : undefined
66
+ names.add(typeof input?.tool_id === 'string' ? input.tool_id : block.name)
67
+ }
68
+ }
69
+ }
70
+ return names
71
+ }
72
+
73
+ export function latestAssistantText(messages: readonly Message[]): string {
74
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
75
+ if (messageRole(messages[index]) !== 'assistant') continue
76
+ const text = textFromContent(messageContent(messages[index]))
77
+ if (text.trim().length > 0) return text
78
+ }
79
+ return ''
80
+ }
@@ -0,0 +1,92 @@
1
+ import type { Tools } from '../../../Tool.js'
2
+ import type { Message } from '../../../types/message.js'
3
+ import { isNonSyntheticUserMessageText } from '../citizenUserText.js'
4
+ import {
5
+ isRecord,
6
+ latestAssistantText,
7
+ messageContent,
8
+ messageRole,
9
+ textFromContent,
10
+ } from './messageAccess.js'
11
+
12
+ type PromptParams = { readonly messages: readonly Message[] }
13
+ type CandidateWithholdParams = PromptParams & { readonly candidate: Message }
14
+
15
+ const GENERIC_PENDING_FINAL_RE =
16
+ /(답변을?\s*제공하겠습니다|제공하겠습니다|확인해\s*보겠습니다|확인하겠습니다|조회하겠습니다|찾아보겠습니다|검색해\s*보겠습니다|검색하겠습니다|최종\s*답변은|final answer should|will\s+(?:answer|provide|check|search|look\s+up))/iu
17
+ const GENERIC_PENDING_FINAL_REPAIR_PROMPT =
18
+ 'Final answer repair: successful tool_result evidence already exists, but the previous assistant message was still a plan or promise to answer later. Write the final Korean answer now from the actual tool_result values only. Do not say 제공하겠습니다, 확인하겠습니다, 조회하겠습니다, 찾아보겠습니다, 검색해 보겠습니다, or describe what you will answer next.'
19
+ const GENERIC_PENDING_FINAL_TOOL_USE_BLOCKED_TEXT =
20
+ '이미 도구 결과가 반환되어 최종 답변 보정이 요청되었습니다. 이 단계에서는 추가 도구를 실행하지 않습니다. 현재 확인된 도구 결과만 근거로 답변을 마무리하고, 연결되지 않은 업무는 공식 채널 확인 또는 필요한 adapter/credential 준비로 넘겨야 합니다.'
21
+
22
+ export function buildGenericPendingFinalAnswerRepairPromptIfNeeded(
23
+ params: PromptParams,
24
+ ): string | undefined {
25
+ if (!hasToolResultAfterLatestUser(params.messages)) return undefined
26
+ if (hasGenericPendingFinalRepairPrompt(params.messages)) return undefined
27
+ if (!GENERIC_PENDING_FINAL_RE.test(latestAssistantText(params.messages))) {
28
+ return undefined
29
+ }
30
+ return GENERIC_PENDING_FINAL_REPAIR_PROMPT
31
+ }
32
+
33
+ export function shouldWithholdGenericPendingFinalAnswer(
34
+ params: CandidateWithholdParams,
35
+ ): boolean {
36
+ if (hasGenericPendingFinalRepairPrompt(params.messages)) return false
37
+ if (candidateHasToolUse(params.candidate)) return false
38
+ return buildGenericPendingFinalAnswerRepairPromptIfNeeded({
39
+ messages: [...params.messages, params.candidate],
40
+ }) !== undefined
41
+ }
42
+
43
+ export function shouldBlockToolUseAfterGenericPendingFinalAnswerRepair(
44
+ params: CandidateWithholdParams,
45
+ ): boolean {
46
+ return hasGenericPendingFinalRepairPrompt(params.messages) &&
47
+ candidateHasToolUse(params.candidate)
48
+ }
49
+
50
+ export function buildGenericPendingFinalAnswerToolUseBlockedText(): string {
51
+ return GENERIC_PENDING_FINAL_TOOL_USE_BLOCKED_TEXT
52
+ }
53
+
54
+ export function selectUmmayaClientForcedToolUseForPublicData(_params: {
55
+ readonly messages: readonly Message[]
56
+ readonly tools: Tools
57
+ }): undefined {
58
+ return undefined
59
+ }
60
+
61
+ function hasGenericPendingFinalRepairPrompt(messages: readonly Message[]): boolean {
62
+ return messages.some(message =>
63
+ textFromContent(messageContent(message)).includes(
64
+ 'Final answer repair: successful tool_result',
65
+ ),
66
+ )
67
+ }
68
+
69
+ function candidateHasToolUse(candidate: Message): boolean {
70
+ const content = messageContent(candidate)
71
+ return Array.isArray(content) &&
72
+ content.some(block => isRecord(block) && block.type === 'tool_use')
73
+ }
74
+
75
+ function hasToolResultAfterLatestUser(messages: readonly Message[]): boolean {
76
+ let latestUserIndex = -1
77
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
78
+ const message = messages[index]
79
+ if (messageRole(message) !== 'user') continue
80
+ const text = textFromContent(messageContent(message))
81
+ if (isNonSyntheticUserMessageText(message, text)) {
82
+ latestUserIndex = index
83
+ break
84
+ }
85
+ }
86
+ if (latestUserIndex < 0) return false
87
+ return messages.slice(latestUserIndex + 1).some(message => {
88
+ const content = messageContent(message)
89
+ return Array.isArray(content) &&
90
+ content.some(block => isRecord(block) && block.type === 'tool_result')
91
+ })
92
+ }