@bli-cockpit/cli 0.2.263 → 0.2.265
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/adapters/agent-image-evidence.js +4 -4
- package/dist/adapters/raw-evidence-collection-state.js +14 -2
- package/dist/adapters/raw-evidence-sanitize-held.js +191 -0
- package/dist/adapters/raw-evidence-sanitize.js +10 -10
- package/dist/adapters/raw-evidence-transcript-body.js +80 -0
- package/dist/adapters/raw-evidence-transcript-file.js +43 -56
- package/dist/adapters/raw-evidence-transcript-stream.js +63 -0
- package/dist/adapters/transcript-line-stream.js +47 -0
- package/dist/adapters/transcript-text-stream.js +124 -0
- package/dist/commands/public-root.js +1 -1
- package/dist/image-census-stream.js +37 -0
- package/dist/image-description-session.js +116 -24
- package/dist/slim/slim-stream.js +77 -0
- package/dist/slim/slim-transcript.js +99 -22
- package/package.json +1 -1
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* What each rule keeps and drops: claude-rules.ts and codex-rules.ts. The table for people:
|
|
23
23
|
* docs/architecture/image-descriptions.md.
|
|
24
24
|
*/
|
|
25
|
+
import { replaceImagesWithMarkers } from "@bli-cockpit/telemetry-core";
|
|
25
26
|
import { newClaudeSlimState, slimClaudeRecord } from "./claude-rules.js";
|
|
26
27
|
import { newCodexSlimState, slimCodexRecord } from "./codex-rules.js";
|
|
27
28
|
import { LineEdits, SeenBlocks, isJsonObject } from "./slim-support.js";
|
|
@@ -103,17 +104,89 @@ function slimOneLine(line, applyRules, stats) {
|
|
|
103
104
|
stats.linesModified += 1;
|
|
104
105
|
return JSON.stringify(record) + (line.endsWith("\r") ? "\r" : "");
|
|
105
106
|
}
|
|
106
|
-
/**
|
|
107
|
-
|
|
107
|
+
/**
|
|
108
|
+
* The slim form of a whole transcript's text, line for line, with the image swap folded into the
|
|
109
|
+
* same pass (BLI-23317). Output is byte-identical to `replaceImagesWithMarkers` followed by the old
|
|
110
|
+
* split/map/join: lines are found by `indexOf`, never `split`; a line no rule touched stays part of
|
|
111
|
+
* a slice of the input and is not copied on its own, so the only new allocation is the one joined
|
|
112
|
+
* result (and only when some line changed). An image sits inside one line (its characters exclude
|
|
113
|
+
* "\n"), so it is swapped inside that line before the rules read it, as the two-step order did.
|
|
114
|
+
*/
|
|
115
|
+
export function slimPass(text, kind, swap) {
|
|
108
116
|
const slimmer = createSlimmer(kind);
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
117
|
+
const pieces = [];
|
|
118
|
+
let emitted = 0;
|
|
119
|
+
let nextImage = 0;
|
|
120
|
+
let replacedCount = 0;
|
|
121
|
+
let charsSaved = 0;
|
|
122
|
+
for (let position = 0;;) {
|
|
123
|
+
const newline = text.indexOf("\n", position);
|
|
124
|
+
const end = newline === -1 ? text.length : newline;
|
|
125
|
+
let line = text.slice(position, end);
|
|
126
|
+
let swapped = false;
|
|
127
|
+
if (swap) {
|
|
128
|
+
const local = [];
|
|
129
|
+
while (nextImage < swap.images.length && swap.images[nextImage].replaceStart < end) {
|
|
130
|
+
const image = swap.images[nextImage];
|
|
131
|
+
nextImage += 1;
|
|
132
|
+
if (image.replaceStart < position || image.replaceEnd > end)
|
|
133
|
+
throw new Error("image_spans_lines");
|
|
134
|
+
local.push({
|
|
135
|
+
...image,
|
|
136
|
+
replaceStart: image.replaceStart - position,
|
|
137
|
+
replaceEnd: image.replaceEnd - position,
|
|
138
|
+
base64Start: image.base64Start - position,
|
|
139
|
+
base64End: image.base64End - position,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (local.length > 0) {
|
|
143
|
+
const replaced = replaceImagesWithMarkers(line, local, swap.replace);
|
|
144
|
+
if (replaced.replacedCount > 0) {
|
|
145
|
+
line = replaced.text;
|
|
146
|
+
swapped = true;
|
|
147
|
+
replacedCount += replaced.replacedCount;
|
|
148
|
+
charsSaved += replaced.charsSaved;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const out = slimmer.slimLine(line);
|
|
153
|
+
if (swapped || out !== line) {
|
|
154
|
+
pieces.push(text.slice(emitted, position), out);
|
|
155
|
+
emitted = end;
|
|
156
|
+
}
|
|
157
|
+
if (newline === -1)
|
|
158
|
+
break;
|
|
159
|
+
position = newline + 1;
|
|
160
|
+
}
|
|
113
161
|
const stats = slimmer.stats();
|
|
114
|
-
|
|
162
|
+
if (pieces.length === 0)
|
|
163
|
+
return { text, stats, replacedCount, charsSaved, changed: false };
|
|
164
|
+
pieces.push(text.slice(emitted));
|
|
165
|
+
return { text: pieces.join(""), stats, replacedCount, charsSaved, changed: true };
|
|
166
|
+
}
|
|
167
|
+
/** The slim form of a whole transcript's text, line for line. */
|
|
168
|
+
export function slimTranscript(text, kind) {
|
|
169
|
+
const slim = slimPass(text, kind);
|
|
170
|
+
return { text: slim.text, stats: slim.stats };
|
|
115
171
|
}
|
|
116
172
|
const TAG = "[slim-transcript]";
|
|
173
|
+
export function logSlimmed(kind, sessionId, stats, startedAt) {
|
|
174
|
+
console.error(TAG + (stats.linesModified === 0 ? " nothing to strip" : " transcript slimmed"), JSON.stringify({
|
|
175
|
+
source: kind,
|
|
176
|
+
session_id: sessionId.slice(0, 80),
|
|
177
|
+
lines: stats.lines,
|
|
178
|
+
lines_modified: stats.linesModified,
|
|
179
|
+
lines_failed: stats.linesFailed,
|
|
180
|
+
bytes_before: stats.bytesBefore,
|
|
181
|
+
bytes_after: stats.bytesAfter,
|
|
182
|
+
chars_by_rule: stats.charsByRule,
|
|
183
|
+
lines_by_rule: stats.linesByRule,
|
|
184
|
+
elapsed_ms: Date.now() - startedAt,
|
|
185
|
+
}));
|
|
186
|
+
}
|
|
187
|
+
function logSlimFailed(kind, error, bytes) {
|
|
188
|
+
console.error(TAG + " failed, uploading the transcript as it was", JSON.stringify({ reason: "slim_failed", source: kind, error_name: error instanceof Error ? error.name : typeof error, bytes }));
|
|
189
|
+
}
|
|
117
190
|
/**
|
|
118
191
|
* `slimTranscript` that can never fail a transcript: any exception returns the text it was given and
|
|
119
192
|
* logs the reason. Metadata only: counts, sizes, rule names. Never a line, never a field value.
|
|
@@ -122,23 +195,27 @@ export function slimOrKeep(text, kind, label) {
|
|
|
122
195
|
const startedAt = Date.now();
|
|
123
196
|
try {
|
|
124
197
|
const slim = slimTranscript(text, kind);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
source: kind,
|
|
128
|
-
session_id: label.sessionId.slice(0, 80),
|
|
129
|
-
lines: stats.lines,
|
|
130
|
-
lines_modified: stats.linesModified,
|
|
131
|
-
lines_failed: stats.linesFailed,
|
|
132
|
-
bytes_before: stats.bytesBefore,
|
|
133
|
-
bytes_after: stats.bytesAfter,
|
|
134
|
-
chars_by_rule: stats.charsByRule,
|
|
135
|
-
lines_by_rule: stats.linesByRule,
|
|
136
|
-
elapsed_ms: Date.now() - startedAt,
|
|
137
|
-
}));
|
|
138
|
-
return { text: slim.text, stats };
|
|
198
|
+
logSlimmed(kind, label.sessionId, slim.stats, startedAt);
|
|
199
|
+
return { text: slim.text, stats: slim.stats };
|
|
139
200
|
}
|
|
140
201
|
catch (error) {
|
|
141
|
-
|
|
202
|
+
logSlimFailed(kind, error, typeof text === "string" ? text.length : 0);
|
|
142
203
|
return { text, stats: null };
|
|
143
204
|
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* `slimPass` that can never fail a transcript: a pass that throws (an image that would span lines,
|
|
208
|
+
* an exhausted string) logs the reason and returns null, and the caller takes the two-step path.
|
|
209
|
+
*/
|
|
210
|
+
export function slimPassOrNull(text, kind, label, swap) {
|
|
211
|
+
const startedAt = Date.now();
|
|
212
|
+
try {
|
|
213
|
+
const slim = slimPass(text, kind, swap);
|
|
214
|
+
logSlimmed(kind, label.sessionId, slim.stats, startedAt);
|
|
215
|
+
return slim;
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
logSlimFailed(kind, error, text.length);
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
144
221
|
}
|