@segmentstream/agent 0.6.14 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{customer-text-DjszxgTo.mjs → inbound-request-BwBvXk0A.mjs} +110 -109
- package/dist/extension/_manifest.json +2 -0
- package/dist/extension/channels/telegram.mjs +1 -0
- package/dist/extension/config.d.ts +7 -0
- package/dist/extension/config.mjs +13 -1
- package/dist/extension/connections/ontology.mjs +1 -1
- package/dist/extension/hooks/conversations.mjs +1 -1
- package/dist/extension/instructions/conversations.mjs +1 -1
- package/dist/extension/instructions.md +17 -0
- package/dist/extension/lib/confirmation-description.d.ts +5 -0
- package/dist/extension/lib/confirmation-description.mjs +7 -1
- package/dist/extension/lib/confirmation-outcome.d.ts +19 -0
- package/dist/extension/lib/confirmation-outcome.mjs +34 -0
- package/dist/extension/lib/confirmations.mjs +1 -1
- package/dist/extension/lib/conversation-runtime.mjs +1 -1
- package/dist/extension/lib/customer-text-safety.mjs +2 -1
- package/dist/extension/lib/deferred-confirmations.d.ts +39 -0
- package/dist/extension/lib/deferred-confirmations.mjs +149 -0
- package/dist/extension/lib/ontology-tools.d.ts +2 -0
- package/dist/extension/lib/ontology-tools.mjs +6 -1
- package/dist/extension/lib/telegram/adapter.d.ts +1 -0
- package/dist/extension/lib/telegram/adapter.mjs +72 -6
- package/dist/extension/lib/telegram/attachment-description.mjs +1 -1
- package/dist/extension/lib/telegram/attachments-send.mjs +3 -3
- package/dist/extension/lib/telegram/confirmation-expiry.d.ts +4 -0
- package/dist/extension/lib/telegram/confirmation-expiry.mjs +50 -0
- package/dist/extension/lib/telegram/confirmations.d.ts +2 -1
- package/dist/extension/lib/telegram/confirmations.mjs +13 -5
- package/dist/extension/lib/telegram/conversations.mjs +1 -1
- package/dist/extension/lib/telegram/customer-text.mjs +1 -1
- package/dist/extension/lib/telegram/deferred-confirmations.d.ts +26 -0
- package/dist/extension/lib/telegram/deferred-confirmations.mjs +282 -0
- 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.d.ts +2 -0
- 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/observed.d.ts +1 -0
- package/dist/extension/lib/telegram/routing-context.mjs +27 -2
- package/dist/extension/lib/telegram/silent.mjs +1 -1
- package/dist/extension/lib/telegram/turn-errors.mjs +1 -1
- package/dist/extension/lib/telegram/voice.mjs +1 -1
- package/dist/extension/schedules/confirmations.d.ts +6 -0
- package/dist/extension/schedules/confirmations.mjs +33 -0
- package/dist/extension/tools/ontology.d.ts +4 -0
- package/dist/extension/tools/ontology.mjs +30 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.mjs +2 -1
- package/package.json +2 -2
- package/dist/_chunks/{conversation-runtime-BINKO_6b.mjs → conversation-runtime-ovs8IhXJ.mjs} +1 -1
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { fileURLToPath as __eveFileURLToPath } from "node:url";
|
|
2
|
+
import { dirname as __eveDirname } from "node:path";
|
|
3
|
+
import { createRequire as __eveCreateRequire } from "node:module";
|
|
4
|
+
const __filename = __eveFileURLToPath(import.meta.url);
|
|
5
|
+
__eveDirname(__filename);
|
|
6
|
+
__eveCreateRequire(import.meta.url);
|
|
7
|
+
import { telegramPrincipal } from "./principal.mjs";
|
|
8
|
+
import { humanText } from "../confirmation-description.mjs";
|
|
9
|
+
import { renderConfirmation, withConfirmationText } from "./confirmation-text.mjs";
|
|
10
|
+
import { confirmationOutcome } from "../confirmation-outcome.mjs";
|
|
11
|
+
import { chatPostCard, chatPostCardStatus, chatPostReceipt, withChatPostCard } from "./chat-post-card.mjs";
|
|
12
|
+
import { CONFIRMATION_TTL_MS, inputHash } from "../confirmations.mjs";
|
|
13
|
+
import { deferredConfirmations, deferredKey, runDeferredAction } from "../deferred-confirmations.mjs";
|
|
14
|
+
import { conversationEvent } from "../conversations.mjs";
|
|
15
|
+
import { n as currentInboundRequest, p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
|
|
16
|
+
import { formatAddress } from "./sessions.mjs";
|
|
17
|
+
import { agentMessage, observedChatKey, withConfirmationPrompt } from "./observed.mjs";
|
|
18
|
+
import { telegramTextLinks } from "@segmentstream-cloud/ontology/telegram";
|
|
19
|
+
const PREFIX = "ss-confirm:d:";
|
|
20
|
+
const isDeferredCallback = (data) => data?.startsWith(PREFIX) === true;
|
|
21
|
+
const deferredCallback = (record, choice) => `${PREFIX}${record.key}:${choice}`;
|
|
22
|
+
const copyOf = (record) => record.data.confirmation.description?.chatPost ? chatPostCard(record.data.confirmation.description, record.data.confirmation.copy) : renderConfirmation(record.data.confirmation.description, record.data.confirmation.copy);
|
|
23
|
+
function promptOf(record, state) {
|
|
24
|
+
const name = humanText(record.data.requesterName);
|
|
25
|
+
return {
|
|
26
|
+
mode: "deferred",
|
|
27
|
+
requestId: record.id,
|
|
28
|
+
sessionId: record.data.sessionId,
|
|
29
|
+
address: record.data.address,
|
|
30
|
+
action: humanText(record.data.confirmation.description?.action) ?? "❓",
|
|
31
|
+
requestedBy: name ?? null,
|
|
32
|
+
at: new Date(record.expiresAt - CONFIRMATION_TTL_MS).toISOString(),
|
|
33
|
+
state,
|
|
34
|
+
...name === void 0 ? {} : { requester: {
|
|
35
|
+
id: record.data.requester,
|
|
36
|
+
author: name
|
|
37
|
+
} }
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function remember(record, text, prompt, observed) {
|
|
41
|
+
if (record.data.messageId === void 0) return;
|
|
42
|
+
observed?.remember(observedChatKey({
|
|
43
|
+
chatId: record.data.chatId,
|
|
44
|
+
...record.data.threadId ? { messageThreadId: Number(record.data.threadId) } : {}
|
|
45
|
+
}), {
|
|
46
|
+
...agentMessage({
|
|
47
|
+
text,
|
|
48
|
+
at: new Date().toISOString(),
|
|
49
|
+
messageId: record.data.messageId,
|
|
50
|
+
...prompt.requester === void 0 ? {} : { inReplyTo: prompt.requester }
|
|
51
|
+
}),
|
|
52
|
+
confirmation: prompt
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async function archiveDeferred(record, phase, archive) {
|
|
56
|
+
await archive.append(conversationEvent({
|
|
57
|
+
eventId: `confirmation:${record.id}:${phase}`,
|
|
58
|
+
provider: "telegram",
|
|
59
|
+
chatId: record.data.chatId,
|
|
60
|
+
threadId: record.data.threadId || null,
|
|
61
|
+
chatType: record.data.chatId.startsWith("-") ? "group" : "private",
|
|
62
|
+
participantIds: [record.memberId],
|
|
63
|
+
kind: "tool_result",
|
|
64
|
+
sessionId: record.data.sessionId,
|
|
65
|
+
toolCallId: record.id,
|
|
66
|
+
operationId: record.id,
|
|
67
|
+
toolName: record.data.action,
|
|
68
|
+
reason: phase,
|
|
69
|
+
status: phase === "done" ? "completed" : phase === "failed" ? "failed" : phase === "cancelled" || phase === "expired" ? "cancelled" : "requested"
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
async function postDeferredCard(id, channel, ctx, options, archive, observed) {
|
|
73
|
+
const store = deferredConfirmations(options);
|
|
74
|
+
const record = await store.command({
|
|
75
|
+
operation: "read",
|
|
76
|
+
key: deferredKey(id)
|
|
77
|
+
});
|
|
78
|
+
if (!record || record.data.sessionId !== ctx.session.id || record.status !== "pending" || record.data.messageId) return;
|
|
79
|
+
const copy = copyOf(record);
|
|
80
|
+
const address = channel.continuation?.token ?? formatAddress({
|
|
81
|
+
chatId: record.data.chatId,
|
|
82
|
+
messageThreadId: record.data.threadId,
|
|
83
|
+
conversationId: channel.telegram.conversationId ?? ""
|
|
84
|
+
});
|
|
85
|
+
const prompt = {
|
|
86
|
+
...promptOf(record, "pending"),
|
|
87
|
+
address
|
|
88
|
+
};
|
|
89
|
+
await archiveDeferred(record, "requested", archive);
|
|
90
|
+
const post = () => channel.telegram.post({
|
|
91
|
+
text: copy.text,
|
|
92
|
+
reply_markup: { inline_keyboard: [[
|
|
93
|
+
{
|
|
94
|
+
text: copy.confirm,
|
|
95
|
+
callback_data: deferredCallback(record, "y")
|
|
96
|
+
},
|
|
97
|
+
...record.data.confirmation.description?.chatPost ? [{
|
|
98
|
+
text: copy.edit,
|
|
99
|
+
callback_data: deferredCallback(record, "e")
|
|
100
|
+
}] : [],
|
|
101
|
+
{
|
|
102
|
+
text: copy.cancel,
|
|
103
|
+
callback_data: deferredCallback(record, "n")
|
|
104
|
+
}
|
|
105
|
+
]] }
|
|
106
|
+
});
|
|
107
|
+
const sent = await withConfirmationPrompt(prompt, () => record.data.confirmation.description?.chatPost ? withChatPostCard(copy.text, post, copy.previewLinks) : withConfirmationText(copy.text, post));
|
|
108
|
+
await store.command({
|
|
109
|
+
operation: "attach",
|
|
110
|
+
key: record.key,
|
|
111
|
+
messageId: sent.id,
|
|
112
|
+
address
|
|
113
|
+
});
|
|
114
|
+
remember({
|
|
115
|
+
...record,
|
|
116
|
+
data: {
|
|
117
|
+
...record.data,
|
|
118
|
+
messageId: sent.id,
|
|
119
|
+
address
|
|
120
|
+
}
|
|
121
|
+
}, copy.text, prompt, observed);
|
|
122
|
+
}
|
|
123
|
+
async function editCard(record, context, status, state, observed) {
|
|
124
|
+
if (!record.data.messageId) return;
|
|
125
|
+
const copy = copyOf(record);
|
|
126
|
+
const exact = record.data.confirmation.description?.chatPost !== void 0;
|
|
127
|
+
const text = exact ? chatPostCardStatus(copy.text, status) : `${copy.text}\n\n${status}`;
|
|
128
|
+
const edit = () => context.telegram.editMessageText({
|
|
129
|
+
messageId: record.data.messageId,
|
|
130
|
+
text,
|
|
131
|
+
replyMarkup: { inline_keyboard: [] }
|
|
132
|
+
});
|
|
133
|
+
const prompt = promptOf(record, state);
|
|
134
|
+
await withConfirmationPrompt(prompt, () => exact ? withChatPostCard(text, edit, [...copy.previewLinks ?? [], ...telegramTextLinks(status)]) : withConfirmationText(text, edit));
|
|
135
|
+
remember(record, text, prompt, observed);
|
|
136
|
+
}
|
|
137
|
+
async function handleDeferredCallback(input) {
|
|
138
|
+
const { query, context, options, archive } = input;
|
|
139
|
+
const notice = async (text) => {
|
|
140
|
+
try {
|
|
141
|
+
await context.telegram.answerCallbackQuery({
|
|
142
|
+
callbackQueryId: query.id,
|
|
143
|
+
text,
|
|
144
|
+
showAlert: false
|
|
145
|
+
});
|
|
146
|
+
} catch (error) {
|
|
147
|
+
reportTelegramError("deferred_acknowledgment_failed", error);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const parts = /^ss-confirm:d:([0-9a-f]{20}):([yne])$/.exec(query.data ?? "");
|
|
151
|
+
if (!parts || !query.message || query.from.isBot) {
|
|
152
|
+
await notice("⚠️");
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const store = deferredConfirmations(options);
|
|
156
|
+
const record = await store.command({
|
|
157
|
+
operation: "read",
|
|
158
|
+
key: parts[1]
|
|
159
|
+
});
|
|
160
|
+
const lookup = await input.identities.lookup({
|
|
161
|
+
provider: "telegram",
|
|
162
|
+
externalId: query.from.id
|
|
163
|
+
});
|
|
164
|
+
if (!record || lookup.status !== "paired" || lookup.member.id !== record.memberId || record.data.requester !== query.from.id || record.data.chatId !== query.message.chat.id || record.data.threadId !== String(query.message.messageThreadId ?? "") || record.data.messageId !== query.message.messageId) {
|
|
165
|
+
await notice("🔒");
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (record.inputHash !== inputHash(record.data.input) || parts[2] === "e" && record.data.confirmation.description?.chatPost === void 0) {
|
|
169
|
+
await notice("⚠️");
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const copy = copyOf(record);
|
|
173
|
+
const decision = parts[2] === "y" ? "approve" : "cancel";
|
|
174
|
+
const claimed = await store.command({
|
|
175
|
+
operation: "decide",
|
|
176
|
+
key: record.key,
|
|
177
|
+
memberId: record.memberId,
|
|
178
|
+
inputHash: inputHash(record.data.input),
|
|
179
|
+
decision
|
|
180
|
+
});
|
|
181
|
+
if (!claimed || claimed.status === "pending") {
|
|
182
|
+
await notice("⌛");
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
await notice(claimed.status === "expired" ? "⌛" : void 0);
|
|
186
|
+
let status = claimed.status;
|
|
187
|
+
let cardStatus = status === "expired" ? copy.expired : copy.cancelled;
|
|
188
|
+
let execution;
|
|
189
|
+
try {
|
|
190
|
+
await archiveDeferred(claimed, claimed.status, archive);
|
|
191
|
+
} catch (error) {
|
|
192
|
+
const reference = reportTelegramError("deferred_decision_archive_failed", error);
|
|
193
|
+
if (status === "approved") {
|
|
194
|
+
status = "failed";
|
|
195
|
+
execution = "not_started";
|
|
196
|
+
cardStatus = `${copy.failed} ${reference}`;
|
|
197
|
+
await store.command({
|
|
198
|
+
operation: "finish",
|
|
199
|
+
key: claimed.key,
|
|
200
|
+
status
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (status === "approved") {
|
|
205
|
+
try {
|
|
206
|
+
await editCard(claimed, context, copy.executing, "approved", input.observed);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
reportTelegramError("deferred_card_update_failed", error);
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
const result = await runDeferredAction(claimed, options);
|
|
212
|
+
status = "done";
|
|
213
|
+
cardStatus = claimed.data.confirmation.description?.chatPost ? chatPostReceipt(result.structuredContent, copy.completed) ?? "⚠️ ❓" : copy.completed;
|
|
214
|
+
} catch (error) {
|
|
215
|
+
status = "failed";
|
|
216
|
+
const reference = reportTelegramError("deferred_action_failed", error);
|
|
217
|
+
cardStatus = `${copy.failed} ${reference}`;
|
|
218
|
+
}
|
|
219
|
+
await store.command({
|
|
220
|
+
operation: "finish",
|
|
221
|
+
key: claimed.key,
|
|
222
|
+
status
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
if (status === "done" || status === "failed") try {
|
|
226
|
+
await archiveDeferred(claimed, status, archive);
|
|
227
|
+
} catch (error) {
|
|
228
|
+
reportTelegramError("deferred_outcome_archive_failed", error);
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
await editCard(claimed, context, cardStatus, status === "done" ? "completed" : status, input.observed);
|
|
232
|
+
} catch (error) {
|
|
233
|
+
reportTelegramError("deferred_card_update_failed", error);
|
|
234
|
+
}
|
|
235
|
+
const principal = telegramPrincipal({
|
|
236
|
+
member: lookup.member,
|
|
237
|
+
message: {
|
|
238
|
+
...query.message,
|
|
239
|
+
from: query.from,
|
|
240
|
+
text: "",
|
|
241
|
+
caption: "",
|
|
242
|
+
raw: {},
|
|
243
|
+
attachments: []
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
await currentInboundRequest()?.confirmationEvent?.(claimed, confirmationOutcome(claimed, status, {
|
|
247
|
+
...execution === void 0 ? {} : { execution },
|
|
248
|
+
...parts[2] === "e" && status === "cancelled" ? { editRequested: true } : {}
|
|
249
|
+
}), principal);
|
|
250
|
+
}
|
|
251
|
+
async function expireDeferredRecord(record, context, options, archive, notify, observed) {
|
|
252
|
+
const claimed = await deferredConfirmations(options).command({
|
|
253
|
+
operation: "decide",
|
|
254
|
+
key: record.key,
|
|
255
|
+
memberId: record.memberId,
|
|
256
|
+
inputHash: record.inputHash,
|
|
257
|
+
decision: "expire"
|
|
258
|
+
});
|
|
259
|
+
if (!claimed) return;
|
|
260
|
+
try {
|
|
261
|
+
await archiveDeferred(claimed, "expired", archive);
|
|
262
|
+
} catch (error) {
|
|
263
|
+
reportTelegramError("deferred_outcome_archive_failed", error);
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
await editCard(claimed, context, copyOf(claimed).expired, "expired", observed);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
reportTelegramError("deferred_card_update_failed", error);
|
|
269
|
+
}
|
|
270
|
+
await notify(claimed, confirmationOutcome(claimed, "expired"), null);
|
|
271
|
+
}
|
|
272
|
+
async function expireDeferredCards(context, options, archive, observed) {
|
|
273
|
+
const records = await deferredConfirmations(options).command({
|
|
274
|
+
operation: "expired",
|
|
275
|
+
chatId: context.telegram.chatId
|
|
276
|
+
});
|
|
277
|
+
for (const record of records) {
|
|
278
|
+
if (record.data.threadId !== String(context.telegram.messageThreadId ?? "")) continue;
|
|
279
|
+
await expireDeferredRecord(record, context, options, archive, async (saved, result, auth) => currentInboundRequest()?.confirmationEvent?.(saved, result, auth), observed);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
export { archiveDeferred, deferredCallback, expireDeferredCards, expireDeferredRecord, handleDeferredCallback, isDeferredCallback, postDeferredCard };
|
|
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { conversationLanguage } from "./principal.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { d as failureText, p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
|
|
9
9
|
import { describableImage, describeReceivedImage } from "./images.mjs";
|
|
10
10
|
import { MAXIMUM_ATTACHMENT_BYTES, attachmentUrl } from "../attachments.mjs";
|
|
11
11
|
function telegramConversation(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-BwBvXk0A.mjs";
|
|
8
8
|
import { gateway, generateText } from "ai";
|
|
9
9
|
const MAXIMUM_IMAGE_DESCRIPTION_BYTES = 5242880;
|
|
10
10
|
const MAXIMUM_NATIVE_IMAGE_BYTES = 3145728;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DeferredConfirmation } from "../deferred-confirmations.js";
|
|
1
2
|
import type { UserContent } from "ai";
|
|
2
3
|
import type { ChannelSource } from "eve/channels";
|
|
3
4
|
import type { SessionAuthContext } from "eve/context";
|
|
@@ -61,6 +62,7 @@ export declare class InboundRequest {
|
|
|
61
62
|
waitUntil: ((task: Promise<unknown>) => void) | undefined;
|
|
62
63
|
/** Continues the exact pending question's session, including under thread scope. */
|
|
63
64
|
address: string | undefined;
|
|
65
|
+
confirmationEvent: ((record: DeferredConfirmation, result: Readonly<Record<string, unknown>>, auth: SessionAuthContext | null) => Promise<unknown>) | undefined;
|
|
64
66
|
respond: ((address: string, requestId: string, decision: "approve" | "cancel", principal: SessionAuthContext, text?: string) => Promise<unknown>) | undefined;
|
|
65
67
|
constructor(
|
|
66
68
|
/** The agent's description from the compiled manifest, for the routing decision. */
|
|
@@ -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 {
|
|
7
|
+
import { i as withReplacedText, n as currentInboundRequest, r as runInboundRequest, t as InboundRequest } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
|
|
8
8
|
export { InboundRequest, currentInboundRequest, runInboundRequest, withReplacedText };
|
|
@@ -5,16 +5,16 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { conversationLanguage, telegramPrincipal } from "./principal.mjs";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { MAXIMUM_ROUTING_ATTACHMENT_BYTES, describeRoutingAttachment, routingAttachmentDeadline } from "./attachment-description.mjs";
|
|
11
|
-
import { attachmentUrl } from "../attachments.mjs";
|
|
8
|
+
import { p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
|
|
9
|
+
import { formatAddress, messageAddress, scopedAddress } from "./sessions.mjs";
|
|
12
10
|
import { contentShape, messageContent } from "./content.mjs";
|
|
13
11
|
import { messageAudience } from "./audience.mjs";
|
|
14
12
|
import { attachmentKind, messageMetadata, observedChatKey, observedContext } from "./observed.mjs";
|
|
13
|
+
import { MAXIMUM_NATIVE_IMAGE_BYTES } from "./images.mjs";
|
|
14
|
+
import { MAXIMUM_ROUTING_ATTACHMENT_BYTES, describeRoutingAttachment, routingAttachmentDeadline } from "./attachment-description.mjs";
|
|
15
|
+
import { attachmentUrl } from "../attachments.mjs";
|
|
15
16
|
import { addressingReason, conversationContext, routeMessage } from "./router.mjs";
|
|
16
17
|
import { answerMarker } from "../questions.mjs";
|
|
17
|
-
import { formatAddress, messageAddress, scopedAddress } from "./sessions.mjs";
|
|
18
18
|
import { questionAddress, questionFromHistory } from "./confirmations.mjs";
|
|
19
19
|
import { routingContext } from "./routing-context.mjs";
|
|
20
20
|
import { recordGateDecision, recordInboundContent, recordRouteDecision } from "./conversations.mjs";
|
|
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { DEFAULT_IMAGE_DESCRIPTION_MODEL } from "../../config.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
|
|
9
9
|
function planMedia(capabilities, descriptionModel = null) {
|
|
10
10
|
if (typeof descriptionModel === "string") return {
|
|
11
11
|
images: "describe",
|
|
@@ -69,6 +69,7 @@ export interface PendingConfirmation {
|
|
|
69
69
|
}
|
|
70
70
|
/** Internal correlation stays in the archive and never enters classifier state. */
|
|
71
71
|
export interface ConfirmationPrompt extends PendingConfirmation {
|
|
72
|
+
readonly mode?: "deferred";
|
|
72
73
|
readonly requestId: string;
|
|
73
74
|
readonly sessionId?: string;
|
|
74
75
|
readonly address?: string;
|
|
@@ -19,6 +19,18 @@ function archivedMetadata(event) {
|
|
|
19
19
|
}
|
|
20
20
|
function archivedRoutingMessages(events) {
|
|
21
21
|
const messages = collapseConversationEvents(events).filter((event) => event.kind === "inbound" || event.kind === "outbound" && (event.status === "sent" || event.status === "completed"));
|
|
22
|
+
const deferredStates = new Map();
|
|
23
|
+
for (const event of [...events].reverse()) {
|
|
24
|
+
if (event.kind !== "tool_result" || event.operationId == null) continue;
|
|
25
|
+
const state = event.reason === "done" ? "completed" : event.reason;
|
|
26
|
+
if ([
|
|
27
|
+
"approved",
|
|
28
|
+
"cancelled",
|
|
29
|
+
"expired",
|
|
30
|
+
"completed",
|
|
31
|
+
"failed"
|
|
32
|
+
].includes(state ?? "")) deferredStates.set(event.operationId, state);
|
|
33
|
+
}
|
|
22
34
|
const membership = new Map();
|
|
23
35
|
for (const event of [...events].reverse()) {
|
|
24
36
|
if (event.kind !== "decision" || event.senderId === null) continue;
|
|
@@ -28,6 +40,8 @@ function archivedRoutingMessages(events) {
|
|
|
28
40
|
}
|
|
29
41
|
return messages.slice(0, 30).reverse().map((event) => {
|
|
30
42
|
const metadata = archivedMetadata(event);
|
|
43
|
+
const prompt = metadata.confirmation;
|
|
44
|
+
const decision = prompt?.mode === "deferred" ? deferredStates.get(prompt.requestId) : void 0;
|
|
31
45
|
const parent = messages.find((candidate) => candidate.messageId !== null && candidate.messageId === event.replyToMessageId);
|
|
32
46
|
const replyTo = metadata.replyTo ?? (event.replyToMessageId === null ? void 0 : {
|
|
33
47
|
messageId: event.replyToMessageId,
|
|
@@ -60,7 +74,10 @@ function archivedRoutingMessages(events) {
|
|
|
60
74
|
};
|
|
61
75
|
return event.kind === "outbound" ? {
|
|
62
76
|
...common,
|
|
63
|
-
...
|
|
77
|
+
...prompt === void 0 ? {} : { confirmation: {
|
|
78
|
+
...prompt,
|
|
79
|
+
...decision === void 0 ? {} : { state: decision }
|
|
80
|
+
} },
|
|
64
81
|
...agentMessage({
|
|
65
82
|
text,
|
|
66
83
|
at: event.at,
|
|
@@ -103,7 +120,15 @@ async function routingContext(input) {
|
|
|
103
120
|
return {
|
|
104
121
|
recent: reconciled,
|
|
105
122
|
pendingQuestions: [...pending.values()].slice(-30),
|
|
106
|
-
pendingConfirmations: [...histories.values()].flatMap((history) => routingConfirmations(history, reconciled, input.at)).
|
|
123
|
+
pendingConfirmations: [...[...histories.values()].flatMap((history) => routingConfirmations(history, reconciled, input.at)), ...reconciled.flatMap((message) => {
|
|
124
|
+
const prompt = "role" in message ? message.confirmation : void 0;
|
|
125
|
+
return prompt?.mode === "deferred" && prompt.state === "pending" ? [{
|
|
126
|
+
state: prompt.state,
|
|
127
|
+
action: prompt.action,
|
|
128
|
+
requestedBy: prompt.requestedBy,
|
|
129
|
+
at: prompt.at
|
|
130
|
+
}] : [];
|
|
131
|
+
})].slice(-5)
|
|
107
132
|
};
|
|
108
133
|
};
|
|
109
134
|
if (input.operations === void 0) return context(input.remembered);
|
|
@@ -5,10 +5,10 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import "./principal.mjs";
|
|
8
|
-
import { a as customerMessage, l as reportTelegramError, n as currentLocale, t as TelegramDeliveryError } from "../../../_chunks/customer-text-DjszxgTo.mjs";
|
|
9
8
|
import { confirmationLocale } from "./confirmation-text.mjs";
|
|
10
9
|
import { splitTelegramText } from "./format.mjs";
|
|
11
10
|
import { inTelegramSendQueue } from "./send-queue.mjs";
|
|
11
|
+
import { a as TelegramDeliveryError, l as customerMessage, o as currentLocale, p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
|
|
12
12
|
import { agentMessage, observedChatKey } from "./observed.mjs";
|
|
13
13
|
const SILENT_MARKERS = new Set(["[silent]", "no_reply"]);
|
|
14
14
|
function isSilentReply(text) {
|
|
@@ -5,8 +5,8 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { memberIdOf } from "./principal.mjs";
|
|
8
|
-
import { i as customerCopy, l as reportTelegramError, n as currentLocale, s as failureText } from "../../../_chunks/customer-text-DjszxgTo.mjs";
|
|
9
8
|
import { confirmationLocale } from "./confirmation-text.mjs";
|
|
9
|
+
import { c as customerCopy, d as failureText, o as currentLocale, p as reportTelegramError } from "../../../_chunks/inbound-request-BwBvXk0A.mjs";
|
|
10
10
|
const telegramFailureEvents = {
|
|
11
11
|
async "turn.cancelled"(event, channel, context) {
|
|
12
12
|
const errorId = reportTelegramError("turn_cancelled", event, {
|
|
@@ -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-BwBvXk0A.mjs";
|
|
8
8
|
import "../connection-proxy.mjs";
|
|
9
9
|
import { gateway, transcribe } from "ai";
|
|
10
10
|
const LABELS = {
|
|
@@ -0,0 +1,33 @@
|
|
|
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 { channelsEnabled } from "../lib/environment.mjs";
|
|
8
|
+
import segmentstream from "../extension.mjs";
|
|
9
|
+
import telegram_default from "../channels/telegram.mjs";
|
|
10
|
+
import { expireScheduledConfirmations } from "../lib/telegram/confirmation-expiry.mjs";
|
|
11
|
+
import { defineSchedule } from "eve/schedules";
|
|
12
|
+
var confirmations_default = defineSchedule({
|
|
13
|
+
cron: "* * * * *",
|
|
14
|
+
async run({ to }) {
|
|
15
|
+
const settings = segmentstream.config.channels.telegram;
|
|
16
|
+
if (!channelsEnabled(process.env) || !settings || segmentstream.config.confirmations.mode !== "deferred") return;
|
|
17
|
+
await expireScheduledConfirmations(settings.connection, async (record, result) => {
|
|
18
|
+
await to(telegram_default, {
|
|
19
|
+
chatId: record.data.chatId,
|
|
20
|
+
messageThreadId: record.data.threadId ? Number(record.data.threadId) : void 0,
|
|
21
|
+
confirmationAddress: record.data.address,
|
|
22
|
+
confirmationSessionId: record.data.sessionId
|
|
23
|
+
}).send(JSON.stringify({
|
|
24
|
+
type: "confirmation_result",
|
|
25
|
+
...result
|
|
26
|
+
}), {
|
|
27
|
+
auth: null,
|
|
28
|
+
turnPolicy: "queue"
|
|
29
|
+
});
|
|
30
|
+
}, {}, settings);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
export { confirmations_default as default };
|
|
@@ -0,0 +1,30 @@
|
|
|
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 { memberIdOf } from "../lib/telegram/principal.mjs";
|
|
8
|
+
import segmentstream from "../extension.mjs";
|
|
9
|
+
import { ontologyTools } from "../lib/ontology-tools.mjs";
|
|
10
|
+
import { executeDeferredTool } from "../lib/deferred-confirmations.mjs";
|
|
11
|
+
import { defineDynamic, defineTool } from "eve/tools";
|
|
12
|
+
var ontology_default = defineDynamic({ events: { "turn.started": async (_event, context) => {
|
|
13
|
+
const memberId = memberIdOf(context.session.auth.current);
|
|
14
|
+
if (!segmentstream.config.ontology.connection || segmentstream.config.confirmations.mode !== "deferred" || memberId === void 0) return null;
|
|
15
|
+
return Object.fromEntries((await ontologyTools().list(memberId)).map((tool) => {
|
|
16
|
+
const action = String(tool.name);
|
|
17
|
+
const schema = tool.inputSchema;
|
|
18
|
+
const properties = Object.fromEntries(Object.entries(schema.properties ?? {}).filter(([key]) => key !== "_segmentstream"));
|
|
19
|
+
return [`ontology__${action}`, defineTool({
|
|
20
|
+
deferred: true,
|
|
21
|
+
description: String(tool.description ?? tool.title ?? action),
|
|
22
|
+
inputSchema: {
|
|
23
|
+
...schema,
|
|
24
|
+
properties
|
|
25
|
+
},
|
|
26
|
+
execute: (input, ctx) => executeDeferredTool(memberId, action, input, ctx)
|
|
27
|
+
})];
|
|
28
|
+
}));
|
|
29
|
+
} } });
|
|
30
|
+
export { ontology_default as default };
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -6,4 +6,5 @@ export { default as attachments_promote } from "../extension/tools/attachments_p
|
|
|
6
6
|
export { default as attachments_read } from "../extension/tools/attachments_read.js";
|
|
7
7
|
export { default as attachments_send } from "../extension/tools/attachments_send.js";
|
|
8
8
|
export { default as attachments_table } from "../extension/tools/attachments_table.js";
|
|
9
|
+
export { default as ontology } from "../extension/tools/ontology.js";
|
|
9
10
|
export { default as questions_ask } from "../extension/tools/questions_ask.js";
|
package/dist/tools/index.mjs
CHANGED
|
@@ -10,5 +10,6 @@ import attachments_promote_default from "../extension/tools/attachments_promote.
|
|
|
10
10
|
import attachments_read_default from "../extension/tools/attachments_read.mjs";
|
|
11
11
|
import attachments_send_default from "../extension/tools/attachments_send.mjs";
|
|
12
12
|
import attachments_table_default from "../extension/tools/attachments_table.mjs";
|
|
13
|
+
import ontology_default from "../extension/tools/ontology.mjs";
|
|
13
14
|
import questions_ask_default from "../extension/tools/questions_ask.mjs";
|
|
14
|
-
export { attachments_discard_default as attachments_discard, attachments_list_default as attachments_list, attachments_promote_default as attachments_promote, attachments_read_default as attachments_read, attachments_send_default as attachments_send, attachments_table_default as attachments_table, questions_ask_default as questions_ask };
|
|
15
|
+
export { attachments_discard_default as attachments_discard, attachments_list_default as attachments_list, attachments_promote_default as attachments_promote, attachments_read_default as attachments_read, attachments_send_default as attachments_send, attachments_table_default as attachments_table, ontology_default as ontology, questions_ask_default as questions_ask };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@segmentstream/agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Mount a SegmentStream workspace's agent on eve: the ontology as tools, acting as the member who writes, and Telegram through the workspace's connection.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "SegmentStream",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"@chat-adapter/telegram": "4.41.0",
|
|
65
|
-
"@segmentstream-cloud/ontology": "0.
|
|
65
|
+
"@segmentstream-cloud/ontology": "0.32.0",
|
|
66
66
|
"@vercel/oidc": "^3.8.4",
|
|
67
67
|
"ai": "^7.0.128",
|
|
68
68
|
"csv-parse": "^7.0.3",
|
package/dist/_chunks/{conversation-runtime-BINKO_6b.mjs → conversation-runtime-ovs8IhXJ.mjs}
RENAMED
|
@@ -6,8 +6,8 @@ __eveDirname(__filename);
|
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { memberIdOf } from "../extension/lib/telegram/principal.mjs";
|
|
8
8
|
import { conversationEvent, conversations, summarizeArguments } from "../extension/lib/conversations.mjs";
|
|
9
|
-
import { completionKind } from "../extension/lib/telegram/silent.mjs";
|
|
10
9
|
import { parseAddress } from "../extension/lib/telegram/sessions.mjs";
|
|
10
|
+
import { completionKind } from "../extension/lib/telegram/silent.mjs";
|
|
11
11
|
const CONTENT_CAPS = {
|
|
12
12
|
args: 16384,
|
|
13
13
|
result: 32768,
|