@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
@@ -36,6 +36,7 @@ export declare function ontologyConnection(input: {
36
36
  readonly fetch?: typeof fetch;
37
37
  /** Set only by the authenticated catalog handshake, never by model input. */
38
38
  readonly chatPosting?: boolean;
39
+ readonly runtimeSource?: boolean;
39
40
  }): McpClientConnectionDefinition | null;
40
41
  /** Negotiate before opening Eve's client: old strict schemas never receive the new envelope. */
41
42
  export declare function ontologyConnectionForTurn(input: Parameters<typeof ontologyConnection>[0]): Promise<McpClientConnectionDefinition | null>;
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
5
5
  __eveDirname(__filename);
6
6
  __eveCreateRequire(import.meta.url);
7
7
  import { appOrigin } from "./environment.mjs";
8
- import { identityProviderOf, memberIdOf } from "./telegram/principal.mjs";
8
+ import { c as compatibleRuntimeEnvelope, i as memberIdOf, r as identityProviderOf, u as runtimeEnvelope } from "../../_chunks/principal-VFQWqe5S.mjs";
9
9
  import { runtimeToken, tokenExpiry } from "./runtime-token.mjs";
10
10
  import { CHAT_POST_ENVELOPE, chatPostDigest, chatPostOperationId, isChatPost } from "./chat-post-confirmation.mjs";
11
11
  import { actionApproval, confirmations } from "./confirmations.mjs";
