@aiwg/cli 2026.9.19 → 2026.9.21
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/agentic/code/providers/capability-matrix.yaml +58 -6
- package/agentic/code/providers/model-capabilities.v1.json +34 -0
- package/agentic/code/providers/model-catalog.v1.json +55 -13
- package/bin/aiwg.mjs +2 -0
- package/dist/src/api/index.d.ts +1 -0
- package/dist/src/api/index.js +1 -0
- package/dist/src/artifacts/enrichment/cli.js +1 -1
- package/dist/src/artifacts/views/cli.js +1 -1
- package/dist/src/audit/operator-decision.js +10 -0
- package/dist/src/auth/credential-store.js +127 -27
- package/dist/src/catalog/builtin-models.json +272 -40
- package/dist/src/catalog/cli.js +1 -1
- package/dist/src/catalog/cli.mjs +1 -1
- package/dist/src/cli/handlers/effect.js +872 -0
- package/dist/src/cli/handlers/help.js +2 -0
- package/dist/src/cli/handlers/index.js +4 -2
- package/dist/src/cli/handlers/models.js +41 -10
- package/dist/src/cli/handlers/ralph.js +1 -1
- package/dist/src/cli/handlers/sessions.js +113 -37
- package/dist/src/cli/handlers/subcommands.js +31 -0
- package/dist/src/cli/handlers/use.js +46 -9
- package/dist/src/cli/handlers/utilities.js +10 -0
- package/dist/src/cli/handlers/workspace.js +3 -1
- package/dist/src/cli/scope-resolver.js +112 -9
- package/dist/src/cli/services/deployment-verification.js +5 -0
- package/dist/src/config/aiwg-config.js +3 -0
- package/dist/src/decision/acceptance-rollout.js +93 -0
- package/dist/src/decision/acceptance.js +175 -0
- package/dist/src/decision/adapters/jev.js +234 -13
- package/dist/src/decision/adapters/llm-subagent.js +60 -12
- package/dist/src/decision/admission.js +550 -0
- package/dist/src/decision/batch-benchmark.js +47 -0
- package/dist/src/decision/batch-receipts/accounting.js +75 -0
- package/dist/src/decision/batch-receipts/export.js +40 -0
- package/dist/src/decision/batch-receipts/index.js +9 -0
- package/dist/src/decision/batch-receipts/protection.js +40 -0
- package/dist/src/decision/batch-receipts/receipt.js +44 -0
- package/dist/src/decision/batch-receipts/result-store.js +341 -0
- package/dist/src/decision/batch-receipts/store.js +362 -0
- package/dist/src/decision/batch-receipts/types.js +2 -0
- package/dist/src/decision/batch-receipts/validate.js +127 -0
- package/dist/src/decision/batch.js +68 -0
- package/dist/src/decision/calibration/index.js +4 -0
- package/dist/src/decision/calibration/receipts.js +130 -0
- package/dist/src/decision/calibration/registry.js +258 -0
- package/dist/src/decision/calibration/types.js +2 -0
- package/dist/src/decision/compile-cache/benchmark.js +62 -0
- package/dist/src/decision/compile-cache/compatibility.js +65 -0
- package/dist/src/decision/compile-cache/file-store.js +280 -0
- package/dist/src/decision/compile-cache/identity.js +26 -0
- package/dist/src/decision/compile-cache/index.js +9 -0
- package/dist/src/decision/compile-cache/prefix.js +21 -0
- package/dist/src/decision/compile-cache/records.js +86 -0
- package/dist/src/decision/compile-cache/runtime.js +68 -0
- package/dist/src/decision/compile-cache/store.js +108 -0
- package/dist/src/decision/compile-cache/types.js +2 -0
- package/dist/src/decision/context-plan.js +234 -0
- package/dist/src/decision/context-qualification.js +60 -0
- package/dist/src/decision/ensemble/aggregate.js +215 -0
- package/dist/src/decision/ensemble/contract.js +316 -0
- package/dist/src/decision/ensemble/drift.js +51 -0
- package/dist/src/decision/ensemble/index.js +6 -0
- package/dist/src/decision/ensemble/report.js +71 -0
- package/dist/src/decision/ensemble/types.js +2 -0
- package/dist/src/decision/evaluate.js +1024 -78
- package/dist/src/decision/file-lifecycle-store.js +168 -0
- package/dist/src/decision/graph-beam.js +40 -0
- package/dist/src/decision/graph-budget.js +110 -0
- package/dist/src/decision/graph-decision-bridge.js +93 -0
- package/dist/src/decision/graph-evidence.js +123 -0
- package/dist/src/decision/graph-flow-adapter.js +56 -0
- package/dist/src/decision/graph-flow.js +105 -0
- package/dist/src/decision/graph-parallel.js +79 -0
- package/dist/src/decision/graph-patterns.js +20 -0
- package/dist/src/decision/graph-run-store.js +66 -0
- package/dist/src/decision/graph-run.js +166 -0
- package/dist/src/decision/graph-skill-bridge.js +91 -0
- package/dist/src/decision/graph-templates.js +56 -0
- package/dist/src/decision/graph.js +115 -0
- package/dist/src/decision/index.js +35 -0
- package/dist/src/decision/job-accounting.js +93 -0
- package/dist/src/decision/job-contract.js +186 -0
- package/dist/src/decision/job-effects.js +95 -0
- package/dist/src/decision/job-evaluate.js +80 -0
- package/dist/src/decision/job-gateway.js +121 -0
- package/dist/src/decision/job-http.js +194 -0
- package/dist/src/decision/job-payload-store.js +258 -0
- package/dist/src/decision/job-poll-limiter.js +92 -0
- package/dist/src/decision/job-quota.js +158 -0
- package/dist/src/decision/job-runtime.js +240 -0
- package/dist/src/decision/job-scheduler.js +26 -0
- package/dist/src/decision/job-service.js +117 -0
- package/dist/src/decision/job-store.js +264 -0
- package/dist/src/decision/job-worker.js +141 -0
- package/dist/src/decision/lifecycle.js +148 -0
- package/dist/src/decision/patterns/artifacts.js +173 -0
- package/dist/src/decision/patterns/catalog.js +108 -0
- package/dist/src/decision/patterns/durable-review.js +237 -0
- package/dist/src/decision/patterns/index.js +8 -0
- package/dist/src/decision/patterns/playground.js +401 -0
- package/dist/src/decision/patterns/recorded.js +43 -0
- package/dist/src/decision/patterns/specs.js +174 -0
- package/dist/src/decision/patterns/types.js +2 -0
- package/dist/src/decision/portable-secrets.js +53 -0
- package/dist/src/decision/projection.js +210 -0
- package/dist/src/decision/qualification/capture.js +67 -0
- package/dist/src/decision/qualification/drift.js +68 -0
- package/dist/src/decision/qualification/gate-evidence.js +172 -0
- package/dist/src/decision/qualification/gates.js +83 -0
- package/dist/src/decision/qualification/index.js +12 -0
- package/dist/src/decision/qualification/load.js +275 -0
- package/dist/src/decision/qualification/manifest.js +37 -0
- package/dist/src/decision/qualification/privacy.js +41 -0
- package/dist/src/decision/qualification/quality.js +213 -0
- package/dist/src/decision/qualification/release.js +116 -0
- package/dist/src/decision/qualification/runner.js +408 -0
- package/dist/src/decision/qualification/types.js +2 -0
- package/dist/src/decision/receipts.js +30 -7
- package/dist/src/decision/result-cache/index.js +6 -0
- package/dist/src/decision/result-cache/integrity.js +28 -0
- package/dist/src/decision/result-cache/key.js +28 -0
- package/dist/src/decision/result-cache/service.js +92 -0
- package/dist/src/decision/result-cache/store.js +327 -0
- package/dist/src/decision/result-cache/types.js +3 -0
- package/dist/src/decision/review/authorization.js +110 -0
- package/dist/src/decision/review/effect-ledger-adapter.js +321 -0
- package/dist/src/decision/review/index.js +12 -0
- package/dist/src/decision/review/migrate.js +34 -0
- package/dist/src/decision/review/operator-audit.js +59 -0
- package/dist/src/decision/review/recovery-adapters.js +252 -0
- package/dist/src/decision/review/recovery.js +33 -0
- package/dist/src/decision/review/service.js +498 -0
- package/dist/src/decision/review/store.js +219 -0
- package/dist/src/decision/review/types.js +2 -0
- package/dist/src/decision/review/validate.js +205 -0
- package/dist/src/decision/scheduler.js +115 -0
- package/dist/src/decision/telemetry/context.js +42 -0
- package/dist/src/decision/telemetry/debug-sidecar.js +152 -0
- package/dist/src/decision/telemetry/exporter.js +77 -0
- package/dist/src/decision/telemetry/file-debug-backend.js +112 -0
- package/dist/src/decision/telemetry/index.js +13 -0
- package/dist/src/decision/telemetry/mapping.js +146 -0
- package/dist/src/decision/telemetry/metrics.js +164 -0
- package/dist/src/decision/telemetry/otlp-http.js +183 -0
- package/dist/src/decision/telemetry/redaction.js +93 -0
- package/dist/src/decision/telemetry/retention.js +109 -0
- package/dist/src/decision/telemetry/runtime.js +310 -0
- package/dist/src/decision/telemetry/trace.js +158 -0
- package/dist/src/decision/telemetry/types.js +3 -0
- package/dist/src/decision/validate.js +135 -5
- package/dist/src/effects/checkpoint-sinks.js +94 -0
- package/dist/src/effects/checkpoint.js +76 -0
- package/dist/src/effects/decision-links.js +54 -0
- package/dist/src/effects/errors.js +48 -0
- package/dist/src/effects/identity.js +178 -0
- package/dist/src/effects/index.js +25 -0
- package/dist/src/effects/keyring.js +160 -0
- package/dist/src/effects/keys.js +130 -0
- package/dist/src/effects/ledger.js +435 -0
- package/dist/src/effects/lifecycle.js +110 -0
- package/dist/src/effects/lock-recovery.js +269 -0
- package/dist/src/effects/reader.js +103 -0
- package/dist/src/effects/records.js +114 -0
- package/dist/src/effects/redaction.js +51 -0
- package/dist/src/effects/schema.js +73 -0
- package/dist/src/effects/store.js +239 -0
- package/dist/src/effects/types.js +49 -0
- package/dist/src/effects/verifiers/decision.js +168 -0
- package/dist/src/effects/verifiers/file.js +106 -0
- package/dist/src/effects/verifiers/git.js +206 -0
- package/dist/src/effects/verifiers/index.js +90 -0
- package/dist/src/effects/verifiers/registry.js +148 -0
- package/dist/src/effects/verifiers/review.js +123 -0
- package/dist/src/effects/verifiers/tracker.js +299 -0
- package/dist/src/effects/verifiers/types.js +21 -0
- package/dist/src/effects/verify.js +295 -0
- package/dist/src/evidence/bundle.js +2 -0
- package/dist/src/extensions/commands/definitions.js +28 -0
- package/dist/src/extensions/manifest.js +1 -0
- package/dist/src/marketplace/provenance.js +25 -27
- package/dist/src/mcp/cli.mjs +11 -1
- package/dist/src/mcp/grok-build-config.mjs +189 -0
- package/dist/src/mcp/registry.js +21 -1
- package/dist/src/mcp/registry.mjs +20 -1
- package/dist/src/models/grok-build-models.js +356 -0
- package/dist/src/models/index.js +1 -0
- package/dist/src/models/model-capabilities.v1.json +34 -0
- package/dist/src/models/model-catalog.v1.json +55 -13
- package/dist/src/models/model-discovery.js +41 -5
- package/dist/src/models/provider-policy.js +3 -2
- package/dist/src/plugin/skill-command-translator.js +1 -0
- package/dist/src/providers/capability-matrix.yaml +58 -6
- package/dist/src/providers/grok-build-acp.js +192 -0
- package/dist/src/providers/grok-build-dispatch.js +251 -0
- package/dist/src/providers/grok-build-headless.js +170 -0
- package/dist/src/providers/muse-paths.js +105 -0
- package/dist/src/providers/provider-definitions.js +93 -7
- package/dist/src/providers/provider-definitions.mjs +21 -1
- package/dist/src/providers/provider-inventory.js +3 -0
- package/dist/src/security/artifact-attestation.js +4 -8
- package/dist/src/security/signing.js +119 -0
- package/dist/src/sessions/adapters/grok-build.js +187 -0
- package/dist/src/sessions/adapters/muse.js +412 -0
- package/dist/src/sessions/contracts.js +1 -1
- package/dist/src/sessions/grok-build-cli.js +196 -0
- package/dist/src/sessions/index.js +3 -0
- package/dist/src/sessions/workspace-discovery.js +9 -5
- package/dist/src/skills/deployer.js +33 -5
- package/dist/src/smiths/context-pipeline/claude-hook.js +2 -0
- package/dist/src/smiths/context-pipeline/context-file-safety.js +18 -0
- package/dist/src/smiths/context-pipeline/finalization.js +1 -32
- package/dist/src/smiths/context-pipeline/generator.js +12 -0
- package/dist/src/smiths/context-pipeline/index.js +1 -1
- package/dist/src/smiths/context-pipeline/managed-hook.js +2 -0
- package/dist/src/smiths/context-pipeline/muse-bridge.js +50 -0
- package/dist/src/smiths/context-pipeline/provider-policy.js +5 -0
- package/dist/src/smiths/context-pipeline/workspace-context.js +22 -16
- package/dist/src/smiths/hook-bridge/grok-build-translator.js +64 -0
- package/dist/src/smiths/hook-bridge/index.js +3 -0
- package/dist/src/smiths/hook-bridge/shim.js +2 -0
- package/dist/src/smiths/hook-bridge/types.js +5 -0
- package/dist/src/smiths/skillsmith/collision-detector.js +1 -0
- package/dist/src/storage/protected-files.js +102 -0
- package/dist/src/tracker/forge-http.js +371 -0
- package/dist/src/tracker/project-inputs.js +41 -0
- package/package.json +2 -1
- package/schemas/decision/BatchReceipt.v1.schema.json +50 -0
- package/schemas/decision/CalibrationArtifact.v1.schema.json +76 -0
- package/schemas/decision/CalibrationCompatibility.v1.schema.json +18 -0
- package/schemas/decision/CalibrationGovernanceReceipt.v1.schema.json +44 -0
- package/schemas/decision/DecisionAdmissionEvidence.v1.schema.json +43 -0
- package/schemas/decision/DecisionBinding.schema.json +309 -0
- package/schemas/decision/DecisionBinding.v1alpha2.schema.json +369 -0
- package/schemas/decision/DecisionCacheTelemetry.v1.schema.json +20 -0
- package/schemas/decision/DecisionChampionChallenger.v1.schema.json +100 -0
- package/schemas/decision/DecisionCompileCacheEntry.v1.schema.json +35 -0
- package/schemas/decision/DecisionCompileCacheIdentity.v1.schema.json +26 -0
- package/schemas/decision/DecisionCompileCacheTombstone.v1.schema.json +31 -0
- package/schemas/decision/DecisionContextEvidence.v1.schema.json +136 -0
- package/schemas/decision/DecisionDefinition.schema.json +159 -0
- package/schemas/decision/DecisionDefinition.v1alpha2.schema.json +203 -0
- package/schemas/decision/DecisionDriftResponse.v1.schema.json +55 -0
- package/schemas/decision/DecisionEnsembleAggregate.v1.schema.json +86 -0
- package/schemas/decision/DecisionEnsembleIntegrityReport.v1.schema.json +64 -0
- package/schemas/decision/DecisionEnsemblePolicy.v1.schema.json +130 -0
- package/schemas/decision/DecisionGraph.v1.schema.json +77 -0
- package/schemas/decision/DecisionJob.v1.schema.json +71 -0
- package/schemas/decision/DecisionLifecyclePolicy.v1.schema.json +52 -0
- package/schemas/decision/DecisionProjectionPolicy.v1.schema.json +65 -0
- package/schemas/decision/DecisionProviderPrefixCompatibility.v1.schema.json +45 -0
- package/schemas/decision/DecisionProviderPrefixEvidence.v1.schema.json +17 -0
- package/schemas/decision/DecisionProviderPrefixIdentity.v1.schema.json +36 -0
- package/schemas/decision/DecisionResult.schema.json +524 -0
- package/schemas/decision/DecisionResult.v1alpha2.schema.json +619 -0
- package/schemas/decision/DecisionResultCacheEntry.v1.schema.json +53 -0
- package/schemas/decision/DecisionReview.schema.json +29 -0
- package/schemas/decision/DecisionRuleset.schema.json +313 -0
- package/schemas/decision/DecisionRuleset.v1alpha2.schema.json +313 -0
- package/schemas/decision/DecisionTelemetryTrace.v1.schema.json +95 -0
- package/schemas/decision/RulesetResult.schema.json +721 -0
- package/schemas/decision/RulesetResult.v1alpha2.schema.json +891 -0
- package/schemas/security/pr-evidence-receipt.v1.schema.json +77 -0
- package/schemas/security/threat-assessment-report.v1.schema.json +71 -1
- package/tools/agents/deploy-agents.mjs +21 -6
- package/tools/agents/providers/base.mjs +7 -4
- package/tools/agents/providers/codex.mjs +1 -1
- package/tools/agents/providers/grok-build.d.mts +7 -0
- package/tools/agents/providers/grok-build.mjs +249 -9
- package/tools/agents/providers/model-role.mjs +6 -3
- package/tools/agents/providers/muse-hooks.mjs +785 -0
- package/tools/agents/providers/muse-paths.mjs +112 -0
- package/tools/agents/providers/muse.mjs +336 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grok Build model/config discovery.
|
|
3
|
+
*
|
|
4
|
+
* `grok inspect --json` is authoritative for active config sources. We read only
|
|
5
|
+
* model-selection fields from those reported files because current InspectReport
|
|
6
|
+
* versions do not expose effective model values. Secret-bearing fields are reduced
|
|
7
|
+
* to credential availability or header names and never leave this module.
|
|
8
|
+
*
|
|
9
|
+
* @issue #2579
|
|
10
|
+
*/
|
|
11
|
+
import { readFile } from 'node:fs/promises';
|
|
12
|
+
import { homedir, tmpdir } from 'node:os';
|
|
13
|
+
import { resolveGrokHomeResult } from '../providers/grok-build-paths.js';
|
|
14
|
+
import { classifyDiscoveryError, runModelDiscoveryCommand } from './model-discovery.js';
|
|
15
|
+
const MAX_CONFIG_BYTES = 1024 * 1024;
|
|
16
|
+
const PROJECT_ALLOWED = new Set(['mcp_servers', 'plugins', 'permission', 'mcp']);
|
|
17
|
+
function unquote(value) {
|
|
18
|
+
const text = value.trim();
|
|
19
|
+
if (text.startsWith('"') && text.endsWith('"')) {
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(text);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (text.startsWith("'") && text.endsWith("'"))
|
|
28
|
+
return text.slice(1, -1);
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
function stringArray(value) {
|
|
32
|
+
const text = value.trim();
|
|
33
|
+
if (!text.startsWith('[') || !text.endsWith(']'))
|
|
34
|
+
return undefined;
|
|
35
|
+
const matches = [...text.matchAll(/"((?:\\.|[^"\\])*)"|'([^']*)'/g)];
|
|
36
|
+
return matches.map(match => match[1] !== undefined
|
|
37
|
+
? JSON.parse(`"${match[1]}"`)
|
|
38
|
+
: match[2]);
|
|
39
|
+
}
|
|
40
|
+
function tableName(line) {
|
|
41
|
+
const match = line.match(/^\s*\[([^\]]+)]\s*(?:#.*)?$/);
|
|
42
|
+
return match?.[1]?.trim();
|
|
43
|
+
}
|
|
44
|
+
function modelAlias(table) {
|
|
45
|
+
const match = table.match(/^model\.(?:"((?:\\.|[^"\\])*)"|'([^']*)'|([A-Za-z0-9_.-]+))$/);
|
|
46
|
+
if (!match)
|
|
47
|
+
return undefined;
|
|
48
|
+
return match[1] !== undefined ? JSON.parse(`"${match[1]}"`) : (match[2] ?? match[3]);
|
|
49
|
+
}
|
|
50
|
+
function mapKeys(value) {
|
|
51
|
+
const body = value.trim().replace(/^\{/, '').replace(/}$/, '');
|
|
52
|
+
return [...body.matchAll(/(?:^|,)\s*(?:"([^"]+)"|'([^']+)'|([A-Za-z0-9_-]+))\s*=/g)]
|
|
53
|
+
.map(match => match[1] ?? match[2] ?? match[3])
|
|
54
|
+
.filter(Boolean);
|
|
55
|
+
}
|
|
56
|
+
/** Parse only non-secret fields needed for model discovery. */
|
|
57
|
+
export function parseGrokBuildModelConfig(text, scope) {
|
|
58
|
+
const parsed = { models: new Map(), projectModelFields: false };
|
|
59
|
+
let table = '';
|
|
60
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
61
|
+
const nextTable = tableName(raw);
|
|
62
|
+
if (nextTable !== undefined) {
|
|
63
|
+
table = nextTable;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const match = raw.match(/^\s*([A-Za-z0-9_-]+)\s*=\s*(.*?)\s*(?:#.*)?$/);
|
|
67
|
+
if (!match)
|
|
68
|
+
continue;
|
|
69
|
+
const [, key, value] = match;
|
|
70
|
+
const top = table.split('.', 1)[0];
|
|
71
|
+
if (scope === 'project' && !PROJECT_ALLOWED.has(top)) {
|
|
72
|
+
if (top === 'models' || top === 'model')
|
|
73
|
+
parsed.projectModelFields = true;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (table === 'models') {
|
|
77
|
+
if (key === 'default')
|
|
78
|
+
parsed.defaultModel = unquote(value);
|
|
79
|
+
else if (key === 'allowed_models')
|
|
80
|
+
parsed.allowedModels = stringArray(value);
|
|
81
|
+
else if (key === 'disabled_models')
|
|
82
|
+
parsed.disabledModels = stringArray(value);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const alias = modelAlias(table);
|
|
86
|
+
if (!alias)
|
|
87
|
+
continue;
|
|
88
|
+
const model = parsed.models.get(alias) ?? {
|
|
89
|
+
alias, envKeys: [], hasInlineCredential: false, headerNames: [],
|
|
90
|
+
};
|
|
91
|
+
if (key === 'model')
|
|
92
|
+
model.model = unquote(value);
|
|
93
|
+
else if (key === 'name')
|
|
94
|
+
model.name = unquote(value);
|
|
95
|
+
else if (key === 'base_url' || key === 'api_base_url')
|
|
96
|
+
model.baseUrl = unquote(value);
|
|
97
|
+
else if (key === 'env_key')
|
|
98
|
+
model.envKeys = unquote(value) ? [unquote(value)] : (stringArray(value) ?? []);
|
|
99
|
+
else if (key === 'api_key')
|
|
100
|
+
model.hasInlineCredential = Boolean(unquote(value));
|
|
101
|
+
else if (key === 'extra_headers' || key === 'env_http_headers')
|
|
102
|
+
model.headerNames.push(...mapKeys(value));
|
|
103
|
+
else if (key === 'hidden')
|
|
104
|
+
model.hidden = value.trim() === 'true';
|
|
105
|
+
else if (key === 'context_window')
|
|
106
|
+
model.contextWindow = Number(value.trim()) || undefined;
|
|
107
|
+
else if (key === 'supports_backend_search')
|
|
108
|
+
model.supportsBackendSearch = value.trim() === 'true';
|
|
109
|
+
else if (key === 'reasoning_efforts')
|
|
110
|
+
model.reasoningEfforts = stringArray(value);
|
|
111
|
+
parsed.models.set(alias, model);
|
|
112
|
+
}
|
|
113
|
+
return parsed;
|
|
114
|
+
}
|
|
115
|
+
function inspectLayers(report) {
|
|
116
|
+
const sources = (report.configSources ?? report.config_sources);
|
|
117
|
+
if (!sources || !Array.isArray(sources.layers))
|
|
118
|
+
return [];
|
|
119
|
+
return sources.layers.flatMap((entry, index) => {
|
|
120
|
+
if (!entry || typeof entry !== 'object')
|
|
121
|
+
return [];
|
|
122
|
+
const item = entry;
|
|
123
|
+
return typeof item.role === 'string' && typeof item.path === 'string'
|
|
124
|
+
? [{ role: item.role, path: item.path, ...(typeof item.note === 'string' ? { note: item.note } : {}), precedence: index + 1 }]
|
|
125
|
+
: [];
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function inspectModels(report) {
|
|
129
|
+
const candidates = [report.models, report.modelCatalog, report.model_catalog]
|
|
130
|
+
.find(Array.isArray);
|
|
131
|
+
if (!candidates)
|
|
132
|
+
return [];
|
|
133
|
+
return candidates.flatMap(entry => {
|
|
134
|
+
if (typeof entry === 'string')
|
|
135
|
+
return [{ id: entry, alias: entry }];
|
|
136
|
+
if (!entry || typeof entry !== 'object')
|
|
137
|
+
return [];
|
|
138
|
+
const model = entry;
|
|
139
|
+
const alias = [model.alias, model.key, model.id].find(value => typeof value === 'string');
|
|
140
|
+
if (!alias)
|
|
141
|
+
return [];
|
|
142
|
+
return [{
|
|
143
|
+
id: alias,
|
|
144
|
+
alias,
|
|
145
|
+
...(typeof model.name === 'string' ? { displayName: model.name } : {}),
|
|
146
|
+
...(model.default === true || model.isDefault === true ? { isDefault: true } : {}),
|
|
147
|
+
...(model.hidden === true ? { hidden: true } : {}),
|
|
148
|
+
...(Array.isArray(model.reasoningEfforts)
|
|
149
|
+
? { reasoningEfforts: model.reasoningEfforts.filter((item) => typeof item === 'string') }
|
|
150
|
+
: {}),
|
|
151
|
+
}];
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
function setSelected(selected, key, value, layer, constraint) {
|
|
155
|
+
if (value === undefined)
|
|
156
|
+
return;
|
|
157
|
+
selected[key] = { value, source: layer.path, scope: layer.role, precedence: layer.precedence, ...(constraint ? { constraint } : {}) };
|
|
158
|
+
}
|
|
159
|
+
function globMatches(pattern, value) {
|
|
160
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*').replace(/\?/g, '.');
|
|
161
|
+
return new RegExp(`^${escaped}$`).test(value);
|
|
162
|
+
}
|
|
163
|
+
function dedupe(models) {
|
|
164
|
+
return [...new Map(models.map(model => [model.alias ?? model.id, model])).values()];
|
|
165
|
+
}
|
|
166
|
+
function parseEnvOverlay(env) {
|
|
167
|
+
let content;
|
|
168
|
+
try {
|
|
169
|
+
content = JSON.parse(env.GROK_CONFIG ?? '');
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
if (!content || typeof content !== 'object' || Array.isArray(content))
|
|
175
|
+
return null;
|
|
176
|
+
const value = content;
|
|
177
|
+
const parsed = { models: new Map(), projectModelFields: false };
|
|
178
|
+
const settings = value.models;
|
|
179
|
+
if (settings && typeof settings === 'object' && !Array.isArray(settings)) {
|
|
180
|
+
const table = settings;
|
|
181
|
+
if (typeof table.default === 'string')
|
|
182
|
+
parsed.defaultModel = table.default;
|
|
183
|
+
if (Array.isArray(table.allowed_models) && table.allowed_models.every(entry => typeof entry === 'string'))
|
|
184
|
+
parsed.allowedModels = table.allowed_models;
|
|
185
|
+
if (Array.isArray(table.disabled_models) && table.disabled_models.every(entry => typeof entry === 'string'))
|
|
186
|
+
parsed.disabledModels = table.disabled_models;
|
|
187
|
+
}
|
|
188
|
+
// The host allowlists env-overlay sections; per-model secrets and model definitions
|
|
189
|
+
// are intentionally not imported from arbitrary JSON here.
|
|
190
|
+
return parsed;
|
|
191
|
+
}
|
|
192
|
+
async function readLayer(layer) {
|
|
193
|
+
if (layer.path.startsWith('$') || layer.path.includes('(inline)'))
|
|
194
|
+
return null;
|
|
195
|
+
try {
|
|
196
|
+
const text = await readFile(layer.path, 'utf8');
|
|
197
|
+
if (Buffer.byteLength(text) > MAX_CONFIG_BYTES)
|
|
198
|
+
return null;
|
|
199
|
+
return parseGrokBuildModelConfig(text, layer.role === 'project' ? 'project' : layer.role);
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
export async function discoverGrokBuildModels(options = {}) {
|
|
206
|
+
const command = options.command ?? 'grok';
|
|
207
|
+
const runner = options.runner ?? runModelDiscoveryCommand;
|
|
208
|
+
const cwd = options.cwd ?? tmpdir();
|
|
209
|
+
const env = options.env ?? process.env;
|
|
210
|
+
const observedAt = new Date().toISOString();
|
|
211
|
+
const base = {
|
|
212
|
+
provider: 'grok-build', source: 'native', observedAt,
|
|
213
|
+
accountScope: 'local-runtime', models: [],
|
|
214
|
+
};
|
|
215
|
+
let report = options.inspectReport;
|
|
216
|
+
let runtimeVersion;
|
|
217
|
+
if (!report) {
|
|
218
|
+
const [version, result] = await Promise.all([
|
|
219
|
+
runner(command, ['--version'], { cwd, timeoutMs: 5_000, env }),
|
|
220
|
+
runner(command, ['inspect', '--json'], { cwd, timeoutMs: 15_000, env }),
|
|
221
|
+
]);
|
|
222
|
+
runtimeVersion = version.exitCode === 0 ? version.stdout.trim().split(/\r?\n/, 1)[0] : undefined;
|
|
223
|
+
if (result.exitCode !== 0) {
|
|
224
|
+
// Native stderr can include arbitrary headers, API keys and endpoint URLs.
|
|
225
|
+
// Classify it, but never echo untrusted command output into audit/receipts.
|
|
226
|
+
const detail = result.stderr || result.stdout;
|
|
227
|
+
return { ...base, ...(runtimeVersion ? { runtimeVersion } : {}),
|
|
228
|
+
errorKind: result.exitCode === 124 ? 'timeout' : classifyDiscoveryError(detail),
|
|
229
|
+
error: `Grok Build inspect failed (exit ${result.exitCode}); check CLI version, config layers and credentials locally.` };
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
const parsed = JSON.parse(result.stdout);
|
|
233
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
234
|
+
throw new Error('object expected');
|
|
235
|
+
report = parsed;
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
return { ...base, ...(runtimeVersion ? { runtimeVersion } : {}), errorKind: 'invalid-output',
|
|
239
|
+
error: 'Grok Build inspect returned an unsupported JSON shape; update Grok Build or AIWG.' };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const layers = inspectLayers(report);
|
|
243
|
+
if (layers.length === 0 && !Object.keys(report).some(key => ['models', 'modelCatalog', 'model_catalog'].includes(key))) {
|
|
244
|
+
return { ...base, ...(runtimeVersion ? { runtimeVersion } : {}), errorKind: 'invalid-output',
|
|
245
|
+
error: 'Grok Build inspect JSON omitted configSources; update Grok Build or AIWG.' };
|
|
246
|
+
}
|
|
247
|
+
const diagnostics = [];
|
|
248
|
+
const selected = {};
|
|
249
|
+
const constraints = [];
|
|
250
|
+
const discovered = inspectModels(report);
|
|
251
|
+
const parsedByLayer = await Promise.all(layers.map(layer => layer.role === 'env_overlay'
|
|
252
|
+
&& layer.path.includes('(inline)') ? parseEnvOverlay(env) : readLayer(layer)));
|
|
253
|
+
let requirementsDefault;
|
|
254
|
+
let requirementsAllowed;
|
|
255
|
+
for (let i = 0; i < layers.length; i++) {
|
|
256
|
+
const layer = layers[i];
|
|
257
|
+
const parsed = parsedByLayer[i];
|
|
258
|
+
if (!parsed)
|
|
259
|
+
continue;
|
|
260
|
+
if (parsed.projectModelFields)
|
|
261
|
+
diagnostics.push(`${layer.path}: ignored model settings because Grok Build project scope does not allow them`);
|
|
262
|
+
const requirement = /requirements|mdm/i.test(layer.role);
|
|
263
|
+
setSelected(selected, 'models.default', parsed.defaultModel, layer, requirement ? 'pin' : undefined);
|
|
264
|
+
setSelected(selected, 'models.allowed_models', parsed.allowedModels, layer, requirement ? 'allowlist' : undefined);
|
|
265
|
+
setSelected(selected, 'models.disabled_models', parsed.disabledModels, layer);
|
|
266
|
+
if (requirement && parsed.defaultModel)
|
|
267
|
+
requirementsDefault = selected['models.default'];
|
|
268
|
+
if (requirement && parsed.allowedModels)
|
|
269
|
+
requirementsAllowed = selected['models.allowed_models'];
|
|
270
|
+
if (requirement && parsed.defaultModel)
|
|
271
|
+
constraints.push({ key: 'models.default', source: layer.path, precedence: layer.precedence, kind: 'pin' });
|
|
272
|
+
if (requirement && parsed.allowedModels)
|
|
273
|
+
constraints.push({ key: 'models.allowed_models', source: layer.path, precedence: layer.precedence, kind: 'allowlist' });
|
|
274
|
+
for (const model of parsed.models.values()) {
|
|
275
|
+
setSelected(selected, `model.${model.alias}.alias`, model.alias, layer);
|
|
276
|
+
setSelected(selected, `model.${model.alias}.model`, model.model, layer);
|
|
277
|
+
setSelected(selected, `model.${model.alias}.name`, model.name, layer);
|
|
278
|
+
setSelected(selected, `model.${model.alias}.context_window`, model.contextWindow, layer);
|
|
279
|
+
setSelected(selected, `model.${model.alias}.supports_backend_search`, model.supportsBackendSearch, layer);
|
|
280
|
+
const credentialState = model.hasInlineCredential
|
|
281
|
+
|| model.envKeys.some(key => Boolean(env[key])) ? 'available'
|
|
282
|
+
: model.envKeys.length > 0 ? 'unavailable' : 'session';
|
|
283
|
+
discovered.push({
|
|
284
|
+
id: model.alias,
|
|
285
|
+
alias: model.alias,
|
|
286
|
+
...(model.model ? { apiModelId: model.model } : {}),
|
|
287
|
+
...(model.name ? { displayName: model.name } : {}),
|
|
288
|
+
...(model.hidden !== undefined ? { hidden: model.hidden } : {}),
|
|
289
|
+
...(model.reasoningEfforts ? { reasoningEfforts: model.reasoningEfforts } : {}),
|
|
290
|
+
capabilities: [
|
|
291
|
+
...(model.contextWindow ? [`context:${model.contextWindow}`] : []),
|
|
292
|
+
...(model.supportsBackendSearch ? ['backend-search'] : []),
|
|
293
|
+
...(model.baseUrl ? ['custom-endpoint'] : []),
|
|
294
|
+
...model.headerNames.map(name => `header:${name}`),
|
|
295
|
+
],
|
|
296
|
+
credentialState,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const homeResult = resolveGrokHomeResult(env, env.HOME ?? env.USERPROFILE ?? homedir());
|
|
301
|
+
if (!homeResult.ok)
|
|
302
|
+
diagnostics.push(homeResult.message);
|
|
303
|
+
const envDefault = env.GROK_DEFAULT_MODEL?.trim();
|
|
304
|
+
if (envDefault && !requirementsDefault) {
|
|
305
|
+
const layer = { role: 'environment', path: 'GROK_DEFAULT_MODEL', precedence: layers.length + 1 };
|
|
306
|
+
setSelected(selected, 'models.default', envDefault, layer);
|
|
307
|
+
}
|
|
308
|
+
if (requirementsDefault)
|
|
309
|
+
selected['models.default'] = requirementsDefault;
|
|
310
|
+
if (requirementsAllowed)
|
|
311
|
+
selected['models.allowed_models'] = requirementsAllowed;
|
|
312
|
+
let models = dedupe(discovered);
|
|
313
|
+
const defaultAlias = selected['models.default']?.value;
|
|
314
|
+
if (typeof defaultAlias === 'string' && !models.some(model => (model.alias ?? model.id) === defaultAlias)) {
|
|
315
|
+
models.push({ id: defaultAlias, alias: defaultAlias, credentialState: 'session' });
|
|
316
|
+
}
|
|
317
|
+
const disabled = selected['models.disabled_models']?.value;
|
|
318
|
+
if (Array.isArray(disabled))
|
|
319
|
+
models = models.filter(model => !disabled.includes(model.alias ?? model.id));
|
|
320
|
+
const allowed = selected['models.allowed_models']?.value;
|
|
321
|
+
if (Array.isArray(allowed) && allowed.length > 0) {
|
|
322
|
+
models = models.filter(model => allowed.some(pattern => globMatches(pattern, model.alias ?? model.id)));
|
|
323
|
+
}
|
|
324
|
+
models = models.map(model => ({ ...model, isDefault: (model.alias ?? model.id) === defaultAlias }));
|
|
325
|
+
if (models.some(model => model.credentialState === 'unavailable')) {
|
|
326
|
+
diagnostics.push('One or more configured models lack their named credential environment variable; secret values were not read into output.');
|
|
327
|
+
}
|
|
328
|
+
return {
|
|
329
|
+
...base,
|
|
330
|
+
...(runtimeVersion ? { runtimeVersion } : {}),
|
|
331
|
+
models,
|
|
332
|
+
policy: {
|
|
333
|
+
layers: layers.map(layer => ({ scope: layer.role, source: layer.path, precedence: layer.precedence,
|
|
334
|
+
policyConstraint: /requirements|mdm/i.test(layer.role) })),
|
|
335
|
+
selected,
|
|
336
|
+
constraints,
|
|
337
|
+
diagnostics,
|
|
338
|
+
},
|
|
339
|
+
...(models.length === 0 ? { errorKind: 'invalid-output',
|
|
340
|
+
error: 'Grok Build exposed no model aliases. Configure [models].default or [model.<alias>] in $GROK_HOME/config.toml; AIWG will not fabricate an xAI model ID.' } : {}),
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
/** Resolve aliases only from the observed catalog. Exact API model ids are never synthesized. */
|
|
344
|
+
export function resolveGrokBuildRoleModel(catalog, role, mappings = {}, explicit) {
|
|
345
|
+
const available = new Set(catalog.models.map(model => model.alias ?? model.id));
|
|
346
|
+
const requested = explicit ?? mappings[role];
|
|
347
|
+
if (requested) {
|
|
348
|
+
if (available.has(requested))
|
|
349
|
+
return { role, model: requested, source: explicit ? 'explicit' : 'project-policy' };
|
|
350
|
+
return { role, source: 'unresolved', diagnostic: `Grok Build model alias "${requested}" is unavailable for ${role}; choose an alias reported by grok inspect/config discovery. No xAI model ID was substituted.` };
|
|
351
|
+
}
|
|
352
|
+
if (available.size === 1)
|
|
353
|
+
return { role, model: [...available][0], source: 'single-model-fallback' };
|
|
354
|
+
return { role, source: 'unresolved', diagnostic: `Grok Build ${role} role has no mapping and ${available.size} models are available; configure an explicit alias in models.json. No xAI model ID was guessed.` };
|
|
355
|
+
}
|
|
356
|
+
//# sourceMappingURL=grok-build-models.js.map
|
package/dist/src/models/index.js
CHANGED
|
@@ -18,5 +18,6 @@ export { ConfigLoader } from './config-loader.js';
|
|
|
18
18
|
export { ModelResolver } from './resolver.js';
|
|
19
19
|
// Export provider-neutral runtime tier routing primitive
|
|
20
20
|
export { routeModelTier } from './router.js';
|
|
21
|
+
export { discoverGrokBuildModels, parseGrokBuildModelConfig, resolveGrokBuildRoleModel, } from './grok-build-models.js';
|
|
21
22
|
export { compileModelPolicy, loadProviderModelCapabilities, loadProviderModelCatalog, renderCodexAgentToml, resetModelPolicyCachesForTests, validateCanonicalModelPolicy, validateUserProjectModelConfig, } from './provider-policy.js';
|
|
22
23
|
//# sourceMappingURL=index.js.map
|
|
@@ -228,6 +228,19 @@
|
|
|
228
228
|
"sourceUrl": "https://github.com/jmagly/aiwg/blob/main/docs/architecture/adr-grokbot-provider-target.md",
|
|
229
229
|
"verifiedAt": "2026-09-15"
|
|
230
230
|
},
|
|
231
|
+
"grok-build": {
|
|
232
|
+
"agent": "inherited",
|
|
233
|
+
"skill": "inherited",
|
|
234
|
+
"globalChild": "native",
|
|
235
|
+
"identifierSyntax": "Provider-local alias from grok inspect and $GROK_HOME config; distinct from API model id",
|
|
236
|
+
"inheritance": "Agent and skill roles resolve through the session model unless a validated Grok Build alias is selected",
|
|
237
|
+
"invalidPinFallback": "Report the unavailable alias; use the sole discovered model only when exactly one is available",
|
|
238
|
+
"configTarget": "$GROK_HOME/config.toml [models] and [model.<alias>] (read-only discovery)",
|
|
239
|
+
"artifactFormat": "Grok Build model alias",
|
|
240
|
+
"verification": "grok inspect --json plus bounded parsing of model fields from reported config layers",
|
|
241
|
+
"sourceUrl": "https://docs.x.ai/build/settings",
|
|
242
|
+
"verifiedAt": "2026-09-21"
|
|
243
|
+
},
|
|
231
244
|
"hermes": {
|
|
232
245
|
"agent": "global-only",
|
|
233
246
|
"skill": "unsupported",
|
|
@@ -253,6 +266,27 @@
|
|
|
253
266
|
"verification": "Parse against OpenHuman definition schema",
|
|
254
267
|
"sourceUrl": "https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/harness/definition.rs",
|
|
255
268
|
"verifiedAt": "2026-07-20"
|
|
269
|
+
},
|
|
270
|
+
"muse": {
|
|
271
|
+
"agent": "unsupported",
|
|
272
|
+
"skill": "unsupported",
|
|
273
|
+
"globalChild": "informational",
|
|
274
|
+
"identifierSyntax": "Meta provider catalog model_id (Muse Code 1.4.0: muse-spark-1.3 current, muse-spark-1.3-contributor default, muse-spark-1.2, muse-spark-1.2-contributor), passed as muse exec --model",
|
|
275
|
+
"inheritance": "The session model comes from --model, else settings.json `model`, else the provider catalog default; per-agent and per-skill pins are not verified",
|
|
276
|
+
"invalidPinFallback": "muse exits 1 with run.terminal.failed (\"model `<id>` does not exist or you lack access\"); never falls back to another model",
|
|
277
|
+
"configTarget": "$XDG_CONFIG_HOME/muse/settings.json `model` (read-only; AIWG never writes it)",
|
|
278
|
+
"artifactFormat": "Meta provider model id (session-level only)",
|
|
279
|
+
"verification": "muse exec --json --model <id> emits run.model.configured with model_id; observed muse-spark-1.3 and muse-spark-1.3-contributor in native session logs on Muse Code 1.4.0",
|
|
280
|
+
"sourceUrl": "https://github.com/jmagly/aiwg/blob/main/docs/architecture/adr-muse-provider-target.md",
|
|
281
|
+
"verifiedAt": "2026-09-25",
|
|
282
|
+
"effortValues": [
|
|
283
|
+
"minimal",
|
|
284
|
+
"low",
|
|
285
|
+
"medium",
|
|
286
|
+
"high",
|
|
287
|
+
"xhigh",
|
|
288
|
+
"max"
|
|
289
|
+
]
|
|
256
290
|
}
|
|
257
291
|
}
|
|
258
292
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "../../../schemas/models/model-catalog.v1.schema.json",
|
|
3
3
|
"version": "1.0.0",
|
|
4
|
-
"refreshedAt": "2026-
|
|
4
|
+
"refreshedAt": "2026-09-21",
|
|
5
5
|
"staleAfterDays": 90,
|
|
6
6
|
"providers": {
|
|
7
7
|
"antigravity": {
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
"claude": {
|
|
29
29
|
"roles": {
|
|
30
30
|
"reasoning": {
|
|
31
|
-
"id": "claude-opus-
|
|
31
|
+
"id": "claude-opus-5",
|
|
32
32
|
"status": "active",
|
|
33
33
|
"observed": false
|
|
34
34
|
},
|
|
35
35
|
"coding": {
|
|
36
|
-
"id": "claude-sonnet-
|
|
36
|
+
"id": "claude-sonnet-5",
|
|
37
37
|
"status": "active",
|
|
38
38
|
"observed": false
|
|
39
39
|
},
|
|
@@ -43,29 +43,29 @@
|
|
|
43
43
|
"observed": false
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
|
-
"sourceUrl": "https://
|
|
47
|
-
"verifiedAt": "2026-
|
|
46
|
+
"sourceUrl": "https://platform.claude.com/docs/en/about-claude/models/overview",
|
|
47
|
+
"verifiedAt": "2026-09-21"
|
|
48
48
|
},
|
|
49
49
|
"codex": {
|
|
50
50
|
"roles": {
|
|
51
51
|
"reasoning": {
|
|
52
|
-
"id": "gpt-5.
|
|
52
|
+
"id": "gpt-5.6-sol",
|
|
53
53
|
"status": "active",
|
|
54
54
|
"observed": true
|
|
55
55
|
},
|
|
56
56
|
"coding": {
|
|
57
|
-
"id": "gpt-5.
|
|
57
|
+
"id": "gpt-5.6-terra",
|
|
58
58
|
"status": "active",
|
|
59
59
|
"observed": true
|
|
60
60
|
},
|
|
61
61
|
"efficiency": {
|
|
62
|
-
"id": "gpt-5.
|
|
62
|
+
"id": "gpt-5.6-luna",
|
|
63
63
|
"status": "active",
|
|
64
64
|
"observed": true
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
|
-
"sourceUrl": "https://learn.chatgpt.com/docs/
|
|
68
|
-
"verifiedAt": "2026-
|
|
67
|
+
"sourceUrl": "https://learn.chatgpt.com/docs/models",
|
|
68
|
+
"verifiedAt": "2026-09-21"
|
|
69
69
|
},
|
|
70
70
|
"copilot": {
|
|
71
71
|
"roles": {
|
|
@@ -133,12 +133,12 @@
|
|
|
133
133
|
"opencode": {
|
|
134
134
|
"roles": {
|
|
135
135
|
"reasoning": {
|
|
136
|
-
"id": "anthropic/claude-opus-
|
|
136
|
+
"id": "anthropic/claude-opus-5",
|
|
137
137
|
"status": "unverified",
|
|
138
138
|
"observed": false
|
|
139
139
|
},
|
|
140
140
|
"coding": {
|
|
141
|
-
"id": "anthropic/claude-sonnet-
|
|
141
|
+
"id": "anthropic/claude-sonnet-5",
|
|
142
142
|
"status": "unverified",
|
|
143
143
|
"observed": false
|
|
144
144
|
},
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
}
|
|
150
150
|
},
|
|
151
151
|
"sourceUrl": "https://opencode.ai/docs/models",
|
|
152
|
-
"verifiedAt": "2026-
|
|
152
|
+
"verifiedAt": "2026-09-21"
|
|
153
153
|
},
|
|
154
154
|
"omp": {
|
|
155
155
|
"roles": {
|
|
@@ -298,6 +298,27 @@
|
|
|
298
298
|
"sourceUrl": "https://github.com/jmagly/aiwg/blob/main/docs/architecture/adr-grokbot-provider-target.md",
|
|
299
299
|
"verifiedAt": "2026-09-15"
|
|
300
300
|
},
|
|
301
|
+
"grok-build": {
|
|
302
|
+
"roles": {
|
|
303
|
+
"reasoning": {
|
|
304
|
+
"id": "configured/reasoning",
|
|
305
|
+
"status": "unverified",
|
|
306
|
+
"observed": false
|
|
307
|
+
},
|
|
308
|
+
"coding": {
|
|
309
|
+
"id": "configured/coding",
|
|
310
|
+
"status": "unverified",
|
|
311
|
+
"observed": false
|
|
312
|
+
},
|
|
313
|
+
"efficiency": {
|
|
314
|
+
"id": "configured/efficiency",
|
|
315
|
+
"status": "unverified",
|
|
316
|
+
"observed": false
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
"sourceUrl": "https://docs.x.ai/build/settings",
|
|
320
|
+
"verifiedAt": "2026-09-21"
|
|
321
|
+
},
|
|
301
322
|
"hermes": {
|
|
302
323
|
"roles": {
|
|
303
324
|
"reasoning": {
|
|
@@ -339,6 +360,27 @@
|
|
|
339
360
|
},
|
|
340
361
|
"sourceUrl": "https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/harness/definition.rs",
|
|
341
362
|
"verifiedAt": "2026-07-20"
|
|
363
|
+
},
|
|
364
|
+
"muse": {
|
|
365
|
+
"roles": {
|
|
366
|
+
"reasoning": {
|
|
367
|
+
"id": "muse-spark-1.3",
|
|
368
|
+
"status": "active",
|
|
369
|
+
"observed": true
|
|
370
|
+
},
|
|
371
|
+
"coding": {
|
|
372
|
+
"id": "muse-spark-1.3",
|
|
373
|
+
"status": "active",
|
|
374
|
+
"observed": true
|
|
375
|
+
},
|
|
376
|
+
"efficiency": {
|
|
377
|
+
"id": "muse-spark-1.3",
|
|
378
|
+
"status": "active",
|
|
379
|
+
"observed": true
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
"sourceUrl": "https://dev.meta.ai/docs/models",
|
|
383
|
+
"verifiedAt": "2026-09-25"
|
|
342
384
|
}
|
|
343
385
|
}
|
|
344
386
|
}
|
|
@@ -46,6 +46,13 @@ export const PROVIDER_DISCOVERY_DECISIONS = {
|
|
|
46
46
|
reason: 'Grok Bot is a desktop multi-agent runtime with no verified non-interactive model-list command; AIWG does not invent xAI/Grok API enumeration as Grok Bot entitlement.',
|
|
47
47
|
documentation: 'https://github.com/jmagly/aiwg/blob/main/docs/architecture/adr-grokbot-provider-target.md',
|
|
48
48
|
},
|
|
49
|
+
'grok-build': {
|
|
50
|
+
provider: 'grok-build',
|
|
51
|
+
status: 'native',
|
|
52
|
+
interface: 'grok inspect --json plus bounded model fields from reported config sources',
|
|
53
|
+
reason: 'Inspect is the authority for active configuration layers; current releases require reading only model-selection fields from those files.',
|
|
54
|
+
documentation: 'https://docs.x.ai/build/settings',
|
|
55
|
+
},
|
|
49
56
|
hermes: {
|
|
50
57
|
provider: 'hermes',
|
|
51
58
|
status: 'unsupported',
|
|
@@ -53,6 +60,13 @@ export const PROVIDER_DISCOVERY_DECISIONS = {
|
|
|
53
60
|
reason: 'hermes model is interactive; the optional API server /v1/models endpoint requires a separately running service and represents that service rather than local CLI entitlement.',
|
|
54
61
|
documentation: 'https://hermes-agent.nousresearch.com/docs/reference/cli-commands',
|
|
55
62
|
},
|
|
63
|
+
muse: {
|
|
64
|
+
provider: 'muse',
|
|
65
|
+
status: 'unsupported',
|
|
66
|
+
interface: null,
|
|
67
|
+
reason: 'Muse Code is a terminal/CI coding agent with no verified non-interactive model-list command; AIWG does not invent Meta Model API enumeration as Muse Code entitlement.',
|
|
68
|
+
documentation: 'https://github.com/jmagly/aiwg/blob/main/docs/architecture/adr-muse-provider-target.md',
|
|
69
|
+
},
|
|
56
70
|
opencode: {
|
|
57
71
|
provider: 'opencode',
|
|
58
72
|
status: 'native',
|
|
@@ -110,6 +124,15 @@ export function classifyDiscoveryError(message) {
|
|
|
110
124
|
return 'timeout';
|
|
111
125
|
return 'command';
|
|
112
126
|
}
|
|
127
|
+
const SECRET_ASSIGNMENT = /((?:api[_-]?key|authorization|token|secret|password|cookie|extra_headers?)\s*[=:]\s*)([^\s,}\]]+)/gi;
|
|
128
|
+
const BEARER_SECRET = /(bearer\s+)[A-Za-z0-9._~+/=-]+/gi;
|
|
129
|
+
/** Keep native diagnostics useful without ever echoing credential material. */
|
|
130
|
+
export function redactModelDiscoveryText(value) {
|
|
131
|
+
return value
|
|
132
|
+
.replace(SECRET_ASSIGNMENT, '$1[REDACTED]')
|
|
133
|
+
.replace(BEARER_SECRET, '$1[REDACTED]')
|
|
134
|
+
.slice(0, 4096);
|
|
135
|
+
}
|
|
113
136
|
export const runModelDiscoveryCommand = (command, args, options = {}) => new Promise(resolveCommand => {
|
|
114
137
|
const child = spawn(command, args, {
|
|
115
138
|
cwd: options.cwd,
|
|
@@ -298,16 +321,25 @@ function isFresh(catalog, now, ttlMs, signature) {
|
|
|
298
321
|
const age = now.getTime() - Date.parse(fetchedAt);
|
|
299
322
|
return Number.isFinite(age) && age >= 0 && age <= ttlMs;
|
|
300
323
|
}
|
|
324
|
+
/** Tier families by name, anchored on separators so `solution` or `lunar` do not match. */
|
|
325
|
+
const FLAGSHIP_FAMILY = /(?:^|[/:._-])(?:fable|astra)(?:$|[/:._[-]|\d)/i;
|
|
326
|
+
const PREMIUM_FAMILY = /(?:^|[/:._-])(?:opus|sol)(?:$|[/:._[-]|\d)/i;
|
|
327
|
+
const STANDARD_FAMILY = /(?:^|[/:._-])(?:sonnet|terra)(?:$|[/:._[-]|\d)/i;
|
|
301
328
|
export function selectRoleModels(models) {
|
|
302
|
-
|
|
329
|
+
// Flagship families are user-elected only (epic #2642): discovery never
|
|
330
|
+
// assigns them to a role, even when the provider marks one as its default.
|
|
331
|
+
const visible = models.filter(model => !model.hidden && !FLAGSHIP_FAMILY.test(model.id));
|
|
303
332
|
if (visible.length === 0)
|
|
304
333
|
return {};
|
|
305
|
-
const coding = visible.find(model => model.
|
|
334
|
+
const coding = visible.find(model => STANDARD_FAMILY.test(model.id))
|
|
335
|
+
?? visible.find(model => model.isDefault && !PREMIUM_FAMILY.test(model.id))
|
|
336
|
+
?? visible.find(model => model.isDefault)
|
|
306
337
|
?? visible.find(model => /(?:codex|code|sonnet|gpt)/i.test(model.id))
|
|
307
338
|
?? visible[0];
|
|
308
|
-
const efficiency = visible.find(model => /(?:mini|spark|haiku|light|flash)/i.test(model.id))
|
|
339
|
+
const efficiency = visible.find(model => /(?:mini|spark|haiku|light|flash|luna)/i.test(model.id))
|
|
309
340
|
?? [...visible].sort((a, b) => (a.reasoningEfforts?.length ?? 0) - (b.reasoningEfforts?.length ?? 0))[0];
|
|
310
|
-
const
|
|
341
|
+
const premium = visible.filter(model => PREMIUM_FAMILY.test(model.id));
|
|
342
|
+
const reasoningCandidates = premium.length > 0 ? premium : visible.filter(model => /(?:opus|reason|ultra|max|pro(?:[-_/]|$))/i.test(model.id));
|
|
311
343
|
const reasoning = [...(reasoningCandidates.length > 0 ? reasoningCandidates : visible)].sort((a, b) => {
|
|
312
344
|
const effortDelta = (b.reasoningEfforts?.length ?? 0) - (a.reasoningEfforts?.length ?? 0);
|
|
313
345
|
if (effortDelta !== 0)
|
|
@@ -462,7 +494,7 @@ export async function resolveDynamicModelCatalog(options) {
|
|
|
462
494
|
: undefined,
|
|
463
495
|
};
|
|
464
496
|
}
|
|
465
|
-
if (!options.allowNetwork) {
|
|
497
|
+
if (!options.allowNetwork && !options.nativeDiscoverers) {
|
|
466
498
|
return {
|
|
467
499
|
...staticCatalog,
|
|
468
500
|
discovery: {
|
|
@@ -503,6 +535,10 @@ export async function resolveDynamicModelCatalog(options) {
|
|
|
503
535
|
openclaw: () => discoverOpenClawModels(),
|
|
504
536
|
pi: () => discoverPiModels(),
|
|
505
537
|
omp: () => discoverOmpModels(process.env.AIWG_OMP_BIN || 'omp', runModelDiscoveryCommand, options.omp),
|
|
538
|
+
'grok-build': async () => {
|
|
539
|
+
const { discoverGrokBuildModels } = await import('./grok-build-models.js');
|
|
540
|
+
return discoverGrokBuildModels(options.grokBuild);
|
|
541
|
+
},
|
|
506
542
|
};
|
|
507
543
|
const providerDiscovery = {};
|
|
508
544
|
for (const provider of available) {
|
|
@@ -26,8 +26,8 @@ function requireModelResource(filename) {
|
|
|
26
26
|
const capabilityData = requireModelResource('model-capabilities.v1.json');
|
|
27
27
|
const catalogData = requireModelResource('model-catalog.v1.json');
|
|
28
28
|
const ProviderSchema = z.enum([
|
|
29
|
-
'antigravity', 'claude', 'codex', 'copilot', 'cursor', 'deepseek-harness', 'factory', 'grokbot', 'hermes',
|
|
30
|
-
'opencode', 'openclaw', 'openhuman', 'omp', 'pi', 'warp', 'windsurf',
|
|
29
|
+
'antigravity', 'claude', 'codex', 'copilot', 'cursor', 'deepseek-harness', 'factory', 'grokbot', 'grok-build', 'hermes',
|
|
30
|
+
'muse', 'opencode', 'openclaw', 'openhuman', 'omp', 'pi', 'warp', 'windsurf',
|
|
31
31
|
]);
|
|
32
32
|
const OutcomeSchema = z.enum([
|
|
33
33
|
'native', 'compiled', 'inherited', 'global-only', 'informational', 'unsupported',
|
|
@@ -160,6 +160,7 @@ function fieldNames(provider) {
|
|
|
160
160
|
case 'copilot':
|
|
161
161
|
case 'cursor':
|
|
162
162
|
case 'opencode': return { model: 'model' };
|
|
163
|
+
case 'grok-build': return { model: 'model', effort: 'effort' };
|
|
163
164
|
case 'omp': return { model: 'model', effort: 'thinkingLevel' };
|
|
164
165
|
case 'pi': return { model: 'model', effort: 'thinking' };
|
|
165
166
|
case 'openhuman': return { model: 'model_hint' };
|