@segmentstream/agent 0.12.2 → 0.14.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 (75) hide show
  1. package/README.md +29 -22
  2. package/dist/_chunks/{build-metadata-CLprTpsn.mjs → build-metadata-BB2uSGsI.mjs} +1 -1
  3. package/dist/_chunks/{inbound-request-BrWspFw5.mjs → inbound-request-BXhiIph-.mjs} +21 -19
  4. package/dist/_chunks/principal-VFQWqe5S.mjs +126 -0
  5. package/dist/extension/_manifest.json +0 -1
  6. package/dist/extension/config.d.ts +23 -5
  7. package/dist/extension/config.mjs +167 -18
  8. package/dist/extension/extension.d.ts +7 -1
  9. package/dist/extension/hooks/authorization.d.ts +3 -0
  10. package/dist/extension/hooks/authorization.mjs +16 -0
  11. package/dist/extension/instructions.md +3 -4
  12. package/dist/extension/lib/attachment-tools.mjs +1 -1
  13. package/dist/extension/lib/attachments.d.ts +2 -0
  14. package/dist/extension/lib/attachments.mjs +1 -0
  15. package/dist/extension/lib/build-metadata.mjs +1 -1
  16. package/dist/extension/lib/chat-post-confirmation.d.ts +1 -0
  17. package/dist/extension/lib/chat-post-confirmation.mjs +4 -2
  18. package/dist/extension/lib/confirmation-outcome.d.ts +1 -1
  19. package/dist/extension/lib/confirmations.d.ts +2 -0
  20. package/dist/extension/lib/confirmations.mjs +8 -5
  21. package/dist/extension/lib/conversation-runtime.mjs +1 -1
  22. package/dist/extension/lib/deferred-confirmations.d.ts +5 -0
  23. package/dist/extension/lib/deferred-confirmations.mjs +23 -10
  24. package/dist/extension/lib/ontology-connection.d.ts +1 -0
  25. package/dist/extension/lib/ontology-connection.mjs +18 -12
  26. package/dist/extension/lib/ontology-gateway.mjs +9 -2
  27. package/dist/extension/lib/ontology-metadata-read.mjs +1 -1
  28. package/dist/extension/lib/ontology-tools.d.ts +9 -2
  29. package/dist/extension/lib/ontology-tools.mjs +29 -5
  30. package/dist/extension/lib/runtime-envelope.d.ts +28 -0
  31. package/dist/extension/lib/runtime-envelope.mjs +8 -0
  32. package/dist/extension/lib/stored-files.mjs +1 -1
  33. package/dist/extension/lib/telegram/adapter.mjs +53 -11
  34. package/dist/extension/lib/telegram/attachment-description.mjs +1 -1
  35. package/dist/extension/lib/telegram/attachments-send.mjs +15 -12
  36. package/dist/extension/lib/telegram/callbacks.d.ts +18 -0
  37. package/dist/extension/lib/telegram/callbacks.mjs +155 -0
  38. package/dist/extension/lib/telegram/chat-post-card.d.ts +1 -1
  39. package/dist/extension/lib/telegram/chat-post-card.mjs +13 -10
  40. package/dist/extension/lib/telegram/confirmation-expiry.d.ts +2 -1
  41. package/dist/extension/lib/telegram/confirmation-expiry.mjs +6 -5
  42. package/dist/extension/lib/telegram/confirmation-text.d.ts +1 -1
  43. package/dist/extension/lib/telegram/confirmation-text.mjs +18 -12
  44. package/dist/extension/lib/telegram/confirmations.mjs +28 -23
  45. package/dist/extension/lib/telegram/conversations.d.ts +2 -0
  46. package/dist/extension/lib/telegram/conversations.mjs +14 -1
  47. package/dist/extension/lib/telegram/customer-text.d.ts +9 -8
  48. package/dist/extension/lib/telegram/customer-text.mjs +1 -1
  49. package/dist/extension/lib/telegram/deferred-confirmations.mjs +14 -13
  50. package/dist/extension/lib/telegram/files.mjs +2 -2
  51. package/dist/extension/lib/telegram/health.mjs +1 -1
  52. package/dist/extension/lib/telegram/images.mjs +1 -1
  53. package/dist/extension/lib/telegram/inbound-request.mjs +1 -1
  54. package/dist/extension/lib/telegram/inbound.mjs +25 -20
  55. package/dist/extension/lib/telegram/lifecycle.mjs +15 -3
  56. package/dist/extension/lib/telegram/media-policy.mjs +1 -1
  57. package/dist/extension/lib/telegram/principal.d.ts +1 -0
  58. package/dist/extension/lib/telegram/principal.mjs +1 -49
  59. package/dist/extension/lib/telegram/sessions.d.ts +3 -1
  60. package/dist/extension/lib/telegram/silent.mjs +3 -3
  61. package/dist/extension/lib/telegram/texts.d.ts +16 -0
  62. package/dist/extension/lib/telegram/texts.mjs +70 -0
  63. package/dist/extension/lib/telegram/turn-errors.d.ts +1 -1
  64. package/dist/extension/lib/telegram/turn-errors.mjs +38 -4
  65. package/dist/extension/lib/telegram/voice.mjs +1 -1
  66. package/dist/extension/lib/telegram/workspace-action.d.ts +21 -0
  67. package/dist/extension/lib/telegram/workspace-action.mjs +23 -0
  68. package/dist/extension/model.mjs +1 -1
  69. package/dist/extension/schedules/confirmations.mjs +1 -1
  70. package/dist/extension/tools/attachments_promote.mjs +8 -0
  71. package/dist/extension/tools/ontology.mjs +2 -2
  72. package/dist/extension/tools/questions_ask.mjs +1 -1
  73. package/package.json +2 -2
  74. package/dist/extension/connections/ontology.d.ts +0 -7
  75. package/dist/extension/connections/ontology.mjs +0 -11
