@polos/sdk 0.2.1 → 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.cjs +294 -193
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +294 -193
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
},
|
|
@@ -5322,7 +5534,27 @@ function spawnCommand(command, args, options) {
|
|
|
5322
5534
|
killed = true;
|
|
5323
5535
|
proc.kill("SIGKILL");
|
|
5324
5536
|
}, timeoutMs);
|
|
5537
|
+
let exitGraceTimer = null;
|
|
5538
|
+
let exitCode = null;
|
|
5539
|
+
proc.on("exit", (code) => {
|
|
5540
|
+
exitCode = code;
|
|
5541
|
+
exitGraceTimer = setTimeout(() => {
|
|
5542
|
+
clearTimeout(timer);
|
|
5543
|
+
settle(() => {
|
|
5544
|
+
if (killed) {
|
|
5545
|
+
resolve10({
|
|
5546
|
+
exitCode: 137,
|
|
5547
|
+
stdout,
|
|
5548
|
+
stderr: stderr + "\n[Process killed: timeout exceeded]"
|
|
5549
|
+
});
|
|
5550
|
+
} else {
|
|
5551
|
+
resolve10({ exitCode: exitCode ?? 1, stdout, stderr });
|
|
5552
|
+
}
|
|
5553
|
+
});
|
|
5554
|
+
}, 2e3);
|
|
5555
|
+
});
|
|
5325
5556
|
proc.on("close", (code) => {
|
|
5557
|
+
if (exitGraceTimer) clearTimeout(exitGraceTimer);
|
|
5326
5558
|
clearTimeout(timer);
|
|
5327
5559
|
settle(() => {
|
|
5328
5560
|
if (killed) {
|
|
@@ -5332,11 +5564,12 @@ function spawnCommand(command, args, options) {
|
|
|
5332
5564
|
stderr: stderr + "\n[Process killed: timeout exceeded]"
|
|
5333
5565
|
});
|
|
5334
5566
|
} else {
|
|
5335
|
-
resolve10({ exitCode: code ?? 1, stdout, stderr });
|
|
5567
|
+
resolve10({ exitCode: code ?? exitCode ?? 1, stdout, stderr });
|
|
5336
5568
|
}
|
|
5337
5569
|
});
|
|
5338
5570
|
});
|
|
5339
5571
|
proc.on("error", (err) => {
|
|
5572
|
+
if (exitGraceTimer) clearTimeout(exitGraceTimer);
|
|
5340
5573
|
clearTimeout(timer);
|
|
5341
5574
|
settle(() => {
|
|
5342
5575
|
reject(err);
|
|
@@ -5582,7 +5815,27 @@ function spawnLocal(command, options) {
|
|
|
5582
5815
|
killed = true;
|
|
5583
5816
|
proc.kill("SIGKILL");
|
|
5584
5817
|
}, timeoutMs);
|
|
5818
|
+
let exitGraceTimer = null;
|
|
5819
|
+
let exitCode = null;
|
|
5820
|
+
proc.on("exit", (code) => {
|
|
5821
|
+
exitCode = code;
|
|
5822
|
+
exitGraceTimer = setTimeout(() => {
|
|
5823
|
+
clearTimeout(timer);
|
|
5824
|
+
settle(() => {
|
|
5825
|
+
if (killed) {
|
|
5826
|
+
resolve10({
|
|
5827
|
+
exitCode: 137,
|
|
5828
|
+
stdout,
|
|
5829
|
+
stderr: stderr + "\n[Process killed: timeout exceeded]"
|
|
5830
|
+
});
|
|
5831
|
+
} else {
|
|
5832
|
+
resolve10({ exitCode: exitCode ?? 1, stdout, stderr });
|
|
5833
|
+
}
|
|
5834
|
+
});
|
|
5835
|
+
}, 2e3);
|
|
5836
|
+
});
|
|
5585
5837
|
proc.on("close", (code) => {
|
|
5838
|
+
if (exitGraceTimer) clearTimeout(exitGraceTimer);
|
|
5586
5839
|
clearTimeout(timer);
|
|
5587
5840
|
settle(() => {
|
|
5588
5841
|
if (killed) {
|
|
@@ -5592,11 +5845,12 @@ function spawnLocal(command, options) {
|
|
|
5592
5845
|
stderr: stderr + "\n[Process killed: timeout exceeded]"
|
|
5593
5846
|
});
|
|
5594
5847
|
} else {
|
|
5595
|
-
resolve10({ exitCode: code ?? 1, stdout, stderr });
|
|
5848
|
+
resolve10({ exitCode: code ?? exitCode ?? 1, stdout, stderr });
|
|
5596
5849
|
}
|
|
5597
5850
|
});
|
|
5598
5851
|
});
|
|
5599
5852
|
proc.on("error", (err) => {
|
|
5853
|
+
if (exitGraceTimer) clearTimeout(exitGraceTimer);
|
|
5600
5854
|
clearTimeout(timer);
|
|
5601
5855
|
settle(() => {
|
|
5602
5856
|
reject(err);
|
|
@@ -6227,10 +6481,24 @@ var Worker = class {
|
|
|
6227
6481
|
state = "stopped";
|
|
6228
6482
|
heartbeatInterval = null;
|
|
6229
6483
|
activeExecutions = /* @__PURE__ */ new Map();
|
|
6484
|
+
/** Tracks running channel bridges so we don't start duplicates on re-dispatch. */
|
|
6485
|
+
activeChannelBridges = /* @__PURE__ */ new Set();
|
|
6230
6486
|
signalHandler = null;
|
|
6231
6487
|
constructor(config) {
|
|
6232
6488
|
this.config = config;
|
|
6233
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
|
+
}
|
|
6234
6502
|
this.maxConcurrentWorkflows = config.maxConcurrentWorkflows ?? 100;
|
|
6235
6503
|
this.workerServerUrl = config.workerServerUrl ?? `http://localhost:${String(config.port ?? 8e3)}`;
|
|
6236
6504
|
this.port = config.port ?? 8e3;
|
|
@@ -6764,6 +7032,11 @@ var Worker = class {
|
|
|
6764
7032
|
};
|
|
6765
7033
|
const hasWorkflowChannels = workflow.config.channels !== void 0;
|
|
6766
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
|
+
}
|
|
6767
7040
|
result = await executeWorkflow({
|
|
6768
7041
|
workflow,
|
|
6769
7042
|
payload: data.payload,
|
|
@@ -6775,9 +7048,6 @@ var Worker = class {
|
|
|
6775
7048
|
sandboxManager: this.sandboxManager,
|
|
6776
7049
|
channelContext: hasWorkflowChannels ? void 0 : data.channelContext
|
|
6777
7050
|
});
|
|
6778
|
-
if (data.channelContext) {
|
|
6779
|
-
this.startChannelBridge(executionId, workflowId, data.channelContext, workflow);
|
|
6780
|
-
}
|
|
6781
7051
|
await this.handleExecutionResult(executionId, workflowId, context2, result);
|
|
6782
7052
|
retryableFailure = !result.success && !result.waiting && (result.retryable ?? true);
|
|
6783
7053
|
} catch (error) {
|
|
@@ -6920,15 +7190,20 @@ var Worker = class {
|
|
|
6920
7190
|
/**
|
|
6921
7191
|
* Start a channel bridge that streams execution events back to the originating channel.
|
|
6922
7192
|
*/
|
|
6923
|
-
startChannelBridge(
|
|
7193
|
+
startChannelBridge(rootExecutionId, rootWorkflowId, channelCtx, workflow) {
|
|
7194
|
+
if (this.activeChannelBridges.has(rootExecutionId)) return;
|
|
6924
7195
|
const channel = this.channels.find((ch) => ch.id === channelCtx.channelId);
|
|
6925
|
-
if (!channel
|
|
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;
|
|
6926
7204
|
const outputMode = workflow.config["channelOutputMode"] ?? channel.outputMode ?? "per_step";
|
|
6927
7205
|
if (outputMode === "none") return;
|
|
6928
|
-
|
|
6929
|
-
if (!execution) return;
|
|
6930
|
-
const rootExecutionId = execution.abortController.signal.aborted ? executionId : executionId;
|
|
6931
|
-
const rootWorkflowId = workflowId;
|
|
7206
|
+
this.activeChannelBridges.add(rootExecutionId);
|
|
6932
7207
|
void (async () => {
|
|
6933
7208
|
try {
|
|
6934
7209
|
const stream = this.orchestratorClient.streamEvents({
|
|
@@ -6936,13 +7211,14 @@ var Worker = class {
|
|
|
6936
7211
|
workflowRunId: rootExecutionId
|
|
6937
7212
|
});
|
|
6938
7213
|
for await (const event of stream) {
|
|
6939
|
-
if (execution.abortController.signal.aborted) break;
|
|
6940
7214
|
if (shouldForwardEvent(event, outputMode)) {
|
|
6941
7215
|
await channel.sendOutput?.(channelCtx, event);
|
|
6942
7216
|
}
|
|
6943
7217
|
}
|
|
6944
7218
|
} catch (err) {
|
|
6945
|
-
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);
|
|
6946
7222
|
}
|
|
6947
7223
|
})();
|
|
6948
7224
|
}
|
|
@@ -7647,181 +7923,6 @@ function sandboxTools(config) {
|
|
|
7647
7923
|
return tools;
|
|
7648
7924
|
}
|
|
7649
7925
|
|
|
7650
|
-
// src/channels/slack.ts
|
|
7651
|
-
var SlackChannel = class {
|
|
7652
|
-
id = "slack";
|
|
7653
|
-
outputMode = "per_step";
|
|
7654
|
-
config;
|
|
7655
|
-
constructor(config) {
|
|
7656
|
-
if (!config.botToken.startsWith("xoxb-")) {
|
|
7657
|
-
throw new Error(
|
|
7658
|
-
`Invalid Slack bot token: must start with "xoxb-". Use the Bot User OAuth Token from your Slack app's OAuth & Permissions page.`
|
|
7659
|
-
);
|
|
7660
|
-
}
|
|
7661
|
-
this.config = config;
|
|
7662
|
-
}
|
|
7663
|
-
async notify(notification) {
|
|
7664
|
-
const overrides = notification.channelOverrides;
|
|
7665
|
-
const channel = overrides?.["channel"] ?? this.config.defaultChannel;
|
|
7666
|
-
const threadTs = overrides?.["thread_ts"];
|
|
7667
|
-
const blocks = this.buildBlocks(notification);
|
|
7668
|
-
const text = notification.title ?? "Agent needs your input";
|
|
7669
|
-
await this.postMessage(channel, threadTs, text, blocks);
|
|
7670
|
-
}
|
|
7671
|
-
async sendOutput(context2, event) {
|
|
7672
|
-
const channel = context2.source["channel"];
|
|
7673
|
-
const threadTs = context2.source["threadTs"];
|
|
7674
|
-
if (!channel) return;
|
|
7675
|
-
const text = this.formatOutputEvent(event);
|
|
7676
|
-
if (!text) return;
|
|
7677
|
-
await this.postMessage(channel, threadTs, text);
|
|
7678
|
-
}
|
|
7679
|
-
async postMessage(channel, threadTs, text, blocks) {
|
|
7680
|
-
const body = { channel, text };
|
|
7681
|
-
if (threadTs) body["thread_ts"] = threadTs;
|
|
7682
|
-
if (blocks) body["blocks"] = blocks;
|
|
7683
|
-
const response = await fetch("https://slack.com/api/chat.postMessage", {
|
|
7684
|
-
method: "POST",
|
|
7685
|
-
headers: {
|
|
7686
|
-
Authorization: `Bearer ${this.config.botToken}`,
|
|
7687
|
-
"Content-Type": "application/json"
|
|
7688
|
-
},
|
|
7689
|
-
body: JSON.stringify(body)
|
|
7690
|
-
});
|
|
7691
|
-
const data = await response.json();
|
|
7692
|
-
if (!data.ok) {
|
|
7693
|
-
throw new Error(`Slack API error: ${data.error ?? "unknown"}`);
|
|
7694
|
-
}
|
|
7695
|
-
}
|
|
7696
|
-
formatOutputEvent(event) {
|
|
7697
|
-
const eventType = event.eventType;
|
|
7698
|
-
if (eventType === "workflow_finish" || eventType === "agent_finish") {
|
|
7699
|
-
const metadata = event.data["_metadata"];
|
|
7700
|
-
const result = event.data["result"];
|
|
7701
|
-
const error = event.data["error"];
|
|
7702
|
-
const workflowId = metadata?.["workflow_id"];
|
|
7703
|
-
if (error) {
|
|
7704
|
-
return `\u274C *${workflowId ?? "Workflow"} failed:* ${error}`;
|
|
7705
|
-
}
|
|
7706
|
-
const resultStr = typeof result === "string" ? result : JSON.stringify(result, null, 2);
|
|
7707
|
-
if (resultStr) {
|
|
7708
|
-
return `\u2705 *${workflowId ?? "Workflow"} finished:*
|
|
7709
|
-
${resultStr}`;
|
|
7710
|
-
}
|
|
7711
|
-
return `\u2705 *${workflowId ?? "Workflow"} finished*`;
|
|
7712
|
-
}
|
|
7713
|
-
if (eventType === "tool_call") {
|
|
7714
|
-
const toolCall = event.data["tool_call"];
|
|
7715
|
-
if (toolCall) {
|
|
7716
|
-
const fn = toolCall["function"];
|
|
7717
|
-
const name = fn?.["name"];
|
|
7718
|
-
if (name) {
|
|
7719
|
-
return `\u{1F527} Calling tool: \`${name}\``;
|
|
7720
|
-
}
|
|
7721
|
-
}
|
|
7722
|
-
return null;
|
|
7723
|
-
}
|
|
7724
|
-
if (eventType === "step_finish") {
|
|
7725
|
-
const stepKey = event.data["step_key"];
|
|
7726
|
-
const error = event.data["error"];
|
|
7727
|
-
if (error) {
|
|
7728
|
-
return `\u26A0\uFE0F Step \`${stepKey ?? "unknown"}\` failed: ${error}`;
|
|
7729
|
-
}
|
|
7730
|
-
return null;
|
|
7731
|
-
}
|
|
7732
|
-
return null;
|
|
7733
|
-
}
|
|
7734
|
-
buildBlocks(n) {
|
|
7735
|
-
const blocks = [];
|
|
7736
|
-
blocks.push({
|
|
7737
|
-
type: "header",
|
|
7738
|
-
text: { type: "plain_text", text: n.title ?? "Agent needs your input" }
|
|
7739
|
-
});
|
|
7740
|
-
if (n.description) {
|
|
7741
|
-
blocks.push({
|
|
7742
|
-
type: "section",
|
|
7743
|
-
text: { type: "mrkdwn", text: n.description }
|
|
7744
|
-
});
|
|
7745
|
-
}
|
|
7746
|
-
if (n.source || n.tool) {
|
|
7747
|
-
const parts = [];
|
|
7748
|
-
if (n.source) parts.push(`*Source:* ${n.source}`);
|
|
7749
|
-
if (n.tool) parts.push(`*Tool:* \`${n.tool}\``);
|
|
7750
|
-
blocks.push({
|
|
7751
|
-
type: "context",
|
|
7752
|
-
elements: [{ type: "mrkdwn", text: parts.join(" | ") }]
|
|
7753
|
-
});
|
|
7754
|
-
}
|
|
7755
|
-
if (n.context && Object.keys(n.context).length > 0) {
|
|
7756
|
-
const contextText = JSON.stringify(n.context, null, 2);
|
|
7757
|
-
blocks.push({
|
|
7758
|
-
type: "section",
|
|
7759
|
-
text: { type: "mrkdwn", text: "```" + contextText + "```" }
|
|
7760
|
-
});
|
|
7761
|
-
}
|
|
7762
|
-
if (n.expiresAt) {
|
|
7763
|
-
blocks.push({
|
|
7764
|
-
type: "context",
|
|
7765
|
-
elements: [{ type: "mrkdwn", text: `Expires: ${n.expiresAt}` }]
|
|
7766
|
-
});
|
|
7767
|
-
}
|
|
7768
|
-
if (this.isSimpleApproval(n)) {
|
|
7769
|
-
const approveValue = JSON.stringify({
|
|
7770
|
-
executionId: n.executionId,
|
|
7771
|
-
stepKey: n.stepKey,
|
|
7772
|
-
approved: true
|
|
7773
|
-
});
|
|
7774
|
-
const rejectValue = JSON.stringify({
|
|
7775
|
-
executionId: n.executionId,
|
|
7776
|
-
stepKey: n.stepKey,
|
|
7777
|
-
approved: false
|
|
7778
|
-
});
|
|
7779
|
-
blocks.push({
|
|
7780
|
-
type: "actions",
|
|
7781
|
-
elements: [
|
|
7782
|
-
{
|
|
7783
|
-
type: "button",
|
|
7784
|
-
action_id: "polos_approve",
|
|
7785
|
-
text: { type: "plain_text", text: "Approve" },
|
|
7786
|
-
style: "primary",
|
|
7787
|
-
value: approveValue
|
|
7788
|
-
},
|
|
7789
|
-
{
|
|
7790
|
-
type: "button",
|
|
7791
|
-
action_id: "polos_reject",
|
|
7792
|
-
text: { type: "plain_text", text: "Reject" },
|
|
7793
|
-
style: "danger",
|
|
7794
|
-
value: rejectValue
|
|
7795
|
-
},
|
|
7796
|
-
{
|
|
7797
|
-
type: "button",
|
|
7798
|
-
text: { type: "plain_text", text: "View Details" },
|
|
7799
|
-
url: n.approvalUrl
|
|
7800
|
-
}
|
|
7801
|
-
]
|
|
7802
|
-
});
|
|
7803
|
-
} else {
|
|
7804
|
-
blocks.push({
|
|
7805
|
-
type: "actions",
|
|
7806
|
-
elements: [
|
|
7807
|
-
{
|
|
7808
|
-
type: "button",
|
|
7809
|
-
text: { type: "plain_text", text: "Respond" },
|
|
7810
|
-
url: n.approvalUrl,
|
|
7811
|
-
style: "primary"
|
|
7812
|
-
}
|
|
7813
|
-
]
|
|
7814
|
-
});
|
|
7815
|
-
}
|
|
7816
|
-
return blocks;
|
|
7817
|
-
}
|
|
7818
|
-
isSimpleApproval(n) {
|
|
7819
|
-
const fields = n.formFields;
|
|
7820
|
-
if (!fields || fields.length === 0) return false;
|
|
7821
|
-
return fields.some((f) => f["key"] === "approved" && f["type"] === "boolean");
|
|
7822
|
-
}
|
|
7823
|
-
};
|
|
7824
|
-
|
|
7825
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 };
|
|
7826
7927
|
//# sourceMappingURL=index.js.map
|
|
7827
7928
|
//# sourceMappingURL=index.js.map
|