@vellumai/assistant 0.8.2 → 0.8.4
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 +11 -12
- package/docker-entrypoint.sh +13 -2
- package/docker-init-apt-root.sh +79 -6
- package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
- package/openapi.yaml +945 -36
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +271 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
- package/src/__tests__/agent-loop.test.ts +88 -3
- package/src/__tests__/anthropic-provider.test.ts +272 -0
- package/src/__tests__/approval-cascade.test.ts +1 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/channel-delivery-store.test.ts +193 -0
- package/src/__tests__/channel-reply-delivery.test.ts +284 -5
- package/src/__tests__/channel-retry-sweep.test.ts +274 -1
- package/src/__tests__/compaction-events.test.ts +1 -1
- package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
- package/src/__tests__/compactor-tail-resolution.test.ts +107 -1
- package/src/__tests__/config-get-vision-flag.test.ts +136 -0
- package/src/__tests__/config-loader-backfill.test.ts +115 -18
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/context-token-estimator.test.ts +112 -57
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
- package/src/__tests__/conversation-agent-loop.test.ts +77 -3
- 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-confirmation-signals.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +161 -0
- package/src/__tests__/conversation-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-media-retry.test.ts +19 -8
- 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 +1 -1
- package/src/__tests__/conversation-queue.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +290 -85
- package/src/__tests__/conversation-seed-composer.test.ts +66 -4
- 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-surfaces-task-progress.test.ts +220 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -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-security-invariants.test.ts +6 -0
- package/src/__tests__/cu-unified-flow.test.ts +10 -1
- package/src/__tests__/date-context.test.ts +45 -0
- 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__/external-plugin-loader.test.ts +91 -19
- package/src/__tests__/first-greeting.test.ts +23 -2
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -0
- package/src/__tests__/headless-browser-navigate.test.ts +172 -0
- package/src/__tests__/heartbeat-service.test.ts +24 -164
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/host-app-control-proxy.test.ts +241 -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-proxy-preactivation.test.ts +200 -13
- 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__/injector-background-turn.test.ts +153 -0
- package/src/__tests__/injector-chain.test.ts +7 -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__/lifecycle-memory-v2-seed.test.ts +9 -2
- 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 +17 -16
- package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +3 -0
- package/src/__tests__/llm-context-normalization.test.ts +0 -2
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -0
- package/src/__tests__/llm-resolver.test.ts +340 -3
- package/src/__tests__/log-export-routes.test.ts +99 -2
- package/src/__tests__/managed-profile-guard.test.ts +10 -0
- package/src/__tests__/message-queue-steer.test.ts +114 -0
- package/src/__tests__/notification-decision-fallback.test.ts +0 -91
- package/src/__tests__/notification-decision-strategy.test.ts +14 -31
- package/src/__tests__/notification-deep-link.test.ts +15 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -2
- package/src/__tests__/notification-platform-adapter.test.ts +5 -4
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
- package/src/__tests__/openai-provider.test.ts +323 -3
- package/src/__tests__/openai-responses-cutover-guard.test.ts +3 -3
- package/src/__tests__/openai-responses-provider.test.ts +4 -4
- package/src/__tests__/openrouter-provider-only.test.ts +51 -3
- package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
- package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
- package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
- package/src/__tests__/platform-proxy-context.test.ts +6 -1
- package/src/__tests__/platform.test.ts +0 -3
- package/src/__tests__/plugin-source-watcher.test.ts +302 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +3 -3
- package/src/__tests__/plugin-types.test.ts +2 -2
- 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__/provider-catalog-visibility.test.ts +16 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +27 -25
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +83 -4
- package/src/__tests__/steer-tool-repair.test.ts +249 -0
- package/src/__tests__/system-prompt.test.ts +57 -101
- package/src/__tests__/terminal-tools.test.ts +11 -1
- package/src/__tests__/thinking-block-replay.test.ts +113 -0
- package/src/__tests__/thread-backfill.test.ts +370 -22
- package/src/__tests__/tool-executor.test.ts +90 -1
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/web-fetch.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +88 -5
- package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
- package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
- package/src/a2a/__tests__/agent-card.test.ts +98 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
- package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
- package/src/a2a/__tests__/task-store.test.ts +246 -0
- package/src/a2a/agent-card.ts +58 -0
- package/src/a2a/feature-gate.ts +8 -0
- package/src/a2a/protocol-constants.ts +21 -0
- package/src/a2a/protocol-errors.ts +50 -0
- package/src/a2a/protocol-types.ts +162 -0
- package/src/a2a/task-store.ts +168 -0
- package/src/agent/attachments.ts +1 -0
- package/src/agent/loop.ts +208 -22
- package/src/background-wake/next-wake.test.ts +289 -0
- package/src/background-wake/next-wake.ts +172 -0
- package/src/browser/operations.ts +15 -0
- package/src/channels/config.ts +9 -0
- package/src/channels/types.ts +14 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
- package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
- package/src/cli/commands/__tests__/schedules.test.ts +469 -0
- package/src/cli/commands/conversations.ts +128 -1
- package/src/cli/commands/inference-providers.ts +147 -1
- package/src/cli/commands/memory-v2.ts +308 -0
- package/src/cli/commands/notifications.ts +89 -37
- package/src/cli/commands/plugins.ts +67 -0
- package/src/cli/commands/schedules.ts +297 -5
- package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
- package/src/cli/lib/install-from-github.ts +8 -9
- package/src/cli/lib/search-plugins.ts +163 -0
- package/src/cli/program.ts +14 -0
- package/src/cli/utils/conversation-id.ts +17 -5
- package/src/config/assistant-feature-flags.ts +24 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +117 -1
- package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
- package/src/config/bundled-skills/document-editor/TOOLS.json +240 -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-replace-text.ts +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +8 -0
- package/src/config/bundled-tool-registry.ts +22 -12
- package/src/config/call-site-defaults.ts +124 -0
- package/src/config/feature-flag-registry.json +111 -23
- package/src/config/llm-resolver.ts +66 -1
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +7 -3
- package/src/config/schemas/call-site-catalog.ts +21 -0
- package/src/config/schemas/channels.ts +9 -0
- package/src/config/schemas/conversations.ts +10 -0
- package/src/config/schemas/heartbeat.ts +14 -0
- package/src/config/schemas/llm.ts +4 -3
- package/src/config/schemas/memory-retrospective.ts +1 -1
- package/src/config/schemas/memory-v2.ts +51 -4
- package/src/config/schemas/memory.ts +3 -1
- package/src/config/seed-inference-profiles.ts +99 -29
- package/src/context/compactor.ts +80 -13
- package/src/context/token-estimator.ts +72 -31
- package/src/context/window-manager.ts +25 -0
- package/src/credential-health/credential-health-service.ts +34 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -22
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
- 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 +231 -23
- package/src/daemon/conversation-agent-loop.ts +252 -56
- package/src/daemon/conversation-lifecycle.ts +142 -116
- 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 +144 -75
- package/src/daemon/conversation-slash.ts +37 -5
- package/src/daemon/conversation-surfaces.ts +45 -2
- package/src/daemon/conversation-tool-setup.ts +7 -0
- package/src/daemon/conversation.ts +42 -12
- package/src/daemon/date-context.ts +40 -0
- package/src/daemon/first-greeting.ts +10 -0
- package/src/daemon/guardian-action-generators.ts +1 -125
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
- package/src/daemon/handlers/config-a2a.ts +449 -0
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +80 -0
- package/src/daemon/handlers/shared.ts +92 -29
- package/src/daemon/host-app-control-proxy.ts +69 -18
- package/src/daemon/host-bash-proxy.ts +1 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/host-file-proxy.ts +1 -1
- package/src/daemon/host-proxy-preactivation.ts +85 -18
- package/src/daemon/host-transfer-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +67 -65
- package/src/daemon/memory-v2-startup.ts +49 -13
- package/src/daemon/message-protocol.ts +4 -0
- package/src/daemon/message-types/conversations.ts +8 -0
- package/src/daemon/message-types/document-comments.ts +50 -0
- package/src/daemon/message-types/messages.ts +68 -1
- package/src/daemon/message-types/notifications.ts +21 -0
- package/src/daemon/message-types/surfaces.ts +3 -1
- package/src/daemon/message-types/web-activity.ts +57 -0
- package/src/daemon/pkb-reminder-builder.test.ts +10 -53
- package/src/daemon/pkb-reminder-builder.ts +4 -19
- package/src/daemon/plugin-source-watcher.ts +135 -3
- package/src/daemon/process-message.ts +72 -12
- package/src/daemon/query-complexity-router.ts +75 -0
- package/src/daemon/skill-memory-refresh.ts +5 -1
- package/src/daemon/trust-context.ts +6 -0
- package/src/daemon/wake-target-adapter.ts +2 -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/export/__tests__/transcript-formatter.test.ts +121 -0
- package/src/export/transcript-formatter.ts +54 -20
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +44 -1
- package/src/heartbeat/heartbeat-service.ts +35 -191
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/__tests__/suggested-prompts.test.ts +33 -2
- package/src/home/feed-types.ts +20 -3
- package/src/home/home-content-refresh.ts +52 -0
- package/src/home/home-greeting-cache.ts +69 -0
- package/src/home/home-greeting.ts +94 -0
- package/src/home/suggested-prompts.ts +177 -9
- package/src/ipc/cli-client.ts +147 -45
- package/src/memory/__tests__/conversation-queries.test.ts +220 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
- package/src/memory/__tests__/memory-retrospective-job.test.ts +407 -10
- package/src/memory/conversation-crud.ts +133 -43
- package/src/memory/conversation-queries.ts +87 -1
- package/src/memory/conversation-title-service.ts +26 -4
- package/src/memory/db-init.ts +22 -0
- 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/__tests__/conversation-graph-memory-v2-routing.test.ts +84 -3
- package/src/memory/graph/conversation-graph-memory.ts +18 -6
- package/src/memory/graph/tools.ts +6 -37
- package/src/memory/invite-store.ts +53 -0
- package/src/memory/jobs-worker.ts +21 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +7 -2
- package/src/memory/llm-request-log-store.ts +92 -1
- package/src/memory/memory-retrospective-constants.ts +28 -0
- package/src/memory/memory-retrospective-enqueue.ts +4 -22
- package/src/memory/memory-retrospective-job.ts +438 -21
- package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
- package/src/memory/memory-v2-activation-log-store.ts +26 -8
- 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/250-provider-connection-base-url-and-models.ts +28 -0
- package/src/memory/migrations/251-a2a-tasks.ts +49 -0
- package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -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/index.ts +20 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/onboarding-events-store.ts +7 -0
- package/src/memory/schema/a2a.ts +15 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/inference.ts +2 -0
- package/src/memory/schema/infrastructure.ts +2 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
- package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
- package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
- package/src/memory/v2/__tests__/injection.test.ts +221 -17
- package/src/memory/v2/__tests__/page-index.test.ts +365 -1
- package/src/memory/v2/__tests__/router.test.ts +489 -1
- package/src/memory/v2/__tests__/static-context.test.ts +12 -1
- package/src/memory/v2/activation-store.ts +14 -16
- package/src/memory/v2/cli-command-content.ts +19 -0
- package/src/memory/v2/cli-command-store.ts +304 -0
- package/src/memory/v2/consolidation-job.ts +14 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -1
- package/src/memory/v2/injection-events.ts +101 -0
- package/src/memory/v2/injection.ts +69 -29
- package/src/memory/v2/page-index.ts +246 -19
- package/src/memory/v2/page-store.ts +18 -0
- package/src/memory/v2/router.ts +209 -55
- package/src/memory/v2/static-context.ts +4 -4
- package/src/memory/v2/types.ts +23 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
- package/src/messaging/providers/a2a/deliver.ts +156 -0
- package/src/messaging/providers/gmail/client.ts +9 -2
- package/src/messaging/providers/index.ts +18 -3
- 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__/broadcaster.test.ts +203 -0
- package/src/notifications/__tests__/decision-engine.test.ts +283 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +5 -1
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +521 -36
- package/src/notifications/adapters/macos.ts +12 -2
- package/src/notifications/broadcaster.ts +29 -4
- package/src/notifications/conversation-seed-composer.ts +14 -2
- package/src/notifications/copy-composer.ts +17 -64
- package/src/notifications/decision-engine.ts +111 -44
- package/src/notifications/deferred-emit.ts +135 -0
- package/src/notifications/deterministic-checks.ts +96 -0
- package/src/notifications/emit-signal.ts +10 -1
- package/src/notifications/home-feed-side-effect.ts +136 -27
- package/src/notifications/signal.ts +0 -4
- package/src/notifications/types.ts +8 -0
- 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/platform-connection.test.ts +43 -3
- package/src/oauth/platform-connection.ts +13 -4
- package/src/oauth/seed-providers.ts +22 -0
- package/src/permissions/prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +4 -1
- package/src/plugins/defaults/injectors.ts +118 -26
- package/src/plugins/external-plugin-loader.ts +82 -10
- package/src/plugins/types.ts +16 -7
- package/src/prompts/__tests__/system-prompt.test.ts +44 -45
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +4 -8
- package/src/prompts/normalize-onboarding.ts +40 -0
- package/src/prompts/sections.ts +32 -14
- package/src/prompts/system-prompt.ts +105 -76
- package/src/prompts/template-detection.ts +37 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/VOICE.md +3 -0
- package/src/prompts/templates/system-sections.ts +51 -10
- package/src/providers/__tests__/inference.test.ts +2 -0
- package/src/providers/anthropic/client.ts +132 -5
- package/src/providers/call-site-routing.ts +24 -6
- package/src/providers/connection-resolution.ts +63 -13
- package/src/providers/fireworks/client.ts +20 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
- 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/__tests__/connections-openai-compatible.test.ts +175 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
- package/src/providers/inference/adapter-factory.ts +24 -21
- package/src/providers/inference/auth.ts +15 -3
- package/src/providers/inference/backfill.ts +14 -1
- package/src/providers/inference/codex-token-refresh.ts +128 -0
- package/src/providers/inference/connections.ts +85 -5
- package/src/providers/inference/resolve-auth.ts +50 -5
- package/src/providers/model-catalog.ts +244 -242
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
- package/src/providers/openai/chat-completions-provider.ts +215 -25
- package/src/providers/openai/responses-provider.ts +9 -3
- package/src/providers/openrouter/client.ts +46 -4
- package/src/providers/platform-proxy/constants.ts +3 -4
- package/src/providers/provider-catalog-visibility.ts +3 -1
- package/src/providers/provider-send-message.ts +27 -12
- package/src/providers/registry.ts +30 -1
- package/src/providers/types.ts +25 -0
- 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 +212 -57
- package/src/runtime/auth/route-policy.ts +20 -3
- package/src/runtime/background-job-runner.ts +26 -0
- package/src/runtime/channel-reply-delivery.ts +182 -47
- package/src/runtime/channel-retry-sweep.ts +141 -16
- package/src/runtime/http-server.ts +7 -16
- package/src/runtime/http-types.ts +7 -51
- package/src/runtime/pending-interactions.ts +51 -8
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +121 -5
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -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/approval-routes.ts +4 -1
- package/src/runtime/routes/channel-availability-routes.ts +5 -0
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
- package/src/runtime/routes/consolidation-routes.ts +100 -0
- package/src/runtime/routes/content-source-routes.ts +78 -0
- package/src/runtime/routes/conversation-cli-routes.ts +146 -1
- package/src/runtime/routes/conversation-query-routes.ts +130 -12
- package/src/runtime/routes/conversation-routes.ts +288 -76
- package/src/runtime/routes/document-comments-routes.ts +287 -0
- package/src/runtime/routes/documents-routes.ts +33 -0
- 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 +8 -1
- 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/background-dispatch.test.ts +365 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
- package/src/runtime/routes/index.ts +14 -4
- package/src/runtime/routes/inference-provider-connection-routes.ts +192 -3
- package/src/runtime/routes/integrations/a2a.ts +294 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
- package/src/runtime/routes/log-export-routes.ts +39 -0
- package/src/runtime/routes/memory-v2-routes.ts +217 -0
- package/src/runtime/routes/notification-routes.ts +19 -2
- package/src/runtime/routes/question-routes.ts +4 -1
- package/src/runtime/routes/sanity-routes.ts +159 -0
- package/src/runtime/routes/slack-channel-routes.ts +187 -0
- package/src/runtime/routes/subagents-routes.ts +41 -0
- package/src/runtime/services/conversation-serializer.ts +30 -4
- 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/subagent/manager.ts +2 -0
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
- package/src/tools/browser/browser-execution.ts +93 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
- package/src/tools/browser/cdp-client/factory.ts +87 -3
- package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
- package/src/tools/browser/cdp-client/types.ts +36 -0
- package/src/tools/browser/pinned-tabs.ts +90 -0
- 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 +128 -2
- package/src/tools/memory/register.ts +1 -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 +213 -64
- package/src/tools/network/web-search.ts +191 -66
- package/src/tools/registry.ts +2 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/tool-approval-handler.ts +19 -12
- package/src/tools/types.ts +41 -2
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/types/onboarding-context.ts +4 -0
- package/src/util/__tests__/favicon.test.ts +84 -0
- package/src/util/favicon.ts +40 -0
- package/src/util/platform.ts +0 -5
- package/src/workspace/git-service.ts +75 -4
- package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
- package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
- 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/memory/graph/__tests__/remember-description.test.ts +0 -55
- package/src/runtime/guardian-action-conversation-turn.ts +0 -99
- 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
|
@@ -50,7 +50,7 @@ import { ensureGroupMigration } from "./conversation-group-migration.js";
|
|
|
50
50
|
import { getDb, getSqliteFrom } from "./db-connection.js";
|
|
51
51
|
import { forkGraphMemoryState } from "./graph/graph-memory-state-store.js";
|
|
52
52
|
import { indexMessageNow } from "./indexer.js";
|
|
53
|
-
import {
|
|
53
|
+
import { MEMORY_RETROSPECTIVE_SOURCES } from "./memory-retrospective-constants.js";
|
|
54
54
|
import { forkRetrospectiveState } from "./memory-retrospective-state.js";
|
|
55
55
|
import { rawExec, rawGet, rawRun } from "./raw-query.js";
|
|
56
56
|
import {
|
|
@@ -190,6 +190,7 @@ export interface ConversationRow {
|
|
|
190
190
|
contextSummary: string | null;
|
|
191
191
|
contextCompactedMessageCount: number;
|
|
192
192
|
contextCompactedAt: number | null;
|
|
193
|
+
cleanedAt: number | null;
|
|
193
194
|
slackContextCompactionWatermarkTs: string | null;
|
|
194
195
|
slackContextCompactionWatermarkAt: number | null;
|
|
195
196
|
conversationType: string;
|
|
@@ -206,6 +207,7 @@ export interface ConversationRow {
|
|
|
206
207
|
inferenceProfile: string | null;
|
|
207
208
|
inferenceProfileSessionId: string | null;
|
|
208
209
|
inferenceProfileExpiresAt: number | null;
|
|
210
|
+
lastNotifiedInferenceProfile: string | null;
|
|
209
211
|
}
|
|
210
212
|
|
|
211
213
|
export const parseConversation = createRowMapper<
|
|
@@ -222,6 +224,7 @@ export const parseConversation = createRowMapper<
|
|
|
222
224
|
contextSummary: "contextSummary",
|
|
223
225
|
contextCompactedMessageCount: "contextCompactedMessageCount",
|
|
224
226
|
contextCompactedAt: "contextCompactedAt",
|
|
227
|
+
cleanedAt: "cleanedAt",
|
|
225
228
|
slackContextCompactionWatermarkTs: "slackContextCompactionWatermarkTs",
|
|
226
229
|
slackContextCompactionWatermarkAt: "slackContextCompactionWatermarkAt",
|
|
227
230
|
conversationType: "conversationType",
|
|
@@ -238,6 +241,7 @@ export const parseConversation = createRowMapper<
|
|
|
238
241
|
inferenceProfile: "inferenceProfile",
|
|
239
242
|
inferenceProfileSessionId: "inferenceProfileSessionId",
|
|
240
243
|
inferenceProfileExpiresAt: "inferenceProfileExpiresAt",
|
|
244
|
+
lastNotifiedInferenceProfile: "lastNotifiedInferenceProfile",
|
|
241
245
|
});
|
|
242
246
|
|
|
243
247
|
export interface MessageRow {
|
|
@@ -482,7 +486,7 @@ export function findMostRecentRetrospectiveFor(
|
|
|
482
486
|
.from(conversations)
|
|
483
487
|
.where(
|
|
484
488
|
and(
|
|
485
|
-
|
|
489
|
+
inArray(conversations.source, MEMORY_RETROSPECTIVE_SOURCES),
|
|
486
490
|
eq(conversations.forkParentConversationId, currentId),
|
|
487
491
|
),
|
|
488
492
|
)
|
|
@@ -535,6 +539,32 @@ function getConversationGroupId(conversationId: string): string | null {
|
|
|
535
539
|
export function forkConversation(params: {
|
|
536
540
|
conversationId: string;
|
|
537
541
|
throughMessageId?: string;
|
|
542
|
+
/**
|
|
543
|
+
* Override the fork's `source` column. Defaults to the standard
|
|
544
|
+
* `createConversation` default (`"user"`). Used by fork-based memory
|
|
545
|
+
* retrospectives to mark the fork as a retrospective artifact distinct
|
|
546
|
+
* from a user-initiated fork, so dedup and cleanup queries can scope
|
|
547
|
+
* correctly.
|
|
548
|
+
*/
|
|
549
|
+
source?: string;
|
|
550
|
+
/**
|
|
551
|
+
* Optional title for the fork. Defaults to `<parent title> (Fork)`.
|
|
552
|
+
*/
|
|
553
|
+
title?: string;
|
|
554
|
+
/**
|
|
555
|
+
* Override the fork's `conversationType` column. Defaults to `"standard"`.
|
|
556
|
+
* Used by fork-based memory retrospectives to bucket the fork as a
|
|
557
|
+
* `"background"` conversation so it doesn't surface in the user's
|
|
558
|
+
* conversation list.
|
|
559
|
+
*/
|
|
560
|
+
conversationType?: ConversationCreateType;
|
|
561
|
+
/**
|
|
562
|
+
* Override the fork's `groupId`. Defaults to the parent conversation's
|
|
563
|
+
* group (or `"system:all"` when the parent has none). Used by fork-based
|
|
564
|
+
* memory retrospectives to route the fork into a dedicated background
|
|
565
|
+
* group.
|
|
566
|
+
*/
|
|
567
|
+
groupId?: string;
|
|
538
568
|
}): ConversationRow {
|
|
539
569
|
const { conversationId, throughMessageId } = params;
|
|
540
570
|
const db = getDb();
|
|
@@ -576,8 +606,19 @@ export function forkConversation(params: {
|
|
|
576
606
|
copyBoundaryIndex >= 0
|
|
577
607
|
? sourceMessages.slice(0, copyBoundaryIndex + 1)
|
|
578
608
|
: ([] as MessageRow[]);
|
|
609
|
+
|
|
610
|
+
// Inherit /clean state only when the fork boundary is at-or-after the
|
|
611
|
+
// clean event. Pre-clean forks branch from history that pre-dates the
|
|
612
|
+
// clean, so the marker would be a no-op and is misleading to copy.
|
|
613
|
+
const sourceCleanedAt = sourceConversation.cleanedAt ?? null;
|
|
614
|
+
const boundaryMessageCreatedAt = messagesToCopy.at(-1)?.createdAt ?? null;
|
|
615
|
+
const inheritsCleanedAt =
|
|
616
|
+
sourceCleanedAt != null &&
|
|
617
|
+
boundaryMessageCreatedAt != null &&
|
|
618
|
+
boundaryMessageCreatedAt >= sourceCleanedAt;
|
|
579
619
|
const forkParentMessageId = messagesToCopy.at(-1)?.id ?? null;
|
|
580
|
-
const forkTitle =
|
|
620
|
+
const forkTitle =
|
|
621
|
+
params.title ?? `${sourceConversation.title ?? "Untitled"} (Fork)`;
|
|
581
622
|
|
|
582
623
|
// Collect disk-sync work to run after the transaction commits.
|
|
583
624
|
const diskSyncQueue: Array<{
|
|
@@ -597,8 +638,9 @@ export function forkConversation(params: {
|
|
|
597
638
|
const forkedConversation = db.transaction(() => {
|
|
598
639
|
const fc = createConversation({
|
|
599
640
|
title: forkTitle,
|
|
600
|
-
conversationType: "standard",
|
|
601
|
-
groupId: parentGroupId ?? "system:all",
|
|
641
|
+
conversationType: params.conversationType ?? "standard",
|
|
642
|
+
groupId: params.groupId ?? parentGroupId ?? "system:all",
|
|
643
|
+
...(params.source != null ? { source: params.source } : {}),
|
|
602
644
|
});
|
|
603
645
|
|
|
604
646
|
db.update(conversations)
|
|
@@ -620,6 +662,7 @@ export function forkConversation(params: {
|
|
|
620
662
|
slackContextCompactionWatermarkAt: preserveSourceCompactionState
|
|
621
663
|
? sourceConversation.slackContextCompactionWatermarkAt
|
|
622
664
|
: null,
|
|
665
|
+
cleanedAt: inheritsCleanedAt ? sourceCleanedAt : null,
|
|
623
666
|
inferenceProfile: sourceConversation.inferenceProfile,
|
|
624
667
|
})
|
|
625
668
|
.where(eq(conversations.id, fc.id))
|
|
@@ -1229,10 +1272,14 @@ interface PaginatedMessagesResult {
|
|
|
1229
1272
|
hasMore: boolean;
|
|
1230
1273
|
}
|
|
1231
1274
|
|
|
1275
|
+
const PAGINATION_CHUNK_MIN = 50;
|
|
1276
|
+
const PAGINATION_SCAN_CAP = 10_000;
|
|
1277
|
+
|
|
1232
1278
|
export function getMessagesPaginated(
|
|
1233
1279
|
conversationId: string,
|
|
1234
1280
|
limit: number | undefined,
|
|
1235
1281
|
beforeTimestamp?: number,
|
|
1282
|
+
filter?: (row: MessageRow) => boolean,
|
|
1236
1283
|
): PaginatedMessagesResult {
|
|
1237
1284
|
const db = getDb();
|
|
1238
1285
|
|
|
@@ -1248,51 +1295,69 @@ export function getMessagesPaginated(
|
|
|
1248
1295
|
.orderBy(asc(messages.createdAt))
|
|
1249
1296
|
.all()
|
|
1250
1297
|
.map(parseMessage);
|
|
1251
|
-
return {
|
|
1298
|
+
return {
|
|
1299
|
+
messages: filter ? rows.filter(filter) : rows,
|
|
1300
|
+
hasMore: false,
|
|
1301
|
+
};
|
|
1252
1302
|
}
|
|
1253
1303
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1304
|
+
// Walk pages newest→oldest, applying `filter` in TS (metadata parsing is
|
|
1305
|
+
// JSON, not a structured column). Keep fetching until we have `limit + 1`
|
|
1306
|
+
// visible rows or the DB is exhausted, so `hasMore` and the cursor reflect
|
|
1307
|
+
// the visible page rather than the unfiltered row count. Without this loop,
|
|
1308
|
+
// a fully-hidden page returns `{ messages: [], hasMore: true }` with no
|
|
1309
|
+
// cursor, which stalls the web client's older-page fetch.
|
|
1310
|
+
let cursorCreatedAt = beforeTimestamp;
|
|
1311
|
+
let cursorMessageId: string | undefined;
|
|
1312
|
+
const visible: MessageRow[] = [];
|
|
1313
|
+
const chunkSize = Math.max(limit + 1, PAGINATION_CHUNK_MIN);
|
|
1314
|
+
// Bound the work a single request can do when `filter` rejects nearly every
|
|
1315
|
+
// row — otherwise a pathological filter against a huge conversation would
|
|
1316
|
+
// tie up a connection for thousands of roundtrips.
|
|
1317
|
+
let rowsScanned = 0;
|
|
1318
|
+
|
|
1319
|
+
while (visible.length < limit + 1 && rowsScanned < PAGINATION_SCAN_CAP) {
|
|
1320
|
+
const cursorPredicate =
|
|
1321
|
+
cursorCreatedAt === undefined
|
|
1322
|
+
? undefined
|
|
1323
|
+
: cursorMessageId === undefined
|
|
1324
|
+
? lt(messages.createdAt, cursorCreatedAt)
|
|
1325
|
+
: or(
|
|
1326
|
+
lt(messages.createdAt, cursorCreatedAt),
|
|
1327
|
+
and(
|
|
1328
|
+
eq(messages.createdAt, cursorCreatedAt),
|
|
1329
|
+
lt(messages.id, cursorMessageId),
|
|
1330
|
+
),
|
|
1331
|
+
);
|
|
1258
1332
|
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1333
|
+
const chunk = db
|
|
1334
|
+
.select()
|
|
1335
|
+
.from(messages)
|
|
1336
|
+
.where(and(eq(messages.conversationId, conversationId), cursorPredicate))
|
|
1337
|
+
.orderBy(desc(messages.createdAt), desc(messages.id))
|
|
1338
|
+
.limit(chunkSize)
|
|
1339
|
+
.all()
|
|
1340
|
+
.map(parseMessage);
|
|
1267
1341
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1342
|
+
if (chunk.length === 0) break;
|
|
1343
|
+
rowsScanned += chunk.length;
|
|
1344
|
+
|
|
1345
|
+
for (const row of chunk) {
|
|
1346
|
+
if (!filter || filter(row)) visible.push(row);
|
|
1347
|
+
if (visible.length >= limit + 1) break;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
if (chunk.length < chunkSize) break;
|
|
1351
|
+
const lastRow = chunk[chunk.length - 1];
|
|
1352
|
+
cursorCreatedAt = lastRow.createdAt;
|
|
1353
|
+
cursorMessageId = lastRow.id;
|
|
1271
1354
|
}
|
|
1272
|
-
rows.reverse();
|
|
1273
1355
|
|
|
1274
|
-
|
|
1275
|
-
|
|
1356
|
+
const hasMore = visible.length > limit;
|
|
1357
|
+
if (hasMore) visible.splice(limit);
|
|
1358
|
+
visible.reverse();
|
|
1276
1359
|
|
|
1277
|
-
|
|
1278
|
-
conversationId: string,
|
|
1279
|
-
beforeTimestamp: number,
|
|
1280
|
-
): number {
|
|
1281
|
-
const db = getDb();
|
|
1282
|
-
const row = db
|
|
1283
|
-
.select({ createdAt: messages.createdAt })
|
|
1284
|
-
.from(messages)
|
|
1285
|
-
.where(
|
|
1286
|
-
and(
|
|
1287
|
-
eq(messages.conversationId, conversationId),
|
|
1288
|
-
eq(messages.role, "assistant"),
|
|
1289
|
-
lt(messages.createdAt, beforeTimestamp),
|
|
1290
|
-
),
|
|
1291
|
-
)
|
|
1292
|
-
.orderBy(desc(messages.createdAt))
|
|
1293
|
-
.limit(1)
|
|
1294
|
-
.get();
|
|
1295
|
-
return row?.createdAt ?? 0;
|
|
1360
|
+
return { messages: visible, hasMore };
|
|
1296
1361
|
}
|
|
1297
1362
|
|
|
1298
1363
|
export function getLastUserTimestampBefore(
|
|
@@ -1386,6 +1451,20 @@ export function updateConversationContextWindow(
|
|
|
1386
1451
|
.run();
|
|
1387
1452
|
}
|
|
1388
1453
|
|
|
1454
|
+
export function setConversationCleanedAt(
|
|
1455
|
+
id: string,
|
|
1456
|
+
cleanedAt: number | null,
|
|
1457
|
+
): void {
|
|
1458
|
+
const db = getDb();
|
|
1459
|
+
db.update(conversations)
|
|
1460
|
+
.set({
|
|
1461
|
+
cleanedAt,
|
|
1462
|
+
updatedAt: Date.now(),
|
|
1463
|
+
})
|
|
1464
|
+
.where(eq(conversations.id, id))
|
|
1465
|
+
.run();
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1389
1468
|
export function updateConversationSlackContextWatermark(
|
|
1390
1469
|
id: string,
|
|
1391
1470
|
watermarkTs: string,
|
|
@@ -1609,6 +1688,17 @@ export function getConversationOverrideProfile(
|
|
|
1609
1688
|
return getConversationOverrideProfileFromRow(getConversation(conversationId));
|
|
1610
1689
|
}
|
|
1611
1690
|
|
|
1691
|
+
export function setLastNotifiedInferenceProfile(
|
|
1692
|
+
conversationId: string,
|
|
1693
|
+
profileKey: string | null,
|
|
1694
|
+
): void {
|
|
1695
|
+
rawRun(
|
|
1696
|
+
"UPDATE conversations SET last_notified_inference_profile = ? WHERE id = ?",
|
|
1697
|
+
profileKey,
|
|
1698
|
+
conversationId,
|
|
1699
|
+
);
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1612
1702
|
/**
|
|
1613
1703
|
* Delete all conversations, messages, and related data (tool invocations,
|
|
1614
1704
|
* memory segments, etc.) from the daemon database.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { and, count, desc, eq, sql } from "drizzle-orm";
|
|
1
|
+
import { and, count, desc, eq, inArray, isNull, sql } from "drizzle-orm";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
parseExternalContentEnvelope,
|
|
@@ -86,6 +86,92 @@ export function listConversations(
|
|
|
86
86
|
return query.all().map(parseConversation);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* List conversations matching an exact `source` value, ordered by `createdAt`
|
|
91
|
+
* descending. The surgical filter for "find every background run produced by
|
|
92
|
+
* job X" — heartbeat, memory_v2_consolidation, watcher-engine, etc. — since
|
|
93
|
+
* `source` is the canonical job-class distinguisher across the background
|
|
94
|
+
* bucket. `conversationType` + `group_id` only narrow to "background vs
|
|
95
|
+
* scheduled vs standard"; neither identifies which job produced the row.
|
|
96
|
+
*
|
|
97
|
+
* Filter is exact (no `LIKE`, no implicit exclusions): the route layer is
|
|
98
|
+
* responsible for knowing which source constants exist and passing one. The
|
|
99
|
+
* defensive `source != 'subagent'` carve-out applied by `listConversations`
|
|
100
|
+
* is deliberately NOT replicated here — a caller asking for an exact source
|
|
101
|
+
* gets exactly that source.
|
|
102
|
+
*
|
|
103
|
+
* @param source Exact match against `conversations.source`. Pass the
|
|
104
|
+
* canonical constant (e.g. `MEMORY_V2_CONSOLIDATION_SOURCE`).
|
|
105
|
+
* @param limit Maximum rows to return (default 20).
|
|
106
|
+
* @param opts.includeArchived Include rows with non-null `archivedAt`.
|
|
107
|
+
* Defaults to `true` so callers that want a full
|
|
108
|
+
* run history get one; pass `false` for views
|
|
109
|
+
* that hide archived rows.
|
|
110
|
+
*/
|
|
111
|
+
export function listConversationsBySource(
|
|
112
|
+
source: string,
|
|
113
|
+
limit = 20,
|
|
114
|
+
opts?: { includeArchived?: boolean },
|
|
115
|
+
): ConversationRow[] {
|
|
116
|
+
const db = getDb();
|
|
117
|
+
const includeArchived = opts?.includeArchived ?? true;
|
|
118
|
+
const where = includeArchived
|
|
119
|
+
? eq(conversations.source, source)
|
|
120
|
+
: and(eq(conversations.source, source), isNull(conversations.archivedAt));
|
|
121
|
+
const rows = db
|
|
122
|
+
.select()
|
|
123
|
+
.from(conversations)
|
|
124
|
+
.where(where)
|
|
125
|
+
.orderBy(desc(conversations.createdAt))
|
|
126
|
+
.limit(limit)
|
|
127
|
+
.all();
|
|
128
|
+
return rows.map(parseConversation);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Per-conversation aggregate of messages with a specific role. Powers
|
|
133
|
+
* heartbeat-shaped run endpoints (e.g. `consolidation/runs`) that need a
|
|
134
|
+
* "did the agent emit any output?" signal stronger than
|
|
135
|
+
* `conversations.lastMessageAt` — which is bumped by the kickoff user
|
|
136
|
+
* prompt and so cannot distinguish "agent ran" from "agent dispatched but
|
|
137
|
+
* crashed before responding".
|
|
138
|
+
*
|
|
139
|
+
* Single batched aggregate query (no N+1). Conversations with zero matching
|
|
140
|
+
* messages are NOT present in the returned map — callers should treat a
|
|
141
|
+
* missing key as `{ count: 0, lastAt: null }`.
|
|
142
|
+
*
|
|
143
|
+
* @param conversationIds Conversation ids to look up (empty → empty map).
|
|
144
|
+
* @param role Message role to count (default `"assistant"`).
|
|
145
|
+
*/
|
|
146
|
+
export function getMessageRoleStatsByConversation(
|
|
147
|
+
conversationIds: string[],
|
|
148
|
+
role: string = "assistant",
|
|
149
|
+
): Map<string, { count: number; lastAt: number }> {
|
|
150
|
+
if (conversationIds.length === 0) return new Map();
|
|
151
|
+
const db = getDb();
|
|
152
|
+
const rows = db
|
|
153
|
+
.select({
|
|
154
|
+
conversationId: messages.conversationId,
|
|
155
|
+
count: sql<number>`COUNT(*)`.as("count"),
|
|
156
|
+
lastAt: sql<number>`MAX(${messages.createdAt})`.as("last_at"),
|
|
157
|
+
})
|
|
158
|
+
.from(messages)
|
|
159
|
+
.where(
|
|
160
|
+
and(
|
|
161
|
+
inArray(messages.conversationId, conversationIds),
|
|
162
|
+
eq(messages.role, role),
|
|
163
|
+
),
|
|
164
|
+
)
|
|
165
|
+
.groupBy(messages.conversationId)
|
|
166
|
+
.all();
|
|
167
|
+
return new Map(
|
|
168
|
+
rows.map((r) => [
|
|
169
|
+
r.conversationId,
|
|
170
|
+
{ count: Number(r.count), lastAt: Number(r.lastAt) },
|
|
171
|
+
]),
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
89
175
|
export function listPinnedConversations(): ConversationRow[] {
|
|
90
176
|
ensureDisplayOrderMigration();
|
|
91
177
|
ensureGroupMigration();
|
|
@@ -298,9 +298,11 @@ function buildTitleSystemPrompt(): string {
|
|
|
298
298
|
"You generate ultra-concise conversation titles. Output ONLY the title text — no explanation, no quotes, no markdown, no preamble.",
|
|
299
299
|
"",
|
|
300
300
|
"Rules:",
|
|
301
|
-
"- 2–
|
|
302
|
-
"-
|
|
303
|
-
"-
|
|
301
|
+
"- 2–5 words maximum. Titles longer than 5 words are unacceptable — ruthlessly compress to a short noun phrase",
|
|
302
|
+
"- 40 characters absolute maximum — if your title exceeds 40 characters it will be truncated and look broken",
|
|
303
|
+
"- Summarize only the TOPIC, not the request or instructions",
|
|
304
|
+
"- Noun phrases are ideal (e.g. 'Auth Middleware Rewrite', 'Docker Volume Mounts', 'Onboarding Flow')",
|
|
305
|
+
"- Think: what would make a scannable sidebar label?",
|
|
304
306
|
"- Do NOT echo back what the user asked you to do",
|
|
305
307
|
"- Do NOT respond to the conversation content",
|
|
306
308
|
"- Do NOT assess feasibility or comment on capabilities",
|
|
@@ -353,13 +355,33 @@ const META_FAILURE_TITLES = new Set([
|
|
|
353
355
|
"no content",
|
|
354
356
|
]);
|
|
355
357
|
|
|
358
|
+
const MAX_TITLE_LENGTH = 40;
|
|
359
|
+
const MAX_TITLE_WORDS = 7;
|
|
360
|
+
|
|
361
|
+
function truncateTitle(title: string): string {
|
|
362
|
+
if (title.length <= MAX_TITLE_LENGTH) return title;
|
|
363
|
+
const words = title.split(/\s+/);
|
|
364
|
+
if (words.length <= MAX_TITLE_WORDS) {
|
|
365
|
+
// Long words but few of them — truncate to char limit at word boundary
|
|
366
|
+
let result = "";
|
|
367
|
+
for (const word of words) {
|
|
368
|
+
const candidate = result ? result + " " + word : word;
|
|
369
|
+
if (candidate.length > MAX_TITLE_LENGTH) break;
|
|
370
|
+
result = candidate;
|
|
371
|
+
}
|
|
372
|
+
return result || title.slice(0, MAX_TITLE_LENGTH);
|
|
373
|
+
}
|
|
374
|
+
// Too many words — trim to 5 words
|
|
375
|
+
return words.slice(0, 5).join(" ");
|
|
376
|
+
}
|
|
377
|
+
|
|
356
378
|
function normalizeTitle(raw: string): string {
|
|
357
379
|
let title = raw.trim().replace(/^["']|["']$/g, "");
|
|
358
380
|
title = stripMarkdown(title);
|
|
359
381
|
if (META_FAILURE_TITLES.has(title.toLowerCase())) {
|
|
360
382
|
return "";
|
|
361
383
|
}
|
|
362
|
-
return title;
|
|
384
|
+
return truncateTitle(title);
|
|
363
385
|
}
|
|
364
386
|
|
|
365
387
|
/** Strip common markdown formatting so titles render as plain text. */
|
package/src/memory/db-init.ts
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
createWatchersAndLogsTables,
|
|
40
40
|
migrate230AcpSessionHistory,
|
|
41
41
|
migrate231RepairMemoryGraphEventDates,
|
|
42
|
+
migrateA2ATasks,
|
|
42
43
|
migrateActivationState,
|
|
43
44
|
migrateActivationStateFkCascade,
|
|
44
45
|
migrateAddConversationInferenceProfile,
|
|
@@ -57,6 +58,7 @@ import {
|
|
|
57
58
|
migrateCanonicalGuardianRequesterChatId,
|
|
58
59
|
migrateCapabilityCardColumns,
|
|
59
60
|
migrateChannelInboundDeliveredSegments,
|
|
61
|
+
migrateChannelInboundDeliveryAttempts,
|
|
60
62
|
migrateChannelInteractionColumns,
|
|
61
63
|
migrateContactChannelsAccessFields,
|
|
62
64
|
migrateContactChannelsTypeChatIdIndex,
|
|
@@ -64,13 +66,16 @@ import {
|
|
|
64
66
|
migrateContactsNotesColumn,
|
|
65
67
|
migrateContactsRolePrincipal,
|
|
66
68
|
migrateContactsUserFileColumn,
|
|
69
|
+
migrateConversationCleanedAt,
|
|
67
70
|
migrateConversationForkLineage,
|
|
68
71
|
migrateConversationHostAccess,
|
|
69
72
|
migrateConversationInferenceProfileSession,
|
|
73
|
+
migrateConversationLastNotifiedProfile,
|
|
70
74
|
migrateConversationsArchivedAt,
|
|
71
75
|
migrateConversationsLastMessageAt,
|
|
72
76
|
migrateConversationsThreadTypeIndex,
|
|
73
77
|
migrateCreateConversationGraphMemoryState,
|
|
78
|
+
migrateCreateDocumentComments,
|
|
74
79
|
migrateCreateDocumentConversations,
|
|
75
80
|
migrateCreateMemoryGraphNodeEdits,
|
|
76
81
|
migrateCreateMemoryGraphTables,
|
|
@@ -95,6 +100,7 @@ import {
|
|
|
95
100
|
migrateDropSetupSkillIdColumn,
|
|
96
101
|
migrateDropSimplifiedMemory,
|
|
97
102
|
migrateDropUsageCompositeIndexes,
|
|
103
|
+
migrateExternalConversationBindingChatName,
|
|
98
104
|
migrateExternalConversationBindingThreadId,
|
|
99
105
|
migrateFkCascadeRebuilds,
|
|
100
106
|
migrateGuardianActionFollowup,
|
|
@@ -111,6 +117,7 @@ import {
|
|
|
111
117
|
migrateHeartbeatRuns,
|
|
112
118
|
migrateInviteCodeHashColumn,
|
|
113
119
|
migrateInviteContactId,
|
|
120
|
+
migrateLlmRequestLogAgentLoopExitReason,
|
|
114
121
|
migrateLlmRequestLogMessageId,
|
|
115
122
|
migrateLlmRequestLogProvider,
|
|
116
123
|
migrateLlmRequestLogsCreatedAtIndex,
|
|
@@ -120,6 +127,7 @@ import {
|
|
|
120
127
|
migrateMemoryRecallLogsQueryContext,
|
|
121
128
|
migrateMemoryRetrospectiveState,
|
|
122
129
|
migrateMemoryV2ActivationLogs,
|
|
130
|
+
migrateMemoryV2InjectionEvents,
|
|
123
131
|
migrateMessageBookmarks,
|
|
124
132
|
migrateMessagesConversationCreatedAtIndex,
|
|
125
133
|
migrateMessagesFtsBackfill,
|
|
@@ -142,6 +150,8 @@ import {
|
|
|
142
150
|
migrateOAuthProvidersScopeSeparator,
|
|
143
151
|
migrateOAuthProvidersTokenAuthMethodDefault,
|
|
144
152
|
migrateOAuthProvidersTokenExchangeBodyFormat,
|
|
153
|
+
migrateOnboardingEventsPriorAssistants,
|
|
154
|
+
migrateProviderConnectionBaseUrlAndModels,
|
|
145
155
|
migrateProviderConnectionStatusLabel,
|
|
146
156
|
migrateReminderRoutingIntent,
|
|
147
157
|
migrateRemindersToSchedules,
|
|
@@ -171,6 +181,7 @@ import {
|
|
|
171
181
|
migrateSchemaIndexesAndColumns,
|
|
172
182
|
migrateScrubCorruptedImageAttachments,
|
|
173
183
|
migrateSlackCompactionWatermark,
|
|
184
|
+
migrateStripBaseUrlNonOpenaiCompatible,
|
|
174
185
|
migrateStripIntegrationPrefixFromProviderKeys,
|
|
175
186
|
migrateStripPlaceholderSentinelsFromMessages,
|
|
176
187
|
migrateStripThinkingFromConsolidated,
|
|
@@ -430,6 +441,17 @@ export function initializeDb(): void {
|
|
|
430
441
|
migrateExternalConversationBindingThreadId,
|
|
431
442
|
createOnboardingEventsTable,
|
|
432
443
|
migrateNormalizeSlackExternalContent,
|
|
444
|
+
migrateProviderConnectionBaseUrlAndModels,
|
|
445
|
+
migrateA2ATasks,
|
|
446
|
+
migrateLlmRequestLogAgentLoopExitReason,
|
|
447
|
+
migrateCreateDocumentComments,
|
|
448
|
+
migrateExternalConversationBindingChatName,
|
|
449
|
+
migrateChannelInboundDeliveryAttempts,
|
|
450
|
+
migrateMemoryV2InjectionEvents,
|
|
451
|
+
migrateConversationLastNotifiedProfile,
|
|
452
|
+
migrateStripBaseUrlNonOpenaiCompatible,
|
|
453
|
+
migrateOnboardingEventsPriorAssistants,
|
|
454
|
+
migrateConversationCleanedAt,
|
|
433
455
|
];
|
|
434
456
|
|
|
435
457
|
// Run each migration step, catching and logging individual failures so one
|
|
@@ -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.
|