@theokit/sdk 4.15.4 → 4.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,6 +17,7 @@
17
17
  *
18
18
  * @internal
19
19
  */
20
+ export type { CompressibleMessage };
20
21
  /**
21
22
  * Typed error thrown when the compression LLM call fails or returns
22
23
  * an empty/ineffective summary. The caller catches and handles per
@@ -17,6 +17,15 @@ import type { SessionMessage } from "./session-types.js";
17
17
  export interface PersistTurnInput {
18
18
  userText: string;
19
19
  conversation: readonly ConversationTurn[];
20
+ /**
21
+ * M50 — when supplied, size-driven auto-compaction runs in the SAME write chain after the turn
22
+ * persists (usage real vs the model's context window; summarizer injected by the caller).
23
+ */
24
+ autoCompact?: {
25
+ usageTotal?: number | undefined;
26
+ contextWindow?: number | undefined;
27
+ summarize: (messages: readonly import("../../compaction.js").CompressibleMessage[]) => Promise<string>;
28
+ };
20
29
  }
21
30
  /**
22
31
  * The per-agent transcript metadata used to seed a {@link SessionTranscript}. The
@@ -0,0 +1,78 @@
1
+ /**
2
+ * M50 (agent-builder) — session-transcript compaction, Codex-faithful.
3
+ *
4
+ * Mirrors the vendored Codex mechanism (`codex-rs/core/src/compact.rs`):
5
+ * - the replacement history = recent USER messages verbatim (newest→oldest under a token budget;
6
+ * prior summaries filtered by marker) + ONE summary message with a textual marker prefix,
7
+ * injected as `role:"user"` (`build_compacted_history`, compact.rs:589-663);
8
+ * - persistence is APPEND-ONLY: a `compact_boundary` record becomes the new DAG root and the
9
+ * replacement messages are chained onto it — resume replays boundary→replacement→suffix
10
+ * (equivalent of `CompactedItem.replacement_history`, rollout is never truncated);
11
+ * - a failing summarizer leaves the transcript UNTOUCHED (typed error; no partial state).
12
+ *
13
+ * The summarizer is dependency-injected: tests pass a deterministic fake; the public
14
+ * `Agent.compact` wires the ADR-D440 compression summarizer (its first real caller).
15
+ */
16
+ import { type CompressibleMessage } from "../../compaction.js";
17
+ import type { SessionStore } from "../../types/session-store.js";
18
+ /** Textual marker prefixing every compact summary (Codex `SUMMARY_PREFIX` analog). */
19
+ export declare const COMPACT_SUMMARY_MARKER = "[[theokit:compact-summary]]";
20
+ /** Budget of VERBATIM user messages preserved in the replacement (Codex `COMPACT_USER_MESSAGE_MAX_TOKENS`). */
21
+ export declare const COMPACT_USER_MESSAGE_MAX_TOKENS = 20000;
22
+ export interface CompactLocation {
23
+ cwd: string;
24
+ agentId: string;
25
+ model?: string;
26
+ }
27
+ export interface CompactResult {
28
+ preTokens: number;
29
+ postTokens: number;
30
+ }
31
+ /** Is this message a summary produced by a PRIOR compaction? (filtered from verbatim preservation). */
32
+ export declare function isCompactSummary(content: string): boolean;
33
+ /**
34
+ * Compact one session transcript: summarize the reconstructed history, then append (append-only)
35
+ * a `compact_boundary` + the replacement chain (recent user messages verbatim + marker'd summary).
36
+ *
37
+ * @throws whatever `summarize` throws — with the transcript guaranteed untouched.
38
+ */
39
+ export declare function compactSessionTranscript(opts: {
40
+ store: SessionStore;
41
+ loc: CompactLocation;
42
+ sessionId: string;
43
+ trigger: "manual" | "auto";
44
+ summarize: (messages: readonly CompressibleMessage[]) => Promise<string>;
45
+ }): Promise<CompactResult>;
46
+ /**
47
+ * Build the default summarizer for `Agent.compact`: the D440 `compressConversationWindow`
48
+ * (aux-LLM summarization with typed failure) driven by a router-resolved LLM client. The
49
+ * compression model resolves via the D440 registry with the agent's own model as fallback.
50
+ */
51
+ export declare function buildDefaultSummarizer(opts: {
52
+ agentModel: string;
53
+ apiKey?: string;
54
+ }): (messages: readonly CompressibleMessage[]) => Promise<string>;
55
+ /**
56
+ * Should auto-compaction fire? Codex parity: `token_limit_reached` when real usage crosses 90% of
57
+ * the model's context window (`context_window.rs:74-79`; limit default `(cw*9)/10`,
58
+ * `openai_models.rs:459-469`). Missing inputs (no usage reported / model absent from the catalog)
59
+ * NEVER fire — fail-safe toward "do nothing".
60
+ */
61
+ export declare function shouldAutoCompact(opts: {
62
+ usageTotal?: number | undefined;
63
+ contextWindow?: number | undefined;
64
+ }): boolean;
65
+ /**
66
+ * Fire auto-compaction when the threshold is crossed — at most ONE attempt per turn per agent
67
+ * (anti-cascade: a failing summarizer or a non-reducing summary must not loop). Returns whether a
68
+ * compaction actually happened. Failures WARN and leave the transcript untouched.
69
+ */
70
+ export declare function autoCompactIfNeeded(opts: {
71
+ store: SessionStore;
72
+ loc: CompactLocation;
73
+ sessionId: string;
74
+ usageTotal?: number | undefined;
75
+ contextWindow?: number | undefined;
76
+ turnCount: number;
77
+ summarize: (messages: readonly CompressibleMessage[]) => Promise<string>;
78
+ }): Promise<boolean>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theokit/sdk",
3
- "version": "4.15.4",
3
+ "version": "4.16.1",
4
4
  "description": "TypeScript SDK for the Theo agent harness — same surface, local or cloud.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/usetheodev/theokit-sdk#readme",
