@segmentstream/agent 0.28.0 → 0.29.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/{build-metadata-CMmCRD8l.mjs → build-metadata-DZs-ivRD.mjs} +1 -1
- package/dist/extension/extension.d.ts +1 -1
- package/dist/extension/extension.mjs +2 -2
- package/dist/extension/lib/build-metadata.mjs +1 -1
- package/dist/extension/lib/group-routing/burst.d.ts +0 -17
- package/dist/extension/lib/group-routing/burst.mjs +1 -17
- package/dist/extension/lib/group-routing/policy.d.ts +5 -5
- package/dist/extension/lib/group-routing/policy.mjs +3 -5
- package/dist/extension/lib/telegram/adapter.mjs +1 -1
- package/dist/extension/lib/telegram/health.mjs +1 -1
- package/dist/extension/lib/telegram/inbound-request.d.ts +1 -1
- package/dist/extension/lib/telegram/inbound.mjs +1 -53
- package/dist/extension/lib/telegram/lifecycle.mjs +1 -1
- package/dist/extension/lib/telegram/turn-errors.mjs +0 -19
- package/package.json +1 -1
- package/dist/extension/hooks/group-routing.d.ts +0 -2
- package/dist/extension/hooks/group-routing.mjs +0 -10
- package/dist/extension/lib/group-routing/cancellation.d.ts +0 -4
- package/dist/extension/lib/group-routing/cancellation.mjs +0 -22
- package/dist/extension/lib/group-routing/dequeue.d.ts +0 -5
- package/dist/extension/lib/group-routing/dequeue.mjs +0 -145
|
@@ -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
|
-
var version = "0.
|
|
7
|
+
var version = "0.29.0";
|
|
8
8
|
function agentBuild(environment = process.env) {
|
|
9
9
|
return {
|
|
10
10
|
agent: version,
|
|
@@ -29,5 +29,5 @@ export { agentMessage as groupAgentMessage, type RecentMessage, type AgentMessag
|
|
|
29
29
|
export { archivedRoutingMessages } from "./lib/group-routing/routing-context.js";
|
|
30
30
|
export { replayRouterPayload } from "./lib/group-routing/replay.js";
|
|
31
31
|
export { conversationAddressing as groupConversationAddressing } from "./lib/group-routing/addressing.js";
|
|
32
|
-
export { routingBurst
|
|
32
|
+
export { routingBurst } from "./lib/group-routing/burst.js";
|
|
33
33
|
export type { TelegramTexts } from "./lib/telegram/texts.js";
|
|
@@ -13,11 +13,11 @@ import { decisionRouter, routeMessage } from "./lib/group-routing/router.mjs";
|
|
|
13
13
|
import { agentMessage } from "./lib/group-routing/messages.mjs";
|
|
14
14
|
import { archivedRoutingMessages } from "./lib/group-routing/routing-context.mjs";
|
|
15
15
|
import { replayRouterPayload } from "./lib/group-routing/replay.mjs";
|
|
16
|
-
import {
|
|
16
|
+
import { routingBurst } from "./lib/group-routing/burst.mjs";
|
|
17
17
|
import { defineExtension } from "eve/extension";
|
|
18
18
|
const extension = defineExtension({ config: configSchema });
|
|
19
19
|
const segmentstream = Object.assign(extension, {
|
|
20
20
|
model: (choice) => model(choice ?? (() => extension.config.models.chat)),
|
|
21
21
|
manifestOf
|
|
22
22
|
});
|
|
23
|
-
export { DEFAULT_ADMISSION_LIMITS, DEFAULT_DECISION_MODEL, DEFAULT_GROUP_POLICY, DEFAULT_STT_MODEL, SegmentStreamAgentConfigError, archivedRoutingMessages, chooseModel, conversationKey,
|
|
23
|
+
export { DEFAULT_ADMISSION_LIMITS, DEFAULT_DECISION_MODEL, DEFAULT_GROUP_POLICY, DEFAULT_STT_MODEL, SegmentStreamAgentConfigError, archivedRoutingMessages, chooseModel, conversationKey, segmentstream as default, segmentstream, effectiveGroupPolicy, addressingReason as groupAddressingReason, agentMessage as groupAgentMessage, conversationAddressing as groupConversationAddressing, decisionRouter as groupDecisionRouter, groupPolicy, manifestOf, model, replayRouterPayload, routeMessage as routeGroupMessage, routingBurst };
|
|
@@ -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 { t as agentBuild } from "../../_chunks/build-metadata-
|
|
7
|
+
import { t as agentBuild } from "../../_chunks/build-metadata-DZs-ivRD.mjs";
|
|
8
8
|
export { agentBuild };
|
|
@@ -9,20 +9,3 @@ export declare function routingBurst(signals: GroupMessageSignals, recent: Reado
|
|
|
9
9
|
startedAt: string;
|
|
10
10
|
latestAt: string;
|
|
11
11
|
};
|
|
12
|
-
/** Wait only inside the foreground webhook; every read checks durable, already captured messages. */
|
|
13
|
-
export declare function debounceBurst(input: {
|
|
14
|
-
signals: GroupMessageSignals;
|
|
15
|
-
policy: GroupPolicy;
|
|
16
|
-
read: () => Promise<ReadonlyArray<RecentMessage>>;
|
|
17
|
-
sleep?: (ms: number) => Promise<void>;
|
|
18
|
-
now?: () => number;
|
|
19
|
-
}): Promise<{
|
|
20
|
-
recent: readonly RecentMessage[];
|
|
21
|
-
burst: {
|
|
22
|
-
id: string;
|
|
23
|
-
superseded: boolean;
|
|
24
|
-
messages: RecentMessage[];
|
|
25
|
-
startedAt: string;
|
|
26
|
-
latestAt: string;
|
|
27
|
-
};
|
|
28
|
-
}>;
|
|
@@ -45,20 +45,4 @@ function routingBurst(signals, recent, policy) {
|
|
|
45
45
|
latestAt: rows[end].at
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
const now = input.now ?? Date.now;
|
|
50
|
-
const sleep = input.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
51
|
-
let recent = await input.read();
|
|
52
|
-
let burst = routingBurst(input.signals, recent, input.policy);
|
|
53
|
-
const deadline = Math.min(Date.parse(burst.latestAt) + input.policy.smart.engagement.burst.quietSeconds * 1e3, Date.parse(burst.startedAt) + input.policy.smart.engagement.burst.maxSeconds * 1e3);
|
|
54
|
-
if (!burst.superseded && deadline > now()) {
|
|
55
|
-
await sleep(deadline - now());
|
|
56
|
-
recent = await input.read();
|
|
57
|
-
burst = routingBurst(input.signals, recent, input.policy);
|
|
58
|
-
}
|
|
59
|
-
return {
|
|
60
|
-
recent,
|
|
61
|
-
burst
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
export { debounceBurst, routingBurst };
|
|
48
|
+
export { routingBurst };
|
|
@@ -30,8 +30,6 @@ export interface SmartPolicy {
|
|
|
30
30
|
readonly policy: "legacy" | "engaged" | "conversation";
|
|
31
31
|
readonly agentAliases: ReadonlyArray<string>;
|
|
32
32
|
readonly burst: {
|
|
33
|
-
readonly quietSeconds: number;
|
|
34
|
-
readonly maxSeconds: number;
|
|
35
33
|
readonly gapSeconds: number;
|
|
36
34
|
};
|
|
37
35
|
readonly followUpMinutes: number;
|
|
@@ -59,13 +57,15 @@ export interface GroupPolicy {
|
|
|
59
57
|
}
|
|
60
58
|
export declare function smartPolicy(input?: SmartPolicyInput, base?: SmartPolicy): SmartPolicy;
|
|
61
59
|
/**
|
|
62
|
-
* Settings of the
|
|
63
|
-
*
|
|
64
|
-
* chat's recent
|
|
60
|
+
* Settings of former SDK mechanisms: the conversation state machine's timers and per-state
|
|
61
|
+
* thresholds, and the webhook's wait for the rest of a burst. They are still accepted so that
|
|
62
|
+
* existing configurations deploy, and are ignored: the classifier reads the chat's recent
|
|
63
|
+
* messages, and a member's next message joins their active turn through eve's steering.
|
|
65
64
|
*/
|
|
66
65
|
export declare const IGNORED_GROUP_SETTINGS: {
|
|
67
66
|
readonly engagement: readonly ["idleMinutes", "humanExchangeMinutes", "humanQuestionMinutes", "inferredMaxMinutes"];
|
|
68
67
|
readonly thresholds: readonly ["continuation", "inferredContinuation", "contested", "ambient", "humanExchange"];
|
|
68
|
+
readonly burst: readonly ["quietSeconds", "maxSeconds"];
|
|
69
69
|
};
|
|
70
70
|
/** Whether a settings path names an ignored setting, in the agent, a chat or the shadow policy. */
|
|
71
71
|
export declare function ignoredGroupSetting(path: ReadonlyArray<string>): boolean;
|
|
@@ -61,11 +61,9 @@ function smartPolicy(input = {}, base) {
|
|
|
61
61
|
} : {},
|
|
62
62
|
...withoutIgnored(input.engagement, IGNORED_GROUP_SETTINGS.engagement),
|
|
63
63
|
burst: {
|
|
64
|
-
quietSeconds: 6,
|
|
65
|
-
maxSeconds: 15,
|
|
66
64
|
gapSeconds: 30,
|
|
67
65
|
...base?.engagement.burst,
|
|
68
|
-
...input.engagement?.burst
|
|
66
|
+
...withoutIgnored(input.engagement?.burst, IGNORED_GROUP_SETTINGS.burst)
|
|
69
67
|
}
|
|
70
68
|
},
|
|
71
69
|
thresholds: {
|
|
@@ -77,7 +75,6 @@ function smartPolicy(input = {}, base) {
|
|
|
77
75
|
},
|
|
78
76
|
timeoutSeconds: input.timeoutSeconds ?? base?.timeoutSeconds ?? 15
|
|
79
77
|
};
|
|
80
|
-
if (policy.engagement.burst.quietSeconds > policy.engagement.burst.maxSeconds) throw new RangeError("Burst quietSeconds must not exceed maxSeconds after inheritance.");
|
|
81
78
|
if ((conversation ? policy.instructions.length + JSON.stringify(ADDRESSEE_CRITERIA).length + 260 : policy.instructions.length + policy.criteria.observe.length + policy.criteria.reply.length) > 8e3) throw new RangeError("Group instructions and criteria must fit 8000 characters after inheritance.");
|
|
82
79
|
return policy;
|
|
83
80
|
}
|
|
@@ -94,7 +91,8 @@ const IGNORED_GROUP_SETTINGS = {
|
|
|
94
91
|
"contested",
|
|
95
92
|
"ambient",
|
|
96
93
|
"humanExchange"
|
|
97
|
-
]
|
|
94
|
+
],
|
|
95
|
+
burst: ["quietSeconds", "maxSeconds"]
|
|
98
96
|
};
|
|
99
97
|
function withoutIgnored(value, ignored) {
|
|
100
98
|
return Object.fromEntries(Object.entries(value ?? {}).filter(([key]) => !ignored.includes(key)));
|
|
@@ -23,7 +23,7 @@ import { archivedRoutingMessages } from "../group-routing/routing-context.mjs";
|
|
|
23
23
|
import { dispatchStructuredMessage, structuredMessage } from "./structured.mjs";
|
|
24
24
|
import { scopedAddress } from "./sessions.mjs";
|
|
25
25
|
import { handleWorkspaceCallback, isWorkspaceCallback } from "./callbacks.mjs";
|
|
26
|
-
import { t as agentBuild } from "../../../_chunks/build-metadata-
|
|
26
|
+
import { t as agentBuild } from "../../../_chunks/build-metadata-DZs-ivRD.mjs";
|
|
27
27
|
import { attachmentLifecycle } from "./lifecycle.mjs";
|
|
28
28
|
import { gatewayImageDescriber } from "./images.mjs";
|
|
29
29
|
import { gatewayAttachmentDescriber } from "./attachment-description.mjs";
|
|
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { runtimeRequestFailure } from "./runtime-request.mjs";
|
|
8
|
-
import { t as agentBuild } from "../../../_chunks/build-metadata-
|
|
8
|
+
import { t as agentBuild } from "../../../_chunks/build-metadata-DZs-ivRD.mjs";
|
|
9
9
|
import { GET } from "eve/channels";
|
|
10
10
|
const HEALTH_ROUTE = "/eve/v1/telegram/health";
|
|
11
11
|
function healthRoute(input) {
|
|
@@ -29,7 +29,7 @@ export declare class InboundRequest {
|
|
|
29
29
|
readonly agentDescription: () => Promise<string>;
|
|
30
30
|
readonly agentName: () => Promise<string>;
|
|
31
31
|
readonly traceId: `${string}-${string}-${string}-${string}-${string}`;
|
|
32
|
-
/** Conversation policy
|
|
32
|
+
/** Conversation policy steers the active caller's turn; Eve queues other callers. */
|
|
33
33
|
turnPolicy: "queue" | "steer";
|
|
34
34
|
edited: boolean;
|
|
35
35
|
triggeringMessageId: string | undefined;
|
|
@@ -9,10 +9,9 @@ import { admitMessage, localizedText } from "../admission.mjs";
|
|
|
9
9
|
import { d as telegramRuntimeSource, n as conversationLanguage, o as telegramPrincipal, u as runtimeEnvelope } from "../../../_chunks/principal-D99Lleae.mjs";
|
|
10
10
|
import { p as reportTelegramError } from "../../../_chunks/inbound-request-D1r0FkDI.mjs";
|
|
11
11
|
import { addressingReason, conversationKey, otherRecipient } from "../group-routing/signals.mjs";
|
|
12
|
-
import { conversationAddressing } from "../group-routing/addressing.mjs";
|
|
13
12
|
import { questionInvitation } from "../group-routing/engagement.mjs";
|
|
14
13
|
import { routeMessage } from "../group-routing/router.mjs";
|
|
15
|
-
import {
|
|
14
|
+
import { routingBurst } from "../group-routing/burst.mjs";
|
|
16
15
|
import { WorkspaceActionAlreadyDispatched } from "./workspace-action.mjs";
|
|
17
16
|
import { structuredMessage } from "./structured.mjs";
|
|
18
17
|
import { formatAddress, messageAddress, scopedAddress } from "./sessions.mjs";
|
|
@@ -495,11 +494,6 @@ async function handleInboundMessage(input) {
|
|
|
495
494
|
model: dependencies.decisionModel
|
|
496
495
|
}), conversationKey(policySignals));
|
|
497
496
|
const conversationPolicy = group && groups.smart.engagement.policy === "conversation";
|
|
498
|
-
const agentAliases = [...groups.smart.engagement.agentAliases, ...[
|
|
499
|
-
bot?.username,
|
|
500
|
-
bot?.firstName,
|
|
501
|
-
bot?.displayName
|
|
502
|
-
].filter((n) => !!n)];
|
|
503
497
|
let conversationRecent = conversationPolicy ? await recentConversation() : [];
|
|
504
498
|
if (conversationPolicy && input.request && input.request.lifecycleKey === void 0 && input.request.structuredContext === void 0) {
|
|
505
499
|
address = topicAddress;
|
|
@@ -626,7 +620,6 @@ async function handleInboundMessage(input) {
|
|
|
626
620
|
};
|
|
627
621
|
return question;
|
|
628
622
|
};
|
|
629
|
-
let burstId;
|
|
630
623
|
if (conversationPolicy && input.request?.lifecycleKey === void 0 && input.request?.structuredContext === void 0) {
|
|
631
624
|
if (voice !== void 0) await transcribeVoice(true);
|
|
632
625
|
const routingSignals = {
|
|
@@ -636,26 +629,7 @@ async function handleInboundMessage(input) {
|
|
|
636
629
|
text
|
|
637
630
|
}
|
|
638
631
|
};
|
|
639
|
-
const evidence = conversationAddressing(routingSignals, conversationRecent, groups, agentAliases);
|
|
640
|
-
if (!evidence.agent_named && !evidence.reply_to_agent && evidence.human_targets.length === 0) {
|
|
641
|
-
await recordContent({
|
|
642
|
-
text,
|
|
643
|
-
decoded
|
|
644
|
-
});
|
|
645
|
-
const refreshed = await debounceBurst({
|
|
646
|
-
signals: routingSignals,
|
|
647
|
-
policy: groups,
|
|
648
|
-
read: freshConversation
|
|
649
|
-
});
|
|
650
|
-
conversationRecent = refreshed.recent;
|
|
651
|
-
question = void 0;
|
|
652
|
-
if (refreshed.burst.superseded) {
|
|
653
|
-
recordGateDecision("burst_superseded");
|
|
654
|
-
return null;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
632
|
const burst = routingBurst(routingSignals, conversationRecent, groups);
|
|
658
|
-
burstId = burst.id;
|
|
659
633
|
const q = await conversation();
|
|
660
634
|
question = {
|
|
661
635
|
...q,
|
|
@@ -1054,32 +1028,6 @@ async function handleInboundMessage(input) {
|
|
|
1054
1028
|
chatGuidance: guidance
|
|
1055
1029
|
}
|
|
1056
1030
|
};
|
|
1057
|
-
if (conversationPolicy && input.request?.lifecycleKey === void 0 && input.request?.structuredContext === void 0) principal = {
|
|
1058
|
-
...principal,
|
|
1059
|
-
attributes: {
|
|
1060
|
-
...principal.attributes,
|
|
1061
|
-
groupRouting: JSON.stringify({
|
|
1062
|
-
policy: {
|
|
1063
|
-
...groups,
|
|
1064
|
-
chats: {}
|
|
1065
|
-
},
|
|
1066
|
-
signals: {
|
|
1067
|
-
...policySignals,
|
|
1068
|
-
message: {
|
|
1069
|
-
...policySignals.message,
|
|
1070
|
-
text
|
|
1071
|
-
}
|
|
1072
|
-
},
|
|
1073
|
-
agent: question?.agent.slice(0, 600) ?? "",
|
|
1074
|
-
agentIdentity: question?.agentIdentity,
|
|
1075
|
-
chat: question?.chat,
|
|
1076
|
-
burst_id: burstId ?? routingBurst(policySignals, conversationRecent, groups).id,
|
|
1077
|
-
message: question?.message,
|
|
1078
|
-
pendingQuestions: question?.pendingQuestions,
|
|
1079
|
-
pendingQuestionAt: asked?.meta.at
|
|
1080
|
-
})
|
|
1081
|
-
}
|
|
1082
|
-
};
|
|
1083
1031
|
return {
|
|
1084
1032
|
auth: answering && pending !== void 0 ? {
|
|
1085
1033
|
...principal,
|
|
@@ -10,7 +10,7 @@ import { n as currentInboundRequest } from "../../../_chunks/inbound-request-D1r
|
|
|
10
10
|
import { member } from "../actor.mjs";
|
|
11
11
|
import { needsConfirmation } from "../confirmations.mjs";
|
|
12
12
|
import { OntologyActionNotPermitted, actionToolName, ontologyTools } from "../ontology-tools.mjs";
|
|
13
|
-
import { t as agentBuild } from "../../../_chunks/build-metadata-
|
|
13
|
+
import { t as agentBuild } from "../../../_chunks/build-metadata-DZs-ivRD.mjs";
|
|
14
14
|
var AttachmentLifecycleNotPermitted = class extends Error {
|
|
15
15
|
code = "attachment_lifecycle_not_permitted";
|
|
16
16
|
};
|
|
@@ -9,7 +9,6 @@ import { i as memberIdOf } from "../../../_chunks/principal-D99Lleae.mjs";
|
|
|
9
9
|
import { confirmationLocale } from "./confirmation-text.mjs";
|
|
10
10
|
import { c as customerCopy, d as failureText, o as currentLocale, p as reportTelegramError, s as currentThreadId } from "../../../_chunks/inbound-request-D1r0FkDI.mjs";
|
|
11
11
|
import { recordSessionFailure } from "./conversations.mjs";
|
|
12
|
-
import { isSilentRoutingCancellation } from "../group-routing/cancellation.mjs";
|
|
13
12
|
import { modelServiceFailure } from "../model-service-failure.mjs";
|
|
14
13
|
function telegramFailureEvents(input) {
|
|
15
14
|
return {
|
|
@@ -49,15 +48,6 @@ function telegramFailureEvents(input) {
|
|
|
49
48
|
const authorizationTurn = state.authorizationCancellationTurnId;
|
|
50
49
|
delete state.authorizationCancellationTurnId;
|
|
51
50
|
if (typeof event.turnId === "string" && authorizationTurn === event.turnId) return;
|
|
52
|
-
try {
|
|
53
|
-
if (await isSilentRoutingCancellation(input.archive, context, event.turnId)) return;
|
|
54
|
-
} catch (error) {
|
|
55
|
-
reportTelegramError("routing_cancellation_lookup_failed", error, {
|
|
56
|
-
sessionId: context.session.id,
|
|
57
|
-
turnId: event.turnId
|
|
58
|
-
});
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
51
|
const errorId = reportTelegramError("turn_cancelled", event, {
|
|
62
52
|
chatId: channel.state.chatId,
|
|
63
53
|
sessionId: context.session.id,
|
|
@@ -73,15 +63,6 @@ function telegramFailureEvents(input) {
|
|
|
73
63
|
sessionId: context.session.id,
|
|
74
64
|
turnId: event.turnId
|
|
75
65
|
});
|
|
76
|
-
try {
|
|
77
|
-
if (await isSilentRoutingCancellation(input.archive, context, event.turnId)) return;
|
|
78
|
-
} catch (error) {
|
|
79
|
-
reportTelegramError("routing_failure_lookup_failed", error, {
|
|
80
|
-
sessionId: context.session.id,
|
|
81
|
-
turnId: event.turnId
|
|
82
|
-
});
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
66
|
await channel.telegram.post(failureText(errorId, modelServiceFailure(event.error) ?? "failed", confirmationLocale(context.session.auth.current, currentLocale())));
|
|
86
67
|
},
|
|
87
68
|
async "session.ended"(fact, context) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@segmentstream/agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.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",
|
|
@@ -1,10 +0,0 @@
|
|
|
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 { conversationDequeueGuard } from "../lib/group-routing/dequeue.mjs";
|
|
8
|
-
import { defineHook } from "eve/hooks";
|
|
9
|
-
var group_routing_default = defineHook({ events: { "turn.started": conversationDequeueGuard() } });
|
|
10
|
-
export { group_routing_default as default };
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { SessionContext } from "eve/context";
|
|
2
|
-
import type { Conversations } from "../conversations.js";
|
|
3
|
-
/** The durable routing verdict owns silence, including after a channel callback is replayed. */
|
|
4
|
-
export declare function isSilentRoutingCancellation(archive: Conversations, context: SessionContext, turnId: string): Promise<boolean>;
|
|
@@ -1,22 +0,0 @@
|
|
|
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
|
-
async function isSilentRoutingCancellation(archive, context, turnId) {
|
|
8
|
-
const principal = context.session.auth.current;
|
|
9
|
-
const attributes = principal?.attributes;
|
|
10
|
-
if (principal?.authenticator !== "segmentstream-telegram" || typeof attributes?.groupRouting !== "string" || attributes.chatType !== "group" && attributes.chatType !== "supergroup" || typeof attributes.chatId !== "string") return false;
|
|
11
|
-
const { events } = await archive.context({
|
|
12
|
-
provider: "telegram",
|
|
13
|
-
chatId: attributes.chatId,
|
|
14
|
-
...typeof attributes.messageThreadId === "string" ? { threadId: attributes.messageThreadId } : {},
|
|
15
|
-
limit: 200,
|
|
16
|
-
includeDecisions: true,
|
|
17
|
-
...typeof attributes.replyToMessageId === "string" ? { messageId: attributes.replyToMessageId } : {}
|
|
18
|
-
});
|
|
19
|
-
const scoped = events.filter((event) => event.provider === "telegram" && event.chatId === attributes.chatId && event.threadId === (attributes.messageThreadId ?? null) && event.sessionId === context.session.id && event.turnId === turnId && event.kind === "decision");
|
|
20
|
-
return scoped.some((event) => event.decision === "silent" && (event.reason === "burst_already_answered" || event.reason === "dequeue_observe")) || !scoped.some((event) => event.decision === "reply" && (event.reason === "burst_turn_started" || event.reason === "dequeue_reply"));
|
|
21
|
-
}
|
|
22
|
-
export { isSilentRoutingCancellation };
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { HookContext, HookEvent } from "eve/hooks";
|
|
2
|
-
import { type Conversations } from "../conversations.js";
|
|
3
|
-
import { type ConversationDecideFunction } from "./conversation-router.js";
|
|
4
|
-
/** Recheck queued callers at the durable turn boundary, before any model or business action. */
|
|
5
|
-
export declare function conversationDequeueGuard(archive?: Conversations, classifier?: ConversationDecideFunction): (event: HookEvent<"turn.started">, ctx: HookContext) => Promise<void>;
|
|
@@ -1,145 +0,0 @@
|
|
|
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 { conversationEvent, conversations } from "../conversations.mjs";
|
|
8
|
-
import { addressingReason } from "./signals.mjs";
|
|
9
|
-
import { recordedMessageSignals } from "./addressing.mjs";
|
|
10
|
-
import { conversationDecisionRouter } from "./conversation-router.mjs";
|
|
11
|
-
import { routeMessage } from "./router.mjs";
|
|
12
|
-
import { archivedRoutingMessages } from "./routing-context.mjs";
|
|
13
|
-
import { routingBurst } from "./burst.mjs";
|
|
14
|
-
import { conversationCoordinates } from "../conversation-runtime.mjs";
|
|
15
|
-
import { createHash } from "node:crypto";
|
|
16
|
-
import { decide } from "eve/ai";
|
|
17
|
-
function conversationDequeueGuard(archive = conversations(), classifier = decide) {
|
|
18
|
-
return async (event, ctx) => {
|
|
19
|
-
const auth = ctx.session.auth.current;
|
|
20
|
-
const encoded = auth?.attributes.groupRouting;
|
|
21
|
-
const coordinates = conversationCoordinates(ctx);
|
|
22
|
-
if (auth?.authenticator !== "segmentstream-telegram" || typeof encoded !== "string" || coordinates?.chatType !== "group") return;
|
|
23
|
-
try {
|
|
24
|
-
const input = JSON.parse(encoded);
|
|
25
|
-
if (input.policy.smart.engagement.policy !== "conversation") return;
|
|
26
|
-
if (input.signals.sender.externalId !== auth.subject || input.signals.conversation.externalId !== coordinates.chatId) throw new Error("Routing provenance does not match the turn caller.");
|
|
27
|
-
const events = (await archive.context({
|
|
28
|
-
provider: coordinates.provider,
|
|
29
|
-
chatId: coordinates.chatId,
|
|
30
|
-
...coordinates.threadId === null ? {} : { threadId: coordinates.threadId },
|
|
31
|
-
limit: 200,
|
|
32
|
-
includeDecisions: true
|
|
33
|
-
})).events;
|
|
34
|
-
const fence = `group-routing:burst:${createHash("sha256").update(input.burst_id).digest("hex")}`;
|
|
35
|
-
const existing = events.find((entry) => entry.eventId === fence);
|
|
36
|
-
if (existing !== void 0) {
|
|
37
|
-
if (existing.turnId !== ctx.session.turn.id) {
|
|
38
|
-
await archive.append(conversationEvent({
|
|
39
|
-
...coordinates,
|
|
40
|
-
eventId: `${fence}:duplicate:${ctx.session.turn.id}`,
|
|
41
|
-
sessionId: ctx.session.id,
|
|
42
|
-
turnId: ctx.session.turn.id,
|
|
43
|
-
messageId: input.signals.message.id,
|
|
44
|
-
kind: "decision",
|
|
45
|
-
decision: "silent",
|
|
46
|
-
reason: "burst_already_answered",
|
|
47
|
-
argsSummary: JSON.stringify({ burst_id: input.burst_id })
|
|
48
|
-
}));
|
|
49
|
-
ctx.cancel();
|
|
50
|
-
}
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
const recent = archivedRoutingMessages(events, 100);
|
|
54
|
-
const decisions = [];
|
|
55
|
-
const burst = routingBurst(input.signals, recent, input.policy);
|
|
56
|
-
const latest = burst.messages.at(-1);
|
|
57
|
-
const signals = recordedMessageSignals(latest, input.signals);
|
|
58
|
-
const claimedAddressing = addressingReason(input.signals);
|
|
59
|
-
const explicit = claimedAddressing === "mention" || claimedAddressing === "command";
|
|
60
|
-
const route = explicit ? "reply" : await routeMessage({
|
|
61
|
-
groups: input.policy,
|
|
62
|
-
signals,
|
|
63
|
-
policy: input.policy.mode,
|
|
64
|
-
chatId: coordinates.chatId,
|
|
65
|
-
memberId: input.signals.sender.externalId,
|
|
66
|
-
addressed: void 0,
|
|
67
|
-
pendingQuestionAt: input.pendingQuestionAt,
|
|
68
|
-
question: async () => ({
|
|
69
|
-
groups: input.policy,
|
|
70
|
-
signals,
|
|
71
|
-
agent: input.agent,
|
|
72
|
-
processingAt: ctx.now.toISOString(),
|
|
73
|
-
agentIdentity: input.agentIdentity,
|
|
74
|
-
chat: input.chat,
|
|
75
|
-
recent,
|
|
76
|
-
burstId: input.burst_id,
|
|
77
|
-
messagesToClassify: burst.messages,
|
|
78
|
-
pendingQuestions: input.pendingQuestions,
|
|
79
|
-
message: {
|
|
80
|
-
...input.message,
|
|
81
|
-
...latest
|
|
82
|
-
}
|
|
83
|
-
}),
|
|
84
|
-
decide: conversationDecisionRouter(classifier),
|
|
85
|
-
record: (d) => decisions.push(d)
|
|
86
|
-
});
|
|
87
|
-
const base = {
|
|
88
|
-
...coordinates,
|
|
89
|
-
sessionId: ctx.session.id,
|
|
90
|
-
turnId: ctx.session.turn.id,
|
|
91
|
-
at: ctx.now.toISOString(),
|
|
92
|
-
messageId: input.signals.message.id
|
|
93
|
-
};
|
|
94
|
-
if (route === "reply") {
|
|
95
|
-
if (await archive.append(conversationEvent({
|
|
96
|
-
...base,
|
|
97
|
-
eventId: fence,
|
|
98
|
-
kind: "decision",
|
|
99
|
-
decision: "reply",
|
|
100
|
-
reason: "burst_turn_started",
|
|
101
|
-
argsSummary: JSON.stringify({ burst_id: input.burst_id })
|
|
102
|
-
})) !== true) {
|
|
103
|
-
if (!(await archive.context({
|
|
104
|
-
provider: coordinates.provider,
|
|
105
|
-
chatId: coordinates.chatId,
|
|
106
|
-
...coordinates.threadId === null ? {} : { threadId: coordinates.threadId },
|
|
107
|
-
limit: 200,
|
|
108
|
-
includeDecisions: true
|
|
109
|
-
})).events.find((e) => e.eventId === fence && e.turnId === ctx.session.turn.id)) {
|
|
110
|
-
await archive.append(conversationEvent({
|
|
111
|
-
...base,
|
|
112
|
-
eventId: `${fence}:duplicate:${ctx.session.turn.id}`,
|
|
113
|
-
kind: "decision",
|
|
114
|
-
decision: "silent",
|
|
115
|
-
reason: "burst_already_answered",
|
|
116
|
-
argsSummary: JSON.stringify({ burst_id: input.burst_id })
|
|
117
|
-
}));
|
|
118
|
-
ctx.cancel();
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
await archive.append(conversationEvent({
|
|
124
|
-
...base,
|
|
125
|
-
eventId: `group-routing:dequeue:${ctx.session.turn.id}`,
|
|
126
|
-
kind: "decision",
|
|
127
|
-
decision: route === "reply" ? "reply" : "silent",
|
|
128
|
-
reason: explicit ? "dequeue_explicit_kept" : `dequeue_${route}`,
|
|
129
|
-
argsSummary: JSON.stringify({
|
|
130
|
-
router: decisions.at(-1)?.router,
|
|
131
|
-
burst_id: input.burst_id,
|
|
132
|
-
claimed_addressing: explicit ? claimedAddressing : void 0
|
|
133
|
-
})
|
|
134
|
-
}));
|
|
135
|
-
if (route === "observe") ctx.cancel();
|
|
136
|
-
} catch (error) {
|
|
137
|
-
console.error("[segmentstream] conversation dequeue routing failed", {
|
|
138
|
-
error,
|
|
139
|
-
sessionId: ctx.session.id
|
|
140
|
-
});
|
|
141
|
-
ctx.cancel();
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
export { conversationDequeueGuard };
|