@superatomai/sdk-node 0.0.2 → 0.0.3
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 +528 -85
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +361 -174
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +361 -174
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1866,55 +1866,126 @@ import fs3 from "fs";
|
|
|
1866
1866
|
import path3 from "path";
|
|
1867
1867
|
var PromptLoader = class {
|
|
1868
1868
|
constructor(config) {
|
|
1869
|
+
this.promptCache = /* @__PURE__ */ new Map();
|
|
1870
|
+
this.isInitialized = false;
|
|
1869
1871
|
logger.debug("Initializing PromptLoader...", process.cwd());
|
|
1870
1872
|
this.promptsDir = config?.promptsDir || path3.join(process.cwd(), ".prompts");
|
|
1873
|
+
this.defaultPromptsDir = path3.join(__dirname, "..", "..", ".prompts");
|
|
1871
1874
|
}
|
|
1872
1875
|
/**
|
|
1873
|
-
*
|
|
1876
|
+
* Initialize and cache all prompts into memory
|
|
1877
|
+
* This should be called once at SDK startup
|
|
1878
|
+
*/
|
|
1879
|
+
async initialize() {
|
|
1880
|
+
if (this.isInitialized) {
|
|
1881
|
+
logger.debug("PromptLoader already initialized, skipping...");
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1884
|
+
logger.info("Loading prompts into memory...");
|
|
1885
|
+
const promptTypes = [
|
|
1886
|
+
"classify",
|
|
1887
|
+
"match-component",
|
|
1888
|
+
"modify-props",
|
|
1889
|
+
"single-component",
|
|
1890
|
+
"mutli-component",
|
|
1891
|
+
"actions",
|
|
1892
|
+
"container-metadata"
|
|
1893
|
+
];
|
|
1894
|
+
for (const promptType of promptTypes) {
|
|
1895
|
+
try {
|
|
1896
|
+
const template = await this.loadPromptTemplate(promptType);
|
|
1897
|
+
this.promptCache.set(promptType, template);
|
|
1898
|
+
logger.debug(`Cached prompt: ${promptType}`);
|
|
1899
|
+
} catch (error) {
|
|
1900
|
+
logger.error(`Failed to load prompt '${promptType}':`, error);
|
|
1901
|
+
throw error;
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
this.isInitialized = true;
|
|
1905
|
+
logger.info(`Successfully loaded ${this.promptCache.size} prompt templates into memory`);
|
|
1906
|
+
}
|
|
1907
|
+
/**
|
|
1908
|
+
* Load a prompt template from file system (tries custom dir first, then defaults to SDK dir)
|
|
1874
1909
|
* @param promptName - Name of the prompt folder
|
|
1875
|
-
* @
|
|
1876
|
-
* @param variables - Variables to replace in the template
|
|
1877
|
-
* @returns Processed prompt string
|
|
1910
|
+
* @returns Template with system and user prompts
|
|
1878
1911
|
*/
|
|
1879
|
-
async
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
promptName,
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1912
|
+
async loadPromptTemplate(promptName) {
|
|
1913
|
+
const tryLoadFromDir = (dir) => {
|
|
1914
|
+
try {
|
|
1915
|
+
const systemPath = path3.join(dir, promptName, "system.md");
|
|
1916
|
+
const userPath = path3.join(dir, promptName, "user.md");
|
|
1917
|
+
if (fs3.existsSync(systemPath) && fs3.existsSync(userPath)) {
|
|
1918
|
+
const system = fs3.readFileSync(systemPath, "utf-8");
|
|
1919
|
+
const user = fs3.readFileSync(userPath, "utf-8");
|
|
1920
|
+
logger.debug(`Loaded prompt '${promptName}' from ${dir}`);
|
|
1921
|
+
return { system, user };
|
|
1922
|
+
}
|
|
1923
|
+
return null;
|
|
1924
|
+
} catch (error) {
|
|
1925
|
+
return null;
|
|
1892
1926
|
}
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1927
|
+
};
|
|
1928
|
+
let template = tryLoadFromDir(this.promptsDir);
|
|
1929
|
+
if (!template) {
|
|
1930
|
+
logger.warn(`Prompt '${promptName}' not found in ${this.promptsDir}, trying default location...`);
|
|
1931
|
+
template = tryLoadFromDir(this.defaultPromptsDir);
|
|
1932
|
+
}
|
|
1933
|
+
if (!template) {
|
|
1934
|
+
throw new Error(`Prompt template '${promptName}' not found in either ${this.promptsDir} or ${this.defaultPromptsDir}`);
|
|
1935
|
+
}
|
|
1936
|
+
return template;
|
|
1937
|
+
}
|
|
1938
|
+
/**
|
|
1939
|
+
* Replace variables in a template string using {{VARIABLE_NAME}} pattern
|
|
1940
|
+
* @param template - Template string with placeholders
|
|
1941
|
+
* @param variables - Variables to replace in the template
|
|
1942
|
+
* @returns Processed string
|
|
1943
|
+
*/
|
|
1944
|
+
replaceVariables(template, variables) {
|
|
1945
|
+
let content = template;
|
|
1946
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
1947
|
+
const pattern = new RegExp(`{{${key}}}`, "g");
|
|
1948
|
+
const replacementValue = typeof value === "string" ? value : JSON.stringify(value);
|
|
1949
|
+
content = content.replace(pattern, replacementValue);
|
|
1897
1950
|
}
|
|
1951
|
+
return content;
|
|
1898
1952
|
}
|
|
1899
1953
|
/**
|
|
1900
|
-
* Load both system and user prompts and replace variables
|
|
1954
|
+
* Load both system and user prompts from cache and replace variables
|
|
1901
1955
|
* @param promptName - Name of the prompt folder
|
|
1902
1956
|
* @param variables - Variables to replace in the templates
|
|
1903
1957
|
* @returns Object containing both system and user prompts
|
|
1904
1958
|
*/
|
|
1905
1959
|
async loadPrompts(promptName, variables) {
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
this.
|
|
1909
|
-
|
|
1910
|
-
|
|
1960
|
+
if (!this.isInitialized) {
|
|
1961
|
+
logger.warn("PromptLoader not initialized, loading prompts on-demand (not recommended)");
|
|
1962
|
+
await this.initialize();
|
|
1963
|
+
}
|
|
1964
|
+
const template = this.promptCache.get(promptName);
|
|
1965
|
+
if (!template) {
|
|
1966
|
+
throw new Error(`Prompt template '${promptName}' not found in cache. Available prompts: ${Array.from(this.promptCache.keys()).join(", ")}`);
|
|
1967
|
+
}
|
|
1968
|
+
return {
|
|
1969
|
+
system: this.replaceVariables(template.system, variables),
|
|
1970
|
+
user: this.replaceVariables(template.user, variables)
|
|
1971
|
+
};
|
|
1911
1972
|
}
|
|
1912
1973
|
/**
|
|
1913
|
-
*
|
|
1974
|
+
* DEPRECATED: Use loadPrompts instead
|
|
1975
|
+
* Load a single prompt file and replace variables using {{VARIABLE_NAME}} pattern
|
|
1976
|
+
*/
|
|
1977
|
+
async loadPrompt(promptName, promptType, variables) {
|
|
1978
|
+
const prompts = await this.loadPrompts(promptName, variables);
|
|
1979
|
+
return promptType === "system" ? prompts.system : prompts.user;
|
|
1980
|
+
}
|
|
1981
|
+
/**
|
|
1982
|
+
* Set custom prompts directory (requires re-initialization)
|
|
1914
1983
|
* @param dir - Path to the prompts directory
|
|
1915
1984
|
*/
|
|
1916
1985
|
setPromptsDir(dir) {
|
|
1917
1986
|
this.promptsDir = dir;
|
|
1987
|
+
this.isInitialized = false;
|
|
1988
|
+
this.promptCache.clear();
|
|
1918
1989
|
}
|
|
1919
1990
|
/**
|
|
1920
1991
|
* Get current prompts directory
|
|
@@ -1923,8 +1994,23 @@ var PromptLoader = class {
|
|
|
1923
1994
|
getPromptsDir() {
|
|
1924
1995
|
return this.promptsDir;
|
|
1925
1996
|
}
|
|
1997
|
+
/**
|
|
1998
|
+
* Check if prompts are loaded in memory
|
|
1999
|
+
*/
|
|
2000
|
+
isReady() {
|
|
2001
|
+
return this.isInitialized;
|
|
2002
|
+
}
|
|
2003
|
+
/**
|
|
2004
|
+
* Get the number of cached prompts
|
|
2005
|
+
*/
|
|
2006
|
+
getCacheSize() {
|
|
2007
|
+
return this.promptCache.size;
|
|
2008
|
+
}
|
|
1926
2009
|
};
|
|
1927
|
-
var
|
|
2010
|
+
var defaultPromptsPath = process.env.PROMPTS_DIR || path3.join(process.cwd(), ".prompts");
|
|
2011
|
+
var promptLoader = new PromptLoader({
|
|
2012
|
+
promptsDir: defaultPromptsPath
|
|
2013
|
+
});
|
|
1928
2014
|
|
|
1929
2015
|
// src/llm.ts
|
|
1930
2016
|
import Anthropic from "@anthropic-ai/sdk";
|
|
@@ -1982,8 +2068,6 @@ var LLM = class {
|
|
|
1982
2068
|
// ============================================================
|
|
1983
2069
|
static async _anthropicText(messages, modelName, options) {
|
|
1984
2070
|
const apiKey = options.apiKey || process.env.ANTHROPIC_API_KEY || "";
|
|
1985
|
-
console.log("[LLM DEBUG] Anthropic Text - apiKey from options:", options.apiKey ? `${options.apiKey.substring(0, 10)}...` : "NOT SET");
|
|
1986
|
-
console.log("[LLM DEBUG] Anthropic Text - final apiKey:", apiKey ? `${apiKey.substring(0, 10)}...` : "EMPTY STRING");
|
|
1987
2071
|
const client = new Anthropic({
|
|
1988
2072
|
apiKey
|
|
1989
2073
|
});
|
|
@@ -2002,9 +2086,6 @@ var LLM = class {
|
|
|
2002
2086
|
}
|
|
2003
2087
|
static async _anthropicStream(messages, modelName, options, json) {
|
|
2004
2088
|
const apiKey = options.apiKey || process.env.ANTHROPIC_API_KEY || "";
|
|
2005
|
-
console.log("[LLM DEBUG] Anthropic - apiKey from options:", options.apiKey ? `${options.apiKey.substring(0, 10)}...` : "NOT SET");
|
|
2006
|
-
console.log("[LLM DEBUG] Anthropic - apiKey from env:", process.env.ANTHROPIC_API_KEY ? `${process.env.ANTHROPIC_API_KEY.substring(0, 10)}...` : "NOT SET");
|
|
2007
|
-
console.log("[LLM DEBUG] Anthropic - final apiKey:", apiKey ? `${apiKey.substring(0, 10)}...` : "EMPTY STRING");
|
|
2008
2089
|
const client = new Anthropic({
|
|
2009
2090
|
apiKey
|
|
2010
2091
|
});
|
|
@@ -2054,9 +2135,6 @@ var LLM = class {
|
|
|
2054
2135
|
}
|
|
2055
2136
|
static async _groqStream(messages, modelName, options, json) {
|
|
2056
2137
|
const apiKey = options.apiKey || process.env.GROQ_API_KEY || "";
|
|
2057
|
-
console.log("[LLM DEBUG] Groq - apiKey from options:", options.apiKey ? `${options.apiKey.substring(0, 10)}...` : "NOT SET");
|
|
2058
|
-
console.log("[LLM DEBUG] Groq - model:", modelName);
|
|
2059
|
-
console.log("[LLM DEBUG] Groq - final apiKey:", apiKey ? `${apiKey.substring(0, 10)}...` : "EMPTY STRING");
|
|
2060
2138
|
const client = new Groq({
|
|
2061
2139
|
apiKey
|
|
2062
2140
|
});
|
|
@@ -2128,11 +2206,8 @@ var BaseLLM = class {
|
|
|
2128
2206
|
* Classify user question to determine the type and required visualizations
|
|
2129
2207
|
*/
|
|
2130
2208
|
async classifyUserQuestion(userPrompt, apiKey, logCollector, conversationHistory) {
|
|
2131
|
-
const schemaDoc = schema.generateSchemaDocumentation();
|
|
2132
|
-
logger.info("Generating prompts...", userPrompt, conversationHistory);
|
|
2133
2209
|
try {
|
|
2134
2210
|
const prompts = await promptLoader.loadPrompts("classify", {
|
|
2135
|
-
SCHEMA_DOC: schemaDoc || "No schema available",
|
|
2136
2211
|
USER_PROMPT: userPrompt,
|
|
2137
2212
|
CONVERSATION_HISTORY: conversationHistory || "No previous conversation"
|
|
2138
2213
|
});
|
|
@@ -2187,6 +2262,7 @@ var BaseLLM = class {
|
|
|
2187
2262
|
CURRENT_PROPS: JSON.stringify(originalProps, null, 2),
|
|
2188
2263
|
CONVERSATION_HISTORY: conversationHistory || "No previous conversation"
|
|
2189
2264
|
});
|
|
2265
|
+
logger.debug("props-modification: System prompt\n", prompts.system.substring(0, 100), "\n\n\n", "User prompt:", prompts.user.substring(0, 50));
|
|
2190
2266
|
const result = await LLM.stream(
|
|
2191
2267
|
{
|
|
2192
2268
|
sys: prompts.system,
|
|
@@ -2234,21 +2310,47 @@ var BaseLLM = class {
|
|
|
2234
2310
|
}
|
|
2235
2311
|
}
|
|
2236
2312
|
/**
|
|
2237
|
-
*
|
|
2238
|
-
* This
|
|
2313
|
+
* Match and select a component from available components filtered by type
|
|
2314
|
+
* This picks the best matching component based on user prompt and modifies its props
|
|
2239
2315
|
*/
|
|
2240
|
-
async generateAnalyticalComponent(userPrompt, preferredVisualizationType, apiKey, logCollector, conversationHistory) {
|
|
2241
|
-
const schemaDoc = schema.generateSchemaDocumentation();
|
|
2316
|
+
async generateAnalyticalComponent(userPrompt, components, preferredVisualizationType, apiKey, logCollector, conversationHistory) {
|
|
2242
2317
|
try {
|
|
2318
|
+
const filteredComponents = preferredVisualizationType ? components.filter((c) => c.type === preferredVisualizationType) : components;
|
|
2319
|
+
if (filteredComponents.length === 0) {
|
|
2320
|
+
logCollector?.warn(
|
|
2321
|
+
`No components found of type ${preferredVisualizationType}`,
|
|
2322
|
+
"explanation",
|
|
2323
|
+
{ reason: "No matching components available for this visualization type" }
|
|
2324
|
+
);
|
|
2325
|
+
return {
|
|
2326
|
+
component: null,
|
|
2327
|
+
reasoning: `No components available of type ${preferredVisualizationType}`,
|
|
2328
|
+
isGenerated: false
|
|
2329
|
+
};
|
|
2330
|
+
}
|
|
2331
|
+
const componentsText = filteredComponents.map((comp, idx) => {
|
|
2332
|
+
const keywords = comp.keywords ? comp.keywords.join(", ") : "";
|
|
2333
|
+
const category = comp.category || "general";
|
|
2334
|
+
const propsPreview = comp.props ? JSON.stringify(comp.props, null, 2) : "No props";
|
|
2335
|
+
return `${idx + 1}. ID: ${comp.id}
|
|
2336
|
+
Name: ${comp.name}
|
|
2337
|
+
Type: ${comp.type}
|
|
2338
|
+
Category: ${category}
|
|
2339
|
+
Description: ${comp.description || "No description"}
|
|
2340
|
+
Keywords: ${keywords}
|
|
2341
|
+
Props Preview: ${propsPreview}`;
|
|
2342
|
+
}).join("\n\n");
|
|
2243
2343
|
const visualizationConstraint = preferredVisualizationType ? `
|
|
2244
|
-
**IMPORTANT:
|
|
2344
|
+
**IMPORTANT: Components are filtered to type ${preferredVisualizationType}. Select the best match.**
|
|
2245
2345
|
` : "";
|
|
2246
2346
|
const prompts = await promptLoader.loadPrompts("single-component", {
|
|
2247
|
-
|
|
2347
|
+
COMPONENT_TYPE: preferredVisualizationType || "any",
|
|
2348
|
+
COMPONENTS_LIST: componentsText,
|
|
2248
2349
|
VISUALIZATION_CONSTRAINT: visualizationConstraint,
|
|
2249
2350
|
USER_PROMPT: userPrompt,
|
|
2250
2351
|
CONVERSATION_HISTORY: conversationHistory || "No previous conversation"
|
|
2251
2352
|
});
|
|
2353
|
+
logger.debug("single-component: System prompt\n", prompts.system.substring(0, 100), "\n\n\n", "User prompt:", prompts.user.substring(0, 50));
|
|
2252
2354
|
const result = await LLM.stream(
|
|
2253
2355
|
{
|
|
2254
2356
|
sys: prompts.system,
|
|
@@ -2263,53 +2365,63 @@ var BaseLLM = class {
|
|
|
2263
2365
|
true
|
|
2264
2366
|
// Parse as JSON
|
|
2265
2367
|
);
|
|
2266
|
-
if (!result.canGenerate) {
|
|
2368
|
+
if (!result.canGenerate || result.confidence < 50) {
|
|
2267
2369
|
logCollector?.warn(
|
|
2268
|
-
"Cannot
|
|
2370
|
+
"Cannot match component",
|
|
2269
2371
|
"explanation",
|
|
2270
|
-
{ reason: result.reasoning || "Unable to
|
|
2372
|
+
{ reason: result.reasoning || "Unable to find matching component for this question" }
|
|
2271
2373
|
);
|
|
2272
2374
|
return {
|
|
2273
2375
|
component: null,
|
|
2274
|
-
reasoning: result.reasoning || "Unable to
|
|
2376
|
+
reasoning: result.reasoning || "Unable to find matching component for this question",
|
|
2275
2377
|
isGenerated: false
|
|
2276
2378
|
};
|
|
2277
2379
|
}
|
|
2278
|
-
const
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2380
|
+
const componentIndex = result.componentIndex;
|
|
2381
|
+
const componentId = result.componentId;
|
|
2382
|
+
let matchedComponent = null;
|
|
2383
|
+
if (componentId) {
|
|
2384
|
+
matchedComponent = filteredComponents.find((c) => c.id === componentId);
|
|
2385
|
+
}
|
|
2386
|
+
if (!matchedComponent && componentIndex) {
|
|
2387
|
+
matchedComponent = filteredComponents[componentIndex - 1];
|
|
2388
|
+
}
|
|
2389
|
+
if (!matchedComponent) {
|
|
2390
|
+
logCollector?.warn("Component not found in filtered list");
|
|
2391
|
+
return {
|
|
2392
|
+
component: null,
|
|
2393
|
+
reasoning: "Component not found in filtered list",
|
|
2394
|
+
isGenerated: false
|
|
2395
|
+
};
|
|
2396
|
+
}
|
|
2397
|
+
logCollector?.info(`Matched component: ${matchedComponent.name} (confidence: ${result.confidence}%)`);
|
|
2398
|
+
const propsValidation = await this.validateAndModifyProps(
|
|
2399
|
+
userPrompt,
|
|
2400
|
+
matchedComponent.props,
|
|
2401
|
+
matchedComponent.name,
|
|
2402
|
+
matchedComponent.type,
|
|
2403
|
+
matchedComponent.description,
|
|
2404
|
+
apiKey,
|
|
2405
|
+
logCollector,
|
|
2406
|
+
conversationHistory
|
|
2287
2407
|
);
|
|
2408
|
+
const modifiedComponent = {
|
|
2409
|
+
...matchedComponent,
|
|
2410
|
+
props: propsValidation.props
|
|
2411
|
+
};
|
|
2288
2412
|
logCollector?.logExplanation(
|
|
2289
|
-
"Analytical component
|
|
2290
|
-
result.reasoning || "
|
|
2413
|
+
"Analytical component selected and modified",
|
|
2414
|
+
result.reasoning || "Selected component based on analytical question",
|
|
2291
2415
|
{
|
|
2292
|
-
|
|
2293
|
-
|
|
2416
|
+
componentName: matchedComponent.name,
|
|
2417
|
+
componentType: matchedComponent.type,
|
|
2418
|
+
confidence: result.confidence,
|
|
2419
|
+
propsModified: propsValidation.isModified
|
|
2294
2420
|
}
|
|
2295
2421
|
);
|
|
2296
|
-
const dynamicComponent = {
|
|
2297
|
-
id: `dynamic_${Date.now()}`,
|
|
2298
|
-
name: `Dynamic${result.componentType}`,
|
|
2299
|
-
type: result.componentType,
|
|
2300
|
-
description: result.description,
|
|
2301
|
-
category: "dynamic",
|
|
2302
|
-
keywords: [],
|
|
2303
|
-
props: {
|
|
2304
|
-
query,
|
|
2305
|
-
title: result.title,
|
|
2306
|
-
description: result.description,
|
|
2307
|
-
config: result.config || {}
|
|
2308
|
-
}
|
|
2309
|
-
};
|
|
2310
2422
|
return {
|
|
2311
|
-
component:
|
|
2312
|
-
reasoning: result.reasoning || "
|
|
2423
|
+
component: modifiedComponent,
|
|
2424
|
+
reasoning: result.reasoning || "Selected and modified component based on analytical question",
|
|
2313
2425
|
isGenerated: true
|
|
2314
2426
|
};
|
|
2315
2427
|
} catch (error) {
|
|
@@ -2317,6 +2429,51 @@ var BaseLLM = class {
|
|
|
2317
2429
|
throw error;
|
|
2318
2430
|
}
|
|
2319
2431
|
}
|
|
2432
|
+
/**
|
|
2433
|
+
* Generate container metadata (title and description) for multi-component dashboard
|
|
2434
|
+
*/
|
|
2435
|
+
async generateContainerMetadata(userPrompt, visualizationTypes, apiKey, logCollector, conversationHistory) {
|
|
2436
|
+
try {
|
|
2437
|
+
const prompts = await promptLoader.loadPrompts("container-metadata", {
|
|
2438
|
+
USER_PROMPT: userPrompt,
|
|
2439
|
+
VISUALIZATION_TYPES: visualizationTypes.join(", "),
|
|
2440
|
+
CONVERSATION_HISTORY: conversationHistory || "No previous conversation"
|
|
2441
|
+
});
|
|
2442
|
+
const result = await LLM.stream(
|
|
2443
|
+
{
|
|
2444
|
+
sys: prompts.system,
|
|
2445
|
+
user: prompts.user
|
|
2446
|
+
},
|
|
2447
|
+
{
|
|
2448
|
+
model: this.model,
|
|
2449
|
+
maxTokens: 500,
|
|
2450
|
+
temperature: 0.3,
|
|
2451
|
+
apiKey: this.getApiKey(apiKey)
|
|
2452
|
+
},
|
|
2453
|
+
true
|
|
2454
|
+
// Parse as JSON
|
|
2455
|
+
);
|
|
2456
|
+
logCollector?.logExplanation(
|
|
2457
|
+
"Container metadata generated",
|
|
2458
|
+
`Generated title and description for multi-component dashboard`,
|
|
2459
|
+
{
|
|
2460
|
+
title: result.title,
|
|
2461
|
+
description: result.description,
|
|
2462
|
+
visualizationTypes
|
|
2463
|
+
}
|
|
2464
|
+
);
|
|
2465
|
+
return {
|
|
2466
|
+
title: result.title || `${userPrompt} - Dashboard`,
|
|
2467
|
+
description: result.description || `Multi-component dashboard showing ${visualizationTypes.join(", ")}`
|
|
2468
|
+
};
|
|
2469
|
+
} catch (error) {
|
|
2470
|
+
console.error("Error generating container metadata:", error);
|
|
2471
|
+
return {
|
|
2472
|
+
title: `${userPrompt} - Dashboard`,
|
|
2473
|
+
description: `Multi-component dashboard showing ${visualizationTypes.join(", ")}`
|
|
2474
|
+
};
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2320
2477
|
/**
|
|
2321
2478
|
* Match component from a list with enhanced props modification
|
|
2322
2479
|
*/
|
|
@@ -2378,12 +2535,12 @@ var BaseLLM = class {
|
|
|
2378
2535
|
const noMatchMsg = `No matching component found (confidence: ${confidence}%)`;
|
|
2379
2536
|
console.log("\u2717", noMatchMsg);
|
|
2380
2537
|
logCollector?.warn(noMatchMsg);
|
|
2381
|
-
const genMsg = "Attempting to
|
|
2538
|
+
const genMsg = "Attempting to match component from analytical question...";
|
|
2382
2539
|
console.log("\u2713", genMsg);
|
|
2383
2540
|
logCollector?.info(genMsg);
|
|
2384
|
-
const generatedResult = await this.generateAnalyticalComponent(userPrompt, void 0, apiKey, logCollector, conversationHistory);
|
|
2541
|
+
const generatedResult = await this.generateAnalyticalComponent(userPrompt, components, void 0, apiKey, logCollector, conversationHistory);
|
|
2385
2542
|
if (generatedResult.component) {
|
|
2386
|
-
const genSuccessMsg = `Successfully
|
|
2543
|
+
const genSuccessMsg = `Successfully matched component: ${generatedResult.component.name}`;
|
|
2387
2544
|
logCollector?.info(genSuccessMsg);
|
|
2388
2545
|
return {
|
|
2389
2546
|
component: generatedResult.component,
|
|
@@ -2395,10 +2552,10 @@ var BaseLLM = class {
|
|
|
2395
2552
|
queryModified: false
|
|
2396
2553
|
};
|
|
2397
2554
|
}
|
|
2398
|
-
logCollector?.error("Failed to
|
|
2555
|
+
logCollector?.error("Failed to match component");
|
|
2399
2556
|
return {
|
|
2400
2557
|
component: null,
|
|
2401
|
-
reasoning: result.reasoning || "No matching component found and unable to
|
|
2558
|
+
reasoning: result.reasoning || "No matching component found and unable to match component",
|
|
2402
2559
|
method: `${this.getProviderName()}-llm`,
|
|
2403
2560
|
confidence
|
|
2404
2561
|
};
|
|
@@ -2446,15 +2603,15 @@ var BaseLLM = class {
|
|
|
2446
2603
|
}
|
|
2447
2604
|
}
|
|
2448
2605
|
/**
|
|
2449
|
-
*
|
|
2606
|
+
* Match multiple components for analytical questions by visualization types
|
|
2450
2607
|
* This is used when the user needs multiple visualizations
|
|
2451
2608
|
*/
|
|
2452
|
-
async generateMultipleAnalyticalComponents(userPrompt, visualizationTypes, apiKey, logCollector, conversationHistory) {
|
|
2609
|
+
async generateMultipleAnalyticalComponents(userPrompt, availableComponents, visualizationTypes, apiKey, logCollector, conversationHistory) {
|
|
2453
2610
|
try {
|
|
2454
|
-
console.log("\u2713
|
|
2611
|
+
console.log("\u2713 Matching multiple components:", visualizationTypes);
|
|
2455
2612
|
const components = [];
|
|
2456
2613
|
for (const vizType of visualizationTypes) {
|
|
2457
|
-
const result = await this.generateAnalyticalComponent(userPrompt, vizType, apiKey, logCollector, conversationHistory);
|
|
2614
|
+
const result = await this.generateAnalyticalComponent(userPrompt, availableComponents, vizType, apiKey, logCollector, conversationHistory);
|
|
2458
2615
|
if (result.component) {
|
|
2459
2616
|
components.push(result.component);
|
|
2460
2617
|
}
|
|
@@ -2462,75 +2619,45 @@ var BaseLLM = class {
|
|
|
2462
2619
|
if (components.length === 0) {
|
|
2463
2620
|
return {
|
|
2464
2621
|
components: [],
|
|
2465
|
-
reasoning: "Failed to
|
|
2622
|
+
reasoning: "Failed to match any components",
|
|
2466
2623
|
isGenerated: false
|
|
2467
2624
|
};
|
|
2468
2625
|
}
|
|
2469
2626
|
return {
|
|
2470
2627
|
components,
|
|
2471
|
-
reasoning: `
|
|
2628
|
+
reasoning: `Matched ${components.length} components: ${visualizationTypes.join(", ")}`,
|
|
2472
2629
|
isGenerated: true
|
|
2473
2630
|
};
|
|
2474
2631
|
} catch (error) {
|
|
2475
|
-
console.error("Error
|
|
2632
|
+
console.error("Error matching multiple analytical components:", error);
|
|
2476
2633
|
return {
|
|
2477
2634
|
components: [],
|
|
2478
|
-
reasoning: "Error occurred while
|
|
2635
|
+
reasoning: "Error occurred while matching components",
|
|
2479
2636
|
isGenerated: false
|
|
2480
2637
|
};
|
|
2481
2638
|
}
|
|
2482
2639
|
}
|
|
2483
2640
|
/**
|
|
2484
|
-
*
|
|
2641
|
+
* Match multiple components and wrap them in a container
|
|
2485
2642
|
*/
|
|
2486
|
-
async generateMultiComponentResponse(userPrompt, visualizationTypes, apiKey, logCollector, conversationHistory) {
|
|
2487
|
-
const schemaDoc = schema.generateSchemaDocumentation();
|
|
2643
|
+
async generateMultiComponentResponse(userPrompt, availableComponents, visualizationTypes, apiKey, logCollector, conversationHistory) {
|
|
2488
2644
|
try {
|
|
2489
|
-
const
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
const result = await LLM.stream(
|
|
2497
|
-
{
|
|
2498
|
-
sys: prompts.system,
|
|
2499
|
-
user: prompts.user
|
|
2500
|
-
},
|
|
2501
|
-
{
|
|
2502
|
-
model: this.model,
|
|
2503
|
-
maxTokens: 3e3,
|
|
2504
|
-
temperature: 0.2,
|
|
2505
|
-
apiKey: this.getApiKey(apiKey)
|
|
2506
|
-
},
|
|
2507
|
-
true
|
|
2508
|
-
// Parse as JSON
|
|
2645
|
+
const matchResult = await this.generateMultipleAnalyticalComponents(
|
|
2646
|
+
userPrompt,
|
|
2647
|
+
availableComponents,
|
|
2648
|
+
visualizationTypes,
|
|
2649
|
+
apiKey,
|
|
2650
|
+
logCollector,
|
|
2651
|
+
conversationHistory
|
|
2509
2652
|
);
|
|
2510
|
-
if (!
|
|
2653
|
+
if (!matchResult.isGenerated || matchResult.components.length === 0) {
|
|
2511
2654
|
return {
|
|
2512
2655
|
containerComponent: null,
|
|
2513
|
-
reasoning:
|
|
2656
|
+
reasoning: matchResult.reasoning || "Unable to match multi-component dashboard",
|
|
2514
2657
|
isGenerated: false
|
|
2515
2658
|
};
|
|
2516
2659
|
}
|
|
2517
|
-
const generatedComponents =
|
|
2518
|
-
const query = ensureQueryLimit(compData.query, this.defaultLimit);
|
|
2519
|
-
return {
|
|
2520
|
-
id: `dynamic_${compData.componentType.toLowerCase()}_${Date.now()}_${index}`,
|
|
2521
|
-
name: `Dynamic${compData.componentType}`,
|
|
2522
|
-
type: compData.componentType,
|
|
2523
|
-
description: compData.description,
|
|
2524
|
-
category: "dynamic",
|
|
2525
|
-
keywords: [],
|
|
2526
|
-
props: {
|
|
2527
|
-
query,
|
|
2528
|
-
title: compData.title,
|
|
2529
|
-
description: compData.description,
|
|
2530
|
-
config: compData.config || {}
|
|
2531
|
-
}
|
|
2532
|
-
};
|
|
2533
|
-
});
|
|
2660
|
+
const generatedComponents = matchResult.components;
|
|
2534
2661
|
generatedComponents.forEach((component, index) => {
|
|
2535
2662
|
if (component.props.query) {
|
|
2536
2663
|
logCollector?.logQuery(
|
|
@@ -2545,21 +2672,24 @@ var BaseLLM = class {
|
|
|
2545
2672
|
);
|
|
2546
2673
|
}
|
|
2547
2674
|
});
|
|
2675
|
+
const containerTitle = `${userPrompt} - Dashboard`;
|
|
2676
|
+
const containerDescription = `Multi-component dashboard showing ${visualizationTypes.join(", ")}`;
|
|
2548
2677
|
logCollector?.logExplanation(
|
|
2549
|
-
"Multi-component dashboard
|
|
2550
|
-
|
|
2678
|
+
"Multi-component dashboard matched",
|
|
2679
|
+
matchResult.reasoning || `Matched ${generatedComponents.length} components for comprehensive analysis`,
|
|
2551
2680
|
{
|
|
2552
2681
|
totalComponents: generatedComponents.length,
|
|
2553
2682
|
componentTypes: generatedComponents.map((c) => c.type),
|
|
2554
|
-
|
|
2555
|
-
|
|
2683
|
+
componentNames: generatedComponents.map((c) => c.name),
|
|
2684
|
+
containerTitle,
|
|
2685
|
+
containerDescription
|
|
2556
2686
|
}
|
|
2557
2687
|
);
|
|
2558
2688
|
const containerComponent = {
|
|
2559
2689
|
id: `multi_container_${Date.now()}`,
|
|
2560
2690
|
name: "MultiComponentContainer",
|
|
2561
2691
|
type: "Container",
|
|
2562
|
-
description:
|
|
2692
|
+
description: containerDescription,
|
|
2563
2693
|
category: "dynamic",
|
|
2564
2694
|
keywords: ["multi", "container", "dashboard"],
|
|
2565
2695
|
props: {
|
|
@@ -2567,14 +2697,14 @@ var BaseLLM = class {
|
|
|
2567
2697
|
components: generatedComponents,
|
|
2568
2698
|
layout: "grid",
|
|
2569
2699
|
spacing: 24,
|
|
2570
|
-
title:
|
|
2571
|
-
description:
|
|
2700
|
+
title: containerTitle,
|
|
2701
|
+
description: containerDescription
|
|
2572
2702
|
}
|
|
2573
2703
|
}
|
|
2574
2704
|
};
|
|
2575
2705
|
return {
|
|
2576
2706
|
containerComponent,
|
|
2577
|
-
reasoning:
|
|
2707
|
+
reasoning: matchResult.reasoning || `Matched multi-component dashboard with ${generatedComponents.length} components`,
|
|
2578
2708
|
isGenerated: true
|
|
2579
2709
|
};
|
|
2580
2710
|
} catch (error) {
|
|
@@ -2595,41 +2725,89 @@ var BaseLLM = class {
|
|
|
2595
2725
|
const classInfo = `Question type: ${classification.questionType}, Visualizations: ${classification.visualizations.join(", ") || "None"}, Multiple components: ${classification.needsMultipleComponents}`;
|
|
2596
2726
|
logCollector?.info(classInfo);
|
|
2597
2727
|
if (classification.questionType === "analytical") {
|
|
2598
|
-
if (classification.visualizations.length >
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2728
|
+
if (classification.visualizations.length > 1) {
|
|
2729
|
+
const multiMsg = `Matching ${classification.visualizations.length} components for types: ${classification.visualizations.join(", ")}`;
|
|
2730
|
+
logCollector?.info(multiMsg);
|
|
2731
|
+
const matchedComponents = [];
|
|
2732
|
+
for (const vizType of classification.visualizations) {
|
|
2733
|
+
logCollector?.info(`Matching component for type: ${vizType}`);
|
|
2734
|
+
const result = await this.generateAnalyticalComponent(
|
|
2603
2735
|
userPrompt,
|
|
2604
|
-
|
|
2736
|
+
components,
|
|
2737
|
+
vizType,
|
|
2605
2738
|
apiKey,
|
|
2606
2739
|
logCollector,
|
|
2607
2740
|
conversationHistory
|
|
2608
2741
|
);
|
|
2742
|
+
if (result.component) {
|
|
2743
|
+
matchedComponents.push(result.component);
|
|
2744
|
+
logCollector?.info(`Matched: ${result.component.name}`);
|
|
2745
|
+
} else {
|
|
2746
|
+
logCollector?.warn(`Failed to match component for type: ${vizType}`);
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
if (matchedComponents.length === 0) {
|
|
2609
2750
|
return {
|
|
2610
|
-
component:
|
|
2611
|
-
reasoning:
|
|
2612
|
-
method: "classification-multi-
|
|
2751
|
+
component: null,
|
|
2752
|
+
reasoning: "Failed to match any components for the requested visualization types",
|
|
2753
|
+
method: "classification-multi-failed",
|
|
2613
2754
|
questionType: classification.questionType,
|
|
2614
2755
|
needsMultipleComponents: true,
|
|
2615
2756
|
propsModified: false,
|
|
2616
2757
|
queryModified: false
|
|
2617
2758
|
};
|
|
2618
|
-
} else {
|
|
2619
|
-
const vizType = classification.visualizations[0];
|
|
2620
|
-
const result = await this.generateAnalyticalComponent(userPrompt, vizType, apiKey, logCollector, conversationHistory);
|
|
2621
|
-
return {
|
|
2622
|
-
component: result.component,
|
|
2623
|
-
reasoning: result.reasoning,
|
|
2624
|
-
method: "classification-generated",
|
|
2625
|
-
questionType: classification.questionType,
|
|
2626
|
-
needsMultipleComponents: false,
|
|
2627
|
-
propsModified: false,
|
|
2628
|
-
queryModified: false
|
|
2629
|
-
};
|
|
2630
2759
|
}
|
|
2760
|
+
logCollector?.info("Generating container metadata...");
|
|
2761
|
+
const containerMetadata = await this.generateContainerMetadata(
|
|
2762
|
+
userPrompt,
|
|
2763
|
+
classification.visualizations,
|
|
2764
|
+
apiKey,
|
|
2765
|
+
logCollector,
|
|
2766
|
+
conversationHistory
|
|
2767
|
+
);
|
|
2768
|
+
const containerComponent = {
|
|
2769
|
+
id: `multi_container_${Date.now()}`,
|
|
2770
|
+
name: "MultiComponentContainer",
|
|
2771
|
+
type: "Container",
|
|
2772
|
+
description: containerMetadata.description,
|
|
2773
|
+
category: "dynamic",
|
|
2774
|
+
keywords: ["multi", "container", "dashboard"],
|
|
2775
|
+
props: {
|
|
2776
|
+
config: {
|
|
2777
|
+
components: matchedComponents,
|
|
2778
|
+
layout: "grid",
|
|
2779
|
+
spacing: 24,
|
|
2780
|
+
title: containerMetadata.title,
|
|
2781
|
+
description: containerMetadata.description
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
};
|
|
2785
|
+
logCollector?.info(`Created multi-component container with ${matchedComponents.length} components: "${containerMetadata.title}"`);
|
|
2786
|
+
return {
|
|
2787
|
+
component: containerComponent,
|
|
2788
|
+
reasoning: `Matched ${matchedComponents.length} components for visualization types: ${classification.visualizations.join(", ")}`,
|
|
2789
|
+
method: "classification-multi-generated",
|
|
2790
|
+
questionType: classification.questionType,
|
|
2791
|
+
needsMultipleComponents: true,
|
|
2792
|
+
propsModified: false,
|
|
2793
|
+
queryModified: false
|
|
2794
|
+
};
|
|
2795
|
+
} else if (classification.visualizations.length === 1) {
|
|
2796
|
+
const vizType = classification.visualizations[0];
|
|
2797
|
+
logCollector?.info(`Matching single component for type: ${vizType}`);
|
|
2798
|
+
const result = await this.generateAnalyticalComponent(userPrompt, components, vizType, apiKey, logCollector, conversationHistory);
|
|
2799
|
+
return {
|
|
2800
|
+
component: result.component,
|
|
2801
|
+
reasoning: result.reasoning,
|
|
2802
|
+
method: "classification-generated",
|
|
2803
|
+
questionType: classification.questionType,
|
|
2804
|
+
needsMultipleComponents: false,
|
|
2805
|
+
propsModified: false,
|
|
2806
|
+
queryModified: false
|
|
2807
|
+
};
|
|
2631
2808
|
} else {
|
|
2632
|
-
|
|
2809
|
+
logCollector?.info("No specific visualization type - matching from all components");
|
|
2810
|
+
const result = await this.generateAnalyticalComponent(userPrompt, components, void 0, apiKey, logCollector, conversationHistory);
|
|
2633
2811
|
return {
|
|
2634
2812
|
component: result.component,
|
|
2635
2813
|
reasoning: result.reasoning,
|
|
@@ -2640,7 +2818,7 @@ var BaseLLM = class {
|
|
|
2640
2818
|
queryModified: false
|
|
2641
2819
|
};
|
|
2642
2820
|
}
|
|
2643
|
-
} else if (classification.questionType === "data_modification") {
|
|
2821
|
+
} else if (classification.questionType === "data_modification" || classification.questionType === "general") {
|
|
2644
2822
|
const matchMsg = "Using component matching for data modification...";
|
|
2645
2823
|
logCollector?.info(matchMsg);
|
|
2646
2824
|
const matchResult = await this.matchComponent(userPrompt, components, apiKey, logCollector, conversationHistory);
|
|
@@ -2788,7 +2966,6 @@ var useAnthropicMethod = async (prompt, components, apiKey, logCollector, conver
|
|
|
2788
2966
|
}
|
|
2789
2967
|
try {
|
|
2790
2968
|
const matchResult = await anthropicLLM.handleUserRequest(prompt, components, apiKey, logCollector, conversationHistory);
|
|
2791
|
-
logger.debug(`Anthropic method success: ${matchResult}`);
|
|
2792
2969
|
return { success: true, data: matchResult };
|
|
2793
2970
|
} catch (error) {
|
|
2794
2971
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
@@ -2842,7 +3019,6 @@ var get_user_response = async (prompt, components, anthropicApiKey, groqApiKey,
|
|
|
2842
3019
|
let result;
|
|
2843
3020
|
if (provider === "anthropic") {
|
|
2844
3021
|
result = await useAnthropicMethod(prompt, components, anthropicApiKey, logCollector, conversationHistory);
|
|
2845
|
-
logger.debug("Anthropic result:", result);
|
|
2846
3022
|
} else if (provider === "groq") {
|
|
2847
3023
|
result = await useGroqMethod(prompt, components, groqApiKey, logCollector, conversationHistory);
|
|
2848
3024
|
} else {
|
|
@@ -3043,7 +3219,6 @@ async function handleUserPromptRequest(data, components, sendMessage, anthropicA
|
|
|
3043
3219
|
const SA_RUNTIME = payload.SA_RUNTIME;
|
|
3044
3220
|
const wsId = userPromptRequest.from.id || "unknown";
|
|
3045
3221
|
logger.info(`[REQUEST ${id}] Processing user prompt: "${prompt.substring(0, 50)}..."`);
|
|
3046
|
-
logger.info(`[REQUEST ${id}] Providers: ${llmProviders?.join(", ")}, Anthropic key: ${anthropicApiKey ? "SET" : "NOT SET"}, Groq key: ${groqApiKey ? "SET" : "NOT SET"}`);
|
|
3047
3222
|
if (processedMessageIds.has(id)) {
|
|
3048
3223
|
logger.warn(`[REQUEST ${id}] Duplicate request detected - ignoring`);
|
|
3049
3224
|
return;
|
|
@@ -3094,7 +3269,6 @@ async function handleUserPromptRequest(data, components, sendMessage, anthropicA
|
|
|
3094
3269
|
return;
|
|
3095
3270
|
}
|
|
3096
3271
|
logCollector.info(`Starting user prompt request with ${components.length} components`);
|
|
3097
|
-
logger.info(`components length: ${components.length}`);
|
|
3098
3272
|
const threadManager = ThreadManager.getInstance();
|
|
3099
3273
|
let thread = threadManager.getThread(threadId);
|
|
3100
3274
|
if (!thread) {
|
|
@@ -3104,7 +3278,6 @@ async function handleUserPromptRequest(data, components, sendMessage, anthropicA
|
|
|
3104
3278
|
const conversationHistory = thread.getConversationContext(CONTEXT_CONFIG.MAX_CONVERSATION_CONTEXT_BLOCKS, existingUiBlockId);
|
|
3105
3279
|
const userResponse = await get_user_response(prompt, components, anthropicApiKey, groqApiKey, llmProviders, logCollector, conversationHistory);
|
|
3106
3280
|
logCollector.info("User prompt request completed");
|
|
3107
|
-
logger.info(`[REQUEST ${id}] Response success: ${userResponse.success}, reason: ${userResponse.success ? "N/A" : userResponse}`);
|
|
3108
3281
|
if (userResponse.success && userResponse.data && typeof userResponse.data === "object" && "component" in userResponse.data) {
|
|
3109
3282
|
const component = userResponse.data.component;
|
|
3110
3283
|
const uiBlockId = existingUiBlockId;
|
|
@@ -3146,10 +3319,6 @@ function sendDataResponse4(id, res, sendMessage, clientId) {
|
|
|
3146
3319
|
...res
|
|
3147
3320
|
}
|
|
3148
3321
|
};
|
|
3149
|
-
logger.info(`[REQUEST ${id}] Sending USER_PROMPT_RES with success=${res.success}`);
|
|
3150
|
-
if (!res.success && res.reason) {
|
|
3151
|
-
logger.info(`[REQUEST ${id}] Error reason: ${res.reason}`);
|
|
3152
|
-
}
|
|
3153
3322
|
sendMessage(response);
|
|
3154
3323
|
}
|
|
3155
3324
|
|
|
@@ -4848,6 +5017,9 @@ var SuperatomSDK = class {
|
|
|
4848
5017
|
this.userManager = new UserManager(this.projectId, 5e3);
|
|
4849
5018
|
this.dashboardManager = new DashboardManager(this.projectId);
|
|
4850
5019
|
this.reportManager = new ReportManager(this.projectId);
|
|
5020
|
+
this.initializePromptLoader(config.promptsDir).catch((error) => {
|
|
5021
|
+
logger.error("Failed to initialize PromptLoader:", error);
|
|
5022
|
+
});
|
|
4851
5023
|
this.initializeUserManager().catch((error) => {
|
|
4852
5024
|
logger.error("Failed to initialize UserManager:", error);
|
|
4853
5025
|
});
|
|
@@ -4857,6 +5029,21 @@ var SuperatomSDK = class {
|
|
|
4857
5029
|
logger.error("Failed to connect to Superatom:", error);
|
|
4858
5030
|
});
|
|
4859
5031
|
}
|
|
5032
|
+
/**
|
|
5033
|
+
* Initialize PromptLoader and load prompts into memory
|
|
5034
|
+
*/
|
|
5035
|
+
async initializePromptLoader(promptsDir) {
|
|
5036
|
+
try {
|
|
5037
|
+
if (promptsDir) {
|
|
5038
|
+
promptLoader.setPromptsDir(promptsDir);
|
|
5039
|
+
}
|
|
5040
|
+
await promptLoader.initialize();
|
|
5041
|
+
logger.info(`PromptLoader initialized with ${promptLoader.getCacheSize()} prompts from ${promptLoader.getPromptsDir()}`);
|
|
5042
|
+
} catch (error) {
|
|
5043
|
+
logger.error("Failed to initialize PromptLoader:", error);
|
|
5044
|
+
throw error;
|
|
5045
|
+
}
|
|
5046
|
+
}
|
|
4860
5047
|
/**
|
|
4861
5048
|
* Initialize UserManager for the project
|
|
4862
5049
|
*/
|