mirror of
https://github.com/morluto/rea.git
synced 2026-11-09 08:17:02 +00:00
fix(mcp): retain complete application results across response limits
Retain complete authenticated application Evidence when the repeated MCP representation exceeds the default receive frame or Node string limit. Return a typed transport constraint, keep useful followup queries available, and stream full canonical bundles to atomic destinations. Verify complete Notion and Obsidian workflows on Linux and native Windows, full CLI/Evidence parity, and real large Chrome screenshot recovery. Preserve complete success contracts and caller-selected evidence paths. Refs #1065, #1053.
This commit is contained in:
1 parent
c701376777
commit
a1ed4232de
43 files changed
+1314
-186
No files matched your search
@@ -0,0 +1,55 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import type { JsonValue } from "../domain/jsonValue.js";
|
||||
import { encodeToolResult } from "./toolResultEncoding.js";
|
||||
|
||||
const projectedResult = (candidate: JsonValue) => ({
|
||||
content: [{ type: "text", text: JSON.stringify(candidate) }],
|
||||
structuredContent: candidate,
|
||||
});
|
||||
|
||||
describe("MCP result encoding budget", () => {
|
||||
it.each([
|
||||
{ result: { value: 1 } },
|
||||
{ result: ["中文", "😀", "\ud800", '"\\\n'] },
|
||||
{ result: "x".repeat(8191) + "😀" + '中文\n"'.repeat(20000) },
|
||||
])("counts actual UTF-8 structured and escaped text bytes", (candidate) => {
|
||||
const encoded = encodeToolResult(candidate);
|
||||
expect(encoded.ok).toBe(true);
|
||||
if (!encoded.ok) throw new Error("Expected complete encoding");
|
||||
expect(encoded.text).toBe(JSON.stringify(candidate));
|
||||
expect(encoded.bytes).toBe(
|
||||
Buffer.byteLength(JSON.stringify(projectedResult(candidate))),
|
||||
);
|
||||
});
|
||||
|
||||
it("accounts for repeated Evidence representations", () => {
|
||||
const normalized = { value: '中文"'.repeat(30000) };
|
||||
const candidate = {
|
||||
result: normalized,
|
||||
evidence: { normalized_result: normalized },
|
||||
};
|
||||
const completeBytes = Buffer.byteLength(
|
||||
JSON.stringify(projectedResult(candidate)),
|
||||
);
|
||||
expect(encodeToolResult(candidate, completeBytes).ok).toBe(true);
|
||||
expect(encodeToolResult(candidate, completeBytes - 1)).toMatchObject({
|
||||
ok: false,
|
||||
bytesAtLeast: completeBytes,
|
||||
});
|
||||
});
|
||||
|
||||
it("stops before reading the remainder of an oversized result", () => {
|
||||
const candidate: JsonValue = { text: "x".repeat(1000000) };
|
||||
Object.defineProperty(candidate, "remainder", {
|
||||
enumerable: true,
|
||||
get() {
|
||||
throw new Error("The remainder must not be read");
|
||||
},
|
||||
});
|
||||
// Only an already-known first property is visited before exhausting the
|
||||
// budget. The serializer's property discovery must not eagerly read values.
|
||||
expect(() => encodeToolResult(candidate, 1000)).not.toThrow();
|
||||
expect(encodeToolResult(candidate, 1000).ok).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user