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%
8.1 KB · 282 lines typescript
Raw Blame History
1/**2 * KHAELOR3 * File: tests/session/fixtures.ts4 * Description: Test fixtures — one realistic sample for every durable and ephemeral event type.5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910import { EVENT_SCHEMA_VERSION } from "../../src/session/events.js";11import type {12  DurableEvent,13  DurableEventInput,14  EphemeralEvent,15  EphemeralEventInput,16} from "../../src/session/events.js";17import { ulid } from "../../src/shared/index.js";1819export const SESSION_ID = "01TESTSESSION0000000000000";2021export function envelope<T extends DurableEventInput>(seq: number, input: T): DurableEvent {22  return {23    v: EVENT_SCHEMA_VERSION,24    id: ulid(),25    sessionId: SESSION_ID,26    seq,27    ts: 1_700_000_000_000 + seq,28    type: input.type,29    payload: input.payload,30  } as DurableEvent;31}3233export function ephemeralEnvelope<T extends EphemeralEventInput>(input: T): EphemeralEvent {34  return {35    id: ulid(),36    sessionId: SESSION_ID,37    ts: 1_700_000_000_000,38    type: input.type,39    payload: input.payload,40  } as EphemeralEvent;41}4243/** One input per durable event type — 32 total, matching DURABLE_EVENT_TYPES. */44export function sampleDurableInputs(): DurableEventInput[] {45  return [46    {47      type: "session.started",48      payload: {49        title: "Fix the session store",50        projectHash: "abc123",51        workingDirectory: "/home/user/project",52        gitBranch: "main",53        model: "claude-sonnet-4-5",54        auxModel: "claude-haiku-4-5",55        khaelorVersion: "0.1.0",56      },57    },58    {59      type: "session.resumed",60      payload: {61        khaelorVersion: "0.1.0",62        replayedSeq: 42,63        model: "claude-sonnet-4-5",64        toolNames: ["read", "write", "edit", "grep", "glob", "bash", "process"],65      },66    },67    { type: "session.renamed", payload: { title: "New title" } },68    {69      type: "session.model-changed",70      payload: { from: "claude-sonnet-4-5", to: "claude-opus-4-6", reason: "user" },71    },72    {73      type: "git.baseline-recorded",74      payload: {75        when: "session-start",76        baseline: {77          branch: "main",78          dirtyFiles: ["src/a.ts"],79          untrackedFiles: ["notes.txt"],80          diffHash: "deadbeef",81        },82      },83    },84    {85      type: "user.message-created",86      payload: {87        text: "Fix the bug in @src/store.ts",88        mentions: [{ path: "src/store.ts", range: { start: 10, end: 20 } }],89      },90    },91    { type: "user.steering-queued", payload: { text: "Also add tests" } },92    {93      type: "user.steering-injected",94      payload: { queuedEventId: "01QUEUED000000000000000000", seam: "post-tool-batch", afterSeq: 7 },95    },96    { type: "user.interrupted", payload: { scope: "turn", pendingToolUseIds: ["toolu_1"] } },97    {98      type: "model.request-started",99      payload: {100        requestId: "req_1",101        model: "claude-sonnet-4-5",102        purpose: "main",103        contextStats: {104          estimatedInputTokens: 1234,105          sections: [{ name: "system", estimatedTokens: 400 }],106        },107      },108    },109    {110      type: "model.text-block-completed",111      payload: { requestId: "req_1", blockIndex: 1, text: "I found the bug." },112    },113    {114      type: "model.thinking-block-completed",115      payload: { requestId: "req_1", blockIndex: 0, thinking: "Let me check…", signature: "sig_abc" },116    },117    {118      type: "tool.requested",119      payload: {120        requestId: "req_1",121        blockIndex: 2,122        toolUseId: "toolu_1",123        toolName: "read",124        input: { path: "src/store.ts" },125      },126    },127    {128      type: "model.response-completed",129      payload: {130        requestId: "req_1",131        stopReason: "tool_use",132        usage: { inputTokens: 100, outputTokens: 50, cacheReadTokens: 80, cacheWriteTokens: 20 },133        durationMs: 1500,134      },135    },136    {137      type: "model.request-failed",138      payload: {139        requestId: "req_2",140        kind: "retryable",141        message: "overloaded",142        status: 529,143        retriesExhausted: false,144      },145    },146    {147      type: "permission.requested",148      payload: {149        permissionRequestId: "perm_1",150        toolUseId: "toolu_2",151        capability: "process.execute",152        descriptor: "Run `npm install` in ~/project",153        suggestion: { capability: "process.execute", pattern: "npm install *" },154      },155    },156    { type: "permission.granted", payload: { permissionRequestId: "perm_1", scope: "once" } },157    {158      type: "permission.denied",159      payload: { permissionRequestId: "perm_2", source: "user", feedback: "Do not run that." },160    },161    { type: "tool.approved", payload: { toolUseId: "toolu_1", via: "policy-allow" } },162    { type: "tool.started", payload: { toolUseId: "toolu_1", toolName: "read" } },163    {164      type: "tool.completed",165      payload: {166        toolUseId: "toolu_1",167        modelText: "1  const x = 1;",168        spillFile: "/home/user/.khaelor/spill/toolu_1.txt",169        durationMs: 12,170        ui: { kind: "read", summary: "Read src/store.ts", matchCount: 0 },171      },172    },173    {174      type: "tool.failed",175      payload: {176        toolUseId: "toolu_2",177        modelText: "File not found: src/missing.ts",178        errorKind: "not-found",179        durationMs: 3,180      },181    },182    {183      type: "tool.cancelled",184      payload: {185        toolUseId: "toolu_3",186        reason: "interrupted",187        modelText: "[Tool execution cancelled by user]",188      },189    },190    {191      type: "file.read",192      payload: {193        path: "src/store.ts",194        range: { start: 1, end: 50 },195        bytes: 2048,196        mtimeMs: 1_700_000_000_000,197        toolUseId: "toolu_1",198      },199    },200    {201      type: "file.modified",202      payload: {203        path: "src/store.ts",204        operation: "edit",205        diffStats: { added: 3, removed: 1 },206        diff: "--- a/src/store.ts\n+++ b/src/store.ts\n",207        toolUseId: "toolu_4",208      },209    },210    {211      type: "process.started",212      payload: {213        processId: "proc_1",214        pid: 4242,215        command: "npm run dev",216        cwd: "/home/user/project",217        name: "dev-server",218        toolUseId: "toolu_5",219      },220    },221    {222      type: "process.exited",223      payload: { processId: "proc_1", exitCode: 0, cause: "exited", durationMs: 60000 },224    },225    {226      type: "context.pruned",227      payload: {228        toolUseIds: ["toolu_1"],229        placeholder: "[Old tool result removed to save context]",230        tokensReclaimedEstimate: 900,231      },232    },233    {234      type: "context.compacted",235      payload: {236        checkpointYaml: "objective: fix the bug\ncompleted: []\n",237        cut: { fromSeq: 2, toSeq: 9 },238        trigger: "proactive-token-budget",239        tokensBefore: 150000,240        summaryModel: "claude-haiku-4-5",241      },242    },243    {244      type: "task.verification-requested",245      payload: { attempt: 1, detectedChecks: ["npm test"], withheldCandidateSeq: 30 },246    },247    {248      type: "task.completed",249      payload: {250        evidence: {251          objective: "Fix the bug",252          changedFiles: ["src/store.ts"],253          checks: [{ command: "npm test", exitCode: 0, summary: "12 passed", durationMs: 2100 }],254          unresolvedIssues: [],255        },256      },257    },258    {259      type: "task.failed",260      payload: { reason: "iteration-budget-exhausted", detail: "gave up after 50 iterations" },261    },262  ];263}264265/** One input per ephemeral event type — 6 total, matching EPHEMERAL_EVENT_TYPES. */266export function sampleEphemeralInputs(): EphemeralEventInput[] {267  return [268    { type: "model.text-delta", payload: { requestId: "req_1", blockIndex: 1, text: "Hel" } },269    { type: "model.thinking-delta", payload: { requestId: "req_1", blockIndex: 0, text: "hmm" } },270    {271      type: "model.tool-call-started",272      payload: { requestId: "req_1", blockIndex: 2, toolUseId: "toolu_1", toolName: "read" },273    },274    {275      type: "model.tool-input-delta",276      payload: { requestId: "req_1", blockIndex: 2, toolUseId: "toolu_1", partialJson: '{"pa' },277    },278    { type: "tool.output", payload: { toolUseId: "toolu_1", chunk: "line 1\n" } },279    { type: "process.output", payload: { processId: "proc_1", stream: "stdout", chunk: "ready\n" } },280  ];281}282