@coreplane/switchboard 1.216.0 → 1.216.2
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.
|
@@ -439,7 +439,10 @@ export default {
|
|
|
439
439
|
: pathname === COPY_PATH
|
|
440
440
|
? // The artifact copy (artifactsCopy.ts): the R2 binding and the Slack
|
|
441
441
|
// token are this Worker's; the bot only asks, with its copy bearer.
|
|
442
|
-
|
|
442
|
+
// `forwarded`, never `inbound`: `withTraceContext` rebuilt the request
|
|
443
|
+
// with `new Request(inbound, …)`, which takes the body stream with it —
|
|
444
|
+
// `inbound.text()` is empty afterwards and the route read "not JSON" live.
|
|
445
|
+
await handleArtifactsCopy(forwarded, {
|
|
443
446
|
bucket: env.ARTIFACTS,
|
|
444
447
|
bucketName: env.ARTIFACTS_BUCKET_NAME,
|
|
445
448
|
copyToken: env.ARTIFACTS_COPY_TOKEN,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchboard",
|
|
3
|
-
"version": "1.216.
|
|
3
|
+
"version": "1.216.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "switchboard",
|
|
9
|
-
"version": "1.216.
|
|
9
|
+
"version": "1.216.2",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"workspaces": [
|
|
12
12
|
"web",
|
|
@@ -19000,7 +19000,7 @@
|
|
|
19000
19000
|
},
|
|
19001
19001
|
"packages/switchboard": {
|
|
19002
19002
|
"name": "@coreplane/switchboard",
|
|
19003
|
-
"version": "1.216.
|
|
19003
|
+
"version": "1.216.2",
|
|
19004
19004
|
"license": "Apache-2.0",
|
|
19005
19005
|
"dependencies": {
|
|
19006
19006
|
"@anthropic-ai/sdk": "^0.124.0",
|
package/dist/assets/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "switchboard",
|
|
3
|
-
"version": "1.216.
|
|
3
|
+
"version": "1.216.2",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
|
|
6
6
|
"license": "Apache-2.0",
|
package/dist/assets/source.json
CHANGED
|
@@ -88,6 +88,19 @@ export interface LiveRunMeta {
|
|
|
88
88
|
* attachments when they fit — so a reclaim of an `attaching` row can
|
|
89
89
|
* dispatch it again under the same run id and card. */
|
|
90
90
|
request?: Record<string, unknown>;
|
|
91
|
+
/** The router's decision when it chose the run's preset (routing-and-config
|
|
92
|
+
* item 21) — the same fields the record's `route` event carries. On the row
|
|
93
|
+
* so a resume repaints the card as it was (` · routed: <reason>`, the
|
|
94
|
+
* parts, the override footer on the close) and a reclaim closing the run
|
|
95
|
+
* knows it was routed without reading the events. Absent for a preset a
|
|
96
|
+
* person, a scope or the default chose. */
|
|
97
|
+
route?: {
|
|
98
|
+
preset: string;
|
|
99
|
+
reason: string;
|
|
100
|
+
model: string;
|
|
101
|
+
parts?: { preset: string; text: string }[];
|
|
102
|
+
collapsed?: { presets: string[] };
|
|
103
|
+
};
|
|
91
104
|
}
|
|
92
105
|
|
|
93
106
|
/** Dispatcher-local run state a resume must restore (the `submit_*` callbacks,
|
package/dist/cli.js
CHANGED
|
@@ -9290,6 +9290,7 @@ var init_resident = __esm({
|
|
|
9290
9290
|
ref: data.ref,
|
|
9291
9291
|
sha: data.sha,
|
|
9292
9292
|
...typeof data.workspace === "string" && data.workspace ? { workspace: data.workspace } : {},
|
|
9293
|
+
...typeof data.user === "string" && data.user ? { user: data.user } : {},
|
|
9293
9294
|
...trace.length > 0 ? { trace } : {},
|
|
9294
9295
|
...typeof data.attachMs === "number" && Number.isFinite(data.attachMs) ? { attachMs: data.attachMs } : {}
|
|
9295
9296
|
};
|
|
@@ -24312,6 +24313,73 @@ var init_resolve = __esm({
|
|
|
24312
24313
|
}
|
|
24313
24314
|
});
|
|
24314
24315
|
|
|
24316
|
+
// ../../src/core/statusCardFrame.ts
|
|
24317
|
+
function createCardShell(opts) {
|
|
24318
|
+
let label = opts.label;
|
|
24319
|
+
let link = opts.link;
|
|
24320
|
+
let frame = 0;
|
|
24321
|
+
let finishedAt;
|
|
24322
|
+
let setupLabel;
|
|
24323
|
+
const lead = opts.lead ?? [];
|
|
24324
|
+
const elapsed2 = () => formatDuration((finishedAt ?? opts.now()) - opts.startedAt, "clock");
|
|
24325
|
+
const headline = (icon) => `${icon} ${label} \xB7 ${elapsed2()}`;
|
|
24326
|
+
const closeDetail = (close, own) => [close.shape, close.queued, own, opts.footer].filter(Boolean).join("\n") || void 0;
|
|
24327
|
+
return {
|
|
24328
|
+
get label() {
|
|
24329
|
+
return label;
|
|
24330
|
+
},
|
|
24331
|
+
setLabel(next) {
|
|
24332
|
+
label = next;
|
|
24333
|
+
},
|
|
24334
|
+
setLink(next) {
|
|
24335
|
+
link = next;
|
|
24336
|
+
},
|
|
24337
|
+
freeze(at) {
|
|
24338
|
+
finishedAt = at;
|
|
24339
|
+
},
|
|
24340
|
+
setSetupLabel(next) {
|
|
24341
|
+
setupLabel = next;
|
|
24342
|
+
},
|
|
24343
|
+
ack() {
|
|
24344
|
+
const detail = lead.join("\n");
|
|
24345
|
+
return { title: `\u{1F440} ${label} \xB7 preparing workspace\u2026`, ...detail ? { detail } : {} };
|
|
24346
|
+
},
|
|
24347
|
+
live(parts = {}) {
|
|
24348
|
+
const glyph = SPINNER_GLYPHS[frame++ % SPINNER_GLYPHS.length];
|
|
24349
|
+
const detail = [...lead, ...parts.detail ?? []].filter(Boolean).join("\n");
|
|
24350
|
+
return {
|
|
24351
|
+
title: headline(glyph) + (setupLabel ? ` \u2014 ${setupLabel}` : "") + (parts.suffix ?? "") + (parts.notice ? ` \xB7 ${parts.notice}` : ""),
|
|
24352
|
+
detail: detail || void 0,
|
|
24353
|
+
link
|
|
24354
|
+
};
|
|
24355
|
+
},
|
|
24356
|
+
close(close) {
|
|
24357
|
+
const detail = closeDetail(close, close.kind === "done" ? close.detail : void 0);
|
|
24358
|
+
switch (close.kind) {
|
|
24359
|
+
case "done":
|
|
24360
|
+
return { title: headline(close.icon), detail, link };
|
|
24361
|
+
case "not_started":
|
|
24362
|
+
return { title: `${close.icon} ${label} \xB7 not started (${close.reason}) \xB7 ${elapsed2()}`, detail };
|
|
24363
|
+
case "refused":
|
|
24364
|
+
return { title: `${close.icon} ${label} \xB7 ${close.reason} \xB7 ${elapsed2()}`, detail };
|
|
24365
|
+
case "setup_failed":
|
|
24366
|
+
return { title: `\u274C setup failed \xB7 ${close.reason} \xB7 ${elapsed2()}`, detail };
|
|
24367
|
+
}
|
|
24368
|
+
}
|
|
24369
|
+
};
|
|
24370
|
+
}
|
|
24371
|
+
var SPINNER_GLYPHS, LIVE_CARD_PREFIXES, ROUTED_LABEL_PREFIX, ROUTED_CARD_FOOTER;
|
|
24372
|
+
var init_statusCardFrame = __esm({
|
|
24373
|
+
"../../src/core/statusCardFrame.ts"() {
|
|
24374
|
+
"use strict";
|
|
24375
|
+
init_formatDuration();
|
|
24376
|
+
SPINNER_GLYPHS = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
|
|
24377
|
+
LIVE_CARD_PREFIXES = [...SPINNER_GLYPHS, "\u{1F440}"];
|
|
24378
|
+
ROUTED_LABEL_PREFIX = "routed:";
|
|
24379
|
+
ROUTED_CARD_FOOTER = "reply agent:<preset> to run it another way";
|
|
24380
|
+
}
|
|
24381
|
+
});
|
|
24382
|
+
|
|
24315
24383
|
// ../../src/core/dispatch/awaitChildren.ts
|
|
24316
24384
|
function decideWait(inputs) {
|
|
24317
24385
|
const { children, now, budgetEndsAt, timeoutAt, stop, followUpPending } = inputs;
|
|
@@ -24849,9 +24917,24 @@ function providerRouteModel(provider, model, opts = {}) {
|
|
|
24849
24917
|
return result.content.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
24850
24918
|
};
|
|
24851
24919
|
}
|
|
24920
|
+
function resolveRouted(deps, msg, directives, sticky, preset) {
|
|
24921
|
+
return deps.config.resolve({
|
|
24922
|
+
channelId: msg.channelId,
|
|
24923
|
+
userId: msg.userId,
|
|
24924
|
+
request: {
|
|
24925
|
+
agent: preset,
|
|
24926
|
+
model: directives.model ?? sticky.model,
|
|
24927
|
+
effort: directives.effort ?? sticky.effort
|
|
24928
|
+
}
|
|
24929
|
+
});
|
|
24930
|
+
}
|
|
24852
24931
|
async function routeRequest(deps, ctx) {
|
|
24853
|
-
const { msg, directives, sticky, agentSource, threadLive, root } = ctx;
|
|
24932
|
+
const { msg, directives, sticky, agentSource, threadLive, root, carried } = ctx;
|
|
24854
24933
|
const cfg = deps.config.config;
|
|
24934
|
+
if (carried) {
|
|
24935
|
+
console.log(`[route] ${msg.threadKey} routed to ${carried.preset} as before the restart: ${carried.reason}`);
|
|
24936
|
+
return { kind: "routed", resolved: resolveRouted(deps, msg, directives, sticky, carried.preset), route: carried };
|
|
24937
|
+
}
|
|
24855
24938
|
if (!routingOn(cfg) || agentSource !== "default" || threadLive) return { kind: "unrouted" };
|
|
24856
24939
|
const modelRef2 = cfg.routing?.model ?? cfg.defaults.models["general"];
|
|
24857
24940
|
if (!modelRef2) {
|
|
@@ -24892,15 +24975,7 @@ async function routeRequest(deps, ctx) {
|
|
|
24892
24975
|
console.log(`[route] ${msg.threadKey} not routed (${decision.reason}) \u2014 running ${cfg.defaults.agent}`);
|
|
24893
24976
|
return decision.compoundRejected ? { kind: "unrouted", rejected: { preset: cfg.defaults.agent, reason: decision.reason, model: modelRef2 } } : { kind: "unrouted" };
|
|
24894
24977
|
}
|
|
24895
|
-
const resolved = deps.
|
|
24896
|
-
channelId: msg.channelId,
|
|
24897
|
-
userId: msg.userId,
|
|
24898
|
-
request: {
|
|
24899
|
-
agent: decision.preset,
|
|
24900
|
-
model: directives.model ?? sticky.model,
|
|
24901
|
-
effort: directives.effort ?? sticky.effort
|
|
24902
|
-
}
|
|
24903
|
-
});
|
|
24978
|
+
const resolved = resolveRouted(deps, msg, directives, sticky, decision.preset);
|
|
24904
24979
|
const { parts, collapsed } = decision;
|
|
24905
24980
|
console.log(
|
|
24906
24981
|
`[route] ${msg.threadKey} routed to ${decision.preset} on ${modelRef2}${parts ? ` (${parts.length} parts)` : ""}${collapsed ? ` (compound collapsed: ${collapsed.presets.join("+")})` : ""}: ${decision.reason}`
|
|
@@ -24918,7 +24993,7 @@ async function routeRequest(deps, ctx) {
|
|
|
24918
24993
|
};
|
|
24919
24994
|
}
|
|
24920
24995
|
function routedLabel(reason, collapsed) {
|
|
24921
|
-
return
|
|
24996
|
+
return `${ROUTED_LABEL_PREFIX} ${reason}${collapsed ? ` (compound collapsed: ${collapsed.presets.join("+")})` : ""}`;
|
|
24922
24997
|
}
|
|
24923
24998
|
function routedPartLines(parts) {
|
|
24924
24999
|
return parts.map((p) => {
|
|
@@ -24934,7 +25009,7 @@ function compoundBrief(text, parts) {
|
|
|
24934
25009
|
...parts.map((p, i) => `${i + 1}. \`${p.preset}\`: ${p.text}`)
|
|
24935
25010
|
].join("\n");
|
|
24936
25011
|
}
|
|
24937
|
-
var ROUTE_TEXT_CAP, ROUTE_REASON_CAP, ROUTE_MIN_OUTPUT_TOKENS, ROUTE_TOOL_NAME, ROUTE_TIMEOUT_MS, ROUTE_PART_TEXT_CAP, ROUTE_PART_LINE_CAP, COMPOUND_BRIEF_HEADING, identityOf
|
|
25012
|
+
var ROUTE_TEXT_CAP, ROUTE_REASON_CAP, ROUTE_MIN_OUTPUT_TOKENS, ROUTE_TOOL_NAME, ROUTE_TIMEOUT_MS, ROUTE_PART_TEXT_CAP, ROUTE_PART_LINE_CAP, COMPOUND_BRIEF_HEADING, identityOf;
|
|
24938
25013
|
var init_route = __esm({
|
|
24939
25014
|
"../../src/core/dispatch/route.ts"() {
|
|
24940
25015
|
"use strict";
|
|
@@ -24942,7 +25017,9 @@ var init_route = __esm({
|
|
|
24942
25017
|
init_config2();
|
|
24943
25018
|
init_types3();
|
|
24944
25019
|
init_redact();
|
|
25020
|
+
init_statusCardFrame();
|
|
24945
25021
|
init_spawn();
|
|
25022
|
+
init_statusCardFrame();
|
|
24946
25023
|
ROUTE_TEXT_CAP = 2e3;
|
|
24947
25024
|
ROUTE_REASON_CAP = 120;
|
|
24948
25025
|
ROUTE_MIN_OUTPUT_TOKENS = 200;
|
|
@@ -24952,7 +25029,6 @@ var init_route = __esm({
|
|
|
24952
25029
|
ROUTE_PART_LINE_CAP = 100;
|
|
24953
25030
|
COMPOUND_BRIEF_HEADING = "Routed as a compound request";
|
|
24954
25031
|
identityOf = (preset) => AGENTS[preset]?.identity;
|
|
24955
|
-
ROUTED_CARD_FOOTER = "reply agent:<preset> to run it another way";
|
|
24956
25032
|
}
|
|
24957
25033
|
});
|
|
24958
25034
|
|
|
@@ -28923,71 +28999,6 @@ var init_customInstructions = __esm({
|
|
|
28923
28999
|
}
|
|
28924
29000
|
});
|
|
28925
29001
|
|
|
28926
|
-
// ../../src/core/statusCardFrame.ts
|
|
28927
|
-
function createCardShell(opts) {
|
|
28928
|
-
let label = opts.label;
|
|
28929
|
-
let link = opts.link;
|
|
28930
|
-
let frame = 0;
|
|
28931
|
-
let finishedAt;
|
|
28932
|
-
let setupLabel;
|
|
28933
|
-
const lead = opts.lead ?? [];
|
|
28934
|
-
const elapsed2 = () => formatDuration((finishedAt ?? opts.now()) - opts.startedAt, "clock");
|
|
28935
|
-
const headline = (icon) => `${icon} ${label} \xB7 ${elapsed2()}`;
|
|
28936
|
-
const closeDetail = (close, own) => [close.shape, close.queued, own, opts.footer].filter(Boolean).join("\n") || void 0;
|
|
28937
|
-
return {
|
|
28938
|
-
get label() {
|
|
28939
|
-
return label;
|
|
28940
|
-
},
|
|
28941
|
-
setLabel(next) {
|
|
28942
|
-
label = next;
|
|
28943
|
-
},
|
|
28944
|
-
setLink(next) {
|
|
28945
|
-
link = next;
|
|
28946
|
-
},
|
|
28947
|
-
freeze(at) {
|
|
28948
|
-
finishedAt = at;
|
|
28949
|
-
},
|
|
28950
|
-
setSetupLabel(next) {
|
|
28951
|
-
setupLabel = next;
|
|
28952
|
-
},
|
|
28953
|
-
ack() {
|
|
28954
|
-
const detail = lead.join("\n");
|
|
28955
|
-
return { title: `\u{1F440} ${label} \xB7 preparing workspace\u2026`, ...detail ? { detail } : {} };
|
|
28956
|
-
},
|
|
28957
|
-
live(parts = {}) {
|
|
28958
|
-
const glyph = SPINNER_GLYPHS[frame++ % SPINNER_GLYPHS.length];
|
|
28959
|
-
const detail = [...lead, ...parts.detail ?? []].filter(Boolean).join("\n");
|
|
28960
|
-
return {
|
|
28961
|
-
title: headline(glyph) + (setupLabel ? ` \u2014 ${setupLabel}` : "") + (parts.suffix ?? "") + (parts.notice ? ` \xB7 ${parts.notice}` : ""),
|
|
28962
|
-
detail: detail || void 0,
|
|
28963
|
-
link
|
|
28964
|
-
};
|
|
28965
|
-
},
|
|
28966
|
-
close(close) {
|
|
28967
|
-
const detail = closeDetail(close, close.kind === "done" ? close.detail : void 0);
|
|
28968
|
-
switch (close.kind) {
|
|
28969
|
-
case "done":
|
|
28970
|
-
return { title: headline(close.icon), detail, link };
|
|
28971
|
-
case "not_started":
|
|
28972
|
-
return { title: `${close.icon} ${label} \xB7 not started (${close.reason}) \xB7 ${elapsed2()}`, detail };
|
|
28973
|
-
case "refused":
|
|
28974
|
-
return { title: `${close.icon} ${label} \xB7 ${close.reason} \xB7 ${elapsed2()}`, detail };
|
|
28975
|
-
case "setup_failed":
|
|
28976
|
-
return { title: `\u274C setup failed \xB7 ${close.reason} \xB7 ${elapsed2()}`, detail };
|
|
28977
|
-
}
|
|
28978
|
-
}
|
|
28979
|
-
};
|
|
28980
|
-
}
|
|
28981
|
-
var SPINNER_GLYPHS, LIVE_CARD_PREFIXES;
|
|
28982
|
-
var init_statusCardFrame = __esm({
|
|
28983
|
-
"../../src/core/statusCardFrame.ts"() {
|
|
28984
|
-
"use strict";
|
|
28985
|
-
init_formatDuration();
|
|
28986
|
-
SPINNER_GLYPHS = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
|
|
28987
|
-
LIVE_CARD_PREFIXES = [...SPINNER_GLYPHS, "\u{1F440}"];
|
|
28988
|
-
}
|
|
28989
|
-
});
|
|
28990
|
-
|
|
28991
29002
|
// ../../src/core/statusCoalescer.ts
|
|
28992
29003
|
function coalesceStatus(inner, minIntervalMs, now = Date.now, schedule = setTimeout) {
|
|
28993
29004
|
let lastSentAt = -Infinity;
|
|
@@ -29210,7 +29221,8 @@ async function reserveRun(deps, ctx) {
|
|
|
29210
29221
|
root,
|
|
29211
29222
|
parentRunId,
|
|
29212
29223
|
coordinator,
|
|
29213
|
-
seed
|
|
29224
|
+
seed,
|
|
29225
|
+
route: route3
|
|
29214
29226
|
} = ctx;
|
|
29215
29227
|
if (!resume && !restart) {
|
|
29216
29228
|
const requestRow = durableInboxMessage(msg, msg.text, receivedAt);
|
|
@@ -29239,6 +29251,7 @@ async function reserveRun(deps, ctx) {
|
|
|
29239
29251
|
...parentRunId !== void 0 ? { parentRunId } : {},
|
|
29240
29252
|
...coordinatorFields(coordinator),
|
|
29241
29253
|
...seed !== void 0 ? { seed } : {},
|
|
29254
|
+
...route3 !== void 0 ? { route: route3 } : {},
|
|
29242
29255
|
request: requestRow
|
|
29243
29256
|
},
|
|
29244
29257
|
card: card.handle ?? null,
|
|
@@ -29469,7 +29482,8 @@ async function claimRun(deps, ctx) {
|
|
|
29469
29482
|
root,
|
|
29470
29483
|
parentRunId,
|
|
29471
29484
|
coordinator,
|
|
29472
|
-
seed
|
|
29485
|
+
seed,
|
|
29486
|
+
route: route3
|
|
29473
29487
|
} = ctx;
|
|
29474
29488
|
const { resident, binding } = selection;
|
|
29475
29489
|
let ledgerRun = ctx.ledgerRun;
|
|
@@ -29500,6 +29514,7 @@ async function claimRun(deps, ctx) {
|
|
|
29500
29514
|
...parentRunId !== void 0 ? { parentRunId } : {},
|
|
29501
29515
|
...coordinatorFields(coordinator),
|
|
29502
29516
|
...seed !== void 0 ? { seed } : {},
|
|
29517
|
+
...route3 !== void 0 ? { route: route3 } : {},
|
|
29503
29518
|
selection: resident === true ? "resident" : "sandbox",
|
|
29504
29519
|
...binding?.workspace !== void 0 ? { workspace: binding.workspace } : {},
|
|
29505
29520
|
...requestRow !== void 0 ? { request: requestRow } : {}
|
|
@@ -30367,7 +30382,8 @@ function piBuiltinToolsFor(identity2) {
|
|
|
30367
30382
|
function piThinkingLevel(effort2) {
|
|
30368
30383
|
return effort2;
|
|
30369
30384
|
}
|
|
30370
|
-
function piRunPaths(runId3,
|
|
30385
|
+
function piRunPaths(runId3, user) {
|
|
30386
|
+
const root = user ? `/tmp/switchboard-pi-${user}` : "/tmp/switchboard-pi";
|
|
30371
30387
|
const dir = `${root}/${runId3}`;
|
|
30372
30388
|
return {
|
|
30373
30389
|
dir,
|
|
@@ -30615,7 +30631,7 @@ async function runPiHarness(deps, run2) {
|
|
|
30615
30631
|
emit({ type: "run_note", kind, summary, ...mode ? { mode } : {} });
|
|
30616
30632
|
};
|
|
30617
30633
|
const bridge = new PiBridge({ emit, onProgress: run2.onProgress, agentSpan, clock: clock3 });
|
|
30618
|
-
const paths = piRunPaths(run2.runId,
|
|
30634
|
+
const paths = piRunPaths(run2.runId, run2.user);
|
|
30619
30635
|
const remainingMs = run2.resume?.remainingMs ?? run2.agent.maxMinutes * 6e4;
|
|
30620
30636
|
const deadline = now() + remainingMs;
|
|
30621
30637
|
const warnAt = deadline - Math.min(3 * 6e4, run2.agent.maxMinutes * 15e3);
|
|
@@ -31635,6 +31651,10 @@ async function runLoop2(deps, ctx) {
|
|
|
31635
31651
|
...ownBranch !== void 0 ? { branch: ownBranch } : {},
|
|
31636
31652
|
protectedBranches
|
|
31637
31653
|
},
|
|
31654
|
+
// The resident runs this thread's commands as its pool user: pi's
|
|
31655
|
+
// files go under that user's own root, never one another thread's
|
|
31656
|
+
// user created (harness-pi.md item 4).
|
|
31657
|
+
...binding?.user ? { user: binding.user } : {},
|
|
31638
31658
|
...round2.selection.backend ? { backend: round2.selection.backend } : {},
|
|
31639
31659
|
span: root,
|
|
31640
31660
|
control: run2.control,
|
|
@@ -33524,13 +33544,24 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
33524
33544
|
let { resolved, agentSource } = settled;
|
|
33525
33545
|
let route3;
|
|
33526
33546
|
const threadLive = admission.get(msg.threadKey) !== void 0 || !resume && !restart && deps.threadsElsewhere.get(msg.threadKey) !== void 0;
|
|
33527
|
-
const routing = await routeRequest(deps, {
|
|
33547
|
+
const routing = await routeRequest(deps, {
|
|
33548
|
+
msg,
|
|
33549
|
+
directives,
|
|
33550
|
+
sticky,
|
|
33551
|
+
agentSource,
|
|
33552
|
+
threadLive,
|
|
33553
|
+
root,
|
|
33554
|
+
// A restart is the same run under the same card: the row's decision
|
|
33555
|
+
// (run-history item 35) is the route, re-resolved, never re-asked.
|
|
33556
|
+
...restart?.row.meta.route ? { carried: restart.row.meta.route } : {}
|
|
33557
|
+
});
|
|
33528
33558
|
if (routing.kind === "routed") {
|
|
33529
33559
|
resolved = routing.resolved;
|
|
33530
33560
|
route3 = routing.route;
|
|
33531
33561
|
agentSource = "route";
|
|
33532
33562
|
}
|
|
33533
33563
|
const routeEvent = routing.kind === "routed" ? routing.route : routing.rejected;
|
|
33564
|
+
if (resume?.row.meta.route) route3 = resume.row.meta.route;
|
|
33534
33565
|
if ((await authorizeAgent(deps, { msg, io, refuse: refuse3, agentName: resolved.agentName })).kind === "refused")
|
|
33535
33566
|
return ended;
|
|
33536
33567
|
const agent = resolved.agentName === "ship" ? shipPresetFor(deps.config.config.ship) : getAgent(resolved.agentName);
|
|
@@ -33714,6 +33745,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
33714
33745
|
restart,
|
|
33715
33746
|
card,
|
|
33716
33747
|
hooks: reservationHooks,
|
|
33748
|
+
route: route3,
|
|
33717
33749
|
admitted,
|
|
33718
33750
|
root,
|
|
33719
33751
|
parentRunId,
|
|
@@ -33849,6 +33881,7 @@ async function dispatch(deps, msg, io, opts = {}) {
|
|
|
33849
33881
|
resume,
|
|
33850
33882
|
ledgerRun,
|
|
33851
33883
|
card,
|
|
33884
|
+
route: route3,
|
|
33852
33885
|
clock: clock3,
|
|
33853
33886
|
root,
|
|
33854
33887
|
parentRunId,
|
|
@@ -35969,9 +36002,12 @@ function findOrphanedCards(input) {
|
|
|
35969
36002
|
}
|
|
35970
36003
|
function interruptedCardFrame(cardText) {
|
|
35971
36004
|
const label = cardText.replace(LIVE_GLYPH_PREFIX, "").replace(SHUTDOWN_NOTICE_SUFFIX, "").replace(ACTIVITY_SUFFIX, "").replaceAll("<", "<").replaceAll(">", ">").replaceAll("&", "&").trim();
|
|
36005
|
+
const detail = "The bot restarted (a deploy) while this run was in flight, so the run was lost and this card stopped updating. Re-send your request to run it again.";
|
|
36006
|
+
const routed = label.includes(` \xB7 ${ROUTED_LABEL_PREFIX}`);
|
|
35972
36007
|
return {
|
|
35973
36008
|
title: `\u274C interrupted \xB7 ${label}`,
|
|
35974
|
-
detail:
|
|
36009
|
+
detail: routed ? `${detail}
|
|
36010
|
+
${ROUTED_CARD_FOOTER}` : detail
|
|
35975
36011
|
};
|
|
35976
36012
|
}
|
|
35977
36013
|
async function catchUpMissedMentions(opts) {
|
|
@@ -36282,9 +36318,14 @@ async function closeReclaimedCards(client, closures, warn = console.warn) {
|
|
|
36282
36318
|
let closed = 0;
|
|
36283
36319
|
for (const c of closures) {
|
|
36284
36320
|
if (!c.card || !(c.status in glyph)) continue;
|
|
36321
|
+
const detail = c.status === "interrupted" ? c.note ?? "The bot restarted while this run was in flight and it could not be resumed." : "The bot restarted after this run replied; its record is complete.";
|
|
36285
36322
|
const frame = {
|
|
36286
36323
|
title: `${glyph[c.status]} ${c.agent ?? "run"} \xB7 ${c.status.replace("_", " ")}`,
|
|
36287
|
-
|
|
36324
|
+
// A routed run's close ends with the override footer wherever it is
|
|
36325
|
+
// written: this is the close a person most needs it on — the run was
|
|
36326
|
+
// cut by a deploy, and `agent:<preset>` in a reply is how to run it again.
|
|
36327
|
+
detail: c.routed ? `${detail}
|
|
36328
|
+
${ROUTED_CARD_FOOTER}` : detail
|
|
36288
36329
|
};
|
|
36289
36330
|
try {
|
|
36290
36331
|
await client.chat.update({ channel: c.card.channel, ts: c.card.ts, ...render2(frame) });
|
|
@@ -36322,6 +36363,7 @@ var RENDER_DETAIL_RAW_MAX, liveCards, liveCardKey, foreignLiveCards, foreignLive
|
|
|
36322
36363
|
var init_statusCard = __esm({
|
|
36323
36364
|
"../../src/channels/slack/statusCard.ts"() {
|
|
36324
36365
|
"use strict";
|
|
36366
|
+
init_statusCardFrame();
|
|
36325
36367
|
init_slackEscape();
|
|
36326
36368
|
RENDER_DETAIL_RAW_MAX = 900;
|
|
36327
36369
|
liveCards = /* @__PURE__ */ new Set();
|
|
@@ -39712,6 +39754,9 @@ function prUrlOf(events) {
|
|
|
39712
39754
|
for (const e of events) if (e.type === "pr_opened" && typeof e.url === "string") url = e.url;
|
|
39713
39755
|
return url;
|
|
39714
39756
|
}
|
|
39757
|
+
function routedOf(meta, events) {
|
|
39758
|
+
return meta.route !== void 0 || events.some((e) => e.type === "run_meta" && e.agentSource === "route");
|
|
39759
|
+
}
|
|
39715
39760
|
async function reclaimRuns(opts) {
|
|
39716
39761
|
const { ledger, gen } = opts;
|
|
39717
39762
|
const now = opts.now ?? Date.now;
|
|
@@ -39786,6 +39831,7 @@ async function reclaimRuns(opts) {
|
|
|
39786
39831
|
events: events.length,
|
|
39787
39832
|
...row.meta.agent !== void 0 ? { agent: row.meta.agent } : {},
|
|
39788
39833
|
...prUrl2 !== void 0 ? { prUrl: prUrl2 } : {},
|
|
39834
|
+
...routedOf(row.meta, events) ? { routed: true } : {},
|
|
39789
39835
|
...status3 === "interrupted" ? { note: closureNote(row.meta.agent, prUrl2) } : {}
|
|
39790
39836
|
});
|
|
39791
39837
|
log(
|
|
@@ -42787,7 +42833,8 @@ async function runBot() {
|
|
|
42787
42833
|
status: c.status,
|
|
42788
42834
|
agent: c.agent,
|
|
42789
42835
|
card: c.card,
|
|
42790
|
-
...c.note ? { note: c.note } : {}
|
|
42836
|
+
...c.note ? { note: c.note } : {},
|
|
42837
|
+
...c.routed ? { routed: true } : {}
|
|
42791
42838
|
})),
|
|
42792
42839
|
(w) => console.warn(w)
|
|
42793
42840
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coreplane/switchboard",
|
|
3
|
-
"version": "1.216.
|
|
3
|
+
"version": "1.216.2",
|
|
4
4
|
"description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://openswitchboard.dev",
|