rust-kgdb 0.8.9 → 0.8.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -72,29 +72,37 @@ db.loadTtl(`
72
72
  brain:carol brain:transfers brain:alice .
73
73
  `, null)
74
74
 
75
- // 2. Create HyperMindAgent with Snowflake federation (ThinkingReasoner BUILT-IN)
75
+ // 2. Create RpcFederationProxy - TWO MODES:
76
+ // • IN-MEMORY (WASM): GraphDB runs in-process via NAPI-RS (no server needed)
77
+ // • RPC MODE: Connect to HyperFederate K8s server for distributed queries
78
+ const federation = new RpcFederationProxy({
79
+ mode: 'inMemory', // 'inMemory' (WASM) or 'rpc' (K8s)
80
+ kg: db, // GraphDB for in-memory mode
81
+ connectors: { snowflake: { database: 'SNOWFLAKE_SAMPLE_DATA', schema: 'TPCH_SF1' } }
82
+ })
83
+ // For distributed K8s mode:
84
+ // const federation = new RpcFederationProxy({ mode: 'rpc', endpoint: 'http://localhost:30180' })
85
+
86
+ // 3. Create HyperMindAgent with ThinkingReasoner BUILT-IN
76
87
  const agent = new HyperMindAgent({
77
88
  name: 'fraud-detector',
78
89
  kg: db,
79
90
  apiKey: process.env.OPENAI_API_KEY, // Optional: LLM
80
- federate: new RpcFederationProxy({ // RPC to Snowflake/BigQuery
81
- endpoint: 'http://localhost:30180',
82
- connectors: { snowflake: { database: 'SNOWFLAKE_SAMPLE_DATA', schema: 'TPCH_SF1' } }
83
- })
91
+ federate: federation
84
92
  })
85
93
 
86
- // 3. Record observations (ground truth from SPARQL/SQL results)
94
+ // 4. Record observations (ground truth from SPARQL/SQL results)
87
95
  agent.reasoner.observe("Alice transfers $10K to Bob", { subject: "alice", predicate: "transfers", object: "bob" })
88
96
  agent.reasoner.observe("Bob transfers $9.5K to Carol", { subject: "bob", predicate: "transfers", object: "carol" })
89
97
  agent.reasoner.observe("Carol transfers $9K to Alice", { subject: "carol", predicate: "transfers", object: "alice" })
90
98
 
91
- // 4. Deduce → Get derivation chain
99
+ // 5. Deduce → Get derivation chain
92
100
  const deduction = agent.reasoner.deduce()
93
101
  const graph = agent.reasoner.getThinkingGraph()
94
102
  console.log('Events:', agent.reasoner.getStats().events) // 3 observations
95
103
  console.log('Facts:', agent.reasoner.getStats().facts) // 3 facts recorded
96
104
 
97
- // 5. Natural language query with federated data
105
+ // 6. Natural language query with federated data
98
106
  const result = await agent.call('Find circular payments and cross-ref with Snowflake TPCH')
99
107
  console.log(result.answer)
100
108
  ```
@@ -19,6 +19,7 @@ const {
19
19
  GraphDB,
20
20
  HyperMindAgent,
21
21
  ThinkingReasoner,
22
+ RpcFederationProxy,
22
23
  getVersion
23
24
  } = require('../index.js')
24
25
 
@@ -137,77 +138,15 @@ brain:supp002 brain:relatedTo brain:supp003 .
137
138
  `
138
139
 
139
140
  // =============================================================================
140
- // SNOWFLAKE TPCH VIRTUAL TABLE SIMULATION
141
- // In production, HyperFederate connects to real Snowflake SNOWFLAKE_SAMPLE_DATA.TPCH_SF1
141
+ // NOTE: RpcFederationProxy now supports TWO modes:
142
+ //
143
+ // 1. IN-MEMORY (WASM): GraphDB runs in-process via NAPI-RS - NO external server
144
+ // const federation = new RpcFederationProxy({ mode: 'inMemory', kg: myGraphDB })
145
+ //
146
+ // 2. RPC MODE: Connects to remote HyperFederate server for distributed queries
147
+ // const federation = new RpcFederationProxy({ mode: 'rpc', endpoint: 'http://...' })
142
148
  // =============================================================================
143
149
 
