@4da/mcp-server 5.0.0 → 5.0.2
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 +20 -2
- package/dist/auth-context.d.ts +49 -0
- package/dist/auth-context.js +72 -0
- package/dist/auth.d.ts +42 -15
- package/dist/auth.js +160 -49
- package/dist/http-transport.d.ts +61 -3
- package/dist/http-transport.js +159 -49
- package/dist/index.js +46 -8
- package/dist/setup.js +0 -0
- package/dist/tool-dispatch.d.ts +4 -0
- package/dist/tool-dispatch.js +6 -0
- package/package.json +13 -25
- package/dist/llm.d.ts +0 -162
- package/dist/llm.js +0 -502
- package/dist/output-manager.d.ts +0 -156
- package/dist/output-manager.js +0 -157
- package/dist/scheduler/core.d.ts +0 -25
- package/dist/scheduler/core.js +0 -61
- package/dist/scheduler/freshness.d.ts +0 -17
- package/dist/scheduler/freshness.js +0 -41
- package/dist/scheduler/index.d.ts +0 -21
- package/dist/scheduler/index.js +0 -32
- package/dist/scheduler/refreshers.d.ts +0 -21
- package/dist/scheduler/refreshers.js +0 -21
package/dist/llm.js
DELETED
|
@@ -1,502 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
/**
|
|
3
|
-
* LLM Client for 4DA MCP Server
|
|
4
|
-
*
|
|
5
|
-
* Provides intelligence synthesis over raw tool data.
|
|
6
|
-
* Supports Anthropic Claude, OpenAI, and Ollama (local).
|
|
7
|
-
*
|
|
8
|
-
* Features:
|
|
9
|
-
* - Tiered model selection (use smaller models for simpler tasks)
|
|
10
|
-
* - Optimized prompts for local models
|
|
11
|
-
* - Automatic fallback
|
|
12
|
-
*/
|
|
13
|
-
// =============================================================================
|
|
14
|
-
// Model Tiers - Optimized for 16GB VRAM (RTX 4080 Super)
|
|
15
|
-
// =============================================================================
|
|
16
|
-
/**
|
|
17
|
-
* Default models for different task complexities
|
|
18
|
-
* Optimized for 16GB VRAM
|
|
19
|
-
*/
|
|
20
|
-
export const DEFAULT_OLLAMA_MODELS = {
|
|
21
|
-
light: "gemma3:4b",
|
|
22
|
-
medium: "qwen3:8b",
|
|
23
|
-
heavy: "qwen3:14b",
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* Task complexity by tool
|
|
27
|
-
*/
|
|
28
|
-
export const TOOL_COMPLEXITY = {
|
|
29
|
-
daily_briefing: "medium", // Needs to synthesize multiple themes
|
|
30
|
-
score_autopsy: "heavy", // Needs to reason about score correctness
|
|
31
|
-
trend_analysis: "heavy", // Needs pattern recognition + prediction
|
|
32
|
-
context_analysis: "medium", // Structured advice
|
|
33
|
-
topic_connections: "heavy", // Graph reasoning
|
|
34
|
-
};
|
|
35
|
-
// =============================================================================
|
|
36
|
-
// Configuration
|
|
37
|
-
// =============================================================================
|
|
38
|
-
import { readFileSync, existsSync, statSync } from "fs";
|
|
39
|
-
import { join, dirname } from "path";
|
|
40
|
-
import { fileURLToPath } from "node:url";
|
|
41
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
42
|
-
const __dirname = dirname(__filename);
|
|
43
|
-
/**
|
|
44
|
-
* Find settings.json by looking in common locations
|
|
45
|
-
*/
|
|
46
|
-
function findSettingsFile() {
|
|
47
|
-
// 1. Environment variable (highest priority)
|
|
48
|
-
const envPath = process.env.FOURDA_SETTINGS_PATH;
|
|
49
|
-
if (envPath && existsSync(envPath)) {
|
|
50
|
-
return envPath;
|
|
51
|
-
}
|
|
52
|
-
// 2. Sibling to database path
|
|
53
|
-
const dbPath = process.env.FOURDA_DB_PATH;
|
|
54
|
-
if (dbPath) {
|
|
55
|
-
const settingsPath = join(dirname(dbPath), "settings.json");
|
|
56
|
-
if (existsSync(settingsPath)) {
|
|
57
|
-
return settingsPath;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
// 3. Common relative locations (portable — no hardcoded dev paths)
|
|
61
|
-
const searchPaths = [
|
|
62
|
-
join(process.cwd(), "data", "settings.json"), // CWD/data/
|
|
63
|
-
join(__dirname, "..", "..", "data", "settings.json"), // Project root (mcp-4da-server/../data/)
|
|
64
|
-
join(process.cwd(), "..", "data", "settings.json"), // Parent/data/
|
|
65
|
-
];
|
|
66
|
-
for (const candidate of searchPaths) {
|
|
67
|
-
if (existsSync(candidate)) {
|
|
68
|
-
return candidate;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
// =============================================================================
|
|
74
|
-
// Settings Cache — re-read only when file mtime changes
|
|
75
|
-
// =============================================================================
|
|
76
|
-
let _cachedConfig = null;
|
|
77
|
-
let _cachedSettingsPath = null;
|
|
78
|
-
let _cachedMtimeMs = 0;
|
|
79
|
-
/**
|
|
80
|
-
* Get LLM configuration from settings.json file.
|
|
81
|
-
*
|
|
82
|
-
* Uses a cached approach: the file is only re-read if its mtime has changed,
|
|
83
|
-
* avoiding unnecessary filesystem reads on every tool invocation.
|
|
84
|
-
*/
|
|
85
|
-
export function getLLMConfig(_db) {
|
|
86
|
-
const settingsPath = findSettingsFile();
|
|
87
|
-
if (!settingsPath) {
|
|
88
|
-
// Return environment-based config as fallback
|
|
89
|
-
return {
|
|
90
|
-
provider: process.env.LLM_PROVIDER || null,
|
|
91
|
-
anthropic_api_key: process.env.ANTHROPIC_API_KEY,
|
|
92
|
-
openai_api_key: process.env.OPENAI_API_KEY,
|
|
93
|
-
ollama_url: process.env.OLLAMA_URL || "http://localhost:11434",
|
|
94
|
-
model: process.env.LLM_MODEL,
|
|
95
|
-
model_light: process.env.LLM_MODEL_LIGHT,
|
|
96
|
-
model_heavy: process.env.LLM_MODEL_HEAVY,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
// Check if we can use the cached config
|
|
100
|
-
try {
|
|
101
|
-
const currentMtimeMs = statSync(settingsPath).mtimeMs;
|
|
102
|
-
if (_cachedConfig &&
|
|
103
|
-
_cachedSettingsPath === settingsPath &&
|
|
104
|
-
_cachedMtimeMs === currentMtimeMs) {
|
|
105
|
-
return _cachedConfig;
|
|
106
|
-
}
|
|
107
|
-
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
108
|
-
const llm = settings.llm || {};
|
|
109
|
-
const config = {
|
|
110
|
-
provider: (llm.provider ?? null),
|
|
111
|
-
anthropic_api_key: llm.api_key || llm.anthropic_api_key,
|
|
112
|
-
openai_api_key: llm.openai_api_key,
|
|
113
|
-
ollama_url: llm.base_url || llm.ollama_url || "http://localhost:11434",
|
|
114
|
-
model: llm.model,
|
|
115
|
-
model_light: llm.model_light,
|
|
116
|
-
model_heavy: llm.model_heavy,
|
|
117
|
-
};
|
|
118
|
-
// Update cache
|
|
119
|
-
_cachedConfig = config;
|
|
120
|
-
_cachedSettingsPath = settingsPath;
|
|
121
|
-
_cachedMtimeMs = currentMtimeMs;
|
|
122
|
-
return config;
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
console.error("Failed to read settings.json:", error);
|
|
126
|
-
return { provider: null };
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Check if LLM synthesis is available
|
|
131
|
-
*/
|
|
132
|
-
export function canSynthesize(config) {
|
|
133
|
-
if (!config.provider)
|
|
134
|
-
return false;
|
|
135
|
-
switch (config.provider) {
|
|
136
|
-
case "anthropic":
|
|
137
|
-
return !!config.anthropic_api_key;
|
|
138
|
-
case "openai":
|
|
139
|
-
return !!config.openai_api_key;
|
|
140
|
-
case "ollama":
|
|
141
|
-
return true; // Ollama doesn't need a key
|
|
142
|
-
default:
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Get the appropriate model for task complexity
|
|
148
|
-
*/
|
|
149
|
-
function getModelForComplexity(config, complexity) {
|
|
150
|
-
if (config.provider !== "ollama") {
|
|
151
|
-
// Cloud providers use the configured model
|
|
152
|
-
return config.model || (config.provider === "anthropic" ? "claude-sonnet-4-6" : "gpt-4o");
|
|
153
|
-
}
|
|
154
|
-
// Ollama: use tiered models
|
|
155
|
-
switch (complexity) {
|
|
156
|
-
case "light":
|
|
157
|
-
return config.model_light || config.model || DEFAULT_OLLAMA_MODELS.light;
|
|
158
|
-
case "medium":
|
|
159
|
-
return config.model || DEFAULT_OLLAMA_MODELS.medium;
|
|
160
|
-
case "heavy":
|
|
161
|
-
return config.model_heavy || config.model || DEFAULT_OLLAMA_MODELS.heavy;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
// =============================================================================
|
|
165
|
-
// Synthesis
|
|
166
|
-
// =============================================================================
|
|
167
|
-
/**
|
|
168
|
-
* Synthesize insights using LLM
|
|
169
|
-
*
|
|
170
|
-
* Accepts an optional AbortSignal to allow timeout/cancellation of the
|
|
171
|
-
* underlying fetch calls.
|
|
172
|
-
*/
|
|
173
|
-
export async function synthesize(config, request, signal) {
|
|
174
|
-
if (!canSynthesize(config)) {
|
|
175
|
-
throw new Error("LLM not configured - cannot synthesize");
|
|
176
|
-
}
|
|
177
|
-
const startTime = Date.now();
|
|
178
|
-
const complexity = request.complexity || "medium";
|
|
179
|
-
let result;
|
|
180
|
-
switch (config.provider) {
|
|
181
|
-
case "anthropic":
|
|
182
|
-
result = await synthesizeAnthropic(config, request, signal);
|
|
183
|
-
break;
|
|
184
|
-
case "openai":
|
|
185
|
-
result = await synthesizeOpenAI(config, request, signal);
|
|
186
|
-
break;
|
|
187
|
-
case "ollama":
|
|
188
|
-
result = await synthesizeOllama(config, request, complexity, signal);
|
|
189
|
-
break;
|
|
190
|
-
default:
|
|
191
|
-
throw new Error(`Unknown LLM provider: ${config.provider}`);
|
|
192
|
-
}
|
|
193
|
-
result.latency_ms = Date.now() - startTime;
|
|
194
|
-
return result;
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Synthesize with a timeout wrapper.
|
|
198
|
-
*
|
|
199
|
-
* Wraps the LLM API call with an AbortController + configurable timeout.
|
|
200
|
-
* On timeout, throws a descriptive error so callers can fall back to
|
|
201
|
-
* data-only results.
|
|
202
|
-
*
|
|
203
|
-
* @param config - LLM provider configuration
|
|
204
|
-
* @param request - Synthesis request (system prompt, user prompt, etc.)
|
|
205
|
-
* @param timeoutMs - Timeout in milliseconds (default: 30000)
|
|
206
|
-
*/
|
|
207
|
-
export async function synthesizeWithTimeout(config, request, timeoutMs = 30000) {
|
|
208
|
-
const controller = new AbortController();
|
|
209
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
210
|
-
try {
|
|
211
|
-
return await synthesize(config, request, controller.signal);
|
|
212
|
-
}
|
|
213
|
-
catch (error) {
|
|
214
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
215
|
-
throw new Error(`LLM timeout after ${timeoutMs / 1000}s`);
|
|
216
|
-
}
|
|
217
|
-
throw error;
|
|
218
|
-
}
|
|
219
|
-
finally {
|
|
220
|
-
clearTimeout(timeout);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Anthropic Claude synthesis
|
|
225
|
-
*/
|
|
226
|
-
async function synthesizeAnthropic(config, request, signal) {
|
|
227
|
-
const model = config.model || "claude-sonnet-4-6";
|
|
228
|
-
const maxTokens = request.max_tokens || 1024;
|
|
229
|
-
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
230
|
-
method: "POST",
|
|
231
|
-
headers: {
|
|
232
|
-
"Content-Type": "application/json",
|
|
233
|
-
"x-api-key": config.anthropic_api_key,
|
|
234
|
-
"anthropic-version": "2023-06-01",
|
|
235
|
-
},
|
|
236
|
-
body: JSON.stringify({
|
|
237
|
-
model,
|
|
238
|
-
max_tokens: maxTokens,
|
|
239
|
-
system: request.system,
|
|
240
|
-
messages: [{ role: "user", content: request.prompt }],
|
|
241
|
-
}),
|
|
242
|
-
signal,
|
|
243
|
-
});
|
|
244
|
-
if (!response.ok) {
|
|
245
|
-
const error = await response.text();
|
|
246
|
-
throw new Error(`Anthropic API error: ${error}`);
|
|
247
|
-
}
|
|
248
|
-
const data = (await response.json());
|
|
249
|
-
return {
|
|
250
|
-
synthesis: data.content[0]?.text || "",
|
|
251
|
-
model_used: model,
|
|
252
|
-
tokens_used: data.usage?.output_tokens,
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* OpenAI synthesis
|
|
257
|
-
*/
|
|
258
|
-
async function synthesizeOpenAI(config, request, signal) {
|
|
259
|
-
const model = config.model || "gpt-4o";
|
|
260
|
-
const maxTokens = request.max_tokens || 1024;
|
|
261
|
-
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
|
262
|
-
method: "POST",
|
|
263
|
-
headers: {
|
|
264
|
-
"Content-Type": "application/json",
|
|
265
|
-
Authorization: `Bearer ${config.openai_api_key}`,
|
|
266
|
-
},
|
|
267
|
-
body: JSON.stringify({
|
|
268
|
-
model,
|
|
269
|
-
max_tokens: maxTokens,
|
|
270
|
-
messages: [
|
|
271
|
-
{ role: "system", content: request.system },
|
|
272
|
-
{ role: "user", content: request.prompt },
|
|
273
|
-
],
|
|
274
|
-
}),
|
|
275
|
-
signal,
|
|
276
|
-
});
|
|
277
|
-
if (!response.ok) {
|
|
278
|
-
const error = await response.text();
|
|
279
|
-
throw new Error(`OpenAI API error: ${error}`);
|
|
280
|
-
}
|
|
281
|
-
const data = (await response.json());
|
|
282
|
-
return {
|
|
283
|
-
synthesis: data.choices[0]?.message?.content || "",
|
|
284
|
-
model_used: model,
|
|
285
|
-
tokens_used: data.usage?.completion_tokens,
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Ollama synthesis (local) - optimized for local models
|
|
290
|
-
*/
|
|
291
|
-
async function synthesizeOllama(config, request, complexity, signal) {
|
|
292
|
-
const model = getModelForComplexity(config, complexity);
|
|
293
|
-
const baseUrl = config.ollama_url || "http://localhost:11434";
|
|
294
|
-
// Use chat endpoint for better instruction following
|
|
295
|
-
const response = await fetch(`${baseUrl}/api/chat`, {
|
|
296
|
-
method: "POST",
|
|
297
|
-
headers: {
|
|
298
|
-
"Content-Type": "application/json",
|
|
299
|
-
},
|
|
300
|
-
body: JSON.stringify({
|
|
301
|
-
model,
|
|
302
|
-
messages: [
|
|
303
|
-
{ role: "system", content: request.system },
|
|
304
|
-
{ role: "user", content: request.prompt },
|
|
305
|
-
],
|
|
306
|
-
stream: false,
|
|
307
|
-
options: {
|
|
308
|
-
num_predict: request.max_tokens || 512,
|
|
309
|
-
temperature: 0.7,
|
|
310
|
-
top_p: 0.9,
|
|
311
|
-
},
|
|
312
|
-
}),
|
|
313
|
-
signal,
|
|
314
|
-
});
|
|
315
|
-
if (!response.ok) {
|
|
316
|
-
const error = await response.text();
|
|
317
|
-
throw new Error(`Ollama API error: ${error}`);
|
|
318
|
-
}
|
|
319
|
-
const data = (await response.json());
|
|
320
|
-
return {
|
|
321
|
-
synthesis: data.message?.content || "",
|
|
322
|
-
model_used: model,
|
|
323
|
-
tokens_used: data.eval_count,
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
// =============================================================================
|
|
327
|
-
// Synthesis Prompts - Optimized for Local Models
|
|
328
|
-
// =============================================================================
|
|
329
|
-
/**
|
|
330
|
-
* Prompts are optimized for:
|
|
331
|
-
* 1. Clear structure (local models need explicit formatting)
|
|
332
|
-
* 2. Concise output (fewer tokens = faster inference)
|
|
333
|
-
* 3. Specific instructions (reduce ambiguity)
|
|
334
|
-
*/
|
|
335
|
-
export const SYNTHESIS_PROMPTS = {
|
|
336
|
-
/**
|
|
337
|
-
* Daily Briefing - Executive synthesis
|
|
338
|
-
* Complexity: MEDIUM
|
|
339
|
-
*/
|
|
340
|
-
dailyBriefing: {
|
|
341
|
-
complexity: "medium",
|
|
342
|
-
system: `You are an intelligence analyst. Synthesize data into actionable briefings.
|
|
343
|
-
|
|
344
|
-
OUTPUT FORMAT:
|
|
345
|
-
1. One-sentence summary of the day
|
|
346
|
-
2. The single most important thing to review (with reason)
|
|
347
|
-
3. One recommended action
|
|
348
|
-
|
|
349
|
-
Be direct. No filler. Every word must add value.`,
|
|
350
|
-
buildPrompt: (data, context) => `
|
|
351
|
-
DATA:
|
|
352
|
-
${JSON.stringify(data, null, 2)}
|
|
353
|
-
|
|
354
|
-
USER CONTEXT:
|
|
355
|
-
${JSON.stringify(context, null, 2)}
|
|
356
|
-
|
|
357
|
-
Generate briefing with:
|
|
358
|
-
1. ONE-LINE SUMMARY
|
|
359
|
-
2. TOP PRIORITY (title + why it matters to this user)
|
|
360
|
-
3. RECOMMENDED ACTION`,
|
|
361
|
-
},
|
|
362
|
-
/**
|
|
363
|
-
* Score Autopsy - Explain the reasoning
|
|
364
|
-
* Complexity: HEAVY (needs to reason about correctness)
|
|
365
|
-
*/
|
|
366
|
-
scoreAutopsy: {
|
|
367
|
-
complexity: "heavy",
|
|
368
|
-
system: `You are a scoring forensics expert. Analyze if relevance scores are correct.
|
|
369
|
-
|
|
370
|
-
OUTPUT FORMAT:
|
|
371
|
-
1. VERDICT: [ACCURATE / TOO HIGH / TOO LOW]
|
|
372
|
-
2. REASONING: Why you reached this verdict (cite specific data)
|
|
373
|
-
3. KEY FACTOR: The main thing driving this score
|
|
374
|
-
4. SUGGESTION: How to get more/fewer items like this
|
|
375
|
-
|
|
376
|
-
Be analytical. Cite numbers from the data.`,
|
|
377
|
-
buildPrompt: (data, context) => `
|
|
378
|
-
SCORE DATA:
|
|
379
|
-
${JSON.stringify(data, null, 2)}
|
|
380
|
-
|
|
381
|
-
USER INTERESTS:
|
|
382
|
-
${JSON.stringify(context, null, 2)}
|
|
383
|
-
|
|
384
|
-
Analyze: Is this score correct given the user's interests?`,
|
|
385
|
-
},
|
|
386
|
-
/**
|
|
387
|
-
* Trend Analysis - Predict and explain
|
|
388
|
-
* Complexity: HEAVY (needs pattern recognition + prediction)
|
|
389
|
-
*/
|
|
390
|
-
trendAnalysis: {
|
|
391
|
-
complexity: "heavy",
|
|
392
|
-
system: `You are a tech trend analyst. Interpret patterns and predict trajectories.
|
|
393
|
-
|
|
394
|
-
OUTPUT FORMAT:
|
|
395
|
-
1. KEY SIGNAL: The most important trend (one sentence)
|
|
396
|
-
2. WHY IT'S HAPPENING: Brief explanation
|
|
397
|
-
3. PREDICTION: What to expect in the next 1-2 weeks
|
|
398
|
-
4. ACTION: Should the user adjust their focus?
|
|
399
|
-
|
|
400
|
-
Ground predictions in the data. Don't speculate wildly.`,
|
|
401
|
-
buildPrompt: (data, context) => `
|
|
402
|
-
TREND DATA:
|
|
403
|
-
${JSON.stringify(data, null, 2)}
|
|
404
|
-
|
|
405
|
-
USER CONTEXT:
|
|
406
|
-
${JSON.stringify(context, null, 2)}
|
|
407
|
-
|
|
408
|
-
Interpret: What do these trends mean for this specific user?`,
|
|
409
|
-
},
|
|
410
|
-
/**
|
|
411
|
-
* Context Analysis - Personalized optimization advice
|
|
412
|
-
* Complexity: MEDIUM (structured recommendations)
|
|
413
|
-
*/
|
|
414
|
-
contextAnalysis: {
|
|
415
|
-
complexity: "medium",
|
|
416
|
-
system: `You are a personalization expert. Help users optimize their content filtering.
|
|
417
|
-
|
|
418
|
-
OUTPUT FORMAT:
|
|
419
|
-
1. BIGGEST GAP: What's missing from their context?
|
|
420
|
-
2. HIGHEST IMPACT CHANGE: One specific thing to add/remove
|
|
421
|
-
3. QUICK WIN: Something they can do in 30 seconds
|
|
422
|
-
|
|
423
|
-
Be specific. Give exact examples they can copy-paste.`,
|
|
424
|
-
buildPrompt: (data) => `
|
|
425
|
-
CONTEXT DATA:
|
|
426
|
-
${JSON.stringify(data, null, 2)}
|
|
427
|
-
|
|
428
|
-
Provide optimization recommendations. Be specific and actionable.`,
|
|
429
|
-
},
|
|
430
|
-
/**
|
|
431
|
-
* Topic Connections - Explain the knowledge graph
|
|
432
|
-
* Complexity: HEAVY (needs graph reasoning)
|
|
433
|
-
*/
|
|
434
|
-
topicConnections: {
|
|
435
|
-
complexity: "heavy",
|
|
436
|
-
system: `You are a knowledge graph analyst. Find hidden patterns in topic relationships.
|
|
437
|
-
|
|
438
|
-
OUTPUT FORMAT:
|
|
439
|
-
1. SURPRISING CONNECTION: A non-obvious relationship and its significance
|
|
440
|
-
2. MISSING LINK: Topics that should connect but don't
|
|
441
|
-
3. EXPLORATION PATH: A topic worth investigating based on the graph
|
|
442
|
-
4. PATTERN: What the graph structure reveals about their interests
|
|
443
|
-
|
|
444
|
-
Look for insights the user wouldn't notice themselves.`,
|
|
445
|
-
buildPrompt: (data, context) => `
|
|
446
|
-
GRAPH DATA:
|
|
447
|
-
${JSON.stringify(data, null, 2)}
|
|
448
|
-
|
|
449
|
-
USER CONTEXT:
|
|
450
|
-
${JSON.stringify(context, null, 2)}
|
|
451
|
-
|
|
452
|
-
Interpret: What hidden patterns does this graph reveal?`,
|
|
453
|
-
},
|
|
454
|
-
};
|
|
455
|
-
// =============================================================================
|
|
456
|
-
// Utility: Check Ollama availability
|
|
457
|
-
// =============================================================================
|
|
458
|
-
/**
|
|
459
|
-
* Check if Ollama is running and has required models
|
|
460
|
-
*/
|
|
461
|
-
export async function checkOllamaStatus(baseUrl = "http://localhost:11434") {
|
|
462
|
-
try {
|
|
463
|
-
const response = await fetch(`${baseUrl}/api/tags`, {
|
|
464
|
-
method: "GET",
|
|
465
|
-
signal: AbortSignal.timeout(5000),
|
|
466
|
-
});
|
|
467
|
-
if (!response.ok) {
|
|
468
|
-
return { available: false, models: [], error: "Ollama not responding" };
|
|
469
|
-
}
|
|
470
|
-
const data = (await response.json());
|
|
471
|
-
const models = data.models?.map(m => m.name) || [];
|
|
472
|
-
return { available: true, models };
|
|
473
|
-
}
|
|
474
|
-
catch (error) {
|
|
475
|
-
return {
|
|
476
|
-
available: false,
|
|
477
|
-
models: [],
|
|
478
|
-
error: error instanceof Error ? error.message : "Connection failed",
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
/**
|
|
483
|
-
* Recommended models for 4DA synthesis tasks
|
|
484
|
-
*/
|
|
485
|
-
export const RECOMMENDED_MODELS = {
|
|
486
|
-
"16GB_VRAM": {
|
|
487
|
-
primary: "qwen3:14b",
|
|
488
|
-
fallback: "gemma3:12b",
|
|
489
|
-
install: "ollama pull qwen3:14b",
|
|
490
|
-
},
|
|
491
|
-
"12GB_VRAM": {
|
|
492
|
-
primary: "gemma3:12b",
|
|
493
|
-
fallback: "qwen3:8b",
|
|
494
|
-
install: "ollama pull gemma3:12b",
|
|
495
|
-
},
|
|
496
|
-
"8GB_VRAM": {
|
|
497
|
-
primary: "qwen3:8b",
|
|
498
|
-
fallback: "gemma3:4b",
|
|
499
|
-
install: "ollama pull qwen3:8b",
|
|
500
|
-
},
|
|
501
|
-
};
|
|
502
|
-
//# sourceMappingURL=llm.js.map
|
package/dist/output-manager.d.ts
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Output Manager for Dynamic Context Discovery
|
|
3
|
-
*
|
|
4
|
-
* Reduces token usage by ~80% through:
|
|
5
|
-
* - Writing full results to files (referenced by path)
|
|
6
|
-
* - Returning compact summaries inline
|
|
7
|
-
* - Providing retrieval hints for common queries
|
|
8
|
-
*
|
|
9
|
-
* Full results stored at: ~/.local/share/4da/context/results/
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Compact result format - what gets returned inline to Claude
|
|
13
|
-
*/
|
|
14
|
-
export interface CompactResult<T> {
|
|
15
|
-
/** 2-3 sentence human-readable summary */
|
|
16
|
-
summary: string;
|
|
17
|
-
/** Essential 20% of data inline for immediate use */
|
|
18
|
-
key_data: T;
|
|
19
|
-
/** Path to complete JSON file */
|
|
20
|
-
full_result_path: string;
|
|
21
|
-
/** Hints for retrieving specific data (jq patterns, grep patterns) */
|
|
22
|
-
retrieval_hints: string[];
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Get the results directory path (for documentation)
|
|
26
|
-
*/
|
|
27
|
-
export declare function getResultsDir(): string;
|
|
28
|
-
/**
|
|
29
|
-
* Daily Briefing compact output
|
|
30
|
-
*/
|
|
31
|
-
export interface DailyBriefingKeyData {
|
|
32
|
-
total_items: number;
|
|
33
|
-
high_priority: number;
|
|
34
|
-
top_theme: string;
|
|
35
|
-
tldr: string;
|
|
36
|
-
executive_brief?: string;
|
|
37
|
-
}
|
|
38
|
-
export declare function createDailyBriefingCompact(result: {
|
|
39
|
-
summary: {
|
|
40
|
-
total_items_analyzed: number;
|
|
41
|
-
high_relevance_count: number;
|
|
42
|
-
tldr: string;
|
|
43
|
-
};
|
|
44
|
-
themes: {
|
|
45
|
-
name: string;
|
|
46
|
-
item_count: number;
|
|
47
|
-
}[];
|
|
48
|
-
ai_synthesis?: {
|
|
49
|
-
executive_brief: string;
|
|
50
|
-
};
|
|
51
|
-
}): CompactResult<DailyBriefingKeyData>;
|
|
52
|
-
/**
|
|
53
|
-
* Trend Analysis compact output
|
|
54
|
-
*/
|
|
55
|
-
export interface TrendAnalysisKeyData {
|
|
56
|
-
total_items: number;
|
|
57
|
-
volume_trend: string;
|
|
58
|
-
top_rising: string | null;
|
|
59
|
-
top_falling: string | null;
|
|
60
|
-
anomaly_count: number;
|
|
61
|
-
narrative?: string;
|
|
62
|
-
}
|
|
63
|
-
export declare function createTrendAnalysisCompact(result: {
|
|
64
|
-
summary: {
|
|
65
|
-
total_items: number;
|
|
66
|
-
volume_trend: string;
|
|
67
|
-
top_rising_topic: string | null;
|
|
68
|
-
top_falling_topic: string | null;
|
|
69
|
-
};
|
|
70
|
-
anomalies: unknown[];
|
|
71
|
-
ai_interpretation?: {
|
|
72
|
-
narrative: string;
|
|
73
|
-
};
|
|
74
|
-
}): CompactResult<TrendAnalysisKeyData>;
|
|
75
|
-
/**
|
|
76
|
-
* Score Autopsy compact output
|
|
77
|
-
*/
|
|
78
|
-
export interface ScoreAutopsyKeyData {
|
|
79
|
-
item_title: string;
|
|
80
|
-
final_score: number;
|
|
81
|
-
score_assessment?: "accurate" | "too_high" | "too_low" | "uncertain";
|
|
82
|
-
top_contributor: string;
|
|
83
|
-
verdict?: string;
|
|
84
|
-
}
|
|
85
|
-
export declare function createScoreAutopsyCompact(result: {
|
|
86
|
-
item: {
|
|
87
|
-
title: string;
|
|
88
|
-
};
|
|
89
|
-
final_score: number;
|
|
90
|
-
components: {
|
|
91
|
-
name: string;
|
|
92
|
-
contribution: number;
|
|
93
|
-
}[];
|
|
94
|
-
ai_analysis?: {
|
|
95
|
-
score_assessment: "accurate" | "too_high" | "too_low" | "uncertain";
|
|
96
|
-
verdict: string;
|
|
97
|
-
};
|
|
98
|
-
}): CompactResult<ScoreAutopsyKeyData>;
|
|
99
|
-
/**
|
|
100
|
-
* Context Analysis compact output
|
|
101
|
-
*/
|
|
102
|
-
export interface ContextAnalysisKeyData {
|
|
103
|
-
quality_score: number;
|
|
104
|
-
interests_count: number;
|
|
105
|
-
tech_count: number;
|
|
106
|
-
gap_count: number;
|
|
107
|
-
top_recommendation: string;
|
|
108
|
-
personalized_advice?: string;
|
|
109
|
-
}
|
|
110
|
-
export declare function createContextAnalysisCompact(result: {
|
|
111
|
-
context_summary: {
|
|
112
|
-
interests_count: number;
|
|
113
|
-
tech_stack_count: number;
|
|
114
|
-
};
|
|
115
|
-
quality_score: {
|
|
116
|
-
overall: number;
|
|
117
|
-
};
|
|
118
|
-
coverage_gaps: unknown[];
|
|
119
|
-
recommendations: {
|
|
120
|
-
action: string;
|
|
121
|
-
}[];
|
|
122
|
-
ai_advice?: {
|
|
123
|
-
personalized_recommendations: string;
|
|
124
|
-
};
|
|
125
|
-
}): CompactResult<ContextAnalysisKeyData>;
|
|
126
|
-
/**
|
|
127
|
-
* Topic Connections compact output
|
|
128
|
-
*/
|
|
129
|
-
export interface TopicConnectionsKeyData {
|
|
130
|
-
items_analyzed: number;
|
|
131
|
-
node_count: number;
|
|
132
|
-
edge_count: number;
|
|
133
|
-
central_topics: string[];
|
|
134
|
-
top_connection: {
|
|
135
|
-
from: string;
|
|
136
|
-
to: string;
|
|
137
|
-
strength: number;
|
|
138
|
-
} | null;
|
|
139
|
-
graph_narrative?: string;
|
|
140
|
-
}
|
|
141
|
-
export declare function createTopicConnectionsCompact(result: {
|
|
142
|
-
analysis_period: {
|
|
143
|
-
items_analyzed: number;
|
|
144
|
-
};
|
|
145
|
-
nodes: unknown[];
|
|
146
|
-
edges: {
|
|
147
|
-
from: string;
|
|
148
|
-
to: string;
|
|
149
|
-
co_occurrences: number;
|
|
150
|
-
}[];
|
|
151
|
-
central_topics: string[];
|
|
152
|
-
ai_insights?: {
|
|
153
|
-
graph_narrative: string;
|
|
154
|
-
};
|
|
155
|
-
}): CompactResult<TopicConnectionsKeyData>;
|
|
156
|
-
//# sourceMappingURL=output-manager.d.ts.map
|