@kognai/orchestrator-core 0.2.0 → 0.2.2
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/dist/lib/acp.js +16 -2
- package/dist/lib/anthropic-direct.js +1 -1
- package/dist/lib/cto-approval-gate.js +27 -0
- package/dist/lib/cto-gate-types.d.ts +1 -1
- package/dist/lib/engine-agents.d.ts +8 -1
- package/dist/lib/engine-agents.js +10 -3
- package/dist/lib/engine-coding-agent.js +2 -1
- package/dist/lib/engine-primitives.js +10 -3
- package/dist/lib/sovereign-agent-factory.d.ts +9 -2
- package/dist/lib/sovereign-agent-factory.js +9 -3
- package/dist/lib/sprint-runner-engine.d.ts +1 -1
- package/dist/lib/sprint-runner-engine.js +1 -1
- package/package.json +1 -1
package/dist/lib/acp.js
CHANGED
|
@@ -66,11 +66,25 @@ const REGISTRY = [
|
|
|
66
66
|
max_model_tier: 'power',
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
|
+
// TICKET-346 Finding 8: the supervisor reviews code on the cloud tier (T2.5/
|
|
70
|
+
// haiku) but lacked llm_call_cloud, so every review tripped the ClawRouter
|
|
71
|
+
// spend-gate shadow-downgrade ("agent supervisor lacks llm_call_cloud — T2.5
|
|
72
|
+
// WOULD be downgraded"), slowing/degrading review quality. Supervisors are
|
|
73
|
+
// sovereign — their review tier must not be role-gated. Grant cloud routing.
|
|
69
74
|
agent_id: 'supervisor', display_name: 'Supervisor', tier: 'T3',
|
|
70
|
-
capabilities: ['read_files', 'search_code', 'git_read', 'llm_call_local', 'db_query'],
|
|
75
|
+
capabilities: ['read_files', 'search_code', 'git_read', 'llm_call_local', 'llm_call_cloud', 'db_query'],
|
|
71
76
|
denied: ['write_files', 'shell_exec', 'deploy', 'git_push'],
|
|
72
77
|
scope: 'Sprint review, quality validation. Read-only analysis.',
|
|
73
|
-
max_model_tier: '
|
|
78
|
+
max_model_tier: 'cloud',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
// Second independent reviewer (haiku). Registered so it is GOVERNED by the
|
|
82
|
+
// spend-gate rather than silently passing through as an unknown agent_id.
|
|
83
|
+
agent_id: 'supervisor-2', display_name: 'Supervisor (2nd opinion)', tier: 'T3',
|
|
84
|
+
capabilities: ['read_files', 'search_code', 'git_read', 'llm_call_local', 'llm_call_cloud', 'db_query'],
|
|
85
|
+
denied: ['write_files', 'shell_exec', 'deploy', 'git_push'],
|
|
86
|
+
scope: 'Independent second-opinion review (haiku). Read-only analysis.',
|
|
87
|
+
max_model_tier: 'cloud',
|
|
74
88
|
},
|
|
75
89
|
{
|
|
76
90
|
agent_id: 'devops', display_name: 'DevOps', tier: 'T4',
|
|
@@ -55,7 +55,7 @@ async function callAnthropic(opts) {
|
|
|
55
55
|
throw new Error('ANTHROPIC_API_KEY not set');
|
|
56
56
|
const body = JSON.stringify({
|
|
57
57
|
model: opts.model,
|
|
58
|
-
max_tokens: opts.max_tokens ??
|
|
58
|
+
max_tokens: opts.max_tokens ?? 4096,
|
|
59
59
|
temperature: opts.temperature ?? 0.4,
|
|
60
60
|
system: opts.system,
|
|
61
61
|
messages: [{ role: 'user', content: opts.user }],
|
|
@@ -149,6 +149,33 @@ async function requestCTOApproval(proposal, projectRoot, product = 'kognai') {
|
|
|
149
149
|
timestamp,
|
|
150
150
|
};
|
|
151
151
|
}
|
|
152
|
+
// TICKET-346: CEO-approved autonomous proposals are sanctioned work — the CEO
|
|
153
|
+
// approval IS the plan authorization (exactly as 'queue-prescribed' means "the
|
|
154
|
+
// queue IS the plan"). The dispatcher (dispatch-approved-proposals.ts) only
|
|
155
|
+
// authors these from reports/cto/approved-proposals.json AFTER CEO approval,
|
|
156
|
+
// so the plan-alignment LLM must not reject them for NOT_IN_PLAN. Without this
|
|
157
|
+
// the autonomous loop fought its own governance: dispatcher authored → CTO gate
|
|
158
|
+
// rejected → $0 output (the 2026-06-12 diagnostic). Capability + Police checks
|
|
159
|
+
// belong here but the established sanctioned-source pattern (human, queue-
|
|
160
|
+
// prescribed) bypasses them too; the CEO approval is the upstream safety gate.
|
|
161
|
+
if (proposal.source === 'cto-autonomous') {
|
|
162
|
+
logCTODecision({
|
|
163
|
+
approved: true,
|
|
164
|
+
sprint_id: proposal.sprint_id,
|
|
165
|
+
reason: 'CEO-approved autonomous proposal — approval is the plan authorization (TICKET-346).',
|
|
166
|
+
plan_reference: 'CEO_APPROVED_AUTONOMOUS',
|
|
167
|
+
cto_confidence: 100,
|
|
168
|
+
timestamp,
|
|
169
|
+
}, projectRoot, product);
|
|
170
|
+
return {
|
|
171
|
+
approved: true,
|
|
172
|
+
sprint_id: proposal.sprint_id,
|
|
173
|
+
reason: 'CEO-approved autonomous proposal — approval is the plan authorization (TICKET-346).',
|
|
174
|
+
plan_reference: 'CEO_APPROVED_AUTONOMOUS',
|
|
175
|
+
cto_confidence: 100,
|
|
176
|
+
timestamp,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
152
179
|
// Sprint 650: ACP pre-check — reject if agents lack required capabilities
|
|
153
180
|
if (proposal.agent_capabilities && proposal.agent_capabilities.length > 0) {
|
|
154
181
|
const violations = [];
|
|
@@ -11,7 +11,7 @@ export interface SprintProposal {
|
|
|
11
11
|
description: string;
|
|
12
12
|
tasks: string[];
|
|
13
13
|
estimated_complexity: string;
|
|
14
|
-
source: 'autonomous_loop' | 'human' | 'cto_backlog' | 'queue-prescribed' | 'auto-queue-empty' | 'queue-empty-autonomous';
|
|
14
|
+
source: 'autonomous_loop' | 'human' | 'cto_backlog' | 'queue-prescribed' | 'auto-queue-empty' | 'queue-empty-autonomous' | 'cto-autonomous';
|
|
15
15
|
/** Sprint TICKET-005-RULE2: research | implementation phase gate */
|
|
16
16
|
phase?: 'research' | 'implementation';
|
|
17
17
|
/** ID of the research sprint that must be done before this implementation sprint can run */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CitizenOwner } from './citizenship';
|
|
1
|
+
import { type CitizenOwner, type CitizenRecord } from './citizenship';
|
|
2
2
|
import type { AgentTask, ReviewResult, CTOProposal, CTOReport } from './orchestrate-engine';
|
|
3
3
|
export declare class SupervisorAgent {
|
|
4
4
|
private systemPrompt;
|
|
@@ -69,6 +69,13 @@ export interface SpawnGateResult {
|
|
|
69
69
|
* Voxight swarm's a Voxight citizen, etc. The running company is carried by
|
|
70
70
|
* the template-injected gate's requester_did, not hardcoded in the engine. */
|
|
71
71
|
owner?: CitizenOwner;
|
|
72
|
+
/** TICKET-334b: the citizen the gate already minted through the template's
|
|
73
|
+
* canonical issuer (Kognai → SAF.spawnCitizen — governance + owner-lineage +
|
|
74
|
+
* ACP-at-birth). When present the engine adopts it verbatim and SKIPS its own
|
|
75
|
+
* bare mintCitizen, so the engine path no longer loses the ACP seeding. When
|
|
76
|
+
* absent (gate-less templates, or a gate that only governs) the engine falls
|
|
77
|
+
* back to minting itself with the resolved owner. */
|
|
78
|
+
citizen?: CitizenRecord;
|
|
72
79
|
}
|
|
73
80
|
export type SpawnGate = (spec: AgentSpawnSpec) => SpawnGateResult;
|
|
74
81
|
export declare class AgentCreator {
|
|
@@ -736,6 +736,7 @@ class AgentCreator {
|
|
|
736
736
|
// anything on disk. Approval/rejection only; the citizenship logic below is
|
|
737
737
|
// unchanged (its extraction is tracked separately as TICKET-226).
|
|
738
738
|
let spawnOwner;
|
|
739
|
+
let gateCitizen;
|
|
739
740
|
if (this.spawnGate) {
|
|
740
741
|
const decision = this.spawnGate(spec);
|
|
741
742
|
if (!decision.approved) {
|
|
@@ -753,6 +754,10 @@ class AgentCreator {
|
|
|
753
754
|
// The gate (SAF) resolves the lineage from its requester_did — this is the
|
|
754
755
|
// running company's context, plumbed in rather than hardcoded here.
|
|
755
756
|
spawnOwner = decision.owner;
|
|
757
|
+
// TICKET-334b: when the gate minted through the canonical issuer
|
|
758
|
+
// (SAF.spawnCitizen — owner-lineage + ACP-at-birth), adopt that citizen
|
|
759
|
+
// and skip the bare mint below (which would skip ACP seeding).
|
|
760
|
+
gateCitizen = decision.citizen;
|
|
756
761
|
}
|
|
757
762
|
const agentDir = `./agents/${spec.name}`;
|
|
758
763
|
(0, fs_1.mkdirSync)(agentDir, { recursive: true });
|
|
@@ -760,9 +765,11 @@ class AgentCreator {
|
|
|
760
765
|
// citizen — not a bare agent. Mint citizenship (citizen_id + roll
|
|
761
766
|
// number + Kōpus avatar + ACP baseline) BEFORE writing the agent
|
|
762
767
|
// files so the citizen record can be referenced in the prompt.
|
|
763
|
-
//
|
|
764
|
-
//
|
|
765
|
-
|
|
768
|
+
// Prefer the citizen the gate already minted through the canonical issuer
|
|
769
|
+
// (carries ACP-at-birth); else mint here owner-scoped when the gate supplied
|
|
770
|
+
// a lineage (e.g. invoica/voxight), or via the legacy kognai-internal path
|
|
771
|
+
// for gate-less templates.
|
|
772
|
+
const citizen = gateCitizen ?? (0, citizenship_1.mintCitizen)(spec.name, {
|
|
766
773
|
founding_agent: 'ceo',
|
|
767
774
|
proposing_agent: 'cto',
|
|
768
775
|
citizen_type: 'spawned',
|
|
@@ -743,7 +743,8 @@ ${originalContent}
|
|
|
743
743
|
task_type: 'json_repair', tier_class: 'text', complexity: 'nano',
|
|
744
744
|
context_tokens: Math.ceil(repairPrompt.length / 4), constitutional_flag: false,
|
|
745
745
|
agent_id: 'json-repair',
|
|
746
|
-
|
|
746
|
+
// TICKET-346 Finding 6: repair returns the WHOLE file; cap must hold it.
|
|
747
|
+
payload: { prompt: repairPrompt, max_tokens: parseInt(process.env.KOGNAI_DEBUG_REPAIR_MAX_TOKENS ?? process.env.KOGNAI_MAX_OUTPUT_TOKENS ?? '8192', 10) },
|
|
747
748
|
});
|
|
748
749
|
const fixed = result.content.trim();
|
|
749
750
|
try {
|
|
@@ -671,6 +671,13 @@ async function typecheckChangedFiles(filePaths) {
|
|
|
671
671
|
}
|
|
672
672
|
return { pass: true, errorCount: 0, firstError: `${projects.size} project(s) typechecked clean` };
|
|
673
673
|
}
|
|
674
|
+
// TICKET-346 Finding 6 (TICKET-336): the repair OUTPUT cap must be decoupled
|
|
675
|
+
// from issue severity. tieredDebug returns the WHOLE fixed file, so a "minor"
|
|
676
|
+
// fix to a 400-line file still needs room to emit all 400 lines. The old caps
|
|
677
|
+
// (4096/2048/1024) truncated full-file repairs → [TRUNCATION] rejection → repair
|
|
678
|
+
// exhausted (this killed scorer.ts in sprint-1665). Severity still selects the
|
|
679
|
+
// MODEL tier (exec vs power); only the output ceiling is now uniform & generous.
|
|
680
|
+
const DEBUG_REPAIR_MAX_TOKENS = parseInt(process.env.KOGNAI_DEBUG_REPAIR_MAX_TOKENS ?? process.env.KOGNAI_MAX_OUTPUT_TOKENS ?? '8192', 10);
|
|
674
681
|
// B.11: Tiered debugger — routes debug effort by issue severity via ClawRouter v2.0
|
|
675
682
|
async function tieredDebug(task, review, _systemPrompt) {
|
|
676
683
|
const issueText = (review.issues || []).map(i => `[${i.severity}] ${i.file}: ${i.description}`).join('\n');
|
|
@@ -683,7 +690,7 @@ async function tieredDebug(task, review, _systemPrompt) {
|
|
|
683
690
|
task_type: 'debug_architectural', tier_class: 'text', complexity: 'exec',
|
|
684
691
|
context_tokens: Math.ceil((issueText.length + 800) / 4), constitutional_flag: false,
|
|
685
692
|
agent_id: 'tiered-debugger',
|
|
686
|
-
payload: { prompt: `Fix this code. Issues:\n${issueText}\n\nTask: ${task.context.substring(0, 800)}`, max_tokens:
|
|
693
|
+
payload: { prompt: `Fix this code. Issues:\n${issueText}\n\nTask: ${task.context.substring(0, 800)}`, max_tokens: DEBUG_REPAIR_MAX_TOKENS },
|
|
687
694
|
});
|
|
688
695
|
return result.content || null;
|
|
689
696
|
}
|
|
@@ -693,7 +700,7 @@ async function tieredDebug(task, review, _systemPrompt) {
|
|
|
693
700
|
task_type: 'debug_systemic', tier_class: 'text', complexity: 'power',
|
|
694
701
|
context_tokens: Math.ceil((issueText.length + 600) / 4), constitutional_flag: false,
|
|
695
702
|
agent_id: 'tiered-debugger',
|
|
696
|
-
payload: { prompt: `Fix these code issues:\n${issueText}\n\nTask: ${task.context.substring(0, 600)}`, max_tokens:
|
|
703
|
+
payload: { prompt: `Fix these code issues:\n${issueText}\n\nTask: ${task.context.substring(0, 600)}`, max_tokens: DEBUG_REPAIR_MAX_TOKENS },
|
|
697
704
|
});
|
|
698
705
|
return result.content;
|
|
699
706
|
}
|
|
@@ -703,7 +710,7 @@ async function tieredDebug(task, review, _systemPrompt) {
|
|
|
703
710
|
task_type: 'debug_minor', tier_class: 'text', complexity: 'power',
|
|
704
711
|
context_tokens: Math.ceil((issueText.length + 500) / 4), constitutional_flag: false,
|
|
705
712
|
agent_id: 'tiered-debugger',
|
|
706
|
-
payload: { prompt: `Fix these minor code issues:\n${issueText}\n\nTask: ${task.context.substring(0, 500)}`, max_tokens:
|
|
713
|
+
payload: { prompt: `Fix these minor code issues:\n${issueText}\n\nTask: ${task.context.substring(0, 500)}`, max_tokens: DEBUG_REPAIR_MAX_TOKENS },
|
|
707
714
|
});
|
|
708
715
|
return result.content;
|
|
709
716
|
}
|
|
@@ -119,12 +119,19 @@ export declare function deriveOwner(requester_did: string): CitizenOwner;
|
|
|
119
119
|
*
|
|
120
120
|
* Returns the governance decision plus the minted citizen (when approved). The
|
|
121
121
|
* caller still writes citizen.yaml via renderCitizenYaml(citizen). The initial
|
|
122
|
-
* ACP (
|
|
123
|
-
*
|
|
122
|
+
* ACP is seeded here at birth (writeInitialAcp) so the citizen has a routing
|
|
123
|
+
* profile from the moment it exists — this is the property the engine seam lost
|
|
124
|
+
* when it minted via bare mintCitizen (TICKET-334b).
|
|
125
|
+
*
|
|
126
|
+
* `founding_agent` / `proposing_agent` let a caller preserve its own attribution
|
|
127
|
+
* (e.g. the engine's CEO-founds / CTO-proposes lineage). When omitted, the
|
|
128
|
+
* proposing agent defaults to the requester DID.
|
|
124
129
|
*/
|
|
125
130
|
export declare function spawnCitizen(req: SpawnRequest, opts?: {
|
|
126
131
|
agent_name?: string;
|
|
127
132
|
now?: Date;
|
|
133
|
+
founding_agent?: string;
|
|
134
|
+
proposing_agent?: string;
|
|
128
135
|
}): {
|
|
129
136
|
decision: SpawnDecision;
|
|
130
137
|
citizen?: CitizenRecord;
|
|
@@ -328,8 +328,13 @@ function deriveOwner(requester_did) {
|
|
|
328
328
|
*
|
|
329
329
|
* Returns the governance decision plus the minted citizen (when approved). The
|
|
330
330
|
* caller still writes citizen.yaml via renderCitizenYaml(citizen). The initial
|
|
331
|
-
* ACP (
|
|
332
|
-
*
|
|
331
|
+
* ACP is seeded here at birth (writeInitialAcp) so the citizen has a routing
|
|
332
|
+
* profile from the moment it exists — this is the property the engine seam lost
|
|
333
|
+
* when it minted via bare mintCitizen (TICKET-334b).
|
|
334
|
+
*
|
|
335
|
+
* `founding_agent` / `proposing_agent` let a caller preserve its own attribution
|
|
336
|
+
* (e.g. the engine's CEO-founds / CTO-proposes lineage). When omitted, the
|
|
337
|
+
* proposing agent defaults to the requester DID.
|
|
333
338
|
*/
|
|
334
339
|
function spawnCitizen(req, opts = {}) {
|
|
335
340
|
const decision = sovereignSpawn(req);
|
|
@@ -339,7 +344,8 @@ function spawnCitizen(req, opts = {}) {
|
|
|
339
344
|
const citizen = (0, citizenship_1.mintCitizen)(opts.agent_name ?? req.requested_role, {
|
|
340
345
|
owner,
|
|
341
346
|
citizen_type: 'spawned',
|
|
342
|
-
|
|
347
|
+
founding_agent: opts.founding_agent,
|
|
348
|
+
proposing_agent: opts.proposing_agent ?? req.requester_did,
|
|
343
349
|
now: opts.now,
|
|
344
350
|
});
|
|
345
351
|
decision.citizen_did = citizen.agent_did;
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
export interface SprintRunnerOpts {
|
|
23
23
|
orchestratorScript: string;
|
|
24
|
-
postSprintHook?: () => void
|
|
24
|
+
postSprintHook?: () => void | Promise<void>;
|
|
25
25
|
}
|
|
26
26
|
declare function runSprintCycle(opts: SprintRunnerOpts): Promise<void>;
|
|
27
27
|
export { runSprintCycle };
|
|
@@ -1033,7 +1033,7 @@ async function runSprintCycle(opts) {
|
|
|
1033
1033
|
// TICKET-201: post-sprint hook (e.g. dispatch-approved-proposals).
|
|
1034
1034
|
// Supplied by the product entry so core stays product-agnostic.
|
|
1035
1035
|
try {
|
|
1036
|
-
opts.postSprintHook?.();
|
|
1036
|
+
await opts.postSprintHook?.();
|
|
1037
1037
|
}
|
|
1038
1038
|
catch (e) {
|
|
1039
1039
|
log(`WARN: post-sprint hook failed (non-fatal): ${(e?.message || String(e)).substring(0, 200)}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kognai/orchestrator-core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Kognai sovereign orchestrator — core engine (template-agnostic). Shared by all products (Kognai/coding, Voxight/market-intel, Invoica/fin-compliance); each supplies only its template. Replaces per-repo forks of orchestrate-agents-v2 / sprint-runner / lib.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SkinGem",
|