@segmentstream/agent 0.26.1 → 0.27.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 -43
- package/dist/_chunks/{build-metadata-D_Gqlb5f.mjs → build-metadata-R_ssK2uR.mjs} +1 -1
- package/dist/extension/config.d.ts +11 -12
- package/dist/extension/config.mjs +13 -36
- package/dist/extension/extension.d.ts +1 -1
- package/dist/extension/extension.mjs +2 -2
- package/dist/extension/hooks/chat-context.d.ts +3 -0
- package/dist/extension/hooks/chat-context.mjs +10 -0
- package/dist/extension/hooks/sandbox.d.ts +2 -3
- package/dist/extension/instructions/conversations.d.ts +3 -2
- package/dist/extension/instructions/conversations.mjs +7 -11
- package/dist/extension/instructions.md +18 -0
- package/dist/extension/lib/build-metadata.mjs +1 -1
- package/dist/extension/lib/chat-context.d.ts +108 -0
- package/dist/extension/lib/chat-context.mjs +217 -0
- package/dist/extension/lib/conversations.d.ts +10 -6
- package/dist/extension/lib/conversations.mjs +28 -42
- package/dist/extension/lib/group-routing/burst.d.ts +1 -1
- package/dist/extension/lib/group-routing/conversation.d.ts +1 -1
- package/dist/extension/lib/group-routing/engagement.d.ts +1 -1
- package/dist/extension/lib/group-routing/{observed.d.ts → messages.d.ts} +9 -31
- package/dist/extension/lib/group-routing/messages.mjs +38 -0
- package/dist/extension/lib/group-routing/router.d.ts +3 -9
- package/dist/extension/lib/group-routing/router.mjs +2 -4
- package/dist/extension/lib/group-routing/routing-context.d.ts +6 -2
- package/dist/extension/lib/group-routing/routing-context.mjs +12 -1
- package/dist/extension/lib/telegram/adapter.d.ts +1 -3
- package/dist/extension/lib/telegram/adapter.mjs +9 -18
- package/dist/extension/lib/telegram/confirmations.d.ts +3 -3
- package/dist/extension/lib/telegram/confirmations.mjs +3 -25
- package/dist/extension/lib/telegram/conversations.d.ts +14 -3
- package/dist/extension/lib/telegram/conversations.mjs +16 -37
- package/dist/extension/lib/telegram/delivery-diagnostics.d.ts +4 -1
- package/dist/extension/lib/telegram/delivery-diagnostics.mjs +9 -3
- package/dist/extension/lib/telegram/health.mjs +1 -1
- package/dist/extension/lib/telegram/inbound.d.ts +14 -14
- package/dist/extension/lib/telegram/inbound.mjs +72 -68
- package/dist/extension/lib/telegram/lifecycle.mjs +1 -1
- package/dist/extension/lib/telegram/{observed.d.ts → message-metadata.d.ts} +2 -6
- package/dist/extension/lib/telegram/{observed.mjs → message-metadata.mjs} +1 -14
- package/dist/extension/lib/telegram/routing-context.d.ts +4 -3
- package/dist/extension/lib/telegram/routing-context.mjs +2 -2
- package/dist/extension/lib/telegram/sessions.d.ts +5 -52
- package/dist/extension/lib/telegram/sessions.mjs +1 -188
- package/dist/extension/lib/telegram/signals.mjs +1 -1
- package/dist/extension/lib/telegram/silent.d.ts +5 -6
- package/dist/extension/lib/telegram/silent.mjs +4 -31
- package/package.json +1 -1
- package/dist/extension/lib/group-routing/observed.mjs +0 -103
|
@@ -11,27 +11,26 @@ import { p as reportTelegramError } from "../../../_chunks/inbound-request-D1r0F
|
|
|
11
11
|
import { addressingReason, conversationKey, otherRecipient } from "../group-routing/signals.mjs";
|
|
12
12
|
import { conversationAddressing, conversationState } from "../group-routing/conversation.mjs";
|
|
13
13
|
import { questionInvitation } from "../group-routing/engagement.mjs";
|
|
14
|
-
import {
|
|
15
|
-
import { observedContext } from "../group-routing/observed.mjs";
|
|
14
|
+
import { routeMessage } from "../group-routing/router.mjs";
|
|
16
15
|
import { debounceBurst, routingBurst } from "../group-routing/burst.mjs";
|
|
17
16
|
import { WorkspaceActionAlreadyDispatched } from "./workspace-action.mjs";
|
|
18
17
|
import { structuredMessage } from "./structured.mjs";
|
|
19
|
-
import {
|
|
18
|
+
import { formatAddress, messageAddress, scopedAddress } from "./sessions.mjs";
|
|
20
19
|
import { AttachmentLifecycleNotPermitted } from "./lifecycle.mjs";
|
|
21
20
|
import { MAXIMUM_NATIVE_IMAGE_BYTES } from "./images.mjs";
|
|
22
21
|
import { MAXIMUM_ROUTING_ATTACHMENT_BYTES, describeRoutingAttachment, routingAttachmentDeadline } from "./attachment-description.mjs";
|
|
23
22
|
import { attachmentUrl } from "../attachments.mjs";
|
|
24
23
|
import { contentShape, messageContent } from "./content.mjs";
|
|
25
24
|
import { messageAudience } from "./audience.mjs";
|
|
26
|
-
import { attachmentKind, messageMetadata } from "./
|
|
27
|
-
import {
|
|
25
|
+
import { attachmentKind, messageMetadata } from "./message-metadata.mjs";
|
|
26
|
+
import { recordGateDecision, recordInboundContent, recordRouteDecision } from "./conversations.mjs";
|
|
28
27
|
import { answerMarker } from "../questions.mjs";
|
|
29
28
|
import { questionAddress, questionFromHistory } from "./confirmations.mjs";
|
|
30
|
-
import { routingContext } from "./routing-context.mjs";
|
|
31
|
-
import { recordGateDecision, recordInboundContent, recordRouteDecision } from "./conversations.mjs";
|
|
32
29
|
import { chatContext } from "./chats.mjs";
|
|
30
|
+
import { telegramSignals } from "./signals.mjs";
|
|
33
31
|
import { attachmentsContext, inboundAttachments, stageFiles } from "./files.mjs";
|
|
34
32
|
import { heldApprovals, releaseHeldApproval } from "./held-approvals.mjs";
|
|
33
|
+
import { routingContext } from "./routing-context.mjs";
|
|
35
34
|
import { voiceOf, voiceText } from "./voice.mjs";
|
|
36
35
|
const MAXIMUM_QUOTE_LENGTH = 500;
|
|
37
36
|
function buttonTo(text, url) {
|
|
@@ -68,6 +67,10 @@ function observedMessage(message, text, member, media, bot) {
|
|
|
68
67
|
...media ? { media } : {}
|
|
69
68
|
};
|
|
70
69
|
}
|
|
70
|
+
function observedImages(recent, current) {
|
|
71
|
+
const answered = recent.findLastIndex((message) => message.admitted === true);
|
|
72
|
+
return recent.slice(answered + 1).filter((message) => !("role" in message) && message.messageId !== current).flatMap((message) => message.images ?? []);
|
|
73
|
+
}
|
|
71
74
|
function isRecord(value) {
|
|
72
75
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
73
76
|
}
|
|
@@ -268,7 +271,19 @@ async function handleInboundMessage(input) {
|
|
|
268
271
|
const turn = structured === void 0 && input.request?.structuredContext === void 0 && addressed !== void 0 && hasContent && (addressed !== "reply-to-bot" || elsewhere === void 0);
|
|
269
272
|
const lookup = await resolve(turn);
|
|
270
273
|
const group = isGroupChat(sent);
|
|
271
|
-
const
|
|
274
|
+
const freshConversation = async () => await dependencies.recentConversation?.(sent.chat.id, sent.messageThreadId === void 0 ? void 0 : String(sent.messageThreadId)) ?? [];
|
|
275
|
+
let archived;
|
|
276
|
+
const recentConversation = () => archived ??= freshConversation();
|
|
277
|
+
const languageOf = async (current) => {
|
|
278
|
+
const own = conversationLanguage([current]);
|
|
279
|
+
if (own !== void 0) return own;
|
|
280
|
+
try {
|
|
281
|
+
return conversationLanguage((await recentConversation()).map((message) => message.text).reverse());
|
|
282
|
+
} catch (error) {
|
|
283
|
+
reportTelegramError("conversation_language_unavailable", error, { chatId: sent.chat.id });
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
272
287
|
const report = group ? dependencies.chats.seen({
|
|
273
288
|
chatId: sent.chat.id,
|
|
274
289
|
title: sent.chat.title ?? "",
|
|
@@ -349,9 +364,9 @@ async function handleInboundMessage(input) {
|
|
|
349
364
|
async function observeRaw() {
|
|
350
365
|
await recordInboundContent({
|
|
351
366
|
text,
|
|
352
|
-
decoded
|
|
367
|
+
decoded,
|
|
368
|
+
author: authorOf(sent.from, void 0)
|
|
353
369
|
});
|
|
354
|
-
if (group) dependencies.observed.add(chat, observedMessage(sent, text || "[attachment]", void 0, void 0, bot));
|
|
355
370
|
}
|
|
356
371
|
if (lookup.status !== "existing" && lookup.status !== "created") {
|
|
357
372
|
const configuredGroupPairing = lookup.status === "pairing_required" && localizedText(dependencies.admission().replies.groupPairingRequired, sent.from.languageCode) !== void 0;
|
|
@@ -360,6 +375,10 @@ async function handleInboundMessage(input) {
|
|
|
360
375
|
return null;
|
|
361
376
|
}
|
|
362
377
|
let member = lookup.member;
|
|
378
|
+
const recordContent = (content) => recordInboundContent({
|
|
379
|
+
...content,
|
|
380
|
+
author: authorOf(sent.from, member)
|
|
381
|
+
});
|
|
363
382
|
if (input.request?.structuredContext !== void 0 && input.request.structuredContext.memberId !== member.id) {
|
|
364
383
|
recordGateDecision("structured_context_actor_changed");
|
|
365
384
|
return null;
|
|
@@ -393,7 +412,7 @@ async function handleInboundMessage(input) {
|
|
|
393
412
|
const principal = telegramPrincipal({
|
|
394
413
|
message: sent,
|
|
395
414
|
member,
|
|
396
|
-
conversationLanguage:
|
|
415
|
+
conversationLanguage: await languageOf(sent.text || sent.caption)
|
|
397
416
|
});
|
|
398
417
|
input.request.lifecycle = dependencies.lifecycle(principal, member.id, sent);
|
|
399
418
|
await context.telegram.startTyping();
|
|
@@ -481,8 +500,7 @@ async function handleInboundMessage(input) {
|
|
|
481
500
|
bot?.firstName,
|
|
482
501
|
bot?.displayName
|
|
483
502
|
].filter((n) => !!n)];
|
|
484
|
-
|
|
485
|
-
let conversationRecent = conversationPolicy ? await freshConversation() : dependencies.observed.recent(chat);
|
|
503
|
+
let conversationRecent = conversationPolicy ? await recentConversation() : [];
|
|
486
504
|
if (conversationPolicy && input.request && input.request.lifecycleKey === void 0 && input.request.structuredContext === void 0) {
|
|
487
505
|
address = topicAddress;
|
|
488
506
|
input.request.address = topicAddress;
|
|
@@ -512,11 +530,10 @@ async function handleInboundMessage(input) {
|
|
|
512
530
|
input.request.address = address;
|
|
513
531
|
}
|
|
514
532
|
if (input.request?.lifecycleKey === void 0 && input.request?.structuredContext === void 0 && group && (addressed === void 0 && !answering && groups.mode === "mention" || !conversationPolicy && elsewhere !== void 0 && (addressed === void 0 || addressed === "reply-to-bot" && !recipientAnswer))) {
|
|
515
|
-
await
|
|
516
|
-
text,
|
|
533
|
+
await recordContent({
|
|
534
|
+
text: text || (structured === void 0 ? text : `[${structured.kind}]`),
|
|
517
535
|
decoded
|
|
518
536
|
});
|
|
519
|
-
dependencies.observed.add(chat, observedMessage(sent, text || (structured === void 0 ? "[attachment]" : `[${structured.kind}]`), member, void 0, bot));
|
|
520
537
|
recordRouteDecision("observe", addressed, groups.mode, {
|
|
521
538
|
reason: elsewhere === void 0 ? "mention_policy" : "other_recipient",
|
|
522
539
|
note: elsewhere ?? "Mention policy observes unaddressed messages."
|
|
@@ -531,7 +548,12 @@ async function handleInboundMessage(input) {
|
|
|
531
548
|
await observeRaw();
|
|
532
549
|
return null;
|
|
533
550
|
}
|
|
534
|
-
|
|
551
|
+
if (group && !conversationPolicy) conversationRecent = (await recentConversation()).filter((message) => message.messageId !== sent.messageId).map(({ signedAuthor, ...message }) => signedAuthor === void 0 ? message : {
|
|
552
|
+
...message,
|
|
553
|
+
author: signedAuthor
|
|
554
|
+
});
|
|
555
|
+
const carried = observedImages(conversationRecent, sent.messageId);
|
|
556
|
+
const mediaPlan = voice !== void 0 || sent.attachments.length > 0 || carried.length > 0 ? await dependencies.mediaPlan?.(member, owner?.id) : void 0;
|
|
535
557
|
if (voice !== void 0 && !group) await transcribeVoice(false);
|
|
536
558
|
if (voice !== void 0 && mediaPlan?.audio) notes.push("[The chat model supports audio, but this host cannot deliver native audio. The configured speech-to-text fallback was used if enabled.]");
|
|
537
559
|
if (structured !== void 0) {
|
|
@@ -575,7 +597,7 @@ async function handleInboundMessage(input) {
|
|
|
575
597
|
address,
|
|
576
598
|
operations,
|
|
577
599
|
read: dependencies.history ?? dependencies.readHistory,
|
|
578
|
-
remembered:
|
|
600
|
+
remembered: conversationRecent,
|
|
579
601
|
at: sentAt(sent),
|
|
580
602
|
questionHistory,
|
|
581
603
|
questionSessionId: owner?.id
|
|
@@ -625,7 +647,7 @@ async function handleInboundMessage(input) {
|
|
|
625
647
|
};
|
|
626
648
|
const evidence = conversationAddressing(routingSignals, conversationRecent, groups, agentAliases);
|
|
627
649
|
if (!evidence.agent_named && !evidence.reply_to_agent && evidence.human_targets.length === 0) {
|
|
628
|
-
await
|
|
650
|
+
await recordContent({
|
|
629
651
|
text,
|
|
630
652
|
decoded
|
|
631
653
|
});
|
|
@@ -718,7 +740,7 @@ async function handleInboundMessage(input) {
|
|
|
718
740
|
...notes
|
|
719
741
|
].join("\n");
|
|
720
742
|
} else if (voice !== void 0) media = [...attachmentMetadata, ...notes].join("\n");
|
|
721
|
-
await
|
|
743
|
+
await recordContent({
|
|
722
744
|
text,
|
|
723
745
|
decoded,
|
|
724
746
|
...processedMedia === void 0 ? {} : { media: processedMedia }
|
|
@@ -743,11 +765,10 @@ async function handleInboundMessage(input) {
|
|
|
743
765
|
let structuredDispatched = false;
|
|
744
766
|
if (structured !== void 0 && dependencies.structured !== void 0) {
|
|
745
767
|
if (route === "observe" || admissionRefused) {
|
|
746
|
-
await
|
|
768
|
+
await recordContent({
|
|
747
769
|
text,
|
|
748
770
|
decoded
|
|
749
771
|
});
|
|
750
|
-
if (group) dependencies.observed.add(chat, observedMessage(sent, text, member, media, bot));
|
|
751
772
|
return null;
|
|
752
773
|
}
|
|
753
774
|
if (!await admitTurn(true)) return null;
|
|
@@ -813,14 +834,12 @@ async function handleInboundMessage(input) {
|
|
|
813
834
|
note: "The configured workspace action admitted this attachment task."
|
|
814
835
|
});
|
|
815
836
|
if (admissionRefused) {
|
|
816
|
-
await
|
|
837
|
+
await recordContent({
|
|
817
838
|
text,
|
|
818
839
|
decoded
|
|
819
840
|
});
|
|
820
|
-
dependencies.observed.add(chat, observedMessage(sent, text || "[attachment]", member, void 0, bot));
|
|
821
841
|
return null;
|
|
822
842
|
}
|
|
823
|
-
if (group && route === "observe") dependencies.observed.add(chat, observedMessage(sent, text, member, media, bot));
|
|
824
843
|
if (sent.attachments.length > 0) await report;
|
|
825
844
|
let files = input.request?.edited && !input.request.attachmentsChanged && (input.request.previousContent?.decoded.length ?? 0) > 0 || sent.attachments.length === 0 || dependencies.attachments === void 0 || input.request === void 0 ? new Map() : await stageFiles({
|
|
826
845
|
message: sent,
|
|
@@ -937,24 +956,24 @@ async function handleInboundMessage(input) {
|
|
|
937
956
|
if (input.request !== void 0 && (voice !== void 0 || processedMedia !== void 0)) input.request.text = text;
|
|
938
957
|
const retainedMedia = processedMedia ?? ([...files.values()].flatMap((file) => file.status === "stored" && file.description !== void 0 ? [file.description] : []).join("\n") || void 0);
|
|
939
958
|
if (decoded.length === 0) decoded.push(...[...files.values()].flatMap((file) => file.status === "stored" && file.decoded !== void 0 ? [file.decoded] : []));
|
|
940
|
-
await
|
|
959
|
+
await recordContent({
|
|
941
960
|
text,
|
|
942
961
|
decoded,
|
|
943
|
-
...retainedMedia === void 0 ? {} : { media: retainedMedia }
|
|
962
|
+
...retainedMedia === void 0 ? {} : { media: retainedMedia },
|
|
963
|
+
files: [...files.values()].flatMap((file) => file.status === "stored" ? [{
|
|
964
|
+
id: file.attachment.id,
|
|
965
|
+
filename: file.attachment.filename,
|
|
966
|
+
contentType: file.attachment.contentType,
|
|
967
|
+
size: file.attachment.size,
|
|
968
|
+
expiresAt: file.attachment.expiresAt,
|
|
969
|
+
...file.imageInput === "native" ? { image: true } : {}
|
|
970
|
+
}] : [])
|
|
944
971
|
});
|
|
945
|
-
if (route === "observe")
|
|
946
|
-
const images = [...files.values()].flatMap((file) => file.status === "stored" && file.imageInput === "native" ? [file.attachment] : []);
|
|
947
|
-
dependencies.observed.add(chat, {
|
|
948
|
-
...observedMessage(sent, text === "" ? "[attachment]" : text, member, media, bot),
|
|
949
|
-
images
|
|
950
|
-
});
|
|
951
|
-
return null;
|
|
952
|
-
}
|
|
972
|
+
if (route === "observe") return null;
|
|
953
973
|
if (!structuredDispatched && input.request?.claimTurn !== void 0 && !await input.request.claimTurn()) {
|
|
954
974
|
recordGateDecision("message_already_handled");
|
|
955
975
|
return null;
|
|
956
976
|
}
|
|
957
|
-
let receivingHistory;
|
|
958
977
|
if (operations !== void 0 && dependencies.history !== void 0) {
|
|
959
978
|
let recoverySessionId;
|
|
960
979
|
try {
|
|
@@ -962,7 +981,6 @@ async function handleInboundMessage(input) {
|
|
|
962
981
|
if (session !== void 0) {
|
|
963
982
|
recoverySessionId = session.id;
|
|
964
983
|
const previous = session.id === owner?.id ? questionHistory : await dependencies.history(session.id);
|
|
965
|
-
receivingHistory = previous;
|
|
966
984
|
const recovery = heldApprovals(previous).length === 0 ? void 0 : await releaseHeldApproval({
|
|
967
985
|
events: await dependencies.history(session.id),
|
|
968
986
|
now: Date.now(),
|
|
@@ -996,24 +1014,6 @@ async function handleInboundMessage(input) {
|
|
|
996
1014
|
notes.push(`<pending_question>\nTask: ${pending.task}\nQuestion: ${pending.question}\nUse this member's answer to continue the pending task with their current permissions.
|
|
997
1015
|
</pending_question>`);
|
|
998
1016
|
}
|
|
999
|
-
if (operations !== void 0) {
|
|
1000
|
-
const newest = dependencies.observed.list(chat).at(-1);
|
|
1001
|
-
if (await dependencies.sessionPolicy.apply({
|
|
1002
|
-
address,
|
|
1003
|
-
operations,
|
|
1004
|
-
...newest === void 0 ? {} : { activeAt: Date.parse(newest.at) || 0 }
|
|
1005
|
-
}) === "cleared") {
|
|
1006
|
-
dependencies.observed.clear(chat);
|
|
1007
|
-
question = void 0;
|
|
1008
|
-
if (answering && input.request !== void 0) {
|
|
1009
|
-
answering = false;
|
|
1010
|
-
input.request.text = text;
|
|
1011
|
-
const questionNote = notes.findIndex((note) => note.startsWith("<pending_question>"));
|
|
1012
|
-
if (questionNote !== -1) notes.splice(questionNote, 1);
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
dependencies.sessionPolicy.delivered(address);
|
|
1016
|
-
}
|
|
1017
1017
|
await context.telegram.startTyping();
|
|
1018
1018
|
await report;
|
|
1019
1019
|
if (input.request !== void 0 && files.size > 0) input.request.files = files;
|
|
@@ -1021,7 +1021,7 @@ async function handleInboundMessage(input) {
|
|
|
1021
1021
|
const currentImages = [...files.values()].flatMap((file) => file.status === "stored" && file.imageInput === "native" ? [file.attachment] : []);
|
|
1022
1022
|
let remaining = Math.max(0, MAXIMUM_NATIVE_IMAGE_BYTES - currentImages.reduce((sum, file) => sum + file.size, 0));
|
|
1023
1023
|
let count = currentImages.length;
|
|
1024
|
-
input.request.extraFiles =
|
|
1024
|
+
input.request.extraFiles = carried.flatMap((image) => {
|
|
1025
1025
|
if (Date.parse(image.expiresAt) <= Date.now() || image.size > remaining || count >= 5) {
|
|
1026
1026
|
notes.push(`[Earlier image ${JSON.stringify(image.filename)} omitted: expired or native context limit.]`);
|
|
1027
1027
|
return [];
|
|
@@ -1038,16 +1038,15 @@ async function handleInboundMessage(input) {
|
|
|
1038
1038
|
mediaType: image.contentType,
|
|
1039
1039
|
filename: image.filename
|
|
1040
1040
|
}];
|
|
1041
|
-
})
|
|
1041
|
+
});
|
|
1042
1042
|
}
|
|
1043
|
-
const language =
|
|
1044
|
-
const
|
|
1043
|
+
const language = await languageOf(text);
|
|
1044
|
+
const confirmationReply = (group ? await conversation() : void 0)?.recent.some((entry) => "role" in entry && entry.confirmation !== void 0 && entry.messageId === audience.replyTo?.messageId) === true;
|
|
1045
1045
|
const beginTurnDispatch = structuredDispatched ? input.request?.beginStructuredContinuation : input.request?.beginDispatch;
|
|
1046
1046
|
if (beginTurnDispatch !== void 0 && !await beginTurnDispatch()) {
|
|
1047
1047
|
recordGateDecision("message_already_handled");
|
|
1048
1048
|
return null;
|
|
1049
1049
|
}
|
|
1050
|
-
dependencies.observed.remember(chat, observedMessage(sent, text, member, retainedMedia, bot));
|
|
1051
1050
|
let principal = telegramPrincipal({
|
|
1052
1051
|
message: {
|
|
1053
1052
|
...sent,
|
|
@@ -1056,6 +1055,14 @@ async function handleInboundMessage(input) {
|
|
|
1056
1055
|
member,
|
|
1057
1056
|
conversationLanguage: language
|
|
1058
1057
|
});
|
|
1058
|
+
const [guidance] = group ? chatContext(dependencies.chats.chat(sent.chat.id)) : [];
|
|
1059
|
+
if (guidance !== void 0) principal = {
|
|
1060
|
+
...principal,
|
|
1061
|
+
attributes: {
|
|
1062
|
+
...principal.attributes,
|
|
1063
|
+
chatGuidance: guidance
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1059
1066
|
if (conversationPolicy && input.request?.lifecycleKey === void 0 && input.request?.structuredContext === void 0) principal = {
|
|
1060
1067
|
...principal,
|
|
1061
1068
|
attributes: {
|
|
@@ -1109,27 +1116,24 @@ async function handleInboundMessage(input) {
|
|
|
1109
1116
|
},
|
|
1110
1117
|
context: [
|
|
1111
1118
|
...input.request?.lifecycleContext === void 0 ? [] : [input.request.lifecycleContext],
|
|
1112
|
-
...observedContext(dependencies.observed.take(chat).slice(-groups.smart.context.messages), sharedContext),
|
|
1113
|
-
...group ? chatContext(dependencies.chats.chat(sent.chat.id)) : [],
|
|
1114
1119
|
speakerBlock({
|
|
1115
1120
|
message: sent,
|
|
1116
1121
|
member,
|
|
1117
1122
|
bot,
|
|
1118
|
-
omitQuote:
|
|
1123
|
+
omitQuote: confirmationReply
|
|
1119
1124
|
}),
|
|
1120
1125
|
"<message_audience>\n" + JSON.stringify({
|
|
1121
1126
|
bot_addressed: addressed !== void 0 || answering,
|
|
1122
1127
|
bot_tagged: audience.botTagged,
|
|
1123
|
-
reply_target:
|
|
1124
|
-
tagged_users: audience.mentions
|
|
1125
|
-
|
|
1126
|
-
|
|
1128
|
+
reply_target: confirmationReply && audience.replyTo !== null ? Object.fromEntries(Object.entries(audience.replyTo).filter(([key]) => key !== "text")) : audience.replyTo,
|
|
1129
|
+
tagged_users: audience.mentions,
|
|
1130
|
+
...conversationPolicy ? { engagement_policy: "conversation" } : {}
|
|
1131
|
+
}) + "\n</message_audience>",
|
|
1127
1132
|
...attachmentsContext({
|
|
1128
1133
|
files,
|
|
1129
1134
|
group
|
|
1130
1135
|
}),
|
|
1131
1136
|
...processedMedia === void 0 ? [] : [processedMedia],
|
|
1132
|
-
...conversationPolicy ? ["If this member declines your involvement or closes the conversation, output exactly [SILENT]. Do not acknowledge the rejection or perform actions."] : [],
|
|
1133
1137
|
...notes
|
|
1134
1138
|
]
|
|
1135
1139
|
};
|
|
@@ -10,7 +10,7 @@ import { n as currentInboundRequest } from "../../../_chunks/inbound-request-D1r
|
|
|
10
10
|
import { member } from "../actor.mjs";
|
|
11
11
|
import { needsConfirmation } from "../confirmations.mjs";
|
|
12
12
|
import { OntologyActionNotPermitted, actionToolName, ontologyTools } from "../ontology-tools.mjs";
|
|
13
|
-
import { t as agentBuild } from "../../../_chunks/build-metadata-
|
|
13
|
+
import { t as agentBuild } from "../../../_chunks/build-metadata-R_ssK2uR.mjs";
|
|
14
14
|
var AttachmentLifecycleNotPermitted = class extends Error {
|
|
15
15
|
code = "attachment_lifecycle_not_permitted";
|
|
16
16
|
};
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import { type ObservedMessages } from "../group-routing/observed.js";
|
|
2
1
|
import type { TelegramMessage } from "eve/channels/telegram";
|
|
3
2
|
import type { BotIdentity } from "./router.js";
|
|
4
|
-
import type { ObservedMessage } from "../group-routing/
|
|
5
|
-
export * from "../group-routing/observed.js";
|
|
3
|
+
import type { ObservedMessage } from "../group-routing/messages.js";
|
|
6
4
|
/** Eve represents non-image media as documents; retain the actual Telegram kind in context. */
|
|
7
5
|
export declare function attachmentKind(message: TelegramMessage, file: {
|
|
8
6
|
readonly fileId: string;
|
|
9
7
|
readonly kind: string;
|
|
10
8
|
}): string;
|
|
11
|
-
/** Bounded provider structure,
|
|
9
|
+
/** Bounded provider structure, archived with each message for routing. No file grants. */
|
|
12
10
|
export declare function messageMetadata(message: TelegramMessage, bot?: BotIdentity): Pick<ObservedMessage, "invitation" | "kind" | "username" | "replyTo" | "taggedUsers" | "attachmentKinds" | "hasCaption" | "revision">;
|
|
13
|
-
/** Compatibility boundary for callers that used Telegram's former unqualified ring keys. */
|
|
14
|
-
export declare function observedMessages(capacity?: number): ObservedMessages;
|
|
@@ -4,7 +4,6 @@ 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 { OBSERVED_MESSAGES, agentMessage, currentConfirmationPrompt, observedChatKey, observedContext, observedMessages as observedMessages$1, withConfirmationPrompt } from "../group-routing/observed.mjs";
|
|
8
7
|
import { messageAudience } from "./audience.mjs";
|
|
9
8
|
const PROVIDER_MEDIA_KINDS = [
|
|
10
9
|
"voice",
|
|
@@ -49,16 +48,4 @@ function messageMetadata(message, bot) {
|
|
|
49
48
|
}
|
|
50
49
|
};
|
|
51
50
|
}
|
|
52
|
-
|
|
53
|
-
const ring = observedMessages$1(capacity);
|
|
54
|
-
const key = (value) => /^[a-z][a-z0-9_-]*:/u.test(value) ? value : `telegram:${value.replace(/:/u, "/")}`;
|
|
55
|
-
return {
|
|
56
|
-
add: (chat, message) => ring.add(key(chat), message),
|
|
57
|
-
remember: (chat, message) => ring.remember(key(chat), message),
|
|
58
|
-
list: (chat) => ring.list(key(chat)),
|
|
59
|
-
recent: (chat) => ring.recent(key(chat)),
|
|
60
|
-
take: (chat) => ring.take(key(chat)),
|
|
61
|
-
clear: (chat) => ring.clear(key(chat))
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
export { OBSERVED_MESSAGES, agentMessage, attachmentKind, currentConfirmationPrompt, messageMetadata, observedChatKey, observedContext, observedMessages, withConfirmationPrompt };
|
|
51
|
+
export { attachmentKind, messageMetadata };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { type RecentMessage, type PendingConfirmation } from "
|
|
1
|
+
import { type RecentMessage, type PendingConfirmation } from "../group-routing/messages.js";
|
|
2
2
|
import type { HistoryReader, RecordedEvent, SessionOperations } from "./sessions.js";
|
|
3
3
|
import { type PendingQuestion } from "../questions.js";
|
|
4
4
|
export { archivedRoutingMessages } from "../group-routing/routing-context.js";
|
|
5
5
|
/**
|
|
6
|
-
* Recover the agent's questions from the existing session without starting a turn. The
|
|
7
|
-
*
|
|
6
|
+
* Recover the agent's questions from the existing session without starting a turn. The archived
|
|
7
|
+
* messages (`remembered`) supplement this with recipient identities and chatter not written to
|
|
8
|
+
* Eve's stream.
|
|
8
9
|
*/
|
|
9
10
|
export declare function routingContext(input: {
|
|
10
11
|
readonly address: string;
|
|
@@ -5,11 +5,11 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import "../group-routing/router.mjs";
|
|
8
|
-
import { agentMessage } from "../group-routing/
|
|
8
|
+
import { agentMessage } from "../group-routing/messages.mjs";
|
|
9
9
|
import { archivedRoutingMessages } from "../group-routing/routing-context.mjs";
|
|
10
|
-
import { isSilentReply } from "./silent.mjs";
|
|
11
10
|
import { questionKey } from "../questions.mjs";
|
|
12
11
|
import { questionsFromHistory, routingConfirmationState, routingConfirmations } from "./confirmations.mjs";
|
|
12
|
+
import { isSilentReply } from "./silent.mjs";
|
|
13
13
|
const DELIVERY_CLOCK_TOLERANCE_MS = 6e4;
|
|
14
14
|
async function routingContext(input) {
|
|
15
15
|
const histories = new Map();
|
|
@@ -3,11 +3,9 @@ import type { ChannelSource } from "eve/channels";
|
|
|
3
3
|
import type { TelegramChannelState } from "eve/channels/telegram";
|
|
4
4
|
import type { SessionSettings } from "../../config.js";
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* on a continuation address (`resolveSession`, `compact`, `clear`); the history it needs is read
|
|
10
|
-
* from the session's own durable stream, so nothing is stored beside eve.
|
|
6
|
+
* Telegram session addressing (`agent-design.md`, section 4, and docs/agent.md, "Sessions"): what
|
|
7
|
+
* a group session spans. Compaction and idle expiry are eve's own: automatic compaction near the
|
|
8
|
+
* context window and `limits.sessionTimeoutMs` in the workspace's `agent.ts`.
|
|
11
9
|
*/
|
|
12
10
|
/** eve's Telegram continuation address: `chat:thread:conversation`, the last two possibly empty. */
|
|
13
11
|
export interface TelegramAddress {
|
|
@@ -28,18 +26,7 @@ export declare function messageAddress(message: TelegramMessage): string;
|
|
|
28
26
|
* eve's own address. A private chat has no anchor either way.
|
|
29
27
|
*/
|
|
30
28
|
export declare function scopedAddress(address: string, scope: SessionSettings["scope"]): string;
|
|
31
|
-
/**
|
|
32
|
-
export declare function compactBoundary(now: Date, compactAt: string, timezone: string): Date;
|
|
33
|
-
/** What the policy knows about one session: from its stream, then kept per process. */
|
|
34
|
-
export interface SessionHistory {
|
|
35
|
-
/** When the session last did anything. */
|
|
36
|
-
readonly lastAt: number;
|
|
37
|
-
/** When its history last started afresh: creation, compaction or clear. */
|
|
38
|
-
readonly resetAt: number;
|
|
39
|
-
/** Turns completed since `resetAt`; a compaction is worth nothing before the first. */
|
|
40
|
-
readonly turnsSinceReset: number;
|
|
41
|
-
}
|
|
42
|
-
/** One recorded event used by session policy, routing context and interaction projections. */
|
|
29
|
+
/** One recorded event used by routing context and interaction projections. */
|
|
43
30
|
export interface RecordedEvent {
|
|
44
31
|
readonly type: string;
|
|
45
32
|
readonly scope?: {
|
|
@@ -53,18 +40,8 @@ export interface RecordedEvent {
|
|
|
53
40
|
}
|
|
54
41
|
/** Session events, oldest first; readers choose a tail or full stream for their consumers. */
|
|
55
42
|
export type HistoryReader = (sessionId: string) => Promise<ReadonlyArray<RecordedEvent>>;
|
|
56
|
-
/** How many events of the tail the reader fetches
|
|
43
|
+
/** How many events of the tail the adapter's tail reader fetches. */
|
|
57
44
|
export declare const HISTORY_TAIL = 400;
|
|
58
|
-
/** Folds a tail into a history; with no reset marker in it, `resetAt` is its earliest event. */
|
|
59
|
-
export declare function historyOf(events: ReadonlyArray<RecordedEvent>): SessionHistory;
|
|
60
|
-
/**
|
|
61
|
-
* The earliest message time a group turn's conversation evidence still needs: each member
|
|
62
|
-
* message the session took in carried the chat's evidence up to then, and its history keeps it
|
|
63
|
-
* until a compaction or clear. Undefined when the session has none since its last reset, so the
|
|
64
|
-
* turn carries the whole window. Schedule sends and button answers carry no evidence and are
|
|
65
|
-
* skipped; a workspace callback turn is indistinguishable and may hide earlier unseen chatter.
|
|
66
|
-
*/
|
|
67
|
-
export declare function evidenceSince(events: ReadonlyArray<RecordedEvent>): number | undefined;
|
|
68
45
|
/** The route's operations on a continuation address, as eve gives them to the handler. */
|
|
69
46
|
export interface SessionOperations {
|
|
70
47
|
readonly resolveSession: (address: string) => Promise<{
|
|
@@ -75,29 +52,5 @@ export interface SessionOperations {
|
|
|
75
52
|
} | undefined>;
|
|
76
53
|
readonly from: (address: string) => {
|
|
77
54
|
readonly send?: ChannelSource<TelegramChannelState>["send"];
|
|
78
|
-
compact: ChannelSource<TelegramChannelState>["compact"];
|
|
79
|
-
clear: ChannelSource<TelegramChannelState>["clear"];
|
|
80
55
|
};
|
|
81
56
|
}
|
|
82
|
-
export type SessionAction = "none" | "cleared" | "compacted";
|
|
83
|
-
export interface SessionPolicy {
|
|
84
|
-
/**
|
|
85
|
-
* Applies the policy to the session `address` continues, before a message is delivered to it:
|
|
86
|
-
* clears a history idle for longer than `idleResetHours`, else compacts it once after each
|
|
87
|
-
* day's `compactAt`. A session that does not exist yet needs neither.
|
|
88
|
-
*/
|
|
89
|
-
apply(input: {
|
|
90
|
-
readonly address: string;
|
|
91
|
-
readonly operations: SessionOperations;
|
|
92
|
-
/** The newest activity the stream does not show, such as an observed group message. */
|
|
93
|
-
readonly activeAt?: number;
|
|
94
|
-
readonly now?: Date;
|
|
95
|
-
}): Promise<SessionAction>;
|
|
96
|
-
/** Records that a message was just delivered to the session. */
|
|
97
|
-
delivered(address: string, now?: Date): void;
|
|
98
|
-
}
|
|
99
|
-
export declare function sessionPolicy(input: {
|
|
100
|
-
readonly settings: () => SessionSettings;
|
|
101
|
-
readonly read: HistoryReader;
|
|
102
|
-
readonly log?: (message: string, error: unknown) => void;
|
|
103
|
-
}): SessionPolicy;
|