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%
6.6 KB · 187 lines typescript
Raw Blame History
1/**2 * KHAELOR3 * File: src/anthropic/types.ts4 * Description: Model Runtime types — ModelClient, ModelRequest, ModelEvent stream vocabulary, honest usage (ARCHITECTURE.md §7).5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910// Layer 1 — this module imports `shared` only (plus @anthropic-ai/sdk).11// It therefore owns its own copies of the model-facing vocabulary; the12// session event catalog mirrors these shapes (EVENT_MODEL.md §4), and the13// agent-layer reducer maps ModelEvents onto session events:14//15//   started                  → ModelRequestStarted16//   text-delta               → ModelTextDelta            (ephemeral)17//   thinking-delta           → ModelThinkingDelta        (ephemeral)18//   tool-call-started        → ToolCallStarted           (ephemeral)19//   tool-input-delta         → ToolInputDelta            (ephemeral)20//   text-block-completed     → ModelTextBlockCompleted   (durable)21//   thinking-block-completed → ModelThinkingBlockCompleted (durable)22//   tool-call-completed      → ToolRequested             (durable)23//   completed                → ModelResponseCompleted    (durable)2425// ───────────────────────── stop reason and usage ─────────────────────────2627/** Normalized stop reason (EVENT_MODEL.md §4). */28export type StopReason = "end_turn" | "tool_use" | "max_tokens" | "refusal";2930/**31 * Real API usage only — never estimated (Absolute Rule #4).32 * Field sources (Anthropic Messages API `usage` object):33 *   inputTokens      ← input_tokens34 *   outputTokens     ← output_tokens35 *   cacheReadTokens  ← cache_read_input_tokens36 *   cacheWriteTokens ← cache_creation_input_tokens37 */38export interface ModelUsage {39  inputTokens: number;40  outputTokens: number;41  cacheReadTokens: number;42  cacheWriteTokens: number;43}4445// ───────────────────────── request shapes ─────────────────────────4647/** `{ type: "ephemeral" }` cache breakpoint marker (prompt caching). */48export interface CacheControl {49  type: "ephemeral";50}5152/**53 * One stable system-prompt tier (ADR-7): [identity/behavior] →54 * [tool guidance] → [project instructions]. Built once per session,55 * never re-rendered; cache breakpoints are placed at tier ends.56 */57export interface SystemTier {58  /** Stable label for /context stats — e.g. "identity", "project-instructions". */59  name: string;60  text: string;61}6263/** Text content block. */64export interface TextBlockParam {65  type: "text";66  text: string;67  cache_control?: CacheControl;68}6970/** Thinking block — replayed byte-exact (thinking + signature) in tool loops. */71export interface ThinkingBlockParam {72  type: "thinking";73  thinking: string;74  signature: string;75}7677/** Redacted thinking block — opaque, replayed verbatim. */78export interface RedactedThinkingBlockParam {79  type: "redacted_thinking";80  data: string;81}8283/** Assistant tool_use block. */84export interface ToolUseBlockParam {85  type: "tool_use";86  id: string;87  name: string;88  input: unknown;89  cache_control?: CacheControl;90}9192/** User tool_result block — pairs with a tool_use id. */93export interface ToolResultBlockParam {94  type: "tool_result";95  tool_use_id: string;96  content: string | TextBlockParam[];97  is_error?: boolean;98  cache_control?: CacheControl;99}100101export type ContentBlockParam =102  | TextBlockParam103  | ThinkingBlockParam104  | RedactedThinkingBlockParam105  | ToolUseBlockParam106  | ToolResultBlockParam;107108/** One message of the byte-stable LlmHistory projection (ARCHITECTURE.md §6.5). */109export interface AnthropicMessage {110  role: "user" | "assistant";111  content: ContentBlockParam[];112}113114/** Tool schema handed to the API (≤5 properties per ADR-8; enforced upstream). */115export interface ToolSchema {116  name: string;117  description: string;118  /** JSON Schema for the tool input (`input_schema` on the wire). */119  inputSchema: Record<string, unknown>;120}121122/** Extended-thinking configuration. */123export type ThinkingConfig =124  | { mode: "enabled"; budgetTokens: number }125  | { mode: "disabled" };126127/** The assembled model request (ARCHITECTURE.md §7). */128export interface ModelRequest {129  model: string;130  /** Stable tiers; cache_control breakpoints are planned by caching.ts. */131  system: SystemTier[];132  /** Byte-stable projection (§6.5) — never mutated by the client. */133  messages: AnthropicMessage[];134  tools: ToolSchema[];135  maxOutputTokens: number;136  thinking?: ThinkingConfig;137}138139// ───────────────────────── the event stream ─────────────────────────140141/**142 * Events produced by ModelClient.stream(). Errors are NOT events: the143 * async iterable throws a typed ModelError (errors.ts) which the kernel144 * classifies (ARCHITECTURE.md §4.2 / §7).145 */146export type ModelEvent =147  | { type: "started"; requestId: string }148  | { type: "text-delta"; blockIndex: number; text: string }149  | { type: "thinking-delta"; blockIndex: number; text: string }150  | { type: "tool-call-started"; blockIndex: number; toolUseId: string; toolName: string }151  | { type: "tool-input-delta"; blockIndex: number; toolUseId: string; partialJson: string }152  | { type: "text-block-completed"; blockIndex: number; text: string }153  | { type: "thinking-block-completed"; blockIndex: number; thinking: string; signature: string }154  | {155      type: "tool-call-completed";156      blockIndex: number;157      toolUseId: string;158      toolName: string;159      /** Complete parsed input, accumulated across input_json_delta chunks. */160      input: unknown;161    }162  | {163      type: "completed";164      stopReason: StopReason;165      /** REAL usage from message_start/message_delta payloads — sole source for /cost. */166      usage: ModelUsage;167      durationMs: number;168    };169170// ───────────────────────── the client boundary ─────────────────────────171172/**173 * The single model boundary (CLAUDE.md §6, ADR-10). Anthropic-only in V1;174 * this interface exists for clean architecture, not multi-provider plumbing.175 */176export interface ModelClient {177  /**178   * Stream a completion. Cancellation is AbortSignal end to end: aborting179   * `signal` aborts the underlying HTTP request and the iterable throws180   * ModelError{kind:"cancelled"}.181   */182  stream(request: ModelRequest, signal?: AbortSignal): AsyncIterable<ModelEvent>;183184  /** Best-effort budgeting aid (real API count, no retry). */185  countTokens?(request: ModelRequest): Promise<number>;186}187