rust-kgdb 0.5.3 → 0.5.5

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.
@@ -1,13 +1,16 @@
1
1
  /**
2
- * ============================================================================
3
2
  * UNDERWRITING AGENT - Built on HyperMind Framework
4
- * ============================================================================
5
3
  *
6
- * This agent demonstrates the HyperMind neuro-symbolic architecture:
4
+ * This example demonstrates proper agentic flow using the HyperMind framework:
7
5
  *
8
- * TYPE THEORY → All tools have typed signatures (A → B)
9
- * CATEGORY THEORY → Tools compose as morphisms (f ∘ g)
10
- * PROOF THEORY → Every execution produces an audit witness
6
+ * ┌─────────────────────────────────────────────────────────────────────┐
7
+ * │ HyperMind Framework Architecture │
8
+ * │ │
9
+ * │ TYPE THEORY → Tools have typed signatures (A → B) │
10
+ * │ CATEGORY THEORY → Tools compose as morphisms (f ∘ g) │
11
+ * │ PROOF THEORY → Every execution produces audit witness │
12
+ * │ │
13
+ * └─────────────────────────────────────────────────────────────────────┘
11
14
  *
12
15
  * Real-World Data Sources:
13
16
  * - ISO (Insurance Services Office) rating factors
@@ -15,534 +18,559 @@
15
18
  * - US Census Bureau NAICS industry codes
16
19
  * - FEMA catastrophe exposure zones
17
20
  *
18
- * Industry Standards Applied:
19
- * - Loss ratio threshold: 0.70 (industry standard referral trigger)
20
- * - Experience modification: 5/10 year breaks
21
- * - Territory factors: Catastrophe zones (hurricane, earthquake, tornado)
22
- * - Premium formula: ISO standard methodology
21
+ * Requirements:
22
+ * - Set ANTHROPIC_API_KEY or OPENAI_API_KEY environment variable
23
+ * - Or use model: 'mock' for offline testing
23
24
  *
24
- * ============================================================================
25
+ * Usage:
26
+ * ANTHROPIC_API_KEY=sk-... node examples/underwriting-agent.js
27
+ * OPENAI_API_KEY=sk-... node examples/underwriting-agent.js --model gpt-4o
28
+ * node examples/underwriting-agent.js --model mock
25
29
  */
26
30
 
31
+ const { HyperMindAgent } = require('../hypermind-agent.js')
27
32
  const {
28
33
  GraphDB,
29
- GraphFrame,
30
34
  EmbeddingService,
31
35
  DatalogProgram,
32
36
  evaluateDatalog,
37
+ GraphFrame,
33
38
  getVersion
34
39
  } = require('../index.js')
35
40
 
36
- // ============================================================================
37
- // REAL-WORLD COMMERCIAL INSURANCE DATA
38
- // Based on ISO rating factors and NAIC guidelines
39
- // ============================================================================
41
+ // ═══════════════════════════════════════════════════════════════════════════
42
+ // CONFIGURATION
43
+ // ═══════════════════════════════════════════════════════════════════════════
44
+
45
+ const MODEL = process.argv.includes('--model')
46
+ ? process.argv[process.argv.indexOf('--model') + 1]
47
+ : process.env.ANTHROPIC_API_KEY ? 'claude-sonnet-4'
48
+ : process.env.OPENAI_API_KEY ? 'gpt-4o'
49
+ : 'mock'
40
50
 
41
- const UNDERWRITING_DATA_TTL = `
42
- @prefix : <http://underwriting.org/> .
51
+ // ═══════════════════════════════════════════════════════════════════════════
52
+ // UNDERWRITING KNOWLEDGE BASE (ISO/NAIC-Informed Data)
53
+ // ═══════════════════════════════════════════════════════════════════════════
54
+
55
+ const UNDERWRITING_KB = `
56
+ @prefix uw: <http://underwriting.org/> .
57
+ @prefix naics: <http://naics.com/code/> .
58
+ @prefix fema: <http://fema.gov/zone/> .
43
59
  @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
44
60
  @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
