@vellumai/assistant 0.12.1-staging.1 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +0 -4
- package/ARCHITECTURE.md +12 -11
- package/docs/architecture/turn-actor.md +8 -15
- package/openapi.yaml +1 -291
- package/package.json +1 -1
- package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
- package/src/__tests__/app-compiler.test.ts +0 -6
- package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
- package/src/__tests__/app-dir-path-guard.test.ts +3 -1
- package/src/__tests__/app-source-watcher.test.ts +218 -0
- package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
- package/src/__tests__/computer-use-tools.test.ts +5 -17
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +29 -28
- package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
- package/src/__tests__/config-watcher.test.ts +8 -23
- package/src/__tests__/connection-model-compat.test.ts +2 -2
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +0 -26
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
- package/src/__tests__/conversation-queue.test.ts +207 -48
- package/src/__tests__/conversation-retry-discard.test.ts +1 -54
- package/src/__tests__/conversation-skill-tools.test.ts +0 -27
- package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
- package/src/__tests__/conversation-title-service.test.ts +10 -14
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
- package/src/__tests__/credential-record-retire.test.ts +1 -171
- package/src/__tests__/credential-routes.test.ts +3 -212
- package/src/__tests__/credential-security-invariants.test.ts +1 -2
- package/src/__tests__/cu-unified-flow.test.ts +2 -8
- package/src/__tests__/drain-kick-guard.test.ts +2 -0
- package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/host-bash-proxy.test.ts +45 -26
- package/src/__tests__/host-browser-proxy.test.ts +17 -6
- package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
- package/src/__tests__/host-file-proxy.test.ts +23 -11
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
- package/src/__tests__/llm-catalog-parity.test.ts +0 -25
- package/src/__tests__/mcp-auth-routes.test.ts +9 -6
- package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
- package/src/__tests__/mcp-health-check.test.ts +11 -8
- package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
- package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
- package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
- package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
- package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +548 -355
- package/src/__tests__/model-intents.test.ts +0 -3
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
- package/src/__tests__/script-proxy-certs.test.ts +0 -35
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/speaker-identification.test.ts +56 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
- package/src/__tests__/subagent-tools.test.ts +2 -3
- package/src/__tests__/telephony-tts-guard.test.ts +3 -38
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
- package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
- package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
- package/src/__tests__/workspace-git-service.test.ts +0 -26
- package/src/acp/__tests__/agent-process.test.ts +4 -258
- package/src/acp/__tests__/auth-required.test.ts +0 -96
- package/src/acp/__tests__/client-handler.test.ts +2 -90
- package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
- package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
- package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
- package/src/acp/__tests__/session-manager.test.ts +4 -895
- package/src/acp/agent-process.test.ts +1 -4
- package/src/acp/agent-process.ts +9 -94
- package/src/acp/auth-required.ts +1 -50
- package/src/acp/auto-install.test.ts +7 -9
- package/src/acp/client-handler.ts +3 -16
- package/src/acp/resolve-agent.test.ts +6 -220
- package/src/acp/resolve-agent.ts +23 -88
- package/src/acp/session-manager.test.ts +3 -196
- package/src/acp/session-manager.ts +18 -441
- package/src/acp/types.ts +5 -50
- package/src/api/events/app-files-changed.ts +3 -4
- package/src/api/index.ts +0 -6
- package/src/apps/app-store.ts +1 -1
- package/src/bundler/app-compiler.ts +0 -15
- package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
- package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
- package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
- package/src/calls/call-constants.ts +4 -24
- package/src/calls/call-controller.ts +199 -499
- package/src/calls/call-transport.ts +0 -16
- package/src/calls/media-stream-output.ts +0 -32
- package/src/calls/media-stream-server.ts +30 -82
- package/src/calls/media-stream-stt-session.ts +0 -15
- package/src/calls/resolve-call-tts-provider.ts +2 -33
- package/src/calls/speaker-identification.ts +233 -0
- package/src/calls/tts-call-strategy.ts +5 -9
- package/src/calls/types.ts +0 -2
- package/src/calls/voice-control-protocol.ts +21 -53
- package/src/calls/voice-session-bridge.ts +46 -59
- package/src/calls/voice-triage-escalate.ts +56 -175
- package/src/cli/commands/apps.help.ts +13 -67
- package/src/cli/commands/apps.ts +0 -183
- package/src/cli/commands/channels/index.help.ts +2 -70
- package/src/cli/commands/channels/index.ts +3 -16
- package/src/cli/commands/credentials.help.ts +2 -6
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/roadmap.help.ts +1 -5
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +90 -103
- package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
- package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
- package/src/config/__tests__/platform-rehydration.test.ts +0 -93
- package/src/config/acp-defaults.test.ts +3 -13
- package/src/config/acp-defaults.ts +6 -23
- package/src/config/acp-schema.ts +2 -30
- package/src/config/bundled-skills/acp/SKILL.md +14 -22
- package/src/config/bundled-skills/acp/TOOLS.json +1 -5
- package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +12 -8
- package/src/config/memory-v3-gate.test.ts +0 -31
- package/src/config/memory-v3-gate.ts +16 -20
- package/src/config/platform-rehydration.ts +21 -75
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
- package/src/config/schemas/calls.ts +28 -1
- package/src/config/schemas/live-voice.ts +173 -1
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +0 -10
- package/src/config/schemas/skills.ts +14 -0
- package/src/credential-execution/process-manager.test.ts +19 -18
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
- package/src/daemon/app-source-watcher.ts +218 -0
- package/src/daemon/config-watcher.ts +194 -13
- package/src/daemon/conversation-process.ts +64 -35
- package/src/daemon/conversation-skill-tools.ts +31 -13
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +8 -10
- package/src/daemon/conversation-tool-setup.ts +43 -37
- package/src/daemon/conversation.ts +3 -0
- package/src/daemon/host-bash-proxy.ts +12 -8
- package/src/daemon/host-browser-proxy.ts +1 -15
- package/src/daemon/host-file-proxy.ts +10 -8
- package/src/daemon/host-transfer-proxy.ts +18 -14
- package/src/daemon/lifecycle.ts +5 -0
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/shutdown-handlers.ts +9 -1
- package/src/daemon/skill-memory-refresh.ts +0 -64
- package/src/daemon/tool-side-effects.ts +18 -7
- package/src/hooks/types.ts +0 -33
- package/src/inbound/platform-callback-registration.ts +5 -4
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
- package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
- package/src/live-voice/live-voice-session.ts +693 -213
- package/src/{calls → live-voice}/progress-narration.ts +2 -2
- package/src/live-voice/protocol.ts +2 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +45 -29
- package/src/mcp/startup.ts +4 -8
- package/src/messaging/provider.ts +3 -10
- package/src/messaging/providers/callback-routing.ts +0 -18
- package/src/messaging/providers/channel-transport.ts +0 -56
- package/src/messaging/providers/discord/transport.ts +0 -17
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
- package/src/messaging/providers/slack/adapter.ts +44 -7
- package/src/messaging/providers/slack/transport.ts +0 -16
- package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
- package/src/messaging/providers/telegram-bot/client.ts +26 -0
- package/src/messaging/providers/telegram-bot/transport.ts +0 -20
- package/src/messaging/providers/whatsapp/adapter.ts +48 -1
- package/src/messaging/providers/whatsapp/client.ts +29 -0
- package/src/messaging/providers/whatsapp/transport.ts +0 -18
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
- package/src/notifications/assistant-reply-producer.ts +3 -8
- package/src/notifications/conversation-pairing.ts +16 -36
- package/src/notifications/delivered-post-record.ts +1 -11
- package/src/notifications/home-feed-side-effect.ts +7 -55
- package/src/outbound-proxy/certs.ts +5 -3
- package/src/permissions/checker.test.ts +6 -11
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +63 -71
- package/src/persistence/conversation-lineage.ts +4 -12
- package/src/persistence/conversation-title-service.ts +26 -9
- package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
- package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
- package/src/persistence/message-reads.ts +0 -30
- package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
- package/src/persistence/schema/memory-core.ts +0 -5
- package/src/platform/client.test.ts +0 -2
- package/src/platform/client.ts +10 -2
- package/src/plugin-api/constants.ts +0 -2
- package/src/plugin-api/index.ts +0 -1
- package/src/plugin-api/types.ts +0 -2
- package/src/plugins/defaults/index.ts +0 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
- package/src/plugins/defaults/memory/hooks/init.ts +0 -10
- package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
- package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
- package/src/plugins/defaults/memory/startup.ts +1 -6
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
- package/src/plugins/defaults/memory/worker.ts +0 -6
- package/src/plugins/mcp-servers.ts +75 -15
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/gemini/client.ts +23 -9
- package/src/providers/model-catalog.ts +0 -34
- package/src/providers/model-intents.ts +5 -10
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
- package/src/providers/openai/chat-completions-provider.ts +78 -192
- package/src/providers/openai/codex-models.ts +4 -0
- package/src/runtime/AGENTS.md +0 -2
- package/src/runtime/auth/same-actor.ts +3 -38
- package/src/runtime/http-server.ts +151 -160
- package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
- package/src/runtime/routes/acp-routes.test.ts +0 -15
- package/src/runtime/routes/acp-routes.ts +9 -72
- package/src/runtime/routes/app-management-routes.ts +0 -73
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +3 -14
- package/src/runtime/routes/conversation-query-routes.ts +0 -40
- package/src/runtime/routes/credential-routes.ts +10 -19
- package/src/runtime/routes/diagnostics-routes.ts +3 -55
- package/src/runtime/routes/index.ts +0 -4
- package/src/runtime/routes/log-export-routes.ts +0 -2
- package/src/runtime/routes/mcp-auth-routes.ts +47 -39
- package/src/runtime/routes/migration-routes.ts +21 -8
- package/src/runtime/routes/platform-routes.ts +15 -18
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
- package/src/runtime/services/conversation-serializer.ts +3 -16
- package/src/runtime/sync/resource-sync-events.ts +1 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/ces-rpc-record-backend.ts +0 -7
- package/src/subagent/consult-context.ts +25 -12
- package/src/tools/acp/list-agents.test.ts +1 -3
- package/src/tools/acp/spawn.test.ts +11 -146
- package/src/tools/acp/spawn.ts +3 -21
- package/src/tools/acp/status.ts +3 -40
- package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
- package/src/tools/capability-offer.test.ts +2 -22
- package/src/tools/capability-offer.ts +1 -16
- package/src/tools/computer-use/definitions.ts +2 -4
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +0 -100
- package/src/tools/host-filesystem/edit.test.ts +1 -2
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +1 -2
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +1 -2
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +1 -2
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +0 -16
- package/src/tools/host-terminal/host-shell.ts +20 -4
- package/src/tools/policy-context.ts +7 -6
- package/src/tools/subagent/spawn.ts +8 -5
- package/src/tools/watch/watch-retro-report.ts +8 -0
- package/src/util/__tests__/language-subtag.test.ts +1 -23
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/language-subtag.ts +0 -16
- package/src/util/platform.ts +0 -8
- package/src/workspace/git-service.ts +54 -5
- package/src/workspace/migrations/registry.ts +0 -6
- package/scripts/smoke-desktop-window-theme.ts +0 -186
- package/src/__tests__/git-porcelain.test.ts +0 -47
- package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
- package/src/__tests__/resolve-app.test.ts +0 -135
- package/src/__tests__/source-fingerprint.test.ts +0 -184
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
- package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
- package/src/acp/model-config.test.ts +0 -166
- package/src/acp/model-config.ts +0 -138
- package/src/api/events/acp-session-model-update.test.ts +0 -88
- package/src/api/events/acp-session-model-update.ts +0 -46
- package/src/apps/resolve-app.ts +0 -81
- package/src/apps/source-fingerprint.ts +0 -266
- package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
- package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
- package/src/calls/barge-in-guard.ts +0 -118
- package/src/calls/voice-leg-coordinator.ts +0 -189
- package/src/calls/voice-progress-cadence.ts +0 -423
- package/src/cli/commands/__tests__/apps.test.ts +0 -245
- package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
- package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
- package/src/cli/commands/channels/send.ts +0 -128
- package/src/config/__tests__/platform-identity.test.ts +0 -117
- package/src/config/acp-agent-write.ts +0 -43
- package/src/config/acp-schema.test.ts +0 -81
- package/src/config/platform-identity.ts +0 -144
- package/src/config/schemas/__tests__/voice.test.ts +0 -148
- package/src/config/schemas/voice.ts +0 -150
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
- package/src/daemon/app-change-notify.ts +0 -45
- package/src/desktop/__tests__/fake-desktop.ts +0 -119
- package/src/desktop/desktop-chrome-policy.test.ts +0 -71
- package/src/desktop/desktop-chrome-policy.ts +0 -42
- package/src/desktop/desktop-dependencies.test.ts +0 -102
- package/src/desktop/desktop-dependencies.ts +0 -306
- package/src/desktop/desktop-feature.test.ts +0 -18
- package/src/desktop/desktop-feature.ts +0 -19
- package/src/desktop/desktop-panel-config.test.ts +0 -135
- package/src/desktop/desktop-panel-config.ts +0 -149
- package/src/desktop/desktop-session-manager.test.ts +0 -627
- package/src/desktop/desktop-session-manager.ts +0 -814
- package/src/desktop/desktop-stream-bridge.test.ts +0 -395
- package/src/desktop/desktop-stream-bridge.ts +0 -214
- package/src/desktop/desktop-wallpaper.test.ts +0 -191
- package/src/desktop/desktop-wallpaper.ts +0 -113
- package/src/desktop/desktop-window-theme.ts +0 -170
- package/src/i18n/AGENTS.md +0 -22
- package/src/i18n/__tests__/i18n.test.ts +0 -108
- package/src/i18n/index.ts +0 -16
- package/src/i18n/locales.ts +0 -93
- package/src/i18n/messages.ts +0 -61
- package/src/i18n/title.ts +0 -25
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
- package/src/mcp/spec-schema.ts +0 -111
- package/src/mcp/workspace-mcp-config.ts +0 -188
- package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
- package/src/persistence/conversation-title-placeholders.ts +0 -23
- package/src/persistence/message-cursor.ts +0 -78
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
- package/src/providers/gemini-thought-signature.test.ts +0 -63
- package/src/providers/gemini-thought-signature.ts +0 -44
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
- package/src/providers/openai/google-thought-signature.ts +0 -320
- package/src/runtime/__tests__/channel-send.test.ts +0 -443
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
- package/src/runtime/channel-send.ts +0 -316
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
- package/src/runtime/routes/channel-send-routes.ts +0 -85
- package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
- package/src/runtime/routes/desktop-setup-routes.ts +0 -35
- package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
- package/src/security/ces-http-record-backend.ts +0 -120
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
- package/src/skills/workspace-skill-md-signature.ts +0 -50
- package/src/tools/acp/status.test.ts +0 -94
- package/src/util/ca-bundle.ts +0 -13
- package/src/workspace/git-porcelain.ts +0 -66
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
- /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
|
@@ -23,10 +23,7 @@ import {
|
|
|
23
23
|
getMessageById,
|
|
24
24
|
updateMessageContent,
|
|
25
25
|
} from "../persistence/conversation-crud.js";
|
|
26
|
-
import {
|
|
27
|
-
ASSISTANT_INITIATED_SOURCE,
|
|
28
|
-
isBackgroundConversationType,
|
|
29
|
-
} from "../persistence/conversation-types.js";
|
|
26
|
+
import { isBackgroundConversationType } from "../persistence/conversation-types.js";
|
|
30
27
|
import { publishConversationMessagesChanged } from "../runtime/sync/resource-sync-events.js";
|
|
31
28
|
import { getLogger } from "../util/logger.js";
|
|
32
29
|
import { normalizeTitle, stripMarkdown } from "../util/short-title.js";
|
|
@@ -275,11 +272,6 @@ async function resolveOwnedConversationMessageId(
|
|
|
275
272
|
sourceConversationId: string | undefined,
|
|
276
273
|
summary: string,
|
|
277
274
|
): Promise<string | undefined> {
|
|
278
|
-
// The completed reply is already the source conversation's canonical row.
|
|
279
|
-
// This signal's body is a compact push preview, not conversation content.
|
|
280
|
-
if (signal.sourceEventName === "chat.assistant_reply") {
|
|
281
|
-
return undefined;
|
|
282
|
-
}
|
|
283
275
|
if (vellumDelivery?.conversationId) {
|
|
284
276
|
return vellumDelivery.conversationId === sourceConversationId
|
|
285
277
|
? vellumDelivery.messageId
|
|
@@ -503,18 +495,6 @@ function deriveDetailPanelKind(
|
|
|
503
495
|
* `isAsyncBackground` hint. `chat.assistant_reply` also mirrors: it is the
|
|
504
496
|
* durable in-app record for the push sent after a user leaves a chat, while
|
|
505
497
|
* retaining the normal interactive conversation as its navigation target.
|
|
506
|
-
*
|
|
507
|
-
* A delivery that materialized an assistant-initiated thread never mirrors.
|
|
508
|
-
* Under the `assistant-initiated-threads` flag, `conversation-pairing.ts`
|
|
509
|
-
* promotes a background `assistant.share` into a standard conversation
|
|
510
|
-
* stamped {@link ASSISTANT_INITIATED_SOURCE}, and that thread's row in the
|
|
511
|
-
* sidebar's assistant section is the share's one surface. Mirroring it here
|
|
512
|
-
* as well put the same share in the bell a second time, labeled by its
|
|
513
|
-
* source channel ("Heartbeat"). The check reads the paired conversation's
|
|
514
|
-
* `source` rather than re-deriving the promotion rule, so it holds however
|
|
515
|
-
* that rule narrows or widens. Guardian requests are checked first on
|
|
516
|
-
* purpose: the bell is their canonical home whatever conversation they pair
|
|
517
|
-
* with.
|
|
518
498
|
*/
|
|
519
499
|
function resolveHomeFeedMirror(
|
|
520
500
|
signal: NotificationSignal,
|
|
@@ -545,15 +525,6 @@ function resolveHomeFeedMirror(
|
|
|
545
525
|
: fallbackConversationId;
|
|
546
526
|
const sourceScheduleJobId = sourceRow?.scheduleJobId ?? undefined;
|
|
547
527
|
|
|
548
|
-
// Guardian requests always project into the feed: the "Needs
|
|
549
|
-
// attention" item is the request's canonical home, and the request
|
|
550
|
-
// blocks on the guardian whatever kind of conversation raised it.
|
|
551
|
-
if (isGuardianRequestSignalEvent(signal.sourceEventName)) {
|
|
552
|
-
return { mirror: true, sourceConversationId, sourceScheduleJobId };
|
|
553
|
-
}
|
|
554
|
-
if (isAssistantInitiatedThreadDelivery(fallbackConversationId)) {
|
|
555
|
-
return { mirror: false };
|
|
556
|
-
}
|
|
557
528
|
if (
|
|
558
529
|
signal.sourceChannel === "assistant_tool" ||
|
|
559
530
|
signal.sourceEventName === "chat.assistant_reply"
|
|
@@ -563,37 +534,18 @@ function resolveHomeFeedMirror(
|
|
|
563
534
|
if (signal.attentionHints.isAsyncBackground) {
|
|
564
535
|
return { mirror: true, sourceConversationId, sourceScheduleJobId };
|
|
565
536
|
}
|
|
537
|
+
// Guardian requests always project into the feed: the "Needs
|
|
538
|
+
// attention" item is the request's canonical home, and the request
|
|
539
|
+
// blocks on the guardian whatever kind of conversation raised it.
|
|
540
|
+
if (isGuardianRequestSignalEvent(signal.sourceEventName)) {
|
|
541
|
+
return { mirror: true, sourceConversationId, sourceScheduleJobId };
|
|
542
|
+
}
|
|
566
543
|
if (isBackgroundConversationType(sourceRow?.conversationType)) {
|
|
567
544
|
return { mirror: true, sourceConversationId, sourceScheduleJobId };
|
|
568
545
|
}
|
|
569
546
|
return { mirror: false };
|
|
570
547
|
}
|
|
571
548
|
|
|
572
|
-
/**
|
|
573
|
-
* Whether the vellum delivery this signal produced landed in a thread the
|
|
574
|
-
* sidebar's assistant section already shows.
|
|
575
|
-
*
|
|
576
|
-
* Best-effort like the source lookup above: a missing id, a missing row, or
|
|
577
|
-
* a lookup failure all read as "not an assistant thread", so a storage
|
|
578
|
-
* hiccup degrades to the pre-existing behavior (a bell row) rather than
|
|
579
|
-
* dropping the notification everywhere.
|
|
580
|
-
*/
|
|
581
|
-
function isAssistantInitiatedThreadDelivery(
|
|
582
|
-
deliveryConversationId: string | undefined,
|
|
583
|
-
): boolean {
|
|
584
|
-
if (!deliveryConversationId) {
|
|
585
|
-
return false;
|
|
586
|
-
}
|
|
587
|
-
try {
|
|
588
|
-
return (
|
|
589
|
-
getConversation(deliveryConversationId)?.source ===
|
|
590
|
-
ASSISTANT_INITIATED_SOURCE
|
|
591
|
-
);
|
|
592
|
-
} catch {
|
|
593
|
-
return false;
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
|
|
597
549
|
/**
|
|
598
550
|
* Routing-intent enforcement can prune `selectedChannels` without also
|
|
599
551
|
* pruning `renderedCopy`, so iterating `renderedCopy` directly risks
|
|
@@ -2,8 +2,6 @@ import { X509Certificate } from "node:crypto";
|
|
|
2
2
|
import { chmod, mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
|
|
5
|
-
import { writeCombinedCABundle } from "../util/ca-bundle.js";
|
|
6
|
-
|
|
7
5
|
const CA_CERT_FILENAME = "ca.pem";
|
|
8
6
|
const CA_KEY_FILENAME = "ca-key.pem";
|
|
9
7
|
const COMBINED_CA_FILENAME = "combined-ca-bundle.pem";
|
|
@@ -265,7 +263,11 @@ export async function ensureCombinedCABundle(
|
|
|
265
263
|
}
|
|
266
264
|
|
|
267
265
|
try {
|
|
268
|
-
|
|
266
|
+
const [systemCAs, proxyCACert] = await Promise.all([
|
|
267
|
+
readFile(systemBundlePath, "utf-8"),
|
|
268
|
+
readFile(caCertPath, "utf-8"),
|
|
269
|
+
]);
|
|
270
|
+
await writeFile(combinedPath, systemCAs + "\n" + proxyCACert);
|
|
269
271
|
return combinedPath;
|
|
270
272
|
} catch {
|
|
271
273
|
return null;
|
|
@@ -15,16 +15,13 @@ mock.module("../config/assistant-feature-flags.js", () => ({
|
|
|
15
15
|
}));
|
|
16
16
|
|
|
17
17
|
// `buildPolicyContext` (used by the integration tests below) precomputes the
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// opt-out rather than the old v3 condition.
|
|
18
|
+
// proc-to-skills gate via `isV3TierActive`. Drive it through this slot so a
|
|
19
|
+
// test can put the production threading path in the active / inactive state.
|
|
21
20
|
let mockV3TierActive = true;
|
|
22
|
-
let mockSkillImprovementActive = true;
|
|
23
21
|
mock.module("../config/memory-v3-gate.js", () => ({
|
|
24
22
|
isMemoryEnabled: (config?: { memory?: { enabled?: boolean } }) =>
|
|
25
23
|
config?.memory?.enabled !== false,
|
|
26
24
|
isV3TierActive: () => mockV3TierActive,
|
|
27
|
-
isSkillImprovementActive: () => mockSkillImprovementActive,
|
|
28
25
|
isMemoryV3Live: () => mockV3TierActive,
|
|
29
26
|
usesConceptPageMemory: (memory?: {
|
|
30
27
|
enabled?: boolean;
|
|
@@ -222,7 +219,6 @@ describe("Permission Checker (gateway IPC)", () => {
|
|
|
222
219
|
mockCachedThreshold = "low";
|
|
223
220
|
mockRefreshedThreshold = null;
|
|
224
221
|
mockV3TierActive = true;
|
|
225
|
-
mockSkillImprovementActive = true;
|
|
226
222
|
thresholdCallLog.length = 0;
|
|
227
223
|
mockSkillCatalog = [];
|
|
228
224
|
mockResolvedSkill = null;
|
|
@@ -1177,11 +1173,10 @@ describe("Permission Checker (gateway IPC)", () => {
|
|
|
1177
1173
|
});
|
|
1178
1174
|
|
|
1179
1175
|
test("grant does NOT fire when proc-to-skills is inactive, even for the retrospective turn", async () => {
|
|
1180
|
-
//
|
|
1181
|
-
//
|
|
1182
|
-
// grant is dead and the high-risk scaffold prompts.
|
|
1183
|
-
mockV3TierActive =
|
|
1184
|
-
mockSkillImprovementActive = false;
|
|
1176
|
+
// Same retrospective ToolContext, but the feature is inactive (flag off
|
|
1177
|
+
// or v3 not live). buildPolicyContext stamps `procToSkillsActive: false`,
|
|
1178
|
+
// so the grant is dead and the high-risk scaffold prompts.
|
|
1179
|
+
mockV3TierActive = false;
|
|
1185
1180
|
mockIpcClassifyRiskResult = {
|
|
1186
1181
|
risk: "high",
|
|
1187
1182
|
reason: "Skill scaffold",
|
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import type { AgentEvent } from "../agent/loop.js";
|
|
28
28
|
import { getConfig } from "../config/loader.js";
|
|
29
|
-
import { resolvePlatformAssistantIdOrNull } from "../config/platform-identity.js";
|
|
30
29
|
import type { CompactionLogsClickHouseConfig } from "../config/schemas/compaction-logs.js";
|
|
31
30
|
import { credentialKey } from "../security/credential-key.js";
|
|
32
31
|
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
@@ -137,7 +136,7 @@ export interface ClickHouseCompactionLogStoreDeps {
|
|
|
137
136
|
resolveUrl?: () => Promise<string | null>;
|
|
138
137
|
/** Override the credential read for `clickhouse:password`. */
|
|
139
138
|
resolvePassword?: () => Promise<string | null>;
|
|
140
|
-
/** Override the
|
|
139
|
+
/** Override the credential read for `vellum:platform_assistant_id`. */
|
|
141
140
|
resolveAssistantId?: () => Promise<string | null>;
|
|
142
141
|
/** Override fetch for testing. */
|
|
143
142
|
fetchImpl?: CompactionLogFetch;
|
|
@@ -164,7 +163,8 @@ export class ClickHouseCompactionLogStore {
|
|
|
164
163
|
deps.resolvePassword ??
|
|
165
164
|
(() => readCredentialOrNull("clickhouse", "password"));
|
|
166
165
|
this.resolveAssistantId =
|
|
167
|
-
deps.resolveAssistantId ??
|
|
166
|
+
deps.resolveAssistantId ??
|
|
167
|
+
(() => readCredentialOrNull("vellum", "platform_assistant_id"));
|
|
168
168
|
this.fetchImpl = deps.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -35,10 +35,7 @@ import { findConversation } from "../daemon/conversation-registry.js";
|
|
|
35
35
|
import { conversationMetadataSyncTag } from "../daemon/message-types/sync.js";
|
|
36
36
|
import type { TrustContext } from "../daemon/trust-context-types.js";
|
|
37
37
|
import { clearAllConversationIds } from "../home/feed-writer.js";
|
|
38
|
-
import type {
|
|
39
|
-
ConversationDeletedInputContext,
|
|
40
|
-
MessageDeletedInputContext,
|
|
41
|
-
} from "../hooks/types.js";
|
|
38
|
+
import type { ConversationDeletedInputContext } from "../hooks/types.js";
|
|
42
39
|
import { readProviderMetadata } from "../messaging/read-provider-metadata.js";
|
|
43
40
|
import { HOOKS } from "../plugin-api/constants.js";
|
|
44
41
|
import { forkConversationMemory } from "../plugins/defaults/memory/fork-conversation-memory.js";
|
|
@@ -84,6 +81,7 @@ import { ensureDisplayOrderMigration } from "./conversation-display-order-migrat
|
|
|
84
81
|
import { ensureGroupMigration } from "./conversation-group-migration.js";
|
|
85
82
|
import {
|
|
86
83
|
isReferentialFork,
|
|
84
|
+
type LineageBound,
|
|
87
85
|
type LineageConversationRow,
|
|
88
86
|
lineageMessageFilter,
|
|
89
87
|
lineageMessagesAfterFilter,
|
|
@@ -123,11 +121,6 @@ import {
|
|
|
123
121
|
} from "./job-handlers/message-lexical.js";
|
|
124
122
|
import { buildLifecycleTelemetryEvent } from "./lifecycle-events-store.js";
|
|
125
123
|
import { resolveMessageContentBlocks } from "./message-content-file.js";
|
|
126
|
-
import {
|
|
127
|
-
loadMessageBound,
|
|
128
|
-
type MessagesAfterRef,
|
|
129
|
-
resolveMessagesAfterBound,
|
|
130
|
-
} from "./message-cursor.js";
|
|
131
124
|
import { mergeMessageMetadata } from "./message-metadata.js";
|
|
132
125
|
import {
|
|
133
126
|
rawAll,
|
|
@@ -2648,6 +2641,16 @@ function loadLineageRow(id: string): LineageConversationRow | null {
|
|
|
2648
2641
|
return row ?? null;
|
|
2649
2642
|
}
|
|
2650
2643
|
|
|
2644
|
+
/** The `(createdAt, id)` bound of a single message, or null when it is gone. */
|
|
2645
|
+
function loadMessageBound(messageId: string): LineageBound | null {
|
|
2646
|
+
const row = getDb()
|
|
2647
|
+
.select({ createdAt: messages.createdAt, id: messages.id })
|
|
2648
|
+
.from(messages)
|
|
2649
|
+
.where(eq(messages.id, messageId))
|
|
2650
|
+
.get();
|
|
2651
|
+
return row ?? null;
|
|
2652
|
+
}
|
|
2653
|
+
|
|
2651
2654
|
/**
|
|
2652
2655
|
* The segments making up a conversation's logical message set. Non-forks and
|
|
2653
2656
|
* copied forks resolve to a single unbounded segment after one row lookup, so
|
|
@@ -2969,67 +2972,81 @@ export function selectNewestSightFrameCapture(
|
|
|
2969
2972
|
}
|
|
2970
2973
|
|
|
2971
2974
|
/**
|
|
2972
|
-
* Count messages in a conversation created strictly after the
|
|
2973
|
-
* reference. `
|
|
2974
|
-
*
|
|
2975
|
-
*
|
|
2976
|
-
*
|
|
2977
|
-
*
|
|
2978
|
-
* defensible starting point, and the conservative answer is "no new work."
|
|
2975
|
+
* Count messages in a conversation that were created strictly after the
|
|
2976
|
+
* `afterMessageId` reference message. If `afterMessageId` is `null` or empty,
|
|
2977
|
+
* counts all messages in the conversation. If the referenced message no
|
|
2978
|
+
* longer exists (e.g. deleted by a separate flow), returns 0 — callers
|
|
2979
|
+
* decide how to react to a vanished reference, and the conservative answer
|
|
2980
|
+
* here is "no new work."
|
|
2979
2981
|
*
|
|
2980
2982
|
* Used by the memory-retrospective trigger check to decide whether to fire
|
|
2981
2983
|
* the message-count trigger without loading message bodies.
|
|
2982
2984
|
*/
|
|
2983
2985
|
export function countMessagesAfter(
|
|
2984
2986
|
conversationId: string,
|
|
2985
|
-
|
|
2987
|
+
afterMessageId: string | null,
|
|
2986
2988
|
): number {
|
|
2987
2989
|
const db = getDb();
|
|
2988
2990
|
const segments = resolveLineage(conversationId);
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
+
if (afterMessageId === null || afterMessageId === "") {
|
|
2992
|
+
const row = db
|
|
2993
|
+
.select({ c: count() })
|
|
2994
|
+
.from(messages)
|
|
2995
|
+
.where(lineageMessageFilter(segments))
|
|
2996
|
+
.get();
|
|
2997
|
+
return row?.c ?? 0;
|
|
2998
|
+
}
|
|
2999
|
+
const ref = loadMessageBound(afterMessageId);
|
|
3000
|
+
if (!ref) {
|
|
2991
3001
|
return 0;
|
|
2992
3002
|
}
|
|
3003
|
+
// Tie-breaker on `messages.id` so rows that share a millisecond timestamp
|
|
3004
|
+
// with the reference are not permanently skipped. Mirrors the
|
|
3005
|
+
// `(createdAt, id)` cursor pattern used by the backfill job-handler and
|
|
3006
|
+
// turn-events-store.
|
|
2993
3007
|
const row = db
|
|
2994
3008
|
.select({ c: count() })
|
|
2995
3009
|
.from(messages)
|
|
2996
|
-
.where(
|
|
2997
|
-
start.kind === "all"
|
|
2998
|
-
? lineageMessageFilter(segments)
|
|
2999
|
-
: lineageMessagesAfterFilter(segments, start.bound),
|
|
3000
|
-
)
|
|
3010
|
+
.where(lineageMessagesAfterFilter(segments, ref))
|
|
3001
3011
|
.get();
|
|
3002
3012
|
return row?.c ?? 0;
|
|
3003
3013
|
}
|
|
3004
3014
|
|
|
3005
3015
|
/**
|
|
3006
|
-
* Return messages in a conversation created strictly after the
|
|
3007
|
-
*
|
|
3008
|
-
*
|
|
3009
|
-
*
|
|
3010
|
-
* processes.
|
|
3016
|
+
* Return messages in a conversation created strictly after the
|
|
3017
|
+
* `afterMessageId` reference. If the reference is `null`/empty, returns all
|
|
3018
|
+
* messages. If the reference doesn't exist, returns an empty array (mirrors
|
|
3019
|
+
* `countMessagesAfter`'s conservative semantics). Used by the
|
|
3020
|
+
* memory-retrospective job handler to load the message slice it processes.
|
|
3011
3021
|
*/
|
|
3012
3022
|
export function getMessagesAfter(
|
|
3013
3023
|
conversationId: string,
|
|
3014
|
-
|
|
3024
|
+
afterMessageId: string | null,
|
|
3015
3025
|
): MessageRow[] {
|
|
3016
3026
|
const db = getDb();
|
|
3017
3027
|
const segments = resolveLineage(conversationId);
|
|
3018
|
-
|
|
3019
|
-
|
|
3028
|
+
if (afterMessageId === null || afterMessageId === "") {
|
|
3029
|
+
// Secondary `asc(messages.id)` matches the non-null path's cursor
|
|
3030
|
+
// ordering, so callers tracking `cutoffMessageId` across runs see a
|
|
3031
|
+
// consistent ordering when multiple rows share a millisecond timestamp.
|
|
3032
|
+
return db
|
|
3033
|
+
.select()
|
|
3034
|
+
.from(messages)
|
|
3035
|
+
.where(lineageMessageFilter(segments))
|
|
3036
|
+
.orderBy(asc(messages.createdAt), asc(messages.id))
|
|
3037
|
+
.all()
|
|
3038
|
+
.map(parseMessage);
|
|
3039
|
+
}
|
|
3040
|
+
const ref = loadMessageBound(afterMessageId);
|
|
3041
|
+
if (!ref) {
|
|
3020
3042
|
return [];
|
|
3021
3043
|
}
|
|
3022
|
-
//
|
|
3023
|
-
//
|
|
3024
|
-
// multiple rows share a millisecond timestamp.
|
|
3044
|
+
// Same `(createdAt, id)` cursor as `countMessagesAfter` — rows sharing
|
|
3045
|
+
// the reference's millisecond timestamp would otherwise be skipped.
|
|
3025
3046
|
return db
|
|
3026
3047
|
.select()
|
|
3027
3048
|
.from(messages)
|
|
3028
|
-
.where(
|
|
3029
|
-
start.kind === "all"
|
|
3030
|
-
? lineageMessageFilter(segments)
|
|
3031
|
-
: lineageMessagesAfterFilter(segments, start.bound),
|
|
3032
|
-
)
|
|
3049
|
+
.where(lineageMessagesAfterFilter(segments, ref))
|
|
3033
3050
|
.orderBy(asc(messages.createdAt), asc(messages.id))
|
|
3034
3051
|
.all()
|
|
3035
3052
|
.map(parseMessage);
|
|
@@ -4287,12 +4304,12 @@ export function deleteLastExchange(conversationId: string): number {
|
|
|
4287
4304
|
|
|
4288
4305
|
// Collect attachment IDs linked to the messages being deleted so we can
|
|
4289
4306
|
// scope orphan cleanup to only those candidates (not freshly uploaded ones).
|
|
4290
|
-
const
|
|
4291
|
-
.select({ id: messages.id
|
|
4307
|
+
const messageIds = db
|
|
4308
|
+
.select({ id: messages.id })
|
|
4292
4309
|
.from(messages)
|
|
4293
4310
|
.where(condition)
|
|
4294
|
-
.all()
|
|
4295
|
-
|
|
4311
|
+
.all()
|
|
4312
|
+
.map((r) => r.id);
|
|
4296
4313
|
const candidateAttachmentIds =
|
|
4297
4314
|
messageIds.length > 0
|
|
4298
4315
|
? db
|
|
@@ -4339,17 +4356,6 @@ export function deleteLastExchange(conversationId: string): number {
|
|
|
4339
4356
|
enqueueDeleteMessageLexical(deletedMessageId);
|
|
4340
4357
|
}
|
|
4341
4358
|
|
|
4342
|
-
// Notify `message-deleted` hooks for each removed row, as the
|
|
4343
|
-
// single-message primitive does: undo removes the same tail a regenerate
|
|
4344
|
-
// does, and a hook keeping a cursor on one of these rows needs its position.
|
|
4345
|
-
for (const row of deletedRows) {
|
|
4346
|
-
void runHook(HOOKS.MESSAGE_DELETED, {
|
|
4347
|
-
conversationId,
|
|
4348
|
-
messageId: row.id,
|
|
4349
|
-
createdAt: row.createdAt,
|
|
4350
|
-
} satisfies MessageDeletedInputContext);
|
|
4351
|
-
}
|
|
4352
|
-
|
|
4353
4359
|
return deleted;
|
|
4354
4360
|
}
|
|
4355
4361
|
|
|
@@ -4588,13 +4594,9 @@ export function deleteMessageById(
|
|
|
4588
4594
|
.map((r) => r.attachmentId)
|
|
4589
4595
|
.filter((id): id is string => id !== undefined);
|
|
4590
4596
|
|
|
4591
|
-
// Look up the conversation before the transaction so we can recalculate
|
|
4592
|
-
// lastMessageAt, and the row's createdAt for the `message-deleted` hook.
|
|
4597
|
+
// Look up the conversation before the transaction so we can recalculate lastMessageAt.
|
|
4593
4598
|
const msgRow = db
|
|
4594
|
-
.select({
|
|
4595
|
-
conversationId: messages.conversationId,
|
|
4596
|
-
createdAt: messages.createdAt,
|
|
4597
|
-
})
|
|
4599
|
+
.select({ conversationId: messages.conversationId })
|
|
4598
4600
|
.from(messages)
|
|
4599
4601
|
.where(eq(messages.id, messageId))
|
|
4600
4602
|
.get();
|
|
@@ -4650,16 +4652,6 @@ export function deleteMessageById(
|
|
|
4650
4652
|
// not go through the conversation-level purge.
|
|
4651
4653
|
if (msgRow) {
|
|
4652
4654
|
enqueueDeleteMessageLexical(messageId);
|
|
4653
|
-
|
|
4654
|
-
// Notify `message-deleted` hooks (e.g. the memory plugin stamping a
|
|
4655
|
-
// retrospective cursor that sat on this row). Fire-and-forget from this
|
|
4656
|
-
// synchronous primitive, like `conversation-deleted`; the context carries
|
|
4657
|
-
// the row's position because the row itself is gone.
|
|
4658
|
-
void runHook(HOOKS.MESSAGE_DELETED, {
|
|
4659
|
-
conversationId: msgRow.conversationId,
|
|
4660
|
-
messageId,
|
|
4661
|
-
createdAt: msgRow.createdAt,
|
|
4662
|
-
} satisfies MessageDeletedInputContext);
|
|
4663
4655
|
}
|
|
4664
4656
|
|
|
4665
4657
|
return result;
|
|
@@ -227,17 +227,9 @@ export function lineageMessagesAfterFilter(
|
|
|
227
227
|
): SQL {
|
|
228
228
|
return and(
|
|
229
229
|
lineageMessageFilter(segments),
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Predicate for rows strictly after a `(createdAt, id)` bound, with the id
|
|
236
|
-
* tie-breaker so rows sharing the bound's millisecond keep their order.
|
|
237
|
-
*/
|
|
238
|
-
export function messagesAfterBoundFilter(after: LineageBound): SQL {
|
|
239
|
-
return or(
|
|
240
|
-
gt(messages.createdAt, after.createdAt),
|
|
241
|
-
and(eq(messages.createdAt, after.createdAt), gt(messages.id, after.id)),
|
|
230
|
+
or(
|
|
231
|
+
gt(messages.createdAt, after.createdAt),
|
|
232
|
+
and(eq(messages.createdAt, after.createdAt), gt(messages.id, after.id)),
|
|
233
|
+
),
|
|
242
234
|
) as SQL;
|
|
243
235
|
}
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { SEND_USER_MESSAGE_DELIVERED_ACK } from "../config/send-user-message-constants.js";
|
|
11
|
-
import { MESSAGE_KEYS } from "../i18n/index.js";
|
|
12
11
|
import {
|
|
13
12
|
requestShortLabel,
|
|
14
13
|
type ShortLabelTool,
|
|
@@ -25,11 +24,8 @@ import {
|
|
|
25
24
|
type MessageRow,
|
|
26
25
|
updateConversationTitle,
|
|
27
26
|
} from "./conversation-crud.js";
|
|
28
|
-
import { isReplaceableTitle } from "./conversation-title-placeholders.js";
|
|
29
27
|
import { projectPersistedAssistantContent } from "./user-facing-content.js";
|
|
30
28
|
|
|
31
|
-
export { isReplaceableTitle } from "./conversation-title-placeholders.js";
|
|
32
|
-
|
|
33
29
|
const log = getLogger("conversation-title-service");
|
|
34
30
|
|
|
35
31
|
// ── Types ────────────────────────────────────────────────────────────
|
|
@@ -69,8 +65,8 @@ export interface TitleContext {
|
|
|
69
65
|
|
|
70
66
|
// ── Placeholder / loading state ──────────────────────────────────────
|
|
71
67
|
|
|
72
|
-
export const GENERATING_TITLE =
|
|
73
|
-
const UNTITLED_FALLBACK =
|
|
68
|
+
export const GENERATING_TITLE = "Generating title...";
|
|
69
|
+
const UNTITLED_FALLBACK = "Untitled Conversation";
|
|
74
70
|
|
|
75
71
|
// ── `conversations.isAutoTitle` values ───────────────────────────────
|
|
76
72
|
//
|
|
@@ -87,6 +83,28 @@ export const AUTO_TITLE_LLM = 1;
|
|
|
87
83
|
*/
|
|
88
84
|
export const AUTO_TITLE_DETERMINISTIC = 2;
|
|
89
85
|
|
|
86
|
+
// ── Replaceability check ─────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
const REPLACEABLE_PATTERNS = [
|
|
89
|
+
/^Runtime:\s/,
|
|
90
|
+
/^New Conversation$/,
|
|
91
|
+
/^Untitled$/,
|
|
92
|
+
/^Untitled Conversation$/,
|
|
93
|
+
/^Generating title\.\.\.$/,
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Check whether a title is a system-generated placeholder that can be
|
|
98
|
+
* safely overwritten by auto-generated titles. Returns `false` for
|
|
99
|
+
* user-provided custom titles.
|
|
100
|
+
*/
|
|
101
|
+
export function isReplaceableTitle(title: string | null): boolean {
|
|
102
|
+
if (title == null || title.trim() === "") {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
return REPLACEABLE_PATTERNS.some((pattern) => pattern.test(title));
|
|
106
|
+
}
|
|
107
|
+
|
|
90
108
|
/**
|
|
91
109
|
* Whether auto-generation may overwrite the conversation's current title.
|
|
92
110
|
* True for placeholder/system titles and for deterministic bootstrap titles
|
|
@@ -237,7 +255,7 @@ function settleForDeterministicTitle(
|
|
|
237
255
|
* conversation creation (e.g. 5 new chats in quick succession) fires N
|
|
238
256
|
* concurrent requests that can hit provider rate limits or contend for
|
|
239
257
|
* API capacity, causing later calls to time out and fall back to
|
|
240
|
-
*
|
|
258
|
+
* "Untitled Conversation".
|
|
241
259
|
*
|
|
242
260
|
* A serial queue ensures at most one title-generation LLM call is
|
|
243
261
|
* in-flight at a time. Each call is lightweight (~1–3 s for a ≤5-word
|
|
@@ -271,7 +289,7 @@ export function queueGenerateConversationTitle(
|
|
|
271
289
|
// Replace loading placeholder with a retryable fallback.
|
|
272
290
|
try {
|
|
273
291
|
const conversation = getConversation(params.conversationId);
|
|
274
|
-
if (conversation &&
|
|
292
|
+
if (conversation && conversation.title === GENERATING_TITLE) {
|
|
275
293
|
const fallback =
|
|
276
294
|
deriveFallbackTitle(params.context) ?? UNTITLED_FALLBACK;
|
|
277
295
|
updateConversationTitle(
|
|
@@ -406,7 +424,6 @@ function buildTitleSystemPrompt(): string {
|
|
|
406
424
|
"- Think: what would make a scannable sidebar label?",
|
|
407
425
|
"- Do NOT echo back what the user asked you to do",
|
|
408
426
|
"- Do NOT respond to the conversation content",
|
|
409
|
-
"- Write the title in the same language as the conversation content",
|
|
410
427
|
"- Do NOT assess feasibility or comment on capabilities",
|
|
411
428
|
"- If input is sparse or references external context, extract a topic from the words that ARE present (e.g. 'so about that t-shirt...' → 'T-Shirt Discussion'). Never describe the absence, emptiness, or insufficiency of context — titles like 'Missing Context', 'Unclear Request', 'No Topic' are forbidden",
|
|
412
429
|
].join("\n");
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
* can never abort a turn.
|
|
31
31
|
*/
|
|
32
32
|
import { getConfigReadOnly } from "../config/loader.js";
|
|
33
|
-
import { resolvePlatformAssistantIdOrNull } from "../config/platform-identity.js";
|
|
34
33
|
import type { LlmRequestLogsClickHouseConfig } from "../config/schemas/llm-request-logs.js";
|
|
35
34
|
import { credentialKey } from "../security/credential-key.js";
|
|
36
35
|
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
@@ -72,7 +71,7 @@ export interface ClickHouseLlmRequestLogSinkDeps {
|
|
|
72
71
|
resolveUrl?: () => Promise<string | null>;
|
|
73
72
|
/** Override the credential read for `clickhouse:password`. */
|
|
74
73
|
resolvePassword?: () => Promise<string | null>;
|
|
75
|
-
/** Override the
|
|
74
|
+
/** Override the credential read for `vellum:platform_assistant_id`. */
|
|
76
75
|
resolveAssistantId?: () => Promise<string | null>;
|
|
77
76
|
/** Override fetch for testing. */
|
|
78
77
|
fetchImpl?: ClickHouseSinkFetch;
|
|
@@ -99,7 +98,8 @@ export class ClickHouseLlmRequestLogSink implements LlmRequestLogWriter {
|
|
|
99
98
|
deps.resolvePassword ??
|
|
100
99
|
(() => readCredentialOrNull("clickhouse", "password"));
|
|
101
100
|
this.resolveAssistantId =
|
|
102
|
-
deps.resolveAssistantId ??
|
|
101
|
+
deps.resolveAssistantId ??
|
|
102
|
+
(() => readCredentialOrNull("vellum", "platform_assistant_id"));
|
|
103
103
|
this.fetchImpl = deps.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
* than the local source. Acceptable for the "internal use while we
|
|
16
16
|
* finetune prompts" use case; revisit when mirror updates are added.
|
|
17
17
|
*/
|
|
18
|
-
import { resolvePlatformAssistantIdOrNull } from "../config/platform-identity.js";
|
|
19
18
|
import type { LlmRequestLogsClickHouseConfig } from "../config/schemas/llm-request-logs.js";
|
|
20
19
|
import { credentialKey } from "../security/credential-key.js";
|
|
21
20
|
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
@@ -105,7 +104,7 @@ export interface ClickHouseLlmRequestLogSourceDeps {
|
|
|
105
104
|
resolveUrl?: () => Promise<string | null>;
|
|
106
105
|
/** Override the credential read for `clickhouse:password`. */
|
|
107
106
|
resolvePassword?: () => Promise<string | null>;
|
|
108
|
-
/** Override the
|
|
107
|
+
/** Override the credential read for `vellum:platform_assistant_id`. */
|
|
109
108
|
resolveAssistantId?: () => Promise<string | null>;
|
|
110
109
|
/** Override the turn-id resolver (default: `getAssistantMessageIdsInTurn`). */
|
|
111
110
|
resolveTurnMessageIds?: (messageId: string) => string[];
|
|
@@ -139,7 +138,8 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
139
138
|
deps.resolvePassword ??
|
|
140
139
|
(() => readCredentialOrNull("clickhouse", "password"));
|
|
141
140
|
this.resolveAssistantId =
|
|
142
|
-
deps.resolveAssistantId ??
|
|
141
|
+
deps.resolveAssistantId ??
|
|
142
|
+
(() => readCredentialOrNull("vellum", "platform_assistant_id"));
|
|
143
143
|
this.resolveTurnMessageIds =
|
|
144
144
|
deps.resolveTurnMessageIds ?? getAssistantMessageIdsInTurn;
|
|
145
145
|
this.resolveMessage = deps.resolveMessage ?? getMessageById;
|
|
@@ -190,36 +190,6 @@ export function existingMessageIds(
|
|
|
190
190
|
);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
/**
|
|
194
|
-
* `createdAt` of each of `messageIds` that exists as a row, keyed by id, in
|
|
195
|
-
* any state.
|
|
196
|
-
*
|
|
197
|
-
* Any-state deliberately: a row's `createdAt` is fixed at insert, so its
|
|
198
|
-
* completeness does not change the answer, and the callers (retrospective
|
|
199
|
-
* cursor bookkeeping) hold ids taken from rows they have already reviewed.
|
|
200
|
-
* An empty input returns an empty map without querying.
|
|
201
|
-
*/
|
|
202
|
-
export function messageCreatedAtByIds(
|
|
203
|
-
messageIds: readonly string[],
|
|
204
|
-
opts?: { db?: MessageReadHandle },
|
|
205
|
-
): Map<string, number> {
|
|
206
|
-
const db = opts?.db ?? getDb();
|
|
207
|
-
const result = new Map<string, number>();
|
|
208
|
-
// Chunked so a whole-conversation id list stays under SQLite's bound
|
|
209
|
-
// parameter limit.
|
|
210
|
-
for (let offset = 0; offset < messageIds.length; offset += 500) {
|
|
211
|
-
const rows = db
|
|
212
|
-
.select({ id: messages.id, createdAt: messages.createdAt })
|
|
213
|
-
.from(messages)
|
|
214
|
-
.where(inArray(messages.id, messageIds.slice(offset, offset + 500)))
|
|
215
|
-
.all();
|
|
216
|
-
for (const row of rows) {
|
|
217
|
-
result.set(row.id, row.createdAt);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
return result;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
193
|
/**
|
|
224
194
|
* The conversation that owns `messageId`, in any state, or null when the
|
|
225
195
|
* message does not exist.
|