@theokit/sdk 4.19.1 → 4.19.3

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.
Files changed (45) hide show
  1. package/dist/cron-Bhdyjl0B.d.ts +2582 -0
  2. package/dist/cron-M2Xz7lq2.d.cts +2582 -0
  3. package/dist/cron.cjs +19 -8
  4. package/dist/cron.cjs.map +1 -1
  5. package/dist/cron.d.cts +3 -0
  6. package/dist/cron.d.ts +3 -0
  7. package/dist/cron.js +19 -8
  8. package/dist/cron.js.map +1 -1
  9. package/dist/errors-CG2RpeW-.d.ts +516 -0
  10. package/dist/errors-gE8612p9.d.cts +516 -0
  11. package/dist/errors.d.cts +3 -0
  12. package/dist/eval.cjs +19 -8
  13. package/dist/eval.cjs.map +1 -1
  14. package/dist/eval.js +19 -8
  15. package/dist/eval.js.map +1 -1
  16. package/dist/filesystem/index.cjs +2 -1
  17. package/dist/filesystem/index.cjs.map +1 -1
  18. package/dist/filesystem/index.js +2 -1
  19. package/dist/filesystem/index.js.map +1 -1
  20. package/dist/goal-loop.d.ts +35 -0
  21. package/dist/index.cjs +139 -130
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +2309 -0
  24. package/dist/index.d.ts +2309 -0
  25. package/dist/index.js +139 -130
  26. package/dist/index.js.map +1 -1
  27. package/dist/internal/runtime/lifecycle/run-until.d.ts +1 -1
  28. package/dist/internal/security/index.cjs +2 -1
  29. package/dist/internal/security/index.cjs.map +1 -1
  30. package/dist/internal/security/index.js +2 -1
  31. package/dist/internal/security/index.js.map +1 -1
  32. package/dist/path-safety.cjs +2 -1
  33. package/dist/path-safety.cjs.map +1 -1
  34. package/dist/path-safety.js +2 -1
  35. package/dist/path-safety.js.map +1 -1
  36. package/dist/provider-catalog.json +1620 -0
  37. package/dist/run-DFM1H2jW.d.cts +1589 -0
  38. package/dist/run-DFM1H2jW.d.ts +1589 -0
  39. package/dist/skills.cjs +2 -1
  40. package/dist/skills.cjs.map +1 -1
  41. package/dist/skills.js +2 -1
  42. package/dist/skills.js.map +1 -1
  43. package/dist/workflow.cjs.map +1 -1
  44. package/dist/workflow.js.map +1 -1
  45. package/package.json +13 -12