45
- @prefix iso: <http://iso.com/rating/> .
46
- @prefix naics: <http://census.gov/naics/> .
47
-
48
- # === BUSINESS ENTITIES (Real NAICS codes from US Census Bureau) ===
49
-
50
- :BUS001 rdf:type :CommercialAccount ;
51
- :name "Acme Manufacturing Inc" ;
52
- :naicsCode "332119" ;
53
- :naicsDescription "Metal Stamping" ;
54
- :employees "250"^^xsd:integer ;
55
- :annualRevenue "45000000"^^xsd:decimal ;
56
- :territory "FL-33101" ;
57
- :yearsInBusiness "15"^^xsd:integer ;
58
- :safetyProgram "true"^^xsd:boolean .
59
-
60
- :BUS002 rdf:type :CommercialAccount ;
61
- :name "TechStart LLC" ;
62
- :naicsCode "541512" ;
63
- :naicsDescription "Computer Systems Design" ;
64
- :employees "45"^^xsd:integer ;
65
- :annualRevenue "8500000"^^xsd:decimal ;
66
- :territory "CA-94105" ;
67
- :yearsInBusiness "3"^^xsd:integer ;
68
- :cyberCoverage "required"^^xsd:boolean .
69
-
70
- :BUS003 rdf:type :CommercialAccount ;
71
- :name "SafeHaul Logistics" ;
72
- :naicsCode "484121" ;
73
- :naicsDescription "General Freight Trucking, Long-Distance" ;
74
- :employees "120"^^xsd:integer ;
75
- :annualRevenue "22000000"^^xsd:decimal ;
76
- :territory "TX-75201" ;
77
- :yearsInBusiness "8"^^xsd:integer ;
78
- :fleetSize "45"^^xsd:integer .
79
-
80
- :BUS004 rdf:type :CommercialAccount ;
81
- :name "Downtown Restaurant Group" ;
82
- :naicsCode "722511" ;
83
- :naicsDescription "Full-Service Restaurants" ;
84
- :employees "85"^^xsd:integer ;
85
- :annualRevenue "12000000"^^xsd:decimal ;
86
- :territory "NY-10001" ;
87
- :yearsInBusiness "12"^^xsd:integer ;
88
- :liquorLicense "true"^^xsd:boolean .
89
-
90
- # === ISO RATING FACTORS (Industry standard base rates) ===
91
-
92
- iso:NAICS-332119 rdf:type :RatingClass ;
93
- :baseRate "2.45"^^xsd:decimal ;
94
- :modificationClass "manufacturing" ;
95
- :hazardGrade "B" ;
96
- :description "Metal stamping - moderate machinery risk" .
97
-
98
- iso:NAICS-541512 rdf:type :RatingClass ;
99
- :baseRate "0.85"^^xsd:decimal ;
100
- :modificationClass "technology" ;
101
- :hazardGrade "A" ;
102
- :description "Professional services - low physical risk" .
103
-
104
- iso:NAICS-484121 rdf:type :RatingClass ;
105
- :baseRate "3.80"^^xsd:decimal ;
106
- :modificationClass "transportation" ;
107
- :hazardGrade "C" ;
108
- :description "Trucking - high accident frequency" .
109
-
110
- iso:NAICS-722511 rdf:type :RatingClass ;
111
- :baseRate "1.95"^^xsd:decimal ;
112
- :modificationClass "hospitality" ;
113
- :hazardGrade "B" ;
114
- :description "Restaurant - slip/fall, food safety" .
115
-
116
- # === TERRITORY FACTORS (FEMA catastrophe zones) ===
117
-
118
- :TERR-FL-33101 rdf:type :TerritoryRating ;
119
- :territoryMod "1.35"^^xsd:decimal ;
120
- :catExposure "hurricane" ;
121
- :femaZone "V" ;
122
- :description "Miami-Dade - high hurricane exposure" .
123
-
124
- :TERR-CA-94105 rdf:type :TerritoryRating ;
125
- :territoryMod "1.15"^^xsd:decimal ;
126
- :catExposure "earthquake" ;
127
- :femaZone "Seismic-4" ;
128
- :description "San Francisco - earthquake zone" .
129
-
130
- :TERR-TX-75201 rdf:type :TerritoryRating ;
131
- :territoryMod "1.05"^^xsd:decimal ;
132
- :catExposure "tornado" ;
133
- :femaZone "Tornado-Alley" ;
134
- :description "Dallas - moderate tornado exposure" .
135
-
136
- :TERR-NY-10001 rdf:type :TerritoryRating ;
137
- :territoryMod "1.25"^^xsd:decimal ;
138
- :catExposure "flood" ;
139
- :femaZone "AE" ;
140
- :description "Manhattan - flood zone, high density" .
141
-
142
- # === LOSS HISTORY (5-year experience) ===
143
-
144
- :BUS001 :lossCount "2"^^xsd:integer ;
145
- :totalLossAmount "125000"^^xsd:decimal ;
146
- :lossRatio "0.45"^^xsd:decimal ;
147
- :largestClaim "85000"^^xsd:decimal .
148
-
149
- :BUS002 :lossCount "0"^^xsd:integer ;
150
- :totalLossAmount "0"^^xsd:decimal ;
151
- :lossRatio "0.00"^^xsd:decimal ;
152
- :largestClaim "0"^^xsd:decimal .
153
-
154
- :BUS003 :lossCount "4"^^xsd:integer ;
155
- :totalLossAmount "380000"^^xsd:decimal ;
156
- :lossRatio "0.72"^^xsd:decimal ;
157
- :largestClaim "145000"^^xsd:decimal .
158
-
159
- :BUS004 :lossCount "1"^^xsd:integer ;
160
- :totalLossAmount "45000"^^xsd:decimal ;
161
- :lossRatio "0.28"^^xsd:decimal ;
162
- :largestClaim "45000"^^xsd:decimal .
163
- `
164
-
165
- // ============================================================================
166
- // HYPERMIND TOOL: Risk Embedding Generator (Morphism: RiskProfile → Vector)
167
- // Type signature enforced at compile-time
168
- // ============================================================================
169
61
 
170
- function generateRiskEmbedding(industryClass, lossRatio, territoryMod, yearsInBusiness) {
171
- const embedding = new Array(384).fill(0)
62
+ # Business Accounts with NAICS Industry Codes
63
+ uw:BUS001 rdf:type uw:BusinessAccount ;
64
+ uw:name "Acme Manufacturing Inc." ;
65
+ uw:naicsCode naics:332710 ;
66
+ uw:industry "Machine Shops" ;
67
+ uw:yearsInBusiness "15"^^xsd:integer ;
68
+ uw:annualRevenue "8500000"^^xsd:decimal ;
69
+ uw:employeeCount "45"^^xsd:integer ;
70
+ uw:lossRatio "0.45"^^xsd:float ;
71
+ uw:femaZone fema:X ;
72
+ uw:territoryCode "FL-027" .
73
+
74
+ uw:BUS002 rdf:type uw:BusinessAccount ;
75
+ uw:name "TechStart LLC" ;
76
+ uw:naicsCode naics:541511 ;
77
+ uw:industry "Custom Computer Programming" ;
78
+ uw:yearsInBusiness "3"^^xsd:integer ;
79
+ uw:annualRevenue "1200000"^^xsd:decimal ;
80
+ uw:employeeCount "12"^^xsd:integer ;
81
+ uw:lossRatio "0.15"^^xsd:float ;
82
+ uw:femaZone fema:C ;
83
+ uw:territoryCode "CA-037" .
84
+
85
+ uw:BUS003 rdf:type uw:BusinessAccount ;
86
+ uw:name "SafeHaul Logistics" ;
87
+ uw:naicsCode naics:484110 ;
88
+ uw:industry "General Freight Trucking" ;
89
+ uw:yearsInBusiness "8"^^xsd:integer ;
90
+ uw:annualRevenue "4200000"^^xsd:decimal ;
91
+ uw:employeeCount "28"^^xsd:integer ;
92
+ uw:lossRatio "0.72"^^xsd:float ;
93
+ uw:femaZone fema:AE ;
94
+ uw:territoryCode "TX-201" .
95
+
96
+ uw:BUS004 rdf:type uw:BusinessAccount ;
97
+ uw:name "Downtown Restaurant Group" ;
98
+ uw:naicsCode naics:722511 ;
99
+ uw:industry "Full-Service Restaurants" ;
100
+ uw:yearsInBusiness "12"^^xsd:integer ;
101
+ uw:annualRevenue "3100000"^^xsd:decimal ;
102
+ uw:employeeCount "65"^^xsd:integer ;
103
+ uw:lossRatio "0.28"^^xsd:float ;
104
+ uw:femaZone fema:X500 ;
105
+ uw:territoryCode "NY-061" .
106
+
107
+ # ISO Base Rates by Industry Class
108
+ naics:332710 uw:isoBaseRate "12.50"^^xsd:decimal ;
109
+ uw:hazardClass "Manufacturing" ;
110
+ uw:riskTier "Medium" .
111
+
112
+ naics:541511 uw:isoBaseRate "4.25"^^xsd:decimal ;
113
+ uw:hazardClass "Office/Professional" ;
114
+ uw:riskTier "Low" .
115
+
116
+ naics:484110 uw:isoBaseRate "18.75"^^xsd:decimal ;
117
+ uw:hazardClass "Transportation" ;
118
+ uw:riskTier "High" .
119
+
120
+ naics:722511 uw:isoBaseRate "8.90"^^xsd:decimal ;
121
+ uw:hazardClass "Restaurant/Hospitality" ;
122
+ uw:riskTier "Medium" .
123
+
124
+ # FEMA Zone Risk Multipliers
125
+ fema:X uw:floodRisk "Minimal" ;
126
+ uw:territoryMultiplier "1.0"^^xsd:float .
127
+
128
+ fema:C uw:floodRisk "Moderate" ;
129
+ uw:territoryMultiplier "1.15"^^xsd:float .
130
+
131
+ fema:AE uw:floodRisk "High - 1% Annual Chance" ;
132
+ uw:territoryMultiplier "1.45"^^xsd:float .
133
+
134
+ fema:X500 uw:floodRisk "Moderate - 0.2% Annual Chance" ;
135
+ uw:territoryMultiplier "1.10"^^xsd:float .
136
+
137
+ # Territory Modifiers (based on state/region)
138
+ uw:Territory_FL uw:hurricaneExposure "High" ;
139
+ uw:modificationFactor "1.35"^^xsd:float .
140
+
141
+ uw:Territory_CA uw:earthquakeExposure "High" ;
142
+ uw:modificationFactor "1.25"^^xsd:float .
143
+
144
+ uw:Territory_TX uw:hurricaneExposure "Moderate" ;
145
+ uw:modificationFactor "1.20"^^xsd:float .
146
+
147
+ uw:Territory_NY uw:litigationRisk "High" ;
148
+ uw:modificationFactor "1.30"^^xsd:float .
149
+ `
172
150
 
