ummaya 0.2.4 → 0.2.6

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 (482) hide show
  1. package/README.md +15 -2
  2. package/bin/ummaya +10 -1
  3. package/bun.lock +180 -244
  4. package/npm-shrinkwrap.json +760 -1760
  5. package/package.json +39 -22
  6. package/prompts/manifest.yaml +1 -1
  7. package/prompts/system_v1.md +1 -0
  8. package/pyproject.toml +27 -2
  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/_canonical/baselines.yaml +113 -0
  12. package/src/ummaya/engine/engine.py +29 -132
  13. package/src/ummaya/evidence/__init__.py +21 -2
  14. package/src/ummaya/evidence/dataset_contract.py +193 -0
  15. package/src/ummaya/evidence/document_authoring_cases.py +33 -0
  16. package/src/ummaya/evidence/document_harness.py +313 -0
  17. package/src/ummaya/evidence/document_viewer_ux.py +391 -0
  18. package/src/ummaya/evidence/gates.py +70 -0
  19. package/src/ummaya/evidence/json_types.py +20 -0
  20. package/src/ummaya/evidence/models.py +88 -1
  21. package/src/ummaya/evidence/output_payload.py +89 -0
  22. package/src/ummaya/evidence/payload_documents.py +233 -0
  23. package/src/ummaya/evidence/route_contracts.py +224 -0
  24. package/src/ummaya/evidence/route_helpers.py +150 -0
  25. package/src/ummaya/evidence/runner.py +81 -212
  26. package/src/ummaya/evidence/source_provenance.py +246 -0
  27. package/src/ummaya/evidence/source_provenance_redaction.py +176 -0
  28. package/src/ummaya/evidence/tool_layer.py +39 -0
  29. package/src/ummaya/evidence/tool_layer_models.py +151 -0
  30. package/src/ummaya/ipc/adapter_manifest_emitter.py +26 -10
  31. package/src/ummaya/ipc/document_intent_normalization.py +185 -0
  32. package/src/ummaya/ipc/frame_schema.py +5 -5
  33. package/src/ummaya/ipc/route_diagnostics.py +73 -0
  34. package/src/ummaya/ipc/stdio.py +1109 -477
  35. package/src/ummaya/llm/client.py +102 -3
  36. package/src/ummaya/llm/config.py +8 -3
  37. package/src/ummaya/primitives/__init__.py +6 -2
  38. package/src/ummaya/primitives/delegation.py +1 -1
  39. package/src/ummaya/primitives/document.py +28 -0
  40. package/src/ummaya/settings.py +0 -3
  41. package/src/ummaya/tools/discovery_bridge.py +17 -1
  42. package/src/ummaya/tools/documents/__init__.py +297 -0
  43. package/src/ummaya/tools/documents/adapter_registry.py +487 -0
  44. package/src/ummaya/tools/documents/archive_container_probe.py +167 -0
  45. package/src/ummaya/tools/documents/artifact_store.py +454 -0
  46. package/src/ummaya/tools/documents/authoring.py +283 -0
  47. package/src/ummaya/tools/documents/baselines.py +132 -0
  48. package/src/ummaya/tools/documents/capability.py +331 -0
  49. package/src/ummaya/tools/documents/contracts.py +112 -0
  50. package/src/ummaya/tools/documents/conversion.py +521 -0
  51. package/src/ummaya/tools/documents/diff.py +275 -0
  52. package/src/ummaya/tools/documents/engines.py +163 -0
  53. package/src/ummaya/tools/documents/evaluation.py +291 -0
  54. package/src/ummaya/tools/documents/explicit_values.py +108 -0
  55. package/src/ummaya/tools/documents/fixtures.py +174 -0
  56. package/src/ummaya/tools/documents/format_completion_audit.py +471 -0
  57. package/src/ummaya/tools/documents/formats/__init__.py +2 -0
  58. package/src/ummaya/tools/documents/formats/archive.py +528 -0
  59. package/src/ummaya/tools/documents/formats/base.py +41 -0
  60. package/src/ummaya/tools/documents/formats/code_file.py +211 -0
  61. package/src/ummaya/tools/documents/formats/data_file.py +272 -0
  62. package/src/ummaya/tools/documents/formats/hwp.py +284 -0
  63. package/src/ummaya/tools/documents/formats/hwpx.py +1837 -0
  64. package/src/ummaya/tools/documents/formats/odf.py +435 -0
  65. package/src/ummaya/tools/documents/formats/ooxml.py +1030 -0
  66. package/src/ummaya/tools/documents/formats/passive.py +766 -0
  67. package/src/ummaya/tools/documents/formats/pdf.py +702 -0
  68. package/src/ummaya/tools/documents/formats/text_web.py +268 -0
  69. package/src/ummaya/tools/documents/hwp_conversion_probe.py +178 -0
  70. package/src/ummaya/tools/documents/hwp_direct_candidate.py +141 -0
  71. package/src/ummaya/tools/documents/inspection.py +289 -0
  72. package/src/ummaya/tools/documents/intake.py +1079 -0
  73. package/src/ummaya/tools/documents/legacy_office_promotion_probe.py +366 -0
  74. package/src/ummaya/tools/documents/models.py +1598 -0
  75. package/src/ummaya/tools/documents/odf_promotion_probe.py +167 -0
  76. package/src/ummaya/tools/documents/orchestrator.py +96 -0
  77. package/src/ummaya/tools/documents/passive_capability_probe.py +251 -0
  78. package/src/ummaya/tools/documents/patch.py +170 -0
  79. package/src/ummaya/tools/documents/pdfa_conformance.py +284 -0
  80. package/src/ummaya/tools/documents/pdfa_promotion_probe.py +198 -0
  81. package/src/ummaya/tools/documents/permissions.py +110 -0
  82. package/src/ummaya/tools/documents/planner.py +616 -0
  83. package/src/ummaya/tools/documents/registry.py +2733 -0
  84. package/src/ummaya/tools/documents/render.py +978 -0
  85. package/src/ummaya/tools/documents/render_comparison.py +113 -0
  86. package/src/ummaya/tools/documents/render_comparison_models.py +74 -0
  87. package/src/ummaya/tools/documents/render_comparison_regions.py +73 -0
  88. package/src/ummaya/tools/documents/render_comparison_style.py +161 -0
  89. package/src/ummaya/tools/documents/reread.py +157 -0
  90. package/src/ummaya/tools/documents/runtime_authoring.py +244 -0
  91. package/src/ummaya/tools/documents/runtime_authoring_bundle.py +76 -0
  92. package/src/ummaya/tools/documents/scorecard.py +184 -0
  93. package/src/ummaya/tools/documents/socratic_planner.py +193 -0
  94. package/src/ummaya/tools/documents/style.py +48 -0
  95. package/src/ummaya/tools/documents/tool_defs.py +523 -0
  96. package/src/ummaya/tools/documents/validate.py +347 -0
  97. package/src/ummaya/tools/executor.py +29 -0
  98. package/src/ummaya/tools/live_proxy.py +0 -3
  99. package/src/ummaya/tools/models.py +5 -1
  100. package/src/ummaya/tools/register_all.py +8 -0
  101. package/src/ummaya/tools/registry.py +10 -1
  102. package/src/ummaya/tools/routing/__init__.py +59 -0
  103. package/src/ummaya/tools/routing/builder.py +105 -0
  104. package/src/ummaya/tools/routing/cards.py +29 -0
  105. package/src/ummaya/tools/routing/decision_service.py +534 -0
  106. package/src/ummaya/tools/routing/decision_types.py +74 -0
  107. package/src/ummaya/tools/routing/feasibility.py +122 -0
  108. package/src/ummaya/tools/routing/intent.py +17 -0
  109. package/src/ummaya/tools/routing/intent_extractor.py +207 -0
  110. package/src/ummaya/tools/routing/intent_patterns.py +160 -0
  111. package/src/ummaya/tools/routing/intent_public_data.py +150 -0
  112. package/src/ummaya/tools/routing/intent_types.py +48 -0
  113. package/src/ummaya/tools/routing/lint.py +78 -0
  114. package/src/ummaya/tools/routing/metadata.py +174 -0
  115. package/src/ummaya/tools/routing/projection.py +340 -0
  116. package/src/ummaya/tools/routing/retrieval_policy.py +629 -0
  117. package/src/ummaya/tools/routing/schema.py +81 -0
  118. package/src/ummaya/tools/routing/types.py +96 -0
  119. package/src/ummaya/tools/routing_index.py +2 -2
  120. package/src/ummaya/tools/search.py +34 -746
  121. package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
  122. package/tui/bun.lock +126 -305
  123. package/tui/package.json +35 -22
  124. package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
  125. package/tui/src/QueryEngine.ts +12 -8
  126. package/tui/src/bridge/inboundAttachments.ts +3 -3
  127. package/tui/src/cli/handlers/auth.ts +3 -12
  128. package/tui/src/cli/handlers/mcp.tsx +0 -1
  129. package/tui/src/cli/print.ts +8 -9
  130. package/tui/src/commands/insights.ts +1 -1
  131. package/tui/src/commands/install-github-app/types.ts +8 -30
  132. package/tui/src/commands/plugin/types.ts +6 -28
  133. package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
  134. package/tui/src/commands/rename/generateSessionName.ts +1 -1
  135. package/tui/src/components/Feedback.tsx +1 -1
  136. package/tui/src/components/LogoV2/EmergencyTip.tsx +11 -2
  137. package/tui/src/components/LogoV2/WelcomeV2.tsx +1 -3
  138. package/tui/src/components/ScrollKeybindingHandler.tsx +6 -6
  139. package/tui/src/components/Spinner/types.ts +6 -28
  140. package/tui/src/components/agents/generateAgent.ts +1 -1
  141. package/tui/src/components/agents/new-agent-creation/types.ts +4 -26
  142. package/tui/src/components/config/EnvSecretIsolatedEditor.tsx +1 -1
  143. package/tui/src/components/mcp/types.ts +16 -38
  144. package/tui/src/components/messages/AssistantToolUseMessage.tsx +3 -2
  145. package/tui/src/components/messages/UserCrossSessionMessage.ts +16 -4
  146. package/tui/src/components/messages/UserForkBoilerplateMessage.ts +16 -4
  147. package/tui/src/components/messages/UserGitHubWebhookMessage.ts +16 -4
  148. package/tui/src/components/messages/UserToolResultMessage/utils.tsx +3 -2
  149. package/tui/src/components/permissions/MonitorPermissionRequest/MonitorPermissionRequest.ts +9 -4
  150. package/tui/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.ts +9 -4
  151. package/tui/src/components/primitive/DocumentSocraticReviewBlock.tsx +129 -0
  152. package/tui/src/components/primitive/DocumentToolResultCard.tsx +224 -0
  153. package/tui/src/components/primitive/documentSocraticReview.ts +215 -0
  154. package/tui/src/components/primitive/index.tsx +43 -1
  155. package/tui/src/components/primitive/types.ts +137 -0
  156. package/tui/src/components/ui/option.ts +4 -26
  157. package/tui/src/constants/common.ts +0 -2
  158. package/tui/src/constants/prompts.ts +4 -3
  159. package/tui/src/constants/querySource.ts +4 -26
  160. package/tui/src/entrypoints/sdk/controlTypes.ts +26 -48
  161. package/tui/src/entrypoints/sdk/coreTypes.generated.ts +3 -25
  162. package/tui/src/entrypoints/sdk/runtimeTypes.ts +38 -60
  163. package/tui/src/entrypoints/sdk/sdkUtilityTypes.ts +4 -26
  164. package/tui/src/entrypoints/sdk/settingsTypes.generated.ts +3 -25
  165. package/tui/src/entrypoints/sdk/toolTypes.ts +3 -25
  166. package/tui/src/hooks/toolPermission/handlers/interactiveHandler.ts +10 -0
  167. package/tui/src/hooks/useApiKeyVerification.ts +1 -1
  168. package/tui/src/hooks/useVirtualScroll.ts +1 -1
  169. package/tui/src/ink/ink.tsx +33 -14
  170. package/tui/src/ink/reconciler.ts +2 -3
  171. package/tui/src/ink/render-to-screen.ts +30 -10
  172. package/tui/src/ipc/bridge.ts +62 -15
  173. package/tui/src/ipc/bridgeSingleton.ts +5 -1
  174. package/tui/src/ipc/codec.ts +3 -3
  175. package/tui/src/ipc/frames.generated.ts +12 -12
  176. package/tui/src/ipc/llmClient.ts +151 -27
  177. package/tui/src/ipc/schema/frame.schema.json +1 -1
  178. package/tui/src/keybindings/defaultBindings.ts +4 -0
  179. package/tui/src/main.tsx +32 -15
  180. package/tui/src/native-ts/file-index/index.ts +33 -3
  181. package/tui/src/observability/surface.ts +2 -2
  182. package/tui/src/probes/toolRegistryProbe.tsx +3 -1
  183. package/tui/src/projectOnboardingState.ts +7 -6
  184. package/tui/src/query/chatMessageTypes.ts +18 -0
  185. package/tui/src/query/chatMessagesBuilder.ts +1 -1
  186. package/tui/src/query/deps.ts +1 -1
  187. package/tui/src/query/messageGuards.ts +106 -0
  188. package/tui/src/query/publicDataTerminalRepair.ts +384 -0
  189. package/tui/src/query/run.ts +1075 -0
  190. package/tui/src/query/supportBoundary.ts +168 -0
  191. package/tui/src/query/toolResultErrors.ts +103 -0
  192. package/tui/src/query/toolRunner.ts +687 -0
  193. package/tui/src/query/unavailableToolRepair.ts +118 -0
  194. package/tui/src/query.ts +9 -2186
  195. package/tui/src/screens/REPL.tsx +40 -29
  196. package/tui/src/services/api/adapterManifest.ts +4 -0
  197. package/tui/src/services/api/backendChat/events.ts +117 -0
  198. package/tui/src/services/api/backendChat/finalMessage.ts +40 -0
  199. package/tui/src/services/api/backendChat/frame.ts +9 -0
  200. package/tui/src/services/api/backendChat/streaming.ts +430 -0
  201. package/tui/src/services/api/backendChat/types.ts +62 -0
  202. package/tui/src/services/api/backendChat.ts +1 -0
  203. package/tui/src/services/api/client.ts +65 -2
  204. package/tui/src/services/api/errorUtils.ts +5 -5
  205. package/tui/src/services/api/errors.ts +1 -1
  206. package/tui/src/services/api/logging.ts +1 -1
  207. package/tui/src/services/api/ummaya/evidence.ts +194 -0
  208. package/tui/src/services/api/ummaya/messages.ts +255 -0
  209. package/tui/src/services/api/ummaya/nonStreaming.ts +66 -0
  210. package/tui/src/services/api/ummaya/provider.ts +200 -0
  211. package/tui/src/services/api/ummaya/reasoning.ts +24 -0
  212. package/tui/src/services/api/ummaya/request.ts +200 -0
  213. package/tui/src/services/api/ummaya/selectionContext.ts +240 -0
  214. package/tui/src/services/api/ummaya/streaming.ts +365 -0
  215. package/tui/src/services/api/ummaya/streamingPayload.ts +129 -0
  216. package/tui/src/services/api/ummaya/streamingReader.ts +40 -0
  217. package/tui/src/services/api/ummaya/toolSelection.ts +217 -0
  218. package/tui/src/services/api/ummaya/types.ts +110 -0
  219. package/tui/src/services/api/ummaya/usage.ts +30 -0
  220. package/tui/src/services/api/ummaya.ts +26 -418
  221. package/tui/src/services/api/withRetry.ts +1 -1
  222. package/tui/src/services/awaySummary.ts +2 -2
  223. package/tui/src/services/claudeAiLimits.ts +1 -1
  224. package/tui/src/services/compact/autoCompact.ts +1 -1
  225. package/tui/src/services/compact/compact.ts +1 -1
  226. package/tui/src/services/lsp/types.ts +8 -30
  227. package/tui/src/services/tips/types.ts +6 -28
  228. package/tui/src/services/tokenEstimation.ts +1 -1
  229. package/tui/src/services/toolRegistry/bootGuard.ts +5 -5
  230. package/tui/src/services/toolUseSummary/toolUseSummaryGenerator.ts +1 -1
  231. package/tui/src/services/tools/toolExecution.ts +94 -1
  232. package/tui/src/store/pendingPermissionSlot.ts +1 -1
  233. package/tui/src/store/session-store.ts +10 -36
  234. package/tui/src/stubs/any-stub.ts +15 -10
  235. package/tui/src/stubs/color-diff-napi.ts +37 -23
  236. package/tui/src/stubs/globals.d.ts +3 -3
  237. package/tui/src/stubs/macro-preload.ts +23 -12
  238. package/tui/src/tools/AdapterTool/AdapterTool.ts +1207 -714
  239. package/tui/src/tools/AdapterTool/routeDiagnostics.ts +75 -0
  240. package/tui/src/tools/AgentTool/AgentTool.tsx +84 -1371
  241. package/tui/src/tools/AgentTool/agentToolHandoff.ts +114 -0
  242. package/tui/src/tools/AgentTool/agentToolPartialResult.ts +16 -0
  243. package/tui/src/tools/AgentTool/agentToolProgress.ts +32 -0
  244. package/tui/src/tools/AgentTool/agentToolResolver.ts +161 -0
  245. package/tui/src/tools/AgentTool/agentToolResult.ts +163 -0
  246. package/tui/src/tools/AgentTool/agentToolUtils.ts +14 -686
  247. package/tui/src/tools/AgentTool/asyncAgentLifecycle.ts +208 -0
  248. package/tui/src/tools/AgentTool/asyncLifecycle.ts +153 -0
  249. package/tui/src/tools/AgentTool/backgroundedCompletion.ts +126 -0
  250. package/tui/src/tools/AgentTool/backgroundedLifecycle.ts +174 -0
  251. package/tui/src/tools/AgentTool/foregroundBackground.ts +83 -0
  252. package/tui/src/tools/AgentTool/foregroundDrain.tsx +133 -0
  253. package/tui/src/tools/AgentTool/foregroundFinalize.ts +98 -0
  254. package/tui/src/tools/AgentTool/foregroundLifecycle.tsx +237 -0
  255. package/tui/src/tools/AgentTool/foregroundProgress.tsx +169 -0
  256. package/tui/src/tools/AgentTool/foregroundTask.ts +89 -0
  257. package/tui/src/tools/AgentTool/forkSubagent.ts +1 -12
  258. package/tui/src/tools/AgentTool/forkSubagentGate.ts +34 -0
  259. package/tui/src/tools/AgentTool/launchRouting.ts +203 -0
  260. package/tui/src/tools/AgentTool/lifecycle.ts +244 -0
  261. package/tui/src/tools/AgentTool/mcpRouting.ts +73 -0
  262. package/tui/src/tools/AgentTool/orchestrationSupport.ts +70 -0
  263. package/tui/src/tools/AgentTool/permissions.ts +39 -0
  264. package/tui/src/tools/AgentTool/promptSetup.ts +181 -0
  265. package/tui/src/tools/AgentTool/remoteRouting.ts +62 -0
  266. package/tui/src/tools/AgentTool/resultMapping.ts +116 -0
  267. package/tui/src/tools/AgentTool/resumeAgent.ts +39 -107
  268. package/tui/src/tools/AgentTool/resumeAgentHelpers.ts +140 -0
  269. package/tui/src/tools/AgentTool/runAgent.ts +1 -1
  270. package/tui/src/tools/AgentTool/runtimeConfig.ts +57 -0
  271. package/tui/src/tools/AgentTool/schemas.ts +196 -0
  272. package/tui/src/tools/AgentTool/sourceVerificationPropagation.ts +263 -0
  273. package/tui/src/tools/AgentTool/worktreeLifecycle.ts +105 -0
  274. package/tui/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +174 -202
  275. package/tui/src/tools/BashTool/BashTool.tsx +71 -1072
  276. package/tui/src/tools/BashTool/bashCommandHelpers.ts +12 -12
  277. package/tui/src/tools/BashTool/bashPermissions/astPreflight.ts +173 -0
  278. package/tui/src/tools/BashTool/bashPermissions/classifierChecks.ts +199 -0
  279. package/tui/src/tools/BashTool/bashPermissions/compoundGuards.ts +53 -0
  280. package/tui/src/tools/BashTool/bashPermissions/constants.ts +99 -0
  281. package/tui/src/tools/BashTool/bashPermissions/index.ts +38 -0
  282. package/tui/src/tools/BashTool/bashPermissions/legacyMisparsing.ts +62 -0
  283. package/tui/src/tools/BashTool/bashPermissions/main.ts +135 -0
  284. package/tui/src/tools/BashTool/bashPermissions/normalizedCommands.ts +33 -0
  285. package/tui/src/tools/BashTool/bashPermissions/operatorFlow.ts +98 -0
  286. package/tui/src/tools/BashTool/bashPermissions/permissionChecks.ts +200 -0
  287. package/tui/src/tools/BashTool/bashPermissions/prefixSuggestions.ts +88 -0
  288. package/tui/src/tools/BashTool/bashPermissions/promptClassifierRules.ts +125 -0
  289. package/tui/src/tools/BashTool/bashPermissions/ruleDelegates.ts +19 -0
  290. package/tui/src/tools/BashTool/bashPermissions/ruleMatching.ts +145 -0
  291. package/tui/src/tools/BashTool/bashPermissions/sandboxAutoAllow.ts +75 -0
  292. package/tui/src/tools/BashTool/bashPermissions/subcommandFlow.ts +205 -0
  293. package/tui/src/tools/BashTool/bashPermissions/subcommandGuards.ts +73 -0
  294. package/tui/src/tools/BashTool/bashPermissions/subcommandResultHelpers.ts +116 -0
  295. package/tui/src/tools/BashTool/bashPermissions/types.ts +26 -0
  296. package/tui/src/tools/BashTool/bashPermissions/wrapperStripping.ts +139 -0
  297. package/tui/src/tools/BashTool/bashPermissions.ts +26 -2621
  298. package/tui/src/tools/BashTool/call.ts +202 -0
  299. package/tui/src/tools/BashTool/callLoader.ts +35 -0
  300. package/tui/src/tools/BashTool/commandClassification.ts +151 -0
  301. package/tui/src/tools/BashTool/commandClassificationLoader.ts +40 -0
  302. package/tui/src/tools/BashTool/cwdReset.ts +33 -0
  303. package/tui/src/tools/BashTool/lineTruncation.ts +11 -0
  304. package/tui/src/tools/BashTool/modeValidation.ts +13 -1
  305. package/tui/src/tools/BashTool/outputPersistence.ts +42 -0
  306. package/tui/src/tools/BashTool/permissionClassification.ts +66 -0
  307. package/tui/src/tools/BashTool/permissionLoader.ts +44 -0
  308. package/tui/src/tools/BashTool/resultLoader.ts +29 -0
  309. package/tui/src/tools/BashTool/resultMapping.ts +83 -0
  310. package/tui/src/tools/BashTool/sandboxPolicy.ts +79 -0
  311. package/tui/src/tools/BashTool/schemas.ts +65 -0
  312. package/tui/src/tools/BashTool/sedEditExecution.ts +59 -0
  313. package/tui/src/tools/BashTool/shellExecution.tsx +245 -0
  314. package/tui/src/tools/BashTool/shellOutputUtils.ts +85 -0
  315. package/tui/src/tools/BashTool/shellPermissionGauntlet.ts +97 -0
  316. package/tui/src/tools/BashTool/uiLoader.ts +37 -0
  317. package/tui/src/tools/BriefTool/upload.ts +1 -1
  318. package/tui/src/tools/CalculatorTool/parser.ts +2 -2
  319. package/tui/src/tools/DocumentPrimitive/DocumentPrimitive.ts +262 -0
  320. package/tui/src/tools/DocumentPrimitive/dispatchNormalization.ts +270 -0
  321. package/tui/src/tools/DocumentPrimitive/documentDestinationPath.ts +18 -0
  322. package/tui/src/tools/DocumentPrimitive/documentMutationGuard.ts +22 -0
  323. package/tui/src/tools/DocumentPrimitive/documentPatchNormalization.ts +248 -0
  324. package/tui/src/tools/DocumentPrimitive/documentSourceVerification.ts +245 -0
  325. package/tui/src/tools/DocumentPrimitive/documentSourceVerificationFields.ts +103 -0
  326. package/tui/src/tools/DocumentPrimitive/modelVisibleOutput.ts +40 -0
  327. package/tui/src/tools/DocumentPrimitive/prompt.ts +35 -0
  328. package/tui/src/tools/FileEditTool/FileEditTool.ts +9 -507
  329. package/tui/src/tools/FileEditTool/call.ts +228 -0
  330. package/tui/src/tools/FileEditTool/validateInput.ts +196 -0
  331. package/tui/src/tools/FileReadTool/imageProcessor.ts +13 -0
  332. package/tui/src/tools/FileWriteTool/FileWriteTool.ts +7 -300
  333. package/tui/src/tools/FileWriteTool/call.ts +223 -0
  334. package/tui/src/tools/FileWriteTool/validateInput.ts +80 -0
  335. package/tui/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +19 -3
  336. package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +25 -32
  337. package/tui/src/tools/LookupPrimitive/prompt.ts +0 -2
  338. package/tui/src/tools/MCPTool/trustPolicy.ts +118 -0
  339. package/tui/src/tools/McpAuthTool/McpAuthTool.ts +21 -3
  340. package/tui/src/tools/NotebookEditTool/NotebookEditTool.ts +7 -326
  341. package/tui/src/tools/NotebookEditTool/call.ts +254 -0
  342. package/tui/src/tools/NotebookEditTool/notebookModel.ts +51 -0
  343. package/tui/src/tools/NotebookEditTool/validateInput.ts +142 -0
  344. package/tui/src/tools/PowerShellTool/PowerShellTool.tsx +46 -937
  345. package/tui/src/tools/PowerShellTool/acceptEditsCommandValidation.ts +162 -0
  346. package/tui/src/tools/PowerShellTool/call.ts +179 -0
  347. package/tui/src/tools/PowerShellTool/callLoader.ts +37 -0
  348. package/tui/src/tools/PowerShellTool/commandClassification.ts +86 -0
  349. package/tui/src/tools/PowerShellTool/modeValidation.ts +25 -332
  350. package/tui/src/tools/PowerShellTool/outputPersistence.ts +42 -0
  351. package/tui/src/tools/PowerShellTool/permissionClassification.ts +28 -0
  352. package/tui/src/tools/PowerShellTool/resultLoader.ts +31 -0
  353. package/tui/src/tools/PowerShellTool/resultMapping.ts +75 -0
  354. package/tui/src/tools/PowerShellTool/schemas.ts +40 -0
  355. package/tui/src/tools/PowerShellTool/shellExecution.tsx +258 -0
  356. package/tui/src/tools/PowerShellTool/symlinkModeValidation.ts +44 -0
  357. package/tui/src/tools/PowerShellTool/uiLoader.ts +37 -0
  358. package/tui/src/tools/PowerShellTool/validation.ts +39 -0
  359. package/tui/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +19 -3
  360. package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +1 -11
  361. package/tui/src/tools/ResolveLocationPrimitive/prompt.ts +2 -6
  362. package/tui/src/tools/SkillTool/SkillTool.ts +2 -2
  363. package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +27 -10
  364. package/tui/src/tools/TaskCreateTool/TaskCreateTool.ts +16 -2
  365. package/tui/src/tools/TaskGetTool/TaskGetTool.ts +23 -3
  366. package/tui/src/tools/TaskListTool/TaskListTool.ts +22 -4
  367. package/tui/src/tools/TaskOutputTool/TaskOutputTool.tsx +46 -547
  368. package/tui/src/tools/TaskOutputTool/lookup.ts +216 -0
  369. package/tui/src/tools/TaskOutputTool/render.tsx +257 -0
  370. package/tui/src/tools/TaskOutputTool/schemas.ts +55 -0
  371. package/tui/src/tools/TaskOutputTool/serialization.ts +36 -0
  372. package/tui/src/tools/TaskStopTool/TaskStopTool.ts +10 -0
  373. package/tui/src/tools/TaskUpdateTool/TaskUpdateTool.ts +14 -364
  374. package/tui/src/tools/TaskUpdateTool/completion.ts +62 -0
  375. package/tui/src/tools/TaskUpdateTool/schemas.ts +62 -0
  376. package/tui/src/tools/TaskUpdateTool/serialization.ts +46 -0
  377. package/tui/src/tools/TaskUpdateTool/statusUpdate.ts +247 -0
  378. package/tui/src/tools/TodoWriteTool/TodoWriteTool.ts +21 -2
  379. package/tui/src/tools/ToolSearchTool/ToolSearchTool.ts +21 -302
  380. package/tui/src/tools/ToolSearchTool/ccSupportTools.ts +223 -0
  381. package/tui/src/tools/ToolSearchTool/descriptionCache.ts +50 -0
  382. package/tui/src/tools/ToolSearchTool/keywordSearch.ts +216 -0
  383. package/tui/src/tools/ToolSearchTool/prompt.ts +10 -4
  384. package/tui/src/tools/ToolSearchTool/resultMapping.ts +30 -0
  385. package/tui/src/tools/ToolSearchTool/schemas.ts +30 -0
  386. package/tui/src/tools/ToolSearchTool/searchPool.ts +47 -0
  387. package/tui/src/tools/ToolSearchTool/supportIntentHints.ts +140 -0
  388. package/tui/src/tools/TranslateTool/TranslateTool.ts +1 -1
  389. package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +2 -1
  390. package/tui/src/tools/WebFetchTool/WebFetchTool.ts +43 -138
  391. package/tui/src/tools/WebFetchTool/call.ts +227 -0
  392. package/tui/src/tools/WebFetchTool/resolvedAddressSafety.ts +78 -0
  393. package/tui/src/tools/WebFetchTool/sourceVerification.ts +204 -0
  394. package/tui/src/tools/WebFetchTool/types.ts +23 -0
  395. package/tui/src/tools/WebFetchTool/urlSafety.ts +181 -0
  396. package/tui/src/tools/WebFetchTool/utils.ts +1 -1
  397. package/tui/src/tools/WebSearchTool/UI.tsx +0 -1
  398. package/tui/src/tools/WebSearchTool/WebSearchTool.ts +9 -313
  399. package/tui/src/tools/WebSearchTool/call.ts +33 -0
  400. package/tui/src/tools/WebSearchTool/responseMapping.ts +190 -0
  401. package/tui/src/tools/WebSearchTool/resultBlock.ts +47 -0
  402. package/tui/src/tools/WebSearchTool/schemas.ts +47 -0
  403. package/tui/src/tools/WebSearchTool/toolSchema.ts +12 -0
  404. package/tui/src/tools/WorkspaceToolAdapter/WorkspaceToolAdapter.ts +79 -0
  405. package/tui/src/tools/WorkspaceToolAdapter/allowedRootPolicy.ts +85 -0
  406. package/tui/src/tools/WorkspaceToolAdapter/documentFormatGuards.ts +73 -0
  407. package/tui/src/tools/WorkspaceToolAdapter/inputNormalization.ts +105 -0
  408. package/tui/src/tools/WorkspaceToolAdapter/mcpExposurePolicy.ts +64 -0
  409. package/tui/src/tools/WorkspaceToolAdapter/toolDefFactory.ts +215 -0
  410. package/tui/src/tools/WorkspaceToolAdapter/toolNames.ts +6 -0
  411. package/tui/src/tools/WorkspaceToolAdapter/workspacePolicy.ts +15 -0
  412. package/tui/src/tools/_shared/dispatchPrimitive.ts +6 -6
  413. package/tui/src/tools/_shared/documentChangeToPatch.ts +125 -0
  414. package/tui/src/tools/_shared/documentDispatchArguments.ts +87 -0
  415. package/tui/src/tools/_shared/documentPrimitiveTimeout.ts +13 -0
  416. package/tui/src/tools/_shared/documentToolResultRender.ts +98 -0
  417. package/tui/src/tools/_shared/pendingCallRegistry.ts +1 -6
  418. package/tui/src/tools/_shared/rootPrimitiveInput.ts +1 -0
  419. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPatterns.ts +58 -0
  420. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPrompt.ts +271 -0
  421. package/tui/src/tools/_shared/toolChoiceRepair/documentRepair.ts +452 -0
  422. package/tui/src/tools/_shared/toolChoiceRepair/messageAccess.ts +80 -0
  423. package/tui/src/tools/_shared/toolChoiceRepair/publicDataRepair.ts +92 -0
  424. package/tui/src/tools/_shared/toolChoiceRepair/supportRepair.ts +135 -0
  425. package/tui/src/tools/_shared/toolChoiceRepair.ts +55 -860
  426. package/tui/src/tools/shared/mockDisclaimer.ts +1 -1
  427. package/tui/src/tools.ts +39 -190
  428. package/tui/src/types/fileSuggestion.ts +4 -26
  429. package/tui/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +186 -148
  430. package/tui/src/types/generated/events_mono/common/v1/auth.ts +25 -11
  431. package/tui/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +47 -30
  432. package/tui/src/types/generated/google/protobuf/timestamp.ts +21 -7
  433. package/tui/src/types/message.ts +80 -102
  434. package/tui/src/types/messageQueueTypes.ts +6 -28
  435. package/tui/src/types/notebook.ts +16 -38
  436. package/tui/src/types/statusLine.ts +4 -26
  437. package/tui/src/types/tools.ts +24 -46
  438. package/tui/src/types/utils.ts +6 -28
  439. package/tui/src/upstreamproxy/relay.ts +7 -3
  440. package/tui/src/upstreamproxy/upstreamproxy.ts +1 -1
  441. package/tui/src/utils/assistantMessageFactories.ts +9 -3
  442. package/tui/src/utils/auth.ts +129 -139
  443. package/tui/src/utils/bash/ast.ts +23 -23
  444. package/tui/src/utils/bash/bashParser.ts +5 -5
  445. package/tui/src/utils/billing.ts +1 -1
  446. package/tui/src/utils/claudeDesktop.ts +4 -4
  447. package/tui/src/utils/collapseReadSearch.ts +3 -3
  448. package/tui/src/utils/cronTasks.ts +1 -1
  449. package/tui/src/utils/execFileNoThrow.ts +1 -1
  450. package/tui/src/utils/filePersistence/types.ts +16 -38
  451. package/tui/src/utils/forkedAgent.ts +1 -1
  452. package/tui/src/utils/gracefulShutdown.ts +4 -4
  453. package/tui/src/utils/heapDumpService.ts +12 -8
  454. package/tui/src/utils/hooks/apiQueryHookHelper.ts +1 -1
  455. package/tui/src/utils/hooks/execPromptHook.ts +1 -1
  456. package/tui/src/utils/hooks/skillImprovement.ts +1 -1
  457. package/tui/src/utils/mcp/dateTimeParser.ts +1 -1
  458. package/tui/src/utils/messages.ts +18 -0
  459. package/tui/src/utils/migrateSessions.ts +3 -3
  460. package/tui/src/utils/model/model.ts +6 -6
  461. package/tui/src/utils/permissions/yoloClassifier.ts +1 -1
  462. package/tui/src/utils/plugins/headlessPluginInstall.ts +1 -1
  463. package/tui/src/utils/plugins/mcpPluginIntegration.ts +1 -1
  464. package/tui/src/utils/plugins/mcpbHandler.ts +1 -1
  465. package/tui/src/utils/plugins/pluginLoader.ts +8 -8
  466. package/tui/src/utils/protectedNamespace.ts +5 -3
  467. package/tui/src/utils/rawJsonToolCall.ts +242 -0
  468. package/tui/src/utils/ripgrep.ts +16 -7
  469. package/tui/src/utils/sessionTitle.ts +1 -1
  470. package/tui/src/utils/settings/permissionValidation.ts +14 -2
  471. package/tui/src/utils/shell/prefix.ts +1 -1
  472. package/tui/src/utils/sideQuery.ts +1 -1
  473. package/tui/src/utils/systemThemeWatcher.ts +13 -3
  474. package/tui/src/utils/teleport.tsx +1 -1
  475. package/uv.lock +426 -45
  476. package/tui/src/services/api/claude.ts +0 -3540
  477. package/tui/src/tools/_shared/directPublicDataGuard.ts +0 -362
  478. package/tui/src/tools/_shared/kmaAnalysisGuard.ts +0 -197
  479. package/tui/src/tools/_shared/kmaAviationGuard.ts +0 -70
  480. package/tui/src/tools/_shared/nmcAedGuard.ts +0 -234
  481. package/tui/src/tools/_shared/protectedCheckGuard.ts +0 -207
  482. package/tui/src/tools/_shared/textToolCallGuard.ts +0 -91
