@vellumai/assistant 0.8.3 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +2 -2
- package/docker-entrypoint.sh +0 -1
- package/docs/browser-use-architecture-phase2.md +1 -1
- package/knip.json +2 -1
- package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
- package/openapi.yaml +1492 -100
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +88 -3
- package/src/__tests__/anthropic-provider.test.ts +302 -33
- package/src/__tests__/approval-cascade.test.ts +1 -1
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
- package/src/__tests__/audit-log-rotation.test.ts +70 -16
- package/src/__tests__/background-workers-disk-pressure.test.ts +4 -3
- package/src/__tests__/btw-routes.test.ts +2 -3
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/channel-delivery-store.test.ts +193 -0
- package/src/__tests__/channel-guardian.test.ts +3 -3
- package/src/__tests__/channel-reply-delivery.test.ts +284 -5
- package/src/__tests__/channel-retry-sweep.test.ts +274 -1
- package/src/__tests__/checker.test.ts +6 -15
- package/src/__tests__/compaction-events.test.ts +2 -1
- package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
- package/src/__tests__/computer-use-tools.test.ts +2 -4
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/context-token-estimator.test.ts +91 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +55 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +228 -8
- package/src/__tests__/conversation-agent-loop.test.ts +188 -129
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-clean-command.test.ts +137 -0
- package/src/__tests__/conversation-clear-safety.test.ts +25 -25
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-fork-crud.test.ts +324 -0
- package/src/__tests__/conversation-lifecycle.test.ts +53 -12
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-load-history-stripped.test.ts +279 -0
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-process-callsite.test.ts +1 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -1
- package/src/__tests__/conversation-queue.test.ts +1 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
- package/src/__tests__/conversation-seed-composer.test.ts +66 -4
- package/src/__tests__/conversation-skill-tools.test.ts +2 -5
- package/src/__tests__/conversation-slash-commands.test.ts +36 -8
- package/src/__tests__/conversation-slash-queue.test.ts +1 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
- package/src/__tests__/conversation-speed-override.test.ts +1 -1
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
- package/src/__tests__/conversation-sync-tags.test.ts +99 -32
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
- package/src/__tests__/credential-execution-tools.test.ts +6 -6
- package/src/__tests__/credential-security-invariants.test.ts +7 -0
- package/src/__tests__/credential-vault-unit.test.ts +2 -2
- package/src/__tests__/cu-unified-flow.test.ts +10 -1
- package/src/__tests__/dm-backfill.test.ts +64 -0
- package/src/__tests__/dm-persistence.test.ts +33 -0
- package/src/__tests__/document-find-replace.test.ts +501 -0
- package/src/__tests__/dynamic-page-surface.test.ts +2 -2
- package/src/__tests__/email-html-renderer.test.ts +12 -0
- package/src/__tests__/first-greeting.test.ts +23 -2
- package/src/__tests__/gateway-flag-listener.test.ts +237 -0
- package/src/__tests__/gemini-provider.test.ts +78 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +7 -5
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/headless-browser-navigate.test.ts +172 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +4 -0
- package/src/__tests__/host-bash-proxy.test.ts +6 -0
- package/src/__tests__/host-browser-proxy.test.ts +10 -0
- package/src/__tests__/host-cu-proxy.test.ts +8 -1
- package/src/__tests__/host-file-proxy.test.ts +8 -1
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/host-transfer-proxy.test.ts +8 -1
- package/src/__tests__/identity-routes.test.ts +57 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
- package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
- package/src/__tests__/injector-chain.test.ts +2 -0
- package/src/__tests__/injector-document-comments.test.ts +378 -0
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
- package/src/__tests__/list-messages-attachments.test.ts +21 -17
- package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
- package/src/__tests__/list-messages-page-latest.test.ts +130 -14
- package/src/__tests__/list-messages-tool-merge.test.ts +77 -17
- package/src/__tests__/llm-context-normalization.test.ts +0 -2
- package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
- package/src/__tests__/llm-resolver.test.ts +161 -9
- package/src/__tests__/llm-usage-store.test.ts +66 -0
- package/src/__tests__/log-export-routes.test.ts +99 -2
- package/src/__tests__/logger.test.ts +89 -0
- package/src/__tests__/mcp-abort-signal.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +31 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
- package/src/__tests__/message-queue-steer.test.ts +114 -0
- package/src/__tests__/model-intents.test.ts +2 -4
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/onboarding-template-contract.test.ts +1 -1
- package/src/__tests__/openai-provider.test.ts +151 -0
- package/src/__tests__/openai-responses-provider.test.ts +118 -16
- package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
- package/src/__tests__/pending-interactions-resolved-event.test.ts +189 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
- package/src/__tests__/platform.test.ts +2 -5
- package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
- package/src/__tests__/plugin-bootstrap.test.ts +2 -2
- package/src/__tests__/plugin-source-watcher.test.ts +302 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
- package/src/__tests__/plugin-types.test.ts +3 -2
- package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
- package/src/__tests__/pricing.test.ts +12 -0
- package/src/__tests__/process-message-background-slack.test.ts +1 -51
- package/src/__tests__/process-message-display-content.test.ts +21 -16
- package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
- package/src/__tests__/registry.test.ts +2 -8
- package/src/__tests__/require-fresh-approval.test.ts +2 -2
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
- package/src/__tests__/server-history-render.test.ts +83 -4
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
- package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
- package/src/__tests__/skill-tool-factory.test.ts +1 -1
- package/src/__tests__/steer-tool-repair.test.ts +249 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/sync-message-contract.test.ts +59 -0
- package/src/__tests__/system-prompt.test.ts +161 -124
- package/src/__tests__/terminal-tools.test.ts +12 -2
- package/src/__tests__/thinking-block-replay.test.ts +113 -0
- package/src/__tests__/thread-backfill.test.ts +370 -22
- package/src/__tests__/tool-approval-handler.test.ts +1 -5
- package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
- package/src/__tests__/tool-executor.test.ts +89 -53
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
- package/src/__tests__/usage-routes.test.ts +3 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
- package/src/__tests__/web-fetch.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +94 -10
- package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
- package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
- package/src/acp/prepare-agent-env.ts +78 -0
- package/src/acp/session-manager.ts +1 -1
- package/src/agent/attachments.ts +1 -0
- package/src/agent/loop.ts +65 -20
- package/src/api/README.md +5 -0
- package/src/api/index.ts +4 -0
- package/src/api/package.json +10 -0
- package/src/background-wake/background-wake-routes.test.ts +233 -0
- package/src/background-wake/next-wake.test.ts +289 -0
- package/src/background-wake/next-wake.ts +172 -0
- package/src/background-wake/runtime-registry.ts +24 -0
- package/src/browser/operations.ts +15 -0
- package/src/cli/commands/__tests__/browser.test.ts +23 -5
- package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
- package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
- package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +10 -12
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
- package/src/cli/commands/browser.ts +247 -0
- package/src/cli/commands/conversations.ts +128 -1
- package/src/cli/commands/domain.ts +91 -41
- package/src/cli/commands/inference-providers.ts +147 -1
- package/src/cli/commands/inference.ts +93 -40
- package/src/cli/commands/memory-v2-compare-render.ts +115 -0
- package/src/cli/commands/memory-v2.ts +483 -0
- package/src/cli/commands/memory-v3-render.ts +344 -0
- package/src/cli/commands/memory-v3.ts +316 -0
- package/src/cli/commands/notifications.ts +24 -2
- package/src/cli/program.ts +2 -0
- package/src/cli/utils/conversation-id.ts +17 -5
- package/src/config/assistant-feature-flags.ts +21 -9
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/document-editor/SKILL.md +124 -0
- package/src/config/bundled-skills/document-editor/TOOLS.json +258 -0
- package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
- package/src/config/bundled-skills/schedule/SKILL.md +8 -0
- package/src/config/bundled-tool-registry.ts +24 -12
- package/src/config/call-site-defaults.ts +20 -0
- package/src/config/feature-flag-registry.json +115 -3
- package/src/config/llm-resolver.ts +16 -2
- package/src/config/schemas/__tests__/memory-v2.test.ts +217 -1
- package/src/config/schemas/call-site-catalog.ts +35 -0
- package/src/config/schemas/llm.ts +14 -0
- package/src/config/schemas/memory-v2.ts +294 -1
- package/src/config/schemas/memory.ts +2 -1
- package/src/context/compactor.ts +60 -1
- package/src/context/token-estimator.ts +47 -4
- package/src/context/window-manager.ts +25 -0
- package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
- package/src/conversations/message-consolidation.ts +404 -0
- package/src/credential-health/credential-health-service.ts +34 -19
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +155 -36
- package/src/daemon/conversation-agent-loop.ts +307 -88
- package/src/daemon/conversation-error.ts +31 -1
- package/src/daemon/conversation-lifecycle.ts +149 -118
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +273 -0
- package/src/daemon/conversation-queue-manager.ts +14 -0
- package/src/daemon/conversation-runtime-assembly.ts +145 -84
- package/src/daemon/conversation-slash.ts +37 -5
- package/src/daemon/conversation-surfaces.ts +45 -2
- package/src/daemon/conversation-tool-setup.ts +70 -3
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +54 -32
- package/src/daemon/disk-pressure-guard.ts +14 -2
- package/src/daemon/first-greeting.ts +10 -0
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
- package/src/daemon/handlers/config-a2a.ts +160 -0
- package/src/daemon/handlers/config-model.test.ts +2 -0
- package/src/daemon/handlers/conversations.ts +90 -3
- package/src/daemon/handlers/shared.ts +92 -29
- package/src/daemon/host-bash-proxy.ts +1 -1
- package/src/daemon/host-browser-proxy.ts +5 -5
- package/src/daemon/host-cu-proxy.ts +5 -5
- package/src/daemon/host-file-proxy.ts +5 -5
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/host-transfer-proxy.ts +11 -11
- package/src/daemon/lifecycle.ts +40 -23
- package/src/daemon/meet-manifest-loader.ts +1 -7
- package/src/daemon/message-protocol.ts +4 -0
- package/src/daemon/message-types/conversations.ts +14 -9
- package/src/daemon/message-types/document-comments.ts +50 -0
- package/src/daemon/message-types/home.ts +1 -13
- package/src/daemon/message-types/messages.ts +66 -7
- package/src/daemon/message-types/surfaces.ts +3 -1
- package/src/daemon/message-types/sync.ts +14 -0
- package/src/daemon/message-types/web-activity.ts +57 -0
- package/src/daemon/plugin-source-watcher.ts +135 -3
- package/src/daemon/process-message.ts +69 -12
- package/src/daemon/shutdown-handlers.ts +24 -5
- package/src/daemon/switch-inference-profile-tool.ts +52 -0
- package/src/daemon/tool-setup-types.ts +13 -0
- package/src/daemon/trust-context.ts +6 -0
- package/src/documents/document-comments-store.test.ts +338 -0
- package/src/documents/document-comments-store.ts +237 -0
- package/src/documents/document-store.ts +202 -0
- package/src/events/relationship-state-updated.ts +25 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -2
- package/src/heartbeat/heartbeat-service.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +33 -2
- package/src/home/feed-types.ts +6 -1
- package/src/home/home-content-refresh.ts +52 -0
- package/src/home/home-greeting-cache.ts +69 -0
- package/src/home/home-greeting.ts +85 -0
- package/src/home/suggested-prompts.ts +168 -9
- package/src/ipc/gateway-flag-listener.ts +123 -0
- package/src/ipc/skill-routes/registries.ts +8 -12
- package/src/memory/__tests__/db-async-query.test.ts +165 -0
- package/src/memory/__tests__/db-maintenance.test.ts +115 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
- package/src/memory/__tests__/memory-retrospective-job.test.ts +327 -6
- package/src/memory/auto-analysis-enqueue.ts +5 -1
- package/src/memory/conversation-crud.ts +191 -100
- package/src/memory/conversation-starters-cadence.ts +3 -1
- package/src/memory/conversation-title-service.ts +19 -3
- package/src/memory/db-async-query.ts +214 -0
- package/src/memory/db-init.ts +26 -0
- package/src/memory/db-maintenance.ts +30 -21
- package/src/memory/delivery-crud.ts +41 -0
- package/src/memory/delivery-status.ts +141 -15
- package/src/memory/external-conversation-store.ts +32 -1
- package/src/memory/graph/bootstrap.ts +8 -1
- package/src/memory/graph/capability-seed.ts +7 -3
- package/src/memory/graph/conversation-graph-memory.ts +100 -17
- package/src/memory/graph/extraction.ts +1 -5
- package/src/memory/graph/graph-search.ts +7 -1
- package/src/memory/indexer.ts +28 -18
- package/src/memory/job-handlers/cleanup.ts +76 -18
- package/src/memory/job-handlers/conversation-starters.ts +1 -4
- package/src/memory/jobs/embed-pkb-file.ts +6 -1
- package/src/memory/jobs-store.ts +14 -0
- package/src/memory/jobs-worker.ts +68 -15
- package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
- package/src/memory/llm-request-log-source-local.ts +7 -0
- package/src/memory/llm-request-log-source.ts +9 -2
- package/src/memory/llm-request-log-store.ts +43 -1
- package/src/memory/llm-usage-store.ts +24 -0
- package/src/memory/memory-retrospective-constants.ts +28 -0
- package/src/memory/memory-retrospective-enqueue.ts +11 -3
- package/src/memory/memory-retrospective-job.ts +413 -18
- package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
- package/src/memory/memory-v2-activation-log-store.ts +41 -14
- package/src/memory/migrations/100-core-tables.ts +1 -0
- package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
- package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
- package/src/memory/migrations/253-document-comments.ts +47 -0
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
- package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
- package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
- package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
- package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
- package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
- package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
- package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
- package/src/memory/migrations/index.ts +34 -0
- package/src/memory/migrations/registry.ts +58 -0
- package/src/memory/onboarding-events-store.ts +7 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/infrastructure.ts +22 -0
- package/src/memory/tool-usage-store.ts +36 -8
- package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
- package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
- package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
- package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
- package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
- package/src/memory/v2/__tests__/injection.test.ts +158 -112
- package/src/memory/v2/__tests__/page-index.test.ts +365 -1
- package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
- package/src/memory/v2/__tests__/router.test.ts +660 -4
- package/src/memory/v2/consolidation-job.ts +14 -0
- package/src/memory/v2/harness/compare.ts +57 -0
- package/src/memory/v2/harness/metrics.ts +124 -0
- package/src/memory/v2/harness/oracle.ts +145 -0
- package/src/memory/v2/harness/replay-input.ts +224 -0
- package/src/memory/v2/harness/retriever.ts +74 -0
- package/src/memory/v2/harness/router-retriever.ts +43 -0
- package/src/memory/v2/harness/runner.ts +106 -0
- package/src/memory/v2/harness/trace.ts +58 -0
- package/src/memory/v2/injection-events.ts +101 -0
- package/src/memory/v2/injection.ts +42 -25
- package/src/memory/v2/page-index.ts +209 -7
- package/src/memory/v2/page-store.ts +18 -0
- package/src/memory/v2/prompts/router.ts +26 -1
- package/src/memory/v2/qdrant.ts +14 -2
- package/src/memory/v2/router.ts +369 -62
- package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
- package/src/memory/v3/__tests__/edges.test.ts +563 -0
- package/src/memory/v3/__tests__/filter.test.ts +512 -0
- package/src/memory/v3/__tests__/gate.test.ts +574 -0
- package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
- package/src/memory/v3/__tests__/loop.test.ts +530 -0
- package/src/memory/v3/__tests__/retriever.test.ts +226 -0
- package/src/memory/v3/__tests__/scouts.test.ts +440 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
- package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
- package/src/memory/v3/__tests__/traversal.test.ts +469 -0
- package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
- package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
- package/src/memory/v3/__tests__/validate.test.ts +245 -0
- package/src/memory/v3/auto-edges.ts +223 -0
- package/src/memory/v3/coactivation-store.ts +124 -0
- package/src/memory/v3/consolidation-job.ts +323 -0
- package/src/memory/v3/edge-learning-job.ts +160 -0
- package/src/memory/v3/edges.ts +249 -0
- package/src/memory/v3/filter.ts +281 -0
- package/src/memory/v3/gate.ts +334 -0
- package/src/memory/v3/index-composition.ts +113 -0
- package/src/memory/v3/llm-capture.ts +46 -0
- package/src/memory/v3/loop.ts +382 -0
- package/src/memory/v3/maintenance.ts +144 -0
- package/src/memory/v3/prompt-context.ts +33 -0
- package/src/memory/v3/prompts/consolidation.ts +458 -0
- package/src/memory/v3/prompts/system-prompts.ts +196 -0
- package/src/memory/v3/retriever.ts +33 -0
- package/src/memory/v3/scouts.ts +420 -0
- package/src/memory/v3/shadow-middleware.ts +305 -0
- package/src/memory/v3/traversal.ts +206 -0
- package/src/memory/v3/tree-index.ts +237 -0
- package/src/memory/v3/tree-store.ts +394 -0
- package/src/memory/v3/tree-walk.ts +351 -0
- package/src/memory/v3/types.ts +65 -0
- package/src/memory/v3/validate.ts +300 -0
- package/src/messaging/providers/index.ts +7 -1
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
- package/src/messaging/providers/slack/adapter.ts +178 -25
- package/src/messaging/providers/slack/api.test.ts +54 -0
- package/src/messaging/providers/slack/api.ts +119 -3
- package/src/messaging/providers/slack/client.ts +12 -0
- package/src/messaging/providers/slack/deep-link.ts +20 -1
- package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
- package/src/messaging/providers/slack/message-metadata.ts +156 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
- package/src/messaging/providers/slack/render-transcript.ts +176 -49
- package/src/messaging/providers/slack/send.test.ts +77 -0
- package/src/messaging/providers/slack/send.ts +8 -2
- package/src/messaging/providers/slack/types.ts +14 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
- package/src/notifications/adapters/macos.ts +18 -1
- package/src/notifications/adapters/platform.ts +1 -1
- package/src/notifications/conversation-seed-composer.ts +14 -2
- package/src/notifications/decision-engine.ts +1 -4
- package/src/notifications/deferred-emit.ts +135 -0
- package/src/notifications/emit-signal.ts +38 -50
- package/src/notifications/home-feed-side-effect.ts +60 -30
- package/src/oauth/connect-orchestrator.ts +3 -0
- package/src/oauth/credential-token-resolver.ts +2 -0
- package/src/oauth/manual-token-connection.ts +19 -0
- package/src/oauth/oauth-store.ts +12 -0
- package/src/oauth/seed-providers.ts +22 -0
- package/src/permissions/prompter.ts +8 -5
- package/src/permissions/question-prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +6 -3
- package/src/plugin-api/index.ts +4 -0
- package/src/plugin-api/types.ts +7 -33
- package/src/plugins/defaults/index.ts +6 -0
- package/src/plugins/defaults/injectors.ts +100 -20
- package/src/plugins/external-plugin-loader.ts +5 -68
- package/src/plugins/types.ts +11 -16
- package/src/proactive-artifact/aux-message-injector.ts +17 -4
- package/src/prompts/__tests__/system-prompt.test.ts +46 -2
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
- package/src/prompts/normalize-onboarding.ts +40 -0
- package/src/prompts/persona-resolver.ts +36 -21
- package/src/prompts/sections.ts +69 -19
- package/src/prompts/system-prompt.ts +118 -216
- package/src/prompts/template-detection.ts +37 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
- package/src/prompts/templates/BOOTSTRAP.md +10 -2
- package/src/prompts/templates/VOICE.md +3 -0
- package/src/prompts/templates/system-sections.ts +281 -9
- package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
- package/src/providers/__tests__/retry-callsite.test.ts +85 -5
- package/src/providers/anthropic/client.ts +159 -66
- package/src/providers/call-site-routing.ts +14 -2
- package/src/providers/connection-model-compat.ts +38 -0
- package/src/providers/connection-resolution.ts +16 -2
- package/src/providers/fireworks/client.ts +20 -2
- package/src/providers/gemini/client.ts +49 -6
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
- package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
- package/src/providers/inference/adapter-factory.ts +18 -1
- package/src/providers/inference/auth.ts +3 -3
- package/src/providers/inference/codex-token-refresh.ts +128 -0
- package/src/providers/inference/resolve-auth.ts +49 -6
- package/src/providers/minimax/client.ts +106 -0
- package/src/providers/model-catalog.ts +91 -1
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openai/chat-completions-provider.ts +63 -23
- package/src/providers/openai/codex-models.ts +18 -0
- package/src/providers/openai/responses-provider.ts +86 -23
- package/src/providers/openrouter/client.ts +5 -1
- package/src/providers/provider-send-message.ts +7 -1
- package/src/providers/retry.ts +34 -3
- package/src/providers/thinking-config.ts +26 -1
- package/src/providers/types.ts +25 -0
- package/src/providers/usage-tracking.ts +2 -0
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/__tests__/agent-wake.test.ts +214 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
- package/src/runtime/agent-wake.ts +152 -56
- package/src/runtime/assistant-event-hub.ts +76 -6
- package/src/runtime/auth/route-policy.ts +43 -3
- package/src/runtime/background-job-runner.ts +26 -0
- package/src/runtime/btw-sidechain.ts +0 -6
- package/src/runtime/channel-reply-delivery.ts +182 -47
- package/src/runtime/channel-retry-sweep.ts +141 -16
- package/src/runtime/http-types.ts +7 -6
- package/src/runtime/migrations/vbundle-builder.ts +10 -3
- package/src/runtime/pending-interactions.ts +50 -8
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +161 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +290 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
- package/src/runtime/routes/acp-routes.test.ts +255 -6
- package/src/runtime/routes/acp-routes.ts +8 -1
- package/src/runtime/routes/approval-routes.ts +4 -1
- package/src/runtime/routes/avatar-routes.ts +10 -10
- package/src/runtime/routes/background-wake-routes.ts +188 -0
- package/src/runtime/routes/browser-tabs-routes.ts +200 -0
- package/src/runtime/routes/btw-routes.ts +0 -6
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
- package/src/runtime/routes/content-source-routes.ts +78 -0
- package/src/runtime/routes/conversation-cli-routes.ts +147 -2
- package/src/runtime/routes/conversation-list-routes.ts +12 -4
- package/src/runtime/routes/conversation-management-routes.ts +77 -20
- package/src/runtime/routes/conversation-query-routes.ts +196 -31
- package/src/runtime/routes/conversation-routes.ts +472 -425
- package/src/runtime/routes/conversation-starter-routes.ts +6 -3
- package/src/runtime/routes/disk-pressure-routes.ts +1 -1
- package/src/runtime/routes/document-comments-routes.ts +287 -0
- package/src/runtime/routes/documents-routes.ts +33 -0
- package/src/runtime/routes/domain-routes.ts +60 -10
- package/src/runtime/routes/email-routes.ts +5 -2
- package/src/runtime/routes/events-routes.ts +54 -10
- package/src/runtime/routes/group-routes.ts +24 -8
- package/src/runtime/routes/home-feed-routes.ts +6 -3
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-browser-routes.ts +17 -2
- package/src/runtime/routes/host-cu-routes.ts +2 -2
- package/src/runtime/routes/identity-routes.ts +21 -0
- package/src/runtime/routes/inbound-message-handler.ts +288 -58
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
- package/src/runtime/routes/index.ts +20 -4
- package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
- package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
- package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
- package/src/runtime/routes/integrations/a2a.ts +60 -1
- package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
- package/src/runtime/routes/log-export-routes.ts +39 -0
- package/src/runtime/routes/memory-item-routes.ts +8 -3
- package/src/runtime/routes/memory-v2-routes.ts +427 -0
- package/src/runtime/routes/memory-v3-routes.ts +316 -0
- package/src/runtime/routes/migration-routes.ts +21 -24
- package/src/runtime/routes/notification-routes.ts +19 -2
- package/src/runtime/routes/plugins-routes.ts +337 -0
- package/src/runtime/routes/question-routes.ts +4 -1
- package/src/runtime/routes/rename-conversation-routes.ts +6 -2
- package/src/runtime/routes/sanity-routes.ts +159 -0
- package/src/runtime/routes/secret-routes.ts +25 -5
- package/src/runtime/routes/settings-routes.ts +12 -11
- package/src/runtime/routes/slack-channel-routes.ts +188 -0
- package/src/runtime/routes/workspace-routes.ts +25 -10
- package/src/runtime/services/conversation-serializer.ts +30 -4
- package/src/runtime/sync/resource-sync-events.ts +106 -38
- package/src/runtime/sync/sync-publisher.test.ts +49 -0
- package/src/runtime/sync/sync-publisher.ts +2 -1
- package/src/runtime/verification-outbound-actions.ts +73 -1
- package/src/schedule/integration-status.ts +3 -1
- package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
- package/src/security/oauth2-device-code.ts +307 -0
- package/src/security/oauth2.ts +26 -9
- package/src/security/secure-keys.ts +5 -0
- package/src/skills/catalog-install.ts +6 -2
- package/src/telemetry/types.ts +12 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/acp/spawn.test.ts +119 -0
- package/src/tools/acp/spawn.ts +15 -2
- package/src/tools/apps/definitions.ts +2 -8
- package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
- package/src/tools/ask-question/ask-question-tool.ts +38 -45
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +150 -0
- package/src/tools/browser/browser-execution.ts +106 -0
- package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +4 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +22 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +42 -2
- package/src/tools/browser/cdp-client/factory.ts +171 -4
- package/src/tools/browser/cdp-client/local-cdp-client.ts +21 -0
- package/src/tools/browser/cdp-client/types.ts +101 -0
- package/src/tools/browser/pinned-tabs.ts +146 -0
- package/src/tools/computer-use/definitions.ts +22 -78
- package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
- package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
- package/src/tools/credentials/vault.ts +3 -9
- package/src/tools/document/document-comment-tool.test.ts +379 -0
- package/src/tools/document/document-comment-tool.ts +156 -0
- package/src/tools/document/document-tool.ts +187 -2
- package/src/tools/execution-target.ts +21 -23
- package/src/tools/executor.ts +6 -1
- package/src/tools/filesystem/edit.ts +3 -9
- package/src/tools/filesystem/list.ts +3 -9
- package/src/tools/filesystem/read.ts +3 -9
- package/src/tools/filesystem/write.ts +3 -9
- package/src/tools/host-filesystem/edit.ts +3 -9
- package/src/tools/host-filesystem/read.ts +3 -9
- package/src/tools/host-filesystem/transfer.ts +3 -9
- package/src/tools/host-filesystem/write.ts +3 -9
- package/src/tools/host-terminal/host-shell.ts +3 -9
- package/src/tools/mcp/mcp-tool-factory.ts +1 -8
- package/src/tools/memory/register.test.ts +1 -1
- package/src/tools/memory/register.ts +4 -9
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
- package/src/tools/network/domain-normalize.ts +17 -0
- package/src/tools/network/web-fetch.ts +216 -73
- package/src/tools/network/web-search.ts +216 -98
- package/src/tools/registry.ts +7 -23
- package/src/tools/schema-transforms.ts +1 -1
- package/src/tools/skills/execute.ts +3 -9
- package/src/tools/skills/load.ts +3 -9
- package/src/tools/skills/skill-tool-factory.ts +1 -8
- package/src/tools/subagent/notify-parent.ts +3 -9
- package/src/tools/system/request-permission.ts +3 -9
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +3 -9
- package/src/tools/tool-approval-handler.ts +19 -12
- package/src/tools/tool-defaults.ts +94 -0
- package/src/tools/types.ts +31 -98
- package/src/tools/ui-surface/definitions.ts +9 -23
- package/src/types/onboarding-context.ts +4 -0
- package/src/usage/pricing.ts +23 -0
- package/src/usage/types.ts +12 -0
- package/src/util/__tests__/favicon.test.ts +84 -0
- package/src/util/favicon.ts +40 -0
- package/src/util/logger.ts +16 -7
- package/src/util/platform.ts +7 -7
- package/src/util/sqlite3-runtime.ts +65 -0
- package/src/workspace/git-service.ts +75 -4
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
- package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
- package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
- package/src/__tests__/message-complete-display-id.test.ts +0 -175
- package/src/config/bundled-skills/document/SKILL.md +0 -54
- package/src/config/bundled-skills/document/TOOLS.json +0 -106
- package/src/daemon/seed-files.ts +0 -18
- package/src/prompts/cache-boundary.ts +0 -8
- package/src/runtime/routes/interface-routes.ts +0 -43
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run a SQL statement asynchronously, without blocking the daemon's
|
|
3
|
+
* main event loop.
|
|
4
|
+
*
|
|
5
|
+
* `bun:sqlite` is synchronous, so any long-running statement on the
|
|
6
|
+
* shared in-process connection stalls the event loop for the full
|
|
7
|
+
* duration of the statement. For multi-minute operations like `VACUUM`
|
|
8
|
+
* on a multi-GB database, this stalls every other piece of I/O —
|
|
9
|
+
* including the healthz handler — and on platform that has been
|
|
10
|
+
* observed to fail liveness probes and crashloop the pod.
|
|
11
|
+
*
|
|
12
|
+
* Backend selection:
|
|
13
|
+
* 1. **`sqlite3` CLI subprocess (preferred).** Spawn a child process
|
|
14
|
+
* that opens its own SQLite connection, runs the statement, and
|
|
15
|
+
* exits. The daemon's event loop is free for the full duration.
|
|
16
|
+
* SQLite's own file-locking arbitrates between the subprocess and
|
|
17
|
+
* the still-running in-process connection.
|
|
18
|
+
* 2. **In-process `bun:sqlite` (fallback).** Synchronous, blocking.
|
|
19
|
+
* Only fires when no `sqlite3` binary is on the host. This is the
|
|
20
|
+
* same behavior the daemon had before this abstraction existed,
|
|
21
|
+
* and is acceptable on desktop where no liveness probe is going to
|
|
22
|
+
* kill the process for a long stall.
|
|
23
|
+
*
|
|
24
|
+
* Use this for statements known to be slow (`VACUUM`, `ANALYZE`,
|
|
25
|
+
* `PRAGMA optimize`, large bulk `DELETE`/`UPDATE`). Fast queries (a few
|
|
26
|
+
* ms) should keep using the in-process drizzle / `bun:sqlite` handle
|
|
27
|
+
* directly — the subprocess overhead would dominate.
|
|
28
|
+
*/
|
|
29
|
+
import { getLogger } from "../util/logger.js";
|
|
30
|
+
import { getDbPath } from "../util/platform.js";
|
|
31
|
+
import { findSqlite3 } from "../util/sqlite3-runtime.js";
|
|
32
|
+
import { getSqlite } from "./db-connection.js";
|
|
33
|
+
|
|
34
|
+
const log = getLogger("db-async-query");
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Default wall-clock cap for an async statement. A real `VACUUM` on a
|
|
38
|
+
* multi-GB database can legitimately take many minutes; the cap is
|
|
39
|
+
* here to bound a runaway subprocess (e.g. one stuck on a stale file
|
|
40
|
+
* lock). Override per call via `runAsyncSqlite(sql, { timeoutMs })`.
|
|
41
|
+
*/
|
|
42
|
+
const DEFAULT_TIMEOUT_MS = 60 * 60 * 1000; // 1 hour
|
|
43
|
+
|
|
44
|
+
export type AsyncSqliteBackend = "sqlite3-cli" | "in-process-blocking";
|
|
45
|
+
|
|
46
|
+
export interface AsyncSqliteResult {
|
|
47
|
+
ok: boolean;
|
|
48
|
+
backend: AsyncSqliteBackend;
|
|
49
|
+
error: string | null;
|
|
50
|
+
elapsedMs: number;
|
|
51
|
+
stdout?: string;
|
|
52
|
+
stderr?: string;
|
|
53
|
+
timedOut?: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface RunAsyncSqliteOptions {
|
|
57
|
+
/** Override the default 1 h subprocess timeout. */
|
|
58
|
+
timeoutMs?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Force a specific backend. Test-only; production callers should let
|
|
61
|
+
* the runtime pick.
|
|
62
|
+
*/
|
|
63
|
+
forceBackend?: AsyncSqliteBackend;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let warnedAboutFallback = false;
|
|
67
|
+
|
|
68
|
+
export async function runAsyncSqlite(
|
|
69
|
+
sql: string,
|
|
70
|
+
options: RunAsyncSqliteOptions = {},
|
|
71
|
+
): Promise<AsyncSqliteResult> {
|
|
72
|
+
const forced = options.forceBackend;
|
|
73
|
+
const sqlite3Path =
|
|
74
|
+
forced === "in-process-blocking" ? undefined : findSqlite3();
|
|
75
|
+
|
|
76
|
+
if (sqlite3Path && forced !== "in-process-blocking") {
|
|
77
|
+
return runViaCli(sqlite3Path, sql, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!warnedAboutFallback) {
|
|
81
|
+
warnedAboutFallback = true;
|
|
82
|
+
log.warn(
|
|
83
|
+
"No sqlite3 CLI found on host — falling back to in-process blocking " +
|
|
84
|
+
"execution for slow SQLite statements. Install sqlite3 to keep the " +
|
|
85
|
+
"event loop responsive during VACUUM and other long operations.",
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
return runInProcessBlocking(sql);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** For tests: reset the once-only fallback warning. */
|
|
92
|
+
export function _resetFallbackWarning(): void {
|
|
93
|
+
warnedAboutFallback = false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function runViaCli(
|
|
97
|
+
sqlite3Path: string,
|
|
98
|
+
sql: string,
|
|
99
|
+
timeoutMs: number,
|
|
100
|
+
): Promise<AsyncSqliteResult> {
|
|
101
|
+
const startMs = Date.now();
|
|
102
|
+
const dbPath = getDbPath();
|
|
103
|
+
|
|
104
|
+
log.info(
|
|
105
|
+
{ sqlite3Path, dbPath, timeoutMs, sqlPreview: sql.slice(0, 80) },
|
|
106
|
+
"Running async SQL via sqlite3 CLI subprocess",
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// Pass the SQL via stdin rather than -cmd so newlines and quoting are
|
|
110
|
+
// never an issue regardless of the statement complexity.
|
|
111
|
+
const proc = Bun.spawn({
|
|
112
|
+
cmd: [sqlite3Path, dbPath],
|
|
113
|
+
stdin: "pipe",
|
|
114
|
+
stdout: "pipe",
|
|
115
|
+
stderr: "pipe",
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Write the SQL and close stdin so sqlite3 sees EOF and exits.
|
|
119
|
+
proc.stdin.write(sql + "\n");
|
|
120
|
+
await proc.stdin.end();
|
|
121
|
+
|
|
122
|
+
// Begin draining the streams immediately so the subprocess never
|
|
123
|
+
// blocks on a full pipe buffer.
|
|
124
|
+
const stdoutPromise = new Response(proc.stdout).text();
|
|
125
|
+
const stderrPromise = new Response(proc.stderr).text();
|
|
126
|
+
|
|
127
|
+
let timedOut = false;
|
|
128
|
+
const timer = setTimeout(() => {
|
|
129
|
+
timedOut = true;
|
|
130
|
+
proc.kill("SIGKILL");
|
|
131
|
+
}, timeoutMs);
|
|
132
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
133
|
+
|
|
134
|
+
const exitCode = await proc.exited;
|
|
135
|
+
clearTimeout(timer);
|
|
136
|
+
|
|
137
|
+
const stdout = await stdoutPromise;
|
|
138
|
+
const stderr = await stderrPromise;
|
|
139
|
+
const elapsedMs = Date.now() - startMs;
|
|
140
|
+
|
|
141
|
+
if (timedOut) {
|
|
142
|
+
log.error(
|
|
143
|
+
{ timeoutMs, elapsedMs, stderr: stderr.slice(0, 2000) },
|
|
144
|
+
"Async SQL subprocess timed out — killed",
|
|
145
|
+
);
|
|
146
|
+
return {
|
|
147
|
+
ok: false,
|
|
148
|
+
backend: "sqlite3-cli",
|
|
149
|
+
error: `sqlite3 subprocess timed out after ${timeoutMs}ms`,
|
|
150
|
+
elapsedMs,
|
|
151
|
+
stdout,
|
|
152
|
+
stderr,
|
|
153
|
+
timedOut: true,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (exitCode !== 0) {
|
|
157
|
+
log.error(
|
|
158
|
+
{ exitCode, elapsedMs, stderr: stderr.slice(0, 2000) },
|
|
159
|
+
"Async SQL subprocess failed",
|
|
160
|
+
);
|
|
161
|
+
return {
|
|
162
|
+
ok: false,
|
|
163
|
+
backend: "sqlite3-cli",
|
|
164
|
+
error: `sqlite3 exited with code ${exitCode}: ${stderr.slice(0, 500)}`,
|
|
165
|
+
elapsedMs,
|
|
166
|
+
stdout,
|
|
167
|
+
stderr,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
ok: true,
|
|
172
|
+
backend: "sqlite3-cli",
|
|
173
|
+
error: null,
|
|
174
|
+
elapsedMs,
|
|
175
|
+
stdout,
|
|
176
|
+
stderr,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function runInProcessBlocking(sql: string): Promise<AsyncSqliteResult> {
|
|
181
|
+
const startMs = Date.now();
|
|
182
|
+
try {
|
|
183
|
+
const sqlite = getSqlite();
|
|
184
|
+
sqlite.exec(sql);
|
|
185
|
+
// Synthesize `stdout` to match what the CLI backend would emit
|
|
186
|
+
// when the caller chained `SELECT changes();` at the end of their
|
|
187
|
+
// SQL. `bun:sqlite`'s `exec()` discards SELECT results, so without
|
|
188
|
+
// this synthesis, callers that read `stdout` to get the row count
|
|
189
|
+
// (the prune jobs in cleanup.ts, for one) would see `undefined`
|
|
190
|
+
// and treat the run as "no rows deleted" — silently dropping the
|
|
191
|
+
// re-enqueue gate on every fallback host. Captured atomically with
|
|
192
|
+
// exec (same synchronous slice — no other code can run between
|
|
193
|
+
// these two lines), so the count is accurate for the SQL we just
|
|
194
|
+
// ran. Harmless for callers that don't read stdout.
|
|
195
|
+
const changes = (
|
|
196
|
+
sqlite.query("SELECT changes() AS c").get() as { c: number }
|
|
197
|
+
).c;
|
|
198
|
+
return {
|
|
199
|
+
ok: true,
|
|
200
|
+
backend: "in-process-blocking",
|
|
201
|
+
error: null,
|
|
202
|
+
elapsedMs: Date.now() - startMs,
|
|
203
|
+
stdout: `${changes}\n`,
|
|
204
|
+
};
|
|
205
|
+
} catch (err) {
|
|
206
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
207
|
+
return {
|
|
208
|
+
ok: false,
|
|
209
|
+
backend: "in-process-blocking",
|
|
210
|
+
error: message,
|
|
211
|
+
elapsedMs: Date.now() - startMs,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
package/src/memory/db-init.ts
CHANGED
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
migrateCanonicalGuardianRequesterChatId,
|
|
59
59
|
migrateCapabilityCardColumns,
|
|
60
60
|
migrateChannelInboundDeliveredSegments,
|
|
61
|
+
migrateChannelInboundDeliveryAttempts,
|
|
61
62
|
migrateChannelInteractionColumns,
|
|
62
63
|
migrateContactChannelsAccessFields,
|
|
63
64
|
migrateContactChannelsTypeChatIdIndex,
|
|
@@ -65,13 +66,16 @@ import {
|
|
|
65
66
|
migrateContactsNotesColumn,
|
|
66
67
|
migrateContactsRolePrincipal,
|
|
67
68
|
migrateContactsUserFileColumn,
|
|
69
|
+
migrateConversationCleanedAt,
|
|
68
70
|
migrateConversationForkLineage,
|
|
69
71
|
migrateConversationHostAccess,
|
|
70
72
|
migrateConversationInferenceProfileSession,
|
|
73
|
+
migrateConversationLastNotifiedProfile,
|
|
71
74
|
migrateConversationsArchivedAt,
|
|
72
75
|
migrateConversationsLastMessageAt,
|
|
73
76
|
migrateConversationsThreadTypeIndex,
|
|
74
77
|
migrateCreateConversationGraphMemoryState,
|
|
78
|
+
migrateCreateDocumentComments,
|
|
75
79
|
migrateCreateDocumentConversations,
|
|
76
80
|
migrateCreateMemoryGraphNodeEdits,
|
|
77
81
|
migrateCreateMemoryGraphTables,
|
|
@@ -96,6 +100,7 @@ import {
|
|
|
96
100
|
migrateDropSetupSkillIdColumn,
|
|
97
101
|
migrateDropSimplifiedMemory,
|
|
98
102
|
migrateDropUsageCompositeIndexes,
|
|
103
|
+
migrateExternalConversationBindingChatName,
|
|
99
104
|
migrateExternalConversationBindingThreadId,
|
|
100
105
|
migrateFkCascadeRebuilds,
|
|
101
106
|
migrateGuardianActionFollowup,
|
|
@@ -113,15 +118,20 @@ import {
|
|
|
113
118
|
migrateInviteCodeHashColumn,
|
|
114
119
|
migrateInviteContactId,
|
|
115
120
|
migrateLlmRequestLogAgentLoopExitReason,
|
|
121
|
+
migrateLlmRequestLogCallSite,
|
|
116
122
|
migrateLlmRequestLogMessageId,
|
|
117
123
|
migrateLlmRequestLogProvider,
|
|
118
124
|
migrateLlmRequestLogsCreatedAtIndex,
|
|
125
|
+
migrateLlmUsageAddRawUsage,
|
|
119
126
|
migrateLlmUsageAttribution,
|
|
120
127
|
migrateMemoryGraphImageRefs,
|
|
121
128
|
migrateMemoryItemSupersession,
|
|
122
129
|
migrateMemoryRecallLogsQueryContext,
|
|
123
130
|
migrateMemoryRetrospectiveState,
|
|
124
131
|
migrateMemoryV2ActivationLogs,
|
|
132
|
+
migrateMemoryV2InjectionEvents,
|
|
133
|
+
migrateMemoryV3AutoEdges,
|
|
134
|
+
migrateMemoryV3Coactivation,
|
|
125
135
|
migrateMessageBookmarks,
|
|
126
136
|
migrateMessagesConversationCreatedAtIndex,
|
|
127
137
|
migrateMessagesFtsBackfill,
|
|
@@ -144,10 +154,12 @@ import {
|
|
|
144
154
|
migrateOAuthProvidersScopeSeparator,
|
|
145
155
|
migrateOAuthProvidersTokenAuthMethodDefault,
|
|
146
156
|
migrateOAuthProvidersTokenExchangeBodyFormat,
|
|
157
|
+
migrateOnboardingEventsPriorAssistants,
|
|
147
158
|
migrateProviderConnectionBaseUrlAndModels,
|
|
148
159
|
migrateProviderConnectionStatusLabel,
|
|
149
160
|
migrateReminderRoutingIntent,
|
|
150
161
|
migrateRemindersToSchedules,
|
|
162
|
+
migrateRenameCleanedAt,
|
|
151
163
|
migrateRenameConversationTypeColumn,
|
|
152
164
|
migrateRenameCreatedBySessionIdColumns,
|
|
153
165
|
migrateRenameFollowupsThreadIdColumn,
|
|
@@ -174,6 +186,7 @@ import {
|
|
|
174
186
|
migrateSchemaIndexesAndColumns,
|
|
175
187
|
migrateScrubCorruptedImageAttachments,
|
|
176
188
|
migrateSlackCompactionWatermark,
|
|
189
|
+
migrateStripBaseUrlNonOpenaiCompatible,
|
|
177
190
|
migrateStripIntegrationPrefixFromProviderKeys,
|
|
178
191
|
migrateStripPlaceholderSentinelsFromMessages,
|
|
179
192
|
migrateStripThinkingFromConsolidated,
|
|
@@ -436,6 +449,19 @@ export function initializeDb(): void {
|
|
|
436
449
|
migrateProviderConnectionBaseUrlAndModels,
|
|
437
450
|
migrateA2ATasks,
|
|
438
451
|
migrateLlmRequestLogAgentLoopExitReason,
|
|
452
|
+
migrateCreateDocumentComments,
|
|
453
|
+
migrateExternalConversationBindingChatName,
|
|
454
|
+
migrateChannelInboundDeliveryAttempts,
|
|
455
|
+
migrateMemoryV2InjectionEvents,
|
|
456
|
+
migrateConversationLastNotifiedProfile,
|
|
457
|
+
migrateStripBaseUrlNonOpenaiCompatible,
|
|
458
|
+
migrateOnboardingEventsPriorAssistants,
|
|
459
|
+
migrateConversationCleanedAt,
|
|
460
|
+
migrateRenameCleanedAt,
|
|
461
|
+
migrateLlmUsageAddRawUsage,
|
|
462
|
+
migrateMemoryV3Coactivation,
|
|
463
|
+
migrateMemoryV3AutoEdges,
|
|
464
|
+
migrateLlmRequestLogCallSite,
|
|
439
465
|
];
|
|
440
466
|
|
|
441
467
|
// Run each migration step, catching and logging individual failures so one
|
|
@@ -3,6 +3,7 @@ import { statSync } from "node:fs";
|
|
|
3
3
|
import { getLogger } from "../util/logger.js";
|
|
4
4
|
import { getDbPath } from "../util/platform.js";
|
|
5
5
|
import { getMemoryCheckpoint, setMemoryCheckpoint } from "./checkpoints.js";
|
|
6
|
+
import { runAsyncSqlite } from "./db-async-query.js";
|
|
6
7
|
import { getSqlite } from "./db-connection.js";
|
|
7
8
|
|
|
8
9
|
const log = getLogger("db-maintenance");
|
|
@@ -11,7 +12,7 @@ const DB_MAINTENANCE_CHECKPOINT_KEY = "db_maintenance:last_run";
|
|
|
11
12
|
const DB_MAINTENANCE_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
12
13
|
|
|
13
14
|
interface DbStats {
|
|
14
|
-
|
|
15
|
+
pageSize: number;
|
|
15
16
|
pageCount: number;
|
|
16
17
|
freelistCount: number;
|
|
17
18
|
fileSizeBytes: number | null;
|
|
@@ -19,7 +20,7 @@ interface DbStats {
|
|
|
19
20
|
|
|
20
21
|
function getDbStats(): DbStats {
|
|
21
22
|
const sqlite = getSqlite();
|
|
22
|
-
const
|
|
23
|
+
const pageSize = (
|
|
23
24
|
sqlite.query("PRAGMA page_size").get() as { page_size: number }
|
|
24
25
|
).page_size;
|
|
25
26
|
const pageCount = (
|
|
@@ -34,10 +35,10 @@ function getDbStats(): DbStats {
|
|
|
34
35
|
} catch {
|
|
35
36
|
/* non-fatal */
|
|
36
37
|
}
|
|
37
|
-
return {
|
|
38
|
+
return { pageSize, pageCount, freelistCount, fileSizeBytes };
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
function runDbMaintenance(): void {
|
|
41
|
+
async function runDbMaintenance(): Promise<void> {
|
|
41
42
|
const before = getDbStats();
|
|
42
43
|
const freelistPct =
|
|
43
44
|
before.pageCount > 0
|
|
@@ -54,22 +55,24 @@ function runDbMaintenance(): void {
|
|
|
54
55
|
"Starting database maintenance",
|
|
55
56
|
);
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
// VACUUM is the long-running one — minutes on a multi-GB DB. PRAGMA
|
|
59
|
+
// optimize is fast but routed through the same async path for
|
|
60
|
+
// consistency and to keep both off the main thread when the CLI
|
|
61
|
+
// backend is available.
|
|
62
|
+
const vacuumResult = await runAsyncSqlite("VACUUM");
|
|
63
|
+
if (!vacuumResult.ok) {
|
|
64
|
+
log.warn(
|
|
65
|
+
{ error: vacuumResult.error, backend: vacuumResult.backend },
|
|
66
|
+
"VACUUM failed (non-fatal)",
|
|
67
|
+
);
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
const optimizeResult = await runAsyncSqlite("PRAGMA optimize");
|
|
71
|
+
if (!optimizeResult.ok) {
|
|
72
|
+
log.warn(
|
|
73
|
+
{ error: optimizeResult.error, backend: optimizeResult.backend },
|
|
74
|
+
"PRAGMA optimize failed (non-fatal)",
|
|
75
|
+
);
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
const after = getDbStats();
|
|
@@ -81,17 +84,23 @@ function runDbMaintenance(): void {
|
|
|
81
84
|
|
|
82
85
|
log.info(
|
|
83
86
|
{
|
|
87
|
+
backend: vacuumResult.backend,
|
|
88
|
+
vacuumOk: vacuumResult.ok,
|
|
89
|
+
optimizeOk: optimizeResult.ok,
|
|
90
|
+
vacuumElapsedMs: vacuumResult.elapsedMs,
|
|
91
|
+
optimizeElapsedMs: optimizeResult.elapsedMs,
|
|
84
92
|
beforePageCount: before.pageCount,
|
|
85
93
|
afterPageCount: after.pageCount,
|
|
86
94
|
reclaimedPages,
|
|
87
|
-
|
|
95
|
+
beforeFileSizeBytes: before.fileSizeBytes,
|
|
88
96
|
afterFileSizeBytes: after.fileSizeBytes,
|
|
97
|
+
reclaimedBytes,
|
|
89
98
|
},
|
|
90
99
|
"Database maintenance complete",
|
|
91
100
|
);
|
|
92
101
|
}
|
|
93
102
|
|
|
94
|
-
export function maybeRunDbMaintenance(nowMs = Date.now()): void {
|
|
103
|
+
export async function maybeRunDbMaintenance(nowMs = Date.now()): Promise<void> {
|
|
95
104
|
const lastRun = parseInt(
|
|
96
105
|
getMemoryCheckpoint(DB_MAINTENANCE_CHECKPOINT_KEY) ?? "0",
|
|
97
106
|
10,
|
|
@@ -99,7 +108,7 @@ export function maybeRunDbMaintenance(nowMs = Date.now()): void {
|
|
|
99
108
|
if (nowMs - lastRun < DB_MAINTENANCE_INTERVAL_MS) return;
|
|
100
109
|
|
|
101
110
|
try {
|
|
102
|
-
runDbMaintenance();
|
|
111
|
+
await runDbMaintenance();
|
|
103
112
|
} catch (err) {
|
|
104
113
|
log.error({ err }, "Database maintenance failed unexpectedly");
|
|
105
114
|
}
|
|
@@ -313,6 +313,47 @@ export function storePayload(
|
|
|
313
313
|
.run();
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
+
/**
|
|
317
|
+
* Persist the assistant reply row generated for an inbound event so callback
|
|
318
|
+
* delivery retries target that exact response instead of the latest message in
|
|
319
|
+
* the conversation.
|
|
320
|
+
*/
|
|
321
|
+
export function storeReplyMessageId(
|
|
322
|
+
eventId: string,
|
|
323
|
+
replyMessageId: string,
|
|
324
|
+
): void {
|
|
325
|
+
const db = getDb();
|
|
326
|
+
const row = db
|
|
327
|
+
.select({ rawPayload: channelInboundEvents.rawPayload })
|
|
328
|
+
.from(channelInboundEvents)
|
|
329
|
+
.where(eq(channelInboundEvents.id, eventId))
|
|
330
|
+
.get();
|
|
331
|
+
if (!row?.rawPayload) return;
|
|
332
|
+
|
|
333
|
+
let payload: Record<string, unknown>;
|
|
334
|
+
try {
|
|
335
|
+
const parsed = JSON.parse(row.rawPayload) as unknown;
|
|
336
|
+
if (
|
|
337
|
+
parsed === null ||
|
|
338
|
+
typeof parsed !== "object" ||
|
|
339
|
+
Array.isArray(parsed)
|
|
340
|
+
) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
payload = parsed as Record<string, unknown>;
|
|
344
|
+
} catch {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
db.update(channelInboundEvents)
|
|
349
|
+
.set({
|
|
350
|
+
rawPayload: JSON.stringify({ ...payload, replyMessageId }),
|
|
351
|
+
updatedAt: Date.now(),
|
|
352
|
+
})
|
|
353
|
+
.where(eq(channelInboundEvents.id, eventId))
|
|
354
|
+
.run();
|
|
355
|
+
}
|
|
356
|
+
|
|
316
357
|
/**
|
|
317
358
|
* Clear a previously stored payload. Used when the ingress check
|
|
318
359
|
* detects secret-bearing content — the payload must not remain on disk.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* retryable and dead-lettered events, and replaying dead letters.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { and, eq, lte } from "drizzle-orm";
|
|
9
|
+
import { and, eq, lte, or } from "drizzle-orm";
|
|
10
10
|
|
|
11
11
|
import { getDb } from "./db-connection.js";
|
|
12
12
|
import {
|
|
@@ -44,6 +44,7 @@ export function acknowledgeDelivery(
|
|
|
44
44
|
db.update(channelInboundEvents)
|
|
45
45
|
.set({
|
|
46
46
|
deliveryStatus: "delivered",
|
|
47
|
+
retryAfter: null,
|
|
47
48
|
updatedAt: now,
|
|
48
49
|
})
|
|
49
50
|
.where(eq(channelInboundEvents.id, existing.id))
|
|
@@ -61,6 +62,23 @@ export function markProcessed(eventId: string): void {
|
|
|
61
62
|
.run();
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
/** Mark an event's outbound callback delivery as complete. */
|
|
66
|
+
export function markDeliveryDelivered(eventId: string): void {
|
|
67
|
+
const db = getDb();
|
|
68
|
+
db.update(channelInboundEvents)
|
|
69
|
+
.set({
|
|
70
|
+
deliveryStatus: "delivered",
|
|
71
|
+
retryAfter: null,
|
|
72
|
+
updatedAt: Date.now(),
|
|
73
|
+
})
|
|
74
|
+
.where(eq(channelInboundEvents.id, eventId))
|
|
75
|
+
.run();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function errorMessage(err: unknown): string {
|
|
79
|
+
return err instanceof Error ? err.message : String(err);
|
|
80
|
+
}
|
|
81
|
+
|
|
64
82
|
/**
|
|
65
83
|
* Record a processing failure. Classifies the error to decide whether
|
|
66
84
|
* the event should be retried (status='failed') or dead-lettered
|
|
@@ -79,7 +97,7 @@ export function recordProcessingFailure(eventId: string, err: unknown): void {
|
|
|
79
97
|
|
|
80
98
|
const attempts = (row?.attempts ?? 0) + 1;
|
|
81
99
|
const category = classifyError(err);
|
|
82
|
-
const errorMsg =
|
|
100
|
+
const errorMsg = errorMessage(err);
|
|
83
101
|
|
|
84
102
|
if (category === "fatal" || attempts >= RETRY_MAX_ATTEMPTS) {
|
|
85
103
|
db.update(channelInboundEvents)
|
|
@@ -107,6 +125,51 @@ export function recordProcessingFailure(eventId: string, err: unknown): void {
|
|
|
107
125
|
}
|
|
108
126
|
}
|
|
109
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Record an outbound callback delivery failure without changing the processing
|
|
130
|
+
* status. Delivery uses its own retry budget so a turn that needed processing
|
|
131
|
+
* retries still gets a full delivery retry window.
|
|
132
|
+
*/
|
|
133
|
+
export function recordDeliveryFailure(eventId: string, err: unknown): void {
|
|
134
|
+
const db = getDb();
|
|
135
|
+
const now = Date.now();
|
|
136
|
+
|
|
137
|
+
const row = db
|
|
138
|
+
.select({ attempts: channelInboundEvents.deliveryAttempts })
|
|
139
|
+
.from(channelInboundEvents)
|
|
140
|
+
.where(eq(channelInboundEvents.id, eventId))
|
|
141
|
+
.get();
|
|
142
|
+
|
|
143
|
+
const attempts = (row?.attempts ?? 0) + 1;
|
|
144
|
+
const category = classifyError(err);
|
|
145
|
+
const errorMsg = errorMessage(err);
|
|
146
|
+
|
|
147
|
+
if (category === "fatal" || attempts >= RETRY_MAX_ATTEMPTS) {
|
|
148
|
+
db.update(channelInboundEvents)
|
|
149
|
+
.set({
|
|
150
|
+
deliveryStatus: "dead_letter",
|
|
151
|
+
deliveryAttempts: attempts,
|
|
152
|
+
lastProcessingError: errorMsg,
|
|
153
|
+
retryAfter: null,
|
|
154
|
+
updatedAt: now,
|
|
155
|
+
})
|
|
156
|
+
.where(eq(channelInboundEvents.id, eventId))
|
|
157
|
+
.run();
|
|
158
|
+
} else {
|
|
159
|
+
const delay = retryDelayForAttempt(attempts);
|
|
160
|
+
db.update(channelInboundEvents)
|
|
161
|
+
.set({
|
|
162
|
+
deliveryStatus: "failed",
|
|
163
|
+
deliveryAttempts: attempts,
|
|
164
|
+
lastProcessingError: errorMsg,
|
|
165
|
+
retryAfter: now + delay,
|
|
166
|
+
updatedAt: now,
|
|
167
|
+
})
|
|
168
|
+
.where(eq(channelInboundEvents.id, eventId))
|
|
169
|
+
.run();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
110
173
|
/**
|
|
111
174
|
* Mark an event as failed with a specific error message, bypassing error
|
|
112
175
|
* classification. Use this when the failure reason is known and the event
|
|
@@ -180,6 +243,38 @@ export function getRetryableEvents(limit = 20): Array<{
|
|
|
180
243
|
.all();
|
|
181
244
|
}
|
|
182
245
|
|
|
246
|
+
/** Fetch callback deliveries eligible for retry without rerunning processing. */
|
|
247
|
+
export function getRetryableDeliveryEvents(limit = 20): Array<{
|
|
248
|
+
id: string;
|
|
249
|
+
conversationId: string;
|
|
250
|
+
messageId: string | null;
|
|
251
|
+
processingAttempts: number;
|
|
252
|
+
rawPayload: string | null;
|
|
253
|
+
deliveredSegmentCount: number;
|
|
254
|
+
}> {
|
|
255
|
+
const db = getDb();
|
|
256
|
+
const now = Date.now();
|
|
257
|
+
return db
|
|
258
|
+
.select({
|
|
259
|
+
id: channelInboundEvents.id,
|
|
260
|
+
conversationId: channelInboundEvents.conversationId,
|
|
261
|
+
messageId: channelInboundEvents.messageId,
|
|
262
|
+
processingAttempts: channelInboundEvents.processingAttempts,
|
|
263
|
+
rawPayload: channelInboundEvents.rawPayload,
|
|
264
|
+
deliveredSegmentCount: channelInboundEvents.deliveredSegmentCount,
|
|
265
|
+
})
|
|
266
|
+
.from(channelInboundEvents)
|
|
267
|
+
.where(
|
|
268
|
+
and(
|
|
269
|
+
eq(channelInboundEvents.processingStatus, "processed"),
|
|
270
|
+
eq(channelInboundEvents.deliveryStatus, "failed"),
|
|
271
|
+
lte(channelInboundEvents.retryAfter, now),
|
|
272
|
+
),
|
|
273
|
+
)
|
|
274
|
+
.limit(limit)
|
|
275
|
+
.all();
|
|
276
|
+
}
|
|
277
|
+
|
|
183
278
|
/** Fetch dead-lettered events. */
|
|
184
279
|
export function getDeadLetterEvents(): Array<{
|
|
185
280
|
id: string;
|
|
@@ -204,7 +299,15 @@ export function getDeadLetterEvents(): Array<{
|
|
|
204
299
|
createdAt: channelInboundEvents.createdAt,
|
|
205
300
|
})
|
|
206
301
|
.from(channelInboundEvents)
|
|
207
|
-
.where(
|
|
302
|
+
.where(
|
|
303
|
+
or(
|
|
304
|
+
eq(channelInboundEvents.processingStatus, "dead_letter"),
|
|
305
|
+
and(
|
|
306
|
+
eq(channelInboundEvents.processingStatus, "processed"),
|
|
307
|
+
eq(channelInboundEvents.deliveryStatus, "dead_letter"),
|
|
308
|
+
),
|
|
309
|
+
),
|
|
310
|
+
)
|
|
208
311
|
.all();
|
|
209
312
|
}
|
|
210
313
|
|
|
@@ -218,27 +321,50 @@ export function replayDeadLetters(eventIds: string[]): number {
|
|
|
218
321
|
let count = 0;
|
|
219
322
|
for (const id of eventIds) {
|
|
220
323
|
const existing = db
|
|
221
|
-
.select({
|
|
324
|
+
.select({
|
|
325
|
+
id: channelInboundEvents.id,
|
|
326
|
+
processingStatus: channelInboundEvents.processingStatus,
|
|
327
|
+
deliveryStatus: channelInboundEvents.deliveryStatus,
|
|
328
|
+
})
|
|
222
329
|
.from(channelInboundEvents)
|
|
223
330
|
.where(
|
|
224
331
|
and(
|
|
225
332
|
eq(channelInboundEvents.id, id),
|
|
226
|
-
|
|
333
|
+
or(
|
|
334
|
+
eq(channelInboundEvents.processingStatus, "dead_letter"),
|
|
335
|
+
and(
|
|
336
|
+
eq(channelInboundEvents.processingStatus, "processed"),
|
|
337
|
+
eq(channelInboundEvents.deliveryStatus, "dead_letter"),
|
|
338
|
+
),
|
|
339
|
+
),
|
|
227
340
|
),
|
|
228
341
|
)
|
|
229
342
|
.get();
|
|
230
343
|
if (!existing) continue;
|
|
231
344
|
|
|
232
|
-
|
|
233
|
-
.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
345
|
+
if (existing.processingStatus === "dead_letter") {
|
|
346
|
+
db.update(channelInboundEvents)
|
|
347
|
+
.set({
|
|
348
|
+
processingStatus: "failed",
|
|
349
|
+
processingAttempts: 0,
|
|
350
|
+
lastProcessingError: null,
|
|
351
|
+
retryAfter: now,
|
|
352
|
+
updatedAt: now,
|
|
353
|
+
})
|
|
354
|
+
.where(eq(channelInboundEvents.id, id))
|
|
355
|
+
.run();
|
|
356
|
+
} else {
|
|
357
|
+
db.update(channelInboundEvents)
|
|
358
|
+
.set({
|
|
359
|
+
deliveryStatus: "failed",
|
|
360
|
+
deliveryAttempts: 0,
|
|
361
|
+
lastProcessingError: null,
|
|
362
|
+
retryAfter: now,
|
|
363
|
+
updatedAt: now,
|
|
364
|
+
})
|
|
365
|
+
.where(eq(channelInboundEvents.id, id))
|
|
366
|
+
.run();
|
|
367
|
+
}
|
|
242
368
|
count++;
|
|
243
369
|
}
|
|
244
370
|
return count;
|