ummaya 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (534) hide show
  1. package/README.md +17 -3
  2. package/bin/ummaya +10 -1
  3. package/npm-shrinkwrap.json +253 -2
  4. package/package.json +5 -1
  5. package/prompts/manifest.yaml +2 -2
  6. package/prompts/session_guidance_v1.md +3 -1
  7. package/prompts/system_v1.md +9 -7
  8. package/pyproject.toml +26 -7
  9. package/specs/2803-document-production-hardening/contracts/document-tools.schema.json +1043 -0
  10. package/src/ummaya/_canonical/__init__.py +2 -0
  11. package/src/ummaya/context/builder.py +17 -11
  12. package/src/ummaya/engine/engine.py +30 -113
  13. package/src/ummaya/engine/query.py +20 -0
  14. package/src/ummaya/evidence/__init__.py +44 -0
  15. package/src/ummaya/evidence/__main__.py +7 -0
  16. package/src/ummaya/evidence/dataset_contract.py +193 -0
  17. package/src/ummaya/evidence/document_authoring_cases.py +33 -0
  18. package/src/ummaya/evidence/document_harness.py +313 -0
  19. package/src/ummaya/evidence/document_viewer_ux.py +391 -0
  20. package/src/ummaya/evidence/gates.py +70 -0
  21. package/src/ummaya/evidence/json_types.py +20 -0
  22. package/src/ummaya/evidence/models.py +145 -0
  23. package/src/ummaya/evidence/output_payload.py +89 -0
  24. package/src/ummaya/evidence/payload_documents.py +233 -0
  25. package/src/ummaya/evidence/route_contracts.py +224 -0
  26. package/src/ummaya/evidence/route_helpers.py +150 -0
  27. package/src/ummaya/evidence/runner.py +177 -0
  28. package/src/ummaya/evidence/source_provenance.py +246 -0
  29. package/src/ummaya/evidence/source_provenance_redaction.py +176 -0
  30. package/src/ummaya/evidence/task_registry.py +264 -0
  31. package/src/ummaya/evidence/tool_layer.py +39 -0
  32. package/src/ummaya/evidence/tool_layer_models.py +151 -0
  33. package/src/ummaya/ipc/adapter_manifest_emitter.py +26 -10
  34. package/src/ummaya/ipc/document_intent_normalization.py +185 -0
  35. package/src/ummaya/ipc/frame_schema.py +52 -5
  36. package/src/ummaya/ipc/route_diagnostics.py +73 -0
  37. package/src/ummaya/ipc/stdio.py +2282 -417
  38. package/src/ummaya/llm/client.py +234 -59
  39. package/src/ummaya/llm/config.py +8 -3
  40. package/src/ummaya/llm/reasoning.py +84 -0
  41. package/src/ummaya/primitives/__init__.py +6 -2
  42. package/src/ummaya/primitives/delegation.py +1 -1
  43. package/src/ummaya/primitives/document.py +28 -0
  44. package/src/ummaya/settings.py +0 -3
  45. package/src/ummaya/tools/discovery_bridge.py +34 -2
  46. package/src/ummaya/tools/documents/__init__.py +297 -0
  47. package/src/ummaya/tools/documents/adapter_registry.py +487 -0
  48. package/src/ummaya/tools/documents/archive_container_probe.py +167 -0
  49. package/src/ummaya/tools/documents/artifact_store.py +454 -0
  50. package/src/ummaya/tools/documents/authoring.py +283 -0
  51. package/src/ummaya/tools/documents/baselines.py +114 -0
  52. package/src/ummaya/tools/documents/capability.py +331 -0
  53. package/src/ummaya/tools/documents/contracts.py +112 -0
  54. package/src/ummaya/tools/documents/conversion.py +521 -0
  55. package/src/ummaya/tools/documents/diff.py +275 -0
  56. package/src/ummaya/tools/documents/engines.py +163 -0
  57. package/src/ummaya/tools/documents/evaluation.py +291 -0
  58. package/src/ummaya/tools/documents/explicit_values.py +108 -0
  59. package/src/ummaya/tools/documents/fixtures.py +174 -0
  60. package/src/ummaya/tools/documents/format_completion_audit.py +471 -0
  61. package/src/ummaya/tools/documents/formats/__init__.py +2 -0
  62. package/src/ummaya/tools/documents/formats/archive.py +528 -0
  63. package/src/ummaya/tools/documents/formats/base.py +41 -0
  64. package/src/ummaya/tools/documents/formats/code_file.py +211 -0
  65. package/src/ummaya/tools/documents/formats/data_file.py +272 -0
  66. package/src/ummaya/tools/documents/formats/hwp.py +284 -0
  67. package/src/ummaya/tools/documents/formats/hwpx.py +1837 -0
  68. package/src/ummaya/tools/documents/formats/odf.py +435 -0
  69. package/src/ummaya/tools/documents/formats/ooxml.py +1030 -0
  70. package/src/ummaya/tools/documents/formats/passive.py +766 -0
  71. package/src/ummaya/tools/documents/formats/pdf.py +702 -0
  72. package/src/ummaya/tools/documents/formats/text_web.py +268 -0
  73. package/src/ummaya/tools/documents/hwp_conversion_probe.py +178 -0
  74. package/src/ummaya/tools/documents/hwp_direct_candidate.py +141 -0
  75. package/src/ummaya/tools/documents/inspection.py +289 -0
  76. package/src/ummaya/tools/documents/intake.py +1079 -0
  77. package/src/ummaya/tools/documents/legacy_office_promotion_probe.py +366 -0
  78. package/src/ummaya/tools/documents/models.py +1598 -0
  79. package/src/ummaya/tools/documents/odf_promotion_probe.py +167 -0
  80. package/src/ummaya/tools/documents/orchestrator.py +96 -0
  81. package/src/ummaya/tools/documents/passive_capability_probe.py +251 -0
  82. package/src/ummaya/tools/documents/patch.py +170 -0
  83. package/src/ummaya/tools/documents/pdfa_conformance.py +284 -0
  84. package/src/ummaya/tools/documents/pdfa_promotion_probe.py +198 -0
  85. package/src/ummaya/tools/documents/permissions.py +110 -0
  86. package/src/ummaya/tools/documents/planner.py +616 -0
  87. package/src/ummaya/tools/documents/registry.py +2733 -0
  88. package/src/ummaya/tools/documents/render.py +978 -0
  89. package/src/ummaya/tools/documents/render_comparison.py +113 -0
  90. package/src/ummaya/tools/documents/render_comparison_models.py +74 -0
  91. package/src/ummaya/tools/documents/render_comparison_regions.py +73 -0
  92. package/src/ummaya/tools/documents/render_comparison_style.py +161 -0
  93. package/src/ummaya/tools/documents/reread.py +157 -0
  94. package/src/ummaya/tools/documents/runtime_authoring.py +244 -0
  95. package/src/ummaya/tools/documents/runtime_authoring_bundle.py +76 -0
  96. package/src/ummaya/tools/documents/scorecard.py +184 -0
  97. package/src/ummaya/tools/documents/socratic_planner.py +193 -0
  98. package/src/ummaya/tools/documents/style.py +48 -0
  99. package/src/ummaya/tools/documents/tool_defs.py +523 -0
  100. package/src/ummaya/tools/documents/validate.py +347 -0
  101. package/src/ummaya/tools/executor.py +61 -12
  102. package/src/ummaya/tools/geocoding/kakao_client.py +1 -2
  103. package/src/ummaya/tools/kma/apihub_catalog.py +984 -1
  104. package/src/ummaya/tools/kma/apihub_structured_adapter.py +86 -6
  105. package/src/ummaya/tools/kma/apihub_url_adapter.py +593 -0
  106. package/src/ummaya/tools/kma/apihub_url_catalog.py +296 -0
  107. package/src/ummaya/tools/live_proxy.py +0 -3
  108. package/src/ummaya/tools/location_adapters.py +8 -6
  109. package/src/ummaya/tools/manifest_metadata.py +16 -3
  110. package/src/ummaya/tools/models.py +5 -1
  111. package/src/ummaya/tools/mvp_surface.py +2 -2
  112. package/src/ummaya/tools/nmc/emergency_search.py +8 -6
  113. package/src/ummaya/tools/register_all.py +17 -0
  114. package/src/ummaya/tools/registry.py +10 -1
  115. package/src/ummaya/tools/resolve_location.py +4 -4
  116. package/src/ummaya/tools/routing/__init__.py +59 -0
  117. package/src/ummaya/tools/routing/builder.py +105 -0
  118. package/src/ummaya/tools/routing/cards.py +29 -0
  119. package/src/ummaya/tools/routing/decision_service.py +534 -0
  120. package/src/ummaya/tools/routing/decision_types.py +74 -0
  121. package/src/ummaya/tools/routing/feasibility.py +122 -0
  122. package/src/ummaya/tools/routing/intent.py +17 -0
  123. package/src/ummaya/tools/routing/intent_extractor.py +207 -0
  124. package/src/ummaya/tools/routing/intent_patterns.py +160 -0
  125. package/src/ummaya/tools/routing/intent_public_data.py +150 -0
  126. package/src/ummaya/tools/routing/intent_types.py +48 -0
  127. package/src/ummaya/tools/routing/lint.py +78 -0
  128. package/src/ummaya/tools/routing/metadata.py +174 -0
  129. package/src/ummaya/tools/routing/projection.py +340 -0
  130. package/src/ummaya/tools/routing/retrieval_policy.py +629 -0
  131. package/src/ummaya/tools/routing/schema.py +81 -0
  132. package/src/ummaya/tools/routing/types.py +96 -0
  133. package/src/ummaya/tools/routing_index.py +2 -2
  134. package/src/ummaya/tools/search.py +40 -106
  135. package/src/ummaya/tools/verified_data_go_kr/_manifest.py +115 -25
  136. package/src/ummaya/tools/verified_data_go_kr/airkorea_air_quality.py +109 -4
  137. package/src/ummaya/tools/verified_data_go_kr/nmc_aed_site.py +108 -2
  138. package/src/ummaya/tools/verified_data_go_kr/pps_bid_public_info.py +174 -9
  139. package/src/ummaya/tools/verified_data_go_kr/tago_bus_arrival.py +66 -3
  140. package/src/ummaya/tools/verified_data_go_kr/tago_bus_location.py +12 -2
  141. package/src/ummaya/tools/verified_data_go_kr/tago_bus_route.py +8 -2
  142. package/src/ummaya/tools/verified_data_go_kr/tago_bus_route_station.py +114 -0
  143. package/src/ummaya/tools/verified_data_go_kr/tago_bus_station.py +14 -3
  144. package/src/ummaya/tools/verify_canonical_map.py +21 -0
  145. package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
  146. package/tui/package.json +1 -2
  147. package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
  148. package/tui/src/QueryEngine.ts +12 -4
  149. package/tui/src/bridge/inboundAttachments.ts +3 -3
  150. package/tui/src/cli/handlers/auth.ts +4 -13
  151. package/tui/src/cli/handlers/mcp.tsx +3 -3
  152. package/tui/src/cli/print.ts +69 -18
  153. package/tui/src/cli/update.ts +13 -13
  154. package/tui/src/commands/copy/index.ts +1 -1
  155. package/tui/src/commands/cost/cost.ts +2 -2
  156. package/tui/src/commands/init-verifiers.ts +5 -5
  157. package/tui/src/commands/init.ts +30 -30
  158. package/tui/src/commands/insights.ts +44 -44
  159. package/tui/src/commands/install-github-app/install-github-app.tsx +2 -2
  160. package/tui/src/commands/install-github-app/setupGitHubActions.ts +3 -3
  161. package/tui/src/commands/install-github-app/types.ts +8 -30
  162. package/tui/src/commands/install.tsx +5 -5
  163. package/tui/src/commands/mcp/addCommand.ts +5 -5
  164. package/tui/src/commands/mcp/xaaIdpCommand.ts +2 -2
  165. package/tui/src/commands/plugin/ManageMarketplaces.tsx +2 -2
  166. package/tui/src/commands/plugin/types.ts +6 -28
  167. package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
  168. package/tui/src/commands/reasoning/index.ts +13 -0
  169. package/tui/src/commands/reasoning/reasoning.tsx +177 -0
  170. package/tui/src/commands/rename/generateSessionName.ts +1 -1
  171. package/tui/src/commands/thinkback/thinkback.tsx +3 -3
  172. package/tui/src/commands.ts +2 -0
  173. package/tui/src/components/Feedback.tsx +1 -1
  174. package/tui/src/components/LogoV2/EmergencyTip.tsx +11 -2
  175. package/tui/src/components/LogoV2/WelcomeV2.tsx +1 -3
  176. package/tui/src/components/Messages.tsx +2 -1
  177. package/tui/src/components/ScrollKeybindingHandler.tsx +6 -6
  178. package/tui/src/components/Spinner/types.ts +6 -28
  179. package/tui/src/components/Spinner.tsx +2 -2
  180. package/tui/src/components/agents/generateAgent.ts +1 -1
  181. package/tui/src/components/agents/new-agent-creation/types.ts +4 -26
  182. package/tui/src/components/config/EnvSecretIsolatedEditor.tsx +1 -1
  183. package/tui/src/components/design-system/LoadingState.tsx +2 -2
  184. package/tui/src/components/mcp/types.ts +16 -38
  185. package/tui/src/components/messages/AssistantToolUseMessage.tsx +3 -2
  186. package/tui/src/components/messages/UserCrossSessionMessage.ts +16 -4
  187. package/tui/src/components/messages/UserForkBoilerplateMessage.ts +16 -4
  188. package/tui/src/components/messages/UserGitHubWebhookMessage.ts +16 -4
  189. package/tui/src/components/messages/UserToolResultMessage/utils.tsx +3 -2
  190. package/tui/src/components/permissions/MonitorPermissionRequest/MonitorPermissionRequest.ts +9 -4
  191. package/tui/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.ts +9 -4
  192. package/tui/src/components/primitive/DocumentSocraticReviewBlock.tsx +129 -0
  193. package/tui/src/components/primitive/DocumentToolResultCard.tsx +224 -0
  194. package/tui/src/components/primitive/documentSocraticReview.ts +215 -0
  195. package/tui/src/components/primitive/index.tsx +43 -1
  196. package/tui/src/components/primitive/types.ts +137 -0
  197. package/tui/src/components/ui/option.ts +4 -26
  198. package/tui/src/constants/common.ts +0 -2
  199. package/tui/src/constants/prompts.ts +4 -3
  200. package/tui/src/constants/querySource.ts +4 -26
  201. package/tui/src/entrypoints/sdk/controlTypes.ts +26 -48
  202. package/tui/src/entrypoints/sdk/coreTypes.generated.ts +3 -25
  203. package/tui/src/entrypoints/sdk/runtimeTypes.ts +38 -60
  204. package/tui/src/entrypoints/sdk/sdkUtilityTypes.ts +4 -26
  205. package/tui/src/entrypoints/sdk/settingsTypes.generated.ts +3 -25
  206. package/tui/src/entrypoints/sdk/toolTypes.ts +3 -25
  207. package/tui/src/hooks/toolPermission/handlers/interactiveHandler.ts +10 -0
  208. package/tui/src/hooks/useApiKeyVerification.ts +1 -1
  209. package/tui/src/hooks/useVirtualScroll.ts +1 -1
  210. package/tui/src/ink/ink.tsx +33 -14
  211. package/tui/src/ink/reconciler.ts +2 -3
  212. package/tui/src/ink/render-to-screen.ts +30 -10
  213. package/tui/src/ipc/bridge.ts +62 -15
  214. package/tui/src/ipc/bridgeSingleton.ts +5 -1
  215. package/tui/src/ipc/codec.ts +29 -3
  216. package/tui/src/ipc/frames.generated.ts +407 -312
  217. package/tui/src/ipc/llmClient.ts +279 -76
  218. package/tui/src/ipc/llmTypes.ts +16 -1
  219. package/tui/src/ipc/schema/frame.schema.json +1 -3475
  220. package/tui/src/keybindings/defaultBindings.ts +4 -0
  221. package/tui/src/main.tsx +32 -11
  222. package/tui/src/native-ts/file-index/index.ts +33 -3
  223. package/tui/src/observability/surface.ts +2 -2
  224. package/tui/src/probes/toolRegistryProbe.tsx +3 -1
  225. package/tui/src/projectOnboardingState.ts +7 -6
  226. package/tui/src/query/chatMessageTypes.ts +18 -0
  227. package/tui/src/query/chatMessagesBuilder.ts +1 -1
  228. package/tui/src/query/deps.ts +1 -1
  229. package/tui/src/query/messageGuards.ts +106 -0
  230. package/tui/src/query/publicDataTerminalRepair.ts +384 -0
  231. package/tui/src/query/run.ts +1075 -0
  232. package/tui/src/query/supportBoundary.ts +168 -0
  233. package/tui/src/query/toolResultErrors.ts +103 -0
  234. package/tui/src/query/toolRunner.ts +687 -0
  235. package/tui/src/query/unavailableToolRepair.ts +118 -0
  236. package/tui/src/query.ts +9 -1721
  237. package/tui/src/screens/REPL.tsx +42 -31
  238. package/tui/src/services/api/adapterManifest.ts +4 -0
  239. package/tui/src/services/api/backendChat/events.ts +117 -0
  240. package/tui/src/services/api/backendChat/finalMessage.ts +40 -0
  241. package/tui/src/services/api/backendChat/frame.ts +9 -0
  242. package/tui/src/services/api/backendChat/streaming.ts +430 -0
  243. package/tui/src/services/api/backendChat/types.ts +62 -0
  244. package/tui/src/services/api/backendChat.ts +1 -0
  245. package/tui/src/services/api/client.ts +98 -14
  246. package/tui/src/services/api/errorUtils.ts +5 -5
  247. package/tui/src/services/api/errors.ts +1 -1
  248. package/tui/src/services/api/logging.ts +1 -1
  249. package/tui/src/services/api/ummaya/evidence.ts +194 -0
  250. package/tui/src/services/api/ummaya/messages.ts +255 -0
  251. package/tui/src/services/api/ummaya/nonStreaming.ts +66 -0
  252. package/tui/src/services/api/ummaya/provider.ts +200 -0
  253. package/tui/src/services/api/ummaya/reasoning.ts +24 -0
  254. package/tui/src/services/api/ummaya/request.ts +200 -0
  255. package/tui/src/services/api/ummaya/selectionContext.ts +240 -0
  256. package/tui/src/services/api/ummaya/streaming.ts +365 -0
  257. package/tui/src/services/api/ummaya/streamingPayload.ts +129 -0
  258. package/tui/src/services/api/ummaya/streamingReader.ts +40 -0
  259. package/tui/src/services/api/ummaya/toolSelection.ts +217 -0
  260. package/tui/src/services/api/ummaya/types.ts +110 -0
  261. package/tui/src/services/api/ummaya/usage.ts +30 -0
  262. package/tui/src/services/api/ummaya.ts +26 -364
  263. package/tui/src/services/api/withRetry.ts +1 -1
  264. package/tui/src/services/awaySummary.ts +2 -2
  265. package/tui/src/services/claudeAiLimits.ts +1 -1
  266. package/tui/src/services/compact/autoCompact.ts +1 -1
  267. package/tui/src/services/compact/compact.ts +1 -1
  268. package/tui/src/services/lsp/types.ts +8 -30
  269. package/tui/src/services/tips/types.ts +6 -28
  270. package/tui/src/services/tokenEstimation.ts +1 -1
  271. package/tui/src/services/toolRegistry/bootGuard.ts +5 -5
  272. package/tui/src/services/toolUseSummary/toolUseSummaryGenerator.ts +1 -1
  273. package/tui/src/services/tools/toolExecution.ts +94 -1
  274. package/tui/src/skills/bundled/stuck.ts +12 -12
  275. package/tui/src/state/AppStateStore.ts +7 -0
  276. package/tui/src/store/pendingPermissionSlot.ts +1 -1
  277. package/tui/src/store/session-store.ts +10 -36
  278. package/tui/src/stubs/any-stub.ts +15 -10
  279. package/tui/src/stubs/color-diff-napi.ts +37 -23
  280. package/tui/src/stubs/globals.d.ts +3 -3
  281. package/tui/src/stubs/macro-preload.ts +23 -12
  282. package/tui/src/tools/AdapterTool/AdapterTool.ts +1239 -163
  283. package/tui/src/tools/AdapterTool/routeDiagnostics.ts +75 -0
  284. package/tui/src/tools/AgentTool/AgentTool.tsx +84 -1371
  285. package/tui/src/tools/AgentTool/agentToolHandoff.ts +114 -0
  286. package/tui/src/tools/AgentTool/agentToolPartialResult.ts +16 -0
  287. package/tui/src/tools/AgentTool/agentToolProgress.ts +32 -0
  288. package/tui/src/tools/AgentTool/agentToolResolver.ts +161 -0
  289. package/tui/src/tools/AgentTool/agentToolResult.ts +163 -0
  290. package/tui/src/tools/AgentTool/agentToolUtils.ts +14 -686
  291. package/tui/src/tools/AgentTool/asyncAgentLifecycle.ts +208 -0
  292. package/tui/src/tools/AgentTool/asyncLifecycle.ts +153 -0
  293. package/tui/src/tools/AgentTool/backgroundedCompletion.ts +126 -0
  294. package/tui/src/tools/AgentTool/backgroundedLifecycle.ts +174 -0
  295. package/tui/src/tools/AgentTool/foregroundBackground.ts +83 -0
  296. package/tui/src/tools/AgentTool/foregroundDrain.tsx +133 -0
  297. package/tui/src/tools/AgentTool/foregroundFinalize.ts +98 -0
  298. package/tui/src/tools/AgentTool/foregroundLifecycle.tsx +237 -0
  299. package/tui/src/tools/AgentTool/foregroundProgress.tsx +169 -0
  300. package/tui/src/tools/AgentTool/foregroundTask.ts +89 -0
  301. package/tui/src/tools/AgentTool/forkSubagent.ts +1 -12
  302. package/tui/src/tools/AgentTool/forkSubagentGate.ts +34 -0
  303. package/tui/src/tools/AgentTool/launchRouting.ts +203 -0
  304. package/tui/src/tools/AgentTool/lifecycle.ts +244 -0
  305. package/tui/src/tools/AgentTool/mcpRouting.ts +73 -0
  306. package/tui/src/tools/AgentTool/orchestrationSupport.ts +70 -0
  307. package/tui/src/tools/AgentTool/permissions.ts +39 -0
  308. package/tui/src/tools/AgentTool/promptSetup.ts +181 -0
  309. package/tui/src/tools/AgentTool/remoteRouting.ts +62 -0
  310. package/tui/src/tools/AgentTool/resultMapping.ts +116 -0
  311. package/tui/src/tools/AgentTool/resumeAgent.ts +39 -107
  312. package/tui/src/tools/AgentTool/resumeAgentHelpers.ts +140 -0
  313. package/tui/src/tools/AgentTool/runAgent.ts +1 -1
  314. package/tui/src/tools/AgentTool/runtimeConfig.ts +57 -0
  315. package/tui/src/tools/AgentTool/schemas.ts +196 -0
  316. package/tui/src/tools/AgentTool/sourceVerificationPropagation.ts +263 -0
  317. package/tui/src/tools/AgentTool/worktreeLifecycle.ts +105 -0
  318. package/tui/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +174 -202
  319. package/tui/src/tools/BashTool/BashTool.tsx +71 -1072
  320. package/tui/src/tools/BashTool/bashCommandHelpers.ts +12 -12
  321. package/tui/src/tools/BashTool/bashPermissions/astPreflight.ts +173 -0
  322. package/tui/src/tools/BashTool/bashPermissions/classifierChecks.ts +199 -0
  323. package/tui/src/tools/BashTool/bashPermissions/compoundGuards.ts +53 -0
  324. package/tui/src/tools/BashTool/bashPermissions/constants.ts +99 -0
  325. package/tui/src/tools/BashTool/bashPermissions/index.ts +38 -0
  326. package/tui/src/tools/BashTool/bashPermissions/legacyMisparsing.ts +62 -0
  327. package/tui/src/tools/BashTool/bashPermissions/main.ts +135 -0
  328. package/tui/src/tools/BashTool/bashPermissions/normalizedCommands.ts +33 -0
  329. package/tui/src/tools/BashTool/bashPermissions/operatorFlow.ts +98 -0
  330. package/tui/src/tools/BashTool/bashPermissions/permissionChecks.ts +200 -0
  331. package/tui/src/tools/BashTool/bashPermissions/prefixSuggestions.ts +88 -0
  332. package/tui/src/tools/BashTool/bashPermissions/promptClassifierRules.ts +125 -0
  333. package/tui/src/tools/BashTool/bashPermissions/ruleDelegates.ts +19 -0
  334. package/tui/src/tools/BashTool/bashPermissions/ruleMatching.ts +145 -0
  335. package/tui/src/tools/BashTool/bashPermissions/sandboxAutoAllow.ts +75 -0
  336. package/tui/src/tools/BashTool/bashPermissions/subcommandFlow.ts +205 -0
  337. package/tui/src/tools/BashTool/bashPermissions/subcommandGuards.ts +73 -0
  338. package/tui/src/tools/BashTool/bashPermissions/subcommandResultHelpers.ts +116 -0
  339. package/tui/src/tools/BashTool/bashPermissions/types.ts +26 -0
  340. package/tui/src/tools/BashTool/bashPermissions/wrapperStripping.ts +139 -0
  341. package/tui/src/tools/BashTool/bashPermissions.ts +26 -2621
  342. package/tui/src/tools/BashTool/call.ts +202 -0
  343. package/tui/src/tools/BashTool/callLoader.ts +35 -0
  344. package/tui/src/tools/BashTool/commandClassification.ts +151 -0
  345. package/tui/src/tools/BashTool/commandClassificationLoader.ts +40 -0
  346. package/tui/src/tools/BashTool/cwdReset.ts +33 -0
  347. package/tui/src/tools/BashTool/lineTruncation.ts +11 -0
  348. package/tui/src/tools/BashTool/modeValidation.ts +13 -1
  349. package/tui/src/tools/BashTool/outputPersistence.ts +42 -0
  350. package/tui/src/tools/BashTool/permissionClassification.ts +66 -0
  351. package/tui/src/tools/BashTool/permissionLoader.ts +44 -0
  352. package/tui/src/tools/BashTool/resultLoader.ts +29 -0
  353. package/tui/src/tools/BashTool/resultMapping.ts +83 -0
  354. package/tui/src/tools/BashTool/sandboxPolicy.ts +79 -0
  355. package/tui/src/tools/BashTool/schemas.ts +65 -0
  356. package/tui/src/tools/BashTool/sedEditExecution.ts +59 -0
  357. package/tui/src/tools/BashTool/shellExecution.tsx +245 -0
  358. package/tui/src/tools/BashTool/shellOutputUtils.ts +85 -0
  359. package/tui/src/tools/BashTool/shellPermissionGauntlet.ts +97 -0
  360. package/tui/src/tools/BashTool/uiLoader.ts +37 -0
  361. package/tui/src/tools/BriefTool/upload.ts +1 -1
  362. package/tui/src/tools/CalculatorTool/parser.ts +2 -2
  363. package/tui/src/tools/DocumentPrimitive/DocumentPrimitive.ts +262 -0
  364. package/tui/src/tools/DocumentPrimitive/dispatchNormalization.ts +270 -0
  365. package/tui/src/tools/DocumentPrimitive/documentDestinationPath.ts +18 -0
  366. package/tui/src/tools/DocumentPrimitive/documentMutationGuard.ts +22 -0
  367. package/tui/src/tools/DocumentPrimitive/documentPatchNormalization.ts +248 -0
  368. package/tui/src/tools/DocumentPrimitive/documentSourceVerification.ts +245 -0
  369. package/tui/src/tools/DocumentPrimitive/documentSourceVerificationFields.ts +103 -0
  370. package/tui/src/tools/DocumentPrimitive/modelVisibleOutput.ts +40 -0
  371. package/tui/src/tools/DocumentPrimitive/prompt.ts +35 -0
  372. package/tui/src/tools/FileEditTool/FileEditTool.ts +9 -507
  373. package/tui/src/tools/FileEditTool/call.ts +228 -0
  374. package/tui/src/tools/FileEditTool/validateInput.ts +196 -0
  375. package/tui/src/tools/FileReadTool/imageProcessor.ts +13 -0
  376. package/tui/src/tools/FileWriteTool/FileWriteTool.ts +7 -300
  377. package/tui/src/tools/FileWriteTool/call.ts +223 -0
  378. package/tui/src/tools/FileWriteTool/validateInput.ts +80 -0
  379. package/tui/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +19 -3
  380. package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +48 -29
  381. package/tui/src/tools/LookupPrimitive/prompt.ts +6 -7
  382. package/tui/src/tools/MCPTool/trustPolicy.ts +118 -0
  383. package/tui/src/tools/McpAuthTool/McpAuthTool.ts +21 -3
  384. package/tui/src/tools/NotebookEditTool/NotebookEditTool.ts +7 -326
  385. package/tui/src/tools/NotebookEditTool/call.ts +254 -0
  386. package/tui/src/tools/NotebookEditTool/notebookModel.ts +51 -0
  387. package/tui/src/tools/NotebookEditTool/validateInput.ts +142 -0
  388. package/tui/src/tools/PowerShellTool/PowerShellTool.tsx +46 -937
  389. package/tui/src/tools/PowerShellTool/acceptEditsCommandValidation.ts +162 -0
  390. package/tui/src/tools/PowerShellTool/call.ts +179 -0
  391. package/tui/src/tools/PowerShellTool/callLoader.ts +37 -0
  392. package/tui/src/tools/PowerShellTool/commandClassification.ts +86 -0
  393. package/tui/src/tools/PowerShellTool/modeValidation.ts +25 -332
  394. package/tui/src/tools/PowerShellTool/outputPersistence.ts +42 -0
  395. package/tui/src/tools/PowerShellTool/permissionClassification.ts +28 -0
  396. package/tui/src/tools/PowerShellTool/resultLoader.ts +31 -0
  397. package/tui/src/tools/PowerShellTool/resultMapping.ts +75 -0
  398. package/tui/src/tools/PowerShellTool/schemas.ts +40 -0
  399. package/tui/src/tools/PowerShellTool/shellExecution.tsx +258 -0
  400. package/tui/src/tools/PowerShellTool/symlinkModeValidation.ts +44 -0
  401. package/tui/src/tools/PowerShellTool/uiLoader.ts +37 -0
  402. package/tui/src/tools/PowerShellTool/validation.ts +39 -0
  403. package/tui/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +19 -3
  404. package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +30 -19
  405. package/tui/src/tools/ResolveLocationPrimitive/prompt.ts +2 -6
  406. package/tui/src/tools/SkillTool/SkillTool.ts +2 -2
  407. package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +51 -18
  408. package/tui/src/tools/TaskCreateTool/TaskCreateTool.ts +16 -2
  409. package/tui/src/tools/TaskGetTool/TaskGetTool.ts +23 -3
  410. package/tui/src/tools/TaskListTool/TaskListTool.ts +22 -4
  411. package/tui/src/tools/TaskOutputTool/TaskOutputTool.tsx +46 -547
  412. package/tui/src/tools/TaskOutputTool/lookup.ts +216 -0
  413. package/tui/src/tools/TaskOutputTool/render.tsx +257 -0
  414. package/tui/src/tools/TaskOutputTool/schemas.ts +55 -0
  415. package/tui/src/tools/TaskOutputTool/serialization.ts +36 -0
  416. package/tui/src/tools/TaskStopTool/TaskStopTool.ts +10 -0
  417. package/tui/src/tools/TaskUpdateTool/TaskUpdateTool.ts +14 -364
  418. package/tui/src/tools/TaskUpdateTool/completion.ts +62 -0
  419. package/tui/src/tools/TaskUpdateTool/schemas.ts +62 -0
  420. package/tui/src/tools/TaskUpdateTool/serialization.ts +46 -0
  421. package/tui/src/tools/TaskUpdateTool/statusUpdate.ts +247 -0
  422. package/tui/src/tools/TodoWriteTool/TodoWriteTool.ts +21 -2
  423. package/tui/src/tools/ToolSearchTool/ToolSearchTool.ts +21 -302
  424. package/tui/src/tools/ToolSearchTool/ccSupportTools.ts +223 -0
  425. package/tui/src/tools/ToolSearchTool/descriptionCache.ts +50 -0
  426. package/tui/src/tools/ToolSearchTool/keywordSearch.ts +216 -0
  427. package/tui/src/tools/ToolSearchTool/prompt.ts +10 -4
  428. package/tui/src/tools/ToolSearchTool/resultMapping.ts +30 -0
  429. package/tui/src/tools/ToolSearchTool/schemas.ts +30 -0
  430. package/tui/src/tools/ToolSearchTool/searchPool.ts +47 -0
  431. package/tui/src/tools/ToolSearchTool/supportIntentHints.ts +140 -0
  432. package/tui/src/tools/TranslateTool/TranslateTool.ts +1 -1
  433. package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +27 -10
  434. package/tui/src/tools/WebFetchTool/WebFetchTool.ts +43 -138
  435. package/tui/src/tools/WebFetchTool/call.ts +227 -0
  436. package/tui/src/tools/WebFetchTool/resolvedAddressSafety.ts +78 -0
  437. package/tui/src/tools/WebFetchTool/sourceVerification.ts +204 -0
  438. package/tui/src/tools/WebFetchTool/types.ts +23 -0
  439. package/tui/src/tools/WebFetchTool/urlSafety.ts +181 -0
  440. package/tui/src/tools/WebFetchTool/utils.ts +1 -1
  441. package/tui/src/tools/WebSearchTool/UI.tsx +0 -1
  442. package/tui/src/tools/WebSearchTool/WebSearchTool.ts +9 -313
  443. package/tui/src/tools/WebSearchTool/call.ts +33 -0
  444. package/tui/src/tools/WebSearchTool/responseMapping.ts +190 -0
  445. package/tui/src/tools/WebSearchTool/resultBlock.ts +47 -0
  446. package/tui/src/tools/WebSearchTool/schemas.ts +47 -0
  447. package/tui/src/tools/WebSearchTool/toolSchema.ts +12 -0
  448. package/tui/src/tools/WorkspaceToolAdapter/WorkspaceToolAdapter.ts +79 -0
  449. package/tui/src/tools/WorkspaceToolAdapter/allowedRootPolicy.ts +85 -0
  450. package/tui/src/tools/WorkspaceToolAdapter/documentFormatGuards.ts +73 -0
  451. package/tui/src/tools/WorkspaceToolAdapter/inputNormalization.ts +105 -0
  452. package/tui/src/tools/WorkspaceToolAdapter/mcpExposurePolicy.ts +64 -0
  453. package/tui/src/tools/WorkspaceToolAdapter/toolDefFactory.ts +215 -0
  454. package/tui/src/tools/WorkspaceToolAdapter/toolNames.ts +6 -0
  455. package/tui/src/tools/WorkspaceToolAdapter/workspacePolicy.ts +15 -0
  456. package/tui/src/tools/_shared/citizenUserText.ts +49 -0
  457. package/tui/src/tools/_shared/dispatchPrimitive.ts +6 -6
  458. package/tui/src/tools/_shared/documentChangeToPatch.ts +125 -0
  459. package/tui/src/tools/_shared/documentDispatchArguments.ts +87 -0
  460. package/tui/src/tools/_shared/documentPrimitiveTimeout.ts +13 -0
  461. package/tui/src/tools/_shared/documentToolResultRender.ts +98 -0
  462. package/tui/src/tools/_shared/locationInputRepair.ts +112 -0
  463. package/tui/src/tools/_shared/pendingCallRegistry.ts +1 -6
  464. package/tui/src/tools/_shared/rootPrimitiveInput.ts +68 -0
  465. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPatterns.ts +58 -0
  466. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPrompt.ts +271 -0
  467. package/tui/src/tools/_shared/toolChoiceRepair/documentRepair.ts +452 -0
  468. package/tui/src/tools/_shared/toolChoiceRepair/messageAccess.ts +80 -0
  469. package/tui/src/tools/_shared/toolChoiceRepair/publicDataRepair.ts +92 -0
  470. package/tui/src/tools/_shared/toolChoiceRepair/supportRepair.ts +135 -0
  471. package/tui/src/tools/_shared/toolChoiceRepair.ts +61 -0
  472. package/tui/src/tools/shared/mockDisclaimer.ts +1 -1
  473. package/tui/src/tools.ts +39 -190
  474. package/tui/src/types/fileSuggestion.ts +4 -26
  475. package/tui/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +186 -148
  476. package/tui/src/types/generated/events_mono/common/v1/auth.ts +25 -11
  477. package/tui/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +47 -30
  478. package/tui/src/types/generated/google/protobuf/timestamp.ts +21 -7
  479. package/tui/src/types/message.ts +80 -102
  480. package/tui/src/types/messageQueueTypes.ts +6 -28
  481. package/tui/src/types/notebook.ts +16 -38
  482. package/tui/src/types/statusLine.ts +4 -26
  483. package/tui/src/types/tools.ts +24 -46
  484. package/tui/src/types/utils.ts +6 -28
  485. package/tui/src/upstreamproxy/relay.ts +7 -3
  486. package/tui/src/upstreamproxy/upstreamproxy.ts +1 -1
  487. package/tui/src/utils/assistantMessageFactories.ts +9 -3
  488. package/tui/src/utils/attachments.ts +1 -1
  489. package/tui/src/utils/auth.ts +129 -139
  490. package/tui/src/utils/bash/ast.ts +23 -23
  491. package/tui/src/utils/bash/bashParser.ts +5 -5
  492. package/tui/src/utils/billing.ts +1 -1
  493. package/tui/src/utils/collapseReadSearch.ts +3 -3
  494. package/tui/src/utils/cronTasks.ts +1 -1
  495. package/tui/src/utils/execFileNoThrow.ts +1 -1
  496. package/tui/src/utils/filePersistence/types.ts +16 -38
  497. package/tui/src/utils/forkedAgent.ts +1 -1
  498. package/tui/src/utils/gracefulShutdown.ts +4 -4
  499. package/tui/src/utils/heapDumpService.ts +12 -8
  500. package/tui/src/utils/hooks/apiQueryHookHelper.ts +1 -1
  501. package/tui/src/utils/hooks/execPromptHook.ts +1 -1
  502. package/tui/src/utils/hooks/skillImprovement.ts +1 -1
  503. package/tui/src/utils/kExaoneReasoning.ts +138 -0
  504. package/tui/src/utils/mcp/dateTimeParser.ts +1 -1
  505. package/tui/src/utils/messages.ts +19 -0
  506. package/tui/src/utils/migrateSessions.ts +3 -3
  507. package/tui/src/utils/model/model.ts +6 -6
  508. package/tui/src/utils/multiToolLayout.ts +13 -0
  509. package/tui/src/utils/permissions/yoloClassifier.ts +1 -1
  510. package/tui/src/utils/plugins/headlessPluginInstall.ts +1 -1
  511. package/tui/src/utils/plugins/mcpPluginIntegration.ts +1 -1
  512. package/tui/src/utils/plugins/mcpbHandler.ts +1 -1
  513. package/tui/src/utils/plugins/pluginLoader.ts +8 -8
  514. package/tui/src/utils/processUserInput/processSlashCommand.tsx +2 -2
  515. package/tui/src/utils/processUserInput/processUserInput.ts +26 -0
  516. package/tui/src/utils/protectedNamespace.ts +5 -3
  517. package/tui/src/utils/rawJsonToolCall.ts +242 -0
  518. package/tui/src/utils/ripgrep.ts +16 -7
  519. package/tui/src/utils/sessionTitle.ts +1 -1
  520. package/tui/src/utils/settings/applySettingsChange.ts +4 -0
  521. package/tui/src/utils/settings/permissionValidation.ts +14 -2
  522. package/tui/src/utils/settings/types.ts +9 -3
  523. package/tui/src/utils/shell/prefix.ts +1 -1
  524. package/tui/src/utils/sideQuery.ts +1 -1
  525. package/tui/src/utils/stats.ts +1 -1
  526. package/tui/src/utils/systemThemeWatcher.ts +13 -3
  527. package/tui/src/utils/teleport.tsx +1 -1
  528. package/uv.lock +394 -22
  529. package/assets/copilot-gate-logo.svg +0 -58
  530. package/assets/govon-logo.svg +0 -40
  531. package/src/ummaya/eval/__init__.py +0 -5
  532. package/src/ummaya/eval/retrieval.py +0 -713
  533. package/tui/src/services/api/claude.ts +0 -3510
  534. package/tui/src/utils/messageStream.ts +0 -186
