@superatomai/sdk-node 0.0.42-mds → 0.0.43-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/dist/index.mjs CHANGED
@@ -360,8 +360,10 @@ var ToolSchema = z3.object({
360
360
  fullSchema: z3.string().optional(),
361
361
  params: z3.record(z3.string()),
362
362
  fn: z3.function().args(z3.any()).returns(z3.any()),
363
- outputSchema: OutputSchema.optional()
363
+ outputSchema: OutputSchema.optional(),
364
364
  // Optional: describes the data structure returned by this tool
365
+ /** Cache policy. `false` = never cache (live data, write ops). Mirrors HTTP `Cache-Control: no-store`. */
366
+ cache: z3.union([z3.literal(false), z3.object({ ttlMs: z3.number().optional() })]).optional()
365
367
  });
366
368
  var UserQueryFiltersSchema = z3.object({
367
369
  username: z3.string().optional(),
@@ -2021,6 +2023,21 @@ function formatResultAsString(formattedResult) {
2021
2023
  return JSON.stringify(formattedResult, null, 2);
2022
2024
  }
2023
2025
 
2026
+ // src/utils/cache-key.ts
2027
+ function stableStringify(value) {
2028
+ if (value === null || typeof value !== "object") {
2029
+ return JSON.stringify(value);
2030
+ }
2031
+ if (Array.isArray(value)) {
2032
+ return "[" + value.map(stableStringify).join(",") + "]";
2033
+ }
2034
+ const keys = Object.keys(value).sort();
2035
+ return "{" + keys.map((k) => JSON.stringify(k) + ":" + stableStringify(value[k])).join(",") + "}";
2036
+ }
2037
+ function buildDirectToolCacheKey(toolId, parameters) {
2038
+ return `et-direct:${toolId}:${stableStringify(parameters || {})}`;
2039
+ }
2040
+
2024
2041
  // src/handlers/data-request.ts
2025
2042
  function getQueryCacheKey(query) {
2026
2043
  if (typeof query === "string") {
@@ -2034,16 +2051,6 @@ function getQueryCacheKey(query) {
2034
2051
  }
2035
2052
  return "";
2036
2053
  }
2037
- function stableStringify(value) {
2038
- if (value === null || typeof value !== "object") {
2039
- return JSON.stringify(value);
2040
- }
2041
- if (Array.isArray(value)) {
2042
- return "[" + value.map(stableStringify).join(",") + "]";
2043
- }
2044
- const keys = Object.keys(value).sort();
2045
- return "{" + keys.map((k) => JSON.stringify(k) + ":" + stableStringify(value[k])).join(",") + "}";
2046
- }
2047
2054
  function getCacheKey(collection, op, params, tools) {
2048
2055
  if (collection === "database" && op === "execute" && params?.sql) {
2049
2056
  return getQueryCacheKey(params.sql);
@@ -14520,17 +14527,45 @@ function formatComponentsForPrompt(components) {
14520
14527
  Props Structure: ${propsPreview}`;
14521
14528
  }).join("\n\n");
14522
14529
  }
14530
+ function classifyTool(tool) {
14531
+ if (tool.toolType === "direct") return "direct";
14532
+ if (tool.id.endsWith("_query")) return "sql";
14533
+ if (tool.id.endsWith("_call")) return "rest";
14534
+ if (tool.id.endsWith("_graphql")) return "graphql";
14535
+ return "direct";
14536
+ }
14523
14537
  function formatToolsForPrompt(tools) {
14524
14538
  if (!tools || tools.length === 0) {
14525
14539
  return "No external tools available.";
14526
14540
  }
14527
- return tools.map((tool, idx) => {
14541
+ const directTools = [];
14542
+ const sourceTools = [];
14543
+ for (const t of tools) {
14544
+ (classifyTool(t) === "direct" ? directTools : sourceTools).push(t);
14545
+ }
14546
+ const renderTool = (tool, idx, label) => {
14528
14547
  const paramsStr = Object.entries(tool.params || {}).map(([key, type]) => `${key}: ${type}`).join(", ");
14529
- return `${idx + 1}. ID: ${tool.id}
14548
+ return `${idx + 1}. [${label}] ID: ${tool.id}
14530
14549
  Name: ${tool.name}
14531
14550
  Description: ${tool.description}
14532
14551
  Parameters: { ${paramsStr} }`;
14533
- }).join("\n\n");
14552
+ };
14553
+ const sections = [];
14554
+ if (directTools.length > 0) {
14555
+ const body = directTools.map((t, i) => renderTool(t, i, "DIRECT \u2014 PREFER")).join("\n\n");
14556
+ sections.push(`### Direct Tools (try these first \u2014 they answer most questions without SQL)
14557
+ ${body}`);
14558
+ }
14559
+ if (sourceTools.length > 0) {
14560
+ const body = sourceTools.map((t, i) => {
14561
+ const kind = classifyTool(t);
14562
+ const label = kind === "sql" ? "SQL" : kind === "rest" ? "REST" : "GRAPHQL";
14563
+ return renderTool(t, i, label);
14564
+ }).join("\n\n");
14565
+ sections.push(`### Source Tools (fallback \u2014 use only when no direct tool fits)
14566
+ ${body}`);
14567
+ }
14568
+ return sections.join("\n\n");
14534
14569
  }
14535
14570
  function formatExistingComponentsForPrompt(existingComponents) {
14536
14571
  if (!existingComponents || existingComponents.length === 0) {
@@ -14945,6 +14980,18 @@ Fixed SQL query:`;
14945
14980
  logger.info(`[DASH_COMP_REQ] Replaced direct query with queryId: ${queryId}`);
14946
14981
  }
14947
14982
  finalComponent = { ...finalComponent, props };
14983
+ const ext = finalComponent.props?.externalTool;
14984
+ if (ext?.toolId && !ext?.parameters?.sql) {
14985
+ const matchedTool = tools?.find((t) => t.id === ext.toolId);
14986
+ if (matchedTool && matchedTool.cache !== false) {
14987
+ const match = executedTools.find((t) => t.id === ext.toolId);
14988
+ if (match) {
14989
+ const cacheKey = buildDirectToolCacheKey(ext.toolId, ext.parameters);
14990
+ queryCache.set(cacheKey, { success: true, data: match.result });
14991
+ logger.info(`[DASH_COMP_REQ] Pre-populated et-direct cache for ${ext.toolId}`);
14992
+ }
14993
+ }
14994
+ }
14948
14995
  if (parsedResult.props.query) {
14949
14996
  logger.info(`[DASH_COMP_REQ] Data source: Database query`);
14950
14997
  }
@@ -15116,7 +15163,35 @@ async function createFilterWithLLM(prompt, components, existingComponents, anthr
15116
15163
  const updatedComponents = result.updatedComponents || [];
15117
15164
  for (const comp of updatedComponents) {
15118
15165
  const extTool = comp.props?.externalTool;
15119
- if (!extTool?.parameters?.sql || !extTool?.toolId) continue;
15166
+ if (!extTool?.toolId) continue;
15167
+ const isDirectTool = !extTool?.parameters?.sql;
15168
+ if (isDirectTool) {
15169
+ const directTool = tools?.find((t) => t.id === extTool.toolId);
15170
+ if (!directTool) {
15171
+ logger.warn(`[DASH_COMP_REQ:FILTER] direct tool ${extTool.toolId} not found in tool registry`);
15172
+ continue;
15173
+ }
15174
+ const declared = new Set(Object.keys(directTool.params || {}));
15175
+ const sentKeys = Object.keys(extTool.parameters || {});
15176
+ const unknown = sentKeys.filter((k) => !declared.has(k));
15177
+ if (unknown.length > 0) {
15178
+ logger.warn(`[DASH_COMP_REQ:FILTER] dropping unknown params on ${extTool.toolId}: ${unknown.join(", ")}`);
15179
+ unknown.forEach((k) => delete extTool.parameters[k]);
15180
+ }
15181
+ if (directTool.cache !== false) {
15182
+ try {
15183
+ const directResult = await directTool.fn(extTool.parameters || {});
15184
+ const cacheKey2 = buildDirectToolCacheKey(extTool.toolId, extTool.parameters);
15185
+ queryCache.set(cacheKey2, { success: true, data: directResult });
15186
+ logger.info(`[DASH_COMP_REQ:FILTER] direct tool ${extTool.toolId} validated and cached for component: ${comp.id}`);
15187
+ } catch (err) {
15188
+ const errMsg = err instanceof Error ? err.message : String(err);
15189
+ logger.warn(`[DASH_COMP_REQ:FILTER] direct tool validation failed for ${extTool.toolId} on component ${comp.id}: ${errMsg}`);
15190
+ }
15191
+ }
15192
+ continue;
15193
+ }
15194
+ if (!extTool?.parameters?.sql) continue;
15120
15195
  let sql = extTool.parameters.sql;
15121
15196
  const defaultParams = extTool.parameters.params || {};
15122
15197
  const toolId = extTool.toolId;