@segmentstream/agent 0.14.0 → 0.15.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/README.md +7 -1
- package/dist/_chunks/{build-metadata-BB2uSGsI.mjs → build-metadata-CJlaXNhc.mjs} +1 -1
- package/dist/_chunks/{inbound-request-BXhiIph-.mjs → inbound-request-RIRNBxUC.mjs} +3 -0
- package/dist/_chunks/{principal-VFQWqe5S.mjs → principal-MEMlG3EG.mjs} +1 -1
- package/dist/extension/config.d.ts +6 -0
- package/dist/extension/config.mjs +31 -1
- package/dist/extension/hooks/authorization.mjs +1 -1
- package/dist/extension/lib/attachment-tools.mjs +1 -1
- package/dist/extension/lib/build-metadata.mjs +1 -1
- package/dist/extension/lib/confirmations.mjs +1 -1
- package/dist/extension/lib/conversation-runtime.mjs +1 -1
- package/dist/extension/lib/deferred-confirmations.mjs +1 -1
- package/dist/extension/lib/ontology-connection.mjs +1 -1
- package/dist/extension/lib/ontology-gateway.mjs +1 -1
- package/dist/extension/lib/ontology-metadata-read.mjs +1 -1
- package/dist/extension/lib/ontology-tools.d.ts +2 -0
- package/dist/extension/lib/ontology-tools.mjs +2 -1
- package/dist/extension/lib/runtime-envelope.mjs +1 -1
- package/dist/extension/lib/stored-files.mjs +1 -1
- package/dist/extension/lib/telegram/adapter.mjs +23 -4
- package/dist/extension/lib/telegram/attachment-description.mjs +1 -1
- package/dist/extension/lib/telegram/attachments-send.mjs +2 -2
- package/dist/extension/lib/telegram/callbacks.mjs +3 -3
- package/dist/extension/lib/telegram/confirmation-expiry.mjs +1 -1
- package/dist/extension/lib/telegram/confirmations.mjs +3 -3
- package/dist/extension/lib/telegram/conversations.d.ts +3 -0
- package/dist/extension/lib/telegram/conversations.mjs +57 -12
- package/dist/extension/lib/telegram/customer-text.mjs +1 -1
- package/dist/extension/lib/telegram/deferred-confirmations.mjs +3 -3
- package/dist/extension/lib/telegram/files.mjs +2 -2
- package/dist/extension/lib/telegram/health.mjs +1 -1
- package/dist/extension/lib/telegram/images.mjs +1 -1
- package/dist/extension/lib/telegram/inbound-request.d.ts +7 -0
- package/dist/extension/lib/telegram/inbound-request.mjs +1 -1
- package/dist/extension/lib/telegram/inbound.d.ts +5 -0
- package/dist/extension/lib/telegram/inbound.mjs +104 -14
- package/dist/extension/lib/telegram/lifecycle.mjs +3 -3
- 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/structured-settings.d.ts +6 -0
- package/dist/extension/lib/telegram/structured-settings.mjs +12 -0
- package/dist/extension/lib/telegram/structured.d.ts +28 -0
- package/dist/extension/lib/telegram/structured.mjs +114 -0
- package/dist/extension/lib/telegram/turn-errors.mjs +2 -2
- package/dist/extension/lib/telegram/voice.mjs +1 -1
- package/dist/extension/lib/telegram/workspace-action.d.ts +3 -0
- package/dist/extension/lib/telegram/workspace-action.mjs +8 -2
- package/dist/extension/model.mjs +1 -1
- package/dist/extension/tools/attachments_promote.mjs +1 -1
- package/dist/extension/tools/ontology.mjs +1 -1
- package/dist/extension/tools/questions_ask.mjs +1 -1
- package/package.json +2 -2
|
@@ -4,7 +4,7 @@ import { createRequire as __eveCreateRequire } from "node:module";
|
|
|
4
4
|
const __filename = __eveFileURLToPath(import.meta.url);
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
|
-
import { p as reportTelegramError } from "../../../_chunks/inbound-request-
|
|
7
|
+
import { p as reportTelegramError } from "../../../_chunks/inbound-request-RIRNBxUC.mjs";
|
|
8
8
|
import { gateway, generateText } from "ai";
|
|
9
9
|
const MAXIMUM_IMAGE_DESCRIPTION_BYTES = 5242880;
|
|
10
10
|
const MAXIMUM_NATIVE_IMAGE_BYTES = 3145728;
|
|
@@ -60,6 +60,13 @@ export declare class InboundRequest {
|
|
|
60
60
|
/** Finalize the reservation only after the durable inbox acknowledges delivery. */
|
|
61
61
|
beginDispatch: (() => Promise<boolean>) | undefined;
|
|
62
62
|
finishClaim: ((accepted: boolean) => Promise<void>) | undefined;
|
|
63
|
+
/** A known successful hook's continuation, bound to its admitted member. */
|
|
64
|
+
structuredContext: {
|
|
65
|
+
readonly text: string;
|
|
66
|
+
readonly memberId: string;
|
|
67
|
+
} | undefined;
|
|
68
|
+
recordStructuredContext: ((text: string, memberId: string) => Promise<void>) | undefined;
|
|
69
|
+
beginStructuredContinuation: (() => Promise<boolean>) | undefined;
|
|
63
70
|
locale: string | undefined;
|
|
64
71
|
threadId: string | undefined;
|
|
65
72
|
/** The text the turn should carry instead of the parsed message, once a transcript exists. */
|
|
@@ -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-RIRNBxUC.mjs";
|
|
8
8
|
export { InboundRequest, currentInboundRequest, runInboundRequest, withReplacedText };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type StructuredInbound, type StructuredMessage, type StructuredResult } from "./structured.js";
|
|
1
2
|
import type { RecentMessage } from "../group-routing/observed.js";
|
|
2
3
|
import { type GroupPolicy } from "../group-routing/policy.js";
|
|
3
4
|
import type { TelegramSettings } from "../../config.js";
|
|
@@ -41,6 +42,10 @@ import type { PdfTextExtractor } from "./pdf-text.js";
|
|
|
41
42
|
* its `<chat>` block.
|
|
42
43
|
*/
|
|
43
44
|
export interface InboundDependencies {
|
|
45
|
+
readonly structured?: {
|
|
46
|
+
readonly configuration: StructuredInbound;
|
|
47
|
+
readonly run: (principal: import("eve/context").SessionAuthContext, memberId: string, message: TelegramMessage, event: StructuredMessage, beforeDispatch?: () => Promise<void>) => Promise<StructuredResult>;
|
|
48
|
+
};
|
|
44
49
|
readonly policy: TelegramPolicy;
|
|
45
50
|
readonly decisionModel?: string;
|
|
46
51
|
readonly groups?: GroupPolicy;
|
|
@@ -6,14 +6,16 @@ __eveDirname(__filename);
|
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { effectiveGroupPolicy, groupPolicy } from "../group-routing/policy.mjs";
|
|
8
8
|
import { admitMessage, localizedText } from "../admission.mjs";
|
|
9
|
-
import { d as telegramRuntimeSource, n as conversationLanguage, o as telegramPrincipal, u as runtimeEnvelope } from "../../../_chunks/principal-
|
|
10
|
-
import { p as reportTelegramError } from "../../../_chunks/inbound-request-
|
|
9
|
+
import { d as telegramRuntimeSource, n as conversationLanguage, o as telegramPrincipal, u as runtimeEnvelope } from "../../../_chunks/principal-MEMlG3EG.mjs";
|
|
10
|
+
import { p as reportTelegramError } from "../../../_chunks/inbound-request-RIRNBxUC.mjs";
|
|
11
11
|
import { addressingReason, conversationKey, otherRecipient } from "../group-routing/signals.mjs";
|
|
12
12
|
import { conversationAddressing, conversationState } from "../group-routing/conversation.mjs";
|
|
13
13
|
import { questionInvitation } from "../group-routing/engagement.mjs";
|
|
14
14
|
import { conversationContext, routeMessage } from "../group-routing/router.mjs";
|
|
15
15
|
import { observedContext } from "../group-routing/observed.mjs";
|
|
16
16
|
import { debounceBurst, routingBurst } from "../group-routing/burst.mjs";
|
|
17
|
+
import { WorkspaceActionAlreadyDispatched } from "./workspace-action.mjs";
|
|
18
|
+
import { structuredMessage } from "./structured.mjs";
|
|
17
19
|
import { formatAddress, messageAddress, scopedAddress } from "./sessions.mjs";
|
|
18
20
|
import { AttachmentLifecycleNotPermitted, startTypingHeartbeat, typingUntilComplete } from "./lifecycle.mjs";
|
|
19
21
|
import { contentShape, messageContent } from "./content.mjs";
|
|
@@ -225,13 +227,14 @@ async function handleInboundMessage(input) {
|
|
|
225
227
|
from: message.from,
|
|
226
228
|
attachments: inboundAttachments(message)
|
|
227
229
|
};
|
|
230
|
+
const structured = dependencies.structured === void 0 ? void 0 : structuredMessage(sent.raw, dependencies.structured.configuration.kinds);
|
|
228
231
|
const bot = await dependencies.bot(context.telegram);
|
|
229
232
|
const audience = messageAudience(sent, bot);
|
|
230
233
|
const signals = telegramSignals(sent, bot, dependencies.signalSettings);
|
|
231
234
|
const addressed = addressingReason(signals);
|
|
232
235
|
const elsewhere = otherRecipient(audience);
|
|
233
236
|
if (input.request?.edited) {
|
|
234
|
-
if (addressed === void 0 && !input.request.attachmentsChanged && (input.request.previousText ?? "").trim().replace(/\s+/gu, " ") === audience.originalText.trim().replace(/\s+/gu, " ")) {
|
|
237
|
+
if (structured === void 0 && addressed === void 0 && !input.request.attachmentsChanged && (input.request.previousText ?? "").trim().replace(/\s+/gu, " ") === audience.originalText.trim().replace(/\s+/gu, " ")) {
|
|
235
238
|
recordGateDecision("message_edit");
|
|
236
239
|
return null;
|
|
237
240
|
}
|
|
@@ -262,7 +265,7 @@ async function handleInboundMessage(input) {
|
|
|
262
265
|
reportTelegramError("identity_notice_failed", error, { provider: "telegram" });
|
|
263
266
|
}
|
|
264
267
|
});
|
|
265
|
-
const turn = addressed !== void 0 && hasContent && (addressed !== "reply-to-bot" || elsewhere === void 0);
|
|
268
|
+
const turn = structured === void 0 && input.request?.structuredContext === void 0 && addressed !== void 0 && hasContent && (addressed !== "reply-to-bot" || elsewhere === void 0);
|
|
266
269
|
const lookup = await resolve(turn);
|
|
267
270
|
const group = isGroupChat(sent);
|
|
268
271
|
const chat = conversationKey(signals);
|
|
@@ -334,7 +337,7 @@ async function handleInboundMessage(input) {
|
|
|
334
337
|
}
|
|
335
338
|
};
|
|
336
339
|
async function reject(refused, reply) {
|
|
337
|
-
const replied = hasContent && reply && (refused.status !== "limited" || refused.notify) ? await answerUnpaired({
|
|
340
|
+
const replied = (hasContent || structured !== void 0) && reply && (refused.status !== "limited" || refused.notify) ? await answerUnpaired({
|
|
338
341
|
context,
|
|
339
342
|
message: sent,
|
|
340
343
|
lookup: refused,
|
|
@@ -357,13 +360,28 @@ async function handleInboundMessage(input) {
|
|
|
357
360
|
return null;
|
|
358
361
|
}
|
|
359
362
|
let member = lookup.member;
|
|
360
|
-
|
|
363
|
+
if (input.request?.structuredContext !== void 0 && input.request.structuredContext.memberId !== member.id) {
|
|
364
|
+
recordGateDecision("structured_context_actor_changed");
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
let turnAdmitted = turn || input.request?.structuredContext !== void 0 || !lookup.provisioned || member.roles.length !== 1 || member.roles[0] !== "member";
|
|
361
368
|
let admissionRefused = false;
|
|
369
|
+
let structuredClaimed = input.request?.structuredContext !== void 0;
|
|
362
370
|
async function admitTurn(reply) {
|
|
371
|
+
if (admissionRefused) return false;
|
|
372
|
+
if (structured !== void 0 && !structuredClaimed) {
|
|
373
|
+
if (input.request?.claimTurn !== void 0 && !await input.request.claimTurn()) {
|
|
374
|
+
admissionRefused = true;
|
|
375
|
+
recordGateDecision("message_already_handled");
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
structuredClaimed = true;
|
|
379
|
+
}
|
|
363
380
|
if (turnAdmitted) return true;
|
|
364
381
|
const admitted = await resolve(true);
|
|
365
382
|
if (admitted.status !== "existing" && admitted.status !== "created") {
|
|
366
383
|
admissionRefused = true;
|
|
384
|
+
if (structuredClaimed) await input.request?.finishClaim?.(false);
|
|
367
385
|
await reject(admitted, reply);
|
|
368
386
|
return false;
|
|
369
387
|
}
|
|
@@ -474,7 +492,7 @@ async function handleInboundMessage(input) {
|
|
|
474
492
|
].filter((n) => !!n)];
|
|
475
493
|
const freshConversation = async () => dependencies.recentConversation ? dependencies.recentConversation(sent.chat.id, sent.messageThreadId === void 0 ? void 0 : String(sent.messageThreadId)) : dependencies.observed.recent(chat);
|
|
476
494
|
let conversationRecent = conversationPolicy ? await freshConversation() : dependencies.observed.recent(chat);
|
|
477
|
-
if (conversationPolicy && input.request && input.request.lifecycleKey === void 0) {
|
|
495
|
+
if (conversationPolicy && input.request && input.request.lifecycleKey === void 0 && input.request.structuredContext === void 0) {
|
|
478
496
|
address = topicAddress;
|
|
479
497
|
input.request.address = topicAddress;
|
|
480
498
|
input.request.turnPolicy = "steer";
|
|
@@ -503,12 +521,12 @@ async function handleInboundMessage(input) {
|
|
|
503
521
|
address = pending.address || (questionSession === void 0 ? topicAddress : memberQuestionAddress);
|
|
504
522
|
input.request.address = address;
|
|
505
523
|
}
|
|
506
|
-
if (input.request?.lifecycleKey === void 0 && group && (addressed === void 0 && !answering && groups.mode === "mention" || !conversationPolicy && elsewhere !== void 0 && (addressed === void 0 || addressed === "reply-to-bot" && !recipientAnswer))) {
|
|
524
|
+
if (input.request?.lifecycleKey === void 0 && input.request?.structuredContext === void 0 && group && (addressed === void 0 && !answering && groups.mode === "mention" || !conversationPolicy && elsewhere !== void 0 && (addressed === void 0 || addressed === "reply-to-bot" && !recipientAnswer))) {
|
|
507
525
|
await recordInboundContent({
|
|
508
526
|
text,
|
|
509
527
|
decoded
|
|
510
528
|
});
|
|
511
|
-
dependencies.observed.add(chat, observedMessage(sent, text || "[attachment]", member, void 0, bot));
|
|
529
|
+
dependencies.observed.add(chat, observedMessage(sent, text || (structured === void 0 ? "[attachment]" : `[${structured.kind}]`), member, void 0, bot));
|
|
512
530
|
recordRouteDecision("observe", addressed, groups.mode, {
|
|
513
531
|
reason: elsewhere === void 0 ? "mention_policy" : "other_recipient",
|
|
514
532
|
note: elsewhere ?? "Mention policy observes unaddressed messages."
|
|
@@ -526,6 +544,9 @@ async function handleInboundMessage(input) {
|
|
|
526
544
|
const mediaPlan = voice !== void 0 || sent.attachments.length > 0 || dependencies.observed.list(chat).some((message) => (message.images?.length ?? 0) > 0) ? await dependencies.mediaPlan?.(member, owner?.id) : void 0;
|
|
527
545
|
if (voice !== void 0 && !group) await transcribeVoice(false);
|
|
528
546
|
if (voice !== void 0 && mediaPlan?.audio) notes.push("[The chat model supports audio, but this host cannot deliver native audio. The configured speech-to-text fallback was used if enabled.]");
|
|
547
|
+
if (structured !== void 0) {
|
|
548
|
+
if (text.trim() === "") text = `[${structured.kind}]`;
|
|
549
|
+
}
|
|
529
550
|
if (text.trim() === "" && sent.attachments.length === 0) {
|
|
530
551
|
console.info("[segmentstream] Telegram message has no readable content", {
|
|
531
552
|
chatId: sent.chat.id,
|
|
@@ -603,7 +624,7 @@ async function handleInboundMessage(input) {
|
|
|
603
624
|
return question;
|
|
604
625
|
};
|
|
605
626
|
let burstId;
|
|
606
|
-
if (conversationPolicy && input.request?.lifecycleKey === void 0) {
|
|
627
|
+
if (conversationPolicy && input.request?.lifecycleKey === void 0 && input.request?.structuredContext === void 0) {
|
|
607
628
|
if (voice !== void 0) await transcribeVoice(true);
|
|
608
629
|
const routingSignals = {
|
|
609
630
|
...policySignals,
|
|
@@ -644,7 +665,7 @@ async function handleInboundMessage(input) {
|
|
|
644
665
|
messagesToClassify: burst.messages
|
|
645
666
|
};
|
|
646
667
|
}
|
|
647
|
-
const route = input.request?.lifecycleKey !== void 0 ? "reply" : await routeMessage({
|
|
668
|
+
const route = input.request?.lifecycleKey !== void 0 || input.request?.structuredContext !== void 0 ? "reply" : await routeMessage({
|
|
648
669
|
chatId: sent.chat.id,
|
|
649
670
|
memberId: member.id,
|
|
650
671
|
policy: groups.mode,
|
|
@@ -728,6 +749,74 @@ async function handleInboundMessage(input) {
|
|
|
728
749
|
return conversation();
|
|
729
750
|
}
|
|
730
751
|
});
|
|
752
|
+
let structuredDispatched = false;
|
|
753
|
+
if (structured !== void 0 && dependencies.structured !== void 0) {
|
|
754
|
+
if (route === "observe" || admissionRefused) {
|
|
755
|
+
await recordInboundContent({
|
|
756
|
+
text,
|
|
757
|
+
decoded
|
|
758
|
+
});
|
|
759
|
+
if (group) dependencies.observed.add(chat, observedMessage(sent, text, member, media, bot));
|
|
760
|
+
return null;
|
|
761
|
+
}
|
|
762
|
+
if (!await admitTurn(true)) return null;
|
|
763
|
+
const retained = input.request?.structuredContext;
|
|
764
|
+
let result;
|
|
765
|
+
if (retained !== void 0) {
|
|
766
|
+
structuredDispatched = true;
|
|
767
|
+
result = { context: retained.text };
|
|
768
|
+
} else {
|
|
769
|
+
const principal = telegramPrincipal({
|
|
770
|
+
message: sent,
|
|
771
|
+
member
|
|
772
|
+
});
|
|
773
|
+
try {
|
|
774
|
+
result = await dependencies.structured.run(principal, member.id, sent, structured, async () => {
|
|
775
|
+
if (input.request?.beginDispatch !== void 0 && !await input.request.beginDispatch()) throw new WorkspaceActionAlreadyDispatched("structured_action_already_dispatched");
|
|
776
|
+
structuredDispatched = true;
|
|
777
|
+
});
|
|
778
|
+
} catch (error) {
|
|
779
|
+
try {
|
|
780
|
+
await input.request?.finishClaim?.(false);
|
|
781
|
+
} catch (cleanupError) {
|
|
782
|
+
reportTelegramError("workspace_structured_claim_release_failed", new AggregateError([error, cleanupError], "Structured action and claim cleanup failed"));
|
|
783
|
+
}
|
|
784
|
+
if (error instanceof WorkspaceActionAlreadyDispatched) {
|
|
785
|
+
recordGateDecision("message_already_handled");
|
|
786
|
+
return null;
|
|
787
|
+
}
|
|
788
|
+
throw error;
|
|
789
|
+
}
|
|
790
|
+
if (result.complete !== true && result.context?.trim()) {
|
|
791
|
+
if (input.request !== void 0) input.request.structuredContext = {
|
|
792
|
+
text: result.context,
|
|
793
|
+
memberId: member.id
|
|
794
|
+
};
|
|
795
|
+
try {
|
|
796
|
+
if (input.request?.recordStructuredContext === void 0) throw new Error("A structured continuation requires durable conversation capture.");
|
|
797
|
+
await input.request.recordStructuredContext(result.context, member.id);
|
|
798
|
+
} catch (error) {
|
|
799
|
+
reportTelegramError("workspace_structured_context_recording_failed", error);
|
|
800
|
+
}
|
|
801
|
+
} else try {
|
|
802
|
+
await input.request?.finishClaim?.(true);
|
|
803
|
+
} catch (error) {
|
|
804
|
+
reportTelegramError("workspace_structured_admission_recording_failed", error);
|
|
805
|
+
}
|
|
806
|
+
if (result.acknowledgement?.trim()) try {
|
|
807
|
+
await context.telegram.post(result.acknowledgement);
|
|
808
|
+
} catch (error) {
|
|
809
|
+
reportTelegramError("workspace_structured_ack_failed", error, {
|
|
810
|
+
chatId: sent.chat.id,
|
|
811
|
+
messageId: sent.messageId
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
recordGateDecision("workspace_structured_inbound", result.context ? "reply" : "silent");
|
|
816
|
+
if (result.complete === true || !result.context?.trim()) return null;
|
|
817
|
+
text = result.context;
|
|
818
|
+
if (input.request !== void 0) input.request.text = text;
|
|
819
|
+
}
|
|
731
820
|
if (input.request?.lifecycleKey !== void 0) recordRouteDecision("reply", addressed, groups.mode, {
|
|
732
821
|
reason: "workspace_attachment_lifecycle",
|
|
733
822
|
note: "The configured workspace action admitted this attachment task."
|
|
@@ -870,7 +959,7 @@ async function handleInboundMessage(input) {
|
|
|
870
959
|
});
|
|
871
960
|
return null;
|
|
872
961
|
}
|
|
873
|
-
if (input.request?.claimTurn !== void 0 && !await input.request.claimTurn()) {
|
|
962
|
+
if (!structuredDispatched && input.request?.claimTurn !== void 0 && !await input.request.claimTurn()) {
|
|
874
963
|
recordGateDecision("message_already_handled");
|
|
875
964
|
return null;
|
|
876
965
|
}
|
|
@@ -961,7 +1050,8 @@ async function handleInboundMessage(input) {
|
|
|
961
1050
|
}
|
|
962
1051
|
const language = conversationLanguage([text, ...dependencies.observed.recent(chat).map((message) => message.text).reverse()]);
|
|
963
1052
|
const sharedContext = group ? conversationContext(await conversation()) : void 0;
|
|
964
|
-
|
|
1053
|
+
const beginTurnDispatch = structuredDispatched ? input.request?.beginStructuredContinuation : input.request?.beginDispatch;
|
|
1054
|
+
if (beginTurnDispatch !== void 0 && !await beginTurnDispatch()) {
|
|
965
1055
|
recordGateDecision("message_already_handled");
|
|
966
1056
|
return null;
|
|
967
1057
|
}
|
|
@@ -974,7 +1064,7 @@ async function handleInboundMessage(input) {
|
|
|
974
1064
|
member,
|
|
975
1065
|
conversationLanguage: language
|
|
976
1066
|
});
|
|
977
|
-
if (conversationPolicy && input.request?.lifecycleKey === void 0) principal = {
|
|
1067
|
+
if (conversationPolicy && input.request?.lifecycleKey === void 0 && input.request?.structuredContext === void 0) principal = {
|
|
978
1068
|
...principal,
|
|
979
1069
|
attributes: {
|
|
980
1070
|
...principal.attributes,
|
|
@@ -4,12 +4,12 @@ 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 { d as telegramRuntimeSource, l as principalRuntimeSource, u as runtimeEnvelope } from "../../../_chunks/principal-
|
|
7
|
+
import { d as telegramRuntimeSource, l as principalRuntimeSource, u as runtimeEnvelope } from "../../../_chunks/principal-MEMlG3EG.mjs";
|
|
8
8
|
import { object } from "../confirmation-description.mjs";
|
|
9
|
-
import { n as currentInboundRequest, p as reportTelegramError } from "../../../_chunks/inbound-request-
|
|
9
|
+
import { n as currentInboundRequest, p as reportTelegramError } from "../../../_chunks/inbound-request-RIRNBxUC.mjs";
|
|
10
10
|
import { needsConfirmation } from "../confirmations.mjs";
|
|
11
11
|
import { OntologyActionNotPermitted, actionToolName, ontologyTools } from "../ontology-tools.mjs";
|
|
12
|
-
import { t as agentBuild } from "../../../_chunks/build-metadata-
|
|
12
|
+
import { t as agentBuild } from "../../../_chunks/build-metadata-CJlaXNhc.mjs";
|
|
13
13
|
var AttachmentLifecycleNotPermitted = class extends Error {
|
|
14
14
|
code = "attachment_lifecycle_not_permitted";
|
|
15
15
|
};
|
|
@@ -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 { p as reportTelegramError } from "../../../_chunks/inbound-request-
|
|
8
|
+
import { p as reportTelegramError } from "../../../_chunks/inbound-request-RIRNBxUC.mjs";
|
|
9
9
|
function planMedia(capabilities, descriptionModel = null) {
|
|
10
10
|
if (typeof descriptionModel === "string") return {
|
|
11
11
|
images: "describe",
|
|
@@ -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 { a as rolesOf, i as memberIdOf, n as conversationLanguage, o as telegramPrincipal, r as identityProviderOf, t as TELEGRAM_AUTHENTICATOR } from "../../../_chunks/principal-
|
|
7
|
+
import { a as rolesOf, i as memberIdOf, n as conversationLanguage, o as telegramPrincipal, r as identityProviderOf, t as TELEGRAM_AUTHENTICATOR } from "../../../_chunks/principal-MEMlG3EG.mjs";
|
|
8
8
|
export { TELEGRAM_AUTHENTICATOR, conversationLanguage, identityProviderOf, memberIdOf, rolesOf, telegramPrincipal };
|
|
@@ -4,11 +4,11 @@ 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 "../../../_chunks/principal-
|
|
7
|
+
import "../../../_chunks/principal-MEMlG3EG.mjs";
|
|
8
8
|
import { confirmationLocale } from "./confirmation-text.mjs";
|
|
9
9
|
import { splitTelegramText } from "./format.mjs";
|
|
10
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-
|
|
11
|
+
import { a as TelegramDeliveryError, l as customerMessage, o as currentLocale, p as reportTelegramError } from "../../../_chunks/inbound-request-RIRNBxUC.mjs";
|
|
12
12
|
import { agentMessage, observedChatKey } from "../group-routing/observed.mjs";
|
|
13
13
|
const SILENT_MARKERS = new Set(["[silent]", "no_reply"]);
|
|
14
14
|
function isSilentReply(text) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { WorkspaceActionHook } from "./workspace-action.js";
|
|
2
|
+
export declare const STRUCTURED_KINDS: readonly ["location", "venue", "contact"];
|
|
3
|
+
export type StructuredKind = (typeof STRUCTURED_KINDS)[number];
|
|
4
|
+
export interface StructuredInbound extends WorkspaceActionHook {
|
|
5
|
+
readonly kinds: ReadonlyArray<StructuredKind>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
const STRUCTURED_KINDS = [
|
|
8
|
+
"location",
|
|
9
|
+
"venue",
|
|
10
|
+
"contact"
|
|
11
|
+
];
|
|
12
|
+
export { STRUCTURED_KINDS };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { TelegramMessage } from "eve/channels/telegram";
|
|
2
|
+
import type { SessionAuthContext } from "eve/context";
|
|
3
|
+
import type { Environment } from "../environment.js";
|
|
4
|
+
import type { RuntimeToken } from "../runtime-token.js";
|
|
5
|
+
import type { StructuredInbound, StructuredKind } from "./structured-settings.js";
|
|
6
|
+
export { STRUCTURED_KINDS, type StructuredInbound, type StructuredKind, } from "./structured-settings.js";
|
|
7
|
+
export interface StructuredMessage {
|
|
8
|
+
readonly kind: StructuredKind;
|
|
9
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
10
|
+
}
|
|
11
|
+
export interface StructuredResult {
|
|
12
|
+
readonly acknowledgement?: string;
|
|
13
|
+
readonly context?: string;
|
|
14
|
+
readonly complete?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** Just declared provider fields, bounded to 16 KiB; unknown kinds and malformed payloads stay undispatched. */
|
|
17
|
+
export declare function structuredMessage(raw: Readonly<Record<string, unknown>>, kinds: ReadonlyArray<StructuredKind>): StructuredMessage | undefined;
|
|
18
|
+
export declare function dispatchStructuredMessage(input: {
|
|
19
|
+
readonly configuration: StructuredInbound;
|
|
20
|
+
readonly event: StructuredMessage;
|
|
21
|
+
readonly principal: SessionAuthContext;
|
|
22
|
+
readonly memberId: string;
|
|
23
|
+
readonly message: TelegramMessage;
|
|
24
|
+
readonly environment?: Environment;
|
|
25
|
+
readonly token?: RuntimeToken;
|
|
26
|
+
readonly fetch?: typeof fetch;
|
|
27
|
+
readonly beforeDispatch?: () => Promise<void>;
|
|
28
|
+
}): Promise<StructuredResult>;
|
|
@@ -0,0 +1,114 @@
|
|
|
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 { STRUCTURED_KINDS } from "./structured-settings.mjs";
|
|
8
|
+
import { d as telegramRuntimeSource, u as runtimeEnvelope } from "../../../_chunks/principal-MEMlG3EG.mjs";
|
|
9
|
+
import { workspaceAction } from "./workspace-action.mjs";
|
|
10
|
+
const record = (value) => {
|
|
11
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("Invalid structured Telegram object.");
|
|
12
|
+
return value;
|
|
13
|
+
};
|
|
14
|
+
function text(value, maximum) {
|
|
15
|
+
if (typeof value !== "string" || value.length > maximum) throw new Error("Invalid structured Telegram text field.");
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
function numeric(value, minimum, maximum, integer = false) {
|
|
19
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < minimum || value > maximum || integer && !Number.isSafeInteger(value)) throw new Error("Invalid structured Telegram number field.");
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
function location(value) {
|
|
23
|
+
const data = record(value);
|
|
24
|
+
const result = {
|
|
25
|
+
latitude: numeric(data.latitude, -90, 90),
|
|
26
|
+
longitude: numeric(data.longitude, -180, 180)
|
|
27
|
+
};
|
|
28
|
+
for (const [key, minimum, maximum, integer] of [
|
|
29
|
+
[
|
|
30
|
+
"horizontal_accuracy",
|
|
31
|
+
0,
|
|
32
|
+
1500,
|
|
33
|
+
false
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
"live_period",
|
|
37
|
+
0,
|
|
38
|
+
2 ** 31 - 1,
|
|
39
|
+
true
|
|
40
|
+
],
|
|
41
|
+
[
|
|
42
|
+
"heading",
|
|
43
|
+
1,
|
|
44
|
+
360,
|
|
45
|
+
true
|
|
46
|
+
],
|
|
47
|
+
[
|
|
48
|
+
"proximity_alert_radius",
|
|
49
|
+
0,
|
|
50
|
+
1e5,
|
|
51
|
+
true
|
|
52
|
+
]
|
|
53
|
+
]) if (data[key] !== void 0) result[key] = numeric(data[key], minimum, maximum, integer);
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
function structuredMessage(raw, kinds) {
|
|
57
|
+
for (const kind of [
|
|
58
|
+
"venue",
|
|
59
|
+
"contact",
|
|
60
|
+
"location"
|
|
61
|
+
]) {
|
|
62
|
+
if (raw[kind] === void 0) continue;
|
|
63
|
+
if (!kinds.includes(kind)) return;
|
|
64
|
+
try {
|
|
65
|
+
const input = record(raw[kind]);
|
|
66
|
+
const data = kind === "location" ? location(input) : kind === "venue" ? {
|
|
67
|
+
location: location(input.location),
|
|
68
|
+
title: text(input.title, 1024),
|
|
69
|
+
address: text(input.address, 1024)
|
|
70
|
+
} : {
|
|
71
|
+
phone_number: text(input.phone_number, 256),
|
|
72
|
+
first_name: text(input.first_name, 256)
|
|
73
|
+
};
|
|
74
|
+
if (kind === "venue") {
|
|
75
|
+
for (const key of [
|
|
76
|
+
"foursquare_id",
|
|
77
|
+
"foursquare_type",
|
|
78
|
+
"google_place_id",
|
|
79
|
+
"google_place_type"
|
|
80
|
+
]) if (input[key] !== void 0) data[key] = text(input[key], 1024);
|
|
81
|
+
}
|
|
82
|
+
if (kind === "contact") {
|
|
83
|
+
for (const [key, maximum] of [["last_name", 256], ["vcard", 16384]]) if (input[key] !== void 0) data[key] = text(input[key], maximum);
|
|
84
|
+
if (input.user_id !== void 0) data.user_id = numeric(input.user_id, 0, Number.MAX_SAFE_INTEGER, true);
|
|
85
|
+
}
|
|
86
|
+
if (new TextEncoder().encode(JSON.stringify(data)).byteLength <= 16384) return {
|
|
87
|
+
kind,
|
|
88
|
+
data
|
|
89
|
+
};
|
|
90
|
+
} catch {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function dispatchStructuredMessage(input) {
|
|
96
|
+
const source = telegramRuntimeSource(input.message);
|
|
97
|
+
const result = await workspaceAction({
|
|
98
|
+
...input,
|
|
99
|
+
input: {
|
|
100
|
+
...input.event,
|
|
101
|
+
source
|
|
102
|
+
},
|
|
103
|
+
envelope: runtimeEnvelope({
|
|
104
|
+
principal: input.principal,
|
|
105
|
+
source
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
...typeof result.acknowledgement === "string" && result.acknowledgement.trim() !== "" && result.acknowledgement.length <= 4096 ? { acknowledgement: result.acknowledgement } : {},
|
|
110
|
+
...typeof result.context === "string" && result.context.length <= 16384 ? { context: result.context } : {},
|
|
111
|
+
...typeof result.complete === "boolean" ? { complete: result.complete } : {}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export { STRUCTURED_KINDS, dispatchStructuredMessage, structuredMessage };
|
|
@@ -5,9 +5,9 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { telegramText } from "./texts.mjs";
|
|
8
|
-
import { i as memberIdOf } from "../../../_chunks/principal-
|
|
8
|
+
import { i as memberIdOf } from "../../../_chunks/principal-MEMlG3EG.mjs";
|
|
9
9
|
import { confirmationLocale } from "./confirmation-text.mjs";
|
|
10
|
-
import { c as customerCopy, d as failureText, o as currentLocale, p as reportTelegramError } from "../../../_chunks/inbound-request-
|
|
10
|
+
import { c as customerCopy, d as failureText, o as currentLocale, p as reportTelegramError } from "../../../_chunks/inbound-request-RIRNBxUC.mjs";
|
|
11
11
|
const telegramFailureEvents = {
|
|
12
12
|
async "authorization.required"(event, channel, context) {
|
|
13
13
|
if (event.candidateId !== void 0) return;
|
|
@@ -4,7 +4,7 @@ import { createRequire as __eveCreateRequire } from "node:module";
|
|
|
4
4
|
const __filename = __eveFileURLToPath(import.meta.url);
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
|
-
import { p as reportTelegramError } from "../../../_chunks/inbound-request-
|
|
7
|
+
import { p as reportTelegramError } from "../../../_chunks/inbound-request-RIRNBxUC.mjs";
|
|
8
8
|
import "../connection-proxy.mjs";
|
|
9
9
|
import { gateway, transcribe } from "ai";
|
|
10
10
|
const LABELS = {
|
|
@@ -2,6 +2,8 @@ import type { SessionAuthContext } from "eve/context";
|
|
|
2
2
|
import type { RuntimeEnvelope } from "../runtime-envelope.js";
|
|
3
3
|
import type { Environment } from "../environment.js";
|
|
4
4
|
import type { RuntimeToken } from "../runtime-token.js";
|
|
5
|
+
export declare class WorkspaceActionAlreadyDispatched extends Error {
|
|
6
|
+
}
|
|
5
7
|
export interface WorkspaceActionHook {
|
|
6
8
|
readonly entity: string;
|
|
7
9
|
readonly action: string;
|
|
@@ -18,4 +20,5 @@ export declare function workspaceAction(input: {
|
|
|
18
20
|
readonly token?: RuntimeToken;
|
|
19
21
|
readonly fetch?: typeof fetch;
|
|
20
22
|
readonly signal?: AbortSignal;
|
|
23
|
+
readonly beforeDispatch?: () => Promise<void>;
|
|
21
24
|
}): Promise<Record<string, unknown>>;
|
|
@@ -7,9 +7,15 @@ __eveCreateRequire(import.meta.url);
|
|
|
7
7
|
import { object } from "../confirmation-description.mjs";
|
|
8
8
|
import { needsConfirmation } from "../confirmations.mjs";
|
|
9
9
|
import { actionToolName, ontologyTools } from "../ontology-tools.mjs";
|
|
10
|
+
var WorkspaceActionAlreadyDispatched = class extends Error {};
|
|
10
11
|
async function workspaceAction(input) {
|
|
11
|
-
const tools = ontologyTools(input);
|
|
12
12
|
const action = actionToolName(input.configuration.entity, input.configuration.action);
|
|
13
|
+
const tools = ontologyTools({
|
|
14
|
+
...input,
|
|
15
|
+
beforeCall: async (name) => {
|
|
16
|
+
if (name === action) await input.beforeDispatch?.();
|
|
17
|
+
}
|
|
18
|
+
});
|
|
13
19
|
if (needsConfirmation(await tools.labels(input.memberId, action, input.input, input.signal))) throw new Error("A Telegram workspace hook must be a permitted routine action.");
|
|
14
20
|
if (!await tools.supportsRuntimeSource(input.memberId, input.signal)) throw new Error("A Telegram workspace hook requires the runtime-source capability.");
|
|
15
21
|
const raw = await tools.rpc(input.memberId, "tools/call", {
|
|
@@ -20,4 +26,4 @@ async function workspaceAction(input) {
|
|
|
20
26
|
if (object(envelope.validation).ok === false) throw new Error("The Telegram workspace hook rejected its event.");
|
|
21
27
|
return object(envelope.result ?? envelope);
|
|
22
28
|
}
|
|
23
|
-
export { workspaceAction };
|
|
29
|
+
export { WorkspaceActionAlreadyDispatched, workspaceAction };
|
package/dist/extension/model.mjs
CHANGED
|
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { isPreview } from "./lib/environment.mjs";
|
|
8
|
-
import { a as rolesOf } from "../_chunks/principal-
|
|
8
|
+
import { a as rolesOf } from "../_chunks/principal-MEMlG3EG.mjs";
|
|
9
9
|
import { defineDynamic } from "eve";
|
|
10
10
|
function chooseModel(input) {
|
|
11
11
|
const { choice } = input;
|
|
@@ -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 { u as runtimeEnvelope } from "../../_chunks/principal-
|
|
7
|
+
import { u as runtimeEnvelope } from "../../_chunks/principal-MEMlG3EG.mjs";
|
|
8
8
|
import { n as workflowToolResult } from "../../_chunks/workflow-serializable-DVQBWK8p.mjs";
|
|
9
9
|
import segmentstream from "../extension.mjs";
|
|
10
10
|
import { actionApproval } from "../lib/confirmations.mjs";
|
|
@@ -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 { i as memberIdOf } from "../../_chunks/principal-
|
|
7
|
+
import { i as memberIdOf } from "../../_chunks/principal-MEMlG3EG.mjs";
|
|
8
8
|
import segmentstream from "../extension.mjs";
|
|
9
9
|
import { executeDeferredTool } from "../lib/deferred-confirmations.mjs";
|
|
10
10
|
import { ontologyInspect, ontologyMetadata } from "../lib/ontology-gateway.mjs";
|
|
@@ -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 { i as memberIdOf } from "../../_chunks/principal-
|
|
7
|
+
import { i as memberIdOf } from "../../_chunks/principal-MEMlG3EG.mjs";
|
|
8
8
|
import { n as workflowToolResult } from "../../_chunks/workflow-serializable-DVQBWK8p.mjs";
|
|
9
9
|
import { pendingQuestions, questionKey } from "../lib/questions.mjs";
|
|
10
10
|
import { stringArgument } from "../lib/attachment-tools.mjs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@segmentstream/agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.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.50.
|
|
65
|
+
"@segmentstream-cloud/ontology": "0.50.1",
|
|
66
66
|
"@vercel/oidc": "^3.8.4",
|
|
67
67
|
"ai": "^7.0.128",
|
|
68
68
|
"csv-parse": "^7.0.3",
|