@vellumai/assistant 0.11.2 → 0.11.3-dev.202608080427.92f668a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +69 -9
- package/docs/flux-turn-detection-spike.md +243 -0
- package/docs/stt-provider-onboarding.md +3 -1
- package/docs/trusted-contact-access.md +9 -5
- package/docs/vellum-doctor.md +195 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +50 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
- package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
- package/node_modules/@vellumai/environments/src/index.ts +17 -6
- package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +50 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
- package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
- package/node_modules/@vellumai/service-contracts/src/channels.ts +50 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
- package/openapi.yaml +619 -47
- package/package.json +1 -1
- package/scripts/voice-ttft-spike.ts +3 -3
- package/src/__tests__/agent-image-optimize.test.ts +4 -4
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
- package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
- package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/answered-question-persistence.test.ts +240 -0
- package/src/__tests__/anthropic-provider.test.ts +165 -30
- package/src/__tests__/app-control-flow.test.ts +9 -8
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
- package/src/__tests__/attachments-store.test.ts +130 -68
- package/src/__tests__/attachments.test.ts +36 -36
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/call-controller.test.ts +120 -0
- package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
- package/src/__tests__/canned-reply-release.test.ts +86 -0
- package/src/__tests__/channel-availability-routes.test.ts +14 -1
- package/src/__tests__/channel-guardian.test.ts +59 -29
- package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
- package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
- package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/config-loader-backfill.test.ts +19 -0
- package/src/__tests__/config-schema.test.ts +150 -7
- package/src/__tests__/consult-deadline.test.ts +65 -0
- package/src/__tests__/conversation-agent-loop.test.ts +438 -2
- package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
- package/src/__tests__/conversation-disk-view.test.ts +4 -4
- package/src/__tests__/conversation-error.test.ts +22 -3
- package/src/__tests__/conversation-fork-crud.test.ts +5 -1
- package/src/__tests__/conversation-fork-referential.test.ts +352 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
- package/src/__tests__/conversation-group-tools.test.ts +32 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
- package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
- package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
- package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
- package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
- package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
- package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
- package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
- package/src/__tests__/conversation-queue.test.ts +433 -1
- package/src/__tests__/conversation-retry-route.test.ts +3 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
- package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
- package/src/__tests__/conversation-store.test.ts +26 -10
- package/src/__tests__/conversation-summarize-route.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
- package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
- package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
- package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
- package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
- package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
- package/src/__tests__/credential-prompt-route.test.ts +54 -7
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +89 -28
- package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
- package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
- package/src/__tests__/disk-pressure-guard.test.ts +55 -55
- package/src/__tests__/disk-pressure-routes.test.ts +10 -10
- package/src/__tests__/disk-pressure-tools.test.ts +2 -2
- package/src/__tests__/disk-usage.test.ts +35 -20
- package/src/__tests__/document-sync-tags.test.ts +379 -0
- package/src/__tests__/document-update-default-surface.test.ts +28 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
- package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
- package/src/__tests__/events-dev-bypass-actor.test.ts +294 -1
- package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
- package/src/__tests__/file-list-tool.test.ts +12 -10
- package/src/__tests__/file-ops-service.test.ts +151 -44
- package/src/__tests__/file-read-container-boundary.test.ts +137 -0
- package/src/__tests__/file-read-tool.test.ts +21 -9
- package/src/__tests__/file-url-path-guard.test.ts +83 -0
- package/src/__tests__/filesystem-tools.test.ts +82 -66
- package/src/__tests__/guardian-outbound-http.test.ts +8 -8
- package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
- package/src/__tests__/helpers/hub-clients.ts +42 -0
- package/src/__tests__/helpers/mock-conversation.ts +46 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
- package/src/__tests__/history-repair.test.ts +112 -12
- package/src/__tests__/host-bash-proxy.test.ts +10 -5
- package/src/__tests__/host-bash-routes.test.ts +67 -0
- package/src/__tests__/host-browser-proxy.test.ts +2 -2
- package/src/__tests__/host-cu-proxy.test.ts +3 -7
- package/src/__tests__/host-file-proxy.test.ts +3 -7
- package/src/__tests__/host-file-read-tool.test.ts +5 -1
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
- package/src/__tests__/http-conversation-lineage.test.ts +2 -5
- package/src/__tests__/http-user-message-parity.test.ts +44 -0
- package/src/__tests__/identity-routes.test.ts +13 -13
- package/src/__tests__/image-conversion.test.ts +29 -26
- package/src/__tests__/image-source-path-reinject.test.ts +2 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
- package/src/__tests__/introduction-card-resolver.test.ts +6 -1
- package/src/__tests__/list-messages-attachments.test.ts +56 -32
- package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
- package/src/__tests__/list-messages-page-latest.test.ts +61 -61
- package/src/__tests__/list-messages-provider-error.test.ts +6 -6
- package/src/__tests__/list-messages-queued.test.ts +49 -6
- package/src/__tests__/list-messages-system-card.test.ts +4 -4
- package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
- package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
- package/src/__tests__/llm-usage-store.test.ts +55 -0
- package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
- package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
- package/src/__tests__/media-stream-output.test.ts +175 -0
- package/src/__tests__/media-stream-server-integration.test.ts +36 -0
- package/src/__tests__/media-stream-stt-session.test.ts +67 -0
- package/src/__tests__/migration-export-http.test.ts +1 -1
- package/src/__tests__/migration-import-commit-http.test.ts +1 -1
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
- package/src/__tests__/migration-validate-http.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +65 -3
- package/src/__tests__/notification-platform-adapter.test.ts +104 -0
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
- package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
- package/src/__tests__/path-policy.test.ts +164 -1
- package/src/__tests__/persist-media-references.test.ts +2 -2
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
- package/src/__tests__/persist-unsendable-image.test.ts +23 -23
- package/src/__tests__/persona-resolver.test.ts +154 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
- package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
- package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
- package/src/__tests__/profiler-routes.test.ts +13 -13
- package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
- package/src/__tests__/proxy-approval-callback.test.ts +3 -3
- package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
- package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
- package/src/__tests__/resolve-trust-class.test.ts +20 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
- package/src/__tests__/run-due-schedules.test.ts +174 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
- package/src/__tests__/schedule-routes.test.ts +730 -8
- package/src/__tests__/schedule-store.test.ts +540 -0
- package/src/__tests__/schedule-tools.test.ts +103 -0
- package/src/__tests__/scheduler-wake.test.ts +5 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
- package/src/__tests__/secure-keys.test.ts +91 -0
- package/src/__tests__/server-history-render.test.ts +97 -7
- package/src/__tests__/size-guard.test.ts +8 -8
- package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
- package/src/__tests__/skill-tool-factory.test.ts +247 -0
- package/src/__tests__/skills-install-staging.test.ts +15 -6
- package/src/__tests__/skills.test.ts +32 -0
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
- package/src/__tests__/slack-inbound-verification.test.ts +4 -1
- package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
- package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
- package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
- package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
- package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
- package/src/__tests__/subagent-disposal.test.ts +10 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
- package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
- package/src/__tests__/subagent-manager-notify.test.ts +148 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/subagent-persistence.test.ts +141 -0
- package/src/__tests__/subagent-role-registry.test.ts +172 -63
- package/src/__tests__/subagent-role-resolution.test.ts +88 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
- package/src/__tests__/subagent-terminal-message.test.ts +88 -1
- package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
- package/src/__tests__/subagent-tools.test.ts +1901 -108
- package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
- package/src/__tests__/system-prompt.test.ts +82 -7
- package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
- package/src/__tests__/tool-result-spool.test.ts +74 -18
- package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
- package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
- package/src/__tests__/tools-audio-read.test.ts +10 -10
- package/src/__tests__/tools-get-route.test.ts +85 -12
- package/src/__tests__/tools-list-cli.test.ts +171 -0
- package/src/__tests__/top-level-renderer.test.ts +54 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
- package/src/__tests__/turn-tail-chain.test.ts +135 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
- package/src/__tests__/ui-visual-surface.test.ts +5 -4
- package/src/__tests__/ui-work-result-surface.test.ts +5 -4
- package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
- package/src/__tests__/usage-routes.test.ts +62 -0
- package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
- package/src/__tests__/visible-app-context.test.ts +20 -4
- package/src/__tests__/web-search-history.test.ts +96 -0
- package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
- package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
- package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +150 -0
- package/src/acp/failure-error.ts +3 -5
- package/src/agent/attachments.ts +26 -24
- package/src/agent/history-repair/history-repair.ts +27 -26
- package/src/agent/image-optimize.ts +6 -6
- package/src/agent/loop.ts +40 -22
- package/src/agent/message-types.ts +3 -3
- package/src/api/constants/document-tools.ts +55 -0
- package/src/api/events/question-answered.ts +53 -0
- package/src/api/events/tool-result.ts +7 -0
- package/src/api/index.ts +13 -0
- package/src/api/responses/conversation-message.ts +11 -0
- package/src/api/surfaces-oauth-connect.test.ts +96 -0
- package/src/api/surfaces.ts +36 -8
- package/src/approvals/guardian-channel-delivery.ts +83 -0
- package/src/approvals/guardian-expiry-notifier.ts +13 -11
- package/src/approvals/guardian-request-resolvers.ts +222 -135
- package/src/calls/__tests__/tts-text-sanitizer.test.ts +13 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +131 -12
- package/src/calls/__tests__/voice-triage-escalate.test.ts +106 -0
- package/src/calls/call-controller.ts +30 -2
- package/src/calls/call-speech-output.ts +12 -4
- package/src/calls/call-transport.ts +18 -1
- package/src/calls/media-stream-output.ts +53 -5
- package/src/calls/media-stream-server.ts +21 -1
- package/src/calls/media-stream-stt-session.ts +49 -0
- package/src/calls/telephony-synthesis-language.ts +84 -0
- package/src/calls/tts-text-sanitizer.ts +12 -5
- package/src/calls/voice-session-bridge.ts +86 -17
- package/src/calls/voice-triage-escalate.ts +54 -7
- package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
- package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
- package/src/channels/config.ts +20 -2
- package/src/channels/gateway-verification-sessions.ts +7 -2
- package/src/channels/plugin-channel-declarations.ts +108 -0
- package/src/channels/types.ts +37 -1
- package/src/cli/AGENTS.md +5 -2
- package/src/cli/commands/__tests__/cache.test.ts +7 -4
- package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
- package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
- package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
- package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
- package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
- package/src/cli/commands/__tests__/plugins.test.ts +692 -0
- package/src/cli/commands/__tests__/schedules.test.ts +136 -37
- package/src/cli/commands/conversations.ts +7 -3
- package/src/cli/commands/credentials.help.ts +7 -0
- package/src/cli/commands/inference-profiles.ts +9 -3
- package/src/cli/commands/inference.help.ts +16 -2
- package/src/cli/commands/mcp.help.ts +17 -6
- package/src/cli/commands/mcp.ts +9 -0
- package/src/cli/commands/memory/memory-retrospective.ts +18 -0
- package/src/cli/commands/notifications.ts +3 -6
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
- package/src/cli/commands/oauth/connect.test.ts +26 -1
- package/src/cli/commands/oauth/connect.ts +4 -1
- package/src/cli/commands/oauth/index.help.ts +3 -1
- package/src/cli/commands/oauth/providers.ts +3 -0
- package/src/cli/commands/plugins.help.ts +25 -2
- package/src/cli/commands/plugins.ts +289 -10
- package/src/cli/commands/schedules.help.ts +14 -12
- package/src/cli/commands/schedules.ts +19 -5
- package/src/cli/commands/stt.help.ts +27 -2
- package/src/cli/commands/tools.help.ts +4 -2
- package/src/cli/commands/tools.ts +38 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
- package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +161 -0
- package/src/cli/lib/install-from-github.ts +61 -0
- package/src/cli/lib/install-from-platform.ts +13 -2
- package/src/cli/lib/plugin-surfaces.ts +124 -4
- package/src/cli/lib/upgrade-plugin.ts +60 -0
- package/src/cli.ts +1 -1
- package/src/config/__tests__/default-profile-catalog.test.ts +11 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
- package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
- package/src/config/__tests__/profile-tool-support.test.ts +131 -0
- package/src/config/bundled-skills/AGENTS.md +1 -1
- package/src/config/bundled-skills/acp/SKILL.md +6 -7
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +15 -15
- package/src/config/bundled-skills/schedule/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
- package/src/config/bundled-skills/subagent/SKILL.md +53 -22
- package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
- package/src/config/bundled-skills/visualize/SKILL.md +1 -1
- package/src/config/call-site-defaults.ts +4 -5
- package/src/config/default-profile-catalog.ts +9 -5
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +45 -15
- package/src/config/loader.ts +75 -1
- package/src/config/profile-tool-support.ts +110 -0
- package/src/config/sanitize-for-transfer.ts +11 -0
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/live-voice.test.ts +142 -4
- package/src/config/schemas/__tests__/stt.test.ts +20 -5
- package/src/config/schemas/call-site-catalog.ts +4 -4
- package/src/config/schemas/calls.ts +0 -4
- package/src/config/schemas/channels.ts +13 -0
- package/src/config/schemas/live-voice.ts +82 -23
- package/src/config/schemas/llm.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +25 -0
- package/src/config/schemas/plugin-updates.ts +59 -0
- package/src/config/schemas/services.ts +8 -4
- package/src/config/schemas/stt.ts +18 -5
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/config/schemas/tts.ts +63 -0
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
- package/src/contacts/guardian-delivery-reader.ts +29 -2
- package/src/context/compactor.ts +4 -4
- package/src/context/post-turn-tool-result-truncation.ts +32 -16
- package/src/context/strip-injections.ts +42 -0
- package/src/context/tool-result-spool.ts +32 -18
- package/src/credential-execution/ces-runtime.ts +3 -0
- package/src/credential-execution/client.ts +22 -1
- package/src/credential-execution/process-manager.test.ts +99 -0
- package/src/credential-execution/process-manager.ts +62 -16
- package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
- package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
- package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
- package/src/daemon/channel-ui-capability.ts +4 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
- package/src/daemon/conversation-agent-loop.ts +318 -148
- package/src/daemon/conversation-attachments.ts +1 -1
- package/src/daemon/conversation-error.ts +8 -1
- package/src/daemon/conversation-initial-prompt.ts +16 -38
- package/src/daemon/conversation-lifecycle.ts +154 -32
- package/src/daemon/conversation-messaging.ts +106 -43
- package/src/daemon/conversation-process.ts +131 -33
- package/src/daemon/conversation-queue-manager.ts +10 -0
- package/src/daemon/conversation-runtime-assembly.ts +9 -4
- package/src/daemon/conversation-store.ts +52 -3
- package/src/daemon/conversation-surface-state.ts +9 -0
- package/src/daemon/conversation-surfaces.ts +403 -210
- package/src/daemon/conversation-tool-setup.ts +56 -7
- package/src/daemon/conversation-turn-finalize.ts +134 -89
- package/src/daemon/conversation.ts +111 -27
- package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
- package/src/daemon/disk-pressure-guard.ts +3 -3
- package/src/daemon/doordash-steps.ts +5 -5
- package/src/daemon/external-plugins-bootstrap.ts +7 -1
- package/src/daemon/handlers/config-channels.ts +48 -5
- package/src/daemon/handlers/conversation-history.ts +1 -1
- package/src/daemon/handlers/conversations.ts +62 -17
- package/src/daemon/handlers/shared.ts +12 -0
- package/src/daemon/handlers/skills.ts +11 -1
- package/src/daemon/identity-helpers.ts +38 -10
- package/src/daemon/install-assistant-command.ts +322 -0
- package/src/daemon/lifecycle.ts +14 -3
- package/src/daemon/message-types/conversations.ts +6 -7
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/persist-media-references.ts +23 -14
- package/src/daemon/process-message.ts +6 -6
- package/src/daemon/tool-setup-types.ts +19 -122
- package/src/daemon/tool-side-effects.ts +17 -94
- package/src/daemon/trust-context-types.ts +39 -0
- package/src/daemon/trust-context.ts +14 -6
- package/src/daemon/turn-tail-chain.ts +73 -0
- package/src/daemon/web-search-history.ts +47 -33
- package/src/heartbeat/heartbeat-service.ts +6 -6
- package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
- package/src/inbound/oauth-callback-url.ts +61 -0
- package/src/ipc/__tests__/socket-path.test.ts +21 -0
- package/src/ipc/assistant-server.ts +17 -10
- package/src/ipc/cli-client.ts +10 -1
- package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
- package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
- package/src/ipc/socket-cleanup.ts +9 -7
- package/src/ipc/socket-path.ts +4 -96
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
- package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
- package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
- package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +932 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +12 -5
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
- package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +179 -146
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +324 -2
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +131 -2
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
- package/src/live-voice/__tests__/live-voice-tts.test.ts +148 -2
- package/src/live-voice/__tests__/live-voice-vad.test.ts +313 -32
- package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
- package/src/live-voice/__tests__/progress-phrases.test.ts +167 -0
- package/src/live-voice/__tests__/protocol.test.ts +52 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
- package/src/live-voice/live-voice-archive.ts +13 -13
- package/src/live-voice/live-voice-connection.ts +7 -1
- package/src/live-voice/live-voice-metrics.ts +57 -32
- package/src/live-voice/live-voice-photo.ts +168 -0
- package/src/live-voice/live-voice-session.ts +1137 -351
- package/src/live-voice/live-voice-tts.ts +18 -2
- package/src/live-voice/progress-narration.ts +277 -0
- package/src/live-voice/progress-phrases.ts +105 -2
- package/src/live-voice/protocol.ts +110 -2
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +196 -0
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
- package/src/mcp/client.ts +14 -7
- package/src/mcp/mcp-auth-orchestrator.ts +13 -22
- package/src/mcp/mcp-oauth-provider.ts +195 -240
- package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
- package/src/messaging/providers/callback-routing.ts +1 -0
- package/src/messaging/providers/discord/api.ts +312 -0
- package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
- package/src/messaging/providers/discord/render.test.ts +204 -0
- package/src/messaging/providers/discord/render.ts +195 -0
- package/src/messaging/providers/discord/send.test.ts +179 -0
- package/src/messaging/providers/discord/send.ts +212 -0
- package/src/messaging/providers/discord/transport.ts +81 -0
- package/src/messaging/providers/index.ts +3 -1
- package/src/messaging/providers/retry-policy.test.ts +247 -0
- package/src/messaging/providers/retry-policy.ts +206 -0
- package/src/messaging/providers/slack/mention-source.test.ts +285 -0
- package/src/messaging/providers/slack/mention-source.ts +287 -0
- package/src/messaging/providers/telegram-bot/api.ts +47 -130
- package/src/messaging/providers/whatsapp/api.ts +47 -136
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +495 -0
- package/src/monitoring/db-integrity-sample.ts +6 -1
- package/src/monitoring/plugin-auto-update.ts +463 -0
- package/src/monitoring/resource-sampler.ts +21 -5
- package/src/monitoring/worker.ts +13 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
- package/src/notifications/__tests__/broadcaster.test.ts +37 -1
- package/src/notifications/__tests__/copy-composer.test.ts +165 -0
- package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
- package/src/notifications/__tests__/notification-utils.test.ts +249 -0
- package/src/notifications/adapters/platform.ts +31 -2
- package/src/notifications/assistant-reply-producer.ts +79 -32
- package/src/notifications/broadcaster.ts +30 -10
- package/src/notifications/copy-composer.ts +69 -0
- package/src/notifications/emit-signal.ts +82 -15
- package/src/notifications/events-store.ts +10 -2
- package/src/notifications/home-feed-side-effect.ts +6 -3
- package/src/notifications/notification-utils.ts +173 -5
- package/src/notifications/signal.ts +13 -0
- package/src/oauth/AGENTS.md +4 -2
- package/src/oauth/byo-connection.ts +6 -1
- package/src/oauth/credential-token-resolver.ts +3 -10
- package/src/oauth/manual-token-connection.ts +29 -64
- package/src/oauth/manual-token-providers.ts +62 -0
- package/src/oauth/provider-serializer.ts +13 -0
- package/src/oauth/seed-providers.ts +62 -11
- package/src/onboarding/onboarding-events-store.ts +91 -1
- package/src/permissions/question-prompter.test.ts +4 -0
- package/src/permissions/question-prompter.ts +21 -4
- package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
- package/src/persistence/attachments-store.ts +15 -15
- package/src/persistence/conversation-attention-store.ts +30 -10
- package/src/persistence/conversation-bootstrap.ts +17 -0
- package/src/persistence/conversation-crud.ts +363 -97
- package/src/persistence/conversation-group-migration.ts +1 -1
- package/src/persistence/conversation-key-store.ts +38 -10
- package/src/persistence/conversation-lineage.ts +226 -0
- package/src/persistence/conversation-plugin-facade.ts +28 -3
- package/src/persistence/conversation-queries.ts +207 -33
- package/src/persistence/conversation-types.ts +107 -1
- package/src/persistence/jobs-store.ts +32 -8
- package/src/persistence/llm-usage-store.ts +22 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
- package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
- package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
- package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
- package/src/persistence/schema/conversations.ts +32 -0
- package/src/persistence/schema/infrastructure.ts +3 -0
- package/src/persistence/steps.ts +30 -0
- package/src/persistence/subagent-store.ts +148 -6
- package/src/platform/managed-speech.test.ts +20 -0
- package/src/platform/managed-speech.ts +9 -0
- package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
- package/src/plugin-api/index.ts +28 -5
- package/src/plugin-api/webhook-url.ts +151 -0
- package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
- package/src/plugins/__tests__/mcp-servers.test.ts +370 -0
- package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
- package/src/plugins/collect-source-versions.ts +4 -27
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
- package/src/plugins/defaults/exploration-drift/package.json +1 -1
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
- package/src/plugins/defaults/image-recovery/recover.ts +67 -57
- package/src/plugins/defaults/index.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
- package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
- package/src/plugins/defaults/memory/job-handlers.ts +87 -5
- package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
- package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
- package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
- package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
- package/src/plugins/defaults/memory/v2/router.ts +8 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
- package/src/plugins/external-plugin-loader.ts +64 -8
- package/src/plugins/installed-plugin-dirs.ts +101 -0
- package/src/plugins/mcp-servers.ts +343 -0
- package/src/plugins/mtime-cache.ts +34 -22
- package/src/plugins/types.ts +69 -8
- package/src/prompts/persona-resolver.ts +6 -2
- package/src/prompts/system-prompt.ts +72 -17
- package/src/providers/__tests__/inference.test.ts +40 -0
- package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
- package/src/providers/__tests__/retry-callsite.test.ts +72 -2
- package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
- package/src/providers/anthropic/client.ts +112 -95
- package/src/providers/connection-resolution.ts +35 -1
- package/src/providers/gemini/client.ts +5 -5
- package/src/providers/inference/adapter-factory.ts +16 -10
- package/src/providers/inference/auth.ts +16 -0
- package/src/providers/inference/connection-availability.ts +164 -12
- package/src/providers/inference/connections.ts +25 -1
- package/src/providers/media-resolve.ts +21 -11
- package/src/providers/model-catalog.ts +15 -0
- package/src/providers/openai/chat-completions-provider.ts +4 -4
- package/src/providers/openai/responses-provider.ts +12 -25
- package/src/providers/registry.ts +9 -4
- package/src/providers/retry.ts +25 -0
- package/src/providers/server-tool-pairing.ts +134 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +620 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +472 -12
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +719 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +283 -1
- package/src/providers/speech-to-text/deepgram-realtime.ts +117 -3
- package/src/providers/speech-to-text/deepgram.ts +1 -0
- package/src/providers/speech-to-text/provider-catalog.ts +137 -8
- package/src/providers/speech-to-text/resolve.ts +105 -12
- package/src/providers/speech-to-text/vellum-managed.ts +7 -1
- package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
- package/src/providers/types.ts +26 -6
- package/src/providers/vellum-model-routing.ts +6 -7
- package/src/runtime/AGENTS.md +2 -0
- package/src/runtime/__tests__/agent-wake.test.ts +16 -16
- package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
- package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
- package/src/runtime/__tests__/local-actor-identity-force-refresh.test.ts +104 -0
- package/src/runtime/agent-wake.ts +63 -24
- package/src/runtime/assistant-event-hub.ts +110 -12
- package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
- package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
- package/src/runtime/auth/same-actor.ts +56 -8
- package/src/runtime/auth/scopes.ts +12 -0
- package/src/runtime/auth/types.ts +2 -0
- package/src/runtime/background-job-runner.ts +5 -27
- package/src/runtime/channel-readiness-service.ts +59 -3
- package/src/runtime/channel-readiness-types.ts +18 -0
- package/src/runtime/desktop-presence.ts +69 -0
- package/src/runtime/http-server.ts +12 -0
- package/src/runtime/local-actor-identity.ts +29 -14
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +217 -1
- package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
- package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
- package/src/runtime/routes/__tests__/sse-actor-principal-heal.test.ts +165 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +2 -0
- package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
- package/src/runtime/routes/archive-utils.ts +16 -12
- package/src/runtime/routes/attachment-routes.ts +13 -6
- package/src/runtime/routes/canned-reply-release.ts +54 -0
- package/src/runtime/routes/channel-availability-routes.ts +32 -14
- package/src/runtime/routes/channel-verification-routes.ts +2 -27
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
- package/src/runtime/routes/client-routes.ts +114 -2
- package/src/runtime/routes/conversation-cli-routes.ts +10 -12
- package/src/runtime/routes/conversation-list-routes.ts +59 -10
- package/src/runtime/routes/conversation-management-routes.ts +47 -18
- package/src/runtime/routes/conversation-query-routes.ts +32 -53
- package/src/runtime/routes/conversation-routes.ts +360 -293
- package/src/runtime/routes/credential-prompt-routes.ts +20 -2
- package/src/runtime/routes/debug-routes.ts +4 -1
- package/src/runtime/routes/default-provider-routes.ts +7 -11
- package/src/runtime/routes/documents-routes.ts +44 -1
- package/src/runtime/routes/events-routes.ts +29 -1
- package/src/runtime/routes/host-app-control-routes.ts +2 -0
- package/src/runtime/routes/host-bash-routes.ts +2 -0
- package/src/runtime/routes/host-browser-routes.ts +2 -0
- package/src/runtime/routes/host-cu-routes.ts +2 -0
- package/src/runtime/routes/host-file-routes.ts +2 -0
- package/src/runtime/routes/host-transfer-routes.ts +4 -0
- package/src/runtime/routes/identity-routes.ts +6 -6
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
- package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
- package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
- package/src/runtime/routes/inference-profiles-routes.ts +152 -73
- package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
- package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
- package/src/runtime/routes/log-export-routes.ts +1 -1
- package/src/runtime/routes/mcp-auth-routes.ts +141 -57
- package/src/runtime/routes/notification-routes.ts +0 -14
- package/src/runtime/routes/oauth-providers.ts +1 -0
- package/src/runtime/routes/plugins-routes.ts +127 -4
- package/src/runtime/routes/profiler-routes.ts +4 -2
- package/src/runtime/routes/question-routes.ts +28 -10
- package/src/runtime/routes/retrospective-routes.ts +9 -3
- package/src/runtime/routes/schedule-routes.ts +210 -12
- package/src/runtime/routes/secret-routes.ts +40 -23
- package/src/runtime/routes/settings-routes.ts +41 -13
- package/src/runtime/routes/skills-routes.ts +79 -0
- package/src/runtime/routes/sse-actor-principal-heal.ts +113 -0
- package/src/runtime/routes/stt-routes.ts +31 -25
- package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
- package/src/runtime/routes/wake-conversation-routes.ts +23 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +24 -9
- package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
- package/src/runtime/sync/resource-sync-events.ts +79 -1
- package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
- package/src/runtime/sync/worker-daemon-notify.ts +44 -6
- package/src/runtime/verification-outbound-actions.ts +250 -222
- package/src/runtime/verification-templates.ts +41 -30
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
- package/src/schedule/inference-profile.ts +64 -3
- package/src/schedule/plugin-schedule-declarations.ts +518 -0
- package/src/schedule/plugin-schedule-reconciler.ts +605 -0
- package/src/schedule/plugin-schedules-gate.ts +23 -0
- package/src/schedule/schedule-store.ts +520 -26
- package/src/schedule/scheduler.ts +38 -0
- package/src/security/credential-backend.ts +51 -4
- package/src/security/encrypted-store.ts +64 -42
- package/src/security/oauth2.ts +6 -22
- package/src/security/secure-keys.ts +55 -7
- package/src/skills/catalog-install.ts +20 -7
- package/src/skills/inline-command-runner.ts +2 -7
- package/src/skills/skill-history.test.ts +269 -0
- package/src/skills/skill-history.ts +250 -0
- package/src/skills/skillssh-registry.ts +1 -1
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
- package/src/stt/__tests__/language-metadata.test.ts +85 -0
- package/src/stt/__tests__/speech-energy.test.ts +79 -0
- package/src/stt/__tests__/types.test.ts +94 -0
- package/src/stt/daemon-batch-transcriber.ts +18 -6
- package/src/stt/language-metadata.ts +65 -0
- package/src/stt/speech-energy.ts +115 -12
- package/src/stt/stt-stream-session.ts +8 -4
- package/src/stt/types.ts +119 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
- package/src/subagent/consult-prompt.ts +3 -1
- package/src/subagent/consult-transcript.ts +1 -1
- package/src/subagent/manager.ts +304 -44
- package/src/subagent/progress-events.ts +35 -0
- package/src/subagent/role-resolution.ts +88 -0
- package/src/subagent/types.ts +303 -67
- package/src/subagent/validate-allowlists.ts +3 -4
- package/src/telegram/__tests__/webhook-health.test.ts +73 -1
- package/src/telegram/webhook-health.ts +101 -3
- package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
- package/src/telemetry/activation-funnel.ts +6 -1
- package/src/telemetry/live-voice-funnel.ts +75 -0
- package/src/telemetry/telemetry-event-sources.ts +6 -0
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire.generated.ts +2 -0
- package/src/telemetry/types.ts +23 -4
- package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
- package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
- package/src/tools/ask-question/ask-question-tool.ts +56 -2
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/calls/call-start.ts +8 -5
- package/src/tools/conversation-groups/move_to_group.ts +10 -12
- package/src/tools/document/document-tool.ts +11 -4
- package/src/tools/execution-timeout.ts +9 -2
- package/src/tools/executor.ts +7 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +7 -13
- package/src/tools/filesystem/search.ts +23 -21
- package/src/tools/filesystem/write.ts +4 -1
- package/src/tools/host-filesystem/edit.ts +7 -2
- package/src/tools/host-filesystem/read.ts +21 -8
- package/src/tools/host-filesystem/write.ts +10 -2
- package/src/tools/host-terminal/host-shell.ts +2 -2
- package/src/tools/mcp/mcp-tool-factory.ts +25 -1
- package/src/tools/permission-checker.ts +8 -3
- package/src/tools/schedule/delete.ts +13 -1
- package/src/tools/schedule/list.ts +14 -3
- package/src/tools/schedule/update.ts +56 -33
- package/src/tools/shared/filesystem/audio-read.ts +6 -4
- package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
- package/src/tools/shared/filesystem/image-read.ts +12 -12
- package/src/tools/shared/filesystem/path-policy.ts +70 -5
- package/src/tools/shared/filesystem/size-guard.ts +6 -6
- package/src/tools/shared/input-misuse.ts +72 -0
- package/src/tools/skills/scaffold-managed.ts +82 -0
- package/src/tools/skills/skill-tool-factory.ts +14 -1
- package/src/tools/subagent/consult-deadline.ts +12 -7
- package/src/tools/subagent/message.ts +3 -1
- package/src/tools/subagent/read.ts +66 -4
- package/src/tools/subagent/spawn.ts +500 -78
- package/src/tools/tool-approval-handler.ts +45 -4
- package/src/tools/types.ts +22 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
- package/src/tools/ui-surface/visual-validation.ts +2 -0
- package/src/tts/__tests__/provider-adapters.test.ts +147 -0
- package/src/tts/__tests__/speakable-segments.test.ts +470 -0
- package/src/tts/language-voices.ts +23 -0
- package/src/tts/providers/deepgram-provider.ts +3 -1
- package/src/tts/providers/elevenlabs-provider.ts +73 -1
- package/src/tts/providers/xai-provider.ts +28 -2
- package/src/tts/speakable-segments.ts +293 -23
- package/src/tts/synthesis-stream.ts +7 -0
- package/src/tts/types.ts +7 -0
- package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
- package/src/usage/subagent-attribution.ts +108 -0
- package/src/util/__tests__/language-subtag.test.ts +54 -0
- package/src/util/__tests__/sqlite-retry.test.ts +112 -0
- package/src/util/abort-reasons.ts +16 -0
- package/src/util/ansi.ts +44 -0
- package/src/util/disk-usage.ts +17 -13
- package/src/util/image-conversion.ts +20 -13
- package/src/util/language-subtag.ts +43 -0
- package/src/util/schedule-source-key.ts +23 -0
- package/src/util/unicode.ts +1 -1
- package/src/util/worker-process.ts +7 -1
- package/src/workspace/git-service.ts +33 -9
- package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
- package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
- package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +116 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/workspace/top-level-renderer.ts +15 -2
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
- package/src/daemon/install-symlink.ts +0 -207
- package/src/live-voice/__tests__/front-decision.test.ts +0 -525
- package/src/live-voice/front-decision.ts +0 -429
- package/src/notifications/deferred-emit.ts +0 -147
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
* `plugins:list` tag via the canonical resource-sync publisher (enable and
|
|
39
39
|
* disable emit the SAME invalidation)
|
|
40
40
|
* - Threads `x-vellum-client-id` into the published event's `originClientId`
|
|
41
|
+
* - Pokes the plugin-declared schedule reconcile on a successful toggle (and
|
|
42
|
+
* not on a failed one), so the plugin's rows disarm / re-arm immediately
|
|
43
|
+
* instead of at the reconciler's next backstop sweep
|
|
41
44
|
* - A broadcast failure does not fail a successful toggle (the publisher
|
|
42
45
|
* swallows hub errors)
|
|
43
46
|
* - Maps `InvalidPluginNameError` → BadRequestError (400)
|
|
@@ -106,6 +109,7 @@ import {
|
|
|
106
109
|
} from "../../../cli/lib/uninstall-plugin.js";
|
|
107
110
|
import {
|
|
108
111
|
PluginMergeBaselineError,
|
|
112
|
+
PluginNotCuratedError,
|
|
109
113
|
PluginNotUpgradableError,
|
|
110
114
|
type PluginUpgradeResult,
|
|
111
115
|
type UpgradePluginDeps,
|
|
@@ -249,6 +253,7 @@ const upgradeSpy = mock(
|
|
|
249
253
|
|
|
250
254
|
mock.module("../../../cli/lib/upgrade-plugin.js", () => ({
|
|
251
255
|
PluginMergeBaselineError,
|
|
256
|
+
PluginNotCuratedError,
|
|
252
257
|
PluginNotUpgradableError,
|
|
253
258
|
upgradePlugin: upgradeSpy,
|
|
254
259
|
}));
|
|
@@ -311,6 +316,15 @@ mock.module("../../../cli/lib/toggle-plugin.js", () => ({
|
|
|
311
316
|
enablePlugin: enablePluginSpy,
|
|
312
317
|
}));
|
|
313
318
|
|
|
319
|
+
// Spy on the plugin-schedule reconcile the toggle handlers poke. The handlers
|
|
320
|
+
// import it lazily at call time, so this mock intercepts the dynamic import
|
|
321
|
+
// and keeps the reconciler's persistence graph out of the test.
|
|
322
|
+
const reconcilePluginSchedulesSpy = mock(() => Promise.resolve());
|
|
323
|
+
|
|
324
|
+
mock.module("../../../schedule/plugin-schedule-reconciler.js", () => ({
|
|
325
|
+
reconcilePluginSchedules: reconcilePluginSchedulesSpy,
|
|
326
|
+
}));
|
|
327
|
+
|
|
314
328
|
// Spy on broadcastMessage so we can assert the sync_changed invalidation the
|
|
315
329
|
// enable/disable handlers emit. The handlers publish through the canonical
|
|
316
330
|
// `publishPluginsChanged` → `publishSyncInvalidation` path (both left real), so
|
|
@@ -1883,7 +1897,14 @@ function inspection(
|
|
|
1883
1897
|
remoteError: overrides.remoteError ?? null,
|
|
1884
1898
|
surfaces:
|
|
1885
1899
|
overrides.surfaces === undefined
|
|
1886
|
-
? {
|
|
1900
|
+
? {
|
|
1901
|
+
skills: [],
|
|
1902
|
+
hooks: ["post-model-call"],
|
|
1903
|
+
tools: [],
|
|
1904
|
+
schedules: [
|
|
1905
|
+
{ name: "digest", cadence: "0 9 * * *", mode: "execute" },
|
|
1906
|
+
],
|
|
1907
|
+
}
|
|
1887
1908
|
: overrides.surfaces,
|
|
1888
1909
|
};
|
|
1889
1910
|
}
|
|
@@ -1913,6 +1934,26 @@ describe("GET /v1/plugins/:name/inspect", () => {
|
|
|
1913
1934
|
expect(inspectSpy.mock.calls[0]?.[0]).toEqual({ name: "level-up" });
|
|
1914
1935
|
});
|
|
1915
1936
|
|
|
1937
|
+
test("the inspect wire schema carries the schedules surface", async () => {
|
|
1938
|
+
// GIVEN an inspection whose surfaces declare a schedule
|
|
1939
|
+
inspectSpy.mockImplementation(async () => inspection());
|
|
1940
|
+
const result = await invokeInspect({ pathParams: { name: "level-up" } });
|
|
1941
|
+
|
|
1942
|
+
// WHEN the handler result is parsed through the route's response schema
|
|
1943
|
+
// (zod strips undeclared keys, so an omission would drop the field)
|
|
1944
|
+
const route = PLUGINS_ROUTES.find(
|
|
1945
|
+
(r) => r.operationId === "plugins_inspect",
|
|
1946
|
+
)!;
|
|
1947
|
+
const parsed = (
|
|
1948
|
+
route.responseBody as { parse: (v: unknown) => PluginInspection }
|
|
1949
|
+
).parse(result);
|
|
1950
|
+
|
|
1951
|
+
// THEN the declared schedules survive the wire contract
|
|
1952
|
+
expect(parsed.surfaces?.schedules).toEqual([
|
|
1953
|
+
{ name: "digest", cadence: "0 9 * * *", mode: "execute" },
|
|
1954
|
+
]);
|
|
1955
|
+
});
|
|
1956
|
+
|
|
1916
1957
|
test("a captured marketplace error is returned as 200 with remote-unavailable, not thrown", async () => {
|
|
1917
1958
|
// GIVEN the catalog was unreachable but a local copy exists, so the lib
|
|
1918
1959
|
// returns a status rather than throwing
|
|
@@ -2088,6 +2129,7 @@ describe("POST /v1/plugins/:name/upgrade", () => {
|
|
|
2088
2129
|
name: "level-up",
|
|
2089
2130
|
dryRun: false,
|
|
2090
2131
|
strategy: undefined,
|
|
2132
|
+
marketplaceOnly: false,
|
|
2091
2133
|
});
|
|
2092
2134
|
});
|
|
2093
2135
|
|
|
@@ -2109,6 +2151,7 @@ describe("POST /v1/plugins/:name/upgrade", () => {
|
|
|
2109
2151
|
name: "level-up",
|
|
2110
2152
|
dryRun: undefined,
|
|
2111
2153
|
strategy: "ours",
|
|
2154
|
+
marketplaceOnly: false,
|
|
2112
2155
|
});
|
|
2113
2156
|
});
|
|
2114
2157
|
|
|
@@ -2136,9 +2179,94 @@ describe("POST /v1/plugins/:name/upgrade", () => {
|
|
|
2136
2179
|
name: "level-up",
|
|
2137
2180
|
dryRun: undefined,
|
|
2138
2181
|
strategy: "assistant",
|
|
2182
|
+
marketplaceOnly: false,
|
|
2139
2183
|
});
|
|
2140
2184
|
});
|
|
2141
2185
|
|
|
2186
|
+
test("refuses a concurrent upgrade of the same plugin with ConflictError (409)", async () => {
|
|
2187
|
+
// Two upgrades of one plugin derive the same staging path in this
|
|
2188
|
+
// process, so the second would delete the first's tree mid-swap. It is
|
|
2189
|
+
// refused instead \u2014 the monitor's auto-update sweep and a user clicking
|
|
2190
|
+
// Upgrade can now land at the same moment.
|
|
2191
|
+
let releaseFirst: () => void = () => {};
|
|
2192
|
+
const firstStarted = Promise.withResolvers<void>();
|
|
2193
|
+
upgradeSpy.mockImplementation(async () => {
|
|
2194
|
+
firstStarted.resolve();
|
|
2195
|
+
await new Promise<void>((resolve) => {
|
|
2196
|
+
releaseFirst = resolve;
|
|
2197
|
+
});
|
|
2198
|
+
return upgradeResult();
|
|
2199
|
+
});
|
|
2200
|
+
|
|
2201
|
+
const first = invokeUpgrade({ pathParams: { name: "level-up" } });
|
|
2202
|
+
await firstStarted.promise;
|
|
2203
|
+
|
|
2204
|
+
await expect(
|
|
2205
|
+
invokeUpgrade({ pathParams: { name: "level-up" } }),
|
|
2206
|
+
).rejects.toBeInstanceOf(ConflictError);
|
|
2207
|
+
|
|
2208
|
+
releaseFirst();
|
|
2209
|
+
await expect(first).resolves.toMatchObject({ outcome: "upgraded" });
|
|
2210
|
+
|
|
2211
|
+
// The guard is released once the first settles, so the next one runs.
|
|
2212
|
+
upgradeSpy.mockImplementation(async () => upgradeResult());
|
|
2213
|
+
await expect(
|
|
2214
|
+
invokeUpgrade({ pathParams: { name: "level-up" } }),
|
|
2215
|
+
).resolves.toMatchObject({ outcome: "upgraded" });
|
|
2216
|
+
});
|
|
2217
|
+
|
|
2218
|
+
test("a different plugin is not blocked by an in-flight upgrade", async () => {
|
|
2219
|
+
let releaseFirst: () => void = () => {};
|
|
2220
|
+
const firstStarted = Promise.withResolvers<void>();
|
|
2221
|
+
upgradeSpy.mockImplementation(async (opts) => {
|
|
2222
|
+
if (opts.name === "level-up") {
|
|
2223
|
+
firstStarted.resolve();
|
|
2224
|
+
await new Promise<void>((resolve) => {
|
|
2225
|
+
releaseFirst = resolve;
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
2228
|
+
return upgradeResult({ name: opts.name });
|
|
2229
|
+
});
|
|
2230
|
+
|
|
2231
|
+
const first = invokeUpgrade({ pathParams: { name: "level-up" } });
|
|
2232
|
+
await firstStarted.promise;
|
|
2233
|
+
|
|
2234
|
+
await expect(
|
|
2235
|
+
invokeUpgrade({ pathParams: { name: "other-plugin" } }),
|
|
2236
|
+
).resolves.toMatchObject({ name: "other-plugin" });
|
|
2237
|
+
|
|
2238
|
+
releaseFirst();
|
|
2239
|
+
await first;
|
|
2240
|
+
});
|
|
2241
|
+
|
|
2242
|
+
test("a dry run neither takes nor respects the in-flight guard", async () => {
|
|
2243
|
+
// Dry runs return before the swap boundary, so they never stage.
|
|
2244
|
+
let releaseFirst: () => void = () => {};
|
|
2245
|
+
const firstStarted = Promise.withResolvers<void>();
|
|
2246
|
+
upgradeSpy.mockImplementation(async (opts) => {
|
|
2247
|
+
if (!opts.dryRun) {
|
|
2248
|
+
firstStarted.resolve();
|
|
2249
|
+
await new Promise<void>((resolve) => {
|
|
2250
|
+
releaseFirst = resolve;
|
|
2251
|
+
});
|
|
2252
|
+
}
|
|
2253
|
+
return upgradeResult();
|
|
2254
|
+
});
|
|
2255
|
+
|
|
2256
|
+
const first = invokeUpgrade({ pathParams: { name: "level-up" } });
|
|
2257
|
+
await firstStarted.promise;
|
|
2258
|
+
|
|
2259
|
+
await expect(
|
|
2260
|
+
invokeUpgrade({
|
|
2261
|
+
pathParams: { name: "level-up" },
|
|
2262
|
+
body: { dryRun: true },
|
|
2263
|
+
}),
|
|
2264
|
+
).resolves.toMatchObject({ outcome: "upgraded" });
|
|
2265
|
+
|
|
2266
|
+
releaseFirst();
|
|
2267
|
+
await first;
|
|
2268
|
+
});
|
|
2269
|
+
|
|
2142
2270
|
test("PluginMergeBaselineError \u2192 ConflictError (409)", async () => {
|
|
2143
2271
|
// A merge strategy whose install-time baseline can't be reconstructed: a
|
|
2144
2272
|
// well-formed request that isn't actionable in the current state.
|
|
@@ -2177,6 +2305,10 @@ describe("POST /v1/plugins/:name/upgrade", () => {
|
|
|
2177
2305
|
expect(upgradeSpy.mock.calls[0]?.[0]).toEqual({
|
|
2178
2306
|
name: "level-up",
|
|
2179
2307
|
dryRun: undefined,
|
|
2308
|
+
strategy: undefined,
|
|
2309
|
+
// Unlike dryRun, an absent flag here is a definite "no": the untrusted
|
|
2310
|
+
// direct path stays available unless a caller opts out of it.
|
|
2311
|
+
marketplaceOnly: false,
|
|
2180
2312
|
});
|
|
2181
2313
|
});
|
|
2182
2314
|
|
|
@@ -2220,6 +2352,41 @@ describe("POST /v1/plugins/:name/upgrade", () => {
|
|
|
2220
2352
|
).rejects.toBeInstanceOf(ConflictError);
|
|
2221
2353
|
});
|
|
2222
2354
|
|
|
2355
|
+
test("marketplaceOnly is forwarded so the lib enforces it, not the caller", async () => {
|
|
2356
|
+
// The lib re-inspects the catalog inside the call, so the flag has to
|
|
2357
|
+
// travel with the request: a caller's own pre-check cannot bind a decision
|
|
2358
|
+
// the lib makes afterwards.
|
|
2359
|
+
upgradeSpy.mockImplementation(async () => upgradeResult());
|
|
2360
|
+
|
|
2361
|
+
await invokeUpgrade({
|
|
2362
|
+
pathParams: { name: "level-up" },
|
|
2363
|
+
body: { marketplaceOnly: true },
|
|
2364
|
+
});
|
|
2365
|
+
|
|
2366
|
+
expect(upgradeSpy.mock.calls[0]?.[0]).toEqual({
|
|
2367
|
+
name: "level-up",
|
|
2368
|
+
dryRun: undefined,
|
|
2369
|
+
strategy: undefined,
|
|
2370
|
+
marketplaceOnly: true,
|
|
2371
|
+
});
|
|
2372
|
+
});
|
|
2373
|
+
|
|
2374
|
+
test("PluginNotCuratedError → ConflictError (409)", async () => {
|
|
2375
|
+
// A marketplaceOnly caller asked about an install the catalog does not
|
|
2376
|
+
// claim. Retrying changes nothing: only a human upgrading it without the
|
|
2377
|
+
// flag can move it.
|
|
2378
|
+
upgradeSpy.mockImplementation(async () => {
|
|
2379
|
+
throw new PluginNotCuratedError("level-up");
|
|
2380
|
+
});
|
|
2381
|
+
|
|
2382
|
+
await expect(
|
|
2383
|
+
invokeUpgrade({
|
|
2384
|
+
pathParams: { name: "level-up" },
|
|
2385
|
+
body: { marketplaceOnly: true },
|
|
2386
|
+
}),
|
|
2387
|
+
).rejects.toBeInstanceOf(ConflictError);
|
|
2388
|
+
});
|
|
2389
|
+
|
|
2223
2390
|
test("PluginNotFoundError → NotFoundError (404)", async () => {
|
|
2224
2391
|
upgradeSpy.mockImplementation(async () => {
|
|
2225
2392
|
throw new PluginNotFoundError("level-up", "main", "vellum-ai/level-up");
|
|
@@ -2414,6 +2581,21 @@ function invokeDisable(args: RouteHandlerArgs = {}): { ok: boolean } {
|
|
|
2414
2581
|
return disableHandler(args) as { ok: boolean };
|
|
2415
2582
|
}
|
|
2416
2583
|
|
|
2584
|
+
/**
|
|
2585
|
+
* Wait for the toggle handlers' fire-and-forget reconcile poke to land. The
|
|
2586
|
+
* lazy `import()` resolves off the microtask queue, so the assertion cannot
|
|
2587
|
+
* run on the handler's synchronous return.
|
|
2588
|
+
*/
|
|
2589
|
+
async function waitForScheduleReconcile(): Promise<void> {
|
|
2590
|
+
for (let i = 0; i < 50; i++) {
|
|
2591
|
+
if (reconcilePluginSchedulesSpy.mock.calls.length > 0) {
|
|
2592
|
+
return;
|
|
2593
|
+
}
|
|
2594
|
+
await new Promise((resolve) => setTimeout(resolve, 2));
|
|
2595
|
+
}
|
|
2596
|
+
throw new Error("plugin schedule reconcile was never triggered");
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2417
2599
|
/** Assert the spy received exactly one sync_changed carrying `plugins:list`. */
|
|
2418
2600
|
function expectPluginsListBroadcast(): void {
|
|
2419
2601
|
expect(broadcastMessageSpy.mock.calls).toHaveLength(1);
|
|
@@ -2426,6 +2608,15 @@ describe("POST /v1/plugins/:name/enable", () => {
|
|
|
2426
2608
|
beforeEach(() => {
|
|
2427
2609
|
enablePluginSpy.mockReset();
|
|
2428
2610
|
broadcastMessageSpy.mockReset();
|
|
2611
|
+
reconcilePluginSchedulesSpy.mockClear();
|
|
2612
|
+
});
|
|
2613
|
+
|
|
2614
|
+
test("reconciles plugin-declared schedules so the plugin's rows re-arm now", async () => {
|
|
2615
|
+
enablePluginSpy.mockImplementation((name) => toggleResult(name, "enable"));
|
|
2616
|
+
|
|
2617
|
+
invokeEnable({ pathParams: { name: "simple-memory" } });
|
|
2618
|
+
|
|
2619
|
+
await waitForScheduleReconcile();
|
|
2429
2620
|
});
|
|
2430
2621
|
|
|
2431
2622
|
test("enables the plugin and broadcasts sync_changed(plugins:list)", () => {
|
|
@@ -2504,6 +2695,31 @@ describe("POST /v1/plugins/:name/disable", () => {
|
|
|
2504
2695
|
beforeEach(() => {
|
|
2505
2696
|
disablePluginSpy.mockReset();
|
|
2506
2697
|
broadcastMessageSpy.mockReset();
|
|
2698
|
+
reconcilePluginSchedulesSpy.mockClear();
|
|
2699
|
+
});
|
|
2700
|
+
|
|
2701
|
+
test("reconciles plugin-declared schedules so the plugin's rows disarm now", async () => {
|
|
2702
|
+
disablePluginSpy.mockImplementation((name) =>
|
|
2703
|
+
toggleResult(name, "disable"),
|
|
2704
|
+
);
|
|
2705
|
+
|
|
2706
|
+
invokeDisable({ pathParams: { name: "simple-memory" } });
|
|
2707
|
+
|
|
2708
|
+
// Without this poke the rows stay armed until the reconciler's next
|
|
2709
|
+
// backstop sweep.
|
|
2710
|
+
await waitForScheduleReconcile();
|
|
2711
|
+
});
|
|
2712
|
+
|
|
2713
|
+
test("a failed toggle does not poke the schedule reconcile", async () => {
|
|
2714
|
+
disablePluginSpy.mockImplementation((name) => {
|
|
2715
|
+
throw new PluginDirectoryNotFoundError(name);
|
|
2716
|
+
});
|
|
2717
|
+
|
|
2718
|
+
expect(() => invokeDisable({ pathParams: { name: "ghost" } })).toThrow(
|
|
2719
|
+
NotFoundError,
|
|
2720
|
+
);
|
|
2721
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
2722
|
+
expect(reconcilePluginSchedulesSpy).not.toHaveBeenCalled();
|
|
2507
2723
|
});
|
|
2508
2724
|
|
|
2509
2725
|
test("disables the plugin and broadcasts sync_changed(plugins:list)", () => {
|
|
@@ -394,4 +394,68 @@ describe("POST /v1/question-response", () => {
|
|
|
394
394
|
// Pending interaction left in place.
|
|
395
395
|
expect(pendingInteractions.get("req-legacy-multi")).toBeDefined();
|
|
396
396
|
});
|
|
397
|
+
|
|
398
|
+
// A gone interaction must read as 404 for every body shape. Clients treat
|
|
399
|
+
// 404 as the terminal signal that retires a stale card; a 400 leaves the
|
|
400
|
+
// card on screen and surfaces a body-validation string the user cannot act
|
|
401
|
+
// on. The legacy shapes are the ones that matter here: the web client sends
|
|
402
|
+
// them for every single-question answer, which is the common prompt.
|
|
403
|
+
test("legacy option against a gone interaction is 404, not a validation 400", async () => {
|
|
404
|
+
let thrown: unknown;
|
|
405
|
+
try {
|
|
406
|
+
await call({
|
|
407
|
+
body: { requestId: "req-gone", kind: "option", optionId: "yes" },
|
|
408
|
+
});
|
|
409
|
+
} catch (err) {
|
|
410
|
+
thrown = err;
|
|
411
|
+
}
|
|
412
|
+
expect(thrown).toBeInstanceOf(NotFoundError);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
test("legacy free-text against a gone interaction is 404, not a validation 400", async () => {
|
|
416
|
+
let thrown: unknown;
|
|
417
|
+
try {
|
|
418
|
+
await call({
|
|
419
|
+
body: { requestId: "req-gone", kind: "free_text", text: "maybe" },
|
|
420
|
+
});
|
|
421
|
+
} catch (err) {
|
|
422
|
+
thrown = err;
|
|
423
|
+
}
|
|
424
|
+
expect(thrown).toBeInstanceOf(NotFoundError);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
test("close against a gone interaction is 404", async () => {
|
|
428
|
+
let thrown: unknown;
|
|
429
|
+
try {
|
|
430
|
+
await call({ body: { requestId: "req-gone", kind: "close" } });
|
|
431
|
+
} catch (err) {
|
|
432
|
+
thrown = err;
|
|
433
|
+
}
|
|
434
|
+
expect(thrown).toBeInstanceOf(NotFoundError);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
test("legacy option against a confirmation requestId is 404, not a validation 400", async () => {
|
|
438
|
+
// Cross-talk safety has to hold for the legacy shapes too: the wrong-kind
|
|
439
|
+
// interaction carries no question metadata for the shim to read.
|
|
440
|
+
pendingInteractions.register("req-confirm-legacy", {
|
|
441
|
+
conversationId: "conv-1",
|
|
442
|
+
kind: "confirmation",
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
let thrown: unknown;
|
|
446
|
+
try {
|
|
447
|
+
await call({
|
|
448
|
+
body: {
|
|
449
|
+
requestId: "req-confirm-legacy",
|
|
450
|
+
kind: "option",
|
|
451
|
+
optionId: "y",
|
|
452
|
+
},
|
|
453
|
+
});
|
|
454
|
+
} catch (err) {
|
|
455
|
+
thrown = err;
|
|
456
|
+
}
|
|
457
|
+
expect(thrown).toBeInstanceOf(NotFoundError);
|
|
458
|
+
// The confirmation is left intact rather than consumed.
|
|
459
|
+
expect(pendingInteractions.get("req-confirm-legacy")).toBeDefined();
|
|
460
|
+
});
|
|
397
461
|
});
|
|
@@ -413,6 +413,26 @@ describe("getRetrospectiveConfig handler", () => {
|
|
|
413
413
|
expect(result.success).toBe(true);
|
|
414
414
|
});
|
|
415
415
|
|
|
416
|
+
test("available but not enabled when only the retrospective switch is off", async () => {
|
|
417
|
+
writeFileSync(
|
|
418
|
+
configPath,
|
|
419
|
+
JSON.stringify(
|
|
420
|
+
{ memory: { retrospective: { enabled: false } } },
|
|
421
|
+
null,
|
|
422
|
+
2,
|
|
423
|
+
) + "\n",
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
const handler = findHandler("getRetrospectiveConfig");
|
|
427
|
+
const result = (await handler({})) as ConfigResponse;
|
|
428
|
+
|
|
429
|
+
// `available` stays true so the Settings row still renders. It reads
|
|
430
|
+
// "Paused" rather than disappearing as it would with memory off.
|
|
431
|
+
expect(result.available).toBe(true);
|
|
432
|
+
expect(result.enabled).toBe(false);
|
|
433
|
+
expect(result.success).toBe(true);
|
|
434
|
+
});
|
|
435
|
+
|
|
416
436
|
test("stays available when memory v2 is disabled (retrospectives do not gate on v2)", async () => {
|
|
417
437
|
writeFileSync(
|
|
418
438
|
configPath,
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the `getSkillHistory` route's current-resource boundary.
|
|
3
|
+
*
|
|
4
|
+
* The service layer reads retained git history, which outlives the skill it
|
|
5
|
+
* describes: a deleted skill's commits stay in the workspace repository
|
|
6
|
+
* forever. The route is therefore the only place that can decide whether an id
|
|
7
|
+
* still names something, and it must reach the same answer as the sibling file
|
|
8
|
+
* routes rather than serving history for a resource the rest of the API
|
|
9
|
+
* reports as gone.
|
|
10
|
+
*
|
|
11
|
+
* Both collaborators are mocked, because what is under test is the ordering
|
|
12
|
+
* between them: the existence check has to gate the history read, not run
|
|
13
|
+
* alongside it.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
17
|
+
|
|
18
|
+
const skillExistsLocallyMock = mock((_id: string): boolean => true);
|
|
19
|
+
const getSkillHistoryMock = mock(async (_id: string, _opts?: unknown) => ({
|
|
20
|
+
skillId: _id,
|
|
21
|
+
revisions: [{ id: "abc1234", changedAt: "", files: ["SKILL.md"], diff: "" }],
|
|
22
|
+
truncatedByCompaction: false,
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
mock.module("../../../daemon/handlers/skills.js", () => ({
|
|
26
|
+
skillExistsLocally: skillExistsLocallyMock,
|
|
27
|
+
// The route module imports the whole handler surface; the rest is unused
|
|
28
|
+
// here and only needs to exist.
|
|
29
|
+
checkSkillUpdates: mock(),
|
|
30
|
+
configureSkill: mock(),
|
|
31
|
+
createSkill: mock(),
|
|
32
|
+
disableSkill: mock(),
|
|
33
|
+
draftSkill: mock(),
|
|
34
|
+
enableSkill: mock(),
|
|
35
|
+
getSkill: mock(),
|
|
36
|
+
getSkillFileContent: mock(),
|
|
37
|
+
getSkillFiles: mock(),
|
|
38
|
+
getSkillLocalDetail: mock(),
|
|
39
|
+
inspectSkill: mock(),
|
|
40
|
+
installSkill: mock(),
|
|
41
|
+
listSkills: mock(),
|
|
42
|
+
listSkillsFiltered: mock(),
|
|
43
|
+
searchSkills: mock(),
|
|
44
|
+
uninstallSkill: mock(),
|
|
45
|
+
updateSkill: mock(),
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
mock.module("../../../skills/skill-history.js", () => ({
|
|
49
|
+
getSkillHistory: getSkillHistoryMock,
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
const { ROUTES } = await import("../skills-routes.js");
|
|
53
|
+
|
|
54
|
+
const handler = ROUTES.find(
|
|
55
|
+
(r) => r.operationId === "getSkillHistory",
|
|
56
|
+
)!.handler;
|
|
57
|
+
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
skillExistsLocallyMock.mockClear();
|
|
60
|
+
getSkillHistoryMock.mockClear();
|
|
61
|
+
skillExistsLocallyMock.mockImplementation(() => true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("getSkillHistory route", () => {
|
|
65
|
+
test("returns history for a skill that currently exists", async () => {
|
|
66
|
+
const result = (await handler({
|
|
67
|
+
pathParams: { id: "release-triage" },
|
|
68
|
+
})) as {
|
|
69
|
+
revisions: unknown[];
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
expect(result.revisions).toHaveLength(1);
|
|
73
|
+
expect(getSkillHistoryMock).toHaveBeenCalledTimes(1);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("404s for a deleted skill whose commits are still in the repository", async () => {
|
|
77
|
+
// The skill is gone from the resolver, but git would still answer.
|
|
78
|
+
skillExistsLocallyMock.mockImplementation(() => false);
|
|
79
|
+
|
|
80
|
+
await expect(
|
|
81
|
+
handler({ pathParams: { id: "release-triage" } }),
|
|
82
|
+
).rejects.toThrow(/not found/i);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("does not read history at all when the skill is gone", async () => {
|
|
86
|
+
skillExistsLocallyMock.mockImplementation(() => false);
|
|
87
|
+
|
|
88
|
+
await Promise.resolve(
|
|
89
|
+
handler({ pathParams: { id: "release-triage" } }),
|
|
90
|
+
).catch(() => {});
|
|
91
|
+
|
|
92
|
+
// Ordering is the point: a check that ran after the read would still
|
|
93
|
+
// reject, but would have spent the git traversal to do it.
|
|
94
|
+
expect(getSkillHistoryMock).not.toHaveBeenCalled();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("rejects a malformed id as the caller's error, not a server fault", async () => {
|
|
98
|
+
getSkillHistoryMock.mockImplementation(() => {
|
|
99
|
+
throw new Error("Invalid skill id: contains a path separator");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await expect(handler({ pathParams: { id: "bad" } })).rejects.toMatchObject({
|
|
103
|
+
statusCode: 400,
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("surfaces an unexpected service failure as a server error", async () => {
|
|
108
|
+
getSkillHistoryMock.mockImplementation(() => {
|
|
109
|
+
throw new Error("git exploded");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
await expect(handler({ pathParams: { id: "ok" } })).rejects.toMatchObject({
|
|
113
|
+
statusCode: 500,
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the retrying SSE actor-principal self-heal.
|
|
3
|
+
*
|
|
4
|
+
* The invariant they pin: a single empty or failed guardian lookup must not
|
|
5
|
+
* strand the subscription without a principal. The read goes over the gateway
|
|
6
|
+
* IPC and comes back empty both when the transport fails and when no binding
|
|
7
|
+
* exists yet, and a subscription that stays principal-less rejects every
|
|
8
|
+
* host-proxy result its client submits with "Submitting actor does not match
|
|
9
|
+
* the target client's actor for this request" until it reconnects.
|
|
10
|
+
*/
|
|
11
|
+
import { describe, expect, mock, test } from "bun:test";
|
|
12
|
+
|
|
13
|
+
import { startActorPrincipalHeal } from "../sse-actor-principal-heal.js";
|
|
14
|
+
|
|
15
|
+
/** All-zero schedule so the retries run without real wall-clock delay. */
|
|
16
|
+
const NO_DELAYS = [0, 0, 0];
|
|
17
|
+
|
|
18
|
+
/** Minimal hub double: `needs` flips to false once a principal is filled. */
|
|
19
|
+
function fakeHub(options?: { needs?: boolean }) {
|
|
20
|
+
let needs = options?.needs ?? true;
|
|
21
|
+
const filled: string[] = [];
|
|
22
|
+
return {
|
|
23
|
+
filled,
|
|
24
|
+
setNeeds(value: boolean) {
|
|
25
|
+
needs = value;
|
|
26
|
+
},
|
|
27
|
+
needsActorPrincipalHeal: mock(() => needs),
|
|
28
|
+
fillClientActorPrincipalId: mock((_connectionId: string, id: string) => {
|
|
29
|
+
filled.push(id);
|
|
30
|
+
needs = false;
|
|
31
|
+
}),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Let the heal's async loop run to completion. */
|
|
36
|
+
async function settle(): Promise<void> {
|
|
37
|
+
for (let i = 0; i < 10; i++) {
|
|
38
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
describe("startActorPrincipalHeal", () => {
|
|
43
|
+
test("fills the principal on the first successful attempt", async () => {
|
|
44
|
+
const hub = fakeHub();
|
|
45
|
+
startActorPrincipalHeal({
|
|
46
|
+
hub,
|
|
47
|
+
connectionId: "conn-1",
|
|
48
|
+
resolve: () => Promise.resolve("guardian-real-id"),
|
|
49
|
+
delaysMs: NO_DELAYS,
|
|
50
|
+
});
|
|
51
|
+
await settle();
|
|
52
|
+
|
|
53
|
+
expect(hub.filled).toEqual(["guardian-real-id"]);
|
|
54
|
+
expect(hub.needsActorPrincipalHeal).toHaveBeenCalledTimes(1);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("retries after a lookup that resolves undefined (gateway unreachable)", async () => {
|
|
58
|
+
const hub = fakeHub();
|
|
59
|
+
let calls = 0;
|
|
60
|
+
startActorPrincipalHeal({
|
|
61
|
+
hub,
|
|
62
|
+
connectionId: "conn-1",
|
|
63
|
+
resolve: () => {
|
|
64
|
+
calls++;
|
|
65
|
+
// Two failed reads, then the gateway comes up.
|
|
66
|
+
return Promise.resolve(calls < 3 ? undefined : "guardian-real-id");
|
|
67
|
+
},
|
|
68
|
+
delaysMs: NO_DELAYS,
|
|
69
|
+
});
|
|
70
|
+
await settle();
|
|
71
|
+
|
|
72
|
+
expect(calls).toBe(3);
|
|
73
|
+
expect(hub.filled).toEqual(["guardian-real-id"]);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("retries after a lookup that rejects", async () => {
|
|
77
|
+
const hub = fakeHub();
|
|
78
|
+
let calls = 0;
|
|
79
|
+
startActorPrincipalHeal({
|
|
80
|
+
hub,
|
|
81
|
+
connectionId: "conn-1",
|
|
82
|
+
resolve: () => {
|
|
83
|
+
calls++;
|
|
84
|
+
return calls === 1
|
|
85
|
+
? Promise.reject(new Error("ipc timeout"))
|
|
86
|
+
: Promise.resolve("guardian-real-id");
|
|
87
|
+
},
|
|
88
|
+
delaysMs: NO_DELAYS,
|
|
89
|
+
});
|
|
90
|
+
await settle();
|
|
91
|
+
|
|
92
|
+
expect(calls).toBe(2);
|
|
93
|
+
expect(hub.filled).toEqual(["guardian-real-id"]);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("stops retrying once the connection no longer needs healing", async () => {
|
|
97
|
+
// Models a disconnect (or a reconnect that replaced this subscription)
|
|
98
|
+
// between attempts: the loop must not keep polling the gateway for a
|
|
99
|
+
// connection that is gone.
|
|
100
|
+
const hub = fakeHub();
|
|
101
|
+
let calls = 0;
|
|
102
|
+
startActorPrincipalHeal({
|
|
103
|
+
hub,
|
|
104
|
+
connectionId: "conn-1",
|
|
105
|
+
resolve: () => {
|
|
106
|
+
calls++;
|
|
107
|
+
hub.setNeeds(false);
|
|
108
|
+
return Promise.resolve(undefined);
|
|
109
|
+
},
|
|
110
|
+
delaysMs: NO_DELAYS,
|
|
111
|
+
});
|
|
112
|
+
await settle();
|
|
113
|
+
|
|
114
|
+
expect(calls).toBe(1);
|
|
115
|
+
expect(hub.filled).toEqual([]);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("never starts a lookup when the connection is already healed or gone", async () => {
|
|
119
|
+
const hub = fakeHub({ needs: false });
|
|
120
|
+
const resolve = mock(() => Promise.resolve("guardian-real-id"));
|
|
121
|
+
startActorPrincipalHeal({
|
|
122
|
+
hub,
|
|
123
|
+
connectionId: "conn-1",
|
|
124
|
+
resolve,
|
|
125
|
+
delaysMs: NO_DELAYS,
|
|
126
|
+
});
|
|
127
|
+
await settle();
|
|
128
|
+
|
|
129
|
+
expect(resolve).toHaveBeenCalledTimes(0);
|
|
130
|
+
expect(hub.filled).toEqual([]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("gives up after the schedule is exhausted without filling", async () => {
|
|
134
|
+
const hub = fakeHub();
|
|
135
|
+
let calls = 0;
|
|
136
|
+
startActorPrincipalHeal({
|
|
137
|
+
hub,
|
|
138
|
+
connectionId: "conn-1",
|
|
139
|
+
resolve: () => {
|
|
140
|
+
calls++;
|
|
141
|
+
return Promise.resolve(undefined);
|
|
142
|
+
},
|
|
143
|
+
delaysMs: NO_DELAYS,
|
|
144
|
+
});
|
|
145
|
+
await settle();
|
|
146
|
+
|
|
147
|
+
expect(calls).toBe(NO_DELAYS.length);
|
|
148
|
+
expect(hub.filled).toEqual([]);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("dispatches the first attempt synchronously", () => {
|
|
152
|
+
const hub = fakeHub();
|
|
153
|
+
const resolve = mock(() => Promise.resolve("guardian-real-id"));
|
|
154
|
+
startActorPrincipalHeal({
|
|
155
|
+
hub,
|
|
156
|
+
connectionId: "conn-1",
|
|
157
|
+
resolve,
|
|
158
|
+
delaysMs: NO_DELAYS,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// No await: the leading zero delay must not cost a macrotask, so a
|
|
162
|
+
// warm-cache heal lands before the stream delivers its first event.
|
|
163
|
+
expect(resolve).toHaveBeenCalledTimes(1);
|
|
164
|
+
});
|
|
165
|
+
});
|