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
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
6
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
7
7
|
|
|
8
8
|
from ummaya.tools.executor import ToolExecutor
|
|
9
9
|
from ummaya.tools.models import GovAPITool
|
|
@@ -21,11 +21,29 @@ class AirKoreaAirQualityInput(BaseModel):
|
|
|
21
21
|
|
|
22
22
|
model_config = ConfigDict(extra="forbid")
|
|
23
23
|
|
|
24
|
-
sido_name: str = Field(
|
|
24
|
+
sido_name: str = Field(
|
|
25
|
+
...,
|
|
26
|
+
min_length=1,
|
|
27
|
+
description="AirKorea short province/city name, e.g. 서울, 부산, 경기.",
|
|
28
|
+
)
|
|
25
29
|
page_no: int = Field(default=1, ge=1, description="Page number.")
|
|
26
|
-
num_of_rows: int = Field(
|
|
30
|
+
num_of_rows: int = Field(
|
|
31
|
+
default=100,
|
|
32
|
+
ge=1,
|
|
33
|
+
le=100,
|
|
34
|
+
description="Rows per page; 100 captures all city/province stations in normal use.",
|
|
35
|
+
)
|
|
27
36
|
ver: str = Field(default="1.0", description="AirKorea response version.")
|
|
28
37
|
|
|
38
|
+
@field_validator("sido_name", mode="before")
|
|
39
|
+
@classmethod
|
|
40
|
+
def normalize_sido_name(cls, value: object) -> object:
|
|
41
|
+
"""AirKorea returns rows for short 시도 names, not full 행정명 names."""
|
|
42
|
+
|
|
43
|
+
if not isinstance(value, str):
|
|
44
|
+
return value
|
|
45
|
+
return _normalize_airkorea_sido_name(value)
|
|
46
|
+
|
|
29
47
|
|
|
30
48
|
SPEC = require_spec("airkorea_ctprvn_air_quality")
|
|
31
49
|
INPUT_SCHEMA = AirKoreaAirQualityInput
|
|
@@ -39,7 +57,94 @@ async def handle(
|
|
|
39
57
|
) -> dict[str, object]:
|
|
40
58
|
"""Fetch or replay AirKorea air quality rows."""
|
|
41
59
|
|
|
42
|
-
|
|
60
|
+
output = await handle_verified_input(input_model, SPEC, fixture_body=fixture_body)
|
|
61
|
+
return _enrich_air_quality_grades(output)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
_AIRKOREA_GRADE_LABELS: dict[str, str] = {
|
|
65
|
+
"1": "좋음",
|
|
66
|
+
"2": "보통",
|
|
67
|
+
"3": "나쁨",
|
|
68
|
+
"4": "매우나쁨",
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_AIRKOREA_ITEM_NAMES: dict[str, str] = {
|
|
72
|
+
"khai": "통합대기환경지수(CAI)",
|
|
73
|
+
"pm10": "미세먼지(PM10)",
|
|
74
|
+
"pm25": "초미세먼지(PM2.5)",
|
|
75
|
+
"o3": "오존(O3)",
|
|
76
|
+
"no2": "이산화질소(NO2)",
|
|
77
|
+
"co": "일산화탄소(CO)",
|
|
78
|
+
"so2": "아황산가스(SO2)",
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
_AIRKOREA_SIDO_ALIASES: dict[str, str] = {
|
|
82
|
+
"서울특별시": "서울",
|
|
83
|
+
"부산광역시": "부산",
|
|
84
|
+
"대구광역시": "대구",
|
|
85
|
+
"인천광역시": "인천",
|
|
86
|
+
"광주광역시": "광주",
|
|
87
|
+
"대전광역시": "대전",
|
|
88
|
+
"울산광역시": "울산",
|
|
89
|
+
"세종특별자치시": "세종",
|
|
90
|
+
"경기도": "경기",
|
|
91
|
+
"강원특별자치도": "강원",
|
|
92
|
+
"강원도": "강원",
|
|
93
|
+
"충청북도": "충북",
|
|
94
|
+
"충청남도": "충남",
|
|
95
|
+
"전북특별자치도": "전북",
|
|
96
|
+
"전라북도": "전북",
|
|
97
|
+
"전라남도": "전남",
|
|
98
|
+
"경상북도": "경북",
|
|
99
|
+
"경상남도": "경남",
|
|
100
|
+
"제주특별자치도": "제주",
|
|
101
|
+
"제주도": "제주",
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _normalize_airkorea_sido_name(value: str) -> str:
|
|
106
|
+
normalized = value.strip()
|
|
107
|
+
return _AIRKOREA_SIDO_ALIASES.get(normalized, normalized)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _enrich_air_quality_grades(output: dict[str, object]) -> dict[str, object]:
|
|
111
|
+
items = output.get("items")
|
|
112
|
+
if not isinstance(items, list):
|
|
113
|
+
return output
|
|
114
|
+
enriched_items: list[dict[str, object]] = []
|
|
115
|
+
changed = False
|
|
116
|
+
for item in items:
|
|
117
|
+
if not isinstance(item, dict):
|
|
118
|
+
continue
|
|
119
|
+
record_raw = item.get("record")
|
|
120
|
+
if not isinstance(record_raw, dict):
|
|
121
|
+
enriched_items.append(item)
|
|
122
|
+
continue
|
|
123
|
+
record = dict(record_raw)
|
|
124
|
+
for prefix, name_ko in _AIRKOREA_ITEM_NAMES.items():
|
|
125
|
+
name_key = f"{prefix}NameKo"
|
|
126
|
+
if name_key not in record:
|
|
127
|
+
record[name_key] = name_ko
|
|
128
|
+
changed = True
|
|
129
|
+
grade_value = record.get(f"{prefix}Grade")
|
|
130
|
+
label = _airkorea_grade_label(grade_value)
|
|
131
|
+
if label is not None:
|
|
132
|
+
record[f"{prefix}GradeLabelKo"] = label
|
|
133
|
+
changed = True
|
|
134
|
+
next_item = dict(item)
|
|
135
|
+
next_item["record"] = record
|
|
136
|
+
enriched_items.append(next_item)
|
|
137
|
+
if not changed:
|
|
138
|
+
return output
|
|
139
|
+
enriched_output = dict(output)
|
|
140
|
+
enriched_output["items"] = enriched_items
|
|
141
|
+
return enriched_output
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _airkorea_grade_label(value: object) -> str | None:
|
|
145
|
+
if value is None:
|
|
146
|
+
return None
|
|
147
|
+
return _AIRKOREA_GRADE_LABELS.get(str(value).strip())
|
|
43
148
|
|
|
44
149
|
|
|
45
150
|
def register(registry: ToolRegistry, executor: ToolExecutor) -> None:
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import math
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
7
9
|
|
|
8
10
|
from ummaya.tools.executor import ToolExecutor
|
|
9
11
|
from ummaya.tools.models import GovAPITool
|
|
@@ -25,6 +27,30 @@ class NmcAedSiteInput(BaseModel):
|
|
|
25
27
|
q1: str = Field(..., min_length=1, description="District/county name.")
|
|
26
28
|
page_no: int = Field(default=1, ge=1, description="Page number.")
|
|
27
29
|
num_of_rows: int = Field(default=10, ge=1, le=100, description="Rows per page.")
|
|
30
|
+
origin_lat: float | None = Field(
|
|
31
|
+
default=None,
|
|
32
|
+
ge=-90,
|
|
33
|
+
le=90,
|
|
34
|
+
description=(
|
|
35
|
+
"Optional original query latitude for client-side distance sorting. "
|
|
36
|
+
"Not sent to the upstream NMC AED API."
|
|
37
|
+
),
|
|
38
|
+
)
|
|
39
|
+
origin_lon: float | None = Field(
|
|
40
|
+
default=None,
|
|
41
|
+
ge=-180,
|
|
42
|
+
le=180,
|
|
43
|
+
description=(
|
|
44
|
+
"Optional original query longitude for client-side distance sorting. "
|
|
45
|
+
"Not sent to the upstream NMC AED API."
|
|
46
|
+
),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
@model_validator(mode="after")
|
|
50
|
+
def _origin_pair_is_complete(self) -> NmcAedSiteInput:
|
|
51
|
+
if (self.origin_lat is None) ^ (self.origin_lon is None):
|
|
52
|
+
raise ValueError("origin_lat and origin_lon must be supplied together")
|
|
53
|
+
return self
|
|
28
54
|
|
|
29
55
|
|
|
30
56
|
SPEC = require_spec("nmc_aed_site_locate")
|
|
@@ -39,7 +65,87 @@ async def handle(
|
|
|
39
65
|
) -> dict[str, object]:
|
|
40
66
|
"""Fetch or replay NMC AED rows."""
|
|
41
67
|
|
|
42
|
-
|
|
68
|
+
output = await handle_verified_input(input_model, SPEC, fixture_body=fixture_body)
|
|
69
|
+
if input_model.origin_lat is None or input_model.origin_lon is None:
|
|
70
|
+
return output
|
|
71
|
+
_sort_items_by_origin_distance(
|
|
72
|
+
output,
|
|
73
|
+
origin_lat=input_model.origin_lat,
|
|
74
|
+
origin_lon=input_model.origin_lon,
|
|
75
|
+
)
|
|
76
|
+
return output
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _sort_items_by_origin_distance(
|
|
80
|
+
output: dict[str, object],
|
|
81
|
+
*,
|
|
82
|
+
origin_lat: float,
|
|
83
|
+
origin_lon: float,
|
|
84
|
+
) -> None:
|
|
85
|
+
items = output.get("items")
|
|
86
|
+
if not isinstance(items, list):
|
|
87
|
+
return
|
|
88
|
+
for item in items:
|
|
89
|
+
if not isinstance(item, dict):
|
|
90
|
+
continue
|
|
91
|
+
record = item.get("record")
|
|
92
|
+
if not isinstance(record, dict):
|
|
93
|
+
continue
|
|
94
|
+
lat = _as_float(record.get("wgs84Lat"))
|
|
95
|
+
lon = _as_float(record.get("wgs84Lon"))
|
|
96
|
+
if lat is None or lon is None:
|
|
97
|
+
continue
|
|
98
|
+
distance_km = round(
|
|
99
|
+
_haversine_km(
|
|
100
|
+
lat1=origin_lat,
|
|
101
|
+
lon1=origin_lon,
|
|
102
|
+
lat2=lat,
|
|
103
|
+
lon2=lon,
|
|
104
|
+
),
|
|
105
|
+
3,
|
|
106
|
+
)
|
|
107
|
+
record["distance"] = distance_km
|
|
108
|
+
record["distance_km"] = distance_km
|
|
109
|
+
record["distance_unit"] = "km"
|
|
110
|
+
items.sort(key=_distance_sort_key)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _distance_sort_key(item: object) -> tuple[int, float]:
|
|
114
|
+
if not isinstance(item, dict):
|
|
115
|
+
return (1, 0.0)
|
|
116
|
+
record = item.get("record")
|
|
117
|
+
if not isinstance(record, dict):
|
|
118
|
+
return (1, 0.0)
|
|
119
|
+
distance = _as_float(record.get("distance_km"))
|
|
120
|
+
if distance is None:
|
|
121
|
+
return (1, 0.0)
|
|
122
|
+
return (0, distance)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _as_float(value: object) -> float | None:
|
|
126
|
+
if isinstance(value, bool):
|
|
127
|
+
return None
|
|
128
|
+
if isinstance(value, int | float):
|
|
129
|
+
return float(value)
|
|
130
|
+
if not isinstance(value, str):
|
|
131
|
+
return None
|
|
132
|
+
try:
|
|
133
|
+
return float(value.strip())
|
|
134
|
+
except ValueError:
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _haversine_km(*, lat1: float, lon1: float, lat2: float, lon2: float) -> float:
|
|
139
|
+
radius_km = 6371.0088
|
|
140
|
+
phi1 = math.radians(lat1)
|
|
141
|
+
phi2 = math.radians(lat2)
|
|
142
|
+
delta_phi = math.radians(lat2 - lat1)
|
|
143
|
+
delta_lambda = math.radians(lon2 - lon1)
|
|
144
|
+
a = (
|
|
145
|
+
math.sin(delta_phi / 2.0) ** 2
|
|
146
|
+
+ math.cos(phi1) * math.cos(phi2) * math.sin(delta_lambda / 2.0) ** 2
|
|
147
|
+
)
|
|
148
|
+
return radius_km * 2.0 * math.atan2(math.sqrt(a), math.sqrt(1.0 - a))
|
|
43
149
|
|
|
44
150
|
|
|
45
151
|
def register(registry: ToolRegistry, executor: ToolExecutor) -> None:
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
+
from datetime import datetime, timedelta
|
|
6
7
|
from typing import Literal
|
|
7
8
|
|
|
8
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
9
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
9
10
|
|
|
10
11
|
from ummaya.tools.executor import ToolExecutor
|
|
11
12
|
from ummaya.tools.models import GovAPITool
|
|
@@ -17,27 +18,113 @@ from ummaya.tools.verified_data_go_kr._factory import (
|
|
|
17
18
|
)
|
|
18
19
|
from ummaya.tools.verified_data_go_kr._manifest import require_spec
|
|
19
20
|
|
|
21
|
+
_PPS_DATETIME_FORMAT = "%Y%m%d%H%M"
|
|
22
|
+
_PPS_MAX_SEARCH_WINDOW = timedelta(days=31)
|
|
23
|
+
|
|
20
24
|
|
|
21
25
|
class PpsBidPublicInfoInput(BaseModel):
|
|
22
26
|
"""Input for PPS bid public information."""
|
|
23
27
|
|
|
24
28
|
model_config = ConfigDict(extra="forbid")
|
|
25
29
|
|
|
26
|
-
inqry_div: Literal["2"] = Field(
|
|
27
|
-
default="
|
|
30
|
+
inqry_div: Literal["1", "2"] = Field(
|
|
31
|
+
default="1",
|
|
32
|
+
description=(
|
|
33
|
+
"Official PPS inqryDiv. Use '1' for bid notice publication datetime "
|
|
34
|
+
"(pblancDate) searches such as 'this week posted notices'; use '2' "
|
|
35
|
+
"for bid opening datetime (opengDt) searches."
|
|
36
|
+
),
|
|
37
|
+
)
|
|
38
|
+
inqry_bgn_dt: str = Field(
|
|
39
|
+
...,
|
|
40
|
+
pattern=r"^\d{12}$",
|
|
28
41
|
description=(
|
|
29
|
-
"PPS
|
|
30
|
-
"
|
|
42
|
+
"Official PPS inqryBgnDt search start datetime in YYYYMMDDHHMM. "
|
|
43
|
+
"Required when inqry_div is '1' or '2'. Keep each PPS request window "
|
|
44
|
+
"within 31 days."
|
|
31
45
|
),
|
|
32
46
|
)
|
|
33
|
-
|
|
47
|
+
inqry_end_dt: str = Field(
|
|
34
48
|
...,
|
|
35
|
-
|
|
36
|
-
description=
|
|
49
|
+
pattern=r"^\d{12}$",
|
|
50
|
+
description=(
|
|
51
|
+
"Official PPS inqryEndDt search end datetime in YYYYMMDDHHMM. "
|
|
52
|
+
"Required when inqry_div is '1' or '2'. Keep each PPS request window "
|
|
53
|
+
"within 31 days."
|
|
54
|
+
),
|
|
55
|
+
)
|
|
56
|
+
bid_ntce_nm: str | None = Field(
|
|
57
|
+
default=None,
|
|
58
|
+
max_length=1000,
|
|
59
|
+
description=(
|
|
60
|
+
"Official PPS bidNtceNm notice-name keyword. Partial names are allowed; "
|
|
61
|
+
"use this for citizen keywords such as 전기공사."
|
|
62
|
+
),
|
|
63
|
+
)
|
|
64
|
+
ntce_instt_nm: str | None = Field(
|
|
65
|
+
default=None,
|
|
66
|
+
max_length=400,
|
|
67
|
+
description=(
|
|
68
|
+
"Official PPS ntceInsttNm public notice agency name filter. "
|
|
69
|
+
"Partial agency names are allowed."
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
dminstt_nm: str | None = Field(
|
|
73
|
+
default=None,
|
|
74
|
+
max_length=400,
|
|
75
|
+
description=(
|
|
76
|
+
"Official PPS dminsttNm demand agency name filter. Partial agency names are allowed."
|
|
77
|
+
),
|
|
78
|
+
)
|
|
79
|
+
region_name: str | None = Field(
|
|
80
|
+
default=None,
|
|
81
|
+
max_length=100,
|
|
82
|
+
description=(
|
|
83
|
+
"UMMAYA client-side region relevance filter copied from citizen wording. "
|
|
84
|
+
"This is not sent to PPS upstream; after the official response, UMMAYA "
|
|
85
|
+
"keeps rows whose documented region/agency fields such as cnstrtsiteRgnNm, "
|
|
86
|
+
"prtcptLmtRgnNm, ntceInsttNm, or dminsttNm match this value."
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
prtcpt_lmt_rgn_nm: str | None = Field(
|
|
90
|
+
default=None,
|
|
91
|
+
max_length=100,
|
|
92
|
+
description=(
|
|
93
|
+
"Official PPS prtcptLmtRgnNm participation-limit region name. "
|
|
94
|
+
"For Busan-region notices use 부산광역시 when the citizen says 부산시."
|
|
95
|
+
),
|
|
96
|
+
)
|
|
97
|
+
indstryty_nm: str | None = Field(
|
|
98
|
+
default=None,
|
|
99
|
+
max_length=100,
|
|
100
|
+
description=(
|
|
101
|
+
"Official PPS indstrytyNm industry/license name. Use 전기공사업 "
|
|
102
|
+
"for electrical-construction qualification searches when requested."
|
|
103
|
+
),
|
|
37
104
|
)
|
|
38
105
|
page_no: int = Field(default=1, ge=1, description="Page number.")
|
|
39
106
|
num_of_rows: int = Field(default=10, ge=1, le=100, description="Rows per page.")
|
|
40
107
|
|
|
108
|
+
@model_validator(mode="after")
|
|
109
|
+
def validate_official_search_window(self) -> PpsBidPublicInfoInput:
|
|
110
|
+
"""Keep PPS searches inside the observed upstream contract window."""
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
start = datetime.strptime(self.inqry_bgn_dt, _PPS_DATETIME_FORMAT)
|
|
114
|
+
end = datetime.strptime(self.inqry_end_dt, _PPS_DATETIME_FORMAT)
|
|
115
|
+
except ValueError as exc:
|
|
116
|
+
raise ValueError(
|
|
117
|
+
"PPS inqry_bgn_dt and inqry_end_dt must be valid YYYYMMDDHHMM datetimes."
|
|
118
|
+
) from exc
|
|
119
|
+
if end < start:
|
|
120
|
+
raise ValueError("PPS inqry_end_dt must be greater than or equal to inqry_bgn_dt.")
|
|
121
|
+
if end - start > _PPS_MAX_SEARCH_WINDOW:
|
|
122
|
+
raise ValueError(
|
|
123
|
+
"PPS Nara Market bid searches must be split into 31-day-or-smaller "
|
|
124
|
+
"inqry_bgn_dt/inqry_end_dt windows before calling the upstream API."
|
|
125
|
+
)
|
|
126
|
+
return self
|
|
127
|
+
|
|
41
128
|
|
|
42
129
|
SPEC = require_spec("pps_bid_public_info")
|
|
43
130
|
INPUT_SCHEMA = PpsBidPublicInfoInput
|
|
@@ -51,7 +138,85 @@ async def handle(
|
|
|
51
138
|
) -> dict[str, object]:
|
|
52
139
|
"""Fetch or replay PPS bid public information rows."""
|
|
53
140
|
|
|
54
|
-
|
|
141
|
+
output = await handle_verified_input(input_model, SPEC, fixture_body=fixture_body)
|
|
142
|
+
return _filter_output_by_region_name(output, input_model.region_name)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
_REGION_RELEVANCE_FIELDS: tuple[str, ...] = (
|
|
146
|
+
"cnstrtsiteRgnNm",
|
|
147
|
+
"prtcptLmtRgnNm",
|
|
148
|
+
"ntceInsttNm",
|
|
149
|
+
"dminsttNm",
|
|
150
|
+
"jntcontrctDutyRgnNm1",
|
|
151
|
+
"jntcontrctDutyRgnNm2",
|
|
152
|
+
"jntcontrctDutyRgnNm3",
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _filter_output_by_region_name(
|
|
157
|
+
output: dict[str, object],
|
|
158
|
+
region_name: str | None,
|
|
159
|
+
) -> dict[str, object]:
|
|
160
|
+
"""Filter PPS rows by documented region-bearing response fields."""
|
|
161
|
+
|
|
162
|
+
terms = _region_terms(region_name)
|
|
163
|
+
if not terms:
|
|
164
|
+
return output
|
|
165
|
+
|
|
166
|
+
raw_items = output.get("items")
|
|
167
|
+
if not isinstance(raw_items, list):
|
|
168
|
+
return output
|
|
169
|
+
|
|
170
|
+
filtered: list[dict[str, object]] = []
|
|
171
|
+
for raw_item in raw_items:
|
|
172
|
+
if not isinstance(raw_item, dict):
|
|
173
|
+
continue
|
|
174
|
+
if _item_matches_region(raw_item, terms):
|
|
175
|
+
filtered.append(raw_item)
|
|
176
|
+
|
|
177
|
+
next_output = dict(output)
|
|
178
|
+
next_output["items"] = filtered
|
|
179
|
+
next_output["total_count"] = len(filtered)
|
|
180
|
+
raw_meta = output.get("meta")
|
|
181
|
+
meta = dict(raw_meta) if isinstance(raw_meta, dict) else {}
|
|
182
|
+
meta["upstream_total_count"] = output.get("total_count")
|
|
183
|
+
meta["client_filter"] = {
|
|
184
|
+
"field": "region_name",
|
|
185
|
+
"value": region_name,
|
|
186
|
+
"matched_count": len(filtered),
|
|
187
|
+
}
|
|
188
|
+
next_output["meta"] = meta
|
|
189
|
+
return next_output
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _region_terms(region_name: str | None) -> tuple[str, ...]:
|
|
193
|
+
if region_name is None:
|
|
194
|
+
return ()
|
|
195
|
+
normalized = " ".join(region_name.split())
|
|
196
|
+
if not normalized:
|
|
197
|
+
return ()
|
|
198
|
+
terms = [normalized]
|
|
199
|
+
for suffix in ("특별자치시", "특별자치도", "특별시", "광역시", "도"):
|
|
200
|
+
if normalized.endswith(suffix):
|
|
201
|
+
short = normalized[: -len(suffix)]
|
|
202
|
+
if short:
|
|
203
|
+
terms.append(short)
|
|
204
|
+
break
|
|
205
|
+
return tuple(dict.fromkeys(terms))
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _item_matches_region(item: dict[str, object], terms: tuple[str, ...]) -> bool:
|
|
209
|
+
raw_record = item.get("record")
|
|
210
|
+
record = raw_record if isinstance(raw_record, dict) else item
|
|
211
|
+
for field_name in _REGION_RELEVANCE_FIELDS:
|
|
212
|
+
value = record.get(field_name)
|
|
213
|
+
if not isinstance(value, str):
|
|
214
|
+
continue
|
|
215
|
+
compact_value = value.replace(" ", "")
|
|
216
|
+
for term in terms:
|
|
217
|
+
if term in value or term.replace(" ", "") in compact_value:
|
|
218
|
+
return True
|
|
219
|
+
return False
|
|
55
220
|
|
|
56
221
|
|
|
57
222
|
def register(registry: ToolRegistry, executor: ToolExecutor) -> None:
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
+
from typing import cast
|
|
7
|
+
|
|
6
8
|
from pydantic import BaseModel, ConfigDict, Field
|
|
7
9
|
|
|
8
10
|
from ummaya.tools.executor import ToolExecutor
|
|
@@ -15,14 +17,41 @@ from ummaya.tools.verified_data_go_kr._factory import (
|
|
|
15
17
|
)
|
|
16
18
|
from ummaya.tools.verified_data_go_kr._manifest import require_spec
|
|
17
19
|
|
|
20
|
+
_TAGO_CITY_CODE_DESCRIPTION = (
|
|
21
|
+
"Official TAGO cityCode from the provider getCtyCodeList contract. "
|
|
22
|
+
"Common metropolitan examples: Busan=21, Daegu=22, Incheon=23, "
|
|
23
|
+
"Gwangju=24, Daejeon=25, Ulsan=26."
|
|
24
|
+
)
|
|
25
|
+
|
|
18
26
|
|
|
19
27
|
class TagoBusArrivalInput(BaseModel):
|
|
20
28
|
"""Input for TAGO bus arrival search."""
|
|
21
29
|
|
|
22
30
|
model_config = ConfigDict(extra="forbid")
|
|
23
31
|
|
|
24
|
-
city_code: str = Field(..., min_length=1, description=
|
|
25
|
-
node_id: str = Field(
|
|
32
|
+
city_code: str = Field(..., min_length=1, description=_TAGO_CITY_CODE_DESCRIPTION)
|
|
33
|
+
node_id: str = Field(
|
|
34
|
+
...,
|
|
35
|
+
min_length=1,
|
|
36
|
+
description="Official TAGO nodeId returned by tago_bus_station_search.",
|
|
37
|
+
)
|
|
38
|
+
route_no: str | None = Field(
|
|
39
|
+
default=None,
|
|
40
|
+
min_length=1,
|
|
41
|
+
description=(
|
|
42
|
+
"Optional client-side filter against the official TAGO response field routeno. "
|
|
43
|
+
"It is not sent upstream; use it when the citizen names a visible bus route "
|
|
44
|
+
"such as 1001."
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
route_id: str | None = Field(
|
|
48
|
+
default=None,
|
|
49
|
+
min_length=1,
|
|
50
|
+
description=(
|
|
51
|
+
"Optional client-side filter against the official TAGO response field routeid. "
|
|
52
|
+
"Get it from tago_bus_route_search when route_no alone is ambiguous."
|
|
53
|
+
),
|
|
54
|
+
)
|
|
26
55
|
page_no: int = Field(default=1, ge=1, description="Page number.")
|
|
27
56
|
num_of_rows: int = Field(default=10, ge=1, le=100, description="Rows per page.")
|
|
28
57
|
|
|
@@ -39,7 +68,41 @@ async def handle(
|
|
|
39
68
|
) -> dict[str, object]:
|
|
40
69
|
"""Fetch or replay TAGO bus arrival rows."""
|
|
41
70
|
|
|
42
|
-
|
|
71
|
+
output = await handle_verified_input(input_model, SPEC, fixture_body=fixture_body)
|
|
72
|
+
if input_model.route_no is None and input_model.route_id is None:
|
|
73
|
+
return output
|
|
74
|
+
return _filter_arrivals(output, route_no=input_model.route_no, route_id=input_model.route_id)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _filter_arrivals(
|
|
78
|
+
output: dict[str, object],
|
|
79
|
+
*,
|
|
80
|
+
route_no: str | None,
|
|
81
|
+
route_id: str | None,
|
|
82
|
+
) -> dict[str, object]:
|
|
83
|
+
items = output.get("items")
|
|
84
|
+
if not isinstance(items, list):
|
|
85
|
+
return output
|
|
86
|
+
|
|
87
|
+
filtered: list[dict[str, object]] = []
|
|
88
|
+
for item in items:
|
|
89
|
+
if not isinstance(item, dict):
|
|
90
|
+
continue
|
|
91
|
+
record = item.get("record")
|
|
92
|
+
if not isinstance(record, dict):
|
|
93
|
+
continue
|
|
94
|
+
typed_record = cast(dict[str, object], record)
|
|
95
|
+
if route_no is not None and str(typed_record.get("routeno", "")) != route_no:
|
|
96
|
+
continue
|
|
97
|
+
if route_id is not None and str(typed_record.get("routeid", "")) != route_id:
|
|
98
|
+
continue
|
|
99
|
+
filtered.append(cast(dict[str, object], item))
|
|
100
|
+
|
|
101
|
+
filtered_output = dict(output)
|
|
102
|
+
filtered_output["items"] = filtered
|
|
103
|
+
filtered_output["total_count"] = len(filtered)
|
|
104
|
+
filtered_output["next_cursor"] = None
|
|
105
|
+
return filtered_output
|
|
43
106
|
|
|
44
107
|
|
|
45
108
|
def register(registry: ToolRegistry, executor: ToolExecutor) -> None:
|
|
@@ -15,14 +15,24 @@ from ummaya.tools.verified_data_go_kr._factory import (
|
|
|
15
15
|
)
|
|
16
16
|
from ummaya.tools.verified_data_go_kr._manifest import require_spec
|
|
17
17
|
|
|
18
|
+
_TAGO_CITY_CODE_DESCRIPTION = (
|
|
19
|
+
"Official TAGO cityCode from the provider getCtyCodeList contract. "
|
|
20
|
+
"Common metropolitan examples: Busan=21, Daegu=22, Incheon=23, "
|
|
21
|
+
"Gwangju=24, Daejeon=25, Ulsan=26."
|
|
22
|
+
)
|
|
23
|
+
|
|
18
24
|
|
|
19
25
|
class TagoBusLocationInput(BaseModel):
|
|
20
26
|
"""Input for TAGO bus location search."""
|
|
21
27
|
|
|
22
28
|
model_config = ConfigDict(extra="forbid")
|
|
23
29
|
|
|
24
|
-
city_code: str = Field(..., min_length=1, description=
|
|
25
|
-
route_id: str = Field(
|
|
30
|
+
city_code: str = Field(..., min_length=1, description=_TAGO_CITY_CODE_DESCRIPTION)
|
|
31
|
+
route_id: str = Field(
|
|
32
|
+
...,
|
|
33
|
+
min_length=1,
|
|
34
|
+
description="Official TAGO routeId returned by tago_bus_route_search.",
|
|
35
|
+
)
|
|
26
36
|
page_no: int = Field(default=1, ge=1, description="Page number.")
|
|
27
37
|
num_of_rows: int = Field(default=10, ge=1, le=100, description="Rows per page.")
|
|
28
38
|
|
|
@@ -15,14 +15,20 @@ from ummaya.tools.verified_data_go_kr._factory import (
|
|
|
15
15
|
)
|
|
16
16
|
from ummaya.tools.verified_data_go_kr._manifest import require_spec
|
|
17
17
|
|
|
18
|
+
_TAGO_CITY_CODE_DESCRIPTION = (
|
|
19
|
+
"Official TAGO cityCode from the provider getCtyCodeList contract. "
|
|
20
|
+
"Common metropolitan examples: Busan=21, Daegu=22, Incheon=23, "
|
|
21
|
+
"Gwangju=24, Daejeon=25, Ulsan=26."
|
|
22
|
+
)
|
|
23
|
+
|
|
18
24
|
|
|
19
25
|
class TagoBusRouteInput(BaseModel):
|
|
20
26
|
"""Input for TAGO bus route search."""
|
|
21
27
|
|
|
22
28
|
model_config = ConfigDict(extra="forbid")
|
|
23
29
|
|
|
24
|
-
city_code: str = Field(..., min_length=1, description=
|
|
25
|
-
route_no: str = Field(..., min_length=1, description="Bus route number.")
|
|
30
|
+
city_code: str = Field(..., min_length=1, description=_TAGO_CITY_CODE_DESCRIPTION)
|
|
31
|
+
route_no: str = Field(..., min_length=1, description="Bus route number visible to citizens.")
|
|
26
32
|
page_no: int = Field(default=1, ge=1, description="Page number.")
|
|
27
33
|
num_of_rows: int = Field(default=10, ge=1, le=100, description="Rows per page.")
|
|
28
34
|
|