theokit 0.29.0 → 0.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/LICENSE +201 -0
  2. package/dist/{actions-virtual-module-JB5ZTS5U.js → actions-virtual-module-PBLLMJY4.js} +3 -3
  3. package/dist/actions-virtual-module-Z2IXNF72.js +0 -0
  4. package/dist/add-W6FNTAFS.js +0 -0
  5. package/dist/agent-I5QEOMCN.js +0 -0
  6. package/dist/agents-typed-client-5DCGDWFZ.js +0 -0
  7. package/dist/{app-typed-client-VMSRQGKL.js → app-typed-client-EXHUWPOI.js} +3 -3
  8. package/dist/app-typed-client-YCQC3MZ7.js +0 -0
  9. package/dist/aws-lambda-7GSCNLPY.js +0 -0
  10. package/dist/body-parser-web-FV5HWCY3.js +0 -0
  11. package/dist/broadcast-LUMOJIJT.js +0 -0
  12. package/dist/build-V2QEBE7I.js +0 -0
  13. package/dist/build-request-body-preview-QMWD2IXK.js +0 -0
  14. package/dist/bun-KP2KES6S.js +0 -0
  15. package/dist/check-PD2FTKMM.js +0 -0
  16. package/dist/chunk-2CVV6CNN.js +0 -0
  17. package/dist/chunk-45C3WUQ7.js +0 -0
  18. package/dist/chunk-5ODOE6EF.js +0 -0
  19. package/dist/chunk-AFVTEAES.js +0 -0
  20. package/dist/{chunk-R4VVXLKZ.js → chunk-EHUT4FMG.js} +10 -10
  21. package/dist/chunk-FOZIR3TG.js +0 -0
  22. package/dist/chunk-FRUEDJFX.js +0 -0
  23. package/dist/chunk-GDN3PXFH.js +0 -0
  24. package/dist/chunk-GEQJAFSV.js +0 -0
  25. package/dist/chunk-GSO77FSM.js +0 -0
  26. package/dist/chunk-HGZL5EOI.js +0 -0
  27. package/dist/chunk-HNBWZKIQ.js +0 -0
  28. package/dist/chunk-IEES3CHD.js +0 -0
  29. package/dist/chunk-JAIKGP3Q.js +0 -0
  30. package/dist/chunk-KXA37ONC.js +0 -0
  31. package/dist/chunk-M6NMS5LR.js +0 -0
  32. package/dist/chunk-P37RZRFV.js +0 -0
  33. package/dist/chunk-RBRDTYOO.js +470 -0
  34. package/dist/chunk-RBRDTYOO.js.map +1 -0
  35. package/dist/chunk-S7L6H3KP.js +0 -0
  36. package/dist/chunk-TERFLG67.js +0 -0
  37. package/dist/{chunk-H243MR3F.js → chunk-TGTNRUH3.js} +2 -2
  38. package/dist/{chunk-W4XWVTN4.js → chunk-UYFZ6DDW.js} +2 -2
  39. package/dist/chunk-VRVNM3QL.js +0 -0
  40. package/dist/{chunk-Z5IGLBWE.js → chunk-WFNLNIJX.js} +1 -1
  41. package/dist/chunk-WR4F4EEZ.js +0 -0
  42. package/dist/chunk-Y4TOVMNC.js +0 -0
  43. package/dist/chunk-YJWEADAW.js +0 -0
  44. package/dist/client/core.d.ts +294 -0
  45. package/dist/client/core.js +22 -0
  46. package/dist/client/index.d.ts +4 -251
  47. package/dist/client/index.js +11 -401
  48. package/dist/client/index.js.map +1 -1
  49. package/dist/cloudflare-C6E5SPAE.js +0 -0
  50. package/dist/configure-agent-registry-ZOBVU3MV.js +0 -0
  51. package/dist/db-3UNAMSFK.js +0 -0
  52. package/dist/deno-deploy-RFZN56X4.js +0 -0
  53. package/dist/dev-5ZQMWVFC.js +0 -0
  54. package/dist/dev-emit-EFQRBVYS.js +0 -0
  55. package/dist/dispatcher-EJHL6JMJ.js +0 -0
  56. package/dist/docker-LZZB4D5E.js +0 -0
  57. package/dist/generate-373DALPY.js +0 -0
  58. package/dist/index.js +6 -6
  59. package/dist/info-2OOXFTJX.js +0 -0
  60. package/dist/{internal-api-KPULK7ZK.js → internal-api-JIR3HRKF.js} +3 -3
  61. package/dist/internal-api-JIR3HRKF.js.map +1 -0
  62. package/dist/internal-api-Y5REPVUS.js +0 -0
  63. package/dist/load-config-3EAQTXPH.js +0 -0
  64. package/dist/mcp-VMKWB2BY.js +0 -0
  65. package/dist/netlify-PMLHVPN4.js +0 -0
  66. package/dist/node-BPJ3Z4DT.js +0 -0
  67. package/dist/openapi-ERYWAT3A.js +0 -0
  68. package/dist/registry-3NB7KOUI.js +0 -0
  69. package/dist/router-TLEAOFID.js +0 -0
  70. package/dist/routes-XNS3UM3B.js +0 -0
  71. package/dist/scan-7MJC6PYU.js +0 -0
  72. package/dist/schema-LYOLNHZ7.js +0 -0
  73. package/dist/server/http/index.js +2 -2
  74. package/dist/server/index.js +3 -3
  75. package/dist/server/observability/index.js +1 -1
  76. package/dist/server-error-to-envelope-UUXDSLAZ.js +0 -0
  77. package/dist/server-routes-hmr-VZXOP5YT.js +0 -0
  78. package/dist/services-json-Y3XODNB5.js +0 -0
  79. package/dist/services-typed-client-32KMTTXR.js +0 -0
  80. package/dist/start-IFTLTEPZ.js +0 -0
  81. package/dist/static-MB2CD5Y3.js +0 -0
  82. package/dist/storage-manager-ZSQFLEYT.js +0 -0
  83. package/dist/theo-cloud-DQRP6S6M.js +0 -0
  84. package/dist/upgrade-readiness-ACGW44JC.js +0 -0
  85. package/dist/vercel-J6G7ZHYQ.js +0 -0
  86. package/dist/vite-plugin/index.js +6 -6
  87. package/dist/vite-plugin-BNI7YLCD.js +0 -0
  88. package/package.json +14 -10
  89. /package/dist/{actions-virtual-module-JB5ZTS5U.js.map → actions-virtual-module-PBLLMJY4.js.map} +0 -0
  90. /package/dist/{app-typed-client-VMSRQGKL.js.map → app-typed-client-EXHUWPOI.js.map} +0 -0
  91. /package/dist/{chunk-R4VVXLKZ.js.map → chunk-EHUT4FMG.js.map} +0 -0
  92. /package/dist/{chunk-H243MR3F.js.map → chunk-TGTNRUH3.js.map} +0 -0
  93. /package/dist/{chunk-W4XWVTN4.js.map → chunk-UYFZ6DDW.js.map} +0 -0
  94. /package/dist/{chunk-Z5IGLBWE.js.map → chunk-WFNLNIJX.js.map} +0 -0
  95. /package/dist/{internal-api-KPULK7ZK.js.map → client/core.js.map} +0 -0
