SPB Git

spb/khaelor Public

KHAELOR — a terminal-native autonomous engineering agent powered by Anthropic.

TypeScript 82.9% HTML 14.9% CSS 1.1% JavaScript 0.7%
4.4 KB · 126 lines typescript
Raw Blame History
1/**2 * KHAELOR3 * File: tests/cli/print.test.ts4 * Description: --print helpers — final-answer extraction from the durable stream, log redaction.5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910import { describe, expect, it } from "vitest";11import { redactForLog } from "../../src/cli/logger.js";12import { finalAnswerText } from "../../src/cli/print.js";13import { renderResumedTranscript } from "../../src/cli/sessions.js";14import type { DurableEvent } from "../../src/session/index.js";15import { envelope } from "../session/fixtures.js";1617function turnEvents(): DurableEvent[] {18  return [19    envelope(1, { type: "user.message-created", payload: { text: "what is in the file?", mentions: [] } }),20    envelope(2, {21      type: "model.request-started",22      payload: { requestId: "req-1", model: "m", purpose: "main", contextStats: { estimatedInputTokens: 1, sections: [] } },23    }),24    envelope(3, {25      type: "model.text-block-completed",26      payload: { requestId: "req-1", blockIndex: 0, text: "Let me read it." },27    }),28    envelope(4, {29      type: "tool.requested",30      payload: { requestId: "req-1", blockIndex: 1, toolUseId: "t1", toolName: "read", input: { file_path: "x" } },31    }),32    envelope(5, {33      type: "model.response-completed",34      payload: {35        requestId: "req-1",36        stopReason: "tool_use",37        usage: { inputTokens: 1, outputTokens: 1, cacheReadTokens: 0, cacheWriteTokens: 0 },38        durationMs: 5,39      },40    }),41    envelope(6, {42      type: "tool.completed",43      payload: { toolUseId: "t1", modelText: "codeword: AZURE-FALCON", durationMs: 3, ui: { kind: "read", summary: "Read x" } },44    }),45    envelope(7, {46      type: "model.request-started",47      payload: { requestId: "req-2", model: "m", purpose: "main", contextStats: { estimatedInputTokens: 1, sections: [] } },48    }),49    envelope(8, {50      type: "model.text-block-completed",51      payload: { requestId: "req-2", blockIndex: 0, text: "The codeword is AZURE-FALCON." },52    }),53    envelope(9, {54      type: "model.response-completed",55      payload: {56        requestId: "req-2",57        stopReason: "end_turn",58        usage: { inputTokens: 1, outputTokens: 1, cacheReadTokens: 0, cacheWriteTokens: 0 },59        durationMs: 5,60      },61    }),62  ];63}6465describe("finalAnswerText", () => {66  it("returns the text of the last non-tool_use response, not intermediate turns", () => {67    expect(finalAnswerText(turnEvents())).toBe("The codeword is AZURE-FALCON.");68  });6970  it("joins multiple settled blocks in block order", () => {71    const events = [72      ...turnEvents(),73      envelope(10, {74        type: "model.request-started",75        payload: { requestId: "req-3", model: "m", purpose: "main", contextStats: { estimatedInputTokens: 1, sections: [] } },76      }),77      envelope(11, {78        type: "model.text-block-completed",79        payload: { requestId: "req-3", blockIndex: 1, text: "second" },80      }),81      envelope(12, {82        type: "model.text-block-completed",83        payload: { requestId: "req-3", blockIndex: 0, text: "first" },84      }),85      envelope(13, {86        type: "model.response-completed",87        payload: {88          requestId: "req-3",89          stopReason: "end_turn",90          usage: { inputTokens: 1, outputTokens: 1, cacheReadTokens: 0, cacheWriteTokens: 0 },91          durationMs: 5,92        },93      }),94    ];95    expect(finalAnswerText(events)).toBe("first\nsecond");96  });9798  it("is empty when no response completed the turn", () => {99    expect(finalAnswerText(turnEvents().slice(0, 5))).toBe("");100  });101});102103describe("resumed transcript", () => {104  it("shows user, assistant, and tool entries compactly", () => {105    const lines = renderResumedTranscript(turnEvents()).join("\n");106    expect(lines).toContain("❯ what is in the file?");107    expect(lines).toContain("▸ Read x");108    expect(lines).toContain("The codeword is AZURE-FALCON.");109  });110});111112describe("log redaction", () => {113  it("removes API keys and authorization material", () => {114    const dirty =115      "request failed authorization: Bearer abc123def456ghi with key sk-ant-api03-SECRETSECRET and x-api-key: sk-ant-other";116    const clean = redactForLog(dirty);117    expect(clean).not.toContain("sk-ant-api03-SECRETSECRET");118    expect(clean).not.toContain("abc123def456ghi");119    expect(clean).toContain("[redacted]");120  });121122  it("leaves ordinary text untouched", () => {123    expect(redactForLog("tool read completed in 12ms")).toBe("tool read completed in 12ms");124  });125});126