@spexcode/transcript 0.7.0-next.14 → 0.7.0-next.15
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/parsers.js +23 -3
- package/package.json +1 -1
package/dist/parsers.js
CHANGED
|
@@ -54,6 +54,28 @@ const compact = (value) => {
|
|
|
54
54
|
// (Claude's tool_result content, Codex's input_text output blocks, MCP results everywhere) means the text of
|
|
55
55
|
// those blocks, with their line breaks; encoding the block list itself as JSON would show the reader escaped
|
|
56
56
|
// newlines inside a JSON shell. A block that is not text — an image, a reference — is named, not dumped.
|
|
57
|
+
// @@@ a block that is not text is NAMED, with what the producer said about it - the output contract is text,
|
|
58
|
+
// so a picture cannot be carried in it; the honest substitute is a placeholder that says what was there. A
|
|
59
|
+
// bare `[image]` answers none of the questions a person actually has, and both facts worth having are already
|
|
60
|
+
// in the record: the media type when the producer states it (Claude's `source.media_type`, the `data:<mime>;`
|
|
61
|
+
// prefix of Codex's `image_url`) and the size, which base64 always yields. Neither is guessed — an image with
|
|
62
|
+
// no stated type is named `[image 1.2 MB]`, not sniffed from its bytes.
|
|
63
|
+
const KB = 1024;
|
|
64
|
+
const humanBytes = (bytes) => bytes >= KB * KB ? `${(bytes / (KB * KB)).toFixed(1)} MB`
|
|
65
|
+
: bytes >= KB ? `${Math.round(bytes / KB)} KB` : `${bytes} B`;
|
|
66
|
+
const base64Bytes = (data) => {
|
|
67
|
+
const body = data.replace(/=+$/, '');
|
|
68
|
+
return Math.floor((body.length * 3) / 4);
|
|
69
|
+
};
|
|
70
|
+
const blockLabel = (block, type) => {
|
|
71
|
+
const source = object(block.source);
|
|
72
|
+
const url = string(block.image_url) ?? string(block.url) ?? string(source?.url);
|
|
73
|
+
const dataUrl = url && url.startsWith('data:') ? /^data:([^;,]*)[;,]/.exec(url) : null;
|
|
74
|
+
const mime = string(source?.media_type) ?? string(block.mimeType) ?? string(block.mime_type) ?? (dataUrl ? dataUrl[1] : null);
|
|
75
|
+
const encoded = string(source?.data) ?? (url && url.startsWith('data:') ? url.slice(url.indexOf(',') + 1) : null);
|
|
76
|
+
const size = encoded ? ` ${humanBytes(base64Bytes(encoded))}` : '';
|
|
77
|
+
return `[${mime || type}${size}]`;
|
|
78
|
+
};
|
|
57
79
|
const resultText = (value) => {
|
|
58
80
|
if (typeof value === 'string')
|
|
59
81
|
return value;
|
|
@@ -67,10 +89,8 @@ const resultText = (value) => {
|
|
|
67
89
|
if (text !== null)
|
|
68
90
|
return text;
|
|
69
91
|
const type = string(block.type);
|
|
70
|
-
if (type === 'image')
|
|
71
|
-
return '[image]';
|
|
72
92
|
if (type)
|
|
73
|
-
return
|
|
93
|
+
return blockLabel(block, type);
|
|
74
94
|
return compact(blockValue);
|
|
75
95
|
}).join('\n');
|
|
76
96
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spexcode/transcript",
|
|
3
|
-
"version": "0.7.0-next.
|
|
3
|
+
"version": "0.7.0-next.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Normalized agent transcripts: one parser per harness, a bounded interval reader over a native thread file or an in-memory event stream, and the full/delta frame protocol every transport and renderer share.",
|
|
6
6
|
"files": [
|