@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
|
@@ -66,7 +66,7 @@ mock.module("../persistence/conversation-crud.js", () => ({
|
|
|
66
66
|
updates: Record<string, unknown>,
|
|
67
67
|
) => {
|
|
68
68
|
const row = persistedRows.find((candidate) => candidate.id === messageId);
|
|
69
|
-
if (!row) return;
|
|
69
|
+
if (!row) {return;}
|
|
70
70
|
const existing =
|
|
71
71
|
row.metadata && typeof row.metadata === "string"
|
|
72
72
|
? (JSON.parse(row.metadata) as Record<string, unknown>)
|
|
@@ -78,18 +78,18 @@ mock.module("../persistence/conversation-crud.js", () => ({
|
|
|
78
78
|
// `lastAssistantPersisted()` assertions continue to find the row that
|
|
79
79
|
// was reserved at `llm_call_started` time.
|
|
80
80
|
const row = persistedRows.find((candidate) => candidate.id === messageId);
|
|
81
|
-
if (row) row.content = content;
|
|
81
|
+
if (row) {row.content = content;}
|
|
82
82
|
const call = addMessageCalls.find((c) => c.id === messageId);
|
|
83
|
-
if (call) call.content = content;
|
|
83
|
+
if (call) {call.content = content;}
|
|
84
84
|
},
|
|
85
85
|
markMessageContentInflight: () => {},
|
|
86
86
|
finalizeMessageContent: (messageId: string, content: string) => {
|
|
87
87
|
// The finalize seam writes through `finalizeMessageContent`; mirror it
|
|
88
88
|
// into the same captures as `updateMessageContent`.
|
|
89
89
|
const row = persistedRows.find((candidate) => candidate.id === messageId);
|
|
90
|
-
if (row) row.content = content;
|
|
90
|
+
if (row) {row.content = content;}
|
|
91
91
|
const call = addMessageCalls.find((c) => c.id === messageId);
|
|
92
|
-
if (call) call.content = content;
|
|
92
|
+
if (call) {call.content = content;}
|
|
93
93
|
},
|
|
94
94
|
// The handler treats provenance as a flat spread; returning {} keeps the
|
|
95
95
|
// metadata snapshot focused on the fields under test.
|
|
@@ -153,6 +153,7 @@ mock.module("../persistence/attachments-store.js", () => ({
|
|
|
153
153
|
// ── Imports (after mocks) ──────────────────────────────────────────────────
|
|
154
154
|
|
|
155
155
|
import type { AgentEvent } from "../agent/loop.js";
|
|
156
|
+
import type { AssistantEvent } from "../api/index.js";
|
|
156
157
|
import type {
|
|
157
158
|
EventHandlerDeps,
|
|
158
159
|
EventHandlerState,
|
|
@@ -162,7 +163,6 @@ import {
|
|
|
162
163
|
handleLlmCallStarted,
|
|
163
164
|
handleMessageComplete,
|
|
164
165
|
} from "../daemon/conversation-agent-loop-handlers.js";
|
|
165
|
-
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
166
166
|
import { readSlackMetadata } from "../messaging/providers/slack/message-metadata.js";
|
|
167
167
|
import { deliverReplyViaCallback } from "../runtime/channel-reply-delivery.js";
|
|
168
168
|
import { setConfig } from "./helpers/set-config.js";
|
|
@@ -194,7 +194,7 @@ function makeDeps(
|
|
|
194
194
|
},
|
|
195
195
|
clientTimezone: overrides.clientTimezone,
|
|
196
196
|
} as unknown as EventHandlerDeps["ctx"],
|
|
197
|
-
onEvent: (_msg:
|
|
197
|
+
onEvent: (_msg: AssistantEvent) => {},
|
|
198
198
|
reqId: "test-req-id",
|
|
199
199
|
isFirstMessage: false,
|
|
200
200
|
shouldGenerateTitle: false,
|
|
@@ -233,7 +233,7 @@ function makeMessageCompleteEvent(
|
|
|
233
233
|
/** Find the most recently persisted assistant-role message in the capture log. */
|
|
234
234
|
function lastAssistantPersisted(): AddMessageCall {
|
|
235
235
|
for (let i = addMessageCalls.length - 1; i >= 0; i--) {
|
|
236
|
-
if (addMessageCalls[i].role === "assistant") return addMessageCalls[i];
|
|
236
|
+
if (addMessageCalls[i].role === "assistant") {return addMessageCalls[i];}
|
|
237
237
|
}
|
|
238
238
|
throw new Error("No assistant message was persisted via addMessage");
|
|
239
239
|
}
|
|
@@ -14,7 +14,9 @@ import {
|
|
|
14
14
|
hostPolicy,
|
|
15
15
|
resolveRealPath,
|
|
16
16
|
sandboxPolicy,
|
|
17
|
+
sandboxPolicyWithHostFallback,
|
|
17
18
|
} from "../tools/shared/filesystem/path-policy.js";
|
|
19
|
+
import { getDotEnvPath } from "../util/platform.js";
|
|
18
20
|
|
|
19
21
|
// ── Mock setup for skill path classifier ────────────────────────────────────
|
|
20
22
|
// The classifier imports getWorkspaceSkillsDir and getBundledSkillsDir, which
|
|
@@ -94,6 +96,30 @@ describe("sandboxPolicy", () => {
|
|
|
94
96
|
}
|
|
95
97
|
});
|
|
96
98
|
|
|
99
|
+
test("resolveRealPath follows a trailing dangling symlink to its destination", () => {
|
|
100
|
+
const dir = makeTempDir();
|
|
101
|
+
const outside = makeTempDir();
|
|
102
|
+
const destination = join(outside, "not-yet.txt");
|
|
103
|
+
symlinkSync(destination, join(dir, "dangle"));
|
|
104
|
+
|
|
105
|
+
expect(resolveRealPath(join(dir, "dangle"))).toBe(destination);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("rejects a dangling symlink whose destination escapes the boundary", () => {
|
|
109
|
+
const boundary = makeTempDir();
|
|
110
|
+
const outside = makeTempDir();
|
|
111
|
+
|
|
112
|
+
// A dangling link inside the boundary pointing at a nonexistent outside
|
|
113
|
+
// file: a write through it would create the outside destination.
|
|
114
|
+
symlinkSync(join(outside, "not-yet.txt"), join(boundary, "dangle"));
|
|
115
|
+
|
|
116
|
+
const result = sandboxPolicy("dangle", boundary, { mustExist: false });
|
|
117
|
+
expect(result.ok).toBe(false);
|
|
118
|
+
if (!result.ok) {
|
|
119
|
+
expect(result.reason).toBe("out_of_bounds");
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
97
123
|
test("rejects parent dir symlink escape in mustExist=false flow", () => {
|
|
98
124
|
const boundary = makeTempDir();
|
|
99
125
|
const outside = makeTempDir();
|
|
@@ -191,6 +217,295 @@ describe("sandboxPolicy", () => {
|
|
|
191
217
|
});
|
|
192
218
|
});
|
|
193
219
|
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
// Sandbox policy with host fallback
|
|
222
|
+
// ---------------------------------------------------------------------------
|
|
223
|
+
|
|
224
|
+
describe("sandboxPolicyWithHostFallback", () => {
|
|
225
|
+
afterEach(() => {
|
|
226
|
+
delete process.env.IS_CONTAINERIZED;
|
|
227
|
+
delete process.env.GATEWAY_SECURITY_DIR;
|
|
228
|
+
delete process.env.CREDENTIAL_SECURITY_DIR;
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test("matches sandboxPolicy for in-bounds paths", () => {
|
|
232
|
+
const boundary = makeTempDir();
|
|
233
|
+
mkdirSync(join(boundary, "sub"));
|
|
234
|
+
|
|
235
|
+
const result = sandboxPolicyWithHostFallback("sub/file.txt", boundary);
|
|
236
|
+
expect(result).toEqual(sandboxPolicy("sub/file.txt", boundary));
|
|
237
|
+
expect(result.ok).toBe(true);
|
|
238
|
+
if (result.ok) {
|
|
239
|
+
expect(result.resolved).toBe(join(boundary, "sub", "file.txt"));
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("allows an absolute path outside the boundary", () => {
|
|
244
|
+
const boundary = makeTempDir();
|
|
245
|
+
const outside = makeTempDir();
|
|
246
|
+
const target = join(outside, "file.txt");
|
|
247
|
+
writeFileSync(target, "x");
|
|
248
|
+
|
|
249
|
+
const result = sandboxPolicyWithHostFallback(target, boundary);
|
|
250
|
+
expect(result.ok).toBe(true);
|
|
251
|
+
if (result.ok) {
|
|
252
|
+
expect(result.resolved).toBe(target);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
test("allows a relative traversal escape", () => {
|
|
257
|
+
const boundary = makeTempDir();
|
|
258
|
+
|
|
259
|
+
const result = sandboxPolicyWithHostFallback("../escape.txt", boundary, {
|
|
260
|
+
mustExist: false,
|
|
261
|
+
});
|
|
262
|
+
expect(result.ok).toBe(true);
|
|
263
|
+
if (result.ok) {
|
|
264
|
+
expect(result.resolved).toBe(join(boundary, "..", "escape.txt"));
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test("allows a symlink that escapes the boundary", () => {
|
|
269
|
+
const boundary = makeTempDir();
|
|
270
|
+
const outside = makeTempDir();
|
|
271
|
+
symlinkSync(outside, join(boundary, "escape-link"));
|
|
272
|
+
|
|
273
|
+
const result = sandboxPolicyWithHostFallback("escape-link", boundary);
|
|
274
|
+
expect(result.ok).toBe(true);
|
|
275
|
+
if (result.ok) {
|
|
276
|
+
expect(result.resolved).toBe(join(boundary, "escape-link"));
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test("denies out-of-bounds denylisted basenames", () => {
|
|
281
|
+
const boundary = makeTempDir();
|
|
282
|
+
const outside = makeTempDir();
|
|
283
|
+
|
|
284
|
+
const result = sandboxPolicyWithHostFallback(
|
|
285
|
+
join(outside, "backup.key"),
|
|
286
|
+
boundary,
|
|
287
|
+
{ mustExist: false },
|
|
288
|
+
);
|
|
289
|
+
expect(result.ok).toBe(false);
|
|
290
|
+
if (!result.ok) {
|
|
291
|
+
expect(result.reason).toBe("denied");
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test("denies paths inside the gateway security dir (env override)", () => {
|
|
296
|
+
const boundary = makeTempDir();
|
|
297
|
+
const securityDir = makeTempDir();
|
|
298
|
+
process.env.GATEWAY_SECURITY_DIR = securityDir;
|
|
299
|
+
|
|
300
|
+
const result = sandboxPolicyWithHostFallback(
|
|
301
|
+
join(securityDir, "trust.json"),
|
|
302
|
+
boundary,
|
|
303
|
+
{ mustExist: false },
|
|
304
|
+
);
|
|
305
|
+
expect(result.ok).toBe(false);
|
|
306
|
+
if (!result.ok) {
|
|
307
|
+
expect(result.reason).toBe("denied");
|
|
308
|
+
expect(result.error).toContain("service security directory");
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test("denies paths inside the CES security dir (env override)", () => {
|
|
313
|
+
const boundary = makeTempDir();
|
|
314
|
+
const securityDir = makeTempDir();
|
|
315
|
+
process.env.CREDENTIAL_SECURITY_DIR = securityDir;
|
|
316
|
+
|
|
317
|
+
for (const basename of ["keys.enc", "store.key"]) {
|
|
318
|
+
const result = sandboxPolicyWithHostFallback(
|
|
319
|
+
join(securityDir, basename),
|
|
320
|
+
boundary,
|
|
321
|
+
{ mustExist: false },
|
|
322
|
+
);
|
|
323
|
+
expect(result.ok).toBe(false);
|
|
324
|
+
if (!result.ok) {
|
|
325
|
+
expect(result.reason).toBe("denied");
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test("a root-configured security dir denies every absolute target", () => {
|
|
331
|
+
const boundary = makeTempDir();
|
|
332
|
+
const outside = makeTempDir();
|
|
333
|
+
process.env.GATEWAY_SECURITY_DIR = "/";
|
|
334
|
+
|
|
335
|
+
const result = sandboxPolicyWithHostFallback(
|
|
336
|
+
join(outside, "trust.json"),
|
|
337
|
+
boundary,
|
|
338
|
+
{ mustExist: false },
|
|
339
|
+
);
|
|
340
|
+
expect(result.ok).toBe(false);
|
|
341
|
+
if (!result.ok) {
|
|
342
|
+
expect(result.reason).toBe("denied");
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test("denies the daemon dotenv", () => {
|
|
347
|
+
const boundary = makeTempDir();
|
|
348
|
+
|
|
349
|
+
const result = sandboxPolicyWithHostFallback(getDotEnvPath(), boundary, {
|
|
350
|
+
mustExist: false,
|
|
351
|
+
});
|
|
352
|
+
expect(result.ok).toBe(false);
|
|
353
|
+
if (!result.ok) {
|
|
354
|
+
expect(result.reason).toBe("denied");
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
test("denies the default gateway security dir when the env is unset", () => {
|
|
359
|
+
const boundary = makeTempDir();
|
|
360
|
+
|
|
361
|
+
const result = sandboxPolicyWithHostFallback(
|
|
362
|
+
join(
|
|
363
|
+
process.env.HOME!,
|
|
364
|
+
".vellum",
|
|
365
|
+
"protected",
|
|
366
|
+
"actor-token-signing-key",
|
|
367
|
+
),
|
|
368
|
+
boundary,
|
|
369
|
+
{ mustExist: false },
|
|
370
|
+
);
|
|
371
|
+
expect(result.ok).toBe(false);
|
|
372
|
+
if (!result.ok) {
|
|
373
|
+
expect(result.reason).toBe("denied");
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test("denies the gateway security dir even when it sits inside the boundary", () => {
|
|
378
|
+
const boundary = makeTempDir();
|
|
379
|
+
const securityDir = join(boundary, "protected");
|
|
380
|
+
mkdirSync(securityDir);
|
|
381
|
+
process.env.GATEWAY_SECURITY_DIR = securityDir;
|
|
382
|
+
|
|
383
|
+
for (const policy of [sandboxPolicy, sandboxPolicyWithHostFallback]) {
|
|
384
|
+
const result = policy("protected/trust.json", boundary, {
|
|
385
|
+
mustExist: false,
|
|
386
|
+
});
|
|
387
|
+
expect(result.ok).toBe(false);
|
|
388
|
+
if (!result.ok) {
|
|
389
|
+
expect(result.reason).toBe("denied");
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
test("denies a dangling symlink pointing into the gateway security dir", () => {
|
|
395
|
+
const boundary = makeTempDir();
|
|
396
|
+
const outside = makeTempDir();
|
|
397
|
+
const securityDir = makeTempDir();
|
|
398
|
+
process.env.GATEWAY_SECURITY_DIR = securityDir;
|
|
399
|
+
// The destination does NOT exist — a write through the link would create
|
|
400
|
+
// it inside the security dir.
|
|
401
|
+
symlinkSync(
|
|
402
|
+
join(securityDir, "new-signing-key"),
|
|
403
|
+
join(outside, "innocent.txt"),
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
const result = sandboxPolicyWithHostFallback(
|
|
407
|
+
join(outside, "innocent.txt"),
|
|
408
|
+
boundary,
|
|
409
|
+
{ mustExist: false },
|
|
410
|
+
);
|
|
411
|
+
expect(result.ok).toBe(false);
|
|
412
|
+
if (!result.ok) {
|
|
413
|
+
expect(result.reason).toBe("denied");
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
test("denies a long dangling symlink chain into the gateway security dir", () => {
|
|
418
|
+
const boundary = makeTempDir();
|
|
419
|
+
const outside = makeTempDir();
|
|
420
|
+
const securityDir = makeTempDir();
|
|
421
|
+
process.env.GATEWAY_SECURITY_DIR = securityDir;
|
|
422
|
+
|
|
423
|
+
// A 33-link chain exceeds macOS's own 32-link traversal limit but stays
|
|
424
|
+
// within Linux's 40 — the policy must resolve past it either way.
|
|
425
|
+
let target = join(securityDir, "new-signing-key");
|
|
426
|
+
for (let i = 32; i >= 0; i--) {
|
|
427
|
+
const link = join(outside, `link-${i}`);
|
|
428
|
+
symlinkSync(target, link);
|
|
429
|
+
target = link;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const result = sandboxPolicyWithHostFallback(target, boundary, {
|
|
433
|
+
mustExist: false,
|
|
434
|
+
});
|
|
435
|
+
expect(result.ok).toBe(false);
|
|
436
|
+
if (!result.ok) {
|
|
437
|
+
expect(result.reason).toBe("denied");
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
test("denies a symlink that resolves into the gateway security dir", () => {
|
|
442
|
+
const boundary = makeTempDir();
|
|
443
|
+
const outside = makeTempDir();
|
|
444
|
+
const securityDir = makeTempDir();
|
|
445
|
+
process.env.GATEWAY_SECURITY_DIR = securityDir;
|
|
446
|
+
writeFileSync(join(securityDir, "trust.json"), "{}");
|
|
447
|
+
symlinkSync(
|
|
448
|
+
join(securityDir, "trust.json"),
|
|
449
|
+
join(outside, "innocent.json"),
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
const result = sandboxPolicyWithHostFallback(
|
|
453
|
+
join(outside, "innocent.json"),
|
|
454
|
+
boundary,
|
|
455
|
+
);
|
|
456
|
+
expect(result.ok).toBe(false);
|
|
457
|
+
if (!result.ok) {
|
|
458
|
+
expect(result.reason).toBe("denied");
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
test("fails closed to the hard boundary when a security-dir override is relative", () => {
|
|
463
|
+
const boundary = makeTempDir();
|
|
464
|
+
const outside = makeTempDir();
|
|
465
|
+
// A relative override resolves against the owning service's cwd, which
|
|
466
|
+
// the daemon cannot know — the deny set is unmirrorable, so no escape
|
|
467
|
+
// is permitted at all.
|
|
468
|
+
process.env.GATEWAY_SECURITY_DIR = "relative/security-dir";
|
|
469
|
+
|
|
470
|
+
const result = sandboxPolicyWithHostFallback(
|
|
471
|
+
join(outside, "file.txt"),
|
|
472
|
+
boundary,
|
|
473
|
+
{ mustExist: false },
|
|
474
|
+
);
|
|
475
|
+
expect(result.ok).toBe(false);
|
|
476
|
+
if (!result.ok) {
|
|
477
|
+
expect(result.reason).toBe("out_of_bounds");
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test("keeps the hard boundary when containerized", () => {
|
|
482
|
+
const boundary = makeTempDir();
|
|
483
|
+
const outside = makeTempDir();
|
|
484
|
+
process.env.IS_CONTAINERIZED = "true";
|
|
485
|
+
|
|
486
|
+
const result = sandboxPolicyWithHostFallback(
|
|
487
|
+
join(outside, "file.txt"),
|
|
488
|
+
boundary,
|
|
489
|
+
{ mustExist: false },
|
|
490
|
+
);
|
|
491
|
+
expect(result.ok).toBe(false);
|
|
492
|
+
if (!result.ok) {
|
|
493
|
+
expect(result.reason).toBe("out_of_bounds");
|
|
494
|
+
expect(result.error).toContain("outside the working directory");
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
test("still accepts in-bounds paths when containerized", () => {
|
|
499
|
+
const boundary = makeTempDir();
|
|
500
|
+
process.env.IS_CONTAINERIZED = "true";
|
|
501
|
+
|
|
502
|
+
const result = sandboxPolicyWithHostFallback("file.txt", boundary, {
|
|
503
|
+
mustExist: false,
|
|
504
|
+
});
|
|
505
|
+
expect(result.ok).toBe(true);
|
|
506
|
+
});
|
|
507
|
+
});
|
|
508
|
+
|
|
194
509
|
// ---------------------------------------------------------------------------
|
|
195
510
|
// Host policy
|
|
196
511
|
// ---------------------------------------------------------------------------
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
|
|
11
11
|
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
12
12
|
|
|
13
|
-
import type {
|
|
13
|
+
import type { AssistantEvent } from "../api/index.js";
|
|
14
14
|
|
|
15
15
|
// Capture every broadcast emitted by the tracker. The real hub is replaced
|
|
16
16
|
// with a thin recorder so we can assert payloads deterministically.
|
|
17
|
-
const publishedMessages:
|
|
17
|
+
const publishedMessages: AssistantEvent[] = [];
|
|
18
18
|
|
|
19
19
|
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
20
|
-
broadcastMessage: (msg:
|
|
20
|
+
broadcastMessage: (msg: AssistantEvent) => {
|
|
21
21
|
publishedMessages.push(msg);
|
|
22
22
|
},
|
|
23
23
|
capabilityForMessageType: () => undefined,
|
|
@@ -41,7 +41,7 @@ afterEach(() => {
|
|
|
41
41
|
function lastResolvedEvent() {
|
|
42
42
|
const evt = publishedMessages.find((m) => m.type === "interaction_resolved");
|
|
43
43
|
expect(evt).toBeDefined();
|
|
44
|
-
return evt as Extract<
|
|
44
|
+
return evt as Extract<AssistantEvent, { type: "interaction_resolved" }>;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
describe("pendingInteractions.resolve emits interaction_resolved", () => {
|
|
@@ -181,7 +181,7 @@ describe("removeByConversation emits interaction_resolved per entry", () => {
|
|
|
181
181
|
|
|
182
182
|
const events = publishedMessages.filter(
|
|
183
183
|
(m) => m.type === "interaction_resolved",
|
|
184
|
-
) as Extract<
|
|
184
|
+
) as Extract<AssistantEvent, { type: "interaction_resolved" }>[];
|
|
185
185
|
expect(events).toHaveLength(2);
|
|
186
186
|
expect(events.every((e) => e.state === "superseded")).toBe(true);
|
|
187
187
|
const requestIds = new Set(events.map((e) => e.requestId));
|
|
@@ -207,7 +207,7 @@ describe("removeByConversation emits interaction_resolved per entry", () => {
|
|
|
207
207
|
);
|
|
208
208
|
expect(events).toHaveLength(1);
|
|
209
209
|
expect(
|
|
210
|
-
(events[0] as Extract<
|
|
210
|
+
(events[0] as Extract<AssistantEvent, { type: "interaction_resolved" }>)
|
|
211
211
|
.state,
|
|
212
212
|
).toBe("cancelled");
|
|
213
213
|
});
|
|
@@ -65,7 +65,7 @@ const PERSISTENCE_TO_MEMORY_ALLOWLIST: Record<string, ReadonlySet<string>> = {
|
|
|
65
65
|
*
|
|
66
66
|
* `steps.ts` is the ordered list of every migration step; it imports each
|
|
67
67
|
* migration's forward/down function from the domain that owns it (memory's
|
|
68
|
-
* `graph/bootstrap`, apps' `app-store`, …). Migrations are append-only and
|
|
68
|
+
* `v1/graph/bootstrap`, apps' `app-store`, …). Migrations are append-only and
|
|
69
69
|
* checkpointed by stable function name, so they live in their owning feature by
|
|
70
70
|
* design and are merely *referenced* here by the registry — this is the
|
|
71
71
|
* registry's job, not a layering violation to ratchet to zero. Validated by the
|
|
@@ -73,7 +73,7 @@ const PERSISTENCE_TO_MEMORY_ALLOWLIST: Record<string, ReadonlySet<string>> = {
|
|
|
73
73
|
* entry here.
|
|
74
74
|
*/
|
|
75
75
|
const MIGRATION_REGISTRY_MEMORY_IMPORTS: Record<string, ReadonlySet<string>> = {
|
|
76
|
-
"assistant/src/persistence/steps.ts": new Set(["graph/bootstrap"]),
|
|
76
|
+
"assistant/src/persistence/steps.ts": new Set(["v1/graph/bootstrap"]),
|
|
77
77
|
};
|
|
78
78
|
|
|
79
79
|
/** Match `from "x"`, `import "x"`, `import("x")`, and `mock.module("x", …)`. */
|
|
@@ -6,7 +6,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
|
6
6
|
import {
|
|
7
7
|
getPkbAutoInjectList,
|
|
8
8
|
readAutoinjectList,
|
|
9
|
-
} from "../plugins/defaults/memory/pkb/autoinject.js";
|
|
9
|
+
} from "../plugins/defaults/memory/v1/pkb/autoinject.js";
|
|
10
10
|
|
|
11
11
|
const PKB_DEFAULT_FILES = [
|
|
12
12
|
"INDEX.md",
|
|
@@ -92,6 +92,7 @@ mock.module("../tools/registry.js", () => ({
|
|
|
92
92
|
|
|
93
93
|
mock.module("../tools/shared/filesystem/path-policy.js", () => ({
|
|
94
94
|
sandboxPolicy: () => ({ ok: false }),
|
|
95
|
+
sandboxPolicyWithHostFallback: () => ({ ok: false }),
|
|
95
96
|
hostPolicy: () => ({ ok: false }),
|
|
96
97
|
}));
|
|
97
98
|
|
|
@@ -7,27 +7,27 @@ let mockPlatformBaseUrl = "";
|
|
|
7
7
|
let mockPlatformAssistantId = "";
|
|
8
8
|
let mockSecureKeys: Record<string, string> = {};
|
|
9
9
|
|
|
10
|
+
// Bun shares mocked modules across test files in a combined run, so each mock
|
|
11
|
+
// spreads the real module and overrides only what this file drives. Replacing
|
|
12
|
+
// a module wholesale drops the exports peer tests import from it and breaks
|
|
13
|
+
// their ESM named-import validation whenever this mock wins evaluation.
|
|
14
|
+
const actualEnvRegistry = await import("../config/env-registry.js");
|
|
10
15
|
mock.module("../config/env-registry.js", () => ({
|
|
16
|
+
...actualEnvRegistry,
|
|
11
17
|
getIsPlatform: () => mockIsPlatform,
|
|
12
|
-
// Not called by this test, but the real util/logger.js + util/platform.js
|
|
13
|
-
// (loaded now that the logger is silent under test instead of mocked)
|
|
14
|
-
// import these names, and ESM named-import validation requires them.
|
|
15
|
-
getWorkspaceDirOverride: () => process.env.VELLUM_WORKSPACE_DIR,
|
|
16
|
-
getDebugStdoutLogs: () => false,
|
|
17
|
-
getIsContainerized: () => false,
|
|
18
18
|
}));
|
|
19
19
|
|
|
20
|
+
const actualEnv = await import("../config/env.js");
|
|
20
21
|
mock.module("../config/env.js", () => ({
|
|
22
|
+
...actualEnv,
|
|
21
23
|
getPlatformBaseUrl: () => mockPlatformBaseUrl,
|
|
22
24
|
getPlatformAssistantId: () => mockPlatformAssistantId,
|
|
23
25
|
}));
|
|
24
26
|
|
|
27
|
+
const actualSecureKeys = await import("../security/secure-keys.js");
|
|
25
28
|
mock.module("../security/secure-keys.js", () => ({
|
|
29
|
+
...actualSecureKeys,
|
|
26
30
|
getSecureKeyAsync: async (key: string) => mockSecureKeys[key] ?? undefined,
|
|
27
|
-
// Bun shares mocked modules across test files in a combined run; peer
|
|
28
|
-
// tests import this name from the same module, so stub it to keep their
|
|
29
|
-
// ESM named-import validation satisfied when this mock wins evaluation.
|
|
30
|
-
deleteSecureKeyAsync: async () => ({ deleted: false }),
|
|
31
31
|
}));
|
|
32
32
|
|
|
33
33
|
const originalFetch = globalThis.fetch;
|
|
@@ -10,13 +10,17 @@
|
|
|
10
10
|
|
|
11
11
|
import { describe, expect, test } from "bun:test";
|
|
12
12
|
|
|
13
|
+
import type { AssistantEventEnvelope } from "../api/index.js";
|
|
13
14
|
import { assistantEventHub as pluginHub } from "../plugin-api/index.js";
|
|
14
|
-
import type { AssistantEvent } from "../runtime/assistant-event.js";
|
|
15
15
|
import { assistantEventHub as rawHub } from "../runtime/assistant-event-hub.js";
|
|
16
16
|
|
|
17
|
+
// The hub's `publish` fans out locally only in the main daemon; elsewhere it
|
|
18
|
+
// forwards over IPC. A test process defaults to "main daemon" (set by the test
|
|
19
|
+
// preload), so these local-delivery assertions hold.
|
|
20
|
+
|
|
17
21
|
/** Minimal event envelope; the facade guard keys only off `message.type`. */
|
|
18
|
-
function envelope(type: string):
|
|
19
|
-
return { message: { type } } as unknown as
|
|
22
|
+
function envelope(type: string): AssistantEventEnvelope {
|
|
23
|
+
return { message: { type } } as unknown as AssistantEventEnvelope;
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
function eventType(event: unknown): unknown {
|
|
@@ -24,7 +28,7 @@ function eventType(event: unknown): unknown {
|
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
/** Register a host-capable desktop client subscriber on the raw hub. */
|
|
27
|
-
function subscribeHostClient(clientId: string, sink:
|
|
31
|
+
function subscribeHostClient(clientId: string, sink: AssistantEventEnvelope[]) {
|
|
28
32
|
return rawHub.subscribe({
|
|
29
33
|
type: "client",
|
|
30
34
|
clientId,
|
|
@@ -65,11 +69,14 @@ describe("plugin-facing assistantEventHub facade", () => {
|
|
|
65
69
|
const proto = Object.getPrototypeOf(pluginHub) as { publish?: unknown };
|
|
66
70
|
expect(typeof proto?.publish).not.toBe("function");
|
|
67
71
|
|
|
68
|
-
const received:
|
|
72
|
+
const received: AssistantEventEnvelope[] = [];
|
|
69
73
|
const sub = subscribeHostClient("facade-proto-client", received);
|
|
70
74
|
try {
|
|
71
75
|
const p = Object.getPrototypeOf(pluginHub) as {
|
|
72
|
-
publish?: (
|
|
76
|
+
publish?: (
|
|
77
|
+
event: AssistantEventEnvelope,
|
|
78
|
+
options?: unknown,
|
|
79
|
+
) => Promise<void>;
|
|
73
80
|
} | null;
|
|
74
81
|
await p?.publish?.call(pluginHub, envelope("host_bash_request"), {
|
|
75
82
|
targetClientId: "facade-proto-client",
|
|
@@ -97,7 +104,7 @@ describe("plugin-facing assistantEventHub facade", () => {
|
|
|
97
104
|
});
|
|
98
105
|
|
|
99
106
|
test("snapshots the event so a mutating type getter cannot bypass the guard (Codex P1)", async () => {
|
|
100
|
-
const received:
|
|
107
|
+
const received: AssistantEventEnvelope[] = [];
|
|
101
108
|
const sub = subscribeHostClient("facade-toctou-client", received);
|
|
102
109
|
try {
|
|
103
110
|
// `message.type` reads benign first (what the guard would see) then turns
|
|
@@ -111,7 +118,7 @@ describe("plugin-facing assistantEventHub facade", () => {
|
|
|
111
118
|
return reads === 1 ? "sync_changed" : "host_bash_request";
|
|
112
119
|
},
|
|
113
120
|
});
|
|
114
|
-
const sneaky = { message } as unknown as
|
|
121
|
+
const sneaky = { message } as unknown as AssistantEventEnvelope;
|
|
115
122
|
|
|
116
123
|
await pluginHub.publish(sneaky, {
|
|
117
124
|
targetClientId: "facade-toctou-client",
|
|
@@ -127,7 +134,7 @@ describe("plugin-facing assistantEventHub facade", () => {
|
|
|
127
134
|
});
|
|
128
135
|
|
|
129
136
|
test("freezes the published snapshot so a subscriber cannot mutate it mid-fanout (Codex P1)", async () => {
|
|
130
|
-
const hostReceived:
|
|
137
|
+
const hostReceived: AssistantEventEnvelope[] = [];
|
|
131
138
|
// A malicious subscriber registered first tries to turn the in-flight event
|
|
132
139
|
// into a host request before the host-capable client (registered after)
|
|
133
140
|
// receives the same fanned-out object.
|
|
@@ -154,7 +161,7 @@ describe("plugin-facing assistantEventHub facade", () => {
|
|
|
154
161
|
});
|
|
155
162
|
|
|
156
163
|
test("rejects host events disguised as boxed strings (Codex P1)", async () => {
|
|
157
|
-
const received:
|
|
164
|
+
const received: AssistantEventEnvelope[] = [];
|
|
158
165
|
const sub = subscribeHostClient("facade-boxed-client", received);
|
|
159
166
|
try {
|
|
160
167
|
// `new String(...)` is typeof "object" (slipping a naive string guard) but
|
|
@@ -164,7 +171,7 @@ describe("plugin-facing assistantEventHub facade", () => {
|
|
|
164
171
|
const boxedType = new String("host_bash_request");
|
|
165
172
|
const boxed = {
|
|
166
173
|
message: { type: boxedType },
|
|
167
|
-
} as unknown as
|
|
174
|
+
} as unknown as AssistantEventEnvelope;
|
|
168
175
|
let rejected: unknown;
|
|
169
176
|
try {
|
|
170
177
|
await pluginHub.publish(boxed, {
|
|
@@ -183,7 +190,7 @@ describe("plugin-facing assistantEventHub facade", () => {
|
|
|
183
190
|
});
|
|
184
191
|
|
|
185
192
|
test("delegates non-host publish to the shared singleton", async () => {
|
|
186
|
-
const received:
|
|
193
|
+
const received: AssistantEventEnvelope[] = [];
|
|
187
194
|
// Subscribe on the RAW hub, publish through the FACADE: delivery proves the
|
|
188
195
|
// facade delegates to the same instance (shared subscriber state). The
|
|
189
196
|
// delivered event is a snapshot, so it is compared by value, not identity.
|
|
@@ -214,7 +221,7 @@ describe("plugin-facing assistantEventHub facade", () => {
|
|
|
214
221
|
});
|
|
215
222
|
|
|
216
223
|
test("downgrades plugin client subscriptions to in-process (no host-event interception) (Codex P1)", async () => {
|
|
217
|
-
const received:
|
|
224
|
+
const received: AssistantEventEnvelope[] = [];
|
|
218
225
|
// Ask for a host-capable client subscription; the facade must register a
|
|
219
226
|
// process subscriber, which never receives capability-targeted host events.
|
|
220
227
|
const sub = pluginHub.subscribe({
|
|
@@ -237,7 +244,7 @@ describe("plugin-facing assistantEventHub facade", () => {
|
|
|
237
244
|
});
|
|
238
245
|
|
|
239
246
|
test("isolates plugin callbacks so they cannot mutate the in-flight fanout event (Codex P1)", async () => {
|
|
240
|
-
const hostReceived:
|
|
247
|
+
const hostReceived: AssistantEventEnvelope[] = [];
|
|
241
248
|
// The plugin subscribes first and, from its callback, tries to rewrite the
|
|
242
249
|
// shared in-flight event into a host request. It must only see an isolated
|
|
243
250
|
// copy, leaving the real client's event untouched.
|
|
@@ -292,7 +299,7 @@ describe("plugin-facing assistantEventHub facade", () => {
|
|
|
292
299
|
{
|
|
293
300
|
message: { type: "host_bash_request" },
|
|
294
301
|
conversationId: "conv-1",
|
|
295
|
-
} as unknown as
|
|
302
|
+
} as unknown as AssistantEventEnvelope,
|
|
296
303
|
{ targetCapability: "host_bash" },
|
|
297
304
|
);
|
|
298
305
|
expect(getterCalls).toBe(callsAfterSubscribe);
|