@vellumai/assistant 0.10.12 → 0.11.0-staging.2
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 +264 -14
- 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__/app-conversation-ids-backfill.test.ts +33 -2
- package/src/__tests__/app-conversation-ids.test.ts +204 -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-group-tools.test.ts +279 -0
- 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-lineage.test.ts +235 -0
- 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__/platform-callback-registration.test.ts +10 -10
- 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__/resolve-app-id.test.ts +32 -0
- 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 +26 -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 +587 -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-side-effects-slack-dm.test.ts +1 -0
- 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 +482 -2
- 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/api/responses/subagent-detail.ts +13 -0
- package/src/approvals/AGENTS.md +2 -0
- package/src/approvals/guardian-request-resolvers.ts +118 -24
- package/src/apps/app-store.ts +95 -4
- package/src/calls/__tests__/voice-control-protocol.test.ts +57 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +229 -7
- 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 +178 -65
- 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/commands/webhooks.help.ts +9 -4
- 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/conversation-groups/SKILL.md +29 -0
- package/src/config/bundled-skills/conversation-groups/TOOLS.json +58 -0
- package/src/config/bundled-skills/conversation-groups/tools/group-create.ts +12 -0
- package/src/config/bundled-skills/conversation-groups/tools/group-list.ts +12 -0
- package/src/config/bundled-skills/conversation-groups/tools/move-to-group.ts +12 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +13 -7
- package/src/config/bundled-skills/schedule/SKILL.md +2 -0
- package/src/config/feature-flag-cache.ts +6 -16
- package/src/config/feature-flag-registry.json +14 -38
- 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-lineage.ts +76 -0
- 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 +8 -14
- 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 +32 -16
- 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-continuation-fork-hydration.test.ts +286 -0
- 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 +1154 -636
- 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 +1288 -439
- 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 +298 -15
- package/src/permissions/checker.ts +102 -36
- 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 +269 -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/conversation-parent.ts +27 -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/migrations/354-backfill-app-conversation-lineage.ts +41 -0
- package/src/persistence/schema/infrastructure.ts +11 -0
- package/src/persistence/steps.ts +9 -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/prompts/sections.ts +4 -16
- 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/__tests__/subagents-routes.test.ts +250 -0
- package/src/runtime/routes/__tests__/webhook-routes.test.ts +201 -0
- 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/subagents-routes.ts +35 -8
- package/src/runtime/routes/upgrade-broadcast-routes.ts +4 -5
- package/src/runtime/routes/webhook-routes.ts +89 -30
- 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__/conversation-group-tool-input-schemas.test.ts +61 -0
- 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/apps/resolve-app-id.ts +15 -3
- 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/conversation-groups/group_create.ts +63 -0
- package/src/tools/conversation-groups/group_list.ts +20 -0
- package/src/tools/conversation-groups/group_shared.ts +52 -0
- package/src/tools/conversation-groups/move_to_group.ts +106 -0
- 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/util/platform.ts +15 -0
- 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/tsconfig.plugin-api.json +1 -1
- 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,5 +1,11 @@
|
|
|
1
1
|
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
installThresholdReaderMock,
|
|
5
|
+
resetThresholdReaderMock,
|
|
6
|
+
thresholdReaderMock,
|
|
7
|
+
} from "./gateway-threshold-reader-mock.js";
|
|
8
|
+
|
|
3
9
|
const testDir = process.env.VELLUM_WORKSPACE_DIR!;
|
|
4
10
|
|
|
5
11
|
// Mock verification control-plane policy -- not targeting control-plane by default
|
|
@@ -22,22 +28,75 @@ const fakeTool = {
|
|
|
22
28
|
execute: async () => ({ content: "ok", isError: false }),
|
|
23
29
|
};
|
|
24
30
|
|
|
31
|
+
/** Same tool class as `fakeTool`, but reaching the guardian's own machine. */
|
|
32
|
+
const fakeHostTool = {
|
|
33
|
+
...fakeTool,
|
|
34
|
+
name: "host_bash",
|
|
35
|
+
executionTarget: "host" as const,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A skill shadowing a core side-effect name. A novel third-party tool name is
|
|
40
|
+
* not a side-effect tool at all, so it never reaches the floor — shadowing is
|
|
41
|
+
* the case where an unvetted manifest lands on a liftable invocation.
|
|
42
|
+
*/
|
|
43
|
+
const fakeSkillTool = {
|
|
44
|
+
...fakeTool,
|
|
45
|
+
name: "document_create",
|
|
46
|
+
category: "documents",
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const fakeTools: Record<string, typeof fakeTool> = {
|
|
50
|
+
bash: fakeTool,
|
|
51
|
+
host_bash: fakeHostTool,
|
|
52
|
+
document_create: fakeSkillTool,
|
|
53
|
+
acme_send: { ...fakeTool, name: "acme_send", category: "messaging" },
|
|
54
|
+
ws_deploy: { ...fakeTool, name: "ws_deploy", category: "workspace" },
|
|
55
|
+
mcp_lookup: { ...fakeTool, name: "mcp_lookup", category: "mcp" },
|
|
56
|
+
file_write: { ...fakeTool, name: "file_write", category: "filesystem" },
|
|
57
|
+
web_fetch: { ...fakeTool, name: "web_fetch", category: "network" },
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/** Registry ownership per tool — drives the extension-owned gate checks. */
|
|
61
|
+
const toolOwners: Record<string, { kind: string; id: string }> = {
|
|
62
|
+
document_create: { kind: "skill", id: "some-skill" },
|
|
63
|
+
acme_send: { kind: "skill", id: "some-skill" },
|
|
64
|
+
ws_deploy: { kind: "workspace", id: "tools/ws-deploy.ts" },
|
|
65
|
+
mcp_lookup: { kind: "mcp", id: "some-server" },
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Per-test owner override for `file_write`, for the workspace-override-of-a-
|
|
70
|
+
* core-name case. `undefined` = unowned built-in, the lift tests' baseline.
|
|
71
|
+
*/
|
|
72
|
+
let fileWriteOwner: { kind: string; id: string } | undefined;
|
|
73
|
+
|
|
25
74
|
mock.module("../tools/registry.js", () => ({
|
|
26
|
-
getTool: (name: string) =>
|
|
27
|
-
resolveTool: (name: string) =>
|
|
28
|
-
getAllTools: () =>
|
|
75
|
+
getTool: (name: string) => fakeTools[name],
|
|
76
|
+
resolveTool: (name: string) => fakeTools[name],
|
|
77
|
+
getAllTools: () => Object.values(fakeTools),
|
|
78
|
+
getToolOwner: (name: string) =>
|
|
79
|
+
name === "file_write" && fileWriteOwner ? fileWriteOwner : toolOwners[name],
|
|
29
80
|
}));
|
|
30
81
|
|
|
31
82
|
// Mock the dynamic-skill predicate so isSensitiveTool's skill_load branch is
|
|
32
83
|
// exercised without a real skill catalog: "dynamic-skill" is an inline-command
|
|
33
84
|
// load, anything else is plain.
|
|
85
|
+
/** Whether the owning skill of the tool under test reports as first-party. */
|
|
86
|
+
let skillOwnerBundled = false;
|
|
87
|
+
|
|
34
88
|
mock.module("../permissions/checker.js", () => ({
|
|
35
89
|
isDynamicSkillLoadInvocation: (
|
|
36
90
|
_name: string,
|
|
37
91
|
input: Record<string, unknown>,
|
|
38
92
|
) => input?.skill === "dynamic-skill",
|
|
93
|
+
isToolOwnerSkillBundled: () => skillOwnerBundled,
|
|
39
94
|
}));
|
|
40
95
|
|
|
96
|
+
// The channel permission-matrix cell is a gateway IPC call; the shared mock
|
|
97
|
+
// makes it per-test controllable and counts lookups.
|
|
98
|
+
installThresholdReaderMock();
|
|
99
|
+
|
|
41
100
|
// Capture tool-audit terminal calls so tests can assert on denied/error outcomes
|
|
42
101
|
// the way they previously asserted on emitted lifecycle events.
|
|
43
102
|
const auditCalls = {
|
|
@@ -60,6 +119,10 @@ function resetAuditCalls(): void {
|
|
|
60
119
|
auditCalls.prompted.length = 0;
|
|
61
120
|
}
|
|
62
121
|
|
|
122
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
123
|
+
import { tmpdir } from "node:os";
|
|
124
|
+
import { join } from "node:path";
|
|
125
|
+
|
|
63
126
|
import {
|
|
64
127
|
mintGrantFromDecision,
|
|
65
128
|
type MintGrantParams,
|
|
@@ -71,8 +134,8 @@ import { scopedApprovalGrants } from "../persistence/schema/index.js";
|
|
|
71
134
|
import { computeToolApprovalDigest } from "../security/tool-approval-digest.js";
|
|
72
135
|
import {
|
|
73
136
|
type ApprovalCellThreshold,
|
|
74
|
-
isSensitiveTool,
|
|
75
137
|
resolveSensitiveToolDecision,
|
|
138
|
+
sensitiveToolReach,
|
|
76
139
|
ToolApprovalHandler,
|
|
77
140
|
} from "../tools/tool-approval-handler.js";
|
|
78
141
|
import type { ToolContext } from "../tools/types.js";
|
|
@@ -528,36 +591,100 @@ describe("ToolApprovalHandler / pre-exec gate grant check", () => {
|
|
|
528
591
|
});
|
|
529
592
|
});
|
|
530
593
|
|
|
531
|
-
describe("
|
|
532
|
-
test("
|
|
533
|
-
// Side-effect tools
|
|
534
|
-
expect(
|
|
535
|
-
expect(
|
|
536
|
-
//
|
|
537
|
-
expect(
|
|
538
|
-
expect(
|
|
539
|
-
// UI surface tools are exempt even on the host target.
|
|
540
|
-
expect(
|
|
541
|
-
expect(
|
|
542
|
-
expect(
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
test("an inline-command (dynamic) skill_load
|
|
594
|
+
describe("sensitiveToolReach", () => {
|
|
595
|
+
test("reach is a property of the tool and execution target", () => {
|
|
596
|
+
// Side-effect tools reach the sandbox wherever they run…
|
|
597
|
+
expect(sensitiveToolReach("bash", "sandbox")).toBe("sandbox");
|
|
598
|
+
expect(sensitiveToolReach("file_write", "sandbox")).toBe("sandbox");
|
|
599
|
+
// …read-only tools reach only when they execute on the host…
|
|
600
|
+
expect(sensitiveToolReach("web_search", "host")).toBe("host");
|
|
601
|
+
expect(sensitiveToolReach("web_search", "sandbox")).toBe("none");
|
|
602
|
+
// …and UI surface tools are exempt even on the host target.
|
|
603
|
+
expect(sensitiveToolReach("ui_show", "host")).toBe("none");
|
|
604
|
+
expect(sensitiveToolReach("ui_update", "host")).toBe("none");
|
|
605
|
+
expect(sensitiveToolReach("ui_dismiss", "host")).toBe("none");
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
test("an inline-command (dynamic) skill_load reaches the host; a plain one is not sensitive", () => {
|
|
546
609
|
// skill_load is not a side-effect tool, but a load that executes embedded
|
|
547
610
|
// shell at load time must pass through the capability floor — so a
|
|
548
611
|
// non-guardian's dynamic load escalates to the guardian, Full-access-proof.
|
|
549
612
|
expect(
|
|
550
|
-
|
|
551
|
-
).toBe(
|
|
613
|
+
sensitiveToolReach("skill_load", "sandbox", { skill: "dynamic-skill" }),
|
|
614
|
+
).toBe("host");
|
|
552
615
|
expect(
|
|
553
|
-
|
|
554
|
-
).toBe(
|
|
616
|
+
sensitiveToolReach("skill_load", "sandbox", { skill: "plain-skill" }),
|
|
617
|
+
).toBe("none");
|
|
555
618
|
// Without input, skill_load falls back to the name/target rule.
|
|
556
|
-
expect(
|
|
619
|
+
expect(sensitiveToolReach("skill_load", "sandbox")).toBe("none");
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
test("an out-of-workspace file_read reaches the host; an in-workspace one is not sensitive", () => {
|
|
623
|
+
const workingDir = mkdtempSync(join(tmpdir(), "sensitive-tool-test-"));
|
|
624
|
+
try {
|
|
625
|
+
// Out-of-workspace file access is host-equivalent: the host-fallback
|
|
626
|
+
// path policy executes the escape, so it carries the host capability
|
|
627
|
+
// floor even for the read-only sandbox tool.
|
|
628
|
+
expect(
|
|
629
|
+
sensitiveToolReach(
|
|
630
|
+
"file_read",
|
|
631
|
+
"sandbox",
|
|
632
|
+
{ path: "/etc/hosts" },
|
|
633
|
+
workingDir,
|
|
634
|
+
),
|
|
635
|
+
).toBe("host");
|
|
636
|
+
expect(
|
|
637
|
+
sensitiveToolReach(
|
|
638
|
+
"file_read",
|
|
639
|
+
"sandbox",
|
|
640
|
+
{ path: "notes.txt" },
|
|
641
|
+
workingDir,
|
|
642
|
+
),
|
|
643
|
+
).toBe("none");
|
|
644
|
+
// `path` is the executed field — a benign `file_path` must not mask it.
|
|
645
|
+
expect(
|
|
646
|
+
sensitiveToolReach(
|
|
647
|
+
"file_read",
|
|
648
|
+
"sandbox",
|
|
649
|
+
{ path: "/etc/hosts", file_path: "notes.txt" },
|
|
650
|
+
workingDir,
|
|
651
|
+
),
|
|
652
|
+
).toBe("host");
|
|
653
|
+
// Container-style /workspace paths remap to the workspace.
|
|
654
|
+
expect(
|
|
655
|
+
sensitiveToolReach(
|
|
656
|
+
"file_read",
|
|
657
|
+
"sandbox",
|
|
658
|
+
{ path: "/workspace/notes.txt" },
|
|
659
|
+
workingDir,
|
|
660
|
+
),
|
|
661
|
+
).toBe("none");
|
|
662
|
+
// Without a workingDir the boundary is unknown — name/target rule only.
|
|
663
|
+
expect(
|
|
664
|
+
sensitiveToolReach("file_read", "sandbox", { path: "/etc/hosts" }),
|
|
665
|
+
).toBe("none");
|
|
666
|
+
// Containerized installs keep the hard execution boundary, so the
|
|
667
|
+
// escape never executes and does not need the floor.
|
|
668
|
+
process.env.IS_CONTAINERIZED = "true";
|
|
669
|
+
try {
|
|
670
|
+
expect(
|
|
671
|
+
sensitiveToolReach(
|
|
672
|
+
"file_read",
|
|
673
|
+
"sandbox",
|
|
674
|
+
{ path: "/etc/hosts" },
|
|
675
|
+
workingDir,
|
|
676
|
+
),
|
|
677
|
+
).toBe("none");
|
|
678
|
+
} finally {
|
|
679
|
+
delete process.env.IS_CONTAINERIZED;
|
|
680
|
+
}
|
|
681
|
+
} finally {
|
|
682
|
+
rmSync(workingDir, { recursive: true, force: true });
|
|
683
|
+
}
|
|
557
684
|
});
|
|
558
685
|
});
|
|
559
686
|
|
|
560
|
-
describe("resolveSensitiveToolDecision / CapabilitySet floor
|
|
687
|
+
describe("resolveSensitiveToolDecision / CapabilitySet floor × approval cell", () => {
|
|
561
688
|
const cellThresholds: Array<ApprovalCellThreshold | undefined> = [
|
|
562
689
|
undefined,
|
|
563
690
|
"none",
|
|
@@ -565,24 +692,58 @@ describe("resolveSensitiveToolDecision / CapabilitySet floor invariant", () => {
|
|
|
565
692
|
"medium",
|
|
566
693
|
"high",
|
|
567
694
|
];
|
|
568
|
-
|
|
695
|
+
/** The cells that authorize something, and so can lift the floor. */
|
|
696
|
+
const liftingThresholds: ApprovalCellThreshold[] = ["low", "medium", "high"];
|
|
697
|
+
|
|
698
|
+
test("no cell and a none cell both leave the escalate floor standing", () => {
|
|
699
|
+
for (const cellThreshold of [undefined, "none"] as const) {
|
|
700
|
+
expect(
|
|
701
|
+
resolveSensitiveToolDecision({
|
|
702
|
+
reach: "sandbox",
|
|
703
|
+
cellThreshold,
|
|
704
|
+
sensitiveToolApproval: "escalate-and-wait",
|
|
705
|
+
}),
|
|
706
|
+
).toBe("escalate-and-wait");
|
|
707
|
+
}
|
|
708
|
+
});
|
|
569
709
|
|
|
570
|
-
test("
|
|
710
|
+
test("a cell that authorizes something lifts the escalate floor", () => {
|
|
711
|
+
for (const cellThreshold of liftingThresholds) {
|
|
712
|
+
expect(
|
|
713
|
+
resolveSensitiveToolDecision({
|
|
714
|
+
reach: "sandbox",
|
|
715
|
+
cellThreshold,
|
|
716
|
+
sensitiveToolApproval: "escalate-and-wait",
|
|
717
|
+
}),
|
|
718
|
+
).toBe("proceed");
|
|
719
|
+
}
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
// A room-level posture says what the assistant may do in that room. It is
|
|
723
|
+
// never a grant of the owner's own machine or accounts, so no cell at any
|
|
724
|
+
// cascade level reaches past the sandbox.
|
|
725
|
+
test("host reach is never lifted, at any cell threshold", () => {
|
|
571
726
|
for (const cellThreshold of cellThresholds) {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
727
|
+
expect(
|
|
728
|
+
resolveSensitiveToolDecision({
|
|
729
|
+
reach: "host",
|
|
730
|
+
cellThreshold,
|
|
731
|
+
sensitiveToolApproval: "escalate-and-wait",
|
|
732
|
+
}),
|
|
733
|
+
).toBe("escalate-and-wait");
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
// An actor with no established identity has no cell to stand on: the matrix
|
|
738
|
+
// is keyed by contact type, and "unknown" is the absence of one. No cell at
|
|
739
|
+
// any cascade level may turn that into permission to act.
|
|
740
|
+
test("deny is absolute — no cell threshold lifts it", () => {
|
|
741
|
+
for (const cellThreshold of cellThresholds) {
|
|
742
|
+
for (const reach of ["sandbox", "host"] as const) {
|
|
581
743
|
expect(
|
|
582
744
|
resolveSensitiveToolDecision({
|
|
583
|
-
|
|
745
|
+
reach,
|
|
584
746
|
cellThreshold,
|
|
585
|
-
riskLevel,
|
|
586
747
|
sensitiveToolApproval: "deny",
|
|
587
748
|
}),
|
|
588
749
|
).toBe("deny");
|
|
@@ -592,12 +753,11 @@ describe("resolveSensitiveToolDecision / CapabilitySet floor invariant", () => {
|
|
|
592
753
|
|
|
593
754
|
test("self capability proceeds for sensitive tools (lane-B policy governs downstream)", () => {
|
|
594
755
|
for (const cellThreshold of cellThresholds) {
|
|
595
|
-
for (const
|
|
756
|
+
for (const reach of ["sandbox", "host"] as const) {
|
|
596
757
|
expect(
|
|
597
758
|
resolveSensitiveToolDecision({
|
|
598
|
-
|
|
759
|
+
reach,
|
|
599
760
|
cellThreshold,
|
|
600
|
-
riskLevel,
|
|
601
761
|
sensitiveToolApproval: "self",
|
|
602
762
|
}),
|
|
603
763
|
).toBe("proceed");
|
|
@@ -613,9 +773,8 @@ describe("resolveSensitiveToolDecision / CapabilitySet floor invariant", () => {
|
|
|
613
773
|
] as const) {
|
|
614
774
|
expect(
|
|
615
775
|
resolveSensitiveToolDecision({
|
|
616
|
-
|
|
776
|
+
reach: "none",
|
|
617
777
|
cellThreshold: undefined,
|
|
618
|
-
riskLevel: "high",
|
|
619
778
|
sensitiveToolApproval,
|
|
620
779
|
}),
|
|
621
780
|
).toBe("proceed");
|
|
@@ -623,6 +782,391 @@ describe("resolveSensitiveToolDecision / CapabilitySet floor invariant", () => {
|
|
|
623
782
|
});
|
|
624
783
|
});
|
|
625
784
|
|
|
785
|
+
describe("ToolApprovalHandler / approval cell lifts the sensitive-tool floor", () => {
|
|
786
|
+
const handler = new ToolApprovalHandler();
|
|
787
|
+
/** An ordinary workspace write: sandbox reach, and nothing excludes it. */
|
|
788
|
+
const toolName = "file_write";
|
|
789
|
+
const input = { path: "notes/todo.md", content: "x" };
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* A contact in a room, with no `requesterExternalUserId` — escalation needs
|
|
793
|
+
* one, so when the floor stands the gate takes the generic denial path
|
|
794
|
+
* instead of reaching for the guardian-request machinery. That keeps these
|
|
795
|
+
* tests on the gate's own decision.
|
|
796
|
+
*/
|
|
797
|
+
function channelContext(overrides: Partial<ToolContext> = {}): ToolContext {
|
|
798
|
+
return makeContext({
|
|
799
|
+
trustClass: "trusted_contact",
|
|
800
|
+
executionChannel: "telegram",
|
|
801
|
+
channelPermissionChannelId: "C-room",
|
|
802
|
+
...overrides,
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function cell(threshold: string) {
|
|
807
|
+
return { ok: true, resolved: { threshold, scope: "channel" } } as const;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
beforeEach(() => {
|
|
811
|
+
clearTables();
|
|
812
|
+
resetAuditCalls();
|
|
813
|
+
resetThresholdReaderMock();
|
|
814
|
+
skillOwnerBundled = false;
|
|
815
|
+
fileWriteOwner = undefined;
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
test.each(["low", "medium", "high"])(
|
|
819
|
+
"a %s cell lifts the floor — no scoped grant required",
|
|
820
|
+
async (threshold) => {
|
|
821
|
+
thresholdReaderMock.cell = cell(threshold);
|
|
822
|
+
|
|
823
|
+
const result = await handler.checkPreExecutionGates(
|
|
824
|
+
toolName,
|
|
825
|
+
input,
|
|
826
|
+
channelContext(),
|
|
827
|
+
"low",
|
|
828
|
+
Date.now(),
|
|
829
|
+
);
|
|
830
|
+
|
|
831
|
+
expect(result.allowed).toBe(true);
|
|
832
|
+
if (!result.allowed) {
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
// Not "approved via a grant" — the gate stepped out of the grant
|
|
836
|
+
// mechanism entirely and handed off to the risk/threshold policy.
|
|
837
|
+
expect(result.grantConsumed).toBeFalsy();
|
|
838
|
+
expect(auditCalls.denied.length).toBe(0);
|
|
839
|
+
},
|
|
840
|
+
);
|
|
841
|
+
|
|
842
|
+
test("a none cell authorizes nothing — the floor stands", async () => {
|
|
843
|
+
thresholdReaderMock.cell = cell("none");
|
|
844
|
+
|
|
845
|
+
const result = await handler.checkPreExecutionGates(
|
|
846
|
+
toolName,
|
|
847
|
+
input,
|
|
848
|
+
channelContext(),
|
|
849
|
+
"low",
|
|
850
|
+
Date.now(),
|
|
851
|
+
);
|
|
852
|
+
|
|
853
|
+
expect(result.allowed).toBe(false);
|
|
854
|
+
if (result.allowed) {
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
expect(result.result.content).toContain("requires guardian approval");
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
// Fail closed: an unreadable cell is indistinguishable from a strict one, so
|
|
861
|
+
// a gateway outage must never widen what a channel actor may do.
|
|
862
|
+
test("a failed cell lookup does not lift the floor", async () => {
|
|
863
|
+
thresholdReaderMock.cell = { ok: false };
|
|
864
|
+
|
|
865
|
+
const result = await handler.checkPreExecutionGates(
|
|
866
|
+
toolName,
|
|
867
|
+
input,
|
|
868
|
+
channelContext(),
|
|
869
|
+
"low",
|
|
870
|
+
Date.now(),
|
|
871
|
+
);
|
|
872
|
+
|
|
873
|
+
expect(result.allowed).toBe(false);
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
// The matrix is keyed by contact type, and "unknown" is the absence of one.
|
|
877
|
+
test("an unknown actor stays fail-closed even under a full-access cell", async () => {
|
|
878
|
+
thresholdReaderMock.cell = cell("high");
|
|
879
|
+
|
|
880
|
+
const result = await handler.checkPreExecutionGates(
|
|
881
|
+
toolName,
|
|
882
|
+
input,
|
|
883
|
+
channelContext({ trustClass: "unknown" }),
|
|
884
|
+
"low",
|
|
885
|
+
Date.now(),
|
|
886
|
+
);
|
|
887
|
+
|
|
888
|
+
expect(result.allowed).toBe(false);
|
|
889
|
+
if (result.allowed) {
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
expect(result.result.content).toContain("verified channel identity");
|
|
893
|
+
// Nothing to resolve: no cell can lift an absolute deny.
|
|
894
|
+
expect(thresholdReaderMock.cellLookups).toBe(0);
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
// The cell says what the assistant may do in a room, not what a contact may
|
|
898
|
+
// do to the owner's machine. `host_bash` is the same tool class as `bash`
|
|
899
|
+
// and the same Full-access cell — only the reach differs.
|
|
900
|
+
test("a full-access cell does not lift a host-reach tool", async () => {
|
|
901
|
+
thresholdReaderMock.cell = cell("high");
|
|
902
|
+
|
|
903
|
+
const result = await handler.checkPreExecutionGates(
|
|
904
|
+
"host_bash",
|
|
905
|
+
{ command: "ls" },
|
|
906
|
+
channelContext(),
|
|
907
|
+
"low",
|
|
908
|
+
Date.now(),
|
|
909
|
+
);
|
|
910
|
+
|
|
911
|
+
expect(result.allowed).toBe(false);
|
|
912
|
+
if (result.allowed) {
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
expect(result.result.content).toContain("requires guardian approval");
|
|
916
|
+
// Host reach is decided before the cell matters, so nothing is looked up.
|
|
917
|
+
expect(thresholdReaderMock.cellLookups).toBe(0);
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
// Each of these is a way back out of the sandbox, so a cell that lifted any
|
|
921
|
+
// one of them would lift the others by the back door. Excluding only some
|
|
922
|
+
// would read as safe while leaving the path open.
|
|
923
|
+
describe("what no cell lifts, even at Full access", () => {
|
|
924
|
+
beforeEach(() => {
|
|
925
|
+
thresholdReaderMock.cell = cell("high");
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
async function expectFloored(
|
|
929
|
+
toolName: string,
|
|
930
|
+
toolInput: Record<string, unknown>,
|
|
931
|
+
) {
|
|
932
|
+
const result = await handler.checkPreExecutionGates(
|
|
933
|
+
toolName,
|
|
934
|
+
toolInput,
|
|
935
|
+
channelContext(),
|
|
936
|
+
"low",
|
|
937
|
+
Date.now(),
|
|
938
|
+
);
|
|
939
|
+
expect(result.allowed).toBe(false);
|
|
940
|
+
if (result.allowed) {
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
expect(result.result.content).toContain("requires guardian approval");
|
|
944
|
+
// Excluded before the cell matters, so nothing is looked up.
|
|
945
|
+
expect(thresholdReaderMock.cellLookups).toBe(0);
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// Running code in the workspace is how you write everything else in it.
|
|
949
|
+
test("sandbox bash", async () => {
|
|
950
|
+
await expectFloored("bash", { command: "ls" });
|
|
951
|
+
});
|
|
952
|
+
|
|
953
|
+
test.each([
|
|
954
|
+
["hooks", "hooks/on-message.ts"],
|
|
955
|
+
["plugins", "plugins/acme/register.ts"],
|
|
956
|
+
["skills", "skills/acme/SKILL.md"],
|
|
957
|
+
["tools", "tools/acme.ts"],
|
|
958
|
+
["routes", "routes/acme.ts"],
|
|
959
|
+
["workflows", "workflows/acme.ts"],
|
|
960
|
+
])("a write into %s/ — code the daemon runs later", async (_dir, path) => {
|
|
961
|
+
await expectFloored("file_write", { path, content: "x" });
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
// Prompt surfaces are instructions the daemon obeys — rewriting them is
|
|
965
|
+
// the same delegation as planting code, one layer up.
|
|
966
|
+
test.each([
|
|
967
|
+
["the assistant's own instructions", "SOUL.md"],
|
|
968
|
+
["its identity", "IDENTITY.md"],
|
|
969
|
+
["a per-user context file", "users/someone.md"],
|
|
970
|
+
["a per-channel context file", "channels/general.md"],
|
|
971
|
+
[
|
|
972
|
+
"a system-section override",
|
|
973
|
+
"prompts/system/10a-non-guardian-boundary.md",
|
|
974
|
+
],
|
|
975
|
+
])("a write to %s — %s", async (_label, path) => {
|
|
976
|
+
await expectFloored("file_write", { path, content: "x" });
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
// Nothing reviewed an unvetted manifest, so the risk it claims about
|
|
980
|
+
// itself must not be what decides whether a room may run it unattended.
|
|
981
|
+
test("an unvetted skill shadowing a core side-effect tool", async () => {
|
|
982
|
+
skillOwnerBundled = false;
|
|
983
|
+
await expectFloored("document_create", { title: "x" });
|
|
984
|
+
});
|
|
985
|
+
|
|
986
|
+
// A novel name is in no side-effect list, so without the unvetted check it
|
|
987
|
+
// would not be gated at all — the case the shadowing guard alone misses.
|
|
988
|
+
test("an unvetted skill tool with a name of its own", async () => {
|
|
989
|
+
skillOwnerBundled = false;
|
|
990
|
+
await expectFloored("acme_send", { to: "someone" });
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
// Workspace-owned tools are dynamic-imported on-disk code with no
|
|
994
|
+
// bundled tier — unvetted by definition, whatever the bundled flag says.
|
|
995
|
+
test("a workspace-owned tool with a name of its own", async () => {
|
|
996
|
+
skillOwnerBundled = true;
|
|
997
|
+
await expectFloored("ws_deploy", { target: "prod" });
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
// A workspace tool registered over a delegable core name must not
|
|
1001
|
+
// inherit that name's liftability — the owner decides, not the name.
|
|
1002
|
+
test("a workspace override of a delegable core tool", async () => {
|
|
1003
|
+
fileWriteOwner = { kind: "workspace", id: "tools/file-write.ts" };
|
|
1004
|
+
await expectFloored("file_write", {
|
|
1005
|
+
path: "notes/todo.md",
|
|
1006
|
+
content: "x",
|
|
1007
|
+
});
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
// MCP tools are floored as host reach; this pins that the unvetted
|
|
1011
|
+
// allowlist catches them independently, so the floor does not hinge on
|
|
1012
|
+
// the host stamp alone.
|
|
1013
|
+
test("an MCP-owned tool, even without the host target", async () => {
|
|
1014
|
+
await expectFloored("mcp_lookup", { query: "q" });
|
|
1015
|
+
});
|
|
1016
|
+
|
|
1017
|
+
// The private network is the guardian's machine: the daemon's own HTTP
|
|
1018
|
+
// surface, the gateway, whatever else is listening there.
|
|
1019
|
+
test("web_fetch reaching the private network", async () => {
|
|
1020
|
+
await expectFloored("web_fetch", {
|
|
1021
|
+
url: "http://localhost:7821/",
|
|
1022
|
+
allow_private_network: true,
|
|
1023
|
+
});
|
|
1024
|
+
});
|
|
1025
|
+
});
|
|
1026
|
+
|
|
1027
|
+
test("a public web_fetch is still lifted", async () => {
|
|
1028
|
+
thresholdReaderMock.cell = cell("low");
|
|
1029
|
+
|
|
1030
|
+
const result = await handler.checkPreExecutionGates(
|
|
1031
|
+
"web_fetch",
|
|
1032
|
+
{ url: "https://example.com/" },
|
|
1033
|
+
channelContext(),
|
|
1034
|
+
"low",
|
|
1035
|
+
Date.now(),
|
|
1036
|
+
);
|
|
1037
|
+
|
|
1038
|
+
expect(result.allowed).toBe(true);
|
|
1039
|
+
});
|
|
1040
|
+
|
|
1041
|
+
// A successful cascade walk that finds no cell resolves the room's
|
|
1042
|
+
// default — Conservative — so an unconfigured room behaves exactly as the
|
|
1043
|
+
// picker and legend present it. (The mock's reset state IS the successful
|
|
1044
|
+
// no-cell resolution.)
|
|
1045
|
+
test("an unconfigured room lifts at the Conservative default", async () => {
|
|
1046
|
+
const result = await handler.checkPreExecutionGates(
|
|
1047
|
+
"file_write",
|
|
1048
|
+
{ path: "notes/todo.md", content: "x" },
|
|
1049
|
+
channelContext(),
|
|
1050
|
+
"low",
|
|
1051
|
+
Date.now(),
|
|
1052
|
+
);
|
|
1053
|
+
|
|
1054
|
+
expect(result.allowed).toBe(true);
|
|
1055
|
+
expect(thresholdReaderMock.cellLookups).toBe(1);
|
|
1056
|
+
});
|
|
1057
|
+
|
|
1058
|
+
// The room default is the owner's global setting collapsed — a Strict
|
|
1059
|
+
// global yields Strict rooms, so nothing lifts.
|
|
1060
|
+
test("a Strict global keeps unconfigured rooms on the floor", async () => {
|
|
1061
|
+
thresholdReaderMock.roomDefault = "none";
|
|
1062
|
+
|
|
1063
|
+
const result = await handler.checkPreExecutionGates(
|
|
1064
|
+
"file_write",
|
|
1065
|
+
{ path: "notes/todo.md", content: "x" },
|
|
1066
|
+
channelContext(),
|
|
1067
|
+
"low",
|
|
1068
|
+
Date.now(),
|
|
1069
|
+
);
|
|
1070
|
+
|
|
1071
|
+
expect(result.allowed).toBe(false);
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
// An unreadable global lifts nothing — the default derives from it, so
|
|
1075
|
+
// without it the floor stands.
|
|
1076
|
+
test("an unreadable global keeps unconfigured rooms on the floor", async () => {
|
|
1077
|
+
thresholdReaderMock.roomDefault = undefined;
|
|
1078
|
+
|
|
1079
|
+
const result = await handler.checkPreExecutionGates(
|
|
1080
|
+
"file_write",
|
|
1081
|
+
{ path: "notes/todo.md", content: "x" },
|
|
1082
|
+
channelContext(),
|
|
1083
|
+
"low",
|
|
1084
|
+
Date.now(),
|
|
1085
|
+
);
|
|
1086
|
+
|
|
1087
|
+
expect(result.allowed).toBe(false);
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
// A write whose target cannot be resolved is never liftable — without a
|
|
1091
|
+
// workingDir the sink check cannot see where the write lands, and it must
|
|
1092
|
+
// fail closed rather than be skipped.
|
|
1093
|
+
test("a write with no workingDir stays floored at any cell", async () => {
|
|
1094
|
+
thresholdReaderMock.cell = cell("high");
|
|
1095
|
+
|
|
1096
|
+
const result = await handler.checkPreExecutionGates(
|
|
1097
|
+
"file_write",
|
|
1098
|
+
{ path: "hooks/evil.ts", content: "x" },
|
|
1099
|
+
channelContext({ workingDir: undefined }),
|
|
1100
|
+
"low",
|
|
1101
|
+
Date.now(),
|
|
1102
|
+
);
|
|
1103
|
+
|
|
1104
|
+
expect(result.allowed).toBe(false);
|
|
1105
|
+
expect(thresholdReaderMock.cellLookups).toBe(0);
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
// The exclusions are about provenance and reach, not about naming: an
|
|
1109
|
+
// ordinary workspace write is still delegable.
|
|
1110
|
+
test("an ordinary workspace file write is still lifted", async () => {
|
|
1111
|
+
thresholdReaderMock.cell = cell("high");
|
|
1112
|
+
|
|
1113
|
+
const result = await handler.checkPreExecutionGates(
|
|
1114
|
+
"file_write",
|
|
1115
|
+
{ path: "notes/todo.md", content: "x" },
|
|
1116
|
+
channelContext(),
|
|
1117
|
+
"low",
|
|
1118
|
+
Date.now(),
|
|
1119
|
+
);
|
|
1120
|
+
|
|
1121
|
+
expect(result.allowed).toBe(true);
|
|
1122
|
+
if (!result.allowed) {
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
expect(result.grantConsumed).toBeFalsy();
|
|
1126
|
+
});
|
|
1127
|
+
|
|
1128
|
+
test("a bundled skill's side-effect tool is still lifted", async () => {
|
|
1129
|
+
thresholdReaderMock.cell = cell("high");
|
|
1130
|
+
skillOwnerBundled = true;
|
|
1131
|
+
|
|
1132
|
+
const result = await handler.checkPreExecutionGates(
|
|
1133
|
+
"document_create",
|
|
1134
|
+
{ title: "x" },
|
|
1135
|
+
channelContext(),
|
|
1136
|
+
"low",
|
|
1137
|
+
Date.now(),
|
|
1138
|
+
);
|
|
1139
|
+
|
|
1140
|
+
expect(result.allowed).toBe(true);
|
|
1141
|
+
});
|
|
1142
|
+
|
|
1143
|
+
test("a guardian never pays for the cell lookup", async () => {
|
|
1144
|
+
const result = await handler.checkPreExecutionGates(
|
|
1145
|
+
toolName,
|
|
1146
|
+
input,
|
|
1147
|
+
channelContext({ trustClass: "guardian" }),
|
|
1148
|
+
"low",
|
|
1149
|
+
Date.now(),
|
|
1150
|
+
);
|
|
1151
|
+
|
|
1152
|
+
expect(result.allowed).toBe(true);
|
|
1153
|
+
expect(thresholdReaderMock.cellLookups).toBe(0);
|
|
1154
|
+
});
|
|
1155
|
+
|
|
1156
|
+
test("a turn with no channel coordinates skips the lookup", async () => {
|
|
1157
|
+
const result = await handler.checkPreExecutionGates(
|
|
1158
|
+
toolName,
|
|
1159
|
+
input,
|
|
1160
|
+
makeContext({ trustClass: "trusted_contact" }),
|
|
1161
|
+
"low",
|
|
1162
|
+
Date.now(),
|
|
1163
|
+
);
|
|
1164
|
+
|
|
1165
|
+
expect(result.allowed).toBe(false);
|
|
1166
|
+
expect(thresholdReaderMock.cellLookups).toBe(0);
|
|
1167
|
+
});
|
|
1168
|
+
});
|
|
1169
|
+
|
|
626
1170
|
describe("ToolApprovalHandler / unparseable tool args gate", () => {
|
|
627
1171
|
const handler = new ToolApprovalHandler();
|
|
628
1172
|
|