rust-kgdb 0.5.6 → 0.5.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/CHANGELOG.md +205 -0
- package/README.md +812 -36
- package/examples/embeddings-example.ts +4 -4
- package/examples/hypermind-agent-architecture.js +1709 -0
- package/hypermind-agent.js +636 -1
- package/index.d.ts +248 -0
- package/package.json +1 -1
package/hypermind-agent.js
CHANGED
|
@@ -5,11 +5,637 @@
|
|
|
5
5
|
* Given the same tools (access to a Mixedbread retriever and document access),
|
|
6
6
|
* LLMs score X% with HyperMind compared to Y% without.
|
|
7
7
|
*
|
|
8
|
+
* Architecture Components:
|
|
9
|
+
* - TypeId: Hindley-Milner type system with refinement types
|
|
10
|
+
* - LLMPlanner: Natural language to typed tool pipelines
|
|
11
|
+
* - WasmSandbox: Capability-based security with fuel metering
|
|
12
|
+
* - ObjectProxy: gRPC-style tool invocation with audit logging
|
|
13
|
+
* - AgentBuilder: Fluent builder pattern for agent composition
|
|
14
|
+
*
|
|
8
15
|
* @module hypermind-agent
|
|
9
16
|
*/
|
|
10
17
|
|
|
11
18
|
const http = require('http')
|
|
12
19
|
const https = require('https')
|
|
20
|
+
const crypto = require('crypto')
|
|
21
|
+
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// TYPE SYSTEM (Hindley-Milner + Refinement Types)
|
|
24
|
+
// ============================================================================
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* TypeId - Complete type system for HyperMind
|
|
28
|
+
* Based on Hindley-Milner with refinement types for business domains
|
|
29
|
+
*/
|
|
30
|
+
const TypeId = {
|
|
31
|
+
// Base types
|
|
32
|
+
String: 'String',
|
|
33
|
+
Int64: 'Int64',
|
|
34
|
+
Float64: 'Float64',
|
|
35
|
+
Bool: 'Bool',
|
|
36
|
+
Unit: 'Unit',
|
|
37
|
+
|
|
38
|
+
// RDF-native types (knowledge graph first-class citizens)
|
|
39
|
+
Node: 'Node',
|
|
40
|
+
Triple: 'Triple',
|
|
41
|
+
Quad: 'Quad',
|
|
42
|
+
BindingSet: 'BindingSet',
|
|
43
|
+
|
|
44
|
+
// Compound types (higher-kinded)
|
|
45
|
+
List: (t) => `List<${t}>`,
|
|
46
|
+
Option: (t) => `Option<${t}>`,
|
|
47
|
+
Result: (t, e) => `Result<${t}, ${e}>`,
|
|
48
|
+
Map: (k, v) => `Map<${k}, ${v}>`,
|
|
49
|
+
|
|
50
|
+
// Refinement types (business domain values with constraints)
|
|
51
|
+
RiskScore: 'RiskScore', // Float64 where 0.0 <= x <= 1.0
|
|
52
|
+
PolicyNumber: 'PolicyNumber', // String matching /^POL-\d{4}-\d{4}$/
|
|
53
|
+
ClaimAmount: 'ClaimAmount', // Currency where amount > 0
|
|
54
|
+
ClaimId: 'ClaimId', // String matching /^CLM-\d{4}-\d+$/
|
|
55
|
+
CreditScore: 'CreditScore', // Int64 where 300 <= x <= 850
|
|
56
|
+
ConfidenceScore: 'ConfidenceScore', // Float64 where 0.0 <= x <= 1.0
|
|
57
|
+
|
|
58
|
+
// Schema types (for type-safe graph queries)
|
|
59
|
+
SchemaType: (name) => `Schema<${name}>`,
|
|
60
|
+
|
|
61
|
+
// Type checking utilities
|
|
62
|
+
isCompatible: (output, input) => {
|
|
63
|
+
if (output === input) return true
|
|
64
|
+
if (output === 'BindingSet' && input === 'String') return true
|
|
65
|
+
if (output.startsWith('List<') && input === 'String') return true
|
|
66
|
+
return false
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// TOOL REGISTRY (Typed Morphisms)
|
|
72
|
+
// ============================================================================
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* TOOL_REGISTRY - All available tools as typed morphisms
|
|
76
|
+
* Each tool is an arrow in the category of types: A -> B
|
|
77
|
+
*/
|
|
78
|
+
const TOOL_REGISTRY = {
|
|
79
|
+
'kg.sparql.query': {
|
|
80
|
+
name: 'kg.sparql.query',
|
|
81
|
+
input: TypeId.String,
|
|
82
|
+
output: TypeId.BindingSet,
|
|
83
|
+
description: 'Execute SPARQL SELECT query against knowledge graph',
|
|
84
|
+
domain: 'knowledge_graph',
|
|
85
|
+
constraints: { readOnly: true, maxResults: 10000, timeout: 30000 }
|
|
86
|
+
},
|
|
87
|
+
'kg.sparql.construct': {
|
|
88
|
+
name: 'kg.sparql.construct',
|
|
89
|
+
input: TypeId.String,
|
|
90
|
+
output: TypeId.List('Triple'),
|
|
91
|
+
description: 'Execute SPARQL CONSTRUCT to build new triples',
|
|
92
|
+
domain: 'knowledge_graph',
|
|
93
|
+
constraints: { readOnly: true }
|
|
94
|
+
},
|
|
95
|
+
'kg.sparql.update': {
|
|
96
|
+
name: 'kg.sparql.update',
|
|
97
|
+
input: TypeId.String,
|
|
98
|
+
output: TypeId.Unit,
|
|
99
|
+
description: 'Execute SPARQL UPDATE operations',
|
|
100
|
+
domain: 'knowledge_graph',
|
|
101
|
+
constraints: { readOnly: false }
|
|
102
|
+
},
|
|
103
|
+
'kg.motif.find': {
|
|
104
|
+
name: 'kg.motif.find',
|
|
105
|
+
input: TypeId.String,
|
|
106
|
+
output: TypeId.List('Match'),
|
|
107
|
+
description: 'Find graph motif patterns (fraud rings, cycles)',
|
|
108
|
+
domain: 'graph_analytics',
|
|
109
|
+
patterns: {
|
|
110
|
+
'collusion': '(a)-[claims_with]->(p); (b)-[claims_with]->(p); (a)-[knows]->(b)',
|
|
111
|
+
'circular_payment': '(a)-[paid]->(b); (b)-[paid]->(c); (c)-[paid]->(a)',
|
|
112
|
+
'star_pattern': '(center)-[]->(a); (center)-[]->(b); (center)-[]->(c)'
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
'kg.datalog.infer': {
|
|
116
|
+
name: 'kg.datalog.infer',
|
|
117
|
+
input: TypeId.List('Rule'),
|
|
118
|
+
output: TypeId.List('Fact'),
|
|
119
|
+
description: 'Apply Datalog rules for logical inference',
|
|
120
|
+
domain: 'reasoning',
|
|
121
|
+
prebuiltRules: {
|
|
122
|
+
'potential_collusion': 'Claimants who know each other using same provider',
|
|
123
|
+
'staged_accident': 'Soft tissue claims with high amounts in first 90 days',
|
|
124
|
+
'organized_fraud': 'High prior claims + high provider volume'
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
'kg.embeddings.search': {
|
|
128
|
+
name: 'kg.embeddings.search',
|
|
129
|
+
input: TypeId.String,
|
|
130
|
+
output: TypeId.List('SimilarEntity'),
|
|
131
|
+
description: 'Find semantically similar entities via HNSW index',
|
|
132
|
+
domain: 'embeddings',
|
|
133
|
+
constraints: { maxK: 100, minThreshold: 0.0, maxThreshold: 1.0 }
|
|
134
|
+
},
|
|
135
|
+
'kg.graphframe.pagerank': {
|
|
136
|
+
name: 'kg.graphframe.pagerank',
|
|
137
|
+
input: TypeId.Map('String', 'Float64'),
|
|
138
|
+
output: TypeId.Map('String', 'Float64'),
|
|
139
|
+
description: 'Compute PageRank to find central entities',
|
|
140
|
+
domain: 'graph_analytics'
|
|
141
|
+
},
|
|
142
|
+
'kg.graphframe.triangles': {
|
|
143
|
+
name: 'kg.graphframe.triangles',
|
|
144
|
+
input: TypeId.String,
|
|
145
|
+
output: TypeId.Int64,
|
|
146
|
+
description: 'Count triangles in graph (fraud ring indicator)',
|
|
147
|
+
domain: 'graph_analytics'
|
|
148
|
+
},
|
|
149
|
+
'kg.graphframe.components': {
|
|
150
|
+
name: 'kg.graphframe.components',
|
|
151
|
+
input: TypeId.String,
|
|
152
|
+
output: TypeId.Map('String', 'Int64'),
|
|
153
|
+
description: 'Find connected components (network clusters)',
|
|
154
|
+
domain: 'graph_analytics'
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ============================================================================
|
|
159
|
+
// LLM PLANNER (Natural Language -> Typed Tool Pipelines)
|
|
160
|
+
// ============================================================================
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* LLMPlanner - Converts natural language to validated tool pipelines
|
|
164
|
+
* Implements type checking before execution (Curry-Howard correspondence)
|
|
165
|
+
*/
|
|
166
|
+
class LLMPlanner {
|
|
167
|
+
constructor(model, tools = TOOL_REGISTRY) {
|
|
168
|
+
this.model = model // 'claude-sonnet-4' | 'gpt-4o' | 'mock'
|
|
169
|
+
this.tools = tools
|
|
170
|
+
this.planHistory = []
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Generate an execution plan from natural language
|
|
175
|
+
* @param {string} prompt - Natural language request
|
|
176
|
+
* @param {object} context - Additional context (history, domain hints)
|
|
177
|
+
* @returns {object} Validated execution plan
|
|
178
|
+
*/
|
|
179
|
+
async plan(prompt, context = {}) {
|
|
180
|
+
// Step 1: Decompose natural language into intent
|
|
181
|
+
const intent = this.decomposeIntent(prompt)
|
|
182
|
+
|
|
183
|
+
// Step 2: Select tools based on intent
|
|
184
|
+
const selectedTools = this.selectTools(intent)
|
|
185
|
+
|
|
186
|
+
// Step 3: Validate type composition
|
|
187
|
+
const validation = this.validateComposition(selectedTools)
|
|
188
|
+
if (!validation.valid) {
|
|
189
|
+
throw new Error(`Type composition error: ${validation.error}`)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Step 4: Generate execution plan
|
|
193
|
+
const plan = {
|
|
194
|
+
id: `plan_${Date.now()}`,
|
|
195
|
+
prompt,
|
|
196
|
+
intent,
|
|
197
|
+
steps: selectedTools.map((tool, i) => ({
|
|
198
|
+
id: i + 1,
|
|
199
|
+
tool: tool.name,
|
|
200
|
+
input_type: tool.input,
|
|
201
|
+
output_type: tool.output,
|
|
202
|
+
args: this.generateArgs(tool, intent, context)
|
|
203
|
+
})),
|
|
204
|
+
type_chain: validation.chain,
|
|
205
|
+
confidence: this.calculateConfidence(intent, selectedTools),
|
|
206
|
+
explanation: `Execute ${intent.action} using ${selectedTools.length} tools`
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
this.planHistory.push(plan)
|
|
210
|
+
return plan
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Decompose natural language into structured intent
|
|
215
|
+
*/
|
|
216
|
+
decomposeIntent(prompt) {
|
|
217
|
+
const lowerPrompt = prompt.toLowerCase()
|
|
218
|
+
|
|
219
|
+
if (lowerPrompt.includes('suspicious') || lowerPrompt.includes('fraud')) {
|
|
220
|
+
return {
|
|
221
|
+
action: 'detect_fraud',
|
|
222
|
+
target: 'claims',
|
|
223
|
+
domain: 'insurance_fraud',
|
|
224
|
+
entities: ['claims', 'claimants', 'providers']
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (lowerPrompt.includes('similar') || lowerPrompt.includes('like')) {
|
|
229
|
+
return {
|
|
230
|
+
action: 'find_similar',
|
|
231
|
+
target: 'entities',
|
|
232
|
+
domain: 'embeddings'
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (lowerPrompt.includes('rule') || lowerPrompt.includes('proof')) {
|
|
237
|
+
return {
|
|
238
|
+
action: 'explain_derivation',
|
|
239
|
+
target: 'inference',
|
|
240
|
+
domain: 'reasoning'
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (lowerPrompt.includes('professor') || lowerPrompt.includes('student')) {
|
|
245
|
+
return {
|
|
246
|
+
action: 'query',
|
|
247
|
+
target: 'academic',
|
|
248
|
+
domain: 'lubm'
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
action: 'query',
|
|
254
|
+
target: 'knowledge_graph',
|
|
255
|
+
domain: 'general'
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Select tools based on intent
|
|
261
|
+
*/
|
|
262
|
+
selectTools(intent) {
|
|
263
|
+
const toolsByAction = {
|
|
264
|
+
'detect_fraud': [
|
|
265
|
+
this.tools['kg.sparql.query'],
|
|
266
|
+
this.tools['kg.graphframe.triangles'],
|
|
267
|
+
this.tools['kg.datalog.infer']
|
|
268
|
+
],
|
|
269
|
+
'find_similar': [
|
|
270
|
+
this.tools['kg.embeddings.search']
|
|
271
|
+
],
|
|
272
|
+
'explain_derivation': [
|
|
273
|
+
this.tools['kg.datalog.infer']
|
|
274
|
+
],
|
|
275
|
+
'query': [
|
|
276
|
+
this.tools['kg.sparql.query']
|
|
277
|
+
]
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return toolsByAction[intent.action] || [this.tools['kg.sparql.query']]
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Validate type composition (Category Theory morphism composition)
|
|
285
|
+
*/
|
|
286
|
+
validateComposition(tools) {
|
|
287
|
+
for (let i = 0; i < tools.length - 1; i++) {
|
|
288
|
+
const current = tools[i]
|
|
289
|
+
const next = tools[i + 1]
|
|
290
|
+
if (!TypeId.isCompatible(current.output, next.input)) {
|
|
291
|
+
return {
|
|
292
|
+
valid: false,
|
|
293
|
+
error: `${current.name}.output (${current.output}) is incompatible with ${next.name}.input (${next.input})`
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const chain = tools.map(t => t.input).join(' -> ') + ' -> ' + tools[tools.length - 1].output
|
|
299
|
+
return { valid: true, chain }
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Generate tool-specific arguments
|
|
304
|
+
*/
|
|
305
|
+
generateArgs(tool, intent, context) {
|
|
306
|
+
switch (tool.name) {
|
|
307
|
+
case 'kg.sparql.query':
|
|
308
|
+
return { query: this._generateSPARQL(intent) }
|
|
309
|
+
case 'kg.graphframe.triangles':
|
|
310
|
+
return { graph: 'default' }
|
|
311
|
+
case 'kg.datalog.infer':
|
|
312
|
+
return { rules: ['potential_collusion', 'staged_accident'] }
|
|
313
|
+
case 'kg.embeddings.search':
|
|
314
|
+
return { entityId: intent.entities?.[0] || 'unknown', k: 10, threshold: 0.7 }
|
|
315
|
+
default:
|
|
316
|
+
return {}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
_generateSPARQL(intent) {
|
|
321
|
+
if (intent.domain === 'insurance_fraud') {
|
|
322
|
+
return `PREFIX ins: <http://insurance.example.org/>
|
|
323
|
+
SELECT ?claim ?claimant ?amount ?riskScore
|
|
324
|
+
WHERE {
|
|
325
|
+
?claim a ins:Claim ;
|
|
326
|
+
ins:claimant ?claimant ;
|
|
327
|
+
ins:amount ?amount ;
|
|
328
|
+
ins:riskScore ?riskScore .
|
|
329
|
+
FILTER (?riskScore > 0.7)
|
|
330
|
+
}`
|
|
331
|
+
}
|
|
332
|
+
return 'SELECT * WHERE { ?s ?p ?o } LIMIT 10'
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
calculateConfidence(intent, tools) {
|
|
336
|
+
const baseConfidence = 0.85
|
|
337
|
+
const toolBonus = tools.length * 0.02
|
|
338
|
+
const intentBonus = intent.domain === 'insurance_fraud' ? 0.05 : 0
|
|
339
|
+
return Math.min(0.99, baseConfidence + toolBonus + intentBonus)
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// ============================================================================
|
|
344
|
+
// WASM SANDBOX (Capability-Based Security)
|
|
345
|
+
// ============================================================================
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* WasmSandbox - Secure WASM execution environment with capabilities
|
|
349
|
+
*
|
|
350
|
+
* All interaction with the Rust core flows through WASM for complete security:
|
|
351
|
+
* - Isolated linear memory (no direct host access)
|
|
352
|
+
* - CPU fuel metering (configurable operation limits)
|
|
353
|
+
* - Capability-based permissions (ReadKG, WriteKG, ExecuteTool)
|
|
354
|
+
* - Memory limits (configurable maximum allocation)
|
|
355
|
+
* - Full audit logging (all tool invocations recorded)
|
|
356
|
+
*
|
|
357
|
+
* The WASM sandbox ensures that agent tool execution cannot:
|
|
358
|
+
* - Access the filesystem
|
|
359
|
+
* - Make unauthorized network calls
|
|
360
|
+
* - Exceed allocated resources
|
|
361
|
+
* - Bypass security boundaries
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* const sandbox = new WasmSandbox({
|
|
365
|
+
* capabilities: ['ReadKG', 'ExecuteTool'],
|
|
366
|
+
* fuelLimit: 1000000,
|
|
367
|
+
* maxMemory: 64 * 1024 * 1024
|
|
368
|
+
* })
|
|
369
|
+
*/
|
|
370
|
+
class WasmSandbox {
|
|
371
|
+
constructor(config = {}) {
|
|
372
|
+
this.config = {
|
|
373
|
+
maxMemory: config.maxMemory || 64 * 1024 * 1024, // 64MB
|
|
374
|
+
maxExecTime: config.maxExecTime || 10000, // 10 seconds
|
|
375
|
+
capabilities: config.capabilities || ['ReadKG', 'ExecuteTool'],
|
|
376
|
+
fuelLimit: config.fuelLimit || 1000000 // 1M fuel units
|
|
377
|
+
}
|
|
378
|
+
this.fuel = this.config.fuelLimit
|
|
379
|
+
this.memoryUsed = 0
|
|
380
|
+
this.auditLog = []
|
|
381
|
+
this.startTime = null
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Create an Object Proxy for gRPC-style tool invocation
|
|
386
|
+
*/
|
|
387
|
+
createObjectProxy(tools) {
|
|
388
|
+
const sandbox = this
|
|
389
|
+
|
|
390
|
+
return new Proxy({}, {
|
|
391
|
+
get(target, toolName) {
|
|
392
|
+
return async (args) => {
|
|
393
|
+
// Security Check 1: Capability verification
|
|
394
|
+
if (!sandbox.hasCapability('ExecuteTool')) {
|
|
395
|
+
const error = `BLOCKED: Missing ExecuteTool capability`
|
|
396
|
+
sandbox._logAudit(toolName, args, null, 'DENIED', error)
|
|
397
|
+
throw new Error(error)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Security Check 2: Fuel metering
|
|
401
|
+
const fuelCost = sandbox._calculateFuelCost(toolName, args)
|
|
402
|
+
if (sandbox.fuel < fuelCost) {
|
|
403
|
+
const error = `BLOCKED: Insufficient fuel (need ${fuelCost}, have ${sandbox.fuel})`
|
|
404
|
+
sandbox._logAudit(toolName, args, null, 'DENIED', error)
|
|
405
|
+
throw new Error(error)
|
|
406
|
+
}
|
|
407
|
+
sandbox.fuel -= fuelCost
|
|
408
|
+
|
|
409
|
+
// Security Check 3: Memory bounds
|
|
410
|
+
const estimatedMemory = JSON.stringify(args).length * 2
|
|
411
|
+
if (sandbox.memoryUsed + estimatedMemory > sandbox.config.maxMemory) {
|
|
412
|
+
const error = `BLOCKED: Memory limit exceeded`
|
|
413
|
+
sandbox._logAudit(toolName, args, null, 'DENIED', error)
|
|
414
|
+
throw new Error(error)
|
|
415
|
+
}
|
|
416
|
+
sandbox.memoryUsed += estimatedMemory
|
|
417
|
+
|
|
418
|
+
// Security Check 4: Execution time
|
|
419
|
+
if (!sandbox.startTime) {
|
|
420
|
+
sandbox.startTime = Date.now()
|
|
421
|
+
}
|
|
422
|
+
if (Date.now() - sandbox.startTime > sandbox.config.maxExecTime) {
|
|
423
|
+
const error = `BLOCKED: Execution time limit exceeded`
|
|
424
|
+
sandbox._logAudit(toolName, args, null, 'DENIED', error)
|
|
425
|
+
throw new Error(error)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Execute tool
|
|
429
|
+
const tool = tools[toolName]
|
|
430
|
+
if (!tool) {
|
|
431
|
+
const error = `BLOCKED: Unknown tool ${toolName}`
|
|
432
|
+
sandbox._logAudit(toolName, args, null, 'DENIED', error)
|
|
433
|
+
throw new Error(error)
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const result = tool.execute ? await tool.execute(args) : { status: 'success' }
|
|
437
|
+
sandbox._logAudit(toolName, args, result, 'OK')
|
|
438
|
+
|
|
439
|
+
return result
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
})
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
hasCapability(cap) {
|
|
446
|
+
return this.config.capabilities.includes(cap)
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
_calculateFuelCost(toolName, args) {
|
|
450
|
+
const baseCosts = {
|
|
451
|
+
'kg.sparql.query': 500,
|
|
452
|
+
'kg.motif.find': 1000,
|
|
453
|
+
'kg.datalog.infer': 2000,
|
|
454
|
+
'kg.embeddings.search': 300,
|
|
455
|
+
'kg.graphframe.pagerank': 5000,
|
|
456
|
+
'kg.graphframe.triangles': 1500,
|
|
457
|
+
'kg.graphframe.components': 2000
|
|
458
|
+
}
|
|
459
|
+
return (baseCosts[toolName] || 100) + JSON.stringify(args).length * 10
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
_logAudit(tool, args, result, status, error = null) {
|
|
463
|
+
this.auditLog.push({
|
|
464
|
+
timestamp: new Date().toISOString(),
|
|
465
|
+
tool,
|
|
466
|
+
args,
|
|
467
|
+
result: result ? { status: result.status } : null,
|
|
468
|
+
status,
|
|
469
|
+
error,
|
|
470
|
+
fuel_remaining: this.fuel
|
|
471
|
+
})
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
getAuditLog() {
|
|
475
|
+
return this.auditLog
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
getMetrics() {
|
|
479
|
+
return {
|
|
480
|
+
fuel_initial: this.config.fuelLimit,
|
|
481
|
+
fuel_remaining: this.fuel,
|
|
482
|
+
fuel_consumed: this.config.fuelLimit - this.fuel,
|
|
483
|
+
memory_used: this.memoryUsed,
|
|
484
|
+
memory_limit: this.config.maxMemory,
|
|
485
|
+
capabilities: this.config.capabilities,
|
|
486
|
+
tool_calls: this.auditLog.length
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// ============================================================================
|
|
492
|
+
// AGENT BUILDER (Fluent Composition Pattern)
|
|
493
|
+
// ============================================================================
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* ComposedAgent - Agent built from composed tools, planner, and sandbox
|
|
497
|
+
*/
|
|
498
|
+
class ComposedAgent {
|
|
499
|
+
constructor(spec) {
|
|
500
|
+
this.name = spec.name
|
|
501
|
+
this.tools = spec.tools
|
|
502
|
+
this.planner = spec.planner
|
|
503
|
+
this.sandbox = spec.sandbox
|
|
504
|
+
this.hooks = spec.hooks || []
|
|
505
|
+
this.conversationHistory = []
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
async call(prompt) {
|
|
509
|
+
this._fireHooks('beforePlan', { prompt })
|
|
510
|
+
|
|
511
|
+
const plan = await this.planner.plan(prompt, {
|
|
512
|
+
history: this.conversationHistory
|
|
513
|
+
})
|
|
514
|
+
|
|
515
|
+
this._fireHooks('afterPlan', { plan })
|
|
516
|
+
|
|
517
|
+
const proxy = this.sandbox.createObjectProxy(this.tools)
|
|
518
|
+
const results = []
|
|
519
|
+
|
|
520
|
+
for (const step of plan.steps) {
|
|
521
|
+
this._fireHooks('beforeExecute', { step })
|
|
522
|
+
|
|
523
|
+
try {
|
|
524
|
+
const result = await proxy[step.tool](step.args)
|
|
525
|
+
results.push({ step, result, status: 'success' })
|
|
526
|
+
this._fireHooks('afterExecute', { step, result })
|
|
527
|
+
} catch (error) {
|
|
528
|
+
results.push({ step, error: error.message, status: 'failed' })
|
|
529
|
+
this._fireHooks('onError', { step, error })
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const witness = this._generateWitness(plan, results)
|
|
534
|
+
|
|
535
|
+
this.conversationHistory.push({ prompt, plan, results, witness })
|
|
536
|
+
|
|
537
|
+
return {
|
|
538
|
+
response: `Executed ${results.length} tools`,
|
|
539
|
+
plan,
|
|
540
|
+
results,
|
|
541
|
+
witness,
|
|
542
|
+
metrics: this.sandbox.getMetrics()
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
_fireHooks(event, data) {
|
|
547
|
+
for (const hook of this.hooks) {
|
|
548
|
+
if (hook.event === event) hook.handler(data)
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
_generateWitness(plan, results) {
|
|
553
|
+
const witnessData = {
|
|
554
|
+
witness_version: '1.0',
|
|
555
|
+
timestamp: new Date().toISOString(),
|
|
556
|
+
agent: this.name,
|
|
557
|
+
model: this.planner.model,
|
|
558
|
+
plan: { id: plan.id, steps: plan.steps.length, confidence: plan.confidence },
|
|
559
|
+
execution: {
|
|
560
|
+
tool_calls: results.map(r => ({
|
|
561
|
+
tool: r.step.tool,
|
|
562
|
+
status: r.status
|
|
563
|
+
}))
|
|
564
|
+
},
|
|
565
|
+
sandbox_metrics: this.sandbox.getMetrics(),
|
|
566
|
+
audit_log: this.sandbox.getAuditLog()
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const proofHash = crypto
|
|
570
|
+
.createHash('sha256')
|
|
571
|
+
.update(JSON.stringify(witnessData))
|
|
572
|
+
.digest('hex')
|
|
573
|
+
|
|
574
|
+
return { ...witnessData, proof_hash: `sha256:${proofHash}` }
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* AgentBuilder - Fluent builder for composing agents
|
|
580
|
+
*/
|
|
581
|
+
class AgentBuilder {
|
|
582
|
+
constructor(name) {
|
|
583
|
+
this.spec = {
|
|
584
|
+
name,
|
|
585
|
+
tools: {},
|
|
586
|
+
planner: null,
|
|
587
|
+
sandbox: null,
|
|
588
|
+
hooks: []
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
withTool(toolName, toolImpl = null) {
|
|
593
|
+
if (TOOL_REGISTRY[toolName]) {
|
|
594
|
+
this.spec.tools[toolName] = {
|
|
595
|
+
...TOOL_REGISTRY[toolName],
|
|
596
|
+
execute: toolImpl || this._createMockExecutor(toolName)
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return this
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
withPlanner(model) {
|
|
603
|
+
this.spec.planner = new LLMPlanner(model, this.spec.tools)
|
|
604
|
+
return this
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
withSandbox(config) {
|
|
608
|
+
this.spec.sandbox = new WasmSandbox(config)
|
|
609
|
+
return this
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
withHook(event, handler) {
|
|
613
|
+
this.spec.hooks.push({ event, handler })
|
|
614
|
+
return this
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
_createMockExecutor(toolName) {
|
|
618
|
+
return async (args) => {
|
|
619
|
+
const mockResults = {
|
|
620
|
+
'kg.sparql.query': { status: 'success', bindings: [], count: 3 },
|
|
621
|
+
'kg.graphframe.triangles': { status: 'success', count: 2 },
|
|
622
|
+
'kg.datalog.infer': { status: 'success', facts: [], count: 5 },
|
|
623
|
+
'kg.embeddings.search': { status: 'success', similar: [], count: 8 }
|
|
624
|
+
}
|
|
625
|
+
return mockResults[toolName] || { status: 'success', resultCount: 1 }
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
build() {
|
|
630
|
+
if (!this.spec.planner) this.withPlanner('mock')
|
|
631
|
+
if (!this.spec.sandbox) this.withSandbox({})
|
|
632
|
+
return new ComposedAgent(this.spec)
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// ============================================================================
|
|
637
|
+
// ORIGINAL HYPERMIND AGENT CODE (Preserved Below)
|
|
638
|
+
// ============================================================================
|
|
13
639
|
|
|
14
640
|
// LUBM Benchmark Test Suite (12 questions)
|
|
15
641
|
const LUBM_TEST_SUITE = [
|
|
@@ -906,11 +1532,20 @@ async function runHyperMindBenchmark(endpoint, model, options = {}) {
|
|
|
906
1532
|
|
|
907
1533
|
// Export for CommonJS
|
|
908
1534
|
module.exports = {
|
|
1535
|
+
// Original HyperMind Agent API
|
|
909
1536
|
HyperMindAgent,
|
|
910
1537
|
runHyperMindBenchmark,
|
|
911
1538
|
getHyperMindBenchmarkSuite,
|
|
912
1539
|
validateSparqlSyntax,
|
|
913
1540
|
createPlanningContext,
|
|
914
1541
|
LUBM_TEST_SUITE,
|
|
915
|
-
HYPERMIND_TOOLS
|
|
1542
|
+
HYPERMIND_TOOLS,
|
|
1543
|
+
|
|
1544
|
+
// Architecture Components (v0.5.8+)
|
|
1545
|
+
TypeId, // Type system (Hindley-Milner + Refinement Types)
|
|
1546
|
+
TOOL_REGISTRY, // Typed tool morphisms
|
|
1547
|
+
LLMPlanner, // Natural language -> typed tool pipelines
|
|
1548
|
+
WasmSandbox, // WASM sandbox with capability-based security
|
|
1549
|
+
AgentBuilder, // Fluent builder for agent composition
|
|
1550
|
+
ComposedAgent // Composed agent with sandbox execution
|
|
916
1551
|
}
|