package/README.md CHANGED
@@ -189,13 +189,13 @@ continue using GET lookup. Starter templates and pins remain unchanged in this s
189
189
 
190
190
  ## What the extension contributes
191
191
 
192
- | Name | Slot | What it does |
193
- | ------------------------------------------------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
194
- | `segmentstream__ontology` | `connections` | The app's `/mcp`, resolved per turn for the turn's member. No member, no connection. |
195
- | `segmentstream__telegram` | `channels` | `POST /eve/v1/telegram`: Telegram through the connection, with pairing, routing and voice. |
196
- | `segmentstream__attachments_list`, `_read`, `_promote`, `_discard` | `tools` | The member's temporary attachments in this chat: list, read, keep through an action, drop. |
197
- | `segmentstream__attachments_send` | `tools` | Sends readable stored ontology files into the current Telegram chat and topic. |
198
- | platform rules | `instructions` | Changes go through actions; `describe` indexes or inspects refs; `discover` searches metadata; tools are already narrowed; when to answer `[SILENT]`; how to handle attachments |
192
+ | Name | Slot | What it does |
193
+ | -------------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
194
+ | `segmentstream__ontology_describe`, `_discover`, `_inspect`, `_call` | `tools` | Permission-filtered metadata, schema inspection and action calls as the current member. |
195
+ | `segmentstream__telegram` | `channels` | `POST /eve/v1/telegram`: Telegram through the connection, with pairing, routing and voice. |
196
+ | `segmentstream__attachments_list`, `_read`, `_promote`, `_discard` | `tools` | The member's temporary attachments in this chat: list, read, keep through an action, drop. |
197
+ | `segmentstream__attachments_send` | `tools` | Sends readable stored ontology files into the current Telegram chat and topic. |
198
+ | platform rules | `instructions` | Changes go through actions; `describe` indexes or inspects refs; `discover` searches metadata; tools are already narrowed; when to answer `[SILENT]`; how to handle attachments |
199
199
 
200
200
  ### The ontology
201
201
 
@@ -222,15 +222,17 @@ share a group chat's session never share a client.
222
222
  proxy. The token stays in SegmentStream.
223
223
  - **Webhook.** A webhook is accepted only with `X-Telegram-Bot-Api-Secret-Token` equal to
224
224
  `SEGMENTSTREAM_AGENT_WEBHOOK_SECRET`, compared in constant time. The platform generates the
