@vellumai/assistant 0.11.2 → 0.11.3-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 +58 -3
- 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 +39 -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 +39 -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 +39 -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 +589 -30
- package/package.json +1 -1
- 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-start-guardian-guard.test.ts +18 -4
- package/src/__tests__/canned-reply-release.test.ts +86 -0
- 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__/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 +57 -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 +183 -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-tool-annotations-risk.test.ts +133 -0
- package/src/__tests__/media-stream-server-integration.test.ts +36 -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__/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/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__/voice-session-bridge.test.ts +50 -0
- package/src/calls/media-stream-server.ts +9 -1
- package/src/calls/voice-session-bridge.ts +38 -0
- package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
- package/src/channels/config.ts +7 -2
- package/src/channels/gateway-verification-sessions.ts +7 -2
- package/src/channels/types.ts +7 -1
- 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 +4 -2
- 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/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 +122 -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 +18 -0
- package/src/cli.ts +1 -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/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
- 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 +2 -2
- 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/visualize/SKILL.md +1 -1
- package/src/config/default-profile-catalog.ts +6 -2
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +45 -15
- package/src/config/loader.ts +70 -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__/stt.test.ts +20 -5
- package/src/config/schemas/channels.ts +13 -0
- package/src/config/schemas/memory-retrospective.ts +25 -0
- package/src/config/schemas/plugin-updates.ts +55 -0
- package/src/config/schemas/services.ts +8 -4
- package/src/config/schemas/stt.ts +17 -5
- package/src/config/schemas/timeouts.ts +1 -1
- 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/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-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-integration.test.ts +7 -5
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
- package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
- 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-photo.ts +169 -0
- package/src/live-voice/live-voice-session.ts +108 -4
- package/src/live-voice/protocol.ts +89 -1
- package/src/mcp/client.ts +10 -0
- 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 +332 -0
- package/src/monitoring/db-integrity-sample.ts +6 -1
- package/src/monitoring/plugin-auto-update.ts +359 -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 +12 -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/index.ts +8 -0
- package/src/plugin-api/webhook-url.ts +151 -0
- package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -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/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 +17 -8
- package/src/plugins/installed-plugin-dirs.ts +101 -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 +67 -0
- 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__/resolve.test.ts +187 -6
- package/src/providers/speech-to-text/deepgram.ts +1 -0
- package/src/providers/speech-to-text/resolve.ts +80 -10
- 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/agent-wake.ts +63 -24
- package/src/runtime/assistant-event-hub.ts +87 -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 +11 -9
- 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 +173 -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__/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-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 +23 -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 +28 -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/notification-routes.ts +0 -14
- package/src/runtime/routes/oauth-providers.ts +1 -0
- package/src/runtime/routes/plugins-routes.ts +106 -1
- 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/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/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/daemon-batch-transcriber.ts +8 -6
- 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 +302 -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/usage/__tests__/subagent-attribution.test.ts +109 -0
- package/src/usage/subagent-attribution.ts +108 -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/schedule-source-key.ts +23 -0
- 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/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
- package/src/workspace/migrations/registry.ts +4 -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/notifications/deferred-emit.ts +0 -147
|
@@ -10,17 +10,29 @@
|
|
|
10
10
|
* (see the external plugin loader's tool walk).
|
|
11
11
|
* - `skills/<id>/SKILL.md` → a skill owned by the plugin (see the skills
|
|
12
12
|
* catalog's `discoverPluginResidentSkills`).
|
|
13
|
+
* - `schedules/<name>/` → a declared schedule (see the daemon's plugin
|
|
14
|
+
* schedule declaration parser).
|
|
13
15
|
*
|
|
14
16
|
* This module re-derives those same sets so `plugins inspect` can report exactly
|
|
15
17
|
* what a plugin contributes. Detection is intentionally a self-contained walk of
|
|
16
|
-
* the install tree
|
|
17
|
-
* skills catalog
|
|
18
|
-
* the runtime actually loads.
|
|
18
|
+
* the install tree (`cli/lib` does not reach into the daemon-internal loader,
|
|
19
|
+
* skills catalog, or schedule parser), but it mirrors their conventions so
|
|
20
|
+
* inspect agrees with what the runtime actually loads.
|
|
19
21
|
*/
|
|
20
22
|
|
|
21
|
-
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
23
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
22
24
|
import { join } from "node:path";
|
|
23
25
|
|
|
26
|
+
/** A schedule the plugin declares under `schedules/`. */
|
|
27
|
+
export interface PluginScheduleSurface {
|
|
28
|
+
/** Schedule name: the declaration directory's name. */
|
|
29
|
+
readonly name: string;
|
|
30
|
+
/** Raw schedule `expression` string from the declaration's config. */
|
|
31
|
+
readonly cadence: string;
|
|
32
|
+
/** `execute` for a markdown prompt entrypoint, `script` for `index.sh`. */
|
|
33
|
+
readonly mode: "execute" | "script";
|
|
34
|
+
}
|
|
35
|
+
|
|
24
36
|
/** The surfaces an installed plugin contributes, each sorted and de-duplicated. */
|
|
25
37
|
export interface PluginSurfaces {
|
|
26
38
|
/** Skill ids shipped at `skills/<id>/SKILL.md`. */
|
|
@@ -36,6 +48,18 @@ export interface PluginSurfaces {
|
|
|
36
48
|
* importing and executing untrusted plugin code, which inspection avoids.
|
|
37
49
|
*/
|
|
38
50
|
readonly tools: readonly string[];
|
|
51
|
+
/**
|
|
52
|
+
* Schedules declared under `schedules/`, each a `<name>/` directory with a
|
|
53
|
+
* `config.json` plus exactly one `index.md` (`execute`) or `index.sh`
|
|
54
|
+
* (`script`) entrypoint. This is a display surface, not the arming path:
|
|
55
|
+
* a file directly under `schedules/` and structurally malformed directories
|
|
56
|
+
* (a bad entrypoint set, an empty prompt body, frontmatter in `index.md`, an
|
|
57
|
+
* unreadable config, a missing `expression`) are skipped rather than reported
|
|
58
|
+
* as errors. Detection stays permissive beyond structure: `expression`
|
|
59
|
+
* validity is not checked CLI-side, so a declaration whose expression the
|
|
60
|
+
* daemon rejects is still listed here.
|
|
61
|
+
*/
|
|
62
|
+
readonly schedules: readonly PluginScheduleSurface[];
|
|
39
63
|
}
|
|
40
64
|
|
|
41
65
|
/**
|
|
@@ -97,6 +121,101 @@ function listSkillIds(skillsDir: string): string[] {
|
|
|
97
121
|
return ids.sort();
|
|
98
122
|
}
|
|
99
123
|
|
|
124
|
+
/** Matches a `---` delimited YAML frontmatter block at the start of a file. */
|
|
125
|
+
const FRONTMATTER_REGEX = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
|
|
126
|
+
|
|
127
|
+
/** Read the raw `expression` string from a parsed schedule config, or `null`. */
|
|
128
|
+
function readConfigExpression(config: unknown): string | null {
|
|
129
|
+
if (typeof config !== "object" || config === null || Array.isArray(config)) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const expression = (config as Record<string, unknown>).expression;
|
|
133
|
+
return typeof expression === "string" && expression.trim() !== ""
|
|
134
|
+
? expression
|
|
135
|
+
: null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Read a `<name>/` directory declaration: `config.json` supplies the cadence
|
|
140
|
+
* and the single `index.md`/`index.sh` entrypoint decides the mode. `null` for
|
|
141
|
+
* anything the loader would refuse (zero or multiple `index.*` entries, an
|
|
142
|
+
* unsupported entrypoint, an `index.md` carrying frontmatter or an empty
|
|
143
|
+
* prompt body, an unreadable config, a missing expression).
|
|
144
|
+
*/
|
|
145
|
+
function readDirectorySchedule(
|
|
146
|
+
dirPath: string,
|
|
147
|
+
): { cadence: string; mode: PluginScheduleSurface["mode"] } | null {
|
|
148
|
+
let children;
|
|
149
|
+
try {
|
|
150
|
+
children = readdirSync(dirPath, { withFileTypes: true });
|
|
151
|
+
} catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
const entrypoints = children
|
|
155
|
+
.filter((c) => c.isFile() && c.name.startsWith("index."))
|
|
156
|
+
.map((c) => c.name);
|
|
157
|
+
if (entrypoints.length !== 1) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
const entrypoint = entrypoints[0]!;
|
|
161
|
+
if (entrypoint !== "index.md" && entrypoint !== "index.sh") {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
if (entrypoint === "index.md") {
|
|
165
|
+
let body: string;
|
|
166
|
+
try {
|
|
167
|
+
body = readFileSync(join(dirPath, "index.md"), "utf8");
|
|
168
|
+
} catch {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
// Directory-form config belongs in config.json, so the loader refuses an
|
|
172
|
+
// index.md with frontmatter; it also refuses an empty prompt body.
|
|
173
|
+
if (FRONTMATTER_REGEX.test(body) || !body.trim()) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
let config: unknown;
|
|
178
|
+
try {
|
|
179
|
+
config = JSON.parse(readFileSync(join(dirPath, "config.json"), "utf8"));
|
|
180
|
+
} catch {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
const cadence = readConfigExpression(config);
|
|
184
|
+
if (cadence === null) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
return { cadence, mode: entrypoint === "index.md" ? "execute" : "script" };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* List the schedules a plugin declares under `schedules/`, mirroring the
|
|
192
|
+
* declaration parser's directory-only form. A file directly under
|
|
193
|
+
* `schedules/` is not a declaration, so it is skipped. Returns schedules
|
|
194
|
+
* sorted by name; a missing directory yields `[]`.
|
|
195
|
+
*/
|
|
196
|
+
function listSchedules(schedulesDir: string): PluginScheduleSurface[] {
|
|
197
|
+
let entries;
|
|
198
|
+
try {
|
|
199
|
+
entries = readdirSync(schedulesDir, { withFileTypes: true });
|
|
200
|
+
} catch {
|
|
201
|
+
return [];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const schedules: PluginScheduleSurface[] = [];
|
|
205
|
+
for (const entry of entries) {
|
|
206
|
+
if (entry.name.startsWith(".") || !entry.isDirectory()) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const parsed = readDirectorySchedule(join(schedulesDir, entry.name));
|
|
210
|
+
if (parsed) {
|
|
211
|
+
schedules.push({ name: entry.name, ...parsed });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return schedules.sort((a, b) =>
|
|
215
|
+
a.name < b.name ? -1 : a.name > b.name ? 1 : 0,
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
100
219
|
/**
|
|
101
220
|
* Detect the {@link PluginSurfaces} an installed plugin contributes by walking
|
|
102
221
|
* its install tree at `pluginDir`. Surface types with no contributions come
|
|
@@ -110,5 +229,6 @@ export function detectPluginSurfaces(pluginDir: string): PluginSurfaces {
|
|
|
110
229
|
skills: listSkillIds(join(pluginDir, "skills")),
|
|
111
230
|
hooks: listModuleBasenames(join(pluginDir, "hooks")),
|
|
112
231
|
tools: [...new Set(toolNames)].sort(),
|
|
232
|
+
schedules: listSchedules(join(pluginDir, "schedules")),
|
|
113
233
|
};
|
|
114
234
|
}
|
|
@@ -54,6 +54,8 @@ import {
|
|
|
54
54
|
type PluginLocalInfo,
|
|
55
55
|
} from "./inspect-plugin.js";
|
|
56
56
|
import {
|
|
57
|
+
type ConfirmStagedInstall,
|
|
58
|
+
confirmStagedOrAbort,
|
|
57
59
|
finalizeStagedInstall,
|
|
58
60
|
type GitRunner,
|
|
59
61
|
installPlugin,
|
|
@@ -138,6 +140,14 @@ export interface UpgradePluginDeps {
|
|
|
138
140
|
* for dry runs or no-op upgrades (they never reach the swap).
|
|
139
141
|
*/
|
|
140
142
|
readonly beforeSwap?: () => Promise<void>;
|
|
143
|
+
/**
|
|
144
|
+
* Consent gate between staging and finalize, identical to the install
|
|
145
|
+
* path's ({@link ConfirmStagedInstall}): the caller inspects the staged
|
|
146
|
+
* upgraded tree (e.g. its declared schedules) and may abort before
|
|
147
|
+
* anything replaces the live install. Applies to overwrite and merge
|
|
148
|
+
* upgrades alike; dry runs and no-ops never stage, so it is not invoked.
|
|
149
|
+
*/
|
|
150
|
+
readonly confirmStaged?: ConfirmStagedInstall;
|
|
141
151
|
}
|
|
142
152
|
|
|
143
153
|
/** Result of an upgrade attempt. */
|
|
@@ -401,6 +411,7 @@ export async function upgradePlugin(
|
|
|
401
411
|
runPostinstall: deps.runPostinstall,
|
|
402
412
|
runInstallDeps: deps.runInstallDeps,
|
|
403
413
|
beforeSwap: deps.beforeSwap,
|
|
414
|
+
confirmStaged: deps.confirmStaged,
|
|
404
415
|
},
|
|
405
416
|
);
|
|
406
417
|
|
|
@@ -591,6 +602,7 @@ async function directUpgrade(
|
|
|
591
602
|
runPostinstall: deps.runPostinstall,
|
|
592
603
|
runInstallDeps: deps.runInstallDeps,
|
|
593
604
|
beforeSwap: deps.beforeSwap,
|
|
605
|
+
confirmStaged: deps.confirmStaged,
|
|
594
606
|
},
|
|
595
607
|
);
|
|
596
608
|
|
|
@@ -747,6 +759,12 @@ async function mergeUpgrade(
|
|
|
747
759
|
conflictLabels,
|
|
748
760
|
});
|
|
749
761
|
|
|
762
|
+
// Same staging-to-finalize consent boundary as `installPlugin`: the
|
|
763
|
+
// caller sees the fully merged tree before it replaces the live install.
|
|
764
|
+
// A decline removes the staging dir and throws; the outer catch's rmSync
|
|
765
|
+
// is then a no-op.
|
|
766
|
+
await confirmStagedOrAbort(name, stagingDir, deps.confirmStaged);
|
|
767
|
+
|
|
750
768
|
const toCommit = theirs.commit ?? ctx.toCommit;
|
|
751
769
|
const toTimestamp = theirs.committedAt ?? ctx.toTimestamp;
|
|
752
770
|
await finalizeStagedInstall(stagingDir, {
|
package/src/cli.ts
CHANGED
|
@@ -513,7 +513,7 @@ export async function startCli(): Promise<void> {
|
|
|
513
513
|
if (content === "/conversations") {
|
|
514
514
|
pendingSessionPick = true;
|
|
515
515
|
try {
|
|
516
|
-
const rows = listConversations(20);
|
|
516
|
+
const rows = listConversations({ limit: 20 });
|
|
517
517
|
const conversations = rows.map((r) => ({
|
|
518
518
|
id: r.id,
|
|
519
519
|
title: r.title || "Untitled",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
existsSync,
|
|
3
3
|
mkdirSync,
|
|
4
|
+
readdirSync,
|
|
4
5
|
readFileSync,
|
|
5
6
|
rmSync,
|
|
6
7
|
writeFileSync,
|
|
@@ -267,4 +268,76 @@ describe("deployment-context embedding-provider default (via loadConfig)", () =>
|
|
|
267
268
|
>;
|
|
268
269
|
expect(v3Raw.live).toBe(true);
|
|
269
270
|
});
|
|
271
|
+
|
|
272
|
+
describe("quarantine-reseed carries memory.v3.live forward", () => {
|
|
273
|
+
function removeQuarantineFiles(): void {
|
|
274
|
+
for (const name of readdirSync(WORKSPACE_DIR)) {
|
|
275
|
+
if (name.startsWith("config.json.corrupt-")) {
|
|
276
|
+
rmSync(join(WORKSPACE_DIR, name), { force: true });
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function readV3Raw(): Record<string, unknown> {
|
|
282
|
+
const raw = readConfig();
|
|
283
|
+
return ((raw.memory as Record<string, unknown>).v3 ?? {}) as Record<
|
|
284
|
+
string,
|
|
285
|
+
unknown
|
|
286
|
+
>;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
afterEach(() => {
|
|
290
|
+
removeQuarantineFiles();
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
test("a corrupt live-v3 config is quarantined and the reseed keeps live=true", () => {
|
|
294
|
+
// Truncated mid-write JSON from a memory-v3 assistant: unparseable,
|
|
295
|
+
// but the live flag survives in the raw text.
|
|
296
|
+
writeFileSync(
|
|
297
|
+
CONFIG_PATH,
|
|
298
|
+
`{\n "memory": {\n "v3": {\n "live": true\n }\n },\n "llm": {\n "activeProf`,
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
const config = loadConfig();
|
|
302
|
+
|
|
303
|
+
// The corrupt file was quarantined and the reseeded config carries the
|
|
304
|
+
// tier forward, both in-memory (this boot runs v3) and on disk
|
|
305
|
+
// (migration 105 is checkpointed on existing workspaces and never
|
|
306
|
+
// re-runs, so the persisted value is the only durable record).
|
|
307
|
+
expect(config.memory.v3.live).toBe(true);
|
|
308
|
+
expect(readV3Raw()).toEqual({ live: true });
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
test("a corrupt config without live=true reseeds with the leaf absent", () => {
|
|
312
|
+
writeFileSync(
|
|
313
|
+
CONFIG_PATH,
|
|
314
|
+
`{\n "memory": {\n "v3": {\n "live": false\n }\n },\n "llm": {\n "activeProf`,
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
const config = loadConfig();
|
|
318
|
+
|
|
319
|
+
// Never carry `false` forward: an absent leaf is the only way to keep
|
|
320
|
+
// "no decision recorded" representable for migration 105.
|
|
321
|
+
expect(config.memory.v3.live).toBe(false);
|
|
322
|
+
expect(readV3Raw()).toEqual({});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
test("a deleted config with an earlier live-v3 quarantine still carries live=true", () => {
|
|
326
|
+
if (existsSync(CONFIG_PATH)) {
|
|
327
|
+
rmSync(CONFIG_PATH, { force: true });
|
|
328
|
+
}
|
|
329
|
+
writeFileSync(
|
|
330
|
+
join(
|
|
331
|
+
WORKSPACE_DIR,
|
|
332
|
+
"config.json.corrupt-2026-08-01T10-00-00.000Z.json",
|
|
333
|
+
),
|
|
334
|
+
JSON.stringify({ memory: { v3: { live: true } } }, null, 2),
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
const config = loadConfig();
|
|
338
|
+
|
|
339
|
+
expect(config.memory.v3.live).toBe(true);
|
|
340
|
+
expect(readV3Raw()).toEqual({ live: true });
|
|
341
|
+
});
|
|
342
|
+
});
|
|
270
343
|
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guards over the `memory.retrospective` switches that decide whether the
|
|
3
|
+
* retrospective pass runs at all, and how its fork is materialized.
|
|
4
|
+
*
|
|
5
|
+
* The defaults are the contract: a workspace that says nothing must behave
|
|
6
|
+
* exactly as it did before the fields existed: retrospectives on, forks
|
|
7
|
+
* cloned.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, expect, test } from "bun:test";
|
|
11
|
+
|
|
12
|
+
import { MemoryRetrospectiveConfigSchema } from "../schemas/memory-retrospective.js";
|
|
13
|
+
|
|
14
|
+
describe("memory.retrospective config schema", () => {
|
|
15
|
+
test("an empty block leaves retrospectives on and forks cloning", () => {
|
|
16
|
+
const parsed = MemoryRetrospectiveConfigSchema.parse({});
|
|
17
|
+
expect(parsed.enabled).toBe(true);
|
|
18
|
+
expect(parsed.forkStrategy).toBe("cloning");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("enabled is a boolean-only kill switch", () => {
|
|
22
|
+
expect(
|
|
23
|
+
MemoryRetrospectiveConfigSchema.parse({ enabled: false }).enabled,
|
|
24
|
+
).toBe(false);
|
|
25
|
+
expect(
|
|
26
|
+
MemoryRetrospectiveConfigSchema.safeParse({ enabled: "false" }).success,
|
|
27
|
+
).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("forkStrategy accepts only cloning and reference", () => {
|
|
31
|
+
expect(
|
|
32
|
+
MemoryRetrospectiveConfigSchema.parse({ forkStrategy: "reference" })
|
|
33
|
+
.forkStrategy,
|
|
34
|
+
).toBe("reference");
|
|
35
|
+
expect(
|
|
36
|
+
MemoryRetrospectiveConfigSchema.safeParse({ forkStrategy: "referential" })
|
|
37
|
+
.success,
|
|
38
|
+
).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guards over the `pluginUpdates` config block — the opt-in that decides
|
|
3
|
+
* whether installed plugins move on their own.
|
|
4
|
+
*
|
|
5
|
+
* The defaults are the contract: a workspace that says nothing must behave
|
|
6
|
+
* exactly as it did before the block existed (manual, nothing upgrades), and
|
|
7
|
+
* an opted-in workspace must land on the `theirs` merge strategy.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, expect, test } from "bun:test";
|
|
11
|
+
|
|
12
|
+
import { PluginUpdatesConfigSchema } from "../schemas/plugin-updates.js";
|
|
13
|
+
|
|
14
|
+
describe("pluginUpdates config schema", () => {
|
|
15
|
+
test("defaults are manual / theirs / hourly", () => {
|
|
16
|
+
expect(PluginUpdatesConfigSchema.parse({})).toEqual({
|
|
17
|
+
mode: "manual",
|
|
18
|
+
strategy: "theirs",
|
|
19
|
+
checkIntervalMs: 3_600_000,
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("mode accepts only manual and auto", () => {
|
|
24
|
+
expect(PluginUpdatesConfigSchema.parse({ mode: "auto" }).mode).toBe("auto");
|
|
25
|
+
expect(
|
|
26
|
+
PluginUpdatesConfigSchema.safeParse({ mode: "sometimes" }).success,
|
|
27
|
+
).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("the unattended-hostile `assistant` strategy is not selectable", () => {
|
|
31
|
+
// It resolves conflicts by writing git conflict markers into the plugin's
|
|
32
|
+
// files, which unattended would leave broken code on disk.
|
|
33
|
+
expect(
|
|
34
|
+
PluginUpdatesConfigSchema.safeParse({ strategy: "assistant" }).success,
|
|
35
|
+
).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("sub-5-minute sweep intervals are rejected", () => {
|
|
39
|
+
expect(
|
|
40
|
+
PluginUpdatesConfigSchema.safeParse({ checkIntervalMs: 1_000 }).success,
|
|
41
|
+
).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { profileSupportsTools } from "../profile-tool-support.js";
|
|
4
|
+
import type { AssistantConfig } from "../schema.js";
|
|
5
|
+
import { LLMSchema } from "../schemas/llm.js";
|
|
6
|
+
|
|
7
|
+
/** An `AssistantConfig` carrying nothing the profile lookup does not read. */
|
|
8
|
+
function configWithProfiles(
|
|
9
|
+
profiles: Record<string, Record<string, unknown>>,
|
|
10
|
+
): AssistantConfig {
|
|
11
|
+
return { llm: LLMSchema.parse({ profiles }) } as AssistantConfig;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("profileSupportsTools", () => {
|
|
15
|
+
test("reports false only for a model the catalog declares tool-less", () => {
|
|
16
|
+
const config = configWithProfiles({
|
|
17
|
+
"no-tools": { provider: "openrouter", model: "minimax/minimax-01" },
|
|
18
|
+
});
|
|
19
|
+
expect(profileSupportsTools("no-tools", config)).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("reports true for a catalog model declared tool-capable", () => {
|
|
23
|
+
const config = configWithProfiles({
|
|
24
|
+
"with-tools": { provider: "anthropic", model: "claude-fable-5" },
|
|
25
|
+
});
|
|
26
|
+
expect(profileSupportsTools("with-tools", config)).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("fails open for a BYOK model the catalog has never seen", () => {
|
|
30
|
+
const config = configWithProfiles({
|
|
31
|
+
byok: { provider: "openrouter", model: "acme/private-llm-9" },
|
|
32
|
+
});
|
|
33
|
+
expect(profileSupportsTools("byok", config)).toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("fails open for a profile key that resolves to nothing", () => {
|
|
37
|
+
expect(profileSupportsTools("not-a-profile", configWithProfiles({}))).toBe(
|
|
38
|
+
undefined,
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("verdicts a catalog default profile through the code catalog", () => {
|
|
43
|
+
// `balanced` carries no workspace body, so the answer has to come from the
|
|
44
|
+
// resolved default-profile catalog rather than `llm.profiles`.
|
|
45
|
+
expect(profileSupportsTools("balanced", configWithProfiles({}))).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("reports false for a mix whose every arm is catalog-denied", () => {
|
|
49
|
+
const config = configWithProfiles({
|
|
50
|
+
"no-tools": { provider: "openrouter", model: "minimax/minimax-01" },
|
|
51
|
+
"no-tools-too": {
|
|
52
|
+
provider: "openrouter",
|
|
53
|
+
model: "minimax/minimax-m2-her",
|
|
54
|
+
},
|
|
55
|
+
blend: {
|
|
56
|
+
mix: [
|
|
57
|
+
{ profile: "no-tools", weight: 1 },
|
|
58
|
+
{ profile: "no-tools-too", weight: 1 },
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
// Whichever arm the child's seed lands on, it cannot call tools.
|
|
63
|
+
expect(profileSupportsTools("blend", config)).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("reports true for a mix whose every arm is catalog-capable", () => {
|
|
67
|
+
const config = configWithProfiles({
|
|
68
|
+
"tools-a": { provider: "anthropic", model: "claude-fable-5" },
|
|
69
|
+
"tools-b": {
|
|
70
|
+
provider: "anthropic",
|
|
71
|
+
model: "claude-haiku-4-5-20251001",
|
|
72
|
+
},
|
|
73
|
+
blend: {
|
|
74
|
+
mix: [
|
|
75
|
+
{ profile: "tools-a", weight: 3 },
|
|
76
|
+
{ profile: "tools-b", weight: 1 },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
expect(profileSupportsTools("blend", config)).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("fails open for a mix of tool-capable and tool-less arms", () => {
|
|
84
|
+
const config = configWithProfiles({
|
|
85
|
+
"no-tools": { provider: "openrouter", model: "minimax/minimax-01" },
|
|
86
|
+
"with-tools": { provider: "anthropic", model: "claude-fable-5" },
|
|
87
|
+
blend: {
|
|
88
|
+
mix: [
|
|
89
|
+
{ profile: "no-tools", weight: 1 },
|
|
90
|
+
{ profile: "with-tools", weight: 1 },
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
// The arm is picked from the child conversation's seed, and no such
|
|
95
|
+
// conversation exists yet, so neither arm's verdict speaks for the mix.
|
|
96
|
+
expect(profileSupportsTools("blend", config)).toBeUndefined();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("fails open for a mix with an arm the catalog has never seen", () => {
|
|
100
|
+
const config = configWithProfiles({
|
|
101
|
+
"no-tools": { provider: "openrouter", model: "minimax/minimax-01" },
|
|
102
|
+
byok: { provider: "openrouter", model: "acme/private-llm-9" },
|
|
103
|
+
blend: {
|
|
104
|
+
mix: [
|
|
105
|
+
{ profile: "no-tools", weight: 1 },
|
|
106
|
+
{ profile: "byok", weight: 1 },
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
expect(profileSupportsTools("blend", config)).toBeUndefined();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("answers a mixed-capability mix identically on every call", () => {
|
|
114
|
+
const config = configWithProfiles({
|
|
115
|
+
"no-tools": { provider: "openrouter", model: "minimax/minimax-01" },
|
|
116
|
+
"with-tools": { provider: "anthropic", model: "claude-fable-5" },
|
|
117
|
+
blend: {
|
|
118
|
+
mix: [
|
|
119
|
+
{ profile: "no-tools", weight: 1 },
|
|
120
|
+
{ profile: "with-tools", weight: 1 },
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
// No seed is available at probe time, so the verdict must not ride on a
|
|
125
|
+
// random arm pick.
|
|
126
|
+
const verdicts = new Set(
|
|
127
|
+
Array.from({ length: 50 }, () => profileSupportsTools("blend", config)),
|
|
128
|
+
);
|
|
129
|
+
expect([...verdicts]).toEqual([undefined]);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -8,7 +8,7 @@ Each executor is a module exporting `run(input, context)` (the `SkillToolScript`
|
|
|
8
8
|
|
|
9
9
|
## Keeping public docs in sync
|
|
10
10
|
|
|
11
|
-
A bundled skill's `SKILL.md` is its behavioral source of truth. Skills with a public reference page (`https://www.vellum.ai/docs/skills-reference/<slug>`, authored in
|
|
11
|
+
A bundled skill's `SKILL.md` is its behavioral source of truth. Skills with a public reference page (`https://www.vellum.ai/docs/skills-reference/<slug>`, authored in this repo at `clients/docs/src/app/docs/_components/skills-reference-<slug>-content.tsx`) are fingerprinted in `scripts/skill-docs-sync.manifest.json` and enforced by `skill-docs-sync-guard.test.ts`.
|
|
12
12
|
|
|
13
13
|
When you change a documented skill's `SKILL.md`, the guard fails until you reconcile it:
|
|
14
14
|
|
|
@@ -75,7 +75,7 @@ Every app is multi-file TSX (`formatVersion: 2`). Never write a root-level `inde
|
|
|
75
75
|
|
|
76
76
|
## Responsive & design system
|
|
77
77
|
|
|
78
|
-
Every app works phone (~360px) to desktop (~1400px+). The `<turn_context>` block carries a `client_os:` field (the OS the user is on): `ios`/`android` → mobile-first (design narrow first, body 17px); `macos`/`web` → desktop-first (multi-column, body 14px); absent → desktop-first unless the request implies phone use ("for my iPhone"). (The sibling `interface:` field is the transport surface
|
|
78
|
+
Every app works phone (~360px) to desktop (~1400px+). The `<turn_context>` block carries a `client_os:` field (the OS the user is on): `ios`/`android` → mobile-first (design narrow first, body 17px); `macos`/`windows`/`web` → desktop-first (multi-column, body 14px); absent → desktop-first unless the request implies phone use ("for my iPhone"). (The sibling `interface:` field is the transport surface, always `web` for the apps, so key layout off `client_os`, not `interface`.)
|
|
79
79
|
|
|
80
80
|
**Universal baseline — every build, regardless of client_os:**
|
|
81
81
|
- Viewport meta: `width=device-width, initial-scale=1, viewport-fit=cover`. Never `user-scalable=no` (blocks accessibility zoom).
|
|
@@ -4,12 +4,12 @@ Every app must work across phone (~360px) to desktop (~1400px+).
|
|
|
4
4
|
|
|
5
5
|
## Mode selection
|
|
6
6
|
|
|
7
|
-
The conversation context's `<turn_context>` block carries a `client_os:` field
|
|
7
|
+
The conversation context's `<turn_context>` block carries a `client_os:` field, the OS the user is on. (Key layout off this, not the sibling `interface:` field: `interface:` is the transport surface and is always `web` for the web/iOS/macOS/Windows apps.)
|
|
8
8
|
|
|
9
9
|
**If `client_os: ios` or `android`** (any mobile-web surface):
|
|
10
10
|
→ Mobile-first build. Design the narrow viewport first, enhance upward.
|
|
11
11
|
|
|
12
|
-
**If `client_os: macos` or `web`**:
|
|
12
|
+
**If `client_os: macos`, `windows`, or `web`**:
|
|
13
13
|
→ Desktop-first build. Design larger composition first; narrow fallback still meets the universal baseline below.
|
|
14
14
|
|
|
15
15
|
**If field is absent or ambiguous**:
|
|
@@ -52,6 +52,6 @@ The conversation context's `<turn_context>` block carries a `client_os:` field
|
|
|
52
52
|
- Bottom-anchor the primary action: `position: sticky; bottom: env(safe-area-inset-bottom)`.
|
|
53
53
|
- Replace side modals and popovers with bottom sheets.
|
|
54
54
|
|
|
55
|
-
## Desktop-first priorities (`client_os: macos` / `web`)
|
|
55
|
+
## Desktop-first priorities (`client_os: macos` / `windows` / `web`)
|
|
56
56
|
|
|
57
57
|
Multi-column composition, hover-rich affordances, denser information, side modals, inline primary actions. The universal baseline above is still the floor — narrow view must still work.
|
|
@@ -121,7 +121,11 @@ assistant conversations wake "$id" --hint "Summarize the new items" --external-c
|
|
|
121
121
|
|
|
122
122
|
## Inference Profile
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
Every schedule carries a pinned `inference_profile` (a key from `llm.profiles`), so a recurring task keeps running on the model (and the price) it was created under even when the user later changes their default profile. Creating a schedule without `inference_profile` pins it to the user's current default; pass one explicitly when a task should run on a specific model, e.g. a cost-optimized profile for a high-frequency digest. Passing `inference_profile: null` on update re-pins the schedule to the user's current default rather than unpinning it. The pinned profile is shown on the schedule's details page in settings.
|
|
125
|
+
|
|
126
|
+
The pin governs the agent turns a schedule runs: an execute-mode run, a wake-mode run, and the turns a script-mode schedule hands off to the agent loop with `assistant conversations wake`. The schedule id travels in the script's environment, so those handoff turns run on the pinned profile with no flag to pass. Notify-mode schedules run no agent turn at all, so their pin never comes into play.
|
|
127
|
+
|
|
128
|
+
Workflow-mode schedules are the exception: each step of a workflow resolves its own model, so a workflow schedule's pin does not govern its runs.
|
|
125
129
|
|
|
126
130
|
## Conversation Group
|
|
127
131
|
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
},
|
|
111
111
|
"inference_profile": {
|
|
112
112
|
"type": "string",
|
|
113
|
-
"description": "Inference profile (a key from llm.profiles) the schedule's LLM-executed runs should use, e.g. to run a heavy task on a cheaper model. When omitted,
|
|
113
|
+
"description": "Inference profile (a key from llm.profiles) the schedule's LLM-executed runs should use, e.g. to run a heavy task on a cheaper model. When omitted, the schedule is pinned to the user's current default profile so its model does not change later. Must name a configured profile. Workflow-mode schedules resolve a model per workflow step, so the pin does not govern their runs."
|
|
114
114
|
},
|
|
115
115
|
"group": {
|
|
116
116
|
"type": "string",
|
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
},
|
|
234
234
|
"inference_profile": {
|
|
235
235
|
"type": ["string", "null"],
|
|
236
|
-
"description": "Inference profile (a key from llm.profiles) the schedule's LLM-executed runs should use. Pass null to
|
|
236
|
+
"description": "Inference profile (a key from llm.profiles) the schedule's LLM-executed runs should use. Pass null to re-pin the schedule to the user's current default profile. Must name a configured profile. Workflow-mode schedules resolve a model per workflow step, so the pin does not govern their runs."
|
|
237
237
|
},
|
|
238
238
|
"group": {
|
|
239
239
|
"type": ["string", "null"],
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"tools": [
|
|
4
4
|
{
|
|
5
5
|
"name": "voice_config_update",
|
|
6
|
-
"description": "Update a voice configuration setting. Use tts_provider / stt_provider to switch the active TTS / STT provider. Provider \"vellum\" is Vellum-managed speech (billed to your organization; requires a Vellum platform connection via 'assistant platform connect'); any other provider uses the user's own API key. Valid TTS providers come from the provider catalog (vellum, elevenlabs, fish-audio, deepgram, xai); valid STT providers: vellum, deepgram, google-gemini, openai-whisper, xai. Use tts_voice_id to change the voice; it targets whichever TTS provider is currently active. For elevenlabs, pass an ElevenLabs voice ID. For vellum (managed), pass a managed voice model ID: this may be an ElevenLabs voice ID (managed speech serves the same ElevenLabs voices) or a Deepgram Aura model ID (e.g. aura-2-thalia-en); only rate-carded voices synthesize, so prefer models from the managed catalog (daemon route GET tts/managed-voices, also used by the web voice picker). For deepgram, pass a Deepgram Aura model ID. Use fish_audio_reference_id for Fish Audio voice reference. Use stt_language to set the spoken language for speech recognition: one of the
|
|
6
|
+
"description": "Update a voice configuration setting. Use tts_provider / stt_provider to switch the active TTS / STT provider. Provider \"vellum\" is Vellum-managed speech (billed to your organization; requires a Vellum platform connection via 'assistant platform connect'); any other provider uses the user's own API key. Valid TTS providers come from the provider catalog (vellum, elevenlabs, fish-audio, deepgram, xai); valid STT providers: vellum, deepgram, google-gemini, openai-whisper, xai. Use tts_voice_id to change the voice; it targets whichever TTS provider is currently active. For elevenlabs, pass an ElevenLabs voice ID. For vellum (managed), pass a managed voice model ID: this may be an ElevenLabs voice ID (managed speech serves the same ElevenLabs voices) or a Deepgram Aura model ID (e.g. aura-2-thalia-en); only rate-carded voices synthesize, so prefer models from the managed catalog (daemon route GET tts/managed-voices, also used by the web voice picker). For deepgram, pass a Deepgram Aura model ID. Use fish_audio_reference_id for Fish Audio voice reference. Use stt_language to set the spoken language for speech recognition: one of the 50 base language codes on the verified Deepgram nova-3 monolingual roster (e.g. en, es, hi, ta, zh, ko), or \"multi\" for code-switching mid-sentence across its 10-language roster (English, Spanish, French, German, Hindi, Russian, Portuguese, Japanese, Italian, Dutch; e.g. Hinglish); plain language names like \"tamil\" or \"multilingual\" are accepted and normalized. Accepted values follow the configured STT provider: vellum-managed and deepgram accept the full roster plus \"multi\"; xai accepts only the 10 multilingual-roster codes (en, es, fr, de, hi, ru, pt, ja, it, nl) and rejects \"multi\" and the extended codes (both are verified for Deepgram nova-3 only); google-gemini / openai-whisper auto-detect natively, so the value persists but is ignored while they are active. Deepgram uses the same API key for TTS and STT. Changes persist to services.stt / services.tts config and take effect immediately.",
|
|
7
7
|
"category": "system",
|
|
8
8
|
"risk": "low",
|
|
9
9
|
"input_schema": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"description": "The voice setting to change. tts_provider / stt_provider select the active provider for each service (\"vellum\" = Vellum-managed speech; anything else = the user's own API key). tts_voice_id sets the voice for the currently active TTS provider (ElevenLabs voice ID for elevenlabs; a managed voice model ID for vellum, meaning an ElevenLabs voice ID or a Deepgram Aura model ID like aura-2-thalia-en; a Deepgram Aura model ID for deepgram; voice ID for xai). fish_audio_reference_id sets the Fish Audio voice reference. stt_language sets the spoken language for speech recognition (vellum-managed/deepgram: the full roster plus \"multi\"; xai: only the 10 multilingual-roster codes, with \"multi\" and the extended codes rejected; google-gemini and openai-whisper auto-detect and ignore it). Deepgram shares one API key across TTS and STT."
|
|
24
24
|
},
|
|
25
25
|
"value": {
|
|
26
|
-
"description": "The new value for the setting. For tts_provider: one of vellum, elevenlabs, fish-audio, deepgram, xai. For stt_provider: one of vellum, deepgram, google-gemini, openai-whisper, xai. For tts_voice_id: a voice ID for the active TTS provider: an alphanumeric ElevenLabs voice ID (elevenlabs), a managed voice model ID which may be an ElevenLabs voice ID or a Deepgram Aura model ID like aura-2-thalia-en (vellum), or a Deepgram Aura model ID (deepgram). For fish_audio_reference_id: a Fish Audio voice reference ID. For stt_language: one of the
|
|
26
|
+
"description": "The new value for the setting. For tts_provider: one of vellum, elevenlabs, fish-audio, deepgram, xai. For stt_provider: one of vellum, deepgram, google-gemini, openai-whisper, xai. For tts_voice_id: a voice ID for the active TTS provider: an alphanumeric ElevenLabs voice ID (elevenlabs), a managed voice model ID which may be an ElevenLabs voice ID or a Deepgram Aura model ID like aura-2-thalia-en (vellum), or a Deepgram Aura model ID (deepgram). For fish_audio_reference_id: a Fish Audio voice reference ID. For stt_language: one of the 50 base codes on the nova-3 monolingual roster (e.g. en, es, hi, ta, zh, ko), or multi (code-switching across its 10-language roster); language names like \"hindi\", \"tamil\", or \"multilingual\" are also accepted and normalized; when the configured STT provider is xai, only the 10 multilingual-roster codes (en, es, fr, de, hi, ru, pt, ja, it, nl) are accepted. For conversation_timeout: seconds (5, 10, 15, 30, or 60). For activation_key: key identifier string."
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
},
|