@superatomai/sdk-node 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +942 -942
- package/dist/index.d.mts +30 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.js +549 -122
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +549 -122
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -445,6 +445,13 @@ var ComponentListResponseMessageSchema = z3.object({
|
|
|
445
445
|
type: z3.literal("COMPONENT_LIST_RES"),
|
|
446
446
|
payload: ComponentListResponsePayloadSchema
|
|
447
447
|
});
|
|
448
|
+
var ToolSchema = z3.object({
|
|
449
|
+
id: z3.string(),
|
|
450
|
+
name: z3.string(),
|
|
451
|
+
description: z3.string(),
|
|
452
|
+
params: z3.record(z3.string()),
|
|
453
|
+
fn: z3.function().args(z3.any()).returns(z3.any())
|
|
454
|
+
});
|
|
448
455
|
var UsersRequestPayloadSchema = z3.object({
|
|
449
456
|
operation: z3.enum(["create", "update", "delete", "getAll", "getOne"]),
|
|
450
457
|
data: z3.object({
|
|
@@ -515,6 +522,26 @@ var ReportsRequestMessageSchema = z3.object({
|
|
|
515
522
|
type: z3.literal("REPORTS"),
|
|
516
523
|
payload: ReportsRequestPayloadSchema
|
|
517
524
|
});
|
|
525
|
+
var BookmarkDataSchema = z3.object({
|
|
526
|
+
id: z3.number().optional(),
|
|
527
|
+
uiblock: z3.any(),
|
|
528
|
+
// JSON object
|
|
529
|
+
created_at: z3.string().optional(),
|
|
530
|
+
updated_at: z3.string().optional()
|
|
531
|
+
});
|
|
532
|
+
var BookmarksRequestPayloadSchema = z3.object({
|
|
533
|
+
operation: z3.enum(["create", "update", "delete", "getAll", "getOne"]),
|
|
534
|
+
data: z3.object({
|
|
535
|
+
id: z3.number().optional(),
|
|
536
|
+
uiblock: z3.any().optional()
|
|
537
|
+
}).optional()
|
|
538
|
+
});
|
|
539
|
+
var BookmarksRequestMessageSchema = z3.object({
|
|
540
|
+
id: z3.string(),
|
|
541
|
+
from: MessageParticipantSchema,
|
|
542
|
+
type: z3.literal("BOOKMARKS"),
|
|
543
|
+
payload: BookmarksRequestPayloadSchema
|
|
544
|
+
});
|
|
518
545
|
|
|
519
546
|
// src/utils/logger.ts
|
|
520
547
|
import fs from "fs";
|
|
@@ -972,6 +999,7 @@ var Thread = class {
|
|
|
972
999
|
let assistantResponse = "";
|
|
973
1000
|
const hasComponent = metadata && Object.keys(metadata).length > 0 && metadata.type;
|
|
974
1001
|
const hasTextResponse = textResponse && textResponse.trim().length > 0;
|
|
1002
|
+
const responseParts = [];
|
|
975
1003
|
if (hasComponent) {
|
|
976
1004
|
const parts = [];
|
|
977
1005
|
if (metadata.type) {
|
|
@@ -980,21 +1008,19 @@ var Thread = class {
|
|
|
980
1008
|
if (metadata.name) {
|
|
981
1009
|
parts.push(`Name: ${metadata.name}`);
|
|
982
1010
|
}
|
|
983
|
-
if (metadata.
|
|
984
|
-
parts.push(`
|
|
985
|
-
}
|
|
986
|
-
if (metadata.props?.query) {
|
|
987
|
-
const query = metadata.props.query;
|
|
988
|
-
const truncatedQuery = query.length > 200 ? query.substring(0, 200) + "..." : query;
|
|
989
|
-
parts.push(`Query: ${truncatedQuery}`);
|
|
1011
|
+
if (metadata.description) {
|
|
1012
|
+
parts.push(`Description: ${metadata.description}`);
|
|
990
1013
|
}
|
|
991
|
-
if (metadata.props
|
|
992
|
-
|
|
993
|
-
parts.push(`Multi-component with: ${componentTypes}`);
|
|
1014
|
+
if (metadata.props) {
|
|
1015
|
+
parts.push(`Props: ${JSON.stringify(metadata.props)}`);
|
|
994
1016
|
}
|
|
995
|
-
|
|
996
|
-
}
|
|
997
|
-
|
|
1017
|
+
responseParts.push(parts.join("\n"));
|
|
1018
|
+
}
|
|
1019
|
+
if (hasTextResponse) {
|
|
1020
|
+
responseParts.push(textResponse);
|
|
1021
|
+
}
|
|
1022
|
+
if (responseParts.length > 0) {
|
|
1023
|
+
assistantResponse = responseParts.join("\n");
|
|
998
1024
|
} else {
|
|
999
1025
|
assistantResponse = "No response generated";
|
|
1000
1026
|
}
|
|
@@ -2346,18 +2372,16 @@ Your job is to:
|
|
|
2346
2372
|
1. **Parse the component suggestions** from the text response (format: 1:component_type : reasoning)
|
|
2347
2373
|
2. **Match each suggestion with an actual component** from the available list
|
|
2348
2374
|
3. **Generate proper props** for each matched component to **visualize the analysis results** that were already fetched
|
|
2349
|
-
4. **
|
|
2375
|
+
4. **Generate title and description** for the dashboard container
|
|
2350
2376
|
5. **Generate intelligent follow-up questions (actions)** that the user might naturally ask next based on the data analysis
|
|
2351
2377
|
|
|
2352
2378
|
**CRITICAL GOAL**: Create dashboard components that display the **same data that was already analyzed** - NOT new data. The queries already ran and got results. You're just creating different visualizations of those results.
|
|
2353
2379
|
|
|
2354
|
-
**APPROACH**: First match all the components suggested in the text response, THEN find the layout that best fits those components.
|
|
2355
|
-
|
|
2356
2380
|
## Available Components
|
|
2357
2381
|
|
|
2358
2382
|
{{AVAILABLE_COMPONENTS}}
|
|
2359
2383
|
|
|
2360
|
-
## Component Matching Rules
|
|
2384
|
+
## Component Matching Rules
|
|
2361
2385
|
For each component suggestion (c1, c2, c3, etc.) from the text response:
|
|
2362
2386
|
|
|
2363
2387
|
1. **Match by type**: Find components whose \`type\` matches the suggested component type
|
|
@@ -2366,23 +2390,10 @@ For each component suggestion (c1, c2, c3, etc.) from the text response:
|
|
|
2366
2390
|
- Best fit for the data being visualized
|
|
2367
2391
|
3. **Fallback**: If no exact type match, find the closest alternative
|
|
2368
2392
|
|
|
2369
|
-
##
|
|
2370
|
-
|
|
2371
|
-
**
|
|
2372
|
-
|
|
2373
|
-
1. **Find layout components** by looking for components with \`type: "DashboardLayout"\` in the available components list
|
|
2374
|
-
2. **Read each layout's description** to understand:
|
|
2375
|
-
- What structure it provides
|
|
2376
|
-
- When it's best used (e.g., comprehensive analysis vs focused analysis)
|
|
2377
|
-
- The number and types of components it can accommodate
|
|
2378
|
-
3. **Select the best layout** based on:
|
|
2379
|
-
- Which layout can best display ALL the matched components
|
|
2380
|
-
- The layout's capacity (how many components it supports)
|
|
2381
|
-
- The types of matched components (KPI, charts, tables, etc.)
|
|
2382
|
-
- The user question and data complexity
|
|
2383
|
-
4. **If no specific layout fits**, fall back to "MultiComponentContainer" as the default layout
|
|
2384
|
-
|
|
2385
|
-
**IMPORTANT:** The layout should be chosen to FIT the matched components, not the other way around. Don't force components to fit a layout - find a layout that accommodates your components.
|
|
2393
|
+
## Dashboard Container
|
|
2394
|
+
All matched components will be placed in the default **MultiComponentContainer** layout. Your job is to:
|
|
2395
|
+
1. **Generate a clear title** for the dashboard that summarizes what it shows
|
|
2396
|
+
2. **Generate a brief description** explaining the dashboard's purpose and scope
|
|
2386
2397
|
|
|
2387
2398
|
## Props Generation Rules
|
|
2388
2399
|
|
|
@@ -2496,8 +2507,8 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
|
|
|
2496
2507
|
|
|
2497
2508
|
\`\`\`json
|
|
2498
2509
|
{
|
|
2499
|
-
"
|
|
2500
|
-
"
|
|
2510
|
+
"layoutTitle": "Clear, concise title for the overall dashboard/layout (5-10 words)",
|
|
2511
|
+
"layoutDescription": "Brief description of what the dashboard shows and its purpose (1-2 sentences)",
|
|
2501
2512
|
"matchedComponents": [
|
|
2502
2513
|
{
|
|
2503
2514
|
"componentId": "id_from_available_list",
|
|
@@ -2527,17 +2538,14 @@ You MUST respond with ONLY a valid JSON object (no markdown, no code blocks):
|
|
|
2527
2538
|
\`\`\`
|
|
2528
2539
|
|
|
2529
2540
|
**CRITICAL:**
|
|
2530
|
-
- \`matchedComponents\` MUST include ALL components suggested in the text response
|
|
2531
|
-
- \`
|
|
2532
|
-
-
|
|
2533
|
-
|
|
2534
|
-
-
|
|
2535
|
-
- Why this layout is the best fit for displaying these specific matched components
|
|
2536
|
-
- What makes this layout appropriate for the component types and count
|
|
2537
|
-
- The layout selection happens AFTER component matching - don't force components to fit a pre-selected layout
|
|
2541
|
+
- \`matchedComponents\` MUST include ALL components suggested in the text response
|
|
2542
|
+
- \`layoutTitle\` MUST be a clear, concise title (5-10 words) that summarizes what the entire dashboard shows
|
|
2543
|
+
- Examples: "Sales Performance Overview", "Customer Metrics Analysis", "Product Category Breakdown"
|
|
2544
|
+
- \`layoutDescription\` MUST be a brief description (1-2 sentences) explaining the purpose and scope of the dashboard
|
|
2545
|
+
- Should describe what insights the dashboard provides and what data it shows
|
|
2538
2546
|
- \`actions\` MUST be an array of 4-5 intelligent follow-up questions based on the analysis
|
|
2539
2547
|
- Return ONLY valid JSON (no markdown code blocks, no text before/after)
|
|
2540
|
-
- Generate complete props for each component
|
|
2548
|
+
- Generate complete props for each component including query, title, description, and config
|
|
2541
2549
|
|
|
2542
2550
|
|
|
2543
2551
|
`,
|
|
@@ -2589,6 +2597,71 @@ Format your response as a JSON object with this structure:
|
|
|
2589
2597
|
}
|
|
2590
2598
|
|
|
2591
2599
|
Return ONLY valid JSON.`
|
|
2600
|
+
},
|
|
2601
|
+
"execute-tools": {
|
|
2602
|
+
system: `You are an expert AI assistant that executes external tools to fetch data from external services.
|
|
2603
|
+
|
|
2604
|
+
You have access to external tools that can retrieve information like emails, calendar events, and other external data. When the user requests this information, you should call the appropriate tools.
|
|
2605
|
+
|
|
2606
|
+
## Available External Tools
|
|
2607
|
+
{{AVAILABLE_TOOLS}}
|
|
2608
|
+
|
|
2609
|
+
## Your Task
|
|
2610
|
+
|
|
2611
|
+
Analyze the user's request and:
|
|
2612
|
+
|
|
2613
|
+
1. **Determine if external tools are needed**
|
|
2614
|
+
- Examples that NEED external tools:
|
|
2615
|
+
- "Show me my emails" \u2192 needs email tool
|
|
2616
|
+
- "Get my last 5 Gmail messages" \u2192 needs Gmail tool
|
|
2617
|
+
- "Check my Outlook inbox" \u2192 needs Outlook tool
|
|
2618
|
+
|
|
2619
|
+
- Examples that DON'T need external tools:
|
|
2620
|
+
- "What is the total sales?" \u2192 database query (handled elsewhere)
|
|
2621
|
+
- "Show me revenue trends" \u2192 internal data analysis
|
|
2622
|
+
- "Hello" \u2192 general conversation
|
|
2623
|
+
|
|
2624
|
+
2. **Call the appropriate tools**
|
|
2625
|
+
- Use the tool calling mechanism to execute external tools
|
|
2626
|
+
- Extract parameters from the user's request
|
|
2627
|
+
- Use sensible defaults when parameters aren't specified:
|
|
2628
|
+
- For email limit: default to 10
|
|
2629
|
+
- For email address: use "me" for the authenticated user if not specified
|
|
2630
|
+
|
|
2631
|
+
3. **Handle errors and retry**
|
|
2632
|
+
- If a tool call fails, analyze the error message
|
|
2633
|
+
- Retry with corrected parameters if possible
|
|
2634
|
+
- You have up to 3 attempts per tool
|
|
2635
|
+
|
|
2636
|
+
## Important Guidelines
|
|
2637
|
+
|
|
2638
|
+
- **Only call external tools when necessary** - Don't call tools for database queries or general conversation
|
|
2639
|
+
- **Choose the right tool** - For email requests, select Gmail vs Outlook based on:
|
|
2640
|
+
- Explicit mention (e.g., "Gmail", "Outlook")
|
|
2641
|
+
- Email domain (e.g., @gmail.com \u2192 Gmail, @company.com \u2192 Outlook)
|
|
2642
|
+
- **Extract parameters carefully** - Use the user's exact values when provided
|
|
2643
|
+
- **If no tools are needed** - Simply respond that no external tools are required for this request
|
|
2644
|
+
|
|
2645
|
+
## Examples
|
|
2646
|
+
|
|
2647
|
+
**Example 1 - Gmail Request:**
|
|
2648
|
+
User: "Show me my last 5 Gmail messages"
|
|
2649
|
+
Action: Call get-gmail-mails tool with parameters: { email: "me", limit: 5 }
|
|
2650
|
+
|
|
2651
|
+
**Example 2 - Outlook Request:**
|
|
2652
|
+
User: "Get emails from john.doe@company.com"
|
|
2653
|
+
Action: Call get-outlook-mails tool with parameters: { email: "john.doe@company.com", limit: 10 }
|
|
2654
|
+
|
|
2655
|
+
**Example 3 - No Tools Needed:**
|
|
2656
|
+
User: "What is the total sales?"
|
|
2657
|
+
Response: This is a database query, not an external tool request. No external tools are needed.
|
|
2658
|
+
|
|
2659
|
+
**Example 4 - Error Retry:**
|
|
2660
|
+
Tool call fails with: "Invalid email parameter"
|
|
2661
|
+
Action: Analyze error, correct the parameter, and retry the tool call
|
|
2662
|
+
`,
|
|
2663
|
+
user: `{{USER_PROMPT}}
|
|
2664
|
+
`
|
|
2592
2665
|
}
|
|
2593
2666
|
};
|
|
2594
2667
|
|
|
@@ -3633,12 +3706,14 @@ var BaseLLM = class {
|
|
|
3633
3706
|
/**
|
|
3634
3707
|
* Match components from text response suggestions and generate follow-up questions
|
|
3635
3708
|
* Takes a text response with component suggestions (c1:type format) and matches with available components
|
|
3636
|
-
* Also generates intelligent follow-up questions (actions) based on the analysis
|
|
3709
|
+
* Also generates title, description, and intelligent follow-up questions (actions) based on the analysis
|
|
3710
|
+
* All components are placed in a default MultiComponentContainer layout
|
|
3637
3711
|
* @param textResponse - The text response containing component suggestions
|
|
3638
3712
|
* @param components - List of available components
|
|
3639
3713
|
* @param apiKey - Optional API key
|
|
3640
3714
|
* @param logCollector - Optional log collector
|
|
3641
|
-
* @
|
|
3715
|
+
* @param componentStreamCallback - Optional callback to stream primary KPI component as soon as it's identified
|
|
3716
|
+
* @returns Object containing matched components, layout title/description, and follow-up actions
|
|
3642
3717
|
*/
|
|
3643
3718
|
async matchComponentsFromTextResponse(textResponse, components, apiKey, logCollector) {
|
|
3644
3719
|
try {
|
|
@@ -3681,24 +3756,17 @@ var BaseLLM = class {
|
|
|
3681
3756
|
);
|
|
3682
3757
|
logger.debug(`[${this.getProviderName()}] Component matching response parsed successfully`);
|
|
3683
3758
|
const matchedComponents = result.matchedComponents || [];
|
|
3684
|
-
const
|
|
3685
|
-
const
|
|
3759
|
+
const layoutTitle = result.layoutTitle || "Dashboard";
|
|
3760
|
+
const layoutDescription = result.layoutDescription || "Multi-component dashboard";
|
|
3686
3761
|
const rawActions = result.actions || [];
|
|
3687
3762
|
const actions = convertQuestionsToActions(rawActions);
|
|
3688
|
-
let selectedLayoutComponent = null;
|
|
3689
|
-
if (selectedLayoutId) {
|
|
3690
|
-
selectedLayoutComponent = components.find((c) => c.id === selectedLayoutId) || null;
|
|
3691
|
-
if (!selectedLayoutComponent) {
|
|
3692
|
-
logger.warn(`[${this.getProviderName()}] Layout component ${selectedLayoutId} not found in available components`);
|
|
3693
|
-
}
|
|
3694
|
-
}
|
|
3695
3763
|
logger.info(`[${this.getProviderName()}] Matched ${matchedComponents.length} components from text response`);
|
|
3696
|
-
logger.info(`[${this.getProviderName()}]
|
|
3697
|
-
logger.info(`[${this.getProviderName()}] Layout
|
|
3764
|
+
logger.info(`[${this.getProviderName()}] Layout title: "${layoutTitle}"`);
|
|
3765
|
+
logger.info(`[${this.getProviderName()}] Layout description: "${layoutDescription}"`);
|
|
3698
3766
|
logger.info(`[${this.getProviderName()}] Generated ${actions.length} follow-up actions`);
|
|
3699
3767
|
if (matchedComponents.length > 0) {
|
|
3700
|
-
logCollector?.info(`Matched ${matchedComponents.length} components for visualization
|
|
3701
|
-
logCollector?.info(`
|
|
3768
|
+
logCollector?.info(`Matched ${matchedComponents.length} components for visualization`);
|
|
3769
|
+
logCollector?.info(`Dashboard: "${layoutTitle}"`);
|
|
3702
3770
|
matchedComponents.forEach((comp, idx) => {
|
|
3703
3771
|
logCollector?.info(` ${idx + 1}. ${comp.componentName} (${comp.componentType}): ${comp.reasoning}`);
|
|
3704
3772
|
if (comp.props?.query) {
|
|
@@ -3732,9 +3800,8 @@ var BaseLLM = class {
|
|
|
3732
3800
|
}).filter(Boolean);
|
|
3733
3801
|
return {
|
|
3734
3802
|
components: finalComponents,
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
layoutReasoning,
|
|
3803
|
+
layoutTitle,
|
|
3804
|
+
layoutDescription,
|
|
3738
3805
|
actions
|
|
3739
3806
|
};
|
|
3740
3807
|
} catch (error) {
|
|
@@ -3743,13 +3810,158 @@ var BaseLLM = class {
|
|
|
3743
3810
|
logCollector?.error(`Failed to match components: ${errorMsg}`);
|
|
3744
3811
|
return {
|
|
3745
3812
|
components: [],
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
layoutReasoning: "Failed to match components due to parsing error",
|
|
3813
|
+
layoutTitle: "Dashboard",
|
|
3814
|
+
layoutDescription: "Failed to generate dashboard",
|
|
3749
3815
|
actions: []
|
|
3750
3816
|
};
|
|
3751
3817
|
}
|
|
3752
3818
|
}
|
|
3819
|
+
/**
|
|
3820
|
+
* Execute external tools based on user request using agentic LLM tool calling
|
|
3821
|
+
* The LLM can directly call tools and retry on errors
|
|
3822
|
+
* @param userPrompt - The user's question/request
|
|
3823
|
+
* @param availableTools - Array of available external tools
|
|
3824
|
+
* @param apiKey - Optional API key for LLM
|
|
3825
|
+
* @param logCollector - Optional log collector
|
|
3826
|
+
* @returns Object containing tool execution results and summary
|
|
3827
|
+
*/
|
|
3828
|
+
async executeExternalTools(userPrompt, availableTools, apiKey, logCollector) {
|
|
3829
|
+
const MAX_TOOL_ATTEMPTS = 3;
|
|
3830
|
+
const toolResults = [];
|
|
3831
|
+
try {
|
|
3832
|
+
logger.debug(`[${this.getProviderName()}] Starting agentic external tool execution`);
|
|
3833
|
+
logger.debug(`[${this.getProviderName()}] Available tools: ${availableTools.map((t) => t.name).join(", ")}`);
|
|
3834
|
+
const llmTools = availableTools.map((tool) => {
|
|
3835
|
+
const properties = {};
|
|
3836
|
+
const required = [];
|
|
3837
|
+
Object.entries(tool.params || {}).forEach(([key, type]) => {
|
|
3838
|
+
properties[key] = {
|
|
3839
|
+
type: String(type).toLowerCase(),
|
|
3840
|
+
description: `${key} parameter`
|
|
3841
|
+
};
|
|
3842
|
+
required.push(key);
|
|
3843
|
+
});
|
|
3844
|
+
return {
|
|
3845
|
+
name: tool.id,
|
|
3846
|
+
description: tool.description,
|
|
3847
|
+
input_schema: {
|
|
3848
|
+
type: "object",
|
|
3849
|
+
properties,
|
|
3850
|
+
required
|
|
3851
|
+
}
|
|
3852
|
+
};
|
|
3853
|
+
});
|
|
3854
|
+
const toolAttempts = /* @__PURE__ */ new Map();
|
|
3855
|
+
const toolHandler = async (toolName, toolInput) => {
|
|
3856
|
+
const tool = availableTools.find((t) => t.id === toolName);
|
|
3857
|
+
if (!tool) {
|
|
3858
|
+
const errorMsg = `Tool ${toolName} not found in available tools`;
|
|
3859
|
+
logger.error(`[${this.getProviderName()}] ${errorMsg}`);
|
|
3860
|
+
logCollector?.error(errorMsg);
|
|
3861
|
+
throw new Error(errorMsg);
|
|
3862
|
+
}
|
|
3863
|
+
const attempts = (toolAttempts.get(toolName) || 0) + 1;
|
|
3864
|
+
toolAttempts.set(toolName, attempts);
|
|
3865
|
+
logger.info(`[${this.getProviderName()}] Executing tool: ${tool.name} (attempt ${attempts}/${MAX_TOOL_ATTEMPTS})`);
|
|
3866
|
+
logCollector?.info(`Executing ${tool.name} (attempt ${attempts}/${MAX_TOOL_ATTEMPTS})...`);
|
|
3867
|
+
if (attempts > MAX_TOOL_ATTEMPTS) {
|
|
3868
|
+
const errorMsg = `Maximum attempts (${MAX_TOOL_ATTEMPTS}) reached for tool: ${tool.name}`;
|
|
3869
|
+
logger.error(`[${this.getProviderName()}] ${errorMsg}`);
|
|
3870
|
+
logCollector?.error(errorMsg);
|
|
3871
|
+
toolResults.push({
|
|
3872
|
+
toolName: tool.name,
|
|
3873
|
+
toolId: tool.id,
|
|
3874
|
+
result: null,
|
|
3875
|
+
error: errorMsg
|
|
3876
|
+
});
|
|
3877
|
+
throw new Error(errorMsg);
|
|
3878
|
+
}
|
|
3879
|
+
try {
|
|
3880
|
+
logger.debug(`[${this.getProviderName()}] Tool ${tool.name} parameters:`, toolInput);
|
|
3881
|
+
const result2 = await tool.fn(toolInput);
|
|
3882
|
+
logger.info(`[${this.getProviderName()}] Tool ${tool.name} executed successfully`);
|
|
3883
|
+
logCollector?.info(`\u2713 ${tool.name} completed successfully`);
|
|
3884
|
+
toolResults.push({
|
|
3885
|
+
toolName: tool.name,
|
|
3886
|
+
toolId: tool.id,
|
|
3887
|
+
result: result2
|
|
3888
|
+
});
|
|
3889
|
+
return JSON.stringify(result2, null, 2);
|
|
3890
|
+
} catch (error) {
|
|
3891
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3892
|
+
logger.error(`[${this.getProviderName()}] Tool ${tool.name} failed (attempt ${attempts}): ${errorMsg}`);
|
|
3893
|
+
logCollector?.error(`\u2717 ${tool.name} failed: ${errorMsg}`);
|
|
3894
|
+
if (attempts >= MAX_TOOL_ATTEMPTS) {
|
|
3895
|
+
toolResults.push({
|
|
3896
|
+
toolName: tool.name,
|
|
3897
|
+
toolId: tool.id,
|
|
3898
|
+
result: null,
|
|
3899
|
+
error: errorMsg
|
|
3900
|
+
});
|
|
3901
|
+
}
|
|
3902
|
+
throw new Error(`Tool execution failed: ${errorMsg}`);
|
|
3903
|
+
}
|
|
3904
|
+
};
|
|
3905
|
+
const prompts = await promptLoader.loadPrompts("execute-tools", {
|
|
3906
|
+
USER_PROMPT: userPrompt,
|
|
3907
|
+
AVAILABLE_TOOLS: availableTools.map((tool, idx) => {
|
|
3908
|
+
const paramsText = Object.entries(tool.params || {}).map(([key, type]) => ` - ${key}: ${type}`).join("\n");
|
|
3909
|
+
return `${idx + 1}. ID: ${tool.id}
|
|
3910
|
+
Name: ${tool.name}
|
|
3911
|
+
Description: ${tool.description}
|
|
3912
|
+
Parameters:
|
|
3913
|
+
${paramsText}`;
|
|
3914
|
+
}).join("\n\n")
|
|
3915
|
+
});
|
|
3916
|
+
logger.debug(`[${this.getProviderName()}] Using agentic tool calling for external tools`);
|
|
3917
|
+
logCollector?.info("Analyzing request and executing external tools...");
|
|
3918
|
+
const result = await LLM.streamWithTools(
|
|
3919
|
+
{
|
|
3920
|
+
sys: prompts.system,
|
|
3921
|
+
user: prompts.user
|
|
3922
|
+
},
|
|
3923
|
+
llmTools,
|
|
3924
|
+
toolHandler,
|
|
3925
|
+
{
|
|
3926
|
+
model: this.model,
|
|
3927
|
+
maxTokens: 2e3,
|
|
3928
|
+
temperature: 0.2,
|
|
3929
|
+
apiKey: this.getApiKey(apiKey)
|
|
3930
|
+
},
|
|
3931
|
+
MAX_TOOL_ATTEMPTS + 2
|
|
3932
|
+
// max iterations: allows for retries + final response
|
|
3933
|
+
);
|
|
3934
|
+
logger.info(`[${this.getProviderName()}] External tool execution completed`);
|
|
3935
|
+
const successfulTools = toolResults.filter((r) => !r.error);
|
|
3936
|
+
const failedTools = toolResults.filter((r) => r.error);
|
|
3937
|
+
let summary = "";
|
|
3938
|
+
if (successfulTools.length > 0) {
|
|
3939
|
+
summary += `Successfully executed ${successfulTools.length} tool(s): ${successfulTools.map((t) => t.toolName).join(", ")}.
|
|
3940
|
+
`;
|
|
3941
|
+
}
|
|
3942
|
+
if (failedTools.length > 0) {
|
|
3943
|
+
summary += `Failed to execute ${failedTools.length} tool(s): ${failedTools.map((t) => t.toolName).join(", ")}.`;
|
|
3944
|
+
}
|
|
3945
|
+
if (toolResults.length === 0) {
|
|
3946
|
+
summary = "No external tools were needed for this request.";
|
|
3947
|
+
}
|
|
3948
|
+
logger.info(`[${this.getProviderName()}] Tool execution summary: ${summary}`);
|
|
3949
|
+
return {
|
|
3950
|
+
toolResults,
|
|
3951
|
+
summary,
|
|
3952
|
+
hasResults: successfulTools.length > 0
|
|
3953
|
+
};
|
|
3954
|
+
} catch (error) {
|
|
3955
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3956
|
+
logger.error(`[${this.getProviderName()}] Error in external tool execution: ${errorMsg}`);
|
|
3957
|
+
logCollector?.error(`Error executing external tools: ${errorMsg}`);
|
|
3958
|
+
return {
|
|
3959
|
+
toolResults,
|
|
3960
|
+
summary: `Error executing external tools: ${errorMsg}`,
|
|
3961
|
+
hasResults: false
|
|
3962
|
+
};
|
|
3963
|
+
}
|
|
3964
|
+
}
|
|
3753
3965
|
/**
|
|
3754
3966
|
* Generate text-based response for user question
|
|
3755
3967
|
* This provides conversational text responses instead of component generation
|
|
@@ -3758,12 +3970,40 @@ var BaseLLM = class {
|
|
|
3758
3970
|
* @param streamCallback - Optional callback function to receive text chunks as they stream
|
|
3759
3971
|
* @param collections - Collection registry for executing database queries via database.execute
|
|
3760
3972
|
* @param components - Optional list of available components for matching suggestions
|
|
3973
|
+
* @param externalTools - Optional array of external tools (email, calendar, etc.) that can be called
|
|
3761
3974
|
*/
|
|
3762
|
-
async generateTextResponse(userPrompt, apiKey, logCollector, conversationHistory, streamCallback, collections, components) {
|
|
3975
|
+
async generateTextResponse(userPrompt, apiKey, logCollector, conversationHistory, streamCallback, collections, components, externalTools) {
|
|
3763
3976
|
const errors = [];
|
|
3764
3977
|
logger.debug(`[${this.getProviderName()}] Starting text response generation`);
|
|
3765
3978
|
logger.debug(`[${this.getProviderName()}] User prompt: "${userPrompt.substring(0, 50)}..."`);
|
|
3766
3979
|
try {
|
|
3980
|
+
let externalToolContext = "No external tools were used for this request.";
|
|
3981
|
+
if (externalTools && externalTools.length > 0) {
|
|
3982
|
+
logger.info(`[${this.getProviderName()}] Executing external tools...`);
|
|
3983
|
+
const toolExecution = await this.executeExternalTools(
|
|
3984
|
+
userPrompt,
|
|
3985
|
+
externalTools,
|
|
3986
|
+
apiKey,
|
|
3987
|
+
logCollector
|
|
3988
|
+
);
|
|
3989
|
+
if (toolExecution.hasResults) {
|
|
3990
|
+
const toolResultsText = toolExecution.toolResults.map((tr) => {
|
|
3991
|
+
if (tr.error) {
|
|
3992
|
+
return `**${tr.toolName}** (Failed): ${tr.error}`;
|
|
3993
|
+
}
|
|
3994
|
+
return `**${tr.toolName}** (Success):
|
|
3995
|
+
${JSON.stringify(tr.result, null, 2)}`;
|
|
3996
|
+
}).join("\n\n");
|
|
3997
|
+
externalToolContext = `## External Tool Results
|
|
3998
|
+
|
|
3999
|
+
${toolExecution.summary}
|
|
4000
|
+
|
|
4001
|
+
${toolResultsText}`;
|
|
4002
|
+
logger.info(`[${this.getProviderName()}] External tools executed, results available`);
|
|
4003
|
+
} else {
|
|
4004
|
+
logger.info(`[${this.getProviderName()}] No external tools were needed`);
|
|
4005
|
+
}
|
|
4006
|
+
}
|
|
3767
4007
|
const schemaDoc = schema.generateSchemaDocumentation();
|
|
3768
4008
|
const knowledgeBaseContext = await knowledge_base_default.getKnowledgeBase({
|
|
3769
4009
|
prompt: userPrompt,
|
|
@@ -3771,11 +4011,13 @@ var BaseLLM = class {
|
|
|
3771
4011
|
topK: 1
|
|
3772
4012
|
});
|
|
3773
4013
|
logger.file("\n=============================\nknowledge base context:", knowledgeBaseContext);
|
|
4014
|
+
logger.file("\n=============================\nexternal tool context:", externalToolContext);
|
|
3774
4015
|
const prompts = await promptLoader.loadPrompts("text-response", {
|
|
3775
4016
|
USER_PROMPT: userPrompt,
|
|
3776
4017
|
CONVERSATION_HISTORY: conversationHistory || "No previous conversation",
|
|
3777
4018
|
SCHEMA_DOC: schemaDoc,
|
|
3778
|
-
KNOWLEDGE_BASE_CONTEXT: knowledgeBaseContext || "No additional knowledge base context available."
|
|
4019
|
+
KNOWLEDGE_BASE_CONTEXT: knowledgeBaseContext || "No additional knowledge base context available.",
|
|
4020
|
+
EXTERNAL_TOOL_CONTEXT: externalToolContext
|
|
3779
4021
|
});
|
|
3780
4022
|
logger.file("\n=============================\nsystem prompt:", prompts.system);
|
|
3781
4023
|
logger.file("\n=============================\nuser prompt:", prompts.user);
|
|
@@ -3989,9 +4231,12 @@ ${errorMsg}
|
|
|
3989
4231
|
textLength: textResponse.length
|
|
3990
4232
|
}
|
|
3991
4233
|
);
|
|
4234
|
+
if (wrappedStreamCallback && components && components.length > 0) {
|
|
4235
|
+
wrappedStreamCallback("__TEXT_COMPLETE__COMPONENT_GENERATION_START__");
|
|
4236
|
+
}
|
|
3992
4237
|
let matchedComponents = [];
|
|
3993
|
-
let
|
|
3994
|
-
let
|
|
4238
|
+
let layoutTitle = "Dashboard";
|
|
4239
|
+
let layoutDescription = "Multi-component dashboard";
|
|
3995
4240
|
let actions = [];
|
|
3996
4241
|
if (components && components.length > 0) {
|
|
3997
4242
|
logger.info(`[${this.getProviderName()}] Matching components from text response...`);
|
|
@@ -4002,46 +4247,30 @@ ${errorMsg}
|
|
|
4002
4247
|
logCollector
|
|
4003
4248
|
);
|
|
4004
4249
|
matchedComponents = matchResult.components;
|
|
4005
|
-
|
|
4006
|
-
|
|
4250
|
+
layoutTitle = matchResult.layoutTitle;
|
|
4251
|
+
layoutDescription = matchResult.layoutDescription;
|
|
4007
4252
|
actions = matchResult.actions;
|
|
4008
4253
|
}
|
|
4009
4254
|
let container_componet = null;
|
|
4010
4255
|
if (matchedComponents.length > 0) {
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
}
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
}
|
|
4028
|
-
|
|
4029
|
-
id: `multi_container_${Date.now()}`,
|
|
4030
|
-
name: "MultiComponentContainer",
|
|
4031
|
-
type: "Container",
|
|
4032
|
-
description: layoutReasoning,
|
|
4033
|
-
category: "dynamic",
|
|
4034
|
-
keywords: ["dashboard", "layout", "container"],
|
|
4035
|
-
props: {
|
|
4036
|
-
config: {
|
|
4037
|
-
components: matchedComponents
|
|
4038
|
-
},
|
|
4039
|
-
actions
|
|
4040
|
-
}
|
|
4041
|
-
};
|
|
4042
|
-
logger.info(`[${this.getProviderName()}] Created fallback MultiComponentContainer with ${matchedComponents.length} components and ${actions.length} actions`);
|
|
4043
|
-
logCollector?.info(`Created MultiComponentContainer with ${matchedComponents.length} components and ${actions.length} actions: ${layoutReasoning}`);
|
|
4044
|
-
}
|
|
4256
|
+
container_componet = {
|
|
4257
|
+
id: `multi_container_${Date.now()}`,
|
|
4258
|
+
name: "MultiComponentContainer",
|
|
4259
|
+
type: "Container",
|
|
4260
|
+
description: layoutDescription,
|
|
4261
|
+
category: "dynamic",
|
|
4262
|
+
keywords: ["dashboard", "layout", "container"],
|
|
4263
|
+
props: {
|
|
4264
|
+
config: {
|
|
4265
|
+
components: matchedComponents,
|
|
4266
|
+
title: layoutTitle,
|
|
4267
|
+
description: layoutDescription
|
|
4268
|
+
},
|
|
4269
|
+
actions
|
|
4270
|
+
}
|
|
4271
|
+
};
|
|
4272
|
+
logger.info(`[${this.getProviderName()}] Created MultiComponentContainer: "${layoutTitle}" with ${matchedComponents.length} components and ${actions.length} actions`);
|
|
4273
|
+
logCollector?.info(`Created dashboard: "${layoutTitle}" with ${matchedComponents.length} components and ${actions.length} actions`);
|
|
4045
4274
|
}
|
|
4046
4275
|
return {
|
|
4047
4276
|
success: true,
|
|
@@ -4049,7 +4278,6 @@ ${errorMsg}
|
|
|
4049
4278
|
text: textResponse,
|
|
4050
4279
|
matchedComponents,
|
|
4051
4280
|
component: container_componet,
|
|
4052
|
-
layoutReasoning,
|
|
4053
4281
|
actions,
|
|
4054
4282
|
method: `${this.getProviderName()}-text-response`
|
|
4055
4283
|
},
|
|
@@ -4260,8 +4488,9 @@ ${errorMsg}
|
|
|
4260
4488
|
* @param responseMode - 'component' for component generation (default), 'text' for text responses
|
|
4261
4489
|
* @param streamCallback - Optional callback function to receive text chunks as they stream (only for text mode)
|
|
4262
4490
|
* @param collections - Collection registry for executing database queries (required for text mode)
|
|
4491
|
+
* @param externalTools - Optional array of external tools (email, calendar, etc.) that can be called (only for text mode)
|
|
4263
4492
|
*/
|
|
4264
|
-
async handleUserRequest(userPrompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections) {
|
|
4493
|
+
async handleUserRequest(userPrompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools) {
|
|
4265
4494
|
const startTime = Date.now();
|
|
4266
4495
|
logger.info(`[${this.getProviderName()}] handleUserRequest called with responseMode: ${responseMode}`);
|
|
4267
4496
|
if (responseMode === "text") {
|
|
@@ -4274,7 +4503,8 @@ ${errorMsg}
|
|
|
4274
4503
|
conversationHistory,
|
|
4275
4504
|
streamCallback,
|
|
4276
4505
|
collections,
|
|
4277
|
-
components
|
|
4506
|
+
components,
|
|
4507
|
+
externalTools
|
|
4278
4508
|
);
|
|
4279
4509
|
if (!textResponse.success) {
|
|
4280
4510
|
const elapsedTime3 = Date.now() - startTime;
|
|
@@ -4420,7 +4650,7 @@ function getLLMProviders() {
|
|
|
4420
4650
|
return DEFAULT_PROVIDERS;
|
|
4421
4651
|
}
|
|
4422
4652
|
}
|
|
4423
|
-
var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections) => {
|
|
4653
|
+
var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools) => {
|
|
4424
4654
|
logger.debug("[useAnthropicMethod] Initializing Anthropic Claude matching method");
|
|
4425
4655
|
logger.debug(`[useAnthropicMethod] Response mode: ${responseMode}`);
|
|
4426
4656
|
const msg = `Using Anthropic Claude ${responseMode === "text" ? "text response" : "matching"} method...`;
|
|
@@ -4432,11 +4662,11 @@ var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conver
|
|
|
4432
4662
|
return { success: false, errors: [emptyMsg] };
|
|
4433
4663
|
}
|
|
4434
4664
|
logger.debug(`[useAnthropicMethod] Processing with ${components.length} components`);
|
|
4435
|
-
const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections);
|
|
4665
|
+
const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools);
|
|
4436
4666
|
logger.info(`[useAnthropicMethod] Successfully generated ${responseMode} using Anthropic`);
|
|
4437
4667
|
return matchResult;
|
|
4438
4668
|
};
|
|
4439
|
-
var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections) => {
|
|
4669
|
+
var useGroqMethod = async (prompt, components, apiKey, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools) => {
|
|
4440
4670
|
logger.debug("[useGroqMethod] Initializing Groq LLM matching method");
|
|
4441
4671
|
logger.debug(`[useGroqMethod] Response mode: ${responseMode}`);
|
|
4442
4672
|
const msg = `Using Groq LLM ${responseMode === "text" ? "text response" : "matching"} method...`;
|
|
@@ -4449,14 +4679,14 @@ var useGroqMethod = async (prompt, components, apiKey, logCollector, conversatio
|
|
|
4449
4679
|
return { success: false, errors: [emptyMsg] };
|
|
4450
4680
|
}
|
|
4451
4681
|
logger.debug(`[useGroqMethod] Processing with ${components.length} components`);
|
|
4452
|
-
const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections);
|
|
4682
|
+
const matchResult = await groqLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools);
|
|
4453
4683
|
logger.info(`[useGroqMethod] Successfully generated ${responseMode} using Groq`);
|
|
4454
4684
|
return matchResult;
|
|
4455
4685
|
};
|
|
4456
4686
|
var getUserResponseFromCache = async (prompt) => {
|
|
4457
4687
|
return false;
|
|
4458
4688
|
};
|
|
4459
|
-
var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory, responseMode = "component", streamCallback, collections) => {
|
|
4689
|
+
var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory, responseMode = "component", streamCallback, collections, externalTools) => {
|
|
4460
4690
|
logger.debug(`[get_user_response] Starting user response generation for prompt: "${prompt.substring(0, 50)}..."`);
|
|
4461
4691
|
logger.debug(`[get_user_response] Response mode: ${responseMode}`);
|
|
4462
4692
|
logger.debug("[get_user_response] Checking cache for existing response");
|
|
@@ -4489,9 +4719,9 @@ var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey,
|
|
|
4489
4719
|
logCollector?.info(attemptMsg);
|
|
4490
4720
|
let result;
|
|
4491
4721
|
if (provider === "anthropic") {
|
|
4492
|
-
result = await useAnthropicMethod(prompt, components, anthropicApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections);
|
|
4722
|
+
result = await useAnthropicMethod(prompt, components, anthropicApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools);
|
|
4493
4723
|
} else if (provider === "groq") {
|
|
4494
|
-
result = await useGroqMethod(prompt, components, groqApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections);
|
|
4724
|
+
result = await useGroqMethod(prompt, components, groqApiKey, logCollector, conversationHistory, responseMode, streamCallback, collections, externalTools);
|
|
4495
4725
|
} else {
|
|
4496
4726
|
logger.warn(`[get_user_response] Unknown provider: ${provider} - skipping`);
|
|
4497
4727
|
errors.push(`Unknown provider: ${provider}`);
|
|
@@ -4715,11 +4945,11 @@ var CONTEXT_CONFIG = {
|
|
|
4715
4945
|
* Set to 0 to disable conversation history
|
|
4716
4946
|
* Higher values provide more context but may increase token usage
|
|
4717
4947
|
*/
|
|
4718
|
-
MAX_CONVERSATION_CONTEXT_BLOCKS:
|
|
4948
|
+
MAX_CONVERSATION_CONTEXT_BLOCKS: 3
|
|
4719
4949
|
};
|
|
4720
4950
|
|
|
4721
4951
|
// src/handlers/user-prompt-request.ts
|
|
4722
|
-
var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders, collections) => {
|
|
4952
|
+
var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders, collections, externalTools) => {
|
|
4723
4953
|
const errors = [];
|
|
4724
4954
|
logger.debug("[USER_PROMPT_REQ] Parsing incoming message data");
|
|
4725
4955
|
const parseResult = UserPromptRequestMessageSchema.safeParse(data);
|
|
@@ -4799,7 +5029,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
4799
5029
|
conversationHistory,
|
|
4800
5030
|
responseMode,
|
|
4801
5031
|
streamCallback,
|
|
4802
|
-
collections
|
|
5032
|
+
collections,
|
|
5033
|
+
externalTools
|
|
4803
5034
|
);
|
|
4804
5035
|
logCollector.info("User prompt request completed");
|
|
4805
5036
|
const uiBlockId = existingUiBlockId;
|
|
@@ -4860,8 +5091,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
|
|
|
4860
5091
|
wsId
|
|
4861
5092
|
};
|
|
4862
5093
|
};
|
|
4863
|
-
async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders, collections) {
|
|
4864
|
-
const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders, collections);
|
|
5094
|
+
async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders, collections, externalTools) {
|
|
5095
|
+
const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, llmProviders, collections, externalTools);
|
|
4865
5096
|
sendDataResponse4(
|
|
4866
5097
|
response.id || data.id,
|
|
4867
5098
|
{
|
|
@@ -5935,6 +6166,183 @@ function sendResponse5(id, res, sendMessage, clientId) {
|
|
|
5935
6166
|
sendMessage(response);
|
|
5936
6167
|
}
|
|
5937
6168
|
|
|
6169
|
+
// src/handlers/bookmarks.ts
|
|
6170
|
+
async function handleBookmarksRequest(data, collections, sendMessage) {
|
|
6171
|
+
const executeCollection = async (collection, op, params) => {
|
|
6172
|
+
const handler = collections[collection]?.[op];
|
|
6173
|
+
if (!handler) {
|
|
6174
|
+
throw new Error(`Collection operation ${collection}.${op} not found`);
|
|
6175
|
+
}
|
|
6176
|
+
return await handler(params);
|
|
6177
|
+
};
|
|
6178
|
+
try {
|
|
6179
|
+
const request = BookmarksRequestMessageSchema.parse(data);
|
|
6180
|
+
const { id, payload, from } = request;
|
|
6181
|
+
const { operation, data: requestData } = payload;
|
|
6182
|
+
const bookmarkId = requestData?.id;
|
|
6183
|
+
const uiblock = requestData?.uiblock;
|
|
6184
|
+
switch (operation) {
|
|
6185
|
+
case "create":
|
|
6186
|
+
await handleCreate4(id, uiblock, executeCollection, sendMessage, from.id);
|
|
6187
|
+
break;
|
|
6188
|
+
case "update":
|
|
6189
|
+
await handleUpdate4(id, bookmarkId, uiblock, executeCollection, sendMessage, from.id);
|
|
6190
|
+
break;
|
|
6191
|
+
case "delete":
|
|
6192
|
+
await handleDelete4(id, bookmarkId, executeCollection, sendMessage, from.id);
|
|
6193
|
+
break;
|
|
6194
|
+
case "getAll":
|
|
6195
|
+
await handleGetAll4(id, executeCollection, sendMessage, from.id);
|
|
6196
|
+
break;
|
|
6197
|
+
case "getOne":
|
|
6198
|
+
await handleGetOne4(id, bookmarkId, executeCollection, sendMessage, from.id);
|
|
6199
|
+
break;
|
|
6200
|
+
default:
|
|
6201
|
+
sendResponse6(id, {
|
|
6202
|
+
success: false,
|
|
6203
|
+
error: `Unknown operation: ${operation}`
|
|
6204
|
+
}, sendMessage, from.id);
|
|
6205
|
+
}
|
|
6206
|
+
} catch (error) {
|
|
6207
|
+
logger.error("Failed to handle bookmarks request:", error);
|
|
6208
|
+
sendResponse6(null, {
|
|
6209
|
+
success: false,
|
|
6210
|
+
error: error instanceof Error ? error.message : "Unknown error occurred"
|
|
6211
|
+
}, sendMessage);
|
|
6212
|
+
}
|
|
6213
|
+
}
|
|
6214
|
+
async function handleCreate4(id, uiblock, executeCollection, sendMessage, clientId) {
|
|
6215
|
+
if (!uiblock) {
|
|
6216
|
+
sendResponse6(id, {
|
|
6217
|
+
success: false,
|
|
6218
|
+
error: "UIBlock data is required"
|
|
6219
|
+
}, sendMessage, clientId);
|
|
6220
|
+
return;
|
|
6221
|
+
}
|
|
6222
|
+
try {
|
|
6223
|
+
const result = await executeCollection("bookmarks", "create", { uiblock });
|
|
6224
|
+
sendResponse6(id, {
|
|
6225
|
+
success: true,
|
|
6226
|
+
data: result.data,
|
|
6227
|
+
message: "Bookmark created successfully"
|
|
6228
|
+
}, sendMessage, clientId);
|
|
6229
|
+
logger.info(`Bookmark created: ID ${result.data.id}`);
|
|
6230
|
+
} catch (error) {
|
|
6231
|
+
sendResponse6(id, {
|
|
6232
|
+
success: false,
|
|
6233
|
+
error: error instanceof Error ? error.message : "Failed to create bookmark"
|
|
6234
|
+
}, sendMessage, clientId);
|
|
6235
|
+
}
|
|
6236
|
+
}
|
|
6237
|
+
async function handleUpdate4(id, bookmarkId, uiblock, executeCollection, sendMessage, clientId) {
|
|
6238
|
+
if (!bookmarkId) {
|
|
6239
|
+
sendResponse6(id, {
|
|
6240
|
+
success: false,
|
|
6241
|
+
error: "Bookmark ID is required"
|
|
6242
|
+
}, sendMessage, clientId);
|
|
6243
|
+
return;
|
|
6244
|
+
}
|
|
6245
|
+
if (!uiblock) {
|
|
6246
|
+
sendResponse6(id, {
|
|
6247
|
+
success: false,
|
|
6248
|
+
error: "UIBlock data is required"
|
|
6249
|
+
}, sendMessage, clientId);
|
|
6250
|
+
return;
|
|
6251
|
+
}
|
|
6252
|
+
try {
|
|
6253
|
+
const result = await executeCollection("bookmarks", "update", { id: bookmarkId, uiblock });
|
|
6254
|
+
sendResponse6(id, {
|
|
6255
|
+
success: true,
|
|
6256
|
+
data: result.data,
|
|
6257
|
+
message: "Bookmark updated successfully"
|
|
6258
|
+
}, sendMessage, clientId);
|
|
6259
|
+
logger.info(`Bookmark updated: ID ${bookmarkId}`);
|
|
6260
|
+
} catch (error) {
|
|
6261
|
+
sendResponse6(id, {
|
|
6262
|
+
success: false,
|
|
6263
|
+
error: error instanceof Error ? error.message : "Failed to update bookmark"
|
|
6264
|
+
}, sendMessage, clientId);
|
|
6265
|
+
}
|
|
6266
|
+
}
|
|
6267
|
+
async function handleDelete4(id, bookmarkId, executeCollection, sendMessage, clientId) {
|
|
6268
|
+
if (!bookmarkId) {
|
|
6269
|
+
sendResponse6(id, {
|
|
6270
|
+
success: false,
|
|
6271
|
+
error: "Bookmark ID is required"
|
|
6272
|
+
}, sendMessage, clientId);
|
|
6273
|
+
return;
|
|
6274
|
+
}
|
|
6275
|
+
try {
|
|
6276
|
+
const result = await executeCollection("bookmarks", "delete", { id: bookmarkId });
|
|
6277
|
+
sendResponse6(id, {
|
|
6278
|
+
success: true,
|
|
6279
|
+
data: result.data,
|
|
6280
|
+
message: "Bookmark deleted successfully"
|
|
6281
|
+
}, sendMessage, clientId);
|
|
6282
|
+
logger.info(`Bookmark deleted: ID ${bookmarkId}`);
|
|
6283
|
+
} catch (error) {
|
|
6284
|
+
sendResponse6(id, {
|
|
6285
|
+
success: false,
|
|
6286
|
+
error: error instanceof Error ? error.message : "Failed to delete bookmark"
|
|
6287
|
+
}, sendMessage, clientId);
|
|
6288
|
+
}
|
|
6289
|
+
}
|
|
6290
|
+
async function handleGetAll4(id, executeCollection, sendMessage, clientId) {
|
|
6291
|
+
try {
|
|
6292
|
+
const result = await executeCollection("bookmarks", "getAll", {});
|
|
6293
|
+
sendResponse6(id, {
|
|
6294
|
+
success: true,
|
|
6295
|
+
data: result.data,
|
|
6296
|
+
count: result.count,
|
|
6297
|
+
message: `Retrieved ${result.count} bookmarks`
|
|
6298
|
+
}, sendMessage, clientId);
|
|
6299
|
+
logger.info(`Retrieved all bookmarks (count: ${result.count})`);
|
|
6300
|
+
} catch (error) {
|
|
6301
|
+
sendResponse6(id, {
|
|
6302
|
+
success: false,
|
|
6303
|
+
error: error instanceof Error ? error.message : "Failed to get bookmarks"
|
|
6304
|
+
}, sendMessage, clientId);
|
|
6305
|
+
}
|
|
6306
|
+
}
|
|
6307
|
+
async function handleGetOne4(id, bookmarkId, executeCollection, sendMessage, clientId) {
|
|
6308
|
+
if (!bookmarkId) {
|
|
6309
|
+
sendResponse6(id, {
|
|
6310
|
+
success: false,
|
|
6311
|
+
error: "Bookmark ID is required"
|
|
6312
|
+
}, sendMessage, clientId);
|
|
6313
|
+
return;
|
|
6314
|
+
}
|
|
6315
|
+
try {
|
|
6316
|
+
const result = await executeCollection("bookmarks", "getOne", { id: bookmarkId });
|
|
6317
|
+
sendResponse6(id, {
|
|
6318
|
+
success: true,
|
|
6319
|
+
data: result.data,
|
|
6320
|
+
message: `Retrieved bookmark ID ${bookmarkId}`
|
|
6321
|
+
}, sendMessage, clientId);
|
|
6322
|
+
logger.info(`Retrieved bookmark: ID ${bookmarkId}`);
|
|
6323
|
+
} catch (error) {
|
|
6324
|
+
sendResponse6(id, {
|
|
6325
|
+
success: false,
|
|
6326
|
+
error: error instanceof Error ? error.message : "Failed to get bookmark"
|
|
6327
|
+
}, sendMessage, clientId);
|
|
6328
|
+
}
|
|
6329
|
+
}
|
|
6330
|
+
function sendResponse6(id, res, sendMessage, clientId) {
|
|
6331
|
+
const response = {
|
|
6332
|
+
id: id || "unknown",
|
|
6333
|
+
type: "BOOKMARKS_RES",
|
|
6334
|
+
from: { type: "data-agent" },
|
|
6335
|
+
to: {
|
|
6336
|
+
type: "user",
|
|
6337
|
+
id: clientId
|
|
6338
|
+
},
|
|
6339
|
+
payload: {
|
|
6340
|
+
...res
|
|
6341
|
+
}
|
|
6342
|
+
};
|
|
6343
|
+
sendMessage(response);
|
|
6344
|
+
}
|
|
6345
|
+
|
|
5938
6346
|
// src/auth/user-manager.ts
|
|
5939
6347
|
import fs5 from "fs";
|
|
5940
6348
|
import path4 from "path";
|
|
@@ -6759,6 +7167,7 @@ var SuperatomSDK = class {
|
|
|
6759
7167
|
this.maxReconnectAttempts = 5;
|
|
6760
7168
|
this.collections = {};
|
|
6761
7169
|
this.components = [];
|
|
7170
|
+
this.tools = [];
|
|
6762
7171
|
if (config.logLevel) {
|
|
6763
7172
|
logger.setLogLevel(config.logLevel);
|
|
6764
7173
|
}
|
|
@@ -6914,7 +7323,7 @@ var SuperatomSDK = class {
|
|
|
6914
7323
|
});
|
|
6915
7324
|
break;
|
|
6916
7325
|
case "USER_PROMPT_REQ":
|
|
6917
|
-
handleUserPromptRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.llmProviders, this.collections).catch((error) => {
|
|
7326
|
+
handleUserPromptRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.llmProviders, this.collections, this.tools).catch((error) => {
|
|
6918
7327
|
logger.error("Failed to handle user prompt request:", error);
|
|
6919
7328
|
});
|
|
6920
7329
|
break;
|
|
@@ -6948,6 +7357,11 @@ var SuperatomSDK = class {
|
|
|
6948
7357
|
logger.error("Failed to handle reports request:", error);
|
|
6949
7358
|
});
|
|
6950
7359
|
break;
|
|
7360
|
+
case "BOOKMARKS":
|
|
7361
|
+
handleBookmarksRequest(parsed, this.collections, (msg) => this.send(msg)).catch((error) => {
|
|
7362
|
+
logger.error("Failed to handle bookmarks request:", error);
|
|
7363
|
+
});
|
|
7364
|
+
break;
|
|
6951
7365
|
default:
|
|
6952
7366
|
const handler = this.messageTypeHandlers.get(message.type);
|
|
6953
7367
|
if (handler) {
|
|
@@ -7054,6 +7468,19 @@ var SuperatomSDK = class {
|
|
|
7054
7468
|
storeComponents(components) {
|
|
7055
7469
|
this.components = components;
|
|
7056
7470
|
}
|
|
7471
|
+
/**
|
|
7472
|
+
* Set tools for the SDK instance
|
|
7473
|
+
*/
|
|
7474
|
+
setTools(tools) {
|
|
7475
|
+
this.tools = tools;
|
|
7476
|
+
logger.info(`Tools stored in SDK: ${tools.length} tools`);
|
|
7477
|
+
}
|
|
7478
|
+
/**
|
|
7479
|
+
* Get the stored tools
|
|
7480
|
+
*/
|
|
7481
|
+
getTools() {
|
|
7482
|
+
return this.tools;
|
|
7483
|
+
}
|
|
7057
7484
|
};
|
|
7058
7485
|
export {
|
|
7059
7486
|
CONTEXT_CONFIG,
|