225
- secret and registers the webhook after each production deployment, and sets the bot's menu
226
- button, shown in private chats, to open the workspace app.
225
+ secret and registers the webhook after each production deployment. A workspace-supplied
226
+ `menuButton.text` enables the app menu button; omitting it resets the provider menu to its default
227
+ for Agent SDK 0.13 or later. Pre-0.13 archives without menu copy retain their existing provider menu.
227
228
  - **Production only.** Outside `VERCEL_ENV=production` the route answers 200 and does nothing, so a
228
229
  preview never answers a real chat. Without `channels.telegram` it answers 404.
229
230
  - **Pairing.** Bots and channel posts are archived without starting turns. The sender's Telegram
230
231
  account is checked on every message, so revocation takes effect immediately. Unlinked group
231
232
  speech and attachment metadata remain raw context, including edits; no unlinked voice is decoded or gets
232
- a reply. An unknown private sender gets a neutral connection button to `/agent/connect?code=…`,
233
- valid for ten minutes; revoked or inactive private senders get a neutral refusal marker.
233
+ a reply. An unknown private sender gets the workspace pairing prompt and button to `/agent/connect?code=…`,
234
+ valid for ten minutes; revoked or inactive private senders receive configured refusal copy,
235
+ or no message when it is absent.
234
236
  - **Who the agent is.** A paired sender's turn runs with the principal id `telegram:<user>`
235
237
  (`telegram:<chat>:<user>` in groups) and the attributes `memberId`, `memberName`, `roles`,
236
238
  `chatId`, `chatType` and `username`.
@@ -516,7 +518,7 @@ ontology SDK along with this extension. See the repository's
516
518
  [conversation storage guide](../../docs/agent-conversation-storage.md) for APIs, retention,
517
519
  eve's existing storage, and Telegram's delivery limits.
518
520
 
519
- ### Exact chat posting protocol (prepared in agent SDK 0.6.0)
521
+ ### Exact chat posting protocol
520
522
 
521
523
  An authenticated `tools/list` advertises `_meta: { "segmentstream/chat-post": 1 }` on
522
524
  `chat_post_message`. Without this marker,
@@ -525,12 +527,12 @@ missing/incomplete preview metadata is denied. The versioned connection has its
525
527
 
526
528
  The runtime reads `me` for the server-derived `attribution`, and `chat_list({ chat })` for exactly
527
529
  one eligible destination: `{ items: [{ id, title, provider, external_id }], next_cursor: null }`.
528
- Provider is currently `telegram`. The final plain text is exactly `attribution + ": " + text`;
530
+ Provider is currently `telegram`. The final plain text is `text + separator + attribution`, with a blank line as the neutral separator;
529
531
  `reply_to` is optional. A preview digest is SHA-256 of the JSON array of chat ID, provider,
530
532
  external ID, title, attribution, text, final text and nullable reply target, in that order.
531
533
  The target/attribution are resolved again immediately before executing the frozen call.
532
534
 
533
- Eve supplies the model-hidden `_segmentstream` argument on **all** calls of a negotiated connection.
535
+ The SDK constructs model-hidden `_segmentstream` metadata for approved runtime posts.
534
536
  It contains `version: 1`, `session_id` and `call_id`. A consumed, unexpired chat approval additionally
535
537
  supplies `operation_id`, source provider/chat/topic coordinates and `expected: { chat_id, digest }`.
536
538
  The operation ID is `hq:` plus SHA-256 of the JSON array `[session_id, call_id]`; it stays stable
@@ -538,7 +540,8 @@ on replay and changes for a revision. The model cannot provide an idempotency ke
538
540
  The ontology must authenticate runtime provenance, consume/remove the envelope before strict input
539
541
  validation for ordinary tools, derive the posting key from the operation, and recompute attribution.
540
542
  External OAuth/service callers still supply their own `idempotency_key` and cannot use this envelope.
541
- These server changes belong to the later ontology stage; do not advertise the marker prematurely.
543
+ The coordinated ontology SDK implements this protocol; deploy the compatible ontology before
544
+ using agent exact posting.
542
545
 
543
546
  Source previews, accepted decisions and receipts use existing archive events with operation-linked
544
547
  `toolCallId`/event IDs. A cancelled Edit carries its pending revision question in the authoritative
@@ -546,10 +549,12 @@ Eve resolution, so member/topic routing survives a cold start. No second provide
546
549
 
