@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
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { and, asc, eq, gt, lt, lte, or, sql } from "drizzle-orm";
|
|
2
|
+
|
|
3
|
+
import { findConversation } from "../daemon/conversation-registry.js";
|
|
4
|
+
import type {
|
|
5
|
+
TurnTrace,
|
|
6
|
+
TurnTraceMessage,
|
|
7
|
+
TurnTraceToolCall,
|
|
8
|
+
} from "../telemetry/types.js";
|
|
9
|
+
import { getLogger } from "../util/logger.js";
|
|
10
|
+
import { getDb } from "./db-connection.js";
|
|
11
|
+
import { messages, toolInvocations } from "./schema.js";
|
|
12
|
+
|
|
13
|
+
const log = getLogger("turn-trace-store");
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* SQL fragment that excludes tool-result rows persisted with role="user".
|
|
17
|
+
* Duplicated from `turn-events-store.ts` on purpose: a turn boundary in the
|
|
18
|
+
* trace must use exactly the same notion of "real user turn" the eligibility
|
|
19
|
+
* predicate / `turn_index` count use, so the trace window can never disagree
|
|
20
|
+
* with the `turn` event it rides on. `<alias>` is interpolated as the SQL
|
|
21
|
+
* identifier for the table whose `content` column is filtered.
|
|
22
|
+
*/
|
|
23
|
+
function realUserTurnContentFilter(alias: string): ReturnType<typeof sql> {
|
|
24
|
+
return sql.raw(
|
|
25
|
+
`${alias}.content NOT LIKE '%"type":"tool\\_result"%' ESCAPE '\\' ` +
|
|
26
|
+
`AND ${alias}.content NOT LIKE '%"type":"web\\_search\\_tool\\_result"%' ESCAPE '\\'`,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Identifies the user message a trace is being assembled for. Mirrors the
|
|
32
|
+
* `(createdAt, id)` compound cursor the turn-event stream uses so the window
|
|
33
|
+
* boundaries line up exactly.
|
|
34
|
+
*/
|
|
35
|
+
export interface TurnTraceBoundary {
|
|
36
|
+
conversationId: string;
|
|
37
|
+
/** `messages.id` of the real user turn that opens this turn. */
|
|
38
|
+
userMessageId: string;
|
|
39
|
+
/** `messages.created_at` of that user message. */
|
|
40
|
+
userMessageCreatedAt: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Parse a stored `messages.content` string into its JSON value, verbatim. */
|
|
44
|
+
function parseStoredContent(raw: string): unknown {
|
|
45
|
+
try {
|
|
46
|
+
return JSON.parse(raw) as unknown;
|
|
47
|
+
} catch {
|
|
48
|
+
// Legacy rows stored a plain (non-JSON) string. Forward as-is.
|
|
49
|
+
return raw;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Compound `(createdAt, id)` boundary of the next real user turn. */
|
|
54
|
+
interface NextTurnBoundary {
|
|
55
|
+
createdAt: number;
|
|
56
|
+
id: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Find the next real user turn strictly after the given boundary in the same
|
|
61
|
+
* conversation, by the same `(createdAt, id)` cursor the turn-event stream
|
|
62
|
+
* uses. Returns `null` when the boundary is the latest real user turn (the
|
|
63
|
+
* window then runs to the end of the conversation).
|
|
64
|
+
*
|
|
65
|
+
* Returns the next turn's `id` alongside its `createdAt` so the window upper
|
|
66
|
+
* bound is a compound `(createdAt, id)` comparison. Two real user messages can
|
|
67
|
+
* share a `created_at` (forked conversations preserve the source `created_at`
|
|
68
|
+
* with fresh ids; `monotonicNow()` only guarantees monotonicity within a single
|
|
69
|
+
* process), so a timestamp-only upper bound would equal the current turn's own
|
|
70
|
+
* `created_at` and truncate the trace.
|
|
71
|
+
*
|
|
72
|
+
* "Next real user turn" excludes tool-result rows persisted with role="user"
|
|
73
|
+
* (same filter as the turn-event stream), so a turn that issued tool calls —
|
|
74
|
+
* whose results land as role="user" rows — is not truncated at its own tool
|
|
75
|
+
* results.
|
|
76
|
+
*/
|
|
77
|
+
function nextRealUserTurn(
|
|
78
|
+
boundary: TurnTraceBoundary,
|
|
79
|
+
): NextTurnBoundary | null {
|
|
80
|
+
const db = getDb();
|
|
81
|
+
const row = db
|
|
82
|
+
.select({ createdAt: messages.createdAt, id: messages.id })
|
|
83
|
+
.from(messages)
|
|
84
|
+
.where(
|
|
85
|
+
and(
|
|
86
|
+
eq(messages.conversationId, boundary.conversationId),
|
|
87
|
+
eq(messages.role, "user"),
|
|
88
|
+
realUserTurnContentFilter("messages"),
|
|
89
|
+
or(
|
|
90
|
+
gt(messages.createdAt, boundary.userMessageCreatedAt),
|
|
91
|
+
and(
|
|
92
|
+
eq(messages.createdAt, boundary.userMessageCreatedAt),
|
|
93
|
+
gt(messages.id, boundary.userMessageId),
|
|
94
|
+
),
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
.orderBy(asc(messages.createdAt), asc(messages.id))
|
|
99
|
+
.limit(1)
|
|
100
|
+
.get();
|
|
101
|
+
return row ?? null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Whether a turn is COMPLETE — its own assistant response has finished and the
|
|
106
|
+
* full transcript is durably persisted — so its trace can be assembled without
|
|
107
|
+
* risk of capturing a partial mid-turn snapshot.
|
|
108
|
+
*
|
|
109
|
+
* A turn is settled iff its live conversation is not actively processing.
|
|
110
|
+
* `Conversation.isProcessing()` is flipped to `false` in the agent-loop
|
|
111
|
+
* `finally` *after* the awaited turn-boundary commit, so a non-processing
|
|
112
|
+
* conversation has no in-flight response and all of its persisted turn rows are
|
|
113
|
+
* durable. A conversation absent from the live registry (evicted, or never
|
|
114
|
+
* loaded this process) has no in-flight turn either, so it reads as settled —
|
|
115
|
+
* including after a restart, where a turn that was mid-flight when the process
|
|
116
|
+
* died reads as settled because no more rows are coming.
|
|
117
|
+
*
|
|
118
|
+
* Why this gates on processing for EVERY turn, not just the latest: a
|
|
119
|
+
* "successor real user turn exists ⟹ settled" shortcut is unsound in the
|
|
120
|
+
* batched-message path. When queued messages drain as a batch, `drainBatch`
|
|
121
|
+
* (daemon/conversation-process.ts) persists the head user row AND the tail user
|
|
122
|
+
* rows up front, then runs ONE shared `runAgentLoop` whose response is
|
|
123
|
+
* broadcast to all of them. So the batched HEAD turn has a later real user row
|
|
124
|
+
* (a tail) while the shared response and its tool calls are still in flight —
|
|
125
|
+
* the shortcut would mark the head settled and ship a trace missing the shared
|
|
126
|
+
* response, never retried. Gating on `isProcessing()` defers the head (and any
|
|
127
|
+
* backlog) until the shared response completes and the conversation goes idle.
|
|
128
|
+
*
|
|
129
|
+
* Turns are serialized per conversation and `isProcessing()` is per-response,
|
|
130
|
+
* so the conversation is idle between turns and completed past turns settle
|
|
131
|
+
* promptly; the only cost is that a just-finished turn waits for the current
|
|
132
|
+
* response when one started before it could be reported — minimal latency,
|
|
133
|
+
* preferred over shipping a partial trace.
|
|
134
|
+
*
|
|
135
|
+
* The `isProcessing()` read relies on the daemon's in-memory state, so the
|
|
136
|
+
* reporter and the agent loop share one process (they do — both live in the
|
|
137
|
+
* daemon).
|
|
138
|
+
*/
|
|
139
|
+
export function isTurnSettled(boundary: TurnTraceBoundary): boolean {
|
|
140
|
+
return findConversation(boundary.conversationId)?.isProcessing() !== true;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Message rows belonging to the turn window, oldest-first. */
|
|
144
|
+
function queryTurnMessages(
|
|
145
|
+
boundary: TurnTraceBoundary,
|
|
146
|
+
nextTurn: NextTurnBoundary | null,
|
|
147
|
+
): TurnTraceMessage[] {
|
|
148
|
+
const db = getDb();
|
|
149
|
+
// Lower bound: the user message itself (inclusive), using the same
|
|
150
|
+
// `(createdAt, id)` lex-comparison as the cursor so a row sharing the
|
|
151
|
+
// user message's millisecond isn't dropped.
|
|
152
|
+
const lowerBound = or(
|
|
153
|
+
gt(messages.createdAt, boundary.userMessageCreatedAt),
|
|
154
|
+
and(
|
|
155
|
+
eq(messages.createdAt, boundary.userMessageCreatedAt),
|
|
156
|
+
sql`${messages.id} >= ${boundary.userMessageId}`,
|
|
157
|
+
),
|
|
158
|
+
);
|
|
159
|
+
// Upper bound: strictly before the next real user turn, using the same
|
|
160
|
+
// compound `(createdAt, id)` comparison. A timestamp-only bound would empty
|
|
161
|
+
// the window when the next user turn shares this turn's `created_at`.
|
|
162
|
+
const upperBound =
|
|
163
|
+
nextTurn == null
|
|
164
|
+
? undefined
|
|
165
|
+
: or(
|
|
166
|
+
lt(messages.createdAt, nextTurn.createdAt),
|
|
167
|
+
and(
|
|
168
|
+
eq(messages.createdAt, nextTurn.createdAt),
|
|
169
|
+
sql`${messages.id} < ${nextTurn.id}`,
|
|
170
|
+
),
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const rows = db
|
|
174
|
+
.select({
|
|
175
|
+
id: messages.id,
|
|
176
|
+
role: messages.role,
|
|
177
|
+
content: messages.content,
|
|
178
|
+
createdAt: messages.createdAt,
|
|
179
|
+
})
|
|
180
|
+
.from(messages)
|
|
181
|
+
.where(
|
|
182
|
+
and(
|
|
183
|
+
eq(messages.conversationId, boundary.conversationId),
|
|
184
|
+
lowerBound,
|
|
185
|
+
...(upperBound ? [upperBound] : []),
|
|
186
|
+
),
|
|
187
|
+
)
|
|
188
|
+
.orderBy(asc(messages.createdAt), asc(messages.id))
|
|
189
|
+
.all();
|
|
190
|
+
|
|
191
|
+
return rows.map((r) => ({
|
|
192
|
+
id: r.id,
|
|
193
|
+
role: r.role,
|
|
194
|
+
created_at: r.createdAt,
|
|
195
|
+
content: parseStoredContent(r.content),
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Parse a stored tool-invocation input verbatim.
|
|
201
|
+
*
|
|
202
|
+
* The consented trace is full-fidelity: the input is forwarded exactly as
|
|
203
|
+
* stored (structured JSON when it parses, raw string otherwise — symmetric
|
|
204
|
+
* with how message content is handled). No field-level redaction is applied;
|
|
205
|
+
* the protections for this PII are the consent gate, the PII-segregated
|
|
206
|
+
* `pii_turn_raw` table, and its 30-day TTL.
|
|
207
|
+
*/
|
|
208
|
+
function parseToolInput(raw: string): unknown {
|
|
209
|
+
try {
|
|
210
|
+
return JSON.parse(raw) as unknown;
|
|
211
|
+
} catch {
|
|
212
|
+
// Non-JSON input — forward the raw string verbatim.
|
|
213
|
+
return raw;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Tool invocations recorded inside the turn window, oldest-first.
|
|
219
|
+
*
|
|
220
|
+
* `tool_invocations` has no message-id link and its ids are unrelated to
|
|
221
|
+
* `messages.id`, so the window is correlated purely by `created_at`:
|
|
222
|
+
* `[userMessageCreatedAt, nextTurn.createdAt)`. The lower bound is inclusive
|
|
223
|
+
* (a tool can fire in the same millisecond as the user message).
|
|
224
|
+
*
|
|
225
|
+
* Degenerate same-`created_at` case: when the next real user turn shares this
|
|
226
|
+
* turn's `created_at`, a strict `<` upper bound yields an empty `[X, X)` window
|
|
227
|
+
* and drops this turn's same-millisecond tools. In that case the upper bound is
|
|
228
|
+
* widened to `<=` so those tools are retained. Same-millisecond tools cannot be
|
|
229
|
+
* attributed to one of two colliding user turns by timestamp alone; including
|
|
230
|
+
* them in the earlier turn matches the message window (which keeps this turn's
|
|
231
|
+
* rows at that millisecond) and is the conservative choice for a diagnostic
|
|
232
|
+
* trace.
|
|
233
|
+
*/
|
|
234
|
+
function queryTurnToolCalls(
|
|
235
|
+
boundary: TurnTraceBoundary,
|
|
236
|
+
nextTurn: NextTurnBoundary | null,
|
|
237
|
+
): TurnTraceToolCall[] {
|
|
238
|
+
const db = getDb();
|
|
239
|
+
let upperBound;
|
|
240
|
+
if (nextTurn == null) {
|
|
241
|
+
upperBound = undefined;
|
|
242
|
+
} else if (nextTurn.createdAt <= boundary.userMessageCreatedAt) {
|
|
243
|
+
// Next turn collides on (or, defensively, predates) this turn's
|
|
244
|
+
// millisecond — keep tools at that millisecond instead of emptying the
|
|
245
|
+
// window.
|
|
246
|
+
upperBound = lte(toolInvocations.createdAt, nextTurn.createdAt);
|
|
247
|
+
} else {
|
|
248
|
+
upperBound = lt(toolInvocations.createdAt, nextTurn.createdAt);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const rows = db
|
|
252
|
+
.select({
|
|
253
|
+
id: toolInvocations.id,
|
|
254
|
+
toolName: toolInvocations.toolName,
|
|
255
|
+
input: toolInvocations.input,
|
|
256
|
+
result: toolInvocations.result,
|
|
257
|
+
decision: toolInvocations.decision,
|
|
258
|
+
durationMs: toolInvocations.durationMs,
|
|
259
|
+
createdAt: toolInvocations.createdAt,
|
|
260
|
+
})
|
|
261
|
+
.from(toolInvocations)
|
|
262
|
+
.where(
|
|
263
|
+
and(
|
|
264
|
+
eq(toolInvocations.conversationId, boundary.conversationId),
|
|
265
|
+
sql`${toolInvocations.createdAt} >= ${boundary.userMessageCreatedAt}`,
|
|
266
|
+
...(upperBound ? [upperBound] : []),
|
|
267
|
+
),
|
|
268
|
+
)
|
|
269
|
+
.orderBy(asc(toolInvocations.createdAt), asc(toolInvocations.id))
|
|
270
|
+
.all();
|
|
271
|
+
|
|
272
|
+
return rows.map((r) => ({
|
|
273
|
+
id: r.id,
|
|
274
|
+
tool_name: r.toolName,
|
|
275
|
+
input: parseToolInput(r.input),
|
|
276
|
+
result: r.result,
|
|
277
|
+
decision: r.decision,
|
|
278
|
+
duration_ms: r.durationMs,
|
|
279
|
+
created_at: r.createdAt,
|
|
280
|
+
}));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Assemble the full transcript for one turn: the user message, the assistant
|
|
285
|
+
* response message(s), any intervening tool-result rows, and the tool
|
|
286
|
+
* invocations recorded for the turn — bounded to the window between this real
|
|
287
|
+
* user turn and the next one.
|
|
288
|
+
*
|
|
289
|
+
* The trace is each turn's natural window. A turn whose own window holds no
|
|
290
|
+
* assistant response (a coalesced-batch head, or a turn that failed/cancelled
|
|
291
|
+
* before producing a response) traces user-only, which is faithful: its window
|
|
292
|
+
* genuinely has no response. A coalesced batch's shared response lives on the
|
|
293
|
+
* batch's FINAL turn's window — exactly where the daemon already attributes it
|
|
294
|
+
* (via `lastUserMessageId` / `llm_usage` / `turn_index`). There is no durable
|
|
295
|
+
* batch signal in the stored messages to distinguish a real batch from a
|
|
296
|
+
* failed/cancelled turn, so no batch inference is attempted.
|
|
297
|
+
*
|
|
298
|
+
* Read-only; touches only existing tables (`messages`, `tool_invocations`), so
|
|
299
|
+
* no migration is involved. Caller is responsible for the consent gate and the
|
|
300
|
+
* serialized-size cap — this function always returns a faithful trace for the
|
|
301
|
+
* window.
|
|
302
|
+
*/
|
|
303
|
+
export function assembleTurnTrace(boundary: TurnTraceBoundary): TurnTrace {
|
|
304
|
+
const nextTurn = nextRealUserTurn(boundary);
|
|
305
|
+
return {
|
|
306
|
+
schema_version: 1,
|
|
307
|
+
messages: queryTurnMessages(boundary, nextTurn),
|
|
308
|
+
tool_calls: queryTurnToolCalls(boundary, nextTurn),
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Maximum serialized size of a trace the platform will accept (it drops traces
|
|
314
|
+
* whose JSON exceeds ~256 KiB). Keep the daemon-side cap a touch under that so
|
|
315
|
+
* we never ship a trace the platform will silently drop. A trace over the cap
|
|
316
|
+
* is omitted entirely (the trace-free turn row still flushes).
|
|
317
|
+
*/
|
|
318
|
+
export const MAX_TRACE_SERIALIZED_BYTES = 256 * 1024;
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Assemble a turn trace and serialize it, returning the JSON-ready object only
|
|
322
|
+
* when it fits under {@link MAX_TRACE_SERIALIZED_BYTES}. Returns `null` (no
|
|
323
|
+
* trace) when assembly fails or the trace is too large — both fail-closed so a
|
|
324
|
+
* single oversized/broken turn never blocks the turn event from flushing.
|
|
325
|
+
*/
|
|
326
|
+
export function assembleBoundedTurnTrace(
|
|
327
|
+
boundary: TurnTraceBoundary,
|
|
328
|
+
): TurnTrace | null {
|
|
329
|
+
let trace: TurnTrace;
|
|
330
|
+
try {
|
|
331
|
+
trace = assembleTurnTrace(boundary);
|
|
332
|
+
} catch (err) {
|
|
333
|
+
log.warn(
|
|
334
|
+
{ err, conversationId: boundary.conversationId },
|
|
335
|
+
"Failed to assemble turn trace — omitting trace for this turn",
|
|
336
|
+
);
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
let serializedBytes: number;
|
|
341
|
+
try {
|
|
342
|
+
serializedBytes = Buffer.byteLength(JSON.stringify(trace), "utf8");
|
|
343
|
+
} catch (err) {
|
|
344
|
+
log.warn(
|
|
345
|
+
{ err, conversationId: boundary.conversationId },
|
|
346
|
+
"Failed to serialize turn trace — omitting trace for this turn",
|
|
347
|
+
);
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (serializedBytes > MAX_TRACE_SERIALIZED_BYTES) {
|
|
352
|
+
log.debug(
|
|
353
|
+
{
|
|
354
|
+
conversationId: boundary.conversationId,
|
|
355
|
+
serializedBytes,
|
|
356
|
+
cap: MAX_TRACE_SERIALIZED_BYTES,
|
|
357
|
+
},
|
|
358
|
+
"Turn trace exceeds size cap — omitting trace for this turn",
|
|
359
|
+
);
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return trace;
|
|
364
|
+
}
|
|
@@ -117,6 +117,14 @@ mock.module("../../../config/assistant-feature-flags.js", () => ({
|
|
|
117
117
|
isAssistantFeatureFlagEnabled: (key: string) => flagStates[key] ?? v3FlagOn,
|
|
118
118
|
}));
|
|
119
119
|
|
|
120
|
+
// The v3-live gate moved to config (`config.memory.v3.live`), read via
|
|
121
|
+
// `isMemoryV3Live`. Mirror the flag mock so the shadow-vs-live tests keep
|
|
122
|
+
// driving live through `flagStates["memory-v3-live"]` (and `v3FlagOn` toggles
|
|
123
|
+
// it alongside shadow for the existing on/off tests).
|
|
124
|
+
mock.module("../../../config/memory-v3-gate.js", () => ({
|
|
125
|
+
isMemoryV3Live: () => flagStates["memory-v3-live"] ?? v3FlagOn,
|
|
126
|
+
}));
|
|
127
|
+
|
|
120
128
|
// ── Workspace pin ───────────────────────────────────────────────────
|
|
121
129
|
let tmpWorkspace: string;
|
|
122
130
|
let previousWorkspaceEnv: string | undefined;
|
|
@@ -45,6 +45,36 @@ describe("buildSkillContent", () => {
|
|
|
45
45
|
const out = buildSkillContent(input);
|
|
46
46
|
expect(out.length).toBeLessThanOrEqual(500);
|
|
47
47
|
});
|
|
48
|
+
|
|
49
|
+
test("respects a larger maxChars budget", async () => {
|
|
50
|
+
const { buildSkillContent } = await import("../skill-content.js");
|
|
51
|
+
const input: SkillCapabilityInput = {
|
|
52
|
+
id: "example-skill",
|
|
53
|
+
displayName: "Example Skill",
|
|
54
|
+
description: "x".repeat(1000),
|
|
55
|
+
};
|
|
56
|
+
const out = buildSkillContent(input, 900);
|
|
57
|
+
expect(out.length).toBeLessThanOrEqual(900);
|
|
58
|
+
expect(out.length).toBeGreaterThan(500);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("renders hints as a bulleted list when the budget is enlarged", async () => {
|
|
62
|
+
const { buildSkillContent } = await import("../skill-content.js");
|
|
63
|
+
const input: SkillCapabilityInput = {
|
|
64
|
+
id: "wf",
|
|
65
|
+
displayName: "Workflows",
|
|
66
|
+
description: "Delegate a big job",
|
|
67
|
+
activationHints: ["Batch many items", "Exhaustive sweep"],
|
|
68
|
+
avoidWhen: ["A single lookup"],
|
|
69
|
+
};
|
|
70
|
+
const rich = buildSkillContent(input, 900);
|
|
71
|
+
expect(rich).toContain("Use when:\n- Batch many items\n- Exhaustive sweep");
|
|
72
|
+
expect(rich).toContain("Avoid when:\n- A single lookup");
|
|
73
|
+
// The default (500) budget keeps the compact inline form.
|
|
74
|
+
expect(buildSkillContent(input)).toContain(
|
|
75
|
+
"Use when: Batch many items; Exhaustive sweep.",
|
|
76
|
+
);
|
|
77
|
+
});
|
|
48
78
|
});
|
|
49
79
|
|
|
50
80
|
describe("augmentMcpSetupDescription", () => {
|
|
@@ -65,6 +65,7 @@ import {
|
|
|
65
65
|
import { dirname, join } from "node:path";
|
|
66
66
|
|
|
67
67
|
import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
|
|
68
|
+
import { isMemoryV3Live } from "../../config/memory-v3-gate.js";
|
|
68
69
|
import type { AssistantConfig } from "../../config/types.js";
|
|
69
70
|
import { runBackgroundJob } from "../../runtime/background-job-runner.js";
|
|
70
71
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -89,7 +90,6 @@ const JOB_NAME = "memory.consolidate";
|
|
|
89
90
|
* post-consolidation follow-up. These gate the v3 plugin itself.
|
|
90
91
|
*/
|
|
91
92
|
const MEMORY_V3_SHADOW = "memory-v3-shadow" as const;
|
|
92
|
-
const MEMORY_V3_LIVE = "memory-v3-live" as const;
|
|
93
93
|
|
|
94
94
|
/**
|
|
95
95
|
* Hard timeout for the consolidation run. Consolidation reads the buffer,
|
|
@@ -269,7 +269,7 @@ export async function memoryV2ConsolidateJob(
|
|
|
269
269
|
// The article SHAPE is keyed on the live flag alone: under shadow, live
|
|
270
270
|
// prompts are still assembled by v2's injection model, so consolidation
|
|
271
271
|
// must keep producing `summary:`-bearing fragment pages until the flip.
|
|
272
|
-
const memoryV3Live =
|
|
272
|
+
const memoryV3Live = isMemoryV3Live(config);
|
|
273
273
|
const memoryV3Active =
|
|
274
274
|
isAssistantFeatureFlagEnabled(MEMORY_V3_SHADOW, config) || memoryV3Live;
|
|
275
275
|
const prompt = resolveConsolidationPrompt(
|
|
@@ -1,22 +1,40 @@
|
|
|
1
1
|
import { getConfig } from "../../config/loader.js";
|
|
2
2
|
import type { SkillCapabilityInput } from "../../skills/skill-memory.js";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Character budget for an always-candidate skill's capability statement. Larger
|
|
6
|
+
* than the default so a cross-cutting skill (pinned into the selector pool every
|
|
7
|
+
* turn) can describe its full range of uses rather than a single mode — see
|
|
8
|
+
* `buildSkillContent`'s `maxChars` and `skill-store.ts`'s seeding loop.
|
|
9
|
+
*/
|
|
10
|
+
export const ALWAYS_CANDIDATE_CARD_CHARS = 900;
|
|
11
|
+
|
|
4
12
|
/**
|
|
5
13
|
* Render the prose-style capability statement embedded into the unified
|
|
6
14
|
* `memory_v2_concept_pages` Qdrant collection (under the `skills/<id>` slug
|
|
7
|
-
* prefix) and rendered in `### Skills You Can Use
|
|
8
|
-
*
|
|
15
|
+
* prefix) and rendered in `### Skills You Can Use` / the memory-v3 selector
|
|
16
|
+
* card. Capped at `maxChars` (default 500). A larger budget switches the hints
|
|
17
|
+
* to a bulleted list — easier for the selector to parse one mode per line — so
|
|
18
|
+
* always-candidate skills can carry a fuller, multi-mode description.
|
|
9
19
|
*/
|
|
10
|
-
export function buildSkillContent(
|
|
20
|
+
export function buildSkillContent(
|
|
21
|
+
input: SkillCapabilityInput,
|
|
22
|
+
maxChars = 500,
|
|
23
|
+
): string {
|
|
24
|
+
const list = maxChars > 500;
|
|
11
25
|
let content = `The "${input.displayName}" skill (${input.id}) is available. ${input.description}.`;
|
|
12
26
|
if (input.activationHints && input.activationHints.length > 0) {
|
|
13
|
-
content +=
|
|
27
|
+
content += list
|
|
28
|
+
? `\nUse when:\n${input.activationHints.map((h) => `- ${h}`).join("\n")}`
|
|
29
|
+
: ` Use when: ${input.activationHints.join("; ")}.`;
|
|
14
30
|
}
|
|
15
31
|
if (input.avoidWhen && input.avoidWhen.length > 0) {
|
|
16
|
-
content +=
|
|
32
|
+
content += list
|
|
33
|
+
? `\nAvoid when:\n${input.avoidWhen.map((a) => `- ${a}`).join("\n")}`
|
|
34
|
+
: ` Avoid when: ${input.avoidWhen.join("; ")}.`;
|
|
17
35
|
}
|
|
18
|
-
if (content.length >
|
|
19
|
-
content = content.slice(0,
|
|
36
|
+
if (content.length > maxChars) {
|
|
37
|
+
content = content.slice(0, maxChars);
|
|
20
38
|
}
|
|
21
39
|
return content;
|
|
22
40
|
}
|
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
upsertConceptPageEmbedding,
|
|
42
42
|
} from "./qdrant.js";
|
|
43
43
|
import {
|
|
44
|
+
ALWAYS_CANDIDATE_CARD_CHARS,
|
|
44
45
|
augmentMcpSetupDescription,
|
|
45
46
|
buildSkillContent,
|
|
46
47
|
} from "./skill-content.js";
|
|
@@ -188,7 +189,12 @@ async function runSeedV2SkillEntries(generation: number): Promise<void> {
|
|
|
188
189
|
if (flagKey && !isAssistantFeatureFlagEnabled(flagKey, config)) continue;
|
|
189
190
|
|
|
190
191
|
const augmented = augmentMcpSetupDescription(fromSkillSummary(summary));
|
|
191
|
-
|
|
192
|
+
// Always-candidate skills are pinned into the selector pool every turn, so
|
|
193
|
+
// they get a larger budget for a fuller, multi-mode capability statement.
|
|
194
|
+
const content = buildSkillContent(
|
|
195
|
+
augmented,
|
|
196
|
+
summary.alwaysCandidate ? ALWAYS_CANDIDATE_CARD_CHARS : undefined,
|
|
197
|
+
);
|
|
192
198
|
seeds.push({ id: summary.id, content });
|
|
193
199
|
}
|
|
194
200
|
|