@segmentstream/agent 0.6.8 → 0.6.10
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 +18 -4
- package/dist/_chunks/conversation-runtime-ovs8IhXJ.mjs +212 -0
- package/dist/extension/hooks/conversations.mjs +1 -1
- package/dist/extension/instructions/conversations.mjs +1 -1
- package/dist/extension/lib/conversation-runtime.mjs +1 -109
- package/dist/extension/lib/conversations.d.ts +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -381,11 +381,25 @@ Apache-2.0
|
|
|
381
381
|
|
|
382
382
|
Production Telegram webhooks archive every receivable message in the platform database,
|
|
383
383
|
including automated posts and unanswered messages. The extension also records replies,
|
|
384
|
-
reply/silent decisions, tool names
|
|
384
|
+
reply/silent decisions, tool names, redacted arguments/results/errors, and
|
|
385
385
|
attachment references. It reloads stored context for the same chat/topic each turn, including
|
|
386
|
-
across cold starts and compaction. File bytes
|
|
387
|
-
|
|
388
|
-
|
|
386
|
+
across cold starts and compaction. File bytes are replaced by markers.
|
|
387
|
+
|
|
388
|
+
The Eve hook sanitizes tool arguments, results and failure messages in `argsText`,
|
|
389
|
+
`resultText` and `errorText`; ingestion re-sanitizes them. UTF-8 caps are 16/32/4 KiB, with explicit JSON
|
|
390
|
+
truncation markers. Content and argument summaries expire within 30 days of the original event
|
|
391
|
+
timestamp (clamped to server time); replay cannot renew that window after archive deletion.
|
|
392
|
+
Embedded JSON objects and arrays are sanitized recursively. Strings under text/content/body/csv/tsv
|
|
393
|
+
and file/email body fields are omitted unless they parse as JSON objects or arrays. This includes
|
|
394
|
+
all CSV/TSV documents, with or without headers. `argsSummary` keeps its pre-log semantics: the SDK
|
|
395
|
+
applies bounded credential and file-byte redaction, and ingestion preserves the supplied summary.
|
|
396
|
+
Deploy backend migration 0043/API before upgrading to agent SDK 0.6.10.
|
|
397
|
+
`segmentstream agent logs` and its `show`/`call` commands read this content
|
|
398
|
+
with a human Cloud session; all members with workspace access can read DMs too.
|
|
399
|
+
Runtime/model/MCP conversation readers never receive these new fields.
|
|
400
|
+
|
|
401
|
+
Archive metadata and message text retain the workspace policy (365 days by default).
|
|
402
|
+
Platform REST reads, the workspace ontology's
|
|
389
403
|
`chat_history` and `chat_search`, and the member REST facade enforce workspace/group
|
|
390
404
|
permissions and DM participant/admin scope. Deploy the backend migration/API and upgrade the
|
|
391
405
|
ontology SDK along with this extension. See the repository's
|
|
@@ -0,0 +1,212 @@
|
|
|
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 "../extension/lib/telegram/principal.mjs";
|
|
8
|
+
import { conversationEvent, conversations, summarizeArguments } from "../extension/lib/conversations.mjs";
|
|
9
|
+
import { parseAddress } from "../extension/lib/telegram/sessions.mjs";
|
|
10
|
+
import { completionKind } from "../extension/lib/telegram/silent.mjs";
|
|
11
|
+
const CONTENT_CAPS = {
|
|
12
|
+
args: 16384,
|
|
13
|
+
result: 32768,
|
|
14
|
+
error: 4096
|
|
15
|
+
};
|
|
16
|
+
const sensitive = /token|password|passwd|secret|authorization|cookie|credential|api.?key|private.?key|session|iban|card|cvv|ssn|email|phone|address|birth|document.?text|raw.?content|body|bytes|base64/i;
|
|
17
|
+
const encoder = new TextEncoder();
|
|
18
|
+
function luhn(value) {
|
|
19
|
+
const digits = value.replace(/\D/g, "");
|
|
20
|
+
if (digits.length < 13 || digits.length > 19) return false;
|
|
21
|
+
let sum = 0;
|
|
22
|
+
let double = false;
|
|
23
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
24
|
+
let n = Number(digits[i]);
|
|
25
|
+
if (double && (n *= 2) > 9) n -= 9;
|
|
26
|
+
sum += n;
|
|
27
|
+
double = !double;
|
|
28
|
+
}
|
|
29
|
+
return sum % 10 === 0;
|
|
30
|
+
}
|
|
31
|
+
function redactText(value) {
|
|
32
|
+
return value.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/g, "[binary data]").replace(/-----BEGIN [^-\r\n]+-----[\s\S]*?(?:-----END [^-\r\n]+-----|$)/g, "[redacted PEM]").replace(/data:[^\s"']+/gi, "[binary data]").replace(/\b(?:Bearer|Basic)\s+[A-Za-z0-9+/_=.:~\-]+/gi, "[redacted authorization]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, "[redacted JWT]").replace(/\b(?:ssw_|sscli_|sk[-_]|rk[-_])[A-Za-z0-9._~\-]+/gi, "[redacted key]").replace(/\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/gi, "$1[redacted]@").replace(/([?&](?:[^=&#\s]*(?:token|password|secret|key|signature|credential|session|auth|cookie)[^=&#\s]*|sig)=)[^&#\s"']*/gi, "$1[redacted]").replace(/((?:["']?)(?:[\w-]*(?:token|password|passwd|secret|authorization|cookie|credential|api.?key|private.?key|session|iban|card|cvv|ssn)[\w-]*)(?:["']?)\s*[:=]\s*)(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,;})]+)/gi, "$1[redacted]").replace(/\b[A-Z]{2}\d{2}(?:[ -]?[A-Z0-9]){11,30}\b/gi, "[redacted IBAN]").replace(/\b\d(?:[ -]?\d){12,18}\b/g, (candidate) => luhn(candidate) ? "[redacted card]" : candidate).replace(/[A-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[A-Z0-9](?:[A-Z0-9.-]*[A-Z0-9])?\.[A-Z]{2,}/gi, "[email]").replace(/\b\d{3}-\d{2}-\d{4}\b/g, "[redacted SSN]").replace(/\b[A-Za-z0-9+/]{128,}={0,2}/g, "[binary data]");
|
|
33
|
+
}
|
|
34
|
+
const documentField = /^(?:text|content|body|csv|tsv|file[_-]?body|email[_-]?body)$/i;
|
|
35
|
+
const omittedDocument = "[omitted: unstructured document content]";
|
|
36
|
+
function redactContent(value) {
|
|
37
|
+
const seen = new WeakSet();
|
|
38
|
+
let nodes = 0;
|
|
39
|
+
const visit = (item, depth, field) => {
|
|
40
|
+
if (++nodes > 5e3 || depth > 12) return "[omitted: content complexity]";
|
|
41
|
+
if (typeof item === "string") {
|
|
42
|
+
try {
|
|
43
|
+
const embedded = JSON.parse(item);
|
|
44
|
+
if (embedded !== null && typeof embedded === "object") return JSON.stringify(visit(embedded, depth + 1, field));
|
|
45
|
+
} catch {}
|
|
46
|
+
if (documentField.test(field ?? "")) return omittedDocument;
|
|
47
|
+
return redactText(item);
|
|
48
|
+
}
|
|
49
|
+
if (typeof item === "bigint") return item.toString();
|
|
50
|
+
if (item === null || typeof item !== "object") return item;
|
|
51
|
+
if (ArrayBuffer.isView(item) || item instanceof ArrayBuffer) return "[binary data]";
|
|
52
|
+
if (seen.has(item)) return "[omitted: circular]";
|
|
53
|
+
seen.add(item);
|
|
54
|
+
if (Array.isArray(item)) {
|
|
55
|
+
const entries = item.slice(0, 200).map((entry) => visit(entry, depth + 1, field));
|
|
56
|
+
if (item.length > 200) entries.push("[omitted: array entries]");
|
|
57
|
+
return entries;
|
|
58
|
+
}
|
|
59
|
+
const entries = Object.entries(item);
|
|
60
|
+
return Object.fromEntries([...entries.slice(0, 200).map(([key, entry]) => [redactText(key), sensitive.test(key) && !documentField.test(key) ? "[redacted]" : visit(entry, depth + 1, key)]), ...entries.length > 200 ? [["_omitted", "[omitted: object entries]"]] : []]);
|
|
61
|
+
};
|
|
62
|
+
return visit(value, 0);
|
|
63
|
+
}
|
|
64
|
+
function contentText(value, cap) {
|
|
65
|
+
if (value == null) return null;
|
|
66
|
+
let parsed = value;
|
|
67
|
+
if (typeof value === "string") try {
|
|
68
|
+
parsed = JSON.parse(value);
|
|
69
|
+
} catch {}
|
|
70
|
+
const redacted = redactContent(parsed);
|
|
71
|
+
const text = typeof redacted === "string" ? redacted : JSON.stringify(redacted) ?? "[omitted]";
|
|
72
|
+
if (encoder.encode(text).length <= cap) return text;
|
|
73
|
+
let preview = text;
|
|
74
|
+
while (true) {
|
|
75
|
+
const result = JSON.stringify({
|
|
76
|
+
truncated: true,
|
|
77
|
+
preview
|
|
78
|
+
});
|
|
79
|
+
const bytes = encoder.encode(result).length;
|
|
80
|
+
if (bytes <= cap) return result;
|
|
81
|
+
const available = Math.max(0, encoder.encode(preview).length - (bytes - cap) - 4);
|
|
82
|
+
preview = new TextDecoder().decode(encoder.encode(preview).slice(0, available), { stream: true });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function conversationCoordinates(context) {
|
|
86
|
+
const principal = context.session.auth.current;
|
|
87
|
+
const telegram = principal?.authenticator === "segmentstream-telegram" || context.channel.kind?.includes("telegram");
|
|
88
|
+
const address = context.channel.continuationToken;
|
|
89
|
+
const attributes = principal?.attributes;
|
|
90
|
+
const fields = address?.split(":");
|
|
91
|
+
const localAddress = telegram && fields?.length === 4 ? fields.slice(1).join(":") : address;
|
|
92
|
+
const parsed = telegram && localAddress !== void 0 && /^-?\d+:\d*:\d*$/u.test(localAddress) ? parseAddress(localAddress) : void 0;
|
|
93
|
+
const attributeChatId = typeof attributes?.chatId === "string" && (!telegram || /^-?\d+$/u.test(attributes.chatId)) ? attributes.chatId : void 0;
|
|
94
|
+
const chatId = telegram ? parsed?.chatId ?? attributeChatId : attributeChatId !== void 0 ? attributeChatId : address;
|
|
95
|
+
if (!chatId) return;
|
|
96
|
+
const memberId = memberIdOf(principal);
|
|
97
|
+
const chatType = attributes?.chatType;
|
|
98
|
+
return {
|
|
99
|
+
provider: telegram ? "telegram" : context.channel.kind ?? "eve",
|
|
100
|
+
chatId,
|
|
101
|
+
chatType: chatType === "group" || chatType === "supergroup" || chatType === void 0 && telegram && chatId.startsWith("-") ? "group" : chatType === "channel" ? "channel" : "private",
|
|
102
|
+
threadId: !telegram ? null : parsed !== void 0 ? parsed.messageThreadId || null : typeof attributes?.messageThreadId === "string" ? attributes.messageThreadId : null,
|
|
103
|
+
participantIds: memberId === void 0 ? [] : [memberId],
|
|
104
|
+
senderId: principal?.subject ?? null
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function conversationRecorder(archive = conversations()) {
|
|
108
|
+
return async (event, context) => {
|
|
109
|
+
const coordinates = conversationCoordinates(context);
|
|
110
|
+
if (coordinates === void 0) return;
|
|
111
|
+
const base = {
|
|
112
|
+
...coordinates,
|
|
113
|
+
sessionId: context.session.id,
|
|
114
|
+
turnId: event.data !== void 0 && "turnId" in event.data ? event.data.turnId : context.session.turn.id,
|
|
115
|
+
at: event.meta.at
|
|
116
|
+
};
|
|
117
|
+
const eventId = `eve:${context.session.id}:${event.meta.id}`;
|
|
118
|
+
if (event.type === "actions.requested") for (const action of event.data.actions) {
|
|
119
|
+
const name = "toolName" in action ? action.toolName : action.name;
|
|
120
|
+
await archive.append(conversationEvent({
|
|
121
|
+
...base,
|
|
122
|
+
eventId: `${eventId}:${action.callId}`,
|
|
123
|
+
kind: "tool_call",
|
|
124
|
+
toolCallId: action.callId,
|
|
125
|
+
toolName: name,
|
|
126
|
+
argsSummary: summarizeArguments(action.input),
|
|
127
|
+
argsText: contentText(action.input, CONTENT_CAPS.args),
|
|
128
|
+
status: "requested"
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
else if (event.type === "action.result") {
|
|
132
|
+
const result = event.data.result;
|
|
133
|
+
const name = "toolName" in result ? result.toolName : "name" in result ? result.name : result.subagentName;
|
|
134
|
+
await archive.append(conversationEvent({
|
|
135
|
+
...base,
|
|
136
|
+
eventId,
|
|
137
|
+
kind: "tool_result",
|
|
138
|
+
toolCallId: result.callId,
|
|
139
|
+
toolName: name,
|
|
140
|
+
status: event.data.status,
|
|
141
|
+
resultText: contentText("output" in result ? result.output : null, CONTENT_CAPS.result),
|
|
142
|
+
errorText: contentText(event.data.error?.message ?? (event.data.status === "failed" ? resultErrorMessage(result.output) : null), CONTENT_CAPS.error)
|
|
143
|
+
}));
|
|
144
|
+
} else if (event.type === "task.started" || event.type === "task.settled") await archive.append(conversationEvent({
|
|
145
|
+
...base,
|
|
146
|
+
eventId,
|
|
147
|
+
kind: event.type === "task.started" ? "tool_call" : "tool_result",
|
|
148
|
+
toolCallId: event.data.callId,
|
|
149
|
+
toolName: event.data.name ?? "task",
|
|
150
|
+
argsSummary: "{}",
|
|
151
|
+
...event.type === "task.settled" ? {
|
|
152
|
+
resultText: contentText(event.data.output, CONTENT_CAPS.result),
|
|
153
|
+
errorText: contentText(event.data.error?.message, CONTENT_CAPS.error)
|
|
154
|
+
} : {},
|
|
155
|
+
status: event.type === "task.started" ? "requested" : event.data.status === "cancelled" ? "cancelled" : event.data.status === "failed" ? "failed" : "completed"
|
|
156
|
+
}));
|
|
157
|
+
else if (event.type === "turn.failed" || event.type === "step.failed") await archive.append(conversationEvent({
|
|
158
|
+
...base,
|
|
159
|
+
turnId: event.data.turnId,
|
|
160
|
+
eventId,
|
|
161
|
+
kind: "decision",
|
|
162
|
+
decision: "silent",
|
|
163
|
+
reason: event.type,
|
|
164
|
+
status: "failed",
|
|
165
|
+
errorText: contentText(event.data.message, CONTENT_CAPS.error)
|
|
166
|
+
}));
|
|
167
|
+
else if (event.type === "message.completed" && event.data.finishReason !== "tool-calls") {
|
|
168
|
+
const kind = completionKind(event.data.message, event.data.finishReason);
|
|
169
|
+
const silent = kind !== "reply";
|
|
170
|
+
const note = kind === "silent_marker" ? "Model returned an explicit silence marker; no message delivery." : kind === "empty" ? "Model completed without final text; no message delivery." : kind === "whitespace" ? "Model returned only whitespace; no message delivery." : "Model produced a reply; transport delivery is recorded separately.";
|
|
171
|
+
await archive.append(conversationEvent({
|
|
172
|
+
...base,
|
|
173
|
+
eventId,
|
|
174
|
+
kind: "decision",
|
|
175
|
+
decision: silent ? "silent" : "reply",
|
|
176
|
+
reason: kind === "reply" ? "model_reply" : `model_${kind}_output`,
|
|
177
|
+
text: note,
|
|
178
|
+
argsSummary: JSON.stringify({
|
|
179
|
+
outputKind: kind,
|
|
180
|
+
outputCharacters: event.data.message?.length ?? 0,
|
|
181
|
+
finishReason: event.data.finishReason
|
|
182
|
+
})
|
|
183
|
+
}));
|
|
184
|
+
if (coordinates.provider !== "telegram" && !silent) await archive.append(conversationEvent({
|
|
185
|
+
...base,
|
|
186
|
+
eventId: `${eventId}:outbound`,
|
|
187
|
+
kind: "outbound",
|
|
188
|
+
text: event.data.message,
|
|
189
|
+
senderId: "agent",
|
|
190
|
+
senderIsBot: true,
|
|
191
|
+
status: "completed"
|
|
192
|
+
}));
|
|
193
|
+
} else if (event.type === "message.received" && coordinates.provider !== "telegram") await archive.append(conversationEvent({
|
|
194
|
+
...base,
|
|
195
|
+
eventId,
|
|
196
|
+
kind: "inbound",
|
|
197
|
+
text: event.data.message,
|
|
198
|
+
attachments: (event.data.parts ?? []).filter((part) => part.type === "file").map((part, index) => ({
|
|
199
|
+
id: `${eventId}:file:${index}`,
|
|
200
|
+
kind: "file",
|
|
201
|
+
...part.filename ? { filename: part.filename } : {},
|
|
202
|
+
contentType: part.mediaType
|
|
203
|
+
}))
|
|
204
|
+
}));
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function resultErrorMessage(output) {
|
|
208
|
+
if (typeof output === "string") return output;
|
|
209
|
+
if (output !== null && typeof output === "object" && "message" in output && typeof output.message === "string") return output.message;
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
export { conversationRecorder as n, conversationCoordinates as t };
|
|
@@ -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 { conversationRecorder } from "
|
|
7
|
+
import { n as conversationRecorder } from "../../_chunks/conversation-runtime-ovs8IhXJ.mjs";
|
|
8
8
|
import { defineHook } from "eve/hooks";
|
|
9
9
|
var conversations_default = defineHook({ events: { "*": conversationRecorder() } });
|
|
10
10
|
export { conversations_default as default };
|
|
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { conversations, storedConversationContext } from "../lib/conversations.mjs";
|
|
8
|
-
import { conversationCoordinates } from "
|
|
8
|
+
import { t as conversationCoordinates } from "../../_chunks/conversation-runtime-ovs8IhXJ.mjs";
|
|
9
9
|
import { defineDynamic, defineInstructions } from "eve/instructions";
|
|
10
10
|
const archive = conversations();
|
|
11
11
|
var conversations_default = defineDynamic({ events: { "turn.started": async (_event, context) => {
|
|
@@ -4,113 +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 {
|
|
8
|
-
import { conversationEvent, conversations, summarizeArguments } from "./conversations.mjs";
|
|
9
|
-
import { parseAddress } from "./telegram/sessions.mjs";
|
|
10
|
-
import { completionKind } from "./telegram/silent.mjs";
|
|
11
|
-
function conversationCoordinates(context) {
|
|
12
|
-
const principal = context.session.auth.current;
|
|
13
|
-
const telegram = principal?.authenticator === "segmentstream-telegram" || context.channel.kind?.includes("telegram");
|
|
14
|
-
const address = context.channel.continuationToken;
|
|
15
|
-
const attributes = principal?.attributes;
|
|
16
|
-
const fields = address?.split(":");
|
|
17
|
-
const localAddress = telegram && fields?.length === 4 ? fields.slice(1).join(":") : address;
|
|
18
|
-
const parsed = telegram && localAddress !== void 0 && /^-?\d+:\d*:\d*$/u.test(localAddress) ? parseAddress(localAddress) : void 0;
|
|
19
|
-
const attributeChatId = typeof attributes?.chatId === "string" && (!telegram || /^-?\d+$/u.test(attributes.chatId)) ? attributes.chatId : void 0;
|
|
20
|
-
const chatId = telegram ? parsed?.chatId ?? attributeChatId : attributeChatId !== void 0 ? attributeChatId : address;
|
|
21
|
-
if (!chatId) return;
|
|
22
|
-
const memberId = memberIdOf(principal);
|
|
23
|
-
const chatType = attributes?.chatType;
|
|
24
|
-
return {
|
|
25
|
-
provider: telegram ? "telegram" : context.channel.kind ?? "eve",
|
|
26
|
-
chatId,
|
|
27
|
-
chatType: chatType === "group" || chatType === "supergroup" || chatType === void 0 && telegram && chatId.startsWith("-") ? "group" : chatType === "channel" ? "channel" : "private",
|
|
28
|
-
threadId: !telegram ? null : parsed !== void 0 ? parsed.messageThreadId || null : typeof attributes?.messageThreadId === "string" ? attributes.messageThreadId : null,
|
|
29
|
-
participantIds: memberId === void 0 ? [] : [memberId],
|
|
30
|
-
senderId: principal?.subject ?? null
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
function conversationRecorder(archive = conversations()) {
|
|
34
|
-
return async (event, context) => {
|
|
35
|
-
const coordinates = conversationCoordinates(context);
|
|
36
|
-
if (coordinates === void 0) return;
|
|
37
|
-
const base = {
|
|
38
|
-
...coordinates,
|
|
39
|
-
sessionId: context.session.id,
|
|
40
|
-
turnId: context.session.turn.id,
|
|
41
|
-
at: event.meta.at
|
|
42
|
-
};
|
|
43
|
-
const eventId = `eve:${context.session.id}:${event.meta.id}`;
|
|
44
|
-
if (event.type === "actions.requested") for (const action of event.data.actions) {
|
|
45
|
-
const name = "toolName" in action ? action.toolName : action.name;
|
|
46
|
-
await archive.append(conversationEvent({
|
|
47
|
-
...base,
|
|
48
|
-
eventId: `${eventId}:${action.callId}`,
|
|
49
|
-
kind: "tool_call",
|
|
50
|
-
toolCallId: action.callId,
|
|
51
|
-
toolName: name,
|
|
52
|
-
argsSummary: summarizeArguments(action.input),
|
|
53
|
-
status: "requested"
|
|
54
|
-
}));
|
|
55
|
-
}
|
|
56
|
-
else if (event.type === "action.result") {
|
|
57
|
-
const result = event.data.result;
|
|
58
|
-
const name = "toolName" in result ? result.toolName : "name" in result ? result.name : result.kind;
|
|
59
|
-
await archive.append(conversationEvent({
|
|
60
|
-
...base,
|
|
61
|
-
eventId,
|
|
62
|
-
kind: "tool_result",
|
|
63
|
-
toolCallId: result.callId,
|
|
64
|
-
toolName: name,
|
|
65
|
-
status: event.data.status
|
|
66
|
-
}));
|
|
67
|
-
} else if (event.type === "task.started" || event.type === "task.settled") await archive.append(conversationEvent({
|
|
68
|
-
...base,
|
|
69
|
-
eventId,
|
|
70
|
-
kind: event.type === "task.started" ? "tool_call" : "tool_result",
|
|
71
|
-
toolCallId: event.data.callId,
|
|
72
|
-
toolName: event.data.name ?? "task",
|
|
73
|
-
argsSummary: "{}",
|
|
74
|
-
status: event.type === "task.started" ? "requested" : event.data.status === "cancelled" ? "cancelled" : event.data.status === "failed" ? "failed" : "completed"
|
|
75
|
-
}));
|
|
76
|
-
else if (event.type === "message.completed" && event.data.finishReason !== "tool-calls") {
|
|
77
|
-
const kind = completionKind(event.data.message, event.data.finishReason);
|
|
78
|
-
const silent = kind !== "reply";
|
|
79
|
-
const note = kind === "silent_marker" ? "Model returned an explicit silence marker; no message delivery." : kind === "empty" ? "Model completed without final text; no message delivery." : kind === "whitespace" ? "Model returned only whitespace; no message delivery." : "Model produced a reply; transport delivery is recorded separately.";
|
|
80
|
-
await archive.append(conversationEvent({
|
|
81
|
-
...base,
|
|
82
|
-
eventId,
|
|
83
|
-
kind: "decision",
|
|
84
|
-
decision: silent ? "silent" : "reply",
|
|
85
|
-
reason: kind === "reply" ? "model_reply" : `model_${kind}_output`,
|
|
86
|
-
text: note,
|
|
87
|
-
argsSummary: JSON.stringify({
|
|
88
|
-
outputKind: kind,
|
|
89
|
-
outputCharacters: event.data.message?.length ?? 0,
|
|
90
|
-
finishReason: event.data.finishReason
|
|
91
|
-
})
|
|
92
|
-
}));
|
|
93
|
-
if (coordinates.provider !== "telegram" && !silent) await archive.append(conversationEvent({
|
|
94
|
-
...base,
|
|
95
|
-
eventId: `${eventId}:outbound`,
|
|
96
|
-
kind: "outbound",
|
|
97
|
-
text: event.data.message,
|
|
98
|
-
senderId: "agent",
|
|
99
|
-
senderIsBot: true,
|
|
100
|
-
status: "completed"
|
|
101
|
-
}));
|
|
102
|
-
} else if (event.type === "message.received" && coordinates.provider !== "telegram") await archive.append(conversationEvent({
|
|
103
|
-
...base,
|
|
104
|
-
eventId,
|
|
105
|
-
kind: "inbound",
|
|
106
|
-
text: event.data.message,
|
|
107
|
-
attachments: (event.data.parts ?? []).filter((part) => part.type === "file").map((part, index) => ({
|
|
108
|
-
id: `${eventId}:file:${index}`,
|
|
109
|
-
kind: "file",
|
|
110
|
-
...part.filename ? { filename: part.filename } : {},
|
|
111
|
-
contentType: part.mediaType
|
|
112
|
-
}))
|
|
113
|
-
}));
|
|
114
|
-
};
|
|
115
|
-
}
|
|
7
|
+
import { n as conversationRecorder, t as conversationCoordinates } from "../../_chunks/conversation-runtime-ovs8IhXJ.mjs";
|
|
116
8
|
export { conversationCoordinates, conversationRecorder };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Environment } from "./environment.js";
|
|
2
2
|
import { type RuntimeToken } from "./runtime-token.js";
|
|
3
|
-
/** Provider-neutral platform archive.
|
|
3
|
+
/** Provider-neutral platform archive. Content uses the shared redaction and byte-limit policy. */
|
|
4
4
|
export interface ConversationEvent {
|
|
5
5
|
readonly eventId: string;
|
|
6
6
|
readonly provider: string;
|
|
@@ -22,6 +22,9 @@ export interface ConversationEvent {
|
|
|
22
22
|
readonly toolCallId: string | null;
|
|
23
23
|
readonly toolName: string | null;
|
|
24
24
|
readonly argsSummary: string | null;
|
|
25
|
+
readonly argsText?: string | null;
|
|
26
|
+
readonly resultText?: string | null;
|
|
27
|
+
readonly errorText?: string | null;
|
|
25
28
|
readonly status: "requested" | "completed" | "failed" | "rejected" | "cancelled" | "unknown" | "sent" | "uncertain" | null;
|
|
26
29
|
readonly operationId?: string | null;
|
|
27
30
|
readonly requestedBy?: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@segmentstream/agent",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.10",
|
|
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",
|