gsd-pi 2.76.0-dev.4100bd590 → 2.76.0-dev.479ad0e78
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/claude-cli-check.js +32 -3
- package/dist/mcp-server.d.ts +7 -0
- package/dist/mcp-server.js +35 -1
- package/dist/onboarding.js +45 -0
- package/dist/resource-loader.d.ts +1 -1
- package/dist/resource-loader.js +2 -8
- package/dist/resources/extensions/claude-code-cli/readiness.js +4 -3
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
- package/dist/resources/extensions/gsd/auto/loop.js +9 -0
- package/dist/resources/extensions/gsd/auto/phases.js +58 -5
- package/dist/resources/extensions/gsd/auto/run-unit.js +38 -2
- package/dist/resources/extensions/gsd/auto/session.js +22 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +14 -3
- package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +32 -1
- package/dist/resources/extensions/gsd/auto-start.js +58 -57
- package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
- package/dist/resources/extensions/gsd/auto.js +70 -28
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +52 -6
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
- package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
- package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
- package/dist/resources/extensions/gsd/error-classifier.js +10 -3
- package/dist/resources/extensions/gsd/exec-history.js +120 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
- package/dist/resources/extensions/gsd/gitignore.js +1 -0
- package/dist/resources/extensions/gsd/gsd-db.js +149 -31
- package/dist/resources/extensions/gsd/guided-flow.js +190 -1
- package/dist/resources/extensions/gsd/health-widget.js +4 -1
- package/dist/resources/extensions/gsd/init-wizard.js +15 -1
- package/dist/resources/extensions/gsd/key-manager.js +28 -0
- package/dist/resources/extensions/gsd/model-router.js +36 -3
- package/dist/resources/extensions/gsd/pre-execution-checks.js +44 -9
- package/dist/resources/extensions/gsd/preferences-types.js +9 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
- package/dist/resources/extensions/gsd/preferences.js +17 -17
- package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
- package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
- package/dist/resources/extensions/gsd/token-counter.js +22 -5
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
- package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
- package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
- package/dist/resources/skills/verify-before-complete/SKILL.md +2 -1
- package/dist/resources/skills/write-docs/SKILL.md +2 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
- 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/required-server-files.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- 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/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 +17 -17
- package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/server.js +1 -1
- package/dist/welcome-screen.js +6 -1
- package/dist/wizard.js +2 -0
- package/package.json +1 -1
- package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
- package/packages/mcp-server/dist/remote-questions.js +732 -0
- package/packages/mcp-server/dist/remote-questions.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts +7 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +70 -8
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/session-manager.d.ts +14 -0
- package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
- package/packages/mcp-server/dist/session-manager.js +49 -1
- package/packages/mcp-server/dist/session-manager.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +64 -25
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -1
- package/packages/mcp-server/src/mcp-server.test.ts +67 -0
- package/packages/mcp-server/src/remote-questions.test.ts +294 -0
- package/packages/mcp-server/src/remote-questions.ts +916 -0
- package/packages/mcp-server/src/server.ts +89 -14
- package/packages/mcp-server/src/session-manager.ts +43 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
- package/packages/mcp-server/src/workflow-tools.ts +84 -43
- package/packages/mcp-server/tsconfig.test.json +19 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/models/custom.d.ts +38 -0
- package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/custom.js +41 -0
- package/packages/pi-ai/dist/models/custom.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +8 -3
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +16 -1
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
- package/packages/pi-ai/src/models/custom.ts +42 -0
- package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
- package/packages/pi-ai/src/providers/anthropic.ts +9 -3
- package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
- package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
- package/packages/pi-ai/src/providers/simple-options.ts +17 -1
- package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
- package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -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 +7 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -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-discovery.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
- package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -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 +90 -10
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +10 -6
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +45 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.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 +13 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +3 -2
- package/packages/pi-coding-agent/src/core/agent-session.ts +11 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +2 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
- package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
- package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
- package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
- package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +102 -10
- package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
- package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -1
- package/packages/pi-coding-agent/src/core/session-manager.ts +10 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/scripts/link-workspace-packages.cjs +1 -0
- package/src/resources/extensions/claude-code-cli/readiness.ts +4 -3
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
- package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -0
- package/src/resources/extensions/gsd/auto/loop.ts +9 -0
- package/src/resources/extensions/gsd/auto/phases.ts +82 -4
- package/src/resources/extensions/gsd/auto/run-unit.ts +40 -2
- package/src/resources/extensions/gsd/auto/session.ts +35 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
- package/src/resources/extensions/gsd/auto-model-selection.ts +17 -2
- package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +26 -1
- package/src/resources/extensions/gsd/auto-start.ts +60 -68
- package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
- package/src/resources/extensions/gsd/auto.ts +73 -28
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +23 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +54 -6
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
- package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
- package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
- package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
- package/src/resources/extensions/gsd/error-classifier.ts +10 -3
- package/src/resources/extensions/gsd/exec-history.ts +153 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
- package/src/resources/extensions/gsd/gitignore.ts +1 -1
- package/src/resources/extensions/gsd/gsd-db.ts +157 -33
- package/src/resources/extensions/gsd/guided-flow.ts +222 -1
- package/src/resources/extensions/gsd/health-widget.ts +3 -1
- package/src/resources/extensions/gsd/init-wizard.ts +15 -1
- package/src/resources/extensions/gsd/journal.ts +2 -1
- package/src/resources/extensions/gsd/key-manager.ts +28 -0
- package/src/resources/extensions/gsd/model-router.ts +42 -1
- package/src/resources/extensions/gsd/pre-execution-checks.ts +46 -10
- package/src/resources/extensions/gsd/preferences-types.ts +46 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
- package/src/resources/extensions/gsd/preferences.ts +17 -17
- package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
- package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +188 -2
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +237 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +447 -1
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +356 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
- package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
- package/src/resources/extensions/gsd/token-counter.ts +22 -5
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
- package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
- package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
- package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
- package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
- package/src/resources/skills/verify-before-complete/SKILL.md +2 -1
- package/src/resources/skills/write-docs/SKILL.md +2 -1
- /package/dist/web/standalone/.next/static/{YnUwu2WWaT0_hyTLUF4nq → JgU2F-5N9mTyB7kUSSk9A}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{YnUwu2WWaT0_hyTLUF4nq → JgU2F-5N9mTyB7kUSSk9A}/_ssgManifest.js +0 -0
|
@@ -14,8 +14,9 @@ describe("#4243 — abort() must be called before _disconnectFromAgent()", () =>
|
|
|
14
14
|
const newSessionStart = source.indexOf("async newSession(options?:");
|
|
15
15
|
assert.ok(newSessionStart >= 0, "should find newSession method");
|
|
16
16
|
|
|
17
|
-
// Get a window that includes the abort/disconnect section
|
|
18
|
-
|
|
17
|
+
// Get a window that includes the abort/disconnect section.
|
|
18
|
+
// Use 2000 chars to accommodate guard checks inserted between the two calls.
|
|
19
|
+
const window = source.slice(newSessionStart, newSessionStart + 2000);
|
|
19
20
|
|
|
20
21
|
// Find the abort and _disconnectFromAgent calls
|
|
21
22
|
const abortIdx = window.indexOf("await this.abort();");
|
|
@@ -1568,6 +1568,8 @@ export class AgentSession {
|
|
|
1568
1568
|
async newSession(options?: {
|
|
1569
1569
|
parentSession?: string;
|
|
1570
1570
|
setup?: (sessionManager: SessionManager) => Promise<void>;
|
|
1571
|
+
/** See ExtensionCommandContext.newSession for docs (#3731). */
|
|
1572
|
+
abortSignal?: AbortSignal;
|
|
1571
1573
|
}): Promise<boolean> {
|
|
1572
1574
|
const previousSessionFile = this.sessionFile;
|
|
1573
1575
|
|
|
@@ -1587,6 +1589,15 @@ export class AgentSession {
|
|
|
1587
1589
|
// message_end/agent_end events fire and the #4216 finalization code
|
|
1588
1590
|
// can run before we unsubscribe from the event bus.
|
|
1589
1591
|
await this.abort();
|
|
1592
|
+
|
|
1593
|
+
// #3731: If the caller aborted (e.g. runUnit() timed out and restored cwd to
|
|
1594
|
+
// project root), discard this session before capturing process.cwd() and
|
|
1595
|
+
// rebuilding the tool runtime. Without this check, the late newSession()
|
|
1596
|
+
// would rebuild tools with root cwd, breaking worktree isolation.
|
|
1597
|
+
if (options?.abortSignal?.aborted) {
|
|
1598
|
+
return false;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1590
1601
|
this._disconnectFromAgent();
|
|
1591
1602
|
this.agent.reset();
|
|
1592
1603
|
// Update cwd to current process directory — auto-mode may have chdir'd
|
|
@@ -164,6 +164,8 @@ export type ExtensionErrorListener = (error: ExtensionError) => void;
|
|
|
164
164
|
export type NewSessionHandler = (options?: {
|
|
165
165
|
parentSession?: string;
|
|
166
166
|
setup?: (sessionManager: SessionManager) => Promise<void>;
|
|
167
|
+
/** See ExtensionCommandContext.newSession for docs (#3731). */
|
|
168
|
+
abortSignal?: AbortSignal;
|
|
167
169
|
}) => Promise<{ cancelled: boolean }>;
|
|
168
170
|
|
|
169
171
|
export type ForkHandler = (entryId: string) => Promise<{ cancelled: boolean }>;
|
|
@@ -303,6 +303,11 @@ export interface ExtensionCommandContext extends ExtensionContext {
|
|
|
303
303
|
newSession(options?: {
|
|
304
304
|
parentSession?: string;
|
|
305
305
|
setup?: (sessionManager: SessionManager) => Promise<void>;
|
|
306
|
+
/** When aborted before the session is fully configured, newSession() returns
|
|
307
|
+
* early without rebuilding the tool runtime. Used by runUnit() to discard
|
|
308
|
+
* a late-resolving newSession() after the session-creation timeout fires,
|
|
309
|
+
* preventing the tool runtime from being rebuilt with the wrong cwd (#3731). */
|
|
310
|
+
abortSignal?: AbortSignal;
|
|
306
311
|
}): Promise<{ cancelled: boolean }>;
|
|
307
312
|
|
|
308
313
|
/** Fork from a specific entry, creating a new session file. */
|
|
@@ -1747,6 +1752,8 @@ export interface ExtensionCommandContextActions {
|
|
|
1747
1752
|
newSession: (options?: {
|
|
1748
1753
|
parentSession?: string;
|
|
1749
1754
|
setup?: (sessionManager: SessionManager) => Promise<void>;
|
|
1755
|
+
/** See ExtensionCommandContext.newSession for docs (#3731). */
|
|
1756
|
+
abortSignal?: AbortSignal;
|
|
1750
1757
|
}) => Promise<{ cancelled: boolean }>;
|
|
1751
1758
|
fork: (entryId: string) => Promise<{ cancelled: boolean }>;
|
|
1752
1759
|
navigateTree: (
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
getDefaultTTL,
|
|
6
6
|
getDiscoverableProviders,
|
|
7
7
|
getDiscoveryAdapter,
|
|
8
|
+
supportsDiscoveryForApi,
|
|
8
9
|
} from "./model-discovery.js";
|
|
9
10
|
|
|
10
11
|
// ─── getDiscoveryAdapter ─────────────────────────────────────────────────────
|
|
@@ -52,6 +53,12 @@ describe("getDiscoveryAdapter", () => {
|
|
|
52
53
|
assert.equal(adapter.supportsDiscovery, false);
|
|
53
54
|
});
|
|
54
55
|
|
|
56
|
+
it("returns OpenAI-style adapter for unknown provider with OpenAI-compatible API", () => {
|
|
57
|
+
const adapter = getDiscoveryAdapter("my-proxy", ["openai-completions"]);
|
|
58
|
+
assert.equal(adapter.provider, "my-proxy");
|
|
59
|
+
assert.equal(adapter.supportsDiscovery, true);
|
|
60
|
+
});
|
|
61
|
+
|
|
55
62
|
it("static adapter fetchModels returns empty array", async () => {
|
|
56
63
|
const adapter = getDiscoveryAdapter("anthropic");
|
|
57
64
|
const models = await adapter.fetchModels("key");
|
|
@@ -123,3 +130,15 @@ describe("DISCOVERY_TTLS", () => {
|
|
|
123
130
|
}
|
|
124
131
|
});
|
|
125
132
|
});
|
|
133
|
+
|
|
134
|
+
describe("supportsDiscoveryForApi", () => {
|
|
135
|
+
it("returns true for OpenAI-compatible APIs", () => {
|
|
136
|
+
assert.equal(supportsDiscoveryForApi("openai-completions"), true);
|
|
137
|
+
assert.equal(supportsDiscoveryForApi("openai-responses"), true);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("returns false for non-discoverable APIs", () => {
|
|
141
|
+
assert.equal(supportsDiscoveryForApi("anthropic-messages"), false);
|
|
142
|
+
assert.equal(supportsDiscoveryForApi(undefined), false);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -26,6 +26,14 @@ export interface ProviderDiscoveryAdapter {
|
|
|
26
26
|
fetchModels(apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]>;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
export const OPENAI_COMPAT_DISCOVERY_APIS = new Set([
|
|
30
|
+
"openai",
|
|
31
|
+
"openai-completions",
|
|
32
|
+
"openai-responses",
|
|
33
|
+
"openai-codex-responses",
|
|
34
|
+
"azure-openai-responses",
|
|
35
|
+
]);
|
|
36
|
+
|
|
29
37
|
/** Per-provider TTLs in milliseconds */
|
|
30
38
|
export const DISCOVERY_TTLS: Record<string, number> = {
|
|
31
39
|
ollama: 5 * 60 * 1000, // 5 minutes (local, models change often)
|
|
@@ -53,10 +61,77 @@ async function fetchWithTimeout(url: string, options: RequestInit = {}, timeoutM
|
|
|
53
61
|
|
|
54
62
|
const OPENAI_EXCLUDED_PREFIXES = ["embedding", "tts", "dall-e", "whisper", "text-embedding", "davinci", "babbage"];
|
|
55
63
|
|
|
64
|
+
function asPositiveNumber(value: unknown): number | undefined {
|
|
65
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
|
|
66
|
+
if (typeof value === "string") {
|
|
67
|
+
const n = Number.parseFloat(value);
|
|
68
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function pickFirstPositiveNumber(record: Record<string, unknown>, keys: string[]): number | undefined {
|
|
74
|
+
for (const key of keys) {
|
|
75
|
+
const value = asPositiveNumber(record[key]);
|
|
76
|
+
if (value !== undefined) return value;
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function discoverInputModalities(rawModel: Record<string, unknown>, id: string): Array<"text" | "image"> {
|
|
82
|
+
const directModalities = rawModel.input_modalities;
|
|
83
|
+
const capabilitiesModalities = (rawModel.capabilities as Record<string, unknown> | undefined)?.input_modalities;
|
|
84
|
+
const source = Array.isArray(directModalities)
|
|
85
|
+
? directModalities
|
|
86
|
+
: Array.isArray(capabilitiesModalities)
|
|
87
|
+
? capabilitiesModalities
|
|
88
|
+
: [];
|
|
89
|
+
const supportsImage = source.some((m) => typeof m === "string" && /image|vision/i.test(m))
|
|
90
|
+
|| /vision|image|omni|multimodal/i.test(id);
|
|
91
|
+
return supportsImage ? ["text", "image"] : ["text"];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function parseOpenAICompatibleModel(rawModel: Record<string, unknown>): DiscoveredModel | undefined {
|
|
95
|
+
const id = typeof rawModel.id === "string" ? rawModel.id : "";
|
|
96
|
+
if (!id) return undefined;
|
|
97
|
+
if (OPENAI_EXCLUDED_PREFIXES.some((prefix) => id.startsWith(prefix))) return undefined;
|
|
98
|
+
|
|
99
|
+
const contextWindow = pickFirstPositiveNumber(rawModel, [
|
|
100
|
+
"context_window",
|
|
101
|
+
"context_length",
|
|
102
|
+
"max_context_length",
|
|
103
|
+
"max_input_tokens",
|
|
104
|
+
"input_token_limit",
|
|
105
|
+
"max_model_len",
|
|
106
|
+
]);
|
|
107
|
+
const maxTokens = pickFirstPositiveNumber(rawModel, [
|
|
108
|
+
"max_output_tokens",
|
|
109
|
+
"output_token_limit",
|
|
110
|
+
"max_completion_tokens",
|
|
111
|
+
"max_tokens",
|
|
112
|
+
]);
|
|
113
|
+
const reasoning = rawModel.reasoning === true
|
|
114
|
+
|| rawModel.supports_reasoning === true
|
|
115
|
+
|| ((rawModel.capabilities as Record<string, unknown> | undefined)?.reasoning === true);
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
id,
|
|
119
|
+
name: typeof rawModel.name === "string" && rawModel.name.length > 0 ? rawModel.name : id,
|
|
120
|
+
contextWindow,
|
|
121
|
+
maxTokens,
|
|
122
|
+
reasoning,
|
|
123
|
+
input: discoverInputModalities(rawModel, id),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
56
127
|
class OpenAIDiscoveryAdapter implements ProviderDiscoveryAdapter {
|
|
57
|
-
provider
|
|
128
|
+
provider: string;
|
|
58
129
|
supportsDiscovery = true;
|
|
59
130
|
|
|
131
|
+
constructor(provider: string) {
|
|
132
|
+
this.provider = provider;
|
|
133
|
+
}
|
|
134
|
+
|
|
60
135
|
async fetchModels(apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]> {
|
|
61
136
|
const url = `${baseUrl ?? "https://api.openai.com"}/v1/models`;
|
|
62
137
|
const response = await fetchWithTimeout(url, {
|
|
@@ -67,14 +142,10 @@ class OpenAIDiscoveryAdapter implements ProviderDiscoveryAdapter {
|
|
|
67
142
|
throw new Error(`OpenAI models API returned ${response.status}: ${response.statusText}`);
|
|
68
143
|
}
|
|
69
144
|
|
|
70
|
-
const data = (await response.json()) as { data
|
|
71
|
-
return data.data
|
|
72
|
-
.
|
|
73
|
-
.
|
|
74
|
-
id: m.id,
|
|
75
|
-
name: m.id,
|
|
76
|
-
input: ["text" as const, "image" as const],
|
|
77
|
-
}));
|
|
145
|
+
const data = (await response.json()) as { data?: Array<Record<string, unknown>> };
|
|
146
|
+
return (data.data ?? [])
|
|
147
|
+
.map((m) => parseOpenAICompatibleModel(m))
|
|
148
|
+
.filter((m): m is DiscoveredModel => !!m);
|
|
78
149
|
}
|
|
79
150
|
}
|
|
80
151
|
|
|
@@ -207,7 +278,7 @@ class StaticDiscoveryAdapter implements ProviderDiscoveryAdapter {
|
|
|
207
278
|
// ─── Registry ────────────────────────────────────────────────────────────────
|
|
208
279
|
|
|
209
280
|
const adapters: Record<string, ProviderDiscoveryAdapter> = {
|
|
210
|
-
openai: new OpenAIDiscoveryAdapter(),
|
|
281
|
+
openai: new OpenAIDiscoveryAdapter("openai"),
|
|
211
282
|
ollama: new OllamaDiscoveryAdapter(),
|
|
212
283
|
openrouter: new OpenRouterDiscoveryAdapter(),
|
|
213
284
|
google: new GoogleDiscoveryAdapter(),
|
|
@@ -220,8 +291,24 @@ const adapters: Record<string, ProviderDiscoveryAdapter> = {
|
|
|
220
291
|
mistral: new StaticDiscoveryAdapter("mistral"),
|
|
221
292
|
};
|
|
222
293
|
|
|
223
|
-
export function
|
|
224
|
-
|
|
294
|
+
export function supportsDiscoveryForApi(api: string | undefined): boolean {
|
|
295
|
+
if (!api) return false;
|
|
296
|
+
return OPENAI_COMPAT_DISCOVERY_APIS.has(api);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export function getDiscoveryAdapter(provider: string, providerApis?: Iterable<string>): ProviderDiscoveryAdapter {
|
|
300
|
+
const known = adapters[provider];
|
|
301
|
+
if (known) return known;
|
|
302
|
+
|
|
303
|
+
if (providerApis) {
|
|
304
|
+
for (const api of providerApis) {
|
|
305
|
+
if (supportsDiscoveryForApi(api)) {
|
|
306
|
+
return new OpenAIDiscoveryAdapter(provider);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return new StaticDiscoveryAdapter(provider);
|
|
225
312
|
}
|
|
226
313
|
|
|
227
314
|
export function getDiscoverableProviders(): string[] {
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression tests for #4563:
|
|
3
|
+
* Bug 1 — custom/Anthropic-compatible models were hard-capped to 32 k output tokens
|
|
4
|
+
* Bug 2 — custom models in models.json could not declare capabilities.supportsXhigh
|
|
5
|
+
*/
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
11
|
+
import { AuthStorage } from "./auth-storage.js";
|
|
12
|
+
import { ModelRegistry } from "./model-registry.js";
|
|
13
|
+
|
|
14
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
let testDir: string;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
testDir = join(
|
|
20
|
+
tmpdir(),
|
|
21
|
+
`model-registry-custom-caps-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
22
|
+
);
|
|
23
|
+
mkdirSync(testDir, { recursive: true });
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
try {
|
|
28
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
29
|
+
} catch {
|
|
30
|
+
// best-effort cleanup
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
function createRegistry(modelsJson: object): ModelRegistry {
|
|
35
|
+
const path = join(testDir, "models.json");
|
|
36
|
+
writeFileSync(path, JSON.stringify(modelsJson));
|
|
37
|
+
return new ModelRegistry(AuthStorage.inMemory(), path);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function writeModelsJson(obj: object): string {
|
|
41
|
+
const path = join(testDir, "models.json");
|
|
42
|
+
writeFileSync(path, JSON.stringify(obj));
|
|
43
|
+
return path;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ─── Bug 1: 32 k cap must not apply to custom/OpenAI-compatible models ────────
|
|
47
|
+
|
|
48
|
+
describe("Bug 1 — maxTokens cap (#4563)", () => {
|
|
49
|
+
it("custom openai-completions model with maxTokens > 32 k is not capped", () => {
|
|
50
|
+
const registry = createRegistry({
|
|
51
|
+
providers: {
|
|
52
|
+
"kimi-custom": {
|
|
53
|
+
baseUrl: "https://api.example.com/v1",
|
|
54
|
+
apiKey: "sk-test",
|
|
55
|
+
api: "openai-completions",
|
|
56
|
+
models: [
|
|
57
|
+
{
|
|
58
|
+
id: "kimi-k2.6-code-preview",
|
|
59
|
+
name: "Kimi K2.6 Code Preview",
|
|
60
|
+
maxTokens: 131072,
|
|
61
|
+
contextWindow: 262144,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const model = registry.getAll().find((m) => m.id === "kimi-k2.6-code-preview");
|
|
69
|
+
assert.ok(model, "model should be registered");
|
|
70
|
+
assert.equal(
|
|
71
|
+
model.maxTokens,
|
|
72
|
+
131072,
|
|
73
|
+
"maxTokens must be preserved as declared — not capped to 32 000",
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("custom model with maxTokens exactly 32 k is not affected", () => {
|
|
78
|
+
const registry = createRegistry({
|
|
79
|
+
providers: {
|
|
80
|
+
"custom-provider": {
|
|
81
|
+
baseUrl: "https://api.example.com/v1",
|
|
82
|
+
apiKey: "sk-test",
|
|
83
|
+
api: "openai-completions",
|
|
84
|
+
models: [{ id: "model-32k", maxTokens: 32000, contextWindow: 128000 }],
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const model = registry.getAll().find((m) => m.id === "model-32k");
|
|
90
|
+
assert.ok(model);
|
|
91
|
+
assert.equal(model.maxTokens, 32000);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("custom model with maxTokens 65 k is stored at full value", () => {
|
|
95
|
+
const registry = createRegistry({
|
|
96
|
+
providers: {
|
|
97
|
+
"dashscope-custom": {
|
|
98
|
+
baseUrl: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
|
|
99
|
+
apiKey: "sk-test",
|
|
100
|
+
api: "openai-completions",
|
|
101
|
+
models: [
|
|
102
|
+
{
|
|
103
|
+
id: "qwen3.5-plus",
|
|
104
|
+
name: "Qwen3.5 Plus",
|
|
105
|
+
maxTokens: 65536,
|
|
106
|
+
contextWindow: 1000000,
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const model = registry.getAll().find((m) => m.id === "qwen3.5-plus" && m.provider === "dashscope-custom");
|
|
114
|
+
assert.ok(model);
|
|
115
|
+
assert.equal(model.maxTokens, 65536);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// ─── Bug 2: capabilities.supportsXhigh must be declarable in models.json ──────
|
|
120
|
+
|
|
121
|
+
describe("Bug 2 — capabilities.supportsXhigh in models.json (#4563)", () => {
|
|
122
|
+
it("model with capabilities.supportsXhigh: true surfaces the flag", () => {
|
|
123
|
+
const registry = createRegistry({
|
|
124
|
+
providers: {
|
|
125
|
+
"kimi-custom": {
|
|
126
|
+
baseUrl: "https://api.example.com/v1",
|
|
127
|
+
apiKey: "sk-test",
|
|
128
|
+
api: "anthropic-messages",
|
|
129
|
+
models: [
|
|
130
|
+
{
|
|
131
|
+
id: "kimi-k2.6-code-preview",
|
|
132
|
+
name: "Kimi K2.6 Code Preview",
|
|
133
|
+
maxTokens: 131072,
|
|
134
|
+
contextWindow: 262144,
|
|
135
|
+
capabilities: { supportsXhigh: true },
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const model = registry.getAll().find((m) => m.id === "kimi-k2.6-code-preview");
|
|
143
|
+
assert.ok(model, "model should be registered");
|
|
144
|
+
assert.equal(
|
|
145
|
+
model.capabilities?.supportsXhigh,
|
|
146
|
+
true,
|
|
147
|
+
"supportsXhigh must be true as declared in models.json",
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("model without capabilities declaration has no supportsXhigh", () => {
|
|
152
|
+
const registry = createRegistry({
|
|
153
|
+
providers: {
|
|
154
|
+
"plain-provider": {
|
|
155
|
+
baseUrl: "https://api.example.com/v1",
|
|
156
|
+
apiKey: "sk-test",
|
|
157
|
+
api: "openai-completions",
|
|
158
|
+
models: [{ id: "plain-model", maxTokens: 16384, contextWindow: 128000 }],
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const model = registry.getAll().find((m) => m.id === "plain-model");
|
|
164
|
+
assert.ok(model);
|
|
165
|
+
// supportsXhigh should be absent or explicitly false — never implicitly true
|
|
166
|
+
assert.ok(
|
|
167
|
+
!model.capabilities?.supportsXhigh,
|
|
168
|
+
"supportsXhigh must not be set for models that don't declare it",
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("capabilities.supportsXhigh: false is respected", () => {
|
|
173
|
+
const registry = createRegistry({
|
|
174
|
+
providers: {
|
|
175
|
+
"explicit-provider": {
|
|
176
|
+
baseUrl: "https://api.example.com/v1",
|
|
177
|
+
apiKey: "sk-test",
|
|
178
|
+
api: "openai-completions",
|
|
179
|
+
models: [
|
|
180
|
+
{
|
|
181
|
+
id: "no-xhigh-model",
|
|
182
|
+
capabilities: { supportsXhigh: false },
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const model = registry.getAll().find((m) => m.id === "no-xhigh-model");
|
|
190
|
+
assert.ok(model);
|
|
191
|
+
assert.equal(model.capabilities?.supportsXhigh, false);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("supportsXhigh declared in models.json is not overwritten by capability patches", () => {
|
|
195
|
+
// The capability-patches system must not overwrite an explicit declaration in models.json.
|
|
196
|
+
// applyCapabilityPatches uses spread: { ...patch.caps, ...model.capabilities }
|
|
197
|
+
// so model.capabilities wins. This test verifies the precedence end-to-end.
|
|
198
|
+
const registry = createRegistry({
|
|
199
|
+
providers: {
|
|
200
|
+
"compat-provider": {
|
|
201
|
+
baseUrl: "https://api.example.com/v1",
|
|
202
|
+
apiKey: "sk-test",
|
|
203
|
+
api: "openai-completions",
|
|
204
|
+
models: [
|
|
205
|
+
{
|
|
206
|
+
id: "custom-xhigh-model",
|
|
207
|
+
capabilities: { supportsXhigh: true },
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
const model = registry.getAll().find((m) => m.id === "custom-xhigh-model");
|
|
215
|
+
assert.ok(model);
|
|
216
|
+
assert.equal(model.capabilities?.supportsXhigh, true);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("modelOverrides can set capabilities.supportsXhigh on built-in models", () => {
|
|
220
|
+
// A user-facing override in models.json should be able to add supportsXhigh
|
|
221
|
+
// to a built-in model that doesn't declare it.
|
|
222
|
+
const path = writeModelsJson({
|
|
223
|
+
providers: {
|
|
224
|
+
anthropic: {
|
|
225
|
+
modelOverrides: {
|
|
226
|
+
"claude-3-5-haiku-20241022": {
|
|
227
|
+
capabilities: { supportsXhigh: true },
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const registry = new ModelRegistry(AuthStorage.inMemory(), path);
|
|
235
|
+
const model = registry.getAll().find(
|
|
236
|
+
(m) => m.provider === "anthropic" && m.id === "claude-3-5-haiku-20241022",
|
|
237
|
+
);
|
|
238
|
+
assert.ok(model, "built-in model must still be present");
|
|
239
|
+
assert.equal(
|
|
240
|
+
model.capabilities?.supportsXhigh,
|
|
241
|
+
true,
|
|
242
|
+
"modelOverrides must be able to set capabilities.supportsXhigh",
|
|
243
|
+
);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
@@ -6,6 +6,7 @@ import { afterEach, beforeEach, describe, it } from "node:test";
|
|
|
6
6
|
import { AuthStorage } from "./auth-storage.js";
|
|
7
7
|
import { ModelDiscoveryCache } from "./discovery-cache.js";
|
|
8
8
|
import { getDefaultTTL, getDiscoverableProviders, getDiscoveryAdapter } from "./model-discovery.js";
|
|
9
|
+
import { ModelRegistry } from "./model-registry.js";
|
|
9
10
|
|
|
10
11
|
let testDir: string;
|
|
11
12
|
|
|
@@ -133,3 +134,77 @@ describe("Discovery TTL configuration", () => {
|
|
|
133
134
|
assert.equal(customTTL, defaultTTL);
|
|
134
135
|
});
|
|
135
136
|
});
|
|
137
|
+
|
|
138
|
+
describe("ModelRegistry discovery — OpenAI-compatible custom providers", () => {
|
|
139
|
+
it("discovers custom OpenAI-compatible providers and maps capability metadata", async () => {
|
|
140
|
+
const providerName = `minimax-openai-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
141
|
+
const modelsPath = join(testDir, "models.json");
|
|
142
|
+
writeFileSync(
|
|
143
|
+
modelsPath,
|
|
144
|
+
JSON.stringify(
|
|
145
|
+
{
|
|
146
|
+
providers: {
|
|
147
|
+
[providerName]: {
|
|
148
|
+
baseUrl: "https://api.minimax.example",
|
|
149
|
+
apiKey: "minimax-test-key",
|
|
150
|
+
api: "openai-completions",
|
|
151
|
+
models: [{ id: "bootstrap-model" }],
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
null,
|
|
156
|
+
2,
|
|
157
|
+
),
|
|
158
|
+
"utf-8",
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const prevFetch = globalThis.fetch;
|
|
162
|
+
let requestedUrl = "";
|
|
163
|
+
globalThis.fetch = (async (input: string | URL | Request) => {
|
|
164
|
+
requestedUrl = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
165
|
+
return new Response(
|
|
166
|
+
JSON.stringify({
|
|
167
|
+
data: [
|
|
168
|
+
{
|
|
169
|
+
id: "MiniMax-M2.7-highspeed",
|
|
170
|
+
name: "MiniMax M2.7 Highspeed",
|
|
171
|
+
context_window: 165000,
|
|
172
|
+
max_output_tokens: 32768,
|
|
173
|
+
supports_reasoning: true,
|
|
174
|
+
input_modalities: ["text", "image"],
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
}),
|
|
178
|
+
{
|
|
179
|
+
status: 200,
|
|
180
|
+
headers: { "content-type": "application/json" },
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
}) as typeof globalThis.fetch;
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
const registry = new ModelRegistry(AuthStorage.inMemory({}), modelsPath);
|
|
187
|
+
// Guard against global cache leakage from prior test runs.
|
|
188
|
+
registry.getDiscoveryCache().clear(providerName);
|
|
189
|
+
const results = await registry.discoverModels([providerName]);
|
|
190
|
+
|
|
191
|
+
const discovery = results.find((r) => r.provider === providerName);
|
|
192
|
+
assert.ok(discovery, "discovery result should include custom provider");
|
|
193
|
+
assert.equal(discovery?.error, undefined, "custom provider discovery should succeed");
|
|
194
|
+
assert.equal(requestedUrl, "https://api.minimax.example/v1/models");
|
|
195
|
+
|
|
196
|
+
const discovered = registry
|
|
197
|
+
.getAllWithDiscovered()
|
|
198
|
+
.find((m) => m.provider === providerName && m.id === "MiniMax-M2.7-highspeed");
|
|
199
|
+
assert.ok(discovered, "discovered model should be merged into model list");
|
|
200
|
+
assert.equal(discovered?.api, "openai-completions");
|
|
201
|
+
assert.equal(discovered?.baseUrl, "https://api.minimax.example");
|
|
202
|
+
assert.equal(discovered?.contextWindow, 165000);
|
|
203
|
+
assert.equal(discovered?.maxTokens, 32768);
|
|
204
|
+
assert.equal(discovered?.reasoning, true);
|
|
205
|
+
assert.deepEqual(discovered?.input, ["text", "image"]);
|
|
206
|
+
} finally {
|
|
207
|
+
globalThis.fetch = prevFetch;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
});
|