@@ -0,0 +1,294 @@
1
+ import { ChatTransport, UIMessage, UIMessageChunk } from 'ai';
2
+
3
+ /**
4
+ * M41 (ADR-0050 D2) — a HITL approval decision sent to settle a paused gated-tool call. Mirrors the
5
+ * `POST /api/agents/<name>/approve/<id>` wire body (`approve-agent.ts` `parseApprovalBody`). Defined
6
+ * on the client side (not imported from `server/`) as the client's view of the boundary contract.
7
+ */
8
+ interface ApprovalDecision {
9
+ /** Whether the paused gated tool may proceed. */
10
+ approved: boolean;
11
+ /** Optional reason surfaced to the model on denial. */
12
+ reason?: string;
13
+ /** Optional small structured note (edited args, a reviewer comment) — capped server-side at 16 KiB. */
14
+ payload?: unknown;
15
+ }
16
+ /**
17
+ * M43 (ADR-0052) — per-request context attached uniformly across every transport.
18
+ *
19
+ * `headers` is the serializable, HTTP-native half (an auth token → request headers on `HttpTransport`);
20
+ * `metadata` is the structured, same-process half forwarded to the in-process runner
21
+ * (`InProcessTransport`) / the Tauri `invoke` (`ChannelTransport`). Threaded through the seam's existing
22
+ * `ChatRequestOptions` — NOT a new channel. The turn input stays the request `body`.
23
+ */
24
+ interface RequestContext {
25
+ /** Per-request headers (e.g. auth). HTTP-native; mapped to request headers by `HttpTransport`. */
26
+ headers?: Record<string, string>;
27
+ /** Structured per-request context (tenant, provider, …) forwarded to in-process / channel runners. */
28
+ metadata?: unknown;
29
+ }
30
+ /**
31
+ * M41 (ADR-0050 D1/D2) — the client transport seam.
32
+ *
33
+ * It IS `ai`'s `ChatTransport<UIMessage>` (the adopted SOTA interface — we do NOT invent a parallel
34
+ * one) plus ONE optional method, `approve`, for TheoKit's OUT-OF-BAND HITL (the server pauses the run;
35
+ * the client settles it via a separate call). `ai`'s `ChatTransport` has no `approve` because its HITL
36
+ * is in-band (a re-sent message part); ours is out-of-band, and the settle route differs per transport
37
+ * (HTTP `POST /approve/<id>` vs an inline callback), so it belongs on the transport. `approve` is
38
+ * optional — agents without gated tools never settle an approval.
39
+ *
40
+ * `HttpTransport` (web) and `InProcessTransport` (TUI/desktop) implement this; `useAgent` drives it.
41
+ */
42
+ type AgentTransport = ChatTransport<UIMessage> & {
43
+ approve?(approvalId: string, decision: ApprovalDecision): Promise<void>;
44
+ };
45
+
46
+ type UseAgentStatus = 'idle' | 'streaming' | 'done' | 'error';
47
+ /** The observable state the store exposes (stable reference between emits — `useSyncExternalStore` contract). */
48
+ interface AgentClientState {
49
+ messages: UIMessage[];
50
+ status: UseAgentStatus;
51
+ error: Error | undefined;
52
+ }
53
+ /**
54
+ * M41 (ADR-0050 D6) — the framework-agnostic agent client store.
55
+ *
56
+ * Holds `messages`/`status`/`error`, drives an {@link AgentTransport}, and notifies subscribers on
57
+ * change. It is the SINGLE consolidation point: web (`HttpTransport`) and terminal/desktop
58
+ * (`InProcessTransport`) run the SAME store. `useAgent` is a thin React binding over it via
59
+ * `useSyncExternalStore`; a standalone (no-React) client (M44) can subscribe directly. Being
60
+ * framework-agnostic, it is unit-tested without a DOM.
61
+ */
62
+ declare class AgentClient<TInput = unknown> {
63
+ #private;
64
+ constructor(transport: AgentTransport, contextResolver?: () => RequestContext | undefined);
65
+ /** Subscribe to state changes; returns an unsubscribe fn. */
66
+ subscribe: (listener: () => void) => (() => void);
67
+ /** The current immutable snapshot (stable reference until the next emit). */
68
+ getSnapshot: () => AgentClientState;
69
+ /** Send a typed input; opens a fresh stream (replaces prior messages). */
70
+ send: (input: TInput) => void;
71
+ /** Resume an interrupted stream via the transport's `reconnectToStream` (no-op when unavailable). */
72
+ reconnect: () => void;
73
+ /** Abort an in-flight stream (not an error — leaves messages as-is). */
74
+ abort: () => void;
75
+ /** Clear messages + error, back to idle. */
76
+ reset: () => void;
77
+ /** Settle a paused HITL approval via the transport's HITL path (HTTP POST or inline callback). */
78
+ approve: (approvalId: string, decision: ApprovalDecision) => Promise<void>;
79
+ }
80
+
81
+ interface CreateAgentClientOptions {
82
+ /**
83
+ * M43 — per-request context attached to every turn (`headers` → HTTP; `metadata` → in-process/channel).
84
+ * A value OR a resolver. **To keep context live across sends, pass a RESOLVER** (`() => ({...})`) — a
85
+ * plain value is captured at construction and not re-read, so mutating `options.context` afterwards has
86
+ * no effect (unlike `useAgent`, which reads a live ref). A resolver is re-evaluated every send/reconnect.
87
+ */
88
+ context?: RequestContext | (() => RequestContext | undefined);
89
+ }
90
+ /**
91
+ * M44 (ADR-0053) — the standalone (no-React) agent client. A plain handle over the framework-agnostic
92
+ * {@link AgentClient} store: drive a turn, observe state, settle HITL — from a node script, a CLI, a
93
+ * test, or a non-React UI, over ANY {@link AgentTransport}.
94
+ */
95
+ interface AgentClientHandle<TInput = unknown> {
96
+ /** Send a typed input; opens a fresh stream (replaces prior messages). */
97
+ send(input: TInput): void;
98
+ /** Abort an in-flight stream. */
99
+ abort(): void;
100
+ /** Clear messages + error, back to idle. */
101
+ reset(): void;
102
+ /** Settle a paused HITL approval via the transport's HITL path. */
103
+ approve(approvalId: string, decision: ApprovalDecision): Promise<void>;
104
+ /** Resume an interrupted stream (no-op when the transport can't). */
105
+ reconnect(): void;
106
+ /** Subscribe to state changes; returns an unsubscribe fn. */
107
+ subscribe(listener: () => void): () => void;
108
+ /** The current immutable snapshot (messages / status / error). */
109
+ getState(): AgentClientState;
110
+ /**
111
+ * Drive one turn and yield the assistant `UIMessage` as it streams (progressive snapshots); iteration
112
+ * ends when the turn settles. A `for await` script takes the last yielded value as the final result;
113
+ * a failed turn rejects the iterator with the run error.
114
+ */
115
+ stream(input: TInput): AsyncIterable<UIMessage>;
116
+ }
117
+ /**
118
+ * Create a standalone (no-React) agent client over a transport. `useAgent` is the React binding over the
119
+ * same store; this is the equivalent for any JS runtime — one agent, consumable everywhere on the seam.
120
+ */
121
+ declare function createAgentClient<TInput = unknown>(transport: AgentTransport, options?: CreateAgentClientOptions): AgentClientHandle<TInput>;
122
+
123
+ /** Extra request headers — a static record OR a resolver called per request (for dynamic auth). */
124
+ type HeadersResolver = Record<string, string> | (() => Record<string, string> | undefined);
125
+ interface HttpTransportOptions {
126
+ /** Agent endpoint path or URL, e.g. `/api/agents/support`. */
127
+ api: string;
128
+ /**
129
+ * Extra request headers (e.g. auth). Static record OR a resolver evaluated on EVERY request — pass a
130
+ * resolver when the value is dynamic (a rotating JWT), so a stale header is never sent. Merged UNDER
131
+ * per-request headers.
132
+ */
133
+ headers?: HeadersResolver;
134
+ /** Override fetch (primarily for tests / non-browser hosts) — static; resolved once at construction. */
135
+ fetch?: typeof fetch;
136
+ }
137
+ /**
138
+ * M41 (ADR-0050 D3) — `ChatTransport` over the web agent path.
139
+ *
140
+ * - `sendMessages`: `POST <api>` with the UIMessageStream `accept` + the `X-Theo-Action` CSRF header
141
+ * (HTTP method + headers are identical to the pre-M41 `useAgent` fetch; the body shape is a superset —
142
+ * `{ ...input, messages: [UIMessage] }` — which the server's dual-path parser accepts, so no
143
+ * regression), captures the server-minted `x-theokit-run-id`, and returns `ReadableStream<UIMessageChunk>`
144
+ * via `ai`'s own SSE parser (`responseToChunkStream`).
145
+ * - `reconnectToStream`: `GET <api>/runs/<runId>/stream` (M37 durable transport); 404 → `null` (the run
146
+ * completed / was evicted). A caller may pass a `Last-Event-ID` header to resume only the tail; by
147
+ * default the server replays the run from the start and the client upserts by message id (idempotent).
148
+ * - `approve`: `POST <api>/approve/<id>` (out-of-band HITL settle).
149
+ *
150
+ * Implemented directly (not by subclassing `DefaultChatTransport`) because reconnect keys on our
151
+ * server-minted `runId` captured from a response header, which the base class does not expose — see
152
+ * ADR-0050 D3.
153
+ */
154
+ declare class HttpTransport implements AgentTransport {
155
+ #private;
156
+ constructor(options: HttpTransportOptions);
157
+ sendMessages(options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0]): Promise<ReadableStream<UIMessageChunk>>;
158
+ reconnectToStream(options: Parameters<ChatTransport<UIMessage>['reconnectToStream']>[0]): Promise<ReadableStream<UIMessageChunk> | null>;
159
+ approve(approvalId: string, decision: ApprovalDecision): Promise<void>;
160
+ }
161
+
162
+ /** An inline approval request handed to the transport's resolver (structural — no server import). */
163
+ interface InProcessApprovalRequestLike {
164
+ approvalId: string;
165
+ toolName: string;
166
+ opts: unknown;
167
+ }
168
+ /** Resolve one gated-tool approval inline (mirrors the SDK's `boolean | HitlDecision` return). */
169
+ type InProcessAwaitApproval = (req: InProcessApprovalRequestLike) => Promise<boolean | ApprovalDecision>;
170
+ /** The input the injected runner receives (structurally compatible with `StreamAgentTurnInProcessInput`). */
171
+ interface InProcessRunInput {
172
+ message: string;
173
+ sessionId?: string;
174
+ signal?: AbortSignal;
175
+ awaitApproval?: InProcessAwaitApproval;
176
+ /** M43 — per-request context (from `sendMessages`'s `metadata`) — tenant / provider / auth for the runner. */
177
+ context?: unknown;
178
+ }
179
+ /**
180
+ * The in-process turn runner. The consumer binds `streamAgentTurnInProcess(mod, apiKey, …)`:
181
+ * `new InProcessTransport({ run: (input) => streamAgentTurnInProcess(mod, apiKey, input) })`.
182
+ * Injecting it keeps this client module decoupled from `server/` and makes the transport testable.
183
+ */
184
+ type InProcessRunner = (input: InProcessRunInput) => AsyncGenerator<UIMessageChunk>;
185
+ interface InProcessTransportOptions {
186
+ run: InProcessRunner;
187
+ }
188
+ /**
189
+ * M41 (ADR-0050 D4) — `ChatTransport` over the in-process seam (`streamAgentTurnInProcess`), for the
190
+ * terminal/desktop surfaces that run client + server in ONE process (no HTTP loopback).
191
+ *
192
+ * - `sendMessages`: bridge the injected runner's `AsyncGenerator<UIMessageChunk>` into a
193
+ * `ReadableStream<UIMessageChunk>` (honoring `abortSignal`, which the runner forwards to the SDK).
194
+ * - `reconnectToStream`: always `null` — a single process has no dropped server-side stream to resume
195
+ * (mirrors `ai`'s `DirectChatTransport`).
196
+ * - `approve`: resolve the pending inline approval by id (the run parks on `awaitApproval`). An unknown
197
+ * id rejects (fail-fast, Rule 8 — never a silent resolve).
198
+ *
199
+ * Error asymmetry vs `HttpTransport` (by design, matching the `ChatTransport` contract): a runner that
200
+ * throws SYNCHRONOUSLY surfaces the error when the stream is READ (via `controller.error`), not from the
201
+ * `sendMessages` promise — whereas `HttpTransport` throws from `sendMessages` on a non-2xx response.
202
+ */
203
+ declare class InProcessTransport implements AgentTransport {
204
+ #private;
205
+ constructor(options: InProcessTransportOptions);
206
+ sendMessages(options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0]): Promise<ReadableStream<UIMessageChunk>>;
207
+ reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null>;
208
+ approve(approvalId: string, decision: ApprovalDecision): Promise<void>;
209
+ }
210
+
211
+ /** Handlers the transport hands to the injected push source for one turn. */
212
+ interface ChannelTurnHandlers {
213
+ /** One pushed JSONL line (a serialized `UIMessageChunk`). */
214
+ onLine: (line: string) => void;
215
+ /** The turn ended — no more lines. */
216
+ onClose: () => void;
217
+ /** The push source failed. */
218
+ onError?: (err: unknown) => void;
219
+ }
220
+ /**
221
+ * The injected push source — a Tauri `Channel`/`invoke` bridge, kept STRUCTURAL so core adds no
222
+ * `@tauri-apps/*` dependency and the transport is testable with a fake (ADR-0051 D2). The Tauri app
223
+ * wires it: `new Channel()`, `channel.onmessage = onLine`, `invoke('run_agent', { message, channel })`,
224
+ * returning a teardown that aborts the sidecar turn.
225
+ */
226
+ interface ChannelPushSource {
227
+ /**
228
+ * Start a turn; deliver each JSONL `UIMessageChunk` line to `onLine`, then `onClose`. Return a teardown.
229
+ * `turn.context` (M43) is the per-request context (from the seam's `metadata`) — the Tauri `invoke`
230
+ * forwards it to the sidecar. When no context is set it is present as `context: undefined` (the key is
231
+ * NOT absent) — a sidecar that checks `'context' in turn` should treat `undefined` as "no context".
232
+ */
233
+ start(turn: {
234
+ message: string;
235
+ context?: unknown;
236
+ }, handlers: ChannelTurnHandlers): () => void;
237
+ /** Optional HITL settle (another Tauri `invoke`). */
238
+ settle?(approvalId: string, decision: ApprovalDecision): Promise<void>;
239
+ }
240
+ interface ChannelTransportOptions {
241
+ source: ChannelPushSource;
242
+ }
243
+ /**
244
+ * M42 (ADR-0051) — `ChatTransport` over a Tauri-`Channel`-shaped push source, for the desktop webview.
245
+ *
246
+ * - `sendMessages`: start the turn via the injected source and bridge its pushed JSONL frames into a
247
+ * `ReadableStream<UIMessageChunk>` (built in `start` — a Channel is push, so the stream's queue buffers
248
+ * frames; ADR-0051 D3). A malformed JSONL line is SKIPPED, never fatal (ADR-0051 D4, Rule 8). `abortSignal`
249
+ * tears down the source and closes the stream.
250
+ * - `reconnectToStream`: always `null` — the M36 sidecar runs the turn directly (no durable server stream);
251
+ * this is the honest parity for a single-process push surface (ADR-0051 D5; mirrors `InProcessTransport`).
252
+ * - `approve`: routes to the injected `settle` (another Tauri `invoke`); absent `settle` → a typed error.
253
+ *
254
+ * The push source is INJECTED — core stays Tauri-agnostic and this transport is unit-tested with a fake.
255
+ */
256
+ declare class ChannelTransport implements AgentTransport {
257
+ #private;
258
+ constructor(options: ChannelTransportOptions);
259
+ sendMessages(options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0]): Promise<ReadableStream<UIMessageChunk>>;
260
+ reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null>;
261
+ approve(approvalId: string, decision: ApprovalDecision): Promise<void>;
262
+ }
263
+
264
+ /**
265
+ * M2 (theokit-ai-first) — read a TheoKit agent endpoint's `UIMessageStream` SSE `Response`
266
+ * into reconstructed assistant `UIMessage`s, reusing the `ai` package's own consumer
267
+ * primitives (`parseJsonEventStream` + `readUIMessageStream`) — the exact path
268
+ * `@ai-sdk/react`'s `useChat` runs internally. No reinvented wire parser (Rule 9).
269
+ *
270
+ * `ai` is an OPTIONAL peer dependency, so it is imported dynamically: an app that never
271
+ * calls an agent never pays for it, and importing `theokit/client` does not hard-require
272
+ * `ai` (mirrors how the agent runtime dynamically imports `@theokit/sdk`). An agent app
273
+ * always has `ai` installed (it is the UIMessageStream consumer).
274
+ *
275
+ * `onMessage` is invoked on every reconstruction step with the latest snapshot of the
276
+ * assistant message, so a caller (the `useAgent` hook) can render streaming updates.
277
+ */
278
+ declare function consumeUIMessageStream(response: Response, onMessage: (message: UIMessage) => void): Promise<void>;
279
+ /**
280
+ * M41 (ADR-0050 D3) — the reusable middle piece: a UIMessageStream SSE `Response` →
281
+ * `ReadableStream<UIMessageChunk>`, reusing `ai`'s own `parseJsonEventStream` (the exact primitive
282
+ * `useChat` runs). This is precisely what a `ChatTransport.sendMessages` returns, so `HttpTransport`
283
+ * builds on it directly (no reinvented wire parser — Rule 9). A body-less response yields an empty stream.
284
+ */
285
+ declare function responseToChunkStream(response: Response): Promise<ReadableStream<UIMessageChunk>>;
286
+ /**
287
+ * M41 (ADR-0050 D6) — read a `ReadableStream<UIMessageChunk>` into reconstructed assistant
288
+ * `UIMessage`s via `ai`'s `readUIMessageStream`. Shared by `consumeUIMessageStream` (Response path)
289
+ * and the framework-agnostic `AgentClient` store (transport path). `onMessage` fires on every
290
+ * reconstruction step so a caller can render streaming updates.
291
+ */
292
+ declare function consumeChunkStream(stream: ReadableStream<UIMessageChunk>, onMessage: (message: UIMessage) => void): Promise<void>;
293
+
294
+ export { AgentClient, type AgentClientHandle, type AgentClientState, type AgentTransport, type ApprovalDecision, type ChannelPushSource, ChannelTransport, type ChannelTransportOptions, type ChannelTurnHandlers, type CreateAgentClientOptions, type HeadersResolver, HttpTransport, type HttpTransportOptions, type InProcessApprovalRequestLike, type InProcessAwaitApproval, type InProcessRunInput, type InProcessRunner, InProcessTransport, type InProcessTransportOptions, type RequestContext, type UseAgentStatus, consumeChunkStream, consumeUIMessageStream, createAgentClient, responseToChunkStream };
@@ -0,0 +1,22 @@
1
+ import {
2
+ AgentClient,
3
+ ChannelTransport,
4
+ HttpTransport,
5
+ InProcessTransport,
6
+ consumeChunkStream,
7
+ consumeUIMessageStream,
8
+ createAgentClient,
9
+ responseToChunkStream
10
+ } from "../chunk-RBRDTYOO.js";
11
+ import "../chunk-DGUM43GV.js";
12
+ export {
13
+ AgentClient,
14
+ ChannelTransport,
15
+ HttpTransport,
16
+ InProcessTransport,
17
+ consumeChunkStream,
18
+ consumeUIMessageStream,
19
+ createAgentClient,
20
+ responseToChunkStream
21
+ };
22
+ //# sourceMappingURL=core.js.map
@@ -1,7 +1,9 @@
1
1
  import { z } from 'zod';