@@ -0,0 +1,246 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ from __future__ import annotations
3
+
4
+ from datetime import datetime
5
+ from typing import Literal, Self
6
+
7
+ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
8
+ from pydantic_core import PydanticCustomError
9
+
10
+ from ummaya.evidence.source_provenance_redaction import (
11
+ PromptInjectionState,
12
+ RedactionCategory,
13
+ detect_prompt_injection,
14
+ ordered_redaction_categories,
15
+ redact_source_text,
16
+ redact_source_url,
17
+ redaction_categories_for_text,
18
+ )
19
+ from ummaya.tools.routing.schema import sha256, unique
20
+
21
+ SourceKind = Literal["web", "mcp", "agent", "file"]
22
+ SourceUseState = Literal["used", "blocked"]
23
+ SourceTrust = Literal["trusted", "untrusted"]
24
+ SynthesisState = Literal[
25
+ "eligible_for_synthesis",
26
+ "blocked_pending_user_approval",
27
+ "blocked_untrusted",
28
+ "blocked_missing_source",
29
+ ]
30
+ DocumentAuthoringState = Literal[
31
+ "approved_for_document",
32
+ "blocked_pending_user_approval",
33
+ "blocked_untrusted",
34
+ "blocked_missing_source",
35
+ ]
36
+
37
+
38
+ class SourceRedactionMetadata(BaseModel):
39
+ model_config = ConfigDict(frozen=True, extra="forbid")
40
+
41
+ redacted: bool
42
+ categories: tuple[RedactionCategory, ...] = Field(default_factory=tuple)
43
+ raw_private_document_stored: Literal[False] = False
44
+ secret_values_stored: Literal[False] = False
45
+ pii_values_stored: Literal[False] = False
46
+
47
+ @model_validator(mode="after")
48
+ def _categories_match_redacted_flag(self) -> Self:
49
+ if self.redacted and not self.categories:
50
+ raise PydanticCustomError(
51
+ "source_provenance_missing_redaction_categories",
52
+ "redacted provenance requires redaction categories",
53
+ )
54
+ if not self.redacted and self.categories:
55
+ raise PydanticCustomError(
56
+ "source_provenance_unexpected_redaction_categories",
57
+ "unredacted provenance cannot carry redaction categories",
58
+ )
59
+ return self
60
+
61
+
62
+ class SourceProvenanceRecord(BaseModel):
63
+ model_config = ConfigDict(frozen=True, extra="forbid")
64
+
65
+ source_kind: SourceKind
66
+ source_url: str | None
67
+ local_evidence_handle: str | None
68
+ title: str | None
69
+ description: str | None
70
+ tool_id: str = Field(min_length=1)
71
+ observed_at: datetime
72
+ state: SourceUseState
73
+ citation_id: str = Field(min_length=1)
74
+ provenance_id: str = Field(min_length=1)
75
+ trust: SourceTrust
76
+ prompt_injection: PromptInjectionState = "not_detected"
77
+ redaction: SourceRedactionMetadata
78
+
79
+ @field_validator(
80
+ "source_url",
81
+ "local_evidence_handle",
82
+ "title",
83
+ "description",
84
+ "tool_id",
85
+ "citation_id",
86
+ "provenance_id",
87
+ )
88
+ @classmethod
89
+ def _reject_unredacted_sensitive_value(cls, value: str | None) -> str | None:
90
+ if value is not None and redaction_categories_for_text(value):
91
+ raise PydanticCustomError(
92
+ "source_provenance_unredacted_sensitive_value",
93
+ "source provenance contains unredacted sensitive value",
94
+ )
95
+ return value
96
+
97
+ @model_validator(mode="after")
98
+ def _requires_source_handle_and_label(self) -> Self:
99
+ if self.source_url is None and self.local_evidence_handle is None:
100
+ raise PydanticCustomError(
101
+ "source_provenance_missing_source",
102
+ "source provenance requires source_url or local_evidence_handle",
103
+ )
104
+ if self.title is None and self.description is None:
105
+ raise PydanticCustomError(
106
+ "source_provenance_missing_label",
107
+ "source provenance requires title or description when available",
108
+ )
109
+ return self
110
+
111
+
112
+ class SourceProvenanceDecision(BaseModel):
113
+ model_config = ConfigDict(frozen=True, extra="forbid")
114
+
115
+ decision_id: str = Field(min_length=1)
116
+ provenance_ids: tuple[str, ...] = Field(min_length=1)
117
+ synthesis_state: SynthesisState
118
+ document_authoring_state: DocumentAuthoringState
119
+ requires_user_approval: bool
120
+ approved_by_user: bool
121
+ rationale: str = Field(min_length=1)
122
+
123
+ @model_validator(mode="after")
124
+ def _document_approval_requires_user_approval(self) -> Self:
125
+ if self.document_authoring_state == "approved_for_document" and (
126
+ self.requires_user_approval or not self.approved_by_user
127
+ ):
128
+ raise PydanticCustomError(
129
+ "source_provenance_document_approval_missing_user_approval",
130
+ "approved document authoring requires completed user approval",
131
+ )
132
+ return self
133
+
134
+
135
+ class SourceProvenanceLedger(BaseModel):
136
+ model_config = ConfigDict(frozen=True, extra="forbid")
137
+
138
+ schema_version: Literal["source_provenance_ledger.v1"] = "source_provenance_ledger.v1"
139
+ ledger_id: str = Field(min_length=1)
140
+ records: tuple[SourceProvenanceRecord, ...] = Field(min_length=1)
141
+ decisions: tuple[SourceProvenanceDecision, ...] = Field(default_factory=tuple)
142
+
143
+ @model_validator(mode="after")
144
+ def _decisions_reference_known_provenance_ids(self) -> Self:
145
+ known_ids = {record.provenance_id for record in self.records}
146
+ if len(known_ids) != len(self.records):
147
+ raise PydanticCustomError(
148
+ "source_provenance_duplicate_ids",
149
+ "source provenance ledger contains duplicate provenance ids",
150
+ )
151
+ unknown_ids = tuple(
152
+ unique(
153
+ provenance_id
154
+ for decision in self.decisions
155
+ for provenance_id in decision.provenance_ids
156
+ if provenance_id not in known_ids
157
+ )
158
+ )
159
+ if unknown_ids:
160
+ raise PydanticCustomError(
161
+ "source_provenance_unknown_ids",
162
+ "unknown provenance ids: " + ", ".join(unknown_ids),
163
+ )
164
+ return self
165
+
166
+
167
+ def build_source_provenance_record(
168
+ *,
169
+ source_kind: SourceKind,
170
+ tool_id: str,
171
+ source_url: str | None,
172
+ local_evidence_handle: str | None,
173
+ title: str | None,
174
+ description: str | None,
175
+ observed_at: datetime,
176
+ state: SourceUseState,
177
+ trust: SourceTrust,
178
+ citation_id: str,
179
+ ) -> SourceProvenanceRecord:
180
+ redacted_url, url_categories = redact_source_url(source_url)
181
+ redacted_handle, handle_categories = redact_source_text(local_evidence_handle)
182
+ redacted_title, title_categories = redact_source_text(title)
183
+ redacted_description, description_categories = redact_source_text(description)
184
+ categories = ordered_redaction_categories(
185
+ (
186
+ *url_categories,
187
+ *handle_categories,
188
+ *title_categories,
189
+ *description_categories,
190
+ )
191
+ )
192
+ prompt_injection_text_parts = (
193
+ title or "",
194
+ description or "",
195
+ source_url or "",
196
+ local_evidence_handle or "",
197
+ )
198
+ return SourceProvenanceRecord(
199
+ source_kind=source_kind,
200
+ source_url=redacted_url,
201
+ local_evidence_handle=redacted_handle,
202
+ title=redacted_title,
203
+ description=redacted_description,
204
+ tool_id=tool_id,
205
+ observed_at=observed_at,
206
+ state=state,
207
+ citation_id=citation_id,
208
+ provenance_id=stable_source_provenance_id(
209
+ source_kind=source_kind,
210
+ tool_id=tool_id,
211
+ source_url=redacted_url,
212
+ local_evidence_handle=redacted_handle,
213
+ citation_id=citation_id,
214
+ ),
215
+ trust=trust,
216
+ prompt_injection=detect_prompt_injection(
217
+ "\n".join(part for part in prompt_injection_text_parts if part)
218
+ ),
219
+ redaction=SourceRedactionMetadata(
220
+ redacted=bool(categories),
221
+ categories=categories,
222
+ raw_private_document_stored=False,
223
+ secret_values_stored=False,
224
+ pii_values_stored=False,
225
+ ),
226
+ )
227
+
228
+
229
+ def stable_source_provenance_id(
230
+ *,
231
+ source_kind: SourceKind,
232
+ tool_id: str,
233
+ source_url: str | None,
234
+ local_evidence_handle: str | None,
235
+ citation_id: str,
236
+ ) -> str:
237
+ digest = sha256(
238
+ {
239
+ "citation_id": citation_id,
240
+ "local_evidence_handle": local_evidence_handle,
241
+ "source_kind": source_kind,
242
+ "source_url": source_url,
243
+ "tool_id": tool_id,
244
+ }
245
+ )
246
+ return f"prov-{digest[:24]}"
@@ -0,0 +1,176 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ from __future__ import annotations
3
+
4
+ import re
5
+ from collections.abc import Iterable
6
+ from typing import Literal
7
+ from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit
8
+
9
+ RedactionCategory = Literal[
10
+ "auth_header",
11
+ "cookie",
12
+ "service_key",
13
+ "token",
14
+ "pii",
15
+ "private_document",
16
+ ]
17
+ PromptInjectionState = Literal["detected", "not_detected"]
18
+
19
+ _AUTH_HEADER_PATTERN = re.compile(r"\bAuthorization\s*:\s*[^\n\r;]+", re.IGNORECASE)
20
+ _AUTH_ASSIGNMENT_PATTERN = re.compile(
21
+ r"\bauthorization\s*=\s*[^\s&;\n\r]+",
22
+ re.IGNORECASE,
23
+ )
24
+ _COOKIE_PATTERN = re.compile(r"\bCookie\s*:\s*[^;\n\r]+;?\s*", re.IGNORECASE)
25
+ _COOKIE_ASSIGNMENT_PATTERN = re.compile(
26
+ r"\bcookie\s*=\s*[^\s&;\n\r]+",
27
+ re.IGNORECASE,
28
+ )
29
+ _SERVICE_KEY_PATTERN = re.compile(
30
+ r"\b(?:serviceKey|authKey)\s*=\s*[^\s&]+",
31
+ re.IGNORECASE,
32
+ )
33
+ _TOKEN_PATTERN = re.compile(
34
+ r"\b(?:UMMAYA_[A-Z0-9_]*TOKEN|"
35
+ r"[A-Z0-9_]*(?:API|AUTH|ACCESS|REFRESH|SESSION)[_-]?KEY|"
36
+ r"(?:session|access|refresh|id)[_-]?token)\s*=\s*[^\s&]+|"
37
+ r"\bBearer\s+[A-Za-z0-9._~+/=-]+",
38
+ re.IGNORECASE,
39
+ )
40
+ _GENERIC_TOKEN_ASSIGNMENT_PATTERN = re.compile(
41
+ r"\b(?:token|secret|api[_-]?key|access[_-]?token|session[_-]?token|"
42
+ r"refresh[_-]?token|id[_-]?token|client[_-]?secret)\s*=\s*[^\s&;\n\r]+",
43
+ re.IGNORECASE,
44
+ )
45
+ _EMAIL_PATTERN = re.compile(r"\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b", re.IGNORECASE)
46
+ _KOREAN_RRN_PATTERN = re.compile(r"\b\d{6}-[1-4]\d{6}\b")
47
+ _PHONE_PATTERN = re.compile(r"\b01[016789]-?\d{3,4}-?\d{4}\b")
48
+ _PRIVATE_DOCUMENT_PATTERN = re.compile(
49
+ r"-----BEGIN [A-Z ]*PRIVATE KEY-----|raw private document|private document bytes",
50
+ re.IGNORECASE,
51
+ )
52
+ _PROMPT_INJECTION_PATTERNS: tuple[re.Pattern[str], ...] = (
53
+ re.compile(r"ignore\s+(?:all\s+)?previous\s+instructions", re.IGNORECASE),
54
+ re.compile(r"change\s+(?:the\s+)?permission\s+policy", re.IGNORECASE),
55
+ re.compile(r"bypass\s+(?:permissions?|approval|policy)", re.IGNORECASE),
56
+ re.compile(r"treat\s+this\s+as\s+(?:a\s+)?system\s+instruction", re.IGNORECASE),
57
+ )
58
+ _SECRET_QUERY_KEYS = frozenset(
59
+ {
60
+ "access_token",
61
+ "api_key",
62
+ "apikey",
63
+ "auth",
64
+ "authkey",
65
+ "authorization",
66
+ "cookie",
67
+ "id_token",
68
+ "key",
69
+ "refresh_token",
70
+ "servicekey",
71
+ "session",
72
+ "session_token",
73
+ "token",
74
+ }
75
+ )
76
+
77
+
78
+ def redact_source_url(value: str | None) -> tuple[str | None, tuple[RedactionCategory, ...]]:
79
+ if value is None:
80
+ return None, ()
81
+ categories: list[RedactionCategory] = []
82
+ try:
83
+ parsed = urlsplit(value)
84
+ except ValueError:
85
+ return redact_source_text(value)
86
+ query_items: list[tuple[str, str]] = []
87
+ for key, item_value in parse_qsl(parsed.query, keep_blank_values=True):
88
+ lowered_key = key.lower()
89
+ if lowered_key in _SECRET_QUERY_KEYS:
90
+ categories.append(
91
+ "service_key" if lowered_key in {"authkey", "servicekey"} else "token"
92
+ )
93
+ continue
94
+ redacted_value, item_categories = redact_source_text(item_value)
95
+ categories.extend(item_categories)
96
+ query_items.append((key, redacted_value or ""))
97
+ rebuilt = urlunsplit(
98
+ (
99
+ parsed.scheme,
100
+ parsed.netloc,
101
+ parsed.path,
102
+ urlencode(query_items),
103
+ parsed.fragment,
104
+ )
105
+ )
106
+ redacted_text, text_categories = redact_source_text(rebuilt)
107
+ categories.extend(text_categories)
108
+ return redacted_text, ordered_redaction_categories(categories)
109
+
110
+
111
+ def redact_source_text(value: str | None) -> tuple[str | None, tuple[RedactionCategory, ...]]:
112
+ if value is None:
113
+ return None, ()
114
+ categories = list(redaction_categories_for_text(value))
115
+ redacted = _AUTH_HEADER_PATTERN.sub("[REDACTED_AUTH_HEADER]", value)
116
+ redacted = _AUTH_ASSIGNMENT_PATTERN.sub("[REDACTED_AUTH_HEADER]", redacted)
117
+ redacted = _COOKIE_PATTERN.sub("[REDACTED_COOKIE] ", redacted)
118
+ redacted = _COOKIE_ASSIGNMENT_PATTERN.sub("[REDACTED_COOKIE]", redacted)
119
+ redacted = _SERVICE_KEY_PATTERN.sub("[REDACTED_SERVICE_KEY]", redacted)
120
+ redacted = _TOKEN_PATTERN.sub("[REDACTED_TOKEN]", redacted)
121
+ redacted = _GENERIC_TOKEN_ASSIGNMENT_PATTERN.sub("[REDACTED_TOKEN]", redacted)
122
+ redacted = _EMAIL_PATTERN.sub("[REDACTED_PII]", redacted)
123
+ redacted = _KOREAN_RRN_PATTERN.sub("[REDACTED_PII]", redacted)
124
+ redacted = _PHONE_PATTERN.sub("[REDACTED_PII]", redacted)
125
+ redacted = _PRIVATE_DOCUMENT_PATTERN.sub("[REDACTED_PRIVATE_DOCUMENT]", redacted)
126
+ return re.sub(r"[ \t]{2,}", " ", redacted).strip(), ordered_redaction_categories(categories)
127
+
128
+
129
+ def detect_prompt_injection(value: str) -> PromptInjectionState:
130
+ return (
131
+ "detected"
132
+ if any(pattern.search(value) for pattern in _PROMPT_INJECTION_PATTERNS)
133
+ else "not_detected"
134
+ )
135
+
136
+
137
+ def redaction_categories_for_text(value: str) -> tuple[RedactionCategory, ...]:
138
+ categories: list[RedactionCategory] = []
139
+ if _AUTH_HEADER_PATTERN.search(value):
140
+ categories.append("auth_header")
141
+ if _AUTH_ASSIGNMENT_PATTERN.search(value):
142
+ categories.append("auth_header")
143
+ if _COOKIE_PATTERN.search(value):
144
+ categories.append("cookie")
145
+ if _COOKIE_ASSIGNMENT_PATTERN.search(value):
146
+ categories.append("cookie")
147
+ if _SERVICE_KEY_PATTERN.search(value):
148
+ categories.append("service_key")
149
+ if _TOKEN_PATTERN.search(value):
150
+ categories.append("token")
151
+ if _GENERIC_TOKEN_ASSIGNMENT_PATTERN.search(value):
152
+ categories.append("token")
153
+ if (
154
+ _EMAIL_PATTERN.search(value)
155
+ or _KOREAN_RRN_PATTERN.search(value)
156
+ or _PHONE_PATTERN.search(value)
157
+ ):
158
+ categories.append("pii")
159
+ if _PRIVATE_DOCUMENT_PATTERN.search(value):
160
+ categories.append("private_document")
161
+ return ordered_redaction_categories(categories)
162
+
163
+
164
+ def ordered_redaction_categories(
165
+ categories: Iterable[RedactionCategory],
166
+ ) -> tuple[RedactionCategory, ...]:
167
+ order: tuple[RedactionCategory, ...] = (
168
+ "auth_header",
169
+ "cookie",
170
+ "service_key",
171
+ "token",
172
+ "pii",
173
+ "private_document",
174
+ )
175
+ present = set(categories)
176
+ return tuple(category for category in order if category in present)
@@ -0,0 +1,264 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Harbor-style task registry for Evidence Fabric v2.
3
+
4
+ The registry mirrors Harbor's task boundary: a task has an instruction,
5
+ metadata/configuration, and a verifier script. UMMAYA keeps execution local and
6
+ deterministic; this module only resolves and validates task definitions.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import tomllib
12
+ from collections.abc import Mapping, Sequence
13
+ from pathlib import Path
14
+ from typing import Literal, cast
15
+
16
+ import yaml
17
+ from pydantic import BaseModel, ConfigDict, Field, ValidationError
18
+
19
+ _REPO_ROOT = Path(__file__).resolve().parents[3]
20
+ _BANNED_MODEL_VISIBLE_KEYS = frozenset(
21
+ {
22
+ "adapter_id",
23
+ "tool_id",
24
+ "expected_tool_id",
25
+ "fixture_refs",
26
+ "fixture_ref",
27
+ "current_adapter_id",
28
+ }
29
+ )
30
+
31
+
32
+ class TaskRegistryError(ValueError):
33
+ """Raised when an Evidence Fabric task registry is invalid."""
34
+
35
+
36
+ class EvidenceTask(BaseModel):
37
+ """One resolved Harbor-style evidence task."""
38
+
39
+ model_config = ConfigDict(frozen=True, extra="forbid")
40
+
41
+ task_id: str
42
+ task_dir: Path
43
+ instruction_path: Path
44
+ verifier_path: Path
45
+ description: str
46
+ dataset_id: str
47
+ keywords: tuple[str, ...] = Field(default_factory=tuple)
48
+ environment_os: Literal["linux", "windows"] = "linux"
49
+ allow_internet: bool = False
50
+ verifier_timeout_sec: float = 120.0
51
+
52
+
53
+ class EvidenceDatasetRef(BaseModel):
54
+ """A dataset reference resolved from the local task registry."""
55
+
56
+ model_config = ConfigDict(frozen=True, extra="forbid")
57
+
58
+ ref: str
59
+ dataset_id: str
60
+ scenario_path: Path
61
+ tasks: tuple[EvidenceTask, ...]
62
+
63
+
64
+ class EvidenceTaskRegistry(BaseModel):
65
+ """Resolved Evidence Fabric task registry."""
66
+
67
+ model_config = ConfigDict(frozen=True, extra="forbid")
68
+
69
+ version: int
70
+ registry_id: str
71
+ datasets: tuple[EvidenceDatasetRef, ...]
72
+
73
+ def resolve_dataset(self, ref: str) -> EvidenceDatasetRef:
74
+ """Return the dataset entry matching a Harbor-style dataset ref."""
75
+
76
+ for dataset in self.datasets:
77
+ if dataset.ref == ref:
78
+ return dataset
79
+ raise TaskRegistryError(f"dataset ref not found in task registry: {ref}")
80
+
81
+
82
+ def _load_yaml_mapping(path: Path) -> Mapping[str, object]:
83
+ if not path.exists():
84
+ raise TaskRegistryError(f"task registry not found: {path}")
85
+ loaded = yaml.safe_load(path.read_text(encoding="utf-8"))
86
+ if not isinstance(loaded, Mapping):
87
+ raise TaskRegistryError(f"task registry must be a mapping: {path}")
88
+ return cast(Mapping[str, object], loaded)
89
+
90
+
91
+ def _find_banned_keys(value: object, path: str = "$") -> tuple[str, ...]:
92
+ if isinstance(value, Mapping):
93
+ hits: list[str] = []
94
+ for key, nested in value.items():
95
+ key_text = str(key)
96
+ nested_path = f"{path}.{key_text}"
97
+ if key_text in _BANNED_MODEL_VISIBLE_KEYS:
98
+ hits.append(nested_path)
99
+ hits.extend(_find_banned_keys(nested, nested_path))
100
+ return tuple(hits)
101
+ if isinstance(value, Sequence) and not isinstance(value, str | bytes | bytearray):
102
+ hits = []
103
+ for index, nested in enumerate(value):
104
+ hits.extend(_find_banned_keys(nested, f"{path}[{index}]"))
105
+ return tuple(hits)
106
+ return ()
107
+
108
+
109
+ def _read_path(path: Path) -> Path:
110
+ return path if path.is_absolute() else _REPO_ROOT / path
111
+
112
+
113
+ def _require_existing_files(paths: tuple[Path, ...]) -> None:
114
+ for required in paths:
115
+ if not _read_path(required).exists():
116
+ raise TaskRegistryError(f"task file missing: {required}")
117
+
118
+
119
+ def _require_mapping(value: object, label: str) -> Mapping[str, object]:
120
+ if not isinstance(value, Mapping):
121
+ raise TaskRegistryError(f"{label} must be a mapping")
122
+ return cast(Mapping[str, object], value)
123
+
124
+
125
+ def _require_non_empty_str(value: object, label: str) -> str:
126
+ if not isinstance(value, str) or not value:
127
+ raise TaskRegistryError(f"{label} must be a non-empty string")
128
+ return value
129
+
130
+
131
+ def _require_sequence(value: object, label: str) -> Sequence[object]:
132
+ if not isinstance(value, Sequence) or isinstance(value, str | bytes | bytearray):
133
+ raise TaskRegistryError(f"{label} must be a list")
134
+ return cast(Sequence[object], value)
135
+
136
+
137
+ def _optional_float(value: object, label: str, default: float) -> float:
138
+ if value is None:
139
+ return default
140
+ if isinstance(value, bool) or not isinstance(value, str | int | float):
141
+ raise TaskRegistryError(f"{label} must be a number")
142
+ return float(value)
143
+
144
+
145
+ def _load_task_toml(task_toml: Path) -> Mapping[str, object]:
146
+ raw = tomllib.loads(_read_path(task_toml).read_text(encoding="utf-8"))
147
+ banned = _find_banned_keys(raw)
148
+ if banned:
149
+ raise TaskRegistryError(
150
+ "model-visible task registry contains banned implementation keys: " + ", ".join(banned)
151
+ )
152
+ return cast(Mapping[str, object], raw)
153
+
154
+
155
+ def _build_task(
156
+ *,
157
+ task_dir: Path,
158
+ instruction_path: Path,
159
+ verifier_path: Path,
160
+ raw: Mapping[str, object],
161
+ ) -> EvidenceTask:
162
+ task_section = _require_mapping(raw.get("task"), "task.toml [task]")
163
+ metadata_section = _require_mapping(raw.get("metadata", {}), "task.toml [metadata]")
164
+ environment_section = _require_mapping(raw.get("environment", {}), "task.toml [environment]")
165
+ verifier_section = _require_mapping(raw.get("verifier", {}), "task.toml [verifier]")
166
+ keywords = _require_sequence(task_section.get("keywords", ()), "task.toml [task].keywords")
167
+
168
+ try:
169
+ return EvidenceTask(
170
+ task_id=_require_non_empty_str(task_section.get("name"), "task.toml [task].name"),
171
+ task_dir=task_dir,
172
+ instruction_path=instruction_path,
173
+ verifier_path=verifier_path,
174
+ description=_require_non_empty_str(
175
+ task_section.get("description"),
176
+ "task.toml [task].description",
177
+ ),
178
+ dataset_id=_require_non_empty_str(
179
+ metadata_section.get("dataset_id"),
180
+ "task.toml [metadata].dataset_id",
181
+ ),
182
+ keywords=tuple(str(keyword) for keyword in keywords),
183
+ environment_os=cast(
184
+ Literal["linux", "windows"],
185
+ environment_section.get("os", "linux"),
186
+ ),
187
+ allow_internet=bool(environment_section.get("allow_internet", False)),
188
+ verifier_timeout_sec=_optional_float(
189
+ verifier_section.get("timeout_sec"),
190
+ "task.toml [verifier].timeout_sec",
191
+ 120.0,
192
+ ),
193
+ )
194
+ except ValidationError as exc:
195
+ raise TaskRegistryError(str(exc)) from exc
196
+
197
+
198
+ def _load_task(task_dir: Path) -> EvidenceTask:
199
+ task_toml = task_dir / "task.toml"
200
+ instruction_path = task_dir / "instruction.md"
201
+ verifier_path = task_dir / "tests" / "test.sh"
202
+ _require_existing_files((task_toml, instruction_path, verifier_path))
203
+ return _build_task(
204
+ task_dir=task_dir,
205
+ instruction_path=instruction_path,
206
+ verifier_path=verifier_path,
207
+ raw=_load_task_toml(task_toml),
208
+ )
209
+
210
+
211
+ def _load_dataset_ref(index: int, dataset_raw: object) -> EvidenceDatasetRef:
212
+ dataset_map = _require_mapping(dataset_raw, f"datasets[{index}]")
213
+ ref = _require_non_empty_str(dataset_map.get("ref"), f"datasets[{index}].ref")
214
+ dataset_id = _require_non_empty_str(
215
+ dataset_map.get("dataset_id"),
216
+ f"datasets[{index}].dataset_id",
217
+ )
218
+ scenario_path = _require_non_empty_str(
219
+ dataset_map.get("scenario_path"),
220
+ f"datasets[{index}].scenario_path",
221
+ )
222
+ task_paths = _require_sequence(dataset_map.get("task_paths"), f"datasets[{index}].task_paths")
223
+
224
+ tasks = tuple(_load_task(Path(str(task_path))) for task_path in task_paths)
225
+ mismatched = tuple(task.task_id for task in tasks if task.dataset_id != dataset_id)
226
+ if mismatched:
227
+ raise TaskRegistryError(
228
+ f"dataset {ref} has tasks with mismatched dataset_id: {', '.join(mismatched)}"
229
+ )
230
+ return EvidenceDatasetRef(
231
+ ref=ref,
232
+ dataset_id=dataset_id,
233
+ scenario_path=Path(scenario_path),
234
+ tasks=tasks,
235
+ )
236
+
237
+
238
+ def load_task_registry(path: Path) -> EvidenceTaskRegistry:
239
+ """Load and validate a Harbor-style Evidence Fabric task registry."""
240
+
241
+ raw = _load_yaml_mapping(path)
242
+ banned = _find_banned_keys(raw)
243
+ if banned:
244
+ raise TaskRegistryError(
245
+ "model-visible task registry contains banned implementation keys: " + ", ".join(banned)
246
+ )
247
+
248
+ version = raw.get("version")
249
+ if not isinstance(version, int):
250
+ raise TaskRegistryError("task registry version must be an integer")
251
+ registry_id = _require_non_empty_str(raw.get("registry_id"), "task registry_id")
252
+ datasets = _require_sequence(raw.get("datasets"), "task registry datasets")
253
+ resolved_datasets = tuple(
254
+ _load_dataset_ref(index, dataset_raw) for index, dataset_raw in enumerate(datasets)
255
+ )
256
+
257
+ try:
258
+ return EvidenceTaskRegistry(
259
+ version=version,
260
+ registry_id=registry_id,
261
+ datasets=resolved_datasets,
262
+ )
263
+ except ValidationError as exc:
264
+ raise TaskRegistryError(str(exc)) from exc