@event4u/agent-config 9.28.0 → 9.30.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/.claude-plugin/marketplace.json +1 -1
- package/AGENTS.md +6 -6
- package/CHANGELOG.md +172 -5
- package/README.md +2 -1
- package/agents/templates/.ai-council.yml.example +55 -24
- package/dist/agent-src/commands/analyze/inbox.md +22 -1
- package/dist/agent-src/commands/cost/report.md +2 -2
- package/dist/agent-src/commands/explain-run.md +31 -1
- package/dist/agent-src/commands/team/adversarial.md +8 -7
- package/dist/agent-src/commands/team/delegate.md +14 -12
- package/dist/agent-src/commands/team/review.md +9 -8
- package/dist/agent-src/commands/team/status.md +9 -8
- package/dist/agent-src/commands/team.md +29 -19
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +88 -2
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +29 -21
- package/dist/agent-src/contexts/execution/host-capability-manifest.md +26 -15
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +22 -1
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +17 -0
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +65 -1
- package/dist/agent-src/contexts/execution/subagent-routing.md +13 -11
- package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +25 -0
- package/dist/agent-src/contexts/execution/subagent-steering.md +6 -3
- package/dist/agent-src/rules/delegation-policy.md +11 -7
- package/dist/agent-src/rules/preservation-guard.md +9 -0
- package/dist/agent-src/rules/settings-ask-protocol.md +8 -7
- package/dist/agent-src/rules/token-budget-discipline.md +1 -1
- package/dist/agent-src/scripts/roadmap_gates.ts +312 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +72 -4
- package/dist/agent-src/skills/forensics-report/SKILL.md +114 -0
- package/dist/agent-src/skills/forensics-report/evals/triggers.json +17 -0
- package/dist/agent-src/skills/premortem/SKILL.md +30 -1
- package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +2 -1
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +17 -5
- package/dist/agent-src/skills/subagent-orchestration/schemas/subagent-status.json +61 -3
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +1 -1
- package/dist/agent-src/templates/AGENTS.md +4 -4
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +23 -0
- package/dist/cli/registry.js +2 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-22GCIJ2O.js → chunk-66OVWGB5.js} +1 -1
- package/dist/cli-delegate/{chunk-7OMQCH4V.js → chunk-BTJNRUX3.js} +22 -35
- package/dist/cli-delegate/{chunk-DVRS2KVR.js → chunk-DDUNNFYX.js} +24 -17
- package/dist/cli-delegate/{chunk-PQSAQKHW.js → chunk-EQY4FLJB.js} +3 -3
- package/dist/cli-delegate/{chunk-2BE5I2MN.js → chunk-IYTGIG2Y.js} +155 -91
- package/dist/cli-delegate/{chunk-GB2FSUEE.js → chunk-LCFJIQ4J.js} +32 -0
- package/dist/cli-delegate/{chunk-VSYT7OHO.js → chunk-LVRYBKTI.js} +31 -2
- package/dist/cli-delegate/chunk-MMJL4TIX.js +18 -0
- package/dist/cli-delegate/{chunk-JXARCGVN.js → chunk-MP3JT3IU.js} +1 -1
- package/dist/cli-delegate/chunk-O3CO5BFB.js +161 -0
- package/dist/cli-delegate/{chunk-REKCMYOU.js → chunk-PFBV6XRT.js} +36 -20
- package/dist/cli-delegate/chunk-RVGBH4XK.js +142 -0
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +2803 -137
- package/dist/cli-delegate/cmd_doctor.js +10 -5
- package/dist/cli-delegate/cmd_explain.js +2 -2
- package/dist/cli-delegate/cmd_export.js +4 -4
- package/dist/cli-delegate/cmd_handoff.js +88 -8
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +4 -4
- package/dist/cli-delegate/cmd_route_audit.js +3 -2
- package/dist/cli-delegate/cmd_route_explain.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +177 -0
- package/dist/cli-delegate/cmd_settings_get.js +2 -8
- package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
- package/dist/cli-delegate/cmd_settings_set.js +2 -2
- package/dist/cli-delegate/cmd_sync.js +4 -4
- package/dist/cli-delegate/cmd_uninstall.js +4 -4
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +1 -1
- package/dist/cli-delegate/cmd_validate.js +4 -4
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +72 -23
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -2
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +39 -2
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +12 -4
- package/dist/hooks/dispatch.js +2278 -611
- package/dist/install/install.mjs +56 -17
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +4122 -699
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +54 -0
- package/dist/scripts/_lib/agent_settings.js.map +1 -1
- package/dist/scripts/condense.js +147 -2
- package/dist/scripts/condense.js.map +1 -1
- package/dist/server/schemas/settings.js +12 -7
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/shared/settingsCarveOut.js +0 -9
- package/dist/shared/settingsCarveOut.js.map +1 -1
- package/dist/shared/settingsClasses.js +11 -9
- package/dist/shared/settingsClasses.js.map +1 -1
- package/dist/ui/assets/index-B5qGYOJo.js +26 -0
- package/dist/ui/assets/index-B5qGYOJo.js.map +1 -0
- package/dist/ui/index.html +1 -1
- package/docs/contracts/settings-classes.md +58 -12
- package/package.json +1 -1
- package/src/agent-src/scripts/roadmap_gates.ts +312 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +72 -4
- package/src/agent-src/templates/AGENTS.md +4 -4
- package/src/config/agent-settings.template.yml +88 -66
- package/src/config/discovery/packs.yml +11 -0
- package/src/config/discovery/workspaces.yml +1 -1
- package/src/config/dispatch-economy-metrics.json +61 -0
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-violation-baselines.json +3 -3
- package/src/config/hook-token-budget.json +91 -0
- package/src/config/recycle-threshold-budget.json +12 -0
- package/src/config/rule-enforcement-baseline.json +86 -0
- package/src/scripts/_cli/cmd_conformance.ts +31 -44
- package/src/scripts/_cli/cmd_doctor.ts +65 -48
- package/src/scripts/_cli/cmd_session_recycle.ts +226 -0
- package/src/scripts/_dispatch.bash +23 -0
- package/src/scripts/_lib/agent_settings.ts +58 -0
- package/src/scripts/_lib/auto_dispatch.corpus.test.ts +1 -1
- package/src/scripts/_lib/auto_dispatch.ts +23 -18
- package/src/scripts/_lib/capsule_trigger.ts +124 -0
- package/src/scripts/_lib/host_capability.ts +63 -6
- package/src/scripts/_lib/judgment_ladder.ts +634 -0
- package/src/scripts/_lib/orchestration_gate.ts +8 -0
- package/src/scripts/_lib/orchestration_record.ts +78 -10
- package/src/scripts/_lib/orchestration_savings.ts +1 -1
- package/src/scripts/_lib/recycle_envelope_paths.ts +35 -0
- package/src/scripts/_lib/self_repair.ts +354 -13
- package/src/scripts/_lib/self_repair_store.ts +28 -0
- package/src/scripts/_lib/session_eol.ts +230 -0
- package/src/scripts/_lib/session_role.ts +42 -0
- package/src/scripts/_lib/subagent_capsule.ts +341 -0
- package/src/scripts/_lib/subagent_response.ts +94 -0
- package/src/scripts/_lib/subagent_spawn.ts +13 -0
- package/src/scripts/_lib/subagent_steering.ts +9 -4
- package/src/scripts/_lib/tier_budget_routing.ts +6 -1
- package/src/scripts/_lib/worker_budget.ts +37 -2
- package/src/scripts/ai_council/clients.ts +126 -55
- package/src/scripts/ai_council/config.ts +94 -6
- package/src/scripts/ai_council/handoff.ts +113 -0
- package/src/scripts/ai_council/modes.ts +19 -4
- package/src/scripts/ai_council/orchestrator.ts +105 -0
- package/src/scripts/ai_council/quorum.ts +84 -0
- package/src/scripts/ai_council/session.ts +44 -0
- package/src/scripts/ai_council/transport_resolver.ts +127 -1
- package/src/scripts/ai_team/availability.ts +110 -0
- package/src/scripts/ai_team/config.ts +34 -14
- package/src/scripts/ai_team/team_dispatch.ts +71 -29
- package/src/scripts/ask_transport.ts +221 -0
- package/src/scripts/bench_critic_protocol.ts +396 -0
- package/src/scripts/bench_hook_injection.ts +234 -0
- package/src/scripts/check_adr_frontmatter.ts +84 -40
- package/src/scripts/check_branch_freshness.ts +1 -0
- package/src/scripts/check_corpus_staleness.ts +18 -4
- package/src/scripts/check_detector_corpus.ts +219 -0
- package/src/scripts/check_gitignore_freshness.ts +42 -8
- package/src/scripts/check_hook_bundle_freshness.ts +24 -1
- package/src/scripts/check_kernel_prefix_stability.ts +1 -0
- package/src/scripts/check_standing_rule_delivery.ts +73 -32
- package/src/scripts/check_static_layer_stability.ts +154 -0
- package/src/scripts/check_suppression_hygiene.ts +48 -0
- package/src/scripts/condense.ts +162 -2
- package/src/scripts/council_cli.ts +401 -25
- package/src/scripts/dispatch_economy_report.ts +448 -0
- package/src/scripts/dispatch_r2_reviewer.ts +15 -2
- package/src/scripts/explain_run.ts +206 -4
- package/src/scripts/forensics_report.ts +333 -0
- package/src/scripts/generate_settings_reference.ts +1 -0
- package/src/scripts/handoff_context_hook.ts +112 -4
- package/src/scripts/hook_manifest.yaml +117 -10
- package/src/scripts/hooks/concern_registry.ts +8 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +106 -35
- package/src/scripts/hooks/dispatch_hook.ts +39 -2
- package/src/scripts/hooks/edit_shape_hook.ts +303 -0
- package/src/scripts/hooks/orchestration_record_hook.ts +19 -1
- package/src/scripts/hooks/reread_guard_hook.ts +314 -0
- package/src/scripts/hooks/rtk_wrap_hook.ts +133 -14
- package/src/scripts/hooks/session_eol_hook.ts +268 -0
- package/src/scripts/hooks/turn_end_gate_hook.ts +507 -0
- package/src/scripts/install-hooks.sh +1 -1
- package/src/scripts/language_mirror_hook.ts +89 -0
- package/src/scripts/lint_decision_impact.ts +14 -1
- package/src/scripts/lint_discovery_vocabulary.ts +2 -0
- package/src/scripts/lint_hook_manifest.ts +82 -0
- package/src/scripts/lint_never_silent.ts +276 -0
- package/src/scripts/lint_no_activation_gates.ts +271 -0
- package/src/scripts/lint_readme_serial_comma.ts +1 -0
- package/src/scripts/lint_rule_enforcement_declaration.ts +347 -0
- package/src/scripts/measure_turn_end_gate.ts +194 -0
- package/src/scripts/orchestration_record.ts +12 -1
- package/src/scripts/rebuild_hook_bundle.ts +178 -0
- package/src/scripts/release.ts +74 -2
- package/src/scripts/report_conformance_funnel.ts +284 -0
- package/src/scripts/report_imperative_density.ts +1 -0
- package/src/scripts/routing_doctor.ts +118 -36
- package/src/scripts/score_skill_selection.ts +19 -5
- package/src/scripts/self_repair_cli.ts +337 -59
- package/src/scripts/session_eol_report.ts +261 -0
- package/src/scripts/team_events_spike.ts +271 -0
- package/src/scripts/team_review_gate_hook.ts +31 -9
- package/src/server/schemas/settings.ts +24 -17
- package/src/shared/settingsCarveOut.ts +0 -10
- package/src/shared/settingsClasses.ts +11 -9
- package/src/templates/compact-instructions.md +40 -0
- package/dist/ui/assets/index-DmR0mbk4.js +0 -26
- package/dist/ui/assets/index-DmR0mbk4.js.map +0 -1
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* Contract: `src/agent-src/contexts/execution/subagent-response-contract.md`.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { validateAssumption, type CapsuleAssumption } from './subagent_capsule.js';
|
|
13
|
+
|
|
12
14
|
export type Confidence = 'low' | 'medium' | 'high';
|
|
13
15
|
|
|
14
16
|
export interface Finding {
|
|
@@ -19,12 +21,46 @@ export interface Finding {
|
|
|
19
21
|
mutating?: boolean;
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
// ── Committed envelope size caps (road-to-token-economy-dispatch Phase 6.1) ──
|
|
25
|
+
// The envelope is the ONLY return channel: a worker's full result lands on
|
|
26
|
+
// disk (runtime artifact dir, gitignored) and the envelope carries paths +
|
|
27
|
+
// verdict + a BOUNDED summary. Without caps, transcript-shaped output flows
|
|
28
|
+
// back into the orchestrator context and refunds the isolation win — the
|
|
29
|
+
// measured spawn floor is ~251k tokens; a capped envelope is ≤ ~3k. Caps are
|
|
30
|
+
// validator ERRORS, never silent truncation (never-silent discipline): an
|
|
31
|
+
// oversized envelope is rejected loudly and the author shortens it.
|
|
32
|
+
/** Max chars for the summary — bounded prose, not a transcript. */
|
|
33
|
+
export const MAX_SUMMARY_CHARS = 2000;
|
|
34
|
+
/** Max chars for one line-shaped field (handoff, a risk, a finding title). */
|
|
35
|
+
export const MAX_RESPONSE_LINE_CHARS = 240;
|
|
36
|
+
/** Max entries per array (findings, risks, artifact_paths) — mirrors the capsule. */
|
|
37
|
+
export const MAX_RESPONSE_ENTRIES = 40;
|
|
38
|
+
/** Max chars for one artifact path ref. Mirrors the capsule's ref cap. */
|
|
39
|
+
export const MAX_ARTIFACT_REF_CHARS = 200;
|
|
40
|
+
/** Committed max for the WHOLE serialized envelope (~3k tokens ceiling). */
|
|
41
|
+
export const MAX_ENVELOPE_CHARS = 12000;
|
|
42
|
+
|
|
22
43
|
export interface SubagentResponse {
|
|
23
44
|
summary: string;
|
|
24
45
|
findings: Finding[];
|
|
25
46
|
risks: string[];
|
|
26
47
|
confidence: Confidence;
|
|
27
48
|
handoff: string;
|
|
49
|
+
/**
|
|
50
|
+
* Where the worker's FULL results live on disk (runtime artifact dir,
|
|
51
|
+
* gitignored) — the orchestrator consumes from these paths on demand,
|
|
52
|
+
* never via wholesale transcript ingestion (Phase 6.1/6.2). Ref tokens
|
|
53
|
+
* only, capped like every other array.
|
|
54
|
+
*/
|
|
55
|
+
artifact_paths?: string[];
|
|
56
|
+
/**
|
|
57
|
+
* Premises the worker acted on, `{statement, basis, epistemic_state}` —
|
|
58
|
+
* the same shape and the same validator as the CHECKPOINT capsule
|
|
59
|
+
* (`subagent_capsule.ts`), so the completed-result and handoff surfaces
|
|
60
|
+
* cannot drift apart. Optional: absent means not recorded, which is not
|
|
61
|
+
* the same claim as "no assumptions were made".
|
|
62
|
+
*/
|
|
63
|
+
assumptions?: CapsuleAssumption[];
|
|
28
64
|
}
|
|
29
65
|
|
|
30
66
|
const CONFIDENCE: ReadonlySet<string> = new Set<Confidence>(['low', 'medium', 'high']);
|
|
@@ -55,6 +91,64 @@ export function validateResponse(input: unknown): ValidationResult {
|
|
|
55
91
|
}
|
|
56
92
|
}
|
|
57
93
|
}
|
|
94
|
+
if (r.assumptions !== undefined) {
|
|
95
|
+
if (!Array.isArray(r.assumptions)) {
|
|
96
|
+
errors.push('assumptions must be an array of {statement, basis, epistemic_state}');
|
|
97
|
+
} else {
|
|
98
|
+
for (const [i, a] of (r.assumptions as unknown[]).entries()) {
|
|
99
|
+
errors.push(...validateAssumption(a, `assumptions[${i}]`));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// ── Committed size caps (Phase 6.1) — errors, never silent truncation ──
|
|
104
|
+
if (typeof r.summary === 'string' && r.summary.length > MAX_SUMMARY_CHARS) {
|
|
105
|
+
errors.push(`summary is ${r.summary.length} chars (max ${MAX_SUMMARY_CHARS}) — the envelope carries a bounded summary; the full result belongs on disk (artifact_paths)`);
|
|
106
|
+
}
|
|
107
|
+
if (typeof r.handoff === 'string' && r.handoff.length > MAX_RESPONSE_LINE_CHARS) {
|
|
108
|
+
errors.push(`handoff is ${r.handoff.length} chars (max ${MAX_RESPONSE_LINE_CHARS})`);
|
|
109
|
+
}
|
|
110
|
+
for (const [key, arr] of [
|
|
111
|
+
['findings', r.findings],
|
|
112
|
+
['risks', r.risks],
|
|
113
|
+
['artifact_paths', r.artifact_paths],
|
|
114
|
+
] as const) {
|
|
115
|
+
if (Array.isArray(arr) && arr.length > MAX_RESPONSE_ENTRIES) {
|
|
116
|
+
errors.push(`${key} carries ${arr.length} entries (max ${MAX_RESPONSE_ENTRIES}) — an envelope is a handoff, not a transcript`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (Array.isArray(r.risks)) {
|
|
120
|
+
for (const [i, risk] of (r.risks as unknown[]).entries()) {
|
|
121
|
+
if (typeof risk === 'string' && risk.length > MAX_RESPONSE_LINE_CHARS) {
|
|
122
|
+
errors.push(`risks[${i}] is ${risk.length} chars (max ${MAX_RESPONSE_LINE_CHARS})`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (Array.isArray(r.findings)) {
|
|
127
|
+
for (const [i, f] of (r.findings as Finding[]).entries()) {
|
|
128
|
+
if (f && typeof f.title === 'string' && f.title.length > MAX_RESPONSE_LINE_CHARS) {
|
|
129
|
+
errors.push(`finding[${i}] title is ${f.title.length} chars (max ${MAX_RESPONSE_LINE_CHARS})`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (r.artifact_paths !== undefined) {
|
|
134
|
+
if (!Array.isArray(r.artifact_paths)) {
|
|
135
|
+
errors.push('artifact_paths must be an array of path ref tokens');
|
|
136
|
+
} else {
|
|
137
|
+
for (const [i, p] of (r.artifact_paths as unknown[]).entries()) {
|
|
138
|
+
if (typeof p !== 'string' || p.includes('\n') || p.length > MAX_ARTIFACT_REF_CHARS) {
|
|
139
|
+
errors.push(`artifact_paths[${i}] must be a single-line path ref ≤ ${MAX_ARTIFACT_REF_CHARS} chars`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const serialized = JSON.stringify(input);
|
|
146
|
+
if (serialized.length > MAX_ENVELOPE_CHARS) {
|
|
147
|
+
errors.push(`envelope serializes to ${serialized.length} chars (max ${MAX_ENVELOPE_CHARS}) — move content to disk and reference it via artifact_paths`);
|
|
148
|
+
}
|
|
149
|
+
} catch {
|
|
150
|
+
errors.push('envelope is not JSON-serializable');
|
|
151
|
+
}
|
|
58
152
|
return { valid: errors.length === 0, errors };
|
|
59
153
|
}
|
|
60
154
|
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
import * as crypto from 'node:crypto';
|
|
15
15
|
|
|
16
|
+
import { CAPSULE_WATERMARK_FRACTION } from './worker_budget.js';
|
|
17
|
+
|
|
16
18
|
export type RoleMode = 'developer' | 'reviewer' | 'tester' | 'po' | 'incident' | 'planner';
|
|
17
19
|
|
|
18
20
|
const ROLE_MODES: ReadonlySet<string> = new Set<RoleMode>([
|
|
@@ -55,6 +57,12 @@ export interface SpawnBrief {
|
|
|
55
57
|
knowledge_refs: string[];
|
|
56
58
|
/** Per-worker token stop-loss; null = unset (legacy dispatch). */
|
|
57
59
|
max_tokens_per_worker: number | null;
|
|
60
|
+
/**
|
|
61
|
+
* Token count at which the worker emits a CHECKPOINT capsule — DERIVED from
|
|
62
|
+
* `max_tokens_per_worker`, never set independently, so the watermark cannot
|
|
63
|
+
* drift away from the budget it sits under. Null when no budget is set.
|
|
64
|
+
*/
|
|
65
|
+
capsule_watermark: number | null;
|
|
58
66
|
warnings: string[];
|
|
59
67
|
}
|
|
60
68
|
|
|
@@ -112,6 +120,10 @@ export function composeSpawnBrief(sel: SpawnSelection): SpawnBrief {
|
|
|
112
120
|
personas,
|
|
113
121
|
knowledge_refs,
|
|
114
122
|
max_tokens_per_worker,
|
|
123
|
+
capsule_watermark:
|
|
124
|
+
max_tokens_per_worker === null
|
|
125
|
+
? null
|
|
126
|
+
: Math.floor(max_tokens_per_worker * CAPSULE_WATERMARK_FRACTION),
|
|
115
127
|
warnings,
|
|
116
128
|
};
|
|
117
129
|
}
|
|
@@ -133,6 +145,7 @@ export function serializeSpawnPayload(brief: SpawnBrief): string {
|
|
|
133
145
|
profile: brief.profile,
|
|
134
146
|
personas: brief.personas,
|
|
135
147
|
max_tokens_per_worker: brief.max_tokens_per_worker,
|
|
148
|
+
capsule_watermark: brief.capsule_watermark,
|
|
136
149
|
});
|
|
137
150
|
const variableTail = JSON.stringify({
|
|
138
151
|
task: brief.task,
|
|
@@ -26,14 +26,19 @@ export const GUARDRAILS = {
|
|
|
26
26
|
user_override_rate: 0.3,
|
|
27
27
|
} as const;
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Always-on orchestration (road-to-always-on-orchestration Phase 1) removed
|
|
31
|
+
* the `enabled`/`auto` settings this state used to carry — the only
|
|
32
|
+
* surviving switch is the audited incident halt.
|
|
33
|
+
*/
|
|
29
34
|
export interface LayerState {
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
/** `emergency.orchestration_halt`. */
|
|
36
|
+
halted: boolean;
|
|
32
37
|
}
|
|
33
38
|
|
|
34
|
-
/** The kill-switch: layer is disabled
|
|
39
|
+
/** The kill-switch: layer is disabled only during an active emergency halt. */
|
|
35
40
|
export function isLayerDisabled(state: LayerState): boolean {
|
|
36
|
-
return
|
|
41
|
+
return state.halted;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
/** N=3 per-target budget: halt once consecutive failed attempts reach the cap. */
|
|
@@ -43,7 +43,12 @@ export interface PickTierInputs {
|
|
|
43
43
|
adequate_tier: BudgetTier;
|
|
44
44
|
/** Per-tier budget state, complete over TIER_ORDER. */
|
|
45
45
|
budgets: Record<BudgetTier, TierBudgetState>;
|
|
46
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Caller-supplied switch. Formerly sourced from the `subagents.budget_routing`
|
|
48
|
+
* settings key, deleted by always-on orchestration (Phase 1) — this
|
|
49
|
+
* function has no production caller today, so the field stays as the
|
|
50
|
+
* DESIGNED input shape; a future wiring supplies its own source.
|
|
51
|
+
*/
|
|
47
52
|
routing_switch: BudgetRoutingSwitch;
|
|
48
53
|
/** Estimated cost of the dispatch (USD) for the availability check. */
|
|
49
54
|
estimated_cost_usd: number;
|
|
@@ -35,6 +35,24 @@ export function budgetForTier(tier: Tier, sessionTier: Exclude<Tier, 'inherit'>
|
|
|
35
35
|
return MAX_TOKENS_PER_WORKER[effective];
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Fraction of the stop-loss budget at which a worker emits its CHECKPOINT
|
|
40
|
+
* capsule (road-to-worker-generation-recycling, Phase 1).
|
|
41
|
+
*
|
|
42
|
+
* The headroom IS the mechanism: a worker at 100 % of its budget cannot
|
|
43
|
+
* summarise itself, so the watermark sits below the kill line rather than on
|
|
44
|
+
* it. A start value, not a tuned one — Phase 1 measures it in shadow against a
|
|
45
|
+
* second trigger arm before anything acts on it, and `blocker:
|
|
46
|
+
* capsule-quality-near-budget` exists because a bad watermark and a bad
|
|
47
|
+
* mechanism look identical from one sample.
|
|
48
|
+
*/
|
|
49
|
+
export const CAPSULE_WATERMARK_FRACTION = 0.8;
|
|
50
|
+
|
|
51
|
+
/** Token count at which a worker of this tier emits its capsule. */
|
|
52
|
+
export function watermarkForTier(tier: Tier, sessionTier: Exclude<Tier, 'inherit'> = 'high'): number {
|
|
53
|
+
return Math.floor(budgetForTier(tier, sessionTier) * CAPSULE_WATERMARK_FRACTION);
|
|
54
|
+
}
|
|
55
|
+
|
|
38
56
|
/** Where the orchestrator should send the task after a budget hit. */
|
|
39
57
|
export type NextRung = 'primitive' | 'higher-tier-subagent' | 'in-session';
|
|
40
58
|
|
|
@@ -64,19 +82,36 @@ export interface BudgetEvaluation {
|
|
|
64
82
|
budget_hit: boolean;
|
|
65
83
|
consumed: number;
|
|
66
84
|
budget: number;
|
|
85
|
+
/** Token count at which the CHECKPOINT capsule is due (below the kill line). */
|
|
86
|
+
watermark: number;
|
|
87
|
+
/** Consumption reached the watermark but not yet the stop-loss. */
|
|
88
|
+
watermark_hit: boolean;
|
|
67
89
|
reason: string;
|
|
68
90
|
}
|
|
69
91
|
|
|
70
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* Evaluate consumption against the worker's budget.
|
|
94
|
+
*
|
|
95
|
+
* Two lines, not one: the **watermark** (emit a capsule, still working) and the
|
|
96
|
+
* **stop-loss** (return a partial result, stop). A budget hit implies the
|
|
97
|
+
* watermark was passed, so `watermark_hit` marks the band BETWEEN them — the
|
|
98
|
+
* only window in which a capsule can still be written.
|
|
99
|
+
*/
|
|
71
100
|
export function evaluateWorkerBudget(consumed: number, budget: number): BudgetEvaluation {
|
|
72
101
|
const hit = consumed >= budget;
|
|
102
|
+
const watermark = Math.floor(budget * CAPSULE_WATERMARK_FRACTION);
|
|
103
|
+
const watermarkHit = !hit && consumed >= watermark;
|
|
73
104
|
return {
|
|
74
105
|
budget_hit: hit,
|
|
75
106
|
consumed,
|
|
76
107
|
budget,
|
|
108
|
+
watermark,
|
|
109
|
+
watermark_hit: watermarkHit,
|
|
77
110
|
reason: hit
|
|
78
111
|
? `budget hit (${consumed} >= ${budget}) — return partial result + escalation flag, stop exploring`
|
|
79
|
-
:
|
|
112
|
+
: watermarkHit
|
|
113
|
+
? `watermark reached (${consumed} >= ${watermark}) — emit a CHECKPOINT capsule while there is headroom to write one`
|
|
114
|
+
: `within budget (${consumed} < ${budget})`,
|
|
80
115
|
};
|
|
81
116
|
}
|
|
82
117
|
|
|
@@ -45,6 +45,37 @@ import * as fs from 'node:fs';
|
|
|
45
45
|
import * as path from 'node:path';
|
|
46
46
|
|
|
47
47
|
import { hardenedSpawnEnv } from '../_lib/spawn_env.js';
|
|
48
|
+
import { SESSION_ROLE_ENV } from '../_lib/session_role.js';
|
|
49
|
+
import { load_agent_settings } from '../_lib/agent_settings.js';
|
|
50
|
+
|
|
51
|
+
// Session-wide subagent model ceiling (token-economy-dispatch Phase 5.2):
|
|
52
|
+
// class-C setting, default absent, HUMAN-set only. When present, the CLI
|
|
53
|
+
// spawn below exports CLAUDE_CODE_SUBAGENT_MODEL so the spawned vendor
|
|
54
|
+
// session caps its own subagents' models. Memoised PER CWD, not per
|
|
55
|
+
// process (review finding 2026-08-10): a long-lived server process may
|
|
56
|
+
// serve several projects, and a single-slot memo would apply project A's
|
|
57
|
+
// spend cap to project B's spawns. A human edit still needs a process
|
|
58
|
+
// restart to be seen — acceptable for a per-install cap, stated here.
|
|
59
|
+
const _modelCeilingMemo = new Map<string, string | null>();
|
|
60
|
+
export function _subagentModelCeiling(cwd: string = process.cwd()): string | null {
|
|
61
|
+
const hit = _modelCeilingMemo.get(cwd);
|
|
62
|
+
if (hit !== undefined) return hit;
|
|
63
|
+
let ceiling: string | null;
|
|
64
|
+
try {
|
|
65
|
+
const settings = load_agent_settings({ cwd }) as Record<string, unknown>;
|
|
66
|
+
const sub = (settings['subagents'] ?? {}) as Record<string, unknown>;
|
|
67
|
+
const v = typeof sub['model_ceiling'] === 'string' ? sub['model_ceiling'].trim() : '';
|
|
68
|
+
ceiling = v.length > 0 ? v : null;
|
|
69
|
+
} catch {
|
|
70
|
+
ceiling = null; // unreadable settings → no ceiling (fail-open)
|
|
71
|
+
}
|
|
72
|
+
_modelCeilingMemo.set(cwd, ceiling);
|
|
73
|
+
return ceiling;
|
|
74
|
+
}
|
|
75
|
+
/** Test seam: reset the per-cwd ceiling memo. */
|
|
76
|
+
export function _resetModelCeilingMemo(): void {
|
|
77
|
+
_modelCeilingMemo.clear();
|
|
78
|
+
}
|
|
48
79
|
import * as user_global_paths from '../_lib/user_global_paths.js';
|
|
49
80
|
import { appendEvent } from './events_log.js';
|
|
50
81
|
|
|
@@ -1052,9 +1083,12 @@ export class SubprocessError extends Error {
|
|
|
1052
1083
|
* `~/.event4u/agent-config/cli-calls.json` and resets on UTC date rollover.
|
|
1053
1084
|
*
|
|
1054
1085
|
* Subclass contract:
|
|
1055
|
-
* - `name
|
|
1056
|
-
*
|
|
1057
|
-
* `binary:` field is not set.
|
|
1086
|
+
* - `super(opts, { name, default_binary })`: `name` is the provider key
|
|
1087
|
+
* (`anthropic`, `openai`, `gemini`, …); `default_binary` is the executable
|
|
1088
|
+
* resolved via PATH when the member-level `binary:` field is not set. Both
|
|
1089
|
+
* are passed explicitly to `super()` — not read off subclass instance
|
|
1090
|
+
* fields — because a subclass's own field initializers run only AFTER this
|
|
1091
|
+
* `super()` call returns.
|
|
1058
1092
|
* - `_build_command(system_prompt, user_prompt, max_tokens)`: return the argv.
|
|
1059
1093
|
* - `_parse_output(stdout, stderr)`: return a partial `CouncilResponse`.
|
|
1060
1094
|
*
|
|
@@ -1097,8 +1131,22 @@ export abstract class CliClient extends ExternalAIClient {
|
|
|
1097
1131
|
'usage limit',
|
|
1098
1132
|
];
|
|
1099
1133
|
|
|
1100
|
-
|
|
1134
|
+
/**
|
|
1135
|
+
* `identity` carries the subclass constants (`name`, `default_binary`)
|
|
1136
|
+
* that construction validates against. They are passed explicitly rather
|
|
1137
|
+
* than read off `this.name` / `this.default_binary` because subclass
|
|
1138
|
+
* instance-field initializers (`override default_binary = 'claude'`,
|
|
1139
|
+
* declared in the subclass body) run only AFTER this `super()` call
|
|
1140
|
+
* returns — reading them here, before that happens, would always see the
|
|
1141
|
+
* base class's own field defaults (`''`), not the subclass override.
|
|
1142
|
+
*/
|
|
1143
|
+
constructor(
|
|
1144
|
+
opts: CliClientOptions & { model: string },
|
|
1145
|
+
identity: { name: string; default_binary: string },
|
|
1146
|
+
) {
|
|
1101
1147
|
super();
|
|
1148
|
+
this.name = identity.name;
|
|
1149
|
+
this.default_binary = identity.default_binary;
|
|
1102
1150
|
this.model = opts.model;
|
|
1103
1151
|
this.timeout_seconds = opts.timeout_seconds ?? DEFAULT_CLI_TIMEOUT_SECONDS;
|
|
1104
1152
|
this.max_calls_per_day = opts.max_calls_per_day ?? null;
|
|
@@ -1162,7 +1210,25 @@ export abstract class CliClient extends ExternalAIClient {
|
|
|
1162
1210
|
// (loader preload, git *_COMMAND, NODE_OPTIONS, …) so an
|
|
1163
1211
|
// attacker-influenced parent env cannot RCE via the spawned CLI
|
|
1164
1212
|
// or a `git` it invokes internally.
|
|
1165
|
-
|
|
1213
|
+
// Role marking (token-economy-dispatch Phase 2.2): a council
|
|
1214
|
+
// member CLI session is worker-class — it never talks to OUR
|
|
1215
|
+
// user, never dispatches sub-workers, never runs a council.
|
|
1216
|
+
// The spawned vendor CLI loads this repo's hook chains; the
|
|
1217
|
+
// marker lets the dispatcher run the thinner worker chain
|
|
1218
|
+
// (manifest `roles.worker.drop`; pre_tool_use guards are
|
|
1219
|
+
// structurally exempt). This is the ONE in-tree spawn point
|
|
1220
|
+
// that launches a separate CLI session today — Agent-tool
|
|
1221
|
+
// subagents share the host process env and cannot be marked
|
|
1222
|
+
// (probed live 2026-08-10; see _lib/session_role.ts).
|
|
1223
|
+
// The optional model ceiling (subagents.model_ceiling, class C)
|
|
1224
|
+
// rides the same spawn: a spend cap the human set per install.
|
|
1225
|
+
env: hardenedSpawnEnv({
|
|
1226
|
+
[SESSION_ROLE_ENV]: 'worker',
|
|
1227
|
+
...((): Record<string, string> => {
|
|
1228
|
+
const ceiling = _subagentModelCeiling();
|
|
1229
|
+
return ceiling !== null ? { CLAUDE_CODE_SUBAGENT_MODEL: ceiling } : {};
|
|
1230
|
+
})(),
|
|
1231
|
+
}),
|
|
1166
1232
|
};
|
|
1167
1233
|
if (stdinPayload !== null) {
|
|
1168
1234
|
spawnOpts.input = stdinPayload;
|
|
@@ -1353,19 +1419,20 @@ export abstract class CliClient extends ExternalAIClient {
|
|
|
1353
1419
|
* collides with argv length limits.
|
|
1354
1420
|
*/
|
|
1355
1421
|
export class AnthropicCliClient extends CliClient {
|
|
1356
|
-
override name = 'anthropic';
|
|
1357
|
-
override default_binary = 'claude';
|
|
1358
1422
|
override subscription_label = 'claude-pro';
|
|
1359
1423
|
|
|
1360
1424
|
constructor(opts: CliClientOptions = {}) {
|
|
1361
|
-
super(
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1425
|
+
super(
|
|
1426
|
+
{
|
|
1427
|
+
model: opts.model ?? DEFAULT_ANTHROPIC_CLI_MODEL,
|
|
1428
|
+
binary: opts.binary,
|
|
1429
|
+
timeout_seconds: opts.timeout_seconds,
|
|
1430
|
+
max_calls_per_day: opts.max_calls_per_day,
|
|
1431
|
+
warn_at: opts.warn_at,
|
|
1432
|
+
cli_calls_path: opts.cli_calls_path,
|
|
1433
|
+
},
|
|
1434
|
+
{ name: 'anthropic', default_binary: 'claude' },
|
|
1435
|
+
);
|
|
1369
1436
|
}
|
|
1370
1437
|
|
|
1371
1438
|
protected override _build_command(
|
|
@@ -1446,8 +1513,6 @@ export class AnthropicCliClient extends CliClient {
|
|
|
1446
1513
|
* token usage in `usage.input_tokens` / `usage.output_tokens`.
|
|
1447
1514
|
*/
|
|
1448
1515
|
export class OpenAICliClient extends CliClient {
|
|
1449
|
-
override name = 'openai';
|
|
1450
|
-
override default_binary = 'codex';
|
|
1451
1516
|
override subscription_label = 'chatgpt-plus';
|
|
1452
1517
|
|
|
1453
1518
|
static override _AUTH_FAILURE_PATTERNS: readonly string[] = [
|
|
@@ -1458,14 +1523,17 @@ export class OpenAICliClient extends CliClient {
|
|
|
1458
1523
|
];
|
|
1459
1524
|
|
|
1460
1525
|
constructor(opts: CliClientOptions = {}) {
|
|
1461
|
-
super(
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1526
|
+
super(
|
|
1527
|
+
{
|
|
1528
|
+
model: opts.model ?? DEFAULT_OPENAI_CLI_MODEL,
|
|
1529
|
+
binary: opts.binary,
|
|
1530
|
+
timeout_seconds: opts.timeout_seconds,
|
|
1531
|
+
max_calls_per_day: opts.max_calls_per_day,
|
|
1532
|
+
warn_at: opts.warn_at,
|
|
1533
|
+
cli_calls_path: opts.cli_calls_path,
|
|
1534
|
+
},
|
|
1535
|
+
{ name: 'openai', default_binary: 'codex' },
|
|
1536
|
+
);
|
|
1469
1537
|
}
|
|
1470
1538
|
|
|
1471
1539
|
protected override _build_command(
|
|
@@ -1569,8 +1637,6 @@ export class OpenAICliClient extends CliClient {
|
|
|
1569
1637
|
* stdin to dodge argv limits.
|
|
1570
1638
|
*/
|
|
1571
1639
|
export class GeminiCliClient extends CliClient {
|
|
1572
|
-
override name = 'gemini';
|
|
1573
|
-
override default_binary = 'gemini';
|
|
1574
1640
|
override subscription_label = 'gemini-pro';
|
|
1575
1641
|
|
|
1576
1642
|
static override _AUTH_FAILURE_PATTERNS: readonly string[] = [
|
|
@@ -1581,14 +1647,17 @@ export class GeminiCliClient extends CliClient {
|
|
|
1581
1647
|
];
|
|
1582
1648
|
|
|
1583
1649
|
constructor(opts: CliClientOptions = {}) {
|
|
1584
|
-
super(
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1650
|
+
super(
|
|
1651
|
+
{
|
|
1652
|
+
model: opts.model ?? DEFAULT_GEMINI_CLI_MODEL,
|
|
1653
|
+
binary: opts.binary,
|
|
1654
|
+
timeout_seconds: opts.timeout_seconds,
|
|
1655
|
+
max_calls_per_day: opts.max_calls_per_day,
|
|
1656
|
+
warn_at: opts.warn_at,
|
|
1657
|
+
cli_calls_path: opts.cli_calls_path,
|
|
1658
|
+
},
|
|
1659
|
+
{ name: 'gemini', default_binary: 'gemini' },
|
|
1660
|
+
);
|
|
1592
1661
|
}
|
|
1593
1662
|
|
|
1594
1663
|
protected override _build_command(
|
|
@@ -1686,8 +1755,6 @@ export class GeminiCliClient extends CliClient {
|
|
|
1686
1755
|
* heuristically (chars / 4) for the audit-trail.
|
|
1687
1756
|
*/
|
|
1688
1757
|
export class XAICliClient extends CliClient {
|
|
1689
|
-
override name = 'xai';
|
|
1690
|
-
override default_binary = 'grok';
|
|
1691
1758
|
override billable = true; // community CLI consumes an API key — billable applies
|
|
1692
1759
|
|
|
1693
1760
|
static override _AUTH_FAILURE_PATTERNS: readonly string[] = [
|
|
@@ -1698,14 +1765,17 @@ export class XAICliClient extends CliClient {
|
|
|
1698
1765
|
];
|
|
1699
1766
|
|
|
1700
1767
|
constructor(opts: CliClientOptions = {}) {
|
|
1701
|
-
super(
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1768
|
+
super(
|
|
1769
|
+
{
|
|
1770
|
+
model: opts.model ?? DEFAULT_XAI_MODEL,
|
|
1771
|
+
binary: opts.binary,
|
|
1772
|
+
timeout_seconds: opts.timeout_seconds,
|
|
1773
|
+
max_calls_per_day: opts.max_calls_per_day,
|
|
1774
|
+
warn_at: opts.warn_at,
|
|
1775
|
+
cli_calls_path: opts.cli_calls_path,
|
|
1776
|
+
},
|
|
1777
|
+
{ name: 'xai', default_binary: 'grok' },
|
|
1778
|
+
);
|
|
1709
1779
|
}
|
|
1710
1780
|
|
|
1711
1781
|
protected override _build_command(
|
|
@@ -1752,8 +1822,6 @@ export class XAICliClient extends CliClient {
|
|
|
1752
1822
|
* Invokes `perplexity -p <prompt>`. Output is plain text — no JSON envelope.
|
|
1753
1823
|
*/
|
|
1754
1824
|
export class PerplexityCliClient extends CliClient {
|
|
1755
|
-
override name = 'perplexity';
|
|
1756
|
-
override default_binary = 'perplexity';
|
|
1757
1825
|
override billable = true; // community CLI consumes an API key — billable applies
|
|
1758
1826
|
|
|
1759
1827
|
static override _AUTH_FAILURE_PATTERNS: readonly string[] = [
|
|
@@ -1764,14 +1832,17 @@ export class PerplexityCliClient extends CliClient {
|
|
|
1764
1832
|
];
|
|
1765
1833
|
|
|
1766
1834
|
constructor(opts: CliClientOptions = {}) {
|
|
1767
|
-
super(
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1835
|
+
super(
|
|
1836
|
+
{
|
|
1837
|
+
model: opts.model ?? DEFAULT_PERPLEXITY_MODEL,
|
|
1838
|
+
binary: opts.binary,
|
|
1839
|
+
timeout_seconds: opts.timeout_seconds,
|
|
1840
|
+
max_calls_per_day: opts.max_calls_per_day,
|
|
1841
|
+
warn_at: opts.warn_at,
|
|
1842
|
+
cli_calls_path: opts.cli_calls_path,
|
|
1843
|
+
},
|
|
1844
|
+
{ name: 'perplexity', default_binary: 'perplexity' },
|
|
1845
|
+
);
|
|
1775
1846
|
}
|
|
1776
1847
|
|
|
1777
1848
|
protected override _build_command(
|