@vellumai/assistant 0.11.2 → 0.11.3-dev.202608080427.92f668a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +69 -9
- package/docs/flux-turn-detection-spike.md +243 -0
- package/docs/stt-provider-onboarding.md +3 -1
- package/docs/trusted-contact-access.md +9 -5
- package/docs/vellum-doctor.md +195 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +50 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
- package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
- package/node_modules/@vellumai/environments/src/index.ts +17 -6
- package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +50 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
- package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
- package/node_modules/@vellumai/service-contracts/src/channels.ts +50 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
- package/openapi.yaml +619 -47
- package/package.json +1 -1
- package/scripts/voice-ttft-spike.ts +3 -3
- package/src/__tests__/agent-image-optimize.test.ts +4 -4
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
- package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
- package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/answered-question-persistence.test.ts +240 -0
- package/src/__tests__/anthropic-provider.test.ts +165 -30
- package/src/__tests__/app-control-flow.test.ts +9 -8
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
- package/src/__tests__/attachments-store.test.ts +130 -68
- package/src/__tests__/attachments.test.ts +36 -36
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/call-controller.test.ts +120 -0
- package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
- package/src/__tests__/canned-reply-release.test.ts +86 -0
- package/src/__tests__/channel-availability-routes.test.ts +14 -1
- package/src/__tests__/channel-guardian.test.ts +59 -29
- package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
- package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
- package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/config-loader-backfill.test.ts +19 -0
- package/src/__tests__/config-schema.test.ts +150 -7
- package/src/__tests__/consult-deadline.test.ts +65 -0
- package/src/__tests__/conversation-agent-loop.test.ts +438 -2
- package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
- package/src/__tests__/conversation-disk-view.test.ts +4 -4
- package/src/__tests__/conversation-error.test.ts +22 -3
- package/src/__tests__/conversation-fork-crud.test.ts +5 -1
- package/src/__tests__/conversation-fork-referential.test.ts +352 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
- package/src/__tests__/conversation-group-tools.test.ts +32 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
- package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
- package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
- package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
- package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
- package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
- package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
- package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
- package/src/__tests__/conversation-queue.test.ts +433 -1
- package/src/__tests__/conversation-retry-route.test.ts +3 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
- package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
- package/src/__tests__/conversation-store.test.ts +26 -10
- package/src/__tests__/conversation-summarize-route.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
- package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
- package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
- package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
- package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
- package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
- package/src/__tests__/credential-prompt-route.test.ts +54 -7
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +89 -28
- package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
- package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
- package/src/__tests__/disk-pressure-guard.test.ts +55 -55
- package/src/__tests__/disk-pressure-routes.test.ts +10 -10
- package/src/__tests__/disk-pressure-tools.test.ts +2 -2
- package/src/__tests__/disk-usage.test.ts +35 -20
- package/src/__tests__/document-sync-tags.test.ts +379 -0
- package/src/__tests__/document-update-default-surface.test.ts +28 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
- package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
- package/src/__tests__/events-dev-bypass-actor.test.ts +294 -1
- package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
- package/src/__tests__/file-list-tool.test.ts +12 -10
- package/src/__tests__/file-ops-service.test.ts +151 -44
- package/src/__tests__/file-read-container-boundary.test.ts +137 -0
- package/src/__tests__/file-read-tool.test.ts +21 -9
- package/src/__tests__/file-url-path-guard.test.ts +83 -0
- package/src/__tests__/filesystem-tools.test.ts +82 -66
- package/src/__tests__/guardian-outbound-http.test.ts +8 -8
- package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
- package/src/__tests__/helpers/hub-clients.ts +42 -0
- package/src/__tests__/helpers/mock-conversation.ts +46 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
- package/src/__tests__/history-repair.test.ts +112 -12
- package/src/__tests__/host-bash-proxy.test.ts +10 -5
- package/src/__tests__/host-bash-routes.test.ts +67 -0
- package/src/__tests__/host-browser-proxy.test.ts +2 -2
- package/src/__tests__/host-cu-proxy.test.ts +3 -7
- package/src/__tests__/host-file-proxy.test.ts +3 -7
- package/src/__tests__/host-file-read-tool.test.ts +5 -1
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
- package/src/__tests__/http-conversation-lineage.test.ts +2 -5
- package/src/__tests__/http-user-message-parity.test.ts +44 -0
- package/src/__tests__/identity-routes.test.ts +13 -13
- package/src/__tests__/image-conversion.test.ts +29 -26
- package/src/__tests__/image-source-path-reinject.test.ts +2 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
- package/src/__tests__/introduction-card-resolver.test.ts +6 -1
- package/src/__tests__/list-messages-attachments.test.ts +56 -32
- package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
- package/src/__tests__/list-messages-page-latest.test.ts +61 -61
- package/src/__tests__/list-messages-provider-error.test.ts +6 -6
- package/src/__tests__/list-messages-queued.test.ts +49 -6
- package/src/__tests__/list-messages-system-card.test.ts +4 -4
- package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
- package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
- package/src/__tests__/llm-usage-store.test.ts +55 -0
- package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
- package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
- package/src/__tests__/media-stream-output.test.ts +175 -0
- package/src/__tests__/media-stream-server-integration.test.ts +36 -0
- package/src/__tests__/media-stream-stt-session.test.ts +67 -0
- package/src/__tests__/migration-export-http.test.ts +1 -1
- package/src/__tests__/migration-import-commit-http.test.ts +1 -1
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
- package/src/__tests__/migration-validate-http.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +65 -3
- package/src/__tests__/notification-platform-adapter.test.ts +104 -0
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
- package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
- package/src/__tests__/path-policy.test.ts +164 -1
- package/src/__tests__/persist-media-references.test.ts +2 -2
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
- package/src/__tests__/persist-unsendable-image.test.ts +23 -23
- package/src/__tests__/persona-resolver.test.ts +154 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
- package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
- package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
- package/src/__tests__/profiler-routes.test.ts +13 -13
- package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
- package/src/__tests__/proxy-approval-callback.test.ts +3 -3
- package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
- package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
- package/src/__tests__/resolve-trust-class.test.ts +20 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
- package/src/__tests__/run-due-schedules.test.ts +174 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
- package/src/__tests__/schedule-routes.test.ts +730 -8
- package/src/__tests__/schedule-store.test.ts +540 -0
- package/src/__tests__/schedule-tools.test.ts +103 -0
- package/src/__tests__/scheduler-wake.test.ts +5 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
- package/src/__tests__/secure-keys.test.ts +91 -0
- package/src/__tests__/server-history-render.test.ts +97 -7
- package/src/__tests__/size-guard.test.ts +8 -8
- package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
- package/src/__tests__/skill-tool-factory.test.ts +247 -0
- package/src/__tests__/skills-install-staging.test.ts +15 -6
- package/src/__tests__/skills.test.ts +32 -0
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
- package/src/__tests__/slack-inbound-verification.test.ts +4 -1
- package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
- package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
- package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
- package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
- package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
- package/src/__tests__/subagent-disposal.test.ts +10 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
- package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
- package/src/__tests__/subagent-manager-notify.test.ts +148 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/subagent-persistence.test.ts +141 -0
- package/src/__tests__/subagent-role-registry.test.ts +172 -63
- package/src/__tests__/subagent-role-resolution.test.ts +88 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
- package/src/__tests__/subagent-terminal-message.test.ts +88 -1
- package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
- package/src/__tests__/subagent-tools.test.ts +1901 -108
- package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
- package/src/__tests__/system-prompt.test.ts +82 -7
- package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
- package/src/__tests__/tool-result-spool.test.ts +74 -18
- package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
- package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
- package/src/__tests__/tools-audio-read.test.ts +10 -10
- package/src/__tests__/tools-get-route.test.ts +85 -12
- package/src/__tests__/tools-list-cli.test.ts +171 -0
- package/src/__tests__/top-level-renderer.test.ts +54 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
- package/src/__tests__/turn-tail-chain.test.ts +135 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
- package/src/__tests__/ui-visual-surface.test.ts +5 -4
- package/src/__tests__/ui-work-result-surface.test.ts +5 -4
- package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
- package/src/__tests__/usage-routes.test.ts +62 -0
- package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
- package/src/__tests__/visible-app-context.test.ts +20 -4
- package/src/__tests__/web-search-history.test.ts +96 -0
- package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
- package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
- package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +150 -0
- package/src/acp/failure-error.ts +3 -5
- package/src/agent/attachments.ts +26 -24
- package/src/agent/history-repair/history-repair.ts +27 -26
- package/src/agent/image-optimize.ts +6 -6
- package/src/agent/loop.ts +40 -22
- package/src/agent/message-types.ts +3 -3
- package/src/api/constants/document-tools.ts +55 -0
- package/src/api/events/question-answered.ts +53 -0
- package/src/api/events/tool-result.ts +7 -0
- package/src/api/index.ts +13 -0
- package/src/api/responses/conversation-message.ts +11 -0
- package/src/api/surfaces-oauth-connect.test.ts +96 -0
- package/src/api/surfaces.ts +36 -8
- package/src/approvals/guardian-channel-delivery.ts +83 -0
- package/src/approvals/guardian-expiry-notifier.ts +13 -11
- package/src/approvals/guardian-request-resolvers.ts +222 -135
- package/src/calls/__tests__/tts-text-sanitizer.test.ts +13 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +131 -12
- package/src/calls/__tests__/voice-triage-escalate.test.ts +106 -0
- package/src/calls/call-controller.ts +30 -2
- package/src/calls/call-speech-output.ts +12 -4
- package/src/calls/call-transport.ts +18 -1
- package/src/calls/media-stream-output.ts +53 -5
- package/src/calls/media-stream-server.ts +21 -1
- package/src/calls/media-stream-stt-session.ts +49 -0
- package/src/calls/telephony-synthesis-language.ts +84 -0
- package/src/calls/tts-text-sanitizer.ts +12 -5
- package/src/calls/voice-session-bridge.ts +86 -17
- package/src/calls/voice-triage-escalate.ts +54 -7
- package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
- package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
- package/src/channels/config.ts +20 -2
- package/src/channels/gateway-verification-sessions.ts +7 -2
- package/src/channels/plugin-channel-declarations.ts +108 -0
- package/src/channels/types.ts +37 -1
- package/src/cli/AGENTS.md +5 -2
- package/src/cli/commands/__tests__/cache.test.ts +7 -4
- package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
- package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
- package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
- package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
- package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
- package/src/cli/commands/__tests__/plugins.test.ts +692 -0
- package/src/cli/commands/__tests__/schedules.test.ts +136 -37
- package/src/cli/commands/conversations.ts +7 -3
- package/src/cli/commands/credentials.help.ts +7 -0
- package/src/cli/commands/inference-profiles.ts +9 -3
- package/src/cli/commands/inference.help.ts +16 -2
- package/src/cli/commands/mcp.help.ts +17 -6
- package/src/cli/commands/mcp.ts +9 -0
- package/src/cli/commands/memory/memory-retrospective.ts +18 -0
- package/src/cli/commands/notifications.ts +3 -6
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
- package/src/cli/commands/oauth/connect.test.ts +26 -1
- package/src/cli/commands/oauth/connect.ts +4 -1
- package/src/cli/commands/oauth/index.help.ts +3 -1
- package/src/cli/commands/oauth/providers.ts +3 -0
- package/src/cli/commands/plugins.help.ts +25 -2
- package/src/cli/commands/plugins.ts +289 -10
- package/src/cli/commands/schedules.help.ts +14 -12
- package/src/cli/commands/schedules.ts +19 -5
- package/src/cli/commands/stt.help.ts +27 -2
- package/src/cli/commands/tools.help.ts +4 -2
- package/src/cli/commands/tools.ts +38 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
- package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +161 -0
- package/src/cli/lib/install-from-github.ts +61 -0
- package/src/cli/lib/install-from-platform.ts +13 -2
- package/src/cli/lib/plugin-surfaces.ts +124 -4
- package/src/cli/lib/upgrade-plugin.ts +60 -0
- package/src/cli.ts +1 -1
- package/src/config/__tests__/default-profile-catalog.test.ts +11 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
- package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
- package/src/config/__tests__/profile-tool-support.test.ts +131 -0
- package/src/config/bundled-skills/AGENTS.md +1 -1
- package/src/config/bundled-skills/acp/SKILL.md +6 -7
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +15 -15
- package/src/config/bundled-skills/schedule/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
- package/src/config/bundled-skills/subagent/SKILL.md +53 -22
- package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
- package/src/config/bundled-skills/visualize/SKILL.md +1 -1
- package/src/config/call-site-defaults.ts +4 -5
- package/src/config/default-profile-catalog.ts +9 -5
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +45 -15
- package/src/config/loader.ts +75 -1
- package/src/config/profile-tool-support.ts +110 -0
- package/src/config/sanitize-for-transfer.ts +11 -0
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/live-voice.test.ts +142 -4
- package/src/config/schemas/__tests__/stt.test.ts +20 -5
- package/src/config/schemas/call-site-catalog.ts +4 -4
- package/src/config/schemas/calls.ts +0 -4
- package/src/config/schemas/channels.ts +13 -0
- package/src/config/schemas/live-voice.ts +82 -23
- package/src/config/schemas/llm.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +25 -0
- package/src/config/schemas/plugin-updates.ts +59 -0
- package/src/config/schemas/services.ts +8 -4
- package/src/config/schemas/stt.ts +18 -5
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/config/schemas/tts.ts +63 -0
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
- package/src/contacts/guardian-delivery-reader.ts +29 -2
- package/src/context/compactor.ts +4 -4
- package/src/context/post-turn-tool-result-truncation.ts +32 -16
- package/src/context/strip-injections.ts +42 -0
- package/src/context/tool-result-spool.ts +32 -18
- package/src/credential-execution/ces-runtime.ts +3 -0
- package/src/credential-execution/client.ts +22 -1
- package/src/credential-execution/process-manager.test.ts +99 -0
- package/src/credential-execution/process-manager.ts +62 -16
- package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
- package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
- package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
- package/src/daemon/channel-ui-capability.ts +4 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
- package/src/daemon/conversation-agent-loop.ts +318 -148
- package/src/daemon/conversation-attachments.ts +1 -1
- package/src/daemon/conversation-error.ts +8 -1
- package/src/daemon/conversation-initial-prompt.ts +16 -38
- package/src/daemon/conversation-lifecycle.ts +154 -32
- package/src/daemon/conversation-messaging.ts +106 -43
- package/src/daemon/conversation-process.ts +131 -33
- package/src/daemon/conversation-queue-manager.ts +10 -0
- package/src/daemon/conversation-runtime-assembly.ts +9 -4
- package/src/daemon/conversation-store.ts +52 -3
- package/src/daemon/conversation-surface-state.ts +9 -0
- package/src/daemon/conversation-surfaces.ts +403 -210
- package/src/daemon/conversation-tool-setup.ts +56 -7
- package/src/daemon/conversation-turn-finalize.ts +134 -89
- package/src/daemon/conversation.ts +111 -27
- package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
- package/src/daemon/disk-pressure-guard.ts +3 -3
- package/src/daemon/doordash-steps.ts +5 -5
- package/src/daemon/external-plugins-bootstrap.ts +7 -1
- package/src/daemon/handlers/config-channels.ts +48 -5
- package/src/daemon/handlers/conversation-history.ts +1 -1
- package/src/daemon/handlers/conversations.ts +62 -17
- package/src/daemon/handlers/shared.ts +12 -0
- package/src/daemon/handlers/skills.ts +11 -1
- package/src/daemon/identity-helpers.ts +38 -10
- package/src/daemon/install-assistant-command.ts +322 -0
- package/src/daemon/lifecycle.ts +14 -3
- package/src/daemon/message-types/conversations.ts +6 -7
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/persist-media-references.ts +23 -14
- package/src/daemon/process-message.ts +6 -6
- package/src/daemon/tool-setup-types.ts +19 -122
- package/src/daemon/tool-side-effects.ts +17 -94
- package/src/daemon/trust-context-types.ts +39 -0
- package/src/daemon/trust-context.ts +14 -6
- package/src/daemon/turn-tail-chain.ts +73 -0
- package/src/daemon/web-search-history.ts +47 -33
- package/src/heartbeat/heartbeat-service.ts +6 -6
- package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
- package/src/inbound/oauth-callback-url.ts +61 -0
- package/src/ipc/__tests__/socket-path.test.ts +21 -0
- package/src/ipc/assistant-server.ts +17 -10
- package/src/ipc/cli-client.ts +10 -1
- package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
- package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
- package/src/ipc/socket-cleanup.ts +9 -7
- package/src/ipc/socket-path.ts +4 -96
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
- package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
- package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
- package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +932 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +12 -5
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
- package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +179 -146
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +324 -2
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +131 -2
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
- package/src/live-voice/__tests__/live-voice-tts.test.ts +148 -2
- package/src/live-voice/__tests__/live-voice-vad.test.ts +313 -32
- package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
- package/src/live-voice/__tests__/progress-phrases.test.ts +167 -0
- package/src/live-voice/__tests__/protocol.test.ts +52 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
- package/src/live-voice/live-voice-archive.ts +13 -13
- package/src/live-voice/live-voice-connection.ts +7 -1
- package/src/live-voice/live-voice-metrics.ts +57 -32
- package/src/live-voice/live-voice-photo.ts +168 -0
- package/src/live-voice/live-voice-session.ts +1137 -351
- package/src/live-voice/live-voice-tts.ts +18 -2
- package/src/live-voice/progress-narration.ts +277 -0
- package/src/live-voice/progress-phrases.ts +105 -2
- package/src/live-voice/protocol.ts +110 -2
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +196 -0
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
- package/src/mcp/client.ts +14 -7
- package/src/mcp/mcp-auth-orchestrator.ts +13 -22
- package/src/mcp/mcp-oauth-provider.ts +195 -240
- package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
- package/src/messaging/providers/callback-routing.ts +1 -0
- package/src/messaging/providers/discord/api.ts +312 -0
- package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
- package/src/messaging/providers/discord/render.test.ts +204 -0
- package/src/messaging/providers/discord/render.ts +195 -0
- package/src/messaging/providers/discord/send.test.ts +179 -0
- package/src/messaging/providers/discord/send.ts +212 -0
- package/src/messaging/providers/discord/transport.ts +81 -0
- package/src/messaging/providers/index.ts +3 -1
- package/src/messaging/providers/retry-policy.test.ts +247 -0
- package/src/messaging/providers/retry-policy.ts +206 -0
- package/src/messaging/providers/slack/mention-source.test.ts +285 -0
- package/src/messaging/providers/slack/mention-source.ts +287 -0
- package/src/messaging/providers/telegram-bot/api.ts +47 -130
- package/src/messaging/providers/whatsapp/api.ts +47 -136
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +495 -0
- package/src/monitoring/db-integrity-sample.ts +6 -1
- package/src/monitoring/plugin-auto-update.ts +463 -0
- package/src/monitoring/resource-sampler.ts +21 -5
- package/src/monitoring/worker.ts +13 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
- package/src/notifications/__tests__/broadcaster.test.ts +37 -1
- package/src/notifications/__tests__/copy-composer.test.ts +165 -0
- package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
- package/src/notifications/__tests__/notification-utils.test.ts +249 -0
- package/src/notifications/adapters/platform.ts +31 -2
- package/src/notifications/assistant-reply-producer.ts +79 -32
- package/src/notifications/broadcaster.ts +30 -10
- package/src/notifications/copy-composer.ts +69 -0
- package/src/notifications/emit-signal.ts +82 -15
- package/src/notifications/events-store.ts +10 -2
- package/src/notifications/home-feed-side-effect.ts +6 -3
- package/src/notifications/notification-utils.ts +173 -5
- package/src/notifications/signal.ts +13 -0
- package/src/oauth/AGENTS.md +4 -2
- package/src/oauth/byo-connection.ts +6 -1
- package/src/oauth/credential-token-resolver.ts +3 -10
- package/src/oauth/manual-token-connection.ts +29 -64
- package/src/oauth/manual-token-providers.ts +62 -0
- package/src/oauth/provider-serializer.ts +13 -0
- package/src/oauth/seed-providers.ts +62 -11
- package/src/onboarding/onboarding-events-store.ts +91 -1
- package/src/permissions/question-prompter.test.ts +4 -0
- package/src/permissions/question-prompter.ts +21 -4
- package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
- package/src/persistence/attachments-store.ts +15 -15
- package/src/persistence/conversation-attention-store.ts +30 -10
- package/src/persistence/conversation-bootstrap.ts +17 -0
- package/src/persistence/conversation-crud.ts +363 -97
- package/src/persistence/conversation-group-migration.ts +1 -1
- package/src/persistence/conversation-key-store.ts +38 -10
- package/src/persistence/conversation-lineage.ts +226 -0
- package/src/persistence/conversation-plugin-facade.ts +28 -3
- package/src/persistence/conversation-queries.ts +207 -33
- package/src/persistence/conversation-types.ts +107 -1
- package/src/persistence/jobs-store.ts +32 -8
- package/src/persistence/llm-usage-store.ts +22 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
- package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
- package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
- package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
- package/src/persistence/schema/conversations.ts +32 -0
- package/src/persistence/schema/infrastructure.ts +3 -0
- package/src/persistence/steps.ts +30 -0
- package/src/persistence/subagent-store.ts +148 -6
- package/src/platform/managed-speech.test.ts +20 -0
- package/src/platform/managed-speech.ts +9 -0
- package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
- package/src/plugin-api/index.ts +28 -5
- package/src/plugin-api/webhook-url.ts +151 -0
- package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
- package/src/plugins/__tests__/mcp-servers.test.ts +370 -0
- package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
- package/src/plugins/collect-source-versions.ts +4 -27
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
- package/src/plugins/defaults/exploration-drift/package.json +1 -1
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
- package/src/plugins/defaults/image-recovery/recover.ts +67 -57
- package/src/plugins/defaults/index.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
- package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
- package/src/plugins/defaults/memory/job-handlers.ts +87 -5
- package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
- package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
- package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
- package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
- package/src/plugins/defaults/memory/v2/router.ts +8 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
- package/src/plugins/external-plugin-loader.ts +64 -8
- package/src/plugins/installed-plugin-dirs.ts +101 -0
- package/src/plugins/mcp-servers.ts +343 -0
- package/src/plugins/mtime-cache.ts +34 -22
- package/src/plugins/types.ts +69 -8
- package/src/prompts/persona-resolver.ts +6 -2
- package/src/prompts/system-prompt.ts +72 -17
- package/src/providers/__tests__/inference.test.ts +40 -0
- package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
- package/src/providers/__tests__/retry-callsite.test.ts +72 -2
- package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
- package/src/providers/anthropic/client.ts +112 -95
- package/src/providers/connection-resolution.ts +35 -1
- package/src/providers/gemini/client.ts +5 -5
- package/src/providers/inference/adapter-factory.ts +16 -10
- package/src/providers/inference/auth.ts +16 -0
- package/src/providers/inference/connection-availability.ts +164 -12
- package/src/providers/inference/connections.ts +25 -1
- package/src/providers/media-resolve.ts +21 -11
- package/src/providers/model-catalog.ts +15 -0
- package/src/providers/openai/chat-completions-provider.ts +4 -4
- package/src/providers/openai/responses-provider.ts +12 -25
- package/src/providers/registry.ts +9 -4
- package/src/providers/retry.ts +25 -0
- package/src/providers/server-tool-pairing.ts +134 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +620 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +472 -12
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +719 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +283 -1
- package/src/providers/speech-to-text/deepgram-realtime.ts +117 -3
- package/src/providers/speech-to-text/deepgram.ts +1 -0
- package/src/providers/speech-to-text/provider-catalog.ts +137 -8
- package/src/providers/speech-to-text/resolve.ts +105 -12
- package/src/providers/speech-to-text/vellum-managed.ts +7 -1
- package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
- package/src/providers/types.ts +26 -6
- package/src/providers/vellum-model-routing.ts +6 -7
- package/src/runtime/AGENTS.md +2 -0
- package/src/runtime/__tests__/agent-wake.test.ts +16 -16
- package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
- package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
- package/src/runtime/__tests__/local-actor-identity-force-refresh.test.ts +104 -0
- package/src/runtime/agent-wake.ts +63 -24
- package/src/runtime/assistant-event-hub.ts +110 -12
- package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
- package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
- package/src/runtime/auth/same-actor.ts +56 -8
- package/src/runtime/auth/scopes.ts +12 -0
- package/src/runtime/auth/types.ts +2 -0
- package/src/runtime/background-job-runner.ts +5 -27
- package/src/runtime/channel-readiness-service.ts +59 -3
- package/src/runtime/channel-readiness-types.ts +18 -0
- package/src/runtime/desktop-presence.ts +69 -0
- package/src/runtime/http-server.ts +12 -0
- package/src/runtime/local-actor-identity.ts +29 -14
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +217 -1
- package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
- package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
- package/src/runtime/routes/__tests__/sse-actor-principal-heal.test.ts +165 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +2 -0
- package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
- package/src/runtime/routes/archive-utils.ts +16 -12
- package/src/runtime/routes/attachment-routes.ts +13 -6
- package/src/runtime/routes/canned-reply-release.ts +54 -0
- package/src/runtime/routes/channel-availability-routes.ts +32 -14
- package/src/runtime/routes/channel-verification-routes.ts +2 -27
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
- package/src/runtime/routes/client-routes.ts +114 -2
- package/src/runtime/routes/conversation-cli-routes.ts +10 -12
- package/src/runtime/routes/conversation-list-routes.ts +59 -10
- package/src/runtime/routes/conversation-management-routes.ts +47 -18
- package/src/runtime/routes/conversation-query-routes.ts +32 -53
- package/src/runtime/routes/conversation-routes.ts +360 -293
- package/src/runtime/routes/credential-prompt-routes.ts +20 -2
- package/src/runtime/routes/debug-routes.ts +4 -1
- package/src/runtime/routes/default-provider-routes.ts +7 -11
- package/src/runtime/routes/documents-routes.ts +44 -1
- package/src/runtime/routes/events-routes.ts +29 -1
- package/src/runtime/routes/host-app-control-routes.ts +2 -0
- package/src/runtime/routes/host-bash-routes.ts +2 -0
- package/src/runtime/routes/host-browser-routes.ts +2 -0
- package/src/runtime/routes/host-cu-routes.ts +2 -0
- package/src/runtime/routes/host-file-routes.ts +2 -0
- package/src/runtime/routes/host-transfer-routes.ts +4 -0
- package/src/runtime/routes/identity-routes.ts +6 -6
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
- package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
- package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
- package/src/runtime/routes/inference-profiles-routes.ts +152 -73
- package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
- package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
- package/src/runtime/routes/log-export-routes.ts +1 -1
- package/src/runtime/routes/mcp-auth-routes.ts +141 -57
- package/src/runtime/routes/notification-routes.ts +0 -14
- package/src/runtime/routes/oauth-providers.ts +1 -0
- package/src/runtime/routes/plugins-routes.ts +127 -4
- package/src/runtime/routes/profiler-routes.ts +4 -2
- package/src/runtime/routes/question-routes.ts +28 -10
- package/src/runtime/routes/retrospective-routes.ts +9 -3
- package/src/runtime/routes/schedule-routes.ts +210 -12
- package/src/runtime/routes/secret-routes.ts +40 -23
- package/src/runtime/routes/settings-routes.ts +41 -13
- package/src/runtime/routes/skills-routes.ts +79 -0
- package/src/runtime/routes/sse-actor-principal-heal.ts +113 -0
- package/src/runtime/routes/stt-routes.ts +31 -25
- package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
- package/src/runtime/routes/wake-conversation-routes.ts +23 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +24 -9
- package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
- package/src/runtime/sync/resource-sync-events.ts +79 -1
- package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
- package/src/runtime/sync/worker-daemon-notify.ts +44 -6
- package/src/runtime/verification-outbound-actions.ts +250 -222
- package/src/runtime/verification-templates.ts +41 -30
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
- package/src/schedule/inference-profile.ts +64 -3
- package/src/schedule/plugin-schedule-declarations.ts +518 -0
- package/src/schedule/plugin-schedule-reconciler.ts +605 -0
- package/src/schedule/plugin-schedules-gate.ts +23 -0
- package/src/schedule/schedule-store.ts +520 -26
- package/src/schedule/scheduler.ts +38 -0
- package/src/security/credential-backend.ts +51 -4
- package/src/security/encrypted-store.ts +64 -42
- package/src/security/oauth2.ts +6 -22
- package/src/security/secure-keys.ts +55 -7
- package/src/skills/catalog-install.ts +20 -7
- package/src/skills/inline-command-runner.ts +2 -7
- package/src/skills/skill-history.test.ts +269 -0
- package/src/skills/skill-history.ts +250 -0
- package/src/skills/skillssh-registry.ts +1 -1
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
- package/src/stt/__tests__/language-metadata.test.ts +85 -0
- package/src/stt/__tests__/speech-energy.test.ts +79 -0
- package/src/stt/__tests__/types.test.ts +94 -0
- package/src/stt/daemon-batch-transcriber.ts +18 -6
- package/src/stt/language-metadata.ts +65 -0
- package/src/stt/speech-energy.ts +115 -12
- package/src/stt/stt-stream-session.ts +8 -4
- package/src/stt/types.ts +119 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
- package/src/subagent/consult-prompt.ts +3 -1
- package/src/subagent/consult-transcript.ts +1 -1
- package/src/subagent/manager.ts +304 -44
- package/src/subagent/progress-events.ts +35 -0
- package/src/subagent/role-resolution.ts +88 -0
- package/src/subagent/types.ts +303 -67
- package/src/subagent/validate-allowlists.ts +3 -4
- package/src/telegram/__tests__/webhook-health.test.ts +73 -1
- package/src/telegram/webhook-health.ts +101 -3
- package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
- package/src/telemetry/activation-funnel.ts +6 -1
- package/src/telemetry/live-voice-funnel.ts +75 -0
- package/src/telemetry/telemetry-event-sources.ts +6 -0
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire.generated.ts +2 -0
- package/src/telemetry/types.ts +23 -4
- package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
- package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
- package/src/tools/ask-question/ask-question-tool.ts +56 -2
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/calls/call-start.ts +8 -5
- package/src/tools/conversation-groups/move_to_group.ts +10 -12
- package/src/tools/document/document-tool.ts +11 -4
- package/src/tools/execution-timeout.ts +9 -2
- package/src/tools/executor.ts +7 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +7 -13
- package/src/tools/filesystem/search.ts +23 -21
- package/src/tools/filesystem/write.ts +4 -1
- package/src/tools/host-filesystem/edit.ts +7 -2
- package/src/tools/host-filesystem/read.ts +21 -8
- package/src/tools/host-filesystem/write.ts +10 -2
- package/src/tools/host-terminal/host-shell.ts +2 -2
- package/src/tools/mcp/mcp-tool-factory.ts +25 -1
- package/src/tools/permission-checker.ts +8 -3
- package/src/tools/schedule/delete.ts +13 -1
- package/src/tools/schedule/list.ts +14 -3
- package/src/tools/schedule/update.ts +56 -33
- package/src/tools/shared/filesystem/audio-read.ts +6 -4
- package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
- package/src/tools/shared/filesystem/image-read.ts +12 -12
- package/src/tools/shared/filesystem/path-policy.ts +70 -5
- package/src/tools/shared/filesystem/size-guard.ts +6 -6
- package/src/tools/shared/input-misuse.ts +72 -0
- package/src/tools/skills/scaffold-managed.ts +82 -0
- package/src/tools/skills/skill-tool-factory.ts +14 -1
- package/src/tools/subagent/consult-deadline.ts +12 -7
- package/src/tools/subagent/message.ts +3 -1
- package/src/tools/subagent/read.ts +66 -4
- package/src/tools/subagent/spawn.ts +500 -78
- package/src/tools/tool-approval-handler.ts +45 -4
- package/src/tools/types.ts +22 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
- package/src/tools/ui-surface/visual-validation.ts +2 -0
- package/src/tts/__tests__/provider-adapters.test.ts +147 -0
- package/src/tts/__tests__/speakable-segments.test.ts +470 -0
- package/src/tts/language-voices.ts +23 -0
- package/src/tts/providers/deepgram-provider.ts +3 -1
- package/src/tts/providers/elevenlabs-provider.ts +73 -1
- package/src/tts/providers/xai-provider.ts +28 -2
- package/src/tts/speakable-segments.ts +293 -23
- package/src/tts/synthesis-stream.ts +7 -0
- package/src/tts/types.ts +7 -0
- package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
- package/src/usage/subagent-attribution.ts +108 -0
- package/src/util/__tests__/language-subtag.test.ts +54 -0
- package/src/util/__tests__/sqlite-retry.test.ts +112 -0
- package/src/util/abort-reasons.ts +16 -0
- package/src/util/ansi.ts +44 -0
- package/src/util/disk-usage.ts +17 -13
- package/src/util/image-conversion.ts +20 -13
- package/src/util/language-subtag.ts +43 -0
- package/src/util/schedule-source-key.ts +23 -0
- package/src/util/unicode.ts +1 -1
- package/src/util/worker-process.ts +7 -1
- package/src/workspace/git-service.ts +33 -9
- package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
- package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
- package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +116 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/workspace/top-level-renderer.ts +15 -2
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
- package/src/daemon/install-symlink.ts +0 -207
- package/src/live-voice/__tests__/front-decision.test.ts +0 -525
- package/src/live-voice/front-decision.ts +0 -429
- package/src/notifications/deferred-emit.ts +0 -147
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
import { z } from "zod";
|
|
42
42
|
|
|
43
43
|
import type { AssistantConfig } from "../../../../config/types.js";
|
|
44
|
+
import { warmGuardianBindings } from "../../../../contacts/guardian-delivery-reader.js";
|
|
44
45
|
import {
|
|
45
46
|
cachedTextBlock,
|
|
46
47
|
extractToolUse,
|
|
@@ -393,6 +394,13 @@ async function runRouterBatch(
|
|
|
393
394
|
provider,
|
|
394
395
|
} = params;
|
|
395
396
|
|
|
397
|
+
// Warm both guardian-delivery cache keys (vellum + unfiltered) so
|
|
398
|
+
// resolveUserName's sync guardian-file resolution, including its
|
|
399
|
+
// any-channel fallback, hits fresh keys instead of falling back to
|
|
400
|
+
// users/default.md on a cold/TTL-expired cache. Two local-socket IPC
|
|
401
|
+
// reads per batch, dwarfed by the batch's provider call.
|
|
402
|
+
await warmGuardianBindings();
|
|
403
|
+
|
|
396
404
|
const systemPrompt = resolveRouterPrompt(
|
|
397
405
|
config.memory?.v2?.router?.router_prompt_path ?? null,
|
|
398
406
|
workspaceDir,
|
|
@@ -29,7 +29,6 @@ export interface UnifiedTurnContextOptions {
|
|
|
29
29
|
name: string;
|
|
30
30
|
/** Directory stem: the handle a human would recognize the app by. */
|
|
31
31
|
slug: string;
|
|
32
|
-
sourceDir: string;
|
|
33
32
|
/** Set when the app is bundled by an installed plugin rather than built here. */
|
|
34
33
|
pluginName?: string;
|
|
35
34
|
} | null;
|
|
@@ -127,7 +126,7 @@ export function buildUnifiedTurnContextBlock(
|
|
|
127
126
|
? ` It is bundled by the "${sanitizeInlineContextValue(app.pluginName)}" plugin, not built in the sandbox.`
|
|
128
127
|
: "";
|
|
129
128
|
lines.push(
|
|
130
|
-
`visible_app: "${sanitizeInlineContextValue(app.name)}" (app_id: "${sanitizeInlineContextValue(app.appId)}", slug: "${sanitizeInlineContextValue(app.slug)}"
|
|
129
|
+
`visible_app: "${sanitizeInlineContextValue(app.name)}" (app_id: "${sanitizeInlineContextValue(app.appId)}", slug: "${sanitizeInlineContextValue(app.slug)}"). The user has this app open on screen; unqualified references to "the app" mean this one.${provenance}`,
|
|
131
130
|
);
|
|
132
131
|
}
|
|
133
132
|
|
|
@@ -92,6 +92,12 @@ const PluginPackageJsonSchema = z
|
|
|
92
92
|
version: z.string().optional(),
|
|
93
93
|
peerDependencies: z.record(z.string(), z.string()).optional(),
|
|
94
94
|
credentialKeyPatterns: z.unknown().optional(),
|
|
95
|
+
/** Human title, when the package name is not one ("@vellumai/imessage"). */
|
|
96
|
+
displayName: z.string().min(1).optional(),
|
|
97
|
+
/** Standard npm field, reused as the one-line description clients show. */
|
|
98
|
+
description: z.string().min(1).optional(),
|
|
99
|
+
/** Lucide icon name without the `lucide-` prefix, matching `ChannelInfo`. */
|
|
100
|
+
icon: z.string().min(1).optional(),
|
|
95
101
|
})
|
|
96
102
|
.passthrough();
|
|
97
103
|
|
|
@@ -461,9 +467,55 @@ export async function loadExternalPlugin(
|
|
|
461
467
|
* Exported so the mtime cache can discover plugin identity without going
|
|
462
468
|
* through the full `buildExternalPlugin` path. The identity mirrors
|
|
463
469
|
* {@link buildPluginFromDir}: the directory name, not `package.json` `name`.
|
|
470
|
+
*
|
|
471
|
+
* `quiet` suppresses the failure logs, for callers that poll on a timer and
|
|
472
|
+
* surface the failure through their own channel (e.g. the schedule
|
|
473
|
+
* reconciler's per-day deduped notification).
|
|
474
|
+
*/
|
|
475
|
+
/**
|
|
476
|
+
* How a plugin presents itself: its title, its one line, its glyph.
|
|
477
|
+
*
|
|
478
|
+
* Every field is optional and none of them gate anything. A surface that
|
|
479
|
+
* shows a plugin falls back rather than hiding it, so a missing `icon`
|
|
480
|
+
* costs an icon and not the row.
|
|
481
|
+
*/
|
|
482
|
+
export interface PluginPresentation {
|
|
483
|
+
displayName?: string;
|
|
484
|
+
description?: string;
|
|
485
|
+
icon?: string;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Read a plugin's presentation fields from its manifest.
|
|
490
|
+
*
|
|
491
|
+
* Separate from {@link parsePluginManifest} because the two answer different
|
|
492
|
+
* questions: that one decides whether a plugin is loadable, this one only
|
|
493
|
+
* dresses it for display. An unreadable or invalid manifest yields `undefined`
|
|
494
|
+
* here rather than an error, since a caller showing a plugin has already
|
|
495
|
+
* established it exists.
|
|
464
496
|
*/
|
|
497
|
+
export async function parsePluginPresentation(
|
|
498
|
+
pluginDir: string,
|
|
499
|
+
): Promise<PluginPresentation | undefined> {
|
|
500
|
+
let rawPkg: unknown;
|
|
501
|
+
try {
|
|
502
|
+
rawPkg = JSON.parse(
|
|
503
|
+
await readFile(join(pluginDir, "package.json"), "utf8"),
|
|
504
|
+
);
|
|
505
|
+
} catch {
|
|
506
|
+
return undefined;
|
|
507
|
+
}
|
|
508
|
+
const parsed = PluginPackageJsonSchema.safeParse(rawPkg);
|
|
509
|
+
if (!parsed.success) {
|
|
510
|
+
return undefined;
|
|
511
|
+
}
|
|
512
|
+
const { displayName, description, icon } = parsed.data;
|
|
513
|
+
return { displayName, description, icon };
|
|
514
|
+
}
|
|
515
|
+
|
|
465
516
|
export async function parsePluginManifest(
|
|
466
517
|
pluginDir: string,
|
|
518
|
+
opts: { quiet?: boolean } = {},
|
|
467
519
|
): Promise<
|
|
468
520
|
Pick<PluginManifest, "name" | "version" | "credentialKeyPatterns"> | undefined
|
|
469
521
|
> {
|
|
@@ -473,18 +525,22 @@ export async function parsePluginManifest(
|
|
|
473
525
|
rawPkg = JSON.parse(await readFile(pkgPath, "utf8"));
|
|
474
526
|
} catch (err) {
|
|
475
527
|
const reason = err instanceof Error ? err.message : String(err);
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
528
|
+
if (!opts.quiet) {
|
|
529
|
+
log.error(
|
|
530
|
+
{ err, pluginDir },
|
|
531
|
+
`package.json at ${pluginDir} could not be read or parsed: ${reason}`,
|
|
532
|
+
);
|
|
533
|
+
}
|
|
480
534
|
return undefined;
|
|
481
535
|
}
|
|
482
536
|
const parsed = PluginPackageJsonSchema.safeParse(rawPkg);
|
|
483
537
|
if (!parsed.success) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
538
|
+
if (!opts.quiet) {
|
|
539
|
+
log.error(
|
|
540
|
+
{ err: parsed.error, pluginDir },
|
|
541
|
+
`package.json at ${pluginDir} failed schema validation: ${parsed.error.message}`,
|
|
542
|
+
);
|
|
543
|
+
}
|
|
488
544
|
return undefined;
|
|
489
545
|
}
|
|
490
546
|
const pkg: PluginPackageJson = parsed.data;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enumerate installed plugin directories under the workspace plugins dir.
|
|
3
|
+
*
|
|
4
|
+
* An installed plugin is a non-hidden directory carrying a `package.json`,
|
|
5
|
+
* whose realpath stays under the realpath of the plugins directory. This walk
|
|
6
|
+
* is shared by the plugin source-version collector
|
|
7
|
+
* (`./collect-source-versions.ts`) and the schedule reconciler
|
|
8
|
+
* (`../schedule/plugin-schedule-reconciler.ts`) so both agree on what counts
|
|
9
|
+
* as an installed plugin. Disabled-state and manifest validation are caller
|
|
10
|
+
* concerns: the source collector fingerprints disabled plugins too, while the
|
|
11
|
+
* reconciler skips them and additionally gates on `parsePluginManifest`.
|
|
12
|
+
*
|
|
13
|
+
* The containment half of that definition is exported on its own
|
|
14
|
+
* ({@link isInsidePluginRoot}) for the plugin loader, which applies the same
|
|
15
|
+
* boundary at boot discovery and before it imports a plugin directory, and for
|
|
16
|
+
* the schedule fire-time probe, which applies it before answering that a
|
|
17
|
+
* declaration is available to run.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { existsSync, readdirSync, realpathSync, statSync } from "node:fs";
|
|
21
|
+
import { join, sep } from "node:path";
|
|
22
|
+
|
|
23
|
+
import { getWorkspacePluginsDir } from "../util/platform.js";
|
|
24
|
+
|
|
25
|
+
export interface InstalledPluginDir {
|
|
26
|
+
/** Directory basename: the plugin's install identity. */
|
|
27
|
+
readonly name: string;
|
|
28
|
+
/** Absolute path to the plugin directory. */
|
|
29
|
+
readonly dir: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* True when `dir` resolves to a location strictly inside `root`, where `root`
|
|
34
|
+
* is the tree the caller requires `dir` to stay in: an allowed plugin root
|
|
35
|
+
* (the workspace plugins directory, or the standalone workspace hooks
|
|
36
|
+
* directory) for a plugin directory, or a plugin directory for something
|
|
37
|
+
* installed under it.
|
|
38
|
+
*
|
|
39
|
+
* Both sides are resolved before the comparison. Resolving the candidate is
|
|
40
|
+
* what judges a symlinked entry by where it points rather than by where it
|
|
41
|
+
* sits; resolving the root is what keeps a root that itself sits behind a
|
|
42
|
+
* symlinked path component (macOS `/tmp` to `/private/tmp`, a workspace under
|
|
43
|
+
* a linked home) matching its own children. A resolved candidate compared
|
|
44
|
+
* against an unresolved root reports every entry as outside.
|
|
45
|
+
*
|
|
46
|
+
* This is the one containment boundary the plugin loader applies: enumeration
|
|
47
|
+
* here, boot discovery, and the pre-import check before a plugin directory is
|
|
48
|
+
* dynamic-imported (`scanPlugins` and `isAllowedPluginDir` in
|
|
49
|
+
* `./mtime-cache.ts`) all go through it, so a root the loader refuses to
|
|
50
|
+
* activate is never reported as installed either. A link pointing at the root
|
|
51
|
+
* itself is outside the boundary: it aliases the root, not a plugin. The
|
|
52
|
+
* schedule fire-time probe
|
|
53
|
+
* (`../schedule/plugin-schedule-declarations.ts`) applies the same boundary,
|
|
54
|
+
* so such a root cannot be run by a declared schedule either.
|
|
55
|
+
*/
|
|
56
|
+
export function isInsidePluginRoot(dir: string, root: string): boolean {
|
|
57
|
+
try {
|
|
58
|
+
return realpathSync(dir).startsWith(realpathSync(root) + sep);
|
|
59
|
+
} catch {
|
|
60
|
+
// Unresolvable (dangling link, races with an uninstall, unreadable): not
|
|
61
|
+
// provably contained, so it is not inside.
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* List every installed plugin directory, sorted by the underlying readdir
|
|
68
|
+
* order. A missing plugins directory yields `[]`.
|
|
69
|
+
*/
|
|
70
|
+
export function listInstalledPluginDirs(): InstalledPluginDir[] {
|
|
71
|
+
const pluginsDir = getWorkspacePluginsDir();
|
|
72
|
+
let entries: string[] = [];
|
|
73
|
+
try {
|
|
74
|
+
entries = readdirSync(pluginsDir);
|
|
75
|
+
} catch {
|
|
76
|
+
// No plugins directory yet, so nothing installed.
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
const out: InstalledPluginDir[] = [];
|
|
80
|
+
for (const entry of entries) {
|
|
81
|
+
if (entry.startsWith(".")) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const dir = join(pluginsDir, entry);
|
|
85
|
+
try {
|
|
86
|
+
if (!statSync(dir).isDirectory()) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (!isInsidePluginRoot(dir, pluginsDir)) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (!existsSync(join(dir, "package.json"))) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
out.push({ name: entry, dir });
|
|
99
|
+
}
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin-contributed MCP servers.
|
|
3
|
+
*
|
|
4
|
+
* A plugin declares MCP servers in a root `mcp.json`, per the Agent
|
|
5
|
+
* Plugins 1.0.0 specification:
|
|
6
|
+
*
|
|
7
|
+
* {
|
|
8
|
+
* "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
|
|
9
|
+
* "mcpServers": {
|
|
10
|
+
* "unabyss": { "type": "streamable-http", "url": "https://mcp.unabyss.com" }
|
|
11
|
+
* }
|
|
12
|
+
* }
|
|
13
|
+
*
|
|
14
|
+
* This module reads those files and projects each entry onto the
|
|
15
|
+
* assistant's own `McpServerConfig` shape, so a plugin-declared server can
|
|
16
|
+
* flow through the same surfaces as one configured in the workspace
|
|
17
|
+
* `config.json`.
|
|
18
|
+
*
|
|
19
|
+
* Failure isolation follows the spec: an invalid top-level `mcp.json`
|
|
20
|
+
* disables MCP for that plugin only, and an invalid individual server
|
|
21
|
+
* disables only that entry. Neither ever throws, because a malformed file
|
|
22
|
+
* in one plugin must not remove another plugin's servers from a listing.
|
|
23
|
+
*
|
|
24
|
+
* Authentication is deliberately absent. Agent Plugins 1.0.0 defines no
|
|
25
|
+
* portable OAuth or credential-reference fields; authentication is
|
|
26
|
+
* client-managed, and any `headers` in the file are literal package data.
|
|
27
|
+
* A plugin therefore cannot ship a credential, and the assistant's own
|
|
28
|
+
* credential store stays the only place secrets live.
|
|
29
|
+
*
|
|
30
|
+
* Consumers must not resolve a plugin server's id against the
|
|
31
|
+
* `mcp:<serverId>:*` credential namespace. Those keys belong to
|
|
32
|
+
* workspace-configured servers, and a plugin controls both its server key
|
|
33
|
+
* and its URL, so honoring them for a plugin-declared server would send a
|
|
34
|
+
* workspace credential to an endpoint the plugin chose.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
38
|
+
import { join } from "node:path";
|
|
39
|
+
|
|
40
|
+
import { z } from "zod";
|
|
41
|
+
|
|
42
|
+
import {
|
|
43
|
+
type AllPluginInfo,
|
|
44
|
+
listAllPlugins,
|
|
45
|
+
type ListInstalledPluginsOptions,
|
|
46
|
+
} from "../cli/lib/list-installed-plugins.js";
|
|
47
|
+
import type { McpServerConfig, McpTransport } from "../config/schemas/mcp.js";
|
|
48
|
+
import { getLogger } from "../util/logger.js";
|
|
49
|
+
|
|
50
|
+
const log = getLogger("plugin-mcp-servers");
|
|
51
|
+
|
|
52
|
+
/** Filename a plugin declares its MCP servers in, at the plugin root. */
|
|
53
|
+
export const PLUGIN_MCP_MANIFEST = "mcp.json";
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Risk level assigned to a plugin-declared server. `mcp.json` has no risk
|
|
57
|
+
* field, since the spec defines none, so the assistant's own default
|
|
58
|
+
* applies. `high` matches `McpServerConfigSchema` and is the safe
|
|
59
|
+
* direction: a plugin cannot lower the approval bar for the tools it
|
|
60
|
+
* introduces.
|
|
61
|
+
*/
|
|
62
|
+
const PLUGIN_SERVER_DEFAULT_RISK = "high" as const;
|
|
63
|
+
|
|
64
|
+
/** Matches the `maxTools` default in `McpServerConfigSchema`. */
|
|
65
|
+
const PLUGIN_SERVER_DEFAULT_MAX_TOOLS = 20;
|
|
66
|
+
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Wire schema (Agent Plugins 1.0.0)
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
const PluginStdioServerSchema = z.object({
|
|
72
|
+
type: z.literal("stdio"),
|
|
73
|
+
command: z.string().min(1),
|
|
74
|
+
args: z.array(z.string()).optional(),
|
|
75
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
76
|
+
cwd: z.string().optional(),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const PluginHttpServerSchema = z.object({
|
|
80
|
+
type: z.enum(["streamable-http", "sse"]),
|
|
81
|
+
url: z.string().min(1),
|
|
82
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const PluginMcpServerSchema = z.discriminatedUnion("type", [
|
|
86
|
+
PluginStdioServerSchema,
|
|
87
|
+
PluginHttpServerSchema,
|
|
88
|
+
]);
|
|
89
|
+
|
|
90
|
+
const PluginMcpManifestSchema = z.object({
|
|
91
|
+
mcpServers: z.record(z.string(), z.unknown()),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
// Public shape
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
/** One MCP server declared by one plugin. */
|
|
99
|
+
export interface PluginMcpServer {
|
|
100
|
+
/** Server id in the assistant's namespace. See {@link buildServerId}. */
|
|
101
|
+
readonly id: string;
|
|
102
|
+
/** Directory name of the plugin that declared it. */
|
|
103
|
+
readonly pluginName: string;
|
|
104
|
+
/** Key this server appears under in the plugin's `mcp.json`. */
|
|
105
|
+
readonly serverKey: string;
|
|
106
|
+
/** Projected onto the assistant's own server-config shape. */
|
|
107
|
+
readonly config: McpServerConfig;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** A plugin's `mcp.json` that could not be used, in whole or in part. */
|
|
111
|
+
export interface PluginMcpIssue {
|
|
112
|
+
readonly pluginName: string;
|
|
113
|
+
/** Absent when the whole manifest is unusable rather than one entry. */
|
|
114
|
+
readonly serverKey?: string;
|
|
115
|
+
readonly message: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface PluginMcpServersResult {
|
|
119
|
+
readonly servers: readonly PluginMcpServer[];
|
|
120
|
+
readonly issues: readonly PluginMcpIssue[];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Server id for a plugin-declared server.
|
|
125
|
+
*
|
|
126
|
+
* Plugin servers share one namespace with workspace servers and with each
|
|
127
|
+
* other, so the plugin name is the qualifier. The redundant case is
|
|
128
|
+
* collapsed: a plugin named `unabyss` whose server key is also `unabyss`
|
|
129
|
+
* yields `unabyss`, not `unabyss__unabyss`, which matters because the id
|
|
130
|
+
* is embedded in every tool name the server contributes
|
|
131
|
+
* (`mcp__<id>__<tool>`).
|
|
132
|
+
*/
|
|
133
|
+
export function buildServerId(pluginName: string, serverKey: string): string {
|
|
134
|
+
return pluginName === serverKey ? pluginName : `${pluginName}__${serverKey}`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Expand the two path variables the Agent Plugins spec defines for stdio
|
|
139
|
+
* servers. They interpolate textually in `args`, `env` values, and `cwd`
|
|
140
|
+
* only, never in `command`, a URL, or a header, so a manifest cannot use
|
|
141
|
+
* them to build the executable path itself.
|
|
142
|
+
*/
|
|
143
|
+
export function interpolatePluginPaths(
|
|
144
|
+
value: string,
|
|
145
|
+
pluginRoot: string,
|
|
146
|
+
pluginData: string,
|
|
147
|
+
): string {
|
|
148
|
+
return value
|
|
149
|
+
.replaceAll("${PLUGIN_ROOT}", pluginRoot)
|
|
150
|
+
.replaceAll("${PLUGIN_DATA}", pluginData);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Whether a directory is a plugin the runtime would actually load.
|
|
155
|
+
*
|
|
156
|
+
* `listAllPlugins` is an inventory of directories and reports a malformed
|
|
157
|
+
* entry rather than dropping it, so it happily returns a directory with no
|
|
158
|
+
* usable `package.json`. The runtime loader rejects those in
|
|
159
|
+
* `parsePluginManifest`: the manifest must parse and carry a non-empty
|
|
160
|
+
* `name`. Applying the same gate here keeps `mcp.json` from being honored
|
|
161
|
+
* for a directory that will never load as a plugin.
|
|
162
|
+
*/
|
|
163
|
+
export function hasLoadableManifest(plugin: AllPluginInfo): boolean {
|
|
164
|
+
const name = plugin.packageJson?.name;
|
|
165
|
+
return typeof name === "string" && name.length > 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
// Reading
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Read every installed plugin's `mcp.json` and return the servers they
|
|
174
|
+
* declare, plus anything that could not be read.
|
|
175
|
+
*
|
|
176
|
+
* A disabled plugin is skipped entirely: `.disabled` means the plugin
|
|
177
|
+
* contributes no hooks and no tools, and an MCP server it declares is no
|
|
178
|
+
* different.
|
|
179
|
+
*/
|
|
180
|
+
export function readPluginMcpServers(
|
|
181
|
+
opts: ListInstalledPluginsOptions = {},
|
|
182
|
+
): PluginMcpServersResult {
|
|
183
|
+
const servers: PluginMcpServer[] = [];
|
|
184
|
+
const issues: PluginMcpIssue[] = [];
|
|
185
|
+
const seen = new Map<string, string>();
|
|
186
|
+
|
|
187
|
+
let plugins: readonly AllPluginInfo[];
|
|
188
|
+
try {
|
|
189
|
+
plugins = listAllPlugins(opts);
|
|
190
|
+
} catch (err) {
|
|
191
|
+
// The plugins directory being unreadable is not a reason to fail a
|
|
192
|
+
// listing that also has workspace-configured servers in it.
|
|
193
|
+
log.warn({ err }, "Could not enumerate plugins for MCP declarations");
|
|
194
|
+
return { servers: [], issues: [] };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
for (const plugin of plugins) {
|
|
198
|
+
if (plugin.disabled) {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const manifestPath = join(plugin.target, PLUGIN_MCP_MANIFEST);
|
|
202
|
+
if (!existsSync(manifestPath)) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (!hasLoadableManifest(plugin)) {
|
|
207
|
+
issues.push({
|
|
208
|
+
pluginName: plugin.name,
|
|
209
|
+
message: `${PLUGIN_MCP_MANIFEST} ignored: package.json is missing, unparseable, or has no name, so the runtime will not load this directory as a plugin`,
|
|
210
|
+
});
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const parsed = parseManifest(manifestPath);
|
|
215
|
+
if ("error" in parsed) {
|
|
216
|
+
issues.push({ pluginName: plugin.name, message: parsed.error });
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
for (const [serverKey, raw] of Object.entries(parsed.mcpServers)) {
|
|
221
|
+
if (serverKey.trim().length === 0) {
|
|
222
|
+
issues.push({
|
|
223
|
+
pluginName: plugin.name,
|
|
224
|
+
message: "server key must be a non-empty string; skipping",
|
|
225
|
+
});
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const entry = PluginMcpServerSchema.safeParse(raw);
|
|
230
|
+
if (!entry.success) {
|
|
231
|
+
issues.push({
|
|
232
|
+
pluginName: plugin.name,
|
|
233
|
+
serverKey,
|
|
234
|
+
message: `invalid server entry: ${entry.error.issues
|
|
235
|
+
.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`)
|
|
236
|
+
.join("; ")}`,
|
|
237
|
+
});
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const id = buildServerId(plugin.name, serverKey);
|
|
242
|
+
const previous = seen.get(id);
|
|
243
|
+
if (previous) {
|
|
244
|
+
// Two plugins claiming one id would silently shadow each other, and
|
|
245
|
+
// the loser's tools would just be missing. Report both instead.
|
|
246
|
+
issues.push({
|
|
247
|
+
pluginName: plugin.name,
|
|
248
|
+
serverKey,
|
|
249
|
+
message: `server id "${id}" is already declared by plugin "${previous}"; skipping`,
|
|
250
|
+
});
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
seen.set(id, plugin.name);
|
|
254
|
+
|
|
255
|
+
// The spec allows `cwd` on a stdio server; the assistant's transport
|
|
256
|
+
// has no such field. Dropping it silently would leave a server that
|
|
257
|
+
// resolves its relative paths against the wrong directory and fails
|
|
258
|
+
// for no visible reason, so say so.
|
|
259
|
+
if (entry.data.type === "stdio" && entry.data.cwd) {
|
|
260
|
+
issues.push({
|
|
261
|
+
pluginName: plugin.name,
|
|
262
|
+
serverKey,
|
|
263
|
+
message: `"cwd" is not supported by this host and was ignored; the server runs in the daemon's working directory`,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
servers.push({
|
|
268
|
+
id,
|
|
269
|
+
pluginName: plugin.name,
|
|
270
|
+
serverKey,
|
|
271
|
+
config: {
|
|
272
|
+
transport: projectTransport(entry.data, plugin.target),
|
|
273
|
+
enabled: true,
|
|
274
|
+
defaultRiskLevel: PLUGIN_SERVER_DEFAULT_RISK,
|
|
275
|
+
maxTools: PLUGIN_SERVER_DEFAULT_MAX_TOOLS,
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return { servers, issues };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function parseManifest(
|
|
285
|
+
path: string,
|
|
286
|
+
): { mcpServers: Record<string, unknown> } | { error: string } {
|
|
287
|
+
let raw: string;
|
|
288
|
+
try {
|
|
289
|
+
raw = readFileSync(path, "utf8");
|
|
290
|
+
} catch (err) {
|
|
291
|
+
return {
|
|
292
|
+
error: `${PLUGIN_MCP_MANIFEST} unreadable: ${err instanceof Error ? err.message : String(err)}`,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
let json: unknown;
|
|
297
|
+
try {
|
|
298
|
+
json = JSON.parse(raw);
|
|
299
|
+
} catch (err) {
|
|
300
|
+
return {
|
|
301
|
+
error: `${PLUGIN_MCP_MANIFEST} invalid JSON: ${err instanceof Error ? err.message : String(err)}`,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const manifest = PluginMcpManifestSchema.safeParse(json);
|
|
306
|
+
if (!manifest.success) {
|
|
307
|
+
return {
|
|
308
|
+
error: `${PLUGIN_MCP_MANIFEST} is missing a valid "mcpServers" object`,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
return { mcpServers: manifest.data.mcpServers };
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Project one spec-shaped entry onto the assistant's transport union. The
|
|
316
|
+
* two vocabularies already agree on type names and required fields, so this
|
|
317
|
+
* is a field copy plus path interpolation for the stdio case.
|
|
318
|
+
*/
|
|
319
|
+
function projectTransport(
|
|
320
|
+
entry: z.infer<typeof PluginMcpServerSchema>,
|
|
321
|
+
pluginRoot: string,
|
|
322
|
+
): McpTransport {
|
|
323
|
+
if (entry.type === "stdio") {
|
|
324
|
+
const pluginData = join(pluginRoot, "data");
|
|
325
|
+
const expand = (v: string): string =>
|
|
326
|
+
interpolatePluginPaths(v, pluginRoot, pluginData);
|
|
327
|
+
return {
|
|
328
|
+
type: "stdio",
|
|
329
|
+
command: entry.command,
|
|
330
|
+
args: (entry.args ?? []).map(expand),
|
|
331
|
+
...(entry.env && {
|
|
332
|
+
env: Object.fromEntries(
|
|
333
|
+
Object.entries(entry.env).map(([k, v]) => [k, expand(v)]),
|
|
334
|
+
),
|
|
335
|
+
}),
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
type: entry.type,
|
|
340
|
+
url: entry.url,
|
|
341
|
+
...(entry.headers && { headers: entry.headers }),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
@@ -31,13 +31,7 @@
|
|
|
31
31
|
* each hook through the hook loader on demand.
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
-
import {
|
|
35
|
-
existsSync,
|
|
36
|
-
readdirSync,
|
|
37
|
-
readFileSync,
|
|
38
|
-
realpathSync,
|
|
39
|
-
statSync,
|
|
40
|
-
} from "node:fs";
|
|
34
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
41
35
|
import { join } from "node:path";
|
|
42
36
|
|
|
43
37
|
import type { Logger } from "pino";
|
|
@@ -72,6 +66,7 @@ import {
|
|
|
72
66
|
listSurfaceDir,
|
|
73
67
|
parsePluginManifest,
|
|
74
68
|
} from "./external-plugin-loader.js";
|
|
69
|
+
import { isInsidePluginRoot } from "./installed-plugin-dirs.js";
|
|
75
70
|
import { snapshotPluginSource } from "./source-fingerprint.js";
|
|
76
71
|
import type { PluginSourceVersion } from "./source-versions.js";
|
|
77
72
|
import {
|
|
@@ -293,6 +288,18 @@ export async function reconcilePluginSourcesNow(): Promise<void> {
|
|
|
293
288
|
} catch (err) {
|
|
294
289
|
log.error({ err }, "imperative plugin reconcile failed");
|
|
295
290
|
}
|
|
291
|
+
// Converge plugin-declared schedules against the plugin set this apply
|
|
292
|
+
// just settled, so install/uninstall/upgrade arm and disarm rows in the
|
|
293
|
+
// same poke. Imported lazily to keep the notification pipeline out of
|
|
294
|
+
// this module's static graph (sidecar workers import it for hook reads).
|
|
295
|
+
// Self-contained: never throws and checks DB readiness itself.
|
|
296
|
+
try {
|
|
297
|
+
const { reconcilePluginSchedules } =
|
|
298
|
+
await import("../schedule/plugin-schedule-reconciler.js");
|
|
299
|
+
await reconcilePluginSchedules();
|
|
300
|
+
} catch (err) {
|
|
301
|
+
log.error({ err }, "plugin schedule reconcile failed");
|
|
302
|
+
}
|
|
296
303
|
})().finally(() => {
|
|
297
304
|
reconcileInFlight = null;
|
|
298
305
|
});
|
|
@@ -306,32 +313,26 @@ export async function reconcilePluginSourcesNow(): Promise<void> {
|
|
|
306
313
|
* never dynamically imports code from outside the designated plugin roots,
|
|
307
314
|
* regardless of what the collector walked.
|
|
308
315
|
*
|
|
309
|
-
*
|
|
310
|
-
* symlinked path that looks like it's under the
|
|
311
|
-
* elsewhere is rejected
|
|
316
|
+
* Containment runs through {@link isInsidePluginRoot}, which resolves the
|
|
317
|
+
* candidate and the root, so a symlinked path that looks like it's under the
|
|
318
|
+
* plugins dir but points elsewhere is rejected while a plugins dir reached
|
|
319
|
+
* through a symlinked path component still accepts its own children.
|
|
312
320
|
*/
|
|
313
321
|
function isAllowedPluginDir(
|
|
314
322
|
dir: string,
|
|
315
323
|
pluginsDir: string,
|
|
316
324
|
hooksDir: string,
|
|
317
325
|
): boolean {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
// Directory doesn't exist or is inaccessible — allow it through so
|
|
323
|
-
// bringUpPlugin/parsePluginManifest can log the normal failure. The
|
|
326
|
+
if (!existsSync(dir)) {
|
|
327
|
+
// Directory doesn't exist or is inaccessible: allow it through so
|
|
328
|
+
// bringUpPlugin/parsePluginManifest can log the normal failure, and so a
|
|
329
|
+
// directory that just went away still reaches its teardown branch. The
|
|
324
330
|
// danger is importing code from an unexpected location, not a missing
|
|
325
331
|
// directory.
|
|
326
332
|
return true;
|
|
327
333
|
}
|
|
328
|
-
const normalizedPluginsDir = pluginsDir + "/";
|
|
329
|
-
const normalizedHooksDir = hooksDir + "/";
|
|
330
334
|
return (
|
|
331
|
-
|
|
332
|
-
resolved.startsWith(normalizedPluginsDir) ||
|
|
333
|
-
resolved === hooksDir ||
|
|
334
|
-
resolved.startsWith(normalizedHooksDir)
|
|
335
|
+
isInsidePluginRoot(dir, pluginsDir) || isInsidePluginRoot(dir, hooksDir)
|
|
335
336
|
);
|
|
336
337
|
}
|
|
337
338
|
|
|
@@ -754,6 +755,17 @@ async function scanPlugins(): Promise<void> {
|
|
|
754
755
|
} catch {
|
|
755
756
|
continue;
|
|
756
757
|
}
|
|
758
|
+
// Judge the entry by where it resolves. A symlinked plugin root pointing
|
|
759
|
+
// out of the plugins directory is not an install, and activating one at
|
|
760
|
+
// boot would run code that enumeration and the reload path both refuse to
|
|
761
|
+
// touch.
|
|
762
|
+
if (!isInsidePluginRoot(pluginDir, pluginsDir)) {
|
|
763
|
+
log.warn(
|
|
764
|
+
{ pluginDir },
|
|
765
|
+
"plugin root resolves outside the plugins directory, skipping",
|
|
766
|
+
);
|
|
767
|
+
continue;
|
|
768
|
+
}
|
|
757
769
|
if (!existsSync(join(pluginDir, "package.json"))) {
|
|
758
770
|
continue;
|
|
759
771
|
}
|