@vellumai/assistant 0.8.12 → 0.9.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/AGENTS.md +0 -14
- package/ARCHITECTURE.md +45 -45
- package/README.md +1 -1
- package/bun.lock +200 -154
- package/docs/architecture/integrations.md +3 -3
- package/docs/architecture/memory.md +2 -2
- package/docs/architecture/security.md +10 -10
- package/docs/runbook-trusted-contacts.md +12 -12
- package/docs/skills.md +6 -6
- package/docs/workflows-testing.md +221 -0
- package/docs/workflows.md +510 -0
- package/examples/plugins/echo/README.md +5 -5
- package/knip.json +2 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +105 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +12 -0
- package/openapi.yaml +7197 -5708
- package/package.json +8 -4
- package/scripts/generate-openapi.ts +66 -114
- package/src/__tests__/access-request-seed-content-blocks.test.ts +213 -0
- package/src/__tests__/adaptive-thinking-repair.test.ts +32 -3
- package/src/__tests__/agent-loop-output-hooks.test.ts +183 -0
- package/src/__tests__/agent-loop-regrowth-guard.test.ts +506 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +77 -0
- package/src/__tests__/app-compiler.test.ts +7 -1
- package/src/__tests__/app-dir-path-guard.test.ts +27 -3
- package/src/__tests__/app-executors.test.ts +43 -0
- package/src/__tests__/approval-cascade.test.ts +0 -5
- package/src/__tests__/approval-routes-http.test.ts +91 -0
- package/src/__tests__/assistant-stream-state.test.ts +107 -0
- package/src/__tests__/browser-fill-credential.test.ts +3 -3
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +1 -1
- package/src/__tests__/compaction-events.test.ts +63 -7
- package/src/__tests__/compaction-trail-store.test.ts +74 -1
- package/src/__tests__/compaction.benchmark.test.ts +63 -41
- package/src/__tests__/compactor-low-watermark-cut.test.ts +349 -0
- package/src/__tests__/context-window-manager-compact-retry.test.ts +64 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -5
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -5
- package/src/__tests__/conversation-history-web-search.test.ts +7 -0
- package/src/__tests__/conversation-process-callsite.test.ts +0 -5
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -5
- package/src/__tests__/conversation-queue.test.ts +0 -5
- package/src/__tests__/conversation-slash-queue.test.ts +0 -5
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -5
- package/src/__tests__/conversation-speed-override.test.ts +0 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +97 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-usage.test.ts +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -5
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -5
- package/src/__tests__/credential-broker-browser-fill.test.ts +2 -2
- package/src/__tests__/credential-broker-server-use.test.ts +2 -2
- package/src/__tests__/credential-broker.test.ts +1 -1
- package/src/__tests__/credential-prompt-route.test.ts +417 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault.test.ts +37 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +24 -0
- package/src/__tests__/dynamic-page-surface.test.ts +219 -0
- package/src/__tests__/empty-state-greeting-cache.test.ts +94 -0
- package/src/__tests__/gateway-flag-listener.test.ts +24 -7
- package/src/__tests__/guardian-action-sweep.test.ts +56 -219
- package/src/__tests__/guardian-routing-invariants.test.ts +138 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +99 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +87 -1
- package/src/__tests__/llm-resolver.test.ts +115 -0
- package/src/__tests__/managed-profile-guard.test.ts +6 -5
- package/src/__tests__/max-tokens-continue-hook.test.ts +184 -0
- package/src/__tests__/media-generate-image.test.ts +20 -9
- package/src/__tests__/mock-gateway-ipc.ts +23 -0
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/normalize-onboarding.test.ts +26 -0
- package/src/__tests__/notification-decision-strategy.test.ts +4 -2
- package/src/__tests__/notification-telegram-adapter.test.ts +21 -3
- package/src/__tests__/pending-interactions-resolved-event.test.ts +62 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +72 -18
- package/src/__tests__/require-fresh-approval.test.ts +425 -1
- package/src/__tests__/resolve-app-id.test.ts +56 -0
- package/src/__tests__/runtime-events-sse-parity.test.ts +2 -0
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +408 -0
- package/src/__tests__/schedule-routes.test.ts +257 -4
- package/src/__tests__/schedule-store.test.ts +60 -0
- package/src/__tests__/schedule-tools.test.ts +247 -2
- package/src/__tests__/skill-execute-input.test.ts +85 -0
- package/src/__tests__/skill-secret-handling-guard.test.ts +21 -20
- package/src/__tests__/skills.test.ts +3 -3
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +1 -1
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +547 -0
- package/src/__tests__/system-prompt.test.ts +1 -1
- package/src/__tests__/task-progress-nudge-hook.test.ts +372 -0
- package/src/__tests__/task-scheduler.test.ts +299 -0
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +209 -0
- package/src/__tests__/tool-result-spool.test.ts +3 -1
- package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +181 -0
- package/src/__tests__/workspace-migration-103-upgrade-quality-profile-to-opus-4-8.test.ts +174 -0
- package/src/agent/compaction-circuit.ts +11 -0
- package/src/agent/loop.ts +181 -12
- package/src/api/constants/call-sites.ts +12 -0
- package/src/api/events/assistant-thinking-delta.ts +10 -0
- package/src/api/events/usage-update.ts +7 -0
- package/src/api/index.ts +4 -1
- package/src/api/responses/memory-v3-selection-log.ts +18 -11
- package/src/approvals/approval-primitive.ts +2 -2
- package/src/background-wake/background-wake-routes.test.ts +5 -2
- package/src/bundler/compiler-tools.ts +1 -1
- package/src/bundler/package-resolver.ts +0 -1
- package/src/calls/call-domain.ts +1 -1
- package/src/calls/guardian-action-sweep.ts +16 -93
- package/src/cli/AGENTS.md +4 -0
- package/src/cli/commands/__tests__/schedules.test.ts +430 -1
- package/src/cli/commands/credentials.ts +28 -24
- package/src/cli/commands/image-generation.ts +23 -9
- package/src/cli/commands/notifications.ts +1 -1
- package/src/cli/commands/plugins.ts +89 -46
- package/src/cli/commands/schedules.ts +384 -11
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +69 -5
- package/src/cli/lib/__tests__/install-from-github.test.ts +15 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +81 -4
- package/src/cli/lib/inspect-plugin.ts +62 -1
- package/src/cli/lib/install-from-github.ts +52 -5
- package/src/cli/lib/upgrade-plugin.ts +18 -0
- package/src/config/__tests__/workflows-schema.test.ts +60 -0
- package/src/config/bundled-skills/acp/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +6 -1
- package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +7 -1
- package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +7 -1
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +10 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +66 -19
- package/src/config/bundled-skills/image-studio/TOOLS.json +1 -6
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +22 -3
- package/src/config/bundled-skills/personal-page/SKILL.md +57 -0
- package/src/config/bundled-skills/personal-page/TOOLS.json +27 -0
- package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +17 -0
- package/src/config/bundled-skills/schedule/SKILL.md +7 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +48 -4
- package/src/config/bundled-skills/workflows/SKILL.md +214 -0
- package/src/config/bundled-skills/workflows/TOOLS.json +84 -0
- package/src/config/bundled-skills/workflows/tools/manage-workflows.ts +12 -0
- package/src/config/bundled-skills/workflows/tools/run-workflow.ts +12 -0
- package/src/config/bundled-tool-registry.ts +14 -2
- package/src/config/call-site-defaults.ts +5 -0
- package/src/config/feature-flag-registry.json +12 -4
- package/src/config/llm-context-resolution.ts +8 -0
- package/src/config/llm-resolver.ts +30 -0
- package/src/config/preloaded-apps/personal-page/src/components/About.tsx +22 -0
- package/src/config/preloaded-apps/personal-page/src/components/App.tsx +16 -0
- package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +77 -0
- package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +57 -0
- package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +28 -0
- package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +234 -0
- package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +48 -0
- package/src/config/preloaded-apps/personal-page/src/components/media.ts +16 -0
- package/src/config/preloaded-apps/personal-page/src/index.html +20 -0
- package/src/config/preloaded-apps/personal-page/src/main.tsx +7 -0
- package/src/config/preloaded-apps/personal-page/src/profile-data.ts +82 -0
- package/src/config/preloaded-apps/personal-page/src/styles.css +759 -0
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/heartbeat.ts +4 -1
- package/src/config/schemas/llm.ts +33 -26
- package/src/config/schemas/memory-retrospective.ts +19 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/schemas/services.ts +5 -2
- package/src/config/schemas/workflows.ts +42 -0
- package/src/config/skills.ts +3 -3
- package/src/context/compactor.ts +273 -39
- package/src/context/post-turn-tool-result-truncation.ts +23 -6
- package/src/context/tool-result-spool.ts +12 -17
- package/src/credential-execution/executable-discovery.ts +1 -1
- package/src/credential-execution/process-manager.ts +37 -3
- package/src/credential-execution/prompted-credential.ts +205 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +14 -0
- package/src/daemon/conversation-process.ts +11 -2
- package/src/daemon/conversation-surfaces.ts +167 -3
- package/src/daemon/conversation-tool-setup.ts +103 -26
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +115 -11
- package/src/daemon/handlers/shared.ts +26 -14
- package/src/daemon/host-cu-proxy.ts +15 -12
- package/src/daemon/host-file-proxy.ts +15 -12
- package/src/daemon/host-transfer-proxy.ts +30 -24
- package/src/daemon/lifecycle.ts +40 -3
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/messages.ts +2 -10
- package/src/daemon/message-types/workflows.ts +49 -0
- package/src/daemon/parse-actual-tokens-from-error.test.ts +62 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +43 -4
- package/src/daemon/process-message.ts +6 -0
- package/src/daemon/tool-setup-types.ts +57 -0
- package/src/daemon/wake-conversation-ops.ts +18 -0
- package/src/heartbeat/heartbeat-run-store.ts +8 -2
- package/src/home/feed-types.ts +1 -1
- package/src/ipc/gateway-flag-listener.ts +28 -6
- package/src/mcp/mcp-auth-state.ts +8 -20
- package/src/media/__tests__/image-models.test.ts +57 -0
- package/src/media/image-models.ts +66 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +38 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +12 -2
- package/src/memory/__tests__/memory-retrospective-job.test.ts +911 -34
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +227 -5
- package/src/memory/__tests__/memory-retrospective-state.test.ts +195 -0
- package/src/memory/__tests__/preloaded-apps.test.ts +85 -0
- package/src/memory/auto-analysis-enqueue.ts +14 -1
- package/src/memory/compaction-log-store-clickhouse.ts +6 -4
- package/src/memory/conversation-crud.ts +9 -2
- package/src/memory/conversation-disk-view.ts +1 -1
- package/src/memory/conversation-queries.ts +22 -7
- package/src/memory/db-init.ts +20 -0
- package/src/memory/db-maintenance.ts +16 -0
- package/src/memory/embedding-runtime-manager.ts +1 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +112 -14
- package/src/memory/llm-request-log-source-local.ts +19 -1
- package/src/memory/llm-request-log-source.ts +35 -6
- package/src/memory/llm-request-log-store.ts +90 -2
- package/src/memory/memory-retrospective-constants.ts +9 -0
- package/src/memory/memory-retrospective-enqueue.ts +3 -6
- package/src/memory/memory-retrospective-fork-boundary.ts +94 -0
- package/src/memory/memory-retrospective-job.ts +500 -208
- package/src/memory/memory-retrospective-startup-cleanup.ts +97 -19
- package/src/memory/memory-retrospective-state.ts +85 -2
- package/src/memory/migrations/281-memory-retrospective-remembered-log.ts +40 -0
- package/src/memory/migrations/282-schedule-inference-profile.test.ts +77 -0
- package/src/memory/migrations/282-schedule-inference-profile.ts +26 -0
- package/src/memory/migrations/283-memory-v3-selections-message-id-and-sections.test.ts +102 -0
- package/src/memory/migrations/283-memory-v3-selections-message-id-and-sections.ts +53 -0
- package/src/memory/migrations/284-workflow-runs.ts +51 -0
- package/src/memory/migrations/285-schedule-workflow-mode.ts +26 -0
- package/src/memory/migrations/286-workflow-run-trust.ts +27 -0
- package/src/memory/migrations/287-conversation-origin-channel-index.ts +15 -0
- package/src/memory/migrations/288-backfill-origin-channel-from-bindings.ts +43 -0
- package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +115 -0
- package/src/memory/migrations/290-schedule-capabilities.test.ts +77 -0
- package/src/memory/migrations/290-schedule-capabilities.ts +25 -0
- package/src/memory/migrations/__tests__/281-memory-retrospective-remembered-log.test.ts +96 -0
- package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +571 -0
- package/src/memory/migrations/index.ts +10 -0
- package/src/memory/preloaded-apps.ts +116 -0
- package/src/memory/schema/infrastructure.ts +4 -0
- package/src/memory/schema/memory-core.ts +4 -0
- package/src/memory/v2/__tests__/concept-page-frontmatter-schema.test.ts +45 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +11 -7
- package/src/memory/v2/__tests__/page-store.test.ts +13 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +24 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -6
- package/src/memory/v2/page-store.ts +4 -3
- package/src/memory/v2/qdrant.ts +42 -3
- package/src/memory/v2/types.ts +16 -10
- package/src/messaging/draft-store.ts +1 -1
- package/src/notifications/access-request-copy.ts +200 -113
- package/src/notifications/adapters/slack.ts +250 -111
- package/src/notifications/adapters/telegram.ts +7 -44
- package/src/notifications/approval-card-builder.ts +93 -0
- package/src/notifications/broadcaster.ts +74 -0
- package/src/notifications/conversation-pairing.ts +8 -6
- package/src/notifications/copy-composer.ts +32 -26
- package/src/notifications/decision-engine.ts +59 -7
- package/src/notifications/guardian-question-mode.ts +145 -155
- package/src/notifications/home-feed-side-effect.ts +28 -11
- package/src/notifications/notification-utils.ts +66 -0
- package/src/notifications/signal.ts +6 -0
- package/src/notifications/tool-approval-copy.ts +142 -0
- package/src/notifications/types.ts +19 -0
- package/src/permissions/threshold.ts +11 -0
- package/src/plugin-api/types.ts +16 -4
- package/src/plugins/defaults/compaction/window-manager.ts +44 -0
- package/src/plugins/defaults/index.ts +46 -0
- package/src/plugins/defaults/max-tokens-continue/continue-state-store.ts +53 -0
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +80 -0
- package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +20 -0
- package/src/plugins/defaults/max-tokens-continue/package.json +14 -0
- package/src/plugins/defaults/memory-retrieval/hooks/__tests__/user-prompt-submit.test.ts +37 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +29 -1
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +8 -3
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +4 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +28 -18
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +67 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +122 -22
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +2 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +63 -1
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +61 -18
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +1 -1
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +39 -10
- package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +34 -1
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +112 -47
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +78 -15
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +206 -0
- package/src/plugins/defaults/task-progress-nudge/package.json +15 -0
- package/src/prompts/__tests__/system-prompt.test.ts +100 -1
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +5 -7
- package/src/prompts/normalize-onboarding.ts +2 -0
- package/src/prompts/persona-resolver.ts +3 -0
- package/src/prompts/system-prompt.ts +51 -2
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +3 -1
- package/src/prompts/templates/system-sections.ts +8 -3
- package/src/providers/call-site-routing.ts +6 -3
- package/src/providers/fireworks/client.ts +3 -0
- package/src/providers/inference/auth.ts +52 -46
- package/src/providers/model-intents.ts +2 -2
- package/src/providers/openai/__tests__/coerce-object-args.test.ts +105 -0
- package/src/providers/openai/chat-completions-provider.ts +47 -9
- package/src/providers/openai/coerce-object-args.ts +104 -0
- package/src/providers/retry.ts +8 -5
- package/src/providers/types.ts +10 -0
- package/src/runtime/__tests__/agent-wake.test.ts +629 -7
- package/src/runtime/access-request-helper.ts +16 -9
- package/src/runtime/agent-wake.ts +302 -51
- package/src/runtime/assistant-stream-state.ts +141 -8
- package/src/runtime/background-job-runner.ts +9 -0
- package/src/runtime/channel-approval-types.ts +1 -0
- package/src/runtime/channel-invite-transports/telegram.ts +6 -5
- package/src/runtime/channel-invite-transports/voice.ts +2 -2
- package/src/runtime/channel-invite-types.ts +4 -2
- package/src/runtime/channel-retry-sweep.ts +19 -41
- package/src/runtime/finalize-event-delivery.ts +72 -0
- package/src/runtime/guardian-action-message-composer.ts +0 -54
- package/src/runtime/http-server.ts +6 -14
- package/src/runtime/http-types.ts +0 -1
- package/src/runtime/message-composer-types.ts +0 -9
- package/src/runtime/middleware/__tests__/rate-limiter.test.ts +63 -0
- package/src/runtime/middleware/auth.ts +27 -3
- package/src/runtime/middleware/rate-limiter.ts +28 -1
- package/src/runtime/migrations/vbundle-builder.ts +6 -5
- package/src/runtime/pending-interactions.ts +20 -1
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +232 -173
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +18 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +436 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +11 -0
- package/src/runtime/routes/approval-routes.ts +35 -8
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -1
- package/src/runtime/routes/btw-routes.ts +37 -1
- package/src/runtime/routes/channel-delivery-routes.ts +11 -7
- package/src/runtime/routes/channel-route-definitions.ts +3 -0
- package/src/runtime/routes/channel-route-shared.ts +3 -1
- package/src/runtime/routes/consolidation-routes.ts +17 -13
- package/src/runtime/routes/conversation-compaction-routes.ts +159 -119
- package/src/runtime/routes/conversation-list-routes.ts +41 -4
- package/src/runtime/routes/conversation-query-routes.ts +196 -11
- package/src/runtime/routes/conversation-routes.ts +15 -1
- package/src/runtime/routes/credential-prompt-routes.ts +39 -17
- package/src/runtime/routes/empty-state-greeting-cache.ts +65 -0
- package/src/runtime/routes/heartbeat-routes.ts +18 -13
- package/src/runtime/routes/image-generation-routes.ts +20 -2
- package/src/runtime/routes/inbound-message-handler.ts +13 -12
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +32 -31
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +7 -5
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +7 -21
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +6 -15
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +1 -1
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/log-export/AGENTS.md +1 -1
- package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
- package/src/runtime/routes/migration-routes.ts +5 -9
- package/src/runtime/routes/plugins-routes.ts +26 -0
- package/src/runtime/routes/ps-routes.ts +10 -8
- package/src/runtime/routes/retrospective-routes.ts +235 -0
- package/src/runtime/routes/runs-pagination.ts +75 -0
- package/src/runtime/routes/schedule-routes.ts +367 -59
- package/src/runtime/routes/sounds-config-routes.ts +239 -0
- package/src/runtime/routes/surface-action-routes.ts +84 -4
- package/src/runtime/routes/workflow-routes.test.ts +372 -0
- package/src/runtime/routes/workflow-routes.ts +363 -0
- package/src/runtime/routes/workspace-routes.test.ts +61 -1
- package/src/runtime/routes/workspace-routes.ts +26 -1
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +38 -0
- package/src/runtime/services/analyze-conversation.ts +26 -13
- package/src/schedule/inference-profile.ts +28 -0
- package/src/schedule/schedule-store.ts +152 -4
- package/src/schedule/scheduler-types.ts +6 -0
- package/src/schedule/scheduler.ts +96 -0
- package/src/security/secret-allowlist.ts +1 -1
- package/src/skills/path-classifier.ts +1 -1
- package/src/tools/apps/executors.ts +23 -0
- package/src/tools/apps/resolve-app-id.ts +42 -0
- package/src/tools/browser/browser-execution.ts +9 -11
- package/src/tools/credentials/broker.ts +4 -4
- package/src/tools/credentials/vault.ts +26 -137
- package/src/tools/executor.ts +69 -0
- package/src/tools/flag-gated-tools.test.ts +76 -0
- package/src/tools/permission-checker.ts +8 -1
- package/src/tools/registry.ts +51 -0
- package/src/tools/schedule/create.ts +77 -1
- package/src/tools/schedule/list.ts +1 -0
- package/src/tools/schedule/update.ts +73 -1
- package/src/tools/skills/execute.ts +56 -0
- package/src/tools/terminal/shell.ts +1 -1
- package/src/tools/ui-surface/definitions.ts +91 -2
- package/src/tools/workflows/manage-workflows.ts +183 -0
- package/src/tools/workflows/run-workflow.test.ts +442 -0
- package/src/tools/workflows/run-workflow.ts +88 -0
- package/src/types/onboarding-context.ts +2 -0
- package/src/usage/attribution.ts +24 -0
- package/src/util/canonicalize-identity.ts +12 -3
- package/src/util/platform.ts +17 -17
- package/src/watcher/__tests__/engine.test.ts +24 -0
- package/src/watcher/__tests__/telemetry.test.ts +135 -0
- package/src/watcher/engine.ts +7 -0
- package/src/watcher/telemetry.ts +74 -0
- package/src/workflows/capabilities.test.ts +365 -0
- package/src/workflows/capabilities.ts +359 -0
- package/src/workflows/deterministic-stringify.ts +27 -0
- package/src/workflows/engine-integration.test.ts +656 -0
- package/src/workflows/engine.test.ts +1144 -0
- package/src/workflows/engine.ts +1078 -0
- package/src/workflows/fanout-load.test.ts +168 -0
- package/src/workflows/journal-store.test.ts +369 -0
- package/src/workflows/journal-store.ts +470 -0
- package/src/workflows/leaf-runner.test.ts +704 -0
- package/src/workflows/leaf-runner.ts +589 -0
- package/src/workflows/library.test.ts +134 -0
- package/src/workflows/library.ts +124 -0
- package/src/workflows/run-manager.test.ts +711 -0
- package/src/workflows/run-manager.ts +593 -0
- package/src/workflows/sandbox-escape.test.ts +339 -0
- package/src/workflows/sandbox.test.ts +251 -0
- package/src/workflows/sandbox.ts +447 -0
- package/src/workspace/adaptive-thinking-repair.ts +33 -11
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +1 -1
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +1 -1
- package/src/workspace/migrations/026-backfill-install-meta.ts +1 -1
- package/src/workspace/migrations/030-seed-pkb-autoinject.ts +2 -1
- package/src/workspace/migrations/031-drop-user-md.ts +1 -4
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +1 -1
- package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +5 -2
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +1 -1
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +8 -2
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +41 -14
- package/src/workspace/migrations/102-preserve-heartbeat-enabled-for-existing-workspaces.ts +69 -0
- package/src/workspace/migrations/103-upgrade-quality-profile-to-opus-4-8.ts +83 -0
- package/src/workspace/migrations/104-recheck-adaptive-thinking-model-implied-anthropic.ts +133 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/workspace/migrations/runner.ts +1 -1
- package/tsconfig.json +1 -1
- package/src/__tests__/guardian-action-copy-generator.test.ts +0 -200
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -579
- package/src/__tests__/guardian-action-store.test.ts +0 -106
- package/src/daemon/guardian-action-generators.ts +0 -71
- package/src/memory/guardian-action-store.ts +0 -484
- package/src/runtime/guardian-action-grant-minter.ts +0 -150
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Add `workflow_name` + `workflow_args_json` columns to `cron_jobs`.
|
|
6
|
+
*
|
|
7
|
+
* These back the new `workflow` schedule mode, which triggers a saved
|
|
8
|
+
* workflow by name on a schedule. Both are nullable and only populated for
|
|
9
|
+
* `mode = 'workflow'` rows; existing schedules stay NULL and unchanged.
|
|
10
|
+
*
|
|
11
|
+
* Idempotent — each ALTER is wrapped so a re-run (column already present)
|
|
12
|
+
* is a no-op.
|
|
13
|
+
*/
|
|
14
|
+
export function migrateScheduleWorkflowMode(database: DrizzleDb): void {
|
|
15
|
+
const raw = getSqliteFrom(database);
|
|
16
|
+
try {
|
|
17
|
+
raw.exec(`ALTER TABLE cron_jobs ADD COLUMN workflow_name TEXT`);
|
|
18
|
+
} catch {
|
|
19
|
+
/* Column already exists */
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
raw.exec(`ALTER TABLE cron_jobs ADD COLUMN workflow_args_json TEXT`);
|
|
23
|
+
} catch {
|
|
24
|
+
/* Column already exists */
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Add a `trust_json` column to `workflow_runs`.
|
|
6
|
+
*
|
|
7
|
+
* Persists the originating {@link TrustContext} (trust metadata — NOT secret
|
|
8
|
+
* material) so a crash-orphaned run can reconstruct the exact trust class it
|
|
9
|
+
* started under when it is resumed after a restart. Without this, resume could
|
|
10
|
+
* only fall back to a default, and the previous fallback was the internal
|
|
11
|
+
* guardian context — a privilege escalation, since a run started by a low-trust
|
|
12
|
+
* actor would resume with the side-effect approval gate cleared.
|
|
13
|
+
*
|
|
14
|
+
* Nullable — legacy rows written before this column stay NULL and resume at the
|
|
15
|
+
* low-trust fallback (never guardian).
|
|
16
|
+
*
|
|
17
|
+
* Idempotent — the ALTER is wrapped so a re-run (column already present) is a
|
|
18
|
+
* no-op.
|
|
19
|
+
*/
|
|
20
|
+
export function migrateWorkflowRunTrust(database: DrizzleDb): void {
|
|
21
|
+
const raw = getSqliteFrom(database);
|
|
22
|
+
try {
|
|
23
|
+
raw.exec(`ALTER TABLE workflow_runs ADD COLUMN trust_json TEXT`);
|
|
24
|
+
} catch {
|
|
25
|
+
/* Column already exists */
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Add an index on `origin_channel` to support the new `originChannel` query
|
|
5
|
+
* parameter on `GET /v1/conversations`. Channel-based sidebar sections fetch
|
|
6
|
+
* conversations filtered by origin channel; without this index, each such
|
|
7
|
+
* query requires a full table scan.
|
|
8
|
+
*/
|
|
9
|
+
export function migrateConversationOriginChannelIndex(
|
|
10
|
+
database: DrizzleDb,
|
|
11
|
+
): void {
|
|
12
|
+
database.run(
|
|
13
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_conversations_origin_channel ON conversations(origin_channel)`,
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fully normalize `conversations.origin_channel` so no rows remain NULL.
|
|
5
|
+
*
|
|
6
|
+
* Step 1: Backfill from `external_conversation_bindings.source_channel` for
|
|
7
|
+
* conversations that have a channel binding but NULL origin_channel (created
|
|
8
|
+
* before origin_channel was consistently set on first inbound message).
|
|
9
|
+
*
|
|
10
|
+
* Step 2: Set remaining NULL rows to 'vellum'. These are native/local
|
|
11
|
+
* conversations created before the mechanism existed — they have no external
|
|
12
|
+
* binding and were always implicitly vellum-channel conversations.
|
|
13
|
+
*/
|
|
14
|
+
export function migrateBackfillOriginChannelFromBindings(
|
|
15
|
+
database: DrizzleDb,
|
|
16
|
+
): void {
|
|
17
|
+
const raw = getSqliteFrom(database);
|
|
18
|
+
|
|
19
|
+
// Step 1: Backfill from external bindings
|
|
20
|
+
raw
|
|
21
|
+
.query(
|
|
22
|
+
/*sql*/ `
|
|
23
|
+
UPDATE conversations
|
|
24
|
+
SET origin_channel = (
|
|
25
|
+
SELECT source_channel
|
|
26
|
+
FROM external_conversation_bindings
|
|
27
|
+
WHERE external_conversation_bindings.conversation_id = conversations.id
|
|
28
|
+
)
|
|
29
|
+
WHERE origin_channel IS NULL
|
|
30
|
+
AND id IN (
|
|
31
|
+
SELECT conversation_id FROM external_conversation_bindings
|
|
32
|
+
)
|
|
33
|
+
`,
|
|
34
|
+
)
|
|
35
|
+
.run();
|
|
36
|
+
|
|
37
|
+
// Step 2: Remaining NULL rows are native/local — set to 'vellum'
|
|
38
|
+
raw
|
|
39
|
+
.query(
|
|
40
|
+
/*sql*/ `UPDATE conversations SET origin_channel = 'vellum' WHERE origin_channel IS NULL`,
|
|
41
|
+
)
|
|
42
|
+
.run();
|
|
43
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { getLogger } from "../../util/logger.js";
|
|
2
|
+
import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
|
|
4
|
+
const log = getLogger("migration-289");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Deduplicates historical case collisions in contact_channels.
|
|
8
|
+
*
|
|
9
|
+
* Pure dedup — removes duplicate rows but does not change any stored values.
|
|
10
|
+
*
|
|
11
|
+
* Steps:
|
|
12
|
+
* 1. Deduplicate by (type, address) case-insensitively — keeps the best row.
|
|
13
|
+
* 2. Deduplicate by (type, external_user_id) case-insensitively — ensures
|
|
14
|
+
* at most one row per external identity.
|
|
15
|
+
* 3. Remove cross-column collision blockers — rows with NULL external_user_id
|
|
16
|
+
* whose address equals another row's external_user_id.
|
|
17
|
+
*/
|
|
18
|
+
export function migrateContactChannelsUniqueExtUser(database: DrizzleDb): void {
|
|
19
|
+
const raw = getSqliteFrom(database);
|
|
20
|
+
|
|
21
|
+
// Step 1: Deduplicate historical case collisions. After this, the existing
|
|
22
|
+
// case-sensitive UNIQUE(type, address) constraint remains valid because
|
|
23
|
+
// only one row per case-insensitive group survives.
|
|
24
|
+
const addressDedupResult = raw.run(/*sql*/ `
|
|
25
|
+
DELETE FROM contact_channels
|
|
26
|
+
WHERE id NOT IN (
|
|
27
|
+
SELECT id FROM (
|
|
28
|
+
SELECT id,
|
|
29
|
+
ROW_NUMBER() OVER (
|
|
30
|
+
PARTITION BY type, address COLLATE NOCASE
|
|
31
|
+
ORDER BY
|
|
32
|
+
CASE status
|
|
33
|
+
WHEN 'blocked' THEN 0
|
|
34
|
+
WHEN 'revoked' THEN 1
|
|
35
|
+
WHEN 'active' THEN 2
|
|
36
|
+
WHEN 'unverified' THEN 3
|
|
37
|
+
ELSE 4
|
|
38
|
+
END,
|
|
39
|
+
updated_at DESC
|
|
40
|
+
) AS rn
|
|
41
|
+
FROM contact_channels
|
|
42
|
+
)
|
|
43
|
+
WHERE rn = 1
|
|
44
|
+
)
|
|
45
|
+
`);
|
|
46
|
+
|
|
47
|
+
if (addressDedupResult.changes > 0) {
|
|
48
|
+
log.info(
|
|
49
|
+
{ rowsDeleted: addressDedupResult.changes },
|
|
50
|
+
"Deduplicated contact_channels by (type, address) case-insensitive",
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Step 2: Deduplicate by (type, external_user_id) so that a future
|
|
55
|
+
// normalization (SET address = external_user_id) cannot produce collisions.
|
|
56
|
+
// Two rows with different addresses but the same external_user_id would
|
|
57
|
+
// both get the same address after normalization.
|
|
58
|
+
const extIdDedupResult = raw.run(/*sql*/ `
|
|
59
|
+
DELETE FROM contact_channels
|
|
60
|
+
WHERE external_user_id IS NOT NULL
|
|
61
|
+
AND id NOT IN (
|
|
62
|
+
SELECT id FROM (
|
|
63
|
+
SELECT id,
|
|
64
|
+
ROW_NUMBER() OVER (
|
|
65
|
+
PARTITION BY type, external_user_id COLLATE NOCASE
|
|
66
|
+
ORDER BY
|
|
67
|
+
CASE status
|
|
68
|
+
WHEN 'blocked' THEN 0
|
|
69
|
+
WHEN 'revoked' THEN 1
|
|
70
|
+
WHEN 'active' THEN 2
|
|
71
|
+
WHEN 'unverified' THEN 3
|
|
72
|
+
ELSE 4
|
|
73
|
+
END,
|
|
74
|
+
updated_at DESC
|
|
75
|
+
) AS rn
|
|
76
|
+
FROM contact_channels
|
|
77
|
+
WHERE external_user_id IS NOT NULL
|
|
78
|
+
)
|
|
79
|
+
WHERE rn = 1
|
|
80
|
+
)
|
|
81
|
+
`);
|
|
82
|
+
|
|
83
|
+
if (extIdDedupResult.changes > 0) {
|
|
84
|
+
log.info(
|
|
85
|
+
{ rowsDeleted: extIdDedupResult.changes },
|
|
86
|
+
"Deduplicated contact_channels by (type, external_user_id)",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Step 3: Remove rows that would block future normalization due to
|
|
91
|
+
// cross-column collisions. A row with NULL external_user_id whose address
|
|
92
|
+
// equals another row's external_user_id would prevent that row's
|
|
93
|
+
// normalization in a later migration.
|
|
94
|
+
const crossColResult = raw.run(/*sql*/ `
|
|
95
|
+
DELETE FROM contact_channels
|
|
96
|
+
WHERE external_user_id IS NULL
|
|
97
|
+
AND id IN (
|
|
98
|
+
SELECT blocker.id
|
|
99
|
+
FROM contact_channels AS blocker
|
|
100
|
+
INNER JOIN contact_channels AS normalizer
|
|
101
|
+
ON normalizer.type = blocker.type
|
|
102
|
+
AND normalizer.external_user_id = blocker.address COLLATE NOCASE
|
|
103
|
+
AND normalizer.address != normalizer.external_user_id
|
|
104
|
+
AND normalizer.external_user_id IS NOT NULL
|
|
105
|
+
AND normalizer.id != blocker.id
|
|
106
|
+
)
|
|
107
|
+
`);
|
|
108
|
+
|
|
109
|
+
if (crossColResult.changes > 0) {
|
|
110
|
+
log.info(
|
|
111
|
+
{ rowsDeleted: crossColResult.changes },
|
|
112
|
+
"Removed cross-column collision blockers",
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import { describe, expect, test } from "bun:test";
|
|
3
|
+
|
|
4
|
+
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
5
|
+
|
|
6
|
+
import * as schema from "../schema.js";
|
|
7
|
+
import { migrateScheduleCapabilities } from "./290-schedule-capabilities.js";
|
|
8
|
+
|
|
9
|
+
function createTestDb() {
|
|
10
|
+
const sqlite = new Database(":memory:");
|
|
11
|
+
// Pre-290 shape: no capabilities_json column (trimmed to the columns the
|
|
12
|
+
// migration and assertions touch).
|
|
13
|
+
sqlite.exec(/*sql*/ `
|
|
14
|
+
CREATE TABLE cron_jobs (
|
|
15
|
+
id TEXT PRIMARY KEY,
|
|
16
|
+
name TEXT NOT NULL,
|
|
17
|
+
message TEXT NOT NULL,
|
|
18
|
+
next_run_at INTEGER NOT NULL,
|
|
19
|
+
created_by TEXT NOT NULL,
|
|
20
|
+
created_at INTEGER NOT NULL,
|
|
21
|
+
updated_at INTEGER NOT NULL
|
|
22
|
+
)
|
|
23
|
+
`);
|
|
24
|
+
return { sqlite, db: drizzle(sqlite, { schema }) };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function columnNames(sqlite: Database): string[] {
|
|
28
|
+
return (
|
|
29
|
+
sqlite.query("PRAGMA table_info(cron_jobs)").all() as Array<{
|
|
30
|
+
name: string;
|
|
31
|
+
}>
|
|
32
|
+
).map((c) => c.name);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe("migration 290: cron_jobs capabilities_json", () => {
|
|
36
|
+
test("adds a nullable capabilities_json column", () => {
|
|
37
|
+
const { sqlite, db } = createTestDb();
|
|
38
|
+
expect(columnNames(sqlite)).not.toContain("capabilities_json");
|
|
39
|
+
|
|
40
|
+
migrateScheduleCapabilities(db);
|
|
41
|
+
|
|
42
|
+
const column = (
|
|
43
|
+
sqlite.query("PRAGMA table_info(cron_jobs)").all() as Array<{
|
|
44
|
+
name: string;
|
|
45
|
+
notnull: number;
|
|
46
|
+
}>
|
|
47
|
+
).find((c) => c.name === "capabilities_json");
|
|
48
|
+
expect(column).toBeDefined();
|
|
49
|
+
expect(column?.notnull).toBe(0);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("existing rows read back with capabilities_json null", () => {
|
|
53
|
+
const { sqlite, db } = createTestDb();
|
|
54
|
+
sqlite.exec(/*sql*/ `
|
|
55
|
+
INSERT INTO cron_jobs (id, name, message, next_run_at, created_by, created_at, updated_at)
|
|
56
|
+
VALUES ('job-1', 'Daily digest', 'write the digest', 1000, 'agent', 1000, 1000)
|
|
57
|
+
`);
|
|
58
|
+
|
|
59
|
+
migrateScheduleCapabilities(db);
|
|
60
|
+
|
|
61
|
+
const row = sqlite
|
|
62
|
+
.query("SELECT capabilities_json FROM cron_jobs WHERE id = 'job-1'")
|
|
63
|
+
.get() as { capabilities_json: string | null };
|
|
64
|
+
expect(row.capabilities_json).toBeNull();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("is idempotent — re-run is a no-op", () => {
|
|
68
|
+
const { sqlite, db } = createTestDb();
|
|
69
|
+
|
|
70
|
+
migrateScheduleCapabilities(db);
|
|
71
|
+
expect(() => migrateScheduleCapabilities(db)).not.toThrow();
|
|
72
|
+
|
|
73
|
+
expect(
|
|
74
|
+
columnNames(sqlite).filter((name) => name === "capabilities_json"),
|
|
75
|
+
).toHaveLength(1);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Add a nullable `capabilities_json TEXT` column to `cron_jobs`.
|
|
6
|
+
*
|
|
7
|
+
* Persists the capability manifest a scheduled workflow run should execute
|
|
8
|
+
* under. `NULL` (all pre-existing rows) means no persisted manifest — runs
|
|
9
|
+
* fall back to the hardcoded read-only manifest.
|
|
10
|
+
*
|
|
11
|
+
* Idempotent — the PRAGMA guard makes re-running a no-op once the column
|
|
12
|
+
* exists.
|
|
13
|
+
*/
|
|
14
|
+
export function migrateScheduleCapabilities(database: DrizzleDb): void {
|
|
15
|
+
const raw = getSqliteFrom(database);
|
|
16
|
+
|
|
17
|
+
const columns = raw.query(`PRAGMA table_info(cron_jobs)`).all() as Array<{
|
|
18
|
+
name: string;
|
|
19
|
+
}>;
|
|
20
|
+
const columnNames = new Set(columns.map((c) => c.name));
|
|
21
|
+
|
|
22
|
+
if (!columnNames.has("capabilities_json")) {
|
|
23
|
+
raw.exec(`ALTER TABLE cron_jobs ADD COLUMN capabilities_json TEXT`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import { describe, expect, test } from "bun:test";
|
|
3
|
+
|
|
4
|
+
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
5
|
+
|
|
6
|
+
import { getSqliteFrom } from "../../db-connection.js";
|
|
7
|
+
import * as schema from "../../schema.js";
|
|
8
|
+
import { migrateMemoryRetrospectiveState } from "../245-memory-retrospective-state.js";
|
|
9
|
+
import { migrateMemoryRetrospectiveRememberedLog } from "../281-memory-retrospective-remembered-log.js";
|
|
10
|
+
|
|
11
|
+
interface ColumnRow {
|
|
12
|
+
name: string;
|
|
13
|
+
type: string;
|
|
14
|
+
notnull: number;
|
|
15
|
+
dflt_value: string | null;
|
|
16
|
+
pk: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function createTestDb() {
|
|
20
|
+
const sqlite = new Database(":memory:");
|
|
21
|
+
sqlite.exec("PRAGMA journal_mode=WAL");
|
|
22
|
+
sqlite.exec("PRAGMA foreign_keys = ON");
|
|
23
|
+
// `withCrashRecovery` (used by the migrations) reads/writes a
|
|
24
|
+
// `memory_checkpoints` table. Seed a minimal version so the migrations'
|
|
25
|
+
// structural setup can be exercised without booting the entire
|
|
26
|
+
// db-init pipeline.
|
|
27
|
+
sqlite.exec(`
|
|
28
|
+
CREATE TABLE memory_checkpoints (
|
|
29
|
+
key TEXT PRIMARY KEY,
|
|
30
|
+
value TEXT NOT NULL,
|
|
31
|
+
updated_at INTEGER NOT NULL
|
|
32
|
+
)
|
|
33
|
+
`);
|
|
34
|
+
// The state table FK references `conversations(id)`. Minimal stand-in.
|
|
35
|
+
sqlite.exec(`
|
|
36
|
+
CREATE TABLE conversations (
|
|
37
|
+
id TEXT PRIMARY KEY,
|
|
38
|
+
created_at INTEGER NOT NULL
|
|
39
|
+
)
|
|
40
|
+
`);
|
|
41
|
+
return drizzle(sqlite, { schema });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe("migration 281 — memory_retrospective_state.remembered_log", () => {
|
|
45
|
+
test("adds a nullable remembered_log TEXT column", () => {
|
|
46
|
+
const db = createTestDb();
|
|
47
|
+
const raw = getSqliteFrom(db);
|
|
48
|
+
|
|
49
|
+
migrateMemoryRetrospectiveState(db);
|
|
50
|
+
migrateMemoryRetrospectiveRememberedLog(db);
|
|
51
|
+
|
|
52
|
+
const cols = raw
|
|
53
|
+
.query(`PRAGMA table_info(memory_retrospective_state)`)
|
|
54
|
+
.all() as ColumnRow[];
|
|
55
|
+
const col = cols.find((c) => c.name === "remembered_log");
|
|
56
|
+
|
|
57
|
+
expect(col).toBeDefined();
|
|
58
|
+
expect(col!.type).toBe("TEXT");
|
|
59
|
+
expect(col!.notnull).toBe(0);
|
|
60
|
+
expect(col!.pk).toBe(0);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("is idempotent — running twice does not throw or duplicate the column", () => {
|
|
64
|
+
const db = createTestDb();
|
|
65
|
+
const raw = getSqliteFrom(db);
|
|
66
|
+
|
|
67
|
+
migrateMemoryRetrospectiveState(db);
|
|
68
|
+
migrateMemoryRetrospectiveRememberedLog(db);
|
|
69
|
+
expect(() => migrateMemoryRetrospectiveRememberedLog(db)).not.toThrow();
|
|
70
|
+
|
|
71
|
+
const cols = raw
|
|
72
|
+
.query(`PRAGMA table_info(memory_retrospective_state)`)
|
|
73
|
+
.all() as ColumnRow[];
|
|
74
|
+
expect(cols.filter((c) => c.name === "remembered_log")).toHaveLength(1);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("pre-existing rows get NULL for the new column", () => {
|
|
78
|
+
const db = createTestDb();
|
|
79
|
+
const raw = getSqliteFrom(db);
|
|
80
|
+
|
|
81
|
+
migrateMemoryRetrospectiveState(db);
|
|
82
|
+
raw.exec(`INSERT INTO conversations (id, created_at) VALUES ('c1', 0)`);
|
|
83
|
+
raw.exec(
|
|
84
|
+
`INSERT INTO memory_retrospective_state (conversation_id, last_processed_message_id, last_run_at) VALUES ('c1', 'm1', 1000)`,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
migrateMemoryRetrospectiveRememberedLog(db);
|
|
88
|
+
|
|
89
|
+
const row = raw
|
|
90
|
+
.query(
|
|
91
|
+
`SELECT remembered_log FROM memory_retrospective_state WHERE conversation_id = 'c1'`,
|
|
92
|
+
)
|
|
93
|
+
.get() as { remembered_log: string | null };
|
|
94
|
+
expect(row.remembered_log).toBeNull();
|
|
95
|
+
});
|
|
96
|
+
});
|