@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
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
} from "../../persistence/llm-usage-store.js";
|
|
18
18
|
import { isDeferSchedule } from "../../schedule/defer-provenance.js";
|
|
19
19
|
import { validateScheduleInferenceProfile } from "../../schedule/inference-profile.js";
|
|
20
|
+
import { declarationExistsOnDisk } from "../../schedule/plugin-schedule-declarations.js";
|
|
21
|
+
import { isPluginSchedulesEnabled } from "../../schedule/plugin-schedules-gate.js";
|
|
20
22
|
import {
|
|
21
23
|
describeRRuleExpression,
|
|
22
24
|
isSingleFireRRule,
|
|
@@ -39,6 +41,7 @@ import {
|
|
|
39
41
|
listSchedules,
|
|
40
42
|
resolveScheduleConversationGroupId,
|
|
41
43
|
type ScheduleJob,
|
|
44
|
+
setUserEnabled,
|
|
42
45
|
updateSchedule,
|
|
43
46
|
} from "../../schedule/schedule-store.js";
|
|
44
47
|
import { getScheduleUsageSummaries } from "../../schedule/schedule-usage-store.js";
|
|
@@ -135,7 +138,24 @@ const scheduleSchema = z.object({
|
|
|
135
138
|
reuseConversation: z.boolean(),
|
|
136
139
|
wakeConversationId: z.string().nullable(),
|
|
137
140
|
workflowName: z.string().nullable(),
|
|
141
|
+
sourceKey: z
|
|
142
|
+
.string()
|
|
143
|
+
.nullable()
|
|
144
|
+
.describe(
|
|
145
|
+
"Plugin declaration this schedule mirrors (plugin:<pluginName>/<scheduleName>); null for user-created schedules",
|
|
146
|
+
),
|
|
147
|
+
userEnabled: z
|
|
148
|
+
.boolean()
|
|
149
|
+
.nullable()
|
|
150
|
+
.describe(
|
|
151
|
+
"User enable/disable override on a plugin-sourced schedule; null when the declaration's own enabled value applies. Always null for user-created schedules.",
|
|
152
|
+
),
|
|
138
153
|
isOneShot: z.boolean(),
|
|
154
|
+
// A deferred wake ("remind me about this tomorrow") is an ordinary schedule
|
|
155
|
+
// row created by the defer path, distinguishable only by `createdBy`, which
|
|
156
|
+
// is not otherwise projected. Clients need it to separate the user's named
|
|
157
|
+
// schedules from their reminders when listing what a change affects.
|
|
158
|
+
isDeferred: z.boolean(),
|
|
139
159
|
});
|
|
140
160
|
|
|
141
161
|
const scheduleRunSchema = z.object({
|
|
@@ -218,6 +238,15 @@ function getCadenceDescription(
|
|
|
218
238
|
return describeRRuleExpression(job.cronExpression);
|
|
219
239
|
}
|
|
220
240
|
|
|
241
|
+
/**
|
|
242
|
+
* Whether a schedule still has a firing ahead of it. `fired` and `cancelled`
|
|
243
|
+
* are the two terminal states a one-shot lands in; everything else (including
|
|
244
|
+
* a disabled row, which fires again once re-enabled) can still run.
|
|
245
|
+
*/
|
|
246
|
+
function canScheduleStillRun(job: Pick<ScheduleJob, "status">): boolean {
|
|
247
|
+
return job.status !== "fired" && job.status !== "cancelled";
|
|
248
|
+
}
|
|
249
|
+
|
|
221
250
|
/**
|
|
222
251
|
* Presentation-layer one-shot flag. A COUNT=1 rrule fires exactly once and
|
|
223
252
|
* should read as one-time in clients, even though the scheduler internally
|
|
@@ -271,13 +300,19 @@ function serializeSchedule(
|
|
|
271
300
|
reuseConversation: j.reuseConversation,
|
|
272
301
|
wakeConversationId: j.wakeConversationId,
|
|
273
302
|
workflowName: j.workflowName,
|
|
303
|
+
sourceKey: j.sourceKey,
|
|
304
|
+
userEnabled: j.userEnabled,
|
|
274
305
|
isOneShot: isOneShotForDisplay(j),
|
|
306
|
+
isDeferred: isDeferSchedule(j.createdBy),
|
|
275
307
|
};
|
|
276
308
|
}
|
|
277
309
|
|
|
278
310
|
function handleListSchedules(queryParams: Record<string, string>) {
|
|
279
311
|
const includeAll = queryParams.include_all === "true";
|
|
280
|
-
const
|
|
312
|
+
const inferenceProfile = queryParams.inference_profile?.trim();
|
|
313
|
+
const jobs = listSchedules(
|
|
314
|
+
inferenceProfile ? { inferenceProfile } : undefined,
|
|
315
|
+
);
|
|
281
316
|
const filtered = includeAll
|
|
282
317
|
? jobs
|
|
283
318
|
: jobs.filter((j) => !isDeferSchedule(j.createdBy));
|
|
@@ -300,6 +335,88 @@ function handleGetSchedule(id: string) {
|
|
|
300
335
|
return { schedule: serializeSchedule(job, new Map()) };
|
|
301
336
|
}
|
|
302
337
|
|
|
338
|
+
/**
|
|
339
|
+
* Move schedules onto the `to` inference profile.
|
|
340
|
+
*
|
|
341
|
+
* `from` narrows the move to the schedules pinned to that profile. It is the
|
|
342
|
+
* companion to deleting an inference profile: without it the profile's
|
|
343
|
+
* schedules keep a pin that no longer names anything. The dangling pin is not
|
|
344
|
+
* fatal (the resolver drops a missing override and falls through to the call
|
|
345
|
+
* site's own selection), so this exists to keep the user's stated model choice
|
|
346
|
+
* rather than to prevent a failure.
|
|
347
|
+
*
|
|
348
|
+
* Omitting `from` selects every schedule that can still run, which is what
|
|
349
|
+
* re-pinning the whole set onto the current default needs: schedules pinned by
|
|
350
|
+
* earlier defaults name several different profiles, so there is no single
|
|
351
|
+
* source to move from. A one-shot that already fired and a cancelled row are
|
|
352
|
+
* left out: their profile is history, and rewriting them would report a move
|
|
353
|
+
* larger than the set the user was looking at. An explicit `from` still
|
|
354
|
+
* selects exactly the rows pinned to it, dead or not, since a deleted profile
|
|
355
|
+
* has to be swept out of every row that names it. Rows already pinned to `to`
|
|
356
|
+
* are skipped either way, so the returned count is the number of schedules
|
|
357
|
+
* whose model actually changed.
|
|
358
|
+
*
|
|
359
|
+
* Each row goes through `updateSchedule`, so the store's profile validation
|
|
360
|
+
* and re-snapshot semantics apply exactly as they do to a single-row PATCH.
|
|
361
|
+
* Deferred-wake rows are moved too, since a defer inherits the profile of the
|
|
362
|
+
* conversation it was created in and would otherwise be the one row left
|
|
363
|
+
* dangling. Callers that warn a user before deleting a profile must count
|
|
364
|
+
* those rows as well, which is what `include_all` plus the serialized
|
|
365
|
+
* `isDeferred` flag on the list route are for. Moving one is a guardian-owned
|
|
366
|
+
* state change, so the whole call requires owner authority as soon as a wake
|
|
367
|
+
* row is in the selected set.
|
|
368
|
+
*/
|
|
369
|
+
async function handleReassignScheduleInferenceProfile(
|
|
370
|
+
body: Record<string, unknown>,
|
|
371
|
+
headers?: Record<string, string>,
|
|
372
|
+
) {
|
|
373
|
+
const hasFrom = body.from !== undefined && body.from !== null;
|
|
374
|
+
const from = typeof body.from === "string" ? body.from.trim() : "";
|
|
375
|
+
const to = typeof body.to === "string" ? body.to.trim() : "";
|
|
376
|
+
if (hasFrom && !from) {
|
|
377
|
+
throw new BadRequestError(
|
|
378
|
+
"from must name an inference profile when provided",
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
if (!to) {
|
|
382
|
+
throw new BadRequestError("to is required");
|
|
383
|
+
}
|
|
384
|
+
// `to` must name a configured profile; `from` deliberately is not validated
|
|
385
|
+
// so an already-deleted profile's leftover pins can still be swept up.
|
|
386
|
+
const profileError = validateScheduleInferenceProfile(to);
|
|
387
|
+
if (profileError) {
|
|
388
|
+
throw new BadRequestError(profileError);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const selected = hasFrom
|
|
392
|
+
? listSchedules({ inferenceProfile: from })
|
|
393
|
+
: listSchedules().filter(canScheduleStillRun);
|
|
394
|
+
const matches = selected.filter((job) => job.inferenceProfile !== to);
|
|
395
|
+
// The guard depends only on the caller, so its answer is the same for every
|
|
396
|
+
// row: settle it once for the whole set. Checking per row would spend a
|
|
397
|
+
// cache-bypassing gateway round trip per matching reminder, and a profile
|
|
398
|
+
// that many reminders point at would take seconds to move or time out.
|
|
399
|
+
// All-or-nothing either way: one wake row in scope refuses the whole call
|
|
400
|
+
// before anything moves.
|
|
401
|
+
const wakeMatch = matches.find((job) => job.mode === "wake") ?? null;
|
|
402
|
+
await assertWakeMutationAllowed(wakeMatch, undefined, headers);
|
|
403
|
+
|
|
404
|
+
let reassigned = 0;
|
|
405
|
+
for (const job of matches) {
|
|
406
|
+
const updated = await updateSchedule(job.id, { inferenceProfile: to });
|
|
407
|
+
if (updated) {
|
|
408
|
+
reassigned += 1;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (reassigned > 0) {
|
|
412
|
+
log.info(
|
|
413
|
+
{ from: hasFrom ? from : null, to, reassigned },
|
|
414
|
+
"Schedules reassigned to new profile",
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
return { reassigned };
|
|
418
|
+
}
|
|
419
|
+
|
|
303
420
|
async function handleCreateSchedule(body: Record<string, unknown>) {
|
|
304
421
|
const name = typeof body.name === "string" ? body.name.trim() : "";
|
|
305
422
|
const expression =
|
|
@@ -382,6 +499,7 @@ async function handleCreateSchedule(body: Record<string, unknown>) {
|
|
|
382
499
|
timezone,
|
|
383
500
|
expression: normalized.expression,
|
|
384
501
|
syntax: normalized.syntax,
|
|
502
|
+
inferenceProfile,
|
|
385
503
|
});
|
|
386
504
|
log.info(
|
|
387
505
|
{ id: job.id, name: job.name, workflowName },
|
|
@@ -420,6 +538,7 @@ async function handleCreateSchedule(body: Record<string, unknown>) {
|
|
|
420
538
|
expression: normalized.expression,
|
|
421
539
|
syntax: normalized.syntax,
|
|
422
540
|
timeoutMs,
|
|
541
|
+
inferenceProfile,
|
|
423
542
|
});
|
|
424
543
|
log.info({ id: job.id, name: job.name }, "Script schedule created");
|
|
425
544
|
return { schedule: serializeSchedule(job, new Map()) };
|
|
@@ -468,7 +587,9 @@ async function handleToggleSchedule(
|
|
|
468
587
|
// enabled, with no further caller involvement.
|
|
469
588
|
await assertWakeMutationAllowed(getSchedule(id), undefined, headers);
|
|
470
589
|
|
|
471
|
-
|
|
590
|
+
// One endpoint serves both kinds of row: imperative schedules take the
|
|
591
|
+
// plain enabled write, plugin-sourced ones record the user_enabled override.
|
|
592
|
+
const updated = await setUserEnabled(id, enabled);
|
|
472
593
|
if (!updated) {
|
|
473
594
|
throw new NotFoundError("Schedule not found");
|
|
474
595
|
}
|
|
@@ -481,7 +602,18 @@ async function handleDeleteSchedule(
|
|
|
481
602
|
headers?: Record<string, string>,
|
|
482
603
|
) {
|
|
483
604
|
await assertWakeMutationAllowed(getSchedule(id), undefined, headers);
|
|
484
|
-
|
|
605
|
+
let removed: boolean;
|
|
606
|
+
try {
|
|
607
|
+
removed = await deleteSchedule(id);
|
|
608
|
+
} catch (err) {
|
|
609
|
+
// Store-layer refusals (e.g. plugin-sourced rows, which only the plugin's
|
|
610
|
+
// schedule file can remove) are caller mistakes with an actionable
|
|
611
|
+
// message, not daemon faults.
|
|
612
|
+
if (err instanceof UserError) {
|
|
613
|
+
throw new BadRequestError(err.message);
|
|
614
|
+
}
|
|
615
|
+
throw err;
|
|
616
|
+
}
|
|
485
617
|
if (!removed) {
|
|
486
618
|
throw new NotFoundError("Schedule not found");
|
|
487
619
|
}
|
|
@@ -494,7 +626,18 @@ async function handleCancelSchedule(
|
|
|
494
626
|
headers?: Record<string, string>,
|
|
495
627
|
) {
|
|
496
628
|
await assertWakeMutationAllowed(getSchedule(id), undefined, headers);
|
|
497
|
-
|
|
629
|
+
let cancelled: boolean;
|
|
630
|
+
try {
|
|
631
|
+
cancelled = await cancelSchedule(id);
|
|
632
|
+
} catch (err) {
|
|
633
|
+
// Store-layer refusals (plugin-sourced rows, for which cancellation is a
|
|
634
|
+
// permanent latch) are caller mistakes with an actionable message, not
|
|
635
|
+
// daemon faults.
|
|
636
|
+
if (err instanceof UserError) {
|
|
637
|
+
throw new BadRequestError(err.message);
|
|
638
|
+
}
|
|
639
|
+
throw err;
|
|
640
|
+
}
|
|
498
641
|
if (!cancelled) {
|
|
499
642
|
throw new NotFoundError("Schedule not found or not cancellable");
|
|
500
643
|
}
|
|
@@ -625,8 +768,8 @@ async function handleUpdateSchedule(
|
|
|
625
768
|
}
|
|
626
769
|
}
|
|
627
770
|
|
|
628
|
-
// Inference profile: null
|
|
629
|
-
//
|
|
771
|
+
// Inference profile: null re-pins to the currently resolved default; a
|
|
772
|
+
// string must name a configured profile.
|
|
630
773
|
if ("inferenceProfile" in body) {
|
|
631
774
|
const inferenceProfile = body.inferenceProfile;
|
|
632
775
|
if (inferenceProfile !== null && typeof inferenceProfile !== "string") {
|
|
@@ -761,6 +904,12 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
761
904
|
description:
|
|
762
905
|
"When 'true', include deferred schedules that are normally hidden.",
|
|
763
906
|
},
|
|
907
|
+
{
|
|
908
|
+
name: "inference_profile",
|
|
909
|
+
schema: { type: "string" },
|
|
910
|
+
description:
|
|
911
|
+
"Return only schedules pinned to this inference profile (llm.profiles key).",
|
|
912
|
+
},
|
|
764
913
|
],
|
|
765
914
|
responseBody: z.object({
|
|
766
915
|
schedules: z.array(scheduleSchema).describe("Schedule objects"),
|
|
@@ -802,8 +951,38 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
802
951
|
handler: ({ queryParams }: RouteHandlerArgs) =>
|
|
803
952
|
handleScheduleUsageSummary(queryParams ?? {}),
|
|
804
953
|
},
|
|
805
|
-
|
|
806
|
-
|
|
954
|
+
{
|
|
955
|
+
operationId: "reassignScheduleInferenceProfile",
|
|
956
|
+
endpoint: "schedules/reassign-profile",
|
|
957
|
+
method: "POST",
|
|
958
|
+
policy: {
|
|
959
|
+
requiredScopes: ["settings.write"],
|
|
960
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
961
|
+
},
|
|
962
|
+
summary: "Reassign schedules to another inference profile",
|
|
963
|
+
description:
|
|
964
|
+
"Move schedules onto one inference profile. Pass 'from' to move only the schedules pinned to that profile, so deleting a profile does not leave its schedules pointing at a name that no longer exists. Omit 'from' to move every schedule, which re-pins the whole set onto one profile. Schedules already pinned to the target are skipped.",
|
|
965
|
+
tags: ["schedules"],
|
|
966
|
+
requestBody: z.object({
|
|
967
|
+
from: z
|
|
968
|
+
.string()
|
|
969
|
+
.optional()
|
|
970
|
+
.describe(
|
|
971
|
+
"Inference profile key the schedules are pinned to now; omit to select every schedule",
|
|
972
|
+
),
|
|
973
|
+
to: z
|
|
974
|
+
.string()
|
|
975
|
+
.describe("Inference profile key to move them to; must be configured"),
|
|
976
|
+
}),
|
|
977
|
+
responseBody: z.object({
|
|
978
|
+
reassigned: z.number().describe("Number of schedules moved"),
|
|
979
|
+
}),
|
|
980
|
+
handler: ({ body, headers }: RouteHandlerArgs) =>
|
|
981
|
+
handleReassignScheduleInferenceProfile(body ?? {}, headers),
|
|
982
|
+
},
|
|
983
|
+
// Must stay after literal `schedules/*` siblings (e.g. usage-summary,
|
|
984
|
+
// reassign-profile): the router matches in declaration order and `:id`
|
|
985
|
+
// would shadow them.
|
|
807
986
|
{
|
|
808
987
|
operationId: "getSchedule",
|
|
809
988
|
endpoint: "schedules/:id",
|
|
@@ -882,7 +1061,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
882
1061
|
.string()
|
|
883
1062
|
.nullable()
|
|
884
1063
|
.describe(
|
|
885
|
-
"Inference profile (llm.profiles key) the schedule's runs use. Omitted or null
|
|
1064
|
+
"Inference profile (llm.profiles key) the schedule's runs use. Omitted or null pins the schedule to the currently resolved default profile, so its model does not move when that default changes. Workflow-mode schedules resolve a model per workflow step, so the pin is recorded but does not govern their runs.",
|
|
886
1065
|
)
|
|
887
1066
|
.optional(),
|
|
888
1067
|
}),
|
|
@@ -919,7 +1098,8 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
919
1098
|
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
920
1099
|
},
|
|
921
1100
|
summary: "Toggle schedule",
|
|
922
|
-
description:
|
|
1101
|
+
description:
|
|
1102
|
+
"Enable or disable a schedule. On a plugin-managed schedule this records the user's override (userEnabled).",
|
|
923
1103
|
tags: ["schedules"],
|
|
924
1104
|
requestBody: z.object({
|
|
925
1105
|
enabled: z.boolean().describe("New enabled state"),
|
|
@@ -1002,7 +1182,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
1002
1182
|
.string()
|
|
1003
1183
|
.nullable()
|
|
1004
1184
|
.describe(
|
|
1005
|
-
"Inference profile (llm.profiles key) the schedule's runs use; null
|
|
1185
|
+
"Inference profile (llm.profiles key) the schedule's runs use; null re-pins the schedule to the currently resolved default profile. Workflow-mode schedules resolve a model per workflow step, so the pin is recorded but does not govern their runs.",
|
|
1006
1186
|
)
|
|
1007
1187
|
.optional(),
|
|
1008
1188
|
}),
|
|
@@ -1038,7 +1218,8 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
1038
1218
|
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
1039
1219
|
},
|
|
1040
1220
|
summary: "Run schedule now",
|
|
1041
|
-
description:
|
|
1221
|
+
description:
|
|
1222
|
+
"Trigger an immediate execution of a schedule. A plugin-sourced schedule is rejected with a 400 when its plugin is disabled or no longer declares it.",
|
|
1042
1223
|
tags: ["schedules"],
|
|
1043
1224
|
responseBody: z.object({
|
|
1044
1225
|
schedules: z.array(scheduleSchema).describe("Updated schedule list"),
|
|
@@ -1057,6 +1238,23 @@ async function handleRunScheduleNow(
|
|
|
1057
1238
|
throw new NotFoundError("Schedule not found");
|
|
1058
1239
|
}
|
|
1059
1240
|
|
|
1241
|
+
// A plugin-sourced row runs the plugin's own script or prompt, so run-now is
|
|
1242
|
+
// only offered while that plugin is something the runtime would activate.
|
|
1243
|
+
// `declarationExistsOnDisk` is the same probe the enable path uses: it covers
|
|
1244
|
+
// a disabled plugin, an unreadable or invalid manifest, and a declaration
|
|
1245
|
+
// that is simply gone. Turning the feature flag off retires the surface
|
|
1246
|
+
// wholesale and takes the same path. The row can still be armed at this
|
|
1247
|
+
// point, because the reconciler that disarms it runs on its own schedule.
|
|
1248
|
+
if (
|
|
1249
|
+
schedule.sourceKey !== null &&
|
|
1250
|
+
(!isPluginSchedulesEnabled() ||
|
|
1251
|
+
!(await declarationExistsOnDisk(schedule.sourceKey)))
|
|
1252
|
+
) {
|
|
1253
|
+
throw new BadRequestError(
|
|
1254
|
+
"This schedule's plugin is disabled or no longer declares it, so it cannot be run.",
|
|
1255
|
+
);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1060
1258
|
// ── Script mode (shell command, no LLM) ──────────────────────────
|
|
1061
1259
|
if (schedule.mode === "script") {
|
|
1062
1260
|
if (!schedule.script) {
|
|
@@ -108,7 +108,7 @@ async function queueApiKeyPropagation(
|
|
|
108
108
|
getPlatformAssistantId() || undefined,
|
|
109
109
|
);
|
|
110
110
|
log.info(
|
|
111
|
-
"
|
|
111
|
+
"Notified CES of the queued assistant API key after handshake completed (ack only; CES reads the durable value from the credential store)",
|
|
112
112
|
);
|
|
113
113
|
} catch (err) {
|
|
114
114
|
log.warn(
|
|
@@ -124,6 +124,44 @@ async function queueApiKeyPropagation(
|
|
|
124
124
|
);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Notify CES that the assistant API key changed. This is advisory: the key is
|
|
129
|
+
* durably stored in the credential vault and CES reads it from there. When no
|
|
130
|
+
* CES client is connected the notification is skipped, but the skip is logged
|
|
131
|
+
* rather than dropped silently. Exported for direct testing.
|
|
132
|
+
*/
|
|
133
|
+
export async function notifyCesOfAssistantApiKeyUpdate(
|
|
134
|
+
value: string,
|
|
135
|
+
cesClient: CesClient | undefined,
|
|
136
|
+
logger: Pick<ReturnType<typeof getLogger>, "info" | "warn"> = log,
|
|
137
|
+
): Promise<void> {
|
|
138
|
+
const generation = ++apiKeyGeneration;
|
|
139
|
+
if (!cesClient) {
|
|
140
|
+
logger.warn(
|
|
141
|
+
"Assistant API key updated but no CES client is connected; skipping the CES key-update notification (advisory only; CES reads the durable value from the credential store)",
|
|
142
|
+
);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (cesClient.isReady()) {
|
|
146
|
+
try {
|
|
147
|
+
await cesClient.updateAssistantApiKey(
|
|
148
|
+
value,
|
|
149
|
+
getPlatformAssistantId() || undefined,
|
|
150
|
+
);
|
|
151
|
+
logger.info(
|
|
152
|
+
"Notified CES of the updated assistant API key (ack only; CES reads the durable value from the credential store)",
|
|
153
|
+
);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
logger.warn(
|
|
156
|
+
{ error: err instanceof Error ? err.message : String(err) },
|
|
157
|
+
"Failed to notify CES of the assistant API key update (non-fatal)",
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
void queueApiKeyPropagation(cesClient, value, generation);
|
|
163
|
+
}
|
|
164
|
+
|
|
127
165
|
// ---------------------------------------------------------------------------
|
|
128
166
|
// Provider refresh after secret changes
|
|
129
167
|
// ---------------------------------------------------------------------------
|
|
@@ -381,28 +419,7 @@ async function handleAddSecret({ body }: RouteHandlerArgs) {
|
|
|
381
419
|
// pages unseeded until restart. Detached — must not block the response.
|
|
382
420
|
void maybeReseedCapabilitiesAfterManagedCredential(getConfig());
|
|
383
421
|
if (service === "vellum" && field === "assistant_api_key") {
|
|
384
|
-
|
|
385
|
-
const cesClient = getCesClient();
|
|
386
|
-
if (cesClient) {
|
|
387
|
-
if (cesClient.isReady()) {
|
|
388
|
-
try {
|
|
389
|
-
await cesClient.updateAssistantApiKey(
|
|
390
|
-
value,
|
|
391
|
-
getPlatformAssistantId() || undefined,
|
|
392
|
-
);
|
|
393
|
-
log.info(
|
|
394
|
-
"Pushed assistant API key to CES after managed proxy credential update",
|
|
395
|
-
);
|
|
396
|
-
} catch (err) {
|
|
397
|
-
log.warn(
|
|
398
|
-
{ error: err instanceof Error ? err.message : String(err) },
|
|
399
|
-
"Failed to push assistant API key to CES (non-fatal)",
|
|
400
|
-
);
|
|
401
|
-
}
|
|
402
|
-
} else {
|
|
403
|
-
void queueApiKeyPropagation(cesClient, value, generation);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
422
|
+
await notifyCesOfAssistantApiKeyUpdate(value, getCesClient());
|
|
406
423
|
}
|
|
407
424
|
}
|
|
408
425
|
if (
|
|
@@ -46,6 +46,7 @@ import { getSecureKeyAsync } from "../../security/secure-keys.js";
|
|
|
46
46
|
import { parseToolManifestFile } from "../../skills/tool-manifest.js";
|
|
47
47
|
import { getSubagentManager } from "../../subagent/index.js";
|
|
48
48
|
import { mergeSkillIds } from "../../subagent/manager.js";
|
|
49
|
+
import { resolveSubagentRole } from "../../subagent/role-resolution.js";
|
|
49
50
|
import {
|
|
50
51
|
SUBAGENT_ROLE_REGISTRY,
|
|
51
52
|
type SubagentRole,
|
|
@@ -407,10 +408,24 @@ type SchemaShape = {
|
|
|
407
408
|
required?: string[];
|
|
408
409
|
};
|
|
409
410
|
|
|
411
|
+
/** How an `agent` query param was read, when one was given by role. */
|
|
412
|
+
interface ResolvedAgentInfo {
|
|
413
|
+
/** The `agent` value as asked for. */
|
|
414
|
+
requested: string;
|
|
415
|
+
/** The subagent type whose surface is listed. */
|
|
416
|
+
role: SubagentRole;
|
|
417
|
+
/** The older type name that produced `role`, when one did. */
|
|
418
|
+
alias?: string;
|
|
419
|
+
/** The free text carried as a persona, when `requested` named no type. */
|
|
420
|
+
persona?: string;
|
|
421
|
+
}
|
|
422
|
+
|
|
410
423
|
interface ToolNamesListResponse {
|
|
411
424
|
names: string[];
|
|
412
425
|
schemas: Record<string, SchemaShape>;
|
|
413
426
|
tools: ToolListEntry[];
|
|
427
|
+
/** Present only for an `agent` listing resolved from a role string. */
|
|
428
|
+
agent?: ResolvedAgentInfo;
|
|
414
429
|
}
|
|
415
430
|
|
|
416
431
|
/**
|
|
@@ -475,7 +490,11 @@ function handleToolNamesList(
|
|
|
475
490
|
|
|
476
491
|
/**
|
|
477
492
|
* Resolve the tool surface a subagent would receive, identified either by a
|
|
478
|
-
*
|
|
493
|
+
* live subagent id or by any string a spawn's `role` field accepts: a type
|
|
494
|
+
* name (e.g. "researcher"), an older type name, or free text that a spawn
|
|
495
|
+
* carries as a persona. The response reports which type the string landed on
|
|
496
|
+
* and what carried it there, so a surface that came from an alias or a persona
|
|
497
|
+
* fallback is not mistaken for one that was asked for by name.
|
|
479
498
|
*
|
|
480
499
|
* For a role name: build a minimal {@link Conversation} stand-in matching what
|
|
481
500
|
* the {@link SubagentManager} sets up at spawn time (isSubagent, allowedTools,
|
|
@@ -495,16 +514,13 @@ function handleAgentToolList(agent: string): ToolNamesListResponse {
|
|
|
495
514
|
return handleConversationToolList(state.conversationId);
|
|
496
515
|
}
|
|
497
516
|
|
|
498
|
-
// Otherwise,
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
`or a live subagent id.`,
|
|
506
|
-
);
|
|
507
|
-
}
|
|
517
|
+
// Otherwise, read it the way a spawn reads its `role` field. Resolution is
|
|
518
|
+
// total: a type name passes through, an older name resolves to its successor
|
|
519
|
+
// type, and anything else is a persona that runs as a researcher. Rejecting
|
|
520
|
+
// what a spawn accepts would leave the two spawn shapes a caller most wants
|
|
521
|
+
// to preview (an alias, a persona) with no way to see their tool surface.
|
|
522
|
+
const resolved = resolveSubagentRole(agent);
|
|
523
|
+
const roleConfig = SUBAGENT_ROLE_REGISTRY[resolved.role];
|
|
508
524
|
|
|
509
525
|
// Build the same context the SubagentManager creates at spawn time. The
|
|
510
526
|
// resolver reads only this subset of Conversation state, so a minimal
|
|
@@ -525,6 +541,11 @@ function handleAgentToolList(agent: string): ToolNamesListResponse {
|
|
|
525
541
|
? new Set(roleConfig.allowedTools)
|
|
526
542
|
: undefined,
|
|
527
543
|
subagentToolGateMode: undefined,
|
|
544
|
+
// Roles that refuse side effects require an allowed name to resolve to a
|
|
545
|
+
// first-party built-in, so a workspace or plugin tool claiming one is off
|
|
546
|
+
// the surface. Without this the preview would advertise a tool the live
|
|
547
|
+
// subagent refuses at dispatch.
|
|
548
|
+
subagentDenySideEffects: roleConfig.denySideEffects === true,
|
|
528
549
|
toolsDisabledDepth: 0,
|
|
529
550
|
diskPressureCleanupModeActive: false,
|
|
530
551
|
skillProjectionState: new Map<string, string>(),
|
|
@@ -533,12 +554,19 @@ function handleAgentToolList(agent: string): ToolNamesListResponse {
|
|
|
533
554
|
preactivatedSkillIds: mergedSkillIds,
|
|
534
555
|
} as unknown as Conversation;
|
|
535
556
|
|
|
557
|
+
const agentInfo: ResolvedAgentInfo = {
|
|
558
|
+
requested: agent,
|
|
559
|
+
role: resolved.role,
|
|
560
|
+
...(resolved.alias ? { alias: resolved.alias } : {}),
|
|
561
|
+
...(resolved.personaText ? { persona: resolved.personaText } : {}),
|
|
562
|
+
};
|
|
563
|
+
|
|
536
564
|
// Run the real tool resolver — the same callback a subagent conversation
|
|
537
565
|
// uses each turn. An empty message history simulates the first turn before
|
|
538
566
|
// any skill activations have been recorded.
|
|
539
567
|
const resolveTools = createResolveToolsCallback(toolDefs, ctx);
|
|
540
568
|
if (!resolveTools) {
|
|
541
|
-
return { names: [], schemas: {}, tools: [] };
|
|
569
|
+
return { names: [], schemas: {}, tools: [], agent: agentInfo };
|
|
542
570
|
}
|
|
543
571
|
const resolvedDefs = resolveTools([]);
|
|
544
572
|
const names = resolvedDefs
|
|
@@ -562,7 +590,7 @@ function handleAgentToolList(agent: string): ToolNamesListResponse {
|
|
|
562
590
|
tools.push(toolEntryForName(name));
|
|
563
591
|
}
|
|
564
592
|
|
|
565
|
-
return { names, schemas, tools };
|
|
593
|
+
return { names, schemas, tools, agent: agentInfo };
|
|
566
594
|
}
|
|
567
595
|
|
|
568
596
|
/**
|
|
@@ -23,10 +23,12 @@ import {
|
|
|
23
23
|
listSkills,
|
|
24
24
|
listSkillsFiltered,
|
|
25
25
|
searchSkills,
|
|
26
|
+
skillExistsLocally,
|
|
26
27
|
uninstallSkill,
|
|
27
28
|
updateSkill,
|
|
28
29
|
} from "../../daemon/handlers/skills.js";
|
|
29
30
|
import { getCategories } from "../../skills/categories-cache.js";
|
|
31
|
+
import { getSkillHistory } from "../../skills/skill-history.js";
|
|
30
32
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
31
33
|
import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
|
|
32
34
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
@@ -351,6 +353,83 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
351
353
|
return result;
|
|
352
354
|
},
|
|
353
355
|
},
|
|
356
|
+
{
|
|
357
|
+
operationId: "getSkillHistory",
|
|
358
|
+
endpoint: "skills/:id/history",
|
|
359
|
+
method: "GET",
|
|
360
|
+
policy: {
|
|
361
|
+
requiredScopes: ["settings.read"],
|
|
362
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
363
|
+
},
|
|
364
|
+
summary: "Get skill revision history",
|
|
365
|
+
description:
|
|
366
|
+
"Return a skill's recent updates, newest first, each with a combined diff across the skill directory. Read-only: revisions come from the workspace git repository, which already retains prior content. Commits whose only in-skill change is the `lastUsedAt` usage stamp are omitted, so entries are edits rather than loads.",
|
|
367
|
+
tags: ["skills"],
|
|
368
|
+
queryParams: [
|
|
369
|
+
{
|
|
370
|
+
name: "limit",
|
|
371
|
+
schema: { type: "integer" },
|
|
372
|
+
required: false,
|
|
373
|
+
description:
|
|
374
|
+
"Maximum revisions to return, newest first. Defaults to 20 and is clamped to 100.",
|
|
375
|
+
},
|
|
376
|
+
],
|
|
377
|
+
responseBody: z.object({
|
|
378
|
+
skillId: z.string().describe("The skill these revisions belong to"),
|
|
379
|
+
revisions: z
|
|
380
|
+
.array(
|
|
381
|
+
z.object({
|
|
382
|
+
id: z.string().describe("Opaque revision identifier"),
|
|
383
|
+
changedAt: z.string().describe("ISO-8601 time of the update"),
|
|
384
|
+
files: z
|
|
385
|
+
.array(z.string())
|
|
386
|
+
.describe("Paths changed, relative to the skill directory"),
|
|
387
|
+
diff: z
|
|
388
|
+
.string()
|
|
389
|
+
.describe("Unified diff of this update, scoped to the skill"),
|
|
390
|
+
}),
|
|
391
|
+
)
|
|
392
|
+
.describe("Recent updates, newest first"),
|
|
393
|
+
truncatedByCompaction: z
|
|
394
|
+
.boolean()
|
|
395
|
+
.describe(
|
|
396
|
+
"Older history was squashed away, so the oldest entry is a floor rather than the skill's creation",
|
|
397
|
+
),
|
|
398
|
+
}),
|
|
399
|
+
handler: async ({ pathParams, queryParams }: RouteHandlerArgs) => {
|
|
400
|
+
const rawLimit = queryParams?.limit;
|
|
401
|
+
const limit =
|
|
402
|
+
typeof rawLimit === "string" && rawLimit.trim().length > 0
|
|
403
|
+
? Number.parseInt(rawLimit, 10)
|
|
404
|
+
: undefined;
|
|
405
|
+
try {
|
|
406
|
+
// Same current-resource boundary as the file routes. Git retains a
|
|
407
|
+
// deleted skill's commits, so without this a removed skill keeps
|
|
408
|
+
// answering with history for something the rest of the API reports as
|
|
409
|
+
// gone. An existing skill with nothing recorded still gets an empty
|
|
410
|
+
// list, which is the honest answer for a bundled skill or one the
|
|
411
|
+
// workspace has not committed yet.
|
|
412
|
+
if (!skillExistsLocally(pathParams!.id)) {
|
|
413
|
+
throw new NotFoundError(`Skill "${pathParams!.id}" not found`);
|
|
414
|
+
}
|
|
415
|
+
return await getSkillHistory(pathParams!.id, {
|
|
416
|
+
...(limit !== undefined && Number.isFinite(limit) ? { limit } : {}),
|
|
417
|
+
});
|
|
418
|
+
} catch (err) {
|
|
419
|
+
if (err instanceof NotFoundError) {
|
|
420
|
+
throw err;
|
|
421
|
+
}
|
|
422
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
423
|
+
// The id reaches a git pathspec, so a malformed one is the caller's
|
|
424
|
+
// error. Anything else escaping the service is a server fault: the
|
|
425
|
+
// read is otherwise fail-soft and returns an empty history.
|
|
426
|
+
if (message.startsWith("Invalid skill id")) {
|
|
427
|
+
throw new BadRequestError(message);
|
|
428
|
+
}
|
|
429
|
+
throw new InternalError(message);
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
},
|
|
354
433
|
{
|
|
355
434
|
operationId: "enableSkill",
|
|
356
435
|
endpoint: "skills/:id/enable",
|
|
@@ -206,6 +206,7 @@ async function handleHostUiSnapshotResult({ body, headers }: RouteHandlerArgs) {
|
|
|
206
206
|
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
207
207
|
targetClientId: peeked.targetClientId,
|
|
208
208
|
op: "host_ui_snapshot",
|
|
209
|
+
hubForMissingTarget: assistantEventHub,
|
|
209
210
|
});
|
|
210
211
|
}
|
|
211
212
|
|