switchroom 0.20.3 → 0.20.4
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/cli/switchroom.js +9977 -957
- package/dist/host-control/main.js +1 -1
- package/package.json +3 -3
- package/telegram-plugin/dist/gateway/gateway.js +429 -98
- package/telegram-plugin/edit-flood-fuse.ts +332 -14
- package/telegram-plugin/gateway/feed-open-gate.ts +28 -8
- package/telegram-plugin/gateway/feed-reopen-gate.ts +88 -6
- package/telegram-plugin/gateway/gateway.ts +128 -104
- package/telegram-plugin/gateway/narrative-lane.ts +4 -0
- package/telegram-plugin/gateway/progress-fallback-cap.ts +195 -0
- package/telegram-plugin/gateway/stream-render.ts +67 -12
- package/telegram-plugin/gateway/subagent-handback-inbound-builder.ts +13 -0
- package/telegram-plugin/gateway/subagent-origin-surface.ts +181 -0
- package/telegram-plugin/gateway/subagent-progress-inbound-builder.ts +7 -0
- package/telegram-plugin/registry/subagents-schema.ts +61 -0
- package/telegram-plugin/registry/turns-schema.ts +26 -0
- package/telegram-plugin/tests/edit-flood-fuse-cosmetic-fairness.test.ts +229 -0
- package/telegram-plugin/tests/feed-open-gate.test.ts +42 -0
- package/telegram-plugin/tests/feed-reopen-gate.test.ts +114 -0
- package/telegram-plugin/tests/progress-cap.test.ts +182 -0
- package/telegram-plugin/tests/progress-fallback-cap.test.ts +91 -0
- package/telegram-plugin/tests/progress-update.test.ts +108 -12
- package/telegram-plugin/tests/subagent-handback-inbound-builder.test.ts +46 -0
- package/telegram-plugin/tests/subagent-progress-inbound-builder.test.ts +26 -0
- package/telegram-plugin/tests/worker-origin-gap-dispatch.test.ts +304 -0
|
@@ -65060,6 +65060,9 @@ var EDIT_FLOOD_FUSE_DEFAULTS = {
|
|
|
65060
65060
|
perChatSendMaxPerWindow: 25,
|
|
65061
65061
|
cosmeticPerMessageMaxPerWindow: 4,
|
|
65062
65062
|
cosmeticPerChatMaxPerWindow: 6,
|
|
65063
|
+
cosmeticFloorPerWindow: 2,
|
|
65064
|
+
cosmeticFloorSlots: 2,
|
|
65065
|
+
throttleNoticeMs: 45000,
|
|
65063
65066
|
perChatTotalMaxPerWindow: 20,
|
|
65064
65067
|
perChatReplyReserve: 8,
|
|
65065
65068
|
perChatCriticalMinPerWindow: 3,
|
|
@@ -65094,6 +65097,11 @@ function editFloodFuseConfigFromEnv(env) {
|
|
|
65094
65097
|
};
|
|
65095
65098
|
assign("cosmeticPerMessageMaxPerWindow", envInt(env.SWITCHROOM_FEED_EDIT_MAX_PER_MSG_PER_MIN));
|
|
65096
65099
|
assign("cosmeticPerChatMaxPerWindow", envInt(env.SWITCHROOM_FEED_EDIT_MAX_PER_CHAT_PER_MIN));
|
|
65100
|
+
if (env.SWITCHROOM_FEED_FAIR_SHARE === "0")
|
|
65101
|
+
cfg.cosmeticFairShareEnabled = false;
|
|
65102
|
+
assign("cosmeticFloorPerWindow", envInt(env.SWITCHROOM_FEED_EDIT_FLOOR_PER_MSG_PER_MIN));
|
|
65103
|
+
assign("cosmeticFloorSlots", envInt(env.SWITCHROOM_FEED_EDIT_FLOOR_SLOTS));
|
|
65104
|
+
assign("throttleNoticeMs", envInt(env.SWITCHROOM_FEED_THROTTLE_NOTICE_MS));
|
|
65097
65105
|
assign("perChatTotalMaxPerWindow", envInt(env.SWITCHROOM_CHAT_TOTAL_MAX_PER_MIN));
|
|
65098
65106
|
assign("perChatReplyReserve", envInt(env.SWITCHROOM_CHAT_REPLY_RESERVE));
|
|
65099
65107
|
assign("perChatCriticalMinPerWindow", envInt(env.SWITCHROOM_CHAT_CRITICAL_MIN_PER_MIN));
|
|
@@ -65118,6 +65126,11 @@ function createEditFloodFuse(config = {}) {
|
|
|
65118
65126
|
const perChatSendMax = config.perChatSendMaxPerWindow ?? D.perChatSendMaxPerWindow;
|
|
65119
65127
|
const cosmeticPerMessageMax = Math.min(perMessageMax, config.cosmeticPerMessageMaxPerWindow ?? D.cosmeticPerMessageMaxPerWindow);
|
|
65120
65128
|
const cosmeticPerChatMax = Math.min(perChatEditMax, config.cosmeticPerChatMaxPerWindow ?? D.cosmeticPerChatMaxPerWindow);
|
|
65129
|
+
const cosmeticFairShareEnabled = config.cosmeticFairShareEnabled ?? true;
|
|
65130
|
+
const cosmeticFloorPerWindow = Math.min(cosmeticPerMessageMax, Math.max(0, config.cosmeticFloorPerWindow ?? D.cosmeticFloorPerWindow));
|
|
65131
|
+
const cosmeticFloorAggMax = Math.min(cosmeticPerChatMax, cosmeticFloorPerWindow * Math.max(0, config.cosmeticFloorSlots ?? D.cosmeticFloorSlots));
|
|
65132
|
+
const cosmeticRemainderMax = Math.max(0, cosmeticPerChatMax - cosmeticFloorAggMax);
|
|
65133
|
+
const throttleNoticeMs = Math.max(0, config.throttleNoticeMs ?? D.throttleNoticeMs);
|
|
65121
65134
|
const perChatTotalMax = config.perChatTotalMaxPerWindow ?? D.perChatTotalMaxPerWindow;
|
|
65122
65135
|
const perChatWindowMs = config.perChatWindowMs ?? D.perChatWindowMs;
|
|
65123
65136
|
const perChatReplyReserve = Math.min(Math.max(0, config.perChatReplyReserve ?? D.perChatReplyReserve), Math.max(0, perChatTotalMax - 1));
|
|
@@ -65142,7 +65155,8 @@ function createEditFloodFuse(config = {}) {
|
|
|
65142
65155
|
superseded: 0,
|
|
65143
65156
|
floodObserved: 0,
|
|
65144
65157
|
meteredByDefault: 0,
|
|
65145
|
-
chatless: 0
|
|
65158
|
+
chatless: 0,
|
|
65159
|
+
throttled: 0
|
|
65146
65160
|
};
|
|
65147
65161
|
let tightenLevel = 0;
|
|
65148
65162
|
let tightenedUntil = 0;
|
|
@@ -65189,6 +65203,12 @@ function createEditFloodFuse(config = {}) {
|
|
|
65189
65203
|
return eff;
|
|
65190
65204
|
return Math.max(eff, Math.min(base, perChatCriticalMin));
|
|
65191
65205
|
}
|
|
65206
|
+
function cosmeticMessageCeiling(now) {
|
|
65207
|
+
const eff = ceiling(cosmeticPerMessageMax, now);
|
|
65208
|
+
if (!cosmeticFairShareEnabled)
|
|
65209
|
+
return eff;
|
|
65210
|
+
return Math.max(eff, Math.min(cosmeticPerMessageMax, cosmeticFloorPerWindow));
|
|
65211
|
+
}
|
|
65192
65212
|
function cosmeticTotalMax(now) {
|
|
65193
65213
|
const eff = ceiling(perChatTotalMax, now);
|
|
65194
65214
|
if (replyReserveFraction <= 0)
|
|
@@ -65281,9 +65301,87 @@ function createEditFloodFuse(config = {}) {
|
|
|
65281
65301
|
if (i >= 0)
|
|
65282
65302
|
w.ts.splice(i, 1);
|
|
65283
65303
|
}
|
|
65304
|
+
function makeThrottleNotice(method, key, cls) {
|
|
65305
|
+
if (!cosmeticFairShareEnabled || cls !== "cosmetic" || throttleNoticeMs <= 0) {
|
|
65306
|
+
return { tick: () => {}, sleepCap: () => Number.POSITIVE_INFINITY };
|
|
65307
|
+
}
|
|
65308
|
+
let firstAt = Number.NaN;
|
|
65309
|
+
let fired = false;
|
|
65310
|
+
return {
|
|
65311
|
+
tick: (now) => {
|
|
65312
|
+
if (Number.isNaN(firstAt))
|
|
65313
|
+
firstAt = now;
|
|
65314
|
+
if (fired || now - firstAt < throttleNoticeMs)
|
|
65315
|
+
return;
|
|
65316
|
+
fired = true;
|
|
65317
|
+
counters.throttled++;
|
|
65318
|
+
onTrip?.({ method, key, action: "throttled", cls });
|
|
65319
|
+
},
|
|
65320
|
+
sleepCap: (now) => {
|
|
65321
|
+
if (fired || Number.isNaN(firstAt))
|
|
65322
|
+
return Number.POSITIVE_INFINITY;
|
|
65323
|
+
return Math.max(1, firstAt + throttleNoticeMs - now);
|
|
65324
|
+
}
|
|
65325
|
+
};
|
|
65326
|
+
}
|
|
65327
|
+
async function awaitCosmeticChatFair(chat, msg, method, cls, dropGuard, deadline, lateReleaseKey) {
|
|
65328
|
+
const fMsgKey = `cmf:${chat}:${msg}`;
|
|
65329
|
+
const fAggKey = `cfa:${chat}`;
|
|
65330
|
+
const remKey = `cer:${chat}`;
|
|
65331
|
+
const fw = win(fMsgKey);
|
|
65332
|
+
const aw = win(fAggKey);
|
|
65333
|
+
const rw = win(remKey);
|
|
65334
|
+
let counted = false;
|
|
65335
|
+
const throttle = makeThrottleNotice(method, remKey, cls);
|
|
65336
|
+
for (;; ) {
|
|
65337
|
+
const now = clock.now();
|
|
65338
|
+
const wFloor = Math.max(waitFor(fw, now, perChatWindowMs, cosmeticFloorPerWindow), waitFor(aw, now, perChatWindowMs, cosmeticFloorAggMax));
|
|
65339
|
+
const remCap = cosmeticRemainderMax <= 0 ? 0 : ceiling(cosmeticRemainderMax, now);
|
|
65340
|
+
const wRem = waitFor(rw, now, perChatWindowMs, remCap);
|
|
65341
|
+
if (wFloor === 0) {
|
|
65342
|
+
fw.ts.push(now);
|
|
65343
|
+
aw.ts.push(now);
|
|
65344
|
+
return [[fMsgKey, now], [fAggKey, now]];
|
|
65345
|
+
}
|
|
65346
|
+
if (remCap > 0 && wRem === 0) {
|
|
65347
|
+
rw.ts.push(now);
|
|
65348
|
+
return [[remKey, now]];
|
|
65349
|
+
}
|
|
65350
|
+
if (now >= deadline) {
|
|
65351
|
+
if (dropGuard()) {
|
|
65352
|
+
counters.dropped++;
|
|
65353
|
+
onTrip?.({ method, key: remKey, action: "dropped", cls });
|
|
65354
|
+
return null;
|
|
65355
|
+
}
|
|
65356
|
+
const lw = win(lateReleaseKey);
|
|
65357
|
+
prune(lw, now, perChatWindowMs);
|
|
65358
|
+
if (lw.ts.length >= ceiling(lateReleaseMax, now)) {
|
|
65359
|
+
counters.dropped++;
|
|
65360
|
+
onTrip?.({ method, key: remKey, action: "dropped", cls });
|
|
65361
|
+
return null;
|
|
65362
|
+
}
|
|
65363
|
+
lw.ts.push(now);
|
|
65364
|
+
if (cosmeticRemainderMax > 0) {
|
|
65365
|
+
rw.ts.push(now);
|
|
65366
|
+
return [[remKey, now]];
|
|
65367
|
+
}
|
|
65368
|
+
fw.ts.push(now);
|
|
65369
|
+
aw.ts.push(now);
|
|
65370
|
+
return [[fMsgKey, now], [fAggKey, now]];
|
|
65371
|
+
}
|
|
65372
|
+
if (!counted) {
|
|
65373
|
+
counters.deferred++;
|
|
65374
|
+
counted = true;
|
|
65375
|
+
onTrip?.({ method, key: remKey, action: "deferred", cls });
|
|
65376
|
+
}
|
|
65377
|
+
throttle.tick(now);
|
|
65378
|
+
await clock.sleep(Math.min(Math.min(wFloor, wRem), deadline - now, throttle.sleepCap(now)));
|
|
65379
|
+
}
|
|
65380
|
+
}
|
|
65284
65381
|
async function awaitRoom(key, windowMs, maxFor, method, mode, cls, dropGuard, deadline, lateReleaseKey) {
|
|
65285
65382
|
const w = win(key);
|
|
65286
65383
|
let counted = false;
|
|
65384
|
+
const throttle = makeThrottleNotice(method, key, cls);
|
|
65287
65385
|
for (;; ) {
|
|
65288
65386
|
const now = clock.now();
|
|
65289
65387
|
const wait = waitFor(w, now, windowMs, maxFor(now));
|
|
@@ -65315,6 +65413,8 @@ function createEditFloodFuse(config = {}) {
|
|
|
65315
65413
|
counted = true;
|
|
65316
65414
|
onTrip?.({ method, key, action: "deferred", cls });
|
|
65317
65415
|
}
|
|
65416
|
+
throttle.tick(now);
|
|
65417
|
+
const nap = Math.min(wait, deadline - now, throttle.sleepCap(now));
|
|
65318
65418
|
let killed = false;
|
|
65319
65419
|
if (mode === "supersede") {
|
|
65320
65420
|
w.waiter?.kill();
|
|
@@ -65324,7 +65424,7 @@ function createEditFloodFuse(config = {}) {
|
|
|
65324
65424
|
resolve6();
|
|
65325
65425
|
} };
|
|
65326
65426
|
});
|
|
65327
|
-
await Promise.race([clock.sleep(
|
|
65427
|
+
await Promise.race([clock.sleep(nap), superseded]);
|
|
65328
65428
|
if (killed) {
|
|
65329
65429
|
counters.superseded++;
|
|
65330
65430
|
onTrip?.({ method, key, action: "superseded", cls });
|
|
@@ -65332,7 +65432,7 @@ function createEditFloodFuse(config = {}) {
|
|
|
65332
65432
|
}
|
|
65333
65433
|
w.waiter = null;
|
|
65334
65434
|
} else {
|
|
65335
|
-
await clock.sleep(
|
|
65435
|
+
await clock.sleep(nap);
|
|
65336
65436
|
}
|
|
65337
65437
|
}
|
|
65338
65438
|
}
|
|
@@ -65368,7 +65468,7 @@ function createEditFloodFuse(config = {}) {
|
|
|
65368
65468
|
const dropGuard = () => mw.inflight > 1;
|
|
65369
65469
|
const lateKey = cls === "cosmetic" ? `lr:${chat}` : undefined;
|
|
65370
65470
|
try {
|
|
65371
|
-
const msgSlot = await awaitRoom(msgKey, perMessageWindowMs, cls === "cosmetic" ? (t) =>
|
|
65471
|
+
const msgSlot = await awaitRoom(msgKey, perMessageWindowMs, cls === "cosmetic" ? (t) => cosmeticMessageCeiling(t) : (t) => classCeiling(perMessageMax, cls, t), method, "supersede", cls, dropGuard, deadline, lateKey);
|
|
65372
65472
|
if (msgSlot === null)
|
|
65373
65473
|
return DROPPED_RESULT;
|
|
65374
65474
|
const reserved = [[msgKey, msgSlot]];
|
|
@@ -65376,13 +65476,22 @@ function createEditFloodFuse(config = {}) {
|
|
|
65376
65476
|
for (const [k, at] of reserved)
|
|
65377
65477
|
unreserve(k, at);
|
|
65378
65478
|
};
|
|
65379
|
-
|
|
65380
|
-
|
|
65381
|
-
|
|
65382
|
-
|
|
65383
|
-
|
|
65479
|
+
if (cls === "cosmetic" && cosmeticFairShareEnabled) {
|
|
65480
|
+
const fairSlots = await awaitCosmeticChatFair(chat, msg, method, cls, dropGuard, deadline, lateKey);
|
|
65481
|
+
if (fairSlots === null) {
|
|
65482
|
+
giveBack();
|
|
65483
|
+
return DROPPED_RESULT;
|
|
65484
|
+
}
|
|
65485
|
+
reserved.push(...fairSlots);
|
|
65486
|
+
} else {
|
|
65487
|
+
const chatKey2 = `ce:${chat}`;
|
|
65488
|
+
const chatSlot = await awaitRoom(chatKey2, perChatWindowMs, cls === "cosmetic" ? (t) => ceiling(cosmeticPerChatMax, t) : (t) => classCeiling(perChatEditMax, cls, t), method, "drop", cls, dropGuard, deadline, lateKey);
|
|
65489
|
+
if (chatSlot === null) {
|
|
65490
|
+
giveBack();
|
|
65491
|
+
return DROPPED_RESULT;
|
|
65492
|
+
}
|
|
65493
|
+
reserved.push([chatKey2, chatSlot]);
|
|
65384
65494
|
}
|
|
65385
|
-
reserved.push([chatKey2, chatSlot]);
|
|
65386
65495
|
const totalSlot = await awaitRoom(totalKey, perChatWindowMs, chatTotalMax, method, cls === "cosmetic" ? "drop" : "release", cls, dropGuard, deadline, lateKey);
|
|
65387
65496
|
if (totalSlot === null) {
|
|
65388
65497
|
giveBack();
|
|
@@ -65431,6 +65540,8 @@ function createEditFloodFuse(config = {}) {
|
|
|
65431
65540
|
deferred: counters.deferred,
|
|
65432
65541
|
dropped: counters.dropped,
|
|
65433
65542
|
superseded: counters.superseded,
|
|
65543
|
+
throttled: counters.throttled,
|
|
65544
|
+
cosmeticFairShareEnabled,
|
|
65434
65545
|
floodObserved: counters.floodObserved,
|
|
65435
65546
|
tightened: isTightened(now),
|
|
65436
65547
|
tightenLevel: levelAt(now),
|
|
@@ -78753,6 +78864,28 @@ init_rich_send();
|
|
|
78753
78864
|
init_format();
|
|
78754
78865
|
|
|
78755
78866
|
// registry/subagents-schema.ts
|
|
78867
|
+
function mapSubagentRow(row) {
|
|
78868
|
+
return {
|
|
78869
|
+
id: row.id,
|
|
78870
|
+
parent_session_id: row.parent_session_id,
|
|
78871
|
+
parent_turn_key: row.parent_turn_key,
|
|
78872
|
+
agent_type: row.agent_type,
|
|
78873
|
+
description: row.description,
|
|
78874
|
+
background: row.background !== 0,
|
|
78875
|
+
started_at: row.started_at,
|
|
78876
|
+
last_activity_at: row.last_activity_at,
|
|
78877
|
+
ended_at: row.ended_at,
|
|
78878
|
+
status: row.status,
|
|
78879
|
+
result_summary: row.result_summary,
|
|
78880
|
+
jsonl_agent_id: row.jsonl_agent_id,
|
|
78881
|
+
parent_agent_id: row.parent_agent_id ?? null,
|
|
78882
|
+
model: row.model ?? null
|
|
78883
|
+
};
|
|
78884
|
+
}
|
|
78885
|
+
function getSubagentByJsonlId(db2, jsonlAgentId) {
|
|
78886
|
+
const row = db2.prepare("SELECT * FROM subagents WHERE jsonl_agent_id = ?").get(jsonlAgentId);
|
|
78887
|
+
return row ? mapSubagentRow(row) : null;
|
|
78888
|
+
}
|
|
78756
78889
|
function countRunningBackgroundSubagents(db2) {
|
|
78757
78890
|
const row = db2.prepare("SELECT count(*) AS n FROM subagents WHERE background = 1 AND status = 'running'").get();
|
|
78758
78891
|
return row?.n ?? 0;
|
|
@@ -78847,6 +78980,19 @@ function recordNestedSubagentDispatch(db2, args) {
|
|
|
78847
78980
|
WHERE id = ?
|
|
78848
78981
|
`).run(args.parentJsonlAgentId, args.parentJsonlAgentId, args.toolUseId);
|
|
78849
78982
|
}
|
|
78983
|
+
function stampSubagentDispatchTurn(db2, args) {
|
|
78984
|
+
db2.prepare(`
|
|
78985
|
+
INSERT OR IGNORE INTO subagents
|
|
78986
|
+
(id, parent_session_id, parent_turn_key, agent_type, description,
|
|
78987
|
+
background, started_at, last_activity_at, status)
|
|
78988
|
+
VALUES (?, NULL, ?, ?, ?, ?, ?, ?, 'running')
|
|
78989
|
+
`).run(args.toolUseId, args.parentTurnKey, args.agentType ?? null, args.description ?? null, args.background ? 1 : 0, args.now, args.now);
|
|
78990
|
+
db2.prepare(`
|
|
78991
|
+
UPDATE subagents
|
|
78992
|
+
SET parent_turn_key = COALESCE(parent_turn_key, ?)
|
|
78993
|
+
WHERE id = ?
|
|
78994
|
+
`).run(args.parentTurnKey, args.toolUseId);
|
|
78995
|
+
}
|
|
78850
78996
|
function resolveSubagentOriginTurnKey(db2, jsonlAgentId, maxHops = 5) {
|
|
78851
78997
|
const seen = new Set;
|
|
78852
78998
|
let currentJsonlId = jsonlAgentId;
|
|
@@ -81177,6 +81323,28 @@ function isDraftOfReply(textBlock, replyText) {
|
|
|
81177
81323
|
}
|
|
81178
81324
|
|
|
81179
81325
|
// registry/turns-schema.ts
|
|
81326
|
+
function mapRow(row) {
|
|
81327
|
+
return {
|
|
81328
|
+
turn_key: row.turn_key,
|
|
81329
|
+
chat_id: row.chat_id,
|
|
81330
|
+
thread_id: row.thread_id,
|
|
81331
|
+
started_at: row.started_at,
|
|
81332
|
+
ended_at: row.ended_at,
|
|
81333
|
+
ended_via: row.ended_via ?? null,
|
|
81334
|
+
last_assistant_msg_id: row.last_assistant_msg_id,
|
|
81335
|
+
last_assistant_done: row.last_assistant_done === null ? null : row.last_assistant_done !== 0,
|
|
81336
|
+
last_user_msg_id: row.last_user_msg_id,
|
|
81337
|
+
user_prompt_preview: row.user_prompt_preview,
|
|
81338
|
+
assistant_reply_preview: row.assistant_reply_preview,
|
|
81339
|
+
tool_call_count: row.tool_call_count,
|
|
81340
|
+
interrupt_reason: row.interrupt_reason,
|
|
81341
|
+
resumed_at: row.resumed_at,
|
|
81342
|
+
session_id: row.session_id ?? null,
|
|
81343
|
+
answer_redelivered_at: row.answer_redelivered_at ?? null,
|
|
81344
|
+
created_at: row.created_at,
|
|
81345
|
+
updated_at: row.updated_at
|
|
81346
|
+
};
|
|
81347
|
+
}
|
|
81180
81348
|
function recordTurnStart(db3, args) {
|
|
81181
81349
|
const now = Date.now();
|
|
81182
81350
|
db3.prepare(`
|
|
@@ -81201,6 +81369,19 @@ function recordTurnEnd(db3, args) {
|
|
|
81201
81369
|
WHERE turn_key = ?
|
|
81202
81370
|
`).run(now, args.endedVia, args.lastAssistantMsgId ?? null, args.lastAssistantDone !== undefined ? args.lastAssistantDone ? 1 : 0 : null, args.assistantReplyPreview ?? null, args.toolCallCount !== undefined ? args.toolCallCount : null, now, args.turnKey);
|
|
81203
81371
|
}
|
|
81372
|
+
function getTurnByKey(db3, turnKey3) {
|
|
81373
|
+
const row = db3.prepare(`SELECT * FROM turns WHERE turn_key = ?`).get(turnKey3);
|
|
81374
|
+
return row ? mapRow(row) : null;
|
|
81375
|
+
}
|
|
81376
|
+
function findMostRecentTurn(db3, beforeOrAtMs) {
|
|
81377
|
+
const row = db3.prepare(`
|
|
81378
|
+
SELECT * FROM turns
|
|
81379
|
+
WHERE started_at <= ?
|
|
81380
|
+
ORDER BY started_at DESC
|
|
81381
|
+
LIMIT 1
|
|
81382
|
+
`).get(beforeOrAtMs);
|
|
81383
|
+
return row ? mapRow(row) : null;
|
|
81384
|
+
}
|
|
81204
81385
|
var INTERRUPTED_VIA = new Set([
|
|
81205
81386
|
"restart",
|
|
81206
81387
|
"reaped_stale",
|
|
@@ -81316,7 +81497,7 @@ function mayOpenActivityCard(input) {
|
|
|
81316
81497
|
if (input.crossTurnAnswerDelivered)
|
|
81317
81498
|
return false;
|
|
81318
81499
|
if (input.finalAnswerEverDelivered) {
|
|
81319
|
-
if (input.postAnswerSubagentActivity && input.producer === "tool")
|
|
81500
|
+
if ((input.postAnswerSubagentActivity || input.postAnswerMainActivity) && input.producer === "tool")
|
|
81320
81501
|
return true;
|
|
81321
81502
|
return false;
|
|
81322
81503
|
}
|
|
@@ -81429,17 +81610,24 @@ class EmissionAuthority {
|
|
|
81429
81610
|
}
|
|
81430
81611
|
|
|
81431
81612
|
// gateway/feed-reopen-gate.ts
|
|
81613
|
+
var SUBSTANTIVE_REOPEN_MIN_LABELS = 2;
|
|
81432
81614
|
function shouldReopenFeedAfterAck(input) {
|
|
81433
81615
|
if (!input.finalAnswerDelivered)
|
|
81434
81616
|
return false;
|
|
81435
|
-
if (input.finalAnswerSubstantive)
|
|
81436
|
-
|
|
81617
|
+
if (input.finalAnswerSubstantive) {
|
|
81618
|
+
if (input.reopenAfterSubstantiveEnabled !== true)
|
|
81619
|
+
return false;
|
|
81620
|
+
return (input.postSubstantiveToolLabelCount ?? 0) >= SUBSTANTIVE_REOPEN_MIN_LABELS;
|
|
81621
|
+
}
|
|
81437
81622
|
return input.enabled === true;
|
|
81438
81623
|
}
|
|
81439
81624
|
function decideFeedReopen(input) {
|
|
81440
81625
|
if (!shouldReopenFeedAfterAck(input)) {
|
|
81441
81626
|
return { dropLabel: true };
|
|
81442
81627
|
}
|
|
81628
|
+
if (input.finalAnswerSubstantive) {
|
|
81629
|
+
return { dropLabel: false, liftLeverOne: true };
|
|
81630
|
+
}
|
|
81443
81631
|
return {
|
|
81444
81632
|
dropLabel: false,
|
|
81445
81633
|
reset: {
|
|
@@ -82165,6 +82353,8 @@ function beginTurn(deps, ev) {
|
|
|
82165
82353
|
replyCalled: false,
|
|
82166
82354
|
finalAnswerDelivered: false,
|
|
82167
82355
|
finalAnswerSubstantive: false,
|
|
82356
|
+
postSubstantiveToolLabelCount: 0,
|
|
82357
|
+
postAnswerMainActivity: false,
|
|
82168
82358
|
finalAnswerEverDelivered: false,
|
|
82169
82359
|
answerDelivered: false,
|
|
82170
82360
|
flushedAnswerText: null,
|
|
@@ -82278,6 +82468,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
82278
82468
|
CONTEXT_EXHAUSTION_COOLDOWN_MS,
|
|
82279
82469
|
DELIVERY_CONFIRM_ENABLED,
|
|
82280
82470
|
FEED_REOPEN_AFTER_ACK_ENABLED,
|
|
82471
|
+
FEED_REOPEN_AFTER_SUBSTANTIVE_ENABLED,
|
|
82281
82472
|
HANDBACK_PRETURN_ENABLED,
|
|
82282
82473
|
HISTORY_ENABLED,
|
|
82283
82474
|
LIVENESS_TERMINAL_HONESTY,
|
|
@@ -82472,6 +82663,21 @@ function handleSessionEvent(deps, ev) {
|
|
|
82472
82663
|
resolvePendingNarrativeOnTool(turn, ev.toolName, ev.input);
|
|
82473
82664
|
turn.toolCallCount++;
|
|
82474
82665
|
touchTurnActiveMarker(STATE_DIR);
|
|
82666
|
+
if ((ev.toolName === "Agent" || ev.toolName === "Task") && ev.toolUseId != null && ev.toolUseId.length > 0 && turn.registryKey != null && turnsDb != null) {
|
|
82667
|
+
try {
|
|
82668
|
+
stampSubagentDispatchTurn(turnsDb, {
|
|
82669
|
+
toolUseId: ev.toolUseId,
|
|
82670
|
+
parentTurnKey: turn.registryKey,
|
|
82671
|
+
agentType: typeof ev.input?.subagent_type === "string" ? ev.input.subagent_type : null,
|
|
82672
|
+
description: typeof ev.input?.description === "string" ? ev.input.description : null,
|
|
82673
|
+
background: ev.input?.run_in_background === true,
|
|
82674
|
+
now: Date.now()
|
|
82675
|
+
});
|
|
82676
|
+
} catch (err) {
|
|
82677
|
+
process.stderr.write(`telegram gateway: dispatch-time parent_turn_key stamp failed toolUseId=${ev.toolUseId}: ${err.message}
|
|
82678
|
+
`);
|
|
82679
|
+
}
|
|
82680
|
+
}
|
|
82475
82681
|
preambleSuppressor.onTool({ isReplyTool: isTelegramSurfaceTool(ev.toolName) });
|
|
82476
82682
|
surfaceMemoryLegibility(turn, ev.toolName, ev.toolUseId, ev.input);
|
|
82477
82683
|
const ctrl = activeStatusReactions.get(statusKey(turn.sessionChatId, turn.sessionThreadId));
|
|
@@ -82510,16 +82716,24 @@ function handleSessionEvent(deps, ev) {
|
|
|
82510
82716
|
if (isTelegramSurfaceTool(ev.toolName))
|
|
82511
82717
|
return;
|
|
82512
82718
|
if (turn.finalAnswerDelivered) {
|
|
82719
|
+
if (turn.finalAnswerSubstantive)
|
|
82720
|
+
turn.postSubstantiveToolLabelCount++;
|
|
82513
82721
|
const reopen = decideFeedReopen({
|
|
82514
82722
|
finalAnswerDelivered: turn.finalAnswerDelivered,
|
|
82515
82723
|
finalAnswerSubstantive: turn.finalAnswerSubstantive,
|
|
82516
|
-
enabled: FEED_REOPEN_AFTER_ACK_ENABLED
|
|
82724
|
+
enabled: FEED_REOPEN_AFTER_ACK_ENABLED,
|
|
82725
|
+
reopenAfterSubstantiveEnabled: FEED_REOPEN_AFTER_SUBSTANTIVE_ENABLED,
|
|
82726
|
+
postSubstantiveToolLabelCount: turn.postSubstantiveToolLabelCount
|
|
82517
82727
|
});
|
|
82518
82728
|
if (reopen.dropLabel)
|
|
82519
82729
|
return;
|
|
82520
|
-
|
|
82521
|
-
|
|
82522
|
-
|
|
82730
|
+
if (reopen.reset != null) {
|
|
82731
|
+
turn.finalAnswerDelivered = reopen.reset.finalAnswerDelivered;
|
|
82732
|
+
turn.activityMessageId = reopen.reset.activityMessageId;
|
|
82733
|
+
turn.activityLastSentRender = reopen.reset.activityLastSentRender;
|
|
82734
|
+
}
|
|
82735
|
+
if (reopen.liftLeverOne)
|
|
82736
|
+
turn.postAnswerMainActivity = true;
|
|
82523
82737
|
}
|
|
82524
82738
|
const rendered = appendActivityLabel(turn.mirrorLines, ev.label);
|
|
82525
82739
|
if (rendered != null) {
|
|
@@ -83450,7 +83664,8 @@ function createNarrativeLane(deps) {
|
|
|
83450
83664
|
finalAnswerEverDelivered: turn.finalAnswerEverDelivered,
|
|
83451
83665
|
labeledToolCount: turn.labeledToolCount,
|
|
83452
83666
|
crossTurnAnswerDelivered,
|
|
83453
|
-
postAnswerSubagentActivity: openFlags?.postAnswerSubagentActivity
|
|
83667
|
+
postAnswerSubagentActivity: openFlags?.postAnswerSubagentActivity,
|
|
83668
|
+
postAnswerMainActivity: turn.postAnswerMainActivity
|
|
83454
83669
|
})) {
|
|
83455
83670
|
break;
|
|
83456
83671
|
}
|
|
@@ -94966,6 +95181,77 @@ function createTurnStartSurfaces(deps) {
|
|
|
94966
95181
|
return { armTurnStartSurfaces };
|
|
94967
95182
|
}
|
|
94968
95183
|
|
|
95184
|
+
// gateway/progress-fallback-cap.ts
|
|
95185
|
+
var recentSends = new Map;
|
|
95186
|
+
var PROGRESS_FALLBACK_WINDOW_MS = 15 * 60000;
|
|
95187
|
+
var PROGRESS_FALLBACK_MAX = 5;
|
|
95188
|
+
function prune(key, now) {
|
|
95189
|
+
const cutoff = now - PROGRESS_FALLBACK_WINDOW_MS;
|
|
95190
|
+
const recent = (recentSends.get(key) ?? []).filter((ts) => ts > cutoff);
|
|
95191
|
+
if (recent.length === 0)
|
|
95192
|
+
recentSends.delete(key);
|
|
95193
|
+
else
|
|
95194
|
+
recentSends.set(key, recent);
|
|
95195
|
+
return recent;
|
|
95196
|
+
}
|
|
95197
|
+
function reserveProgressFallbackSlot(key, now) {
|
|
95198
|
+
const recent = prune(key, now);
|
|
95199
|
+
if (recent.length >= PROGRESS_FALLBACK_MAX)
|
|
95200
|
+
return null;
|
|
95201
|
+
recent.push(now);
|
|
95202
|
+
recentSends.set(key, recent);
|
|
95203
|
+
let released = false;
|
|
95204
|
+
return {
|
|
95205
|
+
release: () => {
|
|
95206
|
+
if (released)
|
|
95207
|
+
return;
|
|
95208
|
+
released = true;
|
|
95209
|
+
const arr = recentSends.get(key);
|
|
95210
|
+
if (!arr)
|
|
95211
|
+
return;
|
|
95212
|
+
const idx = arr.indexOf(now);
|
|
95213
|
+
if (idx >= 0)
|
|
95214
|
+
arr.splice(idx, 1);
|
|
95215
|
+
if (arr.length === 0)
|
|
95216
|
+
recentSends.delete(key);
|
|
95217
|
+
else
|
|
95218
|
+
recentSends.set(key, arr);
|
|
95219
|
+
}
|
|
95220
|
+
};
|
|
95221
|
+
}
|
|
95222
|
+
var PROGRESS_TURN_MAX = 5;
|
|
95223
|
+
function reserveProgressSlot(deps) {
|
|
95224
|
+
const { key, now, turnStart, turnCount } = deps;
|
|
95225
|
+
if (turnStart != null) {
|
|
95226
|
+
const current = turnCount.get(key) ?? 0;
|
|
95227
|
+
if (current >= PROGRESS_TURN_MAX)
|
|
95228
|
+
return null;
|
|
95229
|
+
turnCount.set(key, current + 1);
|
|
95230
|
+
let released = false;
|
|
95231
|
+
return {
|
|
95232
|
+
release: () => {
|
|
95233
|
+
if (released)
|
|
95234
|
+
return;
|
|
95235
|
+
released = true;
|
|
95236
|
+
turnCount.set(key, Math.max(0, (turnCount.get(key) ?? 0) - 1));
|
|
95237
|
+
}
|
|
95238
|
+
};
|
|
95239
|
+
}
|
|
95240
|
+
return reserveProgressFallbackSlot(key, now);
|
|
95241
|
+
}
|
|
95242
|
+
async function sendWithProgressCap(deps, send) {
|
|
95243
|
+
const reservation = reserveProgressSlot(deps);
|
|
95244
|
+
if (reservation === null)
|
|
95245
|
+
return { capped: true };
|
|
95246
|
+
try {
|
|
95247
|
+
const result = await send();
|
|
95248
|
+
return { capped: false, result };
|
|
95249
|
+
} catch (err) {
|
|
95250
|
+
reservation.release();
|
|
95251
|
+
throw err;
|
|
95252
|
+
}
|
|
95253
|
+
}
|
|
95254
|
+
|
|
94969
95255
|
// gateway/delivery-confirm-wiring.ts
|
|
94970
95256
|
function createDeliveryConfirmWiring(deps) {
|
|
94971
95257
|
const {
|
|
@@ -96432,6 +96718,7 @@ ${result}
|
|
|
96432
96718
|
meta: {
|
|
96433
96719
|
source: "subagent_handback",
|
|
96434
96720
|
outcome: opts.ctx.outcome,
|
|
96721
|
+
chat_id: opts.ctx.chatId,
|
|
96435
96722
|
message_id: String(ts),
|
|
96436
96723
|
...opts.ctx.threadId != null ? { message_thread_id: String(opts.ctx.threadId) } : {},
|
|
96437
96724
|
...opts.ctx.jsonlAgentId ? { subagent_jsonl_id: opts.ctx.jsonlAgentId } : {}
|
|
@@ -96511,6 +96798,7 @@ ${summary}
|
|
|
96511
96798
|
text: text4,
|
|
96512
96799
|
meta: {
|
|
96513
96800
|
source: "subagent_progress",
|
|
96801
|
+
chat_id: opts.ctx.chatId,
|
|
96514
96802
|
...opts.ctx.threadId != null ? { message_thread_id: String(opts.ctx.threadId) } : {},
|
|
96515
96803
|
subagent_jsonl_id: opts.ctx.subagentJsonlId,
|
|
96516
96804
|
bucket_idx: String(opts.ctx.bucketIdx),
|
|
@@ -102121,10 +102409,10 @@ function startOutboxSweep(deps) {
|
|
|
102121
102409
|
}
|
|
102122
102410
|
|
|
102123
102411
|
// ../src/build-info.ts
|
|
102124
|
-
var VERSION2 = "0.20.
|
|
102125
|
-
var COMMIT_SHA = "
|
|
102126
|
-
var COMMIT_DATE = "2026-08-
|
|
102127
|
-
var LATEST_PR =
|
|
102412
|
+
var VERSION2 = "0.20.4";
|
|
102413
|
+
var COMMIT_SHA = "7f669382";
|
|
102414
|
+
var COMMIT_DATE = "2026-08-04T01:43:38Z";
|
|
102415
|
+
var LATEST_PR = 4331;
|
|
102128
102416
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
102129
102417
|
|
|
102130
102418
|
// gateway/boot-version.ts
|
|
@@ -103176,7 +103464,7 @@ function openTurnsDb(agentDir) {
|
|
|
103176
103464
|
} catch {}
|
|
103177
103465
|
return db3;
|
|
103178
103466
|
}
|
|
103179
|
-
function
|
|
103467
|
+
function mapRow2(row) {
|
|
103180
103468
|
return {
|
|
103181
103469
|
turn_key: row.turn_key,
|
|
103182
103470
|
chat_id: row.chat_id,
|
|
@@ -103213,10 +103501,6 @@ function recordTurnEnd2(db3, args) {
|
|
|
103213
103501
|
WHERE turn_key = ?
|
|
103214
103502
|
`).run(now, args.endedVia, args.lastAssistantMsgId ?? null, args.lastAssistantDone !== undefined ? args.lastAssistantDone ? 1 : 0 : null, args.assistantReplyPreview ?? null, args.toolCallCount !== undefined ? args.toolCallCount : null, now, args.turnKey);
|
|
103215
103503
|
}
|
|
103216
|
-
function getTurnByKey(db3, turnKey3) {
|
|
103217
|
-
const row = db3.prepare(`SELECT * FROM turns WHERE turn_key = ?`).get(turnKey3);
|
|
103218
|
-
return row ? mapRow(row) : null;
|
|
103219
|
-
}
|
|
103220
103504
|
function markOrphanedWithTimeoutClassification(db3, opts) {
|
|
103221
103505
|
const now = opts.now ?? Date.now();
|
|
103222
103506
|
const isHang = opts.markerAgeMs != null && opts.markerAgeMs >= opts.hangThresholdMs && opts.markerTurnKey != null && opts.markerTurnKey.length > 0;
|
|
@@ -103307,7 +103591,7 @@ function findLatestTurnIfInterrupted(db3) {
|
|
|
103307
103591
|
`).get();
|
|
103308
103592
|
if (!row)
|
|
103309
103593
|
return null;
|
|
103310
|
-
const turn =
|
|
103594
|
+
const turn = mapRow2(row);
|
|
103311
103595
|
if (turn.resumed_at != null)
|
|
103312
103596
|
return null;
|
|
103313
103597
|
if (turn.ended_at == null)
|
|
@@ -104296,7 +104580,7 @@ function applySubagentsSchema(db3) {
|
|
|
104296
104580
|
db3.exec("CREATE INDEX IF NOT EXISTS subagents_jsonl_id ON subagents(jsonl_agent_id)");
|
|
104297
104581
|
db3.exec("CREATE INDEX IF NOT EXISTS subagents_parent_agent ON subagents(parent_agent_id)");
|
|
104298
104582
|
}
|
|
104299
|
-
function
|
|
104583
|
+
function mapSubagentRow2(row) {
|
|
104300
104584
|
return {
|
|
104301
104585
|
id: row.id,
|
|
104302
104586
|
parent_session_id: row.parent_session_id,
|
|
@@ -104314,9 +104598,9 @@ function mapSubagentRow(row) {
|
|
|
104314
104598
|
model: row.model ?? null
|
|
104315
104599
|
};
|
|
104316
104600
|
}
|
|
104317
|
-
function
|
|
104601
|
+
function getSubagentByJsonlId2(db3, jsonlAgentId) {
|
|
104318
104602
|
const row = db3.prepare("SELECT * FROM subagents WHERE jsonl_agent_id = ?").get(jsonlAgentId);
|
|
104319
|
-
return row ?
|
|
104603
|
+
return row ? mapSubagentRow2(row) : null;
|
|
104320
104604
|
}
|
|
104321
104605
|
function listNonTerminalSubagentsForTurn(db3, parentTurnKey) {
|
|
104322
104606
|
const rows = db3.prepare(`
|
|
@@ -104325,23 +104609,74 @@ function listNonTerminalSubagentsForTurn(db3, parentTurnKey) {
|
|
|
104325
104609
|
AND status NOT IN ('completed', 'failed')
|
|
104326
104610
|
ORDER BY started_at ASC
|
|
104327
104611
|
`).all(parentTurnKey);
|
|
104328
|
-
return rows.map(
|
|
104612
|
+
return rows.map(mapSubagentRow2);
|
|
104329
104613
|
}
|
|
104330
|
-
|
|
104331
|
-
|
|
104332
|
-
|
|
104333
|
-
|
|
104334
|
-
|
|
104614
|
+
|
|
104615
|
+
// gateway/subagent-origin-surface.ts
|
|
104616
|
+
function turnToSurfaceChat(turn) {
|
|
104617
|
+
if (turn == null || turn.chat_id.length === 0)
|
|
104618
|
+
return null;
|
|
104619
|
+
const threadNum = turn.thread_id != null && turn.thread_id.length > 0 ? Number(turn.thread_id) : NaN;
|
|
104620
|
+
return {
|
|
104621
|
+
chatId: turn.chat_id,
|
|
104622
|
+
...Number.isFinite(threadNum) ? { threadId: threadNum } : {}
|
|
104623
|
+
};
|
|
104624
|
+
}
|
|
104625
|
+
function resolveSubagentOriginChatDb(db3, jsonlAgentId) {
|
|
104626
|
+
try {
|
|
104627
|
+
const originKey = resolveSubagentOriginTurnKey(db3, jsonlAgentId);
|
|
104628
|
+
if (originKey == null)
|
|
104335
104629
|
return null;
|
|
104336
|
-
|
|
104337
|
-
|
|
104338
|
-
|
|
104630
|
+
return turnToSurfaceChat(getTurnByKey(db3, originKey));
|
|
104631
|
+
} catch {
|
|
104632
|
+
return null;
|
|
104633
|
+
}
|
|
104634
|
+
}
|
|
104635
|
+
function resolveRecentTurnFallbackChat(db3, jsonlAgentId) {
|
|
104636
|
+
try {
|
|
104637
|
+
const worker = getSubagentByJsonlId(db3, jsonlAgentId);
|
|
104638
|
+
if (worker == null)
|
|
104339
104639
|
return null;
|
|
104340
|
-
|
|
104341
|
-
|
|
104342
|
-
|
|
104640
|
+
return turnToSurfaceChat(findMostRecentTurn(db3, worker.started_at));
|
|
104641
|
+
} catch {
|
|
104642
|
+
return null;
|
|
104343
104643
|
}
|
|
104344
|
-
|
|
104644
|
+
}
|
|
104645
|
+
var RECENT_TURN_FLOOR_LOG_CAP = 256;
|
|
104646
|
+
var recentTurnFloorLogged = new Set;
|
|
104647
|
+
function noteWorkerRecentTurnFloor(agentId, dest, log = (line) => process.stderr.write(line)) {
|
|
104648
|
+
if (recentTurnFloorLogged.has(agentId))
|
|
104649
|
+
return;
|
|
104650
|
+
recentTurnFloorLogged.add(agentId);
|
|
104651
|
+
if (recentTurnFloorLogged.size > RECENT_TURN_FLOOR_LOG_CAP) {
|
|
104652
|
+
const oldest = recentTurnFloorLogged.values().next().value;
|
|
104653
|
+
if (oldest != null)
|
|
104654
|
+
recentTurnFloorLogged.delete(oldest);
|
|
104655
|
+
}
|
|
104656
|
+
log(`telegram gateway: worker origin unresolved agent=${agentId} \u2014 flooring to pre-dispatch recent turn chat=${dest.chatId}${dest.threadId != null ? ` thread=${dest.threadId}` : ""}
|
|
104657
|
+
`);
|
|
104658
|
+
}
|
|
104659
|
+
function resolveWorkerSurfaceForDecider(db3, jsonlAgentId, opts) {
|
|
104660
|
+
const dest = resolveWorkerSurfaceChat(db3, jsonlAgentId, opts);
|
|
104661
|
+
if (dest.via === "recent-turn")
|
|
104662
|
+
noteWorkerRecentTurnFloor(jsonlAgentId, dest);
|
|
104663
|
+
return {
|
|
104664
|
+
fleetChatId: dest.via === "owner-dm" || dest.via === "none" ? "" : dest.chatId,
|
|
104665
|
+
...dest.threadId != null ? { originThreadId: dest.threadId } : {}
|
|
104666
|
+
};
|
|
104667
|
+
}
|
|
104668
|
+
function resolveWorkerSurfaceChat(db3, jsonlAgentId, opts) {
|
|
104669
|
+
const origin = db3 != null ? resolveSubagentOriginChatDb(db3, jsonlAgentId) : null;
|
|
104670
|
+
if (origin != null && origin.chatId.length > 0)
|
|
104671
|
+
return { ...origin, via: "origin" };
|
|
104672
|
+
if (opts.fleetChatId.length > 0)
|
|
104673
|
+
return { chatId: opts.fleetChatId, via: "fleet" };
|
|
104674
|
+
const recent = db3 != null ? resolveRecentTurnFallbackChat(db3, jsonlAgentId) : null;
|
|
104675
|
+
if (recent != null)
|
|
104676
|
+
return { ...recent, via: "recent-turn" };
|
|
104677
|
+
if (opts.ownerDm.length > 0)
|
|
104678
|
+
return { chatId: opts.ownerDm, via: "owner-dm" };
|
|
104679
|
+
return { chatId: "", via: "none" };
|
|
104345
104680
|
}
|
|
104346
104681
|
|
|
104347
104682
|
// gateway/worker-feed-dispatch.ts
|
|
@@ -104887,21 +105222,12 @@ if (isGatewayMain)
|
|
|
104887
105222
|
function resolveSubagentOriginChat(agentId) {
|
|
104888
105223
|
if (turnsDb == null)
|
|
104889
105224
|
return null;
|
|
104890
|
-
|
|
104891
|
-
|
|
104892
|
-
|
|
104893
|
-
|
|
104894
|
-
const turn = getTurnByKey(turnsDb, originKey);
|
|
104895
|
-
if (turn == null || turn.chat_id.length === 0)
|
|
104896
|
-
return null;
|
|
104897
|
-
const threadNum = turn.thread_id != null && turn.thread_id.length > 0 ? Number(turn.thread_id) : NaN;
|
|
104898
|
-
return {
|
|
104899
|
-
chatId: turn.chat_id,
|
|
104900
|
-
threadId: Number.isFinite(threadNum) ? threadNum : undefined
|
|
104901
|
-
};
|
|
104902
|
-
} catch {
|
|
105225
|
+
return resolveSubagentOriginChatDb(turnsDb, agentId);
|
|
105226
|
+
}
|
|
105227
|
+
function recentTurnFallbackChat(agentId) {
|
|
105228
|
+
if (turnsDb == null)
|
|
104903
105229
|
return null;
|
|
104904
|
-
|
|
105230
|
+
return resolveRecentTurnFallbackChat(turnsDb, agentId);
|
|
104905
105231
|
}
|
|
104906
105232
|
var WORKER_FEED_FALLBACK_LOG_CAP = 256;
|
|
104907
105233
|
var WORKER_FEED_STALE_TTL_MARGIN_MS = 5 * 60000;
|
|
@@ -104925,17 +105251,16 @@ function noteWorkerFeedOwnerDmFallback(agentId) {
|
|
|
104925
105251
|
}
|
|
104926
105252
|
var workerFeedOriginDeferrals = new Map;
|
|
104927
105253
|
var WORKER_FEED_ORIGIN_DEFER_MAX = 10;
|
|
104928
|
-
function resolveWorkerFeedChat(agentId, fleetChatId
|
|
104929
|
-
const
|
|
104930
|
-
|
|
104931
|
-
|
|
104932
|
-
|
|
104933
|
-
|
|
104934
|
-
|
|
104935
|
-
if (
|
|
105254
|
+
function resolveWorkerFeedChat(agentId, fleetChatId) {
|
|
105255
|
+
const dest = resolveWorkerSurfaceChat(turnsDb, agentId, {
|
|
105256
|
+
fleetChatId,
|
|
105257
|
+
ownerDm: loadAccess().allowFrom[0] ?? ""
|
|
105258
|
+
});
|
|
105259
|
+
if (dest.via === "recent-turn")
|
|
105260
|
+
noteWorkerRecentTurnFloor(agentId, dest);
|
|
105261
|
+
if (dest.via === "owner-dm")
|
|
104936
105262
|
noteWorkerFeedOwnerDmFallback(agentId);
|
|
104937
|
-
}
|
|
104938
|
-
return { chatId: ownerDm, threadId: origin?.threadId ?? fallbackThreadId };
|
|
105263
|
+
return { chatId: dest.chatId, ...dest.threadId != null ? { threadId: dest.threadId } : {} };
|
|
104939
105264
|
}
|
|
104940
105265
|
var REGISTRY_REAPER_INTERVAL_MS = 6 * 60 * 60 * 1000;
|
|
104941
105266
|
function runHistoryReaperNow(reason) {
|
|
@@ -105197,6 +105522,7 @@ var TOPIC_FRAMING_ENABLED = process.env.SWITCHROOM_TOPIC_FRAMING !== "0";
|
|
|
105197
105522
|
var QUEUED_STATUS_UX_ENABLED = process.env.SWITCHROOM_QUEUED_STATUS_UX !== "0";
|
|
105198
105523
|
var MIDFLIGHT_BUSY_ACK_ENABLED = process.env.SWITCHROOM_MIDFLIGHT_BUSY_ACK !== "0";
|
|
105199
105524
|
var FEED_REOPEN_AFTER_ACK_ENABLED = process.env.SWITCHROOM_FEED_REOPEN_AFTER_ACK !== "0";
|
|
105525
|
+
var FEED_REOPEN_AFTER_SUBSTANTIVE_ENABLED = process.env.SWITCHROOM_FEED_REOPEN_AFTER_SUBSTANTIVE !== "0";
|
|
105200
105526
|
var FEED_HEARTBEAT_ENABLED = process.env.SWITCHROOM_FEED_HEARTBEAT !== "0";
|
|
105201
105527
|
var FEED_HEARTBEAT_TICK_MS = 6000;
|
|
105202
105528
|
var FEED_HEARTBEAT_MIN_STALE_MS = 6000;
|
|
@@ -107697,7 +108023,7 @@ async function runMidSessionCardReaper() {
|
|
|
107697
108023
|
if (turnsDb == null)
|
|
107698
108024
|
return "unknown";
|
|
107699
108025
|
try {
|
|
107700
|
-
const row =
|
|
108026
|
+
const row = getSubagentByJsonlId2(turnsDb, agentId);
|
|
107701
108027
|
if (row == null)
|
|
107702
108028
|
return "unknown";
|
|
107703
108029
|
if (row.status === "completed" || row.status === "failed")
|
|
@@ -109571,26 +109897,23 @@ async function executeProgressUpdate(args) {
|
|
|
109571
109897
|
}
|
|
109572
109898
|
}
|
|
109573
109899
|
const turnStart = activeTurnStartedAt.get(key);
|
|
109574
|
-
if (turnStart != null) {
|
|
109575
|
-
const currentCount = progressUpdateTurnCount.get(key) ?? 0;
|
|
109576
|
-
if (currentCount >= 5) {
|
|
109577
|
-
return {
|
|
109578
|
-
content: [
|
|
109579
|
-
{
|
|
109580
|
-
type: "text",
|
|
109581
|
-
text: JSON.stringify({ ok: false, reason: "turn_limit" })
|
|
109582
|
-
}
|
|
109583
|
-
]
|
|
109584
|
-
};
|
|
109585
|
-
}
|
|
109586
|
-
progressUpdateTurnCount.set(key, currentCount + 1);
|
|
109587
|
-
}
|
|
109588
109900
|
const access = loadAccess();
|
|
109589
109901
|
const literalText = (access.parseMode ?? "html") === "text";
|
|
109590
109902
|
const sendOpts = {
|
|
109591
109903
|
...threadId != null ? { message_thread_id: threadId } : {}
|
|
109592
109904
|
};
|
|
109593
|
-
const
|
|
109905
|
+
const capped = await sendWithProgressCap({ key, now, turnStart, turnCount: progressUpdateTurnCount }, () => robustApiCall(() => literalText ? lockedBot.api.sendMessage(chat_id, text5, sendOpts) : lockedBot.api.sendRichMessage(chat_id, richMessage2(text5), sendOpts), { verb: "sendMessage", chat_id, threadId }));
|
|
109906
|
+
if (capped.capped) {
|
|
109907
|
+
return {
|
|
109908
|
+
content: [
|
|
109909
|
+
{
|
|
109910
|
+
type: "text",
|
|
109911
|
+
text: JSON.stringify({ ok: false, reason: "turn_limit" })
|
|
109912
|
+
}
|
|
109913
|
+
]
|
|
109914
|
+
};
|
|
109915
|
+
}
|
|
109916
|
+
const sent = capped.result;
|
|
109594
109917
|
if (HISTORY_ENABLED) {
|
|
109595
109918
|
recordOutbound({
|
|
109596
109919
|
chat_id,
|
|
@@ -110421,6 +110744,7 @@ function gatewayStreamRenderDeps() {
|
|
|
110421
110744
|
CONTEXT_EXHAUSTION_COOLDOWN_MS,
|
|
110422
110745
|
DELIVERY_CONFIRM_ENABLED,
|
|
110423
110746
|
FEED_REOPEN_AFTER_ACK_ENABLED,
|
|
110747
|
+
FEED_REOPEN_AFTER_SUBSTANTIVE_ENABLED,
|
|
110424
110748
|
HANDBACK_PRETURN_ENABLED,
|
|
110425
110749
|
HISTORY_ENABLED,
|
|
110426
110750
|
LIVENESS_TERMINAL_HONESTY,
|
|
@@ -116006,7 +116330,7 @@ async function startGateway() {
|
|
|
116006
116330
|
let dispatch = resolveWorkerFeedDispatch(null, description2, entryBackground);
|
|
116007
116331
|
if (turnsDb != null) {
|
|
116008
116332
|
try {
|
|
116009
|
-
dispatch = resolveWorkerFeedDispatch(
|
|
116333
|
+
dispatch = resolveWorkerFeedDispatch(getSubagentByJsonlId2(turnsDb, agentId), description2, entryBackground);
|
|
116010
116334
|
} catch {}
|
|
116011
116335
|
}
|
|
116012
116336
|
let isBackground = dispatch.isBackground;
|
|
@@ -116088,14 +116412,13 @@ async function startGateway() {
|
|
|
116088
116412
|
model: dispatch.feedModel ?? undefined
|
|
116089
116413
|
});
|
|
116090
116414
|
}
|
|
116091
|
-
const
|
|
116415
|
+
const hbOwnerDm = loadAccess().allowFrom[0] ?? "";
|
|
116092
116416
|
const decision = decideSubagentHandback({
|
|
116093
116417
|
handbackEnvValue: process.env.SWITCHROOM_SUBAGENT_HANDBACK,
|
|
116094
116418
|
outcome,
|
|
116095
116419
|
isBackground,
|
|
116096
|
-
|
|
116097
|
-
|
|
116098
|
-
ownerChatId: loadAccess().allowFrom[0] ?? "",
|
|
116420
|
+
...resolveWorkerSurfaceForDecider(turnsDb, agentId, { fleetChatId, ownerDm: hbOwnerDm }),
|
|
116421
|
+
ownerChatId: hbOwnerDm,
|
|
116099
116422
|
taskDescription: description2,
|
|
116100
116423
|
resultText,
|
|
116101
116424
|
jsonlAgentId: agentId
|
|
@@ -116136,7 +116459,7 @@ async function startGateway() {
|
|
|
116136
116459
|
let dispatch = resolveWorkerFeedDispatch(null, description2);
|
|
116137
116460
|
if (turnsDb != null) {
|
|
116138
116461
|
try {
|
|
116139
|
-
dispatch = resolveWorkerFeedDispatch(
|
|
116462
|
+
dispatch = resolveWorkerFeedDispatch(getSubagentByJsonlId2(turnsDb, agentId), description2);
|
|
116140
116463
|
} catch {}
|
|
116141
116464
|
}
|
|
116142
116465
|
const isBackground = dispatch.isBackground || dispatch.isNested;
|
|
@@ -116212,14 +116535,16 @@ async function startGateway() {
|
|
|
116212
116535
|
stampTurn.subagentActivityAt = Date.now();
|
|
116213
116536
|
}
|
|
116214
116537
|
if (workerFeedEnabled) {
|
|
116538
|
+
const wfOrigin = resolveSubagentOriginChat(agentId);
|
|
116539
|
+
const wfStamp = stampTurn != null ? { chatId: stampTurn.sessionChatId, threadId: stampTurn.sessionThreadId } : wfOrigin == null ? recentTurnFallbackChat(agentId) : null;
|
|
116215
116540
|
const dest = decideWorkerFeedDestination({
|
|
116216
|
-
origin:
|
|
116541
|
+
origin: wfOrigin,
|
|
116217
116542
|
cardExists: workerActivityFeed?.has(agentId) === true,
|
|
116218
116543
|
priorDeferrals: workerFeedOriginDeferrals.get(agentId) ?? 0,
|
|
116219
116544
|
maxDeferrals: WORKER_FEED_ORIGIN_DEFER_MAX,
|
|
116220
116545
|
fleetChatId,
|
|
116221
|
-
stampChatId:
|
|
116222
|
-
stampThreadId:
|
|
116546
|
+
stampChatId: wfStamp?.chatId,
|
|
116547
|
+
stampThreadId: wfStamp?.threadId,
|
|
116223
116548
|
ownerDm: loadAccess().allowFrom[0] ?? ""
|
|
116224
116549
|
});
|
|
116225
116550
|
if (dest.action === "defer") {
|
|
@@ -116233,6 +116558,9 @@ async function startGateway() {
|
|
|
116233
116558
|
}
|
|
116234
116559
|
if (dest.ownerDmFallback)
|
|
116235
116560
|
noteWorkerFeedOwnerDmFallback(agentId);
|
|
116561
|
+
if (stampTurn == null && wfOrigin == null && wfStamp != null && dest.chatId === wfStamp.chatId) {
|
|
116562
|
+
noteWorkerRecentTurnFloor(agentId, wfStamp);
|
|
116563
|
+
}
|
|
116236
116564
|
workerActivityFeed?.update(agentId, dest.chatId, {
|
|
116237
116565
|
description: dispatch.feedDescription,
|
|
116238
116566
|
lastTool,
|
|
@@ -116245,14 +116573,17 @@ async function startGateway() {
|
|
|
116245
116573
|
}, dest.threadId);
|
|
116246
116574
|
return;
|
|
116247
116575
|
}
|
|
116248
|
-
const
|
|
116576
|
+
const pgOwnerDm = loadAccess().allowFrom[0] ?? "";
|
|
116577
|
+
const progressSurface = resolveWorkerSurfaceForDecider(turnsDb, agentId, {
|
|
116578
|
+
fleetChatId,
|
|
116579
|
+
ownerDm: pgOwnerDm
|
|
116580
|
+
});
|
|
116249
116581
|
const decision = decideSubagentProgress({
|
|
116250
116582
|
skeleton: skeleton === true,
|
|
116251
116583
|
disableEnvValue: process.env.SWITCHROOM_DISABLE_SUBAGENT_PROGRESS,
|
|
116252
116584
|
isBackground,
|
|
116253
|
-
|
|
116254
|
-
|
|
116255
|
-
ownerChatId: loadAccess().allowFrom[0] ?? "",
|
|
116585
|
+
...progressSurface,
|
|
116586
|
+
ownerChatId: pgOwnerDm,
|
|
116256
116587
|
subagentJsonlId: agentId,
|
|
116257
116588
|
taskDescription: description2,
|
|
116258
116589
|
latestSummary,
|
|
@@ -116264,7 +116595,7 @@ async function startGateway() {
|
|
|
116264
116595
|
return;
|
|
116265
116596
|
setBucketIdx(decision.bucketIdx);
|
|
116266
116597
|
pendingInboundBuffer.push(process.env.SWITCHROOM_AGENT_NAME ?? "", decision.inbound);
|
|
116267
|
-
clearPending(statusKey(decision.chatId,
|
|
116598
|
+
clearPending(statusKey(decision.chatId, progressSurface.originThreadId), "progress");
|
|
116268
116599
|
process.stderr.write(`telegram gateway: subagent-progress queued agent=${agentId} bucket=${decision.bucketIdx} elapsed_ms=${elapsedMs} chat=${decision.chatId}
|
|
116269
116600
|
`);
|
|
116270
116601
|
}
|