173
- // Industry risk encoding (dims 0-95) - based on ISO hazard grades
174
- const industryRiskFactors = {
175
- manufacturing: 0.60, // Moderate - machinery hazards
176
- technology: 0.25, // Low - office environment
177
- transportation: 0.85, // High - vehicle accidents
178
- hospitality: 0.55 // Moderate - public liability
179
- }
180
- const industryRisk = industryRiskFactors[industryClass] || 0.5
181
- for (let i = 0; i < 96; i++) {
182
- embedding[i] = industryRisk * (0.7 + Math.sin(i * 0.1) * 0.3)
183
- }
151
+ // ═══════════════════════════════════════════════════════════════════════════
152
+ // TOOL IMPLEMENTATIONS (Typed Morphisms)
153
+ // ═══════════════════════════════════════════════════════════════════════════
184
154
 
185
- // Loss ratio encoding (dims 96-191) - key underwriting metric
186
- for (let i = 96; i < 192; i++) {
187
- embedding[i] = lossRatio * (0.6 + Math.cos((i - 96) * 0.08) * 0.4)
188
- }
155
+ /**
156
+ * Tool: kg.sparql.query
157
+ * Type: SPARQLQuery BindingSet
158
+ */
159
+ async function sparqlQuery(db, query) {
160
+ const results = db.querySelect(query)
161
+ return results.map(r => r.bindings)
162
+ }
189
163
 
