@sider-ai/chrome-openclaw-sider 1.0.31
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 +75 -0
- package/README.zh_CN.md +108 -0
- package/dist/account-cW9SLuNu.d.ts +75 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +87 -0
- package/dist/setup-entry.d.ts +6 -0
- package/dist/setup-entry.js +11 -0
- package/dist/setup-plugin-api.d.ts +7 -0
- package/dist/setup-plugin-api.js +4 -0
- package/dist/src/account.d.ts +6 -0
- package/dist/src/account.js +260 -0
- package/dist/src/auth.d.ts +30 -0
- package/dist/src/auth.js +225 -0
- package/dist/src/channel-auto-title.d.ts +6 -0
- package/dist/src/channel-auto-title.js +102 -0
- package/dist/src/channel-builders.d.ts +105 -0
- package/dist/src/channel-builders.js +238 -0
- package/dist/src/channel-hooks.d.ts +30 -0
- package/dist/src/channel-hooks.js +380 -0
- package/dist/src/channel-monitor.d.ts +34 -0
- package/dist/src/channel-monitor.js +335 -0
- package/dist/src/channel-parts.d.ts +26 -0
- package/dist/src/channel-parts.js +32 -0
- package/dist/src/channel-relay.d.ts +117 -0
- package/dist/src/channel-relay.js +574 -0
- package/dist/src/channel-runtime.d.ts +33 -0
- package/dist/src/channel-runtime.js +138 -0
- package/dist/src/channel-send-result.d.ts +19 -0
- package/dist/src/channel-send-result.js +126 -0
- package/dist/src/channel-send.d.ts +73 -0
- package/dist/src/channel-send.js +291 -0
- package/dist/src/channel-session-model.d.ts +19 -0
- package/dist/src/channel-session-model.js +244 -0
- package/dist/src/channel-shared.d.ts +153 -0
- package/dist/src/channel-shared.js +96 -0
- package/dist/src/channel-state.d.ts +93 -0
- package/dist/src/channel-state.js +475 -0
- package/dist/src/channel-streaming.d.ts +117 -0
- package/dist/src/channel-streaming.js +681 -0
- package/dist/src/channel-types.d.ts +209 -0
- package/dist/src/channel-types.js +40 -0
- package/dist/src/channel-typing.d.ts +17 -0
- package/dist/src/channel-typing.js +79 -0
- package/dist/src/channel-util.d.ts +78 -0
- package/dist/src/channel-util.js +604 -0
- package/dist/src/channel.d.ts +14 -0
- package/dist/src/channel.js +834 -0
- package/dist/src/channel.setup.d.ts +10 -0
- package/dist/src/channel.setup.js +9 -0
- package/dist/src/config.d.ts +18 -0
- package/dist/src/config.js +38 -0
- package/dist/src/inbound-media.d.ts +37 -0
- package/dist/src/inbound-media.js +148 -0
- package/dist/src/media-upload.d.ts +87 -0
- package/dist/src/media-upload.js +1308 -0
- package/dist/src/setup-core.d.ts +72 -0
- package/dist/src/setup-core.js +343 -0
- package/dist/src/user-agent.d.ts +4 -0
- package/dist/src/user-agent.js +6 -0
- package/openclaw.plugin.json +96 -0
- package/package.json +47 -0
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
|
|
2
|
+
import { formatAuthorizationHeader, resolveSiderApiUrl } from "./auth.js";
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_MEDIA_SAVE_MAX_BYTES,
|
|
5
|
+
DEFAULT_STRUCTURED_PAYLOAD_MAX_CHARS
|
|
6
|
+
} from "./channel-types.js";
|
|
7
|
+
import { getSiderRuntime } from "./channel-runtime.js";
|
|
8
|
+
import { SIDER_CHANNEL_ID } from "./config.js";
|
|
9
|
+
import { SIDER_PLUGIN_VERSION, SIDER_USER_AGENT } from "./user-agent.js";
|
|
10
|
+
function hasFiniteNumber(value) {
|
|
11
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
12
|
+
}
|
|
13
|
+
function addUsageTotals(target, next) {
|
|
14
|
+
if (!next) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
for (const field of ["input", "output", "cacheRead", "cacheWrite", "total"]) {
|
|
18
|
+
const value = next[field];
|
|
19
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
20
|
+
target[field] = (target[field] ?? 0) + value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function hasUsageTotals(usage) {
|
|
25
|
+
if (!usage) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return hasFiniteNumber(usage.input) || hasFiniteNumber(usage.output) || hasFiniteNumber(usage.cacheRead) || hasFiniteNumber(usage.cacheWrite) || hasFiniteNumber(usage.total);
|
|
29
|
+
}
|
|
30
|
+
function firstUsageCount(...values) {
|
|
31
|
+
for (const v of values) {
|
|
32
|
+
if (typeof v === "number" && Number.isFinite(v)) {
|
|
33
|
+
return Math.max(0, v);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
function toJsonSafeValue(value) {
|
|
39
|
+
if (value === void 0) {
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(JSON.stringify(value));
|
|
44
|
+
} catch {
|
|
45
|
+
return String(value);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function clipText(text, maxChars = DEFAULT_STRUCTURED_PAYLOAD_MAX_CHARS) {
|
|
49
|
+
if (text.length <= maxChars) {
|
|
50
|
+
return text;
|
|
51
|
+
}
|
|
52
|
+
return `${text.slice(0, maxChars)}...`;
|
|
53
|
+
}
|
|
54
|
+
function appendStructuredPayloadField(payload, fieldName, value, maxChars = DEFAULT_STRUCTURED_PAYLOAD_MAX_CHARS) {
|
|
55
|
+
const safeValue = toJsonSafeValue(value);
|
|
56
|
+
if (safeValue === void 0) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
let serialized = "";
|
|
60
|
+
try {
|
|
61
|
+
serialized = JSON.stringify(safeValue);
|
|
62
|
+
} catch {
|
|
63
|
+
serialized = String(safeValue);
|
|
64
|
+
}
|
|
65
|
+
if (!serialized) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (serialized.length <= maxChars) {
|
|
69
|
+
payload[fieldName] = safeValue;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
payload[`${fieldName}_preview`] = clipText(serialized, maxChars);
|
|
73
|
+
payload[`${fieldName}_truncated`] = true;
|
|
74
|
+
}
|
|
75
|
+
function extractToolResultText(result) {
|
|
76
|
+
const record = toRecord(result);
|
|
77
|
+
const fromPartRecord = (part) => {
|
|
78
|
+
const candidateKeys = ["text", "content", "message", "output", "stdout"];
|
|
79
|
+
for (const key of candidateKeys) {
|
|
80
|
+
const value = part[key];
|
|
81
|
+
if (typeof value === "string" && value.trim()) {
|
|
82
|
+
return clipText(value.trim(), 4e3);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const nestedText = typeof part.text === "string" ? part.text : typeof part.value === "string" ? part.value : typeof part.output_text === "string" ? part.output_text : void 0;
|
|
86
|
+
if (nestedText?.trim()) {
|
|
87
|
+
return clipText(nestedText.trim(), 4e3);
|
|
88
|
+
}
|
|
89
|
+
return "";
|
|
90
|
+
};
|
|
91
|
+
const fromContentArray = (value) => {
|
|
92
|
+
if (!Array.isArray(value)) {
|
|
93
|
+
return "";
|
|
94
|
+
}
|
|
95
|
+
const chunks = [];
|
|
96
|
+
for (const item of value) {
|
|
97
|
+
if (typeof item === "string" && item.trim()) {
|
|
98
|
+
chunks.push(item.trim());
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const part = toRecord(item);
|
|
102
|
+
if (!part) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const text = fromPartRecord(part);
|
|
106
|
+
if (text) {
|
|
107
|
+
chunks.push(text);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return chunks.length > 0 ? clipText(chunks.join("\n\n"), 4e3) : "";
|
|
111
|
+
};
|
|
112
|
+
if (!record) {
|
|
113
|
+
return fromContentArray(result);
|
|
114
|
+
}
|
|
115
|
+
const direct = fromPartRecord(record);
|
|
116
|
+
if (direct) {
|
|
117
|
+
return direct;
|
|
118
|
+
}
|
|
119
|
+
const contentText = fromContentArray(record.content) || fromContentArray(record.message) || fromContentArray(record.output);
|
|
120
|
+
if (contentText) {
|
|
121
|
+
return contentText;
|
|
122
|
+
}
|
|
123
|
+
return "";
|
|
124
|
+
}
|
|
125
|
+
function collectMediaUrlStrings(value, sink, seen) {
|
|
126
|
+
if (!value) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (typeof value === "string") {
|
|
130
|
+
const trimmed = value.trim();
|
|
131
|
+
if (trimmed && !seen.has(trimmed)) {
|
|
132
|
+
seen.add(trimmed);
|
|
133
|
+
sink.push(trimmed);
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (Array.isArray(value)) {
|
|
138
|
+
for (const item of value) {
|
|
139
|
+
collectMediaUrlStrings(item, sink, seen);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function extractToolResultMediaUrls(result) {
|
|
144
|
+
const visited = [];
|
|
145
|
+
const seen = /* @__PURE__ */ new Set();
|
|
146
|
+
const record = toRecord(result);
|
|
147
|
+
if (!record) {
|
|
148
|
+
return visited;
|
|
149
|
+
}
|
|
150
|
+
const pools = [record];
|
|
151
|
+
const detailsCandidate = toRecord(record.details);
|
|
152
|
+
if (detailsCandidate) {
|
|
153
|
+
pools.push(detailsCandidate);
|
|
154
|
+
}
|
|
155
|
+
for (const pool of pools) {
|
|
156
|
+
const entry = pool;
|
|
157
|
+
collectMediaUrlStrings(entry.source, visited, seen);
|
|
158
|
+
collectMediaUrlStrings(entry.source_url, visited, seen);
|
|
159
|
+
collectMediaUrlStrings(entry.sourceUrl, visited, seen);
|
|
160
|
+
collectMediaUrlStrings(entry.source_path, visited, seen);
|
|
161
|
+
collectMediaUrlStrings(entry.sourcePath, visited, seen);
|
|
162
|
+
collectMediaUrlStrings(entry.download_url, visited, seen);
|
|
163
|
+
collectMediaUrlStrings(entry.downloadUrl, visited, seen);
|
|
164
|
+
collectMediaUrlStrings(entry.path, visited, seen);
|
|
165
|
+
const files = entry.files;
|
|
166
|
+
if (Array.isArray(files)) {
|
|
167
|
+
for (const file of files) {
|
|
168
|
+
const fileRecord = toRecord(file);
|
|
169
|
+
if (!fileRecord) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
collectMediaUrlStrings(fileRecord.source, visited, seen);
|
|
173
|
+
collectMediaUrlStrings(fileRecord.source_url, visited, seen);
|
|
174
|
+
collectMediaUrlStrings(fileRecord.sourceUrl, visited, seen);
|
|
175
|
+
collectMediaUrlStrings(fileRecord.source_path, visited, seen);
|
|
176
|
+
collectMediaUrlStrings(fileRecord.sourcePath, visited, seen);
|
|
177
|
+
collectMediaUrlStrings(fileRecord.download_url, visited, seen);
|
|
178
|
+
collectMediaUrlStrings(fileRecord.downloadUrl, visited, seen);
|
|
179
|
+
collectMediaUrlStrings(fileRecord.path, visited, seen);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return visited;
|
|
184
|
+
}
|
|
185
|
+
function toRecord(value) {
|
|
186
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
return value;
|
|
190
|
+
}
|
|
191
|
+
function getSocketCloseInfo(closeInfo) {
|
|
192
|
+
if (!closeInfo || typeof closeInfo !== "object") {
|
|
193
|
+
return {};
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
code: typeof closeInfo.code === "number" ? closeInfo.code : void 0,
|
|
197
|
+
reason: typeof closeInfo.reason === "string" ? closeInfo.reason : Buffer.isBuffer(closeInfo.reason) ? closeInfo.reason.toString("utf8") : void 0,
|
|
198
|
+
wasClean: typeof closeInfo.wasClean === "boolean" ? closeInfo.wasClean : void 0
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function describeSocketClose(closeInfo) {
|
|
202
|
+
const { code, reason, wasClean } = getSocketCloseInfo(closeInfo);
|
|
203
|
+
const parts = [];
|
|
204
|
+
if (typeof code === "number") {
|
|
205
|
+
parts.push(`code=${code}`);
|
|
206
|
+
}
|
|
207
|
+
if (typeof reason === "string" && reason) {
|
|
208
|
+
parts.push(`reason=${reason}`);
|
|
209
|
+
}
|
|
210
|
+
if (typeof wasClean === "boolean") {
|
|
211
|
+
parts.push(`clean=${wasClean}`);
|
|
212
|
+
}
|
|
213
|
+
return parts.length > 0 ? ` (${parts.join(", ")})` : "";
|
|
214
|
+
}
|
|
215
|
+
function decodeBase64AttachmentBuffer(raw) {
|
|
216
|
+
const normalized = raw.trim();
|
|
217
|
+
if (!normalized) {
|
|
218
|
+
throw new Error("sider sendAttachment requires non-empty buffer");
|
|
219
|
+
}
|
|
220
|
+
const buffer = Buffer.from(normalized, "base64");
|
|
221
|
+
if (buffer.length === 0) {
|
|
222
|
+
throw new Error("sider sendAttachment requires valid non-empty base64 buffer");
|
|
223
|
+
}
|
|
224
|
+
return buffer;
|
|
225
|
+
}
|
|
226
|
+
async function updateSiderSessionTitle(params) {
|
|
227
|
+
const sessionId = params.sessionId.trim();
|
|
228
|
+
if (!sessionId) {
|
|
229
|
+
throw new Error("sider updateSessionTitle requires non-empty sessionId");
|
|
230
|
+
}
|
|
231
|
+
const title = params.title.trim();
|
|
232
|
+
if (!title) {
|
|
233
|
+
throw new Error("sider updateSessionTitle requires non-empty title");
|
|
234
|
+
}
|
|
235
|
+
const url = resolveSiderApiUrl(`/v1/sessions/${encodeURIComponent(sessionId)}`);
|
|
236
|
+
const response = await fetch(url, {
|
|
237
|
+
method: "PATCH",
|
|
238
|
+
headers: {
|
|
239
|
+
Authorization: formatAuthorizationHeader(params.authorization),
|
|
240
|
+
"Content-Type": "application/json",
|
|
241
|
+
"User-Agent": SIDER_USER_AGENT
|
|
242
|
+
},
|
|
243
|
+
body: JSON.stringify({ title })
|
|
244
|
+
});
|
|
245
|
+
if (!response.ok) {
|
|
246
|
+
let detail = "";
|
|
247
|
+
try {
|
|
248
|
+
const text = (await response.text()).trim();
|
|
249
|
+
if (text) {
|
|
250
|
+
detail = `: ${text}`;
|
|
251
|
+
}
|
|
252
|
+
} catch {
|
|
253
|
+
}
|
|
254
|
+
throw new Error(
|
|
255
|
+
`sider updateSessionTitle failed (${response.status} ${response.statusText})${detail}`
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
async function persistInlineAttachmentBuffer(params) {
|
|
260
|
+
const configuredMaxBytes = resolveChannelMediaMaxBytes({
|
|
261
|
+
cfg: params.cfg,
|
|
262
|
+
accountId: params.accountId,
|
|
263
|
+
resolveChannelLimitMb: () => void 0
|
|
264
|
+
});
|
|
265
|
+
const maxBytes = Math.max(
|
|
266
|
+
params.buffer.length,
|
|
267
|
+
configuredMaxBytes ?? 0,
|
|
268
|
+
DEFAULT_MEDIA_SAVE_MAX_BYTES
|
|
269
|
+
);
|
|
270
|
+
return await getSiderRuntime().channel.media.saveMediaBuffer(
|
|
271
|
+
params.buffer,
|
|
272
|
+
params.contentType,
|
|
273
|
+
"outbound",
|
|
274
|
+
maxBytes,
|
|
275
|
+
params.fileName
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
function parseTextFromPart(part) {
|
|
279
|
+
if (part.type !== "core.text") {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
const payload = toRecord(part.payload);
|
|
283
|
+
if (payload?.text && typeof payload.text === "string") {
|
|
284
|
+
const text = payload.text.trim();
|
|
285
|
+
return text || null;
|
|
286
|
+
}
|
|
287
|
+
if (typeof part.payload === "string") {
|
|
288
|
+
const text = part.payload.trim();
|
|
289
|
+
return text || null;
|
|
290
|
+
}
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
function collectTextPartValues(parts) {
|
|
294
|
+
const seen = /* @__PURE__ */ new Set();
|
|
295
|
+
for (const part of parts) {
|
|
296
|
+
const text = parseTextFromPart(part);
|
|
297
|
+
if (text) {
|
|
298
|
+
seen.add(text);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return seen;
|
|
302
|
+
}
|
|
303
|
+
function filterDuplicateTextParts(params) {
|
|
304
|
+
const seenTexts = params.seenTexts ?? /* @__PURE__ */ new Set();
|
|
305
|
+
const duplicateTexts = [];
|
|
306
|
+
const parts = [];
|
|
307
|
+
for (const part of params.parts) {
|
|
308
|
+
const text = parseTextFromPart(part);
|
|
309
|
+
if (!text) {
|
|
310
|
+
parts.push(part);
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (seenTexts.has(text)) {
|
|
314
|
+
duplicateTexts.push(text);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
seenTexts.add(text);
|
|
318
|
+
parts.push(part);
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
parts,
|
|
322
|
+
duplicateTexts,
|
|
323
|
+
seenTexts
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function parseMediaFromPart(part) {
|
|
327
|
+
if (part.type !== "core.media" && part.type !== "core.file") {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
const payload = toRecord(part.payload);
|
|
331
|
+
if (!payload) {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
const readString = (value) => {
|
|
335
|
+
if (typeof value !== "string") {
|
|
336
|
+
return void 0;
|
|
337
|
+
}
|
|
338
|
+
const trimmed = value.trim();
|
|
339
|
+
return trimmed || void 0;
|
|
340
|
+
};
|
|
341
|
+
const url = readString(payload.download_url) ?? readString(payload.downloadUrl) ?? readString(payload.url) ?? readString(payload.resource_url) ?? readString(payload.resourceUrl) ?? readString(payload.media_url) ?? readString(payload.mediaUrl);
|
|
342
|
+
const objectKey = readString(payload.object_key) ?? readString(payload.objectKey);
|
|
343
|
+
const fileId = readString(payload.file_id) ?? readString(payload.fileId);
|
|
344
|
+
if (!url && !objectKey && !fileId) {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
const mimeType = readString(payload.mime) ?? readString(payload.mime_type) ?? readString(payload.mimeType) ?? readString(payload.content_type) ?? readString(payload.contentType);
|
|
348
|
+
const fileName = readString(payload.name) ?? readString(payload.file_name) ?? readString(payload.fileName);
|
|
349
|
+
return {
|
|
350
|
+
...url ? { url } : {},
|
|
351
|
+
...objectKey ? { objectKey } : {},
|
|
352
|
+
...fileId ? { fileId } : {},
|
|
353
|
+
...mimeType ? { mimeType } : {},
|
|
354
|
+
...fileName ? { fileName } : {}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function describeInboundMediaReference(item) {
|
|
358
|
+
if (item.url?.trim()) {
|
|
359
|
+
return item.url.trim();
|
|
360
|
+
}
|
|
361
|
+
if (item.objectKey?.trim()) {
|
|
362
|
+
return `sider-object-key:${item.objectKey.trim()}`;
|
|
363
|
+
}
|
|
364
|
+
if (item.fileId?.trim()) {
|
|
365
|
+
return `sider-file-id:${item.fileId.trim()}`;
|
|
366
|
+
}
|
|
367
|
+
return void 0;
|
|
368
|
+
}
|
|
369
|
+
function buildEventMeta(params) {
|
|
370
|
+
return {
|
|
371
|
+
channel: SIDER_CHANNEL_ID,
|
|
372
|
+
account_id: params.accountId,
|
|
373
|
+
plugin_version: SIDER_PLUGIN_VERSION,
|
|
374
|
+
schema_version: 1
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
function formatUsageForMessageMeta(usage) {
|
|
378
|
+
if (!hasUsageTotals(usage)) {
|
|
379
|
+
return void 0;
|
|
380
|
+
}
|
|
381
|
+
const result = {};
|
|
382
|
+
if (usage.input !== void 0) result.input = usage.input;
|
|
383
|
+
if (usage.output !== void 0) result.output = usage.output;
|
|
384
|
+
if (usage.cacheRead !== void 0) result.cache_read = usage.cacheRead;
|
|
385
|
+
if (usage.cacheWrite !== void 0) result.cache_write = usage.cacheWrite;
|
|
386
|
+
if (usage.total !== void 0) result.total = usage.total;
|
|
387
|
+
return result;
|
|
388
|
+
}
|
|
389
|
+
function parseUsageTotals(value) {
|
|
390
|
+
const record = toRecord(value);
|
|
391
|
+
if (!record) {
|
|
392
|
+
return void 0;
|
|
393
|
+
}
|
|
394
|
+
const cacheDetails = toRecord(record.prompt_tokens_details) ?? toRecord(record.promptTokensDetails);
|
|
395
|
+
const input = firstUsageCount(record.input, record.input_tokens, record.inputTokens);
|
|
396
|
+
const output = firstUsageCount(record.output, record.output_tokens, record.outputTokens);
|
|
397
|
+
const cacheRead = firstUsageCount(
|
|
398
|
+
record.cacheRead,
|
|
399
|
+
record.cache_read,
|
|
400
|
+
record.cache_read_input_tokens,
|
|
401
|
+
cacheDetails?.cached_tokens
|
|
402
|
+
);
|
|
403
|
+
const cacheWrite = firstUsageCount(
|
|
404
|
+
record.cacheWrite,
|
|
405
|
+
record.cache_write,
|
|
406
|
+
record.cache_creation_input_tokens
|
|
407
|
+
);
|
|
408
|
+
const total = firstUsageCount(record.total, record.total_tokens, record.totalTokens);
|
|
409
|
+
const usage = {};
|
|
410
|
+
if (input !== void 0) usage.input = input;
|
|
411
|
+
if (output !== void 0) usage.output = output;
|
|
412
|
+
if (cacheRead !== void 0) usage.cacheRead = cacheRead;
|
|
413
|
+
if (cacheWrite !== void 0) usage.cacheWrite = cacheWrite;
|
|
414
|
+
if (total !== void 0) {
|
|
415
|
+
usage.total = total;
|
|
416
|
+
} else if (hasUsageTotals(usage)) {
|
|
417
|
+
usage.total = (usage.input ?? 0) + (usage.output ?? 0) + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);
|
|
418
|
+
}
|
|
419
|
+
return hasUsageTotals(usage) ? usage : void 0;
|
|
420
|
+
}
|
|
421
|
+
function choosePreferredUsageTotals(...candidates) {
|
|
422
|
+
return candidates.find((c) => c && hasUsageTotals(c));
|
|
423
|
+
}
|
|
424
|
+
function parseUsageFromAssistantLike(value) {
|
|
425
|
+
const record = toRecord(value);
|
|
426
|
+
if (!record) {
|
|
427
|
+
return void 0;
|
|
428
|
+
}
|
|
429
|
+
const meta = toRecord(record.meta);
|
|
430
|
+
const agentMeta = toRecord(meta?.agentMeta) ?? toRecord(meta?.agent_meta) ?? toRecord(record.agentMeta) ?? toRecord(record.agent_meta);
|
|
431
|
+
return choosePreferredUsageTotals(
|
|
432
|
+
parseUsageTotals(record.usage),
|
|
433
|
+
parseUsageTotals(meta?.usage),
|
|
434
|
+
parseUsageTotals(meta?.lastCallUsage),
|
|
435
|
+
parseUsageTotals(meta?.last_call_usage),
|
|
436
|
+
parseUsageTotals(agentMeta?.usage),
|
|
437
|
+
parseUsageTotals(agentMeta?.lastCallUsage),
|
|
438
|
+
parseUsageTotals(agentMeta?.last_call_usage)
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
function buildMessageMeta(params) {
|
|
442
|
+
const meta = buildEventMeta({ accountId: params.accountId });
|
|
443
|
+
if (params.runState?.runId) {
|
|
444
|
+
meta.run_id = params.runState.runId;
|
|
445
|
+
}
|
|
446
|
+
if (params.runState?.provider) {
|
|
447
|
+
meta.provider = params.runState.provider;
|
|
448
|
+
}
|
|
449
|
+
if (params.runState?.model) {
|
|
450
|
+
meta.model = params.runState.model;
|
|
451
|
+
}
|
|
452
|
+
if (params.stopReason) {
|
|
453
|
+
meta.stop_reason = params.stopReason;
|
|
454
|
+
}
|
|
455
|
+
const usage = formatUsageForMessageMeta(params.runState?.usage);
|
|
456
|
+
if (usage) {
|
|
457
|
+
meta.usage = usage;
|
|
458
|
+
}
|
|
459
|
+
return meta;
|
|
460
|
+
}
|
|
461
|
+
function isAbortedAssistantStopReason(stopReason) {
|
|
462
|
+
return stopReason?.trim().toLowerCase() === "aborted";
|
|
463
|
+
}
|
|
464
|
+
function parseAssistantOutput(lastAssistant) {
|
|
465
|
+
const assistant = toRecord(lastAssistant);
|
|
466
|
+
if (!assistant) {
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
const content = Array.isArray(assistant.content) ? assistant.content : [];
|
|
470
|
+
const thinkingChunks = [];
|
|
471
|
+
const toolCalls = [];
|
|
472
|
+
const seenToolCalls = /* @__PURE__ */ new Set();
|
|
473
|
+
const pushToolCall = (candidate) => {
|
|
474
|
+
const dedupeKey = `${candidate.toolCallId?.trim() || ""}::${candidate.toolName?.trim() || ""}`;
|
|
475
|
+
if (seenToolCalls.has(dedupeKey)) {
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
seenToolCalls.add(dedupeKey);
|
|
479
|
+
toolCalls.push({
|
|
480
|
+
toolName: candidate.toolName?.trim() || void 0,
|
|
481
|
+
toolCallId: candidate.toolCallId?.trim() || void 0,
|
|
482
|
+
toolArgs: candidate.toolArgs
|
|
483
|
+
});
|
|
484
|
+
};
|
|
485
|
+
for (const item of content) {
|
|
486
|
+
const part = toRecord(item);
|
|
487
|
+
if (!part) {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
const partType = typeof part.type === "string" ? part.type.trim() : "";
|
|
491
|
+
if (partType === "thinking" || partType === "reasoning" || partType === "reasoning_text") {
|
|
492
|
+
const thinking = typeof part.thinking === "string" ? part.thinking.trim() : "";
|
|
493
|
+
const fallbackText = typeof part.text === "string" ? part.text.trim() : "";
|
|
494
|
+
const resolvedThinking = thinking || fallbackText;
|
|
495
|
+
if (resolvedThinking) {
|
|
496
|
+
thinkingChunks.push(resolvedThinking);
|
|
497
|
+
}
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (partType !== "toolCall" && partType !== "toolUse" && partType !== "tool_call" && partType !== "tool_use" && partType !== "tool-call" && partType !== "tool-use" && partType !== "functionCall" && partType !== "function_call" && partType !== "function-call" && partType !== "output_tool_call") {
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
const fn = toRecord(part.function);
|
|
504
|
+
const toolName = typeof part.toolName === "string" ? part.toolName.trim() : typeof part.name === "string" ? part.name.trim() : typeof fn?.name === "string" ? fn.name.trim() : "";
|
|
505
|
+
const toolCallId = typeof part.toolCallId === "string" ? part.toolCallId.trim() : typeof part.toolUseId === "string" ? part.toolUseId.trim() : typeof part.callId === "string" ? part.callId.trim() : typeof part.id === "string" ? part.id.trim() : void 0;
|
|
506
|
+
const rawArguments = typeof fn?.arguments === "string" ? (() => {
|
|
507
|
+
try {
|
|
508
|
+
return JSON.parse(fn.arguments);
|
|
509
|
+
} catch {
|
|
510
|
+
return fn.arguments;
|
|
511
|
+
}
|
|
512
|
+
})() : fn?.arguments;
|
|
513
|
+
pushToolCall({
|
|
514
|
+
toolName: toolName || void 0,
|
|
515
|
+
toolCallId: toolCallId || void 0,
|
|
516
|
+
toolArgs: rawArguments ?? part.arguments ?? part.input ?? part.args ?? part.parameters
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
const topLevelToolCalls = Array.isArray(assistant.tool_calls) ? assistant.tool_calls : [];
|
|
520
|
+
for (const item of topLevelToolCalls) {
|
|
521
|
+
const part = toRecord(item);
|
|
522
|
+
if (!part) {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
const fn = toRecord(part.function);
|
|
526
|
+
const rawArguments = typeof fn?.arguments === "string" ? (() => {
|
|
527
|
+
try {
|
|
528
|
+
return JSON.parse(fn.arguments);
|
|
529
|
+
} catch {
|
|
530
|
+
return fn.arguments;
|
|
531
|
+
}
|
|
532
|
+
})() : fn?.arguments;
|
|
533
|
+
pushToolCall({
|
|
534
|
+
toolName: typeof fn?.name === "string" ? fn.name : typeof part.toolName === "string" ? part.toolName : void 0,
|
|
535
|
+
toolCallId: typeof part.id === "string" ? part.id : typeof part.toolCallId === "string" ? part.toolCallId : typeof part.toolUseId === "string" ? part.toolUseId : void 0,
|
|
536
|
+
toolArgs: rawArguments ?? part.arguments ?? part.input ?? part.args ?? part.parameters
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
const stopReason = typeof assistant.stopReason === "string" ? assistant.stopReason.trim() : "";
|
|
540
|
+
const fallbackThinking = typeof assistant.reasoning_content === "string" ? assistant.reasoning_content.trim() : "";
|
|
541
|
+
return {
|
|
542
|
+
stopReason: stopReason || void 0,
|
|
543
|
+
thinkingText: thinkingChunks.join("\n\n").trim() || fallbackThinking || void 0,
|
|
544
|
+
toolCalls
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
function mergeTextSegments(previous, next) {
|
|
548
|
+
if (!next) {
|
|
549
|
+
return previous;
|
|
550
|
+
}
|
|
551
|
+
if (!previous) {
|
|
552
|
+
return next;
|
|
553
|
+
}
|
|
554
|
+
if (next === previous) {
|
|
555
|
+
return previous;
|
|
556
|
+
}
|
|
557
|
+
if (next.startsWith(previous)) {
|
|
558
|
+
return next;
|
|
559
|
+
}
|
|
560
|
+
if (previous.startsWith(next) || previous.includes(next)) {
|
|
561
|
+
return previous;
|
|
562
|
+
}
|
|
563
|
+
if (next.includes(previous)) {
|
|
564
|
+
return next;
|
|
565
|
+
}
|
|
566
|
+
const maxOverlap = Math.min(previous.length, next.length);
|
|
567
|
+
for (let overlap = maxOverlap; overlap > 0; overlap -= 1) {
|
|
568
|
+
if (previous.endsWith(next.slice(0, overlap))) {
|
|
569
|
+
return previous + next.slice(overlap);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return previous + next;
|
|
573
|
+
}
|
|
574
|
+
export {
|
|
575
|
+
addUsageTotals,
|
|
576
|
+
appendStructuredPayloadField,
|
|
577
|
+
buildEventMeta,
|
|
578
|
+
buildMessageMeta,
|
|
579
|
+
choosePreferredUsageTotals,
|
|
580
|
+
clipText,
|
|
581
|
+
collectTextPartValues,
|
|
582
|
+
decodeBase64AttachmentBuffer,
|
|
583
|
+
describeInboundMediaReference,
|
|
584
|
+
describeSocketClose,
|
|
585
|
+
extractToolResultMediaUrls,
|
|
586
|
+
extractToolResultText,
|
|
587
|
+
filterDuplicateTextParts,
|
|
588
|
+
firstUsageCount,
|
|
589
|
+
formatUsageForMessageMeta,
|
|
590
|
+
getSocketCloseInfo,
|
|
591
|
+
hasFiniteNumber,
|
|
592
|
+
hasUsageTotals,
|
|
593
|
+
isAbortedAssistantStopReason,
|
|
594
|
+
mergeTextSegments,
|
|
595
|
+
parseAssistantOutput,
|
|
596
|
+
parseMediaFromPart,
|
|
597
|
+
parseTextFromPart,
|
|
598
|
+
parseUsageFromAssistantLike,
|
|
599
|
+
parseUsageTotals,
|
|
600
|
+
persistInlineAttachmentBuffer,
|
|
601
|
+
toJsonSafeValue,
|
|
602
|
+
toRecord,
|
|
603
|
+
updateSiderSessionTitle
|
|
604
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ChannelPlugin } from 'openclaw/plugin-sdk';
|
|
2
|
+
import { R as ResolvedSiderAccount } from '../account-cW9SLuNu.js';
|
|
3
|
+
export { setSiderRuntime } from './channel-runtime.js';
|
|
4
|
+
export { emitSiderToolHookEvent, recordSiderAgentEnd, recordSiderLlmOutputUsage, recordSiderPersistedAgentMessage } from './channel-hooks.js';
|
|
5
|
+
import 'openclaw/plugin-sdk/setup';
|
|
6
|
+
import './auth.js';
|
|
7
|
+
import 'openclaw/plugin-sdk/plugin-entry';
|
|
8
|
+
import 'openclaw/plugin-sdk/config-runtime';
|
|
9
|
+
import 'ws';
|
|
10
|
+
import './channel-types.js';
|
|
11
|
+
|
|
12
|
+
declare const siderPlugin: ChannelPlugin<ResolvedSiderAccount>;
|
|
13
|
+
|
|
14
|
+
export { siderPlugin };
|