@vellumai/assistant 0.10.12 → 0.11.0-staging.1
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/AGENTS.md +1 -1
- package/ARCHITECTURE.md +4 -5
- package/README.md +1 -1
- package/docs/architecture/memory.md +60 -23
- package/docs/error-handling.md +3 -3
- package/docs/guardian-request-flow.md +112 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/app.d.ts +28 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/app.d.ts.map +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.d.ts +2 -2
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.d.ts.map +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.js.map +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/message.d.ts +2 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/message.d.ts.map +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/package.json +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
- package/node_modules/@vellumai/gateway-client/package.json +1 -1
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +6 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +34 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
- package/openapi.yaml +246 -10
- package/package.json +2 -2
- package/src/__tests__/acp-session.test.ts +3 -3
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +3 -0
- package/src/__tests__/anthropic-provider.test.ts +40 -0
- package/src/__tests__/approval-cascade.test.ts +5 -5
- package/src/__tests__/approval-routes-http.test.ts +3 -3
- package/src/__tests__/ask-question-resolver.test.ts +207 -0
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +16 -16
- package/src/__tests__/assistant-event-hub-targeted.test.ts +13 -11
- package/src/__tests__/assistant-event-hub.test.ts +13 -11
- package/src/__tests__/assistant-event.test.ts +12 -9
- package/src/__tests__/assistant-feature-flag-guard.test.ts +3 -3
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +1 -1
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -58
- package/src/__tests__/assistant-stream-state.test.ts +17 -7
- package/src/__tests__/avatar-identity-sync.test.ts +3 -3
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
- package/src/__tests__/call-conversation-messages.test.ts +134 -18
- package/src/__tests__/call-start-guardian-guard.test.ts +27 -0
- package/src/__tests__/channel-approvals.test.ts +0 -27
- package/src/__tests__/channel-guardian.test.ts +85 -512
- package/src/__tests__/channel-readiness-slack-remote.test.ts +151 -3
- package/src/__tests__/channel-retry-sweep.test.ts +88 -1
- package/src/__tests__/channel-setup-panel-ack.test.ts +12 -9
- package/src/__tests__/chat-reveal-guard-priming.test.ts +31 -34
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +2 -2
- package/src/__tests__/compaction-events.test.ts +8 -8
- package/src/__tests__/config-loader-platform-defaults.test.ts +54 -28
- package/src/__tests__/config-model-image-provider.test.ts +20 -0
- package/src/__tests__/config-schema-memory-substrate.test.ts +306 -0
- package/src/__tests__/config-schema.test.ts +14 -2
- package/src/__tests__/config-set-platform-guard.test.ts +11 -12
- package/src/__tests__/config-sounds-sync.test.ts +4 -4
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +5 -0
- package/src/__tests__/context-search-memory-source.test.ts +1 -1
- package/src/__tests__/context-search-memory-v2-source.test.ts +6 -6
- package/src/__tests__/context-token-estimator.test.ts +54 -1
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +12 -3
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +13 -4
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +4 -4
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +22 -13
- package/src/__tests__/conversation-agent-loop.test.ts +39 -30
- package/src/__tests__/conversation-confirmation-signals.test.ts +14 -14
- package/src/__tests__/conversation-evictor.test.ts +49 -0
- package/src/__tests__/conversation-fork-crud.test.ts +1 -1
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +5 -5
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +5 -5
- package/src/__tests__/conversation-message-sync-tags.test.ts +4 -4
- package/src/__tests__/conversation-queue.test.ts +81 -81
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +8 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +8 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +10 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +29 -2
- package/src/__tests__/conversation-slash-queue.test.ts +11 -11
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -2
- package/src/__tests__/conversation-speed-override.test.ts +2 -2
- package/src/__tests__/conversation-summarize-route.test.ts +9 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +18 -16
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +17 -17
- package/src/__tests__/conversation-surfaces-app-open.test.ts +7 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +7 -7
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +9 -9
- package/src/__tests__/conversation-surfaces-standalone.test.ts +12 -12
- package/src/__tests__/conversation-surfaces-state-update.test.ts +8 -5
- package/src/__tests__/conversation-surfaces-table-action.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +46 -46
- package/src/__tests__/conversation-sync-tags.test.ts +5 -5
- package/src/__tests__/conversation-wait-for-idle.test.ts +2 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -3
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -3
- package/src/__tests__/copy-composer-tc-templates.test.ts +3 -131
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/daemon-assistant-events.test.ts +14 -15
- package/src/__tests__/db-test-helpers.ts +13 -27
- package/src/__tests__/disk-pressure-routes.test.ts +12 -3
- package/src/__tests__/document-tool-security.test.ts +95 -0
- package/src/__tests__/drain-kick-guard.test.ts +232 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +19 -6
- package/src/__tests__/emit-event-signal.test.ts +5 -6
- package/src/__tests__/encrypted-store-test-helpers.ts +10 -20
- package/src/__tests__/events-tail-route.test.ts +6 -4
- package/src/__tests__/feature-flag-test-helpers.ts +10 -20
- package/src/__tests__/file-edit-tool.test.ts +24 -4
- package/src/__tests__/file-list-tool.test.ts +2 -1
- package/src/__tests__/file-read-tool.test.ts +62 -10
- package/src/__tests__/file-write-tool.test.ts +24 -5
- package/src/__tests__/followup-tools.test.ts +58 -0
- package/src/__tests__/gateway-threshold-reader-mock.ts +99 -0
- package/src/__tests__/graph-extraction-event-date.test.ts +1 -1
- package/src/__tests__/guardian-question-mode.test.ts +42 -3
- package/src/__tests__/guardian-reply-router-answer-mode.test.ts +283 -0
- package/src/__tests__/guardian-vellum-destination-pinning.test.ts +221 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +10 -10
- package/src/__tests__/host-browser-proxy.test.ts +1 -1
- package/src/__tests__/host-file-edit-tool.test.ts +3 -3
- package/src/__tests__/host-file-read-tool.test.ts +2 -2
- package/src/__tests__/host-file-write-tool.test.ts +7 -3
- package/src/__tests__/host-shell-tool.test.ts +17 -5
- package/src/__tests__/host-transfer-pending-interactions.test.ts +8 -8
- package/src/__tests__/image-credentials.test.ts +65 -8
- package/src/__tests__/injection-block.test.ts +4 -4
- package/src/__tests__/injector-chain.test.ts +1 -1
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
- package/src/__tests__/injector-registry-order-guard.test.ts +4 -9
- package/src/__tests__/injector-v3-suppression.test.ts +6 -4
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +27 -28
- package/src/__tests__/list-messages-page-latest.test.ts +2 -2
- package/src/__tests__/llm-usage-store.test.ts +67 -4
- package/src/__tests__/log-redact.test.ts +18 -0
- package/src/__tests__/managed-profile-guard.test.ts +27 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +62 -11
- package/src/__tests__/memory-identity-context-parity.test.ts +1 -1
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +9 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +4 -4
- package/src/__tests__/notification-decision-strategy.test.ts +115 -11
- package/src/__tests__/notification-deep-link.test.ts +12 -12
- package/src/__tests__/notification-vellum-adapter.test.ts +8 -8
- package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
- package/src/__tests__/path-policy.test.ts +315 -0
- package/src/__tests__/pending-interactions-resolved-event.test.ts +6 -6
- package/src/__tests__/persistence-layering-guard.test.ts +2 -2
- package/src/__tests__/pkb-autoinject.test.ts +1 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -0
- package/src/__tests__/plugin-event-hub-facade.test.ts +22 -15
- package/src/__tests__/plugin-import-boundary-guard.test.ts +15 -15
- package/src/__tests__/processing-flag-persist-failure.test.ts +0 -4
- package/src/__tests__/provider-platform-proxy-integration.test.ts +0 -1
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
- package/src/__tests__/request-secret-standalone-channel-gate.test.ts +5 -5
- package/src/__tests__/require-fresh-approval.test.ts +38 -38
- package/src/__tests__/run-due-schedules.test.ts +72 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +11 -10
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/schedule-routes.test.ts +44 -5
- package/src/__tests__/schedule-store.test.ts +3 -3
- package/src/__tests__/schedule-tools.test.ts +176 -0
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +3 -3
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +3 -3
- package/src/__tests__/secret-response-routing.test.ts +3 -3
- package/src/__tests__/secret-routes-platform-proxy.test.ts +4 -7
- package/src/__tests__/secret-scanner.test.ts +36 -0
- package/src/__tests__/send-endpoint-busy.test.ts +7 -7
- package/src/__tests__/slack-required-scopes-mirror.test.ts +81 -0
- package/src/__tests__/starter-task-flow.test.ts +6 -3
- package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
- package/src/__tests__/subagent-disposal.test.ts +40 -11
- package/src/__tests__/subagent-fork-notifications.test.ts +4 -4
- package/src/__tests__/subagent-fork-prompt-role.test.ts +3 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +4 -4
- package/src/__tests__/subagent-manager-notify.test.ts +73 -14
- package/src/__tests__/subagent-notify-parent.test.ts +48 -4
- package/src/__tests__/subagent-spawn-and-await.test.ts +62 -14
- package/src/__tests__/subagent-tools.test.ts +64 -0
- package/src/__tests__/sync-message-contract.test.ts +3 -3
- package/src/__tests__/terminal-tools.test.ts +12 -3
- package/src/__tests__/test-preload.ts +9 -0
- package/src/__tests__/tool-approval-handler.test.ts +583 -43
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +7 -4
- package/src/__tests__/tool-executor.test.ts +116 -0
- package/src/__tests__/tool-grant-request-escalation.test.ts +5 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +32 -29
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +5 -5
- package/src/__tests__/tool-start-timestamp.test.ts +4 -4
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -22
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +13 -13
- package/src/__tests__/ui-work-result-surface.test.ts +3 -3
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +6 -6
- package/src/__tests__/voice-session-bridge.test.ts +44 -44
- package/src/__tests__/workspace-migration-134-image-generation-mode-to-provider.test.ts +284 -0
- package/src/__tests__/workspace-policy.test.ts +399 -0
- package/src/acp/__tests__/client-handler.test.ts +3 -3
- package/src/acp/__tests__/session-manager-persistence.test.ts +10 -10
- package/src/acp/__tests__/session-manager-resume.test.ts +7 -7
- package/src/acp/client-handler.ts +3 -3
- package/src/acp/session-manager.ts +8 -8
- package/src/api/events/subagent-event.ts +2 -2
- package/src/api/responses/memory-v2-activation-log.ts +2 -2
- package/src/approvals/AGENTS.md +2 -0
- package/src/approvals/guardian-request-resolvers.ts +118 -24
- package/src/calls/__tests__/voice-control-protocol.test.ts +57 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +158 -4
- package/src/calls/__tests__/voice-triage-escalate.test.ts +3 -4
- package/src/calls/call-controller.ts +27 -27
- package/src/calls/call-conversation-messages.ts +58 -18
- package/src/calls/voice-control-protocol.ts +56 -0
- package/src/calls/voice-session-bridge.ts +156 -58
- package/src/calls/voice-triage-escalate.ts +2 -3
- package/src/channels/config.ts +8 -0
- package/src/channels/types.ts +1 -0
- package/src/cli/commands/config.ts +49 -13
- package/src/cli/commands/memory/index.help.ts +4 -2
- package/src/cli/commands/memory/memory-retrospective.ts +5 -0
- package/src/cli/lib/bundled-marketplace.json +12 -0
- package/src/cli.ts +2 -109
- package/src/config/__tests__/deployment-context-defaults.test.ts +9 -0
- package/src/config/__tests__/substrate-twin-shadowing.test.ts +191 -0
- package/src/config/assistant-feature-flags.ts +1 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +13 -7
- package/src/config/feature-flag-cache.ts +6 -16
- package/src/config/feature-flag-registry.json +14 -30
- package/src/config/loader.ts +7 -1
- package/src/config/memory-tier.ts +15 -10
- package/src/config/memory-v3-gate.test.ts +278 -1
- package/src/config/memory-v3-gate.ts +88 -26
- package/src/config/raw-config-utils.ts +1 -1
- package/src/config/schemas/__tests__/live-voice.test.ts +27 -16
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/live-voice.ts +33 -7
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-retrospective.ts +13 -0
- package/src/config/schemas/memory-substrate.ts +183 -0
- package/src/config/schemas/memory-v2.ts +3 -2
- package/src/config/schemas/memory-v3.ts +11 -4
- package/src/config/schemas/memory.ts +35 -1
- package/src/config/schemas/services.ts +10 -2
- package/src/config/substrate-twin-shadowing.ts +195 -0
- package/src/config/webhook-routing.ts +67 -0
- package/src/context/compactor.ts +10 -3
- package/src/context/token-estimator.ts +21 -0
- package/src/daemon/__tests__/channel-ui-capability.test.ts +85 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +3 -3
- package/src/daemon/__tests__/embedding-reconcile.test.ts +3 -3
- package/src/daemon/__tests__/inference-profile-notification.test.ts +3 -6
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +5 -5
- package/src/daemon/__tests__/web-search-status-text.test.ts +2 -2
- package/src/daemon/channel-ui-capability.ts +70 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +4 -4
- package/src/daemon/conversation-agent-loop.ts +12 -5
- package/src/daemon/conversation-evictor.ts +26 -4
- package/src/daemon/conversation-launch.ts +11 -14
- package/src/daemon/conversation-messaging.ts +14 -14
- package/src/daemon/conversation-notifiers.ts +2 -2
- package/src/daemon/conversation-process.ts +133 -21
- package/src/daemon/conversation-queue-manager.ts +7 -7
- package/src/daemon/conversation-runtime-assembly.ts +16 -0
- package/src/daemon/conversation-store.ts +11 -3
- package/src/daemon/conversation-surfaces.ts +4 -4
- package/src/daemon/conversation-tool-setup.ts +13 -7
- package/src/daemon/conversation-usage.ts +12 -11
- package/src/daemon/conversation.ts +38 -15
- package/src/daemon/disk-pressure-guard.ts +5 -12
- package/src/daemon/embedding-reconcile.ts +14 -9
- package/src/daemon/handlers/config-channels.ts +40 -134
- package/src/daemon/handlers/config-model.ts +15 -7
- package/src/daemon/handlers/conversations.ts +4 -2
- package/src/daemon/handlers/shared.ts +29 -0
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/lifecycle.ts +13 -0
- package/src/daemon/message-protocol.ts +8 -144
- package/src/daemon/message-types/computer-use.ts +0 -12
- package/src/daemon/message-types/conversations.ts +9 -345
- package/src/daemon/message-types/host-app-control.ts +0 -9
- package/src/daemon/message-types/host-browser.ts +0 -7
- package/src/daemon/message-types/host-ui-snapshot.ts +0 -7
- package/src/daemon/message-types/messages.ts +0 -48
- package/src/daemon/message-types/notifications.ts +0 -7
- package/src/daemon/message-types/skills.ts +0 -5
- package/src/daemon/message-types/surfaces.ts +0 -9
- package/src/daemon/message-types/sync.ts +0 -2
- package/src/daemon/process-message.ts +5 -5
- package/src/daemon/skill-memory-refresh.ts +5 -5
- package/src/daemon/tool-side-effects.ts +13 -13
- package/src/daemon/trust-context.ts +1 -1
- package/src/daemon/wake-conversation-ops.ts +4 -4
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +100 -7
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +67 -0
- package/src/heartbeat/heartbeat-run-store.ts +81 -4
- package/src/heartbeat/heartbeat-service.ts +32 -1
- package/src/home/__tests__/feed-writer.test.ts +7 -7
- package/src/home/__tests__/home-content-refresh.test.ts +3 -0
- package/src/home/__tests__/suggested-prompts.test.ts +1 -0
- package/src/home/feed-writer.ts +6 -13
- package/src/home/home-content-refresh.ts +6 -9
- package/src/home/relationship-state-writer.ts +5 -12
- package/src/home/suggested-prompts-cache.ts +6 -19
- package/src/ipc/__tests__/events-publish-client.test.ts +67 -0
- package/src/ipc/events-publish-client.ts +44 -0
- package/src/ipc/routes/__tests__/conversation-sync-ipc-routes.test.ts +2 -2
- package/src/ipc/routes/__tests__/events-ipc-routes.test.ts +38 -9
- package/src/ipc/routes/events-ipc-routes.ts +11 -31
- package/src/live-voice/__tests__/front-decision.test.ts +4 -176
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +276 -68
- package/src/live-voice/__tests__/live-voice-events.test.ts +6 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +185 -46
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +24 -59
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +38 -54
- package/src/live-voice/__tests__/live-voice-vad.test.ts +218 -422
- package/src/live-voice/front-decision.ts +5 -155
- package/src/live-voice/live-voice-metrics.ts +4 -1
- package/src/live-voice/live-voice-session.ts +650 -333
- package/src/live-voice/progress-phrases.ts +17 -0
- package/src/live-voice/protocol.ts +15 -0
- package/src/media/app-icon-generator.ts +15 -8
- package/src/media/avatar-router.ts +9 -5
- package/src/media/image-credentials.ts +42 -10
- package/src/media/image-service.ts +1 -13
- package/src/media/types.ts +26 -3
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/__tests__/broadcaster.test.ts +95 -0
- package/src/notifications/adapters/macos.ts +3 -3
- package/src/notifications/broadcaster.ts +57 -0
- package/src/notifications/copy-composer.ts +0 -15
- package/src/notifications/decision-engine.ts +21 -22
- package/src/notifications/guardian-question-mode.ts +57 -2
- package/src/notifications/home-feed-side-effect.ts +4 -0
- package/src/notifications/signal.ts +6 -4
- package/src/notifications/trusted-contact-payloads.ts +3 -4
- package/src/notifications/vellum-card-affinity.ts +39 -0
- package/src/oauth/AGENTS.md +1 -1
- package/src/permissions/channel-permission-query.test.ts +69 -0
- package/src/permissions/channel-permission-query.ts +73 -1
- package/src/permissions/checker.test.ts +85 -9
- package/src/permissions/checker.ts +17 -22
- package/src/permissions/confirmation-guardian-request.test.ts +2 -2
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/gateway-threshold-reader.test.ts +224 -17
- package/src/permissions/gateway-threshold-reader.ts +82 -10
- package/src/permissions/ipc-risk-types.ts +8 -0
- package/src/permissions/prompter.ts +5 -5
- package/src/permissions/question-guardian-request.test.ts +222 -0
- package/src/permissions/question-guardian-request.ts +179 -0
- package/src/permissions/question-prompter.test.ts +8 -8
- package/src/permissions/question-prompter.ts +18 -0
- package/src/permissions/secret-prompter.ts +2 -4
- package/src/permissions/workspace-policy.ts +236 -34
- package/src/persistence/__tests__/lifecycle-quiesce.test.ts +82 -0
- package/src/persistence/__tests__/message-content-file.test.ts +58 -3
- package/src/persistence/conversation-crud.ts +93 -0
- package/src/persistence/conversation-key-store.ts +63 -0
- package/src/persistence/db-async-query.ts +1 -1
- package/src/persistence/db-singleton.ts +14 -27
- package/src/persistence/delivery-crud.ts +45 -0
- package/src/persistence/embeddings/embedding-backend.ts +2 -1
- package/src/persistence/embeddings/embedding-identity.ts +7 -3
- package/src/persistence/job-utils.ts +32 -27
- package/src/persistence/jobs-store.ts +92 -3
- package/src/persistence/lifecycle-quiesce.ts +80 -0
- package/src/persistence/llm-usage-store.ts +45 -8
- package/src/persistence/message-content-file.ts +4 -4
- package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +1 -1
- package/src/persistence/migrations/351-schedule-skill-script-handoff.ts +39 -0
- package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.test.ts +83 -0
- package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.ts +36 -0
- package/src/persistence/migrations/353-add-llm-usage-conversation-type.test.ts +110 -0
- package/src/persistence/migrations/353-add-llm-usage-conversation-type.ts +49 -0
- package/src/persistence/schema/infrastructure.ts +11 -0
- package/src/persistence/steps.ts +7 -1
- package/src/plugin-api/__tests__/publish-event-forwarding.test.ts +113 -0
- package/src/plugin-api/__tests__/publish-event.test.ts +57 -0
- package/src/plugin-api/conversation-turn.ts +4 -4
- package/src/plugin-api/event-hub-facade.ts +15 -6
- package/src/plugin-api/index.ts +10 -4
- package/src/plugin-api/publish-event.ts +36 -0
- package/src/plugins/AGENTS.md +2 -0
- package/src/plugins/defaults/compaction/window-manager.ts +9 -0
- package/src/plugins/defaults/index.ts +9 -13
- package/src/plugins/defaults/memory/AGENTS.md +775 -0
- package/src/plugins/defaults/memory/__tests__/capability-seed-embed-gate.test.ts +186 -0
- package/src/plugins/defaults/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/indexer-tier-dispatch.test.ts +129 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-quiesce-gate.test.ts +91 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v1-graph-substrate-noop.test.ts +342 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +9 -1
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +36 -1
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-sweep-defer.test.ts +9 -1
- package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +44 -10
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +151 -10
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1155 -0
- package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -3
- package/src/plugins/defaults/memory/__tests__/tools-delete-memory-page.test.ts +1 -1
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +71 -35
- package/src/plugins/defaults/memory/context-search/sources/memory.ts +5 -1
- package/src/plugins/defaults/memory/fork-conversation-memory.ts +4 -4
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +80 -10
- package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +1 -1
- package/src/plugins/defaults/memory/graph/capability-seed.ts +24 -10
- package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +123 -49
- package/src/plugins/defaults/memory/graph/graph-search.ts +6 -118
- package/src/plugins/defaults/memory/graph/in-context-tracker.test.ts +173 -0
- package/src/plugins/defaults/memory/graph/in-context-tracker.ts +109 -0
- package/src/plugins/defaults/memory/graph/store.ts +1 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.test.ts +1 -1
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +5 -2
- package/src/plugins/defaults/memory/graph-topology/__tests__/build-memory-graph.test.ts +1 -1
- package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +6 -9
- package/src/plugins/defaults/memory/hooks/__tests__/user-prompt-submit.test.ts +30 -16
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +18 -14
- package/src/plugins/defaults/memory/indexer.ts +146 -89
- package/src/plugins/defaults/memory/injectors.ts +86 -41
- package/src/plugins/defaults/memory/job-handlers.ts +130 -39
- package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +2 -2
- package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +22 -10
- package/src/plugins/defaults/memory/jobs-worker.ts +279 -208
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +4 -2
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +40 -3
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +99 -11
- package/src/plugins/defaults/memory/src/__tests__/memory-v2-routes.test.ts +5 -3
- package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +3 -4
- package/src/plugins/defaults/memory/src/memory-graph-routes.ts +2 -1
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +7 -5
- package/src/plugins/defaults/memory/src/memory-item-routes.ts +51 -19
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +31 -20
- package/src/plugins/defaults/memory/startup.ts +58 -21
- package/src/plugins/defaults/memory/substrate/__tests__/boot-maintenance.test.ts +335 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/cli-command-store.test.ts +14 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-job.test.ts +51 -21
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/edge-index.test.ts +1 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/frontmatter-sweep.test.ts +3 -3
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-index.test.ts +1 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-store.test.ts +1 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/prompts-consolidation.test.ts +2 -2
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/qdrant.test.ts +23 -14
- package/src/plugins/defaults/memory/substrate/__tests__/reembed-job.test.ts +262 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sim.test.ts +9 -12
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-content.test.ts +2 -2
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-store.test.ts +9 -9
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sparse-bm25.test.ts +12 -5
- package/src/plugins/defaults/memory/substrate/__tests__/spread.test.ts +276 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/static-context.test.ts +17 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sweep-job.test.ts +9 -9
- package/src/plugins/defaults/memory/{v3/substrate/memory-v2-startup.ts → substrate/boot-maintenance.ts} +43 -24
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-store.ts +13 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/consolidation-job.ts +51 -27
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/constants.ts +1 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/edge-index.ts +28 -9
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/frontmatter-sweep.ts +14 -7
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/injected-block-slugs.ts +9 -3
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-index.ts +29 -10
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-store.ts +35 -12
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/consolidation.ts +14 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/sweep.ts +4 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/qdrant.ts +96 -36
- package/src/plugins/defaults/memory/substrate/reembed-job.ts +54 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/sim.ts +26 -15
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-content.ts +1 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-store.ts +13 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/sparse-bm25.ts +27 -10
- package/src/plugins/defaults/memory/substrate/spread.ts +165 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/static-context.ts +12 -7
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/sweep-job.ts +20 -15
- package/src/plugins/defaults/memory/substrate/tuning.ts +93 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/types.ts +7 -4
- package/src/plugins/defaults/memory/tools.test.ts +1 -1
- package/src/plugins/defaults/memory/tools.ts +1 -1
- package/src/plugins/defaults/memory/v1/README.md +5 -0
- package/src/plugins/defaults/memory/{__tests__ → v1/__tests__}/filing-jobs.test.ts +4 -4
- package/src/plugins/defaults/memory/{filing-jobs.ts → v1/filing-jobs.ts} +3 -3
- package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.test.ts +68 -6
- package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.ts +40 -21
- package/src/plugins/defaults/memory/{graph → v1/graph}/consolidation.ts +14 -14
- package/src/plugins/defaults/memory/{graph → v1/graph}/decay.test.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/decay.ts +3 -3
- package/src/plugins/defaults/memory/{graph → v1/graph}/extraction-job.ts +5 -5
- package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.test.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.ts +20 -14
- package/src/plugins/defaults/memory/{graph → v1/graph}/graph-search.test.ts +3 -3
- package/src/plugins/defaults/memory/v1/graph/graph-search.ts +123 -0
- package/src/plugins/defaults/memory/{graph → v1/graph}/injection.test.ts +1 -118
- package/src/plugins/defaults/memory/{graph → v1/graph}/injection.ts +9 -111
- package/src/plugins/defaults/memory/{graph → v1/graph}/narrative.ts +6 -6
- package/src/plugins/defaults/memory/{graph → v1/graph}/pattern-scan.ts +5 -5
- package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.test.ts +135 -42
- package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.ts +40 -22
- package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.test.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/serendipity.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.test.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.ts +1 -1
- package/src/plugins/defaults/memory/{identity-context.ts → v1/identity-context.ts} +4 -4
- package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/backfill.ts +6 -6
- package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.test.ts +6 -6
- package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.ts +6 -6
- package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/index-maintenance.ts +8 -8
- package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.test.ts +7 -7
- package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.ts +5 -5
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/autoinject.ts +1 -1
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/context.ts +2 -2
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.test.ts +3 -3
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.ts +2 -2
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.test.ts +3 -3
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.ts +2 -2
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.test.ts +3 -3
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.ts +6 -6
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/types.ts +3 -5
- package/src/plugins/defaults/memory/{pkb-schedule.ts → v1/pkb-schedule.ts} +2 -2
- package/src/plugins/defaults/memory/{search/semantic.ts → v1/semantic-search.ts} +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/activation-store.test.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/activation.test.ts +11 -274
- package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +9 -131
- package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +14 -10
- package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +7 -5
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +12 -6
- package/src/plugins/defaults/memory/{memory-v2-activation-log-store.ts → v2/activation-log-store.ts} +2 -2
- package/src/plugins/defaults/memory/v2/activation-store.ts +22 -8
- package/src/plugins/defaults/memory/v2/activation.ts +30 -163
- package/src/plugins/defaults/memory/v2/backfill-jobs.ts +7 -54
- package/src/plugins/defaults/memory/{memory-v2-concept-frequency.ts → v2/concept-frequency.ts} +3 -3
- package/src/plugins/defaults/memory/v2/harness/oracle.ts +1 -1
- package/src/plugins/defaults/memory/v2/harness/replay-input.ts +2 -2
- package/src/plugins/defaults/memory/v2/harness/retriever.ts +1 -1
- package/src/plugins/defaults/memory/v2/injection.ts +36 -26
- package/src/plugins/defaults/memory/v2/migration.ts +2 -2
- package/src/plugins/defaults/memory/{rerank-local.ts → v2/rerank-local.ts} +44 -18
- package/src/plugins/defaults/memory/v2/reranker.ts +29 -11
- package/src/plugins/defaults/memory/v2/router.ts +38 -15
- package/src/plugins/defaults/memory/v3/__tests__/candidate-match.test.ts +5 -3
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +21 -8
- package/src/plugins/defaults/memory/v3/__tests__/edge.test.ts +1 -1
- package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +1 -1
- package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +4 -1
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +181 -3
- package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +3 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +14 -5
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +40 -50
- package/src/plugins/defaults/memory/v3/__tests__/tuning-profile.test.ts +1 -0
- package/src/plugins/defaults/memory/v3/candidate-match.ts +2 -2
- package/src/plugins/defaults/memory/v3/capabilities.ts +6 -4
- package/src/plugins/defaults/memory/v3/card.ts +25 -9
- package/src/plugins/defaults/memory/v3/edge.ts +52 -18
- package/src/plugins/defaults/memory/v3/gate.ts +4 -4
- package/src/plugins/defaults/memory/v3/injector.ts +10 -3
- package/src/plugins/defaults/memory/v3/maintain-job.ts +3 -3
- package/src/plugins/defaults/memory/v3/orchestrate.ts +100 -18
- package/src/plugins/defaults/memory/v3/page-content.ts +26 -10
- package/src/plugins/defaults/memory/v3/prune.ts +40 -16
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +34 -12
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +9 -13
- package/src/plugins/defaults/memory/v3/span-query.test.ts +86 -0
- package/src/plugins/defaults/memory/v3/span-query.ts +71 -0
- package/src/plugins/defaults/memory/v3/tuning-profile.ts +3 -0
- package/src/plugins/defaults/memory/v3/types.ts +4 -1
- package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +2 -2
- package/src/plugins/defaults/memory/validation.ts +1 -1
- package/src/plugins/defaults/memory/worker.ts +2 -1
- package/src/plugins/defaults/platform-hosted/__tests__/reengage.test.ts +104 -12
- package/src/plugins/defaults/platform-hosted/routes/reengage.ts +104 -12
- package/src/plugins/types.ts +2 -2
- package/src/providers/__tests__/registry-native-web-search.test.ts +47 -2
- package/src/providers/anthropic/client.ts +15 -6
- package/src/providers/content-block-schema.ts +26 -0
- package/src/providers/inference/__tests__/connections-credential-normalize.test.ts +87 -0
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/inference/connections.ts +30 -14
- package/src/providers/model-catalog.ts +77 -0
- package/src/providers/openai/__tests__/chat-completions-input-audio.test.ts +260 -0
- package/src/providers/openai/chat-completions-provider.ts +65 -17
- package/src/providers/openai/input-audio.ts +76 -0
- package/src/providers/openrouter/client.ts +0 -2
- package/src/providers/platform-proxy/constants.ts +4 -0
- package/src/providers/poolside/client.ts +42 -0
- package/src/providers/registry.ts +40 -8
- package/src/providers/retry.ts +2 -0
- package/src/providers/types.ts +39 -1
- package/src/providers/vercel-ai-gateway/client.ts +0 -2
- package/src/runtime/AGENTS.md +7 -5
- package/src/runtime/__tests__/question-request-guardian-bridge.test.ts +173 -0
- package/src/runtime/__tests__/question-resolution.test.ts +111 -0
- package/src/runtime/access-request-helper.ts +7 -15
- package/src/runtime/assistant-event-hub.ts +43 -31
- package/src/runtime/assistant-event-publish-options.ts +31 -0
- package/src/runtime/assistant-event.ts +19 -30
- package/src/runtime/assistant-stream-state.ts +4 -4
- package/src/runtime/channel-approvals.ts +0 -25
- package/src/runtime/channel-readiness-service.ts +99 -40
- package/src/runtime/channel-retry-sweep.ts +38 -15
- package/src/runtime/confirmation-request-guardian-bridge.ts +4 -0
- package/src/runtime/guardian-reply-router.ts +108 -0
- package/src/runtime/http-server.ts +8 -0
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/process-role.ts +42 -0
- package/src/runtime/question-request-guardian-bridge.ts +184 -0
- package/src/runtime/question-resolution.ts +153 -0
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +6 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -1
- package/src/runtime/routes/acp-routes.ts +2 -2
- package/src/runtime/routes/bookmark-routes.ts +3 -15
- package/src/runtime/routes/canned-message-complete.ts +2 -2
- package/src/runtime/routes/consolidation-routes.ts +8 -2
- package/src/runtime/routes/conversation-list-routes.ts +3 -19
- package/src/runtime/routes/conversation-management-routes.ts +1 -5
- package/src/runtime/routes/conversation-query-routes.ts +52 -8
- package/src/runtime/routes/conversation-routes.ts +36 -22
- package/src/runtime/routes/credential-request-routes.ts +0 -1
- package/src/runtime/routes/filing-routes.ts +7 -7
- package/src/runtime/routes/global-search-routes.ts +1 -1
- package/src/runtime/routes/guardian-approval-prompt.ts +2 -2
- package/src/runtime/routes/image-generation-routes.ts +12 -9
- package/src/runtime/routes/inbound-message-handler.ts +17 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +50 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +19 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -4
- package/src/runtime/routes/inbound-stages/inbound-content-prep.test.ts +129 -0
- package/src/runtime/routes/inbound-stages/inbound-content-prep.ts +141 -9
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/lifecycle-routes.ts +199 -0
- package/src/runtime/routes/platform-routes.ts +3 -8
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +7 -7
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +5 -5
- package/src/runtime/routes/question-routes.ts +34 -87
- package/src/runtime/routes/secret-routes.ts +11 -1
- package/src/runtime/routes/settings-routes.ts +8 -18
- package/src/runtime/routes/upgrade-broadcast-routes.ts +4 -5
- package/src/runtime/routes/workspace-routes.test.ts +7 -4
- package/src/runtime/slack-reply-session.test.ts +12 -12
- package/src/runtime/slack-reply-session.ts +17 -17
- package/src/runtime/sync/sync-publisher.test.ts +7 -5
- package/src/runtime/tool-grant-request-helper.ts +4 -0
- package/src/schedule/schedule-store.ts +70 -0
- package/src/schedule/scheduler.ts +27 -0
- package/src/security/AGENTS.md +1 -1
- package/src/security/credential-key.ts +17 -0
- package/src/security/secret-ingress.ts +14 -105
- package/src/security/secret-patterns.ts +8 -139
- package/src/security/secret-scanner.ts +8 -3
- package/src/security/store-path-override.ts +6 -16
- package/src/sequence/store.ts +8 -0
- package/src/signals/emit-event.ts +5 -10
- package/src/signals/event-stream.ts +20 -10
- package/src/subagent/manager.ts +76 -25
- package/src/subagent/notify.ts +8 -0
- package/src/subagent/types.ts +13 -3
- package/src/telegram/__tests__/webhook-health.test.ts +442 -0
- package/src/telegram/webhook-health.ts +478 -0
- package/src/telemetry/AGENTS.md +6 -0
- package/src/telemetry/memory-corpus-size.test.ts +129 -0
- package/src/telemetry/memory-corpus-size.ts +184 -0
- package/src/telemetry/memory-tier-reporter.test.ts +67 -2
- package/src/telemetry/memory-tier-reporter.ts +30 -3
- package/src/tools/__tests__/document-tool-input-schemas.test.ts +103 -0
- package/src/tools/__tests__/followup-call-acp-tool-input-schemas.test.ts +125 -0
- package/src/tools/__tests__/schedule-tool-input-schemas.test.ts +83 -0
- package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +116 -0
- package/src/tools/__tests__/tool-input-schemas.test.ts +192 -0
- package/src/tools/__tests__/tool-schema-drift-harness.ts +142 -0
- package/src/tools/acp/abort.ts +21 -1
- package/src/tools/acp/context.ts +5 -5
- package/src/tools/acp/spawn.test.ts +15 -5
- package/src/tools/acp/spawn.ts +26 -3
- package/src/tools/acp/status.ts +20 -1
- package/src/tools/acp/steer.test.ts +20 -0
- package/src/tools/acp/steer.ts +23 -2
- package/src/tools/ask-question/ask-question-tool.test.ts +65 -0
- package/src/tools/ask-question/ask-question-tool.ts +68 -92
- package/src/tools/browser/browser-screencast.ts +6 -6
- package/src/tools/calls/call-end.ts +24 -3
- package/src/tools/calls/call-start.ts +35 -11
- package/src/tools/calls/call-status.ts +20 -1
- package/src/tools/document/document-comment-tool.test.ts +49 -0
- package/src/tools/document/document-comment-tool.ts +45 -6
- package/src/tools/document/document-tool.ts +142 -24
- package/src/tools/executor.ts +27 -13
- package/src/tools/filesystem/edit.ts +62 -60
- package/src/tools/filesystem/list.ts +36 -29
- package/src/tools/filesystem/read.ts +56 -39
- package/src/tools/filesystem/write.ts +44 -38
- package/src/tools/followups/followup_create.ts +41 -12
- package/src/tools/followups/followup_list.ts +34 -6
- package/src/tools/followups/followup_resolve.ts +26 -4
- package/src/tools/host-filesystem/edit.ts +50 -60
- package/src/tools/host-filesystem/read.ts +45 -39
- package/src/tools/host-filesystem/write.ts +31 -36
- package/src/tools/host-terminal/host-shell.ts +76 -62
- package/src/tools/policy-context.ts +27 -10
- package/src/tools/schedule/create.ts +76 -33
- package/src/tools/schedule/delete.ts +21 -2
- package/src/tools/schedule/list.ts +25 -3
- package/src/tools/schedule/update.ts +105 -48
- package/src/tools/shared/filesystem/path-policy.ts +246 -40
- package/src/tools/shared/zod-tool-schema.ts +117 -0
- package/src/tools/subagent/abort.ts +12 -4
- package/src/tools/subagent/consult-deadline.ts +9 -3
- package/src/tools/subagent/message.ts +21 -5
- package/src/tools/subagent/notify-parent.ts +44 -23
- package/src/tools/subagent/read.ts +15 -4
- package/src/tools/subagent/resolve.ts +26 -4
- package/src/tools/subagent/spawn.ts +37 -13
- package/src/tools/subagent/status.ts +12 -4
- package/src/tools/system/request-permission.ts +35 -26
- package/src/tools/terminal/shell.ts +68 -55
- package/src/tools/tool-approval-handler.ts +327 -53
- package/src/tools/tool-input-schemas.ts +85 -0
- package/src/tools/tool-types.ts +7 -0
- package/src/tools/types.ts +8 -0
- package/src/tools/workflows/manage-workflows.ts +30 -2
- package/src/tools/workflows/run-workflow.test.ts +54 -2
- package/src/tools/workflows/run-workflow.ts +32 -4
- package/src/util/fs-symlinks.ts +30 -0
- package/src/util/log-redact.ts +7 -3
- package/src/vellum-assistant-namespace.d.ts +80 -0
- package/src/watcher/watcher-store.ts +8 -0
- package/src/workflows/leaf-runner.test.ts +104 -2
- package/src/workflows/leaf-runner.ts +31 -6
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +2 -2
- package/src/workspace/migrations/134-image-generation-mode-to-provider.ts +128 -0
- package/src/workspace/migrations/135-copy-substrate-tunables.ts +248 -0
- package/src/workspace/migrations/__tests__/135-copy-substrate-tunables.test.ts +446 -0
- package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +2 -2
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/memory-retrieval-budget.test.ts +0 -49
- package/src/__tests__/secret-patterns.test.ts +0 -27
- package/src/config/__tests__/proc-to-skills.test.ts +0 -21
- package/src/config/memory-tier.test.ts +0 -44
- package/src/daemon/message-types/acp.ts +0 -20
- package/src/daemon/message-types/apps.ts +0 -11
- package/src/daemon/message-types/background-tools.ts +0 -14
- package/src/daemon/message-types/bookmarks.ts +0 -13
- package/src/daemon/message-types/contacts.ts +0 -13
- package/src/daemon/message-types/document-comments.ts +0 -14
- package/src/daemon/message-types/documents.ts +0 -13
- package/src/daemon/message-types/home.ts +0 -15
- package/src/daemon/message-types/host-bash.ts +0 -12
- package/src/daemon/message-types/host-cu.ts +0 -10
- package/src/daemon/message-types/host-file.ts +0 -12
- package/src/daemon/message-types/host-transfer.ts +0 -12
- package/src/daemon/message-types/integrations.ts +0 -90
- package/src/daemon/message-types/memory.ts +0 -10
- package/src/daemon/message-types/schedules.ts +0 -14
- package/src/daemon/message-types/settings.ts +0 -17
- package/src/daemon/message-types/subagents.ts +0 -63
- package/src/daemon/message-types/upgrades.ts +0 -14
- package/src/daemon/message-types/workflows.ts +0 -25
- package/src/daemon/message-types/workspace.ts +0 -137
- package/src/live-voice/ack-phrases.ts +0 -58
- package/src/plugins/defaults/memory/retrieval-budget.ts +0 -29
- package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +0 -69
- package/src/plugins/defaults/memory/v3/gate-flag.ts +0 -20
- package/src/plugins/defaults/memory/v3/substrate/__tests__/memory-v2-startup.test.ts +0 -86
- package/src/plugins/defaults/memory/v3/substrate/memory-v2-startup.test.ts +0 -205
- /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/concept-page-frontmatter-schema.test.ts +0 -0
- /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-prompt-flag-gating-guard.test.ts +0 -0
- /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/injected-block-slugs.test.ts +0 -0
- /package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-content.ts +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { realpathSync } from "node:fs";
|
|
2
|
+
import { homedir, userInfo } from "node:os";
|
|
2
3
|
import {
|
|
3
4
|
basename,
|
|
4
5
|
dirname,
|
|
@@ -8,6 +9,10 @@ import {
|
|
|
8
9
|
resolve,
|
|
9
10
|
} from "node:path";
|
|
10
11
|
|
|
12
|
+
import { getIsContainerized } from "../../../config/env-registry.js";
|
|
13
|
+
import { resolveTrailingLinkTarget } from "../../../util/fs-symlinks.js";
|
|
14
|
+
import { getDotEnvPath } from "../../../util/platform.js";
|
|
15
|
+
|
|
11
16
|
/**
|
|
12
17
|
* Result type shared by both sandbox and host path policies.
|
|
13
18
|
*/
|
|
@@ -48,12 +53,15 @@ const CONTAINER_WORKSPACE_EXACT = "/workspace";
|
|
|
48
53
|
/**
|
|
49
54
|
* Resolve symlinks in an absolute path.
|
|
50
55
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
56
|
+
* A trailing (possibly dangling) symlink chain is followed first — see
|
|
57
|
+
* {@link resolveTrailingLinkTarget} — so a link whose destination does not
|
|
58
|
+
* exist yet still reports that destination. For an existing path, returns
|
|
59
|
+
* its `realpathSync`. For a path that does not exist yet (e.g. a
|
|
60
|
+
* `file_write` target), walks up to the nearest existing ancestor, resolves
|
|
61
|
+
* that ancestor via `realpathSync`, then re-appends the trailing
|
|
62
|
+
* (non-existent) components — so a symlink anywhere in the existing prefix
|
|
63
|
+
* is still followed. Falls back to the lexical input when nothing on the
|
|
64
|
+
* path resolves (e.g. the path lives on a filesystem this process cannot
|
|
57
65
|
* see, as with host_file paths proxied to a remote client).
|
|
58
66
|
*
|
|
59
67
|
* Used both for sandbox-boundary enforcement and to canonicalize paths before
|
|
@@ -61,7 +69,7 @@ const CONTAINER_WORKSPACE_EXACT = "/workspace";
|
|
|
61
69
|
* file operation.
|
|
62
70
|
*/
|
|
63
71
|
export function resolveRealPath(absolutePath: string): string {
|
|
64
|
-
let current = absolutePath;
|
|
72
|
+
let current = resolveTrailingLinkTarget(absolutePath);
|
|
65
73
|
const trailing: string[] = [];
|
|
66
74
|
while (current !== dirname(current)) {
|
|
67
75
|
try {
|
|
@@ -79,26 +87,25 @@ export function resolveRealPath(absolutePath: string): string {
|
|
|
79
87
|
// Sandbox policy
|
|
80
88
|
// ---------------------------------------------------------------------------
|
|
81
89
|
|
|
90
|
+
interface SandboxTarget {
|
|
91
|
+
/** Lexically resolved absolute path (boundary-relative input resolved). */
|
|
92
|
+
resolved: string;
|
|
93
|
+
/** Symlink-canonicalized form of `resolved`. */
|
|
94
|
+
realResolved: string;
|
|
95
|
+
/** Symlink-canonicalized boundary directory. */
|
|
96
|
+
realBoundary: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
82
99
|
/**
|
|
83
|
-
* Resolve a user-supplied path against
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* For existing paths, symlinks are resolved via realpathSync so a symlink
|
|
87
|
-
* pointing outside the boundary is caught. For new paths (e.g. file_write),
|
|
88
|
-
* pass `mustExist: false` - the nearest existing ancestor directory is
|
|
89
|
-
* resolved via realpathSync to catch symlinks in parent dirs.
|
|
90
|
-
*
|
|
91
|
-
* Paths starting with `/workspace/` are treated as container-scoped and
|
|
92
|
-
* remapped relative to the boundary directory (the Docker sandbox mounts
|
|
93
|
-
* the host workspace at /workspace).
|
|
100
|
+
* Resolve a user-supplied path against the boundary directory: apply the
|
|
101
|
+
* container /workspace remap, resolve to an absolute path, and canonicalize
|
|
102
|
+
* symlinks on both the target and the boundary.
|
|
94
103
|
*/
|
|
95
|
-
|
|
104
|
+
function resolveSandboxTarget(
|
|
96
105
|
rawPath: string,
|
|
97
106
|
boundaryDir: string,
|
|
98
|
-
|
|
99
|
-
):
|
|
100
|
-
const mustExist = options?.mustExist ?? true;
|
|
101
|
-
|
|
107
|
+
mustExist: boolean,
|
|
108
|
+
): SandboxTarget {
|
|
102
109
|
// Remap container-scoped /workspace paths to the host boundary dir.
|
|
103
110
|
// Skip remapping if the path already starts with boundaryDir to avoid
|
|
104
111
|
// double-nesting (e.g. /workspace/project/file.ts → /workspace/project/project/file.ts
|
|
@@ -114,19 +121,24 @@ export function sandboxPolicy(
|
|
|
114
121
|
|
|
115
122
|
const resolved = resolve(boundaryDir, effectivePath);
|
|
116
123
|
|
|
124
|
+
// Follow a trailing (possibly dangling) symlink chain first — a write
|
|
125
|
+
// through a dangling link creates the link's destination, so the
|
|
126
|
+
// containment and denial checks below must run against it.
|
|
127
|
+
const linkTarget = resolveTrailingLinkTarget(resolved);
|
|
128
|
+
|
|
117
129
|
// Resolve symlinks to catch symlink-based escapes.
|
|
118
130
|
// For mustExist=false, walk up to the nearest existing ancestor and
|
|
119
131
|
// resolve it, then re-append the trailing components.
|
|
120
|
-
let realResolved =
|
|
132
|
+
let realResolved = linkTarget;
|
|
121
133
|
if (mustExist) {
|
|
122
134
|
try {
|
|
123
|
-
realResolved = realpathSync(
|
|
135
|
+
realResolved = realpathSync(linkTarget);
|
|
124
136
|
} catch {
|
|
125
137
|
// File doesn't exist - will be caught by the tool's own existence check
|
|
126
|
-
realResolved =
|
|
138
|
+
realResolved = linkTarget;
|
|
127
139
|
}
|
|
128
140
|
} else {
|
|
129
|
-
realResolved = resolveRealPath(
|
|
141
|
+
realResolved = resolveRealPath(linkTarget);
|
|
130
142
|
}
|
|
131
143
|
|
|
132
144
|
// Resolve the boundary directory's real path too (in case it's a symlink)
|
|
@@ -137,26 +149,220 @@ export function sandboxPolicy(
|
|
|
137
149
|
realBoundary = boundaryDir;
|
|
138
150
|
}
|
|
139
151
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return {
|
|
143
|
-
ok: false,
|
|
144
|
-
reason: "out_of_bounds",
|
|
145
|
-
error: `Path "${rawPath}" resolves to "${realResolved}" which is outside the working directory "${realBoundary}"`,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
152
|
+
return { resolved, realResolved, realBoundary };
|
|
153
|
+
}
|
|
148
154
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
155
|
+
/** Whether the canonicalized target escapes the canonicalized boundary. */
|
|
156
|
+
function isOutOfBounds(target: SandboxTarget): boolean {
|
|
157
|
+
const rel = relative(target.realBoundary, target.realResolved);
|
|
158
|
+
return (
|
|
159
|
+
rel.startsWith("..") ||
|
|
160
|
+
resolve(target.realBoundary, rel) !== target.realResolved
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function outOfBoundsFailure(
|
|
165
|
+
rawPath: string,
|
|
166
|
+
target: SandboxTarget,
|
|
167
|
+
): PathResult {
|
|
168
|
+
return {
|
|
169
|
+
ok: false,
|
|
170
|
+
reason: "out_of_bounds",
|
|
171
|
+
error: `Path "${rawPath}" resolves to "${target.realResolved}" which is outside the working directory "${target.realBoundary}"`,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// The denied check covers both the logical path and the symlink-resolved
|
|
176
|
+
// path so a symlink with a non-denied name pointing at a denied file is
|
|
177
|
+
// still caught.
|
|
178
|
+
function deniedFailure(target: SandboxTarget): PathResult | null {
|
|
179
|
+
if (
|
|
180
|
+
isDeniedBasename(target.resolved) ||
|
|
181
|
+
isDeniedBasename(target.realResolved)
|
|
182
|
+
) {
|
|
152
183
|
return {
|
|
153
184
|
ok: false,
|
|
154
185
|
reason: "denied",
|
|
155
|
-
error: `Access to "${basename(resolved)}" is denied`,
|
|
186
|
+
error: `Access to "${basename(target.resolved)}" is denied`,
|
|
156
187
|
};
|
|
157
188
|
}
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function safeUserInfoHomedir(): string {
|
|
193
|
+
try {
|
|
194
|
+
return userInfo().homedir;
|
|
195
|
+
} catch {
|
|
196
|
+
return "";
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const SECURITY_DIR_ENV_VARS = [
|
|
201
|
+
"GATEWAY_SECURITY_DIR",
|
|
202
|
+
"CREDENTIAL_SECURITY_DIR",
|
|
203
|
+
] as const;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Secret-bearing paths the file tools must never touch, in any policy:
|
|
207
|
+
*
|
|
208
|
+
* - Gateway trust material and token signing keys (GATEWAY_SECURITY_DIR)
|
|
209
|
+
* and CES credential keys (CREDENTIAL_SECURITY_DIR — `keys.enc`,
|
|
210
|
+
* `store.key`). The daemon must never read from or write to them — that
|
|
211
|
+
* data flows through the gateway and CES APIs (root AGENTS.md). The
|
|
212
|
+
* env-based resolution mirrors the owning services', since the
|
|
213
|
+
* cross-package import boundary bars importing it; the shared bare-metal
|
|
214
|
+
* default `<home>/.vellum/protected` is always denied. Only absolute
|
|
215
|
+
* overrides join the set — a relative override is unmirrorable and
|
|
216
|
+
* disables the host fallback outright (see
|
|
217
|
+
* {@link securityDirConfigMirrorable}).
|
|
218
|
+
* - The daemon dotenv (`<vellumRoot>/.env`), which carries provider
|
|
219
|
+
* secrets.
|
|
220
|
+
*/
|
|
221
|
+
function getProtectedServicePaths(): string[] {
|
|
222
|
+
const paths = new Set<string>();
|
|
223
|
+
paths.add(
|
|
224
|
+
join(
|
|
225
|
+
process.env.HOME || safeUserInfoHomedir() || homedir(),
|
|
226
|
+
".vellum",
|
|
227
|
+
"protected",
|
|
228
|
+
),
|
|
229
|
+
);
|
|
230
|
+
for (const name of SECURITY_DIR_ENV_VARS) {
|
|
231
|
+
const override = process.env[name]?.trim();
|
|
232
|
+
if (override && isAbsolute(override)) {
|
|
233
|
+
paths.add(resolve(override));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
paths.add(getDotEnvPath());
|
|
237
|
+
return [...paths];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Whether the security-dir deny set can be mirrored faithfully. A relative
|
|
242
|
+
* override resolves against the owning service's cwd, which this process
|
|
243
|
+
* cannot know — the true directory would be absent from the deny set, so
|
|
244
|
+
* the host fallback fails closed to the hard boundary instead.
|
|
245
|
+
*/
|
|
246
|
+
function securityDirConfigMirrorable(): boolean {
|
|
247
|
+
return SECURITY_DIR_ENV_VARS.every((name) => {
|
|
248
|
+
const override = process.env[name]?.trim();
|
|
249
|
+
return !override || isAbsolute(override);
|
|
250
|
+
});
|
|
251
|
+
}
|
|
158
252
|
|
|
159
|
-
|
|
253
|
+
function isWithinDir(path: string, dir: string): boolean {
|
|
254
|
+
const normalized = dir !== "/" && dir.endsWith("/") ? dir.slice(0, -1) : dir;
|
|
255
|
+
if (normalized === "/") {
|
|
256
|
+
return isAbsolute(path);
|
|
257
|
+
}
|
|
258
|
+
return path === normalized || path.startsWith(normalized + "/");
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Deny a target that lands in (or on) a protected service path. Both the
|
|
263
|
+
* lexical and symlink-resolved target are checked against both the lexical
|
|
264
|
+
* and symlink-resolved protected path, so neither a symlinked target nor a
|
|
265
|
+
* symlinked directory prefix can mask the hit.
|
|
266
|
+
*/
|
|
267
|
+
function securityDirDenial(target: SandboxTarget): PathResult | null {
|
|
268
|
+
for (const protectedPath of getProtectedServicePaths()) {
|
|
269
|
+
const realProtectedPath = resolveRealPath(protectedPath);
|
|
270
|
+
const hit = [target.resolved, target.realResolved].some(
|
|
271
|
+
(path) =>
|
|
272
|
+
isWithinDir(path, protectedPath) ||
|
|
273
|
+
isWithinDir(path, realProtectedPath),
|
|
274
|
+
);
|
|
275
|
+
if (hit) {
|
|
276
|
+
return {
|
|
277
|
+
ok: false,
|
|
278
|
+
reason: "denied",
|
|
279
|
+
error: "Access to the service security directory is denied",
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function evaluateSandboxPolicy(
|
|
287
|
+
rawPath: string,
|
|
288
|
+
boundaryDir: string,
|
|
289
|
+
options: { mustExist?: boolean } | undefined,
|
|
290
|
+
allowOutOfBounds: boolean,
|
|
291
|
+
): PathResult {
|
|
292
|
+
const target = resolveSandboxTarget(
|
|
293
|
+
rawPath,
|
|
294
|
+
boundaryDir,
|
|
295
|
+
options?.mustExist ?? true,
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
if (!allowOutOfBounds && isOutOfBounds(target)) {
|
|
299
|
+
return outOfBoundsFailure(rawPath, target);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Applied unconditionally — even a boundary configured to contain a
|
|
303
|
+
// service security dir must not expose it through the file tools.
|
|
304
|
+
const securityDenied = securityDirDenial(target);
|
|
305
|
+
if (securityDenied) {
|
|
306
|
+
return securityDenied;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const denied = deniedFailure(target);
|
|
310
|
+
if (denied) {
|
|
311
|
+
return denied;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return { ok: true, resolved: target.resolved };
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Resolve a user-supplied path against a boundary directory and verify
|
|
319
|
+
* that the result stays within it.
|
|
320
|
+
*
|
|
321
|
+
* For existing paths, symlinks are resolved via realpathSync so a symlink
|
|
322
|
+
* pointing outside the boundary is caught. For new paths (e.g. file_write),
|
|
323
|
+
* pass `mustExist: false` - the nearest existing ancestor directory is
|
|
324
|
+
* resolved via realpathSync to catch symlinks in parent dirs.
|
|
325
|
+
*
|
|
326
|
+
* Paths starting with `/workspace/` are treated as container-scoped and
|
|
327
|
+
* remapped relative to the boundary directory (the Docker sandbox mounts
|
|
328
|
+
* the host workspace at /workspace).
|
|
329
|
+
*/
|
|
330
|
+
export function sandboxPolicy(
|
|
331
|
+
rawPath: string,
|
|
332
|
+
boundaryDir: string,
|
|
333
|
+
options?: { mustExist?: boolean },
|
|
334
|
+
): PathResult {
|
|
335
|
+
return evaluateSandboxPolicy(rawPath, boundaryDir, options, false);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Sandbox policy that permits out-of-workspace targets on non-containerized
|
|
340
|
+
* installs.
|
|
341
|
+
*
|
|
342
|
+
* Identical to {@link sandboxPolicy} for in-bounds targets. A target that
|
|
343
|
+
* escapes the boundary is allowed with host-style validation: the basename
|
|
344
|
+
* denylist still applies to both the logical and symlink-resolved paths, and
|
|
345
|
+
* the service security directories stay denied outright.
|
|
346
|
+
* The permission lane runs before tool execution and classifies
|
|
347
|
+
* out-of-workspace file operations as elevated risk (see the gateway
|
|
348
|
+
* FileRiskClassifier), so an escape reaching this policy has already been
|
|
349
|
+
* threshold-approved or user-approved.
|
|
350
|
+
*
|
|
351
|
+
* In containerized mode the boundary stays hard: the container filesystem is
|
|
352
|
+
* not the host, and the host_file_* proxy tools are the escape hatch for the
|
|
353
|
+
* guardian's device.
|
|
354
|
+
*/
|
|
355
|
+
export function sandboxPolicyWithHostFallback(
|
|
356
|
+
rawPath: string,
|
|
357
|
+
boundaryDir: string,
|
|
358
|
+
options?: { mustExist?: boolean },
|
|
359
|
+
): PathResult {
|
|
360
|
+
return evaluateSandboxPolicy(
|
|
361
|
+
rawPath,
|
|
362
|
+
boundaryDir,
|
|
363
|
+
options,
|
|
364
|
+
!getIsContainerized() && securityDirConfigMirrorable(),
|
|
365
|
+
);
|
|
160
366
|
}
|
|
161
367
|
|
|
162
368
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import type { ToolExecutionResult } from "../types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Derive a tool's LLM-facing `input_schema` from its Zod input schema, so the
|
|
7
|
+
* schema the model sees and the validation the executor runs share one source
|
|
8
|
+
* and cannot drift (`TOOL_INPUT_SCHEMAS` in `../tool-input-schemas.ts` holds
|
|
9
|
+
* the executor-side half).
|
|
10
|
+
*
|
|
11
|
+
* Conversion uses Zod 4's native `z.toJSONSchema` (mirroring
|
|
12
|
+
* `workflows/leaf-runner.ts`), then adjusts the output for the tool-definition
|
|
13
|
+
* context:
|
|
14
|
+
*
|
|
15
|
+
* - The `$schema` marker is dropped — tool definitions don't carry one.
|
|
16
|
+
* - `additionalProperties` values of `false` / `{}` are dropped. They are
|
|
17
|
+
* authoring artifacts of `z.object` / `z.looseObject`, not intentional
|
|
18
|
+
* contract: runtime validation never rejects unknown keys (registry schemas
|
|
19
|
+
* must tolerate injected fields like `activity`, see
|
|
20
|
+
* `schema-transforms.ts`), so advertising `additionalProperties: false`
|
|
21
|
+
* would claim a strictness the runtime doesn't enforce.
|
|
22
|
+
*
|
|
23
|
+
* `advertiseRequired` names fields to mark required in the advertised schema
|
|
24
|
+
* even though the Zod schema treats them as optional. This is the one
|
|
25
|
+
* sanctioned divergence, and only in the tolerant direction: the model is told
|
|
26
|
+
* to always send the field (e.g. `activity`, which drives status UX), but a
|
|
27
|
+
* call that omits it still executes rather than failing on a field the tool
|
|
28
|
+
* doesn't need.
|
|
29
|
+
*/
|
|
30
|
+
export function toToolInputSchema(
|
|
31
|
+
schema: z.ZodType,
|
|
32
|
+
opts?: { advertiseRequired?: readonly string[] },
|
|
33
|
+
): Record<string, unknown> {
|
|
34
|
+
const json = z.toJSONSchema(schema, { unrepresentable: "any" }) as Record<
|
|
35
|
+
string,
|
|
36
|
+
unknown
|
|
37
|
+
>;
|
|
38
|
+
delete json.$schema;
|
|
39
|
+
stripPermissiveAdditionalProperties(json);
|
|
40
|
+
|
|
41
|
+
for (const field of opts?.advertiseRequired ?? []) {
|
|
42
|
+
const required = Array.isArray(json.required) ? json.required : [];
|
|
43
|
+
if (!required.includes(field)) {
|
|
44
|
+
json.required = [...required, field];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return json;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Recursively remove `additionalProperties` keys whose value is `false` or the
|
|
52
|
+
* empty schema `{}`. A real subschema (e.g. `additionalProperties:
|
|
53
|
+
* { type: "string" }` from `z.record`) is left intact.
|
|
54
|
+
*/
|
|
55
|
+
function stripPermissiveAdditionalProperties(node: unknown): void {
|
|
56
|
+
if (Array.isArray(node)) {
|
|
57
|
+
for (const entry of node) {
|
|
58
|
+
stripPermissiveAdditionalProperties(entry);
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (node === null || typeof node !== "object") {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const record = node as Record<string, unknown>;
|
|
66
|
+
const ap = record.additionalProperties;
|
|
67
|
+
if (
|
|
68
|
+
ap === false ||
|
|
69
|
+
(typeof ap === "object" &&
|
|
70
|
+
ap !== null &&
|
|
71
|
+
!Array.isArray(ap) &&
|
|
72
|
+
Object.keys(ap).length === 0)
|
|
73
|
+
) {
|
|
74
|
+
delete record.additionalProperties;
|
|
75
|
+
}
|
|
76
|
+
for (const value of Object.values(record)) {
|
|
77
|
+
stripPermissiveAdditionalProperties(value);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Wrap an optional field's schema so an explicit `null` parses as "omitted"
|
|
83
|
+
* (`undefined`). Models routinely send `null` for optional fields they mean
|
|
84
|
+
* to skip, and executors read such fields via `input.x ?? fallback`, where
|
|
85
|
+
* null and absent are equivalent — validation must not reject null there.
|
|
86
|
+
* The derived JSON Schema is the inner schema's (the null-tolerance is
|
|
87
|
+
* runtime slack, not advertised contract).
|
|
88
|
+
*/
|
|
89
|
+
export function nullAsOmitted<T extends z.ZodType>(schema: T) {
|
|
90
|
+
return z.preprocess((value) => value ?? undefined, schema.optional());
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Render a failed tool-input parse as a compact `field: message` summary the
|
|
95
|
+
* model can correct from. Mirrors `runtime/routes/parse-body.ts`.
|
|
96
|
+
*/
|
|
97
|
+
export function formatToolInputError(
|
|
98
|
+
toolName: string,
|
|
99
|
+
error: z.ZodError,
|
|
100
|
+
): string {
|
|
101
|
+
const detail = error.issues
|
|
102
|
+
.map((issue) => `${issue.path.join(".") || "(input)"}: ${issue.message}`)
|
|
103
|
+
.join("; ");
|
|
104
|
+
return `Invalid input for tool "${toolName}": ${detail}. Fix the listed field(s) and retry the call.`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Failed-parse tool result for executors that validate their own input (the
|
|
109
|
+
* pre-execution gate in `ToolApprovalHandler` produces the same message, so
|
|
110
|
+
* the error reads identically whichever layer catches it first).
|
|
111
|
+
*/
|
|
112
|
+
export function invalidToolInputResult(
|
|
113
|
+
toolName: string,
|
|
114
|
+
error: z.ZodError,
|
|
115
|
+
): ToolExecutionResult {
|
|
116
|
+
return { content: formatToolInputError(toolName, error), isError: true };
|
|
117
|
+
}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import { getSubagentManager } from "../../subagent/index.js";
|
|
2
|
+
import { invalidToolInputResult } from "../shared/zod-tool-schema.js";
|
|
2
3
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
3
|
-
import { resolveSubagentId } from "./resolve.js";
|
|
4
|
+
import { resolveSubagentId, subagentRefInputSchema } from "./resolve.js";
|
|
5
|
+
|
|
6
|
+
export const subagentAbortInputSchema = subagentRefInputSchema;
|
|
4
7
|
|
|
5
8
|
export async function executeSubagentAbort(
|
|
6
9
|
input: Record<string, unknown>,
|
|
7
10
|
context: ToolContext,
|
|
8
11
|
): Promise<ToolExecutionResult> {
|
|
9
|
-
const
|
|
10
|
-
if (!
|
|
12
|
+
const parsedInput = subagentAbortInputSchema.safeParse(input);
|
|
13
|
+
if (!parsedInput.success) {
|
|
14
|
+
return invalidToolInputResult("subagent_abort", parsedInput.error);
|
|
15
|
+
}
|
|
16
|
+
const parsed = parsedInput.data;
|
|
17
|
+
const subagentId = resolveSubagentId(parsed, context);
|
|
18
|
+
if (!subagentId && parsed.label) {
|
|
11
19
|
return {
|
|
12
|
-
content: `No subagent found with label "${
|
|
20
|
+
content: `No subagent found with label "${parsed.label}".`,
|
|
13
21
|
isError: true,
|
|
14
22
|
};
|
|
15
23
|
}
|
|
@@ -29,8 +29,12 @@ export function createConsultDeadline(opts: {
|
|
|
29
29
|
|
|
30
30
|
const recordProgress = (): void => {
|
|
31
31
|
// Once aborted, don't re-arm — the consult is already being torn down.
|
|
32
|
-
if (controller.signal.aborted)
|
|
33
|
-
|
|
32
|
+
if (controller.signal.aborted) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (idleTimer) {
|
|
36
|
+
clearTimeout(idleTimer);
|
|
37
|
+
}
|
|
34
38
|
idleTimer = setTimeout(() => controller.abort(), opts.idleMs);
|
|
35
39
|
};
|
|
36
40
|
|
|
@@ -41,7 +45,9 @@ export function createConsultDeadline(opts: {
|
|
|
41
45
|
recordProgress();
|
|
42
46
|
|
|
43
47
|
const dispose = (): void => {
|
|
44
|
-
if (idleTimer)
|
|
48
|
+
if (idleTimer) {
|
|
49
|
+
clearTimeout(idleTimer);
|
|
50
|
+
}
|
|
45
51
|
clearTimeout(maxTimer);
|
|
46
52
|
};
|
|
47
53
|
|
|
@@ -1,17 +1,33 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
1
3
|
import { getSubagentManager } from "../../subagent/index.js";
|
|
4
|
+
import {
|
|
5
|
+
invalidToolInputResult,
|
|
6
|
+
nullAsOmitted,
|
|
7
|
+
} from "../shared/zod-tool-schema.js";
|
|
2
8
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
3
|
-
import { resolveSubagentId } from "./resolve.js";
|
|
9
|
+
import { resolveSubagentId, subagentRefInputSchema } from "./resolve.js";
|
|
10
|
+
|
|
11
|
+
export const subagentMessageInputSchema = z.looseObject({
|
|
12
|
+
...subagentRefInputSchema.shape,
|
|
13
|
+
content: nullAsOmitted(z.string()),
|
|
14
|
+
});
|
|
4
15
|
|
|
5
16
|
export async function executeSubagentMessage(
|
|
6
17
|
input: Record<string, unknown>,
|
|
7
18
|
context: ToolContext,
|
|
8
19
|
): Promise<ToolExecutionResult> {
|
|
9
|
-
const
|
|
10
|
-
|
|
20
|
+
const parsedInput = subagentMessageInputSchema.safeParse(input);
|
|
21
|
+
if (!parsedInput.success) {
|
|
22
|
+
return invalidToolInputResult("subagent_message", parsedInput.error);
|
|
23
|
+
}
|
|
24
|
+
const parsed = parsedInput.data;
|
|
25
|
+
const subagentId = resolveSubagentId(parsed, context);
|
|
26
|
+
const content = parsed.content;
|
|
11
27
|
|
|
12
|
-
if (!subagentId &&
|
|
28
|
+
if (!subagentId && parsed.label) {
|
|
13
29
|
return {
|
|
14
|
-
content: `No subagent found with label "${
|
|
30
|
+
content: `No subagent found with label "${parsed.label}".`,
|
|
15
31
|
isError: true,
|
|
16
32
|
};
|
|
17
33
|
}
|
|
@@ -1,17 +1,56 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
1
3
|
import { RiskLevel } from "../../permissions/types.js";
|
|
2
4
|
import { notifyParentFromChild } from "../../subagent/notify.js";
|
|
5
|
+
import {
|
|
6
|
+
invalidToolInputResult,
|
|
7
|
+
nullAsOmitted,
|
|
8
|
+
toToolInputSchema,
|
|
9
|
+
} from "../shared/zod-tool-schema.js";
|
|
3
10
|
import type {
|
|
4
11
|
ToolContext,
|
|
5
12
|
ToolDefinition,
|
|
6
13
|
ToolExecutionResult,
|
|
7
14
|
} from "../types.js";
|
|
8
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Model-input schema, the single source for both runtime validation (via
|
|
18
|
+
* `TOOL_INPUT_SCHEMAS`) and the advertised `input_schema` below. `message`
|
|
19
|
+
* stays runtime-optional (`advertiseRequired`) so the bespoke
|
|
20
|
+
* '"message" is required.' check keeps its test-asserted error; `urgency`
|
|
21
|
+
* catches to `undefined` so a malformed value degrades to "info" instead of
|
|
22
|
+
* forwarding garbage to the parent's notification.
|
|
23
|
+
*/
|
|
24
|
+
export const notifyParentInputSchema = z.looseObject({
|
|
25
|
+
message: nullAsOmitted(
|
|
26
|
+
z.string().describe("The notification content for the parent."),
|
|
27
|
+
),
|
|
28
|
+
urgency: z
|
|
29
|
+
.enum(["info", "important", "blocked"])
|
|
30
|
+
.describe(
|
|
31
|
+
"'info' for progress updates, 'important' for key findings, 'blocked' when you need guidance.",
|
|
32
|
+
)
|
|
33
|
+
.optional()
|
|
34
|
+
.catch(undefined),
|
|
35
|
+
activity: z
|
|
36
|
+
.string()
|
|
37
|
+
.describe(
|
|
38
|
+
"Brief non-technical explanation of what you are doing and why, shown as a status update.",
|
|
39
|
+
)
|
|
40
|
+
.optional()
|
|
41
|
+
.catch(undefined),
|
|
42
|
+
});
|
|
43
|
+
|
|
9
44
|
export async function executeSubagentNotifyParent(
|
|
10
45
|
input: Record<string, unknown>,
|
|
11
46
|
context: ToolContext,
|
|
12
47
|
): Promise<ToolExecutionResult> {
|
|
13
|
-
const
|
|
14
|
-
|
|
48
|
+
const parsed = notifyParentInputSchema.safeParse(input);
|
|
49
|
+
if (!parsed.success) {
|
|
50
|
+
return invalidToolInputResult("notify_parent", parsed.error);
|
|
51
|
+
}
|
|
52
|
+
const message = parsed.data.message;
|
|
53
|
+
const urgency = parsed.data.urgency ?? "info";
|
|
15
54
|
|
|
16
55
|
if (!message) {
|
|
17
56
|
return { content: '"message" is required.', isError: true };
|
|
@@ -41,27 +80,9 @@ export const notifyParentTool = {
|
|
|
41
80
|
executionTarget: "sandbox",
|
|
42
81
|
defaultRiskLevel: RiskLevel.Low,
|
|
43
82
|
|
|
44
|
-
input_schema: {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
message: {
|
|
48
|
-
type: "string",
|
|
49
|
-
description: "The notification content for the parent.",
|
|
50
|
-
},
|
|
51
|
-
urgency: {
|
|
52
|
-
type: "string",
|
|
53
|
-
enum: ["info", "important", "blocked"],
|
|
54
|
-
description:
|
|
55
|
-
"'info' for progress updates, 'important' for key findings, 'blocked' when you need guidance.",
|
|
56
|
-
},
|
|
57
|
-
activity: {
|
|
58
|
-
type: "string",
|
|
59
|
-
description:
|
|
60
|
-
"Brief non-technical explanation of what you are doing and why, shown as a status update.",
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
required: ["message", "activity"],
|
|
64
|
-
},
|
|
83
|
+
input_schema: toToolInputSchema(notifyParentInputSchema, {
|
|
84
|
+
advertiseRequired: ["message", "activity"],
|
|
85
|
+
}),
|
|
65
86
|
|
|
66
87
|
async execute(
|
|
67
88
|
input: Record<string, unknown>,
|
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
import { getMessages } from "../../persistence/conversation-crud.js";
|
|
2
2
|
import { extractTextFromStoredMessageContent } from "../../persistence/message-content.js";
|
|
3
3
|
import { getSubagentManager, TERMINAL_STATUSES } from "../../subagent/index.js";
|
|
4
|
+
import { invalidToolInputResult } from "../shared/zod-tool-schema.js";
|
|
4
5
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
5
|
-
import { resolveSubagentId } from "./resolve.js";
|
|
6
|
+
import { resolveSubagentId, subagentRefInputSchema } from "./resolve.js";
|
|
7
|
+
|
|
8
|
+
// `last_n` is deliberately UNDECLARED (loose passthrough): the executor's
|
|
9
|
+
// typeof-guarded read below ignores it when malformed — including non-integer
|
|
10
|
+
// numbers the advertised `integer` type wouldn't admit.
|
|
11
|
+
export const subagentReadInputSchema = subagentRefInputSchema;
|
|
6
12
|
|
|
7
13
|
export async function executeSubagentRead(
|
|
8
14
|
input: Record<string, unknown>,
|
|
9
15
|
context: ToolContext,
|
|
10
16
|
): Promise<ToolExecutionResult> {
|
|
11
|
-
const
|
|
12
|
-
if (!
|
|
17
|
+
const parsedInput = subagentReadInputSchema.safeParse(input);
|
|
18
|
+
if (!parsedInput.success) {
|
|
19
|
+
return invalidToolInputResult("subagent_read", parsedInput.error);
|
|
20
|
+
}
|
|
21
|
+
const parsed = parsedInput.data;
|
|
22
|
+
const subagentId = resolveSubagentId(parsed, context);
|
|
23
|
+
if (!subagentId && parsed.label) {
|
|
13
24
|
return {
|
|
14
|
-
content: `No subagent found with label "${
|
|
25
|
+
content: `No subagent found with label "${parsed.label}".`,
|
|
15
26
|
isError: true,
|
|
16
27
|
};
|
|
17
28
|
}
|