@superatomai/sdk-node 0.0.73-dsp → 0.0.74-dsp
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 +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +81 -19
- package/dist/index.mjs +81 -19
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -6456,6 +6456,7 @@ declare class SuperatomSDK {
|
|
|
6456
6456
|
private components;
|
|
6457
6457
|
private tools;
|
|
6458
6458
|
private workflows;
|
|
6459
|
+
private registryWaiters;
|
|
6459
6460
|
private anthropicApiKey;
|
|
6460
6461
|
private groqApiKey;
|
|
6461
6462
|
private geminiApiKey;
|
|
@@ -6622,6 +6623,19 @@ declare class SuperatomSDK {
|
|
|
6622
6623
|
* the workflow component is returned directly, with the LLM-extracted props.
|
|
6623
6624
|
*/
|
|
6624
6625
|
setWorkflows(workflows: WorkflowDescriptor[]): void;
|
|
6626
|
+
/**
|
|
6627
|
+
* Make sure the agent has a tool surface before answering a prompt.
|
|
6628
|
+
*
|
|
6629
|
+
* Components and workflows are pushed by the browser once per page load and
|
|
6630
|
+
* kept only in memory, so a backend restart leaves both lists empty until
|
|
6631
|
+
* someone reloads a tab. The agent still answers — with no workflows to route
|
|
6632
|
+
* to and no components to render — which looks like a model regression rather
|
|
6633
|
+
* than lost state. Ask the client to re-send instead, and proceed regardless
|
|
6634
|
+
* so a stale or silent client degrades no worse than it does today.
|
|
6635
|
+
*/
|
|
6636
|
+
private ensureRegistry;
|
|
6637
|
+
/** Release anyone blocked in ensureRegistry() now that the list has arrived. */
|
|
6638
|
+
private resolveRegistryWaiters;
|
|
6625
6639
|
/**
|
|
6626
6640
|
* Get the registered workflow components.
|
|
6627
6641
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -6456,6 +6456,7 @@ declare class SuperatomSDK {
|
|
|
6456
6456
|
private components;
|
|
6457
6457
|
private tools;
|
|
6458
6458
|
private workflows;
|
|
6459
|
+
private registryWaiters;
|
|
6459
6460
|
private anthropicApiKey;
|
|
6460
6461
|
private groqApiKey;
|
|
6461
6462
|
private geminiApiKey;
|
|
@@ -6622,6 +6623,19 @@ declare class SuperatomSDK {
|
|
|
6622
6623
|
* the workflow component is returned directly, with the LLM-extracted props.
|
|
6623
6624
|
*/
|
|
6624
6625
|
setWorkflows(workflows: WorkflowDescriptor[]): void;
|
|
6626
|
+
/**
|
|
6627
|
+
* Make sure the agent has a tool surface before answering a prompt.
|
|
6628
|
+
*
|
|
6629
|
+
* Components and workflows are pushed by the browser once per page load and
|
|
6630
|
+
* kept only in memory, so a backend restart leaves both lists empty until
|
|
6631
|
+
* someone reloads a tab. The agent still answers — with no workflows to route
|
|
6632
|
+
* to and no components to render — which looks like a model regression rather
|
|
6633
|
+
* than lost state. Ask the client to re-send instead, and proceed regardless
|
|
6634
|
+
* so a stale or silent client degrades no worse than it does today.
|
|
6635
|
+
*/
|
|
6636
|
+
private ensureRegistry;
|
|
6637
|
+
/** Release anyone blocked in ensureRegistry() now that the list has arrived. */
|
|
6638
|
+
private resolveRegistryWaiters;
|
|
6625
6639
|
/**
|
|
6626
6640
|
* Get the registered workflow components.
|
|
6627
6641
|
*/
|
package/dist/index.js
CHANGED
|
@@ -121,7 +121,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
121
121
|
// src/websocket.ts
|
|
122
122
|
var import_ws = __toESM(require("ws"));
|
|
123
123
|
function createWebSocket(url) {
|
|
124
|
-
return new import_ws.default(url);
|
|
124
|
+
return new import_ws.default(url, { handshakeTimeout: 15e3 });
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
// src/types.ts
|
|
@@ -5021,6 +5021,7 @@ var LLM = class {
|
|
|
5021
5021
|
try {
|
|
5022
5022
|
currentToolUse.input = currentToolUse.inputJson ? JSON.parse(currentToolUse.inputJson) : {};
|
|
5023
5023
|
} catch (error) {
|
|
5024
|
+
logger.error(`[LLM] Tool "${currentToolUse.name}" input was not valid JSON, falling back to {}: ${String(currentToolUse.inputJson).substring(0, 500)}`);
|
|
5024
5025
|
currentToolUse.input = {};
|
|
5025
5026
|
}
|
|
5026
5027
|
delete currentToolUse.inputJson;
|
|
@@ -5100,10 +5101,12 @@ var LLM = class {
|
|
|
5100
5101
|
content: stripLoneSurrogates(resultContent)
|
|
5101
5102
|
};
|
|
5102
5103
|
} catch (error) {
|
|
5104
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5105
|
+
logger.error(`[LLM] Tool "${toolUse.name}" threw: ${message} | input: ${JSON.stringify(toolUse.input).substring(0, 300)}`);
|
|
5103
5106
|
return {
|
|
5104
5107
|
type: "tool_result",
|
|
5105
5108
|
tool_use_id: toolUse.id,
|
|
5106
|
-
content:
|
|
5109
|
+
content: message,
|
|
5107
5110
|
is_error: true
|
|
5108
5111
|
};
|
|
5109
5112
|
}
|
|
@@ -5111,6 +5114,9 @@ var LLM = class {
|
|
|
5111
5114
|
toolResultEntries.forEach((entry) => toolResults.content.push(entry));
|
|
5112
5115
|
conversationMessages.push(toolResults);
|
|
5113
5116
|
} else {
|
|
5117
|
+
if (stopReason === "tool_use") {
|
|
5118
|
+
logger.error(`[LLM] stop_reason=tool_use but no tool_use block survived parsing (${contentBlocks.length} content block(s))`);
|
|
5119
|
+
}
|
|
5114
5120
|
break;
|
|
5115
5121
|
}
|
|
5116
5122
|
}
|
|
@@ -29277,6 +29283,8 @@ var SuperatomSDK = class {
|
|
|
29277
29283
|
this.components = [];
|
|
29278
29284
|
this.tools = [];
|
|
29279
29285
|
this.workflows = [];
|
|
29286
|
+
// Resolvers waiting on a registry re-send, keyed by the RES type expected.
|
|
29287
|
+
this.registryWaiters = /* @__PURE__ */ new Map();
|
|
29280
29288
|
// Heartbeat properties for keeping WebSocket connection alive.
|
|
29281
29289
|
// 25s ping + 10s grace stays under common NAT/LB idle thresholds (~60-100s)
|
|
29282
29290
|
// so we detect dead sockets within seconds instead of minutes.
|
|
@@ -29486,21 +29494,23 @@ var SuperatomSDK = class {
|
|
|
29486
29494
|
});
|
|
29487
29495
|
break;
|
|
29488
29496
|
case "USER_PROMPT_REQ":
|
|
29489
|
-
|
|
29490
|
-
|
|
29491
|
-
|
|
29492
|
-
|
|
29493
|
-
|
|
29494
|
-
|
|
29495
|
-
|
|
29496
|
-
|
|
29497
|
-
|
|
29498
|
-
|
|
29499
|
-
|
|
29500
|
-
|
|
29501
|
-
|
|
29502
|
-
|
|
29503
|
-
|
|
29497
|
+
this.ensureRegistry().then(
|
|
29498
|
+
() => handleUserPromptRequest(
|
|
29499
|
+
parsed,
|
|
29500
|
+
this.components,
|
|
29501
|
+
(msg) => this.send(msg),
|
|
29502
|
+
this.anthropicApiKey,
|
|
29503
|
+
this.groqApiKey,
|
|
29504
|
+
this.geminiApiKey,
|
|
29505
|
+
this.openaiApiKey,
|
|
29506
|
+
this.llmProviders,
|
|
29507
|
+
this.collections,
|
|
29508
|
+
this.tools,
|
|
29509
|
+
this.mainAgentModel,
|
|
29510
|
+
this.sourceAgentModel,
|
|
29511
|
+
this.workflows,
|
|
29512
|
+
this.answerFlow === "custom" ? this.answerProvider : void 0
|
|
29513
|
+
)
|
|
29504
29514
|
).catch((error) => {
|
|
29505
29515
|
logger.error("Failed to handle user prompt request:", error);
|
|
29506
29516
|
});
|
|
@@ -29518,8 +29528,12 @@ var SuperatomSDK = class {
|
|
|
29518
29528
|
});
|
|
29519
29529
|
break;
|
|
29520
29530
|
case "COMPONENT_LIST_RES":
|
|
29521
|
-
handleComponentListResponse(parsed, (com) =>
|
|
29531
|
+
handleComponentListResponse(parsed, (com) => {
|
|
29532
|
+
this.storeComponents(com);
|
|
29533
|
+
this.resolveRegistryWaiters("COMPONENT_LIST_RES");
|
|
29534
|
+
}, this.collections).catch((error) => {
|
|
29522
29535
|
logger.error("Failed to handle component list request:", error);
|
|
29536
|
+
this.resolveRegistryWaiters("COMPONENT_LIST_RES");
|
|
29523
29537
|
});
|
|
29524
29538
|
break;
|
|
29525
29539
|
/* The dashboard contract, pushed by the bundle that holds it — on
|
|
@@ -29530,8 +29544,12 @@ var SuperatomSDK = class {
|
|
|
29530
29544
|
});
|
|
29531
29545
|
break;
|
|
29532
29546
|
case "WORKFLOW_LIST_RES":
|
|
29533
|
-
handleWorkflowListResponse(parsed, (wf) =>
|
|
29547
|
+
handleWorkflowListResponse(parsed, (wf) => {
|
|
29548
|
+
this.setWorkflows(wf);
|
|
29549
|
+
this.resolveRegistryWaiters("WORKFLOW_LIST_RES");
|
|
29550
|
+
}).catch((error) => {
|
|
29534
29551
|
logger.error("Failed to handle workflow list request:", error);
|
|
29552
|
+
this.resolveRegistryWaiters("WORKFLOW_LIST_RES");
|
|
29535
29553
|
});
|
|
29536
29554
|
break;
|
|
29537
29555
|
case "USERS":
|
|
@@ -29876,6 +29894,50 @@ var SuperatomSDK = class {
|
|
|
29876
29894
|
this.workflows = workflows;
|
|
29877
29895
|
logger.info(`Workflows stored in SDK: ${workflows.length} workflow(s)`);
|
|
29878
29896
|
}
|
|
29897
|
+
/**
|
|
29898
|
+
* Make sure the agent has a tool surface before answering a prompt.
|
|
29899
|
+
*
|
|
29900
|
+
* Components and workflows are pushed by the browser once per page load and
|
|
29901
|
+
* kept only in memory, so a backend restart leaves both lists empty until
|
|
29902
|
+
* someone reloads a tab. The agent still answers — with no workflows to route
|
|
29903
|
+
* to and no components to render — which looks like a model regression rather
|
|
29904
|
+
* than lost state. Ask the client to re-send instead, and proceed regardless
|
|
29905
|
+
* so a stale or silent client degrades no worse than it does today.
|
|
29906
|
+
*/
|
|
29907
|
+
async ensureRegistry(timeoutMs = 4e3) {
|
|
29908
|
+
const missing = [];
|
|
29909
|
+
if (this.workflows.length === 0) missing.push(["WORKFLOW_LIST_REQ", "WORKFLOW_LIST_RES"]);
|
|
29910
|
+
if (this.components.length === 0) missing.push(["COMPONENT_LIST_REQ", "COMPONENT_LIST_RES"]);
|
|
29911
|
+
if (missing.length === 0) return;
|
|
29912
|
+
logger.warn(`Registry empty, requesting from client: ${missing.map(([req]) => req).join(", ")}`);
|
|
29913
|
+
await Promise.all(missing.map(([reqType, resType]) => new Promise((resolve4) => {
|
|
29914
|
+
let settled = false;
|
|
29915
|
+
const finish = () => {
|
|
29916
|
+
if (!settled) {
|
|
29917
|
+
settled = true;
|
|
29918
|
+
resolve4();
|
|
29919
|
+
}
|
|
29920
|
+
};
|
|
29921
|
+
const waiters = this.registryWaiters.get(resType) ?? [];
|
|
29922
|
+
waiters.push(finish);
|
|
29923
|
+
this.registryWaiters.set(resType, waiters);
|
|
29924
|
+
const sent = this.send({
|
|
29925
|
+
type: reqType,
|
|
29926
|
+
from: { type: this.type },
|
|
29927
|
+
to: { type: "runtime" },
|
|
29928
|
+
payload: {}
|
|
29929
|
+
});
|
|
29930
|
+
if (!sent) finish();
|
|
29931
|
+
else setTimeout(finish, timeoutMs);
|
|
29932
|
+
})));
|
|
29933
|
+
}
|
|
29934
|
+
/** Release anyone blocked in ensureRegistry() now that the list has arrived. */
|
|
29935
|
+
resolveRegistryWaiters(resType) {
|
|
29936
|
+
const waiters = this.registryWaiters.get(resType);
|
|
29937
|
+
if (!waiters || waiters.length === 0) return;
|
|
29938
|
+
this.registryWaiters.delete(resType);
|
|
29939
|
+
waiters.forEach((resolve4) => resolve4());
|
|
29940
|
+
}
|
|
29879
29941
|
/**
|
|
29880
29942
|
* Get the registered workflow components.
|
|
29881
29943
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -8,7 +8,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
8
8
|
// src/websocket.ts
|
|
9
9
|
import WebSocket from "ws";
|
|
10
10
|
function createWebSocket(url) {
|
|
11
|
-
return new WebSocket(url);
|
|
11
|
+
return new WebSocket(url, { handshakeTimeout: 15e3 });
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
// src/types.ts
|
|
@@ -4908,6 +4908,7 @@ var LLM = class {
|
|
|
4908
4908
|
try {
|
|
4909
4909
|
currentToolUse.input = currentToolUse.inputJson ? JSON.parse(currentToolUse.inputJson) : {};
|
|
4910
4910
|
} catch (error) {
|
|
4911
|
+
logger.error(`[LLM] Tool "${currentToolUse.name}" input was not valid JSON, falling back to {}: ${String(currentToolUse.inputJson).substring(0, 500)}`);
|
|
4911
4912
|
currentToolUse.input = {};
|
|
4912
4913
|
}
|
|
4913
4914
|
delete currentToolUse.inputJson;
|
|
@@ -4987,10 +4988,12 @@ var LLM = class {
|
|
|
4987
4988
|
content: stripLoneSurrogates(resultContent)
|
|
4988
4989
|
};
|
|
4989
4990
|
} catch (error) {
|
|
4991
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4992
|
+
logger.error(`[LLM] Tool "${toolUse.name}" threw: ${message} | input: ${JSON.stringify(toolUse.input).substring(0, 300)}`);
|
|
4990
4993
|
return {
|
|
4991
4994
|
type: "tool_result",
|
|
4992
4995
|
tool_use_id: toolUse.id,
|
|
4993
|
-
content:
|
|
4996
|
+
content: message,
|
|
4994
4997
|
is_error: true
|
|
4995
4998
|
};
|
|
4996
4999
|
}
|
|
@@ -4998,6 +5001,9 @@ var LLM = class {
|
|
|
4998
5001
|
toolResultEntries.forEach((entry) => toolResults.content.push(entry));
|
|
4999
5002
|
conversationMessages.push(toolResults);
|
|
5000
5003
|
} else {
|
|
5004
|
+
if (stopReason === "tool_use") {
|
|
5005
|
+
logger.error(`[LLM] stop_reason=tool_use but no tool_use block survived parsing (${contentBlocks.length} content block(s))`);
|
|
5006
|
+
}
|
|
5001
5007
|
break;
|
|
5002
5008
|
}
|
|
5003
5009
|
}
|
|
@@ -29164,6 +29170,8 @@ var SuperatomSDK = class {
|
|
|
29164
29170
|
this.components = [];
|
|
29165
29171
|
this.tools = [];
|
|
29166
29172
|
this.workflows = [];
|
|
29173
|
+
// Resolvers waiting on a registry re-send, keyed by the RES type expected.
|
|
29174
|
+
this.registryWaiters = /* @__PURE__ */ new Map();
|
|
29167
29175
|
// Heartbeat properties for keeping WebSocket connection alive.
|
|
29168
29176
|
// 25s ping + 10s grace stays under common NAT/LB idle thresholds (~60-100s)
|
|
29169
29177
|
// so we detect dead sockets within seconds instead of minutes.
|
|
@@ -29373,21 +29381,23 @@ var SuperatomSDK = class {
|
|
|
29373
29381
|
});
|
|
29374
29382
|
break;
|
|
29375
29383
|
case "USER_PROMPT_REQ":
|
|
29376
|
-
|
|
29377
|
-
|
|
29378
|
-
|
|
29379
|
-
|
|
29380
|
-
|
|
29381
|
-
|
|
29382
|
-
|
|
29383
|
-
|
|
29384
|
-
|
|
29385
|
-
|
|
29386
|
-
|
|
29387
|
-
|
|
29388
|
-
|
|
29389
|
-
|
|
29390
|
-
|
|
29384
|
+
this.ensureRegistry().then(
|
|
29385
|
+
() => handleUserPromptRequest(
|
|
29386
|
+
parsed,
|
|
29387
|
+
this.components,
|
|
29388
|
+
(msg) => this.send(msg),
|
|
29389
|
+
this.anthropicApiKey,
|
|
29390
|
+
this.groqApiKey,
|
|
29391
|
+
this.geminiApiKey,
|
|
29392
|
+
this.openaiApiKey,
|
|
29393
|
+
this.llmProviders,
|
|
29394
|
+
this.collections,
|
|
29395
|
+
this.tools,
|
|
29396
|
+
this.mainAgentModel,
|
|
29397
|
+
this.sourceAgentModel,
|
|
29398
|
+
this.workflows,
|
|
29399
|
+
this.answerFlow === "custom" ? this.answerProvider : void 0
|
|
29400
|
+
)
|
|
29391
29401
|
).catch((error) => {
|
|
29392
29402
|
logger.error("Failed to handle user prompt request:", error);
|
|
29393
29403
|
});
|
|
@@ -29405,8 +29415,12 @@ var SuperatomSDK = class {
|
|
|
29405
29415
|
});
|
|
29406
29416
|
break;
|
|
29407
29417
|
case "COMPONENT_LIST_RES":
|
|
29408
|
-
handleComponentListResponse(parsed, (com) =>
|
|
29418
|
+
handleComponentListResponse(parsed, (com) => {
|
|
29419
|
+
this.storeComponents(com);
|
|
29420
|
+
this.resolveRegistryWaiters("COMPONENT_LIST_RES");
|
|
29421
|
+
}, this.collections).catch((error) => {
|
|
29409
29422
|
logger.error("Failed to handle component list request:", error);
|
|
29423
|
+
this.resolveRegistryWaiters("COMPONENT_LIST_RES");
|
|
29410
29424
|
});
|
|
29411
29425
|
break;
|
|
29412
29426
|
/* The dashboard contract, pushed by the bundle that holds it — on
|
|
@@ -29417,8 +29431,12 @@ var SuperatomSDK = class {
|
|
|
29417
29431
|
});
|
|
29418
29432
|
break;
|
|
29419
29433
|
case "WORKFLOW_LIST_RES":
|
|
29420
|
-
handleWorkflowListResponse(parsed, (wf) =>
|
|
29434
|
+
handleWorkflowListResponse(parsed, (wf) => {
|
|
29435
|
+
this.setWorkflows(wf);
|
|
29436
|
+
this.resolveRegistryWaiters("WORKFLOW_LIST_RES");
|
|
29437
|
+
}).catch((error) => {
|
|
29421
29438
|
logger.error("Failed to handle workflow list request:", error);
|
|
29439
|
+
this.resolveRegistryWaiters("WORKFLOW_LIST_RES");
|
|
29422
29440
|
});
|
|
29423
29441
|
break;
|
|
29424
29442
|
case "USERS":
|
|
@@ -29763,6 +29781,50 @@ var SuperatomSDK = class {
|
|
|
29763
29781
|
this.workflows = workflows;
|
|
29764
29782
|
logger.info(`Workflows stored in SDK: ${workflows.length} workflow(s)`);
|
|
29765
29783
|
}
|
|
29784
|
+
/**
|
|
29785
|
+
* Make sure the agent has a tool surface before answering a prompt.
|
|
29786
|
+
*
|
|
29787
|
+
* Components and workflows are pushed by the browser once per page load and
|
|
29788
|
+
* kept only in memory, so a backend restart leaves both lists empty until
|
|
29789
|
+
* someone reloads a tab. The agent still answers — with no workflows to route
|
|
29790
|
+
* to and no components to render — which looks like a model regression rather
|
|
29791
|
+
* than lost state. Ask the client to re-send instead, and proceed regardless
|
|
29792
|
+
* so a stale or silent client degrades no worse than it does today.
|
|
29793
|
+
*/
|
|
29794
|
+
async ensureRegistry(timeoutMs = 4e3) {
|
|
29795
|
+
const missing = [];
|
|
29796
|
+
if (this.workflows.length === 0) missing.push(["WORKFLOW_LIST_REQ", "WORKFLOW_LIST_RES"]);
|
|
29797
|
+
if (this.components.length === 0) missing.push(["COMPONENT_LIST_REQ", "COMPONENT_LIST_RES"]);
|
|
29798
|
+
if (missing.length === 0) return;
|
|
29799
|
+
logger.warn(`Registry empty, requesting from client: ${missing.map(([req]) => req).join(", ")}`);
|
|
29800
|
+
await Promise.all(missing.map(([reqType, resType]) => new Promise((resolve4) => {
|
|
29801
|
+
let settled = false;
|
|
29802
|
+
const finish = () => {
|
|
29803
|
+
if (!settled) {
|
|
29804
|
+
settled = true;
|
|
29805
|
+
resolve4();
|
|
29806
|
+
}
|
|
29807
|
+
};
|
|
29808
|
+
const waiters = this.registryWaiters.get(resType) ?? [];
|
|
29809
|
+
waiters.push(finish);
|
|
29810
|
+
this.registryWaiters.set(resType, waiters);
|
|
29811
|
+
const sent = this.send({
|
|
29812
|
+
type: reqType,
|
|
29813
|
+
from: { type: this.type },
|
|
29814
|
+
to: { type: "runtime" },
|
|
29815
|
+
payload: {}
|
|
29816
|
+
});
|
|
29817
|
+
if (!sent) finish();
|
|
29818
|
+
else setTimeout(finish, timeoutMs);
|
|
29819
|
+
})));
|
|
29820
|
+
}
|
|
29821
|
+
/** Release anyone blocked in ensureRegistry() now that the list has arrived. */
|
|
29822
|
+
resolveRegistryWaiters(resType) {
|
|
29823
|
+
const waiters = this.registryWaiters.get(resType);
|
|
29824
|
+
if (!waiters || waiters.length === 0) return;
|
|
29825
|
+
this.registryWaiters.delete(resType);
|
|
29826
|
+
waiters.forEach((resolve4) => resolve4());
|
|
29827
|
+
}
|
|
29766
29828
|
/**
|
|
29767
29829
|
* Get the registered workflow components.
|
|
29768
29830
|
*/
|