144
- const SNOWFLAKE_TPCH_CUSTOMERS = [
145
- { C_CUSTKEY: 1, C_NAME: 'Customer#000000001', C_ACCTBAL: 711.56, C_MKTSEGMENT: 'BUILDING' },
146
- { C_CUSTKEY: 2, C_NAME: 'Customer#000000002', C_ACCTBAL: 121.65, C_MKTSEGMENT: 'AUTOMOBILE' },
147
- { C_CUSTKEY: 3, C_NAME: 'Customer#000000003', C_ACCTBAL: 7498.12, C_MKTSEGMENT: 'MACHINERY' },
148
- { C_CUSTKEY: 4, C_NAME: 'Customer#000000004', C_ACCTBAL: -866.22, C_MKTSEGMENT: 'FURNITURE' },
149
- { C_CUSTKEY: 5, C_NAME: 'Customer#000000005', C_ACCTBAL: 794.47, C_MKTSEGMENT: 'HOUSEHOLD' }
150
- ]
151
-
152
- const SNOWFLAKE_TPCH_ORDERS = [
153
- { O_ORDERKEY: 1, O_CUSTKEY: 1, O_TOTALPRICE: 173665.47, O_ORDERSTATUS: 'O' },
154
- { O_ORDERKEY: 2, O_CUSTKEY: 2, O_TOTALPRICE: 46929.18, O_ORDERSTATUS: 'F' },
155
- { O_ORDERKEY: 3, O_CUSTKEY: 3, O_TOTALPRICE: 193846.25, O_ORDERSTATUS: 'O' },
156
- { O_ORDERKEY: 4, O_CUSTKEY: 4, O_TOTALPRICE: 32151.78, O_ORDERSTATUS: 'P' }
157
- ]
158
-
159
- // =============================================================================
160
- // HYPERFEDERATE PROXY (Simulates RPC to Rust HyperFederate Server)
161
- // =============================================================================
162
-
163
- class HyperFederateProxy {
164
- constructor(config) {
165
- this.endpoint = config.endpoint || 'http://localhost:30180'
166
- this.snowflake = config.connectors?.snowflake || {}
167
- this.connected = false
168
-
169
- // Check if real Snowflake credentials provided
170
- if (this.snowflake.account && this.snowflake.user && this.snowflake.password) {
171
- console.log(` Snowflake configured: ${this.snowflake.account}`)
172
- this.connected = true
173
- }
174
- }
175
-
176
- // Simulated SQL query (in production, this goes to real Snowflake via HyperFederate)
177
- async querySQL(sql) {
178
- console.log(` [HyperFederate] Executing SQL: ${sql.substring(0, 60)}...`)
179
-
180
- // Parse simple SELECT queries
181
- const sqlUpper = sql.toUpperCase()
182
-
183
- if (sqlUpper.includes('CUSTOMER')) {
184
- return SNOWFLAKE_TPCH_CUSTOMERS
185
- }
186
-
187
- if (sqlUpper.includes('ORDERS')) {
188
- return SNOWFLAKE_TPCH_ORDERS
189
- }
190
-
191
- return []
192
- }
193
-
194
- // Join KG with SQL results
195
- async federatedJoin(kgResults, sqlTable) {
196
- const sqlData = await this.querySQL(`SELECT * FROM ${sqlTable}`)
197
-
198
- // Simulate federated join
199
- const joined = kgResults.map(kg => {
200
- const match = sqlData.find(sql =>
201
- kg.bindings?.name?.includes(sql.C_NAME?.split('#')[1]) ||
202
- kg.bindings?.customerId === `C-00${sql.C_CUSTKEY}`
203
- )
204
- return { ...kg.bindings, ...match }
205
- }).filter(r => r.C_CUSTKEY)
206
-
207
- return joined
208
- }
209
- }
210
-
211
150
  // =============================================================================
212
151
  // MAIN DEMONSTRATION
213
152
  // =============================================================================
