@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
|
@@ -7,20 +7,90 @@
|
|
|
7
7
|
* as soon as it is complete, so speech starts before the full response lands.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { isHighSurrogate, isLowSurrogate } from "../util/unicode.js";
|
|
11
|
+
|
|
10
12
|
const DEFAULT_CHAR_THRESHOLD = 180;
|
|
11
13
|
const EAGER_CHAR_THRESHOLD = 60;
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
// Sentence enders in scripts without inter-word whitespace (CJK, Thai) or
|
|
16
|
+
// with their own terminators (Devanagari danda, Arabic-script marks). Unlike
|
|
17
|
+
// ASCII `. ! ?`, these are unambiguous: a boundary after one is valid even
|
|
18
|
+
// with no following whitespace.
|
|
19
|
+
export const NON_LATIN_SENTENCE_ENDING_PUNCTUATION = new Set([
|
|
20
|
+
"。", // ideographic full stop
|
|
21
|
+
"。", // halfwidth ideographic full stop
|
|
22
|
+
"!", // fullwidth exclamation mark
|
|
23
|
+
"?", // fullwidth question mark
|
|
24
|
+
".", // fullwidth full stop (digit-guarded below: also a decimal point)
|
|
25
|
+
"।", // Devanagari danda
|
|
26
|
+
"॥", // Devanagari double danda
|
|
27
|
+
"؟", // Arabic question mark
|
|
28
|
+
"۔", // Arabic full stop
|
|
29
|
+
]);
|
|
30
|
+
const SENTENCE_ENDING_PUNCTUATION = new Set([
|
|
31
|
+
".",
|
|
32
|
+
"!",
|
|
33
|
+
"?",
|
|
34
|
+
...NON_LATIN_SENTENCE_ENDING_PUNCTUATION,
|
|
35
|
+
]);
|
|
36
|
+
// Unlike the other non-Latin enders, the fullwidth full stop also serves as
|
|
37
|
+
// a decimal point in fullwidth numbers (3.14), so it is not a boundary
|
|
38
|
+
// when a digit follows. The ideographic full stop 。 never marks decimals
|
|
39
|
+
// and stays unconditional.
|
|
40
|
+
const FULLWIDTH_FULL_STOP = ".";
|
|
14
41
|
const TRAILING_SENTENCE_PUNCTUATION = new Set(['"', "'", ")", "]"]);
|
|
15
|
-
|
|
42
|
+
// After a non-Latin ender, locale closers (CJK corner brackets, curly
|
|
43
|
+
// quotes, guillemets) belong to the sentence they follow, exactly like the
|
|
44
|
+
// ASCII closers above; without this, 「こんにちは。」 would orphan 」 into
|
|
45
|
+
// the next segment. Superset of the ASCII closers so mixed-script text still
|
|
46
|
+
// consumes those too.
|
|
47
|
+
const NON_LATIN_TRAILING_SENTENCE_PUNCTUATION = new Set([
|
|
48
|
+
...TRAILING_SENTENCE_PUNCTUATION,
|
|
49
|
+
"」",
|
|
50
|
+
"」", // halfwidth corner bracket closer
|
|
51
|
+
"』",
|
|
52
|
+
")",
|
|
53
|
+
"】",
|
|
54
|
+
"〕",
|
|
55
|
+
"〙",
|
|
56
|
+
"〗",
|
|
57
|
+
"〛",
|
|
58
|
+
"》",
|
|
59
|
+
"〉",
|
|
60
|
+
"]",
|
|
61
|
+
"}",
|
|
62
|
+
"”",
|
|
63
|
+
"’",
|
|
64
|
+
"»",
|
|
65
|
+
]);
|
|
66
|
+
// Clause punctuation in whitespace-free scripts is likewise a valid eager
|
|
67
|
+
// boundary regardless of what follows.
|
|
68
|
+
const NON_LATIN_EAGER_CLAUSE_PUNCTUATION = new Set([
|
|
69
|
+
"、", // ideographic comma
|
|
70
|
+
"、", // halfwidth ideographic comma
|
|
71
|
+
",", // fullwidth comma
|
|
72
|
+
";", // fullwidth semicolon
|
|
73
|
+
"،", // Arabic comma
|
|
74
|
+
]);
|
|
75
|
+
const EAGER_CLAUSE_PUNCTUATION = new Set([
|
|
76
|
+
",",
|
|
77
|
+
";",
|
|
78
|
+
":",
|
|
79
|
+
...NON_LATIN_EAGER_CLAUSE_PUNCTUATION,
|
|
80
|
+
]);
|
|
81
|
+
// The fullwidth comma also serves as a thousands separator in fullwidth
|
|
82
|
+
// numbers (1,000円), so it is not a clause boundary inside a number. The
|
|
83
|
+
// ideographic comma 、 never appears in numbers and needs no guard.
|
|
84
|
+
const FULLWIDTH_COMMA = ",";
|
|
16
85
|
// A clause boundary only counts in eager mode once this much text precedes
|
|
17
86
|
// it — "Sure, " alone would be a one-word blip.
|
|
18
87
|
const EAGER_MIN_CLAUSE_PREFIX_CHARS = 24;
|
|
19
88
|
|
|
20
89
|
export interface ExtractSpeakableSegmentsOptions {
|
|
21
90
|
/**
|
|
22
|
-
* Trade segment quality for onset latency: clause punctuation (`,` `;` `:`
|
|
23
|
-
* followed by whitespace
|
|
91
|
+
* Trade segment quality for onset latency: clause punctuation (`,` `;` `:`
|
|
92
|
+
* followed by whitespace, or a non-Latin clause mark like `、` `,` `،`
|
|
93
|
+
* regardless of what follows) also ends a segment once at least
|
|
24
94
|
* ~24 chars precede it, and the max buffered length before a forced split
|
|
25
95
|
* drops from 180 to 60 chars. Applies only until the
|
|
26
96
|
* first segment of the call is found — later segments keep full-sentence
|
|
@@ -79,6 +149,27 @@ function findSpeakableBoundary(
|
|
|
79
149
|
let inItalic = false;
|
|
80
150
|
let inUnderscore = false;
|
|
81
151
|
let skipSpanChar = false;
|
|
152
|
+
// Inside a Markdown link URL (`](...)`), non-Latin terminators are path
|
|
153
|
+
// characters, not sentence enders: splitting there leaves both fragments
|
|
154
|
+
// unmatchable by the sanitizer's complete-link pattern, so markup or the
|
|
155
|
+
// raw URL gets spoken. Tracked as a paren depth, not a boolean, because
|
|
156
|
+
// the sanitizer's link pattern accepts balanced parens inside the URL
|
|
157
|
+
// (https://example.com/a_(b)/c) and the suppression must cover the same
|
|
158
|
+
// links. 0 = not inside a URL.
|
|
159
|
+
let linkUrlDepth = 0;
|
|
160
|
+
// Inside a potential Markdown link label (`[label](url)`, ``),
|
|
161
|
+
// between `[` and `](`. Terminators there are label text, and a boundary
|
|
162
|
+
// splits the link the same way a URL split does. The state resolves
|
|
163
|
+
// deterministically so a stray `[` in prose cannot suppress boundaries
|
|
164
|
+
// forever: `](` hands off to the URL state; `]` without `(` or a newline
|
|
165
|
+
// cancels the label, splitting at the first boundary it suppressed; a
|
|
166
|
+
// buffer-final `]` or an unterminated label keeps buffering (the rest may
|
|
167
|
+
// arrive in the next delta), bounded by the force flush and the length
|
|
168
|
+
// cap.
|
|
169
|
+
let inLinkLabel = false;
|
|
170
|
+
// First boundary suppressed while the current label is open; returned when
|
|
171
|
+
// the label turns out not to be a link.
|
|
172
|
+
let suppressedLabelBoundary: number | null = null;
|
|
82
173
|
|
|
83
174
|
for (let index = 0; index < text.length; index += 1) {
|
|
84
175
|
const char = text[index];
|
|
@@ -87,8 +178,54 @@ function findSpeakableBoundary(
|
|
|
87
178
|
}
|
|
88
179
|
const inOpenSpan = inBacktick || inBold || inItalic || inUnderscore;
|
|
89
180
|
|
|
90
|
-
if (
|
|
91
|
-
|
|
181
|
+
if (char === "\n") {
|
|
182
|
+
// A URL never spans a line: an unclosed link stops suppressing here so
|
|
183
|
+
// malformed markup cannot defer the newline split. Labels do not span
|
|
184
|
+
// lines either; a suppressed boundary reopens ahead of the newline.
|
|
185
|
+
linkUrlDepth = 0;
|
|
186
|
+
inLinkLabel = false;
|
|
187
|
+
if (suppressedLabelBoundary !== null) {
|
|
188
|
+
return suppressedLabelBoundary;
|
|
189
|
+
}
|
|
190
|
+
if (!inOpenSpan) {
|
|
191
|
+
return index + 1;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (linkUrlDepth > 0) {
|
|
196
|
+
if (char === "(") {
|
|
197
|
+
linkUrlDepth += 1;
|
|
198
|
+
} else if (char === ")") {
|
|
199
|
+
linkUrlDepth -= 1;
|
|
200
|
+
}
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (char === "]" && inLinkLabel && text[index + 1] !== "(") {
|
|
204
|
+
if (index + 1 === text.length) {
|
|
205
|
+
// A buffer-final `]` is ambiguous while streaming: the `(` may open
|
|
206
|
+
// the next delta. Keep buffering; force and the length cap below
|
|
207
|
+
// still flush.
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
// Not a link after all: the label text is plain prose, so the first
|
|
211
|
+
// boundary it suppressed becomes the split point again.
|
|
212
|
+
inLinkLabel = false;
|
|
213
|
+
if (suppressedLabelBoundary !== null) {
|
|
214
|
+
return suppressedLabelBoundary;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (char === "]" && text[index + 1] === "(") {
|
|
218
|
+
inLinkLabel = false;
|
|
219
|
+
suppressedLabelBoundary = null;
|
|
220
|
+
linkUrlDepth = 1;
|
|
221
|
+
// Skip the opening paren so it does not double-count the depth.
|
|
222
|
+
index += 1;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
// A `[` inside an open inline span is literal text (e.g. inline code
|
|
226
|
+
// containing an array literal), never a link-label opener.
|
|
227
|
+
if (char === "[" && !inLinkLabel && !inOpenSpan) {
|
|
228
|
+
inLinkLabel = true;
|
|
92
229
|
}
|
|
93
230
|
|
|
94
231
|
if (
|
|
@@ -96,21 +233,75 @@ function findSpeakableBoundary(
|
|
|
96
233
|
eager &&
|
|
97
234
|
EAGER_CLAUSE_PUNCTUATION.has(char) &&
|
|
98
235
|
index >= EAGER_MIN_CLAUSE_PREFIX_CHARS &&
|
|
99
|
-
|
|
236
|
+
(NON_LATIN_EAGER_CLAUSE_PUNCTUATION.has(char) ||
|
|
237
|
+
isWhitespace(text[index + 1] ?? "")) &&
|
|
238
|
+
!isFullwidthGroupingComma(text, index)
|
|
100
239
|
) {
|
|
101
|
-
|
|
240
|
+
if (inLinkLabel) {
|
|
241
|
+
suppressedLabelBoundary ??= index + 1;
|
|
242
|
+
} else {
|
|
243
|
+
return index + 1;
|
|
244
|
+
}
|
|
102
245
|
}
|
|
103
246
|
|
|
104
247
|
if (!inOpenSpan && SENTENCE_ENDING_PUNCTUATION.has(char)) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
248
|
+
const isNonLatinEnder = NON_LATIN_SENTENCE_ENDING_PUNCTUATION.has(char);
|
|
249
|
+
// The fullwidth full stop doubles as a decimal point in fullwidth
|
|
250
|
+
// numbers (3.14です), so a following digit suppresses the boundary.
|
|
251
|
+
// It also appears inside Latin filename-style tokens (report.pdf):
|
|
252
|
+
// ASCII word chars on both sides mark it as part of the token, not a
|
|
253
|
+
// sentence end. CJK neighbors keep the boundary, since Japanese
|
|
254
|
+
// sentences legitimately end in . between CJK words.
|
|
255
|
+
const isAmbiguousDecimalPoint =
|
|
256
|
+
char === FULLWIDTH_FULL_STOP &&
|
|
257
|
+
(isDecimalDigit(text[index + 1]) ||
|
|
258
|
+
(isAsciiWordChar(text[index - 1]) &&
|
|
259
|
+
isAsciiWordChar(text[index + 1])));
|
|
260
|
+
if (isNonLatinEnder && !isAmbiguousDecimalPoint) {
|
|
261
|
+
// Non-Latin enders are valid boundaries regardless of what follows;
|
|
262
|
+
// consume adjacent enders (本当!?) so combined punctuation keeps
|
|
263
|
+
// its prosody and never becomes a punctuation-only segment, then
|
|
264
|
+
// consume locale closers so they stay with their sentence.
|
|
265
|
+
let boundary = index + 1;
|
|
266
|
+
while (
|
|
267
|
+
boundary < text.length &&
|
|
268
|
+
(NON_LATIN_SENTENCE_ENDING_PUNCTUATION.has(text[boundary] ?? "") ||
|
|
269
|
+
NON_LATIN_TRAILING_SENTENCE_PUNCTUATION.has(text[boundary] ?? ""))
|
|
270
|
+
) {
|
|
271
|
+
boundary += 1;
|
|
272
|
+
}
|
|
273
|
+
// A buffer-final ender is ambiguous while streaming: the next delta
|
|
274
|
+
// may open with closers that belong to this sentence (`「こんにちは。`
|
|
275
|
+
// then `」`) or, for ., with decimal digits (`3.` then `14です`).
|
|
276
|
+
// Keep buffering; the `force` flush path still emits a buffer-final
|
|
277
|
+
// sentence at end of turn, and the length cap below still bounds the
|
|
278
|
+
// buffer. ASCII enders keep their end-of-text boundary: whitespace
|
|
279
|
+
// scripts do not attach closers across deltas the same way.
|
|
280
|
+
if (boundary < text.length) {
|
|
281
|
+
if (inLinkLabel) {
|
|
282
|
+
suppressedLabelBoundary ??= boundary;
|
|
283
|
+
} else {
|
|
284
|
+
return boundary;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
111
287
|
}
|
|
112
|
-
if (
|
|
113
|
-
|
|
288
|
+
if (!isNonLatinEnder) {
|
|
289
|
+
// ASCII enders require following whitespace so decimals (3.14) and
|
|
290
|
+
// file names don't split.
|
|
291
|
+
let boundary = index + 1;
|
|
292
|
+
while (
|
|
293
|
+
boundary < text.length &&
|
|
294
|
+
TRAILING_SENTENCE_PUNCTUATION.has(text[boundary] ?? "")
|
|
295
|
+
) {
|
|
296
|
+
boundary += 1;
|
|
297
|
+
}
|
|
298
|
+
if (boundary === text.length || isWhitespace(text[boundary] ?? "")) {
|
|
299
|
+
if (inLinkLabel) {
|
|
300
|
+
suppressedLabelBoundary ??= boundary;
|
|
301
|
+
} else {
|
|
302
|
+
return boundary;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
114
305
|
}
|
|
115
306
|
}
|
|
116
307
|
|
|
@@ -119,8 +310,8 @@ function findSpeakableBoundary(
|
|
|
119
310
|
} else if (char === "`") {
|
|
120
311
|
inBacktick = !inBacktick;
|
|
121
312
|
} else if (char === "*") {
|
|
122
|
-
const prev = text
|
|
123
|
-
const next = text
|
|
313
|
+
const prev = codePointBefore(text, index);
|
|
314
|
+
const next = codePointAfter(text, index);
|
|
124
315
|
if (next === "*") {
|
|
125
316
|
inBold = !inBold;
|
|
126
317
|
skipSpanChar = true;
|
|
@@ -141,8 +332,8 @@ function findSpeakableBoundary(
|
|
|
141
332
|
} else if (char === "_") {
|
|
142
333
|
// Same word-boundary rule as `*`. Since `_` neighbors in identifiers
|
|
143
334
|
// like `my_var` are word chars, they never open or close a span.
|
|
144
|
-
const prev = text
|
|
145
|
-
const next = text
|
|
335
|
+
const prev = codePointBefore(text, index);
|
|
336
|
+
const next = codePointAfter(text, index);
|
|
146
337
|
if (inUnderscore) {
|
|
147
338
|
if (prev !== undefined && !isWhitespace(prev) && !isWordChar(next)) {
|
|
148
339
|
inUnderscore = false;
|
|
@@ -161,14 +352,93 @@ function findSpeakableBoundary(
|
|
|
161
352
|
return null;
|
|
162
353
|
}
|
|
163
354
|
|
|
355
|
+
// The length cap bounds how long an open label can defer: past it, the
|
|
356
|
+
// first boundary the label suppressed beats an arbitrary mid-text split.
|
|
357
|
+
if (suppressedLabelBoundary !== null) {
|
|
358
|
+
return suppressedLabelBoundary;
|
|
359
|
+
}
|
|
360
|
+
|
|
164
361
|
// Length-threshold splits are a hard cap and must flush even inside an
|
|
165
|
-
// open span
|
|
362
|
+
// open span: unbalanced markers there are an accepted edge.
|
|
166
363
|
const preferredBoundary = findLastWhitespaceBoundary(text, charThreshold);
|
|
167
|
-
|
|
364
|
+
if (preferredBoundary !== null) {
|
|
365
|
+
return preferredBoundary;
|
|
366
|
+
}
|
|
367
|
+
// Never split a UTF-16 surrogate pair: if the cap lands mid-pair, step
|
|
368
|
+
// back one unit so both halves stay in the same segment.
|
|
369
|
+
if (isHighSurrogate(text.charCodeAt(charThreshold - 1))) {
|
|
370
|
+
return charThreshold - 1;
|
|
371
|
+
}
|
|
372
|
+
return charThreshold;
|
|
168
373
|
}
|
|
169
374
|
|
|
375
|
+
/**
|
|
376
|
+
* Accepts a full code point (one or two UTF-16 units) so non-BMP letters
|
|
377
|
+
* like 𠮟 count as word chars, matching the sanitizer's Unicode lookarounds
|
|
378
|
+
* in calls/tts-text-sanitizer.ts.
|
|
379
|
+
*/
|
|
170
380
|
function isWordChar(value: string | undefined): boolean {
|
|
171
|
-
return value !== undefined &&
|
|
381
|
+
return value !== undefined && /[\p{L}\p{N}_]/u.test(value);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function isDecimalDigit(value: string | undefined): boolean {
|
|
385
|
+
return value !== undefined && /[0-90-9]/.test(value);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// ASCII-only on purpose: filename-style tokens (report.pdf) are Latin
|
|
389
|
+
// script, while CJK neighbors around . mark real sentence text.
|
|
390
|
+
function isAsciiWordChar(value: string | undefined): boolean {
|
|
391
|
+
return value !== undefined && /[A-Za-z0-9_]/.test(value);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* A fullwidth comma acting as a thousands separator (1,000円): a digit
|
|
396
|
+
* precedes it and a digit follows, or the buffer ends right after it while
|
|
397
|
+
* streaming (the digits may arrive in the next delta, so keep buffering).
|
|
398
|
+
*/
|
|
399
|
+
function isFullwidthGroupingComma(text: string, index: number): boolean {
|
|
400
|
+
if (text[index] !== FULLWIDTH_COMMA || !isDecimalDigit(text[index - 1])) {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
const next = text[index + 1];
|
|
404
|
+
return next === undefined || isDecimalDigit(next);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* The full code point ending just before `index`. When the preceding unit is
|
|
409
|
+
* a low surrogate, includes its high surrogate so `isWordChar` sees the
|
|
410
|
+
* whole character instead of half a pair.
|
|
411
|
+
*/
|
|
412
|
+
function codePointBefore(text: string, index: number): string | undefined {
|
|
413
|
+
const unit = text[index - 1];
|
|
414
|
+
if (unit === undefined) {
|
|
415
|
+
return undefined;
|
|
416
|
+
}
|
|
417
|
+
if (isLowSurrogate(unit.charCodeAt(0))) {
|
|
418
|
+
const high = text[index - 2];
|
|
419
|
+
if (high !== undefined && isHighSurrogate(high.charCodeAt(0))) {
|
|
420
|
+
return high + unit;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return unit;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* The full code point starting just after `index`. When the following unit
|
|
428
|
+
* is a high surrogate, includes its low surrogate.
|
|
429
|
+
*/
|
|
430
|
+
function codePointAfter(text: string, index: number): string | undefined {
|
|
431
|
+
const unit = text[index + 1];
|
|
432
|
+
if (unit === undefined) {
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
435
|
+
if (isHighSurrogate(unit.charCodeAt(0))) {
|
|
436
|
+
const low = text[index + 2];
|
|
437
|
+
if (low !== undefined && isLowSurrogate(low.charCodeAt(0))) {
|
|
438
|
+
return unit + low;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return unit;
|
|
172
442
|
}
|
|
173
443
|
|
|
174
444
|
function findLastWhitespaceBoundary(
|
|
@@ -56,6 +56,12 @@ export interface SynthesisEmitOptions {
|
|
|
56
56
|
/** Preferred PCM sample rate in Hz, forwarded on the provider request. */
|
|
57
57
|
sampleRateHz?: number;
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Language hint forwarded on the provider request
|
|
61
|
+
* (see {@link TtsSynthesisRequest.language}).
|
|
62
|
+
*/
|
|
63
|
+
language?: string;
|
|
64
|
+
|
|
59
65
|
/** Abort signal forwarded to the provider and checked before each emit. */
|
|
60
66
|
signal?: AbortSignal;
|
|
61
67
|
|
|
@@ -106,6 +112,7 @@ export async function synthesizeAndEmit(
|
|
|
106
112
|
voiceId: options.voiceId,
|
|
107
113
|
outputFormat: options.outputFormat,
|
|
108
114
|
sampleRateHz: options.sampleRateHz,
|
|
115
|
+
language: options.language,
|
|
109
116
|
signal,
|
|
110
117
|
};
|
|
111
118
|
|
package/src/tts/types.ts
CHANGED
|
@@ -113,6 +113,13 @@ export interface TtsSynthesisRequest {
|
|
|
113
113
|
* on provider-documented behavior (see each provider's format mapping).
|
|
114
114
|
*/
|
|
115
115
|
sampleRateHz?: number;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Optional lowercase BCP-47 base subtag (e.g. `"es"`, `"hi"`) hinting the
|
|
119
|
+
* language of `text`. Providers that support language enforcement apply
|
|
120
|
+
* it; providers that cannot use it must ignore it.
|
|
121
|
+
*/
|
|
122
|
+
language?: string;
|
|
116
123
|
}
|
|
117
124
|
|
|
118
125
|
/** Output of a completed TTS synthesis call. */
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { getDb } from "../../persistence/db-connection.js";
|
|
4
|
+
import { initializeDb } from "../../persistence/db-init.js";
|
|
5
|
+
import {
|
|
6
|
+
resetSubagentAttributionCacheForTests,
|
|
7
|
+
resolveSubagentAttribution,
|
|
8
|
+
} from "../subagent-attribution.js";
|
|
9
|
+
|
|
10
|
+
await initializeDb();
|
|
11
|
+
|
|
12
|
+
let counter = 0;
|
|
13
|
+
|
|
14
|
+
function insertConversation(opts: {
|
|
15
|
+
subagentRole?: string;
|
|
16
|
+
subagentSpawnMode?: string;
|
|
17
|
+
}): string {
|
|
18
|
+
counter += 1;
|
|
19
|
+
const id = `conv-attr-${counter}`;
|
|
20
|
+
const db = getDb();
|
|
21
|
+
db.run(
|
|
22
|
+
`INSERT INTO conversations (id, conversation_type, created_at, updated_at, subagent_role, subagent_spawn_mode)
|
|
23
|
+
VALUES ('${id}', 'background', 1000, 1000, ${
|
|
24
|
+
opts.subagentRole === undefined ? "NULL" : `'${opts.subagentRole}'`
|
|
25
|
+
}, ${
|
|
26
|
+
opts.subagentSpawnMode === undefined
|
|
27
|
+
? "NULL"
|
|
28
|
+
: `'${opts.subagentSpawnMode}'`
|
|
29
|
+
})`,
|
|
30
|
+
);
|
|
31
|
+
return id;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe("resolveSubagentAttribution", () => {
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
resetSubagentAttributionCacheForTests();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("returns the stamped role and spawn mode for a subagent conversation", () => {
|
|
40
|
+
const id = insertConversation({
|
|
41
|
+
subagentRole: "advisor",
|
|
42
|
+
subagentSpawnMode: "advisor_consult",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
expect(resolveSubagentAttribution(id)).toEqual({
|
|
46
|
+
subagentRole: "advisor",
|
|
47
|
+
subagentSpawnMode: "advisor_consult",
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("returns nulls for an ordinary conversation", () => {
|
|
52
|
+
const id = insertConversation({});
|
|
53
|
+
|
|
54
|
+
expect(resolveSubagentAttribution(id)).toEqual({
|
|
55
|
+
subagentRole: null,
|
|
56
|
+
subagentSpawnMode: null,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("returns nulls without a conversation id", () => {
|
|
61
|
+
expect(resolveSubagentAttribution(undefined)).toEqual({
|
|
62
|
+
subagentRole: null,
|
|
63
|
+
subagentSpawnMode: null,
|
|
64
|
+
});
|
|
65
|
+
expect(resolveSubagentAttribution("")).toEqual({
|
|
66
|
+
subagentRole: null,
|
|
67
|
+
subagentSpawnMode: null,
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("returns nulls for an unknown conversation and does not cache the miss", () => {
|
|
72
|
+
// The columns are stamped at conversation creation, so a miss means the
|
|
73
|
+
// row has not landed yet, and caching it would pin an empty result.
|
|
74
|
+
expect(resolveSubagentAttribution("conv-not-yet")).toEqual({
|
|
75
|
+
subagentRole: null,
|
|
76
|
+
subagentSpawnMode: null,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const db = getDb();
|
|
80
|
+
db.run(
|
|
81
|
+
`INSERT INTO conversations (id, conversation_type, created_at, updated_at, subagent_role, subagent_spawn_mode)
|
|
82
|
+
VALUES ('conv-not-yet', 'background', 1000, 1000, 'coder', 'regular')`,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(resolveSubagentAttribution("conv-not-yet")).toEqual({
|
|
86
|
+
subagentRole: "coder",
|
|
87
|
+
subagentSpawnMode: "regular",
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("memoizes a resolved conversation", () => {
|
|
92
|
+
const id = insertConversation({
|
|
93
|
+
subagentRole: "general",
|
|
94
|
+
subagentSpawnMode: "fork",
|
|
95
|
+
});
|
|
96
|
+
expect(resolveSubagentAttribution(id).subagentSpawnMode).toBe("fork");
|
|
97
|
+
|
|
98
|
+
// The columns are immutable after creation, so a later write must not be
|
|
99
|
+
// observable, proving the second call did not hit the database.
|
|
100
|
+
const db = getDb();
|
|
101
|
+
db.run(
|
|
102
|
+
`UPDATE conversations SET subagent_spawn_mode = 'regular' WHERE id = '${id}'`,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
expect(resolveSubagentAttribution(id).subagentSpawnMode).toBe("fork");
|
|
106
|
+
resetSubagentAttributionCacheForTests();
|
|
107
|
+
expect(resolveSubagentAttribution(id).subagentSpawnMode).toBe("regular");
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { rawGet } from "../persistence/raw-query.js";
|
|
2
|
+
import { getLogger } from "../util/logger.js";
|
|
3
|
+
|
|
4
|
+
const log = getLogger("subagent-attribution");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The two delegated-work attribution dimensions carried on a conversation:
|
|
8
|
+
* the subagent role it was spawned with, and how it was spawned. Both null
|
|
9
|
+
* for a conversation that is not a subagent.
|
|
10
|
+
*/
|
|
11
|
+
export interface SubagentAttribution {
|
|
12
|
+
subagentRole: string | null;
|
|
13
|
+
subagentSpawnMode: string | null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const NOT_A_SUBAGENT: SubagentAttribution = {
|
|
17
|
+
subagentRole: null,
|
|
18
|
+
subagentSpawnMode: null,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Bound on the memo below. Both columns are stamped once at conversation
|
|
23
|
+
* creation and never updated, so a hit is always correct and the only cost of
|
|
24
|
+
* a bounded cache is an occasional re-read. Sized to comfortably cover the
|
|
25
|
+
* conversations resident in one process without becoming a memory concern.
|
|
26
|
+
*/
|
|
27
|
+
const MAX_CACHED_CONVERSATIONS = 2048;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Insertion-ordered memo. `Map` iteration order is insertion order, so
|
|
31
|
+
* dropping the first key evicts the oldest entry, sufficient for a lookup
|
|
32
|
+
* whose values are immutable and whose miss cost is a single primary-key read.
|
|
33
|
+
*/
|
|
34
|
+
const cache = new Map<string, SubagentAttribution>();
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Resolve the delegated-work attribution for a conversation, for forwarding on
|
|
38
|
+
* the runtime proxy's `X-Vellum-Subagent-*` headers.
|
|
39
|
+
*
|
|
40
|
+
* Reads the columns stamped at spawn time (migration 362) rather than the
|
|
41
|
+
* `subagents` table: `subagents` rows are deleted on dispose, and the billing
|
|
42
|
+
* path must not depend on a row that may already be gone.
|
|
43
|
+
*
|
|
44
|
+
* Never throws. This runs on the provider dispatch hot path and attribution
|
|
45
|
+
* must never be able to take a model request down. Any failure degrades to
|
|
46
|
+
* "no attribution", which is exactly how the platform treats a missing header.
|
|
47
|
+
*/
|
|
48
|
+
export function resolveSubagentAttribution(
|
|
49
|
+
conversationId: string | undefined,
|
|
50
|
+
): SubagentAttribution {
|
|
51
|
+
if (conversationId === undefined || conversationId.length === 0) {
|
|
52
|
+
return NOT_A_SUBAGENT;
|
|
53
|
+
}
|
|
54
|
+
const cached = cache.get(conversationId);
|
|
55
|
+
if (cached !== undefined) {
|
|
56
|
+
return cached;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const row = readRow(conversationId);
|
|
60
|
+
if (!row) {
|
|
61
|
+
// Either no row yet, or the read failed. Deliberately NOT cached: caching
|
|
62
|
+
// a miss would pin an empty result for a conversation whose row lands
|
|
63
|
+
// moments later, or for the whole process after one transient DB error.
|
|
64
|
+
return NOT_A_SUBAGENT;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const attribution: SubagentAttribution = {
|
|
68
|
+
subagentRole: row.subagent_role,
|
|
69
|
+
subagentSpawnMode: row.subagent_spawn_mode,
|
|
70
|
+
};
|
|
71
|
+
if (cache.size >= MAX_CACHED_CONVERSATIONS) {
|
|
72
|
+
const oldest = cache.keys().next();
|
|
73
|
+
if (!oldest.done) {
|
|
74
|
+
cache.delete(oldest.value);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
cache.set(conversationId, attribution);
|
|
78
|
+
return attribution;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface ConversationSubagentRow {
|
|
82
|
+
subagent_role: string | null;
|
|
83
|
+
subagent_spawn_mode: string | null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Read the two columns, or `null` when the conversation has no row or the
|
|
88
|
+
* read fails. Failure covers the pre-migration case (columns absent) and any
|
|
89
|
+
* DB-unavailable context, such as a unit test exercising the provider stack
|
|
90
|
+
* alone. Attribution must never be able to take a model request down.
|
|
91
|
+
*/
|
|
92
|
+
function readRow(conversationId: string): ConversationSubagentRow | null {
|
|
93
|
+
try {
|
|
94
|
+
return rawGet<ConversationSubagentRow>(
|
|
95
|
+
"usage:subagentAttribution",
|
|
96
|
+
`SELECT subagent_role, subagent_spawn_mode FROM conversations WHERE id = ?`,
|
|
97
|
+
conversationId,
|
|
98
|
+
);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
log.debug({ err, conversationId }, "Subagent attribution lookup failed");
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Test seam: drops every memoized entry. */
|
|
106
|
+
export function resetSubagentAttributionCacheForTests(): void {
|
|
107
|
+
cache.clear();
|
|
108
|
+
}
|