@cleocode/brain 2026.6.15 → 2026.6.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/adapters/agent-registry.d.ts +35 -0
- package/dist/src/adapters/agent-registry.d.ts.map +1 -0
- package/dist/src/adapters/agent-registry.js +96 -0
- package/dist/src/adapters/agent-registry.js.map +1 -0
- package/dist/src/adapters/brain.d.ts +35 -0
- package/dist/src/adapters/brain.d.ts.map +1 -0
- package/dist/src/adapters/brain.js +303 -0
- package/dist/src/adapters/brain.js.map +1 -0
- package/dist/src/adapters/conduit.d.ts +25 -0
- package/dist/src/adapters/conduit.d.ts.map +1 -0
- package/dist/src/adapters/conduit.js +94 -0
- package/dist/src/adapters/conduit.js.map +1 -0
- package/dist/src/adapters/index.d.ts +32 -0
- package/dist/src/adapters/index.d.ts.map +1 -0
- package/dist/src/adapters/index.js +194 -0
- package/dist/src/adapters/index.js.map +1 -0
- package/dist/src/adapters/nexus.d.ts +24 -0
- package/dist/src/adapters/nexus.d.ts.map +1 -0
- package/dist/src/adapters/nexus.js +83 -0
- package/dist/src/adapters/nexus.js.map +1 -0
- package/dist/src/adapters/tasks.d.ts +23 -0
- package/dist/src/adapters/tasks.d.ts.map +1 -0
- package/dist/src/adapters/tasks.js +143 -0
- package/dist/src/adapters/tasks.js.map +1 -0
- package/dist/src/cleo-home.d.ts +47 -0
- package/dist/src/cleo-home.d.ts.map +1 -0
- package/dist/src/cleo-home.js +73 -0
- package/dist/src/cleo-home.js.map +1 -0
- package/dist/src/db-connections.d.ts +143 -0
- package/dist/src/db-connections.d.ts.map +1 -0
- package/dist/src/db-connections.js +215 -0
- package/dist/src/db-connections.js.map +1 -0
- package/dist/src/index.d.ts +26 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +29 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/project-context.d.ts +47 -0
- package/dist/src/project-context.d.ts.map +1 -0
- package/dist/src/project-context.js +52 -0
- package/dist/src/project-context.js.map +1 -0
- package/dist/src/types.d.ts +22 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +22 -0
- package/dist/src/types.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AGENT-REGISTRY substrate adapter for the Living Brain API.
|
|
3
|
+
*
|
|
4
|
+
* Read-only visualization path. Queries the LEGACY standalone `signaldock.db`
|
|
5
|
+
* (resolved by `getAgentRegistryDbPath`) and returns BrainNodes/BrainEdges for
|
|
6
|
+
* agents and agent-to-agent social connections. The legacy standalone file still
|
|
7
|
+
* carries the BARE table names (`agents`, `agent_connections`); the brain-package
|
|
8
|
+
* read path is migrated to the consolidated `cleo.db` separately in E6 (T11249),
|
|
9
|
+
* so the SQL below intentionally still targets the bare names.
|
|
10
|
+
*
|
|
11
|
+
* The substrate identifier + node-id prefix were renamed `signaldock` →
|
|
12
|
+
* `agent-registry` under T11622 (display identifiers, decoupled from the physical
|
|
13
|
+
* table names).
|
|
14
|
+
*
|
|
15
|
+
* Node IDs are prefixed with "agent-registry:" to prevent collisions.
|
|
16
|
+
* Agents are the cross-substrate identity bridge — they appear in TASKS
|
|
17
|
+
* (assignee), CONDUIT (from/to), and BRAIN (source agent).
|
|
18
|
+
*
|
|
19
|
+
* @task T11622 (Signaldock → Agent Registry rename; folds T11578 AC2)
|
|
20
|
+
*/
|
|
21
|
+
import type { BrainEdge, BrainNode, BrainQueryOptions } from '../types.js';
|
|
22
|
+
/**
|
|
23
|
+
* Returns all BrainNodes and BrainEdges sourced from the Agent Registry.
|
|
24
|
+
*
|
|
25
|
+
* Fetches all active agents plus their declared connections.
|
|
26
|
+
* Agent nodes serve as the cross-substrate identity anchors.
|
|
27
|
+
*
|
|
28
|
+
* @param options - Query options (limit).
|
|
29
|
+
* @returns Nodes and edges from the AGENT-REGISTRY substrate.
|
|
30
|
+
*/
|
|
31
|
+
export declare function getAgentRegistrySubstrate(options?: BrainQueryOptions): {
|
|
32
|
+
nodes: BrainNode[];
|
|
33
|
+
edges: BrainEdge[];
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=agent-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-registry.d.ts","sourceRoot":"","sources":["../../../src/adapters/agent-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA+B3E;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,iBAAsB,GAAG;IAC1E,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB,CAoEA"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AGENT-REGISTRY substrate adapter for the Living Brain API.
|
|
3
|
+
*
|
|
4
|
+
* Read-only visualization path. Queries the LEGACY standalone `signaldock.db`
|
|
5
|
+
* (resolved by `getAgentRegistryDbPath`) and returns BrainNodes/BrainEdges for
|
|
6
|
+
* agents and agent-to-agent social connections. The legacy standalone file still
|
|
7
|
+
* carries the BARE table names (`agents`, `agent_connections`); the brain-package
|
|
8
|
+
* read path is migrated to the consolidated `cleo.db` separately in E6 (T11249),
|
|
9
|
+
* so the SQL below intentionally still targets the bare names.
|
|
10
|
+
*
|
|
11
|
+
* The substrate identifier + node-id prefix were renamed `signaldock` →
|
|
12
|
+
* `agent-registry` under T11622 (display identifiers, decoupled from the physical
|
|
13
|
+
* table names).
|
|
14
|
+
*
|
|
15
|
+
* Node IDs are prefixed with "agent-registry:" to prevent collisions.
|
|
16
|
+
* Agents are the cross-substrate identity bridge — they appear in TASKS
|
|
17
|
+
* (assignee), CONDUIT (from/to), and BRAIN (source agent).
|
|
18
|
+
*
|
|
19
|
+
* @task T11622 (Signaldock → Agent Registry rename; folds T11578 AC2)
|
|
20
|
+
*/
|
|
21
|
+
import { allTyped, getAgentRegistryDb } from '../db-connections.js';
|
|
22
|
+
/**
|
|
23
|
+
* Converts a UNIX epoch seconds value to an ISO-8601 string.
|
|
24
|
+
* Returns null when the value is not a finite positive number.
|
|
25
|
+
*
|
|
26
|
+
* @param epoch - UNIX timestamp in seconds, or null.
|
|
27
|
+
* @returns ISO-8601 string or null.
|
|
28
|
+
*/
|
|
29
|
+
function epochToIso(epoch) {
|
|
30
|
+
if (epoch === null || !Number.isFinite(epoch) || epoch <= 0)
|
|
31
|
+
return null;
|
|
32
|
+
return new Date(epoch * 1000).toISOString();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Returns all BrainNodes and BrainEdges sourced from the Agent Registry.
|
|
36
|
+
*
|
|
37
|
+
* Fetches all active agents plus their declared connections.
|
|
38
|
+
* Agent nodes serve as the cross-substrate identity anchors.
|
|
39
|
+
*
|
|
40
|
+
* @param options - Query options (limit).
|
|
41
|
+
* @returns Nodes and edges from the AGENT-REGISTRY substrate.
|
|
42
|
+
*/
|
|
43
|
+
export function getAgentRegistrySubstrate(options = {}) {
|
|
44
|
+
const db = getAgentRegistryDb();
|
|
45
|
+
if (!db)
|
|
46
|
+
return { nodes: [], edges: [] };
|
|
47
|
+
const perSubstrateLimit = Math.ceil((options.limit ?? 500) / 5);
|
|
48
|
+
const nodes = [];
|
|
49
|
+
const edges = [];
|
|
50
|
+
try {
|
|
51
|
+
// Active agents (legacy standalone signaldock.db bare table)
|
|
52
|
+
const agentRows = allTyped(db.prepare(`SELECT agent_id, name, status, created_at
|
|
53
|
+
FROM agents
|
|
54
|
+
WHERE status != 'deleted'
|
|
55
|
+
ORDER BY created_at DESC
|
|
56
|
+
LIMIT ?`), perSubstrateLimit);
|
|
57
|
+
const agentIds = new Set();
|
|
58
|
+
for (const row of agentRows) {
|
|
59
|
+
agentIds.add(row.agent_id);
|
|
60
|
+
nodes.push({
|
|
61
|
+
id: `agent-registry:${row.agent_id}`,
|
|
62
|
+
kind: 'agent',
|
|
63
|
+
substrate: 'agent-registry',
|
|
64
|
+
label: row.name,
|
|
65
|
+
weight: row.status === 'active' ? 1.0 : 0.5,
|
|
66
|
+
createdAt: epochToIso(row.created_at),
|
|
67
|
+
meta: {
|
|
68
|
+
status: row.status,
|
|
69
|
+
created_at: row.created_at,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
// Agent connections (declared social graph)
|
|
74
|
+
if (agentIds.size > 0) {
|
|
75
|
+
const placeholders = [...agentIds].map(() => '?').join(',');
|
|
76
|
+
const connRows = allTyped(db.prepare(`SELECT from_agent_id, to_agent_id, connection_type, strength
|
|
77
|
+
FROM agent_connections
|
|
78
|
+
WHERE from_agent_id IN (${placeholders})
|
|
79
|
+
AND to_agent_id IN (${placeholders})`), ...agentIds, ...agentIds);
|
|
80
|
+
for (const row of connRows) {
|
|
81
|
+
edges.push({
|
|
82
|
+
source: `agent-registry:${row.from_agent_id}`,
|
|
83
|
+
target: `agent-registry:${row.to_agent_id}`,
|
|
84
|
+
type: row.connection_type,
|
|
85
|
+
weight: row.strength ?? 0.5,
|
|
86
|
+
substrate: 'agent-registry',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// Return partial results on error
|
|
93
|
+
}
|
|
94
|
+
return { nodes, edges };
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=agent-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-registry.js","sourceRoot":"","sources":["../../../src/adapters/agent-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAYpE;;;;;;GAMG;AACH,SAAS,UAAU,CAAC,KAAoB;IACtC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACzE,OAAO,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;AAC9C,CAAC;AAUD;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CAAC,UAA6B,EAAE;IAIvE,MAAM,EAAE,GAAG,kBAAkB,EAAE,CAAC;IAChC,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAEzC,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAEhE,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAgB,EAAE,CAAC;IAE9B,IAAI,CAAC;QACH,6DAA6D;QAC7D,MAAM,SAAS,GAAG,QAAQ,CACxB,EAAE,CAAC,OAAO,CACR;;;;iBAIS,CACV,EACD,iBAAiB,CAClB,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;QACnC,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;YAC5B,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,kBAAkB,GAAG,CAAC,QAAQ,EAAE;gBACpC,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,gBAAgB;gBAC3B,KAAK,EAAE,GAAG,CAAC,IAAI;gBACf,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;gBAC3C,SAAS,EAAE,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC;gBACrC,IAAI,EAAE;oBACJ,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,UAAU,EAAE,GAAG,CAAC,UAAU;iBAC3B;aACF,CAAC,CAAC;QACL,CAAC;QAED,4CAA4C;QAC5C,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,YAAY,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC5D,MAAM,QAAQ,GAAG,QAAQ,CACvB,EAAE,CAAC,OAAO,CACR;;qCAE2B,YAAY;mCACd,YAAY,GAAG,CACzC,EACD,GAAG,QAAQ,EACX,GAAG,QAAQ,CACZ,CAAC;YAEF,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC3B,KAAK,CAAC,IAAI,CAAC;oBACT,MAAM,EAAE,kBAAkB,GAAG,CAAC,aAAa,EAAE;oBAC7C,MAAM,EAAE,kBAAkB,GAAG,CAAC,WAAW,EAAE;oBAC3C,IAAI,EAAE,GAAG,CAAC,eAAe;oBACzB,MAAM,EAAE,GAAG,CAAC,QAAQ,IAAI,GAAG;oBAC3B,SAAS,EAAE,gBAAgB;iBAC5B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,kCAAkC;IACpC,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BRAIN substrate adapter for the Living Brain API.
|
|
3
|
+
*
|
|
4
|
+
* Queries brain.db and returns BrainNodes/BrainEdges for all typed memory tables:
|
|
5
|
+
* observations, decisions, patterns, learnings, plus the graph layer
|
|
6
|
+
* (brain_page_nodes / brain_page_edges).
|
|
7
|
+
*
|
|
8
|
+
* Cross-substrate bridges are synthesized for:
|
|
9
|
+
* - brain_page_edges whose to_id references a task (task:T-xxx → tasks:T-xxx)
|
|
10
|
+
* - brain_page_edges whose to_id is a nexus-style path (foo.ts::Symbol → nexus:...)
|
|
11
|
+
* - brain_memory_links rows (memory_type + memory_id → task_id link)
|
|
12
|
+
* - brain_observations.files_modified_json (observation → nexus file path)
|
|
13
|
+
*
|
|
14
|
+
* Node IDs are prefixed with "brain:" to prevent collisions.
|
|
15
|
+
*/
|
|
16
|
+
import type { BrainEdge, BrainNode, BrainQueryOptions } from '../types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Returns all BrainNodes and BrainEdges sourced from brain.db.
|
|
19
|
+
*
|
|
20
|
+
* Pulls from all four typed memory tables plus brain_page_edges.
|
|
21
|
+
* Emits intra-brain edges between loaded nodes, cross-substrate
|
|
22
|
+
* brain→tasks bridges, cross-substrate brain→nexus bridges, and
|
|
23
|
+
* brain_memory_links as cross-substrate edges.
|
|
24
|
+
*
|
|
25
|
+
* Applies `minWeight` filter where quality_score is available.
|
|
26
|
+
* Node count is bounded by `limit / 5` to share budget with other substrates.
|
|
27
|
+
*
|
|
28
|
+
* @param options - Query options (limit, minWeight).
|
|
29
|
+
* @returns Nodes and edges from the BRAIN substrate.
|
|
30
|
+
*/
|
|
31
|
+
export declare function getBrainSubstrate(options?: BrainQueryOptions): {
|
|
32
|
+
nodes: BrainNode[];
|
|
33
|
+
edges: BrainEdge[];
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=brain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brain.d.ts","sourceRoot":"","sources":["../../../src/adapters/brain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAyH3E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,iBAAsB,GAAG;IAClE,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB,CAwPA"}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BRAIN substrate adapter for the Living Brain API.
|
|
3
|
+
*
|
|
4
|
+
* Queries brain.db and returns BrainNodes/BrainEdges for all typed memory tables:
|
|
5
|
+
* observations, decisions, patterns, learnings, plus the graph layer
|
|
6
|
+
* (brain_page_nodes / brain_page_edges).
|
|
7
|
+
*
|
|
8
|
+
* Cross-substrate bridges are synthesized for:
|
|
9
|
+
* - brain_page_edges whose to_id references a task (task:T-xxx → tasks:T-xxx)
|
|
10
|
+
* - brain_page_edges whose to_id is a nexus-style path (foo.ts::Symbol → nexus:...)
|
|
11
|
+
* - brain_memory_links rows (memory_type + memory_id → task_id link)
|
|
12
|
+
* - brain_observations.files_modified_json (observation → nexus file path)
|
|
13
|
+
*
|
|
14
|
+
* Node IDs are prefixed with "brain:" to prevent collisions.
|
|
15
|
+
*/
|
|
16
|
+
import { allTyped, getBrainDb } from '../db-connections.js';
|
|
17
|
+
import { resolveDefaultProjectContext } from '../project-context.js';
|
|
18
|
+
/**
|
|
19
|
+
* Converts a brain_page_edges type-prefixed ID (e.g. "observation:O-abc")
|
|
20
|
+
* into the BrainNode ID prefix (e.g. "brain:O-abc").
|
|
21
|
+
*
|
|
22
|
+
* Returns null when the prefix is not a recognised brain type.
|
|
23
|
+
*
|
|
24
|
+
* @param typeId - Type-prefixed ID from brain_page_edges.from_id or to_id.
|
|
25
|
+
* @returns BrainNode-prefixed ID or null.
|
|
26
|
+
*/
|
|
27
|
+
function brainTypeIdToBrainNodeId(typeId) {
|
|
28
|
+
const sep = typeId.indexOf(':');
|
|
29
|
+
if (sep === -1)
|
|
30
|
+
return null;
|
|
31
|
+
const prefix = typeId.slice(0, sep);
|
|
32
|
+
const rawId = typeId.slice(sep + 1);
|
|
33
|
+
if (prefix === 'observation' ||
|
|
34
|
+
prefix === 'decision' ||
|
|
35
|
+
prefix === 'pattern' ||
|
|
36
|
+
prefix === 'learning') {
|
|
37
|
+
return `brain:${rawId}`;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Returns true when a brain_page_edges to_id looks like a nexus node path
|
|
43
|
+
* (contains "::" separator used by nexus for file::Symbol paths, or is a
|
|
44
|
+
* relative file path with a known extension).
|
|
45
|
+
*
|
|
46
|
+
* @param toId - to_id value from brain_page_edges.
|
|
47
|
+
* @returns True when the ID appears to reference a nexus node.
|
|
48
|
+
*/
|
|
49
|
+
function isNexusStyleId(toId) {
|
|
50
|
+
// Nexus symbol IDs contain :: (file::SymbolName)
|
|
51
|
+
if (toId.includes('::'))
|
|
52
|
+
return true;
|
|
53
|
+
// Nexus file IDs are relative paths (no type: prefix, contain a /)
|
|
54
|
+
if (!toId.includes(':') && toId.includes('/'))
|
|
55
|
+
return true;
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Returns true when a brain_page_edges ID looks like a task reference
|
|
60
|
+
* (e.g. "task:T532").
|
|
61
|
+
*
|
|
62
|
+
* @param id - ID from brain_page_edges.
|
|
63
|
+
* @returns True when the ID references a task node.
|
|
64
|
+
*/
|
|
65
|
+
function isTaskId(id) {
|
|
66
|
+
return id.startsWith('task:');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Converts a brain_page_edges task-reference to a tasks-substrate BrainNode ID.
|
|
70
|
+
* e.g. "task:T532" → "tasks:T532"
|
|
71
|
+
*
|
|
72
|
+
* @param taskRef - Task reference from brain_page_edges.
|
|
73
|
+
* @returns tasks-substrate BrainNode ID.
|
|
74
|
+
*/
|
|
75
|
+
function taskRefToBrainNodeId(taskRef) {
|
|
76
|
+
return `tasks:${taskRef.slice('task:'.length)}`;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Returns all BrainNodes and BrainEdges sourced from brain.db.
|
|
80
|
+
*
|
|
81
|
+
* Pulls from all four typed memory tables plus brain_page_edges.
|
|
82
|
+
* Emits intra-brain edges between loaded nodes, cross-substrate
|
|
83
|
+
* brain→tasks bridges, cross-substrate brain→nexus bridges, and
|
|
84
|
+
* brain_memory_links as cross-substrate edges.
|
|
85
|
+
*
|
|
86
|
+
* Applies `minWeight` filter where quality_score is available.
|
|
87
|
+
* Node count is bounded by `limit / 5` to share budget with other substrates.
|
|
88
|
+
*
|
|
89
|
+
* @param options - Query options (limit, minWeight).
|
|
90
|
+
* @returns Nodes and edges from the BRAIN substrate.
|
|
91
|
+
*/
|
|
92
|
+
export function getBrainSubstrate(options = {}) {
|
|
93
|
+
const ctx = options.projectCtx ?? resolveDefaultProjectContext();
|
|
94
|
+
const db = getBrainDb(ctx);
|
|
95
|
+
if (!db)
|
|
96
|
+
return { nodes: [], edges: [] };
|
|
97
|
+
const minWeight = options.minWeight ?? 0;
|
|
98
|
+
const perSubstrateLimit = Math.ceil((options.limit ?? 500) / 5);
|
|
99
|
+
const nodes = [];
|
|
100
|
+
const edges = [];
|
|
101
|
+
try {
|
|
102
|
+
// Observations — normalise created_at to ISO-8601 with 'T' separator via strftime
|
|
103
|
+
const obsRows = allTyped(db.prepare(`SELECT id, title, quality_score, memory_tier,
|
|
104
|
+
strftime('%Y-%m-%dT%H:%M:%S', created_at) AS created_at,
|
|
105
|
+
source_session_id, files_modified_json
|
|
106
|
+
FROM brain_observations
|
|
107
|
+
WHERE (quality_score IS NULL OR quality_score >= ?)
|
|
108
|
+
ORDER BY quality_score DESC, created_at DESC
|
|
109
|
+
LIMIT ?`), minWeight, Math.ceil(perSubstrateLimit * 0.4));
|
|
110
|
+
for (const row of obsRows) {
|
|
111
|
+
nodes.push({
|
|
112
|
+
id: `brain:${row.id}`,
|
|
113
|
+
kind: 'observation',
|
|
114
|
+
substrate: 'brain',
|
|
115
|
+
label: row.title,
|
|
116
|
+
weight: row.quality_score ?? undefined,
|
|
117
|
+
createdAt: row.created_at,
|
|
118
|
+
meta: {
|
|
119
|
+
memory_tier: row.memory_tier,
|
|
120
|
+
created_at: row.created_at,
|
|
121
|
+
source_session_id: row.source_session_id,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
// Decisions — normalise created_at to ISO-8601 with 'T' separator via strftime
|
|
126
|
+
const decRows = allTyped(db.prepare(`SELECT id, decision, quality_score, context_task_id,
|
|
127
|
+
strftime('%Y-%m-%dT%H:%M:%S', created_at) AS created_at
|
|
128
|
+
FROM brain_decisions
|
|
129
|
+
WHERE (quality_score IS NULL OR quality_score >= ?)
|
|
130
|
+
ORDER BY quality_score DESC, created_at DESC
|
|
131
|
+
LIMIT ?`), minWeight, Math.ceil(perSubstrateLimit * 0.25));
|
|
132
|
+
for (const row of decRows) {
|
|
133
|
+
nodes.push({
|
|
134
|
+
id: `brain:${row.id}`,
|
|
135
|
+
kind: 'decision',
|
|
136
|
+
substrate: 'brain',
|
|
137
|
+
label: row.decision.slice(0, 100),
|
|
138
|
+
weight: row.quality_score ?? undefined,
|
|
139
|
+
createdAt: row.created_at,
|
|
140
|
+
meta: {
|
|
141
|
+
context_task_id: row.context_task_id,
|
|
142
|
+
created_at: row.created_at,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// Patterns — uses 'pattern' text column (not 'title') and 'extracted_at' (not 'created_at').
|
|
147
|
+
// SQLite strftime is used to normalise the timestamp to ISO-8601 with 'T' separator.
|
|
148
|
+
const patRows = allTyped(db.prepare(`SELECT id, pattern, type, quality_score,
|
|
149
|
+
strftime('%Y-%m-%dT%H:%M:%S', extracted_at) AS extracted_at
|
|
150
|
+
FROM brain_patterns
|
|
151
|
+
WHERE (quality_score IS NULL OR quality_score >= ?)
|
|
152
|
+
ORDER BY quality_score DESC, extracted_at DESC
|
|
153
|
+
LIMIT ?`), minWeight, Math.ceil(perSubstrateLimit * 0.2));
|
|
154
|
+
for (const row of patRows) {
|
|
155
|
+
nodes.push({
|
|
156
|
+
id: `brain:${row.id}`,
|
|
157
|
+
kind: 'pattern',
|
|
158
|
+
substrate: 'brain',
|
|
159
|
+
label: row.pattern.slice(0, 100),
|
|
160
|
+
weight: row.quality_score ?? undefined,
|
|
161
|
+
createdAt: row.extracted_at,
|
|
162
|
+
meta: { pattern_type: row.type, created_at: row.extracted_at },
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
// Learnings — uses 'insight' text column (not 'title').
|
|
166
|
+
// Normalise created_at to ISO-8601 with 'T' separator via strftime.
|
|
167
|
+
const learnRows = allTyped(db.prepare(`SELECT id, insight, quality_score,
|
|
168
|
+
strftime('%Y-%m-%dT%H:%M:%S', created_at) AS created_at
|
|
169
|
+
FROM brain_learnings
|
|
170
|
+
WHERE (quality_score IS NULL OR quality_score >= ?)
|
|
171
|
+
ORDER BY quality_score DESC, created_at DESC
|
|
172
|
+
LIMIT ?`), minWeight, Math.ceil(perSubstrateLimit * 0.15));
|
|
173
|
+
for (const row of learnRows) {
|
|
174
|
+
nodes.push({
|
|
175
|
+
id: `brain:${row.id}`,
|
|
176
|
+
kind: 'learning',
|
|
177
|
+
substrate: 'brain',
|
|
178
|
+
label: row.insight.slice(0, 100),
|
|
179
|
+
weight: row.quality_score ?? undefined,
|
|
180
|
+
createdAt: row.created_at,
|
|
181
|
+
meta: { created_at: row.created_at },
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
// Build lookup: type-prefixed ID (e.g. "observation:O-abc") → BrainNode ID
|
|
185
|
+
// (e.g. "brain:O-abc"). This is needed because brain_page_edges stores
|
|
186
|
+
// IDs in type-prefixed format while BrainNode IDs use the "brain:" prefix.
|
|
187
|
+
const typeIdToBrainNodeId = new Map();
|
|
188
|
+
for (const n of nodes) {
|
|
189
|
+
const rawId = n.id.slice('brain:'.length);
|
|
190
|
+
// Determine which type prefix this node would have in brain_page_edges
|
|
191
|
+
let typePrefix;
|
|
192
|
+
if (n.kind === 'observation')
|
|
193
|
+
typePrefix = 'observation';
|
|
194
|
+
else if (n.kind === 'decision')
|
|
195
|
+
typePrefix = 'decision';
|
|
196
|
+
else if (n.kind === 'pattern')
|
|
197
|
+
typePrefix = 'pattern';
|
|
198
|
+
else
|
|
199
|
+
typePrefix = 'learning';
|
|
200
|
+
typeIdToBrainNodeId.set(`${typePrefix}:${rawId}`, n.id);
|
|
201
|
+
}
|
|
202
|
+
// brain_page_edges: query all and classify each edge
|
|
203
|
+
const pageEdgeRows = allTyped(db.prepare(`SELECT from_id, to_id, edge_type, weight FROM brain_page_edges`));
|
|
204
|
+
for (const row of pageEdgeRows) {
|
|
205
|
+
const sourceBrainNodeId = typeIdToBrainNodeId.get(row.from_id) ?? brainTypeIdToBrainNodeId(row.from_id);
|
|
206
|
+
if (!sourceBrainNodeId)
|
|
207
|
+
continue; // source not a recognised brain node
|
|
208
|
+
if (isTaskId(row.to_id)) {
|
|
209
|
+
// Cross-substrate: brain → tasks
|
|
210
|
+
edges.push({
|
|
211
|
+
source: sourceBrainNodeId,
|
|
212
|
+
target: taskRefToBrainNodeId(row.to_id),
|
|
213
|
+
type: row.edge_type,
|
|
214
|
+
weight: row.weight ?? 0.5,
|
|
215
|
+
substrate: 'cross',
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
else if (isNexusStyleId(row.to_id)) {
|
|
219
|
+
// Cross-substrate: brain → nexus (code_reference, etc.)
|
|
220
|
+
edges.push({
|
|
221
|
+
source: sourceBrainNodeId,
|
|
222
|
+
target: `nexus:${row.to_id}`,
|
|
223
|
+
type: row.edge_type,
|
|
224
|
+
weight: row.weight ?? 0.5,
|
|
225
|
+
substrate: 'cross',
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// Intra-brain: both IDs should be brain nodes
|
|
230
|
+
const targetBrainNodeId = typeIdToBrainNodeId.get(row.to_id) ?? brainTypeIdToBrainNodeId(row.to_id);
|
|
231
|
+
if (targetBrainNodeId) {
|
|
232
|
+
edges.push({
|
|
233
|
+
source: sourceBrainNodeId,
|
|
234
|
+
target: targetBrainNodeId,
|
|
235
|
+
type: row.edge_type,
|
|
236
|
+
weight: row.weight ?? 0.5,
|
|
237
|
+
substrate: 'brain',
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// brain_memory_links: cross-substrate edges from typed memory nodes to tasks
|
|
243
|
+
const memLinkRows = allTyped(db.prepare(`SELECT memory_type, memory_id, task_id, link_type
|
|
244
|
+
FROM brain_memory_links`));
|
|
245
|
+
for (const row of memLinkRows) {
|
|
246
|
+
const sourceTypeId = `${row.memory_type}:${row.memory_id}`;
|
|
247
|
+
const sourceBrainNodeId = typeIdToBrainNodeId.get(sourceTypeId) ?? brainTypeIdToBrainNodeId(sourceTypeId);
|
|
248
|
+
if (!sourceBrainNodeId)
|
|
249
|
+
continue; // source node not in loaded set
|
|
250
|
+
edges.push({
|
|
251
|
+
source: sourceBrainNodeId,
|
|
252
|
+
target: `tasks:${row.task_id}`,
|
|
253
|
+
type: row.link_type,
|
|
254
|
+
weight: 0.7,
|
|
255
|
+
substrate: 'cross',
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
// brain_observations.files_modified_json: cross-substrate observation → nexus file
|
|
259
|
+
for (const row of obsRows) {
|
|
260
|
+
if (!row.files_modified_json)
|
|
261
|
+
continue;
|
|
262
|
+
let filePaths;
|
|
263
|
+
try {
|
|
264
|
+
filePaths = JSON.parse(row.files_modified_json);
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (!Array.isArray(filePaths))
|
|
270
|
+
continue;
|
|
271
|
+
const sourceBrainNodeId = `brain:${row.id}`;
|
|
272
|
+
for (const rawPath of filePaths) {
|
|
273
|
+
if (typeof rawPath !== 'string' || rawPath.length === 0)
|
|
274
|
+
continue;
|
|
275
|
+
edges.push({
|
|
276
|
+
source: sourceBrainNodeId,
|
|
277
|
+
target: `nexus:${rawPath}`,
|
|
278
|
+
type: 'modified_by',
|
|
279
|
+
weight: 0.6,
|
|
280
|
+
substrate: 'cross',
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// Soft FK: brain_decisions.context_task_id → tasks (direct, not via page_edges)
|
|
285
|
+
// This handles decisions whose context_task_id may not yet appear in brain_page_edges.
|
|
286
|
+
for (const dec of decRows) {
|
|
287
|
+
if (dec.context_task_id) {
|
|
288
|
+
edges.push({
|
|
289
|
+
source: `brain:${dec.id}`,
|
|
290
|
+
target: `tasks:${dec.context_task_id}`,
|
|
291
|
+
type: 'applies_to',
|
|
292
|
+
weight: 0.8,
|
|
293
|
+
substrate: 'cross',
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
// Return partial results on error
|
|
300
|
+
}
|
|
301
|
+
return { nodes, edges };
|
|
302
|
+
}
|
|
303
|
+
//# sourceMappingURL=brain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brain.js","sourceRoot":"","sources":["../../../src/adapters/brain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CONDUIT substrate adapter for the Living Brain API.
|
|
3
|
+
*
|
|
4
|
+
* Queries conduit.db and returns BrainNodes/BrainEdges for agent-to-agent messages.
|
|
5
|
+
* Each message becomes a node; `from_agent_id → to_agent_id` becomes an edge.
|
|
6
|
+
* Co-authoring agent pairs produce cross-substrate edges to SIGNALDOCK.
|
|
7
|
+
*
|
|
8
|
+
* Node IDs are prefixed with "conduit:" to prevent collisions.
|
|
9
|
+
*/
|
|
10
|
+
import type { BrainEdge, BrainNode, BrainQueryOptions } from '../types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Returns all BrainNodes and BrainEdges sourced from conduit.db.
|
|
13
|
+
*
|
|
14
|
+
* Fetches the most recent messages (capped at perSubstrateLimit).
|
|
15
|
+
* Synthesizes agent→agent edges and cross-substrate agent references
|
|
16
|
+
* pointing to signaldock.
|
|
17
|
+
*
|
|
18
|
+
* @param options - Query options (limit).
|
|
19
|
+
* @returns Nodes and edges from the CONDUIT substrate.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getConduitSubstrate(options?: BrainQueryOptions): {
|
|
22
|
+
nodes: BrainNode[];
|
|
23
|
+
edges: BrainEdge[];
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=conduit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conduit.d.ts","sourceRoot":"","sources":["../../../src/adapters/conduit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAyB3E;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,iBAAsB,GAAG;IACpE,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB,CAqEA"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CONDUIT substrate adapter for the Living Brain API.
|
|
3
|
+
*
|
|
4
|
+
* Queries conduit.db and returns BrainNodes/BrainEdges for agent-to-agent messages.
|
|
5
|
+
* Each message becomes a node; `from_agent_id → to_agent_id` becomes an edge.
|
|
6
|
+
* Co-authoring agent pairs produce cross-substrate edges to SIGNALDOCK.
|
|
7
|
+
*
|
|
8
|
+
* Node IDs are prefixed with "conduit:" to prevent collisions.
|
|
9
|
+
*/
|
|
10
|
+
import { allTyped, getConduitDb } from '../db-connections.js';
|
|
11
|
+
import { resolveDefaultProjectContext } from '../project-context.js';
|
|
12
|
+
/**
|
|
13
|
+
* Converts a UNIX epoch seconds value to an ISO-8601 string.
|
|
14
|
+
* Returns null when the value is not a finite positive number.
|
|
15
|
+
*
|
|
16
|
+
* @param epoch - UNIX timestamp in seconds.
|
|
17
|
+
* @returns ISO-8601 string or null.
|
|
18
|
+
*/
|
|
19
|
+
function epochToIso(epoch) {
|
|
20
|
+
if (!Number.isFinite(epoch) || epoch <= 0)
|
|
21
|
+
return null;
|
|
22
|
+
return new Date(epoch * 1000).toISOString();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Returns all BrainNodes and BrainEdges sourced from conduit.db.
|
|
26
|
+
*
|
|
27
|
+
* Fetches the most recent messages (capped at perSubstrateLimit).
|
|
28
|
+
* Synthesizes agent→agent edges and cross-substrate agent references
|
|
29
|
+
* pointing to signaldock.
|
|
30
|
+
*
|
|
31
|
+
* @param options - Query options (limit).
|
|
32
|
+
* @returns Nodes and edges from the CONDUIT substrate.
|
|
33
|
+
*/
|
|
34
|
+
export function getConduitSubstrate(options = {}) {
|
|
35
|
+
const ctx = options.projectCtx ?? resolveDefaultProjectContext();
|
|
36
|
+
const db = getConduitDb(ctx);
|
|
37
|
+
if (!db)
|
|
38
|
+
return { nodes: [], edges: [] };
|
|
39
|
+
const perSubstrateLimit = Math.ceil((options.limit ?? 500) / 5);
|
|
40
|
+
const nodes = [];
|
|
41
|
+
const edges = [];
|
|
42
|
+
try {
|
|
43
|
+
// Most recent messages
|
|
44
|
+
const msgRows = allTyped(db.prepare(`SELECT id, content, from_agent_id, to_agent_id, created_at, conversation_id
|
|
45
|
+
FROM messages
|
|
46
|
+
ORDER BY created_at DESC
|
|
47
|
+
LIMIT ?`), perSubstrateLimit);
|
|
48
|
+
const agentPairs = new Map();
|
|
49
|
+
for (const row of msgRows) {
|
|
50
|
+
// Message node — truncate content for label
|
|
51
|
+
const label = row.content.length > 80 ? `${row.content.slice(0, 80)}…` : row.content;
|
|
52
|
+
nodes.push({
|
|
53
|
+
id: `conduit:${row.id}`,
|
|
54
|
+
kind: 'message',
|
|
55
|
+
substrate: 'conduit',
|
|
56
|
+
label,
|
|
57
|
+
createdAt: epochToIso(row.created_at),
|
|
58
|
+
meta: {
|
|
59
|
+
from_agent_id: row.from_agent_id,
|
|
60
|
+
to_agent_id: row.to_agent_id,
|
|
61
|
+
conversation_id: row.conversation_id,
|
|
62
|
+
created_at: row.created_at,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
// Aggregate agent pairs for social-graph edges
|
|
66
|
+
if (row.from_agent_id && row.to_agent_id) {
|
|
67
|
+
const key = `${row.from_agent_id}→${row.to_agent_id}`;
|
|
68
|
+
const existing = agentPairs.get(key);
|
|
69
|
+
if (existing) {
|
|
70
|
+
existing.count++;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
agentPairs.set(key, { count: 1, from: row.from_agent_id, to: row.to_agent_id });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Cross-substrate: agent social graph edges pointing to signaldock agent nodes
|
|
78
|
+
for (const [, pair] of agentPairs) {
|
|
79
|
+
const weight = Math.min(1.0, pair.count / 10);
|
|
80
|
+
edges.push({
|
|
81
|
+
source: `agent-registry:${pair.from}`,
|
|
82
|
+
target: `agent-registry:${pair.to}`,
|
|
83
|
+
type: 'messages',
|
|
84
|
+
weight,
|
|
85
|
+
substrate: 'cross',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Return partial results on error
|
|
91
|
+
}
|
|
92
|
+
return { nodes, edges };
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=conduit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conduit.js","sourceRoot":"","sources":["../../../src/adapters/conduit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel for all substrate adapters.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports individual adapter functions and provides the unified
|
|
5
|
+
* `getAllSubstrates()` function that merges results from all five databases
|
|
6
|
+
* into a single BrainGraph.
|
|
7
|
+
*/
|
|
8
|
+
export { getAgentRegistrySubstrate } from './agent-registry.js';
|
|
9
|
+
export { getBrainSubstrate } from './brain.js';
|
|
10
|
+
export { getConduitSubstrate } from './conduit.js';
|
|
11
|
+
export { getNexusSubstrate } from './nexus.js';
|
|
12
|
+
export { getTasksSubstrate } from './tasks.js';
|
|
13
|
+
import type { BrainGraph, BrainQueryOptions } from '../types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Queries all five substrates and merges the results into a unified BrainGraph.
|
|
16
|
+
*
|
|
17
|
+
* When `options.substrates` is provided, only those substrates are queried.
|
|
18
|
+
* Node IDs are substrate-prefixed, so deduplication is safe to perform
|
|
19
|
+
* by ID equality alone.
|
|
20
|
+
*
|
|
21
|
+
* After all substrates are loaded, performs a second-pass stub-node load:
|
|
22
|
+
* any edge target ID not yet in the loaded node set is fetched as a minimal
|
|
23
|
+
* stub (id, substrate, kind, label). This recovers cross-substrate edges
|
|
24
|
+
* that would otherwise be silently dropped.
|
|
25
|
+
*
|
|
26
|
+
* Stub nodes carry `meta.isStub: true` for optional UI differentiation.
|
|
27
|
+
*
|
|
28
|
+
* @param options - Query options forwarded to each substrate adapter.
|
|
29
|
+
* @returns Merged BrainGraph across all requested substrates, with stub nodes for unresolved edge targets.
|
|
30
|
+
*/
|
|
31
|
+
export declare function getAllSubstrates(options?: BrainQueryOptions): BrainGraph;
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|