gsd-pi 2.63.0-dev.026d309 → 2.63.0-dev.786f0ff
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/README.md +46 -134
- package/dist/cli.js +48 -6
- package/dist/headless-query.js +11 -1
- package/dist/help-text.js +4 -1
- package/dist/onboarding.js +15 -8
- package/dist/resource-loader.js +18 -3
- package/dist/resources/extensions/cmux/index.js +21 -12
- package/dist/resources/extensions/gsd/auto/detect-stuck.js +27 -0
- package/dist/resources/extensions/gsd/auto/finalize-timeout.js +40 -0
- package/dist/resources/extensions/gsd/auto/loop.js +4 -0
- package/dist/resources/extensions/gsd/auto/phases.js +157 -22
- package/dist/resources/extensions/gsd/auto/session.js +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +9 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +32 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +124 -10
- package/dist/resources/extensions/gsd/auto-prompts.js +25 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +15 -7
- package/dist/resources/extensions/gsd/auto-start.js +10 -21
- package/dist/resources/extensions/gsd/auto-timers.js +2 -1
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +17 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +13 -7
- package/dist/resources/extensions/gsd/auto.js +19 -2
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +147 -75
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +13 -0
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +85 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +3 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +32 -1
- package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +54 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +30 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +9 -4
- package/dist/resources/extensions/gsd/constants.js +42 -0
- package/dist/resources/extensions/gsd/db-writer.js +72 -4
- package/dist/resources/extensions/gsd/forensics.js +20 -4
- package/dist/resources/extensions/gsd/gsd-db.js +64 -17
- package/dist/resources/extensions/gsd/guided-flow.js +19 -0
- package/dist/resources/extensions/gsd/metrics.js +27 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +5 -3
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences.js +7 -2
- package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -0
- package/dist/resources/extensions/gsd/prompts/doctor-heal.md +1 -0
- package/dist/resources/extensions/gsd/prompts/forensics.md +2 -0
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +2 -0
- package/dist/resources/extensions/gsd/prompts/system.md +4 -7
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
- package/dist/resources/extensions/gsd/roadmap-mutations.js +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +9 -5
- package/dist/resources/extensions/gsd/safety/content-validator.js +73 -0
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +34 -0
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +109 -0
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +83 -0
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +71 -0
- package/dist/resources/extensions/gsd/safety/git-checkpoint.js +91 -0
- package/dist/resources/extensions/gsd/safety/safety-harness.js +64 -0
- package/dist/resources/extensions/gsd/slice-parallel-conflict.js +67 -0
- package/dist/resources/extensions/gsd/slice-parallel-eligibility.js +51 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +378 -0
- package/dist/resources/extensions/gsd/state.js +74 -14
- package/dist/resources/extensions/gsd/status-guards.js +11 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +17 -12
- package/dist/resources/extensions/gsd/tools/complete-slice.js +40 -26
- package/dist/resources/extensions/gsd/tools/complete-task.js +12 -12
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +33 -25
- package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -8
- package/dist/resources/extensions/gsd/workflow-projections.js +21 -5
- package/dist/resources/extensions/gsd/worktree-manager.js +82 -29
- package/dist/resources/extensions/gsd/worktree-resolver.js +4 -3
- package/dist/resources/extensions/mcp-client/auth.js +101 -0
- package/dist/resources/extensions/mcp-client/index.js +10 -1
- package/dist/resources/extensions/ollama/index.js +28 -22
- package/dist/resources/extensions/ollama/model-capabilities.js +37 -34
- package/dist/resources/extensions/ollama/ndjson-stream.js +54 -0
- package/dist/resources/extensions/ollama/ollama-chat-provider.js +380 -0
- package/dist/resources/extensions/ollama/ollama-client.js +23 -32
- package/dist/resources/extensions/ollama/ollama-discovery.js +2 -7
- package/dist/resources/extensions/ollama/ollama-tool.js +62 -0
- package/dist/resources/extensions/ollama/thinking-parser.js +104 -0
- package/dist/update-cmd.js +4 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +20 -20
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +20 -20
- package/dist/web/standalone/.next/server/chunks/6897.js +12 -0
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts +8 -0
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +50 -0
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +221 -5
- package/packages/pi-agent-core/src/agent-loop.ts +53 -0
- package/packages/pi-ai/dist/types.d.ts +16 -1
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/src/types.ts +18 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +50 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +41 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +31 -4
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +28 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.js +46 -0
- package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +12 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +3 -3
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +23 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +80 -56
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +9 -0
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +53 -0
- package/packages/pi-coding-agent/src/core/auth-storage.ts +66 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +39 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +34 -4
- package/packages/pi-coding-agent/src/core/extensions/provider-registration.test.ts +81 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +14 -0
- package/packages/pi-coding-agent/src/core/model-resolver.ts +3 -3
- package/packages/pi-coding-agent/src/core/resource-loader.ts +89 -56
- package/packages/pi-coding-agent/src/core/sdk.ts +10 -0
- package/src/resources/extensions/cmux/index.ts +18 -12
- package/src/resources/extensions/gsd/auto/detect-stuck.ts +27 -0
- package/src/resources/extensions/gsd/auto/finalize-timeout.ts +46 -0
- package/src/resources/extensions/gsd/auto/loop.ts +5 -0
- package/src/resources/extensions/gsd/auto/phases.ts +194 -33
- package/src/resources/extensions/gsd/auto/session.ts +14 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +11 -3
- package/src/resources/extensions/gsd/auto-model-selection.ts +36 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +141 -12
- package/src/resources/extensions/gsd/auto-prompts.ts +21 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +9 -8
- package/src/resources/extensions/gsd/auto-start.ts +11 -20
- package/src/resources/extensions/gsd/auto-timers.ts +2 -1
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +14 -6
- package/src/resources/extensions/gsd/auto.ts +22 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +160 -88
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +15 -0
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +98 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +36 -1
- package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +57 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +31 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +10 -4
- package/src/resources/extensions/gsd/constants.ts +44 -0
- package/src/resources/extensions/gsd/db-writer.ts +78 -4
- package/src/resources/extensions/gsd/forensics.ts +21 -5
- package/src/resources/extensions/gsd/gsd-db.ts +64 -17
- package/src/resources/extensions/gsd/guided-flow.ts +22 -0
- package/src/resources/extensions/gsd/metrics.ts +28 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +5 -3
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences.ts +9 -2
- package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -0
- package/src/resources/extensions/gsd/prompts/doctor-heal.md +1 -0
- package/src/resources/extensions/gsd/prompts/forensics.md +2 -0
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +2 -0
- package/src/resources/extensions/gsd/prompts/system.md +4 -7
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
- package/src/resources/extensions/gsd/roadmap-mutations.ts +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +10 -5
- package/src/resources/extensions/gsd/safety/content-validator.ts +98 -0
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +49 -0
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +151 -0
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +120 -0
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +108 -0
- package/src/resources/extensions/gsd/safety/git-checkpoint.ts +106 -0
- package/src/resources/extensions/gsd/safety/safety-harness.ts +105 -0
- package/src/resources/extensions/gsd/slice-parallel-conflict.ts +86 -0
- package/src/resources/extensions/gsd/slice-parallel-eligibility.ts +73 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +477 -0
- package/src/resources/extensions/gsd/state.ts +67 -12
- package/src/resources/extensions/gsd/status-guards.ts +13 -0
- package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +288 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +34 -13
- package/src/resources/extensions/gsd/tests/cmux.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/complete-slice-string-coercion.test.ts +211 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +109 -0
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +13 -9
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +134 -0
- package/src/resources/extensions/gsd/tests/deferred-slice-dispatch.test.ts +203 -0
- package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +130 -0
- package/src/resources/extensions/gsd/tests/doctor-fix-flag.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/git-checkpoint.test.ts +94 -0
- package/src/resources/extensions/gsd/tests/insert-slice-no-wipe.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +27 -7
- package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +116 -1
- package/src/resources/extensions/gsd/tests/milestone-status-tool.test.ts +201 -0
- package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +82 -18
- package/src/resources/extensions/gsd/tests/preferences.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-conflict.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-eligibility.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +349 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +35 -2
- package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +148 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +34 -20
- package/src/resources/extensions/gsd/tools/complete-slice.ts +41 -26
- package/src/resources/extensions/gsd/tools/complete-task.ts +12 -12
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +55 -30
- package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -8
- package/src/resources/extensions/gsd/types.ts +44 -22
- package/src/resources/extensions/gsd/workflow-logger.ts +2 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +23 -5
- package/src/resources/extensions/gsd/worktree-manager.ts +76 -28
- package/src/resources/extensions/gsd/worktree-resolver.ts +4 -3
- package/src/resources/extensions/mcp-client/auth.ts +149 -0
- package/src/resources/extensions/mcp-client/index.ts +16 -1
- package/src/resources/extensions/ollama/index.ts +26 -25
- package/src/resources/extensions/ollama/model-capabilities.ts +41 -34
- package/src/resources/extensions/ollama/ndjson-stream.ts +63 -0
- package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +20 -0
- package/src/resources/extensions/ollama/ollama-chat-provider.ts +459 -0
- package/src/resources/extensions/ollama/ollama-client.ts +30 -30
- package/src/resources/extensions/ollama/ollama-discovery.ts +5 -8
- package/src/resources/extensions/ollama/ollama-tool.ts +69 -0
- package/src/resources/extensions/ollama/tests/ollama-chat-provider-stream.test.ts +82 -0
- package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +0 -27
- package/src/resources/extensions/ollama/thinking-parser.ts +116 -0
- package/src/resources/extensions/ollama/types.ts +23 -0
- package/dist/web/standalone/.next/server/chunks/2229.js +0 -12
- /package/dist/web/standalone/.next/static/{TTlAguZQ5vR9EOv6G8cel → SDB1T-4NqkMjYirjjqQhr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{TTlAguZQ5vR9EOv6G8cel → SDB1T-4NqkMjYirjjqQhr}/_ssgManifest.js +0 -0
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
// agent-loop
|
|
2
|
-
//
|
|
3
|
-
// to continue (re-invoke the LLM) instead of exiting.
|
|
4
|
-
// Regression test for https://github.com/gsd-build/gsd-2/issues/2869
|
|
1
|
+
// agent-loop tests
|
|
2
|
+
// Covers: pauseTurn handling (#2869), schema overload retry cap (#2783)
|
|
5
3
|
|
|
6
|
-
import { describe, it } from "node:test";
|
|
4
|
+
import { describe, it, mock } from "node:test";
|
|
7
5
|
import assert from "node:assert/strict";
|
|
8
6
|
import { readFileSync } from "node:fs";
|
|
9
7
|
import { join, dirname } from "node:path";
|
|
10
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { Type } from "@sinclair/typebox";
|
|
10
|
+
import { agentLoop, MAX_CONSECUTIVE_VALIDATION_FAILURES } from "./agent-loop.js";
|
|
11
|
+
import type { AgentContext, AgentLoopConfig, AgentTool, AgentEvent, AgentMessage } from "./types.js";
|
|
12
|
+
import { AssistantMessageEventStream, EventStream } from "@gsd/pi-ai";
|
|
13
|
+
import type { AssistantMessage, AssistantMessageEvent, Model } from "@gsd/pi-ai";
|
|
11
14
|
|
|
12
15
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
16
|
|
|
@@ -43,3 +46,216 @@ describe("agent-loop — pauseTurn handling (#2869)", () => {
|
|
|
43
46
|
);
|
|
44
47
|
});
|
|
45
48
|
});
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Regression tests for #2783: Stuck-loop on execute-task — tool-call schema
|
|
52
|
+
* overload causes unbounded retry + budget burn.
|
|
53
|
+
*
|
|
54
|
+
* When the LLM repeatedly emits tool calls with arguments that fail schema
|
|
55
|
+
* validation, the agent loop retries indefinitely. Each failed validation
|
|
56
|
+
* returns an error tool result, the LLM retries with the same broken args,
|
|
57
|
+
* and the cycle never breaks — burning budget with no progress.
|
|
58
|
+
*
|
|
59
|
+
* The fix caps consecutive validation failures per turn at
|
|
60
|
+
* MAX_CONSECUTIVE_VALIDATION_FAILURES (default 3). Once the cap is hit, the
|
|
61
|
+
* loop injects a synthetic stop so the agent terminates cleanly instead of
|
|
62
|
+
* spinning forever.
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
const TEST_MODEL: Model<"anthropic-messages"> = {
|
|
68
|
+
id: "claude-test",
|
|
69
|
+
name: "Test Model",
|
|
70
|
+
api: "anthropic-messages",
|
|
71
|
+
provider: "anthropic",
|
|
72
|
+
contextWindow: 200_000,
|
|
73
|
+
maxOutput: 4096,
|
|
74
|
+
supportsImages: false,
|
|
75
|
+
supportsPromptCache: false,
|
|
76
|
+
thinkingLevel: undefined,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
function makeToolWithSchema(): AgentTool<any> {
|
|
80
|
+
return {
|
|
81
|
+
name: "write_file",
|
|
82
|
+
label: "Write File",
|
|
83
|
+
description: "Write content to a file",
|
|
84
|
+
parameters: Type.Object({
|
|
85
|
+
path: Type.String(),
|
|
86
|
+
content: Type.String(),
|
|
87
|
+
}),
|
|
88
|
+
execute: async () => ({
|
|
89
|
+
content: [{ type: "text" as const, text: "done" }],
|
|
90
|
+
details: {},
|
|
91
|
+
}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Creates a mock streamFn that returns assistant messages from a queue.
|
|
97
|
+
* Each call pops the next message. The messages simulate the LLM repeatedly
|
|
98
|
+
* emitting the same tool call with broken arguments.
|
|
99
|
+
*/
|
|
100
|
+
function createMockStreamFn(responses: AssistantMessage[]) {
|
|
101
|
+
let callIndex = 0;
|
|
102
|
+
|
|
103
|
+
return function mockStreamFn(): AssistantMessageEventStream {
|
|
104
|
+
const message = responses[callIndex] ?? responses[responses.length - 1];
|
|
105
|
+
callIndex++;
|
|
106
|
+
|
|
107
|
+
const stream = new AssistantMessageEventStream();
|
|
108
|
+
// Simulate async delivery
|
|
109
|
+
queueMicrotask(() => {
|
|
110
|
+
stream.push({ type: "start", partial: message });
|
|
111
|
+
stream.push({ type: "done", message });
|
|
112
|
+
stream.end(message);
|
|
113
|
+
});
|
|
114
|
+
return stream;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function makeAssistantMessage(overrides: Partial<AssistantMessage> = {}): AssistantMessage {
|
|
119
|
+
return {
|
|
120
|
+
role: "assistant",
|
|
121
|
+
content: [],
|
|
122
|
+
api: "anthropic-messages",
|
|
123
|
+
provider: "anthropic",
|
|
124
|
+
model: "claude-test",
|
|
125
|
+
usage: { input: 100, output: 50, cacheRead: 0, cacheWrite: 0, totalTokens: 150, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
|
|
126
|
+
stopReason: "end_turn",
|
|
127
|
+
timestamp: Date.now(),
|
|
128
|
+
...overrides,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function makeToolCallMessage(toolCallArgs: Record<string, unknown>): AssistantMessage {
|
|
133
|
+
return makeAssistantMessage({
|
|
134
|
+
content: [
|
|
135
|
+
{
|
|
136
|
+
type: "toolCall",
|
|
137
|
+
id: `tc_${Date.now()}_${Math.random()}`,
|
|
138
|
+
name: "write_file",
|
|
139
|
+
arguments: toolCallArgs,
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
stopReason: "tool_use",
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function collectEvents(stream: EventStream<AgentEvent, AgentMessage[]>): Promise<AgentEvent[]> {
|
|
147
|
+
return new Promise(async (resolve) => {
|
|
148
|
+
const events: AgentEvent[] = [];
|
|
149
|
+
for await (const event of stream) {
|
|
150
|
+
events.push(event);
|
|
151
|
+
}
|
|
152
|
+
resolve(events);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ─── Tests ────────────────────────────────────────────────────────────────────
|
|
157
|
+
|
|
158
|
+
describe("agent-loop — schema overload retry cap (#2783)", () => {
|
|
159
|
+
|
|
160
|
+
it("terminates after MAX_CONSECUTIVE_VALIDATION_FAILURES consecutive schema failures", async () => {
|
|
161
|
+
const tool = makeToolWithSchema();
|
|
162
|
+
|
|
163
|
+
// LLM keeps sending tool calls with invalid args (missing required 'content' field)
|
|
164
|
+
const badToolCall = makeToolCallMessage({ path: "/tmp/test" }); // missing 'content'
|
|
165
|
+
const finalStop = makeAssistantMessage({ content: [{ type: "text", text: "I give up." }], stopReason: "end_turn" });
|
|
166
|
+
|
|
167
|
+
// Create enough bad responses to exceed the cap, plus a final stop
|
|
168
|
+
const responses: AssistantMessage[] = [];
|
|
169
|
+
for (let i = 0; i < MAX_CONSECUTIVE_VALIDATION_FAILURES + 5; i++) {
|
|
170
|
+
responses.push(badToolCall);
|
|
171
|
+
}
|
|
172
|
+
responses.push(finalStop);
|
|
173
|
+
|
|
174
|
+
const mockStream = createMockStreamFn(responses);
|
|
175
|
+
|
|
176
|
+
const context: AgentContext = {
|
|
177
|
+
systemPrompt: "You are a test agent.",
|
|
178
|
+
messages: [{ role: "user", content: [{ type: "text", text: "Write a file" }], timestamp: Date.now() }],
|
|
179
|
+
tools: [tool],
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const config: AgentLoopConfig = {
|
|
183
|
+
model: TEST_MODEL,
|
|
184
|
+
convertToLlm: (msgs) => msgs.filter((m): m is any => m.role !== "custom"),
|
|
185
|
+
toolExecution: "sequential",
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const stream = agentLoop(
|
|
189
|
+
[{ role: "user", content: [{ type: "text", text: "Write a file" }], timestamp: Date.now() }],
|
|
190
|
+
context,
|
|
191
|
+
config,
|
|
192
|
+
undefined,
|
|
193
|
+
mockStream as any,
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const events = await collectEvents(stream);
|
|
197
|
+
|
|
198
|
+
// Must have terminated (agent_end event present)
|
|
199
|
+
const agentEnd = events.find((e) => e.type === "agent_end");
|
|
200
|
+
assert.ok(agentEnd, "agent loop must emit agent_end after hitting retry cap");
|
|
201
|
+
|
|
202
|
+
// Count how many turns had validation errors (tool_execution_end with isError: true)
|
|
203
|
+
const toolErrors = events.filter(
|
|
204
|
+
(e) => e.type === "tool_execution_end" && e.isError === true,
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
// Must not exceed the cap
|
|
208
|
+
assert.ok(
|
|
209
|
+
toolErrors.length <= MAX_CONSECUTIVE_VALIDATION_FAILURES,
|
|
210
|
+
`Expected at most ${MAX_CONSECUTIVE_VALIDATION_FAILURES} validation error tool results, got ${toolErrors.length}`,
|
|
211
|
+
);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("resets the failure counter when a tool call succeeds", async () => {
|
|
215
|
+
const tool = makeToolWithSchema();
|
|
216
|
+
|
|
217
|
+
// Pattern: 2 failures, 1 success, 2 failures, 1 success, then stop
|
|
218
|
+
const badCall = makeToolCallMessage({ path: "/tmp/test" }); // missing 'content'
|
|
219
|
+
const goodCall = makeToolCallMessage({ path: "/tmp/test", content: "hello" });
|
|
220
|
+
const finalStop = makeAssistantMessage({ content: [{ type: "text", text: "Done." }], stopReason: "end_turn" });
|
|
221
|
+
|
|
222
|
+
const responses = [badCall, badCall, goodCall, badCall, badCall, goodCall, finalStop];
|
|
223
|
+
const mockStream = createMockStreamFn(responses);
|
|
224
|
+
|
|
225
|
+
const context: AgentContext = {
|
|
226
|
+
systemPrompt: "You are a test agent.",
|
|
227
|
+
messages: [{ role: "user", content: [{ type: "text", text: "Write a file" }], timestamp: Date.now() }],
|
|
228
|
+
tools: [tool],
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const config: AgentLoopConfig = {
|
|
232
|
+
model: TEST_MODEL,
|
|
233
|
+
convertToLlm: (msgs) => msgs.filter((m): m is any => m.role !== "custom"),
|
|
234
|
+
toolExecution: "sequential",
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const stream = agentLoop(
|
|
238
|
+
[{ role: "user", content: [{ type: "text", text: "Write a file" }], timestamp: Date.now() }],
|
|
239
|
+
context,
|
|
240
|
+
config,
|
|
241
|
+
undefined,
|
|
242
|
+
mockStream as any,
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const events = await collectEvents(stream);
|
|
246
|
+
|
|
247
|
+
// Must complete successfully since failures never reached cap consecutively
|
|
248
|
+
const agentEnd = events.find((e) => e.type === "agent_end");
|
|
249
|
+
assert.ok(agentEnd, "agent loop must complete normally when failures are interspersed with successes");
|
|
250
|
+
|
|
251
|
+
// Should have processed all 6 tool-bearing turns
|
|
252
|
+
const toolExecEnds = events.filter((e) => e.type === "tool_execution_end");
|
|
253
|
+
assert.ok(toolExecEnds.length >= 4, `Expected at least 4 tool executions (2 bad + 1 good + 2 bad + 1 good), got ${toolExecEnds.length}`);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it("exports MAX_CONSECUTIVE_VALIDATION_FAILURES as a configurable constant", () => {
|
|
257
|
+
assert.equal(typeof MAX_CONSECUTIVE_VALIDATION_FAILURES, "number");
|
|
258
|
+
assert.ok(MAX_CONSECUTIVE_VALIDATION_FAILURES >= 2, "Cap must be at least 2 to allow one retry");
|
|
259
|
+
assert.ok(MAX_CONSECUTIVE_VALIDATION_FAILURES <= 10, "Cap must not be unreasonably high");
|
|
260
|
+
});
|
|
261
|
+
});
|
|
@@ -22,6 +22,15 @@ import type {
|
|
|
22
22
|
StreamFn,
|
|
23
23
|
} from "./types.js";
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Maximum number of consecutive turns where ALL tool calls in the turn fail
|
|
27
|
+
* schema validation before the loop terminates. This prevents unbounded retry
|
|
28
|
+
* loops when the LLM repeatedly emits tool calls with arguments that cannot
|
|
29
|
+
* pass validation (e.g., schema overload, truncated JSON, missing required
|
|
30
|
+
* fields). See: https://github.com/gsd-build/gsd-2/issues/2783
|
|
31
|
+
*/
|
|
32
|
+
export const MAX_CONSECUTIVE_VALIDATION_FAILURES = 3;
|
|
33
|
+
|
|
25
34
|
export const ZERO_USAGE = {
|
|
26
35
|
input: 0,
|
|
27
36
|
output: 0,
|
|
@@ -175,6 +184,12 @@ async function runLoop(
|
|
|
175
184
|
// Check for steering messages at start (user may have typed while waiting)
|
|
176
185
|
let pendingMessages: AgentMessage[] = (await config.getSteeringMessages?.()) || [];
|
|
177
186
|
|
|
187
|
+
// Track consecutive turns where ALL tool calls fail validation.
|
|
188
|
+
// When the LLM repeatedly emits tool calls with schema-overloaded or malformed
|
|
189
|
+
// arguments, each turn produces only error tool results. Without a cap, this
|
|
190
|
+
// creates an unbounded retry loop that burns budget. (#2783)
|
|
191
|
+
let consecutiveAllToolErrorTurns = 0;
|
|
192
|
+
|
|
178
193
|
// Outer loop: continues when queued follow-up messages arrive after agent would stop
|
|
179
194
|
while (true) {
|
|
180
195
|
let hasMoreToolCalls = true;
|
|
@@ -277,6 +292,44 @@ async function runLoop(
|
|
|
277
292
|
currentContext.messages.push(result);
|
|
278
293
|
newMessages.push(result);
|
|
279
294
|
}
|
|
295
|
+
|
|
296
|
+
// Schema overload detection (#2783): if EVERY tool result in this turn
|
|
297
|
+
// is an error (validation failure, missing tool, etc.), increment the
|
|
298
|
+
// consecutive failure counter. If any tool succeeded, reset to zero.
|
|
299
|
+
const allToolsFailed = toolResults.length > 0 && toolResults.every((r) => r.isError);
|
|
300
|
+
if (allToolsFailed) {
|
|
301
|
+
consecutiveAllToolErrorTurns++;
|
|
302
|
+
} else {
|
|
303
|
+
consecutiveAllToolErrorTurns = 0;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (consecutiveAllToolErrorTurns >= MAX_CONSECUTIVE_VALIDATION_FAILURES) {
|
|
307
|
+
// Force-stop: the LLM is stuck retrying broken tool calls.
|
|
308
|
+
// Emit the turn_end and terminate the agent loop cleanly.
|
|
309
|
+
stream.push({ type: "turn_end", message, toolResults });
|
|
310
|
+
const stopMessage: AssistantMessage = {
|
|
311
|
+
role: "assistant",
|
|
312
|
+
content: [
|
|
313
|
+
{
|
|
314
|
+
type: "text",
|
|
315
|
+
text: `Agent stopped: ${consecutiveAllToolErrorTurns} consecutive turns with all tool calls failing. This usually means the model is repeatedly sending arguments that do not match the tool schema.`,
|
|
316
|
+
},
|
|
317
|
+
],
|
|
318
|
+
api: config.model.api,
|
|
319
|
+
provider: config.model.provider,
|
|
320
|
+
model: config.model.id,
|
|
321
|
+
usage: ZERO_USAGE,
|
|
322
|
+
stopReason: "error",
|
|
323
|
+
errorMessage: "Schema overload: consecutive tool validation failures exceeded cap",
|
|
324
|
+
timestamp: Date.now(),
|
|
325
|
+
};
|
|
326
|
+
emitMessagePair(stream, stopMessage);
|
|
327
|
+
newMessages.push(stopMessage);
|
|
328
|
+
stream.push({ type: "turn_end", message: stopMessage, toolResults: [] });
|
|
329
|
+
stream.push({ type: "agent_end", messages: newMessages });
|
|
330
|
+
stream.end(newMessages);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
280
333
|
}
|
|
281
334
|
|
|
282
335
|
stream.push({ type: "turn_end", message, toolResults });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AssistantMessageEventStream } from "./utils/event-stream.js";
|
|
2
2
|
export type { AssistantMessageEventStream } from "./utils/event-stream.js";
|
|
3
|
-
export type KnownApi = "openai-completions" | "mistral-conversations" | "openai-responses" | "azure-openai-responses" | "openai-codex-responses" | "anthropic-messages" | "anthropic-vertex" | "bedrock-converse-stream" | "google-generative-ai" | "google-gemini-cli" | "google-vertex";
|
|
3
|
+
export type KnownApi = "openai-completions" | "mistral-conversations" | "openai-responses" | "azure-openai-responses" | "openai-codex-responses" | "anthropic-messages" | "anthropic-vertex" | "bedrock-converse-stream" | "google-generative-ai" | "google-gemini-cli" | "google-vertex" | "ollama-chat";
|
|
4
4
|
export type Api = KnownApi | (string & {});
|
|
5
5
|
export type KnownProvider = "amazon-bedrock" | "anthropic" | "anthropic-vertex" | "google" | "google-gemini-cli" | "google-antigravity" | "google-vertex" | "openai" | "azure-openai-responses" | "openai-codex" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "vercel-ai-gateway" | "zai" | "mistral" | "minimax" | "minimax-cn" | "huggingface" | "opencode" | "opencode-go" | "kimi-coding" | "alibaba-coding-plan" | "ollama" | "ollama-cloud";
|
|
6
6
|
export type Provider = KnownProvider | string;
|
|
@@ -144,8 +144,21 @@ export interface AssistantMessage {
|
|
|
144
144
|
errorMessage?: string;
|
|
145
145
|
/** Server-requested retry delay in milliseconds (from Retry-After or rate limit headers). */
|
|
146
146
|
retryAfterMs?: number;
|
|
147
|
+
/** Provider inference performance metrics (e.g. tokens/sec from local models). */
|
|
148
|
+
inferenceMetrics?: InferenceMetrics;
|
|
147
149
|
timestamp: number;
|
|
148
150
|
}
|
|
151
|
+
/** Inference performance metrics reported by providers that support it (e.g. Ollama). */
|
|
152
|
+
export interface InferenceMetrics {
|
|
153
|
+
/** Tokens generated per second during eval phase. */
|
|
154
|
+
tokensPerSecond: number;
|
|
155
|
+
/** Wall-clock duration of the full request in milliseconds. */
|
|
156
|
+
totalDurationMs: number;
|
|
157
|
+
/** Duration of the eval (generation) phase in milliseconds. */
|
|
158
|
+
evalDurationMs: number;
|
|
159
|
+
/** Duration of the prompt eval phase in milliseconds. */
|
|
160
|
+
promptEvalDurationMs: number;
|
|
161
|
+
}
|
|
149
162
|
export interface ToolResultMessage<TDetails = any> {
|
|
150
163
|
role: "toolResult";
|
|
151
164
|
toolCallId: string;
|
|
@@ -336,5 +349,7 @@ export interface Model<TApi extends Api> {
|
|
|
336
349
|
* Read these fields instead of pattern-matching on model IDs or provider names.
|
|
337
350
|
*/
|
|
338
351
|
capabilities?: ModelCapabilities;
|
|
352
|
+
/** Opaque provider-specific options. Cast to the appropriate type in the provider's stream handler. */
|
|
353
|
+
providerOptions?: Record<string, unknown>;
|
|
339
354
|
}
|
|
340
355
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAE3E,YAAY,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAE3E,MAAM,MAAM,QAAQ,GACjB,oBAAoB,GACpB,uBAAuB,GACvB,kBAAkB,GAClB,wBAAwB,GACxB,wBAAwB,GACxB,oBAAoB,GACpB,kBAAkB,GAClB,yBAAyB,GACzB,sBAAsB,GACtB,mBAAmB,GACnB,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type KnownApi =\n\t| \"openai-completions\"\n\t| \"mistral-conversations\"\n\t| \"openai-responses\"\n\t| \"azure-openai-responses\"\n\t| \"openai-codex-responses\"\n\t| \"anthropic-messages\"\n\t| \"anthropic-vertex\"\n\t| \"bedrock-converse-stream\"\n\t| \"google-generative-ai\"\n\t| \"google-gemini-cli\"\n\t| \"google-vertex\";\n\nexport type Api = KnownApi | (string & {});\n\nexport type KnownProvider =\n\t| \"amazon-bedrock\"\n\t| \"anthropic\"\n\t| \"anthropic-vertex\"\n\t| \"google\"\n\t| \"google-gemini-cli\"\n\t| \"google-antigravity\"\n\t| \"google-vertex\"\n\t| \"openai\"\n\t| \"azure-openai-responses\"\n\t| \"openai-codex\"\n\t| \"github-copilot\"\n\t| \"xai\"\n\t| \"groq\"\n\t| \"cerebras\"\n\t| \"openrouter\"\n\t| \"vercel-ai-gateway\"\n\t| \"zai\"\n\t| \"mistral\"\n\t| \"minimax\"\n\t| \"minimax-cn\"\n\t| \"huggingface\"\n\t| \"opencode\"\n\t| \"opencode-go\"\n\t| \"kimi-coding\"\n\t| \"alibaba-coding-plan\"\n\t| \"ollama\"\n\t| \"ollama-cloud\";\nexport type Provider = KnownProvider | string;\n\nexport type ThinkingLevel = \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\n/** Token budgets for each thinking level (token-based providers only) */\nexport interface ThinkingBudgets {\n\tminimal?: number;\n\tlow?: number;\n\tmedium?: number;\n\thigh?: number;\n}\n\n// Base options all providers share\nexport type CacheRetention = \"none\" | \"short\" | \"long\";\n\nexport type Transport = \"sse\" | \"websocket\" | \"auto\";\n\nexport interface StreamOptions {\n\ttemperature?: number;\n\tmaxTokens?: number;\n\tsignal?: AbortSignal;\n\tapiKey?: string;\n\t/**\n\t * Preferred transport for providers that support multiple transports.\n\t * Providers that do not support this option ignore it.\n\t */\n\ttransport?: Transport;\n\t/**\n\t * Prompt cache retention preference. Providers map this to their supported values.\n\t * Default: \"short\".\n\t */\n\tcacheRetention?: CacheRetention;\n\t/**\n\t * Optional session identifier for providers that support session-based caching.\n\t * Providers can use this to enable prompt caching, request routing, or other\n\t * session-aware features. Ignored by providers that don't support it.\n\t */\n\tsessionId?: string;\n\t/**\n\t * Optional callback for inspecting or replacing provider payloads before sending.\n\t * Return undefined to keep the payload unchanged.\n\t */\n\tonPayload?: (payload: unknown, model: Model<Api>) => unknown | undefined | Promise<unknown | undefined>;\n\t/**\n\t * Optional custom HTTP headers to include in API requests.\n\t * Merged with provider defaults; can override default headers.\n\t * Not supported by all providers (e.g., AWS Bedrock uses SDK auth).\n\t */\n\theaders?: Record<string, string>;\n\t/**\n\t * Maximum delay in milliseconds to wait for a retry when the server requests a long wait.\n\t * If the server's requested delay exceeds this value, the request fails immediately\n\t * with an error containing the requested delay, allowing higher-level retry logic\n\t * to handle it with user visibility.\n\t * Default: 60000 (60 seconds). Set to 0 to disable the cap.\n\t */\n\tmaxRetryDelayMs?: number;\n\t/**\n\t * Optional metadata to include in API requests.\n\t * Providers extract the fields they understand and ignore the rest.\n\t * For example, Anthropic uses `user_id` for abuse tracking and rate limiting.\n\t */\n\tmetadata?: Record<string, unknown>;\n}\n\nexport type ProviderStreamOptions = StreamOptions & Record<string, unknown>;\n\n// Unified options with reasoning passed to streamSimple() and completeSimple()\nexport interface SimpleStreamOptions extends StreamOptions {\n\treasoning?: ThinkingLevel;\n\t/** Custom token budgets for thinking levels (token-based providers only) */\n\tthinkingBudgets?: ThinkingBudgets;\n}\n\n// Generic StreamFunction with typed options\nexport type StreamFunction<TApi extends Api = Api, TOptions extends StreamOptions = StreamOptions> = (\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: TOptions,\n) => AssistantMessageEventStream;\n\nexport interface TextSignatureV1 {\n\tv: 1;\n\tid: string;\n\tphase?: \"commentary\" | \"final_answer\";\n}\n\nexport interface TextContent {\n\ttype: \"text\";\n\ttext: string;\n\ttextSignature?: string; // e.g., for OpenAI responses, message metadata (legacy id string or TextSignatureV1 JSON)\n}\n\nexport interface ThinkingContent {\n\ttype: \"thinking\";\n\tthinking: string;\n\tthinkingSignature?: string; // e.g., for OpenAI responses, the reasoning item ID\n\t/** When true, the thinking content was redacted by safety filters. The opaque\n\t * encrypted payload is stored in `thinkingSignature` so it can be passed back\n\t * to the API for multi-turn continuity. */\n\tredacted?: boolean;\n}\n\nexport interface ImageContent {\n\ttype: \"image\";\n\tdata: string; // base64 encoded image data\n\tmimeType: string; // e.g., \"image/jpeg\", \"image/png\"\n}\n\nexport interface ToolCall {\n\ttype: \"toolCall\";\n\tid: string;\n\tname: string;\n\targuments: Record<string, any>;\n\tthoughtSignature?: string; // Google-specific: opaque signature for reusing thought context\n}\n\n/** Server-side tool use (e.g., Anthropic native web search). Executed by the API, not the client. */\nexport interface ServerToolUseContent {\n\ttype: \"serverToolUse\";\n\tid: string;\n\tname: string; // e.g., \"web_search\"\n\tinput: unknown;\n}\n\n/** Result of a server-side tool execution, paired with a ServerToolUseContent by toolUseId. */\nexport interface WebSearchResultContent {\n\ttype: \"webSearchResult\";\n\ttoolUseId: string;\n\t/** Search results or error from the server. Opaque — stored for API replay. */\n\tcontent: unknown;\n}\n\nexport interface Usage {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\ttotalTokens: number;\n\tcost: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheRead: number;\n\t\tcacheWrite: number;\n\t\ttotal: number;\n\t};\n}\n\nexport type StopReason = \"stop\" | \"length\" | \"toolUse\" | \"pauseTurn\" | \"error\" | \"aborted\";\n\nexport interface UserMessage {\n\trole: \"user\";\n\tcontent: string | (TextContent | ImageContent)[];\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface AssistantMessage {\n\trole: \"assistant\";\n\tcontent: (TextContent | ThinkingContent | ToolCall | ServerToolUseContent | WebSearchResultContent)[];\n\tapi: Api;\n\tprovider: Provider;\n\tmodel: string;\n\tusage: Usage;\n\tstopReason: StopReason;\n\terrorMessage?: string;\n\t/** Server-requested retry delay in milliseconds (from Retry-After or rate limit headers). */\n\tretryAfterMs?: number;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface ToolResultMessage<TDetails = any> {\n\trole: \"toolResult\";\n\ttoolCallId: string;\n\ttoolName: string;\n\tcontent: (TextContent | ImageContent)[]; // Supports text and images\n\tdetails?: TDetails;\n\tisError: boolean;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport type Message = UserMessage | AssistantMessage | ToolResultMessage;\n\nimport type { TSchema } from \"@sinclair/typebox\";\n\nexport interface Tool<TParameters extends TSchema = TSchema> {\n\tname: string;\n\tdescription: string;\n\tparameters: TParameters;\n}\n\nexport interface Context {\n\tsystemPrompt?: string;\n\tmessages: Message[];\n\ttools?: Tool[];\n}\n\nexport type AssistantMessageEvent =\n\t| { type: \"start\"; partial: AssistantMessage }\n\t| { type: \"text_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"text_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"thinking_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"thinking_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"toolcall_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"toolcall_end\"; contentIndex: number; toolCall: ToolCall; partial: AssistantMessage; malformedArguments?: boolean }\n\t| { type: \"server_tool_use\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"web_search_result\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"done\"; reason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\" | \"pauseTurn\">; message: AssistantMessage }\n\t| { type: \"error\"; reason: Extract<StopReason, \"aborted\" | \"error\">; error: AssistantMessage };\n\n/**\n * Compatibility settings for OpenAI-compatible completions APIs.\n * Use this to override URL-based auto-detection for custom providers.\n */\nexport interface OpenAICompletionsCompat {\n\t/** Whether the provider supports the `store` field. Default: auto-detected from URL. */\n\tsupportsStore?: boolean;\n\t/** Whether the provider supports the `developer` role (vs `system`). Default: auto-detected from URL. */\n\tsupportsDeveloperRole?: boolean;\n\t/** Whether the provider supports `reasoning_effort`. Default: auto-detected from URL. */\n\tsupportsReasoningEffort?: boolean;\n\t/** Optional mapping from pi-ai reasoning levels to provider/model-specific `reasoning_effort` values. */\n\treasoningEffortMap?: Partial<Record<ThinkingLevel, string>>;\n\t/** Whether the provider supports `stream_options: { include_usage: true }` for token usage in streaming responses. Default: true. */\n\tsupportsUsageInStreaming?: boolean;\n\t/** Which field to use for max tokens. Default: auto-detected from URL. */\n\tmaxTokensField?: \"max_completion_tokens\" | \"max_tokens\";\n\t/** Whether tool results require the `name` field. Default: auto-detected from URL. */\n\trequiresToolResultName?: boolean;\n\t/** Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. */\n\trequiresAssistantAfterToolResult?: boolean;\n\t/** Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL. */\n\trequiresThinkingAsText?: boolean;\n\t/** Format for reasoning/thinking parameter. \"openai\" uses reasoning_effort, \"zai\" uses thinking: { type: \"enabled\" }, \"qwen\" uses enable_thinking: boolean. Default: \"openai\". */\n\tthinkingFormat?: \"openai\" | \"zai\" | \"qwen\";\n\t/** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */\n\topenRouterRouting?: OpenRouterRouting;\n\t/** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */\n\tvercelGatewayRouting?: VercelGatewayRouting;\n\t/** Whether the provider supports the `strict` field in tool definitions. Default: true. */\n\tsupportsStrictMode?: boolean;\n}\n\n/** Compatibility settings for OpenAI Responses APIs. */\nexport interface OpenAIResponsesCompat {\n\t// Reserved for future use\n}\n\n/**\n * OpenRouter provider routing preferences.\n * Controls which upstream providers OpenRouter routes requests to.\n * @see https://openrouter.ai/docs/provider-routing\n */\nexport interface OpenRouterRouting {\n\t/** List of provider slugs to exclusively use for this request (e.g., [\"amazon-bedrock\", \"anthropic\"]). */\n\tonly?: string[];\n\t/** List of provider slugs to try in order (e.g., [\"anthropic\", \"openai\"]). */\n\torder?: string[];\n}\n\n/**\n * Vercel AI Gateway routing preferences.\n * Controls which upstream providers the gateway routes requests to.\n * @see https://vercel.com/docs/ai-gateway/models-and-providers/provider-options\n */\nexport interface VercelGatewayRouting {\n\t/** List of provider slugs to exclusively use for this request (e.g., [\"bedrock\", \"anthropic\"]). */\n\tonly?: string[];\n\t/** List of provider slugs to try in order (e.g., [\"anthropic\", \"openai\"]). */\n\torder?: string[];\n}\n\n/**\n * Provider-agnostic capability declarations for a model.\n *\n * These fields allow models to self-declare supported features so that call\n * sites can read from metadata rather than pattern-matching on model IDs or\n * provider names. Add fields here as new cross-provider capabilities emerge.\n */\nexport interface ModelCapabilities {\n\t/** Whether the model supports xhigh thinking level. */\n\tsupportsXhigh?: boolean;\n\t/**\n\t * Whether tool call IDs must be included and normalised in tool results for\n\t * this model. Relevant for models deployed cross-provider (e.g. Claude or\n\t * GPT variants via Google APIs) where the host API imposes stricter ID rules.\n\t */\n\trequiresToolCallId?: boolean;\n\t/** Whether OpenAI-style service tiers (priority/flex) apply to this model. */\n\tsupportsServiceTier?: boolean;\n\t/**\n\t * Approximate characters per token for this model.\n\t * Used as a fallback when an accurate tokenizer is unavailable.\n\t * If omitted, the provider-level default is used.\n\t */\n\tcharsPerToken?: number;\n}\n\n// Model interface for the unified model system\nexport interface Model<TApi extends Api> {\n\tid: string;\n\tname: string;\n\tapi: TApi;\n\tprovider: Provider;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: (\"text\" | \"image\")[];\n\tcost: {\n\t\tinput: number; // $/million tokens\n\t\toutput: number; // $/million tokens\n\t\tcacheRead: number; // $/million tokens\n\t\tcacheWrite: number; // $/million tokens\n\t};\n\tcontextWindow: number;\n\tmaxTokens: number;\n\theaders?: Record<string, string>;\n\t/** Compatibility overrides for OpenAI-compatible APIs. If not set, auto-detected from baseUrl. */\n\tcompat?: TApi extends \"openai-completions\"\n\t\t? OpenAICompletionsCompat\n\t\t: TApi extends \"openai-responses\"\n\t\t\t? OpenAIResponsesCompat\n\t\t\t: never;\n\t/**\n\t * Provider-agnostic capability declarations for this model.\n\t * Read these fields instead of pattern-matching on model IDs or provider names.\n\t */\n\tcapabilities?: ModelCapabilities;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type KnownApi =\n\t| \"openai-completions\"\n\t| \"mistral-conversations\"\n\t| \"openai-responses\"\n\t| \"azure-openai-responses\"\n\t| \"openai-codex-responses\"\n\t| \"anthropic-messages\"\n\t| \"anthropic-vertex\"\n\t| \"bedrock-converse-stream\"\n\t| \"google-generative-ai\"\n\t| \"google-gemini-cli\"\n\t| \"google-vertex\"\n\t| \"ollama-chat\";\n\nexport type Api = KnownApi | (string & {});\n\nexport type KnownProvider =\n\t| \"amazon-bedrock\"\n\t| \"anthropic\"\n\t| \"anthropic-vertex\"\n\t| \"google\"\n\t| \"google-gemini-cli\"\n\t| \"google-antigravity\"\n\t| \"google-vertex\"\n\t| \"openai\"\n\t| \"azure-openai-responses\"\n\t| \"openai-codex\"\n\t| \"github-copilot\"\n\t| \"xai\"\n\t| \"groq\"\n\t| \"cerebras\"\n\t| \"openrouter\"\n\t| \"vercel-ai-gateway\"\n\t| \"zai\"\n\t| \"mistral\"\n\t| \"minimax\"\n\t| \"minimax-cn\"\n\t| \"huggingface\"\n\t| \"opencode\"\n\t| \"opencode-go\"\n\t| \"kimi-coding\"\n\t| \"alibaba-coding-plan\"\n\t| \"ollama\"\n\t| \"ollama-cloud\";\nexport type Provider = KnownProvider | string;\n\nexport type ThinkingLevel = \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\n/** Token budgets for each thinking level (token-based providers only) */\nexport interface ThinkingBudgets {\n\tminimal?: number;\n\tlow?: number;\n\tmedium?: number;\n\thigh?: number;\n}\n\n// Base options all providers share\nexport type CacheRetention = \"none\" | \"short\" | \"long\";\n\nexport type Transport = \"sse\" | \"websocket\" | \"auto\";\n\nexport interface StreamOptions {\n\ttemperature?: number;\n\tmaxTokens?: number;\n\tsignal?: AbortSignal;\n\tapiKey?: string;\n\t/**\n\t * Preferred transport for providers that support multiple transports.\n\t * Providers that do not support this option ignore it.\n\t */\n\ttransport?: Transport;\n\t/**\n\t * Prompt cache retention preference. Providers map this to their supported values.\n\t * Default: \"short\".\n\t */\n\tcacheRetention?: CacheRetention;\n\t/**\n\t * Optional session identifier for providers that support session-based caching.\n\t * Providers can use this to enable prompt caching, request routing, or other\n\t * session-aware features. Ignored by providers that don't support it.\n\t */\n\tsessionId?: string;\n\t/**\n\t * Optional callback for inspecting or replacing provider payloads before sending.\n\t * Return undefined to keep the payload unchanged.\n\t */\n\tonPayload?: (payload: unknown, model: Model<Api>) => unknown | undefined | Promise<unknown | undefined>;\n\t/**\n\t * Optional custom HTTP headers to include in API requests.\n\t * Merged with provider defaults; can override default headers.\n\t * Not supported by all providers (e.g., AWS Bedrock uses SDK auth).\n\t */\n\theaders?: Record<string, string>;\n\t/**\n\t * Maximum delay in milliseconds to wait for a retry when the server requests a long wait.\n\t * If the server's requested delay exceeds this value, the request fails immediately\n\t * with an error containing the requested delay, allowing higher-level retry logic\n\t * to handle it with user visibility.\n\t * Default: 60000 (60 seconds). Set to 0 to disable the cap.\n\t */\n\tmaxRetryDelayMs?: number;\n\t/**\n\t * Optional metadata to include in API requests.\n\t * Providers extract the fields they understand and ignore the rest.\n\t * For example, Anthropic uses `user_id` for abuse tracking and rate limiting.\n\t */\n\tmetadata?: Record<string, unknown>;\n}\n\nexport type ProviderStreamOptions = StreamOptions & Record<string, unknown>;\n\n// Unified options with reasoning passed to streamSimple() and completeSimple()\nexport interface SimpleStreamOptions extends StreamOptions {\n\treasoning?: ThinkingLevel;\n\t/** Custom token budgets for thinking levels (token-based providers only) */\n\tthinkingBudgets?: ThinkingBudgets;\n}\n\n// Generic StreamFunction with typed options\nexport type StreamFunction<TApi extends Api = Api, TOptions extends StreamOptions = StreamOptions> = (\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: TOptions,\n) => AssistantMessageEventStream;\n\nexport interface TextSignatureV1 {\n\tv: 1;\n\tid: string;\n\tphase?: \"commentary\" | \"final_answer\";\n}\n\nexport interface TextContent {\n\ttype: \"text\";\n\ttext: string;\n\ttextSignature?: string; // e.g., for OpenAI responses, message metadata (legacy id string or TextSignatureV1 JSON)\n}\n\nexport interface ThinkingContent {\n\ttype: \"thinking\";\n\tthinking: string;\n\tthinkingSignature?: string; // e.g., for OpenAI responses, the reasoning item ID\n\t/** When true, the thinking content was redacted by safety filters. The opaque\n\t * encrypted payload is stored in `thinkingSignature` so it can be passed back\n\t * to the API for multi-turn continuity. */\n\tredacted?: boolean;\n}\n\nexport interface ImageContent {\n\ttype: \"image\";\n\tdata: string; // base64 encoded image data\n\tmimeType: string; // e.g., \"image/jpeg\", \"image/png\"\n}\n\nexport interface ToolCall {\n\ttype: \"toolCall\";\n\tid: string;\n\tname: string;\n\targuments: Record<string, any>;\n\tthoughtSignature?: string; // Google-specific: opaque signature for reusing thought context\n}\n\n/** Server-side tool use (e.g., Anthropic native web search). Executed by the API, not the client. */\nexport interface ServerToolUseContent {\n\ttype: \"serverToolUse\";\n\tid: string;\n\tname: string; // e.g., \"web_search\"\n\tinput: unknown;\n}\n\n/** Result of a server-side tool execution, paired with a ServerToolUseContent by toolUseId. */\nexport interface WebSearchResultContent {\n\ttype: \"webSearchResult\";\n\ttoolUseId: string;\n\t/** Search results or error from the server. Opaque — stored for API replay. */\n\tcontent: unknown;\n}\n\nexport interface Usage {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\ttotalTokens: number;\n\tcost: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheRead: number;\n\t\tcacheWrite: number;\n\t\ttotal: number;\n\t};\n}\n\nexport type StopReason = \"stop\" | \"length\" | \"toolUse\" | \"pauseTurn\" | \"error\" | \"aborted\";\n\nexport interface UserMessage {\n\trole: \"user\";\n\tcontent: string | (TextContent | ImageContent)[];\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface AssistantMessage {\n\trole: \"assistant\";\n\tcontent: (TextContent | ThinkingContent | ToolCall | ServerToolUseContent | WebSearchResultContent)[];\n\tapi: Api;\n\tprovider: Provider;\n\tmodel: string;\n\tusage: Usage;\n\tstopReason: StopReason;\n\terrorMessage?: string;\n\t/** Server-requested retry delay in milliseconds (from Retry-After or rate limit headers). */\n\tretryAfterMs?: number;\n\t/** Provider inference performance metrics (e.g. tokens/sec from local models). */\n\tinferenceMetrics?: InferenceMetrics;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\n/** Inference performance metrics reported by providers that support it (e.g. Ollama). */\nexport interface InferenceMetrics {\n\t/** Tokens generated per second during eval phase. */\n\ttokensPerSecond: number;\n\t/** Wall-clock duration of the full request in milliseconds. */\n\ttotalDurationMs: number;\n\t/** Duration of the eval (generation) phase in milliseconds. */\n\tevalDurationMs: number;\n\t/** Duration of the prompt eval phase in milliseconds. */\n\tpromptEvalDurationMs: number;\n}\n\nexport interface ToolResultMessage<TDetails = any> {\n\trole: \"toolResult\";\n\ttoolCallId: string;\n\ttoolName: string;\n\tcontent: (TextContent | ImageContent)[]; // Supports text and images\n\tdetails?: TDetails;\n\tisError: boolean;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport type Message = UserMessage | AssistantMessage | ToolResultMessage;\n\nimport type { TSchema } from \"@sinclair/typebox\";\n\nexport interface Tool<TParameters extends TSchema = TSchema> {\n\tname: string;\n\tdescription: string;\n\tparameters: TParameters;\n}\n\nexport interface Context {\n\tsystemPrompt?: string;\n\tmessages: Message[];\n\ttools?: Tool[];\n}\n\nexport type AssistantMessageEvent =\n\t| { type: \"start\"; partial: AssistantMessage }\n\t| { type: \"text_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"text_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"thinking_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"thinking_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"toolcall_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"toolcall_end\"; contentIndex: number; toolCall: ToolCall; partial: AssistantMessage; malformedArguments?: boolean }\n\t| { type: \"server_tool_use\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"web_search_result\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"done\"; reason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\" | \"pauseTurn\">; message: AssistantMessage }\n\t| { type: \"error\"; reason: Extract<StopReason, \"aborted\" | \"error\">; error: AssistantMessage };\n\n/**\n * Compatibility settings for OpenAI-compatible completions APIs.\n * Use this to override URL-based auto-detection for custom providers.\n */\nexport interface OpenAICompletionsCompat {\n\t/** Whether the provider supports the `store` field. Default: auto-detected from URL. */\n\tsupportsStore?: boolean;\n\t/** Whether the provider supports the `developer` role (vs `system`). Default: auto-detected from URL. */\n\tsupportsDeveloperRole?: boolean;\n\t/** Whether the provider supports `reasoning_effort`. Default: auto-detected from URL. */\n\tsupportsReasoningEffort?: boolean;\n\t/** Optional mapping from pi-ai reasoning levels to provider/model-specific `reasoning_effort` values. */\n\treasoningEffortMap?: Partial<Record<ThinkingLevel, string>>;\n\t/** Whether the provider supports `stream_options: { include_usage: true }` for token usage in streaming responses. Default: true. */\n\tsupportsUsageInStreaming?: boolean;\n\t/** Which field to use for max tokens. Default: auto-detected from URL. */\n\tmaxTokensField?: \"max_completion_tokens\" | \"max_tokens\";\n\t/** Whether tool results require the `name` field. Default: auto-detected from URL. */\n\trequiresToolResultName?: boolean;\n\t/** Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. */\n\trequiresAssistantAfterToolResult?: boolean;\n\t/** Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL. */\n\trequiresThinkingAsText?: boolean;\n\t/** Format for reasoning/thinking parameter. \"openai\" uses reasoning_effort, \"zai\" uses thinking: { type: \"enabled\" }, \"qwen\" uses enable_thinking: boolean. Default: \"openai\". */\n\tthinkingFormat?: \"openai\" | \"zai\" | \"qwen\";\n\t/** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */\n\topenRouterRouting?: OpenRouterRouting;\n\t/** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */\n\tvercelGatewayRouting?: VercelGatewayRouting;\n\t/** Whether the provider supports the `strict` field in tool definitions. Default: true. */\n\tsupportsStrictMode?: boolean;\n}\n\n/** Compatibility settings for OpenAI Responses APIs. */\nexport interface OpenAIResponsesCompat {\n\t// Reserved for future use\n}\n\n/**\n * OpenRouter provider routing preferences.\n * Controls which upstream providers OpenRouter routes requests to.\n * @see https://openrouter.ai/docs/provider-routing\n */\nexport interface OpenRouterRouting {\n\t/** List of provider slugs to exclusively use for this request (e.g., [\"amazon-bedrock\", \"anthropic\"]). */\n\tonly?: string[];\n\t/** List of provider slugs to try in order (e.g., [\"anthropic\", \"openai\"]). */\n\torder?: string[];\n}\n\n/**\n * Vercel AI Gateway routing preferences.\n * Controls which upstream providers the gateway routes requests to.\n * @see https://vercel.com/docs/ai-gateway/models-and-providers/provider-options\n */\nexport interface VercelGatewayRouting {\n\t/** List of provider slugs to exclusively use for this request (e.g., [\"bedrock\", \"anthropic\"]). */\n\tonly?: string[];\n\t/** List of provider slugs to try in order (e.g., [\"anthropic\", \"openai\"]). */\n\torder?: string[];\n}\n\n/**\n * Provider-agnostic capability declarations for a model.\n *\n * These fields allow models to self-declare supported features so that call\n * sites can read from metadata rather than pattern-matching on model IDs or\n * provider names. Add fields here as new cross-provider capabilities emerge.\n */\nexport interface ModelCapabilities {\n\t/** Whether the model supports xhigh thinking level. */\n\tsupportsXhigh?: boolean;\n\t/**\n\t * Whether tool call IDs must be included and normalised in tool results for\n\t * this model. Relevant for models deployed cross-provider (e.g. Claude or\n\t * GPT variants via Google APIs) where the host API imposes stricter ID rules.\n\t */\n\trequiresToolCallId?: boolean;\n\t/** Whether OpenAI-style service tiers (priority/flex) apply to this model. */\n\tsupportsServiceTier?: boolean;\n\t/**\n\t * Approximate characters per token for this model.\n\t * Used as a fallback when an accurate tokenizer is unavailable.\n\t * If omitted, the provider-level default is used.\n\t */\n\tcharsPerToken?: number;\n}\n\n// Model interface for the unified model system\nexport interface Model<TApi extends Api> {\n\tid: string;\n\tname: string;\n\tapi: TApi;\n\tprovider: Provider;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: (\"text\" | \"image\")[];\n\tcost: {\n\t\tinput: number; // $/million tokens\n\t\toutput: number; // $/million tokens\n\t\tcacheRead: number; // $/million tokens\n\t\tcacheWrite: number; // $/million tokens\n\t};\n\tcontextWindow: number;\n\tmaxTokens: number;\n\theaders?: Record<string, string>;\n\t/** Compatibility overrides for OpenAI-compatible APIs. If not set, auto-detected from baseUrl. */\n\tcompat?: TApi extends \"openai-completions\"\n\t\t? OpenAICompletionsCompat\n\t\t: TApi extends \"openai-responses\"\n\t\t\t? OpenAIResponsesCompat\n\t\t\t: never;\n\t/**\n\t * Provider-agnostic capability declarations for this model.\n\t * Read these fields instead of pattern-matching on model IDs or provider names.\n\t */\n\tcapabilities?: ModelCapabilities;\n\t/** Opaque provider-specific options. Cast to the appropriate type in the provider's stream handler. */\n\tproviderOptions?: Record<string, unknown>;\n}\n"]}
|
|
@@ -13,7 +13,8 @@ export type KnownApi =
|
|
|
13
13
|
| "bedrock-converse-stream"
|
|
14
14
|
| "google-generative-ai"
|
|
15
15
|
| "google-gemini-cli"
|
|
16
|
-
| "google-vertex"
|
|
16
|
+
| "google-vertex"
|
|
17
|
+
| "ollama-chat";
|
|
17
18
|
|
|
18
19
|
export type Api = KnownApi | (string & {});
|
|
19
20
|
|
|
@@ -212,9 +213,23 @@ export interface AssistantMessage {
|
|
|
212
213
|
errorMessage?: string;
|
|
213
214
|
/** Server-requested retry delay in milliseconds (from Retry-After or rate limit headers). */
|
|
214
215
|
retryAfterMs?: number;
|
|
216
|
+
/** Provider inference performance metrics (e.g. tokens/sec from local models). */
|
|
217
|
+
inferenceMetrics?: InferenceMetrics;
|
|
215
218
|
timestamp: number; // Unix timestamp in milliseconds
|
|
216
219
|
}
|
|
217
220
|
|
|
221
|
+
/** Inference performance metrics reported by providers that support it (e.g. Ollama). */
|
|
222
|
+
export interface InferenceMetrics {
|
|
223
|
+
/** Tokens generated per second during eval phase. */
|
|
224
|
+
tokensPerSecond: number;
|
|
225
|
+
/** Wall-clock duration of the full request in milliseconds. */
|
|
226
|
+
totalDurationMs: number;
|
|
227
|
+
/** Duration of the eval (generation) phase in milliseconds. */
|
|
228
|
+
evalDurationMs: number;
|
|
229
|
+
/** Duration of the prompt eval phase in milliseconds. */
|
|
230
|
+
promptEvalDurationMs: number;
|
|
231
|
+
}
|
|
232
|
+
|
|
218
233
|
export interface ToolResultMessage<TDetails = any> {
|
|
219
234
|
role: "toolResult";
|
|
220
235
|
toolCallId: string;
|
|
@@ -374,4 +389,6 @@ export interface Model<TApi extends Api> {
|
|
|
374
389
|
* Read these fields instead of pattern-matching on model IDs or provider names.
|
|
375
390
|
*/
|
|
376
391
|
capabilities?: ModelCapabilities;
|
|
392
|
+
/** Opaque provider-specific options. Cast to the appropriate type in the provider's stream handler. */
|
|
393
|
+
providerOptions?: Record<string, unknown>;
|
|
377
394
|
}
|
|
@@ -17,6 +17,15 @@ export type OAuthCredential = {
|
|
|
17
17
|
type: "oauth";
|
|
18
18
|
} & OAuthCredentials;
|
|
19
19
|
export type AuthCredential = ApiKeyCredential | OAuthCredential;
|
|
20
|
+
/**
|
|
21
|
+
* Detect if a string is a Google OAuth access token rather than an API key.
|
|
22
|
+
* Google OAuth access tokens start with "ya29." — these are issued by
|
|
23
|
+
* Google's OAuth2 token endpoint and are not valid as AI Studio API keys.
|
|
24
|
+
*
|
|
25
|
+
* Users who installed Google's Gemini CLI may have these tokens and
|
|
26
|
+
* mistakenly set them as GEMINI_API_KEY.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isGoogleOAuthToken(key: string): boolean;
|
|
20
29
|
/**
|
|
21
30
|
* On-disk format: each provider maps to a single credential or an array of credentials.
|
|
22
31
|
* Single credentials are normalized to arrays at load time for internal use.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-storage.d.ts","sourceRoot":"","sources":["../../src/core/auth-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAEN,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,MAAM,YAAY,CAAC;AASpB,MAAM,MAAM,gBAAgB,GAAG;IAC9B,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,OAAO,CAAC;CACd,GAAG,gBAAgB,CAAC;AAErB,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"auth-storage.d.ts","sourceRoot":"","sources":["../../src/core/auth-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,40 @@ import { getAgentDir } from "../config.js";
|
|
|
16
16
|
import { AUTH_LOCK_STALE_MS } from "./constants.js";
|
|
17
17
|
import { acquireLockAsync, acquireLockSyncWithRetry } from "./lock-utils.js";
|
|
18
18
|
import { resolveConfigValue } from "./resolve-config-value.js";
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Google OAuth token detection
|
|
21
|
+
// ============================================================================
|
|
22
|
+
/**
|
|
23
|
+
* Providers that use Google AI Studio API keys (not OAuth tokens).
|
|
24
|
+
* OAuth access tokens (ya29.*) are not valid API keys for these providers.
|
|
25
|
+
*/
|
|
26
|
+
const GOOGLE_API_KEY_PROVIDERS = new Set(["google"]);
|
|
27
|
+
/**
|
|
28
|
+
* Detect if a string is a Google OAuth access token rather than an API key.
|
|
29
|
+
* Google OAuth access tokens start with "ya29." — these are issued by
|
|
30
|
+
* Google's OAuth2 token endpoint and are not valid as AI Studio API keys.
|
|
31
|
+
*
|
|
32
|
+
* Users who installed Google's Gemini CLI may have these tokens and
|
|
33
|
+
* mistakenly set them as GEMINI_API_KEY.
|
|
34
|
+
*/
|
|
35
|
+
export function isGoogleOAuthToken(key) {
|
|
36
|
+
return key.startsWith("ya29.");
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Validate that an API key is not a Google OAuth token being used for
|
|
40
|
+
* a provider that requires actual API keys (e.g., Google AI Studio).
|
|
41
|
+
* Throws a descriptive error if the key appears to be an OAuth token.
|
|
42
|
+
*/
|
|
43
|
+
function validateNotGoogleOAuthToken(provider, key) {
|
|
44
|
+
if (GOOGLE_API_KEY_PROVIDERS.has(provider) && isGoogleOAuthToken(key)) {
|
|
45
|
+
throw new Error(`The provided key for "${provider}" appears to be a Google OAuth access token (ya29.*), ` +
|
|
46
|
+
`not a valid API key. Google AI Studio requires an API key starting with "AIza...". ` +
|
|
47
|
+
`\n\nIf you're using Google's Gemini CLI, its OAuth tokens are not compatible. ` +
|
|
48
|
+
`Either:\n` +
|
|
49
|
+
` 1. Get an API key from https://aistudio.google.com/apikey and set GEMINI_API_KEY\n` +
|
|
50
|
+
` 2. Use '/login google-gemini-cli' to authenticate via Cloud Code Assist`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
19
53
|
export class FileAuthStorageBackend {
|
|
20
54
|
constructor(authPath = join(getAgentDir(), "auth.json")) {
|
|
21
55
|
this.authPath = authPath;
|
|
@@ -298,6 +332,8 @@ export class AuthStorage {
|
|
|
298
332
|
*/
|
|
299
333
|
set(provider, credential) {
|
|
300
334
|
if (credential.type === "api_key") {
|
|
335
|
+
// Block Google OAuth tokens being stored as API keys for AI Studio providers
|
|
336
|
+
validateNotGoogleOAuthToken(provider, credential.key);
|
|
301
337
|
const existing = this.getCredentialsForProvider(provider);
|
|
302
338
|
// Deduplicate: don't add if same key already exists
|
|
303
339
|
const isDuplicate = existing.some((c) => c.type === "api_key" && c.key === credential.key);
|
|
@@ -670,6 +706,12 @@ export class AuthStorage {
|
|
|
670
706
|
// Runtime override takes highest priority
|
|
671
707
|
const runtimeKey = this.runtimeOverrides.get(providerId);
|
|
672
708
|
if (runtimeKey) {
|
|
709
|
+
// Block Google OAuth tokens used as runtime API key overrides
|
|
710
|
+
if (GOOGLE_API_KEY_PROVIDERS.has(providerId) && isGoogleOAuthToken(runtimeKey)) {
|
|
711
|
+
this.recordError(new Error(`Blocked Google OAuth access token (ya29.*) for provider "${providerId}". ` +
|
|
712
|
+
`Use an API key from https://aistudio.google.com/apikey or '/login google-gemini-cli'.`));
|
|
713
|
+
return undefined;
|
|
714
|
+
}
|
|
673
715
|
return runtimeKey;
|
|
674
716
|
}
|
|
675
717
|
const credentials = this.getCredentialsForProvider(providerId);
|
|
@@ -686,8 +728,15 @@ export class AuthStorage {
|
|
|
686
728
|
}
|
|
687
729
|
// Fall back to environment variable
|
|
688
730
|
const envKey = getEnvApiKey(providerId);
|
|
689
|
-
if (envKey)
|
|
731
|
+
if (envKey) {
|
|
732
|
+
// Block Google OAuth tokens from environment variables (e.g., GEMINI_API_KEY=ya29.*)
|
|
733
|
+
if (GOOGLE_API_KEY_PROVIDERS.has(providerId) && isGoogleOAuthToken(envKey)) {
|
|
734
|
+
this.recordError(new Error(`GEMINI_API_KEY contains a Google OAuth access token (ya29.*), not an API key. ` +
|
|
735
|
+
`Get an API key from https://aistudio.google.com/apikey or use '/login google-gemini-cli'.`));
|
|
736
|
+
return undefined;
|
|
737
|
+
}
|
|
690
738
|
return envKey;
|
|
739
|
+
}
|
|
691
740
|
// Fall back to custom resolver (e.g., models.json custom providers)
|
|
692
741
|
return this.fallbackResolver?.(providerId) ?? undefined;
|
|
693
742
|
}
|