@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
|
@@ -28,7 +28,6 @@ import { getAllDefaultPluginNames } from "../plugins/defaults/main.js";
|
|
|
28
28
|
import { isActivationSession } from "../plugins/defaults/memory/activation-session-store.js";
|
|
29
29
|
import { isPluginDisabled } from "../plugins/disabled-state.js";
|
|
30
30
|
import type { Message, ToolDefinition } from "../providers/types.js";
|
|
31
|
-
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
32
31
|
import { registerConversationSender } from "../tools/browser/browser-screencast.js";
|
|
33
32
|
import { supportsClientOsForSkillTool } from "../tools/client-os.js";
|
|
34
33
|
import type { ToolExecutor } from "../tools/executor.js";
|
|
@@ -260,6 +259,24 @@ export function createToolExecutor(
|
|
|
260
259
|
// see {@link SubagentToolGateMode}): rejects non-allowlisted calls BEFORE
|
|
261
260
|
// any executor dispatch, so a non-allowlisted tool's executor never runs.
|
|
262
261
|
// The error tool_result lets the model continue or finish.
|
|
262
|
+
const rejectUnattendedHostTool = (
|
|
263
|
+
toolName: string,
|
|
264
|
+
): ToolExecutionResult | null => {
|
|
265
|
+
const { transportInterface } = resolveTurnClientOs(ctx);
|
|
266
|
+
const isUnattended = ctx.currentTurnIsNonInteractive ?? ctx.hasNoClient;
|
|
267
|
+
if (
|
|
268
|
+
HOST_TOOL_NAMES.has(toolName) &&
|
|
269
|
+
isUnattended &&
|
|
270
|
+
transportInterface !== "chrome-extension"
|
|
271
|
+
) {
|
|
272
|
+
return {
|
|
273
|
+
content: `The "${toolName}" tool requires an interactive user turn and cannot run in the background.`,
|
|
274
|
+
isError: true,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
return null;
|
|
278
|
+
};
|
|
279
|
+
|
|
263
280
|
const rejectNonAllowlistedTool = (
|
|
264
281
|
toolName: string,
|
|
265
282
|
): ToolExecutionResult | null => {
|
|
@@ -387,6 +404,10 @@ export function createToolExecutor(
|
|
|
387
404
|
if (rejection) {
|
|
388
405
|
return rejection;
|
|
389
406
|
}
|
|
407
|
+
const unattendedRejection = rejectUnattendedHostTool(executionName);
|
|
408
|
+
if (unattendedRejection) {
|
|
409
|
+
return unattendedRejection;
|
|
410
|
+
}
|
|
390
411
|
}
|
|
391
412
|
|
|
392
413
|
if (isDoordashCommand(executionName, executionInput)) {
|
|
@@ -550,6 +571,10 @@ export function createToolExecutor(
|
|
|
550
571
|
if (innerRejection) {
|
|
551
572
|
return innerRejection;
|
|
552
573
|
}
|
|
574
|
+
const unattendedRejection = rejectUnattendedHostTool(toolName);
|
|
575
|
+
if (unattendedRejection) {
|
|
576
|
+
return unattendedRejection;
|
|
577
|
+
}
|
|
553
578
|
|
|
554
579
|
// Per-chat plugin scope: reject the resolved inner tool when it belongs
|
|
555
580
|
// to a plugin outside the conversation's effective set.
|
|
@@ -628,7 +653,6 @@ export const DEFAULT_PREACTIVATED_SKILL_IDS = ["notifications", "subagent"];
|
|
|
628
653
|
// ── Conditional tool sets ────────────────────────────────────────────
|
|
629
654
|
|
|
630
655
|
const UI_SURFACE_TOOL_NAMES = new Set(["ui_show", "ui_update", "ui_dismiss"]);
|
|
631
|
-
const SLACK_TASK_PROGRESS_UI_TOOL_NAMES = new Set(["ui_show", "ui_update"]);
|
|
632
656
|
/**
|
|
633
657
|
* Single source of truth for which tools are host tools and the capability
|
|
634
658
|
* each one requires from the connected client interface. Adding a tool here
|
|
@@ -856,56 +880,26 @@ export function isToolActiveForContext(
|
|
|
856
880
|
return supportsChannelReaction(turnChannel);
|
|
857
881
|
}
|
|
858
882
|
if (UI_SURFACE_TOOL_NAMES.has(name)) {
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
return !hasNoClient;
|
|
864
|
-
}
|
|
865
|
-
return channelCapabilities?.supportsDynamicUi ?? !hasNoClient;
|
|
883
|
+
// Surface calls write conversation content. Background turns persist that
|
|
884
|
+
// content for the next client that opens the conversation, so presence
|
|
885
|
+
// cannot change whether the model receives these definitions.
|
|
886
|
+
return true;
|
|
866
887
|
}
|
|
867
888
|
if (HOST_TOOL_NAMES.has(name)) {
|
|
868
889
|
const capability = HOST_TOOL_TO_CAPABILITY.get(name);
|
|
869
890
|
const transport = transportInterface;
|
|
870
891
|
|
|
871
|
-
//
|
|
872
|
-
//
|
|
892
|
+
// A transport that does not implement a capability can invoke it through
|
|
893
|
+
// an eligible same-user client. Client selection happens when the call
|
|
894
|
+
// runs, so the wire schema stays stable across live and background turns.
|
|
873
895
|
if (transport && capability && !supportsHostProxy(transport, capability)) {
|
|
874
|
-
|
|
875
|
-
// cross-client routing infrastructure (Phases 1–3 plus host_browser
|
|
876
|
-
// via PR #27489) to be exposed for non-host-proxy transports (e.g.
|
|
877
|
-
// "web", "ios") when at least one capable client is connected via
|
|
878
|
-
// the event hub. Members of CROSS_CLIENT_EXPOSED_CAPABILITIES
|
|
879
|
-
// (host_bash, host_file, host_browser) qualify.
|
|
880
|
-
// chrome-extension transport is excluded as a security boundary
|
|
881
|
-
// (extension only gets host_browser via its own executor path);
|
|
882
|
-
// hasNoClient turns are excluded (no interactive approval UI
|
|
883
|
-
// available).
|
|
884
|
-
if (
|
|
885
|
-
capability &&
|
|
896
|
+
return (
|
|
886
897
|
CROSS_CLIENT_EXPOSED_CAPABILITIES.has(capability) &&
|
|
887
|
-
transport !== "chrome-extension"
|
|
888
|
-
|
|
889
|
-
assistantEventHub.listClientsByCapability(capability).length > 0
|
|
890
|
-
) {
|
|
891
|
-
return true;
|
|
892
|
-
}
|
|
893
|
-
return false;
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
// chrome-extension is its own executor — the extension's popup gates
|
|
897
|
-
// commands via its own UI, and the transport does not use an SSE-level
|
|
898
|
-
// interactive approval channel. hasNoClient is intentionally `true` for
|
|
899
|
-
// chrome-extension turns (chrome-extension is not in INTERACTIVE_INTERFACES)
|
|
900
|
-
// and must not gate host_browser. Trust the per-capability check.
|
|
901
|
-
if (transport === "chrome-extension") {
|
|
902
|
-
return true;
|
|
898
|
+
transport !== "chrome-extension"
|
|
899
|
+
);
|
|
903
900
|
}
|
|
904
901
|
|
|
905
|
-
|
|
906
|
-
// fallback), deny when no client is present so the guardian auto-approve
|
|
907
|
-
// path cannot execute host commands unattended.
|
|
908
|
-
return !hasNoClient;
|
|
902
|
+
return true;
|
|
909
903
|
}
|
|
910
904
|
if (CLIENT_CAPABILITY_TOOL_NAMES.has(name)) {
|
|
911
905
|
if (name === "ask_question" && channelCapabilities?.clientOS === "macos") {
|
|
@@ -2366,9 +2366,6 @@ export class Conversation {
|
|
|
2366
2366
|
|
|
2367
2367
|
markStale(): void {
|
|
2368
2368
|
this.stale = true;
|
|
2369
|
-
// Invalidate the cached skill catalog so the next projection picks up
|
|
2370
|
-
// filesystem changes (e.g. a skill created during this run).
|
|
2371
|
-
this.skillProjectionCache.catalog = undefined;
|
|
2372
2369
|
}
|
|
2373
2370
|
|
|
2374
2371
|
isStale(): boolean {
|
|
@@ -10,6 +10,7 @@ import { join } from "node:path";
|
|
|
10
10
|
|
|
11
11
|
import { getLogger } from "../util/logger.js";
|
|
12
12
|
import { getWorkspaceDir } from "../util/platform.js";
|
|
13
|
+
import { safeStringSlice } from "../util/unicode.js";
|
|
13
14
|
|
|
14
15
|
const log = getLogger("dictation-profile-store");
|
|
15
16
|
|
|
@@ -130,7 +131,7 @@ function validateAndClampConfig(raw: unknown): DictationProfilesConfig {
|
|
|
130
131
|
{ profileId: profile.id },
|
|
131
132
|
`stylePrompt exceeds ${MAX_STYLE_PROMPT_LENGTH} chars, truncating`,
|
|
132
133
|
);
|
|
133
|
-
stylePrompt = stylePrompt
|
|
134
|
+
stylePrompt = safeStringSlice(stylePrompt, 0, MAX_STYLE_PROMPT_LENGTH);
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
// Validate dictionary entries
|
|
@@ -32,6 +32,7 @@ import { unwrapExternalContentForDisplay } from "../../security/untrusted-conten
|
|
|
32
32
|
import type { CredentialInjectionTemplate } from "../../tools/credentials/policy-types.js";
|
|
33
33
|
import { getLogger } from "../../util/logger.js";
|
|
34
34
|
import { joinWithSpacing } from "../../util/text-spacing.js";
|
|
35
|
+
import { safeStringSlice } from "../../util/unicode.js";
|
|
35
36
|
import { estimateBase64Bytes } from "../assistant-attachments.js";
|
|
36
37
|
import { conversationSupportsDynamicUi } from "../channel-ui-capability.js";
|
|
37
38
|
import { findConversation } from "../conversation-registry.js";
|
|
@@ -264,7 +265,7 @@ function clampAttachmentText(text: string): string {
|
|
|
264
265
|
if (text.length <= HISTORY_ATTACHMENT_TEXT_LIMIT) {
|
|
265
266
|
return text;
|
|
266
267
|
}
|
|
267
|
-
return `${text
|
|
268
|
+
return `${safeStringSlice(text, 0, HISTORY_ATTACHMENT_TEXT_LIMIT)}<truncated />`;
|
|
268
269
|
}
|
|
269
270
|
|
|
270
271
|
interface FileBlockMetadata {
|
|
@@ -82,6 +82,7 @@ import {
|
|
|
82
82
|
searchSkillsRegistry,
|
|
83
83
|
} from "../../skills/skillssh-registry.js";
|
|
84
84
|
import { getWorkspaceSkillsDir } from "../../util/platform.js";
|
|
85
|
+
import { safeStringSlice } from "../../util/unicode.js";
|
|
85
86
|
import { getConfigWatcher } from "../config-watcher.js";
|
|
86
87
|
import type {
|
|
87
88
|
SkillDetailResponse,
|
|
@@ -237,9 +238,11 @@ function heuristicDraft(body: string): {
|
|
|
237
238
|
const lines = body.split("\n").filter((l) => l.trim());
|
|
238
239
|
const firstLine = lines[0]?.trim() ?? "";
|
|
239
240
|
const name =
|
|
240
|
-
firstLine.replace(/^#+\s*/, "")
|
|
241
|
+
safeStringSlice(firstLine.replace(/^#+\s*/, ""), 0, 100) ||
|
|
242
|
+
"Untitled Skill";
|
|
241
243
|
const skillId = toSkillSlug(name) || "untitled-skill";
|
|
242
|
-
const description =
|
|
244
|
+
const description =
|
|
245
|
+
safeStringSlice(body.trim(), 0, 200) || "No description provided";
|
|
243
246
|
return { skillId, name, description, emoji: "\u{1F4DD}" };
|
|
244
247
|
}
|
|
245
248
|
|
|
@@ -1732,7 +1735,7 @@ export async function draftSkill(params: {
|
|
|
1732
1735
|
"- emoji: a single emoji character representing the skill",
|
|
1733
1736
|
"",
|
|
1734
1737
|
"Skill body:",
|
|
1735
|
-
body
|
|
1738
|
+
safeStringSlice(body, 0, 2000),
|
|
1736
1739
|
].join("\n");
|
|
1737
1740
|
|
|
1738
1741
|
const response = await provider.sendMessage([userMessage(prompt)], {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { getConfig } from "../config/loader.js";
|
|
2
2
|
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
3
3
|
import {
|
|
4
|
-
ambiguousSameUserError,
|
|
5
4
|
enforceSameActorOrErrorResult,
|
|
6
|
-
|
|
5
|
+
pickMostRecentSameUserClient,
|
|
6
|
+
unavailableSameUserClientError,
|
|
7
7
|
} from "../runtime/auth/same-actor.js";
|
|
8
8
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
9
9
|
import { formatShellOutput } from "../tools/shared/shell-output.js";
|
|
@@ -93,21 +93,17 @@ export class HostBashProxy extends HostProxyBase<
|
|
|
93
93
|
}
|
|
94
94
|
resolvedTargetClientId = input.targetClientId;
|
|
95
95
|
} else {
|
|
96
|
-
|
|
97
|
-
// broadcast) when multiple same-user clients are connected so that
|
|
98
|
-
// a single targeted-style request cannot fan out across every one
|
|
99
|
-
// of the user's machines. Zero same-user matches falls through to
|
|
100
|
-
// the existing untargeted code path.
|
|
101
|
-
const resolved = pickSameUserAutoResolve({
|
|
96
|
+
resolvedTargetClientId = pickMostRecentSameUserClient({
|
|
102
97
|
hub: assistantEventHub,
|
|
103
98
|
capability: "host_bash",
|
|
104
99
|
sourceActorPrincipalId,
|
|
105
100
|
});
|
|
106
|
-
if (
|
|
107
|
-
|
|
101
|
+
if (
|
|
102
|
+
resolvedTargetClientId === undefined &&
|
|
103
|
+
sourceActorPrincipalId !== undefined
|
|
104
|
+
) {
|
|
105
|
+
return unavailableSameUserClientError("host_bash");
|
|
108
106
|
}
|
|
109
|
-
resolvedTargetClientId =
|
|
110
|
-
resolved.kind === "match" ? resolved.clientId : undefined;
|
|
111
107
|
}
|
|
112
108
|
|
|
113
109
|
// Targeted requests must be bound to the same authenticated user as the
|
|
@@ -5,7 +5,10 @@ import {
|
|
|
5
5
|
assistantEventHub,
|
|
6
6
|
broadcastMessage,
|
|
7
7
|
} from "../runtime/assistant-event-hub.js";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
enforceSameActorOrErrorResult,
|
|
10
|
+
unavailableSameUserClientError,
|
|
11
|
+
} from "../runtime/auth/same-actor.js";
|
|
9
12
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
10
13
|
import type { ToolExecutionResult } from "../tools/types.js";
|
|
11
14
|
import { AssistantError, ErrorCode } from "../util/errors.js";
|
|
@@ -284,6 +287,17 @@ export class HostBrowserProxy {
|
|
|
284
287
|
targetClientId,
|
|
285
288
|
);
|
|
286
289
|
|
|
290
|
+
if (
|
|
291
|
+
preferredClient === undefined &&
|
|
292
|
+
sourceActorPrincipalId !== undefined &&
|
|
293
|
+
targetClientId === undefined
|
|
294
|
+
) {
|
|
295
|
+
if (isExtensionOnlyMethod(input.cdpMethod)) {
|
|
296
|
+
return Promise.resolve(extensionRequiredResult(input.cdpMethod));
|
|
297
|
+
}
|
|
298
|
+
return Promise.resolve(unavailableSameUserClientError("host_browser"));
|
|
299
|
+
}
|
|
300
|
+
|
|
287
301
|
// Same-user enforcement: when the caller's actor is known, refuse to
|
|
288
302
|
// dispatch to a client owned by a different actor. This covers the
|
|
289
303
|
// cross-client exposure case where a web/iOS turn for actor A would
|
|
@@ -42,6 +42,11 @@ const MAX_HISTORY_ENTRIES = 10;
|
|
|
42
42
|
const LOOP_DETECTION_WINDOW = 3;
|
|
43
43
|
const CONSECUTIVE_UNCHANGED_WARNING_THRESHOLD = 2;
|
|
44
44
|
|
|
45
|
+
const SEQUENCE_TOOL = "computer_use_sequence";
|
|
46
|
+
|
|
47
|
+
const SCREENSHOT_OMITTED_MESSAGE =
|
|
48
|
+
"Screenshot omitted: the accessibility tree above is current. Pass include_screenshot: true on computer_use_observe to see the screen.";
|
|
49
|
+
|
|
45
50
|
// computer_use_key combos that change only selection/cursor/clipboard state.
|
|
46
51
|
// The AX tree models none of these, so they always produce an empty diff —
|
|
47
52
|
// exempt them from the "NO VISIBLE EFFECT" signal (mirrors computer_use_wait).
|
|
@@ -113,6 +118,8 @@ export interface CuObservationResult {
|
|
|
113
118
|
executionResult?: string;
|
|
114
119
|
executionError?: string;
|
|
115
120
|
userGuidance?: string;
|
|
121
|
+
/** Per-phase helper timings in milliseconds, absent on older helpers. */
|
|
122
|
+
timings?: Record<string, number>;
|
|
116
123
|
}
|
|
117
124
|
|
|
118
125
|
export interface ActionRecord {
|
|
@@ -161,6 +168,40 @@ function actionSignature(record: ActionRecord): string {
|
|
|
161
168
|
return `${record.toolName}:${JSON.stringify(record.input)}`;
|
|
162
169
|
}
|
|
163
170
|
|
|
171
|
+
/**
|
|
172
|
+
* The key a desktop's first look is tracked under. An untargeted request has
|
|
173
|
+
* no client id, so it gets a key no real id can take.
|
|
174
|
+
*/
|
|
175
|
+
function observedTargetKey(targetClientId: string | undefined): string {
|
|
176
|
+
return targetClientId === undefined
|
|
177
|
+
? "\u0000untargeted"
|
|
178
|
+
: `client:${targetClientId}`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Whether `input` scopes the observation to one window or display. */
|
|
182
|
+
function hasCaptureTarget(input: Record<string, unknown>): boolean {
|
|
183
|
+
return (
|
|
184
|
+
Object.hasOwn(input, "capture_window_id") ||
|
|
185
|
+
Object.hasOwn(input, "captureWindowId") ||
|
|
186
|
+
Object.hasOwn(input, "captureDisplayId")
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Whether the resolved client claimed `capability` on its connection. An
|
|
192
|
+
* untargeted request has no client to vouch for it, so it never qualifies.
|
|
193
|
+
*/
|
|
194
|
+
function clientAdvertises(
|
|
195
|
+
targetClientId: string | undefined,
|
|
196
|
+
capability: "host_cu_window_capture" | "host_cu_sequence",
|
|
197
|
+
): boolean {
|
|
198
|
+
const client =
|
|
199
|
+
targetClientId == null
|
|
200
|
+
? undefined
|
|
201
|
+
: assistantEventHub.getClientById(targetClientId);
|
|
202
|
+
return client?.capabilities.includes(capability) ?? false;
|
|
203
|
+
}
|
|
204
|
+
|
|
164
205
|
// ---------------------------------------------------------------------------
|
|
165
206
|
// HostCuProxy
|
|
166
207
|
// ---------------------------------------------------------------------------
|
|
@@ -172,8 +213,36 @@ export class HostCuProxy {
|
|
|
172
213
|
private _previousAXTree: string | undefined;
|
|
173
214
|
private _consecutiveUnchangedSteps = 0;
|
|
174
215
|
private _actionHistory: ActionRecord[] = [];
|
|
175
|
-
/**
|
|
176
|
-
|
|
216
|
+
/**
|
|
217
|
+
* Desktops an unscoped observation has come back from since the last reset,
|
|
218
|
+
* keyed by `observedTargetKey`. A first look is per desktop: having seen one
|
|
219
|
+
* machine says nothing about another the conversation switches to.
|
|
220
|
+
*/
|
|
221
|
+
private _observedTargets = new Set<string>();
|
|
222
|
+
/**
|
|
223
|
+
* Bumped on every reset. A request carries the value it was dispatched
|
|
224
|
+
* under, so an observation that lands after a reset cannot restore state
|
|
225
|
+
* that reset cleared.
|
|
226
|
+
*/
|
|
227
|
+
private _resetGeneration = 0;
|
|
228
|
+
/**
|
|
229
|
+
* Owned request IDs mapped to whether their observation is scoped, whether
|
|
230
|
+
* the helper was told to skip the screenshot, and when the request was
|
|
231
|
+
* dispatched. The dispatch time gives the round trip, which is the part of
|
|
232
|
+
* a step the helper's own timings cannot see.
|
|
233
|
+
*/
|
|
234
|
+
private _ownedRequests = new Map<
|
|
235
|
+
string,
|
|
236
|
+
{
|
|
237
|
+
scoped: boolean;
|
|
238
|
+
screenshotSkipped: boolean;
|
|
239
|
+
targetKey: string;
|
|
240
|
+
resetGeneration: number;
|
|
241
|
+
dispatchedAt: number;
|
|
242
|
+
toolName: string;
|
|
243
|
+
step: number;
|
|
244
|
+
}
|
|
245
|
+
>();
|
|
177
246
|
|
|
178
247
|
constructor(maxSteps = loadConfig().maxStepsPerSession) {
|
|
179
248
|
this._maxSteps = maxSteps;
|
|
@@ -288,11 +357,7 @@ export class HostCuProxy {
|
|
|
288
357
|
}
|
|
289
358
|
// Never dispatch this option to a legacy executor: it would forward the
|
|
290
359
|
// unknown snake-case key and silently capture the entire desktop.
|
|
291
|
-
|
|
292
|
-
resolvedTargetClientId == null
|
|
293
|
-
? undefined
|
|
294
|
-
: assistantEventHub.getClientById(resolvedTargetClientId);
|
|
295
|
-
if (!client?.capabilities.includes("host_cu_window_capture")) {
|
|
360
|
+
if (!clientAdvertises(resolvedTargetClientId, "host_cu_window_capture")) {
|
|
296
361
|
return Promise.resolve({
|
|
297
362
|
content:
|
|
298
363
|
"Window-only observation requires a connected client advertising host_cu_window_capture; update the desktop app before retrying. No capture was requested.",
|
|
@@ -300,14 +365,40 @@ export class HostCuProxy {
|
|
|
300
365
|
});
|
|
301
366
|
}
|
|
302
367
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
368
|
+
// An older helper answers an unknown tool name as done, which would end
|
|
369
|
+
// the session with nothing run.
|
|
370
|
+
if (
|
|
371
|
+
toolName === SEQUENCE_TOOL &&
|
|
372
|
+
!clientAdvertises(resolvedTargetClientId, "host_cu_sequence")
|
|
373
|
+
) {
|
|
374
|
+
return Promise.resolve({
|
|
375
|
+
content:
|
|
376
|
+
"Batched actions require a desktop app that supports computer_use_sequence; update the desktop app, or send the actions one at a time. Nothing was run.",
|
|
377
|
+
isError: true,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
const scopedObservation = hasCaptureTarget(input);
|
|
307
381
|
if (scopedObservation) {
|
|
308
382
|
this._previousAXTree = undefined;
|
|
309
383
|
this._consecutiveUnchangedSteps = 0;
|
|
310
384
|
}
|
|
385
|
+
const targetKey = observedTargetKey(resolvedTargetClientId);
|
|
386
|
+
// Pointing never reaches the helper's capture path, so its input goes out
|
|
387
|
+
// as given. Every other request carries the screenshot decision made now,
|
|
388
|
+
// at dispatch, and never the model-facing snake_case key.
|
|
389
|
+
let dispatchInput = input;
|
|
390
|
+
let screenshotSkipped = false;
|
|
391
|
+
if (toolName !== POINT_AT_PROXY_TOOL) {
|
|
392
|
+
const { include_screenshot: _includeScreenshot, ...rest } = input;
|
|
393
|
+
screenshotSkipped = !this.shouldAttachScreenshot(
|
|
394
|
+
toolName,
|
|
395
|
+
input,
|
|
396
|
+
targetKey,
|
|
397
|
+
);
|
|
398
|
+
dispatchInput = screenshotSkipped
|
|
399
|
+
? { ...rest, includeScreenshot: false }
|
|
400
|
+
: rest;
|
|
401
|
+
}
|
|
311
402
|
const requestId = uuid();
|
|
312
403
|
|
|
313
404
|
return new Promise<ToolExecutionResult>((resolve, reject) => {
|
|
@@ -351,7 +442,15 @@ export class HostCuProxy {
|
|
|
351
442
|
detachAbort = () => signal.removeEventListener("abort", onAbort);
|
|
352
443
|
}
|
|
353
444
|
|
|
354
|
-
this._ownedRequests.set(requestId,
|
|
445
|
+
this._ownedRequests.set(requestId, {
|
|
446
|
+
scoped: scopedObservation,
|
|
447
|
+
screenshotSkipped,
|
|
448
|
+
targetKey,
|
|
449
|
+
resetGeneration: this._resetGeneration,
|
|
450
|
+
dispatchedAt: Date.now(),
|
|
451
|
+
toolName,
|
|
452
|
+
step: stepNumber,
|
|
453
|
+
});
|
|
355
454
|
|
|
356
455
|
pendingInteractions.register(requestId, {
|
|
357
456
|
conversationId,
|
|
@@ -375,7 +474,7 @@ export class HostCuProxy {
|
|
|
375
474
|
requestId,
|
|
376
475
|
conversationId,
|
|
377
476
|
toolName,
|
|
378
|
-
input,
|
|
477
|
+
input: dispatchInput,
|
|
379
478
|
stepNumber,
|
|
380
479
|
reasoning,
|
|
381
480
|
...(resolvedTargetClientId != null
|
|
@@ -403,7 +502,8 @@ export class HostCuProxy {
|
|
|
403
502
|
requestId: string,
|
|
404
503
|
observation: CuObservationResult,
|
|
405
504
|
): ToolExecutionResult | undefined {
|
|
406
|
-
const
|
|
505
|
+
const owned = this._ownedRequests.get(requestId);
|
|
506
|
+
const scopedObservation = owned?.scoped ?? false;
|
|
407
507
|
this._ownedRequests.delete(requestId);
|
|
408
508
|
const interaction = pendingInteractions.resolve(requestId, "answered");
|
|
409
509
|
if (!interaction?.rpcResolve) {
|
|
@@ -411,9 +511,33 @@ export class HostCuProxy {
|
|
|
411
511
|
return undefined;
|
|
412
512
|
}
|
|
413
513
|
|
|
514
|
+
// Label the line from what this request was dispatched with, never from
|
|
515
|
+
// current proxy state. One model response can dispatch several CU tools,
|
|
516
|
+
// and the agent loop runs them concurrently, so a later call can advance
|
|
517
|
+
// the history and the step count before an earlier observation lands.
|
|
518
|
+
// Reading them here would file each measurement under whichever tool was
|
|
519
|
+
// dispatched last, and would mislabel computer_use_point_at, which never
|
|
520
|
+
// records an action at all.
|
|
521
|
+
if (owned) {
|
|
522
|
+
log.info(
|
|
523
|
+
{
|
|
524
|
+
requestId,
|
|
525
|
+
toolName: owned.toolName,
|
|
526
|
+
step: owned.step,
|
|
527
|
+
roundTripMs: Date.now() - owned.dispatchedAt,
|
|
528
|
+
...(observation.timings ? { helper: observation.timings } : {}),
|
|
529
|
+
},
|
|
530
|
+
"Host CU step timings",
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
|
|
414
534
|
// A targeted snapshot has no comparable action/diff baseline; neither it
|
|
415
535
|
// nor the first desktop observation after it can imply "no visible effect".
|
|
416
|
-
|
|
536
|
+
// A response dispatched before the last reset belongs to a finished run,
|
|
537
|
+
// so it must not change any state the new run has started building.
|
|
538
|
+
const fromCurrentRun =
|
|
539
|
+
owned === undefined || owned.resetGeneration === this._resetGeneration;
|
|
540
|
+
if (scopedObservation && fromCurrentRun) {
|
|
417
541
|
this._previousAXTree = undefined;
|
|
418
542
|
this._consecutiveUnchangedSteps = 0;
|
|
419
543
|
}
|
|
@@ -421,10 +545,24 @@ export class HostCuProxy {
|
|
|
421
545
|
const comparableObservation = scopedObservation
|
|
422
546
|
? { ...observation, axDiff: undefined, secondaryWindows: undefined }
|
|
423
547
|
: observation;
|
|
424
|
-
|
|
548
|
+
// Pointing observes nothing, so its response leaves the screen state alone.
|
|
549
|
+
if (
|
|
550
|
+
fromCurrentRun &&
|
|
551
|
+
!scopedObservation &&
|
|
552
|
+
owned?.toolName !== POINT_AT_PROXY_TOOL
|
|
553
|
+
) {
|
|
425
554
|
this.updateStateFromObservation(comparableObservation);
|
|
555
|
+
// A desktop has had its first look only once pixels from it arrived,
|
|
556
|
+
// so a failed capture leaves the next request asking again.
|
|
557
|
+
if (owned && observation.screenshot) {
|
|
558
|
+
this._observedTargets.add(owned.targetKey);
|
|
559
|
+
}
|
|
426
560
|
}
|
|
427
|
-
const result = this.formatObservation(
|
|
561
|
+
const result = this.formatObservation(
|
|
562
|
+
comparableObservation,
|
|
563
|
+
prevAXTree,
|
|
564
|
+
owned?.screenshotSkipped ?? false,
|
|
565
|
+
);
|
|
428
566
|
interaction.rpcResolve(result);
|
|
429
567
|
return result;
|
|
430
568
|
}
|
|
@@ -460,6 +598,27 @@ export class HostCuProxy {
|
|
|
460
598
|
this._previousAXTree = undefined;
|
|
461
599
|
this._consecutiveUnchangedSteps = 0;
|
|
462
600
|
this._actionHistory = [];
|
|
601
|
+
this._observedTargets.clear();
|
|
602
|
+
this._resetGeneration++;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Whether the request about to be dispatched should carry a screenshot. The
|
|
607
|
+
* accessibility tree comes back every step. Pixels come back on the first
|
|
608
|
+
* look since the last reset, for a window- or display-scoped capture, and
|
|
609
|
+
* when the model asks for them. Otherwise whether the tree is enough is the
|
|
610
|
+
* model's call.
|
|
611
|
+
*/
|
|
612
|
+
private shouldAttachScreenshot(
|
|
613
|
+
toolName: string,
|
|
614
|
+
input: Record<string, unknown>,
|
|
615
|
+
targetKey: string,
|
|
616
|
+
): boolean {
|
|
617
|
+
return (
|
|
618
|
+
!this._observedTargets.has(targetKey) ||
|
|
619
|
+
hasCaptureTarget(input) ||
|
|
620
|
+
(toolName === "computer_use_observe" && input.include_screenshot === true)
|
|
621
|
+
);
|
|
463
622
|
}
|
|
464
623
|
|
|
465
624
|
// ---------------------------------------------------------------------------
|
|
@@ -474,6 +633,7 @@ export class HostCuProxy {
|
|
|
474
633
|
formatObservation(
|
|
475
634
|
obs: CuObservationResult,
|
|
476
635
|
previousAXTree?: string,
|
|
636
|
+
screenshotSkipped = false,
|
|
477
637
|
): ToolExecutionResult {
|
|
478
638
|
const prevTree = previousAXTree;
|
|
479
639
|
const parts: string[] = [];
|
|
@@ -552,6 +712,15 @@ export class HostCuProxy {
|
|
|
552
712
|
parts.push(...screenshotMeta);
|
|
553
713
|
}
|
|
554
714
|
|
|
715
|
+
// Only a deliberate omission is announced, and only beside a tree the line
|
|
716
|
+
// can point at. A step that asked for pixels and got none is a capture
|
|
717
|
+
// failure, which this line must not disguise. A refused or failed step
|
|
718
|
+
// still carries the line, since that is where asking for pixels helps most.
|
|
719
|
+
const isError = obs.executionError != null;
|
|
720
|
+
if (screenshotSkipped && !obs.screenshot && obs.axTree) {
|
|
721
|
+
parts.push("", SCREENSHOT_OMITTED_MESSAGE);
|
|
722
|
+
}
|
|
723
|
+
|
|
555
724
|
const content = parts.join("\n").trim() || "Action executed";
|
|
556
725
|
|
|
557
726
|
const contentBlocks: ContentBlock[] = [];
|
|
@@ -566,8 +735,6 @@ export class HostCuProxy {
|
|
|
566
735
|
});
|
|
567
736
|
}
|
|
568
737
|
|
|
569
|
-
const isError = obs.executionError != null;
|
|
570
|
-
|
|
571
738
|
return {
|
|
572
739
|
content: isError
|
|
573
740
|
? `Action failed: ${obs.executionError}\n\n${content}`
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
broadcastMessage,
|
|
7
7
|
} from "../runtime/assistant-event-hub.js";
|
|
8
8
|
import {
|
|
9
|
-
ambiguousSameUserError,
|
|
10
9
|
enforceSameActorOrErrorResult,
|
|
11
|
-
|
|
10
|
+
pickMostRecentSameUserClient,
|
|
12
11
|
snapshotHostProxyActorPrincipalId,
|
|
12
|
+
unavailableSameUserClientError,
|
|
13
13
|
} from "../runtime/auth/same-actor.js";
|
|
14
14
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
15
15
|
import { readAudioBase64 } from "../tools/shared/filesystem/audio-read.js";
|
|
@@ -102,19 +102,17 @@ export class HostFileProxy {
|
|
|
102
102
|
});
|
|
103
103
|
}
|
|
104
104
|
} else {
|
|
105
|
-
|
|
106
|
-
// (multi-machine) cases so a single targeted-style request cannot
|
|
107
|
-
// fan out across the user's machines.
|
|
108
|
-
const resolved = pickSameUserAutoResolve({
|
|
105
|
+
resolvedTargetClientId = pickMostRecentSameUserClient({
|
|
109
106
|
hub: assistantEventHub,
|
|
110
107
|
capability: "host_file",
|
|
111
108
|
sourceActorPrincipalId,
|
|
112
109
|
});
|
|
113
|
-
if (
|
|
114
|
-
|
|
110
|
+
if (
|
|
111
|
+
resolvedTargetClientId === undefined &&
|
|
112
|
+
sourceActorPrincipalId !== undefined
|
|
113
|
+
) {
|
|
114
|
+
return Promise.resolve(unavailableSameUserClientError("host_file"));
|
|
115
115
|
}
|
|
116
|
-
resolvedTargetClientId =
|
|
117
|
-
resolved.kind === "match" ? resolved.clientId : undefined;
|
|
118
116
|
}
|
|
119
117
|
|
|
120
118
|
// Same-user check: targeted host_file requests must be bound to the same
|
|
@@ -105,12 +105,13 @@ export const HOST_PROXY_SKILL_PREACTIVATIONS: ReadonlyArray<{
|
|
|
105
105
|
*/
|
|
106
106
|
/**
|
|
107
107
|
* Capabilities a client asks for on its connection rather than getting from
|
|
108
|
-
* what it is.
|
|
108
|
+
* what it is. Each rides the host_cu transport and is answered only by a
|
|
109
109
|
* macOS build new enough to send the header (`events-routes.ts`), so the
|
|
110
110
|
* interface alone cannot say whether one is really there.
|
|
111
111
|
*/
|
|
112
112
|
const NEGOTIATED_CAPABILITIES: ReadonlySet<HostProxyCapability> = new Set([
|
|
113
113
|
"host_cu_window_capture",
|
|
114
|
+
"host_cu_sequence",
|
|
114
115
|
"host_cu_annotate",
|
|
115
116
|
]);
|
|
116
117
|
|