@vellumai/assistant 0.11.3 → 0.11.4-dev.202608190019.b94dbf2
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/AGENTS.md +9 -3
- package/ARCHITECTURE.md +32 -10
- package/docs/architecture/memory.md +43 -5
- package/docs/architecture/security.md +96 -152
- package/docs/architecture/turn-actor.md +70 -0
- package/docs/browser-use-architecture-phase2.md +128 -56
- package/docs/flux-turn-detection-spike.md +248 -0
- package/docs/guardian-request-flow.md +35 -0
- package/docs/stt-provider-onboarding.md +3 -1
- package/knip.json +3 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
- package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/openapi.yaml +289 -113
- package/package.json +1 -1
- package/scripts/voice-ttft-spike.ts +3 -3
- package/scripts/write-plugin-api-shim.ts +10 -0
- package/src/__tests__/app-compiler.test.ts +38 -3
- package/src/__tests__/app-control-flow.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +2 -2
- package/src/__tests__/assistant-feature-flag-guard.test.ts +25 -3
- package/src/__tests__/attachments-store.test.ts +21 -12
- package/src/__tests__/byok-default-profile-ensure.test.ts +17 -0
- package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -1
- package/src/__tests__/call-site-routing-provider.test.ts +1 -1
- package/src/__tests__/channel-availability-routes.test.ts +14 -1
- package/src/__tests__/channel-capabilities-dedupe.test.ts +214 -0
- package/src/__tests__/channel-delivery-store.test.ts +14 -14
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
- package/src/__tests__/channel-setup-panel-ack.test.ts +1 -1
- package/src/__tests__/checker.test.ts +20 -314
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
- package/src/__tests__/compaction-events.test.ts +8 -10
- package/src/__tests__/config-loader-backfill.test.ts +3 -3
- package/src/__tests__/config-schema.test.ts +25 -10
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +8 -11
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +8 -11
- package/src/__tests__/conversation-agent-loop.test.ts +32 -21
- package/src/__tests__/conversation-attachments.test.ts +0 -1
- package/src/__tests__/conversation-attention-store.test.ts +63 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +112 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -4
- package/src/__tests__/conversation-fork-crud.test.ts +69 -0
- package/src/__tests__/conversation-fork-referential.test.ts +67 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +24 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +209 -0
- package/src/__tests__/conversation-notifiers-provenance.test.ts +59 -0
- package/src/__tests__/conversation-queue.test.ts +154 -4
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +1 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +9 -9
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +1 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +187 -102
- package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
- package/src/__tests__/conversation-slash-queue.test.ts +3 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-app-open.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +21 -14
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-state-update.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-table-action.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
- package/src/__tests__/credential-prompt-route.test.ts +7 -10
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +1 -0
- package/src/__tests__/custom-profile-ensure.test.ts +5 -1
- package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +5 -1
- package/src/__tests__/discord-requester-notice-privacy.test.ts +3 -3
- package/src/__tests__/document-append-idempotency.test.ts +233 -0
- package/src/__tests__/document-sync-tags.test.ts +0 -75
- package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
- package/src/__tests__/edit-propagation.test.ts +107 -11
- package/src/__tests__/file-ops-service.test.ts +163 -30
- package/src/__tests__/filesystem-tools.test.ts +23 -24
- package/src/__tests__/gateway-only-guard.test.ts +2 -5
- package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
- package/src/__tests__/helpers/mock-actor-context.ts +49 -0
- package/src/__tests__/helpers/mock-conversation.ts +13 -1
- package/src/__tests__/host-file-read-tool.test.ts +16 -19
- package/src/__tests__/http-user-message-parity.test.ts +1 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +49 -0
- package/src/__tests__/injector-chain.test.ts +63 -41
- package/src/__tests__/injector-disk-pressure.test.ts +11 -23
- package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
- package/src/__tests__/llm-context-resolution.test.ts +73 -1
- package/src/__tests__/llm-schema.test.ts +5 -2
- package/src/__tests__/managed-skill-lifecycle.test.ts +7 -0
- package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
- package/src/__tests__/media-generate-image.test.ts +131 -21
- package/src/__tests__/memory-retrieval-hook.test.ts +100 -7
- package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
- package/src/__tests__/mtime-cache.test.ts +3 -1
- package/src/__tests__/non-member-access-request.test.ts +0 -20
- package/src/__tests__/outbound-slack-persistence.test.ts +40 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
- package/src/__tests__/plugin-api-store-credential.test.ts +261 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +10 -7
- package/src/__tests__/plugin-disabled-state.test.ts +2 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
- package/src/__tests__/plugin-execution-context.test.ts +73 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +7 -4
- package/src/__tests__/plugin-secret-pattern-contribution.test.ts +1 -1
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +14 -7
- package/src/__tests__/provider-commit-message-generator.test.ts +20 -0
- package/src/__tests__/proxy-approval-callback.test.ts +1 -0
- package/src/__tests__/qdrant-manager.test.ts +14 -1
- package/src/__tests__/reaction-persistence.test.ts +200 -7
- package/src/__tests__/require-fresh-approval.test.ts +0 -4
- package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +460 -105
- package/src/__tests__/run-due-schedules.test.ts +21 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +187 -18
- package/src/__tests__/schedule-routes.test.ts +23 -0
- package/src/__tests__/schedule-store.test.ts +17 -0
- package/src/__tests__/scoped-approval-grants.test.ts +11 -6
- package/src/__tests__/secret-ingress-channel.test.ts +0 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +3 -3
- package/src/__tests__/skills.test.ts +32 -0
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
- package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
- package/src/__tests__/subagent-spawn-and-await.test.ts +18 -17
- package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
- package/src/__tests__/subagent-tools.test.ts +81 -101
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +1 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
- package/src/__tests__/tool-executor.test.ts +68 -39
- package/src/__tests__/turn-events-store.test.ts +43 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +1 -1
- package/src/__tests__/ui-shape-teaching.test.ts +33 -0
- package/src/__tests__/ui-visual-surface.test.ts +1 -1
- package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
- package/src/__tests__/ui-work-result-surface.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +3 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/visible-app-context.test.ts +16 -9
- package/src/__tests__/voice-config-update.test.ts +40 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +5 -3
- package/src/__tests__/voice-session-bridge.test.ts +85 -29
- package/src/__tests__/worker-entrypoint-guards.test.ts +54 -0
- package/src/__tests__/worker-plugin-surface.test.ts +77 -0
- package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +158 -0
- package/src/__tests__/workspace-migration-143-repair-deprecated-codex-model-id.test.ts +133 -0
- package/src/__tests__/workspace-migration-144-convert-stranded-subscription-openai-profiles.test.ts +316 -0
- package/src/__tests__/workspace-migration-145-collapse-profile-bindings-to-entries.test.ts +325 -0
- package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +235 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +10 -2
- package/src/acp/__tests__/auth-required.test.ts +161 -0
- package/src/acp/acp-claude-oauth.ts +19 -2
- package/src/acp/agent-process.test.ts +100 -0
- package/src/acp/agent-process.ts +29 -26
- package/src/acp/auth-required.ts +102 -0
- package/src/acp/session-manager.test.ts +119 -0
- package/src/acp/session-manager.ts +76 -3
- package/src/api/events/acp-auth-required.ts +55 -0
- package/src/api/events/host-file.ts +2 -2
- package/src/api/index.ts +7 -0
- package/src/api/surfaces.ts +12 -3
- package/src/apps/app-store.ts +3 -0
- package/src/bundler/package-resolver.ts +2 -30
- package/src/calls/__tests__/voice-session-bridge.test.ts +194 -11
- package/src/calls/__tests__/voice-triage-escalate.test.ts +102 -0
- package/src/calls/call-controller.ts +19 -3
- package/src/calls/call-setup-flow.ts +0 -1
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/calls/voice-session-bridge.ts +115 -41
- package/src/calls/voice-triage-escalate.ts +105 -2
- package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
- package/src/channels/config.ts +13 -0
- package/src/channels/plugin-channel-declarations.ts +108 -0
- package/src/channels/types.ts +30 -0
- package/src/cli/AGENTS.md +5 -2
- package/src/cli/bundled-modules.ts +29 -0
- package/src/cli/commands/credentials.help.ts +2 -2
- package/src/cli/commands/db/repair.ts +4 -8
- package/src/cli/commands/domain.ts +6 -3
- package/src/cli/commands/email.ts +6 -3
- package/src/cli/commands/inference-providers.ts +1 -1
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.help.ts +13 -4
- package/src/cli/commands/mcp.ts +9 -0
- package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
- package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
- package/src/cli/commands/memory/index.help.ts +84 -28
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/memory-v2.ts +58 -54
- package/src/cli/commands/memory/memory-v3.ts +64 -0
- package/src/cli/commands/memory/memory-validate.ts +18 -0
- package/src/cli/commands/plugins.ts +85 -36
- package/src/cli/commands/schedules.ts +35 -1
- package/src/cli/commands/stt.help.ts +27 -2
- package/src/cli/commands/trust.ts +3 -14
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
- package/src/cli/lib/bundled-marketplace.json +14 -1
- package/src/cli/lib/upgrade-plugin.ts +42 -0
- package/src/config/__tests__/balanced-model-experiment.test.ts +278 -0
- package/src/config/__tests__/default-profile-catalog.test.ts +34 -2
- package/src/config/__tests__/default-provider.test.ts +6 -1
- package/src/config/__tests__/profile-materialization.test.ts +75 -19
- package/src/config/assistant-feature-flags.ts +36 -15
- package/src/config/balanced-model-experiment.ts +35 -0
- package/src/config/bundled-skills/acp/SKILL.md +6 -7
- package/src/config/bundled-skills/document-editor/SKILL.md +2 -2
- package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/SKILL.md +5 -4
- package/src/config/bundled-skills/image-studio/TOOLS.json +1 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +101 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.test.ts +65 -0
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +7 -1
- package/src/config/bundled-skills/settings/tools/shared.ts +16 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +9 -3
- package/src/config/bundled-skills/subagent/SKILL.md +17 -12
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -4
- 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/call-site-defaults.ts +11 -5
- package/src/config/default-profile-catalog.ts +179 -16
- package/src/config/default-profile-names.ts +4 -1
- package/src/config/default-provider-resolution.ts +4 -0
- package/src/config/feature-flag-registry.json +12 -12
- package/src/config/llm-context-resolution.ts +11 -3
- package/src/config/llm-resolver.ts +28 -1
- package/src/config/profile-materialization.ts +70 -22
- package/src/config/schemas/__tests__/live-voice.test.ts +107 -4
- package/src/config/schemas/call-site-catalog.ts +4 -4
- package/src/config/schemas/live-voice.ts +57 -23
- package/src/config/schemas/llm.ts +59 -32
- package/src/config/schemas/mcp.ts +23 -0
- package/src/config/schemas/plugin-updates.ts +6 -2
- package/src/config/schemas/stt.ts +1 -0
- package/src/config/skills.ts +9 -2
- package/src/context/outbound-sanitize.ts +96 -1
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +82 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +15 -10
- package/src/daemon/conversation-agent-loop.ts +31 -19
- package/src/daemon/conversation-messaging.ts +5 -1
- package/src/daemon/conversation-notifiers.ts +20 -10
- package/src/daemon/conversation-process.ts +20 -6
- package/src/daemon/conversation-runtime-assembly.ts +12 -6
- package/src/daemon/conversation-store.ts +14 -4
- package/src/daemon/conversation-surfaces.ts +75 -26
- package/src/daemon/conversation-tool-setup.ts +3 -6
- package/src/daemon/conversation.ts +154 -51
- package/src/daemon/doordash-steps.ts +2 -2
- package/src/daemon/lifecycle.ts +14 -1
- package/src/daemon/mcp-reload-service.ts +36 -6
- package/src/daemon/process-message.ts +13 -26
- package/src/daemon/providers-setup.ts +6 -3
- package/src/daemon/trust-context-types.ts +29 -0
- package/src/daemon/trust-context.ts +12 -7
- package/src/daemon/wake-conversation-ops.ts +3 -2
- package/src/daemon/windows-compiled-entry.ts +4 -0
- package/src/documents/document-store.ts +143 -240
- package/src/hooks/hook-loader.ts +3 -3
- package/src/hooks/registry.ts +103 -45
- package/src/hooks/types.ts +5 -0
- package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
- package/src/inbound/oauth-callback-url.ts +61 -0
- package/src/ipc/gateway-client.test.ts +1 -1
- package/src/ipc/gateway-client.ts +14 -21
- package/src/ipc/gateway-flag-listener.ts +17 -3
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
- package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +1050 -0
- 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 +60 -194
- package/src/live-voice/__tests__/live-voice-stt.test.ts +14 -0
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +29 -0
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
- package/src/live-voice/__tests__/live-voice-vad.test.ts +0 -16
- package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
- package/src/live-voice/live-voice-archive.ts +2 -0
- package/src/live-voice/live-voice-manager.ts +16 -3
- package/src/live-voice/live-voice-metrics.ts +57 -32
- package/src/live-voice/live-voice-photo.ts +1 -2
- package/src/live-voice/live-voice-session.ts +598 -323
- package/src/live-voice/progress-narration.ts +277 -0
- package/src/live-voice/protocol.ts +21 -1
- package/src/live-voice/windows-compiled-live-voice.ts +4 -0
- package/src/mcp/__tests__/effective-config.test.ts +238 -0
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +200 -0
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
- package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +95 -0
- package/src/mcp/client.ts +16 -11
- package/src/mcp/effective-config.ts +113 -0
- package/src/mcp/manager.ts +11 -6
- package/src/mcp/mcp-auth-orchestrator.ts +13 -22
- package/src/mcp/mcp-oauth-provider.ts +205 -240
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +166 -3
- package/src/monitoring/control.ts +1 -0
- package/src/monitoring/db-integrity-sample.ts +4 -5
- package/src/monitoring/plugin-auto-update.ts +128 -24
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/approval-card-data.ts +33 -0
- package/src/notifications/signal.ts +1 -0
- package/src/permissions/AGENTS.md +16 -0
- package/src/permissions/checker.test.ts +75 -122
- package/src/permissions/checker.ts +44 -560
- package/src/permissions/confirmation-guardian-request.test.ts +15 -11
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/prompter.ts +1 -5
- package/src/permissions/question-guardian-request.test.ts +14 -6
- package/src/permissions/question-guardian-request.ts +1 -2
- package/src/persistence/attachments-store.ts +8 -1
- package/src/persistence/bookmark-crud.ts +3 -7
- package/src/persistence/conversation-attention-store.ts +16 -45
- package/src/persistence/conversation-crud.ts +33 -4
- package/src/persistence/conversation-lineage.ts +9 -0
- package/src/persistence/conversation-queries.ts +182 -52
- package/src/persistence/delivery-crud.ts +150 -36
- package/src/persistence/embeddings/qdrant-manager.ts +84 -49
- package/src/persistence/external-conversation-store.ts +32 -4
- package/src/persistence/llm-request-log-store.ts +4 -10
- package/src/persistence/llm-usage-store.ts +8 -3
- package/src/persistence/message-reads.test.ts +197 -0
- package/src/persistence/message-reads.ts +211 -0
- package/src/persistence/migrations/360-add-document-workspace-path.ts +5 -14
- package/src/persistence/migrations/366-chatgpt-subscription-row-identity.test.ts +120 -0
- package/src/persistence/migrations/366-chatgpt-subscription-row-identity.ts +62 -0
- package/src/persistence/real-user-turn-filter.ts +27 -3
- package/src/persistence/schema/documents.ts +4 -4
- package/src/persistence/steps.ts +9 -0
- package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
- package/src/plugin-api/constants.ts +8 -0
- package/src/plugin-api/conversation-turn.ts +195 -5
- package/src/plugin-api/index.ts +38 -6
- package/src/plugin-api/resolve-credential.ts +3 -2
- package/src/plugin-api/store-credential.ts +146 -0
- package/src/plugin-api/vision-support.test.ts +1 -1
- package/src/plugin-api/webhook-url.ts +13 -11
- package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
- package/src/plugins/defaults/main.ts +21 -7
- package/src/plugins/defaults/memory/AGENTS.md +15 -3
- package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +204 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +72 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
- package/src/plugins/defaults/memory/buffer-format.ts +165 -0
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +77 -0
- package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +24 -6
- package/src/plugins/defaults/memory/graph/image-ref-utils.ts +3 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -30
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +34 -0
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +17 -24
- package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +53 -5
- package/src/plugins/defaults/memory/indexer.ts +3 -1
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +19 -7
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -4
- package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
- package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +147 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
- package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
- package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
- package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
- package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
- package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +195 -58
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +93 -24
- package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
- package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
- package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
- package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
- package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
- package/src/plugins/defaults/memory/substrate/static-context.ts +160 -33
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +2 -4
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +3 -1
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +18 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +66 -1
- package/src/plugins/defaults/memory/v3/card.ts +9 -9
- package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
- package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
- package/src/plugins/defaults/memory/v3/edge.ts +13 -57
- package/src/plugins/defaults/memory/v3/injector.ts +8 -0
- package/src/plugins/defaults/memory/v3/prune.ts +2 -0
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +23 -9
- package/src/plugins/defaults/memory/worker-control.ts +1 -0
- package/src/plugins/defaults/memory/worker.ts +6 -3
- package/src/plugins/defaults/worker-entrypoints.ts +3 -0
- package/src/plugins/external-plugin-loader.ts +47 -0
- package/src/plugins/mcp-servers.ts +361 -0
- package/src/plugins/mtime-cache.ts +37 -46
- package/src/plugins/pipeline.ts +14 -7
- package/src/plugins/plugin-execution-context.ts +35 -11
- package/src/plugins/worker-plugin-surface.ts +33 -0
- package/src/prompts/templates/system-sections.ts +0 -7
- package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
- package/src/providers/__tests__/context-overflow-error.test.ts +24 -0
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +214 -2
- package/src/providers/__tests__/preflight-resolved-config.test.ts +57 -0
- package/src/providers/__tests__/retry-callsite.test.ts +25 -2
- package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
- package/src/providers/anthropic/client.ts +332 -241
- package/src/providers/call-site-routing.ts +30 -3
- package/src/providers/connection-resolution.ts +194 -11
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +4 -0
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/inference/auth.ts +6 -0
- package/src/providers/inference/connection-availability.ts +24 -2
- package/src/providers/inference/connections.ts +2 -0
- package/src/providers/model-catalog.ts +3 -3
- package/src/providers/model-intents.ts +28 -8
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +163 -40
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
- package/src/providers/openai/chat-completions-provider.ts +133 -36
- package/src/providers/openai/codex-models.ts +2 -1
- package/src/providers/provider-send-message.ts +32 -3
- 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 +625 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +285 -6
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +679 -0
- package/src/providers/speech-to-text/provider-catalog.ts +99 -8
- package/src/providers/speech-to-text/resolve.ts +25 -2
- package/src/routes/control.ts +1 -0
- package/src/routes/route-host-client.ts +1 -0
- package/src/routes/route-host-protocol.ts +7 -0
- package/src/routes/worker.ts +48 -15
- package/src/runtime/AGENTS.md +16 -17
- package/src/runtime/access-request-helper.ts +9 -12
- package/src/runtime/agent-wake.ts +18 -15
- package/src/runtime/effective-capabilities.test.ts +43 -0
- package/src/runtime/effective-capabilities.ts +27 -0
- package/src/runtime/guardian-reply-router.ts +6 -2
- package/src/runtime/pre-first-message-gate.ts +4 -0
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +12 -4
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +522 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +52 -0
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +61 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +44 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +102 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +132 -35
- package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +215 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +133 -1
- package/src/runtime/routes/channel-availability-routes.ts +32 -14
- package/src/runtime/routes/channel-route-shared.ts +0 -6
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +6 -6
- package/src/runtime/routes/conversation-list-routes.ts +181 -23
- package/src/runtime/routes/conversation-management-routes.ts +17 -12
- package/src/runtime/routes/conversation-query-routes.ts +40 -27
- package/src/runtime/routes/conversation-routes.ts +43 -29
- package/src/runtime/routes/credential-prompt-routes.ts +4 -7
- package/src/runtime/routes/credential-routes.ts +26 -82
- package/src/runtime/routes/default-provider-routes.ts +15 -0
- package/src/runtime/routes/documents-routes.ts +3 -222
- package/src/runtime/routes/inbound-message-handler.ts +21 -45
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -9
- package/src/runtime/routes/inbound-stages/admission-policy.ts +1 -17
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -79
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -7
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -8
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -79
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +2 -3
- package/src/runtime/routes/inference-profiles-routes.ts +20 -11
- package/src/runtime/routes/inference-provider-connection-routes.ts +77 -15
- package/src/runtime/routes/log-export-routes.ts +3 -0
- package/src/runtime/routes/mcp-auth-routes.ts +148 -57
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +2 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +3 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -2
- package/src/runtime/routes/playground/reset-circuit.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +38 -8
- package/src/runtime/routes/schedule-routes.ts +94 -7
- package/src/runtime/routes/settings-routes.ts +6 -6
- package/src/runtime/routes/stt-routes.ts +31 -25
- package/src/runtime/routes/surface-action-routes.ts +20 -19
- package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
- package/src/runtime/routes/user-route-dispatcher.ts +69 -15
- package/src/runtime/routes/user-route-import.ts +108 -0
- package/src/runtime/routes/user-route-resolution.ts +18 -1
- package/src/runtime/routes/workspace-routes.ts +0 -9
- package/src/runtime/routes/workspace-utils.ts +3 -13
- package/src/runtime/services/conversation-serializer.ts +7 -2
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +68 -5
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +81 -0
- package/src/schedule/plugin-schedule-availability.ts +58 -0
- package/src/schedule/plugin-schedule-declarations.ts +23 -27
- package/src/schedule/plugin-schedule-reconciler.ts +12 -3
- package/src/schedule/schedule-store.ts +5 -1
- package/src/schedule/scheduler.ts +9 -4
- package/src/schedule/worker-control.ts +1 -0
- package/src/schedule/worker.ts +6 -0
- package/src/security/oauth2.ts +6 -22
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
- package/src/stt/__tests__/types.test.ts +94 -0
- package/src/stt/daemon-batch-transcriber.ts +10 -0
- package/src/stt/stt-stream-session.ts +8 -4
- package/src/stt/types.ts +103 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +26 -15
- package/src/subagent/consult-context.ts +11 -11
- package/src/subagent/consult-prompt.ts +26 -35
- package/src/subagent/manager.ts +21 -40
- package/src/subagent/notify.ts +7 -1
- package/src/subagent/types.ts +15 -12
- package/src/tools/__tests__/tool-input-schemas.test.ts +7 -7
- package/src/tools/acp/spawn.test.ts +97 -0
- package/src/tools/acp/spawn.ts +38 -4
- package/src/tools/credentials/ref-parse.ts +35 -0
- package/src/tools/credentials/resolve.ts +4 -10
- package/src/tools/credentials/store.ts +168 -0
- package/src/tools/document/document-tool.ts +12 -3
- package/src/tools/executor.ts +53 -15
- package/src/tools/filesystem/read.ts +27 -10
- package/src/tools/host-filesystem/read.ts +27 -15
- package/src/tools/network/url-safety.ts +9 -16
- package/src/tools/permission-checker.ts +43 -52
- package/src/tools/registry.ts +2 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +63 -35
- package/src/tools/shared/filesystem/legacy-read-args.ts +22 -0
- package/src/tools/shared/filesystem/types.ts +5 -5
- package/src/tools/skills/scaffold-managed.ts +25 -7
- package/src/tools/subagent/spawn.ts +28 -88
- package/src/tools/tool-types.ts +26 -13
- package/src/tools/types.ts +6 -6
- package/src/tools/ui-surface/surface-shape-docs.ts +12 -1
- package/src/tools/workflows/run-workflow.ts +1 -2
- package/src/tts/__tests__/reasoning-tag-filter.test.ts +78 -0
- package/src/tts/reasoning-tag-filter.ts +89 -0
- package/src/util/__tests__/worker-process-command.test.ts +37 -0
- package/src/util/logger.ts +16 -0
- package/src/util/think-tag-stream.ts +95 -0
- package/src/util/worker-process.ts +37 -4
- package/src/windows-compiled-cli.ts +32 -0
- package/src/windows-compiled-entry.ts +4 -0
- package/src/windows-compiled-logger.ts +6 -0
- package/src/windows-compiled-worker-entry.ts +29 -0
- package/src/workspace/byok-default-profile-ensure.ts +76 -24
- package/src/workspace/custom-profile-ensure.ts +4 -24
- package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
- package/src/workspace/migrations/143-repair-deprecated-codex-model-id.ts +134 -0
- package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +265 -0
- package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +328 -0
- package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +195 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +0 -10
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/provider-commit-message-generator.ts +7 -5
- package/src/__tests__/document-workspace-file.test.ts +0 -467
- package/src/live-voice/__tests__/front-decision.test.ts +0 -645
- package/src/live-voice/front-decision.ts +0 -476
- package/src/permissions/ipc-risk-types.ts +0 -143
- package/src/permissions/risk-types.ts +0 -76
- package/src/subagent/__tests__/consult-transcript.test.ts +0 -184
- package/src/subagent/consult-transcript.ts +0 -90
|
@@ -45,9 +45,29 @@ mock.module("../../notifications/emit-signal.js", () => ({
|
|
|
45
45
|
},
|
|
46
46
|
}));
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Plugin directories the daemon has not activated. The reconciler arms only
|
|
50
|
+
* plugins this process brought up, and no test here runs the plugin loader, so
|
|
51
|
+
* the double answers "activated" unless a case says otherwise.
|
|
52
|
+
*/
|
|
53
|
+
const notActivatedDirs = new Set<string>();
|
|
54
|
+
|
|
55
|
+
/** Every directory the reconciler put through the activation predicate. */
|
|
56
|
+
const activationProbes: string[] = [];
|
|
57
|
+
|
|
58
|
+
const realMtimeCache = await import("../../plugins/mtime-cache.js");
|
|
59
|
+
mock.module("../../plugins/mtime-cache.js", () => ({
|
|
60
|
+
...realMtimeCache,
|
|
61
|
+
isPluginDirActivated: (dir: string) => {
|
|
62
|
+
activationProbes.push(dir);
|
|
63
|
+
return !notActivatedDirs.has(dir);
|
|
64
|
+
},
|
|
65
|
+
}));
|
|
66
|
+
|
|
48
67
|
import { setOverridesForTesting } from "../../__tests__/feature-flag-test-helpers.js";
|
|
49
68
|
import { getDb } from "../../persistence/db-connection.js";
|
|
50
69
|
import { initializeDb } from "../../persistence/db-init.js";
|
|
70
|
+
import { listInstalledPluginDirs } from "../../plugins/installed-plugin-dirs.js";
|
|
51
71
|
import { getWorkspacePluginsDir } from "../../util/platform.js";
|
|
52
72
|
import {
|
|
53
73
|
reconcilePluginSchedules,
|
|
@@ -175,6 +195,8 @@ function resetReconcilerFixtures(): void {
|
|
|
175
195
|
emittedSignals.length = 0;
|
|
176
196
|
emitResultOverride = null;
|
|
177
197
|
emitGate = null;
|
|
198
|
+
notActivatedDirs.clear();
|
|
199
|
+
activationProbes.length = 0;
|
|
178
200
|
resetDefinitionErrorEmitGuardForTests();
|
|
179
201
|
}
|
|
180
202
|
|
|
@@ -970,6 +992,65 @@ describe("reconcilePluginSchedules", () => {
|
|
|
970
992
|
expect(payload.reason).toContain("no upcoming occurrences");
|
|
971
993
|
});
|
|
972
994
|
|
|
995
|
+
test("a plugin the daemon never activated arms nothing", async () => {
|
|
996
|
+
// Everything the parser needs is on disk; only the activation is missing,
|
|
997
|
+
// which is what a directory dropped into the plugins root looks like.
|
|
998
|
+
const dir = writePlugin("news", digest());
|
|
999
|
+
notActivatedDirs.add(dir);
|
|
1000
|
+
|
|
1001
|
+
await reconcilePluginSchedules();
|
|
1002
|
+
|
|
1003
|
+
expect(listDeclaredSchedules()).toHaveLength(0);
|
|
1004
|
+
expect(emittedSignals).toHaveLength(0);
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
test("a row disarms once its plugin is no longer activated", async () => {
|
|
1008
|
+
const dir = writePlugin("news", digest());
|
|
1009
|
+
await reconcilePluginSchedules();
|
|
1010
|
+
const created = listDeclaredSchedules()[0]!;
|
|
1011
|
+
expect(created.enabled).toBe(true);
|
|
1012
|
+
|
|
1013
|
+
notActivatedDirs.add(dir);
|
|
1014
|
+
await reconcilePluginSchedules();
|
|
1015
|
+
|
|
1016
|
+
const row = listDeclaredSchedules()[0]!;
|
|
1017
|
+
expect(row.id).toBe(created.id);
|
|
1018
|
+
expect(row.enabled).toBe(false);
|
|
1019
|
+
});
|
|
1020
|
+
|
|
1021
|
+
test("a plugin activated between passes arms on the second one", async () => {
|
|
1022
|
+
const dir = writePlugin("news", digest());
|
|
1023
|
+
notActivatedDirs.add(dir);
|
|
1024
|
+
await reconcilePluginSchedules();
|
|
1025
|
+
expect(listDeclaredSchedules()).toHaveLength(0);
|
|
1026
|
+
|
|
1027
|
+
notActivatedDirs.delete(dir);
|
|
1028
|
+
await reconcilePluginSchedules();
|
|
1029
|
+
|
|
1030
|
+
const rows = listDeclaredSchedules();
|
|
1031
|
+
expect(rows).toHaveLength(1);
|
|
1032
|
+
expect(rows[0]!.sourceKey).toBe(DIGEST_KEY);
|
|
1033
|
+
expect(rows[0]!.enabled).toBe(true);
|
|
1034
|
+
// The row arms for the first time here, so it announces its arrival.
|
|
1035
|
+
const declared = emittedSignals.filter(
|
|
1036
|
+
(s) => s.sourceEventName === "schedule.declared",
|
|
1037
|
+
);
|
|
1038
|
+
expect(declared).toHaveLength(1);
|
|
1039
|
+
expect(declared[0]!.sourceContextId).toBe(DIGEST_KEY);
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
test("the activation probe sees the directory string the walk yields", async () => {
|
|
1043
|
+
// The predicate is keyed by directory path, so the enumeration the
|
|
1044
|
+
// reconciler walks and the map the daemon activates into have to agree on
|
|
1045
|
+
// the exact string. Both come from `listInstalledPluginDirs`.
|
|
1046
|
+
const dir = writePlugin("news", digest());
|
|
1047
|
+
|
|
1048
|
+
await reconcilePluginSchedules();
|
|
1049
|
+
|
|
1050
|
+
expect(listInstalledPluginDirs().map((p) => p.dir)).toEqual([dir]);
|
|
1051
|
+
expect(activationProbes).toEqual([dir]);
|
|
1052
|
+
});
|
|
1053
|
+
|
|
973
1054
|
test("a suppressed error emit still latches the day guard", async () => {
|
|
974
1055
|
writePlugin("news", brokenDigest());
|
|
975
1056
|
emitResultOverride = {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Availability probe for a plugin-declared schedule's source.
|
|
3
|
+
*
|
|
4
|
+
* Composes the daemon's activation state with the on-disk declaration probe:
|
|
5
|
+
* did this process bring the plugin up, and is its declaration still
|
|
6
|
+
* sourceable.
|
|
7
|
+
*
|
|
8
|
+
* **This probe is only meaningful in the main daemon process.** Activation is
|
|
9
|
+
* tracked in an in-memory map that `bringUpPlugin` writes, so only the process
|
|
10
|
+
* that ran the plugin loader can answer for it. HTTP routes and the plugin
|
|
11
|
+
* schedule reconciler run there, so they may use this. Worker processes (the
|
|
12
|
+
* schedule worker in `schedule/worker.ts`, sidecar turn workers) activate no
|
|
13
|
+
* plugins, so their ledger is empty and every plugin would read as
|
|
14
|
+
* unactivated. Those paths call {@link declarationExistsOnDisk} directly.
|
|
15
|
+
*
|
|
16
|
+
* That split is safe because the reconciler owns arming and runs in the
|
|
17
|
+
* daemon: a plugin it has not activated never arms, and its sweep disarms the
|
|
18
|
+
* rows of a plugin that stops being activated within one pass. The window
|
|
19
|
+
* between those passes is the whole exposure of the worker-side disk-only
|
|
20
|
+
* probes.
|
|
21
|
+
*
|
|
22
|
+
* The composition lives here rather than in `./plugin-schedule-declarations.ts`
|
|
23
|
+
* because that parser is reachable from the plugin loader's own static graph
|
|
24
|
+
* and must stay free of daemon runtime state. `plugins/mtime-cache.ts` reaches
|
|
25
|
+
* the schedule side only through a dynamic import, so importing it here does
|
|
26
|
+
* not close a static cycle.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { join } from "node:path";
|
|
30
|
+
|
|
31
|
+
import { isPluginDirActivated } from "../plugins/mtime-cache.js";
|
|
32
|
+
import { getWorkspacePluginsDir } from "../util/platform.js";
|
|
33
|
+
import { declarationExistsOnDisk } from "./plugin-schedule-declarations.js";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* True when the schedule behind `sourceKey`
|
|
37
|
+
* (`plugin:<pluginName>/<scheduleName>`) may run: the daemon activated the
|
|
38
|
+
* plugin, and {@link declarationExistsOnDisk} still finds the declaration.
|
|
39
|
+
*
|
|
40
|
+
* The activation half is what keeps a plugin directory dropped into the
|
|
41
|
+
* plugins root out of the scheduler. Such a directory has files the disk probe
|
|
42
|
+
* accepts, but no `init` has run for it, so its hooks and tools are not live
|
|
43
|
+
* and its schedules must not be either.
|
|
44
|
+
*/
|
|
45
|
+
export async function pluginScheduleSourceAvailable(
|
|
46
|
+
sourceKey: string,
|
|
47
|
+
): Promise<boolean> {
|
|
48
|
+
const match = /^plugin:([^/]+)\/(.+)$/.exec(sourceKey);
|
|
49
|
+
if (!match) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const [, pluginName] = match;
|
|
53
|
+
const pluginDir = join(getWorkspacePluginsDir(), pluginName!);
|
|
54
|
+
return (
|
|
55
|
+
isPluginDirActivated(pluginDir) &&
|
|
56
|
+
(await declarationExistsOnDisk(sourceKey))
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -30,7 +30,6 @@ import { z } from "zod";
|
|
|
30
30
|
import { isPluginDisabled } from "../plugins/disabled-state.js";
|
|
31
31
|
import { parsePluginManifest } from "../plugins/external-plugin-loader.js";
|
|
32
32
|
import { isInsidePluginRoot } from "../plugins/installed-plugin-dirs.js";
|
|
33
|
-
import { walkPluginTree } from "../plugins/plugin-tree-walk.js";
|
|
34
33
|
import { FRONTMATTER_REGEX } from "../skills/frontmatter.js";
|
|
35
34
|
import { getWorkspacePluginsDir } from "../util/platform.js";
|
|
36
35
|
import {
|
|
@@ -77,9 +76,13 @@ export interface ScheduleDeclaration {
|
|
|
77
76
|
scriptInvocation: string | null;
|
|
78
77
|
config: PluginScheduleConfig;
|
|
79
78
|
/**
|
|
80
|
-
* Stable sha256 over the declaration's
|
|
81
|
-
*
|
|
82
|
-
* declaration
|
|
79
|
+
* Stable sha256 over the declaration's `config.json` and its entrypoint,
|
|
80
|
+
* each hashed together with its path relative to `schedules/`. Nothing else
|
|
81
|
+
* under the declaration directory takes part. Helper scripts, and any state
|
|
82
|
+
* a script writes beside itself, do not change the stored row definition, so
|
|
83
|
+
* hashing them would report a definition change every time a stateful
|
|
84
|
+
* schedule runs. Scripts execute by path, so an edit to a helper takes
|
|
85
|
+
* effect without a definition change.
|
|
83
86
|
*/
|
|
84
87
|
definitionHash: string;
|
|
85
88
|
}
|
|
@@ -292,21 +295,6 @@ function hashDeclarationFiles(files: DeclarationFile[]): string {
|
|
|
292
295
|
return hash.digest("hex");
|
|
293
296
|
}
|
|
294
297
|
|
|
295
|
-
/**
|
|
296
|
-
* Collect every regular file under `dir` (recursively, dot entries and
|
|
297
|
-
* symlinks skipped) with paths relative to the schedules/ root.
|
|
298
|
-
*/
|
|
299
|
-
function collectDeclarationFiles(
|
|
300
|
-
dir: string,
|
|
301
|
-
relPrefix: string,
|
|
302
|
-
): DeclarationFile[] {
|
|
303
|
-
const files: DeclarationFile[] = [];
|
|
304
|
-
walkPluginTree(dir, { excludeDotEntries: true }, (rel, abs) => {
|
|
305
|
-
files.push({ relPath: `${relPrefix}${rel}`, content: readFileSync(abs) });
|
|
306
|
-
});
|
|
307
|
-
return files;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
298
|
function shellQuote(value: string): string {
|
|
311
299
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
312
300
|
}
|
|
@@ -395,25 +383,24 @@ function parseDirectoryDeclaration(
|
|
|
395
383
|
let message: string | null = null;
|
|
396
384
|
let scriptInvocation: string | null = null;
|
|
397
385
|
let mode: PluginScheduleMode;
|
|
386
|
+
let entrypointText: string;
|
|
398
387
|
if (entrypoint === "index.md") {
|
|
399
|
-
|
|
400
|
-
if (FRONTMATTER_REGEX.test(
|
|
388
|
+
entrypointText = readFileSync(join(dirPath, "index.md"), "utf8");
|
|
389
|
+
if (FRONTMATTER_REGEX.test(entrypointText)) {
|
|
401
390
|
return {
|
|
402
391
|
error:
|
|
403
392
|
"index.md must not contain frontmatter: directory-form config belongs in config.json",
|
|
404
393
|
};
|
|
405
394
|
}
|
|
406
|
-
message =
|
|
395
|
+
message = entrypointText.trim();
|
|
407
396
|
if (!message) {
|
|
408
397
|
return { error: "prompt body is empty" };
|
|
409
398
|
}
|
|
410
399
|
mode = "execute";
|
|
411
400
|
} else {
|
|
412
401
|
const scriptPath = join(dirPath, "index.sh");
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
readFileSync(scriptPath, "utf8"),
|
|
416
|
-
);
|
|
402
|
+
entrypointText = readFileSync(scriptPath, "utf8");
|
|
403
|
+
scriptInvocation = buildScriptInvocation(scriptPath, entrypointText);
|
|
417
404
|
mode = "script";
|
|
418
405
|
}
|
|
419
406
|
|
|
@@ -422,7 +409,16 @@ function parseDirectoryDeclaration(
|
|
|
422
409
|
message,
|
|
423
410
|
scriptInvocation,
|
|
424
411
|
config: configResult.config,
|
|
425
|
-
files:
|
|
412
|
+
files: [
|
|
413
|
+
{
|
|
414
|
+
relPath: `${dirName}/config.json`,
|
|
415
|
+
content: Buffer.from(rawConfigText),
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
relPath: `${dirName}/${entrypoint}`,
|
|
419
|
+
content: Buffer.from(entrypointText),
|
|
420
|
+
},
|
|
421
|
+
],
|
|
426
422
|
};
|
|
427
423
|
}
|
|
428
424
|
|
|
@@ -33,6 +33,7 @@ import type { AttentionHints } from "../notifications/signal.js";
|
|
|
33
33
|
import { isPluginDisabled } from "../plugins/disabled-state.js";
|
|
34
34
|
import { parsePluginManifest } from "../plugins/external-plugin-loader.js";
|
|
35
35
|
import { listInstalledPluginDirs } from "../plugins/installed-plugin-dirs.js";
|
|
36
|
+
import { isPluginDirActivated } from "../plugins/mtime-cache.js";
|
|
36
37
|
import { getLogger } from "../util/logger.js";
|
|
37
38
|
import {
|
|
38
39
|
type DeclarationError,
|
|
@@ -264,9 +265,14 @@ function isCompletedRecurrence(
|
|
|
264
265
|
* as the plugin source collector) and gather their schedule declarations.
|
|
265
266
|
* Identity = the directory basename, mirroring `parsePluginManifest`.
|
|
266
267
|
*
|
|
267
|
-
* Disabled plugins
|
|
268
|
-
*
|
|
269
|
-
*
|
|
268
|
+
* Disabled plugins, plugins this daemon has not activated
|
|
269
|
+
* ({@link isPluginDirActivated}), and plugins without a `schedules/` directory
|
|
270
|
+
* are skipped entirely; in particular, only schedule-declaring plugins pay the
|
|
271
|
+
* manifest parse each pass. The activation gate is what keeps a directory
|
|
272
|
+
* dropped into the plugins root out of the desired set: nothing has run its
|
|
273
|
+
* `init`, so its hooks and tools are not live and its schedules must not arm
|
|
274
|
+
* either. It joins the set on the pass after the boot scan or an imperative
|
|
275
|
+
* reconcile brings it up. A schedule-declaring plugin whose manifest fails
|
|
270
276
|
* `parsePluginManifest` (unreadable or schema-invalid `package.json`) also
|
|
271
277
|
* contributes nothing to the desired set: the runtime loader refuses to
|
|
272
278
|
* bring such a plugin up, so its schedules must not stay armed either. Each
|
|
@@ -282,6 +288,9 @@ async function collectDesiredDeclarations(): Promise<CollectedDeclarations> {
|
|
|
282
288
|
if (isPluginDisabled(name)) {
|
|
283
289
|
continue;
|
|
284
290
|
}
|
|
291
|
+
if (!isPluginDirActivated(dir)) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
285
294
|
if (!existsSync(join(dir, "schedules"))) {
|
|
286
295
|
continue;
|
|
287
296
|
}
|
|
@@ -840,7 +840,7 @@ export function listDeclaredSchedules(): ScheduleJob[] {
|
|
|
840
840
|
* a null `lastRunAt` is a declared schedule inserted disabled, not an engine
|
|
841
841
|
* latch, and stays re-armable.
|
|
842
842
|
*/
|
|
843
|
-
function isEngineLatched(row: {
|
|
843
|
+
export function isEngineLatched(row: {
|
|
844
844
|
status: string;
|
|
845
845
|
nextRunAt: number;
|
|
846
846
|
lastRunAt: number | null;
|
|
@@ -1051,6 +1051,10 @@ export async function setUserEnabled(
|
|
|
1051
1051
|
// again. The reconciler is the authority on the declaration set; this
|
|
1052
1052
|
// probe only closes that fire-before-next-sweep window. The override
|
|
1053
1053
|
// itself is still recorded, so it applies if the declaration returns.
|
|
1054
|
+
// The probe is deliberately disk-only. A schedule tool calls this from a
|
|
1055
|
+
// conversation turn, which can run in a sidecar worker process where the
|
|
1056
|
+
// daemon's activation ledger is empty, so consulting activation here would
|
|
1057
|
+
// refuse to re-arm anything. Activation stays the reconciler's call.
|
|
1054
1058
|
if (value && !(await declarationExistsOnDisk(existing.sourceKey))) {
|
|
1055
1059
|
logger.info(
|
|
1056
1060
|
{ scheduleId: id, sourceKey: existing.sourceKey },
|
|
@@ -529,10 +529,15 @@ export async function runDueSchedulesOnce(
|
|
|
529
529
|
|
|
530
530
|
// Fire-time gate for plugin-sourced rows, covering every way the source
|
|
531
531
|
// can go away under an armed row. `declarationExistsOnDisk` is the probe
|
|
532
|
-
// the
|
|
533
|
-
//
|
|
534
|
-
//
|
|
535
|
-
//
|
|
532
|
+
// the enable path uses, and it answers for all of them: a `.disabled`
|
|
533
|
+
// sentinel, a plugin directory a local uninstall removed, a manifest that
|
|
534
|
+
// no longer parses, and a declaration that is simply gone. Turning the
|
|
535
|
+
// feature flag off retires the whole surface.
|
|
536
|
+
// The probe is deliberately disk-only. Schedule execution runs in the
|
|
537
|
+
// schedule worker process, which activates no plugins, so the daemon's
|
|
538
|
+
// in-memory activation ledger is empty here and reading it would skip
|
|
539
|
+
// every plugin schedule. Activation is gated where the daemon owns it: the
|
|
540
|
+
// reconciler decides what arms, and the run-now route refuses by hand.
|
|
536
541
|
// The reconciler is what disarms the rows any of these own, and it runs
|
|
537
542
|
// on its own schedule, so re-reading here is what makes the change take
|
|
538
543
|
// effect immediately: a row still armed (or already claimed) at that
|
|
@@ -96,6 +96,7 @@ async function spawnScheduleWorkerProcessUncoalesced(
|
|
|
96
96
|
return await spawnWorkerProcess({
|
|
97
97
|
pidPath: getScheduleWorkerPidPath(),
|
|
98
98
|
entry: new URL("./worker.ts", import.meta.url),
|
|
99
|
+
packagedEntry: "schedule",
|
|
99
100
|
workerLabel: "Schedule worker",
|
|
100
101
|
options: opts,
|
|
101
102
|
});
|
package/src/schedule/worker.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { writeFileSync } from "node:fs";
|
|
|
16
16
|
import { getConfig } from "../config/loader.js";
|
|
17
17
|
import { rehydratePlatformCredentials } from "../config/platform-rehydration.js";
|
|
18
18
|
import { resetDb } from "../persistence/db-connection.js";
|
|
19
|
+
import { registerWorkerPluginSurface } from "../plugins/worker-plugin-surface.js";
|
|
19
20
|
import { disableStreamSeqStamping } from "../runtime/assistant-stream-state.js";
|
|
20
21
|
import { initializeTools } from "../tools/registry.js";
|
|
21
22
|
import { getLogger } from "../util/logger.js";
|
|
@@ -51,6 +52,11 @@ async function main(): Promise<void> {
|
|
|
51
52
|
// rejected for both inference and background-wake requests.
|
|
52
53
|
await rehydratePlatformCredentials();
|
|
53
54
|
|
|
55
|
+
// This process is the sole runner of schedule execution and hosts real agent
|
|
56
|
+
// conversations (wake, execute, and workflow modes), so it needs the default
|
|
57
|
+
// plugins' hooks and injectors just like the daemon.
|
|
58
|
+
registerWorkerPluginSurface();
|
|
59
|
+
|
|
54
60
|
// Populate the tool registry (core built-ins + workspace tools). The daemon
|
|
55
61
|
// does this at startup; this standalone process has to do it itself so
|
|
56
62
|
// workflow schedules pass the core-tools readiness gate and agent-executed
|
package/src/security/oauth2.ts
CHANGED
|
@@ -273,20 +273,12 @@ async function runGatewayFlow(
|
|
|
273
273
|
): Promise<OAuth2FlowResult> {
|
|
274
274
|
// Dynamic imports required here to avoid circular dependencies with
|
|
275
275
|
// config/loader → security → oauth2 module chains.
|
|
276
|
-
const {
|
|
277
|
-
|
|
278
|
-
await import("../inbound/public-ingress-urls.js");
|
|
279
|
-
const { resolveCallbackUrl } =
|
|
280
|
-
await import("../inbound/platform-callback-registration.js");
|
|
276
|
+
const { resolveOauthCallbackUrl } =
|
|
277
|
+
await import("../inbound/oauth-callback-url.js");
|
|
281
278
|
const { registerPendingCallback } =
|
|
282
279
|
await import("./oauth-callback-registry.js");
|
|
283
280
|
|
|
284
|
-
const
|
|
285
|
-
const redirectUri = await resolveCallbackUrl(
|
|
286
|
-
() => getOAuthCallbackUrl(appConfig),
|
|
287
|
-
"webhooks/oauth/callback",
|
|
288
|
-
"oauth",
|
|
289
|
-
);
|
|
281
|
+
const redirectUri = await resolveOauthCallbackUrl();
|
|
290
282
|
|
|
291
283
|
const codePromise = new Promise<string>((resolve, reject) => {
|
|
292
284
|
registerPendingCallback(state, resolve, reject);
|
|
@@ -556,20 +548,12 @@ export async function prepareOAuth2Flow(
|
|
|
556
548
|
|
|
557
549
|
// Dynamic imports required here to avoid circular dependencies with
|
|
558
550
|
// config/loader → security → oauth2 module chains.
|
|
559
|
-
const {
|
|
560
|
-
|
|
561
|
-
await import("../inbound/public-ingress-urls.js");
|
|
562
|
-
const { resolveCallbackUrl } =
|
|
563
|
-
await import("../inbound/platform-callback-registration.js");
|
|
551
|
+
const { resolveOauthCallbackUrl } =
|
|
552
|
+
await import("../inbound/oauth-callback-url.js");
|
|
564
553
|
const { registerPendingCallback } =
|
|
565
554
|
await import("./oauth-callback-registry.js");
|
|
566
555
|
|
|
567
|
-
const
|
|
568
|
-
const redirectUri = await resolveCallbackUrl(
|
|
569
|
-
() => getOAuthCallbackUrl(appConfig),
|
|
570
|
-
"webhooks/oauth/callback",
|
|
571
|
-
"oauth",
|
|
572
|
-
);
|
|
556
|
+
const redirectUri = await resolveOauthCallbackUrl();
|
|
573
557
|
|
|
574
558
|
const codeVerifier = generateCodeVerifier();
|
|
575
559
|
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
+
import { batchBoundaryGapReason } from "../../providers/speech-to-text/provider-catalog.js";
|
|
3
4
|
import { SttError } from "../types.js";
|
|
4
5
|
|
|
5
6
|
// ---------------------------------------------------------------------------
|
|
@@ -620,3 +621,24 @@ describe("vellum factory case", () => {
|
|
|
620
621
|
expect(createDaemonBatchTranscriber(null, "deepgram")).toBeNull();
|
|
621
622
|
});
|
|
622
623
|
});
|
|
624
|
+
|
|
625
|
+
describe("deepgram-flux factory case", () => {
|
|
626
|
+
// The copy itself is pinned in provider-catalog.test.ts; what matters here
|
|
627
|
+
// is that the factory speaks with the catalog's voice rather than its own.
|
|
628
|
+
test("throws the catalog's streaming-only reason", () => {
|
|
629
|
+
expect(() =>
|
|
630
|
+
createDaemonBatchTranscriber("dg-test-key", "deepgram-flux"),
|
|
631
|
+
).toThrow(batchBoundaryGapReason("deepgram-flux"));
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
test("marks the error user-facing so friendly copy does not overwrite it", () => {
|
|
635
|
+
try {
|
|
636
|
+
createDaemonBatchTranscriber("dg-test-key", "deepgram-flux");
|
|
637
|
+
throw new Error("expected the factory to throw");
|
|
638
|
+
} catch (err) {
|
|
639
|
+
expect(err).toBeInstanceOf(SttError);
|
|
640
|
+
expect((err as SttError).category).toBe("provider-error");
|
|
641
|
+
expect((err as SttError).userFacing).toBe(true);
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
});
|
|
@@ -2,10 +2,14 @@ import { describe, expect, test } from "bun:test";
|
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
4
|
SttStreamServerClosedEvent,
|
|
5
|
+
SttStreamServerEagerTurnEndEvent,
|
|
5
6
|
SttStreamServerErrorEvent,
|
|
6
7
|
SttStreamServerEvent,
|
|
7
8
|
SttStreamServerFinalEvent,
|
|
8
9
|
SttStreamServerPartialEvent,
|
|
10
|
+
SttStreamServerTurnEndEvent,
|
|
11
|
+
SttStreamServerTurnResumedEvent,
|
|
12
|
+
SttStreamServerTurnStartEvent,
|
|
9
13
|
} from "../types.js";
|
|
10
14
|
|
|
11
15
|
// ---------------------------------------------------------------------------
|
|
@@ -87,3 +91,93 @@ describe("SttStreamServerEvent types", () => {
|
|
|
87
91
|
expect(_label).toBeUndefined();
|
|
88
92
|
});
|
|
89
93
|
});
|
|
94
|
+
|
|
95
|
+
describe("turn-detection server events", () => {
|
|
96
|
+
test("turn-start event compiles and round-trips", () => {
|
|
97
|
+
const event: SttStreamServerTurnStartEvent = { type: "turn-start" };
|
|
98
|
+
const asUnion: SttStreamServerEvent = event;
|
|
99
|
+
expect(asUnion.type).toBe("turn-start");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("eager-turn-end event carries the speculated transcript", () => {
|
|
103
|
+
const event: SttStreamServerEagerTurnEndEvent = {
|
|
104
|
+
type: "eager-turn-end",
|
|
105
|
+
text: "is this the end",
|
|
106
|
+
};
|
|
107
|
+
const asUnion: SttStreamServerEvent = event;
|
|
108
|
+
expect(asUnion.type).toBe("eager-turn-end");
|
|
109
|
+
expect(event.text).toBe("is this the end");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("turn-resumed event compiles and round-trips", () => {
|
|
113
|
+
const event: SttStreamServerTurnResumedEvent = { type: "turn-resumed" };
|
|
114
|
+
const asUnion: SttStreamServerEvent = event;
|
|
115
|
+
expect(asUnion.type).toBe("turn-resumed");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("turn-end event carries the committed transcript and optional confidence", () => {
|
|
119
|
+
const withoutConfidence: SttStreamServerTurnEndEvent = {
|
|
120
|
+
type: "turn-end",
|
|
121
|
+
text: "done speaking",
|
|
122
|
+
};
|
|
123
|
+
expect(withoutConfidence.confidence).toBeUndefined();
|
|
124
|
+
|
|
125
|
+
const event: SttStreamServerTurnEndEvent = {
|
|
126
|
+
type: "turn-end",
|
|
127
|
+
text: "done speaking",
|
|
128
|
+
confidence: 0.82,
|
|
129
|
+
};
|
|
130
|
+
const asUnion: SttStreamServerEvent = event;
|
|
131
|
+
expect(asUnion.type).toBe("turn-end");
|
|
132
|
+
expect(event.text).toBe("done speaking");
|
|
133
|
+
expect(event.confidence).toBe(0.82);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("a consumer switch over every variant is exhaustive", () => {
|
|
137
|
+
// Fails to compile if a variant is added to SttStreamServerEvent
|
|
138
|
+
// without a case here, which is what forces consumers to be revisited.
|
|
139
|
+
const label = (event: SttStreamServerEvent): string => {
|
|
140
|
+
switch (event.type) {
|
|
141
|
+
case "partial":
|
|
142
|
+
case "final":
|
|
143
|
+
case "finalized":
|
|
144
|
+
case "error":
|
|
145
|
+
case "closed":
|
|
146
|
+
return "transcript";
|
|
147
|
+
case "turn-start":
|
|
148
|
+
case "eager-turn-end":
|
|
149
|
+
case "turn-resumed":
|
|
150
|
+
case "turn-end":
|
|
151
|
+
return "turn";
|
|
152
|
+
default: {
|
|
153
|
+
const _exhaustive: never = event;
|
|
154
|
+
return _exhaustive;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const events: SttStreamServerEvent[] = [
|
|
160
|
+
{ type: "partial", text: "a" },
|
|
161
|
+
{ type: "final", text: "a" },
|
|
162
|
+
{ type: "finalized" },
|
|
163
|
+
{ type: "error", category: "provider-error", message: "boom" },
|
|
164
|
+
{ type: "closed" },
|
|
165
|
+
{ type: "turn-start" },
|
|
166
|
+
{ type: "eager-turn-end", text: "a" },
|
|
167
|
+
{ type: "turn-resumed" },
|
|
168
|
+
{ type: "turn-end", text: "a" },
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
expect(events.map(label)).toEqual([
|
|
172
|
+
"transcript",
|
|
173
|
+
"transcript",
|
|
174
|
+
"transcript",
|
|
175
|
+
"transcript",
|
|
176
|
+
"transcript",
|
|
177
|
+
"turn",
|
|
178
|
+
"turn",
|
|
179
|
+
"turn",
|
|
180
|
+
"turn",
|
|
181
|
+
]);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* - xAI (`xai`)
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
import { batchBoundaryGapReason } from "../providers/speech-to-text/provider-catalog.js";
|
|
16
17
|
import type {
|
|
17
18
|
BatchTranscriber,
|
|
18
19
|
SttProviderId,
|
|
@@ -245,6 +246,9 @@ class VellumManagedBatchTranscriber implements BatchTranscriber {
|
|
|
245
246
|
* language code), and the vellum managed path, whose platform proxy passes
|
|
246
247
|
* it to Deepgram server-side. Whisper and Gemini auto-detect natively and
|
|
247
248
|
* take no language parameter, so it is silently ignored for them.
|
|
249
|
+
*
|
|
250
|
+
* Throws an {@link SttError} for a provider with no batch endpoint at all,
|
|
251
|
+
* which no key can fix and `null` would understate.
|
|
248
252
|
*/
|
|
249
253
|
export function createDaemonBatchTranscriber(
|
|
250
254
|
apiKey: string | null | undefined,
|
|
@@ -268,6 +272,12 @@ export function createDaemonBatchTranscriber(
|
|
|
268
272
|
return new GoogleGeminiBatchTranscriber(apiKey);
|
|
269
273
|
case "xai":
|
|
270
274
|
return new XAIBatchTranscriber(apiKey, language);
|
|
275
|
+
case "deepgram-flux":
|
|
276
|
+
// Same copy the resolver raises, so a direct factory caller and a
|
|
277
|
+
// config-driven one report the mismatch identically.
|
|
278
|
+
throw new SttError("provider-error", batchBoundaryGapReason(providerId), {
|
|
279
|
+
userFacing: true,
|
|
280
|
+
});
|
|
271
281
|
default: {
|
|
272
282
|
// Exhaustive check — compile error if a new SttProviderId is added
|
|
273
283
|
// without a corresponding case here.
|
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
* a client WebSocket connection and a provider-specific streaming adapter.
|
|
6
6
|
* The orchestrator accepts client events (`audio`, `stop`), routes audio
|
|
7
7
|
* frames to the resolved {@link StreamingTranscriber}, and emits normalized
|
|
8
|
-
* server events
|
|
9
|
-
*
|
|
8
|
+
* server events back over the same WebSocket connection with per-session
|
|
9
|
+
* ordering guarantees: transcripts (`partial`, `final`, `finalized`),
|
|
10
|
+
* turn boundaries from providers that detect them (`turn-start`,
|
|
11
|
+
* `eager-turn-end`, `turn-resumed`, `turn-end`), and termination
|
|
12
|
+
* (`error`, `closed`).
|
|
10
13
|
*
|
|
11
14
|
* Session lifecycle:
|
|
12
15
|
* 1. Client opens a WebSocket to `/v1/stt/stream` with required `mimeType`
|
|
@@ -17,8 +20,9 @@
|
|
|
17
20
|
* `resolveStreamingTranscriber()` and starts the provider session.
|
|
18
21
|
* 3. The client sends `audio` frames (binary or base64-encoded JSON) and
|
|
19
22
|
* a `stop` event when recording is complete.
|
|
20
|
-
* 4. The provider emits
|
|
21
|
-
* orchestrator forwards to the client as
|
|
23
|
+
* 4. The provider emits transcript events, plus turn-boundary events when it
|
|
24
|
+
* detects turns, and the orchestrator forwards each to the client as a
|
|
25
|
+
* JSON frame.
|
|
22
26
|
* 5. The session closes deterministically on client disconnect, `stop`
|
|
23
27
|
* event, idle timeout, or runtime shutdown.
|
|
24
28
|
*
|