@m8tes/sdk 0.1.0-alpha.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.
@@ -0,0 +1,576 @@
1
+ /**
2
+ * @m8tes/react — normalized PUBLIC stream event model.
3
+ *
4
+ * The m8tes V2 backend emits Claude-native FLAT SSE frames (`content_block_delta`,
5
+ * `tool_use`, `permission_request`, `done`, ...). The normalizer (`normalizer.ts`)
6
+ * maps each wire frame to ZERO or MORE events of this stable, versioned
7
+ * discriminated union, keyed on `type`.
8
+ *
9
+ * Type discriminants follow the Vercel AI SDK v5 kebab-case idiom where semantics
10
+ * align (`text-*`, `reasoning-*`, `tool-input-*`, `tool-output-available`) so a
11
+ * future `@m8tes/ai-sdk` adapter maps cleanly. They DIVERGE where m8tes semantics
12
+ * are first-class and have no vanilla-`useChat` analog: human-in-the-loop
13
+ * `approval-request` / `question`, and run rejoin/replay (`run-start` carries
14
+ * runId/runUuid; every terminal path is explicit).
15
+ *
16
+ * Every event carries:
17
+ * - `seq`: a client-assigned monotonic counter. The wire exposes NO SSE `id:`
18
+ * and NO per-event sequence number, so this is assigned by the normalizer and
19
+ * is NOT a dedupe key (see `normalizer.ts` for the domain-id dedupe strategy).
20
+ * - `raw`: the unmodified wire frame, for forward-compatibility.
21
+ *
22
+ * Frames that normalize to nothing renderable (`: keep-alive`, `keep-alive`,
23
+ * `ping`, the duplicate `metadata` preamble frame, `RUNNER_DIAG`, etc.) are
24
+ * dropped by the normalizer and never enter this union.
25
+ *
26
+ * This is a PUBLIC PROTOCOL: once shipped, names are semver-stable. Bump
27
+ * `PROTOCOL_VERSION` on any breaking change to the shape.
28
+ */
29
+ declare const PROTOCOL_VERSION: "m8tes.stream.v2";
30
+ type ProtocolVersion = typeof PROTOCOL_VERSION;
31
+ /** Tool/approval state machine (superset of AI SDK v5 tool-part states + HITL). */
32
+ type ToolState = "input-streaming" | "input-available" | "awaiting-approval" | "output-available" | "output-error" | "denied";
33
+ /** Coarse run status surfaced to the UI. */
34
+ type RunStatus = "connecting" | "running" | "awaiting_approval" | "awaiting_input" | "complete" | "incomplete" | "error" | "cancelled";
35
+ interface BaseEvent {
36
+ type: string;
37
+ /** Client-assigned, monotonic per stream. There is NO wire sequence id. */
38
+ seq: number;
39
+ /** The unmodified wire frame this event was normalized from. */
40
+ raw: Record<string, unknown>;
41
+ }
42
+ /** From the first `metadata` frame. Re-applied (idempotently) on every rejoin. */
43
+ interface RunStartEvent extends BaseEvent {
44
+ type: "run-start";
45
+ protocolVersion: ProtocolVersion;
46
+ runId: number | null;
47
+ runUuid: string | null;
48
+ mode: "task" | "chat";
49
+ agentName?: string;
50
+ instanceId?: number;
51
+ taskId?: number;
52
+ status?: string;
53
+ sandbox?: {
54
+ id: string | null;
55
+ enabled: boolean;
56
+ };
57
+ }
58
+ /** Coarse status transitions (sandbox connect, metadata.status, pause entry). */
59
+ interface RunStatusEvent extends BaseEvent {
60
+ type: "run-status";
61
+ status: RunStatus;
62
+ message?: string;
63
+ sandboxId?: string | null;
64
+ durationMs?: number;
65
+ }
66
+ /** From `run_metrics`. */
67
+ interface RunMetricsEvent extends BaseEvent {
68
+ type: "run-metrics";
69
+ model: string;
70
+ executionTimeMs: number;
71
+ inputTokens: number;
72
+ outputTokens: number;
73
+ costUsd: number | null;
74
+ sdkCostUsd: number | null;
75
+ stopReason: string | null;
76
+ completionState: string;
77
+ unresolvedToolUseIds: string[];
78
+ messageCount: number;
79
+ /** present only when completionState !== "complete" */
80
+ diagnostics?: Record<string, unknown>;
81
+ }
82
+ /** Terminal success path. From `done`. completionState !== "complete" => incomplete run. */
83
+ interface RunFinishEvent extends BaseEvent {
84
+ type: "run-finish";
85
+ status: "complete" | "incomplete";
86
+ completionState: string;
87
+ unresolvedToolUseIds: string[];
88
+ stopReason: string | null;
89
+ terminalCompletionSeen: boolean;
90
+ messageCount: number;
91
+ }
92
+ /** Structured failure codes carried on the wire as a dedicated `type`. */
93
+ type RunErrorCode = "SANDBOX_BOOT_TIMEOUT" | "SANDBOX_QUOTA_EXHAUSTED" | "SANDBOX_UNAVAILABLE" | "SNAPSHOT_VERSION_MISMATCH" | "AGENT_RUNNER_DIED" | "RUNNER_LIFECYCLE_ERROR";
94
+ /** Terminal failure path. From `error`, `sdk_error`, `AGENT_RUNNER_DIED`, SANDBOX_*, SNAPSHOT_VERSION_MISMATCH. */
95
+ interface RunErrorEvent extends BaseEvent {
96
+ type: "run-error";
97
+ error: string;
98
+ message: string;
99
+ /** structured failure code when the wire type was a coded failure, else null */
100
+ code: RunErrorCode | null;
101
+ fatal: true;
102
+ /** HTTP status when the failure was an API (non-stream) error, e.g. 402/429 */
103
+ apiStatus?: number;
104
+ /** v2 envelope `error.details` — carries machine codes like
105
+ * `error_code: "END_USER_RATE_LIMITED"` plus `retry_after`/`period_end` */
106
+ apiDetails?: Record<string, unknown>;
107
+ }
108
+ /** Terminal cancellation. From `cancelled`. */
109
+ interface RunCancelledEvent extends BaseEvent {
110
+ type: "run-cancelled";
111
+ runId?: number | null;
112
+ }
113
+ interface MessageStartEvent extends BaseEvent {
114
+ type: "message-start";
115
+ messageId: string;
116
+ role: "assistant";
117
+ usage?: {
118
+ inputTokens: number;
119
+ outputTokens: number;
120
+ };
121
+ }
122
+ /** From `message_stop` or `message_complete`. */
123
+ interface MessageEndEvent extends BaseEvent {
124
+ type: "message-end";
125
+ messageId: string;
126
+ usage?: {
127
+ inputTokens: number;
128
+ outputTokens: number;
129
+ };
130
+ }
131
+ interface TextStartEvent extends BaseEvent {
132
+ type: "text-start";
133
+ id: string;
134
+ messageId: string;
135
+ }
136
+ interface TextDeltaEvent extends BaseEvent {
137
+ type: "text-delta";
138
+ id: string;
139
+ delta: string;
140
+ messageId: string;
141
+ }
142
+ interface TextEndEvent extends BaseEvent {
143
+ type: "text-end";
144
+ id: string;
145
+ messageId: string;
146
+ }
147
+ interface ReasoningStartEvent extends BaseEvent {
148
+ type: "reasoning-start";
149
+ id: string;
150
+ messageId: string;
151
+ }
152
+ interface ReasoningDeltaEvent extends BaseEvent {
153
+ type: "reasoning-delta";
154
+ id: string;
155
+ delta: string;
156
+ messageId: string;
157
+ }
158
+ interface ReasoningEndEvent extends BaseEvent {
159
+ type: "reasoning-end";
160
+ id: string;
161
+ messageId: string;
162
+ }
163
+ interface PlanStartEvent extends BaseEvent {
164
+ type: "plan-start";
165
+ id: string;
166
+ messageId: string;
167
+ }
168
+ interface PlanDeltaEvent extends BaseEvent {
169
+ type: "plan-delta";
170
+ id: string;
171
+ delta: string;
172
+ messageId: string;
173
+ }
174
+ interface PlanEndEvent extends BaseEvent {
175
+ type: "plan-end";
176
+ id: string;
177
+ messageId: string;
178
+ }
179
+ interface ToolInputStartEvent extends BaseEvent {
180
+ type: "tool-input-start";
181
+ toolCallId: string;
182
+ toolName: string;
183
+ messageId: string;
184
+ state: "input-streaming";
185
+ }
186
+ interface ToolInputDeltaEvent extends BaseEvent {
187
+ type: "tool-input-delta";
188
+ toolCallId: string;
189
+ inputTextDelta: string;
190
+ state: "input-streaming";
191
+ }
192
+ interface ToolInputAvailableEvent extends BaseEvent {
193
+ type: "tool-input-available";
194
+ toolCallId: string;
195
+ toolName: string;
196
+ input: unknown;
197
+ state: "input-available";
198
+ }
199
+ interface ToolOutputAvailableEvent extends BaseEvent {
200
+ type: "tool-output-available";
201
+ toolCallId: string;
202
+ output: unknown;
203
+ isError: boolean;
204
+ state: "output-available" | "output-error";
205
+ }
206
+ /** Tool approval gate. From `awaiting_approval` (toolName !== "AskUserQuestion") or `permission_request`. */
207
+ interface ApprovalRequestEvent extends BaseEvent {
208
+ type: "approval-request";
209
+ requestId: string;
210
+ toolCallId?: string;
211
+ toolName: string;
212
+ toolInput: unknown;
213
+ timeoutSeconds: number;
214
+ }
215
+ /** Derived on resume / from the answer round-trip; surfaced for state reconciliation. */
216
+ interface ApprovalResolvedEvent extends BaseEvent {
217
+ type: "approval-resolved";
218
+ requestId: string;
219
+ resolved: "approved" | "denied";
220
+ }
221
+ /** AskUserQuestion gate. From `awaiting_approval` where toolName === "AskUserQuestion". */
222
+ interface QuestionOption {
223
+ label: string;
224
+ description?: string;
225
+ }
226
+ interface QuestionItem {
227
+ question: string;
228
+ /** Real wire options are `{label, description}` objects; the normalizer also
229
+ * coerces bare-string options into `{label}` defensively. */
230
+ options?: QuestionOption[];
231
+ [k: string]: unknown;
232
+ }
233
+ interface QuestionEvent extends BaseEvent {
234
+ type: "question";
235
+ requestId: string;
236
+ toolCallId: string;
237
+ questions: QuestionItem[];
238
+ timeoutSeconds: number;
239
+ }
240
+ /** From `sandbox-connecting` / `sandbox-connected`. (Fatal sandbox failures => RunErrorEvent with `code`.) */
241
+ interface SandboxStatusEvent extends BaseEvent {
242
+ type: "sandbox-status";
243
+ phase: "connecting" | "connected";
244
+ message: string;
245
+ runId: number | null;
246
+ sandboxId?: string | null;
247
+ durationMs?: number;
248
+ }
249
+ /** Non-fatal diagnostics: stderr, mcp_error/mcp_auth_failed (warning), rate_limit, system_message. */
250
+ interface NoticeEvent extends BaseEvent {
251
+ type: "notice";
252
+ level: "info" | "warning";
253
+ source: "stderr" | "mcp" | "rate_limit" | "system";
254
+ message: string;
255
+ detail?: string;
256
+ }
257
+ /** From `compact_boundary`: the SDK summarized the conversation history. */
258
+ interface CompactBoundaryEvent extends BaseEvent {
259
+ type: "compact-boundary";
260
+ trigger: "manual" | "auto";
261
+ preTokens: number;
262
+ }
263
+ /**
264
+ * Any wire type with no normalized mapping (`sdk_content_snapshot`, `user_message`,
265
+ * `compact_boundary`, and future/unknown types). `raw` is preserved so consumers
266
+ * and a newer normalizer can recover the original. Forward-compat: a new backend
267
+ * event surfaces here instead of crashing.
268
+ */
269
+ interface UnknownEvent extends BaseEvent {
270
+ type: "unknown";
271
+ wireType: string;
272
+ }
273
+ type M8tesStreamEvent = RunStartEvent | RunStatusEvent | RunMetricsEvent | RunFinishEvent | RunErrorEvent | RunCancelledEvent | MessageStartEvent | MessageEndEvent | TextStartEvent | TextDeltaEvent | TextEndEvent | ReasoningStartEvent | ReasoningDeltaEvent | ReasoningEndEvent | PlanStartEvent | PlanDeltaEvent | PlanEndEvent | ToolInputStartEvent | ToolInputDeltaEvent | ToolInputAvailableEvent | ToolOutputAvailableEvent | ApprovalRequestEvent | ApprovalResolvedEvent | QuestionEvent | SandboxStatusEvent | NoticeEvent | CompactBoundaryEvent | UnknownEvent;
274
+ type M8tesStreamEventType = M8tesStreamEvent["type"];
275
+ /** Terminal events end a stream. */
276
+ declare const TERMINAL_EVENT_TYPES: readonly ["run-finish", "run-error", "run-cancelled"];
277
+ type TerminalEventType = (typeof TERMINAL_EVENT_TYPES)[number];
278
+ /** True for the three terminal event types. */
279
+ declare function isTerminalEvent(event: M8tesStreamEvent): event is RunFinishEvent | RunErrorEvent | RunCancelledEvent;
280
+
281
+ /**
282
+ * SSE wire decoder: raw bytes/text -> wire frame objects.
283
+ *
284
+ * Layer 1 of the pipeline (Layer 2 is `normalizer.ts`). This module ONLY knows
285
+ * the SSE envelope + JSON, never the m8tes event semantics.
286
+ *
287
+ * chunk(s) ─push─► [ frame split on blank line ] ─► [ data: lines ]
288
+ * ─► [ concatenated-JSON split ] ─► JSON.parse ─► wire object
289
+ *
290
+ * Wire facts it handles (from the streaming contract):
291
+ * - Frames are separated by a blank line; `\r\n` is normalized to `\n`.
292
+ * - A line starting with `:` is an SSE comment (keepalive) — ignored.
293
+ * - A frame may carry one or more `data:` lines (joined with `\n` per spec).
294
+ * - A single `data:` payload may glue MULTIPLE complete JSON objects together
295
+ * (observed in the app stream); they are split with a string-aware brace
296
+ * scanner — NOT a naive `}{` regex, which breaks on braces inside strings.
297
+ * - Invalid JSON in a completed frame is DROPPED (reported via `onMalformed`),
298
+ * never thrown — a corrupt frame must not kill the stream (contract §7).
299
+ */
300
+ interface SseParserOptions {
301
+ /**
302
+ * Called for each `data:` payload (or split piece) that fails to parse as JSON.
303
+ * Default: no-op. Wire this to telemetry; do NOT throw from it.
304
+ */
305
+ onMalformed?: (rawPayload: string, error: unknown) => void;
306
+ }
307
+ type WireFrame$1 = Record<string, unknown>;
308
+ /** Split a payload into top-level JSON object/array substrings, string-aware. */
309
+ declare function splitConcatenatedJson(payload: string): string[];
310
+ /**
311
+ * Stateful streaming decoder. Feed it response-body chunks (any size, split
312
+ * mid-frame); it returns the wire frames completed by each chunk. Call `flush()`
313
+ * once the stream ends to drain a trailing frame that had no closing blank line.
314
+ */
315
+ declare function createSseDecoder(opts?: SseParserOptions): {
316
+ /** Feed a chunk; returns the wire frames it completed. */
317
+ push(chunk: string): WireFrame$1[];
318
+ /** Flush a trailing unterminated frame at end-of-stream. */
319
+ flush(): WireFrame$1[];
320
+ };
321
+ /** Convenience: parse a whole SSE string into wire frames (used by fixtures/tests). */
322
+ declare function parseSse(text: string, opts?: SseParserOptions): WireFrame$1[];
323
+
324
+ /**
325
+ * Normalizer: wire frames -> public M8tesStreamEvent[].
326
+ *
327
+ * Layer 2 of the pipeline (Layer 1 = `sse-parser.ts`). Each wire frame maps to
328
+ * ZERO or MORE public events. The normalizer owns:
329
+ * - `seq`: a monotonic counter stamped on every emitted event (no wire seq id).
330
+ * - dedupe: a domain-id `open`/`seen` ledger so a `/stream` rejoin that
331
+ * re-streams blocks + re-sends a message_snapshot + re-sends a pending
332
+ * permission_request renders EXACTLY ONCE (streaming contract §dedupeStrategy).
333
+ *
334
+ * One normalizer instance is kept ALIVE across a reconnect (the hook reuses it),
335
+ * so `seen` persists and replayed content is dropped. Idempotent-apply rules:
336
+ * - START events: skip if the key is already open or seen.
337
+ * - DELTA events: drop if the key is in `seen` (finalized) — a replayed delta
338
+ * for a closed block. A bare key not yet seen is lazily opened (tolerates a
339
+ * trimmed replay prefix).
340
+ * - END / result / terminal / approval events: finalize, move key to `seen`;
341
+ * a second occurrence is a no-op.
342
+ *
343
+ * Unknown/unmapped wire types pass through as `UnknownEvent` (never throw).
344
+ */
345
+
346
+ type WireFrame = Record<string, unknown>;
347
+ interface Normalizer {
348
+ /** Map one wire frame to zero+ public events (seq-stamped, in order). */
349
+ push(frame: WireFrame): M8tesStreamEvent[];
350
+ /** Discard all dedupe/lifecycle state (e.g. starting a brand-new run). */
351
+ reset(): void;
352
+ }
353
+ declare function createNormalizer(): Normalizer;
354
+
355
+ /**
356
+ * Accumulator: the normalized event stream -> renderable conversation state.
357
+ *
358
+ * Pure + immutable (new state object on every change) so React can re-render via
359
+ * useState/useSyncExternalStore. Framework-agnostic — `useMate` wraps it. It
360
+ * assumes the normalizer has already deduped (so each event is "new"); it only
361
+ * folds events into messages/parts + run status + pending HITL.
362
+ *
363
+ * Lazy creation: a `text-delta`/`tool-*` with no preceding start (a trimmed
364
+ * replay prefix) lazily creates its message/part, so a partial rejoin still
365
+ * renders rather than dropping content.
366
+ */
367
+
368
+ type TextLikeKind = "text" | "reasoning" | "plan";
369
+ interface TextPart {
370
+ kind: TextLikeKind;
371
+ id: string;
372
+ text: string;
373
+ }
374
+ interface ToolPart {
375
+ kind: "tool";
376
+ toolCallId: string;
377
+ toolName: string;
378
+ state: ToolState;
379
+ inputText: string;
380
+ input?: unknown;
381
+ output?: unknown;
382
+ isError?: boolean;
383
+ }
384
+ /** Non-fatal diagnostics rendered as a quiet inline row (mcp auth failures,
385
+ * rate limits) — the platform surfaces these; silence hides real failures. */
386
+ interface NoticePart {
387
+ kind: "notice";
388
+ id: string;
389
+ level: "info" | "warning";
390
+ source: string;
391
+ message: string;
392
+ }
393
+ /** Sandbox lifecycle pill ("connecting to environment" -> "environment ready"). */
394
+ interface SandboxPart {
395
+ kind: "sandbox";
396
+ id: string;
397
+ phase: "connecting" | "connected";
398
+ durationMs?: number;
399
+ }
400
+ /** Conversation-summarized divider (SDK auto/manual compaction). */
401
+ interface CompactPart {
402
+ kind: "compact";
403
+ id: string;
404
+ trigger: "manual" | "auto";
405
+ preTokens: number;
406
+ }
407
+ type MatePart = TextPart | ToolPart | NoticePart | SandboxPart | CompactPart;
408
+ interface MateMessage {
409
+ id: string;
410
+ role: "assistant" | "user";
411
+ parts: MatePart[];
412
+ }
413
+ type MateStatus = "idle" | RunStatus;
414
+ interface ConversationState {
415
+ runId: number | null;
416
+ runUuid: string | null;
417
+ agentName: string | null;
418
+ status: MateStatus;
419
+ messages: MateMessage[];
420
+ pendingApproval: ApprovalRequestEvent | null;
421
+ pendingQuestion: QuestionEvent | null;
422
+ /** From run-metrics: "refusal" | "max_tokens" render a quiet outcome row
423
+ * ("Request declined" / "Response truncated"); anything else is null. */
424
+ finishStopReason: "refusal" | "max_tokens" | null;
425
+ error: {
426
+ message: string;
427
+ code: string | null;
428
+ /** HTTP status for API errors (402 limit / 429 rate) */
429
+ apiStatus?: number;
430
+ /** v2 `error.details` (machine `error_code`, `retry_after`, `period_end`, ...) */
431
+ apiDetails?: Record<string, unknown>;
432
+ } | null;
433
+ }
434
+ declare const initialConversationState: ConversationState;
435
+ declare function accumulate(state: ConversationState, e: M8tesStreamEvent): ConversationState;
436
+ /** Stateful convenience wrapper for the hook (holds the running snapshot). */
437
+ interface Accumulator {
438
+ readonly state: ConversationState;
439
+ apply(event: M8tesStreamEvent): ConversationState;
440
+ /** Optimistically append the user's own message (shown immediately on send). */
441
+ addUserMessage(text: string): ConversationState;
442
+ reset(): void;
443
+ }
444
+ declare function createAccumulator(): Accumulator;
445
+
446
+ /**
447
+ * Typed error hierarchy for the m8tes V2 API — ONE implementation shared by
448
+ * `@m8tes/sdk` (API-key client) and `@m8tes/react` (browser proxy client).
449
+ *
450
+ * Mirrors the Python SDK's `sdk/py/m8tes/_exceptions.py` so the two languages
451
+ * behave identically: same status→class map, same `docUrl`/`errorCode`/
452
+ * `retryAfter`/`details` fields, just camelCase.
453
+ *
454
+ * The wire envelope is standardized across every /api/v2 route
455
+ * (`fastapi/app/routers/v2/_errors.py`):
456
+ *
457
+ * { "error": { "message", "type", "code", "request_id", "doc_url",
458
+ * "details": { "error_code": "...", ...context } } }
459
+ *
460
+ * Note `error.code` is the int HTTP status by design; the machine-readable app
461
+ * code (e.g. "RUN_LIMIT_REACHED", "END_USER_RATE_LIMITED") lives at
462
+ * `error.details.error_code` and is surfaced here as `errorCode`.
463
+ *
464
+ * No auth and no `node:` imports live in this file — it ships in browser
465
+ * bundles via `@m8tes/sdk/protocol`.
466
+ */
467
+ interface ApiErrorFields {
468
+ /** Envelope `error.type`, e.g. "authentication_error". */
469
+ type: string;
470
+ /** Envelope `error.code` — the int HTTP status (kept for wire fidelity). */
471
+ code: number;
472
+ /** HTTP status of the response. */
473
+ status: number;
474
+ /** `error.request_id`, else the `x-request-id` response header. Quote this in bug reports. */
475
+ requestId?: string;
476
+ /** Full `error.details` object: actionable context (runs_used, period_end, ...). */
477
+ details?: unknown;
478
+ /** `error.doc_url` — docs deep link for this error type. */
479
+ docUrl?: string;
480
+ /** `error.details.error_code` — machine-readable app code for branching. */
481
+ errorCode?: string;
482
+ /** Seconds from the `Retry-After` header. Set on 429; undefined when absent or an HTTP-date. */
483
+ retryAfter?: number;
484
+ }
485
+ /** Base class for every API error. Catch this to catch them all. */
486
+ declare class M8tesApiError extends Error {
487
+ readonly type: string;
488
+ readonly code: number;
489
+ readonly status: number;
490
+ readonly requestId?: string;
491
+ readonly details?: unknown;
492
+ readonly docUrl?: string;
493
+ readonly errorCode?: string;
494
+ readonly retryAfter?: number;
495
+ constructor(message: string, f: ApiErrorFields);
496
+ }
497
+ /** 400 or 422 — invalid request. Check `.status` to tell them apart. */
498
+ declare class ValidationError extends M8tesApiError {
499
+ constructor(message: string, f: ApiErrorFields);
500
+ }
501
+ /** 401 — missing, malformed, or revoked API key. */
502
+ declare class AuthenticationError extends M8tesApiError {
503
+ constructor(message: string, f: ApiErrorFields);
504
+ }
505
+ /** 402 — billing limit reached or subscription issue. `.details` carries the caps. */
506
+ declare class BillingError extends M8tesApiError {
507
+ constructor(message: string, f: ApiErrorFields);
508
+ }
509
+ /** 403 — authenticated but not allowed. */
510
+ declare class PermissionDeniedError extends M8tesApiError {
511
+ constructor(message: string, f: ApiErrorFields);
512
+ }
513
+ /** 404 — no such resource, or it belongs to another account/end-user. */
514
+ declare class NotFoundError extends M8tesApiError {
515
+ constructor(message: string, f: ApiErrorFields);
516
+ }
517
+ /** 409 — conflicting state. */
518
+ declare class ConflictError extends M8tesApiError {
519
+ constructor(message: string, f: ApiErrorFields);
520
+ }
521
+ /**
522
+ * 409 from `GET /runs/{id}/stream` — the run is no longer executing, so there is
523
+ * nothing to join. The caller should fall back to `runs.get(id)` for the final
524
+ * result rather than treating this as a failure.
525
+ */
526
+ declare class RunNotStreamingError extends ConflictError {
527
+ constructor(message: string, f: ApiErrorFields);
528
+ }
529
+ /** 429 — too many requests. Honour `.retryAfter` before retrying. */
530
+ declare class RateLimitError extends M8tesApiError {
531
+ constructor(message: string, f: ApiErrorFields);
532
+ }
533
+ /** 500+ — server-side error. Safe to retry idempotent requests. */
534
+ declare class APIError extends M8tesApiError {
535
+ constructor(message: string, f: ApiErrorFields);
536
+ }
537
+ /**
538
+ * A stream completed but emitted error events (expired credential, provider rate
539
+ * limit, quota exhaustion). Raised so a failed run is never mistaken for a
540
+ * successful empty one. `.details.errors` holds the raw messages.
541
+ */
542
+ declare class RunFailedError extends M8tesApiError {
543
+ constructor(message: string, f: ApiErrorFields);
544
+ }
545
+ /** `Retry-After` in seconds. An HTTP-date (or garbage) yields undefined, matching Python. */
546
+ declare function parseRetryAfter(raw: string | null | undefined): number | undefined;
547
+ /**
548
+ * Pull the standardized envelope out of a parsed error body.
549
+ *
550
+ * Tolerant by design: a proxy, a CDN, or a non-v2 route can return HTML, an
551
+ * empty body, or a bare `{detail: ...}`, and callers still get a usable error
552
+ * with the right status rather than a SyntaxError.
553
+ */
554
+ declare function parseErrorEnvelope(status: number, body: unknown, headers?: {
555
+ get(name: string): string | null;
556
+ }): {
557
+ message: string;
558
+ fields: ApiErrorFields;
559
+ };
560
+ interface ErrorFromResponseOptions {
561
+ /**
562
+ * Map 409 to `RunNotStreamingError` (the "run already finished, fall back to
563
+ * runs.get()" signal) instead of the generic `ConflictError`. Set on stream
564
+ * requests, where 409 has exactly that meaning.
565
+ */
566
+ conflictIsNotStreaming?: boolean;
567
+ }
568
+ /** The error class a status maps to. Exported so clients that build their own
569
+ * message (e.g. the SDK's base-URL diagnostics) still get the right type. */
570
+ declare function errorClassForStatus(status: number, opts?: ErrorFromResponseOptions): new (message: string, f: ApiErrorFields) => M8tesApiError;
571
+ /**
572
+ * Build the right typed error from a non-OK `Response`. Consumes the body.
573
+ */
574
+ declare function errorFromResponse(res: Response, opts?: ErrorFromResponseOptions): Promise<M8tesApiError>;
575
+
576
+ export { APIError, type Accumulator, type ApiErrorFields, type ApprovalRequestEvent, type ApprovalResolvedEvent, AuthenticationError, type BaseEvent, BillingError, type CompactBoundaryEvent, type CompactPart, ConflictError, type ConversationState, type ErrorFromResponseOptions, M8tesApiError, type M8tesStreamEvent, type M8tesStreamEventType, type MateMessage, type MatePart, type MateStatus, type MessageEndEvent, type MessageStartEvent, type Normalizer, NotFoundError, type NoticeEvent, type NoticePart, PROTOCOL_VERSION, PermissionDeniedError, type PlanDeltaEvent, type PlanEndEvent, type PlanStartEvent, type ProtocolVersion, type QuestionEvent, type QuestionItem, type QuestionOption, RateLimitError, type ReasoningDeltaEvent, type ReasoningEndEvent, type ReasoningStartEvent, type RunCancelledEvent, type RunErrorCode, type RunErrorEvent, RunFailedError, type RunFinishEvent, type RunMetricsEvent, RunNotStreamingError, type RunStartEvent, type RunStatus, type RunStatusEvent, type SandboxPart, type SandboxStatusEvent, type SseParserOptions, TERMINAL_EVENT_TYPES, type TerminalEventType, type TextDeltaEvent, type TextEndEvent, type TextLikeKind, type TextPart, type TextStartEvent, type ToolInputAvailableEvent, type ToolInputDeltaEvent, type ToolInputStartEvent, type ToolOutputAvailableEvent, type ToolPart, type ToolState, type UnknownEvent, ValidationError, accumulate, createAccumulator, createNormalizer, createSseDecoder, errorClassForStatus, errorFromResponse, initialConversationState, isTerminalEvent, parseErrorEnvelope, parseRetryAfter, parseSse, splitConcatenatedJson };