@vellumai/assistant 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +2 -7
- package/Dockerfile +75 -1
- package/bun.lock +11 -1
- package/docker-entrypoint.sh +5 -0
- package/docker-init-apt-root.sh +94 -0
- package/docker-kata-apt-env.sh +39 -0
- package/docs/plugins.md +88 -47
- package/docs/skills.md +9 -7
- package/examples/plugins/echo/README.md +27 -27
- package/examples/plugins/echo/package.json +3 -0
- package/examples/plugins/echo/register.ts +31 -31
- package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
- package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
- package/openapi.yaml +325 -3
- package/package.json +3 -1
- package/scripts/generate-openapi.ts +83 -10
- package/scripts/sync-llm-catalog.ts +2 -2
- package/scripts/sync-web-search-catalog.ts +47 -25
- package/src/__tests__/agent-image-optimize.test.ts +11 -3
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
- package/src/__tests__/anthropic-provider.test.ts +45 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
- package/src/__tests__/app-executors.test.ts +220 -4
- package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/channel-availability-routes.test.ts +206 -0
- package/src/__tests__/channel-delivery-store.test.ts +289 -1
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
- package/src/__tests__/clawhub.test.ts +75 -16
- package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
- package/src/__tests__/config-schema.test.ts +21 -0
- package/src/__tests__/config-set-route.test.ts +80 -0
- package/src/__tests__/config-sounds-sync.test.ts +97 -0
- package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
- package/src/__tests__/context-search-conversations-source.test.ts +117 -2
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +7 -0
- package/src/__tests__/context-token-estimator.test.ts +1 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
- package/src/__tests__/conversation-agent-loop.test.ts +2 -0
- package/src/__tests__/conversation-error.test.ts +42 -3
- package/src/__tests__/conversation-fork-crud.test.ts +82 -0
- package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
- package/src/__tests__/conversation-lifecycle.test.ts +173 -0
- package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
- package/src/__tests__/conversation-pairing.test.ts +54 -0
- package/src/__tests__/conversation-process-callsite.test.ts +4 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
- package/src/__tests__/conversation-queue.test.ts +4 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +76 -9
- package/src/__tests__/conversation-slash-queue.test.ts +59 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
- package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
- package/src/__tests__/conversation-sync-tags.test.ts +235 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +3 -2
- package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
- package/src/__tests__/disk-pressure-tools.test.ts +1 -0
- package/src/__tests__/dm-backfill.test.ts +121 -10
- package/src/__tests__/document-tool-security.test.ts +258 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/edit-propagation.test.ts +33 -0
- package/src/__tests__/empty-response-pipeline.test.ts +0 -4
- package/src/__tests__/external-plugin-loader.test.ts +60 -36
- package/src/__tests__/filing-service.test.ts +140 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
- package/src/__tests__/helpers/tar-fixtures.ts +39 -0
- package/src/__tests__/helpers/wait-for.ts +21 -0
- package/src/__tests__/history-repair-pipeline.test.ts +0 -3
- package/src/__tests__/history-repair.test.ts +73 -0
- package/src/__tests__/host-app-control-proxy.test.ts +266 -10
- package/src/__tests__/image-credentials.test.ts +1 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
- package/src/__tests__/inference-profile-reaper.test.ts +4 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
- package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
- package/src/__tests__/injector-chain.test.ts +10 -8
- package/src/__tests__/install-skill-routing.test.ts +155 -37
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +92 -3
- package/src/__tests__/list-messages-page-latest.test.ts +55 -0
- package/src/__tests__/llm-call-pipeline.test.ts +0 -3
- package/src/__tests__/llm-catalog-parity.test.ts +55 -13
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +34 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
- package/src/__tests__/llm-usage-store.test.ts +114 -0
- package/src/__tests__/managed-profile-guard.test.ts +31 -29
- package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
- package/src/__tests__/managed-store.test.ts +84 -192
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
- package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
- package/src/__tests__/oauth-commands-routes.test.ts +168 -16
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
- package/src/__tests__/openai-provider.test.ts +24 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
- package/src/__tests__/persistence-pipeline.test.ts +0 -2
- package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +1 -1
- package/src/__tests__/platform.test.ts +2 -0
- package/src/__tests__/plugin-api-shim.test.ts +125 -0
- package/src/__tests__/plugin-bootstrap.test.ts +10 -36
- package/src/__tests__/plugin-external-api.test.ts +68 -0
- package/src/__tests__/plugin-registry.test.ts +0 -77
- package/src/__tests__/plugin-route-contribution.test.ts +0 -1
- package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
- package/src/__tests__/plugin-types.test.ts +3 -13
- package/src/__tests__/process-message-background-slack.test.ts +8 -1
- package/src/__tests__/process-message-display-content.test.ts +421 -0
- package/src/__tests__/provider-catalog-visibility.test.ts +142 -0
- package/src/__tests__/provider-error-scenarios.test.ts +111 -0
- package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +8 -8
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
- package/src/__tests__/schedule-routes.test.ts +50 -3
- package/src/__tests__/schedule-store.test.ts +94 -0
- package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
- package/src/__tests__/schema-transforms.test.ts +20 -0
- package/src/__tests__/search-skills-unified.test.ts +0 -5
- package/src/__tests__/server-history-render.test.ts +43 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
- package/src/__tests__/skill-load-tool.test.ts +27 -89
- package/src/__tests__/skill-memory.test.ts +23 -3
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
- package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
- package/src/__tests__/skills-install-extract.test.ts +49 -38
- package/src/__tests__/skills-install-staging.test.ts +159 -0
- package/src/__tests__/skills-uninstall.test.ts +9 -41
- package/src/__tests__/skills.test.ts +51 -58
- package/src/__tests__/slack-channel-config.test.ts +9 -0
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/system-prompt.test.ts +737 -63
- package/src/__tests__/terminal-tools.test.ts +28 -1
- package/src/__tests__/thread-backfill.test.ts +557 -27
- package/src/__tests__/title-generate-pipeline.test.ts +0 -13
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
- package/src/__tests__/tool-error-pipeline.test.ts +0 -3
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +16 -4
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
- package/src/__tests__/turn-events-store.test.ts +256 -0
- package/src/__tests__/twilio-routes.test.ts +4 -0
- package/src/__tests__/user-plugin-loader.test.ts +0 -7
- package/src/__tests__/voice-session-bridge.test.ts +198 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
- package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
- package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
- package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
- package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
- package/src/acp/resolve-agent.ts +1 -1
- package/src/agent/image-optimize.ts +13 -5
- package/src/calls/voice-session-bridge.ts +61 -42
- package/src/channels/types.ts +108 -0
- package/src/cli/__tests__/unknown-command.test.ts +24 -0
- package/src/cli/commands/__tests__/changelog.test.ts +304 -319
- package/src/cli/commands/__tests__/schedules.test.ts +491 -0
- package/src/cli/commands/changelog.ts +106 -42
- package/src/cli/commands/conversations.ts +102 -17
- package/src/cli/commands/default-action.ts +10 -53
- package/src/cli/commands/notifications.ts +329 -317
- package/src/cli/commands/plugins.ts +185 -0
- package/src/cli/commands/schedules.ts +391 -0
- package/src/cli/commands/telemetry.ts +40 -0
- package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
- package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
- package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
- package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
- package/src/cli/lib/cli-colors.ts +12 -0
- package/src/cli/lib/confirm-prompt.ts +79 -0
- package/src/cli/lib/install-from-github.ts +304 -0
- package/src/cli/lib/list-installed-plugins.ts +137 -0
- package/src/cli/lib/uninstall-plugin.ts +82 -0
- package/src/cli/lib/unknown-command.ts +111 -0
- package/src/cli/program.ts +38 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
- package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
- package/src/config/bundled-skills/document/SKILL.md +23 -3
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
- package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
- package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
- package/src/config/bundled-tool-registry.ts +6 -0
- package/src/config/feature-flag-registry.json +41 -1
- package/src/config/loader.ts +64 -38
- package/src/config/schema.ts +7 -10
- package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
- package/src/config/schemas/channels.ts +8 -0
- package/src/config/schemas/compaction.ts +28 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm-request-logs.ts +31 -7
- package/src/config/schemas/llm.ts +3 -0
- package/src/config/schemas/memory-retrieval.ts +18 -0
- package/src/config/schemas/tools.ts +14 -0
- package/src/config/skills.ts +3 -96
- package/src/context/compactor.ts +1047 -0
- package/src/context/token-estimator.ts +2 -2
- package/src/context/window-manager.ts +197 -1520
- package/src/credential-execution/managed-catalog.ts +37 -0
- package/src/credential-health/credential-health-service.ts +280 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +34 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
- package/src/daemon/approval-generators.ts +8 -6
- package/src/daemon/config-watcher.ts +94 -31
- package/src/daemon/conversation-agent-loop.ts +169 -9
- package/src/daemon/conversation-error.ts +171 -37
- package/src/daemon/conversation-lifecycle.ts +53 -40
- package/src/daemon/conversation-messaging.ts +25 -6
- package/src/daemon/conversation-process.ts +49 -12
- package/src/daemon/conversation-runtime-assembly.ts +16 -1
- package/src/daemon/conversation-slash.ts +12 -5
- package/src/daemon/conversation-store.ts +11 -4
- package/src/daemon/conversation-tool-setup.ts +39 -7
- package/src/daemon/conversation.ts +33 -1
- package/src/daemon/external-plugins-bootstrap.ts +217 -181
- package/src/daemon/first-greeting.ts +22 -2
- package/src/daemon/handlers/config-model.ts +6 -5
- package/src/daemon/handlers/config-slack-channel.ts +15 -3
- package/src/daemon/handlers/shared.ts +14 -5
- package/src/daemon/handlers/skills.ts +111 -108
- package/src/daemon/history-repair.ts +28 -1
- package/src/daemon/host-app-control-proxy.ts +98 -23
- package/src/daemon/lifecycle.ts +45 -35
- package/src/daemon/meet-host-supervisor.ts +5 -4
- package/src/daemon/memory-v2-startup.ts +49 -0
- package/src/daemon/message-protocol.ts +1 -0
- package/src/daemon/message-types/conversations.ts +25 -0
- package/src/daemon/message-types/messages.ts +61 -0
- package/src/daemon/message-types/subagents.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pkb-reminder-builder.test.ts +1 -1
- package/src/daemon/pkb-reminder-builder.ts +1 -1
- package/src/daemon/plugin-source-watcher.ts +146 -0
- package/src/daemon/process-message.ts +21 -3
- package/src/daemon/server.ts +11 -2
- package/src/daemon/skill-memory-refresh.ts +29 -0
- package/src/documents/document-store.ts +221 -3
- package/src/embedded/plugin-api.ts +40 -0
- package/src/filing/filing-service.ts +39 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +91 -6
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +41 -0
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/feed-types.ts +22 -0
- package/src/home/post-connect-feed.ts +1 -0
- package/src/index.ts +18 -1
- package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
- package/src/mcp/client.ts +20 -4
- package/src/media/image-credentials.ts +3 -3
- package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
- package/src/memory/__tests__/conversation-queries.test.ts +263 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
- package/src/memory/__tests__/message-content.test.ts +35 -0
- package/src/memory/bookmark-crud.ts +42 -10
- package/src/memory/context-search/sources/conversations.ts +62 -2
- package/src/memory/context-search/sources/workspace.ts +4 -0
- package/src/memory/conversation-crud.ts +63 -19
- package/src/memory/conversation-queries.ts +110 -10
- package/src/memory/db-init.ts +6 -0
- package/src/memory/delivery-crud.ts +152 -5
- package/src/memory/embedding-backend.ts +4 -4
- package/src/memory/external-conversation-store.ts +66 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
- package/src/memory/graph/conversation-graph-memory.ts +31 -15
- package/src/memory/graph/tools.ts +3 -3
- package/src/memory/indexer.ts +34 -29
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
- package/src/memory/jobs/embed-concept-page.ts +20 -11
- package/src/memory/jobs-worker.ts +6 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +17 -10
- package/src/memory/llm-request-log-source.ts +19 -52
- package/src/memory/llm-usage-store.ts +125 -5
- package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
- package/src/memory/message-content.ts +1 -1
- package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
- package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
- package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
- package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
- package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/onboarding-events-store.ts +106 -0
- package/src/memory/schema/bookmarks.ts +0 -2
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/inference.ts +1 -3
- package/src/memory/schema/infrastructure.ts +12 -0
- package/src/memory/turn-events-store.ts +127 -2
- package/src/memory/v2/__tests__/activation.test.ts +0 -8
- package/src/memory/v2/__tests__/injection.test.ts +98 -8
- package/src/memory/v2/__tests__/migration.test.ts +87 -0
- package/src/memory/v2/__tests__/page-index.test.ts +83 -0
- package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
- package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
- package/src/memory/v2/__tests__/router.test.ts +15 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
- package/src/memory/v2/injection.ts +32 -6
- package/src/memory/v2/migration.ts +49 -19
- package/src/memory/v2/page-index.ts +35 -5
- package/src/memory/v2/prompts/router.ts +11 -8
- package/src/memory/v2/prompts/sweep.ts +2 -2
- package/src/memory/v2/qdrant.ts +135 -7
- package/src/memory/v2/router.ts +9 -8
- package/src/memory/v2/skill-store.ts +120 -35
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
- package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
- package/src/messaging/providers/slack/adapter.ts +43 -5
- package/src/messaging/providers/slack/client.ts +27 -0
- package/src/messaging/providers/slack/deep-link.ts +65 -0
- package/src/messaging/providers/slack/download.ts +104 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
- package/src/messaging/providers/slack/message-metadata.ts +27 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
- package/src/messaging/providers/slack/render-transcript.ts +69 -5
- package/src/messaging/providers/slack/types.ts +20 -1
- package/src/notifications/conversation-pairing.ts +2 -1
- package/src/notifications/decision-engine.ts +2 -1
- package/src/notifications/emit-signal.ts +20 -1
- package/src/notifications/home-feed-side-effect.ts +54 -0
- package/src/notifications/signal.ts +3 -1
- package/src/oauth/connection-resolver.ts +8 -4
- package/src/oauth/platform-connection.ts +6 -2
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/question-prompter.test.ts +416 -0
- package/src/permissions/question-prompter.ts +294 -0
- package/src/platform/client.test.ts +1 -1
- package/src/platform/client.ts +1 -1
- package/src/plugin-api/constants.ts +26 -0
- package/src/plugin-api/index.ts +34 -1
- package/src/plugin-api/types.ts +104 -22
- package/src/plugins/defaults/circuit-breaker.ts +0 -5
- package/src/plugins/defaults/compaction.ts +0 -4
- package/src/plugins/defaults/empty-response.ts +0 -2
- package/src/plugins/defaults/history-repair.ts +0 -2
- package/src/plugins/defaults/injectors.ts +36 -3
- package/src/plugins/defaults/llm-call.ts +0 -2
- package/src/plugins/defaults/memory-retrieval.ts +0 -1
- package/src/plugins/defaults/overflow-reduce.ts +0 -1
- package/src/plugins/defaults/persistence.ts +0 -2
- package/src/plugins/defaults/title-generate.ts +0 -5
- package/src/plugins/defaults/token-estimate.ts +0 -2
- package/src/plugins/defaults/tool-error.ts +0 -7
- package/src/plugins/defaults/tool-execute.ts +0 -2
- package/src/plugins/defaults/tool-result-truncate.ts +0 -4
- package/src/plugins/ensure-plugin-api-shim.ts +96 -0
- package/src/plugins/external-api.ts +104 -0
- package/src/plugins/external-plugin-loader.ts +105 -32
- package/src/plugins/feature-gate.ts +22 -0
- package/src/plugins/pipeline.ts +37 -0
- package/src/plugins/registry.ts +48 -80
- package/src/plugins/types.ts +31 -26
- package/src/plugins/user-loader.ts +21 -2
- package/src/proactive-artifact/aux-message-injector.ts +11 -0
- package/src/proactive-artifact/job.test.ts +37 -5
- package/src/prompts/__tests__/system-prompt.test.ts +12 -0
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
- package/src/prompts/normalize-onboarding.ts +27 -0
- package/src/prompts/sections.ts +302 -0
- package/src/prompts/system-prompt.ts +63 -166
- package/src/prompts/templates/BOOTSTRAP.md +17 -1
- package/src/prompts/templates/system-sections.ts +173 -0
- package/src/providers/__tests__/inference.test.ts +22 -7
- package/src/providers/anthropic/client.ts +28 -28
- package/src/providers/connection-resolution.ts +7 -0
- package/src/providers/inference/adapter-factory.ts +41 -4
- package/src/providers/inference/connections.ts +74 -29
- package/src/providers/inference/resolve-auth.ts +12 -4
- package/src/providers/model-catalog.ts +294 -12
- package/src/providers/openai/chat-completions-provider.ts +10 -2
- package/src/providers/openrouter/client.ts +7 -0
- package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
- package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
- package/src/providers/provider-availability.ts +17 -2
- package/src/providers/provider-catalog-visibility.ts +36 -0
- package/src/providers/registry.ts +22 -14
- package/src/providers/retry.ts +47 -1
- package/src/runtime/__tests__/agent-wake.test.ts +152 -0
- package/src/runtime/agent-wake.ts +42 -14
- package/src/runtime/auth/route-policy.ts +8 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/http-types.ts +19 -0
- package/src/runtime/migrations/origin-mode.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +107 -20
- package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
- package/src/runtime/routes/acp-routes-list.test.ts +143 -0
- package/src/runtime/routes/acp-routes.ts +5 -3
- package/src/runtime/routes/auth-routes.ts +1 -1
- package/src/runtime/routes/bookmark-routes.ts +5 -3
- package/src/runtime/routes/btw-routes.ts +5 -1
- package/src/runtime/routes/channel-availability-routes.ts +121 -0
- package/src/runtime/routes/conversation-cli-routes.ts +44 -3
- package/src/runtime/routes/conversation-list-routes.ts +3 -20
- package/src/runtime/routes/conversation-management-routes.ts +17 -42
- package/src/runtime/routes/conversation-query-routes.ts +40 -35
- package/src/runtime/routes/conversation-routes.ts +90 -11
- package/src/runtime/routes/documents-routes.ts +25 -86
- package/src/runtime/routes/group-routes.ts +5 -0
- package/src/runtime/routes/inbound-conversation.ts +28 -8
- package/src/runtime/routes/inbound-message-handler.ts +236 -41
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
- package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
- package/src/runtime/routes/inference-provider-connection-routes.ts +65 -21
- package/src/runtime/routes/integrations/slack/share.ts +4 -52
- package/src/runtime/routes/integrations/slack/token.ts +43 -0
- package/src/runtime/routes/integrations/twilio.ts +6 -13
- package/src/runtime/routes/notification-routes.ts +1 -1
- package/src/runtime/routes/oauth-commands-routes.ts +105 -15
- package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
- package/src/runtime/routes/question-routes.ts +259 -0
- package/src/runtime/routes/rename-conversation-routes.ts +2 -33
- package/src/runtime/routes/schedule-routes.ts +4 -7
- package/src/runtime/routes/subagents-routes.ts +57 -18
- package/src/runtime/routes/telemetry-routes.ts +27 -0
- package/src/runtime/routes/tts-routes.ts +27 -2
- package/src/runtime/routes/workspace-routes.test.ts +43 -0
- package/src/runtime/routes/workspace-routes.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +39 -7
- package/src/runtime/sync/resource-sync-events.ts +93 -1
- package/src/schedule/schedule-store.ts +27 -2
- package/src/schedule/scheduler.ts +9 -1
- package/src/security/__tests__/untrusted-content.test.ts +86 -0
- package/src/security/untrusted-content.ts +93 -8
- package/src/skills/catalog-files.ts +1 -1
- package/src/skills/catalog-install.ts +233 -116
- package/src/skills/clawhub.ts +70 -13
- package/src/skills/managed-store.ts +4 -119
- package/src/skills/skillssh-registry.ts +27 -48
- package/src/subagent/manager.ts +15 -7
- package/src/telemetry/types.ts +113 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
- package/src/telemetry/usage-telemetry-reporter.ts +113 -7
- package/src/tools/apps/executors.ts +58 -7
- package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
- package/src/tools/ask-question/ask-question-tool.ts +304 -0
- package/src/tools/browser/browser-execution.ts +15 -11
- package/src/tools/computer-use/definitions.ts +3 -3
- package/src/tools/credentials/vault.ts +1 -1
- package/src/tools/document/document-tool.ts +124 -1
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +5 -2
- package/src/tools/host-filesystem/transfer.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +1 -1
- package/src/tools/permission-checker.ts +1 -1
- package/src/tools/registry.ts +17 -7
- package/src/tools/schedule/create.ts +2 -2
- package/src/tools/schema-transforms.ts +7 -2
- package/src/tools/side-effects.ts +1 -0
- package/src/tools/skills/delete-managed.ts +4 -4
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/scaffold-managed.ts +3 -2
- package/src/tools/subagent/notify-parent.ts +1 -1
- package/src/tools/system/request-permission.ts +2 -2
- package/src/tools/terminal/safe-env.ts +60 -1
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/types.ts +72 -21
- package/src/tools/ui-surface/definitions.ts +6 -5
- package/src/tts/__tests__/provider-adapters.test.ts +76 -2
- package/src/tts/providers/elevenlabs-provider.ts +75 -1
- package/src/types/onboarding-context.ts +2 -0
- package/src/util/errors.ts +17 -0
- package/src/util/platform.ts +10 -0
- package/src/watcher/__tests__/engine.test.ts +22 -0
- package/src/watcher/engine.ts +6 -2
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
- package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
- package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
- package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/runner.ts +39 -9
- package/src/workspace/migrations/types.ts +4 -0
- package/examples/plugins/echo/bun.lock +0 -25
- package/src/__tests__/context-window-manager.test.ts +0 -2481
- package/src/context/__tests__/compact-prompt.test.ts +0 -63
- package/src/context/prompts/compact.md +0 -26
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
- /package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +0 -0
package/src/util/errors.ts
CHANGED
|
@@ -151,14 +151,31 @@ export class ConfigError extends AssistantError {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
export class ProviderNotConfiguredError extends ConfigError {
|
|
154
|
+
/**
|
|
155
|
+
* Optional name of the `provider_connections` row whose credential was
|
|
156
|
+
* missing. Surfaced through `ConversationErrorMessage.connectionName` so
|
|
157
|
+
* the macOS chat banner can render "API key required for connection
|
|
158
|
+
* <name>" instead of a generic message.
|
|
159
|
+
*/
|
|
160
|
+
public readonly connectionName?: string;
|
|
161
|
+
/**
|
|
162
|
+
* Optional name of the resolved profile in play when this error was
|
|
163
|
+
* thrown. Forwarded to the wire `ConversationErrorMessage.profileName`
|
|
164
|
+
* for the same banner-attribution purpose as `connectionName`.
|
|
165
|
+
*/
|
|
166
|
+
public readonly profileName?: string;
|
|
167
|
+
|
|
154
168
|
constructor(
|
|
155
169
|
public readonly requestedProvider: string,
|
|
156
170
|
public readonly registeredProviders: string[],
|
|
171
|
+
attribution?: { connectionName?: string; profileName?: string },
|
|
157
172
|
) {
|
|
158
173
|
super(
|
|
159
174
|
`No providers available. Requested: "${requestedProvider}". Registered: ${registeredProviders.join(", ") || "none"}`,
|
|
160
175
|
);
|
|
161
176
|
this.name = "ProviderNotConfiguredError";
|
|
177
|
+
this.connectionName = attribution?.connectionName;
|
|
178
|
+
this.profileName = attribution?.profileName;
|
|
162
179
|
}
|
|
163
180
|
}
|
|
164
181
|
|
package/src/util/platform.ts
CHANGED
|
@@ -268,6 +268,16 @@ export function getWorkspaceHooksDir(): string {
|
|
|
268
268
|
return join(getWorkspaceDir(), "hooks");
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Returns `<workspaceDir>/plugins` — the directory scanned by the user plugin
|
|
273
|
+
* loader at daemon startup. Writes here are security-sensitive: any
|
|
274
|
+
* `register.{ts,js}` will be dynamic-imported on next restart, so the file
|
|
275
|
+
* risk classifier escalates writes under this path to High.
|
|
276
|
+
*/
|
|
277
|
+
export function getWorkspacePluginsDir(): string {
|
|
278
|
+
return join(getWorkspaceDir(), "plugins");
|
|
279
|
+
}
|
|
280
|
+
|
|
271
281
|
/** Returns $VELLUM_WORKSPACE_DIR/routes — user-defined HTTP route handlers. */
|
|
272
282
|
export function getWorkspaceRoutesDir(): string {
|
|
273
283
|
return join(getWorkspaceDir(), "routes");
|
|
@@ -250,6 +250,28 @@ describe("runWatchersOnce — Phase 2 runBackgroundJob integration", () => {
|
|
|
250
250
|
expect(dispositionCalls[0].reason).toBe("model exploded");
|
|
251
251
|
});
|
|
252
252
|
|
|
253
|
+
test("on bootstrap failure (conversationId: ''): does not overwrite prior conversation id", async () => {
|
|
254
|
+
fakeWatchers = [makeWatcher()];
|
|
255
|
+
fakePending = [makeEvent()];
|
|
256
|
+
// bootstrap failure shape from runBackgroundJob — empty conversationId
|
|
257
|
+
// signals that conversation creation failed before assignment.
|
|
258
|
+
runJobImpl = async () => ({
|
|
259
|
+
conversationId: "",
|
|
260
|
+
ok: false,
|
|
261
|
+
error: new Error("bootstrap exploded"),
|
|
262
|
+
errorKind: "exception",
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
await runWatchersOnce(() => {});
|
|
266
|
+
|
|
267
|
+
// Critical: we must NOT have called setWatcherConversationId with "",
|
|
268
|
+
// which would clobber a valid prior conversation id in the DB.
|
|
269
|
+
expect(setConvCalls).toEqual([]);
|
|
270
|
+
// Failure path still updates event dispositions.
|
|
271
|
+
expect(dispositionCalls).toHaveLength(1);
|
|
272
|
+
expect(dispositionCalls[0].disposition).toBe("error");
|
|
273
|
+
});
|
|
274
|
+
|
|
253
275
|
test("skips runBackgroundJob entirely when no pending events", async () => {
|
|
254
276
|
fakeWatchers = [makeWatcher()];
|
|
255
277
|
fakePending = [];
|
package/src/watcher/engine.ts
CHANGED
|
@@ -263,8 +263,12 @@ export async function runWatchersOnce(
|
|
|
263
263
|
});
|
|
264
264
|
|
|
265
265
|
// Persist the per-tick conversation id so downstream surfaces (UI,
|
|
266
|
-
// store reads) can link back to the most recent watcher run.
|
|
267
|
-
|
|
266
|
+
// store reads) can link back to the most recent watcher run. Skip
|
|
267
|
+
// persistence when the runner failed before bootstrap (conversationId
|
|
268
|
+
// is empty) — otherwise we'd overwrite a valid prior id with "".
|
|
269
|
+
if (result.conversationId !== "") {
|
|
270
|
+
setWatcherConversationId(watcher.id, result.conversationId);
|
|
271
|
+
}
|
|
268
272
|
|
|
269
273
|
if (result.ok) {
|
|
270
274
|
// Mark events as silent by default. The LLM is expected to use
|
|
@@ -35,8 +35,15 @@ export const repairStaleGeminiModelIdsMigration: WorkspaceMigration = {
|
|
|
35
35
|
|
|
36
36
|
const defaultBlock = readObject(llm.default);
|
|
37
37
|
const defaultProvider = readProvider(defaultBlock);
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const profiles = readObject(llm.profiles);
|
|
39
|
+
const activeProfileName =
|
|
40
|
+
typeof llm.activeProfile === "string" ? llm.activeProfile : undefined;
|
|
41
|
+
const activeProfileProvider =
|
|
42
|
+
profiles !== null && activeProfileName !== undefined
|
|
43
|
+
? inferProvider(readObject(profiles[activeProfileName]))
|
|
44
|
+
: undefined;
|
|
45
|
+
|
|
46
|
+
if (defaultBlock !== null && isGeminiProvider(defaultProvider)) {
|
|
40
47
|
changed = repairModel(defaultBlock, DEFAULT_REPLACEMENT_MODEL) || changed;
|
|
41
48
|
}
|
|
42
49
|
|
|
@@ -45,7 +52,14 @@ export const repairStaleGeminiModelIdsMigration: WorkspaceMigration = {
|
|
|
45
52
|
for (const [site, rawConfig] of Object.entries(callSites)) {
|
|
46
53
|
const callSiteConfig = readObject(rawConfig);
|
|
47
54
|
if (callSiteConfig === null) continue;
|
|
48
|
-
|
|
55
|
+
const effective = resolveCallSiteEffectiveProvider({
|
|
56
|
+
callSite: site,
|
|
57
|
+
callSiteConfig,
|
|
58
|
+
profiles,
|
|
59
|
+
activeProfileProvider,
|
|
60
|
+
defaultProvider,
|
|
61
|
+
});
|
|
62
|
+
if (!isGeminiProvider(effective)) continue;
|
|
49
63
|
const replacement = LATENCY_CALL_SITES.has(site)
|
|
50
64
|
? LATENCY_REPLACEMENT_MODEL
|
|
51
65
|
: DEFAULT_REPLACEMENT_MODEL;
|
|
@@ -53,12 +67,12 @@ export const repairStaleGeminiModelIdsMigration: WorkspaceMigration = {
|
|
|
53
67
|
}
|
|
54
68
|
}
|
|
55
69
|
|
|
56
|
-
const profiles = readObject(llm.profiles);
|
|
57
70
|
if (profiles !== null) {
|
|
58
71
|
for (const rawProfile of Object.values(profiles)) {
|
|
59
72
|
const profile = readObject(rawProfile);
|
|
60
73
|
if (profile === null) continue;
|
|
61
|
-
|
|
74
|
+
const effective = inferProvider(profile) ?? defaultProvider;
|
|
75
|
+
if (!isGeminiProvider(effective)) continue;
|
|
62
76
|
changed = repairModel(profile, DEFAULT_REPLACEMENT_MODEL) || changed;
|
|
63
77
|
}
|
|
64
78
|
}
|
|
@@ -109,14 +123,65 @@ function readProvider(
|
|
|
109
123
|
return typeof block.provider === "string" ? block.provider : undefined;
|
|
110
124
|
}
|
|
111
125
|
|
|
112
|
-
//
|
|
113
|
-
// no provider
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
):
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
126
|
+
// Mirrors `resolveCallSiteConfig`'s catalog-based inference: a fragment with
|
|
127
|
+
// no explicit `provider` but a Gemini-catalog `model` resolves to "gemini" at
|
|
128
|
+
// that layer. The stale model is the only catalog entry the migration cares
|
|
129
|
+
// about, so the check stays self-contained.
|
|
130
|
+
function inferProvider(
|
|
131
|
+
block: Record<string, unknown> | null,
|
|
132
|
+
): string | undefined {
|
|
133
|
+
if (block === null) return undefined;
|
|
134
|
+
const explicit = readProvider(block);
|
|
135
|
+
if (explicit !== undefined) return explicit;
|
|
136
|
+
if (block.model === STALE_MODEL) return "gemini";
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function isGeminiProvider(provider: string | undefined): boolean {
|
|
141
|
+
return provider === undefined || provider === "gemini";
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Walks the call-site provider resolution chain the same way
|
|
145
|
+
// `resolveCallSiteConfig` does: for `mainAgent`, `activeProfile` overrides the
|
|
146
|
+
// static `callSites.mainAgent` block, while for every other call site the
|
|
147
|
+
// call-site block (and its referenced profile) wins over `activeProfile`.
|
|
148
|
+
// Returns the highest-precedence inferred provider, falling back to `default`.
|
|
149
|
+
function resolveCallSiteEffectiveProvider(args: {
|
|
150
|
+
callSite: string;
|
|
151
|
+
callSiteConfig: Record<string, unknown>;
|
|
152
|
+
profiles: Record<string, unknown> | null;
|
|
153
|
+
activeProfileProvider: string | undefined;
|
|
154
|
+
defaultProvider: string | undefined;
|
|
155
|
+
}): string | undefined {
|
|
156
|
+
const {
|
|
157
|
+
callSite,
|
|
158
|
+
callSiteConfig,
|
|
159
|
+
profiles,
|
|
160
|
+
activeProfileProvider,
|
|
161
|
+
defaultProvider,
|
|
162
|
+
} = args;
|
|
163
|
+
const siteProvider = inferProvider(callSiteConfig);
|
|
164
|
+
const siteProfileName =
|
|
165
|
+
typeof callSiteConfig.profile === "string"
|
|
166
|
+
? callSiteConfig.profile
|
|
167
|
+
: undefined;
|
|
168
|
+
const siteProfileProvider =
|
|
169
|
+
profiles !== null && siteProfileName !== undefined
|
|
170
|
+
? inferProvider(readObject(profiles[siteProfileName]))
|
|
171
|
+
: undefined;
|
|
172
|
+
|
|
173
|
+
if (callSite === "mainAgent") {
|
|
174
|
+
return (
|
|
175
|
+
activeProfileProvider ??
|
|
176
|
+
siteProvider ??
|
|
177
|
+
siteProfileProvider ??
|
|
178
|
+
defaultProvider
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return (
|
|
182
|
+
siteProvider ??
|
|
183
|
+
siteProfileProvider ??
|
|
184
|
+
activeProfileProvider ??
|
|
185
|
+
defaultProvider
|
|
186
|
+
);
|
|
122
187
|
}
|
|
@@ -14,12 +14,20 @@ import type { WorkspaceMigration } from "./types.js";
|
|
|
14
14
|
* high-effort / extended-thinking default, every turn would kick off an
|
|
15
15
|
* expensive reasoning call and reject the assistant prefill.
|
|
16
16
|
*
|
|
17
|
+
* Carry-forward: when `replySuggestion` is absent but the workspace has a
|
|
18
|
+
* customized `conversationStarters` entry (the call site this one was split
|
|
19
|
+
* out of), clone that entry into `replySuggestion` so users who previously
|
|
20
|
+
* tuned the combined call site keep their override. Only fall back to the
|
|
21
|
+
* fixed Haiku defaults when no `conversationStarters` override exists.
|
|
22
|
+
*
|
|
17
23
|
* Mirrors `046-seed-conversation-starters-callsite`:
|
|
18
24
|
* - Skip entirely when `VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH` is set
|
|
19
25
|
* (platform overlay owns call-site seeds).
|
|
20
|
-
* -
|
|
21
|
-
* seeded model IDs are Anthropic-shaped, so
|
|
22
|
-
* provider would guarantee invalid-model errors).
|
|
26
|
+
* - In the fallback default path, skip when the resolved provider is not
|
|
27
|
+
* Anthropic or OpenRouter (the seeded model IDs are Anthropic-shaped, so
|
|
28
|
+
* mixing with another provider would guarantee invalid-model errors).
|
|
29
|
+
* The carry-forward path is provider-agnostic since the cloned config
|
|
30
|
+
* already reflects the user's explicit choice.
|
|
23
31
|
* - No-op when `llm.callSites.replySuggestion` is already set.
|
|
24
32
|
*
|
|
25
33
|
* Idempotent, append-only — existing entries are untouched.
|
|
@@ -46,29 +54,34 @@ export const seedReplySuggestionCallsiteMigration: WorkspaceMigration = {
|
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
const llm = readObject(config.llm) ?? {};
|
|
49
|
-
const defaultBlock = readObject(llm.default);
|
|
50
|
-
|
|
51
|
-
const explicitProvider = readString(defaultBlock?.provider);
|
|
52
|
-
if (
|
|
53
|
-
explicitProvider !== undefined &&
|
|
54
|
-
explicitProvider !== "anthropic" &&
|
|
55
|
-
explicitProvider !== "openrouter"
|
|
56
|
-
) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
const provider = explicitProvider ?? "anthropic";
|
|
60
|
-
const fastModel = resolveLatencyModel(provider);
|
|
61
|
-
if (fastModel === undefined) return;
|
|
62
|
-
|
|
63
57
|
const callSites = readObject(llm.callSites) ?? {};
|
|
64
58
|
if (readObject(callSites.replySuggestion) !== null) return;
|
|
65
59
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
60
|
+
const conversationStarters = readObject(callSites.conversationStarters);
|
|
61
|
+
let seed: Record<string, unknown>;
|
|
62
|
+
if (conversationStarters !== null) {
|
|
63
|
+
seed = { ...conversationStarters };
|
|
64
|
+
} else {
|
|
65
|
+
const defaultBlock = readObject(llm.default);
|
|
66
|
+
const explicitProvider = readString(defaultBlock?.provider);
|
|
67
|
+
if (
|
|
68
|
+
explicitProvider !== undefined &&
|
|
69
|
+
explicitProvider !== "anthropic" &&
|
|
70
|
+
explicitProvider !== "openrouter"
|
|
71
|
+
) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const provider = explicitProvider ?? "anthropic";
|
|
75
|
+
const fastModel = resolveLatencyModel(provider);
|
|
76
|
+
if (fastModel === undefined) return;
|
|
77
|
+
seed = {
|
|
78
|
+
model: fastModel,
|
|
79
|
+
effort: "low",
|
|
80
|
+
thinking: { enabled: false },
|
|
81
|
+
};
|
|
82
|
+
}
|
|
71
83
|
|
|
84
|
+
callSites.replySuggestion = seed;
|
|
72
85
|
llm.callSites = callSites;
|
|
73
86
|
config.llm = llm;
|
|
74
87
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
@@ -57,7 +57,9 @@ export const repairRecallCallsiteEmptyProfileMigration: WorkspaceMigration = {
|
|
|
57
57
|
if (cheapModel === undefined) return;
|
|
58
58
|
|
|
59
59
|
delete recall.profile;
|
|
60
|
-
recall.model
|
|
60
|
+
if (readString(recall.model) === undefined) {
|
|
61
|
+
recall.model = cheapModel;
|
|
62
|
+
}
|
|
61
63
|
callSites.recall = recall;
|
|
62
64
|
llm.callSites = callSites;
|
|
63
65
|
config.llm = llm;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace migration 083: Move config.systemPromptPrefix to a workspace file.
|
|
3
|
+
*
|
|
4
|
+
* The custom system prompt prefix used to live as a top-level config field
|
|
5
|
+
* (`config.json` → `systemPromptPrefix`). Editable system-prompt sections
|
|
6
|
+
* now live under `<workspace>/prompts/system/<id>.md`. This migration
|
|
7
|
+
* carries any existing config value over to `00-prefix.md` and strips the
|
|
8
|
+
* key from `config.json`.
|
|
9
|
+
*
|
|
10
|
+
* Behavior:
|
|
11
|
+
* - config has non-empty string + 00-prefix.md body is empty → write the
|
|
12
|
+
* prefix into the file body, preserving the bundled frontmatter
|
|
13
|
+
* - config has non-empty string + 00-prefix.md body already has content →
|
|
14
|
+
* leave the file alone (user authorship wins). Just strip the config key
|
|
15
|
+
* - config has null / missing field / whitespace-only string → no-op for
|
|
16
|
+
* the file; strip the key
|
|
17
|
+
*
|
|
18
|
+
* On filesystem write failure we **throw**. The runner marks the migration
|
|
19
|
+
* as `"failed"` so the operator can see it in checkpoints; we explicitly do
|
|
20
|
+
* not silently mark it complete. Note the config key is only deleted on a
|
|
21
|
+
* successful path, so the user's prefix is preserved in `config.json` until
|
|
22
|
+
* the next attempt.
|
|
23
|
+
*
|
|
24
|
+
* Per workspace-migration AGENTS.md, all helpers are inlined.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import {
|
|
28
|
+
existsSync,
|
|
29
|
+
mkdirSync,
|
|
30
|
+
readFileSync,
|
|
31
|
+
renameSync,
|
|
32
|
+
writeFileSync,
|
|
33
|
+
} from "node:fs";
|
|
34
|
+
import { join } from "node:path";
|
|
35
|
+
|
|
36
|
+
import { getLogger } from "../../util/logger.js";
|
|
37
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
38
|
+
|
|
39
|
+
const log = getLogger("workspace-migration-083-system-prompt-prefix-to-file");
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Default frontmatter used when the bundled 00-prefix.md is somehow missing
|
|
43
|
+
* (e.g. running a development build where seeding hasn't happened yet). In
|
|
44
|
+
* the normal startup order, `ensurePromptFiles()` runs before this migration,
|
|
45
|
+
* so the file already exists with the canonical bundled frontmatter.
|
|
46
|
+
*/
|
|
47
|
+
const FALLBACK_PREFIX_FRONTMATTER = [
|
|
48
|
+
"---",
|
|
49
|
+
'enabled: "!excludeCustomPrefix"',
|
|
50
|
+
"---",
|
|
51
|
+
"",
|
|
52
|
+
].join("\n");
|
|
53
|
+
|
|
54
|
+
/** Matches a `---`-delimited frontmatter block at the start of a file. */
|
|
55
|
+
const FRONTMATTER_REGEX = /^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/;
|
|
56
|
+
|
|
57
|
+
export const systemPromptPrefixToFileMigration: WorkspaceMigration = {
|
|
58
|
+
id: "083-system-prompt-prefix-to-file",
|
|
59
|
+
description:
|
|
60
|
+
"Move config.systemPromptPrefix to <workspace>/prompts/system/00-prefix.md",
|
|
61
|
+
|
|
62
|
+
run(workspaceDir: string): void {
|
|
63
|
+
const configPath = join(workspaceDir, "config.json");
|
|
64
|
+
if (!existsSync(configPath)) return;
|
|
65
|
+
|
|
66
|
+
let raw: string;
|
|
67
|
+
try {
|
|
68
|
+
raw = readFileSync(configPath, "utf-8");
|
|
69
|
+
} catch (err) {
|
|
70
|
+
log.warn({ err, configPath }, "Failed to read config.json, skipping");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let config: Record<string, unknown>;
|
|
75
|
+
try {
|
|
76
|
+
const parsed: unknown = JSON.parse(raw);
|
|
77
|
+
if (
|
|
78
|
+
parsed === null ||
|
|
79
|
+
typeof parsed !== "object" ||
|
|
80
|
+
Array.isArray(parsed)
|
|
81
|
+
) {
|
|
82
|
+
log.warn({ configPath }, "config.json is not a JSON object, skipping");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
config = parsed as Record<string, unknown>;
|
|
86
|
+
} catch (err) {
|
|
87
|
+
log.warn({ err, configPath }, "Failed to parse config.json, skipping");
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!Object.prototype.hasOwnProperty.call(config, "systemPromptPrefix")) {
|
|
92
|
+
// Already migrated (or never set). Nothing to do.
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const value = config.systemPromptPrefix;
|
|
97
|
+
const trimmed = typeof value === "string" ? value.trim() : "";
|
|
98
|
+
|
|
99
|
+
const sysDir = join(workspaceDir, "prompts", "system");
|
|
100
|
+
const prefixFile = join(sysDir, "00-prefix.md");
|
|
101
|
+
|
|
102
|
+
if (trimmed.length > 0) {
|
|
103
|
+
// Read the existing file (if any) so we can preserve frontmatter and
|
|
104
|
+
// avoid clobbering user-authored content.
|
|
105
|
+
let existingFrontmatter = FALLBACK_PREFIX_FRONTMATTER;
|
|
106
|
+
let existingBody = "";
|
|
107
|
+
if (existsSync(prefixFile)) {
|
|
108
|
+
const existingRaw = readFileSync(prefixFile, "utf-8");
|
|
109
|
+
const fmMatch = existingRaw.match(FRONTMATTER_REGEX);
|
|
110
|
+
if (fmMatch) {
|
|
111
|
+
existingFrontmatter = fmMatch[0];
|
|
112
|
+
existingBody = existingRaw.slice(fmMatch[0].length).trim();
|
|
113
|
+
} else {
|
|
114
|
+
existingBody = existingRaw.trim();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (existingBody.length > 0) {
|
|
119
|
+
// User already authored content here. Leave the file alone, but
|
|
120
|
+
// continue on to strip the now-superseded config key.
|
|
121
|
+
log.info(
|
|
122
|
+
{ prefixFile },
|
|
123
|
+
"00-prefix.md already has user content; keeping it, dropping config key only",
|
|
124
|
+
);
|
|
125
|
+
} else {
|
|
126
|
+
mkdirSync(sysDir, { recursive: true });
|
|
127
|
+
writeFileSync(
|
|
128
|
+
prefixFile,
|
|
129
|
+
existingFrontmatter + trimmed + "\n",
|
|
130
|
+
"utf-8",
|
|
131
|
+
);
|
|
132
|
+
log.info({ prefixFile }, "Wrote system prompt prefix to file");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Strip the field from config.json regardless of whether we wrote a body
|
|
137
|
+
// — the field is removed from the schema either way.
|
|
138
|
+
delete config.systemPromptPrefix;
|
|
139
|
+
writeJsonAtomic(configPath, config);
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
down(workspaceDir: string): void {
|
|
143
|
+
const configPath = join(workspaceDir, "config.json");
|
|
144
|
+
const prefixFile = join(workspaceDir, "prompts", "system", "00-prefix.md");
|
|
145
|
+
|
|
146
|
+
if (!existsSync(configPath) || !existsSync(prefixFile)) return;
|
|
147
|
+
|
|
148
|
+
let config: Record<string, unknown>;
|
|
149
|
+
try {
|
|
150
|
+
const parsed: unknown = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
151
|
+
if (
|
|
152
|
+
parsed === null ||
|
|
153
|
+
typeof parsed !== "object" ||
|
|
154
|
+
Array.isArray(parsed)
|
|
155
|
+
)
|
|
156
|
+
return;
|
|
157
|
+
config = parsed as Record<string, unknown>;
|
|
158
|
+
} catch {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let body = "";
|
|
163
|
+
try {
|
|
164
|
+
const raw = readFileSync(prefixFile, "utf-8");
|
|
165
|
+
const stripped = raw.replace(FRONTMATTER_REGEX, "").trim();
|
|
166
|
+
// Strip `_` comment lines too — same convention as runtime renderer.
|
|
167
|
+
body = stripped
|
|
168
|
+
.split("\n")
|
|
169
|
+
.filter((line) => !line.trimStart().startsWith("_"))
|
|
170
|
+
.join("\n")
|
|
171
|
+
.trim();
|
|
172
|
+
} catch {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
config.systemPromptPrefix = body.length > 0 ? body : null;
|
|
177
|
+
writeJsonAtomic(configPath, config);
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Atomic JSON write: write to temp file alongside the target, then rename.
|
|
183
|
+
* Throws on failure so callers can propagate to the migration runner (which
|
|
184
|
+
* marks the migration `"failed"`). Inlined per workspace-migration
|
|
185
|
+
* self-containment rule.
|
|
186
|
+
*/
|
|
187
|
+
function writeJsonAtomic(path: string, data: unknown): void {
|
|
188
|
+
const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
|
|
189
|
+
writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
190
|
+
renameSync(tmp, path);
|
|
191
|
+
}
|