switchroom 0.18.25 → 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 +2 -2
- package/profiles/_base/start.sh.hbs +16 -0
- package/telegram-plugin/dist/gateway/gateway.js +832 -38
- 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/render/code-segments.ts +210 -0
- package/telegram-plugin/render/dollar-math-guard.ts +126 -0
- package/telegram-plugin/render/emphasis-guard.ts +158 -0
- package/telegram-plugin/render/inline-pairs-guard.ts +171 -0
- package/telegram-plugin/render/line-start-guard.ts +167 -0
- package/telegram-plugin/render/rich-render.ts +7 -0
- package/telegram-plugin/rich-send.ts +48 -2
- 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/render/dollar-math-guard.test.ts +162 -0
- package/telegram-plugin/tests/render/emphasis-guard.test.ts +205 -0
- package/telegram-plugin/tests/render/guard-composition.test.ts +138 -0
- package/telegram-plugin/tests/render/inline-pairs-guard.test.ts +171 -0
- package/telegram-plugin/tests/render/line-start-guard.test.ts +164 -0
- 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
|
@@ -7525,9 +7525,329 @@ var init_approval_card = __esm(() => {
|
|
|
7525
7525
|
import_grammy3 = __toESM(require_mod2(), 1);
|
|
7526
7526
|
});
|
|
7527
7527
|
|
|
7528
|
+
// render/code-segments.ts
|
|
7529
|
+
function findClosingBackticks(text, from, runLen) {
|
|
7530
|
+
let i = from;
|
|
7531
|
+
while (i < text.length) {
|
|
7532
|
+
if (text[i] === "`") {
|
|
7533
|
+
let j = i;
|
|
7534
|
+
while (j < text.length && text[j] === "`")
|
|
7535
|
+
j++;
|
|
7536
|
+
if (j - i === runLen)
|
|
7537
|
+
return j;
|
|
7538
|
+
i = j;
|
|
7539
|
+
} else {
|
|
7540
|
+
i++;
|
|
7541
|
+
}
|
|
7542
|
+
}
|
|
7543
|
+
return -1;
|
|
7544
|
+
}
|
|
7545
|
+
function splitCodeSegments(text) {
|
|
7546
|
+
const out = [];
|
|
7547
|
+
let i = 0;
|
|
7548
|
+
let plainStart = 0;
|
|
7549
|
+
while (i < text.length) {
|
|
7550
|
+
if (text[i] === "`") {
|
|
7551
|
+
let j = i;
|
|
7552
|
+
while (j < text.length && text[j] === "`")
|
|
7553
|
+
j++;
|
|
7554
|
+
const runLen = j - i;
|
|
7555
|
+
const close = findClosingBackticks(text, j, runLen);
|
|
7556
|
+
if (close !== -1) {
|
|
7557
|
+
if (plainStart < i)
|
|
7558
|
+
out.push({ code: false, text: text.slice(plainStart, i) });
|
|
7559
|
+
out.push({ code: true, text: text.slice(i, close) });
|
|
7560
|
+
i = close;
|
|
7561
|
+
plainStart = close;
|
|
7562
|
+
continue;
|
|
7563
|
+
}
|
|
7564
|
+
}
|
|
7565
|
+
i++;
|
|
7566
|
+
}
|
|
7567
|
+
if (plainStart < text.length)
|
|
7568
|
+
out.push({ code: false, text: text.slice(plainStart) });
|
|
7569
|
+
return out;
|
|
7570
|
+
}
|
|
7571
|
+
function isTableDelimiterRow(line) {
|
|
7572
|
+
const t = line.trim();
|
|
7573
|
+
return t.length > 0 && /^[\s|:-]+$/.test(t) && t.includes("-") && t.includes("|");
|
|
7574
|
+
}
|
|
7575
|
+
function isTableCandidateLine(line) {
|
|
7576
|
+
return /^\s*\|/.test(line);
|
|
7577
|
+
}
|
|
7578
|
+
function findTableRanges(text) {
|
|
7579
|
+
const ranges = [];
|
|
7580
|
+
const lines = text.split(`
|
|
7581
|
+
`);
|
|
7582
|
+
let offset = 0;
|
|
7583
|
+
let runStart = -1;
|
|
7584
|
+
let runEnd = -1;
|
|
7585
|
+
let runHasDelim = false;
|
|
7586
|
+
let runLineCount = 0;
|
|
7587
|
+
const flush = () => {
|
|
7588
|
+
if (runStart !== -1 && runLineCount >= 2 && runHasDelim) {
|
|
7589
|
+
ranges.push([runStart, runEnd]);
|
|
7590
|
+
}
|
|
7591
|
+
runStart = -1;
|
|
7592
|
+
runEnd = -1;
|
|
7593
|
+
runHasDelim = false;
|
|
7594
|
+
runLineCount = 0;
|
|
7595
|
+
};
|
|
7596
|
+
for (let k = 0;k < lines.length; k++) {
|
|
7597
|
+
const line = lines[k];
|
|
7598
|
+
const lineLen = line.length + (k < lines.length - 1 ? 1 : 0);
|
|
7599
|
+
if (isTableCandidateLine(line)) {
|
|
7600
|
+
if (runStart === -1)
|
|
7601
|
+
runStart = offset;
|
|
7602
|
+
runEnd = offset + lineLen;
|
|
7603
|
+
runLineCount += 1;
|
|
7604
|
+
if (isTableDelimiterRow(line))
|
|
7605
|
+
runHasDelim = true;
|
|
7606
|
+
} else {
|
|
7607
|
+
flush();
|
|
7608
|
+
}
|
|
7609
|
+
offset += lineLen;
|
|
7610
|
+
}
|
|
7611
|
+
flush();
|
|
7612
|
+
return ranges;
|
|
7613
|
+
}
|
|
7614
|
+
function splitProseProtected(text) {
|
|
7615
|
+
const out = [];
|
|
7616
|
+
const tables = findTableRanges(text);
|
|
7617
|
+
let tIdx = 0;
|
|
7618
|
+
let i = 0;
|
|
7619
|
+
let plainStart = 0;
|
|
7620
|
+
const pushProtected = (from, to) => {
|
|
7621
|
+
if (plainStart < from)
|
|
7622
|
+
out.push({ code: false, text: text.slice(plainStart, from) });
|
|
7623
|
+
out.push({ code: true, text: text.slice(from, to) });
|
|
7624
|
+
plainStart = to;
|
|
7625
|
+
};
|
|
7626
|
+
while (i < text.length) {
|
|
7627
|
+
while (tIdx < tables.length && tables[tIdx][1] <= i)
|
|
7628
|
+
tIdx++;
|
|
7629
|
+
if (tIdx < tables.length && tables[tIdx][0] === i) {
|
|
7630
|
+
const [, end] = tables[tIdx];
|
|
7631
|
+
pushProtected(i, end);
|
|
7632
|
+
i = end;
|
|
7633
|
+
continue;
|
|
7634
|
+
}
|
|
7635
|
+
const ch = text[i];
|
|
7636
|
+
if (ch === "[") {
|
|
7637
|
+
const close = text.indexOf("]", i + 1);
|
|
7638
|
+
if (close !== -1 && text[close + 1] === "(") {
|
|
7639
|
+
const destClose = text.indexOf(")", close + 2);
|
|
7640
|
+
if (destClose !== -1) {
|
|
7641
|
+
pushProtected(close + 1, destClose + 1);
|
|
7642
|
+
i = destClose + 1;
|
|
7643
|
+
continue;
|
|
7644
|
+
}
|
|
7645
|
+
}
|
|
7646
|
+
i++;
|
|
7647
|
+
continue;
|
|
7648
|
+
}
|
|
7649
|
+
if ((ch === "h" || ch === "w") && (i === 0 || !/[A-Za-z0-9]/.test(text[i - 1]))) {
|
|
7650
|
+
const m = /^(?:https?:\/\/|www\.)[^\s<>()\[\]]+/.exec(text.slice(i));
|
|
7651
|
+
if (m) {
|
|
7652
|
+
const end = i + m[0].length;
|
|
7653
|
+
pushProtected(i, end);
|
|
7654
|
+
i = end;
|
|
7655
|
+
continue;
|
|
7656
|
+
}
|
|
7657
|
+
}
|
|
7658
|
+
i++;
|
|
7659
|
+
}
|
|
7660
|
+
if (plainStart < text.length)
|
|
7661
|
+
out.push({ code: false, text: text.slice(plainStart) });
|
|
7662
|
+
return out;
|
|
7663
|
+
}
|
|
7664
|
+
function splitProtectedSegments(text) {
|
|
7665
|
+
const out = [];
|
|
7666
|
+
for (const seg of splitCodeSegments(text)) {
|
|
7667
|
+
if (seg.code) {
|
|
7668
|
+
out.push(seg);
|
|
7669
|
+
continue;
|
|
7670
|
+
}
|
|
7671
|
+
for (const sub of splitProseProtected(seg.text))
|
|
7672
|
+
out.push(sub);
|
|
7673
|
+
}
|
|
7674
|
+
return out;
|
|
7675
|
+
}
|
|
7676
|
+
|
|
7677
|
+
// render/dollar-math-guard.ts
|
|
7678
|
+
function guardDollarMath(text) {
|
|
7679
|
+
if (!text.includes("$"))
|
|
7680
|
+
return text;
|
|
7681
|
+
const segments = splitProtectedSegments(text);
|
|
7682
|
+
let total = 0;
|
|
7683
|
+
let hasCurrencySignal = false;
|
|
7684
|
+
for (const seg of segments) {
|
|
7685
|
+
if (seg.code)
|
|
7686
|
+
continue;
|
|
7687
|
+
total += seg.text.match(ANY_DOLLAR)?.length ?? 0;
|
|
7688
|
+
if (!hasCurrencySignal && CURRENCY_SIGNAL.test(seg.text))
|
|
7689
|
+
hasCurrencySignal = true;
|
|
7690
|
+
}
|
|
7691
|
+
if (total < 2 || !hasCurrencySignal)
|
|
7692
|
+
return text;
|
|
7693
|
+
return segments.map((seg) => seg.code ? seg.text : seg.text.replace(UNESCAPED_DOLLAR, () => "\\$")).join("");
|
|
7694
|
+
}
|
|
7695
|
+
var ANY_DOLLAR, CURRENCY_SIGNAL, UNESCAPED_DOLLAR;
|
|
7696
|
+
var init_dollar_math_guard = __esm(() => {
|
|
7697
|
+
ANY_DOLLAR = /\$/g;
|
|
7698
|
+
CURRENCY_SIGNAL = /\$\.?\d|\d\s?\$/;
|
|
7699
|
+
UNESCAPED_DOLLAR = /(?<!\\)\$/g;
|
|
7700
|
+
});
|
|
7701
|
+
|
|
7702
|
+
// render/emphasis-guard.ts
|
|
7703
|
+
function guardAccidentalEmphasis(text) {
|
|
7704
|
+
if (!text.includes("_") && !text.includes("*"))
|
|
7705
|
+
return text;
|
|
7706
|
+
const segments = splitProtectedSegments(text);
|
|
7707
|
+
let hasIntraUnderscore = false;
|
|
7708
|
+
let hasIntraAsterisk = false;
|
|
7709
|
+
let underscoreCount = 0;
|
|
7710
|
+
let asteriskCount = 0;
|
|
7711
|
+
for (const seg of segments) {
|
|
7712
|
+
if (seg.code)
|
|
7713
|
+
continue;
|
|
7714
|
+
if (INTRA_WORD_UNDERSCORE.test(seg.text))
|
|
7715
|
+
hasIntraUnderscore = true;
|
|
7716
|
+
if (INTRA_WORD_ASTERISK.test(seg.text))
|
|
7717
|
+
hasIntraAsterisk = true;
|
|
7718
|
+
underscoreCount += seg.text.match(ANY_UNDERSCORE)?.length ?? 0;
|
|
7719
|
+
asteriskCount += seg.text.match(ANY_ASTERISK)?.length ?? 0;
|
|
7720
|
+
}
|
|
7721
|
+
INTRA_WORD_UNDERSCORE.lastIndex = 0;
|
|
7722
|
+
INTRA_WORD_ASTERISK.lastIndex = 0;
|
|
7723
|
+
const armUnderscore = hasIntraUnderscore && underscoreCount >= 2;
|
|
7724
|
+
const armAsterisk = hasIntraAsterisk && asteriskCount >= 2;
|
|
7725
|
+
if (!armUnderscore && !armAsterisk)
|
|
7726
|
+
return text;
|
|
7727
|
+
return segments.map((seg) => {
|
|
7728
|
+
if (seg.code)
|
|
7729
|
+
return seg.text;
|
|
7730
|
+
let out = seg.text;
|
|
7731
|
+
if (armUnderscore)
|
|
7732
|
+
out = out.replace(INTRA_WORD_UNDERSCORE, "\\_");
|
|
7733
|
+
if (armAsterisk)
|
|
7734
|
+
out = out.replace(INTRA_WORD_ASTERISK, "\\*");
|
|
7735
|
+
return out;
|
|
7736
|
+
}).join("");
|
|
7737
|
+
}
|
|
7738
|
+
var INTRA_WORD_UNDERSCORE, INTRA_WORD_ASTERISK, ANY_UNDERSCORE, ANY_ASTERISK;
|
|
7739
|
+
var init_emphasis_guard = __esm(() => {
|
|
7740
|
+
INTRA_WORD_UNDERSCORE = /(?<=[A-Za-z0-9])_(?=[A-Za-z0-9])/g;
|
|
7741
|
+
INTRA_WORD_ASTERISK = /(?<=[A-Za-z0-9])\*(?=[A-Za-z0-9])/g;
|
|
7742
|
+
ANY_UNDERSCORE = /(?<!\\)_/g;
|
|
7743
|
+
ANY_ASTERISK = /(?<!\\)\*/g;
|
|
7744
|
+
});
|
|
7745
|
+
|
|
7746
|
+
// render/line-start-guard.ts
|
|
7747
|
+
function escapeAccidentalLineStart(line) {
|
|
7748
|
+
const indent = /^ */.exec(line)[0];
|
|
7749
|
+
if (indent.length >= 4)
|
|
7750
|
+
return line;
|
|
7751
|
+
const rest = line.slice(indent.length);
|
|
7752
|
+
if (ACCIDENTAL_BLOCKQUOTE.test(rest)) {
|
|
7753
|
+
return indent + "\\" + rest;
|
|
7754
|
+
}
|
|
7755
|
+
const ol = ACCIDENTAL_ORDERED_LIST.exec(rest);
|
|
7756
|
+
if (ol) {
|
|
7757
|
+
const digits = ol[1];
|
|
7758
|
+
const delim = ol[2];
|
|
7759
|
+
return indent + digits + "\\" + delim + rest.slice(digits.length + 1);
|
|
7760
|
+
}
|
|
7761
|
+
return line;
|
|
7762
|
+
}
|
|
7763
|
+
function guardAccidentalBlockConstructs(text) {
|
|
7764
|
+
if (!text.includes(">") && !/\d{4,}[.)]/.test(text))
|
|
7765
|
+
return text;
|
|
7766
|
+
const segments = splitProtectedSegments(text);
|
|
7767
|
+
let out = "";
|
|
7768
|
+
let atLineStart = true;
|
|
7769
|
+
for (const seg of segments) {
|
|
7770
|
+
if (seg.code) {
|
|
7771
|
+
out += seg.text;
|
|
7772
|
+
atLineStart = seg.text.endsWith(`
|
|
7773
|
+
`);
|
|
7774
|
+
continue;
|
|
7775
|
+
}
|
|
7776
|
+
const lines = seg.text.split(`
|
|
7777
|
+
`);
|
|
7778
|
+
for (let k = 0;k < lines.length; k++) {
|
|
7779
|
+
const lineIsAtStart = k === 0 ? atLineStart : true;
|
|
7780
|
+
const processed = lineIsAtStart ? escapeAccidentalLineStart(lines[k]) : lines[k];
|
|
7781
|
+
out += processed;
|
|
7782
|
+
if (k < lines.length - 1)
|
|
7783
|
+
out += `
|
|
7784
|
+
`;
|
|
7785
|
+
}
|
|
7786
|
+
atLineStart = seg.text.endsWith(`
|
|
7787
|
+
`);
|
|
7788
|
+
}
|
|
7789
|
+
return out;
|
|
7790
|
+
}
|
|
7791
|
+
var ACCIDENTAL_BLOCKQUOTE, ACCIDENTAL_ORDERED_LIST;
|
|
7792
|
+
var init_line_start_guard = __esm(() => {
|
|
7793
|
+
ACCIDENTAL_BLOCKQUOTE = /^>[0-9=]/;
|
|
7794
|
+
ACCIDENTAL_ORDERED_LIST = /^(\d{4,})([.)])(\s|$)/;
|
|
7795
|
+
});
|
|
7796
|
+
|
|
7797
|
+
// render/inline-pairs-guard.ts
|
|
7798
|
+
function countMatches(text, re) {
|
|
7799
|
+
return text.match(re)?.length ?? 0;
|
|
7800
|
+
}
|
|
7801
|
+
function guardAccidentalInlinePairs(text) {
|
|
7802
|
+
if (!/[~=|]/.test(text))
|
|
7803
|
+
return text;
|
|
7804
|
+
const segments = splitProtectedSegments(text);
|
|
7805
|
+
let tildes = 0;
|
|
7806
|
+
let marks = 0;
|
|
7807
|
+
let spoilers = 0;
|
|
7808
|
+
for (const seg of segments) {
|
|
7809
|
+
if (seg.code)
|
|
7810
|
+
continue;
|
|
7811
|
+
tildes += countMatches(seg.text, TILDE_APPROX);
|
|
7812
|
+
marks += countMatches(seg.text, MARK_OP);
|
|
7813
|
+
spoilers += countMatches(seg.text, SPOILER_OP);
|
|
7814
|
+
}
|
|
7815
|
+
const armTilde = tildes >= 2;
|
|
7816
|
+
const armMark = marks >= 2;
|
|
7817
|
+
const armSpoiler = spoilers >= 2;
|
|
7818
|
+
if (!armTilde && !armMark && !armSpoiler)
|
|
7819
|
+
return text;
|
|
7820
|
+
return segments.map((seg) => {
|
|
7821
|
+
if (seg.code)
|
|
7822
|
+
return seg.text;
|
|
7823
|
+
let out = seg.text;
|
|
7824
|
+
if (armTilde)
|
|
7825
|
+
out = out.replace(TILDE_APPROX, () => "\\~");
|
|
7826
|
+
if (armMark)
|
|
7827
|
+
out = out.replace(MARK_OP, () => "\\=\\=");
|
|
7828
|
+
if (armSpoiler)
|
|
7829
|
+
out = out.replace(SPOILER_OP, () => "\\|\\|");
|
|
7830
|
+
return out;
|
|
7831
|
+
}).join("");
|
|
7832
|
+
}
|
|
7833
|
+
var TILDE_APPROX, MARK_OP, SPOILER_OP;
|
|
7834
|
+
var init_inline_pairs_guard = __esm(() => {
|
|
7835
|
+
TILDE_APPROX = /(?<!\\)~(?=\$?\.?\d)/g;
|
|
7836
|
+
MARK_OP = /(?<=\w)==(?=\w)/g;
|
|
7837
|
+
SPOILER_OP = /(?<=\w)\|\|(?=\w)/g;
|
|
7838
|
+
});
|
|
7839
|
+
|
|
7528
7840
|
// rich-send.ts
|
|
7841
|
+
function guardAccidentalFormatting(markdown) {
|
|
7842
|
+
let out = markdown;
|
|
7843
|
+
out = guardAccidentalEmphasis(out);
|
|
7844
|
+
out = guardAccidentalBlockConstructs(out);
|
|
7845
|
+
out = guardAccidentalInlinePairs(out);
|
|
7846
|
+
out = guardDollarMath(out);
|
|
7847
|
+
return out;
|
|
7848
|
+
}
|
|
7529
7849
|
function richMessage(markdown) {
|
|
7530
|
-
return { markdown };
|
|
7850
|
+
return { markdown: guardAccidentalFormatting(markdown) };
|
|
7531
7851
|
}
|
|
7532
7852
|
function isParseEntitiesError(err) {
|
|
7533
7853
|
if (!(err instanceof import_grammy4.GrammyError) || err.error_code !== 400)
|
|
@@ -7545,6 +7865,10 @@ function isLengthError(err) {
|
|
|
7545
7865
|
}
|
|
7546
7866
|
var import_grammy4;
|
|
7547
7867
|
var init_rich_send = __esm(() => {
|
|
7868
|
+
init_dollar_math_guard();
|
|
7869
|
+
init_emphasis_guard();
|
|
7870
|
+
init_line_start_guard();
|
|
7871
|
+
init_inline_pairs_guard();
|
|
7548
7872
|
import_grammy4 = __toESM(require_mod2(), 1);
|
|
7549
7873
|
});
|
|
7550
7874
|
|
|
@@ -39346,6 +39670,13 @@ function decideSupersede(record, args) {
|
|
|
39346
39670
|
}
|
|
39347
39671
|
return { supersede: true, deleteMessageIds: [...record.messageIds], reason: "supersede" };
|
|
39348
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
|
+
}
|
|
39349
39680
|
var NULL_TURN_KEY = "<<null-turn>>";
|
|
39350
39681
|
function turnKey(turnId) {
|
|
39351
39682
|
return turnId == null ? NULL_TURN_KEY : turnId;
|
|
@@ -40638,6 +40969,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
40638
40969
|
const nowFn = opts.now ?? Date.now;
|
|
40639
40970
|
const floodWaitRemainingMs = opts.floodWaitRemainingMs ?? (() => 0);
|
|
40640
40971
|
const minEditInterval = opts.minEditIntervalMs ?? 2500;
|
|
40972
|
+
const elapsedRefreshMs = Math.max(minEditInterval, Math.floor(opts.elapsedRefreshMs ?? 15000));
|
|
40641
40973
|
const firstPaintMin = opts.firstPaintMinMs ?? 8000;
|
|
40642
40974
|
const heartbeatTickMs = opts.heartbeatTickMs ?? 6000;
|
|
40643
40975
|
const maxRows = Math.max(1, Math.floor(opts.maxRows ?? 8));
|
|
@@ -40752,6 +41084,35 @@ function createWorkerActivityFeed(opts) {
|
|
|
40752
41084
|
});
|
|
40753
41085
|
return renderCombinedWorkerFeed(rows, { maxRows });
|
|
40754
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
|
+
}
|
|
40755
41116
|
function removeWorker(g, agentId) {
|
|
40756
41117
|
g.workers.delete(agentId);
|
|
40757
41118
|
agentIndex.delete(agentId);
|
|
@@ -40801,6 +41162,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
40801
41162
|
return;
|
|
40802
41163
|
}
|
|
40803
41164
|
const body = renderGroupBody(g, now, opts2.terminalRecap ?? null, opts2.heartbeat ?? false);
|
|
41165
|
+
const substanceKey = groupSubstanceKey(g, opts2.terminalRecap ?? null);
|
|
40804
41166
|
if (body == null) {
|
|
40805
41167
|
if (isTerminal)
|
|
40806
41168
|
clearStaged();
|
|
@@ -40824,6 +41186,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
40824
41186
|
g.messageId = sent.message_id;
|
|
40825
41187
|
g.messageCreatedAtMs = now;
|
|
40826
41188
|
g.lastBody = body;
|
|
41189
|
+
g.lastSubstanceKey = substanceKey;
|
|
40827
41190
|
g.lastEditAt = now;
|
|
40828
41191
|
g.terminalPainted = false;
|
|
40829
41192
|
syncPin(g);
|
|
@@ -40839,8 +41202,13 @@ function createWorkerActivityFeed(opts) {
|
|
|
40839
41202
|
clearStaged();
|
|
40840
41203
|
return;
|
|
40841
41204
|
}
|
|
40842
|
-
if (!opts2.force &&
|
|
40843
|
-
|
|
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
|
+
}
|
|
40844
41212
|
try {
|
|
40845
41213
|
const res = await opts.bot.editMessageText(g.chatId, g.messageId, body, sendOptsFor(g));
|
|
40846
41214
|
if (isSendGateShed(res)) {
|
|
@@ -40848,6 +41216,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
40848
41216
|
return;
|
|
40849
41217
|
}
|
|
40850
41218
|
g.lastBody = body;
|
|
41219
|
+
g.lastSubstanceKey = substanceKey;
|
|
40851
41220
|
g.lastEditAt = now;
|
|
40852
41221
|
if (isTerminal) {
|
|
40853
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}`);
|
|
@@ -40865,6 +41234,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
40865
41234
|
}
|
|
40866
41235
|
if (outcome === "not_modified") {
|
|
40867
41236
|
g.lastBody = body;
|
|
41237
|
+
g.lastSubstanceKey = substanceKey;
|
|
40868
41238
|
g.lastEditAt = now;
|
|
40869
41239
|
if (isTerminal)
|
|
40870
41240
|
clearStaged();
|
|
@@ -40874,6 +41244,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
40874
41244
|
g.messageId = null;
|
|
40875
41245
|
g.messageCreatedAtMs = 0;
|
|
40876
41246
|
g.lastBody = null;
|
|
41247
|
+
g.lastSubstanceKey = null;
|
|
40877
41248
|
if (isTerminal)
|
|
40878
41249
|
clearStaged();
|
|
40879
41250
|
else
|
|
@@ -40983,6 +41354,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
40983
41354
|
g.messageId = null;
|
|
40984
41355
|
g.messageCreatedAtMs = 0;
|
|
40985
41356
|
g.lastBody = null;
|
|
41357
|
+
g.lastSubstanceKey = null;
|
|
40986
41358
|
syncPin(g);
|
|
40987
41359
|
opts.bot.editMessageText(g.chatId, retiredId, WORKER_CARD_SUPERSEDED_BODY, sendOptsFor(g)).catch(() => {});
|
|
40988
41360
|
}
|
|
@@ -41042,6 +41414,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
41042
41414
|
messageId: null,
|
|
41043
41415
|
messageCreatedAtMs: 0,
|
|
41044
41416
|
lastBody: null,
|
|
41417
|
+
lastSubstanceKey: null,
|
|
41045
41418
|
lastEditAt: 0,
|
|
41046
41419
|
cooldownUntil: 0,
|
|
41047
41420
|
chain: Promise.resolve(),
|
|
@@ -41055,6 +41428,7 @@ function createWorkerActivityFeed(opts) {
|
|
|
41055
41428
|
g.messageId = null;
|
|
41056
41429
|
g.messageCreatedAtMs = 0;
|
|
41057
41430
|
g.lastBody = null;
|
|
41431
|
+
g.lastSubstanceKey = null;
|
|
41058
41432
|
g.pendingFinalize.clear();
|
|
41059
41433
|
g.terminalPainted = false;
|
|
41060
41434
|
syncPin(g);
|
|
@@ -45869,6 +46243,207 @@ function createTurnTypingLoop(deps) {
|
|
|
45869
46243
|
};
|
|
45870
46244
|
}
|
|
45871
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
|
+
|
|
45872
46447
|
// typing-emitter.ts
|
|
45873
46448
|
var TYPING_REFRESH_MS = 4000;
|
|
45874
46449
|
var TYPING_FLOOR_MS = 3500;
|
|
@@ -56064,7 +56639,9 @@ var SEND_GATE_DEFAULTS = {
|
|
|
56064
56639
|
perChatBurst: 3,
|
|
56065
56640
|
perGroupPerMin: 18,
|
|
56066
56641
|
perGroupBurst: 2,
|
|
56067
|
-
editFloorMs: 1500
|
|
56642
|
+
editFloorMs: 1500,
|
|
56643
|
+
perMessageEditWindowMs: 300000,
|
|
56644
|
+
perMessageEditMaxPerWindow: 150
|
|
56068
56645
|
};
|
|
56069
56646
|
function createSendGate(config) {
|
|
56070
56647
|
const enabled2 = config.enabled;
|
|
@@ -56076,6 +56653,8 @@ function createSendGate(config) {
|
|
|
56076
56653
|
const perGroupPerMin = config.perGroupPerMin ?? SEND_GATE_DEFAULTS.perGroupPerMin;
|
|
56077
56654
|
const perGroupBurst = config.perGroupBurst ?? SEND_GATE_DEFAULTS.perGroupBurst;
|
|
56078
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));
|
|
56079
56658
|
const messageStateTtlMs = config.messageStateTtlMs ?? 60000;
|
|
56080
56659
|
const maxMessageStates = config.maxMessageStates ?? 5000;
|
|
56081
56660
|
const usefulTtlMs = config.usefulTtlMs ?? 120000;
|
|
@@ -56091,7 +56670,8 @@ function createSendGate(config) {
|
|
|
56091
56670
|
dropped: 0,
|
|
56092
56671
|
shed: 0,
|
|
56093
56672
|
expired: 0,
|
|
56094
|
-
failedFast: 0
|
|
56673
|
+
failedFast: 0,
|
|
56674
|
+
budgetDeferred: 0
|
|
56095
56675
|
};
|
|
56096
56676
|
const bootStart = clock.now();
|
|
56097
56677
|
const globalRamp = config.bootRamp ? {
|
|
@@ -56130,7 +56710,8 @@ function createSendGate(config) {
|
|
|
56130
56710
|
lastHash: undefined,
|
|
56131
56711
|
pending: null,
|
|
56132
56712
|
running: false,
|
|
56133
|
-
suppressedUntilMs: 0
|
|
56713
|
+
suppressedUntilMs: 0,
|
|
56714
|
+
editWindowTs: []
|
|
56134
56715
|
};
|
|
56135
56716
|
perMessage.set(key, state);
|
|
56136
56717
|
}
|
|
@@ -56317,7 +56898,20 @@ function createSendGate(config) {
|
|
|
56317
56898
|
try {
|
|
56318
56899
|
while (state.pending) {
|
|
56319
56900
|
const now = clock.now();
|
|
56320
|
-
|
|
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
|
+
}
|
|
56321
56915
|
const waitMs = readyAt - now;
|
|
56322
56916
|
if (waitMs > 0) {
|
|
56323
56917
|
await clock.sleep(waitMs);
|
|
@@ -56343,6 +56937,12 @@ function createSendGate(config) {
|
|
|
56343
56937
|
await admit(bucketsFor(opts));
|
|
56344
56938
|
}
|
|
56345
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
|
+
}
|
|
56346
56946
|
try {
|
|
56347
56947
|
const res = await p.fn();
|
|
56348
56948
|
state.lastHash = p.hash;
|
|
@@ -56530,6 +57130,12 @@ function sendGateConfigFromEnv(env = process.env) {
|
|
|
56530
57130
|
const editFloorMs = parseNonNegativeInt(env.SWITCHROOM_TG_SEND_GATE_EDIT_FLOOR_MS);
|
|
56531
57131
|
if (editFloorMs !== undefined)
|
|
56532
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;
|
|
56533
57139
|
const conservativeGlobal = parseBoolFlag(env.SWITCHROOM_TG_SEND_GATE_CONSERVATIVE_GLOBAL);
|
|
56534
57140
|
if (conservativeGlobal !== undefined)
|
|
56535
57141
|
out.conservativeGlobalFloodScope = conservativeGlobal;
|
|
@@ -67710,9 +68316,21 @@ function backOffOpenInline2(text4, cut) {
|
|
|
67710
68316
|
}
|
|
67711
68317
|
|
|
67712
68318
|
// rich-send.ts
|
|
68319
|
+
init_dollar_math_guard();
|
|
68320
|
+
init_emphasis_guard();
|
|
68321
|
+
init_line_start_guard();
|
|
68322
|
+
init_inline_pairs_guard();
|
|
67713
68323
|
var import_grammy8 = __toESM(require_mod2(), 1);
|
|
68324
|
+
function guardAccidentalFormatting2(markdown) {
|
|
68325
|
+
let out = markdown;
|
|
68326
|
+
out = guardAccidentalEmphasis(out);
|
|
68327
|
+
out = guardAccidentalBlockConstructs(out);
|
|
68328
|
+
out = guardAccidentalInlinePairs(out);
|
|
68329
|
+
out = guardDollarMath(out);
|
|
68330
|
+
return out;
|
|
68331
|
+
}
|
|
67714
68332
|
function richMessage2(markdown) {
|
|
67715
|
-
return { markdown };
|
|
68333
|
+
return { markdown: guardAccidentalFormatting2(markdown) };
|
|
67716
68334
|
}
|
|
67717
68335
|
|
|
67718
68336
|
// gateway/redelivery-decision.ts
|
|
@@ -70565,6 +71183,15 @@ function parseModelCommand(text4) {
|
|
|
70565
71183
|
function isModelCommandBusy(ctx) {
|
|
70566
71184
|
return ctx.currentTurnActive || ctx.turnInFlight;
|
|
70567
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
|
+
}
|
|
70568
71195
|
function planModelCommand(parsed, ctx) {
|
|
70569
71196
|
if (parsed.kind === "show" && ctx.menuEnabled)
|
|
70570
71197
|
return { kind: "menu" };
|
|
@@ -75187,10 +75814,34 @@ function validateMs365Preview(input) {
|
|
|
75187
75814
|
out.sizeBytesBefore = o.sizeBytesBefore;
|
|
75188
75815
|
if (typeof o.sizeBytesAfter === "number")
|
|
75189
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;
|
|
75190
75822
|
if (typeof o.agentRationale === "string")
|
|
75191
75823
|
out.agentRationale = o.agentRationale;
|
|
75192
75824
|
return out;
|
|
75193
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
|
+
}
|
|
75194
75845
|
var DEFAULT_TTL_MS2 = 5 * 60 * 1000;
|
|
75195
75846
|
var MAX_TTL_MS2 = 30 * 60 * 1000;
|
|
75196
75847
|
var MIN_TTL_MS2 = 30 * 1000;
|
|
@@ -75215,6 +75866,9 @@ function buildMs365CardText(p) {
|
|
|
75215
75866
|
lines.push(`ID: ${truncate3(p.itemId, 96)}`);
|
|
75216
75867
|
}
|
|
75217
75868
|
lines.push(`Account: ${truncate3(p.accountEmail, 96)}`);
|
|
75869
|
+
if (p.eventWhen) {
|
|
75870
|
+
lines.push(`When: ${truncate3(p.eventWhen, 96)}`);
|
|
75871
|
+
}
|
|
75218
75872
|
if (typeof p.sizeBytesBefore === "number" || typeof p.sizeBytesAfter === "number") {
|
|
75219
75873
|
const before = p.sizeBytesBefore ?? 0;
|
|
75220
75874
|
const after = p.sizeBytesAfter ?? 0;
|
|
@@ -75225,19 +75879,29 @@ function buildMs365CardText(p) {
|
|
|
75225
75879
|
if (p.deepLink) {
|
|
75226
75880
|
lines.push(`Link: ${truncate3(p.deepLink, 256)}`);
|
|
75227
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
|
+
}
|
|
75228
75891
|
if (p.agentRationale) {
|
|
75229
75892
|
lines.push("");
|
|
75230
75893
|
lines.push(`\uD83D\uDCAC ${truncate3(p.agentRationale, 512)}`);
|
|
75231
75894
|
}
|
|
75232
75895
|
lines.push("");
|
|
75233
|
-
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.");
|
|
75234
75897
|
return hardenCardBreaks(lines.join(`
|
|
75235
75898
|
`));
|
|
75236
75899
|
}
|
|
75237
75900
|
function truncate3(s, n) {
|
|
75238
|
-
|
|
75239
|
-
|
|
75240
|
-
|
|
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";
|
|
75241
75905
|
}
|
|
75242
75906
|
function humanBytes(bytes) {
|
|
75243
75907
|
const abs = Math.abs(bytes);
|
|
@@ -77828,6 +78492,7 @@ ${result}
|
|
|
77828
78492
|
meta: {
|
|
77829
78493
|
source: "subagent_handback",
|
|
77830
78494
|
outcome: opts.ctx.outcome,
|
|
78495
|
+
message_id: String(ts),
|
|
77831
78496
|
...opts.ctx.threadId != null ? { message_thread_id: String(opts.ctx.threadId) } : {},
|
|
77832
78497
|
...opts.ctx.jsonlAgentId ? { subagent_jsonl_id: opts.ctx.jsonlAgentId } : {}
|
|
77833
78498
|
}
|
|
@@ -79666,6 +80331,7 @@ import {
|
|
|
79666
80331
|
} from "node:fs";
|
|
79667
80332
|
import { join as join39 } from "node:path";
|
|
79668
80333
|
var TURN_ACTIVE_MARKER_FILE = "turn-active.json";
|
|
80334
|
+
var TURN_ACTIVE_HARD_TTL_MS = 10 * 60000;
|
|
79669
80335
|
function touchTurnActiveMarker(stateDir) {
|
|
79670
80336
|
const path2 = join39(stateDir, TURN_ACTIVE_MARKER_FILE);
|
|
79671
80337
|
if (!existsSync34(path2))
|
|
@@ -83392,6 +84058,8 @@ import {
|
|
|
83392
84058
|
} from "node:fs";
|
|
83393
84059
|
import { join as join52 } from "node:path";
|
|
83394
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;
|
|
83395
84063
|
function writeTurnActiveMarker(stateDir, marker) {
|
|
83396
84064
|
try {
|
|
83397
84065
|
mkdirSync37(stateDir, { recursive: true });
|
|
@@ -83458,12 +84126,15 @@ function readTurnActiveMarkerAgeMs(stateDir, now) {
|
|
|
83458
84126
|
return null;
|
|
83459
84127
|
}
|
|
83460
84128
|
}
|
|
84129
|
+
function effectiveTurnAgeMs(markerAgeMs, turnStartedAt, now) {
|
|
84130
|
+
return markerAgeMs ?? now - turnStartedAt;
|
|
84131
|
+
}
|
|
83461
84132
|
|
|
83462
84133
|
// ../src/build-info.ts
|
|
83463
|
-
var VERSION = "0.18.
|
|
83464
|
-
var COMMIT_SHA = "
|
|
83465
|
-
var COMMIT_DATE = "2026-07-
|
|
83466
|
-
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;
|
|
83467
84138
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
83468
84139
|
|
|
83469
84140
|
// gateway/boot-version.ts
|
|
@@ -86143,9 +86814,43 @@ var FEED_LIVENESS_OPEN_MS = (() => {
|
|
|
86143
86814
|
var POST_ANSWER_LIVENESS_STALE_MS = parsePostAnswerLivenessMs(process.env.SWITCHROOM_POST_ANSWER_LIVENESS_STALE_MS) || 30000;
|
|
86144
86815
|
function turnInFlightForGate() {
|
|
86145
86816
|
const hasPendingApproval = pendingPermissions.size > 0;
|
|
86817
|
+
return turnInFlightMachineOnly() || hasPendingApproval;
|
|
86818
|
+
}
|
|
86819
|
+
function turnInFlightMachineOnly() {
|
|
86146
86820
|
if (!isDeliveryCutoverEnabled())
|
|
86147
|
-
return claudeBusyKeys.size > 0
|
|
86148
|
-
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 };
|
|
86149
86854
|
}
|
|
86150
86855
|
function deliverResumeSyntheticOrBuffer(agent, inbound) {
|
|
86151
86856
|
const decision = decideInboundDelivery({
|
|
@@ -86313,11 +87018,6 @@ function findTurnByQuotedMessageId(chatId, replyTo) {
|
|
|
86313
87018
|
return null;
|
|
86314
87019
|
return turn;
|
|
86315
87020
|
}
|
|
86316
|
-
function deriveTurnId(chatId, threadId, messageId) {
|
|
86317
|
-
if (messageId == null || messageId === "" || String(messageId) === "0")
|
|
86318
|
-
return null;
|
|
86319
|
-
return `${chatKey2(chatId, threadId ?? null)}#${messageId}`;
|
|
86320
|
-
}
|
|
86321
87021
|
function findTurnByOriginId(originTurnId) {
|
|
86322
87022
|
if (originTurnId == null || originTurnId === "")
|
|
86323
87023
|
return null;
|
|
@@ -88143,8 +88843,8 @@ var pendingStateReaper = setInterval(() => {
|
|
|
88143
88843
|
try {
|
|
88144
88844
|
sweepStaleTurnActiveMarker(STATE_DIR, {
|
|
88145
88845
|
turnInFlight: currentTurn?.registryKey != null,
|
|
88146
|
-
idleSweepMs:
|
|
88147
|
-
hardTtlMs:
|
|
88846
|
+
idleSweepMs: TURN_ACTIVE_IDLE_SWEEP_MS,
|
|
88847
|
+
hardTtlMs: TURN_ACTIVE_HARD_TTL_MS2,
|
|
88148
88848
|
now,
|
|
88149
88849
|
onRemove: ({ ageMs, reason, payload }) => {
|
|
88150
88850
|
const agent = getMyAgentName();
|
|
@@ -88591,11 +89291,16 @@ async function runMidSessionCardReaper() {
|
|
|
88591
89291
|
isLive: (record2) => topicKeys.has(record2.turnKey),
|
|
88592
89292
|
ttlMs: MID_SESSION_CARD_REAPER_TTL_MS,
|
|
88593
89293
|
now,
|
|
88594
|
-
finalizeCard: (record2) =>
|
|
88595
|
-
|
|
88596
|
-
|
|
88597
|
-
|
|
88598
|
-
|
|
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
|
+
},
|
|
88599
89304
|
unpinCard: async (record2) => {
|
|
88600
89305
|
const pinKey = `fg:${record2.turnKey}`;
|
|
88601
89306
|
if (statusPinState.has(pinKey)) {
|
|
@@ -89075,6 +89780,8 @@ var _deliveryMachineTick = setInterval(() => {
|
|
|
89075
89780
|
}, DELIVERY_MACHINE_TICK_MS);
|
|
89076
89781
|
_deliveryMachineTick.unref?.();
|
|
89077
89782
|
function trackRedeliveredInbound(merged) {
|
|
89783
|
+
if (HANDBACK_PRETURN_ENABLED)
|
|
89784
|
+
handbackPreturnSignal.noteHandbackRelease(merged);
|
|
89078
89785
|
if (!DELIVERY_CONFIRM_ENABLED)
|
|
89079
89786
|
return;
|
|
89080
89787
|
const isTrackableResume = isTrackableResumeSynthetic(merged.meta);
|
|
@@ -90754,6 +91461,7 @@ async function executeReply(args) {
|
|
|
90754
91461
|
return { content: [{ type: "text", text: "sent (deduped \u2014 same content sent via earlier path)" }] };
|
|
90755
91462
|
}
|
|
90756
91463
|
}
|
|
91464
|
+
let supersedeFlushIds = [];
|
|
90757
91465
|
{
|
|
90758
91466
|
const replyThreadId = args.message_thread_id != null ? Number(args.message_thread_id) : undefined;
|
|
90759
91467
|
const ownerTurn = resolveReplyOwnerTurn(turn, chat_id, args);
|
|
@@ -90762,9 +91470,9 @@ async function executeReply(args) {
|
|
|
90762
91470
|
if (decision.supersede) {
|
|
90763
91471
|
process.stderr.write(`telegram gateway: reply: superseding flushed turn message(s) chatId=${chat_id} ids=${JSON.stringify(decision.deleteMessageIds)}
|
|
90764
91472
|
`);
|
|
90765
|
-
|
|
90766
|
-
|
|
90767
|
-
|
|
91473
|
+
supersedeFlushIds = decision.deleteMessageIds;
|
|
91474
|
+
if (ownerTurn != null)
|
|
91475
|
+
ownerTurn.answerDelivered = true;
|
|
90768
91476
|
} else {
|
|
90769
91477
|
const replySubstantive = isSubstantiveFinalReply({
|
|
90770
91478
|
text: rawText,
|
|
@@ -90992,6 +91700,25 @@ ${url}`;
|
|
|
90992
91700
|
});
|
|
90993
91701
|
}
|
|
90994
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
|
+
}
|
|
90995
91722
|
if (previewMessageId != null && reply_to != null && replyMode !== "off") {
|
|
90996
91723
|
await deleteStalePreview(previewMessageId);
|
|
90997
91724
|
previewMessageId = null;
|
|
@@ -91000,7 +91727,7 @@ ${url}`;
|
|
|
91000
91727
|
let silentAnchorEditDone = false;
|
|
91001
91728
|
{
|
|
91002
91729
|
const turn2 = currentTurn;
|
|
91003
|
-
if (turn2 != null && chunks.length === 1) {
|
|
91730
|
+
if (turn2 != null && chunks.length === 1 && supersedeFlushIds.length === 0) {
|
|
91004
91731
|
const decision = decideSilentReplyAnchor({
|
|
91005
91732
|
effectivelySilent: disableNotification,
|
|
91006
91733
|
anchorMessageId: turn2.silentAnchorMessageId,
|
|
@@ -92815,6 +93542,61 @@ function clearActivitySummary(turn, finalHtmlOverride) {
|
|
|
92815
93542
|
}
|
|
92816
93543
|
});
|
|
92817
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
|
+
});
|
|
92818
93600
|
var memoryLegibilityStager = new MemoryLegibilityStager;
|
|
92819
93601
|
function sendMemoryLegibilityLine(event, chatId, threadId) {
|
|
92820
93602
|
const line = renderMemoryLegibilityLine(event);
|
|
@@ -92968,6 +93750,16 @@ function handleSessionEvent(ev) {
|
|
|
92968
93750
|
emissionAuthority: new EmissionAuthority(statusKey(ev.chatId, enqThreadIdNum))
|
|
92969
93751
|
};
|
|
92970
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
|
+
}
|
|
92971
93763
|
setCurrentTurn(next, statusKey(ev.chatId, enqThreadIdNum));
|
|
92972
93764
|
scheduleEarlyLivenessOpen(next);
|
|
92973
93765
|
process.stderr.write(`telegram gateway: ${formatTurnLifecycle("set", "enqueue", next, startedAt)}
|
|
@@ -96014,7 +96806,8 @@ bot.command("model", async (ctx) => {
|
|
|
96014
96806
|
const parsed = parseModelCommand(text5) ?? { kind: "show" };
|
|
96015
96807
|
const chatId = String(ctx.chat.id);
|
|
96016
96808
|
const threadId = resolveThreadId(chatId, ctx.message?.message_thread_id);
|
|
96017
|
-
const
|
|
96809
|
+
const modelBusy = resolveModelEffortBusy();
|
|
96810
|
+
const busyNow = modelBusy.currentTurnActive || modelBusy.turnInFlight;
|
|
96018
96811
|
process.stderr.write(modelCommandReceiptLine(getMyAgentName(), parsed, busyNow) + `
|
|
96019
96812
|
`);
|
|
96020
96813
|
if (HISTORY_ENABLED && ctx.message?.message_id != null) {
|
|
@@ -96035,8 +96828,8 @@ bot.command("model", async (ctx) => {
|
|
|
96035
96828
|
}
|
|
96036
96829
|
const deps = buildModelDeps({ chatId, threadId });
|
|
96037
96830
|
const disposition = planModelCommand(parsed, {
|
|
96038
|
-
currentTurnActive:
|
|
96039
|
-
turnInFlight:
|
|
96831
|
+
currentTurnActive: modelBusy.currentTurnActive,
|
|
96832
|
+
turnInFlight: modelBusy.turnInFlight,
|
|
96040
96833
|
menuEnabled: process.env.SWITCHROOM_MODEL_MENU !== "0"
|
|
96041
96834
|
});
|
|
96042
96835
|
if (disposition.kind === "menu") {
|
|
@@ -96107,7 +96900,8 @@ bot.command("effort", async (ctx) => {
|
|
|
96107
96900
|
await switchroomReply(ctx, menu.text, { html: true, reply_markup: effortMenuReplyMarkup(menu) });
|
|
96108
96901
|
return;
|
|
96109
96902
|
}
|
|
96110
|
-
|
|
96903
|
+
const effortBusy = resolveModelEffortBusy();
|
|
96904
|
+
if ((parsed.kind === "set" || parsed.kind === "default") && effortBusy.currentTurnActive) {
|
|
96111
96905
|
const requestedLevel = parsed.kind === "set" ? parsed.level : "default";
|
|
96112
96906
|
const chatId = String(ctx.chat.id);
|
|
96113
96907
|
const threadId = resolveThreadId(chatId, ctx.message?.message_thread_id);
|