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.
- package/README.md +515 -0
- package/examples/fraud-detection-agent.js +596 -392
- package/examples/underwriting-agent.js +457 -429
- package/package.json +1 -1
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ============================================================================
|
|
3
2
|
* UNDERWRITING AGENT - Built on HyperMind Framework
|
|
4
|
-
* ============================================================================
|
|
5
3
|
*
|
|
6
|
-
* This
|
|
4
|
+
* This example demonstrates proper agentic flow using the HyperMind framework:
|
|
7
5
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
-
*
|
|
19
|
-
* -
|
|
20
|
-
* -
|
|
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
|
-
//
|
|
38
|
-
//
|
|
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
|
-
|
|
42
|
-
|
|
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
|
-
|
|
171
|
-
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
213
|
-
|
|
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 (
|
|
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
|
|
222
|
-
const lossMod = lossRatio < 0.30 ? 0.85 :
|
|
223
|
-
lossRatio < 0.50 ? 1.00 :
|
|
224
|
-
lossRatio < 0.70 ? 1.15 :
|
|
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
|
-
//
|
|
233
|
-
//
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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(
|
|
247
|
-
console.log('═'.repeat(
|
|
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
|
|
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
|
-
//
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
startTime: new Date().toISOString(),
|
|
257
|
-
tools: [],
|
|
258
|
-
decisions: []
|
|
259
|
-
}
|
|
248
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
249
|
+
// PHASE 1: Initialize Knowledge Graph
|
|
250
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
260
251
|
|
|
261
|
-
|
|
262
|
-
|
|
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: TTL → Graph │')
|
|
266
254
|
console.log('└─────────────────────────────────────────────────────────────────────┘')
|
|
267
255
|
|
|
268
|
-
const toolStart1 = Date.now()
|
|
269
256
|
const db = new GraphDB('http://underwriting.org/kb')
|
|
270
|
-
db.loadTtl(
|
|
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
|
-
|
|
273
|
-
|
|
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
|
-
|
|
276
|
-
name: '
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
-
//
|
|
285
|
-
//
|
|
286
|
-
|
|
287
|
-
|
|
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
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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
|
-
|
|
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
|
|
359
|
-
|
|
360
|
-
|
|
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
|
-
|
|
363
|
-
|
|
364
|
-
{
|
|
365
|
-
{
|
|
366
|
-
{
|
|
367
|
-
{
|
|
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
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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
|
-
|
|
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
|
-
|
|
378
|
-
const similarProfiles = JSON.parse(embeddings.findSimilar('BUS003', 5, 0.3))
|
|
354
|
+
const embeddings = new EmbeddingService()
|
|
379
355
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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
|
-
|
|
362
|
+
const similarAccounts = embeddingsSimilar(embeddings, 'BUS003', 0.5)
|
|
388
363
|
console.log(' Accounts similar to BUS003 (highest risk):')
|
|
389
|
-
|
|
390
|
-
.
|
|
391
|
-
|
|
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
|
|
411
|
-
datalog.addFact(JSON.stringify({ predicate: '
|
|
412
|
-
datalog.addFact(JSON.stringify({ predicate: '
|
|
413
|
-
datalog.addFact(JSON.stringify({ predicate: '
|
|
414
|
-
datalog.addFact(JSON.stringify({ predicate: '
|
|
415
|
-
|
|
416
|
-
//
|
|
417
|
-
datalog.addFact(JSON.stringify({ predicate: '
|
|
418
|
-
datalog.addFact(JSON.stringify({ predicate: '
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
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: '
|
|
390
|
+
head: { predicate: 'auto_approve', terms: ['?X'] },
|
|
424
391
|
body: [
|
|
425
|
-
{ predicate: '
|
|
426
|
-
{ predicate: '
|
|
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: '
|
|
398
|
+
head: { predicate: 'refer_to_underwriter', terms: ['?X'] },
|
|
434
399
|
body: [
|
|
435
|
-
{ predicate: '
|
|
400
|
+
{ predicate: 'account', terms: ['?X'] },
|
|
401
|
+
{ predicate: 'high_loss_ratio', terms: ['?X'] }
|
|
436
402
|
]
|
|
437
403
|
}))
|
|
438
404
|
|
|
439
|
-
const
|
|
440
|
-
const
|
|
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
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
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
|
-
|
|
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
|
|
473
|
-
{
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
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
|
-
|
|
481
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
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
|
-
//
|
|
511
|
-
//
|
|
512
|
-
|
|
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(
|
|
484
|
+
console.log('═'.repeat(78))
|
|
515
485
|
console.log()
|
|
486
|
+
|
|
516
487
|
console.log(' SUMMARY:')
|
|
517
|
-
console.log(` Accounts processed: ${
|
|
518
|
-
console.log(` Auto-approved: ${
|
|
519
|
-
console.log(` Referred to UW: ${
|
|
520
|
-
console.log(` Standard processing: ${
|
|
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: ${
|
|
530
|
-
console.log(`
|
|
531
|
-
console.log(`
|
|
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('
|
|
540
|
+
console.log('Full witness:', JSON.stringify(witness, null, 2))
|
|
541
|
+
}
|
|
534
542
|
|
|
535
|
-
|
|
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
|
-
//
|
|
539
|
-
|
|
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)
|