mixdog 1.4.0 → 1.4.2
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/package.json +3 -2
- package/scripts/build-shipped-history.mjs +115 -33
- package/scripts/check-voice-runtime-inputs.mjs +25 -0
- package/scripts/gate-local.mjs +183 -63
- package/scripts/latest-guard.mjs +21 -9
- package/scripts/lib/gate-scheduler.mjs +138 -32
- package/scripts/lib/gate-timing-reporter.mjs +16 -0
- package/scripts/lib/isolated-test-env.mjs +10 -5
- package/scripts/lib/run-node-tests.mjs +91 -66
- package/scripts/lib/scoped-temp.d.mts +16 -0
- package/scripts/lib/scoped-temp.mjs +124 -0
- package/scripts/lib/stale-temp.mjs +44 -0
- package/scripts/lib/test-failure-records.mjs +14 -1
- package/scripts/lib/test-failure-summary.mjs +16 -4
- package/scripts/lib/test-spawn-ledger.mjs +12 -3
- package/scripts/post-release-check.mjs +1 -6
- package/scripts/pptx-kit-index.mjs +17 -5
- package/scripts/suite-health.mjs +115 -24
- package/scripts/test-data-dir.mjs +10 -7
- package/scripts/test.mjs +9 -14
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/explore/AGENT.md +22 -0
- package/src/agents/explore/agent.json +6 -0
- package/src/app.mjs +4 -0
- package/src/cli.mjs +7 -0
- package/src/defaults/agents.json +7 -0
- package/src/defaults/shipped-history.json +23 -2
- package/src/defaults/skills/browser-use/SKILL.md +10 -5
- package/src/defaults/skills/code-tidy/SKILL.md +71 -102
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
- package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
- package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
- package/src/defaults/skills/computer-use/SKILL.md +16 -4
- package/src/defaults/skills/goal-management/SKILL.md +1 -1
- package/src/defaults/skills/setup/references/actions.md +12 -6
- package/src/defaults/skills/setup/references/surfaces.md +2 -2
- package/src/defaults/skills/setup-guide/SKILL.md +5 -2
- package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
- package/src/defaults/skills/skill-creator/SKILL.md +85 -190
- package/src/defaults/skills/skill-creator/references/design.md +70 -162
- package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
- package/src/defaults/skills/test-suite/SKILL.md +194 -0
- package/src/defaults/skills/test-suite/references/case-management.md +51 -0
- package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
- package/src/defaults/skills/test-suite/references/reliability.md +49 -0
- package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
- package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
- package/src/defaults/skills/visualize/SKILL.md +6 -2
- package/src/lib/rules-builder.cjs +35 -42
- package/src/output-styles/common.md +2 -2
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/AGENT.md +5 -4
- package/src/rules/lead/LEAD.md +12 -7
- package/src/rules/shared/10-tool-workflow.md +3 -1
- package/src/rules/shared/20-research.md +3 -6
- package/src/rules/shared/40-editing.md +1 -0
- package/src/rules/shared/45-destructive.md +0 -2
- package/src/rules/shared/50-execution.md +2 -0
- package/src/rules/shared/60-verification.md +10 -9
- package/src/rules/shared/70-delivery.md +8 -9
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +156 -24
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -0
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/config.mjs +12 -7
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +8 -8
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +3 -1
- package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +122 -12
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -3
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +13 -2
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +152 -58
- package/src/runtime/agent/orchestrator/mcp/client.mjs +51 -18
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +88 -54
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +54 -8
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +37 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +248 -41
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
- package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +160 -31
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +22 -12
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +49 -22
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +45 -2
- package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +567 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +41 -13
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -6
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +14 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +102 -12
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +160 -36
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +164 -23
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +139 -19
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +100 -22
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -6
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +33 -3
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +23 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +39 -21
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +30 -13
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +63 -6
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +35 -13
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +24 -14
- package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +10 -6
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +56 -29
- package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +30 -7
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +37 -8
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +252 -39
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +164 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +61 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -20
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +67 -31
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +25 -13
- package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +96 -20
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +103 -13
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +34 -10
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +28 -4
- package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
- package/src/runtime/channels/lib/whisper-port.mjs +29 -11
- package/src/runtime/channels/lib/whisper-server.mjs +10 -1
- package/src/runtime/computer-bridge/action-schema.mjs +2 -2
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +5 -4
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
- package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
- package/src/runtime/connectors/connector-accounts-mcp.mjs +236 -103
- package/src/runtime/connectors/gmail-app-password.mjs +3 -3
- package/src/runtime/explore/explorer.mjs +93 -0
- package/src/runtime/explore/tool-defs.mjs +35 -0
- package/src/runtime/explore/tool.mjs +123 -0
- package/src/runtime/local-provider/server-process.mjs +2 -1
- package/src/runtime/media/adapters/gemini-video.mjs +4 -1
- package/src/runtime/media/adapters/xai-media.mjs +2 -1
- package/src/runtime/memory/index.mjs +4 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +10 -3
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
- package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
- package/src/runtime/office/design/design-art-direction.mjs +29 -27
- package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
- package/src/runtime/office/quality/assurance-structure-docx.mjs +4 -2
- package/src/runtime/office/quality/design-review.mjs +1 -5
- package/src/runtime/office/quality/document-brief.mjs +1 -5
- package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
- package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
- package/src/runtime/shared/agent-route-config.mjs +17 -2
- package/src/runtime/shared/atomic-file.mjs +103 -2
- package/src/runtime/shared/background-tasks.mjs +15 -6
- package/src/runtime/shared/bot-owned-work.mjs +56 -0
- package/src/runtime/shared/connector-accounts.mjs +5 -5
- package/src/runtime/shared/connector-catalog.d.mts +11 -4
- package/src/runtime/shared/connector-catalog.mjs +60 -52
- package/src/runtime/shared/custom-provider-keys.mjs +20 -0
- package/src/runtime/shared/defaults-separation.mjs +1 -4
- package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
- package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
- package/src/runtime/shared/file-has-data.mjs +26 -2
- package/src/runtime/shared/file-lock.mjs +13 -15
- package/src/runtime/shared/git-launch.d.mts +9 -0
- package/src/runtime/shared/git-launch.mjs +213 -0
- package/src/runtime/shared/git-runner-worker.mjs +2 -1
- package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
- package/src/runtime/shared/handoff-artifacts.mjs +18 -8
- package/src/runtime/shared/idle-auto-clear-gate.mjs +29 -7
- package/src/runtime/shared/llm/cost.mjs +11 -2
- package/src/runtime/shared/llm/http-agent.mjs +313 -29
- package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
- package/src/runtime/shared/llm/model-catalog.mjs +46 -6
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
- package/src/runtime/shared/llm/system-proxy.mjs +452 -0
- package/src/runtime/shared/loopback-listener.mjs +25 -2
- package/src/runtime/shared/model-route-chain.d.mts +7 -2
- package/src/runtime/shared/model-route-chain.mjs +22 -4
- package/src/runtime/shared/open-url.mjs +10 -0
- package/src/runtime/shared/provider-accounts.mjs +52 -2
- package/src/runtime/shared/session-activity-signal.mjs +14 -0
- package/src/runtime/shared/session-scratch.mjs +37 -0
- package/src/runtime/shared/staged-install-worker.mjs +5 -0
- package/src/runtime/shared/staged-update.mjs +47 -2
- package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
- package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
- package/src/runtime/shared/tool-result-summary.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +113 -36
- package/src/runtime/shared/tool-work-units.mjs +6 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
- package/src/runtime/shared/turn-worktree-snapshot.mjs +414 -54
- package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
- package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
- package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
- package/src/runtime/shared/worktrees/branch-management.mjs +9 -3
- package/src/runtime/shared/worktrees/contract.mjs +4 -1
- package/src/runtime/shared/worktrees/git.mjs +72 -0
- package/src/runtime/shared/worktrees/manager.mjs +285 -168
- package/src/runtime/shared/worktrees/test-support.mjs +6 -10
- package/src/runtime/tidy/install.mjs +95 -15
- package/src/runtime/tidy/languages.mjs +17 -15
- package/src/runtime/tidy/process.mjs +7 -4
- package/src/runtime/tidy/resolve.mjs +19 -16
- package/src/runtime/tidy/runners/biome.mjs +3 -3
- package/src/runtime/tidy/tool.mjs +1 -1
- package/src/runtime/tidy/worktree.mjs +10 -6
- package/src/runtime/visualize-bridge/client.mjs +6 -1
- package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
- package/src/runtime/web-search/index.mjs +1 -1
- package/src/session-runtime/agent-home-delivery.mjs +41 -0
- package/src/session-runtime/agent-task-sessions.mjs +458 -312
- package/src/session-runtime/agent-tool-routing.mjs +8 -41
- package/src/session-runtime/boot/tools.mjs +7 -1
- package/src/session-runtime/bot-status.mjs +107 -101
- package/src/session-runtime/bot-target.mjs +38 -0
- package/src/session-runtime/channel-config-api.mjs +6 -1
- package/src/session-runtime/connector-merge-migration.mjs +18 -15
- package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
- package/src/session-runtime/conversation-import/discovery.mjs +401 -36
- package/src/session-runtime/conversation-import/service.mjs +35 -8
- package/src/session-runtime/handoff-attachments.mjs +82 -31
- package/src/session-runtime/held-requests.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +12 -13
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +1 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -0
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +145 -112
- package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -1
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -1
- package/src/session-runtime/lifecycle/teardown.mjs +1 -1
- package/src/session-runtime/mcp-glue/server-catalog.mjs +16 -10
- package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
- package/src/session-runtime/mixy-heartbeat.mjs +1 -1
- package/src/session-runtime/model-route/set-route.mjs +11 -2
- package/src/session-runtime/provider-auth/login.mjs +2 -2
- package/src/session-runtime/provider-catalog-cache.mjs +82 -36
- package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
- package/src/session-runtime/provider-models.mjs +4 -2
- package/src/session-runtime/resource-mcp-api.mjs +98 -35
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +44 -31
- package/src/session-runtime/resource-mcp-secrets.mjs +28 -11
- package/src/session-runtime/resource-mcp-servers.mjs +5 -4
- package/src/session-runtime/resource-recall-api.mjs +6 -1
- package/src/session-runtime/runtime-feature-gates.mjs +5 -1
- package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
- package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
- package/src/session-runtime/services/agent-tool/render.mjs +71 -17
- package/src/session-runtime/services/agent-tool/send-flow.mjs +10 -2
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +6 -2
- package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
- package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
- package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
- package/src/session-runtime/services/daemon-candidate.mjs +4 -1
- package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
- package/src/session-runtime/services/plugin-admin.mjs +10 -6
- package/src/session-runtime/services/provider-admin.mjs +283 -11
- package/src/session-runtime/session-turn-api.mjs +2 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +4 -1
- package/src/session-runtime/settings-system-api.mjs +1 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
- package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
- package/src/session-runtime/setup-tool/executor.mjs +6 -2
- package/src/session-runtime/setup-tool/tool-defs.mjs +2 -1
- package/src/session-runtime/tool-policy/policy-stage.mjs +1 -0
- package/src/session-runtime/turn/agent-ops.mjs +23 -0
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +49 -11
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +25 -5
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
- package/src/session-runtime/workspace/activity-guards.mjs +176 -0
- package/src/session-runtime/workspace/session-view.mjs +149 -0
- package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
- package/src/session-runtime/workspace/transition-runner.mjs +188 -0
- package/src/session-runtime/workspace/transitions.mjs +108 -1041
- package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
- package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
- package/src/session-runtime/workspace/worktree-maintenance.mjs +80 -0
- package/src/session-runtime/workspace/worktree-setup.mjs +85 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +73 -56
- package/src/standalone/daemon-desktop-runtime.mjs +2 -0
- package/src/standalone/daemon-session-control.mjs +169 -138
- package/src/standalone/daemon.mjs +7 -0
- package/src/standalone/desktop-service-registry.mjs +9 -0
- package/src/standalone/local-session-runtime.mjs +5 -1
- package/src/standalone/session-client/daemon-unavailable.mjs +3 -0
- package/src/standalone/session-client.mjs +5 -1
- package/src/standalone/session-frame-stream.mjs +83 -11
- package/src/standalone/session-protocol.mjs +4 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
- package/src/standalone/session-service/agent-tree.mjs +45 -9
- package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
- package/src/standalone/session-service/session-calls/session-action.mjs +10 -3
- package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
- package/src/standalone/session-service/stored-reader.mjs +127 -40
- package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
- package/src/tui/App.jsx +154 -164
- package/src/tui/app/app-view/floating-panel.jsx +10 -4
- package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
- package/src/tui/app/clipboard.mjs +21 -10
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
- package/src/tui/app/model-picker/route-selection.mjs +5 -6
- package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
- package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
- package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
- package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
- package/src/tui/app/provider-setup/oauth-actions.mjs +58 -21
- package/src/tui/app/provider-setup/provider-items.mjs +8 -2
- package/src/tui/app/provider-setup-picker.mjs +29 -18
- package/src/tui/app/shell-layout/row-budgets.mjs +12 -10
- package/src/tui/app/slash-commands.mjs +1 -0
- package/src/tui/app/slash-dispatch/session-commands.mjs +46 -0
- package/src/tui/app/slash-dispatch.mjs +1 -1
- package/src/tui/app/use-btw-panel.mjs +29 -0
- package/src/tui/app/use-context-panel-refresh.mjs +31 -0
- package/src/tui/app/use-model-catalog-cache.mjs +13 -10
- package/src/tui/app/use-mouse-input.mjs +11 -0
- package/src/tui/app/use-onboarding-start.mjs +8 -3
- package/src/tui/app/use-panel-transition.mjs +10 -1
- package/src/tui/app/use-pasted-buffers.mjs +28 -20
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
- package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
- package/src/tui/app/use-prompt-queue-history.mjs +3 -2
- package/src/tui/app/use-selection-focus.mjs +11 -2
- package/src/tui/app/use-selection-geometry.mjs +18 -9
- package/src/tui/app/use-selection-paint.mjs +4 -4
- package/src/tui/app/use-selection-stitch.mjs +3 -3
- package/src/tui/app/use-slash-palette.mjs +62 -0
- package/src/tui/app/use-terminal-chrome.mjs +2 -2
- package/src/tui/app/use-transcript-activity.mjs +47 -32
- package/src/tui/app/use-transcript-follow.mjs +12 -4
- package/src/tui/app/use-transcript-scroll.mjs +46 -17
- package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
- package/src/tui/app/use-transcript-window/geometry.mjs +19 -5
- package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
- package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
- package/src/tui/app/use-transcript-window.mjs +21 -11
- package/src/tui/app/use-tui-ready.mjs +18 -0
- package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
- package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
- package/src/tui/components/Picker.jsx +27 -3
- package/src/tui/components/QuestionPanel.jsx +13 -4
- package/src/tui/components/SignInUrl.jsx +68 -0
- package/src/tui/components/TextEntryPanel.jsx +76 -46
- package/src/tui/components/sign-in-url-layout.mjs +24 -0
- package/src/tui/dist/index.mjs +1963 -1361
- package/src/tui/session/goal-turn-state.mjs +6 -2
- package/src/tui/session/session-api/controls.mjs +4 -0
- package/src/tui/session/session-api/extensions.mjs +8 -0
- package/src/tui/session/session-api/intake/abort.mjs +2 -1
- package/src/tui/session/session-api/intake.mjs +2 -0
- package/src/tui/session/session-api/integrations.mjs +2 -2
- package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +2 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +11 -0
- package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
- package/src/tui/session/transcript-spill.mjs +92 -4
- package/src/tui/session/transcript-store.mjs +2 -0
- package/src/ui/statusline-agents.mjs +1 -3
- package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
import { resolveProviderApiKey } from '../../../shared/provider-api-key.mjs';
|
|
2
|
+
import { getLlmDispatcher } from '../../../shared/llm/http-agent.mjs';
|
|
3
|
+
import { sanitizeToolPairs } from '../session/context-utils.mjs';
|
|
4
|
+
import { noteRequestServiceTier } from '../../../shared/llm/usage-context.mjs';
|
|
5
|
+
import { buildGeminiRequest } from './gemini-request-body.mjs';
|
|
6
|
+
import { geminiEndsWithFunctionResponse, runGeminiStreamAttempts } from './gemini-retry-policy.mjs';
|
|
7
|
+
import { consumeGeminiRestStreamResponse } from './gemini-stream.mjs';
|
|
8
|
+
import { geminiTextLeakGuardFor } from './gemini-sdk-request.mjs';
|
|
9
|
+
import { createGeminiReasoningRelay } from './gemini-reasoning-relay.mjs';
|
|
10
|
+
import {
|
|
11
|
+
geminiFailureUsage,
|
|
12
|
+
geminiIncompleteError,
|
|
13
|
+
geminiSendResult,
|
|
14
|
+
parseGeminiCandidate,
|
|
15
|
+
resolveGeminiUsage,
|
|
16
|
+
} from './gemini-response.mjs';
|
|
17
|
+
import { emitGeminiToolCalls } from './gemini-schema.mjs';
|
|
18
|
+
import { geminiRestError } from './gemini.mjs';
|
|
19
|
+
import {
|
|
20
|
+
ANTHROPIC_RETRY_BACKOFF_MS,
|
|
21
|
+
ANTHROPIC_RETRY_JITTER_RATIO,
|
|
22
|
+
anthropicMaxAttempts,
|
|
23
|
+
canFallbackNonStreaming,
|
|
24
|
+
emitProviderRetryStage,
|
|
25
|
+
withRetry,
|
|
26
|
+
} from './retry-classifier.mjs';
|
|
27
|
+
import { buildAnthropicApiRequest } from './anthropic-api-request.mjs';
|
|
28
|
+
import { applyAnthropicErrorContract } from './anthropic-error-contract.mjs';
|
|
29
|
+
import { createAnthropicMidState, assertAnthropicStreamNotEmpty } from './anthropic-midstream-recovery.mjs';
|
|
30
|
+
import { parseSSEStream } from './anthropic-sse.mjs';
|
|
31
|
+
import { buildAnthropicTurnResult } from './anthropic-turn-result.mjs';
|
|
32
|
+
import { streamCallbacks } from './lib/send-callbacks.mjs';
|
|
33
|
+
import { preparePdfTextForProvider } from './media-normalization.mjs';
|
|
34
|
+
import { VERTEX_API_KEY_MODE, VertexAccessTokenManager } from './vertex-ai-auth.mjs';
|
|
35
|
+
import { VertexMaasRoute, toVertexExclusiveUsage, vertexErrorBody } from './vertex-ai-maas.mjs';
|
|
36
|
+
import {
|
|
37
|
+
VERTEX_FLEX_TIER,
|
|
38
|
+
claudeNeedsInterleavedBeta,
|
|
39
|
+
VERTEX_MODELS,
|
|
40
|
+
VERTEX_MULTI_REGIONS,
|
|
41
|
+
VERTEX_PRIORITY_TIER,
|
|
42
|
+
assertVertexServing,
|
|
43
|
+
vertexEnvLocation,
|
|
44
|
+
vertexModelAccessError,
|
|
45
|
+
vertexPricingModel,
|
|
46
|
+
vertexRequestedTier,
|
|
47
|
+
vertexRoute,
|
|
48
|
+
vertexServingProblem,
|
|
49
|
+
vertexTierOption,
|
|
50
|
+
} from './vertex-ai-models.mjs';
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
VERTEX_FLEX_TIER,
|
|
54
|
+
VERTEX_MODELS,
|
|
55
|
+
VERTEX_PRIORITY_TIER,
|
|
56
|
+
VERTEX_REGIONAL_PRICING_SUFFIX,
|
|
57
|
+
VERTEX_SERVICE_TIER_PARAMETER,
|
|
58
|
+
} from './vertex-ai-models.mjs';
|
|
59
|
+
|
|
60
|
+
const VERTEX_ANTHROPIC_VERSION = 'vertex-2023-10-16';
|
|
61
|
+
|
|
62
|
+
// Vertex takes Anthropic betas in the body (`anthropic_beta`), never as a
|
|
63
|
+
// header, and only these (effort, fast mode, server fallback and the other
|
|
64
|
+
// first-party betas are not offered); tool search has its own name there.
|
|
65
|
+
const INTERLEAVED_THINKING_BETA = 'interleaved-thinking-2025-05-14';
|
|
66
|
+
const VERTEX_CLAUDE_BETAS = new Map([
|
|
67
|
+
[INTERLEAVED_THINKING_BETA, INTERLEAVED_THINKING_BETA],
|
|
68
|
+
['advanced-tool-use-2025-11-20', 'tool-search-tool-2025-10-19'],
|
|
69
|
+
['context-1m-2025-08-07', 'context-1m-2025-08-07'],
|
|
70
|
+
['context-management-2025-06-27', 'context-management-2025-06-27'],
|
|
71
|
+
['compact-2026-01-12', 'compact-2026-01-12'],
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
// Interleaved thinking needs the beta only for a manual thinking budget with
|
|
75
|
+
// tools on the models that document it (adaptive thinking interleaves on its own).
|
|
76
|
+
function needsInterleavedThinking(body, model) {
|
|
77
|
+
return (
|
|
78
|
+
body.thinking?.type === 'enabled' &&
|
|
79
|
+
Array.isArray(body.tools) &&
|
|
80
|
+
body.tools.length > 0 &&
|
|
81
|
+
claudeNeedsInterleavedBeta(model)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The Vertex names of the selected `betas` this request body needs. */
|
|
86
|
+
function vertexClaudeBetas(betas, body, model) {
|
|
87
|
+
const out = new Set();
|
|
88
|
+
for (const beta of betas || []) {
|
|
89
|
+
const mapped = VERTEX_CLAUDE_BETAS.get(beta);
|
|
90
|
+
if (!mapped || (mapped === INTERLEAVED_THINKING_BETA && !needsInterleavedThinking(body, model))) continue;
|
|
91
|
+
out.add(mapped);
|
|
92
|
+
}
|
|
93
|
+
return [...out];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Flex and Priority PayGo are selected per request with
|
|
97
|
+
// X-Vertex-AI-LLM-Shared-Request-Type (Provisioned Throughput is still used
|
|
98
|
+
// first when the project has it). The served tier is usageMetadata.trafficType:
|
|
99
|
+
// ON_DEMAND_FLEX, ON_DEMAND_PRIORITY, or ON_DEMAND for a Priority request
|
|
100
|
+
// downgraded to Standard PayGo (billed at Standard rates).
|
|
101
|
+
const SERVED_TIER = Object.freeze({
|
|
102
|
+
ON_DEMAND_FLEX: VERTEX_FLEX_TIER,
|
|
103
|
+
FLEX: VERTEX_FLEX_TIER,
|
|
104
|
+
BATCH: VERTEX_FLEX_TIER,
|
|
105
|
+
ON_DEMAND_PRIORITY: VERTEX_PRIORITY_TIER,
|
|
106
|
+
ON_DEMAND: 'default',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// A Flex request queues server-side and may sit silent for minutes before its
|
|
110
|
+
// first chunk (the docs allow request timeouts up to 30 minutes), so the shared
|
|
111
|
+
// 60s first-chunk window would kill and replay a healthy one. Kept under the
|
|
112
|
+
// 600s socket body timeout (MIXDOG_LLM_BODY_TIMEOUT_MS).
|
|
113
|
+
const VERTEX_FLEX_FIRST_CHUNK_TIMEOUT_MS = 570_000;
|
|
114
|
+
|
|
115
|
+
// Multi-region locations are served by representative endpoints, not by
|
|
116
|
+
// <location>-aiplatform.googleapis.com.
|
|
117
|
+
function vertexHost(location) {
|
|
118
|
+
if (location === 'global') return 'aiplatform.googleapis.com';
|
|
119
|
+
if (VERTEX_MULTI_REGIONS.has(location)) return `aiplatform.${location}.rep.googleapis.com`;
|
|
120
|
+
return `${location}-aiplatform.googleapis.com`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Express mode: an API key on the global endpoint, with no project or location in the path.
|
|
124
|
+
const EXPRESS_BASE = 'https://aiplatform.googleapis.com/v1';
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The request's location, and whether the user configured it (`pinned`):
|
|
128
|
+
* without one, the environment's region (for a Claude model, its own first),
|
|
129
|
+
* else global.
|
|
130
|
+
*/
|
|
131
|
+
function vertexLocation(config, claudeId = '') {
|
|
132
|
+
const configured = String(config?.location || '').trim();
|
|
133
|
+
const location = (configured || vertexEnvLocation(process.env, claudeId) || 'global').trim().toLowerCase();
|
|
134
|
+
// The location names the host the bearer token is sent to: only a region
|
|
135
|
+
// label (or global / a multi-region) may reach the host template.
|
|
136
|
+
if (!/^[a-z][a-z0-9-]{0,62}$/.test(location)) throw new Error('[vertex-ai] location is invalid');
|
|
137
|
+
return { location, pinned: Boolean(configured) };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const servesAt = (route, location, tier) => !vertexServingProblem(route, location, tier);
|
|
141
|
+
|
|
142
|
+
const isNotFound = (error) => [error?.status, error?.httpStatus, error?.response?.status].map(Number).includes(404);
|
|
143
|
+
|
|
144
|
+
function vertexProjectOverride(config) {
|
|
145
|
+
const projectId = String(config?.projectId || '').trim();
|
|
146
|
+
if (projectId && (!/^[a-zA-Z0-9._:-]{1,128}$/.test(projectId) || projectId.includes('/'))) {
|
|
147
|
+
throw new Error('[vertex-ai] project ID override is invalid');
|
|
148
|
+
}
|
|
149
|
+
return projectId;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function geminiCallbacks(opts) {
|
|
153
|
+
const reasoning = createGeminiReasoningRelay(opts);
|
|
154
|
+
return {
|
|
155
|
+
onStreamDelta: typeof opts.onStreamDelta === 'function' ? opts.onStreamDelta : null,
|
|
156
|
+
onToolCall: typeof opts.onToolCall === 'function' ? opts.onToolCall : null,
|
|
157
|
+
onTextDelta: typeof opts.onTextDelta === 'function' ? opts.onTextDelta : null,
|
|
158
|
+
onReasoningDelta: reasoning.onReasoningDelta,
|
|
159
|
+
retractReasoning: reasoning.retract,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Vertex rejects (400) functionCall.id / functionResponse.id, which the
|
|
164
|
+
// Gemini API request builder carries; calls pair by name and order here.
|
|
165
|
+
function withoutFunctionIds(contents) {
|
|
166
|
+
const strip = (key, part) => {
|
|
167
|
+
const { id: _id, ...rest } = part[key];
|
|
168
|
+
return { ...part, [key]: rest };
|
|
169
|
+
};
|
|
170
|
+
return (contents || []).map((content) =>
|
|
171
|
+
Array.isArray(content?.parts)
|
|
172
|
+
? {
|
|
173
|
+
...content,
|
|
174
|
+
parts: content.parts.map((part) => {
|
|
175
|
+
if (part?.functionCall && 'id' in part.functionCall) return strip('functionCall', part);
|
|
176
|
+
if (part?.functionResponse && 'id' in part.functionResponse) return strip('functionResponse', part);
|
|
177
|
+
return part;
|
|
178
|
+
}),
|
|
179
|
+
}
|
|
180
|
+
: content
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function geminiVertexBody(request) {
|
|
185
|
+
return {
|
|
186
|
+
contents: withoutFunctionIds(request.contents),
|
|
187
|
+
// Vertex accepts only a Content object here, never a bare string.
|
|
188
|
+
...(request.systemInstruction ? { systemInstruction: { parts: [{ text: request.systemInstruction }] } } : {}),
|
|
189
|
+
...(request.generationConfig ? { generationConfig: request.generationConfig } : {}),
|
|
190
|
+
...(request.geminiTools ? { tools: request.geminiTools } : {}),
|
|
191
|
+
...(request.toolConfig ? { toolConfig: request.toolConfig } : {}),
|
|
192
|
+
...(request.safetySettings ? { safetySettings: request.safetySettings } : {}),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export class VertexAIProvider {
|
|
197
|
+
static inputExcludesCache = true;
|
|
198
|
+
nativePdf = true;
|
|
199
|
+
name = 'vertex-ai';
|
|
200
|
+
|
|
201
|
+
constructor(config = {}) {
|
|
202
|
+
this.config = config;
|
|
203
|
+
const customFetch = typeof config.fetchFn === 'function' ? config.fetchFn : null;
|
|
204
|
+
this._fetch = customFetch ?? fetch;
|
|
205
|
+
this._auth = new VertexAccessTokenManager({
|
|
206
|
+
credentialResolver: () => resolveProviderApiKey('vertex-ai', this.config),
|
|
207
|
+
authMode: () => this.config.authMode,
|
|
208
|
+
fetchFn: this._fetch,
|
|
209
|
+
now: typeof config.now === 'function' ? config.now : () => Date.now(),
|
|
210
|
+
});
|
|
211
|
+
this._maas = new VertexMaasRoute({
|
|
212
|
+
name: this.name,
|
|
213
|
+
config,
|
|
214
|
+
auth: this._auth,
|
|
215
|
+
fetchFn: customFetch,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
_projectId() {
|
|
220
|
+
return vertexProjectOverride(this.config) || this._auth.projectId();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Only a Flex route has a budget; the shared window covers the rest. Vertex
|
|
224
|
+
// never marks transport progress at the response headers, so the transport
|
|
225
|
+
// deadline must already cover the headers wait plus the first-chunk wait.
|
|
226
|
+
firstResponseBudget(_model, { modelParameters } = {}) {
|
|
227
|
+
if (vertexRequestedTier({ modelParameters }) !== VERTEX_FLEX_TIER) return null;
|
|
228
|
+
const ms = 2 * VERTEX_FLEX_FIRST_CHUNK_TIMEOUT_MS;
|
|
229
|
+
return { transportMs: ms, semanticMs: ms };
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
_express() {
|
|
233
|
+
return this.config.authMode === VERTEX_API_KEY_MODE;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
_expressKey() {
|
|
237
|
+
const key = String(resolveProviderApiKey('vertex-ai', this.config) || '').trim();
|
|
238
|
+
if (!key) throw new Error('[vertex-ai] the Vertex AI API key is not configured');
|
|
239
|
+
return key;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** `target`: the send's { identity, project } and the location it goes to. */
|
|
243
|
+
_locationBase({ location, project }) {
|
|
244
|
+
if (this._express()) return EXPRESS_BASE;
|
|
245
|
+
return `https://${vertexHost(location)}/v1/projects/${encodeURIComponent(project)}/locations/${location}`;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
_url(publisher, model, method, target) {
|
|
249
|
+
// A version suffix (claude-…@default, @YYYYMMDD) stays a literal `@` in the path.
|
|
250
|
+
const id = encodeURIComponent(model).replace(/%40/g, '@');
|
|
251
|
+
return `${this._locationBase(target)}/publishers/${publisher}/models/${id}:${method}`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* `identity` is the account `url` was built for, read in the same tick as
|
|
256
|
+
* the URL before the first attempt; every attempt (retries included) must
|
|
257
|
+
* still run as that account, so a switch in between aborts the request.
|
|
258
|
+
* Express mode sends its API key instead (its URL names no project).
|
|
259
|
+
*/
|
|
260
|
+
async _authorizedFetch(url, init, identity) {
|
|
261
|
+
if (this._express()) {
|
|
262
|
+
const headers = new Headers(init?.headers || {});
|
|
263
|
+
headers.set('x-goog-api-key', this._expressKey());
|
|
264
|
+
return await this._fetch(url, { ...init, headers, dispatcher: getLlmDispatcher() });
|
|
265
|
+
}
|
|
266
|
+
let token = '';
|
|
267
|
+
const run = async () => {
|
|
268
|
+
token = await this._auth.getAccessToken({ identity });
|
|
269
|
+
this._auth.assertIdentity(identity);
|
|
270
|
+
const headers = new Headers(init?.headers || {});
|
|
271
|
+
headers.set('Authorization', `Bearer ${token}`);
|
|
272
|
+
return await this._fetch(url, { ...init, headers, dispatcher: getLlmDispatcher() });
|
|
273
|
+
};
|
|
274
|
+
let response = await run();
|
|
275
|
+
if (response.status === 401) {
|
|
276
|
+
this._auth.invalidate(token);
|
|
277
|
+
response = await run();
|
|
278
|
+
}
|
|
279
|
+
return response;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async send(messages, model, tools, sendOpts = {}) {
|
|
283
|
+
const route = vertexRoute(model);
|
|
284
|
+
const tier = vertexRequestedTier(sendOpts);
|
|
285
|
+
const express = this._express();
|
|
286
|
+
if (express && route.wire !== 'gemini') {
|
|
287
|
+
throw new Error(
|
|
288
|
+
`[vertex-ai] ${route.publisher}/${route.id} needs a service-account key or the gcloud login: ` +
|
|
289
|
+
'a Vertex AI express mode API key serves Gemini models only'
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
const requested = vertexLocation(this.config, route.wire === 'claude' ? route.id : '');
|
|
293
|
+
const { pinned } = requested;
|
|
294
|
+
if (express && pinned && requested.location !== 'global') {
|
|
295
|
+
throw new Error(
|
|
296
|
+
'[vertex-ai] a Vertex AI express mode API key serves only the global location; set the location to global'
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
// A configured location is never moved. A region from the environment
|
|
300
|
+
// gives way to global when it cannot serve the request (or for express mode).
|
|
301
|
+
let location = express ? 'global' : requested.location;
|
|
302
|
+
if (!pinned && location !== 'global' && !servesAt(route, location, tier) && servesAt(route, 'global', tier)) {
|
|
303
|
+
location = 'global';
|
|
304
|
+
}
|
|
305
|
+
assertVertexServing(route, location, tier);
|
|
306
|
+
await this._auth.ready();
|
|
307
|
+
let result;
|
|
308
|
+
try {
|
|
309
|
+
// One account for the whole send, the region fallback included: its
|
|
310
|
+
// identity and project are read in one tick, and every attempt (on any
|
|
311
|
+
// location) must still run as it.
|
|
312
|
+
const account = express
|
|
313
|
+
? { identity: null, project: '' }
|
|
314
|
+
: { identity: this._auth.identity(), project: this._projectId() };
|
|
315
|
+
const sendAt = (at) => {
|
|
316
|
+
const target = { ...account, location: at };
|
|
317
|
+
if (route.wire === 'gemini') return this._sendGemini(messages, route.id, tools, sendOpts, tier, target);
|
|
318
|
+
if (route.wire === 'claude') return this._sendClaude(messages, route.id, tools, sendOpts, target);
|
|
319
|
+
return this._sendMaas(messages, route, tools, sendOpts, target);
|
|
320
|
+
};
|
|
321
|
+
try {
|
|
322
|
+
result = await sendAt(location);
|
|
323
|
+
} catch (error) {
|
|
324
|
+
// A region from the environment that does not have the model (404) is retried once on global.
|
|
325
|
+
if (pinned || location === 'global' || !isNotFound(error) || !servesAt(route, 'global', tier)) throw error;
|
|
326
|
+
location = 'global';
|
|
327
|
+
result = await sendAt(location);
|
|
328
|
+
}
|
|
329
|
+
} catch (error) {
|
|
330
|
+
let project = '(unknown project)';
|
|
331
|
+
try {
|
|
332
|
+
project = this._projectId();
|
|
333
|
+
} catch {
|
|
334
|
+
// No resolvable project: keep the placeholder; the original error is rethrown below.
|
|
335
|
+
}
|
|
336
|
+
throw this._auth.accessError(vertexModelAccessError(error, route, { project, location }), { project });
|
|
337
|
+
}
|
|
338
|
+
const pricingModel = vertexPricingModel(route, location);
|
|
339
|
+
if (pricingModel && result && typeof result === 'object') result.pricingModel = pricingModel;
|
|
340
|
+
return result;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async _sendMaas(messages, route, tools, opts, target) {
|
|
344
|
+
// Built for the account it is sent with.
|
|
345
|
+
const baseURL = `${this._locationBase(target)}/endpoints/openapi`;
|
|
346
|
+
return await this._maas.send(messages, `${route.publisher}/${route.id}`, tools, opts, {
|
|
347
|
+
baseURL,
|
|
348
|
+
identity: target.identity,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async _sendGemini(messages, model, tools, opts, tier, target) {
|
|
353
|
+
const signal = opts.signal || null;
|
|
354
|
+
const headers = {
|
|
355
|
+
'Content-Type': 'application/json',
|
|
356
|
+
...(tier ? { 'X-Vertex-AI-LLM-Shared-Request-Type': tier } : {}),
|
|
357
|
+
};
|
|
358
|
+
const failureUsage = geminiFailureUsage(opts, null, model);
|
|
359
|
+
const vertexFailureUsage = {
|
|
360
|
+
...failureUsage,
|
|
361
|
+
normalize: (um) => toVertexExclusiveUsage(failureUsage.normalize(um)),
|
|
362
|
+
};
|
|
363
|
+
const callbacks = geminiCallbacks(opts);
|
|
364
|
+
const request = buildGeminiRequest(messages, model, tools, opts, null);
|
|
365
|
+
const body = geminiVertexBody(request);
|
|
366
|
+
// One account for every attempt and the unary fallback: the send's.
|
|
367
|
+
const { identity } = target;
|
|
368
|
+
const streamUrl = `${this._url('google', model, 'streamGenerateContent', target)}?alt=sse`;
|
|
369
|
+
const unaryUrl = this._url('google', model, 'generateContent', target);
|
|
370
|
+
const stream = { ...request, opts, signal, useModel: model, tools, callbacks, cachedContent: null };
|
|
371
|
+
try {
|
|
372
|
+
opts.onStageChange?.('requesting');
|
|
373
|
+
} catch {
|
|
374
|
+
// A throwing progress callback must not fail the request.
|
|
375
|
+
}
|
|
376
|
+
// Every attempt sends the same tier; the served trafficType settles the price.
|
|
377
|
+
noteRequestServiceTier(tier === VERTEX_PRIORITY_TIER ? tier : '');
|
|
378
|
+
|
|
379
|
+
let outcome;
|
|
380
|
+
try {
|
|
381
|
+
outcome = await runGeminiStreamAttempts({
|
|
382
|
+
signal,
|
|
383
|
+
sleepFn: this.config.sleepFn,
|
|
384
|
+
afterToolResult: geminiEndsWithFunctionResponse(request.contents),
|
|
385
|
+
failureUsage: vertexFailureUsage,
|
|
386
|
+
run: async ({ signal: attemptSignal, connected }) => {
|
|
387
|
+
callbacks.retractReasoning();
|
|
388
|
+
const res = await this._authorizedFetch(
|
|
389
|
+
streamUrl,
|
|
390
|
+
{ method: 'POST', headers, body: JSON.stringify(body), signal: attemptSignal },
|
|
391
|
+
identity
|
|
392
|
+
);
|
|
393
|
+
if (!res.ok) {
|
|
394
|
+
const text = vertexErrorBody(await res.text().catch(() => ''));
|
|
395
|
+
throw geminiRestError(res, text, 'Vertex AI Gemini streamGenerateContent');
|
|
396
|
+
}
|
|
397
|
+
connected();
|
|
398
|
+
try {
|
|
399
|
+
opts.onStageChange?.('streaming');
|
|
400
|
+
} catch {
|
|
401
|
+
// A throwing progress callback must not fail the request.
|
|
402
|
+
}
|
|
403
|
+
const textLeakGuard = geminiTextLeakGuardFor(stream);
|
|
404
|
+
const response = await consumeGeminiRestStreamResponse(res, {
|
|
405
|
+
signal: attemptSignal,
|
|
406
|
+
onStreamDelta: callbacks.onStreamDelta,
|
|
407
|
+
onTextDelta: callbacks.onTextDelta,
|
|
408
|
+
onReasoningDelta: callbacks.onReasoningDelta,
|
|
409
|
+
textLeakGuard,
|
|
410
|
+
label: 'Vertex AI Gemini streamGenerateContent',
|
|
411
|
+
failureUsage: vertexFailureUsage,
|
|
412
|
+
...(tier === VERTEX_FLEX_TIER
|
|
413
|
+
? { firstByteTimeoutMs: VERTEX_FLEX_FIRST_CHUNK_TIMEOUT_MS, idleAfterFirstChunk: true }
|
|
414
|
+
: {}),
|
|
415
|
+
});
|
|
416
|
+
return { response, textLeakGuard };
|
|
417
|
+
},
|
|
418
|
+
});
|
|
419
|
+
} catch (streamError) {
|
|
420
|
+
if (!canFallbackNonStreaming(streamError, { signal })) throw streamError;
|
|
421
|
+
callbacks.retractReasoning();
|
|
422
|
+
const res = await this._authorizedFetch(
|
|
423
|
+
unaryUrl,
|
|
424
|
+
{ method: 'POST', headers, body: JSON.stringify(body), signal },
|
|
425
|
+
identity
|
|
426
|
+
);
|
|
427
|
+
if (!res.ok) {
|
|
428
|
+
const text = vertexErrorBody(await res.text().catch(() => ''));
|
|
429
|
+
throw geminiRestError(res, text, 'Vertex AI Gemini generateContent');
|
|
430
|
+
}
|
|
431
|
+
outcome = { response: await res.json(), textLeakGuard: null };
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const parsed = parseGeminiCandidate(outcome.response, outcome.textLeakGuard);
|
|
435
|
+
const usage = resolveGeminiUsage(outcome.response, opts, null, model, this.name);
|
|
436
|
+
const incomplete = geminiIncompleteError(outcome.response, parsed, model, usage);
|
|
437
|
+
if (incomplete) throw incomplete;
|
|
438
|
+
outcome.textLeakGuard?.releaseDeferredToolCalls?.();
|
|
439
|
+
emitGeminiToolCalls(parsed.nativeToolCalls, callbacks.onToolCall);
|
|
440
|
+
const result = geminiSendResult(parsed, model, opts, toVertexExclusiveUsage(usage));
|
|
441
|
+
// The served tier decides the price: a Flex or Priority request can be
|
|
442
|
+
// served by Provisioned Throughput first, and a Priority one downgraded.
|
|
443
|
+
const served = SERVED_TIER[usage?.raw?.trafficType];
|
|
444
|
+
if (served) result.serviceTier = served;
|
|
445
|
+
return result;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
async _sendClaude(messages, model, tools, opts, target) {
|
|
449
|
+
messages = sanitizeToolPairs(messages);
|
|
450
|
+
messages = await preparePdfTextForProvider(messages, this);
|
|
451
|
+
const requestOpts = { ...opts, fast: false, serverFallback: false };
|
|
452
|
+
const { params, betas, knownToolNames } = await buildAnthropicApiRequest({
|
|
453
|
+
name: this.name,
|
|
454
|
+
config: { ...this.config, disableBetaHeaders: true },
|
|
455
|
+
messages,
|
|
456
|
+
useModel: model,
|
|
457
|
+
tools,
|
|
458
|
+
opts: requestOpts,
|
|
459
|
+
fastModeLatched: false,
|
|
460
|
+
capabilityModel: model,
|
|
461
|
+
});
|
|
462
|
+
const { model: _model, ...body } = params;
|
|
463
|
+
body.anthropic_version = VERTEX_ANTHROPIC_VERSION;
|
|
464
|
+
const vertexBetas = vertexClaudeBetas(betas, body, model);
|
|
465
|
+
if (vertexBetas.length) body.anthropic_beta = vertexBetas;
|
|
466
|
+
const callbacks = streamCallbacks(opts);
|
|
467
|
+
try {
|
|
468
|
+
callbacks.onStageChange?.('requesting');
|
|
469
|
+
} catch {
|
|
470
|
+
// A throwing progress callback must not fail the request.
|
|
471
|
+
}
|
|
472
|
+
// One account for every attempt: the send's.
|
|
473
|
+
const { identity } = target;
|
|
474
|
+
const url = this._url('anthropic', model, 'streamRawPredict', target);
|
|
475
|
+
const payload = JSON.stringify(body);
|
|
476
|
+
// The initial response retries like the first-party Anthropic route: 429
|
|
477
|
+
// and 529 (and 5xx) on its backoff, Retry-After honored.
|
|
478
|
+
const response = await withRetry(
|
|
479
|
+
async ({ signal: attemptSignal }) => {
|
|
480
|
+
const res = await this._authorizedFetch(
|
|
481
|
+
url,
|
|
482
|
+
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: payload, signal: attemptSignal },
|
|
483
|
+
identity
|
|
484
|
+
);
|
|
485
|
+
if (res.ok) return res;
|
|
486
|
+
const text = await res.text().catch(() => '');
|
|
487
|
+
let data = null;
|
|
488
|
+
try {
|
|
489
|
+
data = JSON.parse(vertexErrorBody(text));
|
|
490
|
+
} catch {
|
|
491
|
+
// A non-JSON body carries no google.rpc.Status; the status code stands alone.
|
|
492
|
+
}
|
|
493
|
+
const error = Object.assign(
|
|
494
|
+
new Error(`Vertex AI Claude streamRawPredict ${res.status}: ${text.slice(0, 300)}`),
|
|
495
|
+
{
|
|
496
|
+
...(data ? { data } : {}),
|
|
497
|
+
status: res.status,
|
|
498
|
+
httpStatus: res.status,
|
|
499
|
+
headers: res.headers,
|
|
500
|
+
response: { status: res.status, headers: res.headers },
|
|
501
|
+
initialResponseError: true,
|
|
502
|
+
}
|
|
503
|
+
);
|
|
504
|
+
throw applyAnthropicErrorContract(error, { status: res.status, headers: res.headers, bodyText: text });
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
signal: opts.signal || null,
|
|
508
|
+
maxAttempts: anthropicMaxAttempts(),
|
|
509
|
+
backoffMs: ANTHROPIC_RETRY_BACKOFF_MS,
|
|
510
|
+
retryJitterRatio: ANTHROPIC_RETRY_JITTER_RATIO,
|
|
511
|
+
retryJitterMode: 'positive',
|
|
512
|
+
recoveryOwner: 'vertex-ai-claude-initial-response',
|
|
513
|
+
retry529: opts.retry529,
|
|
514
|
+
sleepFn: this.config.sleepFn,
|
|
515
|
+
onRetry: ({ attempt, maxAttempts, lastErr, delayMs }) =>
|
|
516
|
+
emitProviderRetryStage(callbacks.onStageChange, { attempt: attempt + 1, maxAttempts, lastErr, delayMs }),
|
|
517
|
+
}
|
|
518
|
+
);
|
|
519
|
+
try {
|
|
520
|
+
callbacks.onStageChange?.('streaming');
|
|
521
|
+
} catch {
|
|
522
|
+
// A throwing progress callback must not fail the request.
|
|
523
|
+
}
|
|
524
|
+
const controller = new AbortController();
|
|
525
|
+
const externalSignal = opts.signal || null;
|
|
526
|
+
const abort = () => controller.abort(externalSignal?.reason);
|
|
527
|
+
if (externalSignal) {
|
|
528
|
+
if (externalSignal.aborted) abort();
|
|
529
|
+
else externalSignal.addEventListener('abort', abort, { once: true });
|
|
530
|
+
}
|
|
531
|
+
const midState = createAnthropicMidState(0);
|
|
532
|
+
try {
|
|
533
|
+
const parsed = await parseSSEStream(
|
|
534
|
+
response,
|
|
535
|
+
controller.signal,
|
|
536
|
+
(reason) => controller.abort(reason),
|
|
537
|
+
callbacks.onStreamDelta,
|
|
538
|
+
callbacks.onToolCall,
|
|
539
|
+
midState,
|
|
540
|
+
callbacks.onTextDelta,
|
|
541
|
+
knownToolNames,
|
|
542
|
+
{ onStreamItemStart: callbacks.onStreamItemStart }
|
|
543
|
+
);
|
|
544
|
+
assertAnthropicStreamNotEmpty(midState, parsed, 'Vertex AI Claude');
|
|
545
|
+
return buildAnthropicTurnResult(parsed, { provider: this.name, useModel: model, opts });
|
|
546
|
+
} finally {
|
|
547
|
+
externalSignal?.removeEventListener?.('abort', abort);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
async listModels() {
|
|
552
|
+
return VERTEX_MODELS.map((model) => {
|
|
553
|
+
const tierOption = vertexTierOption(model.id);
|
|
554
|
+
return { ...model, provider: this.name, ...(tierOption ? { modelParameterOptions: [tierOption] } : {}) };
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
async isAvailable() {
|
|
559
|
+
try {
|
|
560
|
+
if (this._express()) return Boolean(this._expressKey());
|
|
561
|
+
await this._auth.ready();
|
|
562
|
+
return Boolean(this._projectId());
|
|
563
|
+
} catch {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
@@ -8,9 +8,9 @@ export const ASK_USER_TOOL_DEFS = Object.freeze([
|
|
|
8
8
|
name: 'ask_user',
|
|
9
9
|
title: 'Ask User',
|
|
10
10
|
trigger:
|
|
11
|
-
'Ask the user 1–4 multiple-choice questions and wait; when a plan needs the user to pick between clear options, instead of listing them in chat.
|
|
11
|
+
'Ask the user 1–4 multiple-choice questions and wait; when a plan needs the user to pick between clear options, instead of listing them in chat.',
|
|
12
12
|
description:
|
|
13
|
-
'Ask the user multiple-choice questions and wait. Only for a decision only the user can make, with clear options; never for minor choices or approval of requested work, and open questions go in chat. Do not repeat the options in your message. A step only the user can do on a page or app (CAPTCHA, human check, sign-in, 2FA, a password)
|
|
13
|
+
'Ask the user multiple-choice questions and wait. Only for a decision only the user can make, with clear options; never for minor choices or approval of requested work, and open questions go in chat. Do not repeat the options in your message. A step only the user can do on a page or app (CAPTCHA, human check, sign-in, 2FA, a password) goes to handoff_user, never a request in plain chat. Load handoff_user directly if needed; browser/computer skills are not prerequisites.',
|
|
14
14
|
annotations: {
|
|
15
15
|
title: 'Ask User',
|
|
16
16
|
readOnlyHint: true,
|
|
@@ -52,10 +52,37 @@ export const ASK_USER_TOOL_DEFS = Object.freeze([
|
|
|
52
52
|
required: ['question', 'header', 'options'],
|
|
53
53
|
},
|
|
54
54
|
},
|
|
55
|
+
},
|
|
56
|
+
additionalProperties: false,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
// The deferred handoff tool: loaded with the browser-use and computer-use
|
|
62
|
+
// skills (dependencies.tools), the only surfaces a handoff targets.
|
|
63
|
+
export const HANDOFF_USER_TOOL_DEFS = Object.freeze([
|
|
64
|
+
{
|
|
65
|
+
name: 'handoff_user',
|
|
66
|
+
title: 'Hand Off To User',
|
|
67
|
+
trigger:
|
|
68
|
+
'Hand the user a page or app step (CAPTCHA, sign-in, 2FA, a secret); loads with the browser-use and computer-use skills.',
|
|
69
|
+
description:
|
|
70
|
+
'A step only the user can do on a page or app (CAPTCHA, human check, sign-in, 2FA, a password) is a handoff here, never a request in plain chat.',
|
|
71
|
+
annotations: {
|
|
72
|
+
title: 'Hand Off To User',
|
|
73
|
+
readOnlyHint: true,
|
|
74
|
+
destructiveHint: false,
|
|
75
|
+
idempotentHint: false,
|
|
76
|
+
openWorldHint: false,
|
|
77
|
+
agentHidden: true,
|
|
78
|
+
},
|
|
79
|
+
inputSchema: {
|
|
80
|
+
type: 'object',
|
|
81
|
+
properties: {
|
|
55
82
|
handoff: {
|
|
56
83
|
type: 'object',
|
|
57
84
|
description:
|
|
58
|
-
'
|
|
85
|
+
'secret = the user types a password, sign-in, new password or one-time code into that field of the page (you never see it; result entered/user_skipped/no_field/page_changed/blocked/expired); takeover = the user does a step and says done.',
|
|
59
86
|
properties: {
|
|
60
87
|
kind: { type: 'string', enum: ['secret', 'takeover'] },
|
|
61
88
|
surface: { type: 'string', enum: ['browser', 'computer'] },
|
|
@@ -83,26 +110,26 @@ export const ASK_USER_TOOL_DEFS = Object.freeze([
|
|
|
83
110
|
additionalProperties: false,
|
|
84
111
|
},
|
|
85
112
|
},
|
|
113
|
+
required: ['handoff'],
|
|
86
114
|
additionalProperties: false,
|
|
87
115
|
},
|
|
88
116
|
},
|
|
89
117
|
]);
|
|
90
118
|
|
|
91
|
-
/** The handoff of
|
|
92
|
-
export function
|
|
119
|
+
/** The handoff of a handoff_user call ({ kind, surface, target, field, instructions, … }). */
|
|
120
|
+
export function validateUserHandoff(args) {
|
|
93
121
|
const handoff = args?.handoff;
|
|
94
|
-
if (handoff == null)
|
|
95
|
-
if (
|
|
96
|
-
if (typeof handoff !== 'object' || Array.isArray(handoff)) throw new Error('ask_user handoff must be an object');
|
|
122
|
+
if (handoff == null) throw new Error('handoff_user needs a handoff');
|
|
123
|
+
if (typeof handoff !== 'object' || Array.isArray(handoff)) throw new Error('handoff_user handoff must be an object');
|
|
97
124
|
if (handoff.kind !== 'secret' && handoff.kind !== 'takeover') {
|
|
98
|
-
throw new Error('
|
|
125
|
+
throw new Error('handoff_user handoff kind is secret or takeover');
|
|
99
126
|
}
|
|
100
127
|
if (handoff.surface !== 'browser' && handoff.surface !== 'computer') {
|
|
101
|
-
throw new Error('
|
|
128
|
+
throw new Error('handoff_user handoff surface is browser or computer');
|
|
102
129
|
}
|
|
103
130
|
const text = (key, limit) => (typeof handoff[key] === 'string' ? handoff[key].trim().slice(0, limit) : '');
|
|
104
131
|
if (handoff.kind === 'takeover' && !text('instructions', 2000)) {
|
|
105
|
-
throw new Error('
|
|
132
|
+
throw new Error('handoff_user takeover needs instructions');
|
|
106
133
|
}
|
|
107
134
|
const login = handoffLogin(handoff);
|
|
108
135
|
let need = login ? 'sign_in' : 'action';
|
|
@@ -125,10 +152,10 @@ export function validateAskUserHandoff(args) {
|
|
|
125
152
|
function handoffLogin(handoff) {
|
|
126
153
|
if (handoff.purpose == null) return null;
|
|
127
154
|
if (handoff.purpose !== 'login' || handoff.kind !== 'takeover' || handoff.surface !== 'browser') {
|
|
128
|
-
throw new Error('
|
|
155
|
+
throw new Error('handoff_user purpose login is a browser takeover');
|
|
129
156
|
}
|
|
130
157
|
const page = loginPageUrl(handoff.url);
|
|
131
|
-
if (!page) throw new Error('
|
|
158
|
+
if (!page) throw new Error('handoff_user login needs an https url (http only on localhost)');
|
|
132
159
|
return page;
|
|
133
160
|
}
|
|
134
161
|
|
|
@@ -159,6 +186,7 @@ function handoffIdentity(handoff) {
|
|
|
159
186
|
|
|
160
187
|
/** Throws a clear error when the questions are malformed; returns the list. */
|
|
161
188
|
export function validateAskUserQuestions(args) {
|
|
189
|
+
if (args?.handoff != null) throw new Error('ask_user takes questions only; a page or app step goes to handoff_user');
|
|
162
190
|
const questions = args?.questions;
|
|
163
191
|
if (!Array.isArray(questions) || questions.length < 1 || questions.length > ASK_USER_MAX_QUESTIONS) {
|
|
164
192
|
throw new Error(`ask_user requires 1-${ASK_USER_MAX_QUESTIONS} questions`);
|