noverload-mcp 0.7.0 → 0.7.1
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/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/tools/index-old.d.ts +0 -16
- package/dist/tools/index-old.d.ts.map +0 -1
- package/dist/tools/index-old.js +0 -2176
- package/dist/tools/index-old.js.map +0 -1
package/dist/tools/index-old.js
DELETED
|
@@ -1,2176 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { generateLLMInstructions, planQueryStrategy, estimateTokenUsage } from "../llm-instructions.js";
|
|
3
|
-
export const tools = [
|
|
4
|
-
{
|
|
5
|
-
name: "list_saved_content",
|
|
6
|
-
description: "List saved content from Noverload with full details including titles, summaries, and insights. Optionally filter by status or content type.",
|
|
7
|
-
inputSchema: {
|
|
8
|
-
type: "object",
|
|
9
|
-
properties: {
|
|
10
|
-
status: {
|
|
11
|
-
type: "string",
|
|
12
|
-
enum: ["pending", "processing", "completed", "failed"],
|
|
13
|
-
description: "Filter by processing status",
|
|
14
|
-
},
|
|
15
|
-
contentType: {
|
|
16
|
-
type: "string",
|
|
17
|
-
enum: ["youtube", "x_twitter", "reddit", "article", "pdf"],
|
|
18
|
-
description: "Filter by content type",
|
|
19
|
-
},
|
|
20
|
-
limit: {
|
|
21
|
-
type: "number",
|
|
22
|
-
description: "Maximum number of items to return",
|
|
23
|
-
default: 20,
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
modifies: false,
|
|
28
|
-
handler: async (client, args) => {
|
|
29
|
-
const schema = z.object({
|
|
30
|
-
status: z.enum(["pending", "processing", "completed", "failed"]).optional(),
|
|
31
|
-
contentType: z.enum(["youtube", "x_twitter", "reddit", "article", "pdf"]).optional(),
|
|
32
|
-
limit: z.number().optional().default(20),
|
|
33
|
-
});
|
|
34
|
-
const params = schema.parse(args);
|
|
35
|
-
const content = await client.listContent(params);
|
|
36
|
-
// Build detailed response
|
|
37
|
-
let responseText = `# Saved Content Library\n`;
|
|
38
|
-
responseText += `Found ${content.length} items`;
|
|
39
|
-
const filters = [];
|
|
40
|
-
if (params.status)
|
|
41
|
-
filters.push(`status: ${params.status}`);
|
|
42
|
-
if (params.contentType)
|
|
43
|
-
filters.push(`type: ${params.contentType}`);
|
|
44
|
-
if (filters.length > 0) {
|
|
45
|
-
responseText += ` (filtered by ${filters.join(', ')})`;
|
|
46
|
-
}
|
|
47
|
-
responseText += `\n\n`;
|
|
48
|
-
if (content.length > 0) {
|
|
49
|
-
content.forEach((item, idx) => {
|
|
50
|
-
responseText += `## ${idx + 1}. ${item.title || 'Untitled'}\n`;
|
|
51
|
-
responseText += `**ID:** ${item.id}\n`;
|
|
52
|
-
responseText += `**Type:** ${item.contentType} | **Status:** ${item.status}`;
|
|
53
|
-
if (item.tokenCount) {
|
|
54
|
-
responseText += ` | **Size:** ${item.tokenCount.toLocaleString()} tokens`;
|
|
55
|
-
if (item.tokenCount > 50000) {
|
|
56
|
-
responseText += ` 🚨`;
|
|
57
|
-
}
|
|
58
|
-
else if (item.tokenCount > 10000) {
|
|
59
|
-
responseText += ` ⚠️`;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
responseText += `\n**URL:** ${item.url}\n`;
|
|
63
|
-
if (item.summary) {
|
|
64
|
-
const summaryObj = typeof item.summary === 'string'
|
|
65
|
-
? { text: item.summary }
|
|
66
|
-
: item.summary;
|
|
67
|
-
if (summaryObj.one_sentence) {
|
|
68
|
-
responseText += `**Summary:** ${summaryObj.one_sentence}\n`;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
responseText += `**Saved:** ${new Date(item.createdAt).toLocaleDateString()}\n`;
|
|
72
|
-
responseText += '\n---\n\n';
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
responseText += "No content found matching the specified filters.";
|
|
77
|
-
}
|
|
78
|
-
return {
|
|
79
|
-
content: [
|
|
80
|
-
{
|
|
81
|
-
type: "text",
|
|
82
|
-
text: responseText,
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
data: content,
|
|
86
|
-
};
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
name: "get_content_details",
|
|
91
|
-
description: "Get complete details about a specific saved content item including full transcript/article text, AI-generated summary, key insights, and all metadata",
|
|
92
|
-
inputSchema: {
|
|
93
|
-
type: "object",
|
|
94
|
-
properties: {
|
|
95
|
-
contentId: {
|
|
96
|
-
type: "string",
|
|
97
|
-
description: "The ID of the content to retrieve",
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
required: ["contentId"],
|
|
101
|
-
},
|
|
102
|
-
modifies: false,
|
|
103
|
-
handler: async (client, args) => {
|
|
104
|
-
const schema = z.object({
|
|
105
|
-
contentId: z.string(),
|
|
106
|
-
});
|
|
107
|
-
const { contentId } = schema.parse(args);
|
|
108
|
-
const content = await client.getContent(contentId);
|
|
109
|
-
// Build comprehensive response with all details
|
|
110
|
-
let responseText = `# Content Details: ${content.title || 'Untitled'}\n\n`;
|
|
111
|
-
responseText += `**ID:** ${content.id}\n`;
|
|
112
|
-
responseText += `**Type:** ${content.contentType}\n`;
|
|
113
|
-
responseText += `**Status:** ${content.status}\n`;
|
|
114
|
-
responseText += `**URL:** ${content.url}\n`;
|
|
115
|
-
responseText += `**Saved:** ${new Date(content.createdAt).toLocaleDateString()}\n`;
|
|
116
|
-
// Show content size information
|
|
117
|
-
if (content.tokenCount) {
|
|
118
|
-
responseText += `**Full Content Size:** ${content.tokenCount.toLocaleString()} tokens`;
|
|
119
|
-
if (content.tokenCount > 50000) {
|
|
120
|
-
responseText += ` 🚨 EXTREMELY LARGE`;
|
|
121
|
-
}
|
|
122
|
-
else if (content.tokenCount > 10000) {
|
|
123
|
-
responseText += ` ⚠️ LARGE`;
|
|
124
|
-
}
|
|
125
|
-
responseText += '\n';
|
|
126
|
-
}
|
|
127
|
-
if (content.tags && content.tags.length > 0) {
|
|
128
|
-
responseText += `**Tags:** ${content.tags.join(', ')}\n`;
|
|
129
|
-
}
|
|
130
|
-
responseText += '\n## Summary & Insights\n';
|
|
131
|
-
if (content.summary) {
|
|
132
|
-
const summaryObj = typeof content.summary === 'string'
|
|
133
|
-
? { text: content.summary }
|
|
134
|
-
: content.summary;
|
|
135
|
-
if (summaryObj.one_sentence) {
|
|
136
|
-
responseText += `**One-line Summary:** ${summaryObj.one_sentence}\n\n`;
|
|
137
|
-
}
|
|
138
|
-
if (summaryObj.key_insights && Array.isArray(summaryObj.key_insights)) {
|
|
139
|
-
responseText += `**Key Insights:**\n`;
|
|
140
|
-
summaryObj.key_insights.forEach((insight, idx) => {
|
|
141
|
-
responseText += `${idx + 1}. ${insight}\n`;
|
|
142
|
-
});
|
|
143
|
-
responseText += '\n';
|
|
144
|
-
}
|
|
145
|
-
if (summaryObj.main_topics && Array.isArray(summaryObj.main_topics)) {
|
|
146
|
-
responseText += `**Main Topics:** ${summaryObj.main_topics.join(', ')}\n\n`;
|
|
147
|
-
}
|
|
148
|
-
if (summaryObj.actionable_takeaways && Array.isArray(summaryObj.actionable_takeaways)) {
|
|
149
|
-
responseText += `**Actionable Takeaways:**\n`;
|
|
150
|
-
summaryObj.actionable_takeaways.forEach((takeaway, idx) => {
|
|
151
|
-
responseText += `${idx + 1}. ${takeaway}\n`;
|
|
152
|
-
});
|
|
153
|
-
responseText += '\n';
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// Include full text content info and preview
|
|
157
|
-
if (content.rawText) {
|
|
158
|
-
const wordCount = content.rawText.split(/\s+/).length;
|
|
159
|
-
responseText += `## Full Content\n`;
|
|
160
|
-
responseText += `**Word Count:** ${wordCount.toLocaleString()} words\n`;
|
|
161
|
-
// Show a reasonable preview (500 chars is about 100 tokens)
|
|
162
|
-
responseText += `**Preview (first 500 chars):**\n`;
|
|
163
|
-
responseText += `${content.rawText.slice(0, 500)}...\n\n`;
|
|
164
|
-
if (content.tokenCount && content.tokenCount > 10000) {
|
|
165
|
-
responseText += `⚠️ **Note:** The complete ${content.contentType} content (${wordCount.toLocaleString()} words, ~${content.tokenCount.toLocaleString()} tokens) is available in the data field.\n`;
|
|
166
|
-
responseText += `This is a large amount of content that will consume significant context if fully processed.\n`;
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
responseText += `*Note: Complete content is available in the data field for analysis.*\n`;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return {
|
|
173
|
-
content: [
|
|
174
|
-
{
|
|
175
|
-
type: "text",
|
|
176
|
-
text: responseText,
|
|
177
|
-
},
|
|
178
|
-
],
|
|
179
|
-
data: content, // Full content including complete rawText
|
|
180
|
-
};
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
name: "search_content",
|
|
185
|
-
description: "Advanced search with OR/ANY logic, fuzzy matching, and smart filters. Supports multiple search modes, content type filtering, date ranges, and relevance explanations.",
|
|
186
|
-
inputSchema: {
|
|
187
|
-
type: "object",
|
|
188
|
-
properties: {
|
|
189
|
-
query: {
|
|
190
|
-
type: "string",
|
|
191
|
-
description: "Search query (supports 'term1 OR term2' for any match, quotes for exact phrases)",
|
|
192
|
-
},
|
|
193
|
-
searchMode: {
|
|
194
|
-
type: "string",
|
|
195
|
-
enum: ["any", "all", "phrase"],
|
|
196
|
-
description: "Search logic: 'any' (OR logic), 'all' (AND logic), 'phrase' (exact phrase)",
|
|
197
|
-
default: "any",
|
|
198
|
-
},
|
|
199
|
-
fuzzyMatch: {
|
|
200
|
-
type: "boolean",
|
|
201
|
-
description: "Enable fuzzy/typo-tolerant matching",
|
|
202
|
-
default: true,
|
|
203
|
-
},
|
|
204
|
-
tags: {
|
|
205
|
-
type: "array",
|
|
206
|
-
items: {
|
|
207
|
-
type: "string",
|
|
208
|
-
},
|
|
209
|
-
description: "Filter by tags",
|
|
210
|
-
},
|
|
211
|
-
limit: {
|
|
212
|
-
type: "number",
|
|
213
|
-
description: "Maximum results (default: 10)",
|
|
214
|
-
default: 10,
|
|
215
|
-
},
|
|
216
|
-
includeFullContent: {
|
|
217
|
-
type: "boolean",
|
|
218
|
-
description: "Include full text (WARNING: 10k-100k+ tokens)",
|
|
219
|
-
default: false,
|
|
220
|
-
},
|
|
221
|
-
contentTypes: {
|
|
222
|
-
type: "array",
|
|
223
|
-
items: {
|
|
224
|
-
type: "string",
|
|
225
|
-
enum: ["youtube", "x_twitter", "reddit", "article", "pdf"],
|
|
226
|
-
},
|
|
227
|
-
description: "Filter by content types",
|
|
228
|
-
},
|
|
229
|
-
dateFrom: {
|
|
230
|
-
type: "string",
|
|
231
|
-
description: "Content saved after this date (ISO 8601)",
|
|
232
|
-
},
|
|
233
|
-
dateTo: {
|
|
234
|
-
type: "string",
|
|
235
|
-
description: "Content saved before this date (ISO 8601)",
|
|
236
|
-
},
|
|
237
|
-
excludeDomains: {
|
|
238
|
-
type: "array",
|
|
239
|
-
items: {
|
|
240
|
-
type: "string",
|
|
241
|
-
},
|
|
242
|
-
description: "Domains to exclude",
|
|
243
|
-
},
|
|
244
|
-
showRelevanceExplanation: {
|
|
245
|
-
type: "boolean",
|
|
246
|
-
description: "Show why each result matched",
|
|
247
|
-
default: true,
|
|
248
|
-
},
|
|
249
|
-
},
|
|
250
|
-
required: ["query"],
|
|
251
|
-
},
|
|
252
|
-
modifies: false,
|
|
253
|
-
handler: async (client, args) => {
|
|
254
|
-
const schema = z.object({
|
|
255
|
-
query: z.string(),
|
|
256
|
-
searchMode: z.enum(["any", "all", "phrase"]).optional().default("any"),
|
|
257
|
-
fuzzyMatch: z.boolean().optional().default(true),
|
|
258
|
-
tags: z.array(z.string()).optional(),
|
|
259
|
-
limit: z.number().optional().default(10),
|
|
260
|
-
includeFullContent: z.boolean().optional().default(false),
|
|
261
|
-
contentTypes: z.array(z.enum(["youtube", "x_twitter", "reddit", "article", "pdf"])).optional(),
|
|
262
|
-
dateFrom: z.string().optional(),
|
|
263
|
-
dateTo: z.string().optional(),
|
|
264
|
-
excludeDomains: z.array(z.string()).optional(),
|
|
265
|
-
showRelevanceExplanation: z.boolean().optional().default(true),
|
|
266
|
-
});
|
|
267
|
-
const params = schema.parse(args);
|
|
268
|
-
// Enhance search query based on mode
|
|
269
|
-
let enhancedQuery = params.query;
|
|
270
|
-
if (params.searchMode === "any" && !params.query.includes("OR")) {
|
|
271
|
-
// Convert space-separated terms to OR query for broader matching
|
|
272
|
-
const terms = params.query.split(/\s+/).filter(t => t.length > 2);
|
|
273
|
-
if (terms.length > 1) {
|
|
274
|
-
enhancedQuery = terms.join(" OR ");
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
const results = await client.searchContent(enhancedQuery, {
|
|
278
|
-
...params,
|
|
279
|
-
enableConceptExpansion: params.fuzzyMatch, // Use fuzzy matching as concept expansion
|
|
280
|
-
});
|
|
281
|
-
// Format response with visual indicators
|
|
282
|
-
let responseText = `# 🔍 Search Results: "${params.query}"\n`;
|
|
283
|
-
responseText += `**Mode:** ${params.searchMode.toUpperCase()}${params.fuzzyMatch ? " with fuzzy matching" : ""}\n`;
|
|
284
|
-
responseText += `**Found:** ${results.length} results`;
|
|
285
|
-
// Show active filters
|
|
286
|
-
const filters = [];
|
|
287
|
-
if (params.tags?.length)
|
|
288
|
-
filters.push(`📌 tags: ${params.tags.join(", ")}`);
|
|
289
|
-
if (params.contentTypes?.length)
|
|
290
|
-
filters.push(`📁 types: ${params.contentTypes.join(", ")}`);
|
|
291
|
-
if (params.dateFrom || params.dateTo)
|
|
292
|
-
filters.push(`📅 date range`);
|
|
293
|
-
if (params.excludeDomains?.length)
|
|
294
|
-
filters.push(`🚫 excluded: ${params.excludeDomains.join(", ")}`);
|
|
295
|
-
if (filters.length > 0) {
|
|
296
|
-
responseText += `\n**Filters:** ${filters.join(" | ")}`;
|
|
297
|
-
}
|
|
298
|
-
if (params.includeFullContent) {
|
|
299
|
-
responseText += `\n⚠️ **Full content included** - consuming significant tokens`;
|
|
300
|
-
}
|
|
301
|
-
responseText += `\n\n`;
|
|
302
|
-
if (results.length > 0) {
|
|
303
|
-
// Add search suggestions if no perfect matches
|
|
304
|
-
if (results.length < 3) {
|
|
305
|
-
responseText += `💡 **Tip:** Try broader search with 'any' mode or disable filters for more results\n\n`;
|
|
306
|
-
}
|
|
307
|
-
results.forEach((result, idx) => {
|
|
308
|
-
// Visual indicators for content type
|
|
309
|
-
const typeIcons = {
|
|
310
|
-
youtube: "📺",
|
|
311
|
-
x_twitter: "𝕏",
|
|
312
|
-
reddit: "🔗",
|
|
313
|
-
article: "📄",
|
|
314
|
-
pdf: "📑"
|
|
315
|
-
};
|
|
316
|
-
const typeIcon = typeIcons[result.contentType] || "📄";
|
|
317
|
-
// Relevance indicator
|
|
318
|
-
let relevanceIcon = "";
|
|
319
|
-
if (result.relevanceScore) {
|
|
320
|
-
if (result.relevanceScore > 0.8)
|
|
321
|
-
relevanceIcon = "🎯";
|
|
322
|
-
else if (result.relevanceScore > 0.6)
|
|
323
|
-
relevanceIcon = "✅";
|
|
324
|
-
else if (result.relevanceScore > 0.4)
|
|
325
|
-
relevanceIcon = "➡️";
|
|
326
|
-
}
|
|
327
|
-
responseText += `## ${idx + 1}. ${typeIcon} ${result.title || 'Untitled'} ${relevanceIcon}\n`;
|
|
328
|
-
responseText += `**ID:** \`${result.id}\`\n`;
|
|
329
|
-
responseText += `**URL:** ${result.url}\n`;
|
|
330
|
-
// Show relevance explanation if available
|
|
331
|
-
if (params.showRelevanceExplanation) {
|
|
332
|
-
if (result.matchReason && Array.isArray(result.matchReason)) {
|
|
333
|
-
responseText += `**Why matched:** Matched in ${result.matchReason.join(", ")}\n`;
|
|
334
|
-
}
|
|
335
|
-
else if (result.relevanceScore) {
|
|
336
|
-
const percentage = (result.relevanceScore * 100).toFixed(0);
|
|
337
|
-
responseText += `**Relevance:** ${percentage}% match\n`;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
// Content size indicator with better formatting
|
|
341
|
-
if (result.tokenCount) {
|
|
342
|
-
const sizeIcon = result.tokenCount > 50000 ? "🚨" :
|
|
343
|
-
result.tokenCount > 10000 ? "⚠️" :
|
|
344
|
-
result.tokenCount > 5000 ? "📊" : "📝";
|
|
345
|
-
responseText += `**Size:** ${sizeIcon} ~${result.tokenCount.toLocaleString()} tokens`;
|
|
346
|
-
if (params.includeFullContent) {
|
|
347
|
-
responseText += ` (full content included)`;
|
|
348
|
-
}
|
|
349
|
-
responseText += `\n`;
|
|
350
|
-
}
|
|
351
|
-
// Tags with better formatting
|
|
352
|
-
if (result.tags && result.tags.length > 0) {
|
|
353
|
-
responseText += `**Tags:** ${result.tags.map((t) => `\`${t}\``).join(' ')}\n`;
|
|
354
|
-
}
|
|
355
|
-
// Summary section with structure
|
|
356
|
-
if (result.summary) {
|
|
357
|
-
const summaryObj = typeof result.summary === 'string'
|
|
358
|
-
? { text: result.summary }
|
|
359
|
-
: result.summary;
|
|
360
|
-
if (summaryObj.one_sentence) {
|
|
361
|
-
responseText += `\n📝 **Summary:** ${summaryObj.one_sentence}\n`;
|
|
362
|
-
}
|
|
363
|
-
// Key insights with bullets
|
|
364
|
-
if (summaryObj.key_insights && Array.isArray(summaryObj.key_insights) && summaryObj.key_insights.length > 0) {
|
|
365
|
-
responseText += `\n💡 **Key Insights:**\n`;
|
|
366
|
-
summaryObj.key_insights.slice(0, 3).forEach((insight) => {
|
|
367
|
-
responseText += ` • ${insight}\n`;
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
// Actionable takeaways
|
|
371
|
-
if (summaryObj.actionable_takeaways && Array.isArray(summaryObj.actionable_takeaways) && summaryObj.actionable_takeaways.length > 0) {
|
|
372
|
-
responseText += `\n🎯 **Actions:**\n`;
|
|
373
|
-
summaryObj.actionable_takeaways.slice(0, 2).forEach((action) => {
|
|
374
|
-
responseText += ` → ${action}\n`;
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
responseText += '\n---\n\n';
|
|
379
|
-
});
|
|
380
|
-
// Smart token usage summary
|
|
381
|
-
if (!params.includeFullContent) {
|
|
382
|
-
let totalAvailable = 0;
|
|
383
|
-
results.forEach((r) => {
|
|
384
|
-
if (r.tokenCount)
|
|
385
|
-
totalAvailable += r.tokenCount;
|
|
386
|
-
});
|
|
387
|
-
if (totalAvailable > 0) {
|
|
388
|
-
responseText += `\n📊 **Content Overview:**\n`;
|
|
389
|
-
responseText += `- Showing: Summaries and metadata (minimal tokens)\n`;
|
|
390
|
-
responseText += `- Available: ~${totalAvailable.toLocaleString()} tokens of full content\n`;
|
|
391
|
-
responseText += `- To access: Use \`get_content_details\` for specific items\n`;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
// Search quality feedback
|
|
395
|
-
if (results.length === params.limit) {
|
|
396
|
-
responseText += `\n💡 **Note:** Showing top ${params.limit} results. More may be available.\n`;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
else {
|
|
400
|
-
// No results - provide helpful suggestions
|
|
401
|
-
responseText += "## No Results Found 😔\n\n";
|
|
402
|
-
responseText += "**Try these approaches:**\n";
|
|
403
|
-
responseText += "1. 🔄 Switch to `searchMode: 'any'` for broader matching\n";
|
|
404
|
-
responseText += "2. ✏️ Check spelling or use simpler terms\n";
|
|
405
|
-
responseText += "3. 🎯 Remove filters (dates, types, domains)\n";
|
|
406
|
-
responseText += "4. 🔍 Use more general keywords\n";
|
|
407
|
-
// Suggest alternative queries
|
|
408
|
-
const terms = params.query.split(/\s+/);
|
|
409
|
-
if (terms.length > 1) {
|
|
410
|
-
responseText += `\n**Alternative queries:**\n`;
|
|
411
|
-
responseText += `- "${terms[0]}" (single term)\n`;
|
|
412
|
-
responseText += `- "${terms.slice(0, 2).join(' ')}" (first two terms)\n`;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
return {
|
|
416
|
-
content: [
|
|
417
|
-
{
|
|
418
|
-
type: "text",
|
|
419
|
-
text: responseText,
|
|
420
|
-
},
|
|
421
|
-
],
|
|
422
|
-
data: results,
|
|
423
|
-
};
|
|
424
|
-
},
|
|
425
|
-
},
|
|
426
|
-
{
|
|
427
|
-
name: "save_content",
|
|
428
|
-
description: "Save a new URL to Noverload for processing",
|
|
429
|
-
inputSchema: {
|
|
430
|
-
type: "object",
|
|
431
|
-
properties: {
|
|
432
|
-
url: {
|
|
433
|
-
type: "string",
|
|
434
|
-
description: "URL to save (YouTube, X/Twitter, Reddit, article, or PDF)",
|
|
435
|
-
},
|
|
436
|
-
},
|
|
437
|
-
required: ["url"],
|
|
438
|
-
},
|
|
439
|
-
modifies: true,
|
|
440
|
-
handler: async (client, args) => {
|
|
441
|
-
const schema = z.object({
|
|
442
|
-
url: z.string().url(),
|
|
443
|
-
});
|
|
444
|
-
const { url } = schema.parse(args);
|
|
445
|
-
const content = await client.saveContent(url);
|
|
446
|
-
return {
|
|
447
|
-
content: [
|
|
448
|
-
{
|
|
449
|
-
type: "text",
|
|
450
|
-
text: content.title ? `Saved: ${content.title}` : `Saved content from: ${new URL(url).hostname}`,
|
|
451
|
-
},
|
|
452
|
-
],
|
|
453
|
-
data: content,
|
|
454
|
-
};
|
|
455
|
-
},
|
|
456
|
-
},
|
|
457
|
-
{
|
|
458
|
-
name: "list_actions",
|
|
459
|
-
description: "List action items extracted from saved content",
|
|
460
|
-
inputSchema: {
|
|
461
|
-
type: "object",
|
|
462
|
-
properties: {
|
|
463
|
-
contentId: {
|
|
464
|
-
type: "string",
|
|
465
|
-
description: "Filter by content ID",
|
|
466
|
-
},
|
|
467
|
-
goalId: {
|
|
468
|
-
type: "string",
|
|
469
|
-
description: "Filter by goal ID",
|
|
470
|
-
},
|
|
471
|
-
completed: {
|
|
472
|
-
type: "boolean",
|
|
473
|
-
description: "Filter by completion status",
|
|
474
|
-
},
|
|
475
|
-
},
|
|
476
|
-
},
|
|
477
|
-
modifies: false,
|
|
478
|
-
handler: async (client, args) => {
|
|
479
|
-
const schema = z.object({
|
|
480
|
-
contentId: z.string().optional(),
|
|
481
|
-
goalId: z.string().optional(),
|
|
482
|
-
completed: z.boolean().optional(),
|
|
483
|
-
});
|
|
484
|
-
const params = schema.parse(args);
|
|
485
|
-
const actions = await client.listActions(params);
|
|
486
|
-
return {
|
|
487
|
-
content: [
|
|
488
|
-
{
|
|
489
|
-
type: "text",
|
|
490
|
-
text: `Found ${actions.length} actions`,
|
|
491
|
-
},
|
|
492
|
-
],
|
|
493
|
-
data: actions,
|
|
494
|
-
};
|
|
495
|
-
},
|
|
496
|
-
},
|
|
497
|
-
{
|
|
498
|
-
name: "complete_action",
|
|
499
|
-
description: "Mark an action item as completed",
|
|
500
|
-
inputSchema: {
|
|
501
|
-
type: "object",
|
|
502
|
-
properties: {
|
|
503
|
-
actionId: {
|
|
504
|
-
type: "string",
|
|
505
|
-
description: "The ID of the action to complete",
|
|
506
|
-
},
|
|
507
|
-
},
|
|
508
|
-
required: ["actionId"],
|
|
509
|
-
},
|
|
510
|
-
modifies: true,
|
|
511
|
-
handler: async (client, args) => {
|
|
512
|
-
const schema = z.object({
|
|
513
|
-
actionId: z.string(),
|
|
514
|
-
});
|
|
515
|
-
const { actionId } = schema.parse(args);
|
|
516
|
-
const action = await client.completeAction(actionId);
|
|
517
|
-
return {
|
|
518
|
-
content: [
|
|
519
|
-
{
|
|
520
|
-
type: "text",
|
|
521
|
-
text: `Completed action: ${action.title}`,
|
|
522
|
-
},
|
|
523
|
-
],
|
|
524
|
-
data: action,
|
|
525
|
-
};
|
|
526
|
-
},
|
|
527
|
-
},
|
|
528
|
-
{
|
|
529
|
-
name: "list_goals",
|
|
530
|
-
description: "List user's goals (Health, Wealth, Relationships)",
|
|
531
|
-
inputSchema: {
|
|
532
|
-
type: "object",
|
|
533
|
-
properties: {},
|
|
534
|
-
},
|
|
535
|
-
modifies: false,
|
|
536
|
-
handler: async (client) => {
|
|
537
|
-
const goals = await client.listGoals();
|
|
538
|
-
return {
|
|
539
|
-
content: [
|
|
540
|
-
{
|
|
541
|
-
type: "text",
|
|
542
|
-
text: `Found ${goals.length} goals`,
|
|
543
|
-
},
|
|
544
|
-
],
|
|
545
|
-
data: goals,
|
|
546
|
-
};
|
|
547
|
-
},
|
|
548
|
-
},
|
|
549
|
-
{
|
|
550
|
-
name: "estimate_search_tokens",
|
|
551
|
-
description: "Estimate token usage before performing a search. Helps manage context window and API costs.",
|
|
552
|
-
inputSchema: {
|
|
553
|
-
type: "object",
|
|
554
|
-
properties: {
|
|
555
|
-
query: {
|
|
556
|
-
type: "string",
|
|
557
|
-
description: "Search query to estimate",
|
|
558
|
-
},
|
|
559
|
-
limit: {
|
|
560
|
-
type: "number",
|
|
561
|
-
description: "Number of results to estimate for",
|
|
562
|
-
default: 10,
|
|
563
|
-
},
|
|
564
|
-
},
|
|
565
|
-
required: ["query"],
|
|
566
|
-
},
|
|
567
|
-
modifies: false,
|
|
568
|
-
handler: async (client, args) => {
|
|
569
|
-
const schema = z.object({
|
|
570
|
-
query: z.string(),
|
|
571
|
-
limit: z.number().optional().default(10),
|
|
572
|
-
});
|
|
573
|
-
const params = schema.parse(args);
|
|
574
|
-
const estimate = await client.estimateSearchTokens(params.query, params.limit);
|
|
575
|
-
let responseText = `# Token Estimate for: "${params.query}"\n\n`;
|
|
576
|
-
responseText += `**Total Estimated Tokens:** ${estimate.totals?.estimatedTokens || 0}\n`;
|
|
577
|
-
responseText += `**Recommendation:** ${estimate.recommendation || "Unknown"}\n\n`;
|
|
578
|
-
if (estimate.costEstimate) {
|
|
579
|
-
responseText += `## Estimated Costs\n`;
|
|
580
|
-
responseText += `- GPT-4: ${estimate.costEstimate.gpt4}\n`;
|
|
581
|
-
responseText += `- GPT-3.5: ${estimate.costEstimate.gpt35}\n`;
|
|
582
|
-
responseText += `- Claude 3: ${estimate.costEstimate.claude3}\n\n`;
|
|
583
|
-
}
|
|
584
|
-
if (estimate.estimates && estimate.estimates.length > 0) {
|
|
585
|
-
responseText += `## Content Breakdown\n`;
|
|
586
|
-
estimate.estimates.forEach((item, idx) => {
|
|
587
|
-
responseText += `${idx + 1}. ${item.title || "Untitled"} - ${item.estimatedTokens} tokens\n`;
|
|
588
|
-
});
|
|
589
|
-
}
|
|
590
|
-
return {
|
|
591
|
-
content: [
|
|
592
|
-
{
|
|
593
|
-
type: "text",
|
|
594
|
-
text: responseText,
|
|
595
|
-
},
|
|
596
|
-
],
|
|
597
|
-
data: estimate,
|
|
598
|
-
};
|
|
599
|
-
},
|
|
600
|
-
},
|
|
601
|
-
{
|
|
602
|
-
name: "synthesize_content",
|
|
603
|
-
description: "Analyze multiple content sources to generate actionable insights, find patterns, connections, and contradictions. Creates structured synthesis with timeline, next steps, and confidence scores.",
|
|
604
|
-
inputSchema: {
|
|
605
|
-
type: "object",
|
|
606
|
-
properties: {
|
|
607
|
-
query: {
|
|
608
|
-
type: "string",
|
|
609
|
-
description: "Topic or question to synthesize insights about",
|
|
610
|
-
},
|
|
611
|
-
contentIds: {
|
|
612
|
-
type: "array",
|
|
613
|
-
items: {
|
|
614
|
-
type: "string",
|
|
615
|
-
},
|
|
616
|
-
description: "Specific content IDs to analyze (optional, otherwise uses search)",
|
|
617
|
-
},
|
|
618
|
-
synthesisMode: {
|
|
619
|
-
type: "string",
|
|
620
|
-
enum: ["overview", "deep", "actionable", "comparison"],
|
|
621
|
-
description: "Type of synthesis to perform (default: actionable)",
|
|
622
|
-
default: "actionable",
|
|
623
|
-
},
|
|
624
|
-
findContradictions: {
|
|
625
|
-
type: "boolean",
|
|
626
|
-
description: "Look for contradictions between sources",
|
|
627
|
-
default: false,
|
|
628
|
-
},
|
|
629
|
-
findConnections: {
|
|
630
|
-
type: "boolean",
|
|
631
|
-
description: "Find connections and patterns across sources",
|
|
632
|
-
default: true,
|
|
633
|
-
},
|
|
634
|
-
maxSources: {
|
|
635
|
-
type: "number",
|
|
636
|
-
description: "Maximum number of sources to analyze",
|
|
637
|
-
default: 10,
|
|
638
|
-
},
|
|
639
|
-
},
|
|
640
|
-
required: ["query"],
|
|
641
|
-
},
|
|
642
|
-
modifies: false,
|
|
643
|
-
handler: async (client, args) => {
|
|
644
|
-
const schema = z.object({
|
|
645
|
-
query: z.string(),
|
|
646
|
-
contentIds: z.array(z.string()).optional(),
|
|
647
|
-
synthesisMode: z.enum(["overview", "deep", "actionable", "comparison"]).optional().default("actionable"),
|
|
648
|
-
findContradictions: z.boolean().optional().default(false),
|
|
649
|
-
findConnections: z.boolean().optional().default(true),
|
|
650
|
-
maxSources: z.number().optional().default(10),
|
|
651
|
-
});
|
|
652
|
-
const params = schema.parse(args);
|
|
653
|
-
const result = await client.synthesizeContent(params);
|
|
654
|
-
// Handle the API v2 response format
|
|
655
|
-
const synthesis = result.synthesis || result;
|
|
656
|
-
const metadata = result.metadata || {};
|
|
657
|
-
const sources = result.sources || [];
|
|
658
|
-
let responseText = `# 🎯 Synthesis: "${params.query}"\n`;
|
|
659
|
-
responseText += `**Mode:** ${synthesis.mode || params.synthesisMode} | **Sources:** ${metadata.sourceCount || sources.length}`;
|
|
660
|
-
// Add confidence indicator if available
|
|
661
|
-
if (metadata.confidence) {
|
|
662
|
-
const confidenceIcon = metadata.confidence >= 80 ? "🟢" : metadata.confidence >= 60 ? "🟡" : "🔴";
|
|
663
|
-
responseText += ` | **Confidence:** ${confidenceIcon} ${metadata.confidence}%`;
|
|
664
|
-
}
|
|
665
|
-
responseText += `\n\n`;
|
|
666
|
-
// Summary Section
|
|
667
|
-
if (synthesis.summary) {
|
|
668
|
-
responseText += `## 📋 Summary\n${synthesis.summary}\n\n`;
|
|
669
|
-
}
|
|
670
|
-
// Insights Section (most important)
|
|
671
|
-
if (synthesis.insights && synthesis.insights.length > 0) {
|
|
672
|
-
responseText += `## 💡 Key Insights\n`;
|
|
673
|
-
synthesis.insights.forEach((insight, idx) => {
|
|
674
|
-
// Handle both string and object insights
|
|
675
|
-
if (typeof insight === 'string') {
|
|
676
|
-
responseText += `${idx + 1}. ${insight}\n`;
|
|
677
|
-
}
|
|
678
|
-
else if (insight.text) {
|
|
679
|
-
responseText += `${idx + 1}. **${insight.text}**`;
|
|
680
|
-
if (insight.sourceTitle) {
|
|
681
|
-
responseText += ` *(from: ${insight.sourceTitle})*`;
|
|
682
|
-
}
|
|
683
|
-
responseText += `\n`;
|
|
684
|
-
}
|
|
685
|
-
});
|
|
686
|
-
responseText += `\n`;
|
|
687
|
-
}
|
|
688
|
-
// Themes Section
|
|
689
|
-
if (synthesis.themes && synthesis.themes.length > 0) {
|
|
690
|
-
responseText += `## 🎨 Major Themes\n`;
|
|
691
|
-
synthesis.themes.forEach((theme) => {
|
|
692
|
-
if (typeof theme === 'string') {
|
|
693
|
-
responseText += `- ${theme}\n`;
|
|
694
|
-
}
|
|
695
|
-
else if (theme.theme) {
|
|
696
|
-
responseText += `\n### ${theme.theme}`;
|
|
697
|
-
if (theme.prevalence) {
|
|
698
|
-
responseText += ` (strength: ${theme.prevalence})`;
|
|
699
|
-
}
|
|
700
|
-
responseText += `\n`;
|
|
701
|
-
if (theme.concepts && theme.concepts.length > 0) {
|
|
702
|
-
responseText += `Related concepts: `;
|
|
703
|
-
responseText += theme.concepts.slice(0, 3).map((c) => typeof c === 'string' ? c : c.concept).join(', ');
|
|
704
|
-
responseText += `\n`;
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
});
|
|
708
|
-
responseText += `\n`;
|
|
709
|
-
}
|
|
710
|
-
// Priorities (for actionable mode)
|
|
711
|
-
if (synthesis.priorities) {
|
|
712
|
-
responseText += `## 🎯 Priorities\n`;
|
|
713
|
-
if (synthesis.priorities.high && synthesis.priorities.high.length > 0) {
|
|
714
|
-
responseText += `\n### 🔴 High Priority\n`;
|
|
715
|
-
synthesis.priorities.high.forEach((item) => {
|
|
716
|
-
responseText += `- ${item}\n`;
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
if (synthesis.priorities.medium && synthesis.priorities.medium.length > 0) {
|
|
720
|
-
responseText += `\n### 🟡 Medium Priority\n`;
|
|
721
|
-
synthesis.priorities.medium.forEach((item) => {
|
|
722
|
-
responseText += `- ${item}\n`;
|
|
723
|
-
});
|
|
724
|
-
}
|
|
725
|
-
if (synthesis.priorities.low && synthesis.priorities.low.length > 0) {
|
|
726
|
-
responseText += `\n### 🟢 Low Priority\n`;
|
|
727
|
-
synthesis.priorities.low.forEach((item) => {
|
|
728
|
-
responseText += `- ${item}\n`;
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
responseText += `\n`;
|
|
732
|
-
}
|
|
733
|
-
// Implementation Steps (for actionable mode)
|
|
734
|
-
if (synthesis.implementation && synthesis.implementation.length > 0) {
|
|
735
|
-
responseText += `## 📝 Implementation Steps\n`;
|
|
736
|
-
synthesis.implementation.forEach((step, idx) => {
|
|
737
|
-
responseText += `${idx + 1}. ${step}\n`;
|
|
738
|
-
});
|
|
739
|
-
responseText += `\n`;
|
|
740
|
-
}
|
|
741
|
-
// Source Comparison (for comparative mode)
|
|
742
|
-
if (synthesis.sourceComparison && synthesis.sourceComparison.length > 0) {
|
|
743
|
-
responseText += `## 📊 Source Comparison\n`;
|
|
744
|
-
synthesis.sourceComparison.forEach((source) => {
|
|
745
|
-
responseText += `\n### ${source.source}\n`;
|
|
746
|
-
responseText += `- **Insights:** ${source.insightCount}\n`;
|
|
747
|
-
if (source.mainThemes && source.mainThemes.length > 0) {
|
|
748
|
-
responseText += `- **Main themes:** ${source.mainThemes.join(', ')}\n`;
|
|
749
|
-
}
|
|
750
|
-
});
|
|
751
|
-
responseText += `\n`;
|
|
752
|
-
}
|
|
753
|
-
// Commonalities and Differences
|
|
754
|
-
if (synthesis.commonalities && synthesis.commonalities.length > 0) {
|
|
755
|
-
responseText += `## ✅ Common Themes Across Sources\n`;
|
|
756
|
-
synthesis.commonalities.forEach((theme) => {
|
|
757
|
-
responseText += `- ${theme}\n`;
|
|
758
|
-
});
|
|
759
|
-
responseText += `\n`;
|
|
760
|
-
}
|
|
761
|
-
if (synthesis.differences && synthesis.differences.length > 0) {
|
|
762
|
-
responseText += `## 🔀 Unique Perspectives\n`;
|
|
763
|
-
synthesis.differences.forEach((diff) => {
|
|
764
|
-
responseText += `- **${diff.source}:** ${diff.themes.join(', ')}\n`;
|
|
765
|
-
});
|
|
766
|
-
responseText += `\n`;
|
|
767
|
-
}
|
|
768
|
-
// Connections
|
|
769
|
-
if (synthesis.connections && synthesis.connections.length > 0) {
|
|
770
|
-
responseText += `## 🔗 Connections & Patterns\n`;
|
|
771
|
-
synthesis.connections.forEach((conn) => {
|
|
772
|
-
if (conn.concept && conn.sources) {
|
|
773
|
-
responseText += `- **${conn.concept}** appears in: ${conn.sources.join(', ')}`;
|
|
774
|
-
if (conn.strength) {
|
|
775
|
-
responseText += ` (strength: ${conn.strength})`;
|
|
776
|
-
}
|
|
777
|
-
responseText += `\n`;
|
|
778
|
-
}
|
|
779
|
-
else if (conn.pattern) {
|
|
780
|
-
responseText += `- **${conn.pattern}**`;
|
|
781
|
-
if (conn.implication) {
|
|
782
|
-
responseText += `: ${conn.implication}`;
|
|
783
|
-
}
|
|
784
|
-
responseText += `\n`;
|
|
785
|
-
}
|
|
786
|
-
});
|
|
787
|
-
responseText += `\n`;
|
|
788
|
-
}
|
|
789
|
-
// Contradictions
|
|
790
|
-
if (synthesis.contradictions && synthesis.contradictions.length > 0) {
|
|
791
|
-
responseText += `## ⚡ Contradictions Found\n`;
|
|
792
|
-
synthesis.contradictions.forEach((contra) => {
|
|
793
|
-
if (contra.source1 && contra.statement1) {
|
|
794
|
-
responseText += `\n### Potential Contradiction\n`;
|
|
795
|
-
responseText += `- **${contra.source1}:** "${contra.statement1}"\n`;
|
|
796
|
-
responseText += `- **${contra.source2}:** "${contra.statement2}"\n`;
|
|
797
|
-
if (contra.type) {
|
|
798
|
-
responseText += `- **Type:** ${contra.type}\n`;
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
else if (contra.topic) {
|
|
802
|
-
responseText += `\n### ${contra.topic}\n`;
|
|
803
|
-
if (contra.viewpoints) {
|
|
804
|
-
contra.viewpoints.forEach((vp) => {
|
|
805
|
-
responseText += `- **${vp.position}:** ${vp.argument}\n`;
|
|
806
|
-
});
|
|
807
|
-
}
|
|
808
|
-
if (contra.resolution) {
|
|
809
|
-
responseText += `**Suggested resolution:** ${contra.resolution}\n`;
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
});
|
|
813
|
-
responseText += `\n`;
|
|
814
|
-
}
|
|
815
|
-
// Timeline
|
|
816
|
-
if (synthesis.timeline && synthesis.timeline.length > 0) {
|
|
817
|
-
responseText += `## ⏱️ Timeline\n`;
|
|
818
|
-
synthesis.timeline.forEach((event) => {
|
|
819
|
-
if (event.date) {
|
|
820
|
-
responseText += `- **${event.date}:** ${event.event}`;
|
|
821
|
-
if (event.source) {
|
|
822
|
-
responseText += ` *(${event.source})*`;
|
|
823
|
-
}
|
|
824
|
-
responseText += `\n`;
|
|
825
|
-
}
|
|
826
|
-
else if (event.phase) {
|
|
827
|
-
responseText += `\n### ${event.phase}`;
|
|
828
|
-
if (event.duration) {
|
|
829
|
-
responseText += ` (${event.duration})`;
|
|
830
|
-
}
|
|
831
|
-
responseText += `\n`;
|
|
832
|
-
if (event.activities && event.activities.length > 0) {
|
|
833
|
-
event.activities.forEach((activity) => {
|
|
834
|
-
responseText += `- ${activity}\n`;
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
});
|
|
839
|
-
responseText += `\n`;
|
|
840
|
-
}
|
|
841
|
-
// Action Plan
|
|
842
|
-
if (synthesis.actionPlan) {
|
|
843
|
-
responseText += `## 🚀 Action Plan\n`;
|
|
844
|
-
if (synthesis.actionPlan.summary) {
|
|
845
|
-
responseText += `${synthesis.actionPlan.summary}\n\n`;
|
|
846
|
-
}
|
|
847
|
-
if (synthesis.actionPlan.nextAction) {
|
|
848
|
-
responseText += `**🎯 Next Action:** ${synthesis.actionPlan.nextAction.action || synthesis.actionPlan.nextAction}\n\n`;
|
|
849
|
-
}
|
|
850
|
-
if (synthesis.actionPlan.steps && synthesis.actionPlan.steps.length > 0) {
|
|
851
|
-
responseText += `### Steps\n`;
|
|
852
|
-
synthesis.actionPlan.steps.forEach((step, idx) => {
|
|
853
|
-
const priorityIcon = step.priority === "high" ? "🔴" : step.priority === "medium" ? "🟡" : "🟢";
|
|
854
|
-
responseText += `${idx + 1}. ${priorityIcon} **${step.action}**`;
|
|
855
|
-
if (step.timeframe) {
|
|
856
|
-
responseText += ` *(${step.timeframe})*`;
|
|
857
|
-
}
|
|
858
|
-
if (step.reasoning) {
|
|
859
|
-
responseText += `\n - Reasoning: ${step.reasoning}`;
|
|
860
|
-
}
|
|
861
|
-
responseText += `\n`;
|
|
862
|
-
});
|
|
863
|
-
}
|
|
864
|
-
responseText += `\n`;
|
|
865
|
-
}
|
|
866
|
-
// Key Facts (if available)
|
|
867
|
-
if (synthesis.keyFacts && synthesis.keyFacts.length > 0) {
|
|
868
|
-
responseText += `## 📌 Key Facts\n`;
|
|
869
|
-
synthesis.keyFacts.slice(0, 5).forEach((fact) => {
|
|
870
|
-
if (typeof fact === 'string') {
|
|
871
|
-
responseText += `- ${fact}\n`;
|
|
872
|
-
}
|
|
873
|
-
else if (fact.text) {
|
|
874
|
-
responseText += `- ${fact.text}`;
|
|
875
|
-
if (fact.sourceTitle) {
|
|
876
|
-
responseText += ` *(${fact.sourceTitle})*`;
|
|
877
|
-
}
|
|
878
|
-
responseText += `\n`;
|
|
879
|
-
}
|
|
880
|
-
});
|
|
881
|
-
responseText += `\n`;
|
|
882
|
-
}
|
|
883
|
-
// Source Information
|
|
884
|
-
if (sources && sources.length > 0) {
|
|
885
|
-
responseText += `## 📚 Sources Analyzed\n`;
|
|
886
|
-
sources.forEach((source, idx) => {
|
|
887
|
-
const typeIcons = {
|
|
888
|
-
youtube: "📺",
|
|
889
|
-
x_twitter: "𝕏",
|
|
890
|
-
reddit: "🔗",
|
|
891
|
-
article: "📄",
|
|
892
|
-
pdf: "📑"
|
|
893
|
-
};
|
|
894
|
-
const typeIcon = typeIcons[source.type] || "📄";
|
|
895
|
-
responseText += `${idx + 1}. ${typeIcon} [${source.title}](${source.url})\n`;
|
|
896
|
-
});
|
|
897
|
-
responseText += `\n`;
|
|
898
|
-
}
|
|
899
|
-
// Metadata Footer
|
|
900
|
-
responseText += `---\n`;
|
|
901
|
-
responseText += `*Analysis completed in ${metadata.executionTime ? `${metadata.executionTime}ms` : 'N/A'}`;
|
|
902
|
-
if (metadata.totalTokens) {
|
|
903
|
-
responseText += ` | Processed ${metadata.totalTokens.toLocaleString()} tokens`;
|
|
904
|
-
}
|
|
905
|
-
if (metadata.focusAreas && metadata.focusAreas.length > 0) {
|
|
906
|
-
responseText += ` | Focus: ${metadata.focusAreas.join(', ')}`;
|
|
907
|
-
}
|
|
908
|
-
responseText += `*\n`;
|
|
909
|
-
return {
|
|
910
|
-
content: [
|
|
911
|
-
{
|
|
912
|
-
type: "text",
|
|
913
|
-
text: responseText,
|
|
914
|
-
},
|
|
915
|
-
],
|
|
916
|
-
data: result,
|
|
917
|
-
};
|
|
918
|
-
},
|
|
919
|
-
},
|
|
920
|
-
{
|
|
921
|
-
name: "find_similar_content",
|
|
922
|
-
description: "Find content similar to a specific saved item using semantic similarity.",
|
|
923
|
-
inputSchema: {
|
|
924
|
-
type: "object",
|
|
925
|
-
properties: {
|
|
926
|
-
contentId: {
|
|
927
|
-
type: "string",
|
|
928
|
-
description: "ID of the content to find similar items for",
|
|
929
|
-
},
|
|
930
|
-
limit: {
|
|
931
|
-
type: "number",
|
|
932
|
-
description: "Maximum number of similar items to return",
|
|
933
|
-
default: 5,
|
|
934
|
-
},
|
|
935
|
-
minSimilarity: {
|
|
936
|
-
type: "number",
|
|
937
|
-
description: "Minimum similarity score (0-1)",
|
|
938
|
-
default: 0.7,
|
|
939
|
-
},
|
|
940
|
-
},
|
|
941
|
-
required: ["contentId"],
|
|
942
|
-
},
|
|
943
|
-
modifies: false,
|
|
944
|
-
handler: async (client, args) => {
|
|
945
|
-
const schema = z.object({
|
|
946
|
-
contentId: z.string(),
|
|
947
|
-
limit: z.number().optional().default(5),
|
|
948
|
-
minSimilarity: z.number().optional().default(0.7),
|
|
949
|
-
});
|
|
950
|
-
const params = schema.parse(args);
|
|
951
|
-
const result = await client.findSimilarContent(params.contentId, {
|
|
952
|
-
limit: params.limit,
|
|
953
|
-
minSimilarity: params.minSimilarity,
|
|
954
|
-
});
|
|
955
|
-
let responseText = `# Similar Content to: ${result.source?.title || "Unknown"}\n\n`;
|
|
956
|
-
if (result.similarContent && result.similarContent.length > 0) {
|
|
957
|
-
responseText += `Found ${result.similarContent.length} similar items:\n\n`;
|
|
958
|
-
result.similarContent.forEach((item, idx) => {
|
|
959
|
-
responseText += `## ${idx + 1}. ${item.title || "Untitled"}\n`;
|
|
960
|
-
responseText += `**Similarity:** ${(item.similarity * 100).toFixed(1)}%\n`;
|
|
961
|
-
responseText += `**Type:** ${item.type || item.contentType || "unknown"} | **URL:** ${item.url}\n`;
|
|
962
|
-
if (item.summary) {
|
|
963
|
-
responseText += `**Summary:** ${item.summary}\n`;
|
|
964
|
-
}
|
|
965
|
-
responseText += `\n`;
|
|
966
|
-
});
|
|
967
|
-
}
|
|
968
|
-
else {
|
|
969
|
-
responseText += `No similar content found with similarity >= ${params.minSimilarity}`;
|
|
970
|
-
}
|
|
971
|
-
return {
|
|
972
|
-
content: [
|
|
973
|
-
{
|
|
974
|
-
type: "text",
|
|
975
|
-
text: responseText,
|
|
976
|
-
},
|
|
977
|
-
],
|
|
978
|
-
data: result,
|
|
979
|
-
};
|
|
980
|
-
},
|
|
981
|
-
},
|
|
982
|
-
{
|
|
983
|
-
name: "batch_get_content",
|
|
984
|
-
description: "Fetch multiple content items in a single request. Efficient for bulk operations.",
|
|
985
|
-
inputSchema: {
|
|
986
|
-
type: "object",
|
|
987
|
-
properties: {
|
|
988
|
-
ids: {
|
|
989
|
-
type: "array",
|
|
990
|
-
items: {
|
|
991
|
-
type: "string",
|
|
992
|
-
},
|
|
993
|
-
description: "Array of content IDs to fetch",
|
|
994
|
-
},
|
|
995
|
-
includeFullContent: {
|
|
996
|
-
type: "boolean",
|
|
997
|
-
description: "Include full text content (warning: may use many tokens)",
|
|
998
|
-
default: false,
|
|
999
|
-
},
|
|
1000
|
-
},
|
|
1001
|
-
required: ["ids"],
|
|
1002
|
-
},
|
|
1003
|
-
modifies: false,
|
|
1004
|
-
handler: async (client, args) => {
|
|
1005
|
-
const schema = z.object({
|
|
1006
|
-
ids: z.array(z.string()).min(1).max(50),
|
|
1007
|
-
includeFullContent: z.boolean().optional().default(false),
|
|
1008
|
-
});
|
|
1009
|
-
const params = schema.parse(args);
|
|
1010
|
-
const result = await client.batchGetContent(params.ids, params.includeFullContent);
|
|
1011
|
-
let responseText = `# Batch Content Fetch\n\n`;
|
|
1012
|
-
responseText += `Requested: ${params.ids.length} items\n`;
|
|
1013
|
-
responseText += `Found: ${result.metadata?.found || 0} items\n`;
|
|
1014
|
-
// Calculate and warn about total tokens
|
|
1015
|
-
let totalTokens = 0;
|
|
1016
|
-
if (result.results && result.results.length > 0) {
|
|
1017
|
-
result.results.forEach((item) => {
|
|
1018
|
-
if (item.tokenCount)
|
|
1019
|
-
totalTokens += item.tokenCount;
|
|
1020
|
-
});
|
|
1021
|
-
}
|
|
1022
|
-
if (params.includeFullContent && totalTokens > 0) {
|
|
1023
|
-
responseText += `\n⚠️ **Full Content Included - Total Size: ${totalTokens.toLocaleString()} tokens**`;
|
|
1024
|
-
if (totalTokens > 100000) {
|
|
1025
|
-
responseText += ` 🚨 EXTREMELY LARGE!\n`;
|
|
1026
|
-
responseText += `WARNING: This WILL consume most or all of your context window!\n`;
|
|
1027
|
-
responseText += `Consider setting includeFullContent: false to just get summaries.\n`;
|
|
1028
|
-
}
|
|
1029
|
-
else if (totalTokens > 50000) {
|
|
1030
|
-
responseText += ` 🚨 VERY LARGE!\n`;
|
|
1031
|
-
responseText += `This is consuming significant context. Use with caution.\n`;
|
|
1032
|
-
}
|
|
1033
|
-
else if (totalTokens > 10000) {
|
|
1034
|
-
responseText += ` ⚠️\n`;
|
|
1035
|
-
}
|
|
1036
|
-
else {
|
|
1037
|
-
responseText += `\n`;
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
else if (!params.includeFullContent && totalTokens > 0) {
|
|
1041
|
-
responseText += `\n💡 **Showing summaries only.** Total content available: ~${totalTokens.toLocaleString()} tokens.\n`;
|
|
1042
|
-
responseText += `Rich metadata (summaries, tags, insights) included with minimal token usage.\n`;
|
|
1043
|
-
}
|
|
1044
|
-
responseText += `\n`;
|
|
1045
|
-
if (result.results && result.results.length > 0) {
|
|
1046
|
-
result.results.forEach((item, idx) => {
|
|
1047
|
-
if (item.error) {
|
|
1048
|
-
responseText += `## ${idx + 1}. Error: ${item.id}\n`;
|
|
1049
|
-
responseText += `${item.error}\n\n`;
|
|
1050
|
-
}
|
|
1051
|
-
else {
|
|
1052
|
-
responseText += `## ${idx + 1}. ${item.title || "Untitled"}\n`;
|
|
1053
|
-
responseText += `**ID:** ${item.id}\n`;
|
|
1054
|
-
responseText += `**Type:** ${item.contentType} | **URL:** ${item.url}\n`;
|
|
1055
|
-
if (item.tokenCount) {
|
|
1056
|
-
responseText += `**Tokens:** ${item.tokenCount.toLocaleString()}`;
|
|
1057
|
-
if (item.tokenCount > 10000)
|
|
1058
|
-
responseText += ` ⚠️`;
|
|
1059
|
-
responseText += `\n`;
|
|
1060
|
-
}
|
|
1061
|
-
if (item.summary) {
|
|
1062
|
-
responseText += `**Summary:** ${typeof item.summary === "string" ? item.summary : item.summary.one_sentence || "N/A"}\n`;
|
|
1063
|
-
}
|
|
1064
|
-
if (params.includeFullContent && item.fullContent) {
|
|
1065
|
-
responseText += `**Content Length:** ${item.metadata?.contentLength || 0} characters\n`;
|
|
1066
|
-
}
|
|
1067
|
-
responseText += `\n`;
|
|
1068
|
-
}
|
|
1069
|
-
});
|
|
1070
|
-
}
|
|
1071
|
-
return {
|
|
1072
|
-
content: [
|
|
1073
|
-
{
|
|
1074
|
-
type: "text",
|
|
1075
|
-
text: responseText,
|
|
1076
|
-
},
|
|
1077
|
-
],
|
|
1078
|
-
data: result,
|
|
1079
|
-
};
|
|
1080
|
-
},
|
|
1081
|
-
},
|
|
1082
|
-
{
|
|
1083
|
-
name: "get_instructions",
|
|
1084
|
-
description: "Get instructions for optimal MCP usage, including capabilities, best practices, and example workflows",
|
|
1085
|
-
inputSchema: {
|
|
1086
|
-
type: "object",
|
|
1087
|
-
properties: {
|
|
1088
|
-
topic: {
|
|
1089
|
-
type: "string",
|
|
1090
|
-
description: "Specific topic for instructions (optional)",
|
|
1091
|
-
enum: ["search", "synthesis", "retrieval", "general"],
|
|
1092
|
-
},
|
|
1093
|
-
includeExamples: {
|
|
1094
|
-
type: "boolean",
|
|
1095
|
-
description: "Include workflow examples",
|
|
1096
|
-
default: true,
|
|
1097
|
-
},
|
|
1098
|
-
},
|
|
1099
|
-
},
|
|
1100
|
-
modifies: false,
|
|
1101
|
-
handler: async (client, args) => {
|
|
1102
|
-
const schema = z.object({
|
|
1103
|
-
topic: z.enum(["search", "synthesis", "retrieval", "general"]).optional(),
|
|
1104
|
-
includeExamples: z.boolean().optional().default(true),
|
|
1105
|
-
});
|
|
1106
|
-
const params = schema.parse(args);
|
|
1107
|
-
const instructions = generateLLMInstructions();
|
|
1108
|
-
let responseText = `# Noverload MCP Usage Instructions\n\n`;
|
|
1109
|
-
responseText += `## Version: ${instructions.version}\n\n`;
|
|
1110
|
-
if (!params.topic || params.topic === "general") {
|
|
1111
|
-
// Show all capabilities
|
|
1112
|
-
responseText += `## Capabilities Overview\n\n`;
|
|
1113
|
-
for (const [key, capability] of Object.entries(instructions.capabilities)) {
|
|
1114
|
-
responseText += `### ${key.charAt(0).toUpperCase() + key.slice(1)}\n`;
|
|
1115
|
-
responseText += `${capability.description}\n\n`;
|
|
1116
|
-
responseText += `**Strengths:**\n`;
|
|
1117
|
-
capability.strengths.forEach((s) => responseText += `- ${s}\n`);
|
|
1118
|
-
responseText += `\n**When to use:**\n`;
|
|
1119
|
-
capability.whenToUse.forEach((w) => responseText += `- ${w}\n`);
|
|
1120
|
-
responseText += `\n`;
|
|
1121
|
-
}
|
|
1122
|
-
responseText += `## Best Practices\n\n`;
|
|
1123
|
-
for (const [scenario, practice] of Object.entries(instructions.bestPractices)) {
|
|
1124
|
-
responseText += `**${scenario.replace(/([A-Z])/g, ' $1').toLowerCase()}:** ${practice}\n`;
|
|
1125
|
-
}
|
|
1126
|
-
responseText += `\n`;
|
|
1127
|
-
}
|
|
1128
|
-
else {
|
|
1129
|
-
// Show specific capability
|
|
1130
|
-
const capability = instructions.capabilities[params.topic];
|
|
1131
|
-
if (capability) {
|
|
1132
|
-
responseText += `## ${params.topic.charAt(0).toUpperCase() + params.topic.slice(1)} Capability\n\n`;
|
|
1133
|
-
responseText += `${capability.description}\n\n`;
|
|
1134
|
-
responseText += `### Strengths\n`;
|
|
1135
|
-
capability.strengths.forEach(s => responseText += `- ${s}\n`);
|
|
1136
|
-
responseText += `\n### Limitations\n`;
|
|
1137
|
-
capability.limitations.forEach(l => responseText += `- ${l}\n`);
|
|
1138
|
-
responseText += `\n### When to Use\n`;
|
|
1139
|
-
capability.whenToUse.forEach(w => responseText += `- ${w}\n`);
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
if (params.includeExamples && instructions.exampleWorkflows.length > 0) {
|
|
1143
|
-
responseText += `\n## Example Workflows\n\n`;
|
|
1144
|
-
instructions.exampleWorkflows.forEach((example, idx) => {
|
|
1145
|
-
responseText += `### ${idx + 1}. ${example.scenario}\n`;
|
|
1146
|
-
responseText += `**Steps:**\n`;
|
|
1147
|
-
example.steps.forEach((step, i) => responseText += `${i + 1}. ${step}\n`);
|
|
1148
|
-
responseText += `**Expected Outcome:** ${example.expectedOutcome}\n\n`;
|
|
1149
|
-
});
|
|
1150
|
-
}
|
|
1151
|
-
responseText += `## Token Management\n\n`;
|
|
1152
|
-
responseText += `- Search results limit: ${instructions.tokenManagement.searchResultsLimit}\n`;
|
|
1153
|
-
responseText += `- Use chunking: ${instructions.tokenManagement.useChunking ? 'Yes' : 'No'}\n`;
|
|
1154
|
-
responseText += `- Get summaries first: ${instructions.tokenManagement.summaryFirst ? 'Yes' : 'No'}\n`;
|
|
1155
|
-
responseText += `- Max content per query: ${instructions.tokenManagement.maxContentPerQuery.toLocaleString()} tokens\n`;
|
|
1156
|
-
return {
|
|
1157
|
-
content: [
|
|
1158
|
-
{
|
|
1159
|
-
type: "text",
|
|
1160
|
-
text: responseText,
|
|
1161
|
-
},
|
|
1162
|
-
],
|
|
1163
|
-
data: instructions,
|
|
1164
|
-
};
|
|
1165
|
-
},
|
|
1166
|
-
},
|
|
1167
|
-
{
|
|
1168
|
-
name: "plan_query",
|
|
1169
|
-
description: "Plan an optimal query strategy for complex requests, with token estimates",
|
|
1170
|
-
inputSchema: {
|
|
1171
|
-
type: "object",
|
|
1172
|
-
properties: {
|
|
1173
|
-
request: {
|
|
1174
|
-
type: "string",
|
|
1175
|
-
description: "The user's request to plan for",
|
|
1176
|
-
},
|
|
1177
|
-
},
|
|
1178
|
-
required: ["request"],
|
|
1179
|
-
},
|
|
1180
|
-
modifies: false,
|
|
1181
|
-
handler: async (client, args) => {
|
|
1182
|
-
const schema = z.object({
|
|
1183
|
-
request: z.string(),
|
|
1184
|
-
});
|
|
1185
|
-
const { request } = schema.parse(args);
|
|
1186
|
-
const availableTools = [
|
|
1187
|
-
"search_content",
|
|
1188
|
-
"get_content_details",
|
|
1189
|
-
"synthesize_content",
|
|
1190
|
-
"find_similar_content",
|
|
1191
|
-
"list_saved_content"
|
|
1192
|
-
];
|
|
1193
|
-
const plan = planQueryStrategy(request, availableTools);
|
|
1194
|
-
let responseText = `# Query Plan for: "${request}"\n\n`;
|
|
1195
|
-
responseText += `## Strategy: ${plan.strategy}\n`;
|
|
1196
|
-
responseText += `## Estimated Tokens: ~${plan.estimatedTokens.toLocaleString()}\n\n`;
|
|
1197
|
-
responseText += `## Execution Steps:\n\n`;
|
|
1198
|
-
plan.steps.forEach((step, idx) => {
|
|
1199
|
-
responseText += `### Step ${idx + 1}: ${step.tool}\n`;
|
|
1200
|
-
responseText += `**Purpose:** ${step.purpose}\n`;
|
|
1201
|
-
responseText += `**Parameters:**\n`;
|
|
1202
|
-
for (const [key, value] of Object.entries(step.params)) {
|
|
1203
|
-
responseText += `- ${key}: ${JSON.stringify(value)}\n`;
|
|
1204
|
-
}
|
|
1205
|
-
const tokenEstimate = estimateTokenUsage({ tool: step.tool, params: step.params });
|
|
1206
|
-
responseText += `**Estimated Tokens:** ~${tokenEstimate.estimated.toLocaleString()}`;
|
|
1207
|
-
if (tokenEstimate.warning) {
|
|
1208
|
-
responseText += ` ⚠️ ${tokenEstimate.warning}`;
|
|
1209
|
-
}
|
|
1210
|
-
responseText += `\n`;
|
|
1211
|
-
if (tokenEstimate.suggestion) {
|
|
1212
|
-
responseText += `**Suggestion:** ${tokenEstimate.suggestion}\n`;
|
|
1213
|
-
}
|
|
1214
|
-
responseText += `\n`;
|
|
1215
|
-
});
|
|
1216
|
-
return {
|
|
1217
|
-
content: [
|
|
1218
|
-
{
|
|
1219
|
-
type: "text",
|
|
1220
|
-
text: responseText,
|
|
1221
|
-
},
|
|
1222
|
-
],
|
|
1223
|
-
data: plan,
|
|
1224
|
-
};
|
|
1225
|
-
},
|
|
1226
|
-
},
|
|
1227
|
-
{
|
|
1228
|
-
name: "get_raw_content",
|
|
1229
|
-
description: "Access full raw text of saved content with smart chunking for large documents. Requires confirmation for content >10k tokens. Returns complete unprocessed text or intelligently chunked sections.",
|
|
1230
|
-
inputSchema: {
|
|
1231
|
-
type: "object",
|
|
1232
|
-
properties: {
|
|
1233
|
-
contentId: {
|
|
1234
|
-
type: "string",
|
|
1235
|
-
description: "The ID of the content to retrieve raw text for",
|
|
1236
|
-
},
|
|
1237
|
-
format: {
|
|
1238
|
-
type: "string",
|
|
1239
|
-
enum: ["full", "chunks", "sections"],
|
|
1240
|
-
description: "Format: 'full' (complete text), 'chunks' (semantic chunks), 'sections' (logical sections)",
|
|
1241
|
-
default: "chunks",
|
|
1242
|
-
},
|
|
1243
|
-
maxTokens: {
|
|
1244
|
-
type: "number",
|
|
1245
|
-
description: "Maximum tokens to return (only for chunks/sections format)",
|
|
1246
|
-
default: 50000,
|
|
1247
|
-
},
|
|
1248
|
-
chunkSize: {
|
|
1249
|
-
type: "number",
|
|
1250
|
-
description: "Target size for each chunk in tokens (for chunks format)",
|
|
1251
|
-
default: 4000,
|
|
1252
|
-
},
|
|
1253
|
-
includeMetadata: {
|
|
1254
|
-
type: "boolean",
|
|
1255
|
-
description: "Include metadata about sections/chunks",
|
|
1256
|
-
default: true,
|
|
1257
|
-
},
|
|
1258
|
-
confirmLargeContent: {
|
|
1259
|
-
type: "boolean",
|
|
1260
|
-
description: "Confirm retrieval of large content (>10k tokens)",
|
|
1261
|
-
default: false,
|
|
1262
|
-
},
|
|
1263
|
-
},
|
|
1264
|
-
required: ["contentId"],
|
|
1265
|
-
},
|
|
1266
|
-
modifies: false,
|
|
1267
|
-
handler: async (client, args) => {
|
|
1268
|
-
const schema = z.object({
|
|
1269
|
-
contentId: z.string(),
|
|
1270
|
-
format: z.enum(["full", "chunks", "sections"]).optional().default("chunks"),
|
|
1271
|
-
maxTokens: z.number().optional().default(50000),
|
|
1272
|
-
chunkSize: z.number().optional().default(4000),
|
|
1273
|
-
includeMetadata: z.boolean().optional().default(true),
|
|
1274
|
-
confirmLargeContent: z.boolean().optional().default(false),
|
|
1275
|
-
});
|
|
1276
|
-
const params = schema.parse(args);
|
|
1277
|
-
// First get content metadata to check size
|
|
1278
|
-
const content = await client.getContent(params.contentId);
|
|
1279
|
-
if (!content.rawText) {
|
|
1280
|
-
// Try to get raw content through v2 API with enrichment
|
|
1281
|
-
const enrichedResult = await client.getEnrichedContent([params.contentId], true);
|
|
1282
|
-
if (!enrichedResult || enrichedResult.length === 0 || !enrichedResult[0].rawText) {
|
|
1283
|
-
return {
|
|
1284
|
-
content: [
|
|
1285
|
-
{
|
|
1286
|
-
type: "text",
|
|
1287
|
-
text: `No raw text available for content ID: ${params.contentId}. Content may still be processing or does not contain extractable text.`,
|
|
1288
|
-
},
|
|
1289
|
-
],
|
|
1290
|
-
data: null,
|
|
1291
|
-
};
|
|
1292
|
-
}
|
|
1293
|
-
// Use the enriched content
|
|
1294
|
-
content.rawText = enrichedResult[0].rawText;
|
|
1295
|
-
content.tokenCount = enrichedResult[0].tokenCount;
|
|
1296
|
-
}
|
|
1297
|
-
const wordCount = content.rawText ? content.rawText.split(/\s+/).length : 0;
|
|
1298
|
-
const estimatedTokens = content.tokenCount || Math.ceil(wordCount * 1.3);
|
|
1299
|
-
// Check if confirmation is needed for large content
|
|
1300
|
-
if (params.format === "full" && estimatedTokens > 10000 && !params.confirmLargeContent) {
|
|
1301
|
-
let warningText = `# ⚠️ Large Content Warning\n\n`;
|
|
1302
|
-
warningText += `**Content:** ${content.title || 'Untitled'}\n`;
|
|
1303
|
-
warningText += `**Size:** ${wordCount.toLocaleString()} words (~${estimatedTokens.toLocaleString()} tokens)\n\n`;
|
|
1304
|
-
if (estimatedTokens > 100000) {
|
|
1305
|
-
warningText += `## 🚨 CRITICAL: Extremely Large Content\n`;
|
|
1306
|
-
warningText += `This content contains ${estimatedTokens.toLocaleString()} tokens and will **exceed most LLM context windows**.\n\n`;
|
|
1307
|
-
warningText += `**Recommendations:**\n`;
|
|
1308
|
-
warningText += `1. Use format='chunks' to process in smaller pieces\n`;
|
|
1309
|
-
warningText += `2. Use format='sections' to get logical divisions\n`;
|
|
1310
|
-
warningText += `3. Use search_content to find specific information\n`;
|
|
1311
|
-
warningText += `4. Use synthesize_content to get key insights without full text\n\n`;
|
|
1312
|
-
}
|
|
1313
|
-
else if (estimatedTokens > 50000) {
|
|
1314
|
-
warningText += `## ⚠️ Very Large Content\n`;
|
|
1315
|
-
warningText += `This content contains ${estimatedTokens.toLocaleString()} tokens and will use **most of your context window**.\n\n`;
|
|
1316
|
-
warningText += `**Consider:**\n`;
|
|
1317
|
-
warningText += `- Using format='chunks' for manageable pieces\n`;
|
|
1318
|
-
warningText += `- Using search or synthesis tools instead\n\n`;
|
|
1319
|
-
}
|
|
1320
|
-
else {
|
|
1321
|
-
warningText += `## Large Content Notice\n`;
|
|
1322
|
-
warningText += `This content will use ${estimatedTokens.toLocaleString()} tokens of your context.\n\n`;
|
|
1323
|
-
}
|
|
1324
|
-
warningText += `**To proceed with full text retrieval:**\n`;
|
|
1325
|
-
warningText += `Call get_raw_content again with:\n`;
|
|
1326
|
-
warningText += `- contentId: "${params.contentId}"\n`;
|
|
1327
|
-
warningText += `- format: "full"\n`;
|
|
1328
|
-
warningText += `- confirmLargeContent: true\n\n`;
|
|
1329
|
-
warningText += `**Alternative approaches:**\n`;
|
|
1330
|
-
warningText += `- format: "chunks" - Get content in ${Math.ceil(estimatedTokens / params.chunkSize)} chunks of ~${params.chunkSize} tokens\n`;
|
|
1331
|
-
warningText += `- format: "sections" - Get logical sections with headers\n`;
|
|
1332
|
-
return {
|
|
1333
|
-
content: [
|
|
1334
|
-
{
|
|
1335
|
-
type: "text",
|
|
1336
|
-
text: warningText,
|
|
1337
|
-
},
|
|
1338
|
-
],
|
|
1339
|
-
data: {
|
|
1340
|
-
requiresConfirmation: true,
|
|
1341
|
-
contentId: params.contentId,
|
|
1342
|
-
title: content.title,
|
|
1343
|
-
estimatedTokens,
|
|
1344
|
-
suggestedFormat: estimatedTokens > 50000 ? "chunks" : "sections",
|
|
1345
|
-
chunkCount: Math.ceil(estimatedTokens / params.chunkSize),
|
|
1346
|
-
},
|
|
1347
|
-
};
|
|
1348
|
-
}
|
|
1349
|
-
let responseText = `# Raw Content: ${content.title || 'Untitled'}\n\n`;
|
|
1350
|
-
responseText += `**Content Type:** ${content.contentType}\n`;
|
|
1351
|
-
responseText += `**URL:** ${content.url}\n`;
|
|
1352
|
-
responseText += `**Size:** ${wordCount.toLocaleString()} words (~${estimatedTokens.toLocaleString()} tokens)\n`;
|
|
1353
|
-
// Add appropriate warning based on size
|
|
1354
|
-
if (estimatedTokens > 50000 && params.format === "full") {
|
|
1355
|
-
responseText += `\n⚠️ **Large content confirmed** - Returning ${estimatedTokens.toLocaleString()} tokens\n\n`;
|
|
1356
|
-
}
|
|
1357
|
-
let resultData = {
|
|
1358
|
-
id: content.id,
|
|
1359
|
-
title: content.title,
|
|
1360
|
-
contentType: content.contentType,
|
|
1361
|
-
totalTokens: estimatedTokens,
|
|
1362
|
-
format: params.format,
|
|
1363
|
-
};
|
|
1364
|
-
if (params.format === "full") {
|
|
1365
|
-
// Return full text (with confirmation)
|
|
1366
|
-
responseText += `\n## Full Text Content\n`;
|
|
1367
|
-
responseText += `*Complete raw text (${estimatedTokens.toLocaleString()} tokens) is available in the data field.*\n`;
|
|
1368
|
-
resultData.text = content.rawText;
|
|
1369
|
-
resultData.metadata = params.includeMetadata ? {
|
|
1370
|
-
wordCount,
|
|
1371
|
-
estimatedTokens,
|
|
1372
|
-
contentType: content.contentType,
|
|
1373
|
-
extractedAt: content.createdAt,
|
|
1374
|
-
} : undefined;
|
|
1375
|
-
}
|
|
1376
|
-
else if (params.format === "chunks") {
|
|
1377
|
-
// Smart chunking based on token size
|
|
1378
|
-
const chunks = chunkContent(content.rawText || "", params.chunkSize, params.maxTokens);
|
|
1379
|
-
responseText += `\n## Content Chunks\n`;
|
|
1380
|
-
responseText += `**Total Chunks:** ${chunks.length}\n`;
|
|
1381
|
-
responseText += `**Chunk Size:** ~${params.chunkSize} tokens each\n`;
|
|
1382
|
-
if (chunks.length * params.chunkSize > params.maxTokens) {
|
|
1383
|
-
responseText += `**Note:** Showing first ${chunks.length} chunks (limited by maxTokens: ${params.maxTokens})\n`;
|
|
1384
|
-
}
|
|
1385
|
-
responseText += `\n`;
|
|
1386
|
-
// Show chunk previews
|
|
1387
|
-
chunks.slice(0, 3).forEach((chunk, idx) => {
|
|
1388
|
-
responseText += `### Chunk ${idx + 1}/${chunks.length}\n`;
|
|
1389
|
-
responseText += `**Tokens:** ~${chunk.tokenCount}\n`;
|
|
1390
|
-
responseText += `**Preview:** ${chunk.text.slice(0, 200)}...\n\n`;
|
|
1391
|
-
});
|
|
1392
|
-
if (chunks.length > 3) {
|
|
1393
|
-
responseText += `*... and ${chunks.length - 3} more chunks*\n\n`;
|
|
1394
|
-
}
|
|
1395
|
-
responseText += `💡 **Tip:** To get a specific chunk, note the chunk index and request it directly.\n`;
|
|
1396
|
-
resultData.chunks = chunks;
|
|
1397
|
-
resultData.totalChunks = chunks.length;
|
|
1398
|
-
}
|
|
1399
|
-
else if (params.format === "sections") {
|
|
1400
|
-
// Logical section detection (headers, paragraphs, etc.)
|
|
1401
|
-
const sections = detectSections(content.rawText || "", content.contentType);
|
|
1402
|
-
responseText += `\n## Content Sections\n`;
|
|
1403
|
-
responseText += `**Total Sections:** ${sections.length}\n\n`;
|
|
1404
|
-
// Show section outline
|
|
1405
|
-
let totalSectionTokens = 0;
|
|
1406
|
-
sections.forEach((section, idx) => {
|
|
1407
|
-
responseText += `${idx + 1}. **${section.title || `Section ${idx + 1}`}**`;
|
|
1408
|
-
if (section.type) {
|
|
1409
|
-
responseText += ` (${section.type})`;
|
|
1410
|
-
}
|
|
1411
|
-
responseText += ` - ~${section.tokenCount} tokens\n`;
|
|
1412
|
-
totalSectionTokens += section.tokenCount;
|
|
1413
|
-
if (totalSectionTokens > params.maxTokens) {
|
|
1414
|
-
responseText += ` *[Exceeds maxTokens limit]*\n`;
|
|
1415
|
-
}
|
|
1416
|
-
});
|
|
1417
|
-
responseText += `\n*Full section content available in data field*\n`;
|
|
1418
|
-
resultData.sections = sections;
|
|
1419
|
-
resultData.totalSections = sections.length;
|
|
1420
|
-
}
|
|
1421
|
-
return {
|
|
1422
|
-
content: [
|
|
1423
|
-
{
|
|
1424
|
-
type: "text",
|
|
1425
|
-
text: responseText,
|
|
1426
|
-
},
|
|
1427
|
-
],
|
|
1428
|
-
data: resultData,
|
|
1429
|
-
};
|
|
1430
|
-
},
|
|
1431
|
-
},
|
|
1432
|
-
{
|
|
1433
|
-
name: "explore_topic",
|
|
1434
|
-
description: "Deep exploration of a topic across all saved content. Provides comprehensive understanding with multiple perspectives, evolution over time, and key concepts.",
|
|
1435
|
-
inputSchema: {
|
|
1436
|
-
type: "object",
|
|
1437
|
-
properties: {
|
|
1438
|
-
topic: {
|
|
1439
|
-
type: "string",
|
|
1440
|
-
description: "The topic to explore comprehensively",
|
|
1441
|
-
},
|
|
1442
|
-
depth: {
|
|
1443
|
-
type: "string",
|
|
1444
|
-
enum: ["surface", "comprehensive", "expert"],
|
|
1445
|
-
description: "Depth of exploration",
|
|
1446
|
-
default: "comprehensive",
|
|
1447
|
-
},
|
|
1448
|
-
includeTimeline: {
|
|
1449
|
-
type: "boolean",
|
|
1450
|
-
description: "Include chronological evolution of the topic",
|
|
1451
|
-
default: true,
|
|
1452
|
-
},
|
|
1453
|
-
includeConnections: {
|
|
1454
|
-
type: "boolean",
|
|
1455
|
-
description: "Find connections to related topics",
|
|
1456
|
-
default: true,
|
|
1457
|
-
},
|
|
1458
|
-
maxSources: {
|
|
1459
|
-
type: "number",
|
|
1460
|
-
description: "Maximum number of sources to analyze",
|
|
1461
|
-
default: 20,
|
|
1462
|
-
},
|
|
1463
|
-
},
|
|
1464
|
-
required: ["topic"],
|
|
1465
|
-
},
|
|
1466
|
-
modifies: false,
|
|
1467
|
-
handler: async (client, args) => {
|
|
1468
|
-
const schema = z.object({
|
|
1469
|
-
topic: z.string(),
|
|
1470
|
-
depth: z.enum(["surface", "comprehensive", "expert"]).optional().default("comprehensive"),
|
|
1471
|
-
includeTimeline: z.boolean().optional().default(true),
|
|
1472
|
-
includeConnections: z.boolean().optional().default(true),
|
|
1473
|
-
maxSources: z.number().optional().default(20),
|
|
1474
|
-
});
|
|
1475
|
-
const params = schema.parse(args);
|
|
1476
|
-
// Search for all content related to the topic
|
|
1477
|
-
const searchResults = await client.searchContent(params.topic, {
|
|
1478
|
-
limit: params.maxSources,
|
|
1479
|
-
enableConceptExpansion: true,
|
|
1480
|
-
fuzzyMatch: true,
|
|
1481
|
-
});
|
|
1482
|
-
if (!searchResults || searchResults.length === 0) {
|
|
1483
|
-
return {
|
|
1484
|
-
content: [
|
|
1485
|
-
{
|
|
1486
|
-
type: "text",
|
|
1487
|
-
text: `No content found for topic: "${params.topic}". Try saving relevant content first or use a different search term.`,
|
|
1488
|
-
},
|
|
1489
|
-
],
|
|
1490
|
-
data: null,
|
|
1491
|
-
};
|
|
1492
|
-
}
|
|
1493
|
-
// Synthesize the content for deep understanding
|
|
1494
|
-
const synthesis = await client.synthesizeContent({
|
|
1495
|
-
query: `Comprehensive exploration of ${params.topic}`,
|
|
1496
|
-
contentIds: searchResults.slice(0, params.maxSources).map((r) => r.id),
|
|
1497
|
-
synthesisMode: params.depth === "expert" ? "deep" : params.depth === "surface" ? "overview" : "actionable",
|
|
1498
|
-
findConnections: params.includeConnections,
|
|
1499
|
-
findContradictions: true,
|
|
1500
|
-
});
|
|
1501
|
-
let responseText = `# 🔍 Topic Exploration: "${params.topic}"\n`;
|
|
1502
|
-
responseText += `**Depth:** ${params.depth} | **Sources Analyzed:** ${searchResults.length}\n\n`;
|
|
1503
|
-
// Overview Section
|
|
1504
|
-
responseText += `## 📋 Overview\n`;
|
|
1505
|
-
if (synthesis.synthesis?.summary) {
|
|
1506
|
-
responseText += `${synthesis.synthesis.summary}\n\n`;
|
|
1507
|
-
}
|
|
1508
|
-
else {
|
|
1509
|
-
responseText += `Analysis of ${searchResults.length} pieces of content about ${params.topic}.\n\n`;
|
|
1510
|
-
}
|
|
1511
|
-
// Key Concepts
|
|
1512
|
-
responseText += `## 🎯 Key Concepts\n`;
|
|
1513
|
-
const concepts = extractKeyConceptsFromSearch(searchResults, params.topic);
|
|
1514
|
-
concepts.slice(0, 10).forEach((concept, idx) => {
|
|
1515
|
-
responseText += `${idx + 1}. ${concept}\n`;
|
|
1516
|
-
});
|
|
1517
|
-
responseText += `\n`;
|
|
1518
|
-
// Multiple Perspectives
|
|
1519
|
-
responseText += `## 👥 Different Perspectives\n`;
|
|
1520
|
-
const perspectives = groupByPerspective(searchResults);
|
|
1521
|
-
Object.entries(perspectives).slice(0, 5).forEach(([perspective, items]) => {
|
|
1522
|
-
responseText += `\n### ${perspective}\n`;
|
|
1523
|
-
responseText += `*Found in ${items.length} sources*\n`;
|
|
1524
|
-
if (items[0]?.summary) {
|
|
1525
|
-
const summary = typeof items[0].summary === 'string' ? items[0].summary : items[0].summary.one_sentence;
|
|
1526
|
-
responseText += `Example: "${summary?.slice(0, 200)}..."\n`;
|
|
1527
|
-
}
|
|
1528
|
-
});
|
|
1529
|
-
responseText += `\n`;
|
|
1530
|
-
// Timeline (if requested)
|
|
1531
|
-
if (params.includeTimeline && searchResults.length > 1) {
|
|
1532
|
-
responseText += `## ⏱️ Topic Evolution\n`;
|
|
1533
|
-
const timeline = createTopicTimeline(searchResults);
|
|
1534
|
-
timeline.forEach((event) => {
|
|
1535
|
-
responseText += `- **${event.date}:** ${event.title} - ${event.insight}\n`;
|
|
1536
|
-
});
|
|
1537
|
-
responseText += `\n`;
|
|
1538
|
-
}
|
|
1539
|
-
// Connections (if found)
|
|
1540
|
-
if (params.includeConnections && synthesis.synthesis?.connections) {
|
|
1541
|
-
responseText += `## 🔗 Related Topics & Connections\n`;
|
|
1542
|
-
synthesis.synthesis.connections.slice(0, 8).forEach((conn) => {
|
|
1543
|
-
if (typeof conn === 'string') {
|
|
1544
|
-
responseText += `- ${conn}\n`;
|
|
1545
|
-
}
|
|
1546
|
-
else if (conn.concept) {
|
|
1547
|
-
responseText += `- **${conn.concept}**`;
|
|
1548
|
-
if (conn.strength) {
|
|
1549
|
-
responseText += ` (strength: ${conn.strength})`;
|
|
1550
|
-
}
|
|
1551
|
-
responseText += `\n`;
|
|
1552
|
-
}
|
|
1553
|
-
});
|
|
1554
|
-
responseText += `\n`;
|
|
1555
|
-
}
|
|
1556
|
-
// Contradictions & Debates
|
|
1557
|
-
if (synthesis.synthesis?.contradictions && synthesis.synthesis.contradictions.length > 0) {
|
|
1558
|
-
responseText += `## ⚡ Contradictions & Debates\n`;
|
|
1559
|
-
synthesis.synthesis.contradictions.slice(0, 3).forEach((contra) => {
|
|
1560
|
-
responseText += `\n**Point of Contention:**\n`;
|
|
1561
|
-
if (contra.topic) {
|
|
1562
|
-
responseText += `${contra.topic}\n`;
|
|
1563
|
-
}
|
|
1564
|
-
if (contra.viewpoints) {
|
|
1565
|
-
contra.viewpoints.forEach((vp) => {
|
|
1566
|
-
responseText += `- ${vp.position}: ${vp.argument}\n`;
|
|
1567
|
-
});
|
|
1568
|
-
}
|
|
1569
|
-
});
|
|
1570
|
-
responseText += `\n`;
|
|
1571
|
-
}
|
|
1572
|
-
// Learning Path (for comprehensive/expert depth)
|
|
1573
|
-
if (params.depth !== "surface") {
|
|
1574
|
-
responseText += `## 📚 Suggested Learning Path\n`;
|
|
1575
|
-
const learningPath = createLearningPath(searchResults, params.topic);
|
|
1576
|
-
learningPath.forEach((step, idx) => {
|
|
1577
|
-
responseText += `${idx + 1}. **${step.title}** - ${step.reason}\n`;
|
|
1578
|
-
});
|
|
1579
|
-
responseText += `\n`;
|
|
1580
|
-
}
|
|
1581
|
-
// Expert Insights (for expert depth)
|
|
1582
|
-
if (params.depth === "expert" && synthesis.synthesis?.insights) {
|
|
1583
|
-
responseText += `## 💡 Expert-Level Insights\n`;
|
|
1584
|
-
synthesis.synthesis.insights.slice(0, 5).forEach((insight, idx) => {
|
|
1585
|
-
const text = typeof insight === 'string' ? insight : insight.text;
|
|
1586
|
-
responseText += `${idx + 1}. ${text}\n`;
|
|
1587
|
-
});
|
|
1588
|
-
responseText += `\n`;
|
|
1589
|
-
}
|
|
1590
|
-
// Sources
|
|
1591
|
-
responseText += `## 📚 Top Sources\n`;
|
|
1592
|
-
searchResults.slice(0, 5).forEach((source, idx) => {
|
|
1593
|
-
const typeIcons = {
|
|
1594
|
-
youtube: "📺",
|
|
1595
|
-
x_twitter: "𝕏",
|
|
1596
|
-
reddit: "🔗",
|
|
1597
|
-
article: "📄",
|
|
1598
|
-
pdf: "📑"
|
|
1599
|
-
};
|
|
1600
|
-
const icon = typeIcons[source.contentType] || "📄";
|
|
1601
|
-
responseText += `${idx + 1}. ${icon} [${source.title || "Untitled"}](${source.url})\n`;
|
|
1602
|
-
});
|
|
1603
|
-
return {
|
|
1604
|
-
content: [
|
|
1605
|
-
{
|
|
1606
|
-
type: "text",
|
|
1607
|
-
text: responseText,
|
|
1608
|
-
},
|
|
1609
|
-
],
|
|
1610
|
-
data: {
|
|
1611
|
-
topic: params.topic,
|
|
1612
|
-
depth: params.depth,
|
|
1613
|
-
sourcesAnalyzed: searchResults.length,
|
|
1614
|
-
synthesis: synthesis.synthesis,
|
|
1615
|
-
sources: searchResults,
|
|
1616
|
-
concepts,
|
|
1617
|
-
perspectives,
|
|
1618
|
-
},
|
|
1619
|
-
};
|
|
1620
|
-
},
|
|
1621
|
-
},
|
|
1622
|
-
{
|
|
1623
|
-
name: "find_connections",
|
|
1624
|
-
description: "Discover connections and relationships between different pieces of content. Identifies causal links, contradictions, and complementary information.",
|
|
1625
|
-
inputSchema: {
|
|
1626
|
-
type: "object",
|
|
1627
|
-
properties: {
|
|
1628
|
-
contentIds: {
|
|
1629
|
-
type: "array",
|
|
1630
|
-
items: {
|
|
1631
|
-
type: "string",
|
|
1632
|
-
},
|
|
1633
|
-
description: "Array of content IDs to find connections between",
|
|
1634
|
-
},
|
|
1635
|
-
connectionType: {
|
|
1636
|
-
type: "string",
|
|
1637
|
-
enum: ["all", "causal", "contradictory", "complementary", "sequential"],
|
|
1638
|
-
description: "Type of connections to find",
|
|
1639
|
-
default: "all",
|
|
1640
|
-
},
|
|
1641
|
-
depth: {
|
|
1642
|
-
type: "number",
|
|
1643
|
-
description: "How many levels deep to search for connections (1-3)",
|
|
1644
|
-
default: 1,
|
|
1645
|
-
},
|
|
1646
|
-
},
|
|
1647
|
-
required: ["contentIds"],
|
|
1648
|
-
},
|
|
1649
|
-
modifies: false,
|
|
1650
|
-
handler: async (client, args) => {
|
|
1651
|
-
const schema = z.object({
|
|
1652
|
-
contentIds: z.array(z.string()).min(2),
|
|
1653
|
-
connectionType: z.enum(["all", "causal", "contradictory", "complementary", "sequential"]).optional().default("all"),
|
|
1654
|
-
depth: z.number().min(1).max(3).optional().default(1),
|
|
1655
|
-
});
|
|
1656
|
-
const params = schema.parse(args);
|
|
1657
|
-
// Fetch all content items
|
|
1658
|
-
const contents = await client.batchGetContent(params.contentIds, false);
|
|
1659
|
-
if (!contents.results || contents.results.length < 2) {
|
|
1660
|
-
return {
|
|
1661
|
-
content: [
|
|
1662
|
-
{
|
|
1663
|
-
type: "text",
|
|
1664
|
-
text: "Unable to find connections. Need at least 2 valid content items.",
|
|
1665
|
-
},
|
|
1666
|
-
],
|
|
1667
|
-
data: null,
|
|
1668
|
-
};
|
|
1669
|
-
}
|
|
1670
|
-
// Analyze connections between content
|
|
1671
|
-
const connections = analyzeConnections(contents.results, params.connectionType);
|
|
1672
|
-
let responseText = `# 🔗 Content Connections Analysis\n`;
|
|
1673
|
-
responseText += `**Analyzing:** ${contents.results.length} pieces of content\n`;
|
|
1674
|
-
responseText += `**Connection Type:** ${params.connectionType}\n`;
|
|
1675
|
-
responseText += `**Connections Found:** ${connections.length}\n\n`;
|
|
1676
|
-
if (connections.length === 0) {
|
|
1677
|
-
responseText += `No ${params.connectionType} connections found between the provided content.\n`;
|
|
1678
|
-
responseText += `Try using connectionType='all' for broader analysis.\n`;
|
|
1679
|
-
}
|
|
1680
|
-
else {
|
|
1681
|
-
// Group connections by type
|
|
1682
|
-
const byType = groupConnectionsByType(connections);
|
|
1683
|
-
Object.entries(byType).forEach(([type, conns]) => {
|
|
1684
|
-
responseText += `## ${getConnectionTypeEmoji(type)} ${type} Connections (${conns.length})\n\n`;
|
|
1685
|
-
conns.slice(0, 5).forEach((conn) => {
|
|
1686
|
-
responseText += `### ${conn.source1.title} ↔️ ${conn.source2.title}\n`;
|
|
1687
|
-
responseText += `**Relationship:** ${conn.relationship}\n`;
|
|
1688
|
-
responseText += `**Strength:** ${getStrengthIndicator(conn.strength)}\n`;
|
|
1689
|
-
if (conn.explanation) {
|
|
1690
|
-
responseText += `**Why:** ${conn.explanation}\n`;
|
|
1691
|
-
}
|
|
1692
|
-
if (conn.sharedConcepts && conn.sharedConcepts.length > 0) {
|
|
1693
|
-
responseText += `**Shared Concepts:** ${conn.sharedConcepts.join(', ')}\n`;
|
|
1694
|
-
}
|
|
1695
|
-
responseText += `\n`;
|
|
1696
|
-
});
|
|
1697
|
-
});
|
|
1698
|
-
// Network summary
|
|
1699
|
-
responseText += `## 🌐 Connection Network Summary\n`;
|
|
1700
|
-
const networkStats = calculateNetworkStats(connections, contents.results);
|
|
1701
|
-
responseText += `- **Most Connected:** ${networkStats.mostConnected.title} (${networkStats.mostConnected.connectionCount} connections)\n`;
|
|
1702
|
-
responseText += `- **Central Theme:** ${networkStats.centralTheme}\n`;
|
|
1703
|
-
responseText += `- **Network Density:** ${networkStats.density}\n`;
|
|
1704
|
-
if (params.depth > 1) {
|
|
1705
|
-
responseText += `\n## 🔍 Extended Connections (Depth ${params.depth})\n`;
|
|
1706
|
-
responseText += `*Searching for indirect connections through related content...*\n`;
|
|
1707
|
-
// This would require additional searches for related content
|
|
1708
|
-
responseText += `Use find_similar_content on highly connected items to explore further.\n`;
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
return {
|
|
1712
|
-
content: [
|
|
1713
|
-
{
|
|
1714
|
-
type: "text",
|
|
1715
|
-
text: responseText,
|
|
1716
|
-
},
|
|
1717
|
-
],
|
|
1718
|
-
data: {
|
|
1719
|
-
connections,
|
|
1720
|
-
contents: contents.results,
|
|
1721
|
-
networkStats: connections.length > 0 ? calculateNetworkStats(connections, contents.results) : null,
|
|
1722
|
-
},
|
|
1723
|
-
};
|
|
1724
|
-
},
|
|
1725
|
-
},
|
|
1726
|
-
{
|
|
1727
|
-
name: "extract_insights",
|
|
1728
|
-
description: "Extract specific types of insights across multiple content sources. Finds patterns, contradictions, consensus, or evolution of ideas.",
|
|
1729
|
-
inputSchema: {
|
|
1730
|
-
type: "object",
|
|
1731
|
-
properties: {
|
|
1732
|
-
query: {
|
|
1733
|
-
type: "string",
|
|
1734
|
-
description: "What insights to extract (e.g., 'productivity tips', 'AI risks', 'investment strategies')",
|
|
1735
|
-
},
|
|
1736
|
-
insightType: {
|
|
1737
|
-
type: "string",
|
|
1738
|
-
enum: ["patterns", "contradictions", "consensus", "evolution", "actionable", "warnings"],
|
|
1739
|
-
description: "Type of insights to extract",
|
|
1740
|
-
default: "patterns",
|
|
1741
|
-
},
|
|
1742
|
-
maxSources: {
|
|
1743
|
-
type: "number",
|
|
1744
|
-
description: "Maximum number of sources to analyze",
|
|
1745
|
-
default: 15,
|
|
1746
|
-
},
|
|
1747
|
-
minConfidence: {
|
|
1748
|
-
type: "number",
|
|
1749
|
-
description: "Minimum confidence score for insights (0-1)",
|
|
1750
|
-
default: 0.7,
|
|
1751
|
-
},
|
|
1752
|
-
},
|
|
1753
|
-
required: ["query"],
|
|
1754
|
-
},
|
|
1755
|
-
modifies: false,
|
|
1756
|
-
handler: async (client, args) => {
|
|
1757
|
-
const schema = z.object({
|
|
1758
|
-
query: z.string(),
|
|
1759
|
-
insightType: z.enum(["patterns", "contradictions", "consensus", "evolution", "actionable", "warnings"]).optional().default("patterns"),
|
|
1760
|
-
maxSources: z.number().optional().default(15),
|
|
1761
|
-
minConfidence: z.number().min(0).max(1).optional().default(0.7),
|
|
1762
|
-
});
|
|
1763
|
-
const params = schema.parse(args);
|
|
1764
|
-
// Search for relevant content
|
|
1765
|
-
const searchResults = await client.searchContent(params.query, {
|
|
1766
|
-
limit: params.maxSources,
|
|
1767
|
-
enableConceptExpansion: true,
|
|
1768
|
-
});
|
|
1769
|
-
if (!searchResults || searchResults.length === 0) {
|
|
1770
|
-
return {
|
|
1771
|
-
content: [
|
|
1772
|
-
{
|
|
1773
|
-
type: "text",
|
|
1774
|
-
text: `No content found for extracting insights about: "${params.query}"`,
|
|
1775
|
-
},
|
|
1776
|
-
],
|
|
1777
|
-
data: null,
|
|
1778
|
-
};
|
|
1779
|
-
}
|
|
1780
|
-
// Extract insights based on type
|
|
1781
|
-
const insights = extractTypedInsights(searchResults, params.query, params.insightType, params.minConfidence);
|
|
1782
|
-
let responseText = `# 💡 Insight Extraction: "${params.query}"\n`;
|
|
1783
|
-
responseText += `**Type:** ${params.insightType} | **Sources:** ${searchResults.length} | **Min Confidence:** ${(params.minConfidence * 100).toFixed(0)}%\n\n`;
|
|
1784
|
-
if (insights.length === 0) {
|
|
1785
|
-
responseText += `No ${params.insightType} insights found with confidence >= ${params.minConfidence}.\n`;
|
|
1786
|
-
responseText += `Try lowering the confidence threshold or using a different insight type.\n`;
|
|
1787
|
-
}
|
|
1788
|
-
else {
|
|
1789
|
-
// Display insights by type
|
|
1790
|
-
switch (params.insightType) {
|
|
1791
|
-
case "patterns":
|
|
1792
|
-
responseText += `## 🔄 Recurring Patterns\n\n`;
|
|
1793
|
-
insights.forEach((insight, idx) => {
|
|
1794
|
-
responseText += `### Pattern ${idx + 1}: ${insight.pattern}\n`;
|
|
1795
|
-
responseText += `**Frequency:** Appears in ${insight.frequency}/${searchResults.length} sources\n`;
|
|
1796
|
-
responseText += `**Confidence:** ${(insight.confidence * 100).toFixed(0)}%\n`;
|
|
1797
|
-
responseText += `**Examples:**\n`;
|
|
1798
|
-
insight.examples.slice(0, 3).forEach((ex) => {
|
|
1799
|
-
responseText += `- "${ex.text}" *(${ex.source})*\n`;
|
|
1800
|
-
});
|
|
1801
|
-
responseText += `\n`;
|
|
1802
|
-
});
|
|
1803
|
-
break;
|
|
1804
|
-
case "contradictions":
|
|
1805
|
-
responseText += `## ⚡ Contradictions & Disagreements\n\n`;
|
|
1806
|
-
insights.forEach((insight, idx) => {
|
|
1807
|
-
responseText += `### Contradiction ${idx + 1}: ${insight.topic}\n`;
|
|
1808
|
-
responseText += `**Position A:** "${insight.position1.statement}"\n`;
|
|
1809
|
-
responseText += `*Sources:* ${insight.position1.sources.join(', ')}\n\n`;
|
|
1810
|
-
responseText += `**Position B:** "${insight.position2.statement}"\n`;
|
|
1811
|
-
responseText += `*Sources:* ${insight.position2.sources.join(', ')}\n`;
|
|
1812
|
-
if (insight.resolution) {
|
|
1813
|
-
responseText += `\n**Possible Resolution:** ${insight.resolution}\n`;
|
|
1814
|
-
}
|
|
1815
|
-
responseText += `\n`;
|
|
1816
|
-
});
|
|
1817
|
-
break;
|
|
1818
|
-
case "consensus":
|
|
1819
|
-
responseText += `## ✅ Points of Consensus\n\n`;
|
|
1820
|
-
insights.forEach((insight, idx) => {
|
|
1821
|
-
responseText += `${idx + 1}. **${insight.point}**\n`;
|
|
1822
|
-
responseText += ` - Agreement: ${insight.agreementLevel}% of sources\n`;
|
|
1823
|
-
responseText += ` - Confidence: ${(insight.confidence * 100).toFixed(0)}%\n`;
|
|
1824
|
-
if (insight.nuances && insight.nuances.length > 0) {
|
|
1825
|
-
responseText += ` - Nuances: ${insight.nuances.join('; ')}\n`;
|
|
1826
|
-
}
|
|
1827
|
-
});
|
|
1828
|
-
responseText += `\n`;
|
|
1829
|
-
break;
|
|
1830
|
-
case "evolution":
|
|
1831
|
-
responseText += `## 📈 Evolution of Ideas\n\n`;
|
|
1832
|
-
insights.forEach((insight, idx) => {
|
|
1833
|
-
responseText += `### ${insight.concept}\n`;
|
|
1834
|
-
responseText += `**Timeline:**\n`;
|
|
1835
|
-
insight.timeline.forEach((point) => {
|
|
1836
|
-
responseText += `- **${point.date}:** ${point.understanding}\n`;
|
|
1837
|
-
});
|
|
1838
|
-
responseText += `**Current State:** ${insight.currentState}\n`;
|
|
1839
|
-
responseText += `**Trend:** ${insight.trend}\n\n`;
|
|
1840
|
-
});
|
|
1841
|
-
break;
|
|
1842
|
-
case "actionable":
|
|
1843
|
-
responseText += `## 🎯 Actionable Insights\n\n`;
|
|
1844
|
-
insights.forEach((insight, idx) => {
|
|
1845
|
-
responseText += `### ${idx + 1}. ${insight.action}\n`;
|
|
1846
|
-
responseText += `**Why:** ${insight.reasoning}\n`;
|
|
1847
|
-
responseText += `**Priority:** ${insight.priority}\n`;
|
|
1848
|
-
responseText += `**Evidence from:** ${insight.sources.length} sources\n`;
|
|
1849
|
-
if (insight.steps && insight.steps.length > 0) {
|
|
1850
|
-
responseText += `**Steps:**\n`;
|
|
1851
|
-
insight.steps.forEach((step, i) => {
|
|
1852
|
-
responseText += `${i + 1}. ${step}\n`;
|
|
1853
|
-
});
|
|
1854
|
-
}
|
|
1855
|
-
responseText += `\n`;
|
|
1856
|
-
});
|
|
1857
|
-
break;
|
|
1858
|
-
case "warnings":
|
|
1859
|
-
responseText += `## ⚠️ Warnings & Risks\n\n`;
|
|
1860
|
-
insights.forEach((insight, idx) => {
|
|
1861
|
-
const severityEmoji = insight.severity === "high" ? "🔴" : insight.severity === "medium" ? "🟡" : "🟢";
|
|
1862
|
-
responseText += `### ${severityEmoji} ${insight.warning}\n`;
|
|
1863
|
-
responseText += `**Severity:** ${insight.severity}\n`;
|
|
1864
|
-
responseText += `**Mentioned in:** ${insight.sources.length} sources\n`;
|
|
1865
|
-
responseText += `**Context:** ${insight.context}\n`;
|
|
1866
|
-
if (insight.mitigation) {
|
|
1867
|
-
responseText += `**Mitigation:** ${insight.mitigation}\n`;
|
|
1868
|
-
}
|
|
1869
|
-
responseText += `\n`;
|
|
1870
|
-
});
|
|
1871
|
-
break;
|
|
1872
|
-
}
|
|
1873
|
-
// Summary statistics
|
|
1874
|
-
responseText += `## 📊 Extraction Summary\n`;
|
|
1875
|
-
responseText += `- **Total Insights:** ${insights.length}\n`;
|
|
1876
|
-
responseText += `- **Average Confidence:** ${(insights.reduce((sum, i) => sum + i.confidence, 0) / insights.length * 100).toFixed(0)}%\n`;
|
|
1877
|
-
responseText += `- **Sources Analyzed:** ${searchResults.length}\n`;
|
|
1878
|
-
const contributingSources = new Set(insights.flatMap((i) => i.sources || []));
|
|
1879
|
-
responseText += `- **Contributing Sources:** ${contributingSources.size}\n`;
|
|
1880
|
-
}
|
|
1881
|
-
return {
|
|
1882
|
-
content: [
|
|
1883
|
-
{
|
|
1884
|
-
type: "text",
|
|
1885
|
-
text: responseText,
|
|
1886
|
-
},
|
|
1887
|
-
],
|
|
1888
|
-
data: {
|
|
1889
|
-
query: params.query,
|
|
1890
|
-
insightType: params.insightType,
|
|
1891
|
-
insights,
|
|
1892
|
-
sources: searchResults,
|
|
1893
|
-
},
|
|
1894
|
-
};
|
|
1895
|
-
},
|
|
1896
|
-
},
|
|
1897
|
-
];
|
|
1898
|
-
// Helper functions for the new tools
|
|
1899
|
-
function chunkContent(text, targetTokenSize, maxTokens) {
|
|
1900
|
-
const words = text.split(/\s+/);
|
|
1901
|
-
const wordsPerChunk = Math.floor(targetTokenSize / 1.3); // Rough token estimation
|
|
1902
|
-
const chunks = [];
|
|
1903
|
-
let totalTokens = 0;
|
|
1904
|
-
for (let i = 0; i < words.length; i += wordsPerChunk) {
|
|
1905
|
-
const chunkWords = words.slice(i, i + wordsPerChunk);
|
|
1906
|
-
const chunkText = chunkWords.join(' ');
|
|
1907
|
-
const chunkTokens = Math.ceil(chunkWords.length * 1.3);
|
|
1908
|
-
// Stop if we've reached the max token limit
|
|
1909
|
-
if (maxTokens && totalTokens + chunkTokens > maxTokens) {
|
|
1910
|
-
break;
|
|
1911
|
-
}
|
|
1912
|
-
chunks.push({
|
|
1913
|
-
index: chunks.length,
|
|
1914
|
-
text: chunkText,
|
|
1915
|
-
tokenCount: chunkTokens,
|
|
1916
|
-
startOffset: i,
|
|
1917
|
-
endOffset: Math.min(i + wordsPerChunk, words.length),
|
|
1918
|
-
});
|
|
1919
|
-
totalTokens += chunkTokens;
|
|
1920
|
-
}
|
|
1921
|
-
return chunks;
|
|
1922
|
-
}
|
|
1923
|
-
function detectSections(text, contentType) {
|
|
1924
|
-
const sections = [];
|
|
1925
|
-
// Simple section detection based on headers and paragraphs
|
|
1926
|
-
const lines = text.split('\n');
|
|
1927
|
-
let currentSection = { title: "Introduction", text: "", type: "intro", tokenCount: 0 };
|
|
1928
|
-
for (const line of lines) {
|
|
1929
|
-
// Detect headers (various formats)
|
|
1930
|
-
if (line.match(/^#{1,6}\s+/) || line.match(/^[A-Z][^.!?]*:$/) || (line.length < 100 && line.match(/^[A-Z]/))) {
|
|
1931
|
-
if (currentSection.text) {
|
|
1932
|
-
currentSection.tokenCount = Math.ceil(currentSection.text.split(/\s+/).length * 1.3);
|
|
1933
|
-
sections.push(currentSection);
|
|
1934
|
-
}
|
|
1935
|
-
currentSection = {
|
|
1936
|
-
title: line.replace(/^#+\s+/, '').replace(/:$/, ''),
|
|
1937
|
-
text: "",
|
|
1938
|
-
type: "section",
|
|
1939
|
-
tokenCount: 0,
|
|
1940
|
-
};
|
|
1941
|
-
}
|
|
1942
|
-
else {
|
|
1943
|
-
currentSection.text += line + "\n";
|
|
1944
|
-
}
|
|
1945
|
-
}
|
|
1946
|
-
// Add the last section
|
|
1947
|
-
if (currentSection.text) {
|
|
1948
|
-
currentSection.tokenCount = Math.ceil(currentSection.text.split(/\s+/).length * 1.3);
|
|
1949
|
-
sections.push(currentSection);
|
|
1950
|
-
}
|
|
1951
|
-
return sections;
|
|
1952
|
-
}
|
|
1953
|
-
function extractKeyConceptsFromSearch(results, topic) {
|
|
1954
|
-
const concepts = new Map();
|
|
1955
|
-
results.forEach(result => {
|
|
1956
|
-
// Extract from tags
|
|
1957
|
-
if (result.tags) {
|
|
1958
|
-
result.tags.forEach((tag) => {
|
|
1959
|
-
concepts.set(tag, (concepts.get(tag) || 0) + 2);
|
|
1960
|
-
});
|
|
1961
|
-
}
|
|
1962
|
-
// Extract from summary
|
|
1963
|
-
if (result.summary) {
|
|
1964
|
-
const summary = typeof result.summary === 'string' ? result.summary : result.summary.one_sentence;
|
|
1965
|
-
if (summary) {
|
|
1966
|
-
// Simple concept extraction from summary
|
|
1967
|
-
const words = summary.toLowerCase().split(/\s+/);
|
|
1968
|
-
const importantWords = words.filter((w) => w.length > 5 && !['about', 'through', 'between', 'during'].includes(w));
|
|
1969
|
-
importantWords.forEach((word) => {
|
|
1970
|
-
concepts.set(word, (concepts.get(word) || 0) + 1);
|
|
1971
|
-
});
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
});
|
|
1975
|
-
// Sort by frequency and return top concepts
|
|
1976
|
-
return Array.from(concepts.entries())
|
|
1977
|
-
.sort((a, b) => b[1] - a[1])
|
|
1978
|
-
.map(([concept]) => concept)
|
|
1979
|
-
.filter(concept => concept.toLowerCase() !== topic.toLowerCase());
|
|
1980
|
-
}
|
|
1981
|
-
function groupByPerspective(results) {
|
|
1982
|
-
const perspectives = {};
|
|
1983
|
-
results.forEach(result => {
|
|
1984
|
-
// Group by content type as a simple perspective grouping
|
|
1985
|
-
const perspective = result.contentType || 'general';
|
|
1986
|
-
if (!perspectives[perspective]) {
|
|
1987
|
-
perspectives[perspective] = [];
|
|
1988
|
-
}
|
|
1989
|
-
perspectives[perspective].push(result);
|
|
1990
|
-
});
|
|
1991
|
-
return perspectives;
|
|
1992
|
-
}
|
|
1993
|
-
function createTopicTimeline(results) {
|
|
1994
|
-
// Sort by date and create timeline
|
|
1995
|
-
const sorted = results
|
|
1996
|
-
.filter(r => r.createdAt)
|
|
1997
|
-
.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
1998
|
-
return sorted.slice(0, 5).map(result => ({
|
|
1999
|
-
date: new Date(result.createdAt).toLocaleDateString(),
|
|
2000
|
-
title: result.title || "Untitled",
|
|
2001
|
-
insight: typeof result.summary === 'string'
|
|
2002
|
-
? result.summary.slice(0, 100)
|
|
2003
|
-
: result.summary?.one_sentence?.slice(0, 100) || "No summary",
|
|
2004
|
-
}));
|
|
2005
|
-
}
|
|
2006
|
-
function createLearningPath(results, topic) {
|
|
2007
|
-
// Create a simple learning path based on content
|
|
2008
|
-
const path = [];
|
|
2009
|
-
// Find introductory content
|
|
2010
|
-
const intro = results.find(r => r.title?.toLowerCase().includes('introduction') ||
|
|
2011
|
-
r.title?.toLowerCase().includes('basics') ||
|
|
2012
|
-
r.title?.toLowerCase().includes('beginner'));
|
|
2013
|
-
if (intro) {
|
|
2014
|
-
path.push({
|
|
2015
|
-
title: intro.title || "Introduction",
|
|
2016
|
-
reason: "Start with foundational concepts",
|
|
2017
|
-
id: intro.id,
|
|
2018
|
-
});
|
|
2019
|
-
}
|
|
2020
|
-
// Add the most relevant content
|
|
2021
|
-
results
|
|
2022
|
-
.filter(r => r.id !== intro?.id)
|
|
2023
|
-
.slice(0, 3)
|
|
2024
|
-
.forEach(result => {
|
|
2025
|
-
path.push({
|
|
2026
|
-
title: result.title || "Untitled",
|
|
2027
|
-
reason: "Build on core concepts",
|
|
2028
|
-
id: result.id,
|
|
2029
|
-
});
|
|
2030
|
-
});
|
|
2031
|
-
return path;
|
|
2032
|
-
}
|
|
2033
|
-
function analyzeConnections(contents, connectionType) {
|
|
2034
|
-
const connections = [];
|
|
2035
|
-
// Analyze pairs of content
|
|
2036
|
-
for (let i = 0; i < contents.length; i++) {
|
|
2037
|
-
for (let j = i + 1; j < contents.length; j++) {
|
|
2038
|
-
const conn = findConnection(contents[i], contents[j], connectionType);
|
|
2039
|
-
if (conn) {
|
|
2040
|
-
connections.push(conn);
|
|
2041
|
-
}
|
|
2042
|
-
}
|
|
2043
|
-
}
|
|
2044
|
-
return connections;
|
|
2045
|
-
}
|
|
2046
|
-
function findConnection(content1, content2, type) {
|
|
2047
|
-
// Simple connection detection based on shared concepts
|
|
2048
|
-
const tags1 = new Set(content1.tags || []);
|
|
2049
|
-
const tags2 = new Set(content2.tags || []);
|
|
2050
|
-
const sharedTags = Array.from(tags1).filter(t => tags2.has(t));
|
|
2051
|
-
if (sharedTags.length === 0 && type !== "contradictory") {
|
|
2052
|
-
return null;
|
|
2053
|
-
}
|
|
2054
|
-
return {
|
|
2055
|
-
source1: { id: content1.id, title: content1.title || "Untitled" },
|
|
2056
|
-
source2: { id: content2.id, title: content2.title || "Untitled" },
|
|
2057
|
-
type: sharedTags.length > 2 ? "strong" : "weak",
|
|
2058
|
-
relationship: sharedTags.length > 0 ? "complementary" : "independent",
|
|
2059
|
-
strength: sharedTags.length / Math.max(tags1.size, tags2.size),
|
|
2060
|
-
sharedConcepts: sharedTags,
|
|
2061
|
-
explanation: `Share ${sharedTags.length} common concepts`,
|
|
2062
|
-
};
|
|
2063
|
-
}
|
|
2064
|
-
function groupConnectionsByType(connections) {
|
|
2065
|
-
const grouped = {};
|
|
2066
|
-
connections.forEach(conn => {
|
|
2067
|
-
const type = conn.relationship || "unknown";
|
|
2068
|
-
if (!grouped[type]) {
|
|
2069
|
-
grouped[type] = [];
|
|
2070
|
-
}
|
|
2071
|
-
grouped[type].push(conn);
|
|
2072
|
-
});
|
|
2073
|
-
return grouped;
|
|
2074
|
-
}
|
|
2075
|
-
function getConnectionTypeEmoji(type) {
|
|
2076
|
-
const emojis = {
|
|
2077
|
-
complementary: "🤝",
|
|
2078
|
-
contradictory: "⚡",
|
|
2079
|
-
causal: "➡️",
|
|
2080
|
-
sequential: "📅",
|
|
2081
|
-
independent: "🔀",
|
|
2082
|
-
};
|
|
2083
|
-
return emojis[type] || "🔗";
|
|
2084
|
-
}
|
|
2085
|
-
function getStrengthIndicator(strength) {
|
|
2086
|
-
if (strength > 0.8)
|
|
2087
|
-
return "🟢🟢🟢 Very Strong";
|
|
2088
|
-
if (strength > 0.6)
|
|
2089
|
-
return "🟢🟢 Strong";
|
|
2090
|
-
if (strength > 0.4)
|
|
2091
|
-
return "🟡 Moderate";
|
|
2092
|
-
if (strength > 0.2)
|
|
2093
|
-
return "🟠 Weak";
|
|
2094
|
-
return "🔴 Very Weak";
|
|
2095
|
-
}
|
|
2096
|
-
function calculateNetworkStats(connections, contents) {
|
|
2097
|
-
const connectionCounts = new Map();
|
|
2098
|
-
connections.forEach(conn => {
|
|
2099
|
-
const id1 = conn.source1.id;
|
|
2100
|
-
const id2 = conn.source2.id;
|
|
2101
|
-
connectionCounts.set(id1, (connectionCounts.get(id1) || 0) + 1);
|
|
2102
|
-
connectionCounts.set(id2, (connectionCounts.get(id2) || 0) + 1);
|
|
2103
|
-
});
|
|
2104
|
-
const mostConnectedId = Array.from(connectionCounts.entries())
|
|
2105
|
-
.sort((a, b) => b[1] - a[1])[0]?.[0];
|
|
2106
|
-
const mostConnected = contents.find(c => c.id === mostConnectedId) || contents[0];
|
|
2107
|
-
return {
|
|
2108
|
-
mostConnected: {
|
|
2109
|
-
title: mostConnected?.title || "Unknown",
|
|
2110
|
-
connectionCount: connectionCounts.get(mostConnectedId) || 0,
|
|
2111
|
-
},
|
|
2112
|
-
centralTheme: connections[0]?.sharedConcepts?.[0] || "Unknown",
|
|
2113
|
-
density: connections.length > 0 ? "High" : "Low",
|
|
2114
|
-
};
|
|
2115
|
-
}
|
|
2116
|
-
function extractTypedInsights(results, query, type, minConfidence) {
|
|
2117
|
-
// Simplified insight extraction
|
|
2118
|
-
const insights = [];
|
|
2119
|
-
switch (type) {
|
|
2120
|
-
case "patterns":
|
|
2121
|
-
// Find recurring themes
|
|
2122
|
-
const themes = new Map();
|
|
2123
|
-
results.forEach(result => {
|
|
2124
|
-
if (result.tags) {
|
|
2125
|
-
result.tags.forEach((tag) => {
|
|
2126
|
-
if (!themes.has(tag))
|
|
2127
|
-
themes.set(tag, []);
|
|
2128
|
-
themes.get(tag).push(result);
|
|
2129
|
-
});
|
|
2130
|
-
}
|
|
2131
|
-
});
|
|
2132
|
-
Array.from(themes.entries())
|
|
2133
|
-
.filter(([_, sources]) => sources.length >= 2)
|
|
2134
|
-
.forEach(([theme, sources]) => {
|
|
2135
|
-
insights.push({
|
|
2136
|
-
pattern: theme,
|
|
2137
|
-
frequency: sources.length,
|
|
2138
|
-
confidence: sources.length / results.length,
|
|
2139
|
-
examples: sources.slice(0, 3).map(s => ({
|
|
2140
|
-
text: s.title || "Untitled",
|
|
2141
|
-
source: s.contentType,
|
|
2142
|
-
})),
|
|
2143
|
-
});
|
|
2144
|
-
});
|
|
2145
|
-
break;
|
|
2146
|
-
case "actionable":
|
|
2147
|
-
// Extract actionable items from summaries
|
|
2148
|
-
results.forEach(result => {
|
|
2149
|
-
if (result.summary && typeof result.summary === 'object' && result.summary.actionable_takeaways) {
|
|
2150
|
-
result.summary.actionable_takeaways.forEach((action) => {
|
|
2151
|
-
insights.push({
|
|
2152
|
-
action,
|
|
2153
|
-
reasoning: "Extracted from content analysis",
|
|
2154
|
-
priority: "medium",
|
|
2155
|
-
sources: [result],
|
|
2156
|
-
confidence: 0.8,
|
|
2157
|
-
});
|
|
2158
|
-
});
|
|
2159
|
-
}
|
|
2160
|
-
});
|
|
2161
|
-
break;
|
|
2162
|
-
default:
|
|
2163
|
-
// Generic insight extraction
|
|
2164
|
-
results.slice(0, 5).forEach(result => {
|
|
2165
|
-
if (result.summary) {
|
|
2166
|
-
insights.push({
|
|
2167
|
-
text: typeof result.summary === 'string' ? result.summary : result.summary.one_sentence,
|
|
2168
|
-
source: result.title || "Untitled",
|
|
2169
|
-
confidence: 0.75,
|
|
2170
|
-
});
|
|
2171
|
-
}
|
|
2172
|
-
});
|
|
2173
|
-
}
|
|
2174
|
-
return insights.filter((i) => i.confidence >= minConfidence);
|
|
2175
|
-
}
|
|
2176
|
-
//# sourceMappingURL=index-old.js.map
|