@vellumai/assistant 0.11.2 → 0.11.3-dev.202608080427.92f668a
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 +69 -9
- package/docs/flux-turn-detection-spike.md +243 -0
- package/docs/stt-provider-onboarding.md +3 -1
- 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 +50 -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 +50 -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 +50 -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 +619 -47
- package/package.json +1 -1
- package/scripts/voice-ttft-spike.ts +3 -3
- 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-controller.test.ts +120 -0
- 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-availability-routes.test.ts +14 -1
- 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__/config-loader-backfill.test.ts +19 -0
- package/src/__tests__/config-schema.test.ts +150 -7
- 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 +54 -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 +294 -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-list-plugin-servers.test.ts +250 -0
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
- package/src/__tests__/media-stream-output.test.ts +175 -0
- package/src/__tests__/media-stream-server-integration.test.ts +36 -0
- package/src/__tests__/media-stream-stt-session.test.ts +67 -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__/skills.test.ts +32 -0
- 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/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +150 -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__/tts-text-sanitizer.test.ts +13 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +131 -12
- package/src/calls/__tests__/voice-triage-escalate.test.ts +106 -0
- package/src/calls/call-controller.ts +30 -2
- package/src/calls/call-speech-output.ts +12 -4
- package/src/calls/call-transport.ts +18 -1
- package/src/calls/media-stream-output.ts +53 -5
- package/src/calls/media-stream-server.ts +21 -1
- package/src/calls/media-stream-stt-session.ts +49 -0
- package/src/calls/telephony-synthesis-language.ts +84 -0
- package/src/calls/tts-text-sanitizer.ts +12 -5
- package/src/calls/voice-session-bridge.ts +86 -17
- package/src/calls/voice-triage-escalate.ts +54 -7
- package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
- package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
- package/src/channels/config.ts +20 -2
- package/src/channels/gateway-verification-sessions.ts +7 -2
- package/src/channels/plugin-channel-declarations.ts +108 -0
- package/src/channels/types.ts +37 -1
- package/src/cli/AGENTS.md +5 -2
- 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 +17 -6
- package/src/cli/commands/mcp.ts +9 -0
- 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/stt.help.ts +27 -2
- 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 +161 -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 +60 -0
- package/src/cli.ts +1 -1
- package/src/config/__tests__/default-profile-catalog.test.ts +11 -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/acp/SKILL.md +6 -7
- 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/media-processing/services/preprocess.ts +14 -4
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +15 -15
- 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 +3 -3
- 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/transcribe/tools/transcribe-media.test.ts +22 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
- package/src/config/bundled-skills/visualize/SKILL.md +1 -1
- package/src/config/call-site-defaults.ts +4 -5
- package/src/config/default-profile-catalog.ts +9 -5
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +45 -15
- package/src/config/loader.ts +75 -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__/live-voice.test.ts +142 -4
- package/src/config/schemas/__tests__/stt.test.ts +20 -5
- package/src/config/schemas/call-site-catalog.ts +4 -4
- package/src/config/schemas/calls.ts +0 -4
- package/src/config/schemas/channels.ts +13 -0
- package/src/config/schemas/live-voice.ts +82 -23
- package/src/config/schemas/llm.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +25 -0
- package/src/config/schemas/plugin-updates.ts +59 -0
- package/src/config/schemas/services.ts +8 -4
- package/src/config/schemas/stt.ts +18 -5
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/config/schemas/tts.ts +63 -0
- 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/inbound/__tests__/oauth-callback-url.test.ts +83 -0
- package/src/inbound/oauth-callback-url.ts +61 -0
- 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-agent-turn.test.ts +1 -104
- 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-events.test.ts +7 -8
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +932 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +12 -5
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
- package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +179 -146
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +324 -2
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +131 -2
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
- package/src/live-voice/__tests__/live-voice-tts.test.ts +148 -2
- package/src/live-voice/__tests__/live-voice-vad.test.ts +313 -32
- package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
- package/src/live-voice/__tests__/progress-phrases.test.ts +167 -0
- 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-metrics.ts +57 -32
- package/src/live-voice/live-voice-photo.ts +168 -0
- package/src/live-voice/live-voice-session.ts +1137 -351
- package/src/live-voice/live-voice-tts.ts +18 -2
- package/src/live-voice/progress-narration.ts +277 -0
- package/src/live-voice/progress-phrases.ts +105 -2
- package/src/live-voice/protocol.ts +110 -2
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +196 -0
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
- package/src/mcp/client.ts +14 -7
- package/src/mcp/mcp-auth-orchestrator.ts +13 -22
- package/src/mcp/mcp-oauth-provider.ts +195 -240
- 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 +495 -0
- package/src/monitoring/db-integrity-sample.ts +6 -1
- package/src/monitoring/plugin-auto-update.ts +463 -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 +13 -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/__tests__/oauth-callback-url-export.test.ts +29 -0
- package/src/plugin-api/index.ts +28 -5
- package/src/plugin-api/webhook-url.ts +151 -0
- package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
- package/src/plugins/__tests__/mcp-servers.test.ts +370 -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/skill-content.ts +8 -1
- 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 +64 -8
- package/src/plugins/installed-plugin-dirs.ts +101 -0
- package/src/plugins/mcp-servers.ts +343 -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 +72 -2
- 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__/deepgram-flux-frames.test.ts +433 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +620 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +472 -12
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +719 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +283 -1
- package/src/providers/speech-to-text/deepgram-realtime.ts +117 -3
- package/src/providers/speech-to-text/deepgram.ts +1 -0
- package/src/providers/speech-to-text/provider-catalog.ts +137 -8
- package/src/providers/speech-to-text/resolve.ts +105 -12
- 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/__tests__/local-actor-identity-force-refresh.test.ts +104 -0
- package/src/runtime/agent-wake.ts +63 -24
- package/src/runtime/assistant-event-hub.ts +110 -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 +29 -14
- 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 +217 -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__/sse-actor-principal-heal.test.ts +165 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +2 -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-availability-routes.ts +32 -14
- 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 +20 -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 +29 -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/mcp-auth-routes.ts +141 -57
- 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 +127 -4
- 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/sse-actor-principal-heal.ts +113 -0
- package/src/runtime/routes/stt-routes.ts +31 -25
- 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/oauth2.ts +6 -22
- 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/__tests__/daemon-batch-transcriber.test.ts +22 -0
- package/src/stt/__tests__/language-metadata.test.ts +85 -0
- package/src/stt/__tests__/speech-energy.test.ts +79 -0
- package/src/stt/__tests__/types.test.ts +94 -0
- package/src/stt/daemon-batch-transcriber.ts +18 -6
- package/src/stt/language-metadata.ts +65 -0
- package/src/stt/speech-energy.ts +115 -12
- package/src/stt/stt-stream-session.ts +8 -4
- package/src/stt/types.ts +119 -0
- 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 +303 -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/tts/__tests__/provider-adapters.test.ts +147 -0
- package/src/tts/__tests__/speakable-segments.test.ts +470 -0
- package/src/tts/language-voices.ts +23 -0
- package/src/tts/providers/deepgram-provider.ts +3 -1
- package/src/tts/providers/elevenlabs-provider.ts +73 -1
- package/src/tts/providers/xai-provider.ts +28 -2
- package/src/tts/speakable-segments.ts +293 -23
- package/src/tts/synthesis-stream.ts +7 -0
- package/src/tts/types.ts +7 -0
- package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
- package/src/usage/subagent-attribution.ts +108 -0
- package/src/util/__tests__/language-subtag.test.ts +54 -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/language-subtag.ts +43 -0
- package/src/util/schedule-source-key.ts +23 -0
- package/src/util/unicode.ts +1 -1
- 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/142-consolidate-voice-front-door.ts +70 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +116 -0
- package/src/workspace/migrations/registry.ts +6 -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/live-voice/__tests__/front-decision.test.ts +0 -525
- package/src/live-voice/front-decision.ts +0 -429
- package/src/notifications/deferred-emit.ts +0 -147
|
@@ -288,6 +288,31 @@ describe("stt-routes", () => {
|
|
|
288
288
|
expect(err.message).toContain("not available");
|
|
289
289
|
});
|
|
290
290
|
|
|
291
|
+
test("surfaces a typed resolver error verbatim instead of the generic copy", async () => {
|
|
292
|
+
// A streaming-only provider IS configured, so the "nothing configured"
|
|
293
|
+
// and "not available" strings would both send the caller looking for a
|
|
294
|
+
// problem that does not exist.
|
|
295
|
+
const reason =
|
|
296
|
+
'Deepgram Flux is streaming-only. Batch transcription requires the deepgram provider: set services.stt.provider to "deepgram".';
|
|
297
|
+
mockResolveError = new SttError("provider-error", reason, {
|
|
298
|
+
userFacing: true,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const { handler } = getRoute("stt/transcribe");
|
|
302
|
+
const err = await expectRouteError(
|
|
303
|
+
() =>
|
|
304
|
+
handler(
|
|
305
|
+
makeArgs({
|
|
306
|
+
audioBase64: toBase64("audio-data"),
|
|
307
|
+
mimeType: "audio/wav",
|
|
308
|
+
}),
|
|
309
|
+
),
|
|
310
|
+
503,
|
|
311
|
+
"SERVICE_UNAVAILABLE",
|
|
312
|
+
);
|
|
313
|
+
expect(err.message).toBe(reason);
|
|
314
|
+
});
|
|
315
|
+
|
|
291
316
|
// -- Timeout --------------------------------------------------------------
|
|
292
317
|
|
|
293
318
|
test("throws 504 when transcription times out", async () => {
|
|
@@ -59,6 +59,8 @@ let mockReResolve: { trustClass: string; sourceChannel: string } | null = null;
|
|
|
59
59
|
mock.module("../../../contacts/guardian-delivery-reader.js", () => ({
|
|
60
60
|
getGuardianDelivery: (_input?: { channelTypes?: string[] }) =>
|
|
61
61
|
Promise.resolve(mockGuardianList),
|
|
62
|
+
getGuardianDeliveryFresh: (_input?: { channelTypes?: string[] }) =>
|
|
63
|
+
Promise.resolve(mockGuardianList),
|
|
62
64
|
peekCachedGuardianDelivery: () => mockGuardianList ?? undefined,
|
|
63
65
|
guardianForChannel: (
|
|
64
66
|
list: Array<Record<string, unknown>>,
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* Asserts the `wake_conversation` route elevates trust from the caller's
|
|
3
3
|
* verified principal type, never the request body: a `local` (CLI/IPC) caller
|
|
4
4
|
* runs the woken turn as a non-interactive guardian (clientless + guardian
|
|
5
|
-
* trustContext) and may attribute cost to a body-supplied `cronRunId
|
|
6
|
-
*
|
|
5
|
+
* trustContext) and may attribute cost to a body-supplied `cronRunId` and run
|
|
6
|
+
* on a body-supplied schedule's pinned inference profile; a remote `actor`
|
|
7
|
+
* stays `unknown`/interactive and its body `cronRunId` and `scheduleId` are
|
|
8
|
+
* ignored.
|
|
7
9
|
*/
|
|
8
10
|
|
|
9
11
|
import { describe, expect, mock, test } from "bun:test";
|
|
@@ -13,6 +15,7 @@ interface CapturedWake {
|
|
|
13
15
|
hint: string;
|
|
14
16
|
trustContext?: { sourceChannel: string; trustClass: string };
|
|
15
17
|
cronRunId?: string;
|
|
18
|
+
forceOverrideProfile?: string;
|
|
16
19
|
clientless?: boolean;
|
|
17
20
|
persistTriggerAsEvent?: boolean;
|
|
18
21
|
untrustedOutput?: { content: string; source: string };
|
|
@@ -25,6 +28,14 @@ mock.module("../../agent-wake.js", () => ({
|
|
|
25
28
|
},
|
|
26
29
|
}));
|
|
27
30
|
|
|
31
|
+
const schedules = new Map<string, { inferenceProfile: string | null }>([
|
|
32
|
+
["sched-pinned", { inferenceProfile: "profile-cheap" }],
|
|
33
|
+
["sched-unpinned", { inferenceProfile: null }],
|
|
34
|
+
]);
|
|
35
|
+
mock.module("../../../schedule/schedule-store.js", () => ({
|
|
36
|
+
getSchedule: (id: string) => schedules.get(id) ?? null,
|
|
37
|
+
}));
|
|
38
|
+
|
|
28
39
|
import { createConversation } from "../../../persistence/conversation-crud.js";
|
|
29
40
|
import { initializeDb } from "../../../persistence/db-init.js";
|
|
30
41
|
import { ROUTES } from "../wake-conversation-routes.js";
|
|
@@ -85,6 +96,53 @@ describe("wake_conversation principal-gated elevation", () => {
|
|
|
85
96
|
});
|
|
86
97
|
});
|
|
87
98
|
|
|
99
|
+
describe("wake_conversation schedule profile pin", () => {
|
|
100
|
+
test("local principal → woken turn runs on the schedule's pinned profile", async () => {
|
|
101
|
+
wakeCalls.length = 0;
|
|
102
|
+
const conversationId = makeConversation();
|
|
103
|
+
await handler({
|
|
104
|
+
body: { conversationId, hint: "poll result", scheduleId: "sched-pinned" },
|
|
105
|
+
headers: { "x-vellum-principal-type": "local" },
|
|
106
|
+
});
|
|
107
|
+
expect(wakeCalls[0].forceOverrideProfile).toBe("profile-cheap");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("schedule with no pinned profile leaves resolution unchanged", async () => {
|
|
111
|
+
wakeCalls.length = 0;
|
|
112
|
+
const conversationId = makeConversation();
|
|
113
|
+
await handler({
|
|
114
|
+
body: {
|
|
115
|
+
conversationId,
|
|
116
|
+
hint: "poll result",
|
|
117
|
+
scheduleId: "sched-unpinned",
|
|
118
|
+
},
|
|
119
|
+
headers: { "x-vellum-principal-type": "local" },
|
|
120
|
+
});
|
|
121
|
+
expect(wakeCalls[0].forceOverrideProfile).toBeUndefined();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("unknown scheduleId resolves as an ordinary wake", async () => {
|
|
125
|
+
wakeCalls.length = 0;
|
|
126
|
+
const conversationId = makeConversation();
|
|
127
|
+
const result = await handler({
|
|
128
|
+
body: { conversationId, hint: "poll result", scheduleId: "sched-gone" },
|
|
129
|
+
headers: { "x-vellum-principal-type": "local" },
|
|
130
|
+
});
|
|
131
|
+
expect(result).toEqual({ invoked: true, producedToolCalls: false });
|
|
132
|
+
expect(wakeCalls[0].forceOverrideProfile).toBeUndefined();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("actor principal → body scheduleId is ignored", async () => {
|
|
136
|
+
wakeCalls.length = 0;
|
|
137
|
+
const conversationId = makeConversation();
|
|
138
|
+
await handler({
|
|
139
|
+
body: { conversationId, hint: "poll result", scheduleId: "sched-pinned" },
|
|
140
|
+
headers: { "x-vellum-principal-type": "actor" },
|
|
141
|
+
});
|
|
142
|
+
expect(wakeCalls[0].forceOverrideProfile).toBeUndefined();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
88
146
|
describe("wake_conversation fencing", () => {
|
|
89
147
|
test("persist + externalContent fence untrusted data, keep hint trusted", async () => {
|
|
90
148
|
wakeCalls.length = 0;
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
* log export and profiler export routes.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { execFile } from "node:child_process";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
|
|
9
|
+
const execFileAsync = promisify(execFile);
|
|
7
10
|
|
|
8
11
|
/** Maximum compressed archive size (50 MB). */
|
|
9
12
|
export const MAX_ARCHIVE_BYTES = 50 * 1024 * 1024;
|
|
@@ -13,19 +16,20 @@ export const MAX_ARCHIVE_BYTES = 50 * 1024 * 1024;
|
|
|
13
16
|
* Returns the Buffer on success, or `undefined` if the archive exceeds
|
|
14
17
|
* the size limit or tar otherwise fails.
|
|
15
18
|
*/
|
|
16
|
-
export function createTarGz(
|
|
19
|
+
export async function createTarGz(
|
|
17
20
|
staging: string,
|
|
18
21
|
maxBytes: number = MAX_ARCHIVE_BYTES,
|
|
19
|
-
): ArrayBuffer | undefined {
|
|
20
|
-
|
|
21
|
-
maxBuffer
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
): Promise<ArrayBuffer | undefined> {
|
|
23
|
+
try {
|
|
24
|
+
// Exceeding maxBuffer rejects, which maps to the undefined failure return.
|
|
25
|
+
const { stdout } = await execFileAsync(
|
|
26
|
+
"tar",
|
|
27
|
+
["czf", "-", "-C", staging, "."],
|
|
28
|
+
{ maxBuffer: maxBytes, timeout: 30_000, encoding: "buffer" },
|
|
29
|
+
);
|
|
30
|
+
const buf = Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout);
|
|
31
|
+
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
32
|
+
} catch {
|
|
25
33
|
return undefined;
|
|
26
34
|
}
|
|
27
|
-
const buf = Buffer.isBuffer(proc.stdout)
|
|
28
|
-
? proc.stdout
|
|
29
|
-
: Buffer.from(proc.stdout);
|
|
30
|
-
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
31
35
|
}
|
|
@@ -238,7 +238,7 @@ async function handleMultipartUpload(
|
|
|
238
238
|
|
|
239
239
|
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
240
240
|
|
|
241
|
-
const attachment = uploadAttachmentFromBytes(filename, mimeType, bytes);
|
|
241
|
+
const attachment = await uploadAttachmentFromBytes(filename, mimeType, bytes);
|
|
242
242
|
return attachmentPayload(attachment);
|
|
243
243
|
}
|
|
244
244
|
|
|
@@ -248,7 +248,7 @@ async function handleMultipartUpload(
|
|
|
248
248
|
*
|
|
249
249
|
* See `handleMultipartUpload` for `gatewayTrustedSource` semantics.
|
|
250
250
|
*/
|
|
251
|
-
function handleOctetStreamUpload(
|
|
251
|
+
async function handleOctetStreamUpload(
|
|
252
252
|
rawBody: Uint8Array,
|
|
253
253
|
headers: Record<string, string>,
|
|
254
254
|
queryParams: Record<string, string>,
|
|
@@ -287,7 +287,11 @@ function handleOctetStreamUpload(
|
|
|
287
287
|
throw new UnsupportedMediaTypeError(validation.error);
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
const attachment = uploadAttachmentFromBytes(
|
|
290
|
+
const attachment = await uploadAttachmentFromBytes(
|
|
291
|
+
filename,
|
|
292
|
+
mimeType,
|
|
293
|
+
rawBody,
|
|
294
|
+
);
|
|
291
295
|
return attachmentPayload(attachment);
|
|
292
296
|
}
|
|
293
297
|
|
|
@@ -296,7 +300,7 @@ function handleOctetStreamUpload(
|
|
|
296
300
|
*
|
|
297
301
|
* See `handleMultipartUpload` for `gatewayTrustedSource` semantics.
|
|
298
302
|
*/
|
|
299
|
-
function handleJsonUpload(
|
|
303
|
+
async function handleJsonUpload(
|
|
300
304
|
body: Record<string, unknown>,
|
|
301
305
|
rawBody: Uint8Array | undefined,
|
|
302
306
|
gatewayTrustedSource: boolean,
|
|
@@ -369,7 +373,10 @@ function handleJsonUpload(
|
|
|
369
373
|
// non-HEIF files (e.g. large videos) from being read into memory.
|
|
370
374
|
try {
|
|
371
375
|
if (isHeifImage(readFileHead(destPath, 12))) {
|
|
372
|
-
const norm = normalizeImageBytes(
|
|
376
|
+
const norm = await normalizeImageBytes(
|
|
377
|
+
mimeType,
|
|
378
|
+
readFileSync(destPath),
|
|
379
|
+
);
|
|
373
380
|
if (
|
|
374
381
|
norm.converted &&
|
|
375
382
|
norm.bytes.length <= MAX_FILE_BACKED_UPLOAD_BYTES
|
|
@@ -407,7 +414,7 @@ function handleJsonUpload(
|
|
|
407
414
|
}
|
|
408
415
|
|
|
409
416
|
try {
|
|
410
|
-
attachment = uploadAttachment(
|
|
417
|
+
attachment = await uploadAttachment(
|
|
411
418
|
filename,
|
|
412
419
|
mimeType,
|
|
413
420
|
data,
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deferred release for the canned-reply routes (canned first greeting, unknown
|
|
3
|
+
* slash command).
|
|
4
|
+
*
|
|
5
|
+
* These routes answer without an agent loop, so they hold the processing lock
|
|
6
|
+
* themselves and are the only thing that will ever clear it. They publish their
|
|
7
|
+
* client events on the next tick so the HTTP 202 reaches the client first and
|
|
8
|
+
* its `serverToLocalConversationMap` is populated before any SSE arrives, and
|
|
9
|
+
* they release only after that burst so the next queued message cannot start
|
|
10
|
+
* processing ahead of the reply the client is still being told about.
|
|
11
|
+
*
|
|
12
|
+
* The release therefore has to be unconditional: a throw from any broadcast in
|
|
13
|
+
* the burst would otherwise latch the conversation "processing" with no agent
|
|
14
|
+
* loop, no `finally`, and no later path left to clear it, so every subsequent
|
|
15
|
+
* send is queued behind an idle conversation for the life of the daemon.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { Conversation } from "../../daemon/conversation.js";
|
|
19
|
+
import { getLogger } from "../../util/logger.js";
|
|
20
|
+
|
|
21
|
+
const log = getLogger("canned-reply-release");
|
|
22
|
+
|
|
23
|
+
/** The conversation surface {@link scheduleCannedReplyRelease} touches. */
|
|
24
|
+
export type CannedReplyReleaseTarget = Pick<
|
|
25
|
+
Conversation,
|
|
26
|
+
"setProcessing" | "kickDrainQueue"
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
export function scheduleCannedReplyRelease(params: {
|
|
30
|
+
conversation: CannedReplyReleaseTarget;
|
|
31
|
+
/** Names the release site in drain logs (e.g. `"canned_greeting"`). */
|
|
32
|
+
origin: string;
|
|
33
|
+
/** The deferred client event burst. Runs before the release. */
|
|
34
|
+
emit: () => void;
|
|
35
|
+
/** Optional work that only makes sense once the lock is free. */
|
|
36
|
+
afterRelease?: () => void;
|
|
37
|
+
}): void {
|
|
38
|
+
const { conversation, origin, emit, afterRelease } = params;
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
try {
|
|
41
|
+
emit();
|
|
42
|
+
} catch (err) {
|
|
43
|
+
// Swallowed rather than rethrown: this runs from a timer with no caller
|
|
44
|
+
// left to handle it, so an escaping error is an uncaught exception in
|
|
45
|
+
// the daemon process. The reply is already persisted, and clients
|
|
46
|
+
// reconcile a missed event burst on their next fetch.
|
|
47
|
+
log.error({ err, origin }, "Canned reply event burst failed");
|
|
48
|
+
} finally {
|
|
49
|
+
conversation.setProcessing(false);
|
|
50
|
+
void conversation.kickDrainQueue("loop_complete", origin);
|
|
51
|
+
}
|
|
52
|
+
afterRelease?.();
|
|
53
|
+
}, 0);
|
|
54
|
+
}
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* GET /v1/channels/available — return the channels this assistant can
|
|
5
5
|
* surface to clients (Contacts / GuardianChannels views, etc.) along with
|
|
6
6
|
* their display metadata (label, subtitle, icon, verification capability,
|
|
7
|
-
* setup-message copy).
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* switches.
|
|
7
|
+
* setup-message copy). A fixed base list, plus `email` when an inbox is
|
|
8
|
+
* registered, plus the channels installed plugins bring by declaring
|
|
9
|
+
* ingress. One list, because a plugin channel is a channel; each row's
|
|
10
|
+
* `source` says who contributes it. Clients should treat the response as
|
|
11
|
+
* authoritative and stop carrying their own per-channel switches.
|
|
12
12
|
*
|
|
13
13
|
* Distinct from `/v1/channels/readiness` (which answers "is this channel
|
|
14
14
|
* configured and working?"). Availability answers "could this channel be
|
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
import { z } from "zod";
|
|
19
19
|
|
|
20
20
|
import { isA2AEnabled } from "../../a2a/feature-gate.js";
|
|
21
|
+
import { discoverPluginChannels } from "../../channels/plugin-channel-declarations.js";
|
|
21
22
|
import {
|
|
22
|
-
|
|
23
|
+
type AvailableChannel,
|
|
23
24
|
CHANNEL_METADATA,
|
|
24
25
|
type ChannelId,
|
|
25
26
|
type ChannelInfo,
|
|
@@ -73,7 +74,7 @@ async function hasRegisteredInbox(): Promise<boolean> {
|
|
|
73
74
|
|
|
74
75
|
async function handleGetChannelAvailability(
|
|
75
76
|
_args: RouteHandlerArgs,
|
|
76
|
-
): Promise<{ channels:
|
|
77
|
+
): Promise<{ channels: AvailableChannel[] }> {
|
|
77
78
|
const ids: ChannelId[] = [...BASE_AVAILABLE_CHANNELS];
|
|
78
79
|
if (await hasRegisteredInbox()) {
|
|
79
80
|
ids.push("email");
|
|
@@ -86,14 +87,26 @@ async function handleGetChannelAvailability(
|
|
|
86
87
|
// contains channels that BASE_AVAILABLE_CHANNELS / the email branch
|
|
87
88
|
// explicitly chose, so the lookup is always defined — filter to satisfy
|
|
88
89
|
// the type system without a non-null assertion.
|
|
89
|
-
const
|
|
90
|
+
const builtIn: AvailableChannel[] = ids
|
|
90
91
|
.map((id) => CHANNEL_METADATA[id])
|
|
91
|
-
.filter((info): info is ChannelInfo => info !== undefined)
|
|
92
|
-
|
|
92
|
+
.filter((info): info is ChannelInfo => info !== undefined)
|
|
93
|
+
.map((info) => ({ ...info, source: "default" as const }));
|
|
94
|
+
// One list, because a plugin channel is a channel: what differs is who
|
|
95
|
+
// contributes it, which is what `source` says. Built-ins lead, so a client
|
|
96
|
+
// rendering in order gets a stable list that plugin installs append to.
|
|
97
|
+
return { channels: [...builtIn, ...(await discoverPluginChannels())] };
|
|
93
98
|
}
|
|
94
99
|
|
|
95
100
|
const channelInfoSchema = z.object({
|
|
96
|
-
|
|
101
|
+
// A string rather than the channel enum: a plugin channel's id is its
|
|
102
|
+
// plugin name, and `source` is what says which kind a row is.
|
|
103
|
+
id: z.string(),
|
|
104
|
+
source: z
|
|
105
|
+
.string()
|
|
106
|
+
.describe(
|
|
107
|
+
"`default` for a channel the assistant ships, `plugin:<name>` for one " +
|
|
108
|
+
"an installed plugin brings",
|
|
109
|
+
),
|
|
97
110
|
label: z.string(),
|
|
98
111
|
subtitle: z.string(),
|
|
99
112
|
icon: z.string(),
|
|
@@ -117,14 +130,19 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
117
130
|
description:
|
|
118
131
|
"Return the channels this assistant can surface to clients, with " +
|
|
119
132
|
"display metadata (label, icon, verification capability, setup " +
|
|
120
|
-
"copy).
|
|
121
|
-
"
|
|
133
|
+
"copy). A fixed base list plus `email` when an inbox is registered, " +
|
|
134
|
+
"plus the channels installed plugins bring by declaring ingress " +
|
|
135
|
+
"routes. Each carries a `source` saying which of those it is.",
|
|
122
136
|
tags: ["channels"],
|
|
123
137
|
handler: handleGetChannelAvailability,
|
|
124
138
|
responseBody: z.object({
|
|
125
139
|
channels: z
|
|
126
140
|
.array(channelInfoSchema)
|
|
127
|
-
.describe(
|
|
141
|
+
.describe(
|
|
142
|
+
"Available channels in display order: the ones the assistant " +
|
|
143
|
+
"ships, then the ones installed plugins bring by declaring " +
|
|
144
|
+
"ingress routes. `source` distinguishes them.",
|
|
145
|
+
),
|
|
128
146
|
}),
|
|
129
147
|
},
|
|
130
148
|
];
|
|
@@ -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;
|