@vellumai/assistant 0.3.0
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/.dockerignore +27 -0
- package/.env.example +22 -0
- package/Dockerfile +99 -0
- package/Dockerfile.sandbox +5 -0
- package/README.md +248 -0
- package/bun.lock +1723 -0
- package/bunfig.toml +2 -0
- package/docs/skills.md +158 -0
- package/drizzle/0000_dizzy_maggott.sql +301 -0
- package/drizzle/meta/0000_snapshot.json +1999 -0
- package/drizzle/meta/_journal.json +13 -0
- package/drizzle.config.ts +7 -0
- package/eslint.config.mjs +17 -0
- package/hook-templates/debug-prompt-logger/hook.json +7 -0
- package/hook-templates/debug-prompt-logger/run.sh +68 -0
- package/knip.json +9 -0
- package/package.json +70 -0
- package/scripts/capture-x-graphql.ts +545 -0
- package/scripts/ipc/check-contract-inventory.ts +104 -0
- package/scripts/ipc/check-swift-decoder-drift.ts +166 -0
- package/scripts/ipc/generate-swift.ts +492 -0
- package/scripts/test-filesystem-tools.sh +48 -0
- package/scripts/test.sh +127 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +2485 -0
- package/src/__tests__/account-registry.test.ts +245 -0
- package/src/__tests__/active-skill-tools.test.ts +378 -0
- package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
- package/src/__tests__/agent-loop-thinking.test.ts +81 -0
- package/src/__tests__/agent-loop.test.ts +1135 -0
- package/src/__tests__/anthropic-provider.test.ts +778 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +290 -0
- package/src/__tests__/app-bundler.test.ts +292 -0
- package/src/__tests__/app-executors.test.ts +613 -0
- package/src/__tests__/app-git-history.test.ts +176 -0
- package/src/__tests__/app-git-service.test.ts +169 -0
- package/src/__tests__/app-open-proxy.test.ts +62 -0
- package/src/__tests__/asset-materialize-tool.test.ts +452 -0
- package/src/__tests__/asset-search-tool.test.ts +477 -0
- package/src/__tests__/assistant-attachment-directive.test.ts +401 -0
- package/src/__tests__/assistant-attachments.test.ts +437 -0
- package/src/__tests__/assistant-event-hub.test.ts +226 -0
- package/src/__tests__/assistant-event.test.ts +123 -0
- package/src/__tests__/assistant-events-sse-hardening.test.ts +315 -0
- package/src/__tests__/attachments-store.test.ts +476 -0
- package/src/__tests__/attachments.test.ts +134 -0
- package/src/__tests__/audit-log-rotation.test.ts +154 -0
- package/src/__tests__/browser-fill-credential.test.ts +309 -0
- package/src/__tests__/browser-manager.test.ts +203 -0
- package/src/__tests__/browser-runtime-check.test.ts +55 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +68 -0
- package/src/__tests__/browser-skill-endstate.test.ts +195 -0
- package/src/__tests__/bundle-scanner.test.ts +313 -0
- package/src/__tests__/call-bridge.test.ts +517 -0
- package/src/__tests__/call-constants.test.ts +40 -0
- package/src/__tests__/call-domain.test.ts +163 -0
- package/src/__tests__/call-orchestrator.test.ts +625 -0
- package/src/__tests__/call-recovery.test.ts +518 -0
- package/src/__tests__/call-routes-http.test.ts +699 -0
- package/src/__tests__/call-state-machine.test.ts +143 -0
- package/src/__tests__/call-state.test.ts +174 -0
- package/src/__tests__/call-store.test.ts +691 -0
- package/src/__tests__/channel-approval-routes.test.ts +2356 -0
- package/src/__tests__/channel-approval.test.ts +299 -0
- package/src/__tests__/channel-approvals.test.ts +521 -0
- package/src/__tests__/channel-delivery-store.test.ts +447 -0
- package/src/__tests__/channel-guardian.test.ts +1005 -0
- package/src/__tests__/checker.test.ts +3519 -0
- package/src/__tests__/clarification-resolver.test.ts +159 -0
- package/src/__tests__/classifier.test.ts +67 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +127 -0
- package/src/__tests__/claude-code-tool-profiles.test.ts +88 -0
- package/src/__tests__/cli-discover.test.ts +85 -0
- package/src/__tests__/cli.test.ts +26 -0
- package/src/__tests__/clipboard.test.ts +80 -0
- package/src/__tests__/commit-guarantee.test.ts +335 -0
- package/src/__tests__/commit-message-enrichment-service.test.ts +550 -0
- package/src/__tests__/compaction.benchmark.test.ts +176 -0
- package/src/__tests__/computer-use-session-compaction.test.ts +132 -0
- package/src/__tests__/computer-use-session-lifecycle.test.ts +293 -0
- package/src/__tests__/computer-use-session-working-dir.test.ts +117 -0
- package/src/__tests__/computer-use-skill-baseline.test.ts +74 -0
- package/src/__tests__/computer-use-skill-endstate.test.ts +89 -0
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +217 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +107 -0
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +54 -0
- package/src/__tests__/computer-use-tools.test.ts +250 -0
- package/src/__tests__/config-schema.test.ts +1462 -0
- package/src/__tests__/conflict-intent-tokenization.test.ts +141 -0
- package/src/__tests__/conflict-policy.test.ts +121 -0
- package/src/__tests__/conflict-store.test.ts +332 -0
- package/src/__tests__/connection-policy.test.ts +102 -0
- package/src/__tests__/contacts-tools.test.ts +331 -0
- package/src/__tests__/context-memory-e2e.test.ts +434 -0
- package/src/__tests__/context-token-estimator.test.ts +135 -0
- package/src/__tests__/context-window-manager.test.ts +376 -0
- package/src/__tests__/contradiction-checker.test.ts +314 -0
- package/src/__tests__/conversation-store.test.ts +612 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +517 -0
- package/src/__tests__/credential-broker-server-use.test.ts +554 -0
- package/src/__tests__/credential-broker.test.ts +167 -0
- package/src/__tests__/credential-host-pattern-match.test.ts +104 -0
- package/src/__tests__/credential-metadata-store.test.ts +779 -0
- package/src/__tests__/credential-policy-validate.test.ts +121 -0
- package/src/__tests__/credential-resolve.test.ts +328 -0
- package/src/__tests__/credential-security-e2e.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +583 -0
- package/src/__tests__/credential-selection.test.ts +354 -0
- package/src/__tests__/credential-vault-unit.test.ts +780 -0
- package/src/__tests__/credential-vault.test.ts +852 -0
- package/src/__tests__/daemon-assistant-events.test.ts +164 -0
- package/src/__tests__/daemon-server-session-init.test.ts +522 -0
- package/src/__tests__/date-context.test.ts +373 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +97 -0
- package/src/__tests__/diff.test.ts +121 -0
- package/src/__tests__/domain-normalize.test.ts +112 -0
- package/src/__tests__/domain-policy.test.ts +124 -0
- package/src/__tests__/doordash-client.test.ts +186 -0
- package/src/__tests__/doordash-session.test.ts +152 -0
- package/src/__tests__/dynamic-page-surface.test.ts +91 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +132 -0
- package/src/__tests__/edit-engine.test.ts +180 -0
- package/src/__tests__/elevenlabs-client.test.ts +271 -0
- package/src/__tests__/email-cli.test.ts +283 -0
- package/src/__tests__/encrypted-store.test.ts +332 -0
- package/src/__tests__/entity-extractor.test.ts +190 -0
- package/src/__tests__/ephemeral-permissions.test.ts +362 -0
- package/src/__tests__/evaluate-typescript-tool.test.ts +286 -0
- package/src/__tests__/event-bus.test.ts +222 -0
- package/src/__tests__/file-edit-tool.test.ts +122 -0
- package/src/__tests__/file-ops-service.test.ts +330 -0
- package/src/__tests__/file-read-tool.test.ts +75 -0
- package/src/__tests__/file-write-tool.test.ts +113 -0
- package/src/__tests__/filesystem-tools.test.ts +579 -0
- package/src/__tests__/fixtures/credential-security-fixtures.ts +181 -0
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +126 -0
- package/src/__tests__/fixtures/mock-signup-server.ts +387 -0
- package/src/__tests__/fixtures/proxy-fixtures.ts +147 -0
- package/src/__tests__/followup-tools.test.ts +303 -0
- package/src/__tests__/forbidden-legacy-symbols.test.ts +71 -0
- package/src/__tests__/fuzzy-match-property.test.ts +216 -0
- package/src/__tests__/fuzzy-match.test.ts +138 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +631 -0
- package/src/__tests__/gemini-image-service.test.ts +261 -0
- package/src/__tests__/gemini-provider.test.ts +651 -0
- package/src/__tests__/get-weather.test.ts +318 -0
- package/src/__tests__/gmail-integration.test.ts +73 -0
- package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +202 -0
- package/src/__tests__/handlers-cu-observation-blob.test.ts +352 -0
- package/src/__tests__/handlers-ipc-blob-probe.test.ts +191 -0
- package/src/__tests__/handlers-slack-config.test.ts +200 -0
- package/src/__tests__/handlers-task-submit-slash.test.ts +38 -0
- package/src/__tests__/handlers-telegram-config.test.ts +968 -0
- package/src/__tests__/handlers-twilio-config.test.ts +659 -0
- package/src/__tests__/handlers-twitter-config.test.ts +858 -0
- package/src/__tests__/headless-browser-interactions.test.ts +536 -0
- package/src/__tests__/headless-browser-navigate.test.ts +211 -0
- package/src/__tests__/headless-browser-read-tools.test.ts +261 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +185 -0
- package/src/__tests__/history-repair-observability.test.ts +56 -0
- package/src/__tests__/history-repair.test.ts +510 -0
- package/src/__tests__/home-base-bootstrap.test.ts +82 -0
- package/src/__tests__/hooks-blocking.test.ts +128 -0
- package/src/__tests__/hooks-cli.test.ts +144 -0
- package/src/__tests__/hooks-config.test.ts +93 -0
- package/src/__tests__/hooks-discovery.test.ts +199 -0
- package/src/__tests__/hooks-integration.test.ts +189 -0
- package/src/__tests__/hooks-manager.test.ts +187 -0
- package/src/__tests__/hooks-runner.test.ts +182 -0
- package/src/__tests__/hooks-settings.test.ts +154 -0
- package/src/__tests__/hooks-templates.test.ts +137 -0
- package/src/__tests__/hooks-ts-runner.test.ts +125 -0
- package/src/__tests__/hooks-watch.test.ts +100 -0
- package/src/__tests__/host-file-edit-tool.test.ts +228 -0
- package/src/__tests__/host-file-read-tool.test.ts +123 -0
- package/src/__tests__/host-file-write-tool.test.ts +136 -0
- package/src/__tests__/host-shell-tool.test.ts +562 -0
- package/src/__tests__/ingress-reconcile.test.ts +581 -0
- package/src/__tests__/ingress-url-consistency.test.ts +214 -0
- package/src/__tests__/intent-routing.test.ts +259 -0
- package/src/__tests__/ipc-blob-store.test.ts +315 -0
- package/src/__tests__/ipc-contract-inventory.test.ts +54 -0
- package/src/__tests__/ipc-contract.test.ts +74 -0
- package/src/__tests__/ipc-protocol.test.ts +113 -0
- package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
- package/src/__tests__/ipc-snapshot.test.ts +1769 -0
- package/src/__tests__/ipc-validate.test.ts +407 -0
- package/src/__tests__/key-migration.test.ts +206 -0
- package/src/__tests__/keychain.test.ts +258 -0
- package/src/__tests__/llm-usage-store.test.ts +221 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +257 -0
- package/src/__tests__/managed-store.test.ts +608 -0
- package/src/__tests__/media-generate-image.test.ts +238 -0
- package/src/__tests__/media-reuse-story.e2e.test.ts +676 -0
- package/src/__tests__/media-visibility-policy.test.ts +141 -0
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +235 -0
- package/src/__tests__/memory-lifecycle-e2e.test.ts +481 -0
- package/src/__tests__/memory-query-builder.test.ts +59 -0
- package/src/__tests__/memory-recall-quality.test.ts +846 -0
- package/src/__tests__/memory-regressions.experimental.test.ts +538 -0
- package/src/__tests__/memory-regressions.test.ts +4435 -0
- package/src/__tests__/memory-retrieval-budget.test.ts +49 -0
- package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
- package/src/__tests__/migration-cli-flows.test.ts +169 -0
- package/src/__tests__/migration-ordering.test.ts +249 -0
- package/src/__tests__/mock-signup-server.test.ts +528 -0
- package/src/__tests__/oauth-callback-registry.test.ts +92 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +285 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +176 -0
- package/src/__tests__/onboarding-template-contract.test.ts +58 -0
- package/src/__tests__/openai-provider.test.ts +753 -0
- package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
- package/src/__tests__/parser.test.ts +472 -0
- package/src/__tests__/path-classifier.test.ts +73 -0
- package/src/__tests__/path-policy.test.ts +435 -0
- package/src/__tests__/platform-move-helper.test.ts +99 -0
- package/src/__tests__/platform-socket-path.test.ts +52 -0
- package/src/__tests__/platform-workspace-migration.test.ts +1000 -0
- package/src/__tests__/platform.test.ts +131 -0
- package/src/__tests__/playbook-execution.test.ts +502 -0
- package/src/__tests__/playbook-tools.test.ts +340 -0
- package/src/__tests__/prebuilt-home-base-seed.test.ts +75 -0
- package/src/__tests__/pricing.test.ts +256 -0
- package/src/__tests__/profile-compiler.test.ts +374 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +342 -0
- package/src/__tests__/provider-registry-ollama.test.ts +16 -0
- package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
- package/src/__tests__/proxy-approval-callback.test.ts +601 -0
- package/src/__tests__/public-ingress-urls.test.ts +256 -0
- package/src/__tests__/qdrant-manager.test.ts +267 -0
- package/src/__tests__/ratelimit.test.ts +297 -0
- package/src/__tests__/recurrence-engine-rruleset.test.ts +175 -0
- package/src/__tests__/recurrence-engine.test.ts +78 -0
- package/src/__tests__/recurrence-types.test.ts +79 -0
- package/src/__tests__/registry.test.ts +494 -0
- package/src/__tests__/relay-server.test.ts +688 -0
- package/src/__tests__/reminder-store.test.ts +223 -0
- package/src/__tests__/reminder.test.ts +229 -0
- package/src/__tests__/request-file-tool.test.ts +158 -0
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +227 -0
- package/src/__tests__/run-orchestrator.test.ts +425 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +189 -0
- package/src/__tests__/runtime-events-sse-parity.test.ts +343 -0
- package/src/__tests__/runtime-events-sse.test.ts +162 -0
- package/src/__tests__/runtime-runs-http.test.ts +438 -0
- package/src/__tests__/runtime-runs.test.ts +260 -0
- package/src/__tests__/sandbox-diagnostics.test.ts +408 -0
- package/src/__tests__/sandbox-host-parity.test.ts +950 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +253 -0
- package/src/__tests__/schedule-store.test.ts +484 -0
- package/src/__tests__/schedule-tools.test.ts +783 -0
- package/src/__tests__/scheduler-recurrence.test.ts +430 -0
- package/src/__tests__/script-proxy-certs.test.ts +90 -0
- package/src/__tests__/script-proxy-connect-tunnel.test.ts +177 -0
- package/src/__tests__/script-proxy-decision-trace.test.ts +156 -0
- package/src/__tests__/script-proxy-http-forwarder.test.ts +281 -0
- package/src/__tests__/script-proxy-injection-runtime.test.ts +401 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +407 -0
- package/src/__tests__/script-proxy-policy-runtime.test.ts +287 -0
- package/src/__tests__/script-proxy-policy.test.ts +310 -0
- package/src/__tests__/script-proxy-rewrite-specificity.test.ts +135 -0
- package/src/__tests__/script-proxy-router.test.ts +180 -0
- package/src/__tests__/script-proxy-session-manager.test.ts +382 -0
- package/src/__tests__/script-proxy-session-runtime.test.ts +113 -0
- package/src/__tests__/secret-allowlist.test.ts +230 -0
- package/src/__tests__/secret-ingress-handler.test.ts +110 -0
- package/src/__tests__/secret-onetime-send.test.ts +130 -0
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +106 -0
- package/src/__tests__/secret-response-routing.test.ts +93 -0
- package/src/__tests__/secret-scanner-executor.test.ts +348 -0
- package/src/__tests__/secret-scanner.test.ts +900 -0
- package/src/__tests__/secure-keys.test.ts +323 -0
- package/src/__tests__/server-history-render.test.ts +431 -0
- package/src/__tests__/session-abort-tool-results.test.ts +240 -0
- package/src/__tests__/session-conflict-gate.test.ts +1136 -0
- package/src/__tests__/session-error.test.ts +369 -0
- package/src/__tests__/session-evictor.test.ts +188 -0
- package/src/__tests__/session-init.benchmark.test.ts +465 -0
- package/src/__tests__/session-load-history-repair.test.ts +222 -0
- package/src/__tests__/session-pre-run-repair.test.ts +213 -0
- package/src/__tests__/session-process-bridge.test.ts +242 -0
- package/src/__tests__/session-profile-injection.test.ts +444 -0
- package/src/__tests__/session-provider-retry-repair.test.ts +306 -0
- package/src/__tests__/session-queue.test.ts +1535 -0
- package/src/__tests__/session-runtime-assembly.test.ts +476 -0
- package/src/__tests__/session-runtime-workspace.test.ts +183 -0
- package/src/__tests__/session-skill-tools.test.ts +2431 -0
- package/src/__tests__/session-slash-known.test.ts +368 -0
- package/src/__tests__/session-slash-queue.test.ts +288 -0
- package/src/__tests__/session-slash-unknown.test.ts +271 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +473 -0
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +140 -0
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +140 -0
- package/src/__tests__/session-undo.test.ts +75 -0
- package/src/__tests__/session-workspace-cache-state.test.ts +246 -0
- package/src/__tests__/session-workspace-injection.test.ts +327 -0
- package/src/__tests__/session-workspace-tool-tracking.test.ts +240 -0
- package/src/__tests__/shared-filesystem-errors.test.ts +78 -0
- package/src/__tests__/shell-credential-ref.test.ts +187 -0
- package/src/__tests__/shell-identity.test.ts +256 -0
- package/src/__tests__/shell-parser-fuzz.test.ts +544 -0
- package/src/__tests__/shell-parser-property.test.ts +433 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +272 -0
- package/src/__tests__/signup-e2e.test.ts +353 -0
- package/src/__tests__/size-guard.test.ts +117 -0
- package/src/__tests__/skill-include-graph.test.ts +303 -0
- package/src/__tests__/skill-load-tool.test.ts +409 -0
- package/src/__tests__/skill-projection.benchmark.test.ts +338 -0
- package/src/__tests__/skill-script-runner-host.test.ts +489 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +349 -0
- package/src/__tests__/skill-script-runner.test.ts +159 -0
- package/src/__tests__/skill-tool-factory.test.ts +252 -0
- package/src/__tests__/skill-tool-manifest.test.ts +658 -0
- package/src/__tests__/skill-version-hash.test.ts +182 -0
- package/src/__tests__/skills.test.ts +680 -0
- package/src/__tests__/slash-commands-catalog.test.ts +86 -0
- package/src/__tests__/slash-commands-parser.test.ts +119 -0
- package/src/__tests__/slash-commands-resolver.test.ts +193 -0
- package/src/__tests__/slash-commands-rewrite.test.ts +39 -0
- package/src/__tests__/speaker-identification.test.ts +52 -0
- package/src/__tests__/starter-bundle.test.ts +136 -0
- package/src/__tests__/starter-task-flow.test.ts +143 -0
- package/src/__tests__/subagent-manager-notify.test.ts +404 -0
- package/src/__tests__/subagent-tools.test.ts +801 -0
- package/src/__tests__/subagent-types.test.ts +78 -0
- package/src/__tests__/swarm-orchestrator.test.ts +428 -0
- package/src/__tests__/swarm-plan-validator.test.ts +330 -0
- package/src/__tests__/swarm-recursion.test.ts +165 -0
- package/src/__tests__/swarm-router-planner.test.ts +208 -0
- package/src/__tests__/swarm-session-integration.test.ts +274 -0
- package/src/__tests__/swarm-tool.test.ts +145 -0
- package/src/__tests__/swarm-worker-backend.test.ts +129 -0
- package/src/__tests__/swarm-worker-runner.test.ts +272 -0
- package/src/__tests__/system-prompt.test.ts +439 -0
- package/src/__tests__/task-compiler.test.ts +284 -0
- package/src/__tests__/task-management-tools.test.ts +936 -0
- package/src/__tests__/task-runner.test.ts +216 -0
- package/src/__tests__/task-scheduler.test.ts +217 -0
- package/src/__tests__/task-tools.test.ts +595 -0
- package/src/__tests__/terminal-sandbox-docker.test.ts +1064 -0
- package/src/__tests__/terminal-sandbox.integration.test.ts +178 -0
- package/src/__tests__/terminal-sandbox.test.ts +202 -0
- package/src/__tests__/terminal-tools.test.ts +840 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +90 -0
- package/src/__tests__/test-support/computer-use-skill-harness.ts +45 -0
- package/src/__tests__/tool-audit-listener.test.ts +113 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +253 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +516 -0
- package/src/__tests__/tool-executor-redaction.test.ts +289 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +301 -0
- package/src/__tests__/tool-executor.test.ts +1989 -0
- package/src/__tests__/tool-metrics-listener.test.ts +225 -0
- package/src/__tests__/tool-notification-listener.test.ts +49 -0
- package/src/__tests__/tool-permission-simulate-handler.test.ts +336 -0
- package/src/__tests__/tool-policy.test.ts +54 -0
- package/src/__tests__/tool-profiling-listener.test.ts +268 -0
- package/src/__tests__/tool-result-truncation.test.ts +217 -0
- package/src/__tests__/tool-trace-listener.test.ts +226 -0
- package/src/__tests__/top-level-renderer.test.ts +121 -0
- package/src/__tests__/top-level-scanner.test.ts +141 -0
- package/src/__tests__/trace-emitter.test.ts +173 -0
- package/src/__tests__/trust-store.test.ts +1605 -0
- package/src/__tests__/turn-commit.test.ts +554 -0
- package/src/__tests__/twilio-provider.test.ts +329 -0
- package/src/__tests__/twilio-routes-elevenlabs.test.ts +375 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +127 -0
- package/src/__tests__/twilio-routes.test.ts +577 -0
- package/src/__tests__/twitter-auth-handler.test.ts +667 -0
- package/src/__tests__/twitter-cli-error-shaping.test.ts +208 -0
- package/src/__tests__/twitter-cli-routing.test.ts +252 -0
- package/src/__tests__/twitter-oauth-client.test.ts +209 -0
- package/src/__tests__/url-safety.test.ts +418 -0
- package/src/__tests__/view-image-tool.test.ts +217 -0
- package/src/__tests__/weather-skill-regression.test.ts +225 -0
- package/src/__tests__/web-fetch.test.ts +869 -0
- package/src/__tests__/web-search.test.ts +584 -0
- package/src/__tests__/workspace-git-service.test.ts +1153 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +486 -0
- package/src/__tests__/workspace-lifecycle.test.ts +292 -0
- package/src/__tests__/workspace-policy.test.ts +213 -0
- package/src/agent/attachments.ts +35 -0
- package/src/agent/loop.ts +500 -0
- package/src/agent/message-types.ts +17 -0
- package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
- package/src/autonomy/autonomy-resolver.ts +60 -0
- package/src/autonomy/autonomy-store.ts +122 -0
- package/src/autonomy/disposition-mapper.ts +31 -0
- package/src/autonomy/index.ts +11 -0
- package/src/autonomy/types.ts +39 -0
- package/src/bundler/app-bundler.ts +295 -0
- package/src/bundler/bundle-scanner.ts +535 -0
- package/src/bundler/bundle-signer.ts +124 -0
- package/src/bundler/manifest.ts +21 -0
- package/src/bundler/signature-verifier.ts +184 -0
- package/src/calls/call-bridge.ts +168 -0
- package/src/calls/call-constants.ts +48 -0
- package/src/calls/call-domain.ts +430 -0
- package/src/calls/call-orchestrator.ts +498 -0
- package/src/calls/call-recovery.ts +207 -0
- package/src/calls/call-state-machine.ts +68 -0
- package/src/calls/call-state.ts +87 -0
- package/src/calls/call-store.ts +422 -0
- package/src/calls/elevenlabs-client.ts +97 -0
- package/src/calls/elevenlabs-config.ts +31 -0
- package/src/calls/relay-server.ts +390 -0
- package/src/calls/speaker-identification.ts +213 -0
- package/src/calls/twilio-config.ts +45 -0
- package/src/calls/twilio-provider.ts +263 -0
- package/src/calls/twilio-rest.ts +156 -0
- package/src/calls/twilio-routes.ts +311 -0
- package/src/calls/types.ts +39 -0
- package/src/calls/voice-provider.ts +14 -0
- package/src/calls/voice-quality.ts +114 -0
- package/src/cli/autonomy.ts +188 -0
- package/src/cli/config-commands.ts +334 -0
- package/src/cli/contacts.ts +149 -0
- package/src/cli/core-commands.ts +784 -0
- package/src/cli/doordash.ts +1055 -0
- package/src/cli/email-guardrails.ts +200 -0
- package/src/cli/email.ts +405 -0
- package/src/cli/ipc-client.ts +82 -0
- package/src/cli/main-screen.tsx +53 -0
- package/src/cli/map.ts +270 -0
- package/src/cli/twitter.ts +754 -0
- package/src/cli.ts +918 -0
- package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
- package/src/commands/cc-command-registry.ts +209 -0
- package/src/config/bundled-skills/.gitkeep +0 -0
- package/src/config/bundled-skills/agentmail/SKILL.md +128 -0
- package/src/config/bundled-skills/agentmail/icon.svg +21 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +1404 -0
- package/src/config/bundled-skills/app-builder/TOOLS.json +279 -0
- package/src/config/bundled-skills/app-builder/icon.svg +9 -0
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +15 -0
- package/src/config/bundled-skills/app-builder/tools/app-delete.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +11 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +18 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +11 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-query.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +20 -0
- package/src/config/bundled-skills/browser/SKILL.md +28 -0
- package/src/config/bundled-skills/browser/TOOLS.json +234 -0
- package/src/config/bundled-skills/browser/tools/browser-click.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-close.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-type.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +9 -0
- package/src/config/bundled-skills/claude-code/SKILL.md +50 -0
- package/src/config/bundled-skills/claude-code/TOOLS.json +40 -0
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +9 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +17 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +326 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +9 -0
- package/src/config/bundled-skills/contacts/SKILL.md +39 -0
- package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +57 -0
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +60 -0
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +66 -0
- package/src/config/bundled-skills/document/SKILL.md +26 -0
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
- package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
- package/src/config/bundled-skills/doordash/SKILL.md +163 -0
- package/src/config/bundled-skills/followups/SKILL.md +32 -0
- package/src/config/bundled-skills/followups/TOOLS.json +100 -0
- package/src/config/bundled-skills/followups/icon.svg +24 -0
- package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
- package/src/config/bundled-skills/google-calendar/SKILL.md +51 -0
- package/src/config/bundled-skills/google-calendar/TOOLS.json +108 -0
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +165 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +21 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +42 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +13 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +30 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +41 -0
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +18 -0
- package/src/config/bundled-skills/google-calendar/types.ts +97 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +32 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +42 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +115 -0
- package/src/config/bundled-skills/macos-automation/SKILL.md +66 -0
- package/src/config/bundled-skills/messaging/SKILL.md +153 -0
- package/src/config/bundled-skills/messaging/TOOLS.json +357 -0
- package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +26 -0
- package/src/config/bundled-skills/messaging/tools/gmail-label.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +84 -0
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +18 -0
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +125 -0
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +16 -0
- package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +49 -0
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +21 -0
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +28 -0
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +32 -0
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +22 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +31 -0
- package/src/config/bundled-skills/messaging/tools/shared.ts +76 -0
- package/src/config/bundled-skills/messaging/tools/slack-add-reaction.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/slack-leave-channel.ts +23 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +533 -0
- package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
- package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +98 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +54 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +76 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +113 -0
- package/src/config/bundled-skills/public-ingress/SKILL.md +200 -0
- package/src/config/bundled-skills/reminder/SKILL.md +20 -0
- package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
- package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
- package/src/config/bundled-skills/schedule/SKILL.md +74 -0
- package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
- package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
- package/src/config/bundled-skills/self-upgrade/SKILL.md +68 -0
- package/src/config/bundled-skills/start-the-day/SKILL.md +70 -0
- package/src/config/bundled-skills/start-the-day/icon.svg +13 -0
- package/src/config/bundled-skills/subagent/SKILL.md +25 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
- package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
- package/src/config/bundled-skills/tasks/SKILL.md +28 -0
- package/src/config/bundled-skills/tasks/TOOLS.json +281 -0
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
- package/src/config/bundled-skills/transcribe/SKILL.md +25 -0
- package/src/config/bundled-skills/transcribe/TOOLS.json +32 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +370 -0
- package/src/config/bundled-skills/twitter/SKILL.md +220 -0
- package/src/config/bundled-skills/watcher/SKILL.md +27 -0
- package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
- package/src/config/bundled-skills/weather/SKILL.md +37 -0
- package/src/config/bundled-skills/weather/TOOLS.json +32 -0
- package/src/config/bundled-skills/weather/icon.svg +24 -0
- package/src/config/bundled-skills/weather/tools/get-weather.ts +9 -0
- package/src/config/computer-use-prompt.ts +97 -0
- package/src/config/defaults.ts +263 -0
- package/src/config/loader.ts +339 -0
- package/src/config/schema.ts +1436 -0
- package/src/config/skill-state.ts +95 -0
- package/src/config/skills.ts +972 -0
- package/src/config/system-prompt.ts +675 -0
- package/src/config/templates/BOOTSTRAP.md +70 -0
- package/src/config/templates/IDENTITY.md +25 -0
- package/src/config/templates/LOOKS.md +25 -0
- package/src/config/templates/SOUL.md +37 -0
- package/src/config/templates/USER.md +19 -0
- package/src/config/types.ts +42 -0
- package/src/config/vellum-skills/chatgpt-import/SKILL.md +24 -0
- package/src/config/vellum-skills/chatgpt-import/TOOLS.json +23 -0
- package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +284 -0
- package/src/config/vellum-skills/deploy-fullstack-vercel/SKILL.md +179 -0
- package/src/config/vellum-skills/document-writer/SKILL.md +195 -0
- package/src/config/vellum-skills/google-oauth-setup/SKILL.md +199 -0
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +153 -0
- package/src/config/vellum-skills/telegram-setup/SKILL.md +143 -0
- package/src/config/vellum-skills/twilio-setup/SKILL.md +213 -0
- package/src/contacts/contact-store.ts +410 -0
- package/src/contacts/index.ts +11 -0
- package/src/contacts/types.ts +28 -0
- package/src/context/token-estimator.ts +108 -0
- package/src/context/tool-result-truncation.ts +128 -0
- package/src/context/window-manager.ts +531 -0
- package/src/daemon/assistant-attachments.ts +691 -0
- package/src/daemon/classifier.ts +110 -0
- package/src/daemon/computer-use-session.ts +903 -0
- package/src/daemon/connection-policy.ts +41 -0
- package/src/daemon/date-context.ts +136 -0
- package/src/daemon/handlers/apps.ts +530 -0
- package/src/daemon/handlers/browser.ts +54 -0
- package/src/daemon/handlers/computer-use.ts +187 -0
- package/src/daemon/handlers/config.ts +1517 -0
- package/src/daemon/handlers/diagnostics.ts +338 -0
- package/src/daemon/handlers/documents.ts +173 -0
- package/src/daemon/handlers/home-base.ts +78 -0
- package/src/daemon/handlers/identity.ts +127 -0
- package/src/daemon/handlers/index.ts +129 -0
- package/src/daemon/handlers/misc.ts +331 -0
- package/src/daemon/handlers/open-bundle-handler.ts +80 -0
- package/src/daemon/handlers/publish.ts +187 -0
- package/src/daemon/handlers/sessions.ts +555 -0
- package/src/daemon/handlers/shared.ts +570 -0
- package/src/daemon/handlers/signing.ts +37 -0
- package/src/daemon/handlers/skills.ts +486 -0
- package/src/daemon/handlers/subagents.ts +210 -0
- package/src/daemon/handlers/twitter-auth.ts +198 -0
- package/src/daemon/handlers/work-items.ts +632 -0
- package/src/daemon/handlers/workspace-files.ts +75 -0
- package/src/daemon/handlers.ts +17 -0
- package/src/daemon/history-repair.ts +214 -0
- package/src/daemon/ipc-blob-store.ts +231 -0
- package/src/daemon/ipc-contract-inventory.json +495 -0
- package/src/daemon/ipc-contract-inventory.ts +126 -0
- package/src/daemon/ipc-contract.ts +2551 -0
- package/src/daemon/ipc-protocol.ts +75 -0
- package/src/daemon/ipc-validate.ts +188 -0
- package/src/daemon/lifecycle.ts +582 -0
- package/src/daemon/main.ts +21 -0
- package/src/daemon/media-visibility-policy.ts +57 -0
- package/src/daemon/ride-shotgun-handler.ts +309 -0
- package/src/daemon/server.ts +1215 -0
- package/src/daemon/session-agent-loop.ts +922 -0
- package/src/daemon/session-attachments.ts +196 -0
- package/src/daemon/session-conflict-gate.ts +184 -0
- package/src/daemon/session-dynamic-profile.ts +63 -0
- package/src/daemon/session-error.ts +290 -0
- package/src/daemon/session-evictor.ts +196 -0
- package/src/daemon/session-history.ts +437 -0
- package/src/daemon/session-lifecycle.ts +147 -0
- package/src/daemon/session-media-retry.ts +147 -0
- package/src/daemon/session-memory.ts +212 -0
- package/src/daemon/session-messaging.ts +145 -0
- package/src/daemon/session-notifiers.ts +193 -0
- package/src/daemon/session-process.ts +323 -0
- package/src/daemon/session-queue-manager.ts +82 -0
- package/src/daemon/session-runtime-assembly.ts +447 -0
- package/src/daemon/session-skill-tools.ts +356 -0
- package/src/daemon/session-slash.ts +305 -0
- package/src/daemon/session-surfaces.ts +702 -0
- package/src/daemon/session-tool-setup.ts +523 -0
- package/src/daemon/session-usage.ts +72 -0
- package/src/daemon/session-workspace.ts +19 -0
- package/src/daemon/session.ts +400 -0
- package/src/daemon/tls-certs.ts +189 -0
- package/src/daemon/trace-emitter.ts +82 -0
- package/src/daemon/video-thumbnail.ts +62 -0
- package/src/daemon/watch-handler.ts +274 -0
- package/src/doordash/client.ts +999 -0
- package/src/doordash/queries.ts +1311 -0
- package/src/doordash/query-extractor.ts +93 -0
- package/src/doordash/session.ts +82 -0
- package/src/email/provider.ts +117 -0
- package/src/email/providers/agentmail.ts +317 -0
- package/src/email/providers/index.ts +58 -0
- package/src/email/service.ts +303 -0
- package/src/email/types.ts +126 -0
- package/src/events/bus.ts +157 -0
- package/src/events/domain-events.ts +83 -0
- package/src/events/index.ts +18 -0
- package/src/events/tool-audit-listener.ts +80 -0
- package/src/events/tool-domain-event-publisher.ts +111 -0
- package/src/events/tool-metrics-listener.ts +159 -0
- package/src/events/tool-notification-listener.ts +17 -0
- package/src/events/tool-profiling-listener.ts +158 -0
- package/src/events/tool-trace-listener.ts +75 -0
- package/src/export/formatter.ts +98 -0
- package/src/followups/followup-store.ts +168 -0
- package/src/followups/index.ts +10 -0
- package/src/followups/types.ts +29 -0
- package/src/gallery/default-gallery.ts +795 -0
- package/src/gallery/gallery-manifest.ts +24 -0
- package/src/home-base/app-link-store.ts +82 -0
- package/src/home-base/bootstrap.ts +68 -0
- package/src/home-base/prebuilt/index.html +662 -0
- package/src/home-base/prebuilt/seed-metadata.json +21 -0
- package/src/home-base/prebuilt/seed.ts +112 -0
- package/src/home-base/prebuilt-home-base-updater.ts +30 -0
- package/src/hooks/cli.ts +163 -0
- package/src/hooks/config.ts +88 -0
- package/src/hooks/discovery.ts +110 -0
- package/src/hooks/manager.ts +124 -0
- package/src/hooks/runner.ts +123 -0
- package/src/hooks/templates.ts +52 -0
- package/src/hooks/types.ts +72 -0
- package/src/inbound/public-ingress-urls.ts +123 -0
- package/src/index.ts +81 -0
- package/src/instrument.ts +60 -0
- package/src/logfire.ts +99 -0
- package/src/media/gemini-image-service.ts +136 -0
- package/src/memory/account-store.ts +108 -0
- package/src/memory/admin.ts +211 -0
- package/src/memory/app-git-service.ts +295 -0
- package/src/memory/app-store.ts +577 -0
- package/src/memory/attachments-store.ts +397 -0
- package/src/memory/channel-delivery-store.ts +353 -0
- package/src/memory/channel-guardian-store.ts +669 -0
- package/src/memory/checkpoints.ts +52 -0
- package/src/memory/clarification-resolver.ts +298 -0
- package/src/memory/conflict-intent.ts +157 -0
- package/src/memory/conflict-policy.ts +73 -0
- package/src/memory/conflict-store.ts +350 -0
- package/src/memory/contradiction-checker.ts +358 -0
- package/src/memory/conversation-key-store.ts +122 -0
- package/src/memory/conversation-store.ts +470 -0
- package/src/memory/db.ts +1991 -0
- package/src/memory/embedding-backend.ts +229 -0
- package/src/memory/embedding-gemini.ts +52 -0
- package/src/memory/embedding-local.ts +65 -0
- package/src/memory/embedding-ollama.ts +55 -0
- package/src/memory/embedding-openai.ts +25 -0
- package/src/memory/entity-extractor.ts +474 -0
- package/src/memory/external-conversation-store.ts +234 -0
- package/src/memory/fingerprint.ts +20 -0
- package/src/memory/indexer.ts +156 -0
- package/src/memory/items-extractor.ts +461 -0
- package/src/memory/job-handlers/backfill.ts +139 -0
- package/src/memory/job-handlers/cleanup.ts +58 -0
- package/src/memory/job-handlers/conflict.ts +141 -0
- package/src/memory/job-handlers/embedding.ts +61 -0
- package/src/memory/job-handlers/extraction.ts +123 -0
- package/src/memory/job-handlers/index-maintenance.ts +54 -0
- package/src/memory/job-handlers/summarization.ts +286 -0
- package/src/memory/job-utils.ts +170 -0
- package/src/memory/jobs-store.ts +401 -0
- package/src/memory/jobs-worker.ts +313 -0
- package/src/memory/llm-request-log-store.ts +45 -0
- package/src/memory/llm-usage-store.ts +60 -0
- package/src/memory/message-content.ts +54 -0
- package/src/memory/profile-compiler.ts +160 -0
- package/src/memory/published-pages-store.ts +137 -0
- package/src/memory/qdrant-client.ts +366 -0
- package/src/memory/qdrant-manager.ts +242 -0
- package/src/memory/query-builder.ts +45 -0
- package/src/memory/retrieval-budget.ts +30 -0
- package/src/memory/retriever.ts +653 -0
- package/src/memory/runs-store.ts +305 -0
- package/src/memory/schema.ts +677 -0
- package/src/memory/search/entity.ts +298 -0
- package/src/memory/search/formatting.ts +207 -0
- package/src/memory/search/lexical.ts +227 -0
- package/src/memory/search/ranking.ts +401 -0
- package/src/memory/search/semantic.ts +121 -0
- package/src/memory/search/types.ts +137 -0
- package/src/memory/segmenter.ts +68 -0
- package/src/memory/shared-app-links-store.ts +138 -0
- package/src/memory/tool-usage-store.ts +62 -0
- package/src/messaging/activity-analyzer.ts +76 -0
- package/src/messaging/draft-store.ts +88 -0
- package/src/messaging/index.ts +3 -0
- package/src/messaging/provider-types.ts +80 -0
- package/src/messaging/provider.ts +52 -0
- package/src/messaging/providers/gmail/adapter.ts +193 -0
- package/src/messaging/providers/gmail/client.ts +204 -0
- package/src/messaging/providers/gmail/types.ts +90 -0
- package/src/messaging/providers/slack/adapter.ts +202 -0
- package/src/messaging/providers/slack/client.ts +198 -0
- package/src/messaging/providers/slack/types.ts +119 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +162 -0
- package/src/messaging/providers/telegram-bot/client.ts +104 -0
- package/src/messaging/providers/telegram-bot/types.ts +15 -0
- package/src/messaging/registry.ts +35 -0
- package/src/messaging/style-analyzer.ts +159 -0
- package/src/messaging/thread-summarizer.ts +306 -0
- package/src/messaging/triage-engine.ts +323 -0
- package/src/messaging/types.ts +55 -0
- package/src/permissions/checker.ts +640 -0
- package/src/permissions/defaults.ts +254 -0
- package/src/permissions/prompter.ts +98 -0
- package/src/permissions/secret-prompter.ts +114 -0
- package/src/permissions/shell-identity.ts +227 -0
- package/src/permissions/trust-store.ts +607 -0
- package/src/permissions/types.ts +43 -0
- package/src/permissions/workspace-policy.ts +114 -0
- package/src/playbooks/index.ts +2 -0
- package/src/playbooks/playbook-compiler.ts +90 -0
- package/src/playbooks/types.ts +55 -0
- package/src/providers/anthropic/client.ts +751 -0
- package/src/providers/failover.ts +129 -0
- package/src/providers/fireworks/client.ts +20 -0
- package/src/providers/gemini/client.ts +285 -0
- package/src/providers/ollama/client.ts +30 -0
- package/src/providers/openai/client.ts +337 -0
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/ratelimit.ts +93 -0
- package/src/providers/registry.ts +146 -0
- package/src/providers/retry.ts +81 -0
- package/src/providers/stream-timeout.ts +38 -0
- package/src/providers/types.ts +109 -0
- package/src/runtime/assistant-event-hub.ts +157 -0
- package/src/runtime/assistant-event.ts +82 -0
- package/src/runtime/channel-approval-parser.ts +60 -0
- package/src/runtime/channel-approval-types.ts +73 -0
- package/src/runtime/channel-approvals.ts +206 -0
- package/src/runtime/channel-guardian-service.ts +212 -0
- package/src/runtime/gateway-client.ts +58 -0
- package/src/runtime/http-server.ts +1076 -0
- package/src/runtime/http-types.ts +66 -0
- package/src/runtime/routes/app-routes.ts +174 -0
- package/src/runtime/routes/attachment-routes.ts +133 -0
- package/src/runtime/routes/call-routes.ts +190 -0
- package/src/runtime/routes/channel-routes.ts +1404 -0
- package/src/runtime/routes/conversation-routes.ts +352 -0
- package/src/runtime/routes/events-routes.ts +148 -0
- package/src/runtime/routes/run-routes.ts +257 -0
- package/src/runtime/routes/secret-routes.ts +76 -0
- package/src/runtime/run-orchestrator.ts +330 -0
- package/src/schedule/recurrence-engine.ts +162 -0
- package/src/schedule/recurrence-types.ts +67 -0
- package/src/schedule/schedule-store.ts +506 -0
- package/src/schedule/scheduler.ts +171 -0
- package/src/security/encrypted-store.ts +238 -0
- package/src/security/keychain.ts +252 -0
- package/src/security/oauth-callback-registry.ts +66 -0
- package/src/security/oauth2.ts +274 -0
- package/src/security/redaction.ts +89 -0
- package/src/security/secret-allowlist.ts +164 -0
- package/src/security/secret-ingress.ts +57 -0
- package/src/security/secret-scanner.ts +550 -0
- package/src/security/secure-keys.ts +180 -0
- package/src/security/token-manager.ts +141 -0
- package/src/services/published-app-updater.ts +69 -0
- package/src/services/vercel-deploy.ts +73 -0
- package/src/skills/active-skill-tools.ts +81 -0
- package/src/skills/clawhub.ts +414 -0
- package/src/skills/include-graph.ts +146 -0
- package/src/skills/managed-store.ts +233 -0
- package/src/skills/path-classifier.ts +128 -0
- package/src/skills/slash-commands.ts +174 -0
- package/src/skills/tool-manifest.ts +165 -0
- package/src/skills/version-hash.ts +110 -0
- package/src/slack/slack-webhook.ts +61 -0
- package/src/subagent/index.ts +19 -0
- package/src/subagent/manager.ts +511 -0
- package/src/subagent/types.ts +69 -0
- package/src/swarm/backend-claude-code.ts +145 -0
- package/src/swarm/index.ts +44 -0
- package/src/swarm/limits.ts +37 -0
- package/src/swarm/orchestrator.ts +279 -0
- package/src/swarm/plan-validator.ts +151 -0
- package/src/swarm/router-planner.ts +100 -0
- package/src/swarm/router-prompts.ts +36 -0
- package/src/swarm/synthesizer.ts +62 -0
- package/src/swarm/types.ts +62 -0
- package/src/swarm/worker-backend.ts +121 -0
- package/src/swarm/worker-prompts.ts +79 -0
- package/src/swarm/worker-runner.ts +164 -0
- package/src/tasks/SPEC.md +139 -0
- package/src/tasks/candidate-store.ts +86 -0
- package/src/tasks/ephemeral-permissions.ts +48 -0
- package/src/tasks/task-compiler.ts +199 -0
- package/src/tasks/task-runner.ts +90 -0
- package/src/tasks/task-scheduler.ts +21 -0
- package/src/tasks/task-store.ts +127 -0
- package/src/tasks/tool-sanitizer.ts +36 -0
- package/src/tools/apps/definitions.ts +59 -0
- package/src/tools/apps/executors.ts +313 -0
- package/src/tools/apps/open-proxy.ts +43 -0
- package/src/tools/apps/registry.ts +16 -0
- package/src/tools/assets/materialize.ts +218 -0
- package/src/tools/assets/search.ts +361 -0
- package/src/tools/browser/__tests__/auth-cache.test.ts +219 -0
- package/src/tools/browser/__tests__/auth-detector.test.ts +362 -0
- package/src/tools/browser/__tests__/jit-auth.test.ts +189 -0
- package/src/tools/browser/api-map.ts +293 -0
- package/src/tools/browser/auth-cache.ts +149 -0
- package/src/tools/browser/auth-detector.ts +347 -0
- package/src/tools/browser/auto-navigate.ts +270 -0
- package/src/tools/browser/browser-execution.ts +980 -0
- package/src/tools/browser/browser-handoff.ts +79 -0
- package/src/tools/browser/browser-manager.ts +715 -0
- package/src/tools/browser/browser-screencast.ts +217 -0
- package/src/tools/browser/headless-browser.ts +450 -0
- package/src/tools/browser/jit-auth.ts +51 -0
- package/src/tools/browser/network-recorder.ts +349 -0
- package/src/tools/browser/network-recording-types.ts +49 -0
- package/src/tools/browser/recording-store.ts +49 -0
- package/src/tools/browser/runtime-check.ts +43 -0
- package/src/tools/browser/x-auto-navigate.ts +207 -0
- package/src/tools/calls/call-end.ts +67 -0
- package/src/tools/calls/call-start.ts +81 -0
- package/src/tools/calls/call-status.ts +81 -0
- package/src/tools/claude-code/claude-code.ts +428 -0
- package/src/tools/computer-use/definitions.ts +443 -0
- package/src/tools/computer-use/registry.ts +22 -0
- package/src/tools/computer-use/request-computer-control.ts +53 -0
- package/src/tools/computer-use/skill-proxy-bridge.ts +28 -0
- package/src/tools/credentials/account-registry.ts +127 -0
- package/src/tools/credentials/broker-types.ts +107 -0
- package/src/tools/credentials/broker.ts +372 -0
- package/src/tools/credentials/domain-policy.ts +51 -0
- package/src/tools/credentials/host-pattern-match.ts +60 -0
- package/src/tools/credentials/metadata-store.ts +335 -0
- package/src/tools/credentials/policy-types.ts +52 -0
- package/src/tools/credentials/policy-validate.ts +80 -0
- package/src/tools/credentials/resolve.ts +122 -0
- package/src/tools/credentials/selection.ts +159 -0
- package/src/tools/credentials/tool-policy.ts +25 -0
- package/src/tools/credentials/vault.ts +657 -0
- package/src/tools/document/document-tool.ts +92 -0
- package/src/tools/document/editor-template.ts +237 -0
- package/src/tools/execution-target.ts +21 -0
- package/src/tools/execution-timeout.ts +49 -0
- package/src/tools/executor.ts +815 -0
- package/src/tools/filesystem/edit.ts +127 -0
- package/src/tools/filesystem/fuzzy-match.ts +202 -0
- package/src/tools/filesystem/read.ts +71 -0
- package/src/tools/filesystem/view-image.ts +199 -0
- package/src/tools/filesystem/write.ts +79 -0
- package/src/tools/followups/followup_create.ts +76 -0
- package/src/tools/followups/followup_list.ts +60 -0
- package/src/tools/followups/followup_resolve.ts +56 -0
- package/src/tools/host-filesystem/edit.ts +125 -0
- package/src/tools/host-filesystem/read.ts +80 -0
- package/src/tools/host-filesystem/write.ts +76 -0
- package/src/tools/host-terminal/cli-discover.ts +180 -0
- package/src/tools/host-terminal/host-shell.ts +191 -0
- package/src/tools/memory/definitions.ts +69 -0
- package/src/tools/memory/handlers.ts +246 -0
- package/src/tools/memory/register.ts +66 -0
- package/src/tools/network/__tests__/web-search.test.ts +427 -0
- package/src/tools/network/domain-normalize.ts +85 -0
- package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
- package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
- package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
- package/src/tools/network/script-proxy/certs.ts +237 -0
- package/src/tools/network/script-proxy/connect-tunnel.ts +82 -0
- package/src/tools/network/script-proxy/http-forwarder.ts +151 -0
- package/src/tools/network/script-proxy/index.ts +28 -0
- package/src/tools/network/script-proxy/logging.ts +196 -0
- package/src/tools/network/script-proxy/mitm-handler.ts +269 -0
- package/src/tools/network/script-proxy/policy.ts +152 -0
- package/src/tools/network/script-proxy/router.ts +60 -0
- package/src/tools/network/script-proxy/server.ts +136 -0
- package/src/tools/network/script-proxy/session-manager.ts +534 -0
- package/src/tools/network/script-proxy/types.ts +125 -0
- package/src/tools/network/url-safety.ts +227 -0
- package/src/tools/network/web-fetch.ts +713 -0
- package/src/tools/network/web-search.ts +296 -0
- package/src/tools/policy-context.ts +29 -0
- package/src/tools/registry.ts +295 -0
- package/src/tools/reminder/reminder-store.ts +148 -0
- package/src/tools/reminder/reminder.ts +80 -0
- package/src/tools/schedule/create.ts +81 -0
- package/src/tools/schedule/delete.ts +28 -0
- package/src/tools/schedule/list.ts +69 -0
- package/src/tools/schedule/update.ts +97 -0
- package/src/tools/shared/filesystem/edit-engine.ts +56 -0
- package/src/tools/shared/filesystem/errors.ts +85 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +215 -0
- package/src/tools/shared/filesystem/format-diff.ts +35 -0
- package/src/tools/shared/filesystem/path-policy.ts +125 -0
- package/src/tools/shared/filesystem/size-guard.ts +41 -0
- package/src/tools/shared/filesystem/types.ts +80 -0
- package/src/tools/shared/shell-output.ts +52 -0
- package/src/tools/skills/delete-managed.ts +60 -0
- package/src/tools/skills/load.ts +139 -0
- package/src/tools/skills/sandbox-runner.ts +279 -0
- package/src/tools/skills/scaffold-managed.ts +150 -0
- package/src/tools/skills/script-contract.ts +6 -0
- package/src/tools/skills/skill-script-runner.ts +86 -0
- package/src/tools/skills/skill-tool-factory.ts +64 -0
- package/src/tools/skills/vellum-catalog.ts +217 -0
- package/src/tools/subagent/abort.ts +33 -0
- package/src/tools/subagent/message.ts +39 -0
- package/src/tools/subagent/read.ts +67 -0
- package/src/tools/subagent/spawn.ts +46 -0
- package/src/tools/subagent/status.ts +45 -0
- package/src/tools/swarm/delegate.ts +183 -0
- package/src/tools/system/request-permission.ts +98 -0
- package/src/tools/system/version.ts +43 -0
- package/src/tools/tasks/index.ts +27 -0
- package/src/tools/tasks/task-delete.ts +82 -0
- package/src/tools/tasks/task-list.ts +44 -0
- package/src/tools/tasks/task-run.ts +97 -0
- package/src/tools/tasks/task-save.ts +47 -0
- package/src/tools/tasks/work-item-enqueue.ts +234 -0
- package/src/tools/tasks/work-item-list.ts +55 -0
- package/src/tools/tasks/work-item-remove.ts +60 -0
- package/src/tools/tasks/work-item-run.ts +78 -0
- package/src/tools/tasks/work-item-update.ts +114 -0
- package/src/tools/terminal/backends/docker.ts +372 -0
- package/src/tools/terminal/backends/native.ts +190 -0
- package/src/tools/terminal/backends/types.ts +26 -0
- package/src/tools/terminal/evaluate-typescript.ts +275 -0
- package/src/tools/terminal/parser.ts +413 -0
- package/src/tools/terminal/safe-env.ts +37 -0
- package/src/tools/terminal/sandbox-diagnostics.ts +149 -0
- package/src/tools/terminal/sandbox.ts +44 -0
- package/src/tools/terminal/shell.ts +257 -0
- package/src/tools/tool-manifest.ts +198 -0
- package/src/tools/types.ts +176 -0
- package/src/tools/ui-surface/definitions.ts +244 -0
- package/src/tools/ui-surface/registry.ts +14 -0
- package/src/tools/watch/screen-watch.ts +130 -0
- package/src/tools/watch/watch-state.ts +119 -0
- package/src/tools/watcher/create.ts +64 -0
- package/src/tools/watcher/delete.ts +27 -0
- package/src/tools/watcher/digest.ts +50 -0
- package/src/tools/watcher/list.ts +60 -0
- package/src/tools/watcher/update.ts +56 -0
- package/src/tools/weather/service.ts +551 -0
- package/src/twitter/client.ts +690 -0
- package/src/twitter/oauth-client.ts +102 -0
- package/src/twitter/router.ts +101 -0
- package/src/twitter/session.ts +91 -0
- package/src/usage/actors.ts +24 -0
- package/src/usage/types.ts +37 -0
- package/src/util/clipboard.ts +33 -0
- package/src/util/content-id.ts +16 -0
- package/src/util/debounce.ts +88 -0
- package/src/util/diff.ts +181 -0
- package/src/util/errors.ts +129 -0
- package/src/util/logger.ts +243 -0
- package/src/util/network-info.ts +47 -0
- package/src/util/platform.ts +632 -0
- package/src/util/pricing.ts +150 -0
- package/src/util/promise-guard.ts +37 -0
- package/src/util/retry.ts +98 -0
- package/src/util/spinner.ts +51 -0
- package/src/util/time.ts +16 -0
- package/src/util/truncate.ts +6 -0
- package/src/util/xml.ts +4 -0
- package/src/version.ts +3 -0
- package/src/watcher/constants.ts +11 -0
- package/src/watcher/engine.ts +199 -0
- package/src/watcher/provider-registry.ts +15 -0
- package/src/watcher/provider-types.ts +48 -0
- package/src/watcher/providers/gmail.ts +198 -0
- package/src/watcher/providers/google-calendar.ts +228 -0
- package/src/watcher/providers/slack.ts +129 -0
- package/src/watcher/watcher-store.ts +419 -0
- package/src/work-items/work-item-runner.ts +171 -0
- package/src/work-items/work-item-store.ts +325 -0
- package/src/workspace/commit-message-enrichment-service.ts +284 -0
- package/src/workspace/commit-message-provider.ts +95 -0
- package/src/workspace/git-service.ts +857 -0
- package/src/workspace/heartbeat-service.ts +345 -0
- package/src/workspace/provider-commit-message-generator.ts +285 -0
- package/src/workspace/top-level-renderer.ts +19 -0
- package/src/workspace/top-level-scanner.ts +41 -0
- package/src/workspace/turn-commit.ts +175 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,980 @@
|
|
|
1
|
+
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
2
|
+
import type { ImageContent } from '../../providers/types.js';
|
|
3
|
+
import { getLogger } from '../../util/logger.js';
|
|
4
|
+
import { truncate } from '../../util/truncate.js';
|
|
5
|
+
import {
|
|
6
|
+
parseUrl,
|
|
7
|
+
isPrivateOrLocalHost,
|
|
8
|
+
resolveHostAddresses,
|
|
9
|
+
resolveRequestAddress,
|
|
10
|
+
sanitizeUrlForOutput,
|
|
11
|
+
} from '../network/url-safety.js';
|
|
12
|
+
import { browserManager } from './browser-manager.js';
|
|
13
|
+
import type { RouteHandler, PageResponse } from './browser-manager.js';
|
|
14
|
+
import { detectAuthChallenge, detectCaptchaChallenge, formatAuthChallenge } from './auth-detector.js';
|
|
15
|
+
import { credentialBroker } from '../credentials/broker.js';
|
|
16
|
+
import {
|
|
17
|
+
ensureScreencast,
|
|
18
|
+
updateBrowserStatus,
|
|
19
|
+
updatePagesList,
|
|
20
|
+
stopBrowserScreencast,
|
|
21
|
+
stopAllScreencasts,
|
|
22
|
+
getSender,
|
|
23
|
+
getElementBounds,
|
|
24
|
+
updateHighlights,
|
|
25
|
+
} from './browser-screencast.js';
|
|
26
|
+
|
|
27
|
+
const log = getLogger('headless-browser');
|
|
28
|
+
|
|
29
|
+
// ── Constants ────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
export const NAVIGATE_TIMEOUT_MS = 15_000;
|
|
32
|
+
|
|
33
|
+
export const ACTION_TIMEOUT_MS = 10_000;
|
|
34
|
+
|
|
35
|
+
export const MAX_SNAPSHOT_ELEMENTS = 150;
|
|
36
|
+
|
|
37
|
+
export const INTERACTIVE_SELECTOR = [
|
|
38
|
+
'a[href]',
|
|
39
|
+
'button',
|
|
40
|
+
'input',
|
|
41
|
+
'select',
|
|
42
|
+
'textarea',
|
|
43
|
+
'[role="button"]',
|
|
44
|
+
'[role="link"]',
|
|
45
|
+
'[role="checkbox"]',
|
|
46
|
+
'[role="radio"]',
|
|
47
|
+
'[role="tab"]',
|
|
48
|
+
'[role="menuitem"]',
|
|
49
|
+
'[contenteditable="true"]',
|
|
50
|
+
].join(', ');
|
|
51
|
+
|
|
52
|
+
export type SnapshotElement = {
|
|
53
|
+
eid: string;
|
|
54
|
+
tag: string;
|
|
55
|
+
attrs: Record<string, string>;
|
|
56
|
+
text: string;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const MAX_WAIT_MS = 30_000;
|
|
60
|
+
|
|
61
|
+
export const MAX_EXTRACT_LENGTH = 50_000;
|
|
62
|
+
|
|
63
|
+
// ── Shared element resolution ────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
export function resolveSelector(
|
|
66
|
+
sessionId: string,
|
|
67
|
+
input: Record<string, unknown>,
|
|
68
|
+
): { selector: string | null; error: string | null } {
|
|
69
|
+
const elementId = typeof input.element_id === 'string' ? input.element_id : null;
|
|
70
|
+
const rawSelector = typeof input.selector === 'string' ? input.selector : null;
|
|
71
|
+
|
|
72
|
+
if (!elementId && !rawSelector) {
|
|
73
|
+
return { selector: null, error: 'Error: Either element_id or selector is required.' };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (elementId) {
|
|
77
|
+
const resolved = browserManager.resolveSnapshotSelector(sessionId, elementId);
|
|
78
|
+
if (!resolved) {
|
|
79
|
+
return {
|
|
80
|
+
selector: null,
|
|
81
|
+
error: `Error: element_id "${elementId}" not found. Run browser_snapshot first to get current element IDs.`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return { selector: resolved, error: null };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { selector: rawSelector!, error: null };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── browser_navigate ─────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
export async function executeBrowserNavigate(
|
|
93
|
+
input: Record<string, unknown>,
|
|
94
|
+
context: ToolContext,
|
|
95
|
+
): Promise<ToolExecutionResult> {
|
|
96
|
+
const parsedUrl = parseUrl(input.url);
|
|
97
|
+
if (!parsedUrl) {
|
|
98
|
+
return { content: 'Error: url is required and must be a valid HTTP(S) URL', isError: true };
|
|
99
|
+
}
|
|
100
|
+
if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
|
|
101
|
+
return { content: 'Error: url must use http or https', isError: true };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const allowPrivateNetwork = input.allow_private_network === true;
|
|
105
|
+
const safeRequestedUrl = sanitizeUrlForOutput(parsedUrl);
|
|
106
|
+
|
|
107
|
+
// Block private/local targets by default
|
|
108
|
+
if (!allowPrivateNetwork && isPrivateOrLocalHost(parsedUrl.hostname)) {
|
|
109
|
+
return {
|
|
110
|
+
content: `Error: Refusing to navigate to local/private network target (${parsedUrl.hostname}). Set allow_private_network=true if you explicitly need it.`,
|
|
111
|
+
isError: true,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// DNS resolution check for non-literal hostnames
|
|
116
|
+
if (!allowPrivateNetwork) {
|
|
117
|
+
const resolution = await resolveRequestAddress(
|
|
118
|
+
parsedUrl.hostname,
|
|
119
|
+
resolveHostAddresses,
|
|
120
|
+
allowPrivateNetwork,
|
|
121
|
+
);
|
|
122
|
+
if (resolution.blockedAddress) {
|
|
123
|
+
return {
|
|
124
|
+
content: `Error: Refusing to navigate to target (${parsedUrl.hostname}) because it resolves to local/private network address ${resolution.blockedAddress}. Set allow_private_network=true if you explicitly need it.`,
|
|
125
|
+
isError: true,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let routeHandler: RouteHandler | null = null;
|
|
131
|
+
let blockedUrl: string | null = null;
|
|
132
|
+
|
|
133
|
+
// Start screencast if a sender is registered for this session
|
|
134
|
+
const sender = getSender(context.sessionId);
|
|
135
|
+
if (sender) {
|
|
136
|
+
await ensureScreencast(context.sessionId, sender);
|
|
137
|
+
updateBrowserStatus(context.sessionId, sender, 'navigating', `Navigating to ${safeRequestedUrl}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const page = await browserManager.getOrCreateSessionPage(context.sessionId);
|
|
142
|
+
log.debug({ url: safeRequestedUrl, sessionId: context.sessionId }, 'Navigating');
|
|
143
|
+
|
|
144
|
+
// Install request interception to block redirects/sub-requests to private networks.
|
|
145
|
+
// This prevents SSRF bypass via server-side redirects and DNS rebinding attacks,
|
|
146
|
+
// since Playwright follows redirects internally and performs its own DNS resolution.
|
|
147
|
+
// Only skip for connectOverCDP browsers where page.route() is unreliable.
|
|
148
|
+
if (!allowPrivateNetwork && browserManager.supportsRouteInterception) {
|
|
149
|
+
// Cache DNS results per-hostname to avoid redundant lookups on subrequests
|
|
150
|
+
// (heavy sites like DoorDash fire hundreds of requests to the same CDN hostnames).
|
|
151
|
+
// Use a short TTL to mitigate DNS rebinding attacks where a hostname first
|
|
152
|
+
// resolves to a public IP then later to a private one. Blocked results are
|
|
153
|
+
// never cached so they are always re-resolved.
|
|
154
|
+
const DNS_CACHE_TTL_MS = 5_000;
|
|
155
|
+
const dnsCache = new Map<string, { addresses: string[]; blockedAddress?: string; cachedAt: number }>();
|
|
156
|
+
routeHandler = async (route, request) => {
|
|
157
|
+
try {
|
|
158
|
+
const reqUrl = request.url();
|
|
159
|
+
let reqParsed: URL;
|
|
160
|
+
try {
|
|
161
|
+
reqParsed = new URL(reqUrl);
|
|
162
|
+
} catch {
|
|
163
|
+
await route.continue();
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check hostname against private/local patterns
|
|
168
|
+
if (isPrivateOrLocalHost(reqParsed.hostname)) {
|
|
169
|
+
blockedUrl = sanitizeUrlForOutput(reqParsed);
|
|
170
|
+
log.warn({ blockedUrl }, 'Blocked navigation to private network target via redirect');
|
|
171
|
+
await route.abort('blockedbyclient');
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Resolve DNS and check resolved addresses (cached per hostname with TTL).
|
|
176
|
+
// Blocked results are never cached to ensure re-resolution catches
|
|
177
|
+
// DNS rebinding where a hostname flips from public to private IP.
|
|
178
|
+
let cached = dnsCache.get(reqParsed.hostname);
|
|
179
|
+
const now = Date.now();
|
|
180
|
+
if (cached && (now - cached.cachedAt > DNS_CACHE_TTL_MS)) {
|
|
181
|
+
dnsCache.delete(reqParsed.hostname);
|
|
182
|
+
cached = undefined;
|
|
183
|
+
}
|
|
184
|
+
const resolution = cached ?? await (async () => {
|
|
185
|
+
const res = await resolveRequestAddress(
|
|
186
|
+
reqParsed.hostname,
|
|
187
|
+
resolveHostAddresses,
|
|
188
|
+
false,
|
|
189
|
+
);
|
|
190
|
+
// Only cache allowed results; blocked results must be re-resolved
|
|
191
|
+
if (!res.blockedAddress) {
|
|
192
|
+
dnsCache.set(reqParsed.hostname, { ...res, cachedAt: now });
|
|
193
|
+
}
|
|
194
|
+
return res;
|
|
195
|
+
})();
|
|
196
|
+
if (resolution.blockedAddress) {
|
|
197
|
+
blockedUrl = sanitizeUrlForOutput(reqParsed);
|
|
198
|
+
log.warn({ blockedUrl, resolvedTo: resolution.blockedAddress }, 'Blocked navigation: DNS resolves to private address');
|
|
199
|
+
await route.abort('blockedbyclient');
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
await route.continue();
|
|
204
|
+
} catch (err) {
|
|
205
|
+
// Route may already be handled if the page navigated or was closed
|
|
206
|
+
log.debug({ err }, 'Route handler error (route likely already handled)');
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
await page.route('**/*', routeHandler);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Use domcontentloaded but with a shorter timeout — if it times out,
|
|
213
|
+
// the page is likely still usable (heavy SPAs like DoorDash keep loading
|
|
214
|
+
// scripts after DOMContentLoaded). Fall back gracefully instead of failing.
|
|
215
|
+
let response: PageResponse | null = null;
|
|
216
|
+
let navigationTimedOut = false;
|
|
217
|
+
const urlBeforeNav = page.url();
|
|
218
|
+
try {
|
|
219
|
+
response = await page.goto(parsedUrl.href, {
|
|
220
|
+
waitUntil: 'domcontentloaded',
|
|
221
|
+
timeout: NAVIGATE_TIMEOUT_MS,
|
|
222
|
+
});
|
|
223
|
+
} catch (navErr) {
|
|
224
|
+
const navMsg = navErr instanceof Error ? navErr.message : String(navErr);
|
|
225
|
+
if (navMsg.includes('Timeout') || navMsg.includes('timeout')) {
|
|
226
|
+
// If the page URL never changed from before navigation, the page
|
|
227
|
+
// never actually loaded — re-throw instead of reporting success.
|
|
228
|
+
if (page.url() === urlBeforeNav && urlBeforeNav !== parsedUrl.href) {
|
|
229
|
+
throw navErr;
|
|
230
|
+
}
|
|
231
|
+
navigationTimedOut = true;
|
|
232
|
+
log.info({ url: safeRequestedUrl }, 'Navigation timed out waiting for domcontentloaded, continuing with partial load');
|
|
233
|
+
} else {
|
|
234
|
+
throw navErr;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Remove the route handler now that navigation is complete
|
|
239
|
+
if (routeHandler) {
|
|
240
|
+
await page.unroute('**/*', routeHandler);
|
|
241
|
+
routeHandler = null;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// In CDP mode, keep the browser minimized unless a handoff is active.
|
|
245
|
+
if (browserManager.browserMode === 'cdp' && !browserManager.isInteractive(context.sessionId)) {
|
|
246
|
+
await browserManager.moveWindowOffscreen();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (blockedUrl) {
|
|
250
|
+
if (sender) {
|
|
251
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
content: `Error: Navigation blocked. A request targeted a local/private network address (${blockedUrl}). Set allow_private_network=true if you explicitly need it.`,
|
|
255
|
+
isError: true,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Navigation changed the page content, so clear stale snapshot mappings.
|
|
260
|
+
// Without this, element IDs from a previous page could resolve and cause
|
|
261
|
+
// confusing Playwright timeout errors instead of the actionable
|
|
262
|
+
// "run browser_snapshot first" message.
|
|
263
|
+
browserManager.clearSnapshotMap(context.sessionId);
|
|
264
|
+
|
|
265
|
+
// Auto-dismiss common blocker modals (regulatory notices, cookie banners)
|
|
266
|
+
// that aren't exposed in the accessibility tree. Runs silently — if no
|
|
267
|
+
// modal is present the evaluate is a no-op.
|
|
268
|
+
try {
|
|
269
|
+
await page.evaluate(`(() => {
|
|
270
|
+
const dismissPatterns = /^(got it|accept|ok|dismiss|i understand|close)$/i;
|
|
271
|
+
const buttons = document.querySelectorAll('button, [role="button"], input[type="submit"]');
|
|
272
|
+
for (const btn of buttons) {
|
|
273
|
+
const text = (btn.textContent || '').trim();
|
|
274
|
+
if (dismissPatterns.test(text)) {
|
|
275
|
+
const modal = btn.closest('[role="dialog"], [class*="modal"], [class*="Modal"], [class*="overlay"], [class*="Overlay"]');
|
|
276
|
+
if (modal) {
|
|
277
|
+
btn.click();
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
})()`);
|
|
283
|
+
} catch {
|
|
284
|
+
// Page may have navigated during evaluate — safe to ignore
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const finalUrl = page.url();
|
|
288
|
+
const safeFinalUrl = sanitizeUrlForOutput(new URL(finalUrl));
|
|
289
|
+
const title = await page.title();
|
|
290
|
+
const status = response?.status() ?? null;
|
|
291
|
+
|
|
292
|
+
const lines: string[] = [
|
|
293
|
+
`Requested URL: ${safeRequestedUrl}`,
|
|
294
|
+
`Final URL: ${safeFinalUrl}`,
|
|
295
|
+
`Status: ${status ?? 'unknown'}`,
|
|
296
|
+
`Title: ${title || '(none)'}`,
|
|
297
|
+
];
|
|
298
|
+
|
|
299
|
+
if (navigationTimedOut) {
|
|
300
|
+
lines.push(`Note: Page is still loading (domcontentloaded timed out). The page should still be interactive — use browser_snapshot to check.`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (finalUrl !== parsedUrl.href) {
|
|
304
|
+
lines.push(`Note: Page redirected from the requested URL.`);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Detect auth challenges (login pages, 2FA, OAuth consent) and CAPTCHA challenges
|
|
308
|
+
try {
|
|
309
|
+
const authChallenge = await detectAuthChallenge(page);
|
|
310
|
+
const captchaChallenge = await detectCaptchaChallenge(page);
|
|
311
|
+
// CAPTCHA takes priority — it blocks all interaction including login
|
|
312
|
+
let challenge = captchaChallenge ?? authChallenge;
|
|
313
|
+
|
|
314
|
+
// Many CAPTCHA interstitials (e.g. Cloudflare "Just a moment") auto-resolve
|
|
315
|
+
// within a few seconds. Wait and re-check before handing off to the user.
|
|
316
|
+
if (challenge?.type === 'captcha') {
|
|
317
|
+
log.info('CAPTCHA detected, waiting up to 5s for auto-resolve');
|
|
318
|
+
for (let i = 0; i < 5; i++) {
|
|
319
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
320
|
+
const still = await detectCaptchaChallenge(page);
|
|
321
|
+
if (!still) {
|
|
322
|
+
log.info('CAPTCHA auto-resolved');
|
|
323
|
+
// Re-check for auth challenge now that CAPTCHA is gone —
|
|
324
|
+
// the page may have loaded a login form behind it.
|
|
325
|
+
challenge = await detectAuthChallenge(page);
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (challenge) {
|
|
332
|
+
if (challenge.type === 'captcha') {
|
|
333
|
+
// CAPTCHA persisted after auto-resolve wait — hand off to user
|
|
334
|
+
if (browserManager.browserMode === 'cdp' && sender) {
|
|
335
|
+
const { startHandoff } = await import('./browser-handoff.js');
|
|
336
|
+
await startHandoff(context.sessionId, sender, {
|
|
337
|
+
reason: 'captcha',
|
|
338
|
+
message: 'Cloudflare verification detected. Please solve the CAPTCHA in the Chrome window that just opened (not the preview panel — CAPTCHA providers detect preview clicks as automated). Click "Hand back" when done.',
|
|
339
|
+
bringToFront: true,
|
|
340
|
+
});
|
|
341
|
+
const newUrl = page.url();
|
|
342
|
+
const newTitle = await page.title();
|
|
343
|
+
lines.push('');
|
|
344
|
+
lines.push(`CAPTCHA solved by user. Current page: ${newTitle} (${newUrl})`);
|
|
345
|
+
|
|
346
|
+
// Re-check for auth challenges — the page behind the CAPTCHA may have a login form
|
|
347
|
+
const postCaptchaAuth = await detectAuthChallenge(page);
|
|
348
|
+
if (postCaptchaAuth) {
|
|
349
|
+
lines.push('');
|
|
350
|
+
lines.push(formatAuthChallenge(postCaptchaAuth));
|
|
351
|
+
lines.push('');
|
|
352
|
+
lines.push('Handle this by using browser tools to interact with the login form:');
|
|
353
|
+
lines.push('1. Use browser_snapshot to find the sign-in form elements');
|
|
354
|
+
lines.push('2. Use browser_fill_credential to fill email/password from credential_store');
|
|
355
|
+
lines.push('3. For SMS/email verification codes, use ui_show with a form to ask the user for the code mid-turn');
|
|
356
|
+
lines.push('4. Do NOT give up or tell the user to sign in manually — handle the login flow yourself');
|
|
357
|
+
}
|
|
358
|
+
} else {
|
|
359
|
+
lines.push('');
|
|
360
|
+
lines.push('⚠️ CAPTCHA/Cloudflare verification detected on this page.');
|
|
361
|
+
lines.push('The user needs to solve this challenge manually. Please inform the user that the page requires human verification before the content can be accessed.');
|
|
362
|
+
}
|
|
363
|
+
} else {
|
|
364
|
+
// Login / 2FA / OAuth — the agent should handle these itself
|
|
365
|
+
// using browser tools + credential_store. Don't hand off.
|
|
366
|
+
lines.push('');
|
|
367
|
+
lines.push(formatAuthChallenge(challenge));
|
|
368
|
+
lines.push('');
|
|
369
|
+
lines.push('Handle this by using browser tools to interact with the login form:');
|
|
370
|
+
lines.push('1. Use browser_snapshot to find the sign-in form elements');
|
|
371
|
+
lines.push('2. Use browser_fill_credential to fill email/password from credential_store');
|
|
372
|
+
lines.push('3. For SMS/email verification codes, use ui_show with a form to ask the user for the code mid-turn');
|
|
373
|
+
lines.push('4. Do NOT give up or tell the user to sign in manually — handle the login flow yourself');
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
} catch {
|
|
377
|
+
// Auth/CAPTCHA detection is best-effort; don't fail navigation
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (sender) {
|
|
381
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
382
|
+
await updatePagesList(context.sessionId, sender);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return { content: lines.join('\n'), isError: false };
|
|
386
|
+
} catch (err) {
|
|
387
|
+
// Best-effort cleanup of route handler on error
|
|
388
|
+
if (routeHandler) {
|
|
389
|
+
try {
|
|
390
|
+
const page = await browserManager.getOrCreateSessionPage(context.sessionId);
|
|
391
|
+
await page.unroute('**/*', routeHandler);
|
|
392
|
+
} catch { /* ignore cleanup errors */ }
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// If the route handler blocked a redirect to a private network address,
|
|
396
|
+
// page.goto() throws. Return the clear security message instead of the
|
|
397
|
+
// raw Playwright error (which could leak credentials from the URL).
|
|
398
|
+
if (blockedUrl) {
|
|
399
|
+
if (sender) {
|
|
400
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
content: `Error: Navigation blocked. A request targeted a local/private network address (${blockedUrl}). Set allow_private_network=true if you explicitly need it.`,
|
|
404
|
+
isError: true,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
409
|
+
log.error({ err, url: safeRequestedUrl }, 'Navigation failed');
|
|
410
|
+
if (sender) {
|
|
411
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
412
|
+
}
|
|
413
|
+
return { content: `Error: Navigation failed: ${msg}`, isError: true };
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// ── browser_snapshot ─────────────────────────────────────────────────
|
|
418
|
+
|
|
419
|
+
export async function executeBrowserSnapshot(
|
|
420
|
+
_input: Record<string, unknown>,
|
|
421
|
+
context: ToolContext,
|
|
422
|
+
): Promise<ToolExecutionResult> {
|
|
423
|
+
try {
|
|
424
|
+
const page = await browserManager.getOrCreateSessionPage(context.sessionId);
|
|
425
|
+
const currentUrl = page.url();
|
|
426
|
+
const title = await page.title();
|
|
427
|
+
|
|
428
|
+
const elements = (await page.evaluate(`
|
|
429
|
+
(() => {
|
|
430
|
+
const SELECTOR = ${JSON.stringify(INTERACTIVE_SELECTOR)};
|
|
431
|
+
const MAX = ${MAX_SNAPSHOT_ELEMENTS};
|
|
432
|
+
// Clear stale eid attributes from previous snapshots
|
|
433
|
+
document.querySelectorAll('[data-vellum-eid]').forEach(el => el.removeAttribute('data-vellum-eid'));
|
|
434
|
+
const els = Array.from(document.querySelectorAll(SELECTOR));
|
|
435
|
+
const visible = els.filter(el => {
|
|
436
|
+
const rect = el.getBoundingClientRect();
|
|
437
|
+
return rect.width > 0 && rect.height > 0;
|
|
438
|
+
});
|
|
439
|
+
return visible.slice(0, MAX).map((el, i) => {
|
|
440
|
+
const eid = 'e' + (i + 1);
|
|
441
|
+
el.setAttribute('data-vellum-eid', eid);
|
|
442
|
+
const tag = el.tagName.toLowerCase();
|
|
443
|
+
const attrs = {};
|
|
444
|
+
for (const attr of ['type', 'name', 'placeholder', 'href', 'value', 'role', 'aria-label', 'id']) {
|
|
445
|
+
if (el.hasAttribute(attr)) attrs[attr] = el.getAttribute(attr);
|
|
446
|
+
}
|
|
447
|
+
const text = (el.textContent || '').trim().slice(0, 80);
|
|
448
|
+
return { eid, tag, attrs, text };
|
|
449
|
+
});
|
|
450
|
+
})()
|
|
451
|
+
`)) as SnapshotElement[];
|
|
452
|
+
|
|
453
|
+
// Build and store selector map
|
|
454
|
+
const selectorMap = new Map<string, string>();
|
|
455
|
+
for (const el of elements) {
|
|
456
|
+
selectorMap.set(el.eid, `[data-vellum-eid="${el.eid}"]`);
|
|
457
|
+
}
|
|
458
|
+
browserManager.storeSnapshotMap(context.sessionId, selectorMap);
|
|
459
|
+
|
|
460
|
+
// Format output
|
|
461
|
+
const lines: string[] = [
|
|
462
|
+
`URL: ${currentUrl}`,
|
|
463
|
+
`Title: ${title || '(none)'}`,
|
|
464
|
+
'',
|
|
465
|
+
];
|
|
466
|
+
|
|
467
|
+
if (elements.length === 0) {
|
|
468
|
+
lines.push('(no interactive elements found)');
|
|
469
|
+
} else {
|
|
470
|
+
for (const el of elements) {
|
|
471
|
+
let desc = `<${el.tag}`;
|
|
472
|
+
for (const [key, val] of Object.entries(el.attrs)) {
|
|
473
|
+
desc += ` ${key}="${val}"`;
|
|
474
|
+
}
|
|
475
|
+
desc += '>';
|
|
476
|
+
if (el.text) {
|
|
477
|
+
desc += ` ${el.text}`;
|
|
478
|
+
}
|
|
479
|
+
lines.push(`[${el.eid}] ${desc}`);
|
|
480
|
+
}
|
|
481
|
+
lines.push('');
|
|
482
|
+
lines.push(`${elements.length} interactive element${elements.length === 1 ? '' : 's'} found.`);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return { content: lines.join('\n'), isError: false };
|
|
486
|
+
} catch (err) {
|
|
487
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
488
|
+
log.error({ err }, 'Snapshot failed');
|
|
489
|
+
return { content: `Error: Snapshot failed: ${msg}`, isError: true };
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// ── browser_screenshot ───────────────────────────────────────────────
|
|
494
|
+
|
|
495
|
+
export async function executeBrowserScreenshot(
|
|
496
|
+
input: Record<string, unknown>,
|
|
497
|
+
context: ToolContext,
|
|
498
|
+
): Promise<ToolExecutionResult> {
|
|
499
|
+
const fullPage = input.full_page === true;
|
|
500
|
+
|
|
501
|
+
try {
|
|
502
|
+
const page = await browserManager.getOrCreateSessionPage(context.sessionId);
|
|
503
|
+
const buffer = await page.screenshot({ type: 'jpeg', quality: 80, fullPage });
|
|
504
|
+
const base64Data = buffer.toString('base64');
|
|
505
|
+
|
|
506
|
+
const imageBlock: ImageContent = {
|
|
507
|
+
type: 'image' as const,
|
|
508
|
+
source: {
|
|
509
|
+
type: 'base64' as const,
|
|
510
|
+
media_type: 'image/jpeg',
|
|
511
|
+
data: base64Data,
|
|
512
|
+
},
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
return {
|
|
516
|
+
content: `Screenshot captured (${buffer.length} bytes, ${fullPage ? 'full page' : 'viewport'})`,
|
|
517
|
+
isError: false,
|
|
518
|
+
contentBlocks: [imageBlock],
|
|
519
|
+
};
|
|
520
|
+
} catch (err) {
|
|
521
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
522
|
+
log.error({ err }, 'Screenshot failed');
|
|
523
|
+
return { content: `Error: Screenshot failed: ${msg}`, isError: true };
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// ── browser_close ────────────────────────────────────────────────────
|
|
528
|
+
|
|
529
|
+
export async function executeBrowserClose(
|
|
530
|
+
input: Record<string, unknown>,
|
|
531
|
+
context: ToolContext,
|
|
532
|
+
): Promise<ToolExecutionResult> {
|
|
533
|
+
try {
|
|
534
|
+
const sender = getSender(context.sessionId);
|
|
535
|
+
if (sender) {
|
|
536
|
+
await stopBrowserScreencast(context.sessionId, sender);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (input.close_all_pages === true) {
|
|
540
|
+
await stopAllScreencasts();
|
|
541
|
+
await browserManager.closeAllPages();
|
|
542
|
+
return { content: 'All browser pages and context closed.', isError: false };
|
|
543
|
+
}
|
|
544
|
+
await browserManager.closeSessionPage(context.sessionId);
|
|
545
|
+
return { content: 'Browser page closed for this session.', isError: false };
|
|
546
|
+
} catch (err) {
|
|
547
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
548
|
+
log.error({ err }, 'Close failed');
|
|
549
|
+
return { content: `Error: Close failed: ${msg}`, isError: true };
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// ── browser_click ────────────────────────────────────────────────────
|
|
554
|
+
|
|
555
|
+
export async function executeBrowserClick(
|
|
556
|
+
input: Record<string, unknown>,
|
|
557
|
+
context: ToolContext,
|
|
558
|
+
): Promise<ToolExecutionResult> {
|
|
559
|
+
const { selector, error } = resolveSelector(context.sessionId, input);
|
|
560
|
+
if (error) return { content: error, isError: true };
|
|
561
|
+
|
|
562
|
+
const sender = getSender(context.sessionId);
|
|
563
|
+
if (sender) {
|
|
564
|
+
await ensureScreencast(context.sessionId, sender);
|
|
565
|
+
updateBrowserStatus(context.sessionId, sender, 'interacting', 'Clicking element');
|
|
566
|
+
const bounds = await getElementBounds(context.sessionId, selector!);
|
|
567
|
+
if (bounds) {
|
|
568
|
+
updateHighlights(context.sessionId, sender, [{ ...bounds, label: 'Clicking element' }]);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const timeout = typeof input.timeout === 'number' ? input.timeout : ACTION_TIMEOUT_MS;
|
|
573
|
+
|
|
574
|
+
try {
|
|
575
|
+
const page = await browserManager.getOrCreateSessionPage(context.sessionId);
|
|
576
|
+
await page.click(selector!, { timeout });
|
|
577
|
+
if (sender) {
|
|
578
|
+
updateHighlights(context.sessionId, sender, []);
|
|
579
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
580
|
+
}
|
|
581
|
+
return { content: `Clicked element: ${selector}`, isError: false };
|
|
582
|
+
} catch (err) {
|
|
583
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
584
|
+
log.error({ err, selector }, 'Click failed');
|
|
585
|
+
if (sender) {
|
|
586
|
+
updateHighlights(context.sessionId, sender, []);
|
|
587
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
588
|
+
}
|
|
589
|
+
return { content: `Error: Click failed: ${msg}`, isError: true };
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// ── browser_type ─────────────────────────────────────────────────────
|
|
594
|
+
|
|
595
|
+
export async function executeBrowserType(
|
|
596
|
+
input: Record<string, unknown>,
|
|
597
|
+
context: ToolContext,
|
|
598
|
+
): Promise<ToolExecutionResult> {
|
|
599
|
+
const { selector, error } = resolveSelector(context.sessionId, input);
|
|
600
|
+
if (error) return { content: error, isError: true };
|
|
601
|
+
|
|
602
|
+
const text = typeof input.text === 'string' ? input.text : '';
|
|
603
|
+
if (!text) {
|
|
604
|
+
return { content: 'Error: text is required.', isError: true };
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
const clearFirst = input.clear_first !== false; // default true
|
|
608
|
+
const pressEnter = input.press_enter === true;
|
|
609
|
+
|
|
610
|
+
const sender = getSender(context.sessionId);
|
|
611
|
+
if (sender) {
|
|
612
|
+
await ensureScreencast(context.sessionId, sender);
|
|
613
|
+
updateBrowserStatus(context.sessionId, sender, 'interacting', 'Typing text');
|
|
614
|
+
const bounds = await getElementBounds(context.sessionId, selector!);
|
|
615
|
+
if (bounds) {
|
|
616
|
+
updateHighlights(context.sessionId, sender, [{ ...bounds, label: 'Typing' }]);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
try {
|
|
621
|
+
const page = await browserManager.getOrCreateSessionPage(context.sessionId);
|
|
622
|
+
|
|
623
|
+
const fillTimeout = typeof input.timeout === 'number' ? input.timeout : ACTION_TIMEOUT_MS;
|
|
624
|
+
|
|
625
|
+
if (clearFirst) {
|
|
626
|
+
await page.fill(selector!, text, { timeout: fillTimeout });
|
|
627
|
+
} else {
|
|
628
|
+
// Read existing content before appending. Use .value for form inputs,
|
|
629
|
+
// with fallback to .innerText for contenteditable elements (preserves
|
|
630
|
+
// visual line breaks from <br> and block elements, unlike textContent).
|
|
631
|
+
const currentValue = (await page.evaluate(
|
|
632
|
+
`(() => { const el = document.querySelector(${JSON.stringify(selector!)}); if (!el) return ''; if (typeof el.value === 'string') return el.value; return el.innerText ?? ''; })()`,
|
|
633
|
+
)) as string;
|
|
634
|
+
await page.fill(selector!, currentValue + text, { timeout: fillTimeout });
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
if (pressEnter) {
|
|
638
|
+
await page.press(selector!, 'Enter');
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
if (sender) {
|
|
642
|
+
updateHighlights(context.sessionId, sender, []);
|
|
643
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const lines = [`Typed into element: ${selector}`];
|
|
647
|
+
if (clearFirst) lines.push('(cleared existing content first)');
|
|
648
|
+
if (pressEnter) lines.push('(pressed Enter after typing)');
|
|
649
|
+
return { content: lines.join('\n'), isError: false };
|
|
650
|
+
} catch (err) {
|
|
651
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
652
|
+
log.error({ err, selector }, 'Type failed');
|
|
653
|
+
if (sender) {
|
|
654
|
+
updateHighlights(context.sessionId, sender, []);
|
|
655
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
656
|
+
}
|
|
657
|
+
return { content: `Error: Type failed: ${msg}`, isError: true };
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// ── browser_press_key ────────────────────────────────────────────────
|
|
662
|
+
|
|
663
|
+
export async function executeBrowserPressKey(
|
|
664
|
+
input: Record<string, unknown>,
|
|
665
|
+
context: ToolContext,
|
|
666
|
+
): Promise<ToolExecutionResult> {
|
|
667
|
+
const key = typeof input.key === 'string' ? input.key : '';
|
|
668
|
+
if (!key) {
|
|
669
|
+
return { content: 'Error: key is required.', isError: true };
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
const sender = getSender(context.sessionId);
|
|
673
|
+
if (sender) {
|
|
674
|
+
await ensureScreencast(context.sessionId, sender);
|
|
675
|
+
updateBrowserStatus(context.sessionId, sender, 'interacting', `Pressing ${key}`);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
try {
|
|
679
|
+
const page = await browserManager.getOrCreateSessionPage(context.sessionId);
|
|
680
|
+
|
|
681
|
+
// If element_id or selector is provided, press key on that element
|
|
682
|
+
const elementId = typeof input.element_id === 'string' ? input.element_id : null;
|
|
683
|
+
const rawSelector = typeof input.selector === 'string' ? input.selector : null;
|
|
684
|
+
|
|
685
|
+
if (elementId || rawSelector) {
|
|
686
|
+
const { selector, error } = resolveSelector(context.sessionId, input);
|
|
687
|
+
if (error) {
|
|
688
|
+
if (sender) {
|
|
689
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
690
|
+
}
|
|
691
|
+
return { content: error, isError: true };
|
|
692
|
+
}
|
|
693
|
+
if (sender) {
|
|
694
|
+
const bounds = await getElementBounds(context.sessionId, selector!);
|
|
695
|
+
if (bounds) {
|
|
696
|
+
updateHighlights(context.sessionId, sender, [{ ...bounds, label: `Pressing ${key}` }]);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
await page.press(selector!, key);
|
|
700
|
+
if (sender) {
|
|
701
|
+
updateHighlights(context.sessionId, sender, []);
|
|
702
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
703
|
+
}
|
|
704
|
+
return { content: `Pressed "${key}" on element: ${selector}`, isError: false };
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// No target -> press key on the page (focused element)
|
|
708
|
+
await page.keyboard.press(key);
|
|
709
|
+
if (sender) {
|
|
710
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
711
|
+
}
|
|
712
|
+
return { content: `Pressed "${key}"`, isError: false };
|
|
713
|
+
} catch (err) {
|
|
714
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
715
|
+
log.error({ err, key }, 'Press key failed');
|
|
716
|
+
if (sender) {
|
|
717
|
+
updateHighlights(context.sessionId, sender, []);
|
|
718
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
719
|
+
}
|
|
720
|
+
return { content: `Error: Press key failed: ${msg}`, isError: true };
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
// ── browser_scroll ───────────────────────────────────────────────────
|
|
726
|
+
|
|
727
|
+
export async function executeBrowserScroll(
|
|
728
|
+
input: Record<string, unknown>,
|
|
729
|
+
context: ToolContext,
|
|
730
|
+
): Promise<ToolExecutionResult> {
|
|
731
|
+
const direction = typeof input.direction === 'string' ? input.direction : '';
|
|
732
|
+
if (!direction || !['up', 'down', 'left', 'right'].includes(direction)) {
|
|
733
|
+
return { content: 'Error: direction is required and must be one of: up, down, left, right.', isError: true };
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
const amount = typeof input.amount === 'number' ? Math.abs(input.amount) : 500;
|
|
737
|
+
|
|
738
|
+
const sender = getSender(context.sessionId);
|
|
739
|
+
if (sender) {
|
|
740
|
+
await ensureScreencast(context.sessionId, sender);
|
|
741
|
+
updateBrowserStatus(context.sessionId, sender, 'interacting', `Scrolling ${direction}`);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
try {
|
|
745
|
+
const page = await browserManager.getOrCreateSessionPage(context.sessionId);
|
|
746
|
+
|
|
747
|
+
// If element_id or selector is provided, scroll within that element
|
|
748
|
+
const elementId = typeof input.element_id === 'string' ? input.element_id : null;
|
|
749
|
+
const rawSelector = typeof input.selector === 'string' ? input.selector : null;
|
|
750
|
+
|
|
751
|
+
if (elementId || rawSelector) {
|
|
752
|
+
const { selector, error } = resolveSelector(context.sessionId, input);
|
|
753
|
+
if (error) {
|
|
754
|
+
if (sender) updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
755
|
+
return { content: error, isError: true };
|
|
756
|
+
}
|
|
757
|
+
// Move mouse to element center before scrolling
|
|
758
|
+
const bounds = await getElementBounds(context.sessionId, selector!);
|
|
759
|
+
if (bounds) {
|
|
760
|
+
// Convert screencast coords back to page coords for mouse.move
|
|
761
|
+
const result = await page.evaluate(`(() => ({ vw: window.innerWidth, vh: window.innerHeight }))()`) as { vw: number; vh: number };
|
|
762
|
+
const scale = Math.min(1280 / result.vw, 960 / result.vh);
|
|
763
|
+
const pageX = (bounds.x + bounds.w / 2) / scale;
|
|
764
|
+
const pageY = (bounds.y + bounds.h / 2) / scale;
|
|
765
|
+
await page.mouse.move(pageX, pageY);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
let deltaX = 0;
|
|
770
|
+
let deltaY = 0;
|
|
771
|
+
switch (direction) {
|
|
772
|
+
case 'up': deltaY = -amount; break;
|
|
773
|
+
case 'down': deltaY = amount; break;
|
|
774
|
+
case 'left': deltaX = -amount; break;
|
|
775
|
+
case 'right': deltaX = amount; break;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
await page.mouse.wheel(deltaX, deltaY);
|
|
779
|
+
|
|
780
|
+
if (sender) {
|
|
781
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
782
|
+
}
|
|
783
|
+
return { content: `Scrolled ${direction} by ${amount}px`, isError: false };
|
|
784
|
+
} catch (err) {
|
|
785
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
786
|
+
log.error({ err, direction }, 'Scroll failed');
|
|
787
|
+
if (sender) {
|
|
788
|
+
updateBrowserStatus(context.sessionId, sender, 'idle');
|
|
789
|
+
}
|
|
790
|
+
return { content: `Error: Scroll failed: ${msg}`, isError: true };
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// ── browser_wait_for ─────────────────────────────────────────────────
|
|
795
|
+
|
|
796
|
+
export async function executeBrowserWaitFor(
|
|
797
|
+
input: Record<string, unknown>,
|
|
798
|
+
context: ToolContext,
|
|
799
|
+
): Promise<ToolExecutionResult> {
|
|
800
|
+
const selector = typeof input.selector === 'string' && input.selector ? input.selector : null;
|
|
801
|
+
const text = typeof input.text === 'string' && input.text ? input.text : null;
|
|
802
|
+
const duration = typeof input.duration === 'number' ? input.duration : null;
|
|
803
|
+
|
|
804
|
+
const modeCount = [selector, text, duration].filter((v) => v !== null).length;
|
|
805
|
+
if (modeCount === 0) {
|
|
806
|
+
return { content: 'Error: Exactly one of selector, text, or duration is required.', isError: true };
|
|
807
|
+
}
|
|
808
|
+
if (modeCount > 1) {
|
|
809
|
+
return { content: 'Error: Provide exactly one of selector, text, or duration (not multiple).', isError: true };
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
const timeout = typeof input.timeout === 'number'
|
|
813
|
+
? Math.min(input.timeout, MAX_WAIT_MS)
|
|
814
|
+
: MAX_WAIT_MS;
|
|
815
|
+
|
|
816
|
+
try {
|
|
817
|
+
const page = await browserManager.getOrCreateSessionPage(context.sessionId);
|
|
818
|
+
|
|
819
|
+
if (selector) {
|
|
820
|
+
await page.waitForSelector(selector, { timeout });
|
|
821
|
+
return { content: `Element matching "${selector}" appeared.`, isError: false };
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if (text) {
|
|
825
|
+
const escaped = JSON.stringify(text);
|
|
826
|
+
await page.waitForFunction(
|
|
827
|
+
`document.body?.innerText?.includes(${escaped})`,
|
|
828
|
+
{ timeout },
|
|
829
|
+
);
|
|
830
|
+
return { content: `Text "${truncate(text, 80)}" appeared on page.`, isError: false };
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// duration mode (milliseconds)
|
|
834
|
+
const waitMs = Math.min(duration!, MAX_WAIT_MS);
|
|
835
|
+
await new Promise((r) => setTimeout(r, waitMs));
|
|
836
|
+
return { content: `Waited ${waitMs}ms.`, isError: false };
|
|
837
|
+
} catch (err) {
|
|
838
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
839
|
+
log.error({ err }, 'Wait failed');
|
|
840
|
+
return { content: `Error: Wait failed: ${msg}`, isError: true };
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// ── browser_extract ──────────────────────────────────────────────────
|
|
845
|
+
|
|
846
|
+
export async function executeBrowserExtract(
|
|
847
|
+
input: Record<string, unknown>,
|
|
848
|
+
context: ToolContext,
|
|
849
|
+
): Promise<ToolExecutionResult> {
|
|
850
|
+
const includeLinks = input.include_links === true;
|
|
851
|
+
|
|
852
|
+
try {
|
|
853
|
+
const page = await browserManager.getOrCreateSessionPage(context.sessionId);
|
|
854
|
+
const currentUrl = page.url();
|
|
855
|
+
const title = await page.title();
|
|
856
|
+
|
|
857
|
+
let textContent = (await page.evaluate(
|
|
858
|
+
`document.body?.innerText ?? ''`,
|
|
859
|
+
)) as string;
|
|
860
|
+
|
|
861
|
+
if (textContent.length > MAX_EXTRACT_LENGTH) {
|
|
862
|
+
textContent = textContent.slice(0, MAX_EXTRACT_LENGTH) + '\n... (truncated)';
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
const lines: string[] = [
|
|
866
|
+
`URL: ${currentUrl}`,
|
|
867
|
+
`Title: ${title || '(none)'}`,
|
|
868
|
+
'',
|
|
869
|
+
textContent || '(empty page)',
|
|
870
|
+
];
|
|
871
|
+
|
|
872
|
+
if (includeLinks) {
|
|
873
|
+
const links = (await page.evaluate(`
|
|
874
|
+
(() => {
|
|
875
|
+
const anchors = Array.from(document.querySelectorAll('a[href]'));
|
|
876
|
+
return anchors.slice(0, 200).map(a => ({
|
|
877
|
+
text: (a.textContent || '').trim().slice(0, 80),
|
|
878
|
+
href: a.href,
|
|
879
|
+
}));
|
|
880
|
+
})()
|
|
881
|
+
`)) as Array<{ text: string; href: string }>;
|
|
882
|
+
|
|
883
|
+
if (links.length > 0) {
|
|
884
|
+
lines.push('');
|
|
885
|
+
lines.push('Links:');
|
|
886
|
+
for (const link of links) {
|
|
887
|
+
lines.push(` [${link.text || '(no text)'}](${link.href})`);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
return { content: lines.join('\n'), isError: false };
|
|
893
|
+
} catch (err) {
|
|
894
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
895
|
+
log.error({ err }, 'Extract failed');
|
|
896
|
+
return { content: `Error: Extract failed: ${msg}`, isError: true };
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// ── browser_fill_credential ──────────────────────────────────────────
|
|
901
|
+
|
|
902
|
+
export async function executeBrowserFillCredential(
|
|
903
|
+
input: Record<string, unknown>,
|
|
904
|
+
context: ToolContext,
|
|
905
|
+
): Promise<ToolExecutionResult> {
|
|
906
|
+
const service = typeof input.service === 'string' ? input.service : '';
|
|
907
|
+
const field = typeof input.field === 'string' ? input.field : '';
|
|
908
|
+
|
|
909
|
+
if (!service) {
|
|
910
|
+
return { content: 'Error: service is required.', isError: true };
|
|
911
|
+
}
|
|
912
|
+
if (!field) {
|
|
913
|
+
return { content: 'Error: field is required.', isError: true };
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
const { selector, error } = resolveSelector(context.sessionId, input);
|
|
917
|
+
if (error) return { content: error, isError: true };
|
|
918
|
+
|
|
919
|
+
const pressEnter = input.press_enter === true;
|
|
920
|
+
|
|
921
|
+
try {
|
|
922
|
+
const page = await browserManager.getOrCreateSessionPage(context.sessionId);
|
|
923
|
+
|
|
924
|
+
// Extract domain from the current page for domain policy enforcement
|
|
925
|
+
let pageDomain: string | undefined;
|
|
926
|
+
try {
|
|
927
|
+
const pageUrl = page.url();
|
|
928
|
+
if (pageUrl && pageUrl !== 'about:blank') {
|
|
929
|
+
const parsed = new URL(pageUrl);
|
|
930
|
+
pageDomain = parsed.hostname;
|
|
931
|
+
}
|
|
932
|
+
} catch {
|
|
933
|
+
// Invalid URL — pageDomain stays undefined, broker will deny if domain policy exists
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
const result = await credentialBroker.browserFill({
|
|
937
|
+
service,
|
|
938
|
+
field,
|
|
939
|
+
toolName: 'browser_fill_credential',
|
|
940
|
+
domain: pageDomain,
|
|
941
|
+
fill: async (value) => {
|
|
942
|
+
await page.fill(selector!, value);
|
|
943
|
+
},
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
if (!result.success) {
|
|
947
|
+
const reason = result.reason ?? 'unknown error';
|
|
948
|
+
if (reason.includes('No credential found') || reason.includes('no stored value')) {
|
|
949
|
+
return {
|
|
950
|
+
content: `No credential stored for ${service}/${field}. Use credential_store to save it first.`,
|
|
951
|
+
isError: true,
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
if (reason.includes('not allowed to use credential')) {
|
|
955
|
+
return {
|
|
956
|
+
content: `Policy denied: ${reason} Update the credential's allowed_tools via credential_store if this tool should have access.`,
|
|
957
|
+
isError: true,
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
if (reason.includes('not allowed for credential') || reason.includes('no page domain was provided')) {
|
|
961
|
+
return {
|
|
962
|
+
content: `Domain policy denied: ${reason} Navigate to an allowed domain before filling this credential.`,
|
|
963
|
+
isError: true,
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
log.error({ selector, reason }, 'Fill credential failed');
|
|
967
|
+
return { content: `Error: Fill credential failed: ${reason}`, isError: true };
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
if (pressEnter) {
|
|
971
|
+
await page.press(selector!, 'Enter');
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
return { content: `Filled ${field} for ${service} into the target element.`, isError: false };
|
|
975
|
+
} catch (err) {
|
|
976
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
977
|
+
log.error({ err }, 'Fill credential failed');
|
|
978
|
+
return { content: `Error: Fill credential failed: ${msg}`, isError: true };
|
|
979
|
+
}
|
|
980
|
+
}
|