@segmentstream/agent 0.6.11 → 0.6.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/dist/_chunks/{inbound-request-DRNPIIpb.mjs → inbound-request-CysnjMdw.mjs} +62 -62
- package/dist/extension/config.d.ts +7 -8
- package/dist/extension/config.mjs +20 -2
- package/dist/extension/instructions.md +8 -1
- package/dist/extension/lib/chat-post-confirmation.mjs +1 -1
- package/dist/extension/lib/confirmation-description.d.ts +1 -0
- package/dist/extension/lib/confirmation-description.mjs +29 -13
- package/dist/extension/lib/confirmations.d.ts +3 -0
- package/dist/extension/lib/confirmations.mjs +22 -5
- package/dist/extension/lib/customer-text-safety.d.ts +1 -0
- package/dist/extension/lib/customer-text-safety.mjs +23 -0
- package/dist/extension/lib/ontology-tools.mjs +13 -6
- package/dist/extension/lib/telegram/adapter.mjs +10 -6
- package/dist/extension/lib/telegram/attachments-send.mjs +6 -6
- package/dist/extension/lib/telegram/chat-post-card.d.ts +6 -13
- package/dist/extension/lib/telegram/chat-post-card.mjs +29 -37
- package/dist/extension/lib/telegram/confirmation-text.d.ts +20 -8
- package/dist/extension/lib/telegram/confirmation-text.mjs +55 -65
- package/dist/extension/lib/telegram/confirmations.d.ts +1 -2
- package/dist/extension/lib/telegram/confirmations.mjs +40 -96
- package/dist/extension/lib/telegram/content.d.ts +1 -1
- package/dist/extension/lib/telegram/conversations.mjs +1 -1
- package/dist/extension/lib/telegram/customer-text.d.ts +5 -5
- package/dist/extension/lib/telegram/customer-text.mjs +2 -1
- package/dist/extension/lib/telegram/files.mjs +1 -1
- package/dist/extension/lib/telegram/images.mjs +1 -1
- package/dist/extension/lib/telegram/inbound-request.mjs +1 -1
- package/dist/extension/lib/telegram/inbound.mjs +5 -5
- package/dist/extension/lib/telegram/media-policy.mjs +1 -1
- package/dist/extension/lib/telegram/principal.mjs +1 -1
- package/dist/extension/lib/telegram/silent.mjs +2 -2
- package/dist/extension/lib/telegram/turn-errors.mjs +2 -2
- package/dist/extension/lib/telegram/voice.mjs +1 -1
- package/package.json +2 -1
|
@@ -8,17 +8,17 @@ import { appOrigin, channelsEnabled, proxyEnvironment, runtimeIdentityEnvironmen
|
|
|
8
8
|
import { conversationLanguage, telegramPrincipal } from "./principal.mjs";
|
|
9
9
|
import { chooseModel } from "../../model.mjs";
|
|
10
10
|
import { MAXIMUM_DOWNLOAD_BYTES, connectionProxy } from "../connection-proxy.mjs";
|
|
11
|
+
import { confirmationLocale } from "./confirmation-text.mjs";
|
|
11
12
|
import { runtimeToken } from "../runtime-token.mjs";
|
|
12
13
|
import { agentAttachments, parseAttachmentUrl } from "../attachments.mjs";
|
|
13
14
|
import { agentIdentities } from "../identities.mjs";
|
|
14
15
|
import { conversations } from "../conversations.mjs";
|
|
15
16
|
import { observedMessages } from "./observed.mjs";
|
|
16
17
|
import { telegramSendScope } from "./send-queue.mjs";
|
|
17
|
-
import { d as failureText,
|
|
18
|
+
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-CysnjMdw.mjs";
|
|
18
19
|
import { captureRouteDecider, captureTelegramFetch, conversationIdentities, recordGateDecision, telegramConversationCapture } from "./conversations.mjs";
|
|
19
20
|
import { runtimeTokenVerifier } from "../runtime-identity.mjs";
|
|
20
21
|
import { botIdentityCache } from "./bot.mjs";
|
|
21
|
-
import { confirmationLocale, confirmationRenderer } from "./confirmation-text.mjs";
|
|
22
22
|
import { scopedAddress, sessionPolicy } from "./sessions.mjs";
|
|
23
23
|
import { handleConfirmationCallback, telegramConfirmationEvents } from "./confirmations.mjs";
|
|
24
24
|
import { gatewayImageDescriber } from "./images.mjs";
|
|
@@ -32,6 +32,7 @@ import { TELEGRAM_PLACEHOLDER_TOKEN, TELEGRAM_PROXY_ORIGIN, telegramProxyFetch }
|
|
|
32
32
|
import { healthRoute } from "./health.mjs";
|
|
33
33
|
import { telegramFailureEvents } from "./turn-errors.mjs";
|
|
34
34
|
import { telegramWebhookVerifier } from "./webhook.mjs";
|
|
35
|
+
import { telegramPreviewEnvironment } from "@segmentstream-cloud/ontology/telegram";
|
|
35
36
|
import { telegramChannel } from "eve/channels/telegram";
|
|
36
37
|
const eveHistory = async (sessionId) => {
|
|
37
38
|
const { sessions } = await import("eve/server");
|
|
@@ -128,7 +129,10 @@ function segmentstreamTelegram(options) {
|
|
|
128
129
|
api: {
|
|
129
130
|
apiBaseUrl: TELEGRAM_PROXY_ORIGIN,
|
|
130
131
|
fileBaseUrl: TELEGRAM_PROXY_ORIGIN,
|
|
131
|
-
fetch: (input, init) => safeTelegramFetch(captureTelegramFetch(telegramProxyFetch(proxy(), telegramSendScope(environment, settings().connection)), archive, pairing), telegramSendScope(environment, settings().connection)
|
|
132
|
+
fetch: (input, init) => safeTelegramFetch(captureTelegramFetch(telegramProxyFetch(proxy(), telegramSendScope(environment, settings().connection)), archive, pairing), telegramSendScope(environment, settings().connection), {
|
|
133
|
+
settings: settings(),
|
|
134
|
+
ownOrigins: telegramPreviewEnvironment(environment).appOrigins
|
|
135
|
+
})(input, init)
|
|
132
136
|
},
|
|
133
137
|
credentials: {
|
|
134
138
|
botToken: TELEGRAM_PLACEHOLDER_TOKEN,
|
|
@@ -233,16 +237,16 @@ function segmentstreamTelegram(options) {
|
|
|
233
237
|
scope: options.sessions().scope
|
|
234
238
|
});
|
|
235
239
|
} catch (error) {
|
|
236
|
-
|
|
240
|
+
reportTelegramError("confirmation_callback_failed", error);
|
|
237
241
|
await context.telegram.answerCallbackQuery({
|
|
238
242
|
callbackQueryId: query.id,
|
|
239
|
-
text:
|
|
243
|
+
text: "⚠️"
|
|
240
244
|
});
|
|
241
245
|
}
|
|
242
246
|
},
|
|
243
247
|
events: {
|
|
244
248
|
...telegramFailureEvents,
|
|
245
|
-
...telegramConfirmationEvents(
|
|
249
|
+
...telegramConfirmationEvents(archive),
|
|
246
250
|
"message.completed": replyDelivery(observed, () => telegramSendScope(environment, settings().connection))
|
|
247
251
|
}
|
|
248
252
|
});
|
|
@@ -7,13 +7,13 @@ __eveCreateRequire(import.meta.url);
|
|
|
7
7
|
import { appOrigin, channelsEnabled, proxyEnvironment } from "../environment.mjs";
|
|
8
8
|
import "./principal.mjs";
|
|
9
9
|
import { MAXIMUM_PROXY_BODY_BYTES, connectionProxy } from "../connection-proxy.mjs";
|
|
10
|
+
import { confirmationLocale } from "./confirmation-text.mjs";
|
|
10
11
|
import { redactDiagnostic } from "../diagnostics.mjs";
|
|
11
12
|
import { runtimeToken } from "../runtime-token.mjs";
|
|
12
13
|
import { ACT_AS_HEADER } from "../ontology-connection.mjs";
|
|
13
14
|
import { AttachmentError, CONVERSATION_HEADER, SESSION_HEADER } from "../attachments.mjs";
|
|
14
15
|
import { inTelegramSendQueue, telegramSendScope } from "./send-queue.mjs";
|
|
15
|
-
import { c as customerCopy, f as formattingRefused, l as customerMessage,
|
|
16
|
-
import { confirmationLocale } from "./confirmation-text.mjs";
|
|
16
|
+
import { c as customerCopy, f as formattingRefused, l as customerMessage, p as reportTelegramError } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
|
|
17
17
|
import { TELEGRAM_PLACEHOLDER_TOKEN, TELEGRAM_PROXY_ORIGIN, telegramProxyFetch } from "./proxy-fetch.mjs";
|
|
18
18
|
import { attachmentOwner } from "../attachment-tools.mjs";
|
|
19
19
|
const MAXIMUM_PHOTO_BYTES = 10485760;
|
|
@@ -85,7 +85,7 @@ async function sendAttachmentsInOrder(options) {
|
|
|
85
85
|
const locale = confirmationLocale(principal);
|
|
86
86
|
const unavailable = (error, diagnostic) => ({
|
|
87
87
|
error,
|
|
88
|
-
detail: customerCopy(
|
|
88
|
+
detail: customerCopy().attachment,
|
|
89
89
|
reference: reportTelegramError("attachment_send_refused", {
|
|
90
90
|
error,
|
|
91
91
|
diagnostic
|
|
@@ -104,7 +104,7 @@ async function sendAttachmentsInOrder(options) {
|
|
|
104
104
|
const reference = reportTelegramError("attachment_owner_refused", error);
|
|
105
105
|
return {
|
|
106
106
|
error: "forbidden",
|
|
107
|
-
detail: customerCopy(
|
|
107
|
+
detail: customerCopy().attachment,
|
|
108
108
|
reference
|
|
109
109
|
};
|
|
110
110
|
}
|
|
@@ -187,7 +187,7 @@ async function sendAttachmentsInOrder(options) {
|
|
|
187
187
|
id: reference.id,
|
|
188
188
|
filename,
|
|
189
189
|
error: error instanceof AttachmentError ? error.code : "unavailable",
|
|
190
|
-
detail: customerCopy(
|
|
190
|
+
detail: customerCopy().attachment,
|
|
191
191
|
reference: errorId
|
|
192
192
|
};
|
|
193
193
|
}
|
|
@@ -271,7 +271,7 @@ async function sendAttachmentsInOrder(options) {
|
|
|
271
271
|
id: file.id,
|
|
272
272
|
filename: file.filename,
|
|
273
273
|
error: error instanceof AttachmentError ? error.code : "send_failed",
|
|
274
|
-
detail: customerCopy(
|
|
274
|
+
detail: customerCopy().attachment,
|
|
275
275
|
reference: errorId
|
|
276
276
|
};
|
|
277
277
|
});
|
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type {
|
|
1
|
+
import { type ConfirmationCopy, type ConfirmationText } from "./confirmation-text.js";
|
|
2
|
+
import type { ConfirmationDescription } from "../confirmation-description.js";
|
|
3
3
|
/** Only the frozen deterministic card may bypass the generic technical-prose filter. */
|
|
4
|
-
export declare function withChatPostCard<T>(text: string, run: () => T): T;
|
|
4
|
+
export declare function withChatPostCard<T>(text: string, run: () => T, links?: readonly string[]): T;
|
|
5
5
|
export declare function isExactChatPostCard(text: string): boolean;
|
|
6
|
-
export declare function
|
|
7
|
-
|
|
8
|
-
changes: string;
|
|
9
|
-
uncertain: string;
|
|
10
|
-
sent: string;
|
|
11
|
-
history: string;
|
|
12
|
-
expired: string;
|
|
13
|
-
};
|
|
14
|
-
export declare function chatPostCard(preview: ChatPostPreview, locale: string): ConfirmationText;
|
|
6
|
+
export declare function chatPostCardLinks(text: string): readonly string[] | undefined;
|
|
7
|
+
export declare function chatPostCard(description: ConfirmationDescription, copy?: ConfirmationCopy): ConfirmationText;
|
|
15
8
|
/** Status/receipt strings are data outside the already rendered preview. */
|
|
16
9
|
export declare function chatPostCardStatus(text: string, status: string): string;
|
|
17
|
-
export declare function chatPostReceipt(output: unknown,
|
|
10
|
+
export declare function chatPostReceipt(output: unknown, completed?: string): string | undefined;
|
|
@@ -4,65 +4,57 @@ 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 { renderConfirmation } from "./confirmation-text.mjs";
|
|
8
|
+
import { telegramMarkdownLinks, telegramTextLinks } from "@segmentstream-cloud/ontology/telegram";
|
|
7
9
|
import { escapeMarkdownV2 } from "@chat-adapter/telegram";
|
|
8
10
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
9
11
|
const MAX_PREVIEW_LENGTH = 3584;
|
|
10
12
|
const exactText = new AsyncLocalStorage();
|
|
11
|
-
function withChatPostCard(text, run) {
|
|
13
|
+
function withChatPostCard(text, run, links = []) {
|
|
12
14
|
if (text.length > 4096) throw new Error("The complete chat confirmation cannot fit in one Telegram message.");
|
|
13
|
-
return exactText.run(
|
|
15
|
+
return exactText.run({
|
|
16
|
+
text,
|
|
17
|
+
links
|
|
18
|
+
}, run);
|
|
14
19
|
}
|
|
15
20
|
function isExactChatPostCard(text) {
|
|
16
|
-
return exactText.getStore() === text;
|
|
21
|
+
return exactText.getStore()?.text === text;
|
|
17
22
|
}
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
changes: "Что изменить в сообщении?",
|
|
22
|
-
uncertain: "Неизвестно, отправлено ли сообщение. Не отправляйте его повторно автоматически.",
|
|
23
|
-
sent: "Отправлено.",
|
|
24
|
-
history: "Не удалось записать квитанцию в историю.",
|
|
25
|
-
expired: "Срок подтверждения истёк. Ничего не отправлено."
|
|
26
|
-
} : {
|
|
27
|
-
edit: "Edit",
|
|
28
|
-
changes: "What would you like to change in the message?",
|
|
29
|
-
uncertain: "Delivery is uncertain. Do not resend automatically.",
|
|
30
|
-
sent: "Sent.",
|
|
31
|
-
history: "The receipt could not be recorded in history.",
|
|
32
|
-
expired: "This confirmation expired. Nothing was sent."
|
|
33
|
-
};
|
|
23
|
+
function chatPostCardLinks(text) {
|
|
24
|
+
const card = exactText.getStore();
|
|
25
|
+
return card?.text === text ? card.links : void 0;
|
|
34
26
|
}
|
|
35
|
-
function chatPostCard(
|
|
36
|
-
const
|
|
27
|
+
function chatPostCard(description, copy) {
|
|
28
|
+
const preview = description.chatPost;
|
|
29
|
+
if (preview === void 0) throw new Error("An exact chat preview is required.");
|
|
30
|
+
const base = renderConfirmation(description, copy);
|
|
37
31
|
const text = [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
...preview.replyTo === null ? [] : [
|
|
41
|
-
|
|
42
|
-
].map(escapeMarkdownV2).join("\n") + `\n${preview.finalText}`;
|
|
32
|
+
base.text,
|
|
33
|
+
`→ ${preview.title} (${preview.provider})`,
|
|
34
|
+
...preview.replyTo === null ? [] : [`↩️ ${preview.replyTo}`]
|
|
35
|
+
].map(escapeMarkdownV2).join("\n") + `\n\n${preview.finalText}`;
|
|
43
36
|
if (text.length > MAX_PREVIEW_LENGTH) throw new Error("The full message and receipt cannot fit in one Telegram confirmation. Make a shorter draft.");
|
|
44
37
|
return {
|
|
38
|
+
...base,
|
|
45
39
|
text,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
failed: russian ? "Ошибка отправки сообщения." : "Chat posting failed."
|
|
40
|
+
previewLinks: [
|
|
41
|
+
...telegramTextLinks(`${preview.title}\n${preview.replyTo ?? ""}`),
|
|
42
|
+
...telegramMarkdownLinks(preview.text),
|
|
43
|
+
...telegramTextLinks(preview.attribution)
|
|
44
|
+
]
|
|
52
45
|
};
|
|
53
46
|
}
|
|
54
47
|
function chatPostCardStatus(text, status) {
|
|
55
48
|
return `${text}\n\n${escapeMarkdownV2(status)}`;
|
|
56
49
|
}
|
|
57
|
-
function chatPostReceipt(output,
|
|
50
|
+
function chatPostReceipt(output, completed = "✅") {
|
|
58
51
|
const value = typeof output === "object" && output !== null ? output : {};
|
|
59
52
|
if (value.status !== "sent" && value.status !== "uncertain" || typeof value.history_recorded !== "boolean" || typeof value.duplicate !== "boolean" || value.message_id !== null && typeof value.message_id !== "string" || value.url !== null && typeof value.url !== "string") return;
|
|
60
|
-
const copy = chatPostCopy(locale);
|
|
61
53
|
const url = typeof value.url === "string" && value.url.length <= 256 && /^https:\/\/t\.me\/[A-Za-z0-9_/-]+$/u.test(value.url) ? value.url : null;
|
|
62
54
|
return [
|
|
63
|
-
value.status === "sent" ?
|
|
55
|
+
value.status === "sent" ? completed : "⚠️ ❓",
|
|
64
56
|
...url === null ? [] : [url],
|
|
65
|
-
...value.history_recorded ? [] : [
|
|
57
|
+
...value.history_recorded ? [] : ["⚠️"]
|
|
66
58
|
].join("\n");
|
|
67
59
|
}
|
|
68
|
-
export { chatPostCard,
|
|
60
|
+
export { chatPostCard, chatPostCardLinks, chatPostCardStatus, chatPostReceipt, isExactChatPostCard, withChatPostCard };
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import type { SessionAuthContext } from "eve/context";
|
|
2
2
|
import { type ConfirmationDescription } from "../confirmation-description.js";
|
|
3
|
+
/** Confirmation facts and statuses are literal text; delivery still applies the shared validator. */
|
|
4
|
+
export declare function withConfirmationText<T>(text: string, run: () => T): T;
|
|
5
|
+
export declare function isConfirmationText(text: string): boolean;
|
|
6
|
+
export interface ConfirmationCopy {
|
|
7
|
+
readonly question: string;
|
|
8
|
+
readonly confirm: string;
|
|
9
|
+
readonly cancel: string;
|
|
10
|
+
readonly done: string;
|
|
11
|
+
readonly cancelled: string;
|
|
12
|
+
readonly failed: string;
|
|
13
|
+
readonly expired?: string;
|
|
14
|
+
readonly edit?: string;
|
|
15
|
+
}
|
|
3
16
|
export interface ConfirmationText {
|
|
17
|
+
readonly previewLinks?: readonly string[];
|
|
4
18
|
readonly text: string;
|
|
5
19
|
readonly confirm: string;
|
|
6
20
|
readonly cancel: string;
|
|
@@ -8,13 +22,11 @@ export interface ConfirmationText {
|
|
|
8
22
|
readonly cancelled: string;
|
|
9
23
|
readonly completed: string;
|
|
10
24
|
readonly failed: string;
|
|
25
|
+
readonly expired: string;
|
|
26
|
+
readonly edit: string;
|
|
11
27
|
}
|
|
12
28
|
export declare function confirmationLocale(principal: SessionAuthContext | null, fallback?: string): string;
|
|
13
|
-
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export declare function confirmationRenderer(input: {
|
|
18
|
-
readonly model: () => string;
|
|
19
|
-
readonly translate?: (description: ConfirmationDescription, locale: string) => Promise<string>;
|
|
20
|
-
}): ConfirmationRenderer;
|
|
29
|
+
/** Reject the entire presentation object; never partially trust malformed model copy. */
|
|
30
|
+
export declare function confirmationCopy(value?: unknown): ConfirmationCopy | undefined;
|
|
31
|
+
/** Fixed markers retain callback meaning even if the model writes misleading labels. */
|
|
32
|
+
export declare function renderConfirmation(description?: ConfirmationDescription, copy?: ConfirmationCopy): ConfirmationText;
|
|
@@ -4,9 +4,17 @@ import { createRequire as __eveCreateRequire } from "node:module";
|
|
|
4
4
|
const __filename = __eveFileURLToPath(import.meta.url);
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { isTechnicalText } from "../customer-text-safety.mjs";
|
|
8
|
+
import { humanText, object } from "../confirmation-description.mjs";
|
|
9
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
|
+
const plainConfirmation = new AsyncLocalStorage();
|
|
11
|
+
function withConfirmationText(text, run) {
|
|
12
|
+
if (text.length > 4096 || isTechnicalText(text)) throw new Error("The complete confirmation cannot pass the delivery safety check.");
|
|
13
|
+
return plainConfirmation.run(text, run);
|
|
14
|
+
}
|
|
15
|
+
function isConfirmationText(text) {
|
|
16
|
+
return plainConfirmation.getStore() === text;
|
|
17
|
+
}
|
|
10
18
|
function confirmationLocale(principal, fallback = "en") {
|
|
11
19
|
for (const key of [
|
|
12
20
|
"conversationLanguage",
|
|
@@ -19,70 +27,52 @@ function confirmationLocale(principal, fallback = "en") {
|
|
|
19
27
|
}
|
|
20
28
|
return fallback;
|
|
21
29
|
}
|
|
22
|
-
function confirmationCopy(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
function confirmationCopy(value) {
|
|
31
|
+
if (value === void 0) return;
|
|
32
|
+
const copy = object(value);
|
|
33
|
+
const required = [
|
|
34
|
+
"question",
|
|
35
|
+
"confirm",
|
|
36
|
+
"cancel",
|
|
37
|
+
"done",
|
|
38
|
+
"cancelled",
|
|
39
|
+
"failed"
|
|
40
|
+
];
|
|
41
|
+
const optional = ["expired", "edit"];
|
|
42
|
+
const valid = (key) => {
|
|
43
|
+
const text = copy[key];
|
|
44
|
+
return typeof text === "string" && text === text.trim() && (key === "question" || !/[✅❌⌛⚠❓✏]/u.test(text)) && humanText(text, key === "question" ? 300 : 24) === text;
|
|
37
45
|
};
|
|
46
|
+
if (required.some((key) => !valid(key)) || optional.some((key) => copy[key] !== void 0 && !valid(key)) || copy.confirm === copy.cancel || Object.keys(copy).some((key) => ![...required, ...optional].includes(key))) {
|
|
47
|
+
console.warn("Invalid confirmation presentation; using metadata and symbols.");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
return { ...copy };
|
|
38
51
|
}
|
|
39
|
-
function
|
|
40
|
-
|
|
41
|
-
const action =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
function renderConfirmation(description, copy) {
|
|
53
|
+
copy = confirmationCopy(copy);
|
|
54
|
+
const action = humanText(description?.action);
|
|
55
|
+
if (description !== void 0 && (action === void 0 || action === "❓")) throw new Error("A confirmation requires a safe declared action title.");
|
|
56
|
+
const facts = [[description?.warning ? "⚠️" : "", action].filter(Boolean).join(" "), ...(description?.fields ?? []).map(({ label, value }) => {
|
|
57
|
+
if (value.length > 3584) throw new Error("The complete confirmation facts cannot fit in one Telegram message.");
|
|
58
|
+
const safeLabel = humanText(label);
|
|
59
|
+
const safeValue = humanText(value, 3584);
|
|
60
|
+
if (safeLabel === void 0 || safeValue === void 0) throw new Error("The complete confirmation facts contain an unsafe field.");
|
|
61
|
+
return `${safeLabel}: ${safeValue}`;
|
|
62
|
+
})].filter(Boolean).join("\n");
|
|
63
|
+
const text = [copy?.question ?? "❓", facts].filter(Boolean).join("\n\n");
|
|
64
|
+
if (text.length > 3584) throw new Error("The complete confirmation facts cannot fit in one Telegram message.");
|
|
65
|
+
if (isTechnicalText(text)) throw new Error("The complete confirmation cannot pass the delivery safety check.");
|
|
47
66
|
return {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
prompt: JSON.stringify({
|
|
58
|
-
locale,
|
|
59
|
-
facts: description
|
|
60
|
-
}),
|
|
61
|
-
abortSignal: AbortSignal.timeout(15e3)
|
|
62
|
-
})).text;
|
|
63
|
-
});
|
|
64
|
-
return async (description, locale) => {
|
|
65
|
-
const fallback = fallbackConfirmation(description, locale);
|
|
66
|
-
if (description === void 0) return fallback;
|
|
67
|
-
try {
|
|
68
|
-
const translated = object(JSON.parse(await translate(description, locale)));
|
|
69
|
-
const summary = humanText(translated.summary, 300);
|
|
70
|
-
const details = translated.details === void 0 ? void 0 : humanText(translated.details, 900);
|
|
71
|
-
const copy = Object.fromEntries(Object.keys(confirmationCopy(locale)).map((key) => [key, humanText(translated[key], key === "confirm" || key === "cancel" ? 40 : 120)]));
|
|
72
|
-
if (summary === void 0 || Object.values(copy).some((value) => value === void 0) || translated.details !== void 0 && details === void 0 || /\b[a-z]+_[a-z_]+\b/i.test([
|
|
73
|
-
summary,
|
|
74
|
-
details,
|
|
75
|
-
...Object.values(copy)
|
|
76
|
-
].join(" "))) return fallback;
|
|
77
|
-
return {
|
|
78
|
-
...copy,
|
|
79
|
-
text: [summary, details].filter(Boolean).join("\n")
|
|
80
|
-
};
|
|
81
|
-
} catch (error) {
|
|
82
|
-
const secrets = new Set([process.env.AI_GATEWAY_API_KEY, process.env.VERCEL_OIDC_TOKEN].filter((value) => value !== void 0));
|
|
83
|
-
console.warn("Confirmation translation unavailable; using the safe fallback.", redactDiagnostic(error, secrets));
|
|
84
|
-
return fallback;
|
|
85
|
-
}
|
|
67
|
+
text,
|
|
68
|
+
confirm: copy === void 0 ? "✅" : `✅ ${copy.confirm}`,
|
|
69
|
+
cancel: copy === void 0 ? "❌" : `❌ ${copy.cancel}`,
|
|
70
|
+
executing: "⌛",
|
|
71
|
+
cancelled: copy === void 0 ? "❌" : `❌ ${copy.cancelled}`,
|
|
72
|
+
completed: copy === void 0 ? "✅" : `✅ ${copy.done}`,
|
|
73
|
+
failed: copy === void 0 ? "⚠️" : `⚠️ ${copy.failed}`,
|
|
74
|
+
expired: copy?.expired === void 0 ? "⌛" : `⌛ ${copy.expired}`,
|
|
75
|
+
edit: copy?.edit === void 0 ? "✏️" : `✏️ ${copy.edit}`
|
|
86
76
|
};
|
|
87
77
|
}
|
|
88
|
-
export { confirmationCopy, confirmationLocale,
|
|
78
|
+
export { confirmationCopy, confirmationLocale, isConfirmationText, renderConfirmation, withConfirmationText };
|
|
@@ -3,7 +3,6 @@ import type { TelegramCallbackQuery, TelegramChannelEvents, TelegramContext, Tel
|
|
|
3
3
|
import { type Conversations } from "../conversations.js";
|
|
4
4
|
import type { AgentIdentities } from "../identities.js";
|
|
5
5
|
import { type PendingQuestion } from "../questions.js";
|
|
6
|
-
import { type ConfirmationRenderer } from "./confirmation-text.js";
|
|
7
6
|
import { type HistoryReader, type RecordedEvent } from "./sessions.js";
|
|
8
7
|
export declare function confirmationCallback(requestId: string, memberId: string, decision: "approve" | "cancel" | "edit"): string;
|
|
9
8
|
export declare function questionFromHistory(events: readonly RecordedEvent[], owner?: Pick<PendingQuestion, "memberId" | "chatId" | "messageThreadId">): PendingQuestion | undefined;
|
|
@@ -17,5 +16,5 @@ export declare function handleConfirmationCallback(input: {
|
|
|
17
16
|
readonly scope: "chat" | "thread";
|
|
18
17
|
readonly now?: number;
|
|
19
18
|
}): Promise<void>;
|
|
20
|
-
export declare function telegramConfirmationEvents(
|
|
19
|
+
export declare function telegramConfirmationEvents(archive?: Conversations): TelegramChannelEvents & Pick<ChannelEvents<TelegramEventContext>, "context.cleared">;
|
|
21
20
|
export declare const confirmationEvents: TelegramChannelEvents & Pick<ChannelEvents<TelegramEventContext>, "context.cleared">;
|