@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
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from "../calls/media-stream-audio-transcode.js";
|
|
27
27
|
import { MediaStreamOutput } from "../calls/media-stream-output.js";
|
|
28
28
|
import { resolveCallTtsProvider } from "../calls/resolve-call-tts-provider.js";
|
|
29
|
+
import { setConfig } from "./helpers/set-config.js";
|
|
29
30
|
|
|
30
31
|
const mockResolveCallTtsProvider = resolveCallTtsProvider as ReturnType<
|
|
31
32
|
typeof jest.fn
|
|
@@ -1213,6 +1214,180 @@ describe("MediaStreamOutput", () => {
|
|
|
1213
1214
|
});
|
|
1214
1215
|
});
|
|
1215
1216
|
|
|
1217
|
+
// ---------------------------------------------------------------------------
|
|
1218
|
+
// Synthesis language hint
|
|
1219
|
+
// ---------------------------------------------------------------------------
|
|
1220
|
+
|
|
1221
|
+
describe("synthesis language hint", () => {
|
|
1222
|
+
/** Synthesize one turn and return the provider request it produced. */
|
|
1223
|
+
async function synthesizeOneTurn(
|
|
1224
|
+
output: MediaStreamOutput,
|
|
1225
|
+
): Promise<{ language?: string }> {
|
|
1226
|
+
mockSynthesize.mockResolvedValue({
|
|
1227
|
+
audio: makeWavBuffer([1000, 2000, 3000, 4000]),
|
|
1228
|
+
contentType: "audio/wav",
|
|
1229
|
+
});
|
|
1230
|
+
output.sendTextToken("Hello caller.", true);
|
|
1231
|
+
await drain(() => mockSynthesize.mock.calls.length > 0);
|
|
1232
|
+
return mockSynthesize.mock.calls[0][0] as { language?: string };
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
test("the resolver's language rides the provider request", async () => {
|
|
1236
|
+
const { ws } = createMockWs();
|
|
1237
|
+
const output = makeOutput(ws, "stream-lang");
|
|
1238
|
+
output.setSynthesisLanguageResolver(() => "es");
|
|
1239
|
+
|
|
1240
|
+
const request = await synthesizeOneTurn(output);
|
|
1241
|
+
|
|
1242
|
+
expect(request.language).toBe("es");
|
|
1243
|
+
});
|
|
1244
|
+
|
|
1245
|
+
test("fixed system copy synthesizes without the caller-language hint while model text keeps it", async () => {
|
|
1246
|
+
const { ws } = createMockWs();
|
|
1247
|
+
const output = makeOutput(ws, "stream-lang");
|
|
1248
|
+
output.setSynthesisLanguageResolver(() => "ja");
|
|
1249
|
+
mockSynthesize.mockResolvedValue({
|
|
1250
|
+
audio: makeWavBuffer([1000, 2000, 3000, 4000]),
|
|
1251
|
+
contentType: "audio/wav",
|
|
1252
|
+
});
|
|
1253
|
+
|
|
1254
|
+
output.sendTextToken("Model reply.", true);
|
|
1255
|
+
output.sendTextToken("Are you still there?", true, { systemCopy: true });
|
|
1256
|
+
await drain(() => mockSynthesize.mock.calls.length >= 2);
|
|
1257
|
+
|
|
1258
|
+
const requests = mockSynthesize.mock.calls.map(
|
|
1259
|
+
(call) => call[0] as { text: string; language?: string },
|
|
1260
|
+
);
|
|
1261
|
+
expect(requests[0]?.text).toBe("Model reply.");
|
|
1262
|
+
expect(requests[0]?.language).toBe("ja");
|
|
1263
|
+
expect(requests[1]?.text).toBe("Are you still there?");
|
|
1264
|
+
expect(requests[1]?.language).toBeUndefined();
|
|
1265
|
+
});
|
|
1266
|
+
|
|
1267
|
+
test("no language when nothing resolves (default multilingual pin)", async () => {
|
|
1268
|
+
const { ws } = createMockWs();
|
|
1269
|
+
const output = makeOutput(ws, "stream-lang");
|
|
1270
|
+
|
|
1271
|
+
const request = await synthesizeOneTurn(output);
|
|
1272
|
+
|
|
1273
|
+
expect(request.language).toBeUndefined();
|
|
1274
|
+
});
|
|
1275
|
+
|
|
1276
|
+
test("a monolingual pin on a manual-selection provider resolves as the hint", async () => {
|
|
1277
|
+
setConfig("services", {
|
|
1278
|
+
stt: { provider: "deepgram", language: "es-ES" },
|
|
1279
|
+
});
|
|
1280
|
+
try {
|
|
1281
|
+
const { ws } = createMockWs();
|
|
1282
|
+
const output = makeOutput(ws, "stream-lang");
|
|
1283
|
+
|
|
1284
|
+
const request = await synthesizeOneTurn(output);
|
|
1285
|
+
|
|
1286
|
+
expect(request.language).toBe("es");
|
|
1287
|
+
} finally {
|
|
1288
|
+
setConfig("services", {});
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1292
|
+
test("the pin is ignored for auto-detecting providers", async () => {
|
|
1293
|
+
setConfig("services", {
|
|
1294
|
+
stt: { provider: "openai-whisper", language: "es" },
|
|
1295
|
+
});
|
|
1296
|
+
try {
|
|
1297
|
+
const { ws } = createMockWs();
|
|
1298
|
+
const output = makeOutput(ws, "stream-lang");
|
|
1299
|
+
|
|
1300
|
+
const request = await synthesizeOneTurn(output);
|
|
1301
|
+
|
|
1302
|
+
expect(request.language).toBeUndefined();
|
|
1303
|
+
} finally {
|
|
1304
|
+
setConfig("services", {});
|
|
1305
|
+
}
|
|
1306
|
+
});
|
|
1307
|
+
});
|
|
1308
|
+
|
|
1309
|
+
// ---------------------------------------------------------------------------
|
|
1310
|
+
// Per-language voice override (languageVoices)
|
|
1311
|
+
// ---------------------------------------------------------------------------
|
|
1312
|
+
|
|
1313
|
+
describe("per-language voice override", () => {
|
|
1314
|
+
afterEach(() => {
|
|
1315
|
+
setConfig("services", {});
|
|
1316
|
+
});
|
|
1317
|
+
|
|
1318
|
+
/** Seed a deepgram languageVoices entry and resolve deepgram as the provider. */
|
|
1319
|
+
function useDeepgramWithHindiVoice(): void {
|
|
1320
|
+
setConfig("services", {
|
|
1321
|
+
tts: {
|
|
1322
|
+
provider: "deepgram",
|
|
1323
|
+
providers: {
|
|
1324
|
+
deepgram: { languageVoices: { hi: "aura-2-hindi-voice" } },
|
|
1325
|
+
},
|
|
1326
|
+
},
|
|
1327
|
+
});
|
|
1328
|
+
useProvider({
|
|
1329
|
+
id: "deepgram",
|
|
1330
|
+
capabilities: { supportsStreaming: false, supportedFormats: ["wav"] },
|
|
1331
|
+
synthesize: mockSynthesize,
|
|
1332
|
+
});
|
|
1333
|
+
mockSynthesize.mockResolvedValue({
|
|
1334
|
+
audio: makeWavBuffer([1000, 2000, 3000, 4000]),
|
|
1335
|
+
contentType: "audio/wav",
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
test("a configured languageVoices entry for the resolved language rides the request as voiceId", async () => {
|
|
1340
|
+
useDeepgramWithHindiVoice();
|
|
1341
|
+
const { ws } = createMockWs();
|
|
1342
|
+
const output = makeOutput(ws, "stream-voice");
|
|
1343
|
+
output.setSynthesisLanguageResolver(() => "hi");
|
|
1344
|
+
|
|
1345
|
+
output.sendTextToken("Namaste.", true);
|
|
1346
|
+
await drain(() => mockSynthesize.mock.calls.length > 0);
|
|
1347
|
+
|
|
1348
|
+
const request = mockSynthesize.mock.calls[0][0] as {
|
|
1349
|
+
voiceId?: string;
|
|
1350
|
+
language?: string;
|
|
1351
|
+
};
|
|
1352
|
+
expect(request.language).toBe("hi");
|
|
1353
|
+
expect(request.voiceId).toBe("aura-2-hindi-voice");
|
|
1354
|
+
});
|
|
1355
|
+
|
|
1356
|
+
test("no voiceId when the map has no entry for the resolved language", async () => {
|
|
1357
|
+
useDeepgramWithHindiVoice();
|
|
1358
|
+
const { ws } = createMockWs();
|
|
1359
|
+
const output = makeOutput(ws, "stream-voice");
|
|
1360
|
+
output.setSynthesisLanguageResolver(() => "es");
|
|
1361
|
+
|
|
1362
|
+
output.sendTextToken("Hola.", true);
|
|
1363
|
+
await drain(() => mockSynthesize.mock.calls.length > 0);
|
|
1364
|
+
|
|
1365
|
+
const request = mockSynthesize.mock.calls[0][0] as {
|
|
1366
|
+
voiceId?: string;
|
|
1367
|
+
language?: string;
|
|
1368
|
+
};
|
|
1369
|
+
expect(request.language).toBe("es");
|
|
1370
|
+
expect(request.voiceId).toBeUndefined();
|
|
1371
|
+
});
|
|
1372
|
+
|
|
1373
|
+
test("system copy gets neither the language hint nor the language voice", async () => {
|
|
1374
|
+
useDeepgramWithHindiVoice();
|
|
1375
|
+
const { ws } = createMockWs();
|
|
1376
|
+
const output = makeOutput(ws, "stream-voice");
|
|
1377
|
+
output.setSynthesisLanguageResolver(() => "hi");
|
|
1378
|
+
|
|
1379
|
+
output.sendTextToken("Are you still there?", true, { systemCopy: true });
|
|
1380
|
+
await drain(() => mockSynthesize.mock.calls.length > 0);
|
|
1381
|
+
|
|
1382
|
+
const request = mockSynthesize.mock.calls[0][0] as {
|
|
1383
|
+
voiceId?: string;
|
|
1384
|
+
language?: string;
|
|
1385
|
+
};
|
|
1386
|
+
expect(request.language).toBeUndefined();
|
|
1387
|
+
expect(request.voiceId).toBeUndefined();
|
|
1388
|
+
});
|
|
1389
|
+
});
|
|
1390
|
+
|
|
1216
1391
|
// ---------------------------------------------------------------------------
|
|
1217
1392
|
// Streaming PCM synthesis (incremental transcode)
|
|
1218
1393
|
// ---------------------------------------------------------------------------
|
|
@@ -406,6 +406,8 @@ mock.module("../calls/access-request-wait.js", () => ({
|
|
|
406
406
|
// Now import the module under test.
|
|
407
407
|
// ---------------------------------------------------------------------------
|
|
408
408
|
|
|
409
|
+
import { GATEWAY_TUNNEL_LOST_WS_CLOSE_CODE } from "@vellumai/service-contracts/ingress";
|
|
410
|
+
|
|
409
411
|
import { revokeScopedApprovalGrantsForContext } from "../approvals/scoped-approval-grants.js";
|
|
410
412
|
import { CallController } from "../calls/call-controller.js";
|
|
411
413
|
import { postPointerMessageSafe } from "../calls/call-pointer-messages.js";
|
|
@@ -746,6 +748,40 @@ describe("MediaStreamCallSession", () => {
|
|
|
746
748
|
);
|
|
747
749
|
});
|
|
748
750
|
|
|
751
|
+
test("tunnel-lost close code decodes to a readable failure detail", () => {
|
|
752
|
+
const mock = createMockWs();
|
|
753
|
+
mockSessions.set("call-1", {
|
|
754
|
+
id: "call-1",
|
|
755
|
+
conversationId: "conv-1",
|
|
756
|
+
status: "in_progress",
|
|
757
|
+
startedAt: Date.now() - 60000,
|
|
758
|
+
toNumber: "+16175550142",
|
|
759
|
+
initiatedFromConversationId: "conv-origin",
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
const session = new MediaStreamCallSession(mock.ws, "call-1");
|
|
763
|
+
// The gateway's close reason is dropped in relay, so only the code
|
|
764
|
+
// arrives; it must decode to something a human can act on.
|
|
765
|
+
session.handleTransportClosed(GATEWAY_TUNNEL_LOST_WS_CLOSE_CODE);
|
|
766
|
+
|
|
767
|
+
expect(updateCallSession).toHaveBeenCalledWith(
|
|
768
|
+
"call-1",
|
|
769
|
+
expect.objectContaining({
|
|
770
|
+
status: "failed",
|
|
771
|
+
lastError:
|
|
772
|
+
"Media stream WebSocket closed unexpectedly: public ingress tunnel disconnected",
|
|
773
|
+
}),
|
|
774
|
+
);
|
|
775
|
+
expect(postPointerMessageSafe).toHaveBeenCalledWith(
|
|
776
|
+
"conv-origin",
|
|
777
|
+
"failed",
|
|
778
|
+
"+16175550142",
|
|
779
|
+
expect.objectContaining({
|
|
780
|
+
reason: "public ingress tunnel disconnected",
|
|
781
|
+
}),
|
|
782
|
+
);
|
|
783
|
+
});
|
|
784
|
+
|
|
749
785
|
test("close on already-terminal session is a no-op", () => {
|
|
750
786
|
const mock = createMockWs();
|
|
751
787
|
mockSessions.set("call-1", {
|
|
@@ -897,6 +897,73 @@ describe("MediaStreamSttSession", () => {
|
|
|
897
897
|
session.dispose();
|
|
898
898
|
});
|
|
899
899
|
|
|
900
|
+
// ── Detected language (latest tagged utterance) ─────────────────
|
|
901
|
+
|
|
902
|
+
test("a language switch retargets on the first final in the new language", async () => {
|
|
903
|
+
const { session, fake } = await startStreamingSession();
|
|
904
|
+
|
|
905
|
+
expect(session.currentLanguage()).toBeUndefined();
|
|
906
|
+
|
|
907
|
+
fake.emit({ type: "final", text: "hola", languages: ["es", "en"] });
|
|
908
|
+
fake.emit({ type: "final", text: "buenos dias", languages: ["es"] });
|
|
909
|
+
expect(session.currentLanguage()).toBe("es");
|
|
910
|
+
|
|
911
|
+
// The first ja-tagged utterance wins immediately: the caller does
|
|
912
|
+
// not have to outvote the session's es history. The secondary "es"
|
|
913
|
+
// tag does not dilute the utterance's dominant tag.
|
|
914
|
+
fake.emit({ type: "final", text: "konnichiwa", languages: ["ja", "es"] });
|
|
915
|
+
expect(session.currentLanguage()).toBe("ja");
|
|
916
|
+
|
|
917
|
+
session.dispose();
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
test("regional variants normalize to their base subtag", async () => {
|
|
921
|
+
const { session, fake } = await startStreamingSession();
|
|
922
|
+
|
|
923
|
+
fake.emit({ type: "final", text: "tudo bem", languages: ["pt-BR"] });
|
|
924
|
+
|
|
925
|
+
expect(session.currentLanguage()).toBe("pt");
|
|
926
|
+
|
|
927
|
+
session.dispose();
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
test("empty and untagged finals keep the previous value", async () => {
|
|
931
|
+
const { session, fake } = await startStreamingSession();
|
|
932
|
+
|
|
933
|
+
// A silence final can carry container-level tags describing no
|
|
934
|
+
// emitted words; it must not update the language.
|
|
935
|
+
fake.emit({ type: "final", text: " ", languages: ["fr"] });
|
|
936
|
+
expect(session.currentLanguage()).toBeUndefined();
|
|
937
|
+
|
|
938
|
+
fake.emit({ type: "final", text: "hola", languages: ["es"] });
|
|
939
|
+
expect(session.currentLanguage()).toBe("es");
|
|
940
|
+
|
|
941
|
+
// A committed final without tags keeps the previous value.
|
|
942
|
+
fake.emit({ type: "final", text: "hello" });
|
|
943
|
+
expect(session.currentLanguage()).toBe("es");
|
|
944
|
+
|
|
945
|
+
// So does a tagged silence final after a language is established.
|
|
946
|
+
fake.emit({ type: "final", text: " ", languages: ["fr"] });
|
|
947
|
+
expect(session.currentLanguage()).toBe("es");
|
|
948
|
+
|
|
949
|
+
session.dispose();
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
test("falling back to batch mid-call clears the detected language", async () => {
|
|
953
|
+
const { session, fake } = await startStreamingSession();
|
|
954
|
+
|
|
955
|
+
fake.emit({ type: "final", text: "konnichiwa", languages: ["ja"] });
|
|
956
|
+
expect(session.currentLanguage()).toBe("ja");
|
|
957
|
+
|
|
958
|
+
// Provider closes the stream unexpectedly: the session settles on
|
|
959
|
+
// batch, whose transcripts carry no language metadata. The stale ja
|
|
960
|
+
// detection must not keep hinting synthesis for English speech.
|
|
961
|
+
fake.emit({ type: "closed" });
|
|
962
|
+
expect(session.currentLanguage()).toBeUndefined();
|
|
963
|
+
|
|
964
|
+
session.dispose();
|
|
965
|
+
});
|
|
966
|
+
|
|
900
967
|
test("local VAD turn end never triggers batch transcription in streaming mode", async () => {
|
|
901
968
|
const onTranscriptFinal = jest.fn();
|
|
902
969
|
const { session } = await startStreamingSession(
|
|
@@ -563,7 +563,7 @@ describe("integration: existing routes unaffected", () => {
|
|
|
563
563
|
test("GET /v1/health still works (not intercepted by migration routes)", async () => {
|
|
564
564
|
const { handleDetailedHealth } =
|
|
565
565
|
await import("../runtime/routes/identity-routes.js");
|
|
566
|
-
const res = handleDetailedHealth();
|
|
566
|
+
const res = await handleDetailedHealth();
|
|
567
567
|
const body = (await res.json()) as Record<string, unknown>;
|
|
568
568
|
|
|
569
569
|
expect(res.status).toBe(200);
|
|
@@ -1171,7 +1171,7 @@ describe("integration: existing routes unaffected", () => {
|
|
|
1171
1171
|
test("GET /v1/health still works", async () => {
|
|
1172
1172
|
const { handleDetailedHealth } =
|
|
1173
1173
|
await import("../runtime/routes/identity-routes.js");
|
|
1174
|
-
const res = handleDetailedHealth();
|
|
1174
|
+
const res = await handleDetailedHealth();
|
|
1175
1175
|
const body = (await res.json()) as Record<string, unknown>;
|
|
1176
1176
|
|
|
1177
1177
|
expect(res.status).toBe(200);
|
|
@@ -737,7 +737,7 @@ describe("integration: existing routes unaffected", () => {
|
|
|
737
737
|
test("GET /v1/health still works", async () => {
|
|
738
738
|
const { handleDetailedHealth } =
|
|
739
739
|
await import("../runtime/routes/identity-routes.js");
|
|
740
|
-
const res = handleDetailedHealth();
|
|
740
|
+
const res = await handleDetailedHealth();
|
|
741
741
|
const body = (await res.json()) as Record<string, unknown>;
|
|
742
742
|
|
|
743
743
|
expect(res.status).toBe(200);
|
|
@@ -634,7 +634,7 @@ describe("integration: existing routes unaffected", () => {
|
|
|
634
634
|
test("GET /v1/health still works (not intercepted by migration routes)", async () => {
|
|
635
635
|
const { handleDetailedHealth } =
|
|
636
636
|
await import("../runtime/routes/identity-routes.js");
|
|
637
|
-
const res = handleDetailedHealth();
|
|
637
|
+
const res = await handleDetailedHealth();
|
|
638
638
|
const body = (await res.json()) as Record<string, unknown>;
|
|
639
639
|
|
|
640
640
|
expect(res.status).toBe(200);
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
mkdirSync,
|
|
15
15
|
readFileSync,
|
|
16
16
|
rmSync,
|
|
17
|
+
symlinkSync,
|
|
17
18
|
utimesSync,
|
|
18
19
|
writeFileSync,
|
|
19
20
|
} from "node:fs";
|
|
@@ -507,17 +508,17 @@ describe("workspace hooks (<workspace>/hooks/)", () => {
|
|
|
507
508
|
writePackageJson(dir, { ...SIMPLE_PKG, name: "ordering-plugin" });
|
|
508
509
|
writeHook(
|
|
509
510
|
dir,
|
|
510
|
-
"
|
|
511
|
+
"conversation-deleted",
|
|
511
512
|
`export default () => ({ tag: "plugin" });`,
|
|
512
513
|
);
|
|
513
514
|
writeWorkspaceHook(
|
|
514
|
-
"
|
|
515
|
+
"conversation-deleted",
|
|
515
516
|
`export default () => ({ tag: "workspace" });`,
|
|
516
517
|
);
|
|
517
518
|
|
|
518
519
|
await populateCacheAtBoot();
|
|
519
520
|
|
|
520
|
-
const hooks = await getUserHooksFor("
|
|
521
|
+
const hooks = await getUserHooksFor("conversation-deleted");
|
|
521
522
|
expect(hooks).toHaveLength(2);
|
|
522
523
|
const results = hooks.map((fn) =>
|
|
523
524
|
(fn as unknown as () => { tag: string })(),
|
|
@@ -1004,4 +1005,65 @@ describe("plugin root validation (ATL-983)", () => {
|
|
|
1004
1005
|
// The evil plugin's init hook must NOT have run.
|
|
1005
1006
|
expect(existsSync(evilMarker)).toBe(false);
|
|
1006
1007
|
});
|
|
1008
|
+
|
|
1009
|
+
test("a symlinked plugin root escaping the plugins dir is not activated at boot", async () => {
|
|
1010
|
+
// A real plugin outside the plugins directory, linked in under a name the
|
|
1011
|
+
// boot scan reads. Hook resolution follows the link, so discovery is the
|
|
1012
|
+
// only thing between boot and code from anywhere on disk.
|
|
1013
|
+
const escapee = join(ROOT, "outside", "escapee");
|
|
1014
|
+
mkdirSync(escapee, { recursive: true });
|
|
1015
|
+
writePackageJson(escapee, { ...SIMPLE_PKG, name: "escapee" });
|
|
1016
|
+
const escapeeMarker = join(ROOT, "escapee-init.log");
|
|
1017
|
+
rmSync(escapeeMarker, { force: true });
|
|
1018
|
+
writeMarkerHook(escapee, "init", escapeeMarker, "init");
|
|
1019
|
+
writeHook(
|
|
1020
|
+
escapee,
|
|
1021
|
+
"user-prompt-submit",
|
|
1022
|
+
`export default () => ({ tag: "escapee" });`,
|
|
1023
|
+
);
|
|
1024
|
+
symlinkSync(escapee, join(PLUGINS_DIR, "escapee"));
|
|
1025
|
+
|
|
1026
|
+
// A contained plugin in the same scan, so a boot that discovered nothing
|
|
1027
|
+
// at all cannot pass this test.
|
|
1028
|
+
const keeper = freshPluginDir("keeper");
|
|
1029
|
+
writePackageJson(keeper, { ...SIMPLE_PKG, name: "keeper" });
|
|
1030
|
+
writeHook(
|
|
1031
|
+
keeper,
|
|
1032
|
+
"user-prompt-submit",
|
|
1033
|
+
`export default () => ({ tag: "keeper" });`,
|
|
1034
|
+
);
|
|
1035
|
+
|
|
1036
|
+
await populateCacheAtBoot();
|
|
1037
|
+
|
|
1038
|
+
expect(
|
|
1039
|
+
(await getUserHooksFor("user-prompt-submit")).map(
|
|
1040
|
+
(fn) => (fn as unknown as () => { tag: string })().tag,
|
|
1041
|
+
),
|
|
1042
|
+
).toEqual(["keeper"]);
|
|
1043
|
+
expect(existsSync(escapeeMarker)).toBe(false);
|
|
1044
|
+
});
|
|
1045
|
+
|
|
1046
|
+
test("a symlinked plugin root staying inside the plugins dir is activated at boot", async () => {
|
|
1047
|
+
// A symlinked plugin root is supported (see `plugins/source-fingerprint.ts`)
|
|
1048
|
+
// as long as it resolves inside the plugins directory. The link target sits
|
|
1049
|
+
// in a dot-prefixed store directory, which carries no package.json and is
|
|
1050
|
+
// therefore not an install of its own.
|
|
1051
|
+
const target = join(PLUGINS_DIR, ".store", "alias");
|
|
1052
|
+
mkdirSync(target, { recursive: true });
|
|
1053
|
+
writePackageJson(target, { ...SIMPLE_PKG, name: "alias" });
|
|
1054
|
+
writeHook(
|
|
1055
|
+
target,
|
|
1056
|
+
"user-prompt-submit",
|
|
1057
|
+
`export default () => ({ tag: "alias" });`,
|
|
1058
|
+
);
|
|
1059
|
+
symlinkSync(target, join(PLUGINS_DIR, "alias"));
|
|
1060
|
+
|
|
1061
|
+
await populateCacheAtBoot();
|
|
1062
|
+
|
|
1063
|
+
expect(
|
|
1064
|
+
(await getUserHooksFor("user-prompt-submit")).map(
|
|
1065
|
+
(fn) => (fn as unknown as () => { tag: string })().tag,
|
|
1066
|
+
),
|
|
1067
|
+
).toEqual(["alias"]);
|
|
1068
|
+
});
|
|
1007
1069
|
});
|
|
@@ -340,6 +340,110 @@ describe("PlatformPushAdapter", () => {
|
|
|
340
340
|
expect(result.remotePushAccepted).toBeUndefined();
|
|
341
341
|
});
|
|
342
342
|
|
|
343
|
+
// A lock screen renders no markdown, so any marker that survives to the
|
|
344
|
+
// dispatch body reads as literal punctuation. See `stripMarkdownForPreview`.
|
|
345
|
+
describe("markdown flattening", () => {
|
|
346
|
+
test("flattens markdown out of the dispatched title and body", async () => {
|
|
347
|
+
const adapter = new PlatformPushAdapter();
|
|
348
|
+
const payload = makePayload({
|
|
349
|
+
copy: {
|
|
350
|
+
title: "**Build** finished",
|
|
351
|
+
body: [
|
|
352
|
+
"Here is the clip: ",
|
|
353
|
+
"```ts",
|
|
354
|
+
"const a = 1;",
|
|
355
|
+
"```",
|
|
356
|
+
"| name | value |",
|
|
357
|
+
"| --- | --- |",
|
|
358
|
+
"| a | 1 |",
|
|
359
|
+
].join("\n"),
|
|
360
|
+
},
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
const result = await adapter.send(payload, makeDestination());
|
|
364
|
+
|
|
365
|
+
expect(result.success).toBe(true);
|
|
366
|
+
const dispatched = fetchCalls[0]!.body;
|
|
367
|
+
expect(dispatched.title).toBe("Build finished");
|
|
368
|
+
const dispatchedBody = dispatched.body as string;
|
|
369
|
+
expect(dispatchedBody).not.toContain("![");
|
|
370
|
+
expect(dispatchedBody).not.toContain("```");
|
|
371
|
+
expect(dispatchedBody).not.toContain("|");
|
|
372
|
+
expect(dispatchedBody).toContain("Here is the clip:");
|
|
373
|
+
expect(dispatchedBody).toContain("const a = 1;");
|
|
374
|
+
expect(dispatchedBody).toContain("name value");
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// Guardian question copy joins its question and instruction with a blank
|
|
378
|
+
// line, and iOS renders the break, so flattening must not collapse it.
|
|
379
|
+
test("preserves newlines in the dispatched body", async () => {
|
|
380
|
+
const adapter = new PlatformPushAdapter();
|
|
381
|
+
const payload = makePayload({
|
|
382
|
+
copy: {
|
|
383
|
+
title: "Question",
|
|
384
|
+
body: "Should I book the flight?\n\nReply here to answer.",
|
|
385
|
+
},
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
const result = await adapter.send(payload, makeDestination());
|
|
389
|
+
|
|
390
|
+
expect(result.success).toBe(true);
|
|
391
|
+
expect(fetchCalls[0]!.body.body).toBe(
|
|
392
|
+
"Should I book the flight?\n\nReply here to answer.",
|
|
393
|
+
);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
test("leaves plain prose untouched", async () => {
|
|
397
|
+
const adapter = new PlatformPushAdapter();
|
|
398
|
+
const result = await adapter.send(makePayload(), makeDestination());
|
|
399
|
+
|
|
400
|
+
expect(result.success).toBe(true);
|
|
401
|
+
expect(fetchCalls[0]!.body.title).toBe("Reminder");
|
|
402
|
+
expect(fetchCalls[0]!.body.body).toBe("Check the oven!");
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// The pass-through path copies a verbatim `requestedMessage` into both the
|
|
406
|
+
// title and the body, so media-only copy flattens both to nothing. Every
|
|
407
|
+
// empty-copy guard in the pipeline runs upstream of this adapter, and the
|
|
408
|
+
// platform's serializer rejects a blank title, so an unrecovered field
|
|
409
|
+
// costs the whole notification.
|
|
410
|
+
describe("copy that flattens to nothing", () => {
|
|
411
|
+
test("names the media instead of dispatching blank fields", async () => {
|
|
412
|
+
const adapter = new PlatformPushAdapter();
|
|
413
|
+
const embed = "";
|
|
414
|
+
const payload = makePayload({ copy: { title: embed, body: embed } });
|
|
415
|
+
|
|
416
|
+
const result = await adapter.send(payload, makeDestination());
|
|
417
|
+
|
|
418
|
+
expect(result.success).toBe(true);
|
|
419
|
+
expect(fetchCalls[0]!.body.title).toBe("Sent clip");
|
|
420
|
+
expect(fetchCalls[0]!.body.body).toBe("Sent clip");
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
test("counts several embeds", async () => {
|
|
424
|
+
const adapter = new PlatformPushAdapter();
|
|
425
|
+
const embeds =
|
|
426
|
+
" ";
|
|
427
|
+
const payload = makePayload({ copy: { title: embeds, body: embeds } });
|
|
428
|
+
|
|
429
|
+
await adapter.send(payload, makeDestination());
|
|
430
|
+
|
|
431
|
+
expect(fetchCalls[0]!.body.title).toBe("Sent 2 attachments");
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Nothing nameable is left, so the original beats a blank field: ugly
|
|
435
|
+
// copy still delivers, an empty title is a 400.
|
|
436
|
+
test("keeps the original when there is no media to name", async () => {
|
|
437
|
+
const adapter = new PlatformPushAdapter();
|
|
438
|
+
const payload = makePayload({ copy: { title: "###", body: "###" } });
|
|
439
|
+
|
|
440
|
+
await adapter.send(payload, makeDestination());
|
|
441
|
+
|
|
442
|
+
expect(fetchCalls[0]!.body.title).toBe("###");
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
|
|
343
447
|
test("omits optional fields when absent from payload", async () => {
|
|
344
448
|
const adapter = new PlatformPushAdapter();
|
|
345
449
|
const payload: ChannelDeliveryPayload = {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* deduplicated against prior firings of the same schedule.
|
|
4
4
|
*
|
|
5
5
|
* The scheduler supplies a unique per-firing dedupeKey
|
|
6
|
-
* (`schedule:notify:<id>:<timestamp>`) so `
|
|
6
|
+
* (`schedule:notify:<id>:<timestamp>`) so `setEventDedupeKey` is never
|
|
7
7
|
* called for schedule signals and `checkDedupe` never finds a matching
|
|
8
8
|
* row when the LLM decision engine generates a stable key like
|
|
9
9
|
* `schedule:notify:<id>`.
|
|
@@ -23,7 +23,7 @@ describe("oauth provider profiles (DB-seeded)", () => {
|
|
|
23
23
|
);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
test("google provider row contains bearer injection templates for
|
|
26
|
+
test("google provider row contains bearer injection templates for 6 Google API hosts", () => {
|
|
27
27
|
const provider = getProvider("google");
|
|
28
28
|
|
|
29
29
|
expect(provider).toBeDefined();
|
|
@@ -36,7 +36,7 @@ describe("oauth provider profiles (DB-seeded)", () => {
|
|
|
36
36
|
valuePrefix: string;
|
|
37
37
|
}>;
|
|
38
38
|
|
|
39
|
-
expect(templates).toHaveLength(
|
|
39
|
+
expect(templates).toHaveLength(6);
|
|
40
40
|
|
|
41
41
|
const byHost = new Map(templates.map((t) => [t.hostPattern, t]));
|
|
42
42
|
|
|
@@ -45,6 +45,8 @@ describe("oauth provider profiles (DB-seeded)", () => {
|
|
|
45
45
|
"www.googleapis.com",
|
|
46
46
|
"people.googleapis.com",
|
|
47
47
|
"docs.googleapis.com",
|
|
48
|
+
"tasks.googleapis.com",
|
|
49
|
+
"calendar.googleapis.com",
|
|
48
50
|
]) {
|
|
49
51
|
const tpl = byHost.get(host);
|
|
50
52
|
expect(tpl).toBeDefined();
|
|
@@ -1,7 +1,44 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
1
3
|
import { describe, expect, test } from "bun:test";
|
|
2
4
|
|
|
3
5
|
import { PROVIDER_SEED_DATA } from "../oauth/seed-providers.js";
|
|
4
6
|
|
|
7
|
+
const REPO_ROOT = dirname(dirname(dirname(import.meta.dir)));
|
|
8
|
+
const WEB_PUBLIC_DIR = join(REPO_ROOT, "clients/web/public");
|
|
9
|
+
const INTEGRATION_ICON_SOURCE = join(
|
|
10
|
+
REPO_ROOT,
|
|
11
|
+
"clients/web/src/components/integrations/integration-icon.tsx",
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Provider keys the web client draws without a `BUNDLED_LOGO_URLS` entry.
|
|
16
|
+
* Google's mark is multi-colour, so it ships as the `GoogleLogo` component
|
|
17
|
+
* and is returned before the bundled-asset lookup runs.
|
|
18
|
+
*/
|
|
19
|
+
const COMPONENT_RENDERED_PROVIDERS = new Set(["google"]);
|
|
20
|
+
|
|
21
|
+
/** `publicAsset("/images/...")` paths from `BUNDLED_LOGO_URLS`, by key. */
|
|
22
|
+
function readBundledLogoMap(): Map<string, string> {
|
|
23
|
+
const source = readFileSync(INTEGRATION_ICON_SOURCE, "utf8");
|
|
24
|
+
const block = source.match(
|
|
25
|
+
/const BUNDLED_LOGO_URLS: Record<string, string> = \{([\s\S]*?)\n\};/,
|
|
26
|
+
);
|
|
27
|
+
if (!block) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`Could not find BUNDLED_LOGO_URLS in ${INTEGRATION_ICON_SOURCE}. If it ` +
|
|
30
|
+
`was renamed or restructured, update this test rather than deleting it.`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
const entries = new Map<string, string>();
|
|
34
|
+
for (const [, key, path] of block[1]!.matchAll(
|
|
35
|
+
/(\w+):\s*publicAsset\("([^"]+)"\)/g,
|
|
36
|
+
)) {
|
|
37
|
+
entries.set(key!, path!);
|
|
38
|
+
}
|
|
39
|
+
return entries;
|
|
40
|
+
}
|
|
41
|
+
|
|
5
42
|
/**
|
|
6
43
|
* Allowed CDN prefixes for the ``logoUrl`` field on ``PROVIDER_SEED_DATA``
|
|
7
44
|
* (``assistant/src/oauth/seed-providers.ts``):
|
|
@@ -41,3 +78,31 @@ describe("PROVIDER_SEED_DATA logo URLs", () => {
|
|
|
41
78
|
expect(invalid).toEqual([]);
|
|
42
79
|
});
|
|
43
80
|
});
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The `logoUrl` above is a fallback for providers registered at runtime. Every
|
|
84
|
+
* provider we seed ourselves must draw from an asset we ship, because an icon
|
|
85
|
+
* CDN can drop a brand at any time and the client then degrades to an initials
|
|
86
|
+
* avatar with nothing in CI to notice: the prefix check above passes just as
|
|
87
|
+
* happily for a URL that 404s. Simple Icons hosts no Microsoft mark and no
|
|
88
|
+
* Slack mark, so the seeded URLs for those brands do not resolve there.
|
|
89
|
+
*/
|
|
90
|
+
describe("PROVIDER_SEED_DATA bundled logo coverage", () => {
|
|
91
|
+
test("every seeded provider renders from a bundled asset", () => {
|
|
92
|
+
const bundled = readBundledLogoMap();
|
|
93
|
+
const uncovered = Object.keys(PROVIDER_SEED_DATA).filter(
|
|
94
|
+
(provider) =>
|
|
95
|
+
!bundled.has(provider) && !COMPONENT_RENDERED_PROVIDERS.has(provider),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
expect(uncovered).toEqual([]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("every bundled logo path resolves to a file on disk", () => {
|
|
102
|
+
const missingFiles = [...readBundledLogoMap()]
|
|
103
|
+
.filter(([, path]) => !existsSync(join(WEB_PUBLIC_DIR, path)))
|
|
104
|
+
.map(([provider, path]) => ({ provider, path }));
|
|
105
|
+
|
|
106
|
+
expect(missingFiles).toEqual([]);
|
|
107
|
+
});
|
|
108
|
+
});
|