@vellumai/assistant 0.11.2 → 0.11.3-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +58 -3
- package/docs/trusted-contact-access.md +9 -5
- package/docs/vellum-doctor.md +195 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
- package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
- package/node_modules/@vellumai/environments/src/index.ts +17 -6
- package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
- package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
- package/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
- package/openapi.yaml +589 -30
- package/package.json +1 -1
- package/src/__tests__/agent-image-optimize.test.ts +4 -4
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
- package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
- package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/answered-question-persistence.test.ts +240 -0
- package/src/__tests__/anthropic-provider.test.ts +165 -30
- package/src/__tests__/app-control-flow.test.ts +9 -8
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
- package/src/__tests__/attachments-store.test.ts +130 -68
- package/src/__tests__/attachments.test.ts +36 -36
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
- package/src/__tests__/canned-reply-release.test.ts +86 -0
- package/src/__tests__/channel-guardian.test.ts +59 -29
- package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
- package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
- package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/consult-deadline.test.ts +65 -0
- package/src/__tests__/conversation-agent-loop.test.ts +438 -2
- package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
- package/src/__tests__/conversation-disk-view.test.ts +4 -4
- package/src/__tests__/conversation-error.test.ts +22 -3
- package/src/__tests__/conversation-fork-crud.test.ts +5 -1
- package/src/__tests__/conversation-fork-referential.test.ts +352 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
- package/src/__tests__/conversation-group-tools.test.ts +32 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
- package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
- package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
- package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
- package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
- package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
- package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
- package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
- package/src/__tests__/conversation-queue.test.ts +433 -1
- package/src/__tests__/conversation-retry-route.test.ts +3 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
- package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
- package/src/__tests__/conversation-store.test.ts +26 -10
- package/src/__tests__/conversation-summarize-route.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
- package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
- package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
- package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
- package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
- package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
- package/src/__tests__/credential-prompt-route.test.ts +57 -7
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +89 -28
- package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
- package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
- package/src/__tests__/disk-pressure-guard.test.ts +55 -55
- package/src/__tests__/disk-pressure-routes.test.ts +10 -10
- package/src/__tests__/disk-pressure-tools.test.ts +2 -2
- package/src/__tests__/disk-usage.test.ts +35 -20
- package/src/__tests__/document-sync-tags.test.ts +379 -0
- package/src/__tests__/document-update-default-surface.test.ts +28 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
- package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
- package/src/__tests__/events-dev-bypass-actor.test.ts +183 -1
- package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
- package/src/__tests__/file-list-tool.test.ts +12 -10
- package/src/__tests__/file-ops-service.test.ts +151 -44
- package/src/__tests__/file-read-container-boundary.test.ts +137 -0
- package/src/__tests__/file-read-tool.test.ts +21 -9
- package/src/__tests__/file-url-path-guard.test.ts +83 -0
- package/src/__tests__/filesystem-tools.test.ts +82 -66
- package/src/__tests__/guardian-outbound-http.test.ts +8 -8
- package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
- package/src/__tests__/helpers/hub-clients.ts +42 -0
- package/src/__tests__/helpers/mock-conversation.ts +46 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
- package/src/__tests__/history-repair.test.ts +112 -12
- package/src/__tests__/host-bash-proxy.test.ts +10 -5
- package/src/__tests__/host-bash-routes.test.ts +67 -0
- package/src/__tests__/host-browser-proxy.test.ts +2 -2
- package/src/__tests__/host-cu-proxy.test.ts +3 -7
- package/src/__tests__/host-file-proxy.test.ts +3 -7
- package/src/__tests__/host-file-read-tool.test.ts +5 -1
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
- package/src/__tests__/http-conversation-lineage.test.ts +2 -5
- package/src/__tests__/http-user-message-parity.test.ts +44 -0
- package/src/__tests__/identity-routes.test.ts +13 -13
- package/src/__tests__/image-conversion.test.ts +29 -26
- package/src/__tests__/image-source-path-reinject.test.ts +2 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
- package/src/__tests__/introduction-card-resolver.test.ts +6 -1
- package/src/__tests__/list-messages-attachments.test.ts +56 -32
- package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
- package/src/__tests__/list-messages-page-latest.test.ts +61 -61
- package/src/__tests__/list-messages-provider-error.test.ts +6 -6
- package/src/__tests__/list-messages-queued.test.ts +49 -6
- package/src/__tests__/list-messages-system-card.test.ts +4 -4
- package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
- package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
- package/src/__tests__/llm-usage-store.test.ts +55 -0
- package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
- package/src/__tests__/media-stream-server-integration.test.ts +36 -0
- package/src/__tests__/migration-export-http.test.ts +1 -1
- package/src/__tests__/migration-import-commit-http.test.ts +1 -1
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
- package/src/__tests__/migration-validate-http.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +65 -3
- package/src/__tests__/notification-platform-adapter.test.ts +104 -0
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
- package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
- package/src/__tests__/path-policy.test.ts +164 -1
- package/src/__tests__/persist-media-references.test.ts +2 -2
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
- package/src/__tests__/persist-unsendable-image.test.ts +23 -23
- package/src/__tests__/persona-resolver.test.ts +154 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
- package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
- package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
- package/src/__tests__/profiler-routes.test.ts +13 -13
- package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
- package/src/__tests__/proxy-approval-callback.test.ts +3 -3
- package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
- package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
- package/src/__tests__/resolve-trust-class.test.ts +20 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
- package/src/__tests__/run-due-schedules.test.ts +174 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
- package/src/__tests__/schedule-routes.test.ts +730 -8
- package/src/__tests__/schedule-store.test.ts +540 -0
- package/src/__tests__/schedule-tools.test.ts +103 -0
- package/src/__tests__/scheduler-wake.test.ts +5 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
- package/src/__tests__/secure-keys.test.ts +91 -0
- package/src/__tests__/server-history-render.test.ts +97 -7
- package/src/__tests__/size-guard.test.ts +8 -8
- package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
- package/src/__tests__/skill-tool-factory.test.ts +247 -0
- package/src/__tests__/skills-install-staging.test.ts +15 -6
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
- package/src/__tests__/slack-inbound-verification.test.ts +4 -1
- package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
- package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
- package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
- package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
- package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
- package/src/__tests__/subagent-disposal.test.ts +10 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
- package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
- package/src/__tests__/subagent-manager-notify.test.ts +148 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/subagent-persistence.test.ts +141 -0
- package/src/__tests__/subagent-role-registry.test.ts +172 -63
- package/src/__tests__/subagent-role-resolution.test.ts +88 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
- package/src/__tests__/subagent-terminal-message.test.ts +88 -1
- package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
- package/src/__tests__/subagent-tools.test.ts +1901 -108
- package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
- package/src/__tests__/system-prompt.test.ts +82 -7
- package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
- package/src/__tests__/tool-result-spool.test.ts +74 -18
- package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
- package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
- package/src/__tests__/tools-audio-read.test.ts +10 -10
- package/src/__tests__/tools-get-route.test.ts +85 -12
- package/src/__tests__/tools-list-cli.test.ts +171 -0
- package/src/__tests__/top-level-renderer.test.ts +54 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
- package/src/__tests__/turn-tail-chain.test.ts +135 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
- package/src/__tests__/ui-visual-surface.test.ts +5 -4
- package/src/__tests__/ui-work-result-surface.test.ts +5 -4
- package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
- package/src/__tests__/usage-routes.test.ts +62 -0
- package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
- package/src/__tests__/visible-app-context.test.ts +20 -4
- package/src/__tests__/web-search-history.test.ts +96 -0
- package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
- package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
- package/src/acp/failure-error.ts +3 -5
- package/src/agent/attachments.ts +26 -24
- package/src/agent/history-repair/history-repair.ts +27 -26
- package/src/agent/image-optimize.ts +6 -6
- package/src/agent/loop.ts +40 -22
- package/src/agent/message-types.ts +3 -3
- package/src/api/constants/document-tools.ts +55 -0
- package/src/api/events/question-answered.ts +53 -0
- package/src/api/events/tool-result.ts +7 -0
- package/src/api/index.ts +13 -0
- package/src/api/responses/conversation-message.ts +11 -0
- package/src/api/surfaces-oauth-connect.test.ts +96 -0
- package/src/api/surfaces.ts +36 -8
- package/src/approvals/guardian-channel-delivery.ts +83 -0
- package/src/approvals/guardian-expiry-notifier.ts +13 -11
- package/src/approvals/guardian-request-resolvers.ts +222 -135
- package/src/calls/__tests__/voice-session-bridge.test.ts +50 -0
- package/src/calls/media-stream-server.ts +9 -1
- package/src/calls/voice-session-bridge.ts +38 -0
- package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
- package/src/channels/config.ts +7 -2
- package/src/channels/gateway-verification-sessions.ts +7 -2
- package/src/channels/types.ts +7 -1
- package/src/cli/commands/__tests__/cache.test.ts +7 -4
- package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
- package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
- package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
- package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
- package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
- package/src/cli/commands/__tests__/plugins.test.ts +692 -0
- package/src/cli/commands/__tests__/schedules.test.ts +136 -37
- package/src/cli/commands/conversations.ts +7 -3
- package/src/cli/commands/credentials.help.ts +7 -0
- package/src/cli/commands/inference-profiles.ts +9 -3
- package/src/cli/commands/inference.help.ts +16 -2
- package/src/cli/commands/mcp.help.ts +4 -2
- package/src/cli/commands/memory/memory-retrospective.ts +18 -0
- package/src/cli/commands/notifications.ts +3 -6
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
- package/src/cli/commands/oauth/connect.test.ts +26 -1
- package/src/cli/commands/oauth/connect.ts +4 -1
- package/src/cli/commands/oauth/index.help.ts +3 -1
- package/src/cli/commands/oauth/providers.ts +3 -0
- package/src/cli/commands/plugins.help.ts +25 -2
- package/src/cli/commands/plugins.ts +289 -10
- package/src/cli/commands/schedules.help.ts +14 -12
- package/src/cli/commands/schedules.ts +19 -5
- package/src/cli/commands/tools.help.ts +4 -2
- package/src/cli/commands/tools.ts +38 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
- package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +122 -0
- package/src/cli/lib/install-from-github.ts +61 -0
- package/src/cli/lib/install-from-platform.ts +13 -2
- package/src/cli/lib/plugin-surfaces.ts +124 -4
- package/src/cli/lib/upgrade-plugin.ts +18 -0
- package/src/cli.ts +1 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
- package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
- package/src/config/__tests__/profile-tool-support.test.ts +131 -0
- package/src/config/bundled-skills/AGENTS.md +1 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
- package/src/config/bundled-skills/schedule/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
- package/src/config/bundled-skills/subagent/SKILL.md +53 -22
- package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
- package/src/config/bundled-skills/visualize/SKILL.md +1 -1
- package/src/config/default-profile-catalog.ts +6 -2
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +45 -15
- package/src/config/loader.ts +70 -1
- package/src/config/profile-tool-support.ts +110 -0
- package/src/config/sanitize-for-transfer.ts +11 -0
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/stt.test.ts +20 -5
- package/src/config/schemas/channels.ts +13 -0
- package/src/config/schemas/memory-retrospective.ts +25 -0
- package/src/config/schemas/plugin-updates.ts +55 -0
- package/src/config/schemas/services.ts +8 -4
- package/src/config/schemas/stt.ts +17 -5
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
- package/src/contacts/guardian-delivery-reader.ts +29 -2
- package/src/context/compactor.ts +4 -4
- package/src/context/post-turn-tool-result-truncation.ts +32 -16
- package/src/context/strip-injections.ts +42 -0
- package/src/context/tool-result-spool.ts +32 -18
- package/src/credential-execution/ces-runtime.ts +3 -0
- package/src/credential-execution/client.ts +22 -1
- package/src/credential-execution/process-manager.test.ts +99 -0
- package/src/credential-execution/process-manager.ts +62 -16
- package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
- package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
- package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
- package/src/daemon/channel-ui-capability.ts +4 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
- package/src/daemon/conversation-agent-loop.ts +318 -148
- package/src/daemon/conversation-attachments.ts +1 -1
- package/src/daemon/conversation-error.ts +8 -1
- package/src/daemon/conversation-initial-prompt.ts +16 -38
- package/src/daemon/conversation-lifecycle.ts +154 -32
- package/src/daemon/conversation-messaging.ts +106 -43
- package/src/daemon/conversation-process.ts +131 -33
- package/src/daemon/conversation-queue-manager.ts +10 -0
- package/src/daemon/conversation-runtime-assembly.ts +9 -4
- package/src/daemon/conversation-store.ts +52 -3
- package/src/daemon/conversation-surface-state.ts +9 -0
- package/src/daemon/conversation-surfaces.ts +403 -210
- package/src/daemon/conversation-tool-setup.ts +56 -7
- package/src/daemon/conversation-turn-finalize.ts +134 -89
- package/src/daemon/conversation.ts +111 -27
- package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
- package/src/daemon/disk-pressure-guard.ts +3 -3
- package/src/daemon/doordash-steps.ts +5 -5
- package/src/daemon/external-plugins-bootstrap.ts +7 -1
- package/src/daemon/handlers/config-channels.ts +48 -5
- package/src/daemon/handlers/conversation-history.ts +1 -1
- package/src/daemon/handlers/conversations.ts +62 -17
- package/src/daemon/handlers/shared.ts +12 -0
- package/src/daemon/handlers/skills.ts +11 -1
- package/src/daemon/identity-helpers.ts +38 -10
- package/src/daemon/install-assistant-command.ts +322 -0
- package/src/daemon/lifecycle.ts +14 -3
- package/src/daemon/message-types/conversations.ts +6 -7
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/persist-media-references.ts +23 -14
- package/src/daemon/process-message.ts +6 -6
- package/src/daemon/tool-setup-types.ts +19 -122
- package/src/daemon/tool-side-effects.ts +17 -94
- package/src/daemon/trust-context-types.ts +39 -0
- package/src/daemon/trust-context.ts +14 -6
- package/src/daemon/turn-tail-chain.ts +73 -0
- package/src/daemon/web-search-history.ts +47 -33
- package/src/heartbeat/heartbeat-service.ts +6 -6
- package/src/ipc/__tests__/socket-path.test.ts +21 -0
- package/src/ipc/assistant-server.ts +17 -10
- package/src/ipc/cli-client.ts +10 -1
- package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
- package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
- package/src/ipc/socket-cleanup.ts +9 -7
- package/src/ipc/socket-path.ts +4 -96
- package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
- package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
- package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
- package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
- package/src/live-voice/__tests__/protocol.test.ts +52 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
- package/src/live-voice/live-voice-archive.ts +13 -13
- package/src/live-voice/live-voice-connection.ts +7 -1
- package/src/live-voice/live-voice-photo.ts +169 -0
- package/src/live-voice/live-voice-session.ts +108 -4
- package/src/live-voice/protocol.ts +89 -1
- package/src/mcp/client.ts +10 -0
- package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
- package/src/messaging/providers/callback-routing.ts +1 -0
- package/src/messaging/providers/discord/api.ts +312 -0
- package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
- package/src/messaging/providers/discord/render.test.ts +204 -0
- package/src/messaging/providers/discord/render.ts +195 -0
- package/src/messaging/providers/discord/send.test.ts +179 -0
- package/src/messaging/providers/discord/send.ts +212 -0
- package/src/messaging/providers/discord/transport.ts +81 -0
- package/src/messaging/providers/index.ts +3 -1
- package/src/messaging/providers/retry-policy.test.ts +247 -0
- package/src/messaging/providers/retry-policy.ts +206 -0
- package/src/messaging/providers/slack/mention-source.test.ts +285 -0
- package/src/messaging/providers/slack/mention-source.ts +287 -0
- package/src/messaging/providers/telegram-bot/api.ts +47 -130
- package/src/messaging/providers/whatsapp/api.ts +47 -136
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +332 -0
- package/src/monitoring/db-integrity-sample.ts +6 -1
- package/src/monitoring/plugin-auto-update.ts +359 -0
- package/src/monitoring/resource-sampler.ts +21 -5
- package/src/monitoring/worker.ts +13 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
- package/src/notifications/__tests__/broadcaster.test.ts +37 -1
- package/src/notifications/__tests__/copy-composer.test.ts +165 -0
- package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
- package/src/notifications/__tests__/notification-utils.test.ts +249 -0
- package/src/notifications/adapters/platform.ts +31 -2
- package/src/notifications/assistant-reply-producer.ts +79 -32
- package/src/notifications/broadcaster.ts +30 -10
- package/src/notifications/copy-composer.ts +69 -0
- package/src/notifications/emit-signal.ts +82 -15
- package/src/notifications/events-store.ts +10 -2
- package/src/notifications/home-feed-side-effect.ts +6 -3
- package/src/notifications/notification-utils.ts +173 -5
- package/src/notifications/signal.ts +12 -0
- package/src/oauth/AGENTS.md +4 -2
- package/src/oauth/byo-connection.ts +6 -1
- package/src/oauth/credential-token-resolver.ts +3 -10
- package/src/oauth/manual-token-connection.ts +29 -64
- package/src/oauth/manual-token-providers.ts +62 -0
- package/src/oauth/provider-serializer.ts +13 -0
- package/src/oauth/seed-providers.ts +62 -11
- package/src/onboarding/onboarding-events-store.ts +91 -1
- package/src/permissions/question-prompter.test.ts +4 -0
- package/src/permissions/question-prompter.ts +21 -4
- package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
- package/src/persistence/attachments-store.ts +15 -15
- package/src/persistence/conversation-attention-store.ts +30 -10
- package/src/persistence/conversation-bootstrap.ts +17 -0
- package/src/persistence/conversation-crud.ts +363 -97
- package/src/persistence/conversation-group-migration.ts +1 -1
- package/src/persistence/conversation-key-store.ts +38 -10
- package/src/persistence/conversation-lineage.ts +226 -0
- package/src/persistence/conversation-plugin-facade.ts +28 -3
- package/src/persistence/conversation-queries.ts +207 -33
- package/src/persistence/conversation-types.ts +107 -1
- package/src/persistence/jobs-store.ts +32 -8
- package/src/persistence/llm-usage-store.ts +22 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
- package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
- package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
- package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
- package/src/persistence/schema/conversations.ts +32 -0
- package/src/persistence/schema/infrastructure.ts +3 -0
- package/src/persistence/steps.ts +30 -0
- package/src/persistence/subagent-store.ts +148 -6
- package/src/platform/managed-speech.test.ts +20 -0
- package/src/platform/managed-speech.ts +9 -0
- package/src/plugin-api/index.ts +8 -0
- package/src/plugin-api/webhook-url.ts +151 -0
- package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
- package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
- package/src/plugins/collect-source-versions.ts +4 -27
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
- package/src/plugins/defaults/exploration-drift/package.json +1 -1
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
- package/src/plugins/defaults/image-recovery/recover.ts +67 -57
- package/src/plugins/defaults/index.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
- package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
- package/src/plugins/defaults/memory/job-handlers.ts +87 -5
- package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
- package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
- package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
- package/src/plugins/defaults/memory/v2/router.ts +8 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
- package/src/plugins/external-plugin-loader.ts +17 -8
- package/src/plugins/installed-plugin-dirs.ts +101 -0
- package/src/plugins/mtime-cache.ts +34 -22
- package/src/plugins/types.ts +69 -8
- package/src/prompts/persona-resolver.ts +6 -2
- package/src/prompts/system-prompt.ts +72 -17
- package/src/providers/__tests__/inference.test.ts +40 -0
- package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
- package/src/providers/__tests__/retry-callsite.test.ts +67 -0
- package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
- package/src/providers/anthropic/client.ts +112 -95
- package/src/providers/connection-resolution.ts +35 -1
- package/src/providers/gemini/client.ts +5 -5
- package/src/providers/inference/adapter-factory.ts +16 -10
- package/src/providers/inference/auth.ts +16 -0
- package/src/providers/inference/connection-availability.ts +164 -12
- package/src/providers/inference/connections.ts +25 -1
- package/src/providers/media-resolve.ts +21 -11
- package/src/providers/model-catalog.ts +15 -0
- package/src/providers/openai/chat-completions-provider.ts +4 -4
- package/src/providers/openai/responses-provider.ts +12 -25
- package/src/providers/registry.ts +9 -4
- package/src/providers/retry.ts +25 -0
- package/src/providers/server-tool-pairing.ts +134 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +187 -6
- package/src/providers/speech-to-text/deepgram.ts +1 -0
- package/src/providers/speech-to-text/resolve.ts +80 -10
- package/src/providers/speech-to-text/vellum-managed.ts +7 -1
- package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
- package/src/providers/types.ts +26 -6
- package/src/providers/vellum-model-routing.ts +6 -7
- package/src/runtime/AGENTS.md +2 -0
- package/src/runtime/__tests__/agent-wake.test.ts +16 -16
- package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
- package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
- package/src/runtime/agent-wake.ts +63 -24
- package/src/runtime/assistant-event-hub.ts +87 -12
- package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
- package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
- package/src/runtime/auth/same-actor.ts +56 -8
- package/src/runtime/auth/scopes.ts +12 -0
- package/src/runtime/auth/types.ts +2 -0
- package/src/runtime/background-job-runner.ts +5 -27
- package/src/runtime/channel-readiness-service.ts +59 -3
- package/src/runtime/channel-readiness-types.ts +18 -0
- package/src/runtime/desktop-presence.ts +69 -0
- package/src/runtime/http-server.ts +12 -0
- package/src/runtime/local-actor-identity.ts +11 -9
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +173 -1
- package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
- package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
- package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
- package/src/runtime/routes/archive-utils.ts +16 -12
- package/src/runtime/routes/attachment-routes.ts +13 -6
- package/src/runtime/routes/canned-reply-release.ts +54 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -27
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
- package/src/runtime/routes/client-routes.ts +114 -2
- package/src/runtime/routes/conversation-cli-routes.ts +10 -12
- package/src/runtime/routes/conversation-list-routes.ts +59 -10
- package/src/runtime/routes/conversation-management-routes.ts +47 -18
- package/src/runtime/routes/conversation-query-routes.ts +32 -53
- package/src/runtime/routes/conversation-routes.ts +360 -293
- package/src/runtime/routes/credential-prompt-routes.ts +23 -2
- package/src/runtime/routes/debug-routes.ts +4 -1
- package/src/runtime/routes/default-provider-routes.ts +7 -11
- package/src/runtime/routes/documents-routes.ts +44 -1
- package/src/runtime/routes/events-routes.ts +28 -1
- package/src/runtime/routes/host-app-control-routes.ts +2 -0
- package/src/runtime/routes/host-bash-routes.ts +2 -0
- package/src/runtime/routes/host-browser-routes.ts +2 -0
- package/src/runtime/routes/host-cu-routes.ts +2 -0
- package/src/runtime/routes/host-file-routes.ts +2 -0
- package/src/runtime/routes/host-transfer-routes.ts +4 -0
- package/src/runtime/routes/identity-routes.ts +6 -6
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
- package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
- package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
- package/src/runtime/routes/inference-profiles-routes.ts +152 -73
- package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
- package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
- package/src/runtime/routes/log-export-routes.ts +1 -1
- package/src/runtime/routes/notification-routes.ts +0 -14
- package/src/runtime/routes/oauth-providers.ts +1 -0
- package/src/runtime/routes/plugins-routes.ts +106 -1
- package/src/runtime/routes/profiler-routes.ts +4 -2
- package/src/runtime/routes/question-routes.ts +28 -10
- package/src/runtime/routes/retrospective-routes.ts +9 -3
- package/src/runtime/routes/schedule-routes.ts +210 -12
- package/src/runtime/routes/secret-routes.ts +40 -23
- package/src/runtime/routes/settings-routes.ts +41 -13
- package/src/runtime/routes/skills-routes.ts +79 -0
- package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
- package/src/runtime/routes/wake-conversation-routes.ts +23 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +24 -9
- package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
- package/src/runtime/sync/resource-sync-events.ts +79 -1
- package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
- package/src/runtime/sync/worker-daemon-notify.ts +44 -6
- package/src/runtime/verification-outbound-actions.ts +250 -222
- package/src/runtime/verification-templates.ts +41 -30
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
- package/src/schedule/inference-profile.ts +64 -3
- package/src/schedule/plugin-schedule-declarations.ts +518 -0
- package/src/schedule/plugin-schedule-reconciler.ts +605 -0
- package/src/schedule/plugin-schedules-gate.ts +23 -0
- package/src/schedule/schedule-store.ts +520 -26
- package/src/schedule/scheduler.ts +38 -0
- package/src/security/credential-backend.ts +51 -4
- package/src/security/encrypted-store.ts +64 -42
- package/src/security/secure-keys.ts +55 -7
- package/src/skills/catalog-install.ts +20 -7
- package/src/skills/inline-command-runner.ts +2 -7
- package/src/skills/skill-history.test.ts +269 -0
- package/src/skills/skill-history.ts +250 -0
- package/src/skills/skillssh-registry.ts +1 -1
- package/src/stt/daemon-batch-transcriber.ts +8 -6
- package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
- package/src/subagent/consult-prompt.ts +3 -1
- package/src/subagent/consult-transcript.ts +1 -1
- package/src/subagent/manager.ts +304 -44
- package/src/subagent/progress-events.ts +35 -0
- package/src/subagent/role-resolution.ts +88 -0
- package/src/subagent/types.ts +302 -67
- package/src/subagent/validate-allowlists.ts +3 -4
- package/src/telegram/__tests__/webhook-health.test.ts +73 -1
- package/src/telegram/webhook-health.ts +101 -3
- package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
- package/src/telemetry/activation-funnel.ts +6 -1
- package/src/telemetry/live-voice-funnel.ts +75 -0
- package/src/telemetry/telemetry-event-sources.ts +6 -0
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire.generated.ts +2 -0
- package/src/telemetry/types.ts +23 -4
- package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
- package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
- package/src/tools/ask-question/ask-question-tool.ts +56 -2
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/calls/call-start.ts +8 -5
- package/src/tools/conversation-groups/move_to_group.ts +10 -12
- package/src/tools/document/document-tool.ts +11 -4
- package/src/tools/execution-timeout.ts +9 -2
- package/src/tools/executor.ts +7 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +7 -13
- package/src/tools/filesystem/search.ts +23 -21
- package/src/tools/filesystem/write.ts +4 -1
- package/src/tools/host-filesystem/edit.ts +7 -2
- package/src/tools/host-filesystem/read.ts +21 -8
- package/src/tools/host-filesystem/write.ts +10 -2
- package/src/tools/host-terminal/host-shell.ts +2 -2
- package/src/tools/mcp/mcp-tool-factory.ts +25 -1
- package/src/tools/permission-checker.ts +8 -3
- package/src/tools/schedule/delete.ts +13 -1
- package/src/tools/schedule/list.ts +14 -3
- package/src/tools/schedule/update.ts +56 -33
- package/src/tools/shared/filesystem/audio-read.ts +6 -4
- package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
- package/src/tools/shared/filesystem/image-read.ts +12 -12
- package/src/tools/shared/filesystem/path-policy.ts +70 -5
- package/src/tools/shared/filesystem/size-guard.ts +6 -6
- package/src/tools/shared/input-misuse.ts +72 -0
- package/src/tools/skills/scaffold-managed.ts +82 -0
- package/src/tools/skills/skill-tool-factory.ts +14 -1
- package/src/tools/subagent/consult-deadline.ts +12 -7
- package/src/tools/subagent/message.ts +3 -1
- package/src/tools/subagent/read.ts +66 -4
- package/src/tools/subagent/spawn.ts +500 -78
- package/src/tools/tool-approval-handler.ts +45 -4
- package/src/tools/types.ts +22 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
- package/src/tools/ui-surface/visual-validation.ts +2 -0
- package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
- package/src/usage/subagent-attribution.ts +108 -0
- package/src/util/__tests__/sqlite-retry.test.ts +112 -0
- package/src/util/abort-reasons.ts +16 -0
- package/src/util/ansi.ts +44 -0
- package/src/util/disk-usage.ts +17 -13
- package/src/util/image-conversion.ts +20 -13
- package/src/util/schedule-source-key.ts +23 -0
- package/src/util/worker-process.ts +7 -1
- package/src/workspace/git-service.ts +33 -9
- package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
- package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/workspace/top-level-renderer.ts +15 -2
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
- package/src/daemon/install-symlink.ts +0 -207
- package/src/notifications/deferred-emit.ts +0 -147
|
@@ -35,8 +35,6 @@ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
|
35
35
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
36
36
|
import {
|
|
37
37
|
cancelOutbound,
|
|
38
|
-
deliverVerificationEmail,
|
|
39
|
-
deliverVerificationSlack,
|
|
40
38
|
normalizeTelegramDestination,
|
|
41
39
|
resendOutbound,
|
|
42
40
|
startOutbound,
|
|
@@ -152,16 +150,6 @@ export async function handleCreateVerificationSession({
|
|
|
152
150
|
verificationRateLimiter.recordFailure(rateLimitKey);
|
|
153
151
|
}
|
|
154
152
|
|
|
155
|
-
// Dispatch delivery from the daemon process (not sandboxed).
|
|
156
|
-
if (result._pendingSlackDm) {
|
|
157
|
-
const { userId, text, assistantId: aid } = result._pendingSlackDm;
|
|
158
|
-
deliverVerificationSlack(userId, text, aid);
|
|
159
|
-
}
|
|
160
|
-
if (result._pendingEmail) {
|
|
161
|
-
const { to, text, subject, assistantId: aid } = result._pendingEmail;
|
|
162
|
-
deliverVerificationEmail(to, text, subject, aid);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
153
|
if (!result.success) {
|
|
166
154
|
if (result.error === "rate_limited") {
|
|
167
155
|
throw new TooManyRequestsError(
|
|
@@ -174,9 +162,7 @@ export async function handleCreateVerificationSession({
|
|
|
174
162
|
);
|
|
175
163
|
}
|
|
176
164
|
|
|
177
|
-
|
|
178
|
-
const { _pendingSlackDm: _, _pendingEmail: __, ...publicResult } = result;
|
|
179
|
-
return publicResult;
|
|
165
|
+
return result;
|
|
180
166
|
}
|
|
181
167
|
|
|
182
168
|
// Inbound challenge path
|
|
@@ -222,16 +208,6 @@ export async function handleResendVerificationSession({
|
|
|
222
208
|
|
|
223
209
|
const result = await resendOutbound({ channel, originConversationId });
|
|
224
210
|
|
|
225
|
-
// Dispatch delivery from the daemon process (not sandboxed).
|
|
226
|
-
if (result._pendingSlackDm) {
|
|
227
|
-
const { userId, text, assistantId: aid } = result._pendingSlackDm;
|
|
228
|
-
deliverVerificationSlack(userId, text, aid);
|
|
229
|
-
}
|
|
230
|
-
if (result._pendingEmail) {
|
|
231
|
-
const { to, text, subject, assistantId: aid } = result._pendingEmail;
|
|
232
|
-
deliverVerificationEmail(to, text, subject, aid);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
211
|
if (!result.success) {
|
|
236
212
|
if (result.error === "rate_limited") {
|
|
237
213
|
throw new TooManyRequestsError(
|
|
@@ -243,8 +219,7 @@ export async function handleResendVerificationSession({
|
|
|
243
219
|
);
|
|
244
220
|
}
|
|
245
221
|
|
|
246
|
-
|
|
247
|
-
return publicResult;
|
|
222
|
+
return result;
|
|
248
223
|
}
|
|
249
224
|
|
|
250
225
|
/**
|
|
@@ -159,8 +159,13 @@ async function handleExchange(args: RouteHandlerArgs) {
|
|
|
159
159
|
|
|
160
160
|
const existing = getConnection(db, CONNECTION_NAME);
|
|
161
161
|
if (existing) {
|
|
162
|
+
// Stamp the provider with the auth: this row is the subscription
|
|
163
|
+
// connection by name, and dispatch derives auth from the provider for
|
|
164
|
+
// managed rows, so a claiming row with e.g. provider "vellum" would
|
|
165
|
+
// otherwise strand the fresh token behind derived platform auth.
|
|
162
166
|
const updateResult = updateConnection(db, CONNECTION_NAME, {
|
|
163
167
|
auth: authInput,
|
|
168
|
+
provider: "openai",
|
|
164
169
|
});
|
|
165
170
|
if (!updateResult.ok) {
|
|
166
171
|
log.error(
|
|
@@ -10,15 +10,33 @@ import { z } from "zod";
|
|
|
10
10
|
import type { HostProxyCapability } from "../../channels/types.js";
|
|
11
11
|
import { isHttpAuthDisabled } from "../../config/env.js";
|
|
12
12
|
import { datesToISO } from "../../util/json.js";
|
|
13
|
-
import {
|
|
13
|
+
import { getLogger } from "../../util/logger.js";
|
|
14
|
+
import {
|
|
15
|
+
assistantEventHub,
|
|
16
|
+
DESKTOP_PRESENCE_STATES,
|
|
17
|
+
} from "../assistant-event-hub.js";
|
|
14
18
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
15
19
|
import {
|
|
16
20
|
DEFAULT_HEARTBEAT_INTERVAL_MS,
|
|
17
21
|
isClientDegraded,
|
|
18
22
|
} from "../client-health.js";
|
|
19
|
-
import { NotFoundError } from "./errors.js";
|
|
23
|
+
import { BadRequestError, NotFoundError } from "./errors.js";
|
|
24
|
+
import { parseBody } from "./parse-body.js";
|
|
20
25
|
import type { RouteDefinition } from "./types.js";
|
|
21
26
|
|
|
27
|
+
const log = getLogger("client-routes");
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Body of `POST /v1/clients/presence`, declared as the route's `requestBody`
|
|
31
|
+
* and parsed by the handler, so the OpenAPI contract and the runtime check are
|
|
32
|
+
* one schema rather than two hand-kept copies.
|
|
33
|
+
*/
|
|
34
|
+
const PresenceBodySchema = z.object({
|
|
35
|
+
state: z
|
|
36
|
+
.enum(DESKTOP_PRESENCE_STATES)
|
|
37
|
+
.describe("Reported desktop presence state."),
|
|
38
|
+
});
|
|
39
|
+
|
|
22
40
|
export const ROUTES: RouteDefinition[] = [
|
|
23
41
|
{
|
|
24
42
|
operationId: "list_clients",
|
|
@@ -116,4 +134,98 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
116
134
|
return { disconnected: count };
|
|
117
135
|
},
|
|
118
136
|
},
|
|
137
|
+
{
|
|
138
|
+
operationId: "report_client_presence",
|
|
139
|
+
endpoint: "clients/presence",
|
|
140
|
+
method: "POST",
|
|
141
|
+
policy: {
|
|
142
|
+
requiredScopes: ["settings.write"],
|
|
143
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
144
|
+
},
|
|
145
|
+
summary: "Report desktop presence",
|
|
146
|
+
description:
|
|
147
|
+
"Record the desktop presence state reported by the client identified by the X-Vellum-Client-Id header.",
|
|
148
|
+
tags: ["clients"],
|
|
149
|
+
requestBody: PresenceBodySchema,
|
|
150
|
+
responseBody: z.object({
|
|
151
|
+
recorded: z
|
|
152
|
+
.boolean()
|
|
153
|
+
.describe("Whether a connected client matched the reporting clientId."),
|
|
154
|
+
}),
|
|
155
|
+
handler: ({ body, headers }) => {
|
|
156
|
+
const clientId = headers?.["x-vellum-client-id"]?.trim();
|
|
157
|
+
if (!clientId) {
|
|
158
|
+
throw new BadRequestError(
|
|
159
|
+
"x-vellum-client-id header is required to report presence.",
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
const { state } = parseBody(PresenceBodySchema, body);
|
|
163
|
+
|
|
164
|
+
// Resolving the client first separates "nobody is listening" from
|
|
165
|
+
// "somebody else owns this", so only the second one is worth a warn.
|
|
166
|
+
const client = assistantEventHub.getClientById(clientId);
|
|
167
|
+
if (!client) {
|
|
168
|
+
// Debug, not warn: a report racing an SSE reconnect matches nothing,
|
|
169
|
+
// and a reconnect storm would otherwise emit a warn per client every
|
|
170
|
+
// 30 seconds for a benign race. Not a 404 either, for the same reason.
|
|
171
|
+
log.debug(
|
|
172
|
+
{ op: "report_client_presence", state },
|
|
173
|
+
"Presence report matched no connected client",
|
|
174
|
+
);
|
|
175
|
+
return { recorded: false };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Only the actor that opened the target client's SSE stream may report
|
|
179
|
+
// its presence, so a caller who learns another user's clientId cannot
|
|
180
|
+
// spoof that desktop. Clients with no stored `actorPrincipalId` (legacy
|
|
181
|
+
// SSE subscribers, service-gateway tokens) never match: fail-closed, the
|
|
182
|
+
// same posture as the listing filter above. Dev-bypass mode
|
|
183
|
+
// (DISABLE_HTTP_AUTH=true) skips the check for platform-managed
|
|
184
|
+
// deployments where the platform handles auth.
|
|
185
|
+
if (!isHttpAuthDisabled()) {
|
|
186
|
+
const callerPrincipalId = headers?.["x-vellum-actor-principal-id"];
|
|
187
|
+
const ownerPrincipalId = client.actorPrincipalId;
|
|
188
|
+
if (
|
|
189
|
+
ownerPrincipalId === undefined ||
|
|
190
|
+
ownerPrincipalId !== callerPrincipalId
|
|
191
|
+
) {
|
|
192
|
+
// Warn, not debug: the client is connected, so a mismatch means the
|
|
193
|
+
// gateway stopped forwarding the actor header, a scope profile
|
|
194
|
+
// shifted, or a caller is probing someone else's client. Without this
|
|
195
|
+
// line presence gating dies silently and every suppressed push
|
|
196
|
+
// quietly resumes. Client and principal ids stay out of the entry so
|
|
197
|
+
// the log cannot be used to enumerate them.
|
|
198
|
+
log.warn(
|
|
199
|
+
{
|
|
200
|
+
op: "report_client_presence",
|
|
201
|
+
hasStoredOwner: ownerPrincipalId !== undefined,
|
|
202
|
+
hasCallerPrincipal: callerPrincipalId !== undefined,
|
|
203
|
+
targetInterfaceId: client.interfaceId,
|
|
204
|
+
},
|
|
205
|
+
"Rejecting presence report from a caller that does not own the client",
|
|
206
|
+
);
|
|
207
|
+
// Answering like "no match" keeps the reply from probing client ids.
|
|
208
|
+
return { recorded: false };
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// The lookup ran in this same synchronous handler, so the write lands on
|
|
213
|
+
// the entry it resolved.
|
|
214
|
+
assistantEventHub.setClientPresence(clientId, state);
|
|
215
|
+
|
|
216
|
+
// Records which state a client actually reported. Nothing else persists
|
|
217
|
+
// it, so this is the only evidence for why a machine did or did not
|
|
218
|
+
// count as attended. Only `macos` clients gate pushes, hence the
|
|
219
|
+
// interface id.
|
|
220
|
+
log.debug(
|
|
221
|
+
{
|
|
222
|
+
op: "report_client_presence",
|
|
223
|
+
state,
|
|
224
|
+
interfaceId: client.interfaceId,
|
|
225
|
+
},
|
|
226
|
+
"Recorded desktop presence",
|
|
227
|
+
);
|
|
228
|
+
return { recorded: true };
|
|
229
|
+
},
|
|
230
|
+
},
|
|
119
231
|
];
|
|
@@ -44,12 +44,11 @@ function handleListCli({ body = {} }: RouteHandlerArgs) {
|
|
|
44
44
|
// user sees archived rows alongside live ones in the picker.
|
|
45
45
|
const includeArchived = (body.includeArchived as boolean) ?? false;
|
|
46
46
|
|
|
47
|
-
const rows = listConversations(
|
|
47
|
+
const rows = listConversations({
|
|
48
48
|
limit,
|
|
49
|
-
"standard",
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
);
|
|
49
|
+
conversationType: "standard",
|
|
50
|
+
archiveStatus: includeArchived ? "all" : "active",
|
|
51
|
+
});
|
|
53
52
|
return {
|
|
54
53
|
conversations: rows.map((c) => ({
|
|
55
54
|
id: c.id,
|
|
@@ -140,7 +139,7 @@ function handleExportCli({ body = {} }: RouteHandlerArgs) {
|
|
|
140
139
|
let conversationId = body.conversationId as string | undefined;
|
|
141
140
|
|
|
142
141
|
if (!conversationId) {
|
|
143
|
-
const all = listConversations(1);
|
|
142
|
+
const all = listConversations({ limit: 1 });
|
|
144
143
|
if (all.length === 0) {
|
|
145
144
|
throw new NotFoundError("No conversations found");
|
|
146
145
|
}
|
|
@@ -151,12 +150,11 @@ function handleExportCli({ body = {} }: RouteHandlerArgs) {
|
|
|
151
150
|
// behavior of letting `vellum export <prefix>` resolve an archived row.
|
|
152
151
|
let conversation = getConversation(conversationId);
|
|
153
152
|
if (!conversation) {
|
|
154
|
-
const all = listConversations(
|
|
155
|
-
Number.MAX_SAFE_INTEGER,
|
|
156
|
-
"standard",
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
);
|
|
153
|
+
const all = listConversations({
|
|
154
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
155
|
+
conversationType: "standard",
|
|
156
|
+
archiveStatus: "all",
|
|
157
|
+
});
|
|
160
158
|
const match = all.find((c) => c.id.startsWith(conversationId!));
|
|
161
159
|
if (match) {
|
|
162
160
|
conversation = match;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Route handlers for conversation listing, detail, and seen/unread state.
|
|
3
3
|
*
|
|
4
4
|
* GET /v1/conversations — paginated conversation list
|
|
5
|
+
* GET /v1/conversations/unread-count - count of unseen foreground conversations
|
|
5
6
|
* POST /v1/conversations/seen — record a seen signal (single)
|
|
6
7
|
* POST /v1/conversations/seen/bulk — record seen signals (batch)
|
|
7
8
|
* POST /v1/conversations/unread — mark a conversation unread
|
|
@@ -26,7 +27,9 @@ import {
|
|
|
26
27
|
} from "../../persistence/conversation-crud.js";
|
|
27
28
|
import { resolveConversationId } from "../../persistence/conversation-key-store.js";
|
|
28
29
|
import {
|
|
30
|
+
type ConversationListFilter,
|
|
29
31
|
countConversations,
|
|
32
|
+
countUnreadConversations,
|
|
30
33
|
listConversations,
|
|
31
34
|
listPinnedConversations,
|
|
32
35
|
} from "../../persistence/conversation-queries.js";
|
|
@@ -101,6 +104,13 @@ export const conversationSummarySchema = z.object({
|
|
|
101
104
|
displayOrder: z.number().nullable().optional(),
|
|
102
105
|
groupId: z.string().nullable(),
|
|
103
106
|
forkParent: forkParentSchema.optional(),
|
|
107
|
+
/**
|
|
108
|
+
* Present only on a referential fork whose parent conversation was deleted.
|
|
109
|
+
* The fork keeps the messages it owns and the lineage read truncates at the
|
|
110
|
+
* missing parent, so it renders as a conversation that starts mid-thought.
|
|
111
|
+
* Clients surface this so that reads as a deletion rather than as data loss.
|
|
112
|
+
*/
|
|
113
|
+
historyOrphaned: z.literal(true).optional(),
|
|
104
114
|
archivedAt: z.number().optional(),
|
|
105
115
|
/**
|
|
106
116
|
* Epoch-ms timestamp set when a background/scheduled conversation was
|
|
@@ -141,6 +151,10 @@ const conversationDetailResponseSchema = z.object({
|
|
|
141
151
|
conversation: conversationSummarySchema,
|
|
142
152
|
});
|
|
143
153
|
|
|
154
|
+
const unreadConversationCountResponseSchema = z.object({
|
|
155
|
+
count: z.number(),
|
|
156
|
+
});
|
|
157
|
+
|
|
144
158
|
// ---------------------------------------------------------------------------
|
|
145
159
|
// Helpers
|
|
146
160
|
// ---------------------------------------------------------------------------
|
|
@@ -194,18 +208,19 @@ function handleListConversations({ queryParams = {} }: RouteHandlerArgs) {
|
|
|
194
208
|
? queryParams.originChannel
|
|
195
209
|
: undefined;
|
|
196
210
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
);
|
|
204
|
-
const totalCount = countConversations(
|
|
211
|
+
const groupId =
|
|
212
|
+
queryParams.groupId !== undefined && queryParams.groupId !== ""
|
|
213
|
+
? queryParams.groupId
|
|
214
|
+
: undefined;
|
|
215
|
+
|
|
216
|
+
const filter: ConversationListFilter = {
|
|
205
217
|
conversationType,
|
|
206
218
|
archiveStatus,
|
|
207
219
|
originChannel,
|
|
208
|
-
|
|
220
|
+
groupId,
|
|
221
|
+
};
|
|
222
|
+
let rows = listConversations({ ...filter, limit, offset });
|
|
223
|
+
const totalCount = countConversations(filter);
|
|
209
224
|
|
|
210
225
|
// On the first page, ensure all pinned conversations are included
|
|
211
226
|
// even if they fall outside the paginated window. Pinned injection is
|
|
@@ -213,11 +228,19 @@ function handleListConversations({ queryParams = {} }: RouteHandlerArgs) {
|
|
|
213
228
|
// rows in archive-time order, not pin order. Also skipped for
|
|
214
229
|
// channel-scoped queries — those return only items matching the
|
|
215
230
|
// requested origin channel; pinned items render in their own section.
|
|
231
|
+
//
|
|
232
|
+
// Skipped for group-scoped queries for the same reason: a caller asking
|
|
233
|
+
// for one group gets that group, and a client that fetches the Pinned
|
|
234
|
+
// section via `groupId=system:pinned` has no use for rows appended to
|
|
235
|
+
// some other group's page. This is the compatibility shim for clients
|
|
236
|
+
// that still read Pinned out of the unfiltered list; it goes away once
|
|
237
|
+
// every section fetches its own group.
|
|
216
238
|
if (
|
|
217
239
|
offset === 0 &&
|
|
218
240
|
conversationType === "standard" &&
|
|
219
241
|
archiveStatus === "active" &&
|
|
220
|
-
originChannel === undefined
|
|
242
|
+
originChannel === undefined &&
|
|
243
|
+
groupId === undefined
|
|
221
244
|
) {
|
|
222
245
|
const pinned = listPinnedConversations(archiveStatus);
|
|
223
246
|
const seen = new Set(rows.map((c) => c.id));
|
|
@@ -265,6 +288,10 @@ function handleListConversations({ queryParams = {} }: RouteHandlerArgs) {
|
|
|
265
288
|
return response;
|
|
266
289
|
}
|
|
267
290
|
|
|
291
|
+
function handleGetUnreadConversationCount() {
|
|
292
|
+
return { count: countUnreadConversations() };
|
|
293
|
+
}
|
|
294
|
+
|
|
268
295
|
function handleRecordSeen({ body = {}, headers }: RouteHandlerArgs) {
|
|
269
296
|
const rawConversationId = body.conversationId as string | undefined;
|
|
270
297
|
if (!rawConversationId) {
|
|
@@ -450,10 +477,32 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
450
477
|
enum: [...CHANNEL_IDS],
|
|
451
478
|
},
|
|
452
479
|
},
|
|
480
|
+
{
|
|
481
|
+
name: "groupId",
|
|
482
|
+
type: "string",
|
|
483
|
+
required: false,
|
|
484
|
+
description:
|
|
485
|
+
'Filter to a single group, so each sidebar section can load independently of the paginated list. Pass "system:all" for conversations in no group, "system:pinned" for the Pinned section, or a custom group id. A group-scoped request is ordered by the user\'s arrangement (display order, then recency) and never has pinned rows appended to it. Omit to span every group.',
|
|
486
|
+
},
|
|
453
487
|
],
|
|
454
488
|
responseBody: listConversationsResponseSchema,
|
|
455
489
|
handler: handleListConversations,
|
|
456
490
|
},
|
|
491
|
+
{
|
|
492
|
+
operationId: "getUnreadConversationCount",
|
|
493
|
+
endpoint: "conversations/unread-count",
|
|
494
|
+
method: "GET",
|
|
495
|
+
policy: {
|
|
496
|
+
requiredScopes: ["chat.read"],
|
|
497
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
498
|
+
},
|
|
499
|
+
summary: "Unread conversation count",
|
|
500
|
+
description:
|
|
501
|
+
"Count of foreground conversations whose latest assistant message is unseen. Matches the sidebar's unread indicators: archived rows and non-surfaced background/scheduled rows are excluded.",
|
|
502
|
+
tags: ["conversations"],
|
|
503
|
+
responseBody: unreadConversationCountResponseSchema,
|
|
504
|
+
handler: handleGetUnreadConversationCount,
|
|
505
|
+
},
|
|
457
506
|
{
|
|
458
507
|
operationId: "recordConversationSeen",
|
|
459
508
|
endpoint: "conversations/seen",
|
|
@@ -46,7 +46,7 @@ import { normalizeConversationType } from "../../daemon/message-types/shared.js"
|
|
|
46
46
|
import { stripConversationIds } from "../../home/feed-writer.js";
|
|
47
47
|
import {
|
|
48
48
|
archiveConversation,
|
|
49
|
-
|
|
49
|
+
batchSetConversationPlacement,
|
|
50
50
|
countConversationsByScheduleJobId,
|
|
51
51
|
deleteConversation,
|
|
52
52
|
forkConversation as forkConversationInStore,
|
|
@@ -63,9 +63,10 @@ import {
|
|
|
63
63
|
resolveConversationId,
|
|
64
64
|
setConversationKeyIfAbsent,
|
|
65
65
|
} from "../../persistence/conversation-key-store.js";
|
|
66
|
+
import type { NonScheduledConversationType } from "../../persistence/conversation-types.js";
|
|
66
67
|
import { enqueueMemoryJob } from "../../persistence/jobs-store.js";
|
|
67
68
|
import { linkRequestLogsToMessage } from "../../persistence/llm-request-log-store.js";
|
|
68
|
-
import { deleteSchedule } from "../../schedule/schedule-store.js";
|
|
69
|
+
import { deleteSchedule, getSchedule } from "../../schedule/schedule-store.js";
|
|
69
70
|
import { UserError } from "../../util/errors.js";
|
|
70
71
|
import { safeParseRecord } from "../../util/json.js";
|
|
71
72
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -100,6 +101,12 @@ const log = getLogger("conversation-management-routes");
|
|
|
100
101
|
// Helpers
|
|
101
102
|
// ---------------------------------------------------------------------------
|
|
102
103
|
|
|
104
|
+
/** Conversation types this endpoint may mint. */
|
|
105
|
+
const createConversationTypeSchema = z.enum([
|
|
106
|
+
"standard",
|
|
107
|
+
"background",
|
|
108
|
+
] as const satisfies readonly NonScheduledConversationType[]);
|
|
109
|
+
|
|
103
110
|
function resolveOrThrow(rawId: string): string {
|
|
104
111
|
const id = resolveConversationId(rawId);
|
|
105
112
|
if (!id) {
|
|
@@ -111,11 +118,17 @@ function resolveOrThrow(rawId: string): string {
|
|
|
111
118
|
async function cancelScheduleIfLast(conversationId: string): Promise<void> {
|
|
112
119
|
const conv = getConversation(conversationId);
|
|
113
120
|
if (
|
|
114
|
-
conv?.scheduleJobId
|
|
115
|
-
countConversationsByScheduleJobId(conv.scheduleJobId)
|
|
121
|
+
!conv?.scheduleJobId ||
|
|
122
|
+
countConversationsByScheduleJobId(conv.scheduleJobId) > 1
|
|
116
123
|
) {
|
|
117
|
-
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// A plugin-declared schedule outlives its run conversations: its lifecycle
|
|
127
|
+
// belongs to the reconciler, and `deleteSchedule` refuses sourced rows.
|
|
128
|
+
if (getSchedule(conv.scheduleJobId)?.sourceKey != null) {
|
|
129
|
+
return;
|
|
118
130
|
}
|
|
131
|
+
await deleteSchedule(conv.scheduleJobId);
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
// ---------------------------------------------------------------------------
|
|
@@ -126,14 +139,26 @@ function handleCreateConversation({ body = {}, headers }: RouteHandlerArgs) {
|
|
|
126
139
|
const conversationKey =
|
|
127
140
|
(body.conversationKey as string | undefined) ?? crypto.randomUUID();
|
|
128
141
|
// The shared route adapter does not runtime-validate the body against the
|
|
129
|
-
// Zod requestBody (it's codegen-only), so guard the
|
|
130
|
-
//
|
|
142
|
+
// Zod requestBody (it's codegen-only), so guard the types here: a malformed
|
|
143
|
+
// `{ title: 123 }` would otherwise throw on `.trim()` and 500, and an
|
|
144
|
+
// unsupported conversationType would reach the store unchecked.
|
|
145
|
+
// `.nullish()`: an explicit JSON `null` is how serializers spell an absent
|
|
146
|
+
// optional, so it means the same thing as omitting the key.
|
|
147
|
+
const requestedType = createConversationTypeSchema
|
|
148
|
+
.nullish()
|
|
149
|
+
.safeParse(body.conversationType);
|
|
150
|
+
if (!requestedType.success) {
|
|
151
|
+
throw new BadRequestError(
|
|
152
|
+
`conversationType must be one of ${createConversationTypeSchema.options.join(", ")}`,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
131
155
|
if (body.title !== undefined && typeof body.title !== "string") {
|
|
132
156
|
throw new BadRequestError("title must be a string");
|
|
133
157
|
}
|
|
134
158
|
const customTitle = body.title?.trim() || undefined;
|
|
159
|
+
const conversationType = requestedType.data ?? "standard";
|
|
135
160
|
const result = getOrCreateConversation(conversationKey, {
|
|
136
|
-
conversationType
|
|
161
|
+
conversationType,
|
|
137
162
|
});
|
|
138
163
|
if (result.created) {
|
|
139
164
|
// A caller-supplied title is user-set: persist it with isAutoTitle = 0 so
|
|
@@ -151,10 +176,14 @@ function handleCreateConversation({ body = {}, headers }: RouteHandlerArgs) {
|
|
|
151
176
|
headers?.["x-vellum-client-id"]?.trim() || undefined,
|
|
152
177
|
);
|
|
153
178
|
}
|
|
179
|
+
// On a conversationKey hit the row already exists, so the type it carries
|
|
180
|
+
// can differ from the requested one.
|
|
181
|
+
const storedType = normalizeConversationType(result.conversationType);
|
|
154
182
|
log.info(
|
|
155
183
|
{
|
|
156
184
|
conversationId: result.conversationId,
|
|
157
185
|
conversationKey,
|
|
186
|
+
conversationType: storedType,
|
|
158
187
|
created: result.created,
|
|
159
188
|
},
|
|
160
189
|
"Created conversation via POST",
|
|
@@ -162,7 +191,7 @@ function handleCreateConversation({ body = {}, headers }: RouteHandlerArgs) {
|
|
|
162
191
|
return {
|
|
163
192
|
id: result.conversationId,
|
|
164
193
|
conversationKey,
|
|
165
|
-
conversationType:
|
|
194
|
+
conversationType: storedType,
|
|
166
195
|
created: result.created,
|
|
167
196
|
};
|
|
168
197
|
}
|
|
@@ -816,7 +845,6 @@ function handleReorderConversations({ body = {}, headers }: RouteHandlerArgs) {
|
|
|
816
845
|
const updates = body.updates as
|
|
817
846
|
| Array<{
|
|
818
847
|
conversationId: string;
|
|
819
|
-
displayOrder?: number;
|
|
820
848
|
isPinned?: boolean;
|
|
821
849
|
groupId?: string | null;
|
|
822
850
|
}>
|
|
@@ -824,10 +852,9 @@ function handleReorderConversations({ body = {}, headers }: RouteHandlerArgs) {
|
|
|
824
852
|
if (!Array.isArray(updates)) {
|
|
825
853
|
throw new BadRequestError("Missing updates array");
|
|
826
854
|
}
|
|
827
|
-
|
|
855
|
+
batchSetConversationPlacement(
|
|
828
856
|
updates.map((u) => ({
|
|
829
857
|
id: u.conversationId,
|
|
830
|
-
displayOrder: u.displayOrder ?? null,
|
|
831
858
|
isPinned: u.isPinned,
|
|
832
859
|
groupId: u.groupId,
|
|
833
860
|
})),
|
|
@@ -863,10 +890,11 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
863
890
|
.describe(
|
|
864
891
|
"Optional external key. Echoed back in the response. Non-vellum channels (Telegram, WhatsApp) use this to scope to a logical channel thread; vellum-web clients can omit it and rely on the assistant-minted `id`.",
|
|
865
892
|
),
|
|
866
|
-
conversationType:
|
|
867
|
-
.literal("standard")
|
|
893
|
+
conversationType: createConversationTypeSchema
|
|
868
894
|
.optional()
|
|
869
|
-
.describe(
|
|
895
|
+
.describe(
|
|
896
|
+
'Conversation type for the new row. "background" keeps it out of the foreground list and the sidebar\'s Recents grouping, used by internal side-channel flows (onboarding research, persona/identity rewrites) that mint a throwaway thread the user should never see. "scheduled" is not accepted here; scheduled rows are owned by the schedule pipeline.',
|
|
897
|
+
),
|
|
870
898
|
title: z
|
|
871
899
|
.string()
|
|
872
900
|
.optional()
|
|
@@ -1274,14 +1302,15 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
1274
1302
|
requiredScopes: ["chat.write"],
|
|
1275
1303
|
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
1276
1304
|
},
|
|
1277
|
-
summary: "
|
|
1278
|
-
description:
|
|
1305
|
+
summary: "Move conversations between sections",
|
|
1306
|
+
description:
|
|
1307
|
+
"Batch-update which group holds each conversation, and its pin state. " +
|
|
1308
|
+
"Lists are ordered by recency, so this sets placement, not order.",
|
|
1279
1309
|
tags: ["conversations"],
|
|
1280
1310
|
requestBody: z.object({
|
|
1281
1311
|
updates: z.array(
|
|
1282
1312
|
z.object({
|
|
1283
1313
|
conversationId: z.string(),
|
|
1284
|
-
displayOrder: z.number().optional(),
|
|
1285
1314
|
isPinned: z.boolean().optional(),
|
|
1286
1315
|
groupId: z.string().nullable().optional(),
|
|
1287
1316
|
}),
|