@vellumai/assistant 0.12.1-dev.202609141913.5e16607 → 0.12.1-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +0 -4
- package/ARCHITECTURE.md +12 -11
- package/docs/architecture/turn-actor.md +8 -15
- package/docs/guardian-request-flow.md +0 -16
- package/openapi.yaml +49 -291
- package/package.json +1 -1
- package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
- package/src/__tests__/app-compiler.test.ts +0 -6
- package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
- package/src/__tests__/app-dir-path-guard.test.ts +3 -1
- package/src/__tests__/app-source-watcher.test.ts +218 -0
- package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
- package/src/__tests__/computer-use-tools.test.ts +5 -17
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +29 -28
- package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
- package/src/__tests__/config-watcher.test.ts +8 -23
- package/src/__tests__/connection-model-compat.test.ts +2 -2
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +0 -26
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
- package/src/__tests__/conversation-queue.test.ts +207 -48
- package/src/__tests__/conversation-retry-discard.test.ts +1 -54
- package/src/__tests__/conversation-skill-tools.test.ts +0 -27
- package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
- package/src/__tests__/conversation-title-service.test.ts +10 -14
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
- package/src/__tests__/credential-record-retire.test.ts +1 -171
- package/src/__tests__/credential-routes.test.ts +3 -212
- package/src/__tests__/credential-security-invariants.test.ts +2 -4
- package/src/__tests__/cu-unified-flow.test.ts +2 -8
- package/src/__tests__/document-sync-tags.test.ts +0 -25
- package/src/__tests__/drain-kick-guard.test.ts +2 -0
- package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/host-bash-proxy.test.ts +45 -26
- package/src/__tests__/host-browser-proxy.test.ts +17 -6
- package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
- package/src/__tests__/host-file-proxy.test.ts +23 -11
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
- package/src/__tests__/llm-catalog-parity.test.ts +0 -25
- package/src/__tests__/mcp-auth-routes.test.ts +9 -6
- package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
- package/src/__tests__/mcp-health-check.test.ts +11 -8
- package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
- package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
- package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
- package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
- package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +548 -355
- package/src/__tests__/model-intents.test.ts +0 -3
- package/src/__tests__/notification-vellum-adapter.test.ts +2 -85
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +16 -8
- package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
- package/src/__tests__/script-proxy-certs.test.ts +0 -35
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/speaker-identification.test.ts +56 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
- package/src/__tests__/subagent-tools.test.ts +2 -3
- package/src/__tests__/telephony-tts-guard.test.ts +3 -38
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
- package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
- package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
- package/src/__tests__/workspace-git-service.test.ts +0 -26
- package/src/acp/__tests__/agent-process.test.ts +4 -258
- package/src/acp/__tests__/auth-required.test.ts +0 -96
- package/src/acp/__tests__/client-handler.test.ts +2 -90
- package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
- package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
- package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
- package/src/acp/__tests__/session-manager.test.ts +4 -895
- package/src/acp/agent-process.test.ts +1 -4
- package/src/acp/agent-process.ts +9 -94
- package/src/acp/auth-required.ts +1 -50
- package/src/acp/auto-install.test.ts +7 -9
- package/src/acp/client-handler.ts +3 -16
- package/src/acp/resolve-agent.test.ts +6 -220
- package/src/acp/resolve-agent.ts +23 -88
- package/src/acp/session-manager.test.ts +3 -196
- package/src/acp/session-manager.ts +18 -441
- package/src/acp/types.ts +5 -50
- package/src/api/events/app-files-changed.ts +3 -4
- package/src/api/events/notification-intent.ts +0 -2
- package/src/api/index.ts +0 -6
- package/src/apps/app-store.ts +1 -1
- package/src/bundler/app-compiler.ts +0 -15
- package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
- package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
- package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
- package/src/calls/call-constants.ts +4 -24
- package/src/calls/call-controller.ts +199 -499
- package/src/calls/call-transport.ts +0 -16
- package/src/calls/media-stream-output.ts +0 -32
- package/src/calls/media-stream-server.ts +30 -82
- package/src/calls/media-stream-stt-session.ts +0 -15
- package/src/calls/resolve-call-tts-provider.ts +2 -33
- package/src/calls/speaker-identification.ts +233 -0
- package/src/calls/tts-call-strategy.ts +5 -9
- package/src/calls/types.ts +0 -2
- package/src/calls/voice-control-protocol.ts +21 -53
- package/src/calls/voice-session-bridge.ts +46 -59
- package/src/calls/voice-triage-escalate.ts +56 -175
- package/src/cli/commands/apps.help.ts +13 -67
- package/src/cli/commands/apps.ts +0 -183
- package/src/cli/commands/bash.help.ts +13 -8
- package/src/cli/commands/bash.ts +25 -7
- package/src/cli/commands/channels/index.help.ts +2 -70
- package/src/cli/commands/channels/index.ts +3 -16
- package/src/cli/commands/credentials.help.ts +2 -6
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/roadmap.help.ts +1 -5
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +90 -103
- package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
- package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
- package/src/config/__tests__/platform-rehydration.test.ts +9 -99
- package/src/config/acp-defaults.test.ts +3 -13
- package/src/config/acp-defaults.ts +6 -23
- package/src/config/acp-schema.ts +2 -30
- package/src/config/bundled-skills/acp/SKILL.md +14 -22
- package/src/config/bundled-skills/acp/TOOLS.json +1 -5
- package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +139 -67
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +4 -3
- package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +12 -24
- package/src/config/loader.ts +0 -1
- package/src/config/memory-v3-gate.test.ts +0 -31
- package/src/config/memory-v3-gate.ts +16 -20
- package/src/config/platform-rehydration.ts +27 -11
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
- package/src/config/schemas/calls.ts +28 -1
- package/src/config/schemas/live-voice.ts +173 -1
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +0 -10
- package/src/config/schemas/services.ts +0 -8
- package/src/config/schemas/skills.ts +14 -0
- package/src/credential-execution/process-manager.test.ts +19 -18
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
- package/src/daemon/app-source-watcher.ts +218 -0
- package/src/daemon/config-watcher.ts +194 -13
- package/src/daemon/conversation-process.ts +64 -35
- package/src/daemon/conversation-skill-tools.ts +31 -13
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +8 -10
- package/src/daemon/conversation-tool-setup.ts +43 -37
- package/src/daemon/conversation.ts +3 -0
- package/src/daemon/host-bash-proxy.ts +12 -8
- package/src/daemon/host-browser-proxy.ts +1 -15
- package/src/daemon/host-file-proxy.ts +10 -8
- package/src/daemon/host-transfer-proxy.ts +18 -14
- package/src/daemon/lifecycle.ts +5 -0
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/shutdown-handlers.ts +9 -1
- package/src/daemon/skill-memory-refresh.ts +0 -64
- package/src/daemon/tool-side-effects.ts +18 -7
- package/src/home/__tests__/feed-writer.test.ts +0 -22
- package/src/home/feed-writer.ts +2 -11
- package/src/hooks/types.ts +0 -33
- package/src/inbound/platform-callback-registration.ts +5 -4
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
- package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
- package/src/live-voice/live-voice-session.ts +693 -213
- package/src/{calls → live-voice}/progress-narration.ts +2 -2
- package/src/live-voice/protocol.ts +2 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +45 -29
- package/src/mcp/startup.ts +4 -8
- package/src/messaging/provider.ts +3 -10
- package/src/messaging/providers/callback-routing.ts +0 -18
- package/src/messaging/providers/channel-transport.ts +0 -56
- package/src/messaging/providers/discord/transport.ts +0 -17
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
- package/src/messaging/providers/slack/adapter.ts +44 -7
- package/src/messaging/providers/slack/transport.ts +0 -16
- package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
- package/src/messaging/providers/telegram-bot/client.ts +26 -0
- package/src/messaging/providers/telegram-bot/transport.ts +0 -20
- package/src/messaging/providers/whatsapp/adapter.ts +48 -1
- package/src/messaging/providers/whatsapp/client.ts +29 -0
- package/src/messaging/providers/whatsapp/transport.ts +0 -18
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +2 -158
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
- package/src/notifications/__tests__/schedule-result-producer.test.ts +3 -99
- package/src/notifications/adapters/macos.ts +0 -3
- package/src/notifications/assistant-reply-producer.ts +3 -8
- package/src/notifications/conversation-pairing.ts +16 -36
- package/src/notifications/delivered-post-record.ts +1 -11
- package/src/notifications/guardian-feed-projection.ts +5 -125
- package/src/notifications/home-feed-side-effect.ts +7 -55
- package/src/notifications/schedule-result-producer.ts +22 -66
- package/src/oauth/__tests__/seed-providers-managed.test.ts +0 -54
- package/src/oauth/byo-connection.test.ts +0 -45
- package/src/oauth/byo-connection.ts +6 -36
- package/src/oauth/connection-resolver.test.ts +0 -73
- package/src/oauth/connection-resolver.ts +2 -95
- package/src/oauth/seed-providers.ts +0 -165
- package/src/outbound-proxy/certs.ts +5 -3
- package/src/permissions/checker.test.ts +6 -11
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +63 -71
- package/src/persistence/conversation-lineage.ts +4 -12
- package/src/persistence/conversation-title-service.ts +26 -9
- package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
- package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
- package/src/persistence/message-reads.ts +0 -30
- package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
- package/src/persistence/schema/memory-core.ts +0 -5
- package/src/platform/client.test.ts +2 -4
- package/src/platform/client.ts +10 -2
- package/src/plugin-api/constants.ts +0 -2
- package/src/plugin-api/index.ts +0 -1
- package/src/plugin-api/types.ts +0 -2
- package/src/plugins/defaults/index.ts +0 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
- package/src/plugins/defaults/memory/hooks/init.ts +0 -10
- package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
- package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
- package/src/plugins/defaults/memory/startup.ts +1 -6
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
- package/src/plugins/defaults/memory/worker.ts +0 -6
- package/src/plugins/mcp-servers.ts +75 -15
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/gemini/client.ts +23 -9
- package/src/providers/inference/auth.ts +3 -2
- package/src/providers/inference/connection-availability.ts +8 -27
- package/src/providers/inference/resolve-auth.ts +4 -22
- package/src/providers/model-catalog.ts +0 -34
- package/src/providers/model-intents.ts +5 -10
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
- package/src/providers/openai/chat-completions-provider.ts +78 -192
- package/src/providers/openai/codex-models.ts +4 -0
- package/src/runtime/AGENTS.md +0 -2
- package/src/runtime/auth/same-actor.ts +3 -38
- package/src/runtime/http-server.ts +151 -160
- package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
- package/src/runtime/routes/acp-routes.test.ts +0 -15
- package/src/runtime/routes/acp-routes.ts +9 -72
- package/src/runtime/routes/app-management-routes.ts +0 -73
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +3 -14
- package/src/runtime/routes/conversation-query-routes.ts +0 -40
- package/src/runtime/routes/credential-routes.ts +10 -19
- package/src/runtime/routes/debug-bash-routes.ts +173 -0
- package/src/runtime/routes/diagnostics-routes.ts +3 -55
- package/src/runtime/routes/index.ts +2 -4
- package/src/runtime/routes/log-export-routes.ts +0 -2
- package/src/runtime/routes/mcp-auth-routes.ts +47 -39
- package/src/runtime/routes/migration-routes.ts +20 -6
- package/src/runtime/routes/platform-routes.ts +15 -18
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
- package/src/runtime/services/conversation-serializer.ts +3 -16
- package/src/runtime/sync/resource-sync-events.ts +1 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/ces-rpc-record-backend.ts +0 -7
- package/src/subagent/consult-context.ts +25 -12
- package/src/tools/acp/list-agents.test.ts +1 -3
- package/src/tools/acp/spawn.test.ts +11 -146
- package/src/tools/acp/spawn.ts +3 -21
- package/src/tools/acp/status.ts +3 -40
- package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
- package/src/tools/capability-offer.test.ts +2 -22
- package/src/tools/capability-offer.ts +1 -16
- package/src/tools/computer-use/definitions.ts +2 -4
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +0 -100
- package/src/tools/host-filesystem/edit.test.ts +1 -2
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +1 -2
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +1 -2
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +1 -2
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +0 -16
- package/src/tools/host-terminal/host-shell.ts +20 -4
- package/src/tools/policy-context.ts +7 -6
- package/src/tools/subagent/spawn.ts +8 -5
- package/src/tools/watch/watch-retro-report.ts +8 -0
- package/src/util/__tests__/language-subtag.test.ts +1 -23
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/language-subtag.ts +0 -16
- package/src/util/platform.ts +0 -8
- package/src/workspace/git-service.ts +54 -5
- package/src/workspace/migrations/registry.ts +0 -6
- package/scripts/smoke-desktop-window-theme.ts +0 -186
- package/src/__tests__/git-porcelain.test.ts +0 -47
- package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
- package/src/__tests__/resolve-app.test.ts +0 -135
- package/src/__tests__/service-account-token.test.ts +0 -247
- package/src/__tests__/source-fingerprint.test.ts +0 -184
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
- package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
- package/src/acp/model-config.test.ts +0 -166
- package/src/acp/model-config.ts +0 -138
- package/src/api/events/acp-session-model-update.test.ts +0 -88
- package/src/api/events/acp-session-model-update.ts +0 -46
- package/src/apps/resolve-app.ts +0 -81
- package/src/apps/source-fingerprint.ts +0 -266
- package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
- package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
- package/src/calls/barge-in-guard.ts +0 -118
- package/src/calls/voice-leg-coordinator.ts +0 -189
- package/src/calls/voice-progress-cadence.ts +0 -423
- package/src/cli/commands/__tests__/apps.test.ts +0 -245
- package/src/cli/commands/__tests__/bash.test.ts +0 -53
- package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
- package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
- package/src/cli/commands/channels/send.ts +0 -128
- package/src/config/__tests__/platform-identity.test.ts +0 -255
- package/src/config/acp-agent-write.ts +0 -43
- package/src/config/acp-schema.test.ts +0 -81
- package/src/config/platform-identity.ts +0 -201
- package/src/config/schemas/__tests__/voice.test.ts +0 -148
- package/src/config/schemas/voice.ts +0 -150
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
- package/src/daemon/app-change-notify.ts +0 -45
- package/src/desktop/__tests__/fake-desktop.ts +0 -119
- package/src/desktop/desktop-chrome-policy.test.ts +0 -71
- package/src/desktop/desktop-chrome-policy.ts +0 -42
- package/src/desktop/desktop-dependencies.test.ts +0 -102
- package/src/desktop/desktop-dependencies.ts +0 -306
- package/src/desktop/desktop-feature.test.ts +0 -18
- package/src/desktop/desktop-feature.ts +0 -19
- package/src/desktop/desktop-panel-config.test.ts +0 -135
- package/src/desktop/desktop-panel-config.ts +0 -149
- package/src/desktop/desktop-session-manager.test.ts +0 -627
- package/src/desktop/desktop-session-manager.ts +0 -814
- package/src/desktop/desktop-stream-bridge.test.ts +0 -395
- package/src/desktop/desktop-stream-bridge.ts +0 -214
- package/src/desktop/desktop-wallpaper.test.ts +0 -191
- package/src/desktop/desktop-wallpaper.ts +0 -113
- package/src/desktop/desktop-window-theme.ts +0 -170
- package/src/i18n/AGENTS.md +0 -22
- package/src/i18n/__tests__/i18n.test.ts +0 -108
- package/src/i18n/index.ts +0 -16
- package/src/i18n/locales.ts +0 -93
- package/src/i18n/messages.ts +0 -61
- package/src/i18n/title.ts +0 -25
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
- package/src/mcp/spec-schema.ts +0 -111
- package/src/mcp/workspace-mcp-config.ts +0 -188
- package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
- package/src/persistence/conversation-title-placeholders.ts +0 -23
- package/src/persistence/message-cursor.ts +0 -78
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
- package/src/providers/gemini-thought-signature.test.ts +0 -63
- package/src/providers/gemini-thought-signature.ts +0 -44
- package/src/providers/inference/service-account-token.ts +0 -248
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
- package/src/providers/openai/google-thought-signature.ts +0 -320
- package/src/runtime/__tests__/channel-send.test.ts +0 -443
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
- package/src/runtime/channel-send.ts +0 -316
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
- package/src/runtime/routes/channel-send-routes.ts +0 -85
- package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
- package/src/runtime/routes/desktop-setup-routes.ts +0 -35
- package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
- package/src/security/ces-http-record-backend.ts +0 -120
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
- package/src/skills/workspace-skill-md-signature.ts +0 -50
- package/src/tools/acp/status.test.ts +0 -94
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -57
- package/src/tools/terminal/sanitized-bash.ts +0 -105
- package/src/util/ca-bundle.ts +0 -13
- package/src/workspace/git-porcelain.ts +0 -66
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
- /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
|
@@ -104,7 +104,6 @@ mock.module("../runtime/sync/resource-sync-events.js", () => ({
|
|
|
104
104
|
publishConversationTitleChanged: mockPublishConversationTitleChanged,
|
|
105
105
|
}));
|
|
106
106
|
|
|
107
|
-
import { MESSAGE_KEYS } from "../i18n/index.js";
|
|
108
107
|
import {
|
|
109
108
|
AUTO_TITLE_DETERMINISTIC,
|
|
110
109
|
AUTO_TITLE_LLM,
|
|
@@ -310,10 +309,10 @@ describe("conversation-title-service", () => {
|
|
|
310
309
|
userMessage: "so about that t-shirt...",
|
|
311
310
|
});
|
|
312
311
|
|
|
313
|
-
expect(result.title).toBe(
|
|
312
|
+
expect(result.title).toBe("Untitled Conversation");
|
|
314
313
|
expect(mockUpdateConversationTitle).toHaveBeenCalledWith(
|
|
315
314
|
"conv-1",
|
|
316
|
-
|
|
315
|
+
"Untitled Conversation",
|
|
317
316
|
AUTO_TITLE_DETERMINISTIC,
|
|
318
317
|
);
|
|
319
318
|
});
|
|
@@ -334,7 +333,7 @@ describe("conversation-title-service", () => {
|
|
|
334
333
|
userMessage: "something",
|
|
335
334
|
});
|
|
336
335
|
|
|
337
|
-
expect(result.title).toBe(
|
|
336
|
+
expect(result.title).toBe("Untitled Conversation");
|
|
338
337
|
});
|
|
339
338
|
|
|
340
339
|
// The core bug this PR fixes: weak title models emit their reasoning or
|
|
@@ -362,10 +361,10 @@ describe("conversation-title-service", () => {
|
|
|
362
361
|
userMessage: "hey baby",
|
|
363
362
|
});
|
|
364
363
|
|
|
365
|
-
expect(result.title).toBe(
|
|
364
|
+
expect(result.title).toBe("Untitled Conversation");
|
|
366
365
|
expect(mockUpdateConversationTitle).toHaveBeenCalledWith(
|
|
367
366
|
"conv-1",
|
|
368
|
-
|
|
367
|
+
"Untitled Conversation",
|
|
369
368
|
AUTO_TITLE_DETERMINISTIC,
|
|
370
369
|
);
|
|
371
370
|
});
|
|
@@ -424,7 +423,7 @@ describe("conversation-title-service", () => {
|
|
|
424
423
|
userMessage: "x",
|
|
425
424
|
});
|
|
426
425
|
|
|
427
|
-
expect(result.title).toBe(
|
|
426
|
+
expect(result.title).toBe("Untitled Conversation");
|
|
428
427
|
});
|
|
429
428
|
|
|
430
429
|
test("regeneration skips LLM call when recent messages have no extractable text", async () => {
|
|
@@ -516,17 +515,17 @@ describe("conversation-title-service", () => {
|
|
|
516
515
|
});
|
|
517
516
|
|
|
518
517
|
expect(provider.sendMessage).not.toHaveBeenCalled();
|
|
519
|
-
expect(result).toEqual({ title:
|
|
518
|
+
expect(result).toEqual({ title: "Untitled Conversation", updated: true });
|
|
520
519
|
expect(mockUpdateConversationTitle).toHaveBeenCalledWith(
|
|
521
520
|
"conv-1",
|
|
522
|
-
|
|
521
|
+
"Untitled Conversation",
|
|
523
522
|
AUTO_TITLE_DETERMINISTIC,
|
|
524
523
|
);
|
|
525
524
|
});
|
|
526
525
|
|
|
527
526
|
test("keeps a background job's deterministic title when the model declines", async () => {
|
|
528
527
|
// The model answered with prose the normalizer rejects, so there is no
|
|
529
|
-
// generated title. Settling for
|
|
528
|
+
// generated title. Settling for "Untitled Conversation" would name the
|
|
530
529
|
// job's work less well than the bootstrap title already does.
|
|
531
530
|
mockGetConversation.mockImplementation(() => ({
|
|
532
531
|
title: "Memory consolidation",
|
|
@@ -585,9 +584,6 @@ describe("conversation-title-service", () => {
|
|
|
585
584
|
expect(content).not.toContain("Generate a very short title");
|
|
586
585
|
expect(content).not.toContain("do NOT respond");
|
|
587
586
|
expect(options.systemPrompt).toContain("Do NOT respond");
|
|
588
|
-
expect(options.systemPrompt).toContain(
|
|
589
|
-
"same language as the conversation content",
|
|
590
|
-
);
|
|
591
587
|
});
|
|
592
588
|
|
|
593
589
|
test("queueGenerateConversationTitle serializes concurrent calls", async () => {
|
|
@@ -665,7 +661,7 @@ describe("conversation-title-service", () => {
|
|
|
665
661
|
).find((c) => c[0] === "conv-1");
|
|
666
662
|
expect(firstUpdate).toEqual([
|
|
667
663
|
"conv-1",
|
|
668
|
-
|
|
664
|
+
"Untitled Conversation",
|
|
669
665
|
AUTO_TITLE_DETERMINISTIC,
|
|
670
666
|
]);
|
|
671
667
|
const secondUpdate = (
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* app_id from the executor's typed `resolvedAppId` side channel — and that
|
|
8
8
|
* non-hooked tools (app_file_edit, app_file_write) do not trigger side effects.
|
|
9
9
|
*
|
|
10
|
-
* File-change detection for file_write/file_edit is
|
|
11
|
-
*
|
|
10
|
+
* File-change detection for file_write/file_edit is handled by
|
|
11
|
+
* AppSourceWatcher (see app-source-watcher.test.ts).
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
@@ -50,7 +50,9 @@ mock.module("../tools/browser/browser-screencast.js", () => ({
|
|
|
50
50
|
registerConversationSender: mock(() => {}),
|
|
51
51
|
}));
|
|
52
52
|
|
|
53
|
-
// Stub app-store functions used by other modules (e.g.
|
|
53
|
+
// Stub app-store functions used by other modules (e.g. app-source-watcher,
|
|
54
|
+
// conversation-surfaces) so tool-side-effects' hooks can run without touching
|
|
55
|
+
// the real app store during tests.
|
|
54
56
|
mock.module("../apps/app-store.js", () => ({
|
|
55
57
|
getApp: mock(() => null),
|
|
56
58
|
getAppDirPath: mock(() => "/tmp/test-apps/dummy"),
|
|
@@ -354,57 +354,6 @@ describe("createToolExecutor isInteractive threading", () => {
|
|
|
354
354
|
});
|
|
355
355
|
});
|
|
356
356
|
|
|
357
|
-
describe("createToolExecutor unattended host-tool gate", () => {
|
|
358
|
-
test("rejects a direct host tool in a background turn before dispatch", async () => {
|
|
359
|
-
const { executor, calls } = makeCapturingExecutor();
|
|
360
|
-
const toolFn = makeToolFn(
|
|
361
|
-
executor,
|
|
362
|
-
makeCtx({ currentTurnIsNonInteractive: true, transportInterface: "web" }),
|
|
363
|
-
);
|
|
364
|
-
|
|
365
|
-
const result = await toolFn("host_bash", { command: "pwd" });
|
|
366
|
-
|
|
367
|
-
expect(result).toMatchObject({ isError: true });
|
|
368
|
-
expect(result.content).toContain("requires an interactive user turn");
|
|
369
|
-
expect(calls).toHaveLength(0);
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
test("rejects a skill-dispatched host tool in a background turn before dispatch", async () => {
|
|
373
|
-
const { executor, calls } = makeCapturingExecutor();
|
|
374
|
-
const toolFn = makeToolFn(
|
|
375
|
-
executor,
|
|
376
|
-
makeCtx({ currentTurnIsNonInteractive: true, transportInterface: "web" }),
|
|
377
|
-
);
|
|
378
|
-
|
|
379
|
-
const result = await toolFn("skill_execute", {
|
|
380
|
-
tool: "host_file_read",
|
|
381
|
-
input: { path: "/tmp/a" },
|
|
382
|
-
activity: "testing",
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
expect(result).toMatchObject({ isError: true });
|
|
386
|
-
expect(result.content).toContain("requires an interactive user turn");
|
|
387
|
-
expect(calls).toHaveLength(0);
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
test("dispatches a host tool during an interactive turn", async () => {
|
|
391
|
-
const { executor, calls } = makeCapturingExecutor();
|
|
392
|
-
const toolFn = makeToolFn(
|
|
393
|
-
executor,
|
|
394
|
-
makeCtx({
|
|
395
|
-
currentTurnIsNonInteractive: false,
|
|
396
|
-
transportInterface: "web",
|
|
397
|
-
}),
|
|
398
|
-
);
|
|
399
|
-
|
|
400
|
-
const result = await toolFn("host_bash", { command: "pwd" });
|
|
401
|
-
|
|
402
|
-
expect(result).toMatchObject({ content: "ok", isError: false });
|
|
403
|
-
expect(calls).toHaveLength(1);
|
|
404
|
-
expect(calls[0].name).toBe("host_bash");
|
|
405
|
-
});
|
|
406
|
-
});
|
|
407
|
-
|
|
408
357
|
describe("createToolExecutor channel-permission coordinate threading", () => {
|
|
409
358
|
beforeEach(() => {
|
|
410
359
|
mockBindingExternalChatId = null;
|
|
@@ -8,10 +8,8 @@ import type { CredentialRecord } from "@vellumai/service-contracts/credential-rp
|
|
|
8
8
|
import type { CredentialRecordBackend } from "../security/ces-rpc-record-backend.js";
|
|
9
9
|
import {
|
|
10
10
|
_ensureCesRecordsLoaded,
|
|
11
|
-
_setHttpRecordBackendForTests,
|
|
12
11
|
_setMetadataPath,
|
|
13
12
|
getCredentialMetadata,
|
|
14
|
-
listCredentialRecordsLive,
|
|
15
13
|
setCredentialRecordBackend,
|
|
16
14
|
upsertCredentialMetadata,
|
|
17
15
|
} from "../tools/credentials/metadata-store.js";
|
|
@@ -37,9 +35,7 @@ function leftoverContents(): string {
|
|
|
37
35
|
return readFileSync(leftoverPath(), "utf-8");
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
function makeBackend(
|
|
41
|
-
name?: string,
|
|
42
|
-
): CredentialRecordBackend & {
|
|
38
|
+
function makeBackend(): CredentialRecordBackend & {
|
|
43
39
|
store: Map<string, CredentialRecord>;
|
|
44
40
|
bulkSetCalls: number;
|
|
45
41
|
listCalls: number;
|
|
@@ -50,7 +46,6 @@ function makeBackend(
|
|
|
50
46
|
bulkSetCalls: number;
|
|
51
47
|
listCalls: number;
|
|
52
48
|
} = {
|
|
53
|
-
name,
|
|
54
49
|
store,
|
|
55
50
|
bulkSetCalls: 0,
|
|
56
51
|
listCalls: 0,
|
|
@@ -88,7 +83,6 @@ function makeBackend(
|
|
|
88
83
|
describe("CES credential record cache", () => {
|
|
89
84
|
beforeEach(() => {
|
|
90
85
|
setCredentialRecordBackend(undefined);
|
|
91
|
-
_setHttpRecordBackendForTests(null);
|
|
92
86
|
_setMetadataPath(null);
|
|
93
87
|
const leftover = leftoverPath();
|
|
94
88
|
if (existsSync(leftover)) {
|
|
@@ -98,7 +92,6 @@ describe("CES credential record cache", () => {
|
|
|
98
92
|
|
|
99
93
|
afterEach(() => {
|
|
100
94
|
setCredentialRecordBackend(undefined);
|
|
101
|
-
_setHttpRecordBackendForTests(null);
|
|
102
95
|
_setMetadataPath(null);
|
|
103
96
|
const leftover = leftoverPath();
|
|
104
97
|
if (existsSync(leftover)) {
|
|
@@ -225,169 +218,6 @@ describe("CES credential record cache", () => {
|
|
|
225
218
|
await _ensureCesRecordsLoaded();
|
|
226
219
|
});
|
|
227
220
|
|
|
228
|
-
test("live catalog list returns CES records without the in-process cache", async () => {
|
|
229
|
-
const backend = makeBackend();
|
|
230
|
-
const record: CredentialRecord = {
|
|
231
|
-
credentialId: "cred-live",
|
|
232
|
-
service: "github",
|
|
233
|
-
field: "token",
|
|
234
|
-
allowedTools: ["bash"],
|
|
235
|
-
allowedDomains: [],
|
|
236
|
-
createdAt: 1,
|
|
237
|
-
updatedAt: 2,
|
|
238
|
-
};
|
|
239
|
-
backend.store.set(credentialKey("github", "token"), record);
|
|
240
|
-
setCredentialRecordBackend(backend);
|
|
241
|
-
|
|
242
|
-
const live = await listCredentialRecordsLive();
|
|
243
|
-
expect(live.unreachable).toBe(false);
|
|
244
|
-
expect(live.records).toHaveLength(1);
|
|
245
|
-
expect(live.records[0]?.credentialId).toBe("cred-live");
|
|
246
|
-
expect(getCredentialMetadata("github", "token")).toBeUndefined();
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
test("live catalog list reports unreachable when CES list fails", async () => {
|
|
250
|
-
const backend = makeBackend();
|
|
251
|
-
backend.list = async () => null;
|
|
252
|
-
setCredentialRecordBackend(backend);
|
|
253
|
-
|
|
254
|
-
const live = await listCredentialRecordsLive();
|
|
255
|
-
expect(live.unreachable).toBe(true);
|
|
256
|
-
expect(live.records).toEqual([]);
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
test("live catalog list reports unreachable when no record backend is attached", async () => {
|
|
260
|
-
const live = await listCredentialRecordsLive();
|
|
261
|
-
expect(live.unreachable).toBe(true);
|
|
262
|
-
expect(live.records).toEqual([]);
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
test("live catalog list fails over to CES HTTP when CES RPC list fails", async () => {
|
|
266
|
-
const rpc = makeBackend("ces-rpc");
|
|
267
|
-
rpc.list = async () => null;
|
|
268
|
-
setCredentialRecordBackend(rpc);
|
|
269
|
-
|
|
270
|
-
const http = makeBackend("ces-http");
|
|
271
|
-
const record: CredentialRecord = {
|
|
272
|
-
credentialId: "cred-http",
|
|
273
|
-
service: "github",
|
|
274
|
-
field: "token",
|
|
275
|
-
allowedTools: ["bash"],
|
|
276
|
-
allowedDomains: [],
|
|
277
|
-
createdAt: 1,
|
|
278
|
-
updatedAt: 2,
|
|
279
|
-
};
|
|
280
|
-
http.store.set(credentialKey("github", "token"), record);
|
|
281
|
-
_setHttpRecordBackendForTests(http);
|
|
282
|
-
|
|
283
|
-
const live = await listCredentialRecordsLive();
|
|
284
|
-
expect(live.unreachable).toBe(false);
|
|
285
|
-
expect(live.records).toHaveLength(1);
|
|
286
|
-
expect(live.records[0]?.credentialId).toBe("cred-http");
|
|
287
|
-
expect(http.listCalls).toBe(1);
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
test("live catalog list fails over to CES HTTP when CES RPC is unavailable", async () => {
|
|
291
|
-
const rpc = makeBackend("ces-rpc");
|
|
292
|
-
rpc.isAvailable = () => false;
|
|
293
|
-
setCredentialRecordBackend(rpc);
|
|
294
|
-
|
|
295
|
-
const http = makeBackend("ces-http");
|
|
296
|
-
const record: CredentialRecord = {
|
|
297
|
-
credentialId: "cred-http-down-rpc",
|
|
298
|
-
service: "github",
|
|
299
|
-
field: "token",
|
|
300
|
-
allowedTools: ["bash"],
|
|
301
|
-
allowedDomains: [],
|
|
302
|
-
createdAt: 1,
|
|
303
|
-
updatedAt: 2,
|
|
304
|
-
};
|
|
305
|
-
http.store.set(credentialKey("github", "token"), record);
|
|
306
|
-
_setHttpRecordBackendForTests(http);
|
|
307
|
-
|
|
308
|
-
const live = await listCredentialRecordsLive();
|
|
309
|
-
expect(live.unreachable).toBe(false);
|
|
310
|
-
expect(live.records[0]?.credentialId).toBe("cred-http-down-rpc");
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
test("live catalog list uses CES HTTP when no record backend is attached", async () => {
|
|
314
|
-
const http = makeBackend("ces-http");
|
|
315
|
-
const record: CredentialRecord = {
|
|
316
|
-
credentialId: "cred-http-only",
|
|
317
|
-
service: "github",
|
|
318
|
-
field: "token",
|
|
319
|
-
allowedTools: ["bash"],
|
|
320
|
-
allowedDomains: [],
|
|
321
|
-
createdAt: 1,
|
|
322
|
-
updatedAt: 2,
|
|
323
|
-
};
|
|
324
|
-
http.store.set(credentialKey("github", "token"), record);
|
|
325
|
-
_setHttpRecordBackendForTests(http);
|
|
326
|
-
|
|
327
|
-
const live = await listCredentialRecordsLive();
|
|
328
|
-
expect(live.unreachable).toBe(false);
|
|
329
|
-
expect(live.records[0]?.credentialId).toBe("cred-http-only");
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
test("live catalog list does not fail over when CES RPC returns an empty catalog", async () => {
|
|
333
|
-
const rpc = makeBackend("ces-rpc");
|
|
334
|
-
setCredentialRecordBackend(rpc);
|
|
335
|
-
|
|
336
|
-
const http = makeBackend("ces-http");
|
|
337
|
-
http.store.set(credentialKey("github", "token"), {
|
|
338
|
-
credentialId: "cred-http-ignored",
|
|
339
|
-
service: "github",
|
|
340
|
-
field: "token",
|
|
341
|
-
allowedTools: ["bash"],
|
|
342
|
-
allowedDomains: [],
|
|
343
|
-
createdAt: 1,
|
|
344
|
-
updatedAt: 2,
|
|
345
|
-
});
|
|
346
|
-
_setHttpRecordBackendForTests(http);
|
|
347
|
-
|
|
348
|
-
const live = await listCredentialRecordsLive();
|
|
349
|
-
expect(live.unreachable).toBe(false);
|
|
350
|
-
expect(live.records).toEqual([]);
|
|
351
|
-
expect(http.listCalls).toBe(0);
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
test("live catalog list does not fail over for a non-RPC record backend", async () => {
|
|
355
|
-
const backend = makeBackend();
|
|
356
|
-
backend.list = async () => null;
|
|
357
|
-
setCredentialRecordBackend(backend);
|
|
358
|
-
|
|
359
|
-
const http = makeBackend("ces-http");
|
|
360
|
-
http.store.set(credentialKey("github", "token"), {
|
|
361
|
-
credentialId: "cred-http-ignored",
|
|
362
|
-
service: "github",
|
|
363
|
-
field: "token",
|
|
364
|
-
allowedTools: ["bash"],
|
|
365
|
-
allowedDomains: [],
|
|
366
|
-
createdAt: 1,
|
|
367
|
-
updatedAt: 2,
|
|
368
|
-
});
|
|
369
|
-
_setHttpRecordBackendForTests(http);
|
|
370
|
-
|
|
371
|
-
const live = await listCredentialRecordsLive();
|
|
372
|
-
expect(live.unreachable).toBe(true);
|
|
373
|
-
expect(live.records).toEqual([]);
|
|
374
|
-
expect(http.listCalls).toBe(0);
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
test("live catalog list reports unreachable when CES RPC and HTTP both fail", async () => {
|
|
378
|
-
const rpc = makeBackend("ces-rpc");
|
|
379
|
-
rpc.list = async () => null;
|
|
380
|
-
setCredentialRecordBackend(rpc);
|
|
381
|
-
|
|
382
|
-
const http = makeBackend("ces-http");
|
|
383
|
-
http.list = async () => null;
|
|
384
|
-
_setHttpRecordBackendForTests(http);
|
|
385
|
-
|
|
386
|
-
const live = await listCredentialRecordsLive();
|
|
387
|
-
expect(live.unreachable).toBe(true);
|
|
388
|
-
expect(live.records).toEqual([]);
|
|
389
|
-
});
|
|
390
|
-
|
|
391
221
|
test("upsert write-throughs to CES without updating leftover metadata.json", async () => {
|
|
392
222
|
const leftoverRecord: CredentialRecord = {
|
|
393
223
|
credentialId: "cred-leftover",
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
BadRequestError,
|
|
5
|
-
ForbiddenError,
|
|
6
|
-
InternalError,
|
|
7
|
-
} from "../runtime/routes/errors.js";
|
|
3
|
+
import { BadRequestError, ForbiddenError } from "../runtime/routes/errors.js";
|
|
8
4
|
import type { CredentialMetadata } from "../tools/credentials/metadata-store.js";
|
|
9
5
|
|
|
10
6
|
// ---------------------------------------------------------------------------
|
|
@@ -19,8 +15,6 @@ let disconnectedProviders: string[];
|
|
|
19
15
|
let credentialIdCounter: number;
|
|
20
16
|
let scrubbedValues: string[];
|
|
21
17
|
let scrubRejects: boolean;
|
|
22
|
-
let liveRecordsUnreachable: boolean;
|
|
23
|
-
let secretGetUnreachable: boolean;
|
|
24
18
|
|
|
25
19
|
function metaKey(service: string, field: string): string {
|
|
26
20
|
return `${service}:${field}`;
|
|
@@ -55,7 +49,7 @@ mock.module("../security/secure-keys.js", () => ({
|
|
|
55
49
|
getSecureKeyAsync: mock(async (key: string) => secureStore.get(key)),
|
|
56
50
|
getSecureKeyResultAsync: mock(async (key: string) => ({
|
|
57
51
|
value: secureStore.get(key),
|
|
58
|
-
unreachable:
|
|
52
|
+
unreachable: false,
|
|
59
53
|
})),
|
|
60
54
|
deleteSecureKeyAsync: mock(async (key: string) =>
|
|
61
55
|
secureStore.delete(key) ? "deleted" : "not-found",
|
|
@@ -66,10 +60,7 @@ mock.module("../security/secure-keys.js", () => ({
|
|
|
66
60
|
|
|
67
61
|
mock.module("../tools/credentials/metadata-store.js", () => ({
|
|
68
62
|
assertMetadataWritable: () => {},
|
|
69
|
-
|
|
70
|
-
records: Array.from(metadataStore.values()),
|
|
71
|
-
unreachable: liveRecordsUnreachable,
|
|
72
|
-
})),
|
|
63
|
+
listCredentialMetadata: mock(() => Array.from(metadataStore.values())),
|
|
73
64
|
getCredentialMetadata: mock((service: string, field: string) =>
|
|
74
65
|
metadataStore.get(metaKey(service, field)),
|
|
75
66
|
),
|
|
@@ -210,8 +201,6 @@ describe("credentials routes", () => {
|
|
|
210
201
|
credentialIdCounter = 0;
|
|
211
202
|
scrubbedValues = [];
|
|
212
203
|
scrubRejects = false;
|
|
213
|
-
liveRecordsUnreachable = false;
|
|
214
|
-
secretGetUnreachable = false;
|
|
215
204
|
_resetRevealSuccessRegistryForTest();
|
|
216
205
|
resetForChatMintRegistryForTest();
|
|
217
206
|
chatCredentialRevealFlag = false;
|
|
@@ -810,204 +799,6 @@ describe("credentials routes", () => {
|
|
|
810
799
|
expect(result.credentials).toHaveLength(1);
|
|
811
800
|
expect(result.credentials[0].service).toBe("github");
|
|
812
801
|
});
|
|
813
|
-
|
|
814
|
-
test("fails immediately when the credential vault is unreachable", async () => {
|
|
815
|
-
liveRecordsUnreachable = true;
|
|
816
|
-
await setRoute!.handler({
|
|
817
|
-
body: { service: "vercel", field: "api_token", value: SECRET_VALUE },
|
|
818
|
-
});
|
|
819
|
-
|
|
820
|
-
await expect(listRoute!.handler({ body: {} })).rejects.toThrow(
|
|
821
|
-
InternalError,
|
|
822
|
-
);
|
|
823
|
-
await expect(listRoute!.handler({ body: {} })).rejects.toThrow(
|
|
824
|
-
/Credential store is unreachable/,
|
|
825
|
-
);
|
|
826
|
-
});
|
|
827
|
-
|
|
828
|
-
test("fails immediately when a secret fetch reports the vault unreachable", async () => {
|
|
829
|
-
await setRoute!.handler({
|
|
830
|
-
body: { service: "vercel", field: "api_token", value: SECRET_VALUE },
|
|
831
|
-
});
|
|
832
|
-
secretGetUnreachable = true;
|
|
833
|
-
|
|
834
|
-
await expect(listRoute!.handler({ body: {} })).rejects.toThrow(
|
|
835
|
-
InternalError,
|
|
836
|
-
);
|
|
837
|
-
});
|
|
838
|
-
});
|
|
839
|
-
|
|
840
|
-
describe("platform-managed credentials", () => {
|
|
841
|
-
const PLATFORM_KEY = "vk-platform-provisioned-key";
|
|
842
|
-
const PLATFORM_BASE_URL = "https://platform.example";
|
|
843
|
-
|
|
844
|
-
/**
|
|
845
|
-
* The platform provisions the pod's own credentials by POSTing them to
|
|
846
|
-
* `/v1/secrets` as `credential` entries, which land in the same secure
|
|
847
|
-
* store and metadata table as a user's own credentials.
|
|
848
|
-
*/
|
|
849
|
-
function seedPlatformCredential(field: string, value: string): string {
|
|
850
|
-
const key = `vellum:${field}`;
|
|
851
|
-
secureStore.set(key, value);
|
|
852
|
-
const now = Date.now();
|
|
853
|
-
metadataStore.set(key, {
|
|
854
|
-
credentialId: `cred-${++credentialIdCounter}`,
|
|
855
|
-
service: "vellum",
|
|
856
|
-
field,
|
|
857
|
-
allowedTools: [],
|
|
858
|
-
allowedDomains: [],
|
|
859
|
-
createdAt: now,
|
|
860
|
-
updatedAt: now,
|
|
861
|
-
});
|
|
862
|
-
return metadataStore.get(key)!.credentialId;
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
test("the listing omits platform credentials and keeps the user's own", async () => {
|
|
866
|
-
// GIVEN the platform's provisioned credentials alongside a user's
|
|
867
|
-
seedPlatformCredential("assistant_api_key", PLATFORM_KEY);
|
|
868
|
-
seedPlatformCredential("platform_base_url", PLATFORM_BASE_URL);
|
|
869
|
-
await setRoute!.handler({
|
|
870
|
-
body: { service: "vercel", field: "api_token", value: SECRET_VALUE },
|
|
871
|
-
});
|
|
872
|
-
|
|
873
|
-
// WHEN the credentials are listed
|
|
874
|
-
const result = (await listRoute!.handler({ body: {} })) as ListResponse;
|
|
875
|
-
|
|
876
|
-
// THEN only the user's credential is a row, and no platform value leaks
|
|
877
|
-
expect(result.credentials.map((c) => `${c.service}:${c.field}`)).toEqual([
|
|
878
|
-
"vercel:api_token",
|
|
879
|
-
]);
|
|
880
|
-
expect(JSON.stringify(result)).not.toContain(PLATFORM_KEY);
|
|
881
|
-
});
|
|
882
|
-
|
|
883
|
-
test("reveal refuses the platform API key for every principal", async () => {
|
|
884
|
-
/**
|
|
885
|
-
* Both farming paths land on this handler: the assistant's own tool
|
|
886
|
-
* shell arrives as `local`, a Settings click as `user`.
|
|
887
|
-
*/
|
|
888
|
-
seedPlatformCredential("assistant_api_key", PLATFORM_KEY);
|
|
889
|
-
|
|
890
|
-
for (const principal of ["local", "user", "svc_gateway"]) {
|
|
891
|
-
await expect(
|
|
892
|
-
revealRoute!.handler({
|
|
893
|
-
body: { service: "vellum", field: "assistant_api_key" },
|
|
894
|
-
headers: { "x-vellum-principal-type": principal },
|
|
895
|
-
}),
|
|
896
|
-
).rejects.toThrow(ForbiddenError);
|
|
897
|
-
}
|
|
898
|
-
});
|
|
899
|
-
|
|
900
|
-
test("reveal refuses a platform credential looked up by UUID", async () => {
|
|
901
|
-
const credentialId = seedPlatformCredential(
|
|
902
|
-
"assistant_api_key",
|
|
903
|
-
PLATFORM_KEY,
|
|
904
|
-
);
|
|
905
|
-
|
|
906
|
-
await expect(
|
|
907
|
-
revealRoute!.handler({
|
|
908
|
-
body: { id: credentialId },
|
|
909
|
-
headers: { "x-vellum-principal-type": "local" },
|
|
910
|
-
}),
|
|
911
|
-
).rejects.toThrow(/owned by the Vellum platform/);
|
|
912
|
-
});
|
|
913
|
-
|
|
914
|
-
test("inspect refuses platform credentials", async () => {
|
|
915
|
-
seedPlatformCredential("assistant_api_key", PLATFORM_KEY);
|
|
916
|
-
seedPlatformCredential("platform_base_url", PLATFORM_BASE_URL);
|
|
917
|
-
|
|
918
|
-
for (const field of ["assistant_api_key", "platform_base_url"]) {
|
|
919
|
-
await expect(
|
|
920
|
-
inspectRoute!.handler({
|
|
921
|
-
body: { service: "vellum", field },
|
|
922
|
-
}),
|
|
923
|
-
).rejects.toThrow(ForbiddenError);
|
|
924
|
-
}
|
|
925
|
-
});
|
|
926
|
-
|
|
927
|
-
test("set refuses platform credentials", async () => {
|
|
928
|
-
/**
|
|
929
|
-
* A write is a read by another name: repointing `platform_base_url`
|
|
930
|
-
* sends the next platform call, bearing the API key, to a host the
|
|
931
|
-
* writer chose. The platform's own provisioning does not come through
|
|
932
|
-
* this route; it writes over `POST /v1/secrets`.
|
|
933
|
-
*/
|
|
934
|
-
for (const field of ["assistant_api_key", "platform_base_url"]) {
|
|
935
|
-
await expect(
|
|
936
|
-
setRoute!.handler({
|
|
937
|
-
body: { service: "vellum", field, value: "https://attacker.test" },
|
|
938
|
-
}),
|
|
939
|
-
).rejects.toThrow(ForbiddenError);
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
expect(secureStore.has("vellum:assistant_api_key")).toBe(false);
|
|
943
|
-
expect(secureStore.has("vellum:platform_base_url")).toBe(false);
|
|
944
|
-
});
|
|
945
|
-
|
|
946
|
-
test("set does not overwrite an already-provisioned platform credential", async () => {
|
|
947
|
-
seedPlatformCredential("platform_base_url", PLATFORM_BASE_URL);
|
|
948
|
-
|
|
949
|
-
await expect(
|
|
950
|
-
setRoute!.handler({
|
|
951
|
-
body: {
|
|
952
|
-
service: "vellum",
|
|
953
|
-
field: "platform_base_url",
|
|
954
|
-
value: "https://attacker.test",
|
|
955
|
-
},
|
|
956
|
-
}),
|
|
957
|
-
).rejects.toThrow(/owned by the Vellum platform/);
|
|
958
|
-
|
|
959
|
-
expect(secureStore.get("vellum:platform_base_url")).toBe(
|
|
960
|
-
PLATFORM_BASE_URL,
|
|
961
|
-
);
|
|
962
|
-
});
|
|
963
|
-
|
|
964
|
-
test("delete refuses platform credentials", async () => {
|
|
965
|
-
seedPlatformCredential("assistant_api_key", PLATFORM_KEY);
|
|
966
|
-
seedPlatformCredential("platform_base_url", PLATFORM_BASE_URL);
|
|
967
|
-
|
|
968
|
-
for (const field of ["assistant_api_key", "platform_base_url"]) {
|
|
969
|
-
await expect(
|
|
970
|
-
deleteRoute!.handler({ body: { service: "vellum", field } }),
|
|
971
|
-
).rejects.toThrow(ForbiddenError);
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
expect(secureStore.get("vellum:assistant_api_key")).toBe(PLATFORM_KEY);
|
|
975
|
-
expect(secureStore.get("vellum:platform_base_url")).toBe(
|
|
976
|
-
PLATFORM_BASE_URL,
|
|
977
|
-
);
|
|
978
|
-
});
|
|
979
|
-
|
|
980
|
-
test("a user credential is still writable and deletable", async () => {
|
|
981
|
-
const stored = (await setRoute!.handler({
|
|
982
|
-
body: { service: "vercel", field: "api_token", value: SECRET_VALUE },
|
|
983
|
-
})) as SetResponse;
|
|
984
|
-
expect(stored.service).toBe("vercel");
|
|
985
|
-
expect(secureStore.get("vercel:api_token")).toBe(SECRET_VALUE);
|
|
986
|
-
|
|
987
|
-
const deleted = (await deleteRoute!.handler({
|
|
988
|
-
body: { service: "vercel", field: "api_token" },
|
|
989
|
-
})) as DeleteResponse;
|
|
990
|
-
expect(deleted.field).toBe("api_token");
|
|
991
|
-
expect(secureStore.has("vercel:api_token")).toBe(false);
|
|
992
|
-
});
|
|
993
|
-
|
|
994
|
-
test("a user credential still inspects and reveals", async () => {
|
|
995
|
-
seedPlatformCredential("assistant_api_key", PLATFORM_KEY);
|
|
996
|
-
await setRoute!.handler({
|
|
997
|
-
body: { service: "vercel", field: "api_token", value: SECRET_VALUE },
|
|
998
|
-
});
|
|
999
|
-
|
|
1000
|
-
const inspected = (await inspectRoute!.handler({
|
|
1001
|
-
body: { service: "vercel", field: "api_token" },
|
|
1002
|
-
})) as { scrubbedValue: string };
|
|
1003
|
-
expect(inspected.scrubbedValue).toBe("supe****");
|
|
1004
|
-
|
|
1005
|
-
const revealed = (await revealRoute!.handler({
|
|
1006
|
-
body: { service: "vercel", field: "api_token" },
|
|
1007
|
-
headers: { "x-vellum-principal-type": "user" },
|
|
1008
|
-
})) as { value: string };
|
|
1009
|
-
expect(revealed.value).toBe(SECRET_VALUE);
|
|
1010
|
-
});
|
|
1011
802
|
});
|
|
1012
803
|
|
|
1013
804
|
describe("platform-managed credentials", () => {
|
|
@@ -204,7 +204,6 @@ describe("Invariant 2: no generic plaintext secret read API", () => {
|
|
|
204
204
|
"providers/registry.ts", // provider registry API key lookup for initialization
|
|
205
205
|
"providers/inference/resolve-auth.ts", // provider_connection auth resolver (api_key path reads vault, mirrors registry.ts)
|
|
206
206
|
"providers/inference/codex-token-refresh.ts", // Codex OAuth token refresh (reads/writes access_token, refresh_token, expires_at)
|
|
207
|
-
"providers/inference/service-account-token.ts", // Google service-account JWT exchange (reads service-account JSON, writes token_cache blob)
|
|
208
207
|
"providers/inference/chatgpt-subscription-credentials.ts", // ChatGPT subscription sign-in token storage, shared by the daemon routes and the CLI (setSecureKeyAsync only; no reads)
|
|
209
208
|
"providers/provider-availability.ts", // provider availability API key check
|
|
210
209
|
"media/image-credentials.ts", // shared image-gen credential resolver (provider API key lookup)
|
|
@@ -212,8 +211,7 @@ describe("Invariant 2: no generic plaintext secret read API", () => {
|
|
|
212
211
|
"persistence/llm-request-log-source-clickhouse.ts", // ClickHouse read source — lazy lookup of clickhouse:url + clickhouse:password + vellum:platform_assistant_id for self-scoped mirror reads
|
|
213
212
|
"persistence/llm-request-log-sink-clickhouse.ts", // ClickHouse write sink — lazy lookup of clickhouse:url + clickhouse:password + vellum:platform_assistant_id for self-scoped log writes
|
|
214
213
|
"persistence/compaction-log-store-clickhouse.ts", // ClickHouse compaction log writer — lazy lookup of clickhouse:url + clickhouse:password + vellum:platform_assistant_id for self-scoped event writes
|
|
215
|
-
"config/platform-
|
|
216
|
-
"config/platform-rehydration.ts", // startup rehydration of platform base URL from the credential store and ids from platform validate
|
|
214
|
+
"config/platform-rehydration.ts", // startup rehydration of platform base URL + IDs from credential store (daemon and schedule worker)
|
|
217
215
|
"workspace/migrations/006-services-config.ts", // services config migration reads provider API keys
|
|
218
216
|
"workspace/migrations/018-rekey-compound-credential-keys.ts", // re-key compound credential storage keys
|
|
219
217
|
"daemon/conversation-process.ts", // masked provider key display
|
|
@@ -226,7 +224,7 @@ describe("Invariant 2: no generic plaintext secret read API", () => {
|
|
|
226
224
|
"runtime/routes/sanity-routes.ts", // Sanity connect/discover routes (reads stored api_token from credential store)
|
|
227
225
|
"runtime/routes/platform-routes.ts", // CLI platform connect/disconnect/status routes (CLI-migrated to IPC)
|
|
228
226
|
"runtime/routes/roadmap-routes.ts", // signs public-roadmap calls with the assistant API key (outbound Authorization header only; the value never reaches a response, a log, or the CLI process)
|
|
229
|
-
"inbound/platform-callback-registration.ts", // managed credential lookup for platform base URL and API key
|
|
227
|
+
"inbound/platform-callback-registration.ts", // managed credential lookup for platform base URL, assistant ID, and API key
|
|
230
228
|
"tts/providers/elevenlabs-provider.ts", // ElevenLabs TTS API key lookup
|
|
231
229
|
"tts/providers/deepgram-provider.ts", // Deepgram TTS API key lookup
|
|
232
230
|
"tts/providers/xai-provider.ts", // xAI TTS API key lookup
|