547
550
  ## Release and migration
548
551
 
549
- The tested release uses agent SDK 0.6.4, Eve 0.76.3 and ontology SDK 0.28.3.
550
- Deploy the agent first, then backend archive migration 0033/API, then the ontology
551
- with its declared Telegram provider mapping and explicit `agent_chat:post_message`
552
- grant. Older ontologies keep ordinary tools working without the extra envelope.
552
+ The coordinated release uses Agent SDK 0.14.0, Eve 0.76.3, Ontology SDK 0.50.0 and App SDK 0.24.1.
553
+ The compatible Cloud archive/API must be deployed first; migrations run only through its CI/CD gate.
554
+ Publish the ontology SDK before the agent SDK. Upgrade the workspace ontology before its agent,
555
+ with the declared Telegram provider mapping and explicit `agent_chat:post_message` grant.
556
+ Supply the required workspace presentation before upgrading the agent to 0.13.x.
557
+ Older ontologies keep ordinary tools working without the extra envelope.
553
558
  An older archive returning only `{stored:true}` cannot authorize a send.
554
559
 
555
560
  Rollback
@@ -615,7 +620,7 @@ can redeliver the same source; the hook and attachment reservation must preserve
615
620
  idempotent source membership, storage results and the single acknowledgement.
616
621
  Such a failure must not become an HTTP success with no queued work.
617
622
 
618
- ### Legacy held approvals
623
+ ### Deferred approvals and legacy recovery
619
624
 
620
625
  Deferred mode supplies four eager tools: `segmentstream__ontology_discover`,
621
626
  `segmentstream__ontology_describe`, `segmentstream__ontology_inspect` and `segmentstream__ontology_call`. Registration
@@ -636,11 +641,13 @@ actionable explanation. Reply delivery carries the owning turn's reply anchor
636
641
  explicitly after restore. Omitting the version preserves existing closed lifecycle
637
642
  data schemas; workspaces opt in only after their hook accepts the additional fields.
638
643
 
639
- Explicit `confirmations.mode: "held"` overrides the deferred default. Switching a package version
640
- does not migrate already-running held turns. In deferred mode the Telegram adapter reads the owning session's
644
+ `confirmations.mode: "held"` is rejected. Already-running held turns still need recovery.
645
+ The Telegram adapter reads the owning session's
641
646
  recorded approval inputs and requests cancellation of that exact turn before admitting a new
642
647
  addressed message. It never approves the old call or reuses the old member's authorization.
643
648
  Cancellation failure requests webhook replay; terminal/resolved approvals are left alone.
644
649
  Deferred mode retains its ten-minute database deadline and minute expiry sweep. Runtime health
645
650
  reports the effective confirmation mode and attachment-lifecycle presence behind its existing
646
651
  runtime authentication; source pins and public health alone are not settings-adoption proof.
