@superatomai/sdk-node 0.0.38-mds → 0.0.39-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
@@ -319,6 +319,24 @@ var ComponentListResponseMessageSchema = z3.object({
319
319
  type: z3.literal("COMPONENT_LIST_RES"),
320
320
  payload: ComponentListResponsePayloadSchema
321
321
  });
322
+ var WorkflowDescriptorSchema = z3.object({
323
+ id: z3.string(),
324
+ name: z3.string(),
325
+ description: z3.string(),
326
+ whenToUse: z3.string(),
327
+ propsSchema: z3.record(z3.string()),
328
+ defaultProps: z3.record(z3.unknown()).optional()
329
+ });
330
+ var WorkflowsSchema = z3.array(WorkflowDescriptorSchema);
331
+ var WorkflowListResponsePayloadSchema = z3.object({
332
+ workflows: z3.array(WorkflowDescriptorSchema)
333
+ });
334
+ var WorkflowListResponseMessageSchema = z3.object({
335
+ id: z3.string(),
336
+ from: MessageParticipantSchema,
337
+ type: z3.literal("WORKFLOW_LIST_RES"),
338
+ payload: WorkflowListResponsePayloadSchema
339
+ });
322
340
  var OutputFieldSchema = z3.object({
323
341
  name: z3.string(),
324
342
  // Field name (column name in the result)
@@ -7484,8 +7502,9 @@ Even if a table appears in the detailed schema above, search_schema returns samp
7484
7502
 
7485
7503
  // src/userResponse/agents/main-agent.ts
7486
7504
  var MainAgent = class {
7487
- constructor(externalTools, config, streamBuffer) {
7505
+ constructor(externalTools, config, streamBuffer, workflows = []) {
7488
7506
  this.externalTools = externalTools;
7507
+ this.workflows = workflows;
7489
7508
  this.config = config;
7490
7509
  this.streamBuffer = streamBuffer || new StreamBuffer();
7491
7510
  }
@@ -7504,18 +7523,26 @@ var MainAgent = class {
7504
7523
  logger.info(`[MainAgent] Starting | prompt: "${userPrompt.substring(0, 50)}..."`);
7505
7524
  const sourceTools = this.externalTools.filter((t) => t.toolType !== "direct");
7506
7525
  const directTools = this.externalTools.filter((t) => t.toolType === "direct");
7507
- logger.info(`[MainAgent] ${sourceTools.length} source tool(s), ${directTools.length} direct tool(s)`);
7526
+ logger.info(`[MainAgent] ${sourceTools.length} source tool(s), ${directTools.length} direct tool(s), ${this.workflows.length} workflow(s)`);
7508
7527
  const summaries = buildSourceSummaries(sourceTools);
7509
- const systemPrompt = await this.buildSystemPrompt(summaries, directTools, conversationHistory);
7528
+ const systemPrompt = await this.buildSystemPrompt(summaries, directTools, this.workflows, conversationHistory);
7510
7529
  logger.logLLMPrompt("mainAgent", "system", extractPromptText(systemPrompt));
7511
7530
  logger.logLLMPrompt("mainAgent", "user", userPrompt);
7512
7531
  const sourceToolDefs = this.buildSourceToolDefinitions(summaries);
7513
7532
  const directToolDefs = this.buildDirectToolDefinitions(directTools);
7514
- const tools = [...sourceToolDefs, ...directToolDefs];
7533
+ const workflowToolDefs = this.buildWorkflowToolDefinitions(this.workflows);
7534
+ const tools = [...sourceToolDefs, ...directToolDefs, ...workflowToolDefs];
7515
7535
  const sourceResults = [];
7516
7536
  const executedTools = [];
7517
7537
  let sourceCallCounter = 0;
7538
+ let selectedWorkflow;
7518
7539
  const toolHandler = async (toolName, toolInput) => {
7540
+ const workflow = this.workflows.find((w) => w.id === toolName);
7541
+ if (workflow) {
7542
+ return this.handleWorkflow(workflow, toolInput, (w) => {
7543
+ selectedWorkflow = w;
7544
+ });
7545
+ }
7519
7546
  const externalTool = this.externalTools.find((t) => t.id === toolName);
7520
7547
  if (!externalTool) {
7521
7548
  logger.error(`[MainAgent] Unknown tool called: ${toolName}`);
@@ -7566,11 +7593,14 @@ var MainAgent = class {
7566
7593
  this.config.maxIterations
7567
7594
  );
7568
7595
  const totalTime = Date.now() - startTime;
7569
- logger.info(`[MainAgent] Complete | ${sourceResults.length} source queries, ${executedTools.length} successful | ${totalTime}ms`);
7596
+ logger.info(
7597
+ `[MainAgent] Complete | ${sourceResults.length} source queries, ${executedTools.length} successful${selectedWorkflow ? ` | workflow="${selectedWorkflow.name}"` : ""} | ${totalTime}ms`
7598
+ );
7570
7599
  return {
7571
7600
  text,
7572
7601
  executedTools,
7573
- sourceResults
7602
+ sourceResults,
7603
+ workflow: selectedWorkflow
7574
7604
  };
7575
7605
  }
7576
7606
  // ============================================
@@ -7644,9 +7674,10 @@ ${formatted}`;
7644
7674
  // System Prompt
7645
7675
  // ============================================
7646
7676
  /**
7647
- * Build the main agent's system prompt with source summaries and direct tool descriptions.
7677
+ * Build the main agent's system prompt with source summaries, direct tool descriptions,
7678
+ * and workflow component descriptions.
7648
7679
  */
7649
- async buildSystemPrompt(summaries, directTools, conversationHistory) {
7680
+ async buildSystemPrompt(summaries, directTools, workflows, conversationHistory) {
7650
7681
  const summariesText = formatSummariesForPrompt(summaries);
7651
7682
  const maxSourceCalls = Math.max(2, this.config.maxIterations - 2);
7652
7683
  let directToolsText = "";
@@ -7658,9 +7689,25 @@ ${formatted}`;
7658
7689
  ${t.description || "No description"}${paramList ? "\n Parameters:\n" + paramList : ""}`;
7659
7690
  }).join("\n\n");
7660
7691
  }
7692
+ let workflowsText = "";
7693
+ if (workflows.length > 0) {
7694
+ workflowsText = workflows.map((w, idx) => {
7695
+ const propLines = Object.entries(w.propsSchema || {}).map(([k, v]) => ` - ${k}: ${v}`).join("\n");
7696
+ return [
7697
+ `${idx + 1}. **${w.name}** (tool: ${w.id})`,
7698
+ ` ${w.description}`,
7699
+ ` When to use: ${w.whenToUse}`,
7700
+ propLines ? ` Props:
7701
+ ${propLines}` : ""
7702
+ ].filter(Boolean).join("\n");
7703
+ }).join("\n\n");
7704
+ } else {
7705
+ workflowsText = "No workflow components registered for this project.";
7706
+ }
7661
7707
  const prompts = await promptLoader.loadPrompts("agent-main", {
7662
7708
  SOURCE_SUMMARIES: summariesText,
7663
7709
  DIRECT_TOOLS: directToolsText,
7710
+ WORKFLOW_COMPONENTS: workflowsText,
7664
7711
  MAX_ROWS: String(this.config.maxRowsPerSource),
7665
7712
  MAX_SOURCE_CALLS: String(maxSourceCalls),
7666
7713
  GLOBAL_KNOWLEDGE_BASE: this.config.globalKnowledgeBase || "No global knowledge base available.",
@@ -7747,6 +7794,70 @@ ${formatted}`;
7747
7794
  });
7748
7795
  }
7749
7796
  // ============================================
7797
+ // Workflow Handling
7798
+ // ============================================
7799
+ /**
7800
+ * Capture a workflow selection. We do NOT execute anything — the LLM has
7801
+ * already extracted the props it wants the workflow rendered with. We
7802
+ * record the selection (via the capture callback) and return a short
7803
+ * acknowledgement so the LLM ends its turn cleanly without writing
7804
+ * analysis text or calling more tools.
7805
+ */
7806
+ async handleWorkflow(workflow, toolInput, capture) {
7807
+ const props = { ...workflow.defaultProps || {}, ...toolInput || {} };
7808
+ logger.info(
7809
+ `[MainAgent] Workflow selected: "${workflow.name}" | props: ${JSON.stringify(props).substring(0, 200)}`
7810
+ );
7811
+ if (this.streamBuffer.hasCallback()) {
7812
+ this.streamBuffer.write(`
7813
+
7814
+ \u{1F9ED} **Launching ${workflow.name} workflow...**
7815
+
7816
+ `);
7817
+ await streamDelay();
7818
+ }
7819
+ capture({ name: workflow.name, props });
7820
+ return `\u2705 Workflow "${workflow.name}" selected. The UI will render now \u2014 do NOT write analysis text or call any other tools. End your turn.`;
7821
+ }
7822
+ /**
7823
+ * Build LLM tool definitions for workflow components. The workflow's
7824
+ * propsSchema becomes the tool's input_schema so the LLM extracts props
7825
+ * directly from the prompt — same mechanic as direct tools.
7826
+ */
7827
+ buildWorkflowToolDefinitions(workflows) {
7828
+ return workflows.map((workflow) => {
7829
+ const properties = {};
7830
+ const required = [];
7831
+ Object.entries(workflow.propsSchema || {}).forEach(([key, typeOrValue]) => {
7832
+ const valueStr = String(typeOrValue).toLowerCase();
7833
+ let schemaType = "string";
7834
+ const typeMatch = valueStr.match(/^(string|number|integer|boolean|array|object)\b/);
7835
+ if (typeMatch) {
7836
+ schemaType = typeMatch[1];
7837
+ }
7838
+ const isOptional = valueStr.includes("(optional)") || valueStr.includes("optional");
7839
+ const description = typeof typeOrValue === "string" ? typeOrValue : `Prop: ${key}`;
7840
+ if (schemaType === "array") {
7841
+ properties[key] = { type: "array", items: {}, description };
7842
+ } else if (schemaType === "object") {
7843
+ properties[key] = { type: "object", description };
7844
+ } else {
7845
+ properties[key] = { type: schemaType, description };
7846
+ }
7847
+ if (!isOptional) required.push(key);
7848
+ });
7849
+ return {
7850
+ name: workflow.id,
7851
+ description: `[WORKFLOW] ${workflow.description} \u2014 When to use: ${workflow.whenToUse}`,
7852
+ input_schema: {
7853
+ type: "object",
7854
+ properties,
7855
+ required: required.length > 0 ? required : void 0
7856
+ }
7857
+ };
7858
+ });
7859
+ }
7860
+ // ============================================
7750
7861
  // Format Result for Main Agent
7751
7862
  // ============================================
7752
7863
  /**
@@ -10398,7 +10509,7 @@ function getLLMInstance(provider) {
10398
10509
  return anthropicLLM;
10399
10510
  }
10400
10511
  }
10401
- var get_agent_user_response = async (prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, conversationHistory, streamCallback, collections, externalTools, userId, mainAgentModel, sourceAgentModel) => {
10512
+ var get_agent_user_response = async (prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, conversationHistory, streamCallback, collections, externalTools, userId, mainAgentModel, sourceAgentModel, workflows) => {
10402
10513
  const startTime = Date.now();
10403
10514
  const providers = llmProviders || ["anthropic"];
10404
10515
  const provider = providers[0];
@@ -10500,13 +10611,35 @@ var get_agent_user_response = async (prompt, components, anthropicApiKey, groqAp
10500
10611
  knowledgeBaseContext
10501
10612
  };
10502
10613
  const streamBuffer = new StreamBuffer(streamCallback);
10503
- const mainAgent = new MainAgent(agentTools, agentConfig, streamBuffer);
10614
+ const mainAgent = new MainAgent(agentTools, agentConfig, streamBuffer, workflows || []);
10504
10615
  const agentResponse = await mainAgent.handleQuestion(
10505
10616
  prompt,
10506
10617
  apiKey,
10507
10618
  conversationHistory,
10508
10619
  streamBuffer.hasCallback() ? (chunk) => streamBuffer.write(chunk) : void 0
10509
10620
  );
10621
+ if (agentResponse.workflow) {
10622
+ streamBuffer.flush();
10623
+ const workflowComponent = {
10624
+ id: `workflow_${Date.now()}`,
10625
+ name: agentResponse.workflow.name,
10626
+ type: `Workflow_${agentResponse.workflow.name}`,
10627
+ description: `Workflow: ${agentResponse.workflow.name}`,
10628
+ props: agentResponse.workflow.props
10629
+ };
10630
+ const elapsedTime2 = Date.now() - startTime;
10631
+ logger.info(`[AgentFlow] Workflow short-circuit | "${agentResponse.workflow.name}" | ${elapsedTime2}ms`);
10632
+ return {
10633
+ success: true,
10634
+ data: {
10635
+ text: "",
10636
+ component: workflowComponent,
10637
+ actions: [],
10638
+ method: `${provider}-agent-workflow`
10639
+ },
10640
+ errors: []
10641
+ };
10642
+ }
10510
10643
  const rawText = streamBuffer.getFullText() || agentResponse.text || "I apologize, but I was unable to generate a response.";
10511
10644
  const textResponse = rawText.replace(/_?_?SB_END_?_?/g, "").replace(/__SB_\w+_(?:START|MSG)_?_?/g, "").replace(/__QUERY_TIMER_START_[^_]*__/g, "").replace(/__QUERY_TIMER_DONE_[\d.]+__/g, "").replace(/__TEXT_COMPLETE__COMPONENT_GENERATION_START__/g, "").replace(/\[COMPLEXITY:\s*(?:simple|medium|complex)\]/gi, "");
10512
10645
  streamBuffer.flush();
@@ -10859,7 +10992,7 @@ var CONTEXT_CONFIG = {
10859
10992
  };
10860
10993
 
10861
10994
  // src/handlers/user-prompt-request.ts
10862
- var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, mainAgentModel, sourceAgentModel) => {
10995
+ var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, mainAgentModel, sourceAgentModel, workflows) => {
10863
10996
  const errors = [];
10864
10997
  const parseResult = UserPromptRequestMessageSchema.safeParse(data);
10865
10998
  if (!parseResult.success) {
@@ -10945,7 +11078,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
10945
11078
  externalTools,
10946
11079
  userId,
10947
11080
  mainAgentModel,
10948
- sourceAgentModel
11081
+ sourceAgentModel,
11082
+ workflows
10949
11083
  );
10950
11084
  logger.info("User prompt request completed");
10951
11085
  const uiBlockId = existingUiBlockId;
@@ -11098,8 +11232,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
11098
11232
  wsId
11099
11233
  };
11100
11234
  };
11101
- async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, mainAgentModel, sourceAgentModel) {
11102
- const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, mainAgentModel, sourceAgentModel);
11235
+ async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, mainAgentModel, sourceAgentModel, workflows) {
11236
+ const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, mainAgentModel, sourceAgentModel, workflows);
11103
11237
  if (response.data?.component?.props?.config?.components) {
11104
11238
  response.data.component.props.config.components = response.data.component.props.config.components.map((comp) => ({
11105
11239
  ...comp,
@@ -11531,6 +11665,24 @@ async function handleComponentListResponse(data, storeComponents, collections) {
11531
11665
  }
11532
11666
  }
11533
11667
 
11668
+ // src/handlers/workflow-list-response.ts
11669
+ async function handleWorkflowListResponse(data, storeWorkflows) {
11670
+ try {
11671
+ const parsed = WorkflowListResponseMessageSchema.parse(data);
11672
+ const { payload } = parsed;
11673
+ const workflowsList = payload.workflows;
11674
+ if (!workflowsList) {
11675
+ logger.error("Workflows list not found in WORKFLOW_LIST_RES payload");
11676
+ return;
11677
+ }
11678
+ const workflows = WorkflowsSchema.parse(workflowsList);
11679
+ storeWorkflows(workflows);
11680
+ logger.info(`Stored ${workflows.length} workflow descriptor(s) from frontend`);
11681
+ } catch (error) {
11682
+ logger.error("Failed to handle workflow list response:", error);
11683
+ }
11684
+ }
11685
+
11534
11686
  // src/handlers/users.ts
11535
11687
  async function handleUsersRequest(data, collections, sendMessage) {
11536
11688
  const executeCollection = async (collection, op, params) => {
@@ -16864,6 +17016,7 @@ var SuperatomSDK = class {
16864
17016
  this.collections = {};
16865
17017
  this.components = [];
16866
17018
  this.tools = [];
17019
+ this.workflows = [];
16867
17020
  // Heartbeat properties for keeping WebSocket connection alive
16868
17021
  this.pingInterval = null;
16869
17022
  this.lastPong = Date.now();
@@ -17045,7 +17198,7 @@ var SuperatomSDK = class {
17045
17198
  });
17046
17199
  break;
17047
17200
  case "USER_PROMPT_REQ":
17048
- handleUserPromptRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.geminiApiKey, this.openaiApiKey, this.llmProviders, this.collections, this.tools, this.mainAgentModel, this.sourceAgentModel).catch((error) => {
17201
+ handleUserPromptRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.geminiApiKey, this.openaiApiKey, this.llmProviders, this.collections, this.tools, this.mainAgentModel, this.sourceAgentModel, this.workflows).catch((error) => {
17049
17202
  logger.error("Failed to handle user prompt request:", error);
17050
17203
  });
17051
17204
  break;
@@ -17064,6 +17217,11 @@ var SuperatomSDK = class {
17064
17217
  logger.error("Failed to handle component list request:", error);
17065
17218
  });
17066
17219
  break;
17220
+ case "WORKFLOW_LIST_RES":
17221
+ handleWorkflowListResponse(parsed, (wf) => this.setWorkflows(wf)).catch((error) => {
17222
+ logger.error("Failed to handle workflow list request:", error);
17223
+ });
17224
+ break;
17067
17225
  case "USERS":
17068
17226
  handleUsersRequest(parsed, this.collections, (msg) => this.send(msg)).catch((error) => {
17069
17227
  logger.error("Failed to handle users request:", error);
@@ -17303,6 +17461,24 @@ var SuperatomSDK = class {
17303
17461
  getTools() {
17304
17462
  return this.tools;
17305
17463
  }
17464
+ /**
17465
+ * Register workflow components for the SDK instance.
17466
+ *
17467
+ * Workflows are pre-built multi-step UI flows the main agent can pick when
17468
+ * the user's prompt matches a workflow's `whenToUse` trigger. Picking a
17469
+ * workflow short-circuits analysis text + dashboard component generation —
17470
+ * the workflow component is returned directly, with the LLM-extracted props.
17471
+ */
17472
+ setWorkflows(workflows) {
17473
+ this.workflows = workflows;
17474
+ logger.info(`Workflows stored in SDK: ${workflows.length} workflow(s)`);
17475
+ }
17476
+ /**
17477
+ * Get the registered workflow components.
17478
+ */
17479
+ getWorkflows() {
17480
+ return this.workflows;
17481
+ }
17306
17482
  /**
17307
17483
  * Apply model strategy to all LLM provider singletons
17308
17484
  * @param strategy - 'best', 'fast', or 'balanced'