@superatomai/sdk-node 0.0.45-mds → 0.0.46-mds
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 +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +117 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +117 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1708,6 +1708,16 @@ declare class LLM {
|
|
|
1708
1708
|
* @returns Normalized system prompt for Anthropic API
|
|
1709
1709
|
*/
|
|
1710
1710
|
private static _normalizeSystemPrompt;
|
|
1711
|
+
/**
|
|
1712
|
+
* Strip unpaired UTF-16 surrogates from every text field of a message set.
|
|
1713
|
+
*
|
|
1714
|
+
* A lone surrogate (from mid-pair string slicing or corrupt source data)
|
|
1715
|
+
* serializes to a bare `\udXXX` escape that strict JSON parsers — including
|
|
1716
|
+
* the one on Anthropic's API — reject with "no low surrogate in string",
|
|
1717
|
+
* failing the whole request. Sanitizing here, at the single boundary every
|
|
1718
|
+
* provider call flows through, guarantees no request can carry one.
|
|
1719
|
+
*/
|
|
1720
|
+
private static _sanitizeMessages;
|
|
1711
1721
|
/**
|
|
1712
1722
|
* Log cache usage metrics from Anthropic API response
|
|
1713
1723
|
* Shows cache hits, costs, and savings
|
package/dist/index.d.ts
CHANGED
|
@@ -1708,6 +1708,16 @@ declare class LLM {
|
|
|
1708
1708
|
* @returns Normalized system prompt for Anthropic API
|
|
1709
1709
|
*/
|
|
1710
1710
|
private static _normalizeSystemPrompt;
|
|
1711
|
+
/**
|
|
1712
|
+
* Strip unpaired UTF-16 surrogates from every text field of a message set.
|
|
1713
|
+
*
|
|
1714
|
+
* A lone surrogate (from mid-pair string slicing or corrupt source data)
|
|
1715
|
+
* serializes to a bare `\udXXX` escape that strict JSON parsers — including
|
|
1716
|
+
* the one on Anthropic's API — reject with "no low surrogate in string",
|
|
1717
|
+
* failing the whole request. Sanitizing here, at the single boundary every
|
|
1718
|
+
* provider call flows through, guarantees no request can carry one.
|
|
1719
|
+
*/
|
|
1720
|
+
private static _sanitizeMessages;
|
|
1711
1721
|
/**
|
|
1712
1722
|
* Log cache usage metrics from Anthropic API response
|
|
1713
1723
|
* Shows cache hits, costs, and savings
|
package/dist/index.js
CHANGED
|
@@ -1738,6 +1738,21 @@ var QueryCache = class {
|
|
|
1738
1738
|
};
|
|
1739
1739
|
var queryCache = new QueryCache();
|
|
1740
1740
|
|
|
1741
|
+
// src/utils/surrogate.ts
|
|
1742
|
+
var LONE_SURROGATE_RE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
|
|
1743
|
+
function stripLoneSurrogates(value) {
|
|
1744
|
+
if (typeof value !== "string") return value;
|
|
1745
|
+
if (!/[\uD800-\uDFFF]/.test(value)) return value;
|
|
1746
|
+
return value.replace(LONE_SURROGATE_RE, "\uFFFD");
|
|
1747
|
+
}
|
|
1748
|
+
function safeTruncate(text, maxUnits) {
|
|
1749
|
+
if (typeof text !== "string" || text.length <= maxUnits || maxUnits < 0) return text;
|
|
1750
|
+
let end = maxUnits;
|
|
1751
|
+
const lastCode = text.charCodeAt(end - 1);
|
|
1752
|
+
if (lastCode >= 55296 && lastCode <= 56319) end -= 1;
|
|
1753
|
+
return text.slice(0, end);
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1741
1756
|
// src/userResponse/llm-result-truncator.ts
|
|
1742
1757
|
var DEFAULT_MAX_ROWS = 10;
|
|
1743
1758
|
var DEFAULT_MAX_CHARS_PER_FIELD = 500;
|
|
@@ -1780,12 +1795,12 @@ function isDateString(value) {
|
|
|
1780
1795
|
}
|
|
1781
1796
|
function truncateTextField(value, maxLength) {
|
|
1782
1797
|
if (value.length <= maxLength) {
|
|
1783
|
-
return { text: value, wasTruncated: false };
|
|
1798
|
+
return { text: stripLoneSurrogates(value), wasTruncated: false };
|
|
1784
1799
|
}
|
|
1785
|
-
const truncated = value
|
|
1786
|
-
const remaining = value.length -
|
|
1800
|
+
const truncated = safeTruncate(value, maxLength);
|
|
1801
|
+
const remaining = value.length - truncated.length;
|
|
1787
1802
|
return {
|
|
1788
|
-
text: `${truncated}... (${remaining} more chars)`,
|
|
1803
|
+
text: `${stripLoneSurrogates(truncated)}... (${remaining} more chars)`,
|
|
1789
1804
|
wasTruncated: true
|
|
1790
1805
|
};
|
|
1791
1806
|
}
|
|
@@ -5642,6 +5657,7 @@ var LLM = class {
|
|
|
5642
5657
|
/* Get a complete text response from an LLM (Anthropic or Groq) */
|
|
5643
5658
|
static async text(messages, options = {}) {
|
|
5644
5659
|
const [provider, modelName] = this._parseModel(options.model);
|
|
5660
|
+
messages = this._sanitizeMessages(messages);
|
|
5645
5661
|
if (provider === "anthropic") {
|
|
5646
5662
|
return this._anthropicText(messages, modelName, options);
|
|
5647
5663
|
} else if (provider === "groq") {
|
|
@@ -5657,6 +5673,7 @@ var LLM = class {
|
|
|
5657
5673
|
/* Stream response from an LLM (Anthropic or Groq) */
|
|
5658
5674
|
static async stream(messages, options = {}, json) {
|
|
5659
5675
|
const [provider, modelName] = this._parseModel(options.model);
|
|
5676
|
+
messages = this._sanitizeMessages(messages);
|
|
5660
5677
|
if (provider === "anthropic") {
|
|
5661
5678
|
return this._anthropicStream(messages, modelName, options, json);
|
|
5662
5679
|
} else if (provider === "groq") {
|
|
@@ -5672,6 +5689,7 @@ var LLM = class {
|
|
|
5672
5689
|
/* Stream response with tool calling support (Anthropic and Gemini) */
|
|
5673
5690
|
static async streamWithTools(messages, tools, toolHandler, options = {}, maxIterations = 3) {
|
|
5674
5691
|
const [provider, modelName] = this._parseModel(options.model);
|
|
5692
|
+
messages = this._sanitizeMessages(messages);
|
|
5675
5693
|
if (provider === "anthropic") {
|
|
5676
5694
|
return this._anthropicStreamWithTools(messages, tools, toolHandler, modelName, options, maxIterations);
|
|
5677
5695
|
} else if (provider === "gemini") {
|
|
@@ -5697,6 +5715,26 @@ var LLM = class {
|
|
|
5697
5715
|
}
|
|
5698
5716
|
return sys;
|
|
5699
5717
|
}
|
|
5718
|
+
/**
|
|
5719
|
+
* Strip unpaired UTF-16 surrogates from every text field of a message set.
|
|
5720
|
+
*
|
|
5721
|
+
* A lone surrogate (from mid-pair string slicing or corrupt source data)
|
|
5722
|
+
* serializes to a bare `\udXXX` escape that strict JSON parsers — including
|
|
5723
|
+
* the one on Anthropic's API — reject with "no low surrogate in string",
|
|
5724
|
+
* failing the whole request. Sanitizing here, at the single boundary every
|
|
5725
|
+
* provider call flows through, guarantees no request can carry one.
|
|
5726
|
+
*/
|
|
5727
|
+
static _sanitizeMessages(messages) {
|
|
5728
|
+
const sys = typeof messages.sys === "string" ? stripLoneSurrogates(messages.sys) : messages.sys.map(
|
|
5729
|
+
(block) => block?.type === "text" && typeof block.text === "string" ? { ...block, text: stripLoneSurrogates(block.text) } : block
|
|
5730
|
+
);
|
|
5731
|
+
return {
|
|
5732
|
+
...messages,
|
|
5733
|
+
sys,
|
|
5734
|
+
user: stripLoneSurrogates(messages.user),
|
|
5735
|
+
...messages.prefill !== void 0 && { prefill: stripLoneSurrogates(messages.prefill) }
|
|
5736
|
+
};
|
|
5737
|
+
}
|
|
5700
5738
|
/**
|
|
5701
5739
|
* Log cache usage metrics from Anthropic API response
|
|
5702
5740
|
* Shows cache hits, costs, and savings
|
|
@@ -6076,12 +6114,14 @@ var LLM = class {
|
|
|
6076
6114
|
let resultContent = typeof result === "string" ? result : JSON.stringify(result);
|
|
6077
6115
|
const MAX_RESULT_LENGTH = 5e4;
|
|
6078
6116
|
if (resultContent.length > MAX_RESULT_LENGTH) {
|
|
6079
|
-
resultContent = resultContent
|
|
6117
|
+
resultContent = safeTruncate(resultContent, MAX_RESULT_LENGTH) + "\n\n... [Result truncated - showing first 50000 characters of " + resultContent.length + " total]";
|
|
6080
6118
|
}
|
|
6081
6119
|
return {
|
|
6082
6120
|
type: "tool_result",
|
|
6083
6121
|
tool_use_id: toolUse.id,
|
|
6084
|
-
|
|
6122
|
+
// Final safety net: tool results carry source data and are built
|
|
6123
|
+
// mid-loop (after entry-point sanitize), so strip lone surrogates here.
|
|
6124
|
+
content: stripLoneSurrogates(resultContent)
|
|
6085
6125
|
};
|
|
6086
6126
|
} catch (error) {
|
|
6087
6127
|
return {
|
|
@@ -6596,11 +6636,12 @@ var LLM = class {
|
|
|
6596
6636
|
let resultContent = typeof result2 === "string" ? result2 : JSON.stringify(result2);
|
|
6597
6637
|
const MAX_RESULT_LENGTH = 5e4;
|
|
6598
6638
|
if (resultContent.length > MAX_RESULT_LENGTH) {
|
|
6599
|
-
resultContent = resultContent
|
|
6639
|
+
resultContent = safeTruncate(resultContent, MAX_RESULT_LENGTH) + "\n\n... [Result truncated - showing first 50000 characters of " + resultContent.length + " total]";
|
|
6600
6640
|
}
|
|
6601
6641
|
return {
|
|
6602
6642
|
name: fc.name,
|
|
6603
|
-
|
|
6643
|
+
// Final safety net: strip lone surrogates from source-data results.
|
|
6644
|
+
response: { result: stripLoneSurrogates(resultContent) }
|
|
6604
6645
|
};
|
|
6605
6646
|
} catch (error) {
|
|
6606
6647
|
return {
|
|
@@ -6873,12 +6914,12 @@ var LLM = class {
|
|
|
6873
6914
|
result = typeof toolResult === "string" ? toolResult : JSON.stringify(toolResult);
|
|
6874
6915
|
const MAX_RESULT_LENGTH = 5e4;
|
|
6875
6916
|
if (result.length > MAX_RESULT_LENGTH) {
|
|
6876
|
-
result = result
|
|
6917
|
+
result = safeTruncate(result, MAX_RESULT_LENGTH) + "\n\n... [Result truncated - showing first 50000 characters of " + result.length + " total]";
|
|
6877
6918
|
}
|
|
6878
6919
|
} catch (error) {
|
|
6879
6920
|
result = JSON.stringify({ error: error instanceof Error ? error.message : String(error) });
|
|
6880
6921
|
}
|
|
6881
|
-
return { role: "tool", tool_call_id: tc.id, content: result };
|
|
6922
|
+
return { role: "tool", tool_call_id: tc.id, content: stripLoneSurrogates(result) };
|
|
6882
6923
|
}));
|
|
6883
6924
|
toolCallResults.forEach((r) => conversationMessages.push(r));
|
|
6884
6925
|
}
|
|
@@ -7982,7 +8023,7 @@ Execution time: ${metadata.executionTimeMs}ms
|
|
|
7982
8023
|
const truncatedRow = {};
|
|
7983
8024
|
for (const [key, value] of Object.entries(row)) {
|
|
7984
8025
|
if (typeof value === "string" && value.length > 200) {
|
|
7985
|
-
truncatedRow[key] = value
|
|
8026
|
+
truncatedRow[key] = safeTruncate(value, 200) + "...";
|
|
7986
8027
|
} else {
|
|
7987
8028
|
truncatedRow[key] = value;
|
|
7988
8029
|
}
|
|
@@ -15119,7 +15160,7 @@ Fixed SQL query:`;
|
|
|
15119
15160
|
}
|
|
15120
15161
|
|
|
15121
15162
|
// src/dashComp/create-filter.ts
|
|
15122
|
-
async function createFilterWithLLM(prompt, components, existingComponents, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, tools, dashCompModels, collections) {
|
|
15163
|
+
async function createFilterWithLLM(prompt, components, existingComponents, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, tools, dashCompModels, collections, userId) {
|
|
15123
15164
|
const errors = [];
|
|
15124
15165
|
try {
|
|
15125
15166
|
const filterComponents = components.filter((c) => c.type.startsWith("Filter"));
|
|
@@ -15139,6 +15180,25 @@ async function createFilterWithLLM(prompt, components, existingComponents, anthr
|
|
|
15139
15180
|
schemaDoc = schema.generateSchemaDocumentation();
|
|
15140
15181
|
}
|
|
15141
15182
|
const databaseRules = await promptLoader.loadDatabaseRules();
|
|
15183
|
+
let globalKnowledgeBase = "No global knowledge base available.";
|
|
15184
|
+
let knowledgeBaseContext = "No additional knowledge base context available.";
|
|
15185
|
+
if (collections) {
|
|
15186
|
+
const kbResult = await knowledge_base_default.getAllKnowledgeBase({
|
|
15187
|
+
prompt,
|
|
15188
|
+
collections,
|
|
15189
|
+
userId,
|
|
15190
|
+
topK: KNOWLEDGE_BASE_TOP_K
|
|
15191
|
+
});
|
|
15192
|
+
globalKnowledgeBase = kbResult.globalContext || globalKnowledgeBase;
|
|
15193
|
+
const dynamicParts = [];
|
|
15194
|
+
if (kbResult.userContext) {
|
|
15195
|
+
dynamicParts.push("## User-Specific Knowledge Base\n" + kbResult.userContext);
|
|
15196
|
+
}
|
|
15197
|
+
if (kbResult.queryContext) {
|
|
15198
|
+
dynamicParts.push("## Relevant Knowledge Base (Query-Matched)\n" + kbResult.queryContext);
|
|
15199
|
+
}
|
|
15200
|
+
knowledgeBaseContext = dynamicParts.join("\n\n") || knowledgeBaseContext;
|
|
15201
|
+
}
|
|
15142
15202
|
const prompts = await promptLoader.loadPrompts("dash-filter-picker", {
|
|
15143
15203
|
USER_PROMPT: prompt,
|
|
15144
15204
|
AVAILABLE_COMPONENTS: formatComponentsForPrompt(filterComponents),
|
|
@@ -15146,8 +15206,12 @@ async function createFilterWithLLM(prompt, components, existingComponents, anthr
|
|
|
15146
15206
|
SCHEMA_DOC: schemaDoc || "No database schema available",
|
|
15147
15207
|
DATABASE_RULES: databaseRules,
|
|
15148
15208
|
AVAILABLE_TOOLS: formatToolsForPrompt(tools),
|
|
15149
|
-
CURRENT_DATETIME: getCurrentDateTimeForPrompt()
|
|
15209
|
+
CURRENT_DATETIME: getCurrentDateTimeForPrompt(),
|
|
15210
|
+
GLOBAL_KNOWLEDGE_BASE: globalKnowledgeBase,
|
|
15211
|
+
KNOWLEDGE_BASE_CONTEXT: knowledgeBaseContext
|
|
15150
15212
|
});
|
|
15213
|
+
logger.logLLMPrompt("dashFilterPicker", "system", extractPromptText(prompts.system));
|
|
15214
|
+
logger.logLLMPrompt("dashFilterPicker", "user", prompts.user);
|
|
15151
15215
|
logger.debug("[DASH_COMP_REQ:FILTER] Loaded dash-filter-picker prompts");
|
|
15152
15216
|
const { apiKey, model } = getApiKeyAndModel(
|
|
15153
15217
|
anthropicApiKey,
|
|
@@ -15521,7 +15585,8 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
|
|
|
15521
15585
|
llmProviders,
|
|
15522
15586
|
tools,
|
|
15523
15587
|
dashCompModels,
|
|
15524
|
-
collections
|
|
15588
|
+
collections,
|
|
15589
|
+
userId
|
|
15525
15590
|
);
|
|
15526
15591
|
} else {
|
|
15527
15592
|
llmResponse = await pickComponentWithLLM(
|
|
@@ -15675,7 +15740,7 @@ function sendReportCompResponse(id, res, sendMessage, clientId) {
|
|
|
15675
15740
|
}
|
|
15676
15741
|
|
|
15677
15742
|
// src/reportComp/generate-report.ts
|
|
15678
|
-
async function generateReportComponents(prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools, modelConfig, conversationHistory) {
|
|
15743
|
+
async function generateReportComponents(prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, tools, modelConfig, conversationHistory, userId) {
|
|
15679
15744
|
const errors = [];
|
|
15680
15745
|
const availableComponentsText = formatComponentsForPrompt2(components);
|
|
15681
15746
|
const availableToolsText = formatToolsForPrompt2(tools);
|
|
@@ -15691,6 +15756,25 @@ async function generateReportComponents(prompt, components, anthropicApiKey, gro
|
|
|
15691
15756
|
schemaDoc = schema.generateSchemaDocumentation();
|
|
15692
15757
|
}
|
|
15693
15758
|
const databaseRules = await promptLoader.loadDatabaseRules();
|
|
15759
|
+
let globalKnowledgeBase = "No global knowledge base available.";
|
|
15760
|
+
let knowledgeBaseContext = "No additional knowledge base context available.";
|
|
15761
|
+
if (collections) {
|
|
15762
|
+
const kbResult = await knowledge_base_default.getAllKnowledgeBase({
|
|
15763
|
+
prompt,
|
|
15764
|
+
collections,
|
|
15765
|
+
userId,
|
|
15766
|
+
topK: KNOWLEDGE_BASE_TOP_K
|
|
15767
|
+
});
|
|
15768
|
+
globalKnowledgeBase = kbResult.globalContext || globalKnowledgeBase;
|
|
15769
|
+
const dynamicParts = [];
|
|
15770
|
+
if (kbResult.userContext) {
|
|
15771
|
+
dynamicParts.push("## User-Specific Knowledge Base\n" + kbResult.userContext);
|
|
15772
|
+
}
|
|
15773
|
+
if (kbResult.queryContext) {
|
|
15774
|
+
dynamicParts.push("## Relevant Knowledge Base (Query-Matched)\n" + kbResult.queryContext);
|
|
15775
|
+
}
|
|
15776
|
+
knowledgeBaseContext = dynamicParts.join("\n\n") || knowledgeBaseContext;
|
|
15777
|
+
}
|
|
15694
15778
|
const prompts = await promptLoader.loadPrompts("report-comp-picker", {
|
|
15695
15779
|
USER_PROMPT: prompt,
|
|
15696
15780
|
AVAILABLE_COMPONENTS: availableComponentsText,
|
|
@@ -15698,8 +15782,12 @@ async function generateReportComponents(prompt, components, anthropicApiKey, gro
|
|
|
15698
15782
|
DATABASE_RULES: databaseRules,
|
|
15699
15783
|
AVAILABLE_TOOLS: availableToolsText,
|
|
15700
15784
|
CURRENT_DATETIME: getCurrentDateTimeForPrompt(),
|
|
15701
|
-
CONVERSATION_HISTORY: conversationHistory || "No previous conversation"
|
|
15785
|
+
CONVERSATION_HISTORY: conversationHistory || "No previous conversation",
|
|
15786
|
+
GLOBAL_KNOWLEDGE_BASE: globalKnowledgeBase,
|
|
15787
|
+
KNOWLEDGE_BASE_CONTEXT: knowledgeBaseContext
|
|
15702
15788
|
});
|
|
15789
|
+
logger.logLLMPrompt("reportCompPicker", "system", extractPromptText(prompts.system));
|
|
15790
|
+
logger.logLLMPrompt("reportCompPicker", "user", prompts.user);
|
|
15703
15791
|
logger.debug("[REPORT_COMP_REQ] Loaded report-comp-picker prompts with schema and tools");
|
|
15704
15792
|
const { apiKey, model } = getApiKeyAndModel2(
|
|
15705
15793
|
anthropicApiKey,
|
|
@@ -15924,13 +16012,21 @@ async function validateAllExternalToolQueries(components, collections, tools, mo
|
|
|
15924
16012
|
data: {}
|
|
15925
16013
|
});
|
|
15926
16014
|
if (result?.success !== false && !result?.error) {
|
|
15927
|
-
const
|
|
15928
|
-
const
|
|
16015
|
+
const toolResult = result?.data ?? result;
|
|
16016
|
+
const valueKey = comp.props?.config?.valueKey;
|
|
16017
|
+
const isKpi = comp.type === "KPICard" || comp.name === "DynamicKPICard";
|
|
16018
|
+
let dataArray;
|
|
16019
|
+
if (isKpi && valueKey && toolResult && typeof toolResult === "object" && !Array.isArray(toolResult) && toolResult[valueKey] !== void 0) {
|
|
16020
|
+
dataArray = [toolResult];
|
|
16021
|
+
} else {
|
|
16022
|
+
const resultData = toolResult?.data ?? toolResult ?? [];
|
|
16023
|
+
dataArray = Array.isArray(resultData) ? resultData : [resultData];
|
|
16024
|
+
}
|
|
15929
16025
|
if (!comp.props.config) {
|
|
15930
16026
|
comp.props.config = {};
|
|
15931
16027
|
}
|
|
15932
16028
|
comp.props.config.data = dataArray;
|
|
15933
|
-
logger.info(`[REPORT_COMP_REQ] \u2713 ${comp.name} prefetched ${dataArray.length} rows (non-SQL tool)`);
|
|
16029
|
+
logger.info(`[REPORT_COMP_REQ] \u2713 ${comp.name} prefetched ${dataArray.length} ${dataArray.length === 1 && isKpi ? "aggregate" : "rows"} (non-SQL tool)`);
|
|
15934
16030
|
}
|
|
15935
16031
|
} catch (err) {
|
|
15936
16032
|
logger.warn(`[REPORT_COMP_REQ] \u26A0 ${comp.name} non-SQL prefetch failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -16070,7 +16166,8 @@ var processReportCompRequest = async (data, components, _sendMessage, anthropicA
|
|
|
16070
16166
|
collections,
|
|
16071
16167
|
tools,
|
|
16072
16168
|
modelConfig,
|
|
16073
|
-
conversationHistory
|
|
16169
|
+
conversationHistory,
|
|
16170
|
+
userId
|
|
16074
16171
|
);
|
|
16075
16172
|
if (llmResponse.success && reportId && prompt) {
|
|
16076
16173
|
const comps = llmResponse.data?.components;
|