@segmentstream/agent 0.6.13 → 0.7.0
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 +41 -42
- package/dist/_chunks/{inbound-request-CysnjMdw.mjs → inbound-request-BwBvXk0A.mjs} +9 -2
- package/dist/extension/_manifest.json +2 -0
- package/dist/extension/channels/telegram.mjs +1 -0
- package/dist/extension/config.d.ts +17 -5
- package/dist/extension/config.mjs +26 -5
- package/dist/extension/connections/ontology.mjs +1 -1
- package/dist/extension/instructions.md +20 -0
- package/dist/extension/lib/attachment-formats.d.ts +1 -1
- package/dist/extension/lib/attachment-tables.d.ts +1 -1
- package/dist/extension/lib/confirmation-description.d.ts +5 -0
- package/dist/extension/lib/confirmation-description.mjs +7 -1
- package/dist/extension/lib/confirmation-outcome.d.ts +19 -0
- package/dist/extension/lib/confirmation-outcome.mjs +34 -0
- package/dist/extension/lib/confirmations.mjs +1 -1
- package/dist/extension/lib/connection-proxy.d.ts +2 -2
- package/dist/extension/lib/connection-proxy.mjs +6 -6
- package/dist/extension/lib/conversations.mjs +15 -1
- package/dist/extension/lib/customer-text-safety.mjs +2 -1
- package/dist/extension/lib/deferred-confirmations.d.ts +39 -0
- package/dist/extension/lib/deferred-confirmations.mjs +149 -0
- package/dist/extension/lib/ontology-tools.d.ts +2 -0
- package/dist/extension/lib/ontology-tools.mjs +5 -0
- package/dist/extension/lib/telegram/adapter.d.ts +6 -0
- package/dist/extension/lib/telegram/adapter.mjs +89 -14
- package/dist/extension/lib/telegram/attachment-description.d.ts +31 -0
- package/dist/extension/lib/telegram/attachment-description.mjs +82 -0
- package/dist/extension/lib/telegram/attachments-send.mjs +3 -3
- package/dist/extension/lib/telegram/audience.mjs +1 -1
- package/dist/extension/lib/telegram/bot.mjs +3 -1
- package/dist/extension/lib/telegram/chat-post-card.mjs +1 -1
- package/dist/extension/lib/telegram/confirmation-expiry.d.ts +4 -0
- package/dist/extension/lib/telegram/confirmation-expiry.mjs +50 -0
- package/dist/extension/lib/telegram/confirmations.d.ts +9 -1
- package/dist/extension/lib/telegram/confirmations.mjs +136 -15
- package/dist/extension/lib/telegram/conversations.d.ts +10 -1
- package/dist/extension/lib/telegram/conversations.mjs +177 -22
- package/dist/extension/lib/telegram/customer-text.mjs +1 -1
- package/dist/extension/lib/telegram/deferred-confirmations.d.ts +26 -0
- package/dist/extension/lib/telegram/deferred-confirmations.mjs +282 -0
- package/dist/extension/lib/telegram/files.mjs +20 -3
- package/dist/extension/lib/telegram/images.d.ts +1 -0
- package/dist/extension/lib/telegram/images.mjs +2 -1
- package/dist/extension/lib/telegram/inbound-request.d.ts +15 -1
- package/dist/extension/lib/telegram/inbound-request.mjs +1 -1
- package/dist/extension/lib/telegram/inbound.d.ts +12 -4
- package/dist/extension/lib/telegram/inbound.mjs +258 -74
- package/dist/extension/lib/telegram/media-policy.mjs +1 -1
- package/dist/extension/lib/telegram/observed.d.ts +45 -2
- package/dist/extension/lib/telegram/observed.mjs +62 -3
- package/dist/extension/lib/telegram/pdf-text.d.ts +5 -0
- package/dist/extension/lib/telegram/pdf-text.mjs +84 -0
- package/dist/extension/lib/telegram/router.d.ts +31 -7
- package/dist/extension/lib/telegram/router.mjs +152 -41
- package/dist/extension/lib/telegram/routing-context.d.ts +15 -3
- package/dist/extension/lib/telegram/routing-context.mjs +131 -6
- package/dist/extension/lib/telegram/silent.mjs +5 -3
- package/dist/extension/lib/telegram/turn-errors.mjs +1 -1
- package/dist/extension/lib/telegram/voice.d.ts +4 -0
- package/dist/extension/lib/telegram/voice.mjs +7 -6
- package/dist/extension/schedules/confirmations.d.ts +6 -0
- package/dist/extension/schedules/confirmations.mjs +33 -0
- package/dist/extension/tools/ontology.d.ts +4 -0
- package/dist/extension/tools/ontology.mjs +30 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.mjs +2 -1
- package/package.json +7 -4
|
@@ -5,17 +5,20 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { memberIdOf, telegramPrincipal } from "./principal.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { humanText } from "../confirmation-description.mjs";
|
|
9
9
|
import { renderConfirmation, withConfirmationText } from "./confirmation-text.mjs";
|
|
10
|
+
import { chatPostOperationId, isChatPost } from "../chat-post-confirmation.mjs";
|
|
10
11
|
import { chatPostCard, chatPostCardStatus, chatPostReceipt, withChatPostCard } from "./chat-post-card.mjs";
|
|
11
12
|
import { confirmations } from "../confirmations.mjs";
|
|
12
13
|
import { conversationEvent } from "../conversations.mjs";
|
|
13
|
-
import { n as currentInboundRequest, p as reportTelegramError } from "../../../_chunks/inbound-request-
|
|
14
|
-
import { answerMarker, isPendingQuestion, pendingQuestions, questionKey } from "../questions.mjs";
|
|
14
|
+
import { n as currentInboundRequest, p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
|
|
15
15
|
import { formatAddress, scopedAddress } from "./sessions.mjs";
|
|
16
|
+
import { agentMessage, observedChatKey, withConfirmationPrompt } from "./observed.mjs";
|
|
17
|
+
import { postDeferredCard } from "./deferred-confirmations.mjs";
|
|
18
|
+
import { answerMarker, isPendingQuestion, pendingQuestions, questionKey } from "../questions.mjs";
|
|
16
19
|
import { telegramTextLinks } from "@segmentstream-cloud/ontology/telegram";
|
|
17
|
-
import { registerTelegramFreeformPrompt, renderTelegramInputRequest } from "eve/channels/telegram";
|
|
18
20
|
import { createHash } from "node:crypto";
|
|
21
|
+
import { registerTelegramFreeformPrompt, renderTelegramInputRequest } from "eve/channels/telegram";
|
|
19
22
|
const PREFIX = "ss-confirm:";
|
|
20
23
|
function shortHash(value) {
|
|
21
24
|
return createHash("sha256").update(value).digest("hex").slice(0, 20);
|
|
@@ -31,7 +34,7 @@ function openConfirmations(events) {
|
|
|
31
34
|
const open = new Map();
|
|
32
35
|
for (const event of events) {
|
|
33
36
|
const data = object(event.data);
|
|
34
|
-
if (event.type === "context.cleared") open.clear();
|
|
37
|
+
if (event.type === "context.cleared" || event.type === "session.started") open.clear();
|
|
35
38
|
if (event.type === "input.requested" && Array.isArray(data.requests)) for (const item of data.requests) {
|
|
36
39
|
const request = object(item);
|
|
37
40
|
const action = object(request.action);
|
|
@@ -47,10 +50,55 @@ function openConfirmations(events) {
|
|
|
47
50
|
const id = object(item).requestId;
|
|
48
51
|
if (typeof id === "string") open.delete(id);
|
|
49
52
|
}
|
|
53
|
+
if (event.type === "action.result") {
|
|
54
|
+
for (const [key, prompt] of open) if (prompt.callId === object(data.result).callId) open.delete(key);
|
|
55
|
+
}
|
|
50
56
|
}
|
|
51
57
|
return [...open.values()];
|
|
52
58
|
}
|
|
59
|
+
function routingConfirmationState(events, prompt, at) {
|
|
60
|
+
if (prompt.state !== void 0 && prompt.state !== "pending" && prompt.state !== "approved") return prompt.state;
|
|
61
|
+
let state = prompt.state ?? "pending";
|
|
62
|
+
let callId;
|
|
63
|
+
for (const event of prompt.mode === "deferred" ? [] : events) {
|
|
64
|
+
const data = object(event.data);
|
|
65
|
+
if ((event.type === "context.cleared" || event.type === "session.started") && Date.parse(event.meta.at) >= Date.parse(prompt.at)) state = "expired";
|
|
66
|
+
if (event.type === "input.requested" && Array.isArray(data.requests)) {
|
|
67
|
+
for (const request of data.requests) if (object(request).requestId === prompt.requestId) {
|
|
68
|
+
callId = String(object(object(request).action).callId);
|
|
69
|
+
state = prompt.state ?? "pending";
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (event.type === "input.resolved" && Array.isArray(data.resolutions)) {
|
|
73
|
+
for (const resolution of data.resolutions) if (object(resolution).requestId === prompt.requestId) state = object(resolution).outcome === "approved" ? "approved" : "cancelled";
|
|
74
|
+
}
|
|
75
|
+
if (event.type === "action.result" && callId !== void 0 && object(data.result).callId === callId) state = data.status === "completed" ? "completed" : "failed";
|
|
76
|
+
}
|
|
77
|
+
if (state === "pending" && Date.parse(at) - Date.parse(prompt.at) >= 6e5) return "expired";
|
|
78
|
+
return state;
|
|
79
|
+
}
|
|
80
|
+
function routingConfirmations(events, recent, at) {
|
|
81
|
+
return openConfirmations(events).filter((prompt) => {
|
|
82
|
+
const age = Date.parse(at) - prompt.at;
|
|
83
|
+
const delivered = recent.findLast((message) => "role" in message && message.confirmation?.requestId === prompt.requestId);
|
|
84
|
+
const state = delivered !== void 0 && "role" in delivered ? delivered.confirmation?.state : void 0;
|
|
85
|
+
return age >= 0 && age < 6e5 && (state === void 0 || state === "pending");
|
|
86
|
+
}).slice(-5).map((prompt) => {
|
|
87
|
+
const delivered = recent.findLast((message) => "role" in message && message.confirmation?.requestId === prompt.requestId);
|
|
88
|
+
const summary = delivered !== void 0 && "role" in delivered ? delivered.confirmation : void 0;
|
|
89
|
+
return {
|
|
90
|
+
state: "pending",
|
|
91
|
+
action: summary?.action ?? "the requested action",
|
|
92
|
+
requestedBy: summary?.requestedBy ?? null,
|
|
93
|
+
at: summary?.at ?? new Date(prompt.at).toISOString()
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
}
|
|
53
97
|
function questionFromHistory(events, owner) {
|
|
98
|
+
const pending = questionsFromHistory(events);
|
|
99
|
+
return owner === void 0 ? pending.at(-1) : pending.find((question) => questionKey(question) === questionKey(owner));
|
|
100
|
+
}
|
|
101
|
+
function questionsFromHistory(events) {
|
|
54
102
|
const pending = new Map();
|
|
55
103
|
for (const event of events) {
|
|
56
104
|
const data = object(event.data);
|
|
@@ -64,7 +112,7 @@ function questionFromHistory(events, owner) {
|
|
|
64
112
|
for (const [key, question] of pending) if (data.message.startsWith(answerMarker(question.id))) pending.delete(key);
|
|
65
113
|
}
|
|
66
114
|
}
|
|
67
|
-
return
|
|
115
|
+
return [...pending.values()];
|
|
68
116
|
}
|
|
69
117
|
function questionAddress(owner) {
|
|
70
118
|
return formatAddress({
|
|
@@ -136,7 +184,31 @@ async function handleConfirmationCallback(input) {
|
|
|
136
184
|
}, edit ? "The chat post was cancelled for editing. Ask the member what to change using questions_ask, then make a NEW chat_post_message call and confirmation. Never reuse the cancelled call." : void 0);
|
|
137
185
|
await notice(expired ? "⌛" : void 0);
|
|
138
186
|
}
|
|
139
|
-
function
|
|
187
|
+
function messagePrompt(message) {
|
|
188
|
+
return message.prompt ?? {
|
|
189
|
+
requestId: message.requestId,
|
|
190
|
+
action: "the requested action",
|
|
191
|
+
requestedBy: null,
|
|
192
|
+
at: new Date().toISOString()
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function telegramConfirmationEvents(archive, observed, deferredOptions) {
|
|
196
|
+
const remember = (channel, ctx, messageId, text, confirmation) => {
|
|
197
|
+
const principal = ctx.session.auth.current;
|
|
198
|
+
const name = humanText(principal?.attributes.memberName);
|
|
199
|
+
observed?.remember(observedChatKey(channel.telegram), {
|
|
200
|
+
...agentMessage({
|
|
201
|
+
text,
|
|
202
|
+
at: new Date().toISOString(),
|
|
203
|
+
messageId,
|
|
204
|
+
...principal?.subject === void 0 || name === void 0 ? {} : { inReplyTo: {
|
|
205
|
+
id: principal.subject,
|
|
206
|
+
author: name
|
|
207
|
+
} }
|
|
208
|
+
}),
|
|
209
|
+
...confirmation === void 0 ? {} : { confirmation }
|
|
210
|
+
});
|
|
211
|
+
};
|
|
140
212
|
const record = async (callId, phase, text, status, ctx) => {
|
|
141
213
|
const saved = confirmations.get()[callId];
|
|
142
214
|
if (archive === void 0 || saved?.description?.chatPost === void 0 || saved.source === void 0) return;
|
|
@@ -184,6 +256,7 @@ function telegramConfirmationEvents(archive) {
|
|
|
184
256
|
text: rendered.text,
|
|
185
257
|
reply_markup: rendered.replyMarkup
|
|
186
258
|
});
|
|
259
|
+
remember(channel, ctx, sent.id, rendered.text);
|
|
187
260
|
if (rendered.freeformRequestId !== void 0) registerTelegramFreeformPrompt(channel.state, {
|
|
188
261
|
messageId: sent.id,
|
|
189
262
|
requestId: request.requestId
|
|
@@ -228,7 +301,30 @@ function telegramConfirmationEvents(archive) {
|
|
|
228
301
|
}
|
|
229
302
|
]] }
|
|
230
303
|
});
|
|
231
|
-
const
|
|
304
|
+
const prompt = {
|
|
305
|
+
requestId: request.requestId,
|
|
306
|
+
state: "pending",
|
|
307
|
+
sessionId: ctx.session.id,
|
|
308
|
+
address: channel.continuation?.token ?? formatAddress({
|
|
309
|
+
chatId: channel.telegram.chatId,
|
|
310
|
+
messageThreadId: String(channel.telegram.messageThreadId ?? ""),
|
|
311
|
+
conversationId: channel.telegram.conversationId ?? ""
|
|
312
|
+
}),
|
|
313
|
+
action: humanText(description?.action) ?? "the requested action",
|
|
314
|
+
requestedBy: humanText(ctx.session.auth.current?.attributes.memberName) ?? null,
|
|
315
|
+
at: new Date().toISOString(),
|
|
316
|
+
...ctx.session.auth.current?.subject === void 0 ? {} : { requester: {
|
|
317
|
+
id: ctx.session.auth.current.subject,
|
|
318
|
+
author: humanText(ctx.session.auth.current.attributes.memberName) ?? "the requester"
|
|
319
|
+
} }
|
|
320
|
+
};
|
|
321
|
+
const sent = await withConfirmationPrompt(prompt, () => exactPost ? withChatPostCard(text, send, copy.previewLinks) : withConfirmationText(text, send));
|
|
322
|
+
remember(channel, ctx, sent.id, text, prompt);
|
|
323
|
+
channel.continuation?.alias(formatAddress({
|
|
324
|
+
chatId: channel.telegram.chatId,
|
|
325
|
+
messageThreadId: String(channel.telegram.messageThreadId ?? ""),
|
|
326
|
+
conversationId: ""
|
|
327
|
+
}));
|
|
232
328
|
const state = channel.state;
|
|
233
329
|
state.confirmationMessages = {
|
|
234
330
|
...state.confirmationMessages,
|
|
@@ -238,6 +334,7 @@ function telegramConfirmationEvents(archive) {
|
|
|
238
334
|
text,
|
|
239
335
|
copy,
|
|
240
336
|
exactPost,
|
|
337
|
+
prompt,
|
|
241
338
|
previewLinks: copy.previewLinks
|
|
242
339
|
}
|
|
243
340
|
};
|
|
@@ -271,7 +368,13 @@ function telegramConfirmationEvents(archive) {
|
|
|
271
368
|
replyMarkup: { inline_keyboard: [] },
|
|
272
369
|
text
|
|
273
370
|
});
|
|
274
|
-
|
|
371
|
+
const prompt = {
|
|
372
|
+
...messagePrompt(message),
|
|
373
|
+
state: resolution.outcome === "approved" ? "approved" : reason === "expired" ? "expired" : "cancelled"
|
|
374
|
+
};
|
|
375
|
+
message.prompt = prompt;
|
|
376
|
+
await withConfirmationPrompt(prompt, () => message.exactPost ? withChatPostCard(text, edit, [...message.previewLinks ?? [], ...telegramTextLinks(status)]) : withConfirmationText(text, edit));
|
|
377
|
+
remember(channel, ctx, message.messageId, text, prompt);
|
|
275
378
|
await record(callId, reason ?? resolution.outcome, text, resolution.outcome === "approved" ? "requested" : "cancelled", ctx);
|
|
276
379
|
if (resolution.outcome !== "approved") {
|
|
277
380
|
delete state.confirmationMessages?.[callId];
|
|
@@ -287,6 +390,13 @@ function telegramConfirmationEvents(archive) {
|
|
|
287
390
|
},
|
|
288
391
|
async "action.result"(data, channel, ctx) {
|
|
289
392
|
const state = channel.state;
|
|
393
|
+
if (data.result.kind === "tool-result" && deferredOptions !== void 0 && archive !== void 0) {
|
|
394
|
+
const output = object(data.result.output);
|
|
395
|
+
if (output.status === "awaiting_confirmation" && typeof output.confirmation === "string") {
|
|
396
|
+
await postDeferredCard(output.confirmation, channel, ctx, deferredOptions, archive, observed);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
290
400
|
if (data.result.kind === "tool-result") {
|
|
291
401
|
const question = object(data.result.output).pendingQuestion;
|
|
292
402
|
if (data.result.toolName.endsWith("__questions_ask") && isPendingQuestion(question)) {
|
|
@@ -313,13 +423,14 @@ function telegramConfirmationEvents(archive) {
|
|
|
313
423
|
conversationId: ""
|
|
314
424
|
}));
|
|
315
425
|
channel.continuation?.alias(questionAddress(saved));
|
|
316
|
-
await channel.telegram.post({
|
|
426
|
+
const sent = await channel.telegram.post({
|
|
317
427
|
text: question.question,
|
|
318
428
|
reply_markup: {
|
|
319
429
|
force_reply: true,
|
|
320
430
|
selective: true
|
|
321
431
|
}
|
|
322
432
|
});
|
|
433
|
+
remember(channel, ctx, sent.id, question.question);
|
|
323
434
|
}
|
|
324
435
|
}
|
|
325
436
|
const message = state.confirmationMessages?.[data.result.callId];
|
|
@@ -331,22 +442,32 @@ function telegramConfirmationEvents(archive) {
|
|
|
331
442
|
const errorId = failed ? reportTelegramError("confirmed_chat_post_failed", data, { callId: data.result.callId }) : void 0;
|
|
332
443
|
const status = receipt ?? (failed ? `${copy.failed} ${errorId}\n⚠️ ❓` : "⚠️ ❓");
|
|
333
444
|
const text = chatPostCardStatus(message.text, status);
|
|
334
|
-
|
|
445
|
+
const prompt = {
|
|
446
|
+
...messagePrompt(message),
|
|
447
|
+
state: failed ? "failed" : "completed"
|
|
448
|
+
};
|
|
449
|
+
await withConfirmationPrompt(prompt, () => withChatPostCard(text, () => channel.telegram.editMessageText({
|
|
335
450
|
messageId: message.messageId,
|
|
336
451
|
replyMarkup: { inline_keyboard: [] },
|
|
337
452
|
text
|
|
338
|
-
}), [...message.previewLinks ?? [], ...telegramTextLinks(status)]);
|
|
453
|
+
}), [...message.previewLinks ?? [], ...telegramTextLinks(status)]));
|
|
454
|
+
remember(channel, ctx, message.messageId, text, prompt);
|
|
339
455
|
await record(data.result.callId, "receipt", text, failed ? "failed" : object(data.result.kind === "tool-result" ? data.result.output : void 0).status === "sent" ? "completed" : "unknown", ctx);
|
|
340
456
|
} else {
|
|
341
457
|
const copy = message.copy ?? renderConfirmation();
|
|
342
458
|
const errorId = failed ? reportTelegramError("confirmed_action_failed", data, { callId: data.result.callId }) : void 0;
|
|
343
459
|
const status = failed ? `${copy.failed} ${errorId}` : copy.completed;
|
|
344
460
|
const text = `${message.text}\n\n${status}`;
|
|
345
|
-
|
|
461
|
+
const prompt = {
|
|
462
|
+
...messagePrompt(message),
|
|
463
|
+
state: failed ? "failed" : "completed"
|
|
464
|
+
};
|
|
465
|
+
await withConfirmationPrompt(prompt, () => withConfirmationText(text, () => channel.telegram.editMessageText({
|
|
346
466
|
messageId: message.messageId,
|
|
347
467
|
replyMarkup: { inline_keyboard: [] },
|
|
348
468
|
text
|
|
349
|
-
}));
|
|
469
|
+
})));
|
|
470
|
+
remember(channel, ctx, message.messageId, text, prompt);
|
|
350
471
|
}
|
|
351
472
|
delete state.confirmationMessages?.[data.result.callId];
|
|
352
473
|
},
|
|
@@ -368,4 +489,4 @@ function telegramConfirmationEvents(archive) {
|
|
|
368
489
|
};
|
|
369
490
|
}
|
|
370
491
|
const confirmationEvents = telegramConfirmationEvents();
|
|
371
|
-
export { confirmationCallback, confirmationEvents, handleConfirmationCallback, questionAddress, questionFromHistory, telegramConfirmationEvents };
|
|
492
|
+
export { confirmationCallback, confirmationEvents, handleConfirmationCallback, questionAddress, questionFromHistory, questionsFromHistory, routingConfirmationState, routingConfirmations, telegramConfirmationEvents };
|
|
@@ -2,7 +2,10 @@ import type { AgentIdentities } from "../identities.js";
|
|
|
2
2
|
import { type Conversations } from "../conversations.js";
|
|
3
3
|
import type { AgentChats } from "./chats.js";
|
|
4
4
|
import type { ObservedMessages } from "./observed.js";
|
|
5
|
+
import type { DecodedAttachment } from "./attachment-description.js";
|
|
5
6
|
import type { AddressingReason, RouteDecider, RouteDecision } from "./router.js";
|
|
7
|
+
/** A crashed routing attempt can be reclaimed; the per-message turn claim still fences dispatch. */
|
|
8
|
+
export declare const REVISION_CLAIM_TTL_MS: number;
|
|
6
9
|
/** Runs after webhook verification, before eve drops bot/channel/service updates. */
|
|
7
10
|
export declare function captureTelegramWebhook(input: {
|
|
8
11
|
readonly request: Request;
|
|
@@ -14,8 +17,14 @@ export declare function captureTelegramWebhook(input: {
|
|
|
14
17
|
}): Promise<Response>;
|
|
15
18
|
/** Additive inbound hook: the router keeps ownership of the reply policy. */
|
|
16
19
|
export declare function recordGateDecision(reason: string, decision?: "reply" | "silent"): void;
|
|
17
|
-
export declare function recordRouteDecision(route: "reply" | "observe", addressed: boolean | AddressingReason | undefined, policy: string, audit?: Pick<RouteDecision, "reason" | "note">): void;
|
|
20
|
+
export declare function recordRouteDecision(route: "reply" | "observe", addressed: boolean | AddressingReason | undefined, policy: string, audit?: Pick<RouteDecision, "reason" | "note" | "diagnostics">): void;
|
|
18
21
|
export declare function captureRouteDecider(decide: RouteDecider): RouteDecider;
|
|
22
|
+
/** Update the existing inbound event after STT/description, under the same text retention policy. */
|
|
23
|
+
export declare function recordInboundContent(content: {
|
|
24
|
+
readonly text: string;
|
|
25
|
+
readonly media?: string;
|
|
26
|
+
readonly decoded?: ReadonlyArray<DecodedAttachment>;
|
|
27
|
+
}): Promise<void>;
|
|
19
28
|
/** Captures message sends and button/status edits, including pairing and proactive replies. */
|
|
20
29
|
export declare function captureTelegramFetch(fetchImpl: typeof fetch, archive: Conversations, identities: () => AgentIdentities): typeof fetch;
|
|
21
30
|
/** Reuses the request's verified lookup; it never survives into another inbound request. */
|
|
@@ -4,16 +4,18 @@ import { createRequire as __eveCreateRequire } from "node:module";
|
|
|
4
4
|
const __filename = __eveFileURLToPath(import.meta.url);
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { n as currentInboundRequest, s as currentThreadId } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
|
|
10
|
-
import { reportMembership } from "./membership.mjs";
|
|
7
|
+
import { conversationEvent } from "../conversations.mjs";
|
|
8
|
+
import { n as currentInboundRequest, s as currentThreadId } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
|
|
11
9
|
import { contentShape, messageContent } from "./content.mjs";
|
|
12
|
-
import {
|
|
10
|
+
import { currentConfirmationPrompt, messageMetadata, observedChatKey } from "./observed.mjs";
|
|
11
|
+
import { archivedRoutingMessages } from "./routing-context.mjs";
|
|
12
|
+
import { reportMembership } from "./membership.mjs";
|
|
13
13
|
import { createHash, randomUUID } from "node:crypto";
|
|
14
|
+
import { parseTelegramUpdate } from "eve/channels/telegram";
|
|
14
15
|
const captures = new WeakMap();
|
|
15
16
|
const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
16
17
|
const id = (value) => typeof value === "number" || typeof value === "string" ? String(value) : null;
|
|
18
|
+
const REVISION_CLAIM_TTL_MS = 12e4;
|
|
17
19
|
function attachmentRefs(message) {
|
|
18
20
|
const files = message.attachments.map((file) => ({
|
|
19
21
|
id: file.fileId,
|
|
@@ -44,6 +46,16 @@ function attachmentRefs(message) {
|
|
|
44
46
|
}
|
|
45
47
|
return files;
|
|
46
48
|
}
|
|
49
|
+
function attachmentIdentity(files) {
|
|
50
|
+
return JSON.stringify(files.map((file) => [file.kind, file.uniqueId ?? file.id]));
|
|
51
|
+
}
|
|
52
|
+
function eventRouting(event) {
|
|
53
|
+
try {
|
|
54
|
+
return record(record(JSON.parse(event.argsSummary ?? "{}")).routing);
|
|
55
|
+
} catch {
|
|
56
|
+
return {};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
47
59
|
async function participants(message, identities, resolved) {
|
|
48
60
|
if (message.chat.type !== "private" || message.from === void 0 || message.from.isBot) return [];
|
|
49
61
|
try {
|
|
@@ -85,6 +97,7 @@ async function captureTelegramWebhook(input) {
|
|
|
85
97
|
const time = edited === void 0 ? message.raw.date : message.raw.edit_date ?? message.raw.date;
|
|
86
98
|
const sentAt = typeof time === "number" ? time * 1e3 : Date.now();
|
|
87
99
|
const senderChat = record(message.raw.sender_chat);
|
|
100
|
+
const attachments = attachmentRefs(message);
|
|
88
101
|
let lookup;
|
|
89
102
|
const event = conversationEvent({
|
|
90
103
|
eventId: [
|
|
@@ -99,7 +112,13 @@ async function captureTelegramWebhook(input) {
|
|
|
99
112
|
threadId: message.messageThreadId === void 0 ? null : String(message.messageThreadId),
|
|
100
113
|
kind: "inbound",
|
|
101
114
|
text: content.text || null,
|
|
102
|
-
argsSummary: JSON.stringify(
|
|
115
|
+
argsSummary: JSON.stringify({
|
|
116
|
+
...contentShape(message.raw, content),
|
|
117
|
+
routing: {
|
|
118
|
+
...messageMetadata(message),
|
|
119
|
+
...attachments.length === 0 ? {} : { originalText: content.text }
|
|
120
|
+
}
|
|
121
|
+
}),
|
|
103
122
|
messageId: message.messageId,
|
|
104
123
|
replyToMessageId: message.replyToMessage?.messageId ?? null,
|
|
105
124
|
senderId: id(senderChat.id) ?? message.from?.id ?? null,
|
|
@@ -108,15 +127,33 @@ async function captureTelegramWebhook(input) {
|
|
|
108
127
|
participantIds: await participants(message, input.identities, (result) => {
|
|
109
128
|
lookup = result;
|
|
110
129
|
}),
|
|
111
|
-
attachments
|
|
130
|
+
attachments,
|
|
112
131
|
at: new Date(sentAt).toISOString()
|
|
113
132
|
});
|
|
114
133
|
await input.archive.append(event);
|
|
115
134
|
const capture = {
|
|
116
135
|
event,
|
|
117
136
|
message,
|
|
137
|
+
archive: input.archive,
|
|
118
138
|
...lookup === void 0 ? {} : { lookup }
|
|
119
139
|
};
|
|
140
|
+
const revisionId = edited === void 0 ? void 0 : `telegram:${message.chat.id}:${message.messageId}:routing:${createHash("sha256").update(JSON.stringify({
|
|
141
|
+
at: event.at,
|
|
142
|
+
content,
|
|
143
|
+
...event.attachments.length === 0 ? {} : { attachments: attachmentIdentity(event.attachments) }
|
|
144
|
+
})).digest("hex")}`;
|
|
145
|
+
const revisionEvents = [];
|
|
146
|
+
let revisionClaim;
|
|
147
|
+
const finishRevision = async (status) => {
|
|
148
|
+
if (revisionClaim === void 0) return;
|
|
149
|
+
await input.archive.append({
|
|
150
|
+
...revisionClaim,
|
|
151
|
+
eventId: status === "completed" ? `${revisionId}:completed` : `${revisionClaim.eventId}:failed`,
|
|
152
|
+
at: new Date(Date.now()).toISOString(),
|
|
153
|
+
status,
|
|
154
|
+
reason: status === "completed" ? "routing_completed" : "routing_failed"
|
|
155
|
+
});
|
|
156
|
+
};
|
|
120
157
|
const inbound = currentInboundRequest();
|
|
121
158
|
if (inbound !== void 0) captures.set(inbound, capture);
|
|
122
159
|
const chat = observedChatKey({
|
|
@@ -132,37 +169,88 @@ async function captureTelegramWebhook(input) {
|
|
|
132
169
|
includeDecisions: true,
|
|
133
170
|
...lookup?.status === "paired" ? { participantId: lookup.member.id } : {}
|
|
134
171
|
});
|
|
135
|
-
const
|
|
172
|
+
const messageHistory = automated ? [] : (await input.archive.context({
|
|
136
173
|
provider: "telegram",
|
|
137
174
|
chatId: message.chat.id,
|
|
138
175
|
messageId: message.messageId,
|
|
139
176
|
includeDecisions: true,
|
|
140
177
|
limit: 100,
|
|
141
178
|
...lookup?.status === "paired" ? { participantId: lookup.member.id } : {}
|
|
142
|
-
})).events
|
|
179
|
+
})).events;
|
|
180
|
+
const routing = messageHistory.filter((earlier) => earlier.kind === "decision" && earlier.senderId === event.senderId);
|
|
143
181
|
const previousClaim = routing.find((earlier) => earlier.reason === "turn_claimed");
|
|
144
182
|
const admitted = routing.some((earlier) => earlier.reason === "turn_admitted");
|
|
145
183
|
const released = previousClaim !== void 0 && routing.some((earlier) => earlier.eventId === `${previousClaim.eventId}:released`);
|
|
146
184
|
const dispatched = routing.some((earlier) => earlier.reason === "turn_dispatch_started");
|
|
147
185
|
const reserved = previousClaim !== void 0 && !released && Date.now() - Date.parse(previousClaim.at) < 6e5;
|
|
148
186
|
const alreadyHandled = admitted || dispatched || reserved;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
187
|
+
const rememberRevision = (events) => {
|
|
188
|
+
if (revisionId !== void 0) revisionEvents.push(...events.filter((item) => item.eventId === revisionId || item.eventId.startsWith(`${revisionId}:`)));
|
|
189
|
+
};
|
|
190
|
+
const historyEvents = [...messageHistory];
|
|
191
|
+
rememberRevision(historyEvents);
|
|
192
|
+
const previousRevision = (earlier) => earlier.kind === "inbound" && earlier.messageId === message.messageId && earlier.senderId === event.senderId && earlier.eventId !== event.eventId && !(edited !== void 0 && earlier.eventId.includes(":edit:") && earlier.at === event.at && (eventRouting(earlier).originalText ?? earlier.text) === content.text && attachmentIdentity(earlier.attachments) === attachmentIdentity(event.attachments));
|
|
193
|
+
const previous = messageHistory.find(previousRevision);
|
|
194
|
+
const unchangedAttachments = previous !== void 0 && attachmentIdentity(previous.attachments) === attachmentIdentity(event.attachments);
|
|
195
|
+
const previousRouting = previous === void 0 ? {} : eventRouting(previous);
|
|
196
|
+
const originalEvent = previous === void 0 ? void 0 : historyEvents.find((item) => item.eventId === previous.eventId.split(":content:")[0]);
|
|
197
|
+
if (inbound !== void 0) {
|
|
198
|
+
inbound.previousText = typeof previousRouting.originalText === "string" ? previousRouting.originalText : originalEvent?.text ?? previous?.text ?? void 0;
|
|
199
|
+
inbound.attachmentsChanged = previous === void 0 ? event.attachments.length > 0 : !unchangedAttachments;
|
|
200
|
+
if (unchangedAttachments && event.attachments.length > 0) {
|
|
201
|
+
const decoded = Array.isArray(previousRouting.decoded) ? previousRouting.decoded : [];
|
|
202
|
+
const media = typeof previousRouting.media === "string" ? previousRouting.media : void 0;
|
|
203
|
+
const metadata = record(JSON.parse(capture.event.argsSummary ?? "{}"));
|
|
204
|
+
capture.event = {
|
|
205
|
+
...capture.event,
|
|
206
|
+
argsSummary: JSON.stringify({
|
|
207
|
+
...metadata,
|
|
208
|
+
routing: {
|
|
209
|
+
...record(metadata.routing),
|
|
210
|
+
membership: previousRouting.membership
|
|
211
|
+
}
|
|
212
|
+
})
|
|
213
|
+
};
|
|
214
|
+
inbound.previousContent = {
|
|
215
|
+
decoded,
|
|
216
|
+
...media === void 0 ? {} : { media }
|
|
217
|
+
};
|
|
218
|
+
const transcripts = decoded.flatMap((item) => [
|
|
219
|
+
"voice",
|
|
220
|
+
"audio",
|
|
221
|
+
"video_note"
|
|
222
|
+
].includes(item.attachment_kind) && item.processed && typeof item.content === "string" ? [item.content] : []);
|
|
223
|
+
await recordInboundContent({
|
|
224
|
+
text: [content.text, ...transcripts].filter(Boolean).join("\n\n"),
|
|
225
|
+
decoded,
|
|
226
|
+
...media === void 0 ? {} : { media }
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (!automated) for (const earlier of input.observed.recent(chat).length === 0 ? archivedRoutingMessages((history?.events ?? []).filter((item) => item.eventId !== event.eventId)) : []) if ("role" in earlier || history?.events.some((decision) => decision.kind === "decision" && decision.messageId === earlier.messageId && decision.reason === "turn_admitted")) input.observed.remember(chat, earlier);
|
|
231
|
+
else input.observed.add(chat, earlier);
|
|
232
|
+
if (automated || edited !== void 0) {
|
|
157
233
|
if (message.chat.type === "group" || message.chat.type === "supergroup") await input.chats?.seen({
|
|
158
234
|
chatId: message.chat.id,
|
|
159
235
|
title: message.chat.title ?? ""
|
|
160
236
|
});
|
|
161
|
-
input.observed.
|
|
237
|
+
const remembered = input.observed.recent(chat).findLast((entry) => entry.messageId === message.messageId);
|
|
238
|
+
const retained = alreadyHandled && edited === void 0 ? remembered : void 0;
|
|
239
|
+
const retainedContent = archivedRoutingMessages([{
|
|
240
|
+
...capture.event,
|
|
241
|
+
sequence: "1",
|
|
242
|
+
storedAt: event.at
|
|
243
|
+
}])[0];
|
|
244
|
+
input.observed.add(chat, retained ?? (retainedContent === void 0 ? void 0 : {
|
|
245
|
+
...retainedContent,
|
|
246
|
+
...unchangedAttachments && remembered?.images !== void 0 ? { images: remembered.images } : {}
|
|
247
|
+
}) ?? {
|
|
248
|
+
...messageMetadata(message),
|
|
162
249
|
author: event.senderName ?? event.senderId ?? "automated post",
|
|
163
250
|
text: event.text ?? "[attachment or service message]",
|
|
164
251
|
at: event.at,
|
|
165
|
-
messageId: message.messageId
|
|
252
|
+
messageId: message.messageId,
|
|
253
|
+
...event.senderId === null ? {} : { authorId: event.senderId }
|
|
166
254
|
});
|
|
167
255
|
capture.decision = "silent";
|
|
168
256
|
capture.reason = automated ? "automated_or_channel_message" : alreadyHandled ? "message_already_handled" : "message_edit";
|
|
@@ -174,6 +262,27 @@ async function captureTelegramWebhook(input) {
|
|
|
174
262
|
}
|
|
175
263
|
if (inbound !== void 0) {
|
|
176
264
|
inbound.edited = edited !== void 0;
|
|
265
|
+
if (revisionId !== void 0) inbound.claimRevision = async () => {
|
|
266
|
+
if (revisionEvents.some((item) => item.eventId === `${revisionId}:completed`)) return false;
|
|
267
|
+
const claims = revisionEvents.filter((item) => item.reason === "routing_claimed");
|
|
268
|
+
const latest = claims[0];
|
|
269
|
+
if (latest !== void 0 && !revisionEvents.some((item) => item.eventId === `${latest.eventId}:failed`) && Date.now() - Date.parse(latest.at) < 12e4) return false;
|
|
270
|
+
const attempt = claims.length === 0 ? void 0 : Math.max(...claims.map((item) => Number(item.eventId.slice(revisionId.length).replace(":retry:", "")))) + 1;
|
|
271
|
+
const claim = {
|
|
272
|
+
...event,
|
|
273
|
+
eventId: attempt === void 0 ? revisionId : `${revisionId}:retry:${attempt}`,
|
|
274
|
+
at: new Date(Date.now()).toISOString(),
|
|
275
|
+
kind: "decision",
|
|
276
|
+
decision: "silent",
|
|
277
|
+
reason: "routing_claimed",
|
|
278
|
+
status: "requested",
|
|
279
|
+
text: null,
|
|
280
|
+
attachments: []
|
|
281
|
+
};
|
|
282
|
+
const inserted = await input.archive.append(claim);
|
|
283
|
+
if (inserted !== false) revisionClaim = claim;
|
|
284
|
+
return inserted !== false;
|
|
285
|
+
};
|
|
177
286
|
const nextClaim = previousClaim === void 0 ? void 0 : createHash("sha256").update(previousClaim.eventId).digest("hex");
|
|
178
287
|
const claimId = previousClaim === void 0 ? `telegram:${message.chat.id}:${message.messageId}:turn` : `telegram:${message.chat.id}:${message.messageId}:turn:${nextClaim}`;
|
|
179
288
|
let claimed = false;
|
|
@@ -232,6 +341,7 @@ async function captureTelegramWebhook(input) {
|
|
|
232
341
|
reason: "inbound_handler_failed",
|
|
233
342
|
attachments: []
|
|
234
343
|
});
|
|
344
|
+
await finishRevision("failed");
|
|
235
345
|
} catch (storageError) {
|
|
236
346
|
console.error("[segmentstream] recording inbound failure failed", {
|
|
237
347
|
storageError,
|
|
@@ -245,12 +355,16 @@ async function captureTelegramWebhook(input) {
|
|
|
245
355
|
...event,
|
|
246
356
|
eventId: `${event.eventId}:decision`,
|
|
247
357
|
kind: "decision",
|
|
248
|
-
argsSummary:
|
|
358
|
+
argsSummary: JSON.stringify({
|
|
359
|
+
...capture.diagnostics === void 0 ? {} : { decision: capture.diagnostics },
|
|
360
|
+
routing: { membership: capture.lookup === void 0 ? "unknown" : capture.lookup.status === "paired" ? "linked" : "unlinked" }
|
|
361
|
+
}),
|
|
249
362
|
text: capture.note ?? (edited !== void 0 ? "Message edit recorded as context; no agent turn started." : null),
|
|
250
363
|
decision: capture.decision ?? "silent",
|
|
251
364
|
reason: capture.reason ?? (message.raw.left_chat_member ? "member_departure" : message.raw.migrate_to_chat_id || message.raw.migrate_from_chat_id ? "chat_migration" : "unpaired_refused_or_empty_message"),
|
|
252
365
|
attachments: []
|
|
253
366
|
});
|
|
367
|
+
await finishRevision(capture.reason === "inbound_message_failed" || capture.reason === "decision_model_failed" || capture.reason === "decision_model_timeout" ? "failed" : "completed");
|
|
254
368
|
return response;
|
|
255
369
|
}
|
|
256
370
|
function recordGateDecision(reason, decision = "silent") {
|
|
@@ -269,6 +383,7 @@ function recordRouteDecision(route, addressed, policy, audit) {
|
|
|
269
383
|
capture.decision = route === "reply" ? "reply" : "silent";
|
|
270
384
|
capture.reason ??= audit?.reason ?? (typeof addressed === "string" ? addressed : addressed ? "addressed_message" : policy === "mention" ? "mention_policy" : `decision_model_${route}`);
|
|
271
385
|
capture.note = audit?.note.slice(0, 500);
|
|
386
|
+
capture.diagnostics = audit?.diagnostics;
|
|
272
387
|
}
|
|
273
388
|
}
|
|
274
389
|
function captureRouteDecider(decide) {
|
|
@@ -283,6 +398,34 @@ function captureRouteDecider(decide) {
|
|
|
283
398
|
}
|
|
284
399
|
};
|
|
285
400
|
}
|
|
401
|
+
async function recordInboundContent(content) {
|
|
402
|
+
const inbound = currentInboundRequest();
|
|
403
|
+
const capture = inbound === void 0 ? void 0 : captures.get(inbound);
|
|
404
|
+
if (capture?.archive === void 0) return;
|
|
405
|
+
const metadata = record(JSON.parse(capture.event.argsSummary ?? "{}"));
|
|
406
|
+
const membership = capture.lookup === void 0 ? record(metadata.routing).membership : capture.lookup.status === "paired" ? "linked" : "unlinked";
|
|
407
|
+
if (content.text === capture.event.text && content.media === record(metadata.routing).media && membership === record(metadata.routing).membership && JSON.stringify(content.decoded) === JSON.stringify(record(metadata.routing).decoded)) return;
|
|
408
|
+
const contentHash = createHash("sha256").update(JSON.stringify({
|
|
409
|
+
...content,
|
|
410
|
+
membership
|
|
411
|
+
})).digest("hex").slice(0, 16);
|
|
412
|
+
const event = {
|
|
413
|
+
...capture.event,
|
|
414
|
+
eventId: `${capture.event.eventId}:content:${contentHash}`,
|
|
415
|
+
text: content.text,
|
|
416
|
+
argsSummary: JSON.stringify({
|
|
417
|
+
...metadata,
|
|
418
|
+
routing: {
|
|
419
|
+
...record(metadata.routing),
|
|
420
|
+
membership,
|
|
421
|
+
media: content.media?.slice(0, 8e3),
|
|
422
|
+
decoded: content.decoded
|
|
423
|
+
}
|
|
424
|
+
})
|
|
425
|
+
};
|
|
426
|
+
await capture.archive.append(event);
|
|
427
|
+
capture.event = event;
|
|
428
|
+
}
|
|
286
429
|
function captureTelegramFetch(fetchImpl, archive, identities) {
|
|
287
430
|
return async (input, init) => {
|
|
288
431
|
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
@@ -316,6 +459,15 @@ function captureTelegramFetch(fetchImpl, archive, identities) {
|
|
|
316
459
|
senderIsBot: true,
|
|
317
460
|
senderId: "agent",
|
|
318
461
|
senderName: "agent",
|
|
462
|
+
argsSummary: JSON.stringify({ routing: {
|
|
463
|
+
...currentConfirmationPrompt() === void 0 ? {} : { confirmation: currentConfirmationPrompt() },
|
|
464
|
+
...capture?.event.chatId === chatId && capture.event.senderId !== null ? { inReplyTo: {
|
|
465
|
+
id: capture.event.senderId,
|
|
466
|
+
author: capture.event.senderName ?? capture.event.senderId,
|
|
467
|
+
...capture.message.from?.username === void 0 ? {} : { username: capture.message.from.username }
|
|
468
|
+
} } : {},
|
|
469
|
+
...currentConfirmationPrompt()?.requester === void 0 ? {} : { inReplyTo: currentConfirmationPrompt()?.requester }
|
|
470
|
+
} }),
|
|
319
471
|
participantIds,
|
|
320
472
|
threadId: id(body.message_thread_id) ?? currentThreadId() ?? null,
|
|
321
473
|
replyToMessageId: id(body.reply_to_message_id) ?? id(record(body.reply_parameters).message_id),
|
|
@@ -358,7 +510,10 @@ function conversationIdentities(identities) {
|
|
|
358
510
|
lookup: async (account) => {
|
|
359
511
|
const inbound = currentInboundRequest();
|
|
360
512
|
const capture = inbound === void 0 ? void 0 : captures.get(inbound);
|
|
361
|
-
|
|
513
|
+
if (account.provider === "telegram" && capture?.message.from?.id === account.externalId && capture.lookup !== void 0) return capture.lookup;
|
|
514
|
+
const lookup = await identities.lookup(account);
|
|
515
|
+
if (account.provider === "telegram" && capture?.message.from?.id === account.externalId) capture.lookup = lookup;
|
|
516
|
+
return lookup;
|
|
362
517
|
}
|
|
363
518
|
};
|
|
364
519
|
}
|
|
@@ -394,4 +549,4 @@ function telegramConversationCapture(input) {
|
|
|
394
549
|
}
|
|
395
550
|
};
|
|
396
551
|
}
|
|
397
|
-
export { captureRouteDecider, captureTelegramFetch, captureTelegramWebhook, conversationIdentities, recordGateDecision, recordRouteDecision, telegramConversationCapture };
|
|
552
|
+
export { REVISION_CLAIM_TTL_MS, captureRouteDecider, captureTelegramFetch, captureTelegramWebhook, conversationIdentities, recordGateDecision, recordInboundContent, recordRouteDecision, telegramConversationCapture };
|
|
@@ -5,5 +5,5 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { isTechnicalText } from "../customer-text-safety.mjs";
|
|
8
|
-
import { a as TelegramDeliveryError, c as customerCopy, d as failureText, f as formattingRefused, h as withDeliveryLocale, l as customerMessage, m as safeTelegramFetch, o as currentLocale, p as reportTelegramError, s as currentThreadId, u as customerText } from "../../../_chunks/inbound-request-
|
|
8
|
+
import { a as TelegramDeliveryError, c as customerCopy, d as failureText, f as formattingRefused, h as withDeliveryLocale, l as customerMessage, m as safeTelegramFetch, o as currentLocale, p as reportTelegramError, s as currentThreadId, u as customerText } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
|
|
9
9
|
export { TelegramDeliveryError, currentLocale, currentThreadId, customerCopy, customerMessage, customerText, failureText, formattingRefused, isTechnicalText, reportTelegramError, safeTelegramFetch, withDeliveryLocale };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { TelegramCallbackQuery, TelegramContext, TelegramHandle, TelegramEventContext } from "eve/channels/telegram";
|
|
2
|
+
import type { SessionContext } from "eve/context";
|
|
3
|
+
import { type DeferredConfirmation, type DeferredOptions } from "../deferred-confirmations.js";
|
|
4
|
+
import { type Conversations } from "../conversations.js";
|
|
5
|
+
import type { AgentIdentities } from "../identities.js";
|
|
6
|
+
import { type ObservedMessages } from "./observed.js";
|
|
7
|
+
export declare const isDeferredCallback: (data?: string) => boolean;
|
|
8
|
+
export declare const deferredCallback: (record: DeferredConfirmation, choice: "y" | "n" | "e") => string;
|
|
9
|
+
export declare function archiveDeferred(record: DeferredConfirmation, phase: string, archive: Conversations): Promise<void>;
|
|
10
|
+
/** Called at the durable tool-result boundary. Pending cards never become eve input requests. */
|
|
11
|
+
export declare function postDeferredCard(id: string, channel: TelegramEventContext, ctx: SessionContext, options: DeferredOptions, archive: Conversations, observed?: ObservedMessages): Promise<void>;
|
|
12
|
+
/** Every callback re-resolves the live identity. The database arbitrates concurrent presses. */
|
|
13
|
+
export declare function handleDeferredCallback(input: {
|
|
14
|
+
readonly context: TelegramContext;
|
|
15
|
+
readonly query: TelegramCallbackQuery;
|
|
16
|
+
readonly identities: AgentIdentities;
|
|
17
|
+
readonly archive: Conversations;
|
|
18
|
+
readonly options: DeferredOptions;
|
|
19
|
+
readonly observed?: ObservedMessages;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
/** A database-clock expiry claim is shared by webhooks and the minute schedule. */
|
|
22
|
+
export declare function expireDeferredRecord(record: DeferredConfirmation, context: {
|
|
23
|
+
readonly telegram: Pick<TelegramHandle, "editMessageText">;
|
|
24
|
+
}, options: DeferredOptions, archive: Conversations, notify: NonNullable<import("./inbound-request.js").InboundRequest["confirmationEvent"]>, observed?: ObservedMessages): Promise<void>;
|
|
25
|
+
/** Webhooks also reconcile expiry if the host's minute scheduler is delayed. */
|
|
26
|
+
export declare function expireDeferredCards(context: TelegramContext, options: DeferredOptions, archive: Conversations, observed?: ObservedMessages): Promise<void>;
|