gsd-pi 2.10.12 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundled-extension-paths.d.ts +2 -0
- package/dist/bundled-extension-paths.js +10 -0
- package/dist/loader.js +45 -28
- package/dist/onboarding.js +100 -0
- package/dist/resource-loader.js +12 -3
- package/dist/resources/GSD-WORKFLOW.md +661 -0
- package/dist/resources/agents/researcher.md +29 -0
- package/dist/resources/agents/scout.md +56 -0
- package/dist/resources/agents/worker.md +31 -0
- package/dist/resources/extensions/ask-user-questions.ts +289 -0
- package/dist/resources/extensions/async-jobs/async-bash-tool.ts +211 -0
- package/dist/resources/extensions/async-jobs/await-tool.ts +101 -0
- package/dist/resources/extensions/async-jobs/cancel-job-tool.ts +34 -0
- package/dist/resources/extensions/async-jobs/index.ts +133 -0
- package/dist/resources/extensions/async-jobs/job-manager.ts +211 -0
- package/dist/resources/extensions/bg-shell/index.ts +3179 -0
- package/dist/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
- package/dist/resources/extensions/browser-tools/capture.ts +165 -0
- package/dist/resources/extensions/browser-tools/core.d.ts +205 -0
- package/dist/resources/extensions/browser-tools/core.js +1057 -0
- package/dist/resources/extensions/browser-tools/evaluate-helpers.ts +184 -0
- package/dist/resources/extensions/browser-tools/index.ts +51 -0
- package/dist/resources/extensions/browser-tools/lifecycle.ts +270 -0
- package/dist/resources/extensions/browser-tools/package.json +24 -0
- package/dist/resources/extensions/browser-tools/refs.ts +264 -0
- package/dist/resources/extensions/browser-tools/settle.ts +197 -0
- package/dist/resources/extensions/browser-tools/state.ts +408 -0
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +652 -0
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +614 -0
- package/dist/resources/extensions/browser-tools/tools/assertions.ts +342 -0
- package/dist/resources/extensions/browser-tools/tools/forms.ts +801 -0
- package/dist/resources/extensions/browser-tools/tools/inspection.ts +492 -0
- package/dist/resources/extensions/browser-tools/tools/intent.ts +614 -0
- package/dist/resources/extensions/browser-tools/tools/interaction.ts +865 -0
- package/dist/resources/extensions/browser-tools/tools/navigation.ts +232 -0
- package/dist/resources/extensions/browser-tools/tools/pages.ts +303 -0
- package/dist/resources/extensions/browser-tools/tools/refs.ts +541 -0
- package/dist/resources/extensions/browser-tools/tools/screenshot.ts +83 -0
- package/dist/resources/extensions/browser-tools/tools/session.ts +400 -0
- package/dist/resources/extensions/browser-tools/tools/wait.ts +247 -0
- package/dist/resources/extensions/browser-tools/utils.ts +660 -0
- package/dist/resources/extensions/context7/index.ts +428 -0
- package/dist/resources/extensions/context7/package.json +11 -0
- package/dist/resources/extensions/get-secrets-from-user.ts +625 -0
- package/dist/resources/extensions/google-search/index.ts +336 -0
- package/dist/resources/extensions/google-search/package.json +9 -0
- package/dist/resources/extensions/gsd/activity-log.ts +116 -0
- package/dist/resources/extensions/gsd/auto.ts +3732 -0
- package/dist/resources/extensions/gsd/commands.ts +544 -0
- package/dist/resources/extensions/gsd/crash-recovery.ts +105 -0
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +564 -0
- package/dist/resources/extensions/gsd/dispatch-guard.ts +78 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +278 -0
- package/dist/resources/extensions/gsd/doctor.ts +766 -0
- package/dist/resources/extensions/gsd/exit-command.ts +18 -0
- package/dist/resources/extensions/gsd/files.ts +857 -0
- package/dist/resources/extensions/gsd/git-service.ts +904 -0
- package/dist/resources/extensions/gsd/gitignore.ts +200 -0
- package/dist/resources/extensions/gsd/guided-flow.ts +1054 -0
- package/dist/resources/extensions/gsd/index.ts +735 -0
- package/dist/resources/extensions/gsd/metrics.ts +374 -0
- package/dist/resources/extensions/gsd/migrate/command.ts +218 -0
- package/dist/resources/extensions/gsd/migrate/index.ts +42 -0
- package/dist/resources/extensions/gsd/migrate/parser.ts +323 -0
- package/dist/resources/extensions/gsd/migrate/parsers.ts +624 -0
- package/dist/resources/extensions/gsd/migrate/preview.ts +48 -0
- package/dist/resources/extensions/gsd/migrate/transformer.ts +346 -0
- package/dist/resources/extensions/gsd/migrate/types.ts +370 -0
- package/dist/resources/extensions/gsd/migrate/validator.ts +55 -0
- package/dist/resources/extensions/gsd/migrate/writer.ts +539 -0
- package/dist/resources/extensions/gsd/native-git-bridge.ts +181 -0
- package/dist/resources/extensions/gsd/native-parser-bridge.ts +135 -0
- package/dist/resources/extensions/gsd/observability-validator.ts +408 -0
- package/dist/resources/extensions/gsd/package.json +11 -0
- package/dist/resources/extensions/gsd/paths.ts +339 -0
- package/dist/resources/extensions/gsd/post-unit-hooks.ts +449 -0
- package/dist/resources/extensions/gsd/preferences.ts +988 -0
- package/dist/resources/extensions/gsd/prompt-loader.ts +92 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +25 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +27 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +237 -0
- package/dist/resources/extensions/gsd/prompts/doctor-heal.md +29 -0
- package/dist/resources/extensions/gsd/prompts/execute-task.md +63 -0
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +3 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +61 -0
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +3 -0
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +29 -0
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +3 -0
- package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +13 -0
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -0
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +78 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +55 -0
- package/dist/resources/extensions/gsd/prompts/queue.md +100 -0
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +48 -0
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +39 -0
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +37 -0
- package/dist/resources/extensions/gsd/prompts/research-slice.md +28 -0
- package/dist/resources/extensions/gsd/prompts/review-migration.md +66 -0
- package/dist/resources/extensions/gsd/prompts/run-uat.md +109 -0
- package/dist/resources/extensions/gsd/prompts/system.md +190 -0
- package/dist/resources/extensions/gsd/prompts/worktree-merge.md +123 -0
- package/dist/resources/extensions/gsd/roadmap-slices.ts +50 -0
- package/dist/resources/extensions/gsd/session-forensics.ts +500 -0
- package/dist/resources/extensions/gsd/skill-discovery.ts +137 -0
- package/dist/resources/extensions/gsd/state.ts +569 -0
- package/dist/resources/extensions/gsd/templates/context.md +76 -0
- package/dist/resources/extensions/gsd/templates/decisions.md +8 -0
- package/dist/resources/extensions/gsd/templates/milestone-summary.md +73 -0
- package/dist/resources/extensions/gsd/templates/plan.md +131 -0
- package/dist/resources/extensions/gsd/templates/preferences.md +23 -0
- package/dist/resources/extensions/gsd/templates/project.md +31 -0
- package/dist/resources/extensions/gsd/templates/reassessment.md +28 -0
- package/dist/resources/extensions/gsd/templates/requirements.md +81 -0
- package/dist/resources/extensions/gsd/templates/research.md +46 -0
- package/dist/resources/extensions/gsd/templates/roadmap.md +118 -0
- package/dist/resources/extensions/gsd/templates/secrets-manifest.md +22 -0
- package/dist/resources/extensions/gsd/templates/slice-context.md +58 -0
- package/dist/resources/extensions/gsd/templates/slice-summary.md +99 -0
- package/dist/resources/extensions/gsd/templates/state.md +19 -0
- package/dist/resources/extensions/gsd/templates/task-plan.md +52 -0
- package/dist/resources/extensions/gsd/templates/task-summary.md +57 -0
- package/dist/resources/extensions/gsd/templates/uat.md +54 -0
- package/dist/resources/extensions/gsd/tests/activity-log-prune.test.ts +297 -0
- package/dist/resources/extensions/gsd/tests/activity-log-save.test.ts +127 -0
- package/dist/resources/extensions/gsd/tests/auto-draft-pause.test.ts +109 -0
- package/dist/resources/extensions/gsd/tests/auto-preflight.test.ts +45 -0
- package/dist/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +196 -0
- package/dist/resources/extensions/gsd/tests/auto-supervisor.test.mjs +53 -0
- package/dist/resources/extensions/gsd/tests/collect-from-manifest.test.ts +469 -0
- package/dist/resources/extensions/gsd/tests/complete-milestone.test.ts +200 -0
- package/dist/resources/extensions/gsd/tests/cost-projection.test.ts +134 -0
- package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +312 -0
- package/dist/resources/extensions/gsd/tests/derive-state-draft.test.ts +299 -0
- package/dist/resources/extensions/gsd/tests/derive-state.test.ts +660 -0
- package/dist/resources/extensions/gsd/tests/discuss-prompt.test.ts +27 -0
- package/dist/resources/extensions/gsd/tests/dispatch-guard.test.ts +91 -0
- package/dist/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +170 -0
- package/dist/resources/extensions/gsd/tests/doctor.test.ts +594 -0
- package/dist/resources/extensions/gsd/tests/draft-promotion.test.ts +169 -0
- package/dist/resources/extensions/gsd/tests/exit-command.test.ts +50 -0
- package/dist/resources/extensions/gsd/tests/git-service.test.ts +1788 -0
- package/dist/resources/extensions/gsd/tests/idle-recovery.test.ts +577 -0
- package/dist/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +580 -0
- package/dist/resources/extensions/gsd/tests/manifest-status.test.ts +283 -0
- package/dist/resources/extensions/gsd/tests/metrics-io.test.ts +176 -0
- package/dist/resources/extensions/gsd/tests/metrics.test.ts +188 -0
- package/dist/resources/extensions/gsd/tests/migrate-command.test.ts +369 -0
- package/dist/resources/extensions/gsd/tests/migrate-parser.test.ts +757 -0
- package/dist/resources/extensions/gsd/tests/migrate-transformer.test.ts +635 -0
- package/dist/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +414 -0
- package/dist/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +297 -0
- package/dist/resources/extensions/gsd/tests/migrate-writer.test.ts +398 -0
- package/dist/resources/extensions/gsd/tests/must-have-parser.test.ts +291 -0
- package/dist/resources/extensions/gsd/tests/network-error-fallback.test.ts +54 -0
- package/dist/resources/extensions/gsd/tests/next-milestone-id.test.ts +66 -0
- package/dist/resources/extensions/gsd/tests/orphaned-branch.test.ts +353 -0
- package/dist/resources/extensions/gsd/tests/parsers.test.ts +1664 -0
- package/dist/resources/extensions/gsd/tests/plan-milestone.test.ts +133 -0
- package/dist/resources/extensions/gsd/tests/plan-quality-validator.test.ts +363 -0
- package/dist/resources/extensions/gsd/tests/post-unit-hooks.test.ts +297 -0
- package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +226 -0
- package/dist/resources/extensions/gsd/tests/queue-draft-detection.test.ts +126 -0
- package/dist/resources/extensions/gsd/tests/reassess-prompt.test.ts +142 -0
- package/dist/resources/extensions/gsd/tests/regex-hardening.test.ts +281 -0
- package/dist/resources/extensions/gsd/tests/remote-questions.test.ts +155 -0
- package/dist/resources/extensions/gsd/tests/remote-status.test.ts +99 -0
- package/dist/resources/extensions/gsd/tests/replan-slice.test.ts +493 -0
- package/dist/resources/extensions/gsd/tests/requirements.test.ts +106 -0
- package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +35 -0
- package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +11 -0
- package/dist/resources/extensions/gsd/tests/roadmap-slices.test.ts +41 -0
- package/dist/resources/extensions/gsd/tests/run-uat.test.ts +316 -0
- package/dist/resources/extensions/gsd/tests/secure-env-collect.test.ts +185 -0
- package/dist/resources/extensions/gsd/tests/smart-entry-draft.test.ts +123 -0
- package/dist/resources/extensions/gsd/tests/test-helpers.ts +61 -0
- package/dist/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +219 -0
- package/dist/resources/extensions/gsd/tests/unit-runtime.test.ts +234 -0
- package/dist/resources/extensions/gsd/tests/workspace-index.test.ts +75 -0
- package/dist/resources/extensions/gsd/tests/worktree-integration.test.ts +234 -0
- package/dist/resources/extensions/gsd/tests/worktree-manager.test.ts +141 -0
- package/dist/resources/extensions/gsd/tests/worktree.test.ts +597 -0
- package/dist/resources/extensions/gsd/tests/write-gate.test.ts +122 -0
- package/dist/resources/extensions/gsd/types.ts +296 -0
- package/dist/resources/extensions/gsd/unit-runtime.ts +184 -0
- package/dist/resources/extensions/gsd/workspace-index.ts +189 -0
- package/dist/resources/extensions/gsd/worktree-command.ts +845 -0
- package/dist/resources/extensions/gsd/worktree-manager.ts +459 -0
- package/dist/resources/extensions/gsd/{worktree.js → worktree.ts} +92 -61
- package/dist/resources/extensions/mac-tools/index.ts +852 -0
- package/dist/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
- package/dist/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
- package/dist/resources/extensions/mcporter/index.ts +429 -0
- package/dist/resources/extensions/remote-questions/config.ts +81 -0
- package/dist/resources/extensions/remote-questions/discord-adapter.ts +128 -0
- package/dist/resources/extensions/remote-questions/format.ts +163 -0
- package/dist/resources/extensions/remote-questions/manager.ts +192 -0
- package/dist/resources/extensions/remote-questions/remote-command.ts +361 -0
- package/dist/resources/extensions/remote-questions/slack-adapter.ts +92 -0
- package/dist/resources/extensions/remote-questions/status.ts +31 -0
- package/dist/resources/extensions/remote-questions/store.ts +77 -0
- package/dist/resources/extensions/remote-questions/types.ts +75 -0
- package/dist/resources/extensions/search-the-web/cache.ts +78 -0
- package/dist/resources/extensions/search-the-web/command-search-provider.ts +99 -0
- package/dist/resources/extensions/search-the-web/format.ts +258 -0
- package/dist/resources/extensions/search-the-web/http.ts +238 -0
- package/dist/resources/extensions/search-the-web/index.ts +65 -0
- package/dist/resources/extensions/search-the-web/native-search.ts +165 -0
- package/dist/resources/extensions/search-the-web/provider.ts +136 -0
- package/dist/resources/extensions/search-the-web/tavily.ts +116 -0
- package/dist/resources/extensions/search-the-web/tool-fetch-page.ts +581 -0
- package/dist/resources/extensions/search-the-web/tool-llm-context.ts +620 -0
- package/dist/resources/extensions/search-the-web/tool-search.ts +635 -0
- package/dist/resources/extensions/search-the-web/url-utils.ts +91 -0
- package/dist/resources/extensions/shared/bundled-extension-paths.ts +11 -0
- package/dist/resources/extensions/shared/confirm-ui.ts +126 -0
- package/dist/resources/extensions/shared/interview-ui.ts +613 -0
- package/dist/resources/extensions/shared/next-action-ui.ts +197 -0
- package/dist/resources/extensions/shared/progress-widget.ts +282 -0
- package/dist/resources/extensions/shared/terminal.ts +23 -0
- package/dist/resources/extensions/shared/thinking-widget.ts +107 -0
- package/dist/resources/extensions/shared/ui.ts +400 -0
- package/dist/resources/extensions/shared/wizard-ui.ts +551 -0
- package/dist/resources/extensions/slash-commands/audit.ts +88 -0
- package/dist/resources/extensions/slash-commands/clear.ts +10 -0
- package/dist/resources/extensions/slash-commands/create-extension.ts +297 -0
- package/dist/resources/extensions/slash-commands/create-slash-command.ts +234 -0
- package/dist/resources/extensions/slash-commands/index.ts +12 -0
- package/dist/resources/extensions/subagent/agents.ts +126 -0
- package/dist/resources/extensions/subagent/index.ts +1072 -0
- package/dist/resources/extensions/subagent/isolation.ts +498 -0
- package/dist/resources/extensions/ttsr/index.ts +163 -0
- package/dist/resources/extensions/ttsr/rule-loader.ts +121 -0
- package/dist/resources/extensions/ttsr/ttsr-interrupt.md +6 -0
- package/dist/resources/extensions/ttsr/ttsr-manager.ts +430 -0
- package/dist/resources/extensions/universal-config/discovery.ts +78 -0
- package/dist/resources/extensions/universal-config/format.ts +160 -0
- package/dist/resources/extensions/universal-config/index.ts +118 -0
- package/dist/resources/extensions/universal-config/package.json +11 -0
- package/dist/resources/extensions/universal-config/scanners.ts +579 -0
- package/dist/resources/extensions/universal-config/tests/discovery.test.ts +111 -0
- package/dist/resources/extensions/universal-config/tests/format.test.ts +111 -0
- package/dist/resources/extensions/universal-config/tests/scanners.test.ts +438 -0
- package/dist/resources/extensions/universal-config/tools.ts +60 -0
- package/dist/resources/extensions/universal-config/types.ts +116 -0
- package/dist/resources/extensions/voice/index.ts +271 -0
- package/dist/resources/extensions/voice/speech-recognizer.py +504 -0
- package/dist/resources/extensions/voice/speech-recognizer.swift +154 -0
- package/dist/resources/skills/debug-like-expert/SKILL.md +231 -0
- package/dist/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
- package/dist/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
- package/dist/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
- package/dist/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
- package/dist/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
- package/dist/resources/skills/frontend-design/SKILL.md +45 -0
- package/dist/resources/skills/github-workflows/SKILL.md +92 -0
- package/dist/resources/skills/github-workflows/references/gh/SKILL.md +255 -0
- package/dist/resources/skills/github-workflows/references/gh/references/issue-stories.md +204 -0
- package/dist/resources/skills/github-workflows/references/gh/references/labels.md +170 -0
- package/dist/resources/skills/github-workflows/references/gh/references/milestones.md +158 -0
- package/dist/resources/skills/github-workflows/references/gh/references/projects-v2.md +177 -0
- package/dist/resources/skills/github-workflows/references/gh/scripts/experiment_cleanup.py +191 -0
- package/dist/resources/skills/github-workflows/references/gh/scripts/github_project_setup.py +799 -0
- package/dist/resources/skills/github-workflows/references/gh/tests/__init__.py +0 -0
- package/dist/resources/skills/github-workflows/references/gh/tests/test_github_project_setup.py +608 -0
- package/dist/resources/skills/swiftui/SKILL.md +208 -0
- package/dist/resources/skills/swiftui/references/animations.md +921 -0
- package/dist/resources/skills/swiftui/references/architecture.md +1561 -0
- package/dist/resources/skills/swiftui/references/layout-system.md +1186 -0
- package/dist/resources/skills/swiftui/references/navigation.md +1492 -0
- package/dist/resources/skills/swiftui/references/networking-async.md +214 -0
- package/dist/resources/skills/swiftui/references/performance.md +1706 -0
- package/dist/resources/skills/swiftui/references/platform-integration.md +204 -0
- package/dist/resources/skills/swiftui/references/state-management.md +1443 -0
- package/dist/resources/skills/swiftui/references/swiftdata.md +297 -0
- package/dist/resources/skills/swiftui/references/testing-debugging.md +247 -0
- package/dist/resources/skills/swiftui/references/uikit-appkit-interop.md +218 -0
- package/dist/resources/skills/swiftui/workflows/add-feature.md +191 -0
- package/dist/resources/skills/swiftui/workflows/build-new-app.md +311 -0
- package/dist/resources/skills/swiftui/workflows/debug-swiftui.md +192 -0
- package/dist/resources/skills/swiftui/workflows/optimize-performance.md +197 -0
- package/dist/resources/skills/swiftui/workflows/ship-app.md +203 -0
- package/dist/resources/skills/swiftui/workflows/write-tests.md +235 -0
- package/dist/wizard.js +1 -0
- package/package.json +8 -6
- package/packages/native/dist/fd/index.d.ts +1 -0
- package/packages/native/dist/fd/index.js +1 -0
- package/packages/native/dist/grep/index.d.ts +2 -1
- package/packages/native/dist/grep/index.js +1 -0
- package/packages/native/src/__tests__/fd.test.mjs +35 -0
- package/packages/native/src/__tests__/grep.test.mjs +26 -9
- package/packages/native/src/fd/index.ts +1 -0
- package/packages/native/src/grep/index.ts +3 -2
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +169 -55
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +13 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +16 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +91 -1
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +273 -63
- package/packages/pi-agent-core/src/agent.ts +24 -0
- package/packages/pi-agent-core/src/types.ts +98 -0
- package/packages/pi-ai/dist/env-api-keys.js +2 -0
- package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +314 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +236 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.js +6 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +2 -0
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +1 -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/env-api-keys.ts +2 -0
- package/packages/pi-ai/src/models.generated.ts +236 -0
- package/packages/pi-ai/src/providers/google-gemini-cli.ts +8 -0
- package/packages/pi-ai/src/providers/openai-completions.ts +3 -0
- package/packages/pi-ai/src/types.ts +2 -1
- package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/cli/args.js +1 -0
- package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +26 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +137 -22
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +20 -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 +43 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts +51 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.js +119 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +183 -0
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/index.js +1 -0
- package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts +12 -1
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +37 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/session-manager.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +61 -0
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +47 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/find.js +1 -0
- package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +6 -15
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +18 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +46 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +25 -2
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/cli/args.ts +1 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +167 -22
- package/packages/pi-coding-agent/src/core/auth-storage.ts +45 -0
- package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +229 -0
- package/packages/pi-coding-agent/src/core/fallback-resolver.ts +165 -0
- package/packages/pi-coding-agent/src/core/index.ts +1 -0
- package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -0
- package/packages/pi-coding-agent/src/core/session-manager.ts +51 -1
- package/packages/pi-coding-agent/src/core/settings-manager.ts +66 -0
- package/packages/pi-coding-agent/src/core/tools/find.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +6 -16
- package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +49 -4
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +28 -2
- package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/packages/pi-tui/dist/autocomplete.js +3 -4
- package/packages/pi-tui/dist/autocomplete.js.map +1 -1
- package/packages/pi-tui/dist/components/editor.d.ts +7 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +57 -50
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/src/autocomplete.ts +3 -5
- package/packages/pi-tui/src/components/editor.ts +70 -49
- package/pkg/dist/core/export-html/ansi-to-html.d.ts +22 -0
- package/pkg/dist/core/export-html/ansi-to-html.d.ts.map +1 -0
- package/pkg/dist/core/export-html/ansi-to-html.js +249 -0
- package/pkg/dist/core/export-html/ansi-to-html.js.map +1 -0
- package/pkg/dist/core/export-html/index.d.ts +37 -0
- package/pkg/dist/core/export-html/index.d.ts.map +1 -0
- package/pkg/dist/core/export-html/index.js +223 -0
- package/pkg/dist/core/export-html/index.js.map +1 -0
- package/pkg/dist/core/export-html/template.css +971 -0
- package/pkg/dist/core/export-html/template.html +54 -0
- package/pkg/dist/core/export-html/template.js +1583 -0
- package/pkg/dist/core/export-html/tool-renderer.d.ts +38 -0
- package/pkg/dist/core/export-html/tool-renderer.d.ts.map +1 -0
- package/pkg/dist/core/export-html/tool-renderer.js +70 -0
- package/pkg/dist/core/export-html/tool-renderer.js.map +1 -0
- package/pkg/dist/core/export-html/vendor/highlight.min.js +1213 -0
- package/pkg/dist/core/export-html/vendor/marked.min.js +6 -0
- package/scripts/postinstall.js +30 -17
- package/src/resources/extensions/bg-shell/index.ts +51 -7
- package/src/resources/extensions/gsd/activity-log.ts +61 -14
- package/src/resources/extensions/gsd/auto.ts +288 -19
- package/src/resources/extensions/gsd/commands.ts +9 -3
- package/src/resources/extensions/gsd/dashboard-overlay.ts +55 -12
- package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -0
- package/src/resources/extensions/gsd/doctor.ts +60 -3
- package/src/resources/extensions/gsd/files.ts +45 -1
- package/src/resources/extensions/gsd/git-service.ts +46 -41
- package/src/resources/extensions/gsd/guided-flow.ts +81 -9
- package/src/resources/extensions/gsd/index.ts +62 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +181 -0
- package/src/resources/extensions/gsd/paths.ts +35 -4
- package/src/resources/extensions/gsd/post-unit-hooks.ts +449 -0
- package/src/resources/extensions/gsd/preferences.ts +232 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +45 -3
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -3
- package/src/resources/extensions/gsd/prompts/discuss.md +10 -8
- package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +3 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +4 -2
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/guided-research-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +9 -12
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -3
- package/src/resources/extensions/gsd/prompts/queue.md +3 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/state.ts +130 -18
- package/src/resources/extensions/gsd/templates/context.md +1 -1
- package/src/resources/extensions/gsd/templates/state.md +3 -3
- package/src/resources/extensions/gsd/tests/activity-log-save.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/doctor.test.ts +115 -1
- package/src/resources/extensions/gsd/tests/draft-promotion.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/git-service.test.ts +35 -35
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +8 -8
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/network-error-fallback.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/orphaned-branch.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +297 -0
- package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +226 -0
- package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/worktree.test.ts +19 -19
- package/src/resources/extensions/gsd/types.ts +109 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +72 -13
- package/src/resources/extensions/gsd/worktree.ts +5 -4
- package/src/resources/extensions/search-the-web/command-search-provider.ts +8 -4
- package/src/resources/extensions/search-the-web/native-search.ts +32 -23
- package/src/resources/extensions/search-the-web/provider.ts +19 -2
- package/src/resources/extensions/search-the-web/tool-fetch-page.ts +62 -0
- package/src/resources/extensions/search-the-web/tool-llm-context.ts +62 -3
- package/src/resources/extensions/search-the-web/tool-search.ts +62 -3
- package/src/resources/extensions/shared/bundled-extension-paths.ts +11 -0
- package/src/resources/extensions/subagent/index.ts +2 -1
- package/src/resources/skills/github-workflows/SKILL.md +5 -0
- package/dist/resources/extensions/gsd/git-service.d.ts +0 -225
- package/dist/resources/extensions/gsd/git-service.js +0 -756
- package/dist/resources/extensions/gsd/preferences.d.ts +0 -122
- package/dist/resources/extensions/gsd/preferences.js +0 -616
- package/dist/resources/extensions/gsd/worktree.d.ts +0 -106
- package/dist/resources/extensions/remote-questions/config.d.ts +0 -14
- package/dist/resources/extensions/remote-questions/config.js +0 -68
- package/dist/resources/extensions/remote-questions/discord-adapter.d.ts +0 -17
- package/dist/resources/extensions/remote-questions/discord-adapter.js +0 -118
- package/dist/resources/extensions/remote-questions/format.d.ts +0 -38
- package/dist/resources/extensions/remote-questions/format.js +0 -119
- package/dist/resources/extensions/remote-questions/manager.d.ts +0 -23
- package/dist/resources/extensions/remote-questions/manager.js +0 -161
- package/dist/resources/extensions/remote-questions/remote-command.d.ts +0 -6
- package/dist/resources/extensions/remote-questions/remote-command.js +0 -358
- package/dist/resources/extensions/remote-questions/slack-adapter.d.ts +0 -15
- package/dist/resources/extensions/remote-questions/slack-adapter.js +0 -82
- package/dist/resources/extensions/remote-questions/status.d.ts +0 -9
- package/dist/resources/extensions/remote-questions/status.js +0 -25
- package/dist/resources/extensions/remote-questions/store.d.ts +0 -11
- package/dist/resources/extensions/remote-questions/store.js +0 -66
- package/dist/resources/extensions/remote-questions/types.d.ts +0 -68
- package/dist/resources/extensions/remote-questions/types.js +0 -4
|
@@ -290,6 +290,7 @@ ${chalk.bold("Environment Variables:")}
|
|
|
290
290
|
AI_GATEWAY_API_KEY - Vercel AI Gateway API key
|
|
291
291
|
ZAI_API_KEY - ZAI API key
|
|
292
292
|
MISTRAL_API_KEY - Mistral API key
|
|
293
|
+
OLLAMA_API_KEY - Ollama Cloud API key
|
|
293
294
|
MINIMAX_API_KEY - MiniMax API key
|
|
294
295
|
OPENCODE_API_KEY - OpenCode Zen/OpenCode Go API key
|
|
295
296
|
KIMI_API_KEY - Kimi For Coding API key
|
|
@@ -67,9 +67,9 @@ import {
|
|
|
67
67
|
type TurnEndEvent,
|
|
68
68
|
type TurnStartEvent,
|
|
69
69
|
wrapRegisteredTools,
|
|
70
|
-
wrapToolsWithExtensions,
|
|
71
70
|
} from "./extensions/index.js";
|
|
72
71
|
import type { BashExecutionMessage, CustomMessage } from "./messages.js";
|
|
72
|
+
import { FallbackResolver } from "./fallback-resolver.js";
|
|
73
73
|
import type { ModelRegistry } from "./model-registry.js";
|
|
74
74
|
import { expandPromptTemplate, type PromptTemplate } from "./prompt-templates.js";
|
|
75
75
|
import type { ResourceExtensionPaths, ResourceLoader } from "./resource-loader.js";
|
|
@@ -120,7 +120,10 @@ export type AgentSessionEvent =
|
|
|
120
120
|
errorMessage?: string;
|
|
121
121
|
}
|
|
122
122
|
| { type: "auto_retry_start"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }
|
|
123
|
-
| { type: "auto_retry_end"; success: boolean; attempt: number; finalError?: string }
|
|
123
|
+
| { type: "auto_retry_end"; success: boolean; attempt: number; finalError?: string }
|
|
124
|
+
| { type: "fallback_provider_switch"; from: string; to: string; reason: string }
|
|
125
|
+
| { type: "fallback_provider_restored"; provider: string; reason: string }
|
|
126
|
+
| { type: "fallback_chain_exhausted"; reason: string };
|
|
124
127
|
|
|
125
128
|
/** Listener function for agent session events */
|
|
126
129
|
export type AgentSessionEventListener = (event: AgentSessionEvent) => void;
|
|
@@ -267,6 +270,9 @@ export class AgentSession {
|
|
|
267
270
|
// Model registry for API key resolution
|
|
268
271
|
private _modelRegistry: ModelRegistry;
|
|
269
272
|
|
|
273
|
+
// Provider fallback resolver
|
|
274
|
+
private _fallbackResolver: FallbackResolver;
|
|
275
|
+
|
|
270
276
|
// Tool registry for extension getTools/setTools
|
|
271
277
|
private _toolRegistry: Map<string, AgentTool> = new Map();
|
|
272
278
|
private _toolPromptSnippets: Map<string, string> = new Map();
|
|
@@ -284,6 +290,11 @@ export class AgentSession {
|
|
|
284
290
|
this._customTools = config.customTools ?? [];
|
|
285
291
|
this._cwd = config.cwd;
|
|
286
292
|
this._modelRegistry = config.modelRegistry;
|
|
293
|
+
this._fallbackResolver = new FallbackResolver(
|
|
294
|
+
this.settingsManager,
|
|
295
|
+
this._modelRegistry.authStorage,
|
|
296
|
+
this._modelRegistry,
|
|
297
|
+
);
|
|
287
298
|
this._extensionRunnerRef = config.extensionRunnerRef;
|
|
288
299
|
this._initialActiveToolNames = config.initialActiveToolNames;
|
|
289
300
|
this._baseToolsOverride = config.baseToolsOverride;
|
|
@@ -292,6 +303,11 @@ export class AgentSession {
|
|
|
292
303
|
// (session persistence, extensions, auto-compaction, retry logic)
|
|
293
304
|
this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);
|
|
294
305
|
|
|
306
|
+
// Install tool hooks that await the event queue before emitting extension events.
|
|
307
|
+
// This ensures extensions always see settled state (e.g., assistant message appended)
|
|
308
|
+
// even when tools execute in parallel.
|
|
309
|
+
this._installAgentToolHooks();
|
|
310
|
+
|
|
295
311
|
this._buildRuntime({
|
|
296
312
|
activeToolNames: this._initialActiveToolNames,
|
|
297
313
|
includeAllExtensionTools: true,
|
|
@@ -303,6 +319,11 @@ export class AgentSession {
|
|
|
303
319
|
return this._modelRegistry;
|
|
304
320
|
}
|
|
305
321
|
|
|
322
|
+
/** Fallback resolver for cross-provider fallback */
|
|
323
|
+
get fallbackResolver(): FallbackResolver {
|
|
324
|
+
return this._fallbackResolver;
|
|
325
|
+
}
|
|
326
|
+
|
|
306
327
|
// =========================================================================
|
|
307
328
|
// Event Subscription
|
|
308
329
|
// =========================================================================
|
|
@@ -460,6 +481,73 @@ export class AgentSession {
|
|
|
460
481
|
}
|
|
461
482
|
}
|
|
462
483
|
|
|
484
|
+
/**
|
|
485
|
+
* Install beforeToolCall/afterToolCall hooks on the Agent.
|
|
486
|
+
*
|
|
487
|
+
* These hooks await `_agentEventQueue` before emitting extension events,
|
|
488
|
+
* ensuring that all prior events (including `message_end` which appends
|
|
489
|
+
* the assistant message) have fully settled. This prevents a race condition
|
|
490
|
+
* in parallel tool execution where extension `tool_call` handlers could
|
|
491
|
+
* see stale agent state.
|
|
492
|
+
*/
|
|
493
|
+
private _installAgentToolHooks(): void {
|
|
494
|
+
this.agent.setBeforeToolCall(async ({ toolCall, args }) => {
|
|
495
|
+
// Wait for all queued agent events to settle before emitting to extensions
|
|
496
|
+
await this._agentEventQueue;
|
|
497
|
+
|
|
498
|
+
if (!this._extensionRunner?.hasHandlers("tool_call")) return undefined;
|
|
499
|
+
|
|
500
|
+
try {
|
|
501
|
+
const callResult = await this._extensionRunner.emitToolCall({
|
|
502
|
+
type: "tool_call",
|
|
503
|
+
toolName: toolCall.name,
|
|
504
|
+
toolCallId: toolCall.id,
|
|
505
|
+
input: args as Record<string, unknown>,
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
if (callResult?.block) {
|
|
509
|
+
return {
|
|
510
|
+
block: true,
|
|
511
|
+
reason: callResult.reason || "Tool execution was blocked by an extension",
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
} catch (err) {
|
|
515
|
+
if (err instanceof Error) {
|
|
516
|
+
return { block: true, reason: err.message };
|
|
517
|
+
}
|
|
518
|
+
return { block: true, reason: `Extension failed, blocking execution: ${String(err)}` };
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
return undefined;
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
this.agent.setAfterToolCall(async ({ toolCall, args, result, isError }) => {
|
|
525
|
+
// Wait for all queued agent events to settle
|
|
526
|
+
await this._agentEventQueue;
|
|
527
|
+
|
|
528
|
+
if (!this._extensionRunner?.hasHandlers("tool_result")) return undefined;
|
|
529
|
+
|
|
530
|
+
const resultResult = await this._extensionRunner.emitToolResult({
|
|
531
|
+
type: "tool_result",
|
|
532
|
+
toolName: toolCall.name,
|
|
533
|
+
toolCallId: toolCall.id,
|
|
534
|
+
input: args as Record<string, unknown>,
|
|
535
|
+
content: result.content,
|
|
536
|
+
details: result.details,
|
|
537
|
+
isError,
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
if (resultResult) {
|
|
541
|
+
return {
|
|
542
|
+
content: resultResult.content ?? undefined,
|
|
543
|
+
details: resultResult.details ?? undefined,
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
return undefined;
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
|
|
463
551
|
/** Extract text content from a message */
|
|
464
552
|
private _getUserMessageText(message: Message): string {
|
|
465
553
|
if (message.role !== "user") return "";
|
|
@@ -868,6 +956,19 @@ export class AgentSession {
|
|
|
868
956
|
);
|
|
869
957
|
}
|
|
870
958
|
|
|
959
|
+
// Check if a higher-priority provider in the fallback chain has recovered
|
|
960
|
+
const restoration = await this._fallbackResolver.checkForRestoration(this.model);
|
|
961
|
+
if (restoration) {
|
|
962
|
+
const previousProvider = `${this.model.provider}/${this.model.id}`;
|
|
963
|
+
this.agent.setModel(restoration.model);
|
|
964
|
+
this.sessionManager.appendModelChange(restoration.model.provider, restoration.model.id);
|
|
965
|
+
this._emit({
|
|
966
|
+
type: "fallback_provider_restored",
|
|
967
|
+
provider: `${restoration.model.provider}/${restoration.model.id}`,
|
|
968
|
+
reason: `Restored from ${previousProvider}`,
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
|
|
871
972
|
// Validate API key
|
|
872
973
|
const apiKey = await this._modelRegistry.getApiKey(this.model, this.sessionId);
|
|
873
974
|
if (!apiKey) {
|
|
@@ -2151,12 +2252,10 @@ export class AgentSession {
|
|
|
2151
2252
|
toolRegistry.set(tool.name, tool);
|
|
2152
2253
|
}
|
|
2153
2254
|
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
this._toolRegistry = toolRegistry;
|
|
2159
|
-
}
|
|
2255
|
+
// Tool interception (tool_call/tool_result extension events) is handled by
|
|
2256
|
+
// beforeToolCall/afterToolCall hooks installed in _installAgentToolHooks(),
|
|
2257
|
+
// which await _agentEventQueue for safe parallel execution.
|
|
2258
|
+
this._toolRegistry = toolRegistry;
|
|
2160
2259
|
|
|
2161
2260
|
const nextActiveToolNames = options?.activeToolNames
|
|
2162
2261
|
? [...options.activeToolNames]
|
|
@@ -2354,20 +2453,66 @@ export class AgentSession {
|
|
|
2354
2453
|
return true;
|
|
2355
2454
|
}
|
|
2356
2455
|
|
|
2357
|
-
// All credentials are backed off.
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2456
|
+
// All credentials are backed off. Try cross-provider fallback before giving up.
|
|
2457
|
+
if (isCredentialError) {
|
|
2458
|
+
const fallbackResult = await this._fallbackResolver.findFallback(
|
|
2459
|
+
this.model,
|
|
2460
|
+
errorType,
|
|
2461
|
+
);
|
|
2462
|
+
|
|
2463
|
+
if (fallbackResult) {
|
|
2464
|
+
// Swap to fallback model — don't persist to settings
|
|
2465
|
+
const previousProvider = this.model.provider;
|
|
2466
|
+
this.agent.setModel(fallbackResult.model);
|
|
2467
|
+
this.sessionManager.appendModelChange(fallbackResult.model.provider, fallbackResult.model.id);
|
|
2468
|
+
|
|
2469
|
+
// Remove error message from agent state
|
|
2470
|
+
const msgs = this.agent.state.messages;
|
|
2471
|
+
if (msgs.length > 0 && msgs[msgs.length - 1].role === "assistant") {
|
|
2472
|
+
this.agent.replaceMessages(msgs.slice(0, -1));
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
this._emit({
|
|
2476
|
+
type: "fallback_provider_switch",
|
|
2477
|
+
from: `${previousProvider}/${this.model?.id}`,
|
|
2478
|
+
to: `${fallbackResult.model.provider}/${fallbackResult.model.id}`,
|
|
2479
|
+
reason: fallbackResult.reason,
|
|
2480
|
+
});
|
|
2481
|
+
|
|
2482
|
+
this._emit({
|
|
2483
|
+
type: "auto_retry_start",
|
|
2484
|
+
attempt: this._retryAttempt + 1,
|
|
2485
|
+
maxAttempts: settings.maxRetries,
|
|
2486
|
+
delayMs: 0,
|
|
2487
|
+
errorMessage: `${message.errorMessage} (${fallbackResult.reason})`,
|
|
2488
|
+
});
|
|
2489
|
+
|
|
2490
|
+
// Retry immediately with fallback provider - don't increment _retryAttempt
|
|
2491
|
+
setTimeout(() => {
|
|
2492
|
+
this.agent.continue().catch(() => {
|
|
2493
|
+
// Retry failed - will be caught by next agent_end
|
|
2494
|
+
});
|
|
2495
|
+
}, 0);
|
|
2496
|
+
|
|
2497
|
+
return true;
|
|
2498
|
+
}
|
|
2499
|
+
|
|
2500
|
+
// No fallback available either
|
|
2501
|
+
if (errorType === "quota_exhausted") {
|
|
2502
|
+
this._emit({
|
|
2503
|
+
type: "fallback_chain_exhausted",
|
|
2504
|
+
reason: `All providers exhausted for ${this.model.provider}/${this.model.id}`,
|
|
2505
|
+
});
|
|
2506
|
+
this._emit({
|
|
2507
|
+
type: "auto_retry_end",
|
|
2508
|
+
success: false,
|
|
2509
|
+
attempt: this._retryAttempt,
|
|
2510
|
+
finalError: message.errorMessage,
|
|
2511
|
+
});
|
|
2512
|
+
this._retryAttempt = 0;
|
|
2513
|
+
this._resolveRetry();
|
|
2514
|
+
return false;
|
|
2515
|
+
}
|
|
2371
2516
|
}
|
|
2372
2517
|
}
|
|
2373
2518
|
|
|
@@ -248,6 +248,13 @@ export class AuthStorage {
|
|
|
248
248
|
*/
|
|
249
249
|
private credentialBackoff: Map<string, Map<number, number>> = new Map();
|
|
250
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Provider-level backoff tracking.
|
|
253
|
+
* Set when all credentials for a provider are backed off.
|
|
254
|
+
* Map<provider, backoffExpiresAt>
|
|
255
|
+
*/
|
|
256
|
+
private providerBackoff: Map<string, number> = new Map();
|
|
257
|
+
|
|
251
258
|
private constructor(private storage: AuthStorageBackend) {
|
|
252
259
|
this.reload();
|
|
253
260
|
}
|
|
@@ -398,6 +405,7 @@ export class AuthStorage {
|
|
|
398
405
|
delete this.data[provider];
|
|
399
406
|
this.providerRoundRobinIndex.delete(provider);
|
|
400
407
|
this.credentialBackoff.delete(provider);
|
|
408
|
+
this.providerBackoff.delete(provider);
|
|
401
409
|
this.persistProviderChange(provider, undefined);
|
|
402
410
|
}
|
|
403
411
|
|
|
@@ -484,6 +492,43 @@ export class AuthStorage {
|
|
|
484
492
|
return true;
|
|
485
493
|
}
|
|
486
494
|
|
|
495
|
+
/**
|
|
496
|
+
* Mark an entire provider as exhausted.
|
|
497
|
+
* Called when all credentials for a provider are backed off.
|
|
498
|
+
*/
|
|
499
|
+
markProviderExhausted(provider: string, errorType: UsageLimitErrorType): void {
|
|
500
|
+
const backoffMs = getBackoffDuration(errorType);
|
|
501
|
+
this.providerBackoff.set(provider, Date.now() + backoffMs);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Check if a provider is currently available (not backed off at provider level).
|
|
506
|
+
*/
|
|
507
|
+
isProviderAvailable(provider: string): boolean {
|
|
508
|
+
const expiresAt = this.providerBackoff.get(provider);
|
|
509
|
+
if (expiresAt === undefined) return true;
|
|
510
|
+
if (Date.now() >= expiresAt) {
|
|
511
|
+
this.providerBackoff.delete(provider);
|
|
512
|
+
return true;
|
|
513
|
+
}
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Get milliseconds remaining until provider backoff expires.
|
|
519
|
+
* Returns 0 if provider is available.
|
|
520
|
+
*/
|
|
521
|
+
getProviderBackoffRemaining(provider: string): number {
|
|
522
|
+
const expiresAt = this.providerBackoff.get(provider);
|
|
523
|
+
if (expiresAt === undefined) return 0;
|
|
524
|
+
const remaining = expiresAt - Date.now();
|
|
525
|
+
if (remaining <= 0) {
|
|
526
|
+
this.providerBackoff.delete(provider);
|
|
527
|
+
return 0;
|
|
528
|
+
}
|
|
529
|
+
return remaining;
|
|
530
|
+
}
|
|
531
|
+
|
|
487
532
|
/**
|
|
488
533
|
* Check if a credential index is currently backed off.
|
|
489
534
|
*/
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
// GSD Provider Fallback Resolver Tests
|
|
2
|
+
// Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
3
|
+
|
|
4
|
+
import { describe, it, beforeEach, mock } from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { FallbackResolver } from "./fallback-resolver.js";
|
|
7
|
+
import type { Api, Model } from "@gsd/pi-ai";
|
|
8
|
+
import type { AuthStorage } from "./auth-storage.js";
|
|
9
|
+
import type { ModelRegistry } from "./model-registry.js";
|
|
10
|
+
import type { FallbackChainEntry, SettingsManager } from "./settings-manager.js";
|
|
11
|
+
|
|
12
|
+
function createMockModel(provider: string, id: string): Model<Api> {
|
|
13
|
+
return {
|
|
14
|
+
id,
|
|
15
|
+
name: id,
|
|
16
|
+
api: "openai-completions" as Api,
|
|
17
|
+
provider,
|
|
18
|
+
baseUrl: `https://api.${provider}.com`,
|
|
19
|
+
reasoning: false,
|
|
20
|
+
input: ["text"],
|
|
21
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
22
|
+
contextWindow: 128000,
|
|
23
|
+
maxTokens: 16384,
|
|
24
|
+
} as Model<Api>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const zaiModel = createMockModel("zai", "glm-5");
|
|
28
|
+
const alibabaModel = createMockModel("alibaba", "glm-5");
|
|
29
|
+
const openaiModel = createMockModel("openai", "gpt-4.1");
|
|
30
|
+
|
|
31
|
+
const defaultChain: FallbackChainEntry[] = [
|
|
32
|
+
{ provider: "zai", model: "glm-5", priority: 1 },
|
|
33
|
+
{ provider: "alibaba", model: "glm-5", priority: 2 },
|
|
34
|
+
{ provider: "openai", model: "gpt-4.1", priority: 3 },
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
function createResolver(overrides?: {
|
|
38
|
+
enabled?: boolean;
|
|
39
|
+
isProviderAvailable?: (provider: string) => boolean;
|
|
40
|
+
hasAuth?: (provider: string) => boolean;
|
|
41
|
+
find?: (provider: string, modelId: string) => Model<Api> | undefined;
|
|
42
|
+
}) {
|
|
43
|
+
const settingsManager = {
|
|
44
|
+
getFallbackSettings: () => ({
|
|
45
|
+
enabled: overrides?.enabled ?? true,
|
|
46
|
+
chains: { coding: defaultChain },
|
|
47
|
+
}),
|
|
48
|
+
} as unknown as SettingsManager;
|
|
49
|
+
|
|
50
|
+
const authStorage = {
|
|
51
|
+
markProviderExhausted: mock.fn(),
|
|
52
|
+
isProviderAvailable: overrides?.isProviderAvailable ?? (() => true),
|
|
53
|
+
hasAuth: overrides?.hasAuth ?? (() => true),
|
|
54
|
+
} as unknown as AuthStorage;
|
|
55
|
+
|
|
56
|
+
const modelRegistry = {
|
|
57
|
+
find: overrides?.find ?? ((provider: string, modelId: string) => {
|
|
58
|
+
if (provider === "zai" && modelId === "glm-5") return zaiModel;
|
|
59
|
+
if (provider === "alibaba" && modelId === "glm-5") return alibabaModel;
|
|
60
|
+
if (provider === "openai" && modelId === "gpt-4.1") return openaiModel;
|
|
61
|
+
return undefined;
|
|
62
|
+
}),
|
|
63
|
+
} as unknown as ModelRegistry;
|
|
64
|
+
|
|
65
|
+
return { resolver: new FallbackResolver(settingsManager, authStorage, modelRegistry), authStorage };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ─── findFallback ────────────────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
describe("FallbackResolver — findFallback", () => {
|
|
71
|
+
it("returns next available provider when current fails", async () => {
|
|
72
|
+
const { resolver } = createResolver();
|
|
73
|
+
const result = await resolver.findFallback(zaiModel, "quota_exhausted");
|
|
74
|
+
|
|
75
|
+
assert.notEqual(result, null);
|
|
76
|
+
assert.equal(result!.model.provider, "alibaba");
|
|
77
|
+
assert.equal(result!.model.id, "glm-5");
|
|
78
|
+
assert.equal(result!.chainName, "coding");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("marks current provider as exhausted", async () => {
|
|
82
|
+
const { resolver, authStorage } = createResolver();
|
|
83
|
+
await resolver.findFallback(zaiModel, "rate_limit");
|
|
84
|
+
|
|
85
|
+
const fn = authStorage.markProviderExhausted as any;
|
|
86
|
+
assert.equal(fn.mock.calls.length, 1);
|
|
87
|
+
assert.equal(fn.mock.calls[0].arguments[0], "zai");
|
|
88
|
+
assert.equal(fn.mock.calls[0].arguments[1], "rate_limit");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("skips backed-off providers", async () => {
|
|
92
|
+
const { resolver } = createResolver({
|
|
93
|
+
isProviderAvailable: (provider: string) => provider !== "alibaba",
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const result = await resolver.findFallback(zaiModel, "quota_exhausted");
|
|
97
|
+
|
|
98
|
+
assert.notEqual(result, null);
|
|
99
|
+
assert.equal(result!.model.provider, "openai");
|
|
100
|
+
assert.equal(result!.model.id, "gpt-4.1");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("returns null when all providers are backed off", async () => {
|
|
104
|
+
const { resolver } = createResolver({
|
|
105
|
+
isProviderAvailable: () => false,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const result = await resolver.findFallback(zaiModel, "quota_exhausted");
|
|
109
|
+
assert.equal(result, null);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("returns null when fallback is disabled", async () => {
|
|
113
|
+
const { resolver } = createResolver({ enabled: false });
|
|
114
|
+
const result = await resolver.findFallback(zaiModel, "quota_exhausted");
|
|
115
|
+
assert.equal(result, null);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("returns null when model is not in any chain", async () => {
|
|
119
|
+
const { resolver } = createResolver();
|
|
120
|
+
const unknownModel = createMockModel("unknown", "some-model");
|
|
121
|
+
const result = await resolver.findFallback(unknownModel, "quota_exhausted");
|
|
122
|
+
assert.equal(result, null);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("skips providers without auth", async () => {
|
|
126
|
+
const { resolver } = createResolver({
|
|
127
|
+
hasAuth: (provider: string) => provider !== "alibaba",
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const result = await resolver.findFallback(zaiModel, "quota_exhausted");
|
|
131
|
+
|
|
132
|
+
assert.notEqual(result, null);
|
|
133
|
+
assert.equal(result!.model.provider, "openai");
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("skips providers with no model in registry", async () => {
|
|
137
|
+
const { resolver } = createResolver({
|
|
138
|
+
find: (provider: string, modelId: string) => {
|
|
139
|
+
if (provider === "alibaba") return undefined;
|
|
140
|
+
if (provider === "openai" && modelId === "gpt-4.1") return openaiModel;
|
|
141
|
+
return undefined;
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const result = await resolver.findFallback(zaiModel, "quota_exhausted");
|
|
146
|
+
|
|
147
|
+
assert.notEqual(result, null);
|
|
148
|
+
assert.equal(result!.model.provider, "openai");
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// ─── checkForRestoration ─────────────────────────────────────────────────────
|
|
153
|
+
|
|
154
|
+
describe("FallbackResolver — checkForRestoration", () => {
|
|
155
|
+
it("returns higher-priority provider when recovered", async () => {
|
|
156
|
+
const { resolver } = createResolver();
|
|
157
|
+
const result = await resolver.checkForRestoration(alibabaModel);
|
|
158
|
+
|
|
159
|
+
assert.notEqual(result, null);
|
|
160
|
+
assert.equal(result!.model.provider, "zai");
|
|
161
|
+
assert.equal(result!.model.id, "glm-5");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("returns null when already at highest priority", async () => {
|
|
165
|
+
const { resolver } = createResolver();
|
|
166
|
+
const result = await resolver.checkForRestoration(zaiModel);
|
|
167
|
+
assert.equal(result, null);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("returns null when higher-priority provider is still backed off", async () => {
|
|
171
|
+
const { resolver } = createResolver({
|
|
172
|
+
isProviderAvailable: (provider: string) => provider !== "zai",
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const result = await resolver.checkForRestoration(alibabaModel);
|
|
176
|
+
assert.equal(result, null);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("returns null when fallback is disabled", async () => {
|
|
180
|
+
const { resolver } = createResolver({ enabled: false });
|
|
181
|
+
const result = await resolver.checkForRestoration(alibabaModel);
|
|
182
|
+
assert.equal(result, null);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// ─── getBestAvailable ────────────────────────────────────────────────────────
|
|
187
|
+
|
|
188
|
+
describe("FallbackResolver — getBestAvailable", () => {
|
|
189
|
+
it("returns highest-priority available provider", async () => {
|
|
190
|
+
const { resolver } = createResolver();
|
|
191
|
+
const result = await resolver.getBestAvailable("coding");
|
|
192
|
+
|
|
193
|
+
assert.notEqual(result, null);
|
|
194
|
+
assert.equal(result!.model.provider, "zai");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("skips backed-off providers", async () => {
|
|
198
|
+
const { resolver } = createResolver({
|
|
199
|
+
isProviderAvailable: (provider: string) => provider !== "zai",
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const result = await resolver.getBestAvailable("coding");
|
|
203
|
+
|
|
204
|
+
assert.notEqual(result, null);
|
|
205
|
+
assert.equal(result!.model.provider, "alibaba");
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("returns null for unknown chain", async () => {
|
|
209
|
+
const { resolver } = createResolver();
|
|
210
|
+
const result = await resolver.getBestAvailable("nonexistent");
|
|
211
|
+
assert.equal(result, null);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// ─── findChainsForModel ──────────────────────────────────────────────────────
|
|
216
|
+
|
|
217
|
+
describe("FallbackResolver — findChainsForModel", () => {
|
|
218
|
+
it("finds chains containing a model", () => {
|
|
219
|
+
const { resolver } = createResolver();
|
|
220
|
+
const chains = resolver.findChainsForModel("zai", "glm-5");
|
|
221
|
+
assert.deepEqual(chains, ["coding"]);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("returns empty array for model not in any chain", () => {
|
|
225
|
+
const { resolver } = createResolver();
|
|
226
|
+
const chains = resolver.findChainsForModel("unknown", "model");
|
|
227
|
+
assert.deepEqual(chains, []);
|
|
228
|
+
});
|
|
229
|
+
});
|