@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
|
@@ -145,6 +145,40 @@ describe("AssistantConfigSchema", () => {
|
|
|
145
145
|
expect(result.services["web-search"].mode).toBe("your-own");
|
|
146
146
|
});
|
|
147
147
|
|
|
148
|
+
test("accepts Firecrawl as a web search provider", () => {
|
|
149
|
+
const result = AssistantConfigSchema.parse({
|
|
150
|
+
services: {
|
|
151
|
+
"web-search": { mode: "your-own", provider: "firecrawl" },
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(result.services["web-search"].provider).toBe("firecrawl");
|
|
156
|
+
expect(result.services["web-search"].mode).toBe("your-own");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test("defaults the web-fetch provider to the built-in fetcher", () => {
|
|
160
|
+
const result = AssistantConfigSchema.parse({});
|
|
161
|
+
expect(result.services["web-fetch"].provider).toBe("default");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test("accepts Firecrawl as a web fetch provider", () => {
|
|
165
|
+
const result = AssistantConfigSchema.parse({
|
|
166
|
+
services: {
|
|
167
|
+
"web-fetch": { mode: "your-own", provider: "firecrawl" },
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
expect(result.services["web-fetch"].provider).toBe("firecrawl");
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("rejects an unknown web-fetch provider", () => {
|
|
175
|
+
expect(() =>
|
|
176
|
+
AssistantConfigSchema.parse({
|
|
177
|
+
services: { "web-fetch": { provider: "nope" } },
|
|
178
|
+
}),
|
|
179
|
+
).toThrow();
|
|
180
|
+
});
|
|
181
|
+
|
|
148
182
|
test("accepts valid complete config", () => {
|
|
149
183
|
const input = {
|
|
150
184
|
llm: {
|
|
@@ -185,6 +219,7 @@ describe("AssistantConfigSchema", () => {
|
|
|
185
219
|
speed: "standard",
|
|
186
220
|
verbosity: "medium",
|
|
187
221
|
temperature: null,
|
|
222
|
+
topP: null,
|
|
188
223
|
thinking: { enabled: true, streamThinking: true },
|
|
189
224
|
contextWindow: {
|
|
190
225
|
enabled: true,
|
|
@@ -231,24 +231,6 @@ describe("ConfigWatcher workspace file handlers", () => {
|
|
|
231
231
|
expect(evictCallCount).toBe(1);
|
|
232
232
|
});
|
|
233
233
|
|
|
234
|
-
test("SOUL.md change triggers identity intro refetch notification", async () => {
|
|
235
|
-
let introCallCount = 0;
|
|
236
|
-
watcher.start(
|
|
237
|
-
onConversationEvict,
|
|
238
|
-
undefined,
|
|
239
|
-
undefined,
|
|
240
|
-
undefined,
|
|
241
|
-
undefined,
|
|
242
|
-
undefined,
|
|
243
|
-
() => {
|
|
244
|
-
introCallCount += 1;
|
|
245
|
-
},
|
|
246
|
-
);
|
|
247
|
-
simulateFileChange(WORKSPACE_DIR, "SOUL.md");
|
|
248
|
-
await new Promise((r) => setTimeout(r, WAIT_MS));
|
|
249
|
-
expect(introCallCount).toBe(1);
|
|
250
|
-
});
|
|
251
|
-
|
|
252
234
|
test("IDENTITY.md change triggers onConversationEvict", async () => {
|
|
253
235
|
watcher.start(onConversationEvict);
|
|
254
236
|
simulateFileChange(WORKSPACE_DIR, "IDENTITY.md");
|
|
@@ -178,7 +178,7 @@ describe("bridgeConfirmationRequestToGuardian", () => {
|
|
|
178
178
|
|
|
179
179
|
expect("skipped" in result && result.skipped).toBe(true);
|
|
180
180
|
if ("skipped" in result) {
|
|
181
|
-
expect(result.reason).toBe("
|
|
181
|
+
expect(result.reason).toBe("not_bridgeable_trust_class");
|
|
182
182
|
}
|
|
183
183
|
expect(emittedSignals).toHaveLength(0);
|
|
184
184
|
});
|
|
@@ -199,7 +199,7 @@ describe("bridgeConfirmationRequestToGuardian", () => {
|
|
|
199
199
|
|
|
200
200
|
expect("skipped" in result && result.skipped).toBe(true);
|
|
201
201
|
if ("skipped" in result) {
|
|
202
|
-
expect(result.reason).toBe("
|
|
202
|
+
expect(result.reason).toBe("not_bridgeable_trust_class");
|
|
203
203
|
}
|
|
204
204
|
expect(emittedSignals).toHaveLength(0);
|
|
205
205
|
});
|
|
@@ -75,7 +75,6 @@ describe("upsertContact user_file selection", () => {
|
|
|
75
75
|
{
|
|
76
76
|
type: "vellum",
|
|
77
77
|
address: "vellum-principal-abc",
|
|
78
|
-
externalUserId: "vellum-principal-abc",
|
|
79
78
|
},
|
|
80
79
|
],
|
|
81
80
|
});
|
|
@@ -91,7 +90,6 @@ describe("upsertContact user_file selection", () => {
|
|
|
91
90
|
{
|
|
92
91
|
type: "slack",
|
|
93
92
|
address: "u123456",
|
|
94
|
-
externalUserId: "U123456",
|
|
95
93
|
externalChatId: "D987654",
|
|
96
94
|
},
|
|
97
95
|
],
|
|
@@ -109,7 +107,6 @@ describe("upsertContact user_file selection", () => {
|
|
|
109
107
|
{
|
|
110
108
|
type: "slack",
|
|
111
109
|
address: "ualice",
|
|
112
|
-
externalUserId: "UALICE",
|
|
113
110
|
externalChatId: "DALICE",
|
|
114
111
|
},
|
|
115
112
|
],
|
|
@@ -125,7 +122,6 @@ describe("upsertContact user_file selection", () => {
|
|
|
125
122
|
{
|
|
126
123
|
type: "slack",
|
|
127
124
|
address: "ubob1",
|
|
128
|
-
externalUserId: "UBOB1",
|
|
129
125
|
externalChatId: "DBOB1",
|
|
130
126
|
},
|
|
131
127
|
],
|
|
@@ -137,7 +133,6 @@ describe("upsertContact user_file selection", () => {
|
|
|
137
133
|
{
|
|
138
134
|
type: "slack",
|
|
139
135
|
address: "ubob2",
|
|
140
|
-
externalUserId: "UBOB2",
|
|
141
136
|
externalChatId: "DBOB2",
|
|
142
137
|
},
|
|
143
138
|
],
|
|
@@ -164,7 +159,6 @@ describe("upsertContact user_file selection", () => {
|
|
|
164
159
|
{
|
|
165
160
|
type: "phone",
|
|
166
161
|
address: "+15550000",
|
|
167
|
-
externalUserId: "+15550000",
|
|
168
162
|
externalChatId: "+15550000",
|
|
169
163
|
},
|
|
170
164
|
],
|
|
@@ -240,6 +240,35 @@ describe("contact_search tool", () => {
|
|
|
240
240
|
});
|
|
241
241
|
});
|
|
242
242
|
|
|
243
|
+
// ── search_contacts route (HTTP/IPC compat shim) ─────────────────────
|
|
244
|
+
|
|
245
|
+
describe("search_contacts route", () => {
|
|
246
|
+
beforeEach(clearContacts);
|
|
247
|
+
|
|
248
|
+
test("includes externalUserId (= address) on channels for older clients", () => {
|
|
249
|
+
const seeded = upsertFixture({
|
|
250
|
+
display_name: "Dana",
|
|
251
|
+
channels: [{ type: "slack", address: "U12345ABC" }],
|
|
252
|
+
});
|
|
253
|
+
const seededAddress = seeded.channels[0]!.address;
|
|
254
|
+
|
|
255
|
+
const searchRoute = ROUTES.find(
|
|
256
|
+
(r) => r.operationId === "search_contacts",
|
|
257
|
+
)!;
|
|
258
|
+
const contacts = searchRoute.handler({
|
|
259
|
+
body: { channelAddress: seededAddress },
|
|
260
|
+
}) as unknown as Array<{
|
|
261
|
+
channels: Array<{ address: string; externalUserId?: string }>;
|
|
262
|
+
}>;
|
|
263
|
+
|
|
264
|
+
expect(contacts.length).toBeGreaterThanOrEqual(1);
|
|
265
|
+
const channel = contacts[0]!.channels[0]!;
|
|
266
|
+
// The route re-derives the compat field from address, so SDK/macOS
|
|
267
|
+
// clients that read externalUserId keep working.
|
|
268
|
+
expect(channel.externalUserId).toBe(channel.address);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
243
272
|
// ── contact_merge ───────────────────────────────────────────────────
|
|
244
273
|
|
|
245
274
|
describe("contact_merge tool", () => {
|
|
@@ -366,6 +366,7 @@ import { runAgentLoopImpl } from "../daemon/conversation-agent-loop.js";
|
|
|
366
366
|
interface CapturedAgentLoopRun {
|
|
367
367
|
callSite: LLMCallSite | undefined;
|
|
368
368
|
overrideProfile: string | undefined;
|
|
369
|
+
forceOverrideProfile: boolean | undefined;
|
|
369
370
|
resolvedOverrideProfile: string | undefined;
|
|
370
371
|
resolvedMaxInputTokens: number | undefined;
|
|
371
372
|
}
|
|
@@ -383,6 +384,7 @@ function makeCtx(
|
|
|
383
384
|
captured.push({
|
|
384
385
|
callSite: options.callSite,
|
|
385
386
|
overrideProfile: options.overrideProfile,
|
|
387
|
+
forceOverrideProfile: options.forceOverrideProfile,
|
|
386
388
|
resolvedOverrideProfile: options.resolveOverrideProfile?.(),
|
|
387
389
|
resolvedMaxInputTokens: options.resolveContextWindow?.().maxInputTokens,
|
|
388
390
|
});
|
|
@@ -620,6 +622,26 @@ describe("runAgentLoopImpl — per-conversation inferenceProfile", () => {
|
|
|
620
622
|
expect(captured.length).toBeGreaterThan(0);
|
|
621
623
|
for (const call of captured) {
|
|
622
624
|
expect(call.overrideProfile).toBe("fast");
|
|
625
|
+
expect(call.forceOverrideProfile).toBeUndefined();
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
test("explicit options.forceOverrideProfile is passed to AgentLoop.run", async () => {
|
|
630
|
+
const captured: CapturedAgentLoopRun[] = [];
|
|
631
|
+
const ctx = makeCtx(captured, {
|
|
632
|
+
conversationType: "background",
|
|
633
|
+
inferenceProfile: null,
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
await runAgentLoopImpl(ctx, "hello", "msg-1", () => {}, {
|
|
637
|
+
overrideProfile: "fast",
|
|
638
|
+
forceOverrideProfile: true,
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
expect(captured.length).toBeGreaterThan(0);
|
|
642
|
+
for (const call of captured) {
|
|
643
|
+
expect(call.overrideProfile).toBe("fast");
|
|
644
|
+
expect(call.forceOverrideProfile).toBe(true);
|
|
623
645
|
}
|
|
624
646
|
});
|
|
625
647
|
|
|
@@ -1748,6 +1748,64 @@ describe("session-agent-loop", () => {
|
|
|
1748
1748
|
// THEN the queue is drained with the loop-complete reason
|
|
1749
1749
|
expect(drainReason).toBe("loop_complete");
|
|
1750
1750
|
});
|
|
1751
|
+
|
|
1752
|
+
test("abort watchdog drives a wedged turn to its finally", async () => {
|
|
1753
|
+
// GIVEN a provider whose call wedges: it acknowledges the user cancel
|
|
1754
|
+
// (aborts the signal) but its promise never settles and never observes
|
|
1755
|
+
// the signal — the exact condition that latched `processing` true.
|
|
1756
|
+
const events: ServerMessage[] = [];
|
|
1757
|
+
const abortController = new AbortController();
|
|
1758
|
+
let drainReason: string | undefined;
|
|
1759
|
+
// The provider's call wedges on this promise. It settles only on test
|
|
1760
|
+
// teardown so the abandoned `run()` can unwind cleanly instead of leaking
|
|
1761
|
+
// background work (e.g. partial-persist debounce timers) into later tests.
|
|
1762
|
+
let releaseHang: (reason: unknown) => void = () => {};
|
|
1763
|
+
const hang = new Promise<never>((_, reject) => {
|
|
1764
|
+
releaseHang = reject;
|
|
1765
|
+
});
|
|
1766
|
+
const provider: Provider = {
|
|
1767
|
+
name: "mock-provider",
|
|
1768
|
+
sendMessage(_messages, _options) {
|
|
1769
|
+
abortController.abort();
|
|
1770
|
+
// Never observes the signal — the exact condition that latched
|
|
1771
|
+
// `processing` true before the watchdog existed.
|
|
1772
|
+
return hang;
|
|
1773
|
+
},
|
|
1774
|
+
};
|
|
1775
|
+
const ctx = makeCtx({
|
|
1776
|
+
loopProvider: provider,
|
|
1777
|
+
abortController,
|
|
1778
|
+
// Fire the watchdog quickly instead of the ~45s production default.
|
|
1779
|
+
abortWatchdogMs: 30,
|
|
1780
|
+
drainQueue: (reason: string) => {
|
|
1781
|
+
drainReason = reason;
|
|
1782
|
+
},
|
|
1783
|
+
} as unknown as Partial<Conversation>);
|
|
1784
|
+
|
|
1785
|
+
try {
|
|
1786
|
+
// WHEN the orchestrator runs the turn
|
|
1787
|
+
await runAgentLoopImpl(ctx, "hi", "msg-1", (msg) => events.push(msg));
|
|
1788
|
+
|
|
1789
|
+
// THEN the watchdog forces the turn to its finally: processing clears,
|
|
1790
|
+
// the abort controller is torn down, the queue drains, and the user
|
|
1791
|
+
// sees a cancellation (not an error).
|
|
1792
|
+
expect(ctx.isProcessing()).toBe(false);
|
|
1793
|
+
expect(ctx.abortController).toBeNull();
|
|
1794
|
+
expect(drainReason).toBe("loop_complete");
|
|
1795
|
+
expect(
|
|
1796
|
+
events.find((e) => e.type === "generation_cancelled"),
|
|
1797
|
+
).toBeDefined();
|
|
1798
|
+
expect(
|
|
1799
|
+
events.find((e) => e.type === "conversation_error"),
|
|
1800
|
+
).toBeUndefined();
|
|
1801
|
+
} finally {
|
|
1802
|
+
// Let the abandoned run() reject and unwind, then flush microtasks.
|
|
1803
|
+
releaseHang(
|
|
1804
|
+
new DOMException("The operation was aborted", "AbortError"),
|
|
1805
|
+
);
|
|
1806
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1807
|
+
}
|
|
1808
|
+
});
|
|
1751
1809
|
});
|
|
1752
1810
|
|
|
1753
1811
|
describe("stale pending surface cleanup", () => {
|
|
@@ -674,15 +674,13 @@ describe("loadFromDb metadata injection rehydration", () => {
|
|
|
674
674
|
});
|
|
675
675
|
|
|
676
676
|
test("internal-channel trusted_contact view still rehydrates memoryV2StaticBlock", async () => {
|
|
677
|
-
//
|
|
678
|
-
//
|
|
679
|
-
//
|
|
680
|
-
// arriving over the internal `"vellum"` channel
|
|
681
|
-
//
|
|
682
|
-
//
|
|
683
|
-
//
|
|
684
|
-
// rehydrate gate must match so a daemon-restart reload of the same
|
|
685
|
-
// conversation produces an identical prefix.
|
|
677
|
+
// Rehydration keys on `sourceChannel`, not `trustClass`: injection uses
|
|
678
|
+
// `shouldExposePersonalMemory`, which exposes personal memory whenever
|
|
679
|
+
// `sourceChannel === "vellum"` regardless of actor trust class. So a
|
|
680
|
+
// trusted_contact view arriving over the internal `"vellum"` channel
|
|
681
|
+
// rehydrates `memoryV2StaticBlock`. The rehydrate gate must match
|
|
682
|
+
// injection so a daemon-restart reload of the same conversation produces
|
|
683
|
+
// an identical prefix.
|
|
686
684
|
mockConversation = defaultConv();
|
|
687
685
|
mockDbMessages = [
|
|
688
686
|
{
|
|
@@ -552,3 +552,104 @@ describe("loadFromDb history repair", () => {
|
|
|
552
552
|
]);
|
|
553
553
|
});
|
|
554
554
|
});
|
|
555
|
+
|
|
556
|
+
describe("loadFromDb turn-count rehydration", () => {
|
|
557
|
+
beforeEach(() => {
|
|
558
|
+
nextMockMessageId = 1;
|
|
559
|
+
mockConversation = {
|
|
560
|
+
id: "conv-1",
|
|
561
|
+
contextSummary: null,
|
|
562
|
+
contextCompactedMessageCount: 0,
|
|
563
|
+
totalInputTokens: 0,
|
|
564
|
+
totalOutputTokens: 0,
|
|
565
|
+
totalEstimatedCost: 0,
|
|
566
|
+
};
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
const userText = (text: string) => ({
|
|
570
|
+
role: "user",
|
|
571
|
+
content: JSON.stringify([{ type: "text", text }]),
|
|
572
|
+
});
|
|
573
|
+
const assistantText = (text: string) => ({
|
|
574
|
+
role: "assistant",
|
|
575
|
+
content: JSON.stringify([{ type: "text", text }]),
|
|
576
|
+
});
|
|
577
|
+
const assistantToolUse = (id: string) => ({
|
|
578
|
+
role: "assistant",
|
|
579
|
+
content: JSON.stringify([
|
|
580
|
+
{ type: "tool_use", id, name: "bash", input: { cmd: "ls" } },
|
|
581
|
+
]),
|
|
582
|
+
});
|
|
583
|
+
const toolResult = (id: string) => ({
|
|
584
|
+
role: "user",
|
|
585
|
+
content: JSON.stringify([
|
|
586
|
+
{ type: "tool_result", tool_use_id: id, content: "ok" },
|
|
587
|
+
]),
|
|
588
|
+
});
|
|
589
|
+
const withIds = (msgs: Array<{ role: string; content: string }>) =>
|
|
590
|
+
msgs.map((m, i) => ({ id: `m${i}`, ...m }));
|
|
591
|
+
|
|
592
|
+
test("restores turnCount from persisted history rather than resetting to 0", async () => {
|
|
593
|
+
// Three completed human turns persisted before this conversation object
|
|
594
|
+
// was (re)created — e.g. after an idle eviction or daemon restart.
|
|
595
|
+
mockDbMessages = withIds([
|
|
596
|
+
userText("Hello"),
|
|
597
|
+
assistantText("Hi"),
|
|
598
|
+
userText("How are you?"),
|
|
599
|
+
assistantText("Good"),
|
|
600
|
+
userText("Bye"),
|
|
601
|
+
assistantText("Later"),
|
|
602
|
+
]);
|
|
603
|
+
|
|
604
|
+
const conversation = makeConversation();
|
|
605
|
+
// Fresh object starts at 0 (the bug: it would stay 0 after reload).
|
|
606
|
+
expect(conversation.turnCount).toBe(0);
|
|
607
|
+
|
|
608
|
+
await conversation.loadFromDb();
|
|
609
|
+
|
|
610
|
+
expect(conversation.turnCount).toBe(3);
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
test("counts a multi-iteration tool-use turn as a single turn", async () => {
|
|
614
|
+
// One real user message; the tool_result user messages are continuations
|
|
615
|
+
// within the same turn, not new turns.
|
|
616
|
+
mockDbMessages = withIds([
|
|
617
|
+
userText("convert the voice memo"),
|
|
618
|
+
assistantToolUse("tu_1"),
|
|
619
|
+
toolResult("tu_1"),
|
|
620
|
+
assistantToolUse("tu_2"),
|
|
621
|
+
toolResult("tu_2"),
|
|
622
|
+
assistantText("done"),
|
|
623
|
+
]);
|
|
624
|
+
|
|
625
|
+
const conversation = makeConversation();
|
|
626
|
+
await conversation.loadFromDb();
|
|
627
|
+
|
|
628
|
+
expect(conversation.turnCount).toBe(1);
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
test("counts only real user turns when tool iterations are interleaved", async () => {
|
|
632
|
+
mockDbMessages = withIds([
|
|
633
|
+
userText("q1"),
|
|
634
|
+
assistantToolUse("tu_1"),
|
|
635
|
+
toolResult("tu_1"),
|
|
636
|
+
assistantText("a1"),
|
|
637
|
+
userText("q2"),
|
|
638
|
+
assistantText("a2"),
|
|
639
|
+
]);
|
|
640
|
+
|
|
641
|
+
const conversation = makeConversation();
|
|
642
|
+
await conversation.loadFromDb();
|
|
643
|
+
|
|
644
|
+
expect(conversation.turnCount).toBe(2);
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
test("empty history yields turnCount 0", async () => {
|
|
648
|
+
mockDbMessages = [];
|
|
649
|
+
|
|
650
|
+
const conversation = makeConversation();
|
|
651
|
+
await conversation.loadFromDb();
|
|
652
|
+
|
|
653
|
+
expect(conversation.turnCount).toBe(0);
|
|
654
|
+
});
|
|
655
|
+
});
|
|
@@ -222,13 +222,16 @@ describe("handleSendMessage canonical guardian reply interception", () => {
|
|
|
222
222
|
const routerCall = (routeGuardianReplyMock as any).mock
|
|
223
223
|
.calls[0][0] as Record<string, unknown>;
|
|
224
224
|
expect(routerCall.messageText).toBe("05BECB approve");
|
|
225
|
-
expect(routerCall.
|
|
225
|
+
expect(routerCall.pendingScope).toEqual({
|
|
226
|
+
mode: "scoped",
|
|
227
|
+
requestIds: ["access-req-1"],
|
|
228
|
+
});
|
|
226
229
|
expect(addMessageMock).toHaveBeenCalledTimes(2);
|
|
227
230
|
expect(persistUserMessage).toHaveBeenCalledTimes(0);
|
|
228
231
|
expect(runAgentLoop).toHaveBeenCalledTimes(0);
|
|
229
232
|
});
|
|
230
233
|
|
|
231
|
-
test("passes
|
|
234
|
+
test("passes a blocked scope when no canonical hints are found", async () => {
|
|
232
235
|
listPendingByDestinationMock.mockReturnValue([]);
|
|
233
236
|
listCanonicalMock.mockReturnValue([]);
|
|
234
237
|
routeGuardianReplyMock.mockResolvedValue({
|
|
@@ -301,7 +304,7 @@ describe("handleSendMessage canonical guardian reply interception", () => {
|
|
|
301
304
|
expect(routeGuardianReplyMock).toHaveBeenCalledTimes(1);
|
|
302
305
|
const routerCall = (routeGuardianReplyMock as any).mock
|
|
303
306
|
.calls[0][0] as Record<string, unknown>;
|
|
304
|
-
expect(routerCall.
|
|
307
|
+
expect(routerCall.pendingScope).toEqual({ mode: "blocked" });
|
|
305
308
|
expect(persistUserMessage).toHaveBeenCalledTimes(1);
|
|
306
309
|
expect(runAgentLoop).toHaveBeenCalledTimes(1);
|
|
307
310
|
});
|
|
@@ -384,15 +387,15 @@ describe("handleSendMessage canonical guardian reply interception", () => {
|
|
|
384
387
|
expect(routeGuardianReplyMock).toHaveBeenCalledTimes(1);
|
|
385
388
|
const routerCall = (routeGuardianReplyMock as any).mock
|
|
386
389
|
.calls[0][0] as Record<string, unknown>;
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
expect(
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
).toBe(false);
|
|
390
|
+
const scope = routerCall.pendingScope as {
|
|
391
|
+
mode: string;
|
|
392
|
+
requestIds: string[];
|
|
393
|
+
};
|
|
394
|
+
expect(scope).toEqual({
|
|
395
|
+
mode: "scoped",
|
|
396
|
+
requestIds: ["tool-approval-live", "access-req-1"],
|
|
397
|
+
});
|
|
398
|
+
expect(scope.requestIds.includes("tool-approval-stale")).toBe(false);
|
|
396
399
|
});
|
|
397
400
|
|
|
398
401
|
test("text fallback: request-code approve routes through guardian reply router", async () => {
|
|
@@ -10,9 +10,11 @@ mock.module("../util/logger.js", () => ({
|
|
|
10
10
|
}),
|
|
11
11
|
}));
|
|
12
12
|
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
// Analytics consent is granted so recordActivationEvent writes rows.
|
|
14
|
+
let shareAnalytics = true;
|
|
15
|
+
|
|
16
|
+
mock.module("../platform/consent-cache.js", () => ({
|
|
17
|
+
getCachedShareAnalytics: () => shareAnalytics,
|
|
16
18
|
}));
|
|
17
19
|
|
|
18
20
|
let broadcastedMessages: ServerMessage[] = [];
|
|
@@ -117,6 +119,7 @@ async function showTaggedChoice(
|
|
|
117
119
|
|
|
118
120
|
describe("activation moment emission from ui_show surface commits", () => {
|
|
119
121
|
beforeEach(() => {
|
|
122
|
+
shareAnalytics = true;
|
|
120
123
|
broadcastedMessages = [];
|
|
121
124
|
resetTables();
|
|
122
125
|
});
|
|
@@ -69,10 +69,38 @@ import {
|
|
|
69
69
|
describe("conversation-title-service", () => {
|
|
70
70
|
beforeEach(() => {
|
|
71
71
|
mockRunBtwSidechain.mockClear();
|
|
72
|
+
mockRunBtwSidechain.mockImplementation(
|
|
73
|
+
async (_params: Record<string, unknown>) => ({
|
|
74
|
+
text: "Project kickoff",
|
|
75
|
+
hadTextDeltas: true,
|
|
76
|
+
response: {
|
|
77
|
+
content: [{ type: "text", text: "Project kickoff" }],
|
|
78
|
+
model: "test-model",
|
|
79
|
+
usage: { inputTokens: 10, outputTokens: 5 },
|
|
80
|
+
stopReason: "end_turn",
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
);
|
|
72
84
|
mockGetConversation.mockClear();
|
|
85
|
+
mockGetConversation.mockImplementation(
|
|
86
|
+
(_conversationId: string) =>
|
|
87
|
+
({
|
|
88
|
+
title: "Generating title...",
|
|
89
|
+
isAutoTitle: 1,
|
|
90
|
+
}) as {
|
|
91
|
+
title: string;
|
|
92
|
+
isAutoTitle: number;
|
|
93
|
+
},
|
|
94
|
+
);
|
|
73
95
|
mockGetMessages.mockClear();
|
|
96
|
+
mockGetMessages.mockImplementation(() => [
|
|
97
|
+
{ role: "user", content: "first message" },
|
|
98
|
+
{ role: "assistant", content: "first reply" },
|
|
99
|
+
{ role: "user", content: "follow-up" },
|
|
100
|
+
]);
|
|
74
101
|
mockUpdateConversationTitle.mockClear();
|
|
75
102
|
mockGetConfiguredProvider.mockClear();
|
|
103
|
+
mockGetConfiguredProvider.mockImplementation(async () => null);
|
|
76
104
|
mockPublishConversationTitleChanged.mockClear();
|
|
77
105
|
});
|
|
78
106
|
|
|
@@ -232,6 +260,30 @@ describe("conversation-title-service", () => {
|
|
|
232
260
|
);
|
|
233
261
|
});
|
|
234
262
|
|
|
263
|
+
test("fallback retry skips regeneration after a successful initial title", async () => {
|
|
264
|
+
mockGetConversation.mockReturnValueOnce({
|
|
265
|
+
title: "Project kickoff",
|
|
266
|
+
isAutoTitle: 1,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const provider = {
|
|
270
|
+
name: "test-provider",
|
|
271
|
+
sendMessage: mock(async () => {
|
|
272
|
+
throw new Error("should not call directly");
|
|
273
|
+
}),
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const result = await regenerateConversationTitle({
|
|
277
|
+
conversationId: "conv-1",
|
|
278
|
+
provider,
|
|
279
|
+
onlyIfReplaceable: true,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
expect(result).toEqual({ title: "Project kickoff", updated: false });
|
|
283
|
+
expect(mockRunBtwSidechain).not.toHaveBeenCalled();
|
|
284
|
+
expect(mockUpdateConversationTitle).not.toHaveBeenCalled();
|
|
285
|
+
});
|
|
286
|
+
|
|
235
287
|
test("rejects meta-failure outputs like 'Missing Context' and uses fallback", async () => {
|
|
236
288
|
mockRunBtwSidechain.mockImplementationOnce(async () => ({
|
|
237
289
|
text: "Missing Context",
|
|
@@ -482,6 +534,16 @@ describe("conversation-title-service", () => {
|
|
|
482
534
|
|
|
483
535
|
// Both calls went through — failure didn't break the chain
|
|
484
536
|
expect(mockRunBtwSidechain).toHaveBeenCalledTimes(2);
|
|
537
|
+
const firstUpdate = (
|
|
538
|
+
mockUpdateConversationTitle.mock.calls as unknown as Array<
|
|
539
|
+
[string, string, number?]
|
|
540
|
+
>
|
|
541
|
+
).find((c) => c[0] === "conv-1");
|
|
542
|
+
expect(firstUpdate).toEqual([
|
|
543
|
+
"conv-1",
|
|
544
|
+
"Untitled Conversation",
|
|
545
|
+
AUTO_TITLE_DETERMINISTIC,
|
|
546
|
+
]);
|
|
485
547
|
// Second conversation got a proper title
|
|
486
548
|
const secondUpdate = (
|
|
487
549
|
mockUpdateConversationTitle.mock.calls as unknown as string[][]
|