@kognai/orchestrator-core 0.1.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 +44 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +175 -0
- package/dist/lib/aar-middleware.d.ts +6 -0
- package/dist/lib/aar-middleware.js +70 -0
- package/dist/lib/aar-types.d.ts +34 -0
- package/dist/lib/aar-types.js +4 -0
- package/dist/lib/acp-engine.d.ts +68 -0
- package/dist/lib/acp-engine.js +123 -0
- package/dist/lib/acp.d.ts +61 -0
- package/dist/lib/acp.js +425 -0
- package/dist/lib/agent-registry.d.ts +50 -0
- package/dist/lib/agent-registry.js +137 -0
- package/dist/lib/anthropic-direct.d.ts +27 -0
- package/dist/lib/anthropic-direct.js +109 -0
- package/dist/lib/asmr-extractor.d.ts +40 -0
- package/dist/lib/asmr-extractor.js +151 -0
- package/dist/lib/asmr-retrieval.d.ts +76 -0
- package/dist/lib/asmr-retrieval.js +311 -0
- package/dist/lib/asmr.d.ts +8 -0
- package/dist/lib/asmr.js +24 -0
- package/dist/lib/brainx-client.d.ts +72 -0
- package/dist/lib/brainx-client.js +200 -0
- package/dist/lib/brainx-embed.d.ts +14 -0
- package/dist/lib/brainx-embed.js +139 -0
- package/dist/lib/brainx-swarm-bridge.d.ts +93 -0
- package/dist/lib/brainx-swarm-bridge.js +242 -0
- package/dist/lib/byterover-client.d.ts +19 -0
- package/dist/lib/byterover-client.js +59 -0
- package/dist/lib/ceo-wallet.d.ts +37 -0
- package/dist/lib/ceo-wallet.js +176 -0
- package/dist/lib/chomsky-gate.d.ts +24 -0
- package/dist/lib/chomsky-gate.js +178 -0
- package/dist/lib/chomsky-runner.d.ts +29 -0
- package/dist/lib/chomsky-runner.js +157 -0
- package/dist/lib/citizen-score-contract.d.ts +72 -0
- package/dist/lib/citizen-score-contract.js +16 -0
- package/dist/lib/citizen-score-registry.d.ts +25 -0
- package/dist/lib/citizen-score-registry.js +65 -0
- package/dist/lib/citizenship.d.ts +103 -0
- package/dist/lib/citizenship.js +272 -0
- package/dist/lib/clawrouter-client.d.ts +37 -0
- package/dist/lib/clawrouter-client.js +148 -0
- package/dist/lib/code-asset-crystalliser.d.ts +41 -0
- package/dist/lib/code-asset-crystalliser.js +181 -0
- package/dist/lib/code-failure-logger.d.ts +27 -0
- package/dist/lib/code-failure-logger.js +42 -0
- package/dist/lib/cto-approval-gate.d.ts +45 -0
- package/dist/lib/cto-approval-gate.js +478 -0
- package/dist/lib/cto-gate-types.d.ts +28 -0
- package/dist/lib/cto-gate-types.js +8 -0
- package/dist/lib/decomposer-feedback.d.ts +54 -0
- package/dist/lib/decomposer-feedback.js +115 -0
- package/dist/lib/emotional-safety-gate.d.ts +48 -0
- package/dist/lib/emotional-safety-gate.js +97 -0
- package/dist/lib/engine-paths.d.ts +13 -0
- package/dist/lib/engine-paths.js +32 -0
- package/dist/lib/event-bus-listener.d.ts +8 -0
- package/dist/lib/event-bus-listener.js +144 -0
- package/dist/lib/event-bus-publisher.d.ts +25 -0
- package/dist/lib/event-bus-publisher.js +188 -0
- package/dist/lib/event-bus-types.d.ts +73 -0
- package/dist/lib/event-bus-types.js +23 -0
- package/dist/lib/failure-library.d.ts +178 -0
- package/dist/lib/failure-library.js +349 -0
- package/dist/lib/ksl/error-log.d.ts +28 -0
- package/dist/lib/ksl/error-log.js +43 -0
- package/dist/lib/ksl/index.d.ts +9 -0
- package/dist/lib/ksl/index.js +25 -0
- package/dist/lib/ksl/orchestrator-tap.d.ts +16 -0
- package/dist/lib/ksl/orchestrator-tap.js +85 -0
- package/dist/lib/ksl/record-writer.d.ts +46 -0
- package/dist/lib/ksl/record-writer.js +45 -0
- package/dist/lib/llm-cost-table.d.ts +36 -0
- package/dist/lib/llm-cost-table.js +90 -0
- package/dist/lib/local-model-router.d.ts +27 -0
- package/dist/lib/local-model-router.js +61 -0
- package/dist/lib/mc-client.d.ts +51 -0
- package/dist/lib/mc-client.js +249 -0
- package/dist/lib/model-router-contract.d.ts +91 -0
- package/dist/lib/model-router-contract.js +19 -0
- package/dist/lib/model-router-registry.d.ts +24 -0
- package/dist/lib/model-router-registry.js +52 -0
- package/dist/lib/model-router.d.ts +20 -0
- package/dist/lib/model-router.js +79 -0
- package/dist/lib/monotask-state-machine.d.ts +19 -0
- package/dist/lib/monotask-state-machine.js +131 -0
- package/dist/lib/neutral-prompt-checker.d.ts +22 -0
- package/dist/lib/neutral-prompt-checker.js +130 -0
- package/dist/lib/notion-direct.d.ts +92 -0
- package/dist/lib/notion-direct.js +381 -0
- package/dist/lib/ollama-client.d.ts +37 -0
- package/dist/lib/ollama-client.js +158 -0
- package/dist/lib/omel/credential-vault.d.ts +57 -0
- package/dist/lib/omel/credential-vault.js +324 -0
- package/dist/lib/omel/human-brake.d.ts +32 -0
- package/dist/lib/omel/human-brake.js +289 -0
- package/dist/lib/omel/index.d.ts +10 -0
- package/dist/lib/omel/index.js +26 -0
- package/dist/lib/omel/phantom-workspace.d.ts +31 -0
- package/dist/lib/omel/phantom-workspace.js +256 -0
- package/dist/lib/omel/wipe-witness.d.ts +75 -0
- package/dist/lib/omel/wipe-witness.js +398 -0
- package/dist/lib/orchestrate-engine.d.ts +25 -0
- package/dist/lib/orchestrate-engine.js +4436 -0
- package/dist/lib/perm-judge.d.ts +46 -0
- package/dist/lib/perm-judge.js +173 -0
- package/dist/lib/plumber/conformance.d.ts +54 -0
- package/dist/lib/plumber/conformance.js +121 -0
- package/dist/lib/plumber/index.d.ts +9 -0
- package/dist/lib/plumber/index.js +25 -0
- package/dist/lib/plumber/observer.d.ts +52 -0
- package/dist/lib/plumber/observer.js +180 -0
- package/dist/lib/plumber/types.d.ts +78 -0
- package/dist/lib/plumber/types.js +29 -0
- package/dist/lib/research-impl-gate.d.ts +16 -0
- package/dist/lib/research-impl-gate.js +105 -0
- package/dist/lib/sherlock-memory.d.ts +29 -0
- package/dist/lib/sherlock-memory.js +105 -0
- package/dist/lib/skill-crystalliser.d.ts +44 -0
- package/dist/lib/skill-crystalliser.js +60 -0
- package/dist/lib/sprint-runner-engine.d.ts +27 -0
- package/dist/lib/sprint-runner-engine.js +1042 -0
- package/dist/lib/sprint-state.d.ts +71 -0
- package/dist/lib/sprint-state.js +202 -0
- package/dist/lib/stuck-handler.d.ts +17 -0
- package/dist/lib/stuck-handler.js +249 -0
- package/dist/lib/task-contract-checker.d.ts +17 -0
- package/dist/lib/task-contract-checker.js +29 -0
- package/dist/lib/task-router/index.d.ts +17 -0
- package/dist/lib/task-router/index.js +52 -0
- package/dist/lib/task-router/router/generate-execution-id.d.ts +10 -0
- package/dist/lib/task-router/router/generate-execution-id.js +24 -0
- package/dist/lib/task-router/router/resolve-route.d.ts +2 -0
- package/dist/lib/task-router/router/resolve-route.js +49 -0
- package/dist/lib/task-router/types.d.ts +79 -0
- package/dist/lib/task-router/types.js +39 -0
- package/dist/lib/token-budget-validator.d.ts +44 -0
- package/dist/lib/token-budget-validator.js +84 -0
- package/dist/lib/trust-score-updater.d.ts +30 -0
- package/dist/lib/trust-score-updater.js +107 -0
- package/dist/lib/wallet-state.d.ts +26 -0
- package/dist/lib/wallet-state.js +85 -0
- package/package.json +27 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateExecutionId = generateExecutionId;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
/**
|
|
6
|
+
* Generates a deterministic execution ID from sprintId and taskId.
|
|
7
|
+
* Uses SHA256 hash of `${sprintId}:${taskId}` to create a consistent identifier.
|
|
8
|
+
*
|
|
9
|
+
* @param sprintId - The unique identifier for the sprint
|
|
10
|
+
* @param taskId - The unique identifier for the task
|
|
11
|
+
* @returns A 64-character hexadecimal SHA256 hash string
|
|
12
|
+
* @throws Error if sprintId or taskId is not provided
|
|
13
|
+
*/
|
|
14
|
+
function generateExecutionId(sprintId, taskId) {
|
|
15
|
+
if (!sprintId || typeof sprintId !== 'string') {
|
|
16
|
+
throw new Error('sprintId must be a non-empty string');
|
|
17
|
+
}
|
|
18
|
+
if (!taskId || typeof taskId !== 'string') {
|
|
19
|
+
throw new Error('taskId must be a non-empty string');
|
|
20
|
+
}
|
|
21
|
+
const input = `${sprintId}:${taskId}`;
|
|
22
|
+
const hash = (0, crypto_1.createHash)('sha256').update(input).digest('hex');
|
|
23
|
+
return hash;
|
|
24
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveRoute = resolveRoute;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
function resolveRoute(target) {
|
|
6
|
+
switch (target) {
|
|
7
|
+
case 'local': {
|
|
8
|
+
return {
|
|
9
|
+
provider: 'ollama',
|
|
10
|
+
model: process.env.VAULT_MODEL ?? 'qwen3:14b',
|
|
11
|
+
endpoint: process.env.VAULT_OLLAMA_URL ?? 'http://vault:11434',
|
|
12
|
+
timeoutMs: types_1.TIMEOUT_BUDGETS.local,
|
|
13
|
+
target: 'local',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
case 'cloud-code': {
|
|
17
|
+
return {
|
|
18
|
+
provider: 'minimax',
|
|
19
|
+
model: 'MiniMax-M2.5',
|
|
20
|
+
endpoint: 'https://api.minimax.io/v1/chat/completions',
|
|
21
|
+
timeoutMs: types_1.TIMEOUT_BUDGETS['cloud-code'],
|
|
22
|
+
target: 'cloud-code',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
case 'cloud-exec': {
|
|
26
|
+
return {
|
|
27
|
+
provider: 'anthropic',
|
|
28
|
+
model: 'claude-sonnet-4-20250514',
|
|
29
|
+
endpoint: 'https://api.anthropic.com/v1/messages',
|
|
30
|
+
timeoutMs: types_1.TIMEOUT_BUDGETS['cloud-exec'],
|
|
31
|
+
target: 'cloud-exec',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
case 'cloud-post': {
|
|
35
|
+
return {
|
|
36
|
+
provider: 'external',
|
|
37
|
+
model: 'n/a',
|
|
38
|
+
endpoint: '',
|
|
39
|
+
timeoutMs: types_1.TIMEOUT_BUDGETS['cloud-post'],
|
|
40
|
+
target: 'cloud-post',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
default: {
|
|
44
|
+
const exhaustiveCheck = target;
|
|
45
|
+
console.warn(`[resolveRoute] Unhandled target type: ${exhaustiveCheck}, defaulting to cloud-code`);
|
|
46
|
+
return resolveRoute('cloud-code');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kognai Task Router Types
|
|
3
|
+
*
|
|
4
|
+
* Defines the core type definitions for the task routing system,
|
|
5
|
+
* including task targets, timeout budgets, route configurations,
|
|
6
|
+
* and routing log entries.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Task execution target environments
|
|
10
|
+
*/
|
|
11
|
+
export type TaskTarget = 'local' | 'cloud-code' | 'cloud-exec' | 'cloud-post';
|
|
12
|
+
/**
|
|
13
|
+
* Timeout budgets in milliseconds for each task target
|
|
14
|
+
* - local: 10 minutes (600000ms) - local Ollama execution
|
|
15
|
+
* - cloud-code: 2 minutes (120000ms) - cloud code generation
|
|
16
|
+
* - cloud-exec: 90 seconds (90000ms) - cloud code execution
|
|
17
|
+
* - cloud-post: 30 seconds (30000ms) - cloud post-processing
|
|
18
|
+
*/
|
|
19
|
+
export declare const TIMEOUT_BUDGETS: Record<TaskTarget, number>;
|
|
20
|
+
/**
|
|
21
|
+
* Supported AI model providers
|
|
22
|
+
*/
|
|
23
|
+
export type ModelProvider = 'ollama' | 'minimax' | 'anthropic' | 'external';
|
|
24
|
+
/**
|
|
25
|
+
* Task route configuration
|
|
26
|
+
* Defines how a task should be routed to a specific provider and model
|
|
27
|
+
*/
|
|
28
|
+
export interface TaskRoute {
|
|
29
|
+
/** The AI provider to use for this route */
|
|
30
|
+
provider: ModelProvider;
|
|
31
|
+
/** The specific model identifier */
|
|
32
|
+
model: string;
|
|
33
|
+
/** The endpoint URL for the provider */
|
|
34
|
+
endpoint: string;
|
|
35
|
+
/** Timeout in milliseconds for this route */
|
|
36
|
+
timeoutMs: number;
|
|
37
|
+
/** The target environment for task execution */
|
|
38
|
+
target: TaskTarget;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Routing log entry
|
|
42
|
+
* Records the routing decision and execution details for audit and debugging
|
|
43
|
+
*/
|
|
44
|
+
export interface RoutingLogEntry {
|
|
45
|
+
/** Unique execution identifier */
|
|
46
|
+
execution_id: string;
|
|
47
|
+
/** Sprint identifier this task belongs to */
|
|
48
|
+
sprint_id: string;
|
|
49
|
+
/** Task identifier within the sprint */
|
|
50
|
+
task_id: string;
|
|
51
|
+
/** Selected task target environment */
|
|
52
|
+
task_target: TaskTarget;
|
|
53
|
+
/** Provider used for execution */
|
|
54
|
+
provider: string;
|
|
55
|
+
/** Model used for execution */
|
|
56
|
+
model: string;
|
|
57
|
+
/** Timestamp when task was queued */
|
|
58
|
+
queued_at: string;
|
|
59
|
+
/** Timestamp when task started execution (optional) */
|
|
60
|
+
executed_at?: string;
|
|
61
|
+
/** Source of the execution request */
|
|
62
|
+
execution_source: string;
|
|
63
|
+
/** Whether the vault was reachable at routing time */
|
|
64
|
+
vault_reachable?: boolean;
|
|
65
|
+
/** Whether task was queued locally */
|
|
66
|
+
queued_local?: boolean;
|
|
67
|
+
/** Error message if routing or execution failed */
|
|
68
|
+
error?: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Type guard to check if a string is a valid TaskTarget
|
|
72
|
+
*/
|
|
73
|
+
export declare function isValidTaskTarget(value: string): value is TaskTarget;
|
|
74
|
+
/**
|
|
75
|
+
* Get timeout budget for a task target
|
|
76
|
+
* @param target - The task target environment
|
|
77
|
+
* @returns Timeout in milliseconds, defaults to 60000ms if unknown
|
|
78
|
+
*/
|
|
79
|
+
export declare function getTimeoutBudget(target: TaskTarget): number;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Kognai Task Router Types
|
|
4
|
+
*
|
|
5
|
+
* Defines the core type definitions for the task routing system,
|
|
6
|
+
* including task targets, timeout budgets, route configurations,
|
|
7
|
+
* and routing log entries.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.TIMEOUT_BUDGETS = void 0;
|
|
11
|
+
exports.isValidTaskTarget = isValidTaskTarget;
|
|
12
|
+
exports.getTimeoutBudget = getTimeoutBudget;
|
|
13
|
+
/**
|
|
14
|
+
* Timeout budgets in milliseconds for each task target
|
|
15
|
+
* - local: 10 minutes (600000ms) - local Ollama execution
|
|
16
|
+
* - cloud-code: 2 minutes (120000ms) - cloud code generation
|
|
17
|
+
* - cloud-exec: 90 seconds (90000ms) - cloud code execution
|
|
18
|
+
* - cloud-post: 30 seconds (30000ms) - cloud post-processing
|
|
19
|
+
*/
|
|
20
|
+
exports.TIMEOUT_BUDGETS = {
|
|
21
|
+
local: 600000,
|
|
22
|
+
'cloud-code': 120000,
|
|
23
|
+
'cloud-exec': 90000,
|
|
24
|
+
'cloud-post': 30000,
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Type guard to check if a string is a valid TaskTarget
|
|
28
|
+
*/
|
|
29
|
+
function isValidTaskTarget(value) {
|
|
30
|
+
return ['local', 'cloud-code', 'cloud-exec', 'cloud-post'].includes(value);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get timeout budget for a task target
|
|
34
|
+
* @param target - The task target environment
|
|
35
|
+
* @returns Timeout in milliseconds, defaults to 60000ms if unknown
|
|
36
|
+
*/
|
|
37
|
+
function getTimeoutBudget(target) {
|
|
38
|
+
return exports.TIMEOUT_BUDGETS[target] ?? 60000;
|
|
39
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* token-budget-validator.ts — Deterministic pre-flight gate on MiniMax dispatch.
|
|
3
|
+
*
|
|
4
|
+
* Estimates the output-token cost for a task before any LLM is called. Rejects
|
|
5
|
+
* tasks predicted to exceed the truncation threshold (3800 tokens default —
|
|
6
|
+
* 700-token safety margin below MiniMax M2.5's documented ~4500 truncation
|
|
7
|
+
* point per docs/learnings.md §1).
|
|
8
|
+
*
|
|
9
|
+
* Stdlib only. NO LLM calls — this is a budget gate, it can't cost tokens to
|
|
10
|
+
* run. Returns suggested splits when rejecting so the decomposer-feedback
|
|
11
|
+
* router has something concrete to resplit on.
|
|
12
|
+
*
|
|
13
|
+
* Created: sprint-1566 task `wire_token_budget_validator` (F0).
|
|
14
|
+
* Replaces the orphaned `agents/token-budget-validator/` agent that CEO
|
|
15
|
+
* auto-spawned 2026-05-19 but never wired in.
|
|
16
|
+
*/
|
|
17
|
+
/** Minimal task shape the validator needs. Compatible with AgentTask in
|
|
18
|
+
* orchestrate-agents-v2.ts but defined locally to avoid circular imports. */
|
|
19
|
+
export interface ValidatableTask {
|
|
20
|
+
id: string;
|
|
21
|
+
context?: string;
|
|
22
|
+
deliverables?: {
|
|
23
|
+
code?: string[];
|
|
24
|
+
edits?: string[];
|
|
25
|
+
tests?: string[];
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export type ValidationResult = {
|
|
29
|
+
ok: true;
|
|
30
|
+
estimated_tokens: number;
|
|
31
|
+
} | {
|
|
32
|
+
ok: false;
|
|
33
|
+
estimated_tokens: number;
|
|
34
|
+
reason: string;
|
|
35
|
+
suggested_split: string[];
|
|
36
|
+
};
|
|
37
|
+
/** Estimate output tokens for a single task. Heuristic per sprint-1566 spec:
|
|
38
|
+
* base + Σ(per_file_min + tokens_per_loc × estimated_loc) × test_multiplier?
|
|
39
|
+
* estimated_loc derives from context length (denser specs imply more output).
|
|
40
|
+
*/
|
|
41
|
+
export declare function estimateOutputTokens(task: ValidatableTask): number;
|
|
42
|
+
/** Validate a task against the truncation budget. When over budget, suggest a
|
|
43
|
+
* per-file split so the decomposer-feedback router can resplit deterministically. */
|
|
44
|
+
export declare function validateTask(task: ValidatableTask, threshold?: number): ValidationResult;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* token-budget-validator.ts — Deterministic pre-flight gate on MiniMax dispatch.
|
|
4
|
+
*
|
|
5
|
+
* Estimates the output-token cost for a task before any LLM is called. Rejects
|
|
6
|
+
* tasks predicted to exceed the truncation threshold (3800 tokens default —
|
|
7
|
+
* 700-token safety margin below MiniMax M2.5's documented ~4500 truncation
|
|
8
|
+
* point per docs/learnings.md §1).
|
|
9
|
+
*
|
|
10
|
+
* Stdlib only. NO LLM calls — this is a budget gate, it can't cost tokens to
|
|
11
|
+
* run. Returns suggested splits when rejecting so the decomposer-feedback
|
|
12
|
+
* router has something concrete to resplit on.
|
|
13
|
+
*
|
|
14
|
+
* Created: sprint-1566 task `wire_token_budget_validator` (F0).
|
|
15
|
+
* Replaces the orphaned `agents/token-budget-validator/` agent that CEO
|
|
16
|
+
* auto-spawned 2026-05-19 but never wired in.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.estimateOutputTokens = estimateOutputTokens;
|
|
20
|
+
exports.validateTask = validateTask;
|
|
21
|
+
const DEFAULT_THRESHOLD = parseInt(process.env.TOKEN_BUDGET_THRESHOLD || '3800', 10);
|
|
22
|
+
const BASE_BOILERPLATE_TOKENS = 400;
|
|
23
|
+
const PER_FILE_MIN_TOKENS = 200;
|
|
24
|
+
// Calibrated from observed MiniMax M2.5 truncations on real Kognai tasks
|
|
25
|
+
// (data/failure-library/code/). The 138 "truncated" entries cluster around
|
|
26
|
+
// tasks whose context was 4-12KB with 1-3 deliverable files — these numbers
|
|
27
|
+
// reproduce that rejection envelope.
|
|
28
|
+
const TOKENS_PER_LOC = 12;
|
|
29
|
+
const CHARS_PER_LOC = 40;
|
|
30
|
+
const TEST_MULTIPLIER = 1.4;
|
|
31
|
+
/** Estimate output tokens for a single task. Heuristic per sprint-1566 spec:
|
|
32
|
+
* base + Σ(per_file_min + tokens_per_loc × estimated_loc) × test_multiplier?
|
|
33
|
+
* estimated_loc derives from context length (denser specs imply more output).
|
|
34
|
+
*/
|
|
35
|
+
function estimateOutputTokens(task) {
|
|
36
|
+
const codeFiles = task.deliverables?.code || [];
|
|
37
|
+
const editFiles = task.deliverables?.edits || [];
|
|
38
|
+
const testFiles = task.deliverables?.tests || [];
|
|
39
|
+
const fileCount = codeFiles.length + editFiles.length;
|
|
40
|
+
if (fileCount === 0)
|
|
41
|
+
return 0; // pure-edit or non-code task — skip validation
|
|
42
|
+
const contextChars = (task.context || '').length;
|
|
43
|
+
const estimatedLoc = Math.max(40, Math.ceil(contextChars / CHARS_PER_LOC));
|
|
44
|
+
const perFileTokens = PER_FILE_MIN_TOKENS + TOKENS_PER_LOC * estimatedLoc;
|
|
45
|
+
let total = BASE_BOILERPLATE_TOKENS + fileCount * perFileTokens;
|
|
46
|
+
const hasTests = testFiles.length > 0 || codeFiles.some(f => f.includes('__tests__') || f.includes('.test.'));
|
|
47
|
+
if (hasTests)
|
|
48
|
+
total = Math.ceil(total * TEST_MULTIPLIER);
|
|
49
|
+
return total;
|
|
50
|
+
}
|
|
51
|
+
/** Validate a task against the truncation budget. When over budget, suggest a
|
|
52
|
+
* per-file split so the decomposer-feedback router can resplit deterministically. */
|
|
53
|
+
function validateTask(task, threshold = DEFAULT_THRESHOLD) {
|
|
54
|
+
const estimated = estimateOutputTokens(task);
|
|
55
|
+
// Empty deliverables skip the gate (nothing to estimate)
|
|
56
|
+
if (estimated === 0)
|
|
57
|
+
return { ok: true, estimated_tokens: 0 };
|
|
58
|
+
if (estimated <= threshold)
|
|
59
|
+
return { ok: true, estimated_tokens: estimated };
|
|
60
|
+
const codeFiles = task.deliverables?.code || [];
|
|
61
|
+
const editFiles = task.deliverables?.edits || [];
|
|
62
|
+
// Suggested split: if multiple files, propose one sub-task per file. If a
|
|
63
|
+
// single file, propose splitting context into N sub-tasks (caller decides
|
|
64
|
+
// how to actually slice the context — we just hint at the cardinality).
|
|
65
|
+
let suggested;
|
|
66
|
+
if ((codeFiles.length + editFiles.length) > 1) {
|
|
67
|
+
suggested = [...codeFiles, ...editFiles].map(f => `${task.id}__${slugForPath(f)}`);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
const target = codeFiles[0] || editFiles[0] || task.id;
|
|
71
|
+
// Estimate how many splits would each land under threshold
|
|
72
|
+
const splitCount = Math.max(2, Math.ceil(estimated / threshold));
|
|
73
|
+
suggested = Array.from({ length: splitCount }, (_, i) => `${task.id}__part${i + 1}`);
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
estimated_tokens: estimated,
|
|
78
|
+
reason: `Estimated output ${estimated} tokens exceeds threshold ${threshold} (MiniMax truncates at ~4500 per docs/learnings.md §1). Decomposer must re-split.`,
|
|
79
|
+
suggested_split: suggested,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function slugForPath(p) {
|
|
83
|
+
return p.replace(/^scripts\//, '').replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, '').replace(/[^a-z0-9]+/gi, '_').toLowerCase();
|
|
84
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* trust-score-updater.ts — Sprint 703 (GOV Phase 1)
|
|
3
|
+
*
|
|
4
|
+
* Dynamic ACP trust score updater. Adjusts scores based on real outcomes:
|
|
5
|
+
* - Approved tasks (score >= 80): accuracy +1
|
|
6
|
+
* - Rejected tasks: accuracy -2
|
|
7
|
+
* - Safety flags: safety -3
|
|
8
|
+
* - 5% daily decay toward 70 (mean) for stale agents
|
|
9
|
+
*
|
|
10
|
+
* Called by orchestrate-agents-v2.ts on both approval and rejection paths.
|
|
11
|
+
*
|
|
12
|
+
* TICKET-215 Phase 3b-2: the repo root now resolves via engine-paths
|
|
13
|
+
* (KOGNAI_ROOT / cwd) instead of `join(__dirname, '../..')`, so the module is
|
|
14
|
+
* location-independent and can live in @kognai/orchestrator-core. When run from a
|
|
15
|
+
* product repo root, resolveEnginePaths().root === the old __dirname/../.. — same
|
|
16
|
+
* <root>/acp/trust-scores.json path, no behavior change.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Update trust scores after a task outcome.
|
|
20
|
+
* @param agentId - The agent whose scores to update
|
|
21
|
+
* @param outcome - 'approved' or 'rejected'
|
|
22
|
+
* @param taskScore - The supervisor score (0-100)
|
|
23
|
+
* @param safetyFlag - Whether a safety issue was flagged
|
|
24
|
+
*/
|
|
25
|
+
export declare function updateTrustScore(agentId: string, outcome: 'approved' | 'rejected', taskScore: number, safetyFlag?: boolean): void;
|
|
26
|
+
/**
|
|
27
|
+
* Apply daily decay: stale agents drift 5% toward mean (70) per day.
|
|
28
|
+
* Run once per day (e.g., in daily-digest or a cron).
|
|
29
|
+
*/
|
|
30
|
+
export declare function applyDailyDecay(): void;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* trust-score-updater.ts — Sprint 703 (GOV Phase 1)
|
|
4
|
+
*
|
|
5
|
+
* Dynamic ACP trust score updater. Adjusts scores based on real outcomes:
|
|
6
|
+
* - Approved tasks (score >= 80): accuracy +1
|
|
7
|
+
* - Rejected tasks: accuracy -2
|
|
8
|
+
* - Safety flags: safety -3
|
|
9
|
+
* - 5% daily decay toward 70 (mean) for stale agents
|
|
10
|
+
*
|
|
11
|
+
* Called by orchestrate-agents-v2.ts on both approval and rejection paths.
|
|
12
|
+
*
|
|
13
|
+
* TICKET-215 Phase 3b-2: the repo root now resolves via engine-paths
|
|
14
|
+
* (KOGNAI_ROOT / cwd) instead of `join(__dirname, '../..')`, so the module is
|
|
15
|
+
* location-independent and can live in @kognai/orchestrator-core. When run from a
|
|
16
|
+
* product repo root, resolveEnginePaths().root === the old __dirname/../.. — same
|
|
17
|
+
* <root>/acp/trust-scores.json path, no behavior change.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.updateTrustScore = updateTrustScore;
|
|
21
|
+
exports.applyDailyDecay = applyDailyDecay;
|
|
22
|
+
const fs_1 = require("fs");
|
|
23
|
+
const path_1 = require("path");
|
|
24
|
+
const engine_paths_1 = require("./engine-paths");
|
|
25
|
+
const ROOT = (0, engine_paths_1.resolveEnginePaths)().root;
|
|
26
|
+
const TRUST_PATH = (0, path_1.join)(ROOT, 'acp', 'trust-scores.json');
|
|
27
|
+
function clamp(val, min, max) {
|
|
28
|
+
return Math.max(min, Math.min(max, val));
|
|
29
|
+
}
|
|
30
|
+
function recomputeComposite(scores, dims) {
|
|
31
|
+
let weighted = 0;
|
|
32
|
+
let totalWeight = 0;
|
|
33
|
+
for (const [dim, config] of Object.entries(dims)) {
|
|
34
|
+
const val = scores[dim];
|
|
35
|
+
if (typeof val === 'number') {
|
|
36
|
+
weighted += val * config.weight;
|
|
37
|
+
totalWeight += config.weight;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return totalWeight > 0 ? Math.round(weighted / totalWeight) : 0;
|
|
41
|
+
}
|
|
42
|
+
function loadTrustData() {
|
|
43
|
+
return JSON.parse((0, fs_1.readFileSync)(TRUST_PATH, 'utf-8'));
|
|
44
|
+
}
|
|
45
|
+
function saveTrustData(data) {
|
|
46
|
+
data.updated = new Date().toISOString().slice(0, 10);
|
|
47
|
+
(0, fs_1.writeFileSync)(TRUST_PATH, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Update trust scores after a task outcome.
|
|
51
|
+
* @param agentId - The agent whose scores to update
|
|
52
|
+
* @param outcome - 'approved' or 'rejected'
|
|
53
|
+
* @param taskScore - The supervisor score (0-100)
|
|
54
|
+
* @param safetyFlag - Whether a safety issue was flagged
|
|
55
|
+
*/
|
|
56
|
+
function updateTrustScore(agentId, outcome, taskScore, safetyFlag = false) {
|
|
57
|
+
try {
|
|
58
|
+
const data = loadTrustData();
|
|
59
|
+
const scores = data.scores[agentId];
|
|
60
|
+
if (!scores) {
|
|
61
|
+
console.warn(`[trust-updater] Agent '${agentId}' not in trust-scores.json — skipping`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (outcome === 'approved' && taskScore >= 80) {
|
|
65
|
+
scores.accuracy = clamp(scores.accuracy + 1, 0, 100);
|
|
66
|
+
}
|
|
67
|
+
else if (outcome === 'rejected') {
|
|
68
|
+
scores.accuracy = clamp(scores.accuracy - 2, 0, 100);
|
|
69
|
+
}
|
|
70
|
+
if (safetyFlag) {
|
|
71
|
+
scores.safety = clamp(scores.safety - 3, 0, 100);
|
|
72
|
+
}
|
|
73
|
+
scores.composite = recomputeComposite(scores, data.dimensions);
|
|
74
|
+
scores.last_updated = new Date().toISOString().slice(0, 10);
|
|
75
|
+
saveTrustData(data);
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
// Non-fatal — trust score update failure should never block execution
|
|
79
|
+
console.warn(`[trust-updater] Failed to update scores: ${err.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Apply daily decay: stale agents drift 5% toward mean (70) per day.
|
|
84
|
+
* Run once per day (e.g., in daily-digest or a cron).
|
|
85
|
+
*/
|
|
86
|
+
function applyDailyDecay() {
|
|
87
|
+
try {
|
|
88
|
+
const data = loadTrustData();
|
|
89
|
+
const MEAN = 70;
|
|
90
|
+
const DECAY_RATE = 0.05;
|
|
91
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
92
|
+
for (const [agentId, scores] of Object.entries(data.scores)) {
|
|
93
|
+
if (scores.last_updated === today)
|
|
94
|
+
continue; // Active today, skip
|
|
95
|
+
for (const dim of ['safety', 'accuracy', 'brand_alignment', 'cultural_sensitivity', 'legal_compliance']) {
|
|
96
|
+
const current = scores[dim];
|
|
97
|
+
const diff = current - MEAN;
|
|
98
|
+
scores[dim] = Math.round(current - diff * DECAY_RATE);
|
|
99
|
+
}
|
|
100
|
+
scores.composite = recomputeComposite(scores, data.dimensions);
|
|
101
|
+
}
|
|
102
|
+
saveTrustData(data);
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
console.warn(`[trust-updater] Daily decay failed: ${err.message}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wallet-state.ts — CFO budget tracking for ClawRouter spend
|
|
3
|
+
*
|
|
4
|
+
* Accumulates spend from ClawRouter X-Payment-Amount headers.
|
|
5
|
+
* Enforces degraded (≥80%) and frozen (≥95%) modes to protect the wallet.
|
|
6
|
+
* Persists to logs/wallet/state.json across sprint runs.
|
|
7
|
+
*
|
|
8
|
+
* TICKET-215 Phase 3b-3 (Wave B): KOGNAI_ROOT now resolves via engine-paths
|
|
9
|
+
* (KOGNAI_ROOT / cwd) instead of `resolve(__dirname, '../..')`, so the bank
|
|
10
|
+
* state layer is location-independent and ships in @kognai/orchestrator-core.
|
|
11
|
+
* When run from a product repo root, resolveEnginePaths().root === the old
|
|
12
|
+
* __dirname/../.. — same <root>/logs/wallet/state.json, no behavior change.
|
|
13
|
+
*/
|
|
14
|
+
export interface WalletState {
|
|
15
|
+
monthlyBudget: number;
|
|
16
|
+
spentThisMonth: number;
|
|
17
|
+
callCount: number;
|
|
18
|
+
remaining: number;
|
|
19
|
+
burnPct: number;
|
|
20
|
+
isDegraded: boolean;
|
|
21
|
+
isFrozen: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function getWalletState(): WalletState;
|
|
24
|
+
export declare function recordSpend(costUsdc: number): void;
|
|
25
|
+
export declare function resetWallet(): void;
|
|
26
|
+
export declare function logWalletStatus(): void;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* wallet-state.ts — CFO budget tracking for ClawRouter spend
|
|
4
|
+
*
|
|
5
|
+
* Accumulates spend from ClawRouter X-Payment-Amount headers.
|
|
6
|
+
* Enforces degraded (≥80%) and frozen (≥95%) modes to protect the wallet.
|
|
7
|
+
* Persists to logs/wallet/state.json across sprint runs.
|
|
8
|
+
*
|
|
9
|
+
* TICKET-215 Phase 3b-3 (Wave B): KOGNAI_ROOT now resolves via engine-paths
|
|
10
|
+
* (KOGNAI_ROOT / cwd) instead of `resolve(__dirname, '../..')`, so the bank
|
|
11
|
+
* state layer is location-independent and ships in @kognai/orchestrator-core.
|
|
12
|
+
* When run from a product repo root, resolveEnginePaths().root === the old
|
|
13
|
+
* __dirname/../.. — same <root>/logs/wallet/state.json, no behavior change.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.getWalletState = getWalletState;
|
|
17
|
+
exports.recordSpend = recordSpend;
|
|
18
|
+
exports.resetWallet = resetWallet;
|
|
19
|
+
exports.logWalletStatus = logWalletStatus;
|
|
20
|
+
const fs_1 = require("fs");
|
|
21
|
+
const path_1 = require("path");
|
|
22
|
+
const engine_paths_1 = require("./engine-paths");
|
|
23
|
+
const KOGNAI_ROOT = (0, engine_paths_1.resolveEnginePaths)().root;
|
|
24
|
+
const STATE_FILE = (0, path_1.resolve)(KOGNAI_ROOT, 'logs/wallet/state.json');
|
|
25
|
+
const DEFAULT_BUDGET = parseFloat(process.env.CEO_WALLET_BUDGET_USDC || '25'); // $25/month default
|
|
26
|
+
function loadState() {
|
|
27
|
+
if ((0, fs_1.existsSync)(STATE_FILE)) {
|
|
28
|
+
try {
|
|
29
|
+
const raw = JSON.parse((0, fs_1.readFileSync)(STATE_FILE, 'utf8'));
|
|
30
|
+
// Auto-reset on new month
|
|
31
|
+
const lastReset = new Date(raw.lastReset);
|
|
32
|
+
const now = new Date();
|
|
33
|
+
if (lastReset.getMonth() !== now.getMonth() || lastReset.getFullYear() !== now.getFullYear()) {
|
|
34
|
+
return freshState();
|
|
35
|
+
}
|
|
36
|
+
return raw;
|
|
37
|
+
}
|
|
38
|
+
catch { /* fall through */ }
|
|
39
|
+
}
|
|
40
|
+
return freshState();
|
|
41
|
+
}
|
|
42
|
+
function freshState() {
|
|
43
|
+
return {
|
|
44
|
+
monthlyBudget: DEFAULT_BUDGET,
|
|
45
|
+
spentThisMonth: 0,
|
|
46
|
+
callCount: 0,
|
|
47
|
+
lastReset: new Date().toISOString(),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function saveState(data) {
|
|
51
|
+
try {
|
|
52
|
+
(0, fs_1.mkdirSync)((0, path_1.resolve)(KOGNAI_ROOT, 'logs/wallet'), { recursive: true });
|
|
53
|
+
(0, fs_1.writeFileSync)(STATE_FILE, JSON.stringify(data, null, 2), 'utf8');
|
|
54
|
+
}
|
|
55
|
+
catch { /* non-fatal */ }
|
|
56
|
+
}
|
|
57
|
+
// Singleton
|
|
58
|
+
let _state = loadState();
|
|
59
|
+
function getWalletState() {
|
|
60
|
+
const remaining = Math.max(0, _state.monthlyBudget - _state.spentThisMonth);
|
|
61
|
+
const burnPct = (_state.spentThisMonth / _state.monthlyBudget) * 100;
|
|
62
|
+
return {
|
|
63
|
+
monthlyBudget: _state.monthlyBudget,
|
|
64
|
+
spentThisMonth: _state.spentThisMonth,
|
|
65
|
+
callCount: _state.callCount,
|
|
66
|
+
remaining,
|
|
67
|
+
burnPct,
|
|
68
|
+
isDegraded: burnPct >= 80,
|
|
69
|
+
isFrozen: burnPct >= 95,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function recordSpend(costUsdc) {
|
|
73
|
+
_state.spentThisMonth += costUsdc;
|
|
74
|
+
_state.callCount += 1;
|
|
75
|
+
saveState(_state);
|
|
76
|
+
}
|
|
77
|
+
function resetWallet() {
|
|
78
|
+
_state = freshState();
|
|
79
|
+
saveState(_state);
|
|
80
|
+
}
|
|
81
|
+
function logWalletStatus() {
|
|
82
|
+
const s = getWalletState();
|
|
83
|
+
const status = s.isFrozen ? '🔴 FROZEN' : s.isDegraded ? '🟡 DEGRADED' : '🟢 OK';
|
|
84
|
+
console.log(` 💳 Wallet ${status}: $${s.spentThisMonth.toFixed(4)}/$${s.monthlyBudget} (${s.burnPct.toFixed(1)}%)`);
|
|
85
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kognai/orchestrator-core",
|
|
3
|
+
"version": "0.1.0",
|
|
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
|
+
"license": "MIT",
|
|
6
|
+
"author": "SkinGem",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.json",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"kognai",
|
|
22
|
+
"orchestrator",
|
|
23
|
+
"agent-swarm",
|
|
24
|
+
"core-engine"
|
|
25
|
+
],
|
|
26
|
+
"dependencies": {}
|
|
27
|
+
}
|