/** * Core type definitions for the context offload plugin. * Ported from context-offload-plugin with updated runtime defaults. */ // ============================ // Data types // ============================ /** A single offloaded tool call/result summary stored in offload.jsonl */ export interface OffloadEntry { /** ISO timestamp inherited from the original tool result */ timestamp: string; /** Mermaid node ID assigned by L2, null until L2 runs */ node_id: string | null; /** Short description of the tool call command */ tool_call: string; /** LLM-generated summary of the tool result */ summary: string; /** Relative path to the MD file containing the full tool result */ result_ref: string; /** The original tool call ID from the provider */ tool_call_id: string; /** Session key this entry belongs to */ session_key?: string; /** Replaceability score (0-10). Higher = summary can better replace original. Assigned by L1 LLM. */ score?: number; } /** A buffered tool call + result pair waiting to be processed by L1 */ export interface ToolPair { toolName: string; toolCallId: string; params: Record | string; result: unknown; error?: string; timestamp: string; durationMs?: number; } /** Persistent plugin state saved to state.json */ export interface PluginState { /** Path to the currently active MMD file (relative to mmds/) */ activeMmdFile: string | null; /** Identifier/label for the active MMD */ activeMmdId: string | null; /** Counter for auto-incrementing MMD filenames */ mmdCounter: number; /** Last session key the plugin was active in */ lastSessionKey: string | null; /** Last tool_call_id that was successfully offloaded into compact context (L3 cursor) */ lastOffloadedToolCallId: string | null; /** ISO timestamp of the last successful L2 trigger */ lastL2TriggerTime: string | null; } /** Metadata block embedded in MMD files */ export interface MmdMetadata { taskGoal: string; createdTime: string; updatedTime: string; } /** A node in the Mermaid flowchart */ export interface MmdNode { id: string; label: string; status: "done" | "doing" | "todo"; summary: string; timestamp: string; } // ============================ // LLM types // ============================ /** Configuration for the LLM client */ export interface LlmConfig { baseUrl: string; apiKey: string; model: string; } /** Result from L1.5 task judgment */ export interface TaskJudgment { /** Whether the current task is completed */ taskCompleted: boolean; /** Whether the new task is a continuation of a recent task */ isContinuation: boolean; /** If continuation, which MMD file to reactivate */ continuationMmdFile?: string; /** Short label for new task (used in MMD filename) */ newTaskLabel?: string; /** Whether this is a long task (vs. casual chat) */ isLongTask: boolean; } /** L1.5 boundary marker: divides entries into task-attributed segments. * Each boundary defines the ownership of entries from startIndex onward * until the next boundary's startIndex. */ export interface L15Boundary { /** Entry counter value when L1.5 judgment started. * Entries at this index and beyond belong to this boundary's result. */ startIndex: number; /** L1.5 judgment result for this segment */ result: "long" | "short" | "pending"; /** If result="long", the target MMD file for L2 to construct into */ targetMmd: string | null; } /** Result from an LLM call */ export interface LlmResponse { content: string; usage?: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number; }; } /** OpenClaw config model provider shape (minimal) */ export interface ModelProvider { baseUrl?: string; apiKey?: string; models?: Record; } // ============================ // Plugin configuration // ============================ /** * Plugin configuration, read from openclaw.json -> plugins.entries config. * All fields are optional; defaults are used when not specified. */ export interface PluginConfig { /** Explicit LLM model for offload tasks, format: "provider/model-id" (e.g. "dashscope/kimi-k2.5") */ model?: string; /** LLM temperature for offload tasks. Default: 0.2 */ temperature?: number; /** Force-trigger L1 when pending tool pairs >= this threshold. Default: 4 */ forceTriggerThreshold?: number; /** Custom data directory path (absolute). Default: ~/.openclaw/context-offload */ dataDir?: string; /** Default context window size when not found in model config. Default: 200000 */ defaultContextWindow?: number; /** Max tool pairs to process per L1 batch. Default: 20 */ maxPairsPerBatch?: number; /** Trigger L2 when offload.jsonl has >= this many node_id=null entries. Default: 4 */ l2NullThreshold?: number; /** Trigger L2 if it hasn't run for this many seconds. Default: 300 (5 minutes) */ l2TimeoutSeconds?: number; /** * If L2 leaves entries in `node_id="wait"` (e.g. parse/mapping failure), * those entries will be retried after waiting for at least this many seconds. * Default: 120 */ l2WaitRetrySeconds?: number; /** * If true (default), time-based L2 only runs when at least one `node_id=null` entry has * `timestamp` strictly after `lastL2TriggerTime` (i.e. new offload rows since last L2). * Does not affect condition A (null count threshold). Set false for legacy timeout retry of stale nulls. */ l2TimeTriggerRequiresNewOffload?: boolean; /** Mild offload: replace non-current-task tool results when context >= this ratio. Default: 0.5 */ mildOffloadRatio?: number; /** Mild offload scan range: scan the last N% of messages (0.7 = last 70%). Default: 0.7 */ mildOffloadScanRatio?: number; /** Mild offload phase-1: replace top N% highest-score (most replaceable) entries first. Default: 0.4 */ mildScoreTopRatio?: number; /** Mild offload: only trigger when current task messages occupy >= this ratio of total tokens. Default: 0.8 */ mildCurrentTaskRatio?: number; /** Aggressive compress: delete tail messages when context >= this ratio. Default: 0.85 */ aggressiveCompressRatio?: number; /** * Aggressive compress: target fraction of **message** tokens to remove from the **oldest** * messages each round (0.4 ≈ oldest 40% of total per-message token sum). Default: 0.4 */ aggressiveDeleteRatio?: number; /** Emergency trigger: when tokens >= contextWindow * emergencyCompressRatio, fire emergency. Default: 0.95 */ emergencyCompressRatio?: number; /** Emergency target: delete until tokens <= contextWindow * emergencyTargetRatio. Default: 0.6 */ emergencyTargetRatio?: number; /** Max ratio of total tokens that injected MMDs may occupy. Default: 0.2 */ mmdMaxTokenRatio?: number; /** * L3 token counting: `tiktoken` uses js-tiktoken (exact BPE for chosen encoding); * `heuristic` uses 中文/1.7 + 其余/4. Default: tiktoken. */ l3TokenCountMode?: "tiktoken" | "heuristic"; /** * tiktoken encoding when `l3TokenCountMode` is `tiktoken`. * Typical: `o200k_base` (GPT-4o/o-series), `cl100k_base` (GPT-4/3.5). Default: o200k_base. */ l3TiktokenEncoding?: | "gpt2" | "r50k_base" | "p50k_base" | "p50k_edit" | "cl100k_base" | "o200k_base"; /** * Default ratio of context window assumed to be system overhead (system prompt + * tool schemas). Used when no cached overhead is available from llm_input hook. * Default: 0.12 (12%). */ defaultSystemOverheadRatio?: number; } // ============================ // Logger interface // ============================ /** Logger interface used by offload plugin components */ export interface PluginLogger { info: (msg: string) => void; warn: (msg: string) => void; error: (msg: string) => void; debug?: (msg: string) => void; } // ============================ // Plugin defaults // ============================ /** Defaults for all configurable values (sourced from runtime .js) */ export const PLUGIN_DEFAULTS = { temperature: 0.2, forceTriggerThreshold: 4, defaultContextWindow: 200_000, maxPairsPerBatch: 20, l2NullThreshold: 4, l2TimeoutSeconds: 300, /** If L2 leaves entries in node_id="wait", retry after this many seconds */ l2WaitRetrySeconds: 120, /** When true, time-based L2 only fires if some node_id=null row is newer than last L2 */ l2TimeTriggerRequiresNewOffload: true, mildOffloadRatio: 0.5, mildOffloadScanRatio: 0.7, mildScoreTopRatio: 0.4, mildCurrentTaskRatio: 0.8, aggressiveCompressRatio: 0.85, aggressiveDeleteRatio: 0.4, /** Emergency trigger: when tokens >= contextWindow * 0.95, fire emergency */ emergencyCompressRatio: 0.95, /** Emergency target: delete until tokens <= contextWindow * 0.6 */ emergencyTargetRatio: 0.6, mmdMaxTokenRatio: 0.2, l3TokenCountMode: "tiktoken" as const, l3TiktokenEncoding: "cl100k_base" as const, defaultSystemOverheadRatio: 0.12, } as const;