652
+
653
+ Telegram 0.13.0 requires workspace-authored pairing and confirmation text. See [workspace Telegram text](../../docs/agent.md#workspace-telegram-text) for keys, limits, neutral fallbacks and unsupported Eve buttons.
@@ -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
- var version = "0.12.2";
7
+ var version = "0.14.0";
8
8
  function agentBuild(environment = process.env) {
9
9
  return {
10
10
  agent: version,
@@ -4,15 +4,16 @@ 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 { telegramText } from "../extension/lib/telegram/texts.mjs";
7
8
  import { isTechnicalText } from "../extension/lib/customer-text-safety.mjs";
8
9
  import { redactDiagnostic } from "../extension/lib/diagnostics.mjs";
9
10
  import { isConfirmationText } from "../extension/lib/telegram/confirmation-text.mjs";
10
11
  import { chatPostCardLinks, isExactChatPostCard } from "../extension/lib/telegram/chat-post-card.mjs";
11
12
  import { plainTelegramText, splitTelegramText, telegramMarkdown } from "../extension/lib/telegram/format.mjs";
12
13
  import { inTelegramSendQueue } from "../extension/lib/telegram/send-queue.mjs";
13
- import { telegramPreviewOptions, telegramTextLinks } from "@segmentstream-cloud/ontology/telegram";
14
14
  import { randomBytes, randomUUID } from "node:crypto";
15
15
  import { AsyncLocalStorage } from "node:async_hooks";
16
+ import { telegramPreviewOptions, telegramTextLinks } from "@segmentstream-cloud/ontology/telegram";
16
17
  const deliveryLocale = new AsyncLocalStorage();
17
18
  function withDeliveryLocale(locale, run, threadId, replyTo, chatId) {
18
19
  return deliveryLocale.run({
@@ -28,15 +29,16 @@ function currentLocale() {
28
29
  function currentThreadId() {
29
30
  return deliveryLocale.getStore()?.threadId ?? currentInboundRequest()?.threadId;
30
31
  }
31
- function customerCopy() {
32
+ function customerCopy(locale = currentLocale()) {
32
33
  return {
33
- failed: "⚠️",
34
- recovery: "⚠️",
35
- attachment: "⚠️",
36
- authorization: "⚠️",
37
- response: "⚠️",
38
- connected: "✅",
39
- disconnected: "❌"
34
+ failed: telegramText("notice", "failed", locale),
35
+ recovery: telegramText("notice", "recovery", locale),
36
+ attachment: telegramText("notice", "attachment", locale),
37
+ authorization: telegramText("notice", "authorization", locale),
38
+ response: telegramText("notice", "response", locale),
39
+ connected: telegramText("notice", "connected", locale),
40
+ disconnected: telegramText("notice", "disconnected", locale),
41
+ cancelled: telegramText("notice", "cancelled", locale)
40
42
  };
41
43
  }
42
44
  function redactCredentials(value) {
@@ -46,7 +48,7 @@ function redactCredentials(value) {
46
48
  return value;
47
49
  }
48
50
  function reportTelegramError(operation, error, metadata = {}, secrets = new Set()) {
49
- const errorId = randomBytes(4).toString("hex").toUpperCase();
51
+ const errorId = randomBytes(4).toString("hex");
50
52
  const credentials = new Set([...secrets, ...[process.env.AI_GATEWAY_API_KEY, process.env.VERCEL_OIDC_TOKEN].filter((value) => value !== void 0)]);
51
53
  console.error("[segmentstream] Telegram delivery diagnostic", {
52
54
  ...metadata,
@@ -57,8 +59,8 @@ function reportTelegramError(operation, error, metadata = {}, secrets = new Set(
57
59
  return errorId;
58
60
  }
59
61
  function failureText(errorId, kind = "failed", _locale = currentLocale()) {
60
- if (kind === "cancelled") return `⏹ ${errorId}`;
61
- return `${customerCopy()[kind]} ${errorId}`;
62
+ const text = customerCopy(_locale)[kind];
63
+ return text === void 0 ? errorId : `${text} ${errorId}`;
62
64
  }
63
65
  function customerText(text, locale = currentLocale()) {
64
66
  if (!isTechnicalText(text)) return text;
@@ -118,6 +120,7 @@ function safeTelegramFetch(fetchImpl, scope = "telegram", previews = {}) {
118
120
  "sendMessage",
119
121
  "editMessageText",
120
122
  "editMessageCaption",
123
+ "editMessageReplyMarkup",
121
124
  "answerCallbackQuery",
122
125
  "sendPhoto",
123
126
  "sendDocument",
@@ -160,14 +163,13 @@ function safeTelegramFetch(fetchImpl, scope = "telegram", previews = {}) {
160
163
  const markup = body.reply_markup;
161
164
  if (Array.isArray(markup?.inline_keyboard)) {
162
165
  if ((textBlocked || typeof body.text === "string" && body.text.length > 4096) && markup.inline_keyboard.some((row) => row.some((button) => typeof button.callback_data === "string" && button.callback_data.startsWith("ss-confirm:")))) throw new Error("Approval buttons require the complete, safe confirmation text.");
163
- markup.inline_keyboard = markup.inline_keyboard.map((row) => row.map((button) => {
164
- if (typeof button.text !== "string" || !isTechnicalText(button.text)) return button;
166
+ const rows = markup.inline_keyboard.map((row) => row.filter((button) => {
167
+ if (typeof button.text !== "string" || !isTechnicalText(button.text)) return true;
165
168
  reportTelegramError("technical_button_label_blocked", { text: button.text });
166
- return {
167
- ...button,
168
- text: "➡️"
169
- };
170
- }));
169
+ return false;
170
+ })).filter((row) => row.length > 0);
171
+ if (rows.length === 0 && markup.inline_keyboard.length > 0) delete body.reply_markup;
172
+ else markup.inline_keyboard = rows;
171
173
  }
172
174
  const send = async () => {
173
175
  const parts = url.endsWith("/sendMessage") && typeof body.text === "string" && !isExactChatPostCard(body.text) ? splitTelegramText({
@@ -0,0 +1,126 @@
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 { n as currentInboundRequest } from "./inbound-request-BXhiIph-.mjs";
8
+ import { randomUUID } from "node:crypto";
9
+ function telegramRuntimeSource(message, files, callbackQueryId) {
10
+ const attachments = [];
11
+ for (const file of message.attachments) {
12
+ const staged = files?.get(file.fileId);
13
+ if (staged?.status !== "stored" || attachments.length >= 10) continue;
14
+ let kind = file.kind;
15
+ for (const candidate of [
16
+ "voice",
17
+ "audio",
18
+ "video",
19
+ "video_note",
20
+ "sticker",
21
+ "animation"
22
+ ]) {
23
+ const raw = message.raw[candidate];
24
+ if (raw !== null && typeof raw === "object" && !Array.isArray(raw) && raw.file_id === file.fileId) kind = candidate;
25
+ }
26
+ attachments.push({
27
+ file_id: file.fileId,
28
+ kind,
29
+ staged_id: staged.attachment.id,
30
+ ...file.fileUniqueId === void 0 ? {} : { file_unique_id: file.fileUniqueId },
31
+ media_type: staged.attachment.contentType
32
+ });
33
+ }
34
+ return {
35
+ provider: "telegram",
36
+ chat_id: message.chat.id,
37
+ thread_id: String(message.messageThreadId ?? ""),
38
+ message_id: message.messageId,
39
+ ...message.replyToMessage === void 0 ? {} : { reply_to_message_id: message.replyToMessage.messageId },
40
+ ...message.from === void 0 ? {} : { sender: message.from.id },
41
+ ...callbackQueryId === void 0 ? {} : { callback_query_id: callbackQueryId },
42
+ ...attachments.length === 0 ? {} : { attachments }
43
+ };
44
+ }
45
+ function principalRuntimeSource(principal) {
46
+ if (principal?.authenticator !== "segmentstream-telegram") return;
47
+ const value = principal.attributes.segmentstreamRuntimeSource;
48
+ if (typeof value !== "string") return;
49
+ try {
50
+ return JSON.parse(value);
51
+ } catch {
52
+ return;
53
+ }
54
+ }
55
+ function runtimeEnvelope(input = {}) {
56
+ const source = input.source ?? principalRuntimeSource(input.principal);
57
+ return {
58
+ version: 1,
59
+ session_id: input.sessionId ?? randomUUID(),
60
+ call_id: input.callId ?? randomUUID(),
61
+ ...source === void 0 ? {} : { source }
62
+ };
63
+ }
64
+ function compatibleRuntimeEnvelope(envelope, extended) {
65
+ const source = envelope.source;
66
+ return extended || source === void 0 ? envelope : {
67
+ ...envelope,
68
+ source: {
69
+ provider: source.provider,
70
+ chat_id: source.chat_id,
71
+ thread_id: source.thread_id
72
+ }
73
+ };
74
+ }
75
+ const RUNTIME_SOURCE_PROTOCOL = "segmentstream/runtime-source";
76
+ const TELEGRAM_AUTHENTICATOR = "segmentstream-telegram";
77
+ function isGroup(message) {
78
+ return message.chat.type === "group" || message.chat.type === "supergroup";
79
+ }
80
+ function telegramPrincipal(input) {
81
+ const { message, member } = input;
82
+ const sender = message.from.id;
83
+ const attributes = {
84
+ memberId: member.id,
85
+ segmentstreamRuntimeSource: JSON.stringify(telegramRuntimeSource(message, currentInboundRequest()?.files, input.callbackQueryId)),
86
+ identityProvider: "telegram",
87
+ roles: member.roles,
88
+ chatId: message.chat.id,
89
+ chatType: message.chat.type
90
+ };
91
+ if (member.name !== null) attributes.memberName = member.name;
92
+ if (message.messageThreadId !== void 0) attributes.messageThreadId = String(message.messageThreadId);
93
+ if (message.from.username !== void 0) attributes.username = message.from.username;
94
+ const locale = member.locale ?? message.from.languageCode;
95
+ if (locale !== void 0) attributes.locale = locale;
96
+ const language = input.conversationLanguage ?? conversationLanguage([message.text || message.caption]);
97
+ if (language !== void 0) attributes.conversationLanguage = language;
98
+ return {
99
+ authenticator: TELEGRAM_AUTHENTICATOR,
100
+ issuer: "telegram",
101
+ principalId: isGroup(message) ? `telegram:${message.chat.id}:${sender}` : `telegram:${sender}`,
102
+ principalType: "user",
103
+ subject: sender,
104
+ attributes
105
+ };
106
+ }
107
+ function conversationLanguage(texts) {
108
+ for (const text of texts) {
109
+ if (/[\u0430-\u044f\u0451]/iu.test(text)) return "ru";
110
+ if ((text.match(/\b[a-z]+\b/gi)?.length ?? 0) >= 3) return "en";
111
+ }
112
+ }
113
+ function memberIdOf(principal) {
114
+ const memberId = principal?.attributes.memberId;
115
+ return typeof memberId === "string" && memberId !== "" ? memberId : void 0;
116
+ }
117
+ function rolesOf(principal) {
118
+ const roles = principal?.attributes.roles;
119
+ if (typeof roles === "string") return [roles];
120
+ return roles ?? [];
121
+ }
122
+ function identityProviderOf(principal) {
123
+ const provider = principal?.attributes.identityProvider;
124
+ return typeof provider === "string" && provider !== "" ? provider : void 0;
125
+ }
126
+ export { rolesOf as a, compatibleRuntimeEnvelope as c, telegramRuntimeSource as d, memberIdOf as i, principalRuntimeSource as l, conversationLanguage as n, telegramPrincipal as o, identityProviderOf as r, RUNTIME_SOURCE_PROTOCOL as s, TELEGRAM_AUTHENTICATOR as t, runtimeEnvelope as u };
@@ -8,7 +8,6 @@
8
8
  "dynamicTool": 79,
9
9
  "channel": 58,
10
10
  "schedule": 31,
11
- "connection": 46,
12
11
  "hook": 44,
13
12
  "instructions": 2,
14
13
  "dynamicInstructions": 37,
@@ -1,5 +1,7 @@
1
1
  import { type GroupPolicyInput } from "@segmentstream-cloud/ontology/groups";
2
2
  import { type GroupPolicy } from "./lib/group-routing/policy.js";
3
+ import type { WorkspaceActionHook } from "./lib/telegram/workspace-action.js";
4
+ import { type TelegramTexts } from "./lib/telegram/texts.js";
3
5
  import type { AttachmentLifecycle } from "./lib/telegram/lifecycle.js";
4
6
  import { type TelegramLinkPreviews } from "@segmentstream-cloud/ontology/telegram";
5
7
  export declare const TELEGRAM_POLICIES: readonly ["mention", "smart"];
@@ -40,12 +42,13 @@ export interface FirstContactSettings {
40
42
  readonly version: string;
41
43
  readonly notice: LocalizedText;
42
44
  }
43
- export declare const ADMISSION_REPLY_KEYS: readonly ["limited", "perSenderLimited", "workspaceLimited", "registrationsLimited", "groupPairingRequired", "refused"];
45
+ export declare const ADMISSION_REPLY_KEYS: readonly ["pairingRequired", "pairingButton", "groupPairingButton", "limited", "perSenderLimited", "workspaceLimited", "registrationsLimited", "groupPairingRequired", "refused"];
44
46
  export type AdmissionReplies = Partial<Record<(typeof ADMISSION_REPLY_KEYS)[number], LocalizedText>>;
45
47
  export interface AdmissionSettings {
46
48
  readonly firstContact: FirstContactSettings | null;
47
49
  readonly limits: AdmissionLimits;
48
50
  readonly replies: AdmissionReplies;
51
+ readonly texts?: TelegramTexts;
49
52
  }
50
53
  /**
51
54
  * `agent/segmentstream.json` as authored. A JSON import widens string literals to `string` and
@@ -54,6 +57,7 @@ export interface AdmissionSettings {
54
57
  */
55
58
  export interface SegmentStreamAgentConfigInput {
56
59
  readonly groups?: GroupPolicyInput;
60
+ readonly texts?: TelegramTexts;
57
61
  readonly firstContact?: FirstContactSettings;
58
62
  readonly limits?: AdmissionLimitsInput;
59
63
  readonly replies?: AdmissionReplies;
@@ -72,6 +76,12 @@ export interface SegmentStreamAgentConfigInput {
72
76
  readonly linkPreviews?: string;
73
77
  /** Additional exact HTTP(S) origins belonging to this workspace. */
74
78
  readonly additionalOwnOrigins?: readonly string[];
79
+ readonly callbacks?: Omit<WorkspaceActionHook, "contextVersion"> & {
80
+ readonly contextVersion: number;
81
+ };
82
+ readonly menuButton?: {
83
+ readonly text: LocalizedText;
84
+ };
75
85
  readonly attachmentLifecycle?: Omit<AttachmentLifecycle, "contextVersion"> & {
76
86
  readonly contextVersion?: number;
77
87
  };
@@ -102,7 +112,7 @@ export interface SegmentStreamAgentConfigInput {
102
112
  readonly connection?: boolean;
103
113
  };
104
114
  readonly confirmations?: {
105
- /** `deferred` (default) returns immediately; `held` uses eve approval. */
115
+ /** `deferred` (default) returns immediately. Eve button approvals are unsupported. */
106
116
  readonly mode?: string;
107
117
  };
108
118
  readonly sessions?: {
@@ -128,11 +138,15 @@ export interface TelegramSettings {
128
138
  readonly topicScope?: boolean;
129
139
  readonly commandsAddress?: boolean;
130
140
  };
141
+ readonly callbacks?: WorkspaceActionHook;
131
142
  readonly connection: string;
132
143
  readonly policy: TelegramPolicy;
133
144
  readonly linkPreviews?: TelegramLinkPreviews;
134
145
  readonly additionalOwnOrigins?: readonly string[];
135
146
  readonly attachmentLifecycle?: AttachmentLifecycle;
147
+ readonly menuButton?: {
148
+ readonly text: LocalizedText;
149
+ };
136
150
  }
137
151
  /** The chat models `segmentstream.model()` chooses between, as AI Gateway model ids. */
138
152
  export interface ChatModelChoice {
@@ -175,7 +189,7 @@ export interface SegmentStreamAgentConfig extends AdmissionSettings {
175
189
  readonly connection: boolean;
176
190
  };
177
191
  readonly confirmations: {
178
- readonly mode: "deferred" | "held";
192
+ readonly mode: "deferred";
179
193
  };
180
194
  readonly sessions: SessionSettings;
181
195
  }
@@ -196,8 +210,12 @@ export declare class SegmentStreamAgentConfigError extends Error {
196
210
  readonly name = "SegmentStreamAgentConfigError";
197
211
  constructor(issues: ReadonlyArray<ConfigIssue>);
198
212
  }
213
+ /** Exact historical pins retain the pre-0.13 presentation contract at the archive boundary. */
214
+ export declare function isLegacyAgentArchive(version: string | undefined): boolean;
199
215
  /** Validates the authored configuration and applies the defaults. */
200
- export declare function validateConfig(input: unknown): Validation;
216
+ export declare function validateConfig(input: unknown, options?: {
217
+ readonly archiveSdkVersion?: string;
218
+ }): Validation;
201
219
  /**
202
220
  * The Standard Schema eve validates the mount with. `types` exists only for type inference, as the
203
221
  * Standard Schema specification allows.
@@ -206,7 +224,7 @@ export declare const configSchema: {
206
224
  readonly "~standard": {
207
225
  readonly version: 1;
208
226
  readonly vendor: "segmentstream";
209
- readonly validate: typeof validateConfig;
227
+ readonly validate: (input: unknown) => Validation;
210
228
  readonly types: {
211
229
  readonly input: SegmentStreamAgentConfigInput;
212
230
  readonly output: SegmentStreamAgentConfig;