@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
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retrying self-heal for an SSE client subscription that registered without an
|
|
3
|
+
* actor principal.
|
|
4
|
+
*
|
|
5
|
+
* In `DISABLE_HTTP_AUTH` deployments the SSE subscribe path cannot await, so it
|
|
6
|
+
* resolves the dev-bypass actor principal from an IO-free peek at the
|
|
7
|
+
* guardian-delivery cache. A cold cache registers the subscription with
|
|
8
|
+
* `actorPrincipalId: undefined`, and every host-proxy result that client
|
|
9
|
+
* submits then fails the same-actor gate with `missing_target`: a 403 that only
|
|
10
|
+
* a fresh registration clears.
|
|
11
|
+
*
|
|
12
|
+
* The heal resolves the guardian asynchronously and patches the live hub
|
|
13
|
+
* record. Each attempt can come back empty, since the lookup goes over the
|
|
14
|
+
* gateway IPC and yields nothing both when the transport fails (unreachable
|
|
15
|
+
* gateway, its 2s timeout, a pod still starting) and when no guardian binding
|
|
16
|
+
* exists yet, so attempts repeat on a bounded backoff. The loop stops on the
|
|
17
|
+
* first success, when the connection is gone or already carries a principal, or
|
|
18
|
+
* when the schedule is exhausted.
|
|
19
|
+
*
|
|
20
|
+
* Callers must pass a cache-bypassing lookup: the guardian-delivery reader
|
|
21
|
+
* caches a successful empty result for minutes, which outlives the whole
|
|
22
|
+
* schedule, so a cached read would spend every attempt on the same stale
|
|
23
|
+
* answer.
|
|
24
|
+
*/
|
|
25
|
+
import { getLogger } from "../../util/logger.js";
|
|
26
|
+
|
|
27
|
+
const log = getLogger("sse-actor-heal");
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The hub surface this module needs: a liveness check and the fill. Narrow by
|
|
31
|
+
* design so tests can drive the loop without a real hub.
|
|
32
|
+
*/
|
|
33
|
+
export interface ActorPrincipalHealHub {
|
|
34
|
+
needsActorPrincipalHeal(connectionId: string): boolean;
|
|
35
|
+
fillClientActorPrincipalId(
|
|
36
|
+
connectionId: string,
|
|
37
|
+
actorPrincipalId: string,
|
|
38
|
+
): void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Delay before each attempt, in milliseconds. The leading zero dispatches the
|
|
43
|
+
* first attempt inline with the subscribe; the rest back off to cover a gateway
|
|
44
|
+
* that is slow to come up, without holding a timer for the life of a long-lived
|
|
45
|
+
* stream. Total span is about 44s.
|
|
46
|
+
*/
|
|
47
|
+
export const ACTOR_PRINCIPAL_HEAL_DELAYS_MS: readonly number[] = [
|
|
48
|
+
0, 1_000, 3_000, 10_000, 30_000,
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Start the retrying heal for `connectionId`. Fire-and-forget: never awaited by
|
|
53
|
+
* the route, never delays the stream.
|
|
54
|
+
*
|
|
55
|
+
* `resolve` performs the daemon's own server-side guardian lookup, bypassing
|
|
56
|
+
* the guardian-delivery cache. The value must never come from client input. It
|
|
57
|
+
* may resolve `undefined` (no binding yet, or the gateway is unreachable) or
|
|
58
|
+
* reject; both count as a failed attempt.
|
|
59
|
+
*/
|
|
60
|
+
export function startActorPrincipalHeal(args: {
|
|
61
|
+
hub: ActorPrincipalHealHub;
|
|
62
|
+
connectionId: string;
|
|
63
|
+
resolve: () => Promise<string | undefined>;
|
|
64
|
+
/** Override the backoff schedule. Tests pass all-zero delays. */
|
|
65
|
+
delaysMs?: readonly number[];
|
|
66
|
+
}): void {
|
|
67
|
+
const { hub, connectionId, resolve } = args;
|
|
68
|
+
const delays = args.delaysMs ?? ACTOR_PRINCIPAL_HEAL_DELAYS_MS;
|
|
69
|
+
|
|
70
|
+
void (async () => {
|
|
71
|
+
for (let attempt = 0; attempt < delays.length; attempt++) {
|
|
72
|
+
const delayMs = delays[attempt] ?? 0;
|
|
73
|
+
if (delayMs > 0) {
|
|
74
|
+
await sleep(delayMs);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Re-check every pass: the connection may have closed, been replaced by a
|
|
78
|
+
// reconnect, or been healed by another path since the last one.
|
|
79
|
+
if (!hub.needsActorPrincipalHeal(connectionId)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let resolved: string | undefined;
|
|
84
|
+
try {
|
|
85
|
+
resolved = await resolve();
|
|
86
|
+
} catch {
|
|
87
|
+
resolved = undefined;
|
|
88
|
+
}
|
|
89
|
+
if (resolved) {
|
|
90
|
+
hub.fillClientActorPrincipalId(connectionId, resolved);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Log the give-up so a principal-less subscription is greppable next to the
|
|
96
|
+
// same-actor rejections it causes, rather than surfacing only as opaque
|
|
97
|
+
// 403s on the client.
|
|
98
|
+
if (hub.needsActorPrincipalHeal(connectionId)) {
|
|
99
|
+
log.warn(
|
|
100
|
+
{ connectionId, attempts: delays.length },
|
|
101
|
+
"gave up healing missing actorPrincipalId for client subscription; host-proxy results from this connection are rejected until it reconnects",
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
})();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function sleep(ms: number): Promise<void> {
|
|
108
|
+
return new Promise((resolve) => {
|
|
109
|
+
const timer = setTimeout(resolve, ms);
|
|
110
|
+
// Never hold the process (or a test runner) open on a pending backoff.
|
|
111
|
+
(timer as { unref?: () => void }).unref?.();
|
|
112
|
+
});
|
|
113
|
+
}
|
|
@@ -223,6 +223,35 @@ const STT_ERROR_MAP: Record<SttErrorCategory, () => RouteError> = {
|
|
|
223
223
|
"provider-error": () => new BadGatewayError("STT provider error"),
|
|
224
224
|
};
|
|
225
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Resolve the configured batch transcriber, or fail the request with a 503
|
|
228
|
+
* naming which kind of unavailability this is.
|
|
229
|
+
*
|
|
230
|
+
* A typed {@link SttError} already names the situation and its fix (a
|
|
231
|
+
* configured provider that cannot batch transcribe), so its message is
|
|
232
|
+
* surfaced verbatim. `null` means nothing is configured at all, and any other
|
|
233
|
+
* throw is an unexpected resolver failure.
|
|
234
|
+
*/
|
|
235
|
+
async function resolveBatchTranscriberOrUnavailable(): Promise<BatchTranscriber> {
|
|
236
|
+
let transcriber: BatchTranscriber | null;
|
|
237
|
+
try {
|
|
238
|
+
transcriber = await resolveBatchTranscriber();
|
|
239
|
+
} catch (err) {
|
|
240
|
+
if (err instanceof SttError) {
|
|
241
|
+
throw new ServiceUnavailableError(err.message);
|
|
242
|
+
}
|
|
243
|
+
log.error({ err }, "Failed to resolve STT transcriber");
|
|
244
|
+
throw new ServiceUnavailableError("STT provider is not available");
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (!transcriber) {
|
|
248
|
+
throw new ServiceUnavailableError(
|
|
249
|
+
"No speech-to-text provider is configured",
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
return transcriber;
|
|
253
|
+
}
|
|
254
|
+
|
|
226
255
|
// ---------------------------------------------------------------------------
|
|
227
256
|
// Handlers
|
|
228
257
|
// ---------------------------------------------------------------------------
|
|
@@ -288,19 +317,7 @@ async function handleTranscribe({ body }: RouteHandlerArgs) {
|
|
|
288
317
|
}
|
|
289
318
|
|
|
290
319
|
// -- Resolve transcriber --------------------------------------------------
|
|
291
|
-
|
|
292
|
-
try {
|
|
293
|
-
transcriber = await resolveBatchTranscriber();
|
|
294
|
-
} catch (err) {
|
|
295
|
-
log.error({ err }, "Failed to resolve STT transcriber");
|
|
296
|
-
throw new ServiceUnavailableError("STT provider is not available");
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (!transcriber) {
|
|
300
|
-
throw new ServiceUnavailableError(
|
|
301
|
-
"No speech-to-text provider is configured",
|
|
302
|
-
);
|
|
303
|
-
}
|
|
320
|
+
const transcriber = await resolveBatchTranscriberOrUnavailable();
|
|
304
321
|
|
|
305
322
|
// -- Transcribe with timeout ----------------------------------------------
|
|
306
323
|
const abortController = new AbortController();
|
|
@@ -358,18 +375,7 @@ async function handleTranscribeFile({ body }: RouteHandlerArgs) {
|
|
|
358
375
|
);
|
|
359
376
|
}
|
|
360
377
|
|
|
361
|
-
|
|
362
|
-
try {
|
|
363
|
-
transcriber = await resolveBatchTranscriber();
|
|
364
|
-
} catch (err) {
|
|
365
|
-
log.error({ err }, "Failed to resolve STT transcriber");
|
|
366
|
-
throw new ServiceUnavailableError("STT provider is not available");
|
|
367
|
-
}
|
|
368
|
-
if (!transcriber) {
|
|
369
|
-
throw new ServiceUnavailableError(
|
|
370
|
-
"No speech-to-text provider is configured",
|
|
371
|
-
);
|
|
372
|
-
}
|
|
378
|
+
const transcriber = await resolveBatchTranscriberOrUnavailable();
|
|
373
379
|
|
|
374
380
|
const startTime = Date.now();
|
|
375
381
|
let wavPath: string | null = null;
|
|
@@ -206,6 +206,7 @@ async function handleHostUiSnapshotResult({ body, headers }: RouteHandlerArgs) {
|
|
|
206
206
|
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
207
207
|
targetClientId: peeked.targetClientId,
|
|
208
208
|
op: "host_ui_snapshot",
|
|
209
|
+
hubForMissingTarget: assistantEventHub,
|
|
209
210
|
});
|
|
210
211
|
}
|
|
211
212
|
|
|
@@ -8,6 +8,7 @@ import { z } from "zod";
|
|
|
8
8
|
|
|
9
9
|
import { INTERNAL_GUARDIAN_TRUST_CONTEXT } from "../../daemon/trust-context.js";
|
|
10
10
|
import { getConversation } from "../../persistence/conversation-crud.js";
|
|
11
|
+
import { getSchedule } from "../../schedule/schedule-store.js";
|
|
11
12
|
import { wakeAgentForOpportunity } from "../agent-wake.js";
|
|
12
13
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
13
14
|
import { NotFoundError } from "./errors.js";
|
|
@@ -20,6 +21,10 @@ const WakeConversationBody = z.object({
|
|
|
20
21
|
// Honored only for a `local` caller (see handler) — a remote `actor` could
|
|
21
22
|
// otherwise attribute its wake's cost to an arbitrary firing.
|
|
22
23
|
cronRunId: z.string().min(1).optional(),
|
|
24
|
+
// Runs the turn on this schedule's pinned inference profile. Honored only for
|
|
25
|
+
// a `local` caller (see handler): a remote `actor` could otherwise run turns
|
|
26
|
+
// under an arbitrary schedule's profile and spend the owner's money.
|
|
27
|
+
scheduleId: z.string().min(1).optional(),
|
|
23
28
|
// Persist the trigger as a background event rather than an ephemeral hint, so
|
|
24
29
|
// repeated wakes stay prompt-cache-friendly.
|
|
25
30
|
persist: z.boolean().optional(),
|
|
@@ -53,6 +58,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
53
58
|
hint,
|
|
54
59
|
source,
|
|
55
60
|
cronRunId,
|
|
61
|
+
scheduleId,
|
|
56
62
|
persist,
|
|
57
63
|
externalContent,
|
|
58
64
|
} = WakeConversationBody.parse(body);
|
|
@@ -72,6 +78,22 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
72
78
|
// local caller.
|
|
73
79
|
const isLocal = headers?.["x-vellum-principal-type"] === "local";
|
|
74
80
|
|
|
81
|
+
// A script-mode schedule hands off to the agent loop through this route,
|
|
82
|
+
// so the schedule's pinned profile has to be applied here for the woken
|
|
83
|
+
// turn to run on the model the schedule was created under.
|
|
84
|
+
//
|
|
85
|
+
// The pin applies per turn rather than as a durable conversation pin,
|
|
86
|
+
// and it wins over the target conversation's own pin for turns the
|
|
87
|
+
// schedule triggers. That matters because a script may wake any
|
|
88
|
+
// conversation it names, not only the `scheduled` one it created:
|
|
89
|
+
// waking an interactive chat runs that one turn on the schedule's
|
|
90
|
+
// profile, while the user's own replies keep using their selection.
|
|
91
|
+
// A schedule with no pin resolves as any other turn does.
|
|
92
|
+
const scheduleProfile =
|
|
93
|
+
isLocal && scheduleId
|
|
94
|
+
? (getSchedule(scheduleId)?.inferenceProfile ?? null)
|
|
95
|
+
: null;
|
|
96
|
+
|
|
75
97
|
return wakeAgentForOpportunity({
|
|
76
98
|
conversationId,
|
|
77
99
|
hint,
|
|
@@ -80,6 +102,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
80
102
|
? { trustContext: INTERNAL_GUARDIAN_TRUST_CONTEXT, clientless: true }
|
|
81
103
|
: {}),
|
|
82
104
|
...(isLocal && cronRunId ? { cronRunId } : {}),
|
|
105
|
+
...(scheduleProfile ? { forceOverrideProfile: scheduleProfile } : {}),
|
|
83
106
|
...(persist ? { persistTriggerAsEvent: true } : {}),
|
|
84
107
|
...(externalContent !== undefined
|
|
85
108
|
? { untrustedOutput: { content: externalContent, source: "webhook" } }
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
getDisplayMetaForConversations,
|
|
23
23
|
isConversationProcessing,
|
|
24
24
|
} from "../../persistence/conversation-crud.js";
|
|
25
|
+
import { isReferentialFork } from "../../persistence/conversation-lineage.js";
|
|
25
26
|
import type { ExternalConversationBinding } from "../../persistence/external-conversation-store.js";
|
|
26
27
|
import { getBindingsForConversations } from "../../persistence/external-conversation-store.js";
|
|
27
28
|
|
|
@@ -64,14 +65,24 @@ function buildAssistantAttention(attentionState: AttentionState | undefined):
|
|
|
64
65
|
};
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
interface ForkLineage {
|
|
69
|
+
forkParent?: { conversationId: string; messageId: string; title: string };
|
|
70
|
+
/**
|
|
71
|
+
* The fork reads its history from a parent that is gone. Only meaningful for
|
|
72
|
+
* referential forks: a cloning fork holds its own copy, so a deleted parent
|
|
73
|
+
* costs it nothing and is not worth telling the user about.
|
|
74
|
+
*/
|
|
75
|
+
historyOrphaned?: true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function buildForkLineage(
|
|
68
79
|
conversation: ConversationRow,
|
|
69
80
|
parentCache: Map<string, ConversationRow | null>,
|
|
70
|
-
):
|
|
81
|
+
): ForkLineage {
|
|
71
82
|
const parentConversationId = conversation.forkParentConversationId;
|
|
72
83
|
const parentMessageId = conversation.forkParentMessageId;
|
|
73
84
|
if (!parentConversationId || !parentMessageId) {
|
|
74
|
-
return
|
|
85
|
+
return {};
|
|
75
86
|
}
|
|
76
87
|
|
|
77
88
|
let parentConversation: ConversationRow | null | undefined =
|
|
@@ -81,13 +92,17 @@ function buildForkParent(
|
|
|
81
92
|
parentCache.set(parentConversationId, parentConversation);
|
|
82
93
|
}
|
|
83
94
|
if (!parentConversation) {
|
|
84
|
-
|
|
95
|
+
// The parent lookup already happened, so reporting the orphan costs
|
|
96
|
+
// nothing beyond the branch.
|
|
97
|
+
return isReferentialFork(conversation) ? { historyOrphaned: true } : {};
|
|
85
98
|
}
|
|
86
99
|
|
|
87
100
|
return {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
101
|
+
forkParent: {
|
|
102
|
+
conversationId: parentConversationId,
|
|
103
|
+
messageId: parentMessageId,
|
|
104
|
+
title: parentConversation.title ?? "Untitled",
|
|
105
|
+
},
|
|
91
106
|
};
|
|
92
107
|
}
|
|
93
108
|
|
|
@@ -174,7 +189,7 @@ export function serializeConversationSummary(params: {
|
|
|
174
189
|
} = params;
|
|
175
190
|
const originChannel = parseChannelId(conversation.originChannel);
|
|
176
191
|
const assistantAttention = buildAssistantAttention(attentionState);
|
|
177
|
-
const
|
|
192
|
+
const forkLineage = buildForkLineage(conversation, parentCache);
|
|
178
193
|
|
|
179
194
|
return {
|
|
180
195
|
id: conversation.id,
|
|
@@ -208,7 +223,7 @@ export function serializeConversationSummary(params: {
|
|
|
208
223
|
conversation,
|
|
209
224
|
displayMeta?.groupId ?? null,
|
|
210
225
|
),
|
|
211
|
-
...
|
|
226
|
+
...forkLineage,
|
|
212
227
|
...(conversation.archivedAt != null
|
|
213
228
|
? { archivedAt: conversation.archivedAt }
|
|
214
229
|
: {}),
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A scheduled, heartbeat, or background turn runs its document tools in a
|
|
3
|
+
* sidecar worker, whose local hub has no SSE subscriber. The documents-changed
|
|
4
|
+
* broadcast has to be handed to the daemon there, or the document edited while
|
|
5
|
+
* the user was not looking stays invisible on every client.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
9
|
+
|
|
10
|
+
let notifyCount = 0;
|
|
11
|
+
|
|
12
|
+
mock.module("./worker-daemon-notify.js", () => ({
|
|
13
|
+
NOTIFY_CONVERSATION_PERSISTED_IPC_METHOD:
|
|
14
|
+
"notify_conversation_persisted_externally",
|
|
15
|
+
NOTIFY_DOCUMENTS_CHANGED_IPC_METHOD: "notify_documents_changed_externally",
|
|
16
|
+
notifyDaemonConversationPersisted: async () => {},
|
|
17
|
+
notifyDaemonDocumentsChanged: async () => {
|
|
18
|
+
notifyCount++;
|
|
19
|
+
},
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
import type { AssistantEventEnvelope } from "../../api/index.js";
|
|
23
|
+
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
24
|
+
import {
|
|
25
|
+
_resetStreamStateForTesting,
|
|
26
|
+
disableStreamSeqStamping,
|
|
27
|
+
} from "../assistant-stream-state.js";
|
|
28
|
+
import {
|
|
29
|
+
DOCUMENTS_CHANGED_COALESCE_MS,
|
|
30
|
+
publishDocumentsChanged,
|
|
31
|
+
} from "./resource-sync-events.js";
|
|
32
|
+
|
|
33
|
+
async function settle(): Promise<void> {
|
|
34
|
+
await new Promise((resolve) =>
|
|
35
|
+
setTimeout(resolve, DOCUMENTS_CHANGED_COALESCE_MS + 50),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Run `publish`, then return the `sync_changed` events it put on the hub. */
|
|
40
|
+
async function captureLocalPublishes(
|
|
41
|
+
publish: () => void,
|
|
42
|
+
): Promise<AssistantEventEnvelope[]> {
|
|
43
|
+
await settle();
|
|
44
|
+
const received: AssistantEventEnvelope[] = [];
|
|
45
|
+
const subscription = assistantEventHub.subscribe({
|
|
46
|
+
type: "process",
|
|
47
|
+
callback: (event) => {
|
|
48
|
+
if (event.message.type === "sync_changed") {
|
|
49
|
+
received.push(event);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
try {
|
|
54
|
+
publish();
|
|
55
|
+
await settle();
|
|
56
|
+
return received;
|
|
57
|
+
} finally {
|
|
58
|
+
subscription.dispose();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe("publishDocumentsChanged in a sidecar worker", () => {
|
|
63
|
+
beforeEach(async () => {
|
|
64
|
+
await settle();
|
|
65
|
+
notifyCount = 0;
|
|
66
|
+
_resetStreamStateForTesting();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("hands the broadcast to the daemon instead of publishing into a void", async () => {
|
|
70
|
+
disableStreamSeqStamping();
|
|
71
|
+
|
|
72
|
+
const events = await captureLocalPublishes(() => {
|
|
73
|
+
publishDocumentsChanged();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(notifyCount).toBe(1);
|
|
77
|
+
expect(events).toEqual([]);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("coalesces a burst of worker writes into one hand-off", async () => {
|
|
81
|
+
disableStreamSeqStamping();
|
|
82
|
+
|
|
83
|
+
await captureLocalPublishes(() => {
|
|
84
|
+
for (let i = 0; i < 10; i++) {
|
|
85
|
+
publishDocumentsChanged();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(notifyCount).toBe(1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("publishes on the local hub in the daemon, where subscribers live", async () => {
|
|
93
|
+
const events = await captureLocalPublishes(() => {
|
|
94
|
+
publishDocumentsChanged();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(notifyCount).toBe(0);
|
|
98
|
+
expect(events).toHaveLength(1);
|
|
99
|
+
expect(events[0].message).toMatchObject({ type: "sync_changed" });
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -9,7 +9,10 @@ import { getAvatarImagePath } from "../../util/platform.js";
|
|
|
9
9
|
import { broadcastMessage } from "../assistant-event-hub.js";
|
|
10
10
|
import { isStreamSeqStampingDisabled } from "../assistant-stream-state.js";
|
|
11
11
|
import { publishSyncInvalidation } from "./sync-publisher.js";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
notifyDaemonConversationPersisted,
|
|
14
|
+
notifyDaemonDocumentsChanged,
|
|
15
|
+
} from "./worker-daemon-notify.js";
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
18
|
* Derive the initiating client's id from request headers so a sync publish can
|
|
@@ -67,6 +70,81 @@ export function publishAppsChanged(originClientId?: string): void {
|
|
|
67
70
|
void publishSyncInvalidation([SYNC_TAGS.appsList], originClientId);
|
|
68
71
|
}
|
|
69
72
|
|
|
73
|
+
/**
|
|
74
|
+
* How long a documents-list invalidation waits for the writes around it to
|
|
75
|
+
* settle before it is broadcast.
|
|
76
|
+
*
|
|
77
|
+
* Document writes arrive in bursts: the document-editor skill is instructed to
|
|
78
|
+
* stream a document as many small `document_update` calls, and the web editor
|
|
79
|
+
* autosaves as the user types. Every burst member publishes, and every publish
|
|
80
|
+
* makes each client drain its `documentsGet` queries (the per-conversation
|
|
81
|
+
* assets pill, the Library, the intelligence stats), during an SSE stream that
|
|
82
|
+
* is already saturated. Open editors track each individual write through
|
|
83
|
+
* `document_editor_update`, so the list-level invalidation only has to land
|
|
84
|
+
* once the burst settles.
|
|
85
|
+
*/
|
|
86
|
+
export const DOCUMENTS_CHANGED_COALESCE_MS = 150;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Ceiling on how long an unbroken run of writes can defer the invalidation, so
|
|
90
|
+
* a document streamed in sub-window chunks still refreshes the list while it is
|
|
91
|
+
* being written instead of only when the turn ends.
|
|
92
|
+
*/
|
|
93
|
+
export const DOCUMENTS_CHANGED_MAX_DEFER_MS = 1_000;
|
|
94
|
+
|
|
95
|
+
let documentsPublishTimer: ReturnType<typeof setTimeout> | undefined;
|
|
96
|
+
let documentsPublishDeadline = 0;
|
|
97
|
+
let documentsPublishOrigin: string | undefined;
|
|
98
|
+
let documentsPublishOriginSeen = false;
|
|
99
|
+
|
|
100
|
+
function flushDocumentsChanged(): void {
|
|
101
|
+
documentsPublishTimer = undefined;
|
|
102
|
+
documentsPublishDeadline = 0;
|
|
103
|
+
const originClientId = documentsPublishOrigin;
|
|
104
|
+
documentsPublishOrigin = undefined;
|
|
105
|
+
documentsPublishOriginSeen = false;
|
|
106
|
+
|
|
107
|
+
// In a sidecar worker (seq stamping disabled) the local hub has no SSE
|
|
108
|
+
// subscribers, so a local publish reaches no client and a document edited by
|
|
109
|
+
// a scheduled or background turn stays invisible. Hand off to the daemon,
|
|
110
|
+
// which republishes the invalidation where subscribers observe it. Such a
|
|
111
|
+
// turn has no originating client, so no `originClientId` is forwarded.
|
|
112
|
+
if (isStreamSeqStampingDisabled()) {
|
|
113
|
+
void notifyDaemonDocumentsChanged();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
void publishSyncInvalidation([SYNC_TAGS.documentsList], originClientId);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Invalidate the document list on every client, coalescing a burst of writes
|
|
121
|
+
* into a single broadcast (see {@link DOCUMENTS_CHANGED_COALESCE_MS}).
|
|
122
|
+
*/
|
|
123
|
+
export function publishDocumentsChanged(originClientId?: string): void {
|
|
124
|
+
if (!documentsPublishOriginSeen) {
|
|
125
|
+
documentsPublishOrigin = originClientId;
|
|
126
|
+
documentsPublishOriginSeen = true;
|
|
127
|
+
} else if (documentsPublishOrigin !== originClientId) {
|
|
128
|
+
// Writes from more than one client merged into this broadcast, so no single
|
|
129
|
+
// client may suppress it as its own echo.
|
|
130
|
+
documentsPublishOrigin = undefined;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const now = Date.now();
|
|
134
|
+
if (documentsPublishTimer) {
|
|
135
|
+
clearTimeout(documentsPublishTimer);
|
|
136
|
+
} else {
|
|
137
|
+
documentsPublishDeadline = now + DOCUMENTS_CHANGED_MAX_DEFER_MS;
|
|
138
|
+
}
|
|
139
|
+
documentsPublishTimer = setTimeout(
|
|
140
|
+
flushDocumentsChanged,
|
|
141
|
+
Math.max(
|
|
142
|
+
0,
|
|
143
|
+
Math.min(DOCUMENTS_CHANGED_COALESCE_MS, documentsPublishDeadline - now),
|
|
144
|
+
),
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
70
148
|
export function publishPluginsChanged(originClientId?: string): void {
|
|
71
149
|
void publishSyncInvalidation([SYNC_TAGS.pluginsList], originClientId);
|
|
72
150
|
}
|
|
@@ -33,7 +33,9 @@ mock.module("../../ipc/cli-client.js", () => ({
|
|
|
33
33
|
|
|
34
34
|
import {
|
|
35
35
|
NOTIFY_CONVERSATION_PERSISTED_IPC_METHOD,
|
|
36
|
+
NOTIFY_DOCUMENTS_CHANGED_IPC_METHOD,
|
|
36
37
|
notifyDaemonConversationPersisted,
|
|
38
|
+
notifyDaemonDocumentsChanged,
|
|
37
39
|
} from "./worker-daemon-notify.js";
|
|
38
40
|
|
|
39
41
|
describe("notifyDaemonConversationPersisted", () => {
|
|
@@ -67,3 +69,35 @@ describe("notifyDaemonConversationPersisted", () => {
|
|
|
67
69
|
expect(calls).toHaveLength(1);
|
|
68
70
|
});
|
|
69
71
|
});
|
|
72
|
+
|
|
73
|
+
describe("notifyDaemonDocumentsChanged", () => {
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
calls.length = 0;
|
|
76
|
+
nextResult = { ok: true };
|
|
77
|
+
shouldThrow = false;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("asks the daemon to republish over the shared IPC method", async () => {
|
|
81
|
+
await notifyDaemonDocumentsChanged();
|
|
82
|
+
|
|
83
|
+
expect(calls).toHaveLength(1);
|
|
84
|
+
expect(calls[0]!.method).toBe(NOTIFY_DOCUMENTS_CHANGED_IPC_METHOD);
|
|
85
|
+
expect(calls[0]!.params).toEqual({ body: {} });
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("swallows a failed IPC result (best-effort, no throw)", async () => {
|
|
89
|
+
nextResult = { ok: false, error: "daemon unreachable" };
|
|
90
|
+
|
|
91
|
+
const result = await notifyDaemonDocumentsChanged();
|
|
92
|
+
expect(result).toBeUndefined();
|
|
93
|
+
expect(calls).toHaveLength(1);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("swallows a thrown IPC error (best-effort, no throw)", async () => {
|
|
97
|
+
shouldThrow = true;
|
|
98
|
+
|
|
99
|
+
const result = await notifyDaemonDocumentsChanged();
|
|
100
|
+
expect(result).toBeUndefined();
|
|
101
|
+
expect(calls).toHaveLength(1);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Worker → daemon hand-off for
|
|
2
|
+
* Worker → daemon hand-off for sync notifications a sidecar cannot deliver.
|
|
3
3
|
*
|
|
4
4
|
* Sidecar worker processes (schedule, memory) disable SSE seq stamping — the
|
|
5
5
|
* daemon is the sole seq authority — so a worker's own `getCurrentSeq()`
|
|
6
|
-
* reports `0` and its `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* reports `0` and its `sync_changed` broadcasts reach no SSE subscriber (those
|
|
7
|
+
* live in the daemon). A worker hands the notification here instead and the
|
|
8
|
+
* daemon republishes it to real subscribers (see
|
|
9
|
+
* `ipc/routes/conversation-sync-ipc-routes.ts`,
|
|
10
|
+
* `ipc/routes/documents-sync-ipc-routes.ts`).
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { cliIpcCall } from "../../ipc/cli-client.js";
|
|
@@ -22,6 +22,14 @@ const log = getLogger("worker-daemon-notify");
|
|
|
22
22
|
export const NOTIFY_CONVERSATION_PERSISTED_IPC_METHOD =
|
|
23
23
|
"notify_conversation_persisted_externally";
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* IPC method the daemon exposes for the documents-changed hand-off. Shared by
|
|
27
|
+
* the worker caller and the daemon route registration so the wire name cannot
|
|
28
|
+
* drift.
|
|
29
|
+
*/
|
|
30
|
+
export const NOTIFY_DOCUMENTS_CHANGED_IPC_METHOD =
|
|
31
|
+
"notify_documents_changed_externally";
|
|
32
|
+
|
|
25
33
|
/**
|
|
26
34
|
* Short timeout: this is a fire-and-forget invalidation, not a request whose
|
|
27
35
|
* result the worker consumes. A busy or unreachable daemon simply leaves the
|
|
@@ -61,3 +69,33 @@ export async function notifyDaemonConversationPersisted(
|
|
|
61
69
|
);
|
|
62
70
|
}
|
|
63
71
|
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Ask the daemon to republish the documents-list invalidation.
|
|
75
|
+
*
|
|
76
|
+
* A scheduled or background turn runs its document tools in a sidecar worker,
|
|
77
|
+
* so the edit is real but the worker's own broadcast reaches nobody. This is
|
|
78
|
+
* the path that lets the user learn a document changed while they were not
|
|
79
|
+
* looking.
|
|
80
|
+
*
|
|
81
|
+
* Best-effort by design, like the conversation hand-off: an unreachable daemon
|
|
82
|
+
* is logged at debug and swallowed, and the client picks the change up on its
|
|
83
|
+
* next document-list fetch.
|
|
84
|
+
*/
|
|
85
|
+
export async function notifyDaemonDocumentsChanged(): Promise<void> {
|
|
86
|
+
try {
|
|
87
|
+
const result = await cliIpcCall(
|
|
88
|
+
NOTIFY_DOCUMENTS_CHANGED_IPC_METHOD,
|
|
89
|
+
{ body: {} },
|
|
90
|
+
{ timeoutMs: NOTIFY_TIMEOUT_MS },
|
|
91
|
+
);
|
|
92
|
+
if (!result.ok) {
|
|
93
|
+
log.debug(
|
|
94
|
+
{ error: result.error },
|
|
95
|
+
"daemon documents-changed notify was not acknowledged",
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
} catch (err) {
|
|
99
|
+
log.debug({ err }, "daemon documents-changed notify failed");
|
|
100
|
+
}
|
|
101
|
+
}
|