@@ -2,6 +2,98 @@ import * as zod from 'zod';
2
2
  import { ZodType } from 'zod';
3
3
  import { M as ModelSelection, ac as SDKUserMessage, ae as SendOptions, b as Run, G as GenerateOptions, n as GenerateRunResult, _ as RunToCompletionOptions, $ as RunToCompletionResult, S as SDKMessage, al as StreamToCompletionResult, C as CustomTool, c as PermissionMode, a as McpServerConfig, P as Processor, u as MessageOrigin } from './run-DFM1H2jW.js';
4
4
 
5
+ /**
6
+ * `SessionRecord` — the native on-disk transcript record shape (SE40).
7
+ *
8
+ * The theokit session format IS the Claude Code record shape: a
9
+ * `uuid`/`parentUuid` DAG of records with structured
10
+ * `text`/`tool_use`/`tool_result`/`thinking` blocks. This is the contract the
11
+ * pluggable {@link SessionStore} seam operates over.
12
+ *
13
+ * DIP-correct home (SE46): the contract lives in the domain `types/` layer;
14
+ * the application-layer DAG core (`internal/persistence/session-transcript.ts`)
15
+ * re-exports it for back-compat while owning the record builders + reader.
16
+ *
17
+ * @public
18
+ */
19
+ /** One transcript record (one JSONL line). `message` absent on `system` (compact_boundary) records. */
20
+ interface SessionRecord {
21
+ type: "user" | "assistant" | "system";
22
+ uuid: string;
23
+ parentUuid: string | null;
24
+ sessionId: string;
25
+ timestamp: string;
26
+ isSidechain?: boolean;
27
+ userType?: string;
28
+ cwd?: string;
29
+ version?: string;
30
+ subtype?: string;
31
+ compactMetadata?: {
32
+ preTokens: number;
33
+ trigger: string;
34
+ };
35
+ message?: Record<string, unknown>;
36
+ }
37
+
38
+ /**
39
+ * SE41 — the pluggable `SessionStore` seam over the NATIVE session transcript.
40
+ *
41
+ * A minimal, two-method port so an external store (Postgres / Redis / KV /
42
+ * durable object) can be the **primary store AND resume source** — the
43
+ * serverless (ephemeral FS) and multi-host / multi-pod use case that SE40
44
+ * dropped when it removed the `ConversationStorageAdapter`. This is deliberately
45
+ * NOT that removed ~10-method adapter: the seam is JUST record read/append over
46
+ * the native {@link SessionRecord} shape (no getMessages / getSessionMeta /
47
+ * delete / objective methods).
48
+ *
49
+ * The SDK ships a real default implementation, `FsSessionStore`, that reads and
50
+ * append-writes the native Claude-shaped `.jsonl` transcript — omitting
51
+ * `local.sessionStore` yields byte-identical current behavior (back-compat, zero
52
+ * consumer change). Injected via `local.sessionStore` for external stores.
53
+ *
54
+ * Consistency contract: `appendRecords` is append-only and ordering-preserving.
55
+ * The FS default serializes appends per agent with a cross-process file lock;
56
+ * external implementations own (and MUST document) their own concurrency
57
+ * guarantees for two hosts appending to the same `agentId`.
58
+ *
59
+ * @public
60
+ */
61
+
62
+ /**
63
+ * The pluggable session-store seam. Exactly two methods over the native
64
+ * {@link SessionRecord} shape.
65
+ *
66
+ * @public
67
+ */
68
+ interface SessionStore {
69
+ /**
70
+ * Return every persisted record for `agentId`, in append order. A session
71
+ * that was never written MUST resolve to `[]` (not throw) — a fresh agent has
72
+ * no history. The SDK reconstructs the resumable `LlmMessage[]` from these
73
+ * records via the native DAG reader, so the shape MUST be the exact
74
+ * {@link SessionRecord} the SDK writes.
75
+ *
76
+ * A store that cannot READ (e.g. the backing DB is unreachable on resume)
77
+ * MUST throw a typed error rather than silently returning `[]` — a silent
78
+ * empty read would masquerade as "no history" and drop the conversation.
79
+ */
80
+ readRecords(agentId: string): Promise<SessionRecord[]>;
81
+ /**
82
+ * Append `records` (the new-turn delta) to `agentId`'s session, append-only.
83
+ * MUST preserve order and MUST NOT drop or rewrite prior records — the native
84
+ * format is an append-only `parentUuid` DAG (compaction is a new-root
85
+ * `compact_boundary` record, still an append).
86
+ *
87
+ * Note on the write path: per-turn persistence is fire-and-forget so `send()`
88
+ * is never blocked by store I/O — an `appendRecords` rejection is logged to
89
+ * stderr, NOT thrown to the caller (best-effort write). An external store that
90
+ * must guarantee durability should make `appendRecords` resilient (retry /
91
+ * durable write) internally. This differs from {@link SessionStore.readRecords},
92
+ * which MUST throw on failure (a resume cannot proceed on a silent partial history).
93
+ */
94
+ appendRecords(agentId: string, records: readonly SessionRecord[]): Promise<void>;
95
+ }
96
+
5
97
  /**
6
98
  * Public `MemoryAdapter` contract (T1.1, ADRs D141 / D147).
7
99
  *
@@ -233,98 +325,6 @@ declare class Skill {
233
325
  static create(spec: CreateSkillSpec): InlineSkill;
234
326
  }
235
327
 
236
- /**
237
- * `SessionRecord` — the native on-disk transcript record shape (SE40).
238
- *
239
- * The theokit session format IS the Claude Code record shape: a
240
- * `uuid`/`parentUuid` DAG of records with structured
241
- * `text`/`tool_use`/`tool_result`/`thinking` blocks. This is the contract the
242
- * pluggable {@link SessionStore} seam operates over.
243
- *
244
- * DIP-correct home (SE46): the contract lives in the domain `types/` layer;
245
- * the application-layer DAG core (`internal/persistence/session-transcript.ts`)
246
- * re-exports it for back-compat while owning the record builders + reader.
247
- *
248
- * @public
249
- */
250
- /** One transcript record (one JSONL line). `message` absent on `system` (compact_boundary) records. */
251
- interface SessionRecord {
252
- type: "user" | "assistant" | "system";
253
- uuid: string;
254
- parentUuid: string | null;
255
- sessionId: string;
256
- timestamp: string;
257
- isSidechain?: boolean;
258
- userType?: string;
259
- cwd?: string;
260
- version?: string;
261
- subtype?: string;
262
- compactMetadata?: {
263
- preTokens: number;
264
- trigger: string;
265
- };
266
- message?: Record<string, unknown>;
267
- }
268
-
269
- /**
270
- * SE41 — the pluggable `SessionStore` seam over the NATIVE session transcript.
271
- *
272
- * A minimal, two-method port so an external store (Postgres / Redis / KV /
273
- * durable object) can be the **primary store AND resume source** — the
274
- * serverless (ephemeral FS) and multi-host / multi-pod use case that SE40
275
- * dropped when it removed the `ConversationStorageAdapter`. This is deliberately
276
- * NOT that removed ~10-method adapter: the seam is JUST record read/append over
277
- * the native {@link SessionRecord} shape (no getMessages / getSessionMeta /
278
- * delete / objective methods).
279
- *
280
- * The SDK ships a real default implementation, `FsSessionStore`, that reads and
281
- * append-writes the native Claude-shaped `.jsonl` transcript — omitting
282
- * `local.sessionStore` yields byte-identical current behavior (back-compat, zero
283
- * consumer change). Injected via `local.sessionStore` for external stores.
284
- *
285
- * Consistency contract: `appendRecords` is append-only and ordering-preserving.
286
- * The FS default serializes appends per agent with a cross-process file lock;
287
- * external implementations own (and MUST document) their own concurrency
288
- * guarantees for two hosts appending to the same `agentId`.
289
- *
290
- * @public
291
- */
292
-
293
- /**
294
- * The pluggable session-store seam. Exactly two methods over the native
295
- * {@link SessionRecord} shape.
296
- *
297
- * @public
298
- */
299
- interface SessionStore {
300
- /**
301
- * Return every persisted record for `agentId`, in append order. A session
302
- * that was never written MUST resolve to `[]` (not throw) — a fresh agent has
303
- * no history. The SDK reconstructs the resumable `LlmMessage[]` from these
304
- * records via the native DAG reader, so the shape MUST be the exact
305
- * {@link SessionRecord} the SDK writes.
306
- *
307
- * A store that cannot READ (e.g. the backing DB is unreachable on resume)
308
- * MUST throw a typed error rather than silently returning `[]` — a silent
309
- * empty read would masquerade as "no history" and drop the conversation.
310
- */
311
- readRecords(agentId: string): Promise<SessionRecord[]>;
312
- /**
313
- * Append `records` (the new-turn delta) to `agentId`'s session, append-only.
314
- * MUST preserve order and MUST NOT drop or rewrite prior records — the native
315
- * format is an append-only `parentUuid` DAG (compaction is a new-root
316
- * `compact_boundary` record, still an append).
317
- *
318
- * Note on the write path: per-turn persistence is fire-and-forget so `send()`
319
- * is never blocked by store I/O — an `appendRecords` rejection is logged to
320
- * stderr, NOT thrown to the caller (best-effort write). An external store that
321
- * must guarantee durability should make `appendRecords` resilient (retry /
322
- * durable write) internally. This differs from {@link SessionStore.readRecords},
323
- * which MUST throw on failure (a resume cannot proceed on a silent partial history).
324
- */
325
- appendRecords(agentId: string, records: readonly SessionRecord[]): Promise<void>;
326
- }
327
-
328
328
  /**
329
329
  * `BudgetTracker` — runtime contract for budget/usage tracking in the
330
330
  * agent loop (SDK 2.0 Phase 2 / T2.1 — ADR D1 interface inversion).
@@ -2,6 +2,98 @@ import * as zod from 'zod';
2
2
  import { ZodType } from 'zod';
3
3
  import { M as ModelSelection, ac as SDKUserMessage, ae as SendOptions, b as Run, G as GenerateOptions, n as GenerateRunResult, _ as RunToCompletionOptions, $ as RunToCompletionResult, S as SDKMessage, al as StreamToCompletionResult, C as CustomTool, c as PermissionMode, a as McpServerConfig, P as Processor, u as MessageOrigin } from './run-DFM1H2jW.cjs';
4
4
 
5
+ /**
6
+ * `SessionRecord` — the native on-disk transcript record shape (SE40).
7
+ *
8
+ * The theokit session format IS the Claude Code record shape: a
9
+ * `uuid`/`parentUuid` DAG of records with structured
10
+ * `text`/`tool_use`/`tool_result`/`thinking` blocks. This is the contract the
11
+ * pluggable {@link SessionStore} seam operates over.
12
+ *
13
+ * DIP-correct home (SE46): the contract lives in the domain `types/` layer;
14
+ * the application-layer DAG core (`internal/persistence/session-transcript.ts`)
15
+ * re-exports it for back-compat while owning the record builders + reader.
16
+ *
17
+ * @public
18
+ */
19
+ /** One transcript record (one JSONL line). `message` absent on `system` (compact_boundary) records. */
20
+ interface SessionRecord {
21
+ type: "user" | "assistant" | "system";
22
+ uuid: string;
23
+ parentUuid: string | null;
24
+ sessionId: string;
25
+ timestamp: string;
26
+ isSidechain?: boolean;
27
+ userType?: string;
28
+ cwd?: string;
29
+ version?: string;
30
+ subtype?: string;
31
+ compactMetadata?: {
32
+ preTokens: number;
33
+ trigger: string;
34
+ };
35
+ message?: Record<string, unknown>;
36
+ }
37
+
38
+ /**
39
+ * SE41 — the pluggable `SessionStore` seam over the NATIVE session transcript.
40
+ *
41
+ * A minimal, two-method port so an external store (Postgres / Redis / KV /
42
+ * durable object) can be the **primary store AND resume source** — the
43
+ * serverless (ephemeral FS) and multi-host / multi-pod use case that SE40
44
+ * dropped when it removed the `ConversationStorageAdapter`. This is deliberately
45
+ * NOT that removed ~10-method adapter: the seam is JUST record read/append over
46
+ * the native {@link SessionRecord} shape (no getMessages / getSessionMeta /
47
+ * delete / objective methods).
48
+ *
49
+ * The SDK ships a real default implementation, `FsSessionStore`, that reads and
50
+ * append-writes the native Claude-shaped `.jsonl` transcript — omitting
51
+ * `local.sessionStore` yields byte-identical current behavior (back-compat, zero
52
+ * consumer change). Injected via `local.sessionStore` for external stores.
53
+ *
54
+ * Consistency contract: `appendRecords` is append-only and ordering-preserving.
55
+ * The FS default serializes appends per agent with a cross-process file lock;
56
+ * external implementations own (and MUST document) their own concurrency
57
+ * guarantees for two hosts appending to the same `agentId`.
58
+ *
59
+ * @public
60
+ */
61
+
62
+ /**
63
+ * The pluggable session-store seam. Exactly two methods over the native
64
+ * {@link SessionRecord} shape.
65
+ *
66
+ * @public
67
+ */
68
+ interface SessionStore {
69
+ /**
70
+ * Return every persisted record for `agentId`, in append order. A session
71
+ * that was never written MUST resolve to `[]` (not throw) — a fresh agent has
72
+ * no history. The SDK reconstructs the resumable `LlmMessage[]` from these
73
+ * records via the native DAG reader, so the shape MUST be the exact
74
+ * {@link SessionRecord} the SDK writes.
75
+ *
76
+ * A store that cannot READ (e.g. the backing DB is unreachable on resume)
77
+ * MUST throw a typed error rather than silently returning `[]` — a silent
78
+ * empty read would masquerade as "no history" and drop the conversation.
79
+ */
80
+ readRecords(agentId: string): Promise<SessionRecord[]>;
81
+ /**
82
+ * Append `records` (the new-turn delta) to `agentId`'s session, append-only.
83
+ * MUST preserve order and MUST NOT drop or rewrite prior records — the native
84
+ * format is an append-only `parentUuid` DAG (compaction is a new-root
85
+ * `compact_boundary` record, still an append).
86
+ *
87
+ * Note on the write path: per-turn persistence is fire-and-forget so `send()`
88
+ * is never blocked by store I/O — an `appendRecords` rejection is logged to
89
+ * stderr, NOT thrown to the caller (best-effort write). An external store that
90
+ * must guarantee durability should make `appendRecords` resilient (retry /
91
+ * durable write) internally. This differs from {@link SessionStore.readRecords},
92
+ * which MUST throw on failure (a resume cannot proceed on a silent partial history).
93
+ */
94
+ appendRecords(agentId: string, records: readonly SessionRecord[]): Promise<void>;
95
+ }
96
+
5
97
  /**
6
98
  * Public `MemoryAdapter` contract (T1.1, ADRs D141 / D147).
7
99
  *
@@ -233,98 +325,6 @@ declare class Skill {
233
325
  static create(spec: CreateSkillSpec): InlineSkill;
234
326
  }
235
327
 
236
- /**
237
- * `SessionRecord` — the native on-disk transcript record shape (SE40).
238
- *
239
- * The theokit session format IS the Claude Code record shape: a
240
- * `uuid`/`parentUuid` DAG of records with structured
241
- * `text`/`tool_use`/`tool_result`/`thinking` blocks. This is the contract the
242
- * pluggable {@link SessionStore} seam operates over.
243
- *
244
- * DIP-correct home (SE46): the contract lives in the domain `types/` layer;
245
- * the application-layer DAG core (`internal/persistence/session-transcript.ts`)
246
- * re-exports it for back-compat while owning the record builders + reader.
247
- *
248
- * @public
249
- */
250
- /** One transcript record (one JSONL line). `message` absent on `system` (compact_boundary) records. */
251
- interface SessionRecord {
252
- type: "user" | "assistant" | "system";
253
- uuid: string;
254
- parentUuid: string | null;
255
- sessionId: string;
256
- timestamp: string;
257
- isSidechain?: boolean;
258
- userType?: string;
259
- cwd?: string;
260
- version?: string;
261
- subtype?: string;
262
- compactMetadata?: {
263
- preTokens: number;
264
- trigger: string;
265
- };
266
- message?: Record<string, unknown>;
267
- }
268
-
269
- /**
270
- * SE41 — the pluggable `SessionStore` seam over the NATIVE session transcript.
271
- *
272
- * A minimal, two-method port so an external store (Postgres / Redis / KV /
273
- * durable object) can be the **primary store AND resume source** — the
274
- * serverless (ephemeral FS) and multi-host / multi-pod use case that SE40
275
- * dropped when it removed the `ConversationStorageAdapter`. This is deliberately
276
- * NOT that removed ~10-method adapter: the seam is JUST record read/append over
277
- * the native {@link SessionRecord} shape (no getMessages / getSessionMeta /
278
- * delete / objective methods).
279
- *
280
- * The SDK ships a real default implementation, `FsSessionStore`, that reads and
281
- * append-writes the native Claude-shaped `.jsonl` transcript — omitting
282
- * `local.sessionStore` yields byte-identical current behavior (back-compat, zero
283
- * consumer change). Injected via `local.sessionStore` for external stores.
284
- *
285
- * Consistency contract: `appendRecords` is append-only and ordering-preserving.
286
- * The FS default serializes appends per agent with a cross-process file lock;
287
- * external implementations own (and MUST document) their own concurrency
288
- * guarantees for two hosts appending to the same `agentId`.
289
- *
290
- * @public
291
- */
292
-
293
- /**
294
- * The pluggable session-store seam. Exactly two methods over the native
295
- * {@link SessionRecord} shape.
296
- *
297
- * @public
298
- */
299
- interface SessionStore {
300
- /**
301
- * Return every persisted record for `agentId`, in append order. A session
302
- * that was never written MUST resolve to `[]` (not throw) — a fresh agent has
303
- * no history. The SDK reconstructs the resumable `LlmMessage[]` from these
304
- * records via the native DAG reader, so the shape MUST be the exact
305
- * {@link SessionRecord} the SDK writes.
306
- *
307
- * A store that cannot READ (e.g. the backing DB is unreachable on resume)
308
- * MUST throw a typed error rather than silently returning `[]` — a silent
309
- * empty read would masquerade as "no history" and drop the conversation.
310
- */
311
- readRecords(agentId: string): Promise<SessionRecord[]>;
312
- /**
313
- * Append `records` (the new-turn delta) to `agentId`'s session, append-only.
314
- * MUST preserve order and MUST NOT drop or rewrite prior records — the native
315
- * format is an append-only `parentUuid` DAG (compaction is a new-root
316
- * `compact_boundary` record, still an append).
317
- *
318
- * Note on the write path: per-turn persistence is fire-and-forget so `send()`
319
- * is never blocked by store I/O — an `appendRecords` rejection is logged to
320
- * stderr, NOT thrown to the caller (best-effort write). An external store that
321
- * must guarantee durability should make `appendRecords` resilient (retry /
322
- * durable write) internally. This differs from {@link SessionStore.readRecords},
323
- * which MUST throw on failure (a resume cannot proceed on a silent partial history).
324
- */
325
- appendRecords(agentId: string, records: readonly SessionRecord[]): Promise<void>;
326
- }
327
-
328
328
  /**
329
329
  * `BudgetTracker` — runtime contract for budget/usage tracking in the
330
330
  * agent loop (SDK 2.0 Phase 2 / T2.1 — ADR D1 interface inversion).