





















@@ -106,6 +106,108 @@ describe("createAgentToolResultMiddlewareRunner", () => {
106106expect(result.details).toEqual({ status: "error", middlewareError: true });
107107});
108108109+it("delivers tool result unchanged when no middleware is registered", async () => {
110+// Without a middleware handler, the harness has no validator contract to
111+// satisfy and must not penalize tool emitters that legitimately produce
112+// dependency payloads (functions, cycles) on `details`.
113+const client: Record<string, unknown> = { type: "fake-channel-client" };
114+const cyclicDetails: Record<string, unknown> = {
115+ok: true,
116+messageId: "abc",
117+delete: () => Promise.resolve(),
118+ client,
119+};
120+client.message = cyclicDetails;
121+const original = {
122+content: [{ type: "text" as const, text: "delivered" }],
123+details: cyclicDetails,
124+};
125+const runner = createAgentToolResultMiddlewareRunner({ runtime: "pi" }, []);
126+127+const result = await runner.applyToolResultMiddleware({
128+toolCallId: "call-1",
129+toolName: "message",
130+args: {},
131+result: original,
132+});
133+134+expect(result).toBe(original);
135+});
136+137+it("sanitizes incoming cyclic details so a no-op middleware does not fail closed", async () => {
138+// The bug class behind silent Discord delivery in 2026.5.5: any plugin
139+// that registers a tool-result middleware (e.g. bundled tokenjuice)
140+// causes the harness to validate `event.result` against shape rules,
141+// and tool emitters' raw channel-send payloads fail those rules.
142+const client: Record<string, unknown> = { type: "fake-channel-client" };
143+const payload: Record<string, unknown> = {
144+ok: true,
145+messageId: "1501757759073419394",
146+delete: () => Promise.resolve(),
147+ client,
148+};
149+client.message = payload;
150+const runner = createAgentToolResultMiddlewareRunner({ runtime: "pi" }, [() => undefined]);
151+152+const result = await runner.applyToolResultMiddleware({
153+toolCallId: "call-1",
154+toolName: "message",
155+args: {},
156+result: {
157+content: [{ type: "text", text: "delivered" }],
158+details: payload,
159+},
160+});
161+162+expect((result.details as { middlewareError?: boolean }).middlewareError).toBeUndefined();
163+expect(result.details).toEqual({
164+ok: true,
165+messageId: "1501757759073419394",
166+client: { type: "fake-channel-client" },
167+});
168+});
169+170+it("sanitizes incoming function/symbol/bigint values in details", async () => {
171+const runner = createAgentToolResultMiddlewareRunner({ runtime: "codex" }, [() => undefined]);
172+173+const result = await runner.applyToolResultMiddleware({
174+toolCallId: "call-1",
175+toolName: "exec",
176+args: {},
177+result: {
178+content: [{ type: "text", text: "ok" }],
179+details: {
180+ok: true,
181+exitCode: 0,
182+callback: () => 1,
183+tag: Symbol("x"),
184+missing: undefined,
185+id: 10n,
186+},
187+},
188+});
189+190+expect(result.details).toEqual({ ok: true, exitCode: 0, id: "10" });
191+});
192+193+it("collapses oversized incoming details to a truncation marker", async () => {
194+const runner = createAgentToolResultMiddlewareRunner({ runtime: "pi" }, [() => undefined]);
195+196+const result = await runner.applyToolResultMiddleware({
197+toolCallId: "call-1",
198+toolName: "exec",
199+args: {},
200+result: {
201+content: [{ type: "text", text: "ok" }],
202+details: { blob: "x".repeat(200_000) },
203+},
204+});
205+206+const sanitized = result.details as { truncated?: boolean; originalSizeBytes?: number };
207+expect(sanitized.truncated).toBe(true);
208+expect(sanitized.originalSizeBytes ?? 0).toBeGreaterThan(100_000);
209+});
210+109211it("accepts well-formed middleware results", async () => {
110212const runner = createAgentToolResultMiddlewareRunner({ runtime: "codex" }, [
111213(_event, ctx) => ({
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。