2
2
  import { T as TheoErrorEnvelope } from '../error-envelope-BsNzzAV5.js';
3
3
  export { FetchOptionsLike, Fetcher, QueryKey, UseTheoQueryConfig, buildUseTheoQueryConfig, stableQueryKey } from '../react-query/index.js';
4
- import { UIMessageChunk, UIMessage, ChatTransport } from 'ai';
4
+ import { RequestContext, UseAgentStatus, ApprovalDecision, AgentTransport } from './core.js';
5
+ export { AgentClient, AgentClientHandle, AgentClientState, ChannelPushSource, ChannelTransport, ChannelTransportOptions, ChannelTurnHandlers, CreateAgentClientOptions, HttpTransport, HttpTransportOptions, InProcessApprovalRequestLike, InProcessAwaitApproval, InProcessRunInput, InProcessRunner, InProcessTransport, InProcessTransportOptions, consumeChunkStream, consumeUIMessageStream, createAgentClient, responseToChunkStream } from './core.js';
6
+ import { UIMessage } from 'ai';
5
7
  import * as react from 'react';
6
8
  import { LinkProps as LinkProps$1 } from 'react-router';
7
9
 
@@ -115,114 +117,6 @@ interface Batcher {
115
117
  }
116
118
  declare function createBatcher(options: BatcherOptions): Batcher;
