@vellumai/assistant 0.8.10 → 0.8.11-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/bun.lock +62 -1
- package/docs/workspace-tools.md +196 -0
- package/examples/plugins/echo/README.md +3 -3
- package/knip.json +1 -0
- package/openapi.yaml +460 -128
- package/package.json +2 -1
- package/scripts/build-plugin-api.ts +299 -0
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +7 -0
- package/src/__tests__/agent-loop-compaction-events.test.ts +197 -0
- package/src/__tests__/agent-loop-exit-reason.test.ts +93 -96
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +2 -0
- package/src/__tests__/agent-loop-output-hooks.test.ts +274 -1
- package/src/__tests__/agent-loop-override-profile.test.ts +3 -0
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +4 -0
- package/src/__tests__/agent-loop-thinking.test.ts +4 -0
- package/src/__tests__/agent-loop.test.ts +578 -5
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -1
- package/src/__tests__/approval-cascade.test.ts +1 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
- package/src/__tests__/btw-routes.test.ts +0 -1
- package/src/__tests__/build-persisted-content.test.ts +75 -1
- package/src/__tests__/catalog-install-normalize.test.ts +141 -0
- package/src/__tests__/ces-startup-timeout.test.ts +60 -0
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
- package/src/__tests__/context-overflow-reducer.test.ts +264 -124
- package/src/__tests__/context-window-manager-overflow-rung.test.ts +351 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +13 -5
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +284 -455
- package/src/__tests__/conversation-agent-loop.test.ts +131 -551
- package/src/__tests__/conversation-app-control-instantiation.test.ts +13 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
- package/src/__tests__/conversation-fork-crud.test.ts +259 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-lifecycle.test.ts +257 -1
- package/src/__tests__/conversation-process-callsite.test.ts +1 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +38 -377
- package/src/__tests__/conversation-queue.test.ts +1 -39
- package/src/__tests__/conversation-runtime-assembly.test.ts +119 -8
- package/src/__tests__/conversation-skill-tools.test.ts +491 -5
- package/src/__tests__/conversation-slash-queue.test.ts +1 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -0
- package/src/__tests__/conversation-speed-override.test.ts +1 -0
- package/src/__tests__/conversation-store.test.ts +74 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +4 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +323 -0
- package/src/__tests__/conversation-tool-setup-tools-disabled.test.ts +34 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -0
- package/src/__tests__/corrected-target.test.ts +93 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +3 -5
- package/src/__tests__/credential-execution-tools.test.ts +23 -11
- package/src/__tests__/credential-security-invariants.test.ts +6 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +80 -0
- package/src/__tests__/device-id.test.ts +70 -1
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
- package/src/__tests__/empty-response-hook.test.ts +242 -66
- package/src/__tests__/external-plugin-loader.test.ts +0 -31
- package/src/__tests__/get-skill-detail-audit.test.ts +43 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +91 -0
- package/src/__tests__/history-repair-hook.test.ts +228 -3
- package/src/__tests__/host-app-control-proxy.test.ts +45 -0
- package/src/__tests__/host-browser-proxy.test.ts +254 -9
- package/src/__tests__/identity-routes.test.ts +1 -0
- package/src/__tests__/image-recovery-hook.test.ts +387 -0
- package/src/__tests__/injector-chain.test.ts +5 -4
- package/src/__tests__/injector-v3-suppression.test.ts +373 -47
- package/src/__tests__/intent-routing.test.ts +7 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +117 -15
- package/src/__tests__/notification-decision-strategy.test.ts +3 -3
- package/src/__tests__/oauth-store.test.ts +0 -85
- package/src/__tests__/{context-overflow-policy.test.ts → overflow-policy.test.ts} +1 -1
- package/src/__tests__/parallel-tool.benchmark.test.ts +4 -0
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +29 -9
- package/src/__tests__/persist-unsendable-image.test.ts +4 -4
- package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
- package/src/__tests__/plugin-bootstrap.test.ts +82 -73
- package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
- package/src/__tests__/plugin-types.test.ts +0 -8
- package/src/__tests__/provider-catalog-visibility.test.ts +1 -9
- package/src/__tests__/prune-old-conversations-job.test.ts +99 -0
- package/src/__tests__/registry.test.ts +240 -1
- package/src/__tests__/require-fresh-approval.test.ts +3 -0
- package/src/__tests__/schedule-routes.test.ts +116 -1
- package/src/__tests__/schedule-store.test.ts +28 -0
- package/src/__tests__/schedule-tools.test.ts +94 -1
- package/src/__tests__/server-history-render.test.ts +39 -0
- package/src/__tests__/skill-projection-feature-flag.test.ts +13 -0
- package/src/__tests__/skill-projection.benchmark.test.ts +25 -7
- package/src/__tests__/skills.test.ts +202 -0
- package/src/__tests__/slim-skill-category.test.ts +195 -0
- package/src/__tests__/strip-memory-injections.test.ts +33 -39
- package/src/__tests__/test-support/tool-invocation-seed.ts +79 -0
- package/src/__tests__/title-generate-hook.test.ts +9 -7
- package/src/__tests__/tool-audit-listener.test.ts +264 -1
- package/src/__tests__/tool-error-hook.test.ts +4 -3
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +273 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +1 -0
- package/src/__tests__/tool-start-timestamp.test.ts +218 -0
- package/src/__tests__/tools-get-route.test.ts +202 -0
- package/src/__tests__/workspace-tool-loader.test.ts +319 -0
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
- package/src/agent/loop.ts +569 -319
- package/src/api/events/tool-result.ts +9 -0
- package/src/api/events/tool-use-start.ts +7 -0
- package/src/api/index.ts +10 -0
- package/src/api/responses/conversation-message.ts +135 -27
- package/src/api/responses/memory-v3-selection-log.ts +4 -4
- package/src/approvals/guardian-request-resolvers.ts +26 -0
- package/src/browser-session/backends/host-bridge.ts +29 -0
- package/src/browser-session/index.ts +1 -0
- package/src/browser-session/types.ts +5 -1
- package/src/cli/commands/__tests__/schedules.test.ts +62 -4
- package/src/cli/commands/__tests__/skills.test.ts +53 -0
- package/src/cli/commands/channel-verification-sessions.ts +6 -6
- package/src/cli/commands/inference-providers.ts +0 -8
- package/src/cli/commands/plugins.ts +2 -2
- package/src/cli/commands/schedules.ts +27 -4
- package/src/cli/commands/skills.ts +187 -146
- package/src/cli/commands/tools.ts +106 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +256 -328
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +6 -2
- package/src/cli/lib/__tests__/plugin-details.test.ts +10 -16
- package/src/cli/lib/__tests__/plugin-marketplace.test.ts +2 -2
- package/src/cli/lib/__tests__/search-plugins.test.ts +145 -240
- package/src/cli/lib/install-from-github.ts +187 -117
- package/src/cli/lib/plugin-catalog-cache.ts +9 -9
- package/src/cli/lib/plugin-details.ts +38 -68
- package/src/cli/lib/plugin-marketplace.ts +42 -14
- package/src/cli/lib/search-plugins.ts +29 -129
- package/src/cli/program.ts +2 -0
- package/src/config/bundled-skills/acp/SKILL.md +1 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -0
- package/src/config/bundled-skills/app-control/SKILL.md +1 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +1 -0
- package/src/config/bundled-skills/contacts/SKILL.md +1 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +1 -0
- package/src/config/bundled-skills/followups/SKILL.md +1 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +1 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +1 -0
- package/src/config/bundled-skills/messaging/SKILL.md +1 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -0
- package/src/config/bundled-skills/playbooks/SKILL.md +1 -0
- package/src/config/bundled-skills/schedule/SKILL.md +1 -0
- package/src/config/bundled-skills/schedule/TOOLS.json +11 -3
- package/src/config/bundled-skills/sequences/SKILL.md +1 -0
- package/src/config/bundled-skills/settings/SKILL.md +1 -0
- package/src/config/bundled-skills/skill-management/SKILL.md +101 -1
- package/src/config/bundled-skills/subagent/SKILL.md +1 -0
- package/src/config/bundled-skills/transcribe/SKILL.md +1 -0
- package/src/config/env-registry.ts +23 -0
- package/src/config/feature-flag-registry.json +17 -81
- package/src/config/loader.ts +5 -22
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/compaction-logs.test.ts +56 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +0 -1
- package/src/config/schemas/__tests__/memory-v3.test.ts +61 -1
- package/src/config/schemas/compaction-logs.ts +79 -0
- package/src/config/schemas/memory-v2.ts +0 -8
- package/src/config/schemas/memory-v3.ts +104 -33
- package/src/config/seed-inference-profiles.ts +1 -1
- package/src/config/skills.ts +117 -47
- package/src/context/compactor.ts +11 -0
- package/src/context/strip-injections.ts +38 -4
- package/src/credential-execution/feature-gates.ts +0 -21
- package/src/credential-execution/startup-timeout.ts +32 -4
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +18 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +140 -91
- package/src/daemon/conversation-agent-loop.ts +123 -658
- package/src/daemon/conversation-error.ts +6 -33
- package/src/daemon/conversation-lifecycle.ts +1 -1
- package/src/daemon/conversation-runtime-assembly.ts +183 -22
- package/src/daemon/conversation-skill-tools.ts +137 -8
- package/src/daemon/conversation-slash.ts +0 -14
- package/src/daemon/conversation-store.ts +2 -19
- package/src/daemon/conversation-tool-setup.ts +87 -1
- package/src/daemon/conversation.ts +119 -50
- package/src/daemon/external-plugins-bootstrap.ts +36 -95
- package/src/daemon/handlers/config-channels.ts +11 -2
- package/src/daemon/handlers/shared.ts +9 -1
- package/src/daemon/handlers/skills.ts +10 -4
- package/src/daemon/host-app-control-proxy.ts +72 -57
- package/src/daemon/host-browser-proxy.ts +117 -22
- package/src/daemon/lifecycle.ts +34 -5
- package/src/daemon/message-protocol.ts +0 -7
- package/src/daemon/message-types/schedules.ts +1 -0
- package/src/daemon/message-types/skills.ts +17 -0
- package/src/daemon/providers-setup.ts +3 -0
- package/src/daemon/server.ts +3 -3
- package/src/daemon/tool-setup-types.ts +9 -3
- package/src/daemon/trust-context.ts +23 -0
- package/src/daemon/workspace-tools-watcher.ts +324 -0
- package/src/events/tool-audit-listener.ts +78 -16
- package/src/events/tool-metrics-listener.ts +2 -5
- package/src/memory/__tests__/compaction-log-writer-clickhouse.test.ts +227 -0
- package/src/memory/__tests__/conversation-queries.test.ts +176 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +20 -32
- package/src/memory/compaction-log-writer-clickhouse.ts +418 -0
- package/src/memory/conversation-crud.ts +134 -3
- package/src/memory/conversation-queries.ts +64 -7
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.test.ts +130 -1
- package/src/memory/embedding-backend.ts +79 -106
- package/src/memory/embedding-gemini.ts +5 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +12 -0
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +19 -0
- package/src/memory/graph/conversation-graph-memory.ts +36 -25
- package/src/memory/graph/tool-handlers.ts +3 -0
- package/src/memory/job-handlers/cleanup.ts +3 -1
- package/src/memory/jobs-store.ts +0 -28
- package/src/memory/jobs-worker.ts +10 -22
- package/src/memory/memory-marker.ts +29 -0
- package/src/memory/memory-retrospective-startup-cleanup.ts +1 -1
- package/src/memory/migrations/268-add-memory-v3-selections.ts +6 -0
- package/src/memory/migrations/270-schedule-description.ts +36 -0
- package/src/memory/migrations/275-tool-invocations-add-skill-id.test.ts +81 -0
- package/src/memory/migrations/275-tool-invocations-add-skill-id.ts +20 -0
- package/src/memory/migrations/276-tool-invocations-created-at-id-index.test.ts +68 -0
- package/src/memory/migrations/276-tool-invocations-created-at-id-index.ts +20 -0
- package/src/memory/migrations/277-add-memory-v3-ever-injected.ts +29 -0
- package/src/memory/migrations/278-tool-invocations-telemetry-columns.test.ts +96 -0
- package/src/memory/migrations/278-tool-invocations-telemetry-columns.ts +39 -0
- package/src/memory/migrations/279-create-skill-loaded-events.test.ts +84 -0
- package/src/memory/migrations/279-create-skill-loaded-events.ts +26 -0
- package/src/memory/migrations/280-conversations-surfaced-at.test.ts +88 -0
- package/src/memory/migrations/280-conversations-surfaced-at.ts +24 -0
- package/src/memory/migrations/index.ts +10 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/schema/conversations.ts +16 -0
- package/src/memory/schema/infrastructure.ts +26 -0
- package/src/memory/skill-loaded-events-store.test.ts +160 -0
- package/src/memory/skill-loaded-events-store.ts +95 -0
- package/src/memory/tool-executed-events-store.test.ts +219 -0
- package/src/memory/tool-executed-events-store.ts +102 -0
- package/src/memory/tool-usage-store.ts +15 -3
- package/src/memory/v2/__tests__/consolidation-job.test.ts +117 -12
- package/src/memory/v2/__tests__/consolidation-prompt-flag-gating-guard.test.ts +189 -0
- package/src/memory/v2/__tests__/injected-block-slugs.test.ts +90 -0
- package/src/memory/v2/__tests__/page-store.test.ts +33 -0
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +88 -15
- package/src/memory/v2/activation-store.ts +50 -1
- package/src/memory/v2/consolidation-job.ts +113 -29
- package/src/memory/v2/injected-block-slugs.ts +79 -0
- package/src/memory/v2/injection.ts +6 -1
- package/src/memory/v2/prompts/consolidation.ts +414 -13
- package/src/memory/v2/router.ts +2 -28
- package/src/memory/v2/static-context.ts +1 -1
- package/src/memory/v2/types.ts +16 -0
- package/src/notifications/__tests__/copy-composer.test.ts +244 -0
- package/src/notifications/access-request-copy.ts +298 -0
- package/src/notifications/adapters/slack.ts +3 -3
- package/src/notifications/adapters/telegram.ts +2 -1
- package/src/notifications/copy-composer.ts +49 -267
- package/src/notifications/decision-engine.ts +16 -35
- package/src/notifications/home-feed-side-effect.ts +1 -6
- package/src/oauth/oauth-store.ts +0 -9
- package/src/permissions/checker.test.ts +83 -1
- package/src/permissions/checker.ts +25 -2
- package/src/permissions/gateway-threshold-reader.test.ts +182 -0
- package/src/permissions/gateway-threshold-reader.ts +80 -0
- package/src/platform/client.ts +1 -3
- package/src/platform/feature-gate.ts +3 -12
- package/src/plugin-api/constants.ts +4 -2
- package/src/plugin-api/index.ts +63 -11
- package/src/plugin-api/types.ts +236 -71
- package/src/plugins/defaults/compaction/compact.ts +66 -2
- package/src/plugins/defaults/compaction/context-overflow-reducer.ts +240 -32
- package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
- package/src/{daemon/context-overflow-policy.ts → plugins/defaults/compaction/overflow-policy.ts} +1 -1
- package/src/plugins/defaults/compaction/window-manager.ts +303 -1
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +173 -0
- package/src/plugins/defaults/empty-response/hooks/stop.ts +11 -115
- package/src/plugins/defaults/empty-response/nudge-state-store.ts +46 -0
- package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +50 -0
- package/src/plugins/defaults/history-repair/hooks/stop.ts +22 -0
- package/src/plugins/defaults/history-repair/repair-state-store.ts +51 -0
- package/src/plugins/defaults/history-repair/terminal.ts +39 -2
- package/src/plugins/defaults/image-recovery/detect.ts +25 -0
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +73 -0
- package/src/plugins/defaults/image-recovery/hooks/stop.ts +22 -0
- package/src/plugins/defaults/image-recovery/image-recovery-state-store.ts +48 -0
- package/src/plugins/defaults/image-recovery/package.json +14 -0
- package/src/{daemon/persist-unsendable-image.ts → plugins/defaults/image-recovery/recover.ts} +67 -14
- package/src/plugins/defaults/index.ts +71 -5
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +76 -112
- package/src/plugins/defaults/memory-retrieval/hooks/{user-prompt-submit-temp.ts → user-prompt-submit.ts} +83 -74
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +14 -8
- package/src/plugins/defaults/memory-retrieval/injectors.ts +2 -18
- package/src/plugins/defaults/memory-retrieval/package.json +14 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1157 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +683 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +161 -140
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +160 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +335 -316
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +145 -53
- package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +38 -1
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +18 -8
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +112 -71
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +192 -51
- package/src/plugins/defaults/memory-v3-shadow/__tests__/types.test.ts +4 -16
- package/src/plugins/defaults/memory-v3-shadow/card.test.ts +173 -0
- package/src/plugins/defaults/memory-v3-shadow/card.ts +116 -0
- package/src/plugins/defaults/memory-v3-shadow/core-set.test.ts +104 -0
- package/src/plugins/defaults/memory-v3-shadow/core-set.ts +59 -0
- package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.test.ts +305 -0
- package/src/plugins/defaults/memory-v3-shadow/ever-injected-store.ts +278 -0
- package/src/plugins/defaults/memory-v3-shadow/hot-set.test.ts +138 -0
- package/src/plugins/defaults/memory-v3-shadow/hot-set.ts +85 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +331 -24
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +119 -13
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +169 -114
- package/src/plugins/defaults/memory-v3-shadow/page-content.ts +47 -16
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +144 -66
- package/src/plugins/defaults/memory-v3-shadow/prune.test.ts +758 -0
- package/src/plugins/defaults/memory-v3-shadow/prune.ts +471 -0
- package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +68 -16
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +19 -12
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +96 -43
- package/src/plugins/defaults/memory-v3-shadow/types.ts +34 -17
- package/src/plugins/defaults/title-generate/hooks/stop.ts +9 -11
- package/src/plugins/pipeline.ts +8 -5
- package/src/plugins/types.ts +5 -51
- package/src/providers/cache-control.ts +26 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +1 -2
- package/src/providers/model-catalog.ts +13 -1
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +147 -0
- package/src/providers/openai/chat-completions-provider.ts +46 -0
- package/src/providers/openai/responses-provider.ts +45 -0
- package/src/providers/registry.ts +0 -8
- package/src/runtime/__tests__/agent-wake.test.ts +0 -1
- package/src/runtime/agent-wake.ts +13 -0
- package/src/runtime/routes/__tests__/acp-routes.test.ts +151 -0
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +12 -50
- package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +322 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +0 -62
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +31 -11
- package/src/runtime/routes/acp-routes.test.ts +106 -0
- package/src/runtime/routes/acp-routes.ts +248 -2
- package/src/runtime/routes/browser-tabs-routes.ts +1 -1
- package/src/runtime/routes/channel-verification-routes.ts +14 -5
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +0 -14
- package/src/runtime/routes/consolidation-routes.ts +6 -82
- package/src/runtime/routes/conversation-list-routes.ts +6 -0
- package/src/runtime/routes/conversation-management-routes.ts +71 -0
- package/src/runtime/routes/identity-routes.ts +8 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
- package/src/runtime/routes/inference-provider-connection-routes.ts +0 -45
- package/src/runtime/routes/plugins-routes.ts +34 -45
- package/src/runtime/routes/schedule-routes.ts +43 -5
- package/src/runtime/routes/settings-routes.ts +140 -15
- package/src/runtime/routes/skills-routes.ts +18 -6
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +140 -0
- package/src/runtime/services/conversation-serializer.ts +38 -1
- package/src/runtime/verification-outbound-actions.ts +147 -2
- package/src/runtime/verification-templates.ts +29 -3
- package/src/schedule/schedule-store.ts +19 -0
- package/src/skills/catalog-install.ts +77 -13
- package/src/tasks/task-scheduler.ts +1 -0
- package/src/telemetry/types.ts +66 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +542 -13
- package/src/telemetry/usage-telemetry-reporter.ts +213 -20
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +49 -2
- package/src/tools/browser/__tests__/browser-status.test.ts +29 -5
- package/src/tools/browser/browser-execution.ts +27 -9
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +380 -4
- package/src/tools/browser/cdp-client/__tests__/host-bridge-cdp-client.test.ts +107 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +6 -1
- package/src/tools/browser/cdp-client/factory.ts +217 -17
- package/src/tools/browser/cdp-client/host-bridge-cdp-client.ts +67 -0
- package/src/tools/browser/cdp-client/types.ts +22 -2
- package/src/tools/credential-execution/make-authenticated-request.ts +2 -1
- package/src/tools/credential-execution/manage-secure-command-tool.ts +169 -164
- package/src/tools/credential-execution/run-authenticated-command.ts +2 -1
- package/src/tools/executor.ts +39 -7
- package/src/tools/registry.ts +387 -5
- package/src/tools/schedule/create.ts +16 -0
- package/src/tools/schedule/list.ts +12 -4
- package/src/tools/schedule/update.ts +12 -0
- package/src/tools/skills/load.ts +11 -6
- package/src/tools/terminal/safe-env.ts +2 -0
- package/src/tools/types.ts +65 -9
- package/src/tools/workspace-tools/loader.ts +673 -0
- package/src/usage/attribution.ts +28 -0
- package/src/util/device-id.ts +17 -3
- package/src/util/platform.ts +16 -0
- package/tsconfig.plugin-api.json +13 -0
- package/src/__tests__/plugin-external-api.test.ts +0 -68
- package/src/__tests__/plugin-skill-contribution.test.ts +0 -355
- package/src/daemon/message-types/browser.ts +0 -10
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
- package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/eval-turns.json +0 -36
- package/src/plugins/defaults/memory-v3-shadow/__tests__/fixtures/live-turns.json +0 -37
- package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-eviction.test.ts +0 -106
- package/src/plugins/defaults/memory-v3-shadow/__tests__/working-set-skeleton.test.ts +0 -44
- package/src/plugins/defaults/memory-v3-shadow/working-set.ts +0 -91
- package/src/plugins/external-api.ts +0 -114
- package/src/plugins/plugin-skill-contributions.ts +0 -292
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type CdpResult,
|
|
6
6
|
createCdpInspectBackend,
|
|
7
7
|
createExtensionBackend,
|
|
8
|
+
createHostBridgeBackend,
|
|
8
9
|
createLocalBackend,
|
|
9
10
|
} from "../../../browser-session/index.js";
|
|
10
11
|
import { getConfig } from "../../../config/loader.js";
|
|
@@ -15,13 +16,14 @@ import { getPinnedTab } from "../pinned-tabs.js";
|
|
|
15
16
|
import { createCdpInspectClient } from "./cdp-inspect-client.js";
|
|
16
17
|
import { CdpError } from "./errors.js";
|
|
17
18
|
import { createExtensionCdpClient } from "./extension-cdp-client.js";
|
|
19
|
+
import { createHostBridgeCdpClient } from "./host-bridge-cdp-client.js";
|
|
18
20
|
import { createLocalCdpClient } from "./local-cdp-client.js";
|
|
19
21
|
import type {
|
|
20
22
|
AttemptDiagnostic,
|
|
21
23
|
BackendCandidate,
|
|
22
|
-
BrowserMode,
|
|
23
24
|
CdpClient,
|
|
24
25
|
CdpClientKind,
|
|
26
|
+
InternalBrowserMode,
|
|
25
27
|
ScopedCdpClient,
|
|
26
28
|
TabInfo,
|
|
27
29
|
} from "./types.js";
|
|
@@ -52,7 +54,7 @@ let _desktopAutoCooldownSince = 0;
|
|
|
52
54
|
|
|
53
55
|
/**
|
|
54
56
|
* Record a cooldown after a desktop-auto cdp-inspect transport failure.
|
|
55
|
-
* Called by {@link
|
|
57
|
+
* Called by {@link maybeRecordCandidateCooldown} in production; also
|
|
56
58
|
* exported directly for use in tests.
|
|
57
59
|
*/
|
|
58
60
|
export function recordDesktopAutoCooldown(): void {
|
|
@@ -83,6 +85,85 @@ export function _getDesktopAutoCooldownSince(): number {
|
|
|
83
85
|
return _desktopAutoCooldownSince;
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Host-bridge cooldown tracker
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Per-actor timestamps (epoch ms) of the last transport-level failure
|
|
94
|
+
* for a host-bridge attempt. Mirrors the desktop-auto cdp-inspect
|
|
95
|
+
* cooldown above — the failure root cause is the same (the user's
|
|
96
|
+
* Chrome is not exposing a remote-debugging port), just probed through
|
|
97
|
+
* the desktop SSE bridge instead of directly. While the configured
|
|
98
|
+
* `desktopAuto.cooldownMs` window has not elapsed, the factory skips
|
|
99
|
+
* the host-bridge candidate so every browser op doesn't pay an SSE
|
|
100
|
+
* round-trip for a guaranteed failure.
|
|
101
|
+
*
|
|
102
|
+
* **Per-actor scope**: unlike the desktop-auto cooldown (one local
|
|
103
|
+
* machine, so process-global is correct), the bridge reaches a
|
|
104
|
+
* different desktop machine per actor on a multi-actor cloud daemon —
|
|
105
|
+
* one actor's missing debug port must not suppress another actor's
|
|
106
|
+
* only route to their own Chrome. Callers without a resolved actor
|
|
107
|
+
* share the `__default__` slot.
|
|
108
|
+
*/
|
|
109
|
+
const _hostBridgeCooldownSince = new Map<string, number>();
|
|
110
|
+
|
|
111
|
+
/** Entries older than this are swept on record to bound map growth. */
|
|
112
|
+
const HOST_BRIDGE_COOLDOWN_SWEEP_MS = 60 * 60 * 1000;
|
|
113
|
+
|
|
114
|
+
function hostBridgeCooldownKey(sourceActorPrincipalId?: string): string {
|
|
115
|
+
return sourceActorPrincipalId ?? "__default__";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Record a cooldown after a host-bridge transport failure for this actor. */
|
|
119
|
+
export function recordHostBridgeCooldown(
|
|
120
|
+
sourceActorPrincipalId?: string,
|
|
121
|
+
): void {
|
|
122
|
+
const now = Date.now();
|
|
123
|
+
for (const [key, since] of _hostBridgeCooldownSince) {
|
|
124
|
+
if (now - since >= HOST_BRIDGE_COOLDOWN_SWEEP_MS) {
|
|
125
|
+
_hostBridgeCooldownSince.delete(key);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
_hostBridgeCooldownSince.set(
|
|
129
|
+
hostBridgeCooldownKey(sourceActorPrincipalId),
|
|
130
|
+
now,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Whether the host-bridge cooldown is currently active for this actor.
|
|
136
|
+
* Returns `true` if a failure was recorded and the configured cooldown
|
|
137
|
+
* window has not yet elapsed.
|
|
138
|
+
*/
|
|
139
|
+
export function isHostBridgeCooldownActive(
|
|
140
|
+
cooldownMs: number,
|
|
141
|
+
sourceActorPrincipalId?: string,
|
|
142
|
+
): boolean {
|
|
143
|
+
if (cooldownMs <= 0) return false;
|
|
144
|
+
const since = _hostBridgeCooldownSince.get(
|
|
145
|
+
hostBridgeCooldownKey(sourceActorPrincipalId),
|
|
146
|
+
);
|
|
147
|
+
if (since === undefined) return false;
|
|
148
|
+
return Date.now() - since < cooldownMs;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Reset the host-bridge cooldown state. Exported for testing only. */
|
|
152
|
+
export function _resetHostBridgeCooldown(): void {
|
|
153
|
+
_hostBridgeCooldownSince.clear();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Get the raw cooldown-since timestamp for an actor. Exported for testing only. */
|
|
157
|
+
export function _getHostBridgeCooldownSince(
|
|
158
|
+
sourceActorPrincipalId?: string,
|
|
159
|
+
): number {
|
|
160
|
+
return (
|
|
161
|
+
_hostBridgeCooldownSince.get(
|
|
162
|
+
hostBridgeCooldownKey(sourceActorPrincipalId),
|
|
163
|
+
) ?? 0
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
86
167
|
// ---------------------------------------------------------------------------
|
|
87
168
|
// Public API
|
|
88
169
|
// ---------------------------------------------------------------------------
|
|
@@ -96,9 +177,10 @@ export interface GetCdpClientOptions {
|
|
|
96
177
|
* Backend mode preference. When omitted or `"auto"`, the factory
|
|
97
178
|
* uses the existing priority-ordered fallback chain. When set to a
|
|
98
179
|
* specific backend kind, the factory pins to that single backend
|
|
99
|
-
* and disables failover.
|
|
180
|
+
* and disables failover. `"host-bridge"` is internal-only (sticky
|
|
181
|
+
* conversation memo), never user-requestable.
|
|
100
182
|
*/
|
|
101
|
-
mode?:
|
|
183
|
+
mode?: InternalBrowserMode;
|
|
102
184
|
/**
|
|
103
185
|
* Explicit target client id. When provided, the extension backend routes
|
|
104
186
|
* to this specific client instead of auto-resolving to the most-recently-
|
|
@@ -159,7 +241,7 @@ export function getCdpClient(
|
|
|
159
241
|
context: ToolContext,
|
|
160
242
|
options?: GetCdpClientOptions,
|
|
161
243
|
): ScopedCdpClient {
|
|
162
|
-
const mode:
|
|
244
|
+
const mode: InternalBrowserMode = options?.mode ?? "auto";
|
|
163
245
|
const targetClientId = options?.targetClientId;
|
|
164
246
|
const candidates =
|
|
165
247
|
mode === "auto"
|
|
@@ -191,7 +273,7 @@ export function getCdpClient(
|
|
|
191
273
|
*/
|
|
192
274
|
export function buildPinnedCandidateList(
|
|
193
275
|
context: ToolContext,
|
|
194
|
-
mode: Exclude<
|
|
276
|
+
mode: Exclude<InternalBrowserMode, "auto">,
|
|
195
277
|
targetClientId?: string,
|
|
196
278
|
): BackendCandidate[] {
|
|
197
279
|
const { conversationId, sourceActorPrincipalId } = context;
|
|
@@ -199,7 +281,7 @@ export function buildPinnedCandidateList(
|
|
|
199
281
|
switch (mode) {
|
|
200
282
|
case "extension": {
|
|
201
283
|
const hostBrowserProxy = HostBrowserProxy.instance;
|
|
202
|
-
if (!hostBrowserProxy.hasExtensionClient()) {
|
|
284
|
+
if (!hostBrowserProxy.hasExtensionClient(sourceActorPrincipalId)) {
|
|
203
285
|
throw new CdpError(
|
|
204
286
|
"transport_error",
|
|
205
287
|
`Pinned mode "extension" unavailable: no Chrome Extension connected`,
|
|
@@ -267,6 +349,48 @@ export function buildPinnedCandidateList(
|
|
|
267
349
|
},
|
|
268
350
|
];
|
|
269
351
|
}
|
|
352
|
+
case "host-bridge": {
|
|
353
|
+
// Reached only via the conversation's sticky-backend memo after a
|
|
354
|
+
// successful bridge send — never via --browser-mode. Throwing when
|
|
355
|
+
// an extension has since connected (not just when the bridge is
|
|
356
|
+
// gone) deliberately trips the caller's sticky-fallback retry,
|
|
357
|
+
// which clears the memo and re-runs auto mode so the conversation
|
|
358
|
+
// upgrades to the extension candidate with correct kind labeling.
|
|
359
|
+
const hostBrowserProxy = HostBrowserProxy.instance;
|
|
360
|
+
if (
|
|
361
|
+
!hostBrowserProxy.isAvailable(sourceActorPrincipalId) ||
|
|
362
|
+
hostBrowserProxy.hasExtensionClient(sourceActorPrincipalId)
|
|
363
|
+
) {
|
|
364
|
+
const errorMessage = hostBrowserProxy.hasExtensionClient(
|
|
365
|
+
sourceActorPrincipalId,
|
|
366
|
+
)
|
|
367
|
+
? "a Chrome Extension is now connected"
|
|
368
|
+
: "no host_browser bridge client connected";
|
|
369
|
+
throw new CdpError(
|
|
370
|
+
"transport_error",
|
|
371
|
+
`Pinned mode "host-bridge" unavailable: ${errorMessage}`,
|
|
372
|
+
{
|
|
373
|
+
attemptDiagnostics: [
|
|
374
|
+
{
|
|
375
|
+
candidateKind: "host-bridge",
|
|
376
|
+
inclusionReason: "pinned mode: host-bridge",
|
|
377
|
+
stage: "candidate_selection",
|
|
378
|
+
errorCode: "transport_error",
|
|
379
|
+
errorMessage,
|
|
380
|
+
},
|
|
381
|
+
],
|
|
382
|
+
},
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
return [
|
|
386
|
+
makeHostBridgeCandidate(
|
|
387
|
+
hostBrowserProxy,
|
|
388
|
+
conversationId,
|
|
389
|
+
sourceActorPrincipalId,
|
|
390
|
+
"pinned mode: host-bridge (conversation sticky memo)",
|
|
391
|
+
),
|
|
392
|
+
];
|
|
393
|
+
}
|
|
270
394
|
case "local": {
|
|
271
395
|
return [
|
|
272
396
|
{
|
|
@@ -315,7 +439,7 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
|
|
|
315
439
|
// unavailable, fail loudly rather than silently routing to a different
|
|
316
440
|
// browser.
|
|
317
441
|
if (targetClientId != null) {
|
|
318
|
-
if (!hostBrowserProxy.hasExtensionClient()) {
|
|
442
|
+
if (!hostBrowserProxy.hasExtensionClient(sourceActorPrincipalId)) {
|
|
319
443
|
throw new CdpError(
|
|
320
444
|
"transport_error",
|
|
321
445
|
`Cannot reach target_client_id "${targetClientId}": no Chrome Extension connected`,
|
|
@@ -360,7 +484,11 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
|
|
|
360
484
|
}
|
|
361
485
|
|
|
362
486
|
// 1. Extension -- preferred when a Chrome Extension client is connected.
|
|
363
|
-
|
|
487
|
+
// Availability checks are actor-scoped: on a multi-actor cloud daemon,
|
|
488
|
+
// another actor's extension must not select extension-labelled
|
|
489
|
+
// transports for this conversation (the proxy would refuse to
|
|
490
|
+
// dispatch to it anyway).
|
|
491
|
+
if (hostBrowserProxy.hasExtensionClient(sourceActorPrincipalId)) {
|
|
364
492
|
candidates.push({
|
|
365
493
|
kind: "extension",
|
|
366
494
|
reason: "Chrome Extension connected via registry singleton",
|
|
@@ -385,6 +513,33 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
|
|
|
385
513
|
return { client, backend };
|
|
386
514
|
},
|
|
387
515
|
});
|
|
516
|
+
} else if (hostBrowserProxy.isAvailable(sourceActorPrincipalId)) {
|
|
517
|
+
// 1b. Host bridge -- a host_browser-capable client (the desktop SSE
|
|
518
|
+
// bridge) is connected but no Chrome Extension. Raw CDP commands are
|
|
519
|
+
// proxied to the user's machine and executed against Chrome's local
|
|
520
|
+
// remote-debugging port. This is the only route to the user's own
|
|
521
|
+
// Chrome when the daemon runs remotely (cloud), where cdp-inspect
|
|
522
|
+
// would dial the daemon's localhost instead.
|
|
523
|
+
const { cooldownMs } = getConfig().hostBrowser.cdpInspect.desktopAuto;
|
|
524
|
+
if (isHostBridgeCooldownActive(cooldownMs, sourceActorPrincipalId)) {
|
|
525
|
+
log.debug(
|
|
526
|
+
{
|
|
527
|
+
conversationId,
|
|
528
|
+
cooldownMs,
|
|
529
|
+
cooldownSince: _getHostBridgeCooldownSince(sourceActorPrincipalId),
|
|
530
|
+
},
|
|
531
|
+
"CDP factory: host-bridge skipped (cooldown active)",
|
|
532
|
+
);
|
|
533
|
+
} else {
|
|
534
|
+
candidates.push(
|
|
535
|
+
makeHostBridgeCandidate(
|
|
536
|
+
hostBrowserProxy,
|
|
537
|
+
conversationId,
|
|
538
|
+
sourceActorPrincipalId,
|
|
539
|
+
"host_browser bridge connected (no Chrome Extension); raw CDP via desktop SSE bridge",
|
|
540
|
+
),
|
|
541
|
+
);
|
|
542
|
+
}
|
|
388
543
|
} else {
|
|
389
544
|
log.debug(
|
|
390
545
|
{ conversationId },
|
|
@@ -473,6 +628,42 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
|
|
|
473
628
|
return candidates;
|
|
474
629
|
}
|
|
475
630
|
|
|
631
|
+
/**
|
|
632
|
+
* Build the host-bridge backend candidate. Shared between auto mode
|
|
633
|
+
* (no extension connected, bridge available) and the pinned path that
|
|
634
|
+
* serves the conversation's sticky-backend memo.
|
|
635
|
+
*
|
|
636
|
+
* Unlike the extension candidate, no pinned tab is passed: extension
|
|
637
|
+
* pins store Chrome tab ids, which never match the CDP target ids the
|
|
638
|
+
* bridge resolves from /json/list.
|
|
639
|
+
*/
|
|
640
|
+
function makeHostBridgeCandidate(
|
|
641
|
+
hostBrowserProxy: HostBrowserProxy,
|
|
642
|
+
conversationId: string,
|
|
643
|
+
sourceActorPrincipalId: string | undefined,
|
|
644
|
+
reason: string,
|
|
645
|
+
): BackendCandidate {
|
|
646
|
+
return {
|
|
647
|
+
kind: "host-bridge",
|
|
648
|
+
reason,
|
|
649
|
+
sourceActorPrincipalId,
|
|
650
|
+
create() {
|
|
651
|
+
const client = createHostBridgeCdpClient(
|
|
652
|
+
hostBrowserProxy,
|
|
653
|
+
conversationId,
|
|
654
|
+
sourceActorPrincipalId,
|
|
655
|
+
);
|
|
656
|
+
const backend = createHostBridgeBackend({
|
|
657
|
+
isAvailable: () => true,
|
|
658
|
+
sendCdp: (command, signal) =>
|
|
659
|
+
dispatchThroughClient(client, command, signal),
|
|
660
|
+
dispose: () => client.dispose(),
|
|
661
|
+
});
|
|
662
|
+
return { client, backend };
|
|
663
|
+
},
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
|
|
476
667
|
// ---------------------------------------------------------------------------
|
|
477
668
|
// Chained client with per-invocation failover
|
|
478
669
|
// ---------------------------------------------------------------------------
|
|
@@ -487,7 +678,7 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
|
|
|
487
678
|
export function buildChainedClient(
|
|
488
679
|
conversationId: string,
|
|
489
680
|
candidates: BackendCandidate[],
|
|
490
|
-
mode:
|
|
681
|
+
mode: InternalBrowserMode = "auto",
|
|
491
682
|
): ScopedCdpClient {
|
|
492
683
|
if (candidates.length === 0) {
|
|
493
684
|
throw new Error("CDP factory: no backend candidates available");
|
|
@@ -749,7 +940,7 @@ async function sendWithFailover<T>(
|
|
|
749
940
|
}) => void,
|
|
750
941
|
isDisposed: () => boolean,
|
|
751
942
|
conversationId: string,
|
|
752
|
-
mode:
|
|
943
|
+
mode: InternalBrowserMode,
|
|
753
944
|
): Promise<T> {
|
|
754
945
|
let lastError: CdpError | undefined;
|
|
755
946
|
const diagnostics: AttemptDiagnostic[] = [];
|
|
@@ -804,7 +995,7 @@ async function sendWithFailover<T>(
|
|
|
804
995
|
errorCode: "transport_error",
|
|
805
996
|
errorMessage,
|
|
806
997
|
});
|
|
807
|
-
|
|
998
|
+
maybeRecordCandidateCooldown(candidate);
|
|
808
999
|
|
|
809
1000
|
// Emit production-visible fallback log in auto mode
|
|
810
1001
|
if (mode === "auto" && i < candidates.length - 1) {
|
|
@@ -856,7 +1047,7 @@ async function sendWithFailover<T>(
|
|
|
856
1047
|
errorMessage,
|
|
857
1048
|
discoveryCode: extractDiscoveryCode(err),
|
|
858
1049
|
});
|
|
859
|
-
|
|
1050
|
+
maybeRecordCandidateCooldown(candidate);
|
|
860
1051
|
|
|
861
1052
|
// Emit production-visible fallback log in auto mode
|
|
862
1053
|
if (mode === "auto" && i < candidates.length - 1) {
|
|
@@ -903,7 +1094,7 @@ async function sendWithFailover<T>(
|
|
|
903
1094
|
errorMessage: cdpError.message,
|
|
904
1095
|
discoveryCode: extractDiscoveryCode(cdpError.underlying),
|
|
905
1096
|
});
|
|
906
|
-
|
|
1097
|
+
maybeRecordCandidateCooldown(candidate);
|
|
907
1098
|
|
|
908
1099
|
// Emit production-visible fallback log in auto mode
|
|
909
1100
|
if (mode === "auto") {
|
|
@@ -998,10 +1189,19 @@ async function sendWithFailover<T>(
|
|
|
998
1189
|
}
|
|
999
1190
|
|
|
1000
1191
|
/**
|
|
1001
|
-
*
|
|
1002
|
-
*
|
|
1192
|
+
* Record the appropriate cooldown for a failed candidate so subsequent
|
|
1193
|
+
* calls skip the probe: desktop-auto cdp-inspect attempts (matched by
|
|
1194
|
+
* reason prefix, exempting user-pinned cdp-inspect) and host-bridge
|
|
1195
|
+
* attempts (matched by kind alone — the bridge is never user-pinned).
|
|
1003
1196
|
*/
|
|
1004
|
-
function
|
|
1197
|
+
function maybeRecordCandidateCooldown(candidate: BackendCandidate): void {
|
|
1198
|
+
if (candidate.kind === "host-bridge") {
|
|
1199
|
+
log.debug(
|
|
1200
|
+
"CDP factory: recording host-bridge cooldown after transport failure",
|
|
1201
|
+
);
|
|
1202
|
+
recordHostBridgeCooldown(candidate.sourceActorPrincipalId);
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1005
1205
|
if (
|
|
1006
1206
|
candidate.kind === "cdp-inspect" &&
|
|
1007
1207
|
candidate.reason.startsWith("desktopAuto:")
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { HostBrowserProxy } from "../../../daemon/host-browser-proxy.js";
|
|
2
|
+
import { CdpError } from "./errors.js";
|
|
3
|
+
import { ExtensionCdpClient } from "./extension-cdp-client.js";
|
|
4
|
+
import type { CdpClientKind } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* CdpClient for the desktop host-browser bridge: raw CDP commands are
|
|
8
|
+
* routed through HostBrowserProxy to the desktop client's SSE bridge,
|
|
9
|
+
* which executes them against the user's Chrome via its local
|
|
10
|
+
* remote-debugging port. Reuses ExtensionCdpClient's request/reply and
|
|
11
|
+
* error-classification plumbing with three deliberate differences:
|
|
12
|
+
*
|
|
13
|
+
* - `kind` is `"host-bridge"`, so transport-aware tool branches
|
|
14
|
+
* (e.g. `--new-tab`'s `Vellum.createTab` path) correctly treat the
|
|
15
|
+
* bridge as a non-extension backend.
|
|
16
|
+
* - No pinned-tab `cdpSessionId` is ever injected: extension pins
|
|
17
|
+
* store Chrome tab ids, which never match the CDP target ids the
|
|
18
|
+
* bridge resolves from `/json/list` and would guarantee
|
|
19
|
+
* `cdp_session_not_found` failures.
|
|
20
|
+
* - Tab methods throw locally instead of sending `Vellum.*`
|
|
21
|
+
* pseudo-methods the bridge cannot serve (matches the
|
|
22
|
+
* local/cdp-inspect client convention).
|
|
23
|
+
*/
|
|
24
|
+
export class HostBridgeCdpClient extends ExtensionCdpClient {
|
|
25
|
+
override readonly kind: CdpClientKind = "host-bridge";
|
|
26
|
+
|
|
27
|
+
constructor(
|
|
28
|
+
proxy: HostBrowserProxy,
|
|
29
|
+
conversationId: string,
|
|
30
|
+
sourceActorPrincipalId?: string,
|
|
31
|
+
) {
|
|
32
|
+
super(
|
|
33
|
+
proxy,
|
|
34
|
+
conversationId,
|
|
35
|
+
/* cdpSessionId */ undefined,
|
|
36
|
+
sourceActorPrincipalId,
|
|
37
|
+
/* targetClientId */ undefined,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
override async listTabs(): Promise<never> {
|
|
42
|
+
throw unsupportedTabOperation("listTabs");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override async selectTab(_tabId: number): Promise<never> {
|
|
46
|
+
throw unsupportedTabOperation("selectTab");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
override async closeTab(_tabId: number): Promise<never> {
|
|
50
|
+
throw unsupportedTabOperation("closeTab");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function unsupportedTabOperation(operation: string): CdpError {
|
|
55
|
+
return new CdpError(
|
|
56
|
+
"transport_error",
|
|
57
|
+
`${operation} is not supported by the host-bridge backend (extension backend required)`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function createHostBridgeCdpClient(
|
|
62
|
+
proxy: HostBrowserProxy,
|
|
63
|
+
conversationId: string,
|
|
64
|
+
sourceActorPrincipalId?: string,
|
|
65
|
+
): HostBridgeCdpClient {
|
|
66
|
+
return new HostBridgeCdpClient(proxy, conversationId, sourceActorPrincipalId);
|
|
67
|
+
}
|
|
@@ -98,22 +98,36 @@ export interface CdpClient {
|
|
|
98
98
|
* the sacrificial-profile screencast setup when running against the
|
|
99
99
|
* user's own Chrome via the extension).
|
|
100
100
|
*/
|
|
101
|
-
export type CdpClientKind = "local" | "extension" | "cdp-inspect";
|
|
101
|
+
export type CdpClientKind = "local" | "extension" | "cdp-inspect" | "host-bridge";
|
|
102
102
|
|
|
103
103
|
/**
|
|
104
104
|
* Backend mode preference for the CDP factory. Controls which
|
|
105
105
|
* transport is selected:
|
|
106
106
|
*
|
|
107
107
|
* - `"auto"` — default, existing priority-ordered fallback
|
|
108
|
-
* (extension → cdp-inspect → local).
|
|
108
|
+
* (extension → host-bridge → cdp-inspect → local).
|
|
109
109
|
* - `"extension"` — pin to the chrome-extension backend. Fails
|
|
110
110
|
* immediately if the host browser proxy is unavailable.
|
|
111
111
|
* - `"cdp-inspect"` — pin to the cdp-inspect backend. Fails
|
|
112
112
|
* immediately if cdp-inspect cannot connect.
|
|
113
113
|
* - `"local"` — pin to the local Playwright backend. No fallback.
|
|
114
|
+
*
|
|
115
|
+
* The `host-bridge` backend (raw CDP to the user's Chrome via the
|
|
116
|
+
* desktop client's SSE bridge) is auto-mode only and not listed here —
|
|
117
|
+
* see {@link InternalBrowserMode}.
|
|
114
118
|
*/
|
|
115
119
|
export type BrowserMode = "auto" | "extension" | "cdp-inspect" | "local";
|
|
116
120
|
|
|
121
|
+
/**
|
|
122
|
+
* {@link BrowserMode} plus internal-only kinds the factory can pin to.
|
|
123
|
+
* The conversation's sticky-backend memo records the last successful
|
|
124
|
+
* {@link CdpClientKind} and re-pins to it on the next tool call; after
|
|
125
|
+
* a successful host-bridge send that memo is `"host-bridge"`, which is
|
|
126
|
+
* never user-requestable via `--browser-mode` but must round-trip
|
|
127
|
+
* through the factory's pinned-candidate path.
|
|
128
|
+
*/
|
|
129
|
+
export type InternalBrowserMode = BrowserMode | "host-bridge";
|
|
130
|
+
|
|
117
131
|
/**
|
|
118
132
|
* Stage at which a candidate attempt ended. Used in
|
|
119
133
|
* {@link AttemptDiagnostic} to indicate how far the attempt progressed.
|
|
@@ -212,6 +226,12 @@ export interface BackendCandidate {
|
|
|
212
226
|
readonly kind: CdpClientKind;
|
|
213
227
|
/** Human-readable reason this candidate was included. */
|
|
214
228
|
readonly reason: string;
|
|
229
|
+
/**
|
|
230
|
+
* Actor the candidate was built for. Set on host-bridge candidates so
|
|
231
|
+
* a transport failure records the cooldown for the owning actor only
|
|
232
|
+
* (the bridge reaches a different desktop machine per actor).
|
|
233
|
+
*/
|
|
234
|
+
readonly sourceActorPrincipalId?: string;
|
|
215
235
|
/**
|
|
216
236
|
* Materialise the backend. Called at most once — the factory caches
|
|
217
237
|
* the result after the first successful CDP command so subsequent
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "@vellumai/service-contracts/credential-rpc";
|
|
17
17
|
|
|
18
18
|
import { RiskLevel } from "../../permissions/types.js";
|
|
19
|
+
import { getCesClient } from "../../security/secure-keys.js";
|
|
19
20
|
import { getLogger } from "../../util/logger.js";
|
|
20
21
|
import type {
|
|
21
22
|
ToolContext,
|
|
@@ -77,7 +78,7 @@ export const makeAuthenticatedRequestTool = {
|
|
|
77
78
|
input: Record<string, unknown>,
|
|
78
79
|
context: ToolContext,
|
|
79
80
|
): Promise<ToolExecutionResult> {
|
|
80
|
-
const cesClient =
|
|
81
|
+
const cesClient = getCesClient();
|
|
81
82
|
if (!cesClient) {
|
|
82
83
|
return {
|
|
83
84
|
content:
|