generated from nhcarrigan/template
feat: start setting up CI
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { mapMessageToState, extractTextFromMessage, extractToolInfo } from "./stateMapper";
|
||||
import type { ClaudeStreamMessage, AssistantMessage } from "$lib/types/messages";
|
||||
|
||||
describe("stateMapper", () => {
|
||||
describe("mapMessageToState", () => {
|
||||
it("returns idle for system init message", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "system",
|
||||
subtype: "init",
|
||||
session_id: "test-session",
|
||||
};
|
||||
expect(mapMessageToState(message)).toBe("idle");
|
||||
});
|
||||
|
||||
it("returns null for non-init system messages", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "system",
|
||||
subtype: "other",
|
||||
session_id: "test-session",
|
||||
};
|
||||
expect(mapMessageToState(message)).toBeNull();
|
||||
});
|
||||
|
||||
it("returns searching for Read tool", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "assistant",
|
||||
message: {
|
||||
id: "test",
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
content: [
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "tool-1",
|
||||
name: "Read",
|
||||
input: { file_path: "/test/file.txt" },
|
||||
},
|
||||
],
|
||||
model: "claude-3",
|
||||
stop_reason: "tool_use",
|
||||
usage: { input_tokens: 100, output_tokens: 50 },
|
||||
},
|
||||
};
|
||||
expect(mapMessageToState(message)).toBe("searching");
|
||||
});
|
||||
|
||||
it("returns coding for Edit tool", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "assistant",
|
||||
message: {
|
||||
id: "test",
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
content: [
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "tool-1",
|
||||
name: "Edit",
|
||||
input: { file_path: "/test/file.txt", old_string: "foo", new_string: "bar" },
|
||||
},
|
||||
],
|
||||
model: "claude-3",
|
||||
stop_reason: "tool_use",
|
||||
usage: { input_tokens: 100, output_tokens: 50 },
|
||||
},
|
||||
};
|
||||
expect(mapMessageToState(message)).toBe("coding");
|
||||
});
|
||||
|
||||
it("returns mcp for mcp__ prefixed tools", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "assistant",
|
||||
message: {
|
||||
id: "test",
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
content: [
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "tool-1",
|
||||
name: "mcp__github__list_repos",
|
||||
input: {},
|
||||
},
|
||||
],
|
||||
model: "claude-3",
|
||||
stop_reason: "tool_use",
|
||||
usage: { input_tokens: 100, output_tokens: 50 },
|
||||
},
|
||||
};
|
||||
expect(mapMessageToState(message)).toBe("mcp");
|
||||
});
|
||||
|
||||
it("returns thinking for Task tool", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "assistant",
|
||||
message: {
|
||||
id: "test",
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
content: [
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "tool-1",
|
||||
name: "Task",
|
||||
input: { prompt: "test task" },
|
||||
},
|
||||
],
|
||||
model: "claude-3",
|
||||
stop_reason: "tool_use",
|
||||
usage: { input_tokens: 100, output_tokens: 50 },
|
||||
},
|
||||
};
|
||||
expect(mapMessageToState(message)).toBe("thinking");
|
||||
});
|
||||
|
||||
it("returns typing for text content", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "assistant",
|
||||
message: {
|
||||
id: "test",
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "Hello, Naomi!" }],
|
||||
model: "claude-3",
|
||||
stop_reason: "end_turn",
|
||||
usage: { input_tokens: 100, output_tokens: 50 },
|
||||
},
|
||||
};
|
||||
expect(mapMessageToState(message)).toBe("typing");
|
||||
});
|
||||
|
||||
it("returns success for result success message", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "result",
|
||||
subtype: "success",
|
||||
result: "Task completed",
|
||||
session_id: "test-session",
|
||||
};
|
||||
expect(mapMessageToState(message)).toBe("success");
|
||||
});
|
||||
|
||||
it("returns error for result error message", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "result",
|
||||
subtype: "error_max_turns",
|
||||
error: "Max turns exceeded",
|
||||
session_id: "test-session",
|
||||
};
|
||||
expect(mapMessageToState(message)).toBe("error");
|
||||
});
|
||||
|
||||
it("returns null for user messages", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "user",
|
||||
message: { role: "user", content: "Hello" },
|
||||
};
|
||||
expect(mapMessageToState(message)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractTextFromMessage", () => {
|
||||
it("extracts text from assistant message", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "assistant",
|
||||
message: {
|
||||
id: "test",
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
content: [
|
||||
{ type: "text", text: "Hello!" },
|
||||
{ type: "text", text: "How are you?" },
|
||||
],
|
||||
model: "claude-3",
|
||||
stop_reason: "end_turn",
|
||||
usage: { input_tokens: 100, output_tokens: 50 },
|
||||
},
|
||||
};
|
||||
expect(extractTextFromMessage(message)).toBe("Hello!\nHow are you?");
|
||||
});
|
||||
|
||||
it("returns null for assistant message without text", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "assistant",
|
||||
message: {
|
||||
id: "test",
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
content: [
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "tool-1",
|
||||
name: "Read",
|
||||
input: { file_path: "/test/file.txt" },
|
||||
},
|
||||
],
|
||||
model: "claude-3",
|
||||
stop_reason: "tool_use",
|
||||
usage: { input_tokens: 100, output_tokens: 50 },
|
||||
},
|
||||
};
|
||||
expect(extractTextFromMessage(message)).toBeNull();
|
||||
});
|
||||
|
||||
it("extracts text from stream_event delta", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "stream_event",
|
||||
event: {
|
||||
type: "content_block_delta",
|
||||
index: 0,
|
||||
delta: { type: "text_delta", text: "streaming text" },
|
||||
},
|
||||
};
|
||||
expect(extractTextFromMessage(message)).toBe("streaming text");
|
||||
});
|
||||
|
||||
it("extracts result from result message", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "result",
|
||||
subtype: "success",
|
||||
result: "Completed successfully",
|
||||
session_id: "test-session",
|
||||
};
|
||||
expect(extractTextFromMessage(message)).toBe("Completed successfully");
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractToolInfo", () => {
|
||||
it("extracts tool info from assistant message", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "assistant",
|
||||
message: {
|
||||
id: "test",
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
content: [
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "tool-1",
|
||||
name: "Read",
|
||||
input: { file_path: "/test/file.txt" },
|
||||
},
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "tool-2",
|
||||
name: "Edit",
|
||||
input: { file_path: "/test/file.txt", old_string: "a", new_string: "b" },
|
||||
},
|
||||
],
|
||||
model: "claude-3",
|
||||
stop_reason: "tool_use",
|
||||
usage: { input_tokens: 100, output_tokens: 50 },
|
||||
},
|
||||
};
|
||||
const tools = extractToolInfo(message);
|
||||
expect(tools).toHaveLength(2);
|
||||
expect(tools[0]).toEqual({
|
||||
name: "Read",
|
||||
input: { file_path: "/test/file.txt" },
|
||||
});
|
||||
expect(tools[1]).toEqual({
|
||||
name: "Edit",
|
||||
input: { file_path: "/test/file.txt", old_string: "a", new_string: "b" },
|
||||
});
|
||||
});
|
||||
|
||||
it("returns empty array for non-assistant messages", () => {
|
||||
const message: ClaudeStreamMessage = {
|
||||
type: "user",
|
||||
message: { role: "user", content: "Hello" },
|
||||
};
|
||||
expect(extractToolInfo(message)).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user