117
119
 
118
- /**
119
- * M2 (theokit-ai-first) — read a TheoKit agent endpoint's `UIMessageStream` SSE `Response`
120
- * into reconstructed assistant `UIMessage`s, reusing the `ai` package's own consumer
121
- * primitives (`parseJsonEventStream` + `readUIMessageStream`) — the exact path
122
- * `@ai-sdk/react`'s `useChat` runs internally. No reinvented wire parser (Rule 9).
123
- *
124
- * `ai` is an OPTIONAL peer dependency, so it is imported dynamically: an app that never
125
- * calls an agent never pays for it, and importing `theokit/client` does not hard-require
126
- * `ai` (mirrors how the agent runtime dynamically imports `@theokit/sdk`). An agent app
127
- * always has `ai` installed (it is the UIMessageStream consumer).
128
- *
129
- * `onMessage` is invoked on every reconstruction step with the latest snapshot of the
130
- * assistant message, so a caller (the `useAgent` hook) can render streaming updates.
131
- */
132
- declare function consumeUIMessageStream(response: Response, onMessage: (message: UIMessage) => void): Promise<void>;
133
- /**
134
- * M41 (ADR-0050 D3) — the reusable middle piece: a UIMessageStream SSE `Response` →
135
- * `ReadableStream<UIMessageChunk>`, reusing `ai`'s own `parseJsonEventStream` (the exact primitive
136
- * `useChat` runs). This is precisely what a `ChatTransport.sendMessages` returns, so `HttpTransport`
137
- * builds on it directly (no reinvented wire parser — Rule 9). A body-less response yields an empty stream.
138
- */
139
- declare function responseToChunkStream(response: Response): Promise<ReadableStream<UIMessageChunk>>;
140
- /**
141
- * M41 (ADR-0050 D6) — read a `ReadableStream<UIMessageChunk>` into reconstructed assistant
142
- * `UIMessage`s via `ai`'s `readUIMessageStream`. Shared by `consumeUIMessageStream` (Response path)
143
- * and the framework-agnostic `AgentClient` store (transport path). `onMessage` fires on every
144
- * reconstruction step so a caller can render streaming updates.
145
- */
146
- declare function consumeChunkStream(stream: ReadableStream<UIMessageChunk>, onMessage: (message: UIMessage) => void): Promise<void>;
147
-
148
- /**
149
- * M41 (ADR-0050 D2) — a HITL approval decision sent to settle a paused gated-tool call. Mirrors the
150
- * `POST /api/agents/<name>/approve/<id>` wire body (`approve-agent.ts` `parseApprovalBody`). Defined
151
- * on the client side (not imported from `server/`) as the client's view of the boundary contract.
152
- */
153
- interface ApprovalDecision {
154
- /** Whether the paused gated tool may proceed. */
155
- approved: boolean;
156
- /** Optional reason surfaced to the model on denial. */
157
- reason?: string;
158
- /** Optional small structured note (edited args, a reviewer comment) — capped server-side at 16 KiB. */
159
- payload?: unknown;
160
- }
161
- /**
162
- * M43 (ADR-0052) — per-request context attached uniformly across every transport.
163
- *
164
- * `headers` is the serializable, HTTP-native half (an auth token → request headers on `HttpTransport`);
165
- * `metadata` is the structured, same-process half forwarded to the in-process runner
166
- * (`InProcessTransport`) / the Tauri `invoke` (`ChannelTransport`). Threaded through the seam's existing
167
- * `ChatRequestOptions` — NOT a new channel. The turn input stays the request `body`.
168
- */
169
- interface RequestContext {
170
- /** Per-request headers (e.g. auth). HTTP-native; mapped to request headers by `HttpTransport`. */
171
- headers?: Record<string, string>;
172
- /** Structured per-request context (tenant, provider, …) forwarded to in-process / channel runners. */
173
- metadata?: unknown;
174
- }
175
- /**
176
- * M41 (ADR-0050 D1/D2) — the client transport seam.
177
- *
178
- * It IS `ai`'s `ChatTransport<UIMessage>` (the adopted SOTA interface — we do NOT invent a parallel
179
- * one) plus ONE optional method, `approve`, for TheoKit's OUT-OF-BAND HITL (the server pauses the run;
180
- * the client settles it via a separate call). `ai`'s `ChatTransport` has no `approve` because its HITL
181
- * is in-band (a re-sent message part); ours is out-of-band, and the settle route differs per transport
182
- * (HTTP `POST /approve/<id>` vs an inline callback), so it belongs on the transport. `approve` is
183
- * optional — agents without gated tools never settle an approval.
184
- *
185
- * `HttpTransport` (web) and `InProcessTransport` (TUI/desktop) implement this; `useAgent` drives it.
186
- */
187
- type AgentTransport = ChatTransport<UIMessage> & {
188
- approve?(approvalId: string, decision: ApprovalDecision): Promise<void>;
189
- };
190
-
191
- type UseAgentStatus = 'idle' | 'streaming' | 'done' | 'error';
192
- /** The observable state the store exposes (stable reference between emits — `useSyncExternalStore` contract). */
193
- interface AgentClientState {
194
- messages: UIMessage[];
195
- status: UseAgentStatus;
196
- error: Error | undefined;
197
- }
198
- /**
199
- * M41 (ADR-0050 D6) — the framework-agnostic agent client store.
200
- *
201
- * Holds `messages`/`status`/`error`, drives an {@link AgentTransport}, and notifies subscribers on
202
- * change. It is the SINGLE consolidation point: web (`HttpTransport`) and terminal/desktop
203
- * (`InProcessTransport`) run the SAME store. `useAgent` is a thin React binding over it via
204
- * `useSyncExternalStore`; a standalone (no-React) client (M44) can subscribe directly. Being
205
- * framework-agnostic, it is unit-tested without a DOM.
206
- */
207
- declare class AgentClient<TInput = unknown> {
208
- #private;
209
- constructor(transport: AgentTransport, contextResolver?: () => RequestContext | undefined);
210
- /** Subscribe to state changes; returns an unsubscribe fn. */
211
- subscribe: (listener: () => void) => (() => void);
212
- /** The current immutable snapshot (stable reference until the next emit). */
213
- getSnapshot: () => AgentClientState;
214
- /** Send a typed input; opens a fresh stream (replaces prior messages). */
215
- send: (input: TInput) => void;
216
- /** Resume an interrupted stream via the transport's `reconnectToStream` (no-op when unavailable). */
217
- reconnect: () => void;
218
- /** Abort an in-flight stream (not an error — leaves messages as-is). */
219
- abort: () => void;
220
- /** Clear messages + error, back to idle. */
221
- reset: () => void;
222
- /** Settle a paused HITL approval via the transport's HITL path (HTTP POST or inline callback). */
223
- approve: (approvalId: string, decision: ApprovalDecision) => Promise<void>;
224
- }
225
-
226
120
  interface UseAgentReturn<TInput = unknown, TToolNames extends string = string> {
227
121
  /** Reconstructed assistant messages so far (ai `UIMessage[]`). */
228
122
  messages: UIMessage[];
@@ -268,147 +162,6 @@ interface UseAgentOptions {
268
162
  */
269
163
  declare function useAgent<TInput = unknown>(pathOrTransport: string | AgentTransport, options?: UseAgentOptions): UseAgentReturn<TInput>;
270
164
 
271
- /** Extra request headers — a static record OR a resolver called per request (for dynamic auth). */
272
- type HeadersResolver = Record<string, string> | (() => Record<string, string> | undefined);
273
- interface HttpTransportOptions {
274
- /** Agent endpoint path or URL, e.g. `/api/agents/support`. */
275
- api: string;
276
- /**
277
- * Extra request headers (e.g. auth). Static record OR a resolver evaluated on EVERY request — pass a
278
- * resolver when the value is dynamic (a rotating JWT), so a stale header is never sent. Merged UNDER
279
- * per-request headers.
280
- */
281
- headers?: HeadersResolver;
282
- /** Override fetch (primarily for tests / non-browser hosts) — static; resolved once at construction. */
283
- fetch?: typeof fetch;
284
- }
285
- /**
286
- * M41 (ADR-0050 D3) — `ChatTransport` over the web agent path.
287
- *
288
- * - `sendMessages`: `POST <api>` with the UIMessageStream `accept` + the `X-Theo-Action` CSRF header
289
- * (HTTP method + headers are identical to the pre-M41 `useAgent` fetch; the body shape is a superset —
290
- * `{ ...input, messages: [UIMessage] }` — which the server's dual-path parser accepts, so no
291
- * regression), captures the server-minted `x-theokit-run-id`, and returns `ReadableStream<UIMessageChunk>`
292
- * via `ai`'s own SSE parser (`responseToChunkStream`).
293
- * - `reconnectToStream`: `GET <api>/runs/<runId>/stream` (M37 durable transport); 404 → `null` (the run
294
- * completed / was evicted). A caller may pass a `Last-Event-ID` header to resume only the tail; by
295
- * default the server replays the run from the start and the client upserts by message id (idempotent).
296
- * - `approve`: `POST <api>/approve/<id>` (out-of-band HITL settle).
297
- *
298
- * Implemented directly (not by subclassing `DefaultChatTransport`) because reconnect keys on our
299
- * server-minted `runId` captured from a response header, which the base class does not expose — see
300
- * ADR-0050 D3.
301
- */
302
- declare class HttpTransport implements AgentTransport {
303
- #private;
304
- constructor(options: HttpTransportOptions);
305
- sendMessages(options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0]): Promise<ReadableStream<UIMessageChunk>>;
306
- reconnectToStream(options: Parameters<ChatTransport<UIMessage>['reconnectToStream']>[0]): Promise<ReadableStream<UIMessageChunk> | null>;
307
- approve(approvalId: string, decision: ApprovalDecision): Promise<void>;
308
- }
309
-
310
- /** An inline approval request handed to the transport's resolver (structural — no server import). */
311
- interface InProcessApprovalRequestLike {
312
- approvalId: string;
313
- toolName: string;
314
- opts: unknown;
315
- }
316
- /** Resolve one gated-tool approval inline (mirrors the SDK's `boolean | HitlDecision` return). */
317
- type InProcessAwaitApproval = (req: InProcessApprovalRequestLike) => Promise<boolean | ApprovalDecision>;
318
- /** The input the injected runner receives (structurally compatible with `StreamAgentTurnInProcessInput`). */
319
- interface InProcessRunInput {
320
- message: string;
321
- sessionId?: string;
322
- signal?: AbortSignal;
323
- awaitApproval?: InProcessAwaitApproval;
324
- /** M43 — per-request context (from `sendMessages`'s `metadata`) — tenant / provider / auth for the runner. */
325
- context?: unknown;
326
- }
327
- /**
328
- * The in-process turn runner. The consumer binds `streamAgentTurnInProcess(mod, apiKey, …)`:
329
- * `new InProcessTransport({ run: (input) => streamAgentTurnInProcess(mod, apiKey, input) })`.
330
- * Injecting it keeps this client module decoupled from `server/` and makes the transport testable.
331
- */
332
- type InProcessRunner = (input: InProcessRunInput) => AsyncGenerator<UIMessageChunk>;
333
- interface InProcessTransportOptions {
334
- run: InProcessRunner;
335
- }
336
- /**
337
- * M41 (ADR-0050 D4) — `ChatTransport` over the in-process seam (`streamAgentTurnInProcess`), for the
338
- * terminal/desktop surfaces that run client + server in ONE process (no HTTP loopback).
339
- *
340
- * - `sendMessages`: bridge the injected runner's `AsyncGenerator<UIMessageChunk>` into a
341
- * `ReadableStream<UIMessageChunk>` (honoring `abortSignal`, which the runner forwards to the SDK).
342
- * - `reconnectToStream`: always `null` — a single process has no dropped server-side stream to resume
343
- * (mirrors `ai`'s `DirectChatTransport`).
344
- * - `approve`: resolve the pending inline approval by id (the run parks on `awaitApproval`). An unknown
345
- * id rejects (fail-fast, Rule 8 — never a silent resolve).
346
- *
347
- * Error asymmetry vs `HttpTransport` (by design, matching the `ChatTransport` contract): a runner that
348
- * throws SYNCHRONOUSLY surfaces the error when the stream is READ (via `controller.error`), not from the
349
- * `sendMessages` promise — whereas `HttpTransport` throws from `sendMessages` on a non-2xx response.
350
- */
351
- declare class InProcessTransport implements AgentTransport {
352
- #private;
353
- constructor(options: InProcessTransportOptions);
354
- sendMessages(options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0]): Promise<ReadableStream<UIMessageChunk>>;
355
- reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null>;
356
- approve(approvalId: string, decision: ApprovalDecision): Promise<void>;
357
- }
358
-
359
- /** Handlers the transport hands to the injected push source for one turn. */
360
- interface ChannelTurnHandlers {
361
- /** One pushed JSONL line (a serialized `UIMessageChunk`). */
362
- onLine: (line: string) => void;
363
- /** The turn ended — no more lines. */
364
- onClose: () => void;
365
- /** The push source failed. */
366
- onError?: (err: unknown) => void;
367
- }
368
- /**
369
- * The injected push source — a Tauri `Channel`/`invoke` bridge, kept STRUCTURAL so core adds no
370
- * `@tauri-apps/*` dependency and the transport is testable with a fake (ADR-0051 D2). The Tauri app
371
- * wires it: `new Channel()`, `channel.onmessage = onLine`, `invoke('run_agent', { message, channel })`,
372
- * returning a teardown that aborts the sidecar turn.
373
- */
374
- interface ChannelPushSource {
375
- /**
376
- * Start a turn; deliver each JSONL `UIMessageChunk` line to `onLine`, then `onClose`. Return a teardown.
377
- * `turn.context` (M43) is the per-request context (from the seam's `metadata`) — the Tauri `invoke`
378
- * forwards it to the sidecar. When no context is set it is present as `context: undefined` (the key is
379
- * NOT absent) — a sidecar that checks `'context' in turn` should treat `undefined` as "no context".
380
- */
381
- start(turn: {
382
- message: string;
383
- context?: unknown;
384
- }, handlers: ChannelTurnHandlers): () => void;
385
- /** Optional HITL settle (another Tauri `invoke`). */
386
- settle?(approvalId: string, decision: ApprovalDecision): Promise<void>;
387
- }
388
- interface ChannelTransportOptions {
389
- source: ChannelPushSource;
390
- }
391
- /**
392
- * M42 (ADR-0051) — `ChatTransport` over a Tauri-`Channel`-shaped push source, for the desktop webview.
393
- *
394
- * - `sendMessages`: start the turn via the injected source and bridge its pushed JSONL frames into a
395
- * `ReadableStream<UIMessageChunk>` (built in `start` — a Channel is push, so the stream's queue buffers
396
- * frames; ADR-0051 D3). A malformed JSONL line is SKIPPED, never fatal (ADR-0051 D4, Rule 8). `abortSignal`
397
- * tears down the source and closes the stream.
398
- * - `reconnectToStream`: always `null` — the M36 sidecar runs the turn directly (no durable server stream);
399
- * this is the honest parity for a single-process push surface (ADR-0051 D5; mirrors `InProcessTransport`).
400
- * - `approve`: routes to the injected `settle` (another Tauri `invoke`); absent `settle` → a typed error.
401
- *
402
- * The push source is INJECTED — core stays Tauri-agnostic and this transport is unit-tested with a fake.
403
- */
404
- declare class ChannelTransport implements AgentTransport {
405
- #private;
406
- constructor(options: ChannelTransportOptions);
407
- sendMessages(options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0]): Promise<ReadableStream<UIMessageChunk>>;
408
- reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null>;
409
- approve(approvalId: string, decision: ApprovalDecision): Promise<void>;
410
- }
411
-
412
165
  type PrefetchBehavior = 'none' | 'intent' | 'viewport';
