@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
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
recordCallEvent,
|
|
51
51
|
updateCallSession,
|
|
52
52
|
} from "./call-store.js";
|
|
53
|
+
import { getChannelAdmissionPolicy } from "./channel-admission-reader.js";
|
|
53
54
|
import { finalizeCall } from "./finalize-call.js";
|
|
54
55
|
import { MediaStreamOutput } from "./media-stream-output.js";
|
|
55
56
|
import { parseMediaStreamFrame } from "./media-stream-parser.js";
|
|
@@ -90,6 +91,18 @@ export class MediaStreamCallSession {
|
|
|
90
91
|
private streamSid: string | null = null;
|
|
91
92
|
private callSid: string | null = null;
|
|
92
93
|
private disposed = false;
|
|
94
|
+
// True from the synchronous start of handleStart until setup routing
|
|
95
|
+
// completes. Resolving the admission floor yields the event loop, so
|
|
96
|
+
// transcripts/barge-in arriving in this window are ignored — a denied or
|
|
97
|
+
// not-yet-authorized caller's speech is never persisted before the floor
|
|
98
|
+
// and trust ACL are applied. The controller-existence checks below also
|
|
99
|
+
// gate persistence, but this guard makes the intent explicit and covers
|
|
100
|
+
// the brief async window before the controller is created.
|
|
101
|
+
private setupRouting = false;
|
|
102
|
+
// Resolves when the async setup routing kicked off by the `start` frame
|
|
103
|
+
// settles. Exposed via whenSetupSettled() for deterministic test awaiting,
|
|
104
|
+
// since handleStart now yields on the admission-policy read.
|
|
105
|
+
private setupSettled: Promise<void> = Promise.resolve();
|
|
93
106
|
|
|
94
107
|
// ── Operational diagnostics counters ──────────────────────────────
|
|
95
108
|
/** Number of barge-in attempts that were accepted (assistant was speaking). */
|
|
@@ -141,6 +154,14 @@ export class MediaStreamCallSession {
|
|
|
141
154
|
return this.controller;
|
|
142
155
|
}
|
|
143
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Resolves once the async setup routing started by the `start` frame has
|
|
159
|
+
* settled. Test-only convenience — production code does not await this.
|
|
160
|
+
*/
|
|
161
|
+
whenSetupSettled(): Promise<void> {
|
|
162
|
+
return this.setupSettled;
|
|
163
|
+
}
|
|
164
|
+
|
|
144
165
|
/**
|
|
145
166
|
* Feed a raw WebSocket message into the session.
|
|
146
167
|
*
|
|
@@ -154,7 +175,16 @@ export class MediaStreamCallSession {
|
|
|
154
175
|
// Intercept `start` to bootstrap the session before forwarding.
|
|
155
176
|
const parseResult = parseMediaStreamFrame(raw);
|
|
156
177
|
if (parseResult.ok && parseResult.event.event === "start") {
|
|
157
|
-
|
|
178
|
+
// handleStart resolves the admission floor asynchronously; the
|
|
179
|
+
// setupRouting guard set synchronously at its top ensures inbound
|
|
180
|
+
// frames forwarded below are ignored until routing completes.
|
|
181
|
+
this.setupSettled = this.handleStart(parseResult.event).catch((err) => {
|
|
182
|
+
log.error(
|
|
183
|
+
{ err, callSessionId: this.callSessionId },
|
|
184
|
+
"Media-stream setup routing failed",
|
|
185
|
+
);
|
|
186
|
+
this.setupRouting = false;
|
|
187
|
+
});
|
|
158
188
|
}
|
|
159
189
|
|
|
160
190
|
// Always forward to the STT session (it handles all event types).
|
|
@@ -296,7 +326,12 @@ export class MediaStreamCallSession {
|
|
|
296
326
|
|
|
297
327
|
// ── Internal: media-stream event handlers ─────────────────────────
|
|
298
328
|
|
|
299
|
-
private handleStart(event: MediaStreamStartEvent): void {
|
|
329
|
+
private async handleStart(event: MediaStreamStartEvent): Promise<void> {
|
|
330
|
+
// Enter the setup-pending window synchronously, before any await. The
|
|
331
|
+
// admission-policy read below yields the event loop, so frames forwarded
|
|
332
|
+
// to the STT session can produce transcripts/barge-in before routing
|
|
333
|
+
// completes — those are dropped while setupRouting is true.
|
|
334
|
+
this.setupRouting = true;
|
|
300
335
|
this.streamSid = event.streamSid;
|
|
301
336
|
this.callSid = event.start.callSid;
|
|
302
337
|
|
|
@@ -337,12 +372,32 @@ export class MediaStreamCallSession {
|
|
|
337
372
|
const from = session?.fromNumber ?? "";
|
|
338
373
|
const to = session?.toNumber ?? "";
|
|
339
374
|
|
|
375
|
+
// Resolve the phone channel's inbound admission floor so the trust floor
|
|
376
|
+
// (e.g. guardian_only) is enforced on this transport too — not just the
|
|
377
|
+
// gateway webhook's no_one kill switch. The reader fails open to `null`
|
|
378
|
+
// by contract, so a transport hiccup admits the caller.
|
|
379
|
+
const admissionPolicy = await getChannelAdmissionPolicy("phone");
|
|
380
|
+
|
|
381
|
+
// The admission-policy read above yields the event loop; if Twilio closed
|
|
382
|
+
// the WebSocket meanwhile, the close handler will have called destroy().
|
|
383
|
+
// Abort setup so we don't create a controller or speak on a disposed
|
|
384
|
+
// session.
|
|
385
|
+
if (this.disposed) {
|
|
386
|
+
log.info(
|
|
387
|
+
{ callSessionId: this.callSessionId },
|
|
388
|
+
"Media-stream session disposed during admission read — aborting setup",
|
|
389
|
+
);
|
|
390
|
+
this.setupRouting = false;
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
|
|
340
394
|
const { outcome, resolved } = routeSetup({
|
|
341
395
|
callSessionId: this.callSessionId,
|
|
342
396
|
session: session ?? null,
|
|
343
397
|
from,
|
|
344
398
|
to,
|
|
345
399
|
customParameters: event.start.customParameters,
|
|
400
|
+
admissionPolicy,
|
|
346
401
|
});
|
|
347
402
|
|
|
348
403
|
log.info(
|
|
@@ -377,6 +432,10 @@ export class MediaStreamCallSession {
|
|
|
377
432
|
);
|
|
378
433
|
registerCallController(this.callSessionId, this.controller);
|
|
379
434
|
|
|
435
|
+
// Routing/ACL cleared — leave the setup-pending window so subsequent
|
|
436
|
+
// transcripts and barge-in are handled normally.
|
|
437
|
+
this.setupRouting = false;
|
|
438
|
+
|
|
380
439
|
// Fire the initial greeting.
|
|
381
440
|
this.controller.startInitialGreeting().catch((err) => {
|
|
382
441
|
log.error(
|
|
@@ -525,6 +584,18 @@ export class MediaStreamCallSession {
|
|
|
525
584
|
|
|
526
585
|
private handleTranscriptFinal(text: string, _durationMs: number): void {
|
|
527
586
|
if (!text.trim()) return;
|
|
587
|
+
|
|
588
|
+
// Drop transcripts arriving while setup routing is still pending so a
|
|
589
|
+
// not-yet-authorized / floor-denied caller's speech is never persisted
|
|
590
|
+
// before the admission floor and trust ACL are applied.
|
|
591
|
+
if (this.setupRouting) {
|
|
592
|
+
log.debug(
|
|
593
|
+
{ callSessionId: this.callSessionId },
|
|
594
|
+
"Transcript received during setup routing — dropping",
|
|
595
|
+
);
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
|
|
528
599
|
this.transcriptFinalsProduced++;
|
|
529
600
|
|
|
530
601
|
if (!this.controller) {
|
|
@@ -560,6 +631,17 @@ export class MediaStreamCallSession {
|
|
|
560
631
|
}
|
|
561
632
|
|
|
562
633
|
private handleDtmf(digit: string): void {
|
|
634
|
+
// Drop DTMF arriving while setup routing is still pending so a
|
|
635
|
+
// not-yet-authorized / floor-denied caller's digit is never persisted
|
|
636
|
+
// before the admission floor and trust ACL are applied.
|
|
637
|
+
if (this.setupRouting) {
|
|
638
|
+
log.debug(
|
|
639
|
+
{ callSessionId: this.callSessionId, digit },
|
|
640
|
+
"DTMF received during setup routing — dropping",
|
|
641
|
+
);
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
|
|
563
645
|
log.info(
|
|
564
646
|
{ callSessionId: this.callSessionId, digit },
|
|
565
647
|
"DTMF digit received on media-stream",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { randomInt } from "node:crypto";
|
|
10
10
|
|
|
11
|
+
import type { AdmissionPolicy } from "@vellumai/gateway-client";
|
|
11
12
|
import type { ServerWebSocket } from "bun";
|
|
12
13
|
|
|
13
14
|
import {
|
|
@@ -47,6 +48,7 @@ import {
|
|
|
47
48
|
updateCallSession,
|
|
48
49
|
} from "./call-store.js";
|
|
49
50
|
import { ConversationRelayTransport } from "./call-transport.js";
|
|
51
|
+
import { getChannelAdmissionPolicy } from "./channel-admission-reader.js";
|
|
50
52
|
import { finalizeCall } from "./finalize-call.js";
|
|
51
53
|
import {
|
|
52
54
|
classifyWaitUtterance,
|
|
@@ -170,6 +172,11 @@ export function setRelayBroadcast(fn: (msg: ServerMessage) => void): void {
|
|
|
170
172
|
*/
|
|
171
173
|
type RelayConnectionState =
|
|
172
174
|
| "connected"
|
|
175
|
+
// Transient state held synchronously from the start of handleSetup until
|
|
176
|
+
// routing/ACL completes. Prompts arriving in this window are dropped so a
|
|
177
|
+
// not-yet-authorized caller's speech is never persisted/emitted before the
|
|
178
|
+
// admission floor and trust ACL are applied.
|
|
179
|
+
| "setting_up"
|
|
173
180
|
| "verification_pending"
|
|
174
181
|
| "awaiting_name"
|
|
175
182
|
| "awaiting_guardian_decision"
|
|
@@ -550,15 +557,58 @@ export class RelayConnection {
|
|
|
550
557
|
"ConversationRelay setup received",
|
|
551
558
|
);
|
|
552
559
|
|
|
560
|
+
// Enter the setup-pending state synchronously, before any await. The
|
|
561
|
+
// admission-policy read below yields the event loop, and inbound frames are
|
|
562
|
+
// dispatched fire-and-forget, so a `prompt` frame can arrive before routing
|
|
563
|
+
// completes. handlePrompt drops prompts while in "setting_up" so a blocked
|
|
564
|
+
// or admission-denied caller's speech is never stored before the ACL runs.
|
|
565
|
+
this.connectionState = "setting_up";
|
|
566
|
+
|
|
553
567
|
const session = getCallSession(this.callSessionId);
|
|
554
568
|
this.recordSetupBookkeeping(session, msg);
|
|
555
569
|
|
|
570
|
+
// Resolve the phone channel's inbound admission floor. The reader fails
|
|
571
|
+
// open to `null` by contract, so a transport hiccup admits the caller.
|
|
572
|
+
const admissionPolicy = await getChannelAdmissionPolicy("phone");
|
|
573
|
+
|
|
574
|
+
try {
|
|
575
|
+
await this.routeSetupOutcome(msg, session, admissionPolicy);
|
|
576
|
+
} catch (err) {
|
|
577
|
+
// Never leave the connection stranded in "setting_up": a setup that
|
|
578
|
+
// throws before reaching a terminal outcome would otherwise drop every
|
|
579
|
+
// prompt forever. Tear the call down instead.
|
|
580
|
+
log.error(
|
|
581
|
+
{ err, callSessionId: this.callSessionId },
|
|
582
|
+
"Setup routing failed — disconnecting",
|
|
583
|
+
);
|
|
584
|
+
this.connectionState = "disconnecting";
|
|
585
|
+
updateCallSession(this.callSessionId, {
|
|
586
|
+
status: "failed",
|
|
587
|
+
endedAt: Date.now(),
|
|
588
|
+
lastError: "Setup routing failed",
|
|
589
|
+
});
|
|
590
|
+
this.endSession("Setup routing failed");
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Apply the routing/ACL outcome for a setup frame. Synchronous helpers that
|
|
596
|
+
* fire-and-forget (greeting, verification, name capture) are awaited here only
|
|
597
|
+
* when they themselves are async. Each reachable outcome transitions the
|
|
598
|
+
* connection out of "setting_up" into its terminal state.
|
|
599
|
+
*/
|
|
600
|
+
private async routeSetupOutcome(
|
|
601
|
+
msg: RelaySetupMessage,
|
|
602
|
+
session: ReturnType<typeof getCallSession>,
|
|
603
|
+
admissionPolicy: AdmissionPolicy | null,
|
|
604
|
+
): Promise<void> {
|
|
556
605
|
const { outcome, resolved } = routeSetup({
|
|
557
606
|
callSessionId: this.callSessionId,
|
|
558
607
|
session,
|
|
559
608
|
from: msg.from,
|
|
560
609
|
to: msg.to,
|
|
561
610
|
customParameters: msg.customParameters,
|
|
611
|
+
admissionPolicy,
|
|
562
612
|
});
|
|
563
613
|
|
|
564
614
|
const initialTrustContext = toTrustContext(
|
|
@@ -634,6 +684,9 @@ export class RelayConnection {
|
|
|
634
684
|
);
|
|
635
685
|
}
|
|
636
686
|
}
|
|
687
|
+
// Routing/ACL cleared — leave the setup-pending state so subsequent
|
|
688
|
+
// prompts are handled normally.
|
|
689
|
+
this.connectionState = "connected";
|
|
637
690
|
this.startNormalCallFlow(controller, outcome.isInbound);
|
|
638
691
|
return;
|
|
639
692
|
}
|
|
@@ -1822,6 +1875,13 @@ export class RelayConnection {
|
|
|
1822
1875
|
return;
|
|
1823
1876
|
}
|
|
1824
1877
|
|
|
1878
|
+
// Prompts arriving before setup routing/ACL completes are dropped — never
|
|
1879
|
+
// persisted or emitted — so a not-yet-authorized caller's speech can't be
|
|
1880
|
+
// stored ahead of the admission floor / trust ACL decision.
|
|
1881
|
+
if (this.connectionState === "setting_up") {
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1825
1885
|
if (!msg.last) {
|
|
1826
1886
|
// Partial transcript, wait for final
|
|
1827
1887
|
return;
|
|
@@ -2024,6 +2084,12 @@ export class RelayConnection {
|
|
|
2024
2084
|
return;
|
|
2025
2085
|
}
|
|
2026
2086
|
|
|
2087
|
+
// Drop DTMF arriving before setup routing/ACL completes (same reasoning as
|
|
2088
|
+
// handlePrompt): don't record input from a not-yet-authorized caller.
|
|
2089
|
+
if (this.connectionState === "setting_up") {
|
|
2090
|
+
return;
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2027
2093
|
// Ignore DTMF during name capture and guardian decision wait
|
|
2028
2094
|
if (
|
|
2029
2095
|
this.connectionState === "awaiting_name" ||
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* next — without performing any side effects itself.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import type { AdmissionPolicy } from "@vellumai/gateway-client";
|
|
10
|
+
|
|
9
11
|
import { getConfig } from "../config/loader.js";
|
|
10
12
|
import { findActiveVoiceInvites } from "../memory/invite-store.js";
|
|
11
13
|
import {
|
|
@@ -14,6 +16,10 @@ import {
|
|
|
14
16
|
} from "../runtime/actor-trust-resolver.js";
|
|
15
17
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
16
18
|
import { getPendingSession } from "../runtime/channel-verification-service.js";
|
|
19
|
+
import {
|
|
20
|
+
type AdmissionPolicyResult,
|
|
21
|
+
enforceAdmissionPolicy,
|
|
22
|
+
} from "../runtime/routes/inbound-stages/admission-policy.js";
|
|
17
23
|
import { getLogger } from "../util/logger.js";
|
|
18
24
|
import type { CallSession } from "./types.js";
|
|
19
25
|
|
|
@@ -27,6 +33,12 @@ interface SetupContext {
|
|
|
27
33
|
from: string;
|
|
28
34
|
to: string;
|
|
29
35
|
customParameters?: Record<string, string>;
|
|
36
|
+
/**
|
|
37
|
+
* Per-channel inbound admission floor for the `phone` channel, supplied by
|
|
38
|
+
* the caller. When absent/`null`, the floor check is skipped entirely —
|
|
39
|
+
* preserving all pre-admission behavior.
|
|
40
|
+
*/
|
|
41
|
+
admissionPolicy?: AdmissionPolicy | null;
|
|
30
42
|
}
|
|
31
43
|
|
|
32
44
|
// ── Setup outcomes ───────────────────────────────────────────────────
|
|
@@ -184,7 +196,55 @@ export function routeSetup(ctx: SetupContext): {
|
|
|
184
196
|
// ── Inbound call ACL evaluation ─────────────────────────────────
|
|
185
197
|
const pendingChallenge = getPendingSession("phone");
|
|
186
198
|
|
|
187
|
-
|
|
199
|
+
// An admission floor is "active" only when a policy applies and no pending
|
|
200
|
+
// verification challenge is in flight. While active, the floor IS the access
|
|
201
|
+
// decision: an admitted caller bypasses the legacy identity flows
|
|
202
|
+
// (unverified_caller / name_capture) and connects directly. When inactive
|
|
203
|
+
// (null policy, flag off, exempt channel, reader failed open, or a pending
|
|
204
|
+
// challenge), those legacy flows are preserved unchanged.
|
|
205
|
+
const floorActive = ctx.admissionPolicy != null && !pendingChallenge;
|
|
206
|
+
|
|
207
|
+
// Inbound admission floor verdict; defaults to admitted when inactive.
|
|
208
|
+
const floorVerdict = floorActive
|
|
209
|
+
? enforceAdmissionPolicy({
|
|
210
|
+
sourceChannel: "phone",
|
|
211
|
+
trustClass: actorTrust.trustClass,
|
|
212
|
+
memberStatus: actorTrust.memberRecord?.channel.status,
|
|
213
|
+
policy: ctx.admissionPolicy!,
|
|
214
|
+
})
|
|
215
|
+
: ({ admitted: true } as const);
|
|
216
|
+
|
|
217
|
+
// Floor-deny outcome shared by the unknown-caller and member-caller branches.
|
|
218
|
+
// Live calls cannot await async re-verification, so the floor's
|
|
219
|
+
// `shouldChallenge` upgrade UX is not surfaced — same rationale as `escalate`.
|
|
220
|
+
const floorDeny = (
|
|
221
|
+
denyVerdict: Extract<AdmissionPolicyResult, { admitted: false }>,
|
|
222
|
+
) => {
|
|
223
|
+
log.info(
|
|
224
|
+
{
|
|
225
|
+
callSessionId: ctx.callSessionId,
|
|
226
|
+
from: ctx.from,
|
|
227
|
+
trustClass: actorTrust.trustClass,
|
|
228
|
+
effectivePolicy: denyVerdict.effectivePolicy,
|
|
229
|
+
},
|
|
230
|
+
"Inbound voice ACL: admission floor denied caller",
|
|
231
|
+
);
|
|
232
|
+
return {
|
|
233
|
+
outcome: {
|
|
234
|
+
action: "deny" as const,
|
|
235
|
+
message:
|
|
236
|
+
"This number is not authorized to reach the assistant right now.",
|
|
237
|
+
logReason: `Inbound voice admission floor: ${denyVerdict.effectivePolicy}`,
|
|
238
|
+
},
|
|
239
|
+
resolved,
|
|
240
|
+
};
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
if (
|
|
244
|
+
(actorTrust.trustClass === "unknown" ||
|
|
245
|
+
actorTrust.trustClass === "unverified_contact") &&
|
|
246
|
+
!pendingChallenge
|
|
247
|
+
) {
|
|
188
248
|
// Check for blocked caller
|
|
189
249
|
if (actorTrust.memberRecord?.channel.status === "blocked") {
|
|
190
250
|
log.info(
|
|
@@ -241,6 +301,21 @@ export function routeSetup(ctx: SetupContext): {
|
|
|
241
301
|
};
|
|
242
302
|
}
|
|
243
303
|
|
|
304
|
+
// When a floor is active it is the access decision: an admitted caller
|
|
305
|
+
// connects directly (skipping unverified_caller / name_capture), and a
|
|
306
|
+
// below-floor caller is denied. Invites (handled above) bypass the floor
|
|
307
|
+
// as an explicit grant. When the floor is inactive (null policy), fall
|
|
308
|
+
// through to the legacy identity flows below.
|
|
309
|
+
if (floorActive) {
|
|
310
|
+
if (!floorVerdict.admitted) {
|
|
311
|
+
return floorDeny(floorVerdict);
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
outcome: { action: "normal_call" as const, isInbound: true },
|
|
315
|
+
resolved,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
244
319
|
// Known caller whose channel hasn't passed verification yet —
|
|
245
320
|
// mirrors the gateway's pre-intercept (twilio-voice-webhook.ts) so
|
|
246
321
|
// calls slipping past it (e.g. canonicalization mismatch between
|
|
@@ -345,6 +420,12 @@ export function routeSetup(ctx: SetupContext): {
|
|
|
345
420
|
};
|
|
346
421
|
}
|
|
347
422
|
|
|
423
|
+
// Admission floor: deny member/guardian callers below the floor (e.g.
|
|
424
|
+
// `guardian_only` denies a trusted_contact).
|
|
425
|
+
if (!floorVerdict.admitted) {
|
|
426
|
+
return floorDeny(floorVerdict);
|
|
427
|
+
}
|
|
428
|
+
|
|
348
429
|
// Guardian and trusted-contact callers proceed normally
|
|
349
430
|
return {
|
|
350
431
|
outcome: { action: "normal_call", isInbound: true },
|
|
@@ -54,6 +54,7 @@ import {
|
|
|
54
54
|
releaseCallbackClaim,
|
|
55
55
|
updateCallSession,
|
|
56
56
|
} from "./call-store.js";
|
|
57
|
+
import { getChannelAdmissionPolicy } from "./channel-admission-reader.js";
|
|
57
58
|
import { routeSetup } from "./relay-setup-router.js";
|
|
58
59
|
import { resolveCallHints } from "./stt-hints.js";
|
|
59
60
|
import { resolveTelephonySttRouting } from "./telephony-stt-routing.js";
|
|
@@ -277,10 +278,10 @@ const TWIML_HEADERS = { "Content-Type": "text/xml" } as const;
|
|
|
277
278
|
* query for outbound calls). Returns a TwiML string. Throws RouteError
|
|
278
279
|
* subclasses on failure.
|
|
279
280
|
*/
|
|
280
|
-
function processVoiceWebhook(
|
|
281
|
+
async function processVoiceWebhook(
|
|
281
282
|
params: Record<string, string>,
|
|
282
283
|
callSessionId: string | null,
|
|
283
|
-
): string {
|
|
284
|
+
): Promise<string> {
|
|
284
285
|
const callSid = params.CallSid ?? null;
|
|
285
286
|
const callerFrom = params.From ?? "";
|
|
286
287
|
const callerTo = params.To ?? "";
|
|
@@ -371,7 +372,7 @@ export async function handleVoiceWebhook(req: Request): Promise<Response> {
|
|
|
371
372
|
const params = Object.fromEntries(formBody.entries());
|
|
372
373
|
|
|
373
374
|
try {
|
|
374
|
-
return twimlResponse(processVoiceWebhook(params, callSessionId));
|
|
375
|
+
return twimlResponse(await processVoiceWebhook(params, callSessionId));
|
|
375
376
|
} catch (err) {
|
|
376
377
|
if (err instanceof RouteError) {
|
|
377
378
|
return new Response(err.message, { status: err.statusCode });
|
|
@@ -399,7 +400,7 @@ export async function handleVoiceWebhook(req: Request): Promise<Response> {
|
|
|
399
400
|
* the Twilio setup payload. The persisted call session mode is the
|
|
400
401
|
* primary signal for deterministic flow selection in the relay server.
|
|
401
402
|
*/
|
|
402
|
-
function buildVoiceWebhookTwiml(
|
|
403
|
+
async function buildVoiceWebhookTwiml(
|
|
403
404
|
callSessionId: string,
|
|
404
405
|
sessionContext: {
|
|
405
406
|
task: string | null;
|
|
@@ -410,7 +411,7 @@ function buildVoiceWebhookTwiml(
|
|
|
410
411
|
inviteGuardianName: string | null;
|
|
411
412
|
} | null,
|
|
412
413
|
verificationSessionId?: string | null,
|
|
413
|
-
): string {
|
|
414
|
+
): Promise<string> {
|
|
414
415
|
const cfg = loadConfig();
|
|
415
416
|
const profile = resolveVoiceQualityProfile(cfg);
|
|
416
417
|
|
|
@@ -476,11 +477,19 @@ function buildVoiceWebhookTwiml(
|
|
|
476
477
|
const from = sessionContext?.fromNumber ?? "";
|
|
477
478
|
const to = sessionContext?.toNumber ?? "";
|
|
478
479
|
|
|
480
|
+
// Resolve the phone channel's inbound admission floor so this preflight
|
|
481
|
+
// classification matches the real enforcement at stream start — a
|
|
482
|
+
// floor-denied caller is recognized as `deny` here, not `normal_call`.
|
|
483
|
+
// The reader fails open to `null` by contract, so a transport hiccup
|
|
484
|
+
// admits the caller.
|
|
485
|
+
const admissionPolicy = await getChannelAdmissionPolicy("phone");
|
|
486
|
+
|
|
479
487
|
const { outcome } = routeSetup({
|
|
480
488
|
callSessionId,
|
|
481
489
|
session: session ?? null,
|
|
482
490
|
from,
|
|
483
491
|
to,
|
|
492
|
+
admissionPolicy,
|
|
484
493
|
});
|
|
485
494
|
|
|
486
495
|
// The media-stream transport supports normal_call and deny (which speaks
|
|
@@ -780,9 +789,9 @@ const EMPTY_TWIML = '<?xml version="1.0" encoding="UTF-8"?><Response/>';
|
|
|
780
789
|
* Internal voice-webhook handler for gateway→runtime forwarding.
|
|
781
790
|
* Accepts JSON body `{ params, originalUrl? }` from the gateway.
|
|
782
791
|
*/
|
|
783
|
-
export function handleInternalVoiceWebhook({
|
|
792
|
+
export async function handleInternalVoiceWebhook({
|
|
784
793
|
body = {},
|
|
785
|
-
}: RouteHandlerArgs): RouteResponse {
|
|
794
|
+
}: RouteHandlerArgs): Promise<RouteResponse> {
|
|
786
795
|
const { params = {}, originalUrl } = body as {
|
|
787
796
|
params?: Record<string, string>;
|
|
788
797
|
originalUrl?: string;
|
|
@@ -798,7 +807,7 @@ export function handleInternalVoiceWebhook({
|
|
|
798
807
|
}
|
|
799
808
|
}
|
|
800
809
|
|
|
801
|
-
const twiml = processVoiceWebhook(params, callSessionId);
|
|
810
|
+
const twiml = await processVoiceWebhook(params, callSessionId);
|
|
802
811
|
return new RouteResponse(twiml, TWIML_HEADERS);
|
|
803
812
|
}
|
|
804
813
|
|
|
@@ -553,8 +553,8 @@ export async function startVoiceTurn(
|
|
|
553
553
|
} else if (msg.type === "secret_request") {
|
|
554
554
|
if (usesLocalInteractiveApprovals) {
|
|
555
555
|
// Local live voice runs alongside the desktop client, which has a
|
|
556
|
-
// secret-entry UI
|
|
557
|
-
//
|
|
556
|
+
// secret-entry UI. Forward the broadcast and let the prompter's
|
|
557
|
+
// existing registration handle the response.
|
|
558
558
|
broadcastMessage(msg);
|
|
559
559
|
return;
|
|
560
560
|
}
|
|
@@ -13,6 +13,7 @@ interface ClientEntryJSON {
|
|
|
13
13
|
machineName?: string;
|
|
14
14
|
connectedAt: string;
|
|
15
15
|
lastActiveAt: string;
|
|
16
|
+
degraded?: boolean;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
interface ListClientsResponse {
|
|
@@ -111,6 +112,7 @@ Examples:
|
|
|
111
112
|
"LABEL",
|
|
112
113
|
"CONNECTED",
|
|
113
114
|
"LAST ACTIVE",
|
|
115
|
+
"STATUS",
|
|
114
116
|
];
|
|
115
117
|
const rows: string[][] = entries.map((e: ClientEntryJSON) => [
|
|
116
118
|
e.clientId,
|
|
@@ -119,6 +121,7 @@ Examples:
|
|
|
119
121
|
e.machineName ?? "—",
|
|
120
122
|
formatRelativeTime(e.connectedAt),
|
|
121
123
|
formatRelativeTime(e.lastActiveAt),
|
|
124
|
+
e.degraded ? "degraded" : "—",
|
|
122
125
|
]);
|
|
123
126
|
|
|
124
127
|
// Calculate column widths
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import type { ComparisonReport } from "
|
|
3
|
+
import type { ComparisonReport } from "../../../../memory/v2/harness/runner.js";
|
|
4
4
|
import {
|
|
5
5
|
renderComparisonReport,
|
|
6
6
|
renderTurnTrace,
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Validates:
|
|
5
5
|
* - Subcommand registration (reembed, reembed-skills, activation, validate,
|
|
6
|
-
* ema, simulate) under `memory v2`.
|
|
7
|
-
*
|
|
6
|
+
* ema, simulate) under `memory v2`. v1 had its own subcommands but those
|
|
7
|
+
* were retired.
|
|
8
8
|
* - Each mutating subcommand maps to the right `memory_v2_backfill` op.
|
|
9
9
|
* - `validate` calls `memory_v2_validate` and pretty-prints the report.
|
|
10
10
|
* - `reembed-skills` calls `memory_v2_reembed_skills` synchronously.
|
|
@@ -40,7 +40,7 @@ let logOutput: string[] = [];
|
|
|
40
40
|
// Mocks
|
|
41
41
|
// ---------------------------------------------------------------------------
|
|
42
42
|
|
|
43
|
-
mock.module("
|
|
43
|
+
mock.module("../../../../ipc/cli-client.js", () => ({
|
|
44
44
|
cliIpcCall: async (method: string, params?: any) => {
|
|
45
45
|
lastIpcCall = { method, params };
|
|
46
46
|
return mockIpcResult;
|
|
@@ -56,7 +56,7 @@ const fakeLogger = {
|
|
|
56
56
|
error: capture,
|
|
57
57
|
debug: () => {},
|
|
58
58
|
};
|
|
59
|
-
mock.module("
|
|
59
|
+
mock.module("../../../../util/logger.js", () => ({
|
|
60
60
|
getLogger: () => fakeLogger,
|
|
61
61
|
getCliLogger: () => fakeLogger,
|
|
62
62
|
}));
|
|
@@ -72,8 +72,8 @@ const { registerMemoryV2Command } = await import("../memory-v2.js");
|
|
|
72
72
|
// ---------------------------------------------------------------------------
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
|
-
* Build a fresh program and register the v2 subgroup
|
|
76
|
-
*
|
|
75
|
+
* Build a fresh program with a `memory` parent and register the v2 subgroup
|
|
76
|
+
* under it — mirroring how `registerMemoryCommand` wires the namespace.
|
|
77
77
|
*/
|
|
78
78
|
function buildProgram(): Command {
|
|
79
79
|
const program = new Command();
|
|
@@ -82,7 +82,8 @@ function buildProgram(): Command {
|
|
|
82
82
|
writeErr: () => {},
|
|
83
83
|
writeOut: () => {},
|
|
84
84
|
});
|
|
85
|
-
|
|
85
|
+
const memory = program.command("memory");
|
|
86
|
+
registerMemoryV2Command(memory);
|
|
86
87
|
return program;
|
|
87
88
|
}
|
|
88
89
|
|
|
@@ -40,7 +40,7 @@ let logOutput: string[] = [];
|
|
|
40
40
|
// Mocks
|
|
41
41
|
// ---------------------------------------------------------------------------
|
|
42
42
|
|
|
43
|
-
mock.module("
|
|
43
|
+
mock.module("../../../../ipc/cli-client.js", () => ({
|
|
44
44
|
cliIpcCall: async (
|
|
45
45
|
method: string,
|
|
46
46
|
params?: any,
|
|
@@ -60,7 +60,7 @@ const fakeLogger = {
|
|
|
60
60
|
error: capture,
|
|
61
61
|
debug: () => {},
|
|
62
62
|
};
|
|
63
|
-
mock.module("
|
|
63
|
+
mock.module("../../../../util/logger.js", () => ({
|
|
64
64
|
getLogger: () => fakeLogger,
|
|
65
65
|
getCliLogger: () => fakeLogger,
|
|
66
66
|
}));
|
|
@@ -82,7 +82,8 @@ function buildProgram(): Command {
|
|
|
82
82
|
writeErr: () => {},
|
|
83
83
|
writeOut: () => {},
|
|
84
84
|
});
|
|
85
|
-
|
|
85
|
+
const memory = program.command("memory");
|
|
86
|
+
registerMemoryV3Command(memory);
|
|
86
87
|
return program;
|
|
87
88
|
}
|
|
88
89
|
|
|
@@ -144,7 +145,7 @@ describe("subcommand registration", () => {
|
|
|
144
145
|
const v3 = memory!.commands.find((c) => c.name() === "v3");
|
|
145
146
|
expect(v3).toBeDefined();
|
|
146
147
|
const subcommandNames = v3!.commands.map((c) => c.name()).sort();
|
|
147
|
-
expect(subcommandNames).toEqual(["backfill-sections", "rebuild-index"]);
|
|
148
|
+
expect(subcommandNames).toEqual(["backfill-sections", "eval", "rebuild-index"]);
|
|
148
149
|
});
|
|
149
150
|
});
|
|
150
151
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
|
|
3
|
+
import { registerCommand } from "../../lib/register-command.js";
|
|
4
|
+
import { registerMemoryV2Command } from "./memory-v2.js";
|
|
5
|
+
import { registerMemoryV3Command } from "./memory-v3.js";
|
|
6
|
+
|
|
7
|
+
export function registerMemoryCommand(program: Command): void {
|
|
8
|
+
registerCommand(program, {
|
|
9
|
+
name: "memory",
|
|
10
|
+
transport: "ipc",
|
|
11
|
+
description: "Inspect and maintain the assistant memory subsystem",
|
|
12
|
+
build: (memory) => {
|
|
13
|
+
memory.addHelpText(
|
|
14
|
+
"after",
|
|
15
|
+
`
|
|
16
|
+
The memory subsystem retrieves concept pages two ways: the v2 concept-page
|
|
17
|
+
activation model (prose pages with directed edges) and the v3 section-lane
|
|
18
|
+
model (section-grain lanes cached as live shadow state). Each subgroup exposes
|
|
19
|
+
operator-facing maintenance verbs — reindexing, backfills, validation, and evals.
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
$ assistant memory v2 validate
|
|
23
|
+
$ assistant memory v3 rebuild-index`,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
registerMemoryV2Command(memory);
|
|
27
|
+
registerMemoryV3Command(memory);
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* type-only imports but forbids pulling in daemon runtime modules.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type { ComparisonReport } from "
|
|
12
|
+
import type { ComparisonReport } from "../../../memory/v2/harness/runner.js";
|
|
13
13
|
|
|
14
14
|
function sortedKs(report: ComparisonReport): number[] {
|
|
15
15
|
return [...report.ks].sort((a, b) => a - b);
|