@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.js CHANGED
@@ -379,6 +379,24 @@ var ComponentListResponseMessageSchema = import_zod3.z.object({
379
379
  type: import_zod3.z.literal("COMPONENT_LIST_RES"),
380
380
  payload: ComponentListResponsePayloadSchema
381
381
  });
382
+ var WorkflowDescriptorSchema = import_zod3.z.object({
383
+ id: import_zod3.z.string(),
384
+ name: import_zod3.z.string(),
385
+ description: import_zod3.z.string(),
386
+ whenToUse: import_zod3.z.string(),
387
+ propsSchema: import_zod3.z.record(import_zod3.z.string()),
388
+ defaultProps: import_zod3.z.record(import_zod3.z.unknown()).optional()
389
+ });
390
+ var WorkflowsSchema = import_zod3.z.array(WorkflowDescriptorSchema);
391
+ var WorkflowListResponsePayloadSchema = import_zod3.z.object({
392
+ workflows: import_zod3.z.array(WorkflowDescriptorSchema)
393
+ });
394
+ var WorkflowListResponseMessageSchema = import_zod3.z.object({
395
+ id: import_zod3.z.string(),
396
+ from: MessageParticipantSchema,
397
+ type: import_zod3.z.literal("WORKFLOW_LIST_RES"),
398
+ payload: WorkflowListResponsePayloadSchema
399
+ });
382
400
  var OutputFieldSchema = import_zod3.z.object({
383
401
  name: import_zod3.z.string(),
384
402
  // Field name (column name in the result)
@@ -7544,8 +7562,9 @@ Even if a table appears in the detailed schema above, search_schema returns samp
7544
7562
 
7545
7563
  // src/userResponse/agents/main-agent.ts
7546
7564
  var MainAgent = class {
7547
- constructor(externalTools, config, streamBuffer) {
7565
+ constructor(externalTools, config, streamBuffer, workflows = []) {
7548
7566
  this.externalTools = externalTools;
7567
+ this.workflows = workflows;
7549
7568
  this.config = config;
7550
7569
  this.streamBuffer = streamBuffer || new StreamBuffer();
7551
7570
  }
@@ -7564,18 +7583,26 @@ var MainAgent = class {
7564
7583
  logger.info(`[MainAgent] Starting | prompt: "${userPrompt.substring(0, 50)}..."`);
7565
7584
  const sourceTools = this.externalTools.filter((t) => t.toolType !== "direct");
7566
7585
  const directTools = this.externalTools.filter((t) => t.toolType === "direct");
7567
- logger.info(`[MainAgent] ${sourceTools.length} source tool(s), ${directTools.length} direct tool(s)`);
7586
+ logger.info(`[MainAgent] ${sourceTools.length} source tool(s), ${directTools.length} direct tool(s), ${this.workflows.length} workflow(s)`);
7568
7587
  const summaries = buildSourceSummaries(sourceTools);
7569
- const systemPrompt = await this.buildSystemPrompt(summaries, directTools, conversationHistory);
7588
+ const systemPrompt = await this.buildSystemPrompt(summaries, directTools, this.workflows, conversationHistory);
7570
7589
  logger.logLLMPrompt("mainAgent", "system", extractPromptText(systemPrompt));
7571
7590
  logger.logLLMPrompt("mainAgent", "user", userPrompt);
7572
7591
  const sourceToolDefs = this.buildSourceToolDefinitions(summaries);
7573
7592
  const directToolDefs = this.buildDirectToolDefinitions(directTools);
7574
- const tools = [...sourceToolDefs, ...directToolDefs];
7593
+ const workflowToolDefs = this.buildWorkflowToolDefinitions(this.workflows);
7594
+ const tools = [...sourceToolDefs, ...directToolDefs, ...workflowToolDefs];
7575
7595
  const sourceResults = [];
7576
7596
  const executedTools = [];
7577
7597
  let sourceCallCounter = 0;
7598
+ let selectedWorkflow;
7578
7599
  const toolHandler = async (toolName, toolInput) => {
7600
+ const workflow = this.workflows.find((w) => w.id === toolName);
7601
+ if (workflow) {
7602
+ return this.handleWorkflow(workflow, toolInput, (w) => {
7603
+ selectedWorkflow = w;
7604
+ });
7605
+ }
7579
7606
  const externalTool = this.externalTools.find((t) => t.id === toolName);
7580
7607
  if (!externalTool) {
7581
7608
  logger.error(`[MainAgent] Unknown tool called: ${toolName}`);
@@ -7626,11 +7653,14 @@ var MainAgent = class {
7626
7653
  this.config.maxIterations
7627
7654
  );
7628
7655
  const totalTime = Date.now() - startTime;
7629
- logger.info(`[MainAgent] Complete | ${sourceResults.length} source queries, ${executedTools.length} successful | ${totalTime}ms`);
7656
+ logger.info(
7657
+ `[MainAgent] Complete | ${sourceResults.length} source queries, ${executedTools.length} successful${selectedWorkflow ? ` | workflow="${selectedWorkflow.name}"` : ""} | ${totalTime}ms`
7658
+ );
7630
7659
  return {
7631
7660
  text,
7632
7661
  executedTools,
7633
- sourceResults
7662
+ sourceResults,
7663
+ workflow: selectedWorkflow
7634
7664
  };
7635
7665
  }
7636
7666
  // ============================================
@@ -7704,9 +7734,10 @@ ${formatted}`;
7704
7734
  // System Prompt
7705
7735
  // ============================================
7706
7736
  /**
7707
- * Build the main agent's system prompt with source summaries and direct tool descriptions.
7737
+ * Build the main agent's system prompt with source summaries, direct tool descriptions,
7738
+ * and workflow component descriptions.
7708
7739
  */
7709
- async buildSystemPrompt(summaries, directTools, conversationHistory) {
7740
+ async buildSystemPrompt(summaries, directTools, workflows, conversationHistory) {
7710
7741
  const summariesText = formatSummariesForPrompt(summaries);
7711
7742
  const maxSourceCalls = Math.max(2, this.config.maxIterations - 2);
7712
7743
  let directToolsText = "";
@@ -7718,9 +7749,25 @@ ${formatted}`;
7718
7749
  ${t.description || "No description"}${paramList ? "\n Parameters:\n" + paramList : ""}`;
7719
7750
  }).join("\n\n");
7720
7751
  }
7752
+ let workflowsText = "";
7753
+ if (workflows.length > 0) {
7754
+ workflowsText = workflows.map((w, idx) => {
7755
+ const propLines = Object.entries(w.propsSchema || {}).map(([k, v]) => ` - ${k}: ${v}`).join("\n");
7756
+ return [
7757
+ `${idx + 1}. **${w.name}** (tool: ${w.id})`,
7758
+ ` ${w.description}`,
7759
+ ` When to use: ${w.whenToUse}`,
7760
+ propLines ? ` Props:
7761
+ ${propLines}` : ""
7762
+ ].filter(Boolean).join("\n");
7763
+ }).join("\n\n");
7764
+ } else {
7765
+ workflowsText = "No workflow components registered for this project.";
7766
+ }
7721
7767
  const prompts = await promptLoader.loadPrompts("agent-main", {
7722
7768
  SOURCE_SUMMARIES: summariesText,
7723
7769
  DIRECT_TOOLS: directToolsText,
7770
+ WORKFLOW_COMPONENTS: workflowsText,
7724
7771
  MAX_ROWS: String(this.config.maxRowsPerSource),
7725
7772
  MAX_SOURCE_CALLS: String(maxSourceCalls),
7726
7773
  GLOBAL_KNOWLEDGE_BASE: this.config.globalKnowledgeBase || "No global knowledge base available.",
@@ -7807,6 +7854,70 @@ ${formatted}`;
7807
7854
  });
7808
7855
  }
7809
7856
  // ============================================
7857
+ // Workflow Handling
7858
+ // ============================================
7859
+ /**
7860
+ * Capture a workflow selection. We do NOT execute anything — the LLM has
7861
+ * already extracted the props it wants the workflow rendered with. We
7862
+ * record the selection (via the capture callback) and return a short
7863
+ * acknowledgement so the LLM ends its turn cleanly without writing
7864
+ * analysis text or calling more tools.
7865
+ */
7866
+ async handleWorkflow(workflow, toolInput, capture) {
7867
+ const props = { ...workflow.defaultProps || {}, ...toolInput || {} };
7868
+ logger.info(
7869
+ `[MainAgent] Workflow selected: "${workflow.name}" | props: ${JSON.stringify(props).substring(0, 200)}`
7870
+ );
7871
+ if (this.streamBuffer.hasCallback()) {
7872
+ this.streamBuffer.write(`
7873
+
7874
+ \u{1F9ED} **Launching ${workflow.name} workflow...**
7875
+
7876
+ `);
7877
+ await streamDelay();
7878
+ }
7879
+ capture({ name: workflow.name, props });
7880
+ 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.`;
7881
+ }
7882
+ /**
7883
+ * Build LLM tool definitions for workflow components. The workflow's
7884
+ * propsSchema becomes the tool's input_schema so the LLM extracts props
7885
+ * directly from the prompt — same mechanic as direct tools.
7886
+ */
7887
+ buildWorkflowToolDefinitions(workflows) {
7888
+ return workflows.map((workflow) => {
7889
+ const properties = {};
7890
+ const required = [];
7891
+ Object.entries(workflow.propsSchema || {}).forEach(([key, typeOrValue]) => {
7892
+ const valueStr = String(typeOrValue).toLowerCase();
7893
+ let schemaType = "string";
7894
+ const typeMatch = valueStr.match(/^(string|number|integer|boolean|array|object)\b/);
7895
+ if (typeMatch) {
7896
+ schemaType = typeMatch[1];
7897
+ }
7898
+ const isOptional = valueStr.includes("(optional)") || valueStr.includes("optional");
7899
+ const description = typeof typeOrValue === "string" ? typeOrValue : `Prop: ${key}`;
7900
+ if (schemaType === "array") {
7901
+ properties[key] = { type: "array", items: {}, description };
7902
+ } else if (schemaType === "object") {
7903
+ properties[key] = { type: "object", description };
7904
+ } else {
7905
+ properties[key] = { type: schemaType, description };
7906
+ }
7907
+ if (!isOptional) required.push(key);
7908
+ });
7909
+ return {
7910
+ name: workflow.id,
7911
+ description: `[WORKFLOW] ${workflow.description} \u2014 When to use: ${workflow.whenToUse}`,
7912
+ input_schema: {
7913
+ type: "object",
7914
+ properties,
7915
+ required: required.length > 0 ? required : void 0
7916
+ }
7917
+ };
7918
+ });
7919
+ }
7920
+ // ============================================
7810
7921
  // Format Result for Main Agent
7811
7922
  // ============================================
7812
7923
  /**
@@ -10458,7 +10569,7 @@ function getLLMInstance(provider) {
10458
10569
  return anthropicLLM;
10459
10570
  }
10460
10571
  }
10461
- var get_agent_user_response = async (prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, conversationHistory, streamCallback, collections, externalTools, userId, mainAgentModel, sourceAgentModel) => {
10572
+ var get_agent_user_response = async (prompt, components, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, conversationHistory, streamCallback, collections, externalTools, userId, mainAgentModel, sourceAgentModel, workflows) => {
10462
10573
  const startTime = Date.now();
10463
10574
  const providers = llmProviders || ["anthropic"];
10464
10575
  const provider = providers[0];
@@ -10560,13 +10671,35 @@ var get_agent_user_response = async (prompt, components, anthropicApiKey, groqAp
10560
10671
  knowledgeBaseContext
10561
10672
  };
10562
10673
  const streamBuffer = new StreamBuffer(streamCallback);
10563
- const mainAgent = new MainAgent(agentTools, agentConfig, streamBuffer);
10674
+ const mainAgent = new MainAgent(agentTools, agentConfig, streamBuffer, workflows || []);
10564
10675
  const agentResponse = await mainAgent.handleQuestion(
10565
10676
  prompt,
10566
10677
  apiKey,
10567
10678
  conversationHistory,
10568
10679
  streamBuffer.hasCallback() ? (chunk) => streamBuffer.write(chunk) : void 0
10569
10680
  );
10681
+ if (agentResponse.workflow) {
10682
+ streamBuffer.flush();
10683
+ const workflowComponent = {
10684
+ id: `workflow_${Date.now()}`,
10685
+ name: agentResponse.workflow.name,
10686
+ type: `Workflow_${agentResponse.workflow.name}`,
10687
+ description: `Workflow: ${agentResponse.workflow.name}`,
10688
+ props: agentResponse.workflow.props
10689
+ };
10690
+ const elapsedTime2 = Date.now() - startTime;
10691
+ logger.info(`[AgentFlow] Workflow short-circuit | "${agentResponse.workflow.name}" | ${elapsedTime2}ms`);
10692
+ return {
10693
+ success: true,
10694
+ data: {
10695
+ text: "",
10696
+ component: workflowComponent,
10697
+ actions: [],
10698
+ method: `${provider}-agent-workflow`
10699
+ },
10700
+ errors: []
10701
+ };
10702
+ }
10570
10703
  const rawText = streamBuffer.getFullText() || agentResponse.text || "I apologize, but I was unable to generate a response.";
10571
10704
  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, "");
10572
10705
  streamBuffer.flush();
@@ -10919,7 +11052,7 @@ var CONTEXT_CONFIG = {
10919
11052
  };
10920
11053
 
10921
11054
  // src/handlers/user-prompt-request.ts
10922
- var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, mainAgentModel, sourceAgentModel) => {
11055
+ var get_user_request = async (data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, mainAgentModel, sourceAgentModel, workflows) => {
10923
11056
  const errors = [];
10924
11057
  const parseResult = UserPromptRequestMessageSchema.safeParse(data);
10925
11058
  if (!parseResult.success) {
@@ -11005,7 +11138,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
11005
11138
  externalTools,
11006
11139
  userId,
11007
11140
  mainAgentModel,
11008
- sourceAgentModel
11141
+ sourceAgentModel,
11142
+ workflows
11009
11143
  );
11010
11144
  logger.info("User prompt request completed");
11011
11145
  const uiBlockId = existingUiBlockId;
@@ -11158,8 +11292,8 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
11158
11292
  wsId
11159
11293
  };
11160
11294
  };
11161
- async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, mainAgentModel, sourceAgentModel) {
11162
- const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, mainAgentModel, sourceAgentModel);
11295
+ async function handleUserPromptRequest(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, mainAgentModel, sourceAgentModel, workflows) {
11296
+ const response = await get_user_request(data, components, sendMessage, anthropicApiKey, groqApiKey, geminiApiKey, openaiApiKey, llmProviders, collections, externalTools, mainAgentModel, sourceAgentModel, workflows);
11163
11297
  if (response.data?.component?.props?.config?.components) {
11164
11298
  response.data.component.props.config.components = response.data.component.props.config.components.map((comp) => ({
11165
11299
  ...comp,
@@ -11591,6 +11725,24 @@ async function handleComponentListResponse(data, storeComponents, collections) {
11591
11725
  }
11592
11726
  }
11593
11727
 
11728
+ // src/handlers/workflow-list-response.ts
11729
+ async function handleWorkflowListResponse(data, storeWorkflows) {
11730
+ try {
11731
+ const parsed = WorkflowListResponseMessageSchema.parse(data);
11732
+ const { payload } = parsed;
11733
+ const workflowsList = payload.workflows;
11734
+ if (!workflowsList) {
11735
+ logger.error("Workflows list not found in WORKFLOW_LIST_RES payload");
11736
+ return;
11737
+ }
11738
+ const workflows = WorkflowsSchema.parse(workflowsList);
11739
+ storeWorkflows(workflows);
11740
+ logger.info(`Stored ${workflows.length} workflow descriptor(s) from frontend`);
11741
+ } catch (error) {
11742
+ logger.error("Failed to handle workflow list response:", error);
11743
+ }
11744
+ }
11745
+
11594
11746
  // src/handlers/users.ts
11595
11747
  async function handleUsersRequest(data, collections, sendMessage) {
11596
11748
  const executeCollection = async (collection, op, params) => {
@@ -16924,6 +17076,7 @@ var SuperatomSDK = class {
16924
17076
  this.collections = {};
16925
17077
  this.components = [];
16926
17078
  this.tools = [];
17079
+ this.workflows = [];
16927
17080
  // Heartbeat properties for keeping WebSocket connection alive
16928
17081
  this.pingInterval = null;
16929
17082
  this.lastPong = Date.now();
@@ -17105,7 +17258,7 @@ var SuperatomSDK = class {
17105
17258
  });
17106
17259
  break;
17107
17260
  case "USER_PROMPT_REQ":
17108
- 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) => {
17261
+ 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) => {
17109
17262
  logger.error("Failed to handle user prompt request:", error);
17110
17263
  });
17111
17264
  break;
@@ -17124,6 +17277,11 @@ var SuperatomSDK = class {
17124
17277
  logger.error("Failed to handle component list request:", error);
17125
17278
  });
17126
17279
  break;
17280
+ case "WORKFLOW_LIST_RES":
17281
+ handleWorkflowListResponse(parsed, (wf) => this.setWorkflows(wf)).catch((error) => {
17282
+ logger.error("Failed to handle workflow list request:", error);
17283
+ });
17284
+ break;
17127
17285
  case "USERS":
17128
17286
  handleUsersRequest(parsed, this.collections, (msg) => this.send(msg)).catch((error) => {
17129
17287
  logger.error("Failed to handle users request:", error);
@@ -17363,6 +17521,24 @@ var SuperatomSDK = class {
17363
17521
  getTools() {
17364
17522
  return this.tools;
17365
17523
  }
17524
+ /**
17525
+ * Register workflow components for the SDK instance.
17526
+ *
17527
+ * Workflows are pre-built multi-step UI flows the main agent can pick when
17528
+ * the user's prompt matches a workflow's `whenToUse` trigger. Picking a
17529
+ * workflow short-circuits analysis text + dashboard component generation —
17530
+ * the workflow component is returned directly, with the LLM-extracted props.
17531
+ */
17532
+ setWorkflows(workflows) {
17533
+ this.workflows = workflows;
17534
+ logger.info(`Workflows stored in SDK: ${workflows.length} workflow(s)`);
17535
+ }
17536
+ /**
17537
+ * Get the registered workflow components.
17538
+ */
17539
+ getWorkflows() {
17540
+ return this.workflows;
17541
+ }
17366
17542
  /**
17367
17543
  * Apply model strategy to all LLM provider singletons
17368
17544
  * @param strategy - 'best', 'fast', or 'balanced'