@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.
Files changed (67) hide show
  1. package/README.md +41 -42
  2. package/dist/_chunks/{inbound-request-CysnjMdw.mjs → inbound-request-BwBvXk0A.mjs} +9 -2
  3. package/dist/extension/_manifest.json +2 -0
  4. package/dist/extension/channels/telegram.mjs +1 -0
  5. package/dist/extension/config.d.ts +17 -5
  6. package/dist/extension/config.mjs +26 -5
  7. package/dist/extension/connections/ontology.mjs +1 -1
  8. package/dist/extension/instructions.md +20 -0
  9. package/dist/extension/lib/attachment-formats.d.ts +1 -1
  10. package/dist/extension/lib/attachment-tables.d.ts +1 -1
  11. package/dist/extension/lib/confirmation-description.d.ts +5 -0
  12. package/dist/extension/lib/confirmation-description.mjs +7 -1
  13. package/dist/extension/lib/confirmation-outcome.d.ts +19 -0
  14. package/dist/extension/lib/confirmation-outcome.mjs +34 -0
  15. package/dist/extension/lib/confirmations.mjs +1 -1
  16. package/dist/extension/lib/connection-proxy.d.ts +2 -2
  17. package/dist/extension/lib/connection-proxy.mjs +6 -6
  18. package/dist/extension/lib/conversations.mjs +15 -1
  19. package/dist/extension/lib/customer-text-safety.mjs +2 -1
  20. package/dist/extension/lib/deferred-confirmations.d.ts +39 -0
  21. package/dist/extension/lib/deferred-confirmations.mjs +149 -0
  22. package/dist/extension/lib/ontology-tools.d.ts +2 -0
  23. package/dist/extension/lib/ontology-tools.mjs +5 -0
  24. package/dist/extension/lib/telegram/adapter.d.ts +6 -0
  25. package/dist/extension/lib/telegram/adapter.mjs +89 -14
  26. package/dist/extension/lib/telegram/attachment-description.d.ts +31 -0
  27. package/dist/extension/lib/telegram/attachment-description.mjs +82 -0
  28. package/dist/extension/lib/telegram/attachments-send.mjs +3 -3
  29. package/dist/extension/lib/telegram/audience.mjs +1 -1
  30. package/dist/extension/lib/telegram/bot.mjs +3 -1
  31. package/dist/extension/lib/telegram/chat-post-card.mjs +1 -1
  32. package/dist/extension/lib/telegram/confirmation-expiry.d.ts +4 -0
  33. package/dist/extension/lib/telegram/confirmation-expiry.mjs +50 -0
  34. package/dist/extension/lib/telegram/confirmations.d.ts +9 -1
  35. package/dist/extension/lib/telegram/confirmations.mjs +136 -15
  36. package/dist/extension/lib/telegram/conversations.d.ts +10 -1
  37. package/dist/extension/lib/telegram/conversations.mjs +177 -22
  38. package/dist/extension/lib/telegram/customer-text.mjs +1 -1
  39. package/dist/extension/lib/telegram/deferred-confirmations.d.ts +26 -0
  40. package/dist/extension/lib/telegram/deferred-confirmations.mjs +282 -0
  41. package/dist/extension/lib/telegram/files.mjs +20 -3
  42. package/dist/extension/lib/telegram/images.d.ts +1 -0
  43. package/dist/extension/lib/telegram/images.mjs +2 -1
  44. package/dist/extension/lib/telegram/inbound-request.d.ts +15 -1
  45. package/dist/extension/lib/telegram/inbound-request.mjs +1 -1
  46. package/dist/extension/lib/telegram/inbound.d.ts +12 -4
  47. package/dist/extension/lib/telegram/inbound.mjs +258 -74
  48. package/dist/extension/lib/telegram/media-policy.mjs +1 -1
  49. package/dist/extension/lib/telegram/observed.d.ts +45 -2
  50. package/dist/extension/lib/telegram/observed.mjs +62 -3
  51. package/dist/extension/lib/telegram/pdf-text.d.ts +5 -0
  52. package/dist/extension/lib/telegram/pdf-text.mjs +84 -0
  53. package/dist/extension/lib/telegram/router.d.ts +31 -7
  54. package/dist/extension/lib/telegram/router.mjs +152 -41
  55. package/dist/extension/lib/telegram/routing-context.d.ts +15 -3
  56. package/dist/extension/lib/telegram/routing-context.mjs +131 -6
  57. package/dist/extension/lib/telegram/silent.mjs +5 -3
  58. package/dist/extension/lib/telegram/turn-errors.mjs +1 -1
  59. package/dist/extension/lib/telegram/voice.d.ts +4 -0
  60. package/dist/extension/lib/telegram/voice.mjs +7 -6
  61. package/dist/extension/schedules/confirmations.d.ts +6 -0
  62. package/dist/extension/schedules/confirmations.mjs +33 -0
  63. package/dist/extension/tools/ontology.d.ts +4 -0
  64. package/dist/extension/tools/ontology.mjs +30 -0
  65. package/dist/tools/index.d.ts +1 -0
  66. package/dist/tools/index.mjs +2 -1
  67. package/package.json +7 -4
