@vellumai/assistant 0.11.3 → 0.11.4-staging.2
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 +11 -6
- package/docs/architecture/memory.md +11 -0
- package/docs/architecture/turn-actor.md +70 -0
- package/docs/flux-turn-detection-spike.md +243 -0
- package/docs/stt-provider-onboarding.md +3 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/openapi.yaml +139 -37
- package/package.json +1 -1
- package/scripts/voice-ttft-spike.ts +3 -3
- package/src/__tests__/app-compiler.test.ts +38 -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__/config-loader-backfill.test.ts +3 -3
- package/src/__tests__/config-schema.test.ts +25 -10
- 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 +28 -20
- package/src/__tests__/conversation-attention-store.test.ts +63 -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-notifiers-provenance.test.ts +59 -0
- package/src/__tests__/conversation-queue.test.ts +177 -4
- package/src/__tests__/conversation-runtime-assembly.test.ts +134 -102
- package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
- package/src/__tests__/credential-prompt-route.test.ts +7 -10
- package/src/__tests__/custom-profile-ensure.test.ts +5 -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__/edit-propagation.test.ts +0 -7
- package/src/__tests__/helpers/mock-actor-context.ts +49 -0
- package/src/__tests__/helpers/mock-conversation.ts +13 -1
- package/src/__tests__/injector-chain.test.ts +63 -41
- package/src/__tests__/injector-disk-pressure.test.ts +11 -23
- package/src/__tests__/llm-context-resolution.test.ts +73 -1
- package/src/__tests__/llm-schema.test.ts +5 -2
- package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +6 -5
- package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
- package/src/__tests__/mtime-cache.test.ts +1 -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__/plugin-import-boundary-guard.test.ts +5 -0
- 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__/run-conversation-turn-persistence.test.ts +434 -105
- package/src/__tests__/scoped-approval-grants.test.ts +11 -6
- package/src/__tests__/secret-ingress-channel.test.ts +0 -1
- package/src/__tests__/skills.test.ts +32 -0
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
- package/src/__tests__/subagent-spawn-and-await.test.ts +14 -10
- package/src/__tests__/turn-events-store.test.ts +43 -0
- package/src/__tests__/ui-shape-teaching.test.ts +33 -0
- package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
- package/src/__tests__/user-plugin-loader.test.ts +1 -1
- package/src/__tests__/visible-app-context.test.ts +16 -9
- package/src/__tests__/voice-config-update.test.ts +40 -0
- 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 +68 -2
- package/src/api/events/acp-auth-required.ts +55 -0
- package/src/api/index.ts +7 -0
- package/src/api/surfaces.ts +7 -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 +173 -1
- package/src/calls/__tests__/voice-triage-escalate.test.ts +94 -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 +71 -16
- package/src/calls/voice-triage-escalate.ts +104 -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/commands/credentials.help.ts +2 -2
- package/src/cli/commands/inference-providers.ts +1 -1
- package/src/cli/commands/mcp.help.ts +13 -4
- package/src/cli/commands/mcp.ts +9 -0
- package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
- package/src/cli/commands/memory/index.help.ts +43 -1
- package/src/cli/commands/memory/memory-v3.ts +64 -0
- package/src/cli/commands/stt.help.ts +27 -2
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
- package/src/cli/lib/bundled-marketplace.json +13 -0
- package/src/cli/lib/upgrade-plugin.ts +42 -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/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/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/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 +4 -5
- package/src/config/default-profile-catalog.ts +83 -12
- package/src/config/default-profile-names.ts +4 -1
- package/src/config/default-provider-resolution.ts +4 -0
- 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/context/outbound-sanitize.ts +96 -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 +17 -6
- package/src/daemon/conversation-messaging.ts +5 -1
- package/src/daemon/conversation-notifiers.ts +9 -1
- package/src/daemon/conversation-process.ts +36 -6
- package/src/daemon/conversation-runtime-assembly.ts +3 -4
- package/src/daemon/conversation-surfaces.ts +27 -5
- package/src/daemon/conversation-tool-setup.ts +1 -2
- package/src/daemon/conversation.ts +48 -0
- package/src/daemon/interactive-turn-sender.ts +59 -0
- package/src/daemon/mcp-reload-service.ts +36 -6
- package/src/daemon/process-message.ts +24 -24
- package/src/daemon/providers-setup.ts +6 -3
- package/src/daemon/trust-context-types.ts +29 -0
- package/src/daemon/wake-conversation-ops.ts +3 -2
- package/src/documents/document-store.ts +138 -5
- package/src/hooks/hook-loader.ts +3 -3
- package/src/hooks/registry.ts +50 -6
- package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
- package/src/inbound/oauth-callback-url.ts +61 -0
- 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 +932 -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-metrics.ts +57 -32
- package/src/live-voice/live-voice-photo.ts +1 -2
- package/src/live-voice/live-voice-session.ts +535 -314
- package/src/live-voice/progress-narration.ts +277 -0
- package/src/live-voice/protocol.ts +21 -1
- 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/plugin-auto-update.ts +128 -24
- package/src/notifications/signal.ts +1 -0
- package/src/permissions/confirmation-guardian-request.test.ts +15 -11
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- 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 +108 -41
- package/src/persistence/delivery-crud.ts +38 -29
- 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/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/steps.ts +9 -0
- package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
- package/src/plugin-api/conversation-turn.ts +168 -5
- package/src/plugin-api/index.ts +21 -5
- package/src/plugin-api/vision-support.test.ts +1 -1
- package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
- package/src/plugins/defaults/memory/AGENTS.md +4 -0
- 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/buffer-format.ts +165 -0
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
- 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 +8 -12
- package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
- 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/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
- package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +33 -0
- package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +199 -2
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +25 -18
- package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
- package/src/plugins/defaults/memory/substrate/static-context.ts +160 -4
- 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/prune.ts +2 -0
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
- package/src/plugins/defaults/memory/worker.ts +6 -3
- package/src/plugins/external-plugin-loader.ts +47 -0
- package/src/plugins/mcp-servers.ts +361 -0
- package/src/plugins/mtime-cache.ts +23 -49
- package/src/plugins/worker-plugin-surface.ts +33 -0
- package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
- 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 +5 -2
- package/src/providers/call-site-routing.ts +30 -3
- package/src/providers/connection-resolution.ts +194 -11
- 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/chat-completions-provider.ts +5 -6
- 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 +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 +285 -6
- 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/provider-catalog.ts +99 -8
- package/src/providers/speech-to-text/resolve.ts +25 -2
- package/src/routes/worker.ts +17 -5
- package/src/runtime/access-request-helper.ts +9 -12
- package/src/runtime/agent-wake.ts +3 -3
- 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 +219 -1
- 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 +44 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +62 -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 +112 -1
- package/src/runtime/routes/conversation-query-routes.ts +40 -27
- package/src/runtime/routes/credential-prompt-routes.ts +4 -7
- package/src/runtime/routes/default-provider-routes.ts +15 -0
- package/src/runtime/routes/inbound-message-handler.ts +17 -41
- 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 +1 -3
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -4
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +11 -20
- 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/plugins-routes.ts +21 -3
- package/src/runtime/routes/stt-routes.ts +31 -25
- package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
- package/src/runtime/routes/user-route-dispatcher.ts +39 -14
- package/src/runtime/routes/user-route-import.ts +108 -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/manager.ts +1 -3
- package/src/subagent/types.ts +7 -6
- package/src/tools/acp/spawn.test.ts +97 -0
- package/src/tools/acp/spawn.ts +32 -0
- package/src/tools/document/document-tool.ts +12 -3
- package/src/tools/registry.ts +2 -1
- package/src/tools/ui-surface/surface-shape-docs.ts +11 -0
- 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/think-tag-stream.ts +95 -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/live-voice/__tests__/front-decision.test.ts +0 -645
- package/src/live-voice/front-decision.ts +0 -476
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guards that `resolveOauthCallbackUrl` reaches plugins.
|
|
3
|
+
*
|
|
4
|
+
* The shim written into `<workspaceDir>/node_modules/@vellumai/plugin-api`
|
|
5
|
+
* re-binds whatever `Object.keys()` finds on the plugin-api namespace, so an
|
|
6
|
+
* export missing from `index.ts` is missing from every installed plugin with
|
|
7
|
+
* no other signal than a plugin failing to import it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, expect, test } from "bun:test";
|
|
11
|
+
|
|
12
|
+
import { PLUGIN_API_EXPORTS } from "../../embedded/plugin-api.js";
|
|
13
|
+
import * as pluginApi from "../index.js";
|
|
14
|
+
|
|
15
|
+
describe("plugin-api OAuth callback export", () => {
|
|
16
|
+
test("is exported from the plugin-api surface", () => {
|
|
17
|
+
expect(typeof pluginApi.resolveOauthCallbackUrl).toEqual("function");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("is carried into the generated shim's binding list", () => {
|
|
21
|
+
expect(PLUGIN_API_EXPORTS).toContain("resolveOauthCallbackUrl");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("takes no arguments, so a plugin cannot vary the URI", () => {
|
|
25
|
+
// The value a Client ID Metadata Document publishes and the value the
|
|
26
|
+
// host later authorizes with have to be the same string.
|
|
27
|
+
expect(pluginApi.resolveOauthCallbackUrl.length).toEqual(0);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import type { AssistantEvent } from "../api/index.js";
|
|
17
|
+
import type { ChannelId } from "../channels/types.js";
|
|
17
18
|
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
18
19
|
import type { UserMessageAttachment } from "../daemon/message-types/shared.js";
|
|
19
20
|
import type { ContentBlock, MediaSource } from "../providers/types.js";
|
|
@@ -22,12 +23,62 @@ import type { ContentBlock, MediaSource } from "../providers/types.js";
|
|
|
22
23
|
// Public types
|
|
23
24
|
// ---------------------------------------------------------------------------
|
|
24
25
|
|
|
26
|
+
/**
|
|
27
|
+
* The chat a turn belongs to, in the channel's own terms.
|
|
28
|
+
*
|
|
29
|
+
* Supplied instead of a `conversationId` when the caller knows where the
|
|
30
|
+
* message came from but not which conversation that is. The pair resolves to
|
|
31
|
+
* the same conversation an inbound message on those coordinates would land
|
|
32
|
+
* in, because it resolves through the same binding.
|
|
33
|
+
*
|
|
34
|
+
* That sameness is the reason this exists at all. A caller could keep its own
|
|
35
|
+
* `externalChatId -> conversationId` map and pass the id, and turns would run
|
|
36
|
+
* in the right place. What it could not do is make the rest of the assistant
|
|
37
|
+
* agree: conversation reset is addressed by channel coordinates
|
|
38
|
+
* (`handleDeleteConversation`), the deny lanes attach an access-request card
|
|
39
|
+
* by them (`findInboundConversationId`), and the conversation and session
|
|
40
|
+
* APIs read the channel, chat name and sender off the external binding. A
|
|
41
|
+
* private map is a second name for the same conversation, and everything
|
|
42
|
+
* keyed on the public one quietly misses.
|
|
43
|
+
*/
|
|
44
|
+
export interface ConversationChannelAddress {
|
|
45
|
+
/** Channel the message arrived on. */
|
|
46
|
+
sourceChannel: ChannelId;
|
|
47
|
+
/** The chat, in the channel's own id space. */
|
|
48
|
+
externalChatId: string;
|
|
49
|
+
/**
|
|
50
|
+
* Thread within the chat, where the channel has threads. Only Slack and
|
|
51
|
+
* Telegram scope a conversation by thread; elsewhere this is carried as
|
|
52
|
+
* binding metadata and does not split the conversation.
|
|
53
|
+
*/
|
|
54
|
+
externalThreadId?: string | null;
|
|
55
|
+
/** Human-readable chat name, for the conversation list. */
|
|
56
|
+
externalChatName?: string | null;
|
|
57
|
+
/** Who sent it, in the channel's id space. */
|
|
58
|
+
externalUserId?: string | null;
|
|
59
|
+
displayName?: string | null;
|
|
60
|
+
username?: string | null;
|
|
61
|
+
}
|
|
62
|
+
|
|
25
63
|
export interface RunConversationTurnOptions {
|
|
26
64
|
/**
|
|
27
65
|
* Conversation to run the turn in. If omitted, a new conversation is
|
|
28
|
-
* created (its ID is generated with `uuidv7` and returned in the result)
|
|
66
|
+
* created (its ID is generated with `uuidv7` and returned in the result),
|
|
67
|
+
* unless {@link RunConversationTurnOptions.channel} says which chat this
|
|
68
|
+
* belongs to, in which case that chat's conversation is used.
|
|
29
69
|
*/
|
|
30
70
|
conversationId?: string;
|
|
71
|
+
/**
|
|
72
|
+
* The chat this turn belongs to, resolved to a conversation and bound to
|
|
73
|
+
* the channel. See {@link ConversationChannelAddress}.
|
|
74
|
+
*
|
|
75
|
+
* Ignored when `conversationId` is given: an explicit conversation is the
|
|
76
|
+
* caller saying which one, and re-resolving would overrule it. A caller
|
|
77
|
+
* that wants both the binding and a conversation of its own choosing is
|
|
78
|
+
* describing two different conversations, which is a bug worth surfacing
|
|
79
|
+
* as one rather than silently picking a winner.
|
|
80
|
+
*/
|
|
81
|
+
channel?: ConversationChannelAddress;
|
|
31
82
|
/**
|
|
32
83
|
* User message content blocks for this turn. Text blocks become the
|
|
33
84
|
* user message body; image/file blocks are resolved to inline
|
|
@@ -121,6 +172,77 @@ function extractContentAndAttachments(
|
|
|
121
172
|
return { text: textParts.join("\n"), attachments };
|
|
122
173
|
}
|
|
123
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Resolve a chat to its conversation, binding the two if they are not already.
|
|
177
|
+
*
|
|
178
|
+
* Two writes, the same two `handleChannelInbound` makes for an arriving
|
|
179
|
+
* message, and for the same reasons. The conversation key is what makes the
|
|
180
|
+
* chat resolve to this conversation next time and what conversation reset
|
|
181
|
+
* addresses; the external binding is what the conversation and session APIs
|
|
182
|
+
* read to show which channel a conversation came from and who is on the other
|
|
183
|
+
* end. One without the other is a conversation that is half-registered, and
|
|
184
|
+
* which half is missing decides which feature quietly stops working.
|
|
185
|
+
*
|
|
186
|
+
* Deliberately not `recordInbound`, which is the same resolution plus an
|
|
187
|
+
* inbound event row. That row exists to dedup a vendor's redelivery and to
|
|
188
|
+
* correlate later edits, and a caller driving a turn on its own schedule has
|
|
189
|
+
* neither a vendor nor a message id to correlate. Plugin deliveries are
|
|
190
|
+
* deduped upstream in the gateway before the message ever gets here.
|
|
191
|
+
*/
|
|
192
|
+
async function resolveChannelConversation(
|
|
193
|
+
channel: ConversationChannelAddress,
|
|
194
|
+
conversationType?: "standard" | "background",
|
|
195
|
+
): Promise<{ conversationId: string; created: boolean }> {
|
|
196
|
+
const { findInboundConversationId, resolveInboundConversation } =
|
|
197
|
+
await import("../persistence/delivery-crud.js");
|
|
198
|
+
const { upsertBinding } =
|
|
199
|
+
await import("../persistence/external-conversation-store.js");
|
|
200
|
+
|
|
201
|
+
// Asked before resolving, because resolving is what creates it: once the id
|
|
202
|
+
// is in hand a new conversation is indistinguishable from an existing one,
|
|
203
|
+
// and the caller announces only the new. `findInboundConversationId` is the
|
|
204
|
+
// read-only mirror of the resolution below, so the two agree on what
|
|
205
|
+
// "already bound" means, including the Slack flat-key alias.
|
|
206
|
+
const created =
|
|
207
|
+
findInboundConversationId(
|
|
208
|
+
channel.sourceChannel,
|
|
209
|
+
channel.externalChatId,
|
|
210
|
+
channel.externalThreadId,
|
|
211
|
+
) === null;
|
|
212
|
+
|
|
213
|
+
const { conversationId } = resolveInboundConversation(
|
|
214
|
+
channel.sourceChannel,
|
|
215
|
+
channel.externalChatId,
|
|
216
|
+
channel.externalThreadId,
|
|
217
|
+
// Both apply only if this call is what mints the conversation. `origin` is
|
|
218
|
+
// first-message attribution, which a chat's first turn is the only chance
|
|
219
|
+
// to record.
|
|
220
|
+
{
|
|
221
|
+
origin: channel.sourceChannel,
|
|
222
|
+
...(conversationType ? { conversationType } : {}),
|
|
223
|
+
},
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
// Refreshed on every turn rather than only on creation, because the sender's
|
|
227
|
+
// display name and the chat's name are the vendor's to change and the
|
|
228
|
+
// conversation list shows whichever we last heard. The optional fields pass
|
|
229
|
+
// through as given: a caller that omits one on a later turn knows only the
|
|
230
|
+
// chat coordinates this time, which `upsertBinding` reads as silence rather
|
|
231
|
+
// than as the sender having no name.
|
|
232
|
+
upsertBinding({
|
|
233
|
+
conversationId,
|
|
234
|
+
sourceChannel: channel.sourceChannel,
|
|
235
|
+
externalChatId: channel.externalChatId,
|
|
236
|
+
externalChatName: channel.externalChatName,
|
|
237
|
+
externalThreadId: channel.externalThreadId ?? null,
|
|
238
|
+
externalUserId: channel.externalUserId,
|
|
239
|
+
displayName: channel.displayName,
|
|
240
|
+
username: channel.username,
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
return { conversationId, created };
|
|
244
|
+
}
|
|
245
|
+
|
|
124
246
|
// ---------------------------------------------------------------------------
|
|
125
247
|
// Public API
|
|
126
248
|
// ---------------------------------------------------------------------------
|
|
@@ -166,8 +288,25 @@ export async function runConversationTurn(
|
|
|
166
288
|
// below) without requiring a client to approve prompts.
|
|
167
289
|
const { INTERNAL_GUARDIAN_TRUST_CONTEXT } =
|
|
168
290
|
await import("../daemon/trust-context.js");
|
|
169
|
-
|
|
170
|
-
|
|
291
|
+
|
|
292
|
+
// A channel address resolves through the same binding an inbound message
|
|
293
|
+
// uses, so a turn addressed by chat lands in that chat's conversation
|
|
294
|
+
// rather than a private one only this caller can find.
|
|
295
|
+
const channelConversation =
|
|
296
|
+
!options.conversationId && options.channel
|
|
297
|
+
? await resolveChannelConversation(
|
|
298
|
+
options.channel,
|
|
299
|
+
options.conversationType,
|
|
300
|
+
)
|
|
301
|
+
: undefined;
|
|
302
|
+
const conversationId =
|
|
303
|
+
options.conversationId ?? channelConversation?.conversationId ?? uuidv7();
|
|
304
|
+
// A channel address reports its own novelty, since resolving it creates the
|
|
305
|
+
// row: asking the DB here answers yes for a conversation minted a line ago
|
|
306
|
+
// and swallows the announcement it is owed.
|
|
307
|
+
const rowExisted = channelConversation
|
|
308
|
+
? !channelConversation.created
|
|
309
|
+
: getConversation(conversationId) != null;
|
|
171
310
|
const conversation = await getOrCreateConversation(conversationId, {
|
|
172
311
|
trustContext: INTERNAL_GUARDIAN_TRUST_CONTEXT,
|
|
173
312
|
...(options.conversationType
|
|
@@ -199,6 +338,28 @@ export async function runConversationTurn(
|
|
|
199
338
|
resolveMediaSourceData,
|
|
200
339
|
);
|
|
201
340
|
|
|
341
|
+
// The channel this turn speaks on. Runtime assembly reads the per-turn
|
|
342
|
+
// context first and falls back to the conversation's `originChannel`, then
|
|
343
|
+
// to `vellum`, so a turn into a conversation carrying no origin runs as
|
|
344
|
+
// `vellum` without this: the wrong channel for the message row and for the
|
|
345
|
+
// channel-permission cascade the tools are approved against. Null when the
|
|
346
|
+
// caller names no channel, which both restores that fallback and clears any
|
|
347
|
+
// context left by a previous turn.
|
|
348
|
+
const turnChannelContext = options.channel
|
|
349
|
+
? {
|
|
350
|
+
userMessageChannel: options.channel.sourceChannel,
|
|
351
|
+
assistantMessageChannel: options.channel.sourceChannel,
|
|
352
|
+
}
|
|
353
|
+
: null;
|
|
354
|
+
// Carried on the metadata as well, because a queued turn is drained after
|
|
355
|
+
// this call returns and reads its channel from there. Without it the drain
|
|
356
|
+
// inherits whichever turn was in flight, which on a shared conversation is
|
|
357
|
+
// some other channel entirely.
|
|
358
|
+
const metadata = {
|
|
359
|
+
...PLUGIN_TURN_MESSAGE_METADATA,
|
|
360
|
+
...(turnChannelContext ?? {}),
|
|
361
|
+
};
|
|
362
|
+
|
|
202
363
|
// Build the event emitter: fan out to SSE/event-hub subscribers via
|
|
203
364
|
// broadcastMessage, then invoke the collector callback. This mirrors the
|
|
204
365
|
// buildEventEmitter pattern from process-message.ts so plugin-driven
|
|
@@ -221,7 +382,7 @@ export async function runConversationTurn(
|
|
|
221
382
|
onEvent,
|
|
222
383
|
requestId,
|
|
223
384
|
isInteractive: false,
|
|
224
|
-
metadata
|
|
385
|
+
metadata,
|
|
225
386
|
});
|
|
226
387
|
if (enqueueResult.rejected) {
|
|
227
388
|
throw new Error(
|
|
@@ -236,12 +397,14 @@ export async function runConversationTurn(
|
|
|
236
397
|
};
|
|
237
398
|
}
|
|
238
399
|
|
|
400
|
+
conversation.setTurnChannelContext(turnChannelContext);
|
|
401
|
+
|
|
239
402
|
const userMessageId = await conversation.processMessage({
|
|
240
403
|
content: text,
|
|
241
404
|
attachments,
|
|
242
405
|
onEvent,
|
|
243
406
|
isInteractive: false,
|
|
244
|
-
metadata
|
|
407
|
+
metadata,
|
|
245
408
|
...(options.callSite ? { callSite: options.callSite } : {}),
|
|
246
409
|
});
|
|
247
410
|
|
package/src/plugin-api/index.ts
CHANGED
|
@@ -180,6 +180,16 @@ export {
|
|
|
180
180
|
// the same resolution as `webhooks register`, and registers the callback route
|
|
181
181
|
// on the managed branches. The plugin defaults to the one in context.
|
|
182
182
|
export { resolveWebhookUrl, type WebhookUrlOptions } from "./webhook-url.js";
|
|
183
|
+
// Resolve the redirect URI an authorization server should send a user back
|
|
184
|
+
// to after consent. One shared route serves every OAuth flow in the
|
|
185
|
+
// assistant, demultiplexed by OAuth `state`, so this takes no arguments and
|
|
186
|
+
// returns the same URL for every caller and every attempt. A plugin needs it
|
|
187
|
+
// when it publishes something that has to name the redirect URI ahead of the
|
|
188
|
+
// flow, such as a Client ID Metadata Document, whose `redirect_uris` an
|
|
189
|
+
// authorization server matches exactly. Throws when no public ingress is
|
|
190
|
+
// configured and the assistant is not connected to the platform, which is the
|
|
191
|
+
// case where no URL would work.
|
|
192
|
+
export { resolveOauthCallbackUrl } from "../inbound/oauth-callback-url.js";
|
|
183
193
|
// Resolve a provider for a call site (optionally overriding the profile) so a
|
|
184
194
|
// plugin can run inference through the workspace's configured profiles and
|
|
185
195
|
// credentials — managed-proxy or BYOK — without supplying its own API key.
|
|
@@ -345,21 +355,26 @@ export { synthesizeText, TtsSynthesisError } from "../tts/synthesize-text.js";
|
|
|
345
355
|
export type { TtsSynthesisResult } from "../tts/types.js";
|
|
346
356
|
// Streaming speech-to-text — open a live transcription session against the
|
|
347
357
|
// assistant's globally configured STT provider stack. The plugin feeds audio
|
|
348
|
-
// chunks via `sendAudio` and receives
|
|
349
|
-
// the `start(onEvent)` callback, closing with `stop`.
|
|
350
|
-
//
|
|
351
|
-
//
|
|
352
|
-
//
|
|
358
|
+
// chunks via `sendAudio` and receives transcript and turn-boundary events
|
|
359
|
+
// through the `start(onEvent)` callback, closing with `stop`.
|
|
360
|
+
// `SttStreamServerEvent` types the events handed to `onEvent`; every member of
|
|
361
|
+
// that union is exported alongside it so a plugin can name each variant in an
|
|
362
|
+
// exhaustive switch. `SttErrorCategory` classifies `error` events;
|
|
363
|
+
// `SttProviderId` names the resolved session's provider.
|
|
353
364
|
export type {
|
|
354
365
|
StreamingTranscriber,
|
|
355
366
|
SttErrorCategory,
|
|
356
367
|
SttProviderId,
|
|
357
368
|
SttStreamServerClosedEvent,
|
|
369
|
+
SttStreamServerEagerTurnEndEvent,
|
|
358
370
|
SttStreamServerErrorEvent,
|
|
359
371
|
SttStreamServerEvent,
|
|
360
372
|
SttStreamServerFinalEvent,
|
|
361
373
|
SttStreamServerFinalizedEvent,
|
|
362
374
|
SttStreamServerPartialEvent,
|
|
375
|
+
SttStreamServerTurnEndEvent,
|
|
376
|
+
SttStreamServerTurnResumedEvent,
|
|
377
|
+
SttStreamServerTurnStartEvent,
|
|
363
378
|
} from "../stt/types.js";
|
|
364
379
|
export { openTranscriptionSession } from "./transcription-session.js";
|
|
365
380
|
// Conversation agent-loop turn — run a full conversation turn (persist user
|
|
@@ -370,6 +385,7 @@ export { openTranscriptionSession } from "./transcription-session.js";
|
|
|
370
385
|
// (e.g. meeting-bot flushing a transcript excerpt) should prefer this over the
|
|
371
386
|
// stateless `provider.sendMessage()` call.
|
|
372
387
|
export type {
|
|
388
|
+
ConversationChannelAddress,
|
|
373
389
|
RunConversationTurnOptions,
|
|
374
390
|
RunConversationTurnResult,
|
|
375
391
|
} from "./conversation-turn.js";
|
|
@@ -107,7 +107,7 @@ describe("doesSupportVision", () => {
|
|
|
107
107
|
managed: { provider: "vellum", model: "claude-fable-5" },
|
|
108
108
|
"managed-text": {
|
|
109
109
|
provider: "vellum",
|
|
110
|
-
model: "accounts/fireworks/models/deepseek-v4-flash",
|
|
110
|
+
model: "accounts/fireworks/models/deepseek-v4-flash-0731",
|
|
111
111
|
},
|
|
112
112
|
});
|
|
113
113
|
expect(doesSupportVision(profile("managed"))).toBe(true);
|