0xray 3.4.8 → 3.4.9
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/AGENTS-consumer.md +1 -1
- package/AGENTS.md +1 -1
- package/README.md +15 -1
- package/SKILLS.md +1 -1
- package/dist/AGENTS.md +1 -1
- package/dist/CHANGELOG.md +16 -0
- package/dist/README.md +15 -1
- package/dist/SKILLS.md +1 -1
- package/dist/governance/llm-governance-provider.d.ts +2 -0
- package/dist/governance/llm-governance-provider.js +144 -158
- package/dist/mcps/knowledge-skills/code-review.server.js +1 -1
- package/dist/mcps/knowledge-skills/security-audit.server.js +1 -1
- package/dist/mcps/orchestrator/config/memory-routing-bridge.js +2 -1
- package/dist/mcps/orchestrator/execution/execution-planner.d.ts +2 -0
- package/dist/mcps/orchestrator/execution/execution-planner.js +22 -11
- package/dist/mcps/orchestrator/handlers/complexity-handler.d.ts +13 -1
- package/dist/mcps/orchestrator/handlers/complexity-handler.js +40 -4
- package/dist/mcps/orchestrator/handlers/task-handler.js +13 -6
- package/dist/mcps/orchestrator/server.js +9 -1
- package/dist/mcps/orchestrator/types.d.ts +4 -1
- package/dist/mcps/researcher.server.js +1 -1
- package/dist/nucleus/autonomy-kernel.d.ts +5 -1
- package/dist/nucleus/autonomy-kernel.js +20 -16
- package/dist/skills/orchestrator/SKILL.md +3 -2
- package/package.json +1 -1
- package/src/mcps/knowledge-skills/code-review.server.ts +1 -1
- package/src/mcps/knowledge-skills/security-audit.server.ts +1 -1
- package/src/mcps/orchestrator/config/memory-routing-bridge.ts +3 -1
- package/src/mcps/orchestrator/execution/execution-planner.ts +26 -11
- package/src/mcps/orchestrator/handlers/complexity-handler.ts +62 -5
- package/src/mcps/orchestrator/handlers/task-handler.ts +22 -6
- package/src/mcps/orchestrator/server.ts +9 -1
- package/src/mcps/orchestrator/types.ts +4 -1
- package/src/mcps/researcher.server.ts +1 -1
- package/src/skills/orchestrator/SKILL.md +3 -2
package/AGENTS-consumer.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Quick reference for the 0xRay AI orchestration framework (shipped to your project on `npm install 0xray`).
|
|
6
6
|
|
|
7
|
-
**v3.4.
|
|
7
|
+
**v3.4.9** — 7 MCP servers · 45 skills · 68 codex terms · 4 platform bridges
|
|
8
8
|
|
|
9
9
|
## Postinstall (automatic)
|
|
10
10
|
|
package/AGENTS.md
CHANGED
package/README.md
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# xray — MCP-Centric AI Governance OS
|
|
2
2
|
|
|
3
|
-
**v3.4.
|
|
3
|
+
**v3.4.9** — 42 agents · 45 skills · 7 MCP servers · 68 codex terms · 3,226 tests
|
|
4
|
+
|
|
5
|
+
## Your AI Power Suit
|
|
6
|
+
|
|
7
|
+
**Your AI Power ⚡️ Suit 🦾** — an exoskeleton that blocks AI slop from becoming real damage.
|
|
8
|
+
|
|
9
|
+
- learns with **Repertoire** 🧠
|
|
10
|
+
- has a **Solar Ban Hammer** ☀️🔨 (Dynamo governance)
|
|
11
|
+
- can also **Confer** 🗣️ (3-agent internal deliberation)
|
|
12
|
+
|
|
13
|
+
The core AI Governance OS stack is **complete and open source**. A commercial version is next — powers up the suit further.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install 0xray@latest
|
|
17
|
+
```
|
|
4
18
|
|
|
5
19
|
xray is the pure v2 three-subsystem AI orchestration framework — **MCP-centric**, governed by Dynamo, and autonomous via thinDispatch. Consumer `npm install 0xray` auto-wires all four platform bridges and seven MCP servers with zero manual config.
|
|
6
20
|
|
package/SKILLS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 0xray Skills
|
|
2
2
|
|
|
3
|
-
**v3.4.
|
|
3
|
+
**v3.4.9** — **45 skills** · invoked via `xray-skills` MCP · synced on postinstall
|
|
4
4
|
|
|
5
5
|
xray ships 45 knowledge skills (`src/skills/<name>/SKILL.md`) across the full software lifecycle. Lead-dev operating model lives in **`orchestrator`** skill + `multi_agent_orchestration.lead_dev_mode` in features.json. Skills load on demand via the **xray-skills** MCP server (`npx -y 0xray mcp skills`), agent `@mentions`, or platform skill directories after postinstall.
|
|
6
6
|
|
package/dist/AGENTS.md
CHANGED
package/dist/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Conventional Commits](https://www.conventionalcommits.org/).
|
|
6
6
|
|
|
7
|
+
## [3.4.9] - 2026-06-19
|
|
8
|
+
|
|
9
|
+
### ⚠️ Breaking Changes
|
|
10
|
+
- **`orchestrate-task`** — returns `success: false` when implementation agents (backend-engineer, frontend-engineer, bug-triage, etc.) are **deferred**. Only MCP consult skills execute in-process. Callers must not treat a completed response as work done; delegate via host `Task` / `spawn_subagent` per lead-dev-plan.
|
|
11
|
+
|
|
12
|
+
### 🐛 Bug Fixes
|
|
13
|
+
- **Orchestrator honesty** — no fake-complete for implementation agents; `delegate-deferred` + `lead-dev-plan-persisted` logged to `activity.log`
|
|
14
|
+
- **`analyze-complexity` NaN** — `dependencyCount` + `dependencies[]` schema; numeric dependency hints no longer produce NaN scores
|
|
15
|
+
- **Lead-dev plan** — `buildLeadDevPlan` uses per-task inputs; multi-task intake forces phased plan (not collapsed "Direct execution")
|
|
16
|
+
- **Hermes governance voters** — route through `hermes -z` CLI (same path as groover `hermes-runner`); honor `HERMES_BIN`, `HERMES_HOME`
|
|
17
|
+
|
|
18
|
+
### ✅ Tests
|
|
19
|
+
- Unit coverage: `execution-planner-dependencies`, deferred task-handler, per-task lead-dev todos
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
7
23
|
## [3.4.8] - 2026-06-19
|
|
8
24
|
|
|
9
25
|
### 🐛 Bug Fixes
|
package/dist/README.md
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# xray — MCP-Centric AI Governance OS
|
|
2
2
|
|
|
3
|
-
**v3.4.
|
|
3
|
+
**v3.4.9** — 42 agents · 45 skills · 7 MCP servers · 68 codex terms · 3,226 tests
|
|
4
|
+
|
|
5
|
+
## Your AI Power Suit
|
|
6
|
+
|
|
7
|
+
**Your AI Power ⚡️ Suit 🦾** — an exoskeleton that blocks AI slop from becoming real damage.
|
|
8
|
+
|
|
9
|
+
- learns with **Repertoire** 🧠
|
|
10
|
+
- has a **Solar Ban Hammer** ☀️🔨 (Dynamo governance)
|
|
11
|
+
- can also **Confer** 🗣️ (3-agent internal deliberation)
|
|
12
|
+
|
|
13
|
+
The core AI Governance OS stack is **complete and open source**. A commercial version is next — powers up the suit further.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install 0xray@latest
|
|
17
|
+
```
|
|
4
18
|
|
|
5
19
|
xray is the pure v2 three-subsystem AI orchestration framework — **MCP-centric**, governed by Dynamo, and autonomous via thinDispatch. Consumer `npm install 0xray` auto-wires all four platform bridges and seven MCP servers with zero manual config.
|
|
6
20
|
|
package/dist/SKILLS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 0xray Skills
|
|
2
2
|
|
|
3
|
-
**v3.4.
|
|
3
|
+
**v3.4.9** — **45 skills** · invoked via `xray-skills` MCP · synced on postinstall
|
|
4
4
|
|
|
5
5
|
xray ships 45 knowledge skills (`src/skills/<name>/SKILL.md`) across the full software lifecycle. Lead-dev operating model lives in **`orchestrator`** skill + `multi_agent_orchestration.lead_dev_mode` in features.json. Skills load on demand via the **xray-skills** MCP server (`npx -y 0xray mcp skills`), agent `@mentions`, or platform skill directories after postinstall.
|
|
6
6
|
|
|
@@ -4,6 +4,8 @@ export interface GovernanceVote {
|
|
|
4
4
|
confidence: number;
|
|
5
5
|
reasoning: string;
|
|
6
6
|
}
|
|
7
|
+
export declare function resolveHermesBin(): string;
|
|
8
|
+
export declare function hermesCliAvailable(): boolean;
|
|
7
9
|
export declare function tryLLMGovernance(role: GovernanceRole, proposalTitle: string, proposalDescription: string, evidence: string[], proposalType: string): Promise<GovernanceVote | null>;
|
|
8
10
|
export declare function checkHermesOAuthStatus(): {
|
|
9
11
|
configured: boolean;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
4
2
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
5
|
-
const
|
|
6
|
-
const
|
|
3
|
+
const DEFAULT_HERMES_PROVIDER = "xai-oauth";
|
|
4
|
+
const DEFAULT_HERMES_MODEL = "grok-4.3";
|
|
5
|
+
const DEFAULT_HERMES_TIMEOUT_MS = 120_000;
|
|
7
6
|
const ROLE_PROMPTS = {
|
|
8
7
|
"code-review": `You are a senior code reviewer on a governance committee for a software project. Analyze the following proposal from a code quality, maintainability, readability, and engineering best practices perspective.
|
|
9
8
|
|
|
@@ -42,125 +41,97 @@ DECISION: approve|reject|abstain
|
|
|
42
41
|
CONFIDENCE: <0.0-1.0>
|
|
43
42
|
REASONING: <2-4 sentence analysis of the proposal's broader project impact>`,
|
|
44
43
|
};
|
|
45
|
-
function
|
|
46
|
-
|
|
47
|
-
return provider.expires_at;
|
|
48
|
-
const expiresIn = tokens?.expires_in ?? provider.expires_in;
|
|
49
|
-
if (typeof expiresIn !== "number")
|
|
50
|
-
return undefined;
|
|
51
|
-
const refreshCandidates = [provider.last_refresh, tokens?.last_refresh];
|
|
52
|
-
for (const lastRefresh of refreshCandidates) {
|
|
53
|
-
if (typeof lastRefresh !== "string")
|
|
54
|
-
continue;
|
|
55
|
-
const base = Date.parse(lastRefresh);
|
|
56
|
-
if (!Number.isNaN(base)) {
|
|
57
|
-
return Math.floor((base + expiresIn * 1000) / 1000);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return undefined;
|
|
44
|
+
function resolveHermesProvider() {
|
|
45
|
+
return process.env.HERMES_PROVIDER?.trim() || DEFAULT_HERMES_PROVIDER;
|
|
61
46
|
}
|
|
62
|
-
function
|
|
63
|
-
|
|
64
|
-
return undefined;
|
|
65
|
-
if (Array.isArray(data)) {
|
|
66
|
-
return data.find((e) => e.provider === "xai-oauth" || !!e.access_token);
|
|
67
|
-
}
|
|
68
|
-
const record = data;
|
|
69
|
-
const legacy = record["xai-oauth"];
|
|
70
|
-
if (legacy && typeof legacy === "object") {
|
|
71
|
-
const entry = legacy;
|
|
72
|
-
if (entry.access_token)
|
|
73
|
-
return entry;
|
|
74
|
-
}
|
|
75
|
-
if (typeof record.access_token === "string") {
|
|
76
|
-
return record;
|
|
77
|
-
}
|
|
78
|
-
for (const bucket of ["providers", "credential_pool"]) {
|
|
79
|
-
const pool = record[bucket];
|
|
80
|
-
if (!pool || typeof pool !== "object")
|
|
81
|
-
continue;
|
|
82
|
-
const provider = pool["xai-oauth"];
|
|
83
|
-
if (!provider || typeof provider !== "object")
|
|
84
|
-
continue;
|
|
85
|
-
const prov = provider;
|
|
86
|
-
const tokens = prov.tokens && typeof prov.tokens === "object"
|
|
87
|
-
? prov.tokens
|
|
88
|
-
: undefined;
|
|
89
|
-
if (tokens && typeof tokens.access_token === "string") {
|
|
90
|
-
const entry = {
|
|
91
|
-
access_token: tokens.access_token,
|
|
92
|
-
provider: "xai-oauth",
|
|
93
|
-
};
|
|
94
|
-
if (typeof tokens.refresh_token === "string") {
|
|
95
|
-
entry.refresh_token = tokens.refresh_token;
|
|
96
|
-
}
|
|
97
|
-
const expiresAt = resolveHermesExpiresAt(prov, tokens);
|
|
98
|
-
if (expiresAt !== undefined)
|
|
99
|
-
entry.expires_at = expiresAt;
|
|
100
|
-
if (typeof tokens.token_type === "string")
|
|
101
|
-
entry.token_type = tokens.token_type;
|
|
102
|
-
return entry;
|
|
103
|
-
}
|
|
104
|
-
if (typeof prov.access_token === "string") {
|
|
105
|
-
return prov;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return undefined;
|
|
47
|
+
function resolveHermesModel() {
|
|
48
|
+
return process.env.HERMES_MODEL?.trim() || DEFAULT_HERMES_MODEL;
|
|
109
49
|
}
|
|
110
|
-
function
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const data = JSON.parse(raw);
|
|
117
|
-
const entry = extractHermesOAuthEntry(data);
|
|
118
|
-
if (!entry?.access_token) {
|
|
119
|
-
process.stderr.write("[llm] readHermesOAuthToken: no access_token in auth file\n");
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
if (entry.expires_at && Date.now() / 1000 > entry.expires_at) {
|
|
123
|
-
frameworkLogger.log("llm-governance", "hermes-token-expired", "warning", { expiresAt: entry.expires_at });
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
|
-
return entry.access_token;
|
|
127
|
-
}
|
|
128
|
-
catch (err) {
|
|
129
|
-
frameworkLogger.log("llm-governance", "hermes-auth-read-error", "warning", { error: String(err) });
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
50
|
+
function resolveHermesTimeoutMs() {
|
|
51
|
+
const raw = process.env.HERMES_TIMEOUT_MS?.trim();
|
|
52
|
+
if (!raw)
|
|
53
|
+
return DEFAULT_HERMES_TIMEOUT_MS;
|
|
54
|
+
const parsed = Number(raw);
|
|
55
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_HERMES_TIMEOUT_MS;
|
|
132
56
|
}
|
|
133
|
-
function
|
|
134
|
-
const
|
|
57
|
+
export function resolveHermesBin() {
|
|
58
|
+
const explicit = process.env.HERMES_BIN?.trim();
|
|
59
|
+
if (explicit)
|
|
60
|
+
return explicit;
|
|
61
|
+
return "hermes";
|
|
62
|
+
}
|
|
63
|
+
function getDirectLlmConfig() {
|
|
64
|
+
const endpoint = process.env.XRAY_LLM_ENDPOINT ||
|
|
135
65
|
process.env.XRAY_GOVERNANCE_LLM_ENDPOINT ||
|
|
136
66
|
"";
|
|
137
|
-
const
|
|
67
|
+
const apiKey = process.env.XRAY_LLM_API_KEY ||
|
|
138
68
|
process.env.XRAY_GOVERNANCE_LLM_API_KEY ||
|
|
139
69
|
"";
|
|
140
|
-
const
|
|
70
|
+
const model = process.env.XRAY_LLM_MODEL ||
|
|
141
71
|
process.env.XRAY_GOVERNANCE_LLM_MODEL ||
|
|
142
72
|
"gpt-4o";
|
|
143
|
-
// First try: direct env-var config (highest priority)
|
|
144
73
|
const directEnabled = process.env.XRAY_GOVERNANCE_LLM_ENABLED === "true" ||
|
|
145
74
|
process.env.XRAY_LLM_ENABLED === "true";
|
|
146
|
-
if (directEnabled &&
|
|
147
|
-
return {
|
|
148
|
-
}
|
|
149
|
-
// Second try: Hermes xAI OAuth token from ~/.hermes/auth.json
|
|
150
|
-
const hermesToken = readHermesOAuthToken();
|
|
151
|
-
if (hermesToken) {
|
|
152
|
-
frameworkLogger.log("llm-governance", "using-hermes-oauth", "info", { provider: "xai-oauth", endpoint: XAI_ENDPOINT, model: XAI_MODEL });
|
|
153
|
-
return { endpoint: XAI_ENDPOINT, apiKey: hermesToken, model: XAI_MODEL };
|
|
75
|
+
if (directEnabled && endpoint && apiKey) {
|
|
76
|
+
return { mode: "direct", endpoint, apiKey, model };
|
|
154
77
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return { endpoint: directEndpoint, apiKey: directApiKey, model: directModel };
|
|
78
|
+
if (endpoint && apiKey) {
|
|
79
|
+
return { mode: "direct", endpoint, apiKey, model };
|
|
158
80
|
}
|
|
159
|
-
|
|
160
|
-
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
function getConfig() {
|
|
84
|
+
const direct = getDirectLlmConfig();
|
|
85
|
+
if (direct)
|
|
86
|
+
return direct;
|
|
87
|
+
if (hermesCliAvailable()) {
|
|
88
|
+
return {
|
|
89
|
+
mode: "hermes",
|
|
90
|
+
provider: resolveHermesProvider(),
|
|
91
|
+
model: resolveHermesModel(),
|
|
92
|
+
timeoutMs: resolveHermesTimeoutMs(),
|
|
93
|
+
};
|
|
161
94
|
}
|
|
162
95
|
return null;
|
|
163
96
|
}
|
|
97
|
+
export function hermesCliAvailable() {
|
|
98
|
+
try {
|
|
99
|
+
execFileSync(resolveHermesBin(), ["--version"], {
|
|
100
|
+
encoding: "utf8",
|
|
101
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
102
|
+
timeout: 5_000,
|
|
103
|
+
});
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function buildGovernancePrompt(role, proposalTitle, proposalDescription, evidence, proposalType) {
|
|
111
|
+
const evidenceBlock = evidence.length > 0
|
|
112
|
+
? `**Supporting Evidence:**\n${evidence.map((entry, index) => `${index + 1}. ${entry}`).join("\n")}\n\n`
|
|
113
|
+
: "";
|
|
114
|
+
return `${ROLE_PROMPTS[role]}
|
|
115
|
+
|
|
116
|
+
## Proposal
|
|
117
|
+
|
|
118
|
+
**Title:** ${proposalTitle}
|
|
119
|
+
|
|
120
|
+
**Description:** ${proposalDescription}
|
|
121
|
+
|
|
122
|
+
**Type:** ${proposalType}
|
|
123
|
+
|
|
124
|
+
${evidenceBlock}---
|
|
125
|
+
|
|
126
|
+
Please provide your structured vote.`;
|
|
127
|
+
}
|
|
128
|
+
function runHermesGovernanceInference(prompt, config) {
|
|
129
|
+
return execFileSync(resolveHermesBin(), ["-z", prompt, "--provider", config.provider, "--model", config.model], {
|
|
130
|
+
encoding: "utf8",
|
|
131
|
+
timeout: config.timeoutMs,
|
|
132
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
133
|
+
}).trim();
|
|
134
|
+
}
|
|
164
135
|
function parseVote(text) {
|
|
165
136
|
const decisionMatch = text.match(/DECISION:\s*(approve|reject|abstain)/i);
|
|
166
137
|
const confidenceMatch = text.match(/CONFIDENCE:\s*([0-9.]+)/i);
|
|
@@ -175,13 +146,7 @@ function parseVote(text) {
|
|
|
175
146
|
reasoning: reasoningMatch?.[1]?.trim() || "No reasoning provided",
|
|
176
147
|
};
|
|
177
148
|
}
|
|
178
|
-
|
|
179
|
-
const config = getConfig();
|
|
180
|
-
if (!config) {
|
|
181
|
-
process.stderr.write("[llm] no config for role=" + role + "\n");
|
|
182
|
-
return null;
|
|
183
|
-
}
|
|
184
|
-
process.stderr.write("[llm] using config endpoint=" + config.endpoint + " model=" + config.model + "\n");
|
|
149
|
+
async function callDirectLlm(role, config, proposalTitle, proposalDescription, evidence, proposalType) {
|
|
185
150
|
const systemPrompt = ROLE_PROMPTS[role];
|
|
186
151
|
const userMessage = `## Proposal
|
|
187
152
|
|
|
@@ -191,40 +156,61 @@ export async function tryLLMGovernance(role, proposalTitle, proposalDescription,
|
|
|
191
156
|
|
|
192
157
|
**Type:** ${proposalType}
|
|
193
158
|
|
|
194
|
-
${evidence.length > 0 ? `**Supporting Evidence:**\n${evidence.map((
|
|
159
|
+
${evidence.length > 0 ? `**Supporting Evidence:**\n${evidence.map((entry, index) => `${index + 1}. ${entry}`).join("\n")}` : ""}
|
|
195
160
|
|
|
196
161
|
---
|
|
197
162
|
|
|
198
163
|
Please provide your structured vote.`;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
164
|
+
const response = await fetch(config.endpoint, {
|
|
165
|
+
method: "POST",
|
|
166
|
+
headers: {
|
|
167
|
+
"Content-Type": "application/json",
|
|
168
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
169
|
+
},
|
|
170
|
+
body: JSON.stringify({
|
|
171
|
+
model: config.model,
|
|
172
|
+
messages: [
|
|
173
|
+
{ role: "system", content: systemPrompt },
|
|
174
|
+
{ role: "user", content: userMessage },
|
|
175
|
+
],
|
|
176
|
+
temperature: 0.3,
|
|
177
|
+
max_tokens: 500,
|
|
178
|
+
}),
|
|
179
|
+
});
|
|
180
|
+
if (!response.ok) {
|
|
181
|
+
frameworkLogger.log("llm-governance", "api-call", "error", {
|
|
182
|
+
status: response.status,
|
|
183
|
+
statusText: response.statusText,
|
|
184
|
+
role,
|
|
215
185
|
});
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
const data = (await response.json());
|
|
189
|
+
const choices = data?.choices;
|
|
190
|
+
const message = choices?.[0]?.message;
|
|
191
|
+
return message?.content ?? null;
|
|
192
|
+
}
|
|
193
|
+
export async function tryLLMGovernance(role, proposalTitle, proposalDescription, evidence, proposalType) {
|
|
194
|
+
const config = getConfig();
|
|
195
|
+
if (!config) {
|
|
196
|
+
process.stderr.write(`[llm] no config for role=${role}\n`);
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
if (config.mode === "hermes") {
|
|
200
|
+
process.stderr.write(`[llm] using hermes -z provider=${config.provider} model=${config.model}\n`);
|
|
201
|
+
frameworkLogger.log("llm-governance", "using-hermes-cli", "info", {
|
|
202
|
+
provider: config.provider,
|
|
203
|
+
model: config.model,
|
|
204
|
+
role,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
process.stderr.write(`[llm] using direct endpoint=${config.endpoint} model=${config.model}\n`);
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
const content = config.mode === "hermes"
|
|
212
|
+
? runHermesGovernanceInference(buildGovernancePrompt(role, proposalTitle, proposalDescription, evidence, proposalType), config)
|
|
213
|
+
: await callDirectLlm(role, config, proposalTitle, proposalDescription, evidence, proposalType);
|
|
228
214
|
if (!content) {
|
|
229
215
|
frameworkLogger.log("llm-governance", "parse", "warning", {
|
|
230
216
|
issue: "missing content in response",
|
|
@@ -257,23 +243,23 @@ Please provide your structured vote.`;
|
|
|
257
243
|
}
|
|
258
244
|
}
|
|
259
245
|
export function checkHermesOAuthStatus() {
|
|
260
|
-
const
|
|
261
|
-
if (
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
246
|
+
const direct = getDirectLlmConfig();
|
|
247
|
+
if (direct) {
|
|
248
|
+
return {
|
|
249
|
+
configured: true,
|
|
250
|
+
endpoint: direct.endpoint,
|
|
251
|
+
model: direct.model,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
if (hermesCliAvailable()) {
|
|
269
255
|
return {
|
|
270
|
-
configured:
|
|
271
|
-
|
|
256
|
+
configured: true,
|
|
257
|
+
endpoint: "hermes-cli",
|
|
258
|
+
model: resolveHermesModel(),
|
|
272
259
|
};
|
|
273
260
|
}
|
|
274
261
|
return {
|
|
275
|
-
configured:
|
|
276
|
-
|
|
277
|
-
model: XAI_MODEL,
|
|
262
|
+
configured: false,
|
|
263
|
+
error: "Hermes CLI not found on PATH. Install Hermes and ensure xai-oauth is configured (same path as gateway/cron: hermes auth add xai-oauth).",
|
|
278
264
|
};
|
|
279
265
|
}
|
|
@@ -321,7 +321,7 @@ class XrayCodeReviewServer extends XrayKnowledgeSkillBase {
|
|
|
321
321
|
content: [
|
|
322
322
|
{
|
|
323
323
|
type: "text",
|
|
324
|
-
text: "DECISION: abstain\nCONFIDENCE: 0.50\nREASONING: No LLM governance provider configured.
|
|
324
|
+
text: "DECISION: abstain\nCONFIDENCE: 0.50\nREASONING: No LLM governance provider configured. Install Hermes on PATH (hermes -z) with xai-oauth, or set XRAY_GOVERNANCE_LLM_ENABLED=true + XRAY_LLM_ENDPOINT.",
|
|
325
325
|
},
|
|
326
326
|
],
|
|
327
327
|
};
|
|
@@ -666,7 +666,7 @@ class XraySecurityAuditServer extends XrayKnowledgeSkillBase {
|
|
|
666
666
|
content: [
|
|
667
667
|
{
|
|
668
668
|
type: "text",
|
|
669
|
-
text: "DECISION: abstain\nCONFIDENCE: 0.50\nREASONING: No LLM governance provider configured.
|
|
669
|
+
text: "DECISION: abstain\nCONFIDENCE: 0.50\nREASONING: No LLM governance provider configured. Install Hermes on PATH (hermes -z) with xai-oauth, or set XRAY_GOVERNANCE_LLM_ENABLED=true + XRAY_LLM_ENDPOINT.",
|
|
670
670
|
},
|
|
671
671
|
],
|
|
672
672
|
};
|
|
@@ -34,8 +34,9 @@ export function toMemoryTask(task) {
|
|
|
34
34
|
};
|
|
35
35
|
if (task.priority)
|
|
36
36
|
result.priority = task.priority;
|
|
37
|
-
if (task.dependencies)
|
|
37
|
+
if (Array.isArray(task.dependencies) && task.dependencies.length > 0) {
|
|
38
38
|
result.dependencies = task.dependencies;
|
|
39
|
+
}
|
|
39
40
|
if (task.estimatedComplexity !== undefined)
|
|
40
41
|
result.estimatedComplexity = task.estimatedComplexity;
|
|
41
42
|
if (task.metadata)
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Creates optimized execution plans for orchestration tasks
|
|
5
5
|
*/
|
|
6
6
|
import type { OrchestrationTask, ExecutionPlan, ComplexityAnalysis, TaskValidation } from '../types.js';
|
|
7
|
+
/** Dependency count from task-ID list or numeric hint from analyze-complexity */
|
|
8
|
+
export declare function dependencyCount(deps: OrchestrationTask['dependencies'] | undefined): number;
|
|
7
9
|
/**
|
|
8
10
|
* Execution Planner
|
|
9
11
|
* Plans and optimizes task execution strategies
|
|
@@ -5,6 +5,20 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { getAgentCapabilitiesManager } from '../config/agent-capabilities.js';
|
|
7
7
|
import { getProvider, toMemoryTask, fromMemoryTask, } from '../config/memory-routing-bridge.js';
|
|
8
|
+
/** Dependency count from task-ID list or numeric hint from analyze-complexity */
|
|
9
|
+
export function dependencyCount(deps) {
|
|
10
|
+
if (deps == null)
|
|
11
|
+
return 0;
|
|
12
|
+
if (typeof deps === 'number' && Number.isFinite(deps)) {
|
|
13
|
+
return Math.max(0, Math.round(deps));
|
|
14
|
+
}
|
|
15
|
+
if (Array.isArray(deps))
|
|
16
|
+
return deps.length;
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
function isDependencyIdList(deps) {
|
|
20
|
+
return Array.isArray(deps) && deps.length > 0;
|
|
21
|
+
}
|
|
8
22
|
/**
|
|
9
23
|
* Execution Planner
|
|
10
24
|
* Plans and optimizes task execution strategies
|
|
@@ -33,8 +47,8 @@ export class ExecutionPlanner {
|
|
|
33
47
|
if (!task.type) {
|
|
34
48
|
errors.push(`Task ${i}: Missing required field 'type'`);
|
|
35
49
|
}
|
|
36
|
-
// Check dependencies exist
|
|
37
|
-
if (task.dependencies && task.id) {
|
|
50
|
+
// Check task-ID dependencies exist (numeric hints skip graph validation)
|
|
51
|
+
if (isDependencyIdList(task.dependencies) && task.id) {
|
|
38
52
|
const taskIds = new Set(tasks.map(t => t.id).filter((id) => !!id));
|
|
39
53
|
for (const depId of task.dependencies) {
|
|
40
54
|
if (!taskIds.has(depId)) {
|
|
@@ -117,11 +131,11 @@ export class ExecutionPlanner {
|
|
|
117
131
|
const independentTasks = [];
|
|
118
132
|
const dependentTasks = [];
|
|
119
133
|
for (const task of sortedTasks) {
|
|
120
|
-
if (
|
|
121
|
-
|
|
134
|
+
if (isDependencyIdList(task.dependencies)) {
|
|
135
|
+
dependentTasks.push(task);
|
|
122
136
|
}
|
|
123
137
|
else {
|
|
124
|
-
|
|
138
|
+
independentTasks.push(task);
|
|
125
139
|
}
|
|
126
140
|
}
|
|
127
141
|
// Assign independent tasks in parallel
|
|
@@ -140,7 +154,7 @@ export class ExecutionPlanner {
|
|
|
140
154
|
if (visited.has(task.id))
|
|
141
155
|
return;
|
|
142
156
|
visited.add(task.id);
|
|
143
|
-
if (task.dependencies) {
|
|
157
|
+
if (isDependencyIdList(task.dependencies)) {
|
|
144
158
|
for (const depId of task.dependencies) {
|
|
145
159
|
const depTask = taskMap.get(depId);
|
|
146
160
|
if (depTask)
|
|
@@ -263,10 +277,7 @@ export class ExecutionPlanner {
|
|
|
263
277
|
if (task.estimatedComplexity) {
|
|
264
278
|
complexity = (complexity + task.estimatedComplexity) / 2;
|
|
265
279
|
}
|
|
266
|
-
|
|
267
|
-
if (task.dependencies) {
|
|
268
|
-
complexity += task.dependencies.length * 5;
|
|
269
|
-
}
|
|
280
|
+
complexity += dependencyCount(task.dependencies) * 5;
|
|
270
281
|
if (task.metadata?.memoryComplexityBoost !== undefined) {
|
|
271
282
|
complexity += task.metadata.memoryComplexityBoost;
|
|
272
283
|
}
|
|
@@ -295,7 +306,7 @@ export class ExecutionPlanner {
|
|
|
295
306
|
*/
|
|
296
307
|
calculateParallelPotential(tasks) {
|
|
297
308
|
// Tasks without dependencies can run in parallel
|
|
298
|
-
const independent = tasks.filter(t => !t.dependencies
|
|
309
|
+
const independent = tasks.filter((t) => !isDependencyIdList(t.dependencies));
|
|
299
310
|
return independent.length / tasks.length;
|
|
300
311
|
}
|
|
301
312
|
}
|
|
@@ -4,6 +4,17 @@
|
|
|
4
4
|
* Handles complexity analysis requests
|
|
5
5
|
*/
|
|
6
6
|
import type { OrchestrationTask } from '../types.js';
|
|
7
|
+
type AnalyzeComplexityInput = {
|
|
8
|
+
id?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
type?: string;
|
|
11
|
+
files?: string[];
|
|
12
|
+
dependencyCount?: number;
|
|
13
|
+
dependencies?: string[] | number;
|
|
14
|
+
riskLevel?: string;
|
|
15
|
+
estimatedComplexity?: number;
|
|
16
|
+
priority?: OrchestrationTask['priority'];
|
|
17
|
+
};
|
|
7
18
|
/**
|
|
8
19
|
* Complexity Handler
|
|
9
20
|
* Processes analyze-complexity requests
|
|
@@ -14,7 +25,7 @@ export declare class ComplexityHandler {
|
|
|
14
25
|
* Handle analyze-complexity request
|
|
15
26
|
*/
|
|
16
27
|
handleAnalyzeComplexity(args: {
|
|
17
|
-
tasks:
|
|
28
|
+
tasks: AnalyzeComplexityInput[];
|
|
18
29
|
}, asideId?: string): Promise<{
|
|
19
30
|
content: Array<{
|
|
20
31
|
type: string;
|
|
@@ -30,3 +41,4 @@ export declare class ComplexityHandler {
|
|
|
30
41
|
*/
|
|
31
42
|
private formatComplexityResponse;
|
|
32
43
|
}
|
|
44
|
+
export {};
|