0xray 4.0.23 → 4.0.24
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/.grok-plugin/plugin.json +1 -1
- package/.xray/features.json +11 -1
- package/.xray/features.schema.json +17 -0
- package/AGENTS-consumer.md +1 -1
- package/AGENTS.md +1 -1
- package/README.md +2 -2
- package/SKILLS.md +1 -1
- package/dist/AGENTS.md +1 -1
- package/dist/CHANGELOG.md +20 -0
- package/dist/README.md +2 -2
- package/dist/SKILLS.md +1 -1
- package/dist/cli/index.js +131 -100
- package/dist/core/features-config.d.ts +4 -0
- package/dist/core/features-config.js +10 -0
- package/dist/inference/inference-accumulator.d.ts +2 -0
- package/dist/inference/inference-accumulator.js +74 -2
- package/dist/inference/inference-cycle.js +1 -0
- package/dist/inference/inference-proposal-generator.js +65 -7
- package/dist/inference/inference-run-gate.d.ts +8 -0
- package/dist/inference/inference-run-gate.js +10 -0
- package/dist/inference/session-capture.d.ts +27 -0
- package/dist/inference/session-capture.js +277 -1
- package/dist/integrations/cursor/hooks/pre-compact.js +89 -1
- package/dist/integrations/hooks/plates.cjs +165 -0
- package/dist/integrations/hooks/station-hook-runtime.cjs +29 -11
- package/dist/integrations/hooks/station-memory-ingest.mjs +109 -42
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/dist/mcps/researcher-confidence.d.ts +5 -1
- package/dist/mcps/researcher-confidence.js +37 -0
- package/dist/mcps/researcher.server.js +2 -2
- package/dist/memory-routing/plates.d.ts +16 -0
- package/dist/memory-routing/plates.js +71 -0
- package/dist/memory-routing/types.d.ts +2 -0
- package/dist/memory-routing/types.js +2 -1
- package/dist/processors/implementations/inference-improvement-processor.d.ts +5 -0
- package/dist/processors/implementations/inference-improvement-processor.js +101 -2
- package/dist/processors/implementations/storytelling-trigger-processor.js +1 -11
- package/dist/processors/processor-manager.d.ts +1 -1
- package/dist/processors/processor-manager.js +52 -20
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/scripts/foundry/plant/skills/mill/SKILL.md +1 -1
- package/scripts/node/consumer-install-smoke.mjs +3 -3
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/src/mcps/researcher-confidence.ts +56 -3
- package/src/mcps/researcher.server.ts +4 -5
- package/vendor/@0xray/repertoire/README.md +3 -1
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts +23 -3
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +1 -1
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js +119 -16
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +1 -1
- package/vendor/@0xray/repertoire/dist/types.d.ts +1 -1
- package/vendor/@0xray/repertoire/dist/types.d.ts.map +1 -1
- package/vendor/@0xray/repertoire/package.json +1 -1
- package/xray/features.json +11 -1
- package/xray/features.schema.json +17 -0
|
@@ -13,6 +13,9 @@ import { PostProcessor } from "../processor-interfaces.js";
|
|
|
13
13
|
import { frameworkLogger } from "../../core/framework-logger.js";
|
|
14
14
|
import { getConfigDir } from "../../core/config-paths.js";
|
|
15
15
|
import { featuresConfigLoader } from "../../core/features-config.js";
|
|
16
|
+
import { captureCompletedInferenceOperation, saveReflectionSession } from "../../inference/session-capture.js";
|
|
17
|
+
import { loadReflectionInferences } from "../../inference/inference-accumulator.js";
|
|
18
|
+
import { InferenceCycle } from "../../inference/inference-cycle.js";
|
|
16
19
|
export class InferenceImprovementProcessor extends PostProcessor {
|
|
17
20
|
name = "inferenceImprovement";
|
|
18
21
|
priority = 5;
|
|
@@ -55,7 +58,8 @@ export class InferenceImprovementProcessor extends PostProcessor {
|
|
|
55
58
|
try {
|
|
56
59
|
const workflowContext = await this.prepareWorkflowContext(directory);
|
|
57
60
|
await this.saveWorkflowContext(directory, workflowContext);
|
|
58
|
-
await this.triggerAgentWorkflow(workflowContext);
|
|
61
|
+
const workflowId = await this.triggerAgentWorkflow(workflowContext);
|
|
62
|
+
await this.captureFinishedOperationSpeech(directory, workflowId);
|
|
59
63
|
await frameworkLogger.log("inference-improvement", "workflow_triggered", "info", {
|
|
60
64
|
dataFiles: workflowContext.dataLocations.reflections.length +
|
|
61
65
|
workflowContext.dataLocations.logs.length +
|
|
@@ -251,12 +255,107 @@ Final validation and application of approved changes:
|
|
|
251
255
|
});
|
|
252
256
|
const workflowBase = path.isAbsolute(this.workflowDir) ? this.workflowDir : path.join(process.cwd(), this.workflowDir);
|
|
253
257
|
const outputPath = path.join(workflowBase, "workflow-status.json");
|
|
258
|
+
const workflowId = `inference-${Date.now()}`;
|
|
254
259
|
fs.writeFileSync(outputPath, JSON.stringify({
|
|
255
260
|
status: "in_progress",
|
|
256
261
|
phase: "data_gathering",
|
|
257
262
|
nextAgent: "researcher",
|
|
258
263
|
message: "Invoke @researcher to begin data gathering phase",
|
|
259
|
-
workflowId
|
|
264
|
+
workflowId
|
|
260
265
|
}, null, 2));
|
|
266
|
+
return workflowId;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* The operation is finished once its prompt result text is on disk.
|
|
270
|
+
* One session per operation id. Empty speech writes nothing.
|
|
271
|
+
*/
|
|
272
|
+
async captureFinishedOperationSpeech(directory, currentOperationId) {
|
|
273
|
+
const workflowBase = path.isAbsolute(this.workflowDir)
|
|
274
|
+
? this.workflowDir
|
|
275
|
+
: path.join(directory, this.workflowDir);
|
|
276
|
+
const promptsDir = path.join(workflowBase, "prompts");
|
|
277
|
+
const inferenceDir = path.join(directory, "docs", "inference");
|
|
278
|
+
const signalNames = readStoredSignalNames(directory);
|
|
279
|
+
const ids = operationIdsToCapture(promptsDir, currentOperationId);
|
|
280
|
+
let captured = 0;
|
|
281
|
+
for (const operationId of ids) {
|
|
282
|
+
const saved = captureCompletedInferenceOperation({
|
|
283
|
+
operationId,
|
|
284
|
+
promptsDir,
|
|
285
|
+
inferenceDir,
|
|
286
|
+
signalNames,
|
|
287
|
+
});
|
|
288
|
+
if (!saved)
|
|
289
|
+
continue;
|
|
290
|
+
captured += 1;
|
|
291
|
+
await frameworkLogger.log("inference-improvement", "operation_session_captured", "info", { operationId, saved });
|
|
292
|
+
}
|
|
293
|
+
let reflectionSaved = 0;
|
|
294
|
+
for (const session of loadReflectionInferences(inferenceDir)) {
|
|
295
|
+
const saved = saveReflectionSession(session, inferenceDir);
|
|
296
|
+
if (!saved)
|
|
297
|
+
continue;
|
|
298
|
+
reflectionSaved += 1;
|
|
299
|
+
await frameworkLogger.log("inference-improvement", "reflection_session_written", "info", {
|
|
300
|
+
sessionId: session.sessionId,
|
|
301
|
+
saved,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
if (captured === 0 && reflectionSaved === 0)
|
|
305
|
+
return;
|
|
306
|
+
const cycle = new InferenceCycle(directory, undefined, {
|
|
307
|
+
force: true,
|
|
308
|
+
skipApply: true,
|
|
309
|
+
skipDeployVerify: true,
|
|
310
|
+
});
|
|
311
|
+
await cycle.maybeRunCycle();
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function operationIdsToCapture(promptsDir, currentOperationId) {
|
|
315
|
+
const ids = new Set();
|
|
316
|
+
if (currentOperationId.trim().length > 0)
|
|
317
|
+
ids.add(currentOperationId);
|
|
318
|
+
if (!fs.existsSync(promptsDir))
|
|
319
|
+
return [...ids];
|
|
320
|
+
for (const name of fs.readdirSync(promptsDir)) {
|
|
321
|
+
const stem = /^(inference-\d+)\.result\.(md|txt)$/i.exec(name);
|
|
322
|
+
if (stem?.[1])
|
|
323
|
+
ids.add(stem[1]);
|
|
324
|
+
const full = path.join(promptsDir, name);
|
|
325
|
+
if (!name.endsWith(".md") && !name.endsWith(".txt"))
|
|
326
|
+
continue;
|
|
327
|
+
let text = "";
|
|
328
|
+
try {
|
|
329
|
+
text = fs.readFileSync(full, "utf8");
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
const declared = /^operation:\s*(\S+)\s*$/im.exec(text);
|
|
335
|
+
if (declared?.[1])
|
|
336
|
+
ids.add(declared[1]);
|
|
337
|
+
}
|
|
338
|
+
return [...ids];
|
|
339
|
+
}
|
|
340
|
+
function readStoredSignalNames(directory) {
|
|
341
|
+
const dest = path.join(directory, ".xray", "state", "repertoire", "curated_signals.json");
|
|
342
|
+
if (!fs.existsSync(dest))
|
|
343
|
+
return [];
|
|
344
|
+
try {
|
|
345
|
+
const parsed = JSON.parse(fs.readFileSync(dest, "utf8"));
|
|
346
|
+
if (!Array.isArray(parsed.signals))
|
|
347
|
+
return [];
|
|
348
|
+
const names = [];
|
|
349
|
+
for (const signal of parsed.signals) {
|
|
350
|
+
if (!signal || typeof signal !== "object")
|
|
351
|
+
continue;
|
|
352
|
+
const name = signal.name;
|
|
353
|
+
if (typeof name === "string" && name.trim().length > 0)
|
|
354
|
+
names.push(name.trim());
|
|
355
|
+
}
|
|
356
|
+
return names;
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
return [];
|
|
261
360
|
}
|
|
262
361
|
}
|
|
@@ -5,7 +5,6 @@ import { PostProcessor } from "../processor-interfaces.js";
|
|
|
5
5
|
import { frameworkLogger } from "../../core/framework-logger.js";
|
|
6
6
|
import { featuresConfigLoader } from "../../core/features-config.js";
|
|
7
7
|
import { analyzeStructuralPatterns, } from "../../inference/semantic-patterns.js";
|
|
8
|
-
import { captureSessionInference, saveSessionInference, } from "../../inference/session-capture.js";
|
|
9
8
|
export class StorytellingTriggerProcessor extends PostProcessor {
|
|
10
9
|
name = "storytelling-trigger";
|
|
11
10
|
priority = 5;
|
|
@@ -327,16 +326,7 @@ export class StorytellingTriggerProcessor extends PostProcessor {
|
|
|
327
326
|
inferences.push(`${p.name} pattern detected [${Math.round(p.confidence * 100)}%]: ${p.description}${evidence}`);
|
|
328
327
|
}
|
|
329
328
|
if (semanticPatterns.length > 0) {
|
|
330
|
-
|
|
331
|
-
const session = captureSessionInference(sinceRef, untilRef);
|
|
332
|
-
if (session) {
|
|
333
|
-
const savedPath = saveSessionInference(session);
|
|
334
|
-
inferences.push(`Structured inference captured → ${path.basename(savedPath)}`);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
catch {
|
|
338
|
-
// session capture is best-effort
|
|
339
|
-
}
|
|
329
|
+
inferences.push("Semantic patterns stay on the reflection. A graded session comes from finished operation speech, not from commit subjects.");
|
|
340
330
|
}
|
|
341
331
|
}
|
|
342
332
|
if (diff.filesAdded.some(f => f.includes("implementations/") && f.endsWith(".ts"))) {
|
|
@@ -68,7 +68,7 @@ export declare class ProcessorManager {
|
|
|
68
68
|
success: boolean;
|
|
69
69
|
results: ProcessorResult[];
|
|
70
70
|
}>;
|
|
71
|
-
executePostProcessors(operation: string, data:
|
|
71
|
+
executePostProcessors(operation: string, data: unknown, preResults: ProcessorResult[]): Promise<ProcessorResult[]>;
|
|
72
72
|
private executeProcessor;
|
|
73
73
|
private updateMetrics;
|
|
74
74
|
getProcessorHealth(): ProcessorHealth[];
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
2
2
|
import { readdir } from "fs/promises";
|
|
3
|
-
import { join, basename } from "path";
|
|
3
|
+
import { join, basename, dirname } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
function asProcessorContext(ctx) {
|
|
7
|
+
return ctx;
|
|
8
|
+
}
|
|
9
|
+
function readContextString(ctx, key) {
|
|
10
|
+
const direct = ctx[key];
|
|
11
|
+
if (typeof direct === "string" && direct.length > 0)
|
|
12
|
+
return direct;
|
|
13
|
+
const toolInput = ctx.toolInput;
|
|
14
|
+
if (!toolInput || typeof toolInput !== "object")
|
|
15
|
+
return undefined;
|
|
16
|
+
const args = toolInput.args;
|
|
17
|
+
if (!args || typeof args !== "object")
|
|
18
|
+
return undefined;
|
|
19
|
+
const value = args[key];
|
|
20
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
21
|
+
}
|
|
4
22
|
export class ProcessorManager {
|
|
5
23
|
processors = new Map();
|
|
6
24
|
metrics = new Map();
|
|
@@ -13,24 +31,34 @@ export class ProcessorManager {
|
|
|
13
31
|
this.registerBuiltInFactories();
|
|
14
32
|
}
|
|
15
33
|
registerProcessorInstance(processor) {
|
|
16
|
-
|
|
17
|
-
|
|
34
|
+
const factoryExisted = this.factories.has(processor.name);
|
|
35
|
+
if (!factoryExisted) {
|
|
36
|
+
this.factories.set(processor.name, {
|
|
37
|
+
execute: async (ctx) => {
|
|
38
|
+
const result = await processor.execute(asProcessorContext(ctx));
|
|
39
|
+
return result.data;
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const processorExisted = this.processors.has(processor.name);
|
|
44
|
+
if (!processorExisted) {
|
|
45
|
+
this.registerProcessor({
|
|
46
|
+
name: processor.name,
|
|
47
|
+
type: processor.type,
|
|
48
|
+
priority: processor.priority,
|
|
49
|
+
enabled: processor.enabled,
|
|
50
|
+
});
|
|
18
51
|
}
|
|
19
|
-
this.factories.set(processor.name, {
|
|
20
|
-
execute: async (ctx) => {
|
|
21
|
-
const result = await processor.execute(ctx);
|
|
22
|
-
return result.data;
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
52
|
frameworkLogger.log("processor-manager", "auto-discovered-processor", "info", {
|
|
26
53
|
name: processor.name,
|
|
27
54
|
type: processor.type,
|
|
28
55
|
priority: processor.priority,
|
|
56
|
+
registered: !processorExisted,
|
|
29
57
|
});
|
|
30
|
-
return
|
|
58
|
+
return !factoryExisted || !processorExisted;
|
|
31
59
|
}
|
|
32
60
|
async discoverProcessors(directory) {
|
|
33
|
-
const dir = directory || join(
|
|
61
|
+
const dir = directory || join(moduleDir, "implementations");
|
|
34
62
|
const discovered = [];
|
|
35
63
|
let files;
|
|
36
64
|
try {
|
|
@@ -130,8 +158,8 @@ export class ProcessorManager {
|
|
|
130
158
|
execute: async (ctx) => {
|
|
131
159
|
const { LogProtectionProcessor } = await import("./implementations/log-protection-processor.js");
|
|
132
160
|
const p = new LogProtectionProcessor();
|
|
133
|
-
const filePath = ctx
|
|
134
|
-
const operation = ctx
|
|
161
|
+
const filePath = readContextString(ctx, "filePath");
|
|
162
|
+
const operation = readContextString(ctx, "operation");
|
|
135
163
|
const result = await p.execute({ filePath, operation });
|
|
136
164
|
return result.data;
|
|
137
165
|
},
|
|
@@ -229,7 +257,7 @@ export class ProcessorManager {
|
|
|
229
257
|
f.set("testAutoCreation", {
|
|
230
258
|
execute: async (ctx) => {
|
|
231
259
|
const { testAutoCreationProcessor } = await import("./implementations/test-auto-creation-processor.js");
|
|
232
|
-
const result = await testAutoCreationProcessor.execute(ctx);
|
|
260
|
+
const result = await testAutoCreationProcessor.execute(asProcessorContext(ctx));
|
|
233
261
|
return { success: result.success, message: result.message, data: result.data };
|
|
234
262
|
},
|
|
235
263
|
init: async () => {
|
|
@@ -249,8 +277,8 @@ export class ProcessorManager {
|
|
|
249
277
|
const { AgentsMdValidationProcessor } = await import("./implementations/agents-md-validation-processor.js");
|
|
250
278
|
const p = new AgentsMdValidationProcessor(process.cwd());
|
|
251
279
|
const result = await p.execute({
|
|
252
|
-
tool: ctx
|
|
253
|
-
operation: ctx
|
|
280
|
+
tool: readContextString(ctx, "tool") ?? "validate",
|
|
281
|
+
operation: readContextString(ctx, "operation") ?? "pre-commit",
|
|
254
282
|
});
|
|
255
283
|
return {
|
|
256
284
|
success: result.success,
|
|
@@ -283,7 +311,7 @@ export class ProcessorManager {
|
|
|
283
311
|
f.set("typescriptCompilation", {
|
|
284
312
|
execute: async (ctx) => {
|
|
285
313
|
const { runTypeScriptCompilation } = await import("./implementations/typescript-compilation-processor.js");
|
|
286
|
-
const cwd = ctx
|
|
314
|
+
const cwd = readContextString(ctx, "directory") ?? process.cwd();
|
|
287
315
|
return runTypeScriptCompilation(cwd);
|
|
288
316
|
},
|
|
289
317
|
init: async () => {
|
|
@@ -762,10 +790,14 @@ export class ProcessorManager {
|
|
|
762
790
|
if (Array.isArray(context)) {
|
|
763
791
|
return { valid: true, errors: [] };
|
|
764
792
|
}
|
|
765
|
-
const
|
|
793
|
+
const record = context;
|
|
794
|
+
const contextData = record.data;
|
|
766
795
|
if (contextData && typeof contextData !== "object") {
|
|
767
796
|
return { valid: true, errors: [] };
|
|
768
797
|
}
|
|
798
|
+
const dataRecord = contextData && typeof contextData === "object"
|
|
799
|
+
? contextData
|
|
800
|
+
: {};
|
|
769
801
|
const requiredFields = {
|
|
770
802
|
preValidate: ["operation"],
|
|
771
803
|
codexCompliance: ["operation"],
|
|
@@ -779,7 +811,7 @@ export class ProcessorManager {
|
|
|
779
811
|
};
|
|
780
812
|
const required = requiredFields[processorName] || [];
|
|
781
813
|
for (const field of required) {
|
|
782
|
-
if (!(field in
|
|
814
|
+
if (!(field in record) && !(field in dataRecord)) {
|
|
783
815
|
errors.push(`Missing required field: ${field}`);
|
|
784
816
|
}
|
|
785
817
|
}
|
|
@@ -787,7 +819,7 @@ export class ProcessorManager {
|
|
|
787
819
|
frameworkLogger.log("processor-manager", "context-validation-warnings", "info", {
|
|
788
820
|
processor: processorName,
|
|
789
821
|
errors,
|
|
790
|
-
contextKeys: Object.keys(
|
|
822
|
+
contextKeys: Object.keys(record),
|
|
791
823
|
});
|
|
792
824
|
}
|
|
793
825
|
return { valid: errors.length === 0, errors };
|
package/llms.txt
CHANGED
|
@@ -35,7 +35,7 @@ Registered in `.mcp.json` as `npx -y 0xray mcp <cmd>`:
|
|
|
35
35
|
| `xray-code-review` | Proposal quality |
|
|
36
36
|
| `xray-architect-tools` | System design |
|
|
37
37
|
|
|
38
|
-
Not an 8th `xray-*` server. **Repertoire is preferred** — vendored 0.2.
|
|
38
|
+
Not an 8th `xray-*` server. **Repertoire is preferred** — vendored 0.2.8 ships on (`npx @0xray/repertoire mcp`). Dest is named laws, not hangar `repo-*` or git slugs. Survive compact is **Station** (Read `.xray/state/STATION.md`). Station is the ticket, not a substitute for Repertoire. Do not pin 0.1.8.
|
|
39
39
|
|
|
40
40
|
## Codex 69 (always on)
|
|
41
41
|
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ The mill **fastens** a suit. Default mill plant is **inspect** (inspecting AI wo
|
|
|
11
11
|
|
|
12
12
|
**Mill-fill:** their keys/files win. Mill plant names they did not overlay stay. JSON always merges.
|
|
13
13
|
|
|
14
|
-
**Factory:** **Repertoire is preferred** (vendored 0.2.
|
|
14
|
+
**Factory:** **Repertoire is preferred** (vendored 0.2.8 ships on; dest = named laws). Seven generated MCP. Constitution (PPE) stays worn. Not a fifth MCP. Not 5.0.
|
|
15
15
|
|
|
16
16
|
**Costume:** `foundry.json` `"costume": true` copies the 45/42 mill costume.
|
|
17
17
|
|
|
@@ -92,7 +92,7 @@ function assertOrganRequire(tmpRoot) {
|
|
|
92
92
|
if (organPkg.name !== "@0xray/repertoire") {
|
|
93
93
|
throw new Error(`required organ name ${organPkg.name}`);
|
|
94
94
|
}
|
|
95
|
-
if (organPkg.version !== "0.2.
|
|
95
|
+
if (organPkg.version !== "0.2.8") {
|
|
96
96
|
throw new Error(`required organ version ${organPkg.version}`);
|
|
97
97
|
}
|
|
98
98
|
if (fs.existsSync(path.join(tmpRoot, "vendor"))) {
|
|
@@ -165,8 +165,8 @@ function assertFreshInstallDefaults(tmpRoot, version) {
|
|
|
165
165
|
throw new Error("vendored @0xray/repertoire missing from fresh tarball install");
|
|
166
166
|
}
|
|
167
167
|
const organ = JSON.parse(fs.readFileSync(organPkg, "utf-8"));
|
|
168
|
-
if (organ.version !== "0.2.
|
|
169
|
-
throw new Error(`expected organ 0.2.
|
|
168
|
+
if (organ.version !== "0.2.8") {
|
|
169
|
+
throw new Error(`expected organ 0.2.8, got ${organ.version}`);
|
|
170
170
|
}
|
|
171
171
|
console.log(" ✅ .xray/features.json fresh-install defaults (opt-in off)");
|
|
172
172
|
return { consumerFeaturesPath, features };
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { frameworkLogger } from '../core/framework-logger.js';
|
|
2
2
|
import { getMemoryRoutingProvider } from '../memory-routing/index.js';
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import { recallPlate } from '../memory-routing/plates.js';
|
|
4
|
+
import {
|
|
5
|
+
LESSON_TEXT_CAP,
|
|
6
|
+
type MemoryRoutingContext,
|
|
7
|
+
type MemorySignalLessons,
|
|
8
|
+
type MemoryTaskConfidence,
|
|
6
9
|
} from '../memory-routing/types.js';
|
|
7
10
|
|
|
8
11
|
const TRAP_LANGUAGE = /TYPE:\s*ontological-trap|ontological[- ]trap/i;
|
|
@@ -14,6 +17,10 @@ export interface ResearcherMemoryContext {
|
|
|
14
17
|
matchedSignals: string[];
|
|
15
18
|
recommendedAgent: string | null;
|
|
16
19
|
triggeredBy: 'trap-language' | 'high-confidence-primitives';
|
|
20
|
+
/** Graded lines for signals this task already matched. */
|
|
21
|
+
lessons?: MemorySignalLessons[];
|
|
22
|
+
/** Proposal text used to recall at most one pipeline plate. */
|
|
23
|
+
proposalText?: string;
|
|
17
24
|
}
|
|
18
25
|
|
|
19
26
|
export function shouldQueryRepertoireConfidence(
|
|
@@ -80,6 +87,7 @@ export async function resolveResearcherMemoryContext(input: {
|
|
|
80
87
|
confidence.matchedSignals.length > 0
|
|
81
88
|
? confidence.matchedSignals
|
|
82
89
|
: routingContext.matchedSignals;
|
|
90
|
+
const lessons = lessonsForMatchedSignals(routingContext.lessons, matchedSignals);
|
|
83
91
|
|
|
84
92
|
const context: ResearcherMemoryContext = {
|
|
85
93
|
providerId: provider.id,
|
|
@@ -87,6 +95,8 @@ export async function resolveResearcherMemoryContext(input: {
|
|
|
87
95
|
matchedSignals,
|
|
88
96
|
recommendedAgent: confidence.recommendedAgent,
|
|
89
97
|
triggeredBy: trapLanguageDetected ? 'trap-language' : 'high-confidence-primitives',
|
|
98
|
+
proposalText: taskText,
|
|
99
|
+
...(lessons.length > 0 ? { lessons } : {}),
|
|
90
100
|
};
|
|
91
101
|
|
|
92
102
|
if (confidence.highConfidenceTrapPresent) {
|
|
@@ -122,6 +132,12 @@ export function buildMemoryRoutingEvidence(
|
|
|
122
132
|
lines.push(`Recommended agent for trap handling: ${recommendedAgent}`);
|
|
123
133
|
}
|
|
124
134
|
|
|
135
|
+
for (const line of lessonSpeechLines(context.lessons, matchedSignals)) {
|
|
136
|
+
lines.push(`Lesson: ${line}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
appendRecalledPlate(lines, context.proposalText);
|
|
140
|
+
|
|
125
141
|
return lines;
|
|
126
142
|
}
|
|
127
143
|
|
|
@@ -140,5 +156,42 @@ export function formatMemoryRoutingBlock(context: ResearcherMemoryContext): stri
|
|
|
140
156
|
lines.push(` recommendedAgent: ${recommendedAgent}`);
|
|
141
157
|
}
|
|
142
158
|
|
|
159
|
+
for (const line of lessonSpeechLines(context.lessons, matchedSignals)) {
|
|
160
|
+
lines.push(` lesson: ${line}`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
appendRecalledPlate(lines, context.proposalText);
|
|
164
|
+
|
|
143
165
|
return lines.join('\n');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function appendRecalledPlate(lines: string[], proposalText: string | undefined): void {
|
|
169
|
+
const plate = recallPlate(proposalText);
|
|
170
|
+
if (!plate) return;
|
|
171
|
+
lines.push(`Plate: ${plate.id}`);
|
|
172
|
+
lines.push(plate.body);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function lessonsForMatchedSignals(
|
|
176
|
+
lessons: MemorySignalLessons[] | undefined,
|
|
177
|
+
matchedSignals: string[],
|
|
178
|
+
): MemorySignalLessons[] {
|
|
179
|
+
const matched = new Set(matchedSignals);
|
|
180
|
+
return (lessons ?? []).filter((lesson) => matched.has(lesson.name));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Stored lesson text for signals this task matched. Empty text is omitted. */
|
|
184
|
+
function lessonSpeechLines(
|
|
185
|
+
lessons: MemorySignalLessons[] | undefined,
|
|
186
|
+
matchedSignals: string[],
|
|
187
|
+
): string[] {
|
|
188
|
+
const speech: string[] = [];
|
|
189
|
+
for (const lesson of lessonsForMatchedSignals(lessons, matchedSignals)) {
|
|
190
|
+
for (const line of lesson.lines) {
|
|
191
|
+
const text = line.text.trim().slice(0, LESSON_TEXT_CAP);
|
|
192
|
+
if (text.length === 0) continue;
|
|
193
|
+
speech.push(`${lesson.name}: ${text}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return speech;
|
|
144
197
|
}
|
|
@@ -472,7 +472,7 @@ class XrayLibrarianServer extends XrayKnowledgeSkillBase {
|
|
|
472
472
|
});
|
|
473
473
|
|
|
474
474
|
const enrichedEvidence = [...(evidence || [])];
|
|
475
|
-
if (memoryContext
|
|
475
|
+
if (memoryContext) {
|
|
476
476
|
enrichedEvidence.push(...buildMemoryRoutingEvidence(memoryContext));
|
|
477
477
|
}
|
|
478
478
|
|
|
@@ -491,10 +491,9 @@ class XrayLibrarianServer extends XrayKnowledgeSkillBase {
|
|
|
491
491
|
recommendedAgent: memoryContext?.recommendedAgent,
|
|
492
492
|
});
|
|
493
493
|
|
|
494
|
-
const memoryRoutingBlock =
|
|
495
|
-
memoryContext
|
|
496
|
-
|
|
497
|
-
: "";
|
|
494
|
+
const memoryRoutingBlock = memoryContext
|
|
495
|
+
? `\n${formatMemoryRoutingBlock(memoryContext)}`
|
|
496
|
+
: "";
|
|
498
497
|
|
|
499
498
|
return {
|
|
500
499
|
content: [
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Factory memory organ for [0xRay](https://github.com/0xRayAI/xray): seed primitives, in-process memory routing, extra MCP (not an 8th `xray-*` server).
|
|
4
4
|
|
|
5
|
-
**v0.2.
|
|
5
|
+
**v0.2.8** · 0xRay **4.0** wear. Runtime does **not** depend on `0xray` (optional peer for suit-verify scripts).
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -66,6 +66,8 @@ Override with env:
|
|
|
66
66
|
|
|
67
67
|
Routing confidence is **time-weighted**: excess above the 0.55 gate fades after a 14-day grace (60-day half-life). Factory seed sitting on the gate keeps routing. `npm run signals:hygiene` reports decay on the hydrated project copy under `.xray/state/repertoire/`; it dry-runs in this repo unless `--i-mean-it` (writes the project copy, never the tarball).
|
|
68
68
|
|
|
69
|
+
A grade that passes appends one lesson on the named law and stores that line beside the average. The same task id does not step again. `LESSON_LINE_CAP` is 20: past that window the oldest line leaves only after its task id is in the ledger. `RETAINED_LESSON_ID_CAP` is 20, kept in insertion order (oldest first, not alphabetical). Speech that names no stored signal mints one proposed signal tagged `learned`, and the same speech does not mint twice. `LEARNED_SIGNAL_CAP` is 24 and evicts only `proposed` + `learned` signals. Factory signals stay.
|
|
70
|
+
|
|
69
71
|
## 0xRay memory routing (in-process)
|
|
70
72
|
|
|
71
73
|
In `.xray/features.json` or `xray/features.json`:
|
|
@@ -26,6 +26,19 @@ export declare function lawClauseInText(definition: string, text: string, span?:
|
|
|
26
26
|
export declare function isAboveConfidenceFloor(value: number, gate?: number): boolean;
|
|
27
27
|
/** Hot lines kept on a law. Older lines leave only after their task id is in the ledger. */
|
|
28
28
|
export declare const LESSON_LINE_CAP = 20;
|
|
29
|
+
/**
|
|
30
|
+
* Aged task ids kept so a replay does not step the average.
|
|
31
|
+
* Insertion order, oldest first. Same size as the hot window: past this cap the oldest id leaves.
|
|
32
|
+
* Alphabetical order is not age, so the ledger is not sorted.
|
|
33
|
+
*/
|
|
34
|
+
export declare const RETAINED_LESSON_ID_CAP = 20;
|
|
35
|
+
/**
|
|
36
|
+
* Proposed signals minted from speech (`tags` includes `learned`).
|
|
37
|
+
* One lesson-window of room past the hot lines, so unnamed speech can land and then the
|
|
38
|
+
* lowest confidence leaves, then the oldest last_seen. Factory signals and anything not
|
|
39
|
+
* proposed-and-learned stay.
|
|
40
|
+
*/
|
|
41
|
+
export declare const LEARNED_SIGNAL_CAP = 24;
|
|
29
42
|
export declare const LESSON_TEXT_CAP = 400;
|
|
30
43
|
/**
|
|
31
44
|
* The diary names a law only when it contains the signal id, or the id with
|
|
@@ -92,9 +105,16 @@ export declare class CuratedSignalsManager {
|
|
|
92
105
|
*/
|
|
93
106
|
recordFeedbackOutcome(entry: OrchestratorFeedbackEntry): FeedbackOutcomeResult[];
|
|
94
107
|
/**
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
|
|
108
|
+
* Shed proposed speech mints past LEARNED_SIGNAL_CAP.
|
|
109
|
+
* Lowest confidence leaves first, then the oldest last_seen. Factory laws stay.
|
|
110
|
+
*/
|
|
111
|
+
private evictSpeechMints;
|
|
112
|
+
private dropLearnedConviction;
|
|
113
|
+
/**
|
|
114
|
+
* Append one graded line. A task id already on the law, or still in the capped
|
|
115
|
+
* ledger, does not move the average and does not append again.
|
|
116
|
+
* Past the hot cap, the oldest line leaves only after its id is in the ledger.
|
|
117
|
+
* Past the ledger cap, the oldest id leaves. Order is recency, not alphabetical.
|
|
98
118
|
*/
|
|
99
119
|
private rememberLesson;
|
|
100
120
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CuratedSignalsManager.d.ts","sourceRoot":"","sources":["../../src/registry/CuratedSignalsManager.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,yBAAyB,EACzB,cAAc,EAEd,WAAW,EACX,cAAc,EACd,YAAY,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,eAAO,MAAM,gCAAgC,OAAO,CAAC;AACrD,eAAO,MAAM,kCAAkC,IAAI,CAAC;AACpD,4EAA4E;AAC5E,eAAO,MAAM,iCAAiC,MAAM,CAAC;AACrD,eAAO,MAAM,mCAAmC,MAAM,CAAC;AACvD,qFAAqF;AACrF,eAAO,MAAM,uBAAuB,IAAI,CAAC;AACzC,kFAAkF;AAClF,eAAO,MAAM,eAAe,IAAI,CAAC;AAUjC,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,IAAI,SAAmC,GACtC,OAAO,CAET;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAKnD;AAYD;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,SAAkB,GACrB,OAAO,CAcT;
|
|
1
|
+
{"version":3,"file":"CuratedSignalsManager.d.ts","sourceRoot":"","sources":["../../src/registry/CuratedSignalsManager.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,yBAAyB,EACzB,cAAc,EAEd,WAAW,EACX,cAAc,EACd,YAAY,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,eAAO,MAAM,gCAAgC,OAAO,CAAC;AACrD,eAAO,MAAM,kCAAkC,IAAI,CAAC;AACpD,4EAA4E;AAC5E,eAAO,MAAM,iCAAiC,MAAM,CAAC;AACrD,eAAO,MAAM,mCAAmC,MAAM,CAAC;AACvD,qFAAqF;AACrF,eAAO,MAAM,uBAAuB,IAAI,CAAC;AACzC,kFAAkF;AAClF,eAAO,MAAM,eAAe,IAAI,CAAC;AAUjC,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,IAAI,SAAmC,GACtC,OAAO,CAET;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAKnD;AAYD;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,SAAkB,GACrB,OAAO,CAcT;AAqED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,IAAI,SAAmC,GACtC,OAAO,CAET;AAED,4FAA4F;AAC5F,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,KAAkB,CAAC;AACtD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,eAAe,MAAM,CAAC;AAqBnC;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAOpE;AAQD,6FAA6F;AAC7F,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAM1D;AAED,sEAAsE;AACtE,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjE;AAED,4DAA4D;AAC5D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQlF;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CAenF;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,aAAa,EAAE,WAAW,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC;CAC7D;AAED,qBAAa,qBAAqB;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,QAAQ,CAAC,EAAE,MAAM;IAM7B,qBAAqB,IAAI,MAAM;IAI/B,IAAI,IAAI,kBAAkB;IAO1B,IAAI,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAUpC;;;OAGG;IACH,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO;IAYnF,SAAS,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAStC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIlD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,EAAE;IAOtC,sBAAsB,IAAI,aAAa,EAAE;IAIzC,aAAa,CAAC,QAAQ,EAAE,cAAc,GAAG,aAAa,EAAE;IAIxD;;;;OAIG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,WAAW,EAAE;IAyDtD,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE;IAkBrD;;;OAGG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE;IA+BxC,2BAA2B,CACzB,OAAO,EAAE,cAAc,EAAE,EACzB,OAAO,GAAE;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAO,GACnE,MAAM,EAAE;IAgEX,mBAAmB,CACjB,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE,oBAAyB,GACjC,OAAO;IAgBV,uBAAuB,CAAC,OAAO,GAAE,oBAAyB,GAAG,MAAM,EAAE;IAmBrE,yBAAyB,CACvB,gBAAgB,SAAmC,EACnD,OAAO,GAAE,YAAiB,GACzB,aAAa,EAAE;IAOlB;;;OAGG;IACH,2BAA2B,CAAC,OAAO,GAAE,YAAiB,GAAG,MAAM,EAAE;IAkBjE;;;OAGG;IACH,qBAAqB,CAAC,KAAK,EAAE,yBAAyB,GAAG,qBAAqB,EAAE;IA2FhF;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,qBAAqB;IAa7B;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAoBtB;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAW9B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IA8C7B,OAAO,CAAC,yBAAyB;IAoBjC,OAAO,CAAC,0BAA0B;IAKlC,wBAAwB,IAAI,MAAM,EAAE;IA+CpC,OAAO,CAAC,eAAe;CAQxB"}
|