@@ -245,16 +184,19 @@ async function main() {
245
184
  console.log()
246
185
 
247
186
  // =========================================================================
248
- // STEP 2: Configure HyperFederate for Snowflake
187
+ // STEP 2: Configure RpcFederationProxy in IN-MEMORY MODE (WASM)
249
188
  // =========================================================================
250
189
 
251
190
  console.log('+------------------------------------------------------------------------+')
252
- console.log('| STEP 2: Configuring HyperFederate (Snowflake + BigQuery) |')
191
+ console.log('| STEP 2: Configuring RpcFederationProxy (IN-MEMORY WASM MODE) |')
253
192
  console.log('+------------------------------------------------------------------------+')
254
193
  console.log()
255
194
 
256
- const federation = new HyperFederateProxy({
257
- endpoint: process.env.HYPERFEDERATE_URL || 'http://localhost:30180',
195
+ // IN-MEMORY MODE: GraphDB runs in-process via NAPI-RS
196
+ // No external HyperFederate server needed!
197
+ const federation = new RpcFederationProxy({
198
+ mode: 'inMemory', // ★ WASM mode - runs locally via NAPI-RS
199
+ kg: db, // ★ Pass GraphDB instance for in-memory execution
258
200
  connectors: {
259
201
  snowflake: {
260
202
  account: process.env.SNOWFLAKE_ACCOUNT || 'crvrogz-iw23234',
@@ -267,10 +209,10 @@ async function main() {
267
209
  }
268
210
  })
269
211
 
270
- console.log(` Endpoint: ${federation.endpoint}`)
271
- console.log(` Snowflake Account: ${federation.snowflake.account}`)
272
- console.log(` Snowflake User: ${federation.snowflake.user}`)
273
- console.log(` Database: SNOWFLAKE_SAMPLE_DATA.TPCH_SF1`)
212
+ console.log(` Mode: ${federation.getMode()} (WASM - no external server)`)
213
+ console.log(` In-Memory: ${federation.isInMemory()}`)
214
+ console.log(` GraphDB: ${db.countTriples()} triples loaded`)
215
+ console.log(` Snowflake: ${federation.connectors.snowflake.database}.${federation.connectors.snowflake.schema}`)
274
216
  console.log()
275
217
 
276
218
  // =========================================================================
@@ -369,49 +311,52 @@ async function main() {
369
311
  console.log()
370
312
 
371
313
  // =========================================================================
372
- // STEP 6: Federated Query (KGDB + Snowflake)
314
+ // STEP 6: Federated Query using IN-MEMORY RpcFederationProxy
373
315
  // =========================================================================
374
316
 
375
317
  console.log('+------------------------------------------------------------------------+')
376
- console.log('| STEP 6: Federated Query (KGDB + Snowflake TPCH) |')
318
+ console.log('| STEP 6: Federated Query (IN-MEMORY WASM via NAPI-RS) |')
377
319
  console.log('+------------------------------------------------------------------------+')
378
320
  console.log()
379
321
 
380
- // Query high-risk customers from KG
381
- const kgHighRisk = db.querySelect(`
382
- PREFIX brain: <http://brain.gonnect.ai/>
383
- SELECT ?customer ?name ?risk WHERE {
384
- ?customer a brain:Customer .
385
- ?customer brain:name ?name .
386
- ?customer brain:riskScore ?risk .
387
- FILTER(?risk > 0.5)
388
- }
389
- `)
322
+ // Demonstrate IN-MEMORY federation.query() with graph_search()
323
+ // This executes SPARQL via NAPI-RS native binding - NO remote server needed!
324
+ const fedQuery = `
325
+ SELECT kg.s, kg.p, kg.o
326
+ FROM graph_search('SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10') kg
327
+ JOIN snowflake.TPCH_SF1.CUSTOMER sf ON kg.s = sf.C_NAME
328
+ `
390
329
 
391
- console.log(' KG Query: High-risk customers (riskScore > 0.5)')
392
- console.log(` Found: ${kgHighRisk.length} customers`)
330
+ console.log(' Executing federated query via IN-MEMORY mode...')
331
+ console.log(' (NAPI-RS native binding - no external server required)')
393
332
  console.log()
394
333
 
395
- // Federated join with Snowflake TPCH
396
- const federatedResults = await federation.federatedJoin(kgHighRisk, 'CUSTOMER')
334
+ const fedResult = await federation.query(fedQuery, { limit: 10 })
397
335
 
398
- console.log(' FEDERATED JOIN: KG + Snowflake TPCH_SF1.CUSTOMER')
399
- console.log(' +------------------+------------+------------+------------+')
400
- console.log(' | Customer | Risk Score | Balance | Segment |')
401
- console.log(' +------------------+------------+------------+------------+')
336
+ console.log(' FEDERATION RESULT:')
337
+ console.log(' -----------------')
338
+ console.log(` Mode: ${fedResult.metadata.mode}`)
339
+ console.log(` Sources: ${fedResult.metadata.sources.map(s => s.type + '(' + s.mode + ')').join(', ')}`)
340
+ console.log(` Rows: ${fedResult.rowCount}`)
341
+ console.log(` Duration: ${fedResult.duration}ms`)
342
+ console.log()
402
343
 
403
- for (const row of federatedResults) {
404
- const name = (row.name || row.C_NAME || '').slice(0, 16).padEnd(16)
405
- const risk = (row.risk || '0.00').toString().slice(0, 10).padEnd(10)
406
- const balance = ('$' + (row.C_ACCTBAL || 0).toFixed(2)).padEnd(10)
407
- const segment = (row.C_MKTSEGMENT || '').slice(0, 10).padEnd(10)
408
- console.log(` | ${name} | ${risk} | ${balance} | ${segment} |`)
344
+ if (fedResult.columns.length > 0) {
345
+ console.log(' COLUMNS:', fedResult.columns.join(', '))
346
+ console.log(' ROWS (sample):')
347
+ for (const row of fedResult.rows.slice(0, 5)) {
348
+ console.log(' ', row)
349
+ }
409
350
  }
410
- console.log(' +------------------+------------+------------+------------+')
411
351
  console.log()
412
352
 
413
- console.log(' INSIGHT: High-risk customers in MACHINERY segment have')
414
- console.log(' high account balances - potential fraud targets!')
353
+ // Show direct KG query - all triples pattern works
354
+ console.log(' DIRECT KG QUERY (all triples pattern):')
355
+ const kgTriples = db.querySelect('SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10')
356
+ console.log(` Found ${kgTriples.length} triples in KGDB (in-memory NAPI-RS)`)
357
+ for (const t of kgTriples.slice(0, 5)) {
358
+ console.log(` ${t.bindings.s} ${t.bindings.p} ${t.bindings.o}`)
359
+ }
415
360
  console.log()
416
361
 
417
362
  // =========================================================================
@@ -2003,16 +2003,42 @@ const FEDERATION_TOOLS = {
2003
2003
  class RpcFederationProxy {
2004
2004
  /**
2005
2005
  * Create a new RpcFederationProxy
2006
+ *
2007
+ * Supports two modes:
2008
+ * 1. **In-Memory (WASM)**: GraphDB runs in-process via NAPI-RS, no external server needed
2009
+ * 2. **RPC Mode**: Connects to remote HyperFederate server for distributed queries
2010
+ *
2006
2011
  * @param {Object} config - Configuration options
2007
- * @param {string} config.endpoint - HyperFederate server endpoint (default: http://localhost:30180)
2012
+ * @param {string} config.mode - 'inMemory' (WASM) or 'rpc' (remote server). Default: 'inMemory'
2013
+ * @param {Object} config.kg - GraphDB instance for in-memory mode (required for inMemory)
2014
+ * @param {string} config.endpoint - HyperFederate server endpoint (for rpc mode, default: http://localhost:30180)
2015
+ * @param {Object} config.connectors - Database connectors (snowflake, bigquery, postgres)
2008
2016
  * @param {number} config.timeout - Request timeout in ms (default: 30000)
2009
2017
  * @param {WasmSandbox} config.sandbox - WasmSandbox for capability-based security
2010
2018
  * @param {Object} config.headers - Additional HTTP headers
2019
+ *
2020
+ * @example In-Memory Mode (WASM - no external server)
2021
+ * const federation = new RpcFederationProxy({
2022
+ * mode: 'inMemory',
2023
+ * kg: myGraphDB, // GraphDB runs in-process via NAPI-RS
2024
+ * connectors: { snowflake: { ... } } // SQL connector configs
2025
+ * })
2026
+ *
2027
+ * @example RPC Mode (distributed)
2028
+ * const federation = new RpcFederationProxy({
2029
+ * mode: 'rpc',
2030
+ * endpoint: 'http://localhost:30180', // HyperFederate server
2031
+ * connectors: { snowflake: { ... } }
2032
+ * })
2011
2033
  */
2012
2034
  constructor(config = {}) {
2035
+ // Mode: 'inMemory' (WASM) or 'rpc' (remote server)
2036
+ this.mode = config.mode || 'inMemory'
2037
+ this.kg = config.kg || null // GraphDB for in-memory mode
2013
2038
  this.endpoint = config.endpoint || 'http://localhost:30180'
2014
2039
  this.timeout = config.timeout || 30000
2015
2040
  this.headers = config.headers || {}
2041
+ this.connectors = config.connectors || {}
2016
2042
 
2017
2043
  // WasmSandbox for capability-based security with fuel metering
2018
2044
  // Includes 'Federation' capability for cross-database operations
@@ -2062,7 +2088,12 @@ class RpcFederationProxy {
2062
2088
  const start = Date.now()
2063
2089
 
2064
2090
  try {
2065
- // RPC call to HyperFederate server
2091
+ // IN-MEMORY MODE: Execute locally via NAPI-RS (no external server needed)
2092
+ if (this.mode === 'inMemory') {
2093
+ return this._executeInMemory(sql, options, start)
2094
+ }
2095
+
2096
+ // RPC MODE: Remote HyperFederate server
2066
2097
  const response = await fetch(`${this.endpoint}/api/v1/query`, {
2067
2098
  method: 'POST',
2068
2099
  headers: {
@@ -2124,6 +2155,100 @@ class RpcFederationProxy {
2124
2155
  }
2125
2156
  }
2126
2157
 
2158
+ /**
2159
+ * Execute query in-memory via NAPI-RS (WASM mode - no external server)
2160
+ *
2161
+ * Parses SQL to extract:
2162
+ * - graph_search() calls → Executed via this.kg.querySelect()
2163
+ * - snowflake.* / bigquery.* → Simulated with connector configs
2164
+ *
2165
+ * @private
2166
+ */
2167
+ _executeInMemory(sql, options, start) {
2168
+ const results = { columns: [], rows: [], sources: [] }
2169
+
2170
+ // Extract graph_search() SPARQL calls (handles multi-line strings)
2171
+ const graphSearchMatch = sql.match(/graph_search\s*\(\s*['"`]([\s\S]+?)['"`]\s*\)/)
2172
+ if (graphSearchMatch && this.kg) {
2173
+ const sparql = graphSearchMatch[1].replace(/\\n/g, '\n')
2174
+ try {
2175
+ const kgResults = this.kg.querySelect(sparql)
2176
+ results.sources.push({ type: 'kgdb', mode: 'inMemory' })
2177
+
2178
+ // Convert SPARQL results to tabular format
2179
+ if (kgResults && kgResults.length > 0) {
2180
+ const firstRow = kgResults[0]
2181
+ results.columns = Object.keys(firstRow.bindings || firstRow)
2182
+ results.rows = kgResults.map(r => {
2183
+ const bindings = r.bindings || r
2184
+ return results.columns.map(col => bindings[col])
2185
+ })
2186
+ }
2187
+ } catch (e) {
2188
+ console.warn(' [InMemory] SPARQL error:', e.message)
2189
+ }
2190
+ }
2191
+
2192
+ // Check for SQL connector references (simulated in-memory)
2193
+ if (sql.toLowerCase().includes('snowflake') && this.connectors.snowflake) {
2194
+ results.sources.push({
2195
+ type: 'snowflake',
2196
+ mode: 'inMemory',
2197
+ database: this.connectors.snowflake.database,
2198
+ schema: this.connectors.snowflake.schema
2199
+ })
2200
+ }
2201
+ if (sql.toLowerCase().includes('bigquery') && this.connectors.bigquery) {
2202
+ results.sources.push({
2203
+ type: 'bigquery',
2204
+ mode: 'inMemory',
2205
+ project: this.connectors.bigquery.projectId
2206
+ })
2207
+ }
2208
+
2209
+ const duration = Date.now() - start
2210
+
2211
+ // Log to audit trail
2212
+ this.sandbox.log('federation.sql.query', { sql: sql.slice(0, 200), mode: 'inMemory' }, results, 'success')
2213
+ this.auditLog.push({
2214
+ action: 'query',
2215
+ sql,
2216
+ mode: 'inMemory',
2217
+ duration,
2218
+ rows: results.rows.length,
2219
+ timestamp: new Date().toISOString(),
2220
+ sessionId: this.sessionId
2221
+ })
2222
+
2223
+ return {
2224
+ columns: results.columns,
2225
+ rows: results.rows,
2226
+ rowCount: results.rows.length,
2227
+ duration,
2228
+ metadata: {
2229
+ mode: 'inMemory',
2230
+ sources: results.sources,
2231
+ cached: false
2232
+ }
2233
+ }
2234
+ }
2235
+
2236
+ /**
2237
+ * Get the current mode (inMemory or rpc)
2238
+ * @returns {string} Current federation mode
2239
+ */
2240
+ getMode() {
2241
+ return this.mode
2242
+ }
2243
+
2244
+ /**
2245
+ * Check if running in in-memory WASM mode
2246
+ * @returns {boolean} True if in-memory mode
2247
+ */
2248
+ isInMemory() {
2249
+ return this.mode === 'inMemory'
2250
+ }
2251
+
2127
2252
  /**
2128
2253
  * Create a virtual table from a federation query result
2129
2254
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rust-kgdb",
3
- "version": "0.8.9",
3
+ "version": "0.8.10",
4
4
  "description": "High-performance RDF/SPARQL database with AI agent framework and cross-database federation. GraphDB (449ns lookups, 5-11x faster than RDFox), HyperFederate (KGDB + Snowflake + BigQuery), GraphFrames analytics, Datalog reasoning, HNSW vector embeddings. HyperMindAgent for schema-aware query generation with audit trails. W3C SPARQL 1.1 compliant. Native performance via Rust + NAPI-RS.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",