@vellumai/assistant 0.9.0 → 0.10.0-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +18 -34
- package/bun.lock +7 -8
- package/docs/activation-funnel-telemetry.md +28 -22
- package/docs/architecture/security.md +29 -28
- package/docs/stt-provider-onboarding.md +3 -5
- package/docs/workflows-testing.md +13 -44
- package/docs/workflows.md +3 -5
- package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +47 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +28 -5
- package/node_modules/@vellumai/environments/src/seeds.ts +2 -5
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +97 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +32 -6
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +119 -0
- package/node_modules/@vellumai/gateway-client/src/types.ts +15 -84
- package/openapi.yaml +976 -63
- package/package.json +2 -1
- package/scripts/sync-llm-catalog.ts +6 -15
- package/scripts/sync-web-search-catalog.ts +3 -11
- package/src/__tests__/access-request-card-view.test.ts +98 -0
- package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -4
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +72 -32
- package/src/__tests__/agent-loop-compaction-strip.test.ts +241 -0
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
- package/src/__tests__/agent-loop-output-hooks.test.ts +69 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -3
- package/src/__tests__/app-compiler.test.ts +15 -1
- package/src/__tests__/app-dir-path-guard.test.ts +0 -1
- package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
- package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
- package/src/__tests__/avatar-identity-sync.test.ts +2 -27
- package/src/__tests__/btw-routes.test.ts +6 -8
- package/src/__tests__/call-pointer-messages.test.ts +28 -0
- package/src/__tests__/cancel-clears-processing.test.ts +89 -0
- package/src/__tests__/channel-approval-routes.test.ts +0 -4
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
- package/src/__tests__/checker.test.ts +0 -3
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
- package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
- package/src/__tests__/config-loader-backfill.test.ts +268 -27
- package/src/__tests__/config-schema.test.ts +35 -0
- package/src/__tests__/config-watcher.test.ts +0 -18
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +0 -6
- package/src/__tests__/contacts-tools.test.ts +29 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +58 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-lifecycle.test.ts +7 -9
- package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
- package/src/__tests__/conversation-title-service.test.ts +62 -0
- package/src/__tests__/credential-broker.test.ts +449 -1
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
- package/src/__tests__/credential-execution-tools.test.ts +0 -1
- package/src/__tests__/credential-prompt-route.test.ts +4 -4
- package/src/__tests__/credential-routes.test.ts +360 -0
- package/src/__tests__/credential-security-invariants.test.ts +4 -13
- package/src/__tests__/disk-pressure-policy.test.ts +12 -0
- package/src/__tests__/disk-usage.test.ts +65 -0
- package/src/__tests__/dynamic-page-surface.test.ts +152 -1
- package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
- package/src/__tests__/gateway-flag-listener.test.ts +110 -1
- package/src/__tests__/gateway-only-guard.test.ts +3 -7
- package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
- package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
- package/src/__tests__/guardian-grant-minting.test.ts +3 -35
- package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
- package/src/__tests__/guardian-routing-state.test.ts +0 -1
- package/src/__tests__/headless-browser-mode.test.ts +10 -0
- package/src/__tests__/headless-browser-navigate.test.ts +8 -3
- package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
- package/src/__tests__/host-browser-proxy.test.ts +87 -0
- package/src/__tests__/identity-routes.test.ts +0 -189
- package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
- package/src/__tests__/injector-v3-suppression.test.ts +27 -20
- package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
- package/src/__tests__/invite-redemption-service.test.ts +4 -7
- package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
- package/src/__tests__/llm-catalog-parity.test.ts +30 -23
- package/src/__tests__/llm-resolver.test.ts +70 -24
- package/src/__tests__/llm-schema.test.ts +1 -0
- package/src/__tests__/managed-profile-guard.test.ts +163 -4
- package/src/__tests__/mcp-health-check.test.ts +6 -7
- package/src/__tests__/media-stream-server-integration.test.ts +317 -13
- package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
- package/src/__tests__/onboarding-persona-write.test.ts +1 -1
- package/src/__tests__/path-policy.test.ts +34 -0
- package/src/__tests__/persona-resolver.test.ts +49 -14
- package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
- package/src/__tests__/plugin-api-provider.test.ts +24 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
- package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
- package/src/__tests__/reaction-persistence.test.ts +150 -29
- package/src/__tests__/registry.test.ts +2 -7
- package/src/__tests__/relay-server.test.ts +285 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
- package/src/__tests__/schedule-routes.test.ts +0 -30
- package/src/__tests__/schedule-tools.test.ts +2 -18
- package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
- package/src/__tests__/skill-execute-input.test.ts +51 -1
- package/src/__tests__/skill-runtime-path.test.ts +2 -3
- package/src/__tests__/skills.test.ts +51 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
- package/src/__tests__/subagent-tools.test.ts +266 -0
- package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
- package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +100 -3
- package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
- package/src/__tests__/token-manager.test.ts +519 -0
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
- package/src/__tests__/tool-audit-listener.test.ts +7 -7
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
- package/src/__tests__/tool-executor.test.ts +0 -79
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
- package/src/__tests__/trusted-contact-verification.test.ts +8 -10
- package/src/__tests__/twilio-routes.test.ts +81 -1
- package/src/__tests__/voice-invite-redemption.test.ts +2 -3
- package/src/__tests__/weak-open-model.test.ts +30 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
- package/src/__tests__/workspace-greetings.test.ts +152 -0
- package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
- package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
- package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
- package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
- package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
- package/src/agent/loop.ts +49 -29
- package/src/api/README.md +6 -6
- package/src/api/events/tool-result.ts +6 -0
- package/src/api/events/workflow-completed.ts +53 -0
- package/src/api/events/workflow-leaf-finished.ts +38 -0
- package/src/api/events/workflow-leaf-started.ts +35 -0
- package/src/api/events/workflow-progress.ts +32 -0
- package/src/api/events/workflow-started.ts +31 -0
- package/src/api/index.ts +40 -0
- package/src/api/responses/conversation-message.ts +28 -4
- package/src/api/responses/home.ts +26 -4
- package/src/api/responses/workflow-journal.ts +53 -0
- package/src/approvals/guardian-card-withdrawal.ts +145 -0
- package/src/approvals/guardian-decision-primitive.ts +26 -3
- package/src/approvals/guardian-request-resolvers.ts +183 -80
- package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
- package/src/calls/call-pointer-messages.ts +10 -4
- package/src/calls/channel-admission-reader.ts +104 -0
- package/src/calls/guardian-dispatch.ts +17 -45
- package/src/calls/media-stream-server.ts +84 -2
- package/src/calls/relay-access-wait.ts +1 -1
- package/src/calls/relay-server.ts +66 -0
- package/src/calls/relay-setup-router.ts +82 -1
- package/src/calls/twilio-routes.ts +17 -8
- package/src/calls/voice-session-bridge.ts +2 -2
- package/src/cli/commands/clients.ts +3 -0
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
- package/src/cli/commands/memory/index.ts +30 -0
- package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
- package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
- package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
- package/src/cli/commands/oauth/status.test.ts +36 -0
- package/src/cli/commands/oauth/status.ts +23 -3
- package/src/cli/commands/plugins.ts +197 -4
- package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
- package/src/cli/lib/diff-plugin.ts +346 -0
- package/src/cli/lib/inspect-plugin.ts +12 -1
- package/src/cli/lib/install-from-github.ts +105 -17
- package/src/cli/lib/merge-plugin-tree.ts +328 -0
- package/src/cli/lib/plugin-fingerprint.ts +14 -0
- package/src/cli/lib/plugin-surfaces.ts +104 -0
- package/src/cli/lib/upgrade-plugin.ts +298 -10
- package/src/cli/program.ts +2 -6
- package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
- package/src/config/assistant-feature-flags.ts +22 -7
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
- package/src/config/bundled-skills/messaging/SKILL.md +6 -4
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
- package/src/config/bundled-skills/subagent/SKILL.md +4 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
- package/src/config/bundled-skills/workflows/SKILL.md +14 -8
- package/src/config/bundled-tool-registry.ts +2 -7
- package/src/config/call-site-defaults.ts +15 -2
- package/src/config/feature-flag-registry.json +46 -31
- package/src/config/inference-profile-validation.ts +26 -0
- package/src/config/llm-resolver.ts +3 -0
- package/src/config/loader.ts +4 -0
- package/src/config/memory-v3-gate.ts +11 -0
- package/src/config/profile-order.ts +28 -0
- package/src/config/schema.ts +8 -6
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/channels.ts +11 -0
- package/src/config/schemas/elevenlabs.ts +0 -1
- package/src/config/schemas/llm.ts +31 -0
- package/src/config/schemas/memory-lifecycle.ts +3 -7
- package/src/config/schemas/memory-v3.ts +6 -0
- package/src/config/schemas/platform.ts +0 -8
- package/src/config/schemas/services.ts +18 -0
- package/src/config/seed-inference-profiles.ts +109 -44
- package/src/config/skills.ts +21 -0
- package/src/config/sync-gated-profiles.ts +220 -0
- package/src/contacts/contact-store.ts +89 -106
- package/src/contacts/contacts-write.ts +5 -22
- package/src/contacts/types.ts +0 -1
- package/src/context/compactor.ts +88 -54
- package/src/context/strip-injections.ts +58 -10
- package/src/context/token-estimator.ts +1 -1
- package/src/credential-execution/process-manager.ts +55 -14
- package/src/credential-execution/prompted-credential.ts +2 -3
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
- package/src/daemon/config-watcher.ts +0 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
- package/src/daemon/conversation-agent-loop.ts +114 -22
- package/src/daemon/conversation-history.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +3 -5
- package/src/daemon/conversation-process.ts +13 -5
- package/src/daemon/conversation-runtime-assembly.ts +13 -15
- package/src/daemon/conversation-slash.ts +2 -23
- package/src/daemon/conversation-surfaces.ts +26 -0
- package/src/daemon/conversation-tool-setup.ts +27 -14
- package/src/daemon/conversation.ts +66 -14
- package/src/daemon/disk-pressure-policy.ts +5 -3
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
- package/src/daemon/handlers/config-a2a.ts +0 -2
- package/src/daemon/handlers/config-channels.ts +15 -16
- package/src/daemon/handlers/config-slack-channel.ts +22 -3
- package/src/daemon/handlers/conversations.ts +107 -0
- package/src/daemon/host-browser-proxy.ts +41 -0
- package/src/daemon/lifecycle.ts +55 -27
- package/src/daemon/message-provenance.ts +2 -0
- package/src/daemon/message-types/contacts.ts +0 -1
- package/src/daemon/message-types/conversations.ts +3 -3
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/message-types/web-activity.ts +7 -1
- package/src/daemon/message-types/workflows.ts +83 -1
- package/src/daemon/orphan-reaper.test.ts +0 -19
- package/src/daemon/orphan-reaper.ts +2 -24
- package/src/daemon/server.ts +0 -10
- package/src/daemon/tool-setup-types.ts +4 -0
- package/src/daemon/trust-context.ts +1 -1
- package/src/events/tool-audit-listener.ts +2 -2
- package/src/home/feed-source-enrichment.test.ts +151 -0
- package/src/home/feed-source-enrichment.ts +176 -0
- package/src/home/relationship-state.ts +2 -4
- package/src/instrument.ts +18 -6
- package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
- package/src/ipc/assistant-server.ts +37 -4
- package/src/ipc/gateway-flag-listener.ts +18 -2
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
- package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
- package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
- package/src/memory/auth-fallback-events-store.ts +2 -2
- package/src/memory/auto-analysis-enqueue.ts +3 -5
- package/src/memory/bookmark-crud.ts +1 -2
- package/src/memory/canonical-guardian-store.ts +39 -1
- package/src/memory/conversation-crud.ts +9 -4
- package/src/memory/conversation-key-store.ts +17 -2
- package/src/memory/conversation-title-service.ts +64 -7
- package/src/memory/db-init.ts +17 -17
- package/src/memory/embedding-backend.ts +38 -1
- package/src/memory/embedding-billing-breaker.ts +96 -0
- package/src/memory/jobs-store.ts +25 -13
- package/src/memory/jobs-worker.ts +54 -1
- package/src/memory/lifecycle-events-store.ts +2 -2
- package/src/memory/memory-retrospective-constants.ts +4 -4
- package/src/memory/memory-retrospective-enqueue.ts +31 -6
- package/src/memory/memory-retrospective-job.ts +28 -227
- package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
- package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
- package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
- package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
- package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
- package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
- package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
- package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
- package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
- package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/run-migrations.ts +41 -0
- package/src/memory/migrations/validate-migration-state.ts +1 -1
- package/src/memory/onboarding-events-store.ts +3 -3
- package/src/memory/schema/contacts.ts +0 -5
- package/src/memory/skill-loaded-events-store.test.ts +7 -15
- package/src/memory/skill-loaded-events-store.ts +2 -2
- package/src/memory/tool-executed-events-store.test.ts +7 -7
- package/src/memory/turn-trace-store.test.ts +736 -0
- package/src/memory/turn-trace-store.ts +364 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
- package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
- package/src/memory/v2/consolidation-job.ts +2 -2
- package/src/memory/v2/skill-content.ts +25 -7
- package/src/memory/v2/skill-store.ts +7 -1
- package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
- package/src/memory/v3-eval/eval-packets.ts +546 -0
- package/src/messaging/providers/slack/adapter.ts +1 -1
- package/src/messaging/providers/slack/api.ts +31 -0
- package/src/messaging/providers/slack/send.test.ts +114 -2
- package/src/messaging/providers/slack/send.ts +30 -7
- package/src/messaging/providers/slack/withdraw.test.ts +200 -0
- package/src/messaging/providers/slack/withdraw.ts +161 -0
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/access-request-copy.ts +72 -59
- package/src/notifications/adapters/shared.ts +29 -0
- package/src/notifications/adapters/slack.ts +58 -103
- package/src/notifications/adapters/telegram.ts +2 -20
- package/src/notifications/approval-card-data.ts +333 -0
- package/src/notifications/broadcaster.ts +16 -3
- package/src/notifications/canonical-delivery-recorder.ts +139 -0
- package/src/notifications/copy-composer.ts +3 -3
- package/src/notifications/decision-engine.ts +4 -2
- package/src/notifications/destination-resolver.ts +4 -6
- package/src/notifications/guardian-question-mode.ts +10 -0
- package/src/notifications/home-feed-side-effect.ts +7 -16
- package/src/notifications/notification-utils.ts +19 -20
- package/src/notifications/signal.ts +79 -43
- package/src/notifications/types.ts +98 -121
- package/src/oauth/AGENTS.md +5 -24
- package/src/permissions/checker.test.ts +51 -0
- package/src/permissions/checker.ts +185 -26
- package/src/permissions/ipc-risk-types.ts +24 -0
- package/src/permissions/question-prompter.test.ts +27 -0
- package/src/permissions/question-prompter.ts +4 -0
- package/src/platform/client.test.ts +119 -0
- package/src/platform/client.ts +66 -0
- package/src/platform/consent-cache.test.ts +267 -0
- package/src/platform/consent-cache.ts +174 -0
- package/src/plugin-api/constants.ts +1 -1
- package/src/plugin-api/index.ts +33 -1
- package/src/plugin-api/model-profiles.ts +33 -0
- package/src/plugin-api/types.ts +50 -2
- package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
- package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
- package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
- package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
- package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
- package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
- package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
- package/src/plugins/defaults/advisor/config.ts +21 -0
- package/src/plugins/defaults/advisor/consult.ts +93 -0
- package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
- package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
- package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/advisor/package.json +14 -0
- package/src/plugins/defaults/advisor/steering.ts +67 -0
- package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
- package/src/plugins/defaults/advisor/transcript.ts +76 -0
- package/src/plugins/defaults/index.ts +60 -0
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
- package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
- package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
- package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
- package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
- package/src/prompts/persona-resolver.ts +14 -4
- package/src/prompts/templates/system-sections.ts +7 -2
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
- package/src/providers/__tests__/retry-callsite.test.ts +176 -0
- package/src/providers/atlascloud/client.ts +85 -0
- package/src/providers/fetch-provider-catalog.ts +85 -0
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/model-catalog.ts +58 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
- package/src/providers/openai/chat-completions-provider.ts +7 -0
- package/src/providers/openai/responses-provider.ts +10 -0
- package/src/providers/provider-send-message.ts +11 -3
- package/src/providers/retry.ts +53 -12
- package/src/providers/search-provider-catalog.ts +10 -0
- package/src/providers/weak-open-model.ts +22 -0
- package/src/runtime/AGENTS.md +0 -1
- package/src/runtime/__tests__/agent-wake.test.ts +181 -0
- package/src/runtime/__tests__/client-health.test.ts +44 -0
- package/src/runtime/access-request-helper.ts +21 -53
- package/src/runtime/actor-trust-resolver.ts +59 -63
- package/src/runtime/agent-wake.ts +52 -0
- package/src/runtime/assistant-event-hub.ts +18 -4
- package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
- package/src/runtime/auth/require-bound-guardian.ts +1 -4
- package/src/runtime/btw-sidechain.ts +3 -6
- package/src/runtime/capabilities.test.ts +120 -0
- package/src/runtime/capabilities.ts +197 -0
- package/src/runtime/channel-approval-types.ts +22 -45
- package/src/runtime/channel-invite-transports/telegram.ts +4 -4
- package/src/runtime/channel-retry-sweep.ts +1 -0
- package/src/runtime/channel-verification-service.ts +3 -3
- package/src/runtime/client-health.ts +26 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
- package/src/runtime/effective-capabilities.test.ts +128 -0
- package/src/runtime/effective-capabilities.ts +84 -0
- package/src/runtime/guardian-reply-router.ts +106 -21
- package/src/runtime/invite-redemption-service.ts +9 -25
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +123 -0
- package/src/runtime/migrations/vbundle-builder.ts +49 -20
- package/src/runtime/pending-interactions.ts +15 -0
- package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +240 -1
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
- package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
- package/src/runtime/routes/browser-tabs-routes.ts +9 -0
- package/src/runtime/routes/btw-routes.ts +1 -27
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
- package/src/runtime/routes/client-routes.ts +10 -0
- package/src/runtime/routes/contact-routes.ts +31 -8
- package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
- package/src/runtime/routes/conversation-management-routes.ts +80 -1
- package/src/runtime/routes/conversation-query-routes.ts +68 -22
- package/src/runtime/routes/conversation-routes.ts +39 -14
- package/src/runtime/routes/credential-routes.ts +40 -16
- package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
- package/src/runtime/routes/events-routes.ts +1 -3
- package/src/runtime/routes/guardian-approval-interception.ts +14 -73
- package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
- package/src/runtime/routes/home-feed-routes.ts +8 -3
- package/src/runtime/routes/identity-routes.ts +1 -296
- package/src/runtime/routes/inbound-message-handler.ts +214 -228
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
- package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
- package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
- package/src/runtime/routes/integrations/slack/channel.ts +36 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
- package/src/runtime/routes/mcp-auth-routes.ts +233 -41
- package/src/runtime/routes/memory-eval-routes.ts +87 -0
- package/src/runtime/routes/notification-routes.ts +122 -133
- package/src/runtime/routes/platform-routes.ts +2 -2
- package/src/runtime/routes/plugins-routes.ts +202 -3
- package/src/runtime/routes/schedule-routes.ts +0 -22
- package/src/runtime/routes/secret-routes.ts +10 -0
- package/src/runtime/routes/surface-action-routes.ts +2 -1
- package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
- package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
- package/src/runtime/routes/workflow-routes.test.ts +229 -44
- package/src/runtime/routes/workflow-routes.ts +131 -29
- package/src/runtime/routes/workspace-greetings.ts +55 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -11
- package/src/runtime/tool-grant-request-helper.ts +18 -16
- package/src/runtime/trust-context-resolver.ts +8 -5
- package/src/schedule/inference-profile.ts +2 -14
- package/src/schedule/schedule-store.ts +1 -1
- package/src/schedule/scheduler-types.ts +5 -1
- package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
- package/src/security/secret-patterns.ts +3 -0
- package/src/subagent/manager.ts +17 -4
- package/src/subagent/types.ts +6 -0
- package/src/telemetry/trace-collection-policy.test.ts +28 -0
- package/src/telemetry/trace-collection-policy.ts +30 -0
- package/src/telemetry/types.ts +89 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
- package/src/telemetry/usage-telemetry-reporter.ts +148 -41
- package/src/tools/AGENTS.md +3 -3
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
- package/src/tools/browser/browser-execution.ts +30 -19
- package/src/tools/document/document-tool.ts +2 -3
- package/src/tools/executor.ts +5 -3
- package/src/tools/host-terminal/host-shell.ts +5 -4
- package/src/tools/memory/register.ts +2 -2
- package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
- package/src/tools/network/__tests__/web-search.test.ts +143 -0
- package/src/tools/network/web-fetch.ts +372 -1
- package/src/tools/network/web-search-error.ts +1 -1
- package/src/tools/network/web-search.ts +213 -10
- package/src/tools/permission-checker.ts +4 -3
- package/src/tools/registry.ts +20 -0
- package/src/tools/schedule/create.ts +7 -12
- package/src/tools/schedule/update.ts +4 -11
- package/src/tools/shared/filesystem/path-policy.ts +39 -13
- package/src/tools/side-effects.ts +2 -17
- package/src/tools/skills/execute.ts +33 -0
- package/src/tools/subagent/spawn.ts +61 -12
- package/src/tools/terminal/shell.ts +10 -4
- package/src/tools/tool-approval-handler.ts +18 -13
- package/src/tools/tool-manifest.ts +0 -2
- package/src/tools/types.ts +9 -0
- package/src/tools/ui-surface/definitions.ts +64 -3
- package/src/tools/verification-control-plane-policy.ts +3 -1
- package/src/tools/workflows/run-workflow.test.ts +8 -18
- package/src/tools/workflows/run-workflow.ts +1 -0
- package/src/util/disk-usage.ts +78 -23
- package/src/util/platform.ts +10 -3
- package/src/watcher/telemetry.ts +2 -2
- package/src/workflows/capabilities.ts +2 -3
- package/src/workflows/engine.test.ts +175 -1
- package/src/workflows/engine.ts +82 -0
- package/src/workflows/journal-store.test.ts +70 -0
- package/src/workflows/journal-store.ts +18 -3
- package/src/workflows/run-manager.test.ts +171 -28
- package/src/workflows/run-manager.ts +66 -24
- package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
- package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
- package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
- package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
- package/src/__tests__/credential-security-e2e.test.ts +0 -362
- package/src/__tests__/credential-vault-unit.test.ts +0 -1528
- package/src/__tests__/credential-vault.test.ts +0 -1706
- package/src/__tests__/identity-intro-cache.test.ts +0 -315
- package/src/__tests__/secret-onetime-send.test.ts +0 -182
- package/src/cli/commands/__tests__/task.test.ts +0 -914
- package/src/cli/commands/task.ts +0 -771
- package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
- package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
- package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
- package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
- package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
- package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
- package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
- package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
- package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
- package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
- package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
- package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
- package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
- package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
- package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
- package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
- package/src/memory/preloaded-apps.ts +0 -116
- package/src/notifications/tool-approval-copy.ts +0 -142
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
- package/src/runtime/routes/identity-intro-cache.ts +0 -172
- package/src/tools/credentials/vault.ts +0 -712
|
@@ -46,23 +46,20 @@ import { eq } from "drizzle-orm";
|
|
|
46
46
|
|
|
47
47
|
import { upsertContactChannel } from "../contacts/contacts-write.js";
|
|
48
48
|
import type { Conversation } from "../daemon/conversation.js";
|
|
49
|
+
import {
|
|
50
|
+
createCanonicalGuardianDelivery,
|
|
51
|
+
createCanonicalGuardianRequest,
|
|
52
|
+
getCanonicalGuardianRequest,
|
|
53
|
+
} from "../memory/canonical-guardian-store.js";
|
|
49
54
|
import { getDb } from "../memory/db-connection.js";
|
|
50
55
|
import { initializeDb } from "../memory/db-init.js";
|
|
51
|
-
import {
|
|
52
|
-
createApprovalRequest,
|
|
53
|
-
getPendingApprovalForRequest,
|
|
54
|
-
} from "../memory/guardian-approvals.js";
|
|
55
56
|
import { messages } from "../memory/schema/conversations.js";
|
|
56
57
|
import { readSlackMetadata } from "../messaging/providers/slack/message-metadata.js";
|
|
57
58
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
58
|
-
import {
|
|
59
|
-
_clearApprovalPromptTsTrackerForTesting,
|
|
60
|
-
trackApprovalPromptTs,
|
|
61
|
-
} from "../runtime/routes/approval-prompt-ts-tracker.js";
|
|
62
59
|
import {
|
|
63
60
|
isSlackReactionEvent,
|
|
64
61
|
parseSlackReactionCallbackData,
|
|
65
|
-
} from "../runtime/routes/inbound-
|
|
62
|
+
} from "../runtime/routes/inbound-stages/reaction-intercept.js";
|
|
66
63
|
import { handleChannelInbound } from "./helpers/channel-test-adapter.js";
|
|
67
64
|
import { createGuardianBinding } from "./helpers/create-guardian-binding.js";
|
|
68
65
|
|
|
@@ -84,7 +81,6 @@ function resetState(): void {
|
|
|
84
81
|
db.run("DELETE FROM conversations");
|
|
85
82
|
db.run("DELETE FROM contact_channels");
|
|
86
83
|
db.run("DELETE FROM contacts");
|
|
87
|
-
_clearApprovalPromptTsTrackerForTesting();
|
|
88
84
|
}
|
|
89
85
|
|
|
90
86
|
function seedActiveMember(): void {
|
|
@@ -421,21 +417,35 @@ function seedGuardianForChannel(): void {
|
|
|
421
417
|
function seedPendingGuardianApprovalForReaction(
|
|
422
418
|
requestId: string,
|
|
423
419
|
conversationId: string,
|
|
420
|
+
reactedTs: string,
|
|
424
421
|
): void {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
422
|
+
// Canonical tool_approval request keyed by the confirmation requestId — the
|
|
423
|
+
// same record assistant-event-hub creates for every confirmation.
|
|
424
|
+
createCanonicalGuardianRequest({
|
|
425
|
+
id: requestId,
|
|
426
|
+
kind: "tool_approval",
|
|
427
|
+
sourceType: "channel",
|
|
428
|
+
sourceChannel: "slack",
|
|
428
429
|
conversationId,
|
|
429
|
-
channel: "slack",
|
|
430
430
|
requesterExternalUserId: "requester-user-1",
|
|
431
431
|
requesterChatId: SLACK_CHANNEL_ID,
|
|
432
432
|
guardianExternalUserId: GUARDIAN_USER_ID,
|
|
433
|
-
|
|
433
|
+
guardianPrincipalId: GUARDIAN_USER_ID,
|
|
434
434
|
toolName: GUARDIAN_REACTION_TOOL,
|
|
435
|
+
status: "pending",
|
|
435
436
|
expiresAt: Date.now() + 300_000,
|
|
436
437
|
});
|
|
437
438
|
|
|
438
|
-
//
|
|
439
|
+
// The delivered approval card → request mapping the reaction resolves
|
|
440
|
+
// against (destination_message_id = the reacted Slack ts).
|
|
441
|
+
createCanonicalGuardianDelivery({
|
|
442
|
+
requestId,
|
|
443
|
+
destinationChannel: "slack",
|
|
444
|
+
destinationChatId: SLACK_CHANNEL_ID,
|
|
445
|
+
destinationMessageId: reactedTs,
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Register a pending interaction so the tool_approval resolver finds the
|
|
439
449
|
// requester-side hook to drive `allow`.
|
|
440
450
|
const handleConfirmationResponse = mock(() => {});
|
|
441
451
|
const _mockSession = {
|
|
@@ -466,18 +476,17 @@ describe("guardian approval-by-reaction integration via handleChannelInbound", (
|
|
|
466
476
|
db.run("DELETE FROM conversations");
|
|
467
477
|
db.run("DELETE FROM contact_channels");
|
|
468
478
|
db.run("DELETE FROM contacts");
|
|
469
|
-
db.run("DELETE FROM
|
|
479
|
+
db.run("DELETE FROM canonical_guardian_requests");
|
|
480
|
+
db.run("DELETE FROM canonical_guardian_deliveries");
|
|
470
481
|
pendingInteractions.clear();
|
|
471
|
-
_clearApprovalPromptTsTrackerForTesting();
|
|
472
482
|
msgCounter = 0;
|
|
473
483
|
});
|
|
474
484
|
|
|
475
485
|
test("guardian reaction on pending approval applies decision and persists no transcript row", async () => {
|
|
476
486
|
seedGuardianForChannel();
|
|
477
487
|
const requestId = "req-guardian-react-1";
|
|
478
|
-
//
|
|
479
|
-
//
|
|
480
|
-
// ACL allows. Easier: insert directly via the DB layer.
|
|
488
|
+
// Back the canonical request and its pending interaction with a real
|
|
489
|
+
// conversation row, inserted directly via the DB layer.
|
|
481
490
|
const db = getDb();
|
|
482
491
|
const conversationId = "conv-react-test-1";
|
|
483
492
|
const now = Date.now();
|
|
@@ -491,12 +500,15 @@ describe("guardian approval-by-reaction integration via handleChannelInbound", (
|
|
|
491
500
|
)
|
|
492
501
|
.run(conversationId, now, now);
|
|
493
502
|
|
|
494
|
-
seedPendingGuardianApprovalForReaction(requestId, conversationId);
|
|
495
|
-
|
|
496
503
|
const reactedTs = "1700000099.000001";
|
|
497
|
-
//
|
|
498
|
-
// guardian reaction is scoped to a
|
|
499
|
-
|
|
504
|
+
// The approval card was delivered on this ts; its canonical delivery row
|
|
505
|
+
// is how the guardian reaction is scoped to a known approval message.
|
|
506
|
+
seedPendingGuardianApprovalForReaction(
|
|
507
|
+
requestId,
|
|
508
|
+
conversationId,
|
|
509
|
+
reactedTs,
|
|
510
|
+
);
|
|
511
|
+
|
|
500
512
|
const body = {
|
|
501
513
|
sourceChannel: "slack",
|
|
502
514
|
interface: "slack",
|
|
@@ -541,11 +553,11 @@ describe("guardian approval-by-reaction integration via handleChannelInbound", (
|
|
|
541
553
|
|
|
542
554
|
expect(resp.status).toBe(200);
|
|
543
555
|
expect(json.accepted).toBe(true);
|
|
544
|
-
expect(json.
|
|
556
|
+
expect(json.canonicalRouter).toBe("canonical_decision_applied");
|
|
545
557
|
expect(approvalConversationGenerator).not.toHaveBeenCalled();
|
|
546
558
|
|
|
547
|
-
// The
|
|
548
|
-
expect(
|
|
559
|
+
// The canonical request is resolved (no longer pending).
|
|
560
|
+
expect(getCanonicalGuardianRequest(requestId)?.status).toBe("approved");
|
|
549
561
|
|
|
550
562
|
// No transcript row was written for the reaction itself — resolved
|
|
551
563
|
// guardian approval reactions have no transcript representation.
|
|
@@ -563,3 +575,112 @@ describe("guardian approval-by-reaction integration via handleChannelInbound", (
|
|
|
563
575
|
expect(reactionRows.length).toBe(0);
|
|
564
576
|
});
|
|
565
577
|
});
|
|
578
|
+
|
|
579
|
+
// ---------------------------------------------------------------------------
|
|
580
|
+
// Reaction access-control regression (LUM-2489)
|
|
581
|
+
// ---------------------------------------------------------------------------
|
|
582
|
+
//
|
|
583
|
+
// A reaction is a passive signal, not an access attempt. Because reactions are
|
|
584
|
+
// dispatched before the ingress pipeline, an unknown user's 👍 must never run
|
|
585
|
+
// ACL (no trusted-contact verification handshake), create a conversation, or
|
|
586
|
+
// write a binding — it is dropped as channel noise. A known contact's reaction
|
|
587
|
+
// is recorded; neither triggers a verification challenge.
|
|
588
|
+
|
|
589
|
+
describe("reaction access control (no verification handshake)", () => {
|
|
590
|
+
const STRANGER_USER_ID = "U_REACTION_STRANGER";
|
|
591
|
+
const CONTACT_USER_ID = "U_REACTION_CONTACT";
|
|
592
|
+
// Guardian's approval channel is a DM, distinct from the public channel the
|
|
593
|
+
// reaction lands in (mirroring production). Reusing the public channel id
|
|
594
|
+
// would let a reactor match the guardian's channel via findContactChannel's
|
|
595
|
+
// externalChatId fallback and mask the bug.
|
|
596
|
+
const GUARDIAN_DM_CHAT = "D_GUARDIAN_DM";
|
|
597
|
+
|
|
598
|
+
function tableCount(table: string): number {
|
|
599
|
+
return (
|
|
600
|
+
getDb().$client.prepare(`SELECT COUNT(*) AS n FROM ${table}`).get() as {
|
|
601
|
+
n: number;
|
|
602
|
+
}
|
|
603
|
+
).n;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
beforeEach(() => {
|
|
607
|
+
resetState();
|
|
608
|
+
getDb().run("DELETE FROM channel_verification_sessions");
|
|
609
|
+
// The assistant has a guardian (as in production); the reactors below are
|
|
610
|
+
// different users.
|
|
611
|
+
createGuardianBinding({
|
|
612
|
+
channel: "slack",
|
|
613
|
+
guardianExternalUserId: GUARDIAN_USER_ID,
|
|
614
|
+
guardianDeliveryChatId: GUARDIAN_DM_CHAT,
|
|
615
|
+
guardianPrincipalId: GUARDIAN_USER_ID,
|
|
616
|
+
});
|
|
617
|
+
msgCounter = 0;
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
test("stranger's reaction is dropped — no challenge, session, conversation, or row", async () => {
|
|
621
|
+
let agentDispatched = false;
|
|
622
|
+
const processMessage = async (): Promise<{ messageId: string }> => {
|
|
623
|
+
agentDispatched = true;
|
|
624
|
+
return { messageId: "should-not-be-called" };
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
const req = buildReactionRequest("reaction:thumbsup", {
|
|
628
|
+
actorExternalId: STRANGER_USER_ID,
|
|
629
|
+
actorDisplayName: "Outside Reactor",
|
|
630
|
+
actorUsername: "outsider",
|
|
631
|
+
});
|
|
632
|
+
const resp = await handleChannelInbound(
|
|
633
|
+
req,
|
|
634
|
+
processMessage,
|
|
635
|
+
TEST_BEARER_TOKEN,
|
|
636
|
+
);
|
|
637
|
+
const json = (await resp.json()) as Record<string, unknown>;
|
|
638
|
+
|
|
639
|
+
// Accepted as a passive signal — never denied or turned into a challenge.
|
|
640
|
+
expect(json.accepted).toBe(true);
|
|
641
|
+
expect(json.denied).not.toBe(true);
|
|
642
|
+
expect(json.reason).not.toBe("verification_challenge_sent");
|
|
643
|
+
expect(json.verificationSessionId).toBeUndefined();
|
|
644
|
+
expect(agentDispatched).toBe(false);
|
|
645
|
+
|
|
646
|
+
// No verification handshake, and no side effects: a dropped reaction leaves
|
|
647
|
+
// no transcript row, no conversation, and no binding.
|
|
648
|
+
expect(tableCount("channel_verification_sessions")).toBe(0);
|
|
649
|
+
expect(readPersistedMessages().length).toBe(0);
|
|
650
|
+
expect(tableCount("conversations")).toBe(0);
|
|
651
|
+
expect(tableCount("external_conversation_bindings")).toBe(0);
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
test("known contact's reaction is recorded — no challenge", async () => {
|
|
655
|
+
// A pending contact classifies as `unverified_contact` — a known tier, so
|
|
656
|
+
// its reactions are recorded. On a real message it would be re-challenged,
|
|
657
|
+
// but a reaction must not trigger that.
|
|
658
|
+
upsertContactChannel({
|
|
659
|
+
sourceChannel: "slack",
|
|
660
|
+
externalUserId: CONTACT_USER_ID,
|
|
661
|
+
externalChatId: SLACK_CHANNEL_ID,
|
|
662
|
+
status: "pending",
|
|
663
|
+
policy: "allow",
|
|
664
|
+
displayName: "Pending Contact",
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
const req = buildReactionRequest("reaction:tada", {
|
|
668
|
+
actorExternalId: CONTACT_USER_ID,
|
|
669
|
+
actorDisplayName: "Pending Contact",
|
|
670
|
+
actorUsername: "pending_contact",
|
|
671
|
+
});
|
|
672
|
+
const resp = await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
|
|
673
|
+
const json = (await resp.json()) as Record<string, unknown>;
|
|
674
|
+
|
|
675
|
+
expect(json.denied).not.toBe(true);
|
|
676
|
+
expect(json.reason).not.toBe("verification_challenge_sent");
|
|
677
|
+
expect(tableCount("channel_verification_sessions")).toBe(0);
|
|
678
|
+
|
|
679
|
+
const rows = readPersistedMessages();
|
|
680
|
+
expect(rows.length).toBe(1);
|
|
681
|
+
const envelope = JSON.parse(rows[0].metadata!) as Record<string, unknown>;
|
|
682
|
+
const slackMeta = readSlackMetadata(envelope.slackMeta as string);
|
|
683
|
+
expect(slackMeta?.eventKind).toBe("reaction");
|
|
684
|
+
expect(slackMeta?.reaction?.emoji).toBe("tada");
|
|
685
|
+
});
|
|
686
|
+
});
|
|
@@ -21,11 +21,7 @@ import {
|
|
|
21
21
|
unregisterWorkspaceTool,
|
|
22
22
|
} from "../tools/registry.js";
|
|
23
23
|
import { eagerModuleToolNames, explicitTools } from "../tools/tool-manifest.js";
|
|
24
|
-
import type {
|
|
25
|
-
Tool,
|
|
26
|
-
ToolContext,
|
|
27
|
-
ToolExecutionResult,
|
|
28
|
-
} from "../tools/types.js";
|
|
24
|
+
import type { Tool, ToolContext, ToolExecutionResult } from "../tools/types.js";
|
|
29
25
|
|
|
30
26
|
// Clean up global registry after this file completes to prevent
|
|
31
27
|
// contamination of subsequent test files in combined runs.
|
|
@@ -115,12 +111,11 @@ describe("tool manifest", () => {
|
|
|
115
111
|
expect(eagerModuleToolNames.length).toBe(11);
|
|
116
112
|
});
|
|
117
113
|
|
|
118
|
-
test("explicit tools list includes memory
|
|
114
|
+
test("explicit tools list includes memory tools", () => {
|
|
119
115
|
const names = explicitTools.map((t) => t.name);
|
|
120
116
|
expect(names).toContain("recall");
|
|
121
117
|
expect(names.filter((name) => name === "recall")).toHaveLength(1);
|
|
122
118
|
expect(names).toContain("remember");
|
|
123
|
-
expect(names).toContain("credential_store");
|
|
124
119
|
});
|
|
125
120
|
|
|
126
121
|
test("registered tool count is at least eager + host", async () => {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { createHash, randomUUID } from "node:crypto";
|
|
17
17
|
import {
|
|
18
18
|
afterAll,
|
|
19
|
+
beforeAll,
|
|
19
20
|
beforeEach,
|
|
20
21
|
describe,
|
|
21
22
|
expect,
|
|
@@ -25,6 +26,10 @@ import {
|
|
|
25
26
|
test,
|
|
26
27
|
} from "bun:test";
|
|
27
28
|
|
|
29
|
+
import { ADMISSION_FLOOR } from "@vellumai/gateway-client";
|
|
30
|
+
|
|
31
|
+
import { TRUST_CLASS_RANK } from "../runtime/actor-trust-resolver.js";
|
|
32
|
+
|
|
28
33
|
// ── Platform + logger mocks (must come before any source imports) ────
|
|
29
34
|
|
|
30
35
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
@@ -100,6 +105,80 @@ mock.module("../config/loader.js", () => ({
|
|
|
100
105
|
loadConfig: () => mockConfig,
|
|
101
106
|
}));
|
|
102
107
|
|
|
108
|
+
// ── Channel admission policy reader mock ────────────────────────────
|
|
109
|
+
//
|
|
110
|
+
// handleSetup resolves the phone admission floor via this reader and forwards
|
|
111
|
+
// it into routeSetup. Tests drive the floor by setting `mockAdmissionPolicy`
|
|
112
|
+
// (or making the reader throw to exercise the fail-open guard).
|
|
113
|
+
|
|
114
|
+
let mockAdmissionPolicy:
|
|
115
|
+
| import("@vellumai/gateway-client").AdmissionPolicy
|
|
116
|
+
| null = null;
|
|
117
|
+
// Optional gate to hold the reader open mid-setup so tests can drive the
|
|
118
|
+
// race window where a prompt arrives while handleSetup is still awaiting.
|
|
119
|
+
let mockAdmissionGate: Promise<void> | null = null;
|
|
120
|
+
// `mock.module` is process-global in Bun and leaks into sibling files that run
|
|
121
|
+
// later in the same `bun test` invocation. channel-admission-reader.test.ts
|
|
122
|
+
// imports the reader for real, so an unconditional stub here would feed it this
|
|
123
|
+
// stub and break its assertions. Delegate to the real implementation unless
|
|
124
|
+
// this file's tests are active (`admissionMockActive`, toggled in
|
|
125
|
+
// beforeAll/afterAll). Snapshot the real exports into a plain object NOW,
|
|
126
|
+
// before the stub registers — a module namespace is a live view, so reading
|
|
127
|
+
// the real export after the stub installs would resolve back to the stub
|
|
128
|
+
// (infinite recursion).
|
|
129
|
+
const realChannelAdmissionReaderModule = {
|
|
130
|
+
...(await import("../calls/channel-admission-reader.js")),
|
|
131
|
+
};
|
|
132
|
+
let admissionMockActive = false;
|
|
133
|
+
mock.module("../calls/channel-admission-reader.js", () => ({
|
|
134
|
+
...realChannelAdmissionReaderModule,
|
|
135
|
+
getChannelAdmissionPolicy: async (
|
|
136
|
+
channelType: import("../channels/types.js").ChannelId,
|
|
137
|
+
) => {
|
|
138
|
+
if (!admissionMockActive) {
|
|
139
|
+
return realChannelAdmissionReaderModule.getChannelAdmissionPolicy(
|
|
140
|
+
channelType,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
if (mockAdmissionGate) await mockAdmissionGate;
|
|
144
|
+
return mockAdmissionPolicy;
|
|
145
|
+
},
|
|
146
|
+
}));
|
|
147
|
+
|
|
148
|
+
// Real floor semantics, mirroring relay-setup-router.test.ts. The
|
|
149
|
+
// enforceAdmissionPolicy mock omits the exempt-channel short-circuit so the
|
|
150
|
+
// deny path can be exercised end-to-end regardless of channel.
|
|
151
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
152
|
+
const realAdmissionPolicyModule = require("../runtime/routes/inbound-stages/admission-policy.js");
|
|
153
|
+
mock.module("../runtime/routes/inbound-stages/admission-policy.js", () => ({
|
|
154
|
+
...realAdmissionPolicyModule,
|
|
155
|
+
enforceAdmissionPolicy: (input: {
|
|
156
|
+
trustClass: string;
|
|
157
|
+
memberStatus: string | undefined;
|
|
158
|
+
policy: import("@vellumai/gateway-client").AdmissionPolicy;
|
|
159
|
+
}) => {
|
|
160
|
+
if (input.memberStatus === "blocked" || input.memberStatus === "revoked") {
|
|
161
|
+
return {
|
|
162
|
+
admitted: false,
|
|
163
|
+
reason:
|
|
164
|
+
input.memberStatus === "blocked" ? "member_blocked" : "member_revoked",
|
|
165
|
+
shouldChallenge: false,
|
|
166
|
+
effectivePolicy: input.policy,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const rank =
|
|
170
|
+
(TRUST_CLASS_RANK as Record<string, number>)[input.trustClass] ?? 0;
|
|
171
|
+
const floor = ADMISSION_FLOOR[input.policy];
|
|
172
|
+
if (rank >= floor) return { admitted: true };
|
|
173
|
+
return {
|
|
174
|
+
admitted: false,
|
|
175
|
+
reason: `admission_policy_${input.policy}`,
|
|
176
|
+
shouldChallenge: false,
|
|
177
|
+
effectivePolicy: input.policy,
|
|
178
|
+
};
|
|
179
|
+
},
|
|
180
|
+
}));
|
|
181
|
+
|
|
103
182
|
// ── TTS provider mocks (for call-speech-output) ─────────────────────
|
|
104
183
|
|
|
105
184
|
let mockTtsProviderId: string = "elevenlabs";
|
|
@@ -240,7 +319,15 @@ import { createGuardianBinding } from "./helpers/create-guardian-binding.js";
|
|
|
240
319
|
|
|
241
320
|
initializeDb();
|
|
242
321
|
|
|
322
|
+
// Activate the channel-admission-reader stub only while this file's tests run,
|
|
323
|
+
// so the registered (process-global) mock delegates to the real module for
|
|
324
|
+
// sibling files that load later in the same worker.
|
|
325
|
+
beforeAll(() => {
|
|
326
|
+
admissionMockActive = true;
|
|
327
|
+
});
|
|
328
|
+
|
|
243
329
|
afterAll(() => {
|
|
330
|
+
admissionMockActive = false;
|
|
244
331
|
resetDbForTesting();
|
|
245
332
|
});
|
|
246
333
|
|
|
@@ -404,6 +491,8 @@ describe("relay-server", () => {
|
|
|
404
491
|
activeRelayConnections.clear();
|
|
405
492
|
mockUserReference = "my human";
|
|
406
493
|
mockAssistantName = "Vellum";
|
|
494
|
+
mockAdmissionPolicy = null;
|
|
495
|
+
mockAdmissionGate = null;
|
|
407
496
|
mockSendMessage.mockImplementation(createMockProviderResponse(["Hello"]));
|
|
408
497
|
mockConfig.calls.verification.enabled = false;
|
|
409
498
|
mockConfig.calls.verification.maxAttempts = 3;
|
|
@@ -840,6 +929,121 @@ describe("relay-server", () => {
|
|
|
840
929
|
relay.destroy();
|
|
841
930
|
});
|
|
842
931
|
|
|
932
|
+
test("handleMessage: prompt arriving during setup (setting_up) is dropped", async () => {
|
|
933
|
+
ensureConversation("conv-relay-setting-up");
|
|
934
|
+
const session = createCallSession({
|
|
935
|
+
conversationId: "conv-relay-setting-up",
|
|
936
|
+
provider: "twilio",
|
|
937
|
+
fromNumber: "+15551111111",
|
|
938
|
+
toNumber: "+15552222222",
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
addTrustedVoiceContact("+15551111111");
|
|
942
|
+
|
|
943
|
+
const { ws, relay } = createMockWs(session.id);
|
|
944
|
+
|
|
945
|
+
// Hold the admission reader open so handleSetup stays in "setting_up".
|
|
946
|
+
let releaseGate: () => void = () => {};
|
|
947
|
+
mockAdmissionGate = new Promise<void>((resolve) => {
|
|
948
|
+
releaseGate = resolve;
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
// Fire setup without awaiting — it suspends inside getChannelAdmissionPolicy.
|
|
952
|
+
const setupPromise = relay.handleMessage(
|
|
953
|
+
JSON.stringify({
|
|
954
|
+
type: "setup",
|
|
955
|
+
callSid: "CA_setting_up_123",
|
|
956
|
+
from: "+15551111111",
|
|
957
|
+
to: "+15552222222",
|
|
958
|
+
}),
|
|
959
|
+
);
|
|
960
|
+
|
|
961
|
+
// Let the setup task reach the await; state must be "setting_up".
|
|
962
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
963
|
+
expect(relay.getConnectionState()).toBe("setting_up");
|
|
964
|
+
|
|
965
|
+
// A prompt arriving now must be dropped: no transcript, no fallback.
|
|
966
|
+
await relay.handleMessage(
|
|
967
|
+
JSON.stringify({
|
|
968
|
+
type: "prompt",
|
|
969
|
+
voicePrompt: "Wire me money",
|
|
970
|
+
lang: "en-US",
|
|
971
|
+
last: true,
|
|
972
|
+
}),
|
|
973
|
+
);
|
|
974
|
+
|
|
975
|
+
const textMessages = ws.sentMessages
|
|
976
|
+
.map((m) => JSON.parse(m))
|
|
977
|
+
.filter((m: { type: string }) => m.type === "text");
|
|
978
|
+
expect(
|
|
979
|
+
textMessages.some((m) => (m.token ?? "").includes("still setting up")),
|
|
980
|
+
).toBe(false);
|
|
981
|
+
expect(relay.getConversationHistory().length).toBe(0);
|
|
982
|
+
expect(
|
|
983
|
+
getMessages("conv-relay-setting-up").filter((m) => m.role === "user")
|
|
984
|
+
.length,
|
|
985
|
+
).toBe(0);
|
|
986
|
+
|
|
987
|
+
// Release the reader and let setup finish.
|
|
988
|
+
releaseGate();
|
|
989
|
+
await setupPromise;
|
|
990
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
991
|
+
expect(relay.getConnectionState()).toBe("connected");
|
|
992
|
+
|
|
993
|
+
relay.destroy();
|
|
994
|
+
});
|
|
995
|
+
|
|
996
|
+
test("handleMessage: prompt after normal-call setup completes is handled", async () => {
|
|
997
|
+
ensureConversation("conv-relay-postsetup");
|
|
998
|
+
const session = createCallSession({
|
|
999
|
+
conversationId: "conv-relay-postsetup",
|
|
1000
|
+
provider: "twilio",
|
|
1001
|
+
fromNumber: "+15551111111",
|
|
1002
|
+
toNumber: "+15552222222",
|
|
1003
|
+
});
|
|
1004
|
+
|
|
1005
|
+
addTrustedVoiceContact("+15551111111");
|
|
1006
|
+
mockSendMessage.mockImplementation(
|
|
1007
|
+
createMockProviderResponse(["Sure, happy to help."]),
|
|
1008
|
+
);
|
|
1009
|
+
|
|
1010
|
+
const { relay } = createMockWs(session.id);
|
|
1011
|
+
|
|
1012
|
+
await relay.handleMessage(
|
|
1013
|
+
JSON.stringify({
|
|
1014
|
+
type: "setup",
|
|
1015
|
+
callSid: "CA_postsetup_123",
|
|
1016
|
+
from: "+15551111111",
|
|
1017
|
+
to: "+15552222222",
|
|
1018
|
+
}),
|
|
1019
|
+
);
|
|
1020
|
+
|
|
1021
|
+
// Setup completed normally → "connected".
|
|
1022
|
+
expect(relay.getConnectionState()).toBe("connected");
|
|
1023
|
+
|
|
1024
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
1025
|
+
|
|
1026
|
+
// A subsequent prompt routes to the controller (no "still setting up").
|
|
1027
|
+
await relay.handleMessage(
|
|
1028
|
+
JSON.stringify({
|
|
1029
|
+
type: "prompt",
|
|
1030
|
+
voicePrompt: "Hello there",
|
|
1031
|
+
lang: "en-US",
|
|
1032
|
+
last: true,
|
|
1033
|
+
}),
|
|
1034
|
+
);
|
|
1035
|
+
|
|
1036
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
1037
|
+
|
|
1038
|
+
const userMessages = getMessages("conv-relay-postsetup").filter(
|
|
1039
|
+
(m) => m.role === "user",
|
|
1040
|
+
);
|
|
1041
|
+
expect(userMessages.length).toBeGreaterThan(0);
|
|
1042
|
+
expect(relay.getConnectionState()).toBe("connected");
|
|
1043
|
+
|
|
1044
|
+
relay.destroy();
|
|
1045
|
+
});
|
|
1046
|
+
|
|
843
1047
|
// ── Interrupt handling ──────────────────────────────────────────
|
|
844
1048
|
|
|
845
1049
|
test("handleMessage: interrupt message is handled without error", async () => {
|
|
@@ -2722,6 +2926,87 @@ describe("relay-server", () => {
|
|
|
2722
2926
|
relay.destroy();
|
|
2723
2927
|
});
|
|
2724
2928
|
|
|
2929
|
+
// ── Inbound admission floor (reader → routeSetup wiring) ───────────
|
|
2930
|
+
|
|
2931
|
+
test("admission floor: reader floor that excludes caller denies the call end-to-end", async () => {
|
|
2932
|
+
ensureConversation("conv-admission-floor-deny");
|
|
2933
|
+
const session = createCallSession({
|
|
2934
|
+
conversationId: "conv-admission-floor-deny",
|
|
2935
|
+
provider: "twilio",
|
|
2936
|
+
fromNumber: "+15557776666",
|
|
2937
|
+
toNumber: "+15551111111",
|
|
2938
|
+
});
|
|
2939
|
+
|
|
2940
|
+
// A trusted contact (rank 3) is below the `guardian_only` floor (rank 4).
|
|
2941
|
+
addTrustedVoiceContact("+15557776666");
|
|
2942
|
+
mockAdmissionPolicy = "guardian_only";
|
|
2943
|
+
|
|
2944
|
+
const { ws, relay } = createMockWs(session.id);
|
|
2945
|
+
|
|
2946
|
+
await relay.handleMessage(
|
|
2947
|
+
JSON.stringify({
|
|
2948
|
+
type: "setup",
|
|
2949
|
+
callSid: "CA_admission_floor_deny",
|
|
2950
|
+
from: "+15557776666",
|
|
2951
|
+
to: "+15551111111",
|
|
2952
|
+
}),
|
|
2953
|
+
);
|
|
2954
|
+
|
|
2955
|
+
// Floor-excluded caller takes the deny path.
|
|
2956
|
+
expect(relay.getConnectionState()).toBe("disconnecting");
|
|
2957
|
+
|
|
2958
|
+
const updated = getCallSession(session.id);
|
|
2959
|
+
expect(updated).not.toBeNull();
|
|
2960
|
+
expect(updated!.status).toBe("failed");
|
|
2961
|
+
|
|
2962
|
+
const textMessages = ws.sentMessages
|
|
2963
|
+
.map((raw) => JSON.parse(raw) as { type: string; token?: string })
|
|
2964
|
+
.filter((m) => m.type === "text");
|
|
2965
|
+
expect(
|
|
2966
|
+
textMessages.some((m) => (m.token ?? "").includes("not authorized")),
|
|
2967
|
+
).toBe(true);
|
|
2968
|
+
|
|
2969
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
2970
|
+
|
|
2971
|
+
relay.destroy();
|
|
2972
|
+
});
|
|
2973
|
+
|
|
2974
|
+
test("admission floor: null policy from reader leaves the call flow unchanged", async () => {
|
|
2975
|
+
ensureConversation("conv-admission-floor-null");
|
|
2976
|
+
const session = createCallSession({
|
|
2977
|
+
conversationId: "conv-admission-floor-null",
|
|
2978
|
+
provider: "twilio",
|
|
2979
|
+
fromNumber: "+15557776666",
|
|
2980
|
+
toNumber: "+15551111111",
|
|
2981
|
+
});
|
|
2982
|
+
|
|
2983
|
+
addTrustedVoiceContact("+15557776666");
|
|
2984
|
+
mockAdmissionPolicy = null; // no floor supplied
|
|
2985
|
+
|
|
2986
|
+
mockSendMessage.mockImplementation(
|
|
2987
|
+
createMockProviderResponse(["Hello, how can I help you?"]),
|
|
2988
|
+
);
|
|
2989
|
+
|
|
2990
|
+
const { relay } = createMockWs(session.id);
|
|
2991
|
+
|
|
2992
|
+
await relay.handleMessage(
|
|
2993
|
+
JSON.stringify({
|
|
2994
|
+
type: "setup",
|
|
2995
|
+
callSid: "CA_admission_floor_null",
|
|
2996
|
+
from: "+15557776666",
|
|
2997
|
+
to: "+15551111111",
|
|
2998
|
+
}),
|
|
2999
|
+
);
|
|
3000
|
+
|
|
3001
|
+
// Trusted contact proceeds normally — no deny.
|
|
3002
|
+
expect(relay.getConnectionState()).toBe("connected");
|
|
3003
|
+
|
|
3004
|
+
const updated = getCallSession(session.id);
|
|
3005
|
+
expect(updated!.status).toBe("in_progress");
|
|
3006
|
+
|
|
3007
|
+
relay.destroy();
|
|
3008
|
+
});
|
|
3009
|
+
|
|
2725
3010
|
test("name capture flow: access request creates canonical request for guardian", async () => {
|
|
2726
3011
|
ensureConversation("conv-access-req-canonical");
|
|
2727
3012
|
const session = createCallSession({
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
// These tests exercise the PATCH-side `workflowName` validation
|
|
4
|
-
// runs once the `workflows` feature flag is ON (the flag gate short-circuits
|
|
5
|
-
// first when it is off). Mock the flag resolver to ON so the validation path is
|
|
6
|
-
// reachable; the sibling schedule-routes.test.ts keeps the flag OFF and asserts
|
|
7
|
-
// the flag-gate behavior, so the two files do not conflict.
|
|
3
|
+
// These tests exercise the PATCH-side `workflowName` validation.
|
|
8
4
|
mock.module("../util/logger.js", () => ({
|
|
9
5
|
getLogger: () =>
|
|
10
6
|
new Proxy({} as Record<string, unknown>, {
|
|
@@ -12,11 +8,6 @@ mock.module("../util/logger.js", () => ({
|
|
|
12
8
|
}),
|
|
13
9
|
}));
|
|
14
10
|
|
|
15
|
-
mock.module("../config/assistant-feature-flags.js", () => ({
|
|
16
|
-
isAssistantFeatureFlagEnabled: (key: string) => key === "workflows",
|
|
17
|
-
getAssistantFeatureFlagValue: (key: string) => key === "workflows",
|
|
18
|
-
}));
|
|
19
|
-
|
|
20
11
|
mock.module("../config/loader.js", () => ({
|
|
21
12
|
getConfig: () => ({}),
|
|
22
13
|
invalidateConfigCache: () => {},
|
|
@@ -1243,36 +1243,6 @@ describe("POST /schedules — create", () => {
|
|
|
1243
1243
|
).toThrow("Only 'execute' and 'workflow' modes are supported");
|
|
1244
1244
|
});
|
|
1245
1245
|
|
|
1246
|
-
test("rejects workflow-mode creation when the workflows flag is off", () => {
|
|
1247
|
-
// The mocked getConfig returns no feature flags, so `workflows` is off.
|
|
1248
|
-
expect(() =>
|
|
1249
|
-
postCreate({
|
|
1250
|
-
name: "Triage",
|
|
1251
|
-
description: "Triage the inbox every morning",
|
|
1252
|
-
expression: "0 9 * * *",
|
|
1253
|
-
message: "triage inbox",
|
|
1254
|
-
mode: "workflow",
|
|
1255
|
-
workflowName: "triage-inbox",
|
|
1256
|
-
}),
|
|
1257
|
-
).toThrow("Workflows are not enabled");
|
|
1258
|
-
});
|
|
1259
|
-
|
|
1260
|
-
test("rejects PATCH switching to workflow mode when the flag is off", () => {
|
|
1261
|
-
const schedule = createSchedule({
|
|
1262
|
-
name: "Plain execute",
|
|
1263
|
-
cronExpression: "0 9 * * *",
|
|
1264
|
-
message: "hi",
|
|
1265
|
-
syntax: "cron",
|
|
1266
|
-
});
|
|
1267
|
-
const patch = findRoute("schedules/:id", "PATCH");
|
|
1268
|
-
expect(() =>
|
|
1269
|
-
patch.handler({
|
|
1270
|
-
pathParams: { id: schedule.id },
|
|
1271
|
-
body: { mode: "workflow", workflowName: "triage-inbox" },
|
|
1272
|
-
}),
|
|
1273
|
-
).toThrow("Workflows are not enabled");
|
|
1274
|
-
});
|
|
1275
|
-
|
|
1276
1246
|
test("rejects an unparseable expression", () => {
|
|
1277
1247
|
expect(() =>
|
|
1278
1248
|
postCreate({
|