@vellumai/assistant 0.10.1 → 0.10.2-dev.202606241651.2d2b40d
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/docs/workspace-tools.md +42 -33
- package/eslint-rules/cli-no-daemon-internals.js +6 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +31 -0
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +14 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +17 -0
- package/openapi.yaml +74 -1
- package/package.json +1 -1
- package/scripts/test.sh +36 -15
- package/src/__tests__/actor-token-service.test.ts +36 -14
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +2 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -0
- package/src/__tests__/approval-cascade.test.ts +2 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -0
- package/src/__tests__/btw-routes.test.ts +2 -0
- package/src/__tests__/build-persisted-content.test.ts +2 -0
- package/src/__tests__/call-controller.test.ts +19 -0
- package/src/__tests__/channel-guardian.test.ts +94 -58
- package/src/__tests__/channel-reply-delivery.test.ts +2 -0
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +2 -0
- package/src/__tests__/compactor-low-watermark-cut.test.ts +2 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +2 -0
- package/src/__tests__/compactor-summary-call-truncation.test.ts +2 -0
- package/src/__tests__/compactor-web-search-strip.test.ts +2 -0
- package/src/__tests__/computer-use-tools.test.ts +13 -0
- package/src/__tests__/config-loader-backfill.test.ts +5 -1
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +31 -29
- package/src/__tests__/contacts-relay-reads.test.ts +13 -15
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +7 -0
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -0
- package/src/__tests__/conversation-history-web-search.test.ts +2 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -0
- package/src/__tests__/conversation-load-history-stripped.test.ts +2 -0
- package/src/__tests__/conversation-pairing.test.ts +2 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
- package/src/__tests__/conversation-process-callsite.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +91 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +14 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +14 -0
- package/src/__tests__/conversation-slash-queue.test.ts +2 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-speed-override.test.ts +2 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +65 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -0
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
- package/src/__tests__/conversation-usage.test.ts +2 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/db-migration-rollback.test.ts +205 -171
- package/src/__tests__/db-test-helpers.ts +5 -4
- package/src/__tests__/deterministic-verification-control-plane.test.ts +4 -2
- package/src/__tests__/disk-pressure-guard.test.ts +41 -0
- package/src/__tests__/dm-persistence.test.ts +2 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +10 -5
- package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
- package/src/__tests__/filing-service.test.ts +2 -0
- package/src/__tests__/guardian-binding-drift-heal.test.ts +75 -10
- package/src/__tests__/guardian-dispatch.test.ts +95 -1
- package/src/__tests__/guardian-outbound-http.test.ts +13 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
- package/src/__tests__/heartbeat-service.test.ts +2 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +1 -7
- package/src/__tests__/host-app-control-routes.test.ts +24 -30
- package/src/__tests__/host-bash-routes.test.ts +31 -41
- package/src/__tests__/host-browser-routes.test.ts +26 -32
- package/src/__tests__/host-cu-proxy.test.ts +299 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
- package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
- package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
- package/src/__tests__/http-user-message-parity.test.ts +167 -8
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/invite-redemption-service.test.ts +43 -0
- package/src/__tests__/llm-context-normalization.test.ts +105 -0
- package/src/__tests__/llm-usage-store.test.ts +25 -0
- package/src/__tests__/media-stream-server-integration.test.ts +127 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +2 -0
- package/src/__tests__/messaging-send-tool.test.ts +2 -0
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/native-web-search.test.ts +2 -0
- package/src/__tests__/non-member-access-request.test.ts +189 -17
- package/src/__tests__/notification-broadcaster.test.ts +4 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
- package/src/__tests__/notification-deep-link.test.ts +6 -0
- package/src/__tests__/notification-guardian-path.test.ts +19 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
- package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
- package/src/__tests__/plugin-bootstrap.test.ts +3 -73
- package/src/__tests__/plugin-route-contribution.test.ts +4 -17
- package/src/__tests__/plugin-tool-contribution.test.ts +3 -18
- package/src/__tests__/plugin-types.test.ts +0 -2
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/process-message-display-content.test.ts +2 -0
- package/src/__tests__/provider-usage-tracking.test.ts +39 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +2 -0
- package/src/__tests__/registry.test.ts +3 -0
- package/src/__tests__/relay-server.test.ts +694 -25
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/secret-ingress-http.test.ts +14 -0
- package/src/__tests__/send-endpoint-busy.test.ts +30 -8
- package/src/__tests__/skills.test.ts +44 -0
- package/src/__tests__/slack-inbound-verification.test.ts +47 -2
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +102 -0
- package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
- package/src/__tests__/stt-hints.test.ts +44 -13
- package/src/__tests__/subagent-detail.test.ts +27 -0
- package/src/__tests__/subagent-disposal.test.ts +65 -0
- package/src/__tests__/subagent-notify-parent.test.ts +2 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +2 -0
- package/src/__tests__/subagent-tools.test.ts +2 -0
- package/src/__tests__/suggestion-routes.test.ts +2 -0
- package/src/__tests__/title-generate-hook.test.ts +2 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -0
- package/src/__tests__/tool-executor.test.ts +16 -11
- package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
- package/src/__tests__/twilio-routes.test.ts +96 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -0
- package/src/__tests__/web-search-backend-failure.test.ts +2 -0
- package/src/__tests__/workspace-tool-loader.test.ts +195 -2
- package/src/agent/loop-exclusive-tool.test.ts +150 -0
- package/src/agent/loop.ts +56 -0
- package/src/api/constants/sse-replay.ts +41 -0
- package/src/api/index.ts +6 -0
- package/src/api/responses/llm-request-log-entry.ts +25 -0
- package/src/api/responses/subagent-detail.ts +17 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +262 -4
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +10 -8
- package/src/calls/inbound-trust-reader.ts +17 -1
- package/src/calls/media-stream-server.ts +21 -0
- package/src/calls/relay-server.ts +167 -50
- package/src/calls/relay-setup-router.ts +37 -7
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/stt-hints.ts +9 -12
- package/src/calls/twilio-routes.ts +14 -4
- package/src/cli/commands/__tests__/cache.test.ts +8 -1
- package/src/cli/commands/cache.ts +194 -181
- package/src/cli/commands/db/__tests__/repair.test.ts +6 -5
- package/src/cli/commands/db/status.ts +37 -1
- package/src/cli/commands/mcp.ts +252 -218
- package/src/cli/commands/memory/__tests__/worker.test.ts +302 -0
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/worker.ts +175 -0
- package/src/cli/commands/plugins.ts +75 -3
- package/src/cli/lib/__tests__/install-from-github.test.ts +102 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
- package/src/cli/lib/list-installed-plugins.ts +179 -1
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +6 -1
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +27 -17
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +13 -3
- package/src/config/feature-flag-registry.json +0 -8
- package/src/config/loader.ts +36 -5
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/memory-lifecycle.ts +12 -0
- package/src/config/schemas/memory-v3.ts +7 -0
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/timeouts.ts +8 -0
- package/src/config/seed-inference-profiles.ts +14 -5
- package/src/config/skills.ts +27 -5
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
- package/src/contacts/contacts-write.ts +3 -0
- package/src/contacts/guardian-delivery-reader.ts +223 -0
- package/src/daemon/conversation-agent-loop.ts +9 -0
- package/src/daemon/conversation-process.ts +39 -17
- package/src/daemon/conversation-surfaces.ts +8 -0
- package/src/daemon/conversation-tool-setup.ts +49 -16
- package/src/daemon/conversation.ts +21 -2
- package/src/daemon/disk-pressure-guard.ts +12 -2
- package/src/daemon/event-loop-watchdog.ts +28 -1
- package/src/daemon/external-plugins-bootstrap.ts +4 -34
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +25 -0
- package/src/daemon/handlers/__tests__/config-channels.test.ts +225 -0
- package/src/daemon/handlers/config-a2a.ts +6 -14
- package/src/daemon/handlers/config-channels.ts +78 -22
- package/src/daemon/handlers/conversations.ts +77 -0
- package/src/daemon/host-cu-proxy.ts +102 -11
- package/src/daemon/lifecycle.ts +4 -0
- package/src/daemon/memory-v2-startup.test.ts +72 -0
- package/src/daemon/memory-v2-startup.ts +87 -19
- package/src/daemon/server.ts +0 -4
- package/src/daemon/shutdown-handlers.ts +20 -0
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/assistant-server.ts +2 -2
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
- package/src/memory/__tests__/prompt-override.test.ts +192 -0
- package/src/memory/__tests__/watchdog-events-store.test.ts +161 -0
- package/src/memory/conversation-crud.ts +38 -0
- package/src/memory/db-connection.ts +22 -3
- package/src/memory/db-init.ts +36 -502
- package/src/memory/db-singleton.ts +6 -4
- package/src/memory/jobs-worker.ts +58 -0
- package/src/memory/llm-usage-store.ts +48 -20
- package/src/memory/memory-retrospective-job.ts +9 -8
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +13 -3
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -27
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +130 -56
- package/src/memory/migrations/300-add-processing-started-at.ts +30 -0
- package/src/memory/migrations/301-create-watchdog-events.ts +45 -0
- package/src/memory/migrations/__tests__/014-backfill-inbox-thread-state.test.ts +108 -0
- package/src/memory/migrations/__tests__/136-drop-assistant-id-columns.test.ts +82 -0
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +224 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/run-migrations.ts +90 -6
- package/src/memory/migrations/schema-introspection.ts +14 -0
- package/src/memory/migrations/validate-migration-state.ts +101 -66
- package/src/memory/prompt-override.ts +129 -0
- package/src/memory/schema/conversations.ts +9 -0
- package/src/memory/schema/infrastructure.ts +20 -0
- package/src/memory/steps.ts +573 -0
- package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
- package/src/memory/v2/cli-command-store.ts +75 -38
- package/src/memory/v2/prompts/consolidation.ts +13 -82
- package/src/memory/v2/prompts/router.ts +21 -93
- package/src/memory/v2/skill-store.ts +68 -31
- package/src/memory/watchdog-events-store.ts +87 -0
- package/src/memory/worker-control.ts +118 -0
- package/src/memory/worker-process.ts +72 -0
- package/src/notifications/__tests__/broadcaster.test.ts +16 -8
- package/src/notifications/__tests__/connected-channels.test.ts +114 -0
- package/src/notifications/__tests__/decision-engine.test.ts +78 -9
- package/src/notifications/__tests__/destination-resolver.test.ts +256 -0
- package/src/notifications/broadcaster.ts +8 -1
- package/src/notifications/decision-engine.ts +15 -7
- package/src/notifications/destination-resolver.ts +68 -24
- package/src/notifications/emit-signal.ts +39 -14
- package/src/onboarding/checkin-event.test.ts +220 -0
- package/src/onboarding/checkin-event.ts +321 -0
- package/src/onboarding/schedule-checkin.ts +190 -0
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +7 -4
- package/src/plugin-api/index.ts +6 -6
- package/src/plugin-api/types.ts +3 -5
- package/src/plugin-api/vision-support.test.ts +28 -4
- package/src/plugin-api/vision-support.ts +66 -31
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +161 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +106 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +60 -0
- package/src/plugins/defaults/advisor/consult.ts +110 -6
- package/src/plugins/defaults/advisor/context-pack.ts +288 -0
- package/src/plugins/defaults/advisor/steering.ts +14 -2
- package/src/plugins/defaults/advisor/tools/advisor.ts +32 -5
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +47 -7
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +10 -11
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +12 -20
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +42 -11
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +29 -1
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +8 -1
- package/src/plugins/mtime-cache.ts +7 -2
- package/src/plugins/types.ts +0 -2
- package/src/providers/anthropic/client.ts +5 -0
- package/src/providers/call-site-routing.ts +4 -0
- package/src/providers/model-catalog.ts +16 -0
- package/src/providers/openai/responses-provider.ts +5 -0
- package/src/providers/openrouter/client.ts +5 -0
- package/src/providers/provider-send-message.ts +4 -0
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/retry.ts +4 -0
- package/src/providers/types.ts +9 -0
- package/src/providers/usage-tracking.ts +4 -0
- package/src/runtime/__tests__/channel-verification-service.test.ts +133 -0
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +181 -0
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +66 -0
- package/src/runtime/__tests__/local-principal-trust.test.ts +164 -0
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +335 -3
- package/src/runtime/access-request-helper.ts +19 -39
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/anchored-guardian.test.ts +156 -0
- package/src/runtime/anchored-guardian.ts +135 -0
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +9 -2
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
- package/src/runtime/auth/require-bound-guardian.ts +21 -11
- package/src/runtime/channel-verification-service.ts +56 -31
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
- package/src/runtime/guardian-vellum-migration.ts +66 -7
- package/src/runtime/invite-redemption-service.ts +50 -18
- package/src/runtime/local-actor-identity.ts +76 -11
- package/src/runtime/local-principal-trust.ts +52 -0
- package/src/runtime/pending-interactions.ts +11 -1
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +56 -5
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/contact-routes.test.ts +212 -0
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +93 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +215 -1
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +8 -32
- package/src/runtime/routes/conversation-cli-routes.ts +4 -5
- package/src/runtime/routes/conversation-list-routes.ts +4 -7
- package/src/runtime/routes/conversation-routes.ts +74 -81
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +3 -1
- package/src/runtime/routes/guardian-action-routes.ts +4 -5
- package/src/runtime/routes/host-app-control-routes.ts +5 -4
- package/src/runtime/routes/host-bash-routes.ts +5 -4
- package/src/runtime/routes/host-browser-routes.ts +9 -11
- package/src/runtime/routes/host-cu-routes.ts +5 -4
- package/src/runtime/routes/host-file-routes.ts +5 -4
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +3 -2
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +97 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +61 -49
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +16 -4
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/llm-context-normalization.ts +71 -0
- package/src/runtime/routes/mcp-auth-routes.ts +38 -15
- package/src/runtime/routes/migration-rollback-routes.ts +4 -3
- package/src/runtime/routes/migration-routes.ts +4 -1
- package/src/runtime/routes/onboarding-checkin-routes.ts +86 -0
- package/src/runtime/routes/subagents-routes.ts +5 -0
- package/src/runtime/routes/surface-action-routes.ts +51 -55
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +7 -9
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +85 -9
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +16 -0
- package/src/subagent/manager.ts +9 -0
- package/src/telemetry/types.ts +34 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
- package/src/telemetry/usage-telemetry-reporter.ts +87 -3
- package/src/tools/ask-question/ask-question-tool.test.ts +29 -0
- package/src/tools/ask-question/ask-question-tool.ts +13 -0
- package/src/tools/computer-use/definitions.ts +8 -2
- package/src/tools/executor.ts +4 -4
- package/src/tools/registry.ts +18 -0
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +9 -2
- package/src/tools/types.ts +17 -2
- package/src/tools/workspace-tools/loader.ts +348 -244
- package/src/util/platform.ts +5 -0
- package/src/util/telemetry-db-path.ts +24 -0
- package/src/workspace/migrations/017-seed-persona-dirs.ts +3 -34
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +3 -24
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +0 -70
- package/src/daemon/workspace-tools-watcher.ts +0 -328
- package/src/memory/migrations/registry.ts +0 -573
|
@@ -36,17 +36,36 @@ mock.module("../prompts/system-prompt.js", () => ({
|
|
|
36
36
|
buildCoreIdentityContext: () => null,
|
|
37
37
|
}));
|
|
38
38
|
|
|
39
|
-
// ── Guardian contact
|
|
39
|
+
// ── Guardian binding + contact notes mocks ───────────────────────────
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
} | null =
|
|
41
|
+
// Guardian binding (ACL) is resolved via the gateway pull; notes (INFO) are
|
|
42
|
+
// joined locally by contactId. Tests drive both via mutable slots.
|
|
43
|
+
let guardianDeliveryFixture: Array<{ contactId: string }> = [];
|
|
44
|
+
let contactInfoFixture: Record<string, { notes: string | null } | null> = {};
|
|
45
|
+
|
|
46
|
+
mock.module("../contacts/guardian-delivery-reader.js", () => ({
|
|
47
|
+
getGuardianDelivery: async () => guardianDeliveryFixture,
|
|
48
|
+
anyGuardian: (list: Array<{ contactId: string }>) => list[0],
|
|
49
|
+
}));
|
|
45
50
|
|
|
46
51
|
mock.module("../contacts/contact-store.js", () => ({
|
|
47
|
-
|
|
52
|
+
findContactInfoById: (contactId: string) =>
|
|
53
|
+
contactInfoFixture[contactId] ?? null,
|
|
48
54
|
}));
|
|
49
55
|
|
|
56
|
+
const GUARDIAN_CONTACT_ID = "guardian-contact-1";
|
|
57
|
+
|
|
58
|
+
/** Bind a guardian with the given notes (or no guardian when notes is null). */
|
|
59
|
+
function setGuardian(notes: string | null | undefined): void {
|
|
60
|
+
if (notes === undefined) {
|
|
61
|
+
guardianDeliveryFixture = [];
|
|
62
|
+
contactInfoFixture = {};
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
guardianDeliveryFixture = [{ contactId: GUARDIAN_CONTACT_ID }];
|
|
66
|
+
contactInfoFixture = { [GUARDIAN_CONTACT_ID]: { notes } };
|
|
67
|
+
}
|
|
68
|
+
|
|
50
69
|
// ── Provider mock with system prompt capture ──────────────────────────
|
|
51
70
|
|
|
52
71
|
let configuredProvider: {
|
|
@@ -134,15 +153,12 @@ describe("recipient context in notification decision engine", () => {
|
|
|
134
153
|
beforeEach(() => {
|
|
135
154
|
configuredProvider = null;
|
|
136
155
|
extractedToolUse = null;
|
|
137
|
-
|
|
156
|
+
setGuardian(undefined);
|
|
138
157
|
capturedSystemPrompt = undefined;
|
|
139
158
|
});
|
|
140
159
|
|
|
141
160
|
test("guardian contact notes appear in system prompt as <recipient-context>", async () => {
|
|
142
|
-
|
|
143
|
-
contact: { notes: "Prefers formal tone. Address as Dr. Smith." },
|
|
144
|
-
channels: [{ type: "vellum" }],
|
|
145
|
-
};
|
|
161
|
+
setGuardian("Prefers formal tone. Address as Dr. Smith.");
|
|
146
162
|
setupLLMProvider();
|
|
147
163
|
|
|
148
164
|
const signal = makeSignal();
|
|
@@ -157,7 +173,7 @@ describe("recipient context in notification decision engine", () => {
|
|
|
157
173
|
});
|
|
158
174
|
|
|
159
175
|
test("recipient-context is omitted when no guardian exists", async () => {
|
|
160
|
-
|
|
176
|
+
setGuardian(undefined);
|
|
161
177
|
setupLLMProvider();
|
|
162
178
|
|
|
163
179
|
const signal = makeSignal();
|
|
@@ -169,10 +185,7 @@ describe("recipient context in notification decision engine", () => {
|
|
|
169
185
|
});
|
|
170
186
|
|
|
171
187
|
test("recipient-context is omitted when guardian notes are null", async () => {
|
|
172
|
-
|
|
173
|
-
contact: { notes: null },
|
|
174
|
-
channels: [{ type: "vellum" }],
|
|
175
|
-
};
|
|
188
|
+
setGuardian(null);
|
|
176
189
|
setupLLMProvider();
|
|
177
190
|
|
|
178
191
|
const signal = makeSignal();
|
|
@@ -184,10 +197,7 @@ describe("recipient context in notification decision engine", () => {
|
|
|
184
197
|
});
|
|
185
198
|
|
|
186
199
|
test("recipient-context is omitted when guardian notes are empty string", async () => {
|
|
187
|
-
|
|
188
|
-
contact: { notes: "" },
|
|
189
|
-
channels: [{ type: "vellum" }],
|
|
190
|
-
};
|
|
200
|
+
setGuardian("");
|
|
191
201
|
setupLLMProvider();
|
|
192
202
|
|
|
193
203
|
const signal = makeSignal();
|
|
@@ -199,10 +209,7 @@ describe("recipient context in notification decision engine", () => {
|
|
|
199
209
|
});
|
|
200
210
|
|
|
201
211
|
test("large guardian notes are truncated to prevent oversized prompts", async () => {
|
|
202
|
-
|
|
203
|
-
contact: { notes: "N".repeat(3000) },
|
|
204
|
-
channels: [{ type: "vellum" }],
|
|
205
|
-
};
|
|
212
|
+
setGuardian("N".repeat(3000));
|
|
206
213
|
setupLLMProvider();
|
|
207
214
|
|
|
208
215
|
const signal = makeSignal();
|
|
@@ -226,10 +233,7 @@ describe("recipient context in notification decision engine", () => {
|
|
|
226
233
|
});
|
|
227
234
|
|
|
228
235
|
test("fallback path works correctly without recipient context", async () => {
|
|
229
|
-
|
|
230
|
-
contact: { notes: "Prefers formal tone." },
|
|
231
|
-
channels: [{ type: "vellum" }],
|
|
232
|
-
};
|
|
236
|
+
setGuardian("Prefers formal tone.");
|
|
233
237
|
// null provider forces fallback path
|
|
234
238
|
configuredProvider = null;
|
|
235
239
|
|
|
@@ -247,10 +251,7 @@ describe("recipient context in notification decision engine", () => {
|
|
|
247
251
|
});
|
|
248
252
|
|
|
249
253
|
test("recipient-context appears after user-preferences in prompt", async () => {
|
|
250
|
-
|
|
251
|
-
contact: { notes: "Prefers brief updates." },
|
|
252
|
-
channels: [{ type: "vellum" }],
|
|
253
|
-
};
|
|
254
|
+
setGuardian("Prefers brief updates.");
|
|
254
255
|
setupLLMProvider();
|
|
255
256
|
|
|
256
257
|
const signal = makeSignal();
|
|
@@ -20,6 +20,10 @@ mock.module("../util/logger.js", () => ({
|
|
|
20
20
|
}),
|
|
21
21
|
}));
|
|
22
22
|
|
|
23
|
+
mock.module("../contacts/guardian-delivery-reader.js", () => ({
|
|
24
|
+
getGuardianDelivery: async () => null,
|
|
25
|
+
}));
|
|
26
|
+
|
|
23
27
|
// Mock destination-resolver for broadcaster tests
|
|
24
28
|
mock.module("../notifications/destination-resolver.js", () => ({
|
|
25
29
|
resolveDestinations: (channels: string[]) => {
|
|
@@ -42,6 +46,8 @@ mock.module("../notifications/deliveries-store.js", () => ({
|
|
|
42
46
|
// can be driven from tests without DB access.
|
|
43
47
|
let mockExistingConversations: Record<string, { id: string }> = {};
|
|
44
48
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
49
|
+
setConversationProcessingStartedAt: () => {},
|
|
50
|
+
isConversationProcessing: () => false,
|
|
45
51
|
getConversation: (id: string) => mockExistingConversations[id] ?? null,
|
|
46
52
|
}));
|
|
47
53
|
|
|
@@ -68,6 +68,25 @@ mock.module("../notifications/emit-signal.js", () => ({
|
|
|
68
68
|
},
|
|
69
69
|
}));
|
|
70
70
|
|
|
71
|
+
// Guardian principalId is resolved from the gateway binding reader. Mirror the
|
|
72
|
+
// seeded vellum binding so dispatch can resolve the principal.
|
|
73
|
+
mock.module("../contacts/guardian-delivery-reader.js", () => ({
|
|
74
|
+
getGuardianDelivery: async () => [
|
|
75
|
+
{
|
|
76
|
+
channelType: "vellum",
|
|
77
|
+
contactId: "guardian-vellum",
|
|
78
|
+
principalId: "test-principal-id",
|
|
79
|
+
address: "local",
|
|
80
|
+
status: "active",
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
guardianForChannel: (
|
|
84
|
+
list: Array<{ channelType: string; status: string }>,
|
|
85
|
+
channelType: string,
|
|
86
|
+
) => list.find((g) => g.channelType === channelType && g.status === "active"),
|
|
87
|
+
anyGuardian: (list: unknown[]) => list[0],
|
|
88
|
+
}));
|
|
89
|
+
|
|
71
90
|
import {
|
|
72
91
|
createCallSession,
|
|
73
92
|
createPendingQuestion,
|
|
@@ -72,6 +72,8 @@ const persistedRows: Array<{
|
|
|
72
72
|
metadata: string | null;
|
|
73
73
|
}> = [];
|
|
74
74
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
75
|
+
setConversationProcessingStartedAt: () => {},
|
|
76
|
+
isConversationProcessing: () => false,
|
|
75
77
|
addMessage: (
|
|
76
78
|
conversationId: string,
|
|
77
79
|
role: string,
|
|
@@ -155,7 +155,7 @@ describe("pendingInteractions.resolve emits interaction_resolved", () => {
|
|
|
155
155
|
});
|
|
156
156
|
|
|
157
157
|
describe("removeByConversation emits interaction_resolved per entry", () => {
|
|
158
|
-
test("emits superseded for every
|
|
158
|
+
test("emits superseded for every confirmation/secret interaction in the conversation", () => {
|
|
159
159
|
pendingInteractions.register("conf-1", {
|
|
160
160
|
conversationId: "conv-x",
|
|
161
161
|
kind: "confirmation",
|
|
@@ -182,13 +182,16 @@ describe("removeByConversation emits interaction_resolved per entry", () => {
|
|
|
182
182
|
const events = publishedMessages.filter(
|
|
183
183
|
(m) => m.type === "interaction_resolved",
|
|
184
184
|
) as Extract<ServerMessage, { type: "interaction_resolved" }>[];
|
|
185
|
-
expect(events).toHaveLength(
|
|
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));
|
|
188
|
-
expect(requestIds).toEqual(new Set(["conf-1", "secret-1"
|
|
188
|
+
expect(requestIds).toEqual(new Set(["conf-1", "secret-1"]));
|
|
189
189
|
|
|
190
|
-
// host_bash entries survive auto-deny — no event for
|
|
190
|
+
// host_bash and question entries both survive auto-deny — no event for
|
|
191
|
+
// either. host proxies are settled by their result POST; questions by the
|
|
192
|
+
// enqueue steer's turn abort (see removeByConversation's skip list).
|
|
191
193
|
expect(pendingInteractions.get("host-bash-1")).toBeDefined();
|
|
194
|
+
expect(pendingInteractions.get("question-1")).toBeDefined();
|
|
192
195
|
// Unrelated conversation is untouched.
|
|
193
196
|
expect(pendingInteractions.get("conf-other")).toBeDefined();
|
|
194
197
|
});
|
|
@@ -48,6 +48,8 @@ interface AddMessageCall {
|
|
|
48
48
|
}
|
|
49
49
|
const addMessageCalls: AddMessageCall[] = [];
|
|
50
50
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
51
|
+
setConversationProcessingStartedAt: () => {},
|
|
52
|
+
isConversationProcessing: () => false,
|
|
51
53
|
addMessage: (
|
|
52
54
|
conversationId: string,
|
|
53
55
|
role: string,
|
|
@@ -4,32 +4,19 @@
|
|
|
4
4
|
* Covers:
|
|
5
5
|
* - A noop `init()` fires with a valid `PluginInitContext` that exposes every
|
|
6
6
|
* documented field.
|
|
7
|
-
* - `requiresCredential` entries are resolved through the credential store
|
|
8
|
-
* helper and arrive in `ctx.credentials`.
|
|
9
7
|
* - Version-mismatch registration fails with an error that names the plugin
|
|
10
8
|
* (the registry enforces this at `registerPlugin` time, so bootstrap never
|
|
11
9
|
* sees the malformed plugin).
|
|
12
10
|
* - Shutdown hook walks plugins in reverse registration order.
|
|
13
11
|
*
|
|
14
|
-
*
|
|
15
|
-
* resolution doesn't hit the real backend. `resetPluginRegistryForTests()`
|
|
16
|
-
* isolates registry state between cases.
|
|
12
|
+
* `resetPluginRegistryForTests()` isolates registry state between cases.
|
|
17
13
|
*/
|
|
18
14
|
|
|
19
15
|
import { existsSync } from "node:fs";
|
|
20
16
|
import { rm } from "node:fs/promises";
|
|
21
17
|
import { tmpdir } from "node:os";
|
|
22
18
|
import { join } from "node:path";
|
|
23
|
-
import { beforeEach, describe, expect,
|
|
24
|
-
|
|
25
|
-
// Mock credential store before importing the bootstrap module so the
|
|
26
|
-
// module-under-test captures the stubbed binding.
|
|
27
|
-
const getSecureKeyAsyncMock = mock(
|
|
28
|
-
async (_account: string): Promise<string | undefined> => undefined,
|
|
29
|
-
);
|
|
30
|
-
mock.module("../security/secure-keys.js", () => ({
|
|
31
|
-
getSecureKeyAsync: getSecureKeyAsyncMock,
|
|
32
|
-
}));
|
|
19
|
+
import { beforeEach, describe, expect, test } from "bun:test";
|
|
33
20
|
|
|
34
21
|
import { clearFeatureFlagOverridesCache } from "../config/assistant-feature-flags.js";
|
|
35
22
|
import { bootstrapPlugins } from "../daemon/external-plugins-bootstrap.js";
|
|
@@ -68,7 +55,6 @@ function buildPlugin(
|
|
|
68
55
|
onShutdown?: () => Promise<void>;
|
|
69
56
|
} = {},
|
|
70
57
|
options: {
|
|
71
|
-
requiresCredential?: string[];
|
|
72
58
|
requiresFlag?: string[];
|
|
73
59
|
} = {},
|
|
74
60
|
): Plugin {
|
|
@@ -94,9 +80,6 @@ function buildPlugin(
|
|
|
94
80
|
manifest: {
|
|
95
81
|
name,
|
|
96
82
|
version: "0.0.1",
|
|
97
|
-
...(options.requiresCredential
|
|
98
|
-
? { requiresCredential: options.requiresCredential }
|
|
99
|
-
: {}),
|
|
100
83
|
...(options.requiresFlag ? { requiresFlag: options.requiresFlag } : {}),
|
|
101
84
|
},
|
|
102
85
|
...rest,
|
|
@@ -107,8 +90,6 @@ function buildPlugin(
|
|
|
107
90
|
describe("plugin bootstrap", () => {
|
|
108
91
|
beforeEach(async () => {
|
|
109
92
|
resetPluginRegistryForTests();
|
|
110
|
-
getSecureKeyAsyncMock.mockReset();
|
|
111
|
-
getSecureKeyAsyncMock.mockImplementation(async () => undefined);
|
|
112
93
|
// Reset feature-flag cache so tests start from a known state. Individual
|
|
113
94
|
// tests that exercise `requiresFlag` use `setOverridesForTesting(...)`
|
|
114
95
|
// to install their own overrides.
|
|
@@ -133,7 +114,6 @@ describe("plugin bootstrap", () => {
|
|
|
133
114
|
|
|
134
115
|
// Every documented field must be present on the context passed to init.
|
|
135
116
|
expect(ctx.config).toBeUndefined(); // no `plugins.alpha` block in fake config
|
|
136
|
-
expect(ctx.credentials).toEqual({});
|
|
137
117
|
expect(ctx.logger).toBeDefined();
|
|
138
118
|
expect(typeof (ctx.logger as { info: unknown }).info).toBe("function");
|
|
139
119
|
// Storage dir lives under getWorkspaceDir()/plugins-data/<name> and must have
|
|
@@ -145,52 +125,6 @@ describe("plugin bootstrap", () => {
|
|
|
145
125
|
expect(ctx.assistantVersion).toBe(APP_VERSION);
|
|
146
126
|
});
|
|
147
127
|
|
|
148
|
-
test("credential resolution: init receives the resolved value under credentials[key]", async () => {
|
|
149
|
-
getSecureKeyAsyncMock.mockImplementation(async (account: string) => {
|
|
150
|
-
if (account === "some-key") return "super-secret-value";
|
|
151
|
-
return undefined;
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
let received: PluginInitContext | undefined;
|
|
155
|
-
const plugin = buildPlugin(
|
|
156
|
-
"credentialed",
|
|
157
|
-
{
|
|
158
|
-
async init(ctx) {
|
|
159
|
-
received = ctx;
|
|
160
|
-
},
|
|
161
|
-
},
|
|
162
|
-
{ requiresCredential: ["some-key"] },
|
|
163
|
-
);
|
|
164
|
-
registerPlugin(plugin);
|
|
165
|
-
|
|
166
|
-
await bootstrapPlugins();
|
|
167
|
-
|
|
168
|
-
expect(getSecureKeyAsyncMock).toHaveBeenCalledTimes(1);
|
|
169
|
-
expect(getSecureKeyAsyncMock).toHaveBeenCalledWith("some-key");
|
|
170
|
-
expect(received?.credentials).toEqual({ "some-key": "super-secret-value" });
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test("credential resolution: a plugin whose required credential is missing is skipped, not fatal", async () => {
|
|
174
|
-
// GIVEN a plugin that requires a credential the store cannot resolve
|
|
175
|
-
getSecureKeyAsyncMock.mockImplementation(async () => undefined);
|
|
176
|
-
registerPlugin(
|
|
177
|
-
buildPlugin(
|
|
178
|
-
"missing-cred",
|
|
179
|
-
{ async init() {} },
|
|
180
|
-
{ requiresCredential: ["absent-key"] },
|
|
181
|
-
),
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
// WHEN bootstrap runs
|
|
185
|
-
// THEN it completes without throwing — the unresolvable credential is
|
|
186
|
-
// contained to that plugin (same per-plugin isolation as an init throw)
|
|
187
|
-
await bootstrapPlugins();
|
|
188
|
-
|
|
189
|
-
// AND the plugin is dropped from the registry
|
|
190
|
-
const names = getRegisteredPlugins().map((p) => p.manifest.name);
|
|
191
|
-
expect(names).not.toContain("missing-cred");
|
|
192
|
-
});
|
|
193
|
-
|
|
194
128
|
test("version mismatch: external plugin loader rejects when peerDependency unsatisfied", async () => {
|
|
195
129
|
// Host-compat negotiation lives in the external-plugin loader against
|
|
196
130
|
// `peerDependencies["@vellumai/plugin-api"]`. The registry no longer
|
|
@@ -555,11 +489,7 @@ describe("plugin bootstrap", () => {
|
|
|
555
489
|
registerPlugin(plugin);
|
|
556
490
|
|
|
557
491
|
// Create the .disabled sentinel in the workspace plugins dir.
|
|
558
|
-
const sentinelDir = join(
|
|
559
|
-
TEST_WORKSPACE_DIR,
|
|
560
|
-
"plugins",
|
|
561
|
-
"sentinel-off",
|
|
562
|
-
);
|
|
492
|
+
const sentinelDir = join(TEST_WORKSPACE_DIR, "plugins", "sentinel-off");
|
|
563
493
|
const { mkdir, writeFile } = await import("node:fs/promises");
|
|
564
494
|
await mkdir(sentinelDir, { recursive: true });
|
|
565
495
|
await writeFile(join(sentinelDir, ".disabled"), "");
|
|
@@ -22,26 +22,15 @@
|
|
|
22
22
|
* each plugin's shutdown only removes its own route — the other plugin's
|
|
23
23
|
* route stays live until its own teardown runs.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* skill-route-registry state between cases.
|
|
25
|
+
* `resetPluginRegistryForTests()` isolates plugin-registry state and
|
|
26
|
+
* `resetSkillRoutesForTests()` isolates skill-route-registry state between
|
|
27
|
+
* cases.
|
|
29
28
|
*/
|
|
30
29
|
|
|
31
30
|
import { rm } from "node:fs/promises";
|
|
32
31
|
import { tmpdir } from "node:os";
|
|
33
32
|
import { join } from "node:path";
|
|
34
|
-
import { beforeEach, describe, expect,
|
|
35
|
-
|
|
36
|
-
// Stub the credential store before importing bootstrap so the module binds to
|
|
37
|
-
// the mock. Plugins in these tests don't declare `requiresCredential`, but
|
|
38
|
-
// the mock keeps the test hermetic regardless of what the backend would do.
|
|
39
|
-
const getSecureKeyAsyncMock = mock(
|
|
40
|
-
async (_account: string): Promise<string | undefined> => undefined,
|
|
41
|
-
);
|
|
42
|
-
mock.module("../security/secure-keys.js", () => ({
|
|
43
|
-
getSecureKeyAsync: getSecureKeyAsyncMock,
|
|
44
|
-
}));
|
|
33
|
+
import { beforeEach, describe, expect, test } from "bun:test";
|
|
45
34
|
|
|
46
35
|
import { bootstrapPlugins } from "../daemon/external-plugins-bootstrap.js";
|
|
47
36
|
import { runShutdownHooks } from "../daemon/shutdown-registry.js";
|
|
@@ -113,8 +102,6 @@ describe("plugin route contributions", () => {
|
|
|
113
102
|
beforeEach(async () => {
|
|
114
103
|
resetPluginRegistryForTests();
|
|
115
104
|
resetSkillRoutesForTests();
|
|
116
|
-
getSecureKeyAsyncMock.mockReset();
|
|
117
|
-
getSecureKeyAsyncMock.mockImplementation(async () => undefined);
|
|
118
105
|
await rm(TEST_WORKSPACE_DIR, { recursive: true, force: true });
|
|
119
106
|
});
|
|
120
107
|
|
|
@@ -16,11 +16,9 @@
|
|
|
16
16
|
* - Direct `registerPluginTools` / `unregisterPluginTools` semantics,
|
|
17
17
|
* including the plugin-scoped ref count.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* this file can run alongside other plugin/tool-registry tests without
|
|
23
|
-
* cross-contamination.
|
|
19
|
+
* `resetPluginRegistryForTests()` and `__clearRegistryForTesting()` isolate
|
|
20
|
+
* registry state between cases so this file can run alongside other
|
|
21
|
+
* plugin/tool-registry tests without cross-contamination.
|
|
24
22
|
*/
|
|
25
23
|
|
|
26
24
|
import { rm } from "node:fs/promises";
|
|
@@ -28,17 +26,6 @@ import { tmpdir } from "node:os";
|
|
|
28
26
|
import { join } from "node:path";
|
|
29
27
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
30
28
|
|
|
31
|
-
// Mock the credential store before importing the bootstrap so the module
|
|
32
|
-
// under test captures the stubbed binding. Bootstrap only calls this for
|
|
33
|
-
// plugins that declare `requiresCredential`; the tests in this file don't,
|
|
34
|
-
// so the stub simply returns undefined.
|
|
35
|
-
const getSecureKeyAsyncMock = mock(
|
|
36
|
-
async (_account: string): Promise<string | undefined> => undefined,
|
|
37
|
-
);
|
|
38
|
-
mock.module("../security/secure-keys.js", () => ({
|
|
39
|
-
getSecureKeyAsync: getSecureKeyAsyncMock,
|
|
40
|
-
}));
|
|
41
|
-
|
|
42
29
|
import { bootstrapPlugins } from "../daemon/external-plugins-bootstrap.js";
|
|
43
30
|
import { runShutdownHooks } from "../daemon/shutdown-registry.js";
|
|
44
31
|
import { RiskLevel } from "../permissions/types.js";
|
|
@@ -134,8 +121,6 @@ describe("plugin tool contributions", () => {
|
|
|
134
121
|
// assertions about which tools are present. We don't need any of the
|
|
135
122
|
// eager/host tools for these tests.
|
|
136
123
|
__clearRegistryForTesting();
|
|
137
|
-
getSecureKeyAsyncMock.mockReset();
|
|
138
|
-
getSecureKeyAsyncMock.mockImplementation(async () => undefined);
|
|
139
124
|
await rm(TEST_WORKSPACE_DIR, { recursive: true, force: true });
|
|
140
125
|
});
|
|
141
126
|
|
|
@@ -38,7 +38,6 @@ describe("plugin core types", () => {
|
|
|
38
38
|
const manifest: PluginManifest = {
|
|
39
39
|
name: "sample-plugin",
|
|
40
40
|
version: "0.1.0",
|
|
41
|
-
requiresCredential: ["SAMPLE_API_KEY"],
|
|
42
41
|
requiresFlag: ["sample-feature"],
|
|
43
42
|
config: { parse: (input: unknown) => input },
|
|
44
43
|
};
|
|
@@ -61,7 +60,6 @@ describe("plugin core types", () => {
|
|
|
61
60
|
async init(ctx: PluginInitContext) {
|
|
62
61
|
// Touch every field so refactors that rename any of them break here.
|
|
63
62
|
void ctx.config;
|
|
64
|
-
void ctx.credentials;
|
|
65
63
|
void ctx.logger;
|
|
66
64
|
void ctx.pluginStorageDir;
|
|
67
65
|
void ctx.assistantVersion;
|
|
@@ -19,6 +19,8 @@ mock.module("../memory/canonical-guardian-store.js", () => ({
|
|
|
19
19
|
}));
|
|
20
20
|
|
|
21
21
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
22
|
+
setConversationProcessingStartedAt: () => {},
|
|
23
|
+
isConversationProcessing: () => false,
|
|
22
24
|
addMessage: async () => ({ id: "message-id" }),
|
|
23
25
|
getConversation: () => null,
|
|
24
26
|
provenanceFromTrustContext: () => ({}),
|
|
@@ -37,6 +37,8 @@ mock.module("../memory/attachments-store.js", () => ({
|
|
|
37
37
|
}));
|
|
38
38
|
|
|
39
39
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
40
|
+
setConversationProcessingStartedAt: () => {},
|
|
41
|
+
isConversationProcessing: () => false,
|
|
40
42
|
addMessage: async (
|
|
41
43
|
conversationId: string,
|
|
42
44
|
role: string,
|
|
@@ -200,3 +200,42 @@ describe("UsageTrackingProvider", () => {
|
|
|
200
200
|
});
|
|
201
201
|
});
|
|
202
202
|
});
|
|
203
|
+
|
|
204
|
+
describe("native web-search capability survives the wrapper chain", () => {
|
|
205
|
+
function leaf(supports: boolean | undefined): Provider {
|
|
206
|
+
return {
|
|
207
|
+
name: "anthropic",
|
|
208
|
+
...(supports === undefined ? {} : { supportsNativeWebSearch: supports }),
|
|
209
|
+
async sendMessage(): Promise<ProviderResponse> {
|
|
210
|
+
return {
|
|
211
|
+
content: [{ type: "text", text: "" }],
|
|
212
|
+
model: "m",
|
|
213
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
214
|
+
stopReason: "end_turn",
|
|
215
|
+
};
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
test("UsageTrackingProvider forwards supportsNativeWebSearch", () => {
|
|
221
|
+
expect(new UsageTrackingProvider(leaf(true)).supportsNativeWebSearch).toBe(
|
|
222
|
+
true,
|
|
223
|
+
);
|
|
224
|
+
expect(new UsageTrackingProvider(leaf(false)).supportsNativeWebSearch).toBe(
|
|
225
|
+
false,
|
|
226
|
+
);
|
|
227
|
+
expect(
|
|
228
|
+
new UsageTrackingProvider(leaf(undefined)).supportsNativeWebSearch,
|
|
229
|
+
).toBeUndefined();
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test("CallSiteConfiguredProvider forwards it through a nested wrapper", () => {
|
|
233
|
+
// The exact chain getConfiguredProvider returns: CallSiteConfigured →
|
|
234
|
+
// UsageTracking → leaf. The advisor consult reads the flag off the top.
|
|
235
|
+
const wrapped = new CallSiteConfiguredProvider(
|
|
236
|
+
new UsageTrackingProvider(leaf(true)),
|
|
237
|
+
"advisor",
|
|
238
|
+
);
|
|
239
|
+
expect(wrapped.supportsNativeWebSearch).toBe(true);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
@@ -23,6 +23,8 @@ let dbMessages: Array<{
|
|
|
23
23
|
}> = [];
|
|
24
24
|
|
|
25
25
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
26
|
+
setConversationProcessingStartedAt: () => {},
|
|
27
|
+
isConversationProcessing: () => false,
|
|
26
28
|
getMessages: (conversationId: string) =>
|
|
27
29
|
dbMessages.filter((m) => m.conversationId === conversationId),
|
|
28
30
|
deleteMessageById: (messageId: string) => {
|
|
@@ -36,6 +36,9 @@ function makeFakeTool(name: string): Tool {
|
|
|
36
36
|
category: "test",
|
|
37
37
|
defaultRiskLevel: RiskLevel.Low,
|
|
38
38
|
executionTarget: "sandbox",
|
|
39
|
+
// Match the finalized shape the registry stores, so identity comparisons
|
|
40
|
+
// (`getTool(name)` toEqual coreTool) hold after registration fills defaults.
|
|
41
|
+
exclusive: false,
|
|
39
42
|
input_schema: { type: "object", properties: {}, required: [] },
|
|
40
43
|
async execute(
|
|
41
44
|
_input: Record<string, unknown>,
|