ummaya 0.2.4 → 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 +15 -2
- package/bin/ummaya +10 -1
- package/npm-shrinkwrap.json +253 -2
- package/package.json +5 -1
- package/prompts/manifest.yaml +1 -1
- package/prompts/system_v1.md +1 -0
- package/pyproject.toml +26 -2
- package/specs/2803-document-production-hardening/contracts/document-tools.schema.json +1043 -0
- package/src/ummaya/_canonical/__init__.py +2 -0
- package/src/ummaya/engine/engine.py +29 -132
- package/src/ummaya/evidence/__init__.py +21 -2
- 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 +88 -1
- 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 +81 -212
- package/src/ummaya/evidence/source_provenance.py +246 -0
- package/src/ummaya/evidence/source_provenance_redaction.py +176 -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 +5 -5
- package/src/ummaya/ipc/route_diagnostics.py +73 -0
- package/src/ummaya/ipc/stdio.py +1109 -477
- package/src/ummaya/llm/client.py +102 -3
- package/src/ummaya/llm/config.py +8 -3
- 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 +17 -1
- 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 +29 -0
- package/src/ummaya/tools/live_proxy.py +0 -3
- package/src/ummaya/tools/models.py +5 -1
- package/src/ummaya/tools/register_all.py +8 -0
- package/src/ummaya/tools/registry.py +10 -1
- 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 +34 -746
- package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
- package/tui/package.json +1 -1
- package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
- package/tui/src/QueryEngine.ts +12 -8
- package/tui/src/bridge/inboundAttachments.ts +3 -3
- package/tui/src/cli/handlers/auth.ts +3 -12
- package/tui/src/cli/print.ts +7 -7
- package/tui/src/commands/insights.ts +1 -1
- package/tui/src/commands/install-github-app/types.ts +8 -30
- package/tui/src/commands/plugin/types.ts +6 -28
- package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
- package/tui/src/commands/rename/generateSessionName.ts +1 -1
- 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/ScrollKeybindingHandler.tsx +6 -6
- package/tui/src/components/Spinner/types.ts +6 -28
- 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/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 +3 -3
- package/tui/src/ipc/frames.generated.ts +12 -12
- package/tui/src/ipc/llmClient.ts +151 -27
- package/tui/src/ipc/schema/frame.schema.json +1 -1
- package/tui/src/keybindings/defaultBindings.ts +4 -0
- package/tui/src/main.tsx +29 -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 -2186
- package/tui/src/screens/REPL.tsx +40 -29
- 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 +65 -2
- 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 -418
- 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/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 +1207 -714
- 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 +25 -32
- package/tui/src/tools/LookupPrimitive/prompt.ts +0 -2
- 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 +1 -11
- 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 +27 -10
- 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 +2 -1
- 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/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/pendingCallRegistry.ts +1 -6
- package/tui/src/tools/_shared/rootPrimitiveInput.ts +1 -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 +55 -860
- 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/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/mcp/dateTimeParser.ts +1 -1
- package/tui/src/utils/messages.ts +18 -0
- package/tui/src/utils/migrateSessions.ts +3 -3
- package/tui/src/utils/model/model.ts +6 -6
- 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/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/permissionValidation.ts +14 -2
- package/tui/src/utils/shell/prefix.ts +1 -1
- package/tui/src/utils/sideQuery.ts +1 -1
- package/tui/src/utils/systemThemeWatcher.ts +13 -3
- package/tui/src/utils/teleport.tsx +1 -1
- package/uv.lock +400 -14
- package/tui/src/services/api/claude.ts +0 -3540
- package/tui/src/tools/_shared/directPublicDataGuard.ts +0 -362
- package/tui/src/tools/_shared/kmaAnalysisGuard.ts +0 -197
- package/tui/src/tools/_shared/kmaAviationGuard.ts +0 -70
- package/tui/src/tools/_shared/nmcAedGuard.ts +0 -234
- package/tui/src/tools/_shared/protectedCheckGuard.ts +0 -207
- package/tui/src/tools/_shared/textToolCallGuard.ts +0 -91
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { assertFriendliApiKeyForUse } from '../../../utils/auth.js'
|
|
2
|
+
import {
|
|
3
|
+
createAssistantAPIErrorMessage,
|
|
4
|
+
createAssistantMessage,
|
|
5
|
+
} from '../../../utils/messages.js'
|
|
6
|
+
import { ensureUmmayaAdapterManifest } from '../../../ipc/bridgeSingleton.js'
|
|
7
|
+
import { latestUserText } from './messages.js'
|
|
8
|
+
import { buildProviderRequest, getAPIMetadata } from './request.js'
|
|
9
|
+
import {
|
|
10
|
+
ProviderStreamIdleTimeoutError,
|
|
11
|
+
streamResponseToMessages,
|
|
12
|
+
} from './streaming.js'
|
|
13
|
+
import { shouldWaitForAdapterManifestForProviderRequest } from './toolSelection.js'
|
|
14
|
+
import type { QueryModelParams } from './types.js'
|
|
15
|
+
import {
|
|
16
|
+
appendProviderOutputEvidence,
|
|
17
|
+
appendProviderTurnEvidence,
|
|
18
|
+
createProviderTurnEvidenceContext,
|
|
19
|
+
} from './evidence.js'
|
|
20
|
+
import type { ProviderOptions } from './types.js'
|
|
21
|
+
|
|
22
|
+
export { getAPIMetadata }
|
|
23
|
+
|
|
24
|
+
export const PUBLIC_SERVICE_MANIFEST_SYNC_TIMEOUT_MS = 30_000
|
|
25
|
+
const PROVIDER_STREAM_TIMEOUT_HANDOFF =
|
|
26
|
+
'K-EXAONE 응답이 지연되어 이번 요청을 이어갈 수 없습니다. 잠시 후 다시 시도해 주세요.'
|
|
27
|
+
const DEFAULT_PROVIDER_EVENT_IDLE_TIMEOUT_MS = 90_000
|
|
28
|
+
const PROVIDER_EVENT_IDLE_TIMEOUT_ENV = 'UMMAYA_TUI_PROVIDER_EVENT_IDLE_TIMEOUT_MS'
|
|
29
|
+
const FRAME_IDLE_TIMEOUT_ENV = 'UMMAYA_TUI_FRAME_IDLE_TIMEOUT_MS'
|
|
30
|
+
const FRIENDLI_CHAT_COMPLETIONS_URL =
|
|
31
|
+
'https://api.friendli.ai/serverless/v1/chat/completions'
|
|
32
|
+
const TEST_PUBLIC_SERVICE_MANIFEST_SYNC_TIMEOUT_ENV =
|
|
33
|
+
'UMMAYA_TEST_PUBLIC_SERVICE_MANIFEST_SYNC_TIMEOUT_MS'
|
|
34
|
+
|
|
35
|
+
function publicServiceManifestSyncTimeoutMs(): number {
|
|
36
|
+
const rawTimeout = process.env[TEST_PUBLIC_SERVICE_MANIFEST_SYNC_TIMEOUT_ENV]
|
|
37
|
+
if (rawTimeout === undefined) return PUBLIC_SERVICE_MANIFEST_SYNC_TIMEOUT_MS
|
|
38
|
+
|
|
39
|
+
const parsedTimeout = Number(rawTimeout)
|
|
40
|
+
if (!Number.isInteger(parsedTimeout) || parsedTimeout <= 0) {
|
|
41
|
+
return PUBLIC_SERVICE_MANIFEST_SYNC_TIMEOUT_MS
|
|
42
|
+
}
|
|
43
|
+
return parsedTimeout
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function adapterManifestTimeoutMessage(timeoutMs: number): string {
|
|
47
|
+
return [
|
|
48
|
+
`public-service adapter manifest did not sync within ${timeoutMs}ms;`,
|
|
49
|
+
'backend readiness is required before starting public-service provider requests.',
|
|
50
|
+
'Retry after adapter_manifest_sync arrives from the backend.',
|
|
51
|
+
].join(' ')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function providerEventIdleTimeoutMs(): number {
|
|
55
|
+
const rawTimeout =
|
|
56
|
+
process.env[PROVIDER_EVENT_IDLE_TIMEOUT_ENV] ??
|
|
57
|
+
process.env[FRAME_IDLE_TIMEOUT_ENV]
|
|
58
|
+
if (rawTimeout === undefined) return DEFAULT_PROVIDER_EVENT_IDLE_TIMEOUT_MS
|
|
59
|
+
|
|
60
|
+
const parsedTimeout = Number.parseInt(rawTimeout, 10)
|
|
61
|
+
if (!Number.isFinite(parsedTimeout) || parsedTimeout <= 0) {
|
|
62
|
+
return DEFAULT_PROVIDER_EVENT_IDLE_TIMEOUT_MS
|
|
63
|
+
}
|
|
64
|
+
return parsedTimeout
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function getExtraBodyParams(_betaHeaders?: readonly string[]): Record<string, unknown> {
|
|
68
|
+
return {}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function configureTaskBudgetParams(
|
|
72
|
+
taskBudget: { readonly total: number; readonly remaining?: number } | undefined,
|
|
73
|
+
outputConfig: Record<string, unknown>,
|
|
74
|
+
_betas: string[],
|
|
75
|
+
): void {
|
|
76
|
+
if (!taskBudget) return
|
|
77
|
+
outputConfig.task_budget = taskBudget
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function verifyApiKey(
|
|
81
|
+
apiKey: string,
|
|
82
|
+
_isNonInteractiveSession: boolean,
|
|
83
|
+
): Promise<boolean> {
|
|
84
|
+
return apiKey.trim().length > 0
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function* queryModelWithStreaming(
|
|
88
|
+
params: QueryModelParams,
|
|
89
|
+
): AsyncGenerator<unknown> {
|
|
90
|
+
assertFriendliApiKeyForUse()
|
|
91
|
+
const evidenceContext = createProviderTurnEvidenceContext(params)
|
|
92
|
+
const userText = latestUserText(params.messages)
|
|
93
|
+
if (
|
|
94
|
+
shouldWaitForAdapterManifestForProviderRequest({
|
|
95
|
+
querySource: params.options.querySource,
|
|
96
|
+
userText,
|
|
97
|
+
})
|
|
98
|
+
) {
|
|
99
|
+
const timeoutMs = publicServiceManifestSyncTimeoutMs()
|
|
100
|
+
const manifestSynced = await ensureUmmayaAdapterManifest(timeoutMs)
|
|
101
|
+
if (!manifestSynced) {
|
|
102
|
+
yield createAssistantAPIErrorMessage({
|
|
103
|
+
content: adapterManifestTimeoutMessage(timeoutMs),
|
|
104
|
+
apiError: 'api_error',
|
|
105
|
+
})
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const request = buildProviderRequest(params, evidenceContext)
|
|
110
|
+
const fetchImpl: NonNullable<ProviderOptions['fetchOverride']> =
|
|
111
|
+
params.options.fetchOverride ?? ((input, init) => fetch(input, init))
|
|
112
|
+
yield { type: 'stream_request_start' as const }
|
|
113
|
+
let providerTurnStarted = false
|
|
114
|
+
try {
|
|
115
|
+
appendProviderTurnEvidence('provider_turn_start', evidenceContext)
|
|
116
|
+
providerTurnStarted = true
|
|
117
|
+
const response = await fetchProviderResponse(
|
|
118
|
+
fetchImpl,
|
|
119
|
+
{
|
|
120
|
+
method: 'POST',
|
|
121
|
+
headers: {
|
|
122
|
+
'content-type': 'application/json',
|
|
123
|
+
authorization: `Bearer ${process.env.UMMAYA_FRIENDLI_TOKEN ?? ''}`,
|
|
124
|
+
},
|
|
125
|
+
body: JSON.stringify(request),
|
|
126
|
+
signal: params.signal,
|
|
127
|
+
},
|
|
128
|
+
providerEventIdleTimeoutMs(),
|
|
129
|
+
)
|
|
130
|
+
for await (const event of streamResponseToMessages(response, {
|
|
131
|
+
dataIdleTimeoutMs: providerEventIdleTimeoutMs(),
|
|
132
|
+
availableToolNames: rawJsonToolCallNamesForRequest(request),
|
|
133
|
+
includeReasoning: request.include_reasoning === true,
|
|
134
|
+
})) {
|
|
135
|
+
appendProviderOutputEvidence(event, evidenceContext)
|
|
136
|
+
yield event
|
|
137
|
+
}
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if (error instanceof ProviderStreamIdleTimeoutError) {
|
|
140
|
+
yield createAssistantMessage({
|
|
141
|
+
content: PROVIDER_STREAM_TIMEOUT_HANDOFF,
|
|
142
|
+
})
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
throw error
|
|
146
|
+
} finally {
|
|
147
|
+
if (providerTurnStarted) {
|
|
148
|
+
appendProviderTurnEvidence('provider_turn_complete', evidenceContext)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function rawJsonToolCallNamesForRequest(request: {
|
|
154
|
+
readonly tools?: readonly {
|
|
155
|
+
readonly function: { readonly name: string }
|
|
156
|
+
}[]
|
|
157
|
+
}): readonly string[] {
|
|
158
|
+
const names = new Set<string>()
|
|
159
|
+
for (const tool of request.tools ?? []) {
|
|
160
|
+
const name = tool.function.name.trim()
|
|
161
|
+
if (name.length > 0) names.add(name)
|
|
162
|
+
}
|
|
163
|
+
return [...names]
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function fetchProviderResponse(
|
|
167
|
+
fetchImpl: NonNullable<ProviderOptions['fetchOverride']>,
|
|
168
|
+
init: RequestInit,
|
|
169
|
+
timeoutMs: number,
|
|
170
|
+
): Promise<Response> {
|
|
171
|
+
const controller = new AbortController()
|
|
172
|
+
const upstreamSignal = init.signal
|
|
173
|
+
const abortFromUpstream = () => {
|
|
174
|
+
controller.abort(upstreamSignal?.reason)
|
|
175
|
+
}
|
|
176
|
+
if (upstreamSignal?.aborted) {
|
|
177
|
+
controller.abort(upstreamSignal.reason)
|
|
178
|
+
} else {
|
|
179
|
+
upstreamSignal?.addEventListener('abort', abortFromUpstream, { once: true })
|
|
180
|
+
}
|
|
181
|
+
let timeoutId: ReturnType<typeof setTimeout> | undefined
|
|
182
|
+
const timeout = new Promise<never>((_, reject) => {
|
|
183
|
+
timeoutId = setTimeout(() => {
|
|
184
|
+
controller.abort()
|
|
185
|
+
reject(new ProviderStreamIdleTimeoutError(timeoutMs))
|
|
186
|
+
}, timeoutMs)
|
|
187
|
+
})
|
|
188
|
+
try {
|
|
189
|
+
return await Promise.race([
|
|
190
|
+
fetchImpl(FRIENDLI_CHAT_COMPLETIONS_URL, {
|
|
191
|
+
...init,
|
|
192
|
+
signal: controller.signal,
|
|
193
|
+
}),
|
|
194
|
+
timeout,
|
|
195
|
+
])
|
|
196
|
+
} finally {
|
|
197
|
+
if (timeoutId !== undefined) clearTimeout(timeoutId)
|
|
198
|
+
upstreamSignal?.removeEventListener('abort', abortFromUpstream)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getInitialReasoningModeSetting,
|
|
3
|
+
providerReasoningPayload,
|
|
4
|
+
resolveKExaoneReasoningPolicy,
|
|
5
|
+
} from '../../../utils/kExaoneReasoning.js'
|
|
6
|
+
|
|
7
|
+
export function providerReasoningRequestPayload(): {
|
|
8
|
+
readonly chat_template_kwargs: { readonly enable_thinking: boolean }
|
|
9
|
+
readonly parse_reasoning: boolean
|
|
10
|
+
readonly include_reasoning: boolean
|
|
11
|
+
} {
|
|
12
|
+
const envResolvedPolicy = resolveKExaoneReasoningPolicy()
|
|
13
|
+
if (
|
|
14
|
+
envResolvedPolicy.source === 'env' ||
|
|
15
|
+
envResolvedPolicy.source === 'legacy-env'
|
|
16
|
+
) {
|
|
17
|
+
return providerReasoningPayload(envResolvedPolicy)
|
|
18
|
+
}
|
|
19
|
+
return providerReasoningPayload(
|
|
20
|
+
resolveKExaoneReasoningPolicy({
|
|
21
|
+
userSettingsMode: getInitialReasoningModeSetting(),
|
|
22
|
+
}),
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { z } from 'zod/v4'
|
|
2
|
+
import type { Tool } from '../../../Tool.js'
|
|
3
|
+
import type {
|
|
4
|
+
OpenAITool,
|
|
5
|
+
ProviderOptions,
|
|
6
|
+
ProviderRequest,
|
|
7
|
+
QueryModelParams,
|
|
8
|
+
} from './types.js'
|
|
9
|
+
import { latestUserText, transcriptToOpenAIMessages } from './messages.js'
|
|
10
|
+
import {
|
|
11
|
+
selectProviderToolChoiceName,
|
|
12
|
+
selectProviderTools,
|
|
13
|
+
} from './toolSelection.js'
|
|
14
|
+
import type { ProviderTurnEvidenceContext } from './evidence.js'
|
|
15
|
+
import {
|
|
16
|
+
hasCurrentTurnLocationContext,
|
|
17
|
+
selectionTextWithPriorLocationContext,
|
|
18
|
+
} from './selectionContext.js'
|
|
19
|
+
import { providerReasoningRequestPayload } from './reasoning.js'
|
|
20
|
+
|
|
21
|
+
function forcedToolChoiceSystemInstruction(toolName: string): string {
|
|
22
|
+
if (toolName === 'workspace_bash') {
|
|
23
|
+
return [
|
|
24
|
+
`Mandatory tool call: the host selected ${toolName} for this turn.`,
|
|
25
|
+
'Do not answer with prose, do not ask a follow-up question, and do not choose another tool.',
|
|
26
|
+
`Emit exactly one ${toolName} tool call with valid JSON arguments.`,
|
|
27
|
+
'For sequenced shell requests, emit the next concrete shell command requested by the user rather than a status summary.',
|
|
28
|
+
'If the user asks to attempt a destructive command and says they will deny the permission prompt, still emit that destructive command so the host permission gate can prompt and enforce the denial.',
|
|
29
|
+
'Do not replace a requested delete command with ls/find/path-existence prose, and preserve leading dots in hidden paths such as .omo/...',
|
|
30
|
+
].join(' ')
|
|
31
|
+
}
|
|
32
|
+
return `Mandatory tool call: the host selected ${toolName} for this turn. Do not answer with prose, do not ask a follow-up question, and do not choose another tool. Emit exactly one ${toolName} tool call with valid JSON arguments.`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function schemaForTool(tool: Tool): Record<string, unknown> {
|
|
36
|
+
if (tool.inputJSONSchema) {
|
|
37
|
+
return normalizeProviderParameterSchema(tool.inputJSONSchema)
|
|
38
|
+
}
|
|
39
|
+
const generatedSchema = z.toJSONSchema(tool.inputSchema)
|
|
40
|
+
return normalizeProviderParameterSchema(
|
|
41
|
+
isJsonObject(generatedSchema) ? generatedSchema : {},
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function normalizeProviderParameterSchema(
|
|
46
|
+
schema: Record<string, unknown>,
|
|
47
|
+
): Record<string, unknown> {
|
|
48
|
+
const normalized = normalizeSchemaNode(schema, schema, new Set<string>())
|
|
49
|
+
if (isJsonObject(normalized)) return normalized
|
|
50
|
+
return providerSafeUnresolvedRefSchema()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function normalizeSchemaNode(
|
|
54
|
+
value: unknown,
|
|
55
|
+
root: Record<string, unknown>,
|
|
56
|
+
refStack: ReadonlySet<string>,
|
|
57
|
+
): unknown {
|
|
58
|
+
if (Array.isArray(value)) {
|
|
59
|
+
return value.map(item => normalizeSchemaNode(item, root, refStack))
|
|
60
|
+
}
|
|
61
|
+
if (!isJsonObject(value)) return value
|
|
62
|
+
|
|
63
|
+
const ref = typeof value.$ref === 'string' ? value.$ref : undefined
|
|
64
|
+
if (ref !== undefined) {
|
|
65
|
+
const inlined = inlineLocalSchemaRef(ref, value, root, refStack)
|
|
66
|
+
if (inlined !== undefined) return inlined
|
|
67
|
+
return providerSafeUnresolvedRefSchema()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const normalized: Record<string, unknown> = {}
|
|
71
|
+
for (const [key, child] of Object.entries(value)) {
|
|
72
|
+
if (key === '$defs' || key === 'definitions') continue
|
|
73
|
+
normalized[key] = normalizeSchemaNode(child, root, refStack)
|
|
74
|
+
}
|
|
75
|
+
return normalized
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function inlineLocalSchemaRef(
|
|
79
|
+
ref: string,
|
|
80
|
+
schemaWithRef: Record<string, unknown>,
|
|
81
|
+
root: Record<string, unknown>,
|
|
82
|
+
refStack: ReadonlySet<string>,
|
|
83
|
+
): unknown | undefined {
|
|
84
|
+
if (refStack.has(ref)) return undefined
|
|
85
|
+
const resolved = resolveLocalSchemaRef(root, ref)
|
|
86
|
+
if (resolved === undefined) return undefined
|
|
87
|
+
const nextStack = new Set(refStack)
|
|
88
|
+
nextStack.add(ref)
|
|
89
|
+
const normalizedResolved = normalizeSchemaNode(resolved, root, nextStack)
|
|
90
|
+
if (!isJsonObject(normalizedResolved)) return normalizedResolved
|
|
91
|
+
|
|
92
|
+
const normalizedSiblings: Record<string, unknown> = {}
|
|
93
|
+
for (const [key, child] of Object.entries(schemaWithRef)) {
|
|
94
|
+
if (key === '$ref' || key === '$defs' || key === 'definitions') continue
|
|
95
|
+
normalizedSiblings[key] = normalizeSchemaNode(child, root, nextStack)
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
...normalizedResolved,
|
|
99
|
+
...normalizedSiblings,
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function resolveLocalSchemaRef(
|
|
104
|
+
root: Record<string, unknown>,
|
|
105
|
+
ref: string,
|
|
106
|
+
): unknown | undefined {
|
|
107
|
+
if (ref === '#') return root
|
|
108
|
+
if (!ref.startsWith('#/')) return undefined
|
|
109
|
+
|
|
110
|
+
let current: unknown = root
|
|
111
|
+
for (const segment of ref.slice(2).split('/').map(decodeJsonPointerSegment)) {
|
|
112
|
+
if (!isJsonObject(current)) return undefined
|
|
113
|
+
current = current[segment]
|
|
114
|
+
}
|
|
115
|
+
return current
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function decodeJsonPointerSegment(segment: string): string {
|
|
119
|
+
return segment.replace(/~1/g, '/').replace(/~0/g, '~')
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function providerSafeUnresolvedRefSchema(): Record<string, unknown> {
|
|
123
|
+
return {
|
|
124
|
+
type: 'object',
|
|
125
|
+
description:
|
|
126
|
+
'Provider-safe open object for an unresolved local schema reference.',
|
|
127
|
+
properties: {},
|
|
128
|
+
additionalProperties: true,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function isJsonObject(value: unknown): value is Record<string, unknown> {
|
|
133
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function toolToOpenAI(tool: Tool): OpenAITool {
|
|
137
|
+
return {
|
|
138
|
+
type: 'function',
|
|
139
|
+
function: {
|
|
140
|
+
name: tool.name,
|
|
141
|
+
description: tool.searchHint ?? tool.name,
|
|
142
|
+
parameters: schemaForTool(tool),
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function toolChoiceFor(
|
|
148
|
+
toolName: string | undefined,
|
|
149
|
+
): ProviderRequest['tool_choice'] {
|
|
150
|
+
if (toolName === undefined) return undefined
|
|
151
|
+
return {
|
|
152
|
+
type: 'function',
|
|
153
|
+
function: { name: toolName },
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function buildProviderRequest(
|
|
158
|
+
params: QueryModelParams,
|
|
159
|
+
evidenceContext?: ProviderTurnEvidenceContext,
|
|
160
|
+
): ProviderRequest {
|
|
161
|
+
const forcedToolName =
|
|
162
|
+
params.options.toolChoice?.type === 'tool'
|
|
163
|
+
? params.options.toolChoice.name
|
|
164
|
+
: undefined
|
|
165
|
+
const userText = selectionTextWithPriorLocationContext(params.messages)
|
|
166
|
+
const selectedToolChoiceName = selectProviderToolChoiceName({
|
|
167
|
+
tools: params.tools,
|
|
168
|
+
userText,
|
|
169
|
+
forcedToolName,
|
|
170
|
+
})
|
|
171
|
+
const tools = selectProviderTools({
|
|
172
|
+
tools: params.tools,
|
|
173
|
+
userText,
|
|
174
|
+
forcedToolName: selectedToolChoiceName,
|
|
175
|
+
disabledToolNames: params.options.disabledProviderToolNames ?? [],
|
|
176
|
+
querySource: params.options.querySource,
|
|
177
|
+
hasCurrentTurnLocationContext: hasCurrentTurnLocationContext(params.messages),
|
|
178
|
+
evidenceContext,
|
|
179
|
+
})
|
|
180
|
+
const toolChoice = toolChoiceFor(selectedToolChoiceName)
|
|
181
|
+
const toolPayload = tools.map(toolToOpenAI)
|
|
182
|
+
return {
|
|
183
|
+
model: params.options.model,
|
|
184
|
+
stream: true,
|
|
185
|
+
...providerReasoningRequestPayload(),
|
|
186
|
+
messages: transcriptToOpenAIMessages(
|
|
187
|
+
params.messages,
|
|
188
|
+
params.systemPrompt,
|
|
189
|
+
selectedToolChoiceName
|
|
190
|
+
? forcedToolChoiceSystemInstruction(selectedToolChoiceName)
|
|
191
|
+
: undefined,
|
|
192
|
+
),
|
|
193
|
+
...(toolPayload.length > 0 ? { tools: toolPayload } : {}),
|
|
194
|
+
...(toolChoice ? { tool_choice: toolChoice } : {}),
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function getAPIMetadata(): Record<string, string> {
|
|
199
|
+
return { user_id: 'ummaya-local' }
|
|
200
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import type { Message } from '../../../types/message.js'
|
|
2
|
+
import { latestUserText } from './messages.js'
|
|
3
|
+
|
|
4
|
+
const RELATIVE_LOCATION_PROMPT_RE =
|
|
5
|
+
/(주위|주변|인근|가까운|우리\s*동네|여기|이\s*근처|현재\s*위치|내\s*위치)/iu
|
|
6
|
+
const RELATIVE_HEALTH_PROMPT_RE =
|
|
7
|
+
/(응급|응급실|응급의료|병원|의원|진료|야간진료|약국|의료|건강|아파|다쳤|발열|hospital|clinic|pharmacy|emergency|ER)/iu
|
|
8
|
+
|
|
9
|
+
type ToolResultBlock = {
|
|
10
|
+
readonly type: 'tool_result'
|
|
11
|
+
readonly content?: unknown
|
|
12
|
+
readonly isError: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
16
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function asToolResultBlock(value: unknown): ToolResultBlock | undefined {
|
|
20
|
+
if (!isRecord(value)) return undefined
|
|
21
|
+
if (value.type !== 'tool_result') return undefined
|
|
22
|
+
return {
|
|
23
|
+
type: 'tool_result',
|
|
24
|
+
content: value.content,
|
|
25
|
+
isError: value.is_error === true,
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parseJsonObject(value: unknown): Record<string, unknown> | undefined {
|
|
30
|
+
if (isRecord(value)) return value
|
|
31
|
+
if (typeof value !== 'string' || !value.trim()) return undefined
|
|
32
|
+
try {
|
|
33
|
+
const parsed: unknown = JSON.parse(value)
|
|
34
|
+
return isRecord(parsed) ? parsed : undefined
|
|
35
|
+
} catch {
|
|
36
|
+
return undefined
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function textField(
|
|
41
|
+
source: Record<string, unknown>,
|
|
42
|
+
fieldName: string,
|
|
43
|
+
): string | undefined {
|
|
44
|
+
const value = source[fieldName]
|
|
45
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function numberField(
|
|
49
|
+
source: Record<string, unknown>,
|
|
50
|
+
fieldName: string,
|
|
51
|
+
): string | undefined {
|
|
52
|
+
const value = source[fieldName]
|
|
53
|
+
return typeof value === 'number' && Number.isFinite(value) ? String(value) : undefined
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function fieldIndicatesFailure(value: unknown): boolean {
|
|
57
|
+
if (value === false) return true
|
|
58
|
+
if (typeof value !== 'string') return false
|
|
59
|
+
return /(error|fail|failed|failure|timeout|denied|unavailable|invalid)/iu.test(
|
|
60
|
+
value.trim(),
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function hasExplicitFailure(source: Record<string, unknown>): boolean {
|
|
65
|
+
if (fieldIndicatesFailure(source.ok)) return true
|
|
66
|
+
if (fieldIndicatesFailure(source.success)) return true
|
|
67
|
+
if (fieldIndicatesFailure(source.status)) return true
|
|
68
|
+
const error = source.error
|
|
69
|
+
if (typeof error === 'string') return error.trim().length > 0
|
|
70
|
+
return error !== undefined && error !== null && error !== false
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function payloadHasExplicitFailure(payload: Record<string, unknown>): boolean {
|
|
74
|
+
if (hasExplicitFailure(payload)) return true
|
|
75
|
+
const data = recordField(payload, 'data')
|
|
76
|
+
return data !== undefined && hasExplicitFailure(data)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function recordField(
|
|
80
|
+
source: Record<string, unknown>,
|
|
81
|
+
fieldName: string,
|
|
82
|
+
): Record<string, unknown> | undefined {
|
|
83
|
+
const value = source[fieldName]
|
|
84
|
+
return isRecord(value) ? value : undefined
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function firstTextField(
|
|
88
|
+
sources: readonly Record<string, unknown>[],
|
|
89
|
+
fieldNames: readonly string[],
|
|
90
|
+
): string | undefined {
|
|
91
|
+
for (const source of sources) {
|
|
92
|
+
for (const fieldName of fieldNames) {
|
|
93
|
+
const value = textField(source, fieldName)
|
|
94
|
+
if (value !== undefined) return value
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return undefined
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function firstNumberField(
|
|
101
|
+
sources: readonly Record<string, unknown>[],
|
|
102
|
+
fieldNames: readonly string[],
|
|
103
|
+
): string | undefined {
|
|
104
|
+
for (const source of sources) {
|
|
105
|
+
for (const fieldName of fieldNames) {
|
|
106
|
+
const value = numberField(source, fieldName)
|
|
107
|
+
if (value !== undefined) return value
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return undefined
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function locationCandidateRecords(
|
|
114
|
+
result: Record<string, unknown>,
|
|
115
|
+
): readonly Record<string, unknown>[] {
|
|
116
|
+
const candidates = [result]
|
|
117
|
+
for (const slot of ['coords', 'poi', 'region', 'address', 'adm_cd'] as const) {
|
|
118
|
+
const nested = recordField(result, slot)
|
|
119
|
+
if (nested !== undefined) candidates.push(nested)
|
|
120
|
+
}
|
|
121
|
+
return candidates
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function locationContextFromPayload(
|
|
125
|
+
payload: Record<string, unknown>,
|
|
126
|
+
): string | undefined {
|
|
127
|
+
if (payloadHasExplicitFailure(payload)) return undefined
|
|
128
|
+
const data = isRecord(payload.data) ? payload.data : undefined
|
|
129
|
+
const result = isRecord(payload.result)
|
|
130
|
+
? payload.result
|
|
131
|
+
: data !== undefined && isRecord(data.result)
|
|
132
|
+
? data.result
|
|
133
|
+
: data ?? payload
|
|
134
|
+
const candidates = locationCandidateRecords(result)
|
|
135
|
+
const latitude = firstNumberField(candidates, ['lat', 'latitude'])
|
|
136
|
+
const longitude = firstNumberField(candidates, ['lon', 'longitude'])
|
|
137
|
+
const x =
|
|
138
|
+
firstTextField(candidates, ['x']) ??
|
|
139
|
+
firstNumberField(candidates, ['x', 'nx'])
|
|
140
|
+
const y =
|
|
141
|
+
firstTextField(candidates, ['y']) ??
|
|
142
|
+
firstNumberField(candidates, ['y', 'ny'])
|
|
143
|
+
const regionName =
|
|
144
|
+
firstTextField(candidates, ['rdd_da_name', 'address_name', 'name']) ??
|
|
145
|
+
[
|
|
146
|
+
firstTextField(candidates, ['region_1depth_name']),
|
|
147
|
+
firstTextField(candidates, ['region_2depth_name']),
|
|
148
|
+
firstTextField(candidates, ['region_3depth_name']),
|
|
149
|
+
]
|
|
150
|
+
.filter(Boolean)
|
|
151
|
+
.join(' ')
|
|
152
|
+
.trim()
|
|
153
|
+
const address =
|
|
154
|
+
firstTextField(candidates, ['road_address', 'jibun_address'])
|
|
155
|
+
if (!latitude && !longitude && !x && !y && !regionName && !address) {
|
|
156
|
+
return undefined
|
|
157
|
+
}
|
|
158
|
+
return [
|
|
159
|
+
'[prior_location_context]',
|
|
160
|
+
regionName ? `region=${regionName}` : undefined,
|
|
161
|
+
address ? `address=${address}` : undefined,
|
|
162
|
+
latitude && longitude ? `lat=${latitude} lon=${longitude}` : undefined,
|
|
163
|
+
x && y ? `x=${x} y=${y}` : undefined,
|
|
164
|
+
]
|
|
165
|
+
.filter(Boolean)
|
|
166
|
+
.join(' ')
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function latestPriorLocationContext(messages: readonly Message[]): string | undefined {
|
|
170
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
171
|
+
const message = messages[index]
|
|
172
|
+
if (message?.type !== 'user') continue
|
|
173
|
+
const content = message.message.content
|
|
174
|
+
if (!Array.isArray(content)) continue
|
|
175
|
+
for (const block of content) {
|
|
176
|
+
const toolResult = asToolResultBlock(block)
|
|
177
|
+
if (toolResult === undefined) continue
|
|
178
|
+
if (toolResult.isError) continue
|
|
179
|
+
const parsed = parseJsonObject(toolResult.content)
|
|
180
|
+
if (parsed === undefined) continue
|
|
181
|
+
const context = locationContextFromPayload(parsed)
|
|
182
|
+
if (context !== undefined) return context
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return undefined
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function userTextForSelectionIndex(message: Message): string {
|
|
189
|
+
const content = message.message.content
|
|
190
|
+
if (typeof content === 'string') return content.trim()
|
|
191
|
+
if (!Array.isArray(content)) return ''
|
|
192
|
+
return content
|
|
193
|
+
.filter(isRecord)
|
|
194
|
+
.filter(block => block.type === 'text' && typeof block.text === 'string')
|
|
195
|
+
.map(block => String(block.text))
|
|
196
|
+
.join('')
|
|
197
|
+
.trim()
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function latestCitizenTextIndex(messages: readonly Message[]): number {
|
|
201
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
202
|
+
const message = messages[index]
|
|
203
|
+
if (message?.type !== 'user' || message.isMeta === true) continue
|
|
204
|
+
if (userTextForSelectionIndex(message).length > 0) return index
|
|
205
|
+
}
|
|
206
|
+
return -1
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function hasCurrentTurnLocationContext(
|
|
210
|
+
messages: readonly Message[],
|
|
211
|
+
): boolean {
|
|
212
|
+
const latestIndex = latestCitizenTextIndex(messages)
|
|
213
|
+
if (latestIndex < 0) return false
|
|
214
|
+
for (let index = latestIndex + 1; index < messages.length; index += 1) {
|
|
215
|
+
const message = messages[index]
|
|
216
|
+
if (message?.type !== 'user') continue
|
|
217
|
+
const content = message.message.content
|
|
218
|
+
if (!Array.isArray(content)) continue
|
|
219
|
+
for (const block of content) {
|
|
220
|
+
const toolResult = asToolResultBlock(block)
|
|
221
|
+
if (toolResult === undefined) continue
|
|
222
|
+
if (toolResult.isError) continue
|
|
223
|
+
const parsed = parseJsonObject(toolResult.content)
|
|
224
|
+
if (parsed !== undefined && locationContextFromPayload(parsed) !== undefined) {
|
|
225
|
+
return true
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return false
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function selectionTextWithPriorLocationContext(
|
|
233
|
+
messages: readonly Message[],
|
|
234
|
+
): string {
|
|
235
|
+
const latest = latestUserText(messages)
|
|
236
|
+
if (!RELATIVE_LOCATION_PROMPT_RE.test(latest)) return latest
|
|
237
|
+
if (!RELATIVE_HEALTH_PROMPT_RE.test(latest)) return latest
|
|
238
|
+
const locationContext = latestPriorLocationContext(messages)
|
|
239
|
+
return locationContext === undefined ? latest : `${latest}\n${locationContext}`
|
|
240
|
+
}
|