@@ -34,9 +34,8 @@ if (process.env.NODE_ENV === 'development') {
34
34
  try {
35
35
  // eslint-disable-next-line custom-rules/no-top-level-dynamic-import -- dev-only; NODE_ENV check is DCE'd in production
36
36
  void import('./devtools.js')
37
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
- } catch (error: any) {
39
- if (error.code === 'ERR_MODULE_NOT_FOUND') {
37
+ } catch (error: unknown) {
38
+ if (error instanceof Error && 'code' in error && error.code === 'ERR_MODULE_NOT_FOUND') {
40
39
  // biome-ignore lint/suspicious/noConsole: intentional warning
41
40
  console.warn(
42
41
  `
@@ -45,6 +45,31 @@ let output: Output | undefined
45
45
  const timing = { reconcile: 0, yoga: 0, paint: 0, scan: 0, calls: 0 }
46
46
  const LOG_EVERY = 20
47
47
 
48
+ type SearchRendererContainer = ReturnType<typeof reconciler.createContainer>
49
+ type SearchReconcilerRuntime = typeof reconciler & {
50
+ createContainer(
51
+ root: DOMElement,
52
+ tag: typeof LegacyRoot,
53
+ hydrationCallbacks: null,
54
+ isStrictMode: boolean,
55
+ concurrentUpdatesByDefaultOverride: null,
56
+ identifierPrefix: string,
57
+ onUncaughtError: () => void,
58
+ onCaughtError: () => void,
59
+ onRecoverableError: () => void,
60
+ onDefaultTransitionIndicator: () => void,
61
+ ): SearchRendererContainer
62
+ updateContainerSync(
63
+ element: ReactElement | null,
64
+ container: SearchRendererContainer,
65
+ parentComponent: null,
66
+ callback: () => void,
67
+ ): void
68
+ flushSyncWork(): void
69
+ }
70
+
71
+ const searchReconciler = reconciler as SearchReconcilerRuntime
72
+
48
73
  /** Render a React element (wrapped in all contexts the component needs —
49
74
  * caller's job) to an isolated Screen buffer at the given width. Returns
50
75
  * the Screen + natural height (from yoga). Used for search: render ONE
@@ -66,8 +91,7 @@ export function renderToScreen(
66
91
  stylePool = new StylePool()
67
92
  charPool = new CharPool()
68
93
  hyperlinkPool = new HyperlinkPool()
69
- // @ts-expect-error react-reconciler 0.33 takes 10 args; @types says 11
70
- container = reconciler.createContainer(
94
+ container = searchReconciler.createContainer(
71
95
  root,
72
96
  LegacyRoot,
73
97
  null,
@@ -82,10 +106,8 @@ export function renderToScreen(
82
106
  }
83
107
 
84
108
  const t0 = performance.now()
85
- // @ts-expect-error updateContainerSync exists but not in @types
86
- reconciler.updateContainerSync(el, container, null, noop)
87
- // @ts-expect-error flushSyncWork exists but not in @types
88
- reconciler.flushSyncWork()
109
+ searchReconciler.updateContainerSync(el, container, null, noop)
110
+ searchReconciler.flushSyncWork()
89
111
  const t1 = performance.now()
90
112
 
91
113
  // Yoga layout. Root might not have a yogaNode if the tree is empty.
@@ -117,10 +139,8 @@ export function renderToScreen(
117
139
  const t3 = performance.now()
118
140
 
119
141
  // Unmount so next call gets a fresh tree. Leaves root/container/pools.
120
- // @ts-expect-error updateContainerSync exists but not in @types
121
- reconciler.updateContainerSync(null, container, null, noop)
122
- // @ts-expect-error flushSyncWork exists but not in @types
123
- reconciler.flushSyncWork()
142
+ searchReconciler.updateContainerSync(null, container, null, noop)
143
+ searchReconciler.flushSyncWork()
124
144
 
125
145
  timing.reconcile += t1 - t0
126
146
  timing.yoga += t2 - t1
@@ -255,6 +255,14 @@ class AsyncQueue<T> {
255
255
  this._resolve = resolve
256
256
  })
257
257
  },
258
+ return: (): Promise<IteratorResult<T>> => {
259
+ if (this._resolve) {
260
+ const r = this._resolve
261
+ this._resolve = null
262
+ r({ value: undefined as unknown as T, done: true })
263
+ }
264
+ return Promise.resolve({ value: undefined as unknown as T, done: true })
265
+ },
258
266
  }
259
267
  }
260
268
  }
@@ -339,13 +347,19 @@ export function createBridge(opts: BridgeOptions = {}): IPCBridge {
339
347
  let _tuiSessionToken: string | null = opts.tuiSessionToken ?? null
340
348
  let _lastSeenCorrelationId: string | null = null
341
349
  let _lastSeenFrameSeq: number | null = null
342
- // Bounded ring of applied (session_id, frame_seq) keys for replay-dedup.
343
- // Cap mirrors the backend SessionRingBuffer size (Spec 032: 256 frames);
344
- // oldest entries are evicted via FIFO replacement so the Set cannot grow
345
- // unbounded across long sessions.
350
+ // Bounded rings for replay de-duplication.
351
+ //
352
+ // `applied_frame_seqs` remains the public debug surface expected by the
353
+ // resume tests. The actual skip decision uses a fuller frame identity below:
354
+ // some TUI-owned tool_call result paths are not ring-stamped by the backend
355
+ // yet and legally arrive with the default frame_seq=0. Dropping by
356
+ // session:frame_seq alone loses distinct tool_result frames in ordinary
357
+ // runtime, which is worse than replay duplication.
346
358
  const _APPLIED_FRAME_SEQS_CAP = 256
347
359
  const _appliedFrameSeqs = new Set<string>()
348
360
  const _appliedFrameSeqsOrder: string[] = []
361
+ const _appliedFrameIdentities = new Set<string>()
362
+ const _appliedFrameIdentitiesOrder: string[] = []
349
363
 
350
364
  // ------------------------------------------------------------------
351
365
  // Spawn first process
@@ -435,6 +449,40 @@ export function createBridge(opts: BridgeOptions = {}): IPCBridge {
435
449
  }
436
450
  }
437
451
 
452
+ function _frameReplayIdentity(frame: IPCFrame): string | null {
453
+ if (frame.frame_seq == null) return null
454
+ const sessionKey = frame.session_id ?? _sessionId
455
+ if (!sessionKey) return null
456
+ return [
457
+ sessionKey,
458
+ frame.frame_seq,
459
+ frame.kind,
460
+ frame.correlation_id ?? '',
461
+ frame.transaction_id ?? '',
462
+ ].join(':')
463
+ }
464
+
465
+ function _rememberAppliedFrameIdentity(identity: string): void {
466
+ _appliedFrameIdentities.add(identity)
467
+ _appliedFrameIdentitiesOrder.push(identity)
468
+ if (_appliedFrameIdentitiesOrder.length > _APPLIED_FRAME_SEQS_CAP) {
469
+ const evicted = _appliedFrameIdentitiesOrder.shift()
470
+ if (evicted !== undefined) _appliedFrameIdentities.delete(evicted)
471
+ }
472
+ }
473
+
474
+ function _rememberAppliedFrameSeq(frame: IPCFrame): void {
475
+ if (!_sessionId || frame.frame_seq == null) return
476
+ const key = `${frame.session_id ?? _sessionId}:${frame.frame_seq}`
477
+ if (_appliedFrameSeqs.has(key)) return
478
+ _appliedFrameSeqs.add(key)
479
+ _appliedFrameSeqsOrder.push(key)
480
+ if (_appliedFrameSeqsOrder.length > _APPLIED_FRAME_SEQS_CAP) {
481
+ const evicted = _appliedFrameSeqsOrder.shift()
482
+ if (evicted !== undefined) _appliedFrameSeqs.delete(evicted)
483
+ }
484
+ }
485
+
438
486
  async function _doReconnect(): Promise<void> {
439
487
  if (_closed || _reconnecting) return
440
488
  _reconnecting = true
@@ -536,22 +584,21 @@ export function createBridge(opts: BridgeOptions = {}): IPCBridge {
536
584
  _lastSeenCorrelationId = frame.correlation_id
537
585
  }
538
586
 
539
- // De-duplicate replayed frames (applied_frame_seqs set)
540
- if (_sessionId && frame.frame_seq != null) {
541
- const key = `${frame.session_id ?? _sessionId}:${frame.frame_seq}`
542
- if (_appliedFrameSeqs.has(key)) {
587
+ // De-duplicate replayed frames by full frame identity. Do not
588
+ // use session:frame_seq as the skip key: TUI-owned tool_result
589
+ // frames can currently share the default frame_seq=0 while still
590
+ // being separate, valid results.
591
+ const replayIdentity = _frameReplayIdentity(frame)
592
+ if (replayIdentity !== null) {
593
+ if (_appliedFrameIdentities.has(replayIdentity)) {
543
594
  _log(
544
595
  'DEBUG',
545
- `Skipping duplicate replay frame session=${frame.session_id} frame_seq=${frame.frame_seq}`,
596
+ `Skipping duplicate replay frame identity=${replayIdentity}`,
546
597
  )
547
598
  continue
548
599
  }
549
- _appliedFrameSeqs.add(key)
550
- _appliedFrameSeqsOrder.push(key)
551
- if (_appliedFrameSeqsOrder.length > _APPLIED_FRAME_SEQS_CAP) {
552
- const evicted = _appliedFrameSeqsOrder.shift()
553
- if (evicted !== undefined) _appliedFrameSeqs.delete(evicted)
554
- }
600
+ _rememberAppliedFrameIdentity(replayIdentity)
601
+ _rememberAppliedFrameSeq(frame)
555
602
  }
556
603
 
557
604
  _log('DEBUG', `recv kind=${frame.kind} session=${frame.session_id}`)
@@ -11,6 +11,7 @@
11
11
  // prompt is actually typed. Subsequent turns reuse the running child.
12
12
 
13
13
  import { createBridge, type IPCBridge } from './bridge.js'
14
+ import { getSessionId } from '../bootstrap/state.js'
14
15
  import {
15
16
  ingestManifestFrame,
16
17
  waitForManifestSync,
@@ -36,7 +37,9 @@ let _pluginsModifiedThisSession = false
36
37
 
37
38
  export function getOrCreateUmmayaBridge(): IPCBridge {
38
39
  if (_bridge !== null) return _bridge
40
+ const sessionId = getUmmayaBridgeSessionId()
39
41
  _bridge = createBridge({
42
+ sessionId,
40
43
  // Epic ε #2296 T010 — route adapter_manifest_sync frames to the TS-side
41
44
  // manifest cache on receipt (before any LLM turn, at backend boot time).
42
45
  // FR-015: fires once per backend lifecycle; FR-016: replace-on-frame
@@ -69,7 +72,7 @@ export async function ensureUmmayaAdapterManifest(
69
72
 
70
73
  export function getUmmayaBridgeSessionId(): string {
71
74
  if (_sessionId === null) {
72
- _sessionId = crypto.randomUUID()
75
+ _sessionId = getSessionId()
73
76
  }
74
77
  return _sessionId
75
78
  }
@@ -104,4 +107,5 @@ export async function closeUmmayaBridge(): Promise<void> {
104
107
  await b.close()
105
108
  }
106
109
  _pluginsModifiedThisSession = false
110
+ _sessionId = null
107
111
  }
@@ -158,7 +158,7 @@ const ToolCallFrameSchema = BaseFrame.extend({
158
158
  })
159
159
 
160
160
  const ToolResultEnvelopeSchema = z.object({
161
- kind: z.enum(['find', 'locate', 'send', 'check']),
161
+ kind: z.enum(['find', 'locate', 'send', 'check', 'document']),
162
162
  }).passthrough()
163
163
 
164
164
  const ToolResultFrameSchema = BaseFrame.extend({
@@ -176,7 +176,7 @@ const WorkerStatusFrameSchema = BaseFrame.extend({
176
176
  kind: z.literal('worker_status'),
177
177
  worker_id: z.string(),
178
178
  role_id: z.string(),
179
- current_primitive: z.enum(['find', 'locate', 'send', 'check']),
179
+ current_primitive: z.enum(['find', 'locate', 'send', 'check', 'document']),
180
180
  status: z.enum(['idle', 'running', 'waiting_permission', 'error']),
181
181
  })
182
182
 
@@ -184,7 +184,7 @@ const PermissionRequestFrameSchema = BaseFrame.extend({
184
184
  kind: z.literal('permission_request'),
185
185
  request_id: z.string(),
186
186
  worker_id: z.string(),
187
- primitive_kind: z.enum(['find', 'locate', 'send', 'check']),
187
+ primitive_kind: z.enum(['find', 'locate', 'send', 'check', 'document']),
188
188
  description_ko: z.string(),
189
189
  description_en: z.string(),
190
190
  risk_level: z.enum(['low', 'medium', 'high']),
@@ -381,7 +381,7 @@ export type CallId2 = string;
381
381
  /**
382
382
  * Primitive kind discriminator per Spec 031.
383
383
  */
384
- export type Kind6 = 'find' | 'locate' | 'send' | 'check';
384
+ export type Kind6 = 'find' | 'locate' | 'send' | 'check' | 'document';
385
385
  /**
386
386
  * Opaque session identifier.
387
387
  */
@@ -461,7 +461,7 @@ export type RoleId = string;
461
461
  /**
462
462
  * Primitive currently being invoked by this worker.
463
463
  */
464
- export type CurrentPrimitive = 'find' | 'locate' | 'send' | 'check';
464
+ export type CurrentPrimitive = 'find' | 'locate' | 'send' | 'check' | 'document';
465
465
  /**
466
466
  * Worker execution status.
467
467
  */
@@ -509,7 +509,7 @@ export type WorkerId1 = string;
509
509
  /**
510
510
  * The primitive the worker wants to invoke.
511
511
  */
512
- export type PrimitiveKind = 'find' | 'locate' | 'send' | 'check';
512
+ export type PrimitiveKind = 'find' | 'locate' | 'send' | 'check' | 'document';
513
513
  /**
514
514
  * Korean-language description shown to the citizen.
515
515
  */
@@ -573,7 +573,7 @@ export type ReceiptId = string | null;
573
573
  /**
574
574
  * The primitive that was authorised. The TUI feeds this into `aalToLayer(primitive, isIrreversible)` to recompute the gauntlet layer (1=green / 2=orange / 3=red) for the receipt row. None on deny / timeout / legacy backends.
575
575
  */
576
- export type PrimitiveKind1 = ('find' | 'locate' | 'send' | 'check') | null;
576
+ export type PrimitiveKind1 = ('find' | 'locate' | 'send' | 'check' | 'document') | null;
577
577
  /**
578
578
  * The fully-qualified adapter id (e.g. `mock_verify_mobile_id`, `mock_submit_welfare_grant`) the citizen authorised. The TUI uses this to render the human-readable Korean adapter name in /consent list and the modal title. None for non-adapter primitives (rare) or legacy backends.
579
579
  */
@@ -1200,7 +1200,7 @@ export type Name5 = string;
1200
1200
  /**
1201
1201
  * Primitive verb the adapter is registered under (I6).
1202
1202
  */
1203
- export type Primitive = 'find' | 'send' | 'check' | 'locate';
1203
+ export type Primitive = 'find' | 'send' | 'check' | 'locate' | 'document';
1204
1204
  /**
1205
1205
  * Agency-published policy URL (HTTPS). None only when source_mode == 'internal' (I4/I5).
1206
1206
  */
@@ -1442,7 +1442,7 @@ export interface ToolDefinitionFunction {
1442
1442
  * JSON Schema (Draft 2020-12) for the tool input. Pydantic accepts any dict shape; deeper schema validation is delegated to LLMClient.
1443
1443
  */
1444
1444
  export interface Parameters {
1445
- [k: string]: any;
1445
+ [k: string]: unknown;
1446
1446
  }
1447
1447
  /**
1448
1448
  * backend -> TUI: streaming assistant text delta.
@@ -1527,7 +1527,7 @@ export interface ToolCallFrame {
1527
1527
  * Tool-specific arguments. Concrete adapter calls carry adapter schema fields directly.
1528
1528
  */
1529
1529
  export interface Arguments1 {
1530
- [k: string]: any;
1530
+ [k: string]: unknown;
1531
1531
  }
1532
1532
  /**
1533
1533
  * backend -> TUI (render): the output of a tool invocation.
@@ -1553,7 +1553,7 @@ export interface ToolResultFrame {
1553
1553
  */
1554
1554
  export interface ToolResultEnvelope {
1555
1555
  kind: Kind6;
1556
- [k: string]: any;
1556
+ [k: string]: unknown;
1557
1557
  }
1558
1558
  /**
1559
1559
  * backend -> TUI: Spec 027 coordinator phase update.
@@ -1663,7 +1663,7 @@ export interface SessionEventFrame {
1663
1663
  * Event-specific payload. For list: {sessions: [{id, created_at, turn_count}]}. For resume: {id: str}. For others: {}.
1664
1664
  */
1665
1665
  export interface Payload {
1666
- [k: string]: any;
1666
+ [k: string]: unknown;
1667
1667
  }
1668
1668
  /**
1669
1669
  * backend -> TUI: a backend error surfaced to the TUI for rendering.
@@ -1689,7 +1689,7 @@ export interface ErrorFrame {
1689
1689
  * Structured error details. UMMAYA_* env var values MUST be redacted.
1690
1690
  */
1691
1691
  export interface Details {
1692
- [k: string]: any;
1692
+ [k: string]: unknown;
1693
1693
  }
1694
1694
  /**
1695
1695
  * Begins a streamed payload (assistant output, tool result chunking).
@@ -2020,13 +2020,13 @@ export interface AdapterManifestEntry {
2020
2020
  * Full backend Pydantic JSON Schema for adapter input parameters. Credential-only fields such as authKey must be omitted by adapters.
2021
2021
  */
2022
2022
  export interface InputSchemaJson {
2023
- [k: string]: any;
2023
+ [k: string]: unknown;
2024
2024
  }
2025
2025
  /**
2026
2026
  * Full backend Pydantic JSON Schema for adapter output data.
2027
2027
  */
2028
2028
  export interface OutputSchemaJson {
2029
- [k: string]: any;
2029
+ [k: string]: unknown;
2030
2030
  }
2031
2031
  /**
2032
2032
  * TUI -> backend: citizen requests revocation of a prior consent receipt.
@@ -29,8 +29,13 @@ import type {
29
29
  UmmayaContentBlockParam,
30
30
  UmmayaStopReason,
31
31
  } from './llmTypes.js'
32
+ import {
33
+ extractTextualToolCallProposals,
34
+ parseTrailingRawJsonToolCallProposal,
35
+ } from '../utils/rawJsonToolCall.js'
32
36
 
33
37
  export const UMMAYA_DEFAULT_MODEL = 'LGAI-EXAONE/K-EXAONE-236B-A23B'
38
+ const TEXTUAL_TOOL_CALL_OPEN = '<tool_call>'
34
39
 
35
40
  export type LLMClientErrorClass = 'llm' | 'tool' | 'network'
36
41
 
@@ -78,6 +83,9 @@ const _tracer = trace.getTracer('ummaya.tui.llm', '0.1.0')
78
83
  interface _TurnAccumulator {
79
84
  messageId: string | null
80
85
  contentBlocks: UmmayaContentBlockParam[]
86
+ accumulatedText: string
87
+ emittedTextLength: number
88
+ shouldBufferTextDeltas: boolean
81
89
  usage: UmmayaUsage
82
90
  stopReason: UmmayaStopReason
83
91
  /** Index of the current text block. It is opened lazily on the first
@@ -105,6 +113,9 @@ function _defaultAccumulator(): _TurnAccumulator {
105
113
  return {
106
114
  messageId: null,
107
115
  contentBlocks: [],
116
+ accumulatedText: '',
117
+ emittedTextLength: 0,
118
+ shouldBufferTextDeltas: false,
108
119
  usage: { input_tokens: 0, output_tokens: 0 },
109
120
  stopReason: 'end_turn',
110
121
  blockIndex: -1,
@@ -115,13 +126,21 @@ function _defaultAccumulator(): _TurnAccumulator {
115
126
  }
116
127
  }
117
128
 
129
+ function firstToolCallTextOffset(text: string): number {
130
+ const braceOffset = text.indexOf('{')
131
+ const tagOffset = text.indexOf(TEXTUAL_TOOL_CALL_OPEN)
132
+ if (braceOffset < 0) return tagOffset
133
+ if (tagOffset < 0) return braceOffset
134
+ return Math.min(braceOffset, tagOffset)
135
+ }
136
+
118
137
  // ---------------------------------------------------------------------------
119
138
  // Helper: extract usage from an AssistantChunkFrame done-trailer.
120
139
  //
121
140
  // Spec 032 does not currently define a typed usage payload on the frame itself;
122
141
  // the Python backend is expected to embed usage counts in the frame's `trailer`
123
142
  // extra fields or in a sibling ephemeral dict. Until the backend-side contract
124
- // is finalised in Spec 032 US4, we read from `(frame as any).usage` first
143
+ // is finalised in Spec 032 US4, we read from the typed legacy `usage` field first
125
144
  // (a forward-compatible extension field the backend may include) and fall back
126
145
  // to zeros. A TODO(T091) marks the binding point for the actual backend wiring.
127
146
  // ---------------------------------------------------------------------------
@@ -417,6 +436,103 @@ export class LLMClient {
417
436
  } satisfies UmmayaRawMessageStreamEvent
418
437
  }
419
438
 
439
+ const appendVisibleTextDelta = function* (
440
+ text: string,
441
+ previousTextLength: number,
442
+ ): Generator<UmmayaRawMessageStreamEvent, void, unknown> {
443
+ if (text.length === 0) return
444
+ yield* ensureTextBlock()
445
+ yield {
446
+ type: 'content_block_delta',
447
+ index: acc.blockIndex,
448
+ delta: { type: 'text_delta', text },
449
+ } satisfies UmmayaRawMessageStreamEvent
450
+
451
+ const existing = acc.contentBlocks[acc.blockIndex]
452
+ if (existing && existing.type === 'text') {
453
+ existing.text += text
454
+ } else {
455
+ acc.contentBlocks[acc.blockIndex] = { type: 'text', text }
456
+ }
457
+ acc.emittedTextLength = previousTextLength + text.length
458
+ }
459
+
460
+ const appendAssistantText = function* (
461
+ text: string,
462
+ ): Generator<UmmayaRawMessageStreamEvent, void, unknown> {
463
+ if (text.length === 0) return
464
+ const previousTextLength = acc.accumulatedText.length
465
+ const bufferOffset = firstToolCallTextOffset(text)
466
+ const startsBuffering = !acc.shouldBufferTextDeltas && bufferOffset >= 0
467
+ if (startsBuffering) acc.shouldBufferTextDeltas = true
468
+ acc.accumulatedText += text
469
+ if (startsBuffering) {
470
+ if (bufferOffset > 0) {
471
+ yield* appendVisibleTextDelta(
472
+ text.slice(0, bufferOffset),
473
+ previousTextLength,
474
+ )
475
+ }
476
+ return
477
+ }
478
+ if (!acc.shouldBufferTextDeltas) {
479
+ yield* appendVisibleTextDelta(text, previousTextLength)
480
+ }
481
+ }
482
+
483
+ const flushBufferedText = function* (): Generator<
484
+ UmmayaRawMessageStreamEvent,
485
+ void,
486
+ unknown
487
+ > {
488
+ if (acc.accumulatedText.length <= acc.emittedTextLength) return
489
+ yield* appendVisibleTextDelta(
490
+ acc.accumulatedText.slice(acc.emittedTextLength),
491
+ acc.emittedTextLength,
492
+ )
493
+ }
494
+
495
+ const flushPreludeBeforeRawJsonToolUse = function* (
496
+ prelude: string,
497
+ ): Generator<UmmayaRawMessageStreamEvent, void, unknown> {
498
+ if (prelude.length <= acc.emittedTextLength) return
499
+ yield* appendVisibleTextDelta(
500
+ prelude.slice(acc.emittedTextLength),
501
+ acc.emittedTextLength,
502
+ )
503
+ }
504
+
505
+ const appendRawJsonToolUseBlock = function* (params: {
506
+ readonly name: string
507
+ readonly input: Record<string, unknown>
508
+ readonly id?: string
509
+ }): Generator<UmmayaRawMessageStreamEvent, void, unknown> {
510
+ const toolBlockIndex = acc.contentBlocks.length
511
+ acc.toolBlockCounter += 1
512
+ const toolUseId = params.id ?? 'call_raw_json_tool_0'
513
+ yield {
514
+ type: 'content_block_start',
515
+ index: toolBlockIndex,
516
+ content_block: {
517
+ type: 'tool_use',
518
+ id: toolUseId,
519
+ name: params.name,
520
+ input: params.input,
521
+ },
522
+ } satisfies UmmayaRawMessageStreamEvent
523
+ yield {
524
+ type: 'content_block_stop',
525
+ index: toolBlockIndex,
526
+ } satisfies UmmayaRawMessageStreamEvent
527
+ acc.contentBlocks[toolBlockIndex] = {
528
+ type: 'tool_use',
529
+ id: toolUseId,
530
+ name: params.name,
531
+ input: params.input,
532
+ }
533
+ acc.stopReason = 'tool_use'
534
+ }
535
+
420
536
  for await (const frame of this.bridge.frames()) {
421
537
  // Filter: only process frames for this turn's correlation_id.
422
538
  if (frame.correlation_id !== correlationId) continue
@@ -483,21 +599,7 @@ export class LLMClient {
483
599
 
484
600
  // Emit text delta (even if delta is empty — forward compat).
485
601
  if (chunk.delta.length > 0) {
486
- yield* ensureTextBlock()
487
- yield {
488
- type: 'content_block_delta',
489
- index: acc.blockIndex,
490
- delta: { type: 'text_delta', text: chunk.delta },
491
- } satisfies UmmayaRawMessageStreamEvent
492
-
493
- // Accumulate text into the content block for the final object.
494
- const existing = acc.contentBlocks[acc.blockIndex]
495
- if (existing && existing.type === 'text') {
496
- existing.text += chunk.delta
497
- } else {
498
- // First delta for this block index.
499
- acc.contentBlocks[acc.blockIndex] = { type: 'text', text: chunk.delta }
500
- }
602
+ yield* appendAssistantText(chunk.delta)
501
603
  }
502
604
  } else {
503
605
  // done=true: terminal chunk (V2 invariant satisfied here).
@@ -510,18 +612,37 @@ export class LLMClient {
510
612
 
511
613
  // Emit any final delta text if present.
512
614
  if (chunk.delta.length > 0) {
513
- yield* ensureTextBlock()
514
- yield {
515
- type: 'content_block_delta',
516
- index: acc.blockIndex,
517
- delta: { type: 'text_delta', text: chunk.delta },
518
- } satisfies UmmayaRawMessageStreamEvent
519
- const existing = acc.contentBlocks[acc.blockIndex]
520
- if (existing && existing.type === 'text') {
521
- existing.text += chunk.delta
522
- } else {
523
- acc.contentBlocks[acc.blockIndex] = { type: 'text', text: chunk.delta }
615
+ yield* appendAssistantText(chunk.delta)
616
+ }
617
+
618
+ const textualToolUse = extractTextualToolCallProposals({
619
+ text: acc.accumulatedText,
620
+ })
621
+ const rawJsonToolUse = textualToolUse === undefined
622
+ ? parseTrailingRawJsonToolCallProposal({
623
+ text: acc.accumulatedText,
624
+ })
625
+ : undefined
626
+ if (textualToolUse !== undefined || rawJsonToolUse !== undefined) {
627
+ const prelude = textualToolUse?.text ?? rawJsonToolUse?.prelude ?? ''
628
+ yield* flushPreludeBeforeRawJsonToolUse(prelude)
629
+ yield* closeOpenBlock()
630
+ const proposals = textualToolUse?.proposals ??
631
+ (rawJsonToolUse !== undefined ? [rawJsonToolUse.proposal] : [])
632
+ for (let index = 0; index < proposals.length; index += 1) {
633
+ const proposal = proposals[index]
634
+ if (!proposal) continue
635
+ yield* appendRawJsonToolUseBlock({
636
+ name: proposal.name,
637
+ input: proposal.input,
638
+ id: textualToolUse !== undefined
639
+ ? `call_textual_tool_${index}`
640
+ : 'call_raw_json_tool_0',
641
+ })
524
642
  }
643
+ acc.accumulatedText = prelude
644
+ } else if (acc.shouldBufferTextDeltas) {
645
+ yield* flushBufferedText()
525
646
  }
526
647
 
527
648
  // Extract usage from the done-frame.
@@ -557,6 +678,9 @@ export class LLMClient {
557
678
  else if (frame.kind === 'tool_call') {
558
679
  const toolFrame = frame as ToolCallFrame
559
680
  yield* ensureMessageStart(`tool-${correlationId}`)
681
+ if (acc.shouldBufferTextDeltas) {
682
+ yield* flushBufferedText()
683
+ }
560
684
  yield* closeOpenBlock()
561
685
  // tool_call frames may arrive interleaved with text streaming AND
562
686
  // thinking streaming in a multi-turn / parallel-tool / K-EXAONE