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
@@ -0,0 +1,140 @@
1
+ import type { Tool } from '../../Tool.js'
2
+
3
+ const SOURCE_SUPPORT_INTENT_PATTERN =
4
+ /출처|근거|인용|참고\s*문헌|레퍼런스|출전|증빙|증거|자료\s*(?:출처|근거|조사|검색)|최신|현재\s*(?:정보|자료)|웹\s*검색|source|citation|evidence|provenance|reference|bibliography|current\s+(?:information|source|research)|latest|web\s*search|search\s+the\s+web|https?:\/\//iu
5
+
6
+ const MCP_SUPPORT_INTENT_PATTERN =
7
+ /(?:\bmcp\b|mcp__|(?=.*(?:리소스|자원|resources?))(?=.*(?:신뢰\s*경계|신뢰|경계|trust|boundary|connected\s+servers?|서버\s*(?:리소스|자원)|servers?\s+resources?)))/iu
8
+
9
+ const AGENT_SUPPORT_INTENT_PATTERN =
10
+ /에이전트|sub-?agent|agent|별도\s*작업|하위\s*작업|작업자|작업\s*도구|진행\s*상황|취소\s*가능|cancel(?:lable)?\s+task|delegat(?:e|ion)|background\s+task/iu
11
+
12
+ const KOREAN_QUERY_EXPANSIONS: readonly {
13
+ readonly pattern: RegExp
14
+ readonly terms: readonly string[]
15
+ }[] = [
16
+ {
17
+ pattern:
18
+ /(?=.*(?:저장소|작업\s*공간|워크\s*스페이스|로컬|프로젝트|코드\s*베이스|repository|repo|workspace|codebase))(?=.*(?:파일|경로|첫\s*줄|읽|검색|찾|grep|read))/iu,
19
+ terms: ['+workspace', 'local', 'file', 'read', 'grep', 'search'],
20
+ },
21
+ {
22
+ pattern: SOURCE_SUPPORT_INTENT_PATTERN,
23
+ terms: [
24
+ 'web',
25
+ 'search',
26
+ 'current',
27
+ 'information',
28
+ 'fetch',
29
+ 'url',
30
+ 'source',
31
+ 'verification',
32
+ ],
33
+ },
34
+ {
35
+ pattern: MCP_SUPPORT_INTENT_PATTERN,
36
+ terms: ['mcp', 'resources', 'list', 'connected', 'servers'],
37
+ },
38
+ {
39
+ pattern: AGENT_SUPPORT_INTENT_PATTERN,
40
+ terms: ['+agent', 'delegate', 'subagent', 'task', 'cancel', 'progress'],
41
+ },
42
+ {
43
+ pattern: /쉘|셸|명령|터미널|git/iu,
44
+ terms: ['shell', 'bash', 'commands', 'permission', 'blocked'],
45
+ },
46
+ {
47
+ pattern: /쓰기|작성|저장|파일|메모|승인|작업공간/iu,
48
+ terms: ['create', 'overwrite', 'local', 'text', 'files', 'permission', 'blocked'],
49
+ },
50
+ ]
51
+
52
+ const SUPPORT_TOOL_NAMES_BY_PATTERN: readonly {
53
+ readonly pattern: RegExp
54
+ readonly toolNames: readonly string[]
55
+ }[] = [
56
+ {
57
+ pattern:
58
+ /(?=.*(?:저장소|작업\s*공간|워크\s*스페이스|로컬|프로젝트|코드\s*베이스|repository|repo|workspace|codebase))(?=.*(?:파일|경로|첫\s*줄|읽|검색|찾|grep|read))/iu,
59
+ toolNames: ['workspace_grep', 'workspace_read'],
60
+ },
61
+ {
62
+ pattern: SOURCE_SUPPORT_INTENT_PATTERN,
63
+ toolNames: ['WebSearch', 'WebFetch'],
64
+ },
65
+ {
66
+ pattern: MCP_SUPPORT_INTENT_PATTERN,
67
+ toolNames: ['ListMcpResourcesTool'],
68
+ },
69
+ {
70
+ pattern: AGENT_SUPPORT_INTENT_PATTERN,
71
+ toolNames: ['Agent'],
72
+ },
73
+ {
74
+ pattern: /쉘|셸|명령|터미널|git/iu,
75
+ toolNames: ['workspace_bash'],
76
+ },
77
+ {
78
+ pattern: /쓰기|작성|저장|파일|메모|승인|작업공간/iu,
79
+ toolNames: ['workspace_write'],
80
+ },
81
+ ]
82
+
83
+ export function expandedToolSearchTerms(queryLower: string): string[] {
84
+ const terms = queryLower.split(/\s+/).filter(term => term.length > 0)
85
+ for (const expansion of KOREAN_QUERY_EXPANSIONS) {
86
+ if (expansion.pattern.test(queryLower)) {
87
+ terms.push(...expansion.terms)
88
+ }
89
+ }
90
+ return [...new Set(terms)]
91
+ }
92
+
93
+ export function expandedIntentTermSet(queryLower: string): ReadonlySet<string> {
94
+ const expandedTerms: string[] = []
95
+ for (const expansion of KOREAN_QUERY_EXPANSIONS) {
96
+ if (expansion.pattern.test(queryLower)) {
97
+ expandedTerms.push(
98
+ ...expansion.terms.map(term =>
99
+ term.startsWith('+') ? term.slice(1) : term,
100
+ ),
101
+ )
102
+ }
103
+ }
104
+ return new Set(expandedTerms)
105
+ }
106
+
107
+ export function selectRecoveredSupportToolNamesForQuery(
108
+ query: string,
109
+ ): readonly string[] {
110
+ const queryLower = query.toLowerCase()
111
+ const shellIntent = /쉘|셸|명령|터미널|git/iu.test(queryLower)
112
+ const localWorkspaceFileIntent =
113
+ /(?:저장소|작업\s*공간|워크\s*스페이스|로컬|프로젝트|코드\s*베이스|repository|repo|workspace|codebase)/iu.test(
114
+ queryLower,
115
+ ) &&
116
+ /(?:파일|경로|첫\s*줄|읽|검색|찾|grep|read)/iu.test(queryLower)
117
+ if (localWorkspaceFileIntent && !shellIntent) {
118
+ return ['workspace_grep', 'workspace_read']
119
+ }
120
+
121
+ const toolNames: string[] = []
122
+ for (const supportClass of SUPPORT_TOOL_NAMES_BY_PATTERN) {
123
+ if (supportClass.pattern.test(queryLower)) {
124
+ toolNames.push(...supportClass.toolNames)
125
+ }
126
+ }
127
+ return [...new Set(toolNames)]
128
+ }
129
+
130
+ function sanitizeSearchHint(searchHint: string): string {
131
+ return searchHint
132
+ .replace(/[<>]/g, '')
133
+ .replace(/\s+/g, ' ')
134
+ .trim()
135
+ }
136
+
137
+ export function formatDeferredToolSearchLine(tool: Tool): string {
138
+ const searchHint = tool.searchHint ? sanitizeSearchHint(tool.searchHint) : ''
139
+ return searchHint ? `${tool.name} - ${searchHint}` : tool.name
140
+ }
@@ -58,7 +58,7 @@ type OutputSchema = ReturnType<typeof outputSchema>
58
58
  export type Output = z.infer<OutputSchema>
