@segmentstream/agent 0.6.12 → 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/dist/_chunks/{inbound-request-DgyI7oR9.mjs → inbound-request-CysnjMdw.mjs} +51 -59
- 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 +5 -5
- package/dist/extension/lib/telegram/attachments-send.mjs +6 -6
- package/dist/extension/lib/telegram/chat-post-card.d.ts +4 -12
- package/dist/extension/lib/telegram/chat-post-card.mjs +15 -36
- package/dist/extension/lib/telegram/confirmation-text.d.ts +19 -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 +36 -94
- package/dist/extension/lib/telegram/conversations.mjs +1 -1
- package/dist/extension/lib/telegram/customer-text.d.ts +3 -4
- 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 -2
|
@@ -4,6 +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 { renderConfirmation } from "./confirmation-text.mjs";
|
|
7
8
|
import { telegramMarkdownLinks, telegramTextLinks } from "@segmentstream-cloud/ontology/telegram";
|
|
8
9
|
import { escapeMarkdownV2 } from "@chat-adapter/telegram";
|
|
9
10
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -23,59 +24,37 @@ function chatPostCardLinks(text) {
|
|
|
23
24
|
const card = exactText.getStore();
|
|
24
25
|
return card?.text === text ? card.links : void 0;
|
|
25
26
|
}
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
uncertain: "Неизвестно, отправлено ли сообщение. Не отправляйте его повторно автоматически.",
|
|
31
|
-
sent: "Отправлено.",
|
|
32
|
-
history: "Не удалось записать квитанцию в историю.",
|
|
33
|
-
expired: "Срок подтверждения истёк. Ничего не отправлено."
|
|
34
|
-
} : {
|
|
35
|
-
edit: "Edit",
|
|
36
|
-
changes: "What would you like to change in the message?",
|
|
37
|
-
uncertain: "Delivery is uncertain. Do not resend automatically.",
|
|
38
|
-
sent: "Sent.",
|
|
39
|
-
history: "The receipt could not be recorded in history.",
|
|
40
|
-
expired: "This confirmation expired. Nothing was sent."
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
function chatPostCard(preview, locale) {
|
|
44
|
-
const russian = locale.startsWith("ru");
|
|
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);
|
|
45
31
|
const text = [
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
...preview.replyTo === null ? [] : [
|
|
49
|
-
|
|
50
|
-
].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}`;
|
|
51
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.");
|
|
52
37
|
return {
|
|
38
|
+
...base,
|
|
53
39
|
text,
|
|
54
40
|
previewLinks: [
|
|
55
41
|
...telegramTextLinks(`${preview.title}\n${preview.replyTo ?? ""}`),
|
|
56
42
|
...telegramMarkdownLinks(preview.text),
|
|
57
43
|
...telegramTextLinks(preview.attribution)
|
|
58
|
-
]
|
|
59
|
-
confirm: russian ? "Отправить" : "Confirm",
|
|
60
|
-
cancel: russian ? "Отмена" : "Cancel",
|
|
61
|
-
executing: russian ? "Подтверждено." : "Confirmed.",
|
|
62
|
-
cancelled: russian ? "Отменено." : "Cancelled.",
|
|
63
|
-
completed: chatPostCopy(locale).sent,
|
|
64
|
-
failed: russian ? "Ошибка отправки сообщения." : "Chat posting failed."
|
|
44
|
+
]
|
|
65
45
|
};
|
|
66
46
|
}
|
|
67
47
|
function chatPostCardStatus(text, status) {
|
|
68
48
|
return `${text}\n\n${escapeMarkdownV2(status)}`;
|
|
69
49
|
}
|
|
70
|
-
function chatPostReceipt(output,
|
|
50
|
+
function chatPostReceipt(output, completed = "✅") {
|
|
71
51
|
const value = typeof output === "object" && output !== null ? output : {};
|
|
72
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;
|
|
73
|
-
const copy = chatPostCopy(locale);
|
|
74
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;
|
|
75
54
|
return [
|
|
76
|
-
value.status === "sent" ?
|
|
55
|
+
value.status === "sent" ? completed : "⚠️ ❓",
|
|
77
56
|
...url === null ? [] : [url],
|
|
78
|
-
...value.history_recorded ? [] : [
|
|
57
|
+
...value.history_recorded ? [] : ["⚠️"]
|
|
79
58
|
].join("\n");
|
|
80
59
|
}
|
|
81
|
-
export { chatPostCard, chatPostCardLinks, chatPostCardStatus,
|
|
60
|
+
export { chatPostCard, chatPostCardLinks, chatPostCardStatus, chatPostReceipt, isExactChatPostCard, withChatPostCard };
|
|
@@ -1,5 +1,18 @@
|
|
|
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 {
|
|
4
17
|
readonly previewLinks?: readonly string[];
|
|
5
18
|
readonly text: string;
|
|
@@ -9,13 +22,11 @@ export interface ConfirmationText {
|
|
|
9
22
|
readonly cancelled: string;
|
|
10
23
|
readonly completed: string;
|
|
11
24
|
readonly failed: string;
|
|
25
|
+
readonly expired: string;
|
|
26
|
+
readonly edit: string;
|
|
12
27
|
}
|
|
13
28
|
export declare function confirmationLocale(principal: SessionAuthContext | null, fallback?: string): string;
|
|
14
|
-
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export declare function confirmationRenderer(input: {
|
|
19
|
-
readonly model: () => string;
|
|
20
|
-
readonly translate?: (description: ConfirmationDescription, locale: string) => Promise<string>;
|
|
21
|
-
}): 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">;
|
|
@@ -4,14 +4,14 @@ 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 {
|
|
7
|
+
import { memberIdOf, telegramPrincipal } from "./principal.mjs";
|
|
8
8
|
import { chatPostOperationId, isChatPost } from "../chat-post-confirmation.mjs";
|
|
9
|
-
import {
|
|
9
|
+
import { renderConfirmation, withConfirmationText } from "./confirmation-text.mjs";
|
|
10
|
+
import { chatPostCard, chatPostCardStatus, chatPostReceipt, withChatPostCard } from "./chat-post-card.mjs";
|
|
10
11
|
import { confirmations } from "../confirmations.mjs";
|
|
11
12
|
import { conversationEvent } from "../conversations.mjs";
|
|
12
|
-
import {
|
|
13
|
+
import { n as currentInboundRequest, p as reportTelegramError } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
|
|
13
14
|
import { answerMarker, isPendingQuestion, pendingQuestions, questionKey } from "../questions.mjs";
|
|
14
|
-
import { confirmationCopy, confirmationLocale, fallbackConfirmation } from "./confirmation-text.mjs";
|
|
15
15
|
import { formatAddress, scopedAddress } from "./sessions.mjs";
|
|
16
16
|
import { telegramTextLinks } from "@segmentstream-cloud/ontology/telegram";
|
|
17
17
|
import { registerTelegramFreeformPrompt, renderTelegramInputRequest } from "eve/channels/telegram";
|
|
@@ -55,10 +55,6 @@ function questionFromHistory(events, owner) {
|
|
|
55
55
|
for (const event of events) {
|
|
56
56
|
const data = object(event.data);
|
|
57
57
|
if (event.type === "context.cleared") pending.clear();
|
|
58
|
-
if (event.type === "input.resolved" && Array.isArray(data.resolutions)) for (const resolution of data.resolutions) {
|
|
59
|
-
const question = chatPostEditQuestion(object(resolution));
|
|
60
|
-
if (question !== void 0) pending.set(questionKey(question), question);
|
|
61
|
-
}
|
|
62
58
|
if (event.type === "action.result") {
|
|
63
59
|
const result = object(data.result);
|
|
64
60
|
const candidate = object(result.output).pendingQuestion;
|
|
@@ -70,16 +66,6 @@ function questionFromHistory(events, owner) {
|
|
|
70
66
|
}
|
|
71
67
|
return owner === void 0 ? [...pending.values()].at(-1) : pending.get(questionKey(owner));
|
|
72
68
|
}
|
|
73
|
-
function chatPostEditQuestion(resolution) {
|
|
74
|
-
const text = object(resolution.response).text;
|
|
75
|
-
if (resolution.outcome !== "cancelled" || typeof text !== "string") return;
|
|
76
|
-
try {
|
|
77
|
-
const question = object(JSON.parse(text)).pendingChatPostEdit;
|
|
78
|
-
return isPendingQuestion(question) ? question : void 0;
|
|
79
|
-
} catch {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
69
|
function questionAddress(owner) {
|
|
84
70
|
return formatAddress({
|
|
85
71
|
...owner,
|
|
@@ -88,27 +74,15 @@ function questionAddress(owner) {
|
|
|
88
74
|
}
|
|
89
75
|
async function handleConfirmationCallback(input) {
|
|
90
76
|
const { context, query } = input;
|
|
91
|
-
const chatLanguage = conversationLanguage([String(object(query.raw.message).text ?? "")]);
|
|
92
|
-
let language = chatLanguage ?? query.from.languageCode ?? "en";
|
|
93
77
|
const inbound = currentInboundRequest();
|
|
94
|
-
if (inbound !== void 0)
|
|
95
|
-
inbound.locale = language;
|
|
96
|
-
inbound.threadId = query.message?.messageThreadId === void 0 ? void 0 : String(query.message.messageThreadId);
|
|
97
|
-
}
|
|
98
|
-
const notices = {
|
|
99
|
-
"Unsupported action.": "Действие недоступно.",
|
|
100
|
-
"Only the requesting member can confirm or cancel this action.": "Подтвердить или отменить действие может только тот, кто его запросил.",
|
|
101
|
-
"This confirmation is no longer pending.": "Это подтверждение больше не ожидает ответа.",
|
|
102
|
-
"This confirmation expired; nothing executed.": "Срок подтверждения истёк. Действие не выполнено.",
|
|
103
|
-
"Cancellation received.": "Отменено.",
|
|
104
|
-
"Confirmation received.": "Подтверждено."
|
|
105
|
-
};
|
|
78
|
+
if (inbound !== void 0) inbound.threadId = query.message?.messageThreadId === void 0 ? void 0 : String(query.message.messageThreadId);
|
|
106
79
|
const notice = (text) => context.telegram.answerCallbackQuery({
|
|
107
80
|
callbackQueryId: query.id,
|
|
108
|
-
text
|
|
81
|
+
...text === void 0 ? {} : { text },
|
|
82
|
+
showAlert: false
|
|
109
83
|
});
|
|
110
84
|
if (!query.data?.startsWith(PREFIX) || query.message === void 0 || query.from.isBot) {
|
|
111
|
-
await notice("
|
|
85
|
+
await notice("⚠️");
|
|
112
86
|
return;
|
|
113
87
|
}
|
|
114
88
|
const [requestHash, memberHash, choice] = query.data.slice(11).split(":");
|
|
@@ -116,12 +90,8 @@ async function handleConfirmationCallback(input) {
|
|
|
116
90
|
provider: "telegram",
|
|
117
91
|
externalId: query.from.id
|
|
118
92
|
});
|
|
119
|
-
if (lookup.status === "paired" && chatLanguage === void 0) {
|
|
120
|
-
language = lookup.member.locale ?? language;
|
|
121
|
-
if (inbound !== void 0) inbound.locale = language;
|
|
122
|
-
}
|
|
123
93
|
if (lookup.status !== "paired" || shortHash(lookup.member.id) !== memberHash) {
|
|
124
|
-
await notice("
|
|
94
|
+
await notice("🔒");
|
|
125
95
|
return;
|
|
126
96
|
}
|
|
127
97
|
const address = scopedAddress(formatAddress({
|
|
@@ -136,7 +106,7 @@ async function handleConfirmationCallback(input) {
|
|
|
136
106
|
"n",
|
|
137
107
|
"e"
|
|
138
108
|
].includes(choice ?? "") || choice === "e" && !isChatPost(prompt.toolName)) {
|
|
139
|
-
await notice("
|
|
109
|
+
await notice("⌛");
|
|
140
110
|
return;
|
|
141
111
|
}
|
|
142
112
|
const expired = !Number.isFinite(prompt.at) || prompt.at + 6e5 <= (input.now ?? Date.now());
|
|
@@ -155,15 +125,6 @@ async function handleConfirmationCallback(input) {
|
|
|
155
125
|
});
|
|
156
126
|
const source = currentInboundRequest()?.respond;
|
|
157
127
|
if (source === void 0) throw new Error("Confirmation callback has no session continuation.");
|
|
158
|
-
const editQuestion = edit ? {
|
|
159
|
-
id: `edit-${prompt.callId}`,
|
|
160
|
-
memberId: lookup.member.id,
|
|
161
|
-
chatId: query.message.chat.id,
|
|
162
|
-
messageThreadId: String(query.message.messageThreadId ?? ""),
|
|
163
|
-
address,
|
|
164
|
-
question: chatPostCopy(language).changes,
|
|
165
|
-
task: `The previous chat post was cancelled for editing. Apply the member's changes to this draft, then make a NEW chat_post_message call and confirmation. Never reuse the cancelled call. Previous input: ${JSON.stringify(prompt.input)}`
|
|
166
|
-
} : void 0;
|
|
167
128
|
await source(address, prompt.requestId, decision, {
|
|
168
129
|
...principal,
|
|
169
130
|
attributes: {
|
|
@@ -172,10 +133,10 @@ async function handleConfirmationCallback(input) {
|
|
|
172
133
|
confirmationDecision: decision,
|
|
173
134
|
...expired ? { confirmationReason: "expired" } : edit ? { confirmationReason: "edit" } : {}
|
|
174
135
|
}
|
|
175
|
-
},
|
|
176
|
-
await notice(expired ? "
|
|
136
|
+
}, edit ? "The chat post was cancelled for editing. Ask the member what to change using questions_ask, then make a NEW chat_post_message call and confirmation. Never reuse the cancelled call." : void 0);
|
|
137
|
+
await notice(expired ? "⌛" : void 0);
|
|
177
138
|
}
|
|
178
|
-
function telegramConfirmationEvents(
|
|
139
|
+
function telegramConfirmationEvents(archive) {
|
|
179
140
|
const record = async (callId, phase, text, status, ctx) => {
|
|
180
141
|
const saved = confirmations.get()[callId];
|
|
181
142
|
if (archive === void 0 || saved?.description?.chatPost === void 0 || saved.source === void 0) return;
|
|
@@ -242,10 +203,12 @@ function telegramConfirmationEvents(render = async (description, locale) => fall
|
|
|
242
203
|
}
|
|
243
204
|
const memberId = confirmations.get()[request.action.callId]?.memberId ?? memberIdOf(ctx.session.auth.current);
|
|
244
205
|
if (memberId === void 0) throw new Error("Confirmation requires a member.");
|
|
245
|
-
const
|
|
206
|
+
const saved = confirmations.get()[request.action.callId];
|
|
207
|
+
const description = saved?.description;
|
|
246
208
|
const exactPost = isChatPost(request.action.toolName);
|
|
209
|
+
if (description === void 0) throw new Error("Approval buttons require trusted confirmation facts.");
|
|
247
210
|
if (exactPost && description?.chatPost === void 0) throw new Error("An exact chat post cannot show a generic confirmation.");
|
|
248
|
-
const copy = description?.chatPost === void 0 ?
|
|
211
|
+
const copy = description?.chatPost === void 0 ? renderConfirmation(description, saved?.copy) : chatPostCard(description, saved?.copy);
|
|
249
212
|
const text = copy.text;
|
|
250
213
|
await record(request.action.callId, "preview", text, "requested", ctx);
|
|
251
214
|
const send = () => channel.telegram.post({
|
|
@@ -256,7 +219,7 @@ function telegramConfirmationEvents(render = async (description, locale) => fall
|
|
|
256
219
|
callback_data: confirmationCallback(request.requestId, memberId, "approve")
|
|
257
220
|
},
|
|
258
221
|
...exactPost ? [{
|
|
259
|
-
text:
|
|
222
|
+
text: copy.edit,
|
|
260
223
|
callback_data: confirmationCallback(request.requestId, memberId, "edit")
|
|
261
224
|
}] : [],
|
|
262
225
|
{
|
|
@@ -265,7 +228,7 @@ function telegramConfirmationEvents(render = async (description, locale) => fall
|
|
|
265
228
|
}
|
|
266
229
|
]] }
|
|
267
230
|
});
|
|
268
|
-
const sent = await (exactPost ? withChatPostCard(text, send, copy.previewLinks) : send
|
|
231
|
+
const sent = await (exactPost ? withChatPostCard(text, send, copy.previewLinks) : withConfirmationText(text, send));
|
|
269
232
|
const state = channel.state;
|
|
270
233
|
state.confirmationMessages = {
|
|
271
234
|
...state.confirmationMessages,
|
|
@@ -274,7 +237,6 @@ function telegramConfirmationEvents(render = async (description, locale) => fall
|
|
|
274
237
|
messageId: sent.id,
|
|
275
238
|
text,
|
|
276
239
|
copy,
|
|
277
|
-
locale: confirmationLocale(ctx.session.auth.current),
|
|
278
240
|
exactPost,
|
|
279
241
|
previewLinks: copy.previewLinks
|
|
280
242
|
}
|
|
@@ -293,47 +255,24 @@ function telegramConfirmationEvents(render = async (description, locale) => fall
|
|
|
293
255
|
await channel.telegram.editMessageText({
|
|
294
256
|
messageId: prompt.messageId,
|
|
295
257
|
replyMarkup: { inline_keyboard: [] },
|
|
296
|
-
text: `${prompt.text}\n\n${label ??
|
|
258
|
+
text: `${prompt.text}\n\n${label ?? "✅"}`
|
|
297
259
|
});
|
|
298
260
|
delete channel.state.hitlPrompts?.[resolution.requestId];
|
|
299
261
|
}
|
|
300
262
|
continue;
|
|
301
263
|
}
|
|
302
264
|
const [callId, message] = entry;
|
|
303
|
-
const copy = message.copy ??
|
|
265
|
+
const copy = message.copy ?? renderConfirmation();
|
|
304
266
|
const reason = confirmations.get()[callId]?.cancellationReason;
|
|
305
|
-
const status = resolution.outcome === "approved" ? copy.executing : reason === "expired" ?
|
|
306
|
-
const text = message.exactPost ? chatPostCardStatus(message.text, status) : status
|
|
267
|
+
const status = resolution.outcome === "approved" ? copy.executing : reason === "expired" ? copy.expired : copy.cancelled;
|
|
268
|
+
const text = message.exactPost ? chatPostCardStatus(message.text, status) : `${message.text}\n\n${status}`;
|
|
307
269
|
const edit = () => channel.telegram.editMessageText({
|
|
308
270
|
messageId: message.messageId,
|
|
309
271
|
replyMarkup: { inline_keyboard: [] },
|
|
310
272
|
text
|
|
311
273
|
});
|
|
312
|
-
await (message.exactPost ? withChatPostCard(text, edit, [...message.previewLinks ?? [], ...telegramTextLinks(status)]) : edit
|
|
313
|
-
await record(callId, reason ?? resolution.outcome, text, resolution.outcome === "approved" ? "
|
|
314
|
-
const question = chatPostEditQuestion(resolution);
|
|
315
|
-
if (message.exactPost && reason === "edit" && question !== void 0) {
|
|
316
|
-
pendingQuestions.update((all) => ({
|
|
317
|
-
...all,
|
|
318
|
-
[questionKey(question)]: question
|
|
319
|
-
}));
|
|
320
|
-
state.pendingQuestions = {
|
|
321
|
-
...state.pendingQuestions,
|
|
322
|
-
[questionKey(question)]: question
|
|
323
|
-
};
|
|
324
|
-
channel.continuation?.alias(questionAddress(question));
|
|
325
|
-
channel.continuation?.alias(formatAddress({
|
|
326
|
-
...question,
|
|
327
|
-
conversationId: ""
|
|
328
|
-
}));
|
|
329
|
-
await channel.telegram.post({
|
|
330
|
-
text: question.question,
|
|
331
|
-
reply_markup: {
|
|
332
|
-
force_reply: true,
|
|
333
|
-
selective: true
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
}
|
|
274
|
+
await (message.exactPost ? withChatPostCard(text, edit, [...message.previewLinks ?? [], ...telegramTextLinks(status)]) : withConfirmationText(text, edit));
|
|
275
|
+
await record(callId, reason ?? resolution.outcome, text, resolution.outcome === "approved" ? "requested" : "cancelled", ctx);
|
|
337
276
|
if (resolution.outcome !== "approved") {
|
|
338
277
|
delete state.confirmationMessages?.[callId];
|
|
339
278
|
confirmations.update((all) => ({
|
|
@@ -387,10 +326,10 @@ function telegramConfirmationEvents(render = async (description, locale) => fall
|
|
|
387
326
|
if (message === void 0) return;
|
|
388
327
|
const failed = data.status !== "completed" || data.result.kind === "tool-result" && (data.result.isError === true || object(data.result.output).isError === true || object(object(data.result.output).validation).ok === false);
|
|
389
328
|
if (message.exactPost) {
|
|
390
|
-
const
|
|
391
|
-
const receipt = !failed && data.result.kind === "tool-result" ? chatPostReceipt(data.result.output,
|
|
329
|
+
const copy = message.copy ?? renderConfirmation();
|
|
330
|
+
const receipt = !failed && data.result.kind === "tool-result" ? chatPostReceipt(data.result.output, copy.completed) : void 0;
|
|
392
331
|
const errorId = failed ? reportTelegramError("confirmed_chat_post_failed", data, { callId: data.result.callId }) : void 0;
|
|
393
|
-
const status = receipt ?? (failed ? `${
|
|
332
|
+
const status = receipt ?? (failed ? `${copy.failed} ${errorId}\n⚠️ ❓` : "⚠️ ❓");
|
|
394
333
|
const text = chatPostCardStatus(message.text, status);
|
|
395
334
|
await withChatPostCard(text, () => channel.telegram.editMessageText({
|
|
396
335
|
messageId: message.messageId,
|
|
@@ -398,13 +337,16 @@ function telegramConfirmationEvents(render = async (description, locale) => fall
|
|
|
398
337
|
text
|
|
399
338
|
}), [...message.previewLinks ?? [], ...telegramTextLinks(status)]);
|
|
400
339
|
await record(data.result.callId, "receipt", text, failed ? "failed" : object(data.result.kind === "tool-result" ? data.result.output : void 0).status === "sent" ? "completed" : "unknown", ctx);
|
|
401
|
-
} else
|
|
402
|
-
const
|
|
403
|
-
|
|
340
|
+
} else {
|
|
341
|
+
const copy = message.copy ?? renderConfirmation();
|
|
342
|
+
const errorId = failed ? reportTelegramError("confirmed_action_failed", data, { callId: data.result.callId }) : void 0;
|
|
343
|
+
const status = failed ? `${copy.failed} ${errorId}` : copy.completed;
|
|
344
|
+
const text = `${message.text}\n\n${status}`;
|
|
345
|
+
await withConfirmationText(text, () => channel.telegram.editMessageText({
|
|
404
346
|
messageId: message.messageId,
|
|
405
347
|
replyMarkup: { inline_keyboard: [] },
|
|
406
|
-
text
|
|
407
|
-
});
|
|
348
|
+
text
|
|
349
|
+
}));
|
|
408
350
|
}
|
|
409
351
|
delete state.confirmationMessages?.[data.result.callId];
|
|
410
352
|
},
|
|
@@ -6,7 +6,7 @@ __eveDirname(__filename);
|
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { collapseConversationEvents, conversationEvent } from "../conversations.mjs";
|
|
8
8
|
import { observedChatKey } from "./observed.mjs";
|
|
9
|
-
import { n as currentInboundRequest, s as currentThreadId } from "../../../_chunks/inbound-request-
|
|
9
|
+
import { n as currentInboundRequest, s as currentThreadId } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
|
|
10
10
|
import { reportMembership } from "./membership.mjs";
|
|
11
11
|
import { contentShape, messageContent } from "./content.mjs";
|
|
12
12
|
import { parseTelegramUpdate } from "eve/channels/telegram";
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import { type TelegramPreviewContext } from "@segmentstream-cloud/ontology/telegram";
|
|
2
2
|
import { type TelegramText } from "./format.js";
|
|
3
|
+
export { isTechnicalText } from "../customer-text-safety.js";
|
|
3
4
|
export declare function withDeliveryLocale<T>(locale: string, run: () => T, threadId?: string): T;
|
|
4
5
|
export declare function currentLocale(): string;
|
|
5
6
|
export declare function currentThreadId(): string | undefined;
|
|
6
|
-
export declare function customerCopy(
|
|
7
|
+
export declare function customerCopy(): {
|
|
7
8
|
failed: string;
|
|
8
9
|
recovery: string;
|
|
9
10
|
attachment: string;
|
|
10
11
|
authorization: string;
|
|
11
12
|
response: string;
|
|
12
|
-
reference: string;
|
|
13
13
|
connected: string;
|
|
14
14
|
disconnected: string;
|
|
15
15
|
};
|
|
16
|
-
export declare function isTechnicalText(text: string): boolean;
|
|
17
16
|
/** Original failures stay in operator diagnostics, joined to the public notice by a short reference. */
|
|
18
17
|
export declare function reportTelegramError(operation: string, error: unknown, metadata?: Record<string, unknown>, secrets?: ReadonlySet<string>): string;
|
|
19
|
-
export declare function failureText(errorId: string, kind?: "failed" | "cancelled" | "recovery" | "attachment" | "authorization" | "response",
|
|
18
|
+
export declare function failureText(errorId: string, kind?: "failed" | "cancelled" | "recovery" | "attachment" | "authorization" | "response", _locale?: string): string;
|
|
20
19
|
export declare function customerText(text: string, locale?: string): string;
|
|
21
20
|
/** Check what Telegram will display, including hidden link destinations, after removing markup. */
|
|
22
21
|
export declare function customerMessage(text: string, locale?: string): TelegramText;
|
|
@@ -4,5 +4,6 @@ import { createRequire as __eveCreateRequire } from "node:module";
|
|
|
4
4
|
const __filename = __eveFileURLToPath(import.meta.url);
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
|
-
import {
|
|
7
|
+
import { isTechnicalText } from "../customer-text-safety.mjs";
|
|
8
|
+
import { a as TelegramDeliveryError, c as customerCopy, d as failureText, f as formattingRefused, h as withDeliveryLocale, l as customerMessage, m as safeTelegramFetch, o as currentLocale, p as reportTelegramError, s as currentThreadId, u as customerText } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
|
|
8
9
|
export { TelegramDeliveryError, currentLocale, currentThreadId, customerCopy, customerMessage, customerText, failureText, formattingRefused, isTechnicalText, reportTelegramError, safeTelegramFetch, withDeliveryLocale };
|
|
@@ -6,7 +6,7 @@ __eveDirname(__filename);
|
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { conversationLanguage } from "./principal.mjs";
|
|
8
8
|
import { MAXIMUM_ATTACHMENT_BYTES, attachmentUrl } from "../attachments.mjs";
|
|
9
|
-
import { d as failureText,
|
|
9
|
+
import { d as failureText, p as reportTelegramError } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
|
|
10
10
|
import { describableImage, describeReceivedImage } from "./images.mjs";
|
|
11
11
|
function telegramConversation(chatId) {
|
|
12
12
|
return `telegram:${chatId}`;
|
|
@@ -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 {
|
|
7
|
+
import { p as reportTelegramError } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
|
|
8
8
|
import { gateway, generateText } from "ai";
|
|
9
9
|
const MAXIMUM_IMAGE_DESCRIPTION_BYTES = 5242880;
|
|
10
10
|
const MAXIMUM_NATIVE_IMAGE_BYTES = 3145728;
|
|
@@ -4,5 +4,5 @@ import { createRequire as __eveCreateRequire } from "node:module";
|
|
|
4
4
|
const __filename = __eveFileURLToPath(import.meta.url);
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
|
-
import { i as withReplacedText, n as currentInboundRequest, r as runInboundRequest, t as InboundRequest } from "../../../_chunks/inbound-request-
|
|
7
|
+
import { i as withReplacedText, n as currentInboundRequest, r as runInboundRequest, t as InboundRequest } from "../../../_chunks/inbound-request-CysnjMdw.mjs";
|
|
8
8
|
export { InboundRequest, currentInboundRequest, runInboundRequest, withReplacedText };
|