switchroom 0.19.44 → 0.19.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/switchroom.js +848 -826
- package/dist/host-control/main.js +1 -1
- package/package.json +1 -1
- package/profiles/_base/start.sh.hbs +48 -4
- package/telegram-plugin/dist/gateway/gateway.js +499 -322
- package/telegram-plugin/flushed-turn-supersede.ts +190 -16
- package/telegram-plugin/gateway/auth-command.ts +7 -4
- package/telegram-plugin/gateway/auth-loopback-relay.ts +39 -20
- package/telegram-plugin/gateway/cron-session.ts +31 -0
- package/telegram-plugin/gateway/gateway.ts +67 -66
- package/telegram-plugin/gateway/outbound-send-path.ts +60 -8
- package/telegram-plugin/gateway/reply-owner-wiring.ts +128 -0
- package/telegram-plugin/gateway/stream-render.ts +91 -1
- package/telegram-plugin/gateway/subagent-handback-marker.ts +49 -9
- package/telegram-plugin/gateway/subagent-reply-authority.ts +147 -0
- package/telegram-plugin/gateway/turn-end.ts +9 -1
- package/telegram-plugin/reply-owner-resolve.ts +102 -26
- package/telegram-plugin/tests/auth-loopback-relay.test.ts +58 -0
- package/telegram-plugin/tests/flushed-turn-supersede.test.ts +110 -8
- package/telegram-plugin/tests/narrative-lane-golden.test.ts +2 -0
- package/telegram-plugin/tests/reply-owner-resolve.test.ts +297 -27
- package/telegram-plugin/tests/reply-quote-wire.test.ts +2 -0
- package/telegram-plugin/tests/send-reply-golden.test.ts +567 -5
- package/telegram-plugin/tests/stream-render-golden.test.ts +204 -1
|
@@ -41869,7 +41869,8 @@ function normalizeForDedup(text) {
|
|
|
41869
41869
|
}
|
|
41870
41870
|
|
|
41871
41871
|
// flushed-turn-supersede.ts
|
|
41872
|
-
var
|
|
41872
|
+
var SUPERSEDE_OPEN_WINDOW_CAP_MS = 30 * 60000;
|
|
41873
|
+
var SUPERSEDE_COMPLETED_GRACE_MS = 60000;
|
|
41873
41874
|
var SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS = 32;
|
|
41874
41875
|
function normalizeForMatch(text) {
|
|
41875
41876
|
return text.replace(/\s+/g, " ").trim();
|
|
@@ -41888,10 +41889,12 @@ function flushedAnswerMatchesReply(flushedText, replyText) {
|
|
|
41888
41889
|
return false;
|
|
41889
41890
|
}
|
|
41890
41891
|
function decideSupersede(record, args) {
|
|
41891
|
-
const
|
|
41892
|
+
const openCapMs = args.openCapMs ?? SUPERSEDE_OPEN_WINDOW_CAP_MS;
|
|
41893
|
+
const completedGraceMs = args.completedGraceMs ?? SUPERSEDE_COMPLETED_GRACE_MS;
|
|
41892
41894
|
if (record == null)
|
|
41893
41895
|
return { supersede: false, deleteMessageIds: [], reason: "no-record" };
|
|
41894
|
-
|
|
41896
|
+
const expired = record.completedAt == null ? args.now - record.ts > openCapMs : args.now - record.completedAt > completedGraceMs;
|
|
41897
|
+
if (expired) {
|
|
41895
41898
|
return { supersede: false, deleteMessageIds: [], reason: "expired" };
|
|
41896
41899
|
}
|
|
41897
41900
|
const sameTurn = record.turnId != null ? record.turnId === args.liveTurnId : args.liveTurnId == null;
|
|
@@ -41915,9 +41918,11 @@ function turnKey(turnId) {
|
|
|
41915
41918
|
|
|
41916
41919
|
class FlushedTurnSupersedeRegistry {
|
|
41917
41920
|
entries = new Map;
|
|
41918
|
-
|
|
41921
|
+
openCapMs;
|
|
41922
|
+
completedGraceMs;
|
|
41919
41923
|
constructor(opts = {}) {
|
|
41920
|
-
this.
|
|
41924
|
+
this.openCapMs = opts.openCapMs ?? SUPERSEDE_OPEN_WINDOW_CAP_MS;
|
|
41925
|
+
this.completedGraceMs = opts.completedGraceMs ?? SUPERSEDE_COMPLETED_GRACE_MS;
|
|
41921
41926
|
}
|
|
41922
41927
|
record(chatId, threadId, rec, now) {
|
|
41923
41928
|
if (rec.messageIds.length === 0)
|
|
@@ -41933,9 +41938,18 @@ class FlushedTurnSupersedeRegistry {
|
|
|
41933
41938
|
turnId: rec.turnId,
|
|
41934
41939
|
messageIds: [...rec.messageIds],
|
|
41935
41940
|
text: rec.text,
|
|
41936
|
-
ts: now
|
|
41941
|
+
ts: now,
|
|
41942
|
+
completedAt: rec.completedAt ?? null
|
|
41937
41943
|
});
|
|
41938
41944
|
}
|
|
41945
|
+
completeAll(now) {
|
|
41946
|
+
for (const laneMap of this.entries.values()) {
|
|
41947
|
+
for (const rec of laneMap.values()) {
|
|
41948
|
+
if (rec.completedAt == null)
|
|
41949
|
+
rec.completedAt = now;
|
|
41950
|
+
}
|
|
41951
|
+
}
|
|
41952
|
+
}
|
|
41939
41953
|
peek(chatId, threadId, args) {
|
|
41940
41954
|
const rec = this.entries.get(makeKey2(chatId, threadId))?.get(turnKey(args.liveTurnId));
|
|
41941
41955
|
return decideSupersede(rec, {
|
|
@@ -41943,7 +41957,8 @@ class FlushedTurnSupersedeRegistry {
|
|
|
41943
41957
|
replyText: args.replyText,
|
|
41944
41958
|
positiveAttribution: args.positiveAttribution,
|
|
41945
41959
|
now: args.now,
|
|
41946
|
-
|
|
41960
|
+
openCapMs: this.openCapMs,
|
|
41961
|
+
completedGraceMs: this.completedGraceMs
|
|
41947
41962
|
});
|
|
41948
41963
|
}
|
|
41949
41964
|
take(chatId, threadId, args) {
|
|
@@ -41966,7 +41981,8 @@ class FlushedTurnSupersedeRegistry {
|
|
|
41966
41981
|
sweep(now) {
|
|
41967
41982
|
for (const [lane, laneMap] of this.entries) {
|
|
41968
41983
|
for (const [tk, rec] of laneMap) {
|
|
41969
|
-
|
|
41984
|
+
const expired = rec.completedAt == null ? now - rec.ts > this.openCapMs : now - rec.completedAt > this.completedGraceMs;
|
|
41985
|
+
if (expired)
|
|
41970
41986
|
laneMap.delete(tk);
|
|
41971
41987
|
}
|
|
41972
41988
|
if (laneMap.size === 0)
|
|
@@ -41985,6 +42001,302 @@ function makeKey2(chatId, threadId) {
|
|
|
41985
42001
|
return threadId == null ? chatId : `${chatId}|${threadId}`;
|
|
41986
42002
|
}
|
|
41987
42003
|
|
|
42004
|
+
// flushed-turn-supersede.ts
|
|
42005
|
+
var SUPERSEDE_OPEN_WINDOW_CAP_MS2 = 30 * 60000;
|
|
42006
|
+
var SUPERSEDE_COMPLETED_GRACE_MS2 = 60000;
|
|
42007
|
+
var SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 = 32;
|
|
42008
|
+
function normalizeForMatch2(text) {
|
|
42009
|
+
return text.replace(/\s+/g, " ").trim();
|
|
42010
|
+
}
|
|
42011
|
+
function flushedAnswerMatchesReply2(flushedText, replyText) {
|
|
42012
|
+
const flushed = normalizeForMatch2(flushedText);
|
|
42013
|
+
const reply = normalizeForMatch2(replyText);
|
|
42014
|
+
if (flushed.length === 0 || reply.length === 0)
|
|
42015
|
+
return false;
|
|
42016
|
+
if (flushed === reply)
|
|
42017
|
+
return true;
|
|
42018
|
+
if (reply.length >= SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 && flushed.includes(reply))
|
|
42019
|
+
return true;
|
|
42020
|
+
if (flushed.length >= SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 && reply.includes(flushed))
|
|
42021
|
+
return true;
|
|
42022
|
+
return false;
|
|
42023
|
+
}
|
|
42024
|
+
function decideSupersede2(record, args) {
|
|
42025
|
+
const openCapMs = args.openCapMs ?? SUPERSEDE_OPEN_WINDOW_CAP_MS2;
|
|
42026
|
+
const completedGraceMs = args.completedGraceMs ?? SUPERSEDE_COMPLETED_GRACE_MS2;
|
|
42027
|
+
if (record == null)
|
|
42028
|
+
return { supersede: false, deleteMessageIds: [], reason: "no-record" };
|
|
42029
|
+
const expired = record.completedAt == null ? args.now - record.ts > openCapMs : args.now - record.completedAt > completedGraceMs;
|
|
42030
|
+
if (expired) {
|
|
42031
|
+
return { supersede: false, deleteMessageIds: [], reason: "expired" };
|
|
42032
|
+
}
|
|
42033
|
+
const sameTurn = record.turnId != null ? record.turnId === args.liveTurnId : args.liveTurnId == null;
|
|
42034
|
+
if (!sameTurn) {
|
|
42035
|
+
return { supersede: false, deleteMessageIds: [], reason: "different-turn" };
|
|
42036
|
+
}
|
|
42037
|
+
if (!args.positiveAttribution && args.replyText != null && !flushedAnswerMatchesReply2(record.text, args.replyText)) {
|
|
42038
|
+
return { supersede: false, deleteMessageIds: [], reason: "new-content", recordText: record.text };
|
|
42039
|
+
}
|
|
42040
|
+
return {
|
|
42041
|
+
supersede: true,
|
|
42042
|
+
deleteMessageIds: [...record.messageIds],
|
|
42043
|
+
reason: "supersede",
|
|
42044
|
+
recordText: record.text
|
|
42045
|
+
};
|
|
42046
|
+
}
|
|
42047
|
+
function decideSupersedeCorrection(input) {
|
|
42048
|
+
const eligible = input.flushMessageIds.length === 1 && input.chunkCount === 1 && !input.hasFiles && !input.suppressText && !input.hasOpenPreview;
|
|
42049
|
+
if (eligible) {
|
|
42050
|
+
return { mode: "edit-in-place", editMessageId: input.flushMessageIds[0], deleteMessageIds: [] };
|
|
42051
|
+
}
|
|
42052
|
+
return { mode: "delete-resend", deleteMessageIds: [...input.flushMessageIds] };
|
|
42053
|
+
}
|
|
42054
|
+
var NULL_TURN_KEY2 = "<<null-turn>>";
|
|
42055
|
+
function turnKey2(turnId) {
|
|
42056
|
+
return turnId == null ? NULL_TURN_KEY2 : turnId;
|
|
42057
|
+
}
|
|
42058
|
+
|
|
42059
|
+
class FlushedTurnSupersedeRegistry2 {
|
|
42060
|
+
entries = new Map;
|
|
42061
|
+
openCapMs;
|
|
42062
|
+
completedGraceMs;
|
|
42063
|
+
constructor(opts = {}) {
|
|
42064
|
+
this.openCapMs = opts.openCapMs ?? SUPERSEDE_OPEN_WINDOW_CAP_MS2;
|
|
42065
|
+
this.completedGraceMs = opts.completedGraceMs ?? SUPERSEDE_COMPLETED_GRACE_MS2;
|
|
42066
|
+
}
|
|
42067
|
+
record(chatId, threadId, rec, now) {
|
|
42068
|
+
if (rec.messageIds.length === 0)
|
|
42069
|
+
return;
|
|
42070
|
+
this.sweep(now);
|
|
42071
|
+
const lane = makeKey3(chatId, threadId);
|
|
42072
|
+
let laneMap = this.entries.get(lane);
|
|
42073
|
+
if (laneMap == null) {
|
|
42074
|
+
laneMap = new Map;
|
|
42075
|
+
this.entries.set(lane, laneMap);
|
|
42076
|
+
}
|
|
42077
|
+
laneMap.set(turnKey2(rec.turnId), {
|
|
42078
|
+
turnId: rec.turnId,
|
|
42079
|
+
messageIds: [...rec.messageIds],
|
|
42080
|
+
text: rec.text,
|
|
42081
|
+
ts: now,
|
|
42082
|
+
completedAt: rec.completedAt ?? null
|
|
42083
|
+
});
|
|
42084
|
+
}
|
|
42085
|
+
completeAll(now) {
|
|
42086
|
+
for (const laneMap of this.entries.values()) {
|
|
42087
|
+
for (const rec of laneMap.values()) {
|
|
42088
|
+
if (rec.completedAt == null)
|
|
42089
|
+
rec.completedAt = now;
|
|
42090
|
+
}
|
|
42091
|
+
}
|
|
42092
|
+
}
|
|
42093
|
+
peek(chatId, threadId, args) {
|
|
42094
|
+
const rec = this.entries.get(makeKey3(chatId, threadId))?.get(turnKey2(args.liveTurnId));
|
|
42095
|
+
return decideSupersede2(rec, {
|
|
42096
|
+
liveTurnId: args.liveTurnId,
|
|
42097
|
+
replyText: args.replyText,
|
|
42098
|
+
positiveAttribution: args.positiveAttribution,
|
|
42099
|
+
now: args.now,
|
|
42100
|
+
openCapMs: this.openCapMs,
|
|
42101
|
+
completedGraceMs: this.completedGraceMs
|
|
42102
|
+
});
|
|
42103
|
+
}
|
|
42104
|
+
take(chatId, threadId, args) {
|
|
42105
|
+
const lane = makeKey3(chatId, threadId);
|
|
42106
|
+
const decision = this.peek(chatId, threadId, args);
|
|
42107
|
+
if (decision.supersede) {
|
|
42108
|
+
const laneMap = this.entries.get(lane);
|
|
42109
|
+
laneMap?.delete(turnKey2(args.liveTurnId));
|
|
42110
|
+
if (laneMap != null && laneMap.size === 0)
|
|
42111
|
+
this.entries.delete(lane);
|
|
42112
|
+
}
|
|
42113
|
+
return decision;
|
|
42114
|
+
}
|
|
42115
|
+
forget(chatId, threadId) {
|
|
42116
|
+
this.entries.delete(makeKey3(chatId, threadId));
|
|
42117
|
+
}
|
|
42118
|
+
clear() {
|
|
42119
|
+
this.entries.clear();
|
|
42120
|
+
}
|
|
42121
|
+
sweep(now) {
|
|
42122
|
+
for (const [lane, laneMap] of this.entries) {
|
|
42123
|
+
for (const [tk, rec] of laneMap) {
|
|
42124
|
+
const expired = rec.completedAt == null ? now - rec.ts > this.openCapMs : now - rec.completedAt > this.completedGraceMs;
|
|
42125
|
+
if (expired)
|
|
42126
|
+
laneMap.delete(tk);
|
|
42127
|
+
}
|
|
42128
|
+
if (laneMap.size === 0)
|
|
42129
|
+
this.entries.delete(lane);
|
|
42130
|
+
}
|
|
42131
|
+
}
|
|
42132
|
+
size(now) {
|
|
42133
|
+
this.sweep(now);
|
|
42134
|
+
let total = 0;
|
|
42135
|
+
for (const laneMap of this.entries.values())
|
|
42136
|
+
total += laneMap.size;
|
|
42137
|
+
return total;
|
|
42138
|
+
}
|
|
42139
|
+
}
|
|
42140
|
+
function makeKey3(chatId, threadId) {
|
|
42141
|
+
return threadId == null ? chatId : `${chatId}|${threadId}`;
|
|
42142
|
+
}
|
|
42143
|
+
|
|
42144
|
+
class FlushCompletionTracker {
|
|
42145
|
+
pending = [];
|
|
42146
|
+
open(turn) {
|
|
42147
|
+
turn.realEndObservedAt = null;
|
|
42148
|
+
if (!this.pending.includes(turn))
|
|
42149
|
+
this.pending.push(turn);
|
|
42150
|
+
}
|
|
42151
|
+
closeAll(now) {
|
|
42152
|
+
let closed = 0;
|
|
42153
|
+
for (const turn of this.pending) {
|
|
42154
|
+
if (turn.realEndObservedAt == null) {
|
|
42155
|
+
turn.realEndObservedAt = now;
|
|
42156
|
+
closed++;
|
|
42157
|
+
}
|
|
42158
|
+
}
|
|
42159
|
+
this.pending = [];
|
|
42160
|
+
return closed;
|
|
42161
|
+
}
|
|
42162
|
+
pendingCount() {
|
|
42163
|
+
return this.pending.length;
|
|
42164
|
+
}
|
|
42165
|
+
}
|
|
42166
|
+
|
|
42167
|
+
// reply-owner-resolve.ts
|
|
42168
|
+
function latestEndedAccepted(candidates) {
|
|
42169
|
+
if (candidates.latestEndedTurnId == null)
|
|
42170
|
+
return false;
|
|
42171
|
+
const age = candidates.latestEndedAgeMs;
|
|
42172
|
+
const ttl = candidates.latestEndedTtlMs;
|
|
42173
|
+
if (age == null || ttl == null)
|
|
42174
|
+
return false;
|
|
42175
|
+
const realEndAge = candidates.latestEndedRealEndAgeMs;
|
|
42176
|
+
if (realEndAge === undefined || realEndAge === null) {
|
|
42177
|
+
return age <= ttl;
|
|
42178
|
+
}
|
|
42179
|
+
const grace = candidates.latestEndedCompletedGraceMs ?? SUPERSEDE_COMPLETED_GRACE_MS2;
|
|
42180
|
+
return realEndAge <= grace;
|
|
42181
|
+
}
|
|
42182
|
+
function resolveReplyOwnerTier(candidates) {
|
|
42183
|
+
if (candidates.liveTurnId != null)
|
|
42184
|
+
return "live";
|
|
42185
|
+
if (candidates.originTurnId != null)
|
|
42186
|
+
return "origin";
|
|
42187
|
+
if (candidates.quotedTurnId != null)
|
|
42188
|
+
return "quoted";
|
|
42189
|
+
if (latestEndedAccepted(candidates))
|
|
42190
|
+
return "latest-ended";
|
|
42191
|
+
return "none";
|
|
42192
|
+
}
|
|
42193
|
+
function resolveReplyOwnerTurnId(candidates) {
|
|
42194
|
+
switch (resolveReplyOwnerTier(candidates)) {
|
|
42195
|
+
case "live":
|
|
42196
|
+
return candidates.liveTurnId;
|
|
42197
|
+
case "origin":
|
|
42198
|
+
return candidates.originTurnId;
|
|
42199
|
+
case "quoted":
|
|
42200
|
+
return candidates.quotedTurnId;
|
|
42201
|
+
case "latest-ended":
|
|
42202
|
+
return candidates.latestEndedTurnId;
|
|
42203
|
+
case "none":
|
|
42204
|
+
return null;
|
|
42205
|
+
}
|
|
42206
|
+
}
|
|
42207
|
+
function decideContentGateBypass(input) {
|
|
42208
|
+
if (input.tier === "live")
|
|
42209
|
+
return true;
|
|
42210
|
+
if (input.tier === "none")
|
|
42211
|
+
return false;
|
|
42212
|
+
if (input.handbackCouldOwnReply)
|
|
42213
|
+
return false;
|
|
42214
|
+
if (input.subagentCouldOwnReply !== false)
|
|
42215
|
+
return false;
|
|
42216
|
+
if (input.candidates == null)
|
|
42217
|
+
return false;
|
|
42218
|
+
if (!latestEndedAccepted(input.candidates))
|
|
42219
|
+
return false;
|
|
42220
|
+
return input.resolvedTurnId != null && input.resolvedTurnId === input.candidates.latestEndedTurnId;
|
|
42221
|
+
}
|
|
42222
|
+
function decideAnswerLatchSuppression(input) {
|
|
42223
|
+
if (input.superseded)
|
|
42224
|
+
return false;
|
|
42225
|
+
if (!input.replySubstantive)
|
|
42226
|
+
return false;
|
|
42227
|
+
if (!input.isLateReply)
|
|
42228
|
+
return false;
|
|
42229
|
+
if (input.replyMatchesFlushedAnswer === false)
|
|
42230
|
+
return false;
|
|
42231
|
+
return input.ownerAnswerDelivered === "flush";
|
|
42232
|
+
}
|
|
42233
|
+
|
|
42234
|
+
// gateway/reply-owner-wiring.ts
|
|
42235
|
+
var SUPERSEDE_OPEN_CAP_MS = (() => {
|
|
42236
|
+
const raw = Number(process.env.SWITCHROOM_SUPERSEDE_OPEN_CAP_MS);
|
|
42237
|
+
return Number.isFinite(raw) && raw > 0 ? raw : SUPERSEDE_OPEN_WINDOW_CAP_MS2;
|
|
42238
|
+
})();
|
|
42239
|
+
var SUPERSEDE_GRACE_MS = (() => {
|
|
42240
|
+
const raw = Number(process.env.SWITCHROOM_SUPERSEDE_GRACE_MS);
|
|
42241
|
+
return Number.isFinite(raw) && raw > 0 ? raw : SUPERSEDE_COMPLETED_GRACE_MS2;
|
|
42242
|
+
})();
|
|
42243
|
+
function resolveReplyOwnerTurnWith(lookups, liveTurn, chatId, args) {
|
|
42244
|
+
const origin = lookups.findTurnByOriginId(args.origin_turn_id);
|
|
42245
|
+
const quoted = lookups.findTurnByQuotedMessageId(chatId, args.reply_to);
|
|
42246
|
+
const latestEnded = lookups.findLatestTurnForChat(chatId, { endedOnly: true });
|
|
42247
|
+
const byId = new Map;
|
|
42248
|
+
for (const t of [latestEnded, quoted, origin, liveTurn]) {
|
|
42249
|
+
if (t != null)
|
|
42250
|
+
byId.set(t.turnId, t);
|
|
42251
|
+
}
|
|
42252
|
+
const latestEndedAgeMs = latestEnded?.endedAt != null ? lookups.now() - latestEnded.endedAt : null;
|
|
42253
|
+
const latestEndedRealEndAgeMs = latestEnded == null ? null : latestEnded.realEndObservedAt != null ? lookups.now() - latestEnded.realEndObservedAt : null;
|
|
42254
|
+
const candidates = {
|
|
42255
|
+
liveTurnId: liveTurn?.turnId ?? null,
|
|
42256
|
+
originTurnId: origin?.turnId ?? null,
|
|
42257
|
+
quotedTurnId: quoted?.turnId ?? null,
|
|
42258
|
+
latestEndedTurnId: latestEnded?.turnId ?? null,
|
|
42259
|
+
latestEndedAgeMs,
|
|
42260
|
+
latestEndedTtlMs: SUPERSEDE_OPEN_CAP_MS,
|
|
42261
|
+
latestEndedRealEndAgeMs,
|
|
42262
|
+
latestEndedCompletedGraceMs: SUPERSEDE_GRACE_MS
|
|
42263
|
+
};
|
|
42264
|
+
const tier = resolveReplyOwnerTier(candidates);
|
|
42265
|
+
const winnerId = resolveReplyOwnerTurnId(candidates);
|
|
42266
|
+
return { turn: winnerId != null ? byId.get(winnerId) ?? null : null, tier, candidates };
|
|
42267
|
+
}
|
|
42268
|
+
|
|
42269
|
+
// gateway/subagent-reply-authority.ts
|
|
42270
|
+
var SUB_AGENT_KIND_PREFIX = "sub_agent_";
|
|
42271
|
+
|
|
42272
|
+
class SubagentReplyAuthority {
|
|
42273
|
+
live = new Set;
|
|
42274
|
+
noteSessionEvent(ev) {
|
|
42275
|
+
if (ev == null)
|
|
42276
|
+
return;
|
|
42277
|
+
const kind = ev.kind;
|
|
42278
|
+
if (typeof kind !== "string" || !kind.startsWith(SUB_AGENT_KIND_PREFIX))
|
|
42279
|
+
return;
|
|
42280
|
+
const agentId = ev.agentId;
|
|
42281
|
+
if (typeof agentId !== "string" || agentId === "")
|
|
42282
|
+
return;
|
|
42283
|
+
if (kind === `${SUB_AGENT_KIND_PREFIX}turn_end`)
|
|
42284
|
+
this.live.delete(agentId);
|
|
42285
|
+
else
|
|
42286
|
+
this.live.add(agentId);
|
|
42287
|
+
}
|
|
42288
|
+
subagentCouldOwnReply() {
|
|
42289
|
+
return this.live.size > 0;
|
|
42290
|
+
}
|
|
42291
|
+
reset() {
|
|
42292
|
+
this.live.clear();
|
|
42293
|
+
}
|
|
42294
|
+
liveCount() {
|
|
42295
|
+
return this.live.size;
|
|
42296
|
+
}
|
|
42297
|
+
}
|
|
42298
|
+
var subagentReplyAuthority = new SubagentReplyAuthority;
|
|
42299
|
+
|
|
41988
42300
|
// gateway/inbound-coalesce.ts
|
|
41989
42301
|
function createInboundCoalescer(opts) {
|
|
41990
42302
|
const buffer = new Map;
|
|
@@ -53954,11 +54266,11 @@ function createHandbackPreturnSignal(deps) {
|
|
|
53954
54266
|
}
|
|
53955
54267
|
return false;
|
|
53956
54268
|
},
|
|
53957
|
-
isPreTurnRecord(
|
|
53958
|
-
return
|
|
54269
|
+
isPreTurnRecord(turnKey3) {
|
|
54270
|
+
return turnKey3.startsWith(PRETURN_TURNKEY_PREFIX);
|
|
53959
54271
|
},
|
|
53960
|
-
handleReaped(
|
|
53961
|
-
const statusKey = bySyntheticKey.get(
|
|
54272
|
+
handleReaped(turnKey3) {
|
|
54273
|
+
const statusKey = bySyntheticKey.get(turnKey3);
|
|
53962
54274
|
if (statusKey == null)
|
|
53963
54275
|
return;
|
|
53964
54276
|
const entry = byKey.get(statusKey);
|
|
@@ -71288,16 +71600,16 @@ function writeSilentEndState(args, deps) {
|
|
|
71288
71600
|
`);
|
|
71289
71601
|
}
|
|
71290
71602
|
}
|
|
71291
|
-
function clearSilentEndState(
|
|
71603
|
+
function clearSilentEndState(turnKey3, deps) {
|
|
71292
71604
|
const statePath = resolveStatePath2(deps);
|
|
71293
71605
|
if (!existsSync16(statePath))
|
|
71294
71606
|
return;
|
|
71295
71607
|
try {
|
|
71296
71608
|
const prev = JSON.parse(readFileSync18(statePath, "utf8"));
|
|
71297
|
-
if (prev.turnKey != null && prev.turnKey !==
|
|
71609
|
+
if (prev.turnKey != null && prev.turnKey !== turnKey3)
|
|
71298
71610
|
return;
|
|
71299
71611
|
unlinkSync12(statePath);
|
|
71300
|
-
emitLog(deps, `silent-end: cleared state file turnKey=${
|
|
71612
|
+
emitLog(deps, `silent-end: cleared state file turnKey=${turnKey3}
|
|
71301
71613
|
`);
|
|
71302
71614
|
} catch {}
|
|
71303
71615
|
}
|
|
@@ -72469,7 +72781,7 @@ function parseProviderVerb(provider, rest) {
|
|
|
72469
72781
|
return { kind: "provider-cancel", provider };
|
|
72470
72782
|
}
|
|
72471
72783
|
if (sub !== "add") {
|
|
72472
|
-
const usage = provider === "google" ? "Usage: /auth google add <email> [--replace] [--write]" : "Usage: /auth microsoft add <email> [--replace] [--org-mode]";
|
|
72784
|
+
const usage = provider === "google" ? "Usage: /auth google add <email> [--replace] [--write] [--calendar]" : "Usage: /auth microsoft add <email> [--replace] [--org-mode]";
|
|
72473
72785
|
return {
|
|
72474
72786
|
kind: "help",
|
|
72475
72787
|
reason: `Unknown \`${provider}\` subcommand: \`${codeSpanSafe(sub || "(none)")}\`. ${usage}`
|
|
@@ -72480,13 +72792,13 @@ function parseProviderVerb(provider, rest) {
|
|
|
72480
72792
|
const positional = args.filter((a) => !a.startsWith("--"));
|
|
72481
72793
|
const email = positional[0];
|
|
72482
72794
|
if (!email) {
|
|
72483
|
-
const usage = provider === "google" ? "Usage: /auth google add <email> [--replace] [--write]" : "Usage: /auth microsoft add <email> [--replace] [--org-mode]";
|
|
72795
|
+
const usage = provider === "google" ? "Usage: /auth google add <email> [--replace] [--write] [--calendar]" : "Usage: /auth microsoft add <email> [--replace] [--org-mode]";
|
|
72484
72796
|
return { kind: "help", reason: usage };
|
|
72485
72797
|
}
|
|
72486
72798
|
const emailErr = validateAuthAddLabel(email);
|
|
72487
72799
|
if (emailErr)
|
|
72488
72800
|
return { kind: "help", reason: emailErr };
|
|
72489
|
-
const allowed = provider === "google" ? new Set(["--replace", "--write"]) : new Set(["--replace", "--org-mode"]);
|
|
72801
|
+
const allowed = provider === "google" ? new Set(["--replace", "--write", "--calendar"]) : new Set(["--replace", "--org-mode"]);
|
|
72490
72802
|
for (const f of flags) {
|
|
72491
72803
|
if (!allowed.has(f)) {
|
|
72492
72804
|
return {
|
|
@@ -72501,6 +72813,7 @@ function parseProviderVerb(provider, rest) {
|
|
|
72501
72813
|
email,
|
|
72502
72814
|
replace: flags.has("--replace"),
|
|
72503
72815
|
write: provider === "google" && flags.has("--write"),
|
|
72816
|
+
calendar: provider === "google" && flags.has("--calendar"),
|
|
72504
72817
|
orgMode: provider === "microsoft" && flags.has("--org-mode")
|
|
72505
72818
|
};
|
|
72506
72819
|
}
|
|
@@ -74208,16 +74521,16 @@ ${loginUrl}
|
|
|
74208
74521
|
|
|
74209
74522
|
// gateway/auth-loopback-relay.ts
|
|
74210
74523
|
import { spawn } from "node:child_process";
|
|
74211
|
-
function
|
|
74212
|
-
|
|
74213
|
-
const args = provider === "google" ? [
|
|
74524
|
+
function buildRelayArgs(provider, email, opts) {
|
|
74525
|
+
return provider === "google" ? [
|
|
74214
74526
|
"auth",
|
|
74215
74527
|
"google",
|
|
74216
74528
|
"account",
|
|
74217
74529
|
"add",
|
|
74218
74530
|
email,
|
|
74219
74531
|
...opts.replace ? ["--replace"] : [],
|
|
74220
|
-
...opts.write ? ["--write"] : []
|
|
74532
|
+
...opts.write ? ["--write"] : [],
|
|
74533
|
+
...opts.calendar ? ["--calendar"] : []
|
|
74221
74534
|
] : [
|
|
74222
74535
|
"auth",
|
|
74223
74536
|
"microsoft",
|
|
@@ -74227,6 +74540,10 @@ function defaultSpawnRelay(provider, email, opts) {
|
|
|
74227
74540
|
...opts.replace ? ["--replace"] : [],
|
|
74228
74541
|
...opts.orgMode ? ["--org-mode"] : []
|
|
74229
74542
|
];
|
|
74543
|
+
}
|
|
74544
|
+
function defaultSpawnRelay(provider, email, opts) {
|
|
74545
|
+
const binary = opts.binary ?? "switchroom";
|
|
74546
|
+
const args = buildRelayArgs(provider, email, opts);
|
|
74230
74547
|
const child = spawn(binary, args, {
|
|
74231
74548
|
stdio: ["ignore", "pipe", "pipe"],
|
|
74232
74549
|
env: {
|
|
@@ -75372,12 +75689,12 @@ class PendingUserNoticeGate {
|
|
|
75372
75689
|
this.pending = this.pending.filter((p) => !(p.agent === notice.agent && p.key === notice.key));
|
|
75373
75690
|
this.pending.push(notice);
|
|
75374
75691
|
}
|
|
75375
|
-
resolveTurnEnd(
|
|
75692
|
+
resolveTurnEnd(turnKey3, turnDeliveredReply, now = Date.now()) {
|
|
75376
75693
|
this.prune(now);
|
|
75377
75694
|
const resolved = [];
|
|
75378
75695
|
const remaining = [];
|
|
75379
75696
|
for (const p of this.pending) {
|
|
75380
|
-
if (p.key ===
|
|
75697
|
+
if (p.key === turnKey3 || p.key === undefined)
|
|
75381
75698
|
resolved.push(p);
|
|
75382
75699
|
else
|
|
75383
75700
|
remaining.push(p);
|
|
@@ -78005,166 +78322,76 @@ ${input.newReplyText}`;
|
|
|
78005
78322
|
};
|
|
78006
78323
|
}
|
|
78007
78324
|
|
|
78008
|
-
//
|
|
78009
|
-
var
|
|
78010
|
-
|
|
78011
|
-
|
|
78012
|
-
|
|
78013
|
-
}
|
|
78014
|
-
|
|
78015
|
-
|
|
78016
|
-
|
|
78017
|
-
|
|
78325
|
+
// gateway/subagent-handback-marker.ts
|
|
78326
|
+
var INBOUND_SOURCE_CLASSIFICATION = {
|
|
78327
|
+
subagent_handback: { decoupledCompletion: true },
|
|
78328
|
+
cron: { decoupledCompletion: false },
|
|
78329
|
+
reaction: { decoupledCompletion: false },
|
|
78330
|
+
subagent_progress: { decoupledCompletion: false },
|
|
78331
|
+
resume_interrupted: { decoupledCompletion: false },
|
|
78332
|
+
resume_deferred: { decoupledCompletion: false },
|
|
78333
|
+
resume_watchdog_timeout: { decoupledCompletion: false },
|
|
78334
|
+
vault_grant_approved: { decoupledCompletion: false },
|
|
78335
|
+
vault_grant_denied: { decoupledCompletion: false },
|
|
78336
|
+
vault_grant_timeout: { decoupledCompletion: false },
|
|
78337
|
+
vault_save_completed: { decoupledCompletion: false },
|
|
78338
|
+
vault_save_discarded: { decoupledCompletion: false },
|
|
78339
|
+
vault_save_failed: { decoupledCompletion: false },
|
|
78340
|
+
vault_save_timeout: { decoupledCompletion: false },
|
|
78341
|
+
secret_provided: { decoupledCompletion: false },
|
|
78342
|
+
secret_declined: { decoupledCompletion: false },
|
|
78343
|
+
secret_provide_failed: { decoupledCompletion: false },
|
|
78344
|
+
secret_request_timeout: { decoupledCompletion: false },
|
|
78345
|
+
mental_model_propose_timeout: { decoupledCompletion: false },
|
|
78346
|
+
bridge_dead_restart: { decoupledCompletion: false },
|
|
78347
|
+
obligation_represent: { decoupledCompletion: false },
|
|
78348
|
+
missed_approval_retry: { decoupledCompletion: false },
|
|
78349
|
+
skill_proposal_apply: { decoupledCompletion: false },
|
|
78350
|
+
warmup: { decoupledCompletion: false },
|
|
78351
|
+
mental_model_proposal_applied: { decoupledCompletion: false },
|
|
78352
|
+
mental_model_proposal_denied: { decoupledCompletion: false },
|
|
78353
|
+
mental_model_proposal_failed: { decoupledCompletion: false },
|
|
78354
|
+
webhook: { decoupledCompletion: false },
|
|
78355
|
+
linear: { decoupledCompletion: false }
|
|
78356
|
+
};
|
|
78357
|
+
function stampsHandbackMarker(source) {
|
|
78358
|
+
if (source == null)
|
|
78018
78359
|
return false;
|
|
78019
|
-
|
|
78020
|
-
|
|
78021
|
-
if (reply.length >= SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 && flushed.includes(reply))
|
|
78022
|
-
return true;
|
|
78023
|
-
if (flushed.length >= SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 && reply.includes(flushed))
|
|
78360
|
+
const known = INBOUND_SOURCE_CLASSIFICATION[source];
|
|
78361
|
+
if (known == null)
|
|
78024
78362
|
return true;
|
|
78025
|
-
return
|
|
78026
|
-
}
|
|
78027
|
-
function decideSupersede2(record, args) {
|
|
78028
|
-
const ttlMs = args.ttlMs ?? DEFAULT_SUPERSEDE_TTL_MS2;
|
|
78029
|
-
if (record == null)
|
|
78030
|
-
return { supersede: false, deleteMessageIds: [], reason: "no-record" };
|
|
78031
|
-
if (args.now - record.ts > ttlMs) {
|
|
78032
|
-
return { supersede: false, deleteMessageIds: [], reason: "expired" };
|
|
78033
|
-
}
|
|
78034
|
-
const sameTurn = record.turnId != null ? record.turnId === args.liveTurnId : args.liveTurnId == null;
|
|
78035
|
-
if (!sameTurn) {
|
|
78036
|
-
return { supersede: false, deleteMessageIds: [], reason: "different-turn" };
|
|
78037
|
-
}
|
|
78038
|
-
if (!args.positiveAttribution && args.replyText != null && !flushedAnswerMatchesReply2(record.text, args.replyText)) {
|
|
78039
|
-
return { supersede: false, deleteMessageIds: [], reason: "new-content", recordText: record.text };
|
|
78040
|
-
}
|
|
78041
|
-
return {
|
|
78042
|
-
supersede: true,
|
|
78043
|
-
deleteMessageIds: [...record.messageIds],
|
|
78044
|
-
reason: "supersede",
|
|
78045
|
-
recordText: record.text
|
|
78046
|
-
};
|
|
78047
|
-
}
|
|
78048
|
-
function decideSupersedeCorrection(input) {
|
|
78049
|
-
const eligible = input.flushMessageIds.length === 1 && input.chunkCount === 1 && !input.hasFiles && !input.suppressText && !input.hasOpenPreview;
|
|
78050
|
-
if (eligible) {
|
|
78051
|
-
return { mode: "edit-in-place", editMessageId: input.flushMessageIds[0], deleteMessageIds: [] };
|
|
78052
|
-
}
|
|
78053
|
-
return { mode: "delete-resend", deleteMessageIds: [...input.flushMessageIds] };
|
|
78054
|
-
}
|
|
78055
|
-
var NULL_TURN_KEY2 = "<<null-turn>>";
|
|
78056
|
-
function turnKey2(turnId) {
|
|
78057
|
-
return turnId == null ? NULL_TURN_KEY2 : turnId;
|
|
78363
|
+
return known.decoupledCompletion;
|
|
78058
78364
|
}
|
|
78365
|
+
var HANDBACK_RECENCY_WINDOW_MS = 60000;
|
|
78366
|
+
var MAIN_THREAD_KEY = "<main>";
|
|
78059
78367
|
|
|
78060
|
-
class
|
|
78061
|
-
|
|
78062
|
-
|
|
78063
|
-
|
|
78064
|
-
this.ttlMs = opts.ttlMs ?? DEFAULT_SUPERSEDE_TTL_MS2;
|
|
78065
|
-
}
|
|
78066
|
-
record(chatId, threadId, rec, now) {
|
|
78067
|
-
if (rec.messageIds.length === 0)
|
|
78068
|
-
return;
|
|
78069
|
-
this.sweep(now);
|
|
78070
|
-
const lane = makeKey3(chatId, threadId);
|
|
78071
|
-
let laneMap = this.entries.get(lane);
|
|
78072
|
-
if (laneMap == null) {
|
|
78073
|
-
laneMap = new Map;
|
|
78074
|
-
this.entries.set(lane, laneMap);
|
|
78075
|
-
}
|
|
78076
|
-
laneMap.set(turnKey2(rec.turnId), {
|
|
78077
|
-
turnId: rec.turnId,
|
|
78078
|
-
messageIds: [...rec.messageIds],
|
|
78079
|
-
text: rec.text,
|
|
78080
|
-
ts: now
|
|
78081
|
-
});
|
|
78082
|
-
}
|
|
78083
|
-
peek(chatId, threadId, args) {
|
|
78084
|
-
const rec = this.entries.get(makeKey3(chatId, threadId))?.get(turnKey2(args.liveTurnId));
|
|
78085
|
-
return decideSupersede2(rec, {
|
|
78086
|
-
liveTurnId: args.liveTurnId,
|
|
78087
|
-
replyText: args.replyText,
|
|
78088
|
-
positiveAttribution: args.positiveAttribution,
|
|
78089
|
-
now: args.now,
|
|
78090
|
-
ttlMs: this.ttlMs
|
|
78091
|
-
});
|
|
78368
|
+
class SubagentHandbackMarker {
|
|
78369
|
+
byChat = new Map;
|
|
78370
|
+
threadKey(threadId) {
|
|
78371
|
+
return threadId == null ? MAIN_THREAD_KEY : String(threadId);
|
|
78092
78372
|
}
|
|
78093
|
-
|
|
78094
|
-
|
|
78095
|
-
|
|
78096
|
-
|
|
78097
|
-
|
|
78098
|
-
laneMap?.delete(turnKey2(args.liveTurnId));
|
|
78099
|
-
if (laneMap != null && laneMap.size === 0)
|
|
78100
|
-
this.entries.delete(lane);
|
|
78373
|
+
record(chatId, threadId, now) {
|
|
78374
|
+
let inner = this.byChat.get(chatId);
|
|
78375
|
+
if (inner == null) {
|
|
78376
|
+
inner = new Map;
|
|
78377
|
+
this.byChat.set(chatId, inner);
|
|
78101
78378
|
}
|
|
78102
|
-
|
|
78103
|
-
}
|
|
78104
|
-
forget(chatId, threadId) {
|
|
78105
|
-
this.entries.delete(makeKey3(chatId, threadId));
|
|
78106
|
-
}
|
|
78107
|
-
clear() {
|
|
78108
|
-
this.entries.clear();
|
|
78379
|
+
inner.set(this.threadKey(threadId), now);
|
|
78109
78380
|
}
|
|
78110
|
-
|
|
78111
|
-
|
|
78112
|
-
for (const [tk, rec] of laneMap) {
|
|
78113
|
-
if (now - rec.ts > this.ttlMs)
|
|
78114
|
-
laneMap.delete(tk);
|
|
78115
|
-
}
|
|
78116
|
-
if (laneMap.size === 0)
|
|
78117
|
-
this.entries.delete(lane);
|
|
78118
|
-
}
|
|
78381
|
+
lastAt(chatId, threadId) {
|
|
78382
|
+
return this.byChat.get(chatId)?.get(this.threadKey(threadId)) ?? null;
|
|
78119
78383
|
}
|
|
78120
|
-
|
|
78121
|
-
this.
|
|
78122
|
-
|
|
78123
|
-
|
|
78124
|
-
|
|
78125
|
-
|
|
78384
|
+
lastAtInChat(chatId) {
|
|
78385
|
+
const inner = this.byChat.get(chatId);
|
|
78386
|
+
if (inner == null || inner.size === 0)
|
|
78387
|
+
return null;
|
|
78388
|
+
let max = -Infinity;
|
|
78389
|
+
for (const ts of inner.values())
|
|
78390
|
+
if (ts > max)
|
|
78391
|
+
max = ts;
|
|
78392
|
+
return max === -Infinity ? null : max;
|
|
78126
78393
|
}
|
|
78127
78394
|
}
|
|
78128
|
-
function makeKey3(chatId, threadId) {
|
|
78129
|
-
return threadId == null ? chatId : `${chatId}|${threadId}`;
|
|
78130
|
-
}
|
|
78131
|
-
|
|
78132
|
-
// reply-owner-resolve.ts
|
|
78133
|
-
function latestEndedAccepted(candidates) {
|
|
78134
|
-
if (candidates.latestEndedTurnId == null)
|
|
78135
|
-
return false;
|
|
78136
|
-
const age = candidates.latestEndedAgeMs;
|
|
78137
|
-
const ttl = candidates.latestEndedTtlMs;
|
|
78138
|
-
if (age === null)
|
|
78139
|
-
return false;
|
|
78140
|
-
if (age === undefined || ttl == null)
|
|
78141
|
-
return true;
|
|
78142
|
-
return age <= ttl;
|
|
78143
|
-
}
|
|
78144
|
-
function decideContentGateBypass(input) {
|
|
78145
|
-
if (input.tier === "live")
|
|
78146
|
-
return true;
|
|
78147
|
-
if (input.tier === "none")
|
|
78148
|
-
return false;
|
|
78149
|
-
if (input.handbackCouldOwnReply)
|
|
78150
|
-
return false;
|
|
78151
|
-
if (input.candidates == null)
|
|
78152
|
-
return false;
|
|
78153
|
-
if (!latestEndedAccepted(input.candidates))
|
|
78154
|
-
return false;
|
|
78155
|
-
return input.resolvedTurnId != null && input.resolvedTurnId === input.candidates.latestEndedTurnId;
|
|
78156
|
-
}
|
|
78157
|
-
function decideAnswerLatchSuppression(input) {
|
|
78158
|
-
if (input.superseded)
|
|
78159
|
-
return false;
|
|
78160
|
-
if (!input.replySubstantive)
|
|
78161
|
-
return false;
|
|
78162
|
-
if (!input.isLateReply)
|
|
78163
|
-
return false;
|
|
78164
|
-
if (input.replyMatchesFlushedAnswer === false)
|
|
78165
|
-
return false;
|
|
78166
|
-
return input.ownerAnswerDelivered === "flush";
|
|
78167
|
-
}
|
|
78168
78395
|
|
|
78169
78396
|
// telegraph.ts
|
|
78170
78397
|
function deriveTelegraphTitle2(text4) {
|
|
@@ -78739,6 +78966,7 @@ async function sendReply(deps, req) {
|
|
|
78739
78966
|
resolveThreadId,
|
|
78740
78967
|
getLatestInboundMessageId: getLatestInboundMessageId2,
|
|
78741
78968
|
getLastSubagentHandbackAt,
|
|
78969
|
+
subagentReplyAuthority: subagentReplyAuthority2,
|
|
78742
78970
|
recordOutbound: recordOutbound2,
|
|
78743
78971
|
emissionAuthorityFor,
|
|
78744
78972
|
clearActivitySummary,
|
|
@@ -78813,7 +79041,10 @@ async function sendReply(deps, req) {
|
|
|
78813
79041
|
}
|
|
78814
79042
|
}
|
|
78815
79043
|
let supersedeFlushIds = [];
|
|
78816
|
-
{
|
|
79044
|
+
if (req.callerIsForeignSession === true) {
|
|
79045
|
+
process.stderr.write(`telegram gateway: reply: foreign-session caller \u2014 supersede/latch skipped (#4172) ` + `chatId=${chat_id}
|
|
79046
|
+
`);
|
|
79047
|
+
} else {
|
|
78817
79048
|
const replyThreadId = args.message_thread_id != null ? Number(args.message_thread_id) : undefined;
|
|
78818
79049
|
const {
|
|
78819
79050
|
turn: ownerTurn,
|
|
@@ -78825,12 +79056,14 @@ async function sendReply(deps, req) {
|
|
|
78825
79056
|
const gateThreadId = ownerTurn?.sessionThreadId ?? replyThreadId;
|
|
78826
79057
|
const handbackAt = getLastSubagentHandbackAt(chat_id);
|
|
78827
79058
|
const now = Date.now();
|
|
78828
|
-
const handbackCouldOwnReply = handbackAt != null && ownerEndedAt != null && handbackAt > ownerEndedAt && now - handbackAt <=
|
|
79059
|
+
const handbackCouldOwnReply = handbackAt != null && ownerEndedAt != null && handbackAt > ownerEndedAt && now - handbackAt <= HANDBACK_RECENCY_WINDOW_MS;
|
|
79060
|
+
const subagentCouldOwnReply = subagentReplyAuthority2.subagentCouldOwnReply();
|
|
78829
79061
|
const replyIsOwnAnswer = decideContentGateBypass({
|
|
78830
79062
|
tier: ownerTier,
|
|
78831
79063
|
resolvedTurnId,
|
|
78832
79064
|
candidates: ownerCandidates,
|
|
78833
|
-
handbackCouldOwnReply
|
|
79065
|
+
handbackCouldOwnReply,
|
|
79066
|
+
subagentCouldOwnReply
|
|
78834
79067
|
});
|
|
78835
79068
|
const decision = flushedTurnSupersede.take(chat_id, gateThreadId, { liveTurnId: resolvedTurnId, replyText: text4, positiveAttribution: replyIsOwnAnswer, now });
|
|
78836
79069
|
if (decision.supersede) {
|
|
@@ -78856,7 +79089,7 @@ async function sendReply(deps, req) {
|
|
|
78856
79089
|
replyMatchesFlushedAnswer
|
|
78857
79090
|
});
|
|
78858
79091
|
if (decision.reason === "new-content") {
|
|
78859
|
-
process.stderr.write(`telegram gateway: reply: flush supersede declined \u2014 new content (#3429) ` + `chatId=${chat_id} ownerTurnId=${JSON.stringify(resolvedTurnId)} ` + `tier=${ownerTier} latestEnded=${JSON.stringify(ownerCandidates.latestEndedTurnId)} ` + `handbackInWindow=${handbackCouldOwnReply}; sending fresh
|
|
79092
|
+
process.stderr.write(`telegram gateway: reply: flush supersede declined \u2014 new content (#3429) ` + `chatId=${chat_id} ownerTurnId=${JSON.stringify(resolvedTurnId)} ` + `tier=${ownerTier} latestEnded=${JSON.stringify(ownerCandidates.latestEndedTurnId)} ` + `handbackInWindow=${handbackCouldOwnReply} subagentLive=${subagentCouldOwnReply}; sending fresh
|
|
78860
79093
|
`);
|
|
78861
79094
|
}
|
|
78862
79095
|
if (suppressByLatch) {
|
|
@@ -80110,6 +80343,37 @@ function emitRuntimeMetric2(event) {
|
|
|
80110
80343
|
captureEvent(event.kind, { ...event, ts: wrapped.ts });
|
|
80111
80344
|
}
|
|
80112
80345
|
|
|
80346
|
+
// gateway/subagent-reply-authority.ts
|
|
80347
|
+
var SUB_AGENT_KIND_PREFIX2 = "sub_agent_";
|
|
80348
|
+
|
|
80349
|
+
class SubagentReplyAuthority2 {
|
|
80350
|
+
live = new Set;
|
|
80351
|
+
noteSessionEvent(ev) {
|
|
80352
|
+
if (ev == null)
|
|
80353
|
+
return;
|
|
80354
|
+
const kind = ev.kind;
|
|
80355
|
+
if (typeof kind !== "string" || !kind.startsWith(SUB_AGENT_KIND_PREFIX2))
|
|
80356
|
+
return;
|
|
80357
|
+
const agentId = ev.agentId;
|
|
80358
|
+
if (typeof agentId !== "string" || agentId === "")
|
|
80359
|
+
return;
|
|
80360
|
+
if (kind === `${SUB_AGENT_KIND_PREFIX2}turn_end`)
|
|
80361
|
+
this.live.delete(agentId);
|
|
80362
|
+
else
|
|
80363
|
+
this.live.add(agentId);
|
|
80364
|
+
}
|
|
80365
|
+
subagentCouldOwnReply() {
|
|
80366
|
+
return this.live.size > 0;
|
|
80367
|
+
}
|
|
80368
|
+
reset() {
|
|
80369
|
+
this.live.clear();
|
|
80370
|
+
}
|
|
80371
|
+
liveCount() {
|
|
80372
|
+
return this.live.size;
|
|
80373
|
+
}
|
|
80374
|
+
}
|
|
80375
|
+
var subagentReplyAuthority2 = new SubagentReplyAuthority2;
|
|
80376
|
+
|
|
80113
80377
|
// gateway/feed-open-gate.ts
|
|
80114
80378
|
function shouldEarlyOpenLiveness(input) {
|
|
80115
80379
|
if (!input.enabled)
|
|
@@ -80838,6 +81102,12 @@ function discardParkedTurnStart(rawContent) {
|
|
|
80838
81102
|
}
|
|
80839
81103
|
return null;
|
|
80840
81104
|
}
|
|
81105
|
+
var flushCompletionTracker = new FlushCompletionTracker;
|
|
81106
|
+
function closeFlushCompletionWindows(registry, now) {
|
|
81107
|
+
const closed = flushCompletionTracker.closeAll(now);
|
|
81108
|
+
registry?.completeAll?.(now);
|
|
81109
|
+
return closed;
|
|
81110
|
+
}
|
|
80841
81111
|
function drainParkedTurnStartsForChat(deps, chatId, threadId) {
|
|
80842
81112
|
const wantThread = envThreadIdNum(threadId);
|
|
80843
81113
|
const drained = [];
|
|
@@ -80970,6 +81240,7 @@ function beginTurn(deps, ev) {
|
|
|
80970
81240
|
answerDelivered: false,
|
|
80971
81241
|
flushedAnswerText: null,
|
|
80972
81242
|
endedAt: null,
|
|
81243
|
+
realEndObservedAt: null,
|
|
80973
81244
|
firstPingAt: null,
|
|
80974
81245
|
firstPingWasSubstantive: false,
|
|
80975
81246
|
silentAnchorMessageId: null,
|
|
@@ -81025,6 +81296,7 @@ function beginTurn(deps, ev) {
|
|
|
81025
81296
|
`);
|
|
81026
81297
|
}
|
|
81027
81298
|
startTurnTypingLoop(ev.chatId, enqThreadIdNum ?? null);
|
|
81299
|
+
closeFlushCompletionWindows(deps.flushedTurnSupersede, Date.now());
|
|
81028
81300
|
setCurrentTurn(next, statusKey(ev.chatId, enqThreadIdNum));
|
|
81029
81301
|
scheduleEarlyLivenessOpen(next);
|
|
81030
81302
|
process.stderr.write(`telegram gateway: ${formatTurnLifecycle("set", "enqueue", next, startedAt)}
|
|
@@ -81163,6 +81435,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
81163
81435
|
const durationMs = ev.kind === "turn_end" ? ev.durationMs : undefined;
|
|
81164
81436
|
idleTracker.noteEvent(ev.kind, Date.now(), durationMs);
|
|
81165
81437
|
}
|
|
81438
|
+
subagentReplyAuthority2.noteSessionEvent(ev);
|
|
81166
81439
|
switch (ev.kind) {
|
|
81167
81440
|
case "enqueue": {
|
|
81168
81441
|
const enqThreadIdNum = ev.threadId != null ? Number(ev.threadId) : undefined;
|
|
@@ -81475,6 +81748,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
81475
81748
|
return;
|
|
81476
81749
|
}
|
|
81477
81750
|
}
|
|
81751
|
+
closeFlushCompletionWindows(flushedTurnSupersede, Date.now());
|
|
81478
81752
|
const turnEndBackstopTurn = getCurrentTurn();
|
|
81479
81753
|
const turnEndBackstopKey = turnEndBackstopTurn != null ? statusKey(turnEndBackstopTurn.sessionChatId, turnEndBackstopTurn.sessionThreadId) : null;
|
|
81480
81754
|
withTurnEndGateBackstop(turnEndBackstopKey, turnEndBackstopTurn, () => {
|
|
@@ -81648,6 +81922,9 @@ function handleSessionEvent(deps, ev) {
|
|
|
81648
81922
|
const backstopCardMessageId = cardTakeover.wasEmitted && cardTakeover.turnKey != null ? getPinnedProgressCardMessageId?.(cardTakeover.turnKey) ?? null : null;
|
|
81649
81923
|
const backstopCardTurnKey = cardTakeover.turnKey;
|
|
81650
81924
|
const backstopTurnEndedAt = endCurrentTurnAtomic(turn, { deferRecord: true, deferObligationClose: true });
|
|
81925
|
+
if (ev.durationMs === -1) {
|
|
81926
|
+
flushCompletionTracker.open(turn);
|
|
81927
|
+
}
|
|
81651
81928
|
preambleSuppressor.dropNow();
|
|
81652
81929
|
{
|
|
81653
81930
|
const tKey = statusKey(chatId, threadId);
|
|
@@ -81725,7 +82002,12 @@ function handleSessionEvent(deps, ev) {
|
|
|
81725
82002
|
turn.landedUnconfirmed = delivery.landedUnconfirmed;
|
|
81726
82003
|
outboundDedup.record(backstopChatId, backstopThreadId, capturedText, Date.now(), getCurrentTurn()?.registryKey ?? null);
|
|
81727
82004
|
if (sentIds.length > 0) {
|
|
81728
|
-
flushedTurnSupersede.record(backstopChatId, backstopThreadId, {
|
|
82005
|
+
flushedTurnSupersede.record(backstopChatId, backstopThreadId, {
|
|
82006
|
+
turnId: turn.turnId,
|
|
82007
|
+
messageIds: sentIds,
|
|
82008
|
+
text: capturedText,
|
|
82009
|
+
completedAt: turn.realEndObservedAt
|
|
82010
|
+
}, Date.now());
|
|
81729
82011
|
}
|
|
81730
82012
|
if (!delivered) {
|
|
81731
82013
|
if (backstopCtrl)
|
|
@@ -82698,51 +82980,13 @@ function isTurnFlushSafetyEnabled(env = process.env) {
|
|
|
82698
82980
|
return true;
|
|
82699
82981
|
}
|
|
82700
82982
|
|
|
82701
|
-
// reply-owner-resolve.ts
|
|
82702
|
-
function latestEndedAccepted2(candidates) {
|
|
82703
|
-
if (candidates.latestEndedTurnId == null)
|
|
82704
|
-
return false;
|
|
82705
|
-
const age = candidates.latestEndedAgeMs;
|
|
82706
|
-
const ttl = candidates.latestEndedTtlMs;
|
|
82707
|
-
if (age === null)
|
|
82708
|
-
return false;
|
|
82709
|
-
if (age === undefined || ttl == null)
|
|
82710
|
-
return true;
|
|
82711
|
-
return age <= ttl;
|
|
82712
|
-
}
|
|
82713
|
-
function resolveReplyOwnerTier(candidates) {
|
|
82714
|
-
if (candidates.liveTurnId != null)
|
|
82715
|
-
return "live";
|
|
82716
|
-
if (candidates.originTurnId != null)
|
|
82717
|
-
return "origin";
|
|
82718
|
-
if (candidates.quotedTurnId != null)
|
|
82719
|
-
return "quoted";
|
|
82720
|
-
if (latestEndedAccepted2(candidates))
|
|
82721
|
-
return "latest-ended";
|
|
82722
|
-
return "none";
|
|
82723
|
-
}
|
|
82724
|
-
function resolveReplyOwnerTurnId(candidates) {
|
|
82725
|
-
switch (resolveReplyOwnerTier(candidates)) {
|
|
82726
|
-
case "live":
|
|
82727
|
-
return candidates.liveTurnId;
|
|
82728
|
-
case "origin":
|
|
82729
|
-
return candidates.originTurnId;
|
|
82730
|
-
case "quoted":
|
|
82731
|
-
return candidates.quotedTurnId;
|
|
82732
|
-
case "latest-ended":
|
|
82733
|
-
return candidates.latestEndedTurnId;
|
|
82734
|
-
case "none":
|
|
82735
|
-
return null;
|
|
82736
|
-
}
|
|
82737
|
-
}
|
|
82738
|
-
|
|
82739
82983
|
// gateway/subagent-handback-marker.ts
|
|
82740
|
-
var
|
|
82984
|
+
var MAIN_THREAD_KEY2 = "<main>";
|
|
82741
82985
|
|
|
82742
|
-
class
|
|
82986
|
+
class SubagentHandbackMarker2 {
|
|
82743
82987
|
byChat = new Map;
|
|
82744
82988
|
threadKey(threadId) {
|
|
82745
|
-
return threadId == null ?
|
|
82989
|
+
return threadId == null ? MAIN_THREAD_KEY2 : String(threadId);
|
|
82746
82990
|
}
|
|
82747
82991
|
record(chatId, threadId, now) {
|
|
82748
82992
|
let inner = this.byChat.get(chatId);
|
|
@@ -91182,76 +91426,6 @@ function buildDiffPreviewCard(input) {
|
|
|
91182
91426
|
return { text: text4, reply_markup: kb };
|
|
91183
91427
|
}
|
|
91184
91428
|
|
|
91185
|
-
// gateway/subagent-handback-marker.ts
|
|
91186
|
-
var INBOUND_SOURCE_CLASSIFICATION = {
|
|
91187
|
-
subagent_handback: { decoupledCompletion: true },
|
|
91188
|
-
cron: { decoupledCompletion: false },
|
|
91189
|
-
reaction: { decoupledCompletion: false },
|
|
91190
|
-
subagent_progress: { decoupledCompletion: false },
|
|
91191
|
-
resume_interrupted: { decoupledCompletion: false },
|
|
91192
|
-
resume_deferred: { decoupledCompletion: false },
|
|
91193
|
-
resume_watchdog_timeout: { decoupledCompletion: false },
|
|
91194
|
-
vault_grant_approved: { decoupledCompletion: false },
|
|
91195
|
-
vault_grant_denied: { decoupledCompletion: false },
|
|
91196
|
-
vault_grant_timeout: { decoupledCompletion: false },
|
|
91197
|
-
vault_save_completed: { decoupledCompletion: false },
|
|
91198
|
-
vault_save_discarded: { decoupledCompletion: false },
|
|
91199
|
-
vault_save_failed: { decoupledCompletion: false },
|
|
91200
|
-
vault_save_timeout: { decoupledCompletion: false },
|
|
91201
|
-
secret_provided: { decoupledCompletion: false },
|
|
91202
|
-
secret_declined: { decoupledCompletion: false },
|
|
91203
|
-
secret_provide_failed: { decoupledCompletion: false },
|
|
91204
|
-
secret_request_timeout: { decoupledCompletion: false },
|
|
91205
|
-
mental_model_propose_timeout: { decoupledCompletion: false },
|
|
91206
|
-
bridge_dead_restart: { decoupledCompletion: false },
|
|
91207
|
-
obligation_represent: { decoupledCompletion: false },
|
|
91208
|
-
missed_approval_retry: { decoupledCompletion: false },
|
|
91209
|
-
skill_proposal_apply: { decoupledCompletion: false },
|
|
91210
|
-
warmup: { decoupledCompletion: false },
|
|
91211
|
-
mental_model_proposal_applied: { decoupledCompletion: false },
|
|
91212
|
-
mental_model_proposal_denied: { decoupledCompletion: false },
|
|
91213
|
-
mental_model_proposal_failed: { decoupledCompletion: false },
|
|
91214
|
-
webhook: { decoupledCompletion: false },
|
|
91215
|
-
linear: { decoupledCompletion: false }
|
|
91216
|
-
};
|
|
91217
|
-
function stampsHandbackMarker(source) {
|
|
91218
|
-
if (source == null)
|
|
91219
|
-
return false;
|
|
91220
|
-
const known = INBOUND_SOURCE_CLASSIFICATION[source];
|
|
91221
|
-
if (known == null)
|
|
91222
|
-
return true;
|
|
91223
|
-
return known.decoupledCompletion;
|
|
91224
|
-
}
|
|
91225
|
-
var MAIN_THREAD_KEY2 = "<main>";
|
|
91226
|
-
|
|
91227
|
-
class SubagentHandbackMarker2 {
|
|
91228
|
-
byChat = new Map;
|
|
91229
|
-
threadKey(threadId) {
|
|
91230
|
-
return threadId == null ? MAIN_THREAD_KEY2 : String(threadId);
|
|
91231
|
-
}
|
|
91232
|
-
record(chatId, threadId, now) {
|
|
91233
|
-
let inner = this.byChat.get(chatId);
|
|
91234
|
-
if (inner == null) {
|
|
91235
|
-
inner = new Map;
|
|
91236
|
-
this.byChat.set(chatId, inner);
|
|
91237
|
-
}
|
|
91238
|
-
inner.set(this.threadKey(threadId), now);
|
|
91239
|
-
}
|
|
91240
|
-
lastAt(chatId, threadId) {
|
|
91241
|
-
return this.byChat.get(chatId)?.get(this.threadKey(threadId)) ?? null;
|
|
91242
|
-
}
|
|
91243
|
-
lastAtInChat(chatId) {
|
|
91244
|
-
const inner = this.byChat.get(chatId);
|
|
91245
|
-
if (inner == null || inner.size === 0)
|
|
91246
|
-
return null;
|
|
91247
|
-
let max = -Infinity;
|
|
91248
|
-
for (const ts of inner.values())
|
|
91249
|
-
if (ts > max)
|
|
91250
|
-
max = ts;
|
|
91251
|
-
return max === -Infinity ? null : max;
|
|
91252
|
-
}
|
|
91253
|
-
}
|
|
91254
|
-
|
|
91255
91429
|
// gateway/pending-inbound-buffer.ts
|
|
91256
91430
|
var DEFAULT_PENDING_INBOUND_CAP = 32;
|
|
91257
91431
|
function redeliverBufferedInbound(buffer, agent, send, spool, onDelivered) {
|
|
@@ -91405,6 +91579,11 @@ function cronIdentity(agent) {
|
|
|
91405
91579
|
function isCronIdentity(name) {
|
|
91406
91580
|
return typeof name === "string" && name.endsWith(CRON_IDENTITY_SUFFIX);
|
|
91407
91581
|
}
|
|
91582
|
+
function replyCallerIsForeignSession(name) {
|
|
91583
|
+
if (name == null || name === "")
|
|
91584
|
+
return true;
|
|
91585
|
+
return isCronIdentity(name);
|
|
91586
|
+
}
|
|
91408
91587
|
function isCronInjectFire(meta) {
|
|
91409
91588
|
return meta?.source === "cron" || meta?.session === "cron";
|
|
91410
91589
|
}
|
|
@@ -93204,6 +93383,7 @@ function createTurnEndFunnel(deps) {
|
|
|
93204
93383
|
endCurrentTurnForKey(turn, key);
|
|
93205
93384
|
const turnEndedAt = Date.now();
|
|
93206
93385
|
turn.endedAt = turnEndedAt;
|
|
93386
|
+
turn.realEndObservedAt = turnEndedAt;
|
|
93207
93387
|
process.stderr.write(`telegram gateway: ${formatTurnLifecycle("clear", "turn_end", turn, turnEndedAt)}
|
|
93208
93388
|
`);
|
|
93209
93389
|
if (opts?.deferRecord !== true) {
|
|
@@ -100866,10 +101046,10 @@ function startOutboxSweep(deps) {
|
|
|
100866
101046
|
}
|
|
100867
101047
|
|
|
100868
101048
|
// ../src/build-info.ts
|
|
100869
|
-
var VERSION2 = "0.19.
|
|
100870
|
-
var COMMIT_SHA = "
|
|
100871
|
-
var COMMIT_DATE = "2026-08-
|
|
100872
|
-
var LATEST_PR =
|
|
101049
|
+
var VERSION2 = "0.19.46";
|
|
101050
|
+
var COMMIT_SHA = "306c3ed1";
|
|
101051
|
+
var COMMIT_DATE = "2026-08-02T00:29:39Z";
|
|
101052
|
+
var LATEST_PR = 4194;
|
|
100873
101053
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
100874
101054
|
|
|
100875
101055
|
// gateway/boot-version.ts
|
|
@@ -103412,7 +103592,10 @@ var deferredDoneReactions = new DeferredDoneReactions({
|
|
|
103412
103592
|
purge: (key) => purgeReactionTracking(key)
|
|
103413
103593
|
});
|
|
103414
103594
|
var outboundDedup = new OutboundDedupCache;
|
|
103415
|
-
var flushedTurnSupersede = new FlushedTurnSupersedeRegistry
|
|
103595
|
+
var flushedTurnSupersede = new FlushedTurnSupersedeRegistry({
|
|
103596
|
+
openCapMs: SUPERSEDE_OPEN_CAP_MS,
|
|
103597
|
+
completedGraceMs: SUPERSEDE_GRACE_MS
|
|
103598
|
+
});
|
|
103416
103599
|
var backstopDeliveryLedger = new BackstopDeliveryLedger2;
|
|
103417
103600
|
var BACKSTOP_DELIVERY_MAX_ATTEMPTS = (() => {
|
|
103418
103601
|
const raw = Number(process.env.SWITCHROOM_BACKSTOP_DELIVERY_MAX_ATTEMPTS);
|
|
@@ -103776,7 +103959,7 @@ function cardDrainGate(turn, ea, run4) {
|
|
|
103776
103959
|
var RECENT_TURNS_MAX = 32;
|
|
103777
103960
|
var recentTurnsById = new Map;
|
|
103778
103961
|
var recentTurnIdBySourceMessageId = new Map;
|
|
103779
|
-
var subagentHandbackMarker = new
|
|
103962
|
+
var subagentHandbackMarker = new SubagentHandbackMarker2;
|
|
103780
103963
|
var getLastSubagentHandbackAt = (chatId) => subagentHandbackMarker.lastAtInChat(chatId);
|
|
103781
103964
|
function rememberRecentTurn(turn) {
|
|
103782
103965
|
recentTurnsById.set(turn.turnId, turn);
|
|
@@ -103830,26 +104013,7 @@ function findLatestTurnForChat(chatId, opts) {
|
|
|
103830
104013
|
return latestTurnForChat(recentTurnsById.values(), chatId, opts);
|
|
103831
104014
|
}
|
|
103832
104015
|
function resolveReplyOwnerTurn(liveTurn, chatId, args) {
|
|
103833
|
-
|
|
103834
|
-
const quoted = findTurnByQuotedMessageId(chatId, args.reply_to);
|
|
103835
|
-
const latestEnded = findLatestTurnForChat(chatId, { endedOnly: true });
|
|
103836
|
-
const byId = new Map;
|
|
103837
|
-
for (const t of [latestEnded, quoted, origin, liveTurn]) {
|
|
103838
|
-
if (t != null)
|
|
103839
|
-
byId.set(t.turnId, t);
|
|
103840
|
-
}
|
|
103841
|
-
const latestEndedAgeMs = latestEnded?.endedAt != null ? Date.now() - latestEnded.endedAt : null;
|
|
103842
|
-
const candidates = {
|
|
103843
|
-
liveTurnId: liveTurn?.turnId ?? null,
|
|
103844
|
-
originTurnId: origin?.turnId ?? null,
|
|
103845
|
-
quotedTurnId: quoted?.turnId ?? null,
|
|
103846
|
-
latestEndedTurnId: latestEnded?.turnId ?? null,
|
|
103847
|
-
latestEndedAgeMs,
|
|
103848
|
-
latestEndedTtlMs: DEFAULT_SUPERSEDE_TTL_MS
|
|
103849
|
-
};
|
|
103850
|
-
const tier = resolveReplyOwnerTier(candidates);
|
|
103851
|
-
const winnerId = resolveReplyOwnerTurnId(candidates);
|
|
103852
|
-
return { turn: winnerId != null ? byId.get(winnerId) ?? null : null, tier, candidates };
|
|
104016
|
+
return resolveReplyOwnerTurnWith({ findTurnByOriginId, findTurnByQuotedMessageId, findLatestTurnForChat, now: Date.now }, liveTurn, chatId, args);
|
|
103853
104017
|
}
|
|
103854
104018
|
function resolveAnswerThreadWithLog(chatId, explicitThreadId, originTurn, originVia, liveTurn, surface) {
|
|
103855
104019
|
const recovered = LATE_REPLY_TOPIC_RECOVERY_ENABLED && explicitThreadId == null && originTurn == null && liveTurn == null ? findLatestTurnForChat(chatId, { endedOnly: false }) : null;
|
|
@@ -106905,12 +107069,20 @@ if (isGatewayMain)
|
|
|
106905
107069
|
log: (msg) => process.stderr.write(`${msg}
|
|
106906
107070
|
`)
|
|
106907
107071
|
});
|
|
107072
|
+
if (client3.agentName != null && !isCronIdentity(client3.agentName)) {
|
|
107073
|
+
subagentReplyAuthority.reset();
|
|
107074
|
+
const closedWindows = closeFlushCompletionWindows(flushedTurnSupersede, Date.now());
|
|
107075
|
+
if (closedWindows > 0) {
|
|
107076
|
+
process.stderr.write(`telegram gateway: bridge disconnect closed ${closedWindows} open flush-completion window(s) (#4173)
|
|
107077
|
+
`);
|
|
107078
|
+
}
|
|
107079
|
+
}
|
|
106908
107080
|
},
|
|
106909
107081
|
async onToolCall(client3, msg) {
|
|
106910
107082
|
process.stderr.write(`telegram gateway: ipc: tool_call tool=${msg.tool} agent=${client3.agentName ?? "-"} clientId=${client3.id ?? "-"} callId=${msg.id}
|
|
106911
107083
|
`);
|
|
106912
107084
|
try {
|
|
106913
|
-
const result = await executeToolCall(msg.tool, msg.args);
|
|
107085
|
+
const result = await executeToolCall(msg.tool, msg.args, client3.agentName);
|
|
106914
107086
|
return { type: "tool_call_result", id: msg.id, success: true, result };
|
|
106915
107087
|
} catch (err) {
|
|
106916
107088
|
return {
|
|
@@ -107588,13 +107760,13 @@ var ALLOWED_TOOLS = new Set([
|
|
|
107588
107760
|
"linear_create_issue",
|
|
107589
107761
|
"linear_agent_setup"
|
|
107590
107762
|
]);
|
|
107591
|
-
async function executeToolCall(tool, args) {
|
|
107763
|
+
async function executeToolCall(tool, args, callerAgentName = null) {
|
|
107592
107764
|
if (!ALLOWED_TOOLS.has(tool)) {
|
|
107593
107765
|
throw new Error(`tool not allowed: ${tool}`);
|
|
107594
107766
|
}
|
|
107595
107767
|
switch (tool) {
|
|
107596
107768
|
case "reply":
|
|
107597
|
-
return executeReply(args);
|
|
107769
|
+
return executeReply(args, callerAgentName);
|
|
107598
107770
|
case "progress_update":
|
|
107599
107771
|
return executeProgressUpdate(args);
|
|
107600
107772
|
case "react":
|
|
@@ -107875,8 +108047,12 @@ async function synthesizeVoiceOut(plan) {
|
|
|
107875
108047
|
return null;
|
|
107876
108048
|
}
|
|
107877
108049
|
}
|
|
107878
|
-
async function executeReply(args) {
|
|
107879
|
-
return sendReply(gatewaySendReplyDeps(), {
|
|
108050
|
+
async function executeReply(args, callerAgentName = null) {
|
|
108051
|
+
return sendReply(gatewaySendReplyDeps(), {
|
|
108052
|
+
args,
|
|
108053
|
+
turn: currentTurn,
|
|
108054
|
+
callerIsForeignSession: replyCallerIsForeignSession(callerAgentName)
|
|
108055
|
+
});
|
|
107880
108056
|
}
|
|
107881
108057
|
function gatewaySendReplyDeps() {
|
|
107882
108058
|
return {
|
|
@@ -107915,6 +108091,7 @@ function gatewaySendReplyDeps() {
|
|
|
107915
108091
|
resolveThreadId,
|
|
107916
108092
|
getLatestInboundMessageId,
|
|
107917
108093
|
getLastSubagentHandbackAt,
|
|
108094
|
+
subagentReplyAuthority,
|
|
107918
108095
|
recordOutbound,
|
|
107919
108096
|
emissionAuthorityFor,
|
|
107920
108097
|
clearActivitySummary,
|
|
@@ -112355,7 +112532,7 @@ Set \`admin: true\` on this agent in switchroom.yaml to unlock.`, { html: true }
|
|
|
112355
112532
|
return;
|
|
112356
112533
|
}
|
|
112357
112534
|
try {
|
|
112358
|
-
const { consentUrl, state: state7, port, child } = await startLoopbackFlow(parsed.provider, parsed.email, { replace: parsed.replace, write: parsed.write, orgMode: parsed.orgMode });
|
|
112535
|
+
const { consentUrl, state: state7, port, child } = await startLoopbackFlow(parsed.provider, parsed.email, { replace: parsed.replace, write: parsed.write, calendar: parsed.calendar, orgMode: parsed.orgMode });
|
|
112359
112536
|
const newFlow = {
|
|
112360
112537
|
provider: parsed.provider,
|
|
112361
112538
|
email: parsed.email,
|