@vellumai/assistant 0.8.4 → 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 +3 -3
- package/bunfig.toml +6 -1
- package/docs/browser-use-architecture-phase2.md +1 -1
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +4 -3
- package/knip.json +2 -1
- 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 +2748 -216
- 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__/anthropic-provider.test.ts +34 -37
- 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-event-hub-self-exclusion.test.ts +293 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +12 -28
- package/src/__tests__/audit-log-rotation.test.ts +72 -18
- package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
- package/src/__tests__/background-workers-disk-pressure.test.ts +8 -11
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +5 -5
- package/src/__tests__/call-controller.test.ts +3 -3
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +3 -2
- package/src/__tests__/channel-guardian.test.ts +6 -5
- 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 +18 -27
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/compaction-trail-store.test.ts +264 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +215 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -16
- package/src/__tests__/computer-use-tools.test.ts +14 -18
- 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__/confirmation-request-guardian-bridge.test.ts +0 -1
- 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 +2 -1
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +231 -2
- package/src/__tests__/conversation-agent-loop.test.ts +581 -54
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
- package/src/__tests__/conversation-app-control-instantiation.test.ts +31 -24
- 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-clear-safety.test.ts +25 -25
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
- 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 +61 -0
- package/src/__tests__/conversation-fork-crud.test.ts +239 -15
- 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 +53 -11
- 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-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +14 -13
- 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 +6 -0
- package/src/__tests__/conversation-queue.test.ts +333 -291
- package/src/__tests__/conversation-routes-disk-view.test.ts +112 -18
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
- package/src/__tests__/conversation-routes-slash-commands.test.ts +68 -2
- package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
- package/src/__tests__/conversation-skill-tools.test.ts +40 -147
- 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-store.test.ts +1 -1
- 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 +218 -35
- 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 +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -1
- 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 +19 -19
- package/src/__tests__/credential-execution-tools.test.ts +6 -6
- package/src/__tests__/credential-health-service.test.ts +252 -3
- package/src/__tests__/credential-security-invariants.test.ts +6 -5
- package/src/__tests__/credential-vault-unit.test.ts +21 -21
- 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-page-surface.test.ts +2 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
- package/src/__tests__/email-html-renderer.test.ts +12 -0
- 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 +236 -0
- package/src/__tests__/gemini-provider.test.ts +104 -0
- package/src/__tests__/guardian-action-sweep.test.ts +3 -2
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +10 -7
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +5 -0
- package/src/__tests__/heartbeat-service.test.ts +5 -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 +6 -5
- 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__/init-feature-flag-overrides.test.ts +5 -6
- 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__/list-messages-tool-merge.test.ts +70 -11
- package/src/__tests__/llm-context-normalization.test.ts +42 -0
- 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 +408 -9
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/llm-usage-store.test.ts +66 -0
- package/src/__tests__/logger.test.ts +89 -0
- package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
- package/src/__tests__/mcp-abort-signal.test.ts +16 -2
- package/src/__tests__/mcp-client-auth.test.ts +14 -0
- package/src/__tests__/media-generate-image.test.ts +31 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
- 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 +4 -6
- package/src/__tests__/native-web-search.test.ts +30 -2
- package/src/__tests__/notification-deep-link.test.ts +62 -0
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- 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 +4 -3
- package/src/__tests__/openai-provider.test.ts +54 -9
- package/src/__tests__/openai-responses-provider.test.ts +176 -14
- package/src/__tests__/openrouter-provider-only.test.ts +27 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
- package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
- package/src/__tests__/persistence-pipeline.test.ts +139 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
- package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
- package/src/__tests__/platform.test.ts +2 -2
- package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
- package/src/__tests__/plugin-bootstrap.test.ts +11 -13
- package/src/__tests__/plugin-tool-contribution.test.ts +50 -40
- 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 +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__/prune-jobs-changes-parser.test.ts +61 -0
- 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 +84 -84
- package/src/__tests__/relay-server.test.ts +10 -10
- package/src/__tests__/require-fresh-approval.test.ts +2 -2
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
- 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__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
- package/src/__tests__/skill-feature-flags.test.ts +16 -18
- package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
- package/src/__tests__/skill-projection-feature-flag.test.ts +48 -37
- package/src/__tests__/skill-projection.benchmark.test.ts +7 -13
- package/src/__tests__/skill-tool-factory.test.ts +97 -96
- 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 +6 -5
- 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 +2 -0
- package/src/__tests__/sync-message-contract.test.ts +59 -0
- package/src/__tests__/system-prompt.test.ts +183 -131
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/test-preload-verifier.ts +68 -0
- package/src/__tests__/test-preload.ts +32 -39
- 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 +35 -12
- package/src/__tests__/tool-executor.test.ts +64 -72
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
- package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -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 +3 -2
- package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
- package/src/__tests__/usage-routes.test.ts +3 -0
- package/src/__tests__/validate-input.test.ts +381 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +3 -2
- 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-git-service.test.ts +6 -5
- package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
- 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/__tests__/prepare-agent-env.test.ts +146 -0
- package/src/acp/prepare-agent-env.ts +78 -0
- package/src/acp/session-manager.ts +6 -7
- package/src/agent/loop.ts +88 -0
- package/src/api/README.md +127 -0
- 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/api/events/relationship-state-updated.ts +25 -0
- package/src/api/events/tool-use-start.ts +32 -0
- package/src/api/index.ts +129 -0
- package/src/api/package.json +10 -0
- 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 +868 -0
- 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 +24 -0
- 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__/browser.test.ts +23 -5
- package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -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 +1 -0
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
- package/src/cli/commands/__tests__/notifications.test.ts +184 -40
- package/src/cli/commands/browser.ts +247 -0
- package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
- package/src/cli/commands/channels/index.ts +229 -0
- package/src/cli/commands/domain.ts +91 -41
- 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 +176 -1
- package/src/cli/commands/memory-v3-render.ts +491 -0
- package/src/cli/commands/memory-v3.ts +567 -0
- package/src/cli/commands/notifications.ts +365 -55
- package/src/cli/lib/open-browser.ts +7 -2
- package/src/cli/program.ts +4 -0
- package/src/config/assistant-feature-flags.ts +39 -46
- package/src/config/bundled-skills/document-editor/SKILL.md +16 -3
- package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
- package/src/config/bundled-skills/document-editor/tools/document-open.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/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 +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/bundled-tool-registry.ts +2 -0
- package/src/config/call-site-defaults.ts +8 -7
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +33 -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 +228 -1
- package/src/config/schemas/call-site-catalog.ts +21 -7
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +102 -2
- package/src/config/schemas/memory-v2.ts +272 -0
- package/src/config/schemas/memory.ts +2 -1
- package/src/config/schemas/services.ts +6 -2
- package/src/config/seed-inference-profiles.ts +36 -16
- package/src/context/compactor.ts +52 -0
- package/src/context/token-estimator.ts +10 -5
- package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
- package/src/conversations/message-consolidation.ts +404 -0
- 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 +2 -3
- 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 +390 -80
- package/src/daemon/conversation-agent-loop.ts +244 -90
- package/src/daemon/conversation-error.ts +64 -6
- package/src/daemon/conversation-lifecycle.ts +27 -22
- package/src/daemon/conversation-messaging.ts +84 -43
- package/src/daemon/conversation-process.ts +74 -37
- package/src/daemon/conversation-runtime-assembly.ts +38 -17
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-surfaces.ts +69 -34
- package/src/daemon/conversation-tool-setup.ts +77 -32
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +40 -75
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/daemon-skill-host.ts +9 -2
- package/src/daemon/disk-pressure-guard.ts +39 -29
- package/src/daemon/first-greeting.ts +31 -13
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +11 -3
- package/src/daemon/handlers/shared.ts +6 -1
- package/src/daemon/host-browser-proxy.ts +5 -5
- package/src/daemon/host-cu-proxy.ts +4 -4
- package/src/daemon/host-file-proxy.ts +4 -4
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/host-transfer-proxy.ts +10 -10
- package/src/daemon/lifecycle.ts +29 -26
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/meet-manifest-loader.ts +11 -24
- package/src/daemon/message-types/conversations.ts +22 -27
- package/src/daemon/message-types/document-comments.ts +8 -44
- package/src/daemon/message-types/home.ts +2 -14
- package/src/daemon/message-types/integrations.ts +2 -7
- package/src/daemon/message-types/messages.ts +25 -48
- package/src/daemon/message-types/subagents.ts +6 -0
- package/src/daemon/message-types/sync.ts +14 -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/shutdown-handlers.ts +24 -5
- package/src/daemon/switch-inference-profile-tool.ts +62 -0
- package/src/daemon/tool-setup-types.ts +7 -0
- 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 +30 -1
- 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/home-greeting.ts +0 -9
- package/src/home/suggested-prompts.ts +27 -154
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/gateway-client.test.ts +4 -1
- package/src/ipc/gateway-flag-listener.ts +123 -0
- 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 +35 -40
- 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 +242 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
- 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 +8 -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/auto-analysis-enqueue.ts +5 -1
- package/src/memory/conversation-attention-store.ts +17 -3
- package/src/memory/conversation-crud.ts +423 -182
- 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-connection.ts +29 -19
- package/src/memory/db-init.ts +14 -0
- package/src/memory/db-maintenance.ts +30 -21
- 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/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/graph/retriever.test.ts +3 -3
- 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/job-handlers/embedding.test.ts +3 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
- package/src/memory/jobs/embed-pkb-file.ts +6 -1
- package/src/memory/jobs-store.ts +14 -0
- package/src/memory/jobs-worker.ts +66 -22
- package/src/memory/llm-request-log-source-clickhouse.ts +122 -2
- package/src/memory/llm-request-log-source-local.ts +31 -0
- package/src/memory/llm-request-log-source.ts +40 -2
- package/src/memory/llm-request-log-store.ts +228 -1
- package/src/memory/llm-usage-store.ts +24 -0
- package/src/memory/memory-retrospective-enqueue.ts +8 -1
- package/src/memory/memory-retrospective-job.ts +5 -0
- package/src/memory/memory-v2-activation-log-store.ts +110 -7
- 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/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 +19 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/schema/conversations.ts +10 -2
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/schema/infrastructure.ts +21 -0
- package/src/memory/tool-usage-store.ts +36 -8
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- 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 +83 -0
- package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +230 -0
- package/src/memory/v2/__tests__/harness-runner.test.ts +135 -0
- package/src/memory/v2/__tests__/injection.test.ts +127 -98
- package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
- package/src/memory/v2/__tests__/router.test.ts +171 -3
- package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
- package/src/memory/v2/harness/compare.ts +57 -0
- package/src/memory/v2/harness/metrics.ts +128 -0
- package/src/memory/v2/harness/oracle.ts +145 -0
- package/src/memory/v2/harness/replay-input.ts +240 -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 +112 -0
- package/src/memory/v2/harness/trace.ts +64 -0
- package/src/memory/v2/injection.ts +21 -15
- package/src/memory/v2/prompts/router.ts +26 -1
- package/src/memory/v2/qdrant.ts +14 -2
- package/src/memory/v2/router.ts +171 -18
- package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +466 -0
- package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
- package/src/memory/v3/__tests__/edges.test.ts +706 -0
- package/src/memory/v3/__tests__/filter.test.ts +560 -0
- package/src/memory/v3/__tests__/gate.test.ts +637 -0
- package/src/memory/v3/__tests__/index-composition.test.ts +291 -0
- package/src/memory/v3/__tests__/loop.test.ts +775 -0
- package/src/memory/v3/__tests__/retriever.test.ts +226 -0
- package/src/memory/v3/__tests__/scouts.test.ts +489 -0
- package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +398 -0
- package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
- package/src/memory/v3/__tests__/traversal.test.ts +508 -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 +784 -0
- package/src/memory/v3/__tests__/validate.test.ts +277 -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/coretrieval-seed.ts +240 -0
- package/src/memory/v3/edge-learning-job.ts +160 -0
- package/src/memory/v3/edges.ts +286 -0
- package/src/memory/v3/filter.ts +286 -0
- package/src/memory/v3/gate.ts +349 -0
- package/src/memory/v3/index-composition.ts +126 -0
- package/src/memory/v3/llm-capture.ts +46 -0
- package/src/memory/v3/loop.ts +430 -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 +431 -0
- package/src/memory/v3/shadow-diff.ts +287 -0
- package/src/memory/v3/shadow-middleware.ts +347 -0
- package/src/memory/v3/traversal.ts +211 -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 +356 -0
- package/src/memory/v3/types.ts +65 -0
- package/src/memory/v3/validate.ts +323 -0
- 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/macos.ts +18 -1
- package/src/notifications/adapters/platform.ts +1 -1
- 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/decision-engine.ts +1 -4
- 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 +40 -50
- 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/permissions/prompter.ts +3 -3
- package/src/permissions/question-prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +2 -2
- 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/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 +20 -19
- package/src/plugins/defaults/persistence.ts +25 -6
- package/src/plugins/external-plugin-loader.ts +5 -68
- package/src/plugins/types.ts +68 -29
- package/src/proactive-artifact/aux-message-injector.ts +17 -4
- package/src/proactive-artifact/job.test.ts +1 -0
- package/src/prompts/__tests__/system-prompt.test.ts +4 -4
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
- package/src/prompts/persona-resolver.ts +36 -21
- package/src/prompts/sections.ts +39 -7
- package/src/prompts/system-prompt.ts +84 -221
- package/src/prompts/template-detection.ts +10 -4
- package/src/prompts/templates/BOOTSTRAP.md +9 -13
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/prompts/templates/system-sections.ts +230 -8
- package/src/providers/__tests__/connection-model-compat.test.ts +233 -0
- package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
- package/src/providers/__tests__/retry-callsite.test.ts +85 -5
- package/src/providers/anthropic/client.ts +32 -66
- package/src/providers/call-site-routing.ts +42 -6
- package/src/providers/connection-model-compat.ts +61 -0
- package/src/providers/connection-resolution.ts +47 -14
- package/src/providers/fireworks/client.ts +1 -0
- package/src/providers/gemini/client.ts +70 -6
- 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/adapter-factory.ts +3 -0
- 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/minimax/client.ts +106 -0
- package/src/providers/model-catalog.ts +78 -1
- package/src/providers/model-intents.ts +4 -4
- 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 +116 -15
- package/src/providers/openai/codex-models.ts +20 -0
- package/src/providers/openai/responses-provider.ts +87 -30
- package/src/providers/openrouter/client.ts +13 -8
- package/src/providers/provider-send-message.ts +20 -5
- package/src/providers/registry.ts +48 -8
- package/src/providers/retry.ts +50 -7
- package/src/providers/search-provider-catalog.ts +17 -9
- package/src/providers/thinking-config.ts +26 -1
- package/src/providers/types.ts +9 -0
- package/src/providers/usage-tracking.ts +2 -0
- package/src/runtime/AGENTS.md +2 -2
- 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/agent-wake.ts +1 -0
- package/src/runtime/assistant-event-hub.ts +76 -6
- package/src/runtime/auth/route-policy.ts +46 -0
- package/src/runtime/btw-sidechain.ts +0 -6
- 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/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +12 -4
- package/src/runtime/pending-interactions.ts +0 -1
- 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 +204 -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 +76 -9
- package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -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/acp-routes.test.ts +255 -6
- package/src/runtime/routes/acp-routes.ts +8 -1
- package/src/runtime/routes/app-management-routes.ts +111 -4
- package/src/runtime/routes/avatar-routes.ts +10 -10
- package/src/runtime/routes/background-wake-routes.ts +356 -0
- package/src/runtime/routes/browser-tabs-routes.ts +200 -0
- package/src/runtime/routes/btw-routes.ts +4 -10
- package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
- package/src/runtime/routes/conversation-list-routes.ts +159 -4
- package/src/runtime/routes/conversation-management-routes.ts +108 -26
- package/src/runtime/routes/conversation-query-routes.ts +200 -44
- package/src/runtime/routes/conversation-routes.ts +409 -521
- package/src/runtime/routes/conversation-starter-routes.ts +6 -3
- package/src/runtime/routes/conversations-import-routes.ts +19 -6
- package/src/runtime/routes/disk-pressure-routes.ts +1 -1
- package/src/runtime/routes/documents-routes.ts +10 -1
- 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 +35 -8
- package/src/runtime/routes/home-feed-routes.ts +129 -0
- package/src/runtime/routes/host-browser-routes.ts +10 -2
- package/src/runtime/routes/host-cu-routes.ts +2 -2
- 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/acl-enforcement.ts +96 -3
- 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 +10 -0
- 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 +5 -26
- package/src/runtime/routes/integrations/vercel.ts +15 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
- package/src/runtime/routes/llm-context-normalization.ts +7 -2
- package/src/runtime/routes/memory-item-routes.ts +8 -3
- package/src/runtime/routes/memory-v2-routes.ts +215 -5
- package/src/runtime/routes/memory-v3-routes.ts +474 -0
- package/src/runtime/routes/migration-routes.ts +32 -28
- package/src/runtime/routes/notification-routes.ts +63 -1
- package/src/runtime/routes/oauth-commands-routes.ts +6 -1
- package/src/runtime/routes/plugins-routes.ts +337 -0
- package/src/runtime/routes/rename-conversation-routes.ts +6 -2
- 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 +5 -4
- 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/routes/workspace-routes.ts +25 -10
- 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 +106 -38
- package/src/runtime/sync/sync-publisher.test.ts +49 -0
- package/src/runtime/sync/sync-publisher.ts +2 -1
- package/src/runtime/tool-grant-request-helper.ts +1 -0
- package/src/runtime/verification-outbound-actions.ts +73 -1
- 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/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 +36 -28
- 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__/browser-execution-acquire.test.ts +2 -8
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +70 -0
- package/src/tools/browser/browser-execution.ts +16 -3
- package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
- package/src/tools/browser/cdp-client/factory.ts +100 -17
- package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
- package/src/tools/browser/cdp-client/types.ts +65 -0
- package/src/tools/browser/pinned-tabs.ts +96 -40
- package/src/tools/computer-use/definitions.ts +282 -336
- 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-tool.ts +189 -7
- package/src/tools/execution-target.ts +18 -23
- package/src/tools/executor.ts +24 -56
- 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.test.ts +1 -0
- package/src/tools/host-filesystem/edit.ts +3 -9
- package/src/tools/host-filesystem/read.test.ts +1 -0
- package/src/tools/host-filesystem/read.ts +3 -9
- package/src/tools/host-filesystem/transfer.test.ts +31 -6
- package/src/tools/host-filesystem/transfer.ts +3 -9
- package/src/tools/host-filesystem/write.test.ts +1 -0
- 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 -10
- package/src/tools/memory/register.test.ts +1 -1
- package/src/tools/memory/register.ts +4 -9
- 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-fetch.ts +3 -9
- package/src/tools/network/web-search.ts +224 -76
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +150 -123
- package/src/tools/schedule/create.ts +1 -1
- 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 +18 -44
- package/src/tools/subagent/notify-parent.ts +3 -9
- package/src/tools/subagent/spawn.ts +3 -0
- package/src/tools/system/request-permission.ts +3 -9
- package/src/tools/terminal/shell.ts +3 -9
- package/src/tools/tool-approval-handler.ts +10 -4
- package/src/tools/tool-defaults.ts +94 -0
- package/src/tools/tool-name-aliases.ts +72 -14
- package/src/tools/types.ts +32 -101
- package/src/tools/ui-surface/definitions.ts +104 -108
- package/src/types/onboarding-context.ts +6 -0
- package/src/usage/attribution.ts +32 -1
- package/src/usage/pricing.ts +23 -0
- package/src/usage/types.ts +12 -0
- package/src/util/browser.ts +7 -2
- package/src/util/logger.ts +16 -7
- package/src/util/platform.ts +7 -2
- package/src/util/sqlite3-runtime.ts +65 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
- package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
- 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 +6 -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/daemon/query-complexity-router.ts +0 -75
- package/src/prompts/cache-boundary.ts +0 -8
|
@@ -24,7 +24,11 @@ import type { ChannelId, InterfaceId } from "../channels/types.js";
|
|
|
24
24
|
import { parseChannelId, parseInterfaceId } from "../channels/types.js";
|
|
25
25
|
import { CHANNEL_IDS, isChannelId } from "../channels/types.js";
|
|
26
26
|
import { getConfig } from "../config/loader.js";
|
|
27
|
+
import { findDisplayTurnEndIndex } from "../conversations/message-consolidation.js";
|
|
28
|
+
import { conversationMetadataSyncTag } from "../daemon/message-types/sync.js";
|
|
27
29
|
import type { TrustContext } from "../daemon/trust-context.js";
|
|
30
|
+
import { clearAllConversationIds } from "../home/feed-writer.js";
|
|
31
|
+
import { publishSyncInvalidation } from "../runtime/sync/sync-publisher.js";
|
|
28
32
|
import { UserError } from "../util/errors.js";
|
|
29
33
|
import { safeParseRecord } from "../util/json.js";
|
|
30
34
|
import { getLogger } from "../util/logger.js";
|
|
@@ -47,6 +51,7 @@ import {
|
|
|
47
51
|
} from "./conversation-disk-view.js";
|
|
48
52
|
import { ensureDisplayOrderMigration } from "./conversation-display-order-migration.js";
|
|
49
53
|
import { ensureGroupMigration } from "./conversation-group-migration.js";
|
|
54
|
+
import { runAsyncSqlite } from "./db-async-query.js";
|
|
50
55
|
import { getDb, getSqliteFrom } from "./db-connection.js";
|
|
51
56
|
import { forkGraphMemoryState } from "./graph/graph-memory-state-store.js";
|
|
52
57
|
import { indexMessageNow } from "./indexer.js";
|
|
@@ -179,6 +184,24 @@ export function provenanceFromTrustContext(
|
|
|
179
184
|
};
|
|
180
185
|
}
|
|
181
186
|
|
|
187
|
+
/** Extract image file paths from resolved attachments for message metadata. */
|
|
188
|
+
export function extractImageSourcePaths(
|
|
189
|
+
attachments: ReadonlyArray<{
|
|
190
|
+
filename: string;
|
|
191
|
+
mimeType: string;
|
|
192
|
+
filePath?: string;
|
|
193
|
+
}>,
|
|
194
|
+
): Record<string, string> | undefined {
|
|
195
|
+
const paths: Record<string, string> = {};
|
|
196
|
+
for (let i = 0; i < attachments.length; i++) {
|
|
197
|
+
const a = attachments[i];
|
|
198
|
+
if (a.filePath && a.mimeType.toLowerCase().startsWith("image/")) {
|
|
199
|
+
paths[`${i}:${a.filename}`] = a.filePath;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return Object.keys(paths).length > 0 ? paths : undefined;
|
|
203
|
+
}
|
|
204
|
+
|
|
182
205
|
export interface ConversationRow {
|
|
183
206
|
id: string;
|
|
184
207
|
title: string | null;
|
|
@@ -190,7 +213,7 @@ export interface ConversationRow {
|
|
|
190
213
|
contextSummary: string | null;
|
|
191
214
|
contextCompactedMessageCount: number;
|
|
192
215
|
contextCompactedAt: number | null;
|
|
193
|
-
|
|
216
|
+
historyStrippedAt: number | null;
|
|
194
217
|
slackContextCompactionWatermarkTs: string | null;
|
|
195
218
|
slackContextCompactionWatermarkAt: number | null;
|
|
196
219
|
conversationType: string;
|
|
@@ -224,7 +247,7 @@ export const parseConversation = createRowMapper<
|
|
|
224
247
|
contextSummary: "contextSummary",
|
|
225
248
|
contextCompactedMessageCount: "contextCompactedMessageCount",
|
|
226
249
|
contextCompactedAt: "contextCompactedAt",
|
|
227
|
-
|
|
250
|
+
historyStrippedAt: "historyStrippedAt",
|
|
228
251
|
slackContextCompactionWatermarkTs: "slackContextCompactionWatermarkTs",
|
|
229
252
|
slackContextCompactionWatermarkAt: "slackContextCompactionWatermarkAt",
|
|
230
253
|
conversationType: "conversationType",
|
|
@@ -244,6 +267,9 @@ export const parseConversation = createRowMapper<
|
|
|
244
267
|
lastNotifiedInferenceProfile: "lastNotifiedInferenceProfile",
|
|
245
268
|
});
|
|
246
269
|
|
|
270
|
+
/** Allowed values for the `role` column on `messages`. */
|
|
271
|
+
export type MessageRole = "user" | "assistant" | "system";
|
|
272
|
+
|
|
247
273
|
export interface MessageRow {
|
|
248
274
|
id: string;
|
|
249
275
|
conversationId: string;
|
|
@@ -278,6 +304,193 @@ function monotonicNow(): number {
|
|
|
278
304
|
return lastTimestamp;
|
|
279
305
|
}
|
|
280
306
|
|
|
307
|
+
// ── insertMessageCore ─────────────────────────────────────────────────
|
|
308
|
+
|
|
309
|
+
/** Shape returned by {@link insertMessageCore} and its public wrappers. */
|
|
310
|
+
interface InsertedMessage {
|
|
311
|
+
id: string;
|
|
312
|
+
conversationId: string;
|
|
313
|
+
role: MessageRole;
|
|
314
|
+
content: string;
|
|
315
|
+
createdAt: number;
|
|
316
|
+
metadata?: string;
|
|
317
|
+
clientMessageId?: string;
|
|
318
|
+
deduplicated: boolean;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
interface InsertMessageCoreParams {
|
|
322
|
+
conversationId: string;
|
|
323
|
+
role: MessageRole;
|
|
324
|
+
content: string;
|
|
325
|
+
metadata?: Record<string, unknown>;
|
|
326
|
+
clientMessageId?: string;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Core message persistence primitive shared by {@link addMessage} and
|
|
331
|
+
* {@link reserveMessage}.
|
|
332
|
+
*
|
|
333
|
+
* Inserts a message row inside a transaction that atomically bumps the
|
|
334
|
+
* parent conversation's `updatedAt` / `lastMessageAt` timestamps and
|
|
335
|
+
* conditionally sets the conversation's `originChannel` when the first
|
|
336
|
+
* channel-originated message arrives.
|
|
337
|
+
*
|
|
338
|
+
* When a `clientMessageId` is provided the insert runs inside a
|
|
339
|
+
* SAVEPOINT. If the partial unique index on
|
|
340
|
+
* `(conversation_id, client_message_id)` raises
|
|
341
|
+
* `SQLITE_CONSTRAINT_UNIQUE`, the SAVEPOINT is rolled back, the
|
|
342
|
+
* existing row is fetched, and returned with `deduplicated: true`.
|
|
343
|
+
* This makes the operation idempotent for client-generated
|
|
344
|
+
* correlation nonces.
|
|
345
|
+
*
|
|
346
|
+
* Retries up to 3 times on `SQLITE_BUSY*` / `SQLITE_IOERR*` to handle
|
|
347
|
+
* WAL contention. The timestamp is recomputed each attempt so a late
|
|
348
|
+
* retry doesn't persist a stale `updatedAt`.
|
|
349
|
+
*/
|
|
350
|
+
async function insertMessageCore(
|
|
351
|
+
params: InsertMessageCoreParams,
|
|
352
|
+
): Promise<InsertedMessage> {
|
|
353
|
+
const { conversationId, role, content, metadata, clientMessageId } = params;
|
|
354
|
+
const db = getDb();
|
|
355
|
+
const messageId = uuid();
|
|
356
|
+
|
|
357
|
+
if (metadata) {
|
|
358
|
+
const result = messageMetadataSchema.safeParse(metadata);
|
|
359
|
+
if (!result.success) {
|
|
360
|
+
log.warn(
|
|
361
|
+
{ conversationId, messageId, issues: result.error.issues },
|
|
362
|
+
"Invalid message metadata, storing as-is",
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const metadataStr = metadata ? JSON.stringify(metadata) : undefined;
|
|
368
|
+
const originChannelCandidate =
|
|
369
|
+
metadata && isChannelId(metadata.userMessageChannel)
|
|
370
|
+
? metadata.userMessageChannel
|
|
371
|
+
: null;
|
|
372
|
+
|
|
373
|
+
const MAX_RETRIES = 3;
|
|
374
|
+
let now!: number;
|
|
375
|
+
for (let attempt = 0; ; attempt++) {
|
|
376
|
+
now = monotonicNow();
|
|
377
|
+
try {
|
|
378
|
+
const values = {
|
|
379
|
+
id: messageId,
|
|
380
|
+
conversationId,
|
|
381
|
+
role,
|
|
382
|
+
content,
|
|
383
|
+
createdAt: now,
|
|
384
|
+
...(metadataStr ? { metadata: metadataStr } : {}),
|
|
385
|
+
...(clientMessageId ? { clientMessageId } : {}),
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
if (clientMessageId) {
|
|
389
|
+
// Idempotent insert: skip silently if this clientMessageId was
|
|
390
|
+
// already persisted for the conversation.
|
|
391
|
+
const raw = getSqliteFrom(db);
|
|
392
|
+
raw.exec("SAVEPOINT insert_msg");
|
|
393
|
+
try {
|
|
394
|
+
db.insert(messages).values(values).run();
|
|
395
|
+
if (originChannelCandidate) {
|
|
396
|
+
db.update(conversations)
|
|
397
|
+
.set({ originChannel: originChannelCandidate })
|
|
398
|
+
.where(
|
|
399
|
+
and(
|
|
400
|
+
eq(conversations.id, conversationId),
|
|
401
|
+
isNull(conversations.originChannel),
|
|
402
|
+
),
|
|
403
|
+
)
|
|
404
|
+
.run();
|
|
405
|
+
}
|
|
406
|
+
db.update(conversations)
|
|
407
|
+
.set({ updatedAt: now, lastMessageAt: now })
|
|
408
|
+
.where(eq(conversations.id, conversationId))
|
|
409
|
+
.run();
|
|
410
|
+
raw.exec("RELEASE insert_msg");
|
|
411
|
+
} catch (insertErr) {
|
|
412
|
+
raw.exec("ROLLBACK TO insert_msg");
|
|
413
|
+
raw.exec("RELEASE insert_msg");
|
|
414
|
+
const code = (insertErr as { code?: string }).code ?? "";
|
|
415
|
+
if (code === "SQLITE_CONSTRAINT_UNIQUE") {
|
|
416
|
+
// Duplicate clientMessageId — return the existing row.
|
|
417
|
+
const existing = db
|
|
418
|
+
.select()
|
|
419
|
+
.from(messages)
|
|
420
|
+
.where(
|
|
421
|
+
and(
|
|
422
|
+
eq(messages.conversationId, conversationId),
|
|
423
|
+
eq(messages.clientMessageId, clientMessageId),
|
|
424
|
+
),
|
|
425
|
+
)
|
|
426
|
+
.get();
|
|
427
|
+
if (existing) {
|
|
428
|
+
return {
|
|
429
|
+
id: existing.id,
|
|
430
|
+
conversationId: existing.conversationId,
|
|
431
|
+
role: existing.role as MessageRole,
|
|
432
|
+
content: existing.content,
|
|
433
|
+
createdAt: existing.createdAt,
|
|
434
|
+
...(existing.metadata ? { metadata: existing.metadata } : {}),
|
|
435
|
+
clientMessageId: existing.clientMessageId ?? undefined,
|
|
436
|
+
deduplicated: true,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
throw insertErr;
|
|
441
|
+
}
|
|
442
|
+
} else {
|
|
443
|
+
// No clientMessageId — standard insert inside a transaction.
|
|
444
|
+
db.transaction((tx) => {
|
|
445
|
+
tx.insert(messages).values(values).run();
|
|
446
|
+
if (originChannelCandidate) {
|
|
447
|
+
tx.update(conversations)
|
|
448
|
+
.set({ originChannel: originChannelCandidate })
|
|
449
|
+
.where(
|
|
450
|
+
and(
|
|
451
|
+
eq(conversations.id, conversationId),
|
|
452
|
+
isNull(conversations.originChannel),
|
|
453
|
+
),
|
|
454
|
+
)
|
|
455
|
+
.run();
|
|
456
|
+
}
|
|
457
|
+
tx.update(conversations)
|
|
458
|
+
.set({ updatedAt: now, lastMessageAt: now })
|
|
459
|
+
.where(eq(conversations.id, conversationId))
|
|
460
|
+
.run();
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
break;
|
|
464
|
+
} catch (err) {
|
|
465
|
+
const errCode = (err as { code?: string }).code ?? "";
|
|
466
|
+
if (
|
|
467
|
+
attempt < MAX_RETRIES &&
|
|
468
|
+
(errCode.startsWith("SQLITE_BUSY") ||
|
|
469
|
+
errCode.startsWith("SQLITE_IOERR"))
|
|
470
|
+
) {
|
|
471
|
+
log.warn(
|
|
472
|
+
{ attempt, conversationId, code: errCode },
|
|
473
|
+
"insertMessageCore: transient SQLite error, retrying",
|
|
474
|
+
);
|
|
475
|
+
await Bun.sleep(50 * (attempt + 1));
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
throw err;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return {
|
|
483
|
+
id: messageId,
|
|
484
|
+
conversationId,
|
|
485
|
+
role,
|
|
486
|
+
content,
|
|
487
|
+
createdAt: now,
|
|
488
|
+
...(metadataStr ? { metadata: metadataStr } : {}),
|
|
489
|
+
...(clientMessageId ? { clientMessageId } : {}),
|
|
490
|
+
deduplicated: false,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
281
494
|
export function createConversation(
|
|
282
495
|
titleOrOpts?:
|
|
283
496
|
| string
|
|
@@ -574,6 +787,20 @@ export function forkConversation(params: {
|
|
|
574
787
|
throw new UserError(`Conversation ${conversationId} not found`);
|
|
575
788
|
}
|
|
576
789
|
const sourceMessages = getMessages(conversationId);
|
|
790
|
+
if (throughMessageId != null) {
|
|
791
|
+
// `getMessages` orders by `createdAt` only; when rows share an identical
|
|
792
|
+
// millisecond timestamp the tie order is unspecified. Callers that pin the
|
|
793
|
+
// fork to a cutoff choose it from a `(createdAt, id)` cursor (e.g. the
|
|
794
|
+
// memory-retrospective job, via `getMessagesAfter`), so slicing through
|
|
795
|
+
// `throughMessageId` under the unstable order could include same-timestamp
|
|
796
|
+
// siblings the cursor considers *after* the cutoff (reprocessed next run)
|
|
797
|
+
// or exclude ones it considers *before* it (skipped forever). Re-sort on
|
|
798
|
+
// `(createdAt, id)` so the slice agrees with the cutoff. The unpinned full
|
|
799
|
+
// fork copies every row regardless of order, so it keeps source order.
|
|
800
|
+
sourceMessages.sort(
|
|
801
|
+
(a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id),
|
|
802
|
+
);
|
|
803
|
+
}
|
|
577
804
|
|
|
578
805
|
if (sourceMessages.length === 0) {
|
|
579
806
|
throw new UserError(
|
|
@@ -581,17 +808,30 @@ export function forkConversation(params: {
|
|
|
581
808
|
);
|
|
582
809
|
}
|
|
583
810
|
|
|
584
|
-
const
|
|
811
|
+
const initialBoundaryIndex =
|
|
585
812
|
throughMessageId == null
|
|
586
813
|
? sourceMessages.length - 1
|
|
587
814
|
: sourceMessages.findIndex((message) => message.id === throughMessageId);
|
|
588
815
|
|
|
589
|
-
if (throughMessageId != null &&
|
|
816
|
+
if (throughMessageId != null && initialBoundaryIndex === -1) {
|
|
590
817
|
throw new UserError(
|
|
591
818
|
`Message ${throughMessageId} does not belong to conversation ${conversationId}`,
|
|
592
819
|
);
|
|
593
820
|
}
|
|
594
821
|
|
|
822
|
+
// Extend the boundary to cover the full display turn the client
|
|
823
|
+
// addressed. The read-path collapses each assistant turn across
|
|
824
|
+
// multiple DB rows — consecutive assistant rows AND tool-result-only
|
|
825
|
+
// user rows between them — so "fork through message X" semantically
|
|
826
|
+
// means "fork through the entire display turn containing X" no matter
|
|
827
|
+
// which DB row in the cluster the client supplied. Single source of
|
|
828
|
+
// truth is `findDisplayTurnEndIndex`, shared with the read path so
|
|
829
|
+
// both stay in sync.
|
|
830
|
+
const copyBoundaryIndex = findDisplayTurnEndIndex(
|
|
831
|
+
sourceMessages,
|
|
832
|
+
initialBoundaryIndex,
|
|
833
|
+
);
|
|
834
|
+
|
|
595
835
|
const visibleWindowStartIndex = Math.max(
|
|
596
836
|
0,
|
|
597
837
|
Math.min(
|
|
@@ -607,15 +847,16 @@ export function forkConversation(params: {
|
|
|
607
847
|
? sourceMessages.slice(0, copyBoundaryIndex + 1)
|
|
608
848
|
: ([] as MessageRow[]);
|
|
609
849
|
|
|
610
|
-
// Inherit
|
|
611
|
-
//
|
|
612
|
-
//
|
|
613
|
-
|
|
850
|
+
// Inherit the history-strip marker only when the fork boundary is at-or-
|
|
851
|
+
// after the strip event. Pre-strip forks branch from history that pre-
|
|
852
|
+
// dates the strip, so the marker would be a no-op and is misleading to
|
|
853
|
+
// copy.
|
|
854
|
+
const sourceHistoryStrippedAt = sourceConversation.historyStrippedAt ?? null;
|
|
614
855
|
const boundaryMessageCreatedAt = messagesToCopy.at(-1)?.createdAt ?? null;
|
|
615
|
-
const
|
|
616
|
-
|
|
856
|
+
const inheritsHistoryStrippedAt =
|
|
857
|
+
sourceHistoryStrippedAt != null &&
|
|
617
858
|
boundaryMessageCreatedAt != null &&
|
|
618
|
-
boundaryMessageCreatedAt >=
|
|
859
|
+
boundaryMessageCreatedAt >= sourceHistoryStrippedAt;
|
|
619
860
|
const forkParentMessageId = messagesToCopy.at(-1)?.id ?? null;
|
|
620
861
|
const forkTitle =
|
|
621
862
|
params.title ?? `${sourceConversation.title ?? "Untitled"} (Fork)`;
|
|
@@ -662,7 +903,9 @@ export function forkConversation(params: {
|
|
|
662
903
|
slackContextCompactionWatermarkAt: preserveSourceCompactionState
|
|
663
904
|
? sourceConversation.slackContextCompactionWatermarkAt
|
|
664
905
|
: null,
|
|
665
|
-
|
|
906
|
+
historyStrippedAt: inheritsHistoryStrippedAt
|
|
907
|
+
? sourceHistoryStrippedAt
|
|
908
|
+
: null,
|
|
666
909
|
inferenceProfile: sourceConversation.inferenceProfile,
|
|
667
910
|
})
|
|
668
911
|
.where(eq(conversations.id, fc.id))
|
|
@@ -952,92 +1195,36 @@ export function wipeConversation(id: string): WipeConversationResult {
|
|
|
952
1195
|
};
|
|
953
1196
|
}
|
|
954
1197
|
|
|
1198
|
+
/**
|
|
1199
|
+
* Persist a message and run post-insert side effects (memory indexing,
|
|
1200
|
+
* attention projection). Delegates the core insert + retry logic to
|
|
1201
|
+
* {@link insertMessageCore}.
|
|
1202
|
+
*
|
|
1203
|
+
* @param clientMessageId Optional client-generated nonce. When
|
|
1204
|
+
* provided, duplicate inserts for the same `(conversationId,
|
|
1205
|
+
* clientMessageId)` pair are silently skipped (idempotent).
|
|
1206
|
+
*/
|
|
955
1207
|
export async function addMessage(
|
|
956
1208
|
conversationId: string,
|
|
957
|
-
role:
|
|
1209
|
+
role: MessageRole,
|
|
958
1210
|
content: string,
|
|
959
1211
|
metadata?: Record<string, unknown>,
|
|
960
1212
|
opts?: { skipIndexing?: boolean },
|
|
1213
|
+
clientMessageId?: string,
|
|
961
1214
|
) {
|
|
962
|
-
const
|
|
963
|
-
const messageId = uuid();
|
|
964
|
-
|
|
965
|
-
if (metadata) {
|
|
966
|
-
const result = messageMetadataSchema.safeParse(metadata);
|
|
967
|
-
if (!result.success) {
|
|
968
|
-
log.warn(
|
|
969
|
-
{ conversationId, messageId, issues: result.error.issues },
|
|
970
|
-
"Invalid message metadata, storing as-is",
|
|
971
|
-
);
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
const metadataStr = metadata ? JSON.stringify(metadata) : undefined;
|
|
976
|
-
const originChannelCandidate =
|
|
977
|
-
metadata && isChannelId(metadata.userMessageChannel)
|
|
978
|
-
? metadata.userMessageChannel
|
|
979
|
-
: null;
|
|
980
|
-
// Wrap insert + updatedAt bump in a transaction so they're atomic.
|
|
981
|
-
// Retry on SQLITE_BUSY* and SQLITE_IOERR* — covers WAL contention variants
|
|
982
|
-
// (SQLITE_BUSY_SNAPSHOT, SQLITE_BUSY_RECOVERY) and transient disk I/O errors.
|
|
983
|
-
// Timestamp is recomputed each attempt so a late retry doesn't persist a stale updatedAt.
|
|
984
|
-
const MAX_RETRIES = 3;
|
|
985
|
-
let now!: number;
|
|
986
|
-
for (let attempt = 0; ; attempt++) {
|
|
987
|
-
now = monotonicNow();
|
|
988
|
-
try {
|
|
989
|
-
const values = {
|
|
990
|
-
id: messageId,
|
|
991
|
-
conversationId,
|
|
992
|
-
role,
|
|
993
|
-
content,
|
|
994
|
-
createdAt: now,
|
|
995
|
-
...(metadataStr ? { metadata: metadataStr } : {}),
|
|
996
|
-
};
|
|
997
|
-
db.transaction((tx) => {
|
|
998
|
-
tx.insert(messages).values(values).run();
|
|
999
|
-
if (originChannelCandidate) {
|
|
1000
|
-
tx.update(conversations)
|
|
1001
|
-
.set({ originChannel: originChannelCandidate })
|
|
1002
|
-
.where(
|
|
1003
|
-
and(
|
|
1004
|
-
eq(conversations.id, conversationId),
|
|
1005
|
-
isNull(conversations.originChannel),
|
|
1006
|
-
),
|
|
1007
|
-
)
|
|
1008
|
-
.run();
|
|
1009
|
-
}
|
|
1010
|
-
tx.update(conversations)
|
|
1011
|
-
.set({ updatedAt: now, lastMessageAt: now })
|
|
1012
|
-
.where(eq(conversations.id, conversationId))
|
|
1013
|
-
.run();
|
|
1014
|
-
});
|
|
1015
|
-
break;
|
|
1016
|
-
} catch (err) {
|
|
1017
|
-
const errCode = (err as { code?: string }).code ?? "";
|
|
1018
|
-
if (
|
|
1019
|
-
attempt < MAX_RETRIES &&
|
|
1020
|
-
(errCode.startsWith("SQLITE_BUSY") ||
|
|
1021
|
-
errCode.startsWith("SQLITE_IOERR"))
|
|
1022
|
-
) {
|
|
1023
|
-
log.warn(
|
|
1024
|
-
{ attempt, conversationId, code: errCode },
|
|
1025
|
-
"addMessage: transient SQLite error, retrying",
|
|
1026
|
-
);
|
|
1027
|
-
await Bun.sleep(50 * (attempt + 1));
|
|
1028
|
-
continue;
|
|
1029
|
-
}
|
|
1030
|
-
throw err;
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
const message = {
|
|
1034
|
-
id: messageId,
|
|
1215
|
+
const inserted = await insertMessageCore({
|
|
1035
1216
|
conversationId,
|
|
1036
1217
|
role,
|
|
1037
1218
|
content,
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
};
|
|
1219
|
+
metadata,
|
|
1220
|
+
clientMessageId,
|
|
1221
|
+
});
|
|
1222
|
+
|
|
1223
|
+
if (inserted.deduplicated) {
|
|
1224
|
+
return inserted;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
const message = inserted;
|
|
1041
1228
|
|
|
1042
1229
|
if (!opts?.skipIndexing) {
|
|
1043
1230
|
try {
|
|
@@ -1072,11 +1259,16 @@ export async function addMessage(
|
|
|
1072
1259
|
|
|
1073
1260
|
if (role === "assistant") {
|
|
1074
1261
|
try {
|
|
1075
|
-
projectAssistantMessage({
|
|
1262
|
+
const attentionStateChanged = projectAssistantMessage({
|
|
1076
1263
|
conversationId,
|
|
1077
1264
|
messageId: message.id,
|
|
1078
1265
|
messageAt: message.createdAt,
|
|
1079
1266
|
});
|
|
1267
|
+
if (attentionStateChanged) {
|
|
1268
|
+
void publishSyncInvalidation([
|
|
1269
|
+
conversationMetadataSyncTag(conversationId),
|
|
1270
|
+
]);
|
|
1271
|
+
}
|
|
1080
1272
|
} catch (err) {
|
|
1081
1273
|
log.warn(
|
|
1082
1274
|
{ err, conversationId, messageId: message.id },
|
|
@@ -1270,11 +1462,30 @@ export function hasMessages(conversationId: string): boolean {
|
|
|
1270
1462
|
interface PaginatedMessagesResult {
|
|
1271
1463
|
messages: MessageRow[];
|
|
1272
1464
|
hasMore: boolean;
|
|
1465
|
+
/**
|
|
1466
|
+
* Position of the last row scanned when the loop stops on
|
|
1467
|
+
* `PAGINATION_SCAN_CAP` rather than DB exhaustion. Callers derive their
|
|
1468
|
+
* client cursor from the visible page's oldest row, but a cap-truncated
|
|
1469
|
+
* page can be empty (a contiguous block of filtered-out rows longer than
|
|
1470
|
+
* the cap), leaving nothing to resume from. Surfacing the last scanned
|
|
1471
|
+
* `(createdAt, id)` lets the caller hand the client a cursor so it can
|
|
1472
|
+
* request the next window and keep draining instead of stalling.
|
|
1473
|
+
*/
|
|
1474
|
+
nextCursor?: { createdAt: number; id: string };
|
|
1273
1475
|
}
|
|
1274
1476
|
|
|
1275
1477
|
const PAGINATION_CHUNK_MIN = 50;
|
|
1276
1478
|
const PAGINATION_SCAN_CAP = 10_000;
|
|
1277
1479
|
|
|
1480
|
+
// Test-only override for PAGINATION_SCAN_CAP so tests can exercise the
|
|
1481
|
+
// cap-truncation branch with a small cap instead of seeding >10k rows (which
|
|
1482
|
+
// makes the suite slow and the post-test DELETE flaky under parallel CI load).
|
|
1483
|
+
// `undefined` restores the production cap.
|
|
1484
|
+
let paginationScanCapOverride: number | undefined;
|
|
1485
|
+
export function _setPaginationScanCapForTesting(cap: number | undefined): void {
|
|
1486
|
+
paginationScanCapOverride = cap;
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1278
1489
|
export function getMessagesPaginated(
|
|
1279
1490
|
conversationId: string,
|
|
1280
1491
|
limit: number | undefined,
|
|
@@ -1315,8 +1526,19 @@ export function getMessagesPaginated(
|
|
|
1315
1526
|
// row — otherwise a pathological filter against a huge conversation would
|
|
1316
1527
|
// tie up a connection for thousands of roundtrips.
|
|
1317
1528
|
let rowsScanned = 0;
|
|
1318
|
-
|
|
1319
|
-
|
|
1529
|
+
// Distinguish "stopped because we hit the scan cap" from "stopped because the
|
|
1530
|
+
// DB ran out of rows". On a cap-truncated stop there may be more visible rows
|
|
1531
|
+
// past the scanned window, so `hasMore` must stay true and we record the last
|
|
1532
|
+
// scanned position as a resume cursor (the visible page may be empty).
|
|
1533
|
+
let scanCapTruncated = false;
|
|
1534
|
+
let lastScanned: { createdAt: number; id: string } | undefined;
|
|
1535
|
+
const scanCap = paginationScanCapOverride ?? PAGINATION_SCAN_CAP;
|
|
1536
|
+
|
|
1537
|
+
while (visible.length < limit + 1) {
|
|
1538
|
+
if (rowsScanned >= scanCap) {
|
|
1539
|
+
scanCapTruncated = true;
|
|
1540
|
+
break;
|
|
1541
|
+
}
|
|
1320
1542
|
const cursorPredicate =
|
|
1321
1543
|
cursorCreatedAt === undefined
|
|
1322
1544
|
? undefined
|
|
@@ -1349,15 +1571,25 @@ export function getMessagesPaginated(
|
|
|
1349
1571
|
|
|
1350
1572
|
if (chunk.length < chunkSize) break;
|
|
1351
1573
|
const lastRow = chunk[chunk.length - 1];
|
|
1574
|
+
lastScanned = { createdAt: lastRow.createdAt, id: lastRow.id };
|
|
1352
1575
|
cursorCreatedAt = lastRow.createdAt;
|
|
1353
1576
|
cursorMessageId = lastRow.id;
|
|
1354
1577
|
}
|
|
1355
1578
|
|
|
1356
|
-
const
|
|
1357
|
-
|
|
1579
|
+
const filledPage = visible.length > limit;
|
|
1580
|
+
// A cap-truncated stop means the DB may still hold older visible rows past
|
|
1581
|
+
// the scanned window, so report `hasMore: true` to keep the client draining
|
|
1582
|
+
// — returning `false` here is the stall this loop exists to prevent.
|
|
1583
|
+
const hasMore = filledPage || scanCapTruncated;
|
|
1584
|
+
if (filledPage) visible.splice(limit);
|
|
1358
1585
|
visible.reverse();
|
|
1359
1586
|
|
|
1360
|
-
|
|
1587
|
+
// Only hand back a resume cursor when the cap (not DB exhaustion) cut the
|
|
1588
|
+
// search short; callers fall back to it when the visible page came back
|
|
1589
|
+
// empty and has no oldest row to anchor the next request.
|
|
1590
|
+
const nextCursor = scanCapTruncated ? lastScanned : undefined;
|
|
1591
|
+
|
|
1592
|
+
return { messages: visible, hasMore, nextCursor };
|
|
1361
1593
|
}
|
|
1362
1594
|
|
|
1363
1595
|
export function getLastUserTimestampBefore(
|
|
@@ -1451,14 +1683,14 @@ export function updateConversationContextWindow(
|
|
|
1451
1683
|
.run();
|
|
1452
1684
|
}
|
|
1453
1685
|
|
|
1454
|
-
export function
|
|
1686
|
+
export function setConversationHistoryStrippedAt(
|
|
1455
1687
|
id: string,
|
|
1456
|
-
|
|
1688
|
+
historyStrippedAt: number | null,
|
|
1457
1689
|
): void {
|
|
1458
1690
|
const db = getDb();
|
|
1459
1691
|
db.update(conversations)
|
|
1460
1692
|
.set({
|
|
1461
|
-
|
|
1693
|
+
historyStrippedAt,
|
|
1462
1694
|
updatedAt: Date.now(),
|
|
1463
1695
|
})
|
|
1464
1696
|
.where(eq(conversations.id, id))
|
|
@@ -1703,13 +1935,35 @@ export function setLastNotifiedInferenceProfile(
|
|
|
1703
1935
|
* Delete all conversations, messages, and related data (tool invocations,
|
|
1704
1936
|
* memory segments, etc.) from the daemon database.
|
|
1705
1937
|
* Returns { conversations, messages } counts.
|
|
1938
|
+
*
|
|
1939
|
+
* Each bulk DELETE is dispatched through {@link runAsyncSqlite}: when
|
|
1940
|
+
* the host has a `sqlite3` CLI it executes in a subprocess and the
|
|
1941
|
+
* daemon's main event loop stays responsive while large tables
|
|
1942
|
+
* (`llm_request_logs`, `tool_invocations`, etc.) are wiped. On hosts
|
|
1943
|
+
* without the CLI the abstraction falls back to in-process blocking
|
|
1944
|
+
* execution — the same behaviour the daemon had before.
|
|
1706
1945
|
*/
|
|
1707
|
-
export function clearAll(): {
|
|
1946
|
+
export async function clearAll(): Promise<{
|
|
1947
|
+
conversations: number;
|
|
1948
|
+
messages: number;
|
|
1949
|
+
}> {
|
|
1708
1950
|
const msgCount =
|
|
1709
1951
|
rawGet<{ c: number }>("SELECT COUNT(*) AS c FROM messages")?.c ?? 0;
|
|
1710
1952
|
const convCount =
|
|
1711
1953
|
rawGet<{ c: number }>("SELECT COUNT(*) AS c FROM conversations")?.c ?? 0;
|
|
1712
1954
|
|
|
1955
|
+
// Each DELETE goes through `runAsyncSqlite`. The original code threw
|
|
1956
|
+
// on rawExec failure; mirror that here by throwing when the async
|
|
1957
|
+
// result reports `ok: false`, so the route handler still returns 500.
|
|
1958
|
+
const runOrThrow = async (sql: string): Promise<void> => {
|
|
1959
|
+
const result = await runAsyncSqlite(sql);
|
|
1960
|
+
if (!result.ok) {
|
|
1961
|
+
throw new Error(
|
|
1962
|
+
`clearAll: \`${sql}\` failed (${result.backend}): ${result.error ?? "unknown"}`,
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1965
|
+
};
|
|
1966
|
+
|
|
1713
1967
|
// Delete in dependency order. Cascades handle memory_segments and
|
|
1714
1968
|
// tool_invocations, but we explicitly clear non-cascading memory
|
|
1715
1969
|
// tables too.
|
|
@@ -1719,22 +1973,21 @@ export function clearAll(): { conversations: number; messages: number } {
|
|
|
1719
1973
|
// triggers so that the subsequent base-table DELETEs don't also fail
|
|
1720
1974
|
// (SQLite triggers are atomic with the triggering statement, so a
|
|
1721
1975
|
// corrupted FTS table would roll back every base-table DELETE).
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1976
|
+
await runOrThrow("DELETE FROM memory_segments");
|
|
1977
|
+
await runOrThrow("DELETE FROM memory_summaries");
|
|
1978
|
+
await runOrThrow("DELETE FROM memory_embeddings");
|
|
1979
|
+
await runOrThrow("DELETE FROM memory_jobs");
|
|
1980
|
+
await runOrThrow("DELETE FROM memory_checkpoints");
|
|
1981
|
+
await runOrThrow("DELETE FROM llm_request_logs");
|
|
1982
|
+
await runOrThrow("DELETE FROM llm_usage_events");
|
|
1983
|
+
await runOrThrow("DELETE FROM message_attachments");
|
|
1984
|
+
await runOrThrow("DELETE FROM attachments");
|
|
1985
|
+
await runOrThrow("DELETE FROM tool_invocations");
|
|
1732
1986
|
let messagesFtsCorrupted = false;
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
} catch (err) {
|
|
1987
|
+
const ftsResult = await runAsyncSqlite("DELETE FROM messages_fts");
|
|
1988
|
+
if (!ftsResult.ok) {
|
|
1736
1989
|
log.warn(
|
|
1737
|
-
{
|
|
1990
|
+
{ error: ftsResult.error, backend: ftsResult.backend },
|
|
1738
1991
|
"clearAll: failed to clear messages_fts — dropping triggers so base-table cleanup can proceed",
|
|
1739
1992
|
);
|
|
1740
1993
|
rawExec("DROP TRIGGER IF EXISTS messages_fts_ai");
|
|
@@ -1742,8 +1995,8 @@ export function clearAll(): { conversations: number; messages: number } {
|
|
|
1742
1995
|
rawExec("DROP TRIGGER IF EXISTS messages_fts_au");
|
|
1743
1996
|
messagesFtsCorrupted = true;
|
|
1744
1997
|
}
|
|
1745
|
-
|
|
1746
|
-
|
|
1998
|
+
await runOrThrow("DELETE FROM messages");
|
|
1999
|
+
await runOrThrow("DELETE FROM conversations");
|
|
1747
2000
|
|
|
1748
2001
|
// Record audit event — lifecycle_events is NOT deleted by clearAll(),
|
|
1749
2002
|
// so this survives the wipe and provides a permanent trail.
|
|
@@ -1782,6 +2035,8 @@ export function clearAll(): { conversations: number; messages: number } {
|
|
|
1782
2035
|
log.warn({ err }, "clearAll: failed to reset conversations directory");
|
|
1783
2036
|
}
|
|
1784
2037
|
|
|
2038
|
+
void clearAllConversationIds();
|
|
2039
|
+
|
|
1785
2040
|
return { conversations: convCount, messages: msgCount };
|
|
1786
2041
|
}
|
|
1787
2042
|
|
|
@@ -1874,6 +2129,29 @@ interface WipeConversationResult extends DeletedMemoryIds {
|
|
|
1874
2129
|
cancelledJobCount: number;
|
|
1875
2130
|
}
|
|
1876
2131
|
|
|
2132
|
+
/**
|
|
2133
|
+
* Reserve an empty message row so the agent loop can stamp outbound
|
|
2134
|
+
* streaming events with a stable identity before content is produced.
|
|
2135
|
+
*
|
|
2136
|
+
* Intentionally skips Qdrant indexing and attention projection — an empty
|
|
2137
|
+
* placeholder is meaningless for either. The caller writes final content
|
|
2138
|
+
* via {@link updateMessageContent} and handles indexing/projection itself.
|
|
2139
|
+
*
|
|
2140
|
+
* Delegates the core insert + retry logic to {@link insertMessageCore}.
|
|
2141
|
+
*/
|
|
2142
|
+
export async function reserveMessage(
|
|
2143
|
+
conversationId: string,
|
|
2144
|
+
role: MessageRole,
|
|
2145
|
+
metadata?: Record<string, unknown>,
|
|
2146
|
+
) {
|
|
2147
|
+
return insertMessageCore({
|
|
2148
|
+
conversationId,
|
|
2149
|
+
role,
|
|
2150
|
+
content: "[]",
|
|
2151
|
+
metadata,
|
|
2152
|
+
});
|
|
2153
|
+
}
|
|
2154
|
+
|
|
1877
2155
|
/**
|
|
1878
2156
|
* Update the content of an existing message. Used when consolidating
|
|
1879
2157
|
* multiple assistant messages into one.
|
|
@@ -1910,44 +2188,6 @@ export function updateMessageMetadata(
|
|
|
1910
2188
|
.run();
|
|
1911
2189
|
}
|
|
1912
2190
|
|
|
1913
|
-
/**
|
|
1914
|
-
* Bulk-remove the metadata fields that back the blocks stripped by
|
|
1915
|
-
* `stripInjectionsForCompaction` — currently `pkbSystemReminderBlock`
|
|
1916
|
-
* (`<system_reminder>`), `nowScratchpadBlock` (`<NOW.md …>`),
|
|
1917
|
-
* `pkbContextBlock` (`<knowledge_base>`), and `memoryV2StaticBlock`
|
|
1918
|
-
* (the static `<memory>\n…</memory>` block matched by the `<memory>\n`
|
|
1919
|
-
* prefix in `RUNTIME_INJECTION_PREFIXES`). Called from compaction-strip
|
|
1920
|
-
* sites so post-restart rehydration stays consistent with the in-memory
|
|
1921
|
-
* state produced by `stripInjectionsForCompaction` (which removes those
|
|
1922
|
-
* tags from live messages but cannot touch the DB). Fields backing
|
|
1923
|
-
* blocks that are intentionally NOT stripped (`turnContextBlock`,
|
|
1924
|
-
* `workspaceBlock`, `memoryInjectedBlock`) are preserved.
|
|
1925
|
-
*/
|
|
1926
|
-
export function clearStrippedInjectionMetadataForConversation(
|
|
1927
|
-
conversationId: string,
|
|
1928
|
-
): void {
|
|
1929
|
-
rawRun(
|
|
1930
|
-
`UPDATE messages
|
|
1931
|
-
SET metadata = json_remove(
|
|
1932
|
-
metadata,
|
|
1933
|
-
'$.pkbSystemReminderBlock',
|
|
1934
|
-
'$.nowScratchpadBlock',
|
|
1935
|
-
'$.pkbContextBlock',
|
|
1936
|
-
'$.memoryV2StaticBlock'
|
|
1937
|
-
)
|
|
1938
|
-
WHERE conversation_id = ?
|
|
1939
|
-
AND role = 'user'
|
|
1940
|
-
AND metadata IS NOT NULL
|
|
1941
|
-
AND (
|
|
1942
|
-
json_extract(metadata, '$.pkbSystemReminderBlock') IS NOT NULL
|
|
1943
|
-
OR json_extract(metadata, '$.nowScratchpadBlock') IS NOT NULL
|
|
1944
|
-
OR json_extract(metadata, '$.pkbContextBlock') IS NOT NULL
|
|
1945
|
-
OR json_extract(metadata, '$.memoryV2StaticBlock') IS NOT NULL
|
|
1946
|
-
)`,
|
|
1947
|
-
conversationId,
|
|
1948
|
-
);
|
|
1949
|
-
}
|
|
1950
|
-
|
|
1951
2191
|
/**
|
|
1952
2192
|
* Atomically update both `content` and (shallow-merged) `metadata` for a
|
|
1953
2193
|
* message. Used by edit-propagation paths that need to update the message
|
|
@@ -2185,7 +2425,7 @@ export function batchSetDisplayOrders(
|
|
|
2185
2425
|
updates: Array<{
|
|
2186
2426
|
id: string;
|
|
2187
2427
|
displayOrder: number | null;
|
|
2188
|
-
isPinned
|
|
2428
|
+
isPinned?: boolean;
|
|
2189
2429
|
groupId?: string | null;
|
|
2190
2430
|
}>,
|
|
2191
2431
|
): void {
|
|
@@ -2218,35 +2458,36 @@ export function batchSetDisplayOrders(
|
|
|
2218
2458
|
safeGroupId,
|
|
2219
2459
|
update.id,
|
|
2220
2460
|
);
|
|
2461
|
+
} else if (update.isPinned === undefined) {
|
|
2462
|
+
// Only displayOrder provided — preserve existing pin state and group.
|
|
2463
|
+
rawRun(
|
|
2464
|
+
"UPDATE conversations SET display_order = ? WHERE id = ?",
|
|
2465
|
+
update.displayOrder,
|
|
2466
|
+
update.id,
|
|
2467
|
+
);
|
|
2468
|
+
} else if (update.isPinned) {
|
|
2469
|
+
rawRun(
|
|
2470
|
+
"UPDATE conversations SET display_order = ?, is_pinned = 1, group_id = 'system:pinned' WHERE id = ?",
|
|
2471
|
+
update.displayOrder,
|
|
2472
|
+
update.id,
|
|
2473
|
+
);
|
|
2221
2474
|
} else {
|
|
2222
|
-
//
|
|
2223
|
-
//
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
CASE
|
|
2239
|
-
WHEN source IN ('schedule', 'reminder') THEN 'system:scheduled'
|
|
2240
|
-
WHEN source IN ('heartbeat', 'task') THEN 'system:background'
|
|
2241
|
-
WHEN conversation_type = 'background' AND COALESCE(source, '') != 'notification' THEN 'system:background'
|
|
2242
|
-
ELSE 'system:all'
|
|
2243
|
-
END
|
|
2244
|
-
ELSE group_id END
|
|
2245
|
-
WHERE id = ?`,
|
|
2246
|
-
update.displayOrder,
|
|
2247
|
-
update.id,
|
|
2248
|
-
);
|
|
2249
|
-
}
|
|
2475
|
+
// Restore system group from source/conversationType when unpinning,
|
|
2476
|
+
// instead of clearing to NULL (which would lose provenance).
|
|
2477
|
+
rawRun(
|
|
2478
|
+
`UPDATE conversations SET display_order = ?, is_pinned = 0,
|
|
2479
|
+
group_id = CASE WHEN group_id = 'system:pinned' THEN
|
|
2480
|
+
CASE
|
|
2481
|
+
WHEN source IN ('schedule', 'reminder') THEN 'system:scheduled'
|
|
2482
|
+
WHEN source IN ('heartbeat', 'task') THEN 'system:background'
|
|
2483
|
+
WHEN conversation_type = 'background' AND COALESCE(source, '') != 'notification' THEN 'system:background'
|
|
2484
|
+
ELSE 'system:all'
|
|
2485
|
+
END
|
|
2486
|
+
ELSE group_id END
|
|
2487
|
+
WHERE id = ?`,
|
|
2488
|
+
update.displayOrder,
|
|
2489
|
+
update.id,
|
|
2490
|
+
);
|
|
2250
2491
|
}
|
|
2251
2492
|
}
|
|
2252
2493
|
rawExec("COMMIT");
|