Skip to content

Commit db76698

Browse files
author
Peter Steinberger
committed
fix(agents): bound provider result media
1 parent 923b953 commit db76698

2 files changed

Lines changed: 38 additions & 6 deletions

File tree

src/agents/embedded-agent-subscribe.tools.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,13 @@ describe("extractToolResultText", () => {
454454
expect(text).toBe("hello");
455455
});
456456

457+
it("caps top-level text arrays", () => {
458+
const text = extractToolResultText([{ type: "text", text: "x".repeat(9000) }]);
459+
460+
expect(text).toContain("…(truncated)…");
461+
expect(text?.length).toBeLessThanOrEqual(8020);
462+
});
463+
457464
it("redacts whole data URI values without rewriting ordinary data substrings", () => {
458465
const text = extractToolResultText({
459466
content: [
@@ -474,6 +481,14 @@ describe("extractToolResultText", () => {
474481
const text = extractToolResultText({
475482
content: [
476483
{ type: "audio", data: "audio-base64-secret", mimeType: "audio/mpeg" },
484+
{
485+
type: "document",
486+
source: {
487+
type: "base64",
488+
media_type: "application/pdf",
489+
data: "document-base64-secret",
490+
},
491+
},
477492
{
478493
type: "resource",
479494
apiKey: "sk-structured-secret-1234567890",
@@ -489,6 +504,7 @@ describe("extractToolResultText", () => {
489504
expect(text).toContain('"uri":"blob://result"');
490505
expect(text).toContain('"blob":"[binary omitted:');
491506
expect(text).not.toContain("audio-base64-secret");
507+
expect(text).not.toContain("document-base64-secret");
492508
expect(text).not.toContain("resource-base64-secret");
493509
expect(text).not.toContain("sk-structured-secret-1234567890");
494510
});

src/agents/embedded-agent-subscribe.tools.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -288,17 +288,31 @@ function redactInlineDataUriValue(value: string): string {
288288
return `[inline data URI: ${value.length} chars]`;
289289
}
290290

291+
function carriesBinaryData(record: Record<string, unknown>): boolean {
292+
const type = normalizeOptionalLowercaseString(record.type);
293+
if (type === "audio" || type === "image" || type === "base64") {
294+
return true;
295+
}
296+
const mediaType = normalizeOptionalLowercaseString(record.media_type ?? record.mimeType);
297+
return (
298+
mediaType?.startsWith("image/") === true ||
299+
mediaType?.startsWith("audio/") === true ||
300+
mediaType?.startsWith("video/") === true ||
301+
mediaType === "application/pdf"
302+
);
303+
}
304+
291305
function sanitizeStructuredToolResultValue(
292306
value: unknown,
293307
key = "",
294-
parentType?: string,
308+
parentCarriesBinaryData = false,
295309
seen = new WeakSet<object>(),
296310
): unknown {
297311
if (typeof value === "string") {
298312
if (SENSITIVE_STRUCTURED_HEADER_FIELDS.has(key.toLowerCase())) {
299313
return "***";
300314
}
301-
if (key === "blob" || (key === "data" && (parentType === "audio" || parentType === "image"))) {
315+
if (key === "blob" || (key === "data" && parentCarriesBinaryData)) {
302316
return `[binary omitted: ${value.length} chars]`;
303317
}
304318
// Claude CLI result blocks carry replay-only ciphertext that is not useful display text.
@@ -319,14 +333,16 @@ function sanitizeStructuredToolResultValue(
319333
seen.add(value);
320334
if (Array.isArray(value)) {
321335
// Keep the owning key so arrays of credentials inherit the same redaction policy.
322-
return value.map((item) => sanitizeStructuredToolResultValue(item, key, parentType, seen));
336+
return value.map((item) =>
337+
sanitizeStructuredToolResultValue(item, key, parentCarriesBinaryData, seen),
338+
);
323339
}
324340
const record = value as Record<string, unknown>;
325-
const type = readStringValue(record.type);
341+
const hasBinaryData = carriesBinaryData(record);
326342
return Object.fromEntries(
327343
Object.entries(record).map(([childKey, child]) => [
328344
childKey,
329-
sanitizeStructuredToolResultValue(child, childKey, type, seen),
345+
sanitizeStructuredToolResultValue(child, childKey, hasBinaryData, seen),
330346
]),
331347
);
332348
}
@@ -379,7 +395,7 @@ export function extractToolResultText(result: unknown): string | undefined {
379395
})
380396
.filter((value): value is string => Boolean(value));
381397
if (texts.length > 0) {
382-
return texts.join("\n");
398+
return truncateToolText(texts.join("\n"));
383399
}
384400
const structuredTexts: string[] = [];
385401
for (const item of content) {

0 commit comments

Comments
 (0)