@polos/sdk 0.2.2 → 0.2.3

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.d.cts CHANGED
@@ -657,8 +657,11 @@ interface Channel {
657
657
  /**
658
658
  * Send a notification when an agent suspends for user input.
659
659
  * Implementations should throw on failure — the SDK catches and logs errors.
660
+ *
661
+ * May return channel-specific metadata (e.g., Slack message_ts) so the
662
+ * orchestrator can update the notification later (e.g., after approval via UI).
660
663
  */
661
- notify(notification: SuspendNotification): Promise<void>;
664
+ notify(notification: SuspendNotification): Promise<Record<string, unknown> | undefined>;
662
665
  /** Default output mode for this channel. */
663
666
  readonly outputMode?: ChannelOutputMode;
664
667
  /** Send output events back to the originating channel. */
@@ -1641,6 +1644,10 @@ interface BatchInvokeWorkflowsRequest {
1641
1644
  rootWorkflowId?: string | undefined;
1642
1645
  waitForSubworkflow?: boolean | undefined;
1643
1646
  otelTraceparent?: string | undefined;
1647
+ channelContext?: {
1648
+ channelId: string;
1649
+ source: Record<string, unknown>;
1650
+ } | undefined;
1644
1651
  }
1645
1652
  /**
1646
1653
  * Response from batch workflow invocation.
@@ -2927,6 +2934,8 @@ declare class Worker {
2927
2934
  private state;
2928
2935
  private heartbeatInterval;
2929
2936
  private activeExecutions;
2937
+ /** Tracks running channel bridges so we don't start duplicates on re-dispatch. */
2938
+ private activeChannelBridges;
2930
2939
  private signalHandler;
2931
2940
  constructor(config: WorkerConfig);
2932
2941
  /**
@@ -4950,7 +4959,7 @@ declare class SlackChannel implements Channel {
4950
4959
  readonly outputMode: ChannelOutputMode;
4951
4960
  private readonly config;
4952
4961
  constructor(config: SlackChannelConfig);
4953
- notify(notification: SuspendNotification): Promise<void>;
4962
+ notify(notification: SuspendNotification): Promise<Record<string, unknown> | undefined>;
4954
4963
  sendOutput(context: ChannelContext, event: StreamEvent): Promise<void>;
4955
4964
  private postMessage;
4956
4965
  private formatOutputEvent;
package/dist/index.d.ts CHANGED
@@ -657,8 +657,11 @@ interface Channel {
657
657
  /**
658
658
  * Send a notification when an agent suspends for user input.
659
659
  * Implementations should throw on failure — the SDK catches and logs errors.
660
+ *
661
+ * May return channel-specific metadata (e.g., Slack message_ts) so the
662
+ * orchestrator can update the notification later (e.g., after approval via UI).
660
663
  */
661
- notify(notification: SuspendNotification): Promise<void>;
664
+ notify(notification: SuspendNotification): Promise<Record<string, unknown> | undefined>;
662
665
  /** Default output mode for this channel. */
663
666
  readonly outputMode?: ChannelOutputMode;
664
667
  /** Send output events back to the originating channel. */
@@ -1641,6 +1644,10 @@ interface BatchInvokeWorkflowsRequest {
1641
1644
  rootWorkflowId?: string | undefined;
1642
1645
  waitForSubworkflow?: boolean | undefined;
1643
1646
  otelTraceparent?: string | undefined;
1647
+ channelContext?: {
1648
+ channelId: string;
1649
+ source: Record<string, unknown>;
1650
+ } | undefined;
1644
1651
  }
1645
1652
  /**
1646
1653
  * Response from batch workflow invocation.
@@ -2927,6 +2934,8 @@ declare class Worker {
2927
2934
  private state;
2928
2935
  private heartbeatInterval;
2929
2936
  private activeExecutions;
2937
+ /** Tracks running channel bridges so we don't start duplicates on re-dispatch. */
2938
+ private activeChannelBridges;
2930
2939
  private signalHandler;
2931
2940
  constructor(config: WorkerConfig);
2932
2941
  /**
@@ -4950,7 +4959,7 @@ declare class SlackChannel implements Channel {
4950
4959
  readonly outputMode: ChannelOutputMode;
4951
4960
  private readonly config;
4952
4961
  constructor(config: SlackChannelConfig);
4953
- notify(notification: SuspendNotification): Promise<void>;
4962
+ notify(notification: SuspendNotification): Promise<Record<string, unknown> | undefined>;
4954
4963
  sendOutput(context: ChannelContext, event: StreamEvent): Promise<void>;
4955
4964
  private postMessage;
4956
4965
  private formatOutputEvent;
package/dist/index.js CHANGED
@@ -722,6 +722,11 @@ var OrchestratorClient = class {
722
722
  if (request.waitForSubworkflow !== void 0)
723
723
  body["wait_for_subworkflow"] = request.waitForSubworkflow;
724
724
  if (request.otelTraceparent !== void 0) body["otel_traceparent"] = request.otelTraceparent;
725
+ if (request.channelContext !== void 0)
726
+ body["channel_context"] = {
727
+ channel_id: request.channelContext.channelId,
728
+ source: request.channelContext.source
729
+ };
725
730
  return this.request("POST", "/api/v1/workflows/batch_run", {
726
731
  body
727
732
  });
@@ -3355,6 +3360,187 @@ function defineAgent(config) {
3355
3360
  });
3356
3361
  return agentWorkflow;
3357
3362
  }
3363
+
3364
+ // src/channels/slack.ts
3365
+ var SlackChannel = class {
3366
+ id = "slack";
3367
+ outputMode = "per_step";
3368
+ config;
3369
+ constructor(config) {
3370
+ if (!config.botToken.startsWith("xoxb-")) {
3371
+ throw new Error(
3372
+ `Invalid Slack bot token: must start with "xoxb-". Use the Bot User OAuth Token from your Slack app's OAuth & Permissions page.`
3373
+ );
3374
+ }
3375
+ this.config = config;
3376
+ }
3377
+ async notify(notification) {
3378
+ const overrides = notification.channelOverrides;
3379
+ const channel = overrides?.["channel"] ?? this.config.defaultChannel;
3380
+ const threadTs = overrides?.["thread_ts"] ?? overrides?.["threadTs"];
3381
+ const blocks = this.buildBlocks(notification);
3382
+ const text = notification.title ?? "Agent needs your input";
3383
+ const messageTs = await this.postMessage(channel, threadTs, text, blocks);
3384
+ return {
3385
+ slack_channel: channel,
3386
+ slack_message_ts: messageTs,
3387
+ slack_blocks: blocks
3388
+ };
3389
+ }
3390
+ async sendOutput(context2, event) {
3391
+ const channel = context2.source["channel"];
3392
+ const threadTs = context2.source["threadTs"];
3393
+ if (!channel) return;
3394
+ const text = this.formatOutputEvent(event);
3395
+ if (!text) return;
3396
+ await this.postMessage(channel, threadTs, text);
3397
+ }
3398
+ async postMessage(channel, threadTs, text, blocks) {
3399
+ const body = { channel, text };
3400
+ if (threadTs) body["thread_ts"] = threadTs;
3401
+ if (blocks) body["blocks"] = blocks;
3402
+ const response = await fetch("https://slack.com/api/chat.postMessage", {
3403
+ method: "POST",
3404
+ headers: {
3405
+ Authorization: `Bearer ${this.config.botToken}`,
3406
+ "Content-Type": "application/json"
3407
+ },
3408
+ body: JSON.stringify(body)
3409
+ });
3410
+ const data = await response.json();
3411
+ if (!data.ok) {
3412
+ throw new Error(`Slack API error: ${data.error ?? "unknown"}`);
3413
+ }
3414
+ return data.ts ?? "";
3415
+ }
3416
+ formatOutputEvent(event) {
3417
+ const eventType = event.eventType;
3418
+ if (eventType === "workflow_finish" || eventType === "agent_finish") {
3419
+ const metadata = event.data["_metadata"];
3420
+ const rawResult = event.data["result"];
3421
+ const error = event.data["error"];
3422
+ const workflowId = metadata?.["workflow_id"];
3423
+ if (error) {
3424
+ return `\u274C *${workflowId ?? "Workflow"} failed:* ${error}`;
3425
+ }
3426
+ const result = typeof rawResult === "object" && rawResult !== null && "result" in rawResult ? rawResult["result"] : rawResult;
3427
+ const resultStr = typeof result === "string" ? result : JSON.stringify(result, null, 2);
3428
+ if (resultStr) {
3429
+ return resultStr;
3430
+ }
3431
+ return `\u2705 *${workflowId ?? "Workflow"} finished*`;
3432
+ }
3433
+ if (eventType === "tool_call") {
3434
+ const toolCall = event.data["tool_call"];
3435
+ if (toolCall) {
3436
+ const fn = toolCall["function"];
3437
+ const name = fn?.["name"];
3438
+ if (name) {
3439
+ return `\u{1F527} Calling tool: \`${name}\``;
3440
+ }
3441
+ }
3442
+ return null;
3443
+ }
3444
+ if (eventType === "step_finish") {
3445
+ const stepKey = event.data["step_key"];
3446
+ const error = event.data["error"];
3447
+ if (error) {
3448
+ return `\u26A0\uFE0F Step \`${stepKey ?? "unknown"}\` failed: ${error}`;
3449
+ }
3450
+ return null;
3451
+ }
3452
+ return null;
3453
+ }
3454
+ buildBlocks(n) {
3455
+ const blocks = [];
3456
+ blocks.push({
3457
+ type: "header",
3458
+ text: { type: "plain_text", text: n.title ?? "Agent needs your input" }
3459
+ });
3460
+ if (n.description) {
3461
+ blocks.push({
3462
+ type: "section",
3463
+ text: { type: "mrkdwn", text: n.description }
3464
+ });
3465
+ }
3466
+ if (n.source || n.tool) {
3467
+ const parts = [];
3468
+ if (n.source) parts.push(`*Source:* ${n.source}`);
3469
+ if (n.tool) parts.push(`*Tool:* \`${n.tool}\``);
3470
+ blocks.push({
3471
+ type: "context",
3472
+ elements: [{ type: "mrkdwn", text: parts.join(" | ") }]
3473
+ });
3474
+ }
3475
+ if (n.context && Object.keys(n.context).length > 0) {
3476
+ const contextText = JSON.stringify(n.context, null, 2);
3477
+ blocks.push({
3478
+ type: "section",
3479
+ text: { type: "mrkdwn", text: "```" + contextText + "```" }
3480
+ });
3481
+ }
3482
+ if (n.expiresAt) {
3483
+ blocks.push({
3484
+ type: "context",
3485
+ elements: [{ type: "mrkdwn", text: `Expires: ${n.expiresAt}` }]
3486
+ });
3487
+ }
3488
+ if (this.isSimpleApproval(n)) {
3489
+ const approveValue = JSON.stringify({
3490
+ executionId: n.executionId,
3491
+ stepKey: n.stepKey,
3492
+ approved: true
3493
+ });
3494
+ const rejectValue = JSON.stringify({
3495
+ executionId: n.executionId,
3496
+ stepKey: n.stepKey,
3497
+ approved: false
3498
+ });
3499
+ blocks.push({
3500
+ type: "actions",
3501
+ elements: [
3502
+ {
3503
+ type: "button",
3504
+ action_id: "polos_approve",
3505
+ text: { type: "plain_text", text: "Approve" },
3506
+ style: "primary",
3507
+ value: approveValue
3508
+ },
3509
+ {
3510
+ type: "button",
3511
+ action_id: "polos_reject",
3512
+ text: { type: "plain_text", text: "Reject" },
3513
+ style: "danger",
3514
+ value: rejectValue
3515
+ },
3516
+ {
3517
+ type: "button",
3518
+ text: { type: "plain_text", text: "View Details" },
3519
+ url: n.approvalUrl
3520
+ }
3521
+ ]
3522
+ });
3523
+ } else {
3524
+ blocks.push({
3525
+ type: "actions",
3526
+ elements: [
3527
+ {
3528
+ type: "button",
3529
+ text: { type: "plain_text", text: "Respond" },
3530
+ url: n.approvalUrl,
3531
+ style: "primary"
3532
+ }
3533
+ ]
3534
+ });
3535
+ }
3536
+ return blocks;
3537
+ }
3538
+ isSimpleApproval(n) {
3539
+ const fields = n.formFields;
3540
+ if (!fields || fields.length === 0) return false;
3541
+ return fields.some((f) => f["key"] === "approved" && f["type"] === "boolean");
3542
+ }
3543
+ };
3358
3544
  var logger4 = createLogger({ name: "worker-server" });
3359
3545
  var WorkerServer = class {
3360
3546
  app;
@@ -4208,7 +4394,8 @@ function createOrchestratorStepHelper(orchestratorClient, cachedSteps, execCtx,
4208
4394
  otelTraceparent: getCurrentTraceparent(),
4209
4395
  waitForSubworkflow: options?.waitForSubworkflow ?? false,
4210
4396
  initialState: options?.initialState,
4211
- runTimeoutSeconds: options?.runTimeoutSeconds
4397
+ runTimeoutSeconds: options?.runTimeoutSeconds,
4398
+ channelContext
4212
4399
  });
4213
4400
  if (options?.waitForSubworkflow) {
4214
4401
  return [void 0, false];
@@ -4396,7 +4583,8 @@ function createOrchestratorStepHelper(orchestratorClient, cachedSteps, execCtx,
4396
4583
  sessionId: execCtx.sessionId,
4397
4584
  userId: execCtx.userId,
4398
4585
  waitForSubworkflow: false,
4399
- otelTraceparent: getCurrentTraceparent()
4586
+ otelTraceparent: getCurrentTraceparent(),
4587
+ channelContext
4400
4588
  });
4401
4589
  const handleData = response.executions.map((exec, i) => {
4402
4590
  const item = items[i];
@@ -4472,7 +4660,8 @@ function createOrchestratorStepHelper(orchestratorClient, cachedSteps, execCtx,
4472
4660
  sessionId: execCtx.sessionId,
4473
4661
  userId: execCtx.userId,
4474
4662
  waitForSubworkflow: true,
4475
- otelTraceparent: getCurrentTraceparent()
4663
+ otelTraceparent: getCurrentTraceparent(),
4664
+ channelContext
4476
4665
  });
4477
4666
  const workflowIds = items.map((item) => typeof item.workflow === "string" ? item.workflow : item.workflow.id).join(", ");
4478
4667
  throw new WaitError(`Waiting for sub-workflows [${workflowIds}] to complete`, {
@@ -4668,7 +4857,7 @@ function createOrchestratorStepHelper(orchestratorClient, cachedSteps, execCtx,
4668
4857
  if (channelContext !== void 0) {
4669
4858
  notification.channelContext = channelContext;
4670
4859
  }
4671
- await Promise.allSettled(
4860
+ const notifyResults = await Promise.allSettled(
4672
4861
  channels.map(async (ch) => {
4673
4862
  try {
4674
4863
  let overrides = notifyConfig?.[ch.id];
@@ -4676,12 +4865,35 @@ function createOrchestratorStepHelper(orchestratorClient, cachedSteps, execCtx,
4676
4865
  overrides = { ...channelContext.source, ...overrides };
4677
4866
  }
4678
4867
  const n = overrides !== void 0 ? { ...notification, channelOverrides: overrides } : notification;
4679
- await ch.notify(n);
4868
+ const meta = await ch.notify(n);
4869
+ return meta ? { channelId: ch.id, ...meta } : void 0;
4680
4870
  } catch (err) {
4681
4871
  logger6.warn(`Channel ${ch.id} notification failed`, { error: String(err) });
4872
+ return void 0;
4682
4873
  }
4683
4874
  })
4684
4875
  );
4876
+ const metaEntries = [];
4877
+ for (const r of notifyResults) {
4878
+ if (r.status === "fulfilled" && r.value != null) {
4879
+ metaEntries.push(r.value);
4880
+ }
4881
+ }
4882
+ if (metaEntries.length > 0) {
4883
+ orchestratorClient.publishEvent({
4884
+ topic,
4885
+ events: [
4886
+ {
4887
+ eventType: `notification_meta_${key}`,
4888
+ data: { channels: metaEntries }
4889
+ }
4890
+ ],
4891
+ executionId: execCtx.executionId,
4892
+ rootExecutionId: execCtx.rootExecutionId
4893
+ }).catch((err) => {
4894
+ logger6.warn("Failed to publish notification metadata", { error: String(err) });
4895
+ });
4896
+ }
4685
4897
  }
4686
4898
  throw new WaitError(`Waiting for resume event: ${topic}`, { topic });
4687
4899
  },
@@ -6269,10 +6481,24 @@ var Worker = class {
6269
6481
  state = "stopped";
6270
6482
  heartbeatInterval = null;
6271
6483
  activeExecutions = /* @__PURE__ */ new Map();
6484
+ /** Tracks running channel bridges so we don't start duplicates on re-dispatch. */
6485
+ activeChannelBridges = /* @__PURE__ */ new Set();
6272
6486
  signalHandler = null;
6273
6487
  constructor(config) {
6274
6488
  this.config = config;
6275
6489
  this.channels = config.channels ?? [];
6490
+ if (!this.channels.some((ch) => ch.id === "slack")) {
6491
+ const slackBotToken = process.env["SLACK_BOT_TOKEN"];
6492
+ if (slackBotToken) {
6493
+ this.channels.push(
6494
+ new SlackChannel({
6495
+ botToken: slackBotToken,
6496
+ defaultChannel: process.env["SLACK_CHANNEL"] ?? "#general"
6497
+ })
6498
+ );
6499
+ logger9.info("Auto-registered SlackChannel from SLACK_BOT_TOKEN env var");
6500
+ }
6501
+ }
6276
6502
  this.maxConcurrentWorkflows = config.maxConcurrentWorkflows ?? 100;
6277
6503
  this.workerServerUrl = config.workerServerUrl ?? `http://localhost:${String(config.port ?? 8e3)}`;
6278
6504
  this.port = config.port ?? 8e3;
@@ -6806,6 +7032,11 @@ var Worker = class {
6806
7032
  };
6807
7033
  const hasWorkflowChannels = workflow.config.channels !== void 0;
6808
7034
  const resolvedChannels = workflow.config.channels ?? this.channels;
7035
+ if (data.channelContext && !data.parentExecutionId) {
7036
+ const rootExecId = data.rootExecutionId ?? executionId;
7037
+ const rootWfId = data.rootWorkflowId ?? workflowId;
7038
+ this.startChannelBridge(rootExecId, rootWfId, data.channelContext, workflow);
7039
+ }
6809
7040
  result = await executeWorkflow({
6810
7041
  workflow,
6811
7042
  payload: data.payload,
@@ -6817,9 +7048,6 @@ var Worker = class {
6817
7048
  sandboxManager: this.sandboxManager,
6818
7049
  channelContext: hasWorkflowChannels ? void 0 : data.channelContext
6819
7050
  });
6820
- if (data.channelContext) {
6821
- this.startChannelBridge(executionId, workflowId, data.channelContext, workflow);
6822
- }
6823
7051
  await this.handleExecutionResult(executionId, workflowId, context2, result);
6824
7052
  retryableFailure = !result.success && !result.waiting && (result.retryable ?? true);
6825
7053
  } catch (error) {
@@ -6962,15 +7190,20 @@ var Worker = class {
6962
7190
  /**
6963
7191
  * Start a channel bridge that streams execution events back to the originating channel.
6964
7192
  */
6965
- startChannelBridge(executionId, workflowId, channelCtx, workflow) {
7193
+ startChannelBridge(rootExecutionId, rootWorkflowId, channelCtx, workflow) {
7194
+ if (this.activeChannelBridges.has(rootExecutionId)) return;
6966
7195
  const channel = this.channels.find((ch) => ch.id === channelCtx.channelId);
6967
- if (!channel?.sendOutput) return;
7196
+ if (!channel) {
7197
+ logger9.error(
7198
+ `No channel registered for "${channelCtx.channelId}". ` + (channelCtx.channelId === "slack" ? "Set the SLACK_BOT_TOKEN environment variable so the worker can respond to Slack." : `Register a channel with id "${channelCtx.channelId}" on the worker.`),
7199
+ { executionId: rootExecutionId }
7200
+ );
7201
+ return;
7202
+ }
7203
+ if (!channel.sendOutput) return;
6968
7204
  const outputMode = workflow.config["channelOutputMode"] ?? channel.outputMode ?? "per_step";
6969
7205
  if (outputMode === "none") return;
6970
- const execution = this.activeExecutions.get(executionId);
6971
- if (!execution) return;
6972
- const rootExecutionId = execution.abortController.signal.aborted ? executionId : executionId;
6973
- const rootWorkflowId = workflowId;
7206
+ this.activeChannelBridges.add(rootExecutionId);
6974
7207
  void (async () => {
6975
7208
  try {
6976
7209
  const stream = this.orchestratorClient.streamEvents({
@@ -6978,13 +7211,14 @@ var Worker = class {
6978
7211
  workflowRunId: rootExecutionId
6979
7212
  });
6980
7213
  for await (const event of stream) {
6981
- if (execution.abortController.signal.aborted) break;
6982
7214
  if (shouldForwardEvent(event, outputMode)) {
6983
7215
  await channel.sendOutput?.(channelCtx, event);
6984
7216
  }
6985
7217
  }
6986
7218
  } catch (err) {
6987
- logger9.warn("Channel bridge error", { error: String(err), executionId });
7219
+ logger9.warn("Channel bridge error", { error: String(err), executionId: rootExecutionId });
7220
+ } finally {
7221
+ this.activeChannelBridges.delete(rootExecutionId);
6988
7222
  }
6989
7223
  })();
6990
7224
  }
@@ -7689,181 +7923,6 @@ function sandboxTools(config) {
7689
7923
  return tools;
7690
7924
  }
7691
7925
 
7692
- // src/channels/slack.ts
7693
- var SlackChannel = class {
7694
- id = "slack";
7695
- outputMode = "per_step";
7696
- config;
7697
- constructor(config) {
7698
- if (!config.botToken.startsWith("xoxb-")) {
7699
- throw new Error(
7700
- `Invalid Slack bot token: must start with "xoxb-". Use the Bot User OAuth Token from your Slack app's OAuth & Permissions page.`
7701
- );
7702
- }
7703
- this.config = config;
7704
- }
7705
- async notify(notification) {
7706
- const overrides = notification.channelOverrides;
7707
- const channel = overrides?.["channel"] ?? this.config.defaultChannel;
7708
- const threadTs = overrides?.["thread_ts"];
7709
- const blocks = this.buildBlocks(notification);
7710
- const text = notification.title ?? "Agent needs your input";
7711
- await this.postMessage(channel, threadTs, text, blocks);
7712
- }
7713
- async sendOutput(context2, event) {
7714
- const channel = context2.source["channel"];
7715
- const threadTs = context2.source["threadTs"];
7716
- if (!channel) return;
7717
- const text = this.formatOutputEvent(event);
7718
- if (!text) return;
7719
- await this.postMessage(channel, threadTs, text);
7720
- }
7721
- async postMessage(channel, threadTs, text, blocks) {
7722
- const body = { channel, text };
7723
- if (threadTs) body["thread_ts"] = threadTs;
7724
- if (blocks) body["blocks"] = blocks;
7725
- const response = await fetch("https://slack.com/api/chat.postMessage", {
7726
- method: "POST",
7727
- headers: {
7728
- Authorization: `Bearer ${this.config.botToken}`,
7729
- "Content-Type": "application/json"
7730
- },
7731
- body: JSON.stringify(body)
7732
- });
7733
- const data = await response.json();
7734
- if (!data.ok) {
7735
- throw new Error(`Slack API error: ${data.error ?? "unknown"}`);
7736
- }
7737
- }
7738
- formatOutputEvent(event) {
7739
- const eventType = event.eventType;
7740
- if (eventType === "workflow_finish" || eventType === "agent_finish") {
7741
- const metadata = event.data["_metadata"];
7742
- const result = event.data["result"];
7743
- const error = event.data["error"];
7744
- const workflowId = metadata?.["workflow_id"];
7745
- if (error) {
7746
- return `\u274C *${workflowId ?? "Workflow"} failed:* ${error}`;
7747
- }
7748
- const resultStr = typeof result === "string" ? result : JSON.stringify(result, null, 2);
7749
- if (resultStr) {
7750
- return `\u2705 *${workflowId ?? "Workflow"} finished:*
7751
- ${resultStr}`;
7752
- }
7753
- return `\u2705 *${workflowId ?? "Workflow"} finished*`;
7754
- }
7755
- if (eventType === "tool_call") {
7756
- const toolCall = event.data["tool_call"];
7757
- if (toolCall) {
7758
- const fn = toolCall["function"];
7759
- const name = fn?.["name"];
7760
- if (name) {
7761
- return `\u{1F527} Calling tool: \`${name}\``;
7762
- }
7763
- }
7764
- return null;
7765
- }
7766
- if (eventType === "step_finish") {
7767
- const stepKey = event.data["step_key"];
7768
- const error = event.data["error"];
7769
- if (error) {
7770
- return `\u26A0\uFE0F Step \`${stepKey ?? "unknown"}\` failed: ${error}`;
7771
- }
7772
- return null;
7773
- }
7774
- return null;
7775
- }
7776
- buildBlocks(n) {
7777
- const blocks = [];
7778
- blocks.push({
7779
- type: "header",
7780
- text: { type: "plain_text", text: n.title ?? "Agent needs your input" }
7781
- });
7782
- if (n.description) {
7783
- blocks.push({
7784
- type: "section",
7785
- text: { type: "mrkdwn", text: n.description }
7786
- });
7787
- }
7788
- if (n.source || n.tool) {
7789
- const parts = [];
7790
- if (n.source) parts.push(`*Source:* ${n.source}`);
7791
- if (n.tool) parts.push(`*Tool:* \`${n.tool}\``);
7792
- blocks.push({
7793
- type: "context",
7794
- elements: [{ type: "mrkdwn", text: parts.join(" | ") }]
7795
- });
7796
- }
7797
- if (n.context && Object.keys(n.context).length > 0) {
7798
- const contextText = JSON.stringify(n.context, null, 2);
7799
- blocks.push({
7800
- type: "section",
7801
- text: { type: "mrkdwn", text: "```" + contextText + "```" }
7802
- });
7803
- }
7804
- if (n.expiresAt) {
7805
- blocks.push({
7806
- type: "context",
7807
- elements: [{ type: "mrkdwn", text: `Expires: ${n.expiresAt}` }]
7808
- });
7809
- }
7810
- if (this.isSimpleApproval(n)) {
7811
- const approveValue = JSON.stringify({
7812
- executionId: n.executionId,
7813
- stepKey: n.stepKey,
7814
- approved: true
7815
- });
7816
- const rejectValue = JSON.stringify({
7817
- executionId: n.executionId,
7818
- stepKey: n.stepKey,
7819
- approved: false
7820
- });
7821
- blocks.push({
7822
- type: "actions",
7823
- elements: [
7824
- {
7825
- type: "button",
7826
- action_id: "polos_approve",
7827
- text: { type: "plain_text", text: "Approve" },
7828
- style: "primary",
7829
- value: approveValue
7830
- },
7831
- {
7832
- type: "button",
7833
- action_id: "polos_reject",
7834
- text: { type: "plain_text", text: "Reject" },
7835
- style: "danger",
7836
- value: rejectValue
7837
- },
7838
- {
7839
- type: "button",
7840
- text: { type: "plain_text", text: "View Details" },
7841
- url: n.approvalUrl
7842
- }
7843
- ]
7844
- });
7845
- } else {
7846
- blocks.push({
7847
- type: "actions",
7848
- elements: [
7849
- {
7850
- type: "button",
7851
- text: { type: "plain_text", text: "Respond" },
7852
- url: n.approvalUrl,
7853
- style: "primary"
7854
- }
7855
- ]
7856
- });
7857
- }
7858
- return blocks;
7859
- }
7860
- isSimpleApproval(n) {
7861
- const fields = n.formFields;
7862
- if (!fields || fields.length === 0) return false;
7863
- return fields.some((f) => f["key"] === "approved" && f["type"] === "boolean");
7864
- }
7865
- };
7866
-
7867
7926
  export { AgentRunConfig, DockerEnvironment, DuplicateWorkflowError, ExecutionHandle, GuardrailError, GuardrailResult2 as GuardrailResult, HookExecutionError, HookResult, LLM, ManagedSandbox, GuardrailResult as MiddlewareGuardrailResult, OrchestratorApiError, OrchestratorClient, Polos, PolosClient, Queue, SandboxManager, SlackChannel, StateSizeError, StateValidationError, StepExecutionError, StreamResult, WaitError, Worker, WorkerServer, WorkflowNotFoundError, agentStreamFunction, assertSafePath, batchAgentInvoke, batchInvoke, buildSummaryMessages, compactIfNeeded, composeGuardrails, composeHooks, conditionalHook, configureLogging, convertFinishReason, convertMiddlewareToolCallToPython, convertPythonToolCallToMiddleware, convertToolResultsToMessages, convertToolsToVercel, convertVercelToolCallToPython, convertVercelUsageToPython, createAskUserTool, createEditTool, createExecTool, createGlobTool, createGrepTool, createLogger, createReadTool, createStepHelper, createStepStore, createWebSearchTool, createWorkflowRegistry, createWriteTool, defineAgent, defineGuardrail, defineHook, defineTool, defineWorkflow, estimateMessageTokens, estimateMessagesTokens, estimateTokens, evaluateAllowlist, executeGuardrailChain, executeGuardrailsOrThrow, executeHookChain, executeHooksOrThrow, executeWorkflow, executedTool, extractTraceparent, generateTraceIdFromExecutionId, getTracer, globalRegistry, hasText, initializeOtel, initializeState, isAgentWorkflow, isBinary, isGuardrail, isHook, isOtelAvailable, isToolWorkflow, isWaitError, llmGenerate, llmStream, maxSteps, maxTokens, normalizeGuardrail, normalizeGuardrails, normalizeHook, normalizeHooks, parseGrepOutput, retry, sandboxTools, serializeFinalState, sleep, stopCondition, stripAnsi, truncateOutput, validateState };
7868
7927
  //# sourceMappingURL=index.js.map
7869
7928
  //# sourceMappingURL=index.js.map