@vellumai/assistant 0.10.9 → 0.10.10-dev.202607162206.d08e98e
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 +1 -1
- package/Dockerfile +8 -0
- package/docs/activation-funnel-telemetry.md +13 -7
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/openapi.yaml +530 -107
- package/package.json +1 -1
- package/scripts/generate-openapi.ts +8 -0
- package/src/__tests__/activation-early-marking.test.ts +6 -5
- package/src/__tests__/agent-loop-override-profile.test.ts +22 -25
- package/src/__tests__/agent-wake-override-profile.test.ts +21 -48
- package/src/__tests__/app-builder-tool-scripts.test.ts +0 -1
- package/src/__tests__/app-bundler.test.ts +4 -12
- package/src/__tests__/app-executors.test.ts +2 -49
- package/src/__tests__/app-routes-csp.test.ts +114 -146
- package/src/__tests__/auth-fallback-events-store.test.ts +8 -1
- package/src/__tests__/build-persisted-content.test.ts +96 -0
- package/src/__tests__/bundle-scanner.test.ts +27 -1
- package/src/__tests__/call-controller.test.ts +291 -0
- package/src/__tests__/call-site-routing-connection-auto-resolve.test.ts +165 -0
- package/src/__tests__/chat-credential-redaction.test.ts +1395 -0
- package/src/__tests__/chat-reveal-guard-priming.test.ts +791 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -1
- package/src/__tests__/compactor-image-manifest-trust.test.ts +50 -0
- package/src/__tests__/config-loader-backfill.test.ts +9 -4
- package/src/__tests__/config-schema-cmd.test.ts +10 -11
- package/src/__tests__/config-schema.test.ts +190 -257
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +208 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +5 -19
- package/src/__tests__/conversation-agent-loop.test.ts +22 -9
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +110 -0
- package/src/__tests__/conversation-process-callsite.test.ts +12 -19
- package/src/__tests__/conversation-routes-slash-commands.test.ts +7 -21
- package/src/__tests__/conversation-summarize-route.test.ts +36 -44
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +7 -7
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +0 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -1
- package/src/__tests__/conversation-usage.test.ts +4 -12
- package/src/__tests__/credential-routes.test.ts +250 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/db-migration-rollback.test.ts +22 -0
- package/src/__tests__/empty-response-hook.test.ts +186 -1
- package/src/__tests__/external-plugin-loader.test.ts +11 -5
- package/src/__tests__/heartbeat-service.test.ts +0 -28
- package/src/__tests__/host-shell-tool.test.ts +2 -0
- package/src/__tests__/inactive-tool-error-messages.test.ts +2 -2
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +52 -8
- package/src/__tests__/internal-telemetry-routes.test.ts +23 -4
- package/src/__tests__/invite-routes-http.test.ts +12 -16
- package/src/__tests__/list-all-apps.test.ts +0 -4
- package/src/__tests__/llm-context-resolution.test.ts +32 -56
- package/src/__tests__/llm-request-log-turn-query.test.ts +109 -0
- package/src/__tests__/llm-resolver-override-or-default.test.ts +3 -52
- package/src/__tests__/llm-resolver.test.ts +342 -602
- package/src/__tests__/llm-schema.test.ts +79 -37
- package/src/__tests__/max-tokens-continue-hook.test.ts +19 -0
- package/src/__tests__/media-stream-output.test.ts +259 -3
- package/src/__tests__/media-stream-server-integration.test.ts +22 -1
- package/src/__tests__/media-stream-stt-session.test.ts +47 -0
- package/src/__tests__/memory-jobs-worker-cleanup-cadence.test.ts +33 -0
- package/src/__tests__/memory-recall-log-store.test.ts +47 -13
- package/src/__tests__/mock-gateway-ipc.ts +46 -1
- package/src/__tests__/mtime-cache.test.ts +61 -0
- package/src/__tests__/navigate-settings-tab.test.ts +2 -0
- package/src/__tests__/normalize-onboarding.test.ts +33 -0
- package/src/__tests__/onboarding-persona-write.test.ts +26 -0
- package/src/__tests__/plugin-api-resolve-credential.test.ts +140 -0
- package/src/__tests__/plugin-app-serve-routes.test.ts +166 -14
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +2 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +38 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +27 -20
- package/src/__tests__/provider-connections-backfill.test.ts +138 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +10 -31
- package/src/__tests__/provider-registry-ollama.test.ts +8 -18
- package/src/__tests__/provider-send-message-override-profile.test.ts +23 -23
- package/src/__tests__/provider-usage-tracking.test.ts +9 -19
- package/src/__tests__/prune-old-conversations-job.test.ts +12 -0
- package/src/__tests__/published-app-updater.test.ts +22 -16
- package/src/__tests__/registry.test.ts +5 -16
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +22 -23
- package/src/__tests__/retry-thinking-adaptive-only.test.ts +43 -48
- package/src/__tests__/retry-thinking-tool-choice.test.ts +57 -66
- package/src/__tests__/retry-verbosity-normalization.test.ts +24 -23
- package/src/__tests__/reveal-success-registry.test.ts +123 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +130 -0
- package/src/__tests__/secret-fixtures.ts +9 -0
- package/src/__tests__/server-history-render.test.ts +28 -0
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/slack-share-routes.test.ts +0 -1
- package/src/__tests__/stt-stream-session.test.ts +6 -5
- package/src/__tests__/subagent-call-site-routing.test.ts +69 -95
- package/src/__tests__/subagent-disposal.test.ts +2 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +2 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +2 -0
- package/src/__tests__/subagent-manager-notify.test.ts +2 -0
- package/src/__tests__/subagent-role-registry.test.ts +37 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
- package/src/__tests__/subagent-terminal-message.test.ts +50 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -5
- package/src/__tests__/surface-completion-nudge-hook.test.ts +19 -0
- package/src/__tests__/telemetry-routes.test.ts +99 -19
- package/src/__tests__/tool-audit.test.ts +34 -4
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-profiler.test.ts +72 -1
- package/src/__tests__/tool-result-spool.test.ts +49 -4
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -1
- package/src/__tests__/ui-channel-variants.test.ts +108 -0
- package/src/__tests__/ui-shape-teaching.test.ts +255 -0
- package/src/__tests__/usage-attribution.test.ts +18 -41
- package/src/__tests__/user-plugin-loader.test.ts +4 -4
- package/src/__tests__/voice-config-update.test.ts +46 -0
- package/src/__tests__/voice-session-bridge.test.ts +216 -84
- package/src/__tests__/workspace-migration-131-drop-web-fetch-mode.test.ts +120 -0
- package/src/agent/loop.ts +4 -3
- package/src/api/events/open-conversation.test.ts +64 -0
- package/src/api/events/open-conversation.ts +33 -0
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -0
- package/src/apps/app-store.ts +25 -35
- package/src/bundler/app-bundler.ts +34 -48
- package/src/bundler/app-compiler.ts +39 -4
- package/src/bundler/bundle-scanner.ts +13 -0
- package/src/bundler/manifest.ts +1 -1
- package/src/calls/__tests__/voice-session-bridge.test.ts +47 -0
- package/src/calls/call-constants.ts +5 -0
- package/src/calls/call-controller.ts +100 -32
- package/src/calls/call-transport.ts +9 -0
- package/src/calls/media-stream-output.ts +107 -4
- package/src/calls/media-stream-server.ts +29 -9
- package/src/calls/media-stream-stt-session.ts +7 -1
- package/src/calls/media-turn-detector.ts +11 -1
- package/src/calls/voice-session-bridge.ts +84 -63
- package/src/cli/commands/__tests__/inference-providers.test.ts +270 -33
- package/src/cli/commands/__tests__/notifications.test.ts +24 -3
- package/src/cli/commands/config.help.ts +6 -6
- package/src/cli/commands/credentials.help.ts +13 -0
- package/src/cli/commands/credentials.ts +6 -1
- package/src/cli/commands/email.help.ts +7 -0
- package/src/cli/commands/email.ts +35 -1
- package/src/cli/commands/inference-providers.ts +168 -107
- package/src/cli/commands/inference.help.ts +118 -46
- package/src/cli/commands/memory/index.help.ts +23 -0
- package/src/cli/commands/memory/nodes.ts +146 -0
- package/src/cli/commands/notifications.help.ts +10 -10
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +40 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +54 -0
- package/src/cli/commands/oauth/connect.test.ts +126 -0
- package/src/cli/commands/oauth/connect.ts +29 -6
- package/src/cli/commands/oauth/index.help.ts +7 -1
- package/src/cli/commands/oauth/status.test.ts +69 -3
- package/src/cli/commands/oauth/status.ts +50 -12
- package/src/cli/commands/plugins.help.ts +13 -2
- package/src/cli/commands/plugins.ts +61 -7
- package/src/cli/commands/telemetry.help.ts +13 -0
- package/src/cli/commands/telemetry.ts +45 -5
- package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +8 -2
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +213 -9
- package/src/cli/lib/bundled-marketplace.json +93 -36
- package/src/cli/lib/inspect-plugin.ts +5 -1
- package/src/cli/lib/install-from-github.ts +68 -4
- package/src/cli/lib/plugin-catalog-local.ts +6 -2
- package/src/cli/lib/plugin-fingerprint.ts +3 -3
- package/src/cli/lib/upgrade-plugin.ts +236 -35
- package/src/config/__tests__/default-profile-catalog.test.ts +8 -12
- package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +137 -0
- package/src/config/__tests__/profile-materialization.test.ts +1 -88
- package/src/config/bundled-skills/AGENTS.md +3 -30
- package/src/config/bundled-skills/app-builder/SKILL.md +5 -3
- package/src/config/bundled-skills/app-builder/TOOLS.json +23 -0
- package/src/config/bundled-skills/app-builder/tools/app-open.ts +32 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +7 -7
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +3 -1
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +2 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +18 -10
- package/src/config/bundled-skills/subagent/SKILL.md +2 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
- package/src/config/call-site-defaults.ts +3 -3
- package/src/config/feature-flag-registry.json +24 -39
- package/src/config/llm-resolver.ts +88 -475
- package/src/config/profile-materialization.ts +11 -11
- package/src/config/schema.ts +93 -127
- package/src/config/schemas/__tests__/live-voice.test.ts +24 -6
- package/src/config/schemas/__tests__/stt.test.ts +31 -3
- package/src/config/schemas/live-voice.ts +10 -4
- package/src/config/schemas/llm.ts +52 -15
- package/src/config/schemas/memory-lifecycle.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +8 -0
- package/src/config/schemas/memory-v2.ts +2 -2
- package/src/config/schemas/memory-v3.ts +1 -1
- package/src/config/schemas/services.ts +6 -3
- package/src/config/schemas/stt.ts +38 -21
- package/src/config/schemas/tts.ts +13 -18
- package/src/config/skills.ts +31 -21
- package/src/context/compactor.ts +44 -7
- package/src/context/post-turn-tool-result-truncation.ts +4 -2
- package/src/context/tool-result-spool.ts +26 -5
- package/src/conversations/__tests__/message-consolidation.test.ts +48 -0
- package/src/conversations/message-consolidation.ts +22 -2
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +5 -12
- package/src/daemon/app-source-watcher.ts +17 -23
- package/src/daemon/chat-credential-redaction.ts +1365 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +627 -34
- package/src/daemon/conversation-agent-loop.ts +71 -31
- package/src/daemon/conversation-error.ts +36 -14
- package/src/daemon/conversation-process.ts +22 -0
- package/src/daemon/conversation-store.ts +35 -0
- package/src/daemon/conversation-surfaces.ts +25 -25
- package/src/daemon/conversation-tool-setup.ts +33 -7
- package/src/daemon/conversation.ts +55 -5
- package/src/daemon/handlers/shared.ts +33 -2
- package/src/daemon/lifecycle.ts +4 -4
- package/src/daemon/message-types/conversations.ts +6 -17
- package/src/daemon/providers-setup.ts +8 -0
- package/src/daemon/tool-setup-types.ts +7 -1
- package/src/daemon/wake-conversation-ops.ts +10 -1
- package/src/hooks/types.ts +9 -0
- package/src/ipc/__tests__/email-ipc.test.ts +90 -0
- package/src/ipc/gateway-client.test.ts +59 -0
- package/src/ipc/gateway-client.ts +70 -27
- package/src/live-voice/__tests__/live-voice-events.test.ts +14 -2
- package/src/live-voice/__tests__/live-voice-integration.test.ts +116 -2
- package/src/live-voice/__tests__/live-voice-vad.test.ts +804 -13
- package/src/live-voice/__tests__/protocol.test.ts +122 -0
- package/src/live-voice/live-voice-session.ts +443 -40
- package/src/live-voice/protocol.ts +143 -1
- package/src/monitoring/__tests__/plugin-source-watch.test.ts +3 -1
- package/src/monitoring/plugin-source-watch.ts +3 -62
- package/src/notifications/README.md +1 -1
- package/src/permissions/checker.ts +8 -4
- package/src/persistence/__tests__/db-init-migrations-ok.test.ts +26 -0
- package/src/persistence/conversation-crud.ts +104 -2
- package/src/persistence/db-init.ts +14 -3
- package/src/persistence/job-handlers/cleanup.ts +15 -7
- package/src/persistence/llm-request-log-store.ts +88 -52
- package/src/persistence/migrations/298-move-memory-jobs-to-memory-db.ts +7 -31
- package/src/persistence/migrations/305-drop-contact-acl-columns.ts +3 -2
- package/src/persistence/migrations/326-move-injection-events-to-memory-db.ts +8 -34
- package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +90 -0
- package/src/persistence/migrations/337-move-memory-recall-logs-to-memory-db.ts +114 -0
- package/src/persistence/migrations/338-move-memory-v3-selections-to-memory-db.ts +84 -0
- package/src/persistence/migrations/339-move-activation-sessions-to-memory-db.ts +52 -0
- package/src/persistence/migrations/__tests__/run-migrations.test.ts +155 -0
- package/src/persistence/migrations/helpers/relocation.ts +44 -1
- package/src/persistence/migrations/run-migrations.ts +25 -1
- package/src/persistence/schema/infrastructure.ts +9 -0
- package/src/persistence/schema/memory-core.ts +3 -0
- package/src/persistence/schema/memory-injection.ts +2 -0
- package/src/persistence/steps.ts +36 -0
- package/src/platform/client.test.ts +1 -44
- package/src/platform/client.ts +10 -20
- package/src/platform/consent-cache.test.ts +89 -23
- package/src/platform/consent-cache.ts +71 -33
- package/src/plugin-api/constants.ts +12 -0
- package/src/plugin-api/conversation-turn.ts +37 -14
- package/src/plugin-api/index.ts +11 -1
- package/src/plugin-api/resolve-credential.ts +75 -0
- package/src/plugin-api/vision-support.test.ts +8 -19
- package/src/plugin-api/vision-support.ts +26 -17
- package/src/plugins/collect-source-versions.ts +77 -0
- package/src/plugins/defaults/compaction/compact.ts +6 -0
- package/src/plugins/defaults/compaction/window-manager.ts +9 -0
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +18 -24
- package/src/plugins/defaults/empty-response/hooks/user-prompt-submit.ts +38 -0
- package/src/plugins/defaults/empty-response/refusal-quarantine.ts +99 -0
- package/src/plugins/defaults/image-fallback/__tests__/caption-cache-persistence.test.ts +7 -3
- package/src/plugins/defaults/index.ts +8 -1
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +48 -6
- package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +28 -22
- package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +148 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +80 -8
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +202 -0
- package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +64 -25
- package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +24 -11
- package/src/plugins/defaults/memory/__tests__/prompt-override.test.ts +70 -6
- package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +278 -0
- package/src/plugins/defaults/memory/activation-session-store.ts +27 -20
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -9
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +1 -8
- package/src/plugins/defaults/memory/graph/retriever.test.ts +6 -6
- package/src/plugins/defaults/memory/graph/store.ts +114 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +36 -1
- package/src/plugins/defaults/memory/graph/tools.ts +47 -13
- package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +16 -35
- package/src/plugins/defaults/memory/jobs-worker.ts +10 -1
- package/src/plugins/defaults/memory/memory-db.ts +3 -2
- package/src/plugins/defaults/memory/memory-recall-log-store.ts +129 -66
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +8 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +11 -122
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +216 -0
- package/src/plugins/defaults/memory/memory-v2-activation-log-store.ts +84 -46
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +42 -32
- package/src/plugins/defaults/memory/path-containment.ts +21 -0
- package/src/plugins/defaults/memory/prompt-override.ts +51 -13
- package/src/plugins/defaults/memory/tools.test.ts +34 -0
- package/src/plugins/defaults/memory/tools.ts +12 -2
- package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +19 -15
- package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +24 -19
- package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +19 -15
- package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +22 -2
- package/src/plugins/defaults/memory/v2/__tests__/prompts-consolidation.test.ts +5 -3
- package/src/plugins/defaults/memory/v2/harness/oracle.ts +59 -41
- package/src/plugins/defaults/memory/v2/harness/replay-input.ts +29 -25
- package/src/plugins/defaults/memory/v2/migration.ts +46 -16
- package/src/plugins/defaults/memory/v2/prompts/consolidation.ts +4 -0
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +17 -15
- package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +24 -22
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +9 -5
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +277 -10
- package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +57 -5
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +9 -7
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +38 -7
- package/src/plugins/defaults/memory/v3/hot-set.test.ts +36 -18
- package/src/plugins/defaults/memory/v3/hot-set.ts +12 -14
- package/src/plugins/defaults/memory/v3/learned-edges.test.ts +47 -27
- package/src/plugins/defaults/memory/v3/learned-edges.ts +12 -14
- package/src/plugins/defaults/memory/v3/orchestrate.ts +139 -22
- package/src/plugins/defaults/memory/v3/prune.test.ts +10 -3
- package/src/plugins/defaults/memory/v3/prune.ts +17 -11
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +23 -11
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +70 -53
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +9 -6
- package/src/plugins/external-plugin-loader.ts +15 -15
- package/src/plugins/mtime-cache.ts +47 -0
- package/src/plugins/pipeline.ts +9 -1
- package/src/plugins/plugin-execution-context.ts +44 -0
- package/src/plugins/plugin-tree-walk.ts +31 -24
- package/src/plugins/source-fingerprint.ts +3 -4
- package/src/prompts/normalize-onboarding.ts +12 -0
- package/src/prompts/persona-resolver.ts +8 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +1 -1
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +6 -9
- package/src/providers/__tests__/registry-native-web-search.test.ts +4 -10
- package/src/providers/__tests__/retry-callsite.test.ts +235 -215
- package/src/providers/__tests__/satellite-connection-routing.test.ts +8 -16
- package/src/providers/atlascloud/client.ts +10 -49
- package/src/providers/baseten/client.ts +43 -0
- package/src/providers/call-site-routing.ts +26 -13
- package/src/providers/connection-resolution.ts +9 -11
- package/src/providers/fetch-provider-catalog.ts +4 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +29 -4
- package/src/providers/inference/__tests__/connection-availability-keyless.test.ts +78 -0
- package/src/providers/inference/adapter-factory.ts +27 -6
- package/src/providers/inference/auth.ts +29 -1
- package/src/providers/inference/backfill.ts +61 -10
- package/src/providers/inference/connection-availability.ts +3 -2
- package/src/providers/inference/resolve-auth.ts +9 -1
- package/src/providers/model-catalog.ts +37 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +24 -2
- package/src/providers/openai/api-key-validation.ts +70 -0
- package/src/providers/retry.ts +2 -0
- package/src/providers/types.ts +11 -4
- package/src/providers/vellum-model-routing.test.ts +26 -0
- package/src/providers/vellum-model-routing.ts +30 -0
- package/src/providers/voice-error-copy.ts +47 -0
- package/src/runtime/agent-wake.ts +40 -24
- package/src/runtime/for-chat-mint-registry.ts +118 -0
- package/src/runtime/reveal-nonce.ts +49 -0
- package/src/runtime/reveal-success-registry.ts +306 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +88 -3
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +161 -30
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +7 -0
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +15 -0
- package/src/runtime/routes/app-management-routes.ts +152 -45
- package/src/runtime/routes/app-routes.ts +16 -77
- package/src/runtime/routes/canned-message-complete.ts +16 -16
- package/src/runtime/routes/conversation-management-routes.ts +17 -14
- package/src/runtime/routes/conversation-query-routes.ts +54 -6
- package/src/runtime/routes/conversation-routes.ts +48 -2
- package/src/runtime/routes/credential-routes.ts +116 -3
- package/src/runtime/routes/email-routes.ts +17 -1
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +33 -5
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +6 -5
- package/src/runtime/routes/inference-provider-connection-routes.ts +77 -28
- package/src/runtime/routes/inference-send-routes.ts +1 -1
- package/src/runtime/routes/internal-telemetry-routes.ts +7 -6
- package/src/runtime/routes/plugins-routes.ts +37 -6
- package/src/runtime/routes/publish-routes.ts +15 -18
- package/src/runtime/routes/schedule-worker-routes.ts +9 -0
- package/src/runtime/routes/secret-routes.ts +10 -0
- package/src/runtime/routes/telemetry-routes.ts +149 -45
- package/src/schedule/__tests__/schedule-timezone.test.ts +101 -0
- package/src/schedule/__tests__/worker-watchdog.test.ts +209 -0
- package/src/schedule/schedule-store.ts +12 -1
- package/src/schedule/schedule-timezone.ts +63 -0
- package/src/schedule/scheduler.ts +100 -6
- package/src/schedule/worker-control.ts +19 -0
- package/src/security/auth-fallback-events-store.ts +7 -6
- package/src/security/secret-scanner.ts +26 -1
- package/src/services/published-app-updater.ts +6 -11
- package/src/stt/stt-stream-session.ts +36 -16
- package/src/subagent/manager.ts +34 -8
- package/src/telemetry/AGENTS.md +30 -1
- package/src/telemetry/__tests__/config-setting-snapshot.test.ts +18 -0
- package/src/telemetry/__tests__/outbox-test-harness.ts +5 -3
- package/src/telemetry/config-setting-snapshot.ts +44 -10
- package/src/telemetry/telemetry-event-sources.test.ts +124 -30
- package/src/telemetry/telemetry-event-sources.ts +137 -83
- package/src/telemetry/telemetry-events-outbox.test.ts +46 -1
- package/src/telemetry/telemetry-events-outbox.ts +60 -9
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire-validation.ts +39 -2
- package/src/telemetry/telemetry-wire.generated.ts +8 -0
- package/src/telemetry/tool-audit.ts +15 -9
- package/src/telemetry/tool-executed-events-store.test.ts +1 -1
- package/src/telemetry/turn-events-store.ts +20 -0
- package/src/telemetry/types.ts +45 -12
- package/src/telemetry/usage-telemetry-reporter.test.ts +294 -25
- package/src/telemetry/usage-telemetry-reporter.ts +117 -18
- package/src/telemetry/watchdog-direct-emit.test.ts +11 -3
- package/src/telemetry/watchdog-direct-emit.ts +11 -6
- package/src/tools/apps/executors.ts +11 -36
- package/src/tools/executor.ts +14 -1
- package/src/tools/host-terminal/host-shell.ts +6 -2
- package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +1 -1
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +25 -0
- package/src/tools/network/web-fetch.ts +6 -2
- package/src/tools/skills/sandbox-runner.ts +5 -2
- package/src/tools/subagent/spawn.ts +7 -11
- package/src/tools/terminal/shell.ts +5 -2
- package/src/tools/tool-manifest.ts +0 -2
- package/src/tools/tool-profiler.ts +37 -6
- package/src/tools/ui-surface/channel-variants.ts +101 -0
- package/src/tools/ui-surface/definitions.ts +23 -67
- package/src/tools/ui-surface/surface-shape-docs.ts +229 -0
- package/src/tts/__tests__/provider-adapters.test.ts +18 -0
- package/src/tts/provider-catalog.ts +2 -4
- package/src/tts/providers/deepgram-provider.ts +10 -1
- package/src/types/onboarding-context.ts +8 -0
- package/src/usage/attribution.ts +18 -112
- package/src/{config/bundled-skills/messaging/tools/gmail-mime-helpers.ts → util/mime-type.ts} +4 -1
- package/src/util/provider-error-patterns.ts +7 -1
- package/src/util/worker-process.ts +105 -0
- package/src/watcher/__tests__/telemetry.test.ts +17 -4
- package/src/watcher/telemetry.ts +5 -5
- package/src/workspace/migrations/131-drop-web-fetch-mode.ts +61 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/workspace/provider-commit-message-generator.ts +6 -4
- package/src/__tests__/app-open-proxy.test.ts +0 -67
- package/src/onboarding/onboarding-research-events-store.test.ts +0 -230
- package/src/onboarding/onboarding-research-events-store.ts +0 -104
- package/src/runtime/routes/assets/vellum-design-system.css +0 -2236
- package/src/tools/apps/definitions.ts +0 -73
- package/src/tools/apps/open-proxy.ts +0 -43
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Upgrade a single installed plugin to
|
|
2
|
+
* Upgrade a single installed plugin to its source's current revision.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* A marketplace plugin pins to a full, immutable commit SHA (see
|
|
5
5
|
* {@link ./plugin-marketplace}); an upgrade re-materializes the install at
|
|
6
6
|
* whatever SHA the catalog currently advertises. Drift is detected with the
|
|
7
7
|
* same exact commit-SHA comparison {@link ./inspect-plugin} uses, so an
|
|
8
8
|
* upgrade is a no-op when the installed copy already matches the pin.
|
|
9
9
|
*
|
|
10
|
+
* A plugin installed directly from a GitHub URL (untrusted, not in the
|
|
11
|
+
* marketplace) is upgraded against its *recorded* source instead: its
|
|
12
|
+
* `install-meta.json` names the owner/repo/path/ref it was cloned from, and the
|
|
13
|
+
* upgrade target is whatever that ref resolves to now — a pinned SHA is
|
|
14
|
+
* immutable (a no-op), a branch / tag / `HEAD` advances as upstream does. Such
|
|
15
|
+
* an upgrade re-materializes verbatim, with no curated adapter overlay, exactly
|
|
16
|
+
* as the original untrusted install was (see {@link directUpgrade}).
|
|
17
|
+
*
|
|
10
18
|
* This is deliberately a distinct operation from install: `install` is
|
|
11
19
|
* first-time materialization (and errors on an existing install unless
|
|
12
20
|
* `--force` is passed), whereas `upgrade` moves an existing install forward.
|
|
@@ -36,11 +44,11 @@ import { PRESERVED_ENTRIES } from "../../plugins/plugin-tree-walk.js";
|
|
|
36
44
|
import { getWorkspacePluginsDir } from "../../util/platform.js";
|
|
37
45
|
import type { FetchLike } from "./fetch-like.js";
|
|
38
46
|
import {
|
|
47
|
+
fetchCommitDate,
|
|
39
48
|
inspectPlugin,
|
|
40
49
|
type PluginInspection,
|
|
41
50
|
PluginInspectNotFoundError,
|
|
42
51
|
type PluginLocalInfo,
|
|
43
|
-
type PluginRemoteInfo,
|
|
44
52
|
} from "./inspect-plugin.js";
|
|
45
53
|
import {
|
|
46
54
|
finalizeStagedInstall,
|
|
@@ -52,6 +60,7 @@ import {
|
|
|
52
60
|
PluginSourceUnavailableError,
|
|
53
61
|
type PostinstallRunner,
|
|
54
62
|
readInstallMeta,
|
|
63
|
+
resolveRefCommit,
|
|
55
64
|
sanitizePluginName,
|
|
56
65
|
} from "./install-from-github.js";
|
|
57
66
|
import { type ConflictLabels, mergePluginTree } from "./merge-plugin-tree.js";
|
|
@@ -191,23 +200,27 @@ function pluginTarget(name: string, deps: UpgradePluginDeps): string {
|
|
|
191
200
|
}
|
|
192
201
|
|
|
193
202
|
/**
|
|
194
|
-
* Move an installed plugin to
|
|
203
|
+
* Move an installed plugin to its source's current revision — the marketplace
|
|
204
|
+
* pin for a catalog plugin, or the recorded GitHub ref's current commit for a
|
|
205
|
+
* directly-installed one (delegated to {@link directUpgrade}).
|
|
195
206
|
*
|
|
196
|
-
* The `strategy` controls how local edits are reconciled with the
|
|
197
|
-
* `overwrite` (default) re-installs
|
|
207
|
+
* The `strategy` controls how local edits are reconciled with the target:
|
|
208
|
+
* `overwrite` (default) re-installs it wholesale; `ours`/`theirs`/
|
|
198
209
|
* `assistant` do a three-way merge that carries non-conflicting local edits
|
|
199
210
|
* forward, resolving conflicting hunks toward the local edit (`ours`) or the
|
|
200
|
-
*
|
|
201
|
-
* to resolve (`assistant`).
|
|
211
|
+
* target (`theirs`), or leaving git conflict markers in the file for the
|
|
212
|
+
* assistant to resolve (`assistant`).
|
|
202
213
|
*
|
|
203
214
|
* Throws {@link PluginNotInstalledError} when no copy is installed,
|
|
204
|
-
* {@link PluginNotUpgradableError} when the install
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
215
|
+
* {@link PluginNotUpgradableError} when the install is neither in the
|
|
216
|
+
* marketplace nor carries a recorded GitHub source to advance,
|
|
217
|
+
* {@link PluginMergeBaselineError} when a merge strategy is requested but the
|
|
218
|
+
* install-time baseline cannot be reconstructed,
|
|
219
|
+
* {@link PluginSourceUnavailableError} when the marketplace catalog or the
|
|
220
|
+
* plugin source is temporarily unreachable (a retryable outage, distinct from
|
|
221
|
+
* the permanent no-source case), and propagates {@link installPlugin}'s errors
|
|
222
|
+
* (e.g. source unavailable, postinstall failure) when the re-install itself
|
|
223
|
+
* fails.
|
|
211
224
|
*/
|
|
212
225
|
export async function upgradePlugin(
|
|
213
226
|
opts: UpgradePluginOptions,
|
|
@@ -233,11 +246,19 @@ export async function upgradePlugin(
|
|
|
233
246
|
switch (inspection.status) {
|
|
234
247
|
case "not-installed":
|
|
235
248
|
throw new PluginNotInstalledError(name, pluginTarget(name, deps));
|
|
236
|
-
case "not-in-marketplace":
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
249
|
+
case "not-in-marketplace": {
|
|
250
|
+
// The marketplace doesn't claim this name, but a plugin installed directly
|
|
251
|
+
// from a GitHub URL (untrusted) still has a recorded source to advance:
|
|
252
|
+
// upgrade it by re-fetching whatever its recorded ref now resolves to.
|
|
253
|
+
const local = inspection.local;
|
|
254
|
+
if (!local) {
|
|
255
|
+
throw new PluginNotUpgradableError(
|
|
256
|
+
name,
|
|
257
|
+
"it has no marketplace entry and no installed copy to upgrade",
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
return directUpgrade({ name, local, dryRun, strategy }, deps);
|
|
261
|
+
}
|
|
241
262
|
case "remote-unavailable":
|
|
242
263
|
// A transient catalog outage is not a permanent "cannot upgrade" state:
|
|
243
264
|
// the same request can succeed once the marketplace source recovers, so
|
|
@@ -309,17 +330,28 @@ export async function upgradePlugin(
|
|
|
309
330
|
strategy === "theirs" ||
|
|
310
331
|
strategy === "assistant"
|
|
311
332
|
) {
|
|
333
|
+
const [remoteOwner, remoteRepo] = remote.repo.split("/");
|
|
312
334
|
return mergeUpgrade(
|
|
313
335
|
{
|
|
314
336
|
name,
|
|
315
337
|
strategy,
|
|
316
338
|
local,
|
|
317
|
-
remote,
|
|
318
339
|
fromCommit,
|
|
319
340
|
fromTimestamp,
|
|
320
341
|
toCommit,
|
|
321
342
|
toTimestamp,
|
|
322
343
|
provenanceWasUnknown,
|
|
344
|
+
theirsSource: {
|
|
345
|
+
owner: remoteOwner ?? "",
|
|
346
|
+
repo: remoteRepo ?? "",
|
|
347
|
+
rootPath: remote.path,
|
|
348
|
+
ref: remote.commit,
|
|
349
|
+
},
|
|
350
|
+
// The install baseline re-materializes with the curated adapter overlay
|
|
351
|
+
// (canonical ref); the target reads its overlay at the marketplace ref
|
|
352
|
+
// the pin was advertised from.
|
|
353
|
+
baseStubRef: DEFAULT_PLUGIN_REF,
|
|
354
|
+
theirsStubRef: remote.marketplaceRef,
|
|
323
355
|
},
|
|
324
356
|
deps,
|
|
325
357
|
);
|
|
@@ -352,9 +384,176 @@ export async function upgradePlugin(
|
|
|
352
384
|
};
|
|
353
385
|
}
|
|
354
386
|
|
|
387
|
+
/**
|
|
388
|
+
* Upgrade a plugin the marketplace does not claim by re-fetching its recorded
|
|
389
|
+
* GitHub source — the untrusted-direct-install analogue of the marketplace
|
|
390
|
+
* upgrade above.
|
|
391
|
+
*
|
|
392
|
+
* A direct install (`plugins install <github-url>`) records the exact
|
|
393
|
+
* owner/repo/path/ref it was cloned from in its `install-meta.json`. Its
|
|
394
|
+
* "latest" is whatever that ref currently resolves to, so the upgrade target is
|
|
395
|
+
* {@link resolveRefCommit} of the recorded ref — a pinned full SHA is immutable
|
|
396
|
+
* (nothing to advance to), while a branch / tag / `HEAD` moves as upstream does.
|
|
397
|
+
* The move is then materialized verbatim, with no curated adapter overlay,
|
|
398
|
+
* exactly as the original untrusted install was.
|
|
399
|
+
*
|
|
400
|
+
* Throws {@link PluginNotUpgradableError} when no resolvable GitHub source was
|
|
401
|
+
* recorded (a manually-copied install), {@link PluginNotFoundError} when the
|
|
402
|
+
* recorded ref has vanished from the remote, {@link PluginMergeBaselineError}
|
|
403
|
+
* when a merge strategy's install-time baseline cannot be reconstructed, and
|
|
404
|
+
* {@link PluginSourceUnavailableError} on a transient source outage.
|
|
405
|
+
*/
|
|
406
|
+
async function directUpgrade(
|
|
407
|
+
ctx: {
|
|
408
|
+
readonly name: string;
|
|
409
|
+
readonly local: PluginLocalInfo;
|
|
410
|
+
readonly dryRun: boolean;
|
|
411
|
+
readonly strategy: PluginUpgradeStrategy;
|
|
412
|
+
},
|
|
413
|
+
deps: UpgradePluginDeps,
|
|
414
|
+
): Promise<PluginUpgradeResult> {
|
|
415
|
+
const { name, local, dryRun, strategy } = ctx;
|
|
416
|
+
const source = local.source;
|
|
417
|
+
// Without resolvable GitHub coordinates in the provenance sidecar (a
|
|
418
|
+
// manually-copied install, or a sidecar naming a non-github source) there is
|
|
419
|
+
// nothing to re-fetch.
|
|
420
|
+
if (!source || source.kind !== "github" || !source.owner || !source.repo) {
|
|
421
|
+
throw new PluginNotUpgradableError(
|
|
422
|
+
name,
|
|
423
|
+
"it has no marketplace entry and no recorded GitHub source to re-fetch from",
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
const fetchSource: PluginFetchSource = {
|
|
427
|
+
owner: source.owner,
|
|
428
|
+
repo: source.repo,
|
|
429
|
+
rootPath: source.path ?? "",
|
|
430
|
+
ref: source.ref,
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
const fromCommit = local.commit;
|
|
434
|
+
const fromTimestamp = local.committedAt;
|
|
435
|
+
const provenanceWasUnknown = fromCommit === null;
|
|
436
|
+
|
|
437
|
+
// Resolve what the recorded ref points at now, without cloning. A pinned
|
|
438
|
+
// full-SHA ref is immutable, so it resolves to itself — nothing to advance to.
|
|
439
|
+
const toCommit = await resolveRefCommit(fetchSource, deps.runGit);
|
|
440
|
+
if (toCommit === null) {
|
|
441
|
+
// The recorded ref is gone from the remote (deleted branch / tag) or the
|
|
442
|
+
// repo is unreachable as a hard failure — there is no revision to move to.
|
|
443
|
+
throw new PluginNotFoundError(
|
|
444
|
+
name,
|
|
445
|
+
fetchSource.ref,
|
|
446
|
+
`${fetchSource.owner}/${fetchSource.repo}`,
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (
|
|
451
|
+
fromCommit !== null &&
|
|
452
|
+
toCommit.toLowerCase() === fromCommit.toLowerCase()
|
|
453
|
+
) {
|
|
454
|
+
return {
|
|
455
|
+
name,
|
|
456
|
+
outcome: "already-up-to-date",
|
|
457
|
+
fromCommit,
|
|
458
|
+
fromTimestamp,
|
|
459
|
+
toCommit,
|
|
460
|
+
// The ref still points at the installed commit, so the "to" version is the
|
|
461
|
+
// "from" version — reuse its recorded timestamp rather than a fresh fetch.
|
|
462
|
+
toTimestamp: fromTimestamp,
|
|
463
|
+
target: local.target,
|
|
464
|
+
fileCount: null,
|
|
465
|
+
dryRun,
|
|
466
|
+
strategy,
|
|
467
|
+
conflicts: [],
|
|
468
|
+
binaryConflicts: [],
|
|
469
|
+
provenanceWasUnknown: false,
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (dryRun) {
|
|
474
|
+
// Preview: resolve the target commit's date the same way `plugins inspect`
|
|
475
|
+
// does, so the dry run shows the human-readable version it would move to.
|
|
476
|
+
const toTimestamp = await fetchCommitDate(
|
|
477
|
+
`${fetchSource.owner}/${fetchSource.repo}`,
|
|
478
|
+
toCommit,
|
|
479
|
+
deps.fetch,
|
|
480
|
+
);
|
|
481
|
+
return {
|
|
482
|
+
name,
|
|
483
|
+
outcome: "would-upgrade",
|
|
484
|
+
fromCommit,
|
|
485
|
+
fromTimestamp,
|
|
486
|
+
toCommit,
|
|
487
|
+
toTimestamp,
|
|
488
|
+
target: local.target,
|
|
489
|
+
fileCount: null,
|
|
490
|
+
dryRun: true,
|
|
491
|
+
strategy,
|
|
492
|
+
conflicts: [],
|
|
493
|
+
binaryConflicts: [],
|
|
494
|
+
provenanceWasUnknown,
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (
|
|
499
|
+
strategy === "ours" ||
|
|
500
|
+
strategy === "theirs" ||
|
|
501
|
+
strategy === "assistant"
|
|
502
|
+
) {
|
|
503
|
+
// A direct install carries no curated adapter overlay, so both the install
|
|
504
|
+
// baseline and the incoming revision re-materialize verbatim (`stubRef`
|
|
505
|
+
// null), pinned to the recorded install commit and the resolved target.
|
|
506
|
+
return mergeUpgrade(
|
|
507
|
+
{
|
|
508
|
+
name,
|
|
509
|
+
strategy,
|
|
510
|
+
local,
|
|
511
|
+
fromCommit,
|
|
512
|
+
fromTimestamp,
|
|
513
|
+
toCommit,
|
|
514
|
+
toTimestamp: null,
|
|
515
|
+
provenanceWasUnknown,
|
|
516
|
+
theirsSource: { ...fetchSource, ref: toCommit },
|
|
517
|
+
baseStubRef: null,
|
|
518
|
+
theirsStubRef: null,
|
|
519
|
+
},
|
|
520
|
+
deps,
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// overwrite (default): re-install the recorded direct source verbatim, moving
|
|
525
|
+
// to whatever its ref now resolves to. Untrusted — no curated adapter overlay,
|
|
526
|
+
// just as the original direct install was materialized.
|
|
527
|
+
const result = await installPlugin(
|
|
528
|
+
{ name, force: true, directSource: fetchSource },
|
|
529
|
+
{
|
|
530
|
+
fetch: deps.fetch,
|
|
531
|
+
workspacePluginsDir: deps.workspacePluginsDir,
|
|
532
|
+
runGit: deps.runGit,
|
|
533
|
+
runPostinstall: deps.runPostinstall,
|
|
534
|
+
},
|
|
535
|
+
);
|
|
536
|
+
|
|
537
|
+
return {
|
|
538
|
+
name,
|
|
539
|
+
outcome: "upgraded",
|
|
540
|
+
fromCommit,
|
|
541
|
+
fromTimestamp,
|
|
542
|
+
toCommit: result.commit ?? toCommit,
|
|
543
|
+
toTimestamp: result.committedAt,
|
|
544
|
+
target: result.target,
|
|
545
|
+
fileCount: result.fileCount,
|
|
546
|
+
dryRun: false,
|
|
547
|
+
strategy,
|
|
548
|
+
conflicts: [],
|
|
549
|
+
binaryConflicts: [],
|
|
550
|
+
provenanceWasUnknown,
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
|
|
355
554
|
/**
|
|
356
555
|
* Carry local edits forward by three-way merging the on-disk install (`ours`)
|
|
357
|
-
* and the
|
|
556
|
+
* and the incoming revision (`theirs`) against the re-materialized install commit
|
|
358
557
|
* (`base`), then atomically swapping the merged tree into place pinned at the
|
|
359
558
|
* new commit. Conflicting hunks resolve toward `ours` or `theirs` per the
|
|
360
559
|
* strategy, or are left as git conflict markers under `assistant`;
|
|
@@ -365,16 +564,25 @@ async function mergeUpgrade(
|
|
|
365
564
|
readonly name: string;
|
|
366
565
|
readonly strategy: "ours" | "theirs" | "assistant";
|
|
367
566
|
readonly local: PluginLocalInfo;
|
|
368
|
-
readonly remote: PluginRemoteInfo;
|
|
369
567
|
readonly fromCommit: string | null;
|
|
370
568
|
readonly fromTimestamp: string | null;
|
|
371
569
|
readonly toCommit: string;
|
|
372
570
|
readonly toTimestamp: string | null;
|
|
373
571
|
readonly provenanceWasUnknown: boolean;
|
|
572
|
+
/** Coordinates of the revision being merged in (`theirs`), pinned to {@link ctx.toCommit}. */
|
|
573
|
+
readonly theirsSource: PluginFetchSource;
|
|
574
|
+
/**
|
|
575
|
+
* Curated-adapter-stub ref overlaid when re-materializing the install
|
|
576
|
+
* baseline, or `null` for a direct (untrusted) install that carries no
|
|
577
|
+
* curated overlay.
|
|
578
|
+
*/
|
|
579
|
+
readonly baseStubRef: string | null;
|
|
580
|
+
/** Curated-adapter-stub ref overlaid on the incoming revision, or `null` for a direct install. */
|
|
581
|
+
readonly theirsStubRef: string | null;
|
|
374
582
|
},
|
|
375
583
|
deps: UpgradePluginDeps,
|
|
376
584
|
): Promise<PluginUpgradeResult> {
|
|
377
|
-
const { name, strategy, local,
|
|
585
|
+
const { name, strategy, local, theirsSource } = ctx;
|
|
378
586
|
|
|
379
587
|
// Marker labels name each side by its commit so the assistant can tell the
|
|
380
588
|
// local edit from the incoming pin when resolving.
|
|
@@ -401,13 +609,6 @@ async function mergeUpgrade(
|
|
|
401
609
|
rootPath: meta.source.path ?? "",
|
|
402
610
|
ref: meta.commit,
|
|
403
611
|
};
|
|
404
|
-
const [remoteOwner, remoteRepo] = remote.repo.split("/");
|
|
405
|
-
const theirsSource: PluginFetchSource = {
|
|
406
|
-
owner: remoteOwner ?? "",
|
|
407
|
-
repo: remoteRepo ?? "",
|
|
408
|
-
rootPath: remote.path,
|
|
409
|
-
ref: remote.commit,
|
|
410
|
-
};
|
|
411
612
|
|
|
412
613
|
const pluginsDir = deps.workspacePluginsDir ?? getWorkspacePluginsDir();
|
|
413
614
|
const baseDir = mkdtempSync(join(tmpdir(), `plugin-upgrade-base-${name}-`));
|
|
@@ -429,7 +630,7 @@ async function mergeUpgrade(
|
|
|
429
630
|
{
|
|
430
631
|
source: baseSource,
|
|
431
632
|
name,
|
|
432
|
-
stubRef:
|
|
633
|
+
stubRef: ctx.baseStubRef,
|
|
433
634
|
destDir: baseDir,
|
|
434
635
|
},
|
|
435
636
|
deps,
|
|
@@ -457,7 +658,7 @@ async function mergeUpgrade(
|
|
|
457
658
|
{
|
|
458
659
|
source: theirsSource,
|
|
459
660
|
name,
|
|
460
|
-
stubRef:
|
|
661
|
+
stubRef: ctx.theirsStubRef,
|
|
461
662
|
destDir: theirsDir,
|
|
462
663
|
},
|
|
463
664
|
deps,
|
|
@@ -479,8 +680,8 @@ async function mergeUpgrade(
|
|
|
479
680
|
conflictLabels,
|
|
480
681
|
});
|
|
481
682
|
|
|
482
|
-
const toCommit = theirs.commit ??
|
|
483
|
-
const toTimestamp = theirs.committedAt ??
|
|
683
|
+
const toCommit = theirs.commit ?? ctx.toCommit;
|
|
684
|
+
const toTimestamp = theirs.committedAt ?? ctx.toTimestamp;
|
|
484
685
|
finalizeStagedInstall(stagingDir, {
|
|
485
686
|
name,
|
|
486
687
|
source: theirsSource,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import { setOverridesForTesting } from "../../__tests__/feature-flag-test-helpers.js";
|
|
4
3
|
import { resolveModelIntent } from "../../providers/model-intents.js";
|
|
5
4
|
import { CALL_SITE_DEFAULTS } from "../call-site-defaults.js";
|
|
6
5
|
import {
|
|
@@ -177,7 +176,7 @@ describe("resolver integration", () => {
|
|
|
177
176
|
}
|
|
178
177
|
});
|
|
179
178
|
|
|
180
|
-
test("a disabled managed default
|
|
179
|
+
test("a disabled managed default does not divert resolution to the custom-* clone", () => {
|
|
181
180
|
const llm = LLMSchema.parse({
|
|
182
181
|
profiles: {
|
|
183
182
|
balanced: { source: "managed", status: "disabled" },
|
|
@@ -189,18 +188,15 @@ describe("resolver integration", () => {
|
|
|
189
188
|
},
|
|
190
189
|
},
|
|
191
190
|
});
|
|
192
|
-
//
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const resolved = resolveCallSiteConfig("mainAgent", llm);
|
|
196
|
-
expect(resolved.model).toBe("claude-sonnet-4-6");
|
|
197
|
-
// Override-or-default: the hop is gone — the fallback anchor is the
|
|
198
|
-
// code-owned intent, and a legacy disabled stub does not suppress it.
|
|
199
|
-
setOverridesForTesting({});
|
|
191
|
+
// The fallback anchor is the code-owned intent: a legacy disabled stub
|
|
192
|
+
// does not suppress it, and the user-mutable custom-* clone never
|
|
193
|
+
// captures the call site.
|
|
200
194
|
expect(resolveDefaultProfileKey("mainAgent", llm)).toBe("balanced");
|
|
201
|
-
|
|
202
|
-
|
|
195
|
+
const resolved = resolveCallSiteConfig("mainAgent", llm);
|
|
196
|
+
expect(resolved.model).toBe(
|
|
197
|
+
CODE_DEFAULT_PROFILE_ENTRIES.balanced.model as string,
|
|
203
198
|
);
|
|
199
|
+
expect(resolved.model).not.toBe("claude-sonnet-4-6");
|
|
204
200
|
});
|
|
205
201
|
});
|
|
206
202
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for plugin-resident skill discovery in `loadSkillCatalog`.
|
|
3
|
+
*
|
|
4
|
+
* The catalog surfaces skills a plugin ships at `plugins/<dir>/skills/<id>/`.
|
|
5
|
+
* The gate is a loadable manifest (parseable `package.json` with a non-empty
|
|
6
|
+
* `name`) — the manifest `name` need NOT equal the install directory name.
|
|
7
|
+
* That match must not be required: a plugin is installed under its marketplace
|
|
8
|
+
* slug or GitHub path leaf, which routinely differs from its `package.json`
|
|
9
|
+
* `name` (e.g. cognee installs to `cognee`/`vellum-assistant` while its package
|
|
10
|
+
* is named `cognee-memory`). Requiring the match silently drops the plugin's
|
|
11
|
+
* skills even though the runtime loads its hooks and tools fine.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { beforeEach, describe, expect, test } from "bun:test";
|
|
16
|
+
|
|
17
|
+
import { getWorkspacePluginsDir } from "../../util/platform.js";
|
|
18
|
+
import { loadSkillCatalog } from "../skills.js";
|
|
19
|
+
|
|
20
|
+
function writePlugin(
|
|
21
|
+
dirName: string,
|
|
22
|
+
packageName: string,
|
|
23
|
+
skills: Array<{ id: string; description: string }>,
|
|
24
|
+
opts: { disabled?: boolean; packageJson?: string | null } = {},
|
|
25
|
+
): void {
|
|
26
|
+
const pluginDir = join(getWorkspacePluginsDir(), dirName);
|
|
27
|
+
mkdirSync(pluginDir, { recursive: true });
|
|
28
|
+
|
|
29
|
+
if (opts.packageJson === null) {
|
|
30
|
+
// Intentionally omit package.json.
|
|
31
|
+
} else {
|
|
32
|
+
writeFileSync(
|
|
33
|
+
join(pluginDir, "package.json"),
|
|
34
|
+
opts.packageJson ??
|
|
35
|
+
JSON.stringify({
|
|
36
|
+
name: packageName,
|
|
37
|
+
version: "1.0.0",
|
|
38
|
+
peerDependencies: { "@vellumai/plugin-api": "*" },
|
|
39
|
+
}),
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (opts.disabled) writeFileSync(join(pluginDir, ".disabled"), "");
|
|
44
|
+
|
|
45
|
+
for (const skill of skills) {
|
|
46
|
+
const skillDir = join(pluginDir, "skills", skill.id);
|
|
47
|
+
mkdirSync(skillDir, { recursive: true });
|
|
48
|
+
writeFileSync(
|
|
49
|
+
join(skillDir, "SKILL.md"),
|
|
50
|
+
`---\nname: ${skill.id}\ndescription: ${skill.description}\n---\n\nBody for ${skill.id}.\n`,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function skillById(id: string) {
|
|
56
|
+
return loadSkillCatalog().find((s) => s.id === id);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
describe("discoverPluginResidentSkills (via loadSkillCatalog)", () => {
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
const pluginsDir = getWorkspacePluginsDir();
|
|
62
|
+
if (existsSync(pluginsDir))
|
|
63
|
+
rmSync(pluginsDir, { recursive: true, force: true });
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("surfaces a plugin skill when the install dir name differs from package.json name", () => {
|
|
67
|
+
// dir `vellum-assistant` (GitHub path leaf) vs package `cognee-memory`:
|
|
68
|
+
// the exact cognee shape that was silently dropped before.
|
|
69
|
+
writePlugin("vellum-assistant", "cognee-memory", [
|
|
70
|
+
{
|
|
71
|
+
id: "qa-cognee-sync",
|
|
72
|
+
description: "Sync session memory into the graph.",
|
|
73
|
+
},
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
const skill = skillById("qa-cognee-sync");
|
|
77
|
+
expect(skill).toBeDefined();
|
|
78
|
+
expect(skill!.source).toBe("plugin");
|
|
79
|
+
// Attribution is the install slug (directory name), which is the identity
|
|
80
|
+
// used by `plugins list` and per-conversation plugin scoping.
|
|
81
|
+
expect(skill!.owner).toEqual({ kind: "plugin", id: "vellum-assistant" });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("surfaces a plugin skill when dir name equals package.json name", () => {
|
|
85
|
+
writePlugin("demo-matched", "demo-matched", [
|
|
86
|
+
{ id: "qa-matched-skill", description: "A matched-name plugin skill." },
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
const skill = skillById("qa-matched-skill");
|
|
90
|
+
expect(skill).toBeDefined();
|
|
91
|
+
expect(skill!.owner).toEqual({ kind: "plugin", id: "demo-matched" });
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("skips a plugin directory that has no package.json", () => {
|
|
95
|
+
writePlugin(
|
|
96
|
+
"no-manifest",
|
|
97
|
+
"unused",
|
|
98
|
+
[{ id: "qa-no-manifest-skill", description: "Should not surface." }],
|
|
99
|
+
{ packageJson: null },
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
expect(skillById("qa-no-manifest-skill")).toBeUndefined();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("skips a plugin directory whose package.json is unparseable", () => {
|
|
106
|
+
writePlugin(
|
|
107
|
+
"bad-manifest",
|
|
108
|
+
"unused",
|
|
109
|
+
[{ id: "qa-bad-manifest-skill", description: "Should not surface." }],
|
|
110
|
+
{ packageJson: "{ not valid json" },
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
expect(skillById("qa-bad-manifest-skill")).toBeUndefined();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("skips a plugin directory whose package.json has no name", () => {
|
|
117
|
+
writePlugin(
|
|
118
|
+
"nameless",
|
|
119
|
+
"unused",
|
|
120
|
+
[{ id: "qa-nameless-skill", description: "Should not surface." }],
|
|
121
|
+
{ packageJson: JSON.stringify({ version: "1.0.0" }) },
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
expect(skillById("qa-nameless-skill")).toBeUndefined();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("hides resident skills of a disabled plugin", () => {
|
|
128
|
+
writePlugin(
|
|
129
|
+
"disabled-plugin",
|
|
130
|
+
"disabled-pkg",
|
|
131
|
+
[{ id: "qa-disabled-skill", description: "Hidden while disabled." }],
|
|
132
|
+
{ disabled: true },
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
expect(skillById("qa-disabled-skill")).toBeUndefined();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
3
|
import { VELLUM_MANAGED_CONNECTION_NAME } from "../../providers/vellum-model-routing.js";
|
|
4
|
-
import { resolveCallSiteConfig } from "../llm-resolver.js";
|
|
5
4
|
import { completeCustomProfile } from "../profile-materialization.js";
|
|
6
|
-
import { LLMConfigBase,
|
|
5
|
+
import { LLMConfigBase, ProfileEntry } from "../schemas/llm.js";
|
|
7
6
|
|
|
8
7
|
const fullDefault = LLMConfigBase.parse({
|
|
9
8
|
provider: "anthropic",
|
|
@@ -209,89 +208,3 @@ describe("completeCustomProfile", () => {
|
|
|
209
208
|
expect(completed.contextWindow).not.toBe(fullDefault.contextWindow);
|
|
210
209
|
});
|
|
211
210
|
});
|
|
212
|
-
|
|
213
|
-
// Equivalence with the live deep-merge resolver: on a profile-less call site
|
|
214
|
-
// with no activeProfile, the custom profile is the only profile layer above
|
|
215
|
-
// `llm.default`, which is exactly the standalone meaning materialization
|
|
216
|
-
// bakes in. Partial and completed forms must resolve identically — this is
|
|
217
|
-
// the contract that lets migration 128 rewrite profiles without changing
|
|
218
|
-
// behavior under the current resolver, and lets the M6 resolver treat the
|
|
219
|
-
// completed form as the profile's full meaning.
|
|
220
|
-
//
|
|
221
|
-
// (Deliberately NOT covered: a partial profile layered above other profiles
|
|
222
|
-
// — e.g. mainAgent activeProfile above the balanced call-site layer — where
|
|
223
|
-
// omitted fields inherit from the mid layer today. That context-dependent
|
|
224
|
-
// meaning is unrepresentable as a single complete profile; the standalone
|
|
225
|
-
// reading is the one that ships. See the M6 plan, Behavior changes #4.)
|
|
226
|
-
describe("completeCustomProfile — resolver equivalence", () => {
|
|
227
|
-
const PARTIALS: Record<string, ProfileEntry> = {
|
|
228
|
-
empty: {},
|
|
229
|
-
"model only, served by default provider": { model: "claude-fable-5" },
|
|
230
|
-
"model only, implies another provider": { model: "gpt-5.5" },
|
|
231
|
-
"sampling only": { temperature: 0.3 },
|
|
232
|
-
"explicit null sampling": { temperature: null },
|
|
233
|
-
"nested thinking fragment": { thinking: { enabled: false } },
|
|
234
|
-
"tokens and effort": { maxTokens: 1234, effort: "low" },
|
|
235
|
-
"explicit cross-provider without connection": {
|
|
236
|
-
provider: "openai",
|
|
237
|
-
model: "gpt-5.4",
|
|
238
|
-
},
|
|
239
|
-
"complete profile": {
|
|
240
|
-
provider: "openai",
|
|
241
|
-
model: "gpt-5.4",
|
|
242
|
-
provider_connection: "openai-personal",
|
|
243
|
-
maxTokens: 9000,
|
|
244
|
-
effort: "high",
|
|
245
|
-
temperature: 0.1,
|
|
246
|
-
topP: 0.5,
|
|
247
|
-
},
|
|
248
|
-
"metadata alongside config": {
|
|
249
|
-
model: "gpt-5.5",
|
|
250
|
-
label: "My GPT",
|
|
251
|
-
description: "d",
|
|
252
|
-
status: "active",
|
|
253
|
-
},
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
// Run the whole matrix against two defaults: the schema-typical null
|
|
257
|
-
// sampling, and a default with non-null temperature/topP — the latter is
|
|
258
|
-
// what catches sampling-inheritance regressions (null defaults make those
|
|
259
|
-
// cases pass vacuously).
|
|
260
|
-
const DEFAULTS: Record<string, LLMConfigBase> = {
|
|
261
|
-
"null sampling": fullDefault,
|
|
262
|
-
"non-null sampling": LLMConfigBase.parse({
|
|
263
|
-
...fullDefault,
|
|
264
|
-
temperature: 0.7,
|
|
265
|
-
topP: 0.9,
|
|
266
|
-
}),
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
const resolveWith = (dflt: LLMConfigBase, profile: ProfileEntry) => {
|
|
270
|
-
const llm = LLMSchema.parse({
|
|
271
|
-
default: dflt,
|
|
272
|
-
profiles: { "custom-x": { source: "user", ...profile } },
|
|
273
|
-
});
|
|
274
|
-
return resolveCallSiteConfig("vision", llm, {
|
|
275
|
-
overrideProfile: "custom-x",
|
|
276
|
-
// The equivalence contract is a legacy-cascade property by definition:
|
|
277
|
-
// materialization pins what the MERGE produced. Under
|
|
278
|
-
// override-or-default semantics a partial profile falls back instead
|
|
279
|
-
// of merging (pinned by llm-resolver-override-or-default.test.ts).
|
|
280
|
-
resolutionSemantics: "legacy-merge",
|
|
281
|
-
});
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
for (const [defaultName, dflt] of Object.entries(DEFAULTS)) {
|
|
285
|
-
for (const [name, partial] of Object.entries(PARTIALS)) {
|
|
286
|
-
test(`partial and completed resolve identically (${defaultName} default): ${name}`, () => {
|
|
287
|
-
const completed = completeCustomProfile(dflt, {
|
|
288
|
-
source: "user",
|
|
289
|
-
...partial,
|
|
290
|
-
});
|
|
291
|
-
expect(resolveWith(dflt, completed)).toEqual(
|
|
292
|
-
resolveWith(dflt, partial),
|
|
293
|
-
);
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
});
|