ummaya 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -3
- package/bin/ummaya +10 -1
- package/npm-shrinkwrap.json +253 -2
- package/package.json +5 -1
- package/prompts/manifest.yaml +2 -2
- package/prompts/session_guidance_v1.md +3 -1
- package/prompts/system_v1.md +9 -7
- package/pyproject.toml +26 -7
- package/specs/2803-document-production-hardening/contracts/document-tools.schema.json +1043 -0
- package/src/ummaya/_canonical/__init__.py +2 -0
- package/src/ummaya/context/builder.py +17 -11
- package/src/ummaya/engine/engine.py +30 -113
- package/src/ummaya/engine/query.py +20 -0
- package/src/ummaya/evidence/__init__.py +44 -0
- package/src/ummaya/evidence/__main__.py +7 -0
- package/src/ummaya/evidence/dataset_contract.py +193 -0
- package/src/ummaya/evidence/document_authoring_cases.py +33 -0
- package/src/ummaya/evidence/document_harness.py +313 -0
- package/src/ummaya/evidence/document_viewer_ux.py +391 -0
- package/src/ummaya/evidence/gates.py +70 -0
- package/src/ummaya/evidence/json_types.py +20 -0
- package/src/ummaya/evidence/models.py +145 -0
- package/src/ummaya/evidence/output_payload.py +89 -0
- package/src/ummaya/evidence/payload_documents.py +233 -0
- package/src/ummaya/evidence/route_contracts.py +224 -0
- package/src/ummaya/evidence/route_helpers.py +150 -0
- package/src/ummaya/evidence/runner.py +177 -0
- package/src/ummaya/evidence/source_provenance.py +246 -0
- package/src/ummaya/evidence/source_provenance_redaction.py +176 -0
- package/src/ummaya/evidence/task_registry.py +264 -0
- package/src/ummaya/evidence/tool_layer.py +39 -0
- package/src/ummaya/evidence/tool_layer_models.py +151 -0
- package/src/ummaya/ipc/adapter_manifest_emitter.py +26 -10
- package/src/ummaya/ipc/document_intent_normalization.py +185 -0
- package/src/ummaya/ipc/frame_schema.py +52 -5
- package/src/ummaya/ipc/route_diagnostics.py +73 -0
- package/src/ummaya/ipc/stdio.py +2282 -417
- package/src/ummaya/llm/client.py +234 -59
- package/src/ummaya/llm/config.py +8 -3
- package/src/ummaya/llm/reasoning.py +84 -0
- package/src/ummaya/primitives/__init__.py +6 -2
- package/src/ummaya/primitives/delegation.py +1 -1
- package/src/ummaya/primitives/document.py +28 -0
- package/src/ummaya/settings.py +0 -3
- package/src/ummaya/tools/discovery_bridge.py +34 -2
- package/src/ummaya/tools/documents/__init__.py +297 -0
- package/src/ummaya/tools/documents/adapter_registry.py +487 -0
- package/src/ummaya/tools/documents/archive_container_probe.py +167 -0
- package/src/ummaya/tools/documents/artifact_store.py +454 -0
- package/src/ummaya/tools/documents/authoring.py +283 -0
- package/src/ummaya/tools/documents/baselines.py +114 -0
- package/src/ummaya/tools/documents/capability.py +331 -0
- package/src/ummaya/tools/documents/contracts.py +112 -0
- package/src/ummaya/tools/documents/conversion.py +521 -0
- package/src/ummaya/tools/documents/diff.py +275 -0
- package/src/ummaya/tools/documents/engines.py +163 -0
- package/src/ummaya/tools/documents/evaluation.py +291 -0
- package/src/ummaya/tools/documents/explicit_values.py +108 -0
- package/src/ummaya/tools/documents/fixtures.py +174 -0
- package/src/ummaya/tools/documents/format_completion_audit.py +471 -0
- package/src/ummaya/tools/documents/formats/__init__.py +2 -0
- package/src/ummaya/tools/documents/formats/archive.py +528 -0
- package/src/ummaya/tools/documents/formats/base.py +41 -0
- package/src/ummaya/tools/documents/formats/code_file.py +211 -0
- package/src/ummaya/tools/documents/formats/data_file.py +272 -0
- package/src/ummaya/tools/documents/formats/hwp.py +284 -0
- package/src/ummaya/tools/documents/formats/hwpx.py +1837 -0
- package/src/ummaya/tools/documents/formats/odf.py +435 -0
- package/src/ummaya/tools/documents/formats/ooxml.py +1030 -0
- package/src/ummaya/tools/documents/formats/passive.py +766 -0
- package/src/ummaya/tools/documents/formats/pdf.py +702 -0
- package/src/ummaya/tools/documents/formats/text_web.py +268 -0
- package/src/ummaya/tools/documents/hwp_conversion_probe.py +178 -0
- package/src/ummaya/tools/documents/hwp_direct_candidate.py +141 -0
- package/src/ummaya/tools/documents/inspection.py +289 -0
- package/src/ummaya/tools/documents/intake.py +1079 -0
- package/src/ummaya/tools/documents/legacy_office_promotion_probe.py +366 -0
- package/src/ummaya/tools/documents/models.py +1598 -0
- package/src/ummaya/tools/documents/odf_promotion_probe.py +167 -0
- package/src/ummaya/tools/documents/orchestrator.py +96 -0
- package/src/ummaya/tools/documents/passive_capability_probe.py +251 -0
- package/src/ummaya/tools/documents/patch.py +170 -0
- package/src/ummaya/tools/documents/pdfa_conformance.py +284 -0
- package/src/ummaya/tools/documents/pdfa_promotion_probe.py +198 -0
- package/src/ummaya/tools/documents/permissions.py +110 -0
- package/src/ummaya/tools/documents/planner.py +616 -0
- package/src/ummaya/tools/documents/registry.py +2733 -0
- package/src/ummaya/tools/documents/render.py +978 -0
- package/src/ummaya/tools/documents/render_comparison.py +113 -0
- package/src/ummaya/tools/documents/render_comparison_models.py +74 -0
- package/src/ummaya/tools/documents/render_comparison_regions.py +73 -0
- package/src/ummaya/tools/documents/render_comparison_style.py +161 -0
- package/src/ummaya/tools/documents/reread.py +157 -0
- package/src/ummaya/tools/documents/runtime_authoring.py +244 -0
- package/src/ummaya/tools/documents/runtime_authoring_bundle.py +76 -0
- package/src/ummaya/tools/documents/scorecard.py +184 -0
- package/src/ummaya/tools/documents/socratic_planner.py +193 -0
- package/src/ummaya/tools/documents/style.py +48 -0
- package/src/ummaya/tools/documents/tool_defs.py +523 -0
- package/src/ummaya/tools/documents/validate.py +347 -0
- package/src/ummaya/tools/executor.py +61 -12
- package/src/ummaya/tools/geocoding/kakao_client.py +1 -2
- package/src/ummaya/tools/kma/apihub_catalog.py +984 -1
- package/src/ummaya/tools/kma/apihub_structured_adapter.py +86 -6
- package/src/ummaya/tools/kma/apihub_url_adapter.py +593 -0
- package/src/ummaya/tools/kma/apihub_url_catalog.py +296 -0
- package/src/ummaya/tools/live_proxy.py +0 -3
- package/src/ummaya/tools/location_adapters.py +8 -6
- package/src/ummaya/tools/manifest_metadata.py +16 -3
- package/src/ummaya/tools/models.py +5 -1
- package/src/ummaya/tools/mvp_surface.py +2 -2
- package/src/ummaya/tools/nmc/emergency_search.py +8 -6
- package/src/ummaya/tools/register_all.py +17 -0
- package/src/ummaya/tools/registry.py +10 -1
- package/src/ummaya/tools/resolve_location.py +4 -4
- package/src/ummaya/tools/routing/__init__.py +59 -0
- package/src/ummaya/tools/routing/builder.py +105 -0
- package/src/ummaya/tools/routing/cards.py +29 -0
- package/src/ummaya/tools/routing/decision_service.py +534 -0
- package/src/ummaya/tools/routing/decision_types.py +74 -0
- package/src/ummaya/tools/routing/feasibility.py +122 -0
- package/src/ummaya/tools/routing/intent.py +17 -0
- package/src/ummaya/tools/routing/intent_extractor.py +207 -0
- package/src/ummaya/tools/routing/intent_patterns.py +160 -0
- package/src/ummaya/tools/routing/intent_public_data.py +150 -0
- package/src/ummaya/tools/routing/intent_types.py +48 -0
- package/src/ummaya/tools/routing/lint.py +78 -0
- package/src/ummaya/tools/routing/metadata.py +174 -0
- package/src/ummaya/tools/routing/projection.py +340 -0
- package/src/ummaya/tools/routing/retrieval_policy.py +629 -0
- package/src/ummaya/tools/routing/schema.py +81 -0
- package/src/ummaya/tools/routing/types.py +96 -0
- package/src/ummaya/tools/routing_index.py +2 -2
- package/src/ummaya/tools/search.py +40 -106
- package/src/ummaya/tools/verified_data_go_kr/_manifest.py +115 -25
- package/src/ummaya/tools/verified_data_go_kr/airkorea_air_quality.py +109 -4
- package/src/ummaya/tools/verified_data_go_kr/nmc_aed_site.py +108 -2
- package/src/ummaya/tools/verified_data_go_kr/pps_bid_public_info.py +174 -9
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_arrival.py +66 -3
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_location.py +12 -2
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_route.py +8 -2
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_route_station.py +114 -0
- package/src/ummaya/tools/verified_data_go_kr/tago_bus_station.py +14 -3
- package/src/ummaya/tools/verify_canonical_map.py +21 -0
- package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
- package/tui/package.json +1 -2
- package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
- package/tui/src/QueryEngine.ts +12 -4
- package/tui/src/bridge/inboundAttachments.ts +3 -3
- package/tui/src/cli/handlers/auth.ts +4 -13
- package/tui/src/cli/handlers/mcp.tsx +3 -3
- package/tui/src/cli/print.ts +69 -18
- package/tui/src/cli/update.ts +13 -13
- package/tui/src/commands/copy/index.ts +1 -1
- package/tui/src/commands/cost/cost.ts +2 -2
- package/tui/src/commands/init-verifiers.ts +5 -5
- package/tui/src/commands/init.ts +30 -30
- package/tui/src/commands/insights.ts +44 -44
- package/tui/src/commands/install-github-app/install-github-app.tsx +2 -2
- package/tui/src/commands/install-github-app/setupGitHubActions.ts +3 -3
- package/tui/src/commands/install-github-app/types.ts +8 -30
- package/tui/src/commands/install.tsx +5 -5
- package/tui/src/commands/mcp/addCommand.ts +5 -5
- package/tui/src/commands/mcp/xaaIdpCommand.ts +2 -2
- package/tui/src/commands/plugin/ManageMarketplaces.tsx +2 -2
- package/tui/src/commands/plugin/types.ts +6 -28
- package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
- package/tui/src/commands/reasoning/index.ts +13 -0
- package/tui/src/commands/reasoning/reasoning.tsx +177 -0
- package/tui/src/commands/rename/generateSessionName.ts +1 -1
- package/tui/src/commands/thinkback/thinkback.tsx +3 -3
- package/tui/src/commands.ts +2 -0
- package/tui/src/components/Feedback.tsx +1 -1
- package/tui/src/components/LogoV2/EmergencyTip.tsx +11 -2
- package/tui/src/components/LogoV2/WelcomeV2.tsx +1 -3
- package/tui/src/components/Messages.tsx +2 -1
- package/tui/src/components/ScrollKeybindingHandler.tsx +6 -6
- package/tui/src/components/Spinner/types.ts +6 -28
- package/tui/src/components/Spinner.tsx +2 -2
- package/tui/src/components/agents/generateAgent.ts +1 -1
- package/tui/src/components/agents/new-agent-creation/types.ts +4 -26
- package/tui/src/components/config/EnvSecretIsolatedEditor.tsx +1 -1
- package/tui/src/components/design-system/LoadingState.tsx +2 -2
- package/tui/src/components/mcp/types.ts +16 -38
- package/tui/src/components/messages/AssistantToolUseMessage.tsx +3 -2
- package/tui/src/components/messages/UserCrossSessionMessage.ts +16 -4
- package/tui/src/components/messages/UserForkBoilerplateMessage.ts +16 -4
- package/tui/src/components/messages/UserGitHubWebhookMessage.ts +16 -4
- package/tui/src/components/messages/UserToolResultMessage/utils.tsx +3 -2
- package/tui/src/components/permissions/MonitorPermissionRequest/MonitorPermissionRequest.ts +9 -4
- package/tui/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.ts +9 -4
- package/tui/src/components/primitive/DocumentSocraticReviewBlock.tsx +129 -0
- package/tui/src/components/primitive/DocumentToolResultCard.tsx +224 -0
- package/tui/src/components/primitive/documentSocraticReview.ts +215 -0
- package/tui/src/components/primitive/index.tsx +43 -1
- package/tui/src/components/primitive/types.ts +137 -0
- package/tui/src/components/ui/option.ts +4 -26
- package/tui/src/constants/common.ts +0 -2
- package/tui/src/constants/prompts.ts +4 -3
- package/tui/src/constants/querySource.ts +4 -26
- package/tui/src/entrypoints/sdk/controlTypes.ts +26 -48
- package/tui/src/entrypoints/sdk/coreTypes.generated.ts +3 -25
- package/tui/src/entrypoints/sdk/runtimeTypes.ts +38 -60
- package/tui/src/entrypoints/sdk/sdkUtilityTypes.ts +4 -26
- package/tui/src/entrypoints/sdk/settingsTypes.generated.ts +3 -25
- package/tui/src/entrypoints/sdk/toolTypes.ts +3 -25
- package/tui/src/hooks/toolPermission/handlers/interactiveHandler.ts +10 -0
- package/tui/src/hooks/useApiKeyVerification.ts +1 -1
- package/tui/src/hooks/useVirtualScroll.ts +1 -1
- package/tui/src/ink/ink.tsx +33 -14
- package/tui/src/ink/reconciler.ts +2 -3
- package/tui/src/ink/render-to-screen.ts +30 -10
- package/tui/src/ipc/bridge.ts +62 -15
- package/tui/src/ipc/bridgeSingleton.ts +5 -1
- package/tui/src/ipc/codec.ts +29 -3
- package/tui/src/ipc/frames.generated.ts +407 -312
- package/tui/src/ipc/llmClient.ts +279 -76
- package/tui/src/ipc/llmTypes.ts +16 -1
- package/tui/src/ipc/schema/frame.schema.json +1 -3475
- package/tui/src/keybindings/defaultBindings.ts +4 -0
- package/tui/src/main.tsx +32 -11
- package/tui/src/native-ts/file-index/index.ts +33 -3
- package/tui/src/observability/surface.ts +2 -2
- package/tui/src/probes/toolRegistryProbe.tsx +3 -1
- package/tui/src/projectOnboardingState.ts +7 -6
- package/tui/src/query/chatMessageTypes.ts +18 -0
- package/tui/src/query/chatMessagesBuilder.ts +1 -1
- package/tui/src/query/deps.ts +1 -1
- package/tui/src/query/messageGuards.ts +106 -0
- package/tui/src/query/publicDataTerminalRepair.ts +384 -0
- package/tui/src/query/run.ts +1075 -0
- package/tui/src/query/supportBoundary.ts +168 -0
- package/tui/src/query/toolResultErrors.ts +103 -0
- package/tui/src/query/toolRunner.ts +687 -0
- package/tui/src/query/unavailableToolRepair.ts +118 -0
- package/tui/src/query.ts +9 -1721
- package/tui/src/screens/REPL.tsx +42 -31
- package/tui/src/services/api/adapterManifest.ts +4 -0
- package/tui/src/services/api/backendChat/events.ts +117 -0
- package/tui/src/services/api/backendChat/finalMessage.ts +40 -0
- package/tui/src/services/api/backendChat/frame.ts +9 -0
- package/tui/src/services/api/backendChat/streaming.ts +430 -0
- package/tui/src/services/api/backendChat/types.ts +62 -0
- package/tui/src/services/api/backendChat.ts +1 -0
- package/tui/src/services/api/client.ts +98 -14
- package/tui/src/services/api/errorUtils.ts +5 -5
- package/tui/src/services/api/errors.ts +1 -1
- package/tui/src/services/api/logging.ts +1 -1
- package/tui/src/services/api/ummaya/evidence.ts +194 -0
- package/tui/src/services/api/ummaya/messages.ts +255 -0
- package/tui/src/services/api/ummaya/nonStreaming.ts +66 -0
- package/tui/src/services/api/ummaya/provider.ts +200 -0
- package/tui/src/services/api/ummaya/reasoning.ts +24 -0
- package/tui/src/services/api/ummaya/request.ts +200 -0
- package/tui/src/services/api/ummaya/selectionContext.ts +240 -0
- package/tui/src/services/api/ummaya/streaming.ts +365 -0
- package/tui/src/services/api/ummaya/streamingPayload.ts +129 -0
- package/tui/src/services/api/ummaya/streamingReader.ts +40 -0
- package/tui/src/services/api/ummaya/toolSelection.ts +217 -0
- package/tui/src/services/api/ummaya/types.ts +110 -0
- package/tui/src/services/api/ummaya/usage.ts +30 -0
- package/tui/src/services/api/ummaya.ts +26 -364
- package/tui/src/services/api/withRetry.ts +1 -1
- package/tui/src/services/awaySummary.ts +2 -2
- package/tui/src/services/claudeAiLimits.ts +1 -1
- package/tui/src/services/compact/autoCompact.ts +1 -1
- package/tui/src/services/compact/compact.ts +1 -1
- package/tui/src/services/lsp/types.ts +8 -30
- package/tui/src/services/tips/types.ts +6 -28
- package/tui/src/services/tokenEstimation.ts +1 -1
- package/tui/src/services/toolRegistry/bootGuard.ts +5 -5
- package/tui/src/services/toolUseSummary/toolUseSummaryGenerator.ts +1 -1
- package/tui/src/services/tools/toolExecution.ts +94 -1
- package/tui/src/skills/bundled/stuck.ts +12 -12
- package/tui/src/state/AppStateStore.ts +7 -0
- package/tui/src/store/pendingPermissionSlot.ts +1 -1
- package/tui/src/store/session-store.ts +10 -36
- package/tui/src/stubs/any-stub.ts +15 -10
- package/tui/src/stubs/color-diff-napi.ts +37 -23
- package/tui/src/stubs/globals.d.ts +3 -3
- package/tui/src/stubs/macro-preload.ts +23 -12
- package/tui/src/tools/AdapterTool/AdapterTool.ts +1239 -163
- package/tui/src/tools/AdapterTool/routeDiagnostics.ts +75 -0
- package/tui/src/tools/AgentTool/AgentTool.tsx +84 -1371
- package/tui/src/tools/AgentTool/agentToolHandoff.ts +114 -0
- package/tui/src/tools/AgentTool/agentToolPartialResult.ts +16 -0
- package/tui/src/tools/AgentTool/agentToolProgress.ts +32 -0
- package/tui/src/tools/AgentTool/agentToolResolver.ts +161 -0
- package/tui/src/tools/AgentTool/agentToolResult.ts +163 -0
- package/tui/src/tools/AgentTool/agentToolUtils.ts +14 -686
- package/tui/src/tools/AgentTool/asyncAgentLifecycle.ts +208 -0
- package/tui/src/tools/AgentTool/asyncLifecycle.ts +153 -0
- package/tui/src/tools/AgentTool/backgroundedCompletion.ts +126 -0
- package/tui/src/tools/AgentTool/backgroundedLifecycle.ts +174 -0
- package/tui/src/tools/AgentTool/foregroundBackground.ts +83 -0
- package/tui/src/tools/AgentTool/foregroundDrain.tsx +133 -0
- package/tui/src/tools/AgentTool/foregroundFinalize.ts +98 -0
- package/tui/src/tools/AgentTool/foregroundLifecycle.tsx +237 -0
- package/tui/src/tools/AgentTool/foregroundProgress.tsx +169 -0
- package/tui/src/tools/AgentTool/foregroundTask.ts +89 -0
- package/tui/src/tools/AgentTool/forkSubagent.ts +1 -12
- package/tui/src/tools/AgentTool/forkSubagentGate.ts +34 -0
- package/tui/src/tools/AgentTool/launchRouting.ts +203 -0
- package/tui/src/tools/AgentTool/lifecycle.ts +244 -0
- package/tui/src/tools/AgentTool/mcpRouting.ts +73 -0
- package/tui/src/tools/AgentTool/orchestrationSupport.ts +70 -0
- package/tui/src/tools/AgentTool/permissions.ts +39 -0
- package/tui/src/tools/AgentTool/promptSetup.ts +181 -0
- package/tui/src/tools/AgentTool/remoteRouting.ts +62 -0
- package/tui/src/tools/AgentTool/resultMapping.ts +116 -0
- package/tui/src/tools/AgentTool/resumeAgent.ts +39 -107
- package/tui/src/tools/AgentTool/resumeAgentHelpers.ts +140 -0
- package/tui/src/tools/AgentTool/runAgent.ts +1 -1
- package/tui/src/tools/AgentTool/runtimeConfig.ts +57 -0
- package/tui/src/tools/AgentTool/schemas.ts +196 -0
- package/tui/src/tools/AgentTool/sourceVerificationPropagation.ts +263 -0
- package/tui/src/tools/AgentTool/worktreeLifecycle.ts +105 -0
- package/tui/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +174 -202
- package/tui/src/tools/BashTool/BashTool.tsx +71 -1072
- package/tui/src/tools/BashTool/bashCommandHelpers.ts +12 -12
- package/tui/src/tools/BashTool/bashPermissions/astPreflight.ts +173 -0
- package/tui/src/tools/BashTool/bashPermissions/classifierChecks.ts +199 -0
- package/tui/src/tools/BashTool/bashPermissions/compoundGuards.ts +53 -0
- package/tui/src/tools/BashTool/bashPermissions/constants.ts +99 -0
- package/tui/src/tools/BashTool/bashPermissions/index.ts +38 -0
- package/tui/src/tools/BashTool/bashPermissions/legacyMisparsing.ts +62 -0
- package/tui/src/tools/BashTool/bashPermissions/main.ts +135 -0
- package/tui/src/tools/BashTool/bashPermissions/normalizedCommands.ts +33 -0
- package/tui/src/tools/BashTool/bashPermissions/operatorFlow.ts +98 -0
- package/tui/src/tools/BashTool/bashPermissions/permissionChecks.ts +200 -0
- package/tui/src/tools/BashTool/bashPermissions/prefixSuggestions.ts +88 -0
- package/tui/src/tools/BashTool/bashPermissions/promptClassifierRules.ts +125 -0
- package/tui/src/tools/BashTool/bashPermissions/ruleDelegates.ts +19 -0
- package/tui/src/tools/BashTool/bashPermissions/ruleMatching.ts +145 -0
- package/tui/src/tools/BashTool/bashPermissions/sandboxAutoAllow.ts +75 -0
- package/tui/src/tools/BashTool/bashPermissions/subcommandFlow.ts +205 -0
- package/tui/src/tools/BashTool/bashPermissions/subcommandGuards.ts +73 -0
- package/tui/src/tools/BashTool/bashPermissions/subcommandResultHelpers.ts +116 -0
- package/tui/src/tools/BashTool/bashPermissions/types.ts +26 -0
- package/tui/src/tools/BashTool/bashPermissions/wrapperStripping.ts +139 -0
- package/tui/src/tools/BashTool/bashPermissions.ts +26 -2621
- package/tui/src/tools/BashTool/call.ts +202 -0
- package/tui/src/tools/BashTool/callLoader.ts +35 -0
- package/tui/src/tools/BashTool/commandClassification.ts +151 -0
- package/tui/src/tools/BashTool/commandClassificationLoader.ts +40 -0
- package/tui/src/tools/BashTool/cwdReset.ts +33 -0
- package/tui/src/tools/BashTool/lineTruncation.ts +11 -0
- package/tui/src/tools/BashTool/modeValidation.ts +13 -1
- package/tui/src/tools/BashTool/outputPersistence.ts +42 -0
- package/tui/src/tools/BashTool/permissionClassification.ts +66 -0
- package/tui/src/tools/BashTool/permissionLoader.ts +44 -0
- package/tui/src/tools/BashTool/resultLoader.ts +29 -0
- package/tui/src/tools/BashTool/resultMapping.ts +83 -0
- package/tui/src/tools/BashTool/sandboxPolicy.ts +79 -0
- package/tui/src/tools/BashTool/schemas.ts +65 -0
- package/tui/src/tools/BashTool/sedEditExecution.ts +59 -0
- package/tui/src/tools/BashTool/shellExecution.tsx +245 -0
- package/tui/src/tools/BashTool/shellOutputUtils.ts +85 -0
- package/tui/src/tools/BashTool/shellPermissionGauntlet.ts +97 -0
- package/tui/src/tools/BashTool/uiLoader.ts +37 -0
- package/tui/src/tools/BriefTool/upload.ts +1 -1
- package/tui/src/tools/CalculatorTool/parser.ts +2 -2
- package/tui/src/tools/DocumentPrimitive/DocumentPrimitive.ts +262 -0
- package/tui/src/tools/DocumentPrimitive/dispatchNormalization.ts +270 -0
- package/tui/src/tools/DocumentPrimitive/documentDestinationPath.ts +18 -0
- package/tui/src/tools/DocumentPrimitive/documentMutationGuard.ts +22 -0
- package/tui/src/tools/DocumentPrimitive/documentPatchNormalization.ts +248 -0
- package/tui/src/tools/DocumentPrimitive/documentSourceVerification.ts +245 -0
- package/tui/src/tools/DocumentPrimitive/documentSourceVerificationFields.ts +103 -0
- package/tui/src/tools/DocumentPrimitive/modelVisibleOutput.ts +40 -0
- package/tui/src/tools/DocumentPrimitive/prompt.ts +35 -0
- package/tui/src/tools/FileEditTool/FileEditTool.ts +9 -507
- package/tui/src/tools/FileEditTool/call.ts +228 -0
- package/tui/src/tools/FileEditTool/validateInput.ts +196 -0
- package/tui/src/tools/FileReadTool/imageProcessor.ts +13 -0
- package/tui/src/tools/FileWriteTool/FileWriteTool.ts +7 -300
- package/tui/src/tools/FileWriteTool/call.ts +223 -0
- package/tui/src/tools/FileWriteTool/validateInput.ts +80 -0
- package/tui/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +19 -3
- package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +48 -29
- package/tui/src/tools/LookupPrimitive/prompt.ts +6 -7
- package/tui/src/tools/MCPTool/trustPolicy.ts +118 -0
- package/tui/src/tools/McpAuthTool/McpAuthTool.ts +21 -3
- package/tui/src/tools/NotebookEditTool/NotebookEditTool.ts +7 -326
- package/tui/src/tools/NotebookEditTool/call.ts +254 -0
- package/tui/src/tools/NotebookEditTool/notebookModel.ts +51 -0
- package/tui/src/tools/NotebookEditTool/validateInput.ts +142 -0
- package/tui/src/tools/PowerShellTool/PowerShellTool.tsx +46 -937
- package/tui/src/tools/PowerShellTool/acceptEditsCommandValidation.ts +162 -0
- package/tui/src/tools/PowerShellTool/call.ts +179 -0
- package/tui/src/tools/PowerShellTool/callLoader.ts +37 -0
- package/tui/src/tools/PowerShellTool/commandClassification.ts +86 -0
- package/tui/src/tools/PowerShellTool/modeValidation.ts +25 -332
- package/tui/src/tools/PowerShellTool/outputPersistence.ts +42 -0
- package/tui/src/tools/PowerShellTool/permissionClassification.ts +28 -0
- package/tui/src/tools/PowerShellTool/resultLoader.ts +31 -0
- package/tui/src/tools/PowerShellTool/resultMapping.ts +75 -0
- package/tui/src/tools/PowerShellTool/schemas.ts +40 -0
- package/tui/src/tools/PowerShellTool/shellExecution.tsx +258 -0
- package/tui/src/tools/PowerShellTool/symlinkModeValidation.ts +44 -0
- package/tui/src/tools/PowerShellTool/uiLoader.ts +37 -0
- package/tui/src/tools/PowerShellTool/validation.ts +39 -0
- package/tui/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +19 -3
- package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +30 -19
- package/tui/src/tools/ResolveLocationPrimitive/prompt.ts +2 -6
- package/tui/src/tools/SkillTool/SkillTool.ts +2 -2
- package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +51 -18
- package/tui/src/tools/TaskCreateTool/TaskCreateTool.ts +16 -2
- package/tui/src/tools/TaskGetTool/TaskGetTool.ts +23 -3
- package/tui/src/tools/TaskListTool/TaskListTool.ts +22 -4
- package/tui/src/tools/TaskOutputTool/TaskOutputTool.tsx +46 -547
- package/tui/src/tools/TaskOutputTool/lookup.ts +216 -0
- package/tui/src/tools/TaskOutputTool/render.tsx +257 -0
- package/tui/src/tools/TaskOutputTool/schemas.ts +55 -0
- package/tui/src/tools/TaskOutputTool/serialization.ts +36 -0
- package/tui/src/tools/TaskStopTool/TaskStopTool.ts +10 -0
- package/tui/src/tools/TaskUpdateTool/TaskUpdateTool.ts +14 -364
- package/tui/src/tools/TaskUpdateTool/completion.ts +62 -0
- package/tui/src/tools/TaskUpdateTool/schemas.ts +62 -0
- package/tui/src/tools/TaskUpdateTool/serialization.ts +46 -0
- package/tui/src/tools/TaskUpdateTool/statusUpdate.ts +247 -0
- package/tui/src/tools/TodoWriteTool/TodoWriteTool.ts +21 -2
- package/tui/src/tools/ToolSearchTool/ToolSearchTool.ts +21 -302
- package/tui/src/tools/ToolSearchTool/ccSupportTools.ts +223 -0
- package/tui/src/tools/ToolSearchTool/descriptionCache.ts +50 -0
- package/tui/src/tools/ToolSearchTool/keywordSearch.ts +216 -0
- package/tui/src/tools/ToolSearchTool/prompt.ts +10 -4
- package/tui/src/tools/ToolSearchTool/resultMapping.ts +30 -0
- package/tui/src/tools/ToolSearchTool/schemas.ts +30 -0
- package/tui/src/tools/ToolSearchTool/searchPool.ts +47 -0
- package/tui/src/tools/ToolSearchTool/supportIntentHints.ts +140 -0
- package/tui/src/tools/TranslateTool/TranslateTool.ts +1 -1
- package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +27 -10
- package/tui/src/tools/WebFetchTool/WebFetchTool.ts +43 -138
- package/tui/src/tools/WebFetchTool/call.ts +227 -0
- package/tui/src/tools/WebFetchTool/resolvedAddressSafety.ts +78 -0
- package/tui/src/tools/WebFetchTool/sourceVerification.ts +204 -0
- package/tui/src/tools/WebFetchTool/types.ts +23 -0
- package/tui/src/tools/WebFetchTool/urlSafety.ts +181 -0
- package/tui/src/tools/WebFetchTool/utils.ts +1 -1
- package/tui/src/tools/WebSearchTool/UI.tsx +0 -1
- package/tui/src/tools/WebSearchTool/WebSearchTool.ts +9 -313
- package/tui/src/tools/WebSearchTool/call.ts +33 -0
- package/tui/src/tools/WebSearchTool/responseMapping.ts +190 -0
- package/tui/src/tools/WebSearchTool/resultBlock.ts +47 -0
- package/tui/src/tools/WebSearchTool/schemas.ts +47 -0
- package/tui/src/tools/WebSearchTool/toolSchema.ts +12 -0
- package/tui/src/tools/WorkspaceToolAdapter/WorkspaceToolAdapter.ts +79 -0
- package/tui/src/tools/WorkspaceToolAdapter/allowedRootPolicy.ts +85 -0
- package/tui/src/tools/WorkspaceToolAdapter/documentFormatGuards.ts +73 -0
- package/tui/src/tools/WorkspaceToolAdapter/inputNormalization.ts +105 -0
- package/tui/src/tools/WorkspaceToolAdapter/mcpExposurePolicy.ts +64 -0
- package/tui/src/tools/WorkspaceToolAdapter/toolDefFactory.ts +215 -0
- package/tui/src/tools/WorkspaceToolAdapter/toolNames.ts +6 -0
- package/tui/src/tools/WorkspaceToolAdapter/workspacePolicy.ts +15 -0
- package/tui/src/tools/_shared/citizenUserText.ts +49 -0
- package/tui/src/tools/_shared/dispatchPrimitive.ts +6 -6
- package/tui/src/tools/_shared/documentChangeToPatch.ts +125 -0
- package/tui/src/tools/_shared/documentDispatchArguments.ts +87 -0
- package/tui/src/tools/_shared/documentPrimitiveTimeout.ts +13 -0
- package/tui/src/tools/_shared/documentToolResultRender.ts +98 -0
- package/tui/src/tools/_shared/locationInputRepair.ts +112 -0
- package/tui/src/tools/_shared/pendingCallRegistry.ts +1 -6
- package/tui/src/tools/_shared/rootPrimitiveInput.ts +68 -0
- package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPatterns.ts +58 -0
- package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPrompt.ts +271 -0
- package/tui/src/tools/_shared/toolChoiceRepair/documentRepair.ts +452 -0
- package/tui/src/tools/_shared/toolChoiceRepair/messageAccess.ts +80 -0
- package/tui/src/tools/_shared/toolChoiceRepair/publicDataRepair.ts +92 -0
- package/tui/src/tools/_shared/toolChoiceRepair/supportRepair.ts +135 -0
- package/tui/src/tools/_shared/toolChoiceRepair.ts +61 -0
- package/tui/src/tools/shared/mockDisclaimer.ts +1 -1
- package/tui/src/tools.ts +39 -190
- package/tui/src/types/fileSuggestion.ts +4 -26
- package/tui/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +186 -148
- package/tui/src/types/generated/events_mono/common/v1/auth.ts +25 -11
- package/tui/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +47 -30
- package/tui/src/types/generated/google/protobuf/timestamp.ts +21 -7
- package/tui/src/types/message.ts +80 -102
- package/tui/src/types/messageQueueTypes.ts +6 -28
- package/tui/src/types/notebook.ts +16 -38
- package/tui/src/types/statusLine.ts +4 -26
- package/tui/src/types/tools.ts +24 -46
- package/tui/src/types/utils.ts +6 -28
- package/tui/src/upstreamproxy/relay.ts +7 -3
- package/tui/src/upstreamproxy/upstreamproxy.ts +1 -1
- package/tui/src/utils/assistantMessageFactories.ts +9 -3
- package/tui/src/utils/attachments.ts +1 -1
- package/tui/src/utils/auth.ts +129 -139
- package/tui/src/utils/bash/ast.ts +23 -23
- package/tui/src/utils/bash/bashParser.ts +5 -5
- package/tui/src/utils/billing.ts +1 -1
- package/tui/src/utils/collapseReadSearch.ts +3 -3
- package/tui/src/utils/cronTasks.ts +1 -1
- package/tui/src/utils/execFileNoThrow.ts +1 -1
- package/tui/src/utils/filePersistence/types.ts +16 -38
- package/tui/src/utils/forkedAgent.ts +1 -1
- package/tui/src/utils/gracefulShutdown.ts +4 -4
- package/tui/src/utils/heapDumpService.ts +12 -8
- package/tui/src/utils/hooks/apiQueryHookHelper.ts +1 -1
- package/tui/src/utils/hooks/execPromptHook.ts +1 -1
- package/tui/src/utils/hooks/skillImprovement.ts +1 -1
- package/tui/src/utils/kExaoneReasoning.ts +138 -0
- package/tui/src/utils/mcp/dateTimeParser.ts +1 -1
- package/tui/src/utils/messages.ts +19 -0
- package/tui/src/utils/migrateSessions.ts +3 -3
- package/tui/src/utils/model/model.ts +6 -6
- package/tui/src/utils/multiToolLayout.ts +13 -0
- package/tui/src/utils/permissions/yoloClassifier.ts +1 -1
- package/tui/src/utils/plugins/headlessPluginInstall.ts +1 -1
- package/tui/src/utils/plugins/mcpPluginIntegration.ts +1 -1
- package/tui/src/utils/plugins/mcpbHandler.ts +1 -1
- package/tui/src/utils/plugins/pluginLoader.ts +8 -8
- package/tui/src/utils/processUserInput/processSlashCommand.tsx +2 -2
- package/tui/src/utils/processUserInput/processUserInput.ts +26 -0
- package/tui/src/utils/protectedNamespace.ts +5 -3
- package/tui/src/utils/rawJsonToolCall.ts +242 -0
- package/tui/src/utils/ripgrep.ts +16 -7
- package/tui/src/utils/sessionTitle.ts +1 -1
- package/tui/src/utils/settings/applySettingsChange.ts +4 -0
- package/tui/src/utils/settings/permissionValidation.ts +14 -2
- package/tui/src/utils/settings/types.ts +9 -3
- package/tui/src/utils/shell/prefix.ts +1 -1
- package/tui/src/utils/sideQuery.ts +1 -1
- package/tui/src/utils/stats.ts +1 -1
- package/tui/src/utils/systemThemeWatcher.ts +13 -3
- package/tui/src/utils/teleport.tsx +1 -1
- package/uv.lock +394 -22
- package/assets/copilot-gate-logo.svg +0 -58
- package/assets/govon-logo.svg +0 -40
- package/src/ummaya/eval/__init__.py +0 -5
- package/src/ummaya/eval/retrieval.py +0 -713
- package/tui/src/services/api/claude.ts +0 -3510
- package/tui/src/utils/messageStream.ts +0 -186
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Wrappers for KMA APIHub non-structured URL operations."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
from datetime import UTC, datetime
|
|
10
|
+
from functools import cache
|
|
11
|
+
from typing import Literal, cast
|
|
12
|
+
|
|
13
|
+
import httpx
|
|
14
|
+
from pydantic import BaseModel, ConfigDict, Field, create_model
|
|
15
|
+
|
|
16
|
+
from ummaya.tools._outbound_trace import traced_async_client
|
|
17
|
+
from ummaya.tools.errors import ConfigurationError, ToolExecutionError
|
|
18
|
+
from ummaya.tools.executor import AdapterFn, ToolExecutor
|
|
19
|
+
from ummaya.tools.kma.apihub_endpoint import (
|
|
20
|
+
KMA_API_HUB_AUTH_KEY_ENV,
|
|
21
|
+
KMA_API_HUB_BASE_URL,
|
|
22
|
+
)
|
|
23
|
+
from ummaya.tools.kma.apihub_url_catalog import (
|
|
24
|
+
KmaApiHubUrlOperation,
|
|
25
|
+
KmaApiHubUrlScalar,
|
|
26
|
+
get_url_operation_by_id,
|
|
27
|
+
iter_url_operations,
|
|
28
|
+
)
|
|
29
|
+
from ummaya.tools.kma.response_payload import summarize_http_status_error
|
|
30
|
+
from ummaya.tools.models import AdapterRealDomainPolicy, GovAPITool
|
|
31
|
+
from ummaya.tools.registry import ToolRegistry
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
type KmaApiHubUrlQueryValue = str | int | float | bool
|
|
36
|
+
|
|
37
|
+
_MAX_RAW_TEXT_CHARS = 64_000
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class KmaApiHubUrlOutput(BaseModel):
|
|
41
|
+
"""Normalized output from one KMA APIHub non-structured URL operation."""
|
|
42
|
+
|
|
43
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
44
|
+
|
|
45
|
+
operation_id: str
|
|
46
|
+
endpoint_path: str
|
|
47
|
+
approval_state: Literal["approved", "approval_pending"]
|
|
48
|
+
content_type: str
|
|
49
|
+
raw_format: Literal["text", "json", "image", "binary"]
|
|
50
|
+
line_count: int | None = None
|
|
51
|
+
summary: dict[str, object] | None = None
|
|
52
|
+
raw_text: str | None = None
|
|
53
|
+
status_code: int
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
_MISSING_TEXT_VALUES = frozenset({"-99999", "-9999", "-999", ""})
|
|
57
|
+
_METAR_AIRPORT_STATIONS: dict[str, dict[str, str]] = {
|
|
58
|
+
"92": {"airport_name_ko": "양양공항", "airport_name_en": "Yangyang Airport", "icao": "RKNY"},
|
|
59
|
+
"110": {"airport_name_ko": "김포공항", "airport_name_en": "Gimpo Airport", "icao": "RKSS"},
|
|
60
|
+
"113": {"airport_name_ko": "인천공항", "airport_name_en": "Incheon Airport", "icao": "RKSI"},
|
|
61
|
+
"128": {"airport_name_ko": "청주공항", "airport_name_en": "Cheongju Airport", "icao": "RKTU"},
|
|
62
|
+
"139": {
|
|
63
|
+
"airport_name_ko": "포항경주공항",
|
|
64
|
+
"airport_name_en": "Pohang Gyeongju Airport",
|
|
65
|
+
"icao": "RKTH",
|
|
66
|
+
},
|
|
67
|
+
"142": {"airport_name_ko": "대구공항", "airport_name_en": "Daegu Airport", "icao": "RKTN"},
|
|
68
|
+
"151": {"airport_name_ko": "울산공항", "airport_name_en": "Ulsan Airport", "icao": "RKPU"},
|
|
69
|
+
"153": {"airport_name_ko": "김해공항", "airport_name_en": "Gimhae Airport", "icao": "RKPK"},
|
|
70
|
+
"158": {"airport_name_ko": "광주공항", "airport_name_en": "Gwangju Airport", "icao": "RKJJ"},
|
|
71
|
+
"161": {"airport_name_ko": "사천공항", "airport_name_en": "Sacheon Airport", "icao": "RKPS"},
|
|
72
|
+
"163": {"airport_name_ko": "무안공항", "airport_name_en": "Muan Airport", "icao": "RKJB"},
|
|
73
|
+
"167": {"airport_name_ko": "여수공항", "airport_name_en": "Yeosu Airport", "icao": "RKJY"},
|
|
74
|
+
"182": {"airport_name_ko": "제주공항", "airport_name_en": "Jeju Airport", "icao": "RKPC"},
|
|
75
|
+
}
|
|
76
|
+
_METAR_STATION_REFERENCE_SOURCE = (
|
|
77
|
+
"Airport station names come from KMA APIHub SfcYearlyInfoService/getrAirStnLstTbl "
|
|
78
|
+
"direct probe for 2024; ICAO codes come from the official AmmIwxxmService/getMetar examples."
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _field_type(param_type: str, required: bool) -> object:
|
|
83
|
+
if param_type == "integer":
|
|
84
|
+
return int if required else int | None
|
|
85
|
+
if param_type == "number":
|
|
86
|
+
return float if required else float | None
|
|
87
|
+
if param_type == "boolean":
|
|
88
|
+
return bool if required else bool | None
|
|
89
|
+
return str if required else str | None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _model_name(operation: KmaApiHubUrlOperation) -> str:
|
|
93
|
+
return (
|
|
94
|
+
"KmaApiHubUrl"
|
|
95
|
+
+ "".join(part.title() for part in operation.operation_id.split("_") if part)
|
|
96
|
+
+ "Input"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
_FIELD_PATTERNS: dict[str, str] = {
|
|
101
|
+
"tm": r"^\d{12}$",
|
|
102
|
+
"tm1": r"^\d{12}$",
|
|
103
|
+
"tm2": r"^\d{12}$",
|
|
104
|
+
"analTime": r"^\d{12}$",
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_FIELD_DESCRIPTIONS: dict[tuple[str, str], str] = {
|
|
108
|
+
(
|
|
109
|
+
"air_metar_decoded",
|
|
110
|
+
"tm",
|
|
111
|
+
): (
|
|
112
|
+
"METAR decoded-data lookup time in UTC, YYYYMMDDHHMM. Omit it to "
|
|
113
|
+
"request the latest upstream slot."
|
|
114
|
+
),
|
|
115
|
+
(
|
|
116
|
+
"air_metar_decoded",
|
|
117
|
+
"org",
|
|
118
|
+
): (
|
|
119
|
+
"METAR issuing organization. Use K for the official KMA decoded-data "
|
|
120
|
+
"product unless the citizen names another official source. The normalized "
|
|
121
|
+
"summary annotates known KMA airport station numbers such as 153 Gimhae/RKPK."
|
|
122
|
+
),
|
|
123
|
+
(
|
|
124
|
+
"air_metar_decoded",
|
|
125
|
+
"help",
|
|
126
|
+
): "Set 1 to include KMA field-help lines in the raw text; set 0 for compact decoded records.",
|
|
127
|
+
(
|
|
128
|
+
"air_amos_minute",
|
|
129
|
+
"stn",
|
|
130
|
+
): (
|
|
131
|
+
"Official AMOS station number. The APIHub page lists 110 Gimpo, "
|
|
132
|
+
"113 Incheon, 182 Jeju, 163 Muan, 151 Ulsan, 167 Yeosu, and "
|
|
133
|
+
"92 Yangyang. Gimhae is not listed for this AMOS endpoint; use "
|
|
134
|
+
"METAR RKPK for Gimhae airport aviation weather."
|
|
135
|
+
),
|
|
136
|
+
(
|
|
137
|
+
"air_amos_minute",
|
|
138
|
+
"tm",
|
|
139
|
+
): "AMOS lookup time in KST, YYYYMMDDHHMM. Omit it to request the latest upstream slot.",
|
|
140
|
+
(
|
|
141
|
+
"air_amos_minute",
|
|
142
|
+
"dtm",
|
|
143
|
+
): "Lookback window in minutes including tm. Official maximum is 60 minutes.",
|
|
144
|
+
(
|
|
145
|
+
"high_resolution_grid_point",
|
|
146
|
+
"obs",
|
|
147
|
+
): (
|
|
148
|
+
"Comma-separated high-resolution grid elements, for example "
|
|
149
|
+
"ta,td,hm,ws_10m,wd_10m,vs,rn_60m."
|
|
150
|
+
),
|
|
151
|
+
(
|
|
152
|
+
"high_resolution_grid_point",
|
|
153
|
+
"tm1",
|
|
154
|
+
): "Start time in KST, YYYYMMDDHHMM. Omit it to request the latest upstream slot.",
|
|
155
|
+
(
|
|
156
|
+
"high_resolution_grid_point",
|
|
157
|
+
"tm2",
|
|
158
|
+
): "End time in KST, YYYYMMDDHHMM. Official maximum range is 60 minutes.",
|
|
159
|
+
("high_resolution_grid_point", "lat"): "WGS-84 latitude for the point lookup.",
|
|
160
|
+
("high_resolution_grid_point", "lon"): "WGS-84 longitude for the point lookup.",
|
|
161
|
+
(
|
|
162
|
+
"aws_objective_analysis_grid",
|
|
163
|
+
"obj",
|
|
164
|
+
): "Objective-analysis method: mq for Multi Quadric or bn for Barnes.",
|
|
165
|
+
(
|
|
166
|
+
"analysis_weather_chart_image",
|
|
167
|
+
"analTime",
|
|
168
|
+
): (
|
|
169
|
+
"KMA analyzed weather-chart time in UTC, YYYYMMDDHHMM. Include minutes; "
|
|
170
|
+
"do not pass a 10-digit KST hour. For now/today requests, use the latest "
|
|
171
|
+
"completed official UTC analysis slot before the citizen's local time."
|
|
172
|
+
),
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _field_description(operation: KmaApiHubUrlOperation, param_name: str) -> str:
|
|
177
|
+
base = _FIELD_DESCRIPTIONS.get(
|
|
178
|
+
(operation.operation_id, param_name),
|
|
179
|
+
f"KMA APIHub URL request parameter {param_name}.",
|
|
180
|
+
)
|
|
181
|
+
return f"{base} Official parameter name: {param_name}. Operation: {operation.operation_id}."
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _field_default(param_default: KmaApiHubUrlScalar, required: bool) -> object:
|
|
185
|
+
if required and param_default is None:
|
|
186
|
+
return ...
|
|
187
|
+
return param_default
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@cache
|
|
191
|
+
def input_schema_for(operation_id: str) -> type[BaseModel]:
|
|
192
|
+
"""Build the Pydantic input model for one URL operation."""
|
|
193
|
+
operation = get_url_operation_by_id(operation_id)
|
|
194
|
+
fields: dict[str, tuple[object, object]] = {}
|
|
195
|
+
for param in operation.non_credential_params:
|
|
196
|
+
default = _field_default(param.default, param.required)
|
|
197
|
+
pattern = _FIELD_PATTERNS.get(param.name)
|
|
198
|
+
field = (
|
|
199
|
+
Field(
|
|
200
|
+
default,
|
|
201
|
+
description=_field_description(operation, param.name),
|
|
202
|
+
pattern=pattern,
|
|
203
|
+
)
|
|
204
|
+
if pattern is not None
|
|
205
|
+
else Field(default, description=_field_description(operation, param.name))
|
|
206
|
+
)
|
|
207
|
+
fields[param.field_name] = (_field_type(param.value_type, param.required), field)
|
|
208
|
+
|
|
209
|
+
model = create_model( # type: ignore[call-overload]
|
|
210
|
+
_model_name(operation),
|
|
211
|
+
__config__=ConfigDict(frozen=True, extra="forbid"),
|
|
212
|
+
**fields,
|
|
213
|
+
)
|
|
214
|
+
return cast(type[BaseModel], model)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _search_hint(operation: KmaApiHubUrlOperation) -> str:
|
|
218
|
+
return (
|
|
219
|
+
f"KMA APIHub 기상청 {operation.category_name_ko} {operation.title_ko} "
|
|
220
|
+
f"{operation.operation_id} {operation.search_keywords}"
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _llm_description(operation: KmaApiHubUrlOperation) -> str:
|
|
225
|
+
visible_params = ", ".join(param.field_name for param in operation.non_credential_params)
|
|
226
|
+
approval = (
|
|
227
|
+
"Direct curl verification on 2026-05-26 returned APIHub utilization "
|
|
228
|
+
"approval required for this runtime key; fail closed and cite the "
|
|
229
|
+
"official APIHub channel if upstream returns 403."
|
|
230
|
+
if operation.approval_state == "approval_pending"
|
|
231
|
+
else "This operation is approved for live APIHub use with the runtime key."
|
|
232
|
+
)
|
|
233
|
+
return (
|
|
234
|
+
f"KMA APIHub non-structured URL operation {operation.operation_id}. "
|
|
235
|
+
f"Category: {operation.category_name_ko}. Purpose: {operation.purpose} "
|
|
236
|
+
f"Selection rule: {operation.selection_rule} Approval: {approval} "
|
|
237
|
+
f"Input fields: {visible_params}. Credential handling: UMMAYA runtime "
|
|
238
|
+
"supplies authKey from UMMAYA_KMA_API_HUB_AUTH_KEY; the model must "
|
|
239
|
+
"never provide authKey."
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _query_params(
|
|
244
|
+
operation: KmaApiHubUrlOperation,
|
|
245
|
+
params: BaseModel,
|
|
246
|
+
) -> dict[str, KmaApiHubUrlQueryValue]:
|
|
247
|
+
values = params.model_dump(mode="python")
|
|
248
|
+
query: dict[str, KmaApiHubUrlQueryValue] = {}
|
|
249
|
+
for param in operation.non_credential_params:
|
|
250
|
+
value = values.get(param.field_name)
|
|
251
|
+
if value is None:
|
|
252
|
+
continue
|
|
253
|
+
if not isinstance(value, (str, int, float, bool)):
|
|
254
|
+
value = str(value)
|
|
255
|
+
query[param.name] = value
|
|
256
|
+
return query
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _api_key() -> str:
|
|
260
|
+
value = os.environ.get(KMA_API_HUB_AUTH_KEY_ENV, "").strip()
|
|
261
|
+
if not value:
|
|
262
|
+
raise ConfigurationError(KMA_API_HUB_AUTH_KEY_ENV)
|
|
263
|
+
return value
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _url(operation: KmaApiHubUrlOperation) -> str:
|
|
267
|
+
return f"{KMA_API_HUB_BASE_URL}{operation.endpoint_path}"
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _raw_format(
|
|
271
|
+
operation: KmaApiHubUrlOperation,
|
|
272
|
+
response: httpx.Response,
|
|
273
|
+
) -> Literal["text", "json", "image", "binary"]:
|
|
274
|
+
content_type = response.headers.get("content-type", "").lower()
|
|
275
|
+
if "json" in content_type:
|
|
276
|
+
return "json"
|
|
277
|
+
if "text" in content_type or "xml" in content_type or "csv" in content_type:
|
|
278
|
+
return "text"
|
|
279
|
+
if "image" in content_type or operation.response_kind == "image":
|
|
280
|
+
return "image"
|
|
281
|
+
if operation.response_kind == "text":
|
|
282
|
+
return "text"
|
|
283
|
+
return "binary"
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _text_data_lines(raw_text: str) -> list[list[str]]:
|
|
287
|
+
rows: list[list[str]] = []
|
|
288
|
+
for line in raw_text.splitlines():
|
|
289
|
+
stripped = line.strip()
|
|
290
|
+
if not stripped or stripped.startswith("#"):
|
|
291
|
+
continue
|
|
292
|
+
rows.append(stripped.split())
|
|
293
|
+
return rows
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def _int_cell(fields: list[str], index: int) -> int | None:
|
|
297
|
+
if index >= len(fields):
|
|
298
|
+
return None
|
|
299
|
+
value = fields[index]
|
|
300
|
+
if value in _MISSING_TEXT_VALUES:
|
|
301
|
+
return None
|
|
302
|
+
try:
|
|
303
|
+
return int(value)
|
|
304
|
+
except ValueError:
|
|
305
|
+
return None
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def _scaled_cell(fields: list[str], index: int, denominator: float) -> float | None:
|
|
309
|
+
value = _int_cell(fields, index)
|
|
310
|
+
if value is None:
|
|
311
|
+
return None
|
|
312
|
+
return round(value / denominator, 1)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def _slp_hpa(raw_code: str) -> float | None:
|
|
316
|
+
if not re.fullmatch(r"\d{3}", raw_code):
|
|
317
|
+
return None
|
|
318
|
+
value = int(raw_code)
|
|
319
|
+
base = 900.0 if value >= 500 else 1000.0
|
|
320
|
+
return round(base + (value / 10.0), 1)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def _wind_cardinal(direction_deg: int) -> dict[str, str]:
|
|
324
|
+
labels: tuple[tuple[str, str], ...] = (
|
|
325
|
+
("N", "북풍"),
|
|
326
|
+
("NNE", "북북동풍"),
|
|
327
|
+
("NE", "북동풍"),
|
|
328
|
+
("ENE", "동북동풍"),
|
|
329
|
+
("E", "동풍"),
|
|
330
|
+
("ESE", "동남동풍"),
|
|
331
|
+
("SE", "남동풍"),
|
|
332
|
+
("SSE", "남남동풍"),
|
|
333
|
+
("S", "남풍"),
|
|
334
|
+
("SSW", "남남서풍"),
|
|
335
|
+
("SW", "남서풍"),
|
|
336
|
+
("WSW", "서남서풍"),
|
|
337
|
+
("W", "서풍"),
|
|
338
|
+
("WNW", "서북서풍"),
|
|
339
|
+
("NW", "북서풍"),
|
|
340
|
+
("NNW", "북북서풍"),
|
|
341
|
+
)
|
|
342
|
+
index = round((direction_deg % 360) / 22.5) % len(labels)
|
|
343
|
+
en, ko = labels[index]
|
|
344
|
+
return {"en": en, "ko": ko}
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def _first_metar_visibility(fields: list[str]) -> int | None:
|
|
348
|
+
for value in fields[1:]:
|
|
349
|
+
if re.fullmatch(r"\d{4,5}", value) and value != "99999":
|
|
350
|
+
return int(value)
|
|
351
|
+
return None
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _metar_safe_weather(fields: list[str], raw_report: str) -> dict[str, object]:
|
|
355
|
+
safe_weather: dict[str, object] = {
|
|
356
|
+
"wind": None,
|
|
357
|
+
"visibility_m": _first_metar_visibility(fields),
|
|
358
|
+
"rvr_m": None,
|
|
359
|
+
"ceiling": None,
|
|
360
|
+
"sea_level_pressure_hpa": None,
|
|
361
|
+
}
|
|
362
|
+
if fields:
|
|
363
|
+
wind = fields[0]
|
|
364
|
+
if re.fullmatch(r"\d{5}", wind):
|
|
365
|
+
direction_deg = int(wind[0:3])
|
|
366
|
+
cardinal = _wind_cardinal(direction_deg)
|
|
367
|
+
speed_kt = int(wind[3:5])
|
|
368
|
+
safe_weather["wind"] = {
|
|
369
|
+
"raw": wind,
|
|
370
|
+
"direction_deg": direction_deg,
|
|
371
|
+
"direction_from_cardinal_en": cardinal["en"],
|
|
372
|
+
"direction_from_cardinal_ko": cardinal["ko"],
|
|
373
|
+
"speed_kt": speed_kt,
|
|
374
|
+
"speed_mps": round(speed_kt * 0.514444, 1),
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if rvr_match := re.search(r"\bR\d{2}[LRC]?/(\d{4})", raw_report):
|
|
378
|
+
safe_weather["rvr_m"] = int(rvr_match.group(1))
|
|
379
|
+
if ceiling_match := re.search(r"\bCIG(\d{3})\b", raw_report):
|
|
380
|
+
ceiling_raw = f"CIG{ceiling_match.group(1)}"
|
|
381
|
+
safe_weather["ceiling"] = {
|
|
382
|
+
"raw": ceiling_raw,
|
|
383
|
+
"height_ft": int(ceiling_match.group(1)) * 100,
|
|
384
|
+
}
|
|
385
|
+
if slp_match := re.search(r"\bSLP(\d{3})\b", raw_report):
|
|
386
|
+
safe_weather["sea_level_pressure_hpa"] = _slp_hpa(slp_match.group(1))
|
|
387
|
+
|
|
388
|
+
return safe_weather
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _latest_amos_summary(raw_text: str) -> dict[str, object] | None:
|
|
392
|
+
rows = [row for row in _text_data_lines(raw_text) if len(row) >= 27]
|
|
393
|
+
if not rows:
|
|
394
|
+
return None
|
|
395
|
+
latest = rows[-1]
|
|
396
|
+
return {
|
|
397
|
+
"latest_observation": {
|
|
398
|
+
"station": latest[0],
|
|
399
|
+
"observed_at": latest[1],
|
|
400
|
+
"left_visibility_m": _int_cell(latest, 2),
|
|
401
|
+
"right_visibility_m": _int_cell(latest, 3),
|
|
402
|
+
"left_rvr_m": _int_cell(latest, 4),
|
|
403
|
+
"right_rvr_m": _int_cell(latest, 5),
|
|
404
|
+
"cloud_height_min_m": _int_cell(latest, 6),
|
|
405
|
+
"temperature_c": _scaled_cell(latest, 7, 10.0),
|
|
406
|
+
"dew_point_c": _scaled_cell(latest, 8, 10.0),
|
|
407
|
+
"humidity_percent": _int_cell(latest, 9),
|
|
408
|
+
"qff_hpa": _scaled_cell(latest, 10, 10.0),
|
|
409
|
+
"qfe_hpa": _scaled_cell(latest, 11, 10.0),
|
|
410
|
+
"rain_mm": _scaled_cell(latest, 12, 10.0),
|
|
411
|
+
"wind_2min_direction_deg": _int_cell(latest, 15),
|
|
412
|
+
"wind_2min_speed_mps": _scaled_cell(latest, 18, 10.0),
|
|
413
|
+
"wind_10min_direction_deg": _int_cell(latest, 21),
|
|
414
|
+
"wind_10min_speed_mps": _scaled_cell(latest, 24, 10.0),
|
|
415
|
+
},
|
|
416
|
+
"unit_notes": {
|
|
417
|
+
"temperature_c": "TA and TD are converted from official 0.1C units.",
|
|
418
|
+
"pressure_hpa": "PS/QFF and PA/QFE are converted from official 0.1hPa units.",
|
|
419
|
+
"wind_speed_mps": "WS02 and WS10 are converted from official 0.1m/s units.",
|
|
420
|
+
"sentinel": "-99999 values are omitted as null.",
|
|
421
|
+
},
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def _metar_decoded_summary(raw_text: str) -> dict[str, object] | None:
|
|
426
|
+
records: list[dict[str, object]] = []
|
|
427
|
+
for line in raw_text.splitlines():
|
|
428
|
+
stripped = line.strip()
|
|
429
|
+
if not stripped.startswith(("METAR", "SPECI")):
|
|
430
|
+
continue
|
|
431
|
+
report_type, _, payload = stripped.partition(" ")
|
|
432
|
+
parts = payload.strip().split("#")
|
|
433
|
+
if len(parts) < 4:
|
|
434
|
+
continue
|
|
435
|
+
station_number = parts[1]
|
|
436
|
+
record: dict[str, object] = {
|
|
437
|
+
"report_type": report_type,
|
|
438
|
+
"station_number": station_number,
|
|
439
|
+
"observed_at": parts[2],
|
|
440
|
+
"raw_fields": parts[3:],
|
|
441
|
+
"raw_report": stripped,
|
|
442
|
+
"safe_weather": _metar_safe_weather(parts[3:], stripped),
|
|
443
|
+
}
|
|
444
|
+
station = _METAR_AIRPORT_STATIONS.get(station_number)
|
|
445
|
+
if station is not None:
|
|
446
|
+
record["station"] = station
|
|
447
|
+
records.append(record)
|
|
448
|
+
if not records:
|
|
449
|
+
return None
|
|
450
|
+
return {
|
|
451
|
+
"decoded_records": records,
|
|
452
|
+
"interpretation_warning": (
|
|
453
|
+
"Use only decoded_records[].safe_weather for weather values. raw_fields "
|
|
454
|
+
"and raw_report are provenance text, not a model-readable schema; do not "
|
|
455
|
+
"derive pressure, wind, cloud, runway, or temperature values from raw_fields."
|
|
456
|
+
),
|
|
457
|
+
"station_reference_source": _METAR_STATION_REFERENCE_SOURCE,
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def _summary_for_operation(
|
|
462
|
+
operation: KmaApiHubUrlOperation,
|
|
463
|
+
raw_text: str | None,
|
|
464
|
+
) -> dict[str, object] | None:
|
|
465
|
+
if raw_text is None:
|
|
466
|
+
return None
|
|
467
|
+
if operation.operation_id == "air_amos_minute":
|
|
468
|
+
return _latest_amos_summary(raw_text)
|
|
469
|
+
if operation.operation_id == "air_metar_decoded":
|
|
470
|
+
return _metar_decoded_summary(raw_text)
|
|
471
|
+
return None
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def _status_error_message(operation: KmaApiHubUrlOperation, exc: httpx.HTTPStatusError) -> str:
|
|
475
|
+
base = f"HTTP error from KMA APIHub URL operation: {summarize_http_status_error(exc)}"
|
|
476
|
+
if operation.operation_id == "air_amos_minute" and exc.response.status_code == 404:
|
|
477
|
+
return (
|
|
478
|
+
f"{base}. Official KMA APIHub AMOS upstream returned 404 Not Found for "
|
|
479
|
+
"the documented AMOS URL product in this run. Preserve this as an "
|
|
480
|
+
"upstream AMOS failure in the final answer; do not invent runway-area "
|
|
481
|
+
"values. If the citizen needs airport aviation weather and a METAR "
|
|
482
|
+
"candidate/result is available, explain that METAR is the fallback "
|
|
483
|
+
"evidence source."
|
|
484
|
+
)
|
|
485
|
+
if exc.response.status_code != 403:
|
|
486
|
+
return base
|
|
487
|
+
if operation.approval_state != "approval_pending":
|
|
488
|
+
return base
|
|
489
|
+
return (
|
|
490
|
+
f"{base}. APIHub utilization approval is required for "
|
|
491
|
+
f"{operation.operation_id!r}; direct curl verification on 2026-05-26 "
|
|
492
|
+
"observed this endpoint returning the agency approval-required response."
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
async def call_operation(
|
|
497
|
+
operation: KmaApiHubUrlOperation,
|
|
498
|
+
params: BaseModel,
|
|
499
|
+
*,
|
|
500
|
+
client: httpx.AsyncClient | None = None,
|
|
501
|
+
) -> KmaApiHubUrlOutput:
|
|
502
|
+
"""Call one non-structured KMA APIHub URL operation."""
|
|
503
|
+
query_params = _query_params(operation, params)
|
|
504
|
+
query_params["authKey"] = _api_key()
|
|
505
|
+
|
|
506
|
+
own_client = client is None
|
|
507
|
+
if own_client:
|
|
508
|
+
client = traced_async_client(timeout=30.0)
|
|
509
|
+
|
|
510
|
+
try:
|
|
511
|
+
assert client is not None # noqa: S101
|
|
512
|
+
response = await client.get(_url(operation), params=query_params)
|
|
513
|
+
response.raise_for_status()
|
|
514
|
+
content_type = response.headers.get("content-type", "")
|
|
515
|
+
raw_format = _raw_format(operation, response)
|
|
516
|
+
raw_text = response.text[:_MAX_RAW_TEXT_CHARS] if raw_format in {"text", "json"} else None
|
|
517
|
+
line_count = len(raw_text.splitlines()) if raw_text is not None else None
|
|
518
|
+
return KmaApiHubUrlOutput(
|
|
519
|
+
operation_id=operation.operation_id,
|
|
520
|
+
endpoint_path=operation.endpoint_path,
|
|
521
|
+
approval_state=operation.approval_state,
|
|
522
|
+
content_type=content_type,
|
|
523
|
+
raw_format=raw_format,
|
|
524
|
+
line_count=line_count,
|
|
525
|
+
raw_text=raw_text,
|
|
526
|
+
summary=_summary_for_operation(operation, raw_text),
|
|
527
|
+
status_code=response.status_code,
|
|
528
|
+
)
|
|
529
|
+
except (ToolExecutionError, ConfigurationError):
|
|
530
|
+
raise
|
|
531
|
+
except httpx.HTTPStatusError as exc:
|
|
532
|
+
raise ToolExecutionError(
|
|
533
|
+
tool_id=operation.tool_id,
|
|
534
|
+
message=_status_error_message(operation, exc),
|
|
535
|
+
cause=exc,
|
|
536
|
+
) from exc
|
|
537
|
+
except httpx.RequestError as exc:
|
|
538
|
+
raise ToolExecutionError(
|
|
539
|
+
tool_id=operation.tool_id,
|
|
540
|
+
message=f"Network error reaching KMA APIHub: {exc}",
|
|
541
|
+
cause=exc,
|
|
542
|
+
) from exc
|
|
543
|
+
finally:
|
|
544
|
+
if own_client and client is not None:
|
|
545
|
+
await client.aclose()
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def build_tool(operation: KmaApiHubUrlOperation) -> GovAPITool:
|
|
549
|
+
"""Build the GovAPITool definition for a URL operation."""
|
|
550
|
+
return GovAPITool(
|
|
551
|
+
id=operation.tool_id,
|
|
552
|
+
name_ko=f"KMA APIHub {operation.title_ko}",
|
|
553
|
+
ministry="KMA",
|
|
554
|
+
category=["기상청", "APIHub", operation.category_name_ko, "URL"],
|
|
555
|
+
endpoint=_url(operation),
|
|
556
|
+
auth_type="api_key",
|
|
557
|
+
input_schema=input_schema_for(operation.operation_id),
|
|
558
|
+
output_schema=KmaApiHubUrlOutput,
|
|
559
|
+
search_hint=_search_hint(operation),
|
|
560
|
+
llm_description=_llm_description(operation),
|
|
561
|
+
policy=AdapterRealDomainPolicy(
|
|
562
|
+
real_classification_url=operation.official_page_url,
|
|
563
|
+
real_classification_text=(
|
|
564
|
+
"KMA APIHub non-structured URL surface; read-only meteorological data access."
|
|
565
|
+
),
|
|
566
|
+
citizen_facing_gate="read-only",
|
|
567
|
+
last_verified=datetime(2026, 5, 26, tzinfo=UTC),
|
|
568
|
+
),
|
|
569
|
+
is_concurrency_safe=True,
|
|
570
|
+
cache_ttl_seconds=300,
|
|
571
|
+
rate_limit_per_minute=10,
|
|
572
|
+
is_core=False,
|
|
573
|
+
primitive="find",
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def _adapter_for(operation: KmaApiHubUrlOperation) -> AdapterFn:
|
|
578
|
+
async def _adapter(inp: BaseModel) -> dict[str, object]:
|
|
579
|
+
output = await call_operation(operation, inp)
|
|
580
|
+
return {"kind": "record", "item": output.model_dump(mode="python")}
|
|
581
|
+
|
|
582
|
+
return cast(AdapterFn, _adapter)
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
def register(registry: ToolRegistry, executor: ToolExecutor) -> None:
|
|
586
|
+
"""Register every cataloged non-structured KMA APIHub URL operation."""
|
|
587
|
+
count = 0
|
|
588
|
+
for operation in iter_url_operations():
|
|
589
|
+
tool = build_tool(operation)
|
|
590
|
+
registry.register(tool)
|
|
591
|
+
executor.register_adapter(tool.id, _adapter_for(operation))
|
|
592
|
+
count += 1
|
|
593
|
+
logger.info("Registered %d KMA APIHub non-structured URL tools", count)
|