@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091926.ebb2d62
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 +6 -6
- package/bun.lock +2 -2
- package/docs/activation-funnel-telemetry.md +310 -0
- package/examples/plugins/echo/README.md +61 -60
- package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
- package/examples/plugins/echo/hooks/stop.ts +16 -0
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
- package/examples/plugins/echo/package.json +1 -2
- package/examples/plugins/echo/src/emit.ts +19 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +273 -121
- package/package.json +2 -2
- package/scripts/sync-llm-catalog.ts +2 -0
- package/src/__tests__/activation-early-marking.test.ts +120 -0
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
- package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
- package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
- package/src/__tests__/agent-loop-thinking.test.ts +36 -20
- package/src/__tests__/agent-loop.test.ts +441 -96
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
- package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
- package/src/__tests__/anthropic-provider.test.ts +23 -8
- package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +132 -0
- package/src/__tests__/approval-cascade.test.ts +6 -5
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/build-persisted-content.test.ts +75 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +146 -0
- package/src/__tests__/compaction-events.test.ts +7 -7
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
- package/src/__tests__/context-overflow-reducer.test.ts +265 -125
- package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
- package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
- package/src/__tests__/conversation-agent-loop.test.ts +342 -623
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
- package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
- package/src/__tests__/conversation-error.test.ts +15 -1
- package/src/__tests__/conversation-history-web-search.test.ts +6 -1
- package/src/__tests__/conversation-media-retry.test.ts +1 -1
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
- package/src/__tests__/conversation-process-callsite.test.ts +15 -15
- package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
- package/src/__tests__/conversation-queue.test.ts +10 -10
- package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
- package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
- package/src/__tests__/conversation-slash-queue.test.ts +7 -5
- package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
- package/src/__tests__/conversation-speed-override.test.ts +11 -10
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
- package/src/__tests__/conversation-undo.test.ts +2 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
- package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/corrected-target.test.ts +93 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +5 -4
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +36 -0
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
- package/src/__tests__/empty-response-hook.test.ts +1 -1
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +17 -2
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/history-repair-hook.test.ts +5 -1
- package/src/__tests__/host-app-control-proxy.test.ts +45 -0
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- package/src/__tests__/inference-profile-reaper.test.ts +62 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
- package/src/__tests__/injector-background-turn.test.ts +13 -23
- package/src/__tests__/injector-chain.test.ts +268 -44
- package/src/__tests__/injector-disk-pressure.test.ts +210 -52
- package/src/__tests__/injector-document-comments.test.ts +97 -114
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
- package/src/__tests__/injector-v3-suppression.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/llm-catalog-parity.test.ts +4 -0
- package/src/__tests__/llm-resolver.test.ts +73 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
- package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
- package/src/__tests__/notification-decision-strategy.test.ts +3 -3
- package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
- package/src/__tests__/persist-unsendable-image.test.ts +97 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
- package/src/__tests__/plugin-api-shim.test.ts +6 -9
- package/src/__tests__/plugin-bootstrap.test.ts +91 -81
- package/src/__tests__/plugin-registry.test.ts +3 -49
- package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
- package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
- package/src/__tests__/plugin-types.test.ts +0 -70
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
- package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
- package/src/__tests__/published-app-updater.test.ts +138 -0
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/retry-thinking-adaptive-only.test.ts +245 -0
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/server-history-render.test.ts +39 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
- package/src/__tests__/steer-tool-repair.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-detail.test.ts +25 -7
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +5 -1
- package/src/__tests__/tool-error-hook.test.ts +1 -1
- package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
- package/src/__tests__/tool-start-timestamp.test.ts +218 -0
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/__tests__/web-fetch.test.ts +45 -0
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +280 -0
- package/src/acp/auto-install.ts +232 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/prepare-agent-env.ts +80 -27
- package/src/acp/resolve-agent.test.ts +188 -28
- package/src/acp/resolve-agent.ts +119 -42
- package/src/acp/resume-hint.ts +23 -0
- package/src/acp/session-manager.ts +507 -73
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +403 -251
- package/src/api/events/tool-result.ts +9 -0
- package/src/api/events/tool-use-start.ts +7 -0
- package/src/api/responses/conversation-message.ts +72 -13
- package/src/api/responses/memory-v3-selection-log.ts +19 -10
- package/src/approvals/guardian-request-resolvers.ts +27 -1
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
- package/src/cli/commands/channel-verification-sessions.ts +6 -6
- package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
- package/src/cli/commands/memory-v3.ts +57 -199
- package/src/cli/commands/plugins.ts +43 -37
- package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
- package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
- package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
- package/src/cli/lib/install-from-github.ts +797 -60
- package/src/cli/lib/plugin-catalog-cache.ts +84 -0
- package/src/cli/lib/plugin-details.ts +416 -0
- package/src/cli/lib/plugin-marketplace.ts +215 -0
- package/src/cli/lib/search-plugins.ts +201 -29
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +9 -3
- package/src/config/acp-schema.ts +1 -7
- package/src/config/bundled-skills/acp/SKILL.md +80 -41
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
- package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +4 -0
- package/src/config/call-site-defaults.ts +0 -3
- package/src/config/feature-flag-registry.json +10 -56
- package/src/config/llm-resolver.ts +39 -7
- package/src/config/loader.ts +5 -22
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
- package/src/config/schemas/call-site-catalog.ts +0 -21
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +17 -3
- package/src/config/schemas/memory-v3.ts +58 -8
- package/src/config/seed-inference-profiles.ts +18 -0
- package/src/context/compactor.ts +22 -4
- package/src/context/post-turn-tool-result-truncation.ts +39 -1
- package/src/context/strip-injections.ts +8 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +120 -42
- package/src/daemon/conversation-agent-loop.ts +308 -1297
- package/src/daemon/conversation-error.ts +31 -4
- package/src/daemon/conversation-history.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +11 -255
- package/src/daemon/conversation-media-retry.ts +19 -6
- package/src/daemon/conversation-messaging.ts +17 -0
- package/src/daemon/conversation-process.ts +22 -141
- package/src/daemon/conversation-queue-manager.ts +8 -0
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +361 -393
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +165 -11
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +444 -62
- package/src/daemon/disk-pressure-policy.ts +0 -1
- package/src/daemon/external-plugins-bootstrap.ts +36 -46
- package/src/daemon/handlers/config-channels.ts +11 -2
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/shared.ts +9 -1
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-app-control-proxy.ts +72 -57
- package/src/daemon/host-proxy-preactivation.ts +1 -3
- package/src/daemon/lifecycle.ts +21 -7
- package/src/daemon/persist-unsendable-image.ts +62 -25
- package/src/daemon/process-message.ts +1 -1
- package/src/daemon/server.ts +2 -0
- package/src/daemon/tool-side-effects.ts +15 -0
- package/src/daemon/wake-conversation-ops.ts +269 -0
- package/src/embedded/plugin-api.ts +2 -2
- package/src/export/__tests__/transcript-formatter.test.ts +5 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
- package/src/heartbeat/heartbeat-run-store.ts +23 -1
- package/src/heartbeat/heartbeat-service.ts +26 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
- package/src/ipc/skill-routes/memory.ts +4 -2
- package/src/memory/__tests__/activation-session-store.test.ts +41 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
- package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
- package/src/memory/activation-session-store.ts +43 -0
- package/src/memory/conversation-crud.ts +29 -19
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/db-init.ts +6 -0
- package/src/memory/embedding-backend.ts +5 -22
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
- package/src/memory/jobs-worker.ts +25 -1
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
- package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/onboarding-events-store.ts +66 -18
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/infrastructure.ts +13 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
- package/src/memory/v2/__tests__/page-store.test.ts +22 -0
- package/src/memory/v2/consolidation-job.ts +2 -63
- package/src/memory/v2/types.ts +5 -0
- package/src/messaging/providers/telegram-bot/api.ts +14 -5
- package/src/notifications/__tests__/copy-composer.test.ts +244 -0
- package/src/notifications/access-request-copy.ts +298 -0
- package/src/notifications/adapters/slack.ts +3 -3
- package/src/notifications/adapters/telegram.ts +9 -2
- package/src/notifications/copy-composer.ts +49 -267
- package/src/notifications/decision-engine.ts +16 -35
- package/src/notifications/home-feed-side-effect.ts +1 -6
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +40 -11
- package/src/plugin-api/types.ts +108 -0
- package/src/plugins/defaults/compaction/compact.ts +106 -0
- package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
- package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
- package/src/plugins/defaults/compaction/manager-store.ts +57 -0
- package/src/plugins/defaults/compaction/package.json +1 -2
- package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
- package/src/plugins/defaults/empty-response/package.json +0 -1
- package/src/plugins/defaults/history-repair/package.json +0 -1
- package/src/plugins/defaults/index.ts +156 -26
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
- package/src/plugins/defaults/memory-retrieval/package.json +14 -0
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
- package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
- package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
- package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +76 -0
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
- package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
- package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
- package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
- package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
- package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
- package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
- package/src/plugins/defaults/title-generate/package.json +0 -1
- package/src/plugins/defaults/tool-error/package.json +0 -1
- package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
- package/src/plugins/external-api.ts +12 -2
- package/src/plugins/pipeline.ts +6 -293
- package/src/plugins/registry.ts +9 -37
- package/src/plugins/types.ts +76 -381
- package/src/plugins/user-loader.ts +30 -127
- package/src/prompts/__tests__/system-prompt.test.ts +6 -0
- package/src/prompts/system-prompt.ts +61 -10
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
- package/src/providers/anthropic/client.ts +9 -10
- package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
- package/src/providers/inference/logit-bias.ts +55 -0
- package/src/providers/model-catalog.ts +57 -0
- package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -1
- package/src/providers/retry.ts +57 -7
- package/src/providers/types.ts +6 -0
- package/src/runtime/__tests__/agent-wake.test.ts +555 -691
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +108 -209
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
- package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/acp-routes.test.ts +185 -32
- package/src/runtime/routes/acp-routes.ts +328 -30
- package/src/runtime/routes/app-management-routes.ts +3 -0
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/channel-verification-routes.ts +14 -5
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +30 -2
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +18 -3
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
- package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
- package/src/runtime/routes/memory-v3-routes.ts +65 -305
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +337 -35
- package/src/runtime/routes/stt-routes.ts +45 -12
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/routes/workspace-routes.ts +50 -15
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/runtime/verification-outbound-actions.ts +147 -2
- package/src/runtime/verification-templates.ts +29 -3
- package/src/services/published-app-updater.ts +30 -8
- package/src/signals/cancel.ts +2 -4
- package/src/subagent/manager.ts +21 -5
- package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
- package/src/telemetry/activation-funnel.ts +167 -0
- package/src/telemetry/types.ts +13 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
- package/src/telemetry/usage-telemetry-reporter.ts +26 -1
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +9 -19
- package/src/tools/acp/list-agents.ts +3 -15
- package/src/tools/acp/spawn.test.ts +173 -202
- package/src/tools/acp/spawn.ts +37 -172
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +166 -50
- package/src/tools/browser/browser-execution.ts +12 -2
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/network/web-fetch.ts +65 -24
- package/src/tools/skills/load.ts +1 -1
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/ui-surface/definitions.ts +32 -5
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
- package/docs/plugins.md +0 -832
- package/examples/plugins/echo/register.ts +0 -143
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
- package/src/__tests__/pipeline-runner.test.ts +0 -554
- package/src/daemon/wake-target-adapter.ts +0 -253
- package/src/memory/v3/__tests__/assign.test.ts +0 -242
- package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
- package/src/memory/v3/__tests__/core.test.ts +0 -39
- package/src/memory/v3/__tests__/health.test.ts +0 -219
- package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
- package/src/memory/v3/__tests__/needle.test.ts +0 -107
- package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
- package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
- package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
- package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
- package/src/memory/v3/__tests__/router.test.ts +0 -332
- package/src/memory/v3/__tests__/selector.test.ts +0 -470
- package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
- package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
- package/src/memory/v3/__tests__/tree.test.ts +0 -192
- package/src/memory/v3/assign.ts +0 -268
- package/src/memory/v3/capabilities.ts +0 -124
- package/src/memory/v3/core.ts +0 -26
- package/src/memory/v3/health.ts +0 -0
- package/src/memory/v3/maintain-job.ts +0 -314
- package/src/memory/v3/needle.ts +0 -115
- package/src/memory/v3/orchestrate.ts +0 -126
- package/src/memory/v3/page-content.ts +0 -34
- package/src/memory/v3/provider-blocks.ts +0 -26
- package/src/memory/v3/reconcile.ts +0 -523
- package/src/memory/v3/router.ts +0 -190
- package/src/memory/v3/selection-log-store.ts +0 -84
- package/src/memory/v3/selector.ts +0 -226
- package/src/memory/v3/shadow-plugin.ts +0 -411
- package/src/memory/v3/snapshot.ts +0 -209
- package/src/memory/v3/tree.ts +0 -174
- package/src/memory/v3/types.ts +0 -59
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
- package/src/plugins/defaults/circuit-breaker/package.json +0 -15
- package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
- package/src/plugins/defaults/compaction/register.ts +0 -35
- package/src/plugins/defaults/compaction/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/register.ts +0 -23
- package/src/plugins/defaults/history-repair/register.ts +0 -24
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
- package/src/plugins/defaults/overflow-reduce/package.json +0 -15
- package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
- package/src/plugins/defaults/title-generate/register.ts +0 -35
- package/src/plugins/defaults/tool-error/register.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
- package/src/proactive-artifact/aux-message-injector.ts +0 -97
- package/src/proactive-artifact/decision.test.ts +0 -226
- package/src/proactive-artifact/decision.ts +0 -165
- package/src/proactive-artifact/index.ts +0 -7
- package/src/proactive-artifact/job.test.ts +0 -962
- package/src/proactive-artifact/job.ts +0 -372
- package/src/proactive-artifact/message-copy.ts +0 -58
- package/src/proactive-artifact/trigger-state.test.ts +0 -286
- package/src/proactive-artifact/trigger-state.ts +0 -123
- package/src/util/map-limit.ts +0 -27
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
// Silence the logger.
|
|
4
|
+
mock.module("../../util/logger.js", () => ({
|
|
5
|
+
getLogger: () =>
|
|
6
|
+
new Proxy({} as Record<string, unknown>, {
|
|
7
|
+
get: () => () => {},
|
|
8
|
+
}),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
// Mutable usage-data gate, flipped per-test.
|
|
12
|
+
let collectUsageData = true;
|
|
13
|
+
mock.module("../../config/loader.js", () => ({
|
|
14
|
+
getConfig: () => ({ collectUsageData }),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
import { getDb } from "../db-connection.js";
|
|
18
|
+
import { initializeDb } from "../db-init.js";
|
|
19
|
+
import {
|
|
20
|
+
queryUnreportedOnboardingEvents,
|
|
21
|
+
recordActivationEvent,
|
|
22
|
+
} from "../onboarding-events-store.js";
|
|
23
|
+
import { onboardingEvents } from "../schema.js";
|
|
24
|
+
|
|
25
|
+
initializeDb();
|
|
26
|
+
|
|
27
|
+
function resetTable(): void {
|
|
28
|
+
getDb().delete(onboardingEvents).run();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe("onboarding-events-store: recordActivationEvent", () => {
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
collectUsageData = true;
|
|
34
|
+
resetTable();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("persists an activation funnel event that round-trips through the query", () => {
|
|
38
|
+
const event = recordActivationEvent({
|
|
39
|
+
stepName: "activation_moment_1_complete",
|
|
40
|
+
sessionId: "conv-1",
|
|
41
|
+
});
|
|
42
|
+
expect(event).not.toBeNull();
|
|
43
|
+
|
|
44
|
+
const rows = queryUnreportedOnboardingEvents(0, undefined, 10);
|
|
45
|
+
expect(rows).toHaveLength(1);
|
|
46
|
+
const row = rows[0]!;
|
|
47
|
+
expect(row.stepName).toBe("activation_moment_1_complete");
|
|
48
|
+
expect(row.stepIndex).toBe(1);
|
|
49
|
+
expect(row.funnelVersion).toBe("activation_v1_2026_06");
|
|
50
|
+
expect(row.screen).toBe("activation_moment_1_complete");
|
|
51
|
+
expect(row.abVariant).toBe("variant-a");
|
|
52
|
+
expect(row.sessionId).toBe("conv-1");
|
|
53
|
+
expect(row.completedAt).toBe(new Date(row.createdAt).toISOString());
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("honors an explicit abVariant override", () => {
|
|
57
|
+
recordActivationEvent({
|
|
58
|
+
stepName: "activation_moment_2_complete",
|
|
59
|
+
sessionId: "conv-2",
|
|
60
|
+
abVariant: "variant-b",
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const rows = queryUnreportedOnboardingEvents(0, undefined, 10);
|
|
64
|
+
expect(rows).toHaveLength(1);
|
|
65
|
+
expect(rows[0]!.abVariant).toBe("variant-b");
|
|
66
|
+
expect(rows[0]!.stepIndex).toBe(2);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("returns null and writes no row when collectUsageData is disabled", () => {
|
|
70
|
+
collectUsageData = false;
|
|
71
|
+
const event = recordActivationEvent({
|
|
72
|
+
stepName: "activation_moment_1_complete",
|
|
73
|
+
sessionId: "conv-3",
|
|
74
|
+
});
|
|
75
|
+
expect(event).toBeNull();
|
|
76
|
+
|
|
77
|
+
const rows = queryUnreportedOnboardingEvents(0, undefined, 10);
|
|
78
|
+
expect(rows).toHaveLength(0);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { eq } from "drizzle-orm";
|
|
2
|
+
|
|
3
|
+
import { getLogger } from "../util/logger.js";
|
|
4
|
+
import { getDb } from "./db-connection.js";
|
|
5
|
+
import { activationSessions } from "./schema.js";
|
|
6
|
+
|
|
7
|
+
const log = getLogger("activation-session-store");
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Mark a conversation as an activation-rail session. Idempotent (the row's
|
|
11
|
+
* primary key is the conversation id) and best-effort: a write failure is
|
|
12
|
+
* logged and swallowed so it never blocks the turn that triggered it.
|
|
13
|
+
*/
|
|
14
|
+
export function markActivationSession(conversationId: string): void {
|
|
15
|
+
try {
|
|
16
|
+
getDb()
|
|
17
|
+
.insert(activationSessions)
|
|
18
|
+
.values({ conversationId, createdAt: Date.now() })
|
|
19
|
+
.onConflictDoNothing()
|
|
20
|
+
.run();
|
|
21
|
+
} catch (err) {
|
|
22
|
+
log.warn({ err, conversationId }, "Failed to mark activation session");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Whether the given conversation was started on the activation rail. Best-effort:
|
|
28
|
+
* a read failure is logged and treated as "not an activation session".
|
|
29
|
+
*/
|
|
30
|
+
export function isActivationSession(conversationId: string): boolean {
|
|
31
|
+
try {
|
|
32
|
+
const row = getDb()
|
|
33
|
+
.select({ conversationId: activationSessions.conversationId })
|
|
34
|
+
.from(activationSessions)
|
|
35
|
+
.where(eq(activationSessions.conversationId, conversationId))
|
|
36
|
+
.limit(1)
|
|
37
|
+
.get();
|
|
38
|
+
return row !== undefined;
|
|
39
|
+
} catch (err) {
|
|
40
|
+
log.warn({ err, conversationId }, "Failed to read activation session");
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -277,6 +277,7 @@ export interface MessageRow {
|
|
|
277
277
|
content: string;
|
|
278
278
|
createdAt: number;
|
|
279
279
|
metadata: string | null;
|
|
280
|
+
clientMessageId: string | null;
|
|
280
281
|
}
|
|
281
282
|
|
|
282
283
|
const parseMessage = createRowMapper<typeof messages.$inferSelect, MessageRow>({
|
|
@@ -286,6 +287,7 @@ const parseMessage = createRowMapper<typeof messages.$inferSelect, MessageRow>({
|
|
|
286
287
|
content: "content",
|
|
287
288
|
createdAt: "createdAt",
|
|
288
289
|
metadata: "metadata",
|
|
290
|
+
clientMessageId: "clientMessageId",
|
|
289
291
|
});
|
|
290
292
|
|
|
291
293
|
export type ConversationCreateType = "standard" | "background" | "scheduled";
|
|
@@ -1903,21 +1905,30 @@ export function listActiveInferenceProfileSessions(
|
|
|
1903
1905
|
}
|
|
1904
1906
|
|
|
1905
1907
|
/**
|
|
1906
|
-
*
|
|
1907
|
-
*
|
|
1908
|
-
*
|
|
1909
|
-
*
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1908
|
+
* The conversation fields needed to resolve a per-turn inference-profile
|
|
1909
|
+
* override. Satisfied by both the DB {@link ConversationRow} and the live
|
|
1910
|
+
* in-memory `Conversation`, so callers can derive the override from whichever
|
|
1911
|
+
* representation they already hold without a redundant row fetch.
|
|
1912
|
+
*/
|
|
1913
|
+
export interface OverrideProfileFields {
|
|
1914
|
+
conversationType?: string | null;
|
|
1915
|
+
inferenceProfile?: string | null;
|
|
1916
|
+
inferenceProfileExpiresAt?: number | null;
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
/**
|
|
1920
|
+
* Resolve the per-turn inference-profile override from a conversation's
|
|
1921
|
+
* fields. Returns the `inferenceProfile` for interactive conversations,
|
|
1922
|
+
* `undefined` for automation threads (subagent fan-out, scheduled tasks,
|
|
1923
|
+
* update bulletins) so they run on the workspace defaults rather than
|
|
1924
|
+
* inheriting an interactive override.
|
|
1914
1925
|
*/
|
|
1915
|
-
export function
|
|
1916
|
-
|
|
1926
|
+
export function resolveOverrideProfile(
|
|
1927
|
+
fields: OverrideProfileFields | null,
|
|
1917
1928
|
): string | undefined {
|
|
1918
1929
|
if (
|
|
1919
|
-
|
|
1920
|
-
|
|
1930
|
+
fields?.conversationType === "background" ||
|
|
1931
|
+
fields?.conversationType === "scheduled"
|
|
1921
1932
|
) {
|
|
1922
1933
|
return undefined;
|
|
1923
1934
|
}
|
|
@@ -1931,24 +1942,23 @@ export function getConversationOverrideProfileFromRow(
|
|
|
1931
1942
|
// Without this, a session at the exact-expiry millisecond would be served
|
|
1932
1943
|
// for one extra turn here while being cleared by the reaper.
|
|
1933
1944
|
if (
|
|
1934
|
-
|
|
1935
|
-
|
|
1945
|
+
fields?.inferenceProfileExpiresAt != null &&
|
|
1946
|
+
fields.inferenceProfileExpiresAt <= Date.now()
|
|
1936
1947
|
) {
|
|
1937
1948
|
return undefined;
|
|
1938
1949
|
}
|
|
1939
|
-
return
|
|
1950
|
+
return fields?.inferenceProfile ?? undefined;
|
|
1940
1951
|
}
|
|
1941
1952
|
|
|
1942
1953
|
/**
|
|
1943
1954
|
* Resolve the per-turn inference-profile override by conversation id.
|
|
1944
|
-
* Convenience wrapper
|
|
1945
|
-
*
|
|
1946
|
-
* already have the row in hand.
|
|
1955
|
+
* Convenience wrapper for standalone callers (e.g. subagent spawn,
|
|
1956
|
+
* opportunity-wake) that don't already have the conversation in hand.
|
|
1947
1957
|
*/
|
|
1948
1958
|
export function getConversationOverrideProfile(
|
|
1949
1959
|
conversationId: string,
|
|
1950
1960
|
): string | undefined {
|
|
1951
|
-
return
|
|
1961
|
+
return resolveOverrideProfile(getConversation(conversationId));
|
|
1952
1962
|
}
|
|
1953
1963
|
|
|
1954
1964
|
export function setLastNotifiedInferenceProfile(
|
|
@@ -15,6 +15,7 @@ import { memoryCheckpoints } from "./schema.js";
|
|
|
15
15
|
export const CK_ITEM_COUNT = "conversation_starters:item_count_at_last_gen";
|
|
16
16
|
export const CK_BATCH = "conversation_starters:generation_batch";
|
|
17
17
|
export const CK_LAST_GEN_AT = "conversation_starters:last_gen_at";
|
|
18
|
+
export const CK_LAST_ATTEMPT_AT = "conversation_starters:last_attempt_at";
|
|
18
19
|
|
|
19
20
|
export function checkpointKey(base: string, scopeId: string): string {
|
|
20
21
|
return `${base}:${scopeId}`;
|
package/src/memory/db-init.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { getDb, getSqlite } from "./db-connection.js";
|
|
|
16
16
|
import { migrateToolCreatedItems } from "./graph/bootstrap.js";
|
|
17
17
|
import {
|
|
18
18
|
addCoreColumns,
|
|
19
|
+
createActivationSessionsTable,
|
|
19
20
|
createApprovalPromptTsTrackerTable,
|
|
20
21
|
createAssistantInboxTables,
|
|
21
22
|
createAuthFallbackEventsTable,
|
|
@@ -41,6 +42,7 @@ import {
|
|
|
41
42
|
migrate230AcpSessionHistory,
|
|
42
43
|
migrate231RepairMemoryGraphEventDates,
|
|
43
44
|
migrateA2ATasks,
|
|
45
|
+
migrateAcpSessionHistoryCwd,
|
|
44
46
|
migrateActivationState,
|
|
45
47
|
migrateActivationStateFkCascade,
|
|
46
48
|
migrateAddConversationInferenceProfile,
|
|
@@ -160,6 +162,7 @@ import {
|
|
|
160
162
|
migrateOAuthProvidersScopeSeparator,
|
|
161
163
|
migrateOAuthProvidersTokenAuthMethodDefault,
|
|
162
164
|
migrateOAuthProvidersTokenExchangeBodyFormat,
|
|
165
|
+
migrateOnboardingEventsFunnelColumns,
|
|
163
166
|
migrateOnboardingEventsPriorAssistants,
|
|
164
167
|
migrateProviderConnectionBaseUrlAndModels,
|
|
165
168
|
migrateProviderConnectionStatusLabel,
|
|
@@ -478,6 +481,9 @@ export function initializeDb(): void {
|
|
|
478
481
|
migrateScheduleSourceConversation,
|
|
479
482
|
migrateMessagesRoleCreatedAtIndex,
|
|
480
483
|
createAuthFallbackEventsTable,
|
|
484
|
+
migrateAcpSessionHistoryCwd,
|
|
485
|
+
migrateOnboardingEventsFunnelColumns,
|
|
486
|
+
createActivationSessionsTable,
|
|
481
487
|
];
|
|
482
488
|
|
|
483
489
|
// Run each migration step, catching and logging individual failures so one
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
|
|
3
|
-
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
4
3
|
import { getOllamaBaseUrlEnv } from "../config/env.js";
|
|
5
4
|
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
6
5
|
import type { AssistantConfig } from "../config/types.js";
|
|
@@ -302,13 +301,10 @@ export async function selectEmbeddingBackend(
|
|
|
302
301
|
};
|
|
303
302
|
}
|
|
304
303
|
|
|
305
|
-
// When
|
|
306
|
-
//
|
|
307
|
-
//
|
|
308
|
-
if (
|
|
309
|
-
(requested === "auto" || requested === "gemini") &&
|
|
310
|
-
isAssistantFeatureFlagEnabled("managed-gemini-embeddings-enabled", config)
|
|
311
|
-
) {
|
|
304
|
+
// When managed proxy prerequisites are satisfied, insert managed-proxy Gemini
|
|
305
|
+
// at the front of the auto chain so platform assistants use Vellum-managed
|
|
306
|
+
// Gemini embeddings.
|
|
307
|
+
if (requested === "auto" || requested === "gemini") {
|
|
312
308
|
const proxyCtx = await resolveManagedProxyContext();
|
|
313
309
|
if (proxyCtx.enabled) {
|
|
314
310
|
const meta = PLATFORM_PROVIDER_META["gemini"];
|
|
@@ -677,12 +673,7 @@ async function selectFallbackBackends(
|
|
|
677
673
|
geminiCacheExtras(config),
|
|
678
674
|
),
|
|
679
675
|
);
|
|
680
|
-
} else
|
|
681
|
-
isAssistantFeatureFlagEnabled(
|
|
682
|
-
"managed-gemini-embeddings-enabled",
|
|
683
|
-
config,
|
|
684
|
-
)
|
|
685
|
-
) {
|
|
676
|
+
} else {
|
|
686
677
|
// Try managed proxy Gemini as fallback when no direct key exists.
|
|
687
678
|
const proxyCtx = await resolveManagedProxyContext();
|
|
688
679
|
const meta = PLATFORM_PROVIDER_META["gemini"];
|
|
@@ -724,14 +715,6 @@ async function selectFallbackBackends(
|
|
|
724
715
|
);
|
|
725
716
|
if (cached) backends.push(cached);
|
|
726
717
|
}
|
|
727
|
-
} else {
|
|
728
|
-
// Preserve cached backend on transient credential-store failures.
|
|
729
|
-
const cached = getCached(
|
|
730
|
-
"gemini",
|
|
731
|
-
config.memory.embeddings.geminiModel,
|
|
732
|
-
geminiCacheExtras(config),
|
|
733
|
-
);
|
|
734
|
-
if (cached) backends.push(cached);
|
|
735
718
|
}
|
|
736
719
|
break;
|
|
737
720
|
}
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
checkpointKey,
|
|
23
23
|
CK_BATCH,
|
|
24
24
|
CK_ITEM_COUNT,
|
|
25
|
+
CK_LAST_ATTEMPT_AT,
|
|
25
26
|
CK_LAST_GEN_AT,
|
|
26
27
|
countActiveMemoryNodes,
|
|
27
28
|
getCheckpointValue,
|
|
@@ -336,6 +337,7 @@ Bad → Good (incomplete phrase → complete):
|
|
|
336
337
|
config: {
|
|
337
338
|
callSite: "conversationStarters" as const,
|
|
338
339
|
max_tokens: 2048,
|
|
340
|
+
temperature: 0.7,
|
|
339
341
|
tool_choice: {
|
|
340
342
|
type: "tool" as const,
|
|
341
343
|
name: "store_conversation_starters",
|
|
@@ -395,18 +397,27 @@ export async function generateConversationStartersJob(
|
|
|
395
397
|
const db = getDb();
|
|
396
398
|
const now = Date.now();
|
|
397
399
|
|
|
400
|
+
// Record attempt time so the route handler's cooldown prevents rapid retries
|
|
401
|
+
// even when generation produces 0 valid starters.
|
|
402
|
+
upsertCheckpoint(
|
|
403
|
+
checkpointKey(CK_LAST_ATTEMPT_AT, scopeId),
|
|
404
|
+
String(now),
|
|
405
|
+
now,
|
|
406
|
+
);
|
|
407
|
+
|
|
398
408
|
const starters = await generateStarters(scopeId);
|
|
399
409
|
if (starters.length === 0) {
|
|
400
410
|
log.info({ scopeId }, "No conversation starters generated");
|
|
401
411
|
|
|
402
|
-
// Sync
|
|
412
|
+
// Sync the item count checkpoint so `checkpointAhead` clears, but do NOT
|
|
413
|
+
// update `CK_LAST_GEN_AT` — the stale TTL should trigger a retry on the
|
|
414
|
+
// next GET rather than blocking retries for the full TTL window.
|
|
403
415
|
const totalActive = countActiveMemoryNodes(scopeId);
|
|
404
416
|
upsertCheckpoint(
|
|
405
417
|
checkpointKey(CK_ITEM_COUNT, scopeId),
|
|
406
418
|
String(totalActive),
|
|
407
419
|
now,
|
|
408
420
|
);
|
|
409
|
-
upsertCheckpoint(checkpointKey(CK_LAST_GEN_AT, scopeId), String(now), now);
|
|
410
421
|
return;
|
|
411
422
|
}
|
|
412
423
|
|
|
@@ -143,9 +143,8 @@ afterAll(() => {
|
|
|
143
143
|
// `getWorkspaceDir()` resolves to the tmpdir.
|
|
144
144
|
const { DEFAULT_CONFIG } = await import("../../../config/defaults.js");
|
|
145
145
|
const { getDb } = await import("../../db-connection.js");
|
|
146
|
-
const { resetDbForTesting } =
|
|
147
|
-
"../../../__tests__/db-test-helpers.js"
|
|
148
|
-
);
|
|
146
|
+
const { resetDbForTesting } =
|
|
147
|
+
await import("../../../__tests__/db-test-helpers.js");
|
|
149
148
|
const { initializeDb } = await import("../../db-init.js");
|
|
150
149
|
const { memoryEmbeddings, memoryJobs } = await import("../../schema.js");
|
|
151
150
|
const { claimMemoryJobs } = await import("../../jobs-store.js");
|
|
@@ -187,12 +186,14 @@ function makeJob(payload: Record<string, unknown>): MemoryJob {
|
|
|
187
186
|
|
|
188
187
|
beforeEach(() => {
|
|
189
188
|
resetDbForTesting();
|
|
189
|
+
// The first run pays the full cold-start migration chain; bump the hook
|
|
190
|
+
// timeout above bun's 5s default so the leading test doesn't flake in CI.
|
|
190
191
|
initializeDb();
|
|
191
192
|
embedWithBackendCalls.length = 0;
|
|
192
193
|
upsertCalls.length = 0;
|
|
193
194
|
deleteCalls.length = 0;
|
|
194
195
|
_resetQdrantBreaker();
|
|
195
|
-
});
|
|
196
|
+
}, 30_000);
|
|
196
197
|
|
|
197
198
|
afterEach(() => {
|
|
198
199
|
// Clean up any pages written between tests so each scenario starts fresh.
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
diskPressureBackgroundSkipLogFields,
|
|
9
9
|
shouldLogDiskPressureBackgroundSkip,
|
|
10
10
|
} from "../daemon/disk-pressure-background-gate.js";
|
|
11
|
+
import { maintainJob as memoryV3MaintainJob } from "../plugins/defaults/memory-v3-shadow/maintain-job.js";
|
|
11
12
|
import { getLogger } from "../util/logger.js";
|
|
12
13
|
import { getWorkspaceDir } from "../util/platform.js";
|
|
13
14
|
import { getMemoryCheckpoint, setMemoryCheckpoint } from "./checkpoints.js";
|
|
@@ -87,7 +88,6 @@ import {
|
|
|
87
88
|
memoryV2ConsolidateJob,
|
|
88
89
|
} from "./v2/consolidation-job.js";
|
|
89
90
|
import { memoryV2SweepJob } from "./v2/sweep-job.js";
|
|
90
|
-
import { maintainJob as memoryV3MaintainJob } from "./v3/maintain-job.js";
|
|
91
91
|
|
|
92
92
|
const log = getLogger("memory-jobs-worker");
|
|
93
93
|
|
|
@@ -95,6 +95,16 @@ const AUTOMATIC_CONSOLIDATION_JOB_PAYLOAD = {
|
|
|
95
95
|
trigger: MEMORY_V2_CONSOLIDATION_JOB_TRIGGERS.automatic,
|
|
96
96
|
} as const;
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Minimum buffer entries required for a scheduled consolidation run. The
|
|
100
|
+
* time-based schedule noops when `memory/buffer.md` has fewer non-empty lines
|
|
101
|
+
* than this threshold — the LLM cost of a full consolidation pass outweighs
|
|
102
|
+
* the benefit when the buffer is nearly empty. Mirrors the heartbeat
|
|
103
|
+
* max-consecutive-runs skip pattern. Manual "Run now" and the size-based
|
|
104
|
+
* trigger are not affected.
|
|
105
|
+
*/
|
|
106
|
+
export const MIN_BUFFER_LINES_FOR_CONSOLIDATION = 10;
|
|
107
|
+
|
|
98
108
|
/**
|
|
99
109
|
* V1 job types that read or write the v1 Qdrant collection via
|
|
100
110
|
* `getQdrantClient()`. When `memory.v2.enabled` is true, the v1 client is
|
|
@@ -815,6 +825,20 @@ export function maybeEnqueueGraphMaintenanceJobs(
|
|
|
815
825
|
for (const { key, intervalMs, jobType } of schedule) {
|
|
816
826
|
const lastRun = parseInt(getMemoryCheckpoint(key) ?? "0", 10);
|
|
817
827
|
if (nowMs - lastRun >= intervalMs) {
|
|
828
|
+
// Noop scheduled consolidation when the buffer has too few entries to
|
|
829
|
+
// justify an LLM run — mirrors the heartbeat max-consecutive-runs skip.
|
|
830
|
+
// The checkpoint advances so the next check fires after the regular
|
|
831
|
+
// interval. Manual "Run now" is unaffected (routes layer, not schedule).
|
|
832
|
+
if (jobType === consolidateEntry.jobType) {
|
|
833
|
+
const bufferPath = join(getWorkspaceDir(), "memory", "buffer.md");
|
|
834
|
+
if (countBufferLines(bufferPath) < MIN_BUFFER_LINES_FOR_CONSOLIDATION) {
|
|
835
|
+
log.debug(
|
|
836
|
+
"Scheduled consolidation skipped: buffer under minimum line threshold",
|
|
837
|
+
);
|
|
838
|
+
setMemoryCheckpoint(key, String(nowMs));
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
818
842
|
const payload =
|
|
819
843
|
jobType === consolidateEntry.jobType
|
|
820
844
|
? AUTOMATIC_CONSOLIDATION_JOB_PAYLOAD
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
4
|
+
|
|
5
|
+
const CHECKPOINT_KEY = "migration_acp_session_history_cwd_v1";
|
|
6
|
+
|
|
7
|
+
const TABLE = "acp_session_history";
|
|
8
|
+
const COLUMN = "cwd";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Add a nullable `cwd TEXT` column to `acp_session_history`.
|
|
12
|
+
*
|
|
13
|
+
* Records the working directory the ACP agent process was spawned with so
|
|
14
|
+
* that a persisted session can later be resumed (`session/load` /
|
|
15
|
+
* `session/resume` both require the original cwd to reconstruct params).
|
|
16
|
+
*
|
|
17
|
+
* `NULL` for rows persisted before this migration ran — legacy sessions
|
|
18
|
+
* simply are not resumable.
|
|
19
|
+
*
|
|
20
|
+
* Idempotent — the PRAGMA guard makes re-running a no-op once the column
|
|
21
|
+
* exists.
|
|
22
|
+
*/
|
|
23
|
+
export function migrateAcpSessionHistoryCwd(database: DrizzleDb): void {
|
|
24
|
+
withCrashRecovery(database, CHECKPOINT_KEY, () => {
|
|
25
|
+
const raw = getSqliteFrom(database);
|
|
26
|
+
|
|
27
|
+
const columns = raw.query(`PRAGMA table_info(${TABLE})`).all() as Array<{
|
|
28
|
+
name: string;
|
|
29
|
+
}>;
|
|
30
|
+
const columnNames = new Set(columns.map((c) => c.name));
|
|
31
|
+
|
|
32
|
+
if (!columnNames.has(COLUMN)) {
|
|
33
|
+
raw.exec(`ALTER TABLE ${TABLE} ADD COLUMN ${COLUMN} TEXT`);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
2
|
+
|
|
3
|
+
const TABLE = "onboarding_events";
|
|
4
|
+
const COLUMNS: Array<{ name: string; type: string }> = [
|
|
5
|
+
{ name: "session_id", type: "TEXT" },
|
|
6
|
+
{ name: "step_name", type: "TEXT" },
|
|
7
|
+
{ name: "step_index", type: "INTEGER" },
|
|
8
|
+
{ name: "completed_at", type: "TEXT" },
|
|
9
|
+
{ name: "funnel_version", type: "TEXT" },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Add nullable funnel-tracking columns to `onboarding_events`.
|
|
14
|
+
*
|
|
15
|
+
* The original table (#30733) recorded one row per onboarding screen but had
|
|
16
|
+
* no way to stitch those rows into an ordered, per-attempt funnel: there was
|
|
17
|
+
* no session correlator, no step ordering, and no completion timestamp. These
|
|
18
|
+
* columns let the activation-funnel reporting attribute each event to a single
|
|
19
|
+
* onboarding attempt (`session_id`), order steps within it (`step_name` /
|
|
20
|
+
* `step_index`), record when a step finished (`completed_at`), and version the
|
|
21
|
+
* funnel shape so changes to the step set don't silently corrupt historical
|
|
22
|
+
* conversion math (`funnel_version`).
|
|
23
|
+
*
|
|
24
|
+
* All columns are nullable — `NULL` for rows persisted before this migration
|
|
25
|
+
* ran.
|
|
26
|
+
*
|
|
27
|
+
* Idempotent — re-running is a no-op once the columns exist. Pure DDL with a
|
|
28
|
+
* PRAGMA guard, no registry entry needed (matches the 252 / 261 / 264 / 265 /
|
|
29
|
+
* 267 pattern).
|
|
30
|
+
*/
|
|
31
|
+
export function migrateOnboardingEventsFunnelColumns(
|
|
32
|
+
database: DrizzleDb,
|
|
33
|
+
): void {
|
|
34
|
+
const raw = getSqliteFrom(database);
|
|
35
|
+
|
|
36
|
+
const columns = raw.query(`PRAGMA table_info(${TABLE})`).all() as Array<{
|
|
37
|
+
name: string;
|
|
38
|
+
}>;
|
|
39
|
+
const columnNames = new Set(columns.map((c) => c.name));
|
|
40
|
+
|
|
41
|
+
for (const { name, type } of COLUMNS) {
|
|
42
|
+
if (!columnNames.has(name)) {
|
|
43
|
+
raw.exec(`ALTER TABLE ${TABLE} ADD COLUMN ${name} ${type}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create the activation_sessions table. One row per conversation that was
|
|
5
|
+
* started on the activation-rail bootstrap template, used by the activation
|
|
6
|
+
* funnel telemetry to scope events to activation conversations.
|
|
7
|
+
*/
|
|
8
|
+
export function createActivationSessionsTable(database: DrizzleDb): void {
|
|
9
|
+
database.run(/*sql*/ `
|
|
10
|
+
CREATE TABLE IF NOT EXISTS activation_sessions (
|
|
11
|
+
conversation_id TEXT PRIMARY KEY,
|
|
12
|
+
created_at INTEGER NOT NULL
|
|
13
|
+
)
|
|
14
|
+
`);
|
|
15
|
+
}
|
|
@@ -259,6 +259,9 @@ export { migrateScheduleScriptTimeout } from "./269-schedule-script-timeout.js";
|
|
|
259
259
|
export { migrateMessagesRoleCreatedAtIndex } from "./270-messages-role-created-at-index.js";
|
|
260
260
|
export { migrateScheduleSourceConversation } from "./270-schedule-source-conversation.js";
|
|
261
261
|
export { createAuthFallbackEventsTable } from "./271-create-auth-fallback-events.js";
|
|
262
|
+
export { migrateAcpSessionHistoryCwd } from "./272-acp-session-history-cwd.js";
|
|
263
|
+
export { migrateOnboardingEventsFunnelColumns } from "./273-onboarding-events-funnel-columns.js";
|
|
264
|
+
export { createActivationSessionsTable } from "./274-create-activation-sessions.js";
|
|
262
265
|
export {
|
|
263
266
|
MIGRATION_REGISTRY,
|
|
264
267
|
type MigrationRegistryEntry,
|
|
@@ -2,6 +2,12 @@ import { and, asc, eq, gt, or } from "drizzle-orm";
|
|
|
2
2
|
import { v4 as uuid } from "uuid";
|
|
3
3
|
|
|
4
4
|
import { getConfig } from "../config/loader.js";
|
|
5
|
+
import {
|
|
6
|
+
ACTIVATION_AB_VARIANT,
|
|
7
|
+
ACTIVATION_FUNNEL_VERSION,
|
|
8
|
+
activationStepIndex,
|
|
9
|
+
type ActivationStepName,
|
|
10
|
+
} from "../telemetry/activation-funnel.js";
|
|
5
11
|
import { getDb } from "./db-connection.js";
|
|
6
12
|
import { onboardingEvents } from "./schema.js";
|
|
7
13
|
|
|
@@ -16,6 +22,11 @@ export interface OnboardingEvent {
|
|
|
16
22
|
googleScopesJson: string | null;
|
|
17
23
|
priorAssistantsJson: string | null;
|
|
18
24
|
abVariant: string | null;
|
|
25
|
+
sessionId: string | null;
|
|
26
|
+
stepName: string | null;
|
|
27
|
+
stepIndex: number | null;
|
|
28
|
+
completedAt: string | null;
|
|
29
|
+
funnelVersion: string | null;
|
|
19
30
|
}
|
|
20
31
|
|
|
21
32
|
export interface RecordOnboardingEventParams {
|
|
@@ -27,6 +38,17 @@ export interface RecordOnboardingEventParams {
|
|
|
27
38
|
googleScopes?: string[];
|
|
28
39
|
priorAssistants?: string[];
|
|
29
40
|
abVariant?: string;
|
|
41
|
+
sessionId?: string | null;
|
|
42
|
+
stepName?: string | null;
|
|
43
|
+
stepIndex?: number | null;
|
|
44
|
+
completedAt?: string | null;
|
|
45
|
+
funnelVersion?: string | null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Insert a fully-built event row. Shared by all record* entry points. */
|
|
49
|
+
function insertOnboardingEvent(event: OnboardingEvent): OnboardingEvent {
|
|
50
|
+
getDb().insert(onboardingEvents).values(event).run();
|
|
51
|
+
return event;
|
|
30
52
|
}
|
|
31
53
|
|
|
32
54
|
/**
|
|
@@ -37,8 +59,7 @@ export function recordOnboardingEvent(
|
|
|
37
59
|
params: RecordOnboardingEventParams,
|
|
38
60
|
): OnboardingEvent | null {
|
|
39
61
|
if (!getConfig().collectUsageData) return null;
|
|
40
|
-
|
|
41
|
-
const event: OnboardingEvent = {
|
|
62
|
+
return insertOnboardingEvent({
|
|
42
63
|
id: uuid(),
|
|
43
64
|
createdAt: Date.now(),
|
|
44
65
|
screen: params.screen,
|
|
@@ -53,22 +74,44 @@ export function recordOnboardingEvent(
|
|
|
53
74
|
? JSON.stringify(params.priorAssistants)
|
|
54
75
|
: null,
|
|
55
76
|
abVariant: params.abVariant ?? null,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
77
|
+
sessionId: params.sessionId ?? null,
|
|
78
|
+
stepName: params.stepName ?? null,
|
|
79
|
+
stepIndex: params.stepIndex ?? null,
|
|
80
|
+
completedAt: params.completedAt ?? null,
|
|
81
|
+
funnelVersion: params.funnelVersion ?? null,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Record an activation-funnel milestone event. Reuses the onboarding telemetry
|
|
87
|
+
* substrate (`screen` carries the step name to satisfy the NOT NULL column).
|
|
88
|
+
* Returns null when usage data collection is disabled.
|
|
89
|
+
*/
|
|
90
|
+
export function recordActivationEvent(params: {
|
|
91
|
+
stepName: ActivationStepName;
|
|
92
|
+
sessionId: string;
|
|
93
|
+
userId?: string | null;
|
|
94
|
+
abVariant?: string;
|
|
95
|
+
}): OnboardingEvent | null {
|
|
96
|
+
if (!getConfig().collectUsageData) return null;
|
|
97
|
+
const createdAt = Date.now();
|
|
98
|
+
return insertOnboardingEvent({
|
|
99
|
+
id: uuid(),
|
|
100
|
+
createdAt,
|
|
101
|
+
screen: params.stepName,
|
|
102
|
+
toolsJson: null,
|
|
103
|
+
tasksJson: null,
|
|
104
|
+
tone: null,
|
|
105
|
+
googleConnected: null,
|
|
106
|
+
googleScopesJson: null,
|
|
107
|
+
priorAssistantsJson: null,
|
|
108
|
+
abVariant: params.abVariant ?? ACTIVATION_AB_VARIANT,
|
|
109
|
+
sessionId: params.sessionId,
|
|
110
|
+
stepName: params.stepName,
|
|
111
|
+
stepIndex: activationStepIndex(params.stepName),
|
|
112
|
+
completedAt: new Date(createdAt).toISOString(),
|
|
113
|
+
funnelVersion: ACTIVATION_FUNNEL_VERSION,
|
|
114
|
+
});
|
|
72
115
|
}
|
|
73
116
|
|
|
74
117
|
/**
|
|
@@ -93,6 +136,11 @@ export function queryUnreportedOnboardingEvents(
|
|
|
93
136
|
googleScopesJson: onboardingEvents.googleScopesJson,
|
|
94
137
|
priorAssistantsJson: onboardingEvents.priorAssistantsJson,
|
|
95
138
|
abVariant: onboardingEvents.abVariant,
|
|
139
|
+
sessionId: onboardingEvents.sessionId,
|
|
140
|
+
stepName: onboardingEvents.stepName,
|
|
141
|
+
stepIndex: onboardingEvents.stepIndex,
|
|
142
|
+
completedAt: onboardingEvents.completedAt,
|
|
143
|
+
funnelVersion: onboardingEvents.funnelVersion,
|
|
96
144
|
})
|
|
97
145
|
.from(onboardingEvents)
|
|
98
146
|
.where(
|