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
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod/v4'
|
|
2
|
+
import { randomUUID } from 'node:crypto'
|
|
3
|
+
import { existsSync } from 'node:fs'
|
|
4
|
+
import { homedir } from 'node:os'
|
|
5
|
+
import { basename, join } from 'node:path'
|
|
2
6
|
import {
|
|
3
7
|
buildTool,
|
|
4
8
|
type Tool,
|
|
@@ -14,16 +18,77 @@ import {
|
|
|
14
18
|
import { getOrCreateUmmayaBridge } from '../../ipc/bridgeSingleton.js'
|
|
15
19
|
import { getOrCreatePendingCallRegistry } from '../../ipc/pendingCallSingleton.js'
|
|
16
20
|
import { dispatchPrimitive } from '../_shared/dispatchPrimitive.js'
|
|
21
|
+
import {
|
|
22
|
+
applyDocumentVisualRenderGateToOutput,
|
|
23
|
+
extractDocumentToolResultPayload,
|
|
24
|
+
isDocumentVisualRenderFailedOutput,
|
|
25
|
+
renderDocumentToolResultIfPresent,
|
|
26
|
+
} from '../_shared/documentToolResultRender.js'
|
|
17
27
|
import { LookupPrimitive } from '../LookupPrimitive/LookupPrimitive.js'
|
|
18
28
|
import { ResolveLocationPrimitive } from '../ResolveLocationPrimitive/ResolveLocationPrimitive.js'
|
|
19
29
|
import { SubmitPrimitive } from '../SubmitPrimitive/SubmitPrimitive.js'
|
|
20
30
|
import { VerifyPrimitive } from '../VerifyPrimitive/VerifyPrimitive.js'
|
|
31
|
+
import { DocumentPrimitive } from '../DocumentPrimitive/DocumentPrimitive.js'
|
|
32
|
+
import { resolveDocumentPrimitiveTimeoutMs } from '../_shared/documentPrimitiveTimeout.js'
|
|
21
33
|
|
|
22
|
-
type AdapterPrimitive = 'find' | 'locate' | 'send' | 'check'
|
|
34
|
+
type AdapterPrimitive = 'find' | 'locate' | 'send' | 'check' | 'document'
|
|
23
35
|
|
|
24
36
|
type InputSchema = z.ZodType<{ [key: string]: unknown }>
|
|
25
37
|
|
|
26
|
-
const ROOT_PRIMITIVE_TOOL_NAMES = new Set([
|
|
38
|
+
const ROOT_PRIMITIVE_TOOL_NAMES = new Set([
|
|
39
|
+
'locate',
|
|
40
|
+
'find',
|
|
41
|
+
'check',
|
|
42
|
+
'send',
|
|
43
|
+
'document',
|
|
44
|
+
])
|
|
45
|
+
const DOCUMENT_TOOL_NAMES = new Set([
|
|
46
|
+
'document',
|
|
47
|
+
'document_inspect',
|
|
48
|
+
'document_extract',
|
|
49
|
+
'document_form_schema',
|
|
50
|
+
'document_copy_for_edit',
|
|
51
|
+
'document_apply_fill',
|
|
52
|
+
'document_apply_style',
|
|
53
|
+
'document_render',
|
|
54
|
+
'document_validate_public_form',
|
|
55
|
+
'document_save',
|
|
56
|
+
])
|
|
57
|
+
const DOCUMENT_MUTATION_TOOL_NAMES = new Set([
|
|
58
|
+
'document_apply_fill',
|
|
59
|
+
'document_apply_style',
|
|
60
|
+
])
|
|
61
|
+
const DOCUMENT_ARTIFACT_FOLLOWUP_TOOL_NAMES = new Set([
|
|
62
|
+
'document_apply_fill',
|
|
63
|
+
'document_apply_style',
|
|
64
|
+
'document_render',
|
|
65
|
+
'document_validate_public_form',
|
|
66
|
+
'document_save',
|
|
67
|
+
])
|
|
68
|
+
// Purely mechanical pipeline steps that carry no user-meaningful change — only
|
|
69
|
+
// these are hidden on success. Substantive mutations (apply_fill / apply_style)
|
|
70
|
+
// now render their inline structural diff immediately (per-mutation trigger),
|
|
71
|
+
// the same way Claude Code shows a diff the moment an edit lands. See
|
|
72
|
+
// specs/2802-public-doc-harness/deep-research-migration-document-render.md.
|
|
73
|
+
const MECHANICAL_DOCUMENT_TOOL_NAMES = new Set(['document_copy_for_edit'])
|
|
74
|
+
const SAFE_DOCUMENT_ARTIFACT_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/u
|
|
75
|
+
const EXPLICIT_DOCUMENT_ARTIFACT_MARKER_RE =
|
|
76
|
+
/(?:^|[\s"'`(])(?:artifact_id|artifact\s*id|artifact|아티팩트)\s*[:=]?\s*([A-Za-z0-9][A-Za-z0-9_.-]{0,127})(?=$|[^A-Za-z0-9_.-])/iu
|
|
77
|
+
const EXPLICIT_DOCUMENT_ARTIFACT_PREFIX_RE =
|
|
78
|
+
/(?:^|[\s"'`(])((?:source|working|derivative|render|export|viewport)-[A-Za-z0-9][A-Za-z0-9_.-]{0,127})(?=$|[^A-Za-z0-9_.-])/u
|
|
79
|
+
const DOCUMENT_FORMAT_RE = /\b(?:hwpx|hwp|docx|pdf|xlsx|pptx)\b/iu
|
|
80
|
+
const DOWNLOADS_FOLDER_PATH_RE = /(?:^|[\\/])Downloads$/u
|
|
81
|
+
const DOWNLOADS_PATH_SEGMENT_RE = /(?:^|[\\/])Downloads[\\/](?<tail>.+)$/iu
|
|
82
|
+
const DOCUMENT_EXTENSION_RE = /\.(?:hwpx|hwp|docx|pdf|xlsx|pptx)$/iu
|
|
83
|
+
const DOCUMENT_EXTENSION_TRAILING_PUNCT_RE =
|
|
84
|
+
/(\.(?:hwpx|hwp|docx|pdf|xlsx|pptx))[.。.]+$/iu
|
|
85
|
+
const EXPLICIT_LOCAL_DOCUMENT_PATH_RE =
|
|
86
|
+
/(?:^|[\s"'`(])(?<path>(?:~|\/|\.{1,2}\/|[A-Za-z]:\\)[^\n\r"'`]*?\.(?:hwpx|hwp|docx|pdf|xlsx|pptx))(?=$|[\s"'`),,。]|[가-힣])/giu
|
|
87
|
+
const HWPX_TEXT_TARGET_ALIAS_RE =
|
|
88
|
+
/^\/?hwp(?:x)?[-_/]text(?:[-_](?<indexA>\d+)|\[(?<indexB>\d+)\])(?:\/text\(\))?$/iu
|
|
89
|
+
const HWPX_TEXT_TARGET_RE = /^\/hwpx\/text\[\d+\]$/u
|
|
90
|
+
const HWPX_BLOCK_TABLE_CELL_TARGET_RE =
|
|
91
|
+
/^\/hwpx\/\[(?<tableId>hwpx-table-\d{3})\]\/cells\[(?<row>\d+)\]\[(?<column>\d+)\]$/u
|
|
27
92
|
|
|
28
93
|
const fallbackInputSchema = z.object({}).passthrough() as InputSchema
|
|
29
94
|
|
|
@@ -37,6 +102,680 @@ function asJsonObject(value: unknown): JsonObject {
|
|
|
37
102
|
return isJsonObject(value) ? value : {}
|
|
38
103
|
}
|
|
39
104
|
|
|
105
|
+
function documentToolUseAction(toolId: string): string {
|
|
106
|
+
switch (toolId) {
|
|
107
|
+
case 'document':
|
|
108
|
+
return 'Prepare document workflow'
|
|
109
|
+
case 'document_inspect':
|
|
110
|
+
return 'Inspect document form'
|
|
111
|
+
case 'document_extract':
|
|
112
|
+
return 'Read document content'
|
|
113
|
+
case 'document_form_schema':
|
|
114
|
+
return 'Map document fields'
|
|
115
|
+
case 'document_apply_fill':
|
|
116
|
+
return 'Fill document fields'
|
|
117
|
+
case 'document_apply_style':
|
|
118
|
+
return 'Apply document formatting'
|
|
119
|
+
case 'document_render':
|
|
120
|
+
return 'Render document diff'
|
|
121
|
+
case 'document_validate_public_form':
|
|
122
|
+
return 'Validate public-form rules'
|
|
123
|
+
case 'document_save':
|
|
124
|
+
return 'Save document'
|
|
125
|
+
default:
|
|
126
|
+
return 'Process document'
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function documentToolUseTarget(input: Record<string, unknown>): string | undefined {
|
|
131
|
+
const document = asJsonObject(input.document)
|
|
132
|
+
const path =
|
|
133
|
+
typeof document.path === 'string'
|
|
134
|
+
? document.path
|
|
135
|
+
: typeof input.path === 'string'
|
|
136
|
+
? input.path
|
|
137
|
+
: undefined
|
|
138
|
+
if (path !== undefined && path.trim()) {
|
|
139
|
+
return basename(path)
|
|
140
|
+
}
|
|
141
|
+
if (
|
|
142
|
+
typeof document.artifact_id === 'string' ||
|
|
143
|
+
typeof input.artifact_id === 'string'
|
|
144
|
+
) {
|
|
145
|
+
return 'current document'
|
|
146
|
+
}
|
|
147
|
+
return undefined
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function renderDocumentToolUseMessage(
|
|
151
|
+
toolId: string,
|
|
152
|
+
input: Record<string, unknown>,
|
|
153
|
+
): string | null {
|
|
154
|
+
if (MECHANICAL_DOCUMENT_TOOL_NAMES.has(toolId)) return null
|
|
155
|
+
const action = documentToolUseAction(toolId)
|
|
156
|
+
const target = documentToolUseTarget(input)
|
|
157
|
+
return target === undefined ? action : `${action}: ${target}`
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function messageInnerRecord(message: unknown): JsonObject {
|
|
161
|
+
return asJsonObject(asJsonObject(message).message)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function messageRole(message: unknown): string | undefined {
|
|
165
|
+
const inner = messageInnerRecord(message)
|
|
166
|
+
const outer = asJsonObject(message)
|
|
167
|
+
if (typeof inner.role === 'string') return inner.role
|
|
168
|
+
if (typeof outer.role === 'string') return outer.role
|
|
169
|
+
return typeof outer.type === 'string' ? outer.type : undefined
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function messageContent(message: unknown): unknown {
|
|
173
|
+
const inner = messageInnerRecord(message)
|
|
174
|
+
return inner.content ?? asJsonObject(message).content
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function isToolResultContent(content: unknown): boolean {
|
|
178
|
+
if (!Array.isArray(content)) return false
|
|
179
|
+
return content.some(block => asJsonObject(block).type === 'tool_result')
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function textFromMessageContent(content: unknown): string {
|
|
183
|
+
if (typeof content === 'string') return content
|
|
184
|
+
if (!Array.isArray(content)) return ''
|
|
185
|
+
return content
|
|
186
|
+
.map(block => {
|
|
187
|
+
if (typeof block === 'string') return block
|
|
188
|
+
const record = asJsonObject(block)
|
|
189
|
+
if (record.type === 'tool_result') return ''
|
|
190
|
+
if (typeof record.text === 'string') return record.text
|
|
191
|
+
if (typeof record.content === 'string') return record.content
|
|
192
|
+
return ''
|
|
193
|
+
})
|
|
194
|
+
.filter(Boolean)
|
|
195
|
+
.join('\n')
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function latestPlainUserText(messages: readonly unknown[]): string {
|
|
199
|
+
for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
|
|
200
|
+
const content = messageContent(messages[idx])
|
|
201
|
+
if (messageRole(messages[idx]) !== 'user' || isToolResultContent(content)) {
|
|
202
|
+
continue
|
|
203
|
+
}
|
|
204
|
+
const text = textFromMessageContent(content).trim()
|
|
205
|
+
if (text) return text
|
|
206
|
+
}
|
|
207
|
+
return ''
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function safeDocumentArtifactId(value: unknown): string | undefined {
|
|
211
|
+
if (typeof value !== 'string') return undefined
|
|
212
|
+
const candidate = value.trim()
|
|
213
|
+
return SAFE_DOCUMENT_ARTIFACT_ID_RE.test(candidate) ? candidate : undefined
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function explicitDocumentArtifactIdFromText(text: string): string | undefined {
|
|
217
|
+
const marked = EXPLICIT_DOCUMENT_ARTIFACT_MARKER_RE.exec(text)?.[1]
|
|
218
|
+
const markedArtifactId = safeDocumentArtifactId(marked)
|
|
219
|
+
if (markedArtifactId) return markedArtifactId
|
|
220
|
+
const prefixed = EXPLICIT_DOCUMENT_ARTIFACT_PREFIX_RE.exec(text)?.[1]
|
|
221
|
+
return safeDocumentArtifactId(prefixed)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function parseJsonObject(value: unknown): JsonObject | undefined {
|
|
225
|
+
if (isJsonObject(value)) return value
|
|
226
|
+
if (typeof value !== 'string' || !value.trim()) return undefined
|
|
227
|
+
try {
|
|
228
|
+
return asJsonObject(JSON.parse(value))
|
|
229
|
+
} catch {
|
|
230
|
+
return undefined
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function documentToolResultPayload(message: unknown): JsonObject | undefined {
|
|
235
|
+
const directResult = asJsonObject(asJsonObject(message).toolUseResult).result
|
|
236
|
+
if (isJsonObject(directResult)) return directResult
|
|
237
|
+
|
|
238
|
+
const content = messageContent(message)
|
|
239
|
+
if (!Array.isArray(content)) return undefined
|
|
240
|
+
for (const block of content) {
|
|
241
|
+
const record = asJsonObject(block)
|
|
242
|
+
if (record.type !== 'tool_result') continue
|
|
243
|
+
const parsed = parseJsonObject(record.content)
|
|
244
|
+
const nestedResult = asJsonObject(parsed).result
|
|
245
|
+
if (isJsonObject(nestedResult)) return nestedResult
|
|
246
|
+
}
|
|
247
|
+
return undefined
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function latestDocumentArtifactRef(
|
|
251
|
+
messages: readonly unknown[],
|
|
252
|
+
options: {
|
|
253
|
+
toolIds: ReadonlySet<string>
|
|
254
|
+
artifactPrefix: string
|
|
255
|
+
},
|
|
256
|
+
): string | undefined {
|
|
257
|
+
for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
|
|
258
|
+
const payload = documentToolResultPayload(messages[idx])
|
|
259
|
+
if (!payload) continue
|
|
260
|
+
if (
|
|
261
|
+
typeof payload.tool_id !== 'string' ||
|
|
262
|
+
!options.toolIds.has(payload.tool_id)
|
|
263
|
+
) continue
|
|
264
|
+
if (payload.status !== 'ok') continue
|
|
265
|
+
const refs = Array.isArray(payload.artifact_refs) ? payload.artifact_refs : []
|
|
266
|
+
for (let refIdx = refs.length - 1; refIdx >= 0; refIdx -= 1) {
|
|
267
|
+
const ref = safeDocumentArtifactId(refs[refIdx])
|
|
268
|
+
if (ref?.startsWith(options.artifactPrefix)) return ref
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return undefined
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function latestMutableDocumentArtifactRef(messages: readonly unknown[]): string | undefined {
|
|
275
|
+
return (
|
|
276
|
+
latestDocumentArtifactRef(messages, {
|
|
277
|
+
toolIds: DOCUMENT_MUTATION_TOOL_NAMES,
|
|
278
|
+
artifactPrefix: 'derivative-',
|
|
279
|
+
}) ??
|
|
280
|
+
latestDocumentArtifactRef(messages, {
|
|
281
|
+
toolIds: new Set([
|
|
282
|
+
'document_copy_for_edit',
|
|
283
|
+
'document_apply_fill',
|
|
284
|
+
'document_apply_style',
|
|
285
|
+
]),
|
|
286
|
+
artifactPrefix: 'working-',
|
|
287
|
+
})
|
|
288
|
+
)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function shouldHideSuccessfulIntermediateDocumentResult(output: unknown): boolean {
|
|
292
|
+
const payload = extractDocumentToolResultPayload(output)
|
|
293
|
+
return (
|
|
294
|
+
payload !== null &&
|
|
295
|
+
payload.status === 'ok' &&
|
|
296
|
+
typeof payload.tool_id === 'string' &&
|
|
297
|
+
MECHANICAL_DOCUMENT_TOOL_NAMES.has(payload.tool_id)
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function documentCorrelationId(value: unknown): string {
|
|
302
|
+
return typeof value === 'string' && value.trim()
|
|
303
|
+
? value.trim()
|
|
304
|
+
: `document-render-${randomUUID()}`
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function documentFormatFromText(text: string): string | undefined {
|
|
308
|
+
return DOCUMENT_FORMAT_RE.exec(text)?.[0]?.toLowerCase()
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function documentFormatFromPath(path: string): string | undefined {
|
|
312
|
+
const match = /\.(hwpx|hwp|docx|pdf|xlsx|pptx)$/iu.exec(path.trim())
|
|
313
|
+
return match?.[1]?.toLowerCase()
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function inferredDownloadsDocumentPath(text: string): string | undefined {
|
|
317
|
+
if (!/(다운로드\s*폴더|downloads)/iu.test(text)) return undefined
|
|
318
|
+
const formatMatch = DOCUMENT_FORMAT_RE.exec(text)
|
|
319
|
+
const format = formatMatch?.[0]?.toLowerCase()
|
|
320
|
+
if (!format || formatMatch === null) return undefined
|
|
321
|
+
const beforeFormat = text.slice(0, formatMatch.index).trim()
|
|
322
|
+
const nameMatch =
|
|
323
|
+
/(?:다운로드\s*폴더|downloads)(?:에)?\s*(?:있는|의)?\s*(?<name>.+)$/iu.exec(
|
|
324
|
+
beforeFormat,
|
|
325
|
+
)
|
|
326
|
+
const rawName = nameMatch?.groups?.name?.trim()
|
|
327
|
+
if (!rawName) return undefined
|
|
328
|
+
const fileName = rawName
|
|
329
|
+
.replace(/[\\/:*?"<>|]/gu, ' ')
|
|
330
|
+
.replace(/\s+/gu, ' ')
|
|
331
|
+
.replace(/[.。.]+$/gu, '')
|
|
332
|
+
.trim()
|
|
333
|
+
if (!fileName) return undefined
|
|
334
|
+
return join(homedir(), 'Downloads', `${fileName}.${format}`)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function isDownloadsFolderLikePath(value: unknown): boolean {
|
|
338
|
+
if (typeof value !== 'string') return false
|
|
339
|
+
const normalized = value
|
|
340
|
+
.trim()
|
|
341
|
+
.replace(/^['"`]+|['"`]+$/gu, '')
|
|
342
|
+
.replace(/[\\/]+$/u, '')
|
|
343
|
+
.replace(/\.$/u, '')
|
|
344
|
+
return DOWNLOADS_FOLDER_PATH_RE.test(normalized)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function normalizeDownloadsDocumentPath(value: unknown): string | undefined {
|
|
348
|
+
if (typeof value !== 'string') return undefined
|
|
349
|
+
const cleaned = value
|
|
350
|
+
.trim()
|
|
351
|
+
.replace(/^['"`]+|['"`]+$/gu, '')
|
|
352
|
+
.replace(DOCUMENT_EXTENSION_TRAILING_PUNCT_RE, '$1')
|
|
353
|
+
if (!cleaned) return undefined
|
|
354
|
+
const downloadsPathMatch = DOWNLOADS_PATH_SEGMENT_RE.exec(cleaned)
|
|
355
|
+
if (DOCUMENT_EXTENSION_RE.test(cleaned) && downloadsPathMatch) {
|
|
356
|
+
const homeDownloads = `${homedir()}/Downloads/`
|
|
357
|
+
if (cleaned.startsWith(homeDownloads)) return cleaned
|
|
358
|
+
const tail = downloadsPathMatch.groups?.tail
|
|
359
|
+
if (!tail || tail.includes('..')) return undefined
|
|
360
|
+
const parts = tail.split(/[\\/]+/u).filter(Boolean)
|
|
361
|
+
if (parts.length === 0) return undefined
|
|
362
|
+
return join(homedir(), 'Downloads', ...parts)
|
|
363
|
+
}
|
|
364
|
+
return undefined
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function cleanUserDocumentPath(value: string): string {
|
|
368
|
+
return value
|
|
369
|
+
.trim()
|
|
370
|
+
.replace(/^['"`]+|['"`]+$/gu, '')
|
|
371
|
+
.replace(DOCUMENT_EXTENSION_TRAILING_PUNCT_RE, '$1')
|
|
372
|
+
.replace(/^~/u, homedir())
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function existingUserDocumentPathsFromText(text: string): string[] {
|
|
376
|
+
const paths: string[] = []
|
|
377
|
+
for (const match of text.matchAll(EXPLICIT_LOCAL_DOCUMENT_PATH_RE)) {
|
|
378
|
+
const rawPath = match.groups?.path
|
|
379
|
+
if (typeof rawPath !== 'string') continue
|
|
380
|
+
const candidate = cleanUserDocumentPath(rawPath)
|
|
381
|
+
if (!candidate || !DOCUMENT_EXTENSION_RE.test(candidate)) continue
|
|
382
|
+
if (!existsSync(candidate)) continue
|
|
383
|
+
if (!paths.includes(candidate)) paths.push(candidate)
|
|
384
|
+
}
|
|
385
|
+
return paths
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function normalizeExactUserDocumentPathInput(
|
|
389
|
+
input: Record<string, unknown>,
|
|
390
|
+
document: JsonObject,
|
|
391
|
+
messages: readonly unknown[],
|
|
392
|
+
): Record<string, unknown> | undefined {
|
|
393
|
+
if (document.artifact_id !== undefined) return undefined
|
|
394
|
+
const userPaths = existingUserDocumentPathsFromText(latestPlainUserText(messages))
|
|
395
|
+
if (userPaths.length !== 1) return undefined
|
|
396
|
+
const lockedPath = userPaths[0]
|
|
397
|
+
if (lockedPath === undefined) return undefined
|
|
398
|
+
|
|
399
|
+
const currentPath =
|
|
400
|
+
typeof document.path === 'string' ? cleanUserDocumentPath(document.path) : undefined
|
|
401
|
+
if (currentPath !== undefined && existsSync(currentPath)) return undefined
|
|
402
|
+
if (
|
|
403
|
+
currentPath !== undefined &&
|
|
404
|
+
basename(currentPath) !== basename(lockedPath)
|
|
405
|
+
) {
|
|
406
|
+
return undefined
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return {
|
|
410
|
+
...input,
|
|
411
|
+
correlation_id: documentCorrelationId(input.correlation_id),
|
|
412
|
+
document: {
|
|
413
|
+
...document,
|
|
414
|
+
path: lockedPath,
|
|
415
|
+
expected_format:
|
|
416
|
+
documentFormatFromPath(lockedPath) ??
|
|
417
|
+
document.expected_format ??
|
|
418
|
+
input.expected_format ??
|
|
419
|
+
documentFormatFromText(latestPlainUserText(messages)),
|
|
420
|
+
},
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function normalizeDocumentInspectPathInput(
|
|
425
|
+
toolId: string,
|
|
426
|
+
input: Record<string, unknown>,
|
|
427
|
+
document: JsonObject,
|
|
428
|
+
messages: readonly unknown[],
|
|
429
|
+
): Record<string, unknown> | undefined {
|
|
430
|
+
if (toolId !== 'document_inspect' && toolId !== 'document') return undefined
|
|
431
|
+
const path = document.path ?? input.path
|
|
432
|
+
const userText = latestPlainUserText(messages)
|
|
433
|
+
const cleanedPath = typeof path === 'string' ? cleanUserDocumentPath(path) : undefined
|
|
434
|
+
if (
|
|
435
|
+
cleanedPath !== undefined &&
|
|
436
|
+
DOCUMENT_EXTENSION_RE.test(cleanedPath) &&
|
|
437
|
+
existsSync(cleanedPath)
|
|
438
|
+
) {
|
|
439
|
+
return undefined
|
|
440
|
+
}
|
|
441
|
+
const normalizedDownloadsPath = normalizeDownloadsDocumentPath(path)
|
|
442
|
+
const inferredPath = isDownloadsFolderLikePath(path)
|
|
443
|
+
? inferredDownloadsDocumentPath(userText)
|
|
444
|
+
: undefined
|
|
445
|
+
const inferredDownloadsPath = inferredDownloadsDocumentPath(userText)
|
|
446
|
+
const shouldPreferUserTextDownloadsPath =
|
|
447
|
+
normalizedDownloadsPath !== undefined &&
|
|
448
|
+
inferredDownloadsPath !== undefined &&
|
|
449
|
+
normalizedDownloadsPath !== inferredDownloadsPath
|
|
450
|
+
const normalizedPath =
|
|
451
|
+
(shouldPreferUserTextDownloadsPath ? inferredDownloadsPath : undefined) ??
|
|
452
|
+
(normalizedDownloadsPath !== undefined && existsSync(normalizedDownloadsPath)
|
|
453
|
+
? normalizedDownloadsPath
|
|
454
|
+
: undefined) ??
|
|
455
|
+
(inferredPath !== undefined && existsSync(inferredPath) ? inferredPath : undefined) ??
|
|
456
|
+
(inferredDownloadsPath !== undefined && existsSync(inferredDownloadsPath)
|
|
457
|
+
? inferredDownloadsPath
|
|
458
|
+
: undefined) ??
|
|
459
|
+
inferredDownloadsPath ??
|
|
460
|
+
normalizedDownloadsPath ??
|
|
461
|
+
inferredPath
|
|
462
|
+
if (!normalizedPath) return undefined
|
|
463
|
+
return {
|
|
464
|
+
...input,
|
|
465
|
+
correlation_id: documentCorrelationId(input.correlation_id),
|
|
466
|
+
document: {
|
|
467
|
+
...document,
|
|
468
|
+
path: normalizedPath,
|
|
469
|
+
expected_format:
|
|
470
|
+
documentFormatFromPath(normalizedPath) ??
|
|
471
|
+
document.expected_format ??
|
|
472
|
+
input.expected_format ??
|
|
473
|
+
documentFormatFromText(userText),
|
|
474
|
+
},
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function normalizeDocumentPathExpectedFormatInput(
|
|
479
|
+
input: Record<string, unknown>,
|
|
480
|
+
document: JsonObject,
|
|
481
|
+
): Record<string, unknown> | undefined {
|
|
482
|
+
if (document.artifact_id !== undefined) return undefined
|
|
483
|
+
if (typeof document.path !== 'string') return undefined
|
|
484
|
+
const normalizedPath = cleanUserDocumentPath(document.path)
|
|
485
|
+
const pathFormat = documentFormatFromPath(normalizedPath)
|
|
486
|
+
if (pathFormat === undefined) return undefined
|
|
487
|
+
const currentFormat =
|
|
488
|
+
typeof document.expected_format === 'string'
|
|
489
|
+
? document.expected_format.toLowerCase()
|
|
490
|
+
: undefined
|
|
491
|
+
if (currentFormat === pathFormat && document.path === normalizedPath) {
|
|
492
|
+
return undefined
|
|
493
|
+
}
|
|
494
|
+
return {
|
|
495
|
+
...input,
|
|
496
|
+
correlation_id: documentCorrelationId(input.correlation_id),
|
|
497
|
+
document: {
|
|
498
|
+
...document,
|
|
499
|
+
path: normalizedPath,
|
|
500
|
+
expected_format: pathFormat,
|
|
501
|
+
},
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function normalizeHwpxTextTargetPath(value: unknown): string | undefined {
|
|
506
|
+
if (typeof value !== 'string') return undefined
|
|
507
|
+
const targetPath = value.trim()
|
|
508
|
+
const match = HWPX_TEXT_TARGET_ALIAS_RE.exec(targetPath)
|
|
509
|
+
const rawIndex = match?.groups?.indexA ?? match?.groups?.indexB
|
|
510
|
+
if (!rawIndex) return undefined
|
|
511
|
+
return `/hwpx/text[${Number(rawIndex)}]`
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function latestDocumentFieldPaths(messages: readonly unknown[]): Set<string> | undefined {
|
|
515
|
+
for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
|
|
516
|
+
const payload = documentToolResultPayload(messages[idx])
|
|
517
|
+
const extraction = asJsonObject(payload?.extraction)
|
|
518
|
+
const fields = Array.isArray(extraction.fields) ? extraction.fields : []
|
|
519
|
+
const paths = new Set<string>()
|
|
520
|
+
for (const field of fields) {
|
|
521
|
+
const path = asJsonObject(field).path
|
|
522
|
+
if (typeof path === 'string' && path.trim()) {
|
|
523
|
+
paths.add(path.trim())
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
if (paths.size > 0) return paths
|
|
527
|
+
}
|
|
528
|
+
return undefined
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function latestDocumentTableCellFieldAliases(
|
|
532
|
+
messages: readonly unknown[],
|
|
533
|
+
): Map<string, string> | undefined {
|
|
534
|
+
for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
|
|
535
|
+
const payload = documentToolResultPayload(messages[idx])
|
|
536
|
+
const extraction = asJsonObject(payload?.extraction)
|
|
537
|
+
const tables = Array.isArray(extraction.tables) ? extraction.tables : []
|
|
538
|
+
const aliases = new Map<string, string>()
|
|
539
|
+
for (const tableValue of tables) {
|
|
540
|
+
const table = asJsonObject(tableValue)
|
|
541
|
+
const blockId = table.block_id
|
|
542
|
+
const cells = Array.isArray(table.cells) ? table.cells : []
|
|
543
|
+
if (typeof blockId !== 'string' || !blockId.trim()) continue
|
|
544
|
+
for (const cellValue of cells) {
|
|
545
|
+
const cell = asJsonObject(cellValue)
|
|
546
|
+
const rowIndex = cell.row_index
|
|
547
|
+
const columnIndex = cell.column_index
|
|
548
|
+
const fieldPath = cell.field_path
|
|
549
|
+
if (
|
|
550
|
+
typeof rowIndex !== 'number' ||
|
|
551
|
+
typeof columnIndex !== 'number' ||
|
|
552
|
+
typeof fieldPath !== 'string' ||
|
|
553
|
+
!fieldPath.trim()
|
|
554
|
+
) {
|
|
555
|
+
continue
|
|
556
|
+
}
|
|
557
|
+
aliases.set(
|
|
558
|
+
`/hwpx/[${blockId.trim()}]/cells[${rowIndex}][${columnIndex}]`,
|
|
559
|
+
fieldPath.trim(),
|
|
560
|
+
)
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (aliases.size > 0) return aliases
|
|
564
|
+
}
|
|
565
|
+
return undefined
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function normalizeHwpxTableCellTargetPath(
|
|
569
|
+
value: unknown,
|
|
570
|
+
aliases: ReadonlyMap<string, string> | undefined,
|
|
571
|
+
): string | undefined {
|
|
572
|
+
if (typeof value !== 'string') return undefined
|
|
573
|
+
const targetPath = value.trim()
|
|
574
|
+
if (!HWPX_BLOCK_TABLE_CELL_TARGET_RE.test(targetPath)) return undefined
|
|
575
|
+
return aliases?.get(targetPath)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
function normalizeDocumentPatchTargetPaths(
|
|
579
|
+
input: Record<string, unknown>,
|
|
580
|
+
messages: readonly unknown[],
|
|
581
|
+
): Record<string, unknown> {
|
|
582
|
+
const patches = input.patches
|
|
583
|
+
if (!Array.isArray(patches)) return input
|
|
584
|
+
|
|
585
|
+
const fieldPaths = latestDocumentFieldPaths(messages)
|
|
586
|
+
const tableCellAliases = latestDocumentTableCellFieldAliases(messages)
|
|
587
|
+
let changed = false
|
|
588
|
+
const normalizedPatches = patches.flatMap(patch => {
|
|
589
|
+
if (!isJsonObject(patch)) return patch
|
|
590
|
+
const rawTargetPath =
|
|
591
|
+
typeof patch.target_path === 'string' ? patch.target_path.trim() : patch.target_path
|
|
592
|
+
const isHwpxTableCellTarget =
|
|
593
|
+
typeof rawTargetPath === 'string' && HWPX_BLOCK_TABLE_CELL_TARGET_RE.test(rawTargetPath)
|
|
594
|
+
const normalizedTargetPath =
|
|
595
|
+
normalizeHwpxTextTargetPath(patch.target_path) ??
|
|
596
|
+
normalizeHwpxTableCellTargetPath(patch.target_path, tableCellAliases)
|
|
597
|
+
const targetPath =
|
|
598
|
+
normalizedTargetPath ?? (
|
|
599
|
+
typeof rawTargetPath === 'string' ? rawTargetPath : patch.target_path
|
|
600
|
+
)
|
|
601
|
+
if (
|
|
602
|
+
isHwpxTableCellTarget &&
|
|
603
|
+
tableCellAliases !== undefined &&
|
|
604
|
+
normalizedTargetPath === undefined
|
|
605
|
+
) {
|
|
606
|
+
changed = true
|
|
607
|
+
return []
|
|
608
|
+
}
|
|
609
|
+
if (
|
|
610
|
+
typeof targetPath === 'string' &&
|
|
611
|
+
fieldPaths !== undefined &&
|
|
612
|
+
HWPX_TEXT_TARGET_RE.test(targetPath) &&
|
|
613
|
+
!fieldPaths.has(targetPath)
|
|
614
|
+
) {
|
|
615
|
+
changed = true
|
|
616
|
+
return []
|
|
617
|
+
}
|
|
618
|
+
if (
|
|
619
|
+
normalizedTargetPath === undefined ||
|
|
620
|
+
normalizedTargetPath === patch.target_path
|
|
621
|
+
) {
|
|
622
|
+
return patch
|
|
623
|
+
}
|
|
624
|
+
changed = true
|
|
625
|
+
return {
|
|
626
|
+
...patch,
|
|
627
|
+
target_path: normalizedTargetPath,
|
|
628
|
+
}
|
|
629
|
+
})
|
|
630
|
+
|
|
631
|
+
if (normalizedPatches.length === 0) return input
|
|
632
|
+
return changed ? { ...input, patches: normalizedPatches } : input
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function normalizeDocumentPrimitiveInstructionInput(
|
|
636
|
+
toolId: string,
|
|
637
|
+
input: Record<string, unknown>,
|
|
638
|
+
messages: readonly unknown[],
|
|
639
|
+
): Record<string, unknown> {
|
|
640
|
+
if (toolId !== 'document') return input
|
|
641
|
+
if (Array.isArray(input.patches) && input.patches.length > 0) return input
|
|
642
|
+
|
|
643
|
+
const userText = latestPlainUserText(messages)
|
|
644
|
+
if (!userText) return input
|
|
645
|
+
|
|
646
|
+
const instruction =
|
|
647
|
+
typeof input.instruction === 'string' ? input.instruction.trim() : ''
|
|
648
|
+
if (instruction.includes(userText)) return input
|
|
649
|
+
|
|
650
|
+
return {
|
|
651
|
+
...input,
|
|
652
|
+
instruction: instruction
|
|
653
|
+
? `${instruction}\n\nOriginal user request:\n${userText}`
|
|
654
|
+
: userText,
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
export function normalizeExplicitDocumentArtifactInput(
|
|
659
|
+
toolId: string,
|
|
660
|
+
input: Record<string, unknown>,
|
|
661
|
+
messages: readonly unknown[],
|
|
662
|
+
): Record<string, unknown> {
|
|
663
|
+
if (!DOCUMENT_TOOL_NAMES.has(toolId)) return input
|
|
664
|
+
|
|
665
|
+
const instructionInput = normalizeDocumentPrimitiveInstructionInput(
|
|
666
|
+
toolId,
|
|
667
|
+
input,
|
|
668
|
+
messages,
|
|
669
|
+
)
|
|
670
|
+
const normalizedPatchInput = normalizeDocumentPatchTargetPaths(
|
|
671
|
+
instructionInput,
|
|
672
|
+
messages,
|
|
673
|
+
)
|
|
674
|
+
const { artifact_id: topLevelArtifactIdRaw, ...withoutTopLevelArtifactId } =
|
|
675
|
+
normalizedPatchInput
|
|
676
|
+
const document = asJsonObject(normalizedPatchInput.document)
|
|
677
|
+
const normalizedExactUserPathInput = normalizeExactUserDocumentPathInput(
|
|
678
|
+
normalizedPatchInput,
|
|
679
|
+
document,
|
|
680
|
+
messages,
|
|
681
|
+
)
|
|
682
|
+
if (normalizedExactUserPathInput) return normalizedExactUserPathInput
|
|
683
|
+
const normalizedInspectPathInput = normalizeDocumentInspectPathInput(
|
|
684
|
+
toolId,
|
|
685
|
+
normalizedPatchInput,
|
|
686
|
+
document,
|
|
687
|
+
messages,
|
|
688
|
+
)
|
|
689
|
+
if (normalizedInspectPathInput) return normalizedInspectPathInput
|
|
690
|
+
const { path: _documentPath, ...documentWithoutPath } = document
|
|
691
|
+
const existingDocumentArtifactId = safeDocumentArtifactId(document.artifact_id)
|
|
692
|
+
const inputArtifactId =
|
|
693
|
+
existingDocumentArtifactId ?? safeDocumentArtifactId(topLevelArtifactIdRaw)
|
|
694
|
+
const hasExtractionArtifactId = inputArtifactId?.startsWith('document-intake-') === true
|
|
695
|
+
|
|
696
|
+
if (DOCUMENT_ARTIFACT_FOLLOWUP_TOOL_NAMES.has(toolId)) {
|
|
697
|
+
const artifactId = latestMutableDocumentArtifactRef(messages)
|
|
698
|
+
if (
|
|
699
|
+
artifactId &&
|
|
700
|
+
(
|
|
701
|
+
document.path !== undefined ||
|
|
702
|
+
existingDocumentArtifactId?.startsWith('source-') ||
|
|
703
|
+
hasExtractionArtifactId
|
|
704
|
+
)
|
|
705
|
+
) {
|
|
706
|
+
return {
|
|
707
|
+
...withoutTopLevelArtifactId,
|
|
708
|
+
correlation_id: documentCorrelationId(input.correlation_id),
|
|
709
|
+
document: {
|
|
710
|
+
...documentWithoutPath,
|
|
711
|
+
artifact_id: artifactId,
|
|
712
|
+
},
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
if (toolId === 'document_copy_for_edit' && hasExtractionArtifactId) {
|
|
718
|
+
const sourceArtifactId = latestDocumentArtifactRef(messages, {
|
|
719
|
+
toolIds: new Set(['document_inspect', 'document_extract', 'document_form_schema']),
|
|
720
|
+
artifactPrefix: 'source-',
|
|
721
|
+
})
|
|
722
|
+
if (sourceArtifactId) {
|
|
723
|
+
return {
|
|
724
|
+
...withoutTopLevelArtifactId,
|
|
725
|
+
correlation_id: documentCorrelationId(input.correlation_id),
|
|
726
|
+
document: {
|
|
727
|
+
...documentWithoutPath,
|
|
728
|
+
artifact_id: sourceArtifactId,
|
|
729
|
+
},
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
if (existingDocumentArtifactId) {
|
|
735
|
+
return topLevelArtifactIdRaw === undefined
|
|
736
|
+
? { ...normalizedPatchInput, document: documentWithoutPath }
|
|
737
|
+
: { ...withoutTopLevelArtifactId, document: documentWithoutPath }
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
if (toolId === 'document_copy_for_edit' && document.path !== undefined) {
|
|
741
|
+
const sourceArtifactId = latestDocumentArtifactRef(messages, {
|
|
742
|
+
toolIds: new Set(['document_inspect', 'document_extract', 'document_form_schema']),
|
|
743
|
+
artifactPrefix: 'source-',
|
|
744
|
+
})
|
|
745
|
+
if (sourceArtifactId) {
|
|
746
|
+
return {
|
|
747
|
+
...withoutTopLevelArtifactId,
|
|
748
|
+
correlation_id: documentCorrelationId(input.correlation_id),
|
|
749
|
+
document: {
|
|
750
|
+
...documentWithoutPath,
|
|
751
|
+
artifact_id: sourceArtifactId,
|
|
752
|
+
},
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
const topLevelArtifactId = safeDocumentArtifactId(topLevelArtifactIdRaw)
|
|
758
|
+
const currentTextArtifactId = explicitDocumentArtifactIdFromText(
|
|
759
|
+
latestPlainUserText(messages),
|
|
760
|
+
)
|
|
761
|
+
const artifactId = topLevelArtifactId ?? currentTextArtifactId
|
|
762
|
+
if (!artifactId) {
|
|
763
|
+
return (
|
|
764
|
+
normalizeDocumentPathExpectedFormatInput(normalizedPatchInput, document) ??
|
|
765
|
+
normalizedPatchInput
|
|
766
|
+
)
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
return {
|
|
770
|
+
...withoutTopLevelArtifactId,
|
|
771
|
+
correlation_id: documentCorrelationId(input.correlation_id),
|
|
772
|
+
document: {
|
|
773
|
+
...documentWithoutPath,
|
|
774
|
+
artifact_id: artifactId,
|
|
775
|
+
},
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
40
779
|
function asStringArray(value: unknown): string[] {
|
|
41
780
|
return Array.isArray(value)
|
|
42
781
|
? value.filter((item): item is string => typeof item === 'string')
|
|
@@ -197,6 +936,8 @@ function primitiveToolFor(primitive: AdapterPrimitive): Tool {
|
|
|
197
936
|
return ResolveLocationPrimitive as Tool
|
|
198
937
|
case 'send':
|
|
199
938
|
return SubmitPrimitive as Tool
|
|
939
|
+
case 'document':
|
|
940
|
+
return DocumentPrimitive as Tool
|
|
200
941
|
case 'check':
|
|
201
942
|
return VerifyPrimitive as Tool
|
|
202
943
|
case 'find':
|
|
@@ -212,6 +953,22 @@ function rootInputFor(entry: AdapterManifestEntry, input: Record<string, unknown
|
|
|
212
953
|
}
|
|
213
954
|
}
|
|
214
955
|
|
|
956
|
+
function concreteAdapterCallInputFor(
|
|
957
|
+
entry: AdapterManifestEntry,
|
|
958
|
+
input: Record<string, unknown>,
|
|
959
|
+
): Record<string, unknown> {
|
|
960
|
+
if (input.tool_id !== entry.tool_id) return input
|
|
961
|
+
const params = input.params
|
|
962
|
+
return isJsonObject(params) ? params : input
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
function validateAdapterContractInput(
|
|
966
|
+
_toolId: string,
|
|
967
|
+
_input: Record<string, unknown>,
|
|
968
|
+
) {
|
|
969
|
+
return undefined
|
|
970
|
+
}
|
|
971
|
+
|
|
215
972
|
export function isAdapterToolName(name: string): boolean {
|
|
216
973
|
return resolveAdapter(name) !== undefined
|
|
217
974
|
}
|
|
@@ -233,219 +990,487 @@ function searchTokens(text: string): string[] {
|
|
|
233
990
|
return text.toLowerCase().match(/[\p{L}\p{N}_-]+/gu) ?? []
|
|
234
991
|
}
|
|
235
992
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
993
|
+
const KOREAN_TRAILING_PARTICLES = [
|
|
994
|
+
'으로부터',
|
|
995
|
+
'에서부터',
|
|
996
|
+
'에게서',
|
|
997
|
+
'한테서',
|
|
998
|
+
'까지',
|
|
999
|
+
'부터',
|
|
1000
|
+
'으로',
|
|
1001
|
+
'에서',
|
|
1002
|
+
'에게',
|
|
1003
|
+
'한테',
|
|
1004
|
+
'처럼',
|
|
1005
|
+
'보다',
|
|
1006
|
+
'하고',
|
|
1007
|
+
'이며',
|
|
1008
|
+
'이고',
|
|
1009
|
+
'로',
|
|
1010
|
+
'와',
|
|
1011
|
+
'과',
|
|
1012
|
+
'은',
|
|
1013
|
+
'는',
|
|
1014
|
+
'이',
|
|
1015
|
+
'가',
|
|
1016
|
+
'을',
|
|
1017
|
+
'를',
|
|
1018
|
+
'의',
|
|
1019
|
+
'에',
|
|
1020
|
+
'도',
|
|
1021
|
+
'만',
|
|
1022
|
+
] as const
|
|
1023
|
+
|
|
1024
|
+
const LOW_SIGNAL_DISCOVERY_TOKENS = new Set([
|
|
1025
|
+
'지금',
|
|
1026
|
+
'현재',
|
|
1027
|
+
'오늘',
|
|
1028
|
+
'내일',
|
|
1029
|
+
'모레',
|
|
1030
|
+
'이번',
|
|
1031
|
+
'근처',
|
|
1032
|
+
'주변',
|
|
1033
|
+
'어디',
|
|
1034
|
+
'어떻게',
|
|
1035
|
+
'now',
|
|
1036
|
+
'current',
|
|
1037
|
+
'today',
|
|
1038
|
+
'tomorrow',
|
|
1039
|
+
'latest',
|
|
1040
|
+
'nearby',
|
|
1041
|
+
'realtime',
|
|
1042
|
+
'real-time',
|
|
1043
|
+
])
|
|
1044
|
+
|
|
1045
|
+
const KMA_LIFESTYLE_WEATHER_RE =
|
|
1046
|
+
/(날씨|현재\s*기상|실황|관측|예보|기온|습도|풍속|지금\s*비|비\s*(?:와|오|올|내리)|우산|강수|소나기|산책|퇴근|current\s+weather|forecast|rain|umbrella|precipitation|temperature)/iu
|
|
1047
|
+
const HEALTHCARE_RE =
|
|
1048
|
+
/(응급|응급실|응급의료|야간\s*진료|야간진료|병원|의원|의료기관|진료\s*가능|\bemergency\b|\ber\b|\bhospital\b|\bclinic\b)/iu
|
|
1049
|
+
const AIR_QUALITY_RE =
|
|
1050
|
+
/(미세먼지|초미세먼지|초미세|대기질|대기오염|공기질|마스크|pm\s*2\.?5|pm\s*10|air\s*korea|airkorea|air\s*quality|airquality)/iu
|
|
1051
|
+
const KMA_ANALYSIS_RE =
|
|
1052
|
+
/(분석자료|이미\s*분석|고해상도\s*격자|객관분석|AWS\s*객관|지도\s*자료|일기도|분석일기도|비구름|바람\s*흐름|날씨\s*흐름|전국\s*날씨|synoptic|weather\s*chart|objective\s*analysis|high[-\s]?resolution|grid)/iu
|
|
1053
|
+
const AIRPORT_AVIATION_RE =
|
|
1054
|
+
/(AMOS|METAR|SPECI|RVR|항공기상|공항기상|활주로|runway|aviation|비행기|항공편|비행편|이륙|착륙|결항|지연|운항|뜰\s*만|뜨나|뜰\s*수|flight|take\s*off|landing|delay|cancel)/iu
|
|
1055
|
+
const POI_LOCATION_RE =
|
|
1056
|
+
/(근처|주변|주위|인근|가까운|우리\s*동네|여기|이\s*근처|현재\s*위치|내\s*위치|역|터미널|공항|캠퍼스|대학교|대학|해수욕장|시장|공원|랜드마크)/iu
|
|
1057
|
+
const ADMIN_LOCATION_RE =
|
|
1058
|
+
/(?:[가-힣]{2,}(?:시|군|구|동|읍|면)\b|[가-힣0-9]{2,}(?<!으)(?:로|길)\b)/iu
|
|
1059
|
+
const COORDINATE_PAIR_RE =
|
|
1060
|
+
/[+-]?\d{1,2}(?:\.\d+)?\s*,\s*[+-]?\d{2,3}(?:\.\d+)?/u
|
|
1061
|
+
const PRIOR_LOCATION_CONTEXT_RE = /\[prior_location_context\]/u
|
|
1062
|
+
const GOV24_RE = /(정부24|gov24|주민등록등본|등본|증명서|민원)/iu
|
|
1063
|
+
const GOV24_READ_ONLY_RE = /(가능\s*여부|준비물|확인|조회|안내|알려)/iu
|
|
1064
|
+
const GOV24_ACTION_RE = /(신청|진행|제출|접수|발급\s*신청|apply|submit|issue)/iu
|
|
1065
|
+
const WELFARE_RE =
|
|
1066
|
+
/(생활비|기초생활|주거급여|긴급복지|저소득|차상위|복지혜택|지원금|진료비\s*바우처|출산휴가|임신|아동수당|첫만남이용권)/iu
|
|
1067
|
+
const CIVIL_BIRTH_HANDOFF_RE =
|
|
1068
|
+
/(출생신고|아기가\s*태어|아동수당|첫만남이용권|피부양자\s*등록)/iu
|
|
1069
|
+
const UTILITY_RE = /(전기|수도|도시가스|요금|자동이체|공과금|고지서|납부)/iu
|
|
1070
|
+
const HOUSING_HANDOFF_RE =
|
|
1071
|
+
/(생애최초\s*주택구입|주택구입|대출|취득세|등기|전입)/iu
|
|
1072
|
+
const CIVIL_DEATH_RE = /(사망|돌아가|장례|유족|상속|재산|국민연금)/iu
|
|
1073
|
+
|
|
1074
|
+
const LOCATION_TOOL_IDS = new Set([
|
|
1075
|
+
'locate',
|
|
1076
|
+
'kakao_address_search',
|
|
1077
|
+
'kakao_keyword_search',
|
|
1078
|
+
'kakao_coord_to_region',
|
|
1079
|
+
'juso_adm_cd_lookup',
|
|
1080
|
+
'sgis_adm_cd_lookup',
|
|
1081
|
+
])
|
|
1082
|
+
const KMA_LIFESTYLE_WEATHER_TOOL_IDS = new Set([
|
|
1083
|
+
'kma_current_observation',
|
|
1084
|
+
'kma_ultra_short_term_forecast',
|
|
1085
|
+
'kma_short_term_forecast',
|
|
1086
|
+
'kma_forecast_fetch',
|
|
1087
|
+
])
|
|
1088
|
+
const EMERGENCY_TOOL_IDS = new Set([
|
|
1089
|
+
'nmc_emergency_search',
|
|
1090
|
+
'nmc_aed_site_locate',
|
|
1091
|
+
'hira_hospital_search',
|
|
1092
|
+
'hira_medical_institution_detail',
|
|
1093
|
+
])
|
|
1094
|
+
const GOV24_LOOKUP_TOOL_IDS = new Set(['mock_lookup_module_gov24_certificate'])
|
|
1095
|
+
const GOV24_ACTION_TOOL_IDS = new Set([
|
|
1096
|
+
'mock_lookup_module_gov24_certificate',
|
|
1097
|
+
'mock_verify_module_simple_auth',
|
|
1098
|
+
'mock_verify_ganpyeon_injeung',
|
|
1099
|
+
'mock_verify_mobile_id',
|
|
1100
|
+
'mock_submit_module_gov24_minwon',
|
|
1101
|
+
])
|
|
1102
|
+
const WELFARE_TOOL_IDS = new Set([
|
|
1103
|
+
'mohw_welfare_eligibility_search',
|
|
1104
|
+
'mock_welfare_application_submit_v1',
|
|
1105
|
+
])
|
|
1106
|
+
const UTILITY_TOOL_IDS = new Set([
|
|
1107
|
+
'kepco_contract_power_usage',
|
|
1108
|
+
'mock_kftc_opengiro_bill_send_v1',
|
|
1109
|
+
'mock_kftc_opengiro_payment_send_v1',
|
|
1110
|
+
])
|
|
1111
|
+
const CIVIL_DEATH_TOOL_IDS = new Set([
|
|
1112
|
+
'bfc_funeral_area_fee',
|
|
1113
|
+
'reb_real_estate_stat_table',
|
|
1114
|
+
'mohw_welfare_eligibility_search',
|
|
1115
|
+
])
|
|
1116
|
+
|
|
1117
|
+
type ProviderRoutingIntent = {
|
|
1118
|
+
readonly hasCoordinateLocationAnchor: boolean
|
|
1119
|
+
readonly hasAdminLocationAnchor: boolean
|
|
1120
|
+
readonly hasPriorLocationContext: boolean
|
|
1121
|
+
readonly hasLocationAnchor: boolean
|
|
1122
|
+
readonly hasLifestyleWeather: boolean
|
|
1123
|
+
readonly hasEmergencyMedical: boolean
|
|
1124
|
+
readonly hasGov24ReadOnly: boolean
|
|
1125
|
+
readonly hasGov24Action: boolean
|
|
1126
|
+
readonly hasWelfare: boolean
|
|
1127
|
+
readonly hasCivilBirthHandoff: boolean
|
|
1128
|
+
readonly hasUtility: boolean
|
|
1129
|
+
readonly hasHousingHandoff: boolean
|
|
1130
|
+
readonly hasCivilDeath: boolean
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
type AdapterSelectionOptions = {
|
|
1134
|
+
readonly hasCurrentTurnLocationContext?: boolean
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
function hasHangul(text: string): boolean {
|
|
1138
|
+
return /\p{Script=Hangul}/u.test(text)
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
function extractProviderRoutingIntent(query: string): ProviderRoutingIntent {
|
|
1142
|
+
const hasEmergencyMedical = HEALTHCARE_RE.test(query)
|
|
1143
|
+
const hasGov24 = GOV24_RE.test(query)
|
|
1144
|
+
const hasGov24Action = hasGov24 && GOV24_ACTION_RE.test(query)
|
|
1145
|
+
const hasCoordinateLocationAnchor = COORDINATE_PAIR_RE.test(query)
|
|
1146
|
+
const hasAdminLocationAnchor = ADMIN_LOCATION_RE.test(query)
|
|
1147
|
+
const hasPoiLocationAnchor = POI_LOCATION_RE.test(query)
|
|
1148
|
+
const hasPriorLocationContext = PRIOR_LOCATION_CONTEXT_RE.test(query)
|
|
1149
|
+
return {
|
|
1150
|
+
hasCoordinateLocationAnchor,
|
|
1151
|
+
hasAdminLocationAnchor,
|
|
1152
|
+
hasPriorLocationContext,
|
|
1153
|
+
hasLocationAnchor:
|
|
1154
|
+
hasCoordinateLocationAnchor ||
|
|
1155
|
+
hasPoiLocationAnchor ||
|
|
1156
|
+
hasAdminLocationAnchor ||
|
|
1157
|
+
hasPriorLocationContext,
|
|
1158
|
+
hasLifestyleWeather:
|
|
1159
|
+
KMA_LIFESTYLE_WEATHER_RE.test(query) &&
|
|
1160
|
+
!hasEmergencyMedical &&
|
|
1161
|
+
!AIR_QUALITY_RE.test(query) &&
|
|
1162
|
+
!KMA_ANALYSIS_RE.test(query) &&
|
|
1163
|
+
!AIRPORT_AVIATION_RE.test(query),
|
|
1164
|
+
hasEmergencyMedical,
|
|
1165
|
+
hasGov24ReadOnly:
|
|
1166
|
+
hasGov24 &&
|
|
1167
|
+
GOV24_READ_ONLY_RE.test(query) &&
|
|
1168
|
+
!hasGov24Action,
|
|
1169
|
+
hasGov24Action,
|
|
1170
|
+
hasWelfare: WELFARE_RE.test(query),
|
|
1171
|
+
hasCivilBirthHandoff: CIVIL_BIRTH_HANDOFF_RE.test(query),
|
|
1172
|
+
hasUtility: UTILITY_RE.test(query),
|
|
1173
|
+
hasHousingHandoff: HOUSING_HANDOFF_RE.test(query),
|
|
1174
|
+
hasCivilDeath: CIVIL_DEATH_RE.test(query),
|
|
257
1175
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
function addSetValues(target: Set<string>, values: ReadonlySet<string>): void {
|
|
1179
|
+
for (const value of values) target.add(value)
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
function restrictiveToolIdsForIntent(
|
|
1183
|
+
intent: ProviderRoutingIntent,
|
|
1184
|
+
options: AdapterSelectionOptions = {},
|
|
1185
|
+
): Set<string> | undefined {
|
|
1186
|
+
const allowed = new Set<string>()
|
|
1187
|
+
let restrictive = false
|
|
1188
|
+
|
|
1189
|
+
if (intent.hasGov24ReadOnly) {
|
|
1190
|
+
restrictive = true
|
|
1191
|
+
addSetValues(allowed, GOV24_LOOKUP_TOOL_IDS)
|
|
1192
|
+
} else if (intent.hasGov24Action) {
|
|
1193
|
+
restrictive = true
|
|
1194
|
+
addSetValues(allowed, GOV24_ACTION_TOOL_IDS)
|
|
274
1195
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
'hospital',
|
|
284
|
-
'clinic',
|
|
285
|
-
'medical',
|
|
286
|
-
'nearby',
|
|
287
|
-
]) {
|
|
288
|
-
tokens.add(token)
|
|
1196
|
+
|
|
1197
|
+
if (intent.hasLifestyleWeather) {
|
|
1198
|
+
restrictive = true
|
|
1199
|
+
if (
|
|
1200
|
+
options.hasCurrentTurnLocationContext !== true &&
|
|
1201
|
+
!intent.hasPriorLocationContext
|
|
1202
|
+
) {
|
|
1203
|
+
addSetValues(allowed, LOCATION_TOOL_IDS)
|
|
289
1204
|
}
|
|
1205
|
+
addSetValues(allowed, KMA_LIFESTYLE_WEATHER_TOOL_IDS)
|
|
290
1206
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
1207
|
+
|
|
1208
|
+
if (intent.hasEmergencyMedical) {
|
|
1209
|
+
restrictive = true
|
|
1210
|
+
if (
|
|
1211
|
+
options.hasCurrentTurnLocationContext !== true &&
|
|
1212
|
+
!intent.hasPriorLocationContext &&
|
|
1213
|
+
intent.hasLocationAnchor
|
|
1214
|
+
) {
|
|
1215
|
+
addSetValues(allowed, LOCATION_TOOL_IDS)
|
|
294
1216
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
1217
|
+
if (
|
|
1218
|
+
options.hasCurrentTurnLocationContext === true ||
|
|
1219
|
+
intent.hasPriorLocationContext ||
|
|
1220
|
+
intent.hasCoordinateLocationAnchor ||
|
|
1221
|
+
intent.hasAdminLocationAnchor
|
|
1222
|
+
) {
|
|
1223
|
+
addSetValues(allowed, EMERGENCY_TOOL_IDS)
|
|
299
1224
|
}
|
|
300
1225
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
1226
|
+
|
|
1227
|
+
if (intent.hasWelfare) {
|
|
1228
|
+
restrictive = true
|
|
1229
|
+
addSetValues(allowed, WELFARE_TOOL_IDS)
|
|
305
1230
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
1231
|
+
|
|
1232
|
+
if (intent.hasCivilBirthHandoff) {
|
|
1233
|
+
restrictive = true
|
|
310
1234
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
1235
|
+
|
|
1236
|
+
if (intent.hasUtility) {
|
|
1237
|
+
restrictive = true
|
|
1238
|
+
addSetValues(allowed, UTILITY_TOOL_IDS)
|
|
315
1239
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
}
|
|
1240
|
+
|
|
1241
|
+
if (intent.hasHousingHandoff) {
|
|
1242
|
+
restrictive = true
|
|
320
1243
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
1244
|
+
|
|
1245
|
+
if (intent.hasCivilDeath) {
|
|
1246
|
+
restrictive = true
|
|
1247
|
+
addSetValues(allowed, CIVIL_DEATH_TOOL_IDS)
|
|
325
1248
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
1249
|
+
|
|
1250
|
+
return restrictive ? allowed : undefined
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
function routingIntentBoostForTool(
|
|
1254
|
+
toolId: string,
|
|
1255
|
+
intent: ProviderRoutingIntent,
|
|
1256
|
+
): number {
|
|
1257
|
+
if (intent.hasGov24ReadOnly && GOV24_LOOKUP_TOOL_IDS.has(toolId)) return 1200
|
|
1258
|
+
if (intent.hasGov24Action && GOV24_ACTION_TOOL_IDS.has(toolId)) return 1000
|
|
1259
|
+
if (intent.hasLifestyleWeather) {
|
|
1260
|
+
if (toolId === 'kakao_keyword_search') return 1100
|
|
1261
|
+
if (toolId === 'kakao_address_search') return 1000
|
|
1262
|
+
if (toolId === 'kma_current_observation') return 900
|
|
1263
|
+
if (toolId === 'kma_ultra_short_term_forecast') return 800
|
|
1264
|
+
if (toolId === 'kma_short_term_forecast') return 650
|
|
1265
|
+
if (LOCATION_TOOL_IDS.has(toolId)) return 260
|
|
330
1266
|
}
|
|
331
|
-
if (
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
'행정동코드',
|
|
341
|
-
'koroad',
|
|
342
|
-
'accident',
|
|
343
|
-
'hazard',
|
|
344
|
-
'hotspot',
|
|
345
|
-
]) {
|
|
346
|
-
tokens.add(token)
|
|
347
|
-
}
|
|
1267
|
+
if (intent.hasEmergencyMedical && intent.hasLocationAnchor) {
|
|
1268
|
+
if (toolId === 'nmc_emergency_search') return 1200
|
|
1269
|
+
if (toolId === 'nmc_aed_site_locate') return 950
|
|
1270
|
+
if (toolId === 'kakao_keyword_search') return 900
|
|
1271
|
+
if (toolId === 'kakao_address_search') return 800
|
|
1272
|
+
if (toolId === 'kakao_coord_to_region') return 500
|
|
1273
|
+
if (toolId === 'hira_hospital_search') return 250
|
|
1274
|
+
if (toolId === 'hira_medical_institution_detail') return 200
|
|
1275
|
+
if (LOCATION_TOOL_IDS.has(toolId)) return 300
|
|
348
1276
|
}
|
|
349
|
-
if (
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
1277
|
+
if (intent.hasWelfare && WELFARE_TOOL_IDS.has(toolId)) return 1000
|
|
1278
|
+
if (intent.hasUtility && UTILITY_TOOL_IDS.has(toolId)) return 1000
|
|
1279
|
+
if (intent.hasCivilDeath && CIVIL_DEATH_TOOL_IDS.has(toolId)) return 1000
|
|
1280
|
+
return 0
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
function koreanParticleStrippedVariants(token: string): string[] {
|
|
1284
|
+
if (!hasHangul(token)) return []
|
|
1285
|
+
const variants: string[] = []
|
|
1286
|
+
let current = token
|
|
1287
|
+
for (let i = 0; i < 2; i += 1) {
|
|
1288
|
+
const nextSuffix = KOREAN_TRAILING_PARTICLES.find(
|
|
1289
|
+
suffix => current.length > suffix.length + 1 && current.endsWith(suffix),
|
|
1290
|
+
)
|
|
1291
|
+
if (!nextSuffix) break
|
|
1292
|
+
current = current.slice(0, -nextSuffix.length)
|
|
1293
|
+
variants.push(current)
|
|
363
1294
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
'place',
|
|
374
|
-
]) {
|
|
375
|
-
tokens.add(token)
|
|
1295
|
+
return variants
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
function expandedTokensForText(text: string): Set<string> {
|
|
1299
|
+
const tokens = new Set<string>()
|
|
1300
|
+
for (const token of searchTokens(text)) {
|
|
1301
|
+
tokens.add(token)
|
|
1302
|
+
for (const variant of koreanParticleStrippedVariants(token)) {
|
|
1303
|
+
tokens.add(variant)
|
|
376
1304
|
}
|
|
377
1305
|
}
|
|
378
1306
|
return tokens
|
|
379
1307
|
}
|
|
380
1308
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
1309
|
+
function expandedQueryTokens(query: string): Set<string> {
|
|
1310
|
+
return expandedTokensForText(query)
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
function isUsefulDiscoveryToken(token: string): boolean {
|
|
1314
|
+
const compact = token.replace(/[_-]/gu, '')
|
|
1315
|
+
if (compact.length === 0) return false
|
|
1316
|
+
if (LOW_SIGNAL_DISCOVERY_TOKENS.has(token)) return false
|
|
1317
|
+
if (hasHangul(compact)) return compact.length >= 2
|
|
1318
|
+
if (compact === 'er') return true
|
|
1319
|
+
return compact.length >= 3
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
function isSingleHangulPlaceSuffixMatch(
|
|
1323
|
+
fieldToken: string,
|
|
1324
|
+
queryToken: string,
|
|
1325
|
+
): boolean {
|
|
1326
|
+
return (
|
|
1327
|
+
hasHangul(fieldToken) &&
|
|
1328
|
+
fieldToken.length === 1 &&
|
|
1329
|
+
hasHangul(queryToken) &&
|
|
1330
|
+
queryToken.length >= 3 &&
|
|
1331
|
+
queryToken.endsWith(fieldToken)
|
|
1332
|
+
)
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
function fieldMatchesToken(
|
|
1336
|
+
fieldTokens: Set<string>,
|
|
1337
|
+
fieldText: string,
|
|
1338
|
+
queryToken: string,
|
|
1339
|
+
): boolean {
|
|
1340
|
+
if (fieldTokens.has(queryToken) || fieldText.includes(queryToken)) {
|
|
1341
|
+
return true
|
|
1342
|
+
}
|
|
1343
|
+
if (!isUsefulDiscoveryToken(queryToken)) return false
|
|
1344
|
+
for (const fieldToken of fieldTokens) {
|
|
1345
|
+
if (isSingleHangulPlaceSuffixMatch(fieldToken, queryToken)) {
|
|
1346
|
+
return true
|
|
1347
|
+
}
|
|
1348
|
+
if (!isUsefulDiscoveryToken(fieldToken)) continue
|
|
1349
|
+
if (fieldToken.includes(queryToken) || queryToken.includes(fieldToken)) {
|
|
1350
|
+
return true
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
return false
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
function requiredInputFieldsFor(entry: AdapterManifestEntry): string[] {
|
|
1357
|
+
return asStringArray(asJsonObject(entry.input_schema_json).required)
|
|
384
1358
|
}
|
|
385
1359
|
|
|
386
|
-
function
|
|
387
|
-
return
|
|
1360
|
+
function isOpaqueProviderIdentifierField(fieldName: string): boolean {
|
|
1361
|
+
return (
|
|
1362
|
+
fieldName === 'ykiho' ||
|
|
1363
|
+
fieldName === 'id' ||
|
|
1364
|
+
fieldName.endsWith('_id')
|
|
1365
|
+
)
|
|
388
1366
|
}
|
|
389
1367
|
|
|
390
|
-
function
|
|
391
|
-
|
|
1368
|
+
function isOpaqueIdentifierOnlyInitialCandidate(
|
|
1369
|
+
entry: AdapterManifestEntry,
|
|
1370
|
+
queryTokens: Set<string>,
|
|
1371
|
+
query: string,
|
|
1372
|
+
): boolean {
|
|
1373
|
+
const requiredFields = requiredInputFieldsFor(entry)
|
|
1374
|
+
if (requiredFields.length === 0) return false
|
|
1375
|
+
if (!requiredFields.every(isOpaqueProviderIdentifierField)) return false
|
|
1376
|
+
|
|
1377
|
+
const normalizedQuery = query.toLowerCase()
|
|
1378
|
+
if (normalizedQuery.includes(entry.tool_id.toLowerCase())) return false
|
|
1379
|
+
return !requiredFields.some(fieldName => queryTokens.has(fieldName.toLowerCase()))
|
|
392
1380
|
}
|
|
393
1381
|
|
|
394
|
-
|
|
395
|
-
|
|
1382
|
+
type AdapterScore = {
|
|
1383
|
+
score: number
|
|
1384
|
+
qualifyingDiscoveryMatches: number
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
type ScoredAdapterEntry = {
|
|
1388
|
+
entry: AdapterManifestEntry
|
|
1389
|
+
score: number
|
|
396
1390
|
}
|
|
397
1391
|
|
|
398
1392
|
function scoreAdapterEntry(
|
|
399
1393
|
entry: AdapterManifestEntry,
|
|
400
1394
|
queryTokens: Set<string>,
|
|
401
1395
|
query: string,
|
|
402
|
-
):
|
|
1396
|
+
): AdapterScore {
|
|
1397
|
+
const toolId = entry.tool_id.toLowerCase()
|
|
1398
|
+
const name = entry.name.toLowerCase()
|
|
403
1399
|
const searchHint = entry.search_hint.toLowerCase()
|
|
404
1400
|
const description = (entry.llm_description ?? '').toLowerCase()
|
|
405
1401
|
const haystack = [
|
|
406
|
-
|
|
407
|
-
|
|
1402
|
+
toolId,
|
|
1403
|
+
name,
|
|
408
1404
|
entry.primitive,
|
|
409
1405
|
searchHint,
|
|
410
1406
|
description,
|
|
411
1407
|
].join(' ').toLowerCase()
|
|
412
|
-
const
|
|
1408
|
+
const toolIdTokens = expandedTokensForText(toolId)
|
|
1409
|
+
const nameTokens = expandedTokensForText(name)
|
|
1410
|
+
const hintTokens = expandedTokensForText(searchHint)
|
|
413
1411
|
let score = 0
|
|
1412
|
+
let qualifyingDiscoveryMatches = 0
|
|
414
1413
|
for (const token of queryTokens) {
|
|
415
1414
|
if (!token) continue
|
|
416
|
-
|
|
417
|
-
if (
|
|
418
|
-
|
|
1415
|
+
let matchedDiscovery = false
|
|
1416
|
+
if (fieldMatchesToken(toolIdTokens, toolId, token)) {
|
|
1417
|
+
score += 12
|
|
1418
|
+
matchedDiscovery = true
|
|
1419
|
+
}
|
|
1420
|
+
if (fieldMatchesToken(hintTokens, searchHint, token)) {
|
|
1421
|
+
score += 8
|
|
1422
|
+
matchedDiscovery = true
|
|
1423
|
+
}
|
|
1424
|
+
if (fieldMatchesToken(nameTokens, name, token)) {
|
|
1425
|
+
score += 4
|
|
1426
|
+
matchedDiscovery = true
|
|
1427
|
+
}
|
|
419
1428
|
if (description.includes(token)) score += 2
|
|
420
1429
|
if (haystack.includes(token)) score += 1
|
|
1430
|
+
if (matchedDiscovery && isUsefulDiscoveryToken(token)) {
|
|
1431
|
+
qualifyingDiscoveryMatches += 1
|
|
1432
|
+
}
|
|
421
1433
|
}
|
|
422
|
-
if (
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
) {
|
|
426
|
-
score = Math.max(0, score - 24)
|
|
427
|
-
}
|
|
428
|
-
if (queryTargetsKoroadHazardDataset(query)) {
|
|
429
|
-
if (entry.tool_id === 'koroad_accident_hazard_search') score += 32
|
|
430
|
-
if (entry.tool_id === 'koroad_accident_search') score = 0
|
|
1434
|
+
if (query.toLowerCase().includes(toolId)) {
|
|
1435
|
+
score += 1000
|
|
1436
|
+
qualifyingDiscoveryMatches += 1
|
|
431
1437
|
}
|
|
432
|
-
return score
|
|
1438
|
+
return { score, qualifyingDiscoveryMatches }
|
|
433
1439
|
}
|
|
434
1440
|
|
|
435
1441
|
export function selectTopKAdapterToolNamesForQuery(
|
|
436
1442
|
query: string,
|
|
437
1443
|
maxResults = 5,
|
|
1444
|
+
options: AdapterSelectionOptions = {},
|
|
438
1445
|
): string[] {
|
|
439
1446
|
const normalizedQuery = query.trim()
|
|
440
1447
|
if (!normalizedQuery || maxResults <= 0) return []
|
|
441
1448
|
const queryTokens = expandedQueryTokens(normalizedQuery)
|
|
1449
|
+
const routingIntent = extractProviderRoutingIntent(normalizedQuery)
|
|
1450
|
+
const restrictiveToolIds = restrictiveToolIdsForIntent(routingIntent, options)
|
|
442
1451
|
const ranked = listAdapters()
|
|
443
1452
|
.filter(entry => !ROOT_PRIMITIVE_TOOL_NAMES.has(entry.tool_id))
|
|
444
|
-
.map(entry =>
|
|
445
|
-
entry,
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
1453
|
+
.map(entry => {
|
|
1454
|
+
const result = scoreAdapterEntry(entry, queryTokens, normalizedQuery)
|
|
1455
|
+
const routingBoost = routingIntentBoostForTool(entry.tool_id, routingIntent)
|
|
1456
|
+
return {
|
|
1457
|
+
entry,
|
|
1458
|
+
score: result.score + routingBoost,
|
|
1459
|
+
qualifyingDiscoveryMatches:
|
|
1460
|
+
result.qualifyingDiscoveryMatches + (routingBoost > 0 ? 1 : 0),
|
|
1461
|
+
}
|
|
1462
|
+
})
|
|
1463
|
+
.filter(candidate =>
|
|
1464
|
+
(restrictiveToolIds === undefined ||
|
|
1465
|
+
restrictiveToolIds.has(candidate.entry.tool_id)) &&
|
|
1466
|
+
candidate.score > 0 &&
|
|
1467
|
+
candidate.qualifyingDiscoveryMatches > 0 &&
|
|
1468
|
+
!isOpaqueIdentifierOnlyInitialCandidate(
|
|
1469
|
+
candidate.entry,
|
|
1470
|
+
queryTokens,
|
|
1471
|
+
normalizedQuery,
|
|
1472
|
+
)
|
|
1473
|
+
)
|
|
449
1474
|
.sort((a, b) => {
|
|
450
1475
|
if (b.score !== a.score) return b.score - a.score
|
|
451
1476
|
return a.entry.tool_id.localeCompare(b.entry.tool_id)
|
|
@@ -486,6 +1511,8 @@ function buildAdapterTool(entry: AdapterManifestEntry): Tool {
|
|
|
486
1511
|
const primitiveTool = primitiveToolFor(primitive)
|
|
487
1512
|
const adapterInputSchema = inputSchemaFor(entry)
|
|
488
1513
|
const adapterInputJSONSchema = inputJSONSchemaFor(entry)
|
|
1514
|
+
const directCheckAdapterRequiresPermission =
|
|
1515
|
+
primitive === 'check' && !ROOT_PRIMITIVE_TOOL_NAMES.has(entry.tool_id)
|
|
489
1516
|
|
|
490
1517
|
return buildTool({
|
|
491
1518
|
name: entry.tool_id,
|
|
@@ -516,13 +1543,19 @@ function buildAdapterTool(entry: AdapterManifestEntry): Tool {
|
|
|
516
1543
|
},
|
|
517
1544
|
|
|
518
1545
|
isReadOnly(input) {
|
|
1546
|
+
if (directCheckAdapterRequiresPermission) return false
|
|
519
1547
|
return primitiveTool.isReadOnly(rootInputFor(entry, input))
|
|
520
1548
|
},
|
|
521
1549
|
|
|
522
1550
|
isDestructive(input) {
|
|
1551
|
+
if (directCheckAdapterRequiresPermission) return true
|
|
523
1552
|
return primitiveTool.isDestructive?.(rootInputFor(entry, input)) ?? false
|
|
524
1553
|
},
|
|
525
1554
|
|
|
1555
|
+
async checkPermissions(input, context) {
|
|
1556
|
+
return primitiveTool.checkPermissions(rootInputFor(entry, input), context)
|
|
1557
|
+
},
|
|
1558
|
+
|
|
526
1559
|
async description() {
|
|
527
1560
|
return entry.name
|
|
528
1561
|
},
|
|
@@ -536,7 +1569,7 @@ function buildAdapterTool(entry: AdapterManifestEntry): Tool {
|
|
|
536
1569
|
].join('\n\n')
|
|
537
1570
|
},
|
|
538
1571
|
|
|
539
|
-
async validateInput(input) {
|
|
1572
|
+
async validateInput(input, context) {
|
|
540
1573
|
if (!resolveAdapter(entry.tool_id)) {
|
|
541
1574
|
return {
|
|
542
1575
|
result: false as const,
|
|
@@ -551,29 +1584,64 @@ function buildAdapterTool(entry: AdapterManifestEntry): Tool {
|
|
|
551
1584
|
errorCode: 1,
|
|
552
1585
|
}
|
|
553
1586
|
}
|
|
1587
|
+
const contractInput = validateAdapterContractInput(
|
|
1588
|
+
entry.tool_id,
|
|
1589
|
+
input as Record<string, unknown>,
|
|
1590
|
+
)
|
|
1591
|
+
if (contractInput) return contractInput
|
|
554
1592
|
return { result: true as const }
|
|
555
1593
|
},
|
|
556
1594
|
|
|
557
1595
|
async call(input, context) {
|
|
558
|
-
|
|
1596
|
+
const normalizedDocumentInput = normalizeExplicitDocumentArtifactInput(
|
|
1597
|
+
entry.tool_id,
|
|
1598
|
+
input,
|
|
1599
|
+
context.messages,
|
|
1600
|
+
)
|
|
1601
|
+
const adapterCallInput = concreteAdapterCallInputFor(
|
|
1602
|
+
entry,
|
|
1603
|
+
normalizedDocumentInput,
|
|
1604
|
+
)
|
|
1605
|
+
const result = await dispatchPrimitive({
|
|
559
1606
|
primitive,
|
|
560
1607
|
toolName: entry.tool_id,
|
|
561
|
-
args:
|
|
1608
|
+
args: adapterCallInput,
|
|
562
1609
|
context,
|
|
563
1610
|
registry: getOrCreatePendingCallRegistry(),
|
|
564
1611
|
bridge: getOrCreateUmmayaBridge(),
|
|
1612
|
+
timeoutMs:
|
|
1613
|
+
primitive === 'document'
|
|
1614
|
+
? resolveDocumentPrimitiveTimeoutMs()
|
|
1615
|
+
: undefined,
|
|
565
1616
|
})
|
|
1617
|
+
return {
|
|
1618
|
+
...result,
|
|
1619
|
+
data: applyDocumentVisualRenderGateToOutput(result.data),
|
|
1620
|
+
}
|
|
566
1621
|
},
|
|
567
1622
|
|
|
568
1623
|
userFacingName(input) {
|
|
1624
|
+
if (DOCUMENT_TOOL_NAMES.has(entry.tool_id)) {
|
|
1625
|
+
return 'Document'
|
|
1626
|
+
}
|
|
569
1627
|
return primitiveTool.userFacingName(rootInputFor(entry, input ?? {}))
|
|
570
1628
|
},
|
|
571
1629
|
|
|
572
1630
|
mapToolResultToToolResultBlockParam(output, toolUseID) {
|
|
573
|
-
|
|
1631
|
+
const gatedOutput = applyDocumentVisualRenderGateToOutput(output)
|
|
1632
|
+
const block = primitiveTool.mapToolResultToToolResultBlockParam(gatedOutput, toolUseID)
|
|
1633
|
+
return isDocumentVisualRenderFailedOutput(gatedOutput)
|
|
1634
|
+
? { ...block, is_error: true }
|
|
1635
|
+
: block
|
|
574
1636
|
},
|
|
575
1637
|
|
|
576
1638
|
renderToolUseMessage(input, options) {
|
|
1639
|
+
if (DOCUMENT_TOOL_NAMES.has(entry.tool_id)) {
|
|
1640
|
+
return renderDocumentToolUseMessage(
|
|
1641
|
+
entry.tool_id,
|
|
1642
|
+
input as Record<string, unknown>,
|
|
1643
|
+
)
|
|
1644
|
+
}
|
|
577
1645
|
const rendered = primitiveTool.renderToolUseMessage(
|
|
578
1646
|
rootInputFor(entry, input),
|
|
579
1647
|
options,
|
|
@@ -582,8 +1650,16 @@ function buildAdapterTool(entry: AdapterManifestEntry): Tool {
|
|
|
582
1650
|
},
|
|
583
1651
|
|
|
584
1652
|
renderToolResultMessage(output, progressMessagesForMessage, options) {
|
|
1653
|
+
const gatedOutput = applyDocumentVisualRenderGateToOutput(output)
|
|
1654
|
+
if (shouldHideSuccessfulIntermediateDocumentResult(gatedOutput)) {
|
|
1655
|
+
return null
|
|
1656
|
+
}
|
|
1657
|
+
const documentResult = renderDocumentToolResultIfPresent(gatedOutput, options)
|
|
1658
|
+
if (documentResult !== null) {
|
|
1659
|
+
return documentResult
|
|
1660
|
+
}
|
|
585
1661
|
return primitiveTool.renderToolResultMessage?.(
|
|
586
|
-
|
|
1662
|
+
gatedOutput,
|
|
587
1663
|
progressMessagesForMessage,
|
|
588
1664
|
options,
|
|
589
1665
|
) ?? null
|