@opengsd/gsd-pi 1.10.0 → 1.11.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/README.md +10 -9
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto-model-selection.js +1 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto-verification.js +25 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +4 -3
- package/dist/resources/extensions/gsd/db/engine.js +8 -2
- package/dist/resources/extensions/gsd/db-canonical-foundation-schema.js +120 -0
- package/dist/resources/extensions/gsd/db-migration-steps.js +4 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +12 -3
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +16 -4
- package/dist/resources/extensions/gsd/model-cost-table.js +6 -3
- package/dist/resources/extensions/gsd/model-router.js +10 -5
- package/dist/resources/extensions/gsd/planning-subagent-registry.js +12 -4
- package/dist/resources/extensions/gsd/preferences-models.js +50 -10
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +41 -6
- package/dist/resources/extensions/gsd/preferences.js +7 -0
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +3 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -1
- package/dist/resources/extensions/gsd/verification-evidence.js +5 -3
- package/dist/resources/extensions/ollama/ollama-chat-provider.js +2 -2
- package/dist/resources/extensions/subagent/index.js +1 -1
- package/dist/startup-model-validation.d.ts +1 -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 +7 -7
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- 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 +7 -7
- package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- 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/node_modules/@gsd/native/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +7 -6
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/rpc.d.ts +1 -1
- package/packages/contracts/dist/rpc.d.ts.map +1 -1
- package/packages/contracts/dist/rpc.js +1 -1
- package/packages/contracts/dist/rpc.js.map +1 -1
- package/packages/contracts/dist/rpc.test.js +1 -1
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/cli/args.js +2 -2
- package/packages/gsd-agent-modes/dist/cli/args.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/gsd-cloud/README.md +12 -2
- package/packages/gsd-cloud/dist/background-cli.test.js +157 -80
- package/packages/gsd-cloud/dist/background-cli.test.js.map +1 -1
- package/packages/gsd-cloud/dist/cli.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cli.js +36 -12
- package/packages/gsd-cloud/dist/cli.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts +6 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.js +106 -24
- package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.test.js +224 -59
- package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-artifacts.d.ts +3 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.js +36 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts +5 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/runtime-process.js +429 -61
- package/packages/gsd-cloud/dist/runtime-process.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-process.test.js +493 -47
- package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-telemetry.d.ts +117 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.js +291 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.js +434 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.js.map +1 -0
- package/packages/gsd-cloud/package.json +2 -2
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +2 -2
- 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/package.json +1 -1
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +113 -2
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +84 -9
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.js +18 -6
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +3 -2
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/packages/pi-ai/dist/providers/google.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +9 -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/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -3
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.js +1 -0
- package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/theme.d.ts +1 -1
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +1 -0
- package/pkg/dist/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +1 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto-verification.ts +46 -12
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +4 -3
- package/src/resources/extensions/gsd/db/engine.ts +9 -1
- package/src/resources/extensions/gsd/db-canonical-foundation-schema.ts +129 -0
- package/src/resources/extensions/gsd/db-migration-steps.ts +5 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +12 -3
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +15 -4
- package/src/resources/extensions/gsd/model-cost-table.ts +14 -3
- package/src/resources/extensions/gsd/model-router.ts +10 -5
- package/src/resources/extensions/gsd/planning-subagent-registry.ts +18 -4
- package/src/resources/extensions/gsd/preferences-models.ts +54 -10
- package/src/resources/extensions/gsd/preferences-types.ts +10 -2
- package/src/resources/extensions/gsd/preferences-validation.ts +49 -6
- package/src/resources/extensions/gsd/preferences.ts +13 -0
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +3 -0
- package/src/resources/extensions/gsd/tests/db-canonical-foundation.test.ts +459 -0
- package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +22 -7
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/preferences.test.ts +71 -4
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-faults.test.ts +238 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-fixture.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-fixture.ts +141 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-projection-conflict.test.ts +177 -0
- package/src/resources/extensions/gsd/tests/workflow-fault-harness.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/workflow-fault-harness.ts +72 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +40 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +5 -1
- package/src/resources/extensions/gsd/verification-evidence.ts +5 -2
- package/src/resources/extensions/ollama/ollama-chat-provider.ts +2 -2
- package/src/resources/extensions/ollama/tests/ollama-chat-provider-think.test.ts +4 -0
- package/src/resources/extensions/subagent/index.ts +1 -1
- /package/dist/web/standalone/.next/static/{EAhnhYMt5UVOiG9-iPDjc → 8ub6oiEp2YnlOHQU20LJr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{EAhnhYMt5UVOiG9-iPDjc → 8ub6oiEp2YnlOHQU20LJr}/_ssgManifest.js +0 -0
|
@@ -8,10 +8,31 @@
|
|
|
8
8
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
10
|
import { join } from "node:path";
|
|
11
|
+
import { getProviders } from "@gsd/pi-ai";
|
|
11
12
|
import { gsdHome } from "./gsd-home.js";
|
|
12
13
|
import { canonicalModelForTier, defaultRoutingConfig, resolveModelForTier } from "./model-router.js";
|
|
13
14
|
import { clearGSDPreferencesCache, loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
14
15
|
import { getUnitPhaseChain } from "./unit-registry.js";
|
|
16
|
+
/**
|
|
17
|
+
* First-party providers shipped as bundled extensions that delegate to a
|
|
18
|
+
* vendor CLI (`authMode: "externalCli"`). They are registered into the live
|
|
19
|
+
* model registry at runtime, so they are absent from the generated `@gsd/pi-ai`
|
|
20
|
+
* catalog (`getProviders()`), but they are NOT custom: `PREFERENCES.md` can
|
|
21
|
+
* route to them, so they must defer to `PREFERENCES.md` like any other built-in
|
|
22
|
+
* provider. Without this exclusion the registry check below would classify the
|
|
23
|
+
* default `claude-code` provider (and the other CLI providers) as custom and
|
|
24
|
+
* silently skip `PREFERENCES.md` in auto-mode (#801, extends #4122).
|
|
25
|
+
*
|
|
26
|
+
* Kept in sync with the `registerProvider(...)` calls in the bundled CLI
|
|
27
|
+
* extensions (claude-code-cli, cursor-cli, google-cli). Names are lowercase for
|
|
28
|
+
* direct comparison against normalized provider ids.
|
|
29
|
+
*/
|
|
30
|
+
const BUILTIN_EXTENSION_PROVIDERS = new Set([
|
|
31
|
+
"claude-code",
|
|
32
|
+
"cursor-agent",
|
|
33
|
+
"google-gemini-cli",
|
|
34
|
+
"google-antigravity",
|
|
35
|
+
]);
|
|
15
36
|
/**
|
|
16
37
|
* Resolve which model ID to use for a given auto-mode unit type.
|
|
17
38
|
* Returns undefined if no model preference is set for this unit type.
|
|
@@ -281,9 +302,8 @@ export function resolveDefaultSessionModel(sessionProvider, basePath, availableM
|
|
|
281
302
|
return undefined;
|
|
282
303
|
}
|
|
283
304
|
/**
|
|
284
|
-
* Returns true if `provider` is
|
|
285
|
-
*
|
|
286
|
-
* proxies, etc.).
|
|
305
|
+
* Returns true if `provider` is a custom provider. Custom providers may be
|
|
306
|
+
* declared in `models.json` or registered dynamically by a Pi extension.
|
|
287
307
|
*
|
|
288
308
|
* Used by auto-mode bootstrap to decide whether the session model
|
|
289
309
|
* (set via `/gsd model`) should override `PREFERENCES.md`. Custom providers
|
|
@@ -292,13 +312,16 @@ export function resolveDefaultSessionModel(sessionProvider, basePath, availableM
|
|
|
292
312
|
* priority — otherwise auto-mode tries to start the built-in provider from
|
|
293
313
|
* PREFERENCES.md and fails with "Not logged in · Please run /login" (#4122).
|
|
294
314
|
*
|
|
295
|
-
* Reads models.json directly with a lightweight JSON parse
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
315
|
+
* Reads models.json directly with a lightweight JSON parse, then checks the
|
|
316
|
+
* live model registry for extension-registered providers that are not in the
|
|
317
|
+
* generated built-in provider catalog (`getProviders()`) and not one of the
|
|
318
|
+
* bundled external-CLI providers (`BUILTIN_EXTENSION_PROVIDERS`, e.g.
|
|
319
|
+
* `claude-code`), which register at runtime but are still built-in. Falls back
|
|
320
|
+
* to `~/.pi/agent/models.json` for parity with `resolveModelsJsonPath()`. Any
|
|
321
|
+
* read, parse, or registry error yields `false` (treat as not-custom) so
|
|
322
|
+
* bootstrap stays non-fatal.
|
|
300
323
|
*/
|
|
301
|
-
export function isCustomProvider(provider) {
|
|
324
|
+
export function isCustomProvider(provider, registry) {
|
|
302
325
|
if (!provider)
|
|
303
326
|
return false;
|
|
304
327
|
const candidates = [
|
|
@@ -319,7 +342,24 @@ export function isCustomProvider(provider) {
|
|
|
319
342
|
// Ignore — malformed models.json must not break bootstrap.
|
|
320
343
|
}
|
|
321
344
|
}
|
|
322
|
-
|
|
345
|
+
try {
|
|
346
|
+
const normalizedProvider = provider.trim().toLowerCase();
|
|
347
|
+
if (!normalizedProvider)
|
|
348
|
+
return false;
|
|
349
|
+
if (BUILTIN_EXTENSION_PROVIDERS.has(normalizedProvider))
|
|
350
|
+
return false;
|
|
351
|
+
const builtInProviders = new Set(getProviders().map((p) => p.toLowerCase()));
|
|
352
|
+
if (builtInProviders.has(normalizedProvider))
|
|
353
|
+
return false;
|
|
354
|
+
const registryModels = registry?.getAllWithDiscovered?.()
|
|
355
|
+
?? registry?.getAll?.()
|
|
356
|
+
?? registry?.getAvailable?.()
|
|
357
|
+
?? [];
|
|
358
|
+
return registryModels.some((m) => m.provider.toLowerCase() === normalizedProvider);
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
323
363
|
}
|
|
324
364
|
/**
|
|
325
365
|
* Determines the next fallback model to try when the current model fails.
|
|
@@ -10,7 +10,7 @@ import { VALID_BRANCH_NAME } from "./git-service.js";
|
|
|
10
10
|
import { normalizeStringArray } from "../shared/format-utils.js";
|
|
11
11
|
import { getGateIdsForTurn } from "./gate-registry.js";
|
|
12
12
|
import { KNOWN_PREFERENCE_KEYS, KNOWN_UNIT_LABELS, CONFIGURABLE_PLANNING_SUBAGENT_UNITS, GSD_MODEL_PHASE_KEYS, SKILL_ACTIONS, } from "./preferences-types.js";
|
|
13
|
-
import {
|
|
13
|
+
import { allowedPlanningDispatchAgentsList, isReadOnlyPlanningDispatchAgent, } from "./planning-subagent-registry.js";
|
|
14
14
|
const VALID_TOKEN_PROFILES = new Set(["budget", "balanced", "quality", "burn-max"]);
|
|
15
15
|
const VALID_THINKING_LEVELS = new Set([
|
|
16
16
|
"off",
|
|
@@ -19,6 +19,7 @@ const VALID_THINKING_LEVELS = new Set([
|
|
|
19
19
|
"medium",
|
|
20
20
|
"high",
|
|
21
21
|
"xhigh",
|
|
22
|
+
"max",
|
|
22
23
|
]);
|
|
23
24
|
const KNOWN_MODEL_PHASE_KEYS = new Set(GSD_MODEL_PHASE_KEYS);
|
|
24
25
|
const VALID_UOK_TURN_ACTIONS = new Set([
|
|
@@ -69,7 +70,7 @@ function sanitizeModelField(raw, label, errors, warnings) {
|
|
|
69
70
|
}
|
|
70
71
|
else {
|
|
71
72
|
warnings?.push(`${label} thinking "${String(obj.thinking)}" is not a valid thinking level ` +
|
|
72
|
-
`(off, minimal, low, medium, high, xhigh) — ignored`);
|
|
73
|
+
`(off, minimal, low, medium, high, xhigh, max) — ignored`);
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
return sanitized;
|
|
@@ -457,7 +458,7 @@ export function validatePreferences(preferences) {
|
|
|
457
458
|
const level = entry.thinking;
|
|
458
459
|
if (level !== undefined && !VALID_THINKING_LEVELS.has(level)) {
|
|
459
460
|
warnings.push(`models.${phase}.thinking "${String(level)}" is not a valid thinking level ` +
|
|
460
|
-
`(off, minimal, low, medium, high, xhigh) — ignored`);
|
|
461
|
+
`(off, minimal, low, medium, high, xhigh, max) — ignored`);
|
|
461
462
|
const { thinking: _ignored, ...rest } = entry;
|
|
462
463
|
// If stripping the bad thinking leaves no usable model, drop the
|
|
463
464
|
// phase entirely rather than storing a hollow `{}` / `{ provider }`
|
|
@@ -488,7 +489,7 @@ export function validatePreferences(preferences) {
|
|
|
488
489
|
}
|
|
489
490
|
if (!VALID_THINKING_LEVELS.has(level)) {
|
|
490
491
|
warnings.push(`thinking.${phase} "${String(level)}" is not a valid thinking level ` +
|
|
491
|
-
`(off, minimal, low, medium, high, xhigh) — ignored`);
|
|
492
|
+
`(off, minimal, low, medium, high, xhigh, max) — ignored`);
|
|
492
493
|
continue;
|
|
493
494
|
}
|
|
494
495
|
validatedThinking[phase] = level;
|
|
@@ -728,6 +729,38 @@ export function validatePreferences(preferences) {
|
|
|
728
729
|
validated.pre_dispatch_hooks = validPreHooks;
|
|
729
730
|
}
|
|
730
731
|
}
|
|
732
|
+
// ─── Planning Subagent Registry ──────────────────────────────────────────
|
|
733
|
+
if (preferences.planning_subagent_registry !== undefined) {
|
|
734
|
+
if (!preferences.planning_subagent_registry ||
|
|
735
|
+
typeof preferences.planning_subagent_registry !== "object" ||
|
|
736
|
+
Array.isArray(preferences.planning_subagent_registry)) {
|
|
737
|
+
errors.push("planning_subagent_registry must be an object keyed by agent id");
|
|
738
|
+
}
|
|
739
|
+
else {
|
|
740
|
+
const validRegistry = {};
|
|
741
|
+
for (const [rawAgentId, rawConfig] of Object.entries(preferences.planning_subagent_registry)) {
|
|
742
|
+
const agentId = rawAgentId.trim();
|
|
743
|
+
if (!agentId) {
|
|
744
|
+
errors.push("planning_subagent_registry includes an empty agent id");
|
|
745
|
+
continue;
|
|
746
|
+
}
|
|
747
|
+
if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
|
|
748
|
+
errors.push(`planning_subagent_registry.${agentId} must be an object with read_only_specialist: true`);
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
const readOnlySpecialist = rawConfig.read_only_specialist;
|
|
752
|
+
if (readOnlySpecialist !== true) {
|
|
753
|
+
errors.push(`planning_subagent_registry.${agentId}.read_only_specialist must be true to classify ` +
|
|
754
|
+
`"${agentId}" as a read-only planning specialist`);
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
validRegistry[agentId] = { read_only_specialist: true };
|
|
758
|
+
}
|
|
759
|
+
if (Object.keys(validRegistry).length > 0) {
|
|
760
|
+
validated.planning_subagent_registry = validRegistry;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
731
764
|
// ─── Planning Subagents ─────────────────────────────────────────────────
|
|
732
765
|
if (preferences.planning_subagents !== undefined) {
|
|
733
766
|
if (!preferences.planning_subagents ||
|
|
@@ -755,9 +788,11 @@ export function validatePreferences(preferences) {
|
|
|
755
788
|
}
|
|
756
789
|
const sanitizedAllowed = [];
|
|
757
790
|
for (const agentId of allowed) {
|
|
758
|
-
if (!
|
|
791
|
+
if (!isReadOnlyPlanningDispatchAgent(agentId, validated.planning_subagent_registry)) {
|
|
759
792
|
errors.push(`planning_subagents.${unitType}.allowed includes "${agentId}", which is not classified as a ` +
|
|
760
|
-
`read-only planning specialist. Allowed agents:
|
|
793
|
+
`read-only planning specialist. Allowed agents: ` +
|
|
794
|
+
`${allowedPlanningDispatchAgentsList(validated.planning_subagent_registry)}. ` +
|
|
795
|
+
`For custom planning agents, add planning_subagent_registry.${agentId}.read_only_specialist: true`);
|
|
761
796
|
continue;
|
|
762
797
|
}
|
|
763
798
|
sanitizedAllowed.push(agentId);
|
|
@@ -635,6 +635,7 @@ function mergePreferences(base, override) {
|
|
|
635
635
|
: undefined,
|
|
636
636
|
post_unit_hooks: mergePostUnitHooks(base.post_unit_hooks, override.post_unit_hooks),
|
|
637
637
|
pre_dispatch_hooks: mergePreDispatchHooks(base.pre_dispatch_hooks, override.pre_dispatch_hooks),
|
|
638
|
+
planning_subagent_registry: mergePlanningSubagentRegistry(base.planning_subagent_registry, override.planning_subagent_registry),
|
|
638
639
|
planning_subagents: mergePlanningSubagents(base.planning_subagents, override.planning_subagents),
|
|
639
640
|
dynamic_routing: (base.dynamic_routing || override.dynamic_routing)
|
|
640
641
|
? { ...(base.dynamic_routing ?? {}), ...(override.dynamic_routing ?? {}) }
|
|
@@ -769,6 +770,12 @@ function mergePlanningSubagents(base, override) {
|
|
|
769
770
|
}
|
|
770
771
|
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
771
772
|
}
|
|
773
|
+
function mergePlanningSubagentRegistry(base, override) {
|
|
774
|
+
if (!base && !override)
|
|
775
|
+
return undefined;
|
|
776
|
+
const merged = { ...(base ?? {}), ...(override ?? {}) };
|
|
777
|
+
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
778
|
+
}
|
|
772
779
|
// ─── System Prompt Rendering ──────────────────────────────────────────────────
|
|
773
780
|
export function renderPreferencesForSystemPrompt(preferences, resolutions, options) {
|
|
774
781
|
const validated = validatePreferences(preferences);
|
|
@@ -92,6 +92,9 @@ remote_questions:
|
|
|
92
92
|
uat_dispatch:
|
|
93
93
|
post_unit_hooks: []
|
|
94
94
|
pre_dispatch_hooks: []
|
|
95
|
+
# planning_subagent_registry:
|
|
96
|
+
# my-custom-planner:
|
|
97
|
+
# read_only_specialist: true
|
|
95
98
|
# planning_subagents:
|
|
96
99
|
# plan-milestone:
|
|
97
100
|
# allowed: [scout, planner, security]
|
|
@@ -6,7 +6,7 @@ import { isNonEmptyString, validateStringArray } from "../validation.js";
|
|
|
6
6
|
import { getGateIdsForTurn } from "../gate-registry.js";
|
|
7
7
|
import { transaction, getMilestone, getSlice, getSliceTasks, insertTask, upsertSlicePlanning, upsertTaskPlanning, insertGateRow, updateSliceStatus, setSliceSketchFlag, deleteTask, deleteArtifactByPath, } from "../gsd-db.js";
|
|
8
8
|
import { invalidateStateCache } from "../state.js";
|
|
9
|
-
import { renderPlanFromDb } from "../markdown-renderer.js";
|
|
9
|
+
import { renderPlanCheckboxes, renderPlanFromDb } from "../markdown-renderer.js";
|
|
10
10
|
import { writeManifest } from "../workflow-manifest.js";
|
|
11
11
|
import { appendEvent } from "../workflow-events.js";
|
|
12
12
|
import { logWarning } from "../workflow-logger.js";
|
|
@@ -371,9 +371,13 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
371
371
|
deleteArtifactByPath(artifactPath);
|
|
372
372
|
}
|
|
373
373
|
const sliceTasks = getSliceTasks(params.milestoneId, params.sliceId);
|
|
374
|
+
const hasClosedTasks = sliceTasks.some((task) => isClosedStatus(task.status));
|
|
374
375
|
const renderResult = sliceTasks.length === 0
|
|
375
376
|
? { planPath: "", taskPlanPaths: [] }
|
|
376
377
|
: await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
378
|
+
if (sliceTasks.length > 0 && hasClosedTasks) {
|
|
379
|
+
await renderPlanCheckboxes(basePath, params.milestoneId, params.sliceId);
|
|
380
|
+
}
|
|
377
381
|
if (sliceTasks.length > 0) {
|
|
378
382
|
setSliceSketchFlag(params.milestoneId, params.sliceId, false);
|
|
379
383
|
}
|
|
@@ -11,13 +11,14 @@
|
|
|
11
11
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
/**
|
|
14
|
-
* Write a T##-VERIFY.json artifact to the
|
|
14
|
+
* Write a T##-VERIFY.json artifact to the evidence directory.
|
|
15
15
|
* Creates the directory with mkdirSync({ recursive: true }) if it doesn't exist.
|
|
16
|
+
* Flat-phase callers can pass sliceId to write S##-T##-VERIFY.json.
|
|
16
17
|
*
|
|
17
18
|
* stdout/stderr are excluded from the JSON — the full output lives in VerificationResult
|
|
18
19
|
* in memory and is logged to stderr during the gate run.
|
|
19
20
|
*/
|
|
20
|
-
export function writeVerificationJSON(result, tasksDir, taskId, unitId, retryAttempt, maxRetries) {
|
|
21
|
+
export function writeVerificationJSON(result, tasksDir, taskId, unitId, retryAttempt, maxRetries, sliceId) {
|
|
21
22
|
mkdirSync(tasksDir, { recursive: true });
|
|
22
23
|
const evidence = {
|
|
23
24
|
schemaVersion: 1,
|
|
@@ -52,7 +53,8 @@ export function writeVerificationJSON(result, tasksDir, taskId, unitId, retryAtt
|
|
|
52
53
|
fixAvailable: w.fixAvailable,
|
|
53
54
|
}));
|
|
54
55
|
}
|
|
55
|
-
const
|
|
56
|
+
const fileName = sliceId ? `${sliceId}-${taskId}-VERIFY.json` : `${taskId}-VERIFY.json`;
|
|
57
|
+
const filePath = join(tasksDir, fileName);
|
|
56
58
|
writeFileSync(filePath, JSON.stringify(evidence, null, 2) + "\n", "utf-8");
|
|
57
59
|
}
|
|
58
60
|
/**
|
|
@@ -160,7 +160,7 @@ export function streamOllamaChat(model, context, options) {
|
|
|
160
160
|
* - `"low" | "medium" | "high"` are passed through as strings; gpt-oss honors
|
|
161
161
|
* them as strength levels, other thinking models treat any present value
|
|
162
162
|
* as "thinking enabled".
|
|
163
|
-
* - `"xhigh"`
|
|
163
|
+
* - `"xhigh"` and `"max"` are collapsed to `"high"` (ollama caps strength at high).
|
|
164
164
|
*/
|
|
165
165
|
export function buildThinkParam(model, options) {
|
|
166
166
|
if (!model.reasoning)
|
|
@@ -170,7 +170,7 @@ export function buildThinkParam(model, options) {
|
|
|
170
170
|
return undefined;
|
|
171
171
|
if (level === "minimal")
|
|
172
172
|
return false;
|
|
173
|
-
if (level === "xhigh")
|
|
173
|
+
if (level === "xhigh" || level === "max")
|
|
174
174
|
return "high";
|
|
175
175
|
return level;
|
|
176
176
|
}
|
|
@@ -591,7 +591,7 @@ thinkingOverride) {
|
|
|
591
591
|
}
|
|
592
592
|
}
|
|
593
593
|
}
|
|
594
|
-
const ThinkingLevelSchema = StringEnum(["off", "minimal", "low", "medium", "high", "xhigh"], {
|
|
594
|
+
const ThinkingLevelSchema = StringEnum(["off", "minimal", "low", "medium", "high", "xhigh", "max"], {
|
|
595
595
|
description: "Reasoning effort override for the subagent (forwarded as --thinking). " +
|
|
596
596
|
"Independent of model choice; unsupported levels are clamped to the model at dispatch.",
|
|
597
597
|
});
|
|
@@ -15,7 +15,7 @@ interface MinimalModel {
|
|
|
15
15
|
interface MinimalModelRegistry {
|
|
16
16
|
getAvailable(): MinimalModel[];
|
|
17
17
|
}
|
|
18
|
-
type ThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
|
|
18
|
+
type ThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
19
19
|
interface MinimalSettingsManager {
|
|
20
20
|
getDefaultProvider(): string | undefined;
|
|
21
21
|
getDefaultModel(): string | undefined;
|