59
59
 
60
60
  // ---------------------------------------------------------------------------
61
- // The UMMAYA model identifier (matches services/api/claude.ts)
61
+ // The UMMAYA model identifier (matches services/api/ummaya.ts)
62
62
  // ---------------------------------------------------------------------------
63
63
 
64
64
  const UMMAYA_MODEL = 'LGAI-EXAONE/K-EXAONE-236B-A23B'
@@ -388,7 +388,8 @@ export const VerifyPrimitive = buildTool({
388
388
  async checkPermissions(_input) {
389
389
  return {
390
390
  behavior: 'ask' as const,
391
- message: 'Permission delegation required: send identity information to the auth provider. Continue?',
391
+ message:
392
+ '권한 위임 필요: 인증 제공자에게 신원 정보를 전달합니다. 계속할까요? / Permission delegation required: send identity information to the auth provider.',
392
393
  }
393
394
  },
394
395
 
@@ -1,10 +1,10 @@
1
1
  import { z } from 'zod/v4'
2
2
  import { buildTool, type ToolDef } from '../../Tool.js'
3
3
  import type { PermissionUpdate } from '../../types/permissions.js'
4
- import { formatFileSize } from '../../utils/format.js'
5
4
  import { lazySchema } from '../../utils/lazySchema.js'
6
5
  import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js'
7
6
  import { getRuleByContentsForTool } from '../../utils/permissions/permissions.js'
7
+ import { callWebFetch } from './call.js'
8
8
  import { isPreapprovedHost } from './preapproved.js'
9
9
  import { DESCRIPTION, WEB_FETCH_TOOL_NAME } from './prompt.js'
10
10
  import {
@@ -14,12 +14,12 @@ import {
14
14
  renderToolUseProgressMessage,
15
15
  } from './UI.js'
16
16
  import {
17
- applyPromptToMarkdown,
18
- type FetchedContent,
19
- getURLMarkdownContent,
20
- isPreapprovedUrl,
21
- MAX_MARKDOWN_LENGTH,
22
- } from './utils.js'
17
+ formatSourceVerifiedToolResult,
18
+ sourceVerificationSchema,
19
+ } from './sourceVerification.js'
20
+ import type { WebFetchOutput } from './types.js'
21
+ import { validateResolvedPublicWebFetchUrl } from './resolvedAddressSafety.js'
22
+ import { validatePublicWebFetchUrl } from './urlSafety.js'
23
23
 
24
24
  const inputSchema = lazySchema(() =>
25
25
  z.strictObject({
@@ -41,42 +41,31 @@ const outputSchema = lazySchema(() =>
41
41
  .number()
42
42
  .describe('Time taken to fetch and process the content'),
43
43
  url: z.string().describe('The URL that was fetched'),
44
+ sourceVerification: sourceVerificationSchema.optional(),
44
45
  }),
45
46
  )
46
47
  type OutputSchema = ReturnType<typeof outputSchema>
47
48
 
48
- export type Output = z.infer<OutputSchema>
49
+ export type Output = WebFetchOutput
49
50
 
50
51
  function webFetchToolInputToPermissionRuleContent(input: {
51
- [k: string]: unknown
52
+ readonly url: string
52
53
  }): string {
53
- try {
54
- const parsedInput = WebFetchTool.inputSchema.safeParse(input)
55
- if (!parsedInput.success) {
56
- return `input:${input.toString()}`
57
- }
58
- const { url } = parsedInput.data
59
- const hostname = new URL(url).hostname
60
- return `domain:${hostname}`
61
- } catch {
62
- return `input:${input.toString()}`
63
- }
54
+ const validation = validatePublicWebFetchUrl(input.url)
55
+ return validation.ok ? `domain:${validation.hostname}` : `input:${input.url}`
64
56
  }
65
57
 
66
58
  export const WebFetchTool = buildTool({
67
59
  name: WEB_FETCH_TOOL_NAME,
68
- searchHint: 'fetch and extract content from a URL',
60
+ searchHint: 'fetch and extract content from a URL for source verification',
69
61
  // 100K chars - tool result persistence threshold
70
62
  maxResultSizeChars: 100_000,
71
63
  shouldDefer: true,
72
64
  async description(input) {
73
- const { url } = input as { url: string }
74
- try {
75
- const hostname = new URL(url).hostname
76
- return `UMMAYA wants to fetch content from ${hostname}`
77
- } catch {
78
- return `UMMAYA wants to fetch content from this URL`
79
- }
65
+ const validation = validatePublicWebFetchUrl(input.url)
66
+ return validation.ok
67
+ ? `UMMAYA wants to fetch content from ${validation.hostname}`
68
+ : `UMMAYA wants to fetch content from this URL`
80
69
  },
81
70
  userFacingName() {
82
71
  return 'Fetch'
@@ -104,20 +93,28 @@ export const WebFetchTool = buildTool({
104
93
  async checkPermissions(input, context): Promise<PermissionDecision> {
105
94
  const appState = context.getAppState()
106
95
  const permissionContext = appState.toolPermissionContext
96
+ const validation = await validateResolvedPublicWebFetchUrl(input.url)
97
+
98
+ if (!validation.ok) {
99
+ return {
100
+ behavior: 'deny',
101
+ message: `${WebFetchTool.name} rejected unsafe URL: ${validation.message}`,
102
+ decisionReason: { type: 'other', reason: validation.reason },
103
+ }
104
+ }
107
105
 
108
106
  // Check if the hostname is in the preapproved list
109
- try {
110
- const { url } = input as { url: string }
111
- const parsedUrl = new URL(url)
112
- if (isPreapprovedHost(parsedUrl.hostname, parsedUrl.pathname)) {
113
- return {
114
- behavior: 'allow',
115
- updatedInput: input,
116
- decisionReason: { type: 'other', reason: 'Preapproved host' },
117
- }
107
+ if (
108
+ isPreapprovedHost(
109
+ validation.parsedUrl.hostname,
110
+ validation.parsedUrl.pathname,
111
+ )
112
+ ) {
113
+ return {
114
+ behavior: 'allow',
115
+ updatedInput: input,
116
+ decisionReason: { type: 'other', reason: 'Preapproved host' },
118
117
  }
119
- } catch {
120
- // If URL parsing fails, continue with normal permission checks
121
118
  }
122
119
 
123
120
  // Check for a rule specific to the tool input (matching hostname)
@@ -190,13 +187,12 @@ ${DESCRIPTION}`
190
187
  },
191
188
  async validateInput(input) {
192
189
  const { url } = input
193
- try {
194
- new URL(url)
195
- } catch {
190
+ const validation = await validateResolvedPublicWebFetchUrl(url)
191
+ if (!validation.ok) {
196
192
  return {
197
193
  result: false,
198
- message: `Error: Invalid URL "${url}". The URL provided could not be parsed.`,
199
- meta: { reason: 'invalid_url' },
194
+ message: `Error: ${validation.message}`,
195
+ meta: { reason: validation.reason },
200
196
  errorCode: 1,
201
197
  }
202
198
  }
@@ -205,103 +201,12 @@ ${DESCRIPTION}`
205
201
  renderToolUseMessage,
206
202
  renderToolUseProgressMessage,
207
203
  renderToolResultMessage,
208
- async call(
209
- { url, prompt },
210
- { abortController, options: { isNonInteractiveSession } },
211
- ) {
212
- const start = Date.now()
213
-
214
- const response = await getURLMarkdownContent(url, abortController)
215
-
216
- // Check if we got a redirect to a different host
217
- if ('type' in response && response.type === 'redirect') {
218
- const statusText =
219
- response.statusCode === 301
220
- ? 'Moved Permanently'
221
- : response.statusCode === 308
222
- ? 'Permanent Redirect'
223
- : response.statusCode === 307
224
- ? 'Temporary Redirect'
225
- : 'Found'
226
-
227
- const message = `REDIRECT DETECTED: The URL redirects to a different host.
228
-
229
- Original URL: ${response.originalUrl}
230
- Redirect URL: ${response.redirectUrl}
231
- Status: ${response.statusCode} ${statusText}
232
-
233
- To complete your request, I need to fetch content from the redirected URL. Please use WebFetch again with these parameters:
234
- - url: "${response.redirectUrl}"
235
- - prompt: "${prompt}"`
236
-
237
- const output: Output = {
238
- bytes: Buffer.byteLength(message),
239
- code: response.statusCode,
240
- codeText: statusText,
241
- result: message,
242
- durationMs: Date.now() - start,
243
- url,
244
- }
245
-
246
- return {
247
- data: output,
248
- }
249
- }
250
-
251
- const {
252
- content,
253
- bytes,
254
- code,
255
- codeText,
256
- contentType,
257
- persistedPath,
258
- persistedSize,
259
- } = response as FetchedContent
260
-
261
- const isPreapproved = isPreapprovedUrl(url)
262
-
263
- let result: string
264
- if (
265
- isPreapproved &&
266
- contentType.includes('text/markdown') &&
267
- content.length < MAX_MARKDOWN_LENGTH
268
- ) {
269
- result = content
270
- } else {
271
- result = await applyPromptToMarkdown(
272
- prompt,
273
- content,
274
- abortController.signal,
275
- isNonInteractiveSession,
276
- isPreapproved,
277
- )
278
- }
279
-
280
- // Binary content (PDFs, etc.) was additionally saved to disk with a
281
- // mime-derived extension. Note it so Claude can inspect the raw file
282
- // if the Haiku summary above isn't enough.
283
- if (persistedPath) {
284
- result += `\n\n[Binary content (${contentType}, ${formatFileSize(persistedSize ?? bytes)}) also saved to ${persistedPath}]`
285
- }
286
-
287
- const output: Output = {
288
- bytes,
289
- code,
290
- codeText,
291
- result,
292
- durationMs: Date.now() - start,
293
- url,
294
- }
295
-
296
- return {
297
- data: output,
298
- }
299
- },
300
- mapToolResultToToolResultBlockParam({ result }, toolUseID) {
204
+ call: callWebFetch,
205
+ mapToolResultToToolResultBlockParam({ result, sourceVerification }, toolUseID) {
301
206
  return {
302
207
  tool_use_id: toolUseID,
303
208
  type: 'tool_result',
304
- content: result,
209
+ content: formatSourceVerifiedToolResult({ result, sourceVerification }),
305
210
  }
306
211
  },
307
212
  } satisfies ToolDef<InputSchema, Output>)
@@ -0,0 +1,227 @@
1
+ import type { ToolResult } from '../../Tool.js'
2
+ import { errorMessage, isAbortError } from '../../utils/errors.js'
3
+ import { formatFileSize } from '../../utils/format.js'
4
+ import { WEB_FETCH_TOOL_NAME } from './prompt.js'
5
+ import {
6
+ buildSourceEvidence,
7
+ buildSourceVerification,
8
+ redactSourceVerificationText,
9
+ } from './sourceVerification.js'
10
+ import type {
11
+ WebFetchCallContext,
12
+ WebFetchCallInput,
13
+ WebFetchOutput,
14
+ } from './types.js'
15
+ import { validateResolvedPublicWebFetchUrl } from './resolvedAddressSafety.js'
16
+ import {
17
+ applyPromptToMarkdown,
18
+ getURLMarkdownContent,
19
+ isPreapprovedUrl,
20
+ MAX_MARKDOWN_LENGTH,
21
+ } from './utils.js'
22
+
23
+ export async function callWebFetch(
24
+ { url, prompt }: WebFetchCallInput,
25
+ { abortController, options: { isNonInteractiveSession } }: WebFetchCallContext,
26
+ ): Promise<ToolResult<WebFetchOutput>> {
27
+ const start = Date.now()
28
+ const validation = await validateResolvedPublicWebFetchUrl(url)
29
+ if (!validation.ok) {
30
+ return blockedToolResult({
31
+ url,
32
+ start,
33
+ message: `Source verification blocked: ${validation.message}`,
34
+ sourceUrl: null,
35
+ title: 'Unsafe URL',
36
+ })
37
+ }
38
+
39
+ try {
40
+ const response = await getURLMarkdownContent(url, abortController)
41
+
42
+ if ('type' in response && response.type === 'redirect') {
43
+ const redirectValidation = await validateResolvedPublicWebFetchUrl(
44
+ response.redirectUrl,
45
+ )
46
+ if (!redirectValidation.ok) {
47
+ return blockedToolResult({
48
+ url,
49
+ start,
50
+ code: response.statusCode,
51
+ codeText: 'Redirect Target Blocked',
52
+ message: `Source verification blocked: ${redirectValidation.message}`,
53
+ sourceUrl: null,
54
+ title: 'Unsafe redirect target',
55
+ })
56
+ }
57
+ return redirectedToolResult({
58
+ url,
59
+ prompt,
60
+ start,
61
+ originalUrl: response.originalUrl,
62
+ redirectUrl: response.redirectUrl,
63
+ statusCode: response.statusCode,
64
+ })
65
+ }
66
+
67
+ const {
68
+ content,
69
+ bytes,
70
+ code,
71
+ codeText,
72
+ contentType,
73
+ persistedPath,
74
+ persistedSize,
75
+ } = response
76
+ const isPreapproved = isPreapprovedUrl(url)
77
+ let result =
78
+ isPreapproved &&
79
+ contentType.includes('text/markdown') &&
80
+ content.length < MAX_MARKDOWN_LENGTH
81
+ ? content
82
+ : await applyPromptToMarkdown(
83
+ prompt,
84
+ content,
85
+ abortController.signal,
86
+ isNonInteractiveSession,
87
+ isPreapproved,
88
+ )
89
+
90
+ if (persistedPath) {
91
+ result += `\n\n[Binary content (${contentType}, ${formatFileSize(persistedSize ?? bytes)}) also saved to ${persistedPath}]`
92
+ }
93
+
94
+ const sourceVerification = buildSourceVerification([
95
+ buildSourceEvidence({
96
+ toolId: WEB_FETCH_TOOL_NAME,
97
+ sourceUrl: url,
98
+ title: contentType,
99
+ blockedOrUsed: 'needs_input',
100
+ rawText: result,
101
+ }),
102
+ ])
103
+ const safeResult = redactSourceVerificationText(result)
104
+
105
+ return {
106
+ data: {
107
+ bytes,
108
+ code,
109
+ codeText,
110
+ result: safeResult,
111
+ durationMs: Date.now() - start,
112
+ url,
113
+ sourceVerification,
114
+ },
115
+ }
116
+ } catch (error) {
117
+ if (isAbortError(error)) throw error
118
+ const message = `Source verification blocked: ${errorMessage(error)}`
119
+ return blockedToolResult({
120
+ url,
121
+ start,
122
+ message,
123
+ sourceUrl: url,
124
+ title: 'Provider error',
125
+ })
126
+ }
127
+ }
128
+
129
+ function redirectedToolResult({
130
+ url,
131
+ prompt,
132
+ start,
133
+ originalUrl,
134
+ redirectUrl,
135
+ statusCode,
136
+ }: {
137
+ readonly url: string
138
+ readonly prompt: string
139
+ readonly start: number
140
+ readonly originalUrl: string
141
+ readonly redirectUrl: string
142
+ readonly statusCode: number
143
+ }): ToolResult<WebFetchOutput> {
144
+ const statusText = redirectStatusText(statusCode)
145
+ const message = `REDIRECT DETECTED: The URL redirects to a different host.
146
+
147
+ Original URL: ${originalUrl}
148
+ Redirect URL: ${redirectUrl}
149
+ Status: ${statusCode} ${statusText}
150
+
151
+ To complete your request, I need to fetch content from the redirected URL. Please use WebFetch again with these parameters:
152
+ - url: "${redirectUrl}"
153
+ - prompt: "${prompt}"`
154
+ const safeMessage = redactSourceVerificationText(message)
155
+
156
+ return {
157
+ data: {
158
+ bytes: Buffer.byteLength(safeMessage),
159
+ code: statusCode,
160
+ codeText: statusText,
161
+ result: safeMessage,
162
+ durationMs: Date.now() - start,
163
+ url,
164
+ sourceVerification: buildSourceVerification([
165
+ buildSourceEvidence({
166
+ toolId: WEB_FETCH_TOOL_NAME,
167
+ sourceUrl: redirectUrl,
168
+ title: 'Redirect target',
169
+ blockedOrUsed: 'needs_input',
170
+ rawText: message,
171
+ }),
172
+ ]),
173
+ },
174
+ }
175
+ }
176
+
177
+ function blockedToolResult({
178
+ url,
179
+ start,
180
+ message,
181
+ sourceUrl,
182
+ title,
183
+ code = 0,
184
+ codeText = 'Source Verification Blocked',
185
+ }: {
186
+ readonly url: string
187
+ readonly start: number
188
+ readonly message: string
189
+ readonly sourceUrl: string | null
190
+ readonly title: string
191
+ readonly code?: number
192
+ readonly codeText?: string
193
+ }): ToolResult<WebFetchOutput> {
194
+ const safeMessage = redactSourceVerificationText(message)
195
+ return {
196
+ data: {
197
+ bytes: Buffer.byteLength(safeMessage),
198
+ code,
199
+ codeText,
200
+ result: safeMessage,
201
+ durationMs: Date.now() - start,
202
+ url,
203
+ sourceVerification: buildSourceVerification([
204
+ buildSourceEvidence({
205
+ toolId: WEB_FETCH_TOOL_NAME,
206
+ sourceUrl,
207
+ title,
208
+ blockedOrUsed: 'blocked',
209
+ rawText: message,
210
+ }),
211
+ ]),
212
+ },
213
+ }
214
+ }
215
+
216
+ function redirectStatusText(statusCode: number): string {
217
+ switch (statusCode) {
218
+ case 301:
219
+ return 'Moved Permanently'
220
+ case 307:
221
+ return 'Temporary Redirect'
222
+ case 308:
223
+ return 'Permanent Redirect'
224
+ default:
225
+ return 'Found'
226
+ }
227
+ }