@vellumai/assistant 0.12.1 → 0.12.2-staging.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 +4 -0
- package/ARCHITECTURE.md +20 -21
- package/docs/architecture/turn-actor.md +15 -8
- package/docs/guardian-request-flow.md +16 -0
- package/openapi.yaml +327 -52
- package/package.json +3 -1
- package/scripts/smoke-desktop-window-theme.ts +186 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
- package/src/__tests__/anthropic-provider.test.ts +0 -63
- package/src/__tests__/app-compiler.test.ts +6 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
- package/src/__tests__/app-dir-path-guard.test.ts +1 -3
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +6 -7
- package/src/__tests__/assistant-event-hub.test.ts +44 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
- package/src/__tests__/computer-use-tools.test.ts +19 -7
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +28 -29
- package/src/__tests__/config-watcher.test.ts +23 -8
- 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 +26 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
- package/src/__tests__/conversation-queue.test.ts +48 -207
- package/src/__tests__/conversation-retry-discard.test.ts +54 -1
- package/src/__tests__/conversation-skill-tools.test.ts +27 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-title-service.test.ts +14 -10
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
- package/src/__tests__/credential-record-retire.test.ts +171 -1
- package/src/__tests__/credential-routes.test.ts +212 -3
- package/src/__tests__/credential-security-invariants.test.ts +4 -2
- package/src/__tests__/cu-unified-flow.test.ts +8 -2
- package/src/__tests__/document-sync-tags.test.ts +25 -0
- package/src/__tests__/drain-kick-guard.test.ts +0 -2
- package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/git-porcelain.test.ts +47 -0
- package/src/__tests__/heartbeat-service.test.ts +56 -40
- package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
- package/src/__tests__/host-bash-proxy.test.ts +26 -45
- package/src/__tests__/host-browser-proxy.test.ts +6 -17
- package/src/__tests__/host-cu-proxy.test.ts +539 -0
- package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
- package/src/__tests__/host-file-proxy.test.ts +11 -23
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
- package/src/__tests__/list-messages-camera-frame.test.ts +121 -0
- package/src/__tests__/llm-catalog-parity.test.ts +25 -0
- package/src/__tests__/mcp-auth-routes.test.ts +6 -9
- package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
- package/src/__tests__/mcp-health-check.test.ts +8 -11
- package/src/__tests__/mcp-list-plugin-servers.test.ts +8 -10
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
- package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +355 -548
- package/src/__tests__/model-intents.test.ts +3 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
- package/src/__tests__/oauth-commands-routes.test.ts +113 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +18 -0
- package/src/__tests__/openai-provider.test.ts +1 -0
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +8 -16
- package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +14 -0
- package/src/__tests__/qdrant-manager.test.ts +132 -0
- package/src/__tests__/resolve-app.test.ts +135 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +229 -6
- package/src/__tests__/script-proxy-certs.test.ts +35 -0
- package/src/__tests__/service-account-token.test.ts +247 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/source-fingerprint.test.ts +184 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +19 -3
- package/src/__tests__/subagent-tools.test.ts +3 -2
- package/src/__tests__/telephony-tts-guard.test.ts +38 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/unicode.test.ts +13 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
- package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
- package/src/__tests__/workspace-git-service.test.ts +26 -0
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
- package/src/acp/__tests__/agent-process.test.ts +258 -4
- package/src/acp/__tests__/auth-required.test.ts +96 -0
- package/src/acp/__tests__/client-handler.test.ts +90 -2
- package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
- package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
- package/src/acp/__tests__/session-manager.test.ts +895 -4
- package/src/acp/agent-process.test.ts +4 -1
- package/src/acp/agent-process.ts +96 -10
- package/src/acp/auth-required.ts +50 -1
- package/src/acp/auto-install.test.ts +9 -7
- package/src/acp/client-handler.ts +16 -3
- package/src/acp/model-config.test.ts +166 -0
- package/src/acp/model-config.ts +138 -0
- package/src/acp/resolve-agent.test.ts +220 -6
- package/src/acp/resolve-agent.ts +88 -23
- package/src/acp/session-manager.test.ts +196 -3
- package/src/acp/session-manager.ts +441 -18
- package/src/acp/types.ts +50 -5
- package/src/agent/loop.ts +1 -0
- package/src/api/events/acp-session-model-update.test.ts +88 -0
- package/src/api/events/acp-session-model-update.ts +46 -0
- package/src/api/events/app-files-changed.ts +4 -3
- package/src/api/events/notification-intent.ts +2 -0
- package/src/api/events/user-message-echo.ts +7 -1
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -0
- package/src/apps/app-store.ts +1 -1
- package/src/apps/resolve-app.ts +81 -0
- package/src/apps/source-fingerprint.ts +266 -0
- package/src/avatar/identity-avatar.ts +7 -2
- package/src/bundler/app-compiler.ts +15 -0
- package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
- package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
- package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
- package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
- package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
- package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +4 -4
- package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
- package/src/calls/__tests__/voice-control-protocol.test.ts +58 -25
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
- package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
- package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
- package/src/calls/__tests__/voice-session-bridge.test.ts +37 -1
- package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
- package/src/calls/barge-in-guard.ts +118 -0
- package/src/calls/call-constants.ts +24 -4
- package/src/calls/call-controller.ts +499 -199
- package/src/calls/call-transport.ts +16 -0
- package/src/calls/media-stream-output.ts +32 -0
- package/src/calls/media-stream-server.ts +82 -30
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/{live-voice → calls}/progress-narration.ts +2 -2
- package/src/calls/resolve-call-tts-provider.ts +33 -2
- package/src/calls/tts-call-strategy.ts +9 -5
- package/src/calls/types.ts +2 -0
- package/src/calls/voice-control-protocol.ts +53 -21
- package/src/calls/voice-leg-coordinator.ts +189 -0
- package/src/calls/voice-progress-cadence.ts +423 -0
- package/src/calls/voice-session-bridge.ts +59 -46
- package/src/calls/voice-triage-escalate.ts +175 -56
- package/src/cli/commands/__tests__/apps.test.ts +245 -0
- package/src/cli/commands/__tests__/bash.test.ts +53 -0
- package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
- package/src/cli/commands/apps.help.ts +67 -13
- package/src/cli/commands/apps.ts +183 -0
- package/src/cli/commands/bash.help.ts +8 -13
- package/src/cli/commands/bash.ts +7 -25
- package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
- package/src/cli/commands/channels/index.help.ts +70 -2
- package/src/cli/commands/channels/index.ts +16 -3
- package/src/cli/commands/channels/send.ts +128 -0
- package/src/cli/commands/credentials.help.ts +6 -2
- 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 +5 -1
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +103 -90
- package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
- package/src/config/__tests__/platform-identity.test.ts +255 -0
- package/src/config/__tests__/platform-rehydration.test.ts +99 -9
- package/src/config/acp-agent-write.ts +43 -0
- package/src/config/acp-defaults.test.ts +13 -3
- package/src/config/acp-defaults.ts +23 -6
- package/src/config/acp-schema.test.ts +81 -0
- package/src/config/acp-schema.ts +30 -2
- package/src/config/bundled-skills/acp/SKILL.md +22 -14
- package/src/config/bundled-skills/acp/TOOLS.json +5 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +20 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +99 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-sequence.ts +12 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -1
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -1
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -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 +67 -139
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -1
- package/src/config/bundled-skills/schedule/SKILL.md +3 -4
- package/src/config/bundled-skills/screen-annotation/SKILL.md +8 -1
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +6 -2
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +24 -12
- package/src/config/loader.ts +1 -0
- package/src/config/memory-v3-gate.test.ts +31 -0
- package/src/config/memory-v3-gate.ts +20 -16
- package/src/config/platform-identity.ts +201 -0
- package/src/config/platform-rehydration.ts +11 -27
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
- package/src/config/schemas/__tests__/voice.test.ts +148 -0
- package/src/config/schemas/calls.ts +1 -28
- package/src/config/schemas/live-voice.ts +1 -173
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +10 -0
- package/src/config/schemas/services.ts +8 -0
- package/src/config/schemas/skills.ts +0 -14
- package/src/config/schemas/voice.ts +150 -0
- package/src/credential-execution/process-manager.test.ts +18 -19
- package/src/credential-health/credential-health-service.ts +11 -17
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -121
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +4 -1
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
- package/src/daemon/app-change-notify.ts +45 -0
- package/src/daemon/config-watcher.ts +13 -194
- package/src/daemon/conversation-error.ts +3 -2
- package/src/daemon/conversation-media-retry.ts +2 -1
- package/src/daemon/conversation-process.ts +35 -64
- package/src/daemon/conversation-runtime-assembly.ts +2 -1
- package/src/daemon/conversation-skill-tools.ts +13 -31
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +15 -9
- package/src/daemon/conversation-tool-setup.ts +37 -43
- package/src/daemon/conversation.ts +0 -3
- package/src/daemon/dictation-profile-store.ts +2 -1
- package/src/daemon/handlers/shared.ts +2 -1
- package/src/daemon/handlers/skills.ts +6 -3
- package/src/daemon/host-bash-proxy.ts +8 -12
- package/src/daemon/host-browser-proxy.ts +15 -1
- package/src/daemon/host-cu-proxy.ts +186 -19
- package/src/daemon/host-file-proxy.ts +8 -10
- package/src/daemon/host-proxy-preactivation.ts +2 -1
- package/src/daemon/host-transfer-proxy.ts +14 -18
- package/src/daemon/lifecycle.ts +0 -5
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/reaction-history-render.ts +2 -1
- package/src/daemon/shutdown-handlers.ts +1 -9
- package/src/daemon/skill-memory-refresh.ts +64 -0
- package/src/daemon/tool-side-effects.ts +7 -18
- package/src/desktop/__tests__/fake-desktop.ts +122 -0
- package/src/desktop/desktop-chrome-policy.test.ts +79 -0
- package/src/desktop/desktop-chrome-policy.ts +47 -0
- package/src/desktop/desktop-chrome-session.ts +37 -0
- package/src/desktop/desktop-dependencies.test.ts +102 -0
- package/src/desktop/desktop-dependencies.ts +308 -0
- package/src/desktop/desktop-feature.test.ts +18 -0
- package/src/desktop/desktop-feature.ts +19 -0
- package/src/desktop/desktop-panel-config.test.ts +135 -0
- package/src/desktop/desktop-panel-config.ts +149 -0
- package/src/desktop/desktop-session-manager.test.ts +730 -0
- package/src/desktop/desktop-session-manager.ts +850 -0
- package/src/desktop/desktop-stream-bridge.test.ts +395 -0
- package/src/desktop/desktop-stream-bridge.ts +214 -0
- package/src/desktop/desktop-wallpaper.test.ts +191 -0
- package/src/desktop/desktop-wallpaper.ts +113 -0
- package/src/desktop/desktop-window-drag.ts +177 -0
- package/src/desktop/desktop-window-manager-config.test.ts +230 -0
- package/src/desktop/desktop-window-manager-config.ts +238 -0
- package/src/desktop/desktop-window-theme.ts +170 -0
- package/src/heartbeat/heartbeat-service.ts +21 -3
- package/src/home/__tests__/feed-writer.test.ts +22 -0
- package/src/home/feed-writer.ts +11 -2
- package/src/hooks/types.ts +33 -0
- package/src/i18n/AGENTS.md +22 -0
- package/src/i18n/__tests__/i18n.test.ts +108 -0
- package/src/i18n/index.ts +16 -0
- package/src/i18n/locales.ts +93 -0
- package/src/i18n/messages.ts +61 -0
- package/src/i18n/title.ts +25 -0
- package/src/inbound/platform-callback-registration.ts +4 -5
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +238 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
- package/src/live-voice/live-voice-photo.ts +25 -6
- package/src/live-voice/live-voice-session.ts +213 -693
- package/src/live-voice/protocol.ts +0 -2
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +29 -45
- package/src/mcp/spec-schema.ts +111 -0
- package/src/mcp/startup.ts +8 -4
- package/src/mcp/workspace-mcp-config.ts +188 -0
- package/src/messaging/provider.ts +10 -3
- package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
- package/src/messaging/providers/callback-routing.ts +18 -0
- package/src/messaging/providers/channel-transport.ts +56 -0
- package/src/messaging/providers/discord/transport.ts +17 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
- package/src/messaging/providers/slack/adapter.ts +7 -44
- package/src/messaging/providers/slack/transport.ts +16 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
- package/src/messaging/providers/telegram-bot/client.ts +0 -26
- package/src/messaging/providers/telegram-bot/transport.ts +20 -0
- package/src/messaging/providers/whatsapp/adapter.ts +1 -48
- package/src/messaging/providers/whatsapp/transport.ts +18 -0
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
- package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/assistant-reply-producer.ts +8 -3
- package/src/notifications/conversation-pairing.ts +36 -16
- package/src/notifications/delivered-post-record.ts +11 -1
- package/src/notifications/guardian-feed-projection.ts +125 -5
- package/src/notifications/home-feed-side-effect.ts +55 -7
- package/src/notifications/schedule-result-producer.ts +66 -22
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/seed-providers-managed.test.ts +54 -0
- package/src/oauth/byo-connection.test.ts +105 -0
- package/src/oauth/byo-connection.ts +36 -6
- package/src/oauth/connection-resolver.test.ts +73 -0
- package/src/oauth/connection-resolver.ts +95 -2
- package/src/oauth/scope-utils.ts +24 -0
- package/src/oauth/seed-providers.ts +204 -25
- package/src/outbound-proxy/certs.ts +3 -5
- package/src/permissions/checker.test.ts +11 -6
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +71 -63
- package/src/persistence/conversation-lineage.ts +12 -4
- package/src/persistence/conversation-queries.ts +2 -2
- package/src/persistence/conversation-title-placeholders.ts +23 -0
- package/src/persistence/conversation-title-service.ts +9 -26
- package/src/persistence/embeddings/qdrant-manager.ts +163 -18
- 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-cursor.ts +78 -0
- package/src/persistence/message-reads.ts +30 -0
- package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
- package/src/persistence/schema/memory-core.ts +5 -0
- package/src/platform/client.test.ts +4 -2
- package/src/platform/client.ts +2 -10
- package/src/plugin-api/constants.ts +2 -0
- package/src/plugin-api/index.ts +1 -0
- package/src/plugin-api/types.ts +2 -0
- package/src/plugins/defaults/index.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +20 -10
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +5 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +3 -2
- package/src/plugins/defaults/memory/context-search/format.ts +3 -2
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +6 -3
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +3 -2
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -7
- package/src/plugins/defaults/memory/hooks/init.ts +10 -0
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
- package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
- package/src/plugins/defaults/memory/host-utils.ts +10 -0
- package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +12 -3
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
- package/src/plugins/defaults/memory/startup.ts +28 -2
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
- package/src/plugins/defaults/memory/substrate/page-index.ts +6 -1
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +4 -1
- package/src/plugins/defaults/memory/v2/reranker.ts +6 -1
- package/src/plugins/defaults/memory/v3/__tests__/card.test.ts +24 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +125 -0
- package/src/plugins/defaults/memory/v3/__tests__/sections.test.ts +26 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +30 -0
- package/src/plugins/defaults/memory/v3/card.ts +3 -2
- package/src/plugins/defaults/memory/v3/pool-select.ts +5 -3
- package/src/plugins/defaults/memory/v3/sections.ts +9 -3
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +5 -2
- package/src/plugins/defaults/memory/worker.ts +6 -0
- package/src/plugins/mcp-servers.ts +15 -75
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/__tests__/retry-callsite.test.ts +41 -0
- package/src/providers/__tests__/retry-outbound-sanitize.test.ts +176 -0
- package/src/providers/anthropic/client.ts +0 -47
- package/src/providers/gemini/client.ts +9 -23
- package/src/providers/gemini-thought-signature.test.ts +63 -0
- package/src/providers/gemini-thought-signature.ts +44 -0
- package/src/providers/inference/__tests__/endpoint-probe.test.ts +42 -3
- package/src/providers/inference/auth.ts +2 -3
- package/src/providers/inference/connection-availability.ts +27 -8
- package/src/providers/inference/endpoint-probe.ts +10 -1
- package/src/providers/inference/resolve-auth.ts +22 -4
- package/src/providers/inference/service-account-token.ts +248 -0
- package/src/providers/model-catalog.ts +34 -0
- package/src/providers/model-intents.ts +10 -5
- package/src/providers/openai/__tests__/chat-completions-output-token-limit.test.ts +141 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
- package/src/providers/openai/chat-completions-provider.ts +212 -79
- package/src/providers/openai/codex-models.ts +0 -4
- package/src/providers/openai/google-thought-signature.ts +320 -0
- package/src/providers/opencode/client.test.ts +73 -4
- package/src/providers/opencode/client.ts +60 -3
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/outbound-request-sanitize.ts +96 -0
- package/src/providers/retry.ts +30 -19
- package/src/providers/unparseable-tool-args.ts +5 -1
- package/src/runtime/AGENTS.md +3 -1
- package/src/runtime/__tests__/channel-send.test.ts +443 -0
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +89 -0
- package/src/runtime/__tests__/host-observe.test.ts +40 -1
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
- package/src/runtime/agent-wake.ts +2 -1
- package/src/runtime/assistant-event-hub.ts +21 -3
- package/src/runtime/auth/same-actor.ts +38 -3
- package/src/runtime/channel-send.ts +316 -0
- package/src/runtime/host-observe.ts +11 -1
- package/src/runtime/http-server.ts +160 -151
- package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +205 -0
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
- package/src/runtime/routes/acp-routes.test.ts +15 -0
- package/src/runtime/routes/acp-routes.ts +72 -9
- package/src/runtime/routes/app-management-routes.ts +73 -0
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/channel-send-routes.ts +85 -0
- package/src/runtime/routes/conversation-list-routes.ts +14 -3
- package/src/runtime/routes/conversation-query-routes.ts +40 -0
- package/src/runtime/routes/conversation-routes.ts +16 -3
- package/src/runtime/routes/credential-routes.ts +19 -10
- package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
- package/src/runtime/routes/desktop-setup-routes.ts +35 -0
- package/src/runtime/routes/diagnostics-routes.ts +61 -4
- package/src/runtime/routes/events-routes.ts +4 -0
- package/src/runtime/routes/host-cu-routes.ts +6 -0
- package/src/runtime/routes/index.ts +4 -2
- package/src/runtime/routes/log-export-routes.ts +2 -0
- package/src/runtime/routes/mcp-auth-routes.ts +39 -47
- package/src/runtime/routes/migration-routes.ts +6 -20
- package/src/runtime/routes/oauth-commands-routes.ts +36 -0
- package/src/runtime/routes/platform-routes.ts +18 -15
- package/src/runtime/routes/workspace-routes.test.ts +55 -26
- package/src/runtime/routes/workspace-routes.ts +46 -63
- package/src/runtime/routes/workspace-tree-walk.test.ts +244 -0
- package/src/runtime/routes/workspace-tree-walk.ts +240 -0
- package/src/runtime/routes/workspace-utils.ts +17 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +16 -3
- package/src/runtime/sync/resource-sync-events.ts +2 -1
- package/src/schedule/run-script.ts +2 -1
- package/src/schedule/schedule-store.ts +9 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
- package/src/security/ces-http-record-backend.ts +120 -0
- package/src/security/ces-rpc-record-backend.ts +7 -0
- package/src/security/untrusted-content.ts +3 -1
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
- package/src/skills/workspace-skill-md-signature.ts +50 -0
- package/src/subagent/consult-context.ts +12 -25
- package/src/tools/__tests__/side-effect-abort-guard.test.ts +1 -0
- package/src/tools/acp/list-agents.test.ts +3 -1
- package/src/tools/acp/spawn.test.ts +146 -11
- package/src/tools/acp/spawn.ts +21 -3
- package/src/tools/acp/status.test.ts +94 -0
- package/src/tools/acp/status.ts +40 -3
- package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +9 -3
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +2 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +3 -2
- package/src/tools/browser/network-recorder.ts +2 -1
- package/src/tools/capability-offer.test.ts +22 -2
- package/src/tools/capability-offer.ts +16 -1
- package/src/tools/computer-use/definitions.ts +121 -2
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
- package/src/tools/credentials/metadata-store.ts +100 -0
- package/src/tools/filesystem/search.ts +2 -1
- package/src/tools/host-filesystem/edit.test.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +2 -1
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +2 -1
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +2 -1
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +16 -0
- package/src/tools/host-terminal/host-shell.ts +4 -20
- package/src/tools/network/web-search.ts +6 -1
- package/src/tools/policy-context.ts +6 -7
- package/src/tools/skills/scaffold-managed.ts +61 -3
- package/src/tools/subagent/spawn.ts +5 -8
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
- package/src/tools/terminal/sanitized-bash.ts +105 -0
- package/src/tools/watch/watch-retro-report.ts +0 -8
- package/src/types/host-capabilities.ts +5 -3
- package/src/util/__tests__/language-subtag.test.ts +23 -1
- package/src/util/ca-bundle.ts +13 -0
- package/src/util/language-subtag.ts +16 -0
- package/src/util/platform.ts +8 -0
- package/src/util/unicode.ts +15 -1
- package/src/watch/watch-timeline.ts +2 -2
- package/src/workflows/run-manager.ts +2 -1
- package/src/workspace/git-porcelain.ts +66 -0
- package/src/workspace/git-service.ts +6 -55
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/app-source-watcher.test.ts +0 -218
- package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
- package/src/__tests__/speaker-identification.test.ts +0 -56
- package/src/calls/speaker-identification.ts +0 -233
- package/src/daemon/app-source-watcher.ts +0 -218
- package/src/messaging/providers/whatsapp/client.ts +0 -29
- package/src/runtime/routes/debug-bash-routes.ts +0 -173
- package/src/util/fs-watcher-error.ts +0 -36
- /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the `acp_status` tool's projection of session state.
|
|
3
|
+
*
|
|
4
|
+
* The state the manager tracks feeds three surfaces with different budgets:
|
|
5
|
+
* the HTTP route, the SSE picker, and this tool, whose output is spent on
|
|
6
|
+
* LLM context. Only the fields an agent can act on belong here.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, expect, mock, test } from "bun:test";
|
|
10
|
+
|
|
11
|
+
import type { AcpSessionState } from "../../acp/types.js";
|
|
12
|
+
import type { ToolContext } from "../types.js";
|
|
13
|
+
|
|
14
|
+
const RUNNING_STATE: AcpSessionState = {
|
|
15
|
+
id: "acp-1",
|
|
16
|
+
agentId: "claude",
|
|
17
|
+
acpSessionId: "proto-1",
|
|
18
|
+
parentConversationId: "conv-1",
|
|
19
|
+
status: "running",
|
|
20
|
+
startedAt: 1234,
|
|
21
|
+
task: "refactor the parser",
|
|
22
|
+
model: "claude-opus-4-5",
|
|
23
|
+
availableModels: [
|
|
24
|
+
{ value: "sonnet", label: "Sonnet" },
|
|
25
|
+
{ value: "opus", label: "Opus", description: "Most capable" },
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
let statusResult: AcpSessionState | AcpSessionState[] = RUNNING_STATE;
|
|
30
|
+
|
|
31
|
+
const realAcpModule = await import("../../acp/index.js");
|
|
32
|
+
mock.module("../../acp/index.js", () => ({
|
|
33
|
+
...realAcpModule,
|
|
34
|
+
getAcpSessionManager: () => ({ getStatus: () => statusResult }),
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
const { executeAcpStatus } = await import("./status.js");
|
|
38
|
+
|
|
39
|
+
const context = {
|
|
40
|
+
conversationId: "conv-1",
|
|
41
|
+
workingDir: "/tmp",
|
|
42
|
+
} as unknown as ToolContext;
|
|
43
|
+
|
|
44
|
+
describe("executeAcpStatus", () => {
|
|
45
|
+
test("a single session reports its model but not the picker", async () => {
|
|
46
|
+
statusResult = RUNNING_STATE;
|
|
47
|
+
|
|
48
|
+
const result = await executeAcpStatus({ acp_session_id: "acp-1" }, context);
|
|
49
|
+
|
|
50
|
+
expect(result.isError).toBe(false);
|
|
51
|
+
const payload = JSON.parse(result.content);
|
|
52
|
+
expect(payload).toEqual({
|
|
53
|
+
id: "acp-1",
|
|
54
|
+
agentId: "claude",
|
|
55
|
+
acpSessionId: "proto-1",
|
|
56
|
+
parentConversationId: "conv-1",
|
|
57
|
+
status: "running",
|
|
58
|
+
startedAt: 1234,
|
|
59
|
+
task: "refactor the parser",
|
|
60
|
+
model: "claude-opus-4-5",
|
|
61
|
+
});
|
|
62
|
+
expect(result.content).not.toContain("Most capable");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("the listing drops the picker from every entry", async () => {
|
|
66
|
+
statusResult = [
|
|
67
|
+
RUNNING_STATE,
|
|
68
|
+
{ ...RUNNING_STATE, id: "acp-2", model: "sonnet" },
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
const result = await executeAcpStatus({}, context);
|
|
72
|
+
|
|
73
|
+
const payload = JSON.parse(result.content) as Array<
|
|
74
|
+
Record<string, unknown>
|
|
75
|
+
>;
|
|
76
|
+
expect(payload).toHaveLength(2);
|
|
77
|
+
expect(payload.map((entry) => entry.model)).toEqual([
|
|
78
|
+
"claude-opus-4-5",
|
|
79
|
+
"sonnet",
|
|
80
|
+
]);
|
|
81
|
+
for (const entry of payload) {
|
|
82
|
+
expect(entry).not.toHaveProperty("availableModels");
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("an empty listing says so rather than rendering an empty array", async () => {
|
|
87
|
+
statusResult = [];
|
|
88
|
+
|
|
89
|
+
const result = await executeAcpStatus({}, context);
|
|
90
|
+
|
|
91
|
+
expect(result.content).toBe("No ACP sessions found.");
|
|
92
|
+
expect(result.isError).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
});
|
package/src/tools/acp/status.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
3
|
import { getAcpSessionManager } from "../../acp/index.js";
|
|
4
|
+
import type { AcpSessionState } from "../../acp/types.js";
|
|
4
5
|
import {
|
|
5
6
|
invalidToolInputResult,
|
|
6
7
|
nullAsOmitted,
|
|
@@ -16,6 +17,40 @@ export const acpStatusInputSchema = z.looseObject({
|
|
|
16
17
|
acp_session_id: nullAsOmitted(z.string()),
|
|
17
18
|
});
|
|
18
19
|
|
|
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
|
+
|
|
19
54
|
export async function executeAcpStatus(
|
|
20
55
|
input: Record<string, unknown>,
|
|
21
56
|
_context: ToolContext,
|
|
@@ -29,9 +64,8 @@ export async function executeAcpStatus(
|
|
|
29
64
|
|
|
30
65
|
try {
|
|
31
66
|
if (acpSessionId) {
|
|
32
|
-
const state = manager.getStatus(acpSessionId);
|
|
33
67
|
return {
|
|
34
|
-
content: JSON.stringify(
|
|
68
|
+
content: JSON.stringify(projectStatus(manager.getStatus(acpSessionId))),
|
|
35
69
|
isError: false,
|
|
36
70
|
};
|
|
37
71
|
}
|
|
@@ -42,7 +76,10 @@ export async function executeAcpStatus(
|
|
|
42
76
|
return { content: "No ACP sessions found.", isError: false };
|
|
43
77
|
}
|
|
44
78
|
|
|
45
|
-
return {
|
|
79
|
+
return {
|
|
80
|
+
content: JSON.stringify(projectStatus(allStates)),
|
|
81
|
+
isError: false,
|
|
82
|
+
};
|
|
46
83
|
} catch (err) {
|
|
47
84
|
const msg = err instanceof Error ? err.message : String(err);
|
|
48
85
|
return { content: msg, isError: true };
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* the proxy resolver, which forwards the call to the connected client.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { formatDesktopAppRequired } from "../capability-offer.js";
|
|
8
9
|
import { throwIfCancelled } from "../shared/abort.js";
|
|
9
10
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
10
11
|
|
|
@@ -32,7 +33,7 @@ export function forwardAppControlProxyTool(
|
|
|
32
33
|
}
|
|
33
34
|
if (!context.proxyToolResolver) {
|
|
34
35
|
return Promise.resolve({
|
|
35
|
-
content:
|
|
36
|
+
content: formatDesktopAppRequired("apps"),
|
|
36
37
|
isError: true,
|
|
37
38
|
});
|
|
38
39
|
}
|
|
@@ -262,7 +262,7 @@ export const EXTRACT_LINKS_EXPRESSION = `
|
|
|
262
262
|
(() => {
|
|
263
263
|
const anchors = Array.from(document.querySelectorAll('a[href]'));
|
|
264
264
|
return anchors.slice(0, 200).map(a => ({
|
|
265
|
-
text: (a.textContent || '').trim().slice(0, 80),
|
|
265
|
+
text: Array.from((a.textContent || '').trim()).slice(0, 80).join(''),
|
|
266
266
|
href: a.href,
|
|
267
267
|
}));
|
|
268
268
|
})()
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* a later PR is a direct drop-in replacement.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { safeStringSlice } from "../../../util/unicode.js";
|
|
18
|
+
|
|
17
19
|
// ── Types ─────────────────────────────────────────────────────────────
|
|
18
20
|
|
|
19
21
|
/**
|
|
@@ -288,7 +290,11 @@ function extractAttrs(node: RawAxNode): Record<string, string> {
|
|
|
288
290
|
if (!PROPERTY_ALLOWLIST.has(name)) {
|
|
289
291
|
continue;
|
|
290
292
|
}
|
|
291
|
-
attrs[name] =
|
|
293
|
+
attrs[name] = safeStringSlice(
|
|
294
|
+
stringifyAxValue(prop.value?.value),
|
|
295
|
+
0,
|
|
296
|
+
MAX_VALUE_CHARS,
|
|
297
|
+
);
|
|
292
298
|
}
|
|
293
299
|
return attrs;
|
|
294
300
|
}
|
|
@@ -346,12 +352,12 @@ export function transformAxTree(
|
|
|
346
352
|
}
|
|
347
353
|
|
|
348
354
|
const rawName = typeof node.name?.value === "string" ? node.name.value : "";
|
|
349
|
-
const name = rawName.trim()
|
|
355
|
+
const name = safeStringSlice(rawName.trim(), 0, MAX_NAME_CHARS);
|
|
350
356
|
|
|
351
357
|
const rawValue = node.value?.value;
|
|
352
358
|
const value =
|
|
353
359
|
typeof rawValue === "string" && rawValue.length > 0
|
|
354
|
-
? rawValue
|
|
360
|
+
? safeStringSlice(rawValue, 0, MAX_VALUE_CHARS)
|
|
355
361
|
: undefined;
|
|
356
362
|
|
|
357
363
|
const attrs = extractAttrs(node);
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* value.
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
+
import { safeStringSlice } from "../../../../util/unicode.js";
|
|
28
29
|
import type { CdpWsTransport } from "./ws-transport.js";
|
|
29
30
|
|
|
30
31
|
/**
|
|
@@ -336,7 +337,7 @@ function parseJsonText(text: string, endpoint: string): unknown {
|
|
|
336
337
|
} catch (err) {
|
|
337
338
|
throw new DevToolsDiscoveryError(
|
|
338
339
|
"invalid_response",
|
|
339
|
-
`Expected JSON from ${endpoint} but got: ${text
|
|
340
|
+
`Expected JSON from ${endpoint} but got: ${safeStringSlice(text, 0, 200)}`,
|
|
340
341
|
err,
|
|
341
342
|
);
|
|
342
343
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { HostBrowserProxy } from "../../../daemon/host-browser-proxy.js";
|
|
2
2
|
import { getLogger } from "../../../util/logger.js";
|
|
3
|
+
import { safeStringSlice } from "../../../util/unicode.js";
|
|
3
4
|
import type { CdpErrorCode } from "./errors.js";
|
|
4
5
|
import { CdpError } from "./errors.js";
|
|
5
6
|
import type { CdpClientKind, ScopedCdpClient, TabInfo } from "./types.js";
|
|
@@ -121,7 +122,7 @@ export class ExtensionCdpClient implements ScopedCdpClient {
|
|
|
121
122
|
// and mask the extension path as the true failing hop.
|
|
122
123
|
throw new CdpError(
|
|
123
124
|
"cdp_error",
|
|
124
|
-
result.content
|
|
125
|
+
safeStringSlice(result.content, 0, 200) || `CDP error for ${method}`,
|
|
125
126
|
{
|
|
126
127
|
cdpMethod: method,
|
|
127
128
|
cdpParams: params,
|
|
@@ -164,7 +165,7 @@ export class ExtensionCdpClient implements ScopedCdpClient {
|
|
|
164
165
|
} catch (err) {
|
|
165
166
|
throw new CdpError(
|
|
166
167
|
"transport_error",
|
|
167
|
-
`Non-JSON content from host_browser_result: ${result.content
|
|
168
|
+
`Non-JSON content from host_browser_result: ${safeStringSlice(result.content, 0, 200)}`,
|
|
168
169
|
{
|
|
169
170
|
cdpMethod: method,
|
|
170
171
|
cdpParams: params,
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { getLogger } from "../../util/logger.js";
|
|
9
9
|
import { truncate } from "../../util/truncate.js";
|
|
10
|
+
import { safeStringSlice } from "../../util/unicode.js";
|
|
10
11
|
import type {
|
|
11
12
|
ExtractedCredential,
|
|
12
13
|
NetworkRecordedEntry,
|
|
@@ -457,7 +458,7 @@ export class NetworkRecorder {
|
|
|
457
458
|
|
|
458
459
|
entry.response.body =
|
|
459
460
|
body.length > MAX_BODY_SIZE
|
|
460
|
-
? body
|
|
461
|
+
? safeStringSlice(body, 0, MAX_BODY_SIZE) + "...[truncated]"
|
|
461
462
|
: body;
|
|
462
463
|
}
|
|
463
464
|
} catch {
|
|
@@ -4,11 +4,26 @@ import {
|
|
|
4
4
|
appendLoggedInBrowserOffer,
|
|
5
5
|
CHROME_WEB_STORE_INSTALL_URL,
|
|
6
6
|
DESKTOP_APP_DOWNLOAD_URL,
|
|
7
|
+
formatDesktopAppRequired,
|
|
7
8
|
formatLoggedInBrowserOffer,
|
|
8
9
|
isPhoneSurface,
|
|
9
10
|
shouldOfferLoggedInBrowser,
|
|
10
11
|
} from "./capability-offer.js";
|
|
11
12
|
|
|
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
|
+
|
|
12
27
|
describe("isPhoneSurface", () => {
|
|
13
28
|
test("is true for iOS transport and mobile client OS", () => {
|
|
14
29
|
expect(isPhoneSurface({ transportInterface: "ios" })).toBe(true);
|
|
@@ -49,7 +64,9 @@ describe("shouldOfferLoggedInBrowser", () => {
|
|
|
49
64
|
expect(shouldOfferLoggedInBrowser('Invalid browser_mode "bogus"')).toBe(
|
|
50
65
|
false,
|
|
51
66
|
);
|
|
52
|
-
expect(shouldOfferLoggedInBrowser("url must use http or https")).toBe(
|
|
67
|
+
expect(shouldOfferLoggedInBrowser("url must use http or https")).toBe(
|
|
68
|
+
false,
|
|
69
|
+
);
|
|
53
70
|
});
|
|
54
71
|
});
|
|
55
72
|
|
|
@@ -71,6 +88,7 @@ describe("formatLoggedInBrowserOffer", () => {
|
|
|
71
88
|
});
|
|
72
89
|
expect(offer).toContain("no in-app browser");
|
|
73
90
|
expect(offer).toContain("Do not describe a browser panel");
|
|
91
|
+
expect(offer).toContain("Mac or Windows PC");
|
|
74
92
|
expect(offer).toContain(DESKTOP_APP_DOWNLOAD_URL);
|
|
75
93
|
expect(offer).toContain(CHROME_WEB_STORE_INSTALL_URL);
|
|
76
94
|
});
|
|
@@ -78,7 +96,9 @@ describe("formatLoggedInBrowserOffer", () => {
|
|
|
78
96
|
|
|
79
97
|
describe("appendLoggedInBrowserOffer", () => {
|
|
80
98
|
test("appends the offer once", () => {
|
|
81
|
-
const once = appendLoggedInBrowserOffer(
|
|
99
|
+
const once = appendLoggedInBrowserOffer(
|
|
100
|
+
"Error: Navigation failed: timeout",
|
|
101
|
+
);
|
|
82
102
|
expect(once).toContain("Error: Navigation failed: timeout");
|
|
83
103
|
expect(once).toContain(DESKTOP_APP_DOWNLOAD_URL);
|
|
84
104
|
const twice = appendLoggedInBrowserOffer(once);
|
|
@@ -7,7 +7,22 @@ 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 = `
|
|
10
|
+
export const DESKTOP_APP_INSTALL_HINT = `Download the Vellum desktop app: ${DESKTOP_APP_DOWNLOAD_URL}. Open it, then retry.`;
|
|
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
|
+
}
|
|
11
26
|
|
|
12
27
|
/** User-facing install step for status userActions and command-failure hints. */
|
|
13
28
|
export const CHROME_EXTENSION_INSTALL_HINT = `Install the Vellum Assistant Chrome extension from the Chrome Web Store: ${CHROME_WEB_STORE_INSTALL_URL}`;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { RiskLevel } from "../../permissions/types.js";
|
|
11
|
+
import { formatDesktopAppRequired } from "../capability-offer.js";
|
|
11
12
|
import type {
|
|
12
13
|
ToolContext,
|
|
13
14
|
ToolDefinition,
|
|
@@ -31,7 +32,7 @@ function proxyExecute(toolName: string) {
|
|
|
31
32
|
): Promise<ToolExecutionResult> => {
|
|
32
33
|
if (!context.proxyToolResolver) {
|
|
33
34
|
return {
|
|
34
|
-
content:
|
|
35
|
+
content: formatDesktopAppRequired("screen"),
|
|
35
36
|
isError: true,
|
|
36
37
|
};
|
|
37
38
|
}
|
|
@@ -381,6 +382,112 @@ export const computerUseRunAppleScriptTool = {
|
|
|
381
382
|
execute: proxyExecute("computer_use_run_applescript"),
|
|
382
383
|
} satisfies ToolDefinition;
|
|
383
384
|
|
|
385
|
+
// ---------------------------------------------------------------------------
|
|
386
|
+
// sequence
|
|
387
|
+
// ---------------------------------------------------------------------------
|
|
388
|
+
|
|
389
|
+
export const computerUseSequenceTool = {
|
|
390
|
+
name: "computer_use_sequence",
|
|
391
|
+
description:
|
|
392
|
+
"Run several computer-use actions you already know, in order, in one step, for example open an app, press cmd+n, type a URL and press enter. Use it when no action depends on seeing the result of the one before; otherwise act one step at a time. Element IDs refer to the latest observation, so use them only for actions that act before the screen changes. Stops at the first action that is refused or fails and reports which one. Returns one observation after the last action.",
|
|
393
|
+
category: "computer-use",
|
|
394
|
+
defaultRiskLevel: RiskLevel.Low,
|
|
395
|
+
executionTarget: "host",
|
|
396
|
+
supportedClientOs: ["macos"],
|
|
397
|
+
|
|
398
|
+
input_schema: {
|
|
399
|
+
type: "object",
|
|
400
|
+
properties: {
|
|
401
|
+
actions: {
|
|
402
|
+
type: "array",
|
|
403
|
+
minItems: 1,
|
|
404
|
+
maxItems: 10,
|
|
405
|
+
description: "The actions to run, in order",
|
|
406
|
+
items: {
|
|
407
|
+
type: "object",
|
|
408
|
+
properties: {
|
|
409
|
+
action: {
|
|
410
|
+
type: "string",
|
|
411
|
+
enum: [
|
|
412
|
+
"key",
|
|
413
|
+
"type_text",
|
|
414
|
+
"type",
|
|
415
|
+
"click",
|
|
416
|
+
"double_click",
|
|
417
|
+
"right_click",
|
|
418
|
+
"scroll",
|
|
419
|
+
"wait",
|
|
420
|
+
"open_app",
|
|
421
|
+
],
|
|
422
|
+
description: "The action to run",
|
|
423
|
+
},
|
|
424
|
+
key: {
|
|
425
|
+
type: "string",
|
|
426
|
+
description:
|
|
427
|
+
"key: key or shortcut to press (e.g. enter, tab, cmd+n)",
|
|
428
|
+
},
|
|
429
|
+
text: {
|
|
430
|
+
type: "string",
|
|
431
|
+
description: "type_text (or type): the text to type",
|
|
432
|
+
},
|
|
433
|
+
element_id: {
|
|
434
|
+
type: "integer",
|
|
435
|
+
description:
|
|
436
|
+
"click, double_click, right_click, scroll: the [ID] of the element from the latest accessibility tree (preferred)",
|
|
437
|
+
},
|
|
438
|
+
x: {
|
|
439
|
+
type: "integer",
|
|
440
|
+
description:
|
|
441
|
+
"click, double_click, right_click, scroll: X coordinate on screen (fallback when no element_id)",
|
|
442
|
+
},
|
|
443
|
+
y: {
|
|
444
|
+
type: "integer",
|
|
445
|
+
description:
|
|
446
|
+
"click, double_click, right_click, scroll: Y coordinate on screen (fallback when no element_id)",
|
|
447
|
+
},
|
|
448
|
+
direction: {
|
|
449
|
+
type: "string",
|
|
450
|
+
enum: ["up", "down", "left", "right"],
|
|
451
|
+
description: "scroll: scroll direction",
|
|
452
|
+
},
|
|
453
|
+
amount: {
|
|
454
|
+
type: "integer",
|
|
455
|
+
description: "scroll: scroll amount (1-10)",
|
|
456
|
+
},
|
|
457
|
+
duration_ms: {
|
|
458
|
+
type: "integer",
|
|
459
|
+
description: "wait: milliseconds to wait",
|
|
460
|
+
},
|
|
461
|
+
app_name: {
|
|
462
|
+
type: "string",
|
|
463
|
+
description:
|
|
464
|
+
'open_app: the name of the application to open (e.g. "Google Chrome")',
|
|
465
|
+
},
|
|
466
|
+
reasoning: {
|
|
467
|
+
type: "string",
|
|
468
|
+
description: "Optional: why this action",
|
|
469
|
+
},
|
|
470
|
+
},
|
|
471
|
+
required: ["action"],
|
|
472
|
+
},
|
|
473
|
+
},
|
|
474
|
+
reasoning: {
|
|
475
|
+
type: "string",
|
|
476
|
+
description:
|
|
477
|
+
"Optional: what these actions do together. Reasoning on each action works too",
|
|
478
|
+
},
|
|
479
|
+
target_client_id: {
|
|
480
|
+
type: "string",
|
|
481
|
+
description:
|
|
482
|
+
"ID of the specific client to target. Required when multiple clients support host_cu; omit when only one is connected. Obtain IDs from `assistant clients list --capability host_cu`.",
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
required: ["actions"],
|
|
486
|
+
},
|
|
487
|
+
|
|
488
|
+
execute: proxyExecute("computer_use_sequence"),
|
|
489
|
+
} satisfies ToolDefinition;
|
|
490
|
+
|
|
384
491
|
// ---------------------------------------------------------------------------
|
|
385
492
|
// done
|
|
386
493
|
// ---------------------------------------------------------------------------
|
|
@@ -456,7 +563,18 @@ export const computerUseObserveTool = {
|
|
|
456
563
|
type: "integer",
|
|
457
564
|
minimum: 1,
|
|
458
565
|
maximum: 4294967295,
|
|
459
|
-
description:
|
|
566
|
+
description:
|
|
567
|
+
"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.",
|
|
568
|
+
},
|
|
569
|
+
include_screenshot: {
|
|
570
|
+
type: "boolean",
|
|
571
|
+
description:
|
|
572
|
+
"Force a screenshot with this observation. The accessibility tree is returned every step; ask for pixels whenever the tree is not enough to act on, such as a canvas, a game, a custom-drawn view, a window with few or unlabeled controls, or a question about layout.",
|
|
573
|
+
},
|
|
574
|
+
full_tree: {
|
|
575
|
+
type: "boolean",
|
|
576
|
+
description:
|
|
577
|
+
"Walk the accessibility tree to full depth. Observations list the tree to a limited depth and say when it was cut off; pass this when the element you need is not in the tree.",
|
|
460
578
|
},
|
|
461
579
|
target_client_id: {
|
|
462
580
|
type: "string",
|
|
@@ -484,6 +602,7 @@ export const allComputerUseTools: ToolDefinition[] = [
|
|
|
484
602
|
computerUseWaitTool,
|
|
485
603
|
computerUseOpenAppTool,
|
|
486
604
|
computerUseRunAppleScriptTool,
|
|
605
|
+
computerUseSequenceTool,
|
|
487
606
|
computerUseDoneTool,
|
|
488
607
|
computerUseRespondTool,
|
|
489
608
|
];
|
|
@@ -5,6 +5,7 @@
|
|
|
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";
|
|
8
9
|
import { throwIfCancelled } from "../shared/abort.js";
|
|
9
10
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
10
11
|
|
|
@@ -45,7 +46,7 @@ export function forwardComputerUseProxyTool(
|
|
|
45
46
|
}
|
|
46
47
|
if (!context.proxyToolResolver) {
|
|
47
48
|
return Promise.resolve({
|
|
48
|
-
content:
|
|
49
|
+
content: formatDesktopAppRequired("screen"),
|
|
49
50
|
isError: true,
|
|
50
51
|
});
|
|
51
52
|
}
|
|
@@ -20,6 +20,7 @@ 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";
|
|
23
24
|
import type { CredentialRecordBackend } from "../../security/ces-rpc-record-backend.js";
|
|
24
25
|
import { getLogger } from "../../util/logger.js";
|
|
25
26
|
import type { CredentialInjectionTemplate } from "./policy-types.js";
|
|
@@ -55,6 +56,11 @@ const CES_MEMORY_PATH = "ces-in-memory-credential-metadata";
|
|
|
55
56
|
let _store: StaticCredentialMetadataStore | undefined;
|
|
56
57
|
let _overridePath: string | null = null;
|
|
57
58
|
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;
|
|
58
64
|
let _cesRecordsLoaded = false;
|
|
59
65
|
let _cesLoad: Promise<void> | undefined;
|
|
60
66
|
let _cesLoadGeneration = 0;
|
|
@@ -255,6 +261,93 @@ export function listCredentialMetadata(): CredentialMetadata[] {
|
|
|
255
261
|
return getStore().list() as CredentialMetadata[];
|
|
256
262
|
}
|
|
257
263
|
|
|
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
|
+
|
|
258
351
|
/**
|
|
259
352
|
* Delete metadata for a credential.
|
|
260
353
|
*/
|
|
@@ -287,3 +380,10 @@ export function _setMetadataPath(path: string | null): void {
|
|
|
287
380
|
}
|
|
288
381
|
}
|
|
289
382
|
}
|
|
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
|
+
}
|