@aiwg/cli 2026.10.5 → 2026.10.7
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/addons/composition-engine/lib/runtime.mjs +1401 -0
- package/agentic/code/addons/composition-engine/lib/validator.mjs +513 -0
- package/agentic/code/addons/composition-engine/schemas/flow-graph.schema.json +372 -0
- package/agentic/code/providers/model-capabilities.v1.json +74 -50
- package/bin/aiwg.mjs +7 -3
- package/dist/src/a2a/agent-card.js +11 -0
- package/dist/src/api/index.d.ts +1 -0
- package/dist/src/api/index.js +1 -0
- package/dist/src/artifacts/browser-export.js +1 -0
- package/dist/src/artifacts/citation-parser.js +8 -1
- package/dist/src/artifacts/cli.js +57 -6
- package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
- package/dist/src/artifacts/fortemi-core-sync.js +26 -8
- package/dist/src/artifacts/fortemi-shard-contract/2.2.0/contract.json +103 -0
- package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-embedding-config.schema.json +212 -0
- package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-embedding-set.schema.json +240 -0
- package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-manifest.schema.json +451 -0
- package/dist/src/artifacts/fortemi-shard-export.js +284 -0
- package/dist/src/artifacts/graph-query.js +18 -8
- package/dist/src/artifacts/index-adapters.js +339 -0
- package/dist/src/artifacts/index-builder.js +143 -14
- package/dist/src/artifacts/index-files.js +15 -4
- package/dist/src/artifacts/index-preparation.js +2 -0
- package/dist/src/artifacts/index-reader.js +44 -0
- package/dist/src/artifacts/index-refresh.js +114 -55
- package/dist/src/artifacts/index-status.js +20 -5
- package/dist/src/artifacts/memory-maintenance.js +503 -0
- package/dist/src/artifacts/prebuilt-relations.js +3 -1
- package/dist/src/artifacts/query-engine.js +263 -108
- package/dist/src/artifacts/relations-builder.js +2 -2
- package/dist/src/artifacts/source-graph.js +2 -2
- package/dist/src/artifacts/types.js +9 -1
- package/dist/src/auth/client.js +5 -1
- package/dist/src/auth/credential-store.js +5 -1
- package/dist/src/auth/sensitive-input.js +151 -0
- package/dist/src/channel/manager.mjs +3 -0
- package/dist/src/cli/handlers/agentcard.js +47 -25
- package/dist/src/cli/handlers/auth.js +22 -2
- package/dist/src/cli/handlers/decision.js +22 -3
- package/dist/src/cli/handlers/effect.js +4 -84
- package/dist/src/cli/handlers/guided-setup.js +470 -0
- package/dist/src/cli/handlers/help.js +2 -2
- package/dist/src/cli/handlers/housekeeper.js +1110 -0
- package/dist/src/cli/handlers/index.js +4 -2
- package/dist/src/cli/handlers/init.js +41 -6
- package/dist/src/cli/handlers/install.js +6 -0
- package/dist/src/cli/handlers/local-executor.js +5 -3
- package/dist/src/cli/handlers/marketplace.js +15 -4
- package/dist/src/cli/handlers/mc.js +509 -53
- package/dist/src/cli/handlers/models.js +32 -2
- package/dist/src/cli/handlers/ralph-launcher.js +76 -4
- package/dist/src/cli/handlers/rules.js +1 -1
- package/dist/src/cli/handlers/script-runner.js +73 -2
- package/dist/src/cli/handlers/serve.js +5 -3
- package/dist/src/cli/handlers/sessions.js +1 -0
- package/dist/src/cli/handlers/setup.js +432 -1
- package/dist/src/cli/handlers/skill-lint.js +1 -1
- package/dist/src/cli/handlers/subcommands.js +118 -8
- package/dist/src/cli/handlers/use.js +335 -107
- package/dist/src/cli/handlers/workspace.js +3 -1
- package/dist/src/cli/prompt-utils.js +81 -0
- package/dist/src/cli/router.js +16 -1
- package/dist/src/config/aiwg-config.js +42 -0
- package/dist/src/config/cli.js +7 -3
- package/dist/src/config/decision-config.js +14 -1
- package/dist/src/config/gitignore.js +4 -0
- package/dist/src/config/native-sandbox-warnings.js +25 -0
- package/dist/src/config/workspace.js +2 -1
- package/dist/src/contributors/validation.js +6 -5
- package/dist/src/decision/adapters/jev.js +20 -31
- package/dist/src/decision/admission.js +7 -3
- package/dist/src/decision/ask.js +6 -1
- package/dist/src/decision/benchmark.js +482 -0
- package/dist/src/decision/ledger.js +22 -3
- package/dist/src/decision/pricing.js +147 -0
- package/dist/src/decision/qualification/gate-evidence.js +23 -18
- package/dist/src/decision/qualification/load-staged.js +576 -0
- package/dist/src/decision/qualification/load.js +109 -33
- package/dist/src/decision/qualification/runner.js +12 -5
- package/dist/src/decision/review/service.js +6 -4
- package/dist/src/decision/review/validate.js +23 -2
- package/dist/src/decision/savings.js +8 -3
- package/dist/src/discovery/index.js +492 -0
- package/dist/src/discovery/interview.js +238 -0
- package/dist/src/discovery/plan-apply.js +567 -0
- package/dist/src/discovery/plan-store.js +171 -0
- package/dist/src/discovery/plan-types.js +2 -0
- package/dist/src/discovery/plan-validation.js +139 -0
- package/dist/src/discovery/types.js +2 -0
- package/dist/src/effects/host.js +91 -0
- package/dist/src/extensions/commands/definitions.js +49 -9
- package/dist/src/extensions/manifest.js +71 -44
- package/dist/src/extensions/project-local-discovery.js +1 -1
- package/dist/src/extensions/project-local-gitignore.js +2 -0
- package/dist/src/extensions/project-quickref.js +18 -17
- package/dist/src/extensions/validation.js +32 -29
- package/dist/src/housekeeper/daemon-config.js +148 -0
- package/dist/src/housekeeper/ipc.js +84 -0
- package/dist/src/housekeeper/lifecycle.js +148 -0
- package/dist/src/housekeeper/platform.js +35 -0
- package/dist/src/housekeeper/status.js +70 -0
- package/dist/src/housekeeper/units.js +114 -0
- package/dist/src/issues/cli.js +16 -5
- package/dist/src/issues/live.js +44 -12
- package/dist/src/jobs/flow.js +22 -21
- package/dist/src/lint/rule-activation.js +20 -5
- package/dist/src/lint/runner.js +1 -1
- package/dist/src/marketplace/exchange.js +18 -6
- package/dist/src/marketplace/provenance.js +3 -2
- package/dist/src/mcp/adapters/codex-runtime.js +46 -76
- package/dist/src/mcp/cli.mjs +22 -96
- package/dist/src/mcp/config-file.mjs +6 -2
- package/dist/src/mcp/config-layers.mjs +23 -7
- package/dist/src/mcp/grok-build-config.mjs +2 -1
- package/dist/src/mcp/muse-native-config.mjs +2 -1
- package/dist/src/mcp/profiles.js +18 -31
- package/dist/src/mcp/profiles.mjs +18 -32
- package/dist/src/mcp/registry.js +7 -27
- package/dist/src/mcp/registry.mjs +7 -28
- package/dist/src/mcp/server.mjs +34 -1
- package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
- package/dist/src/mcp/tools/command-run.mjs +3 -2
- package/dist/src/mcp/tools/decision.mjs +49 -48
- package/dist/src/mcp/tools/discovery.mjs +46 -21
- package/dist/src/mcp/tools/orchestration.mjs +22 -22
- package/dist/src/mcp/tools/subsystems.mjs +9 -8
- package/dist/src/mcp/tools/worker-invoke.mjs +30 -6
- package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
- package/dist/src/memory/audit.js +719 -0
- package/dist/src/memory/canonical-context.js +392 -13
- package/dist/src/memory/canonical-maintenance.js +95 -0
- package/dist/src/memory/cli-result.js +22 -0
- package/dist/src/memory/cli.js +176 -0
- package/dist/src/memory/context-pack.js +57 -6
- package/dist/src/memory/cost.js +512 -0
- package/dist/src/memory/firewall-classification.d.mts +7 -0
- package/dist/src/memory/firewall-classification.mjs +32 -0
- package/dist/src/memory/index.js +8 -0
- package/dist/src/memory/line-maintenance.js +68 -0
- package/dist/src/memory/maintenance-cli.js +286 -0
- package/dist/src/memory/maintenance-contract.js +136 -0
- package/dist/src/memory/maintenance-index.js +18 -0
- package/dist/src/memory/maintenance-owner.js +2 -0
- package/dist/src/memory/maintenance-record.js +138 -0
- package/dist/src/memory/maintenance.js +254 -0
- package/dist/src/memory/project-registry.js +2 -1
- package/dist/src/memory/provider-memory-adapter.js +154 -0
- package/dist/src/memory/recommend-cli.js +83 -0
- package/dist/src/memory/recommend.js +269 -0
- package/dist/src/memory/scheduled.js +81 -0
- package/dist/src/memory/taxonomy.js +44 -0
- package/dist/src/mission-protocol/codecs.js +19 -9
- package/dist/src/mission-protocol/worker-status.js +91 -1
- package/dist/src/models/config-loader.js +11 -1
- package/dist/src/models/model-capabilities.v1.json +74 -50
- package/dist/src/models/provider-policy.js +125 -62
- package/dist/src/models/resolver.js +45 -8
- package/dist/src/models/worker-installation.d.mts +8 -1
- package/dist/src/models/worker-installation.mjs +231 -38
- package/dist/src/models/wrapper-route.js +1 -1
- package/dist/src/output-modes/registry.js +8 -7
- package/dist/src/packages/adapters/git.js +99 -23
- package/dist/src/packages/adapters/gitea.js +8 -27
- package/dist/src/packages/adapters/github.js +7 -25
- package/dist/src/packages/registry.js +4 -4
- package/dist/src/plugin/metadata-validator.js +1 -1
- package/dist/src/process/cli-command.d.mts +5 -0
- package/dist/src/process/cli-command.mjs +42 -0
- package/dist/src/providers/deploy-version.d.mts +1 -0
- package/dist/src/providers/deploy-version.mjs +17 -0
- package/dist/src/providers/provider-definitions.js +19 -16
- package/dist/src/providers/skill-ownership.d.mts +11 -2
- package/dist/src/providers/skill-ownership.mjs +35 -17
- package/dist/src/rules/activation.d.mts +11 -2
- package/dist/src/rules/activation.mjs +82 -6
- package/dist/src/rules/inventory.js +1 -1
- package/dist/src/rules/rule-frontmatter.schema.json +2 -0
- package/dist/src/schema/zod-validation.d.mts +6 -0
- package/dist/src/schema/zod-validation.mjs +50 -0
- package/dist/src/serve/executor-registry.js +297 -20
- package/dist/src/serve/executor-token.d.mts +1 -0
- package/dist/src/serve/executor-token.mjs +8 -0
- package/dist/src/serve/shared-host-scheduler.js +1102 -31
- package/dist/src/serve/worker-invocation.js +124 -15
- package/dist/src/sessions/adapters/claude.js +19 -18
- package/dist/src/sessions/adapters/codex.js +10 -9
- package/dist/src/sessions/adapters/copilot.js +14 -13
- package/dist/src/sessions/adapters/cursor.js +19 -18
- package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
- package/dist/src/sessions/adapters/factory.js +11 -10
- package/dist/src/sessions/adapters/generic.js +32 -23
- package/dist/src/sessions/adapters/grokbot.js +35 -35
- package/dist/src/sessions/adapters/hermes.js +20 -19
- package/dist/src/sessions/adapters/muse.js +50 -49
- package/dist/src/sessions/adapters/omp.js +5 -4
- package/dist/src/sessions/adapters/openclaw.js +30 -29
- package/dist/src/sessions/adapters/opencode.js +26 -26
- package/dist/src/sessions/adapters/openhuman.js +24 -23
- package/dist/src/sessions/adapters/pi.js +5 -4
- package/dist/src/sessions/adapters/windsurf.js +8 -8
- package/dist/src/sessions/analytics.js +10 -9
- package/dist/src/sessions/candidates.js +7 -6
- package/dist/src/sessions/contracts.js +63 -53
- package/dist/src/sessions/output-registration.js +11 -10
- package/dist/src/sessions/workspace-discovery.js +3 -4
- package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
- package/dist/src/smiths/context-pipeline/claude-hook.js +46 -10
- package/dist/src/smiths/context-pipeline/context-file-safety.js +330 -9
- package/dist/src/smiths/context-pipeline/finalization.js +3 -2
- package/dist/src/smiths/context-pipeline/generator.js +7 -19
- package/dist/src/smiths/context-pipeline/legacy-inject.js +3 -10
- package/dist/src/smiths/context-pipeline/managed-hook.js +5 -5
- package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
- package/dist/src/smiths/context-pipeline/workspace-context.js +110 -22
- package/dist/src/tracker/project-inputs.js +2 -0
- package/dist/src/update/checker.d.mts +4 -0
- package/dist/src/update/checker.mjs +14 -0
- package/dist/src/update/notifier.mjs +2 -4
- package/dist/src/writing/exemplar-selection.js +6 -6
- package/dist/src/writing/voice-evaluation.js +24 -23
- package/dist/src/writing/writer-migration.js +14 -13
- package/dist/src/writing/writer-profile.js +19 -18
- package/dist/src/writing/writing-brief.js +18 -17
- package/dist/src/writing/writing-receipt.js +47 -46
- package/package.json +5 -2
- package/schemas/decision/DecisionReview.schema.json +78 -1
- package/schemas/mission-v1.schema.json +3 -0
- package/tools/agents/deploy-agents.mjs +67 -39
- package/tools/agents/providers/antigravity.mjs +6 -1
- package/tools/agents/providers/base.mjs +24 -14
- package/tools/agents/providers/claude.mjs +6 -3
- package/tools/agents/providers/codex.mjs +54 -57
- package/tools/agents/providers/context-write.mjs +28 -0
- package/tools/agents/providers/copilot.mjs +13 -4
- package/tools/agents/providers/cursor.mjs +1 -1
- package/tools/agents/providers/deepseek-harness.mjs +1 -1
- package/tools/agents/providers/factory.mjs +7 -1
- package/tools/agents/providers/grok-build.mjs +18 -2
- package/tools/agents/providers/grokbot.mjs +1 -1
- package/tools/agents/providers/hermes.mjs +12 -15
- package/tools/agents/providers/muse-hooks.mjs +21 -14
- package/tools/agents/providers/muse.mjs +7 -2
- package/tools/agents/providers/omp.mjs +31 -5
- package/tools/agents/providers/opencode.mjs +14 -5
- package/tools/agents/providers/openhuman.mjs +1 -1
- package/tools/agents/providers/pi.mjs +1 -1
- package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
- package/tools/agents/providers/rule-delivery.mjs +289 -80
- package/tools/agents/providers/warp.mjs +4 -1
- package/tools/agents/providers/windsurf.mjs +13 -3
- package/tools/cli/workspace-status.mjs +5 -0
- package/tools/commands/deploy-prompts-codex.mjs +11 -8
- package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +26 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +7 -1
- package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
- package/tools/ralph-external/lib/recovery-probe.mjs +14 -4
- package/tools/ralph-external/lib/worker-health.mjs +1 -1
- package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
- package/tools/ralph-external/process-monitor.mjs +49 -8
- package/tools/ralph-external/session-launcher.mjs +405 -35
- package/tools/skills/deploy-skills-codex.mjs +11 -7
- package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
|
@@ -9,6 +9,7 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
9
9
|
import { dirname, resolve } from 'node:path';
|
|
10
10
|
import { fileURLToPath } from 'node:url';
|
|
11
11
|
import { z } from 'zod';
|
|
12
|
+
import { integer, dateTime, url, number } from '../schema/zod-validation.mjs';
|
|
12
13
|
import { createRequire } from 'node:module';
|
|
13
14
|
import { compileWorkerVersionPattern, workerVersionRangeMismatch } from './worker-installation.mjs';
|
|
14
15
|
import { normalizeProviderDefinitionId } from '../providers/provider-definitions.js';
|
|
@@ -63,7 +64,7 @@ export const WorkerAdapterSchema = z.custom().superRefine((value, context) => {
|
|
|
63
64
|
message: `Invalid worker adapter: ${error instanceof Error ? error.message : String(error)}` });
|
|
64
65
|
}
|
|
65
66
|
});
|
|
66
|
-
const CapabilityEntrySchema = z.
|
|
67
|
+
const CapabilityEntrySchema = z.strictObject({
|
|
67
68
|
sessionEnvAllowlist: z.array(z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/)).optional(),
|
|
68
69
|
agent: OutcomeSchema,
|
|
69
70
|
skill: OutcomeSchema,
|
|
@@ -75,31 +76,31 @@ const CapabilityEntrySchema = z.object({
|
|
|
75
76
|
configTarget: z.string().min(1),
|
|
76
77
|
artifactFormat: z.string().min(1),
|
|
77
78
|
verification: z.string().min(1),
|
|
78
|
-
sourceUrl:
|
|
79
|
+
sourceUrl: url(),
|
|
79
80
|
verifiedAt: z.string().date(),
|
|
80
81
|
workerAdapter: WorkerAdapterSchema.optional(),
|
|
81
82
|
// Descriptive health coverage is not an installed executable registration.
|
|
82
83
|
workerHealthAdapter: WorkerAdapterSchema.optional(),
|
|
83
|
-
workerHealthCoverage: z.
|
|
84
|
+
workerHealthCoverage: z.strictObject({
|
|
84
85
|
scope: z.literal('out'), coverage: z.literal('unobserved'), handshake: z.literal('unobserved'),
|
|
85
86
|
evidenceGrades: z.array(z.enum(['H', 'R', 'D'])).max(3),
|
|
86
87
|
qualificationOwner: z.string().regex(/^B-OG-[0-9]{2}$/),
|
|
87
88
|
provenance: z.array(z.string().min(1).max(4096)).min(1).max(16), reason: z.string().min(1).max(4096),
|
|
88
|
-
}).
|
|
89
|
-
})
|
|
90
|
-
const CapabilityRegistrySchema = z.
|
|
89
|
+
}).optional(),
|
|
90
|
+
});
|
|
91
|
+
const CapabilityRegistrySchema = z.strictObject({
|
|
91
92
|
$schema: z.enum([
|
|
92
93
|
'../../../schemas/models/provider-model-capabilities.v1.schema.json',
|
|
93
94
|
'https://aiwg.io/schemas/models/provider-model-capabilities.v1.schema.json',
|
|
94
95
|
]).optional(),
|
|
95
96
|
version: z.literal('1.0.0'),
|
|
96
97
|
verifiedAt: z.string().date(),
|
|
97
|
-
providers: z.
|
|
98
|
+
providers: z.partialRecord(ProviderSchema, CapabilityEntrySchema),
|
|
98
99
|
workerAdapters: z.record(z.string().regex(/^[a-z][a-z0-9-]{0,62}$/), WorkerAdapterSchema)
|
|
99
100
|
.refine(value => Object.keys(value).length <= 128, 'At most 128 worker adapters').optional(),
|
|
100
101
|
workerHealthAdapters: z.record(z.string().regex(/^[a-z][a-z0-9-]{0,62}$/), WorkerAdapterSchema)
|
|
101
102
|
.refine(value => Object.keys(value).length <= 128, 'At most 128 worker health descriptors').optional(),
|
|
102
|
-
})
|
|
103
|
+
});
|
|
103
104
|
const CatalogModelSchema = z.object({
|
|
104
105
|
id: z.string().min(1),
|
|
105
106
|
status: z.enum(['active', 'deprecated', 'unverified']),
|
|
@@ -112,7 +113,7 @@ const CatalogProviderSchema = z.object({
|
|
|
112
113
|
coding: CatalogModelSchema,
|
|
113
114
|
efficiency: CatalogModelSchema,
|
|
114
115
|
}),
|
|
115
|
-
sourceUrl:
|
|
116
|
+
sourceUrl: url(),
|
|
116
117
|
verifiedAt: z.string().date(),
|
|
117
118
|
});
|
|
118
119
|
let catalogValidators;
|
|
@@ -134,10 +135,10 @@ export function validateWorkerModelObservation(input) {
|
|
|
134
135
|
return validate(input) ? [] : (validate.errors ?? []).map(error => `${error.instancePath}: ${error.message}`);
|
|
135
136
|
}
|
|
136
137
|
const WorkerObservationSchema = z.custom(input => validateWorkerModelObservation(input).length === 0);
|
|
137
|
-
const DiscoveredWorkerModelSchema = z.
|
|
138
|
+
const DiscoveredWorkerModelSchema = z.looseObject({
|
|
138
139
|
id: z.string().min(1), apiModelId: z.string().optional(), llmProvider: z.string().optional(),
|
|
139
140
|
hidden: z.boolean().optional(), reasoningEfforts: z.array(z.string()).optional(), worker: WorkerObservationSchema.optional(),
|
|
140
|
-
}).
|
|
141
|
+
}).superRefine((model, context) => {
|
|
141
142
|
if (!model.worker)
|
|
142
143
|
return;
|
|
143
144
|
if (model.hidden !== undefined && model.worker.visibility !== (model.hidden ? 'hidden' : 'listed'))
|
|
@@ -147,17 +148,17 @@ const DiscoveredWorkerModelSchema = z.object({
|
|
|
147
148
|
if (efforts.length !== observed.length || new Set(observed).size !== observed.length || efforts.some(e => !observed.includes(e)))
|
|
148
149
|
context.addIssue({ code: 'custom', path: ['worker', 'efforts'], message: 'Conflicting effort evidence' });
|
|
149
150
|
});
|
|
150
|
-
const ProviderDiscoverySchema = z.
|
|
151
|
-
provider: z.string(), source: z.enum(['native', 'cache', 'remote', 'static']), observedAt:
|
|
151
|
+
const ProviderDiscoverySchema = z.looseObject({
|
|
152
|
+
provider: z.string(), source: z.enum(['native', 'cache', 'remote', 'static']), observedAt: dateTime({ offset: true }),
|
|
152
153
|
runtimeVersion: z.string().optional(), accountScope: z.enum(['local-account', 'local-runtime', 'public-feed', 'static']),
|
|
153
154
|
accountBinding: z.string().min(1).optional(), models: z.array(DiscoveredWorkerModelSchema),
|
|
154
|
-
})
|
|
155
|
-
const DiscoverySchema = z.
|
|
155
|
+
});
|
|
156
|
+
const DiscoverySchema = z.strictObject({
|
|
156
157
|
source: z.enum(['native', 'cache', 'remote', 'static']), upstreamSource: z.enum(['native', 'remote', 'static']).optional(),
|
|
157
|
-
fetchedAt:
|
|
158
|
+
fetchedAt: dateTime({ offset: true }), remoteUrl: url().optional(), remoteError: z.string().optional(),
|
|
158
159
|
inventorySignature: z.string().optional(), providers: z.record(z.string(), ProviderDiscoverySchema),
|
|
159
160
|
instances: z.record(z.string(), ProviderDiscoverySchema).optional(),
|
|
160
|
-
})
|
|
161
|
+
});
|
|
161
162
|
/** Optional enrichment is checked without tightening legacy catalog rows. */
|
|
162
163
|
export function validateWorkerCatalogDiscovery(input) {
|
|
163
164
|
if (input === undefined)
|
|
@@ -168,40 +169,40 @@ export function validateWorkerCatalogDiscovery(input) {
|
|
|
168
169
|
const parsed = DiscoverySchema.safeParse(input);
|
|
169
170
|
return parsed.success ? [] : parsed.error.issues.map(issue => `${issue.path.join('/')}: ${issue.message}`);
|
|
170
171
|
}
|
|
171
|
-
const CatalogSchema = z.
|
|
172
|
+
const CatalogSchema = z.strictObject({
|
|
172
173
|
version: z.literal('1.0.0'),
|
|
173
174
|
$schema: z.literal('../../../schemas/models/model-catalog.v1.schema.json').optional(),
|
|
174
175
|
discovery: DiscoverySchema.optional(),
|
|
175
176
|
refreshedAt: z.string().date(),
|
|
176
|
-
staleAfterDays:
|
|
177
|
-
providers: z.
|
|
178
|
-
})
|
|
179
|
-
const PolicySchema = z.
|
|
177
|
+
staleAfterDays: integer().positive(),
|
|
178
|
+
providers: z.partialRecord(ProviderSchema, CatalogProviderSchema),
|
|
179
|
+
});
|
|
180
|
+
const PolicySchema = z.strictObject({
|
|
180
181
|
role: z.enum(['reasoning', 'coding', 'efficiency']),
|
|
181
182
|
tier: z.enum(['economy', 'standard', 'premium']),
|
|
182
183
|
effort: z.enum(['minimal', 'low', 'medium', 'high', 'xhigh']).optional(),
|
|
183
184
|
override: z.string().min(1).optional(),
|
|
184
|
-
})
|
|
185
|
+
});
|
|
185
186
|
const uniqueStrings = z.array(z.string().min(1)).refine(values => new Set(values).size === values.length, 'Duplicate entries');
|
|
186
|
-
const WorkerDataPolicySchema = z.
|
|
187
|
+
const WorkerDataPolicySchema = z.strictObject({
|
|
187
188
|
allowedProcessing: z.array(z.enum(['local', 'remote'])).refine(values => new Set(values).size === values.length).optional(),
|
|
188
189
|
allowProductImprovement: z.boolean().optional(),
|
|
189
190
|
allowUnknown: z.boolean().optional(),
|
|
190
|
-
maxRetentionDays:
|
|
191
|
-
})
|
|
192
|
-
const WorkerRoleSchema = z.
|
|
191
|
+
maxRetentionDays: integer().nonnegative().optional(),
|
|
192
|
+
});
|
|
193
|
+
const WorkerRoleSchema = z.strictObject({
|
|
193
194
|
groups: uniqueStrings.refine(values => values.length > 0),
|
|
194
195
|
tier: z.enum(['economy', 'standard', 'premium', 'max-quality']),
|
|
195
196
|
initialEffort: z.string().min(1).nullable(),
|
|
196
197
|
effortLadder: uniqueStrings,
|
|
197
|
-
escalateAfter:
|
|
198
|
-
maxEscalations:
|
|
199
|
-
deescalateAfter:
|
|
198
|
+
escalateAfter: integer().positive().optional(),
|
|
199
|
+
maxEscalations: integer().nonnegative().optional(),
|
|
200
|
+
deescalateAfter: integer().positive().optional(),
|
|
200
201
|
allowNotApplicableEffort: z.boolean().optional(),
|
|
201
|
-
})
|
|
202
|
-
export const WorkerSelectionPolicySchema = z.
|
|
202
|
+
});
|
|
203
|
+
export const WorkerSelectionPolicySchema = z.strictObject({
|
|
203
204
|
roleGuidance: z.record(z.string().regex(/^[a-z][a-z0-9-]{0,62}$/), WorkerRoleSchema).optional(),
|
|
204
|
-
guards: z.
|
|
205
|
+
guards: z.strictObject({
|
|
205
206
|
deniedEfforts: uniqueStrings.optional(),
|
|
206
207
|
deniedModels: uniqueStrings.optional(),
|
|
207
208
|
denySelfDelegation: z.boolean().optional(),
|
|
@@ -209,16 +210,16 @@ export const WorkerSelectionPolicySchema = z.object({
|
|
|
209
210
|
allowedVisibility: z.array(z.enum(['listed', 'hidden'])).refine(v => new Set(v).size === v.length).optional(),
|
|
210
211
|
allowedLifecycle: z.array(z.enum(['active', 'deprecated'])).refine(v => new Set(v).size === v.length).optional(),
|
|
211
212
|
minimumIdentityEvidence: z.enum(['runtime-configured', 'backend-attested']).optional(),
|
|
212
|
-
}).
|
|
213
|
+
}).optional(),
|
|
213
214
|
dataPolicy: WorkerDataPolicySchema.optional(),
|
|
214
215
|
dataClasses: z.record(z.string().regex(/^[a-z][a-z0-9-]{0,62}$/), WorkerDataPolicySchema).optional(),
|
|
215
|
-
freshness: z.
|
|
216
|
-
warnHours:
|
|
217
|
-
blockHours:
|
|
218
|
-
policyDays:
|
|
219
|
-
}).
|
|
216
|
+
freshness: z.strictObject({
|
|
217
|
+
warnHours: integer().positive().optional(),
|
|
218
|
+
blockHours: integer().positive().optional(),
|
|
219
|
+
policyDays: integer().positive().optional(),
|
|
220
|
+
}).optional(),
|
|
220
221
|
taskClasses: z.record(z.string().regex(/^[a-z][a-z0-9-]{0,62}$/), z.string().min(1)).optional(),
|
|
221
|
-
}).
|
|
222
|
+
}).superRefine((policy, context) => {
|
|
222
223
|
for (const [role, guidance] of Object.entries(policy.roleGuidance ?? {})) {
|
|
223
224
|
if (!['efficiency', 'coding', 'reasoning'].includes(role))
|
|
224
225
|
context.addIssue({ code: 'custom', path: ['roleGuidance', role], message: 'Unknown worker role' });
|
|
@@ -332,28 +333,28 @@ export function mergeWorkerSelection(layers) {
|
|
|
332
333
|
}
|
|
333
334
|
return { policy, origins, diagnostics };
|
|
334
335
|
}
|
|
335
|
-
const UserProjectModelConfigSchema = z.
|
|
336
|
-
defaults: z.
|
|
336
|
+
const UserProjectModelConfigSchema = z.looseObject({
|
|
337
|
+
defaults: z.strictObject({
|
|
337
338
|
tier: z.enum(['economy', 'standard', 'premium', 'max-quality']).optional(),
|
|
338
339
|
provider: ProviderSchema.optional(),
|
|
339
340
|
workerSelection: WorkerSelectionPolicySchema.optional(),
|
|
340
|
-
}).
|
|
341
|
-
agentOverrides: z.record(z.string(), z.
|
|
341
|
+
}).optional(),
|
|
342
|
+
agentOverrides: z.record(z.string(), z.strictObject({
|
|
342
343
|
'model-tier': z.enum(['economy', 'standard', 'premium', 'max-quality']).optional(),
|
|
343
344
|
'model-override': z.string().min(1).optional(),
|
|
344
345
|
rationale: z.string().min(1).optional(),
|
|
345
|
-
})
|
|
346
|
-
customTiers: z.record(z.string(), z.
|
|
346
|
+
})).optional(),
|
|
347
|
+
customTiers: z.record(z.string(), z.strictObject({
|
|
347
348
|
description: z.string().min(1),
|
|
348
|
-
costMultiplier: z.
|
|
349
|
-
roleMapping: z.
|
|
349
|
+
costMultiplier: number().check(z.gte(0)).meta({ type: 'number', minimum: 0 }),
|
|
350
|
+
roleMapping: z.strictObject({
|
|
350
351
|
reasoning: z.enum(['reasoning', 'coding', 'efficiency']),
|
|
351
352
|
coding: z.enum(['reasoning', 'coding', 'efficiency']),
|
|
352
353
|
efficiency: z.enum(['reasoning', 'coding', 'efficiency']),
|
|
353
|
-
})
|
|
354
|
-
})
|
|
354
|
+
}),
|
|
355
|
+
})).optional(),
|
|
355
356
|
rationale: z.string().optional(),
|
|
356
|
-
})
|
|
357
|
+
});
|
|
357
358
|
let registryCache = null;
|
|
358
359
|
let catalogCache = null;
|
|
359
360
|
export function loadProviderModelCapabilities() {
|
|
@@ -415,12 +416,29 @@ export function resolveWorkerInstallation(registry, installation) {
|
|
|
415
416
|
/** Typed policy failures let public surfaces retain the cause without exposing internal details. */
|
|
416
417
|
export class WorkerPolicyError extends Error {
|
|
417
418
|
code;
|
|
418
|
-
|
|
419
|
+
details;
|
|
420
|
+
constructor(code, message, details) {
|
|
419
421
|
super(message);
|
|
420
422
|
this.code = code;
|
|
423
|
+
this.details = details;
|
|
421
424
|
this.name = 'WorkerPolicyError';
|
|
422
425
|
}
|
|
423
426
|
}
|
|
427
|
+
export class WorkerRoleEffortError extends WorkerPolicyError {
|
|
428
|
+
pointer;
|
|
429
|
+
constructor(role) {
|
|
430
|
+
const pointer = `/defaults/workerSelection/roleGuidance/${role.replace(/~/g, '~0').replace(/\//g, '~1')}/initialEffort`;
|
|
431
|
+
super('OG_CONFIG_REFERENCE', `Missing role guidance or explicit initial effort for role ${role}; configure models.json ${pointer}.`);
|
|
432
|
+
this.pointer = pointer;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/** Validate policy input before entering the sanitized adapter boundary. Null
|
|
436
|
+
* remains valid for models whose effort is explicitly not applicable. */
|
|
437
|
+
export function assertWorkerRoleEffort(policy, role, requiresExplicit = false) {
|
|
438
|
+
const effort = policy?.roleGuidance?.[role]?.initialEffort;
|
|
439
|
+
if (effort === undefined || requiresExplicit && (effort === null || !effort.trim()))
|
|
440
|
+
throw new WorkerRoleEffortError(role);
|
|
441
|
+
}
|
|
424
442
|
/**
|
|
425
443
|
* Dispatch-time safety checks belong here, alongside transport qualification.
|
|
426
444
|
* Like route validation, rendering requires observation evidence; a default
|
|
@@ -498,7 +516,8 @@ export function requiredWorkerControls(context) {
|
|
|
498
516
|
}
|
|
499
517
|
/** The same sandbox requirement governs inspection, resolution and rendering. */
|
|
500
518
|
export function requiresWorkerExternalBoundary(adapter, selection) {
|
|
501
|
-
if (hasOperatorWorkerNativeRenderer(adapter)
|
|
519
|
+
if (hasOperatorWorkerNativeRenderer(adapter)
|
|
520
|
+
&& (selection.permissions?.sandbox !== 'external' || selection.transport === 'shell'))
|
|
502
521
|
return false;
|
|
503
522
|
const providers = [adapter.id, adapter.provider].map(normalizeProviderDefinitionId);
|
|
504
523
|
return requiredWorkerControls(selection).includes('sandbox')
|
|
@@ -513,11 +532,23 @@ export function isOperatorQualifiedWorkerAdapter(adapter) {
|
|
|
513
532
|
return adapter.qualification.status === 'qualified'
|
|
514
533
|
&& adapter.qualification.evidenceRef === WORKER_OPERATOR_APPROVAL;
|
|
515
534
|
}
|
|
516
|
-
/**
|
|
535
|
+
/** Bundled renderers with an independently checked native direct baseline. */
|
|
517
536
|
export function hasOperatorWorkerNativeRenderer(adapter) {
|
|
518
|
-
return isOperatorQualifiedWorkerAdapter(adapter) && adapter.provider
|
|
537
|
+
return isOperatorQualifiedWorkerAdapter(adapter) && ['codex', 'muse'].includes(adapter.provider)
|
|
519
538
|
&& adapter.invocation.kind === 'process';
|
|
520
539
|
}
|
|
540
|
+
/** The process-group launch boundary requires the independently verified native renderer. */
|
|
541
|
+
export function assertWorkerLaunchMode(adapter, permissions = {}) {
|
|
542
|
+
const mode = permissions.launchMode ?? 'systemd-unit';
|
|
543
|
+
if (!['systemd-unit', 'native-sandbox'].includes(mode)) {
|
|
544
|
+
throw new WorkerPolicyError('OG_CONFIG_REFERENCE', 'Unknown worker launch mode');
|
|
545
|
+
}
|
|
546
|
+
if (mode === 'native-sandbox' && (!hasOperatorWorkerNativeRenderer(adapter)
|
|
547
|
+
|| !['read-only', 'workspace-write'].includes(permissions.sandbox ?? '')
|
|
548
|
+
|| (permissions.transport ?? 'shell') !== 'shell')) {
|
|
549
|
+
throw new WorkerPolicyError('OG_POLICY_RELAXATION', 'native-sandbox requires a verified native read-only or workspace-write shell renderer');
|
|
550
|
+
}
|
|
551
|
+
}
|
|
521
552
|
/** Check the actual argv before granting the direct renderer exception. */
|
|
522
553
|
export function assertOperatorWorkerNativeArgv(adapter, argv, selected, permissions) {
|
|
523
554
|
if (!hasOperatorWorkerNativeRenderer(adapter))
|
|
@@ -529,10 +560,46 @@ export function assertOperatorWorkerNativeArgv(adapter, argv, selected, permissi
|
|
|
529
560
|
}
|
|
530
561
|
};
|
|
531
562
|
const sandbox = permissions?.sandbox ?? 'workspace-write';
|
|
532
|
-
if (!['read-only', 'workspace-write'].includes(sandbox))
|
|
563
|
+
if (!['read-only', 'workspace-write', 'external'].includes(sandbox))
|
|
533
564
|
throw new Error('Requested sandbox has no verified native renderer');
|
|
565
|
+
if (adapter.provider === 'muse') {
|
|
566
|
+
requirePair('--provider', 'meta');
|
|
567
|
+
requirePair('--model', selected.model);
|
|
568
|
+
if (selected.effort.value === null)
|
|
569
|
+
throw new Error('Muse requires explicit effort');
|
|
570
|
+
requirePair('--reasoning-effort', selected.effort.value);
|
|
571
|
+
if ((permissions?.approval ?? 'never') !== 'never')
|
|
572
|
+
throw new Error('Muse direct worker approval requires never');
|
|
573
|
+
requirePair('--approval-mode', 'never');
|
|
574
|
+
requirePair('--approval-judge', 'off');
|
|
575
|
+
if (args.includes('--disable-sandbox') !== (sandbox === 'external')) {
|
|
576
|
+
throw new Error('Requested native worker sandbox control does not match');
|
|
577
|
+
}
|
|
578
|
+
if (sandbox === 'read-only' && (!args.includes('--disable-write') || !args.includes('--disable-shell'))) {
|
|
579
|
+
throw new Error('Requested native worker read-only control is absent');
|
|
580
|
+
}
|
|
581
|
+
if (args[0] !== 'exec')
|
|
582
|
+
throw new Error('Native worker controls could be overridden');
|
|
583
|
+
const seen = new Set();
|
|
584
|
+
for (let index = 1; index < args.length; index++) {
|
|
585
|
+
const flag = args[index];
|
|
586
|
+
if (seen.has(flag))
|
|
587
|
+
throw new Error('Native worker controls could be overridden');
|
|
588
|
+
seen.add(flag);
|
|
589
|
+
if (['--json', '--trust-workspace', '--disable-write', '--disable-shell', '--disable-sandbox'].includes(flag))
|
|
590
|
+
continue;
|
|
591
|
+
if (!['--provider', '--model', '--reasoning-effort', '--workspace', '--approval-mode', '--approval-judge',
|
|
592
|
+
'--max-model-steps', '--output-schema', '--prompt-file'].includes(flag) || index + 1 >= args.length) {
|
|
593
|
+
throw new Error('Native worker controls could be overridden');
|
|
594
|
+
}
|
|
595
|
+
index++;
|
|
596
|
+
}
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
534
599
|
requirePair('-m', selected.model);
|
|
535
|
-
requirePair('-s', sandbox);
|
|
600
|
+
requirePair('-s', sandbox === 'external' ? 'danger-full-access' : sandbox);
|
|
601
|
+
if ((permissions?.approval ?? 'never') !== 'never')
|
|
602
|
+
throw new Error('Codex direct worker approval requires never');
|
|
536
603
|
for (const [name, value] of [['model_reasoning_effort', selected.effort.value], ['approval_policy', permissions?.approval ?? 'never']]) {
|
|
537
604
|
const overrides = args.flatMap((token, index) => token === '-c' ? [args[index + 1]] : [])
|
|
538
605
|
.filter(token => token?.split('=')[0] === name);
|
|
@@ -577,13 +644,9 @@ export function inspectWorkerInvocationProfile(adapter, selection) {
|
|
|
577
644
|
// The direct CLI baseline trusts the installed driver's bounded renderer.
|
|
578
645
|
// Explicit extra controls still require the existing qualified mappings.
|
|
579
646
|
if (hasOperatorWorkerNativeRenderer(adapter) && profile.transport === 'shell') {
|
|
580
|
-
if (selection.permissions?.sandbox && !['read-only', 'workspace-write'].includes(selection.permissions.sandbox)) {
|
|
647
|
+
if (selection.permissions?.sandbox && !['read-only', 'workspace-write', 'external'].includes(selection.permissions.sandbox)) {
|
|
581
648
|
throw new Error('Requested sandbox has no verified native renderer');
|
|
582
649
|
}
|
|
583
|
-
if (selection.permissions?.sandbox === 'external' && (!selection.boundary
|
|
584
|
-
|| !['os', 'executor'].includes(selection.boundary.kind) || !selection.boundary.controls.includes('sandbox'))) {
|
|
585
|
-
throw new Error('Requested external sandbox requires an enforcing boundary');
|
|
586
|
-
}
|
|
587
650
|
for (const name of selection.requiredControls ?? []) {
|
|
588
651
|
if (!['native', 'external'].includes(profile.controls[name]?.support)) {
|
|
589
652
|
throw new Error(`Required worker control is unqualified: ${name}`);
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { ConfigLoader } from './config-loader.js';
|
|
9
9
|
import { WORKER_DISPATCH_ENABLE_COMMAND, WORKER_DISPATCH_READINESS_COMMAND } from './worker-dispatch-offer.js';
|
|
10
10
|
import { resolveWorkerGroupInstallation, resolveParallelism, validateWorkerGroupQualifications, validateWorkerGroupReferences, validateWorkerBudgetEnforcement, workerActivationDigests, workerConfigDigest, } from '../config/aiwg-config.js';
|
|
11
|
-
import { qualifyWorkerInvocationProfile, validateWorkerPolicyRoute, validateWorkerModelObservation, hasOperatorWorkerNativeRenderer, hasSelectionRelevantConflicts, workerContextHeadroom, workerModelKey, isCanonicalWorkerModelKey, WorkerSelectionPolicySchema, validateWorkerCatalogDiscovery, } from './provider-policy.js';
|
|
11
|
+
import { qualifyWorkerInvocationProfile, validateWorkerPolicyRoute, validateWorkerModelObservation, assertWorkerLaunchMode, hasOperatorWorkerNativeRenderer, hasSelectionRelevantConflicts, workerContextHeadroom, workerModelKey, isCanonicalWorkerModelKey, WorkerSelectionPolicySchema, validateWorkerCatalogDiscovery, } from './provider-policy.js';
|
|
12
12
|
import { MODEL_WRAPPERS } from './provider-models.js';
|
|
13
13
|
import { routeModelTier } from './router.js';
|
|
14
14
|
/**
|
|
@@ -257,6 +257,14 @@ function findWorkerModelRow(rows, model) {
|
|
|
257
257
|
const matches = rows?.filter(row => row.id === model || row.apiModelId === model) ?? [];
|
|
258
258
|
return matches.length === 1 ? matches[0] : undefined;
|
|
259
259
|
}
|
|
260
|
+
function workerCatalogDigest(catalog) {
|
|
261
|
+
if (!catalog.discovery)
|
|
262
|
+
return workerConfigDigest(catalog);
|
|
263
|
+
// Offline loads synthesize fetchedAt. Keep catalog facts and persisted
|
|
264
|
+
// observation/qualification times pinned, independent of the load clock.
|
|
265
|
+
const { fetchedAt, ...discovery } = catalog.discovery;
|
|
266
|
+
return workerConfigDigest({ ...catalog, discovery });
|
|
267
|
+
}
|
|
260
268
|
/** Pure S1 resolution. No probing, launch, activation, admission, or writes.
|
|
261
269
|
* Recheck against freshly loaded snapshots before preparing an invocation. */
|
|
262
270
|
export function resolveWorkerPlan(snapshot, request) {
|
|
@@ -266,7 +274,7 @@ export function resolveWorkerPlan(snapshot, request) {
|
|
|
266
274
|
...snapshot.modelDigests,
|
|
267
275
|
configDigest: workerActivationDigests(snapshot.config).configDigest,
|
|
268
276
|
resolvedModelsDigest: workerConfigDigest(snapshot.models),
|
|
269
|
-
catalogDigest:
|
|
277
|
+
catalogDigest: workerCatalogDigest(snapshot.catalog),
|
|
270
278
|
profileDigest: workerConfigDigest([snapshot.registry, snapshot.installations]),
|
|
271
279
|
constraintsDigest: workerConfigDigest(snapshot.constraints),
|
|
272
280
|
};
|
|
@@ -305,7 +313,6 @@ export function resolveWorkerPlan(snapshot, request) {
|
|
|
305
313
|
if (!activation || ['configDigest', 'projectModelsDigest', 'userModelsDigest', 'builtinModelsDigest'].some(key => activation[key] !== digests[key])) {
|
|
306
314
|
block('OG_CONFIG_REFERENCE', '/parallelism/activation', 'Managed activation is missing or stale');
|
|
307
315
|
}
|
|
308
|
-
block('OG_ADAPTER_UNQUALIFIED', '/parallelism/worker_mode', 'Managed activation/admission runtime is deferred to S2+');
|
|
309
316
|
}
|
|
310
317
|
if (!policy)
|
|
311
318
|
block('OG_CONFIG_REFERENCE', '/defaults/workerSelection', 'Current merged worker policy is required');
|
|
@@ -344,9 +351,12 @@ export function resolveWorkerPlan(snapshot, request) {
|
|
|
344
351
|
? observed.qualification.roles.filter(role => policy.roleGuidance?.[role]?.groups.includes(groupId)) : [];
|
|
345
352
|
}
|
|
346
353
|
}
|
|
347
|
-
|
|
354
|
+
// Qualification gaps are group-scoped: an unqualified group must not block a
|
|
355
|
+
// request that never considers it. Gaps are applied once the candidates are known.
|
|
356
|
+
const qualificationGaps = validateWorkerGroupQualifications(parallelism, qualifiedRoles).map(diagnostic => ({
|
|
348
357
|
...diagnostic, message: `${diagnostic.message}. Run aiwg doctor --probe-workers --qualify.`,
|
|
349
|
-
}))
|
|
358
|
+
}));
|
|
359
|
+
const gapGroup = (diagnostic) => diagnostic.pointer.split('/')[3] ?? '';
|
|
350
360
|
const taskRole = request.taskClass ? policy.taskClasses?.[request.taskClass] : undefined;
|
|
351
361
|
const role = request.role ?? taskRole;
|
|
352
362
|
plan.role = role ?? null;
|
|
@@ -365,10 +375,25 @@ export function resolveWorkerPlan(snapshot, request) {
|
|
|
365
375
|
|| hasSelectionRelevantConflicts(request.reviewOf) || !request.reviewOf.family || request.reviewOf.family === 'unknown')) {
|
|
366
376
|
block('OG_MODEL_UNAPPROVED', '/request/reviewOf', 'Required review needs unambiguous observed source lineage');
|
|
367
377
|
}
|
|
378
|
+
const candidateGroups = request.group ? [request.group] : guidance?.groups ?? [];
|
|
379
|
+
const unqualifiedGroups = new Set(qualificationGaps.map(gapGroup));
|
|
380
|
+
const qualifiedGroups = candidateGroups.filter(groupId => !unqualifiedGroups.has(groupId));
|
|
381
|
+
if (!qualifiedGroups.length) {
|
|
382
|
+
plan.diagnostics.push(...qualificationGaps.filter(gap => candidateGroups.includes(gapGroup(gap))));
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
// Unpinned requests skip an unqualified guidance group visibly instead of failing the role.
|
|
386
|
+
for (const groupId of candidateGroups.filter(groupId => unqualifiedGroups.has(groupId))) {
|
|
387
|
+
const gaps = qualificationGaps.filter(gap => gapGroup(gap) === groupId);
|
|
388
|
+
for (const member of parallelism.groups?.[groupId]?.members ?? []) {
|
|
389
|
+
plan.exclusions.push({ group: groupId, member: member.id, model: member.model, effort: null, diagnostics: gaps });
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
368
393
|
if (plan.diagnostics.length || !role || !guidance)
|
|
369
394
|
return plan;
|
|
370
395
|
const wrapperPin = snapshot.models.agentOverrides[MODEL_WRAPPERS[role]]?.['model-override'];
|
|
371
|
-
const groups =
|
|
396
|
+
const groups = qualifiedGroups;
|
|
372
397
|
for (const groupId of groups) {
|
|
373
398
|
const group = parallelism.groups[groupId];
|
|
374
399
|
const permissions = { ...group.execution, transport: group.execution?.transport ?? 'shell' };
|
|
@@ -420,8 +445,13 @@ export function resolveWorkerPlan(snapshot, request) {
|
|
|
420
445
|
try {
|
|
421
446
|
const { adapter } = resolveWorkerGroupInstallation(parallelism, member.cli, snapshot.registry);
|
|
422
447
|
const configuredProfile = parallelism.clis?.[member.cli]?.invocationProfile;
|
|
423
|
-
|
|
424
|
-
|
|
448
|
+
const profilePointer = `/parallelism/clis/${member.cli}/invocationProfile`;
|
|
449
|
+
if (configuredProfile && !Object.hasOwn(adapter.invocationProfiles ?? {}, configuredProfile)) {
|
|
450
|
+
deny('OG_CONFIG_REFERENCE', profilePointer, 'Configured invocation profile is not registered for this adapter; select a registered profile.');
|
|
451
|
+
}
|
|
452
|
+
else if (configuredProfile && configuredProfile !== binding.profile) {
|
|
453
|
+
deny('OG_PIN_MISMATCH', profilePointer, 'Configured invocation profile differs from installation qualification; qualify the selected profile again.');
|
|
454
|
+
}
|
|
425
455
|
const configuredServer = parallelism.clis?.[member.cli]?.mcpServerRef;
|
|
426
456
|
if (transport === 'mcp' && configuredServer && configuredServer !== binding.mcp?.serverRef)
|
|
427
457
|
throw new Error('Configured MCP server changed');
|
|
@@ -433,9 +463,15 @@ export function resolveWorkerPlan(snapshot, request) {
|
|
|
433
463
|
throw new Error('Requested-only mapping cannot attest backend identity');
|
|
434
464
|
if (!hasOperatorWorkerNativeRenderer(adapter) && group.execution?.sandbox && !adapter.capabilities.sandboxModes.includes(group.execution.sandbox))
|
|
435
465
|
throw new Error('Requested sandbox mode is unqualified');
|
|
466
|
+
assertWorkerLaunchMode(adapter, permissions);
|
|
436
467
|
qualifyWorkerInvocationProfile(adapter, { profile: binding.profile, transport, cliVersion: binding.cliVersion,
|
|
437
468
|
policy, permissions, effort, boundary: binding.boundary,
|
|
438
469
|
requiredControls: request.requiredControls, mcp: binding.mcp });
|
|
470
|
+
if (hasOperatorWorkerNativeRenderer(adapter) && transport === 'shell' && permissions.sandbox === 'external') {
|
|
471
|
+
reasons.push({ code: 'OG_SANDBOX_EXTERNAL', blocking: false,
|
|
472
|
+
pointer: `/parallelism/groups/${groupId}/execution/sandbox`,
|
|
473
|
+
message: `${adapter.provider} CLI's own sandbox is disabled by explicit external policy; isolation relies on the per-task worktree and launcher resource scope.` });
|
|
474
|
+
}
|
|
439
475
|
const { maxAttempts: _maxAttempts, ...budgetLimits } = plan.ceilings;
|
|
440
476
|
const budgetDimensions = { tokens: 'tokens', cost: 'costUsd', 'wall-time': 'wallSeconds' };
|
|
441
477
|
const enforceable = adapter.capabilities.hardBudget.map(key => budgetDimensions[key]);
|
|
@@ -497,6 +533,7 @@ export function resolveWorkerPlan(snapshot, request) {
|
|
|
497
533
|
plan.selected = null;
|
|
498
534
|
if (plan.selected) {
|
|
499
535
|
plan.status = 'eligible';
|
|
536
|
+
plan.diagnostics.push(...plan.selected.diagnostics.filter(item => item.code === 'OG_SANDBOX_EXTERNAL'));
|
|
500
537
|
plan.choice = { source: request.choice ? 'conductor' : 'default', rationale: request.choice?.rationale ?? 'Role group order, member priority/declaration order, then qualified effort ladder',
|
|
501
538
|
...(request.substitution && matchesChoice(plan.selected, request.substitution) ? { substitution: structuredClone(request.substitution) } : {}) };
|
|
502
539
|
}
|
|
@@ -9,7 +9,9 @@ export function loadRecordedWorkerInstallations(input: {
|
|
|
9
9
|
parallelism?: import('../config/aiwg-config.js').ParallelismConfig;
|
|
10
10
|
storePath?: string;
|
|
11
11
|
storeDigest?: string;
|
|
12
|
-
|
|
12
|
+
/** Request validation after store presence, before recorded policy/adapter checks. */
|
|
13
|
+
precheckPolicy?: () => void;
|
|
14
|
+
}): Promise<{ registry: ProviderModelCapabilityRegistry; installations: Record<string, WorkerResolutionBinding>; drivers: Record<string, WorkerInvocationDriver>; observations: Record<string, import('./model-discovery.js').ProviderModelDiscovery>; qualificationFailures?: Record<string, string> }>;
|
|
13
15
|
|
|
14
16
|
export function hasProvider(name: string): boolean;
|
|
15
17
|
|
|
@@ -37,3 +39,8 @@ export function registerWorkerRecoveryCapabilities<T extends object>(driver: T,
|
|
|
37
39
|
export function getWorkerRecoveryCapabilities(driver: object | undefined | null): Readonly<WorkerRecoveryCapabilities> | null;
|
|
38
40
|
|
|
39
41
|
export function prepareWorkerInstallationStore(input: { workerWritableRoots: string[]; apply?: boolean }): Promise<{ path: string; action: string }[]>;
|
|
42
|
+
|
|
43
|
+
/** Historical approvals only; no driver import, probe, auth read, or launch authority. */
|
|
44
|
+
export function inspectRecordedWorkerQualifications(input: {
|
|
45
|
+
cwd: string; policy: WorkerSelectionPolicy; parallelism: import('../config/aiwg-config.js').ParallelismConfig;
|
|
46
|
+
}): Promise<Array<{ cli: string; provider: string }>>;
|