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.
- package/README.md +17 -3
- package/bin/ummaya +10 -1
- package/npm-shrinkwrap.json +253 -2
- package/package.json +5 -1
- package/prompts/manifest.yaml +2 -2
- package/prompts/session_guidance_v1.md +3 -1
- package/prompts/system_v1.md +9 -7
- package/pyproject.toml +26 -7
- package/specs/2803-document-production-hardening/contracts/document-tools.schema.json +1043 -0
- package/src/ummaya/_canonical/__init__.py +2 -0
- package/src/ummaya/context/builder.py +17 -11
- package/src/ummaya/engine/engine.py +30 -113
- package/src/ummaya/engine/query.py +20 -0
- package/src/ummaya/evidence/__init__.py +44 -0
- package/src/ummaya/evidence/__main__.py +7 -0
- package/src/ummaya/evidence/dataset_contract.py +193 -0
- package/src/ummaya/evidence/document_authoring_cases.py +33 -0
- package/src/ummaya/evidence/document_harness.py +313 -0
- package/src/ummaya/evidence/document_viewer_ux.py +391 -0
- package/src/ummaya/evidence/gates.py +70 -0
- package/src/ummaya/evidence/json_types.py +20 -0
- package/src/ummaya/evidence/models.py +145 -0
- package/src/ummaya/evidence/output_payload.py +89 -0
- package/src/ummaya/evidence/payload_documents.py +233 -0
- package/src/ummaya/evidence/route_contracts.py +224 -0
- package/src/ummaya/evidence/route_helpers.py +150 -0
- package/src/ummaya/evidence/runner.py +177 -0
- package/src/ummaya/evidence/source_provenance.py +246 -0
- package/src/ummaya/evidence/source_provenance_redaction.py +176 -0
- package/src/ummaya/evidence/task_registry.py +264 -0
- package/src/ummaya/evidence/tool_layer.py +39 -0
- package/src/ummaya/evidence/tool_layer_models.py +151 -0
- package/src/ummaya/ipc/adapter_manifest_emitter.py +26 -10
- package/src/ummaya/ipc/document_intent_normalization.py +185 -0
- package/src/ummaya/ipc/frame_schema.py +52 -5
- package/src/ummaya/ipc/route_diagnostics.py +73 -0
- package/src/ummaya/ipc/stdio.py +2282 -417
- package/src/ummaya/llm/client.py +234 -59
- package/src/ummaya/llm/config.py +8 -3
- package/src/ummaya/llm/reasoning.py +84 -0
- package/src/ummaya/primitives/__init__.py +6 -2
- package/src/ummaya/primitives/delegation.py +1 -1
- package/src/ummaya/primitives/document.py +28 -0
- package/src/ummaya/settings.py +0 -3
- package/src/ummaya/tools/discovery_bridge.py +34 -2
- package/src/ummaya/tools/documents/__init__.py +297 -0
- package/src/ummaya/tools/documents/adapter_registry.py +487 -0
- package/src/ummaya/tools/documents/archive_container_probe.py +167 -0
- package/src/ummaya/tools/documents/artifact_store.py +454 -0
- package/src/ummaya/tools/documents/authoring.py +283 -0
- package/src/ummaya/tools/documents/baselines.py +114 -0
- package/src/ummaya/tools/documents/capability.py +331 -0
- package/src/ummaya/tools/documents/contracts.py +112 -0
- package/src/ummaya/tools/documents/conversion.py +521 -0
- package/src/ummaya/tools/documents/diff.py +275 -0
- package/src/ummaya/tools/documents/engines.py +163 -0
- package/src/ummaya/tools/documents/evaluation.py +291 -0
- package/src/ummaya/tools/documents/explicit_values.py +108 -0
- package/src/ummaya/tools/documents/fixtures.py +174 -0
- package/src/ummaya/tools/documents/format_completion_audit.py +471 -0
- package/src/ummaya/tools/documents/formats/__init__.py +2 -0
- package/src/ummaya/tools/documents/formats/archive.py +528 -0
- package/src/ummaya/tools/documents/formats/base.py +41 -0
- package/src/ummaya/tools/documents/formats/code_file.py +211 -0
- package/src/ummaya/tools/documents/formats/data_file.py +272 -0
- package/src/ummaya/tools/documents/formats/hwp.py +284 -0
- package/src/ummaya/tools/documents/formats/hwpx.py +1837 -0
- package/src/ummaya/tools/documents/formats/odf.py +435 -0
- package/src/ummaya/tools/documents/formats/ooxml.py +1030 -0
- package/src/ummaya/tools/documents/formats/passive.py +766 -0
- package/src/ummaya/tools/documents/formats/pdf.py +702 -0
- package/src/ummaya/tools/documents/formats/text_web.py +268 -0
- package/src/ummaya/tools/documents/hwp_conversion_probe.py +178 -0
- package/src/ummaya/tools/documents/hwp_direct_candidate.py +141 -0
- package/src/ummaya/tools/documents/inspection.py +289 -0
- package/src/ummaya/tools/documents/intake.py +1079 -0
- package/src/ummaya/tools/documents/legacy_office_promotion_probe.py +366 -0
- package/src/ummaya/tools/documents/models.py +1598 -0
- package/src/ummaya/tools/documents/odf_promotion_probe.py +167 -0
- package/src/ummaya/tools/documents/orchestrator.py +96 -0
- package/src/ummaya/tools/documents/passive_capability_probe.py +251 -0
- package/src/ummaya/tools/documents/patch.py +170 -0
- package/src/ummaya/tools/documents/pdfa_conformance.py +284 -0
- package/src/ummaya/tools/documents/pdfa_promotion_probe.py +198 -0
- package/src/ummaya/tools/documents/permissions.py +110 -0
- package/src/ummaya/tools/documents/planner.py +616 -0
- package/src/ummaya/tools/documents/registry.py +2733 -0
- package/src/ummaya/tools/documents/render.py +978 -0
- package/src/ummaya/tools/documents/render_comparison.py +113 -0
- package/src/ummaya/tools/documents/render_comparison_models.py +74 -0
- package/src/ummaya/tools/documents/render_comparison_regions.py +73 -0
- package/src/ummaya/tools/documents/render_comparison_style.py +161 -0
- package/src/ummaya/tools/documents/reread.py +157 -0
- package/src/ummaya/tools/documents/runtime_authoring.py +244 -0
- package/src/ummaya/tools/documents/runtime_authoring_bundle.py +76 -0
- package/src/ummaya/tools/documents/scorecard.py +184 -0
- package/src/ummaya/tools/documents/socratic_planner.py +193 -0
- package/src/ummaya/tools/documents/style.py +48 -0
- package/src/ummaya/tools/documents/tool_defs.py +523 -0
- package/src/ummaya/tools/documents/validate.py +347 -0
- package/src/ummaya/tools/executor.py +61 -12
- package/src/ummaya/tools/geocoding/kakao_client.py +1 -2
- package/src/ummaya/tools/kma/apihub_catalog.py +984 -1
- package/src/ummaya/tools/kma/apihub_structured_adapter.py +86 -6
- package/src/ummaya/tools/kma/apihub_url_adapter.py +593 -0
- package/src/ummaya/tools/kma/apihub_url_catalog.py +296 -0
- package/src/ummaya/tools/live_proxy.py +0 -3
- package/src/ummaya/tools/location_adapters.py +8 -6
- package/src/ummaya/tools/manifest_metadata.py +16 -3
- package/src/ummaya/tools/models.py +5 -1
- package/src/ummaya/tools/mvp_surface.py +2 -2
- package/src/ummaya/tools/nmc/emergency_search.py +8 -6
- package/src/ummaya/tools/register_all.py +17 -0
- package/src/ummaya/tools/registry.py +10 -1
- package/src/ummaya/tools/resolve_location.py +4 -4
- package/src/ummaya/tools/routing/__init__.py +59 -0
- package/src/ummaya/tools/routing/builder.py +105 -0
- package/src/ummaya/tools/routing/cards.py +29 -0
- package/src/ummaya/tools/routing/decision_service.py +534 -0
- package/src/ummaya/tools/routing/decision_types.py +74 -0
- package/src/ummaya/tools/routing/feasibility.py +122 -0
- package/src/ummaya/tools/routing/intent.py +17 -0
- package/src/ummaya/tools/routing/intent_extractor.py +207 -0
- package/src/ummaya/tools/routing/intent_patterns.py +160 -0
- package/src/ummaya/tools/routing/intent_public_data.py +150 -0
- package/src/ummaya/tools/routing/intent_types.py +48 -0
- package/src/ummaya/tools/routing/lint.py +78 -0
- package/src/ummaya/tools/routing/metadata.py +174 -0
- package/src/ummaya/tools/routing/projection.py +340 -0
- package/src/ummaya/tools/routing/retrieval_policy.py +629 -0
- package/src/ummaya/tools/routing/schema.py +81 -0
- package/src/ummaya/tools/routing/types.py +96 -0
- package/src/ummaya/tools/routing_index.py +2 -2
- package/src/ummaya/tools/search.py +40 -106
- package/src/ummaya/tools/verified_data_go_kr/_manifest.py +115 -25
- package/src/ummaya/tools/verified_data_go_kr/airkorea_air_quality.py +109 -4
- package/src/ummaya/tools/verified_data_go_kr/nmc_aed_site.py +108 -2
- package/src/ummaya/tools/verified_data_go_kr/pps_bid_public_info.py +174 -9
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_arrival.py +66 -3
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_location.py +12 -2
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_route.py +8 -2
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_route_station.py +114 -0
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_station.py +14 -3
- package/src/ummaya/tools/verify_canonical_map.py +21 -0
- package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
- package/tui/package.json +1 -2
- package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
- package/tui/src/QueryEngine.ts +12 -4
- package/tui/src/bridge/inboundAttachments.ts +3 -3
- package/tui/src/cli/handlers/auth.ts +4 -13
- package/tui/src/cli/handlers/mcp.tsx +3 -3
- package/tui/src/cli/print.ts +69 -18
- package/tui/src/cli/update.ts +13 -13
- package/tui/src/commands/copy/index.ts +1 -1
- package/tui/src/commands/cost/cost.ts +2 -2
- package/tui/src/commands/init-verifiers.ts +5 -5
- package/tui/src/commands/init.ts +30 -30
- package/tui/src/commands/insights.ts +44 -44
- package/tui/src/commands/install-github-app/install-github-app.tsx +2 -2
- package/tui/src/commands/install-github-app/setupGitHubActions.ts +3 -3
- package/tui/src/commands/install-github-app/types.ts +8 -30
- package/tui/src/commands/install.tsx +5 -5
- package/tui/src/commands/mcp/addCommand.ts +5 -5
- package/tui/src/commands/mcp/xaaIdpCommand.ts +2 -2
- package/tui/src/commands/plugin/ManageMarketplaces.tsx +2 -2
- package/tui/src/commands/plugin/types.ts +6 -28
- package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
- package/tui/src/commands/reasoning/index.ts +13 -0
- package/tui/src/commands/reasoning/reasoning.tsx +177 -0
- package/tui/src/commands/rename/generateSessionName.ts +1 -1
- package/tui/src/commands/thinkback/thinkback.tsx +3 -3
- package/tui/src/commands.ts +2 -0
- package/tui/src/components/Feedback.tsx +1 -1
- package/tui/src/components/LogoV2/EmergencyTip.tsx +11 -2
- package/tui/src/components/LogoV2/WelcomeV2.tsx +1 -3
- package/tui/src/components/Messages.tsx +2 -1
- package/tui/src/components/ScrollKeybindingHandler.tsx +6 -6
- package/tui/src/components/Spinner/types.ts +6 -28
- package/tui/src/components/Spinner.tsx +2 -2
- package/tui/src/components/agents/generateAgent.ts +1 -1
- package/tui/src/components/agents/new-agent-creation/types.ts +4 -26
- package/tui/src/components/config/EnvSecretIsolatedEditor.tsx +1 -1
- package/tui/src/components/design-system/LoadingState.tsx +2 -2
- package/tui/src/components/mcp/types.ts +16 -38
- package/tui/src/components/messages/AssistantToolUseMessage.tsx +3 -2
- package/tui/src/components/messages/UserCrossSessionMessage.ts +16 -4
- package/tui/src/components/messages/UserForkBoilerplateMessage.ts +16 -4
- package/tui/src/components/messages/UserGitHubWebhookMessage.ts +16 -4
- package/tui/src/components/messages/UserToolResultMessage/utils.tsx +3 -2
- package/tui/src/components/permissions/MonitorPermissionRequest/MonitorPermissionRequest.ts +9 -4
- package/tui/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.ts +9 -4
- package/tui/src/components/primitive/DocumentSocraticReviewBlock.tsx +129 -0
- package/tui/src/components/primitive/DocumentToolResultCard.tsx +224 -0
- package/tui/src/components/primitive/documentSocraticReview.ts +215 -0
- package/tui/src/components/primitive/index.tsx +43 -1
- package/tui/src/components/primitive/types.ts +137 -0
- package/tui/src/components/ui/option.ts +4 -26
- package/tui/src/constants/common.ts +0 -2
- package/tui/src/constants/prompts.ts +4 -3
- package/tui/src/constants/querySource.ts +4 -26
- package/tui/src/entrypoints/sdk/controlTypes.ts +26 -48
- package/tui/src/entrypoints/sdk/coreTypes.generated.ts +3 -25
- package/tui/src/entrypoints/sdk/runtimeTypes.ts +38 -60
- package/tui/src/entrypoints/sdk/sdkUtilityTypes.ts +4 -26
- package/tui/src/entrypoints/sdk/settingsTypes.generated.ts +3 -25
- package/tui/src/entrypoints/sdk/toolTypes.ts +3 -25
- package/tui/src/hooks/toolPermission/handlers/interactiveHandler.ts +10 -0
- package/tui/src/hooks/useApiKeyVerification.ts +1 -1
- package/tui/src/hooks/useVirtualScroll.ts +1 -1
- package/tui/src/ink/ink.tsx +33 -14
- package/tui/src/ink/reconciler.ts +2 -3
- package/tui/src/ink/render-to-screen.ts +30 -10
- package/tui/src/ipc/bridge.ts +62 -15
- package/tui/src/ipc/bridgeSingleton.ts +5 -1
- package/tui/src/ipc/codec.ts +29 -3
- package/tui/src/ipc/frames.generated.ts +407 -312
- package/tui/src/ipc/llmClient.ts +279 -76
- package/tui/src/ipc/llmTypes.ts +16 -1
- package/tui/src/ipc/schema/frame.schema.json +1 -3475
- package/tui/src/keybindings/defaultBindings.ts +4 -0
- package/tui/src/main.tsx +32 -11
- package/tui/src/native-ts/file-index/index.ts +33 -3
- package/tui/src/observability/surface.ts +2 -2
- package/tui/src/probes/toolRegistryProbe.tsx +3 -1
- package/tui/src/projectOnboardingState.ts +7 -6
- package/tui/src/query/chatMessageTypes.ts +18 -0
- package/tui/src/query/chatMessagesBuilder.ts +1 -1
- package/tui/src/query/deps.ts +1 -1
- package/tui/src/query/messageGuards.ts +106 -0
- package/tui/src/query/publicDataTerminalRepair.ts +384 -0
- package/tui/src/query/run.ts +1075 -0
- package/tui/src/query/supportBoundary.ts +168 -0
- package/tui/src/query/toolResultErrors.ts +103 -0
- package/tui/src/query/toolRunner.ts +687 -0
- package/tui/src/query/unavailableToolRepair.ts +118 -0
- package/tui/src/query.ts +9 -1721
- package/tui/src/screens/REPL.tsx +42 -31
- package/tui/src/services/api/adapterManifest.ts +4 -0
- package/tui/src/services/api/backendChat/events.ts +117 -0
- package/tui/src/services/api/backendChat/finalMessage.ts +40 -0
- package/tui/src/services/api/backendChat/frame.ts +9 -0
- package/tui/src/services/api/backendChat/streaming.ts +430 -0
- package/tui/src/services/api/backendChat/types.ts +62 -0
- package/tui/src/services/api/backendChat.ts +1 -0
- package/tui/src/services/api/client.ts +98 -14
- package/tui/src/services/api/errorUtils.ts +5 -5
- package/tui/src/services/api/errors.ts +1 -1
- package/tui/src/services/api/logging.ts +1 -1
- package/tui/src/services/api/ummaya/evidence.ts +194 -0
- package/tui/src/services/api/ummaya/messages.ts +255 -0
- package/tui/src/services/api/ummaya/nonStreaming.ts +66 -0
- package/tui/src/services/api/ummaya/provider.ts +200 -0
- package/tui/src/services/api/ummaya/reasoning.ts +24 -0
- package/tui/src/services/api/ummaya/request.ts +200 -0
- package/tui/src/services/api/ummaya/selectionContext.ts +240 -0
- package/tui/src/services/api/ummaya/streaming.ts +365 -0
- package/tui/src/services/api/ummaya/streamingPayload.ts +129 -0
- package/tui/src/services/api/ummaya/streamingReader.ts +40 -0
- package/tui/src/services/api/ummaya/toolSelection.ts +217 -0
- package/tui/src/services/api/ummaya/types.ts +110 -0
- package/tui/src/services/api/ummaya/usage.ts +30 -0
- package/tui/src/services/api/ummaya.ts +26 -364
- package/tui/src/services/api/withRetry.ts +1 -1
- package/tui/src/services/awaySummary.ts +2 -2
- package/tui/src/services/claudeAiLimits.ts +1 -1
- package/tui/src/services/compact/autoCompact.ts +1 -1
- package/tui/src/services/compact/compact.ts +1 -1
- package/tui/src/services/lsp/types.ts +8 -30
- package/tui/src/services/tips/types.ts +6 -28
- package/tui/src/services/tokenEstimation.ts +1 -1
- package/tui/src/services/toolRegistry/bootGuard.ts +5 -5
- package/tui/src/services/toolUseSummary/toolUseSummaryGenerator.ts +1 -1
- package/tui/src/services/tools/toolExecution.ts +94 -1
- package/tui/src/skills/bundled/stuck.ts +12 -12
- package/tui/src/state/AppStateStore.ts +7 -0
- package/tui/src/store/pendingPermissionSlot.ts +1 -1
- package/tui/src/store/session-store.ts +10 -36
- package/tui/src/stubs/any-stub.ts +15 -10
- package/tui/src/stubs/color-diff-napi.ts +37 -23
- package/tui/src/stubs/globals.d.ts +3 -3
- package/tui/src/stubs/macro-preload.ts +23 -12
- package/tui/src/tools/AdapterTool/AdapterTool.ts +1239 -163
- package/tui/src/tools/AdapterTool/routeDiagnostics.ts +75 -0
- package/tui/src/tools/AgentTool/AgentTool.tsx +84 -1371
- package/tui/src/tools/AgentTool/agentToolHandoff.ts +114 -0
- package/tui/src/tools/AgentTool/agentToolPartialResult.ts +16 -0
- package/tui/src/tools/AgentTool/agentToolProgress.ts +32 -0
- package/tui/src/tools/AgentTool/agentToolResolver.ts +161 -0
- package/tui/src/tools/AgentTool/agentToolResult.ts +163 -0
- package/tui/src/tools/AgentTool/agentToolUtils.ts +14 -686
- package/tui/src/tools/AgentTool/asyncAgentLifecycle.ts +208 -0
- package/tui/src/tools/AgentTool/asyncLifecycle.ts +153 -0
- package/tui/src/tools/AgentTool/backgroundedCompletion.ts +126 -0
- package/tui/src/tools/AgentTool/backgroundedLifecycle.ts +174 -0
- package/tui/src/tools/AgentTool/foregroundBackground.ts +83 -0
- package/tui/src/tools/AgentTool/foregroundDrain.tsx +133 -0
- package/tui/src/tools/AgentTool/foregroundFinalize.ts +98 -0
- package/tui/src/tools/AgentTool/foregroundLifecycle.tsx +237 -0
- package/tui/src/tools/AgentTool/foregroundProgress.tsx +169 -0
- package/tui/src/tools/AgentTool/foregroundTask.ts +89 -0
- package/tui/src/tools/AgentTool/forkSubagent.ts +1 -12
- package/tui/src/tools/AgentTool/forkSubagentGate.ts +34 -0
- package/tui/src/tools/AgentTool/launchRouting.ts +203 -0
- package/tui/src/tools/AgentTool/lifecycle.ts +244 -0
- package/tui/src/tools/AgentTool/mcpRouting.ts +73 -0
- package/tui/src/tools/AgentTool/orchestrationSupport.ts +70 -0
- package/tui/src/tools/AgentTool/permissions.ts +39 -0
- package/tui/src/tools/AgentTool/promptSetup.ts +181 -0
- package/tui/src/tools/AgentTool/remoteRouting.ts +62 -0
- package/tui/src/tools/AgentTool/resultMapping.ts +116 -0
- package/tui/src/tools/AgentTool/resumeAgent.ts +39 -107
- package/tui/src/tools/AgentTool/resumeAgentHelpers.ts +140 -0
- package/tui/src/tools/AgentTool/runAgent.ts +1 -1
- package/tui/src/tools/AgentTool/runtimeConfig.ts +57 -0
- package/tui/src/tools/AgentTool/schemas.ts +196 -0
- package/tui/src/tools/AgentTool/sourceVerificationPropagation.ts +263 -0
- package/tui/src/tools/AgentTool/worktreeLifecycle.ts +105 -0
- package/tui/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +174 -202
- package/tui/src/tools/BashTool/BashTool.tsx +71 -1072
- package/tui/src/tools/BashTool/bashCommandHelpers.ts +12 -12
- package/tui/src/tools/BashTool/bashPermissions/astPreflight.ts +173 -0
- package/tui/src/tools/BashTool/bashPermissions/classifierChecks.ts +199 -0
- package/tui/src/tools/BashTool/bashPermissions/compoundGuards.ts +53 -0
- package/tui/src/tools/BashTool/bashPermissions/constants.ts +99 -0
- package/tui/src/tools/BashTool/bashPermissions/index.ts +38 -0
- package/tui/src/tools/BashTool/bashPermissions/legacyMisparsing.ts +62 -0
- package/tui/src/tools/BashTool/bashPermissions/main.ts +135 -0
- package/tui/src/tools/BashTool/bashPermissions/normalizedCommands.ts +33 -0
- package/tui/src/tools/BashTool/bashPermissions/operatorFlow.ts +98 -0
- package/tui/src/tools/BashTool/bashPermissions/permissionChecks.ts +200 -0
- package/tui/src/tools/BashTool/bashPermissions/prefixSuggestions.ts +88 -0
- package/tui/src/tools/BashTool/bashPermissions/promptClassifierRules.ts +125 -0
- package/tui/src/tools/BashTool/bashPermissions/ruleDelegates.ts +19 -0
- package/tui/src/tools/BashTool/bashPermissions/ruleMatching.ts +145 -0
- package/tui/src/tools/BashTool/bashPermissions/sandboxAutoAllow.ts +75 -0
- package/tui/src/tools/BashTool/bashPermissions/subcommandFlow.ts +205 -0
- package/tui/src/tools/BashTool/bashPermissions/subcommandGuards.ts +73 -0
- package/tui/src/tools/BashTool/bashPermissions/subcommandResultHelpers.ts +116 -0
- package/tui/src/tools/BashTool/bashPermissions/types.ts +26 -0
- package/tui/src/tools/BashTool/bashPermissions/wrapperStripping.ts +139 -0
- package/tui/src/tools/BashTool/bashPermissions.ts +26 -2621
- package/tui/src/tools/BashTool/call.ts +202 -0
- package/tui/src/tools/BashTool/callLoader.ts +35 -0
- package/tui/src/tools/BashTool/commandClassification.ts +151 -0
- package/tui/src/tools/BashTool/commandClassificationLoader.ts +40 -0
- package/tui/src/tools/BashTool/cwdReset.ts +33 -0
- package/tui/src/tools/BashTool/lineTruncation.ts +11 -0
- package/tui/src/tools/BashTool/modeValidation.ts +13 -1
- package/tui/src/tools/BashTool/outputPersistence.ts +42 -0
- package/tui/src/tools/BashTool/permissionClassification.ts +66 -0
- package/tui/src/tools/BashTool/permissionLoader.ts +44 -0
- package/tui/src/tools/BashTool/resultLoader.ts +29 -0
- package/tui/src/tools/BashTool/resultMapping.ts +83 -0
- package/tui/src/tools/BashTool/sandboxPolicy.ts +79 -0
- package/tui/src/tools/BashTool/schemas.ts +65 -0
- package/tui/src/tools/BashTool/sedEditExecution.ts +59 -0
- package/tui/src/tools/BashTool/shellExecution.tsx +245 -0
- package/tui/src/tools/BashTool/shellOutputUtils.ts +85 -0
- package/tui/src/tools/BashTool/shellPermissionGauntlet.ts +97 -0
- package/tui/src/tools/BashTool/uiLoader.ts +37 -0
- package/tui/src/tools/BriefTool/upload.ts +1 -1
- package/tui/src/tools/CalculatorTool/parser.ts +2 -2
- package/tui/src/tools/DocumentPrimitive/DocumentPrimitive.ts +262 -0
- package/tui/src/tools/DocumentPrimitive/dispatchNormalization.ts +270 -0
- package/tui/src/tools/DocumentPrimitive/documentDestinationPath.ts +18 -0
- package/tui/src/tools/DocumentPrimitive/documentMutationGuard.ts +22 -0
- package/tui/src/tools/DocumentPrimitive/documentPatchNormalization.ts +248 -0
- package/tui/src/tools/DocumentPrimitive/documentSourceVerification.ts +245 -0
- package/tui/src/tools/DocumentPrimitive/documentSourceVerificationFields.ts +103 -0
- package/tui/src/tools/DocumentPrimitive/modelVisibleOutput.ts +40 -0
- package/tui/src/tools/DocumentPrimitive/prompt.ts +35 -0
- package/tui/src/tools/FileEditTool/FileEditTool.ts +9 -507
- package/tui/src/tools/FileEditTool/call.ts +228 -0
- package/tui/src/tools/FileEditTool/validateInput.ts +196 -0
- package/tui/src/tools/FileReadTool/imageProcessor.ts +13 -0
- package/tui/src/tools/FileWriteTool/FileWriteTool.ts +7 -300
- package/tui/src/tools/FileWriteTool/call.ts +223 -0
- package/tui/src/tools/FileWriteTool/validateInput.ts +80 -0
- package/tui/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +19 -3
- package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +48 -29
- package/tui/src/tools/LookupPrimitive/prompt.ts +6 -7
- package/tui/src/tools/MCPTool/trustPolicy.ts +118 -0
- package/tui/src/tools/McpAuthTool/McpAuthTool.ts +21 -3
- package/tui/src/tools/NotebookEditTool/NotebookEditTool.ts +7 -326
- package/tui/src/tools/NotebookEditTool/call.ts +254 -0
- package/tui/src/tools/NotebookEditTool/notebookModel.ts +51 -0
- package/tui/src/tools/NotebookEditTool/validateInput.ts +142 -0
- package/tui/src/tools/PowerShellTool/PowerShellTool.tsx +46 -937
- package/tui/src/tools/PowerShellTool/acceptEditsCommandValidation.ts +162 -0
- package/tui/src/tools/PowerShellTool/call.ts +179 -0
- package/tui/src/tools/PowerShellTool/callLoader.ts +37 -0
- package/tui/src/tools/PowerShellTool/commandClassification.ts +86 -0
- package/tui/src/tools/PowerShellTool/modeValidation.ts +25 -332
- package/tui/src/tools/PowerShellTool/outputPersistence.ts +42 -0
- package/tui/src/tools/PowerShellTool/permissionClassification.ts +28 -0
- package/tui/src/tools/PowerShellTool/resultLoader.ts +31 -0
- package/tui/src/tools/PowerShellTool/resultMapping.ts +75 -0
- package/tui/src/tools/PowerShellTool/schemas.ts +40 -0
- package/tui/src/tools/PowerShellTool/shellExecution.tsx +258 -0
- package/tui/src/tools/PowerShellTool/symlinkModeValidation.ts +44 -0
- package/tui/src/tools/PowerShellTool/uiLoader.ts +37 -0
- package/tui/src/tools/PowerShellTool/validation.ts +39 -0
- package/tui/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +19 -3
- package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +30 -19
- package/tui/src/tools/ResolveLocationPrimitive/prompt.ts +2 -6
- package/tui/src/tools/SkillTool/SkillTool.ts +2 -2
- package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +51 -18
- package/tui/src/tools/TaskCreateTool/TaskCreateTool.ts +16 -2
- package/tui/src/tools/TaskGetTool/TaskGetTool.ts +23 -3
- package/tui/src/tools/TaskListTool/TaskListTool.ts +22 -4
- package/tui/src/tools/TaskOutputTool/TaskOutputTool.tsx +46 -547
- package/tui/src/tools/TaskOutputTool/lookup.ts +216 -0
- package/tui/src/tools/TaskOutputTool/render.tsx +257 -0
- package/tui/src/tools/TaskOutputTool/schemas.ts +55 -0
- package/tui/src/tools/TaskOutputTool/serialization.ts +36 -0
- package/tui/src/tools/TaskStopTool/TaskStopTool.ts +10 -0
- package/tui/src/tools/TaskUpdateTool/TaskUpdateTool.ts +14 -364
- package/tui/src/tools/TaskUpdateTool/completion.ts +62 -0
- package/tui/src/tools/TaskUpdateTool/schemas.ts +62 -0
- package/tui/src/tools/TaskUpdateTool/serialization.ts +46 -0
- package/tui/src/tools/TaskUpdateTool/statusUpdate.ts +247 -0
- package/tui/src/tools/TodoWriteTool/TodoWriteTool.ts +21 -2
- package/tui/src/tools/ToolSearchTool/ToolSearchTool.ts +21 -302
- package/tui/src/tools/ToolSearchTool/ccSupportTools.ts +223 -0
- package/tui/src/tools/ToolSearchTool/descriptionCache.ts +50 -0
- package/tui/src/tools/ToolSearchTool/keywordSearch.ts +216 -0
- package/tui/src/tools/ToolSearchTool/prompt.ts +10 -4
- package/tui/src/tools/ToolSearchTool/resultMapping.ts +30 -0
- package/tui/src/tools/ToolSearchTool/schemas.ts +30 -0
- package/tui/src/tools/ToolSearchTool/searchPool.ts +47 -0
- package/tui/src/tools/ToolSearchTool/supportIntentHints.ts +140 -0
- package/tui/src/tools/TranslateTool/TranslateTool.ts +1 -1
- package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +27 -10
- package/tui/src/tools/WebFetchTool/WebFetchTool.ts +43 -138
- package/tui/src/tools/WebFetchTool/call.ts +227 -0
- package/tui/src/tools/WebFetchTool/resolvedAddressSafety.ts +78 -0
- package/tui/src/tools/WebFetchTool/sourceVerification.ts +204 -0
- package/tui/src/tools/WebFetchTool/types.ts +23 -0
- package/tui/src/tools/WebFetchTool/urlSafety.ts +181 -0
- package/tui/src/tools/WebFetchTool/utils.ts +1 -1
- package/tui/src/tools/WebSearchTool/UI.tsx +0 -1
- package/tui/src/tools/WebSearchTool/WebSearchTool.ts +9 -313
- package/tui/src/tools/WebSearchTool/call.ts +33 -0
- package/tui/src/tools/WebSearchTool/responseMapping.ts +190 -0
- package/tui/src/tools/WebSearchTool/resultBlock.ts +47 -0
- package/tui/src/tools/WebSearchTool/schemas.ts +47 -0
- package/tui/src/tools/WebSearchTool/toolSchema.ts +12 -0
- package/tui/src/tools/WorkspaceToolAdapter/WorkspaceToolAdapter.ts +79 -0
- package/tui/src/tools/WorkspaceToolAdapter/allowedRootPolicy.ts +85 -0
- package/tui/src/tools/WorkspaceToolAdapter/documentFormatGuards.ts +73 -0
- package/tui/src/tools/WorkspaceToolAdapter/inputNormalization.ts +105 -0
- package/tui/src/tools/WorkspaceToolAdapter/mcpExposurePolicy.ts +64 -0
- package/tui/src/tools/WorkspaceToolAdapter/toolDefFactory.ts +215 -0
- package/tui/src/tools/WorkspaceToolAdapter/toolNames.ts +6 -0
- package/tui/src/tools/WorkspaceToolAdapter/workspacePolicy.ts +15 -0
- package/tui/src/tools/_shared/citizenUserText.ts +49 -0
- package/tui/src/tools/_shared/dispatchPrimitive.ts +6 -6
- package/tui/src/tools/_shared/documentChangeToPatch.ts +125 -0
- package/tui/src/tools/_shared/documentDispatchArguments.ts +87 -0
- package/tui/src/tools/_shared/documentPrimitiveTimeout.ts +13 -0
- package/tui/src/tools/_shared/documentToolResultRender.ts +98 -0
- package/tui/src/tools/_shared/locationInputRepair.ts +112 -0
- package/tui/src/tools/_shared/pendingCallRegistry.ts +1 -6
- package/tui/src/tools/_shared/rootPrimitiveInput.ts +68 -0
- package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPatterns.ts +58 -0
- package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPrompt.ts +271 -0
- package/tui/src/tools/_shared/toolChoiceRepair/documentRepair.ts +452 -0
- package/tui/src/tools/_shared/toolChoiceRepair/messageAccess.ts +80 -0
- package/tui/src/tools/_shared/toolChoiceRepair/publicDataRepair.ts +92 -0
- package/tui/src/tools/_shared/toolChoiceRepair/supportRepair.ts +135 -0
- package/tui/src/tools/_shared/toolChoiceRepair.ts +61 -0
- package/tui/src/tools/shared/mockDisclaimer.ts +1 -1
- package/tui/src/tools.ts +39 -190
- package/tui/src/types/fileSuggestion.ts +4 -26
- package/tui/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +186 -148
- package/tui/src/types/generated/events_mono/common/v1/auth.ts +25 -11
- package/tui/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +47 -30
- package/tui/src/types/generated/google/protobuf/timestamp.ts +21 -7
- package/tui/src/types/message.ts +80 -102
- package/tui/src/types/messageQueueTypes.ts +6 -28
- package/tui/src/types/notebook.ts +16 -38
- package/tui/src/types/statusLine.ts +4 -26
- package/tui/src/types/tools.ts +24 -46
- package/tui/src/types/utils.ts +6 -28
- package/tui/src/upstreamproxy/relay.ts +7 -3
- package/tui/src/upstreamproxy/upstreamproxy.ts +1 -1
- package/tui/src/utils/assistantMessageFactories.ts +9 -3
- package/tui/src/utils/attachments.ts +1 -1
- package/tui/src/utils/auth.ts +129 -139
- package/tui/src/utils/bash/ast.ts +23 -23
- package/tui/src/utils/bash/bashParser.ts +5 -5
- package/tui/src/utils/billing.ts +1 -1
- package/tui/src/utils/collapseReadSearch.ts +3 -3
- package/tui/src/utils/cronTasks.ts +1 -1
- package/tui/src/utils/execFileNoThrow.ts +1 -1
- package/tui/src/utils/filePersistence/types.ts +16 -38
- package/tui/src/utils/forkedAgent.ts +1 -1
- package/tui/src/utils/gracefulShutdown.ts +4 -4
- package/tui/src/utils/heapDumpService.ts +12 -8
- package/tui/src/utils/hooks/apiQueryHookHelper.ts +1 -1
- package/tui/src/utils/hooks/execPromptHook.ts +1 -1
- package/tui/src/utils/hooks/skillImprovement.ts +1 -1
- package/tui/src/utils/kExaoneReasoning.ts +138 -0
- package/tui/src/utils/mcp/dateTimeParser.ts +1 -1
- package/tui/src/utils/messages.ts +19 -0
- package/tui/src/utils/migrateSessions.ts +3 -3
- package/tui/src/utils/model/model.ts +6 -6
- package/tui/src/utils/multiToolLayout.ts +13 -0
- package/tui/src/utils/permissions/yoloClassifier.ts +1 -1
- package/tui/src/utils/plugins/headlessPluginInstall.ts +1 -1
- package/tui/src/utils/plugins/mcpPluginIntegration.ts +1 -1
- package/tui/src/utils/plugins/mcpbHandler.ts +1 -1
- package/tui/src/utils/plugins/pluginLoader.ts +8 -8
- package/tui/src/utils/processUserInput/processSlashCommand.tsx +2 -2
- package/tui/src/utils/processUserInput/processUserInput.ts +26 -0
- package/tui/src/utils/protectedNamespace.ts +5 -3
- package/tui/src/utils/rawJsonToolCall.ts +242 -0
- package/tui/src/utils/ripgrep.ts +16 -7
- package/tui/src/utils/sessionTitle.ts +1 -1
- package/tui/src/utils/settings/applySettingsChange.ts +4 -0
- package/tui/src/utils/settings/permissionValidation.ts +14 -2
- package/tui/src/utils/settings/types.ts +9 -3
- package/tui/src/utils/shell/prefix.ts +1 -1
- package/tui/src/utils/sideQuery.ts +1 -1
- package/tui/src/utils/stats.ts +1 -1
- package/tui/src/utils/systemThemeWatcher.ts +13 -3
- package/tui/src/utils/teleport.tsx +1 -1
- package/uv.lock +394 -22
- package/assets/copilot-gate-logo.svg +0 -58
- package/assets/govon-logo.svg +0 -40
- package/src/ummaya/eval/__init__.py +0 -5
- package/src/ummaya/eval/retrieval.py +0 -713
- package/tui/src/services/api/claude.ts +0 -3510
- package/tui/src/utils/messageStream.ts +0 -186
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
6
|
+
from ummaya.evidence.models import RouteTraceRecord
|
|
7
|
+
from ummaya.evidence.tool_layer_models import ToolLayerEvidenceEvent
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True, slots=True)
|
|
11
|
+
class ToolLayerEvidenceJoinError(ValueError):
|
|
12
|
+
"""Raised when a tool-layer artifact cannot be joined to route evidence."""
|
|
13
|
+
|
|
14
|
+
event_id: str
|
|
15
|
+
|
|
16
|
+
def __str__(self) -> str:
|
|
17
|
+
return f"tool-layer event does not join to route evidence: {self.event_id}"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def build_tool_layer_events(
|
|
21
|
+
route_trace_records: tuple[RouteTraceRecord, ...],
|
|
22
|
+
*,
|
|
23
|
+
observed_events: tuple[ToolLayerEvidenceEvent, ...] = (),
|
|
24
|
+
) -> tuple[ToolLayerEvidenceEvent, ...]:
|
|
25
|
+
"""Return validated tool-layer artifacts without synthesizing sample events."""
|
|
26
|
+
|
|
27
|
+
if not observed_events:
|
|
28
|
+
return ()
|
|
29
|
+
|
|
30
|
+
route_keys = {
|
|
31
|
+
(record.scenario_id, record.trace_id, record.correlation_id)
|
|
32
|
+
for record in route_trace_records
|
|
33
|
+
if record.trace_kind == "scenario_route"
|
|
34
|
+
}
|
|
35
|
+
for event in observed_events:
|
|
36
|
+
event_key = (event.scenario_id, event.trace_id, event.correlation_id)
|
|
37
|
+
if event_key not in route_keys:
|
|
38
|
+
raise ToolLayerEvidenceJoinError(event_id=event.event_id)
|
|
39
|
+
return observed_events
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Tool-layer Evidence Fabric event models."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from typing import Literal, Self, assert_never
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
|
9
|
+
from pydantic_core import PydanticCustomError
|
|
10
|
+
|
|
11
|
+
ToolLayerExposureState = Literal[
|
|
12
|
+
"always-loaded",
|
|
13
|
+
"deferred-searchable",
|
|
14
|
+
"permission-gated-callable",
|
|
15
|
+
"hidden",
|
|
16
|
+
"unsupported",
|
|
17
|
+
]
|
|
18
|
+
ToolLayerTrustTier = Literal[0, 1, 2, 3, 4, 5]
|
|
19
|
+
ToolLayerPermissionDecision = Literal[
|
|
20
|
+
"not_required",
|
|
21
|
+
"approved",
|
|
22
|
+
"denied",
|
|
23
|
+
"blocked_pending_approval",
|
|
24
|
+
"policy_preapproved",
|
|
25
|
+
]
|
|
26
|
+
ToolLayerResultStatus = Literal["succeeded", "failed", "blocked"]
|
|
27
|
+
ToolLayerBlockedState = Literal[
|
|
28
|
+
"not_blocked",
|
|
29
|
+
"blocked_by_permission",
|
|
30
|
+
"blocked_by_policy",
|
|
31
|
+
"blocked_by_missing_source",
|
|
32
|
+
"blocked_by_unsupported",
|
|
33
|
+
]
|
|
34
|
+
ToolLayerRenderFrame = Literal[
|
|
35
|
+
"permission_prompt",
|
|
36
|
+
"tool_call",
|
|
37
|
+
"tool_result",
|
|
38
|
+
"blocked_state",
|
|
39
|
+
]
|
|
40
|
+
ToolLayerPromptInjectionState = Literal["detected", "not_detected"]
|
|
41
|
+
ToolLayerSourceTrust = Literal["trusted", "untrusted"]
|
|
42
|
+
ToolLayerSourceInstructionVisibility = Literal["evidence_only"]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _validation_error(code: str, message: str) -> PydanticCustomError:
|
|
46
|
+
return PydanticCustomError(code, message)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class ToolLayerEvidenceEvent(BaseModel):
|
|
50
|
+
"""One recovered Claude Code support-tool exposure and provenance event."""
|
|
51
|
+
|
|
52
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
53
|
+
|
|
54
|
+
event_id: str = Field(min_length=1)
|
|
55
|
+
scenario_id: str = Field(min_length=1)
|
|
56
|
+
trace_id: str = Field(min_length=1)
|
|
57
|
+
correlation_id: str = Field(min_length=1)
|
|
58
|
+
frame_hash: str = Field(min_length=64, max_length=64)
|
|
59
|
+
render_frame: ToolLayerRenderFrame
|
|
60
|
+
selected_tool: str = Field(min_length=1)
|
|
61
|
+
exposure_state: ToolLayerExposureState
|
|
62
|
+
trust_tier: ToolLayerTrustTier
|
|
63
|
+
permission_decision: ToolLayerPermissionDecision
|
|
64
|
+
source_url: str | None
|
|
65
|
+
source_local_handle: str | None
|
|
66
|
+
source_citation_id: str = Field(min_length=1)
|
|
67
|
+
provenance_id: str = Field(min_length=1)
|
|
68
|
+
source_trust: ToolLayerSourceTrust
|
|
69
|
+
source_prompt_injection: ToolLayerPromptInjectionState
|
|
70
|
+
source_instruction_visibility: ToolLayerSourceInstructionVisibility = "evidence_only"
|
|
71
|
+
result_status: ToolLayerResultStatus
|
|
72
|
+
result_summary: str | None
|
|
73
|
+
error_summary: str | None
|
|
74
|
+
blocked_state: ToolLayerBlockedState
|
|
75
|
+
|
|
76
|
+
@field_validator("frame_hash")
|
|
77
|
+
@classmethod
|
|
78
|
+
def _validate_frame_hash(cls, value: str) -> str:
|
|
79
|
+
if len(value) != 64 or any(ch not in "0123456789abcdef" for ch in value):
|
|
80
|
+
raise _validation_error(
|
|
81
|
+
"tool_layer_frame_hash", "frame_hash must be lowercase SHA-256 hex"
|
|
82
|
+
)
|
|
83
|
+
return value
|
|
84
|
+
|
|
85
|
+
@field_validator("source_url", "source_local_handle", "source_citation_id", "provenance_id")
|
|
86
|
+
@classmethod
|
|
87
|
+
def _reject_model_visible_leakage_keys(cls, value: str | None) -> str | None:
|
|
88
|
+
if value is not None and ("adapter_id" in value or "expected_tool" in value):
|
|
89
|
+
raise _validation_error(
|
|
90
|
+
"tool_layer_model_visible_leakage",
|
|
91
|
+
"tool-layer evidence cannot carry model-visible leakage keys",
|
|
92
|
+
)
|
|
93
|
+
return value
|
|
94
|
+
|
|
95
|
+
@field_validator("result_summary", "error_summary")
|
|
96
|
+
@classmethod
|
|
97
|
+
def _reject_empty_summary(cls, value: str | None) -> str | None:
|
|
98
|
+
if value is not None and not value.strip():
|
|
99
|
+
raise _validation_error(
|
|
100
|
+
"tool_layer_blank_summary", "tool-layer summaries cannot be blank"
|
|
101
|
+
)
|
|
102
|
+
return value
|
|
103
|
+
|
|
104
|
+
@model_validator(mode="after")
|
|
105
|
+
def _requires_source_reference(self) -> Self:
|
|
106
|
+
if self.source_url is None and self.source_local_handle is None:
|
|
107
|
+
raise _validation_error(
|
|
108
|
+
"tool_layer_missing_source",
|
|
109
|
+
"tool-layer evidence requires source_url or source_local_handle",
|
|
110
|
+
)
|
|
111
|
+
return self
|
|
112
|
+
|
|
113
|
+
@model_validator(mode="after")
|
|
114
|
+
def _requires_status_payload(self) -> Self:
|
|
115
|
+
match self.result_status:
|
|
116
|
+
case "succeeded":
|
|
117
|
+
if self.result_summary is None:
|
|
118
|
+
raise _validation_error(
|
|
119
|
+
"tool_layer_missing_result_summary",
|
|
120
|
+
"succeeded tool-layer event requires result_summary",
|
|
121
|
+
)
|
|
122
|
+
if self.error_summary is not None:
|
|
123
|
+
raise _validation_error(
|
|
124
|
+
"tool_layer_unexpected_error_summary",
|
|
125
|
+
"succeeded tool-layer event cannot carry error_summary",
|
|
126
|
+
)
|
|
127
|
+
if self.blocked_state != "not_blocked":
|
|
128
|
+
raise _validation_error(
|
|
129
|
+
"tool_layer_unexpected_blocked_state",
|
|
130
|
+
"succeeded tool-layer event must not be blocked",
|
|
131
|
+
)
|
|
132
|
+
case "failed":
|
|
133
|
+
if self.error_summary is None:
|
|
134
|
+
raise _validation_error(
|
|
135
|
+
"tool_layer_failed_without_error",
|
|
136
|
+
"failed tool-layer event requires error_summary",
|
|
137
|
+
)
|
|
138
|
+
case "blocked":
|
|
139
|
+
if self.error_summary is None:
|
|
140
|
+
raise _validation_error(
|
|
141
|
+
"tool_layer_blocked_without_error",
|
|
142
|
+
"blocked tool-layer event requires error_summary",
|
|
143
|
+
)
|
|
144
|
+
if self.blocked_state == "not_blocked":
|
|
145
|
+
raise _validation_error(
|
|
146
|
+
"tool_layer_blocked_without_state",
|
|
147
|
+
"blocked tool-layer event requires a blocked_state",
|
|
148
|
+
)
|
|
149
|
+
case unreachable:
|
|
150
|
+
assert_never(unreachable)
|
|
151
|
+
return self
|
|
@@ -47,6 +47,7 @@ import importlib
|
|
|
47
47
|
import json
|
|
48
48
|
import logging
|
|
49
49
|
import os
|
|
50
|
+
import re
|
|
50
51
|
from datetime import UTC, datetime
|
|
51
52
|
from typing import IO, Any, Literal
|
|
52
53
|
|
|
@@ -255,7 +256,7 @@ def _build_entries( # noqa: C901, ANN401 — three-source walker, refactor defe
|
|
|
255
256
|
except Exception:
|
|
256
257
|
tools_list = []
|
|
257
258
|
|
|
258
|
-
root_primitive_tool_ids = frozenset({"locate", "find", "check", "send"})
|
|
259
|
+
root_primitive_tool_ids = frozenset({"locate", "find", "check", "send", "document"})
|
|
259
260
|
|
|
260
261
|
for tool in tools_list:
|
|
261
262
|
tool_id_opt: str | None = tool.id if hasattr(tool, "id") else getattr(tool, "tool_id", None)
|
|
@@ -371,24 +372,39 @@ def _verify_family_llm_description(
|
|
|
371
372
|
"""Build model-facing prose for a verify-family manifest entry."""
|
|
372
373
|
|
|
373
374
|
metadata = metadata or {}
|
|
374
|
-
tool_id = str(metadata.get("tool_id") or family).strip()
|
|
375
375
|
name = str(metadata.get("name_ko") or family).strip()
|
|
376
|
-
scope_rules = str(metadata.get("scope_rules") or "").strip()
|
|
376
|
+
scope_rules = _safe_verify_scope_rules(str(metadata.get("scope_rules") or "").strip())
|
|
377
377
|
scope_clause = f" {scope_rules}" if scope_rules else ""
|
|
378
378
|
return (
|
|
379
|
-
f"Internal check-family surface for {name} (family_hint='{family}'
|
|
380
|
-
|
|
381
|
-
"
|
|
382
|
-
"
|
|
383
|
-
"
|
|
384
|
-
"
|
|
379
|
+
f"Internal check-family surface for {name} (family_hint='{family}'). "
|
|
380
|
+
"Use this only through the core check primitive before a downstream "
|
|
381
|
+
"protected find/send action needs delegated authorization. Params must "
|
|
382
|
+
"follow input_schema_json exactly: scope_list contains "
|
|
383
|
+
"'<verb>:<adapter_family>.<action>' scope strings, purpose_ko is the "
|
|
384
|
+
"Korean citizen-facing consent purpose, and purpose_en is the audit-log "
|
|
385
385
|
"English purpose. The manifest entry stays source_mode='internal' because "
|
|
386
386
|
"the agency citation is emitted by the verify response transparency stamp, "
|
|
387
|
-
"while the pre-call tool schema remains stable for the TUI and LLM loop."
|
|
387
|
+
"while the pre-call tool schema remains stable for the TUI and LLM loop. "
|
|
388
|
+
"Do not mention internal mock bridge identifiers in citizen-facing prose."
|
|
388
389
|
f"{scope_clause}"
|
|
389
390
|
)
|
|
390
391
|
|
|
391
392
|
|
|
393
|
+
def _safe_verify_scope_rules(scope_rules: str) -> str:
|
|
394
|
+
if not scope_rules:
|
|
395
|
+
return ""
|
|
396
|
+
safe_sentences: list[str] = []
|
|
397
|
+
for sentence in re.split(r"(?<=[.!?])\s+", scope_rules):
|
|
398
|
+
candidate = sentence.strip()
|
|
399
|
+
if not candidate:
|
|
400
|
+
continue
|
|
401
|
+
lowered = candidate.lower()
|
|
402
|
+
if "mock_verify" in lowered or "tool_id" in lowered:
|
|
403
|
+
continue
|
|
404
|
+
safe_sentences.append(candidate)
|
|
405
|
+
return " ".join(safe_sentences)
|
|
406
|
+
|
|
407
|
+
|
|
392
408
|
def _string_list(value: object) -> list[str]:
|
|
393
409
|
"""Return non-empty strings from a loosely typed metadata list."""
|
|
394
410
|
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
import uuid
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Final
|
|
9
|
+
|
|
10
|
+
_DOCUMENT_WRITE_REQUEST_RE: Final = re.compile(
|
|
11
|
+
r"(작성|수정|편집|채우|채워|입력|변경|저장|write|edit|fill|apply|save)",
|
|
12
|
+
re.IGNORECASE,
|
|
13
|
+
)
|
|
14
|
+
_DOCUMENT_SAVE_REQUEST_RE: Final = re.compile(
|
|
15
|
+
r"(저장|내보내|export|save)",
|
|
16
|
+
re.IGNORECASE,
|
|
17
|
+
)
|
|
18
|
+
_DOCUMENT_READ_ONLY_INSPECT_RE: Final = re.compile(
|
|
19
|
+
r"(구조.{0,30}빈칸.{0,30}확인|빈칸.{0,30}확인|구조.{0,30}확인|"
|
|
20
|
+
r"확인해\s*줘|검토만|inspect|read[- ]?only)",
|
|
21
|
+
re.IGNORECASE,
|
|
22
|
+
)
|
|
23
|
+
_DOCUMENT_MUTATION_PROHIBITION_RE: Final = re.compile(
|
|
24
|
+
r"(절대.{0,40}(?:수정|저장|작성|채우|입력|변경).{0,40}"
|
|
25
|
+
r"(?:하지\s*마|하지\s*말|금지)|"
|
|
26
|
+
r"(?:수정|저장|작성|채우|입력|변경).{0,30}(?:하지\s*마|하지\s*말)|"
|
|
27
|
+
r"(?:do not|don't).{0,40}(?:modify|save|write|edit|fill))",
|
|
28
|
+
re.IGNORECASE,
|
|
29
|
+
)
|
|
30
|
+
_QUESTION_FIRST_AUTHORING_RE: Final = re.compile(
|
|
31
|
+
r"(근거가\s*부족하면\s*먼저\s*질문|먼저\s*(?:확인|파악|검토|질문|물어)|"
|
|
32
|
+
r"초안을?\s*먼저|아직.{0,40}(?:쓰지\s*마|작성하지\s*마|저장하지\s*마|"
|
|
33
|
+
r"반영하지\s*마)|문서에는\s*쓰지\s*마)",
|
|
34
|
+
re.IGNORECASE,
|
|
35
|
+
)
|
|
36
|
+
_DOCUMENT_MUTATION_PARAM_KEYS: Final[frozenset[str]] = frozenset(
|
|
37
|
+
{
|
|
38
|
+
"approved_draft_id",
|
|
39
|
+
"destination_display_name",
|
|
40
|
+
"destination_path",
|
|
41
|
+
"dry_run",
|
|
42
|
+
"patches",
|
|
43
|
+
"styles",
|
|
44
|
+
"template_id",
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
_DOCUMENT_INTERNAL_USER_QUERY_KEY: Final = "__ummaya_user_query"
|
|
48
|
+
_DOCUMENT_ROOT_SYNTHESIS_KEYS: Final[frozenset[str]] = frozenset(
|
|
49
|
+
{_DOCUMENT_INTERNAL_USER_QUERY_KEY}
|
|
50
|
+
)
|
|
51
|
+
_DOCUMENT_EXPLICIT_LOCAL_PATH_RE: Final = re.compile(
|
|
52
|
+
r"(?P<path>(?:~|/)[^\s\"'<>]+?\."
|
|
53
|
+
r"(?:hwpx|hwp|docx|pdf|xlsx|pptx|odt|ods|odp|doc|xls|ppt|csv|txt|md|json|xml|html))",
|
|
54
|
+
re.IGNORECASE,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _normalize_document_root_call_for_user_intent(
|
|
59
|
+
fname: str,
|
|
60
|
+
args_obj: dict[str, object],
|
|
61
|
+
latest_user_utt: str,
|
|
62
|
+
) -> dict[str, object]:
|
|
63
|
+
if fname != "document" or args_obj.get("tool_id") != "document":
|
|
64
|
+
return args_obj
|
|
65
|
+
params_obj = args_obj.get("params")
|
|
66
|
+
if not isinstance(params_obj, dict):
|
|
67
|
+
return args_obj
|
|
68
|
+
|
|
69
|
+
intent_text = _document_intent_text(params_obj, latest_user_utt)
|
|
70
|
+
synthesized_params = _synthesize_document_read_params(params_obj, intent_text)
|
|
71
|
+
if synthesized_params is not None:
|
|
72
|
+
return {**args_obj, "params": synthesized_params}
|
|
73
|
+
|
|
74
|
+
normalized_params = dict(params_obj)
|
|
75
|
+
normalized_params.pop(_DOCUMENT_INTERNAL_USER_QUERY_KEY, None)
|
|
76
|
+
_normalize_document_path_from_user_query(normalized_params, intent_text)
|
|
77
|
+
if _is_explicit_read_only_inspect_intent(intent_text):
|
|
78
|
+
read_only_params = _strip_mutation_params(normalized_params)
|
|
79
|
+
read_only_params["operation"] = "inspect"
|
|
80
|
+
read_only_params["instruction"] = intent_text
|
|
81
|
+
return {**args_obj, "params": read_only_params}
|
|
82
|
+
|
|
83
|
+
operation = str(params_obj.get("operation") or "").casefold()
|
|
84
|
+
changed = normalized_params != params_obj
|
|
85
|
+
if (
|
|
86
|
+
operation in {"fill", "save"}
|
|
87
|
+
and intent_text
|
|
88
|
+
and _DOCUMENT_WRITE_REQUEST_RE.search(intent_text)
|
|
89
|
+
):
|
|
90
|
+
if _DOCUMENT_SAVE_REQUEST_RE.search(intent_text):
|
|
91
|
+
normalized_params["operation"] = "save"
|
|
92
|
+
normalized_params["instruction"] = intent_text
|
|
93
|
+
return {**args_obj, "params": normalized_params}
|
|
94
|
+
if operation not in {"inspect", "extract"}:
|
|
95
|
+
return {**args_obj, "params": normalized_params} if changed else args_obj
|
|
96
|
+
if _should_keep_read_only_for_question_first_authoring(intent_text):
|
|
97
|
+
return {**args_obj, "params": normalized_params} if changed else args_obj
|
|
98
|
+
if not intent_text or not _DOCUMENT_WRITE_REQUEST_RE.search(intent_text):
|
|
99
|
+
return {**args_obj, "params": normalized_params} if changed else args_obj
|
|
100
|
+
|
|
101
|
+
normalized_params["operation"] = (
|
|
102
|
+
"save" if _DOCUMENT_SAVE_REQUEST_RE.search(intent_text) else "fill"
|
|
103
|
+
)
|
|
104
|
+
normalized_params["instruction"] = intent_text
|
|
105
|
+
return {**args_obj, "params": normalized_params}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _document_intent_text(params_obj: dict[str, object], latest_user_utt: str) -> str:
|
|
109
|
+
internal_user_query = params_obj.get(_DOCUMENT_INTERNAL_USER_QUERY_KEY)
|
|
110
|
+
if isinstance(internal_user_query, str) and internal_user_query.strip():
|
|
111
|
+
return internal_user_query.strip()
|
|
112
|
+
return latest_user_utt
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _synthesize_document_read_params(
|
|
116
|
+
params_obj: dict[str, object],
|
|
117
|
+
intent_text: str,
|
|
118
|
+
) -> dict[str, object] | None:
|
|
119
|
+
if (
|
|
120
|
+
not intent_text
|
|
121
|
+
or isinstance(params_obj.get("document"), dict)
|
|
122
|
+
or set(params_obj) - _DOCUMENT_ROOT_SYNTHESIS_KEYS
|
|
123
|
+
):
|
|
124
|
+
return None
|
|
125
|
+
local_path = _first_existing_document_path(intent_text, None)
|
|
126
|
+
if local_path is None:
|
|
127
|
+
return None
|
|
128
|
+
document_format = local_path.suffix.removeprefix(".").lower()
|
|
129
|
+
return {
|
|
130
|
+
"correlation_id": f"document-intent-{uuid.uuid4().hex}",
|
|
131
|
+
"document": {"path": str(local_path), "expected_format": document_format},
|
|
132
|
+
"operation": "inspect",
|
|
133
|
+
"instruction": intent_text,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _normalize_document_path_from_user_query(
|
|
138
|
+
normalized_params: dict[str, object],
|
|
139
|
+
intent_text: str,
|
|
140
|
+
) -> None:
|
|
141
|
+
if not intent_text:
|
|
142
|
+
return
|
|
143
|
+
document_obj = normalized_params.get("document")
|
|
144
|
+
if not isinstance(document_obj, dict):
|
|
145
|
+
return
|
|
146
|
+
current_path = document_obj.get("path")
|
|
147
|
+
if isinstance(current_path, str) and Path(current_path).expanduser().exists():
|
|
148
|
+
return
|
|
149
|
+
expected_format = document_obj.get("expected_format")
|
|
150
|
+
expected_suffix = f".{expected_format}".lower() if isinstance(expected_format, str) else None
|
|
151
|
+
explicit_path = _first_existing_document_path(intent_text, expected_suffix)
|
|
152
|
+
if explicit_path is None:
|
|
153
|
+
return
|
|
154
|
+
normalized_params["document"] = {
|
|
155
|
+
**document_obj,
|
|
156
|
+
"path": str(explicit_path),
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _first_existing_document_path(intent_text: str, expected_suffix: str | None) -> Path | None:
|
|
161
|
+
for match in _DOCUMENT_EXPLICIT_LOCAL_PATH_RE.finditer(intent_text):
|
|
162
|
+
candidate = Path(match.group("path").rstrip(".,;:)]})")).expanduser()
|
|
163
|
+
if expected_suffix is not None and candidate.suffix.lower() != expected_suffix:
|
|
164
|
+
continue
|
|
165
|
+
if candidate.exists():
|
|
166
|
+
return candidate.resolve()
|
|
167
|
+
return None
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _should_keep_read_only_for_question_first_authoring(intent_text: str) -> bool:
|
|
171
|
+
return bool(intent_text and _QUESTION_FIRST_AUTHORING_RE.search(intent_text))
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _is_explicit_read_only_inspect_intent(intent_text: str) -> bool:
|
|
175
|
+
return bool(
|
|
176
|
+
intent_text
|
|
177
|
+
and _DOCUMENT_READ_ONLY_INSPECT_RE.search(intent_text)
|
|
178
|
+
and _DOCUMENT_MUTATION_PROHIBITION_RE.search(intent_text)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _strip_mutation_params(params_obj: dict[str, object]) -> dict[str, object]:
|
|
183
|
+
return {
|
|
184
|
+
key: value for key, value in params_obj.items() if key not in _DOCUMENT_MUTATION_PARAM_KEYS
|
|
185
|
+
}
|
|
@@ -56,6 +56,7 @@ _ROLE_KIND_ALLOW_LIST: dict[str, frozenset[str]] = {
|
|
|
56
56
|
# Spec 1978 ADR-0001 — tools-aware chat request from TUI
|
|
57
57
|
"chat_request": frozenset({"tui"}),
|
|
58
58
|
"assistant_chunk": frozenset({"backend", "llm"}),
|
|
59
|
+
"progress_event": frozenset({"backend"}),
|
|
59
60
|
"tool_call": frozenset({"backend", "tool"}),
|
|
60
61
|
"tool_result": frozenset({"backend", "tool"}),
|
|
61
62
|
"coordinator_phase": frozenset({"backend"}),
|
|
@@ -385,6 +386,10 @@ class ChatRequestFrame(_BaseFrame):
|
|
|
385
386
|
le=1.0,
|
|
386
387
|
description="Nucleus sampling threshold.",
|
|
387
388
|
)
|
|
389
|
+
reasoning_mode: Literal["fast", "balanced", "deep", "diagnostic", "auto"] | None = Field(
|
|
390
|
+
default=None,
|
|
391
|
+
description="K-EXAONE/FriendliAI reasoning policy for this assistant turn.",
|
|
392
|
+
)
|
|
388
393
|
|
|
389
394
|
@model_validator(mode="after")
|
|
390
395
|
def _v_tool_message_integrity(self) -> ChatRequestFrame:
|
|
@@ -449,6 +454,46 @@ class AssistantChunkFrame(_BaseFrame):
|
|
|
449
454
|
done: bool = Field(description="True if this is the terminal chunk for this message_id.")
|
|
450
455
|
|
|
451
456
|
|
|
457
|
+
# ---------------------------------------------------------------------------
|
|
458
|
+
# Arm: progress_event (UMMAYA query-loop painting — deterministic and safe)
|
|
459
|
+
# ---------------------------------------------------------------------------
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
class ProgressEventFrame(_BaseFrame):
|
|
463
|
+
"""backend -> TUI: deterministic query-loop progress.
|
|
464
|
+
|
|
465
|
+
This is intentionally separate from ``AssistantChunkFrame.thinking``.
|
|
466
|
+
``progress_event`` carries safe harness state such as analysis, tool
|
|
467
|
+
selection, tool dispatch/result, and answer synthesis. Provider reasoning
|
|
468
|
+
remains on the gated ``thinking_delta`` channel.
|
|
469
|
+
"""
|
|
470
|
+
|
|
471
|
+
kind: Literal["progress_event"] = Field(
|
|
472
|
+
default="progress_event", description="Frame discriminator."
|
|
473
|
+
)
|
|
474
|
+
phase: Literal[
|
|
475
|
+
"analysis",
|
|
476
|
+
"tool_selection",
|
|
477
|
+
"tool_call",
|
|
478
|
+
"tool_result",
|
|
479
|
+
"answer_synthesis",
|
|
480
|
+
] = Field(description="Safe query-loop phase represented by this event.")
|
|
481
|
+
message_ko: str = Field(min_length=1, description="Korean progress text for the TUI.")
|
|
482
|
+
message_en: str = Field(min_length=1, description="English fallback progress text.")
|
|
483
|
+
safe_to_persist: bool = Field(
|
|
484
|
+
default=True,
|
|
485
|
+
description="True because this channel never carries raw provider chain-of-thought.",
|
|
486
|
+
)
|
|
487
|
+
tool_id: str | None = Field(
|
|
488
|
+
default=None,
|
|
489
|
+
description="Concrete adapter/tool id when this event is tied to one.",
|
|
490
|
+
)
|
|
491
|
+
call_id: str | None = Field(
|
|
492
|
+
default=None,
|
|
493
|
+
description="Tool call id when this event is tied to a specific invocation.",
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
|
|
452
497
|
# ---------------------------------------------------------------------------
|
|
453
498
|
# Arm: tool_call (Spec 287 baseline — arguments changed from Any to dict[str, object])
|
|
454
499
|
# ---------------------------------------------------------------------------
|
|
@@ -483,7 +528,7 @@ class ToolResultEnvelope(BaseModel):
|
|
|
483
528
|
|
|
484
529
|
model_config = ConfigDict(frozen=True, extra="allow", populate_by_name=True)
|
|
485
530
|
|
|
486
|
-
kind: Literal["find", "locate", "send", "check"] = Field(
|
|
531
|
+
kind: Literal["find", "locate", "send", "check", "document"] = Field(
|
|
487
532
|
description="Primitive kind discriminator per Spec 031."
|
|
488
533
|
)
|
|
489
534
|
|
|
@@ -531,7 +576,7 @@ class WorkerStatusFrame(_BaseFrame):
|
|
|
531
576
|
role_id: str = Field(
|
|
532
577
|
description="Specialist label (e.g., transport-specialist, health-specialist)."
|
|
533
578
|
)
|
|
534
|
-
current_primitive: Literal["find", "locate", "send", "check"] = Field(
|
|
579
|
+
current_primitive: Literal["find", "locate", "send", "check", "document"] = Field(
|
|
535
580
|
description="Primitive currently being invoked by this worker."
|
|
536
581
|
)
|
|
537
582
|
status: Literal["idle", "running", "waiting_permission", "error"] = Field(
|
|
@@ -554,7 +599,7 @@ class PermissionRequestFrame(_BaseFrame):
|
|
|
554
599
|
description="ULID; round-trips in the matching permission_response frame."
|
|
555
600
|
)
|
|
556
601
|
worker_id: str = Field(description="Worker requesting permission.")
|
|
557
|
-
primitive_kind: Literal["find", "locate", "send", "check"] = Field(
|
|
602
|
+
primitive_kind: Literal["find", "locate", "send", "check", "document"] = Field(
|
|
558
603
|
description="The primitive the worker wants to invoke."
|
|
559
604
|
)
|
|
560
605
|
description_ko: str = Field(description="Korean-language description shown to the citizen.")
|
|
@@ -624,7 +669,7 @@ class PermissionResponseFrame(_BaseFrame):
|
|
|
624
669
|
# `layer: 1, tool_name: 'unknown'` (UI-C-1 spec violation: Layer 2/3
|
|
625
670
|
# submits were colour-coded green like a Layer 1 verify).
|
|
626
671
|
# Both fields are optional so legacy backends remain wire-compatible.
|
|
627
|
-
primitive_kind: Literal["find", "locate", "send", "check"] | None = Field(
|
|
672
|
+
primitive_kind: Literal["find", "locate", "send", "check", "document"] | None = Field(
|
|
628
673
|
default=None,
|
|
629
674
|
description=(
|
|
630
675
|
"The primitive that was authorised. The TUI feeds this into "
|
|
@@ -1175,7 +1220,7 @@ class AdapterManifestEntry(BaseModel):
|
|
|
1175
1220
|
max_length=80,
|
|
1176
1221
|
description="Human-readable display name; bilingual permitted.",
|
|
1177
1222
|
)
|
|
1178
|
-
primitive: Literal["find", "send", "check", "locate"] = Field(
|
|
1223
|
+
primitive: Literal["find", "send", "check", "locate", "document"] = Field(
|
|
1179
1224
|
description="Primitive verb the adapter is registered under (I6).",
|
|
1180
1225
|
)
|
|
1181
1226
|
policy_authority_url: str | None = Field(
|
|
@@ -1436,6 +1481,7 @@ IPCFrame = Annotated[
|
|
|
1436
1481
|
UserInputFrame
|
|
1437
1482
|
| ChatRequestFrame
|
|
1438
1483
|
| AssistantChunkFrame
|
|
1484
|
+
| ProgressEventFrame
|
|
1439
1485
|
| ToolCallFrame
|
|
1440
1486
|
| ToolResultFrame
|
|
1441
1487
|
| CoordinatorPhaseFrame
|
|
@@ -1505,6 +1551,7 @@ __all__ = [
|
|
|
1505
1551
|
"ToolDefinition",
|
|
1506
1552
|
"ToolDefinitionFunction",
|
|
1507
1553
|
"AssistantChunkFrame",
|
|
1554
|
+
"ProgressEventFrame",
|
|
1508
1555
|
"ToolCallFrame",
|
|
1509
1556
|
"ToolResultFrame",
|
|
1510
1557
|
"ToolResultEnvelope",
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Literal
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
10
|
+
|
|
11
|
+
from ummaya.tools.routing import RouteDecision, RouteStopReason, SchemaProjectionLevel
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RouteDecisionDiagnosticPayload(BaseModel):
|
|
15
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
16
|
+
|
|
17
|
+
turn_index: int = Field(ge=1)
|
|
18
|
+
session_id: str = Field(min_length=1)
|
|
19
|
+
correlation_id: str = Field(min_length=1)
|
|
20
|
+
decision_id: str = Field(min_length=1)
|
|
21
|
+
query_hash: str = Field(min_length=64, max_length=64)
|
|
22
|
+
manifest_hash: str = Field(min_length=64, max_length=64)
|
|
23
|
+
backend_label: str = Field(min_length=1)
|
|
24
|
+
selected_tools: tuple[str, ...]
|
|
25
|
+
candidate_count: int = Field(ge=0)
|
|
26
|
+
effective_top_k: int = Field(ge=0)
|
|
27
|
+
schema_projection_level: SchemaProjectionLevel
|
|
28
|
+
stop_reason: RouteStopReason
|
|
29
|
+
permission_gate: bool
|
|
30
|
+
clarification_reason: (
|
|
31
|
+
Literal[
|
|
32
|
+
"missing_slots",
|
|
33
|
+
"equal_candidates",
|
|
34
|
+
"side_effect_confirmation",
|
|
35
|
+
"execution_risk_input_fault",
|
|
36
|
+
]
|
|
37
|
+
| None
|
|
38
|
+
)
|
|
39
|
+
evidence_events: tuple[str, ...]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def log_route_decision_diagnostic(
|
|
43
|
+
*,
|
|
44
|
+
logger: logging.Logger,
|
|
45
|
+
turn_index: int,
|
|
46
|
+
session_id: str,
|
|
47
|
+
correlation_id: str,
|
|
48
|
+
decision: RouteDecision | None,
|
|
49
|
+
) -> None:
|
|
50
|
+
if decision is None:
|
|
51
|
+
return
|
|
52
|
+
clarification_reason = None if decision.clarification is None else decision.clarification.reason
|
|
53
|
+
payload = RouteDecisionDiagnosticPayload(
|
|
54
|
+
turn_index=turn_index,
|
|
55
|
+
session_id=session_id,
|
|
56
|
+
correlation_id=correlation_id,
|
|
57
|
+
decision_id=decision.decision_id,
|
|
58
|
+
query_hash=decision.query_hash,
|
|
59
|
+
manifest_hash=decision.manifest_hash,
|
|
60
|
+
backend_label=decision.backend_label,
|
|
61
|
+
selected_tools=decision.selected_tools,
|
|
62
|
+
candidate_count=len(decision.candidate_set),
|
|
63
|
+
effective_top_k=decision.effective_top_k,
|
|
64
|
+
schema_projection_level=decision.schema_projection_level,
|
|
65
|
+
stop_reason=decision.stop_reason,
|
|
66
|
+
permission_gate=decision.permission_gate,
|
|
67
|
+
clarification_reason=clarification_reason,
|
|
68
|
+
evidence_events=decision.evidence_events,
|
|
69
|
+
)
|
|
70
|
+
logger.info(
|
|
71
|
+
"[ROUTE_DECISION] payload=%s",
|
|
72
|
+
json.dumps(payload.model_dump(mode="json"), ensure_ascii=False, sort_keys=True),
|
|
73
|
+
)
|