@@ -0,0 +1,282 @@
1
+ import { fileURLToPath as __eveFileURLToPath } from "node:url";
2
+ import { dirname as __eveDirname } from "node:path";
3
+ import { createRequire as __eveCreateRequire } from "node:module";
4
+ const __filename = __eveFileURLToPath(import.meta.url);
5
+ __eveDirname(__filename);
6
+ __eveCreateRequire(import.meta.url);
7
+ import { telegramPrincipal } from "./principal.mjs";
8
+ import { humanText } from "../confirmation-description.mjs";
9
+ import { renderConfirmation, withConfirmationText } from "./confirmation-text.mjs";
10
+ import { confirmationOutcome } from "../confirmation-outcome.mjs";
11
+ import { chatPostCard, chatPostCardStatus, chatPostReceipt, withChatPostCard } from "./chat-post-card.mjs";
12
+ import { CONFIRMATION_TTL_MS, inputHash } from "../confirmations.mjs";
13
+ import { deferredConfirmations, deferredKey, runDeferredAction } from "../deferred-confirmations.mjs";
14
+ import { conversationEvent } from "../conversations.mjs";
15
+ import { n as currentInboundRequest, p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
16
+ import { formatAddress } from "./sessions.mjs";
17
+ import { agentMessage, observedChatKey, withConfirmationPrompt } from "./observed.mjs";
18
+ import { telegramTextLinks } from "@segmentstream-cloud/ontology/telegram";
19
+ const PREFIX = "ss-confirm:d:";
20
+ const isDeferredCallback = (data) => data?.startsWith(PREFIX) === true;
21
+ const deferredCallback = (record, choice) => `${PREFIX}${record.key}:${choice}`;
22
+ const copyOf = (record) => record.data.confirmation.description?.chatPost ? chatPostCard(record.data.confirmation.description, record.data.confirmation.copy) : renderConfirmation(record.data.confirmation.description, record.data.confirmation.copy);
23
+ function promptOf(record, state) {
24
+ const name = humanText(record.data.requesterName);
25
+ return {
26
+ mode: "deferred",
27
+ requestId: record.id,
28
+ sessionId: record.data.sessionId,
29
+ address: record.data.address,
30
+ action: humanText(record.data.confirmation.description?.action) ?? "❓",
31
+ requestedBy: name ?? null,
32
+ at: new Date(record.expiresAt - CONFIRMATION_TTL_MS).toISOString(),
33
+ state,
34
+ ...name === void 0 ? {} : { requester: {
35
+ id: record.data.requester,
36
+ author: name
37
+ } }
38
+ };
39
+ }
40
+ function remember(record, text, prompt, observed) {
41
+ if (record.data.messageId === void 0) return;
42
+ observed?.remember(observedChatKey({
43
+ chatId: record.data.chatId,
44
+ ...record.data.threadId ? { messageThreadId: Number(record.data.threadId) } : {}
45
+ }), {
46
+ ...agentMessage({
47
+ text,
48
+ at: new Date().toISOString(),
49
+ messageId: record.data.messageId,
50
+ ...prompt.requester === void 0 ? {} : { inReplyTo: prompt.requester }
51
+ }),
52
+ confirmation: prompt
53
+ });
54
+ }
55
+ async function archiveDeferred(record, phase, archive) {
56
+ await archive.append(conversationEvent({
57
+ eventId: `confirmation:${record.id}:${phase}`,
58
+ provider: "telegram",
59
+ chatId: record.data.chatId,
60
+ threadId: record.data.threadId || null,
61
+ chatType: record.data.chatId.startsWith("-") ? "group" : "private",
62
+ participantIds: [record.memberId],
63
+ kind: "tool_result",
64
+ sessionId: record.data.sessionId,
65
+ toolCallId: record.id,
66
+ operationId: record.id,
67
+ toolName: record.data.action,
68
+ reason: phase,
69
+ status: phase === "done" ? "completed" : phase === "failed" ? "failed" : phase === "cancelled" || phase === "expired" ? "cancelled" : "requested"
70
+ }));
71
+ }
72
+ async function postDeferredCard(id, channel, ctx, options, archive, observed) {
73
+ const store = deferredConfirmations(options);
74
+ const record = await store.command({
75
+ operation: "read",
76
+ key: deferredKey(id)
77
+ });
78
+ if (!record || record.data.sessionId !== ctx.session.id || record.status !== "pending" || record.data.messageId) return;
79
+ const copy = copyOf(record);
80
+ const address = channel.continuation?.token ?? formatAddress({
81
+ chatId: record.data.chatId,
82
+ messageThreadId: record.data.threadId,
83
+ conversationId: channel.telegram.conversationId ?? ""
84
+ });
85
+ const prompt = {
86
+ ...promptOf(record, "pending"),
87
+ address
88
+ };
89
+ await archiveDeferred(record, "requested", archive);
90
+ const post = () => channel.telegram.post({
91
+ text: copy.text,
92
+ reply_markup: { inline_keyboard: [[
93
+ {
94
+ text: copy.confirm,
95
+ callback_data: deferredCallback(record, "y")
96
+ },
97
+ ...record.data.confirmation.description?.chatPost ? [{
98
+ text: copy.edit,
99
+ callback_data: deferredCallback(record, "e")
100
+ }] : [],
101
+ {
102
+ text: copy.cancel,
103
+ callback_data: deferredCallback(record, "n")
104
+ }
105
+ ]] }
106
+ });
107
+ const sent = await withConfirmationPrompt(prompt, () => record.data.confirmation.description?.chatPost ? withChatPostCard(copy.text, post, copy.previewLinks) : withConfirmationText(copy.text, post));
108
+ await store.command({
109
+ operation: "attach",
110
+ key: record.key,
111
+ messageId: sent.id,
112
+ address
113
+ });
114
+ remember({
115
+ ...record,
116
+ data: {
117
+ ...record.data,
118
+ messageId: sent.id,
119
+ address
120
+ }
121
+ }, copy.text, prompt, observed);
122
+ }
123
+ async function editCard(record, context, status, state, observed) {
124
+ if (!record.data.messageId) return;
125
+ const copy = copyOf(record);
126
+ const exact = record.data.confirmation.description?.chatPost !== void 0;
127
+ const text = exact ? chatPostCardStatus(copy.text, status) : `${copy.text}\n\n${status}`;
128
+ const edit = () => context.telegram.editMessageText({
129
+ messageId: record.data.messageId,
130
+ text,
131
+ replyMarkup: { inline_keyboard: [] }
132
+ });
133
+ const prompt = promptOf(record, state);
134
+ await withConfirmationPrompt(prompt, () => exact ? withChatPostCard(text, edit, [...copy.previewLinks ?? [], ...telegramTextLinks(status)]) : withConfirmationText(text, edit));
135
+ remember(record, text, prompt, observed);
136
+ }
137
+ async function handleDeferredCallback(input) {
138
+ const { query, context, options, archive } = input;
139
+ const notice = async (text) => {
140
+ try {
141
+ await context.telegram.answerCallbackQuery({
142
+ callbackQueryId: query.id,
143
+ text,
144
+ showAlert: false
145
+ });
146
+ } catch (error) {
147
+ reportTelegramError("deferred_acknowledgment_failed", error);
148
+ }
149
+ };
150
+ const parts = /^ss-confirm:d:([0-9a-f]{20}):([yne])$/.exec(query.data ?? "");
151
+ if (!parts || !query.message || query.from.isBot) {
152
+ await notice("⚠️");
153
+ return;
154
+ }
155
+ const store = deferredConfirmations(options);
156
+ const record = await store.command({
157
+ operation: "read",
158
+ key: parts[1]
159
+ });
160
+ const lookup = await input.identities.lookup({
161
+ provider: "telegram",
162
+ externalId: query.from.id
163
+ });
164
+ if (!record || lookup.status !== "paired" || lookup.member.id !== record.memberId || record.data.requester !== query.from.id || record.data.chatId !== query.message.chat.id || record.data.threadId !== String(query.message.messageThreadId ?? "") || record.data.messageId !== query.message.messageId) {
165
+ await notice("🔒");
166
+ return;
167
+ }
168
+ if (record.inputHash !== inputHash(record.data.input) || parts[2] === "e" && record.data.confirmation.description?.chatPost === void 0) {
169
+ await notice("⚠️");
170
+ return;
171
+ }
172
+ const copy = copyOf(record);
173
+ const decision = parts[2] === "y" ? "approve" : "cancel";
174
+ const claimed = await store.command({
175
+ operation: "decide",
176
+ key: record.key,
177
+ memberId: record.memberId,
178
+ inputHash: inputHash(record.data.input),
179
+ decision
180
+ });
181
+ if (!claimed || claimed.status === "pending") {
182
+ await notice("⌛");
183
+ return;
184
+ }
185
+ await notice(claimed.status === "expired" ? "⌛" : void 0);
186
+ let status = claimed.status;
187
+ let cardStatus = status === "expired" ? copy.expired : copy.cancelled;
188
+ let execution;
189
+ try {
190
+ await archiveDeferred(claimed, claimed.status, archive);
191
+ } catch (error) {
192
+ const reference = reportTelegramError("deferred_decision_archive_failed", error);
193
+ if (status === "approved") {
194
+ status = "failed";
195
+ execution = "not_started";
196
+ cardStatus = `${copy.failed} ${reference}`;
197
+ await store.command({
198
+ operation: "finish",
199
+ key: claimed.key,
200
+ status
201
+ });
202
+ }
203
+ }
204
+ if (status === "approved") {
205
+ try {
206
+ await editCard(claimed, context, copy.executing, "approved", input.observed);
207
+ } catch (error) {
208
+ reportTelegramError("deferred_card_update_failed", error);
209
+ }
210
+ try {
211
+ const result = await runDeferredAction(claimed, options);
212
+ status = "done";
213
+ cardStatus = claimed.data.confirmation.description?.chatPost ? chatPostReceipt(result.structuredContent, copy.completed) ?? "⚠️ ❓" : copy.completed;
214
+ } catch (error) {
215
+ status = "failed";
216
+ const reference = reportTelegramError("deferred_action_failed", error);
217
+ cardStatus = `${copy.failed} ${reference}`;
218
+ }
219
+ await store.command({
220
+ operation: "finish",
221
+ key: claimed.key,
222
+ status
223
+ });
224
+ }
225
+ if (status === "done" || status === "failed") try {
226
+ await archiveDeferred(claimed, status, archive);
227
+ } catch (error) {
228
+ reportTelegramError("deferred_outcome_archive_failed", error);
229
+ }
230
+ try {
231
+ await editCard(claimed, context, cardStatus, status === "done" ? "completed" : status, input.observed);
232
+ } catch (error) {
233
+ reportTelegramError("deferred_card_update_failed", error);
234
+ }
235
+ const principal = telegramPrincipal({
236
+ member: lookup.member,
237
+ message: {
238
+ ...query.message,
239
+ from: query.from,
240
+ text: "",
241
+ caption: "",
242
+ raw: {},
243
+ attachments: []
244
+ }
245
+ });
246
+ await currentInboundRequest()?.confirmationEvent?.(claimed, confirmationOutcome(claimed, status, {
247
+ ...execution === void 0 ? {} : { execution },
248
+ ...parts[2] === "e" && status === "cancelled" ? { editRequested: true } : {}
249
+ }), principal);
250
+ }
251
+ async function expireDeferredRecord(record, context, options, archive, notify, observed) {
252
+ const claimed = await deferredConfirmations(options).command({
253
+ operation: "decide",
254
+ key: record.key,
255
+ memberId: record.memberId,
256
+ inputHash: record.inputHash,
257
+ decision: "expire"
258
+ });
259
+ if (!claimed) return;
260
+ try {
261
+ await archiveDeferred(claimed, "expired", archive);
262
+ } catch (error) {
263
+ reportTelegramError("deferred_outcome_archive_failed", error);
264
+ }
265
+ try {
266
+ await editCard(claimed, context, copyOf(claimed).expired, "expired", observed);
267
+ } catch (error) {
268
+ reportTelegramError("deferred_card_update_failed", error);
269
+ }
270
+ await notify(claimed, confirmationOutcome(claimed, "expired"), null);
271
+ }
272
+ async function expireDeferredCards(context, options, archive, observed) {
273
+ const records = await deferredConfirmations(options).command({
274
+ operation: "expired",
275
+ chatId: context.telegram.chatId
276
+ });
277
+ for (const record of records) {
278
+ if (record.data.threadId !== String(context.telegram.messageThreadId ?? "")) continue;
279
+ await expireDeferredRecord(record, context, options, archive, async (saved, result, auth) => currentInboundRequest()?.confirmationEvent?.(saved, result, auth), observed);
280
+ }
281
+ }
282
+ export { archiveDeferred, deferredCallback, expireDeferredCards, expireDeferredRecord, handleDeferredCallback, isDeferredCallback, postDeferredCard };
@@ -5,9 +5,9 @@ const __filename = __eveFileURLToPath(import.meta.url);
5
5
  __eveDirname(__filename);
6
6
  __eveCreateRequire(import.meta.url);
7
7
  import { conversationLanguage } from "./principal.mjs";
8
- import { MAXIMUM_ATTACHMENT_BYTES, attachmentUrl } from "../attachments.mjs";
9
- import { d as failureText, p as reportTelegramError } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
8
+ import { d as failureText, p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
10
9
  import { describableImage, describeReceivedImage } from "./images.mjs";
10
+ import { MAXIMUM_ATTACHMENT_BYTES, attachmentUrl } from "../attachments.mjs";
11
11
  function telegramConversation(chatId) {
12
12
  return `telegram:${chatId}`;
13
13
  }
@@ -80,17 +80,33 @@ async function stageFiles(input) {
80
80
  sourceRef: `${message.chat.id}:${message.messageId}:${index}`
81
81
  });
82
82
  let description;
83
+ let decoded;
83
84
  let imageInput;
84
85
  if (input.imagePlan !== void 0 && contentType.startsWith("image/")) {
85
86
  imageInput = "text";
86
87
  if (!describableImage(contentType)) description = "[unsupported image format; original remains stored]";
87
88
  else if (input.imagePlan.images === "native" && bytes.byteLength <= 3145728) imageInput = "native";
88
89
  else if (input.imagePlan.images === "describe" && input.imagePlan.descriptionModel && input.describeImage) {
90
+ decoded = {
91
+ attachment_kind: file.kind,
92
+ model: input.imagePlan.descriptionModel,
93
+ processed: false,
94
+ status: "not_processed"
95
+ };
89
96
  description = descriptions >= 1 ? "[image description skipped: per-message limit; original remains stored]" : await describeReceivedImage({
90
97
  bytes,
91
98
  mediaType: contentType,
92
99
  model: input.imagePlan.descriptionModel,
93
- describe: input.describeImage
100
+ describe: input.describeImage,
101
+ retain: (content) => {
102
+ decoded = {
103
+ attachment_kind: file.kind,
104
+ model: input.imagePlan.descriptionModel,
105
+ processed: true,
106
+ status: "processed",
107
+ content
108
+ };
109
+ }
94
110
  });
95
111
  descriptions += 1;
96
112
  } else description = input.imagePlan.images === "native" ? "[image exceeds the native 3 MiB context limit; original remains stored]" : "[image analysis unavailable or disabled; original remains stored]";
@@ -104,6 +120,7 @@ async function stageFiles(input) {
104
120
  conversation
105
121
  }),
106
122
  ...description === void 0 ? {} : { description },
123
+ ...decoded === void 0 ? {} : { decoded },
107
124
  ...imageInput === void 0 ? {} : { imageInput }
108
125
  });
