@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vellumai/assistant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0-staging.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"@vellumai/twilio-client": "file:../packages/twilio-client",
|
|
54
54
|
"commander": "13.1.0",
|
|
55
55
|
"croner": "10.0.1",
|
|
56
|
+
"diff": "8.0.4",
|
|
56
57
|
"dotenv": "17.3.1",
|
|
57
58
|
"drizzle-orm": "0.45.2",
|
|
58
59
|
"jszip": "3.10.1",
|
|
@@ -3,19 +3,13 @@
|
|
|
3
3
|
* Generate `llm-provider-catalog.json` from the canonical
|
|
4
4
|
* `PROVIDER_CATALOG` in `assistant/src/providers/model-catalog.ts`.
|
|
5
5
|
*
|
|
6
|
-
* The JSON file is the client-facing catalog
|
|
7
|
-
*
|
|
8
|
-
* the
|
|
9
|
-
* that the parity test only catches after push.
|
|
6
|
+
* The JSON file is the client-facing catalog. Keeping it generated — rather
|
|
7
|
+
* than hand-mirrored — eliminates the recurring "I edited model-catalog.ts and
|
|
8
|
+
* forgot the JSON" failure mode that the parity test only catches after push.
|
|
10
9
|
*
|
|
11
|
-
*
|
|
10
|
+
* Output:
|
|
12
11
|
* - `meta/llm-provider-catalog.json` — primary checked-in artifact, read
|
|
13
|
-
* by web codegen (§D) and any
|
|
14
|
-
* - `clients/shared/Resources/llm-provider-catalog.json` — SwiftPM resource
|
|
15
|
-
* bundled into `VellumAssistantShared`. SwiftPM cannot reach files
|
|
16
|
-
* outside a target's source directory, so this mirror is necessary;
|
|
17
|
-
* both files are produced by the same generator and asserted equal by
|
|
18
|
-
* the parity test, making drift impossible.
|
|
12
|
+
* by web codegen (§D) and any downstream consumer.
|
|
19
13
|
*
|
|
20
14
|
* The projection drops daemon-only fields (today: `apiKeyUrl`, which clients
|
|
21
15
|
* read from `credentialsGuide.url` instead) and pins field order so the
|
|
@@ -37,10 +31,7 @@ import {
|
|
|
37
31
|
} from "../src/providers/model-catalog.js";
|
|
38
32
|
|
|
39
33
|
const ROOT = resolve(import.meta.dir, "../..");
|
|
40
|
-
const OUTPUT_PATHS = [
|
|
41
|
-
join(ROOT, "meta/llm-provider-catalog.json"),
|
|
42
|
-
join(ROOT, "clients/shared/Resources/llm-provider-catalog.json"),
|
|
43
|
-
] as const;
|
|
34
|
+
const OUTPUT_PATHS = [join(ROOT, "meta/llm-provider-catalog.json")] as const;
|
|
44
35
|
|
|
45
36
|
/**
|
|
46
37
|
* Bumped when the *shape* of the client catalog JSON changes in a way native
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* canonical `SEARCH_PROVIDER_CATALOG` in
|
|
5
5
|
* `assistant/src/providers/search-provider-catalog.ts`.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* Output:
|
|
8
8
|
* - `meta/web-search-provider-catalog.json` — primary checked-in artifact,
|
|
9
9
|
* consumed by:
|
|
10
10
|
* - `cli/src/__tests__/search-provider-env-var-parity.test.ts`
|
|
@@ -12,13 +12,8 @@
|
|
|
12
12
|
* - Downstream `vellum-assistant-platform/web/src/lib/generated/
|
|
13
13
|
* web-search-provider-catalog.json` (manually sync'd today; the
|
|
14
14
|
* scheduled sync workflow is a planned follow-up).
|
|
15
|
-
* - `clients/shared/Resources/web-search-provider-catalog.json` — SwiftPM
|
|
16
|
-
* resource bundled into `VellumAssistantShared`. SwiftPM cannot reach
|
|
17
|
-
* files outside a target's source directory, so this mirror is
|
|
18
|
-
* necessary; both files are produced by the same generator and
|
|
19
|
-
* asserted equal by the parity test, making drift impossible.
|
|
20
15
|
*
|
|
21
|
-
* Companion to `sync-llm-catalog.ts
|
|
16
|
+
* Companion to `sync-llm-catalog.ts`.
|
|
22
17
|
*
|
|
23
18
|
* Usage:
|
|
24
19
|
* cd assistant && bun run scripts/sync-web-search-catalog.ts
|
|
@@ -37,7 +32,6 @@ import {
|
|
|
37
32
|
const ROOT = resolve(import.meta.dir, "../..");
|
|
38
33
|
const OUTPUT_PATHS = [
|
|
39
34
|
join(ROOT, "meta/web-search-provider-catalog.json"),
|
|
40
|
-
join(ROOT, "clients/shared/Resources/web-search-provider-catalog.json"),
|
|
41
35
|
] as const;
|
|
42
36
|
|
|
43
37
|
/**
|
|
@@ -108,9 +102,7 @@ async function main(): Promise<void> {
|
|
|
108
102
|
continue;
|
|
109
103
|
}
|
|
110
104
|
if (existing !== next) {
|
|
111
|
-
console.error(
|
|
112
|
-
`${rel} is stale. Run: bun run sync:web-search-catalog`,
|
|
113
|
-
);
|
|
105
|
+
console.error(`${rel} is stale. Run: bun run sync:web-search-catalog`);
|
|
114
106
|
anyStale = true;
|
|
115
107
|
continue;
|
|
116
108
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
buildAccessRequestCardView,
|
|
5
|
+
parseAccessRequestPayload,
|
|
6
|
+
} from "../notifications/access-request-copy.js";
|
|
7
|
+
|
|
8
|
+
function view(raw: Record<string, unknown>) {
|
|
9
|
+
return buildAccessRequestCardView(parseAccessRequestPayload(raw));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const TAB = String.fromCharCode(9);
|
|
13
|
+
|
|
14
|
+
describe("buildAccessRequestCardView", () => {
|
|
15
|
+
test("prefers actorDisplayName, falls back to senderIdentifier then 'Someone'", () => {
|
|
16
|
+
expect(
|
|
17
|
+
view({ actorDisplayName: "Alice", senderIdentifier: "U999" }).displayName,
|
|
18
|
+
).toBe("Alice");
|
|
19
|
+
expect(view({ senderIdentifier: "U999" }).displayName).toBe("U999");
|
|
20
|
+
expect(view({}).displayName).toBe("Someone");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("sanitizes identity fields (strips control characters)", () => {
|
|
24
|
+
const v = view({
|
|
25
|
+
actorDisplayName: `Al${TAB}ice`,
|
|
26
|
+
actorUsername: `a${TAB}lice`,
|
|
27
|
+
actorExternalId: `U9${TAB}99`,
|
|
28
|
+
});
|
|
29
|
+
expect(v.displayName).toBe("Al ice");
|
|
30
|
+
expect(v.username).toBe("a lice");
|
|
31
|
+
expect(v.externalId).toBe("U9 99");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("username and externalId are undefined when absent", () => {
|
|
35
|
+
const v = view({ actorDisplayName: "Alice" });
|
|
36
|
+
expect(v.username).toBeUndefined();
|
|
37
|
+
expect(v.externalId).toBeUndefined();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("detects Slack DM conversations", () => {
|
|
41
|
+
expect(
|
|
42
|
+
view({ sourceChannel: "slack", conversationExternalId: "D01XYZ" })
|
|
43
|
+
.isSlackDm,
|
|
44
|
+
).toBe(true);
|
|
45
|
+
expect(
|
|
46
|
+
view({ sourceChannel: "slack", conversationExternalId: "C01ABC" })
|
|
47
|
+
.isSlackDm,
|
|
48
|
+
).toBe(false);
|
|
49
|
+
expect(
|
|
50
|
+
view({ sourceChannel: "telegram", conversationExternalId: "D01XYZ" })
|
|
51
|
+
.isSlackDm,
|
|
52
|
+
).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("builds a Slack permalink only with slack source + conversation + ts", () => {
|
|
56
|
+
expect(
|
|
57
|
+
view({
|
|
58
|
+
sourceChannel: "slack",
|
|
59
|
+
conversationExternalId: "C01ABC",
|
|
60
|
+
messageTs: "1700000000.000100",
|
|
61
|
+
}).messagePermalink,
|
|
62
|
+
).toBe("https://slack.com/archives/C01ABC/p1700000000000100");
|
|
63
|
+
expect(
|
|
64
|
+
view({ sourceChannel: "slack", conversationExternalId: "C01ABC" })
|
|
65
|
+
.messagePermalink,
|
|
66
|
+
).toBeUndefined();
|
|
67
|
+
expect(
|
|
68
|
+
view({
|
|
69
|
+
sourceChannel: "telegram",
|
|
70
|
+
conversationExternalId: "C01ABC",
|
|
71
|
+
messageTs: "1.2",
|
|
72
|
+
}).messagePermalink,
|
|
73
|
+
).toBeUndefined();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("sanitizes message preview and yields undefined when blank after sanitizing", () => {
|
|
77
|
+
expect(view({ messagePreview: " hello " }).messagePreview).toBe("hello");
|
|
78
|
+
// Blank / control-character-only previews sanitize to empty → undefined
|
|
79
|
+
// (no empty quote block is rendered downstream).
|
|
80
|
+
expect(view({ messagePreview: "" }).messagePreview).toBeUndefined();
|
|
81
|
+
expect(view({ messagePreview: " " }).messagePreview).toBeUndefined();
|
|
82
|
+
expect(view({}).messagePreview).toBeUndefined();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("collects trust/security warnings", () => {
|
|
86
|
+
const v = view({
|
|
87
|
+
isStranger: true,
|
|
88
|
+
isRestricted: true,
|
|
89
|
+
previousMemberStatus: "revoked",
|
|
90
|
+
});
|
|
91
|
+
expect(v.warnings).toEqual([
|
|
92
|
+
"This user was previously revoked.",
|
|
93
|
+
"External Slack user (not in this workspace).",
|
|
94
|
+
"Guest / restricted account.",
|
|
95
|
+
]);
|
|
96
|
+
expect(view({}).warnings).toEqual([]);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
parseAccessRequestPayload,
|
|
6
|
-
} from "../notifications/access-request-copy.js";
|
|
3
|
+
import { parseAccessRequestPayload } from "../notifications/access-request-copy.js";
|
|
4
|
+
import { buildAccessRequestSeedContentBlocks } from "../notifications/approval-card-data.js";
|
|
7
5
|
|
|
8
6
|
describe("buildAccessRequestSeedContentBlocks", () => {
|
|
9
7
|
const basePayload: Record<string, unknown> = {
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tests for
|
|
2
|
+
* Tests for address-based member resolution in resolveActorTrust.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* ("I don't recognize this number") path instead of the unverified-caller
|
|
9
|
-
* guidance path.
|
|
4
|
+
* All member lookups use the canonical (type, address) path — the address
|
|
5
|
+
* column is the sole identity for all channel types. Phone channels
|
|
6
|
+
* registered by the inbound name-capture flow have `address` set (E.164)
|
|
7
|
+
* and are discovered through the same path as every other channel.
|
|
10
8
|
*
|
|
11
|
-
* This suite verifies that
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* This suite verifies that address-based lookup returns the correct
|
|
10
|
+
* `memberRecord` with the right channel/status so relay-setup-router
|
|
11
|
+
* can emit the appropriate outcome (e.g. `unverified_caller`).
|
|
14
12
|
*/
|
|
15
13
|
|
|
16
14
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
@@ -22,18 +20,14 @@ mock.module("../util/logger.js", () => ({
|
|
|
22
20
|
}));
|
|
23
21
|
|
|
24
22
|
// ── Contact store stubs — filled in per test ─────────────────────────────────
|
|
25
|
-
let _byExternalId: ReturnType<
|
|
26
|
-
typeof import("../contacts/contact-store.js")["findContactByChannelExternalId"]
|
|
27
|
-
> = null;
|
|
28
23
|
let _byAddress: ReturnType<
|
|
29
|
-
typeof import("../contacts/contact-store.js")["findContactByAddress"]
|
|
24
|
+
(typeof import("../contacts/contact-store.js"))["findContactByAddress"]
|
|
30
25
|
> = null;
|
|
31
26
|
let _guardian: ReturnType<
|
|
32
|
-
typeof import("../contacts/contact-store.js")["findGuardianForChannel"]
|
|
27
|
+
(typeof import("../contacts/contact-store.js"))["findGuardianForChannel"]
|
|
33
28
|
> = null;
|
|
34
29
|
|
|
35
30
|
mock.module("../contacts/contact-store.js", () => ({
|
|
36
|
-
findContactByChannelExternalId: (_type: string, _id: string) => _byExternalId,
|
|
37
31
|
findContactByAddress: (_type: string, _addr: string) => _byAddress,
|
|
38
32
|
findGuardianForChannel: (_channel: string) => _guardian,
|
|
39
33
|
}));
|
|
@@ -49,7 +43,6 @@ const PHONE = "+15559871234";
|
|
|
49
43
|
function makeContact(
|
|
50
44
|
role: "guardian" | "contact" = "contact",
|
|
51
45
|
status: "unverified" | "active" = "unverified",
|
|
52
|
-
externalUserId: string | null = null,
|
|
53
46
|
): ContactWithChannels {
|
|
54
47
|
const channelId = "ch-test";
|
|
55
48
|
return {
|
|
@@ -69,8 +62,7 @@ function makeContact(
|
|
|
69
62
|
id: channelId,
|
|
70
63
|
contactId: "contact-test",
|
|
71
64
|
type: "phone",
|
|
72
|
-
address: PHONE
|
|
73
|
-
externalUserId,
|
|
65
|
+
address: PHONE,
|
|
74
66
|
externalChatId: null,
|
|
75
67
|
isPrimary: true,
|
|
76
68
|
status,
|
|
@@ -94,14 +86,13 @@ function makeContact(
|
|
|
94
86
|
|
|
95
87
|
describe("resolveActorTrust — address fallback", () => {
|
|
96
88
|
beforeEach(() => {
|
|
97
|
-
_byExternalId = null;
|
|
98
89
|
_byAddress = null;
|
|
99
90
|
_guardian = null;
|
|
100
91
|
});
|
|
101
92
|
|
|
102
93
|
test("finds unverified channel via address when externalUserId is null", () => {
|
|
103
94
|
// Simulate a contact registered by name-capture: address set, externalUserId null.
|
|
104
|
-
_byAddress = makeContact("contact", "unverified"
|
|
95
|
+
_byAddress = makeContact("contact", "unverified");
|
|
105
96
|
|
|
106
97
|
const result = resolveActorTrust({
|
|
107
98
|
assistantId: "asst-1",
|
|
@@ -113,16 +104,13 @@ describe("resolveActorTrust — address fallback", () => {
|
|
|
113
104
|
expect(result.memberRecord).not.toBeNull();
|
|
114
105
|
expect(result.memberRecord?.contact.displayName).toBe("Patrick Test");
|
|
115
106
|
expect(result.memberRecord?.channel.status).toBe("unverified");
|
|
116
|
-
// trustClass is '
|
|
117
|
-
|
|
107
|
+
// trustClass is 'unverified_contact' for a member whose channel is
|
|
108
|
+
// pending or unverified — known to the guardian but not yet verified.
|
|
109
|
+
expect(result.trustClass).toBe("unverified_contact");
|
|
118
110
|
});
|
|
119
111
|
|
|
120
|
-
test("
|
|
121
|
-
|
|
122
|
-
const primaryContact = makeContact("contact", "active", PHONE);
|
|
123
|
-
const addressContact = makeContact("contact", "unverified", null);
|
|
124
|
-
_byExternalId = primaryContact;
|
|
125
|
-
_byAddress = addressContact;
|
|
112
|
+
test("address lookup is the sole member resolution path", () => {
|
|
113
|
+
_byAddress = makeContact("contact", "active");
|
|
126
114
|
|
|
127
115
|
const result = resolveActorTrust({
|
|
128
116
|
assistantId: "asst-1",
|
|
@@ -132,11 +120,10 @@ describe("resolveActorTrust — address fallback", () => {
|
|
|
132
120
|
});
|
|
133
121
|
|
|
134
122
|
expect(result.memberRecord?.channel.status).toBe("active");
|
|
135
|
-
expect(result.memberRecord?.channel.
|
|
123
|
+
expect(result.memberRecord?.channel.address).toBe(PHONE);
|
|
136
124
|
});
|
|
137
125
|
|
|
138
126
|
test("returns null memberRecord when neither lookup finds the number", () => {
|
|
139
|
-
_byExternalId = null;
|
|
140
127
|
_byAddress = null;
|
|
141
128
|
|
|
142
129
|
const result = resolveActorTrust({
|
|
@@ -153,7 +140,7 @@ describe("resolveActorTrust — address fallback", () => {
|
|
|
153
140
|
test("address-found active channel elevates trust to trusted_contact", () => {
|
|
154
141
|
// An active channel found via address (e.g. after manual verify without externalUserId set)
|
|
155
142
|
// should still yield trusted_contact trust class.
|
|
156
|
-
_byAddress = makeContact("contact", "active"
|
|
143
|
+
_byAddress = makeContact("contact", "active");
|
|
157
144
|
|
|
158
145
|
const result = resolveActorTrust({
|
|
159
146
|
assistantId: "asst-1",
|
|
@@ -166,4 +153,57 @@ describe("resolveActorTrust — address fallback", () => {
|
|
|
166
153
|
expect(result.memberRecord?.channel.status).toBe("active");
|
|
167
154
|
expect(result.trustClass).toBe("trusted_contact");
|
|
168
155
|
});
|
|
156
|
+
|
|
157
|
+
test("pending-status member is classified as unverified_contact", () => {
|
|
158
|
+
// Mirrors the unverified branch but for `pending` status (e.g. a phone
|
|
159
|
+
// contact registered by name-capture awaiting the DTMF challenge).
|
|
160
|
+
const contact = makeContact("contact", "unverified");
|
|
161
|
+
// Override status to "pending" — makeContact only accepts unverified/active
|
|
162
|
+
contact.channels[0]!.status = "pending";
|
|
163
|
+
_byAddress = contact;
|
|
164
|
+
|
|
165
|
+
const result = resolveActorTrust({
|
|
166
|
+
assistantId: "asst-1",
|
|
167
|
+
sourceChannel: "phone",
|
|
168
|
+
conversationExternalId: PHONE,
|
|
169
|
+
actorExternalId: PHONE,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
expect(result.memberRecord?.channel.status).toBe("pending");
|
|
173
|
+
expect(result.trustClass).toBe("unverified_contact");
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test("blocked-status member is classified as unknown (not unverified_contact)", () => {
|
|
177
|
+
// Hard-deny statuses (blocked, revoked) stay `unknown` — admission-layer
|
|
178
|
+
// re-checks channel.status and emits the hard-deny reasons.
|
|
179
|
+
const contact = makeContact("contact", "unverified");
|
|
180
|
+
contact.channels[0]!.status = "blocked";
|
|
181
|
+
_byAddress = contact;
|
|
182
|
+
|
|
183
|
+
const result = resolveActorTrust({
|
|
184
|
+
assistantId: "asst-1",
|
|
185
|
+
sourceChannel: "phone",
|
|
186
|
+
conversationExternalId: PHONE,
|
|
187
|
+
actorExternalId: PHONE,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
expect(result.memberRecord?.channel.status).toBe("blocked");
|
|
191
|
+
expect(result.trustClass).toBe("unknown");
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("revoked-status member is classified as unknown", () => {
|
|
195
|
+
const contact = makeContact("contact", "unverified");
|
|
196
|
+
contact.channels[0]!.status = "revoked";
|
|
197
|
+
_byAddress = contact;
|
|
198
|
+
|
|
199
|
+
const result = resolveActorTrust({
|
|
200
|
+
assistantId: "asst-1",
|
|
201
|
+
sourceChannel: "phone",
|
|
202
|
+
conversationExternalId: PHONE,
|
|
203
|
+
actorExternalId: PHONE,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
expect(result.memberRecord?.channel.status).toBe("revoked");
|
|
207
|
+
expect(result.trustClass).toBe("unknown");
|
|
208
|
+
});
|
|
169
209
|
});
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The compaction summarizer's input.
|
|
3
|
+
*
|
|
4
|
+
* Both the budget gate and overflow recovery summarize the *injected* history
|
|
5
|
+
* (the genuine conversation as the agent saw it) so the summary call's prompt
|
|
6
|
+
* prefix matches the agent's warm prefix cache — a cache read rather than a
|
|
7
|
+
* fresh cache write. The agent loop hands the full injected history to
|
|
8
|
+
* compaction unconditionally; the post-compaction re-injection hook owns
|
|
9
|
+
* injection idempotency by stripping the tail's per-turn blocks before
|
|
10
|
+
* re-applying them.
|
|
11
|
+
*/
|
|
12
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
13
|
+
|
|
14
|
+
import type { PostCompactContext } from "@vellumai/plugin-api";
|
|
15
|
+
|
|
16
|
+
import type { AgentEvent } from "../agent/loop.js";
|
|
17
|
+
import { AgentLoop } from "../agent/loop.js";
|
|
18
|
+
import type { ContextWindowConfig } from "../config/types.js";
|
|
19
|
+
import type { TrustContext } from "../daemon/trust-context.js";
|
|
20
|
+
import { HOOKS } from "../plugin-api/constants.js";
|
|
21
|
+
import {
|
|
22
|
+
createContextWindowManager,
|
|
23
|
+
disposeContextWindowManager,
|
|
24
|
+
getContextWindowManager,
|
|
25
|
+
} from "../plugins/defaults/compaction/manager-store.js";
|
|
26
|
+
import {
|
|
27
|
+
registerPlugin,
|
|
28
|
+
resetPluginRegistryForTests,
|
|
29
|
+
} from "../plugins/registry.js";
|
|
30
|
+
import type {
|
|
31
|
+
Message,
|
|
32
|
+
Provider,
|
|
33
|
+
ProviderResponse,
|
|
34
|
+
SendMessageOptions,
|
|
35
|
+
} from "../providers/types.js";
|
|
36
|
+
import { ContextOverflowError } from "../providers/types.js";
|
|
37
|
+
|
|
38
|
+
const testPostCompactPlugin = {
|
|
39
|
+
manifest: { name: "test-post-compact", version: "0.0.0" },
|
|
40
|
+
hooks: {
|
|
41
|
+
[HOOKS.POST_COMPACT]: async (input: PostCompactContext): Promise<void> => {
|
|
42
|
+
void input;
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const CONVERSATION_ID = "compaction-strip-conversation";
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A runtime `<workspace>` injection block. Its presence in the summarizer's
|
|
51
|
+
* input proves compaction received the injected history rather than a stripped
|
|
52
|
+
* copy.
|
|
53
|
+
*/
|
|
54
|
+
const WORKSPACE_INJECTION =
|
|
55
|
+
"<workspace>\nActive workspace: project-x\n</workspace>";
|
|
56
|
+
const TURN_BODY = "Hello there, this is the turn body.";
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* A user turn carrying a real text block plus a runtime injection block, both
|
|
60
|
+
* of which ride into compaction's input as-is.
|
|
61
|
+
*/
|
|
62
|
+
const injectedUserMessage: Message = {
|
|
63
|
+
role: "user",
|
|
64
|
+
content: [
|
|
65
|
+
{ type: "text", text: TURN_BODY },
|
|
66
|
+
{ type: "text", text: WORKSPACE_INJECTION },
|
|
67
|
+
],
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
function textResponse(text: string): ProviderResponse {
|
|
71
|
+
return {
|
|
72
|
+
content: [{ type: "text", text }],
|
|
73
|
+
model: "mock-model",
|
|
74
|
+
usage: { inputTokens: 10, outputTokens: 5 },
|
|
75
|
+
stopReason: "end_turn",
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function createMockProvider(responses: ProviderResponse[]): Provider {
|
|
80
|
+
let callIndex = 0;
|
|
81
|
+
return {
|
|
82
|
+
name: "mock",
|
|
83
|
+
async sendMessage(
|
|
84
|
+
_messages: Message[],
|
|
85
|
+
_options?: SendMessageOptions,
|
|
86
|
+
): Promise<ProviderResponse> {
|
|
87
|
+
const response = responses[callIndex] ?? responses[responses.length - 1];
|
|
88
|
+
callIndex++;
|
|
89
|
+
return response;
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
interface CompactionInputCapture {
|
|
95
|
+
budget: Message[] | null;
|
|
96
|
+
overflow: Message[] | null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Install a per-conversation manager that records the messages handed to the
|
|
101
|
+
* budget summarizer (`maybeCompact`) and to overflow recovery
|
|
102
|
+
* (`recoverContextOverflow`).
|
|
103
|
+
*/
|
|
104
|
+
function installCapturingManager(capture: CompactionInputCapture): {
|
|
105
|
+
trust: TrustContext;
|
|
106
|
+
} {
|
|
107
|
+
createContextWindowManager({
|
|
108
|
+
provider: { name: "mock-provider" } as unknown as Provider,
|
|
109
|
+
systemPrompt: "system",
|
|
110
|
+
config: {} as unknown as ContextWindowConfig,
|
|
111
|
+
conversationId: CONVERSATION_ID,
|
|
112
|
+
});
|
|
113
|
+
const manager = getContextWindowManager(CONVERSATION_ID);
|
|
114
|
+
if (manager) {
|
|
115
|
+
manager.maybeCompact = (async (messages: Message[]) => {
|
|
116
|
+
capture.budget = messages;
|
|
117
|
+
return {
|
|
118
|
+
messages: [injectedUserMessage],
|
|
119
|
+
compacted: true,
|
|
120
|
+
exhausted: false,
|
|
121
|
+
};
|
|
122
|
+
}) as unknown as typeof manager.maybeCompact;
|
|
123
|
+
manager.recoverContextOverflow = (async (messages: Message[]) => {
|
|
124
|
+
capture.overflow = messages;
|
|
125
|
+
return {
|
|
126
|
+
messages: [injectedUserMessage],
|
|
127
|
+
compacted: true,
|
|
128
|
+
exhausted: false,
|
|
129
|
+
};
|
|
130
|
+
}) as unknown as typeof manager.recoverContextOverflow;
|
|
131
|
+
}
|
|
132
|
+
return { trust: { sourceChannel: "vellum", trustClass: "unknown" } };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function serialize(messages: Message[] | null): string {
|
|
136
|
+
return JSON.stringify(messages ?? []);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
describe("AgentLoop compaction summarizer input", () => {
|
|
140
|
+
beforeEach(() => {
|
|
141
|
+
resetPluginRegistryForTests();
|
|
142
|
+
registerPlugin(testPostCompactPlugin);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
afterEach(() => {
|
|
146
|
+
disposeContextWindowManager(CONVERSATION_ID);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("budget-gate compaction summarizes the injected history", async () => {
|
|
150
|
+
// GIVEN a history whose user turn carries a runtime-injection block
|
|
151
|
+
const capture: CompactionInputCapture = { budget: null, overflow: null };
|
|
152
|
+
const provider = createMockProvider([
|
|
153
|
+
textResponse("done after compaction"),
|
|
154
|
+
]);
|
|
155
|
+
const loop = new AgentLoop({
|
|
156
|
+
provider,
|
|
157
|
+
systemPrompt: "system",
|
|
158
|
+
conversationId: CONVERSATION_ID,
|
|
159
|
+
tools: [],
|
|
160
|
+
toolExecutor: async () => ({ content: "ok", isError: false }),
|
|
161
|
+
});
|
|
162
|
+
const events: AgentEvent[] = [];
|
|
163
|
+
|
|
164
|
+
// WHEN the budget gate trips and in-place compaction runs
|
|
165
|
+
await loop.run({
|
|
166
|
+
requestId: "req",
|
|
167
|
+
messages: [injectedUserMessage],
|
|
168
|
+
onEvent: (event) => {
|
|
169
|
+
events.push(event);
|
|
170
|
+
},
|
|
171
|
+
resolveContextWindow: () => ({
|
|
172
|
+
maxInputTokens: 10,
|
|
173
|
+
overflowRecovery: { enabled: true, safetyMarginRatio: 0 },
|
|
174
|
+
}),
|
|
175
|
+
compactInPlace: true,
|
|
176
|
+
...installCapturingManager(capture),
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// THEN the budget summarizer received the injected history, injection intact
|
|
180
|
+
expect(capture.budget).not.toBeNull();
|
|
181
|
+
expect(serialize(capture.budget)).toContain("<workspace>");
|
|
182
|
+
// AND overflow recovery was not invoked
|
|
183
|
+
expect(capture.overflow).toBeNull();
|
|
184
|
+
// AND the history-stripped marker still fires for the durable base
|
|
185
|
+
expect(events.some((e) => e.type === "history_stripped")).toBe(true);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("overflow-driven compaction summarizes the injected history", async () => {
|
|
189
|
+
// GIVEN a history whose user turn carries a runtime-injection block
|
|
190
|
+
const capture: CompactionInputCapture = { budget: null, overflow: null };
|
|
191
|
+
|
|
192
|
+
// AND a provider that rejects the first call as context-too-large
|
|
193
|
+
let throwOnce = true;
|
|
194
|
+
const provider: Provider = {
|
|
195
|
+
name: "mock",
|
|
196
|
+
async sendMessage(): Promise<ProviderResponse> {
|
|
197
|
+
if (throwOnce) {
|
|
198
|
+
throwOnce = false;
|
|
199
|
+
throw new ContextOverflowError("prompt too long", "mock", {
|
|
200
|
+
actualTokens: 999_999,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return textResponse("done after overflow recovery");
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
const loop = new AgentLoop({
|
|
207
|
+
provider,
|
|
208
|
+
systemPrompt: "system",
|
|
209
|
+
conversationId: CONVERSATION_ID,
|
|
210
|
+
tools: [],
|
|
211
|
+
toolExecutor: async () => ({ content: "ok", isError: false }),
|
|
212
|
+
});
|
|
213
|
+
// A blocking watermark plus `compactInPlace: false` keep the budget gate
|
|
214
|
+
// from firing, so only the overflow rejection drives compaction.
|
|
215
|
+
loop.compactionCircuit.lastPostCompactionEstimate = 0;
|
|
216
|
+
const events: AgentEvent[] = [];
|
|
217
|
+
|
|
218
|
+
// WHEN the provider overflow forces overflow recovery
|
|
219
|
+
await loop.run({
|
|
220
|
+
requestId: "req",
|
|
221
|
+
messages: [injectedUserMessage],
|
|
222
|
+
onEvent: (event) => {
|
|
223
|
+
events.push(event);
|
|
224
|
+
},
|
|
225
|
+
resolveContextWindow: () => ({
|
|
226
|
+
maxInputTokens: 10,
|
|
227
|
+
overflowRecovery: { enabled: true, safetyMarginRatio: 0 },
|
|
228
|
+
}),
|
|
229
|
+
compactInPlace: false,
|
|
230
|
+
...installCapturingManager(capture),
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// THEN overflow recovery received the injected history, injection intact
|
|
234
|
+
expect(capture.overflow).not.toBeNull();
|
|
235
|
+
expect(serialize(capture.overflow)).toContain("<workspace>");
|
|
236
|
+
// AND the real turn body is present alongside the injection
|
|
237
|
+
expect(serialize(capture.overflow)).toContain(TURN_BODY);
|
|
238
|
+
// AND the budget summarizer was not invoked
|
|
239
|
+
expect(capture.budget).toBeNull();
|
|
240
|
+
});
|
|
241
|
+
});
|