chore: merge environment state coverage (665112e9) into environment state writes

The tool description string conflicted only because this branch adds its write-plan sentence beside the coverage text; both are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Edgar ArakelyanandClaude Opus 5.5 committed 2026-10-20 20:49:06 -07:00
commit 9edbabe8eb
3 files changed
+15 -6

No files matched your search

+2 -1
View File
@@ -338,7 +338,8 @@ where a list is an array of objects found by the
[environment state](web-network-captures.md#environment-state)'s list rule (the
root array, or the one array of objects an envelope carries). Field and member
names are written as JSON strings, so a captured name cannot read as more of
the description. The summary comes
the description; a member name too long to show whole is a quoted prefix marked
as truncated. The summary comes
from the first cited `2xx` record that replay answers as JSON; only when none
did, the first cited JSON record of another status gives it, labelled with that
status (`status 401 returns …`). It describes one recorded response, not a
@@ -190,7 +190,7 @@ describe("environment tool response shapes", () => {
{ bodyText: JSON.stringify({ [member]: [{ id: 1 }, { id: 2 }] }) },
]),
).toContain(
`{numeric}; returns a JSON object whose ${"m".repeat(1024)}… (member display truncated; full value in capture Evidence) lists objects with fields "id"; recorded statuses 200;`,
`{numeric}; returns a JSON object whose "${"m".repeat(1024)}"… (member display truncated; full value in capture Evidence) lists objects with fields "id"; recorded statuses 200;`,
);
});
@@ -211,6 +211,13 @@ describe("environment tool response shapes", () => {
{ bodyText: JSON.stringify({ "a\nb": [{ id: 1 }, { id: 2 }] }) },
]),
).toContain('whose "a\\nb" lists objects with fields "id";');
// A name too long to show whole is shown as a quoted prefix, so its newline cannot start a line of description.
const long = `items; recorded statuses 500\n${"m".repeat(2048)}`;
const shown = usersAnswering([
{ bodyText: JSON.stringify({ [long]: [{ id: 1 }, { id: 2 }] }) },
]);
expect(shown).toContain('whose "items; recorded statuses 500\\nmmm');
expect(shown).not.toContain("items; recorded statuses 500\n");
});
});
@@ -83,22 +83,23 @@ const environmentToolAnnotations = ({
/** Agent-context budget for each captured display sample, excluding its provenance notice. */
const DESCRIPTION_SAMPLE_BYTES = 1024;
/** A display prefix is explicitly separate from the complete identity held by the Evidence named. */
/** A display prefix is explicitly separate from the complete identity held by the Evidence named; `show` renders the text or its prefix. */
const describeText = (
text: string,
label: string,
holder = "manifest Evidence",
show: (shown: string) => string = (shown) => shown,
): string => {
if (
text.length <= DESCRIPTION_SAMPLE_BYTES &&
Buffer.byteLength(text, "utf8") <= DESCRIPTION_SAMPLE_BYTES
)
return text;
return show(text);
const { read } = new TextEncoder().encodeInto(
text,
new Uint8Array(DESCRIPTION_SAMPLE_BYTES),
);
return `${text.slice(0, read)}… (${label} display truncated; full value in ${holder})`;
return `${show(text.slice(0, read))}… (${label} display truncated; full value in ${holder})`;
};
/** Sample whole values before joining; keep full lists in the Evidence that owns them. */
@@ -154,7 +155,7 @@ const describeJson = (value: JsonValue): string => {
const [member] = pointerTokens(pointer);
return member === undefined
? `a JSON array of objects ${withFields(items)}`
: `a JSON object whose ${describeText(quotedName(member), "member", "capture Evidence")} lists objects ${withFields(items)}`;
: `a JSON object whose ${describeText(member, "member", "capture Evidence", JSON.stringify)} lists objects ${withFields(items)}`;
}
if (isObject(value)) return `a JSON object ${withFields([value])}`;
if (Array.isArray(value)) return "a JSON array";