413
166
  interface LinkProps extends LinkProps$1 {
414
167
  /** Prefetch strategy. Default: 'intent' (on hover + focus). */
@@ -556,4 +309,4 @@ declare function mountMcpApp(container: HTMLElement, resource: {
556
309
  html: string;
557
310
  }, opts: McpAppHostOptions): McpAppHandle;
558
311
 
559
- export { AgentClient, type AgentClientState, type AgentTransport, type ApprovalDecision, type BatchRequest, type BatchResponse, type BatchTransport, type Batcher, type BatcherOptions, type ChannelPushSource, ChannelTransport, type ChannelTransportOptions, type ChannelTurnHandlers, type CreateAppClientOptions, type GuestMessage, HttpTransport, type HttpTransportOptions, Image, type ImageProps, type InProcessApprovalRequestLike, type InProcessAwaitApproval, type InProcessRunInput, type InProcessRunner, InProcessTransport, type InProcessTransportOptions, type InferBody, type InferQuery, type InferResponse, Link, type LinkProps, MCP_APP_SANDBOX, type McpAppHandle, type McpAppHostOptions, Metadata, type MetadataProps, type PrefetchBehavior, type RequestContext, TheoFetchError, type TheoFetchOptions, type UseAgentOptions, type UseAgentReturn, type UseAgentStatus, consumeChunkStream, consumeUIMessageStream, createAppClient, createBatcher, createGuestMessageHandler, mountMcpApp, responseToChunkStream, theoFetch, useAgent };
312
+ export { AgentTransport, ApprovalDecision, type BatchRequest, type BatchResponse, type BatchTransport, type Batcher, type BatcherOptions, type CreateAppClientOptions, type GuestMessage, Image, type ImageProps, type InferBody, type InferQuery, type InferResponse, Link, type LinkProps, MCP_APP_SANDBOX, type McpAppHandle, type McpAppHostOptions, Metadata, type MetadataProps, type PrefetchBehavior, RequestContext, TheoFetchError, type TheoFetchOptions, type UseAgentOptions, type UseAgentReturn, UseAgentStatus, createAppClient, createBatcher, createGuestMessageHandler, mountMcpApp, theoFetch, useAgent };