@segmentstream/agent 0.8.4 → 0.8.6
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 +19 -0
- package/dist/_chunks/{build-metadata-ByEgTqDs.mjs → build-metadata-BIjXU_y3.mjs} +1 -1
- package/dist/_chunks/workflow-serializable-BwttWNmY.mjs +715 -0
- package/dist/extension/lib/attachment-tables.mjs +3 -2
- package/dist/extension/lib/build-metadata.mjs +1 -1
- package/dist/extension/lib/conversations.mjs +10 -4
- package/dist/extension/lib/telegram/adapter.mjs +9 -4
- package/dist/extension/lib/telegram/confirmation-text.d.ts +2 -0
- package/dist/extension/lib/telegram/confirmation-text.mjs +6 -1
- package/dist/extension/lib/telegram/confirmations.mjs +3 -3
- package/dist/extension/lib/telegram/health.d.ts +4 -0
- package/dist/extension/lib/telegram/health.mjs +3 -2
- package/dist/extension/lib/telegram/held-approvals.d.ts +27 -0
- package/dist/extension/lib/telegram/held-approvals.mjs +51 -0
- package/dist/extension/lib/telegram/inbound-request.d.ts +1 -1
- package/dist/extension/lib/telegram/inbound.d.ts +2 -0
- package/dist/extension/lib/telegram/inbound.mjs +33 -0
- package/dist/extension/lib/telegram/lifecycle.mjs +1 -1
- package/dist/extension/lib/telegram/observed.d.ts +1 -1
- package/dist/extension/lib/telegram/sessions.d.ts +4 -0
- package/dist/extension/lib/workflow-serializable.d.ts +29 -0
- package/dist/extension/lib/workflow-serializable.mjs +8 -0
- package/dist/extension/tools/attachments_discard.d.ts +2 -24
- package/dist/extension/tools/attachments_discard.mjs +2 -1
- package/dist/extension/tools/attachments_list.d.ts +2 -24
- package/dist/extension/tools/attachments_list.mjs +3 -1
- package/dist/extension/tools/attachments_promote.d.ts +2 -28
- package/dist/extension/tools/attachments_promote.mjs +3 -2
- package/dist/extension/tools/attachments_read.mjs +3 -2
- package/dist/extension/tools/attachments_send.d.ts +1 -7
- package/dist/extension/tools/attachments_send.mjs +4 -3
- package/dist/extension/tools/attachments_table.d.ts +2 -62
- package/dist/extension/tools/attachments_table.mjs +3 -2
- package/dist/extension/tools/questions_ask.d.ts +3 -13
- package/dist/extension/tools/questions_ask.mjs +2 -1
- package/package.json +2 -2
|
@@ -0,0 +1,715 @@
|
|
|
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 { createHash, randomUUID } from "node:crypto";
|
|
8
|
+
import { Buffer as Buffer$1 } from "node:buffer";
|
|
9
|
+
import { types } from "node:util";
|
|
10
|
+
function makeRedactor(values = []) {
|
|
11
|
+
const secrets = [...new Set(values.filter((v) => typeof v === "string" && v.length > 0))].sort((a, b) => b.length - a.length);
|
|
12
|
+
return (input) => {
|
|
13
|
+
let text = input;
|
|
14
|
+
for (const value of secrets) text = text.replaceAll(value, "[REDACTED]");
|
|
15
|
+
return redactPrivateKeys(text).replace(/\bsscli_(?:access_)?v1\.[a-f0-9-]{36}\.[A-Za-z0-9_-]{43}\b/gi, "[REDACTED CLI CREDENTIAL]").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(?:sk|rk|vercel_blob_rw|vercel_blob_r|access_token|refresh_token)_[A-Za-z0-9._~-]{8,}/g, "[REDACTED]").replace(/\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/gi, "$1[REDACTED]@").replace(/([?&](?:access_token|api_key|apikey|key|password|refresh_token|secret|token|signature|sig)=)[^&#\s]*/gi, "$1[REDACTED]").replace(/((?:["']?)(?:password|passwd|credential|secret|client_secret|api_key|access_token|refresh_token|authorization|cookie|set-cookie|token)(?:["']?)\s*[:=]\s*)(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,;})]+)/gi, "$1[REDACTED]").replace(/(Key\s*\([^)]*\)\s*=\s*)\([^)]*\)/gi, "$1([REDACTED])").replace(/(invalid input syntax for [^:]+:\s*)"[^"]*"/gi, "$1[REDACTED]");
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function environmentSecrets(env) {
|
|
19
|
+
return Object.entries(env).filter(([key]) => /(?:TOKEN|SECRET|PASSWORD|PRIVATE_KEY|API_KEY|COOKIE|SIGNING_KEY|DATABASE_URL|POSTGRES_URL|GRANT)/i.test(key)).map(([, value]) => value);
|
|
20
|
+
}
|
|
21
|
+
function isSensitiveField(key) {
|
|
22
|
+
return /password|passwd|credential|secret|token|authorization|cookie|private[_-]?key|api[_-]?key|grant/i.test(key);
|
|
23
|
+
}
|
|
24
|
+
function redactPrivateKeys(text) {
|
|
25
|
+
const begin = /-----BEGIN [^-]*PRIVATE KEY-----/g;
|
|
26
|
+
const end = /-----END [^-]*PRIVATE KEY-----/g;
|
|
27
|
+
const parts = [];
|
|
28
|
+
let copiedThrough = 0;
|
|
29
|
+
let opening;
|
|
30
|
+
while ((opening = begin.exec(text)) !== null) {
|
|
31
|
+
end.lastIndex = begin.lastIndex;
|
|
32
|
+
if (end.exec(text) === null) break;
|
|
33
|
+
parts.push(text.slice(copiedThrough, opening.index), "[REDACTED PRIVATE KEY]");
|
|
34
|
+
copiedThrough = end.lastIndex;
|
|
35
|
+
begin.lastIndex = copiedThrough;
|
|
36
|
+
}
|
|
37
|
+
parts.push(text.slice(copiedThrough));
|
|
38
|
+
return parts.join("");
|
|
39
|
+
}
|
|
40
|
+
const failureRedactions = new WeakMap();
|
|
41
|
+
const MAX_BYTES = 1048576;
|
|
42
|
+
const MAX_NODES = 1024;
|
|
43
|
+
const FIELDS = [
|
|
44
|
+
"fiberId",
|
|
45
|
+
"code",
|
|
46
|
+
"status",
|
|
47
|
+
"statusCode",
|
|
48
|
+
"provider",
|
|
49
|
+
"providerCode",
|
|
50
|
+
"providerRequestId",
|
|
51
|
+
"method",
|
|
52
|
+
"host",
|
|
53
|
+
"path",
|
|
54
|
+
"retryable",
|
|
55
|
+
"constraint",
|
|
56
|
+
"sqlState",
|
|
57
|
+
"field",
|
|
58
|
+
"expected",
|
|
59
|
+
"actual",
|
|
60
|
+
"setting",
|
|
61
|
+
"resourceId",
|
|
62
|
+
"runtimeAttemptId",
|
|
63
|
+
"sandboxId",
|
|
64
|
+
"sessionId",
|
|
65
|
+
"remoteErrorId",
|
|
66
|
+
"endpoint",
|
|
67
|
+
"requestId",
|
|
68
|
+
"providerMessage",
|
|
69
|
+
"providerDescription",
|
|
70
|
+
"stderr",
|
|
71
|
+
"exitCode"
|
|
72
|
+
];
|
|
73
|
+
const links = Symbol.for("segmentstream.diagnostic.links");
|
|
74
|
+
const incomplete = Symbol.for("segmentstream.diagnostic.omissions");
|
|
75
|
+
const RELATIONS = [
|
|
76
|
+
"cause",
|
|
77
|
+
"aggregate",
|
|
78
|
+
"primary",
|
|
79
|
+
"cleanup",
|
|
80
|
+
"concurrent"
|
|
81
|
+
];
|
|
82
|
+
const MAX_EDGES = 8192;
|
|
83
|
+
function property(value, key) {
|
|
84
|
+
if ((typeof value !== "object" || value === null) && typeof value !== "function") return void 0;
|
|
85
|
+
try {
|
|
86
|
+
return Reflect.get(value, key);
|
|
87
|
+
} catch {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function scalar(value) {
|
|
92
|
+
return typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
|
|
93
|
+
}
|
|
94
|
+
function ownValues(value) {
|
|
95
|
+
if (!value || typeof value !== "object") return [];
|
|
96
|
+
try {
|
|
97
|
+
return Object.values(Object.getOwnPropertyDescriptors(value)).filter((descriptor) => "value" in descriptor).map((descriptor) => descriptor.value);
|
|
98
|
+
} catch {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function schemaInputRedactions(root) {
|
|
103
|
+
const values = new Set();
|
|
104
|
+
const seen = new Set();
|
|
105
|
+
const errors = [root];
|
|
106
|
+
const issues = [];
|
|
107
|
+
let limited = false;
|
|
108
|
+
let traversed = 0;
|
|
109
|
+
while (errors.length && seen.size < MAX_NODES) {
|
|
110
|
+
if (++traversed > MAX_EDGES || errors.length > MAX_EDGES) {
|
|
111
|
+
limited = true;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
const value = errors.shift();
|
|
115
|
+
if (seen.has(value)) continue;
|
|
116
|
+
seen.add(value);
|
|
117
|
+
if (value !== null && (typeof value === "object" || typeof value === "function")) {
|
|
118
|
+
for (const secret of failureRedactions.get(value) ?? []) if (secret) values.add(secret);
|
|
119
|
+
}
|
|
120
|
+
if (property(value, "_tag") === "SchemaError" || property(value, "name") === "SchemaError") issues.push(property(value, "issue"));
|
|
121
|
+
const explicit = property(value, links);
|
|
122
|
+
if (Array.isArray(explicit)) {
|
|
123
|
+
if (explicit.length > MAX_NODES) limited = true;
|
|
124
|
+
errors.push(...explicit.slice(0, MAX_NODES).map((item) => property(item, "error")));
|
|
125
|
+
}
|
|
126
|
+
const cause = property(value, "cause");
|
|
127
|
+
if (cause !== void 0) errors.push(cause);
|
|
128
|
+
const aggregate = property(value, "errors");
|
|
129
|
+
if (property(value, "name") === "AggregateError" && Array.isArray(aggregate)) {
|
|
130
|
+
if (aggregate.length > MAX_NODES) limited = true;
|
|
131
|
+
errors.push(...aggregate.slice(0, MAX_NODES));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (errors.length) limited = true;
|
|
135
|
+
seen.clear();
|
|
136
|
+
const inputs = [];
|
|
137
|
+
while (issues.length && seen.size < MAX_NODES) {
|
|
138
|
+
if (++traversed > MAX_EDGES || issues.length > MAX_EDGES) {
|
|
139
|
+
limited = true;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
const issue = issues.pop();
|
|
143
|
+
if (!issue || seen.has(issue)) continue;
|
|
144
|
+
seen.add(issue);
|
|
145
|
+
for (const key of ["input", "actual"]) {
|
|
146
|
+
const input = property(issue, key);
|
|
147
|
+
if (input !== void 0) inputs.push(input);
|
|
148
|
+
}
|
|
149
|
+
const child = property(issue, "issue");
|
|
150
|
+
if (child !== void 0) issues.push(child);
|
|
151
|
+
const children = property(issue, "issues");
|
|
152
|
+
if (Array.isArray(children)) {
|
|
153
|
+
if (children.length > MAX_NODES) limited = true;
|
|
154
|
+
issues.push(...children.slice(0, MAX_NODES));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (issues.length) limited = true;
|
|
158
|
+
seen.clear();
|
|
159
|
+
let characters = 0;
|
|
160
|
+
while (inputs.length && seen.size < 4096 && characters < MAX_BYTES) {
|
|
161
|
+
if (++traversed > MAX_EDGES || inputs.length > MAX_EDGES) {
|
|
162
|
+
limited = true;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
const value = inputs.pop();
|
|
166
|
+
if (seen.has(value)) continue;
|
|
167
|
+
seen.add(value);
|
|
168
|
+
if (scalar(value) && String(value)) {
|
|
169
|
+
const text = String(value);
|
|
170
|
+
characters += text.length;
|
|
171
|
+
values.add(text);
|
|
172
|
+
if (typeof value === "string") values.add(JSON.stringify(value).slice(1, -1));
|
|
173
|
+
} else {
|
|
174
|
+
const children = ownValues(value);
|
|
175
|
+
if (children.length > 4096) limited = true;
|
|
176
|
+
inputs.push(...children.slice(0, 4096));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (inputs.length) limited = true;
|
|
180
|
+
return {
|
|
181
|
+
values: [...values],
|
|
182
|
+
limited
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function createFailureReport(error, options) {
|
|
186
|
+
const schemaInputs = schemaInputRedactions(error);
|
|
187
|
+
if (schemaInputs.limited) return redactionLimitReport();
|
|
188
|
+
const redact = makeRedactor([...options.redactedValues ?? [], ...schemaInputs.values]);
|
|
189
|
+
let remaining = 1044480;
|
|
190
|
+
const omissions = new Set();
|
|
191
|
+
const clean = (value) => {
|
|
192
|
+
const safe = redact(value.slice(0, MAX_BYTES));
|
|
193
|
+
if (value.length > MAX_BYTES) omissions.add("field input exceeded 1 MiB");
|
|
194
|
+
const bytes = Buffer.from(JSON.stringify(safe));
|
|
195
|
+
const allowance = Math.max(0, remaining);
|
|
196
|
+
if (bytes.length > allowance) {
|
|
197
|
+
omissions.add("report exceeded 1 MiB");
|
|
198
|
+
remaining = 0;
|
|
199
|
+
let low = 0;
|
|
200
|
+
let high = safe.length;
|
|
201
|
+
while (low < high) {
|
|
202
|
+
const middle = Math.ceil((low + high) / 2);
|
|
203
|
+
if (Buffer.byteLength(JSON.stringify(safe.slice(0, middle))) + 20 <= allowance) low = middle;
|
|
204
|
+
else high = middle - 1;
|
|
205
|
+
}
|
|
206
|
+
return safe.slice(0, low).replace(/[\uD800-\uDBFF]$/, "") + " [TRUNCATED]";
|
|
207
|
+
}
|
|
208
|
+
remaining -= bytes.length;
|
|
209
|
+
return safe;
|
|
210
|
+
};
|
|
211
|
+
const report = {
|
|
212
|
+
version: 1,
|
|
213
|
+
errorId: options.errorId && /^[A-Za-z0-9_.:-]{1,200}$/.test(options.errorId) ? options.errorId : `err_${randomUUID().replaceAll("-", "")}`,
|
|
214
|
+
timestamp: options.timestamp?.slice(0, 100) ?? new Date().toISOString(),
|
|
215
|
+
service: clean(options.service),
|
|
216
|
+
context: {},
|
|
217
|
+
roots: [],
|
|
218
|
+
nodes: [],
|
|
219
|
+
complete: true,
|
|
220
|
+
omissions: []
|
|
221
|
+
};
|
|
222
|
+
const contextEntries = Object.entries(options.context ?? {});
|
|
223
|
+
if (contextEntries.length > 128) omissions.add("context exceeded 128 fields");
|
|
224
|
+
for (const [key, value] of contextEntries.slice(0, 128)) if (scalar(value)) report.context[clean(key)] = isSensitiveField(key) ? "[REDACTED]" : typeof value === "string" ? clean(value) : value;
|
|
225
|
+
const seen = new Map();
|
|
226
|
+
const queue = [];
|
|
227
|
+
const add = (value) => {
|
|
228
|
+
const object = typeof value === "object" && value !== null || typeof value === "function";
|
|
229
|
+
if (object && seen.has(value)) return seen.get(value);
|
|
230
|
+
if (queue.length >= MAX_NODES || remaining < 1024) {
|
|
231
|
+
omissions.add(queue.length >= MAX_NODES ? "report exceeded 1024 nodes" : "report exceeded 1 MiB");
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const id = `n${queue.length + 1}`;
|
|
235
|
+
if (object) seen.set(value, id);
|
|
236
|
+
queue.push({
|
|
237
|
+
value,
|
|
238
|
+
id
|
|
239
|
+
});
|
|
240
|
+
remaining -= 512;
|
|
241
|
+
return id;
|
|
242
|
+
};
|
|
243
|
+
const root = add(error);
|
|
244
|
+
if (root) report.roots.push(root);
|
|
245
|
+
let edges = 0;
|
|
246
|
+
for (let index = 0; index < queue.length; index++) {
|
|
247
|
+
const { value, id } = queue[index];
|
|
248
|
+
const inheritedOmissions = property(value, incomplete);
|
|
249
|
+
if (Array.isArray(inheritedOmissions)) {
|
|
250
|
+
for (const reason of inheritedOmissions.slice(0, 128)) if (typeof reason === "string") omissions.add(clean(reason));
|
|
251
|
+
}
|
|
252
|
+
const name = property(value, "_tag") ?? property(value, "name");
|
|
253
|
+
const message = property(value, "message");
|
|
254
|
+
const node = {
|
|
255
|
+
id,
|
|
256
|
+
type: typeof name === "string" ? clean(name) : "NonErrorThrow",
|
|
257
|
+
message: clean(typeof message === "string" && message ? message : typeof value === "string" ? value : `Thrown ${typeof value} value`),
|
|
258
|
+
causes: []
|
|
259
|
+
};
|
|
260
|
+
for (const key of [
|
|
261
|
+
"stack",
|
|
262
|
+
"operation",
|
|
263
|
+
"diagnostic"
|
|
264
|
+
]) {
|
|
265
|
+
const field = property(value, key);
|
|
266
|
+
if (typeof field === "string") node[key] = clean(field);
|
|
267
|
+
}
|
|
268
|
+
const details = {};
|
|
269
|
+
for (const key of FIELDS) {
|
|
270
|
+
const field = property(value, key);
|
|
271
|
+
if (scalar(field)) details[key] = (key === "expected" || key === "actual") && isSensitiveField(String(property(value, "field") ?? "")) ? "[REDACTED]" : typeof field === "string" ? clean(field) : field;
|
|
272
|
+
}
|
|
273
|
+
if (Object.keys(details).length) node.details = details;
|
|
274
|
+
const children = [];
|
|
275
|
+
const explicit = property(value, links);
|
|
276
|
+
if (Array.isArray(explicit)) {
|
|
277
|
+
for (const item of explicit.slice(0, MAX_NODES)) {
|
|
278
|
+
const relation = property(item, "relation");
|
|
279
|
+
if (typeof relation === "string" && RELATIONS.includes(relation)) children.push({
|
|
280
|
+
error: property(item, "error"),
|
|
281
|
+
relation
|
|
282
|
+
});
|
|
283
|
+
else omissions.add("invalid diagnostic cause link");
|
|
284
|
+
}
|
|
285
|
+
if (explicit.length > MAX_NODES) omissions.add("cause links exceeded 1024 children");
|
|
286
|
+
}
|
|
287
|
+
const cause = property(value, "cause");
|
|
288
|
+
if (cause !== void 0) children.push({
|
|
289
|
+
error: cause,
|
|
290
|
+
relation: "cause"
|
|
291
|
+
});
|
|
292
|
+
if (value instanceof AggregateError || property(value, "name") === "AggregateError") {
|
|
293
|
+
const errors = property(value, "errors");
|
|
294
|
+
if (Array.isArray(errors)) {
|
|
295
|
+
for (const item of errors.slice(0, MAX_NODES)) children.push({
|
|
296
|
+
error: item,
|
|
297
|
+
relation: "aggregate"
|
|
298
|
+
});
|
|
299
|
+
if (errors.length > MAX_NODES) omissions.add("aggregate exceeded 1024 children");
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
for (const child of children) {
|
|
303
|
+
if (edges >= MAX_EDGES || remaining < 100) {
|
|
304
|
+
omissions.add(edges >= MAX_EDGES ? "report exceeded 8192 cause links" : "report exceeded 1 MiB");
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
edges++;
|
|
308
|
+
remaining -= 100;
|
|
309
|
+
const childId = add(child.error);
|
|
310
|
+
if (childId) node.causes.push({
|
|
311
|
+
id: childId,
|
|
312
|
+
relation: child.relation
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
report.nodes.push(node);
|
|
316
|
+
}
|
|
317
|
+
report.omissions = [...omissions];
|
|
318
|
+
report.complete = !report.omissions.length;
|
|
319
|
+
return fitReport(report);
|
|
320
|
+
}
|
|
321
|
+
function redactionLimitReport() {
|
|
322
|
+
return {
|
|
323
|
+
version: 1,
|
|
324
|
+
errorId: `err_${randomUUID().replaceAll("-", "")}`,
|
|
325
|
+
timestamp: new Date().toISOString(),
|
|
326
|
+
service: "diagnostics",
|
|
327
|
+
context: {},
|
|
328
|
+
roots: ["n1"],
|
|
329
|
+
nodes: [{
|
|
330
|
+
id: "n1",
|
|
331
|
+
type: "RedactionLimitError",
|
|
332
|
+
message: "Failure details omitted because secret-redaction traversal was incomplete.",
|
|
333
|
+
causes: []
|
|
334
|
+
}],
|
|
335
|
+
complete: false,
|
|
336
|
+
omissions: ["secret redaction traversal exceeded its defensive budget (1024 graph/issue nodes, 4096 input values, 8192 traversal steps, 1 MiB)"]
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
function fitReport(report) {
|
|
340
|
+
const wireBytes = () => Buffer.byteLength(JSON.stringify(report));
|
|
341
|
+
if (wireBytes() <= MAX_BYTES) return report;
|
|
342
|
+
report.complete = false;
|
|
343
|
+
report.omissions.push("serialized report exceeded 1 MiB");
|
|
344
|
+
while (wireBytes() > MAX_BYTES && report.nodes.length > 1) report.nodes.pop();
|
|
345
|
+
const retained = new Set(report.nodes.map((node) => node.id));
|
|
346
|
+
report.roots = report.roots.filter((id) => retained.has(id));
|
|
347
|
+
for (const node of report.nodes) node.causes = node.causes.filter((edge) => retained.has(edge.id));
|
|
348
|
+
if (wireBytes() > MAX_BYTES) {
|
|
349
|
+
report.context = {};
|
|
350
|
+
report.service = report.service.slice(0, 200);
|
|
351
|
+
report.omissions = report.omissions.map((message) => message.slice(0, 1e3)).slice(0, 128);
|
|
352
|
+
report.nodes = report.nodes.map((node) => ({
|
|
353
|
+
id: node.id,
|
|
354
|
+
type: node.type.slice(0, 200),
|
|
355
|
+
message: node.message.slice(0, 1e3) + " [TRUNCATED]",
|
|
356
|
+
causes: node.causes
|
|
357
|
+
}));
|
|
358
|
+
}
|
|
359
|
+
return report;
|
|
360
|
+
}
|
|
361
|
+
function renderFailure(report, maxBytes = 8192) {
|
|
362
|
+
const nodes = new Map(report.nodes.map((node) => [node.id, node]));
|
|
363
|
+
const seen = new Set();
|
|
364
|
+
const pending = report.roots.map((id) => ({
|
|
365
|
+
id,
|
|
366
|
+
depth: 0,
|
|
367
|
+
relation: "root"
|
|
368
|
+
}));
|
|
369
|
+
const lines = [`Failure ${report.errorId} (${report.service})`];
|
|
370
|
+
while (pending.length) {
|
|
371
|
+
const item = pending.pop();
|
|
372
|
+
const prefix = `${" ".repeat(Math.min(item.depth, 32))}${item.relation}: `;
|
|
373
|
+
if (seen.has(item.id)) {
|
|
374
|
+
lines.push(`${prefix}[reference ${item.id}]`);
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
seen.add(item.id);
|
|
378
|
+
const node = nodes.get(item.id);
|
|
379
|
+
if (!node) {
|
|
380
|
+
lines.push(`${prefix}[missing ${item.id}]`);
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
lines.push(`${prefix}${node.type}${node.diagnostic ? `:${node.diagnostic}` : ""}${node.operation ? ` at ${node.operation}` : ""}: ${node.message}`);
|
|
384
|
+
if (node.details) lines.push(`${prefix}${JSON.stringify(node.details)}`);
|
|
385
|
+
for (const child of [...node.causes].reverse()) pending.push({
|
|
386
|
+
...child,
|
|
387
|
+
depth: item.depth + 1
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
if (!report.complete) lines.push(`Incomplete: ${report.omissions.join("; ")}`);
|
|
391
|
+
const text = lines.join("\n");
|
|
392
|
+
if (Buffer.byteLength(text) <= maxBytes) return text;
|
|
393
|
+
const suffix = `\n[Journal shortened; complete report in diagnostics logs: ${report.errorId}]`;
|
|
394
|
+
return Buffer.from(text).subarray(0, Math.max(0, maxBytes - Buffer.byteLength(suffix) - 3)).toString("utf8").replace(/\uFFFD$/, "") + suffix;
|
|
395
|
+
}
|
|
396
|
+
function encodeReport(report) {
|
|
397
|
+
const direct = JSON.stringify({
|
|
398
|
+
event: "diagnostics.report",
|
|
399
|
+
report
|
|
400
|
+
});
|
|
401
|
+
if (Buffer.byteLength(direct) <= 4096) return [direct];
|
|
402
|
+
const bytes = Buffer.from(JSON.stringify(report));
|
|
403
|
+
const checksum = createHash("sha256").update(bytes).digest("hex");
|
|
404
|
+
const size = 2e3;
|
|
405
|
+
const correlation = Object.fromEntries([
|
|
406
|
+
"workflowRunId",
|
|
407
|
+
"requestId",
|
|
408
|
+
"pipelineRunId"
|
|
409
|
+
].flatMap((key) => typeof report.context[key] === "string" && /^[A-Za-z0-9_.:-]{1,200}$/.test(String(report.context[key])) ? [[key, String(report.context[key]).slice(0, 200)]] : []));
|
|
410
|
+
const total = Math.ceil(bytes.length / size);
|
|
411
|
+
return Array.from({ length: total }, (_, i) => JSON.stringify({
|
|
412
|
+
event: "diagnostics.chunk",
|
|
413
|
+
errorId: report.errorId,
|
|
414
|
+
part: i + 1,
|
|
415
|
+
total,
|
|
416
|
+
checksum,
|
|
417
|
+
correlation,
|
|
418
|
+
encoding: "base64",
|
|
419
|
+
data: bytes.subarray(i * size, (i + 1) * size).toString("base64")
|
|
420
|
+
}));
|
|
421
|
+
}
|
|
422
|
+
function makeErrorReporter({ configuration, generateId = randomUUID, now = () => new Date(), observe, write = (severity, line) => severity === "warning" ? console.warn(line) : console.error(line) }) {
|
|
423
|
+
function capture(error, context) {
|
|
424
|
+
let report;
|
|
425
|
+
const errorId = context.errorReference ?? `err_${randomUUID().replaceAll("-", "")}`;
|
|
426
|
+
try {
|
|
427
|
+
report = createFailureReport(error, {
|
|
428
|
+
service: configuration.service,
|
|
429
|
+
context: {
|
|
430
|
+
environment: configuration.environment,
|
|
431
|
+
release: configuration.release,
|
|
432
|
+
region: configuration.region,
|
|
433
|
+
...context
|
|
434
|
+
},
|
|
435
|
+
errorId: context.errorReference ?? `err_${generateId().replaceAll("-", "").toLowerCase()}`,
|
|
436
|
+
timestamp: now().toISOString(),
|
|
437
|
+
redactedValues: configuration.redactedValues
|
|
438
|
+
});
|
|
439
|
+
} catch {
|
|
440
|
+
report = createFailureReport(error, {
|
|
441
|
+
service: configuration.service,
|
|
442
|
+
errorId,
|
|
443
|
+
redactedValues: configuration.redactedValues,
|
|
444
|
+
context: { reportingFailure: true }
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
try {
|
|
448
|
+
const lines = encodeReport(report);
|
|
449
|
+
if (lines.length > 1) {
|
|
450
|
+
let budget = 2e3;
|
|
451
|
+
let summary;
|
|
452
|
+
do {
|
|
453
|
+
summary = JSON.stringify({
|
|
454
|
+
event: "diagnostics.summary",
|
|
455
|
+
errorId: report.errorId,
|
|
456
|
+
tree: renderFailure(report, budget),
|
|
457
|
+
completeReport: "Reconstruct diagnostics.chunk entries by errorId"
|
|
458
|
+
});
|
|
459
|
+
budget = Math.floor(budget / 2);
|
|
460
|
+
} while (Buffer.byteLength(summary) > 4096 && budget > 128);
|
|
461
|
+
if (Buffer.byteLength(summary) <= 4096) write(context.severity ?? "error", summary);
|
|
462
|
+
}
|
|
463
|
+
for (const line of lines) write(context.severity ?? "error", line);
|
|
464
|
+
} catch {
|
|
465
|
+
report.context.reportingFailure = true;
|
|
466
|
+
try {
|
|
467
|
+
for (const line of encodeReport(report)) process.stderr.write(line + "\n");
|
|
468
|
+
} catch {}
|
|
469
|
+
}
|
|
470
|
+
try {
|
|
471
|
+
observe?.(report);
|
|
472
|
+
} catch {}
|
|
473
|
+
return report;
|
|
474
|
+
}
|
|
475
|
+
return {
|
|
476
|
+
capture,
|
|
477
|
+
report: (error, context) => capture(error, context).errorId
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
function reportRuntimeFailure(error, context, environment = process.env) {
|
|
481
|
+
const { service, ...details } = context;
|
|
482
|
+
return makeErrorReporter({ configuration: {
|
|
483
|
+
service,
|
|
484
|
+
redactedValues: environmentSecrets(environment)
|
|
485
|
+
} }).report(error, details);
|
|
486
|
+
}
|
|
487
|
+
const errorStackGetter = Object.getOwnPropertyDescriptor(new Error(), "stack")?.get;
|
|
488
|
+
function intrinsicGetter(prototype, name) {
|
|
489
|
+
return Object.getOwnPropertyDescriptor(prototype, name)?.get;
|
|
490
|
+
}
|
|
491
|
+
const binaryGetters = [Object.getPrototypeOf(Uint8Array.prototype), DataView.prototype].map((prototype) => ({
|
|
492
|
+
buffer: intrinsicGetter(prototype, "buffer"),
|
|
493
|
+
offset: intrinsicGetter(prototype, "byteOffset"),
|
|
494
|
+
length: intrinsicGetter(prototype, "byteLength")
|
|
495
|
+
}));
|
|
496
|
+
function binaryBytes(item) {
|
|
497
|
+
if (!ArrayBuffer.isView(item)) return new Uint8Array(item);
|
|
498
|
+
const getters = binaryGetters[types.isDataView(item) ? 1 : 0];
|
|
499
|
+
return new Uint8Array(getters.buffer.call(item), getters.offset.call(item), getters.length.call(item));
|
|
500
|
+
}
|
|
501
|
+
function toWorkflowSerializable(value, report = () => {}) {
|
|
502
|
+
const ancestors = new WeakSet();
|
|
503
|
+
let remaining = 5e4;
|
|
504
|
+
const issue = (path, reason, cause) => {
|
|
505
|
+
try {
|
|
506
|
+
report({
|
|
507
|
+
path,
|
|
508
|
+
reason,
|
|
509
|
+
...cause === void 0 ? {} : { cause }
|
|
510
|
+
});
|
|
511
|
+
} catch {}
|
|
512
|
+
};
|
|
513
|
+
const property = (output, key, item) => {
|
|
514
|
+
Object.defineProperty(output, key, {
|
|
515
|
+
value: item,
|
|
516
|
+
enumerable: true,
|
|
517
|
+
configurable: true
|
|
518
|
+
});
|
|
519
|
+
};
|
|
520
|
+
const dropped = (item) => item === void 0 || typeof item === "function" || typeof item === "symbol";
|
|
521
|
+
const dataProperty = (item, key) => {
|
|
522
|
+
let current = item;
|
|
523
|
+
for (let depth = 0; current !== null && depth <= 64; depth++) {
|
|
524
|
+
const descriptor = Object.getOwnPropertyDescriptor(current, key);
|
|
525
|
+
if (descriptor) return "value" in descriptor ? descriptor.value : void 0;
|
|
526
|
+
current = Object.getPrototypeOf(current);
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
function visit(item, path, depth) {
|
|
530
|
+
if (--remaining < 0 || depth > 64) {
|
|
531
|
+
issue(path, "limit");
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
if (item === null || typeof item === "string" || typeof item === "boolean") return item;
|
|
535
|
+
if (typeof item === "number") {
|
|
536
|
+
if (Number.isFinite(item)) return item;
|
|
537
|
+
issue(path, "non-finite number");
|
|
538
|
+
return null;
|
|
539
|
+
}
|
|
540
|
+
if (typeof item === "bigint") {
|
|
541
|
+
issue(path, "bigint");
|
|
542
|
+
return String(item);
|
|
543
|
+
}
|
|
544
|
+
if (typeof item !== "object") {
|
|
545
|
+
issue(path, typeof item);
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
if (ancestors.has(item)) {
|
|
549
|
+
issue(path, "cycle");
|
|
550
|
+
return null;
|
|
551
|
+
}
|
|
552
|
+
ancestors.add(item);
|
|
553
|
+
try {
|
|
554
|
+
if (types.isDate(item)) {
|
|
555
|
+
issue(path, "Date");
|
|
556
|
+
const time = Date.prototype.getTime.call(item);
|
|
557
|
+
return Number.isFinite(time) ? new Date(time).toISOString() : null;
|
|
558
|
+
}
|
|
559
|
+
if (ArrayBuffer.isView(item) || types.isAnyArrayBuffer(item)) {
|
|
560
|
+
issue(path, "binary");
|
|
561
|
+
const bytes = binaryBytes(item);
|
|
562
|
+
return Buffer$1.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
|
|
563
|
+
}
|
|
564
|
+
if (types.isMap(item)) {
|
|
565
|
+
issue(path, "Map");
|
|
566
|
+
const output = [];
|
|
567
|
+
for (const [key, entry] of Map.prototype.entries.call(item)) {
|
|
568
|
+
if (remaining <= 0) {
|
|
569
|
+
issue(path, "map limit");
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
const index = output.length;
|
|
573
|
+
output.push([visit(key, `${path}[${index}][0]`, depth + 1), visit(entry, `${path}[${index}][1]`, depth + 1)]);
|
|
574
|
+
}
|
|
575
|
+
return output;
|
|
576
|
+
}
|
|
577
|
+
if (types.isSet(item)) {
|
|
578
|
+
issue(path, "Set");
|
|
579
|
+
const output = [];
|
|
580
|
+
for (const entry of Set.prototype.values.call(item)) {
|
|
581
|
+
if (remaining <= 0) {
|
|
582
|
+
issue(path, "set limit");
|
|
583
|
+
break;
|
|
584
|
+
}
|
|
585
|
+
output.push(visit(entry, `${path}[${output.length}]`, depth + 1));
|
|
586
|
+
}
|
|
587
|
+
return output;
|
|
588
|
+
}
|
|
589
|
+
if (Array.isArray(item)) {
|
|
590
|
+
const count = Object.getOwnPropertyDescriptor(item, "length")?.value;
|
|
591
|
+
if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0) {
|
|
592
|
+
issue(path, "invalid array length");
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
const length = Math.min(count, Math.max(remaining, 0));
|
|
596
|
+
if (length !== count) issue(path, "array limit");
|
|
597
|
+
return Array.from({ length }, (_, index) => {
|
|
598
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, String(index));
|
|
599
|
+
if (descriptor?.get) {
|
|
600
|
+
issue(`${path}[${index}]`, "accessor");
|
|
601
|
+
return null;
|
|
602
|
+
}
|
|
603
|
+
return visit(descriptor?.value, `${path}[${index}]`, depth + 1);
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
const prototype = Object.getPrototypeOf(item);
|
|
607
|
+
const plain = prototype === null || Object.getPrototypeOf(prototype) === null;
|
|
608
|
+
const nativeError = types.isNativeError(item);
|
|
609
|
+
if (!plain) issue(path, nativeError ? "Error" : "class instance");
|
|
610
|
+
if (nativeError) {
|
|
611
|
+
const name = dataProperty(item, "name");
|
|
612
|
+
const message = dataProperty(item, "message");
|
|
613
|
+
const output = {
|
|
614
|
+
name: typeof name === "string" ? name : "Error",
|
|
615
|
+
message: typeof message === "string" ? message : ""
|
|
616
|
+
};
|
|
617
|
+
for (const key of Object.getOwnPropertyNames(item)) {
|
|
618
|
+
if (remaining <= 0) {
|
|
619
|
+
issue(path, "error limit");
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
622
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, key);
|
|
623
|
+
if (key === "stack" && errorStackGetter && descriptor?.get) {
|
|
624
|
+
property(output, key, visit(errorStackGetter.call(item), `${path}.stack`, depth + 1));
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
if (key !== "__proto__" && descriptor && "value" in descriptor && !dropped(descriptor.value)) property(output, key, visit(descriptor.value, `${path}[${JSON.stringify(key)}]`, depth + 1));
|
|
628
|
+
}
|
|
629
|
+
return output;
|
|
630
|
+
}
|
|
631
|
+
if (!plain) {
|
|
632
|
+
let current = prototype;
|
|
633
|
+
const prototypes = new WeakSet();
|
|
634
|
+
for (let prototypeDepth = 0; current !== null; prototypeDepth++) {
|
|
635
|
+
if (prototypeDepth >= 64 || prototypes.has(current)) {
|
|
636
|
+
issue(path, "prototype limit");
|
|
637
|
+
break;
|
|
638
|
+
}
|
|
639
|
+
prototypes.add(current);
|
|
640
|
+
const json = Object.getOwnPropertyDescriptor(current, "toJSON");
|
|
641
|
+
if (typeof json?.value === "function") return visit(json.value.call(item), path, depth + 1);
|
|
642
|
+
current = Object.getPrototypeOf(current);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
const output = {};
|
|
646
|
+
for (const key of Reflect.ownKeys(item)) {
|
|
647
|
+
if (remaining <= 0) {
|
|
648
|
+
issue(path, "object limit");
|
|
649
|
+
break;
|
|
650
|
+
}
|
|
651
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, key);
|
|
652
|
+
if (!descriptor?.enumerable) continue;
|
|
653
|
+
const childPath = `${path}[${JSON.stringify(String(key))}]`;
|
|
654
|
+
if (typeof key === "symbol" || key === "__proto__" || descriptor.get) {
|
|
655
|
+
issue(childPath, descriptor.get ? "accessor" : "unsupported key");
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
if (dropped(descriptor.value)) {
|
|
659
|
+
if (descriptor.value !== void 0) issue(childPath, typeof descriptor.value);
|
|
660
|
+
continue;
|
|
661
|
+
}
|
|
662
|
+
property(output, key, visit(descriptor.value, childPath, depth + 1));
|
|
663
|
+
}
|
|
664
|
+
return output;
|
|
665
|
+
} catch (cause) {
|
|
666
|
+
issue(path, "unreadable value", cause);
|
|
667
|
+
return null;
|
|
668
|
+
} finally {
|
|
669
|
+
ancestors.delete(item);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
return visit(value, "$", 0);
|
|
673
|
+
}
|
|
674
|
+
let diagnosticSequence = 0;
|
|
675
|
+
function workflowValue(value, context) {
|
|
676
|
+
const issues = [];
|
|
677
|
+
const failures = [];
|
|
678
|
+
let count = 0;
|
|
679
|
+
const output = toWorkflowSerializable(value, (issue) => {
|
|
680
|
+
count++;
|
|
681
|
+
if ("cause" in issue) failures.push(issue.cause);
|
|
682
|
+
if (issues.length < 20) issues.push({
|
|
683
|
+
reason: issue.reason,
|
|
684
|
+
path: issue.path.replace(/\["(?:[^"\\]|\\.)*"\]/g, "[field]")
|
|
685
|
+
});
|
|
686
|
+
});
|
|
687
|
+
if (count > 0) try {
|
|
688
|
+
const errorId = globalThis.crypto?.randomUUID?.() ?? `serialization-${Date.now()}-${++diagnosticSequence}`;
|
|
689
|
+
if (failures.length > 0) reportRuntimeFailure(failures.length === 1 ? failures[0] : new AggregateError(failures, "Workflow value projections failed"), {
|
|
690
|
+
service: "segmentstream-agent",
|
|
691
|
+
boundary: context.boundary,
|
|
692
|
+
operation: "workflow.normalize",
|
|
693
|
+
severity: "warning",
|
|
694
|
+
errorReference: errorId
|
|
695
|
+
});
|
|
696
|
+
console.warn("[workflow] normalized non-JSON value", {
|
|
697
|
+
errorId,
|
|
698
|
+
boundary: context.boundary,
|
|
699
|
+
toolName: context.toolName,
|
|
700
|
+
toolCallId: context.toolCallId,
|
|
701
|
+
eventType: context.eventType,
|
|
702
|
+
issues,
|
|
703
|
+
issueCount: count
|
|
704
|
+
});
|
|
705
|
+
} catch {}
|
|
706
|
+
return output;
|
|
707
|
+
}
|
|
708
|
+
function workflowToolResult(value, context) {
|
|
709
|
+
return workflowValue(value, {
|
|
710
|
+
boundary: "SDK tool result",
|
|
711
|
+
toolName: context.toolName,
|
|
712
|
+
toolCallId: context.callId
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
export { workflowToolResult as n, workflowValue as r, toWorkflowSerializable as t };
|