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%
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