@vellumai/assistant 0.8.5 → 0.8.6
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 +33 -1
- package/ARCHITECTURE.md +1 -1
- package/bunfig.toml +6 -1
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +4 -3
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
- package/openapi.yaml +1900 -166
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +3 -2
- package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
- package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/annotate-risk-options.test.ts +1 -0
- package/src/__tests__/approval-cascade.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +9 -13
- package/src/__tests__/assert-not-live-db.ts +79 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +9 -25
- package/src/__tests__/audit-log-rotation.test.ts +2 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
- package/src/__tests__/background-workers-disk-pressure.test.ts +5 -8
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +3 -2
- package/src/__tests__/call-controller.test.ts +3 -2
- package/src/__tests__/channel-approval-routes.test.ts +3 -2
- package/src/__tests__/channel-guardian.test.ts +3 -2
- package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
- package/src/__tests__/channel-reply-delivery.test.ts +35 -0
- package/src/__tests__/channel-retry-sweep.test.ts +320 -3
- package/src/__tests__/checker.test.ts +12 -12
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/compaction-trail-store.test.ts +264 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
- package/src/__tests__/computer-use-tools.test.ts +12 -14
- package/src/__tests__/config-loader-backfill.test.ts +13 -28
- package/src/__tests__/config-loader-corrupt.test.ts +5 -5
- package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
- package/src/__tests__/config-schema.test.ts +10 -10
- package/src/__tests__/connection-model-compat.test.ts +83 -0
- package/src/__tests__/contacts-tools.test.ts +3 -2
- package/src/__tests__/context-token-estimator.test.ts +22 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +34 -0
- package/src/__tests__/conversation-agent-loop.test.ts +488 -2
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
- package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-attention-store.test.ts +101 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
- package/src/__tests__/conversation-error.test.ts +30 -0
- package/src/__tests__/conversation-fork-crud.test.ts +69 -8
- package/src/__tests__/conversation-fork-route.test.ts +3 -2
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
- package/src/__tests__/conversation-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-list-source.test.ts +3 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
- package/src/__tests__/conversation-load-history-stripped.test.ts +1 -0
- package/src/__tests__/conversation-pairing.test.ts +53 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
- package/src/__tests__/conversation-process-callsite.test.ts +1 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -0
- package/src/__tests__/conversation-queue.test.ts +333 -291
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -18
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
- package/src/__tests__/conversation-routes-slash-commands.test.ts +33 -2
- package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
- package/src/__tests__/conversation-skill-tools.test.ts +38 -142
- package/src/__tests__/conversation-slash-queue.test.ts +84 -32
- package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
- package/src/__tests__/conversation-speed-override.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
- package/src/__tests__/conversation-sync-tags.test.ts +128 -12
- package/src/__tests__/conversation-title-service.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
- package/src/__tests__/conversation-usage.test.ts +1 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
- package/src/__tests__/credential-broker-server-use.test.ts +5 -5
- package/src/__tests__/credential-execution-client.test.ts +72 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
- package/src/__tests__/credential-health-service.test.ts +252 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -5
- package/src/__tests__/credential-vault-unit.test.ts +19 -19
- package/src/__tests__/credential-vault.test.ts +5 -5
- package/src/__tests__/cross-provider-web-search.test.ts +56 -2
- package/src/__tests__/db-connection-isolation.test.ts +7 -6
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
- package/src/__tests__/db-test-helpers.ts +58 -0
- package/src/__tests__/disk-pressure-guard.test.ts +58 -41
- package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
- package/src/__tests__/disk-pressure-routes.test.ts +0 -33
- package/src/__tests__/disk-pressure-tools.test.ts +0 -4
- package/src/__tests__/dm-persistence.test.ts +26 -40
- package/src/__tests__/document-create-dedupe.test.ts +189 -0
- package/src/__tests__/document-find-replace.test.ts +3 -2
- package/src/__tests__/document-tool-security.test.ts +81 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
- package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
- package/src/__tests__/encrypted-store.test.ts +11 -9
- package/src/__tests__/feature-flag-test-helpers.ts +53 -0
- package/src/__tests__/filing-service.test.ts +1 -0
- package/src/__tests__/first-greeting.test.ts +62 -12
- package/src/__tests__/gateway-flag-listener.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +26 -0
- package/src/__tests__/guardian-action-sweep.test.ts +3 -2
- package/src/__tests__/guardian-outbound-http.test.ts +3 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/mock-logger.ts +26 -0
- package/src/__tests__/host-bash-routes.test.ts +1 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-shell-tool.test.ts +5 -4
- package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +29 -7
- package/src/__tests__/identity-intro-cache.test.ts +133 -22
- package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
- package/src/__tests__/inference-profile-reaper.test.ts +3 -2
- package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
- package/src/__tests__/injector-disk-pressure.test.ts +3 -17
- package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
- package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
- package/src/__tests__/llm-context-normalization.test.ts +42 -0
- package/src/__tests__/llm-resolver.test.ts +331 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
- package/src/__tests__/mcp-abort-signal.test.ts +14 -0
- package/src/__tests__/mcp-client-auth.test.ts +14 -0
- package/src/__tests__/messaging-send-tool.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +18 -2
- package/src/__tests__/model-intents.test.ts +3 -3
- package/src/__tests__/native-web-search.test.ts +30 -2
- package/src/__tests__/notification-deep-link.test.ts +62 -0
- package/src/__tests__/oauth-commands-routes.test.ts +37 -0
- package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
- package/src/__tests__/oauth-store.test.ts +3 -2
- package/src/__tests__/onboarding-template-contract.test.ts +3 -2
- package/src/__tests__/openai-provider.test.ts +8 -9
- package/src/__tests__/openai-responses-provider.test.ts +70 -10
- package/src/__tests__/openrouter-provider-only.test.ts +27 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
- package/src/__tests__/persistence-pipeline.test.ts +139 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
- package/src/__tests__/plugin-bootstrap.test.ts +9 -11
- package/src/__tests__/plugin-tool-contribution.test.ts +41 -38
- package/src/__tests__/process-message-background-slack.test.ts +21 -16
- package/src/__tests__/process-message-display-content.test.ts +19 -22
- package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
- package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
- package/src/__tests__/provider-registry-ollama.test.ts +45 -22
- package/src/__tests__/recording-handler.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +82 -76
- package/src/__tests__/relay-server.test.ts +10 -10
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
- package/src/__tests__/schedule-store.test.ts +16 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
- package/src/__tests__/secret-ingress-http.test.ts +5 -1
- package/src/__tests__/secure-keys.test.ts +3 -3
- package/src/__tests__/send-endpoint-busy.test.ts +81 -42
- package/src/__tests__/server-history-render.test.ts +4 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
- package/src/__tests__/skill-feature-flags.test.ts +14 -16
- package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
- package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
- package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
- package/src/__tests__/skill-tool-factory.test.ts +96 -95
- package/src/__tests__/slack-channel-config.test.ts +3 -3
- package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
- package/src/__tests__/subagent-disposal.test.ts +27 -8
- package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
- package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
- package/src/__tests__/subagent-manager-notify.test.ts +20 -8
- package/src/__tests__/subagent-notify-parent.test.ts +5 -4
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
- package/src/__tests__/subagent-tools.test.ts +2 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/system-prompt.test.ts +38 -0
- package/src/__tests__/test-preload-verifier.ts +68 -0
- package/src/__tests__/test-preload.ts +32 -39
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
- package/src/__tests__/tool-executor.test.ts +55 -10
- package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/twilio-routes.test.ts +3 -2
- package/src/__tests__/validate-input.test.ts +381 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
- package/src/__tests__/voice-session-bridge.test.ts +37 -28
- package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
- package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
- package/src/acp/session-manager.ts +5 -6
- package/src/agent/loop.ts +80 -0
- package/src/api/README.md +124 -2
- package/src/api/constants/call-sites.ts +27 -0
- package/src/api/events/assistant-outbound-attachment.ts +51 -0
- package/src/api/events/assistant-text-delta.ts +32 -0
- package/src/api/events/assistant-turn-start.ts +33 -0
- package/src/api/events/document-comment-created.ts +48 -0
- package/src/api/events/document-comment-deleted.ts +24 -0
- package/src/api/events/document-comment-reopened.ts +25 -0
- package/src/api/events/document-comment-resolved.ts +27 -0
- package/src/api/events/generation-cancelled.ts +24 -0
- package/src/api/events/generation-handoff.ts +41 -0
- package/src/api/events/message-complete.ts +42 -0
- package/src/api/events/open-url.ts +30 -0
- package/src/{events → api/events}/relationship-state-updated.ts +3 -3
- package/src/api/events/tool-use-start.ts +32 -0
- package/src/api/index.ts +128 -3
- package/src/api/responses/llm-context-response.ts +39 -0
- package/src/api/responses/llm-request-log-entry.ts +93 -0
- package/src/api/responses/memory-recall-log.ts +65 -0
- package/src/api/responses/memory-v2-activation-log.ts +78 -0
- package/src/background-wake/background-wake-routes.test.ts +687 -52
- package/src/background-wake/platform-client.test.ts +308 -0
- package/src/background-wake/platform-client.ts +167 -0
- package/src/background-wake/publisher.ts +91 -0
- package/src/background-wake/runtime-registry.ts +2 -2
- package/src/background-wake/wake-intent-hooks.test.ts +282 -0
- package/src/calls/guardian-dispatch.ts +1 -0
- package/src/calls/voice-session-bridge.ts +4 -4
- package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
- package/src/cli/commands/__tests__/notifications.test.ts +184 -40
- package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
- package/src/cli/commands/channels/index.ts +229 -0
- package/src/cli/commands/memory-v3-render.ts +147 -0
- package/src/cli/commands/memory-v3.ts +255 -4
- package/src/cli/commands/notifications.ts +365 -55
- package/src/cli/lib/open-browser.ts +7 -2
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +23 -42
- package/src/config/bundled-skills/document-editor/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
- package/src/config/call-site-defaults.ts +1 -1
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +17 -17
- package/src/config/llm-context-resolution.ts +10 -1
- package/src/config/llm-resolver.ts +121 -15
- package/src/config/loader.ts +4 -5
- package/src/config/schemas/__tests__/memory-v2.test.ts +15 -0
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +90 -1
- package/src/config/schemas/memory-v2.ts +26 -0
- package/src/config/schemas/services.ts +6 -2
- package/src/config/seed-inference-profiles.ts +36 -16
- package/src/context/token-estimator.ts +10 -5
- package/src/credential-execution/executable-discovery.ts +40 -0
- package/src/credential-execution/process-manager.ts +6 -2
- package/src/credential-health/credential-health-service.ts +125 -40
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +389 -68
- package/src/daemon/conversation-agent-loop.ts +132 -28
- package/src/daemon/conversation-error.ts +33 -5
- package/src/daemon/conversation-messaging.ts +84 -43
- package/src/daemon/conversation-process.ts +74 -37
- package/src/daemon/conversation-runtime-assembly.ts +29 -9
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-surfaces.ts +69 -34
- package/src/daemon/conversation-tool-setup.ts +33 -48
- package/src/daemon/conversation.ts +26 -46
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/daemon-skill-host.ts +9 -2
- package/src/daemon/disk-pressure-guard.ts +27 -29
- package/src/daemon/first-greeting.ts +31 -13
- package/src/daemon/handlers/shared.ts +6 -1
- package/src/daemon/lifecycle.ts +12 -12
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/meet-manifest-loader.ts +10 -17
- package/src/daemon/message-types/conversations.ts +20 -22
- package/src/daemon/message-types/document-comments.ts +8 -44
- package/src/daemon/message-types/home.ts +2 -2
- package/src/daemon/message-types/integrations.ts +2 -7
- package/src/daemon/message-types/messages.ts +23 -38
- package/src/daemon/message-types/subagents.ts +6 -0
- package/src/daemon/process-message.ts +9 -9
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +16 -0
- package/src/daemon/switch-inference-profile-tool.ts +13 -3
- package/src/daemon/tool-setup-types.ts +0 -6
- package/src/daemon/wake-target-adapter.ts +10 -0
- package/src/documents/document-store.ts +38 -0
- package/src/export/__tests__/transcript-formatter.test.ts +1 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +29 -0
- package/src/heartbeat/heartbeat-service.ts +63 -0
- package/src/home/__tests__/feed-writer.test.ts +161 -0
- package/src/home/__tests__/post-connect-feed.test.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +55 -59
- package/src/home/feed-writer.ts +146 -7
- package/src/home/suggested-prompts.ts +27 -145
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/gateway-client.test.ts +4 -1
- package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
- package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
- package/src/ipc/skill-routes/memory.ts +4 -3
- package/src/ipc/skill-routes/registries.ts +28 -29
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
- package/src/memory/conversation-attention-store.ts +17 -3
- package/src/memory/conversation-crud.ts +352 -112
- package/src/memory/db-connection.ts +29 -19
- package/src/memory/db-init.ts +4 -0
- package/src/memory/db-singleton.ts +77 -0
- package/src/memory/delivery-channels.ts +82 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
- package/src/memory/graph/retriever.test.ts +3 -3
- package/src/memory/job-handlers/embedding.test.ts +3 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
- package/src/memory/jobs-worker.ts +12 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +80 -0
- package/src/memory/llm-request-log-source-local.ts +24 -0
- package/src/memory/llm-request-log-source.ts +31 -0
- package/src/memory/llm-request-log-store.ts +188 -3
- package/src/memory/memory-v2-activation-log-store.ts +95 -1
- package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
- package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/schema/conversations.ts +9 -1
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
- package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
- package/src/memory/v2/harness/metrics.ts +5 -1
- package/src/memory/v2/harness/replay-input.ts +19 -3
- package/src/memory/v2/harness/runner.ts +6 -0
- package/src/memory/v2/harness/trace.ts +6 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +2 -4
- package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
- package/src/memory/v3/__tests__/edges.test.ts +144 -1
- package/src/memory/v3/__tests__/filter.test.ts +48 -0
- package/src/memory/v3/__tests__/gate.test.ts +96 -33
- package/src/memory/v3/__tests__/index-composition.test.ts +58 -0
- package/src/memory/v3/__tests__/loop.test.ts +250 -5
- package/src/memory/v3/__tests__/scouts.test.ts +49 -0
- package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +88 -2
- package/src/memory/v3/__tests__/traversal.test.ts +39 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +77 -0
- package/src/memory/v3/__tests__/validate.test.ts +32 -0
- package/src/memory/v3/coretrieval-seed.ts +240 -0
- package/src/memory/v3/edges.ts +58 -21
- package/src/memory/v3/filter.ts +27 -22
- package/src/memory/v3/gate.ts +51 -36
- package/src/memory/v3/index-composition.ts +18 -5
- package/src/memory/v3/loop.ts +65 -17
- package/src/memory/v3/scouts.ts +15 -4
- package/src/memory/v3/shadow-diff.ts +287 -0
- package/src/memory/v3/shadow-middleware.ts +44 -2
- package/src/memory/v3/traversal.ts +6 -1
- package/src/memory/v3/tree-walk.ts +6 -1
- package/src/memory/v3/validate.ts +56 -33
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
- package/src/notifications/adapters/slack.ts +45 -11
- package/src/notifications/broadcaster.ts +114 -63
- package/src/notifications/conversation-pairing.ts +23 -3
- package/src/notifications/decisions-store.ts +32 -1
- package/src/notifications/deliveries-store.ts +45 -0
- package/src/notifications/edit-notification.ts +201 -0
- package/src/notifications/emit-signal.ts +11 -1
- package/src/notifications/signal.ts +10 -0
- package/src/notifications/types.ts +37 -0
- package/src/oauth/byo-connection.test.ts +67 -3
- package/src/oauth/byo-connection.ts +32 -5
- package/src/oauth/connect-orchestrator.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +76 -0
- package/src/oauth/connection-resolver.ts +49 -10
- package/src/oauth/manual-token-connection.ts +51 -3
- package/src/oauth/seed-providers.ts +3 -0
- package/src/permissions/approval-policy.test.ts +19 -5
- package/src/permissions/approval-policy.ts +14 -3
- package/src/permissions/checker.ts +21 -8
- package/src/platform/client.test.ts +24 -1
- package/src/platform/client.ts +8 -0
- package/src/platform/feature-gate.ts +15 -0
- package/src/plugins/defaults/injectors.ts +2 -8
- package/src/plugins/defaults/persistence.ts +25 -6
- package/src/plugins/types.ts +57 -13
- package/src/proactive-artifact/job.test.ts +1 -0
- package/src/prompts/__tests__/system-prompt.test.ts +4 -4
- package/src/prompts/system-prompt.ts +38 -40
- package/src/prompts/template-detection.ts +10 -4
- package/src/prompts/templates/BOOTSTRAP.md +7 -11
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
- package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
- package/src/providers/call-site-routing.ts +33 -9
- package/src/providers/connection-model-compat.ts +23 -0
- package/src/providers/connection-resolution.ts +39 -20
- package/src/providers/fireworks/client.ts +1 -0
- package/src/providers/gemini/client.ts +24 -3
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
- package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
- package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
- package/src/providers/inference/auth.ts +0 -8
- package/src/providers/inference/connections.ts +3 -66
- package/src/providers/inference/resolve-auth.ts +2 -3
- package/src/providers/model-catalog.ts +35 -1
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
- package/src/providers/openai/chat-completions-provider.ts +110 -12
- package/src/providers/openai/codex-models.ts +2 -0
- package/src/providers/openai/responses-provider.ts +53 -53
- package/src/providers/openrouter/client.ts +13 -8
- package/src/providers/provider-send-message.ts +18 -9
- package/src/providers/registry.ts +48 -8
- package/src/providers/retry.ts +16 -4
- package/src/providers/search-provider-catalog.ts +17 -9
- package/src/providers/types.ts +9 -0
- package/src/runtime/__tests__/agent-wake.test.ts +1 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
- package/src/runtime/access-request-helper.ts +1 -0
- package/src/runtime/auth/route-policy.ts +10 -0
- package/src/runtime/channel-readiness-service.ts +68 -0
- package/src/runtime/channel-reply-delivery.ts +23 -0
- package/src/runtime/channel-retry-sweep.ts +47 -14
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/migrations/vbundle-builder.ts +3 -2
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +51 -3
- package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
- package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
- package/src/runtime/routes/acp-routes-list.test.ts +3 -0
- package/src/runtime/routes/app-management-routes.ts +111 -4
- package/src/runtime/routes/background-wake-routes.ts +188 -20
- package/src/runtime/routes/btw-routes.ts +4 -4
- package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
- package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
- package/src/runtime/routes/conversation-list-routes.ts +147 -0
- package/src/runtime/routes/conversation-management-routes.ts +39 -14
- package/src/runtime/routes/conversation-query-routes.ts +60 -10
- package/src/runtime/routes/conversation-routes.ts +186 -140
- package/src/runtime/routes/conversations-import-routes.ts +19 -6
- package/src/runtime/routes/documents-routes.ts +10 -1
- package/src/runtime/routes/group-routes.ts +11 -0
- package/src/runtime/routes/home-feed-routes.ts +129 -0
- package/src/runtime/routes/identity-intro-cache.ts +61 -16
- package/src/runtime/routes/identity-routes.ts +30 -9
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +5 -26
- package/src/runtime/routes/integrations/vercel.ts +15 -0
- package/src/runtime/routes/llm-context-normalization.ts +7 -2
- package/src/runtime/routes/memory-v3-routes.ts +160 -2
- package/src/runtime/routes/migration-routes.ts +20 -13
- package/src/runtime/routes/notification-routes.ts +63 -1
- package/src/runtime/routes/oauth-commands-routes.ts +6 -1
- package/src/runtime/routes/surface-action-routes.ts +1 -38
- package/src/runtime/routes/surface-content-routes.ts +12 -5
- package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
- package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
- package/src/runtime/slack-dm-text-delivery.ts +177 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -1
- package/src/runtime/tool-grant-request-helper.ts +1 -0
- package/src/schedule/schedule-store.ts +8 -1
- package/src/schedule/scheduler.ts +111 -15
- package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
- package/src/security/encrypted-store.ts +7 -16
- package/src/security/store-path-override.ts +61 -0
- package/src/signals/user-message.ts +5 -8
- package/src/skills/validate-input.ts +177 -0
- package/src/subagent/manager.ts +13 -13
- package/src/subagent/types.ts +6 -0
- package/src/tasks/tool-sanitizer.ts +2 -2
- package/src/tools/apps/definitions.ts +35 -21
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
- package/src/tools/computer-use/definitions.ts +268 -266
- package/src/tools/document/document-tool.ts +131 -8
- package/src/tools/execution-target.ts +2 -5
- package/src/tools/executor.ts +18 -55
- package/src/tools/host-filesystem/edit.test.ts +1 -0
- package/src/tools/host-filesystem/read.test.ts +1 -0
- package/src/tools/host-filesystem/transfer.test.ts +31 -6
- package/src/tools/host-filesystem/write.test.ts +1 -0
- package/src/tools/mcp/mcp-tool-factory.ts +0 -2
- package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
- package/src/tools/network/__tests__/web-search.test.ts +211 -3
- package/src/tools/network/managed-search-proxy.ts +183 -0
- package/src/tools/network/web-search.ts +199 -44
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +146 -103
- package/src/tools/schedule/create.ts +1 -1
- package/src/tools/skills/skill-tool-factory.ts +17 -36
- package/src/tools/subagent/spawn.ts +3 -0
- package/src/tools/tool-approval-handler.ts +10 -4
- package/src/tools/tool-name-aliases.ts +72 -14
- package/src/tools/types.ts +17 -15
- package/src/tools/ui-surface/definitions.ts +98 -86
- package/src/types/onboarding-context.ts +6 -0
- package/src/usage/attribution.ts +32 -1
- package/src/util/browser.ts +7 -2
- package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
- package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
- package/src/workspace/migrations/registry.ts +4 -0
|
@@ -11,7 +11,11 @@ import type { ChannelId, InterfaceId } from "../../../channels/types.js";
|
|
|
11
11
|
import { findGuardianForChannel } from "../../../contacts/contact-store.js";
|
|
12
12
|
import type { ServerMessage } from "../../../daemon/message-protocol.js";
|
|
13
13
|
import type { TrustContext } from "../../../daemon/trust-context.js";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
addSlackDmLiveDeliveredTextResponseIndex,
|
|
16
|
+
getSlackDmLiveDeliveredTextResponseIndexes,
|
|
17
|
+
updateDeliveredSegmentCount,
|
|
18
|
+
} from "../../../memory/delivery-channels.js";
|
|
15
19
|
import {
|
|
16
20
|
linkMessage,
|
|
17
21
|
storeReplyMessageId,
|
|
@@ -44,6 +48,10 @@ import type {
|
|
|
44
48
|
MessageProcessor,
|
|
45
49
|
SlackInboundMessageMetadata,
|
|
46
50
|
} from "../../http-types.js";
|
|
51
|
+
import {
|
|
52
|
+
createSlackDmTextDeliveryController,
|
|
53
|
+
isSlackDeliveryCallbackUrl,
|
|
54
|
+
} from "../../slack-dm-text-delivery.js";
|
|
47
55
|
import { resolveRoutingState } from "../../trust-context-resolver.js";
|
|
48
56
|
import { deliverReplyViaCallback } from "../channel-delivery-routes.js";
|
|
49
57
|
import { deliverGeneratedApprovalPrompt } from "../guardian-approval-prompt.js";
|
|
@@ -228,6 +236,21 @@ export function processChannelMessageInBackground(
|
|
|
228
236
|
}
|
|
229
237
|
: undefined;
|
|
230
238
|
let replyMessageId: string | undefined;
|
|
239
|
+
const slackDmTextDelivery = createSlackDmTextDeliveryController({
|
|
240
|
+
sourceChannel,
|
|
241
|
+
chatType,
|
|
242
|
+
replyCallbackUrl,
|
|
243
|
+
chatId: externalChatId,
|
|
244
|
+
assistantId,
|
|
245
|
+
deliveredTextResponseIndexes:
|
|
246
|
+
getSlackDmLiveDeliveredTextResponseIndexes(eventId),
|
|
247
|
+
onTextResponseDelivered: (responseIndex, reason) => {
|
|
248
|
+
addSlackDmLiveDeliveredTextResponseIndex(eventId, responseIndex);
|
|
249
|
+
if (reason === "before_tool") {
|
|
250
|
+
slackThinkingStatus?.refreshAfterReply();
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
});
|
|
231
254
|
const observeAgentEvent = (msg: ServerMessage): void => {
|
|
232
255
|
if (
|
|
233
256
|
msg.type === "message_complete" &&
|
|
@@ -236,6 +259,7 @@ export function processChannelMessageInBackground(
|
|
|
236
259
|
) {
|
|
237
260
|
replyMessageId = msg.messageId;
|
|
238
261
|
}
|
|
262
|
+
slackDmTextDelivery?.observeEvent(msg);
|
|
239
263
|
slackThinkingStatus?.observeEvent(msg);
|
|
240
264
|
};
|
|
241
265
|
|
|
@@ -297,12 +321,21 @@ export function processChannelMessageInBackground(
|
|
|
297
321
|
{ err, conversationId },
|
|
298
322
|
"Background channel message processing failed",
|
|
299
323
|
);
|
|
324
|
+
if (slackDmTextDelivery) {
|
|
325
|
+
await slackDmTextDelivery.waitForPendingDeliveries();
|
|
326
|
+
}
|
|
300
327
|
recordProcessingFailure(eventId, err);
|
|
301
328
|
return;
|
|
302
329
|
}
|
|
303
330
|
|
|
304
331
|
if (replyCallbackUrl) {
|
|
305
332
|
try {
|
|
333
|
+
if (slackDmTextDelivery) {
|
|
334
|
+
await slackDmTextDelivery.waitForPendingDeliveries();
|
|
335
|
+
}
|
|
336
|
+
const liveDeliveryResumeOptions =
|
|
337
|
+
slackDmTextDelivery?.getFinalDeliveryResumeOptions(replyMessageId);
|
|
338
|
+
|
|
306
339
|
await deliverReplyViaCallback(
|
|
307
340
|
conversationId,
|
|
308
341
|
externalChatId,
|
|
@@ -311,6 +344,7 @@ export function processChannelMessageInBackground(
|
|
|
311
344
|
{
|
|
312
345
|
messageId: replyMessageId,
|
|
313
346
|
sinceMessageId: userMessageId,
|
|
347
|
+
...liveDeliveryResumeOptions,
|
|
314
348
|
onSegmentDelivered: (count) =>
|
|
315
349
|
updateDeliveredSegmentCount(eventId, count),
|
|
316
350
|
},
|
|
@@ -395,11 +429,13 @@ function startTelegramTypingHeartbeat(
|
|
|
395
429
|
|
|
396
430
|
type SlackThinkingStatusController = {
|
|
397
431
|
observeEvent: (msg: ServerMessage) => void;
|
|
432
|
+
refreshAfterReply: () => void;
|
|
398
433
|
stop: () => void;
|
|
399
434
|
};
|
|
400
435
|
|
|
401
436
|
type SlackThinkingStatusHandle = {
|
|
402
437
|
updateLoadingMessages: (loadingMessages?: string[]) => void;
|
|
438
|
+
refresh: (loadingMessages?: string[]) => void;
|
|
403
439
|
clear: () => void;
|
|
404
440
|
};
|
|
405
441
|
|
|
@@ -440,12 +476,9 @@ function shouldEmitSlackThinkingStatus(
|
|
|
440
476
|
sourceChannel: ChannelId,
|
|
441
477
|
replyCallbackUrl?: string,
|
|
442
478
|
): boolean {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
} catch {
|
|
447
|
-
return replyCallbackUrl.endsWith("/deliver/slack");
|
|
448
|
-
}
|
|
479
|
+
return (
|
|
480
|
+
sourceChannel === "slack" && isSlackDeliveryCallbackUrl(replyCallbackUrl)
|
|
481
|
+
);
|
|
449
482
|
}
|
|
450
483
|
|
|
451
484
|
export function shouldStartSlackThinkingStatusImmediately(params: {
|
|
@@ -547,6 +580,13 @@ function createSlackThinkingStatusController(params: {
|
|
|
547
580
|
start();
|
|
548
581
|
}
|
|
549
582
|
},
|
|
583
|
+
refreshAfterReply() {
|
|
584
|
+
if (stopped || !slackThinkingStatus) return;
|
|
585
|
+
// Slack clears assistant thread status when the app sends a reply, so
|
|
586
|
+
// live pre-tool replies need to reassert it while work continues.
|
|
587
|
+
slackThinkingStatus.refresh(currentLoadingMessages);
|
|
588
|
+
lastSentLoadingMessageKey = getLoadingMessagesKey(currentLoadingMessages);
|
|
589
|
+
},
|
|
550
590
|
stop() {
|
|
551
591
|
stopped = true;
|
|
552
592
|
slackThinkingStatus?.clear();
|
|
@@ -627,7 +667,9 @@ function getTaskProgressLoadingMessage(
|
|
|
627
667
|
|
|
628
668
|
const activeStep = progress.steps[activeStepIndex]!;
|
|
629
669
|
return [
|
|
630
|
-
`In progress (${activeStepIndex + 1}/${progress.steps.length}): ${
|
|
670
|
+
`In progress (${activeStepIndex + 1}/${progress.steps.length}): ${
|
|
671
|
+
activeStep.label
|
|
672
|
+
}`,
|
|
631
673
|
];
|
|
632
674
|
}
|
|
633
675
|
|
|
@@ -656,6 +698,7 @@ function setSlackThinkingStatus(
|
|
|
656
698
|
if (!messageTs) {
|
|
657
699
|
return {
|
|
658
700
|
updateLoadingMessages: () => {},
|
|
701
|
+
refresh: () => {},
|
|
659
702
|
clear: () => {},
|
|
660
703
|
};
|
|
661
704
|
}
|
|
@@ -697,6 +740,7 @@ function setSlackThinkingStatus(
|
|
|
697
740
|
|
|
698
741
|
return {
|
|
699
742
|
updateLoadingMessages: () => {},
|
|
743
|
+
refresh: () => {},
|
|
700
744
|
clear: clearReaction,
|
|
701
745
|
};
|
|
702
746
|
}
|
|
@@ -739,6 +783,10 @@ function setSlackThinkingStatus(
|
|
|
739
783
|
);
|
|
740
784
|
};
|
|
741
785
|
|
|
786
|
+
const refresh = (nextLoadingMessages?: string[]): void => {
|
|
787
|
+
updateLoadingMessages(nextLoadingMessages);
|
|
788
|
+
};
|
|
789
|
+
|
|
742
790
|
const clearStatus = (): void => {
|
|
743
791
|
if (cleared) return;
|
|
744
792
|
cleared = true;
|
|
@@ -766,6 +814,7 @@ function setSlackThinkingStatus(
|
|
|
766
814
|
|
|
767
815
|
return {
|
|
768
816
|
updateLoadingMessages,
|
|
817
|
+
refresh,
|
|
769
818
|
clear: clearStatus,
|
|
770
819
|
};
|
|
771
820
|
}
|
|
@@ -40,6 +40,7 @@ import { ROUTES as CONTENT_SOURCE_ROUTES } from "./content-source-routes.js";
|
|
|
40
40
|
import { ROUTES as CONVERSATION_ANALYSIS_ROUTES } from "./conversation-analysis-routes.js";
|
|
41
41
|
import { ROUTES as CONVERSATION_ATTENTION_ROUTES } from "./conversation-attention-routes.js";
|
|
42
42
|
import { ROUTES as CONVERSATION_CLI_ROUTES } from "./conversation-cli-routes.js";
|
|
43
|
+
import { ROUTES as CONVERSATION_COMPACTION_ROUTES } from "./conversation-compaction-routes.js";
|
|
43
44
|
import { ROUTES as CONVERSATION_LIST_ROUTES } from "./conversation-list-routes.js";
|
|
44
45
|
import { ROUTES as CONVERSATION_MANAGEMENT_ROUTES } from "./conversation-management-routes.js";
|
|
45
46
|
import { ROUTES as CONVERSATION_QUERY_ROUTES } from "./conversation-query-routes.js";
|
|
@@ -179,6 +180,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
179
180
|
...CREDENTIAL_PROMPT_ROUTES,
|
|
180
181
|
...CREDENTIAL_ROUTES,
|
|
181
182
|
...DEFER_ROUTES,
|
|
183
|
+
...CONVERSATION_COMPACTION_ROUTES,
|
|
182
184
|
...CONVERSATION_QUERY_ROUTES,
|
|
183
185
|
...CONVERSATION_STARTER_ROUTES,
|
|
184
186
|
...DEBUG_BASH_ROUTES,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* GET /v1/inference/provider-connections — list all connections (optional ?provider= filter)
|
|
5
5
|
* GET /v1/inference/provider-connections/:name — single connection by name
|
|
6
6
|
* POST /v1/inference/provider-connections — create a new connection
|
|
7
|
-
* PATCH /v1/inference/provider-connections/:name — update auth/label
|
|
7
|
+
* PATCH /v1/inference/provider-connections/:name — update auth/label (cannot rename or change provider; auth is locked to platform for managed connections)
|
|
8
8
|
* DELETE /v1/inference/provider-connections/:name — delete (rejects if profiles or call sites reference it; rejects outright for managed connections)
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
type ConnectionModel,
|
|
19
19
|
ConnectionModelSchema,
|
|
20
20
|
ConnectionProviderSchema,
|
|
21
|
-
ConnectionStatusSchema,
|
|
22
21
|
ProviderConnectionSchema,
|
|
23
22
|
VALID_CONNECTION_PROVIDERS,
|
|
24
23
|
} from "../../providers/inference/auth.js";
|
|
@@ -223,14 +222,6 @@ async function handleCreateConnection({ body = {} }: RouteHandlerArgs) {
|
|
|
223
222
|
throw new BadRequestError(`Invalid auth: ${authResult.error.message}`);
|
|
224
223
|
}
|
|
225
224
|
|
|
226
|
-
const statusResult =
|
|
227
|
-
body.status !== undefined
|
|
228
|
-
? ConnectionStatusSchema.safeParse(body.status)
|
|
229
|
-
: null;
|
|
230
|
-
if (statusResult && !statusResult.success) {
|
|
231
|
-
throw new BadRequestError(`Invalid status: must be "active" or "disabled"`);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
225
|
const labelRaw = body.label;
|
|
235
226
|
if (
|
|
236
227
|
labelRaw !== undefined &&
|
|
@@ -248,7 +239,6 @@ async function handleCreateConnection({ body = {} }: RouteHandlerArgs) {
|
|
|
248
239
|
name,
|
|
249
240
|
provider: providerResult.data,
|
|
250
241
|
auth: authResult.data,
|
|
251
|
-
...(statusResult ? { status: statusResult.data } : {}),
|
|
252
242
|
...(labelRaw !== undefined ? { label: labelRaw as string | null } : {}),
|
|
253
243
|
...customFields,
|
|
254
244
|
});
|
|
@@ -302,14 +292,6 @@ async function handleUpdateConnection({
|
|
|
302
292
|
throw new BadRequestError(`Invalid auth: ${authResult.error.message}`);
|
|
303
293
|
}
|
|
304
294
|
|
|
305
|
-
const statusResult =
|
|
306
|
-
body.status !== undefined
|
|
307
|
-
? ConnectionStatusSchema.safeParse(body.status)
|
|
308
|
-
: null;
|
|
309
|
-
if (statusResult && !statusResult.success) {
|
|
310
|
-
throw new BadRequestError(`Invalid status: must be "active" or "disabled"`);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
295
|
const labelRaw = body.label;
|
|
314
296
|
if (
|
|
315
297
|
labelRaw !== undefined &&
|
|
@@ -323,8 +305,8 @@ async function handleUpdateConnection({
|
|
|
323
305
|
|
|
324
306
|
// Managed connections: lock auth to `{type:"platform"}`. The boot upsert in
|
|
325
307
|
// `seedCanonicalConnections` would revert any other value on next restart;
|
|
326
|
-
// reject the write here so the surprise loop never happens. Label
|
|
327
|
-
//
|
|
308
|
+
// reject the write here so the surprise loop never happens. Label remains
|
|
309
|
+
// user-editable (the boot upsert leaves it alone).
|
|
328
310
|
if (
|
|
329
311
|
MANAGED_CONNECTION_NAMES.has(name) &&
|
|
330
312
|
authResult.data.type !== "platform"
|
|
@@ -338,7 +320,6 @@ async function handleUpdateConnection({
|
|
|
338
320
|
|
|
339
321
|
const result = updateConnection(getDb(), name, {
|
|
340
322
|
auth: authResult.data,
|
|
341
|
-
...(statusResult ? { status: statusResult.data } : {}),
|
|
342
323
|
...(labelRaw !== undefined ? { label: labelRaw as string | null } : {}),
|
|
343
324
|
...customFields,
|
|
344
325
|
});
|
|
@@ -387,7 +368,7 @@ function handleDeleteConnection({ pathParams = {} }: RouteHandlerArgs) {
|
|
|
387
368
|
// re-overlaid by `seed-inference-profiles.ts` on boot).
|
|
388
369
|
if (MANAGED_CONNECTION_NAMES.has(name)) {
|
|
389
370
|
throw new BadRequestError(
|
|
390
|
-
`Cannot delete managed connection "${name}". This is a Vellum-managed connection
|
|
371
|
+
`Cannot delete managed connection "${name}". This is a Vellum-managed connection that is re-seeded on every startup.`,
|
|
391
372
|
);
|
|
392
373
|
}
|
|
393
374
|
|
|
@@ -485,7 +466,6 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
485
466
|
provider: ConnectionProviderSchema,
|
|
486
467
|
auth: AuthSchema,
|
|
487
468
|
label: z.string().min(1).optional(),
|
|
488
|
-
status: ConnectionStatusSchema.optional(),
|
|
489
469
|
base_url: z.string().url().nullable().optional(),
|
|
490
470
|
models: z.array(ConnectionModelSchema).nullable().optional(),
|
|
491
471
|
}),
|
|
@@ -504,12 +484,11 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
504
484
|
policyKey: "inference/provider-connections/detail",
|
|
505
485
|
summary: "Update a provider connection",
|
|
506
486
|
description:
|
|
507
|
-
"Update an existing connection. Cannot rename or change the provider. For managed connections (anthropic-managed, openai-managed, gemini-managed) the auth is locked to platform; label
|
|
487
|
+
"Update an existing connection. Cannot rename or change the provider. For managed connections (anthropic-managed, openai-managed, gemini-managed) the auth is locked to platform; label remains editable.",
|
|
508
488
|
tags: ["inference"],
|
|
509
489
|
pathParams: [{ name: "name", description: "Connection name" }],
|
|
510
490
|
requestBody: z.object({
|
|
511
491
|
auth: AuthSchema,
|
|
512
|
-
status: ConnectionStatusSchema.optional(),
|
|
513
492
|
label: z.string().min(1).nullable().optional(),
|
|
514
493
|
base_url: z.string().url().nullable().optional(),
|
|
515
494
|
models: z.array(ConnectionModelSchema).nullable().optional(),
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* ("set" or "delete") rather than using HTTP verbs directly.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
12
14
|
import {
|
|
13
15
|
deleteVercelConfig,
|
|
14
16
|
getVercelConfig,
|
|
@@ -17,6 +19,12 @@ import {
|
|
|
17
19
|
import { BadRequestError } from "../errors.js";
|
|
18
20
|
import type { RouteDefinition, RouteHandlerArgs } from "../types.js";
|
|
19
21
|
|
|
22
|
+
const vercelConfigResponseSchema = z.object({
|
|
23
|
+
hasToken: z.boolean(),
|
|
24
|
+
success: z.boolean(),
|
|
25
|
+
error: z.string().optional(),
|
|
26
|
+
});
|
|
27
|
+
|
|
20
28
|
// ---------------------------------------------------------------------------
|
|
21
29
|
// Handlers
|
|
22
30
|
// ---------------------------------------------------------------------------
|
|
@@ -66,6 +74,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
66
74
|
description: "Check if a Vercel API token is stored.",
|
|
67
75
|
tags: ["integrations"],
|
|
68
76
|
requirePolicyEnforcement: true,
|
|
77
|
+
responseBody: vercelConfigResponseSchema,
|
|
69
78
|
handler: () => handleGetVercelConfig(),
|
|
70
79
|
},
|
|
71
80
|
{
|
|
@@ -77,6 +86,11 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
77
86
|
"Set or delete the Vercel API token. Action is determined by the body action field.",
|
|
78
87
|
tags: ["integrations"],
|
|
79
88
|
requirePolicyEnforcement: true,
|
|
89
|
+
requestBody: z.object({
|
|
90
|
+
action: z.enum(["get", "set", "delete"]).optional(),
|
|
91
|
+
apiToken: z.string().optional(),
|
|
92
|
+
}),
|
|
93
|
+
responseBody: vercelConfigResponseSchema,
|
|
80
94
|
handler: handlePostVercelConfig,
|
|
81
95
|
},
|
|
82
96
|
{
|
|
@@ -87,6 +101,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
87
101
|
description: "Delete the stored Vercel API token.",
|
|
88
102
|
tags: ["integrations"],
|
|
89
103
|
requirePolicyEnforcement: true,
|
|
104
|
+
responseBody: vercelConfigResponseSchema,
|
|
90
105
|
handler: () => handleDeleteVercelConfig(),
|
|
91
106
|
},
|
|
92
107
|
];
|
|
@@ -1057,8 +1057,13 @@ function extractOpenAiResponsesRequestToolNames(tools: unknown): string[] {
|
|
|
1057
1057
|
if (asString(tool.type) === "function" && asString(tool.name)) {
|
|
1058
1058
|
return asString(tool.name);
|
|
1059
1059
|
}
|
|
1060
|
-
// Native web search
|
|
1061
|
-
|
|
1060
|
+
// Native web search tools:
|
|
1061
|
+
// - OpenAI API: { type: "web_search_preview" }
|
|
1062
|
+
// - Codex subscription endpoint: { type: "web_search" }
|
|
1063
|
+
if (
|
|
1064
|
+
asString(tool.type) === "web_search_preview" ||
|
|
1065
|
+
asString(tool.type) === "web_search"
|
|
1066
|
+
) {
|
|
1062
1067
|
return "web_search";
|
|
1063
1068
|
}
|
|
1064
1069
|
return undefined;
|
|
@@ -22,14 +22,27 @@ import { z } from "zod";
|
|
|
22
22
|
import { loadConfig } from "../../config/loader.js";
|
|
23
23
|
import type { AssistantConfig } from "../../config/types.js";
|
|
24
24
|
import { getDb } from "../../memory/db-connection.js";
|
|
25
|
+
import { readActivationLogsForShadowDiff } from "../../memory/memory-v2-activation-log-store.js";
|
|
25
26
|
import type {
|
|
26
27
|
RetrievalCost,
|
|
27
28
|
RetrievalInput,
|
|
28
29
|
} from "../../memory/v2/harness/retriever.js";
|
|
29
30
|
import type { DescentTrace } from "../../memory/v2/harness/trace.js";
|
|
30
31
|
import { loadNowText } from "../../memory/v2/now-text.js";
|
|
32
|
+
import {
|
|
33
|
+
DEFAULT_SEED_OPTIONS,
|
|
34
|
+
seedCoretrievalEdges,
|
|
35
|
+
type SeedCoretrievalResult,
|
|
36
|
+
} from "../../memory/v3/coretrieval-seed.js";
|
|
31
37
|
import type { LlmCallRecord } from "../../memory/v3/llm-capture.js";
|
|
32
38
|
import { runRetrievalLoop } from "../../memory/v3/loop.js";
|
|
39
|
+
import type {
|
|
40
|
+
ShadowDiffResult,
|
|
41
|
+
ShadowDiffTurn,
|
|
42
|
+
SlugFrequency,
|
|
43
|
+
UnpairedShadowTurn,
|
|
44
|
+
} from "../../memory/v3/shadow-diff.js";
|
|
45
|
+
import { computeShadowDiff } from "../../memory/v3/shadow-diff.js";
|
|
33
46
|
import { getTreeIndex } from "../../memory/v3/tree-index.js";
|
|
34
47
|
import type { TreeValidationReport } from "../../memory/v3/validate.js";
|
|
35
48
|
import { validateTree } from "../../memory/v3/validate.js";
|
|
@@ -49,6 +62,13 @@ export type {
|
|
|
49
62
|
TreeLevel,
|
|
50
63
|
} from "../../memory/v2/harness/trace.js";
|
|
51
64
|
export type { LlmCallRecord };
|
|
65
|
+
export type {
|
|
66
|
+
ShadowDiffResult,
|
|
67
|
+
ShadowDiffTurn,
|
|
68
|
+
SlugFrequency,
|
|
69
|
+
UnpairedShadowTurn,
|
|
70
|
+
};
|
|
71
|
+
export type { SeedCoretrievalResult };
|
|
52
72
|
|
|
53
73
|
// ── Validate ────────────────────────────────────────────────────────────
|
|
54
74
|
|
|
@@ -119,7 +139,7 @@ async function handleTree({
|
|
|
119
139
|
/** The five v3 retrieval lanes, in fanout order. */
|
|
120
140
|
const V3_LANE_NAMES = ["hot", "sparse", "dense", "tree", "edges"] as const;
|
|
121
141
|
|
|
122
|
-
const MemoryV3SimulateParams = z
|
|
142
|
+
export const MemoryV3SimulateParams = z
|
|
123
143
|
.object({
|
|
124
144
|
/** The ad-hoc user query to route a single synthetic turn against. */
|
|
125
145
|
query: z.string().min(1, "memory.v3.simulate query must be non-empty"),
|
|
@@ -138,7 +158,10 @@ const MemoryV3SimulateParams = z
|
|
|
138
158
|
* Restrict the run to this allowlist of lanes (others forced off). Omit to
|
|
139
159
|
* inherit the live `memory.v3.lanes` toggles.
|
|
140
160
|
*/
|
|
141
|
-
lanes: z
|
|
161
|
+
lanes: z
|
|
162
|
+
.array(z.enum(V3_LANE_NAMES))
|
|
163
|
+
.min(1, "memory.v3.simulate lanes must list at least one lane")
|
|
164
|
+
.optional(),
|
|
142
165
|
})
|
|
143
166
|
.strict();
|
|
144
167
|
|
|
@@ -276,6 +299,118 @@ async function handleSimulate({
|
|
|
276
299
|
};
|
|
277
300
|
}
|
|
278
301
|
|
|
302
|
+
// ── Shadow-diff ─────────────────────────────────────────────────────────
|
|
303
|
+
|
|
304
|
+
/** Default pairing tolerance: a shadow row + its router sibling land ~1-2s apart. */
|
|
305
|
+
const DEFAULT_SHADOW_DIFF_TOLERANCE_SEC = 10;
|
|
306
|
+
/** Default cap on per-turn detail rows returned (aggregates are unbounded). */
|
|
307
|
+
const DEFAULT_SHADOW_DIFF_LIMIT = 50;
|
|
308
|
+
/** Milliseconds per day, for the `sinceDays` read-window cutoff. */
|
|
309
|
+
const MS_PER_DAY = 86_400_000;
|
|
310
|
+
|
|
311
|
+
const MemoryV3ShadowDiffParams = z
|
|
312
|
+
.object({
|
|
313
|
+
/** Only consider shadow rows newer than this many days. Omit for all rows. */
|
|
314
|
+
sinceDays: z
|
|
315
|
+
.number()
|
|
316
|
+
.positive("memory.v3.shadow-diff sinceDays must be positive")
|
|
317
|
+
.optional(),
|
|
318
|
+
/** Max |Δt| (seconds) to pair a shadow row with a router row. */
|
|
319
|
+
toleranceSec: z
|
|
320
|
+
.number()
|
|
321
|
+
.positive("memory.v3.shadow-diff toleranceSec must be positive")
|
|
322
|
+
.optional(),
|
|
323
|
+
/** Cap on per-turn detail rows in the response (newest first). */
|
|
324
|
+
limit: z
|
|
325
|
+
.number()
|
|
326
|
+
.int("memory.v3.shadow-diff limit must be an integer")
|
|
327
|
+
.positive("memory.v3.shadow-diff limit must be positive")
|
|
328
|
+
.optional(),
|
|
329
|
+
})
|
|
330
|
+
.strict();
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Compare the v3 shadow selections against the live v2 router selections,
|
|
334
|
+
* turn-for-turn, from the activation log. Read-only: reads `v3_shadow` rows and
|
|
335
|
+
* the `router` rows they pair with (bounded to those conversations + time
|
|
336
|
+
* span), then diffs each pair. Requires v3 shadow mode to have been running
|
|
337
|
+
* (`memory.v3.enabled` + `.shadow`) so the `v3_shadow` rows exist; the route
|
|
338
|
+
* itself runs no LLM and writes nothing.
|
|
339
|
+
*/
|
|
340
|
+
async function handleShadowDiff({
|
|
341
|
+
body = {},
|
|
342
|
+
}: RouteHandlerArgs): Promise<ShadowDiffResult> {
|
|
343
|
+
const { sinceDays, toleranceSec, limit } =
|
|
344
|
+
MemoryV3ShadowDiffParams.parse(body);
|
|
345
|
+
|
|
346
|
+
const sinceMs =
|
|
347
|
+
sinceDays !== undefined ? Date.now() - sinceDays * MS_PER_DAY : null;
|
|
348
|
+
const toleranceMs =
|
|
349
|
+
(toleranceSec ?? DEFAULT_SHADOW_DIFF_TOLERANCE_SEC) * 1000;
|
|
350
|
+
|
|
351
|
+
const { shadow, router } = readActivationLogsForShadowDiff({
|
|
352
|
+
sinceMs,
|
|
353
|
+
paddingMs: toleranceMs,
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
return computeShadowDiff(shadow, router, {
|
|
357
|
+
toleranceMs,
|
|
358
|
+
detailLimit: limit ?? DEFAULT_SHADOW_DIFF_LIMIT,
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// ── Seed co-retrieval edges ───────────────────────────────────────────────
|
|
363
|
+
|
|
364
|
+
const MemoryV3SeedEdgesParams = z
|
|
365
|
+
.object({
|
|
366
|
+
/** A pair must co-occur on at least this many router turns to earn an edge. */
|
|
367
|
+
minCount: z
|
|
368
|
+
.number()
|
|
369
|
+
.int("memory.v3.seed-edges minCount must be an integer")
|
|
370
|
+
.positive("memory.v3.seed-edges minCount must be positive")
|
|
371
|
+
.optional(),
|
|
372
|
+
/** Neighbors kept per source node, ranked by NPMI descending. */
|
|
373
|
+
topK: z
|
|
374
|
+
.number()
|
|
375
|
+
.int("memory.v3.seed-edges topK must be an integer")
|
|
376
|
+
.positive("memory.v3.seed-edges topK must be positive")
|
|
377
|
+
.optional(),
|
|
378
|
+
/** Exclude neighbors selected on more than this fraction of all turns. */
|
|
379
|
+
maxNeighborFreqRatio: z
|
|
380
|
+
.number()
|
|
381
|
+
.positive("memory.v3.seed-edges maxNeighborFreqRatio must be positive")
|
|
382
|
+
.max(1, "memory.v3.seed-edges maxNeighborFreqRatio must be <= 1")
|
|
383
|
+
.optional(),
|
|
384
|
+
/** Flat weight each seeded edge is written at. */
|
|
385
|
+
seedWeight: z
|
|
386
|
+
.number()
|
|
387
|
+
.positive("memory.v3.seed-edges seedWeight must be positive")
|
|
388
|
+
.optional(),
|
|
389
|
+
})
|
|
390
|
+
.strict();
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Build the co-retrieval graph from the v2 router's selection history and
|
|
394
|
+
* persist it into `memory_v3_auto_edges`. This is the one write surface among
|
|
395
|
+
* the v3 routes — it warm-starts the learned edge graph that the edge-expansion
|
|
396
|
+
* lane merges (when `memory.v3.edges.learnedAdjacencyThreshold > 0`). Idempotent:
|
|
397
|
+
* re-running upserts each seeded edge to the flat seed weight without unbounded
|
|
398
|
+
* growth. Runs no LLM.
|
|
399
|
+
*/
|
|
400
|
+
async function handleSeedEdges({
|
|
401
|
+
body = {},
|
|
402
|
+
}: RouteHandlerArgs): Promise<SeedCoretrievalResult> {
|
|
403
|
+
const { minCount, topK, maxNeighborFreqRatio, seedWeight } =
|
|
404
|
+
MemoryV3SeedEdgesParams.parse(body);
|
|
405
|
+
return seedCoretrievalEdges(getDb(), {
|
|
406
|
+
minCount: minCount ?? DEFAULT_SEED_OPTIONS.minCount,
|
|
407
|
+
topK: topK ?? DEFAULT_SEED_OPTIONS.topK,
|
|
408
|
+
maxNeighborFreqRatio:
|
|
409
|
+
maxNeighborFreqRatio ?? DEFAULT_SEED_OPTIONS.maxNeighborFreqRatio,
|
|
410
|
+
seedWeight: seedWeight ?? DEFAULT_SEED_OPTIONS.seedWeight,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
|
|
279
414
|
// ── Route definitions ───────────────────────────────────────────────────
|
|
280
415
|
|
|
281
416
|
export const ROUTES: RouteDefinition[] = [
|
|
@@ -313,4 +448,27 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
313
448
|
tags: ["memory"],
|
|
314
449
|
requestBody: MemoryV3SimulateParams,
|
|
315
450
|
},
|
|
451
|
+
{
|
|
452
|
+
operationId: "memory_v3_shadow_diff",
|
|
453
|
+
method: "POST",
|
|
454
|
+
endpoint: "memory/v3/shadow-diff",
|
|
455
|
+
handler: handleShadowDiff,
|
|
456
|
+
summary:
|
|
457
|
+
"Diff v3 shadow selections against live v2 router selections (read-only)",
|
|
458
|
+
description:
|
|
459
|
+
"Compares the v3 shadow-mode selections against the live v2 router selections turn-for-turn, from the memory activation log. Pairs each v3_shadow row with the nearest v2 router row in the same conversation (by timestamp, within a tolerance — the turn columns use different counters), then reports per-turn and aggregate overlap, what v3 surfaced that v2 did not, and what v2 had that v3 dropped, broken down by v3 provenance lane. The v2 comparand is the router's fresh per-turn pick (status='injected'), not its accumulated in-context set. Requires that v3 shadow mode has been running so v3_shadow rows exist; the route runs no LLM and writes nothing.",
|
|
460
|
+
tags: ["memory"],
|
|
461
|
+
requestBody: MemoryV3ShadowDiffParams,
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
operationId: "memory_v3_seed_edges",
|
|
465
|
+
method: "POST",
|
|
466
|
+
endpoint: "memory/v3/seed-edges",
|
|
467
|
+
handler: handleSeedEdges,
|
|
468
|
+
summary: "Seed the learned co-retrieval edge graph from v2 router history",
|
|
469
|
+
description:
|
|
470
|
+
"Builds an NPMI-scored co-retrieval graph from the v2 router's per-turn selections (memory_v2_activation_logs, status='injected') and persists it into memory_v3_auto_edges, warm-starting the learned edge graph that the v3 edge-expansion lane merges with curated edges when memory.v3.edges.learnedAdjacencyThreshold > 0. NPMI plus a min co-occurrence floor and an always-on frequency ceiling keep the neighborhoods associative rather than base-rate noise. Idempotent (upserts to a flat seed weight). Runs no LLM; the only write among the v3 routes.",
|
|
471
|
+
tags: ["memory"],
|
|
472
|
+
requestBody: MemoryV3SeedEdgesParams,
|
|
473
|
+
},
|
|
316
474
|
];
|
|
@@ -38,10 +38,7 @@ import {
|
|
|
38
38
|
upsertCredentialMetadata,
|
|
39
39
|
} from "../../tools/credentials/metadata-store.js";
|
|
40
40
|
import { getLogger } from "../../util/logger.js";
|
|
41
|
-
import {
|
|
42
|
-
getWorkspaceDir,
|
|
43
|
-
getWorkspaceHooksDir,
|
|
44
|
-
} from "../../util/platform.js";
|
|
41
|
+
import { getWorkspaceDir, getWorkspaceHooksDir } from "../../util/platform.js";
|
|
45
42
|
import { APP_VERSION } from "../../version.js";
|
|
46
43
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
47
44
|
import {
|
|
@@ -358,11 +355,19 @@ export async function handleMigrationExport(
|
|
|
358
355
|
checkpoint: async () => {
|
|
359
356
|
// Dispatch through `runAsyncSqlite` so the WAL checkpoint runs
|
|
360
357
|
// in a sqlite3 subprocess on hosts where it's available. A WAL
|
|
361
|
-
//
|
|
362
|
-
//
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
358
|
+
// flush on a multi-GB WAL file can otherwise stall the daemon's
|
|
359
|
+
// event loop for the full duration of the flush.
|
|
360
|
+
//
|
|
361
|
+
// FULL (not TRUNCATE): TRUNCATE has a side effect where, if the
|
|
362
|
+
// WAL is empty after the checkpoint, SQLite unlinks the WAL file
|
|
363
|
+
// from the directory. When the daemon's in-process connection
|
|
364
|
+
// still holds the original WAL fd, the unlink orphans that fd
|
|
365
|
+
// into a "ghost WAL" only the daemon can reach, and subsequent
|
|
366
|
+
// connections create a fresh WAL on disk — split-brain. FULL
|
|
367
|
+
// gives us the same flush-completion guarantee without the
|
|
368
|
+
// unlink side effect. See assistant/AGENTS.md "SQLite WAL
|
|
369
|
+
// checkpointing".
|
|
370
|
+
const result = await runAsyncSqlite("PRAGMA wal_checkpoint(FULL)");
|
|
366
371
|
if (!result.ok) {
|
|
367
372
|
// Best-effort: if the DB can't be checkpointed (e.g. not a valid
|
|
368
373
|
// SQLite file, missing WAL, etc.) we still proceed with the export
|
|
@@ -583,11 +588,13 @@ export async function handleMigrationExportToGcs({ body }: RouteHandlerArgs) {
|
|
|
583
588
|
checkpoint: async () => {
|
|
584
589
|
// Dispatch through `runAsyncSqlite` so the WAL checkpoint runs
|
|
585
590
|
// in a sqlite3 subprocess on hosts where it's available. A
|
|
586
|
-
// WAL
|
|
591
|
+
// WAL flush on a multi-GB WAL file can otherwise stall the
|
|
587
592
|
// daemon's event loop for the full duration of the flush.
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
593
|
+
//
|
|
594
|
+
// FULL (not TRUNCATE): see the disk-export checkpoint above
|
|
595
|
+
// for rationale. assistant/AGENTS.md "SQLite WAL
|
|
596
|
+
// checkpointing".
|
|
597
|
+
const result = await runAsyncSqlite("PRAGMA wal_checkpoint(FULL)");
|
|
591
598
|
if (!result.ok) {
|
|
592
599
|
log.warn(
|
|
593
600
|
{ error: result.error, backend: result.backend },
|