@vellumai/assistant 0.12.1-staging.1 → 0.12.1
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/openapi.yaml +1 -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 +1 -2
- package/src/__tests__/cu-unified-flow.test.ts +2 -8
- 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__/outlook-messaging-provider.test.ts +6 -6
- 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/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/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 +0 -93
- 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/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/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 -8
- 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 +21 -75
- 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/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/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/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__/home-feed-side-effect.test.ts +3 -153
- 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/home-feed-side-effect.ts +7 -55
- 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 +0 -2
- 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/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__/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/diagnostics-routes.ts +3 -55
- package/src/runtime/routes/index.ts +0 -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 +21 -8
- 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__/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__/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 -117
- 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 -144
- 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/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/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
|
@@ -124,22 +124,11 @@ const spawnMock = mock(
|
|
|
124
124
|
_cwd: string,
|
|
125
125
|
_parentConversationId: string,
|
|
126
126
|
_sendToVellum: (msg: unknown) => void,
|
|
127
|
-
|
|
128
|
-
)
|
|
129
|
-
acpSessionId:
|
|
130
|
-
protocolSessionId:
|
|
131
|
-
|
|
132
|
-
effectiveModel?: string;
|
|
133
|
-
modelWarning?: string;
|
|
134
|
-
}> => {
|
|
135
|
-
const requestedModel = _options?.model?.trim() || undefined;
|
|
136
|
-
return {
|
|
137
|
-
acpSessionId: "acp-session-test",
|
|
138
|
-
protocolSessionId: "proto-session-test",
|
|
139
|
-
requestedModel,
|
|
140
|
-
effectiveModel: "opus",
|
|
141
|
-
};
|
|
142
|
-
},
|
|
127
|
+
_parentToolUseId?: string,
|
|
128
|
+
) => ({
|
|
129
|
+
acpSessionId: "acp-session-test",
|
|
130
|
+
protocolSessionId: "proto-session-test",
|
|
131
|
+
}),
|
|
143
132
|
);
|
|
144
133
|
|
|
145
134
|
// Spread the real module's exports so transitive importers that pull other
|
|
@@ -212,8 +201,6 @@ describe("executeAcpSpawn - happy path", () => {
|
|
|
212
201
|
const payload = JSON.parse(result.content);
|
|
213
202
|
expect(payload.acpSessionId).toBe("acp-session-test");
|
|
214
203
|
expect(payload.status).toBe("running");
|
|
215
|
-
expect(payload.requestedModel).toBeNull();
|
|
216
|
-
expect(payload.effectiveModel).toBe("opus");
|
|
217
204
|
// The real adapter binary is spawned (no `bun x` wrapper).
|
|
218
205
|
const agentConfigArg = spawnMock.mock.calls[0][1] as { command: string };
|
|
219
206
|
expect(agentConfigArg.command).toBe("claude-agent-acp");
|
|
@@ -227,10 +214,8 @@ describe("executeAcpSpawn - happy path", () => {
|
|
|
227
214
|
|
|
228
215
|
expect(result.isError).toBe(false);
|
|
229
216
|
expect(spawnMock).toHaveBeenCalledTimes(1);
|
|
230
|
-
//
|
|
231
|
-
expect(spawnMock.mock.calls[0][6]).
|
|
232
|
-
parentToolUseId: "toolu_abc123",
|
|
233
|
-
});
|
|
217
|
+
// parentToolUseId is the 7th positional arg to spawn().
|
|
218
|
+
expect(spawnMock.mock.calls[0][6]).toBe("toolu_abc123");
|
|
234
219
|
});
|
|
235
220
|
|
|
236
221
|
test("default-profile fallback when user config is empty", async () => {
|
|
@@ -287,7 +272,7 @@ describe("executeAcpSpawn — input validation", () => {
|
|
|
287
272
|
expect(result.isError).toBe(true);
|
|
288
273
|
expect(result.content).toContain("claude-agent-acp is not on PATH");
|
|
289
274
|
expect(result.content).toContain(
|
|
290
|
-
"bun add -g @agentclientprotocol/claude-agent-acp
|
|
275
|
+
"bun add -g @agentclientprotocol/claude-agent-acp",
|
|
291
276
|
);
|
|
292
277
|
expect(execFileMock).not.toHaveBeenCalled();
|
|
293
278
|
expect(spawnMock).not.toHaveBeenCalled();
|
|
@@ -324,7 +309,7 @@ describe("executeAcpSpawn: sandboxed bun auto-install on missing binary", () =>
|
|
|
324
309
|
expect(spawnMock).toHaveBeenCalledTimes(1);
|
|
325
310
|
const payload = JSON.parse(result.content);
|
|
326
311
|
expect(payload.message).toContain(
|
|
327
|
-
"Installed @agentclientprotocol/claude-agent-acp
|
|
312
|
+
"Installed @agentclientprotocol/claude-agent-acp automatically.",
|
|
328
313
|
);
|
|
329
314
|
// The real binary was spawned with cwd = the project dir and token
|
|
330
315
|
// injected (trusted-binary config, no resolution at spawn).
|
|
@@ -345,7 +330,7 @@ describe("executeAcpSpawn: sandboxed bun auto-install on missing binary", () =>
|
|
|
345
330
|
expect(args).toEqual([
|
|
346
331
|
"add",
|
|
347
332
|
"--global",
|
|
348
|
-
"@agentclientprotocol/claude-agent-acp
|
|
333
|
+
"@agentclientprotocol/claude-agent-acp",
|
|
349
334
|
]);
|
|
350
335
|
});
|
|
351
336
|
|
|
@@ -434,7 +419,7 @@ describe("executeAcpSpawn: sandboxed bun auto-install on missing binary", () =>
|
|
|
434
419
|
expect(result.isError).toBe(true);
|
|
435
420
|
expect(result.content).toContain("claude-agent-acp is not on PATH");
|
|
436
421
|
expect(result.content).toContain(
|
|
437
|
-
"bun add -g @agentclientprotocol/claude-agent-acp
|
|
422
|
+
"bun add -g @agentclientprotocol/claude-agent-acp",
|
|
438
423
|
);
|
|
439
424
|
expect(result.content).toContain("auto-install failed");
|
|
440
425
|
expect(result.content).toContain("EACCES");
|
|
@@ -473,126 +458,6 @@ describe("executeAcpSpawn — per-agent resume hint", () => {
|
|
|
473
458
|
});
|
|
474
459
|
});
|
|
475
460
|
|
|
476
|
-
describe("executeAcpSpawn - model selection", () => {
|
|
477
|
-
test("threads the requested model into manager.spawn's options", async () => {
|
|
478
|
-
const result = await executeAcpSpawn(
|
|
479
|
-
{ agent: "claude", task: "do something", model: "opus" },
|
|
480
|
-
{ ...makeContext(), toolUseId: "toolu_model" },
|
|
481
|
-
);
|
|
482
|
-
|
|
483
|
-
expect(result.isError).toBe(false);
|
|
484
|
-
expect(spawnMock.mock.calls[0][6]).toEqual({
|
|
485
|
-
parentToolUseId: "toolu_model",
|
|
486
|
-
model: "opus",
|
|
487
|
-
});
|
|
488
|
-
const payload = JSON.parse(result.content);
|
|
489
|
-
expect(payload.requestedModel).toBe("opus");
|
|
490
|
-
expect(payload.effectiveModel).toBe("opus");
|
|
491
|
-
expect(payload.message).toContain(
|
|
492
|
-
'The top-level ACP session reports "opus" as its effective model.',
|
|
493
|
-
);
|
|
494
|
-
});
|
|
495
|
-
|
|
496
|
-
test("reports the manager-normalized requested model", async () => {
|
|
497
|
-
const result = await executeAcpSpawn(
|
|
498
|
-
{ agent: "claude", task: "do something", model: " opus " },
|
|
499
|
-
makeContext(),
|
|
500
|
-
);
|
|
501
|
-
|
|
502
|
-
expect(spawnMock.mock.calls[0][6]).toEqual({
|
|
503
|
-
parentToolUseId: undefined,
|
|
504
|
-
model: " opus ",
|
|
505
|
-
});
|
|
506
|
-
expect(JSON.parse(result.content).requestedModel).toBe("opus");
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
test("a null model is treated as omitted", async () => {
|
|
510
|
-
const result = await executeAcpSpawn(
|
|
511
|
-
{ agent: "claude", task: "do something", model: null },
|
|
512
|
-
makeContext(),
|
|
513
|
-
);
|
|
514
|
-
|
|
515
|
-
expect(result.isError).toBe(false);
|
|
516
|
-
const options = spawnMock.mock.calls[0][6] as { model?: string };
|
|
517
|
-
expect(options.model).toBeUndefined();
|
|
518
|
-
});
|
|
519
|
-
|
|
520
|
-
test("a modelWarning from the spawn is relayed in the result message", async () => {
|
|
521
|
-
spawnMock.mockImplementationOnce(async () => ({
|
|
522
|
-
acpSessionId: "acp-session-test",
|
|
523
|
-
protocolSessionId: "proto-session-test",
|
|
524
|
-
requestedModel: "nope",
|
|
525
|
-
effectiveModel: "opus",
|
|
526
|
-
modelWarning: "Unknown model: nope",
|
|
527
|
-
}));
|
|
528
|
-
|
|
529
|
-
const result = await executeAcpSpawn(
|
|
530
|
-
{ agent: "claude", task: "do something", model: "nope" },
|
|
531
|
-
makeContext(),
|
|
532
|
-
);
|
|
533
|
-
|
|
534
|
-
expect(result.isError).toBe(false);
|
|
535
|
-
const payload = JSON.parse(result.content);
|
|
536
|
-
expect(payload.message).toContain(
|
|
537
|
-
"The requested model was not applied: Unknown model: nope",
|
|
538
|
-
);
|
|
539
|
-
expect(payload.requestedModel).toBe("nope");
|
|
540
|
-
expect(payload.effectiveModel).toBe("opus");
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
test("the note relays a no-selector warning without calling it a refusal", async () => {
|
|
544
|
-
spawnMock.mockImplementationOnce(async () => ({
|
|
545
|
-
acpSessionId: "acp-session-test",
|
|
546
|
-
protocolSessionId: "proto-session-test",
|
|
547
|
-
requestedModel: "opus",
|
|
548
|
-
modelWarning:
|
|
549
|
-
'Agent "claude" does not support model selection, so the session is running on the agent\'s own model.',
|
|
550
|
-
}));
|
|
551
|
-
|
|
552
|
-
const result = await executeAcpSpawn(
|
|
553
|
-
{ agent: "claude", task: "do something", model: "opus" },
|
|
554
|
-
makeContext(),
|
|
555
|
-
);
|
|
556
|
-
|
|
557
|
-
const payload = JSON.parse(result.content);
|
|
558
|
-
expect(payload.message).toContain("does not support model selection");
|
|
559
|
-
expect(payload.message).not.toContain("refused");
|
|
560
|
-
});
|
|
561
|
-
|
|
562
|
-
test("no model note when the spawn reports no warning", async () => {
|
|
563
|
-
const result = await executeAcpSpawn(
|
|
564
|
-
{ agent: "claude", task: "do something", model: "opus" },
|
|
565
|
-
makeContext(),
|
|
566
|
-
);
|
|
567
|
-
|
|
568
|
-
expect(result.isError).toBe(false);
|
|
569
|
-
const payload = JSON.parse(result.content);
|
|
570
|
-
expect(payload.message).not.toContain(
|
|
571
|
-
"The requested model was not applied",
|
|
572
|
-
);
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
test("reports when the adapter does not identify the effective model", async () => {
|
|
576
|
-
spawnMock.mockImplementationOnce(async () => ({
|
|
577
|
-
acpSessionId: "acp-session-test",
|
|
578
|
-
protocolSessionId: "proto-session-test",
|
|
579
|
-
requestedModel: "sonnet",
|
|
580
|
-
}));
|
|
581
|
-
|
|
582
|
-
const result = await executeAcpSpawn(
|
|
583
|
-
{ agent: "claude", task: "do something", model: "sonnet" },
|
|
584
|
-
makeContext(),
|
|
585
|
-
);
|
|
586
|
-
|
|
587
|
-
const payload = JSON.parse(result.content);
|
|
588
|
-
expect(payload.requestedModel).toBe("sonnet");
|
|
589
|
-
expect(payload.effectiveModel).toBeNull();
|
|
590
|
-
expect(payload.message).toContain(
|
|
591
|
-
"The top-level ACP session did not report an effective model.",
|
|
592
|
-
);
|
|
593
|
-
});
|
|
594
|
-
});
|
|
595
|
-
|
|
596
461
|
// ---------------------------------------------------------------------------
|
|
597
462
|
// executeAcpSpawn — CLAUDE_CODE_OAUTH_TOKEN env injection + preflight
|
|
598
463
|
//
|
package/src/tools/acp/spawn.ts
CHANGED
|
@@ -37,7 +37,6 @@ export const acpSpawnInputSchema = z.looseObject({
|
|
|
37
37
|
agent: nullAsOmitted(z.string()),
|
|
38
38
|
task: nullAsOmitted(z.string()),
|
|
39
39
|
cwd: nullAsOmitted(z.string()),
|
|
40
|
-
model: nullAsOmitted(z.string()),
|
|
41
40
|
});
|
|
42
41
|
|
|
43
42
|
/**
|
|
@@ -67,7 +66,6 @@ export async function executeAcpSpawn(
|
|
|
67
66
|
}
|
|
68
67
|
const agent = parsedInput.data.agent || "claude";
|
|
69
68
|
const task = parsedInput.data.task;
|
|
70
|
-
const model = parsedInput.data.model;
|
|
71
69
|
|
|
72
70
|
if (!task) {
|
|
73
71
|
return { content: '"task" is required.', isError: true };
|
|
@@ -126,20 +124,14 @@ export async function executeAcpSpawn(
|
|
|
126
124
|
// Recheck: the auto-install and the agent-env preparation above are both
|
|
127
125
|
// awaits, and this is the point a long-lived subprocess starts.
|
|
128
126
|
throwIfCancelled(context);
|
|
129
|
-
const {
|
|
130
|
-
acpSessionId,
|
|
131
|
-
protocolSessionId,
|
|
132
|
-
requestedModel,
|
|
133
|
-
effectiveModel,
|
|
134
|
-
modelWarning,
|
|
135
|
-
} = await manager.spawn(
|
|
127
|
+
const { acpSessionId, protocolSessionId } = await manager.spawn(
|
|
136
128
|
agent,
|
|
137
129
|
agentConfig,
|
|
138
130
|
task,
|
|
139
131
|
cwd,
|
|
140
132
|
context.conversationId,
|
|
141
133
|
sendToClient,
|
|
142
|
-
|
|
134
|
+
context.toolUseId,
|
|
143
135
|
// The manager rechecks after its own protocol handshake and session
|
|
144
136
|
// creation, so a turn stopped in that window tears the child process
|
|
145
137
|
// down instead of handing it the task.
|
|
@@ -158,26 +150,16 @@ export async function executeAcpSpawn(
|
|
|
158
150
|
const installNote = autoInstalledPackage
|
|
159
151
|
? ` Installed ${autoInstalledPackage} automatically.`
|
|
160
152
|
: "";
|
|
161
|
-
// Relayed verbatim: the warning already distinguishes an adapter with no
|
|
162
|
-
// selector from one that refused the value.
|
|
163
|
-
const modelNote = modelWarning
|
|
164
|
-
? ` The requested model was not applied: ${modelWarning}`
|
|
165
|
-
: "";
|
|
166
|
-
const effectiveModelNote = effectiveModel
|
|
167
|
-
? ` The top-level ACP session reports "${effectiveModel}" as its effective model.`
|
|
168
|
-
: " The top-level ACP session did not report an effective model.";
|
|
169
153
|
const payload = JSON.stringify({
|
|
170
154
|
acpSessionId,
|
|
171
155
|
protocolSessionId,
|
|
172
156
|
agent,
|
|
173
157
|
cwd,
|
|
174
|
-
requestedModel: requestedModel ?? null,
|
|
175
|
-
effectiveModel: effectiveModel ?? null,
|
|
176
158
|
status: "running",
|
|
177
159
|
message:
|
|
178
160
|
`ACP agent "${agent}" spawned (session: ${protocolSessionId}). ` +
|
|
179
161
|
`Results stream back via SSE. You will be notified when it completes.` +
|
|
180
|
-
`${installNote}${
|
|
162
|
+
`${installNote}${resumeHint}`,
|
|
181
163
|
});
|
|
182
164
|
|
|
183
165
|
return { content: payload, isError: false };
|
package/src/tools/acp/status.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
3
|
import { getAcpSessionManager } from "../../acp/index.js";
|
|
4
|
-
import type { AcpSessionState } from "../../acp/types.js";
|
|
5
4
|
import {
|
|
6
5
|
invalidToolInputResult,
|
|
7
6
|
nullAsOmitted,
|
|
@@ -17,40 +16,6 @@ export const acpStatusInputSchema = z.looseObject({
|
|
|
17
16
|
acp_session_id: nullAsOmitted(z.string()),
|
|
18
17
|
});
|
|
19
18
|
|
|
20
|
-
/**
|
|
21
|
-
* The session fields worth spending LLM context on. An allowlist rather than
|
|
22
|
-
* an omission: `availableModels` is a picker for the human surfaces (HTTP and
|
|
23
|
-
* SSE) that says nothing the agent can act on, and a field added to
|
|
24
|
-
* `AcpSessionState` for those surfaces should not reach this one by default.
|
|
25
|
-
* `model` stays: which model a session is running on is answerable.
|
|
26
|
-
*/
|
|
27
|
-
function projectSession(state: AcpSessionState) {
|
|
28
|
-
return {
|
|
29
|
-
id: state.id,
|
|
30
|
-
agentId: state.agentId,
|
|
31
|
-
acpSessionId: state.acpSessionId,
|
|
32
|
-
parentConversationId: state.parentConversationId,
|
|
33
|
-
status: state.status,
|
|
34
|
-
startedAt: state.startedAt,
|
|
35
|
-
completedAt: state.completedAt,
|
|
36
|
-
error: state.error,
|
|
37
|
-
stopReason: state.stopReason,
|
|
38
|
-
task: state.task,
|
|
39
|
-
parentToolUseId: state.parentToolUseId,
|
|
40
|
-
authErrorCode: state.authErrorCode,
|
|
41
|
-
authErrorCredential: state.authErrorCredential,
|
|
42
|
-
latestUsage: state.latestUsage,
|
|
43
|
-
model: state.model,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Projects either shape `getStatus` answers with. */
|
|
48
|
-
function projectStatus(status: AcpSessionState | AcpSessionState[]): unknown {
|
|
49
|
-
return Array.isArray(status)
|
|
50
|
-
? status.map(projectSession)
|
|
51
|
-
: projectSession(status);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
19
|
export async function executeAcpStatus(
|
|
55
20
|
input: Record<string, unknown>,
|
|
56
21
|
_context: ToolContext,
|
|
@@ -64,8 +29,9 @@ export async function executeAcpStatus(
|
|
|
64
29
|
|
|
65
30
|
try {
|
|
66
31
|
if (acpSessionId) {
|
|
32
|
+
const state = manager.getStatus(acpSessionId);
|
|
67
33
|
return {
|
|
68
|
-
content: JSON.stringify(
|
|
34
|
+
content: JSON.stringify(state),
|
|
69
35
|
isError: false,
|
|
70
36
|
};
|
|
71
37
|
}
|
|
@@ -76,10 +42,7 @@ export async function executeAcpStatus(
|
|
|
76
42
|
return { content: "No ACP sessions found.", isError: false };
|
|
77
43
|
}
|
|
78
44
|
|
|
79
|
-
return {
|
|
80
|
-
content: JSON.stringify(projectStatus(allStates)),
|
|
81
|
-
isError: false,
|
|
82
|
-
};
|
|
45
|
+
return { content: JSON.stringify(allStates), isError: false };
|
|
83
46
|
} catch (err) {
|
|
84
47
|
const msg = err instanceof Error ? err.message : String(err);
|
|
85
48
|
return { content: msg, isError: true };
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* the proxy resolver, which forwards the call to the connected client.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { formatDesktopAppRequired } from "../capability-offer.js";
|
|
9
8
|
import { throwIfCancelled } from "../shared/abort.js";
|
|
10
9
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
11
10
|
|
|
@@ -33,7 +32,7 @@ export function forwardAppControlProxyTool(
|
|
|
33
32
|
}
|
|
34
33
|
if (!context.proxyToolResolver) {
|
|
35
34
|
return Promise.resolve({
|
|
36
|
-
content:
|
|
35
|
+
content: `Cannot execute ${toolName}: no proxy resolver available. This tool requires a connected client.`,
|
|
37
36
|
isError: true,
|
|
38
37
|
});
|
|
39
38
|
}
|
|
@@ -4,26 +4,11 @@ import {
|
|
|
4
4
|
appendLoggedInBrowserOffer,
|
|
5
5
|
CHROME_WEB_STORE_INSTALL_URL,
|
|
6
6
|
DESKTOP_APP_DOWNLOAD_URL,
|
|
7
|
-
formatDesktopAppRequired,
|
|
8
7
|
formatLoggedInBrowserOffer,
|
|
9
8
|
isPhoneSurface,
|
|
10
9
|
shouldOfferLoggedInBrowser,
|
|
11
10
|
} from "./capability-offer.js";
|
|
12
11
|
|
|
13
|
-
describe("formatDesktopAppRequired", () => {
|
|
14
|
-
test("offers a direct desktop-app download and retry step", () => {
|
|
15
|
-
const message = formatDesktopAppRequired("shell");
|
|
16
|
-
|
|
17
|
-
expect(message).toContain(
|
|
18
|
-
"The Vellum desktop app is needed to run commands on your computer",
|
|
19
|
-
);
|
|
20
|
-
expect(message).toContain(DESKTOP_APP_DOWNLOAD_URL);
|
|
21
|
-
expect(message).toContain("Open it, then retry.");
|
|
22
|
-
expect(message).not.toContain("client");
|
|
23
|
-
expect(message).not.toContain("daemon");
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
|
|
27
12
|
describe("isPhoneSurface", () => {
|
|
28
13
|
test("is true for iOS transport and mobile client OS", () => {
|
|
29
14
|
expect(isPhoneSurface({ transportInterface: "ios" })).toBe(true);
|
|
@@ -64,9 +49,7 @@ describe("shouldOfferLoggedInBrowser", () => {
|
|
|
64
49
|
expect(shouldOfferLoggedInBrowser('Invalid browser_mode "bogus"')).toBe(
|
|
65
50
|
false,
|
|
66
51
|
);
|
|
67
|
-
expect(shouldOfferLoggedInBrowser("url must use http or https")).toBe(
|
|
68
|
-
false,
|
|
69
|
-
);
|
|
52
|
+
expect(shouldOfferLoggedInBrowser("url must use http or https")).toBe(false);
|
|
70
53
|
});
|
|
71
54
|
});
|
|
72
55
|
|
|
@@ -88,7 +71,6 @@ describe("formatLoggedInBrowserOffer", () => {
|
|
|
88
71
|
});
|
|
89
72
|
expect(offer).toContain("no in-app browser");
|
|
90
73
|
expect(offer).toContain("Do not describe a browser panel");
|
|
91
|
-
expect(offer).toContain("Mac or Windows PC");
|
|
92
74
|
expect(offer).toContain(DESKTOP_APP_DOWNLOAD_URL);
|
|
93
75
|
expect(offer).toContain(CHROME_WEB_STORE_INSTALL_URL);
|
|
94
76
|
});
|
|
@@ -96,9 +78,7 @@ describe("formatLoggedInBrowserOffer", () => {
|
|
|
96
78
|
|
|
97
79
|
describe("appendLoggedInBrowserOffer", () => {
|
|
98
80
|
test("appends the offer once", () => {
|
|
99
|
-
const once = appendLoggedInBrowserOffer(
|
|
100
|
-
"Error: Navigation failed: timeout",
|
|
101
|
-
);
|
|
81
|
+
const once = appendLoggedInBrowserOffer("Error: Navigation failed: timeout");
|
|
102
82
|
expect(once).toContain("Error: Navigation failed: timeout");
|
|
103
83
|
expect(once).toContain(DESKTOP_APP_DOWNLOAD_URL);
|
|
104
84
|
const twice = appendLoggedInBrowserOffer(once);
|
|
@@ -7,22 +7,7 @@ export const DESKTOP_APP_DOWNLOAD_URL = "https://www.vellum.ai/downloads";
|
|
|
7
7
|
export const CHROME_WEB_STORE_INSTALL_URL =
|
|
8
8
|
"https://chromewebstore.google.com/detail/vellum-assistant-browser/hphbdmpffeigpcdjkckleobjmhhokpne";
|
|
9
9
|
|
|
10
|
-
export const DESKTOP_APP_INSTALL_HINT = `
|
|
11
|
-
|
|
12
|
-
export type DesktopAppCapability = "files" | "screen" | "shell" | "apps";
|
|
13
|
-
|
|
14
|
-
const DESKTOP_APP_CAPABILITY_ACTION: Record<DesktopAppCapability, string> = {
|
|
15
|
-
files: "access files on your computer",
|
|
16
|
-
screen: "view or control your screen",
|
|
17
|
-
shell: "run commands on your computer",
|
|
18
|
-
apps: "control apps on your computer",
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export function formatDesktopAppRequired(
|
|
22
|
-
capability: DesktopAppCapability,
|
|
23
|
-
): string {
|
|
24
|
-
return `Error: The Vellum desktop app is needed to ${DESKTOP_APP_CAPABILITY_ACTION[capability]}. ${DESKTOP_APP_INSTALL_HINT}`;
|
|
25
|
-
}
|
|
10
|
+
export const DESKTOP_APP_INSTALL_HINT = `Install the Vellum desktop app: ${DESKTOP_APP_DOWNLOAD_URL}`;
|
|
26
11
|
|
|
27
12
|
/** User-facing install step for status userActions and command-failure hints. */
|
|
28
13
|
export const CHROME_EXTENSION_INSTALL_HINT = `Install the Vellum Assistant Chrome extension from the Chrome Web Store: ${CHROME_WEB_STORE_INSTALL_URL}`;
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { RiskLevel } from "../../permissions/types.js";
|
|
11
|
-
import { formatDesktopAppRequired } from "../capability-offer.js";
|
|
12
11
|
import type {
|
|
13
12
|
ToolContext,
|
|
14
13
|
ToolDefinition,
|
|
@@ -32,7 +31,7 @@ function proxyExecute(toolName: string) {
|
|
|
32
31
|
): Promise<ToolExecutionResult> => {
|
|
33
32
|
if (!context.proxyToolResolver) {
|
|
34
33
|
return {
|
|
35
|
-
content:
|
|
34
|
+
content: `No proxy resolver configured for proxy tool "${toolName}". This tool requires a connected desktop client.`,
|
|
36
35
|
isError: true,
|
|
37
36
|
};
|
|
38
37
|
}
|
|
@@ -457,8 +456,7 @@ export const computerUseObserveTool = {
|
|
|
457
456
|
type: "integer",
|
|
458
457
|
minimum: 1,
|
|
459
458
|
maximum: 4294967295,
|
|
460
|
-
description:
|
|
461
|
-
"macOS only: capture this native CGWindowID instead of the desktop, including only its accessibility tree. Obtain a current native window ID first; do not guess or use a browser tab ID. Applies to this observation only, not subsequent actions. Requires a desktop helper with window-capture support. Screenshot coordinates are window-relative; use accessibility element IDs for later actions, not desktop scaling.",
|
|
459
|
+
description: "macOS only: capture this native CGWindowID instead of the desktop, including only its accessibility tree. Obtain a current native window ID first; do not guess or use a browser tab ID. Applies to this observation only, not subsequent actions. Requires a desktop helper with window-capture support. Screenshot coordinates are window-relative; use accessibility element IDs for later actions, not desktop scaling.",
|
|
462
460
|
},
|
|
463
461
|
target_client_id: {
|
|
464
462
|
type: "string",
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* the proxy resolver, which forwards the call to the connected desktop client.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { formatDesktopAppRequired } from "../capability-offer.js";
|
|
9
8
|
import { throwIfCancelled } from "../shared/abort.js";
|
|
10
9
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
11
10
|
|
|
@@ -46,7 +45,7 @@ export function forwardComputerUseProxyTool(
|
|
|
46
45
|
}
|
|
47
46
|
if (!context.proxyToolResolver) {
|
|
48
47
|
return Promise.resolve({
|
|
49
|
-
content:
|
|
48
|
+
content: `Cannot execute ${toolName}: no proxy resolver available. This tool requires a connected desktop client.`,
|
|
50
49
|
isError: true,
|
|
51
50
|
});
|
|
52
51
|
}
|
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
} from "@vellumai/credential-storage";
|
|
21
21
|
import type { CredentialRecord } from "@vellumai/service-contracts/credential-rpc";
|
|
22
22
|
|
|
23
|
-
import { createCesHttpRecordBackendIfConfigured } from "../../security/ces-http-record-backend.js";
|
|
24
23
|
import type { CredentialRecordBackend } from "../../security/ces-rpc-record-backend.js";
|
|
25
24
|
import { getLogger } from "../../util/logger.js";
|
|
26
25
|
import type { CredentialInjectionTemplate } from "./policy-types.js";
|
|
@@ -56,11 +55,6 @@ const CES_MEMORY_PATH = "ces-in-memory-credential-metadata";
|
|
|
56
55
|
let _store: StaticCredentialMetadataStore | undefined;
|
|
57
56
|
let _overridePath: string | null = null;
|
|
58
57
|
let _recordBackend: CredentialRecordBackend | undefined;
|
|
59
|
-
/**
|
|
60
|
-
* Test override for the CES HTTP listing fallback. `undefined` uses the
|
|
61
|
-
* production factory. `null` disables HTTP fallback.
|
|
62
|
-
*/
|
|
63
|
-
let _httpRecordBackendOverride: CredentialRecordBackend | null | undefined;
|
|
64
58
|
let _cesRecordsLoaded = false;
|
|
65
59
|
let _cesLoad: Promise<void> | undefined;
|
|
66
60
|
let _cesLoadGeneration = 0;
|
|
@@ -261,93 +255,6 @@ export function listCredentialMetadata(): CredentialMetadata[] {
|
|
|
261
255
|
return getStore().list() as CredentialMetadata[];
|
|
262
256
|
}
|
|
263
257
|
|
|
264
|
-
export type CredentialRecordListResult = {
|
|
265
|
-
records: CredentialMetadata[];
|
|
266
|
-
unreachable: boolean;
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
type ListedCredentialRecords = Array<{
|
|
270
|
-
account: string;
|
|
271
|
-
record: CredentialRecord;
|
|
272
|
-
}>;
|
|
273
|
-
|
|
274
|
-
function backendIsAvailable(backend: CredentialRecordBackend): boolean {
|
|
275
|
-
try {
|
|
276
|
-
return backend.isAvailable();
|
|
277
|
-
} catch {
|
|
278
|
-
return false;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
async function listFromRecordBackend(
|
|
283
|
-
backend: CredentialRecordBackend,
|
|
284
|
-
): Promise<ListedCredentialRecords | null> {
|
|
285
|
-
if (!backendIsAvailable(backend)) {
|
|
286
|
-
return null;
|
|
287
|
-
}
|
|
288
|
-
return backend.list();
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function resolveHttpRecordBackend(): CredentialRecordBackend | null {
|
|
292
|
-
if (_httpRecordBackendOverride !== undefined) {
|
|
293
|
-
return _httpRecordBackendOverride;
|
|
294
|
-
}
|
|
295
|
-
return createCesHttpRecordBackendIfConfigured();
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
async function listFromHttpFallback(): Promise<ListedCredentialRecords | null> {
|
|
299
|
-
const httpBackend = resolveHttpRecordBackend();
|
|
300
|
-
if (!httpBackend) {
|
|
301
|
-
return null;
|
|
302
|
-
}
|
|
303
|
-
return listFromRecordBackend(httpBackend);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Live catalog from the credential record backend. Does not read the
|
|
308
|
-
* daemon in-process cache, so an outage cannot be mistaken for an empty
|
|
309
|
-
* vault. `unreachable` is true when the backend is missing, down, or
|
|
310
|
-
* the list RPC fails, and CES HTTP failover is also unavailable.
|
|
311
|
-
*
|
|
312
|
-
* When the attached backend is CES RPC (or none is attached), listing
|
|
313
|
-
* fails over to CES HTTP in containerized deployments so a down RPC
|
|
314
|
-
* socket does not hide a healthy vault sidecar. A successful empty
|
|
315
|
-
* catalog (`[]`) does not fall through to HTTP.
|
|
316
|
-
*
|
|
317
|
-
* The file-backed test store is the catalog when a test override path is set.
|
|
318
|
-
*/
|
|
319
|
-
export async function listCredentialRecordsLive(): Promise<CredentialRecordListResult> {
|
|
320
|
-
if (_overridePath) {
|
|
321
|
-
return {
|
|
322
|
-
records: getStore().list() as CredentialMetadata[],
|
|
323
|
-
unreachable: false,
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
if (_recordBackend) {
|
|
327
|
-
const remote = await listFromRecordBackend(_recordBackend);
|
|
328
|
-
if (remote !== null) {
|
|
329
|
-
return {
|
|
330
|
-
records: remote.map((entry) => entry.record as CredentialMetadata),
|
|
331
|
-
unreachable: false,
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
if (_recordBackend.name !== "ces-rpc") {
|
|
335
|
-
return { records: [], unreachable: true };
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
const httpRemote = await listFromHttpFallback();
|
|
339
|
-
if (httpRemote !== null) {
|
|
340
|
-
log.warn(
|
|
341
|
-
"CES RPC credential record list unavailable. Failing over to CES HTTP.",
|
|
342
|
-
);
|
|
343
|
-
return {
|
|
344
|
-
records: httpRemote.map((entry) => entry.record as CredentialMetadata),
|
|
345
|
-
unreachable: false,
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
return { records: [], unreachable: true };
|
|
349
|
-
}
|
|
350
|
-
|
|
351
258
|
/**
|
|
352
259
|
* Delete metadata for a credential.
|
|
353
260
|
*/
|
|
@@ -380,10 +287,3 @@ export function _setMetadataPath(path: string | null): void {
|
|
|
380
287
|
}
|
|
381
288
|
}
|
|
382
289
|
}
|
|
383
|
-
|
|
384
|
-
/** @internal Test-only: override the CES HTTP listing fallback. */
|
|
385
|
-
export function _setHttpRecordBackendForTests(
|
|
386
|
-
backend: CredentialRecordBackend | null | undefined,
|
|
387
|
-
): void {
|
|
388
|
-
_httpRecordBackendOverride = backend;
|
|
389
|
-
}
|
|
@@ -71,9 +71,8 @@ describe("host_file_edit cross-client guards", () => {
|
|
|
71
71
|
);
|
|
72
72
|
expect(result.isError).toBe(true);
|
|
73
73
|
expect(result.content).toContain(
|
|
74
|
-
"
|
|
74
|
+
"no client with host_file capability is connected",
|
|
75
75
|
);
|
|
76
|
-
expect(result.content).toContain("https://www.vellum.ai/downloads");
|
|
77
76
|
});
|
|
78
77
|
|
|
79
78
|
test("returns 'specified client disconnected' error when targetClientId set but proxy unavailable on web", async () => {
|
|
@@ -4,7 +4,7 @@ import { supportsHostProxy } from "../../channels/types.js";
|
|
|
4
4
|
import { HostFileProxy } from "../../daemon/host-file-proxy.js";
|
|
5
5
|
import { RiskLevel } from "../../permissions/types.js";
|
|
6
6
|
import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
|
|
7
|
-
import {
|
|
7
|
+
import { desktopClientName } from "../client-os.js";
|
|
8
8
|
import { FileSystemOps } from "../shared/filesystem/file-ops-service.js";
|
|
9
9
|
import { formatEditDiff } from "../shared/filesystem/format-diff.js";
|
|
10
10
|
import { hostPolicy } from "../shared/filesystem/path-policy.js";
|
|
@@ -115,7 +115,7 @@ export const hostFileEditTool = {
|
|
|
115
115
|
!HostFileProxy.instance.isAvailable()
|
|
116
116
|
) {
|
|
117
117
|
return {
|
|
118
|
-
content:
|
|
118
|
+
content: `Error: no client with host_file capability is connected. Connect a ${desktopClientName(context)} client to use host_file from a non-desktop interface.`,
|
|
119
119
|
isError: true,
|
|
120
120
|
};
|
|
121
121
|
}
|
|
@@ -67,9 +67,8 @@ describe("host_file_read cross-client guards", () => {
|
|
|
67
67
|
);
|
|
68
68
|
expect(result.isError).toBe(true);
|
|
69
69
|
expect(result.content).toContain(
|
|
70
|
-
"
|
|
70
|
+
"no client with host_file capability is connected",
|
|
71
71
|
);
|
|
72
|
-
expect(result.content).toContain("https://www.vellum.ai/downloads");
|
|
73
72
|
});
|
|
74
73
|
|
|
75
74
|
test("returns 'specified client disconnected' error when targetClientId set but proxy unavailable on web", async () => {
|
|
@@ -6,7 +6,7 @@ import { supportsHostProxy } from "../../channels/types.js";
|
|
|
6
6
|
import { HostFileProxy } from "../../daemon/host-file-proxy.js";
|
|
7
7
|
import { RiskLevel } from "../../permissions/types.js";
|
|
8
8
|
import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
|
|
9
|
-
import {
|
|
9
|
+
import { desktopClientName } from "../client-os.js";
|
|
10
10
|
import {
|
|
11
11
|
AUDIO_EXTENSIONS,
|
|
12
12
|
readAudioFile,
|
|
@@ -121,7 +121,7 @@ export const hostFileReadTool = {
|
|
|
121
121
|
!HostFileProxy.instance.isAvailable()
|
|
122
122
|
) {
|
|
123
123
|
return {
|
|
124
|
-
content:
|
|
124
|
+
content: `Error: no client with host_file capability is connected. Connect a ${desktopClientName(context)} client to use host_file from a non-desktop interface.`,
|
|
125
125
|
isError: true,
|
|
126
126
|
};
|
|
127
127
|
}
|