@vellumai/assistant 0.12.1 → 0.12.2-staging.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 +4 -0
- package/ARCHITECTURE.md +20 -21
- package/docs/architecture/turn-actor.md +15 -8
- package/docs/guardian-request-flow.md +16 -0
- package/openapi.yaml +327 -52
- package/package.json +3 -1
- package/scripts/smoke-desktop-window-theme.ts +186 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
- package/src/__tests__/anthropic-provider.test.ts +0 -63
- package/src/__tests__/app-compiler.test.ts +6 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
- package/src/__tests__/app-dir-path-guard.test.ts +1 -3
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +6 -7
- package/src/__tests__/assistant-event-hub.test.ts +44 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
- package/src/__tests__/computer-use-tools.test.ts +19 -7
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +28 -29
- package/src/__tests__/config-watcher.test.ts +23 -8
- 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 +26 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
- package/src/__tests__/conversation-queue.test.ts +48 -207
- package/src/__tests__/conversation-retry-discard.test.ts +54 -1
- package/src/__tests__/conversation-skill-tools.test.ts +27 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-title-service.test.ts +14 -10
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
- package/src/__tests__/credential-record-retire.test.ts +171 -1
- package/src/__tests__/credential-routes.test.ts +212 -3
- package/src/__tests__/credential-security-invariants.test.ts +4 -2
- package/src/__tests__/cu-unified-flow.test.ts +8 -2
- package/src/__tests__/document-sync-tags.test.ts +25 -0
- package/src/__tests__/drain-kick-guard.test.ts +0 -2
- package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/git-porcelain.test.ts +47 -0
- package/src/__tests__/heartbeat-service.test.ts +56 -40
- package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
- package/src/__tests__/host-bash-proxy.test.ts +26 -45
- package/src/__tests__/host-browser-proxy.test.ts +6 -17
- package/src/__tests__/host-cu-proxy.test.ts +539 -0
- package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
- package/src/__tests__/host-file-proxy.test.ts +11 -23
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
- package/src/__tests__/list-messages-camera-frame.test.ts +121 -0
- package/src/__tests__/llm-catalog-parity.test.ts +25 -0
- package/src/__tests__/mcp-auth-routes.test.ts +6 -9
- package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
- package/src/__tests__/mcp-health-check.test.ts +8 -11
- package/src/__tests__/mcp-list-plugin-servers.test.ts +8 -10
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
- package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +355 -548
- package/src/__tests__/model-intents.test.ts +3 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
- package/src/__tests__/oauth-commands-routes.test.ts +113 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +18 -0
- package/src/__tests__/openai-provider.test.ts +1 -0
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +8 -16
- package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +14 -0
- package/src/__tests__/qdrant-manager.test.ts +132 -0
- package/src/__tests__/resolve-app.test.ts +135 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +229 -6
- package/src/__tests__/script-proxy-certs.test.ts +35 -0
- package/src/__tests__/service-account-token.test.ts +247 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/source-fingerprint.test.ts +184 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +19 -3
- package/src/__tests__/subagent-tools.test.ts +3 -2
- package/src/__tests__/telephony-tts-guard.test.ts +38 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/unicode.test.ts +13 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
- package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
- package/src/__tests__/workspace-git-service.test.ts +26 -0
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
- package/src/acp/__tests__/agent-process.test.ts +258 -4
- package/src/acp/__tests__/auth-required.test.ts +96 -0
- package/src/acp/__tests__/client-handler.test.ts +90 -2
- package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
- package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
- package/src/acp/__tests__/session-manager.test.ts +895 -4
- package/src/acp/agent-process.test.ts +4 -1
- package/src/acp/agent-process.ts +96 -10
- package/src/acp/auth-required.ts +50 -1
- package/src/acp/auto-install.test.ts +9 -7
- package/src/acp/client-handler.ts +16 -3
- package/src/acp/model-config.test.ts +166 -0
- package/src/acp/model-config.ts +138 -0
- package/src/acp/resolve-agent.test.ts +220 -6
- package/src/acp/resolve-agent.ts +88 -23
- package/src/acp/session-manager.test.ts +196 -3
- package/src/acp/session-manager.ts +441 -18
- package/src/acp/types.ts +50 -5
- package/src/agent/loop.ts +1 -0
- package/src/api/events/acp-session-model-update.test.ts +88 -0
- package/src/api/events/acp-session-model-update.ts +46 -0
- package/src/api/events/app-files-changed.ts +4 -3
- package/src/api/events/notification-intent.ts +2 -0
- package/src/api/events/user-message-echo.ts +7 -1
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -0
- package/src/apps/app-store.ts +1 -1
- package/src/apps/resolve-app.ts +81 -0
- package/src/apps/source-fingerprint.ts +266 -0
- package/src/avatar/identity-avatar.ts +7 -2
- package/src/bundler/app-compiler.ts +15 -0
- package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
- package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
- package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
- package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
- package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
- package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +4 -4
- package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
- package/src/calls/__tests__/voice-control-protocol.test.ts +58 -25
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
- package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
- package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
- package/src/calls/__tests__/voice-session-bridge.test.ts +37 -1
- package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
- package/src/calls/barge-in-guard.ts +118 -0
- package/src/calls/call-constants.ts +24 -4
- package/src/calls/call-controller.ts +499 -199
- package/src/calls/call-transport.ts +16 -0
- package/src/calls/media-stream-output.ts +32 -0
- package/src/calls/media-stream-server.ts +82 -30
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/{live-voice → calls}/progress-narration.ts +2 -2
- package/src/calls/resolve-call-tts-provider.ts +33 -2
- package/src/calls/tts-call-strategy.ts +9 -5
- package/src/calls/types.ts +2 -0
- package/src/calls/voice-control-protocol.ts +53 -21
- package/src/calls/voice-leg-coordinator.ts +189 -0
- package/src/calls/voice-progress-cadence.ts +423 -0
- package/src/calls/voice-session-bridge.ts +59 -46
- package/src/calls/voice-triage-escalate.ts +175 -56
- package/src/cli/commands/__tests__/apps.test.ts +245 -0
- package/src/cli/commands/__tests__/bash.test.ts +53 -0
- package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
- package/src/cli/commands/apps.help.ts +67 -13
- package/src/cli/commands/apps.ts +183 -0
- package/src/cli/commands/bash.help.ts +8 -13
- package/src/cli/commands/bash.ts +7 -25
- package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
- package/src/cli/commands/channels/index.help.ts +70 -2
- package/src/cli/commands/channels/index.ts +16 -3
- package/src/cli/commands/channels/send.ts +128 -0
- package/src/cli/commands/credentials.help.ts +6 -2
- 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 +5 -1
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +103 -90
- package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
- package/src/config/__tests__/platform-identity.test.ts +255 -0
- package/src/config/__tests__/platform-rehydration.test.ts +99 -9
- package/src/config/acp-agent-write.ts +43 -0
- package/src/config/acp-defaults.test.ts +13 -3
- package/src/config/acp-defaults.ts +23 -6
- package/src/config/acp-schema.test.ts +81 -0
- package/src/config/acp-schema.ts +30 -2
- package/src/config/bundled-skills/acp/SKILL.md +22 -14
- package/src/config/bundled-skills/acp/TOOLS.json +5 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +20 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +99 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-sequence.ts +12 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -1
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -1
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -1
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +67 -139
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -1
- package/src/config/bundled-skills/schedule/SKILL.md +3 -4
- package/src/config/bundled-skills/screen-annotation/SKILL.md +8 -1
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +6 -2
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +24 -12
- package/src/config/loader.ts +1 -0
- package/src/config/memory-v3-gate.test.ts +31 -0
- package/src/config/memory-v3-gate.ts +20 -16
- package/src/config/platform-identity.ts +201 -0
- package/src/config/platform-rehydration.ts +11 -27
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
- package/src/config/schemas/__tests__/voice.test.ts +148 -0
- package/src/config/schemas/calls.ts +1 -28
- package/src/config/schemas/live-voice.ts +1 -173
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +10 -0
- package/src/config/schemas/services.ts +8 -0
- package/src/config/schemas/skills.ts +0 -14
- package/src/config/schemas/voice.ts +150 -0
- package/src/credential-execution/process-manager.test.ts +18 -19
- package/src/credential-health/credential-health-service.ts +11 -17
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -121
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +4 -1
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
- package/src/daemon/app-change-notify.ts +45 -0
- package/src/daemon/config-watcher.ts +13 -194
- package/src/daemon/conversation-error.ts +3 -2
- package/src/daemon/conversation-media-retry.ts +2 -1
- package/src/daemon/conversation-process.ts +35 -64
- package/src/daemon/conversation-runtime-assembly.ts +2 -1
- package/src/daemon/conversation-skill-tools.ts +13 -31
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +15 -9
- package/src/daemon/conversation-tool-setup.ts +37 -43
- package/src/daemon/conversation.ts +0 -3
- package/src/daemon/dictation-profile-store.ts +2 -1
- package/src/daemon/handlers/shared.ts +2 -1
- package/src/daemon/handlers/skills.ts +6 -3
- package/src/daemon/host-bash-proxy.ts +8 -12
- package/src/daemon/host-browser-proxy.ts +15 -1
- package/src/daemon/host-cu-proxy.ts +186 -19
- package/src/daemon/host-file-proxy.ts +8 -10
- package/src/daemon/host-proxy-preactivation.ts +2 -1
- package/src/daemon/host-transfer-proxy.ts +14 -18
- package/src/daemon/lifecycle.ts +0 -5
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/reaction-history-render.ts +2 -1
- package/src/daemon/shutdown-handlers.ts +1 -9
- package/src/daemon/skill-memory-refresh.ts +64 -0
- package/src/daemon/tool-side-effects.ts +7 -18
- package/src/desktop/__tests__/fake-desktop.ts +122 -0
- package/src/desktop/desktop-chrome-policy.test.ts +79 -0
- package/src/desktop/desktop-chrome-policy.ts +47 -0
- package/src/desktop/desktop-chrome-session.ts +37 -0
- package/src/desktop/desktop-dependencies.test.ts +102 -0
- package/src/desktop/desktop-dependencies.ts +308 -0
- package/src/desktop/desktop-feature.test.ts +18 -0
- package/src/desktop/desktop-feature.ts +19 -0
- package/src/desktop/desktop-panel-config.test.ts +135 -0
- package/src/desktop/desktop-panel-config.ts +149 -0
- package/src/desktop/desktop-session-manager.test.ts +730 -0
- package/src/desktop/desktop-session-manager.ts +850 -0
- package/src/desktop/desktop-stream-bridge.test.ts +395 -0
- package/src/desktop/desktop-stream-bridge.ts +214 -0
- package/src/desktop/desktop-wallpaper.test.ts +191 -0
- package/src/desktop/desktop-wallpaper.ts +113 -0
- package/src/desktop/desktop-window-drag.ts +177 -0
- package/src/desktop/desktop-window-manager-config.test.ts +230 -0
- package/src/desktop/desktop-window-manager-config.ts +238 -0
- package/src/desktop/desktop-window-theme.ts +170 -0
- package/src/heartbeat/heartbeat-service.ts +21 -3
- package/src/home/__tests__/feed-writer.test.ts +22 -0
- package/src/home/feed-writer.ts +11 -2
- package/src/hooks/types.ts +33 -0
- package/src/i18n/AGENTS.md +22 -0
- package/src/i18n/__tests__/i18n.test.ts +108 -0
- package/src/i18n/index.ts +16 -0
- package/src/i18n/locales.ts +93 -0
- package/src/i18n/messages.ts +61 -0
- package/src/i18n/title.ts +25 -0
- package/src/inbound/platform-callback-registration.ts +4 -5
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +238 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
- package/src/live-voice/live-voice-photo.ts +25 -6
- package/src/live-voice/live-voice-session.ts +213 -693
- package/src/live-voice/protocol.ts +0 -2
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +29 -45
- package/src/mcp/spec-schema.ts +111 -0
- package/src/mcp/startup.ts +8 -4
- package/src/mcp/workspace-mcp-config.ts +188 -0
- package/src/messaging/provider.ts +10 -3
- package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
- package/src/messaging/providers/callback-routing.ts +18 -0
- package/src/messaging/providers/channel-transport.ts +56 -0
- package/src/messaging/providers/discord/transport.ts +17 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
- package/src/messaging/providers/slack/adapter.ts +7 -44
- package/src/messaging/providers/slack/transport.ts +16 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
- package/src/messaging/providers/telegram-bot/client.ts +0 -26
- package/src/messaging/providers/telegram-bot/transport.ts +20 -0
- package/src/messaging/providers/whatsapp/adapter.ts +1 -48
- package/src/messaging/providers/whatsapp/transport.ts +18 -0
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
- package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/assistant-reply-producer.ts +8 -3
- package/src/notifications/conversation-pairing.ts +36 -16
- package/src/notifications/delivered-post-record.ts +11 -1
- package/src/notifications/guardian-feed-projection.ts +125 -5
- package/src/notifications/home-feed-side-effect.ts +55 -7
- package/src/notifications/schedule-result-producer.ts +66 -22
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/seed-providers-managed.test.ts +54 -0
- package/src/oauth/byo-connection.test.ts +105 -0
- package/src/oauth/byo-connection.ts +36 -6
- package/src/oauth/connection-resolver.test.ts +73 -0
- package/src/oauth/connection-resolver.ts +95 -2
- package/src/oauth/scope-utils.ts +24 -0
- package/src/oauth/seed-providers.ts +204 -25
- package/src/outbound-proxy/certs.ts +3 -5
- package/src/permissions/checker.test.ts +11 -6
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +71 -63
- package/src/persistence/conversation-lineage.ts +12 -4
- package/src/persistence/conversation-queries.ts +2 -2
- package/src/persistence/conversation-title-placeholders.ts +23 -0
- package/src/persistence/conversation-title-service.ts +9 -26
- package/src/persistence/embeddings/qdrant-manager.ts +163 -18
- 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-cursor.ts +78 -0
- package/src/persistence/message-reads.ts +30 -0
- package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
- package/src/persistence/schema/memory-core.ts +5 -0
- package/src/platform/client.test.ts +4 -2
- package/src/platform/client.ts +2 -10
- package/src/plugin-api/constants.ts +2 -0
- package/src/plugin-api/index.ts +1 -0
- package/src/plugin-api/types.ts +2 -0
- package/src/plugins/defaults/index.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +20 -10
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +5 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +3 -2
- package/src/plugins/defaults/memory/context-search/format.ts +3 -2
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +6 -3
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +3 -2
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -7
- package/src/plugins/defaults/memory/hooks/init.ts +10 -0
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
- package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
- package/src/plugins/defaults/memory/host-utils.ts +10 -0
- package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +12 -3
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
- package/src/plugins/defaults/memory/startup.ts +28 -2
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
- package/src/plugins/defaults/memory/substrate/page-index.ts +6 -1
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +4 -1
- package/src/plugins/defaults/memory/v2/reranker.ts +6 -1
- package/src/plugins/defaults/memory/v3/__tests__/card.test.ts +24 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +125 -0
- package/src/plugins/defaults/memory/v3/__tests__/sections.test.ts +26 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +30 -0
- package/src/plugins/defaults/memory/v3/card.ts +3 -2
- package/src/plugins/defaults/memory/v3/pool-select.ts +5 -3
- package/src/plugins/defaults/memory/v3/sections.ts +9 -3
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +5 -2
- package/src/plugins/defaults/memory/worker.ts +6 -0
- package/src/plugins/mcp-servers.ts +15 -75
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/__tests__/retry-callsite.test.ts +41 -0
- package/src/providers/__tests__/retry-outbound-sanitize.test.ts +176 -0
- package/src/providers/anthropic/client.ts +0 -47
- package/src/providers/gemini/client.ts +9 -23
- package/src/providers/gemini-thought-signature.test.ts +63 -0
- package/src/providers/gemini-thought-signature.ts +44 -0
- package/src/providers/inference/__tests__/endpoint-probe.test.ts +42 -3
- package/src/providers/inference/auth.ts +2 -3
- package/src/providers/inference/connection-availability.ts +27 -8
- package/src/providers/inference/endpoint-probe.ts +10 -1
- package/src/providers/inference/resolve-auth.ts +22 -4
- package/src/providers/inference/service-account-token.ts +248 -0
- package/src/providers/model-catalog.ts +34 -0
- package/src/providers/model-intents.ts +10 -5
- package/src/providers/openai/__tests__/chat-completions-output-token-limit.test.ts +141 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
- package/src/providers/openai/chat-completions-provider.ts +212 -79
- package/src/providers/openai/codex-models.ts +0 -4
- package/src/providers/openai/google-thought-signature.ts +320 -0
- package/src/providers/opencode/client.test.ts +73 -4
- package/src/providers/opencode/client.ts +60 -3
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/outbound-request-sanitize.ts +96 -0
- package/src/providers/retry.ts +30 -19
- package/src/providers/unparseable-tool-args.ts +5 -1
- package/src/runtime/AGENTS.md +3 -1
- package/src/runtime/__tests__/channel-send.test.ts +443 -0
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +89 -0
- package/src/runtime/__tests__/host-observe.test.ts +40 -1
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
- package/src/runtime/agent-wake.ts +2 -1
- package/src/runtime/assistant-event-hub.ts +21 -3
- package/src/runtime/auth/same-actor.ts +38 -3
- package/src/runtime/channel-send.ts +316 -0
- package/src/runtime/host-observe.ts +11 -1
- package/src/runtime/http-server.ts +160 -151
- package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +205 -0
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
- package/src/runtime/routes/acp-routes.test.ts +15 -0
- package/src/runtime/routes/acp-routes.ts +72 -9
- package/src/runtime/routes/app-management-routes.ts +73 -0
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/channel-send-routes.ts +85 -0
- package/src/runtime/routes/conversation-list-routes.ts +14 -3
- package/src/runtime/routes/conversation-query-routes.ts +40 -0
- package/src/runtime/routes/conversation-routes.ts +16 -3
- package/src/runtime/routes/credential-routes.ts +19 -10
- package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
- package/src/runtime/routes/desktop-setup-routes.ts +35 -0
- package/src/runtime/routes/diagnostics-routes.ts +61 -4
- package/src/runtime/routes/events-routes.ts +4 -0
- package/src/runtime/routes/host-cu-routes.ts +6 -0
- package/src/runtime/routes/index.ts +4 -2
- package/src/runtime/routes/log-export-routes.ts +2 -0
- package/src/runtime/routes/mcp-auth-routes.ts +39 -47
- package/src/runtime/routes/migration-routes.ts +6 -20
- package/src/runtime/routes/oauth-commands-routes.ts +36 -0
- package/src/runtime/routes/platform-routes.ts +18 -15
- package/src/runtime/routes/workspace-routes.test.ts +55 -26
- package/src/runtime/routes/workspace-routes.ts +46 -63
- package/src/runtime/routes/workspace-tree-walk.test.ts +244 -0
- package/src/runtime/routes/workspace-tree-walk.ts +240 -0
- package/src/runtime/routes/workspace-utils.ts +17 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +16 -3
- package/src/runtime/sync/resource-sync-events.ts +2 -1
- package/src/schedule/run-script.ts +2 -1
- package/src/schedule/schedule-store.ts +9 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
- package/src/security/ces-http-record-backend.ts +120 -0
- package/src/security/ces-rpc-record-backend.ts +7 -0
- package/src/security/untrusted-content.ts +3 -1
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
- package/src/skills/workspace-skill-md-signature.ts +50 -0
- package/src/subagent/consult-context.ts +12 -25
- package/src/tools/__tests__/side-effect-abort-guard.test.ts +1 -0
- package/src/tools/acp/list-agents.test.ts +3 -1
- package/src/tools/acp/spawn.test.ts +146 -11
- package/src/tools/acp/spawn.ts +21 -3
- package/src/tools/acp/status.test.ts +94 -0
- package/src/tools/acp/status.ts +40 -3
- package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +9 -3
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +2 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +3 -2
- package/src/tools/browser/network-recorder.ts +2 -1
- package/src/tools/capability-offer.test.ts +22 -2
- package/src/tools/capability-offer.ts +16 -1
- package/src/tools/computer-use/definitions.ts +121 -2
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
- package/src/tools/credentials/metadata-store.ts +100 -0
- package/src/tools/filesystem/search.ts +2 -1
- package/src/tools/host-filesystem/edit.test.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +2 -1
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +2 -1
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +2 -1
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +16 -0
- package/src/tools/host-terminal/host-shell.ts +4 -20
- package/src/tools/network/web-search.ts +6 -1
- package/src/tools/policy-context.ts +6 -7
- package/src/tools/skills/scaffold-managed.ts +61 -3
- package/src/tools/subagent/spawn.ts +5 -8
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
- package/src/tools/terminal/sanitized-bash.ts +105 -0
- package/src/tools/watch/watch-retro-report.ts +0 -8
- package/src/types/host-capabilities.ts +5 -3
- package/src/util/__tests__/language-subtag.test.ts +23 -1
- package/src/util/ca-bundle.ts +13 -0
- package/src/util/language-subtag.ts +16 -0
- package/src/util/platform.ts +8 -0
- package/src/util/unicode.ts +15 -1
- package/src/watch/watch-timeline.ts +2 -2
- package/src/workflows/run-manager.ts +2 -1
- package/src/workspace/git-porcelain.ts +66 -0
- package/src/workspace/git-service.ts +6 -55
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/app-source-watcher.test.ts +0 -218
- package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
- package/src/__tests__/speaker-identification.test.ts +0 -56
- package/src/calls/speaker-identification.ts +0 -233
- package/src/daemon/app-source-watcher.ts +0 -218
- package/src/messaging/providers/whatsapp/client.ts +0 -29
- package/src/runtime/routes/debug-bash-routes.ts +0 -173
- package/src/util/fs-watcher-error.ts +0 -36
- /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
|
@@ -8,6 +8,7 @@
|
|
|
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";
|
|
11
12
|
import {
|
|
12
13
|
requestShortLabel,
|
|
13
14
|
type ShortLabelTool,
|
|
@@ -24,8 +25,11 @@ import {
|
|
|
24
25
|
type MessageRow,
|
|
25
26
|
updateConversationTitle,
|
|
26
27
|
} from "./conversation-crud.js";
|
|
28
|
+
import { isReplaceableTitle } from "./conversation-title-placeholders.js";
|
|
27
29
|
import { projectPersistedAssistantContent } from "./user-facing-content.js";
|
|
28
30
|
|
|
31
|
+
export { isReplaceableTitle } from "./conversation-title-placeholders.js";
|
|
32
|
+
|
|
29
33
|
const log = getLogger("conversation-title-service");
|
|
30
34
|
|
|
31
35
|
// ── Types ────────────────────────────────────────────────────────────
|
|
@@ -65,8 +69,8 @@ export interface TitleContext {
|
|
|
65
69
|
|
|
66
70
|
// ── Placeholder / loading state ──────────────────────────────────────
|
|
67
71
|
|
|
68
|
-
export const GENERATING_TITLE =
|
|
69
|
-
const UNTITLED_FALLBACK =
|
|
72
|
+
export const GENERATING_TITLE = MESSAGE_KEYS.CONVERSATION_TITLE_GENERATING;
|
|
73
|
+
const UNTITLED_FALLBACK = MESSAGE_KEYS.CONVERSATION_TITLE_UNTITLED;
|
|
70
74
|
|
|
71
75
|
// ── `conversations.isAutoTitle` values ───────────────────────────────
|
|
72
76
|
//
|
|
@@ -83,28 +87,6 @@ export const AUTO_TITLE_LLM = 1;
|
|
|
83
87
|
*/
|
|
84
88
|
export const AUTO_TITLE_DETERMINISTIC = 2;
|
|
85
89
|
|
|
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
|
-
|
|
108
90
|
/**
|
|
109
91
|
* Whether auto-generation may overwrite the conversation's current title.
|
|
110
92
|
* True for placeholder/system titles and for deterministic bootstrap titles
|
|
@@ -255,7 +237,7 @@ function settleForDeterministicTitle(
|
|
|
255
237
|
* conversation creation (e.g. 5 new chats in quick succession) fires N
|
|
256
238
|
* concurrent requests that can hit provider rate limits or contend for
|
|
257
239
|
* API capacity, causing later calls to time out and fall back to
|
|
258
|
-
*
|
|
240
|
+
* the untitled catalog key.
|
|
259
241
|
*
|
|
260
242
|
* A serial queue ensures at most one title-generation LLM call is
|
|
261
243
|
* in-flight at a time. Each call is lightweight (~1–3 s for a ≤5-word
|
|
@@ -289,7 +271,7 @@ export function queueGenerateConversationTitle(
|
|
|
289
271
|
// Replace loading placeholder with a retryable fallback.
|
|
290
272
|
try {
|
|
291
273
|
const conversation = getConversation(params.conversationId);
|
|
292
|
-
if (conversation && conversation.title
|
|
274
|
+
if (conversation && isReplaceableTitle(conversation.title)) {
|
|
293
275
|
const fallback =
|
|
294
276
|
deriveFallbackTitle(params.context) ?? UNTITLED_FALLBACK;
|
|
295
277
|
updateConversationTitle(
|
|
@@ -424,6 +406,7 @@ function buildTitleSystemPrompt(): string {
|
|
|
424
406
|
"- Think: what would make a scannable sidebar label?",
|
|
425
407
|
"- Do NOT echo back what the user asked you to do",
|
|
426
408
|
"- Do NOT respond to the conversation content",
|
|
409
|
+
"- Write the title in the same language as the conversation content",
|
|
427
410
|
"- Do NOT assess feasibility or comment on capabilities",
|
|
428
411
|
"- 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",
|
|
429
412
|
].join("\n");
|
|
@@ -33,6 +33,116 @@ const SHUTDOWN_GRACE_MS = 5_000;
|
|
|
33
33
|
const STDOUT_CAPTURE_LIMIT = 16_384;
|
|
34
34
|
const STDERR_CAPTURE_LIMIT = 4_096;
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Which step of a local start failed. `install` covers the download, checksum
|
|
38
|
+
* and extraction of the binary; `spawn` the OS refusing to run it; `exited`
|
|
39
|
+
* the process dying before `/readyz` answered; `not_ready` the readiness
|
|
40
|
+
* deadline passing with the process still alive (or, in external mode, the
|
|
41
|
+
* remote instance never answering).
|
|
42
|
+
*/
|
|
43
|
+
export type QdrantStartFailureKind =
|
|
44
|
+
| "install"
|
|
45
|
+
| "spawn"
|
|
46
|
+
| "exited"
|
|
47
|
+
| "not_ready";
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A failed `QdrantManager.start()`. The message keeps the captured output for
|
|
51
|
+
* the log line; the fields carry the same facts in a form a reporter can use
|
|
52
|
+
* without parsing that message.
|
|
53
|
+
*/
|
|
54
|
+
export class QdrantStartError extends Error {
|
|
55
|
+
constructor(
|
|
56
|
+
message: string,
|
|
57
|
+
readonly kind: QdrantStartFailureKind,
|
|
58
|
+
readonly exitCode: number | null,
|
|
59
|
+
readonly stdout: string,
|
|
60
|
+
readonly stderr: string,
|
|
61
|
+
options?: ErrorOptions,
|
|
62
|
+
) {
|
|
63
|
+
super(message, options);
|
|
64
|
+
this.name = "QdrantStartError";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Budget for the `panic` string {@link describeQdrantStartFailure} emits, in
|
|
70
|
+
* the bytes the telemetry server counts: JSON with every code unit above 0x7E
|
|
71
|
+
* escaped as `\uXXXX` (see `jsonByteLength` in `telemetry-wire.generated.ts`).
|
|
72
|
+
* A quarter of `WATCHDOG_DETAIL_MAX_JSON_BYTES`, leaving the other fields and
|
|
73
|
+
* the event envelope far from the limit that silently drops the event.
|
|
74
|
+
*/
|
|
75
|
+
const PANIC_REPORT_MAX_JSON_BYTES = 1_024;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Longest prefix of `text` whose server-side JSON size fits `maxBytes`. Each
|
|
79
|
+
* UTF-16 code unit above 0x7E costs six bytes (astral characters two units,
|
|
80
|
+
* so twelve); quotes, backslashes and control characters cost what
|
|
81
|
+
* `JSON.stringify` escapes them to. Counting characters instead would let a
|
|
82
|
+
* non-ASCII reason overshoot the budget six-fold.
|
|
83
|
+
*/
|
|
84
|
+
function truncateToJsonBytes(text: string, maxBytes: number): string {
|
|
85
|
+
let bytes = 0;
|
|
86
|
+
for (let i = 0; i < text.length; i++) {
|
|
87
|
+
const unit = text.charCodeAt(i);
|
|
88
|
+
bytes += unit > 0x7e ? 6 : JSON.stringify(text[i]).length - 2;
|
|
89
|
+
if (bytes > maxBytes) {
|
|
90
|
+
return text.slice(0, i);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return text;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Qdrant's panic hook logs `Panic occurred <location>: <reason>` on stdout. */
|
|
97
|
+
const PANIC_MARKER = "Panic occurred";
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Reduce a start failure to the metadata a `watchdog` telemetry event may
|
|
101
|
+
* carry: the failing step, the exit code, and Qdrant's own one-line reason.
|
|
102
|
+
*
|
|
103
|
+
* The reason is engine output, never conversation content, so it is in the
|
|
104
|
+
* same class as the SQLite `integrity_check` strings `db-integrity-sample.ts`
|
|
105
|
+
* already reports. The one thing in it that is not pure engine text is the
|
|
106
|
+
* absolute data directory, which is swapped for a placeholder. The panic hook
|
|
107
|
+
* prints the reason after the backtrace, so it is everything from the last
|
|
108
|
+
* marker on; when Qdrant died without panicking (a port collision logs a plain
|
|
109
|
+
* error) the last stdout line is the best available explanation. Capped by
|
|
110
|
+
* the server's own byte measure well inside the detail budget. Anything that is not a
|
|
111
|
+
* {@link QdrantStartError} reports as `unknown`, so a new throw site can never
|
|
112
|
+
* silently drop the event.
|
|
113
|
+
*/
|
|
114
|
+
export function describeQdrantStartFailure(
|
|
115
|
+
err: unknown,
|
|
116
|
+
dataDir: string = getDataDir(),
|
|
117
|
+
): {
|
|
118
|
+
kind: QdrantStartFailureKind | "unknown";
|
|
119
|
+
exit_code: number | null;
|
|
120
|
+
panic: string | null;
|
|
121
|
+
} {
|
|
122
|
+
if (!(err instanceof QdrantStartError)) {
|
|
123
|
+
return { kind: "unknown", exit_code: null, panic: null };
|
|
124
|
+
}
|
|
125
|
+
const stdout = err.stdout.trim();
|
|
126
|
+
let reason: string | null = null;
|
|
127
|
+
if (stdout) {
|
|
128
|
+
const marker = stdout.lastIndexOf(PANIC_MARKER);
|
|
129
|
+
reason =
|
|
130
|
+
marker >= 0
|
|
131
|
+
? stdout.slice(marker)
|
|
132
|
+
: (stdout
|
|
133
|
+
.split("\n")
|
|
134
|
+
.filter((line) => line.trim())
|
|
135
|
+
.at(-1) ?? null);
|
|
136
|
+
}
|
|
137
|
+
if (reason) {
|
|
138
|
+
reason = truncateToJsonBytes(
|
|
139
|
+
reason.split(dataDir).join("<data>"),
|
|
140
|
+
PANIC_REPORT_MAX_JSON_BYTES,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
return { kind: err.kind, exit_code: err.exitCode, panic: reason };
|
|
144
|
+
}
|
|
145
|
+
|
|
36
146
|
export function resolveQdrantReleaseAsset(
|
|
37
147
|
os: NodeJS.Platform,
|
|
38
148
|
cpu: string,
|
|
@@ -144,7 +254,11 @@ export class QdrantManager {
|
|
|
144
254
|
|
|
145
255
|
const binaryPath = this.getBinaryPath();
|
|
146
256
|
if (!existsSync(binaryPath)) {
|
|
147
|
-
|
|
257
|
+
try {
|
|
258
|
+
await this.installBinary(binaryPath);
|
|
259
|
+
} catch (err) {
|
|
260
|
+
throw this.startError(err, "install");
|
|
261
|
+
}
|
|
148
262
|
}
|
|
149
263
|
|
|
150
264
|
const spawnPath = this.ensureVellumSymlink(binaryPath);
|
|
@@ -154,21 +268,26 @@ export class QdrantManager {
|
|
|
154
268
|
"Starting Qdrant",
|
|
155
269
|
);
|
|
156
270
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
271
|
+
let proc: Subprocess<"ignore", "pipe", "pipe">;
|
|
272
|
+
try {
|
|
273
|
+
proc = Bun.spawn({
|
|
274
|
+
cmd: [spawnPath],
|
|
275
|
+
windowsHide: true,
|
|
276
|
+
env: {
|
|
277
|
+
...process.env,
|
|
278
|
+
QDRANT__SERVICE__HOST: this.host,
|
|
279
|
+
QDRANT__SERVICE__HTTP_PORT: String(this.port),
|
|
280
|
+
QDRANT__SERVICE__GRPC_PORT: "0", // disable gRPC
|
|
281
|
+
QDRANT__TELEMETRY_DISABLED: "true",
|
|
282
|
+
QDRANT__STORAGE__STORAGE_PATH: this.storagePath,
|
|
283
|
+
QDRANT__LOG_LEVEL: "WARN",
|
|
284
|
+
},
|
|
285
|
+
stdout: "pipe",
|
|
286
|
+
stderr: "pipe",
|
|
287
|
+
});
|
|
288
|
+
} catch (err) {
|
|
289
|
+
throw this.startError(err, "spawn");
|
|
290
|
+
}
|
|
172
291
|
this.process = proc;
|
|
173
292
|
this.drainOutputFrom(proc.stdout, proc.stderr);
|
|
174
293
|
|
|
@@ -311,6 +430,24 @@ export class QdrantManager {
|
|
|
311
430
|
);
|
|
312
431
|
}
|
|
313
432
|
|
|
433
|
+
/**
|
|
434
|
+
* Wrap a failure from a start step in a {@link QdrantStartError}. Errors the
|
|
435
|
+
* manager already classified pass through untouched.
|
|
436
|
+
*/
|
|
437
|
+
private startError(err: unknown, kind: QdrantStartFailureKind): Error {
|
|
438
|
+
if (err instanceof QdrantStartError) {
|
|
439
|
+
return err;
|
|
440
|
+
}
|
|
441
|
+
return new QdrantStartError(
|
|
442
|
+
err instanceof Error ? err.message : String(err),
|
|
443
|
+
kind,
|
|
444
|
+
null,
|
|
445
|
+
this.stdoutBuffer,
|
|
446
|
+
this.stderrBuffer,
|
|
447
|
+
{ cause: err },
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
|
|
314
451
|
private async waitForReady(): Promise<void> {
|
|
315
452
|
const start = Date.now();
|
|
316
453
|
// Build a single exited-promise once so each race reuses the same handle.
|
|
@@ -327,9 +464,13 @@ export class QdrantManager {
|
|
|
327
464
|
|
|
328
465
|
const throwOnExit = async (code: number): Promise<never> => {
|
|
329
466
|
await this.outputDrained;
|
|
330
|
-
throw new
|
|
467
|
+
throw new QdrantStartError(
|
|
331
468
|
`Qdrant process exited with code ${code} before becoming ready` +
|
|
332
469
|
this.formatCapturedOutput(),
|
|
470
|
+
"exited",
|
|
471
|
+
code,
|
|
472
|
+
this.stdoutBuffer,
|
|
473
|
+
this.stderrBuffer,
|
|
333
474
|
);
|
|
334
475
|
};
|
|
335
476
|
|
|
@@ -363,9 +504,13 @@ export class QdrantManager {
|
|
|
363
504
|
await throwOnExit(sleepOutcome.code);
|
|
364
505
|
}
|
|
365
506
|
}
|
|
366
|
-
throw new
|
|
507
|
+
throw new QdrantStartError(
|
|
367
508
|
`Qdrant did not become ready within ${this.readyzTimeoutMs}ms at ${this.url}` +
|
|
368
509
|
this.formatCapturedOutput(),
|
|
510
|
+
"not_ready",
|
|
511
|
+
null,
|
|
512
|
+
this.stdoutBuffer,
|
|
513
|
+
this.stderrBuffer,
|
|
369
514
|
);
|
|
370
515
|
}
|
|
371
516
|
|
|
@@ -30,6 +30,7 @@
|
|
|
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";
|
|
33
34
|
import type { LlmRequestLogsClickHouseConfig } from "../config/schemas/llm-request-logs.js";
|
|
34
35
|
import { credentialKey } from "../security/credential-key.js";
|
|
35
36
|
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
@@ -71,7 +72,7 @@ export interface ClickHouseLlmRequestLogSinkDeps {
|
|
|
71
72
|
resolveUrl?: () => Promise<string | null>;
|
|
72
73
|
/** Override the credential read for `clickhouse:password`. */
|
|
73
74
|
resolvePassword?: () => Promise<string | null>;
|
|
74
|
-
/** Override the
|
|
75
|
+
/** Override the in-memory platform assistant id. */
|
|
75
76
|
resolveAssistantId?: () => Promise<string | null>;
|
|
76
77
|
/** Override fetch for testing. */
|
|
77
78
|
fetchImpl?: ClickHouseSinkFetch;
|
|
@@ -98,8 +99,7 @@ export class ClickHouseLlmRequestLogSink implements LlmRequestLogWriter {
|
|
|
98
99
|
deps.resolvePassword ??
|
|
99
100
|
(() => readCredentialOrNull("clickhouse", "password"));
|
|
100
101
|
this.resolveAssistantId =
|
|
101
|
-
deps.resolveAssistantId ??
|
|
102
|
-
(() => readCredentialOrNull("vellum", "platform_assistant_id"));
|
|
102
|
+
deps.resolveAssistantId ?? resolvePlatformAssistantIdOrNull;
|
|
103
103
|
this.fetchImpl = deps.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -15,6 +15,7 @@
|
|
|
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";
|
|
18
19
|
import type { LlmRequestLogsClickHouseConfig } from "../config/schemas/llm-request-logs.js";
|
|
19
20
|
import { credentialKey } from "../security/credential-key.js";
|
|
20
21
|
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
@@ -104,7 +105,7 @@ export interface ClickHouseLlmRequestLogSourceDeps {
|
|
|
104
105
|
resolveUrl?: () => Promise<string | null>;
|
|
105
106
|
/** Override the credential read for `clickhouse:password`. */
|
|
106
107
|
resolvePassword?: () => Promise<string | null>;
|
|
107
|
-
/** Override the
|
|
108
|
+
/** Override the in-memory platform assistant id. */
|
|
108
109
|
resolveAssistantId?: () => Promise<string | null>;
|
|
109
110
|
/** Override the turn-id resolver (default: `getAssistantMessageIdsInTurn`). */
|
|
110
111
|
resolveTurnMessageIds?: (messageId: string) => string[];
|
|
@@ -138,8 +139,7 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
138
139
|
deps.resolvePassword ??
|
|
139
140
|
(() => readCredentialOrNull("clickhouse", "password"));
|
|
140
141
|
this.resolveAssistantId =
|
|
141
|
-
deps.resolveAssistantId ??
|
|
142
|
-
(() => readCredentialOrNull("vellum", "platform_assistant_id"));
|
|
142
|
+
deps.resolveAssistantId ?? resolvePlatformAssistantIdOrNull;
|
|
143
143
|
this.resolveTurnMessageIds =
|
|
144
144
|
deps.resolveTurnMessageIds ?? getAssistantMessageIdsInTurn;
|
|
145
145
|
this.resolveMessage = deps.resolveMessage ?? getMessageById;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Message cursors: the "(createdAt, id) after which" reference behind the
|
|
3
|
+
// messages-after reads, resilient to the referenced row being deleted.
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
//
|
|
6
|
+
// A bare message id bounds a read only while its row exists. A regenerated
|
|
7
|
+
// reply (the conversation retry route discards the latest assistant turn) or a
|
|
8
|
+
// retried turn deletes the row, and a caller holding just the id can no longer
|
|
9
|
+
// say where it sat. A `MessageCursor` carries the row's `createdAt` alongside
|
|
10
|
+
// its id, so the `(createdAt, id)` bound is reconstructible from the cursor
|
|
11
|
+
// alone. The live row stays authoritative whenever it exists.
|
|
12
|
+
|
|
13
|
+
import { eq } from "drizzle-orm";
|
|
14
|
+
|
|
15
|
+
import type { LineageBound } from "./conversation-lineage.js";
|
|
16
|
+
import { getDb } from "./db-connection.js";
|
|
17
|
+
import { messages } from "./schema/index.js";
|
|
18
|
+
|
|
19
|
+
export { messagesAfterBoundFilter } from "./conversation-lineage.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A `(createdAt, id)` message reference. `createdAt` is null when the holder
|
|
23
|
+
* never recorded it; such a cursor bounds a read only while its row exists.
|
|
24
|
+
*/
|
|
25
|
+
export interface MessageCursor {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly createdAt: number | null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Accepted "after" references: a message id, a {@link MessageCursor}, or
|
|
32
|
+
* null. `null`, `""`, and a cursor whose id is `""` all mean "no lower bound".
|
|
33
|
+
*/
|
|
34
|
+
export type MessagesAfterRef = string | MessageCursor | null;
|
|
35
|
+
|
|
36
|
+
/** Where a messages-after read starts. */
|
|
37
|
+
export type MessagesAfterBound =
|
|
38
|
+
/** No lower bound: every row the conversation owns. */
|
|
39
|
+
| { kind: "all" }
|
|
40
|
+
/** Rows strictly after `bound` in `(createdAt, id)` order. */
|
|
41
|
+
| { kind: "after"; bound: LineageBound }
|
|
42
|
+
/**
|
|
43
|
+
* The referenced row is gone and the reference carried no timestamp, so
|
|
44
|
+
* the read has no defensible starting point. Readers return nothing.
|
|
45
|
+
*/
|
|
46
|
+
| { kind: "vanished" };
|
|
47
|
+
|
|
48
|
+
/** The `(createdAt, id)` bound of a single message, or null when it is gone. */
|
|
49
|
+
export function loadMessageBound(messageId: string): LineageBound | null {
|
|
50
|
+
const row = getDb()
|
|
51
|
+
.select({ createdAt: messages.createdAt, id: messages.id })
|
|
52
|
+
.from(messages)
|
|
53
|
+
.where(eq(messages.id, messageId))
|
|
54
|
+
.get();
|
|
55
|
+
return row ?? null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Resolve an "after" reference to the bound a read filters on. A live row
|
|
60
|
+
* wins; a cursor whose row is gone falls back to the `createdAt` it carries,
|
|
61
|
+
* paired with its id so same-millisecond neighbours keep their order.
|
|
62
|
+
*/
|
|
63
|
+
export function resolveMessagesAfterBound(
|
|
64
|
+
after: MessagesAfterRef,
|
|
65
|
+
): MessagesAfterBound {
|
|
66
|
+
const id = typeof after === "string" ? after : (after?.id ?? "");
|
|
67
|
+
if (id === "") {
|
|
68
|
+
return { kind: "all" };
|
|
69
|
+
}
|
|
70
|
+
const live = loadMessageBound(id);
|
|
71
|
+
if (live) {
|
|
72
|
+
return { kind: "after", bound: live };
|
|
73
|
+
}
|
|
74
|
+
if (typeof after === "object" && after !== null && after.createdAt !== null) {
|
|
75
|
+
return { kind: "after", bound: { createdAt: after.createdAt, id } };
|
|
76
|
+
}
|
|
77
|
+
return { kind: "vanished" };
|
|
78
|
+
}
|
|
@@ -190,6 +190,36 @@ 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
|
+
|
|
193
223
|
/**
|
|
194
224
|
* The conversation that owns `messageId`, in any state, or null when the
|
|
195
225
|
* message does not exist.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
2
|
+
import { tableExists } from "./schema-introspection.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Add a required contact_id column to assistant_ingress_invites.
|
|
@@ -10,8 +11,16 @@ import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
|
10
11
|
* 1. Add the column as nullable.
|
|
11
12
|
* 2. Delete legacy rows that have no contact binding (NULL).
|
|
12
13
|
* 3. Rebuild the table to enforce NOT NULL (SQLite cannot ALTER COLUMN).
|
|
14
|
+
*
|
|
15
|
+
* The rebuild copies whichever session-id column is live:
|
|
16
|
+
* `source_conversation_id` (after migrateRenameCreatedBySessionIdColumns)
|
|
17
|
+
* or `created_by_session_id`.
|
|
13
18
|
*/
|
|
14
19
|
export function migrateInviteContactId(database: DrizzleDb): void {
|
|
20
|
+
if (!tableExists(database, "assistant_ingress_invites")) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
15
24
|
const raw = getSqliteFrom(database);
|
|
16
25
|
|
|
17
26
|
const cols = (
|
|
@@ -20,25 +29,28 @@ export function migrateInviteContactId(database: DrizzleDb): void {
|
|
|
20
29
|
notnull: number;
|
|
21
30
|
}>
|
|
22
31
|
).map((c) => ({ name: c.name, notnull: c.notnull }));
|
|
32
|
+
const colNames = new Set(cols.map((c) => c.name));
|
|
23
33
|
|
|
24
34
|
const col = cols.find((c) => c.name === "contact_id");
|
|
25
35
|
|
|
26
|
-
// Step 1: Add the column as nullable
|
|
27
36
|
if (!col) {
|
|
28
37
|
raw.exec(
|
|
29
38
|
/*sql*/ `ALTER TABLE assistant_ingress_invites ADD COLUMN contact_id TEXT`,
|
|
30
39
|
);
|
|
31
40
|
}
|
|
32
41
|
|
|
33
|
-
// Step 2: Delete legacy rows with no contact binding
|
|
34
42
|
raw.exec(
|
|
35
43
|
/*sql*/ `DELETE FROM assistant_ingress_invites WHERE contact_id IS NULL OR contact_id = ''`,
|
|
36
44
|
);
|
|
37
45
|
|
|
38
|
-
// Step 3: Rebuild the table with NOT NULL on contact_id
|
|
39
46
|
if (col && col.notnull === 1) {
|
|
40
47
|
return;
|
|
41
|
-
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const sessionCol = colNames.has("source_conversation_id")
|
|
51
|
+
? "source_conversation_id"
|
|
52
|
+
: "created_by_session_id";
|
|
53
|
+
const sessionSelect = colNames.has(sessionCol) ? sessionCol : "NULL";
|
|
42
54
|
|
|
43
55
|
raw.exec("PRAGMA foreign_keys = OFF");
|
|
44
56
|
try {
|
|
@@ -49,7 +61,7 @@ export function migrateInviteContactId(database: DrizzleDb): void {
|
|
|
49
61
|
id TEXT PRIMARY KEY,
|
|
50
62
|
source_channel TEXT NOT NULL,
|
|
51
63
|
token_hash TEXT NOT NULL,
|
|
52
|
-
|
|
64
|
+
${sessionCol} TEXT,
|
|
53
65
|
note TEXT,
|
|
54
66
|
max_uses INTEGER NOT NULL DEFAULT 1 CHECK (max_uses > 0),
|
|
55
67
|
use_count INTEGER NOT NULL DEFAULT 0 CHECK (use_count >= 0),
|
|
@@ -70,7 +82,7 @@ export function migrateInviteContactId(database: DrizzleDb): void {
|
|
|
70
82
|
);
|
|
71
83
|
|
|
72
84
|
INSERT INTO assistant_ingress_invites_new
|
|
73
|
-
SELECT id, source_channel, token_hash,
|
|
85
|
+
SELECT id, source_channel, token_hash, ${sessionSelect}, note,
|
|
74
86
|
max_uses, use_count, expires_at, status,
|
|
75
87
|
redeemed_by_external_user_id, redeemed_by_external_chat_id,
|
|
76
88
|
redeemed_at, expected_external_user_id, voice_code_hash,
|