UNPKG

assistant-stream

Version:

Streaming utilities for AI assistants

148 lines (130 loc) • 5.66 kB
import { afterEach, describe, expect, it, vi } from "vitest"; import { GorpStreamAccumulator } from "./GorpStreamAccumulator"; import type { GorpStreamOperation } from "./types"; afterEach(() => { vi.restoreAllMocks(); }); describe("GorpStreamAccumulator", () => { it("applies deeply nested paths without overflowing the stack", () => { const path = Array.from({ length: 20_000 }, (_, index) => `level-${index}`); const acc = new GorpStreamAccumulator({}); acc.append([{ type: "set", path, value: true }]); let current = acc.state; for (const key of path) { current = (current as Record<string, typeof current>)[key]!; } expect(current).toBe(true); }); it("rejects unsafe path segments", () => { for (const path of [ ["__proto__", "polluted"], ["constructor", "prototype", "polluted"], ["a", "__proto__"], ]) { const acc = new GorpStreamAccumulator({}); expect(() => acc.append([{ type: "set", path, value: true }])).toThrow( /Unsafe gorp path segment/, ); } expect(({} as { polluted?: unknown }).polluted).toBeUndefined(); }); it("treats inherited keys as absent when navigating", () => { const acc = new GorpStreamAccumulator({}); acc.append([{ type: "set", path: ["toString", "x"], value: 1 }]); expect(acc.state).toEqual({ toString: { x: 1 } }); const append = new GorpStreamAccumulator({ toString: "hi" }); append.append([{ type: "append-text", path: ["toString"], value: "!" }]); expect(append.state).toEqual({ toString: "hi!" }); }); describe("strict: false", () => { it("skips unappliable operations and keeps applying the rest", () => { const error = vi.spyOn(console, "error").mockImplementation(() => {}); const acc = new GorpStreamAccumulator({ a: 1 }, { strict: false }); acc.append([ { type: "append-text", path: ["a"], value: "x" }, { type: "unknown-op" } as unknown as GorpStreamOperation, { type: "set", path: ["a", "b"], value: 1 }, { type: "set", path: ["ok"], value: true }, ]); expect(acc.state).toEqual({ a: 1, ok: true }); expect(error).toHaveBeenCalledTimes(3); error.mockRestore(); }); it("clamps out-of-bounds array inserts", () => { const warn = vi.spyOn(console, "warn").mockImplementation(() => {}); const acc = new GorpStreamAccumulator({ list: ["a"] }, { strict: false }); acc.append([{ type: "set", path: ["list", "5"], value: "b" }]); expect(acc.state).toEqual({ list: ["a", "b"] }); expect(warn).toHaveBeenCalledOnce(); warn.mockRestore(); }); it("skips non-numeric array indices", () => { const error = vi.spyOn(console, "error").mockImplementation(() => {}); const acc = new GorpStreamAccumulator({ list: ["a"] }, { strict: false }); acc.append([{ type: "set", path: ["list", "x"], value: "b" }]); expect(acc.state).toEqual({ list: ["a"] }); expect(error).toHaveBeenCalledOnce(); error.mockRestore(); }); it("skips fractional array indices", () => { const error = vi.spyOn(console, "error").mockImplementation(() => {}); const acc = new GorpStreamAccumulator( { list: ["a", "b"] }, { strict: false }, ); acc.append([{ type: "set", path: ["list", "0.5"], value: "x" }]); expect(acc.state).toEqual({ list: ["a", "b"] }); expect(error).toHaveBeenCalledOnce(); error.mockRestore(); }); it("skips empty and non-canonical numeric array indices", () => { const error = vi.spyOn(console, "error").mockImplementation(() => {}); const acc = new GorpStreamAccumulator( { list: ["a", "b"] }, { strict: false }, ); acc.append([ { type: "set", path: ["list", ""], value: "x" }, { type: "set", path: ["list", " "], value: "x" }, { type: "set", path: ["list", "1e0"], value: "x" }, { type: "set", path: ["list", "01"], value: "x" }, ]); expect(acc.state).toEqual({ list: ["a", "b"] }); expect(error).toHaveBeenCalledTimes(4); error.mockRestore(); }); it("skips negative array indices", () => { const error = vi.spyOn(console, "error").mockImplementation(() => {}); const acc = new GorpStreamAccumulator({ list: ["a"] }, { strict: false }); acc.append([{ type: "set", path: ["list", "-1"], value: "b" }]); expect(acc.state).toEqual({ list: ["a"] }); expect(error).toHaveBeenCalledOnce(); }); }); it("accepts numeric index segments from the wire", () => { const acc = new GorpStreamAccumulator({ list: ["a", "b"] }); acc.append([ { type: "set", path: ["list", 0] as unknown as string[], value: "x" }, ]); expect(acc.state).toEqual({ list: ["x", "b"] }); }); it("throws on fractional array indices by default", () => { const acc = new GorpStreamAccumulator({ list: ["a", "b"] }); expect(() => acc.append([{ type: "set", path: ["list", "0.5"], value: "x" }]), ).toThrow(/Expected array index/); }); it("throws on an empty-string array index by default", () => { const acc = new GorpStreamAccumulator({ list: ["a", "b"] }); expect(() => acc.append([{ type: "set", path: ["list", ""], value: "x" }]), ).toThrow(/Expected array index/); expect(acc.state).toEqual({ list: ["a", "b"] }); }); it("throws on out-of-bounds array inserts by default", () => { const acc = new GorpStreamAccumulator({ list: ["a"] }); expect(() => acc.append([{ type: "set", path: ["list", "5"], value: "b" }]), ).toThrow(/out of bounds/); }); });