sneakoscope 10.2.0 → 10.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/cli/command-manifest-lite.js +3 -1
- package/dist/cli/command-registry.js +9 -1
- package/dist/cli/install-helpers-menubar.js +57 -0
- package/dist/cli/install-helpers.js +10 -1
- package/dist/commands/decision.js +7 -0
- package/dist/config/skills-manifest.json +1 -1
- package/dist/core/agents/native-worker-backend-router.js +7 -2
- package/dist/core/codex-app/menubar/constants.js +2 -0
- package/dist/core/decisions/cli.js +324 -0
- package/dist/core/decisions/config.js +109 -0
- package/dist/core/decisions/evaluation.js +62 -0
- package/dist/core/decisions/integration.js +262 -0
- package/dist/core/decisions/openrouter.js +270 -0
- package/dist/core/decisions/policy.js +393 -0
- package/dist/core/decisions/questions.js +215 -0
- package/dist/core/decisions/receipt.js +41 -0
- package/dist/core/decisions/recovery.js +39 -0
- package/dist/core/decisions/routing.js +58 -0
- package/dist/core/decisions/state.js +173 -0
- package/dist/core/decisions/types.js +69 -0
- package/dist/core/feature-fixtures.js +1 -0
- package/dist/core/feature-registry.js +1 -0
- package/dist/core/hooks-runtime/subagent-context.js +5 -3
- package/dist/core/hooks-runtime/subagent-spawn-policy.js +9 -3
- package/dist/core/provider/model-router.js +3 -3
- package/dist/core/routes.js +2 -1
- package/dist/core/subagents/model-policy.js +15 -0
- package/dist/core/subagents/official-subagent-lock.js +15 -0
- package/dist/core/subagents/official-subagent-preparation.js +265 -24
- package/dist/core/subagents/official-subagent-prompt.js +56 -13
- package/dist/core/update/update-migration-state/retired-local-decision.js +203 -0
- package/dist/core/update/update-migration-state.js +6 -0
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +6 -3
- package/dist/native/sks-menubar/Sources/LocalDecisionModels.swift +166 -0
- package/dist/native/sks-menubar/Sources/LocalDecisionViewController.swift +200 -0
- package/dist/native/sks-menubar/Sources/OverviewViewController.swift +4 -0
- package/dist/native/sks-menubar/Sources/SidebarItem.swift +2 -0
- package/dist/scripts/current-surface-update-e2e-check.js +1 -0
- package/package.json +1 -1
|
@@ -17,35 +17,91 @@ import { readRoleModelPreferences } from './role-model-preferences.js';
|
|
|
17
17
|
import { readConfiguredCodexModelRoutingContext } from '../codex-app/codex-model-catalog.js';
|
|
18
18
|
import { SUBAGENT_EVIDENCE_FILENAME, SUBAGENT_EVENT_LOG_FILENAME, SUBAGENT_PARENT_SUMMARY_FILENAME, normalizeSubagentParentSummary, writeSubagentEvidence } from './subagent-evidence.js';
|
|
19
19
|
import { sksPrefixedDollarCommand, unprefixedSksSkillName } from '../routes/dollar-prefix.js';
|
|
20
|
-
import {
|
|
20
|
+
import { tryWithFileLock } from '../locks/file-lock.js';
|
|
21
21
|
import { updateCurrentIfMissionAndRun } from '../mission.js';
|
|
22
22
|
import { HOST_CAPABILITY_HOOK_EVIDENCE_FILENAME, HOST_CAPABILITY_HOOK_OBSERVATIONS_FILENAME, HOST_CAPABILITY_HOOK_PENDING_RUNTIME_FILENAME, HOST_CAPABILITY_HOOK_RUNTIME_FILENAME } from '../agent-bridge/host-capability-runtime.js';
|
|
23
23
|
import { uniqueStrings } from '../text/strings.js';
|
|
24
24
|
import { officialSubagentEvidenceReady } from './terminal-subagent-state.js';
|
|
25
|
+
import { OFFICIAL_SUBAGENT_LIFECYCLE_LOCK, withOfficialSubagentLifecycleLock } from './official-subagent-lock.js';
|
|
26
|
+
import { decideOfficialSubagentPreparation } from '../decisions/integration.js';
|
|
27
|
+
import { applySealedRouting } from '../decisions/routing.js';
|
|
28
|
+
import { graphFileDigest, sourceSnapshotDigest } from '../decisions/state.js';
|
|
29
|
+
export { OFFICIAL_SUBAGENT_LIFECYCLE_LOCK, withOfficialSubagentLifecycleLock };
|
|
25
30
|
export const NARUTO_RESULT_SCHEMA = 'sks.naruto-subagent-workflow.v1';
|
|
26
31
|
export const SUBAGENT_PLAN_FILENAME = 'subagent-plan.json';
|
|
27
32
|
export const NARUTO_SUMMARY_FILENAME = 'naruto-summary.json';
|
|
28
33
|
export const NARUTO_GATE_FILENAME = 'naruto-gate.json';
|
|
29
|
-
export const OFFICIAL_SUBAGENT_LIFECYCLE_LOCK = '.subagent-evidence.lock';
|
|
30
34
|
export const OFFICIAL_SUBAGENT_PREPARATION_TRANSACTION = '.official-subagent-preparation-transaction.json';
|
|
31
35
|
export const SUBAGENT_LIFECYCLE_CAPTURE_FAILURE_DIR = 'subagent-lifecycle-capture-failures';
|
|
32
36
|
const OFFICIAL_SUBAGENT_PREPARATION_STAGE_PREFIX = '.official-subagent-preparation-stage-';
|
|
33
|
-
export function withOfficialSubagentLifecycleLock(dir, fn) {
|
|
34
|
-
return withFileLock({
|
|
35
|
-
lockPath: path.join(dir, OFFICIAL_SUBAGENT_LIFECYCLE_LOCK),
|
|
36
|
-
timeoutMs: 5_000,
|
|
37
|
-
staleMs: 60_000
|
|
38
|
-
}, fn);
|
|
39
|
-
}
|
|
40
37
|
export async function prepareOfficialSubagentMission(input) {
|
|
41
|
-
|
|
38
|
+
const opened = await withOfficialSubagentLifecycleLock(input.dir, () => openOfficialSubagentPreparation(input));
|
|
39
|
+
if (opened.kind === 'recovered')
|
|
40
|
+
return opened.result;
|
|
41
|
+
const derived = await deriveOfficialSubagentPreparation(input, opened.snapshot);
|
|
42
|
+
const decided = await decideOfficialSubagentPreparation({
|
|
43
|
+
root: input.root,
|
|
44
|
+
dir: input.dir,
|
|
45
|
+
missionId: input.missionId,
|
|
46
|
+
goal: String(input.goal || '').trim(),
|
|
47
|
+
workflowRunId: derived.workflowRunId,
|
|
48
|
+
workflowRevision: opened.snapshot.workflowRevision,
|
|
49
|
+
slices: derived.slices,
|
|
50
|
+
requestedSource: derived.requestedSource,
|
|
51
|
+
requestedSubagents: derived.budget.requestedSubagents,
|
|
52
|
+
attention: derived.triwikiAttention,
|
|
53
|
+
changedPaths: derived.sliceWriteScopes,
|
|
54
|
+
massParallel: derived.fanoutPolicy.mass_parallel === true,
|
|
55
|
+
routingRoles: derived.mode === 'naruto'
|
|
56
|
+
? routingRolesFromAgents(derived.agentRouting, derived.slices.map((slice) => slice.agent || ''))
|
|
57
|
+
: [],
|
|
58
|
+
env: input.env || process.env
|
|
59
|
+
});
|
|
60
|
+
const rebuilt = applyOfficialSubagentDecision(derived, decided);
|
|
61
|
+
return withOfficialSubagentLifecycleLock(input.dir, () => commitOfficialSubagentPreparation(input, opened.snapshot, rebuilt));
|
|
42
62
|
}
|
|
43
|
-
async function
|
|
63
|
+
async function openOfficialSubagentPreparation(input) {
|
|
44
64
|
const recovered = await recoverOfficialSubagentPreparationTransaction(input);
|
|
45
65
|
if (recovered)
|
|
46
|
-
return recovered;
|
|
66
|
+
return { kind: 'recovered', result: recovered };
|
|
47
67
|
const previousPlan = await readJson(path.join(input.dir, SUBAGENT_PLAN_FILENAME), null).catch(() => null);
|
|
48
|
-
const
|
|
68
|
+
const sourceDigest = await sourceSnapshotDigest(input.root);
|
|
69
|
+
const graphDigest = await graphFileDigest(input.root);
|
|
70
|
+
return {
|
|
71
|
+
kind: 'snapshot',
|
|
72
|
+
snapshot: {
|
|
73
|
+
previousWorkflowRunId: String(previousPlan?.workflow_run_id || '').trim(),
|
|
74
|
+
sourceDigest,
|
|
75
|
+
graphDigest,
|
|
76
|
+
workflowRevision: `${sourceDigest}:${graphDigest || 'no-graph'}`
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async function commitOfficialSubagentPreparation(input, snapshot, derived) {
|
|
81
|
+
const recovered = await recoverOfficialSubagentPreparationTransaction(input);
|
|
82
|
+
if (recovered)
|
|
83
|
+
return recovered;
|
|
84
|
+
const currentPlan = await readJson(path.join(input.dir, SUBAGENT_PLAN_FILENAME), null).catch(() => null);
|
|
85
|
+
const currentRunId = String(currentPlan?.workflow_run_id || '').trim();
|
|
86
|
+
const currentSource = await sourceSnapshotDigest(input.root);
|
|
87
|
+
const currentGraph = await graphFileDigest(input.root);
|
|
88
|
+
if ((currentRunId && currentRunId !== snapshot.previousWorkflowRunId)
|
|
89
|
+
|| currentSource !== snapshot.sourceDigest
|
|
90
|
+
|| currentGraph !== snapshot.graphDigest) {
|
|
91
|
+
if (currentPlan && String(currentPlan.goal || '') === String(input.goal || '').trim()
|
|
92
|
+
&& String(currentPlan.route || '') === String(input.route || '')) {
|
|
93
|
+
return {
|
|
94
|
+
...derived.preparedResultBase,
|
|
95
|
+
plan: currentPlan,
|
|
96
|
+
evidence: await readJson(path.join(input.dir, SUBAGENT_EVIDENCE_FILENAME), null).catch(() => null)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
throw new Error('official_subagent_preparation_stale_snapshot');
|
|
100
|
+
}
|
|
101
|
+
return promoteOfficialSubagentDerived(input, derived, snapshot.previousWorkflowRunId);
|
|
102
|
+
}
|
|
103
|
+
async function deriveOfficialSubagentPreparation(input, snapshot) {
|
|
104
|
+
const expectedWorkflowRunId = snapshot.previousWorkflowRunId;
|
|
49
105
|
const goal = String(input.goal || '').trim();
|
|
50
106
|
const mode = input.mode === 'naruto' ? 'naruto' : 'generic';
|
|
51
107
|
const taskProfile = classifyTaskProfile(goal);
|
|
@@ -208,15 +264,13 @@ async function prepareOfficialSubagentMissionLocked(input) {
|
|
|
208
264
|
readonly: config.sandbox_mode === 'read-only'
|
|
209
265
|
});
|
|
210
266
|
const preference = roleModelPreferences.store.roles[name];
|
|
211
|
-
const routedProvider = 'openai';
|
|
212
|
-
const routedModel = ASTRA_SUBAGENT_MODEL;
|
|
213
267
|
const routedReasoning = preference?.reasoning_effort
|
|
214
268
|
|| config.model_reasoning_effort
|
|
215
269
|
|| decision.model_reasoning_effort;
|
|
216
270
|
return [name, {
|
|
217
271
|
...config,
|
|
218
|
-
routed_provider:
|
|
219
|
-
routed_model:
|
|
272
|
+
routed_provider: 'openai',
|
|
273
|
+
routed_model: preference?.model || ASTRA_SUBAGENT_MODEL,
|
|
220
274
|
routed_model_reasoning_effort: routedReasoning,
|
|
221
275
|
routed_model_policy: preference
|
|
222
276
|
? 'user_role_model_preference'
|
|
@@ -320,7 +374,6 @@ async function prepareOfficialSubagentMissionLocked(input) {
|
|
|
320
374
|
verification: { budget: verification },
|
|
321
375
|
created_at: nowIso()
|
|
322
376
|
};
|
|
323
|
-
const statePatch = input.statePatch?.({ plan, budget, workflowRunId }) || null;
|
|
324
377
|
const preparedResultBase = {
|
|
325
378
|
plan,
|
|
326
379
|
budget,
|
|
@@ -336,19 +389,202 @@ async function prepareOfficialSubagentMissionLocked(input) {
|
|
|
336
389
|
observedParentModel,
|
|
337
390
|
parentModelMatch
|
|
338
391
|
};
|
|
392
|
+
return {
|
|
393
|
+
preparedResultBase,
|
|
394
|
+
slices,
|
|
395
|
+
requestedSource,
|
|
396
|
+
sliceWriteScopes,
|
|
397
|
+
sliceSafety,
|
|
398
|
+
suggestedAgents,
|
|
399
|
+
roleModelPreferences,
|
|
400
|
+
roleModelRouting,
|
|
401
|
+
activeMainModel,
|
|
402
|
+
officialConfig,
|
|
403
|
+
selectedFanoutPolicy,
|
|
404
|
+
configuredMaxThreads,
|
|
405
|
+
externalCodexHostCap,
|
|
406
|
+
externalCodexHostCapVerification,
|
|
407
|
+
taskProfile,
|
|
408
|
+
mode,
|
|
409
|
+
goal,
|
|
410
|
+
delegationGoal,
|
|
411
|
+
observedParentModel,
|
|
412
|
+
parentModelMatch,
|
|
413
|
+
workflowRunId,
|
|
414
|
+
expectedWorkflowRunId,
|
|
415
|
+
ssotGuard,
|
|
416
|
+
verification,
|
|
417
|
+
budget,
|
|
418
|
+
fanoutPolicy,
|
|
419
|
+
agentRouting,
|
|
420
|
+
agentCatalog,
|
|
421
|
+
routeContract,
|
|
422
|
+
operatorRequested,
|
|
423
|
+
requestedSubagents,
|
|
424
|
+
triwikiAttention,
|
|
425
|
+
configBlockers,
|
|
426
|
+
plan,
|
|
427
|
+
sessionScope: input.sessionScope || null
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
function routingRolesFromAgents(agentRouting, preferredNames = []) {
|
|
431
|
+
const preferred = new Set(preferredNames.filter(Boolean));
|
|
432
|
+
const entries = Object.entries(agentRouting);
|
|
433
|
+
const ordered = [
|
|
434
|
+
...entries.filter(([name]) => preferred.has(name)),
|
|
435
|
+
...entries.filter(([name]) => !preferred.has(name))
|
|
436
|
+
];
|
|
437
|
+
return ordered.flatMap(([name, row]) => {
|
|
438
|
+
if (row?.routing_dynamic !== true || row.routed_model_policy === 'user_role_model_preference')
|
|
439
|
+
return [];
|
|
440
|
+
return [{
|
|
441
|
+
name,
|
|
442
|
+
dynamic: true,
|
|
443
|
+
summary: String(row.description || name)
|
|
444
|
+
}];
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
function applyOfficialSubagentDecision(derived, decided) {
|
|
448
|
+
const attention = decided.attention;
|
|
449
|
+
const selectedPlan = derived.requestedSource === 'automatic' ? decided.selectedPlan : null;
|
|
450
|
+
const selectedRouting = derived.requestedSource === 'automatic' ? decided.selectedRouting : null;
|
|
451
|
+
const agents = applySealedRouting(derived.plan.agents, selectedRouting);
|
|
452
|
+
const budget = selectedPlan
|
|
453
|
+
? rebuildBudget(derived, selectedPlan)
|
|
454
|
+
: derived.budget;
|
|
455
|
+
let fanoutPolicy = selectedPlan
|
|
456
|
+
? {
|
|
457
|
+
...derived.fanoutPolicy,
|
|
458
|
+
requested_subagents: budget.requestedSubagents,
|
|
459
|
+
jev_selected_plan: selectedPlan.id
|
|
460
|
+
}
|
|
461
|
+
: { ...derived.fanoutPolicy };
|
|
462
|
+
if (selectedRouting)
|
|
463
|
+
fanoutPolicy = { ...fanoutPolicy, jev_selected_routing: selectedRouting.id };
|
|
464
|
+
const routingPreferences = selectedRouting
|
|
465
|
+
? Object.fromEntries(Object.entries(selectedRouting.efforts)
|
|
466
|
+
.filter(([name]) => !derived.roleModelPreferences.store.roles[name])
|
|
467
|
+
.map(([name, effort]) => [name, {
|
|
468
|
+
provider: 'openai',
|
|
469
|
+
model: selectedRouting.models[name] || 'gpt-6-astra',
|
|
470
|
+
reasoning_effort: effort,
|
|
471
|
+
updated_at: derived.plan.workflow_run_id
|
|
472
|
+
}]))
|
|
473
|
+
: {};
|
|
474
|
+
const delegationPrompt = buildOfficialSubagentPrompt({
|
|
475
|
+
goal: derived.delegationGoal,
|
|
476
|
+
slices: derived.slices,
|
|
477
|
+
requestedSubagents: budget.requestedSubagents,
|
|
478
|
+
requestedSubagentsExplicit: derived.requestedSource === 'operator',
|
|
479
|
+
requestedSubagentsSource: derived.requestedSource,
|
|
480
|
+
maxThreads: budget.maxThreads,
|
|
481
|
+
decompositionStatus: derived.plan.decomposition_status,
|
|
482
|
+
firstWave: budget.firstWave,
|
|
483
|
+
waveCount: budget.waveCount,
|
|
484
|
+
capacity: budget.capacity,
|
|
485
|
+
triwikiAttention: attention,
|
|
486
|
+
recommendedAgents: derived.suggestedAgents,
|
|
487
|
+
roleModelPreferences: {
|
|
488
|
+
...derived.roleModelPreferences.store.roles,
|
|
489
|
+
...routingPreferences
|
|
490
|
+
},
|
|
491
|
+
routedAgents: agents,
|
|
492
|
+
narutoChildRouting: derived.mode === 'naruto',
|
|
493
|
+
activeMainModel: derived.activeMainModel,
|
|
494
|
+
parentOutputMode: derived.mode === 'naruto' && derived.sessionScope ? 'app_naruto_stdin' : 'raw_json',
|
|
495
|
+
missionId: derived.plan.mission_id,
|
|
496
|
+
workflowRunId: derived.workflowRunId,
|
|
497
|
+
decisionContract: decided.compiled.kind === 'apply'
|
|
498
|
+
? {
|
|
499
|
+
planId: selectedPlan?.id ?? null,
|
|
500
|
+
keepContextIds: decided.selectedContextIds,
|
|
501
|
+
routingLane: selectedRouting
|
|
502
|
+
? Object.entries(selectedRouting.models).map(([name, model]) => `${name}=${model}`).join(', ')
|
|
503
|
+
: null,
|
|
504
|
+
executeSelectedIds: true
|
|
505
|
+
}
|
|
506
|
+
: null
|
|
507
|
+
});
|
|
508
|
+
const plan = {
|
|
509
|
+
...derived.plan,
|
|
510
|
+
delegation_prompt: delegationPrompt,
|
|
511
|
+
requested_subagents: budget.requestedSubagents,
|
|
512
|
+
first_wave: budget.firstWave,
|
|
513
|
+
wave_count: budget.waveCount,
|
|
514
|
+
wave_lifecycle: createSubagentWaveLifecycle({
|
|
515
|
+
workflowRunId: derived.workflowRunId,
|
|
516
|
+
targetSubagents: budget.requestedSubagents,
|
|
517
|
+
countPolicy: derived.requestedSource === 'automatic' ? 'dynamic_automatic' : 'exact',
|
|
518
|
+
waveCapacity: budget.firstWave
|
|
519
|
+
}),
|
|
520
|
+
triwiki_attention: attention,
|
|
521
|
+
agents,
|
|
522
|
+
fanout_policy: fanoutPolicy,
|
|
523
|
+
capacity_controller: budget.capacity,
|
|
524
|
+
jev_decision: decided.receipt,
|
|
525
|
+
native_host_dispatch: 'unverified'
|
|
526
|
+
};
|
|
527
|
+
return {
|
|
528
|
+
...derived,
|
|
529
|
+
budget,
|
|
530
|
+
fanoutPolicy,
|
|
531
|
+
triwikiAttention: attention,
|
|
532
|
+
plan,
|
|
533
|
+
preparedResultBase: {
|
|
534
|
+
...derived.preparedResultBase,
|
|
535
|
+
plan,
|
|
536
|
+
budget,
|
|
537
|
+
delegationPrompt,
|
|
538
|
+
triwikiAttention: attention,
|
|
539
|
+
fanoutPolicy
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
function rebuildBudget(derived, selectedPlan) {
|
|
544
|
+
const requested = selectedPlan.workerCount;
|
|
545
|
+
const waveGovernor = decideNarutoConcurrency({
|
|
546
|
+
requestedWorkers: Math.min(requested, derived.configuredMaxThreads),
|
|
547
|
+
totalWorkItems: requested,
|
|
548
|
+
backend: 'official-subagent',
|
|
549
|
+
parallelismMode: 'extreme',
|
|
550
|
+
maxThreads: derived.configuredMaxThreads,
|
|
551
|
+
...(derived.externalCodexHostCap === undefined ? {} : { externalCodexHostCap: derived.externalCodexHostCap })
|
|
552
|
+
});
|
|
553
|
+
return resolveSubagentThreadBudget({
|
|
554
|
+
requested,
|
|
555
|
+
configuredMaxThreads: derived.configuredMaxThreads,
|
|
556
|
+
...(derived.externalCodexHostCap === undefined ? {} : { externalCodexHostCap: derived.externalCodexHostCap }),
|
|
557
|
+
marginalUsefulWorkers: waveGovernor.safe_active_workers,
|
|
558
|
+
reviewerReservedThreads: String(derived.fanoutPolicy.selection_reason || '').includes('reviewer')
|
|
559
|
+
|| derived.fanoutPolicy.critical_multi_domain === true
|
|
560
|
+
? Math.max(1, Number(derived.fanoutPolicy.automatic_reviewer_ceiling || 1))
|
|
561
|
+
: 0,
|
|
562
|
+
...(derived.slices.length > 0
|
|
563
|
+
? {
|
|
564
|
+
independentSliceCount: derived.slices.length,
|
|
565
|
+
readyDagWidth: derived.slices.length,
|
|
566
|
+
disjointOwnershipCount: derived.sliceSafety.safe ? derived.slices.length : 0
|
|
567
|
+
}
|
|
568
|
+
: {})
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
async function promoteOfficialSubagentDerived(input, derived, expectedWorkflowRunId) {
|
|
572
|
+
const { plan, budget, verification, workflowRunId, officialConfig, triwikiAttention, suggestedAgents, fanoutPolicy, configBlockers, observedParentModel, parentModelMatch, taskProfile, delegationPrompt } = derived.preparedResultBase;
|
|
573
|
+
const statePatch = input.statePatch?.({ plan, budget, workflowRunId }) || null;
|
|
574
|
+
const preparedResultBase = derived.preparedResultBase;
|
|
339
575
|
const transactionFile = path.join(input.dir, OFFICIAL_SUBAGENT_PREPARATION_TRANSACTION);
|
|
340
576
|
const stageName = `${OFFICIAL_SUBAGENT_PREPARATION_STAGE_PREFIX}${safePreparationStageId(workflowRunId)}`;
|
|
341
577
|
const stageDir = path.join(input.dir, stageName);
|
|
342
|
-
const artifactInventory = officialSubagentPreparationArtifactInventory(mode);
|
|
343
|
-
const tombstoneInventory = officialSubagentPreparationTombstoneInventory(mode);
|
|
578
|
+
const artifactInventory = officialSubagentPreparationArtifactInventory(derived.mode);
|
|
579
|
+
const tombstoneInventory = officialSubagentPreparationTombstoneInventory(derived.mode);
|
|
344
580
|
let transaction = {
|
|
345
581
|
schema: 'sks.official-subagent-preparation-transaction.v2',
|
|
346
582
|
status: 'staging',
|
|
347
583
|
mission_id: input.missionId,
|
|
348
584
|
session_scope: input.sessionScope || null,
|
|
349
585
|
route: input.route,
|
|
350
|
-
mode,
|
|
351
|
-
goal,
|
|
586
|
+
mode: derived.mode,
|
|
587
|
+
goal: derived.goal,
|
|
352
588
|
previous_workflow_run_id: expectedWorkflowRunId || null,
|
|
353
589
|
target_workflow_run_id: workflowRunId,
|
|
354
590
|
stage_dir: stageName,
|
|
@@ -365,9 +601,9 @@ async function prepareOfficialSubagentMissionLocked(input) {
|
|
|
365
601
|
await fsp.rm(stageDir, { recursive: true, force: true });
|
|
366
602
|
await fsp.mkdir(stageDir, { recursive: true });
|
|
367
603
|
const evidence = await writeOfficialSubagentPreparationStage(stageDir, {
|
|
368
|
-
mode,
|
|
604
|
+
mode: derived.mode,
|
|
369
605
|
plan,
|
|
370
|
-
ssotGuard,
|
|
606
|
+
ssotGuard: derived.ssotGuard,
|
|
371
607
|
budget,
|
|
372
608
|
workflowRunId,
|
|
373
609
|
preparationOnly: input.preparationOnly !== false,
|
|
@@ -409,6 +645,11 @@ async function prepareOfficialSubagentMissionLocked(input) {
|
|
|
409
645
|
return {
|
|
410
646
|
...preparedResultBase,
|
|
411
647
|
evidence,
|
|
648
|
+
officialConfig,
|
|
649
|
+
triwikiAttention,
|
|
650
|
+
fanoutPolicy,
|
|
651
|
+
taskProfile,
|
|
652
|
+
delegationPrompt
|
|
412
653
|
};
|
|
413
654
|
}
|
|
414
655
|
async function recoverOfficialSubagentPreparationTransaction(input) {
|
|
@@ -23,6 +23,7 @@ export function buildOfficialSubagentPrompt(input) {
|
|
|
23
23
|
? `${requestedSubagents} (route-owned exact orchestration contract)`
|
|
24
24
|
: `${requestedSubagents} (dynamic automatic target; keep the final decomposed plan and evidence count exact)`;
|
|
25
25
|
const triwiki = renderBoundedTriwikiAttention(input.triwikiAttention);
|
|
26
|
+
const decisionContract = renderDecisionContract(input.decisionContract);
|
|
26
27
|
const resolvedSlices = input.slices.map((slice) => ({
|
|
27
28
|
slice,
|
|
28
29
|
agentName: slice.agent || selectOfficialSubagentRole({
|
|
@@ -48,7 +49,23 @@ export function buildOfficialSubagentPrompt(input) {
|
|
|
48
49
|
&& ['low', 'medium', 'high', 'xhigh', 'max', 'ultra'].includes(row.reasoning_effort)
|
|
49
50
|
&& officialSubagentOnDemandRoleCatalog([name]).some((role) => role.name === name))
|
|
50
51
|
.map(([name, row]) => [name, row.reasoning_effort]));
|
|
51
|
-
const
|
|
52
|
+
const narutoChildren = input.narutoChildRouting === true;
|
|
53
|
+
const spawnModelRouting = renderSpawnModelRouting(narutoChildren);
|
|
54
|
+
const childModelRules = narutoChildren
|
|
55
|
+
? [
|
|
56
|
+
'- use the model and reasoning_effort named in each slice spawn contract',
|
|
57
|
+
'- sealed child models are gpt-5.6-luna, gpt-5.6-sol, gpt-5.6-terra, and gpt-6-astra',
|
|
58
|
+
'- keep a stored user role-model preference for that role'
|
|
59
|
+
].join('\n')
|
|
60
|
+
: [
|
|
61
|
+
'- use `worker` with gpt-6-astra and low reasoning for tiny short-context mechanical work such as simple search, typing, rename, copy, label, or one-line edits with no exploration or judgment',
|
|
62
|
+
'- use gpt-6-astra with low reasoning for ordinary UI, logic, backend, and native implementation with established instructions',
|
|
63
|
+
'- use gpt-6-astra with max reasoning for planning, analysis, review, focused unresolved, high-risk, architecture, security, database, research, release, or other explicit judgment slices',
|
|
64
|
+
'- use gpt-6-astra with medium reasoning for long context/memory, large docs/repository reads or exploration, large-scale first-draft code processing, and direct Computer Use, Browser/Chrome, or image generation',
|
|
65
|
+
'- explicit task class and phase win over incidental keywords: Astra Medium explores, Astra Low executes mechanical and instructed coding tasks, and Astra Max judges',
|
|
66
|
+
'- in mass fan-out, use worker/Astra Low for tiny mechanical shards and explorer/Astra Medium for broad exploration; use Astra Low for instructed implementation and Astra Max for judgment',
|
|
67
|
+
'- keep context, exploration, review, debugging, planning, and direct tool operation on their assigned defaults; preserve each sealed role model and effort instead of applying the parent profile to every child'
|
|
68
|
+
].join('\n');
|
|
52
69
|
const parentOutputMode = input.parentOutputMode === 'app_naruto_stdin'
|
|
53
70
|
? 'app_naruto_stdin'
|
|
54
71
|
: 'raw_json';
|
|
@@ -56,9 +73,14 @@ export function buildOfficialSubagentPrompt(input) {
|
|
|
56
73
|
const mode = slice.readOnly ? 'read-only' : 'use the parent permission mode';
|
|
57
74
|
const paths = (slice.paths || []).map((entry) => String(entry).trim()).filter(Boolean);
|
|
58
75
|
const role = officialSubagentOnDemandRoleCatalog([agentName])[0];
|
|
59
|
-
const
|
|
76
|
+
const routed = input.routedAgents?.[agentName];
|
|
77
|
+
const sealedReasoning = routed?.routed_model_reasoning_effort
|
|
78
|
+
|| effortPreferences[agentName]
|
|
79
|
+
|| role?.model_reasoning_effort
|
|
80
|
+
|| 'medium';
|
|
81
|
+
const sealedModel = routed?.routed_model || role?.model;
|
|
60
82
|
const spawnContract = role
|
|
61
|
-
? `pass model=${JSON.stringify(
|
|
83
|
+
? `pass model=${JSON.stringify(sealedModel)} and reasoning_effort=${JSON.stringify(sealedReasoning)} from the sealed role policy`
|
|
62
84
|
: 'stop before spawning: resolve an installed sealed Astra role and its effort first';
|
|
63
85
|
return [
|
|
64
86
|
`${index + 1}. [${slice.id}] use custom agent \`${agentName}\``,
|
|
@@ -94,18 +116,12 @@ Subagent rules:
|
|
|
94
116
|
- use only Codex official subagent threads; do not launch shell workers, a custom scheduler, a worker pool, or model fanout
|
|
95
117
|
- select the narrowest matching project custom agent by its description; the custom agent name is the spawn type
|
|
96
118
|
- custom \`agent_type\` selection and spawn-time \`model\`/\`reasoning_effort\` overrides must use \`fork_turns="none"\` or a positive bounded turn count, with the complete bounded slice contract in \`message\`; context contract: pass fork_turns="none" for listed slices
|
|
97
|
-
- \`spawn_agent\` has no provider argument; every child uses the exact model slug gpt-6-astra
|
|
119
|
+
- \`spawn_agent\` has no provider argument; ${narutoChildren ? 'Naruto children use the sealed model named in the spawn contract (gpt-5.6-luna, gpt-5.6-sol, gpt-5.6-terra, or gpt-6-astra)' : 'every child uses the exact model slug gpt-6-astra'}
|
|
98
120
|
- never combine \`fork_turns="all"\` or the omitted/default full-history mode with \`agent_type\`, \`model\`, or \`reasoning_effort\`; Codex rejects that start before SubagentStart
|
|
99
121
|
- never use a full-history fork for SKS children
|
|
100
122
|
${spawnModelRouting}
|
|
101
123
|
${Object.keys(effortPreferences).length ? `- explicit Astra effort preferences override role defaults, including later slices: ${JSON.stringify(effortPreferences)}` : ''}
|
|
102
|
-
|
|
103
|
-
- use gpt-6-astra with low reasoning for ordinary UI, logic, backend, and native implementation with established instructions
|
|
104
|
-
- use gpt-6-astra with max reasoning for planning, analysis, review, focused unresolved, high-risk, architecture, security, database, research, release, or other explicit judgment slices
|
|
105
|
-
- use gpt-6-astra with medium reasoning for long context/memory, large docs/repository reads or exploration, large-scale first-draft code processing, and direct Computer Use, Browser/Chrome, or image generation
|
|
106
|
-
- explicit task class and phase win over incidental keywords: Astra Medium explores, Astra Low executes mechanical and instructed coding tasks, and Astra Max judges
|
|
107
|
-
- in mass fan-out, use worker/Astra Low for tiny mechanical shards and explorer/Astra Medium for broad exploration; use Astra Low for instructed implementation and Astra Max for judgment
|
|
108
|
-
- keep context, exploration, review, debugging, planning, and direct tool operation on their assigned defaults; preserve each sealed role model and effort instead of applying the parent profile to every child
|
|
124
|
+
${childModelRules}
|
|
109
125
|
|
|
110
126
|
Plan and capacity:
|
|
111
127
|
- automatic fan-out is capacity-derived up to ${MAX_AUTOMATIC_SUBAGENT_COUNT}: after decomposition, use every safe useful child slot supported by the ready DAG, disjoint ownership, verifier/tool capacity, and actual host limits; the historical 4/6/8/16 task-class values are fallback hints, not clamps
|
|
@@ -141,6 +157,7 @@ ${renderSliceSafety(sliceSafety, parentDecompositionRequired)}
|
|
|
141
157
|
|
|
142
158
|
Central TriWiki context:
|
|
143
159
|
${triwiki}
|
|
160
|
+
${decisionContract}
|
|
144
161
|
|
|
145
162
|
Project custom agent catalog:
|
|
146
163
|
${catalog}
|
|
@@ -209,7 +226,15 @@ function normalizedActiveMainModel(value) {
|
|
|
209
226
|
const model = String(value?.model || '').trim();
|
|
210
227
|
return provider && model ? { provider, model } : null;
|
|
211
228
|
}
|
|
212
|
-
function renderSpawnModelRouting() {
|
|
229
|
+
function renderSpawnModelRouting(narutoChildRouting) {
|
|
230
|
+
if (narutoChildRouting) {
|
|
231
|
+
return [
|
|
232
|
+
'- Naruto child models come from the spawn contract, including slices created after parent decomposition',
|
|
233
|
+
'- when Jev mode selected a role, that contract names gpt-5.6-luna at low, gpt-5.6-sol at low, gpt-5.6-terra at medium, or gpt-6-astra at max',
|
|
234
|
+
'- explicit user role-model preferences stay authoritative',
|
|
235
|
+
'- preserve the user-selected parent model, reasoning effort, and service tier'
|
|
236
|
+
].join('\n');
|
|
237
|
+
}
|
|
213
238
|
return [
|
|
214
239
|
'- model routing applies to every child, including slices created after parent decomposition: gpt-6-astra only, with the selected role effort',
|
|
215
240
|
'- use sealed Astra Low/Astra Medium/Astra Max role defaults across four task-class profiles; parent selection and saved non-Astra preferences never override the child model; explicit Astra effort preferences, including High, may override role defaults',
|
|
@@ -282,15 +307,33 @@ function renderBoundedTriwikiAttention(value) {
|
|
|
282
307
|
id: anchor.id,
|
|
283
308
|
claim_hash: anchor.claim_hash,
|
|
284
309
|
source_hash: anchor.source_hash,
|
|
285
|
-
hydrate_hint: anchor.hydrate_hint
|
|
310
|
+
hydrate_hint: anchor.hydrate_hint,
|
|
311
|
+
...(anchor.source_path ? { source_path: anchor.source_path } : {}),
|
|
312
|
+
...(anchor.excerpt ? { excerpt: anchor.excerpt } : {})
|
|
286
313
|
}));
|
|
314
|
+
const hasExcerpt = value.anchors.some((anchor) => Boolean(anchor.excerpt));
|
|
287
315
|
return [
|
|
288
316
|
`- consume these ${anchors.length} attention.use_first anchors before broad discovery`,
|
|
289
317
|
'- hydrate a referenced source only when its anchor is relevant to the assigned slice or a risky decision',
|
|
290
318
|
'- do not inject the full context pack or make each subagent repeat repository-wide context discovery',
|
|
319
|
+
...(hasExcerpt
|
|
320
|
+
? ['- keep exact source text and provenance; do not summarize selected excerpts with another model']
|
|
321
|
+
: []),
|
|
291
322
|
`- bounded anchors: ${JSON.stringify(anchors)}`
|
|
292
323
|
].join('\n');
|
|
293
324
|
}
|
|
325
|
+
function renderDecisionContract(value) {
|
|
326
|
+
if (!value || value.executeSelectedIds !== true)
|
|
327
|
+
return '';
|
|
328
|
+
return [
|
|
329
|
+
'Selected decision contract:',
|
|
330
|
+
`- execute the selected plan${value.planId ? ` ${value.planId}` : ''} and retained optional context IDs; do not choose them again`,
|
|
331
|
+
value.routingLane ? `- Jev sealed models: ${value.routingLane}` : '',
|
|
332
|
+
value.keepContextIds?.length
|
|
333
|
+
? `- retained optional context IDs: ${value.keepContextIds.join(', ')}`
|
|
334
|
+
: '- pinned and retained context already unioned by code'
|
|
335
|
+
].filter(Boolean).join('\n');
|
|
336
|
+
}
|
|
294
337
|
function renderAgentCatalog(requested) {
|
|
295
338
|
const names = [...new Set(requested.map(String).map((name) => name.trim()).filter(Boolean))];
|
|
296
339
|
const selected = officialSubagentOnDemandRoleCatalog(names.length ? names : ['expert']);
|