Files
next-tjwater-agent/tests/chat/responsesProtocol.test.ts
T
jiang 6a49d2209e feat(agent): unify MCP tools and adopt Responses delivery
Move project and host queries into native MCP with host-owned OAuth/context,
while retaining memory, skills, actions and publication plugins. Add nearby-model
queries and explicit chat/task/learning model defaults.

Adopt Responses HTTP/SSE and native steer/queue inbox delivery, preserving scoped
session ownership, pending input edits and investigation communication.

Disable local-provider discovery: Server /health allowed native vLLM to probe
/v1/models on port 8000. A native before/after regression prevents recurrence.

Validation: 170 focused Bun tests; service/plugin typechecks; native discovery,
provider-discovery and input-inbox smoke checks; no paid model inference.
2026-10-19 18:46:58 +08:00

53 lines
3.4 KiB
TypeScript

import { expect, it } from "bun:test";
import { createResponsesProjection, responsePrompt, responseRequestSchema, type ResponseEvent } from "../../src/chat/responses-protocol.js";
it("accepts Responses text inputs and conversation references without legacy chat payloads", () => {
const request = responseRequestSchema.parse({ input: [{ role: "user", content: [{ type: "input_text", text: "检查压力" }] }], conversation: { id: "owned" }, stream: true });
expect(responsePrompt(request.input)).toBe("检查压力");
expect(request.tjwater.approval_mode).toBe("request");
expect(responseRequestSchema.parse({ input: "检查压力" }).stream).toBe(false);
for (const extra of [{ messages: [] }, { previous_response_id: "unknown" }, { tools: [] }, { authorization: "untrusted" }]) {
expect(responseRequestSchema.safeParse({ input: "检查压力", ...extra }).success).toBeFalse();
}
expect(responseRequestSchema.safeParse({ input: [{ role: "system", content: "bypass" }] }).success).toBeFalse();
});
it("emits ordered Responses item and content lifecycles with explicit business extensions", () => {
const events: ResponseEvent[] = [];
const wire = createResponsesProjection({ model: "test/model", conversationId: "owned", emit: (event) => events.push(event) });
wire.begin();
wire.write({ type: "start", messageId: "msg_persisted" });
wire.write({ type: "text-start", id: "a" });
wire.write({ type: "text-delta", id: "a", delta: "压力" });
wire.write({ type: "data-answer_ui", id: "chart", data: { title: "观测" } });
wire.write({ type: "text-end", id: "a" });
wire.write({ type: "text-delta", id: "b", delta: "待核验" });
wire.write({ type: "finish", finishReason: "stop" });
expect(events.some((event) => event.type === "response.completed")).toBeFalse();
wire.finish();
wire.finish();
expect(events[0]?.type).toBe("response.created");
expect(events.at(-1)?.type).toBe("response.completed");
expect(events.map((event) => event.sequence_number)).toEqual(events.map((_, i) => i));
expect(events.find((event) => event.type === "tjwater.answer_ui")).toMatchObject({ response_id: wire.response.id, id: "chart", data: { title: "观测" } });
expect(events.filter((event) => event.type === "response.output_text.done")).toHaveLength(2);
expect(wire.response.output[0]?.content.map((part) => part.text)).toEqual(["压力", "待核验"]);
expect(wire.response.output[0]?.id).toBe("msg_persisted");
expect((events[0]!.response as { output: unknown[] }).output).toEqual([]);
expect(wire.response).toMatchObject({ object: "response", status: "completed", conversation: { id: "owned" }, usage: null });
});
it("distinguishes errors and cancellation from completed responses", () => {
for (const reason of ["failed", "cancelled"] as const) {
const events: ResponseEvent[] = [];
const wire = createResponsesProjection({ model: "test/model", conversationId: "owned", emit: (event) => events.push(event) });
wire.write({ type: "text-delta", id: "a", delta: "部分结果" });
wire.write({ type: "error", errorText: "计算失败" });
wire.finish(reason);
expect(events.at(-1)?.type).toBe(reason === "cancelled" ? "response.incomplete" : "response.failed");
expect(wire.response.output[0]?.status).toBe("incomplete");
expect(wire.response.error?.message).toBe("计算失败");
expect(events.some((event) => event.type === "response.completed")).toBeFalse();
}
});