switchroom 0.18.26 → 0.18.27
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/README.md +6 -2
- package/dist/cli/ms-365-write-pretool.mjs +4953 -14
- package/dist/cli/switchroom.js +1 -1
- package/dist/host-control/main.js +1 -1
- package/package.json +1 -1
- package/profiles/_base/start.sh.hbs +16 -0
- package/telegram-plugin/dist/gateway/gateway.js +494 -36
- package/telegram-plugin/flushed-turn-supersede.ts +58 -0
- package/telegram-plugin/gateway/derive-turn-id.ts +32 -0
- package/telegram-plugin/gateway/gateway.ts +305 -41
- package/telegram-plugin/gateway/handback-preturn-signal.ts +442 -0
- package/telegram-plugin/gateway/model-command.ts +68 -0
- package/telegram-plugin/gateway/ms365-write-approval.test.ts +101 -0
- package/telegram-plugin/gateway/ms365-write-approval.ts +65 -3
- package/telegram-plugin/gateway/subagent-handback-inbound-builder.ts +12 -0
- package/telegram-plugin/gateway/turn-active-marker.ts +35 -0
- package/telegram-plugin/send-gate.test.ts +138 -0
- package/telegram-plugin/send-gate.ts +104 -1
- package/telegram-plugin/tests/activity-ever-opened-sticky.test.ts +14 -4
- package/telegram-plugin/tests/effort-command.test.ts +47 -0
- package/telegram-plugin/tests/flushed-turn-supersede.test.ts +60 -0
- package/telegram-plugin/tests/handback-preturn-adoption-roundtrip.test.ts +211 -0
- package/telegram-plugin/tests/handback-preturn-signal.test.ts +346 -0
- package/telegram-plugin/tests/model-command.test.ts +112 -0
- package/telegram-plugin/tests/multitopic-routing-wiring.test.ts +14 -2
- package/telegram-plugin/tests/outbound-send-chunks.test.ts +57 -0
- package/telegram-plugin/tests/permission-no-repeat-wiring.test.ts +18 -11
- package/telegram-plugin/tests/reply-owner-resolve.test.ts +90 -0
- package/telegram-plugin/tests/subagent-handback-inbound-builder.test.ts +5 -0
- package/telegram-plugin/tests/turn-active-marker.test.ts +29 -0
- package/telegram-plugin/tests/worker-activity-feed.test.ts +121 -0
- package/telegram-plugin/worker-activity-feed.ts +91 -1
|
@@ -39670,6 +39670,13 @@ function decideSupersede(record, args) {
|
|
|
39670
39670
|
}
|
|
39671
39671
|
return { supersede: true, deleteMessageIds: [...record.messageIds], reason: "supersede" };
|
|
39672
39672
|
}
|
|
39673
|
+
function decideSupersedeCorrection(input) {
|
|
39674
|
+
const eligible = input.flushMessageIds.length === 1 && input.chunkCount === 1 && !input.hasFiles && !input.suppressText && !input.hasOpenPreview;
|
|
39675
|
+
if (eligible) {
|
|
39676
|
+
return { mode: "edit-in-place", editMessageId: input.flushMessageIds[0], deleteMessageIds: [] };
|
|
39677
|
+
}
|
|
39678
|
+
return { mode: "delete-resend", deleteMessageIds: [...input.flushMessageIds] };
|
|
39679
|
+
}
|
|
39673
39680
|
var NULL_TURN_KEY = "<<null-turn>>";
|
|
39674
39681
|
function turnKey(turnId) {
|
|
39675
39682
|
return turnId == null ? NULL_TURN_KEY : turnId;
|
|
@@ -40962,6 +40969,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
40962
40969
|
const nowFn = opts.now ?? Date.now;
|
|
40963
40970
|
const floodWaitRemainingMs = opts.floodWaitRemainingMs ?? (() => 0);
|
|
40964
40971
|
const minEditInterval = opts.minEditIntervalMs ?? 2500;
|
|
40972
|
+
const elapsedRefreshMs = Math.max(minEditInterval, Math.floor(opts.elapsedRefreshMs ?? 15000));
|
|
40965
40973
|
const firstPaintMin = opts.firstPaintMinMs ?? 8000;
|
|
40966
40974
|
const heartbeatTickMs = opts.heartbeatTickMs ?? 6000;
|
|
40967
40975
|
const maxRows = Math.max(1, Math.floor(opts.maxRows ?? 8));
|
|
@@ -41076,6 +41084,35 @@ function createWorkerActivityFeed(opts) {
|
|
|
41076
41084
|
});
|
|
41077
41085
|
return renderCombinedWorkerFeed(rows, { maxRows });
|
|
41078
41086
|
}
|
|
41087
|
+
function groupSubstanceKey(g, terminalRecap) {
|
|
41088
|
+
const FS = "\x00";
|
|
41089
|
+
const RS = "\x1E";
|
|
41090
|
+
if (terminalRecap != null) {
|
|
41091
|
+
return [
|
|
41092
|
+
"T",
|
|
41093
|
+
terminalRecap.state,
|
|
41094
|
+
terminalRecap.description,
|
|
41095
|
+
terminalRecap.toolCount,
|
|
41096
|
+
terminalRecap.totalTokens ?? "",
|
|
41097
|
+
terminalRecap.latestSummary,
|
|
41098
|
+
...terminalRecap.narrativeLines ?? []
|
|
41099
|
+
].join(FS);
|
|
41100
|
+
}
|
|
41101
|
+
const running = runningRows(g);
|
|
41102
|
+
if (running.length === 0)
|
|
41103
|
+
return "EMPTY";
|
|
41104
|
+
return running.map((r) => {
|
|
41105
|
+
const v = r.lastView;
|
|
41106
|
+
return [
|
|
41107
|
+
r.agentId,
|
|
41108
|
+
v.state,
|
|
41109
|
+
v.description,
|
|
41110
|
+
v.toolCount,
|
|
41111
|
+
v.totalTokens ?? "",
|
|
41112
|
+
...r.narrative
|
|
41113
|
+
].join(FS);
|
|
41114
|
+
}).join(RS);
|
|
41115
|
+
}
|
|
41079
41116
|
function removeWorker(g, agentId) {
|
|
41080
41117
|
g.workers.delete(agentId);
|
|
41081
41118
|
agentIndex.delete(agentId);
|
|
@@ -41125,6 +41162,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
41125
41162
|
return;
|
|
41126
41163
|
}
|
|
41127
41164
|
const body = renderGroupBody(g, now, opts2.terminalRecap ?? null, opts2.heartbeat ?? false);
|
|
41165
|
+
const substanceKey = groupSubstanceKey(g, opts2.terminalRecap ?? null);
|
|
41128
41166
|
if (body == null) {
|
|
41129
41167
|
if (isTerminal)
|
|
41130
41168
|
clearStaged();
|
|
@@ -41148,6 +41186,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
41148
41186
|
g.messageId = sent.message_id;
|
|
41149
41187
|
g.messageCreatedAtMs = now;
|
|
41150
41188
|
g.lastBody = body;
|
|
41189
|
+
g.lastSubstanceKey = substanceKey;
|
|
41151
41190
|
g.lastEditAt = now;
|
|
41152
41191
|
g.terminalPainted = false;
|
|
41153
41192
|
syncPin(g);
|
|
@@ -41163,8 +41202,13 @@ function createWorkerActivityFeed(opts) {
|
|
|
41163
41202
|
clearStaged();
|
|
41164
41203
|
return;
|
|
41165
41204
|
}
|
|
41166
|
-
if (!opts2.force &&
|
|
41167
|
-
|
|
41205
|
+
if (!opts2.force && !isTerminal) {
|
|
41206
|
+
if (now - g.lastEditAt < minEditInterval)
|
|
41207
|
+
return;
|
|
41208
|
+
const substanceChanged = substanceKey !== g.lastSubstanceKey;
|
|
41209
|
+
if (!substanceChanged && now - g.lastEditAt < elapsedRefreshMs)
|
|
41210
|
+
return;
|
|
41211
|
+
}
|
|
41168
41212
|
try {
|
|
41169
41213
|
const res = await opts.bot.editMessageText(g.chatId, g.messageId, body, sendOptsFor(g));
|
|
41170
41214
|
if (isSendGateShed(res)) {
|
|
@@ -41172,6 +41216,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
41172
41216
|
return;
|
|
41173
41217
|
}
|
|
41174
41218
|
g.lastBody = body;
|
|
41219
|
+
g.lastSubstanceKey = substanceKey;
|
|
41175
41220
|
g.lastEditAt = now;
|
|
41176
41221
|
if (isTerminal) {
|
|
41177
41222
|
log(`worker-feed: finish feed=${g.feedKey} chat=${g.chatId} thread=${g.threadId ?? "-"} ` + `msgId=${g.messageId} agent=${finishingAgentId ?? "-"} ` + `state=${opts2.terminalRecap?.state ?? "done"} bytes=${body.length}`);
|
|
@@ -41189,6 +41234,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
41189
41234
|
}
|
|
41190
41235
|
if (outcome === "not_modified") {
|
|
41191
41236
|
g.lastBody = body;
|
|
41237
|
+
g.lastSubstanceKey = substanceKey;
|
|
41192
41238
|
g.lastEditAt = now;
|
|
41193
41239
|
if (isTerminal)
|
|
41194
41240
|
clearStaged();
|
|
@@ -41198,6 +41244,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
41198
41244
|
g.messageId = null;
|
|
41199
41245
|
g.messageCreatedAtMs = 0;
|
|
41200
41246
|
g.lastBody = null;
|
|
41247
|
+
g.lastSubstanceKey = null;
|
|
41201
41248
|
if (isTerminal)
|
|
41202
41249
|
clearStaged();
|
|
41203
41250
|
else
|
|
@@ -41307,6 +41354,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
41307
41354
|
g.messageId = null;
|
|
41308
41355
|
g.messageCreatedAtMs = 0;
|
|
41309
41356
|
g.lastBody = null;
|
|
41357
|
+
g.lastSubstanceKey = null;
|
|
41310
41358
|
syncPin(g);
|
|
41311
41359
|
opts.bot.editMessageText(g.chatId, retiredId, WORKER_CARD_SUPERSEDED_BODY, sendOptsFor(g)).catch(() => {});
|
|
41312
41360
|
}
|
|
@@ -41366,6 +41414,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
41366
41414
|
messageId: null,
|
|
41367
41415
|
messageCreatedAtMs: 0,
|
|
41368
41416
|
lastBody: null,
|
|
41417
|
+
lastSubstanceKey: null,
|
|
41369
41418
|
lastEditAt: 0,
|
|
41370
41419
|
cooldownUntil: 0,
|
|
41371
41420
|
chain: Promise.resolve(),
|
|
@@ -41379,6 +41428,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
41379
41428
|
g.messageId = null;
|
|
41380
41429
|
g.messageCreatedAtMs = 0;
|
|
41381
41430
|
g.lastBody = null;
|
|
41431
|
+
g.lastSubstanceKey = null;
|
|
41382
41432
|
g.pendingFinalize.clear();
|
|
41383
41433
|
g.terminalPainted = false;
|
|
41384
41434
|
syncPin(g);
|
|
@@ -46193,6 +46243,207 @@ function createTurnTypingLoop(deps) {
|
|
|
46193
46243
|
};
|
|
46194
46244
|
}
|
|
46195
46245
|
|
|
46246
|
+
// gateway/handback-preturn-signal.ts
|
|
46247
|
+
var PRETURN_TURNKEY_PREFIX = "preturn:";
|
|
46248
|
+
function isHandbackInbound(msg) {
|
|
46249
|
+
return msg.type === "inbound" && msg.meta?.source === "subagent_handback";
|
|
46250
|
+
}
|
|
46251
|
+
function createHandbackPreturnSignal(deps) {
|
|
46252
|
+
const now = deps.now ?? (() => Date.now());
|
|
46253
|
+
const debounceMs = deps.debounceMs ?? 700;
|
|
46254
|
+
const adoptTimeoutMs = deps.adoptTimeoutMs ?? 30000;
|
|
46255
|
+
const setTimer = deps.setTimer ?? ((fn, ms) => {
|
|
46256
|
+
const t = setTimeout(fn, ms);
|
|
46257
|
+
t.unref?.();
|
|
46258
|
+
return t;
|
|
46259
|
+
});
|
|
46260
|
+
const clearTimer = deps.clearTimer ?? ((h) => clearTimeout(h));
|
|
46261
|
+
const log = deps.log ?? ((l) => process.stderr.write(l));
|
|
46262
|
+
const byKey = new Map;
|
|
46263
|
+
const bySyntheticKey = new Map;
|
|
46264
|
+
function clearTimers(entry) {
|
|
46265
|
+
if (entry.debounceTimer != null) {
|
|
46266
|
+
clearTimer(entry.debounceTimer);
|
|
46267
|
+
entry.debounceTimer = null;
|
|
46268
|
+
}
|
|
46269
|
+
if (entry.reapTimer != null) {
|
|
46270
|
+
clearTimer(entry.reapTimer);
|
|
46271
|
+
entry.reapTimer = null;
|
|
46272
|
+
}
|
|
46273
|
+
}
|
|
46274
|
+
function dropEntry(entry) {
|
|
46275
|
+
clearTimers(entry);
|
|
46276
|
+
byKey.delete(entry.statusKey);
|
|
46277
|
+
bySyntheticKey.delete(entry.syntheticTurnKey);
|
|
46278
|
+
}
|
|
46279
|
+
function emit(entry) {
|
|
46280
|
+
entry.debounceTimer = null;
|
|
46281
|
+
if (entry.consumed)
|
|
46282
|
+
return;
|
|
46283
|
+
if (deps.isTurnSettled?.(entry.statusKey)) {
|
|
46284
|
+
dropEntry(entry);
|
|
46285
|
+
return;
|
|
46286
|
+
}
|
|
46287
|
+
deps.startTypingLoop(entry.chatId, entry.threadId);
|
|
46288
|
+
entry.emitted = true;
|
|
46289
|
+
entry.reapTimer = setTimer(() => reap(entry), adoptTimeoutMs);
|
|
46290
|
+
Promise.resolve().then(() => deps.openCard(entry.chatId, entry.threadId)).then((messageId) => {
|
|
46291
|
+
if (messageId == null)
|
|
46292
|
+
return;
|
|
46293
|
+
if (entry.consumed) {
|
|
46294
|
+
deps.finalizeCard({
|
|
46295
|
+
turnKey: entry.syntheticTurnKey,
|
|
46296
|
+
chatId: entry.chatId,
|
|
46297
|
+
threadId: entry.threadId,
|
|
46298
|
+
activityMessageId: messageId,
|
|
46299
|
+
startedAt: entry.startedAt,
|
|
46300
|
+
pinned: entry.pinned
|
|
46301
|
+
});
|
|
46302
|
+
return;
|
|
46303
|
+
}
|
|
46304
|
+
entry.activityMessageId = messageId;
|
|
46305
|
+
const record = {
|
|
46306
|
+
turnKey: entry.syntheticTurnKey,
|
|
46307
|
+
chatId: entry.chatId,
|
|
46308
|
+
threadId: entry.threadId,
|
|
46309
|
+
activityMessageId: messageId,
|
|
46310
|
+
startedAt: entry.startedAt,
|
|
46311
|
+
pinned: entry.pinned
|
|
46312
|
+
};
|
|
46313
|
+
deps.writeCardRecord(record);
|
|
46314
|
+
}).catch((err) => {
|
|
46315
|
+
log(`handback-preturn-signal: openCard failed key=${entry.statusKey}: ` + `${err instanceof Error ? err.message : String(err)}
|
|
46316
|
+
`);
|
|
46317
|
+
});
|
|
46318
|
+
}
|
|
46319
|
+
function reap(entry) {
|
|
46320
|
+
entry.reapTimer = null;
|
|
46321
|
+
if (entry.consumed)
|
|
46322
|
+
return;
|
|
46323
|
+
entry.consumed = true;
|
|
46324
|
+
deps.stopTypingLoop(entry.chatId, entry.threadId);
|
|
46325
|
+
if (entry.activityMessageId != null) {
|
|
46326
|
+
const record = {
|
|
46327
|
+
turnKey: entry.syntheticTurnKey,
|
|
46328
|
+
chatId: entry.chatId,
|
|
46329
|
+
threadId: entry.threadId,
|
|
46330
|
+
activityMessageId: entry.activityMessageId,
|
|
46331
|
+
startedAt: entry.startedAt,
|
|
46332
|
+
pinned: entry.pinned
|
|
46333
|
+
};
|
|
46334
|
+
deps.clearCardRecord(entry.syntheticTurnKey, entry.activityMessageId);
|
|
46335
|
+
Promise.resolve(deps.finalizeCard(record)).catch((err) => {
|
|
46336
|
+
log(`handback-preturn-signal: orphan finalize failed key=${entry.statusKey}: ` + `${err instanceof Error ? err.message : String(err)}
|
|
46337
|
+
`);
|
|
46338
|
+
});
|
|
46339
|
+
}
|
|
46340
|
+
dropEntry(entry);
|
|
46341
|
+
}
|
|
46342
|
+
return {
|
|
46343
|
+
noteHandbackRelease(inbound) {
|
|
46344
|
+
if (!isHandbackInbound(inbound))
|
|
46345
|
+
return;
|
|
46346
|
+
const chatId = inbound.chatId;
|
|
46347
|
+
if (chatId == null || chatId === "")
|
|
46348
|
+
return;
|
|
46349
|
+
const threadId = inbound.threadId ?? null;
|
|
46350
|
+
const adoptTurnId = deps.deriveTurnId(chatId, threadId, inbound.messageId);
|
|
46351
|
+
if (adoptTurnId == null)
|
|
46352
|
+
return;
|
|
46353
|
+
const statusKey = deps.chatKey(chatId, threadId);
|
|
46354
|
+
if (byKey.has(statusKey))
|
|
46355
|
+
return;
|
|
46356
|
+
const startedAt = now();
|
|
46357
|
+
const syntheticTurnKey = `${PRETURN_TURNKEY_PREFIX}${statusKey}:${startedAt}`;
|
|
46358
|
+
const entry = {
|
|
46359
|
+
statusKey,
|
|
46360
|
+
chatId,
|
|
46361
|
+
threadId,
|
|
46362
|
+
adoptTurnId,
|
|
46363
|
+
syntheticTurnKey,
|
|
46364
|
+
startedAt,
|
|
46365
|
+
pinned: false,
|
|
46366
|
+
debounceTimer: null,
|
|
46367
|
+
reapTimer: null,
|
|
46368
|
+
activityMessageId: null,
|
|
46369
|
+
emitted: false,
|
|
46370
|
+
consumed: false
|
|
46371
|
+
};
|
|
46372
|
+
byKey.set(statusKey, entry);
|
|
46373
|
+
bySyntheticKey.set(syntheticTurnKey, statusKey);
|
|
46374
|
+
entry.debounceTimer = setTimer(() => emit(entry), debounceMs);
|
|
46375
|
+
},
|
|
46376
|
+
tryAdopt(turnId) {
|
|
46377
|
+
let entry;
|
|
46378
|
+
for (const e of byKey.values()) {
|
|
46379
|
+
if (e.adoptTurnId === turnId && !e.consumed) {
|
|
46380
|
+
entry = e;
|
|
46381
|
+
break;
|
|
46382
|
+
}
|
|
46383
|
+
}
|
|
46384
|
+
if (entry == null)
|
|
46385
|
+
return null;
|
|
46386
|
+
entry.consumed = true;
|
|
46387
|
+
clearTimers(entry);
|
|
46388
|
+
const adoption = {
|
|
46389
|
+
statusKey: entry.statusKey,
|
|
46390
|
+
chatId: entry.chatId,
|
|
46391
|
+
threadId: entry.threadId,
|
|
46392
|
+
activityMessageId: entry.activityMessageId,
|
|
46393
|
+
startedAt: entry.startedAt,
|
|
46394
|
+
pinned: entry.pinned
|
|
46395
|
+
};
|
|
46396
|
+
if (entry.activityMessageId != null) {
|
|
46397
|
+
deps.clearCardRecord(entry.syntheticTurnKey, entry.activityMessageId);
|
|
46398
|
+
deps.writeCardRecord({
|
|
46399
|
+
turnKey: entry.statusKey,
|
|
46400
|
+
chatId: entry.chatId,
|
|
46401
|
+
threadId: entry.threadId,
|
|
46402
|
+
activityMessageId: entry.activityMessageId,
|
|
46403
|
+
startedAt: entry.startedAt,
|
|
46404
|
+
pinned: entry.pinned
|
|
46405
|
+
});
|
|
46406
|
+
}
|
|
46407
|
+
dropEntry(entry);
|
|
46408
|
+
return adoption;
|
|
46409
|
+
},
|
|
46410
|
+
isPreTurnRecord(turnKey2) {
|
|
46411
|
+
return turnKey2.startsWith(PRETURN_TURNKEY_PREFIX);
|
|
46412
|
+
},
|
|
46413
|
+
handleReaped(turnKey2) {
|
|
46414
|
+
const statusKey = bySyntheticKey.get(turnKey2);
|
|
46415
|
+
if (statusKey == null)
|
|
46416
|
+
return;
|
|
46417
|
+
const entry = byKey.get(statusKey);
|
|
46418
|
+
if (entry == null)
|
|
46419
|
+
return;
|
|
46420
|
+
entry.consumed = true;
|
|
46421
|
+
deps.stopTypingLoop(entry.chatId, entry.threadId);
|
|
46422
|
+
dropEntry(entry);
|
|
46423
|
+
},
|
|
46424
|
+
pendingCount() {
|
|
46425
|
+
let n = 0;
|
|
46426
|
+
for (const e of byKey.values())
|
|
46427
|
+
if (!e.consumed)
|
|
46428
|
+
n++;
|
|
46429
|
+
return n;
|
|
46430
|
+
},
|
|
46431
|
+
stopAll() {
|
|
46432
|
+
for (const e of [...byKey.values()])
|
|
46433
|
+
clearTimers(e);
|
|
46434
|
+
byKey.clear();
|
|
46435
|
+
bySyntheticKey.clear();
|
|
46436
|
+
}
|
|
46437
|
+
};
|
|
46438
|
+
}
|
|
46439
|
+
|
|
46440
|
+
// gateway/derive-turn-id.ts
|
|
46441
|
+
function deriveTurnId(chatId, threadId, messageId) {
|
|
46442
|
+
if (messageId == null || messageId === "" || String(messageId) === "0")
|
|
46443
|
+
return null;
|
|
46444
|
+
return `${chatKey(chatId, threadId ?? null)}#${messageId}`;
|
|
46445
|
+
}
|
|
46446
|
+
|
|
46196
46447
|
// typing-emitter.ts
|
|
46197
46448
|
var TYPING_REFRESH_MS = 4000;
|
|
46198
46449
|
var TYPING_FLOOR_MS = 3500;
|
|
@@ -56388,7 +56639,9 @@ var SEND_GATE_DEFAULTS = {
|
|
|
56388
56639
|
perChatBurst: 3,
|
|
56389
56640
|
perGroupPerMin: 18,
|
|
56390
56641
|
perGroupBurst: 2,
|
|
56391
|
-
editFloorMs: 1500
|
|
56642
|
+
editFloorMs: 1500,
|
|
56643
|
+
perMessageEditWindowMs: 300000,
|
|
56644
|
+
perMessageEditMaxPerWindow: 150
|
|
56392
56645
|
};
|
|
56393
56646
|
function createSendGate(config) {
|
|
56394
56647
|
const enabled2 = config.enabled;
|
|
@@ -56400,6 +56653,8 @@ function createSendGate(config) {
|
|
|
56400
56653
|
const perGroupPerMin = config.perGroupPerMin ?? SEND_GATE_DEFAULTS.perGroupPerMin;
|
|
56401
56654
|
const perGroupBurst = config.perGroupBurst ?? SEND_GATE_DEFAULTS.perGroupBurst;
|
|
56402
56655
|
const editFloorMs = config.editFloorMs ?? SEND_GATE_DEFAULTS.editFloorMs;
|
|
56656
|
+
const perMessageEditWindowMs = Math.max(1, Math.floor(config.perMessageEditWindowMs ?? SEND_GATE_DEFAULTS.perMessageEditWindowMs));
|
|
56657
|
+
const perMessageEditMaxPerWindow = Math.max(0, Math.floor(config.perMessageEditMaxPerWindow ?? SEND_GATE_DEFAULTS.perMessageEditMaxPerWindow));
|
|
56403
56658
|
const messageStateTtlMs = config.messageStateTtlMs ?? 60000;
|
|
56404
56659
|
const maxMessageStates = config.maxMessageStates ?? 5000;
|
|
56405
56660
|
const usefulTtlMs = config.usefulTtlMs ?? 120000;
|
|
@@ -56415,7 +56670,8 @@ function createSendGate(config) {
|
|
|
56415
56670
|
dropped: 0,
|
|
56416
56671
|
shed: 0,
|
|
56417
56672
|
expired: 0,
|
|
56418
|
-
failedFast: 0
|
|
56673
|
+
failedFast: 0,
|
|
56674
|
+
budgetDeferred: 0
|
|
56419
56675
|
};
|
|
56420
56676
|
const bootStart = clock.now();
|
|
56421
56677
|
const globalRamp = config.bootRamp ? {
|
|
@@ -56454,7 +56710,8 @@ function createSendGate(config) {
|
|
|
56454
56710
|
lastHash: undefined,
|
|
56455
56711
|
pending: null,
|
|
56456
56712
|
running: false,
|
|
56457
|
-
suppressedUntilMs: 0
|
|
56713
|
+
suppressedUntilMs: 0,
|
|
56714
|
+
editWindowTs: []
|
|
56458
56715
|
};
|
|
56459
56716
|
perMessage.set(key, state);
|
|
56460
56717
|
}
|
|
@@ -56641,7 +56898,20 @@ function createSendGate(config) {
|
|
|
56641
56898
|
try {
|
|
56642
56899
|
while (state.pending) {
|
|
56643
56900
|
const now = clock.now();
|
|
56644
|
-
|
|
56901
|
+
let readyAt = Math.max(state.lastSentMs + editFloorMs, state.suppressedUntilMs);
|
|
56902
|
+
if (perMessageEditMaxPerWindow > 0 && state.pending.priorityClass === "cosmetic") {
|
|
56903
|
+
const windowStart = now - perMessageEditWindowMs;
|
|
56904
|
+
while (state.editWindowTs.length > 0 && state.editWindowTs[0] <= windowStart) {
|
|
56905
|
+
state.editWindowTs.shift();
|
|
56906
|
+
}
|
|
56907
|
+
if (state.editWindowTs.length >= perMessageEditMaxPerWindow) {
|
|
56908
|
+
const budgetReadyAt = state.editWindowTs[0] + perMessageEditWindowMs;
|
|
56909
|
+
if (budgetReadyAt > readyAt) {
|
|
56910
|
+
readyAt = budgetReadyAt;
|
|
56911
|
+
counters.budgetDeferred++;
|
|
56912
|
+
}
|
|
56913
|
+
}
|
|
56914
|
+
}
|
|
56645
56915
|
const waitMs = readyAt - now;
|
|
56646
56916
|
if (waitMs > 0) {
|
|
56647
56917
|
await clock.sleep(waitMs);
|
|
@@ -56667,6 +56937,12 @@ function createSendGate(config) {
|
|
|
56667
56937
|
await admit(bucketsFor(opts));
|
|
56668
56938
|
}
|
|
56669
56939
|
state.lastSentMs = clock.now();
|
|
56940
|
+
if (perMessageEditMaxPerWindow > 0 && p.priorityClass === "cosmetic") {
|
|
56941
|
+
state.editWindowTs.push(state.lastSentMs);
|
|
56942
|
+
const overflow = state.editWindowTs.length - (perMessageEditMaxPerWindow + 1);
|
|
56943
|
+
if (overflow > 0)
|
|
56944
|
+
state.editWindowTs.splice(0, overflow);
|
|
56945
|
+
}
|
|
56670
56946
|
try {
|
|
56671
56947
|
const res = await p.fn();
|
|
56672
56948
|
state.lastHash = p.hash;
|
|
@@ -56854,6 +57130,12 @@ function sendGateConfigFromEnv(env = process.env) {
|
|
|
56854
57130
|
const editFloorMs = parseNonNegativeInt(env.SWITCHROOM_TG_SEND_GATE_EDIT_FLOOR_MS);
|
|
56855
57131
|
if (editFloorMs !== undefined)
|
|
56856
57132
|
out.editFloorMs = editFloorMs;
|
|
57133
|
+
const perMsgWindowMs = parsePositiveInt(env.SWITCHROOM_TG_SEND_GATE_PER_MSG_EDIT_WINDOW_MS);
|
|
57134
|
+
if (perMsgWindowMs !== undefined)
|
|
57135
|
+
out.perMessageEditWindowMs = perMsgWindowMs;
|
|
57136
|
+
const perMsgMax = parseNonNegativeInt(env.SWITCHROOM_TG_SEND_GATE_PER_MSG_EDIT_MAX);
|
|
57137
|
+
if (perMsgMax !== undefined)
|
|
57138
|
+
out.perMessageEditMaxPerWindow = perMsgMax;
|
|
56857
57139
|
const conservativeGlobal = parseBoolFlag(env.SWITCHROOM_TG_SEND_GATE_CONSERVATIVE_GLOBAL);
|
|
56858
57140
|
if (conservativeGlobal !== undefined)
|
|
56859
57141
|
out.conservativeGlobalFloodScope = conservativeGlobal;
|
|
@@ -70901,6 +71183,15 @@ function parseModelCommand(text4) {
|
|
|
70901
71183
|
function isModelCommandBusy(ctx) {
|
|
70902
71184
|
return ctx.currentTurnActive || ctx.turnInFlight;
|
|
70903
71185
|
}
|
|
71186
|
+
function resolveStaleAwareBusy(input) {
|
|
71187
|
+
const turnStale = input.currentTurnActive && input.turnAgeMs !== null && input.turnAgeMs > input.hardTtlMs;
|
|
71188
|
+
const approvalLive = input.oldestPendingApprovalAgeMs !== null && input.oldestPendingApprovalAgeMs <= input.hardTtlMs;
|
|
71189
|
+
return {
|
|
71190
|
+
currentTurnActive: input.currentTurnActive && !turnStale,
|
|
71191
|
+
turnInFlight: input.machineInTurn || approvalLive,
|
|
71192
|
+
clearStaleTurn: turnStale
|
|
71193
|
+
};
|
|
71194
|
+
}
|
|
70904
71195
|
function planModelCommand(parsed, ctx) {
|
|
70905
71196
|
if (parsed.kind === "show" && ctx.menuEnabled)
|
|
70906
71197
|
return { kind: "menu" };
|
|
@@ -75523,10 +75814,34 @@ function validateMs365Preview(input) {
|
|
|
75523
75814
|
out.sizeBytesBefore = o.sizeBytesBefore;
|
|
75524
75815
|
if (typeof o.sizeBytesAfter === "number")
|
|
75525
75816
|
out.sizeBytesAfter = o.sizeBytesAfter;
|
|
75817
|
+
if (typeof o.eventWhen === "string")
|
|
75818
|
+
out.eventWhen = o.eventWhen;
|
|
75819
|
+
const changes = sanitizeChanges(o.changes);
|
|
75820
|
+
if (changes)
|
|
75821
|
+
out.changes = changes;
|
|
75526
75822
|
if (typeof o.agentRationale === "string")
|
|
75527
75823
|
out.agentRationale = o.agentRationale;
|
|
75528
75824
|
return out;
|
|
75529
75825
|
}
|
|
75826
|
+
function sanitizeChanges(input) {
|
|
75827
|
+
if (!Array.isArray(input))
|
|
75828
|
+
return;
|
|
75829
|
+
const out = [];
|
|
75830
|
+
for (const raw of input) {
|
|
75831
|
+
if (!raw || typeof raw !== "object")
|
|
75832
|
+
continue;
|
|
75833
|
+
const c = raw;
|
|
75834
|
+
if (typeof c.field !== "string" || c.field.length === 0)
|
|
75835
|
+
continue;
|
|
75836
|
+
const entry = { field: c.field };
|
|
75837
|
+
if (typeof c.before === "string")
|
|
75838
|
+
entry.before = c.before;
|
|
75839
|
+
if (typeof c.after === "string")
|
|
75840
|
+
entry.after = c.after;
|
|
75841
|
+
out.push(entry);
|
|
75842
|
+
}
|
|
75843
|
+
return out.length > 0 ? out : undefined;
|
|
75844
|
+
}
|
|
75530
75845
|
var DEFAULT_TTL_MS2 = 5 * 60 * 1000;
|
|
75531
75846
|
var MAX_TTL_MS2 = 30 * 60 * 1000;
|
|
75532
75847
|
var MIN_TTL_MS2 = 30 * 1000;
|
|
@@ -75551,6 +75866,9 @@ function buildMs365CardText(p) {
|
|
|
75551
75866
|
lines.push(`ID: ${truncate3(p.itemId, 96)}`);
|
|
75552
75867
|
}
|
|
75553
75868
|
lines.push(`Account: ${truncate3(p.accountEmail, 96)}`);
|
|
75869
|
+
if (p.eventWhen) {
|
|
75870
|
+
lines.push(`When: ${truncate3(p.eventWhen, 96)}`);
|
|
75871
|
+
}
|
|
75554
75872
|
if (typeof p.sizeBytesBefore === "number" || typeof p.sizeBytesAfter === "number") {
|
|
75555
75873
|
const before = p.sizeBytesBefore ?? 0;
|
|
75556
75874
|
const after = p.sizeBytesAfter ?? 0;
|
|
@@ -75561,19 +75879,29 @@ function buildMs365CardText(p) {
|
|
|
75561
75879
|
if (p.deepLink) {
|
|
75562
75880
|
lines.push(`Link: ${truncate3(p.deepLink, 256)}`);
|
|
75563
75881
|
}
|
|
75882
|
+
if (p.changes && p.changes.length > 0) {
|
|
75883
|
+
lines.push("");
|
|
75884
|
+
lines.push("Changes:");
|
|
75885
|
+
for (const c of p.changes.slice(0, 8)) {
|
|
75886
|
+
const before = c.before !== undefined ? truncate3(c.before, 96) : "(none)";
|
|
75887
|
+
const after = c.after !== undefined ? truncate3(c.after, 96) : "(cleared)";
|
|
75888
|
+
lines.push(`\u2022 ${c.field}: ${before} \u2192 ${after}`);
|
|
75889
|
+
}
|
|
75890
|
+
}
|
|
75564
75891
|
if (p.agentRationale) {
|
|
75565
75892
|
lines.push("");
|
|
75566
75893
|
lines.push(`\uD83D\uDCAC ${truncate3(p.agentRationale, 512)}`);
|
|
75567
75894
|
}
|
|
75568
75895
|
lines.push("");
|
|
75569
|
-
lines.push("\u26a0\ufe0f Weak attestation (RFC \u00a78 v1): operator should click through to verify the actual change before approving. Structural diff coming v1.5.");
|
|
75896
|
+
lines.push(p.changes && p.changes.length > 0 ? "\u26a0\ufe0f Attestation (RFC \u00a78 v1.5): the diff above is derived from live Graph state + the mutation payload. Verify before approving." : "\u26a0\ufe0f Weak attestation (RFC \u00a78 v1): operator should click through to verify the actual change before approving. Structural diff coming v1.5.");
|
|
75570
75897
|
return hardenCardBreaks(lines.join(`
|
|
75571
75898
|
`));
|
|
75572
75899
|
}
|
|
75573
75900
|
function truncate3(s, n) {
|
|
75574
|
-
|
|
75575
|
-
|
|
75576
|
-
|
|
75901
|
+
const oneLine = s.replace(/[\r\n\t]+/g, " ");
|
|
75902
|
+
if (oneLine.length <= n)
|
|
75903
|
+
return oneLine;
|
|
75904
|
+
return oneLine.slice(0, n - 1) + "\u2026";
|
|
75577
75905
|
}
|
|
75578
75906
|
function humanBytes(bytes) {
|
|
75579
75907
|
const abs = Math.abs(bytes);
|
|
@@ -78164,6 +78492,7 @@ ${result}
|
|
|
78164
78492
|
meta: {
|
|
78165
78493
|
source: "subagent_handback",
|
|
78166
78494
|
outcome: opts.ctx.outcome,
|
|
78495
|
+
message_id: String(ts),
|
|
78167
78496
|
...opts.ctx.threadId != null ? { message_thread_id: String(opts.ctx.threadId) } : {},
|
|
78168
78497
|
...opts.ctx.jsonlAgentId ? { subagent_jsonl_id: opts.ctx.jsonlAgentId } : {}
|
|
78169
78498
|
}
|
|
@@ -80002,6 +80331,7 @@ import {
|
|
|
80002
80331
|
} from "node:fs";
|
|
80003
80332
|
import { join as join39 } from "node:path";
|
|
80004
80333
|
var TURN_ACTIVE_MARKER_FILE = "turn-active.json";
|
|
80334
|
+
var TURN_ACTIVE_HARD_TTL_MS = 10 * 60000;
|
|
80005
80335
|
function touchTurnActiveMarker(stateDir) {
|
|
80006
80336
|
const path2 = join39(stateDir, TURN_ACTIVE_MARKER_FILE);
|
|
80007
80337
|
if (!existsSync34(path2))
|
|
@@ -83728,6 +84058,8 @@ import {
|
|
|
83728
84058
|
} from "node:fs";
|
|
83729
84059
|
import { join as join52 } from "node:path";
|
|
83730
84060
|
var TURN_ACTIVE_MARKER_FILE2 = "turn-active.json";
|
|
84061
|
+
var TURN_ACTIVE_HARD_TTL_MS2 = 10 * 60000;
|
|
84062
|
+
var TURN_ACTIVE_IDLE_SWEEP_MS = 60000;
|
|
83731
84063
|
function writeTurnActiveMarker(stateDir, marker) {
|
|
83732
84064
|
try {
|
|
83733
84065
|
mkdirSync37(stateDir, { recursive: true });
|
|
@@ -83794,12 +84126,15 @@ function readTurnActiveMarkerAgeMs(stateDir, now) {
|
|
|
83794
84126
|
return null;
|
|
83795
84127
|
}
|
|
83796
84128
|
}
|
|
84129
|
+
function effectiveTurnAgeMs(markerAgeMs, turnStartedAt, now) {
|
|
84130
|
+
return markerAgeMs ?? now - turnStartedAt;
|
|
84131
|
+
}
|
|
83797
84132
|
|
|
83798
84133
|
// ../src/build-info.ts
|
|
83799
|
-
var VERSION = "0.18.
|
|
83800
|
-
var COMMIT_SHA = "
|
|
83801
|
-
var COMMIT_DATE = "2026-07-
|
|
83802
|
-
var LATEST_PR =
|
|
84134
|
+
var VERSION = "0.18.27";
|
|
84135
|
+
var COMMIT_SHA = "93871829";
|
|
84136
|
+
var COMMIT_DATE = "2026-07-16T01:31:20Z";
|
|
84137
|
+
var LATEST_PR = 3273;
|
|
83803
84138
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
83804
84139
|
|
|
83805
84140
|
// gateway/boot-version.ts
|
|
@@ -86479,9 +86814,43 @@ var FEED_LIVENESS_OPEN_MS = (() => {
|
|
|
86479
86814
|
var POST_ANSWER_LIVENESS_STALE_MS = parsePostAnswerLivenessMs(process.env.SWITCHROOM_POST_ANSWER_LIVENESS_STALE_MS) || 30000;
|
|
86480
86815
|
function turnInFlightForGate() {
|
|
86481
86816
|
const hasPendingApproval = pendingPermissions.size > 0;
|
|
86817
|
+
return turnInFlightMachineOnly() || hasPendingApproval;
|
|
86818
|
+
}
|
|
86819
|
+
function turnInFlightMachineOnly() {
|
|
86482
86820
|
if (!isDeliveryCutoverEnabled())
|
|
86483
|
-
return claudeBusyKeys.size > 0
|
|
86484
|
-
return probeGateParity(isMachineInTurn(), claudeBusyKeys.size)
|
|
86821
|
+
return claudeBusyKeys.size > 0;
|
|
86822
|
+
return probeGateParity(isMachineInTurn(), claudeBusyKeys.size);
|
|
86823
|
+
}
|
|
86824
|
+
function liveTurnAgeMs(now) {
|
|
86825
|
+
if (currentTurn === null)
|
|
86826
|
+
return null;
|
|
86827
|
+
return effectiveTurnAgeMs(readTurnActiveMarkerAgeMs(STATE_DIR, now), currentTurn.startedAt, now);
|
|
86828
|
+
}
|
|
86829
|
+
function oldestPendingApprovalAgeMs(now) {
|
|
86830
|
+
let oldest = null;
|
|
86831
|
+
for (const p of pendingPermissions.values()) {
|
|
86832
|
+
const age = now - p.startedAt;
|
|
86833
|
+
if (oldest === null || age > oldest)
|
|
86834
|
+
oldest = age;
|
|
86835
|
+
}
|
|
86836
|
+
return oldest;
|
|
86837
|
+
}
|
|
86838
|
+
function resolveModelEffortBusy(now = Date.now()) {
|
|
86839
|
+
const turnAgeMs = liveTurnAgeMs(now);
|
|
86840
|
+
const resolved = resolveStaleAwareBusy({
|
|
86841
|
+
currentTurnActive: currentTurn !== null,
|
|
86842
|
+
turnAgeMs,
|
|
86843
|
+
machineInTurn: turnInFlightMachineOnly(),
|
|
86844
|
+
oldestPendingApprovalAgeMs: oldestPendingApprovalAgeMs(now),
|
|
86845
|
+
hardTtlMs: TURN_ACTIVE_HARD_TTL_MS2
|
|
86846
|
+
});
|
|
86847
|
+
if (resolved.clearStaleTurn && currentTurn !== null) {
|
|
86848
|
+
const ageSec = Math.round((turnAgeMs ?? 0) / 1000);
|
|
86849
|
+
process.stderr.write(`telegram gateway: [phantomturn] cleared stale currentTurn atom age=${ageSec}s ttl=${Math.round(TURN_ACTIVE_HARD_TTL_MS2 / 1000)}s for /model|/effort busy-check agent=${getMyAgentName()}
|
|
86850
|
+
`);
|
|
86851
|
+
clearAllCurrentTurns();
|
|
86852
|
+
}
|
|
86853
|
+
return { currentTurnActive: resolved.currentTurnActive, turnInFlight: resolved.turnInFlight };
|
|
86485
86854
|
}
|
|
86486
86855
|
function deliverResumeSyntheticOrBuffer(agent, inbound) {
|
|
86487
86856
|
const decision = decideInboundDelivery({
|
|
@@ -86649,11 +87018,6 @@ function findTurnByQuotedMessageId(chatId, replyTo) {
|
|
|
86649
87018
|
return null;
|
|
86650
87019
|
return turn;
|
|
86651
87020
|
}
|
|
86652
|
-
function deriveTurnId(chatId, threadId, messageId) {
|
|
86653
|
-
if (messageId == null || messageId === "" || String(messageId) === "0")
|
|
86654
|
-
return null;
|
|
86655
|
-
return `${chatKey2(chatId, threadId ?? null)}#${messageId}`;
|
|
86656
|
-
}
|
|
86657
87021
|
function findTurnByOriginId(originTurnId) {
|
|
86658
87022
|
if (originTurnId == null || originTurnId === "")
|
|
86659
87023
|
return null;
|
|
@@ -88479,8 +88843,8 @@ var pendingStateReaper = setInterval(() => {
|
|
|
88479
88843
|
try {
|
|
88480
88844
|
sweepStaleTurnActiveMarker(STATE_DIR, {
|
|
88481
88845
|
turnInFlight: currentTurn?.registryKey != null,
|
|
88482
|
-
idleSweepMs:
|
|
88483
|
-
hardTtlMs:
|
|
88846
|
+
idleSweepMs: TURN_ACTIVE_IDLE_SWEEP_MS,
|
|
88847
|
+
hardTtlMs: TURN_ACTIVE_HARD_TTL_MS2,
|
|
88484
88848
|
now,
|
|
88485
88849
|
onRemove: ({ ageMs, reason, payload }) => {
|
|
88486
88850
|
const agent = getMyAgentName();
|
|
@@ -88927,11 +89291,16 @@ async function runMidSessionCardReaper() {
|
|
|
88927
89291
|
isLive: (record2) => topicKeys.has(record2.turnKey),
|
|
88928
89292
|
ttlMs: MID_SESSION_CARD_REAPER_TTL_MS,
|
|
88929
89293
|
now,
|
|
88930
|
-
finalizeCard: (record2) =>
|
|
88931
|
-
|
|
88932
|
-
|
|
88933
|
-
|
|
88934
|
-
|
|
89294
|
+
finalizeCard: (record2) => {
|
|
89295
|
+
if (handbackPreturnSignal.isPreTurnRecord(record2.turnKey)) {
|
|
89296
|
+
handbackPreturnSignal.handleReaped(record2.turnKey);
|
|
89297
|
+
}
|
|
89298
|
+
return robustApiCall(() => lockedBot.api.editMessageText(record2.chatId, record2.activityMessageId, richMessage2(restartOrphanCardFinalizeText(record2.startedAt)), {}), {
|
|
89299
|
+
chat_id: record2.chatId,
|
|
89300
|
+
...record2.threadId != null ? { threadId: record2.threadId } : {},
|
|
89301
|
+
verb: "activity-card.mid-session-reap-finalize"
|
|
89302
|
+
});
|
|
89303
|
+
},
|
|
88935
89304
|
unpinCard: async (record2) => {
|
|
88936
89305
|
const pinKey = `fg:${record2.turnKey}`;
|
|
88937
89306
|
if (statusPinState.has(pinKey)) {
|
|
@@ -89411,6 +89780,8 @@ var _deliveryMachineTick = setInterval(() => {
|
|
|
89411
89780
|
}, DELIVERY_MACHINE_TICK_MS);
|
|
89412
89781
|
_deliveryMachineTick.unref?.();
|
|
89413
89782
|
function trackRedeliveredInbound(merged) {
|
|
89783
|
+
if (HANDBACK_PRETURN_ENABLED)
|
|
89784
|
+
handbackPreturnSignal.noteHandbackRelease(merged);
|
|
89414
89785
|
if (!DELIVERY_CONFIRM_ENABLED)
|
|
89415
89786
|
return;
|
|
89416
89787
|
const isTrackableResume = isTrackableResumeSynthetic(merged.meta);
|
|
@@ -91090,6 +91461,7 @@ async function executeReply(args) {
|
|
|
91090
91461
|
return { content: [{ type: "text", text: "sent (deduped \u2014 same content sent via earlier path)" }] };
|
|
91091
91462
|
}
|
|
91092
91463
|
}
|
|
91464
|
+
let supersedeFlushIds = [];
|
|
91093
91465
|
{
|
|
91094
91466
|
const replyThreadId = args.message_thread_id != null ? Number(args.message_thread_id) : undefined;
|
|
91095
91467
|
const ownerTurn = resolveReplyOwnerTurn(turn, chat_id, args);
|
|
@@ -91098,9 +91470,9 @@ async function executeReply(args) {
|
|
|
91098
91470
|
if (decision.supersede) {
|
|
91099
91471
|
process.stderr.write(`telegram gateway: reply: superseding flushed turn message(s) chatId=${chat_id} ids=${JSON.stringify(decision.deleteMessageIds)}
|
|
91100
91472
|
`);
|
|
91101
|
-
|
|
91102
|
-
|
|
91103
|
-
|
|
91473
|
+
supersedeFlushIds = decision.deleteMessageIds;
|
|
91474
|
+
if (ownerTurn != null)
|
|
91475
|
+
ownerTurn.answerDelivered = true;
|
|
91104
91476
|
} else {
|
|
91105
91477
|
const replySubstantive = isSubstantiveFinalReply({
|
|
91106
91478
|
text: rawText,
|
|
@@ -91328,6 +91700,25 @@ ${url}`;
|
|
|
91328
91700
|
});
|
|
91329
91701
|
}
|
|
91330
91702
|
}
|
|
91703
|
+
if (supersedeFlushIds.length > 0) {
|
|
91704
|
+
const correction = decideSupersedeCorrection({
|
|
91705
|
+
flushMessageIds: supersedeFlushIds,
|
|
91706
|
+
chunkCount: chunks.length,
|
|
91707
|
+
hasFiles: files.length > 0,
|
|
91708
|
+
suppressText,
|
|
91709
|
+
hasOpenPreview: previewMessageId != null
|
|
91710
|
+
});
|
|
91711
|
+
if (correction.mode === "edit-in-place") {
|
|
91712
|
+
previewMessageId = correction.editMessageId;
|
|
91713
|
+
reply_to = undefined;
|
|
91714
|
+
process.stderr.write(`telegram gateway: reply: superseding flushed message via edit-in-place chatId=${chat_id} id=${correction.editMessageId}
|
|
91715
|
+
`);
|
|
91716
|
+
} else {
|
|
91717
|
+
for (const id of correction.deleteMessageIds) {
|
|
91718
|
+
await swallowingApiCall(() => lockedBot.api.deleteMessage(chat_id, id), { chat_id, verb: "reply.supersedeFlushed" });
|
|
91719
|
+
}
|
|
91720
|
+
}
|
|
91721
|
+
}
|
|
91331
91722
|
if (previewMessageId != null && reply_to != null && replyMode !== "off") {
|
|
91332
91723
|
await deleteStalePreview(previewMessageId);
|
|
91333
91724
|
previewMessageId = null;
|
|
@@ -91336,7 +91727,7 @@ ${url}`;
|
|
|
91336
91727
|
let silentAnchorEditDone = false;
|
|
91337
91728
|
{
|
|
91338
91729
|
const turn2 = currentTurn;
|
|
91339
|
-
if (turn2 != null && chunks.length === 1) {
|
|
91730
|
+
if (turn2 != null && chunks.length === 1 && supersedeFlushIds.length === 0) {
|
|
91340
91731
|
const decision = decideSilentReplyAnchor({
|
|
91341
91732
|
effectivelySilent: disableNotification,
|
|
91342
91733
|
anchorMessageId: turn2.silentAnchorMessageId,
|
|
@@ -93151,6 +93542,61 @@ function clearActivitySummary(turn, finalHtmlOverride) {
|
|
|
93151
93542
|
}
|
|
93152
93543
|
});
|
|
93153
93544
|
}
|
|
93545
|
+
var HANDBACK_PRETURN_ENABLED = !STATIC && process.env.SWITCHROOM_HANDBACK_PRETURN !== "0";
|
|
93546
|
+
var HANDBACK_PRETURN_HTML = "\uD83E\uDD1D Reading the worker\u2019s results\u2026";
|
|
93547
|
+
var HANDBACK_PRETURN_ORPHAN_HTML = "\uD83E\uDD1D A background worker finished, but the handback never started \u2014 it may need a nudge.";
|
|
93548
|
+
async function openHandbackPreTurnCard(chatId, threadId) {
|
|
93549
|
+
if (STATIC)
|
|
93550
|
+
return null;
|
|
93551
|
+
try {
|
|
93552
|
+
const sent = await robustApiCall(() => bot.api.sendRichMessage(chatId, richMessage2(HANDBACK_PRETURN_HTML), {
|
|
93553
|
+
...threadId != null ? { message_thread_id: threadId } : {},
|
|
93554
|
+
disable_notification: true
|
|
93555
|
+
}), {
|
|
93556
|
+
chat_id: chatId,
|
|
93557
|
+
...threadId != null ? { threadId } : {},
|
|
93558
|
+
verb: "handback-preturn.send"
|
|
93559
|
+
});
|
|
93560
|
+
return sent?.message_id ?? null;
|
|
93561
|
+
} catch (err) {
|
|
93562
|
+
process.stderr.write(`telegram gateway: handback pre-turn card send failed: ${err.message}
|
|
93563
|
+
`);
|
|
93564
|
+
return null;
|
|
93565
|
+
}
|
|
93566
|
+
}
|
|
93567
|
+
function finalizeHandbackPreTurnCard(record2) {
|
|
93568
|
+
return robustApiCall(() => bot.api.editMessageText(record2.chatId, record2.activityMessageId, richMessage2(HANDBACK_PRETURN_ORPHAN_HTML), {}), {
|
|
93569
|
+
chat_id: record2.chatId,
|
|
93570
|
+
...record2.threadId != null ? { threadId: record2.threadId } : {},
|
|
93571
|
+
verb: "handback-preturn.orphan-finalize"
|
|
93572
|
+
}).then(() => {
|
|
93573
|
+
return;
|
|
93574
|
+
}).catch(() => {
|
|
93575
|
+
return;
|
|
93576
|
+
});
|
|
93577
|
+
}
|
|
93578
|
+
var handbackPreturnSignal = createHandbackPreturnSignal({
|
|
93579
|
+
chatKey: (chatId, threadId) => chatKey2(chatId, threadId),
|
|
93580
|
+
deriveTurnId: (chatId, threadId, messageId) => deriveTurnId(chatId, threadId, messageId),
|
|
93581
|
+
startTypingLoop: (chatId, threadId) => startTurnTypingLoop(chatId, threadId),
|
|
93582
|
+
stopTypingLoop: (chatId, threadId) => stopTurnTypingLoop(chatId, threadId),
|
|
93583
|
+
openCard: openHandbackPreTurnCard,
|
|
93584
|
+
finalizeCard: finalizeHandbackPreTurnCard,
|
|
93585
|
+
writeCardRecord: (record2) => {
|
|
93586
|
+
if (!activityCardPersistEnabled)
|
|
93587
|
+
return;
|
|
93588
|
+
writeActivityCardRecord(ACTIVITY_CARD_STORE_PATH, activityCardStoreFs, record2);
|
|
93589
|
+
},
|
|
93590
|
+
clearCardRecord: (turnKey2, activityMessageId) => {
|
|
93591
|
+
if (!activityCardPersistEnabled)
|
|
93592
|
+
return;
|
|
93593
|
+
clearActivityCardRecord(ACTIVITY_CARD_STORE_PATH, activityCardStoreFs, turnKey2, activityMessageId);
|
|
93594
|
+
},
|
|
93595
|
+
isTurnSettled: (key) => {
|
|
93596
|
+
const live = currentTurnMap.get(key);
|
|
93597
|
+
return live != null && (live.finalAnswerDelivered || live.endedAt != null);
|
|
93598
|
+
}
|
|
93599
|
+
});
|
|
93154
93600
|
var memoryLegibilityStager = new MemoryLegibilityStager;
|
|
93155
93601
|
function sendMemoryLegibilityLine(event, chatId, threadId) {
|
|
93156
93602
|
const line = renderMemoryLegibilityLine(event);
|
|
@@ -93304,6 +93750,16 @@ function handleSessionEvent(ev) {
|
|
|
93304
93750
|
emissionAuthority: new EmissionAuthority(statusKey(ev.chatId, enqThreadIdNum))
|
|
93305
93751
|
};
|
|
93306
93752
|
next.narrativeGate = makeNarrativeGate(next);
|
|
93753
|
+
if (HANDBACK_PRETURN_ENABLED) {
|
|
93754
|
+
const handbackAdoption = handbackPreturnSignal.tryAdopt(turnId);
|
|
93755
|
+
if (handbackAdoption != null) {
|
|
93756
|
+
if (handbackAdoption.activityMessageId != null) {
|
|
93757
|
+
next.activityMessageId = handbackAdoption.activityMessageId;
|
|
93758
|
+
next.activityEverOpened = true;
|
|
93759
|
+
}
|
|
93760
|
+
startTurnTypingLoop(ev.chatId, enqThreadIdNum ?? null);
|
|
93761
|
+
}
|
|
93762
|
+
}
|
|
93307
93763
|
setCurrentTurn(next, statusKey(ev.chatId, enqThreadIdNum));
|
|
93308
93764
|
scheduleEarlyLivenessOpen(next);
|
|
93309
93765
|
process.stderr.write(`telegram gateway: ${formatTurnLifecycle("set", "enqueue", next, startedAt)}
|
|
@@ -96350,7 +96806,8 @@ bot.command("model", async (ctx) => {
|
|
|
96350
96806
|
const parsed = parseModelCommand(text5) ?? { kind: "show" };
|
|
96351
96807
|
const chatId = String(ctx.chat.id);
|
|
96352
96808
|
const threadId = resolveThreadId(chatId, ctx.message?.message_thread_id);
|
|
96353
|
-
const
|
|
96809
|
+
const modelBusy = resolveModelEffortBusy();
|
|
96810
|
+
const busyNow = modelBusy.currentTurnActive || modelBusy.turnInFlight;
|
|
96354
96811
|
process.stderr.write(modelCommandReceiptLine(getMyAgentName(), parsed, busyNow) + `
|
|
96355
96812
|
`);
|
|
96356
96813
|
if (HISTORY_ENABLED && ctx.message?.message_id != null) {
|
|
@@ -96371,8 +96828,8 @@ bot.command("model", async (ctx) => {
|
|
|
96371
96828
|
}
|
|
96372
96829
|
const deps = buildModelDeps({ chatId, threadId });
|
|
96373
96830
|
const disposition = planModelCommand(parsed, {
|
|
96374
|
-
currentTurnActive:
|
|
96375
|
-
turnInFlight:
|
|
96831
|
+
currentTurnActive: modelBusy.currentTurnActive,
|
|
96832
|
+
turnInFlight: modelBusy.turnInFlight,
|
|
96376
96833
|
menuEnabled: process.env.SWITCHROOM_MODEL_MENU !== "0"
|
|
96377
96834
|
});
|
|
96378
96835
|
if (disposition.kind === "menu") {
|
|
@@ -96443,7 +96900,8 @@ bot.command("effort", async (ctx) => {
|
|
|
96443
96900
|
await switchroomReply(ctx, menu.text, { html: true, reply_markup: effortMenuReplyMarkup(menu) });
|
|
96444
96901
|
return;
|
|
96445
96902
|
}
|
|
96446
|
-
|
|
96903
|
+
const effortBusy = resolveModelEffortBusy();
|
|
96904
|
+
if ((parsed.kind === "set" || parsed.kind === "default") && effortBusy.currentTurnActive) {
|
|
96447
96905
|
const requestedLevel = parsed.kind === "set" ? parsed.level : "default";
|
|
96448
96906
|
const chatId = String(ctx.chat.id);
|
|
96449
96907
|
const threadId = resolveThreadId(chatId, ctx.message?.message_thread_id);
|