@vellumai/assistant 0.10.2-dev.202606250318.5e7cfb0 → 0.10.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/bun.lock +0 -20
- package/docs/workspace-tools.md +33 -42
- package/eslint-rules/cli-no-daemon-internals.js +0 -6
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -31
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +0 -44
- package/node_modules/@vellumai/gateway-client/src/index.ts +0 -14
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -17
- package/node_modules/@vellumai/service-contracts/package.json +0 -1
- package/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
- package/openapi.yaml +0 -155
- package/package.json +1 -4
- package/scripts/test.sh +15 -36
- package/src/__tests__/actor-token-service.test.ts +14 -36
- package/src/__tests__/agent-loop-override-profile.test.ts +0 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -2
- package/src/__tests__/agent-wake-override-profile.test.ts +0 -2
- package/src/__tests__/annotate-activity-metadata.test.ts +0 -2
- package/src/__tests__/annotate-risk-options.test.ts +0 -2
- package/src/__tests__/approval-cascade.test.ts +0 -2
- package/src/__tests__/assistant-attachments.test.ts +0 -42
- package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
- package/src/__tests__/btw-routes.test.ts +0 -2
- package/src/__tests__/build-persisted-content.test.ts +0 -2
- package/src/__tests__/call-controller.test.ts +0 -19
- package/src/__tests__/channel-guardian.test.ts +58 -94
- package/src/__tests__/channel-reply-delivery.test.ts +0 -2
- package/src/__tests__/compaction-events.test.ts +0 -2
- package/src/__tests__/compaction.benchmark.test.ts +0 -2
- package/src/__tests__/compactor-call-site-logging.test.ts +0 -2
- package/src/__tests__/compactor-low-watermark-cut.test.ts +0 -2
- package/src/__tests__/compactor-preserved-tail-count.test.ts +0 -2
- package/src/__tests__/compactor-summary-call-truncation.test.ts +0 -2
- package/src/__tests__/compactor-web-search-strip.test.ts +0 -2
- package/src/__tests__/config-loader-backfill.test.ts +10 -123
- package/src/__tests__/config-schema.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -31
- package/src/__tests__/contacts-relay-reads.test.ts +15 -13
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop.test.ts +0 -134
- package/src/__tests__/conversation-analysis-routes.test.ts +0 -2
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +0 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -2
- package/src/__tests__/conversation-history-web-search.test.ts +0 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +0 -2
- package/src/__tests__/conversation-load-history-stripped.test.ts +0 -2
- package/src/__tests__/conversation-pairing.test.ts +0 -2
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +0 -2
- package/src/__tests__/conversation-process-callsite.test.ts +0 -2
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -2
- package/src/__tests__/conversation-queue.test.ts +0 -91
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -14
- package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -14
- package/src/__tests__/conversation-slash-queue.test.ts +0 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -2
- package/src/__tests__/conversation-speed-override.test.ts +0 -2
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -29
- package/src/__tests__/conversation-title-service.test.ts +0 -2
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -47
- package/src/__tests__/conversation-usage.test.ts +0 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -2
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/db-migration-rollback.test.ts +171 -205
- package/src/__tests__/db-test-helpers.ts +4 -5
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -4
- package/src/__tests__/disk-pressure-guard.test.ts +0 -41
- package/src/__tests__/dm-persistence.test.ts +0 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +5 -10
- package/src/__tests__/events-dev-bypass-actor.test.ts +1 -7
- package/src/__tests__/exploration-drift-hook.test.ts +2 -3
- package/src/__tests__/filing-service.test.ts +0 -2
- package/src/__tests__/guardian-binding-drift-heal.test.ts +10 -75
- package/src/__tests__/guardian-dispatch.test.ts +1 -95
- package/src/__tests__/guardian-outbound-http.test.ts +0 -13
- package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -2
- package/src/__tests__/heartbeat-service.test.ts +0 -2
- package/src/__tests__/helpers/channel-test-adapter.ts +7 -1
- package/src/__tests__/host-app-control-routes.test.ts +30 -24
- package/src/__tests__/host-bash-routes.test.ts +41 -31
- package/src/__tests__/host-browser-routes.test.ts +32 -26
- package/src/__tests__/host-cu-routes-targeted.test.ts +33 -25
- package/src/__tests__/host-file-routes-targeted.test.ts +52 -40
- package/src/__tests__/host-transfer-routes-targeted.test.ts +43 -31
- package/src/__tests__/http-user-message-parity.test.ts +8 -290
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -28
- package/src/__tests__/inbound-slack-persistence.test.ts +0 -2
- package/src/__tests__/invite-redemption-service.test.ts +0 -198
- package/src/__tests__/llm-context-normalization.test.ts +0 -105
- package/src/__tests__/llm-request-log-error-payload.test.ts +9 -71
- package/src/__tests__/llm-usage-store.test.ts +0 -25
- package/src/__tests__/mcp-health-check.test.ts +1 -2
- package/src/__tests__/media-stream-server-integration.test.ts +0 -127
- package/src/__tests__/memory-retrieval-hook.test.ts +0 -2
- package/src/__tests__/messaging-send-tool.test.ts +0 -2
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +5 -146
- package/src/__tests__/native-web-search.test.ts +0 -2
- package/src/__tests__/non-member-access-request.test.ts +17 -189
- package/src/__tests__/notification-broadcaster.test.ts +0 -4
- package/src/__tests__/notification-decision-recipient-context.test.ts +32 -33
- package/src/__tests__/notification-deep-link.test.ts +0 -6
- package/src/__tests__/notification-guardian-path.test.ts +0 -19
- package/src/__tests__/openai-provider.test.ts +12 -22
- package/src/__tests__/openai-responses-provider.test.ts +2 -12
- package/src/__tests__/outbound-slack-persistence.test.ts +0 -2
- package/src/__tests__/pending-interactions-resolved-event.test.ts +4 -7
- package/src/__tests__/persistence-secret-redaction.test.ts +0 -2
- package/src/__tests__/plugin-bootstrap.test.ts +73 -3
- package/src/__tests__/plugin-route-contribution.test.ts +17 -4
- package/src/__tests__/plugin-tool-contribution.test.ts +18 -3
- package/src/__tests__/plugin-types.test.ts +2 -0
- package/src/__tests__/process-message-background-slack.test.ts +0 -2
- package/src/__tests__/process-message-display-content.test.ts +0 -2
- package/src/__tests__/provider-error-scenarios.test.ts +4 -5
- package/src/__tests__/provider-usage-tracking.test.ts +0 -39
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -2
- package/src/__tests__/registry.test.ts +1 -4
- package/src/__tests__/relay-server.test.ts +25 -694
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -0
- package/src/__tests__/secret-ingress-http.test.ts +0 -14
- package/src/__tests__/send-endpoint-busy.test.ts +8 -30
- package/src/__tests__/skills.test.ts +0 -44
- package/src/__tests__/slack-inbound-verification.test.ts +2 -47
- package/src/__tests__/stt-hints.test.ts +13 -44
- package/src/__tests__/subagent-detail.test.ts +0 -27
- package/src/__tests__/subagent-disposal.test.ts +0 -65
- package/src/__tests__/subagent-notify-parent.test.ts +0 -2
- package/src/__tests__/subagent-role-registry.test.ts +2 -7
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +0 -2
- package/src/__tests__/subagent-tools.test.ts +0 -2
- package/src/__tests__/suggestion-routes.test.ts +0 -2
- package/src/__tests__/title-generate-hook.test.ts +0 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -2
- package/src/__tests__/tool-executor.test.ts +11 -16
- package/src/__tests__/tool-preview-lifecycle.test.ts +0 -2
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +0 -2
- package/src/__tests__/tool-start-timestamp.test.ts +0 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
- package/src/__tests__/twilio-routes.test.ts +0 -96
- package/src/__tests__/ui-file-upload-surface.test.ts +0 -86
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/voice-invite-redemption.test.ts +0 -33
- package/src/__tests__/web-search-backend-failure.test.ts +0 -2
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +35 -14
- package/src/__tests__/workspace-tool-loader.test.ts +2 -195
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
- package/src/agent/loop.ts +0 -56
- package/src/api/index.ts +1 -19
- package/src/api/responses/llm-request-log-entry.ts +0 -29
- package/src/api/responses/subagent-detail.ts +0 -17
- package/src/api/surfaces.ts +3 -39
- package/src/approvals/guardian-request-resolvers.ts +11 -1
- package/src/calls/__tests__/relay-setup-router.test.ts +4 -262
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +8 -10
- package/src/calls/inbound-trust-reader.ts +1 -17
- package/src/calls/media-stream-server.ts +0 -21
- package/src/calls/relay-server.ts +50 -167
- package/src/calls/relay-setup-router.ts +7 -37
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/stt-hints.ts +12 -9
- package/src/calls/twilio-routes.ts +4 -14
- package/src/channels/types.ts +20 -10
- package/src/cli/commands/__tests__/cache.test.ts +1 -8
- package/src/cli/commands/cache.ts +181 -194
- package/src/cli/commands/db/__tests__/repair.test.ts +5 -6
- package/src/cli/commands/db/status.ts +1 -37
- package/src/cli/commands/mcp.ts +218 -252
- package/src/cli/commands/memory/index.ts +0 -2
- package/src/cli/commands/plugins.ts +3 -75
- package/src/cli/lib/__tests__/install-from-github.test.ts +0 -102
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +1 -160
- package/src/cli/lib/list-installed-plugins.ts +1 -179
- package/src/config/__tests__/sync-gated-profiles.test.ts +3 -11
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +17 -27
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +3 -13
- package/src/config/bundled-skills/subagent/SKILL.md +1 -1
- package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
- package/src/config/feature-flag-registry.json +13 -5
- package/src/config/loader.ts +5 -38
- package/src/config/schemas/__tests__/memory-v3.test.ts +0 -1
- package/src/config/schemas/memory-lifecycle.ts +0 -12
- package/src/config/schemas/memory-v3.ts +0 -7
- package/src/config/schemas/memory.ts +0 -4
- package/src/config/schemas/timeouts.ts +0 -8
- package/src/config/seed-inference-profiles.ts +11 -21
- package/src/config/skills.ts +5 -27
- package/src/config/sync-gated-profiles.ts +13 -12
- package/src/contacts/contacts-write.ts +0 -3
- package/src/daemon/assistant-attachments.ts +4 -27
- package/src/daemon/conversation-agent-loop.ts +0 -28
- package/src/daemon/conversation-process.ts +16 -35
- package/src/daemon/conversation-surfaces.ts +38 -111
- package/src/daemon/conversation-tool-setup.ts +16 -50
- package/src/daemon/conversation.ts +1 -13
- package/src/daemon/disk-pressure-guard.ts +2 -12
- package/src/daemon/event-loop-watchdog.ts +1 -28
- package/src/daemon/external-plugins-bootstrap.ts +34 -4
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -25
- package/src/daemon/handlers/config-a2a.ts +14 -6
- package/src/daemon/handlers/config-channels.ts +22 -78
- package/src/daemon/handlers/conversations.ts +0 -77
- package/src/daemon/lifecycle.ts +0 -4
- package/src/daemon/mcp-reload-service.ts +0 -10
- package/src/daemon/memory-v2-startup.test.ts +0 -72
- package/src/daemon/memory-v2-startup.ts +19 -87
- package/src/daemon/message-types/conversations.ts +0 -2
- package/src/daemon/message-types/surfaces.ts +12 -12
- package/src/daemon/server.ts +4 -0
- package/src/daemon/shutdown-handlers.ts +0 -20
- package/src/daemon/tool-setup-types.ts +0 -9
- package/src/daemon/workspace-tools-watcher.ts +328 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/assistant-server.ts +2 -2
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/client.ts +1 -15
- package/src/mcp/mcp-auth-orchestrator.ts +1 -6
- package/src/mcp/mcp-oauth-provider.ts +8 -19
- package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -8
- package/src/memory/conversation-crud.ts +0 -38
- package/src/memory/db-connection.ts +3 -22
- package/src/memory/db-init.ts +502 -36
- package/src/memory/db-singleton.ts +4 -6
- package/src/memory/jobs-worker.ts +0 -58
- package/src/memory/llm-request-log-store.ts +1 -26
- package/src/memory/llm-usage-store.ts +20 -48
- package/src/memory/memory-retrospective-job.ts +8 -9
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +56 -130
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/registry.ts +573 -0
- package/src/memory/migrations/run-migrations.ts +6 -90
- package/src/memory/migrations/validate-migration-state.ts +66 -101
- package/src/memory/schema/conversations.ts +0 -9
- package/src/memory/schema/infrastructure.ts +0 -20
- package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -25
- package/src/memory/v2/__tests__/skill-store.test.ts +0 -80
- package/src/memory/v2/cli-command-store.ts +38 -75
- package/src/memory/v2/prompts/consolidation.ts +82 -13
- package/src/memory/v2/prompts/router.ts +93 -21
- package/src/memory/v2/skill-store.ts +31 -68
- package/src/notifications/__tests__/broadcaster.test.ts +8 -16
- package/src/notifications/__tests__/decision-engine.test.ts +9 -78
- package/src/notifications/broadcaster.ts +1 -8
- package/src/notifications/decision-engine.ts +7 -15
- package/src/notifications/destination-resolver.ts +24 -68
- package/src/notifications/emit-signal.ts +14 -39
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +4 -7
- package/src/plugin-api/index.ts +6 -6
- package/src/plugin-api/types.ts +5 -3
- package/src/plugin-api/vision-support.test.ts +4 -28
- package/src/plugin-api/vision-support.ts +31 -66
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -161
- package/src/plugins/defaults/advisor/consult.ts +6 -110
- package/src/plugins/defaults/advisor/steering.ts +2 -14
- package/src/plugins/defaults/advisor/tools/advisor.ts +5 -32
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +1 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +7 -47
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +11 -10
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +20 -12
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +11 -42
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +3 -33
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +4 -48
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +8 -4
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +15 -43
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +2 -11
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -77
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +11 -12
- package/src/plugins/mtime-cache.ts +291 -76
- package/src/plugins/pipeline.ts +13 -111
- package/src/plugins/types.ts +2 -0
- package/src/providers/anthropic/client.ts +0 -5
- package/src/providers/call-site-routing.ts +0 -4
- package/src/providers/model-catalog.ts +0 -16
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/chat-completions-provider.ts +83 -37
- package/src/providers/openai/responses-provider.ts +46 -50
- package/src/providers/openrouter/client.ts +0 -5
- package/src/providers/provider-send-message.ts +0 -4
- package/src/providers/ratelimit.ts +0 -4
- package/src/providers/retry.ts +0 -4
- package/src/providers/types.ts +0 -9
- package/src/providers/usage-tracking.ts +0 -4
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +3 -335
- package/src/runtime/access-request-helper.ts +39 -19
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +2 -9
- package/src/runtime/auth/require-bound-guardian.ts +11 -21
- package/src/runtime/channel-verification-service.ts +31 -56
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
- package/src/runtime/guardian-vellum-migration.ts +7 -66
- package/src/runtime/invite-redemption-service.ts +187 -198
- package/src/runtime/local-actor-identity.ts +11 -76
- package/src/runtime/pending-interactions.ts +1 -11
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +5 -56
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +0 -187
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -13
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +32 -8
- package/src/runtime/routes/conversation-cli-routes.ts +5 -4
- package/src/runtime/routes/conversation-list-routes.ts +7 -4
- package/src/runtime/routes/conversation-query-routes.ts +0 -72
- package/src/runtime/routes/conversation-routes.ts +85 -84
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +1 -3
- package/src/runtime/routes/guardian-action-routes.ts +5 -4
- package/src/runtime/routes/host-app-control-routes.ts +4 -5
- package/src/runtime/routes/host-bash-routes.ts +4 -5
- package/src/runtime/routes/host-browser-routes.ts +11 -9
- package/src/runtime/routes/host-cu-routes.ts +4 -5
- package/src/runtime/routes/host-file-routes.ts +4 -5
- 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 +2 -3
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +5 -97
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +49 -61
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -16
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +8 -21
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +3 -14
- package/src/runtime/routes/index.ts +0 -2
- package/src/runtime/routes/llm-context-normalization.ts +0 -83
- package/src/runtime/routes/mcp-auth-routes.ts +19 -171
- package/src/runtime/routes/migration-rollback-routes.ts +3 -4
- package/src/runtime/routes/migration-routes.ts +1 -4
- package/src/runtime/routes/subagents-routes.ts +0 -5
- package/src/runtime/routes/surface-action-routes.ts +56 -42
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -1
- package/src/runtime/services/conversation-serializer.ts +9 -7
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +9 -85
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +0 -16
- package/src/subagent/manager.ts +0 -9
- package/src/subagent/types.ts +3 -3
- package/src/telemetry/types.ts +1 -34
- package/src/telemetry/usage-telemetry-reporter.test.ts +2 -3
- package/src/telemetry/usage-telemetry-reporter.ts +3 -87
- package/src/tools/ask-question/ask-question-tool.test.ts +0 -29
- package/src/tools/ask-question/ask-question-tool.ts +0 -13
- package/src/tools/executor.ts +4 -4
- package/src/tools/registry.ts +0 -18
- package/src/tools/shared/filesystem/path-policy.ts +5 -12
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +2 -9
- package/src/tools/tool-manifest.ts +0 -3
- package/src/tools/types.ts +2 -17
- package/src/tools/workspace-tools/loader.ts +244 -348
- package/src/util/errors.ts +1 -26
- package/src/util/platform.ts +0 -5
- package/src/workflows/library.test.ts +0 -140
- package/src/workflows/library.ts +28 -82
- package/src/workspace/migrations/017-seed-persona-dirs.ts +34 -3
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +24 -3
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +66 -14
- package/src/workspace/migrations/registry.ts +0 -2
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +0 -91
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +0 -48
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -28
- package/node_modules/@vellumai/service-contracts/src/channels.ts +0 -41
- package/src/__tests__/code-search-tool.test.ts +0 -585
- package/src/__tests__/guardian-expiry-notifier.test.ts +0 -282
- package/src/__tests__/mcp-config-secret-boundary.test.ts +0 -390
- package/src/__tests__/plugin-pipeline.test.ts +0 -96
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +0 -102
- package/src/__tests__/steer-on-enqueue-question.test.ts +0 -181
- package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +0 -208
- package/src/agent/loop-exclusive-tool.test.ts +0 -150
- package/src/api/constants/sse-replay.ts +0 -41
- package/src/api/events/conversation-notice.ts +0 -26
- package/src/approvals/guardian-channel-delivery.ts +0 -30
- package/src/approvals/guardian-expiry-notifier.ts +0 -148
- package/src/cli/commands/memory/__tests__/worker.test.ts +0 -302
- package/src/cli/commands/memory/worker.ts +0 -175
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +0 -143
- package/src/config/prune-seeded-callsite-defaults.ts +0 -110
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -129
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +0 -312
- package/src/contacts/__tests__/member-write-relay.test.ts +0 -202
- package/src/contacts/guardian-delivery-reader.ts +0 -223
- package/src/contacts/member-write-relay.ts +0 -189
- package/src/daemon/conversation-notices.ts +0 -60
- package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -225
- package/src/hooks/hook-loader.ts +0 -341
- package/src/mcp/mcp-header-store.ts +0 -134
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
- package/src/memory/__tests__/prompt-override.test.ts +0 -192
- package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
- package/src/memory/migrations/300-add-processing-started-at.ts +0 -30
- package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -224
- package/src/memory/prompt-override.ts +0 -129
- package/src/memory/steps.ts +0 -573
- package/src/memory/watchdog-events-store.ts +0 -87
- package/src/memory/worker-control.ts +0 -118
- package/src/memory/worker-process.ts +0 -72
- package/src/notifications/__tests__/connected-channels.test.ts +0 -114
- package/src/notifications/__tests__/destination-resolver.test.ts +0 -256
- package/src/onboarding/checkin-event.test.ts +0 -222
- package/src/onboarding/checkin-event.ts +0 -321
- package/src/onboarding/schedule-checkin.ts +0 -190
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
- package/src/plugins/defaults/advisor/context-pack.ts +0 -288
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
- package/src/plugins/surface-import.ts +0 -121
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +0 -321
- package/src/providers/openai/api-error-normalization.ts +0 -270
- package/src/runtime/__tests__/channel-verification-service.test.ts +0 -133
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +0 -181
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +0 -66
- package/src/runtime/__tests__/local-principal-trust.test.ts +0 -164
- package/src/runtime/anchored-guardian.test.ts +0 -156
- package/src/runtime/anchored-guardian.ts +0 -135
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +0 -99
- package/src/runtime/local-principal-trust.ts +0 -52
- package/src/runtime/routes/__tests__/contact-routes.test.ts +0 -212
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -93
- package/src/runtime/routes/onboarding-checkin-routes.ts +0 -86
- package/src/tools/filesystem/search.ts +0 -543
- package/src/util/telemetry-db-path.ts +0 -24
- package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +0 -134
|
@@ -1827,109 +1827,4 @@ describe("normalizeLlmContextPayloads", () => {
|
|
|
1827
1827
|
},
|
|
1828
1828
|
]);
|
|
1829
1829
|
});
|
|
1830
|
-
|
|
1831
|
-
describe("provider error response payloads", () => {
|
|
1832
|
-
test("extracts a structured error from a rejected call's response payload", () => {
|
|
1833
|
-
const normalized = normalizeLlmContextPayloads({
|
|
1834
|
-
createdAt: 1_742_400_000_000,
|
|
1835
|
-
requestPayload: {
|
|
1836
|
-
model: "accounts/fireworks/models/glm-5p2",
|
|
1837
|
-
messages: [{ role: "user", content: "hello" }],
|
|
1838
|
-
},
|
|
1839
|
-
responsePayload: {
|
|
1840
|
-
error: {
|
|
1841
|
-
name: "ProviderError",
|
|
1842
|
-
message:
|
|
1843
|
-
"This model doesn't support image input. Remove the image or switch to a vision-capable model.",
|
|
1844
|
-
code: "PROVIDER_ERROR",
|
|
1845
|
-
provider: "fireworks",
|
|
1846
|
-
statusCode: 400,
|
|
1847
|
-
},
|
|
1848
|
-
},
|
|
1849
|
-
});
|
|
1850
|
-
|
|
1851
|
-
expect(normalized.error).toEqual({
|
|
1852
|
-
name: "ProviderError",
|
|
1853
|
-
message:
|
|
1854
|
-
"This model doesn't support image input. Remove the image or switch to a vision-capable model.",
|
|
1855
|
-
code: "PROVIDER_ERROR",
|
|
1856
|
-
provider: "fireworks",
|
|
1857
|
-
statusCode: 400,
|
|
1858
|
-
});
|
|
1859
|
-
// No response sections are produced for an error payload.
|
|
1860
|
-
expect(normalized.responseSections).toBeUndefined();
|
|
1861
|
-
});
|
|
1862
|
-
|
|
1863
|
-
test("preserves a normalized request alongside the error", () => {
|
|
1864
|
-
const normalized = normalizeLlmContextPayloads({
|
|
1865
|
-
createdAt: 1_742_400_000_000,
|
|
1866
|
-
requestPayload: {
|
|
1867
|
-
model: "gpt-4.1",
|
|
1868
|
-
tool_choice: "auto",
|
|
1869
|
-
messages: [{ role: "user", content: "hi" }],
|
|
1870
|
-
},
|
|
1871
|
-
responsePayload: { error: { message: "boom" } },
|
|
1872
|
-
});
|
|
1873
|
-
|
|
1874
|
-
expect(normalized.error).toEqual({ message: "boom" });
|
|
1875
|
-
// The request side still normalizes so the Prompt tab keeps working.
|
|
1876
|
-
expect(normalized.requestSections?.length).toBeGreaterThan(0);
|
|
1877
|
-
expect(normalized.summary?.provider).toBe("openai");
|
|
1878
|
-
});
|
|
1879
|
-
|
|
1880
|
-
test("carries statusCode 0 and retryAfterMs through", () => {
|
|
1881
|
-
const normalized = normalizeLlmContextPayloads({
|
|
1882
|
-
createdAt: 1_742_400_000_000,
|
|
1883
|
-
requestPayload: null,
|
|
1884
|
-
responsePayload: {
|
|
1885
|
-
error: {
|
|
1886
|
-
name: "ProviderError",
|
|
1887
|
-
message: "rate limited",
|
|
1888
|
-
provider: "anthropic",
|
|
1889
|
-
statusCode: 0,
|
|
1890
|
-
retryAfterMs: 1500,
|
|
1891
|
-
},
|
|
1892
|
-
},
|
|
1893
|
-
});
|
|
1894
|
-
|
|
1895
|
-
expect(normalized.error).toEqual({
|
|
1896
|
-
name: "ProviderError",
|
|
1897
|
-
message: "rate limited",
|
|
1898
|
-
provider: "anthropic",
|
|
1899
|
-
statusCode: 0,
|
|
1900
|
-
retryAfterMs: 1500,
|
|
1901
|
-
});
|
|
1902
|
-
});
|
|
1903
|
-
|
|
1904
|
-
test("does not treat a successful response with no error as failed", () => {
|
|
1905
|
-
const normalized = normalizeLlmContextPayloads({
|
|
1906
|
-
createdAt: 1_742_400_000_000,
|
|
1907
|
-
requestPayload: {
|
|
1908
|
-
model: "gpt-4.1",
|
|
1909
|
-
messages: [{ role: "user", content: "hi" }],
|
|
1910
|
-
},
|
|
1911
|
-
responsePayload: {
|
|
1912
|
-
model: "gpt-4.1",
|
|
1913
|
-
choices: [
|
|
1914
|
-
{
|
|
1915
|
-
finish_reason: "stop",
|
|
1916
|
-
message: { role: "assistant", content: "hello" },
|
|
1917
|
-
},
|
|
1918
|
-
],
|
|
1919
|
-
},
|
|
1920
|
-
});
|
|
1921
|
-
|
|
1922
|
-
expect(normalized.error).toBeUndefined();
|
|
1923
|
-
});
|
|
1924
|
-
|
|
1925
|
-
test("ignores an empty error object with no identifying fields", () => {
|
|
1926
|
-
const normalized = normalizeLlmContextPayloads({
|
|
1927
|
-
createdAt: 1_742_400_000_000,
|
|
1928
|
-
requestPayload: null,
|
|
1929
|
-
responsePayload: { error: {} },
|
|
1930
|
-
});
|
|
1931
|
-
|
|
1932
|
-
expect(normalized.error).toBeUndefined();
|
|
1933
|
-
});
|
|
1934
|
-
});
|
|
1935
1830
|
});
|
|
@@ -25,15 +25,18 @@
|
|
|
25
25
|
import { describe, expect, test } from "bun:test";
|
|
26
26
|
|
|
27
27
|
import { buildProviderErrorResponsePayload } from "../memory/llm-request-log-store.js";
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
AssistantError,
|
|
30
|
+
ErrorCode,
|
|
31
|
+
ProviderError,
|
|
32
|
+
} from "../util/errors.js";
|
|
29
33
|
|
|
30
|
-
function persisted(err: Error): {
|
|
31
|
-
error: Record<string, unknown>;
|
|
32
|
-
rawResponse?: unknown;
|
|
33
|
-
} {
|
|
34
|
+
function persisted(err: Error): { error: Record<string, unknown> } {
|
|
34
35
|
// Round-trip through JSON to assert on the actual stored shape, not the
|
|
35
36
|
// in-memory object reference.
|
|
36
|
-
return JSON.parse(
|
|
37
|
+
return JSON.parse(
|
|
38
|
+
JSON.stringify(buildProviderErrorResponsePayload(err)),
|
|
39
|
+
);
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
describe("buildProviderErrorResponsePayload", () => {
|
|
@@ -57,34 +60,6 @@ describe("buildProviderErrorResponsePayload", () => {
|
|
|
57
60
|
});
|
|
58
61
|
});
|
|
59
62
|
|
|
60
|
-
test("ProviderError serializes upstream provider error metadata when present", () => {
|
|
61
|
-
const err = new ProviderError(
|
|
62
|
-
"OpenAI API error (401): Invalid API key provided",
|
|
63
|
-
"openai",
|
|
64
|
-
401,
|
|
65
|
-
{
|
|
66
|
-
apiErrorCode: "invalid_api_key",
|
|
67
|
-
apiErrorType: "invalid_request_error",
|
|
68
|
-
apiErrorParam: "api_key",
|
|
69
|
-
requestId: "req_abc123",
|
|
70
|
-
},
|
|
71
|
-
);
|
|
72
|
-
const got = persisted(err);
|
|
73
|
-
expect(got).toEqual({
|
|
74
|
-
error: {
|
|
75
|
-
name: "ProviderError",
|
|
76
|
-
message: "OpenAI API error (401): Invalid API key provided",
|
|
77
|
-
code: ErrorCode.PROVIDER_ERROR,
|
|
78
|
-
provider: "openai",
|
|
79
|
-
statusCode: 401,
|
|
80
|
-
apiErrorCode: "invalid_api_key",
|
|
81
|
-
apiErrorType: "invalid_request_error",
|
|
82
|
-
apiErrorParam: "api_key",
|
|
83
|
-
requestId: "req_abc123",
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
63
|
test("ProviderError without optional metadata omits statusCode + retryAfterMs", () => {
|
|
89
64
|
const err = new ProviderError(
|
|
90
65
|
"Gemini API error: surprise internal state",
|
|
@@ -152,43 +127,6 @@ describe("buildProviderErrorResponsePayload", () => {
|
|
|
152
127
|
});
|
|
153
128
|
});
|
|
154
129
|
|
|
155
|
-
test("captured JSON rawBody is attached as a parsed rawResponse sibling", () => {
|
|
156
|
-
// So the inspector's Raw tab can render the actual upstream provider JSON
|
|
157
|
-
// (like a successful row) instead of only the extracted error fields.
|
|
158
|
-
const err = new ProviderError(
|
|
159
|
-
"Together AI API error (400): Model 'MiniMax-M3' is not supported.",
|
|
160
|
-
"together",
|
|
161
|
-
400,
|
|
162
|
-
{
|
|
163
|
-
apiErrorCode: "model_not_supported",
|
|
164
|
-
rawBody: JSON.stringify({
|
|
165
|
-
detail: "Model 'MiniMax-M3' is not supported.",
|
|
166
|
-
}),
|
|
167
|
-
},
|
|
168
|
-
);
|
|
169
|
-
const got = persisted(err);
|
|
170
|
-
expect(got.error.apiErrorCode).toBe("model_not_supported");
|
|
171
|
-
expect(got.rawResponse).toEqual({
|
|
172
|
-
detail: "Model 'MiniMax-M3' is not supported.",
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
test("non-JSON rawBody (HTML/text error page) is kept verbatim as a string", () => {
|
|
177
|
-
const err = new ProviderError("Bad gateway", "openai", 400, {
|
|
178
|
-
rawBody: "<html><body>upstream timeout</body></html>",
|
|
179
|
-
});
|
|
180
|
-
const got = persisted(err);
|
|
181
|
-
expect(got.rawResponse).toBe("<html><body>upstream timeout</body></html>");
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
test("no captured rawBody omits the rawResponse sibling entirely", () => {
|
|
185
|
-
const err = new ProviderError("rate limited", "anthropic", 429, {
|
|
186
|
-
retryAfterMs: 1500,
|
|
187
|
-
});
|
|
188
|
-
const got = persisted(err);
|
|
189
|
-
expect("rawResponse" in got).toBe(false);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
130
|
test("ProviderError with statusCode 0 is still recorded (not coerced to undefined)", () => {
|
|
193
131
|
// Defensive: `if (err.statusCode !== undefined)` correctly admits 0.
|
|
194
132
|
// A raw `if (err.statusCode)` would drop it, so the test guards against
|
|
@@ -779,31 +779,6 @@ describe("getUsageDayBuckets", () => {
|
|
|
779
779
|
expect(buckets[0].totalEstimatedCostUsd).toBeCloseTo(0.05);
|
|
780
780
|
expect(buckets[0].eventCount).toBe(2);
|
|
781
781
|
});
|
|
782
|
-
|
|
783
|
-
test("collapses many events within a sub-bucket span without losing totals", () => {
|
|
784
|
-
// The read path pre-aggregates events into 15-minute UTC buckets in SQL
|
|
785
|
-
// before local-time bucketing. Many events inside one such window must
|
|
786
|
-
// still sum exactly, and events split across the 15-minute boundary but
|
|
787
|
-
// within the same local day must land in the same day bucket.
|
|
788
|
-
const windowStart = utcMs(2025, 3, 1, 10); // 10:00:00 UTC
|
|
789
|
-
for (let i = 0; i < 50; i++) {
|
|
790
|
-
// Spread across ~16 minutes so the events straddle a 15-minute boundary.
|
|
791
|
-
insertEventAt(windowStart + i * 20_000, {
|
|
792
|
-
inputTokens: 2,
|
|
793
|
-
outputTokens: 1,
|
|
794
|
-
});
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
const buckets = getUsageDayBuckets({
|
|
798
|
-
from: utcMs(2025, 3, 1),
|
|
799
|
-
to: utcMs(2025, 3, 2),
|
|
800
|
-
});
|
|
801
|
-
expect(buckets).toHaveLength(1);
|
|
802
|
-
expect(buckets[0].date).toBe("2025-03-01");
|
|
803
|
-
expect(buckets[0].totalInputTokens).toBe(100);
|
|
804
|
-
expect(buckets[0].totalOutputTokens).toBe(50);
|
|
805
|
-
expect(buckets[0].eventCount).toBe(50);
|
|
806
|
-
});
|
|
807
782
|
});
|
|
808
783
|
|
|
809
784
|
describe("getUsageDayBuckets — timezone-aware", () => {
|
|
@@ -58,8 +58,7 @@ mock.module("../mcp/mcp-auth-state.js", () => ({
|
|
|
58
58
|
}));
|
|
59
59
|
|
|
60
60
|
mock.module("../mcp/mcp-oauth-provider.js", () => ({
|
|
61
|
-
|
|
62
|
-
deleteMcpOAuthCredentials: async () => ({ ok: true, failedKeys: [] }),
|
|
61
|
+
deleteMcpOAuthCredentials: async () => {},
|
|
63
62
|
}));
|
|
64
63
|
|
|
65
64
|
const { ROUTES } = await import("../runtime/routes/mcp-auth-routes.js");
|
|
@@ -176,22 +176,6 @@ mock.module("../calls/channel-admission-reader.js", () => ({
|
|
|
176
176
|
getChannelAdmissionPolicy: mockGetChannelAdmissionPolicy,
|
|
177
177
|
}));
|
|
178
178
|
|
|
179
|
-
// Mock the inbound trust reader. handleStart awaits this and threads the
|
|
180
|
-
// verdict into routeSetup so the media-stream transport enforces the same
|
|
181
|
-
// gateway ACL as ConversationRelay. Tests override mockInboundVerdict.
|
|
182
|
-
let mockInboundVerdict: unknown = null;
|
|
183
|
-
const mockGetInboundTrustVerdict = jest.fn(
|
|
184
|
-
async (_args?: Record<string, unknown>) => mockInboundVerdict,
|
|
185
|
-
);
|
|
186
|
-
mock.module("../calls/inbound-trust-reader.js", () => ({
|
|
187
|
-
getInboundTrustVerdict: mockGetInboundTrustVerdict,
|
|
188
|
-
getPhoneCallerVerdict: (otherPartyNumber: string | undefined) =>
|
|
189
|
-
mockGetInboundTrustVerdict({
|
|
190
|
-
channelType: "phone",
|
|
191
|
-
actorExternalId: otherPartyNumber || undefined,
|
|
192
|
-
}),
|
|
193
|
-
}));
|
|
194
|
-
|
|
195
179
|
// Mock the actor trust resolver (used by handleStart to derive trust context)
|
|
196
180
|
mock.module("../runtime/actor-trust-resolver.js", () => ({
|
|
197
181
|
toTrustContext: jest.fn(() => ({
|
|
@@ -372,8 +356,6 @@ beforeEach(() => {
|
|
|
372
356
|
mockGetChannelAdmissionPolicy.mockClear();
|
|
373
357
|
mockAdmissionPolicy = null;
|
|
374
358
|
mockAdmissionGate = null;
|
|
375
|
-
mockGetInboundTrustVerdict.mockClear();
|
|
376
|
-
mockInboundVerdict = null;
|
|
377
359
|
// Reset routeSetup to default normal_call
|
|
378
360
|
mockRouteSetupResult = {
|
|
379
361
|
outcome: { action: "normal_call" as const, isInbound: true },
|
|
@@ -1553,113 +1535,4 @@ describe("media-stream setup outcome scenarios", () => {
|
|
|
1553
1535
|
expect(speakSystemPrompt).not.toHaveBeenCalled();
|
|
1554
1536
|
});
|
|
1555
1537
|
});
|
|
1556
|
-
|
|
1557
|
-
// ── Gateway trust verdict ──────────────────────────────────────────
|
|
1558
|
-
// handleStart fetches getInboundTrustVerdict for the inbound caller and
|
|
1559
|
-
// threads it into routeSetup, so the media-stream transport enforces the
|
|
1560
|
-
// same gateway ACL as ConversationRelay. routeSetup itself decides
|
|
1561
|
-
// verdict-vs-local; these tests assert the verdict is fetched and passed.
|
|
1562
|
-
|
|
1563
|
-
describe("gateway trust verdict", () => {
|
|
1564
|
-
test("fetches the inbound caller's verdict and threads it into routeSetup", async () => {
|
|
1565
|
-
mockInboundVerdict = {
|
|
1566
|
-
channelType: "phone",
|
|
1567
|
-
actorExternalId: "+14155550000",
|
|
1568
|
-
contactId: "contact-1",
|
|
1569
|
-
channelId: "channel-1",
|
|
1570
|
-
status: "verified",
|
|
1571
|
-
policy: "allow",
|
|
1572
|
-
resolutionFailed: false,
|
|
1573
|
-
};
|
|
1574
|
-
|
|
1575
|
-
const mockWs = createMockWs();
|
|
1576
|
-
mockSessions.set("call-verdict-thread-1", {
|
|
1577
|
-
id: "call-verdict-thread-1",
|
|
1578
|
-
conversationId: "conv-verdict-thread-1",
|
|
1579
|
-
status: "initiated",
|
|
1580
|
-
task: null,
|
|
1581
|
-
startedAt: null,
|
|
1582
|
-
fromNumber: "+14155550000",
|
|
1583
|
-
toNumber: "+15550001111",
|
|
1584
|
-
});
|
|
1585
|
-
|
|
1586
|
-
const session = new MediaStreamCallSession(
|
|
1587
|
-
mockWs.ws,
|
|
1588
|
-
"call-verdict-thread-1",
|
|
1589
|
-
);
|
|
1590
|
-
session.handleMessage(makeStartMessage());
|
|
1591
|
-
await session.whenSetupSettled();
|
|
1592
|
-
|
|
1593
|
-
// Verdict fetched for the inbound caller (from number) on the phone channel.
|
|
1594
|
-
expect(mockGetInboundTrustVerdict).toHaveBeenCalledWith({
|
|
1595
|
-
channelType: "phone",
|
|
1596
|
-
actorExternalId: "+14155550000",
|
|
1597
|
-
});
|
|
1598
|
-
// Verdict threaded into routeSetup.
|
|
1599
|
-
expect(routeSetup).toHaveBeenCalledWith(
|
|
1600
|
-
expect.objectContaining({ verdict: mockInboundVerdict }),
|
|
1601
|
-
);
|
|
1602
|
-
});
|
|
1603
|
-
|
|
1604
|
-
test("a blocked/denied member verdict is enforced (deny) on the media-stream transport", async () => {
|
|
1605
|
-
// The real router returns `deny` for a member verdict whose ACL is
|
|
1606
|
-
// blocked/revoked/deny; the mock reflects that outcome here.
|
|
1607
|
-
mockInboundVerdict = {
|
|
1608
|
-
channelType: "phone",
|
|
1609
|
-
actorExternalId: "+14155550000",
|
|
1610
|
-
contactId: "contact-1",
|
|
1611
|
-
channelId: "channel-1",
|
|
1612
|
-
status: "blocked",
|
|
1613
|
-
policy: "deny",
|
|
1614
|
-
resolutionFailed: false,
|
|
1615
|
-
};
|
|
1616
|
-
mockRouteSetupResult = {
|
|
1617
|
-
outcome: {
|
|
1618
|
-
action: "deny",
|
|
1619
|
-
message:
|
|
1620
|
-
"This number is not authorized to reach the assistant right now.",
|
|
1621
|
-
logReason: "Inbound voice ACL: member blocked",
|
|
1622
|
-
},
|
|
1623
|
-
resolved: {
|
|
1624
|
-
assistantId: "self",
|
|
1625
|
-
isInbound: true,
|
|
1626
|
-
otherPartyNumber: "+14155550000",
|
|
1627
|
-
actorTrust: { trustClass: "unknown", memberRecord: null },
|
|
1628
|
-
},
|
|
1629
|
-
};
|
|
1630
|
-
|
|
1631
|
-
const mockWs = createMockWs();
|
|
1632
|
-
mockSessions.set("call-verdict-deny-1", {
|
|
1633
|
-
id: "call-verdict-deny-1",
|
|
1634
|
-
conversationId: "conv-verdict-deny-1",
|
|
1635
|
-
status: "initiated",
|
|
1636
|
-
task: null,
|
|
1637
|
-
startedAt: null,
|
|
1638
|
-
fromNumber: "+14155550000",
|
|
1639
|
-
toNumber: "+15550001111",
|
|
1640
|
-
});
|
|
1641
|
-
|
|
1642
|
-
const session = new MediaStreamCallSession(
|
|
1643
|
-
mockWs.ws,
|
|
1644
|
-
"call-verdict-deny-1",
|
|
1645
|
-
);
|
|
1646
|
-
session.handleMessage(makeStartMessage());
|
|
1647
|
-
await session.whenSetupSettled();
|
|
1648
|
-
|
|
1649
|
-
// Verdict was passed into routeSetup, which denied the caller.
|
|
1650
|
-
expect(routeSetup).toHaveBeenCalledWith(
|
|
1651
|
-
expect.objectContaining({ verdict: mockInboundVerdict }),
|
|
1652
|
-
);
|
|
1653
|
-
expect(speakSystemPrompt).toHaveBeenCalledWith(
|
|
1654
|
-
expect.anything(),
|
|
1655
|
-
"This number is not authorized to reach the assistant right now.",
|
|
1656
|
-
);
|
|
1657
|
-
expect(updateCallSession).toHaveBeenCalledWith(
|
|
1658
|
-
"call-verdict-deny-1",
|
|
1659
|
-
expect.objectContaining({ status: "failed" }),
|
|
1660
|
-
);
|
|
1661
|
-
expect(registerCallController).not.toHaveBeenCalled();
|
|
1662
|
-
expect(mockStartInitialGreeting).not.toHaveBeenCalled();
|
|
1663
|
-
});
|
|
1664
|
-
});
|
|
1665
1538
|
});
|
|
@@ -19,8 +19,6 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
|
19
19
|
// bindings resolve through the mocks.
|
|
20
20
|
const updateMessageMetadataMock = mock((_id: string, _updates: unknown) => {});
|
|
21
21
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
22
|
-
setConversationProcessingStartedAt: () => {},
|
|
23
|
-
isConversationProcessing: () => false,
|
|
24
22
|
updateMessageMetadata: updateMessageMetadataMock,
|
|
25
23
|
}));
|
|
26
24
|
|
|
@@ -79,8 +79,6 @@ const getBindingByChannelChatMock = mock(
|
|
|
79
79
|
);
|
|
80
80
|
|
|
81
81
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
82
|
-
setConversationProcessingStartedAt: () => {},
|
|
83
|
-
isConversationProcessing: () => false,
|
|
84
82
|
addMessage: addMessageMock,
|
|
85
83
|
getConversation: getConversationMock,
|
|
86
84
|
reserveMessage: mock(async () => ({ id: "msg-reserve" })),
|
|
@@ -421,8 +421,8 @@ describe("handleMigrationImport — JSON {url} body", () => {
|
|
|
421
421
|
describe("handleMigrationImport — no-swap path omits newer-migration warning", () => {
|
|
422
422
|
test("credentials-only bundle does not inherit live-DB migration warnings", async () => {
|
|
423
423
|
// Seed the live workspace DB with a step:* checkpoint that's NOT
|
|
424
|
-
// in the
|
|
425
|
-
//
|
|
424
|
+
// in the registry. validateMigrationState treats this as a "newer
|
|
425
|
+
// version" and would otherwise push a warning into the report. With
|
|
426
426
|
// the gate in appendNewerMigrationWarningsIfAny the warning must be
|
|
427
427
|
// suppressed when the import didn't modify the workspace.
|
|
428
428
|
const dbDir = join(testWorkspaceRoot, "data", "db");
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* cache miss (changed mtime → re-import), plugin deletion (eviction),
|
|
8
8
|
* and hook collection across multiple plugins.
|
|
9
9
|
*/
|
|
10
|
-
import { mkdirSync, rmSync, utimesSync,
|
|
10
|
+
import { mkdirSync, rmSync, utimesSync,writeFileSync } from "node:fs";
|
|
11
11
|
import { tmpdir } from "node:os";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
import {
|
|
@@ -19,8 +19,8 @@ import {
|
|
|
19
19
|
test,
|
|
20
20
|
} from "bun:test";
|
|
21
21
|
|
|
22
|
-
import { _inspectHookCacheForTests } from "../hooks/hook-loader.js";
|
|
23
22
|
import {
|
|
23
|
+
_inspectHookCacheForTests,
|
|
24
24
|
_inspectToolCacheForTests,
|
|
25
25
|
getCachedUserTools,
|
|
26
26
|
getUserHooksFor,
|
|
@@ -62,15 +62,7 @@ function writeHook(dir: string, hookName: string, body: string): void {
|
|
|
62
62
|
function writeInstallMeta(dir: string, installedAt: string): void {
|
|
63
63
|
writeFileSync(
|
|
64
64
|
join(dir, "install-meta.json"),
|
|
65
|
-
JSON.stringify(
|
|
66
|
-
{
|
|
67
|
-
name: "test",
|
|
68
|
-
installedAt,
|
|
69
|
-
source: { kind: "github", owner: "test", repo: "test", ref: "main" },
|
|
70
|
-
},
|
|
71
|
-
null,
|
|
72
|
-
2,
|
|
73
|
-
),
|
|
65
|
+
JSON.stringify({ name: "test", installedAt, source: { kind: "github", owner: "test", repo: "test", ref: "main" } }, null, 2),
|
|
74
66
|
);
|
|
75
67
|
}
|
|
76
68
|
|
|
@@ -80,20 +72,6 @@ function writeTool(dir: string, toolName: string, body: string): void {
|
|
|
80
72
|
writeFileSync(join(toolsDir, `${toolName}.ts`), body);
|
|
81
73
|
}
|
|
82
74
|
|
|
83
|
-
/** The standalone workspace hooks directory (`<workspace>/hooks/`). */
|
|
84
|
-
const WORKSPACE_HOOKS_DIR = join(ROOT, "hooks");
|
|
85
|
-
|
|
86
|
-
function ensureWorkspaceHooksDir(): void {
|
|
87
|
-
rmSync(WORKSPACE_HOOKS_DIR, { recursive: true, force: true });
|
|
88
|
-
mkdirSync(WORKSPACE_HOOKS_DIR, { recursive: true });
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/** Write a standalone hook file directly under `<workspace>/hooks/`. */
|
|
92
|
-
function writeWorkspaceHook(hookName: string, body: string): void {
|
|
93
|
-
mkdirSync(WORKSPACE_HOOKS_DIR, { recursive: true });
|
|
94
|
-
writeFileSync(join(WORKSPACE_HOOKS_DIR, `${hookName}.ts`), body);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
75
|
/**
|
|
98
76
|
* Bump a file's mtime forward by ~2 seconds so the mtime cache detects a
|
|
99
77
|
* change. Using utimesSync avoids race conditions with filesystem mtime
|
|
@@ -119,7 +97,6 @@ beforeAll(() => {
|
|
|
119
97
|
|
|
120
98
|
beforeEach(() => {
|
|
121
99
|
ensurePluginsDir();
|
|
122
|
-
ensureWorkspaceHooksDir();
|
|
123
100
|
resetPluginCacheForTests();
|
|
124
101
|
});
|
|
125
102
|
|
|
@@ -361,9 +338,7 @@ describe("plugin mtime cache (per-surface)", () => {
|
|
|
361
338
|
expect(hooks).toHaveLength(2);
|
|
362
339
|
|
|
363
340
|
// beta was installed earlier (Jan 1) so it should come first.
|
|
364
|
-
const results = hooks.map((fn) =>
|
|
365
|
-
(fn as unknown as () => { tag: string })(),
|
|
366
|
-
);
|
|
341
|
+
const results = hooks.map((fn) => (fn as unknown as () => { tag: string })());
|
|
367
342
|
expect(results[0]!.tag).toBe("beta");
|
|
368
343
|
expect(results[1]!.tag).toBe("alpha");
|
|
369
344
|
});
|
|
@@ -393,124 +368,8 @@ describe("plugin mtime cache (per-surface)", () => {
|
|
|
393
368
|
const hooks = await getUserHooksFor("user-prompt-submit");
|
|
394
369
|
expect(hooks).toHaveLength(2);
|
|
395
370
|
|
|
396
|
-
const results = hooks.map((fn) =>
|
|
397
|
-
(fn as unknown as () => { tag: string })(),
|
|
398
|
-
);
|
|
371
|
+
const results = hooks.map((fn) => (fn as unknown as () => { tag: string })());
|
|
399
372
|
expect(results[0]!.tag).toBe("dated");
|
|
400
373
|
expect(results[1]!.tag).toBe("undated");
|
|
401
374
|
});
|
|
402
375
|
});
|
|
403
|
-
|
|
404
|
-
describe("workspace hooks (<workspace>/hooks/)", () => {
|
|
405
|
-
test("getUserHooksFor loads a standalone workspace hook", async () => {
|
|
406
|
-
writeWorkspaceHook(
|
|
407
|
-
"user-prompt-submit",
|
|
408
|
-
`export default () => ({ ws: 1 });`,
|
|
409
|
-
);
|
|
410
|
-
|
|
411
|
-
await populateCacheAtBoot();
|
|
412
|
-
|
|
413
|
-
const hooks = await getUserHooksFor("user-prompt-submit");
|
|
414
|
-
expect(hooks).toHaveLength(1);
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
test("workspace hooks load even when no plugins directory exists", async () => {
|
|
418
|
-
rmSync(PLUGINS_DIR, { recursive: true, force: true });
|
|
419
|
-
writeWorkspaceHook("post-tool-use", `export default () => ({ ws: 1 });`);
|
|
420
|
-
|
|
421
|
-
await populateCacheAtBoot();
|
|
422
|
-
|
|
423
|
-
const hooks = await getUserHooksFor("post-tool-use");
|
|
424
|
-
expect(hooks).toHaveLength(1);
|
|
425
|
-
expect(getCachedUserTools()).toHaveLength(0);
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
// NB: each test below uses a distinct hook event name so the workspace
|
|
429
|
-
// hook file path is unique. Bun caches dynamic import() by URL and does not
|
|
430
|
-
// bust on content change, so reusing `<workspace>/hooks/<name>.ts` across
|
|
431
|
-
// tests would return a stale module (the existing plugin tests dodge this
|
|
432
|
-
// by using a fresh plugin directory per test).
|
|
433
|
-
test("plugin hooks run before the workspace hook for the same event", async () => {
|
|
434
|
-
const dir = freshPluginDir("ordering-plugin");
|
|
435
|
-
writePackageJson(dir, { ...SIMPLE_PKG, name: "ordering-plugin" });
|
|
436
|
-
writeHook(
|
|
437
|
-
dir,
|
|
438
|
-
"pre-model-call",
|
|
439
|
-
`export default () => ({ tag: "plugin" });`,
|
|
440
|
-
);
|
|
441
|
-
writeWorkspaceHook(
|
|
442
|
-
"pre-model-call",
|
|
443
|
-
`export default () => ({ tag: "workspace" });`,
|
|
444
|
-
);
|
|
445
|
-
|
|
446
|
-
await populateCacheAtBoot();
|
|
447
|
-
|
|
448
|
-
const hooks = await getUserHooksFor("pre-model-call");
|
|
449
|
-
expect(hooks).toHaveLength(2);
|
|
450
|
-
const results = hooks.map((fn) =>
|
|
451
|
-
(fn as unknown as () => { tag: string })(),
|
|
452
|
-
);
|
|
453
|
-
expect(results[0]!.tag).toBe("plugin");
|
|
454
|
-
expect(results[1]!.tag).toBe("workspace");
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
test("editing a workspace hook file triggers re-import", async () => {
|
|
458
|
-
const hookFile = join(WORKSPACE_HOOKS_DIR, "post-model-call.ts");
|
|
459
|
-
writeWorkspaceHook("post-model-call", `export default () => ({ v: 1 });`);
|
|
460
|
-
|
|
461
|
-
await populateCacheAtBoot();
|
|
462
|
-
|
|
463
|
-
const before = _inspectHookCacheForTests().find((c) =>
|
|
464
|
-
c.key.startsWith("__workspace__/"),
|
|
465
|
-
);
|
|
466
|
-
expect(before).toBeDefined();
|
|
467
|
-
|
|
468
|
-
touchFile(hookFile);
|
|
469
|
-
await getUserHooksFor("post-model-call");
|
|
470
|
-
|
|
471
|
-
const after = _inspectHookCacheForTests().find((c) =>
|
|
472
|
-
c.key.startsWith("__workspace__/"),
|
|
473
|
-
);
|
|
474
|
-
expect(after?.sourceMtime).not.toBe(before?.sourceMtime);
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
test("deleting a workspace hook file evicts it on next read", async () => {
|
|
478
|
-
const hookFile = join(WORKSPACE_HOOKS_DIR, "stop.ts");
|
|
479
|
-
writeWorkspaceHook("stop", `export default () => ({ v: 1 });`);
|
|
480
|
-
|
|
481
|
-
await populateCacheAtBoot();
|
|
482
|
-
expect(await getUserHooksFor("stop")).toHaveLength(1);
|
|
483
|
-
|
|
484
|
-
rmSync(hookFile, { force: true });
|
|
485
|
-
|
|
486
|
-
const hooks = await getUserHooksFor("stop");
|
|
487
|
-
expect(hooks).toHaveLength(0);
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
test("a newly added workspace hook is picked up without restart", async () => {
|
|
491
|
-
await populateCacheAtBoot();
|
|
492
|
-
expect(await getUserHooksFor("post-compact")).toHaveLength(0);
|
|
493
|
-
|
|
494
|
-
writeWorkspaceHook("post-compact", `export default () => ({ v: 1 });`);
|
|
495
|
-
|
|
496
|
-
expect(await getUserHooksFor("post-compact")).toHaveLength(1);
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
test("a workspace init hook runs once at boot", async () => {
|
|
500
|
-
// The init hook writes a sentinel file so we can observe it ran exactly
|
|
501
|
-
// once during populateCacheAtBoot.
|
|
502
|
-
const sentinel = join(ROOT, "ws-init-ran.txt");
|
|
503
|
-
rmSync(sentinel, { force: true });
|
|
504
|
-
writeWorkspaceHook(
|
|
505
|
-
"init",
|
|
506
|
-
`import { appendFileSync } from "node:fs";
|
|
507
|
-
export default () => { appendFileSync(${JSON.stringify(sentinel)}, "x"); };`,
|
|
508
|
-
);
|
|
509
|
-
|
|
510
|
-
await populateCacheAtBoot();
|
|
511
|
-
|
|
512
|
-
const { readFileSync: rf, existsSync: ex } = await import("node:fs");
|
|
513
|
-
expect(ex(sentinel)).toBe(true);
|
|
514
|
-
expect(rf(sentinel, "utf8")).toBe("x");
|
|
515
|
-
});
|
|
516
|
-
});
|
|
@@ -95,8 +95,6 @@ mock.module("../config/loader.js", () => ({
|
|
|
95
95
|
}));
|
|
96
96
|
|
|
97
97
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
98
|
-
setConversationProcessingStartedAt: () => {},
|
|
99
|
-
isConversationProcessing: () => false,
|
|
100
98
|
addMessage: () => ({ id: "mock-msg-id" }),
|
|
101
99
|
getMessageById: () => null,
|
|
102
100
|
updateMessageContent: () => {},
|