velixar-mcp-server 0.2.4 → 1.2.0
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 +120 -64
- package/dist/api.d.ts +64 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +405 -0
- package/dist/api.js.map +1 -0
- package/dist/errors.d.ts +19 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +52 -0
- package/dist/errors.js.map +1 -0
- package/dist/justify.d.ts +9 -0
- package/dist/justify.d.ts.map +1 -0
- package/dist/justify.js +114 -0
- package/dist/justify.js.map +1 -0
- package/dist/prompts.d.ts +88 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +693 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +25 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +278 -0
- package/dist/resources.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +392 -0
- package/dist/server.js.map +1 -0
- package/dist/simulation/personas.d.ts +41 -0
- package/dist/simulation/personas.d.ts.map +1 -0
- package/dist/simulation/personas.js +173 -0
- package/dist/simulation/personas.js.map +1 -0
- package/dist/simulation/report.d.ts +28 -0
- package/dist/simulation/report.d.ts.map +1 -0
- package/dist/simulation/report.js +105 -0
- package/dist/simulation/report.js.map +1 -0
- package/dist/simulation/runner.d.ts +63 -0
- package/dist/simulation/runner.d.ts.map +1 -0
- package/dist/simulation/runner.js +167 -0
- package/dist/simulation/runner.js.map +1 -0
- package/dist/temporal_merge.d.ts +70 -0
- package/dist/temporal_merge.d.ts.map +1 -0
- package/dist/temporal_merge.js +258 -0
- package/dist/temporal_merge.js.map +1 -0
- package/dist/tools/clairvoyance.d.ts +9 -0
- package/dist/tools/clairvoyance.d.ts.map +1 -0
- package/dist/tools/clairvoyance.js +321 -0
- package/dist/tools/clairvoyance.js.map +1 -0
- package/dist/tools/cognitive.d.ts +10 -0
- package/dist/tools/cognitive.d.ts.map +1 -0
- package/dist/tools/cognitive.js +462 -0
- package/dist/tools/cognitive.js.map +1 -0
- package/dist/tools/construction.d.ts +9 -0
- package/dist/tools/construction.d.ts.map +1 -0
- package/dist/tools/construction.js +350 -0
- package/dist/tools/construction.js.map +1 -0
- package/dist/tools/graph.d.ts +14 -0
- package/dist/tools/graph.d.ts.map +1 -0
- package/dist/tools/graph.js +263 -0
- package/dist/tools/graph.js.map +1 -0
- package/dist/tools/graph_sanitizer.d.ts +24 -0
- package/dist/tools/graph_sanitizer.d.ts.map +1 -0
- package/dist/tools/graph_sanitizer.js +79 -0
- package/dist/tools/graph_sanitizer.js.map +1 -0
- package/dist/tools/lifecycle.d.ts +9 -0
- package/dist/tools/lifecycle.d.ts.map +1 -0
- package/dist/tools/lifecycle.js +1091 -0
- package/dist/tools/lifecycle.js.map +1 -0
- package/dist/tools/livedata.d.ts +9 -0
- package/dist/tools/livedata.d.ts.map +1 -0
- package/dist/tools/livedata.js +222 -0
- package/dist/tools/livedata.js.map +1 -0
- package/dist/tools/memory.d.ts +10 -0
- package/dist/tools/memory.d.ts.map +1 -0
- package/dist/tools/memory.js +275 -0
- package/dist/tools/memory.js.map +1 -0
- package/dist/tools/recall.d.ts +9 -0
- package/dist/tools/recall.d.ts.map +1 -0
- package/dist/tools/recall.js +206 -0
- package/dist/tools/recall.js.map +1 -0
- package/dist/tools/retrieval.d.ts +9 -0
- package/dist/tools/retrieval.d.ts.map +1 -0
- package/dist/tools/retrieval.js +338 -0
- package/dist/tools/retrieval.js.map +1 -0
- package/dist/tools/system.d.ts +12 -0
- package/dist/tools/system.d.ts.map +1 -0
- package/dist/tools/system.js +228 -0
- package/dist/tools/system.js.map +1 -0
- package/dist/types.d.ts +234 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +79 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +174 -0
- package/dist/validate.js.map +1 -0
- package/dist/validate_retrieval.d.ts +33 -0
- package/dist/validate_retrieval.d.ts.map +1 -0
- package/dist/validate_retrieval.js +97 -0
- package/dist/validate_retrieval.js.map +1 -0
- package/package.json +22 -6
- package/server.json +2 -2
- package/.github/workflows/ci.yml +0 -18
- package/.mcpregistry_github_token +0 -1
- package/.mcpregistry_registry_token +0 -1
- package/src/index.js +0 -262
- package/tests/server.test.js +0 -193
package/dist/server.js
ADDED
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ── Velixar MCP Server ──
|
|
3
|
+
// Persistent cognitive context infrastructure for LLMs.
|
|
4
|
+
// See ~/MCP-SERVER-STRATEGY.md for design rationale.
|
|
5
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
6
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
import { loadConfig, ApiClient, log, setClientRoots, validateWorkspace } from './api.js';
|
|
9
|
+
import { memoryTools, handleMemoryTool } from './tools/memory.js';
|
|
10
|
+
import { systemTools, handleSystemTool, recordAudit } from './tools/system.js';
|
|
11
|
+
import { setCapabilitiesVerified } from './tools/system.js';
|
|
12
|
+
import { recallTools, handleRecallTool } from './tools/recall.js';
|
|
13
|
+
import { graphTools, handleGraphTool } from './tools/graph.js';
|
|
14
|
+
import { cognitiveTools, handleCognitiveTool, trackToolCallForIdentity } from './tools/cognitive.js';
|
|
15
|
+
import { lifecycleTools, handleLifecycleTool } from './tools/lifecycle.js';
|
|
16
|
+
import { liveDataTools, handleLiveDataTool } from './tools/livedata.js';
|
|
17
|
+
import { retrievalTools, handleRetrievalTool } from './tools/retrieval.js';
|
|
18
|
+
import { constructionTools, handleConstructionTool } from './tools/construction.js';
|
|
19
|
+
import { clairvoyanceTools, handleClairvoyanceTool } from './tools/clairvoyance.js';
|
|
20
|
+
import { fetchRecall, getResourceList, readResource, getResourceUris, refreshRelevantMemories, markToolCall, isRelevantStale, getConstitutionFallback } from './resources.js';
|
|
21
|
+
import { getPromptList, getPrompt, allPrompts } from './prompts.js';
|
|
22
|
+
// ── AH-5: Anti-pattern detection ──
|
|
23
|
+
const REINFORCE_INTERVAL = parseInt(process.env.VELIXAR_CONSTITUTION_REINFORCE_INTERVAL || '10', 10);
|
|
24
|
+
let _toolCallCount = 0;
|
|
25
|
+
let _recentToolCalls = []; // last 5 tool names for pattern detection
|
|
26
|
+
let _promptReadCount = 0;
|
|
27
|
+
// Search-like tools — any of these count as "did a search" for anti-pattern purposes
|
|
28
|
+
const SEARCH_TOOLS = new Set([
|
|
29
|
+
'velixar_search', 'velixar_batch_search', 'velixar_multi_search',
|
|
30
|
+
'velixar_context', 'velixar_prepare_context', 'velixar_coverage_check',
|
|
31
|
+
]);
|
|
32
|
+
function detectAntiPattern(toolName) {
|
|
33
|
+
const recent = _recentToolCalls;
|
|
34
|
+
const last = recent.length >= 1 ? recent[recent.length - 1] : null;
|
|
35
|
+
// Sequential single searches that should be batched or use multi_search
|
|
36
|
+
if (toolName === 'velixar_search' && last === 'velixar_search') {
|
|
37
|
+
return 'Tip: use velixar_multi_search for merged results with deduplication, or merge:false for per-query results.';
|
|
38
|
+
}
|
|
39
|
+
// Single search right after context — context already searched
|
|
40
|
+
if (toolName === 'velixar_search' && last === 'velixar_context') {
|
|
41
|
+
return 'Note: velixar_context already includes KG-boosted search results. Only use velixar_search if you need a different query.';
|
|
42
|
+
}
|
|
43
|
+
// Store without prior search (check last 3 calls)
|
|
44
|
+
if (toolName === 'velixar_store' && !recent.slice(-3).some(t => SEARCH_TOOLS.has(t))) {
|
|
45
|
+
return 'Warning: search before storing to avoid duplicates.';
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
function trackToolCall(toolName) {
|
|
50
|
+
_toolCallCount++;
|
|
51
|
+
_recentToolCalls.push(toolName);
|
|
52
|
+
if (_recentToolCalls.length > 5)
|
|
53
|
+
_recentToolCalls.shift();
|
|
54
|
+
}
|
|
55
|
+
// ── Init ──
|
|
56
|
+
const config = loadConfig();
|
|
57
|
+
const api = new ApiClient(config);
|
|
58
|
+
// M19: MCP host detection — infer host from transport/environment signals
|
|
59
|
+
const detectedHost = process.env.CURSOR_SESSION_ID ? 'cursor'
|
|
60
|
+
: process.env.CONTINUE_SESSION_ID ? 'continue'
|
|
61
|
+
: process.env.VSCODE_PID ? 'vscode'
|
|
62
|
+
: process.env.WINDSURF_SESSION ? 'windsurf'
|
|
63
|
+
: process.env.KIRO_SESSION ? 'kiro'
|
|
64
|
+
: 'unknown';
|
|
65
|
+
if (detectedHost !== 'unknown')
|
|
66
|
+
log('info', 'host_detected', { host: detectedHost });
|
|
67
|
+
const allTools = [...memoryTools, ...recallTools, ...graphTools, ...cognitiveTools, ...lifecycleTools, ...liveDataTools, ...retrievalTools, ...constructionTools, ...systemTools, ...clairvoyanceTools];
|
|
68
|
+
const allToolNames = allTools.map(t => t.name);
|
|
69
|
+
// ── Build 7.2: Tool Tier System ──
|
|
70
|
+
// H5.1: Tier 2 is default. H5.2: capabilities always included. H5.3: Tier 1 = 9 core tools.
|
|
71
|
+
// Static at startup only (dynamic tiers deferred per 7 Whys Round 2 Chain 13).
|
|
72
|
+
const TOOL_TIERS = {
|
|
73
|
+
1: new Set([
|
|
74
|
+
'velixar_context', 'velixar_search', 'velixar_store', 'velixar_list',
|
|
75
|
+
'velixar_update', 'velixar_delete', 'velixar_session_resume', 'velixar_health', 'velixar_capabilities',
|
|
76
|
+
]),
|
|
77
|
+
2: new Set([
|
|
78
|
+
// Tier 1 + these
|
|
79
|
+
'velixar_context', 'velixar_search', 'velixar_store', 'velixar_list',
|
|
80
|
+
'velixar_update', 'velixar_delete', 'velixar_session_resume', 'velixar_health', 'velixar_capabilities',
|
|
81
|
+
'velixar_multi_search', 'velixar_prepare_context', 'velixar_distill', 'velixar_timeline',
|
|
82
|
+
'velixar_contradictions', 'velixar_patterns', 'velixar_graph_traverse', 'velixar_session_save',
|
|
83
|
+
'velixar_session_recall', 'velixar_coverage_check', 'velixar_export', 'velixar_import', 'velixar_identity',
|
|
84
|
+
]),
|
|
85
|
+
// Tier 3 = all tools (no filtering)
|
|
86
|
+
};
|
|
87
|
+
const toolTier = parseInt(process.env.VELIXAR_TOOL_TIER || '3', 10);
|
|
88
|
+
const tierFilter = TOOL_TIERS[toolTier];
|
|
89
|
+
const exposedTools = tierFilter ? allTools.filter(t => tierFilter.has(t.name)) : allTools;
|
|
90
|
+
if (tierFilter)
|
|
91
|
+
log('info', 'tool_tier_active', { tier: toolTier, exposed: exposedTools.length, total: allTools.length });
|
|
92
|
+
const toolHandlers = [
|
|
93
|
+
{ names: new Set(memoryTools.map(t => t.name)), handler: handleMemoryTool },
|
|
94
|
+
{ names: new Set(recallTools.map(t => t.name)), handler: handleRecallTool },
|
|
95
|
+
{ names: new Set(graphTools.map(t => t.name)), handler: handleGraphTool },
|
|
96
|
+
{ names: new Set(cognitiveTools.map(t => t.name)), handler: handleCognitiveTool },
|
|
97
|
+
{ names: new Set(lifecycleTools.map(t => t.name)), handler: handleLifecycleTool },
|
|
98
|
+
{ names: new Set(liveDataTools.map(t => t.name)), handler: handleLiveDataTool },
|
|
99
|
+
{ names: new Set(retrievalTools.map(t => t.name).concat('velixar_batch_search')), handler: handleRetrievalTool },
|
|
100
|
+
{ names: new Set(constructionTools.map(t => t.name)), handler: handleConstructionTool },
|
|
101
|
+
{ names: new Set(clairvoyanceTools.map(t => t.name)), handler: handleClairvoyanceTool },
|
|
102
|
+
];
|
|
103
|
+
const systemToolNames = new Set(systemTools.map(t => t.name));
|
|
104
|
+
// ── Server ──
|
|
105
|
+
// H7.5: Server name configurable for white-label partners
|
|
106
|
+
const serverName = process.env.VELIXAR_MCP_SERVER_NAME || 'velixar-mcp-server';
|
|
107
|
+
const server = new Server({ name: serverName, version: '1.1.0' }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
|
|
108
|
+
// ── Resources ──
|
|
109
|
+
fetchRecall(api, config); // non-blocking startup
|
|
110
|
+
// H1.4/Chain 8: Startup capability check — verify backend supports filter params
|
|
111
|
+
// 3s timeout, optimistic fallback (per Round 2)
|
|
112
|
+
(async () => {
|
|
113
|
+
try {
|
|
114
|
+
const health = await Promise.race([
|
|
115
|
+
api.get('/health'),
|
|
116
|
+
new Promise(resolve => setTimeout(() => resolve(null), 3000)),
|
|
117
|
+
]);
|
|
118
|
+
if (health) {
|
|
119
|
+
setCapabilitiesVerified(true);
|
|
120
|
+
log('info', 'capabilities_verified', { status: 'ok' });
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
log('warn', 'capabilities_check_timeout', { hint: 'Backend slow — assuming params supported (optimistic)' });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
log('warn', 'capabilities_check_failed', { hint: 'Backend unreachable at startup — filter params unverified' });
|
|
128
|
+
}
|
|
129
|
+
})();
|
|
130
|
+
// Capture client roots for workspace cross-validation
|
|
131
|
+
server.oninitialized = async () => {
|
|
132
|
+
try {
|
|
133
|
+
const rootsResult = await server.listRoots();
|
|
134
|
+
if (rootsResult?.roots?.length) {
|
|
135
|
+
setClientRoots(rootsResult.roots);
|
|
136
|
+
const warning = validateWorkspace(config);
|
|
137
|
+
if (warning)
|
|
138
|
+
log('warn', 'workspace_mismatch', { warning, workspace: config.workspaceId, roots: rootsResult.roots.map(r => r.uri) });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch { /* host doesn't support roots — that's fine */ }
|
|
142
|
+
};
|
|
143
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => getResourceList());
|
|
144
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (req) => readResource(req.params.uri, api));
|
|
145
|
+
// ── Prompts ──
|
|
146
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => getPromptList());
|
|
147
|
+
server.setRequestHandler(GetPromptRequestSchema, async (req) => {
|
|
148
|
+
// AH-6: Log prompt reads for observability
|
|
149
|
+
_promptReadCount++;
|
|
150
|
+
log('info', 'prompt_read', { prompt: req.params.name, host: detectedHost, total_reads: _promptReadCount });
|
|
151
|
+
return getPrompt(req.params.name, (req.params.arguments || {}));
|
|
152
|
+
});
|
|
153
|
+
// ── Tools ──
|
|
154
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: exposedTools }));
|
|
155
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
156
|
+
const { name, arguments: args = {} } = request.params;
|
|
157
|
+
const start = Date.now();
|
|
158
|
+
try {
|
|
159
|
+
let result;
|
|
160
|
+
if (systemToolNames.has(name)) {
|
|
161
|
+
result = await handleSystemTool(name, args, api, config, allToolNames, getResourceUris(), allPrompts.map(p => p.name));
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
const entry = toolHandlers.find(h => h.names.has(name));
|
|
165
|
+
if (!entry) {
|
|
166
|
+
return {
|
|
167
|
+
content: [{
|
|
168
|
+
type: 'text',
|
|
169
|
+
text: `Unknown tool: ${name}\n\nNote: Velixar MCP tools are only available in the primary agent context. If you're seeing this in a subagent, memory operations must be handled by the primary agent.`,
|
|
170
|
+
}],
|
|
171
|
+
isError: true,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
result = await entry.handler(name, args, api, config);
|
|
175
|
+
}
|
|
176
|
+
log('info', 'tool_call', { tool: name, duration_ms: Date.now() - start, error: false });
|
|
177
|
+
// Build 7.1: Record audit entry
|
|
178
|
+
recordAudit(name, Date.now() - start, args, !result.isError);
|
|
179
|
+
// AH-5: Track tool call sequence for anti-pattern detection
|
|
180
|
+
trackToolCall(name);
|
|
181
|
+
// Workspace cross-validation warning
|
|
182
|
+
const wsWarning = validateWorkspace(config);
|
|
183
|
+
let responseText = result.text;
|
|
184
|
+
if (wsWarning) {
|
|
185
|
+
try {
|
|
186
|
+
const parsed = JSON.parse(responseText);
|
|
187
|
+
parsed._workspace_warning = wsWarning;
|
|
188
|
+
responseText = JSON.stringify(parsed);
|
|
189
|
+
}
|
|
190
|
+
catch { /* non-JSON response, skip */ }
|
|
191
|
+
}
|
|
192
|
+
// H1: Constitution fallback — inject compact constitution if host never read the resource
|
|
193
|
+
const constitutionFallback = getConstitutionFallback();
|
|
194
|
+
if (constitutionFallback) {
|
|
195
|
+
try {
|
|
196
|
+
const parsed = JSON.parse(responseText);
|
|
197
|
+
parsed._constitution = constitutionFallback;
|
|
198
|
+
responseText = JSON.stringify(parsed);
|
|
199
|
+
}
|
|
200
|
+
catch { /* non-JSON response, skip */ }
|
|
201
|
+
}
|
|
202
|
+
// AH-5: Constitution reinforcement every N calls (if host never reads prompts)
|
|
203
|
+
if (_promptReadCount === 0 && _toolCallCount > 1 && _toolCallCount % REINFORCE_INTERVAL === 0) {
|
|
204
|
+
try {
|
|
205
|
+
const parsed = JSON.parse(responseText);
|
|
206
|
+
parsed._constitution_reminder = 'Orient first (velixar_context), then narrow with one specialized tool. Batch independent ops. Never fabricate data.';
|
|
207
|
+
responseText = JSON.stringify(parsed);
|
|
208
|
+
}
|
|
209
|
+
catch { /* non-JSON response, skip */ }
|
|
210
|
+
}
|
|
211
|
+
// AH-5: Anti-pattern hint injection
|
|
212
|
+
const antiPatternHint = detectAntiPattern(name);
|
|
213
|
+
if (antiPatternHint) {
|
|
214
|
+
log('info', 'anti_pattern_detected', { tool: name, hint: antiPatternHint });
|
|
215
|
+
try {
|
|
216
|
+
const parsed = JSON.parse(responseText);
|
|
217
|
+
parsed._hint = antiPatternHint;
|
|
218
|
+
responseText = JSON.stringify(parsed);
|
|
219
|
+
}
|
|
220
|
+
catch { /* non-JSON response, skip */ }
|
|
221
|
+
}
|
|
222
|
+
// Track tool calls for resource staleness; refresh after mutations
|
|
223
|
+
markToolCall();
|
|
224
|
+
trackToolCallForIdentity();
|
|
225
|
+
const mutationTools = new Set([
|
|
226
|
+
'velixar_store', 'velixar_update', 'velixar_delete', 'velixar_distill',
|
|
227
|
+
'velixar_batch_store', 'velixar_import', 'velixar_consolidate', 'velixar_retag',
|
|
228
|
+
]);
|
|
229
|
+
if (mutationTools.has(name) || isRelevantStale()) {
|
|
230
|
+
refreshRelevantMemories(api, config); // non-blocking
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
content: [{ type: 'text', text: responseText }],
|
|
234
|
+
...(result.isError ? { isError: true } : {}),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
239
|
+
log('error', 'tool_error', { tool: name, duration_ms: Date.now() - start, error: msg });
|
|
240
|
+
// Build 7.1: Record failed audit
|
|
241
|
+
recordAudit(name, Date.now() - start, args, false);
|
|
242
|
+
// Alert-level for critical failures — any tool that writes memory state
|
|
243
|
+
const criticalWriteTools = new Set([
|
|
244
|
+
'velixar_store', 'velixar_batch_store', 'velixar_import', 'velixar_upload',
|
|
245
|
+
'velixar_consolidate', 'velixar_distill', 'velixar_update', 'velixar_delete',
|
|
246
|
+
]);
|
|
247
|
+
if (criticalWriteTools.has(name)) {
|
|
248
|
+
log('error', 'alert:memory_store_failure', { tool: name, error: msg });
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
content: [{ type: 'text', text: `Error: ${msg}` }],
|
|
252
|
+
isError: true,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
// ── Health Check HTTP Server (optional, standalone mode) ──
|
|
257
|
+
const healthPort = process.env.VELIXAR_HEALTH_PORT ? parseInt(process.env.VELIXAR_HEALTH_PORT, 10) : 0;
|
|
258
|
+
if (healthPort > 0) {
|
|
259
|
+
const { createServer } = await import('node:http');
|
|
260
|
+
createServer(async (_req, res) => {
|
|
261
|
+
try {
|
|
262
|
+
const health = await api.get('/health', true);
|
|
263
|
+
const circuit = (await import('./api.js')).getCircuitState();
|
|
264
|
+
const status = circuit.open ? 503 : 200;
|
|
265
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
266
|
+
res.end(JSON.stringify({ status: circuit.open ? 'degraded' : 'ok', circuit, api: health }));
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
270
|
+
res.end(JSON.stringify({ status: 'error' }));
|
|
271
|
+
}
|
|
272
|
+
}).listen(healthPort, () => log('info', 'health_server_started', { port: healthPort }));
|
|
273
|
+
}
|
|
274
|
+
// ── Start: HTTP or Stdio transport ──
|
|
275
|
+
const httpPort = process.env.VELIXAR_MCP_HTTP_PORT ? parseInt(process.env.VELIXAR_MCP_HTTP_PORT, 10) : 0;
|
|
276
|
+
if (httpPort > 0) {
|
|
277
|
+
// ── Streamable HTTP transport (for Marco Polo / remote MCP clients) ──
|
|
278
|
+
const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
279
|
+
const { createServer, IncomingMessage, ServerResponse } = await import('node:http');
|
|
280
|
+
const { randomUUID } = await import('node:crypto');
|
|
281
|
+
// Per-session transports (stateful mode)
|
|
282
|
+
const sessions = new Map();
|
|
283
|
+
const CORS_HEADERS = {
|
|
284
|
+
'Access-Control-Allow-Origin': process.env.VELIXAR_MCP_CORS_ORIGIN || '*',
|
|
285
|
+
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
|
|
286
|
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization, Mcp-Session-Id',
|
|
287
|
+
'Access-Control-Expose-Headers': 'Mcp-Session-Id',
|
|
288
|
+
};
|
|
289
|
+
const httpServer = createServer(async (req, res) => {
|
|
290
|
+
// CORS preflight
|
|
291
|
+
if (req.method === 'OPTIONS') {
|
|
292
|
+
res.writeHead(204, CORS_HEADERS);
|
|
293
|
+
res.end();
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
// Apply CORS to all responses
|
|
297
|
+
for (const [k, v] of Object.entries(CORS_HEADERS))
|
|
298
|
+
res.setHeader(k, v);
|
|
299
|
+
const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
|
|
300
|
+
// Health endpoint
|
|
301
|
+
if (url.pathname === '/health' && req.method === 'GET') {
|
|
302
|
+
try {
|
|
303
|
+
const health = await api.get('/health', true);
|
|
304
|
+
const circuit = (await import('./api.js')).getCircuitState();
|
|
305
|
+
res.writeHead(circuit.open ? 503 : 200, { 'Content-Type': 'application/json' });
|
|
306
|
+
res.end(JSON.stringify({ status: circuit.open ? 'degraded' : 'ok', transport: 'http', sessions: sessions.size, circuit, api: health }));
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
310
|
+
res.end(JSON.stringify({ status: 'error', transport: 'http' }));
|
|
311
|
+
}
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
// MCP endpoint
|
|
315
|
+
if (url.pathname === '/mcp') {
|
|
316
|
+
// Check for existing session
|
|
317
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
318
|
+
if (req.method === 'POST') {
|
|
319
|
+
// Check if this is an initialize request (new session)
|
|
320
|
+
if (!sessionId) {
|
|
321
|
+
// New session — create transport
|
|
322
|
+
const transport = new StreamableHTTPServerTransport({
|
|
323
|
+
sessionIdGenerator: () => randomUUID(),
|
|
324
|
+
enableJsonResponse: true,
|
|
325
|
+
});
|
|
326
|
+
// Wire up the server to this transport
|
|
327
|
+
transport.onclose = () => {
|
|
328
|
+
const sid = transport.sessionId;
|
|
329
|
+
if (sid)
|
|
330
|
+
sessions.delete(sid);
|
|
331
|
+
log('info', 'http_session_closed', { session_id: sid });
|
|
332
|
+
};
|
|
333
|
+
await server.connect(transport);
|
|
334
|
+
// Handle the request — this will set the session ID
|
|
335
|
+
await transport.handleRequest(req, res);
|
|
336
|
+
// Store the transport by session ID
|
|
337
|
+
const sid = res.getHeader('mcp-session-id');
|
|
338
|
+
if (sid) {
|
|
339
|
+
sessions.set(sid, transport);
|
|
340
|
+
log('info', 'http_session_created', { session_id: sid });
|
|
341
|
+
}
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
// Existing session
|
|
345
|
+
const existingTransport = sessions.get(sessionId);
|
|
346
|
+
if (!existingTransport) {
|
|
347
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
348
|
+
res.end(JSON.stringify({ error: 'Session not found', code: 'SESSION_NOT_FOUND' }));
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
await existingTransport.handleRequest(req, res);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
if (req.method === 'GET') {
|
|
355
|
+
// SSE stream for server-initiated messages
|
|
356
|
+
if (sessionId && sessions.has(sessionId)) {
|
|
357
|
+
await sessions.get(sessionId).handleRequest(req, res);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
361
|
+
res.end(JSON.stringify({ error: 'Session ID required for GET' }));
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
if (req.method === 'DELETE') {
|
|
365
|
+
// Session termination
|
|
366
|
+
if (sessionId && sessions.has(sessionId)) {
|
|
367
|
+
const t = sessions.get(sessionId);
|
|
368
|
+
await t.handleRequest(req, res);
|
|
369
|
+
sessions.delete(sessionId);
|
|
370
|
+
log('info', 'http_session_terminated', { session_id: sessionId });
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
374
|
+
res.end(JSON.stringify({ error: 'Session not found' }));
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
// 404 for everything else
|
|
379
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
380
|
+
res.end(JSON.stringify({ error: 'Not found', endpoints: ['/mcp', '/health'] }));
|
|
381
|
+
});
|
|
382
|
+
httpServer.listen(httpPort, () => {
|
|
383
|
+
log('info', 'http_transport_started', { port: httpPort, endpoint: `/mcp` });
|
|
384
|
+
console.error(`Velixar MCP Server (HTTP) listening on http://localhost:${httpPort}/mcp`);
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
// ── Stdio transport (default, for local MCP clients) ──
|
|
389
|
+
const transport = new StdioServerTransport();
|
|
390
|
+
await server.connect(transport);
|
|
391
|
+
}
|
|
392
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ApiClient } from '../api.js';
|
|
2
|
+
import type { ApiConfig } from '../types.js';
|
|
3
|
+
export interface Persona {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
role: string;
|
|
7
|
+
type: 'data_grounded' | 'archetype' | 'devils_advocate';
|
|
8
|
+
bio: string;
|
|
9
|
+
goals: string;
|
|
10
|
+
behavior: string;
|
|
11
|
+
sensitivity: 'high' | 'medium' | 'low';
|
|
12
|
+
personality: {
|
|
13
|
+
traits: string[];
|
|
14
|
+
decisionStyle: string;
|
|
15
|
+
riskTolerance: string;
|
|
16
|
+
};
|
|
17
|
+
knowledge: string[];
|
|
18
|
+
relationships: string[];
|
|
19
|
+
activityLevel: number;
|
|
20
|
+
systemPrompt: string;
|
|
21
|
+
memoryCount: number;
|
|
22
|
+
}
|
|
23
|
+
export interface PersonaGenerationResult {
|
|
24
|
+
personas: Persona[];
|
|
25
|
+
dataFoundation: {
|
|
26
|
+
totalMemories: number;
|
|
27
|
+
kgEntities: number;
|
|
28
|
+
groundedCount: number;
|
|
29
|
+
archetypeCount: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
type LLMCall = (system: string, user: string) => Promise<string>;
|
|
33
|
+
export declare function generatePersonas(question: string, variables: Record<string, string>, api: ApiClient, config: ApiConfig, llmCall: LLMCall, opts: {
|
|
34
|
+
agentCount?: number;
|
|
35
|
+
personaTypes?: string[];
|
|
36
|
+
fresh?: boolean;
|
|
37
|
+
simulationId: string;
|
|
38
|
+
}): Promise<PersonaGenerationResult>;
|
|
39
|
+
export declare function generateDevilsAdvocates(consensus: string, simId: string): Persona[];
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=personas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"personas.d.ts","sourceRoot":"","sources":["../../src/simulation/personas.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,eAAe,GAAG,WAAW,GAAG,iBAAiB,CAAC;IACxD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACvC,WAAW,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAChF,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,cAAc,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9G;AAaD,KAAK,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEjE,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC5F,OAAO,CAAC,uBAAuB,CAAC,CAyClC;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,CAUnF"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// ── Persona Generator v2 ──
|
|
2
|
+
// Upgraded based on MiroFish comparison: richer profiles, behavioral depth,
|
|
3
|
+
// activity patterns, LLM-generated personas instead of templates.
|
|
4
|
+
import { validateSearchResponse } from '../validate.js';
|
|
5
|
+
const ROLE_DEFAULTS = {
|
|
6
|
+
customer: { goals: 'Maximize value, minimize cost, evaluate alternatives', traits: ['price-aware', 'comparison-driven', 'loyalty-conditional'], riskTolerance: 'medium' },
|
|
7
|
+
competitor: { goals: 'Capture market share, exploit weaknesses', traits: ['aggressive', 'opportunistic', 'fast-moving'], riskTolerance: 'high' },
|
|
8
|
+
regulator: { goals: 'Ensure fairness, protect consumers, enforce rules', traits: ['rule-based', 'slow-moving', 'precedent-driven'], riskTolerance: 'low' },
|
|
9
|
+
internal_team: { goals: 'Hit targets while retaining customers', traits: ['revenue-focused', 'risk-averse', 'data-driven'], riskTolerance: 'low' },
|
|
10
|
+
market_force: { goals: 'Reflect macro trends and industry dynamics', traits: ['impersonal', 'trend-driven', 'cyclical'], riskTolerance: 'neutral' },
|
|
11
|
+
investor: { goals: 'Maximize returns, evaluate growth vs profitability', traits: ['metrics-driven', 'benchmark-comparing', 'impatient'], riskTolerance: 'high' },
|
|
12
|
+
media: { goals: 'Amplify narratives, drive engagement', traits: ['attention-seeking', 'narrative-driven', 'reactive'], riskTolerance: 'high' },
|
|
13
|
+
partner: { goals: 'Protect joint value, maintain relationship', traits: ['collaborative', 'contract-aware', 'long-term-oriented'], riskTolerance: 'low' },
|
|
14
|
+
};
|
|
15
|
+
export async function generatePersonas(question, variables, api, config, llmCall, opts) {
|
|
16
|
+
const count = Math.min(opts.agentCount || 12, 30);
|
|
17
|
+
const types = opts.personaTypes?.length ? opts.personaTypes : inferTypes(question);
|
|
18
|
+
// Gather workspace context in parallel
|
|
19
|
+
const [memories, kgEntities] = await Promise.all([
|
|
20
|
+
searchWorkspace(question, variables, api, config, opts.fresh),
|
|
21
|
+
traverseKG(question, api),
|
|
22
|
+
]);
|
|
23
|
+
const personas = [];
|
|
24
|
+
const perType = Math.max(1, Math.floor(count / types.length));
|
|
25
|
+
const sensitivities = ['high', 'medium', 'low'];
|
|
26
|
+
for (const role of types) {
|
|
27
|
+
for (let i = 0; i < perType && personas.length < count; i++) {
|
|
28
|
+
const sensitivity = sensitivities[i % 3];
|
|
29
|
+
const roleMemories = memories.filter(m => m.content.toLowerCase().includes(role) || m.relevance > 0.6).slice(0, 8);
|
|
30
|
+
const roleKG = kgEntities.filter(e => e.toLowerCase().includes(role) || role.includes(e.split(' ')[0].toLowerCase())).slice(0, 3);
|
|
31
|
+
const persona = await buildPersonaWithLLM(role, i, sensitivity, question, variables, roleMemories, roleKG, llmCall, opts.simulationId);
|
|
32
|
+
personas.push(persona);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
personas,
|
|
37
|
+
dataFoundation: {
|
|
38
|
+
totalMemories: memories.length,
|
|
39
|
+
kgEntities: kgEntities.length,
|
|
40
|
+
groundedCount: personas.filter(p => p.type === 'data_grounded').length,
|
|
41
|
+
archetypeCount: personas.filter(p => p.type === 'archetype').length,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function generateDevilsAdvocates(consensus, simId) {
|
|
46
|
+
const base = { type: 'devils_advocate', goals: '', behavior: '', sensitivity: 'high', knowledge: [], relationships: [], activityLevel: 1.0, memoryCount: 0 };
|
|
47
|
+
return [
|
|
48
|
+
{ ...base, id: `${simId}-da-1`, name: 'The Skeptic', role: 'devils_advocate', bio: 'Challenges consensus by finding unstated assumptions.',
|
|
49
|
+
personality: { traits: ['contrarian', 'analytical', 'thorough'], decisionStyle: 'evidence-demanding', riskTolerance: 'seeks-risk-in-consensus' },
|
|
50
|
+
systemPrompt: `You are "The Skeptic." The emerging consensus is: "${consensus}". Find the strongest argument AGAINST it. Focus on unstated assumptions, historical precedents where similar consensus was wrong, and hidden risks. Be specific — name what could go wrong and why. 2-4 sentences.` },
|
|
51
|
+
{ ...base, id: `${simId}-da-2`, name: 'The Edge Case', role: 'devils_advocate', bio: 'Identifies tail risks and black swan scenarios.',
|
|
52
|
+
personality: { traits: ['creative', 'paranoid', 'scenario-oriented'], decisionStyle: 'worst-case-first', riskTolerance: 'assumes-tail-risk' },
|
|
53
|
+
systemPrompt: `You are "The Edge Case." The emerging consensus is: "${consensus}". Identify the scenario where this completely breaks down. Think: what external shock, competitor move, or customer behavior would make this prediction catastrophically wrong? Be specific. 2-4 sentences.` },
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
// ── Internal ──
|
|
57
|
+
async function searchWorkspace(question, variables, api, config, fresh) {
|
|
58
|
+
const queries = [
|
|
59
|
+
question.slice(0, 100),
|
|
60
|
+
Object.values(variables).join(' ').slice(0, 100),
|
|
61
|
+
...(fresh ? [] : ['simulation insight']),
|
|
62
|
+
].filter(Boolean);
|
|
63
|
+
const results = [];
|
|
64
|
+
const seen = new Set();
|
|
65
|
+
const fetches = await Promise.allSettled(queries.map(q => {
|
|
66
|
+
const params = new URLSearchParams({ q, user_id: config.userId, limit: '10' });
|
|
67
|
+
return api.get(`/memory/search?${params}`, true);
|
|
68
|
+
}));
|
|
69
|
+
for (const r of fetches) {
|
|
70
|
+
if (r.status !== 'fulfilled')
|
|
71
|
+
continue;
|
|
72
|
+
try {
|
|
73
|
+
const v = validateSearchResponse(r.value, '/memory/search');
|
|
74
|
+
for (const m of v.memories) {
|
|
75
|
+
if (seen.has(m.id) || (m.score ?? 0) < 0.3)
|
|
76
|
+
continue;
|
|
77
|
+
seen.add(m.id);
|
|
78
|
+
results.push({ content: m.content.slice(0, 400), relevance: m.score ?? 0, id: m.id });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch { /* skip */ }
|
|
82
|
+
}
|
|
83
|
+
return results.sort((a, b) => b.relevance - a.relevance).slice(0, 30);
|
|
84
|
+
}
|
|
85
|
+
async function traverseKG(question, api) {
|
|
86
|
+
try {
|
|
87
|
+
const data = await api.post('/graph/traverse', {
|
|
88
|
+
entity: question.split(' ').slice(0, 3).join(' '), max_hops: 2,
|
|
89
|
+
});
|
|
90
|
+
const nodes = Array.isArray(data?.nodes) ? data.nodes : [];
|
|
91
|
+
return nodes.map(n => String(n.label || n.content || '')).filter(Boolean).slice(0, 10);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function inferTypes(question) {
|
|
98
|
+
const q = question.toLowerCase();
|
|
99
|
+
const types = [];
|
|
100
|
+
if (/pric|cost|fee|rate|revenue|churn/.test(q))
|
|
101
|
+
types.push('customer', 'competitor', 'internal_team');
|
|
102
|
+
if (/regulat|compliance|law|policy|government/.test(q))
|
|
103
|
+
types.push('regulator');
|
|
104
|
+
if (/market|industry|trend|economy|macro/.test(q))
|
|
105
|
+
types.push('market_force');
|
|
106
|
+
if (/invest|fund|valuation|growth|ipo/.test(q))
|
|
107
|
+
types.push('investor');
|
|
108
|
+
if (/press|media|public|reputation|brand/.test(q))
|
|
109
|
+
types.push('media');
|
|
110
|
+
if (/partner|channel|integration|alliance/.test(q))
|
|
111
|
+
types.push('partner');
|
|
112
|
+
if (types.length === 0)
|
|
113
|
+
types.push('customer', 'competitor', 'internal_team');
|
|
114
|
+
if (!types.includes('customer') && types.length < 4)
|
|
115
|
+
types.unshift('customer');
|
|
116
|
+
return [...new Set(types)];
|
|
117
|
+
}
|
|
118
|
+
async function buildPersonaWithLLM(role, index, sensitivity, question, variables, memories, kgEntities, llmCall, simId) {
|
|
119
|
+
const defaults = ROLE_DEFAULTS[role] || ROLE_DEFAULTS.customer;
|
|
120
|
+
const id = `${simId}-${role}-${index}`;
|
|
121
|
+
const grounded = memories.length >= 3;
|
|
122
|
+
const variableStr = Object.entries(variables).map(([k, v]) => `${k}: ${v}`).join(', ');
|
|
123
|
+
// Use LLM to generate a rich persona (like MiroFish's profile generator)
|
|
124
|
+
let bio, behavior, name;
|
|
125
|
+
try {
|
|
126
|
+
const raw = await llmCall('You generate concise character profiles for business simulations. Respond in JSON only.', `Create a ${role.replace(/_/g, ' ')} persona for this scenario: "${question}" (variables: ${variableStr}).
|
|
127
|
+
Sensitivity to the scenario: ${sensitivity}.
|
|
128
|
+
${memories.length > 0 ? `Context from real data:\n${memories.slice(0, 5).map(m => `- ${m.content.slice(0, 150)}`).join('\n')}` : 'No specific data available — use general knowledge.'}
|
|
129
|
+
${kgEntities.length > 0 ? `Related entities: ${kgEntities.join(', ')}` : ''}
|
|
130
|
+
|
|
131
|
+
Return JSON: {"name":"<realistic name>","bio":"<1 sentence>","behavior":"<2 sentences: how they react to this scenario specifically>","traits":["<3 traits>"],"decision_style":"<one phrase>"}`);
|
|
132
|
+
const parsed = JSON.parse(raw.replace(/```json?\n?/g, '').replace(/```/g, '').trim());
|
|
133
|
+
name = parsed.name || `${role} ${index + 1}`;
|
|
134
|
+
bio = parsed.bio || `A ${role} stakeholder.`;
|
|
135
|
+
behavior = parsed.behavior || defaults.goals;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
name = `${role.replace(/_/g, ' ')} ${index + 1}`.replace(/\b\w/g, c => c.toUpperCase());
|
|
139
|
+
bio = `A ${role.replace(/_/g, ' ')} stakeholder in this scenario.`;
|
|
140
|
+
behavior = defaults.goals;
|
|
141
|
+
}
|
|
142
|
+
const knowledgeLines = memories.map(m => m.content.slice(0, 300));
|
|
143
|
+
const relationshipLines = kgEntities.map(e => `Connected to: ${e}`);
|
|
144
|
+
const systemPrompt = [
|
|
145
|
+
`You are "${name}" — ${bio}`,
|
|
146
|
+
`Role: ${role.replace(/_/g, ' ')}. Sensitivity to scenario variables: ${sensitivity}.`,
|
|
147
|
+
`Behavior: ${behavior}`,
|
|
148
|
+
'',
|
|
149
|
+
`SCENARIO: ${question}`,
|
|
150
|
+
`VARIABLES: ${variableStr || 'None specified.'}`,
|
|
151
|
+
'',
|
|
152
|
+
knowledgeLines.length > 0
|
|
153
|
+
? `YOUR KNOWLEDGE (from real data):\n${knowledgeLines.slice(0, 8).map((k, i) => `${i + 1}. ${k}`).join('\n')}`
|
|
154
|
+
: 'You have no specific data — reason from general knowledge about your role.',
|
|
155
|
+
relationshipLines.length > 0 ? `\nRELATIONSHIPS:\n${relationshipLines.join('\n')}` : '',
|
|
156
|
+
'',
|
|
157
|
+
'Respond with a specific action or reaction (2-4 sentences). State what you DO and WHY. Reference specific facts from your knowledge when possible.',
|
|
158
|
+
].filter(Boolean).join('\n');
|
|
159
|
+
return {
|
|
160
|
+
id, name, role, bio,
|
|
161
|
+
type: grounded ? 'data_grounded' : 'archetype',
|
|
162
|
+
goals: defaults.goals,
|
|
163
|
+
behavior,
|
|
164
|
+
sensitivity,
|
|
165
|
+
personality: { traits: defaults.traits, decisionStyle: 'contextual', riskTolerance: defaults.riskTolerance },
|
|
166
|
+
knowledge: knowledgeLines,
|
|
167
|
+
relationships: relationshipLines,
|
|
168
|
+
activityLevel: sensitivity === 'high' ? 0.9 : sensitivity === 'medium' ? 0.7 : 0.5,
|
|
169
|
+
systemPrompt,
|
|
170
|
+
memoryCount: memories.length,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=personas.js.map
|