109
126
  } catch (error) {
@@ -16,4 +16,5 @@ export declare function describeReceivedImage(input: {
16
16
  readonly mediaType: string;
17
17
  readonly model: string;
18
18
  readonly describe: ImageDescriber;
19
+ readonly retain?: (text: string) => void;
19
20
  }): Promise<string>;
@@ -4,7 +4,7 @@ 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 { p as reportTelegramError } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
7
+ import { p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
8
8
  import { gateway, generateText } from "ai";
9
9
  const MAXIMUM_IMAGE_DESCRIPTION_BYTES = 5242880;
10
10
  const MAXIMUM_NATIVE_IMAGE_BYTES = 3145728;
@@ -39,6 +39,7 @@ async function describeReceivedImage(input) {
39
39
  if (input.bytes.byteLength > 5242880) return "[image description skipped: exceeds 5 MiB; original remains stored]";
40
40
  try {
41
41
  const text = (await input.describe(input)).trim();
42
+ if (text !== "") input.retain?.(text.slice(0, MAXIMUM_IMAGE_DESCRIPTION_CHARACTERS));
42
43
  return text === "" ? "[image description unavailable: empty result; original remains stored]" : text.length > MAXIMUM_IMAGE_DESCRIPTION_CHARACTERS ? `${text.slice(0, 511)}…` : text;
43
44
  } catch (error) {
44
45
  return `[image description failed; original remains stored; error reference: ${reportTelegramError("image_description_failed", error)}]`;
@@ -1,6 +1,8 @@
1
+ import type { DeferredConfirmation } from "../deferred-confirmations.js";
1
2
  import type { UserContent } from "ai";
2
3
  import type { ChannelSource } from "eve/channels";
3
4
  import type { SessionAuthContext } from "eve/context";
5
+ import type { DecodedAttachment } from "./attachment-description.js";
4
6
  import type { Attachment } from "../attachments.js";
5
7
  import type { SessionOperations } from "./sessions.js";
6
8
  /** What became of one Telegram file of the message: stored as an attachment, or why not. */
@@ -9,6 +11,7 @@ export type StagedFile = {
9
11
  readonly attachment: Attachment;
10
12
  readonly url: URL;
11
13
  readonly description?: string;
14
+ readonly decoded?: DecodedAttachment;
12
15
  readonly imageInput?: "native" | "text";
13
16
  } | {
14
17
  readonly status: "refused";
@@ -25,7 +28,17 @@ export type StagedFile = {
25
28
  export declare class InboundRequest {
26
29
  /** The agent's description from the compiled manifest, for the routing decision. */
27
30
  readonly agentDescription: () => Promise<string>;
31
+ readonly agentName: () => Promise<string>;
28
32
  edited: boolean;
33
+ previousText: string | undefined;
34
+ attachmentsChanged: boolean;
35
+ /** Evidence may be reused only while the provider attachment identities are unchanged. */
36
+ previousContent: {
37
+ readonly media?: string;
38
+ readonly decoded: ReadonlyArray<DecodedAttachment>;
39
+ } | undefined;
40
+ /** Claims one edit revision before routing, including revisions the classifier observes. */
41
+ claimRevision: (() => Promise<boolean>) | undefined;
29
42
  deliveryFailed: ((error: unknown) => Promise<void>) | undefined;
30
43
  /** Atomic per-message admission in the platform archive, after authentication and routing. */
31
44
  claimTurn: (() => Promise<boolean>) | undefined;
@@ -49,10 +62,11 @@ export declare class InboundRequest {
49
62
  waitUntil: ((task: Promise<unknown>) => void) | undefined;
50
63
  /** Continues the exact pending question's session, including under thread scope. */
51
64
  address: string | undefined;
65
+ confirmationEvent: ((record: DeferredConfirmation, result: Readonly<Record<string, unknown>>, auth: SessionAuthContext | null) => Promise<unknown>) | undefined;
52
66
  respond: ((address: string, requestId: string, decision: "approve" | "cancel", principal: SessionAuthContext, text?: string) => Promise<unknown>) | undefined;
53
67
  constructor(
54
68
  /** The agent's description from the compiled manifest, for the routing decision. */
55
- agentDescription: () => Promise<string>);
69
+ agentDescription: () => Promise<string>, agentName?: () => Promise<string>);
56
70
  }
57
71
  export declare function runInboundRequest<Result>(request: InboundRequest, run: () => Result): Result;
58
72
  /** The current webhook request, or `undefined` outside the wrapped route. */
@@ -4,5 +4,5 @@ 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 { i as withReplacedText, n as currentInboundRequest, r as runInboundRequest, t as InboundRequest } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
7
+ import { i as withReplacedText, n as currentInboundRequest, r as runInboundRequest, t as InboundRequest } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
8
8
  export { InboundRequest, currentInboundRequest, runInboundRequest, withReplacedText };
@@ -11,6 +11,8 @@ import { type ObservedMessages } from "./observed.js";
11
11
  import { type RouteDecider } from "./router.js";
12
12
  import { type HistoryReader, type SessionPolicy } from "./sessions.js";
13
13
  import { type Transcriber } from "./voice.js";
14
+ import { type AttachmentDescriber } from "./attachment-description.js";
15
+ import type { PdfTextExtractor } from "./pdf-text.js";
14
16
  /**
15
17
  * eve's Telegram `onMessage` hook, in the order `agent-design.md` gives:
16
18
  *
@@ -21,9 +23,9 @@ import { type Transcriber } from "./voice.js";
21
23
  * and so is the agent's own, which unlinks every member. Neither is the notice, in the old chat
22
24
  * or the new one, that a group became a supergroup: the migration is reported.
23
25
  * 2. Voice becomes text, so the router and the agent read what was said.
24
- * 3. The router answers or observes. Files always start a turn after the identity gates, even
25
- * without a caption or when addressed to another person. They are stored after the registry knows the
26
- * sender. Observing starts no session or typing indication;
26
+ * 3. The router answers or observes. Group files follow the same addressing rules as text;
27
+ * captionless uploads use smart routing and recent agent requests. Files are stored after the
28
+ * registry knows the sender. Observing starts no session or typing indication;
27
29
  * the ring carries the stored files' references (or storage failures) into the next reply.
28
30
  * 4. The session policy runs on the session an answered message continues: an idle one is cleared, the
29
31
  * first message after the day's compaction time compacts it.
@@ -39,6 +41,9 @@ export interface InboundDependencies {
39
41
  readonly sessions: () => SessionSettings;
40
42
  readonly sessionPolicy: SessionPolicy;
41
43
  readonly sttModel: string | false;
44
+ readonly attachmentsModel: string | false;
45
+ readonly describeAttachment: AttachmentDescriber;
46
+ readonly extractPdf?: PdfTextExtractor;
42
47
  readonly mediaPlan?: (member: PairedMember, sessionId?: string) => Promise<MediaPlan>;
43
48
  readonly describeImage?: ImageDescriber;
44
49
  readonly identities: AgentIdentities;
@@ -47,7 +52,10 @@ export interface InboundDependencies {
47
52
  /** Full session history for open questions, which can survive compaction. */
48
53
  readonly history?: HistoryReader;
49
54
  readonly transcribe: Transcriber;
50
- readonly download: (fileId: string) => Promise<Uint8Array>;
55
+ readonly download: (fileId: string, options?: {
56
+ readonly abortSignal?: AbortSignal;
57
+ readonly maxBytes?: number;
58
+ }) => Promise<Uint8Array>;
51
59
  /** The attachment store; without it, files reach the turn as eve's Telegram file parts. */
52
60
  readonly attachments?: AgentAttachments;
53
61
  readonly observed: ObservedMessages;