@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
package/ARCHITECTURE.md
CHANGED
|
@@ -67,8 +67,10 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
|
|
|
67
67
|
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
|
68
68
|
| `actor_client_v1` | `chat.{read,write}`, `approval.{read,write}`, `settings.{read,write}`, `attachments.{read,write}`, `calls.{read,write}`, `feature_flags.{read,write}` | Desktop, CLI clients |
|
|
69
69
|
| `gateway_ingress_v1` | `ingress.write`, `internal.write` | Gateway channel inbound + webhook forwarding |
|
|
70
|
-
| `gateway_service_v1` | `
|
|
71
|
-
| `
|
|
70
|
+
| `gateway_service_v1` | `chat.{read,write}`, `settings.{read,write}`, `attachments.{read,write}`, `internal.write` | Gateway service-to-daemon calls |
|
|
71
|
+
| `local_v1` | `local.all` | Local (loopback) conversation sessions |
|
|
72
|
+
| `speech_relay_v1` | `speech.relay` | Daemon dial of the gateway speech relay only |
|
|
73
|
+
| `ui_page_v1` | `settings.read` | Served UI pages |
|
|
72
74
|
|
|
73
75
|
**Identity lifecycle:**
|
|
74
76
|
|
|
@@ -836,7 +838,7 @@ graph LR
|
|
|
836
838
|
JOBS["memory_jobs<br/>───────────────<br/>Async task queue<br/>Types: embed, extract,<br/>summarize, backfill, cleanup<br/>Status: pending → running →<br/>completed | failed"]
|
|
837
839
|
ATT["attachments<br/>───────────────<br/>base64-encoded file data<br/>mime_type, size_bytes<br/>Linked to messages via<br/>message_attachments join"]
|
|
838
840
|
REM["reminders<br/>───────────────<br/>One-time scheduled reminders<br/>label, message, fireAt<br/>mode: notify | execute<br/>status: pending → fired | cancelled<br/>routing_intent: single_channel |<br/>multi_channel | all_channels<br/>routing_hints_json (free-form)"]
|
|
839
|
-
SCHED_JOBS["cron_jobs (recurrence schedules)<br/>───────────────<br/>Recurring schedule definitions<br/>cron_expression: cron or RRULE string<br/>schedule_syntax: 'cron' | 'rrule'<br/>timezone, message, next_run_at<br/>enabled, retry_count<br/>Legacy alias: scheduleJobs"]
|
|
841
|
+
SCHED_JOBS["cron_jobs (recurrence schedules)<br/>───────────────<br/>Recurring schedule definitions<br/>cron_expression: cron or RRULE string<br/>schedule_syntax: 'cron' | 'rrule'<br/>timezone, message, next_run_at<br/>enabled, retry_count<br/>source_key: plugin-declared provenance<br/>definition_hash, user_enabled<br/>Legacy alias: scheduleJobs"]
|
|
840
842
|
SCHED_RUNS["cron_runs (schedule runs)<br/>───────────────<br/>Execution history per schedule<br/>job_id (FK → cron_jobs)<br/>status: ok | error<br/>duration_ms, output, error<br/>Legacy alias: scheduleRuns"]
|
|
841
843
|
TASKS["tasks<br/>───────────────<br/>Reusable prompt templates<br/>title, Handlebars template<br/>inputSchema, contextFlags<br/>requiredTools, status"]
|
|
842
844
|
TASK_RUNS["task_runs<br/>───────────────<br/>Execution history per task<br/>taskId (FK → tasks)<br/>conversationId, status<br/>startedAt, finishedAt, error"]
|
|
@@ -861,6 +863,59 @@ graph LR
|
|
|
861
863
|
|
|
862
864
|
---
|
|
863
865
|
|
|
866
|
+
## Plugin-Declared Schedules: Declaration → Reconciler → cron_jobs
|
|
867
|
+
|
|
868
|
+
Plugins contribute recurring schedules as a surface: directories under
|
|
869
|
+
`<pluginDir>/schedules/`, each a `<name>/` holding `config.json` plus
|
|
870
|
+
exactly one `index.md` (runs as `execute`) or `index.sh` (runs as `script`)
|
|
871
|
+
entrypoint. Ambiguity fails closed: a file sitting directly under
|
|
872
|
+
`schedules/`, zero/multiple/unsupported entrypoints, and malformed config
|
|
873
|
+
produce per-schedule `DeclarationError`s without affecting siblings
|
|
874
|
+
(`src/schedule/plugin-schedule-declarations.ts`).
|
|
875
|
+
|
|
876
|
+
A level-based reconciler (`src/schedule/plugin-schedule-reconciler.ts`)
|
|
877
|
+
converges declarations into ordinary `cron_jobs` rows keyed by the nullable
|
|
878
|
+
`source_key` column (`plugin:<plugin>/<name>`). Rows with `source_key IS
|
|
879
|
+
NULL` are imperative schedules the reconciler never touches. Triggers: a
|
|
880
|
+
startup pass in `daemon/lifecycle.ts` (after plugin init, before the
|
|
881
|
+
scheduler starts), the end of `reconcilePluginSourcesNow()` in
|
|
882
|
+
`plugins/mtime-cache.ts` (install/uninstall/upgrade and sentinel-driven
|
|
883
|
+
changes), the plugin enable/disable routes, and a 60s backstop sweep
|
|
884
|
+
registered with the HTTP server's background sweeps.
|
|
885
|
+
|
|
886
|
+
Reconcile lag never lets a disabled plugin run. The disable path writes a
|
|
887
|
+
`.disabled` sentinel that only a reconcile pass turns into disarmed rows, so
|
|
888
|
+
the scheduler re-reads the sentinel at fire time and records a skipped run
|
|
889
|
+
instead of executing a claimed row whose plugin is off. Run-now applies the
|
|
890
|
+
same boundary through `declarationExistsOnDisk`, which also covers a plugin
|
|
891
|
+
whose manifest no longer parses, a declaration directory that is gone, and a
|
|
892
|
+
plugin root or declaration directory resolving outside the tree it belongs to
|
|
893
|
+
(the same `isInsidePluginRoot` containment the loader applies before importing
|
|
894
|
+
a plugin).
|
|
895
|
+
|
|
896
|
+
A declaration that stops parsing keeps its execute row armed on the message
|
|
897
|
+
already stored in the row, but disarms its script rows: a script row fires its
|
|
898
|
+
entrypoint by absolute path, so leaving it armed would run the very `index.sh`
|
|
899
|
+
the parser rejected. Those rows re-arm on the pass after the declaration parses
|
|
900
|
+
again.
|
|
901
|
+
|
|
902
|
+
Ownership boundaries: the reconciler owns definition columns (expression,
|
|
903
|
+
timezone, message/script, retry policy, `definition_hash`); the execution
|
|
904
|
+
engine owns runtime columns (`next_run_at`, `status`, `last_*`,
|
|
905
|
+
`retry_count`) and its latches are never overridden; the user owns
|
|
906
|
+
`user_enabled`, a sticky override consulted when computing effective
|
|
907
|
+
`enabled`. Nothing ever writes to plugin files. Execution itself is
|
|
908
|
+
unchanged: declared rows fire through the same `claimDueSchedules` path as
|
|
909
|
+
imperative ones.
|
|
910
|
+
|
|
911
|
+
Consent and surfacing: CLI install/upgrade list declared schedules and
|
|
912
|
+
prompt before finalizing; unattended daemon-route installs are covered by
|
|
913
|
+
`schedule.declared` arrival notifications, with `schedule.definition_changed`
|
|
914
|
+
and `schedule.definition_error` covering upgrades and broken declarations
|
|
915
|
+
(events registered in `notifications/signal.ts`, deterministic templates in
|
|
916
|
+
`notifications/copy-composer.ts`). Settings routes, CLI, and web render
|
|
917
|
+
plugin-sourced rows read-only except the enabled toggle.
|
|
918
|
+
|
|
864
919
|
---
|
|
865
920
|
|
|
866
921
|
## Web Server — Connection Modes
|
|
@@ -43,6 +43,9 @@ Design doc defining how unknown users gain access to a Vellum assistant via chan
|
|
|
43
43
|
5. **On approval the gateway mints a verification session.** The decide op carries a `mint_outbound_session` outcome; inside the decide transaction the gateway (`gateway/src/verification/session-service.ts`) generates a 6-digit code, persists only its SHA-256 hash in `channel_verification_sessions` (identity-bound to the requester, `verificationPurpose: 'trusted_contact'`), and returns the raw secret to the daemon in the decide response for delivery.
|
|
44
44
|
6. **The code is delivered.** The daemon delivers the code to the guardian's verified channel (ephemeral + DM on Slack shared channels so other members never see it). On Slack the code is also DM'd straight to the requester; on other channels the guardian relays it out-of-band (in person, text message, phone call). That out-of-band transfer is the trust anchor: it proves the requester has a real-world relationship with the guardian.
|
|
45
45
|
7. **Requester enters the code** back to the assistant on the same channel. The **gateway** intercepts bare verification codes at ingress (`gateway/src/verification/text-verification.ts`) whenever an interceptable session exists for that channel — the daemon never sees verification code messages.
|
|
46
|
+
|
|
47
|
+
On Discord the code is delivered to, and answered in, a DM (`gateway/src/discord/admit.ts` admits DMs on their own lane). A bare code typed into a guild channel is dropped by the mention gate before it reaches the intercept, so it is never consumed and never reaches the agent.
|
|
48
|
+
|
|
46
49
|
8. **Gateway verifies the code and activates the user.** `validateAndConsumeSession()` checks the rate limit, hashes the code, matches it against a live session, verifies identity binding, atomically consumes the session, then applies the trusted-contact side effects: `applyTrustedContactSideEffects()` upserts the verified channel into the gateway ACL with `status: 'active'`, `policy: 'allow'` and mirrors the contact identity to the assistant DB. A blocked/revoked authoritative gateway row rejects the verification even when the code matched. The gateway delivers the deterministic success reply.
|
|
47
50
|
9. **All subsequent messages are accepted normally.** The gateway stamps an allow verdict and the daemon processes the message.
|
|
48
51
|
|
|
@@ -65,11 +68,12 @@ requested -> pending_guardian -> verification_pending -> active | denied | expir
|
|
|
65
68
|
|
|
66
69
|
Identity binding ensures the verification code can only be consumed by the intended recipient on the intended channel. The binding fields are set on the gateway `channel_verification_sessions` record when the session is created; the check itself is `checkIdentityMatch` (`gateway/src/verification/identity-match.ts`).
|
|
67
70
|
|
|
68
|
-
| Channel | Identity fields | Binding behavior
|
|
69
|
-
| --------- | -------------------------------------------------------------------------------- |
|
|
70
|
-
| Telegram | `expectedExternalUserId` = Telegram user ID, `expectedChatId` = Telegram chat ID | Both are taken from the original denied message's metadata. The `identityBindingStatus` is `'bound'`. Verification requires the actor's user ID or chat ID to match (user ID required when both are set on a shared chat).
|
|
71
|
-
| Voice | `expectedPhoneE164` = phone number in E.164 format | Phone-based identity binding. Verification requires the caller's number to match the expected phone.
|
|
72
|
-
|
|
|
71
|
+
| Channel | Identity fields | Binding behavior |
|
|
72
|
+
| --------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
73
|
+
| Telegram | `expectedExternalUserId` = Telegram user ID, `expectedChatId` = Telegram chat ID | Both are taken from the original denied message's metadata. The `identityBindingStatus` is `'bound'`. Verification requires the actor's user ID or chat ID to match (user ID required when both are set on a shared chat). |
|
|
74
|
+
| Voice | `expectedPhoneE164` = phone number in E.164 format | Phone-based identity binding. Verification requires the caller's number to match the expected phone. |
|
|
75
|
+
| Discord | `expectedExternalUserId` = Discord user snowflake. `expectedChatId` is unset on the guardian-initiated and trusted-contact paths, and is the originating guild channel on the access-request approval path (`mint_outbound_session`), which sets it for every channel alike. | The code is delivered to a DM and answered there, but the DM channel does not exist until it is opened, so those two paths have no chat id to record at mint time. Where the approval path does set one, it is a room rather than an identity and never becomes a sufficient credential on its own: `checkIdentityMatch` requires the `expectedExternalUserId` match whenever both fields are set. That path also writes the room into `destinationAddress`, where it describes nothing the code is ever sent to (see LUM-3110). |
|
|
76
|
+
| Bootstrap | none yet (`identityBindingStatus: 'pending_bootstrap'`) | Unbound deep-link sessions use a 32-byte hex token instead of a numeric code; the identity is bound when the token is redeemed (`verification_sessions_bind_identity`). |
|
|
73
77
|
|
|
74
78
|
**Anti-oracle invariant:** When identity verification fails, the error message is identical to the "invalid or expired code" message. This prevents attackers from distinguishing between a wrong code and a wrong identity, which would leak information about which identities have pending sessions.
|
|
75
79
|
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Vellum Doctor
|
|
2
|
+
|
|
3
|
+
Vellum Doctor is a platform-hosted diagnostic tool for investigating problems with a Vellum assistant.
|
|
4
|
+
|
|
5
|
+
> **Status:** Beta. Vellum Doctor is available in the web client for platform-hosted assistants; it is not available for self-hosted assistants.
|
|
6
|
+
|
|
7
|
+
## What it does
|
|
8
|
+
|
|
9
|
+
Doctor provides a separate diagnostic session where a guardian can describe an issue and receive an investigation that may include:
|
|
10
|
+
|
|
11
|
+
- Plain-language explanations of what the Doctor found.
|
|
12
|
+
- Tool calls with expandable technical details and outputs.
|
|
13
|
+
- Requests for approval before an operation runs.
|
|
14
|
+
- A backup prompt before an operation that may modify the assistant.
|
|
15
|
+
- Feedback prompts when an issue may need attention from the Vellum team.
|
|
16
|
+
- A session transcript that can be copied for follow-up or support.
|
|
17
|
+
|
|
18
|
+
Doctor is separate from the assistant's normal conversation. It is a support and diagnosis surface, not another assistant that builds a long-term relationship with the guardian.
|
|
19
|
+
|
|
20
|
+
## When to use it
|
|
21
|
+
|
|
22
|
+
Open Doctor when an assistant is not behaving as expected, especially when the cause could be a runtime problem, an integration or credential problem, a missing capability, a failed scheduled action, or a permission boundary.
|
|
23
|
+
|
|
24
|
+
The web client may show a **Go to Doctor** action in an operational error notice. Doctor can also be opened from the **Doctor** tab under the assistant's debug settings.
|
|
25
|
+
|
|
26
|
+
### Open Doctor from chat
|
|
27
|
+
|
|
28
|
+
The web client supports a slash command that opens the Doctor panel:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
/doctor
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
You can include the first message after the command:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
/doctor My assistant stopped responding after I connected Slack
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The command navigates to Doctor instead of sending the text as a normal assistant turn. On a self-hosted assistant, Doctor is unavailable and the command does not start a Doctor session.
|
|
41
|
+
|
|
42
|
+
## Session lifecycle
|
|
43
|
+
|
|
44
|
+
A Doctor session follows this flow:
|
|
45
|
+
|
|
46
|
+
1. The web client creates a diagnostic session for the active assistant.
|
|
47
|
+
2. Doctor sends a greeting and opens a live event stream.
|
|
48
|
+
3. The guardian describes the issue and can send follow-up messages while the session is active.
|
|
49
|
+
4. Doctor streams assistant messages, tool activity, approval requests, backup prompts, and errors into the panel.
|
|
50
|
+
5. The session ends with either `completed` or `error` status.
|
|
51
|
+
6. The guardian can start a new session after a terminal state.
|
|
52
|
+
|
|
53
|
+
The web client can load the most recent persisted session when the Doctor panel opens. An active session can be resumed, including pending approval or backup prompts, and completed sessions remain available as history.
|
|
54
|
+
|
|
55
|
+
## Approval and backup prompts
|
|
56
|
+
|
|
57
|
+
Doctor can ask for confirmation before running an operation.
|
|
58
|
+
|
|
59
|
+
- **Allow once** approves the requested operation for the current prompt.
|
|
60
|
+
- **Always Allow** is available for `exec_command` requests and approves future execution requests in that session.
|
|
61
|
+
- **Deny** rejects the requested operation.
|
|
62
|
+
- **Show details** reveals the tool name, description, and input that Doctor received.
|
|
63
|
+
|
|
64
|
+
Before an operation that may modify the assistant, Doctor can ask whether to create a backup first:
|
|
65
|
+
|
|
66
|
+
- **Back up** creates the backup before continuing.
|
|
67
|
+
- **Skip** continues without that backup.
|
|
68
|
+
|
|
69
|
+
Approval and backup prompts are part of the session transcript, so the guardian can see which operations were proposed and how they were handled.
|
|
70
|
+
|
|
71
|
+
## Session history and transcripts
|
|
72
|
+
|
|
73
|
+
Doctor sessions are persisted against the assistant that they diagnose. The web client can retrieve the newest sessions and the ordered message ledger for a selected session.
|
|
74
|
+
|
|
75
|
+
A persisted session includes:
|
|
76
|
+
|
|
77
|
+
- Lifecycle status: `active`, `completed`, or `error`.
|
|
78
|
+
- Ordered user and Doctor messages.
|
|
79
|
+
- Tool calls and tool results.
|
|
80
|
+
- Approval, backup, feedback, status, and error entries.
|
|
81
|
+
- Message timestamps and counts.
|
|
82
|
+
- Token and estimated-cost totals returned by the platform API.
|
|
83
|
+
|
|
84
|
+
The **Copy Session** action serializes the visible session into text. Doctor's idle panel also warns that Doctor logs may be temporarily stored, so guardians should avoid entering secrets that are not necessary for diagnosis.
|
|
85
|
+
|
|
86
|
+
## Feedback and support handoff
|
|
87
|
+
|
|
88
|
+
Doctor can show a feedback prompt when the investigation identifies an issue that may be useful to the Vellum team. The feedback flow can include the Doctor session ID and a transcript file, subject to the diagnostics choice in the feedback form.
|
|
89
|
+
|
|
90
|
+
Sharing feedback is separate from approving a Doctor operation. A guardian can continue describing the issue while the feedback prompt is present.
|
|
91
|
+
|
|
92
|
+
## API reference
|
|
93
|
+
|
|
94
|
+
The platform API exposes Doctor under the assistant-scoped routes below. Requests use the same authentication options as the surrounding platform API.
|
|
95
|
+
|
|
96
|
+
| Operation | Route | Purpose |
|
|
97
|
+
| ---------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------- |
|
|
98
|
+
| List history | `GET /v1/assistants/{assistant_id}/doctor/history/` | List persisted sessions, newest first. |
|
|
99
|
+
| Retrieve history | `GET /v1/assistants/{assistant_id}/doctor/history/{doctor_session_id}/` | Retrieve one session and its ordered message ledger. |
|
|
100
|
+
| Create session | `POST /v1/assistants/{assistant_id}/doctor/sessions/` | Create a new diagnostic session and return its session ID. |
|
|
101
|
+
| Stream events | `GET /v1/assistants/{assistant_id}/doctor/sessions/{session_id}/events/` | Receive Doctor events over Server-Sent Events. |
|
|
102
|
+
| Send message | `POST /v1/assistants/{assistant_id}/doctor/sessions/{session_id}/messages/` | Send a message to an active session. |
|
|
103
|
+
| Record outcome | `POST /v1/assistants/{assistant_id}/doctor/sessions/{session_id}/user-outcome/` | Record whether Doctor solved the problem. |
|
|
104
|
+
| Delete session | `DELETE /v1/assistants/{assistant_id}/doctor/sessions/{session_id}/` | End and clean up a session. |
|
|
105
|
+
|
|
106
|
+
### Create a session
|
|
107
|
+
|
|
108
|
+
A successful create request returns:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"session_id": "doctor-session-id"
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Send a message
|
|
117
|
+
|
|
118
|
+
The message body requires non-empty `content` and can include an optional `source_event_id` for replay-safe delivery:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"content": "My assistant cannot send messages to Slack"
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
A successful request is accepted with HTTP `202` while the response arrives on the event stream.
|
|
127
|
+
|
|
128
|
+
### Record the user outcome
|
|
129
|
+
|
|
130
|
+
When Doctor asks whether it solved the problem, submit the answer to the session's outcome route:
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"resolved": true
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Use `false` when the problem was not resolved. The endpoint returns `200`, records the latest answer for the session, and works for both active and completed sessions.
|
|
139
|
+
|
|
140
|
+
### Event types
|
|
141
|
+
|
|
142
|
+
The event stream validates and handles these event types:
|
|
143
|
+
|
|
144
|
+
| Event | Meaning |
|
|
145
|
+
| --------------------- | --------------------------------------------------------------- |
|
|
146
|
+
| `message` | A complete Doctor message. |
|
|
147
|
+
| `message_delta` | A streamed part of a Doctor message. |
|
|
148
|
+
| `tool_call` | Doctor started a tool operation. |
|
|
149
|
+
| `tool_result` | A tool operation returned output, including whether it failed. |
|
|
150
|
+
| `approval_required` | Doctor is waiting for an approval response. |
|
|
151
|
+
| `backup_prompt` | Doctor is asking whether to create a backup before continuing. |
|
|
152
|
+
| `feedback_prompt` | Doctor is offering a feedback handoff. |
|
|
153
|
+
| `user_outcome_prompt` | Doctor is asking whether it solved the guardian's problem. |
|
|
154
|
+
| `status` | The session is active, completed, or in an error state. |
|
|
155
|
+
| `error` | The session encountered an error with a human-readable message. |
|
|
156
|
+
|
|
157
|
+
Malformed events and unknown event types are ignored by the web client rather than being treated as trusted Doctor output.
|
|
158
|
+
|
|
159
|
+
## Failure states and recovery
|
|
160
|
+
|
|
161
|
+
### No assistant is selected
|
|
162
|
+
|
|
163
|
+
Doctor cannot start without an active assistant. Hatch or select an assistant, then reopen the Doctor panel.
|
|
164
|
+
|
|
165
|
+
### Doctor is unavailable
|
|
166
|
+
|
|
167
|
+
Doctor is platform-hosted. Self-hosted assistants do not expose the Doctor tab or the `/doctor` command.
|
|
168
|
+
|
|
169
|
+
### Monthly session limit
|
|
170
|
+
|
|
171
|
+
The platform can reject session creation when the available Doctor sessions for the month have been used. The web client tells the guardian to try again next month.
|
|
172
|
+
|
|
173
|
+
### Service or connection failure
|
|
174
|
+
|
|
175
|
+
Session creation, message delivery, and event streaming can fail when the Doctor service or platform proxy is unavailable. The panel surfaces the returned error and ends the session when it cannot recover.
|
|
176
|
+
|
|
177
|
+
The event stream retries recoverable interruptions with a bounded reconnect policy. If the session has expired, its event history cannot be replayed, or the stream remains idle, the panel asks the guardian to start a new session.
|
|
178
|
+
|
|
179
|
+
### A tool operation fails
|
|
180
|
+
|
|
181
|
+
A failed tool result is shown in the transcript with its technical output. Doctor can continue investigating, ask for another action, or end the session with an error. A failed operation does not become a successful diagnosis merely because the session is still open.
|
|
182
|
+
|
|
183
|
+
## Source map
|
|
184
|
+
|
|
185
|
+
The implementation currently lives in the web client and platform API contract:
|
|
186
|
+
|
|
187
|
+
- `clients/web/src/domains/settings/pages/debug-page.tsx` exposes the Doctor tab.
|
|
188
|
+
- `clients/web/src/domains/settings/components/panels/doctor-panel.tsx` owns session creation, messaging, history, cleanup, and the panel UI.
|
|
189
|
+
- `clients/web/src/domains/settings/components/panels/use-doctor-sse.ts` owns the event stream, validation boundary, reconnect behavior, and replay handling.
|
|
190
|
+
- `clients/web/src/domains/settings/components/panels/doctor-event-schema.ts` defines the validated event contract.
|
|
191
|
+
- `clients/web/src/domains/settings/components/panels/doctor-event-handlers.ts` maps events into visible session entries.
|
|
192
|
+
- `clients/web/src/domains/settings/components/panels/doctor-history.ts` maps persisted messages and serializes copied transcripts.
|
|
193
|
+
- `clients/web/openapi-schemas/platform.yaml` defines the assistant-scoped Doctor routes and persisted session schemas.
|
|
194
|
+
|
|
195
|
+
The Vellum Assistant runtime does not provide a local Doctor CLI command. Doctor is a web and platform capability, not a command run inside a self-hosted assistant.
|
package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts
CHANGED
|
@@ -40,3 +40,42 @@ export function isChannelId(value: unknown): value is ChannelId {
|
|
|
40
40
|
(CHANNEL_IDS as readonly string[]).includes(value)
|
|
41
41
|
);
|
|
42
42
|
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The provider key holding each channel's bot credential.
|
|
46
|
+
*
|
|
47
|
+
* Two senses of "connected" share the provider registry: a provider the user
|
|
48
|
+
* authorized so the assistant can act **as them** (`slack`, `discord`,
|
|
49
|
+
* `google`), and a bot credential letting people reach the assistant **as
|
|
50
|
+
* itself**. Nothing in a provider key says which, and the naming actively
|
|
51
|
+
* misleads: `slack` and `discord` name the user integration while their bots
|
|
52
|
+
* take a `_channel` suffix, yet `telegram` *is* the bot, because Telegram has
|
|
53
|
+
* no user-identity integration.
|
|
54
|
+
*
|
|
55
|
+
* That irregularity is why this is stated rather than derived from the key,
|
|
56
|
+
* and it is stated here because this file already owns what a channel is.
|
|
57
|
+
*
|
|
58
|
+
* Deliberately only the key. What fields each credential requires is declared
|
|
59
|
+
* once already, per service, in the gateway's credential specs; restating it
|
|
60
|
+
* here would be a second copy of a different fact.
|
|
61
|
+
*
|
|
62
|
+
* Channels absent from this map reach the assistant without a bot credential
|
|
63
|
+
* of their own: `phone` through the voice provider, `vellum` and `platform`
|
|
64
|
+
* internally.
|
|
65
|
+
*/
|
|
66
|
+
export const CHANNEL_BOT_PROVIDER = {
|
|
67
|
+
slack: "slack_channel",
|
|
68
|
+
discord: "discord_channel",
|
|
69
|
+
telegram: "telegram",
|
|
70
|
+
} as const satisfies Partial<Record<ChannelId, string>>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Whether a provider key names a bot the assistant is reached through, rather
|
|
74
|
+
* than a grant letting it act as the user. This is the "which sense of
|
|
75
|
+
* connected" question, for any provider key.
|
|
76
|
+
*/
|
|
77
|
+
export function isChannelBotProvider(providerKey: string): boolean {
|
|
78
|
+
return (Object.values(CHANNEL_BOT_PROVIDER) as readonly string[]).includes(
|
|
79
|
+
providerKey,
|
|
80
|
+
);
|
|
81
|
+
}
|
package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts
CHANGED
|
@@ -20,6 +20,16 @@ export function normalizePublicBaseUrl(value: unknown): string | undefined {
|
|
|
20
20
|
return normalized.length > 0 ? normalized : undefined;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Application close code the gateway's velay bridge sends to proxied
|
|
25
|
+
* WebSockets when the tunnel itself is lost (velay disconnect, gateway
|
|
26
|
+
* shutdown). A dedicated code because the natural 1001 (going away) cannot
|
|
27
|
+
* be sent through the JS `close()` API (the bridge would remap it to a
|
|
28
|
+
* misleading 4001), and Bun's WebSocket client drops close reasons, so the
|
|
29
|
+
* code is the only signal that survives the relay to the daemon.
|
|
30
|
+
*/
|
|
31
|
+
export const GATEWAY_TUNNEL_LOST_WS_CLOSE_CODE = 4801;
|
|
32
|
+
|
|
23
33
|
export function normalizeHttpPublicBaseUrl(value: unknown): string | undefined {
|
|
24
34
|
if (typeof value !== "string") return undefined;
|
|
25
35
|
const trimmed = value.trim();
|
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
* `Date#toISOString()`.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Pairing-challenge TTL in milliseconds (10 minutes): the gateway's challenge
|
|
26
|
+
* store enforces it and the `vellum pair` CLI renders it in user-facing copy.
|
|
27
|
+
*/
|
|
28
|
+
export const REMOTE_WEB_PAIRING_CODE_TTL_MS = 10 * 60 * 1000;
|
|
29
|
+
|
|
24
30
|
/** `POST /v1/remote-web/pairing-challenge` request body. */
|
|
25
31
|
export interface RemoteWebPairingChallengeRequest {
|
|
26
32
|
/** Public https base URL the scanning device can reach the assistant at. */
|
|
@@ -69,11 +69,23 @@ interface PendingRequest {
|
|
|
69
69
|
// Client configuration
|
|
70
70
|
// ---------------------------------------------------------------------------
|
|
71
71
|
|
|
72
|
+
/** Minimal logger interface. Callers can supply pino, console, etc. */
|
|
73
|
+
export interface CesRpcLogger {
|
|
74
|
+
info(obj: Record<string, unknown>, msg: string): void;
|
|
75
|
+
info(msg: string): void;
|
|
76
|
+
}
|
|
77
|
+
|
|
72
78
|
export interface CesRpcClientConfig {
|
|
73
79
|
/** Timeout for individual RPC requests (ms). Default: 30 000 */
|
|
74
80
|
requestTimeoutMs?: number;
|
|
75
81
|
/** Timeout for the initial handshake (ms). Default: 10 000 */
|
|
76
82
|
handshakeTimeoutMs?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Optional logger for lifecycle transitions (handshake accepted, close).
|
|
85
|
+
* These transitions are otherwise invisible, which made a stuck credential
|
|
86
|
+
* backend hard to diagnose.
|
|
87
|
+
*/
|
|
88
|
+
logger?: CesRpcLogger;
|
|
77
89
|
}
|
|
78
90
|
|
|
79
91
|
const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
|
@@ -154,12 +166,15 @@ export function createCesRpcClient(
|
|
|
154
166
|
config?.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
155
167
|
const handshakeTimeoutMs =
|
|
156
168
|
config?.handshakeTimeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS;
|
|
169
|
+
const logger = config?.logger;
|
|
157
170
|
|
|
158
171
|
const sessionId = randomUUID();
|
|
159
172
|
let requestCounter = 0;
|
|
160
173
|
let ready = false;
|
|
161
|
-
let inflightHandshake: Promise<{
|
|
162
|
-
|
|
174
|
+
let inflightHandshake: Promise<{
|
|
175
|
+
accepted: boolean;
|
|
176
|
+
reason?: string;
|
|
177
|
+
}> | null = null;
|
|
163
178
|
|
|
164
179
|
const pending = new Map<string, PendingRequest>();
|
|
165
180
|
|
|
@@ -380,6 +395,7 @@ export function createCesRpcClient(
|
|
|
380
395
|
|
|
381
396
|
if (ack.accepted) {
|
|
382
397
|
ready = true;
|
|
398
|
+
logger?.info("CES RPC client handshake accepted; ready for calls");
|
|
383
399
|
}
|
|
384
400
|
|
|
385
401
|
return { accepted: ack.accepted, reason: ack.reason };
|
|
@@ -413,6 +429,7 @@ export function createCesRpcClient(
|
|
|
413
429
|
close(): void {
|
|
414
430
|
rejectAllPending(new CesTransportError("CES client closed"));
|
|
415
431
|
ready = false;
|
|
432
|
+
logger?.info("CES RPC client closed");
|
|
416
433
|
transport.close();
|
|
417
434
|
},
|
|
418
435
|
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pins the environment-to-cloud-hub mapping in one place. Both consumers
|
|
3
|
+
* (the Capacitor shell's `server.url` and the CLI remote-web edge's
|
|
4
|
+
* `hubUrl`) read this helper, so this matrix is the single behavioral pin
|
|
5
|
+
* for the served URLs.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, expect, test } from "bun:test";
|
|
9
|
+
|
|
10
|
+
import { cloudAssistantHubUrl, SEEDS } from "../index.js";
|
|
11
|
+
|
|
12
|
+
describe("cloudAssistantHubUrl", () => {
|
|
13
|
+
test("cloud environments resolve to their own web origin", () => {
|
|
14
|
+
expect(cloudAssistantHubUrl("production")).toBe(
|
|
15
|
+
"https://www.vellum.ai/assistant",
|
|
16
|
+
);
|
|
17
|
+
expect(cloudAssistantHubUrl("staging")).toBe(
|
|
18
|
+
"https://staging-assistant.vellum.ai/assistant",
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("every other environment falls back to the dev SPA", () => {
|
|
23
|
+
for (const name of ["dev", "test", "local", "unknown-env", undefined]) {
|
|
24
|
+
expect(cloudAssistantHubUrl(name)).toBe(
|
|
25
|
+
"https://dev-assistant.vellum.ai/assistant",
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("cloud hub URLs derive from the seed web URLs", () => {
|
|
31
|
+
for (const name of ["production", "staging"]) {
|
|
32
|
+
expect(cloudAssistantHubUrl(name)).toBe(
|
|
33
|
+
`${SEEDS[name].webUrl}/assistant`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
expect(cloudAssistantHubUrl("local")).toBe(`${SEEDS.dev.webUrl}/assistant`);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for reading an install layout: telling a repo checkout from an
|
|
3
|
+
* installed package, and locating the `assistant` command that ships with an
|
|
4
|
+
* install.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
11
|
+
|
|
12
|
+
import { findAssistantCommand, isRepoCheckoutPath } from "../index.js";
|
|
13
|
+
|
|
14
|
+
let root: string;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
root = mkdtempSync(join(tmpdir(), "install-layout-"));
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
rmSync(root, { recursive: true, force: true });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
/** Create `<nodeModulesDir>/.bin/assistant` and return its path. */
|
|
25
|
+
function seedCommand(nodeModulesDir: string): string {
|
|
26
|
+
const binDir = join(nodeModulesDir, ".bin");
|
|
27
|
+
mkdirSync(binDir, { recursive: true });
|
|
28
|
+
const command = join(binDir, "assistant");
|
|
29
|
+
writeFileSync(command, "#!/usr/bin/env bun\n");
|
|
30
|
+
return command;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe("isRepoCheckoutPath", () => {
|
|
34
|
+
test("an installed package is not a checkout", () => {
|
|
35
|
+
expect(
|
|
36
|
+
isRepoCheckoutPath(
|
|
37
|
+
"/Users/x/Library/Application Support/@vellumai/macos/cli/latest/node_modules/@vellumai/assistant/src/index.ts",
|
|
38
|
+
),
|
|
39
|
+
).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("a repo checkout is", () => {
|
|
43
|
+
expect(
|
|
44
|
+
isRepoCheckoutPath("/Users/x/dev/vellum/assistant/src/index.ts"),
|
|
45
|
+
).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("a directory merely named node_modules-ish is not enough", () => {
|
|
49
|
+
expect(
|
|
50
|
+
isRepoCheckoutPath("/Users/x/node_modules_backup/a/src/index.ts"),
|
|
51
|
+
).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe("findAssistantCommand", () => {
|
|
56
|
+
test("finds the command shipped beside an installed package", () => {
|
|
57
|
+
const nodeModules = join(root, "cli", "latest", "node_modules");
|
|
58
|
+
const command = seedCommand(nodeModules);
|
|
59
|
+
const path = join(nodeModules, "@vellumai", "assistant", "src", "index.ts");
|
|
60
|
+
|
|
61
|
+
expect(findAssistantCommand(path)).toBe(command);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("prefers a nested install over a hoisted one", () => {
|
|
65
|
+
const outer = join(root, "node_modules");
|
|
66
|
+
const outerCommand = seedCommand(outer);
|
|
67
|
+
const inner = join(outer, "vellum", "node_modules");
|
|
68
|
+
const innerCommand = seedCommand(inner);
|
|
69
|
+
const path = join(inner, "@vellumai", "assistant", "src", "index.ts");
|
|
70
|
+
|
|
71
|
+
expect(findAssistantCommand(path)).toBe(innerCommand);
|
|
72
|
+
expect(innerCommand).not.toBe(outerCommand);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("falls back to a hoisted install when the nested one has no command", () => {
|
|
76
|
+
const outer = join(root, "node_modules");
|
|
77
|
+
const outerCommand = seedCommand(outer);
|
|
78
|
+
const inner = join(outer, "vellum", "node_modules");
|
|
79
|
+
mkdirSync(inner, { recursive: true });
|
|
80
|
+
const path = join(inner, "@vellumai", "assistant", "src", "index.ts");
|
|
81
|
+
|
|
82
|
+
expect(findAssistantCommand(path)).toBe(outerCommand);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("returns null for a repo checkout", () => {
|
|
86
|
+
expect(
|
|
87
|
+
findAssistantCommand(join(root, "assistant", "src", "index.ts")),
|
|
88
|
+
).toBeNull();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("returns null when the install ships no assistant command", () => {
|
|
92
|
+
const nodeModules = join(root, "node_modules");
|
|
93
|
+
mkdirSync(join(nodeModules, ".bin"), { recursive: true });
|
|
94
|
+
const path = join(nodeModules, "@vellumai", "assistant", "src", "index.ts");
|
|
95
|
+
|
|
96
|
+
expect(findAssistantCommand(path)).toBeNull();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Package boundary tests for @vellumai/environments.
|
|
3
3
|
*
|
|
4
|
-
* This package is the lowest layer of the shared-packages hierarchy:
|
|
5
|
-
* environment types and
|
|
6
|
-
* stay a leaf so any consumer (CLI, assistant,
|
|
7
|
-
* on it without dragging in a dependency tree.
|
|
4
|
+
* This package is the lowest layer of the shared-packages hierarchy:
|
|
5
|
+
* environment types, constants, and small helpers over node builtins, with no
|
|
6
|
+
* runtime dependencies. It must stay a leaf so any consumer (CLI, assistant,
|
|
7
|
+
* local-mode host) can depend on it without dragging in a dependency tree.
|
|
8
8
|
*
|
|
9
9
|
* Enforces that the package:
|
|
10
10
|
* 1. Imports only node builtins and its own relative modules — no `@vellumai/*`
|
|
@@ -79,7 +79,7 @@ describe("package boundary", () => {
|
|
|
79
79
|
throw new Error(
|
|
80
80
|
`Found ${violations.length} forbidden import(s) in @vellumai/environments:\n` +
|
|
81
81
|
violations.map((v) => ` - ${v}`).join("\n") +
|
|
82
|
-
"\n\n@vellumai/environments is a
|
|
82
|
+
"\n\n@vellumai/environments is a dependency-free leaf and must\n" +
|
|
83
83
|
"import only node builtins and its own relative modules.",
|
|
84
84
|
);
|
|
85
85
|
}
|