@@ -31,21 +31,23 @@ function ontologyConnection(input) {
31
31
  if (memberId === void 0) return null;
32
32
  const origin = appOrigin(input.environment ?? process.env);
33
33
  const token = input.token ?? runtimeToken;
34
+ const chatProtocol = input.chatPosting ? ":chat-post-v1" : "";
35
+ const sourceProtocol = input.runtimeSource ? ":runtime-source-v1" : "";
34
36
  return defineMcpClientConnection({
35
37
  url: `${origin}/mcp`,
36
38
  description: DESCRIPTION,
37
- instanceKey: `${origin}/mcp#member:${memberId}${input.chatPosting ? ":chat-post-v1" : ""}`,
39
+ instanceKey: `${origin}/mcp#member:${memberId}${chatProtocol}${sourceProtocol}`,
38
40
  approval: actionApproval(ontologyTools(input)),
39
- ...input.chatPosting ? { toolCall: { providedArguments: { [CHAT_POST_ENVELOPE]: (ctx) => {
41
+ ...input.chatPosting || input.runtimeSource ? { toolCall: { providedArguments: { [CHAT_POST_ENVELOPE]: (ctx) => {
40
42
  actAsHeaders({
41
43
  principal: ctx.session.auth.current,
42
44
  expectedMemberId: memberId
43
45
  });
44
- const base = {
45
- version: 1,
46
- session_id: ctx.session.id,
47
- call_id: ctx.callId
48
- };
46
+ const base = compatibleRuntimeEnvelope(runtimeEnvelope({
47
+ principal: ctx.session.auth.current,
48
+ sessionId: ctx.session.id,
49
+ callId: ctx.callId
50
+ }), input.runtimeSource === true);
49
51
  if (!isChatPost(ctx.toolName)) return base;
50
52
  const saved = confirmations.get()[ctx.callId];
51
53
  const preview = saved?.description?.chatPost;
@@ -56,7 +58,8 @@ function ontologyConnection(input) {
56
58
  source: {
57
59
  provider: "telegram",
58
60
  chat_id: saved.source.chatId,
59
- thread_id: saved.source.threadId
61
+ thread_id: saved.source.threadId,
62
+ ...base.source
60
63
  },
61
64
  expected: {
62
65
  chat_id: preview.chatId,
@@ -84,15 +87,18 @@ function ontologyConnection(input) {
84
87
  async function ontologyConnectionForTurn(input) {
85
88
  const memberId = memberIdOf(input.principal);
86
89
  if (memberId === void 0) return null;
87
- let chatPosting = false;
90
+ let capabilities = {
91
+ chatPosting: false,
92
+ runtimeSource: false
93
+ };
88
94
  try {
89
- chatPosting = await ontologyTools(input).supportsChatPosting(memberId);
95
+ capabilities = await ontologyTools(input).capabilities(memberId);
90
96
  } catch (error) {
91
97
  console.warn("Chat posting capability unavailable; keeping the compatible ontology connection.", error);
92
98
  }
93
99
  return ontologyConnection({
94
100
  ...input,
95
- chatPosting
101
+ ...capabilities
96
102
  });
97
103
  }
98
104
  export { ACT_AS_HEADER, MemberRequiredError, actAsHeaders, ontologyConnection, ontologyConnectionForTurn };
@@ -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 { memberIdOf } from "./telegram/principal.mjs";
7
+ import { i as memberIdOf, u as runtimeEnvelope } from "../../_chunks/principal-VFQWqe5S.mjs";
8
8
  import { object } from "./confirmation-description.mjs";
9
9
  import { readOntologyMetadata } from "./ontology-metadata-read.mjs";
10
10
  async function ontologyMetadata(memberId, operation, input, context, options = {}) {
@@ -16,7 +16,14 @@ async function ontologyMetadata(memberId, operation, input, context, options = {
16
16
  name: operation,
17
17
  arguments: input
18
18
  }
19
- }, context, options);
19
+ }, context, {
20
+ ...options,
21
+ envelope: runtimeEnvelope({
22
+ principal,
23
+ sessionId: context.session.id,
24
+ callId: context.callId
25
+ })
26
+ });
20
27
  return result.structuredContent === void 0 ? result : object(result.structuredContent);
21
28
  }
22
29
  async function ontologyInspect(memberId, input, context, options = {}) {
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
5
5
  __eveDirname(__filename);
6
6
  __eveCreateRequire(import.meta.url);
7
7
  import { appOrigin } from "./environment.mjs";
8
- import { memberIdOf } from "./telegram/principal.mjs";
8
+ import { i as memberIdOf } from "../../_chunks/principal-VFQWqe5S.mjs";
9
9
  import { redactDiagnostic } from "./diagnostics.mjs";
10
10
  import { object } from "./confirmation-description.mjs";
11
11
  import { OntologyToolRejected, ontologyTools } from "./ontology-tools.mjs";
@@ -1,3 +1,4 @@
1
+ import { type RuntimeEnvelope } from "./runtime-envelope.js";
1
2
  import type { SessionAuthContext } from "eve/context";
2
3
  import type { ActionAnnotations } from "./confirmations.js";
3
4
  import { type Environment } from "./environment.js";
@@ -13,17 +14,23 @@ export declare class OntologyActionNotPermitted extends Error {
13
14
  /** A fresh, permission-filtered catalog. Listing tools cannot run an action's prepare step. */
14
15
  export declare function ontologyTools(options?: {
15
16
  readonly principal?: SessionAuthContext | null;
17
+ readonly envelope?: RuntimeEnvelope;
16
18
  readonly environment?: Environment;
17
19
  readonly token?: RuntimeToken;
18
20
  readonly fetch?: typeof fetch;
19
21
  }): {
20
22
  rpc: (memberId: string, method: string, params: Record<string, unknown>, signal?: AbortSignal) => Promise<Record<string, unknown>>;
21
23
  list(memberId: string): Promise<Record<string, unknown>[]>;
24
+ supportsRuntimeSource(memberId: string, signal?: AbortSignal): Promise<boolean>;
25
+ capabilities(memberId: string): Promise<{
26
+ chatPosting: boolean;
27
+ runtimeSource: boolean;
28
+ }>;
22
29
  supportsChatPosting(memberId: string): Promise<boolean>;
23
- labels(memberId: string, action: string, input?: Readonly<Record<string, unknown>>): Promise<ActionAnnotations>;
30
+ labels(memberId: string, action: string, input?: Readonly<Record<string, unknown>>, signal?: AbortSignal): Promise<ActionAnnotations>;
24
31
  describe(memberId: string, action: string, input: Readonly<Record<string, unknown>>): Promise<import("./confirmation-description.js").ConfirmationDescription>;
25
32
  };
26
- export declare function ontologyToolLabels(options?: Parameters<typeof ontologyTools>[0]): (memberId: string, action: string, input?: Readonly<Record<string, unknown>>) => Promise<ActionAnnotations>;
33
+ export declare function ontologyToolLabels(options?: Parameters<typeof ontologyTools>[0]): (memberId: string, action: string, input?: Readonly<Record<string, unknown>>, signal?: AbortSignal) => Promise<ActionAnnotations>;
27
34
  /** MCP normalizes an authored camelCase action to snake_case. */
28
35
  export declare function actionToolName(entity: string, action: string): string;
29
36
  /** One target contract for native and MCP attachment promotion; never trust supplied safety hints. */
@@ -5,10 +5,10 @@ const __filename = __eveFileURLToPath(import.meta.url);
5
5
  __eveDirname(__filename);
6
6
  __eveCreateRequire(import.meta.url);
7
7
  import { appOrigin } from "./environment.mjs";
8
- import { identityProviderOf, memberIdOf } from "./telegram/principal.mjs";
9
- import { runtimeToken } from "./runtime-token.mjs";
8
+ import { c as compatibleRuntimeEnvelope, i as memberIdOf, r as identityProviderOf, s as RUNTIME_SOURCE_PROTOCOL, u as runtimeEnvelope } from "../../_chunks/principal-VFQWqe5S.mjs";
10
9
  import { redactDiagnostic } from "./diagnostics.mjs";
11
10
  import { describeConfirmation, object } from "./confirmation-description.mjs";
11
+ import { runtimeToken } from "./runtime-token.mjs";
12
12
  import { describeChatPost, isChatPost, supportsChatPost } from "./chat-post-confirmation.mjs";
13
13
  import { randomUUID } from "node:crypto";
14
14
  var OntologyToolRejected = class extends Error {
@@ -18,7 +18,19 @@ var OntologyActionNotPermitted = class extends Error {
18
18
  code = "ontology_action_not_permitted";
19
19
  };
20
20
  function ontologyTools(options = {}) {
21
+ const runtimeSources = new Map();
21
22
  async function rpc(memberId, method, params, signal) {
23
+ if (method === "tools/call") {
24
+ const envelope = options.envelope ?? runtimeEnvelope({ principal: memberIdOf(options.principal) === memberId ? options.principal : null });
25
+ if (envelope.source !== void 0 && !runtimeSources.has(memberId)) await rpc(memberId, "tools/list", {}, signal);
26
+ params = {
27
+ ...params,
28
+ arguments: {
29
+ ...object(params.arguments),
30
+ _segmentstream: compatibleRuntimeEnvelope(envelope, runtimeSources.get(memberId) === true)
31
+ }
32
+ };
33
+ }
22
34
  const provider = memberIdOf(options.principal) === memberId ? identityProviderOf(options.principal) : void 0;
23
35
  const credential = await (options.token ?? runtimeToken)();
24
36
  const secrets = new Set([credential]);
@@ -46,6 +58,7 @@ function ontologyTools(options = {}) {
46
58
  const body = object(await response.json());
47
59
  if (body.error !== void 0) throw new Error("Ontology metadata unavailable.", { cause: body.error });
48
60
  const result = object(body.result);
61
+ if (method === "tools/list" && Array.isArray(result.tools)) runtimeSources.set(memberId, result.tools.map(object).some((tool) => object(tool._meta)[RUNTIME_SOURCE_PROTOCOL] === 1));
49
62
  if (result.isError === true) {
50
63
  const message = (Array.isArray(result.content) ? result.content : []).map(object).filter((part) => part.type === "text" && typeof part.text === "string").map((part) => part.text).join("\n");
51
64
  if ([
@@ -119,12 +132,23 @@ function ontologyTools(options = {}) {
119
132
  const result = await rpc(memberId, "tools/list", {});
120
133
  return Array.isArray(result.tools) ? result.tools.map(object) : [];
121
134
  },
135
+ async supportsRuntimeSource(memberId, signal) {
136
+ if (!runtimeSources.has(memberId)) await rpc(memberId, "tools/list", {}, signal);
137
+ return runtimeSources.get(memberId) === true;
138
+ },
139
+ async capabilities(memberId) {
140
+ const result = await rpc(memberId, "tools/list", {});
141
+ return {
142
+ chatPosting: Array.isArray(result.tools) && result.tools.map(object).some(supportsChatPost),
143
+ runtimeSource: runtimeSources.get(memberId) === true
144
+ };
145
+ },
122
146
  async supportsChatPosting(memberId) {
123
147
  const result = await rpc(memberId, "tools/list", {});
124
148
  return Array.isArray(result.tools) && result.tools.map(object).some(supportsChatPost);
125
149
  },
126
- async labels(memberId, action, input = {}) {
127
- const { tool } = await resolve(memberId, action, input);
150
+ async labels(memberId, action, input = {}, signal) {
151
+ const { tool } = await resolve(memberId, action, input, signal);
128
152
  return {
129
153
  ...object(tool.annotations),
130
154
  confirmation: object(object(tool.inputSchema).properties)._confirmation !== void 0
@@ -154,7 +178,7 @@ function ontologyTools(options = {}) {
154
178
  caller,
155
179
  destinations
156
180
  }),
157
- action: typeof tool.title === "string" ? tool.title : "❓"
181
+ action: typeof tool.title === "string" ? tool.title : typeof tool.description === "string" ? tool.description.split("\n\n")[0] : ""
158
182
  };
159
183
  }
160
184
  let entities = [];
@@ -0,0 +1,28 @@
1
+ import type { RuntimeSource } from "@segmentstream-cloud/ontology";
2
+ import type { SessionAuthContext } from "eve/context";
3
+ import type { TelegramMessage } from "eve/channels/telegram";
4
+ import type { StagedFile } from "./telegram/inbound-request.js";
5
+ export type RuntimeEnvelope = {
6
+ readonly version: 1;
7
+ readonly session_id: string;
8
+ readonly call_id: string;
9
+ readonly operation_id?: string;
10
+ readonly source?: RuntimeSource;
11
+ readonly expected?: {
12
+ readonly chat_id: string;
13
+ readonly digest: string;
14
+ };
15
+ };
16
+ /** The source comes from the verified Telegram message and admitted storage results. */
17
+ export declare function telegramRuntimeSource(message: Pick<TelegramMessage, "chat" | "messageId" | "messageThreadId" | "replyToMessage" | "from" | "raw" | "attachments">, files?: ReadonlyMap<string, StagedFile>, callbackQueryId?: string): RuntimeSource;
18
+ /** Session auth is SDK-owned; no tool argument is read while rebuilding provenance. */
19
+ export declare function principalRuntimeSource(principal?: SessionAuthContext | null): RuntimeSource | undefined;
20
+ export declare function runtimeEnvelope(input?: {
21
+ readonly principal?: SessionAuthContext | null;
22
+ readonly sessionId?: string;
23
+ readonly callId?: string;
24
+ readonly source?: RuntimeSource;
25
+ }): RuntimeEnvelope;
26
+ /** Older strict ontology schemas accept only the original chat identity fields. */
27
+ export declare function compatibleRuntimeEnvelope(envelope: RuntimeEnvelope, extended: boolean): RuntimeEnvelope;
28
+ export declare const RUNTIME_SOURCE_PROTOCOL = "segmentstream/runtime-source";
@@ -0,0 +1,8 @@
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 { c as compatibleRuntimeEnvelope, d as telegramRuntimeSource, l as principalRuntimeSource, s as RUNTIME_SOURCE_PROTOCOL, u as runtimeEnvelope } from "../../_chunks/principal-VFQWqe5S.mjs";
8
+ export { RUNTIME_SOURCE_PROTOCOL, compatibleRuntimeEnvelope, principalRuntimeSource, runtimeEnvelope, telegramRuntimeSource };
@@ -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 { memberIdOf } from "./telegram/principal.mjs";
7
+ import { i as memberIdOf } from "../../_chunks/principal-VFQWqe5S.mjs";
8
8
  import { redactDiagnostic } from "./diagnostics.mjs";
9
9
  import { object } from "./confirmation-description.mjs";
10
10
  import { ontologyTools } from "./ontology-tools.mjs";
@@ -4,21 +4,23 @@ 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, withTelegramTexts } from "./texts.mjs";
7
8
  import { manifestOf } from "../../config.mjs";
8
9
  import { appOrigin, channelsEnabled, proxyEnvironment, runtimeIdentityEnvironment, webhookSecret } from "../environment.mjs";
9
- import { conversationLanguage, telegramPrincipal } from "./principal.mjs";
10
+ import { n as conversationLanguage, o as telegramPrincipal } from "../../../_chunks/principal-VFQWqe5S.mjs";
11
+ import { confirmationLocale } from "./confirmation-text.mjs";
12
+ import { telegramSendScope } from "./send-queue.mjs";
13
+ import { d as failureText, h as withDeliveryLocale, i as withReplacedText, m as safeTelegramFetch, n as currentInboundRequest, o as currentLocale, p as reportTelegramError, r as runInboundRequest, t as InboundRequest } from "../../../_chunks/inbound-request-BXhiIph-.mjs";
10
14
  import { chooseModel } from "../../model.mjs";
11
15
  import { groupRoutingHealth } from "../group-routing/health.mjs";
12
16
  import { decisionRouter } from "../group-routing/router.mjs";
13
17
  import { runtimeToken } from "../runtime-token.mjs";
14
18
  import { conversations } from "../conversations.mjs";
15
19
  import { archivedRoutingMessages } from "../group-routing/routing-context.mjs";
16
- import { t as agentBuild } from "../../../_chunks/build-metadata-CLprTpsn.mjs";
17
- import { confirmationLocale } from "./confirmation-text.mjs";
18
- import { telegramSendScope } from "./send-queue.mjs";
19
- import { d as failureText, h as withDeliveryLocale, i as withReplacedText, m as safeTelegramFetch, n as currentInboundRequest, p as reportTelegramError, r as runInboundRequest, t as InboundRequest } from "../../../_chunks/inbound-request-BrWspFw5.mjs";
20
- import { attachmentLifecycle } from "./lifecycle.mjs";
21
20
  import { scopedAddress, sessionPolicy } from "./sessions.mjs";
21
+ import { handleWorkspaceCallback, isWorkspaceCallback } from "./callbacks.mjs";
22
+ import { t as agentBuild } from "../../../_chunks/build-metadata-BB2uSGsI.mjs";
23
+ import { attachmentLifecycle } from "./lifecycle.mjs";
22
24
  import { observedMessages } from "./observed.mjs";
23
25
  import { expireDeferredCards, handleDeferredCallback, isDeferredCallback } from "./deferred-confirmations.mjs";
24
26
  import { gatewayImageDescriber } from "./images.mjs";
@@ -120,7 +122,31 @@ function segmentstreamTelegram(options) {
120
122
  identities: pairing,
121
123
  observed,
122
124
  chats,
123
- verify: telegramWebhookVerifier(() => webhookSecret(environment))
125
+ verify: telegramWebhookVerifier(() => webhookSecret(environment)),
126
+ answerCallback: async (callbackQueryId, locale) => {
127
+ const text = telegramText("callback", "unsupported", locale);
128
+ const reply = await proxy().request({
129
+ api: "bot",
130
+ method: "POST",
131
+ path: "/answerCallbackQuery",
132
+ headers: [["content-type", "application/json"]],
133
+ body: new TextEncoder().encode(JSON.stringify({
134
+ callback_query_id: callbackQueryId,
135
+ ...text === void 0 ? {} : { text }
136
+ }))
137
+ });
138
+ const body = new TextDecoder().decode(reply.body);
139
+ let answer;
140
+ try {
141
+ answer = JSON.parse(body);
142
+ } catch (cause) {
143
+ throw new Error(`Telegram callback acknowledgement was invalid (HTTP ${reply.status}): ${body}`, { cause });
144
+ }
145
+ if (reply.status < 200 || reply.status >= 300 || answer === null || typeof answer !== "object" || !("ok" in answer) || answer.ok !== true) throw new Error("Telegram callback acknowledgement was refused.", { cause: {
146
+ status: reply.status,
147
+ body
148
+ } });
149
+ }
124
150
  });
125
151
  let store = options.attachments;
126
152
  function attachments() {
@@ -279,7 +305,23 @@ function segmentstreamTelegram(options) {
279
305
  }
280
306
  },
281
307
  onCallbackQuery: async (context, query) => {
308
+ const inbound = currentInboundRequest();
309
+ if (inbound !== void 0) inbound.locale = query.from.languageCode;
282
310
  try {
311
+ if (isWorkspaceCallback(query.data)) {
312
+ await handleWorkspaceCallback({
313
+ context,
314
+ query,
315
+ configuration: settings().callbacks,
316
+ admission: options.admission?.() ?? manifestOf({}),
317
+ scope: options.sessions().scope,
318
+ identities: pairing(),
319
+ environment,
320
+ token,
321
+ ...options.fetch ? { fetch: options.fetch } : {}
322
+ });
323
+ return;
324
+ }
283
325
  if (isDeferredCallback(query.data)) {
284
326
  await handleDeferredCallback({
285
327
  context,
@@ -306,7 +348,7 @@ function segmentstreamTelegram(options) {
306
348
  reportTelegramError("confirmation_callback_failed", error);
307
349
  await context.telegram.answerCallbackQuery({
308
350
  callbackQueryId: query.id,
309
- text: "⚠️"
351
+ ...telegramText("callback", "error") === void 0 ? {} : { text: telegramText("callback", "error") }
310
352
  });
311
353
  }
312
354
  },
@@ -404,7 +446,7 @@ function segmentstreamTelegram(options) {
404
446
  const locale = confirmationLocale(principal ?? null, context.state.customerLocale ?? "en");
405
447
  context.state.customerLocale = locale;
406
448
  await withDeliveryLocale(locale, async () => {
407
- await handler(event, context);
449
+ await withTelegramTexts(options.admission?.().texts ?? {}, () => handler(event, context), currentLocale);
408
450
  }, context.state.messageThreadId === null ? void 0 : String(context.state.messageThreadId), typeof principal?.attributes.replyToMessageId === "string" ? principal.attributes.replyToMessageId : void 0, typeof principal?.attributes.chatId === "string" ? principal.attributes.chatId : void 0);
409
451
  }]))
410
452
  } },
@@ -482,7 +524,7 @@ function gatedRoute(input) {
482
524
  };
483
525
  inbound.waitUntil = waitUntil;
484
526
  inbound.backgroundUntil = (task) => args.waitUntil(task);
485
- return runInboundRequest(inbound, () => input.capture(request, async (routedRequest = request) => {
527
+ return withTelegramTexts(options.admission?.().texts ?? {}, () => runInboundRequest(inbound, () => input.capture(request, async (routedRequest = request) => {
486
528
  const response = await route.handler(routedRequest, {
487
529
  ...args,
488
530
  waitUntil,
@@ -501,7 +543,7 @@ function gatedRoute(input) {
501
543
  headers: { "retry-after": "1" }
502
544
  });
503
545
  return response;
504
- }));
546
+ })), currentLocale);
505
547
  }
506
548
  };
507
549
  }
@@ -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-BrWspFw5.mjs";
7
+ import { p as reportTelegramError } from "../../../_chunks/inbound-request-BXhiIph-.mjs";
8
8
  import { describableImage } from "./images.mjs";
9
9
  import { MAXIMUM_ROUTING_PDF_CHARACTERS, extractRoutingPdf } from "./pdf-text.mjs";
10
10
  import { gateway, generateText } from "ai";
@@ -5,12 +5,12 @@ const __filename = __eveFileURLToPath(import.meta.url);
5
5
  __eveDirname(__filename);
6
6
  __eveCreateRequire(import.meta.url);
7
7
  import { appOrigin, channelsEnabled, proxyEnvironment } from "../environment.mjs";
8
- import "./principal.mjs";
9
- import { runtimeToken } from "../runtime-token.mjs";
8
+ import "../../../_chunks/principal-VFQWqe5S.mjs";
10
9
  import { redactDiagnostic } from "../diagnostics.mjs";
11
10
  import { confirmationLocale } from "./confirmation-text.mjs";
12
11
  import { inTelegramSendQueue, telegramSendScope } from "./send-queue.mjs";
13
- import { c as customerCopy, f as formattingRefused, l as customerMessage, p as reportTelegramError } from "../../../_chunks/inbound-request-BrWspFw5.mjs";
12
+ import { d as failureText, f as formattingRefused, l as customerMessage, p as reportTelegramError } from "../../../_chunks/inbound-request-BXhiIph-.mjs";
13
+ import { runtimeToken } from "../runtime-token.mjs";
14
14
  import { MAXIMUM_PROXY_BODY_BYTES, connectionProxy } from "../connection-proxy.mjs";
15
15
  import { ACT_AS_HEADER } from "../ontology-connection.mjs";
16
16
  import { AttachmentError, CONVERSATION_HEADER, SESSION_HEADER } from "../attachments.mjs";
@@ -83,14 +83,17 @@ async function sendAttachmentsInOrder(options) {
83
83
  const environment = options.environment ?? process.env;
84
84
  const principal = options.principal;
85
85
  const locale = confirmationLocale(principal);
86
- const unavailable = (error, diagnostic) => ({
87
- error,
88
- detail: customerCopy().attachment,
89
- reference: reportTelegramError("attachment_send_refused", {
86
+ const unavailable = (error, diagnostic) => {
87
+ const reference = reportTelegramError("attachment_send_refused", {
90
88
  error,
91
89
  diagnostic
92
- })
93
- });
90
+ });
91
+ return {
92
+ error,
93
+ detail: failureText(reference, "attachment", locale),
94
+ reference
95
+ };
96
+ };
94
97
  if (!channelsEnabled(environment)) return unavailable("channels_disabled", "Attachments can be sent only in production.");
95
98
  if (options.connection === void 0) return unavailable("unsupported", "The Telegram channel is not configured.");
96
99
  if (principal?.authenticator !== "segmentstream-telegram" || typeof principal.attributes.chatId !== "string" || !/^-?\d{1,20}$/.test(principal.attributes.chatId)) return unavailable("no_telegram_chat", "This turn has no Telegram chat.");
@@ -104,7 +107,7 @@ async function sendAttachmentsInOrder(options) {
104
107
  const reference = reportTelegramError("attachment_owner_refused", error);
105
108
  return {
106
109
  error: "forbidden",
107
- detail: customerCopy().attachment,
110
+ detail: failureText(reference, "attachment", locale),
108
111
  reference
109
112
  };
110
113
  }
@@ -187,7 +190,7 @@ async function sendAttachmentsInOrder(options) {
187
190
  id: reference.id,
188
191
  filename,
189
192
  error: error instanceof AttachmentError ? error.code : "unavailable",
190
- detail: customerCopy().attachment,
193
+ detail: failureText(errorId, "attachment", locale),
191
194
  reference: errorId
192
195
  };
193
196
  }
@@ -271,7 +274,7 @@ async function sendAttachmentsInOrder(options) {
271
274
  id: file.id,
272
275
  filename: file.filename,
273
276
  error: error instanceof AttachmentError ? error.code : "send_failed",
274
- detail: customerCopy().attachment,
277
+ detail: failureText(errorId, "attachment", locale),
275
278
  reference: errorId
276
279
  };
277
280
  });
@@ -0,0 +1,18 @@
1
+ import type { TelegramCallbackQuery, TelegramContext } from "eve/channels/telegram";
2
+ import type { AdmissionSettings, SessionSettings, TelegramSettings } from "../../config.js";
3
+ import type { AgentIdentities } from "../identities.js";
4
+ import type { Environment } from "../environment.js";
5
+ import type { RuntimeToken } from "../runtime-token.js";
6
+ export declare const isWorkspaceCallback: (data?: string) => boolean;
7
+ /** A single dispatch and acknowledgement. Token policy and business idempotency belong to the workspace. */
8
+ export declare function handleWorkspaceCallback(input: {
9
+ readonly context: TelegramContext;
10
+ readonly query: TelegramCallbackQuery;
11
+ readonly configuration?: TelegramSettings["callbacks"];
12
+ readonly scope: SessionSettings["scope"];
13
+ readonly admission: AdmissionSettings;
14
+ readonly identities: AgentIdentities;
15
+ readonly environment?: Environment;
16
+ readonly token?: RuntimeToken;
17
+ readonly fetch?: typeof fetch;
18
+ }): Promise<void>;
@@ -0,0 +1,155 @@
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 { admitMessage } from "../admission.mjs";
8
+ import { telegramText } from "./texts.mjs";
9
+ import { d as telegramRuntimeSource, i as memberIdOf, o as telegramPrincipal, u as runtimeEnvelope } from "../../../_chunks/principal-VFQWqe5S.mjs";
10
+ import { object } from "../confirmation-description.mjs";
11
+ import { n as currentInboundRequest, p as reportTelegramError } from "../../../_chunks/inbound-request-BXhiIph-.mjs";
12
+ import { formatAddress, parseAddress, scopedAddress } from "./sessions.mjs";
13
+ import { workspaceAction } from "./workspace-action.mjs";
14
+ const isWorkspaceCallback = (data) => data?.startsWith("ws:") === true;
15
+ async function handleWorkspaceCallback(input) {
16
+ const { query, context } = input;
17
+ const locale = query.from.languageCode;
18
+ let acknowledgement;
19
+ let showAlert = false;
20
+ let result;
21
+ let principal;
22
+ const controller = new AbortController();
23
+ let timer;
24
+ try {
25
+ const token = query.data?.slice(3) ?? "";
26
+ if (!query.message || query.from.isBot || !token || new TextEncoder().encode(token).byteLength > 60) acknowledgement = telegramText("callback", "unknown", locale);
27
+ else if (input.configuration === void 0) acknowledgement = telegramText("callback", "unsupported", locale);
28
+ else {
29
+ const message = {
30
+ ...query.message,
31
+ from: query.from,
32
+ attachments: [],
33
+ text: "",
34
+ caption: "",
35
+ raw: {}
36
+ };
37
+ const dispatch = async () => {
38
+ const lookup = await input.identities.lookup({
39
+ provider: "telegram",
40
+ externalId: query.from.id
41
+ });
42
+ if (lookup.status !== "paired") {
43
+ acknowledgement = telegramText("callback", "forbidden", locale);
44
+ return;
45
+ }
46
+ controller.signal.throwIfAborted();
47
+ principal = telegramPrincipal({
48
+ message,
49
+ member: lookup.member,
50
+ callbackQueryId: query.id
51
+ });
52
+ return workspaceAction({
53
+ ...input,
54
+ configuration: input.configuration,
55
+ principal,
56
+ memberId: lookup.member.id,
57
+ input: { token },
58
+ signal: controller.signal,
59
+ envelope: runtimeEnvelope({
60
+ source: telegramRuntimeSource(message, void 0, query.id),
61
+ sessionId: `telegram:callback:${query.id}`,
62
+ callId: query.id
63
+ })
64
+ });
65
+ };
66
+ const deadline = new Promise((resolve) => {
67
+ timer = setTimeout(() => {
68
+ controller.abort();
69
+ reportTelegramError("workspace_callback_timeout", new Error("Telegram callback dispatch exceeded 10 seconds."), { callbackQueryId: query.id });
70
+ resolve(void 0);
71
+ }, 1e4);
72
+ });
73
+ result = await Promise.race([dispatch(), deadline]);
74
+ if (result !== void 0) {
75
+ acknowledgement = typeof result.acknowledgement === "string" && result.acknowledgement.length <= 200 ? result.acknowledgement : void 0;
76
+ showAlert = result.show_alert === true;
77
+ }
78
+ }
79
+ } catch (error) {
80
+ reportTelegramError("workspace_callback_failed", error, { callbackQueryId: query.id });
81
+ acknowledgement = controller.signal.aborted ? void 0 : telegramText("callback", "error", locale);
82
+ } finally {
83
+ if (timer !== void 0) clearTimeout(timer);
84
+ try {
85
+ await context.telegram.answerCallbackQuery({
86
+ callbackQueryId: query.id,
87
+ ...acknowledgement === void 0 ? {} : { text: acknowledgement },
88
+ showAlert
89
+ });
90
+ } catch (error) {
91
+ reportTelegramError("workspace_callback_ack_failed", error, { callbackQueryId: query.id });
92
+ }
93
+ }
94
+ if (result === void 0 || query.message === void 0 || principal === void 0) return;
95
+ const edit = object(result.edit);
96
+ try {
97
+ if (typeof edit.text === "string" || edit.reply_markup !== void 0) {
98
+ const payload = {
99
+ chat_id: query.message.chat.id,
100
+ message_id: Number(query.message.messageId),
101
+ ...typeof edit.text === "string" && edit.text.length <= 4096 ? { text: edit.text } : {},
102
+ ...[
103
+ "MarkdownV2",
104
+ "Markdown",
105
+ "HTML"
106
+ ].includes(String(edit.parse_mode)) ? { parse_mode: edit.parse_mode } : {},
107
+ ...Array.isArray(edit.entities) && edit.entities.length <= 100 ? { entities: edit.entities } : {},
108
+ ...edit.reply_markup === void 0 ? {} : { reply_markup: edit.reply_markup }
109
+ };
110
+ const encoded = JSON.stringify(payload);
111
+ if (encoded.length > 32768) throw new Error("The callback edit exceeds the Telegram hook limit.");
112
+ await context.telegram.request(typeof edit.text === "string" ? "editMessageText" : "editMessageReplyMarkup", JSON.parse(encoded));
113
+ }
114
+ } catch (error) {
115
+ reportTelegramError("workspace_callback_edit_failed", error, { callbackQueryId: query.id });
116
+ }
117
+ if (typeof result.context === "string" && result.context.trim() && result.context.length <= 16384) try {
118
+ const admitted = await admitMessage({
119
+ identity: {
120
+ provider: "telegram",
121
+ externalId: query.from.id,
122
+ chat: query.message.chat.type === "private" ? "private" : "group",
123
+ turn: true
124
+ },
125
+ identities: input.identities,
126
+ settings: input.admission,
127
+ languageCode: locale,
128
+ sendNotice: (text) => context.telegram.post(text),
129
+ noticeFailed: (error) => reportTelegramError("workspace_callback_notice_failed", error)
130
+ });
131
+ if (admitted.status !== "existing" && admitted.status !== "created" || admitted.member.id !== memberIdOf(principal)) return;
132
+ const sessions = currentInboundRequest()?.sessions;
133
+ if (sessions === void 0) throw new Error("The callback has no session transport.");
134
+ const address = scopedAddress(formatAddress({
135
+ chatId: query.message.chat.type === "private" ? query.from.id : query.message.chat.id,
136
+ messageThreadId: String(query.message.messageThreadId ?? ""),
137
+ conversationId: query.message.chat.type === "private" ? "" : query.message.messageId
138
+ }), input.scope);
139
+ const session = sessions.from(address);
140
+ if (session.send === void 0) throw new Error("The callback session cannot enqueue turns.");
141
+ await session.send(result.context, {
142
+ auth: principal,
143
+ turnPolicy: "queue",
144
+ state: {
145
+ chatId: query.message.chat.id,
146
+ chatType: query.message.chat.type,
147
+ messageThreadId: query.message.messageThreadId ?? null,
148
+ conversationId: parseAddress(address).conversationId || null
149
+ }
150
+ });
151
+ } catch (error) {
152
+ reportTelegramError("workspace_callback_turn_failed", error, { callbackQueryId: query.id });
153
+ }
154
+ }
155
+ export { handleWorkspaceCallback, isWorkspaceCallback };
@@ -7,4 +7,4 @@ export declare function chatPostCardLinks(text: string): readonly string[] | und
7
7
  export declare function chatPostCard(description: ConfirmationDescription, copy?: ConfirmationCopy): ConfirmationText;
8
8
  /** Status/receipt strings are data outside the already rendered preview. */
9
9
  export declare function chatPostCardStatus(text: string, status: string): string;
10
- export declare function chatPostReceipt(output: unknown, completed?: string): string | undefined;
10
+ export declare function chatPostReceipt(output: unknown): string | undefined;