190
- // Territory risk encoding (dims 192-287)
191
- const normalizedTerritory = (territoryMod - 1.0) / 0.35 // Normalize 1.0-1.35 to 0-1
192
- for (let i = 192; i < 288; i++) {
193
- embedding[i] = normalizedTerritory * (0.5 + Math.sin((i - 192) * 0.12) * 0.5)
164
+ /**
165
+ * Tool: kg.graphframe.analyze
166
+ * Type: Graph AnalysisResult
167
+ */
168
+ function graphframeAnalyze(vertices, edges) {
169
+ // GraphFrame constructor requires JSON strings
170
+ const gf = new GraphFrame(JSON.stringify(vertices), JSON.stringify(edges))
171
+ // pageRank and connectedComponents return JSON strings
172
+ const pageRankResult = JSON.parse(gf.pageRank(0.85, 20))
173
+ const componentsResult = JSON.parse(gf.connectedComponents())
174
+ return {
175
+ pageRank: pageRankResult.ranks || pageRankResult,
176
+ components: componentsResult.components || componentsResult
194
177
  }
178
+ }
195
179
 
196
- // Experience factor (dims 288-383) - more years = lower risk
197
- const experienceFactor = Math.min(yearsInBusiness / 20, 1) // Cap at 20 years
198
- for (let i = 288; i < 384; i++) {
199
- embedding[i] = (1 - experienceFactor) * 0.5 * Math.cos((i - 288) * 0.06)
200
- }
180
+ /**
181
+ * Tool: kg.embeddings.similar
182
+ * Type: EntityId × Float List[SimilarEntity]
183
+ */
184
+ function embeddingsSimilar(embeddings, entityId, threshold = 0.7) {
185
+ // findSimilar returns JSON string with {entity, score, distance}
186
+ const resultJson = embeddings.findSimilar(entityId, 5, threshold)
187
+ const results = JSON.parse(resultJson)
188
+ // Map to standard format
189
+ return results.map(r => ({
190
+ id: r.entity,
191
+ similarity: r.score
192
+ }))
193
+ }
201
194
 
202
- // Normalize to unit vector
203
- const magnitude = Math.sqrt(embedding.reduce((s, v) => s + v * v, 0))
204
- if (magnitude > 0) {
205
- for (let i = 0; i < 384; i++) embedding[i] /= magnitude
195
+ /**
196
+ * Tool: kg.datalog.infer
197
+ * Type: DatalogProgram → InferredFacts
198
+ * Result format: {"predicate_name": [[term1, term2], ...], ...}
199
+ */
200
+ function datalogInfer(program) {
201
+ const resultJson = evaluateDatalog(program)
202
+ const result = JSON.parse(resultJson)
203
+ // Convert to array format for easier processing
204
+ const facts = []
205
+ for (const [predicate, termArrays] of Object.entries(result)) {
206
+ for (const terms of termArrays) {
207
+ facts.push({ name: predicate, args: terms })
208
+ }
206
209
  }
207
-
208
- return embedding
210
+ return facts
209
211
  }
210
212
 
211
- // ============================================================================
212
- // ISO PREMIUM CALCULATION (Industry Standard Formula)
213
- // Premium = Base Rate × Exposure × Territory Mod × Experience Mod × Loss Mod
214
- // ============================================================================
215
-
213
+ /**
214
+ * Tool: kg.premium.calculate
215
+ * Type: RiskFactors PremiumQuote
216
+ *
217
+ * ISO Premium Calculation Formula:
218
+ * Premium = Base Rate × Exposure × Territory Mod × Experience Mod × Loss Mod
219
+ */
216
220
  function calculatePremium(baseRate, exposure, territoryMod, lossRatio, yearsInBusiness) {
217
- // Experience modification (NAIC standard breaks)
218
- const experienceMod = yearsInBusiness >= 10 ? 0.90 :
219
- yearsInBusiness >= 5 ? 0.95 : 1.05
221
+ // Experience modification (tenure discount)
222
+ const experienceMod = yearsInBusiness >= 10 ? 0.90 : yearsInBusiness >= 5 ? 0.95 : 1.05
220
223
 
221
- // Loss development factor (actuarial standard)
222
- const lossMod = lossRatio < 0.30 ? 0.85 : // Excellent
223
- lossRatio < 0.50 ? 1.00 : // Average
224
- lossRatio < 0.70 ? 1.15 : // Below average
225
- 1.35 // Poor - surcharge
224
+ // Loss modification (claims history)
225
+ const lossMod = lossRatio < 0.30 ? 0.85 :
226
+ lossRatio < 0.50 ? 1.00 :
227
+ lossRatio < 0.70 ? 1.15 : 1.35
226
228
 
227
229
  const premium = baseRate * exposure * territoryMod * experienceMod * lossMod
228
230
  return Math.round(premium * 100) / 100
229
231
  }
230
232
 
231
- // ============================================================================
232
- // HYPERMIND AGENT: Underwriting Pipeline
233
- //
234
- // Tool Composition (Category Theory):
235
- // kg.sparql.query : Query BindingSet
236
- // kg.graphframe.analyze : Graph → RiskCorrelation
237
- // kg.embeddings.search : Entity → SimilarRiskProfiles
238
- // kg.datalog.infer : Rules → UnderwritingDecisions
239
- //
240
- // Each tool is a typed morphism. Composition is type-checked.
241
- // ============================================================================
242
-
243
- async function runUnderwritingAgent() {
244
- console.log('═'.repeat(74))
233
+ // ═══════════════════════════════════════════════════════════════════════════
234
+ // MAIN UNDERWRITING AGENT
235
+ // ═══════════════════════════════════════════════════════════════════════════
236
+
237
+ async function main() {
238
+ console.log('═'.repeat(78))
245
239
  console.log(' HYPERMIND UNDERWRITING AGENT')
246
- console.log(' rust-kgdb v' + getVersion() + ' | Neuro-Symbolic AI Framework')
247
- console.log('═'.repeat(74))
240
+ console.log(` rust-kgdb ${getVersion()} | Neuro-Symbolic AI Framework`)
241
+ console.log('═'.repeat(78))
248
242
  console.log()
249
243
  console.log(' Architecture: Type Theory + Category Theory + Proof Theory')
250
- console.log(' Data Source: ISO rating factors, NAIC guidelines, NAICS codes')
244
+ console.log(' Data Sources: ISO rating factors, NAIC guidelines, NAICS codes')
245
+ console.log(` LLM Model: ${MODEL}`)
251
246
  console.log()
252
247
 
253
- // Track execution for audit witness
254
- const executionWitness = {
255
- agent: 'UnderwritingAgent',
256
- startTime: new Date().toISOString(),
257
- tools: [],
258
- decisions: []
259
- }
248
+ // ─────────────────────────────────────────────────────────────────────────
249
+ // PHASE 1: Initialize Knowledge Graph
250
+ // ─────────────────────────────────────────────────────────────────────────
260
251
 
261
- // ═══════════════════════════════════════════════════════════════════════════
262
- // TOOL 1: kg.sparql.query (Morphism: QueryBindingSet)
263
- // ═══════════════════════════════════════════════════════════════════════════
264
- console.log('┌─ TOOL: kg.sparql.query ─────────────────────────────────────────────┐')
265
- console.log('│ Type: SPARQLQuery → BindingSet │')
252
+ console.log('┌─ TOOL: kg.sparql.load ───────────────────────────────────────────────┐')
253
+ console.log('│ Type: TTLGraph │')
266
254
  console.log('└─────────────────────────────────────────────────────────────────────┘')
267
255
 
268
- const toolStart1 = Date.now()
269
256
  const db = new GraphDB('http://underwriting.org/kb')
270
- db.loadTtl(UNDERWRITING_DATA_TTL, null)
257
+ db.loadTtl(UNDERWRITING_KB, 'http://underwriting.org/data')
258
+ const tripleCount = db.countTriples()
259
+ console.log(` Knowledge Graph: ${tripleCount} triples loaded`)
260
+ console.log()
271
261
 
272
- console.log(` Knowledge Graph: ${db.countTriples()} triples loaded`)
273
- console.log(` Graph URI: ${db.getGraphUri()}`)
262
+ // ─────────────────────────────────────────────────────────────────────────
263
+ // PHASE 2: Spawn HyperMind Agent
264
+ // ─────────────────────────────────────────────────────────────────────────
265
+
266
+ console.log('┌─ AGENT: HyperMindAgent.spawn() ──────────────────────────────────────┐')
267
+ console.log('│ AgentSpec: { │')
268
+ console.log('│ name: "underwriter", │')
269
+ console.log(`│ model: "${MODEL}", │`)
270
+ console.log('│ tools: [kg.sparql.query, kg.datalog.apply, kg.embeddings.search],│')
271
+ console.log('│ tracing: true │')
272
+ console.log('│ } │')
273
+ console.log('└─────────────────────────────────────────────────────────────────────┘')
274
274
 
275
- executionWitness.tools.push({
276
- name: 'kg.sparql.query',
277
- input: 'underwriting_knowledge_base',
278
- output: `${db.countTriples()} triples`,
279
- durationMs: Date.now() - toolStart1
275
+ const agent = await HyperMindAgent.spawn({
276
+ name: 'underwriter',
277
+ model: MODEL,
278
+ tools: ['kg.sparql.query', 'kg.datalog.apply', 'kg.embeddings.search'],
279
+ endpoint: 'http://localhost:30080',
280
+ tracing: true
280
281
  })
282
+
283
+ console.log(` Agent "${agent.getName()}" spawned with model: ${agent.getModel()}`)
281
284
  console.log()
282
285
 
283
- // ═══════════════════════════════════════════════════════════════════════════
284
- // TOOL 2: kg.graphframe.analyze (Morphism: Graph → RiskCorrelation)
285
- // ═══════════════════════════════════════════════════════════════════════════
286
- console.log('┌─ TOOL: kg.graphframe.analyze ───────────────────────────────────────┐')
287
- console.log('│ Type: Graph {pagerank, components, correlations} │')
286
+ // ─────────────────────────────────────────────────────────────────────────
287
+ // PHASE 3: Execute Underwriting Tools
288
+ // ─────────────────────────────────────────────────────────────────────────
289
+
290
+ // Tool 1: SPARQL Query - Get All Accounts
291
+ console.log('┌─ TOOL: kg.sparql.query ─────────────────────────────────────────────┐')
292
+ console.log('│ Type: SPARQLQuery → BindingSet │')
288
293
  console.log('└─────────────────────────────────────────────────────────────────────┘')
289
294
 
290
- const toolStart2 = Date.now()
291
-
292
- // Build risk correlation graph
293
- const vertices = JSON.stringify([
294
- { id: 'BUS001', type: 'account' },
295
- { id: 'BUS002', type: 'account' },
296
- { id: 'BUS003', type: 'account' },
297
- { id: 'BUS004', type: 'account' },
298
- { id: 'hurricane', type: 'catastrophe' },
299
- { id: 'earthquake', type: 'catastrophe' },
300
- { id: 'tornado', type: 'catastrophe' },
301
- { id: 'flood', type: 'catastrophe' },
302
- { id: 'manufacturing', type: 'industry' },
303
- { id: 'technology', type: 'industry' },
304
- { id: 'transportation', type: 'industry' },
305
- { id: 'hospitality', type: 'industry' }
306
- ])
307
-
308
- const edges = JSON.stringify([
309
- // Business to CAT exposure
310
- { src: 'BUS001', dst: 'hurricane', type: 'exposure' },
311
- { src: 'BUS002', dst: 'earthquake', type: 'exposure' },
312
- { src: 'BUS003', dst: 'tornado', type: 'exposure' },
313
- { src: 'BUS004', dst: 'flood', type: 'exposure' },
314
- // Business to industry class
315
- { src: 'BUS001', dst: 'manufacturing', type: 'class' },
316
- { src: 'BUS002', dst: 'technology', type: 'class' },
317
- { src: 'BUS003', dst: 'transportation', type: 'class' },
318
- { src: 'BUS004', dst: 'hospitality', type: 'class' },
319
- // Correlated risks (for portfolio analysis)
320
- { src: 'hurricane', dst: 'flood', type: 'correlation' },
321
- { src: 'manufacturing', dst: 'transportation', type: 'supplychain' }
322
- ])
323
-
324
- const graph = new GraphFrame(vertices, edges)
325
-
326
- // PageRank for risk concentration analysis
327
- const pageRankResult = JSON.parse(graph.pageRank(0.15, 20))
328
-
329
- // Connected components for portfolio clustering
330
- const components = JSON.parse(graph.connectedComponents())
331
-
332
- executionWitness.tools.push({
333
- name: 'kg.graphframe.analyze',
334
- input: `${graph.vertexCount()} vertices, ${graph.edgeCount()} edges`,
335
- output: 'risk_correlation_complete',
336
- durationMs: Date.now() - toolStart2
295
+ const accountsQuery = `
296
+ PREFIX uw: <http://underwriting.org/>
297
+ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
298
+ SELECT ?account ?name ?industry ?revenue ?lossRatio ?years WHERE {
299
+ ?account a uw:BusinessAccount ;
300
+ uw:name ?name ;
301
+ uw:industry ?industry ;
302
+ uw:annualRevenue ?revenue ;
303
+ uw:lossRatio ?lossRatio ;
304
+ uw:yearsInBusiness ?years .
305
+ }
306
+ `
307
+ const accounts = await sparqlQuery(db, accountsQuery)
308
+ console.log(` Accounts retrieved: ${accounts.length}`)
309
+ accounts.forEach(a => {
310
+ const name = a['?name'] || a.name
311
+ const lr = a['?lossRatio'] || a.lossRatio
312
+ console.log(` - ${name}: loss ratio ${lr}`)
337
313
  })
338
-
339
- console.log(` Risk Network: ${graph.vertexCount()} nodes, ${graph.edgeCount()} edges`)
340
- console.log(' Risk Concentration (PageRank):')
341
- if (pageRankResult.ranks) {
342
- Object.entries(pageRankResult.ranks)
343
- .filter(([k]) => k.startsWith('BUS'))
344
- .sort((a, b) => b[1] - a[1])
345
- .forEach(([node, score]) => {
346
- console.log(` - ${node}: ${score.toFixed(4)}`)
347
- })
348
- }
349
314
  console.log()
350
315
 
351
- // ═══════════════════════════════════════════════════════════════════════════
352
- // TOOL 3: kg.embeddings.search (Morphism: Entity → SimilarRiskProfiles)
353
- // ═══════════════════════════════════════════════════════════════════════════
354
- console.log('┌─ TOOL: kg.embeddings.search ────────────────────────────────────────┐')
355
- console.log('│ Type: EntityId → List[{entity, similarity}] │')
316
+ // Tool 2: GraphFrame - Risk Network Analysis
317
+ console.log('┌─ TOOL: kg.graphframe.analyze ────────────────────────────────────────┐')
318
+ console.log('│ Type: Graph → {pagerank, components} │')
356
319
  console.log('└─────────────────────────────────────────────────────────────────────┘')
357
320
 
358
- const toolStart3 = Date.now()
359
-
360
- const embeddings = new EmbeddingService()
321
+ const riskVertices = [
322
+ { id: 'BUS001', type: 'account', industry: 'manufacturing' },
323
+ { id: 'BUS002', type: 'account', industry: 'technology' },
324
+ { id: 'BUS003', type: 'account', industry: 'transportation' },
325
+ { id: 'BUS004', type: 'account', industry: 'hospitality' },
326
+ { id: 'FL', type: 'territory' },
327
+ { id: 'CA', type: 'territory' },
328
+ { id: 'TX', type: 'territory' },
329
+ { id: 'NY', type: 'territory' }
330
+ ]
361
331
 
362
- // Risk profiles based on real underwriting factors
363
- const riskProfiles = [
364
- { id: 'BUS001', class: 'manufacturing', lossRatio: 0.45, territory: 1.35, years: 15 },
365
- { id: 'BUS002', class: 'technology', lossRatio: 0.00, territory: 1.15, years: 3 },
366
- { id: 'BUS003', class: 'transportation', lossRatio: 0.72, territory: 1.05, years: 8 },
367
- { id: 'BUS004', class: 'hospitality', lossRatio: 0.28, territory: 1.25, years: 12 }
332
+ const riskEdges = [
333
+ { src: 'BUS001', dst: 'FL', relationship: 'located_in' },
334
+ { src: 'BUS002', dst: 'CA', relationship: 'located_in' },
335
+ { src: 'BUS003', dst: 'TX', relationship: 'located_in' },
336
+ { src: 'BUS004', dst: 'NY', relationship: 'located_in' },
337
+ { src: 'FL', dst: 'TX', relationship: 'hurricane_corridor' },
338
+ { src: 'BUS001', dst: 'BUS003', relationship: 'same_class' }
368
339
  ]
369
340
 
370
- riskProfiles.forEach(p => {
371
- const vec = generateRiskEmbedding(p.class, p.lossRatio, p.territory, p.years)
372
- embeddings.storeVector(p.id, vec)
341
+ const analysis = graphframeAnalyze(riskVertices, riskEdges)
342
+ console.log(` Risk Network: ${riskVertices.length} nodes, ${riskEdges.length} edges`)
343
+ console.log(' Risk Concentration (PageRank):')
344
+ Object.entries(analysis.pageRank).slice(0, 4).forEach(([node, rank]) => {
345
+ console.log(` - ${node}: ${rank.toFixed(4)}`)
373
346
  })
347
+ console.log()
374
348
 
375
- embeddings.rebuildIndex()
349
+ // Tool 3: Embeddings - Similar Risk Profiles
350
+ console.log('┌─ TOOL: kg.embeddings.similar ───────────────────────────────────────┐')
351
+ console.log('│ Type: EntityId × Float → List[SimilarEntity] │')
352
+ console.log('└─────────────────────────────────────────────────────────────────────┘')
376
353
 
377
- // Find accounts with similar risk profiles to BUS003 (highest risk)
378
- const similarProfiles = JSON.parse(embeddings.findSimilar('BUS003', 5, 0.3))
354
+ const embeddings = new EmbeddingService()
379
355
 
380
- executionWitness.tools.push({
381
- name: 'kg.embeddings.search',
382
- input: 'BUS003 (high-risk transportation)',
383
- output: `${similarProfiles.length} similar profiles`,
384
- durationMs: Date.now() - toolStart3
385
- })
356
+ // Add account embeddings based on risk characteristics
357
+ embeddings.storeVector('BUS001', generateRiskEmbedding('manufacturing', 0.45, 15, 1.35))
358
+ embeddings.storeVector('BUS002', generateRiskEmbedding('technology', 0.15, 3, 1.25))
359
+ embeddings.storeVector('BUS003', generateRiskEmbedding('transportation', 0.72, 8, 1.20))
360
+ embeddings.storeVector('BUS004', generateRiskEmbedding('hospitality', 0.28, 12, 1.30))
386
361
 
387
- console.log(` Risk Embeddings: ${riskProfiles.length} accounts vectorized (384 dims)`)
362
+ const similarAccounts = embeddingsSimilar(embeddings, 'BUS003', 0.5)
388
363
  console.log(' Accounts similar to BUS003 (highest risk):')
389
- similarProfiles
390
- .filter(s => s.entity !== 'BUS003')
391
- .forEach(s => {
392
- const profile = riskProfiles.find(p => p.id === s.entity)
393
- if (profile) {
394
- console.log(` - ${s.entity}: ${profile.class}, loss ratio ${profile.lossRatio}`)
395
- }
396
- })
364
+ similarAccounts.forEach(s => {
365
+ console.log(` - ${s.id}: similarity ${s.similarity.toFixed(3)}`)
366
+ })
397
367
  console.log()
398
368
 
399
- // ═══════════════════════════════════════════════════════════════════════════
400
- // TOOL 4: kg.datalog.infer (Morphism: Rules → UnderwritingDecisions)
401
- // ═══════════════════════════════════════════════════════════════════════════
369
+ // Tool 4: Datalog - Underwriting Decision Rules
402
370
  console.log('┌─ TOOL: kg.datalog.infer ────────────────────────────────────────────┐')
403
371
  console.log('│ Type: DatalogProgram → UnderwritingDecisions │')
404
372
  console.log('└─────────────────────────────────────────────────────────────────────┘')
405
373
 
406
- const toolStart4 = Date.now()
407
-
408
374
  const datalog = new DatalogProgram()
409
375
 
410
- // Facts: Business profiles
411
- datalog.addFact(JSON.stringify({ predicate: 'business', terms: ['BUS001', 'manufacturing', '0.45'] }))
412
- datalog.addFact(JSON.stringify({ predicate: 'business', terms: ['BUS002', 'technology', '0.00'] }))
413
- datalog.addFact(JSON.stringify({ predicate: 'business', terms: ['BUS003', 'transportation', '0.72'] }))
414
- datalog.addFact(JSON.stringify({ predicate: 'business', terms: ['BUS004', 'hospitality', '0.28'] }))
415
-
416
- // High-risk class definitions
417
- datalog.addFact(JSON.stringify({ predicate: 'highRiskClass', terms: ['transportation'] }))
418
- datalog.addFact(JSON.stringify({ predicate: 'highRiskClass', terms: ['construction'] }))
419
-
420
- // Rule: Refer to underwriter if high-risk class
421
- // referToUW(Bus) :- business(Bus, Class, _), highRiskClass(Class)
376
+ // Facts based on account characteristics - using correct JSON API
377
+ datalog.addFact(JSON.stringify({ predicate: 'account', terms: ['BUS001'] }))
378
+ datalog.addFact(JSON.stringify({ predicate: 'account', terms: ['BUS002'] }))
379
+ datalog.addFact(JSON.stringify({ predicate: 'account', terms: ['BUS003'] }))
380
+ datalog.addFact(JSON.stringify({ predicate: 'account', terms: ['BUS004'] }))
381
+ datalog.addFact(JSON.stringify({ predicate: 'low_loss_ratio', terms: ['BUS002'] })) // < 0.30
382
+ datalog.addFact(JSON.stringify({ predicate: 'low_loss_ratio', terms: ['BUS004'] })) // < 0.30
383
+ datalog.addFact(JSON.stringify({ predicate: 'high_loss_ratio', terms: ['BUS003'] })) // > 0.70
384
+ datalog.addFact(JSON.stringify({ predicate: 'established', terms: ['BUS001'] })) // > 10 years
385
+ datalog.addFact(JSON.stringify({ predicate: 'established', terms: ['BUS004'] }))
386
+ datalog.addFact(JSON.stringify({ predicate: 'high_risk_class', terms: ['BUS003'] })) // transportation
387
+
388
+ // NAIC-informed underwriting rules - using correct JSON API
422
389
  datalog.addRule(JSON.stringify({
423
- head: { predicate: 'referToUW', terms: ['?Bus'] },
390
+ head: { predicate: 'auto_approve', terms: ['?X'] },
424
391
  body: [
425
- { predicate: 'business', terms: ['?Bus', '?Class', '?LR'] },
426
- { predicate: 'highRiskClass', terms: ['?Class'] }
392
+ { predicate: 'account', terms: ['?X'] },
393
+ { predicate: 'low_loss_ratio', terms: ['?X'] }
427
394
  ]
428
395
  }))
429
396
 
430
- // Rule: Auto-approve if technology class (low risk)
431
- // autoApprove(Bus) :- business(Bus, technology, _)
432
397
  datalog.addRule(JSON.stringify({
433
- head: { predicate: 'autoApprove', terms: ['?Bus'] },
398
+ head: { predicate: 'refer_to_underwriter', terms: ['?X'] },
434
399
  body: [
435
- { predicate: 'business', terms: ['?Bus', 'technology', '?LR'] }
400
+ { predicate: 'account', terms: ['?X'] },
401
+ { predicate: 'high_loss_ratio', terms: ['?X'] }
436
402
  ]
437
403
  }))
438
404
 
439
- const inferredResult = evaluateDatalog(datalog)
440
- const inferred = JSON.parse(inferredResult)
405
+ const decisions = datalogInfer(datalog)
406
+ const autoApprove = decisions.filter(d => d.name === 'auto_approve')
407
+ const referToUW = decisions.filter(d => d.name === 'refer_to_underwriter')
441
408
 
442
- executionWitness.tools.push({
443
- name: 'kg.datalog.infer',
444
- input: `${datalog.factCount()} facts, ${datalog.ruleCount()} rules`,
445
- output: `autoApprove=${inferred.autoApprove?.length || 0}, referToUW=${inferred.referToUW?.length || 0}`,
446
- durationMs: Date.now() - toolStart4
447
- })
448
-
449
- console.log(` Facts: ${datalog.factCount()}, Rules: ${datalog.ruleCount()}`)
450
- console.log(' Decisions:')
451
- if (inferred.autoApprove && inferred.autoApprove.length > 0) {
452
- inferred.autoApprove.forEach(a => {
453
- console.log(` ✅ AUTO-APPROVE: ${a[0]}`)
454
- executionWitness.decisions.push({ account: a[0], decision: 'AUTO-APPROVE' })
455
- })
456
- }
457
- if (inferred.referToUW && inferred.referToUW.length > 0) {
458
- inferred.referToUW.forEach(r => {
459
- console.log(` ⚠️ REFER TO UW: ${r[0]}`)
460
- executionWitness.decisions.push({ account: r[0], decision: 'REFER-TO-UW' })
461
- })
462
- }
409
+ console.log(` Inferred decisions: ${decisions.length}`)
410
+ console.log(` Auto-approve: ${autoApprove.length}`)
411
+ autoApprove.forEach(d => console.log(` - ${d.args[0]}`))
412
+ console.log(` Refer to underwriter: ${referToUW.length}`)
413
+ referToUW.forEach(d => console.log(` - ${d.args[0]}`))
463
414
  console.log()
464
415
 
465
- // ═══════════════════════════════════════════════════════════════════════════
466
- // PREMIUM CALCULATION (ISO Standard Methodology)
467
- // ═══════════════════════════════════════════════════════════════════════════
468
- console.log('┌─ TOOL: kg.premium.calculate ────────────────────────────────────────┐')
469
- console.log('│ Formula: Base × Exposure × Territory × Experience × Loss │')
416
+ // Tool 5: Premium Calculation
417
+ console.log('┌─ TOOL: kg.premium.calculate ─────────────────────────────────────────┐')
418
+ console.log('│ Formula: Base × Exposure × Territory × Experience × Loss │')
470
419
  console.log('└─────────────────────────────────────────────────────────────────────┘')
471
420
 
472
- const premiumData = [
473
- { id: 'BUS001', name: 'Acme Manufacturing', baseRate: 2.45, exposure: 45000000, territory: 1.35, loss: 0.45, years: 15 },
474
- { id: 'BUS002', name: 'TechStart LLC', baseRate: 0.85, exposure: 8500000, territory: 1.15, loss: 0.00, years: 3 },
475
- { id: 'BUS003', name: 'SafeHaul Logistics', baseRate: 3.80, exposure: 22000000, territory: 1.05, loss: 0.72, years: 8 },
476
- { id: 'BUS004', name: 'Downtown Restaurant', baseRate: 1.95, exposure: 12000000, territory: 1.25, loss: 0.28, years: 12 }
421
+ const premiums = [
422
+ {
423
+ id: 'BUS001',
424
+ name: 'Acme Manufacturing',
425
+ premium: calculatePremium(12.50, 8500000 / 100, 1.35, 0.45, 15),
426
+ decision: 'STANDARD'
427
+ },
428
+ {
429
+ id: 'BUS002',
430
+ name: 'TechStart LLC',
431
+ premium: calculatePremium(4.25, 1200000 / 100, 1.25, 0.15, 3),
432
+ decision: 'APPROVED'
433
+ },
434
+ {
435
+ id: 'BUS003',
436
+ name: 'SafeHaul Logistics',
437
+ premium: calculatePremium(18.75, 4200000 / 100, 1.45, 0.72, 8),
438
+ decision: 'REFER'
439
+ },
440
+ {
441
+ id: 'BUS004',
442
+ name: 'Downtown Restaurant',
443
+ premium: calculatePremium(8.90, 3100000 / 100, 1.30, 0.28, 12),
444
+ decision: 'STANDARD'
445
+ }
477
446
  ]
478
447
 
479
448
  console.log(' Calculated Premiums:')
480
- premiumData.forEach(p => {
481
- const premium = calculatePremium(p.baseRate, p.exposure / 100, p.territory, p.loss, p.years)
482
- const decision = inferred.autoApprove?.some(a => a[0] === p.id) ? 'APPROVED' :
483
- inferred.referToUW?.some(r => r[0] === p.id) ? 'REFER' : 'STANDARD'
484
- console.log(` - ${p.id} (${p.name}): $${premium.toLocaleString()} [${decision}]`)
449
+ premiums.forEach(p => {
450
+ console.log(` - ${p.id} (${p.name}): $${p.premium.toLocaleString()} [${p.decision}]`)
485
451
  })
486
452
  console.log()
487
453
 
488
- // ═══════════════════════════════════════════════════════════════════════════
489
- // EXECUTION WITNESS (Proof Theory - Curry-Howard Correspondence)
490
- // ═══════════════════════════════════════════════════════════════════════════
491
- executionWitness.endTime = new Date().toISOString()
492
- executionWitness.summary = {
493
- accountsProcessed: riskProfiles.length,
494
- autoApproved: inferred.autoApprove?.length || 0,
495
- referredToUW: inferred.referToUW?.length || 0,
496
- standardProcessing: riskProfiles.length - (inferred.autoApprove?.length || 0) - (inferred.referToUW?.length || 0)
497
- }
454
+ // ─────────────────────────────────────────────────────────────────────────
455
+ // PHASE 4: Agent LLM Call (if real API key available)
456
+ // ─────────────────────────────────────────────────────────────────────────
498
457
 
499
- // Generate deterministic hash of execution
500
- const witnessString = JSON.stringify(executionWitness)
501
- let hash = 0
502
- for (let i = 0; i < witnessString.length; i++) {
503
- const char = witnessString.charCodeAt(i)
504
- hash = ((hash << 5) - hash) + char
505
- hash = hash & hash
458
+ if (MODEL !== 'mock') {
459
+ console.log('┌─ AGENT: agent.call() ─────────────────────────────────────────────┐')
460
+ console.log('│ Natural Language SPARQL → Execution │')
461
+ console.log('└─────────────────────────────────────────────────────────────────────┘')
462
+
463
+ try {
464
+ const result = await agent.call('Find all business accounts with loss ratio above 0.5')
465
+ console.log(` LLM Generated SPARQL: ${result.success ? 'SUCCESS' : 'FAILED'}`)
466
+ if (result.sparql) {
467
+ console.log(` Query: ${result.sparql.slice(0, 60)}...`)
468
+ }
469
+ if (result.error) {
470
+ console.log(` Error: ${result.error}`)
471
+ }
472
+ } catch (e) {
473
+ console.log(` Agent call skipped: ${e.message}`)
474
+ }
475
+ console.log()
506
476
  }
507
- executionWitness.hash = 'sha256:' + Math.abs(hash).toString(16).padStart(16, '0')
508
477
 
509
- // ═══════════════════════════════════════════════════════════════════════════
510
- // FINAL REPORT
511
- // ═══════════════════════════════════════════════════════════════════════════
512
- console.log('═'.repeat(74))
478
+ // ─────────────────────────────────────────────────────────────────────────
479
+ // PHASE 5: Generate Execution Witness (Proof Theory)
480
+ // ─────────────────────────────────────────────────────────────────────────
481
+
482
+ console.log('═'.repeat(78))
513
483
  console.log(' UNDERWRITING DECISION REPORT')
514
- console.log('═'.repeat(74))
484
+ console.log('═'.repeat(78))
515
485
  console.log()
486
+
516
487
  console.log(' SUMMARY:')
517
- console.log(` Accounts processed: ${executionWitness.summary.accountsProcessed}`)
518
- console.log(` Auto-approved: ${executionWitness.summary.autoApproved}`)
519
- console.log(` Referred to UW: ${executionWitness.summary.referredToUW}`)
520
- console.log(` Standard processing: ${executionWitness.summary.standardProcessing}`)
488
+ console.log(` Accounts processed: ${accounts.length}`)
489
+ console.log(` Auto-approved: ${autoApprove.length}`)
490
+ console.log(` Referred to UW: ${referToUW.length}`)
491
+ console.log(` Standard processing: ${accounts.length - autoApprove.length - referToUW.length}`)
521
492
  console.log()
493
+
522
494
  console.log(' RISK INDICATORS:')
523
495
  console.log(' - BUS003 (SafeHaul): HIGH RISK - 72% loss ratio, transportation class')
524
496
  console.log(' - BUS001 (Acme): MODERATE - hurricane exposure, 45% loss ratio')
525
497
  console.log(' - BUS002 (TechStart): LOW - clean history, technology class')
526
498
  console.log(' - BUS004 (Downtown): MODERATE - flood exposure, established')
527
499
  console.log()
500
+
501
+ // Execution Witness
502
+ const witness = {
503
+ agent: agent.getName(),
504
+ model: agent.getModel(),
505
+ timestamp: new Date().toISOString(),
506
+ tools: [
507
+ { name: 'kg.sparql.query', input: 'accounts', output: accounts.length },
508
+ { name: 'kg.graphframe.analyze', input: `${riskVertices.length} nodes`, output: 'pagerank_complete' },
509
+ { name: 'kg.embeddings.similar', input: 'BUS003', output: similarAccounts.length },
510
+ { name: 'kg.datalog.infer', input: '10 facts, 2 rules', output: decisions.length },
511
+ { name: 'kg.premium.calculate', input: '4 accounts', output: premiums.length }
512
+ ],
513
+ decisions: {
514
+ autoApprove: autoApprove.map(d => d.args[0]),
515
+ referToUW: referToUW.map(d => d.args[0])
516
+ },
517
+ premiums: premiums.map(p => ({ id: p.id, premium: p.premium, decision: p.decision })),
518
+ trace: agent.getTrace()
519
+ }
520
+
521
+ // Generate deterministic hash
522
+ const hashInput = JSON.stringify(witness.decisions) + JSON.stringify(witness.premiums)
523
+ let hash = 0
524
+ for (let i = 0; i < hashInput.length; i++) {
525
+ hash = ((hash << 5) - hash) + hashInput.charCodeAt(i)
526
+ hash |= 0
527
+ }
528
+ witness.hash = 'sha256:' + Math.abs(hash).toString(16).padStart(16, '0')
529
+
528
530
  console.log(' EXECUTION WITNESS (for audit):')
529
- console.log(` Hash: ${executionWitness.hash}`)
530
- console.log(` Tools executed: ${executionWitness.tools.length}`)
531
- console.log(` Duration: ${executionWitness.tools.reduce((s, t) => s + t.durationMs, 0)}ms`)
531
+ console.log(` Hash: ${witness.hash}`)
532
+ console.log(` Agent: ${witness.agent}`)
533
+ console.log(` Model: ${witness.model}`)
534
+ console.log(` Tools executed: ${witness.tools.length}`)
535
+ console.log()
536
+ console.log('═'.repeat(78))
537
+ console.log()
538
+ console.log('HyperMind Agent completed successfully.')
532
539
  console.log()
533
- console.log(''.repeat(74))
540
+ console.log('Full witness:', JSON.stringify(witness, null, 2))
541
+ }
534
542
 
535
- return executionWitness
543
+ /**
544
+ * Generate a risk embedding vector based on account characteristics
545
+ */
546
+ function generateRiskEmbedding(industry, lossRatio, yearsInBusiness, territoryMod) {
547
+ const embedding = new Float32Array(384)
548
+
549
+ // Industry encoding
550
+ const industries = {
551
+ manufacturing: 0.5,
552
+ technology: 0.2,
553
+ transportation: 0.8,
554
+ hospitality: 0.4
555
+ }
556
+ embedding[0] = industries[industry] || 0.5
557
+
558
+ // Loss ratio (already 0-1)
559
+ embedding[1] = lossRatio
560
+
561
+ // Years normalized (0-30 range)
562
+ embedding[2] = Math.min(yearsInBusiness / 30, 1.0)
563
+
564
+ // Territory risk
565
+ embedding[3] = (territoryMod - 1.0) * 2 // Normalize 1.0-1.5 to 0-1
566
+
567
+ // Fill rest with deterministic values
568
+ for (let i = 4; i < 384; i++) {
569
+ embedding[i] = ((embedding[0] * embedding[1] * (i + 1)) % 1)
570
+ }
571
+
572
+ return Array.from(embedding)
536
573
  }
537
574
 
538
- // Execute agent
539
- runUnderwritingAgent()
540
- .then(witness => {
541
- console.log('\nHyperMind Agent completed successfully.')
542
- console.log('Full witness:', JSON.stringify(witness, null, 2))
543
- process.exit(0)
544
- })
545
- .catch(err => {
546
- console.error('Agent failed:', err.message)
547
- process.exit(1)
548
- })
575
+ // Run
576
+ main().catch(console.error)