mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Terminal snapshots now carry soft-wrap row metadata only to clients that advertise support, so restored output can resize like live output without breaking older clients.
203 lines
5.4 KiB
TypeScript
203 lines
5.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { AgentTimelineItemPayloadSchema } from "./messages.js";
|
|
|
|
function canonicalBase() {
|
|
return {
|
|
type: "tool_call" as const,
|
|
callId: "call_123",
|
|
name: "shell",
|
|
detail: {
|
|
type: "shell" as const,
|
|
command: "pwd",
|
|
},
|
|
};
|
|
}
|
|
|
|
describe("shared messages tool_call schema", () => {
|
|
it("parses each status-discriminated tool_call variant at runtime", () => {
|
|
const running = AgentTimelineItemPayloadSchema.parse({
|
|
...canonicalBase(),
|
|
status: "running",
|
|
error: null,
|
|
});
|
|
|
|
const completed = AgentTimelineItemPayloadSchema.parse({
|
|
...canonicalBase(),
|
|
status: "completed",
|
|
error: null,
|
|
});
|
|
|
|
const failed = AgentTimelineItemPayloadSchema.parse({
|
|
...canonicalBase(),
|
|
status: "failed",
|
|
error: { message: "command failed" },
|
|
});
|
|
|
|
const canceled = AgentTimelineItemPayloadSchema.parse({
|
|
...canonicalBase(),
|
|
status: "canceled",
|
|
error: null,
|
|
});
|
|
|
|
expect(running.type).toBe("tool_call");
|
|
expect(completed.type).toBe("tool_call");
|
|
expect(failed.type).toBe("tool_call");
|
|
expect(canceled.type).toBe("tool_call");
|
|
});
|
|
|
|
it("rejects non-recoverable invalid tool_call payloads", () => {
|
|
const missingCallId = AgentTimelineItemPayloadSchema.safeParse({
|
|
type: "tool_call",
|
|
name: "shell",
|
|
status: "running",
|
|
detail: {
|
|
type: "shell",
|
|
command: "pwd",
|
|
},
|
|
error: null,
|
|
});
|
|
|
|
const unknownStatus = AgentTimelineItemPayloadSchema.safeParse({
|
|
...canonicalBase(),
|
|
status: "mystery_status",
|
|
error: null,
|
|
});
|
|
|
|
expect(missingCallId.success).toBe(false);
|
|
expect(unknownStatus.success).toBe(false);
|
|
});
|
|
|
|
it("ignores unknown top-level fields on tool_call payloads", () => {
|
|
// Non-strict protocol: extra top-level keys are stripped, not rejected.
|
|
const parsed = AgentTimelineItemPayloadSchema.safeParse({
|
|
...canonicalBase(),
|
|
status: "running",
|
|
error: null,
|
|
input: { command: "pwd" },
|
|
output: { exitCode: 0 },
|
|
});
|
|
|
|
expect(parsed.success).toBe(true);
|
|
});
|
|
|
|
it("rejects legacy status/error combinations without normalization", () => {
|
|
const completedWithError = AgentTimelineItemPayloadSchema.safeParse({
|
|
...canonicalBase(),
|
|
status: "completed",
|
|
error: { message: "unexpected" },
|
|
});
|
|
|
|
const failedWithoutError = AgentTimelineItemPayloadSchema.safeParse({
|
|
...canonicalBase(),
|
|
status: "failed",
|
|
error: null,
|
|
});
|
|
|
|
const missingDetail = AgentTimelineItemPayloadSchema.safeParse({
|
|
type: "tool_call",
|
|
callId: "call_missing_detail",
|
|
name: "shell",
|
|
status: "running",
|
|
error: null,
|
|
});
|
|
|
|
const legacyStatus = AgentTimelineItemPayloadSchema.safeParse({
|
|
...canonicalBase(),
|
|
status: "inProgress",
|
|
error: null,
|
|
});
|
|
|
|
expect(completedWithError.success).toBe(false);
|
|
expect(failedWithoutError.success).toBe(false);
|
|
expect(missingDetail.success).toBe(false);
|
|
expect(legacyStatus.success).toBe(false);
|
|
});
|
|
|
|
it("parses canonical sub_agent detail payload", () => {
|
|
const parsed = AgentTimelineItemPayloadSchema.parse({
|
|
type: "tool_call",
|
|
callId: "call_sub_agent_1",
|
|
name: "Task",
|
|
status: "running",
|
|
error: null,
|
|
detail: {
|
|
type: "sub_agent",
|
|
subAgentType: "Explore",
|
|
description: "Inspect repository structure",
|
|
log: "[Read] README.md\n[Bash] ls",
|
|
},
|
|
});
|
|
|
|
expect(parsed.type).toBe("tool_call");
|
|
if (parsed.type === "tool_call") {
|
|
expect(parsed.detail.type).toBe("sub_agent");
|
|
if (parsed.detail.type === "sub_agent") {
|
|
expect(parsed.detail.subAgentType).toBe("Explore");
|
|
}
|
|
}
|
|
});
|
|
|
|
it("parses sub_agent detail without structured actions", () => {
|
|
const parsed = AgentTimelineItemPayloadSchema.parse({
|
|
type: "tool_call",
|
|
callId: "call_sub_agent_legacy",
|
|
name: "Task",
|
|
status: "running",
|
|
error: null,
|
|
detail: {
|
|
type: "sub_agent",
|
|
subAgentType: "Explore",
|
|
description: "Inspect repository structure",
|
|
log: "[Read] README.md",
|
|
},
|
|
});
|
|
|
|
expect(parsed.type).toBe("tool_call");
|
|
if (parsed.type === "tool_call") {
|
|
expect(parsed.detail.type).toBe("sub_agent");
|
|
if (parsed.detail.type === "sub_agent") {
|
|
expect(parsed.detail.log).toBe("[Read] README.md");
|
|
}
|
|
}
|
|
});
|
|
|
|
it("parses plain_text detail with icon and rejects unknown icon names", () => {
|
|
const parsed = AgentTimelineItemPayloadSchema.parse({
|
|
type: "tool_call",
|
|
callId: "call_plain_text_1",
|
|
name: "task_notification",
|
|
status: "completed",
|
|
error: null,
|
|
detail: {
|
|
type: "plain_text",
|
|
label: "Background task completed",
|
|
icon: "wrench",
|
|
},
|
|
});
|
|
|
|
expect(parsed.type).toBe("tool_call");
|
|
if (parsed.type === "tool_call") {
|
|
expect(parsed.detail.type).toBe("plain_text");
|
|
if (parsed.detail.type === "plain_text") {
|
|
expect(parsed.detail.icon).toBe("wrench");
|
|
}
|
|
}
|
|
|
|
const invalid = AgentTimelineItemPayloadSchema.safeParse({
|
|
type: "tool_call",
|
|
callId: "call_plain_text_invalid",
|
|
name: "task_notification",
|
|
status: "completed",
|
|
error: null,
|
|
detail: {
|
|
type: "plain_text",
|
|
label: "Background task completed",
|
|
icon: "laser",
|
|
},
|
|
});
|
|
|
|
expect(invalid.success).toBe(false);
|
|
});
|
|
});
|