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
@@ -15,7 +15,6 @@ Public API (for external callers):
15
15
  from __future__ import annotations
16
16
 
17
17
  import logging
18
- import re
19
18
  from typing import TYPE_CHECKING
20
19
 
21
20
  from ummaya.tools.bm25_index import BM25Index
@@ -26,715 +25,42 @@ from ummaya.tools.models import (
26
25
  SearchToolsOutput,
27
26
  ToolSearchResult,
28
27
  )
29
-
30
- if TYPE_CHECKING:
31
- from ummaya.tools.registry import ToolRegistry
32
-
33
- logger = logging.getLogger(__name__)
34
-
35
-
36
- _POI_LOCATION_RE = re.compile(
37
- r"(근처|주변|인근|가까운|역|터미널|공항|캠퍼스|대학교|대학|해수욕장|시장|공원|랜드마크)"
38
- )
39
- _ADMIN_LOCATION_RE = re.compile(
40
- r"(?:[가-힣]{2,}(?:시|군|구|동|읍|면)\b|[가-힣0-9]{2,}(?<!으)(?:로|길)\b)"
41
- )
42
- _EMERGENCY_RE = re.compile(r"(응급|응급실|응급의료|\bemergency\b|\ber\b)", re.IGNORECASE)
43
- _IMPLICIT_EMERGENCY_RE = re.compile(
44
- r"(사람이\s*(?:쓰러|쓰러졌|쓰러져)|의식(?:을)?\s*(?:잃|없)|"
45
- r"갑자기\s*쓰러|쓰러진\s*사람|위급|심정지|호흡(?:이)?\s*없|"
46
- r"collapsed|unconscious|cardiac\s*arrest)",
47
- re.IGNORECASE,
48
- )
49
- _AED_RE = re.compile(r"(\bAED\b|자동심장충격기|자동제세동기|제세동기)", re.IGNORECASE)
50
- _TRAFFIC_HAZARD_RE = re.compile(
51
- r"(교통사고|사고\s*위험|사고다발|위험\s*(?:구간|도로|지점)|어린이보호구역|보호구역|"
52
- r"도로\s*구간|accident|hazard|hotspot)",
53
- re.IGNORECASE,
54
- )
55
- _TRAFFIC_HAZARD_SPECIFIC_RE = re.compile(
56
- r"(사고\s*위험|위험\s*(?:구간|도로|지점)|어린이보호구역|보호구역|스쿨존|"
57
- r"도로\s*구간|행정동코드|adm_cd|hazard|hotspot)",
58
- re.IGNORECASE,
59
- )
60
- _KMA_ANALYSIS_CHART_RE = re.compile(
61
- r"(분석일기도|지상일기도|보조일기도|WthrChartInfoService|getSurfaceChart|"
62
- r"getAuxillaryChart|synoptic\s+chart)",
63
- re.IGNORECASE,
64
- )
65
- _KMA_GIMHAE_AIRPORT_RE = re.compile(r"(김해(?:공항)?|Gimhae|RKPK)", re.IGNORECASE)
66
- _KMA_GIMPO_AIRPORT_RE = re.compile(r"(김포(?:공항)?|Gimpo|RKSS)", re.IGNORECASE)
67
- _KMA_AIRPORT_NAME_RE = re.compile(
68
- r"(공항|\bairport\b|\bRK[A-Z]{2}\b|station\s*\d{2,3})",
69
- re.IGNORECASE,
70
- )
71
- _KMA_AIRPORT_AVIATION_RE = re.compile(
72
- r"(AMOS|METAR|SPECI|RVR|항공기상|공항기상|활주로|runway|aviation|"
73
- r"비행기|항공편|비행편|이륙|착륙|결항|지연|운항|뜰\s*만|뜨나|뜰\s*수|"
74
- r"flight|take\s*off|landing|delay|cancel)",
75
- re.IGNORECASE,
76
- )
77
- _KMA_EXPLICIT_METAR_RE = re.compile(r"(\bMETAR\b|\bSPECI\b|해독자료)", re.IGNORECASE)
78
- _KMA_RUNWAY_AREA_RE = re.compile(
79
- r"(AMOS|활주로|RVR|runway|시정|visibility|공항기상관측|매분)",
80
- re.IGNORECASE,
81
- )
82
- _KMA_ANALYSIS_DATA_RE = re.compile(
83
- r"(분석자료|이미\s*분석|고해상도\s*격자|객관분석|AWS\s*객관|지도\s*자료|"
84
- r"일기도|분석일기도|비구름|바람\s*흐름|날씨\s*흐름|공식\s*기상자료|전국\s*날씨|"
85
- r"synoptic|weather\s*chart|"
86
- r"objective\s*analysis|high[-\s]?resolution|grid)",
87
- re.IGNORECASE,
88
- )
89
- _KMA_LIFESTYLE_WEATHER_RE = re.compile(
90
- r"(날씨|현재\s*기상|실황|관측|예보|기온|습도|풍속|지금\s*비|"
91
- r"비\s*(?:와|오|올|내리)|우산|강수|소나기|산책|퇴근|"
92
- r"current\s+weather|forecast|rain|umbrella|precipitation|temperature)",
93
- re.IGNORECASE,
94
- )
95
- _HIRA_MEDICAL_DETAIL_RE = re.compile(
96
- r"((병원|의료기관|의원).*(상세|진료과|진료과목|진료시간|주차)|"
97
- r"(상세|진료시간|주차|응급실).*(병원|의료기관|의원)|ykiho|detail)",
98
- re.IGNORECASE,
99
- )
100
- _MOIS_EMERGENCY_CALL_BOX_RE = re.compile(
101
- r"(안전\s*비상벨|비상벨|긴급\s*신고함|긴급신고함|방범벨|"
102
- r"emergency\s+call\s+box)",
103
- re.IGNORECASE,
104
- )
105
- _GYERYONG_ASSISTIVE_CHARGER_RE = re.compile(
106
- r"((전동보장구|전동\s*휠체어|보장구|장애인).*(충전|충전소|충전장소)|"
107
- r"(충전|충전소|충전장소).*(전동보장구|전동\s*휠체어|보장구|장애인)|"
108
- r"계룡시?.*(충전소|충전\s*장소))",
109
- re.IGNORECASE,
110
- )
111
- _MOF_OCEAN_WATER_QUALITY_RE = re.compile(
112
- r"(해양\s*수질|해양수질|수질\s*자동\s*측정|용존산소|\bpH\b|"
113
- r"water\s+quality|ocean\s+water)",
114
- re.IGNORECASE,
115
- )
116
- _PPS_SHOPPING_RE = re.compile(
117
- r"(종합\s*쇼핑몰|쇼핑몰|계약\s*물품|물품\s*조회|shopping\s*mall)",
118
- re.IGNORECASE,
119
- )
120
- _PPS_BID_RE = re.compile(
121
- r"(입찰|나라장터|조달청|\bbid\b|procurement|tender)",
122
- re.IGNORECASE,
123
- )
124
- _KCUE_ACADEMY_INFO_RE = re.compile(
125
- r"(대학알리미|대학정보공시|학교구분코드|schl[_\s-]?div[_\s-]?cd|KCUE)",
126
- re.IGNORECASE,
28
+ from ummaya.tools.routing.intent import ToolSelectionIntent, extract_tool_selection_intent
29
+ from ummaya.tools.routing.retrieval_policy import (
30
+ expand_query_for_adapter_retrieval as _policy_expand_query_for_adapter_retrieval,
127
31
  )
128
- _KCUE_REGIONAL_FINANCE_RE = re.compile(
129
- r"(지역별\s*(등록금|재정)|등록금\s*(현황|지역별)?|tuition|finance)",
130
- re.IGNORECASE,
32
+ from ummaya.tools.routing.retrieval_policy import (
33
+ expand_query_for_intent as _policy_expand_query_for_intent,
131
34
  )
132
- _KCUE_REGIONAL_FOREIGN_STUDENT_RE = re.compile(
133
- r"(외국인\s*유학생|유학생\s*현황|foreign\s+student|international\s+student)",
134
- re.IGNORECASE,
35
+ from ummaya.tools.routing.retrieval_policy import (
36
+ filter_special_case_scores as _policy_filter_special_case_scores,
135
37
  )
136
- _KCUE_TOOL_IDS = frozenset(
137
- {
138
- "kcue_finance_regional_tuition",
139
- "kcue_student_regional_foreign",
140
- }
38
+ from ummaya.tools.routing.retrieval_policy import (
39
+ is_document_harness_query as _policy_is_document_harness_query,
141
40
  )
142
- _KMA_ANALYSIS_MAP_RE = re.compile(
143
- r"(일기도|분석일기도|지도\s*자료|비구름|바람\s*흐름|날씨\s*흐름|전국\s*날씨|"
144
- r"synoptic|weather\s*chart)",
145
- re.IGNORECASE,
146
- )
147
- _KMA_ANALYSIS_POINT_RE = re.compile(
148
- r"(주변|근처|특정지점|좌표|위도|경도|\blat\b|\blon\b|공항\s*주변)",
149
- re.IGNORECASE,
150
- )
151
- _KMA_URL_AIR_TOOL_IDS = frozenset(
152
- {
153
- "kma_apihub_url_air_amos_minute",
154
- "kma_apihub_url_air_metar_decoded",
155
- }
156
- )
157
- _KMA_ANALYSIS_TOOL_IDS = frozenset(
158
- {
159
- "kma_apihub_url_high_resolution_grid_point",
160
- "kma_apihub_url_aws_objective_analysis_grid",
161
- "kma_apihub_url_analysis_weather_chart_image",
162
- }
163
- )
164
- _KMA_LIFESTYLE_WEATHER_TOOL_IDS = frozenset(
165
- {
166
- "kma_current_observation",
167
- "kma_ultra_short_term_forecast",
168
- "kma_short_term_forecast",
169
- }
170
- )
171
- _LOCATION_TOOL_IDS = frozenset(
172
- {
173
- "locate",
174
- "kakao_address_search",
175
- "kakao_keyword_search",
176
- "kakao_coord_to_region",
177
- "juso_adm_cd_lookup",
178
- "sgis_adm_cd_lookup",
179
- }
180
- )
181
-
182
-
183
- def _is_kma_analysis_point_query(query: str, *, is_analysis_map_query: bool) -> bool:
184
- return bool(_KMA_ANALYSIS_POINT_RE.search(query)) and not is_analysis_map_query
185
-
186
-
187
- def _is_airport_aviation_query(query: str) -> bool:
188
- return bool(
189
- (
190
- _KMA_AIRPORT_NAME_RE.search(query)
191
- or _KMA_GIMHAE_AIRPORT_RE.search(query)
192
- or _KMA_GIMPO_AIRPORT_RE.search(query)
193
- )
194
- and _KMA_AIRPORT_AVIATION_RE.search(query)
195
- )
196
-
197
-
198
- def _is_lifestyle_weather_query(query: str, *, is_airport_aviation_query: bool) -> bool:
199
- return bool(
200
- _KMA_LIFESTYLE_WEATHER_RE.search(query)
201
- and not is_airport_aviation_query
202
- and not _is_emergency_chain_query(query)
203
- and not _KMA_ANALYSIS_DATA_RE.search(query)
204
- and not _TRAFFIC_HAZARD_RE.search(query)
205
- and not _MOF_OCEAN_WATER_QUALITY_RE.search(query)
206
- )
207
-
208
-
209
- def _is_pps_bid_query(query: str) -> bool:
210
- return bool(_PPS_BID_RE.search(query) and not _PPS_SHOPPING_RE.search(query))
211
-
212
-
213
- def _is_kcue_regional_query(query: str) -> bool:
214
- has_kcue_anchor = bool(_KCUE_ACADEMY_INFO_RE.search(query)) or (
215
- bool(re.search(r"대학(?!병원)", query)) and "공식" in query
216
- )
217
- if not has_kcue_anchor:
218
- return False
219
- return bool(
220
- _KCUE_REGIONAL_FINANCE_RE.search(query) or _KCUE_REGIONAL_FOREIGN_STUDENT_RE.search(query)
221
- )
222
-
223
-
224
- def _is_emergency_chain_query(query: str) -> bool:
225
- if _MOIS_EMERGENCY_CALL_BOX_RE.search(query):
226
- return False
227
- return bool(_IMPLICIT_EMERGENCY_RE.search(query) or _EMERGENCY_RE.search(query))
228
-
229
-
230
- def _filter_kma_analysis_scores(
231
- scored: list[tuple[str, float]],
232
- *,
233
- is_analysis_map_query: bool,
234
- is_analysis_point_query: bool,
235
- prefer_poi_location: bool,
236
- ) -> list[tuple[str, float]]:
237
- chart_boost = 900.0 if is_analysis_map_query else 150.0
238
- if is_analysis_point_query and not is_analysis_map_query:
239
- chart_boost = -20.0
240
- analysis_boosts = {
241
- "kma_apihub_url_analysis_weather_chart_image": chart_boost,
242
- "kma_apihub_url_high_resolution_grid_point": (900.0 if is_analysis_point_query else 450.0),
243
- "kma_apihub_url_aws_objective_analysis_grid": (800.0 if is_analysis_point_query else 400.0),
244
- }
245
- allowed_location_ids = _LOCATION_TOOL_IDS if is_analysis_point_query else frozenset()
246
- adjusted: list[tuple[str, float]] = []
247
- for tool_id, score in scored:
248
- if tool_id in _KMA_ANALYSIS_TOOL_IDS:
249
- adjusted.append((tool_id, score + analysis_boosts.get(tool_id, 0.0)))
250
- continue
251
- if tool_id in allowed_location_ids:
252
- location_score = max(1.0, score - 10.0)
253
- if prefer_poi_location and tool_id == "kakao_keyword_search":
254
- location_score += 30.0
255
- elif prefer_poi_location and tool_id == "kakao_address_search":
256
- location_score = max(1.0, location_score - 15.0)
257
- adjusted.append((tool_id, location_score))
258
- return adjusted
259
-
260
-
261
- def _kma_lifestyle_weather_additions() -> list[str]:
262
- return [
263
- "기상청",
264
- "KMA",
265
- "현재날씨",
266
- "초단기실황",
267
- "초단기예보",
268
- "단기예보",
269
- "강수",
270
- "우산",
271
- "nx",
272
- "ny",
273
- "base_date",
274
- "base_time",
275
- "current",
276
- "observation",
277
- "forecast",
278
- "precipitation",
279
- ]
280
-
281
-
282
- def _airport_aviation_additions(query: str) -> list[str]:
283
- additions = [
284
- "METAR",
285
- "SPECI",
286
- "AMOS",
287
- "항공기상",
288
- "공항기상",
289
- "항공",
290
- "비행기",
291
- "항공편",
292
- "운항",
293
- "이륙",
294
- "시정",
295
- "RVR",
296
- "wind",
297
- "visibility",
298
- ]
299
- if _KMA_GIMPO_AIRPORT_RE.search(query) and _KMA_RUNWAY_AREA_RE.search(query):
300
- additions.extend(["AMOS", "공항기상관측", "매분자료", "활주로", "김포공항", "stn110"])
301
- return additions
302
-
303
-
304
- def _kma_analysis_data_additions() -> list[str]:
305
- return [
306
- "분석자료",
307
- "고해상도",
308
- "격자자료",
309
- "객관분석",
310
- "AWS",
311
- "분석일기도",
312
- "지도",
313
- "비구름",
314
- "바람흐름",
315
- "objective",
316
- "analysis",
317
- "grid",
318
- "chart",
319
- ]
320
-
321
-
322
- def _traffic_hazard_additions() -> list[str]:
323
- return [
324
- "교통사고",
325
- "사고다발구역",
326
- "위험지점",
327
- "도로위험구역",
328
- "어린이보호구역",
329
- "행정동코드",
330
- "KOROAD",
331
- "accident",
332
- "hazard",
333
- ]
334
-
335
-
336
- def _emergency_chain_additions(query: str) -> list[str]:
337
- if not _is_emergency_chain_query(query):
338
- return []
339
- additions = [
340
- "응급실",
341
- "응급의료",
342
- "자동심장충격기",
343
- "AED",
344
- "국립중앙의료원",
345
- "NMC",
346
- "nearby",
347
- "emergency",
348
- "hospital",
349
- ]
350
- if _POI_LOCATION_RE.search(query):
351
- additions.extend(["장소", "키워드", "POI", "랜드마크", "역", "keyword"])
352
- return additions
353
-
354
-
355
- def _public_safety_location_additions(query: str) -> list[str]:
356
- additions: list[str] = []
357
- if _MOIS_EMERGENCY_CALL_BOX_RE.search(query):
358
- additions.extend(
359
- [
360
- "안전비상벨",
361
- "비상벨",
362
- "긴급신고함",
363
- "방범",
364
- "행정안전부",
365
- "MOIS",
366
- "emergency",
367
- "call",
368
- "box",
369
- ]
370
- )
371
- if _GYERYONG_ASSISTIVE_CHARGER_RE.search(query):
372
- additions.extend(
373
- [
374
- "계룡시",
375
- "전동보장구",
376
- "전동휠체어",
377
- "장애인",
378
- "충전소",
379
- "충전장소",
380
- "accessibility",
381
- "charger",
382
- ]
383
- )
384
- return additions
385
-
386
-
387
- def _ocean_water_quality_additions(query: str) -> list[str]:
388
- if not _MOF_OCEAN_WATER_QUALITY_RE.search(query):
389
- return []
390
- return [
391
- "해양수산부",
392
- "해양수질",
393
- "수질자동측정망",
394
- "관측소",
395
- "SEA3003",
396
- "용존산소",
397
- "water",
398
- "quality",
399
- "ocean",
400
- ]
401
-
402
-
403
- def _pps_bid_additions(query: str) -> list[str]:
404
- if not _is_pps_bid_query(query):
405
- return []
406
- return [
407
- "조달청",
408
- "나라장터",
409
- "입찰공고",
410
- "공사입찰",
411
- "bidNtceNm",
412
- "inqryBgnDt",
413
- "inqryEndDt",
414
- "PPS",
415
- "bid",
416
- "procurement",
417
- ]
418
-
419
-
420
- def _kcue_regional_additions(query: str) -> list[str]:
421
- if not _is_kcue_regional_query(query):
422
- return []
423
- additions = [
424
- "한국대학교육협의회",
425
- "대학알리미",
426
- "대학정보공시",
427
- "학교구분코드",
428
- "schlDivCd",
429
- "지역별통계",
430
- "KCUE",
431
- ]
432
- if _KCUE_REGIONAL_FINANCE_RE.search(query):
433
- additions.extend(["재정현황", "등록금", "FinancesService", "regional tuition"])
434
- if _KCUE_REGIONAL_FOREIGN_STUDENT_RE.search(query):
435
- additions.extend(["학생현황", "외국인유학생", "regional foreign student"])
436
- return additions
437
-
438
-
439
- def _health_detail_additions(query: str) -> list[str]:
440
- if not _HIRA_MEDICAL_DETAIL_RE.search(query):
441
- return []
442
- return [
443
- "의료기관",
444
- "상세정보",
445
- "진료과목",
446
- "진료시간",
447
- "주차",
448
- "요양기호",
449
- "ykiho",
450
- "HIRA",
451
- "hospital",
452
- "detail",
453
- ]
454
-
455
-
456
- def _filter_kma_lifestyle_weather_scores(
457
- scored: list[tuple[str, float]],
458
- ) -> list[tuple[str, float]]:
459
- allowed_tool_ids = _KMA_LIFESTYLE_WEATHER_TOOL_IDS | _LOCATION_TOOL_IDS
460
- if any(tool_id in allowed_tool_ids for tool_id, _ in scored):
461
- scored = [(tool_id, score) for tool_id, score in scored if tool_id in allowed_tool_ids]
462
- boosts = {
463
- "kakao_keyword_search": 1100.0,
464
- "kakao_address_search": 1000.0,
465
- "kma_current_observation": 900.0,
466
- "kma_ultra_short_term_forecast": 800.0,
467
- "kma_short_term_forecast": 650.0,
468
- "kakao_coord_to_region": 260.0,
469
- "juso_adm_cd_lookup": 260.0,
470
- "sgis_adm_cd_lookup": 260.0,
471
- }
472
- return [(tool_id, score + boosts.get(tool_id, 0.0)) for tool_id, score in scored]
473
-
474
-
475
- def _filter_public_safety_location_scores(
476
- query: str, scored: list[tuple[str, float]]
477
- ) -> list[tuple[str, float]]:
478
- boosts = {}
479
- if _MOIS_EMERGENCY_CALL_BOX_RE.search(query):
480
- boosts["mois_emergency_call_box_lookup"] = 1000.0
481
- if _GYERYONG_ASSISTIVE_CHARGER_RE.search(query):
482
- boosts["gyeryong_assistive_device_charging_place_locate"] = 1000.0
483
- if not boosts:
484
- return scored
485
- return [(tool_id, score + boosts.get(tool_id, 0.0)) for tool_id, score in scored]
486
-
487
-
488
- def _filter_emergency_chain_scores(
489
- query: str, scored: list[tuple[str, float]]
490
- ) -> list[tuple[str, float]]:
491
- if not _is_emergency_chain_query(query):
492
- return scored
493
- emergency_tool_ids = {
494
- "nmc_emergency_search",
495
- "nmc_aed_site_locate",
496
- "hira_hospital_search",
497
- "hira_medical_institution_detail",
498
- }
499
- allowed_tool_ids = emergency_tool_ids | _LOCATION_TOOL_IDS
500
- if any(tool_id in emergency_tool_ids for tool_id, _ in scored):
501
- scored = [(tool_id, score) for tool_id, score in scored if tool_id in allowed_tool_ids]
502
- implicit_collapse = bool(_IMPLICIT_EMERGENCY_RE.search(query))
503
- boosts = {
504
- "nmc_emergency_search": 1200.0,
505
- "nmc_aed_site_locate": 1150.0 if implicit_collapse else 950.0,
506
- "kakao_keyword_search": 1100.0 if implicit_collapse else 900.0,
507
- "kakao_address_search": 800.0,
508
- "kakao_coord_to_region": 500.0,
509
- "juso_adm_cd_lookup": 300.0,
510
- "sgis_adm_cd_lookup": 300.0,
511
- "hira_hospital_search": 250.0,
512
- "hira_medical_institution_detail": 200.0,
513
- }
514
- return [(tool_id, score + boosts.get(tool_id, 0.0)) for tool_id, score in scored]
515
-
516
-
517
- def _filter_ocean_water_quality_scores(
518
- query: str, scored: list[tuple[str, float]]
519
- ) -> list[tuple[str, float]]:
520
- if not _MOF_OCEAN_WATER_QUALITY_RE.search(query):
521
- return scored
522
- return [
523
- (
524
- tool_id,
525
- score + (1000.0 if tool_id == "mof_ocean_water_quality_check" else 0.0),
526
- )
527
- for tool_id, score in scored
528
- ]
529
41
 
42
+ if TYPE_CHECKING:
43
+ from ummaya.tools.registry import ToolRegistry
530
44
 
531
- def _filter_pps_bid_scores(query: str, scored: list[tuple[str, float]]) -> list[tuple[str, float]]:
532
- if not _is_pps_bid_query(query):
533
- return scored
534
- has_pps_bid = any(tool_id == "pps_bid_public_info" for tool_id, _ in scored)
535
- if not has_pps_bid:
536
- return scored
537
- return [
538
- (tool_id, score + 1000.0) for tool_id, score in scored if tool_id == "pps_bid_public_info"
539
- ]
45
+ logger = logging.getLogger(__name__)
540
46
 
541
47
 
542
- def _filter_kcue_regional_scores(
543
- query: str, scored: list[tuple[str, float]]
544
- ) -> list[tuple[str, float]]:
545
- if not _is_kcue_regional_query(query):
546
- return scored
547
- has_kcue = any(tool_id in _KCUE_TOOL_IDS for tool_id, _ in scored)
548
- if not has_kcue:
549
- return scored
550
-
551
- prefer_finance = bool(_KCUE_REGIONAL_FINANCE_RE.search(query))
552
- prefer_foreign_student = bool(_KCUE_REGIONAL_FOREIGN_STUDENT_RE.search(query))
553
- boosts = {
554
- "kcue_finance_regional_tuition": 1000.0 if prefer_finance else 700.0,
555
- "kcue_student_regional_foreign": 1000.0 if prefer_foreign_student else 700.0,
556
- }
557
- return [
558
- (tool_id, score + boosts[tool_id]) for tool_id, score in scored if tool_id in _KCUE_TOOL_IDS
559
- ]
560
-
561
-
562
- def _filter_health_detail_scores(
563
- query: str, scored: list[tuple[str, float]]
564
- ) -> list[tuple[str, float]]:
565
- if not _HIRA_MEDICAL_DETAIL_RE.search(query):
566
- return scored
567
- return [
568
- (
569
- tool_id,
570
- score + (650.0 if tool_id == "hira_medical_institution_detail" else 0.0),
571
- )
572
- for tool_id, score in scored
573
- ]
48
+ def is_document_harness_query(query: str) -> bool:
49
+ return _policy_is_document_harness_query(query)
574
50
 
575
51
 
576
- def _filter_initial_special_scores(
577
- query: str, scored: list[tuple[str, float]]
578
- ) -> list[tuple[str, float]]:
579
- if _TRAFFIC_HAZARD_SPECIFIC_RE.search(query):
580
- scored = [
581
- (tool_id, score) for tool_id, score in scored if tool_id != "koroad_accident_search"
582
- ]
583
- if _KMA_ANALYSIS_CHART_RE.search(query):
584
- return [
585
- (tool_id, score)
586
- for tool_id, score in scored
587
- if tool_id == "kma_apihub_url_analysis_weather_chart_image"
588
- ]
589
- return scored
590
-
591
-
592
- def _filter_kma_aviation_scores(
593
- query: str, scored: list[tuple[str, float]], *, is_airport_aviation_query: bool
594
- ) -> list[tuple[str, float]]:
595
- if _KMA_GIMHAE_AIRPORT_RE.search(query) and _KMA_AIRPORT_AVIATION_RE.search(query):
596
- scored = [
597
- (tool_id, score)
598
- for tool_id, score in scored
599
- if tool_id != "kma_apihub_url_air_amos_minute"
600
- ]
601
- if (
602
- _KMA_GIMPO_AIRPORT_RE.search(query)
603
- and _KMA_RUNWAY_AREA_RE.search(query)
604
- and _KMA_AIRPORT_AVIATION_RE.search(query)
605
- ):
606
- scored = [
607
- (tool_id, score + 500.0 if tool_id == "kma_apihub_url_air_amos_minute" else score)
608
- for tool_id, score in scored
609
- ]
610
- if not is_airport_aviation_query:
611
- return scored
612
-
613
- has_air_url_candidate = any(tool_id in _KMA_URL_AIR_TOOL_IDS for tool_id, _ in scored)
614
- if not has_air_url_candidate:
615
- return scored
616
- if _KMA_EXPLICIT_METAR_RE.search(query):
617
- blocked_tool_ids = (
618
- _LOCATION_TOOL_IDS | _KMA_LIFESTYLE_WEATHER_TOOL_IDS | {"kma_forecast_fetch"}
619
- )
620
- scored = [(tool_id, score) for tool_id, score in scored if tool_id not in blocked_tool_ids]
621
- else:
622
- scored = [(tool_id, score) for tool_id, score in scored if tool_id in _KMA_URL_AIR_TOOL_IDS]
623
- prefer_amos = bool(
624
- _KMA_GIMPO_AIRPORT_RE.search(query)
625
- and _KMA_RUNWAY_AREA_RE.search(query)
626
- and not _KMA_GIMHAE_AIRPORT_RE.search(query)
627
- )
628
- return [
629
- (
630
- tool_id,
631
- score
632
- + (
633
- 800.0
634
- if tool_id == "kma_apihub_url_air_amos_minute" and prefer_amos
635
- else 700.0
636
- if tool_id == "kma_apihub_url_air_metar_decoded"
637
- else 0.0
638
- ),
639
- )
640
- for tool_id, score in scored
641
- ]
642
-
643
-
644
- def _boost_aed_scores(query: str, scored: list[tuple[str, float]]) -> list[tuple[str, float]]:
645
- if not _AED_RE.search(query):
646
- return scored
647
- return [
648
- (
649
- tool_id,
650
- score + 900.0
651
- if tool_id == "nmc_aed_site_locate"
652
- else score + 700.0
653
- if tool_id == "nmc_emergency_search" and _EMERGENCY_RE.search(query)
654
- else score,
655
- )
656
- for tool_id, score in scored
657
- ]
52
+ def _expand_query_for_adapter_retrieval(query: str) -> str:
53
+ return _policy_expand_query_for_adapter_retrieval(query)
658
54
 
659
55
 
660
- def _expand_query_for_adapter_retrieval(query: str) -> str:
661
- """Add domain-neutral retrieval hints that Korean spacing can hide.
662
-
663
- The retriever indexes adapter search hints, not a Korean morphological
664
- parse. A station query such as "하단역 근처 응급실" contains a POI suffix,
665
- but does not literally contain the "키워드/POI/랜드마크" terms in
666
- ``kakao_keyword_search``. Expanding only the retrieval query keeps the
667
- adapter contract unchanged while letting the concrete locate adapter stay
668
- visible to the model.
669
- """
670
- additions: list[str] = []
671
- is_airport_aviation_query = _is_airport_aviation_query(query)
672
- if is_airport_aviation_query:
673
- additions.extend(_airport_aviation_additions(query))
674
- if _KMA_ANALYSIS_DATA_RE.search(query):
675
- additions.extend(_kma_analysis_data_additions())
676
- if _is_lifestyle_weather_query(query, is_airport_aviation_query=is_airport_aviation_query):
677
- additions.extend(_kma_lifestyle_weather_additions())
678
- if _POI_LOCATION_RE.search(query) and not is_airport_aviation_query:
679
- additions.extend(["장소", "키워드", "POI", "랜드마크", "역", "keyword"])
680
- if _ADMIN_LOCATION_RE.search(query):
681
- additions.extend(["주소", "행정동", "법정동", "도로명", "지번", "address"])
682
- if _EMERGENCY_RE.search(query):
683
- additions.extend(["응급실", "응급의료", "NMC", "emergency"])
684
- if _AED_RE.search(query):
685
- additions.extend(["AED", "자동심장충격기", "자동제세동기", "국립중앙의료원"])
686
- additions.extend(_emergency_chain_additions(query))
687
- additions.extend(_pps_bid_additions(query))
688
- additions.extend(_kcue_regional_additions(query))
689
- additions.extend(_ocean_water_quality_additions(query))
690
- additions.extend(_health_detail_additions(query))
691
- additions.extend(_public_safety_location_additions(query))
692
- if _TRAFFIC_HAZARD_RE.search(query):
693
- additions.extend(_traffic_hazard_additions())
694
- if not additions:
695
- return query
696
- return f"{query} {' '.join(additions)}"
56
+ def _expand_query_for_intent(query: str, intent: ToolSelectionIntent) -> str:
57
+ return _policy_expand_query_for_intent(query, intent)
697
58
 
698
59
 
699
60
  def _filter_special_case_scores(
700
- query: str, scored: list[tuple[str, float]]
61
+ intent: ToolSelectionIntent, scored: list[tuple[str, float]]
701
62
  ) -> list[tuple[str, float]]:
702
- """Apply deterministic domain disambiguation after backend scoring."""
703
- is_airport_aviation_query = _is_airport_aviation_query(query)
704
- is_analysis_query = bool(_KMA_ANALYSIS_DATA_RE.search(query))
705
- is_analysis_map_query = bool(_KMA_ANALYSIS_MAP_RE.search(query))
706
- is_analysis_point_query = _is_kma_analysis_point_query(
707
- query, is_analysis_map_query=is_analysis_map_query
708
- )
709
- is_lifestyle_weather_query = _is_lifestyle_weather_query(
710
- query, is_airport_aviation_query=is_airport_aviation_query
711
- )
712
- scored = _filter_initial_special_scores(query, scored)
713
- if is_analysis_query:
714
- scored = _filter_kma_analysis_scores(
715
- scored,
716
- is_analysis_map_query=is_analysis_map_query,
717
- is_analysis_point_query=is_analysis_point_query,
718
- prefer_poi_location=bool(_POI_LOCATION_RE.search(query)),
719
- )
720
- if is_lifestyle_weather_query:
721
- scored = _filter_kma_lifestyle_weather_scores(scored)
722
- scored = _filter_emergency_chain_scores(query, scored)
723
- scored = _filter_pps_bid_scores(query, scored)
724
- scored = _filter_kcue_regional_scores(query, scored)
725
- scored = _filter_health_detail_scores(query, scored)
726
- scored = _filter_public_safety_location_scores(query, scored)
727
- scored = _filter_ocean_water_quality_scores(query, scored)
728
- scored = _filter_kma_aviation_scores(
729
- query, scored, is_airport_aviation_query=is_airport_aviation_query
730
- )
731
- scored = _boost_aed_scores(query, scored)
732
-
733
- query_lower = query.lower()
734
- return [
735
- (tool_id, score + 1000.0 if tool_id.lower() in query_lower else score)
736
- for tool_id, score in scored
737
- ]
63
+ return _policy_filter_special_case_scores(intent, scored)
738
64
 
739
65
 
740
66
  def search(
@@ -775,66 +101,28 @@ def search(
775
101
  if registry_size == 0:
776
102
  return []
777
103
 
778
- retriever = registry._retriever
779
- try:
780
- scored = retriever.score(_expand_query_for_adapter_retrieval(query))
781
- except Exception as exc:
782
- # FR-002 fail-open: a mid-session retriever failure (dense OOM,
783
- # tokenizer crash, encoder corruption) must not surface as a 5xx
784
- # on the citizen path. The Retriever protocol does not forbid
785
- # score() from raising, so this is the last defensive boundary
786
- # before the public ``lookup`` contract. Try the retriever's BM25
787
- # companion (present on ``_DenseFailOpenWrapper`` and
788
- # ``HybridBackend``) before falling back to an empty ranking so
789
- # citizens still see lexical matches when the dense path crashes
790
- # outside its own catch-blocks.
791
- logger.warning(
792
- "search: retriever.score failed (%s: %s) — attempting BM25 companion fallback",
793
- type(exc).__name__,
794
- exc,
795
- )
796
- bm25_companion = getattr(retriever, "_bm25", None)
797
- if bm25_companion is None:
798
- logger.warning(
799
- "search: no BM25 companion on retriever %s — returning empty ranking",
800
- type(retriever).__name__,
801
- )
802
- return []
803
- try:
804
- scored = bm25_companion.score(_expand_query_for_adapter_retrieval(query))
805
- except Exception as bm25_exc:
806
- logger.warning(
807
- "search: BM25 companion also failed (%s: %s) — returning empty ranking",
808
- type(bm25_exc).__name__,
809
- bm25_exc,
810
- )
811
- return []
812
-
813
- scored = _filter_special_case_scores(query, scored)
814
-
815
- # Enforce the deterministic tie-break once, here. Backend-internal
816
- # orderings are not trusted (HybridBackend returns unordered union).
817
- scored = sorted(scored, key=lambda pair: (-pair[1], pair[0]))
818
-
819
- # Derive the backend label from the active retriever. Prefer the
820
- # explicit ``_requested_backend_label`` attribute (set on wrappers
821
- # like ``_DenseFailOpenWrapper`` that report a logical backend name
822
- # distinct from their Python class name) so ``why_matched`` reflects
823
- # the operator's configured backend, not an internal wrapper type.
824
- backend_label = getattr(
825
- retriever,
826
- "_requested_backend_label",
827
- type(retriever).__name__.removesuffix("Backend").lower() or "retrieval",
104
+ intent = extract_tool_selection_intent(query, known_tool_ids=registry._tools.keys())
105
+
106
+ from ummaya.tools.routing.decision_service import RouteDecisionService
107
+
108
+ decision = RouteDecisionService(registry).select_adapters(
109
+ query,
110
+ top_k=effective_top_k,
111
+ max_selected=effective_top_k,
112
+ intent=intent,
113
+ drop_zero_score_candidates=False,
828
114
  )
829
115
 
830
116
  results: list[AdapterCandidate] = []
831
- for tool_id, score in scored[:effective_top_k]:
117
+ for route_candidate in decision.candidate_set:
118
+ tool_id = route_candidate.tool_id
832
119
  try:
833
120
  tool = registry.find(tool_id)
834
121
  except Exception: # pragma: no cover
835
122
  logger.warning("search: tool %r in retriever but not in registry", tool_id)
836
123
  continue
837
124
 
125
+ score = route_candidate.retrieval_score
838
126
  input_schema_json, required_params = _input_schema_export(tool)
839
127
  output_schema_json = _output_schema_export(tool)
840
128
  candidate = AdapterCandidate(
@@ -842,7 +130,7 @@ def search(
842
130
  score=max(0.0, float(score)),
843
131
  required_params=required_params,
844
132
  search_hint=tool.search_hint,
845
- why_matched=f"{backend_label} score {score:.4f} on search_hint",
133
+ why_matched=f"{decision.backend_label} score {score:.4f} on search_hint",
846
134
  input_schema_json=input_schema_json,
847
135
  output_schema_json=output_schema_json,
848
136
  llm_description=tool.llm_description,