@@ -0,0 +1,2582 @@
1
+ import * as zod from 'zod';
2
+ import { ZodType } from 'zod';
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
+
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
+
97
+ /**
98
+ * Public `MemoryAdapter` contract (T1.1, ADRs D141 / D147).
99
+ *
100
+ * The plugin extension point `{ kind: "memory" }` (ADR D98) declares a
101
+ * `createProvider` factory; this file types its return value formally.
102
+ * Adapters implement `write` / `recall` / `delete` plus optional methods
103
+ * gated by `capabilities`. `MemoryId` is a branded string prefixed with
104
+ * the adapter id so cross-adapter use throws on `extractRawId` (EC-B).
105
+ *
106
+ * Each provider-specific package (`@theokit-memory-supermemory`, etc)
107
+ * exports a factory returning a `Plugin { kind: "memory" }` whose
108
+ * `createProvider` resolves to a `MemoryAdapter` instance.
109
+ *
110
+ * @public
111
+ */
112
+ /**
113
+ * Branded provider memory ID. Format: `${adapterId}:${rawProviderId}`.
114
+ * Use `mkMemoryId` / `extractRawId` from `../memory-adapter-helpers.js`
115
+ * to construct and unwrap with cross-adapter safety (EC-B).
116
+ *
117
+ * @public
118
+ */
119
+ type MemoryId = string & {
120
+ readonly __brand: "MemoryId";
121
+ };
122
+ /**
123
+ * Portable identity context. `userId` is the only required field —
124
+ * the lowest common denominator across Supermemory / Honcho / Mem0.
125
+ * Adapter implementations translate the optional fields to their
126
+ * provider's native primitives (Honcho session, Mem0 run_id, etc).
127
+ *
128
+ * @public
129
+ */
130
+ interface MemoryContext {
131
+ /** End-user identity. */
132
+ userId: string;
133
+ /** Agent / persona writing the memory. */
134
+ agentId?: string;
135
+ /** Logical conversation / run boundary. */
136
+ sessionId?: string;
137
+ /** Tenant / workspace partition. */
138
+ tenantId?: string;
139
+ /** Free-form tags for filtering / categorization. */
140
+ tags?: string[];
141
+ /** Provider-passthrough metadata. */
142
+ metadata?: Record<string, unknown>;
143
+ }
144
+ /**
145
+ * A single memory fact returned by `recall` or `get`.
146
+ *
147
+ * @public
148
+ */
149
+ interface MemoryFact {
150
+ id: MemoryId;
151
+ content: string;
152
+ /** Semantic relevance score (provider-defined scale) when result of `recall`. */
153
+ score?: number;
154
+ /** ISO 8601 timestamp of creation. */
155
+ createdAt?: string;
156
+ metadata?: Record<string, unknown>;
157
+ }
158
+ /**
159
+ * Versioned snapshot of a memory's history. Only emitted by providers
160
+ * with `capabilities.history === true` (Mem0 today).
161
+ *
162
+ * @public
163
+ */
164
+ interface MemoryRevision {
165
+ id: MemoryId;
166
+ content: string;
167
+ version: number;
168
+ changedAt: string;
169
+ }
170
+ /**
171
+ * Statically declared adapter feature flags. Consumers feature-detect
172
+ * at compile time via `if (adapter.capabilities.history)`.
173
+ *
174
+ * @public
175
+ */
176
+ interface MemoryAdapterCapabilities {
177
+ /** Returns prior versions of a memory via `history(id)`. */
178
+ history: boolean;
179
+ /** First-class `sessionId` scoping. */
180
+ sessions: boolean;
181
+ /** First-class `tenantId` scoping. */
182
+ tenancy: boolean;
183
+ /** Provider performs reasoning over memory (e.g., Honcho dialectic). */
184
+ reasoning: boolean;
185
+ /** Exposes LLM-callable function-calling schemas. */
186
+ toolSchemas: boolean;
187
+ /** Supports background prefetch (currently informational). */
188
+ prefetch: boolean;
189
+ }
190
+ /**
191
+ * One assistant-turn message in the canonical `{role, content}` shape
192
+ * an adapter may receive instead of a flat string when writing a turn.
193
+ *
194
+ * @public
195
+ */
196
+ interface MemoryTurnMessage {
197
+ role: "user" | "assistant" | "system";
198
+ content: string;
199
+ }
200
+ /**
201
+ * OpenAI-format function-calling schema exposed to the LLM.
202
+ *
203
+ * @public
204
+ */
205
+ interface MemoryToolSchema {
206
+ name: string;
207
+ description: string;
208
+ parameters: Record<string, unknown>;
209
+ }
210
+ /**
211
+ * Portable third-party memory adapter contract. Implementations live
212
+ * in `@theokit-memory-*` packages; the SDK never imports them.
213
+ *
214
+ * @public
215
+ */
216
+ interface MemoryAdapter {
217
+ /** Short identifier — matches the `${adapterId}` prefix in `MemoryId`. */
218
+ readonly id: string;
219
+ readonly capabilities: MemoryAdapterCapabilities;
220
+ /** Synchronous availability probe — no network, no I/O. */
221
+ isAvailable(): boolean;
222
+ /** One-shot initialization. Idempotent: safe to call multiple times. */
223
+ initialize?(): Promise<void>;
224
+ /**
225
+ * Persist a fact or full turn to memory. Returns the stored
226
+ * `MemoryId`. Throws `MemoryAdapterError(code: "invalid_input")` on
227
+ * empty content or invalid identifiers in `ctx`.
228
+ */
229
+ write(content: string | MemoryTurnMessage[], ctx: MemoryContext): Promise<MemoryId>;
230
+ /**
231
+ * Semantic recall — top-`k` facts ordered by relevance. Returns
232
+ * empty array when `k === 0` or no matches.
233
+ */
234
+ recall(query: string, ctx: MemoryContext, k?: number): Promise<MemoryFact[]>;
235
+ /**
236
+ * Delete a memory by id. Throws `MemoryAdapterError(code:
237
+ * "invalid_input")` when the id was minted by a different adapter
238
+ * (EC-B). Throws `code: "not_found"` when the id does not exist.
239
+ */
240
+ delete(id: MemoryId): Promise<void>;
241
+ list?(ctx: MemoryContext, opts?: {
242
+ cursor?: string;
243
+ limit?: number;
244
+ }): AsyncIterable<MemoryFact>;
245
+ get?(id: MemoryId): Promise<MemoryFact | null>;
246
+ history?(id: MemoryId): Promise<MemoryRevision[]>;
247
+ /** Empty array when `capabilities.toolSchemas === false`. */
248
+ getToolSchemas?(): MemoryToolSchema[];
249
+ handleToolCall?(name: string, args: Record<string, unknown>, ctx: MemoryContext): Promise<string>;
250
+ /** Graceful shutdown — flush queues, close connections. */
251
+ shutdown?(): Promise<void>;
252
+ }
253
+ /**
254
+ * Direct memory API exposed on `SDKAgent.memory`. Resolves to whichever
255
+ * memory adapter(s) are registered via `Agent.create({ plugins: [...] })`.
256
+ *
257
+ * @public
258
+ */
259
+ interface AgentMemory {
260
+ /**
261
+ * Persist a fact. Returns the first adapter's id; in multi-adapter
262
+ * setups all adapters receive the write (fan-out).
263
+ */
264
+ write(content: string | MemoryTurnMessage[], ctx?: Partial<MemoryContext>): Promise<MemoryId>;
265
+ /** Semantic recall — merged + deduped across registered adapters. */
266
+ recall(query: string, ctx?: Partial<MemoryContext>, k?: number): Promise<MemoryFact[]>;
267
+ /** Delete a memory by id — routes to the owning adapter via prefix. */
268
+ delete(id: MemoryId): Promise<void>;
269
+ /** Returns the first registered adapter or `null` when none exists. */
270
+ adapter(): MemoryAdapter | null;
271
+ }
272
+
273
+ /**
274
+ * A discovered skill's metadata. The skill BODY is never included — only the
275
+ * strict frontmatter fields plus the resolved `source` path.
276
+ *
277
+ * Public via `@theokit/sdk/skills`.
278
+ *
279
+ * @public
280
+ */
281
+ interface Skill$1 {
282
+ name: string;
283
+ description: string;
284
+ /** Absolute path to the discovered `SKILL.md`. */
285
+ source: string;
286
+ category?: string;
287
+ dependencies?: string[];
288
+ }
289
+
290
+ /**
291
+ * M22 — `createSkill`: define a skill in TypeScript, without a `SKILL.md` file on disk.
292
+ *
293
+ * An inline skill is usable ALONGSIDE filesystem skills (`AgentOptions.skills.inline`), and points
294
+ * an agent at code-defined capabilities without a `.theokit/skills/<name>/SKILL.md`. Like file
295
+ * skills, its `name` + `description` surface in the `<skills>` system-prompt block; its
296
+ * `instructions` (the body) travel on the object for the consumer (the SDK injects name+description,
297
+ * not bodies — inline and file skills are symmetric there). Inline skills override file skills on a
298
+ * name conflict (mirrors the subagents-loader precedent).
299
+ */
300
+
301
+ /** A code-defined skill (from {@link createSkill}) — a {@link Skill} plus its inline body. */
302
+ interface InlineSkill extends Skill$1 {
303
+ /** The skill body/instructions (inline skills carry it here instead of a SKILL.md file). */
304
+ instructions: string;
305
+ /**
306
+ * SE21 — supporting documents bundled with the skill (filename → content),
307
+ * mirroring a filesystem skill's `references/` directory. Surfaced to the app
308
+ * via `agent.skills.get(name)`; not injected into the model prompt.
309
+ */
310
+ references?: Record<string, string>;
311
+ }
312
+ /** Spec accepted by {@link createSkill}. */
313
+ interface CreateSkillSpec {
314
+ name: string;
315
+ description: string;
316
+ instructions: string;
317
+ category?: string;
318
+ dependencies?: string[];
319
+ /** SE21 — supporting documents (filename → content), like a filesystem skill's `references/`. */
320
+ references?: Record<string, string>;
321
+ }
322
+ /** SE36 — `Skill.create` replaces `createSkill` (ADR 0015). @public */
323
+ declare class Skill {
324
+ private constructor();
325
+ static create(spec: CreateSkillSpec): InlineSkill;
326
+ }
327
+
328
+ /**
329
+ * `BudgetTracker` — runtime contract for budget/usage tracking in the
330
+ * agent loop (SDK 2.0 Phase 2 / T2.1 — ADR D1 interface inversion).
331
+ *
332
+ * This interface is the FOUNDATION for the eventual extraction of the
333
+ * Budget subsystem to `@theokit/sdk-budget`. The kernel depends on this
334
+ * contract (not on `UsageAccumulator` / `IterationBudget` concrete classes)
335
+ * so the implementation can move to a separate package without circular
336
+ * imports.
337
+ *
338
+ * DIP-correct home (SE46): the contract types live in the domain `types/`
339
+ * layer; the application-layer implementation
340
+ * (`internal/budget/tracker/budget-tracker.ts`) re-exports them for
341
+ * back-compat while owning the concrete trackers.
342
+ *
343
+ * @public — surface-level interface; impl is internal-but-replaceable.
344
+ */
345
+ /** Single usage event recorded during one LLM call. */
346
+ interface BudgetUsageEvent {
347
+ /** Token count for this event. */
348
+ readonly tokens: number;
349
+ /** Provider/model identifier (e.g., `"openai/gpt-4o-mini"`). */
350
+ readonly model: string;
351
+ /** Whether this is an input (prompt) or output (completion) measurement. */
352
+ readonly type: "input" | "output";
353
+ /** Optional ISO 8601 timestamp; defaults to now() if omitted. */
354
+ readonly at?: string;
355
+ }
356
+ /** Decision the tracker returns on each iteration / pre-flight check. */
357
+ interface BudgetCheck {
358
+ /** Whether the agent loop is allowed to proceed. */
359
+ readonly allowed: boolean;
360
+ /**
361
+ * When `allowed` is false, names the reason in a stable, codemod-friendly
362
+ * form. Consumers map this to retry / surface to user / abort behavior.
363
+ */
364
+ readonly reason?: "budget_exceeded" | "iteration_limit" | "cost_limit" | "token_limit" | "custom";
365
+ /** Free-form details for logs / diagnostics. */
366
+ readonly detail?: string;
367
+ }
368
+ /** Aggregate snapshot of usage so far. */
369
+ interface BudgetTotal {
370
+ /** Sum of all input + output tokens. */
371
+ readonly tokens: number;
372
+ /** USD cost when pricing data is available; `undefined` otherwise. */
373
+ readonly costUsd?: number;
374
+ /** Iteration count if the impl tracks it. */
375
+ readonly iterations?: number;
376
+ }
377
+ /**
378
+ * The kernel-facing contract. Implementations live OUTSIDE the agent loop
379
+ * (in `@theokit/sdk-budget` after Phase 2 / in `internal/budget/` until then).
380
+ *
381
+ * Implementations MUST be:
382
+ * - **Synchronous** — every method returns a value, never a Promise.
383
+ * `track()` is on the hot path (called on every iteration); async would
384
+ * bloat the loop with floating promises and force every call site to
385
+ * await.
386
+ * - **Non-throwing in track()** — record-only semantics. Validation
387
+ * failures bubble up via `check()` instead.
388
+ */
389
+ interface BudgetTracker {
390
+ /** Record a single usage event. MUST be synchronous and non-throwing. */
391
+ track(event: BudgetUsageEvent): void;
392
+ /** Pre-flight check before the next iteration. */
393
+ check(): BudgetCheck;
394
+ /** Snapshot of accumulated totals (for telemetry / final reporting). */
395
+ getTotal(): BudgetTotal;
396
+ /**
397
+ * Advance the iteration counter by one. Called by the agent loop ONCE per
398
+ * completed turn (M1-1) so that trackers which gate on `maxIterations`
399
+ * (e.g. `createCounterBudgetTracker`) actually halt. OPTIONAL: trackers that
400
+ * only gate on tokens/USD omit it and the loop no-ops via optional chaining.
401
+ * MUST be synchronous and non-throwing.
402
+ */
403
+ nextIteration?(): void;
404
+ }
405
+
406
+ /**
407
+ * Context manager backend.
408
+ *
409
+ * - `"file"` — Read `.theokit/context.json` from the workspace (local) or the
410
+ * cloned repo (cloud).
411
+ *
412
+ * @public
413
+ */
414
+ type ContextManagerKind = "file";
415
+ /**
416
+ * Context configuration accepted by `Agent.create()` via {@link AgentOptions.context}.
417
+ *
418
+ * @public
419
+ */
420
+ interface ContextSettings {
421
+ /** Which backend reads context. Defaults to `"file"`. */
422
+ manager?: ContextManagerKind;
423
+ /** Hard cap on tokens emitted into the agent's system prompt. */
424
+ maxTokens?: number;
425
+ /**
426
+ * Per-file truncation cap in characters. Default 40_000 (~10k tokens).
427
+ * Larger files are truncated with 70%/20% head/tail + marker (ADR D155).
428
+ *
429
+ * @public
430
+ */
431
+ maxBytesPerFile?: number;
432
+ /**
433
+ * Aggregate cap across all context files in characters. Default 120_000.
434
+ * When total exceeds this, lower-priority sources are dropped (ADR D155).
435
+ *
436
+ * Note: context snapshot is **refresh-time** (EC-T); modifying context
437
+ * files mid-flight does not auto-update. Call `agent.reload()` to pick
438
+ * up changes.
439
+ *
440
+ * @public
441
+ */
442
+ maxBytesTotal?: number;
443
+ }
444
+ /**
445
+ * Inclusion state of a single context source in a {@link ContextSnapshot}.
446
+ *
447
+ * @public
448
+ */
449
+ type ContextSourceStatus = "included" | "excluded" | "summarized";
450
+ /**
451
+ * A single context source resolved by the context manager.
452
+ *
453
+ * @public
454
+ */
455
+ interface ContextSource {
456
+ /** Stable identifier — usually the filename without extension. */
457
+ name: string;
458
+ /** Path relative to the workspace root, when applicable. */
459
+ path?: string;
460
+ /** Whether the source was included, dropped, or summarized to fit the budget. */
461
+ status: ContextSourceStatus;
462
+ /** Free-text reason when `status !== "included"`. */
463
+ reason?: string;
464
+ }
465
+ /**
466
+ * Token budget used by the context manager for a single agent.
467
+ *
468
+ * @public
469
+ */
470
+ interface ContextBudget {
471
+ maxTokens?: number;
472
+ /**
473
+ * Either a token count or a list of token strings extracted from source
474
+ * content. Normalized to `<tokens>` in golden comparisons.
475
+ */
476
+ usedTokens?: number | string[];
477
+ }
478
+ /**
479
+ * Result of `agent.context.snapshot()`. Public and secret-free by design — safe
480
+ * to log and persist. Raw secrets, local absolute paths, and exact token values
481
+ * are never present.
482
+ *
483
+ * @public
484
+ */
485
+ interface ContextSnapshot {
486
+ runtime: "local" | "cloud";
487
+ sources: ContextSource[];
488
+ budget?: ContextBudget;
489
+ }
490
+ /**
491
+ * Public context manager handle exposed as `agent.context`.
492
+ *
493
+ * @public
494
+ */
495
+ interface SDKContextManager {
496
+ /** Inspect what the context manager actually loaded for the agent. */
497
+ snapshot(): Promise<ContextSnapshot>;
498
+ }
499
+
500
+ /**
501
+ * Fork primitive public type contracts (T1.2, ADRs D110-D114).
502
+ *
503
+ * Extracted into a leaf type module (arch-review ADR 0001) so the public
504
+ * `types/agent.ts` barrel can reference `ForkOptions`/`ForkResult` without
505
+ * importing the `internal/runtime/lifecycle/fork-agent.ts` implementation — which in
506
+ * turn imports back from `types/agent.ts`. That mutual reference created a
507
+ * type-only `madge` cycle. These interfaces are self-contained (no SDKAgent
508
+ * / AgentOptions references), so co-locating them here breaks the cycle with
509
+ * no runtime change. `fork-agent.ts` re-exports them for back-compat.
510
+ */
511
+ /**
512
+ * Caller-supplied fork configuration. See `forkAgentImpl`.
513
+ *
514
+ * @public
515
+ */
516
+ interface ForkOptions {
517
+ /**
518
+ * Tool subset visible to the fork. Names must match the canonical (post-repair)
519
+ * tool name — typically lowercase. Tools not in this set return a `tool_result`
520
+ * with `"Tool blocked by fork whitelist"` content (EC-H).
521
+ */
522
+ allowedTools: Set<string>;
523
+ /** Task prompt sent to the fork. */
524
+ prompt: string;
525
+ /** Override system prompt. Default: byte-identical inheritance from parent (D112). */
526
+ systemPrompt?: string;
527
+ /** Memory write provenance tag (D114). Default `"fork"`. */
528
+ forkOrigin?: string;
529
+ }
530
+ /**
531
+ * Outcome of a fork run.
532
+ *
533
+ * @public
534
+ */
535
+ interface ForkResult {
536
+ /** Final agent response text (`undefined` when the fork produced no result). */
537
+ result: string | undefined;
538
+ /** Tool calls executed inside the fork. */
539
+ toolCalls: ReadonlyArray<{
540
+ name: string;
541
+ input: Record<string, unknown>;
542
+ }>;
543
+ /** Aggregate token usage reported by the run. */
544
+ usage: {
545
+ inputTokens: number;
546
+ outputTokens: number;
547
+ };
548
+ }
549
+
550
+ /**
551
+ * Public event types emitted by {@link SDKAgent.runUntil} (ADRs D115-D117).
552
+ *
553
+ * Discriminated union by `type` field so consumers can `switch (event.type)`
554
+ * with full TypeScript exhaustiveness. Mirrors the
555
+ * {@link import("../stream-object.js").StreamObjectEvent} pattern (ADR D39).
556
+ *
557
+ * @public
558
+ */
559
+ /**
560
+ * Single event emitted while iterating a goal-driven loop. Five variants:
561
+ *
562
+ * - `turn_start` — the agent is about to invoke `send()`. Emitted once
563
+ * per turn.
564
+ * - `agent_response` — the agent's `send()` resolved; carries the text
565
+ * reply.
566
+ * - `judge_verdict` — the auxiliary judge model evaluated the response.
567
+ * `parseFailed: true` indicates the judge returned a malformed reply
568
+ * (fail-safe verdict = `continue`, see ADR D121).
569
+ * - `continuation` — the judge ruled `continue`; carries the prompt that
570
+ * was sent on THIS turn (i.e., the input that produced the agent
571
+ * response just yielded). Useful for consumers who want to audit the
572
+ * exact continuation message that drove each iteration. The prompt
573
+ * for the NEXT turn is composed lazily at the start of that turn
574
+ * from the latest `agent_response.content`.
575
+ * - `status_change` — transition of the overall goal state. Always
576
+ * emitted once at start (`active`) and once at end
577
+ * (`completed | failed | paused`).
578
+ *
579
+ * @public
580
+ */
581
+ type GoalEvent = {
582
+ type: "turn_start";
583
+ turn: number;
584
+ goal: string;
585
+ } | {
586
+ type: "agent_response";
587
+ turn: number;
588
+ content: string;
589
+ } | {
590
+ type: "judge_verdict";
591
+ turn: number;
592
+ verdict: "done" | "continue" | "skipped";
593
+ reason: string;
594
+ parseFailed: boolean;
595
+ } | {
596
+ type: "continuation";
597
+ turn: number;
598
+ prompt: string;
599
+ } | {
600
+ type: "status_change";
601
+ status: "active" | "paused" | "completed" | "failed" | "budget_limited" | "blocked";
602
+ reason: string;
603
+ };
604
+ /**
605
+ * Return value of the `runUntil` async generator. Consumer reads via
606
+ * `const { value } = await gen.next()` (when `done: true`).
607
+ *
608
+ * @public
609
+ */
610
+ interface GoalResult {
611
+ status: "completed" | "failed" | "paused" | "budget_limited" | "blocked";
612
+ turnsUsed: number;
613
+ /** M55 — tokens somados ao longo do loop (0 quando `usage` esteve ausente — fail-open). */
614
+ tokensUsed: number;
615
+ finalResponse: string | undefined;
616
+ }
617
+ /**
618
+ * Return type of {@link import("../internal/local-agent/local-agent.js").LocalAgent.runUntil}.
619
+ * Extracted so the LocalAgent method signature stays a single line (G8 LoC budget).
620
+ *
621
+ * @public
622
+ */
623
+ type RunUntilIterator = AsyncGenerator<GoalEvent, GoalResult, void>;
624
+ /**
625
+ * Per-call configuration for `Agent.runUntil`.
626
+ *
627
+ * @public
628
+ */
629
+ interface GoalOptions {
630
+ /** Hard cap on iterations (safety net against runaway). Default `20`. */
631
+ maxTurns?: number;
632
+ /**
633
+ * M55 — token budget (Codex ext/goal parity, tool.rs:454-465). Soma `run.wait().usage.totalTokens`
634
+ * por turno; ao cruzar, o loop para com status `budget_limited`. Omitido ⇒ ilimitado (só maxTurns).
635
+ * `usage` ausente nunca estoura o budget (fail-open).
636
+ */
637
+ tokenBudget?: number;
638
+ /** Bail after N consecutive judge parse failures. Default `3` (ADR D121). */
639
+ maxConsecutiveJudgeFailures?: number;
640
+ /** Judge model identifier. Default `"openai/gpt-4o-mini"` (ADR D119). */
641
+ judgeModel?: string;
642
+ /** Override env for the judge auxiliary agent. Default `OPENROUTER_API_KEY` (EC-A). */
643
+ judgeApiKey?: string;
644
+ /** Optional subgoals fed to the judge prompt. */
645
+ subgoals?: string[];
646
+ /**
647
+ * Cancel mid-loop via `AbortController.signal`. The generator yields
648
+ * a `status_change: paused` event and returns at the next turn
649
+ * boundary (ADR D117).
650
+ */
651
+ signal?: AbortSignal;
652
+ }
653
+
654
+ /**
655
+ * Capability slot a provider can fulfill.
656
+ *
657
+ * @public
658
+ */
659
+ type ProviderCapability = "chat" | "web_search" | "image" | "embedding";
660
+ /**
661
+ * A single user-declared routing rule. Maps a capability to a provider, and
662
+ * optionally pins a specific model.
663
+ *
664
+ * @public
665
+ */
666
+ interface ProviderRoute {
667
+ capability: ProviderCapability;
668
+ provider: string;
669
+ model?: string;
670
+ /**
671
+ * Opt-in leaked-dialect safe-parse for this route's provider (theokit#58
672
+ * follow-up). When `true`, a `chat_completions` finish that carries ZERO
673
+ * native `tool_calls` has its assistant text scanned for the Hermes
674
+ * `<function=…></tool_call>` dialect, and any recovered calls are surfaced as
675
+ * real `tool_calls` so the loop executes them — for models (qwen3-coder via
676
+ * OpenRouter) that intermittently leak tool calls as text. Default `false`;
677
+ * fail-open (a partial/unclosed block never fabricates a call). Scoped to the
678
+ * resolved chat chain, so a non-leaking route is unaffected.
679
+ */
680
+ extractToolCallsFromContent?: boolean;
681
+ }
682
+ /**
683
+ * Provider routing configuration accepted by `Agent.create()` via
684
+ * {@link AgentOptions.providers}.
685
+ *
686
+ * @public
687
+ */
688
+ interface ProviderRoutingSettings {
689
+ /** Explicit `{ capability → provider }` map. First match wins per capability. */
690
+ routes: ProviderRoute[];
691
+ /** Provider names to try in order when a route has no provider available. */
692
+ fallback?: string[];
693
+ /**
694
+ * Multiple API keys per provider for same-provider key rotation
695
+ * (credential pool — ADRs D123-D133). When a key hits HTTP 429, 402,
696
+ * or 401, the SDK rotates to the next entry transparently before
697
+ * falling back to a different provider.
698
+ *
699
+ * Example:
700
+ * ```ts
701
+ * apiKeys: { openrouter: ["sk-or-...", "sk-or-..."], anthropic: ["..."] }
702
+ * ```
703
+ *
704
+ * Empty arrays and empty strings are filtered out. If a provider has
705
+ * exactly 1 effective key, the pool is transparent (no rotation behavior).
706
+ *
707
+ * Conflicts with the single-key shape `AgentOptions.apiKey: "..."` —
708
+ * use one OR the other, not both.
709
+ *
710
+ * @public
711
+ */
712
+ apiKeys?: Record<string, string[]>;
713
+ /**
714
+ * Rotation strategy per provider for the credential pool. Default is
715
+ * `"fill_first"` (use entries[0] until exhausted). Only consulted when
716
+ * `apiKeys[provider]` has ≥2 entries.
717
+ *
718
+ * @public
719
+ */
720
+ credentialPoolStrategy?: Record<string, "fill_first" | "round_robin" | "least_used" | "random">;
721
+ }
722
+ /**
723
+ * Plugins configuration accepted by `Agent.create()` via
724
+ * {@link AgentOptions.plugins}.
725
+ *
726
+ * @public
727
+ */
728
+ interface PluginsSettings {
729
+ /** Plugin names to enable. Plugin discovery is plugin-provider specific. */
730
+ enabled?: string[];
731
+ }
732
+ /**
733
+ * Resolved routing decision returned by `agent.providers.routes()`. Public and
734
+ * secret-free by design — safe to log.
735
+ *
736
+ * @public
737
+ */
738
+ interface ResolvedProviderRoute {
739
+ capability: string;
740
+ provider: string;
741
+ model?: string;
742
+ /** Why the runtime picked this provider (e.g. `"explicit-model-provider"`). */
743
+ reason: string;
744
+ }
745
+ /**
746
+ * Public providers manager handle exposed as `agent.providers`.
747
+ *
748
+ * @public
749
+ */
750
+ interface SDKProvidersManager {
751
+ /** Inspect which provider serves each capability for this agent. */
752
+ routes(): Promise<ResolvedProviderRoute[]>;
753
+ }
754
+ /**
755
+ * Provider catalog entry returned by `Theokit.providers.list()`.
756
+ *
757
+ * @public
758
+ */
759
+ interface SDKProvider {
760
+ name: string;
761
+ displayName: string;
762
+ capabilities: string[];
763
+ isAvailable: boolean;
764
+ /** JSON Schema describing the env vars / fields needed to enable this provider. */
765
+ setupSchema: object;
766
+ }
767
+
768
+ /**
769
+ * Public skill metadata exposed to the system-prompt resolver. Mirrors the
770
+ * shape returned by `agent.skills.list()` — name + description only, never
771
+ * full skill bodies.
772
+ *
773
+ * @public
774
+ */
775
+ interface SystemPromptSkillRef {
776
+ name: string;
777
+ description: string;
778
+ }
779
+ /**
780
+ * A skill resolved WITH its body, returned by {@link SDKAgentSkills.get}. Unlike
781
+ * {@link SystemPromptSkillRef} (name + description only), this carries the full
782
+ * `instructions` — read from the SKILL.md for filesystem skills or the inline
783
+ * `createSkill` body. @public
784
+ */
785
+ interface SDKAgentSkillDetail {
786
+ name: string;
787
+ description: string;
788
+ instructions: string;
789
+ /** SE21 — supporting documents bundled with the skill (filename → content), when present. */
790
+ references?: Record<string, string>;
791
+ }
792
+ interface SDKAgentSkills {
793
+ list(): Promise<ReadonlyArray<SystemPromptSkillRef>>;
794
+ /**
795
+ * SE20 — resolve a skill by name INCLUDING its body (`instructions`). Returns
796
+ * `undefined` when no enabled skill matches. `list()` stays lean (name +
797
+ * description); full bodies come only through `get`.
798
+ */
799
+ get(name: string): Promise<SDKAgentSkillDetail | undefined>;
800
+ }
801
+ /**
802
+ * Public plugin metadata returned by `agent.plugins.list()`. Mirrors the
803
+ * `.theokit/plugins/<name>/MANIFEST.json` allow-listed shape; never exposes
804
+ * raw plugin bodies, credentials, or internal hooks.
805
+ *
806
+ * @public
807
+ */
808
+ interface SDKPluginMetadata {
809
+ name: string;
810
+ description?: string;
811
+ }
812
+ /**
813
+ * Public plugin listing handle exposed as `agent.plugins`. Populated when
814
+ * `settingSources` includes `"plugins"` OR when `plugins.enabled` is set
815
+ * on the agent options.
816
+ *
817
+ * @public
818
+ */
819
+ interface SDKAgentPlugins {
820
+ list(): Promise<ReadonlyArray<SDKPluginMetadata>>;
821
+ }
822
+ /**
823
+ * Artifact produced inside an agent's workspace. Cloud-only.
824
+ *
825
+ * @public
826
+ */
827
+ interface SDKArtifact {
828
+ path: string;
829
+ sizeBytes: number;
830
+ updatedAt: string;
831
+ }
832
+ /**
833
+ * Handle returned by `Agent.create()` and `Agent.resume()`.
834
+ *
835
+ * @public
836
+ */
837
+ interface SDKAgent {
838
+ readonly agentId: string;
839
+ readonly model: ModelSelection | undefined;
840
+ /**
841
+ * Context manager for this agent. Populated when context is enabled via
842
+ * {@link AgentOptions.context}. See {@link SDKContextManager}.
843
+ */
844
+ readonly context?: SDKContextManager;
845
+ /**
846
+ * Provider routing inspector for this agent. Populated when at least one
847
+ * provider route is configured (via {@link AgentOptions.providers}, plugins,
848
+ * or model-implied providers). See {@link SDKProvidersManager}.
849
+ */
850
+ readonly providers?: SDKProvidersManager;
851
+ /**
852
+ * Skill listing for this agent. Populated when project-scoped skills are
853
+ * enabled (`settingSources: ["project"]`) or when `skills.enabled` is set.
854
+ * See {@link SDKAgentSkills}.
855
+ */
856
+ readonly skills?: SDKAgentSkills;
857
+ /**
858
+ * Plugin listing for this agent. Populated when project-scoped plugins are
859
+ * enabled (`settingSources: ["plugins"]`) or when `plugins.enabled` is set.
860
+ * See {@link SDKAgentPlugins}.
861
+ */
862
+ readonly plugins?: SDKAgentPlugins;
863
+ send(message: string | SDKUserMessage, options?: SendOptions): Promise<Run>;
864
+ /**
865
+ * SE9 — integrated structured output. Runs the normal tool loop (the tools run
866
+ * first) then coerces the final answer into the `output` Zod schema, returning a
867
+ * validated, inferred-typed object. Sugar over `Agent.generateObject` (ADR D33).
868
+ */
869
+ generate<T extends zod.ZodType>(message: string | SDKUserMessage, options: GenerateOptions<T>): Promise<GenerateRunResult<zod.z.infer<T>>>;
870
+ /** Fire-and-forget disposal. */
871
+ close(): void;
872
+ /** Re-read filesystem config (context, hooks, project MCP, subagents) without disposing. */
873
+ reload(): Promise<void>;
874
+ /**
875
+ * Async disposal. Idempotent — calling more than once is a no-op (per ADR D5).
876
+ * Prefer `await using agent = await Agent.create(...)` over explicit
877
+ * `dispose()` for resource safety.
878
+ */
879
+ dispose(): Promise<void>;
880
+ /**
881
+ * `await using` support per ADR D5. Identical semantics to `dispose()` —
882
+ * idempotent across both surfaces.
883
+ */
884
+ [Symbol.asyncDispose](): Promise<void>;
885
+ /** Cloud-only. Local returns an empty array. */
886
+ listArtifacts(): Promise<SDKArtifact[]>;
887
+ /** Cloud-only. Local throws `UnsupportedRunOperationError`. */
888
+ downloadArtifact(path: string): Promise<Buffer>;
889
+ /**
890
+ * Signal that prompt cache should be invalidated. By default deferred —
891
+ * applied at the start of the next `send()`. Pass `{ applyNow: true }` to
892
+ * force immediate disposal (caller must `Agent.create()` again to use).
893
+ *
894
+ * Cache invalidation is a cost regression (provider charges full price
895
+ * for the rebuilt cache; see ADRs D94-D95). Use sparingly and deliberately.
896
+ *
897
+ * Cloud agents: no-op (cloud runtime reconstructs state per request).
898
+ *
899
+ * @public
900
+ */
901
+ invalidateCache?(reason: string, options?: InvalidateCacheOptions): Promise<void>;
902
+ /**
903
+ * Goal-driven Ralph loop (ADRs D115-D121). Iterates `agent.send` →
904
+ * judge → continuation until the auxiliary judge model returns `done`,
905
+ * the judge fails too many times in a row, max turns are exhausted,
906
+ * or the caller aborts via `AbortSignal`.
907
+ *
908
+ * Yields {@link import("./goal-events.js").GoalEvent} per state
909
+ * transition; returns a {@link import("./goal-events.js").GoalResult}
910
+ * summary as the generator's final value.
911
+ *
912
+ * Cloud agents throw {@link import("../errors.js").UnsupportedRunOperationError}
913
+ * **synchronously** (no AsyncGenerator returned) — wrap in try/catch
914
+ * if you support both runtimes.
915
+ *
916
+ * Caveat: do not call `agent.dispose()` mid-iteration; the next `send`
917
+ * propagates the disposal error through the generator to the consumer.
918
+ *
919
+ * @public
920
+ */
921
+ runUntil?(goal?: string, options?: GoalOptions): RunUntilIterator;
922
+ /**
923
+ * Fork a short-lived sub-agent with parent's credentials + system
924
+ * prompt byte-identical (ADR D112 — cache hit) and a restricted tool
925
+ * whitelist (ADR D111 — AsyncLocalStorage isolation).
926
+ *
927
+ * Cloud agents throw {@link import("../errors.js").UnsupportedRunOperationError}.
928
+ *
929
+ * @public
930
+ */
931
+ fork?(options: ForkOptions): Promise<ForkResult>;
932
+ /**
933
+ * Drive `send` to completion across iteration-ceiling truncations (M1 Phase 3).
934
+ * When a `send` stops at the loop's iteration cap (`RunResult.stoppedAtIterationLimit`),
935
+ * this re-sends a short continuation prompt — the agent's stateful session
936
+ * preserves the conversation — until a genuine terminal: `done` (finished),
937
+ * `step_limit` (`maxRounds` exhausted), or `no_progress` (two empty rounds).
938
+ *
939
+ * Local agents only. Cloud agents throw
940
+ * {@link import("../errors.js").UnsupportedRunOperationError} (the cloud
941
+ * runtime manages its own continuation policy server-side).
942
+ *
943
+ * @public
944
+ */
945
+ runToCompletion?(message: string, options?: RunToCompletionOptions): Promise<RunToCompletionResult>;
946
+ /**
947
+ * STREAMING continuation driver (V3-4) — the streaming twin of
948
+ * {@link SDKAgent.runToCompletion}. Returns an `AsyncGenerator` that yields each
949
+ * round's {@link import("./messages.js").SDKMessage}s LIVE (for a UI), reusing the
950
+ * same terminal policy (`done`/`step_limit`/`no_progress` + bounded re-prompt).
951
+ *
952
+ * The {@link import("./run.js").StreamToCompletionResult} is the generator's RETURN
953
+ * value — read it via a manual `gen.next()` loop (`while (!res.done) res = await
954
+ * gen.next()` → `res.value`); a plain `for await...of` consumes the yielded
955
+ * messages but discards the return value.
956
+ *
957
+ * Local agents only. Cloud agents throw
958
+ * {@link import("../errors.js").UnsupportedRunOperationError}.
959
+ *
960
+ * @public
961
+ */
962
+ streamToCompletion?(message: string, options?: RunToCompletionOptions): AsyncGenerator<SDKMessage, StreamToCompletionResult>;
963
+ /**
964
+ * Direct API to third-party memory adapter(s) registered via
965
+ * `plugins: [...]` (ADR D141 / D142). Returns `null` when no adapter
966
+ * is registered. In multi-adapter setups `write` fans out to all;
967
+ * `recall` merges + dedupes; `delete` routes by `MemoryId` prefix.
968
+ *
969
+ * @public
970
+ */
971
+ memory?: AgentMemory;
972
+ /**
973
+ * Activate a personality preset for the next `send` (Hermes #26).
974
+ * Reserved names `"none"`, `"default"`, and `"neutral"` clear the
975
+ * active preset. Returns the resolved preset (or `null` when cleared).
976
+ *
977
+ * Persistence: pass `{ save: true }` to persist across process
978
+ * restarts (stored under `$THEOKIT_HOME/personality.json`).
979
+ *
980
+ * History: by default the conversation history is preserved across
981
+ * the switch. Pass `{ reset: true }` to also clear the session.
982
+ *
983
+ * Cloud agents throw {@link import("../errors.js").UnsupportedRunOperationError}.
984
+ *
985
+ * @public
986
+ */
987
+ usePersonality?(name: string, opts?: {
988
+ save?: boolean;
989
+ reset?: boolean;
990
+ }): Promise<PersonalityPreset | null>;
991
+ }
992
+ /**
993
+ * Resolved personality preset surfaced via {@link SDKAgent.usePersonality}
994
+ * (Hermes #26, ADRs D160-D169). Re-declared here so the public DTS bundle
995
+ * never crosses the `internal/` path boundary. The implementation type in
996
+ * `internal/personality/types.ts` is structurally identical.
997
+ *
998
+ * @public
999
+ */
1000
+ interface PersonalityPreset {
1001
+ readonly name: string;
1002
+ readonly description: string | undefined;
1003
+ readonly tools: ReadonlyArray<string> | undefined;
1004
+ readonly model: string | undefined;
1005
+ readonly tags: ReadonlyArray<string> | undefined;
1006
+ readonly systemPrompt: string;
1007
+ readonly source: "project" | "user";
1008
+ readonly sourcePath: string;
1009
+ }
1010
+ /**
1011
+ * Options for {@link SDKAgent.invalidateCache}.
1012
+ *
1013
+ * @public
1014
+ */
1015
+ interface InvalidateCacheOptions {
1016
+ /**
1017
+ * When `true`, dispose the agent immediately so caller must recreate it
1018
+ * to continue. Default `false` (deferred — applied on next `send()`).
1019
+ */
1020
+ applyNow?: boolean;
1021
+ }
1022
+
1023
+ /**
1024
+ * `MemoryProvider` — kernel-facing port for the memory subsystem
1025
+ * (SDK 2.0 Phase 1 / T1.1 — Hexagonal Architecture / Ports & Adapters,
1026
+ * SOLID Dependency Inversion).
1027
+ *
1028
+ * The agent loop kernel depends on THIS CONTRACT — not on the concrete
1029
+ * `internal/memory/*` modules. Default adapter ships with `@theokit/sdk`
1030
+ * (no-op for back-compat); rich impl ships in `@theokit/sdk-memory`.
1031
+ * Consumers opt-in via `Agent.create({ memoryProvider: ... })`.
1032
+ *
1033
+ * DIP-correct home (SE46): the port + companion contract types live in the
1034
+ * domain `types/` layer; the application-layer module
1035
+ * (`internal/runtime/memory/memory-provider.ts`) re-exports them for
1036
+ * back-compat while the concrete providers live under `internal/`.
1037
+ *
1038
+ * Layered model (mirrors Budget):
1039
+ * - `MemoryAdapter` (in `types/memory-adapter.ts`) — LOW-LEVEL data port:
1040
+ * write / recall / delete primitives.
1041
+ * - `MemoryProvider` (THIS FILE) — HIGH-LEVEL lifecycle port: init,
1042
+ * tool factories, active memory pass, embedding runtime selection.
1043
+ *
1044
+ * @public — surface-level interface; impls are internal-but-replaceable.
1045
+ */
1046
+
1047
+ /** Result of `MemoryProvider.runActivePass(...)` — what the kernel injects into the LLM call. */
1048
+ interface ActiveMemoryPassResult {
1049
+ /** Compressed memory facts to seed the LLM's context window for this turn. */
1050
+ readonly facts: ReadonlyArray<MemoryFact>;
1051
+ /** Optional system-prompt enrichment derived from the recalled facts. */
1052
+ readonly systemPromptAdditions?: string;
1053
+ /** Whether the active-memory circuit breaker tripped (degraded mode). */
1054
+ readonly breakerTripped?: boolean;
1055
+ }
1056
+ /** Arguments for `MemoryProvider.runActivePass(...)`. */
1057
+ interface ActiveMemoryPassArgs {
1058
+ /** The current user message — used as the recall query. */
1059
+ readonly userMessage: string;
1060
+ /** Conversation history (most recent first). */
1061
+ readonly history: ReadonlyArray<{
1062
+ role: "user" | "assistant";
1063
+ content: string;
1064
+ }>;
1065
+ /** Agent identity for scope. */
1066
+ readonly agentId: string;
1067
+ }
1068
+ /**
1069
+ * Arguments for `MemoryProvider.recordSessionSummary(...)`
1070
+ * (SDK 2.0 Phase 1 physical Stage 3 prep — iter 27).
1071
+ *
1072
+ * The "session summary" is the markdown that gets written to disk
1073
+ * after a finished run + indexed under `corpus="sessions"`. This
1074
+ * port method lets sdk-core's `post-run-lifecycle.ts` delegate the
1075
+ * write to the provider instead of importing
1076
+ * `internal/memory/storage/session-summary-writer.ts` directly.
1077
+ *
1078
+ * @public
1079
+ */
1080
+ interface RecordSessionSummaryArgs {
1081
+ /**
1082
+ * Workspace cwd where on-disk artefacts live. Included on the args
1083
+ * (not on a handle) because `recordSessionSummary` is STATELESS — it
1084
+ * runs AFTER `runAgentLoop`'s `dispose()` releases the per-run handle.
1085
+ * The kernel passes its own `workspaceCwd`; the impl uses it to
1086
+ * compute the markdown file path.
1087
+ */
1088
+ readonly cwd: string;
1089
+ /** Run id used as the filename key. */
1090
+ readonly runId: string;
1091
+ /** Agent identity for scope (foldering). */
1092
+ readonly agentId: string;
1093
+ /** Verbatim user message that started the run. */
1094
+ readonly userText: string;
1095
+ /** Final assistant text the run produced. */
1096
+ readonly assistantText: string;
1097
+ /** Final run status (only "finished" is recorded today). */
1098
+ readonly status: "finished" | "error" | "cancelled";
1099
+ /** Wall-clock ms at write time. */
1100
+ readonly at: number;
1101
+ }
1102
+ /** Options for `MemoryProvider.init(...)`. */
1103
+ interface MemoryProviderInitOptions {
1104
+ /** Workspace cwd where on-disk artefacts live (`.theokit/memory/...`). */
1105
+ readonly cwd: string;
1106
+ /** Embedding-provider id (`"openai" | "ollama" | ...`); when omitted the impl picks a default. */
1107
+ readonly embeddingProviderId?: string;
1108
+ }
1109
+ /**
1110
+ * Opaque handle returned by `init()`. Carried back into other methods so
1111
+ * the impl can stash per-agent state (index, breaker, cache, …) without
1112
+ * exposing it to the kernel.
1113
+ */
1114
+ interface MemoryProviderHandle {
1115
+ /** Adapter interface for direct read/write — matches existing `MemoryAdapter` shape. */
1116
+ readonly adapter: MemoryAdapter;
1117
+ /** Implementation-defined opaque field (private state pointer / index handle). */
1118
+ readonly [implState: symbol]: unknown;
1119
+ }
1120
+ /**
1121
+ * The kernel-facing contract. Implementations live OUTSIDE the agent loop
1122
+ * (in `@theokit/sdk-memory` after Phase 1; in `internal/memory/` until then).
1123
+ *
1124
+ * Implementations MUST be:
1125
+ * - **Lazy** — `init()` may be called once per agent; subsequent calls
1126
+ * return the same handle (impl decides via cache). Heavy work
1127
+ * (loading the index, opening SQLite) deferred until first use.
1128
+ * - **Non-throwing on the hot path** — `runActivePass()` returns an
1129
+ * empty `facts: []` on degradation rather than throwing. Errors
1130
+ * surface via the breakerTripped flag + telemetry.
1131
+ */
1132
+ interface MemoryProvider {
1133
+ /** Construct or fetch the per-agent handle. Lazy + idempotent. */
1134
+ init(opts: MemoryProviderInitOptions): Promise<MemoryProviderHandle>;
1135
+ /** Build the LLM-facing tool catalog (memory_search, memory_get, …). */
1136
+ buildTools(handle: MemoryProviderHandle, agent: SDKAgent): ReadonlyArray<CustomTool>;
1137
+ /** Run the active-memory pre-LLM pass — recall + compress + format. */
1138
+ runActivePass(handle: MemoryProviderHandle, args: ActiveMemoryPassArgs): Promise<ActiveMemoryPassResult>;
1139
+ /**
1140
+ * Optional post-run hook (SDK 2.0 Phase 1 physical Stage 1 — iter 19).
1141
+ * Called by the agent loop AFTER a successful send so the impl can
1142
+ * incorporate the session summary into its index (e.g., re-index the
1143
+ * `sessions` corpus so the next recall sees it).
1144
+ *
1145
+ * Fire-and-forget at the call site; impl MUST be idempotent +
1146
+ * non-throwing. Optional so existing impls (createNoopMemoryProvider,
1147
+ * sdk-memory@0.1.0) keep working without modification.
1148
+ *
1149
+ * Mirrors the role of `LocalAgentMemory.syncIfReady()` in sdk-core's
1150
+ * legacy memory path — exposing it via the port is the seam that
1151
+ * unblocks moving LocalAgentMemory's logic out to sdk-memory.
1152
+ */
1153
+ sync?(handle: MemoryProviderHandle): Promise<void> | void;
1154
+ /**
1155
+ * Optional session-summary write hook (SDK 2.0 Phase 1 physical
1156
+ * Stage 3 prep — iter 27, refined iter 28).
1157
+ *
1158
+ * Called by `post-run-lifecycle.ts` AFTER a finished run to persist
1159
+ * the run's session-summary markdown under `corpus="sessions"`. When
1160
+ * defined, the kernel delegates the write to the provider; when
1161
+ * undefined, post-run-lifecycle falls back to the direct
1162
+ * `writeSessionSummary` import (legacy path, until Stage 3 source
1163
+ * move drops that import entirely).
1164
+ *
1165
+ * STATELESS — does NOT take a `MemoryProviderHandle` because post-run-
1166
+ * lifecycle runs AFTER `runAgentLoop` disposed the per-run handle.
1167
+ * `cwd` lives on `args` instead. Impls that need per-agent state can
1168
+ * cache it via closure inside the provider factory.
1169
+ *
1170
+ * Impl MUST be non-throwing on the hot path. The kernel swallows
1171
+ * any throw + emits a stderr warning.
1172
+ *
1173
+ * Optional so existing impls (createNoopMemoryProvider,
1174
+ * createInMemoryMarkdownProvider) keep working without modification.
1175
+ */
1176
+ recordSessionSummary?(args: RecordSessionSummaryArgs): Promise<void> | void;
1177
+ /** Release the handle (close index, flush caches). Idempotent + non-throwing. */
1178
+ dispose(handle: MemoryProviderHandle): Promise<void> | void;
1179
+ }
1180
+
1181
+ /**
1182
+ * ProviderProfile + ApiMode + AuthType contract types (T3.1, ADR D105).
1183
+ *
1184
+ * Profile is **data-only** — no methods. Adding a provider is declaring an
1185
+ * object literal; the Transport layer (D106) consumes `apiMode` to pick
1186
+ * the HTTP dialect.
1187
+ *
1188
+ * SE45/SE46 — relocated from `internal/providers/types.ts` into `types/` so the
1189
+ * public contract (embedded in the `Plugin` type) lives above the DIP boundary;
1190
+ * `internal/providers/types.ts` re-exports these names for back-compat.
1191
+ *
1192
+ * @public
1193
+ */
1194
+ type ApiMode = "chat_completions" | "anthropic_messages" | "responses_api" | "bedrock" | "bedrock_anthropic";
1195
+ type AuthType = "api_key" | "oauth_device_code" | "oauth_external" | "aws_sdk" | "aws_bearer" | "gcp_oauth" | "none";
1196
+ /**
1197
+ * M41 (agent-builder provider framework) — the context a provider's `transform` receives per request. An
1198
+ * object from day one so it can grow without breaking (M42 adds the resolved `credential`).
1199
+ *
1200
+ * @public
1201
+ */
1202
+ interface ProviderTransformContext {
1203
+ /** The bearer the router resolved for this request (env var, injected key, or an oauth access token). */
1204
+ apiKey: string;
1205
+ }
1206
+ /**
1207
+ * M41 — the one OPTIONAL behavior seam on a provider profile. It lets a provider own its per-request auth:
1208
+ * `fetch` is the universal seam (a provider that returns its own fetch fully controls headers + refresh, for
1209
+ * every transport that accepts a fetch); `headers` is a convenience merged over `extraHeaders` on transports
1210
+ * that carry them (responses_api). This is the CONTRACT-shape adaptation of OpenCode's provider `auth.loader`
1211
+ * (MIT © 2025 opencode — `packages/core/src/plugin/provider/*.ts`), retargeted to theokit's transport model.
1212
+ * Closes the gap where a `ProviderProfile` could only declare STATIC headers.
1213
+ *
1214
+ * @public
1215
+ */
1216
+ interface ProviderTransform {
1217
+ /**
1218
+ * Dynamic per-request headers, merged OVER the profile's static `extraHeaders`, and spread AFTER the
1219
+ * transport's base `authorization`/`content-type`. A provider that owns its auth MAY intentionally set
1220
+ * `authorization` here to override the resolved bearer — but a stray `authorization`/`content-type` key
1221
+ * will silently replace the base header, so return only the headers you mean to add.
1222
+ */
1223
+ headers?(ctx: ProviderTransformContext): Record<string, string>;
1224
+ /** A fetch to use for this provider's requests (refresh-aware / fully provider-controlled). */
1225
+ fetch?(ctx: ProviderTransformContext): typeof fetch;
1226
+ }
1227
+ interface ProviderProfile {
1228
+ name: string;
1229
+ apiMode: ApiMode;
1230
+ aliases?: ReadonlyArray<string>;
1231
+ displayName?: string;
1232
+ description?: string;
1233
+ signupUrl?: string;
1234
+ envVars: ReadonlyArray<string>;
1235
+ authType: AuthType;
1236
+ baseUrl: string;
1237
+ modelsUrl?: string;
1238
+ hostname?: string;
1239
+ fallbackModels: ReadonlyArray<string>;
1240
+ extraHeaders?: Record<string, string>;
1241
+ /**
1242
+ * M45 — explicit chat-completions path override (data-only). Absent, the transport derives it: a baseUrl
1243
+ * whose path already carries a version segment (`/v1`, `/v2beta`, …) gets `/chat/completions` appended;
1244
+ * a host-only baseUrl keeps the legacy `/v1/chat/completions`. Set this for shapes neither rule expresses
1245
+ * (e.g. Perplexity's unversioned `/chat/completions`).
1246
+ */
1247
+ chatCompletionsPath?: string;
1248
+ bodyOverrides?: Record<string, unknown>;
1249
+ /**
1250
+ * M41 — the optional per-request behavior seam (dynamic headers + refresh-aware fetch). Absent ⇒ the profile
1251
+ * is pure data and takes the static path byte-for-byte. See {@link ProviderTransform}.
1252
+ */
1253
+ transform?: ProviderTransform;
1254
+ /**
1255
+ * Opt-in leaked-dialect safe-parse (theokit#58 follow-up). When `true`, a chat_completions finish
1256
+ * with ZERO native `tool_calls` has its assistant content scanned for the Hermes
1257
+ * `<function=…></tool_call>` dialect and any recovered calls are surfaced as real `tool_calls`.
1258
+ * Default off — only enable for routes/models known to leak (e.g. a qwen3-coder profile variant).
1259
+ */
1260
+ extractToolCallsFromContent?: boolean;
1261
+ }
1262
+
1263
+ type HookName = "pre_tool_call" | "post_tool_call" | "pre_llm_call" | "post_llm_call" | "on_session_start" | "on_session_end" | "transform_tool_result" | "transform_llm_output" | "pre_user_send" | "post_assistant_reply";
1264
+ interface PreToolCallContext {
1265
+ name: string;
1266
+ args: Record<string, unknown>;
1267
+ agentId: string;
1268
+ runId: string;
1269
+ /**
1270
+ * SE1 — the run's resolved `PermissionMode` (from `SendOptions.permissionMode`
1271
+ * ?? `AgentOptions.permissionMode`), threaded so a permission-style plugin can
1272
+ * gate per-run rather than at construction time. Absent ⇒ the plugin's own
1273
+ * default applies. Ignored by non-permission plugins.
1274
+ */
1275
+ permissionMode?: PermissionMode;
1276
+ }
1277
+ interface PreToolCallDecision {
1278
+ block: true;
1279
+ message: string;
1280
+ }
1281
+ /**
1282
+ * Context passed to `pre_user_send` hook handlers (ADR D145).
1283
+ *
1284
+ * @public
1285
+ */
1286
+ interface PreUserSendContext {
1287
+ prompt: string;
1288
+ agentId: string;
1289
+ runId: string;
1290
+ /** Caller-supplied memory context, flowing through from `AgentOptions.memoryContext`. */
1291
+ memoryContext?: MemoryContext;
1292
+ /** Forwarded `AbortSignal` so adapter recall HTTP can be cancelled mid-flight (EC-H). */
1293
+ signal?: AbortSignal;
1294
+ }
1295
+ /**
1296
+ * Optional result returned by `pre_user_send` handlers. The agent loop
1297
+ * concatenates `recalledContext` from all handlers and injects it as a
1298
+ * `<memory-context>...</memory-context>` block before the user prompt.
1299
+ *
1300
+ * @public
1301
+ */
1302
+ interface PreUserSendResult {
1303
+ recalledContext?: string;
1304
+ }
1305
+ /**
1306
+ * Context passed to `post_assistant_reply` hook handlers (ADR D145).
1307
+ * Fire-and-forget — exceptions are caught and surfaced to stderr; the
1308
+ * caller's `wait()` never blocks on this dispatch.
1309
+ *
1310
+ * @public
1311
+ */
1312
+ interface PostAssistantReplyContext {
1313
+ prompt: string;
1314
+ reply: string;
1315
+ agentId: string;
1316
+ runId: string;
1317
+ memoryContext?: MemoryContext;
1318
+ }
1319
+ type HookHandler = (ctx: unknown) => unknown | Promise<unknown>;
1320
+ type CommandHandler = (args: Record<string, unknown>) => Promise<string> | string;
1321
+ interface CommandOptions {
1322
+ description?: string;
1323
+ }
1324
+ interface PluginContext {
1325
+ /** Register a custom tool. Equivalent to passing in `AgentOptions.tools`. */
1326
+ registerTool(tool: CustomTool): void;
1327
+ /** Register a slash-command-style handler. Consumed by CLI/bot wrappers; NOT used by the agent loop. */
1328
+ registerCommand(name: string, handler: CommandHandler, opts?: CommandOptions): void;
1329
+ /** Attach a hook handler. `pre_tool_call` supports veto via `PreToolCallDecision`. */
1330
+ on(hook: HookName, handler: HookHandler): void;
1331
+ /** Inject a user/system message into the next agent turn. v1 supports only `on_session_start` context. */
1332
+ injectMessage(content: string, role?: "user" | "system"): void;
1333
+ }
1334
+ interface BasePlugin {
1335
+ name: string;
1336
+ version: string;
1337
+ }
1338
+ type Plugin = (BasePlugin & {
1339
+ kind: "general";
1340
+ register: (ctx: PluginContext) => void | Promise<void>;
1341
+ }) | (BasePlugin & {
1342
+ kind: "model-provider";
1343
+ profile: ProviderProfile;
1344
+ }) | (BasePlugin & {
1345
+ kind: "memory";
1346
+ createProvider: MemoryProviderFactory;
1347
+ });
1348
+
1349
+ /**
1350
+ * Which on-disk settings layers a local agent loads.
1351
+ *
1352
+ * @public
1353
+ */
1354
+ type SettingSource = "project" | "user" | "team" | "mdm" | "plugins" | "all";
1355
+ /**
1356
+ * Local agent configuration.
1357
+ *
1358
+ * @public
1359
+ */
1360
+ interface LocalOptions {
1361
+ cwd?: string | string[];
1362
+ settingSources?: SettingSource[];
1363
+ sandboxOptions?: {
1364
+ enabled: boolean;
1365
+ };
1366
+ /**
1367
+ * SE40 — base directory for the native Claude-shaped session transcript
1368
+ * (`<baseDir>/projects/<encoded-cwd>/<agentId>.jsonl`). Default `~/.theokit`.
1369
+ * Set to `~/.claude` to write sessions the Claude Code CLI can `--continue`.
1370
+ */
1371
+ baseDir?: string;
1372
+ /**
1373
+ * SE41 — inject an external {@link import("./session-store.js").SessionStore}
1374
+ * (Postgres / Redis / KV / durable object) as the PRIMARY session store and
1375
+ * resume source. Omit for the default FS transcript store (`baseDir` above) —
1376
+ * byte-identical to SE40. Use this for serverless (ephemeral FS) or multi-host /
1377
+ * multi-pod deployments where a resumed agent must read its history from a shared
1378
+ * store instead of local disk. The records stay the native Claude-shaped shape,
1379
+ * so `--continue` interop is preserved (a store may also mirror to `~/.claude`).
1380
+ */
1381
+ sessionStore?: SessionStore;
1382
+ }
1383
+ /**
1384
+ * Repo to clone into a cloud agent's VM.
1385
+ *
1386
+ * @public
1387
+ */
1388
+ interface CloudRepo {
1389
+ url: string;
1390
+ startingRef?: string;
1391
+ prUrl?: string;
1392
+ }
1393
+ /**
1394
+ * Cloud execution environment.
1395
+ *
1396
+ * @public
1397
+ */
1398
+ interface CloudEnv {
1399
+ type: "cloud" | "pool" | "machine";
1400
+ name?: string;
1401
+ }
1402
+ /**
1403
+ * Cloud agent configuration.
1404
+ *
1405
+ * @public
1406
+ */
1407
+ interface CloudOptions {
1408
+ env?: CloudEnv;
1409
+ repos?: CloudRepo[];
1410
+ workOnCurrentBranch?: boolean;
1411
+ autoCreatePR?: boolean;
1412
+ skipReviewerRequest?: boolean;
1413
+ /**
1414
+ * Short-lived credentials scoped to the agent. Encrypted at rest, deleted
1415
+ * with the agent. Names must not start with `THEOKIT_`.
1416
+ */
1417
+ envVars?: Record<string, string>;
1418
+ }
1419
+ /**
1420
+ * Subagent definition. The parent agent spawns these via its Agent tool.
1421
+ *
1422
+ * @public
1423
+ */
1424
+ interface AgentDefinition {
1425
+ description: string;
1426
+ prompt: string;
1427
+ model?: ModelSelection | "inherit";
1428
+ mcpServers?: Array<string | Record<string, McpServerConfig>>;
1429
+ /**
1430
+ * Tool whitelist (M4-6). When set, the sub-agent may ONLY call tools whose
1431
+ * canonical (post-repair, lowercase) name is in this list — any other tool
1432
+ * call is vetoed at dispatch via the same `withToolWhitelist` enforcement
1433
+ * forks use (NOT `PermissionEngine`). Absent/empty → unscoped (inherits the
1434
+ * parent's full toolset). Apply with `withSubagentToolScope`.
1435
+ */
1436
+ tools?: string[];
1437
+ /**
1438
+ * Per-subagent shell sandbox toggle. When `true`, the spawned child runs with
1439
+ * `local.sandboxOptions.enabled = true` (the SDK's boolean shell sandbox). Absent
1440
+ * ⇒ inherit the parent's sandbox posture. The SDK has no granular sandbox *mode*
1441
+ * (read-only / workspace-write / danger); a mode string in the disk frontmatter is
1442
+ * a typed load error, not a silent boolean coercion. Reasoning effort is NOT a
1443
+ * field here — it rides inside `model.params` (e.g. `[{ id: "thinking", value: "low" }]`).
1444
+ */
1445
+ sandbox?: boolean;
1446
+ }
1447
+ /**
1448
+ * Public view of a recalled memory fact exposed to the system-prompt resolver.
1449
+ *
1450
+ * @public
1451
+ */
1452
+ interface SystemPromptMemoryFact {
1453
+ text: string;
1454
+ }
1455
+ /**
1456
+ * Context passed to a {@link SystemPromptResolver}. Field order is a
1457
+ * compatibility contract: new fields are appended, never reordered.
1458
+ *
1459
+ * @public
1460
+ */
1461
+ interface SystemPromptContext {
1462
+ agentId: string;
1463
+ cwd: string | undefined;
1464
+ model: ModelSelection | undefined;
1465
+ skills: ReadonlyArray<SystemPromptSkillRef>;
1466
+ userMessage: string;
1467
+ /** Recalled durable facts when memory is enabled. Appended in v1.1. */
1468
+ memory: ReadonlyArray<SystemPromptMemoryFact>;
1469
+ }
1470
+ /**
1471
+ * Resolver function that produces the system prompt dynamically. Receives
1472
+ * the {@link SystemPromptContext} and returns a string (or a Promise of one).
1473
+ *
1474
+ * The SDK does NOT impose a timeout on the resolver — wrap your own
1475
+ * `Promise.race` if you call into slow resources. Errors propagate to the
1476
+ * caller of `agent.send()`.
1477
+ *
1478
+ * @public
1479
+ */
1480
+ type SystemPromptResolver = (ctx: SystemPromptContext) => string | Promise<string>;
1481
+ /**
1482
+ * Skills configuration accepted by `Agent.create()` via
1483
+ * {@link AgentOptions.skills}.
1484
+ *
1485
+ * Skills are discovered from `.theokit/skills/<name>/SKILL.md` when
1486
+ * `local.settingSources` includes `"project"`.
1487
+ *
1488
+ * @public
1489
+ */
1490
+ interface SkillsSettings {
1491
+ /**
1492
+ * Names of skills the parent agent may invoke. When omitted, every
1493
+ * discovered skill is enabled.
1494
+ */
1495
+ enabled?: string[];
1496
+ /**
1497
+ * Whether the SDK auto-injects the loaded skill list (name + description) as a
1498
+ * `<skills>` block in the LLM system prompt. Default `true`.
1499
+ *
1500
+ * Set to `false` when supplying a custom `systemPrompt` resolver that formats
1501
+ * skills itself.
1502
+ */
1503
+ autoInject?: boolean;
1504
+ /**
1505
+ * M22 — discover skills from a CUSTOM directory (containing `<name>/SKILL.md`) instead of the
1506
+ * default `<cwd>/.theokit/skills`. Absent ⇒ the default root.
1507
+ */
1508
+ skillsDir?: string;
1509
+ /**
1510
+ * M22 — code-defined skills (from `createSkill`) merged with the discovered ones. An inline skill
1511
+ * overrides a discovered file skill of the same name.
1512
+ */
1513
+ inline?: InlineSkill[];
1514
+ }
1515
+ /**
1516
+ * SE22 — context passed to a {@link SkillsResolver}. Mirrors
1517
+ * {@link SystemPromptContext} MINUS `skills`: the resolver runs BEFORE skills
1518
+ * are assembled, so the resolved list does not exist yet.
1519
+ *
1520
+ * @public
1521
+ */
1522
+ interface SkillsResolverContext {
1523
+ agentId: string;
1524
+ /** Workspace cwd. `string | undefined` mirrors {@link SystemPromptContext}; a local agent always passes a concrete path. */
1525
+ cwd: string | undefined;
1526
+ model: ModelSelection | undefined;
1527
+ userMessage: string;
1528
+ /** Recalled durable facts when memory is enabled. */
1529
+ memory: ReadonlyArray<SystemPromptMemoryFact>;
1530
+ }
1531
+ /**
1532
+ * SE22 — a resolver that produces {@link SkillsSettings} per run from runtime
1533
+ * context (e.g. the user's role). Mirrors the {@link SystemPromptResolver}
1534
+ * pattern: evaluated per `send()` BEFORE skill assembly, so a cached
1535
+ * `getOrCreate` agent re-resolves on every run.
1536
+ *
1537
+ * The SDK imposes NO timeout — wrap your own `Promise.race` for slow sources. A
1538
+ * throwing resolver fails the run (no silent fallback — Rule 8). Cloud agents
1539
+ * reject a function resolver (it can't run on PaaS); resolve to a static
1540
+ * {@link SkillsSettings} object before `Agent.create()`.
1541
+ *
1542
+ * @public
1543
+ */
1544
+ type SkillsResolver = (ctx: SkillsResolverContext) => SkillsSettings | Promise<SkillsSettings>;
1545
+ /**
1546
+ * Memory configuration accepted by `Agent.create()` via {@link AgentOptions.memory}.
1547
+ *
1548
+ * Persists durable facts under `.theokit/memory/<namespace>/<scope>-<userId>.json`.
1549
+ *
1550
+ * @public
1551
+ */
1552
+ interface MemorySettings {
1553
+ enabled: boolean;
1554
+ namespace?: string;
1555
+ userId?: string;
1556
+ scope?: "agent" | "user" | "team";
1557
+ storePath?: string;
1558
+ /**
1559
+ * Whether the SDK auto-injects recalled facts as a `<memory>` block in the
1560
+ * LLM system prompt. Default `true`.
1561
+ */
1562
+ autoInject?: boolean;
1563
+ /**
1564
+ * Index + tools configuration (memory-system-peer-project-parity).
1565
+ *
1566
+ * When `tools !== false`, the SDK registers `memory_search` and
1567
+ * `memory_get` with the LLM. Backed by SQLite + FTS5 (and sqlite-vec
1568
+ * when an embedding provider is configured).
1569
+ */
1570
+ index?: {
1571
+ /** Whether to register `memory_search` + `memory_get` tools. Default `true`. */
1572
+ tools?: boolean;
1573
+ /**
1574
+ * Vector index backend (ADR D43). Default `"sqlite-vec"`. Set to
1575
+ * `"lance"` to use `@lancedb/lancedb` (optional peer dep) for scale.
1576
+ */
1577
+ backend?: "sqlite-vec" | "lance";
1578
+ /** Embedding provider config. When omitted, the index runs in FTS-only mode. */
1579
+ embedding?: {
1580
+ provider: "openai" | "mistral" | "openrouter" | "voyage" | "deepinfra";
1581
+ model?: string;
1582
+ };
1583
+ };
1584
+ /**
1585
+ * Active Memory blocking recall (Phase 7). When `enabled: true`, runs
1586
+ * before each `send()` and prepends an `<active-memory>` block.
1587
+ */
1588
+ activeRecall?: {
1589
+ enabled?: boolean;
1590
+ queryMode?: "message" | "recent" | "full";
1591
+ timeoutMs?: number;
1592
+ maxSummaryChars?: number;
1593
+ persistTranscripts?: boolean;
1594
+ };
1595
+ }
1596
+ /**
1597
+ * Telemetry configuration for an agent. When `enabled: true`, the SDK emits
1598
+ * OpenTelemetry spans for `agent.send`, `llm.call`, `tool.call`, and
1599
+ * `memory.search`. See ADR D34.
1600
+ *
1601
+ * Privacy: content (prompts, responses, tool args) is OMITTED by default —
1602
+ * only timing/counts/IDs are recorded. Opt in via `includeContent: true`
1603
+ * to add prompt/response/args events to the spans (consumer's
1604
+ * responsibility to sanitize PII).
1605
+ *
1606
+ * `@opentelemetry/api` is an OPTIONAL peer dependency. Without it
1607
+ * installed, telemetry is a no-op even when `enabled: true`.
1608
+ *
1609
+ * @public
1610
+ */
1611
+ interface TelemetrySettings {
1612
+ /** Master switch. Default `false`. */
1613
+ enabled: boolean;
1614
+ /** Whether to include prompts/responses/tool args as span events. Default `false`. */
1615
+ includeContent?: boolean;
1616
+ /** Exporter selection. Default `"console"`. Custom exporters are passed-through. */
1617
+ exporter?: "console" | "otlp" | unknown;
1618
+ /** Service name on emitted spans. Default `"theokit-sdk"`. */
1619
+ serviceName?: string;
1620
+ /**
1621
+ * Auto-detect and register OTel exporters for installed observability
1622
+ * libs (Langfuse, Sentry, PostHog) via `createRequire` feature-detect.
1623
+ * Default `true`. See ADR D42.
1624
+ */
1625
+ autoDetect?: boolean;
1626
+ /**
1627
+ * Per-adapter opt-out. Lowercase names: `"langfuse" | "sentry" | "posthog"`.
1628
+ * Default `[]`.
1629
+ */
1630
+ disable?: string[];
1631
+ }
1632
+ /**
1633
+ * Top-level options accepted by `Agent.create()`.
1634
+ *
1635
+ * Pass either `local` or `cloud` to pick a runtime.
1636
+ *
1637
+ * @public
1638
+ */
1639
+ interface AgentOptions {
1640
+ /**
1641
+ * The model to run. SE8 — accepts a bare-string id shorthand
1642
+ * (`"openai/gpt-4o-mini"`, normalized to `{ id }`) OR a {@link ModelSelection}
1643
+ * object (use the object form to pass `params`).
1644
+ */
1645
+ model?: string | ModelSelection;
1646
+ /** Falls back to `THEOKIT_API_KEY`. */
1647
+ apiKey?: string;
1648
+ name?: string;
1649
+ /**
1650
+ * When `true`, `Agent.prompt` (and any helper that goes through `run.wait()`)
1651
+ * rejects with `AgentRunError` instead of resolving with `{ status: 'error' }`.
1652
+ * Cancelled runs (`status: 'cancelled'`) still resolve — cancel ≠ error.
1653
+ * If `result.error` is undefined despite `status: 'error'` (malformed RunResult),
1654
+ * the defensive guard resolves normally (no throw).
1655
+ *
1656
+ * Default `false` (backwards-compatible).
1657
+ *
1658
+ * @public
1659
+ */
1660
+ throwOnError?: boolean;
1661
+ /**
1662
+ * System prompt for the agent. Either a plain string or a resolver
1663
+ * function that receives the {@link SystemPromptContext} and returns the
1664
+ * prompt dynamically. Override per-call via {@link SendOptions.systemPrompt}.
1665
+ *
1666
+ * Subagents do NOT inherit this — they use {@link AgentDefinition.prompt}.
1667
+ */
1668
+ systemPrompt?: string | SystemPromptResolver;
1669
+ local?: LocalOptions;
1670
+ cloud?: CloudOptions;
1671
+ mcpServers?: Record<string, McpServerConfig>;
1672
+ agents?: Record<string, AgentDefinition>;
1673
+ agentId?: string;
1674
+ /** Context manager configuration. See `agent.context`. */
1675
+ context?: ContextSettings;
1676
+ /** Provider routing configuration. See `agent.providers`. */
1677
+ providers?: ProviderRoutingSettings;
1678
+ /**
1679
+ * Plugins for this agent, in one of two forms:
1680
+ *
1681
+ * - **Named-enable settings** — `{ enabled: ["name", ...] }`. Selects which
1682
+ * file-discovered plugin providers (under `.theokit/plugins/`) are active.
1683
+ * Plugin sources must also be active via `local.settingSources`.
1684
+ * - **Code `Plugin` objects** — an array of `Plugin` instances, e.g.
1685
+ * `plugins: [Handoff.asPlugin({ ... })]`. These are registered directly by
1686
+ * the runtime (`extractCodePlugins`); no `settingSources` entry is needed.
1687
+ *
1688
+ * The two forms are mutually exclusive — pass one or the other.
1689
+ */
1690
+ plugins?: PluginsSettings | readonly Plugin[];
1691
+ /**
1692
+ * SE1 — the default permission mode for this agent's runs, threaded to a
1693
+ * registered `PermissionPlugin`'s pre-tool gate. A per-send
1694
+ * `SendOptions.permissionMode` overrides it. Absent ⇒ the plugin's own
1695
+ * construction-time mode applies. Local runtime.
1696
+ */
1697
+ permissionMode?: PermissionMode;
1698
+ /**
1699
+ * Skills configuration. Either a static {@link SkillsSettings} object or —
1700
+ * SE22 — a {@link SkillsResolver} evaluated per `send()` to pick skills from
1701
+ * runtime context (e.g. user role). A cached agent re-resolves each run. The
1702
+ * agent-scoped `agent.skills` handle reflects the STATIC/base config; the
1703
+ * resolver drives the per-send `<skills>` block.
1704
+ */
1705
+ skills?: SkillsSettings | SkillsResolver;
1706
+ /**
1707
+ * SE24 — guardrail processors. `inputProcessors` run in order before the LLM
1708
+ * (normalize / validate / block / rewrite the user message); `outputProcessors`
1709
+ * run on the model's final text before it reaches the caller (redact / block).
1710
+ * A processor that `abort()`s stops the run with a {@link RunResult.tripwire}
1711
+ * (+ a `tripwire` run-event). Empty/absent ⇒ unchanged behavior. See
1712
+ * {@link Processor}.
1713
+ */
1714
+ inputProcessors?: readonly Processor[];
1715
+ outputProcessors?: readonly Processor[];
1716
+ /** Memory configuration. Persists durable facts; auto-recalled on send. */
1717
+ memory?: MemorySettings;
1718
+ /**
1719
+ * Inline custom tools. Local runtime only — cloud agents reject any non-empty
1720
+ * `tools` array. Handlers are not persisted; pass them again on resume.
1721
+ * See {@link CustomTool}.
1722
+ */
1723
+ tools?: CustomTool[];
1724
+ /**
1725
+ * SE37 — opt-in reasoning. When `true`, the agent gets a chain-of-thought
1726
+ * preamble prepended to its system prompt AND the `think` reasoning tool
1727
+ * auto-attached, turning a non-reasoning model into a reason -> act ->
1728
+ * observe loop (same model; reuses the existing tool loop). Default `false` —
1729
+ * byte-identical behaviour when unset. Inert (with a one-time warn) when a
1730
+ * native reasoning model is configured (`model.params: [{ id: "thinking" }]`),
1731
+ * so native and prompt-based reasoning never stack. See `ReasoningTools` in `@theokit/sdk-tools`.
1732
+ */
1733
+ reasoning?: boolean;
1734
+ /**
1735
+ * Telemetry (OpenTelemetry) configuration. Default disabled. See
1736
+ * {@link TelemetrySettings} and ADR D34.
1737
+ */
1738
+ telemetry?: TelemetrySettings;
1739
+ /**
1740
+ * Arbitrary metadata bag for caller-supplied provenance. Currently used by
1741
+ * the fork primitive (ADR D114) to tag `metadata.forkOrigin` and
1742
+ * `metadata.parentAgentId` so memory writes downstream can be attributed.
1743
+ *
1744
+ * Not persisted to the agent registry — informational only at runtime.
1745
+ *
1746
+ * @public
1747
+ */
1748
+ metadata?: Record<string, unknown>;
1749
+ /**
1750
+ * Default `MemoryContext` for third-party memory adapter plugins
1751
+ * (ADR D141). When set, `pre_user_send` / `post_assistant_reply`
1752
+ * hooks receive this context unless the caller overrides it. The
1753
+ * `agent.memory` direct API also defaults to it.
1754
+ *
1755
+ * @public
1756
+ */
1757
+ memoryContext?: MemoryContext;
1758
+ /**
1759
+ * Maximum byte length of the `<memory-context>` block injected by
1760
+ * `pre_user_send` adapter hooks (EC-A). Larger recalls are sliced
1761
+ * with `…[truncated]`. Default 16_000 (~4k tokens). Set lower for
1762
+ * cheaper turns; higher for longer-context models.
1763
+ *
1764
+ * @public
1765
+ */
1766
+ maxRecallContextBytes?: number;
1767
+ /**
1768
+ * Declarative handoff destinations (Adoption Roadmap #4; ADRs D214-D229).
1769
+ * Each entry is either a raw `SDKAgent` (auto-wrapped with defaults) OR a
1770
+ * `HandoffDescriptor` from `Handoff.create(target, opts?)`.
1771
+ *
1772
+ * Runtime injects synthetic `transfer_to_<receiver.name>` tools per
1773
+ * destination (D214/D215). When the LLM invokes one, the receiver takes
1774
+ * over the next turn (peer-to-peer, D217).
1775
+ *
1776
+ * @public
1777
+ */
1778
+ handoffs?: ReadonlyArray<SDKAgent | unknown>;
1779
+ /**
1780
+ * Maximum chain depth across handoffs per `agent.send()` call (D218).
1781
+ * Default 5. Exceeding throws `HandoffLoopError`. Set to 0 to disable
1782
+ * the handoff tools entirely (EC-8 / handoffs never fire).
1783
+ *
1784
+ * @public
1785
+ */
1786
+ maxHandoffDepth?: number;
1787
+ /**
1788
+ * Production-Readiness #6 — quota / abuse gates (ADRs D322-D323).
1789
+ *
1790
+ * `onBeforeCreate` fires BEFORE the agent is registered or persisted —
1791
+ * throw to block creation. `onBeforeSend` fires BEFORE each `agent.send`
1792
+ * (after `pre_user_send` adapter hooks, before any LLM call or storage
1793
+ * write) — throw to block the send.
1794
+ *
1795
+ * Unlike `onTool*` (observation), these hooks are BLOCKERS — errors
1796
+ * propagate as rejection on `Agent.create` / `agent.send`. Use them for
1797
+ * per-user conversation caps, per-conversation message caps, abuse
1798
+ * detection.
1799
+ *
1800
+ * @public
1801
+ */
1802
+ onBeforeCreate?: (event: {
1803
+ conversationId: string;
1804
+ userId?: string;
1805
+ }) => Promise<void> | void;
1806
+ /**
1807
+ * Fires before each `agent.send`. `previousMessageCount` is the count of
1808
+ * messages already persisted BEFORE the current send adds the user
1809
+ * message. Throw to block.
1810
+ *
1811
+ * @public
1812
+ */
1813
+ onBeforeSend?: (event: {
1814
+ conversationId: string;
1815
+ previousMessageCount: number;
1816
+ }) => Promise<void> | void;
1817
+ /**
1818
+ * Production-Readiness #4 — tool lifecycle hooks (ADRs D315-D317).
1819
+ *
1820
+ * `onToolStart` fires BEFORE the handler runs. `onToolEnd` fires after a
1821
+ * successful handler return. `onToolError` fires when validation fails OR
1822
+ * the handler throws — `event.error` is always an `Error` instance.
1823
+ *
1824
+ * Hook errors are SWALLOWED with a stderr warn (do not abort the run).
1825
+ * The `callId` is unique per tool invocation and identical across the
1826
+ * start/end (or start/error) pair, so consumers can correlate.
1827
+ *
1828
+ * Use cases: cost tracking, audit logs, per-tool retry/alerting,
1829
+ * latency telemetry.
1830
+ *
1831
+ * @public
1832
+ */
1833
+ onToolStart?: (event: {
1834
+ toolName: string;
1835
+ args: unknown;
1836
+ conversationId: string;
1837
+ callId: string;
1838
+ }) => void | Promise<void>;
1839
+ /** Fires when a tool handler returns successfully. */
1840
+ onToolEnd?: (event: {
1841
+ toolName: string;
1842
+ args: unknown;
1843
+ result: unknown;
1844
+ conversationId: string;
1845
+ callId: string;
1846
+ durationMs: number;
1847
+ }) => void | Promise<void>;
1848
+ /**
1849
+ * Fires when a tool handler throws OR schema validation rejects the args.
1850
+ * `event.error` is always an `Error` instance (D315/EC-6 — validation
1851
+ * reasons are wrapped in `new Error(reason)`).
1852
+ *
1853
+ * `attempt` is always `1` in v1 (D317 — reserved for future retry policy).
1854
+ */
1855
+ onToolError?: (event: {
1856
+ toolName: string;
1857
+ args: unknown;
1858
+ error: Error;
1859
+ conversationId: string;
1860
+ callId: string;
1861
+ durationMs: number;
1862
+ attempt: number;
1863
+ }) => void | Promise<void>;
1864
+ /**
1865
+ * Pluggable budget/usage tracker (SDK 2.0 Phase 2 / T2.1 — ADR D1 interface
1866
+ * inversion). When provided, the agent loop calls `tracker.track(...)`
1867
+ * after each LLM completion and `tracker.check()` before each iteration.
1868
+ *
1869
+ * **Status (Phase 2 incremental):** the option is wired to the type
1870
+ * surface only. Agent-loop runtime wiring is additive and lands in a
1871
+ * subsequent iteration — for now, the kernel still uses the legacy
1872
+ * `UsageAccumulator` + `IterationBudget` from `internal/budget/`.
1873
+ * Consumers passing a custom tracker today get the type guarantee but
1874
+ * NOT runtime enforcement.
1875
+ *
1876
+ * Default impls available today via `@theokit/sdk`:
1877
+ * - `createCounterBudgetTracker({ maxTokens, maxIterations })`
1878
+ *
1879
+ * Future: post-Phase-2, `@theokit/sdk-budget` ships a richer impl with
1880
+ * USD pricing.
1881
+ *
1882
+ * @public
1883
+ */
1884
+ budgetTracker?: BudgetTracker;
1885
+ /**
1886
+ * Pluggable memory subsystem (SDK 2.0 Phase 1 / T1.3 — Hexagonal
1887
+ * Architecture interface inversion). When provided, the agent loop
1888
+ * calls `provider.init(...)` once per agent, surfaces tools from
1889
+ * `provider.buildTools(...)` to the LLM, runs `provider.runActivePass(...)`
1890
+ * pre-LLM to inject recalled facts, and `provider.dispose(...)` on
1891
+ * Agent shutdown.
1892
+ *
1893
+ * **Status (Phase 1 incremental):** the option is wired to the type
1894
+ * surface only. Agent-loop runtime wiring is additive and lands in
1895
+ * subsequent iterations (T1.4 plumbing, T1.5 runtime hooks). For now,
1896
+ * the kernel still uses the legacy `Memory` class + `internal/memory/*`
1897
+ * runtime files. Consumers passing a custom provider today get the type
1898
+ * guarantee but NOT runtime enforcement.
1899
+ *
1900
+ * Default impls available today via `@theokit/sdk`:
1901
+ * - `createNoopMemoryProvider()` — degenerate fallback / worked example
1902
+ *
1903
+ * Future: post-Phase-1, `@theokit/sdk-memory` ships a rich impl with
1904
+ * LanceDB / embeddings / circuit breaker / active-memory cache.
1905
+ *
1906
+ * @public
1907
+ */
1908
+ memoryProvider?: MemoryProvider;
1909
+ }
1910
+ /**
1911
+ * Metadata returned by `Agent.list()` and `Agent.get()`.
1912
+ *
1913
+ * @public
1914
+ */
1915
+ type SDKAgentInfo = {
1916
+ agentId: string;
1917
+ name: string;
1918
+ summary: string;
1919
+ lastModified: number;
1920
+ status?: "running" | "finished" | "error";
1921
+ createdAt?: number;
1922
+ archived?: boolean;
1923
+ } & ({
1924
+ runtime?: undefined;
1925
+ } | {
1926
+ runtime: "local";
1927
+ cwd?: string;
1928
+ } | {
1929
+ runtime: "cloud";
1930
+ env?: CloudEnv;
1931
+ repos?: string[];
1932
+ });
1933
+ /**
1934
+ * Options for `Agent.list()`.
1935
+ *
1936
+ * @public
1937
+ */
1938
+ type ListAgentsOptions = {
1939
+ limit?: number;
1940
+ cursor?: string;
1941
+ } & ({
1942
+ runtime?: undefined;
1943
+ } | {
1944
+ runtime: "local";
1945
+ cwd?: string;
1946
+ } | {
1947
+ runtime: "cloud";
1948
+ prUrl?: string;
1949
+ includeArchived?: boolean;
1950
+ apiKey?: string;
1951
+ });
1952
+ /**
1953
+ * Options for `Agent.get()`.
1954
+ *
1955
+ * @public
1956
+ */
1957
+ interface GetAgentOptions {
1958
+ cwd?: string;
1959
+ apiKey?: string;
1960
+ }
1961
+ /**
1962
+ * Options for `Agent.listRuns()`.
1963
+ *
1964
+ * @public
1965
+ */
1966
+ type ListRunsOptions = {
1967
+ limit?: number;
1968
+ cursor?: string;
1969
+ } & ({
1970
+ runtime?: "local";
1971
+ cwd?: string;
1972
+ } | {
1973
+ runtime: "cloud";
1974
+ apiKey?: string;
1975
+ });
1976
+ /**
1977
+ * Options for `Agent.getRun()`. Cloud requires the parent `agentId`.
1978
+ *
1979
+ * @public
1980
+ */
1981
+ type GetRunOptions = {
1982
+ runtime?: "local";
1983
+ cwd?: string;
1984
+ } | {
1985
+ runtime: "cloud";
1986
+ agentId: string;
1987
+ apiKey?: string;
1988
+ };
1989
+ /**
1990
+ * Options for archive/unarchive/delete.
1991
+ *
1992
+ * @public
1993
+ */
1994
+ interface AgentOperationOptions {
1995
+ cwd?: string;
1996
+ apiKey?: string;
1997
+ }
1998
+ /**
1999
+ * Paginated list shape.
2000
+ *
2001
+ * @public
2002
+ */
2003
+ interface ListResult<T> {
2004
+ items: T[];
2005
+ nextCursor?: string;
2006
+ }
2007
+
2008
+ /**
2009
+ * Public type contract for `Workflow.create / .run / .resume` (Adoption
2010
+ * Roadmap #5; ADRs D230-D248).
2011
+ *
2012
+ * Step types form a discriminated union by `kind`. Helper factory functions
2013
+ * (`fn()`, `agentStep()`) live in `workflow.ts` and hide the discriminator
2014
+ * from end users.
2015
+ *
2016
+ * @public
2017
+ */
2018
+
2019
+ type Step = FnStep | AgentStep | ParallelStep | BranchStep | ForeachStep | DowhileStep | SleepStep | SuspendStep;
2020
+ /** A pure function step. */
2021
+ interface FnStep {
2022
+ readonly kind: "fn";
2023
+ readonly id: string;
2024
+ readonly fn: (input: unknown, ctx: StepContext) => Promise<unknown> | unknown;
2025
+ readonly inputSchema?: ZodType;
2026
+ readonly outputSchema?: ZodType;
2027
+ readonly retry?: RetryPolicy;
2028
+ /** D238 — slot reserved; runtime throws if engine not yet implemented. */
2029
+ readonly compensate?: (input: unknown, output: unknown, error: Error) => Promise<void> | void;
2030
+ }
2031
+ /** An agent.send-driven step. */
2032
+ interface AgentStep {
2033
+ readonly kind: "agent";
2034
+ readonly id: string;
2035
+ readonly agent: SDKAgent;
2036
+ readonly promptTemplate: string | ((input: unknown) => string);
2037
+ readonly retry?: RetryPolicy;
2038
+ /**
2039
+ * SE3 — provenance stamped onto this step's `agent.send()` (forwarded to
2040
+ * `RunResult.origin`). Squad sets `{ kind: "peer", from: "agent-<i-1>" }` on
2041
+ * every step after the first so a peer-driven turn is attributable.
2042
+ */
2043
+ readonly origin?: MessageOrigin;
2044
+ }
2045
+ /** N concurrent branches, each its own mini-step-list. */
2046
+ interface ParallelStep {
2047
+ readonly kind: "parallel";
2048
+ readonly id: string;
2049
+ readonly branches: ReadonlyArray<ReadonlyArray<Step>>;
2050
+ readonly concurrency?: number;
2051
+ readonly errorPolicy?: "fail-fast" | "collect";
2052
+ }
2053
+ /** First-match-wins predicates + optional fallback. */
2054
+ interface BranchStep {
2055
+ readonly kind: "branch";
2056
+ readonly id: string;
2057
+ readonly predicates: ReadonlyArray<readonly [(input: unknown) => boolean | Promise<boolean>, ReadonlyArray<Step>]>;
2058
+ readonly fallback?: ReadonlyArray<Step>;
2059
+ }
2060
+ /** Map a step over an upstream array output. */
2061
+ interface ForeachStep {
2062
+ readonly kind: "foreach";
2063
+ readonly id: string;
2064
+ /** ID of an upstream top-level step whose output is iterable. */
2065
+ readonly iterableFrom: string;
2066
+ readonly step: Step;
2067
+ readonly concurrency?: number;
2068
+ }
2069
+ /** Loop a step until condFn returns false. */
2070
+ interface DowhileStep {
2071
+ readonly kind: "dowhile";
2072
+ readonly id: string;
2073
+ readonly step: Step;
2074
+ readonly condFn: (output: unknown, iteration: number) => boolean | Promise<boolean>;
2075
+ readonly maxIterations?: number;
2076
+ }
2077
+ /** Pause for a fixed duration. */
2078
+ interface SleepStep {
2079
+ readonly kind: "sleep";
2080
+ readonly id: string;
2081
+ readonly durationMs: number;
2082
+ }
2083
+ /** Standalone explicit suspend point. */
2084
+ interface SuspendStep {
2085
+ readonly kind: "suspend";
2086
+ readonly id: string;
2087
+ readonly payloadSchema?: ZodType;
2088
+ }
2089
+ /** D237 — retry policy applied per fn/agent step. */
2090
+ interface RetryPolicy {
2091
+ /** Total attempts (MIN 1, MAX 20). `1` = no retry. */
2092
+ readonly maxAttempts: number;
2093
+ readonly initialBackoffMs?: number;
2094
+ readonly backoffCoefficient?: number;
2095
+ readonly maximumBackoffMs?: number;
2096
+ readonly nonRetryableErrors?: ReadonlyArray<string>;
2097
+ }
2098
+ /** D247 — context handed to every step.fn. */
2099
+ interface StepContext {
2100
+ readonly runId: string;
2101
+ readonly signal: AbortSignal;
2102
+ readonly log: {
2103
+ debug: (msg: string, attrs?: Record<string, unknown>) => void;
2104
+ info: (msg: string, attrs?: Record<string, unknown>) => void;
2105
+ warn: (msg: string, attrs?: Record<string, unknown>) => void;
2106
+ };
2107
+ /** Pause the workflow; resume via `Workflow.resume({...})`. */
2108
+ readonly suspend: (payload?: unknown) => Promise<never>;
2109
+ /**
2110
+ * SE29 — the workflow's shared state (from `WorkflowOptions.initialState`,
2111
+ * mutated by {@link setState}), visible to every subsequent step in the run.
2112
+ * `undefined` when no `initialState`/`setState` has run. Persisted across
2113
+ * suspend/resume.
2114
+ */
2115
+ readonly state: unknown;
2116
+ /**
2117
+ * SE29 — update the shared state for subsequent steps. Validated against
2118
+ * `WorkflowOptions.stateSchema` when set (a mismatch throws
2119
+ * {@link WorkflowStateError}, which fails the step/run — Rule 8).
2120
+ */
2121
+ readonly setState: (next: unknown) => void;
2122
+ }
2123
+ interface StepResult {
2124
+ readonly stepId: string;
2125
+ readonly kind: Step["kind"];
2126
+ readonly status: "completed" | "failed" | "skipped" | "suspended";
2127
+ readonly attempts: number;
2128
+ readonly durationMs: number;
2129
+ readonly output?: unknown;
2130
+ readonly error?: {
2131
+ name: string;
2132
+ message: string;
2133
+ };
2134
+ }
2135
+ interface WorkflowRun<TOutput = unknown> {
2136
+ readonly id: string;
2137
+ readonly name: string;
2138
+ readonly status: "running" | "completed" | "failed" | "suspended" | "cancelled";
2139
+ readonly output?: TOutput;
2140
+ readonly error?: {
2141
+ name: string;
2142
+ message: string;
2143
+ };
2144
+ readonly startedAt: number;
2145
+ readonly endedAt?: number;
2146
+ readonly stepResults: ReadonlyArray<StepResult>;
2147
+ }
2148
+ /**
2149
+ * SE28 — a step-level workflow event emitted by `Workflow.stream()` as top-level
2150
+ * steps run. Coarse-grained (one event per top-level step; nested
2151
+ * parallel/branch/foreach emit as their single wrapping step), distinct from the
2152
+ * token-delta agent stream. Discriminate on `type`.
2153
+ *
2154
+ * @public
2155
+ */
2156
+ type WorkflowEvent = {
2157
+ readonly type: "step_started";
2158
+ readonly stepId: string;
2159
+ } | {
2160
+ readonly type: "step_completed";
2161
+ readonly stepId: string;
2162
+ readonly output: unknown;
2163
+ } | {
2164
+ readonly type: "step_failed";
2165
+ readonly stepId: string;
2166
+ readonly error: {
2167
+ readonly name: string;
2168
+ readonly message: string;
2169
+ };
2170
+ } | {
2171
+ readonly type: "workflow_suspended";
2172
+ readonly stepId: string;
2173
+ } | {
2174
+ readonly type: "workflow_completed";
2175
+ };
2176
+ /**
2177
+ * SE28 — the async iterator returned by `Workflow.stream()`. Yields
2178
+ * {@link WorkflowEvent}s in execution order; `result` resolves to the same
2179
+ * terminal {@link WorkflowRun} the `run()` path returns (the authoritative
2180
+ * outcome — the stream ends when the run terminates).
2181
+ *
2182
+ * @public
2183
+ */
2184
+ type WorkflowStream<TOutput = unknown> = AsyncIterableIterator<WorkflowEvent> & {
2185
+ readonly result: Promise<WorkflowRun<TOutput>>;
2186
+ };
2187
+ interface WorkflowPersistenceOptions {
2188
+ readonly backend: "memory" | "json";
2189
+ /** Required for `backend: "json"`. */
2190
+ readonly dir?: string;
2191
+ }
2192
+ interface WorkflowOptions {
2193
+ readonly name: string;
2194
+ readonly persistence?: WorkflowPersistenceOptions;
2195
+ /**
2196
+ * SE27 — Zod schema for the WHOLE workflow's input. When set, `run(input)`
2197
+ * validates `input` BEFORE step 1; a mismatch yields `status: "failed"` with a
2198
+ * typed {@link WorkflowInputError} in `error` (fail-fast, no step runs, no
2199
+ * silent coerce). Absent ⇒ no whole-workflow input validation (unchanged).
2200
+ */
2201
+ readonly inputSchema?: ZodType;
2202
+ /**
2203
+ * SE27 — Zod schema for the workflow's final output. When set, the terminal
2204
+ * `completed` output is validated before `WorkflowRun.output` is populated; a
2205
+ * mismatch yields `status: "failed"` with a typed {@link WorkflowOutputError}.
2206
+ * Only validated on the `completed` path (suspended/failed runs skip it).
2207
+ */
2208
+ readonly outputSchema?: ZodType;
2209
+ /**
2210
+ * SE29 — Zod schema for the workflow's shared state (see `StepContext.state` /
2211
+ * `setState`). When set, `initialState` and every `setState(next)` are
2212
+ * validated against it (a mismatch throws {@link WorkflowStateError}). When
2213
+ * `initialState` is absent, `state` starts as `undefined` and validation fires
2214
+ * on the first `setState` call.
2215
+ */
2216
+ readonly stateSchema?: ZodType;
2217
+ /**
2218
+ * SE29 — the initial shared state, seeded onto `StepContext.state` before
2219
+ * step 1. Validated against `stateSchema` when both are set. Persisted across
2220
+ * suspend/resume.
2221
+ */
2222
+ readonly initialState?: unknown;
2223
+ /** Internal — minted at `.commit()`. Not user-facing. */
2224
+ readonly workflowId?: string;
2225
+ }
2226
+ interface WorkflowRunOptions {
2227
+ readonly signal?: AbortSignal;
2228
+ /** Override run ID for deterministic resume (advanced; default = mintRunId). */
2229
+ readonly runId?: string;
2230
+ /**
2231
+ * Opt-in Task wrapping (ADRs D363, D374). Registers the workflow run
2232
+ * as a `Task` (kind="workflow") with a `wf-` namespaced id (D368,
2233
+ * EC-5). The task transitions terminal when `Workflow.run` resolves.
2234
+ *
2235
+ * Auto-id: `wf-{runId}`.
2236
+ *
2237
+ * @public
2238
+ */
2239
+ readonly task?: true | {
2240
+ id?: string;
2241
+ meta?: Record<string, unknown>;
2242
+ };
2243
+ }
2244
+ interface WorkflowResumeOptions<TI = unknown> {
2245
+ readonly runId: string;
2246
+ readonly workflow: {
2247
+ run: (input: TI, opts?: WorkflowRunOptions) => Promise<WorkflowRun>;
2248
+ };
2249
+ readonly payload?: unknown;
2250
+ readonly signal?: AbortSignal;
2251
+ }
2252
+
2253
+ /**
2254
+ * Public `Workflow` class — declarative multi-step orchestration over
2255
+ * `Agent.send`, `Handoff`, `Agent.batch` and friends (Adoption Roadmap #5;
2256
+ * ADRs D230-D248).
2257
+ *
2258
+ * Usage:
2259
+ *
2260
+ * import { Agent } from "@theokit/sdk";
2261
+ * import { Workflow, fn, agentStep } from "@theokit/sdk/workflow";
2262
+ *
2263
+ * const classifier = await Agent.create({ ... });
2264
+ * const wf = Workflow.create({ name: "demo" })
2265
+ * .then(fn("validate", (input: { id: string }) => {
2266
+ * if (!input.id) throw new Error("missing id");
2267
+ * return input;
2268
+ * }))
2269
+ * .then(agentStep("classify", classifier, (i) => `Classify: ${JSON.stringify(i)}`))
2270
+ * .commit();
2271
+ *
2272
+ * const run = await wf.run({ id: "x" });
2273
+ * console.log(run.status, run.output);
2274
+ *
2275
+ * @public
2276
+ */
2277
+
2278
+ declare class WorkflowBuilder<TInput = unknown, TOutput = unknown> {
2279
+ private readonly options;
2280
+ private readonly _steps;
2281
+ private _committed;
2282
+ then<TO = unknown>(step: Step): WorkflowBuilder<TInput, TO>;
2283
+ parallel(branches: ReadonlyArray<ReadonlyArray<Step>>, opts?: {
2284
+ id?: string;
2285
+ concurrency?: number;
2286
+ errorPolicy?: "fail-fast" | "collect";
2287
+ }): WorkflowBuilder<TInput, unknown[]>;
2288
+ branch(predicates: BranchStep["predicates"], opts?: {
2289
+ id?: string;
2290
+ fallback?: ReadonlyArray<Step>;
2291
+ }): WorkflowBuilder<TInput, unknown>;
2292
+ foreach(iterableFrom: string, step: Step, opts?: {
2293
+ id?: string;
2294
+ concurrency?: number;
2295
+ }): WorkflowBuilder<TInput, unknown[]>;
2296
+ dowhile(step: Step, condFn: DowhileStep["condFn"], opts?: {
2297
+ id?: string;
2298
+ maxIterations?: number;
2299
+ }): WorkflowBuilder<TInput, unknown>;
2300
+ sleep(durationMs: number, id?: string): WorkflowBuilder<TInput, TOutput>;
2301
+ suspend(opts?: {
2302
+ id?: string;
2303
+ payloadSchema?: ZodType;
2304
+ }): WorkflowBuilder<TInput, unknown>;
2305
+ commit(): Workflow<TInput, TOutput>;
2306
+ private validateUniqueIds;
2307
+ private assertNotCommitted;
2308
+ }
2309
+ declare class Workflow<TInput = unknown, TOutput = unknown> {
2310
+ private readonly _options;
2311
+ private readonly _steps;
2312
+ /**
2313
+ * Construct a workflow builder. Validate options via Zod and return a
2314
+ * `WorkflowBuilder` for fluent chaining. Call `.commit()` to obtain the
2315
+ * immutable `Workflow`.
2316
+ */
2317
+ static create<TI = unknown, TO = unknown>(options: WorkflowOptions): WorkflowBuilder<TI, TO>;
2318
+ /**
2319
+ * Run this workflow with the given input. Returns a populated
2320
+ * `WorkflowRun`. Errors inside a step DO NOT throw — they propagate via
2321
+ * `run.status === "failed"`.
2322
+ */
2323
+ run(input: TInput, opts?: WorkflowRunOptions): Promise<WorkflowRun<TOutput>>;
2324
+ /**
2325
+ * SE28 — run the workflow and STREAM step-level events as they happen. Returns
2326
+ * an async iterator of {@link WorkflowEvent}s (`step_started` / `step_completed`
2327
+ * / `step_failed` / `workflow_suspended` / `workflow_completed`, top-level
2328
+ * steps) plus a `result` promise resolving to the same terminal
2329
+ * {@link WorkflowRun} `run()` returns. Iterate for progress; await `result` for
2330
+ * the outcome. The stream ends when the run terminates.
2331
+ *
2332
+ * `result` is the AUTHORITATIVE terminal status. Not every terminal state has a
2333
+ * closing event: a step failure emits `step_failed`, but an `outputSchema`
2334
+ * rejection (SE27) or an abort ends the stream WITHOUT `workflow_completed` —
2335
+ * always `await result` to read the final `status`. Consuming order is free:
2336
+ * awaiting `result` without draining, or draining without awaiting `result`,
2337
+ * both work (breaking out of `for await` stops the buffering early).
2338
+ */
2339
+ stream(input: TInput, opts?: WorkflowRunOptions): WorkflowStream<TOutput>;
2340
+ /**
2341
+ * Resume a suspended workflow from its snapshot. Throws
2342
+ * `WorkflowSnapshotNotFoundError` if `runId` is unknown.
2343
+ */
2344
+ static resume<TO = unknown>(opts: WorkflowResumeOptions): Promise<WorkflowRun<TO>>;
2345
+ }
2346
+
2347
+ /**
2348
+ * Runtime hosting a cron job. Mirrors the agent runtime split.
2349
+ *
2350
+ * - `local` — the in-process scheduler activated via `Cron.start()` fires the
2351
+ * job while the host process is alive.
2352
+ * - `cloud` — Theo PaaS schedules the job server-side; fires independent of
2353
+ * any SDK process.
2354
+ *
2355
+ * @public
2356
+ */
2357
+ type CronRuntime = "local" | "cloud";
2358
+ /**
2359
+ * Lifecycle state reported by `Cron.list()` / `Cron.get()`.
2360
+ *
2361
+ * @public
2362
+ */
2363
+ type CronJobStatus = "scheduled" | "running" | "paused" | "errored";
2364
+ /**
2365
+ * Persistent cron-scheduled invocation of the Theo agent or a workflow.
2366
+ *
2367
+ * Exactly one target is set: {@link CronJob.agent} (ephemeral agent created on
2368
+ * each fire), {@link CronJob.agentId} (bound to an existing agent for context
2369
+ * continuity), or {@link CronJob.workflow} (a committed workflow run per fire;
2370
+ * SE35). Agent targets carry a `message`; a workflow target carries `inputData`.
2371
+ *
2372
+ * @public
2373
+ */
2374
+ interface CronJob {
2375
+ id: string;
2376
+ name?: string;
2377
+ /** Standard 5-field POSIX cron expression or shorthand (`@hourly`, `@daily`, ...). */
2378
+ cron: string;
2379
+ /** IANA timezone identifier. Defaults to `"UTC"`. */
2380
+ timezone?: string;
2381
+ /** Message sent to the agent on each fire. Present for agent targets; absent for a workflow target. */
2382
+ message?: string | SDKUserMessage;
2383
+ /** Ephemeral agent options. Mutually exclusive with `agentId`/`workflow`. */
2384
+ agent?: AgentOptions;
2385
+ /** ID of an existing agent to reuse for context continuity. Mutually exclusive with `agent`/`workflow`. */
2386
+ agentId?: string;
2387
+ /**
2388
+ * SE35 — a committed {@link Workflow} run on each fire (`workflow.run(inputData)`).
2389
+ * Mutually exclusive with `agent`/`agentId`. Held in-memory (local runtime only —
2390
+ * a workflow instance cannot cross the cloud process boundary). ADR 0014.
2391
+ */
2392
+ workflow?: Workflow;
2393
+ /** SE35 — input passed to `workflow.run(inputData)` on each fire. Workflow targets only. */
2394
+ inputData?: unknown;
2395
+ /** Whether the scheduler will fire this job on schedule. */
2396
+ enabled: boolean;
2397
+ /** Current status. */
2398
+ status: CronJobStatus;
2399
+ /** Runtime that hosts this job. Inferred from `agent`/`agentId`/`workflow` at create time (a `workflow` target is always `local`). */
2400
+ runtime: CronRuntime;
2401
+ /** Unix ms of the last successful fire, if any. */
2402
+ lastRunAt?: number;
2403
+ /** Unix ms of the next scheduled fire, computed by the scheduler. */
2404
+ nextRunAt?: number;
2405
+ /** Unix ms when the job was created. */
2406
+ createdAt: number;
2407
+ }
2408
+ /**
2409
+ * Options for `Cron.create()`.
2410
+ *
2411
+ * Pass exactly ONE target: `agent` (ephemeral agent fresh per fire), `agentId`
2412
+ * (reuse an existing agent — preserves conversation context), or `workflow`
2413
+ * (SE35 — run a committed workflow per fire). Agent targets REQUIRE `message`;
2414
+ * a workflow target takes `inputData` and MUST NOT set `message`. Violations are
2415
+ * a `ConfigurationError`.
2416
+ *
2417
+ * @public
2418
+ */
2419
+ interface CronCreateOptions {
2420
+ cron: string;
2421
+ /** Message for an agent target. Required with `agent`/`agentId`; forbidden with `workflow`. */
2422
+ message?: string | SDKUserMessage;
2423
+ agent?: AgentOptions;
2424
+ agentId?: string;
2425
+ /** SE35 — a committed {@link Workflow} to run per fire. Mutually exclusive with `agent`/`agentId`. */
2426
+ workflow?: Workflow;
2427
+ /** SE35 — input for `workflow.run(inputData)`. Workflow targets only. */
2428
+ inputData?: unknown;
2429
+ name?: string;
2430
+ timezone?: string;
2431
+ /** Defaults to `true`. */
2432
+ enabled?: boolean;
2433
+ /** Falls back to `THEOKIT_API_KEY`. */
2434
+ apiKey?: string;
2435
+ }
2436
+ /**
2437
+ * Options for `Cron.list()`.
2438
+ *
2439
+ * @public
2440
+ */
2441
+ type CronListOptions = {
2442
+ limit?: number;
2443
+ cursor?: string;
2444
+ } & ({
2445
+ runtime?: undefined;
2446
+ } | {
2447
+ runtime: "local";
2448
+ cwd?: string;
2449
+ } | {
2450
+ runtime: "cloud";
2451
+ apiKey?: string;
2452
+ });
2453
+ /**
2454
+ * Options for `Cron.get()`.
2455
+ *
2456
+ * @public
2457
+ */
2458
+ interface CronGetOptions {
2459
+ cwd?: string;
2460
+ apiKey?: string;
2461
+ }
2462
+ /**
2463
+ * Options for `Cron.delete()` / `Cron.enable()` / `Cron.disable()`.
2464
+ *
2465
+ * @public
2466
+ */
2467
+ interface CronOperationOptions {
2468
+ cwd?: string;
2469
+ apiKey?: string;
2470
+ }
2471
+ /**
2472
+ * Options for `Cron.run()` — manually trigger a job off-schedule.
2473
+ *
2474
+ * @public
2475
+ */
2476
+ interface CronRunOptions {
2477
+ cwd?: string;
2478
+ apiKey?: string;
2479
+ }
2480
+ /**
2481
+ * Options for `Cron.start()` — activates the in-process scheduler for local
2482
+ * jobs.
2483
+ *
2484
+ * @public
2485
+ */
2486
+ interface CronStartOptions {
2487
+ /** Local workspace whose `.theokit/cron/jobs.json` to load. Defaults to `process.cwd()`. */
2488
+ cwd?: string;
2489
+ /** Override the env API key. */
2490
+ apiKey?: string;
2491
+ }
2492
+ /**
2493
+ * Snapshot of the local scheduler returned by `Cron.status()`.
2494
+ *
2495
+ * @public
2496
+ */
2497
+ interface CronSchedulerStatus {
2498
+ /** Whether the in-process scheduler is currently running. */
2499
+ running: boolean;
2500
+ /** Number of jobs loaded into the scheduler. */
2501
+ jobCount: number;
2502
+ /** Unix ms of the next scheduled fire across all jobs, if any. */
2503
+ nextFireAt?: number;
2504
+ /** Last error observed in the scheduler, if any. */
2505
+ lastError?: {
2506
+ jobId: string;
2507
+ message: string;
2508
+ at: number;
2509
+ };
2510
+ }
2511
+
2512
+ /**
2513
+ * Static façade for scheduling Theo agent runs on a cron expression.
2514
+ *
2515
+ * @public
2516
+ */
2517
+ declare class Cron {
2518
+ private constructor();
2519
+ /**
2520
+ * Create and persist a cron job.
2521
+ *
2522
+ * @public
2523
+ */
2524
+ static create(options: CronCreateOptions): Promise<CronJob>;
2525
+ /**
2526
+ * List cron jobs (local, cloud, or both).
2527
+ *
2528
+ * @public
2529
+ */
2530
+ static list(options?: CronListOptions): Promise<ListResult<CronJob>>;
2531
+ /**
2532
+ * Get a single cron job by ID.
2533
+ *
2534
+ * @public
2535
+ */
2536
+ static get(jobId: string, _options?: CronGetOptions): Promise<CronJob>;
2537
+ /**
2538
+ * Delete a cron job permanently.
2539
+ *
2540
+ * @public
2541
+ */
2542
+ static delete(jobId: string, _options?: CronOperationOptions): Promise<void>;
2543
+ /**
2544
+ * Re-enable a paused cron job.
2545
+ *
2546
+ * @public
2547
+ */
2548
+ static enable(jobId: string, _options?: CronOperationOptions): Promise<CronJob>;
2549
+ /**
2550
+ * Pause a cron job without deleting it.
2551
+ *
2552
+ * @public
2553
+ */
2554
+ static disable(jobId: string, _options?: CronOperationOptions): Promise<CronJob>;
2555
+ /**
2556
+ * Manually trigger a cron job off-schedule. Returns the resulting `Run`
2557
+ * (agent target) or `WorkflowRun` (workflow target — SE35).
2558
+ *
2559
+ * @public
2560
+ */
2561
+ static run(jobId: string, _options?: CronRunOptions): Promise<Run | WorkflowRun>;
2562
+ /**
2563
+ * Activate the in-process scheduler for local cron jobs.
2564
+ *
2565
+ * @public
2566
+ */
2567
+ static start(options?: CronStartOptions): Promise<void>;
2568
+ /**
2569
+ * Stop the in-process scheduler. Jobs are preserved.
2570
+ *
2571
+ * @public
2572
+ */
2573
+ static stop(): Promise<void>;
2574
+ /**
2575
+ * Snapshot of the local scheduler.
2576
+ *
2577
+ * @public
2578
+ */
2579
+ static status(_options?: CronStartOptions): Promise<CronSchedulerStatus>;
2580
+ }
2581
+
2582
+ export { type CronSchedulerStatus as $, type AgentOptions as A, type BudgetTracker as B, type CloudOptions as C, type BudgetUsageEvent as D, type CloudEnv as E, type CloudRepo as F, type GetAgentOptions as G, type ContextBudget as H, type InlineSkill as I, type ContextManagerKind as J, type ContextSnapshot as K, type LocalOptions as L, type MemorySettings as M, type ContextSource as N, type ContextSourceStatus as O, type ProviderRoutingSettings as P, type CreateSkillSpec as Q, Cron as R, type SystemPromptResolver as S, type CronCreateOptions as T, type CronGetOptions as U, type CronJob as V, type CronJobStatus as W, type CronListOptions as X, type CronOperationOptions as Y, type CronRunOptions as Z, type CronRuntime as _, type AgentDefinition as a, type CronStartOptions as a0, type HookName as a1, type InvalidateCacheOptions as a2, type MemoryAdapter as a3, type MemoryAdapterCapabilities as a4, type MemoryContext as a5, type MemoryFact as a6, type MemoryProviderHandle as a7, type MemoryProviderInitOptions as a8, type MemoryRevision as a9, type SkillsResolver as aA, type SkillsResolverContext as aB, type SystemPromptContext as aC, type SystemPromptMemoryFact as aD, type SystemPromptSkillRef as aE, type TelemetrySettings as aF, type MemoryToolSchema as aa, type MemoryTurnMessage as ab, type PersonalityPreset as ac, type PluginContext as ad, type PostAssistantReplyContext as ae, type PreToolCallContext as af, type PreUserSendContext as ag, type PreUserSendResult as ah, type ProviderCapability as ai, type ProviderRoute as aj, type ProviderTransform as ak, type ProviderTransformContext as al, type RecordSessionSummaryArgs as am, type ResolvedProviderRoute as an, type RunUntilIterator as ao, type SDKAgentPlugins as ap, type SDKAgentSkillDetail as aq, type SDKAgentSkills as ar, type SDKArtifact as as, type SDKContextManager as at, type SDKPluginMetadata as au, type SDKProvidersManager as av, type SessionRecord as aw, type SessionStore as ax, type SettingSource as ay, Skill as az, type ContextSettings as b, type PluginsSettings as c, type SkillsSettings as d, type SDKAgent as e, type ListAgentsOptions as f, type ListResult as g, type SDKAgentInfo as h, type ListRunsOptions as i, type GetRunOptions as j, type AgentOperationOptions as k, type Plugin as l, type ProviderProfile as m, type GoalOptions as n, type GoalEvent as o, type GoalResult as p, type MemoryProvider as q, type MemoryId as r, type PreToolCallDecision as s, type StepResult as t, type SDKProvider as u, type ActiveMemoryPassArgs as v, type ActiveMemoryPassResult as w, type AgentMemory as x, type BudgetCheck as y, type BudgetTotal as z };