@aiwg/cli 2026.10.10 → 2026.10.12
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/model-capabilities.v1.json +78 -14
- package/agentic/code/providers/model-catalog.v1.json +62 -12
- package/dist/src/artifacts/binding-target-identity.js +51 -0
- package/dist/src/artifacts/checksum-manifest.js +12 -0
- package/dist/src/artifacts/index-builder.js +11 -13
- package/dist/src/artifacts/query-engine.js +5 -11
- package/dist/src/cli/handlers/doctor-help.js +32 -0
- package/dist/src/cli/handlers/gates.js +19 -18
- package/dist/src/cli/handlers/models-help.js +7 -1
- package/dist/src/cli/handlers/models.js +3 -3
- package/dist/src/cli/handlers/script-runner.js +8 -5
- package/dist/src/cli/handlers/sessions-intake.js +104 -0
- package/dist/src/cli/handlers/sessions-tail.js +172 -0
- package/dist/src/cli/handlers/sessions.js +287 -31
- package/dist/src/cli/handlers/skill-lint.js +10 -3
- package/dist/src/cli/handlers/steward-format.js +100 -0
- package/dist/src/cli/handlers/steward-models.js +167 -0
- package/dist/src/cli/handlers/steward.js +14 -248
- package/dist/src/cli/handlers/use-bundle-counts.js +61 -0
- package/dist/src/cli/handlers/use.js +18 -28
- package/dist/src/cli/handlers/utilities.js +1 -24
- package/dist/src/config/aiwg-config.js +7 -0
- package/dist/src/config/authorization-cli.js +89 -0
- package/dist/src/config/cli-help.js +1 -0
- package/dist/src/config/cli.js +10 -1
- package/dist/src/config/worker-context.js +337 -0
- package/dist/src/decision/context-pruning.js +3 -2
- package/dist/src/decision/ensemble/contract.js +15 -4
- package/dist/src/decision/ensemble-study/artifacts.js +5 -0
- package/dist/src/decision/ensemble-study/score.js +4 -3
- package/dist/src/decision/feature-export.js +3 -9
- package/dist/src/decision/heldout/collector.js +2 -2
- package/dist/src/decision/issue-triage/runtime.js +3 -9
- package/dist/src/decision/qualification/gates.js +2 -1
- package/dist/src/decision/qualification/release.js +2 -3
- package/dist/src/decision/routing/report.js +2 -0
- package/dist/src/decision/sdlc-screening.js +3 -5
- package/dist/src/decision/sensitivity/comparative.js +5 -3
- package/dist/src/gates/driver.js +6 -77
- package/dist/src/gates/evaluate.js +4 -11
- package/dist/src/gates/floors.js +4 -4
- package/dist/src/gates/index.js +3 -3
- package/dist/src/gates/lattice.js +26 -0
- package/dist/src/gates/registry.js +2 -1
- package/dist/src/gates/report.js +19 -7
- package/dist/src/issues/audit-cli.js +120 -0
- package/dist/src/issues/audit-contract.js +64 -0
- package/dist/src/issues/audit-local.js +82 -0
- package/dist/src/issues/audit.js +220 -0
- package/dist/src/lint/rule-activation.js +15 -1
- package/dist/src/mcp/tools/worker-invoke.mjs +108 -10
- package/dist/src/mission-protocol/canonical-codecs.js +270 -0
- package/dist/src/mission-protocol/codecs.js +22 -550
- package/dist/src/mission-protocol/health-trace-codecs.js +281 -0
- package/dist/src/mission-protocol/health-trace-types.js +43 -0
- package/dist/src/mission-protocol/types.js +2 -42
- package/dist/src/mission-protocol/worker-contract-json.js +10 -0
- package/dist/src/mission-protocol/worker-review-gate.js +100 -0
- package/dist/src/mission-protocol/worker-review-types.js +2 -0
- package/dist/src/models/catalog-policy.js +280 -0
- package/dist/src/models/index.js +1 -1
- package/dist/src/models/model-capabilities.v1.json +78 -14
- package/dist/src/models/model-catalog.v1.json +62 -12
- package/dist/src/models/policy-resources.js +28 -0
- package/dist/src/models/provider-policy.js +10 -539
- package/dist/src/models/resolver.js +26 -8
- package/dist/src/models/router.js +15 -2
- package/dist/src/models/tiers.js +13 -0
- package/dist/src/models/types.js +0 -6
- package/dist/src/models/worker-ceilings.js +59 -0
- package/dist/src/models/worker-invocation-policy.js +243 -0
- package/dist/src/models/worker-plan.js +16 -20
- package/dist/src/models/worker-review-lineage.js +55 -0
- package/dist/src/models/worker-selection-policy.js +1 -1
- package/dist/src/models/wrapper-route.js +6 -3
- package/dist/src/policy/authorization.js +30 -1
- package/dist/src/policy/hitl-config.js +63 -0
- package/dist/src/policy/hitl-receipt.js +57 -0
- package/dist/src/policy/hitl-types.js +4 -0
- package/dist/src/policy/hitl-validation.js +39 -0
- package/dist/src/policy/hitl.js +117 -0
- package/dist/src/process/aiwg-probe-command.d.mts +15 -0
- package/dist/src/process/aiwg-probe-command.mjs +37 -0
- package/dist/src/rules/activation.d.mts +1 -1
- package/dist/src/rules/activation.mjs +0 -2
- package/dist/src/rules/gate-coverage.js +51 -0
- package/dist/src/rules/gate-references.js +16 -0
- package/dist/src/rules/rule-frontmatter.schema.json +7 -1
- package/dist/src/serve/worker-command-request.js +21 -4
- package/dist/src/serve/worker-invocation-preparation.js +3 -1
- package/dist/src/serve/worker-invocation.js +21 -10
- package/dist/src/sessions/adapters/deepseek-harness.js +1 -0
- package/dist/src/sessions/adapters/grok-build-native.js +269 -0
- package/dist/src/sessions/adapters/grok-build.js +57 -15
- package/dist/src/sessions/adapters/grokbot.js +7 -0
- package/dist/src/sessions/adapters/hermes-state-db.js +252 -0
- package/dist/src/sessions/adapters/hermes.js +42 -3
- package/dist/src/sessions/adapters/warp.js +1 -1
- package/dist/src/sessions/batch-import.js +44 -6
- package/dist/src/sessions/contracts.js +20 -1
- package/dist/src/sessions/coverage-preflight.js +7 -1
- package/dist/src/sessions/discovery-capability.js +38 -0
- package/dist/src/sessions/fortemi-export-mapping.js +33 -3
- package/dist/src/sessions/host-catalog.js +157 -0
- package/dist/src/sessions/image-blobs.js +141 -0
- package/dist/src/sessions/importer.js +9 -232
- package/dist/src/sessions/index.js +6 -0
- package/dist/src/sessions/intake-dir.js +71 -0
- package/dist/src/sessions/normalization.js +251 -0
- package/dist/src/sessions/refresh.js +25 -2
- package/dist/src/sessions/repository.js +164 -22
- package/dist/src/sessions/tail.js +91 -0
- package/dist/src/sessions/workspace-discovery.js +88 -9
- package/dist/src/skills/agent-skill-sidecar.js +28 -0
- package/dist/src/skills/agent-skills.js +4 -23
- package/dist/src/skills/claude-surface-projection.js +25 -0
- package/dist/src/skills/deployer.js +8 -288
- package/dist/src/skills/deployment-policy.js +114 -0
- package/dist/src/skills/deployment-projection.js +152 -0
- package/dist/src/skills/deployment-types.js +20 -0
- package/dist/src/skills/exporter.js +8 -31
- package/dist/src/skills/provider-extensions.js +41 -0
- package/dist/src/skills/run.js +6 -0
- package/dist/src/skills/types.js +0 -8
- package/dist/src/skills/validator-resources.js +68 -0
- package/dist/src/skills/validator.js +6 -55
- package/dist/src/storage/cli-migrate-options.js +125 -0
- package/dist/src/storage/cli-migrate.js +111 -0
- package/dist/src/storage/cli.js +4 -279
- package/dist/src/storage/migration-adapter.js +79 -0
- package/dist/src/storage/migration-copy.js +108 -0
- package/dist/src/storage/migration-protocol.js +14 -197
- package/dist/src/storage/migration-records.js +186 -0
- package/dist/src/storage/migration-types.js +12 -0
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/tracker/issue-pages.js +110 -0
- package/package.json +7 -1
- package/schemas/mission-v1.schema.json +335 -0
- package/schemas/models/model-catalog.v1.schema.json +19 -1
- package/schemas/models/model-config-compatibility.v1.schema.json +3 -2
- package/schemas/models/model-policy.v1.schema.json +1 -1
- package/tools/agents/providers/provider-paths-staging.mjs +35 -0
- package/tools/agents/providers/rule-binding-targets.mjs +146 -0
- package/tools/agents/providers/rule-delivery.mjs +7 -126
- package/tools/ralph-external/lib/muse-adapter.mjs +10 -0
- package/tools/ralph-external/lib/worker-context.mjs +237 -0
- package/tools/ralph-external/lib/worker-invocation-ancestry.mjs +132 -0
- package/tools/ralph-external/lib/worker-invocation-processes.mjs +123 -0
- package/tools/ralph-external/lib/worker-isolation-status.mjs +48 -0
- package/tools/ralph-external/lib/worker-isolation.mjs +17 -29
- package/tools/ralph-external/lib/worker-launch-cli.mjs +3 -1
- package/tools/ralph-external/lib/worker-overflow.mjs +48 -13
- package/tools/ralph-external/lib/worker-retry-evidence.mjs +103 -0
- package/tools/ralph-external/lib/worker-termination.mjs +82 -0
- package/tools/ralph-external/session-launcher.mjs +51 -96
- package/vscode-extension/schemas/aiwg.config.v1.json +177 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Loads bundled policy resources and defines supported provider IDs.
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
export function requireModelResource(filename) {
|
|
6
|
+
const candidates = [
|
|
7
|
+
`./${filename}`,
|
|
8
|
+
`../../agentic/code/providers/${filename}`,
|
|
9
|
+
`../../../agentic/code/providers/${filename}`,
|
|
10
|
+
`../../schemas/models/${filename}`,
|
|
11
|
+
`../../../schemas/models/${filename}`,
|
|
12
|
+
];
|
|
13
|
+
for (const candidate of candidates) {
|
|
14
|
+
try {
|
|
15
|
+
return require(candidate);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error?.code !== 'MODULE_NOT_FOUND')
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
throw new Error(`Model policy resource is missing: ${filename}`);
|
|
23
|
+
}
|
|
24
|
+
export const ProviderSchema = z.enum([
|
|
25
|
+
'antigravity', 'claude', 'codex', 'copilot', 'cursor', 'deepseek-harness', 'factory', 'grokbot', 'grok-build', 'hermes',
|
|
26
|
+
'muse', 'opencode', 'openclaw', 'openhuman', 'omp', 'pi', 'warp', 'windsurf',
|
|
27
|
+
]);
|
|
28
|
+
//# sourceMappingURL=policy-resources.js.map
|
|
@@ -5,43 +5,18 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
7
7
|
import addFormats from 'ajv-formats';
|
|
8
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
9
|
-
import { dirname, resolve } from 'node:path';
|
|
10
|
-
import { fileURLToPath } from 'node:url';
|
|
11
8
|
import { z } from 'zod';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
|
|
9
|
+
import { url } from '../schema/zod-validation.mjs';
|
|
10
|
+
import { compileWorkerVersionPattern } from './worker-installation.mjs';
|
|
11
|
+
import { ProviderSchema, requireModelResource } from './policy-resources.js';
|
|
12
|
+
import { resetCatalogPolicyCache, validateWorkerModelObservation } from './catalog-policy.js';
|
|
13
|
+
import { hasSelectionRelevantConflicts } from './worker-review-lineage.js';
|
|
14
|
+
export { hasSelectionRelevantConflicts } from './worker-review-lineage.js';
|
|
15
|
+
export * from './catalog-policy.js';
|
|
16
|
+
export * from './worker-invocation-policy.js';
|
|
17
|
+
import { DEFAULT_WORKER_SELECTION, workerModelKey, ownWorkerRoleGuidance } from './worker-selection-policy.js';
|
|
18
18
|
export { DEFAULT_WORKER_SELECTION, WorkerSelectionPolicySchema, mergeWorkerSelection, workerModelKey, isCanonicalWorkerModelKey } from './worker-selection-policy.js';
|
|
19
|
-
const require = createRequire(import.meta.url);
|
|
20
|
-
function requireModelResource(filename) {
|
|
21
|
-
const candidates = [
|
|
22
|
-
`./${filename}`,
|
|
23
|
-
`../../agentic/code/providers/${filename}`,
|
|
24
|
-
`../../../agentic/code/providers/${filename}`,
|
|
25
|
-
`../../schemas/models/${filename}`,
|
|
26
|
-
`../../../schemas/models/${filename}`,
|
|
27
|
-
];
|
|
28
|
-
for (const candidate of candidates) {
|
|
29
|
-
try {
|
|
30
|
-
return require(candidate);
|
|
31
|
-
}
|
|
32
|
-
catch (error) {
|
|
33
|
-
if (error?.code !== 'MODULE_NOT_FOUND')
|
|
34
|
-
throw error;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
throw new Error(`Model policy resource is missing: ${filename}`);
|
|
38
|
-
}
|
|
39
19
|
const capabilityData = requireModelResource('model-capabilities.v1.json');
|
|
40
|
-
const catalogData = requireModelResource('model-catalog.v1.json');
|
|
41
|
-
const ProviderSchema = z.enum([
|
|
42
|
-
'antigravity', 'claude', 'codex', 'copilot', 'cursor', 'deepseek-harness', 'factory', 'grokbot', 'grok-build', 'hermes',
|
|
43
|
-
'muse', 'opencode', 'openclaw', 'openhuman', 'omp', 'pi', 'warp', 'windsurf',
|
|
44
|
-
]);
|
|
45
20
|
const OutcomeSchema = z.enum([
|
|
46
21
|
'native', 'compiled', 'inherited', 'global-only', 'informational', 'unsupported',
|
|
47
22
|
]);
|
|
@@ -103,112 +78,7 @@ const CapabilityRegistrySchema = z.strictObject({
|
|
|
103
78
|
workerHealthAdapters: z.record(z.string().regex(/^[a-z][a-z0-9-]{0,62}$/), WorkerAdapterSchema)
|
|
104
79
|
.refine(value => Object.keys(value).length <= 128, 'At most 128 worker health descriptors').optional(),
|
|
105
80
|
});
|
|
106
|
-
const CatalogModelSchema = z.object({
|
|
107
|
-
id: z.string().min(1),
|
|
108
|
-
status: z.enum(['active', 'deprecated', 'unverified']),
|
|
109
|
-
fallback: z.string().min(1).optional(),
|
|
110
|
-
observed: z.boolean().optional(),
|
|
111
|
-
});
|
|
112
|
-
const CatalogProviderSchema = z.object({
|
|
113
|
-
roles: z.object({
|
|
114
|
-
reasoning: CatalogModelSchema,
|
|
115
|
-
coding: CatalogModelSchema,
|
|
116
|
-
efficiency: CatalogModelSchema,
|
|
117
|
-
}),
|
|
118
|
-
sourceUrl: url(),
|
|
119
|
-
verifiedAt: z.string().date(),
|
|
120
|
-
});
|
|
121
|
-
let catalogValidators;
|
|
122
|
-
function getCatalogValidators() {
|
|
123
|
-
if (!catalogValidators) {
|
|
124
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
125
|
-
const file = [resolve(here, '../../schemas/models/model-catalog.v1.schema.json'), resolve(here, '../../../schemas/models/model-catalog.v1.schema.json')].find(existsSync);
|
|
126
|
-
if (!file)
|
|
127
|
-
throw new Error('Model catalog schema is unavailable');
|
|
128
|
-
const schema = JSON.parse(readFileSync(file, 'utf8'));
|
|
129
|
-
const ajv = addFormats(new Ajv2020({ strict: false, allErrors: true }));
|
|
130
|
-
ajv.addSchema(schema);
|
|
131
|
-
catalogValidators = { catalog: ajv.getSchema(schema.$id), observation: ajv.compile({ $ref: `${schema.$id}#/$defs/workerObservation` }), discovery: ajv.compile({ $ref: `${schema.$id}#/properties/discovery` }) };
|
|
132
|
-
}
|
|
133
|
-
return catalogValidators;
|
|
134
|
-
}
|
|
135
|
-
export function validateWorkerModelObservation(input) {
|
|
136
|
-
const validate = getCatalogValidators().observation;
|
|
137
|
-
return validate(input) ? [] : (validate.errors ?? []).map(error => `${error.instancePath}: ${error.message}`);
|
|
138
|
-
}
|
|
139
|
-
const WorkerObservationSchema = z.custom(input => validateWorkerModelObservation(input).length === 0);
|
|
140
|
-
const DiscoveredWorkerModelSchema = z.looseObject({
|
|
141
|
-
id: z.string().min(1), apiModelId: z.string().optional(), llmProvider: z.string().optional(),
|
|
142
|
-
hidden: z.boolean().optional(), reasoningEfforts: z.array(z.string()).optional(), worker: WorkerObservationSchema.optional(),
|
|
143
|
-
}).superRefine((model, context) => {
|
|
144
|
-
if (!model.worker)
|
|
145
|
-
return;
|
|
146
|
-
if (model.hidden !== undefined && model.worker.visibility !== (model.hidden ? 'hidden' : 'listed'))
|
|
147
|
-
context.addIssue({ code: 'custom', path: ['worker', 'visibility'], message: 'Conflicting visibility evidence' });
|
|
148
|
-
const efforts = model.reasoningEfforts ?? [];
|
|
149
|
-
const observed = model.worker.efforts.map(e => e.id);
|
|
150
|
-
if (efforts.length !== observed.length || new Set(observed).size !== observed.length || efforts.some(e => !observed.includes(e)))
|
|
151
|
-
context.addIssue({ code: 'custom', path: ['worker', 'efforts'], message: 'Conflicting effort evidence' });
|
|
152
|
-
});
|
|
153
|
-
const ProviderDiscoverySchema = z.looseObject({
|
|
154
|
-
provider: z.string(), source: z.enum(['native', 'cache', 'remote', 'static']), observedAt: dateTime({ offset: true }),
|
|
155
|
-
runtimeVersion: z.string().optional(), accountScope: z.enum(['local-account', 'local-runtime', 'public-feed', 'static']),
|
|
156
|
-
accountBinding: z.string().min(1).optional(), models: z.array(DiscoveredWorkerModelSchema),
|
|
157
|
-
});
|
|
158
|
-
const DiscoverySchema = z.strictObject({
|
|
159
|
-
source: z.enum(['native', 'cache', 'remote', 'static']), upstreamSource: z.enum(['native', 'remote', 'static']).optional(),
|
|
160
|
-
fetchedAt: dateTime({ offset: true }), remoteUrl: url().optional(), remoteError: z.string().optional(),
|
|
161
|
-
inventorySignature: z.string().optional(), providers: z.record(z.string(), ProviderDiscoverySchema),
|
|
162
|
-
instances: z.record(z.string(), ProviderDiscoverySchema).optional(),
|
|
163
|
-
});
|
|
164
|
-
/** Optional enrichment is checked without tightening legacy catalog rows. */
|
|
165
|
-
export function validateWorkerCatalogDiscovery(input) {
|
|
166
|
-
if (input === undefined)
|
|
167
|
-
return [];
|
|
168
|
-
const validate = getCatalogValidators().discovery;
|
|
169
|
-
if (!validate(input))
|
|
170
|
-
return (validate.errors ?? []).map(error => `${error.instancePath}: ${error.message}`);
|
|
171
|
-
const parsed = DiscoverySchema.safeParse(input);
|
|
172
|
-
return parsed.success ? [] : parsed.error.issues.map(issue => `${issue.path.join('/')}: ${issue.message}`);
|
|
173
|
-
}
|
|
174
|
-
const CatalogSchema = z.strictObject({
|
|
175
|
-
version: z.literal('1.0.0'),
|
|
176
|
-
$schema: z.literal('../../../schemas/models/model-catalog.v1.schema.json').optional(),
|
|
177
|
-
discovery: DiscoverySchema.optional(),
|
|
178
|
-
refreshedAt: z.string().date(),
|
|
179
|
-
staleAfterDays: integer().positive(),
|
|
180
|
-
providers: z.partialRecord(ProviderSchema, CatalogProviderSchema),
|
|
181
|
-
});
|
|
182
|
-
const PolicySchema = z.strictObject({
|
|
183
|
-
role: z.enum(['reasoning', 'coding', 'efficiency']),
|
|
184
|
-
tier: z.enum(['economy', 'standard', 'premium']),
|
|
185
|
-
effort: z.enum(['minimal', 'low', 'medium', 'high', 'xhigh']).optional(),
|
|
186
|
-
override: z.string().min(1).optional(),
|
|
187
|
-
});
|
|
188
|
-
const UserProjectModelConfigSchema = z.looseObject({
|
|
189
|
-
defaults: z.strictObject({
|
|
190
|
-
tier: z.enum(['economy', 'standard', 'premium', 'max-quality']).optional(),
|
|
191
|
-
provider: ProviderSchema.optional(),
|
|
192
|
-
workerSelection: WorkerSelectionPolicySchema.optional(),
|
|
193
|
-
}).optional(),
|
|
194
|
-
agentOverrides: z.record(z.string(), z.strictObject({
|
|
195
|
-
'model-tier': z.enum(['economy', 'standard', 'premium', 'max-quality']).optional(),
|
|
196
|
-
'model-override': z.string().min(1).optional(),
|
|
197
|
-
rationale: z.string().min(1).optional(),
|
|
198
|
-
})).optional(),
|
|
199
|
-
customTiers: z.record(z.string(), z.strictObject({
|
|
200
|
-
description: z.string().min(1),
|
|
201
|
-
costMultiplier: number().check(z.gte(0)).meta({ type: 'number', minimum: 0 }),
|
|
202
|
-
roleMapping: z.strictObject({
|
|
203
|
-
reasoning: z.enum(['reasoning', 'coding', 'efficiency']),
|
|
204
|
-
coding: z.enum(['reasoning', 'coding', 'efficiency']),
|
|
205
|
-
efficiency: z.enum(['reasoning', 'coding', 'efficiency']),
|
|
206
|
-
}),
|
|
207
|
-
})).optional(),
|
|
208
|
-
rationale: z.string().optional(),
|
|
209
|
-
});
|
|
210
81
|
let registryCache = null;
|
|
211
|
-
let catalogCache = null;
|
|
212
82
|
export function loadProviderModelCapabilities() {
|
|
213
83
|
if (!registryCache) {
|
|
214
84
|
registryCache = parseProviderModelCapabilities(capabilityData);
|
|
@@ -345,403 +215,9 @@ export function assertWorkerSelectionAllowed(selected, context) {
|
|
|
345
215
|
}
|
|
346
216
|
}
|
|
347
217
|
}
|
|
348
|
-
const WORKER_CONTROLS = ['model', 'effort', 'sandbox', 'approval', 'workdir',
|
|
349
|
-
'finalOutput', 'stdin', 'structuredOutput', 'stepCap', 'trust', 'children', 'fallback'];
|
|
350
|
-
/** Caller controls only add restrictions. Absent resolved authority, require all controls. */
|
|
351
|
-
export function requiredWorkerControls(context) {
|
|
352
|
-
if (context.requiredControls !== undefined && (!Array.isArray(context.requiredControls)
|
|
353
|
-
|| context.requiredControls.some(name => typeof name !== 'string' || !name))) {
|
|
354
|
-
throw new Error('Worker required controls must be an array of control names');
|
|
355
|
-
}
|
|
356
|
-
const controls = new Set(WORKER_CONTROLS);
|
|
357
|
-
if (context.policy && context.permissions) {
|
|
358
|
-
if (context.effort === null)
|
|
359
|
-
controls.delete('effort');
|
|
360
|
-
// Step limits are observed unless explicitly required by the trusted route.
|
|
361
|
-
controls.delete('stepCap');
|
|
362
|
-
if (context.policy.guards?.denySelfDelegation === false)
|
|
363
|
-
controls.delete('children');
|
|
364
|
-
}
|
|
365
|
-
for (const name of context.requiredControls ?? [])
|
|
366
|
-
controls.add(name);
|
|
367
|
-
return [...controls];
|
|
368
|
-
}
|
|
369
|
-
/** The same sandbox requirement governs inspection, resolution and rendering. */
|
|
370
|
-
export function requiresWorkerExternalBoundary(adapter, selection) {
|
|
371
|
-
if (hasOperatorWorkerNativeRenderer(adapter)
|
|
372
|
-
&& (selection.permissions?.sandbox !== 'external' || selection.transport === 'shell'))
|
|
373
|
-
return false;
|
|
374
|
-
const providers = [adapter.id, adapter.provider].map(normalizeProviderDefinitionId);
|
|
375
|
-
return requiredWorkerControls(selection).includes('sandbox')
|
|
376
|
-
&& (providers.some(provider => provider && ['claude', 'muse', 'hermes'].includes(provider))
|
|
377
|
-
|| adapter.invocationProfiles?.[selection.profile]?.controls.sandbox?.support === 'external'
|
|
378
|
-
|| selection.permissions?.sandbox === 'external');
|
|
379
|
-
}
|
|
380
|
-
/** Explicit local operator approval for the direct CLI baseline (decision 17).
|
|
381
|
-
* This is not backend attestation or a live negative-fixture result. */
|
|
382
|
-
export const WORKER_OPERATOR_APPROVAL = 'aiwg doctor --probe-workers --qualify';
|
|
383
|
-
export function isOperatorQualifiedWorkerAdapter(adapter) {
|
|
384
|
-
return adapter.qualification.status === 'qualified'
|
|
385
|
-
&& adapter.qualification.evidenceRef === WORKER_OPERATOR_APPROVAL;
|
|
386
|
-
}
|
|
387
|
-
/** Bundled renderers with an independently checked native direct baseline. */
|
|
388
|
-
export function hasOperatorWorkerNativeRenderer(adapter) {
|
|
389
|
-
return isOperatorQualifiedWorkerAdapter(adapter) && ['codex', 'muse'].includes(adapter.provider)
|
|
390
|
-
&& adapter.invocation.kind === 'process';
|
|
391
|
-
}
|
|
392
|
-
/** The process-group launch boundary requires the independently verified native renderer. */
|
|
393
|
-
export function assertWorkerLaunchMode(adapter, permissions = {}) {
|
|
394
|
-
const mode = permissions.launchMode ?? 'systemd-unit';
|
|
395
|
-
if (!['systemd-unit', 'native-sandbox'].includes(mode)) {
|
|
396
|
-
throw new WorkerPolicyError('OG_CONFIG_REFERENCE', 'Unknown worker launch mode');
|
|
397
|
-
}
|
|
398
|
-
if (mode === 'native-sandbox' && (!hasOperatorWorkerNativeRenderer(adapter)
|
|
399
|
-
|| !['read-only', 'workspace-write'].includes(permissions.sandbox ?? '')
|
|
400
|
-
|| (permissions.transport ?? 'shell') !== 'shell')) {
|
|
401
|
-
throw new WorkerPolicyError('OG_POLICY_RELAXATION', 'native-sandbox requires a verified native read-only or workspace-write shell renderer');
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
/** Check the actual argv before granting the direct renderer exception. */
|
|
405
|
-
export function assertOperatorWorkerNativeArgv(adapter, argv, selected, permissions) {
|
|
406
|
-
if (!hasOperatorWorkerNativeRenderer(adapter))
|
|
407
|
-
return;
|
|
408
|
-
const args = argv.slice(1);
|
|
409
|
-
const requirePair = (flag, value) => {
|
|
410
|
-
if (args.filter(token => token === flag).length !== 1 || args[args.indexOf(flag) + 1] !== value) {
|
|
411
|
-
throw new Error(`Requested native worker control is absent or ambiguous: ${flag}`);
|
|
412
|
-
}
|
|
413
|
-
};
|
|
414
|
-
const sandbox = permissions?.sandbox ?? 'workspace-write';
|
|
415
|
-
if (!['read-only', 'workspace-write', 'external'].includes(sandbox))
|
|
416
|
-
throw new Error('Requested sandbox has no verified native renderer');
|
|
417
|
-
if (adapter.provider === 'muse') {
|
|
418
|
-
requirePair('--provider', 'meta');
|
|
419
|
-
requirePair('--model', selected.model);
|
|
420
|
-
if (selected.effort.value === null)
|
|
421
|
-
throw new Error('Muse requires explicit effort');
|
|
422
|
-
requirePair('--reasoning-effort', selected.effort.value);
|
|
423
|
-
if ((permissions?.approval ?? 'never') !== 'never')
|
|
424
|
-
throw new Error('Muse direct worker approval requires never');
|
|
425
|
-
requirePair('--approval-mode', 'never');
|
|
426
|
-
requirePair('--approval-judge', 'off');
|
|
427
|
-
if (args.includes('--disable-sandbox') !== (sandbox === 'external')) {
|
|
428
|
-
throw new Error('Requested native worker sandbox control does not match');
|
|
429
|
-
}
|
|
430
|
-
if (sandbox === 'read-only' && (!args.includes('--disable-write') || !args.includes('--disable-shell'))) {
|
|
431
|
-
throw new Error('Requested native worker read-only control is absent');
|
|
432
|
-
}
|
|
433
|
-
if (args[0] !== 'exec')
|
|
434
|
-
throw new Error('Native worker controls could be overridden');
|
|
435
|
-
const seen = new Set();
|
|
436
|
-
for (let index = 1; index < args.length; index++) {
|
|
437
|
-
const flag = args[index];
|
|
438
|
-
if (seen.has(flag))
|
|
439
|
-
throw new Error('Native worker controls could be overridden');
|
|
440
|
-
seen.add(flag);
|
|
441
|
-
if (['--json', '--trust-workspace', '--disable-write', '--disable-shell', '--disable-sandbox'].includes(flag))
|
|
442
|
-
continue;
|
|
443
|
-
if (!['--provider', '--model', '--reasoning-effort', '--workspace', '--approval-mode', '--approval-judge',
|
|
444
|
-
'--max-model-steps', '--output-schema', '--prompt-file'].includes(flag) || index + 1 >= args.length) {
|
|
445
|
-
throw new Error('Native worker controls could be overridden');
|
|
446
|
-
}
|
|
447
|
-
index++;
|
|
448
|
-
}
|
|
449
|
-
return;
|
|
450
|
-
}
|
|
451
|
-
requirePair('-m', selected.model);
|
|
452
|
-
requirePair('-s', sandbox === 'external' ? 'danger-full-access' : sandbox);
|
|
453
|
-
if ((permissions?.approval ?? 'never') !== 'never')
|
|
454
|
-
throw new Error('Codex direct worker approval requires never');
|
|
455
|
-
for (const [name, value] of [['model_reasoning_effort', selected.effort.value], ['approval_policy', permissions?.approval ?? 'never']]) {
|
|
456
|
-
const overrides = args.flatMap((token, index) => token === '-c' ? [args[index + 1]] : [])
|
|
457
|
-
.filter(token => token?.split('=')[0] === name);
|
|
458
|
-
if (value === null || overrides.length !== 1 || overrides[0] !== `${name}=${JSON.stringify(value)}`) {
|
|
459
|
-
throw new Error(`Requested native worker control is absent or ambiguous: ${name}`);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
// Permit only the bounded native command grammar. Alternate/combined flags,
|
|
463
|
-
// profiles and additional config overrides must not undo the checked pairs.
|
|
464
|
-
if (args[0] !== '--no-daemon' || args[1] !== 'exec' || !args.includes('--ignore-user-config')) {
|
|
465
|
-
throw new Error('Native worker controls could be overridden');
|
|
466
|
-
}
|
|
467
|
-
for (let index = 2; index < args.length; index++) {
|
|
468
|
-
const flag = args[index];
|
|
469
|
-
if (['--ignore-user-config', '--skip-git-repo-check', '--json'].includes(flag))
|
|
470
|
-
continue;
|
|
471
|
-
if (flag === '-' && index === args.length - 1)
|
|
472
|
-
continue;
|
|
473
|
-
if (!['-m', '-s', '-c', '-C', '-o'].includes(flag) || index + 1 >= args.length) {
|
|
474
|
-
throw new Error('Native worker controls could be overridden');
|
|
475
|
-
}
|
|
476
|
-
const value = args[++index];
|
|
477
|
-
if (flag === '-c' && !['model_reasoning_effort', 'approval_policy'].includes(value.split('=')[0])) {
|
|
478
|
-
throw new Error('Native worker controls could be overridden');
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
/** Inspect declared controls before installation evidence can be produced. This
|
|
483
|
-
* does not authorize invocation; consumers must use qualifyWorkerInvocationProfile. */
|
|
484
|
-
export function inspectWorkerInvocationProfile(adapter, selection) {
|
|
485
|
-
WorkerAdapterSchema.parse(adapter);
|
|
486
|
-
const profile = adapter.invocationProfiles?.[selection.profile];
|
|
487
|
-
if (adapter.qualification.status !== 'qualified' || !profile || profile.transport !== selection.transport) {
|
|
488
|
-
throw new Error('Worker transport/profile is unqualified');
|
|
489
|
-
}
|
|
490
|
-
// Shared range predicate (worker-installation.mjs): read-only surfaces
|
|
491
|
-
// (worker-direct-readiness.ts) reuse the same helper instead of
|
|
492
|
-
// re-deriving this inspector's range logic.
|
|
493
|
-
if (workerVersionRangeMismatch(selection.cliVersion, [adapter.supportedVersions, profile.supportedVersions]) !== null) {
|
|
494
|
-
throw new Error('Worker CLI version is outside qualified profile');
|
|
495
|
-
}
|
|
496
|
-
// The direct CLI baseline trusts the installed driver's bounded renderer.
|
|
497
|
-
// Explicit extra controls still require the existing qualified mappings.
|
|
498
|
-
if (hasOperatorWorkerNativeRenderer(adapter) && profile.transport === 'shell') {
|
|
499
|
-
if (selection.permissions?.sandbox && !['read-only', 'workspace-write', 'external'].includes(selection.permissions.sandbox)) {
|
|
500
|
-
throw new Error('Requested sandbox has no verified native renderer');
|
|
501
|
-
}
|
|
502
|
-
for (const name of selection.requiredControls ?? []) {
|
|
503
|
-
if (!['native', 'external'].includes(profile.controls[name]?.support)) {
|
|
504
|
-
throw new Error(`Required worker control is unqualified: ${name}`);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
return profile;
|
|
508
|
-
}
|
|
509
|
-
const requiredControls = requiredWorkerControls(selection);
|
|
510
|
-
if (requiresWorkerExternalBoundary(adapter, selection)
|
|
511
|
-
&& (!selection.boundary || !['os', 'executor'].includes(selection.boundary.kind)
|
|
512
|
-
|| !selection.boundary.identity || !/^sha256:[a-f0-9]{64}$/.test(selection.boundary.digest)
|
|
513
|
-
|| !selection.boundary.controls?.includes('sandbox'))) {
|
|
514
|
-
throw new Error('Required worker control sandbox needs a qualified external enforcing boundary');
|
|
515
|
-
}
|
|
516
|
-
for (const name of requiredControls) {
|
|
517
|
-
if ((name === 'children' && !adapter.capabilities.nestedAgentsControllable)
|
|
518
|
-
|| (name === 'fallback' && !adapter.capabilities.nativeFallbackControllable)) {
|
|
519
|
-
throw new Error(`Required worker control is unqualified: ${name}`);
|
|
520
|
-
}
|
|
521
|
-
const control = profile.controls[name];
|
|
522
|
-
if (!control || !['native', 'external'].includes(control.support) || !control.mapping || !control.evidence) {
|
|
523
|
-
throw new Error(`Required worker control is unqualified: ${name}`);
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
if (selection.transport === 'mcp' && (!selection.mcp || !profile.mcp
|
|
527
|
-
|| Object.keys(profile.mcp).some(key => profile.mcp[key]
|
|
528
|
-
!== selection.mcp[key]))) {
|
|
529
|
-
throw new Error('MCP server/tool/schema/session qualification changed');
|
|
530
|
-
}
|
|
531
|
-
return profile;
|
|
532
|
-
}
|
|
533
|
-
/** Qualification is transport/version scoped; declaration or boundary claims
|
|
534
|
-
* alone cannot qualify an external sandbox. The invocation owner rechecks the
|
|
535
|
-
* installation scope, including this boundary, against the recorded digest. */
|
|
536
|
-
export function qualifyWorkerInvocationProfile(adapter, selection) {
|
|
537
|
-
const profile = inspectWorkerInvocationProfile(adapter, selection);
|
|
538
|
-
if (isOperatorQualifiedWorkerAdapter(adapter) && selection.policy?.guards?.denySelfDelegation !== false
|
|
539
|
-
&& !adapter.capabilities.nestedAgentsControllable) {
|
|
540
|
-
throw new Error('Required worker control is unqualified: children');
|
|
541
|
-
}
|
|
542
|
-
if (requiresWorkerExternalBoundary(adapter, selection) && !profile.installationQualification) {
|
|
543
|
-
throw new Error('Required worker control sandbox needs matching installation qualification for its external boundary');
|
|
544
|
-
}
|
|
545
|
-
return profile;
|
|
546
|
-
}
|
|
547
|
-
/** Health timing evidence belongs to the exact execution profile and tuple.
|
|
548
|
-
* Fixture qualification does not become authenticated/live qualification. */
|
|
549
|
-
export function workerHealthScopeDigest(profile, scope) {
|
|
550
|
-
const { installationQualification: _installation, health, ...executionProfile } = profile;
|
|
551
|
-
const { qualification: _qualification, ...signals } = health ?? {};
|
|
552
|
-
return qualificationDigest({ profile: executionProfile, health: signals,
|
|
553
|
-
profileRef: scope.profileRef, cliVersion: scope.cliVersion, accountScope: scope.accountScope,
|
|
554
|
-
modelKey: workerModelKey(scope.inferenceProvider, scope.model), effort: scope.effort });
|
|
555
|
-
}
|
|
556
|
-
/** Reused by observation and invocation owners before using qualified health.
|
|
557
|
-
* Older profiles have no qualification record and retain degraded observation. */
|
|
558
|
-
export function assertWorkerHealthQualification(profile, scope) {
|
|
559
|
-
const evidence = profile.health?.qualification;
|
|
560
|
-
if (!evidence)
|
|
561
|
-
return;
|
|
562
|
-
if (evidence.status === 'unqualified') {
|
|
563
|
-
if (profile.health?.coverage === 'full' || profile.health?.handshake === 'semantic') {
|
|
564
|
-
throw new Error('Unqualified worker health cannot assert full or semantic coverage');
|
|
565
|
-
}
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
const modelKey = workerModelKey(scope.inferenceProvider, scope.model);
|
|
569
|
-
if (evidence.cliVersion !== scope.cliVersion || evidence.accountScope !== scope.accountScope
|
|
570
|
-
|| evidence.profileRef !== scope.profileRef || evidence.modelKey !== modelKey || evidence.effort !== scope.effort
|
|
571
|
-
|| !profile.health?.qualifiedAt || !Number.isFinite(Date.parse(profile.health.qualifiedAt))
|
|
572
|
-
|| evidence.scopeDigest !== workerHealthScopeDigest(profile, scope)
|
|
573
|
-
|| (evidence.status === 'live-qualified' && evidence.authorizedLive !== true)) {
|
|
574
|
-
throw new Error('Worker health qualification scope changed or lacks live authorization');
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
export function parseProviderModelCatalog(input) {
|
|
578
|
-
const validate = getCatalogValidators().catalog;
|
|
579
|
-
if (!validate(input))
|
|
580
|
-
throw new Error(`MODEL_POLICY_INVALID: ${validate.errors?.map(e => `${e.instancePath} ${e.message}`).join('; ')}`);
|
|
581
|
-
return CatalogSchema.parse(input);
|
|
582
|
-
}
|
|
583
|
-
export function loadProviderModelCatalog() {
|
|
584
|
-
if (!catalogCache)
|
|
585
|
-
catalogCache = parseProviderModelCatalog(catalogData);
|
|
586
|
-
return catalogCache;
|
|
587
|
-
}
|
|
588
|
-
export function validateCanonicalModelPolicy(input) {
|
|
589
|
-
const parsed = PolicySchema.safeParse(input);
|
|
590
|
-
if (!parsed.success) {
|
|
591
|
-
return {
|
|
592
|
-
valid: false,
|
|
593
|
-
diagnostics: parsed.error.issues.map(issue => ({
|
|
594
|
-
code: 'MODEL_POLICY_INVALID',
|
|
595
|
-
severity: 'error',
|
|
596
|
-
message: `${issue.path.join('.') || 'policy'}: ${issue.message}`,
|
|
597
|
-
})),
|
|
598
|
-
};
|
|
599
|
-
}
|
|
600
|
-
return { valid: true, policy: parsed.data, diagnostics: [] };
|
|
601
|
-
}
|
|
602
|
-
export function validateUserProjectModelConfig(input) {
|
|
603
|
-
const parsed = UserProjectModelConfigSchema.safeParse(input);
|
|
604
|
-
if (parsed.success)
|
|
605
|
-
return { valid: true, diagnostics: [] };
|
|
606
|
-
return {
|
|
607
|
-
valid: false,
|
|
608
|
-
diagnostics: parsed.error.issues.map(issue => ({
|
|
609
|
-
code: issue.path.includes('workerSelection') ? 'OG_CONFIG_REFERENCE' : 'MODEL_POLICY_INVALID',
|
|
610
|
-
pointer: `/${issue.path.map(p => String(p).replace(/~/g, '~0').replace(/\//g, '~1')).join('/')}`,
|
|
611
|
-
severity: 'error',
|
|
612
|
-
message: `${issue.path.join('.') || 'config'}: ${issue.message}`,
|
|
613
|
-
})),
|
|
614
|
-
};
|
|
615
|
-
}
|
|
616
|
-
function catalogRole(policy) {
|
|
617
|
-
if (policy.tier === 'economy')
|
|
618
|
-
return 'efficiency';
|
|
619
|
-
if (policy.tier === 'premium')
|
|
620
|
-
return 'reasoning';
|
|
621
|
-
return policy.role;
|
|
622
|
-
}
|
|
623
|
-
function fieldNames(provider) {
|
|
624
|
-
switch (provider) {
|
|
625
|
-
case 'antigravity': return { model: 'model', effort: 'effort' };
|
|
626
|
-
case 'codex': return { model: 'model', effort: 'model_reasoning_effort' };
|
|
627
|
-
case 'factory': return { model: 'model', effort: 'reasoningEffort' };
|
|
628
|
-
case 'claude': return { model: 'model', effort: 'effort' };
|
|
629
|
-
case 'copilot':
|
|
630
|
-
case 'cursor':
|
|
631
|
-
case 'opencode': return { model: 'model' };
|
|
632
|
-
case 'grok-build': return { model: 'model', effort: 'effort' };
|
|
633
|
-
case 'omp': return { model: 'model', effort: 'thinkingLevel' };
|
|
634
|
-
case 'pi': return { model: 'model', effort: 'thinking' };
|
|
635
|
-
case 'openhuman': return { model: 'model_hint' };
|
|
636
|
-
case 'openclaw': return { model: 'subagents.model' };
|
|
637
|
-
default: return {};
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
export function compileModelPolicy(input) {
|
|
641
|
-
const registry = loadProviderModelCapabilities();
|
|
642
|
-
const catalog = input.catalog ?? loadProviderModelCatalog();
|
|
643
|
-
const capability = registry.providers[input.provider];
|
|
644
|
-
if (!capability)
|
|
645
|
-
throw new Error(`Unknown provider model capability: ${input.provider}`);
|
|
646
|
-
const surface = capability[input.artifact];
|
|
647
|
-
const diagnostics = [];
|
|
648
|
-
const fields = {};
|
|
649
|
-
const names = fieldNames(input.provider);
|
|
650
|
-
const catalogProvider = catalog.providers[input.provider];
|
|
651
|
-
if (!catalogProvider)
|
|
652
|
-
throw new Error(`Unknown provider model catalog: ${input.provider}`);
|
|
653
|
-
const catalogEntry = catalogProvider.roles[catalogRole(input.policy)];
|
|
654
|
-
const effectiveModel = input.policy.override ?? catalogEntry.id;
|
|
655
|
-
if (surface === 'unsupported' || surface === 'informational') {
|
|
656
|
-
diagnostics.push({
|
|
657
|
-
code: surface === 'unsupported' ? 'MODEL_SURFACE_UNSUPPORTED' : 'MODEL_SURFACE_DEGRADED',
|
|
658
|
-
severity: surface === 'unsupported' ? 'warning' : 'info',
|
|
659
|
-
provider: input.provider,
|
|
660
|
-
message: `${input.provider} cannot enforce ${input.artifact}-scoped model policy (${surface})`,
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
else if (surface === 'global-only' || surface === 'inherited') {
|
|
664
|
-
diagnostics.push({
|
|
665
|
-
code: 'MODEL_SURFACE_DEGRADED', severity: 'warning', provider: input.provider,
|
|
666
|
-
message: `${input.provider} compiles ${input.artifact} policy as ${surface}`,
|
|
667
|
-
});
|
|
668
|
-
}
|
|
669
|
-
else if (names.model) {
|
|
670
|
-
fields[names.model] = effectiveModel;
|
|
671
|
-
}
|
|
672
|
-
if (input.policy.effort) {
|
|
673
|
-
if (names.effort && capability.effortValues?.includes(input.policy.effort)
|
|
674
|
-
&& surface !== 'unsupported' && surface !== 'informational') {
|
|
675
|
-
fields[names.effort] = input.policy.effort;
|
|
676
|
-
}
|
|
677
|
-
else {
|
|
678
|
-
diagnostics.push({
|
|
679
|
-
code: 'MODEL_EFFORT_UNSUPPORTED', severity: 'warning', provider: input.provider,
|
|
680
|
-
message: `${input.provider} does not enforce effort=${input.policy.effort} on ${input.artifact} artifacts`,
|
|
681
|
-
});
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
if (input.policy.override) {
|
|
685
|
-
diagnostics.push({
|
|
686
|
-
code: 'MODEL_OVERRIDE_UNVERIFIED', severity: 'warning', provider: input.provider,
|
|
687
|
-
message: `Exact override ${input.policy.override} requires provider validation`,
|
|
688
|
-
});
|
|
689
|
-
}
|
|
690
|
-
else if (catalogEntry.status === 'deprecated') {
|
|
691
|
-
diagnostics.push({
|
|
692
|
-
code: 'MODEL_CATALOG_DEPRECATED', severity: 'error', provider: input.provider,
|
|
693
|
-
message: `${catalogEntry.id} is deprecated`,
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
else if (catalogEntry.status === 'unverified') {
|
|
697
|
-
diagnostics.push({
|
|
698
|
-
code: 'MODEL_CATALOG_UNVERIFIED', severity: 'warning', provider: input.provider,
|
|
699
|
-
message: `${catalogEntry.id} has not been observed on ${input.provider}`,
|
|
700
|
-
});
|
|
701
|
-
}
|
|
702
|
-
const now = input.now ?? new Date();
|
|
703
|
-
const refreshedAt = new Date(`${catalog.refreshedAt}T00:00:00Z`);
|
|
704
|
-
const ageDays = Math.floor((now.getTime() - refreshedAt.getTime()) / 86_400_000);
|
|
705
|
-
if (ageDays > catalog.staleAfterDays) {
|
|
706
|
-
diagnostics.push({
|
|
707
|
-
code: 'MODEL_CATALOG_STALE', severity: 'warning', provider: input.provider,
|
|
708
|
-
message: `Model catalog is ${ageDays} days old (limit ${catalog.staleAfterDays})`,
|
|
709
|
-
});
|
|
710
|
-
}
|
|
711
|
-
return {
|
|
712
|
-
provider: input.provider,
|
|
713
|
-
artifact: input.artifact,
|
|
714
|
-
outcome: surface,
|
|
715
|
-
effectiveModel: surface === 'unsupported' || surface === 'informational' ? undefined : effectiveModel,
|
|
716
|
-
effectiveEffort: fields[names.effort ?? ''] ? input.policy.effort : undefined,
|
|
717
|
-
fields,
|
|
718
|
-
target: capability.configTarget,
|
|
719
|
-
source: input.policy.override ? 'override' : (surface === 'inherited' ? 'inheritance' : 'catalog'),
|
|
720
|
-
diagnostics,
|
|
721
|
-
};
|
|
722
|
-
}
|
|
723
|
-
function tomlString(value) { return JSON.stringify(value); }
|
|
724
|
-
export function renderCodexAgentToml(definition) {
|
|
725
|
-
const required = [
|
|
726
|
-
['name', definition.name],
|
|
727
|
-
['description', definition.description],
|
|
728
|
-
['developer_instructions', definition.developerInstructions],
|
|
729
|
-
];
|
|
730
|
-
for (const [field, value] of required) {
|
|
731
|
-
if (!value.trim())
|
|
732
|
-
throw new Error(`Codex custom agent requires ${field}`);
|
|
733
|
-
}
|
|
734
|
-
const lines = required.map(([field, value]) => `${field} = ${tomlString(value)}`);
|
|
735
|
-
if (definition.model)
|
|
736
|
-
lines.push(`model = ${tomlString(definition.model)}`);
|
|
737
|
-
if (definition.modelReasoningEffort) {
|
|
738
|
-
lines.push(`model_reasoning_effort = ${tomlString(definition.modelReasoningEffort)}`);
|
|
739
|
-
}
|
|
740
|
-
return `${lines.join('\n')}\n`;
|
|
741
|
-
}
|
|
742
218
|
export function resetModelPolicyCachesForTests() {
|
|
743
219
|
registryCache = null;
|
|
744
|
-
|
|
220
|
+
resetCatalogPolicyCache();
|
|
745
221
|
}
|
|
746
222
|
// Dispatch rechecks consume the effective policy from resolution. Keep these
|
|
747
223
|
// predicates shared with route validation so defaults and restrictions agree.
|
|
@@ -787,11 +263,6 @@ function isWorkerEvidenceStale(observation, policy, now) {
|
|
|
787
263
|
return observed > now || now - observed > blockHours * 3600000
|
|
788
264
|
|| (verified !== undefined && (verified > now || now - verified > policyDays * 86400000));
|
|
789
265
|
}
|
|
790
|
-
/** Optional catalog facts do not veto otherwise qualified selection. */
|
|
791
|
-
export function hasSelectionRelevantConflicts(observation) {
|
|
792
|
-
const relevant = /^\/(?:lifecycle|availability|visibility|hidden|efforts|effortSupport|reasoningEfforts|sunsetAt|retiredAt|replacementModelId|supersededBy|dataUse|id|apiModelId|llmProvider|cliId|family|runtimeVersion|accountScope|endpointFingerprint|identityEvidence|contextTokens|maxOutputTokens|qualification)(?:\/|$)/;
|
|
793
|
-
return observation.conflicts?.some(conflict => relevant.test(conflict.field)) ?? false;
|
|
794
|
-
}
|
|
795
266
|
/** Validate a resolved route without launching or creating managed state. */
|
|
796
267
|
export function validateWorkerPolicyRoute(input) {
|
|
797
268
|
const diagnostics = [];
|