@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
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
getPlatformBaseUrl,
|
|
5
|
-
setPlatformAssistantId,
|
|
6
|
-
setPlatformBaseUrl,
|
|
7
|
-
setPlatformOrganizationId,
|
|
8
|
-
setPlatformUserId,
|
|
9
|
-
} from "../env.js";
|
|
10
|
-
|
|
11
|
-
const actualSecureKeys = await import("../../security/secure-keys.js");
|
|
12
|
-
mock.module("../../security/secure-keys.js", () => ({
|
|
13
|
-
...actualSecureKeys,
|
|
14
|
-
getSecureKeyAsync: async () => undefined,
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
const {
|
|
18
|
-
_resetPlatformIdentityEnsureForTests,
|
|
19
|
-
fetchPlatformIdentityIds,
|
|
20
|
-
PLATFORM_IDENTITY_VALIDATE_PATH,
|
|
21
|
-
resolvePlatformAssistantId,
|
|
22
|
-
} = await import("../platform-identity.js");
|
|
23
|
-
|
|
24
|
-
const BASE_URL = "https://platform.vellum.ai";
|
|
25
|
-
const ASSISTANT_ID = "11111111-2222-4333-8444-555555555555";
|
|
26
|
-
const ORG_ID = "22222222-3333-4444-8555-666666666666";
|
|
27
|
-
const USER_ID = "33333333-4444-4555-8666-777777777777";
|
|
28
|
-
|
|
29
|
-
describe("fetchPlatformIdentityIds", () => {
|
|
30
|
-
const originalFetch = globalThis.fetch;
|
|
31
|
-
const fetchCalls: Array<{ url: string; init?: RequestInit }> = [];
|
|
32
|
-
let fetchImpl: (
|
|
33
|
-
input: RequestInfo | URL,
|
|
34
|
-
init?: RequestInit,
|
|
35
|
-
) => Promise<Response> = async () =>
|
|
36
|
-
new Response("not found", { status: 404 });
|
|
37
|
-
|
|
38
|
-
beforeEach(() => {
|
|
39
|
-
fetchCalls.length = 0;
|
|
40
|
-
fetchImpl = async () => new Response("not found", { status: 404 });
|
|
41
|
-
globalThis.fetch = (async (
|
|
42
|
-
input: RequestInfo | URL,
|
|
43
|
-
init?: RequestInit,
|
|
44
|
-
) => {
|
|
45
|
-
const url = typeof input === "string" ? input : input.toString();
|
|
46
|
-
fetchCalls.push({ url, init });
|
|
47
|
-
return fetchImpl(input, init);
|
|
48
|
-
}) as unknown as typeof fetch;
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
afterEach(() => {
|
|
52
|
-
globalThis.fetch = originalFetch;
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test("returns the three ids from a successful validate response", async () => {
|
|
56
|
-
fetchImpl = async () =>
|
|
57
|
-
new Response(
|
|
58
|
-
JSON.stringify({
|
|
59
|
-
assistant_id: ASSISTANT_ID,
|
|
60
|
-
organization_id: ORG_ID,
|
|
61
|
-
user_id: USER_ID,
|
|
62
|
-
name: "Example Assistant",
|
|
63
|
-
}),
|
|
64
|
-
{ status: 200 },
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
await expect(
|
|
68
|
-
fetchPlatformIdentityIds(BASE_URL, "assistant-key"),
|
|
69
|
-
).resolves.toEqual({
|
|
70
|
-
assistantId: ASSISTANT_ID,
|
|
71
|
-
organizationId: ORG_ID,
|
|
72
|
-
userId: USER_ID,
|
|
73
|
-
});
|
|
74
|
-
expect(fetchCalls[0]?.url).toBe(
|
|
75
|
-
`${BASE_URL}${PLATFORM_IDENTITY_VALIDATE_PATH}`,
|
|
76
|
-
);
|
|
77
|
-
expect(fetchCalls[0]?.init?.method).toBe("POST");
|
|
78
|
-
const headers = new Headers(fetchCalls[0]?.init?.headers);
|
|
79
|
-
expect(headers.get("Authorization")).toBe("Api-Key assistant-key");
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test("strips a trailing slash from the base URL", async () => {
|
|
83
|
-
fetchImpl = async () =>
|
|
84
|
-
new Response(
|
|
85
|
-
JSON.stringify({
|
|
86
|
-
assistant_id: ASSISTANT_ID,
|
|
87
|
-
organization_id: ORG_ID,
|
|
88
|
-
user_id: USER_ID,
|
|
89
|
-
}),
|
|
90
|
-
{ status: 200 },
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
await fetchPlatformIdentityIds(`${BASE_URL}/`, "assistant-key");
|
|
94
|
-
expect(fetchCalls[0]?.url).toBe(
|
|
95
|
-
`${BASE_URL}${PLATFORM_IDENTITY_VALIDATE_PATH}`,
|
|
96
|
-
);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test("returns null on 401 without throwing", async () => {
|
|
100
|
-
fetchImpl = async () => new Response("no", { status: 401 });
|
|
101
|
-
await expect(
|
|
102
|
-
fetchPlatformIdentityIds(BASE_URL, "assistant-key"),
|
|
103
|
-
).resolves.toBeNull();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test("returns null on a network error without throwing", async () => {
|
|
107
|
-
fetchImpl = async () => {
|
|
108
|
-
throw new Error("network down");
|
|
109
|
-
};
|
|
110
|
-
await expect(
|
|
111
|
-
fetchPlatformIdentityIds(BASE_URL, "assistant-key"),
|
|
112
|
-
).resolves.toBeNull();
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
describe("resolvePlatformAssistantId", () => {
|
|
117
|
-
const originalFetch = globalThis.fetch;
|
|
118
|
-
const originalAssistantApiKeyEnv = process.env.ASSISTANT_API_KEY;
|
|
119
|
-
const fetchCalls: Array<{ url: string; init?: RequestInit }> = [];
|
|
120
|
-
let fetchImpl: (
|
|
121
|
-
input: RequestInfo | URL,
|
|
122
|
-
init?: RequestInit,
|
|
123
|
-
) => Promise<Response> = async () =>
|
|
124
|
-
new Response("not found", { status: 404 });
|
|
125
|
-
|
|
126
|
-
beforeEach(() => {
|
|
127
|
-
fetchCalls.length = 0;
|
|
128
|
-
fetchImpl = async () => new Response("not found", { status: 404 });
|
|
129
|
-
globalThis.fetch = (async (
|
|
130
|
-
input: RequestInfo | URL,
|
|
131
|
-
init?: RequestInit,
|
|
132
|
-
) => {
|
|
133
|
-
const url = typeof input === "string" ? input : input.toString();
|
|
134
|
-
fetchCalls.push({ url, init });
|
|
135
|
-
return fetchImpl(input, init);
|
|
136
|
-
}) as unknown as typeof fetch;
|
|
137
|
-
delete process.env.ASSISTANT_API_KEY;
|
|
138
|
-
setPlatformBaseUrl(undefined);
|
|
139
|
-
setPlatformAssistantId(undefined);
|
|
140
|
-
setPlatformOrganizationId(undefined);
|
|
141
|
-
setPlatformUserId(undefined);
|
|
142
|
-
_resetPlatformIdentityEnsureForTests();
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
afterEach(() => {
|
|
146
|
-
globalThis.fetch = originalFetch;
|
|
147
|
-
if (originalAssistantApiKeyEnv === undefined) {
|
|
148
|
-
delete process.env.ASSISTANT_API_KEY;
|
|
149
|
-
} else {
|
|
150
|
-
process.env.ASSISTANT_API_KEY = originalAssistantApiKeyEnv;
|
|
151
|
-
}
|
|
152
|
-
setPlatformBaseUrl(undefined);
|
|
153
|
-
setPlatformAssistantId(undefined);
|
|
154
|
-
setPlatformOrganizationId(undefined);
|
|
155
|
-
setPlatformUserId(undefined);
|
|
156
|
-
_resetPlatformIdentityEnsureForTests();
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
test("returns the in-memory override without calling validate", async () => {
|
|
160
|
-
setPlatformAssistantId(ASSISTANT_ID);
|
|
161
|
-
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
162
|
-
await expect(resolvePlatformAssistantId()).resolves.toBe(ASSISTANT_ID);
|
|
163
|
-
expect(fetchCalls).toHaveLength(0);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
test("returns empty when the in-memory override is unset and there is no API key", async () => {
|
|
167
|
-
await expect(resolvePlatformAssistantId()).resolves.toBe("");
|
|
168
|
-
expect(fetchCalls).toHaveLength(0);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test("loads ids from validate when the in-memory override is empty", async () => {
|
|
172
|
-
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
173
|
-
setPlatformBaseUrl(BASE_URL);
|
|
174
|
-
fetchImpl = async () =>
|
|
175
|
-
new Response(
|
|
176
|
-
JSON.stringify({
|
|
177
|
-
assistant_id: ASSISTANT_ID,
|
|
178
|
-
organization_id: ORG_ID,
|
|
179
|
-
user_id: USER_ID,
|
|
180
|
-
}),
|
|
181
|
-
{ status: 200 },
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
await expect(resolvePlatformAssistantId()).resolves.toBe(ASSISTANT_ID);
|
|
185
|
-
expect(fetchCalls).toHaveLength(1);
|
|
186
|
-
expect(fetchCalls[0]?.url).toBe(
|
|
187
|
-
`${getPlatformBaseUrl().replace(/\/+$/, "")}${PLATFORM_IDENTITY_VALIDATE_PATH}`,
|
|
188
|
-
);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
test("does not retry validate during the cooldown after a failure", async () => {
|
|
192
|
-
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
193
|
-
setPlatformBaseUrl(BASE_URL);
|
|
194
|
-
fetchImpl = async () => new Response("down", { status: 503 });
|
|
195
|
-
|
|
196
|
-
await expect(resolvePlatformAssistantId()).resolves.toBe("");
|
|
197
|
-
await expect(resolvePlatformAssistantId()).resolves.toBe("");
|
|
198
|
-
expect(fetchCalls).toHaveLength(1);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
test("retries validate after a failed attempt once the cooldown is cleared", async () => {
|
|
202
|
-
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
203
|
-
setPlatformBaseUrl(BASE_URL);
|
|
204
|
-
fetchImpl = async () => new Response("down", { status: 503 });
|
|
205
|
-
|
|
206
|
-
await expect(resolvePlatformAssistantId()).resolves.toBe("");
|
|
207
|
-
_resetPlatformIdentityEnsureForTests();
|
|
208
|
-
fetchImpl = async () =>
|
|
209
|
-
new Response(
|
|
210
|
-
JSON.stringify({
|
|
211
|
-
assistant_id: ASSISTANT_ID,
|
|
212
|
-
organization_id: ORG_ID,
|
|
213
|
-
user_id: USER_ID,
|
|
214
|
-
}),
|
|
215
|
-
{ status: 200 },
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
await expect(resolvePlatformAssistantId()).resolves.toBe(ASSISTANT_ID);
|
|
219
|
-
expect(fetchCalls).toHaveLength(2);
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
test("concurrent resolves share one in-flight validate", async () => {
|
|
223
|
-
process.env.ASSISTANT_API_KEY = "assistant-key";
|
|
224
|
-
setPlatformBaseUrl(BASE_URL);
|
|
225
|
-
let release!: (value: Response) => void;
|
|
226
|
-
let notifyFetchStarted!: () => void;
|
|
227
|
-
const fetchStarted = new Promise<void>((resolve) => {
|
|
228
|
-
notifyFetchStarted = resolve;
|
|
229
|
-
});
|
|
230
|
-
fetchImpl = () => {
|
|
231
|
-
notifyFetchStarted();
|
|
232
|
-
return new Promise<Response>((resolve) => {
|
|
233
|
-
release = resolve;
|
|
234
|
-
});
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
const first = resolvePlatformAssistantId();
|
|
238
|
-
const second = resolvePlatformAssistantId();
|
|
239
|
-
await fetchStarted;
|
|
240
|
-
expect(fetchCalls).toHaveLength(1);
|
|
241
|
-
release(
|
|
242
|
-
new Response(
|
|
243
|
-
JSON.stringify({
|
|
244
|
-
assistant_id: ASSISTANT_ID,
|
|
245
|
-
organization_id: ORG_ID,
|
|
246
|
-
user_id: USER_ID,
|
|
247
|
-
}),
|
|
248
|
-
{ status: 200 },
|
|
249
|
-
),
|
|
250
|
-
);
|
|
251
|
-
await expect(first).resolves.toBe(ASSISTANT_ID);
|
|
252
|
-
await expect(second).resolves.toBe(ASSISTANT_ID);
|
|
253
|
-
expect(fetchCalls).toHaveLength(1);
|
|
254
|
-
});
|
|
255
|
-
});
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Raw-config helper shared by the config PATCH and SET routes, the paths that
|
|
3
|
-
* write a coding agent's entry.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { isPlainObject } from "../util/object.js";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Clearing a leaf of a coding agent's entry is a write of `null` - a PATCH of
|
|
10
|
-
* `{ acp: { agents: { <id>: { model: null } } } }` or a
|
|
11
|
-
* `config set acp.agents.<id>.model null`. The deep-merge assigns that literal
|
|
12
|
-
* `null` because the stored value is a scalar, and a SET writes it verbatim by
|
|
13
|
-
* design. Both `command` and `model` are optional strings in `AcpConfigSchema`,
|
|
14
|
-
* so a persisted `null` makes every later `loadConfig()` warn and take its
|
|
15
|
-
* salvage path, dropping the whole `acp` section with the agents defined in it.
|
|
16
|
-
* Clearing means removing the key, so drop it here on every write path.
|
|
17
|
-
*
|
|
18
|
-
* A cleared `command` then reads as an omitted one: a bundled id inherits the
|
|
19
|
-
* profile's command, and an id that has no profile fails the agents refinement
|
|
20
|
-
* with a message naming the id, which tells the user more than zod's "expected
|
|
21
|
-
* string, received null".
|
|
22
|
-
*/
|
|
23
|
-
export function scrubNulledAcpAgentLeaves(raw: Record<string, unknown>): void {
|
|
24
|
-
const acp = raw.acp;
|
|
25
|
-
if (!isPlainObject(acp)) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const agents = acp.agents;
|
|
29
|
-
if (!isPlainObject(agents)) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
for (const entry of Object.values(agents)) {
|
|
33
|
-
if (!isPlainObject(entry)) {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
if (entry.command === null) {
|
|
37
|
-
delete entry.command;
|
|
38
|
-
}
|
|
39
|
-
if (entry.model === null) {
|
|
40
|
-
delete entry.model;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Covers the ACP config leaf that carries model selection, the per-agent
|
|
3
|
-
* `model`. It is optional with no `.default()`, so an absent value must stay
|
|
4
|
-
* absent after parsing: the bundled profile supplies the model a session
|
|
5
|
-
* starts on, and a key materialized as `undefined` would shadow it.
|
|
6
|
-
*
|
|
7
|
-
* `command` is optional in the same shape, so an entry for a bundled id can
|
|
8
|
-
* carry a model and nothing else; the record's own check keeps a command
|
|
9
|
-
* required for every id that has no bundled profile to inherit one from.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { describe, expect, test } from "bun:test";
|
|
13
|
-
|
|
14
|
-
import { AcpAgentConfigSchema, AcpConfigSchema } from "./acp-schema.js";
|
|
15
|
-
|
|
16
|
-
describe("AcpConfigSchema", () => {
|
|
17
|
-
test("populates defaults for an empty config", () => {
|
|
18
|
-
expect(AcpConfigSchema.parse({})).toEqual({
|
|
19
|
-
maxConcurrentSessions: 4,
|
|
20
|
-
agents: {},
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe("AcpConfigSchema agents", () => {
|
|
26
|
-
test("a bundled id's entry may omit command and name only a model", () => {
|
|
27
|
-
const parsed = AcpConfigSchema.parse({
|
|
28
|
-
agents: { claude: { model: "sonnet" } },
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
expect(parsed.agents).toEqual({ claude: { args: [], model: "sonnet" } });
|
|
32
|
-
expect("command" in parsed.agents.claude!).toBe(false);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test("an id with no bundled profile needs a command", () => {
|
|
36
|
-
const result = AcpConfigSchema.safeParse({
|
|
37
|
-
agents: { mine: { model: "sonnet" } },
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
expect(result.success).toBe(false);
|
|
41
|
-
if (result.success) {
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
expect(result.error.issues.map((issue) => issue.path)).toEqual([
|
|
45
|
-
["agents", "mine", "command"],
|
|
46
|
-
]);
|
|
47
|
-
expect(result.error.issues[0]?.message).toContain("acp.agents.mine");
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test("an id naming an Object.prototype member inherits no command", () => {
|
|
51
|
-
expect(
|
|
52
|
-
AcpConfigSchema.safeParse({ agents: { constructor: { model: "x" } } })
|
|
53
|
-
.success,
|
|
54
|
-
).toBe(false);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
describe("AcpAgentConfigSchema", () => {
|
|
59
|
-
test("round-trips a per-agent model override", () => {
|
|
60
|
-
expect(
|
|
61
|
-
AcpAgentConfigSchema.parse({
|
|
62
|
-
command: "claude-agent-acp",
|
|
63
|
-
model: "opus",
|
|
64
|
-
}),
|
|
65
|
-
).toEqual({ command: "claude-agent-acp", args: [], model: "opus" });
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test("leaves model unset when omitted, so a bundled profile's shows through", () => {
|
|
69
|
-
const parsed = AcpAgentConfigSchema.parse({ command: "claude-agent-acp" });
|
|
70
|
-
|
|
71
|
-
expect(parsed.model).toBeUndefined();
|
|
72
|
-
expect("model" in parsed).toBe(false);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test("rejects a non-string model", () => {
|
|
76
|
-
expect(
|
|
77
|
-
AcpAgentConfigSchema.safeParse({ command: "claude-agent-acp", model: 3 })
|
|
78
|
-
.success,
|
|
79
|
-
).toBe(false);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bound platform identity (assistant, organization, user).
|
|
3
|
-
*
|
|
4
|
-
* Django maps an assistant API key to these ids via
|
|
5
|
-
* `POST /v1/internal/assistants/validate/`. Process startup rehydrates from
|
|
6
|
-
* that endpoint into the in-memory overrides. Resolution reads those
|
|
7
|
-
* overrides (and `PLATFORM_ORGANIZATION_ID` / `PLATFORM_USER_ID` when set).
|
|
8
|
-
* When the in-memory assistant id is empty, the next resolve retries
|
|
9
|
-
* validate (single-flight, with a cooldown after a failed attempt).
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { credentialKey } from "../security/credential-key.js";
|
|
13
|
-
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
14
|
-
import { getLogger } from "../util/logger.js";
|
|
15
|
-
import {
|
|
16
|
-
getPlatformAssistantId,
|
|
17
|
-
getPlatformBaseUrl,
|
|
18
|
-
getPlatformOrganizationId,
|
|
19
|
-
getPlatformUserId,
|
|
20
|
-
setPlatformAssistantId,
|
|
21
|
-
setPlatformOrganizationId,
|
|
22
|
-
setPlatformUserId,
|
|
23
|
-
} from "./env.js";
|
|
24
|
-
|
|
25
|
-
const log = getLogger("platform-identity");
|
|
26
|
-
|
|
27
|
-
export const PLATFORM_IDENTITY_VALIDATE_PATH =
|
|
28
|
-
"/v1/internal/assistants/validate/";
|
|
29
|
-
|
|
30
|
-
const VALIDATE_TIMEOUT_MS = 5_000;
|
|
31
|
-
const ENSURE_COOLDOWN_MS = 10_000;
|
|
32
|
-
|
|
33
|
-
export type PlatformIdentityIds = {
|
|
34
|
-
assistantId: string;
|
|
35
|
-
organizationId: string;
|
|
36
|
-
userId: string;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
function asNonEmptyString(value: unknown): string | undefined {
|
|
40
|
-
if (typeof value !== "string") {
|
|
41
|
-
return undefined;
|
|
42
|
-
}
|
|
43
|
-
const trimmed = value.trim();
|
|
44
|
-
return trimmed.length > 0 ? trimmed : undefined;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function applyPlatformIdentityIds(ids: PlatformIdentityIds): void {
|
|
48
|
-
if (ids.assistantId) {
|
|
49
|
-
setPlatformAssistantId(ids.assistantId);
|
|
50
|
-
}
|
|
51
|
-
if (ids.organizationId) {
|
|
52
|
-
setPlatformOrganizationId(ids.organizationId);
|
|
53
|
-
}
|
|
54
|
-
if (ids.userId) {
|
|
55
|
-
setPlatformUserId(ids.userId);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Trade an assistant API key for the bound platform ids.
|
|
61
|
-
*
|
|
62
|
-
* Returns null when the platform is unreachable, refuses the key, or the
|
|
63
|
-
* body has no ids. Never throws.
|
|
64
|
-
*/
|
|
65
|
-
export async function fetchPlatformIdentityIds(
|
|
66
|
-
baseUrl: string,
|
|
67
|
-
apiKey: string,
|
|
68
|
-
): Promise<PlatformIdentityIds | null> {
|
|
69
|
-
const url = `${baseUrl.replace(/\/+$/, "")}${PLATFORM_IDENTITY_VALIDATE_PATH}`;
|
|
70
|
-
try {
|
|
71
|
-
const res = await fetch(url, {
|
|
72
|
-
method: "POST",
|
|
73
|
-
headers: {
|
|
74
|
-
Authorization: `Api-Key ${apiKey}`,
|
|
75
|
-
"Content-Type": "application/json",
|
|
76
|
-
},
|
|
77
|
-
body: "{}",
|
|
78
|
-
signal: AbortSignal.timeout(VALIDATE_TIMEOUT_MS),
|
|
79
|
-
});
|
|
80
|
-
if (!res.ok) {
|
|
81
|
-
log.warn(
|
|
82
|
-
{ status: res.status },
|
|
83
|
-
"platform identity validate returned non-2xx",
|
|
84
|
-
);
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
const body: unknown = await res.json();
|
|
88
|
-
if (!body || typeof body !== "object") {
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
const obj = body as Record<string, unknown>;
|
|
92
|
-
const assistantId = asNonEmptyString(obj.assistant_id);
|
|
93
|
-
const organizationId = asNonEmptyString(obj.organization_id);
|
|
94
|
-
const userId = asNonEmptyString(obj.user_id);
|
|
95
|
-
if (!assistantId && !organizationId && !userId) {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
assistantId: assistantId ?? "",
|
|
100
|
-
organizationId: organizationId ?? "",
|
|
101
|
-
userId: userId ?? "",
|
|
102
|
-
};
|
|
103
|
-
} catch (err) {
|
|
104
|
-
log.warn({ err }, "platform identity validate failed");
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async function readAssistantApiKey(): Promise<string> {
|
|
110
|
-
try {
|
|
111
|
-
const stored = (
|
|
112
|
-
await getSecureKeyAsync(credentialKey("vellum", "assistant_api_key"))
|
|
113
|
-
)?.trim();
|
|
114
|
-
if (stored) {
|
|
115
|
-
return stored;
|
|
116
|
-
}
|
|
117
|
-
} catch (err) {
|
|
118
|
-
log.warn({ err }, "failed to read assistant API key from credential store");
|
|
119
|
-
}
|
|
120
|
-
return process.env.ASSISTANT_API_KEY?.trim() ?? "";
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
let ensureInFlight: Promise<void> | null = null;
|
|
124
|
-
let nextEnsureAttemptAt = 0;
|
|
125
|
-
|
|
126
|
-
export function _resetPlatformIdentityEnsureForTests(): void {
|
|
127
|
-
ensureInFlight = null;
|
|
128
|
-
nextEnsureAttemptAt = 0;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Load in-memory platform ids from validate when they are missing.
|
|
133
|
-
*
|
|
134
|
-
* No-ops when the assistant id is already set, when auth prerequisites are
|
|
135
|
-
* missing, or when a failed attempt is still inside the cooldown window.
|
|
136
|
-
* Concurrent callers share one in-flight request.
|
|
137
|
-
*/
|
|
138
|
-
export async function ensurePlatformIdentityIds(): Promise<void> {
|
|
139
|
-
if (getPlatformAssistantId().trim()) {
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
if (Date.now() < nextEnsureAttemptAt) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
if (!ensureInFlight) {
|
|
146
|
-
ensureInFlight = (async () => {
|
|
147
|
-
try {
|
|
148
|
-
const apiKey = await readAssistantApiKey();
|
|
149
|
-
const baseUrl = getPlatformBaseUrl();
|
|
150
|
-
if (!apiKey || !baseUrl) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
const ids = await fetchPlatformIdentityIds(baseUrl, apiKey);
|
|
154
|
-
if (!ids) {
|
|
155
|
-
nextEnsureAttemptAt = Date.now() + ENSURE_COOLDOWN_MS;
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
applyPlatformIdentityIds(ids);
|
|
159
|
-
nextEnsureAttemptAt = 0;
|
|
160
|
-
log.info("Loaded platform identity from platform validate");
|
|
161
|
-
} finally {
|
|
162
|
-
ensureInFlight = null;
|
|
163
|
-
}
|
|
164
|
-
})();
|
|
165
|
-
}
|
|
166
|
-
await ensureInFlight;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export async function resolvePlatformAssistantId(): Promise<string> {
|
|
170
|
-
const existing = getPlatformAssistantId().trim();
|
|
171
|
-
if (existing) {
|
|
172
|
-
return existing;
|
|
173
|
-
}
|
|
174
|
-
await ensurePlatformIdentityIds();
|
|
175
|
-
return getPlatformAssistantId().trim();
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
export async function resolvePlatformAssistantIdOrNull(): Promise<
|
|
179
|
-
string | null
|
|
180
|
-
> {
|
|
181
|
-
const id = await resolvePlatformAssistantId();
|
|
182
|
-
return id || null;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export async function resolvePlatformOrganizationId(): Promise<string> {
|
|
186
|
-
const existing = getPlatformOrganizationId().trim();
|
|
187
|
-
if (existing) {
|
|
188
|
-
return existing;
|
|
189
|
-
}
|
|
190
|
-
await ensurePlatformIdentityIds();
|
|
191
|
-
return getPlatformOrganizationId().trim();
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
export async function resolvePlatformUserId(): Promise<string> {
|
|
195
|
-
const existing = getPlatformUserId().trim();
|
|
196
|
-
if (existing) {
|
|
197
|
-
return existing;
|
|
198
|
-
}
|
|
199
|
-
await ensurePlatformIdentityIds();
|
|
200
|
-
return getPlatformUserId().trim();
|
|
201
|
-
}
|