@orkestrel/agent 0.0.21 → 0.0.23

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.
@@ -1,16 +1,26 @@
1
+ import { ArrayShape } from '@orkestrel/contract';
2
+ import { BooleanShape } from '@orkestrel/contract';
1
3
  import type { BudgetInterface } from '@orkestrel/budget';
4
+ import { ContractInterface } from '@orkestrel/contract';
5
+ import type { ContractShape } from '@orkestrel/contract';
2
6
  import type { ControllerInterface } from '@orkestrel/workflow';
3
7
  import type { DriverInterface } from '@orkestrel/database';
4
8
  import type { EmitterErrorHandler } from '@orkestrel/emitter';
5
9
  import type { EmitterHooks } from '@orkestrel/emitter';
6
10
  import type { EmitterInterface } from '@orkestrel/emitter';
7
11
  import type { FileInterface } from '@orkestrel/workspace';
8
- import type { JSONValue } from '@orkestrel/contract';
12
+ import { JSONShape } from '@orkestrel/contract';
13
+ import { JSONValue } from '@orkestrel/contract';
14
+ import { LiteralShape } from '@orkestrel/contract';
15
+ import { NumberShape } from '@orkestrel/contract';
16
+ import { ObjectShape } from '@orkestrel/contract';
17
+ import { OptionalShape } from '@orkestrel/contract';
9
18
  import type { QueueContext } from '@orkestrel/queue';
10
19
  import type { QueueInterface } from '@orkestrel/queue';
11
20
  import type { QueueStoreInterface } from '@orkestrel/queue';
12
21
  import type { RunnerInterface } from '@orkestrel/workflow';
13
22
  import type { SchedulerInterface } from '@orkestrel/workflow';
23
+ import { StringShape } from '@orkestrel/contract';
14
24
  import type { TableInterface } from '@orkestrel/database';
15
25
  import type { TokenUsage } from '@orkestrel/budget';
16
26
  import type { ToolCall } from '@orkestrel/tool';
@@ -18,6 +28,7 @@ import type { ToolDefinition } from '@orkestrel/tool';
18
28
  import type { ToolInterface } from '@orkestrel/tool';
19
29
  import type { ToolManagerInterface } from '@orkestrel/tool';
20
30
  import type { ToolResult } from '@orkestrel/tool';
31
+ import { UnionShape } from '@orkestrel/contract';
21
32
  import type { WorkspaceManagerInterface } from '@orkestrel/workspace';
22
33
 
23
34
  /**
@@ -475,6 +486,14 @@ export declare type AgentEventMap = {
475
486
  * - **Bounded.** Each turn arms a single cancel folded from the external `signal`, the
476
487
  * `timeout` deadline, and the `budget` signal (through `AbortSignal.any`); any of them —
477
488
  * or `abort()` — stops the loop and settles the result `partial: true`.
489
+ * Tool handlers receive that run's signal through their `ToolContext`. An agent abort,
490
+ * stream abort, external signal, or deadline can reach a running handler. The budget is
491
+ * charged during provider streaming and between turns, before tool dispatch; exhaustion
492
+ * ends the run without dispatching, never inside a handler. An abort before dispatch
493
+ * appends neither the assistant call turn nor tool messages and emits no tool chunk;
494
+ * streamed content remains in the partial result. Cancellation after entry is cooperative:
495
+ * the loop awaits a running handler even when it ignores the signal.
496
+ * The agent supplies no caller identity.
478
497
  * - **Paced + capped.** The `scheduler` (when given) yields between turns; tool
479
498
  * iteration is capped at `limit` so the loop always terminates.
480
499
  * - **Two observation surfaces.** Pull: the {@link AgentChunk} stream (`stream().events`)
@@ -711,6 +730,126 @@ export declare interface AgentOptions {
711
730
  readonly strict?: boolean;
712
731
  }
713
732
 
733
+ /**
734
+ * Implements bounded HTTP streaming and result assembly behind concrete wire seams.
735
+ *
736
+ * @remarks
737
+ * Every call owns its parser, splitter, deadline, and accumulation. Success bodies
738
+ * have no size limit. A qwen3 implicit-open reclassification corrects the final
739
+ * content while content deltas already yielded cannot be recalled. A subclass fills
740
+ * `name`, `frame`, `body`, `read`, and `finish`; the constructor takes the `split`
741
+ * and `strict` switches to control reasoning separation and settled-result requirements.
742
+ *
743
+ * @example Writing a provider for a new wire
744
+ * ```ts
745
+ * import type {
746
+ * ProviderIncrement,
747
+ * ProviderOptions,
748
+ * ProviderParserInterface,
749
+ * ProviderRequest,
750
+ * } from '@orkestrel/agent'
751
+ * import { AgentProvider } from '@orkestrel/agent'
752
+ *
753
+ * class TextFrame implements ProviderParserInterface<string> {
754
+ * parse(chunk: string): readonly string[] {
755
+ * return [chunk]
756
+ * }
757
+ * clear(): void {} // Raw text retains no framing state.
758
+ * }
759
+ *
760
+ * interface TextOptions extends ProviderOptions {
761
+ * readonly url: string
762
+ * }
763
+ *
764
+ * class TextProvider extends AgentProvider<string> {
765
+ * readonly name = 'text'
766
+ * constructor(options: TextOptions) {
767
+ * super({ ...options, path: '/generate' })
768
+ * }
769
+ * frame(): ProviderParserInterface<string> {
770
+ * return new TextFrame()
771
+ * }
772
+ * body(request: ProviderRequest): object {
773
+ * return { messages: request.messages }
774
+ * }
775
+ * read(record: string): ProviderIncrement {
776
+ * return { content: record, thinking: '', tools: [] }
777
+ * }
778
+ * finish(_parser: ProviderParserInterface<string>): readonly string[] {
779
+ * return [] // Raw text retains no records at end of input.
780
+ * }
781
+ * }
782
+ * ```
783
+ */
784
+ export declare abstract class AgentProvider<TRecord = Readonly<Record<string, unknown>>> implements AgentProviderInterface<TRecord> {
785
+ #private;
786
+ constructor(input: AgentProviderInput);
787
+ /** Identifies the concrete backend. */
788
+ abstract readonly name: string;
789
+ /** Exposes the instance's minted UUID. */
790
+ get id(): string;
791
+ /** Exposes the context framing exactly as supplied. */
792
+ get format(): ContextFormat | undefined;
793
+ /** Creates fresh framing state for the call. */
794
+ abstract frame(): ProviderParserInterface<TRecord>;
795
+ /** Projects a domain request onto the concrete protocol's wire body. */
796
+ abstract body(request: ProviderRequest): object;
797
+ /** Decodes a framed record into a turn increment. */
798
+ abstract read(record: TRecord): ProviderIncrement;
799
+ /** Returns any records retained at end of input. */
800
+ abstract finish(parser: ProviderParserInterface<TRecord>): readonly TRecord[];
801
+ /**
802
+ * Generates a complete turn by draining the shared stream engine.
803
+ *
804
+ * @param messages - The conversation turns
805
+ * @param signal - The caller's cancellation bound
806
+ * @param tools - The advertised tool definitions
807
+ * @param options - The per-call generation configuration
808
+ * @returns The terminal stream result
809
+ */
810
+ generate(messages: readonly Message[], signal: AbortSignal, tools?: readonly ToolDefinition[], options?: ProviderStreamOptions): Promise<ProviderResult>;
811
+ /**
812
+ * Streams decoded deltas and returns the authoritative or assembled turn result.
813
+ *
814
+ * @param messages - The conversation turns
815
+ * @param signal - The caller's cancellation bound
816
+ * @param tools - The advertised tool definitions
817
+ * @param options - The per-call generation configuration
818
+ * @returns Content and native thinking deltas followed by the settled result
819
+ * @throws ProviderAbortError Thrown when the combined cancellation bound fires
820
+ * @throws ProviderError Thrown for an HTTP or protocol failure
821
+ */
822
+ stream(messages: readonly Message[], signal: AbortSignal, tools?: readonly ToolDefinition[], options?: ProviderStreamOptions): AsyncGenerator<ProviderDelta, ProviderResult>;
823
+ }
824
+
825
+ /**
826
+ * Configures the HTTP destination and stream assembly of a provider base.
827
+ *
828
+ * @remarks
829
+ * `path` appends to `url`. If `split` is true, separates in-content reasoning;
830
+ * if false, preserves content verbatim. Default: true.
831
+ * If `strict` is true, requires a settled result record; if false, assembles at end of input.
832
+ * Default: false.
833
+ */
834
+ export declare interface AgentProviderInput extends ProviderOptions {
835
+ readonly url: string;
836
+ readonly path?: string;
837
+ readonly split?: boolean;
838
+ readonly strict?: boolean;
839
+ }
840
+
841
+ /** Defines the wire-specific seams of the shared HTTP provider engine. */
842
+ export declare interface AgentProviderInterface<TRecord = Readonly<Record<string, unknown>>> extends ProviderInterface {
843
+ /** Creates fresh framing state for a call. */
844
+ frame(): ProviderParserInterface<TRecord>;
845
+ /** Projects a request to the concrete protocol's serializable body. */
846
+ body(request: ProviderRequest): object;
847
+ /** Decodes a framed record into its contribution to the turn. */
848
+ read(record: TRecord): ProviderIncrement;
849
+ /** Returns records retained at end of input before the parser is cleared. */
850
+ finish(parser: ProviderParserInterface<TRecord>): readonly TRecord[];
851
+ }
852
+
714
853
  /**
715
854
  * Configures `createAgentQueue` — the registry that rehydrates jobs, the partial-result
716
855
  * policy, and the substrate knobs threaded into the backing `createQueue`.
@@ -1211,6 +1350,21 @@ export declare interface AuthorityRule {
1211
1350
  readonly reason?: string;
1212
1351
  }
1213
1352
 
1353
+ /**
1354
+ * Assembles a provider result with only populated optional fields.
1355
+ *
1356
+ * @param content - The authoritative answer
1357
+ * @param thinking - The joined reasoning
1358
+ * @param tools - The accumulated calls
1359
+ * @param usage - The reported token usage
1360
+ * @returns The assembled result
1361
+ * @example
1362
+ * ```ts
1363
+ * buildProviderResult('ok', '', [], undefined) // { content: 'ok' }
1364
+ * ```
1365
+ */
1366
+ export declare function buildProviderResult(content: string, thinking: string, tools: readonly ToolCall[], usage: TokenUsage | undefined): ProviderResult;
1367
+
1214
1368
  /**
1215
1369
  * Builds the framed recap message for one compacted section — the same role and stable `id` as
1216
1370
  * {@link buildSummaryMessage}, with the content prefixed by {@link
@@ -2459,8 +2613,8 @@ export declare function createChannel<T>(): ChannelInterface<T>;
2459
2613
  *
2460
2614
  * @example Conversations & compaction
2461
2615
  * ```ts
2462
- * import { createConversation } from '@orkestrel/agent'
2463
2616
  * import type { ProviderInterface } from '@orkestrel/agent'
2617
+ * import { createConversation } from '@orkestrel/agent'
2464
2618
  *
2465
2619
  * declare const provider: ProviderInterface // any concrete implementation supplied by the host app
2466
2620
  * // The summarizer seam — built from the provider by the runtime; core stays provider-agnostic.
@@ -2651,6 +2805,77 @@ export declare function createInstructionManager(options?: InstructionManagerOpt
2651
2805
  */
2652
2806
  export declare function createMemoryConversationStore(): ConversationStoreInterface;
2653
2807
 
2808
+ /**
2809
+ * Creates an authorized relay handler that validates a bounded JSON request before streaming.
2810
+ *
2811
+ * @remarks
2812
+ * Answers with the `401` status when authorization refuses or throws, the `400`
2813
+ * status when the body is missing, unreadable, or invalid, the `413` status when
2814
+ * the body fills its byte budget or the inbound read is aborted, and the `502`
2815
+ * status when the upstream provider call cannot be constructed. Refusals carry no body.
2816
+ *
2817
+ * @param options - The upstream provider, authorization decision, and optional byte budget
2818
+ * @returns A fetch-standard handler suitable for a router
2819
+ * @example Mounting the relay on your server
2820
+ * ```ts
2821
+ * import type { ProviderInterface } from '@orkestrel/agent'
2822
+ * import { createRelay } from '@orkestrel/agent'
2823
+ * import { createDispatcher } from '@orkestrel/router'
2824
+ * import { createServer } from '@orkestrel/server'
2825
+ *
2826
+ * declare const upstream: ProviderInterface // the server-side provider holding the credential
2827
+ * declare const bearer: string
2828
+ *
2829
+ * const handler = createRelay({
2830
+ * provider: upstream,
2831
+ * authorize: (request) => request.headers.get('authorization') === `Bearer ${bearer}`,
2832
+ * })
2833
+ * const dispatcher = createDispatcher({
2834
+ * routes: [{ method: 'POST', path: '/relay', handler }],
2835
+ * })
2836
+ *
2837
+ * export function serve(request: Request): Promise<Response> {
2838
+ * return dispatcher.handle(request, undefined)
2839
+ * }
2840
+ *
2841
+ * const server = createServer({ dispatcher, state: () => undefined })
2842
+ * await server.start()
2843
+ * process.on('SIGTERM', () => server.stop()) // signal cancellation, drain, then close the listener
2844
+ * ```
2845
+ */
2846
+ export declare function createRelay(options: RelayOptions): RelayHandler;
2847
+
2848
+ /**
2849
+ * Creates a provider that carries calls through a relay endpoint.
2850
+ *
2851
+ * @remarks
2852
+ * This is the browser end alone. {@link createRelay} mounts the server end, and its example
2853
+ * is the server half this one pairs with.
2854
+ *
2855
+ * @param options - The endpoint, parser factory, and HTTP call configuration
2856
+ * @returns The concrete relay provider
2857
+ * @example Reaching the relay from the browser
2858
+ * ```ts
2859
+ * import type { ProviderInterface } from '@orkestrel/agent'
2860
+ * import { createRelayProvider } from '@orkestrel/agent'
2861
+ * import { createAbort } from '@orkestrel/abort'
2862
+ * // The browser application supplies this parser dependency.
2863
+ * import { createNDJSONParser } from '@orkestrel/ndjson'
2864
+ *
2865
+ * declare const bearer: string
2866
+ * const abort = createAbort()
2867
+ * const messages = [{ id: '1', role: 'user', content: 'Say hello.' }] as const
2868
+ *
2869
+ * const browser: ProviderInterface = createRelayProvider({
2870
+ * url: 'https://app.example/relay',
2871
+ * parser: createNDJSONParser,
2872
+ * headers: () => ({ authorization: `Bearer ${bearer}` }),
2873
+ * })
2874
+ * const result = await browser.generate(messages, abort.signal) // a ProviderResult like a local provider's
2875
+ * ```
2876
+ */
2877
+ export declare function createRelayProvider(options: RelayProviderOptions): RelayProvider;
2878
+
2654
2879
  /**
2655
2880
  * Creates a named scope — an immutable {@link ScopeInterface} from its `name` and its
2656
2881
  * per-category allow-lists, the `id` minted at construction.
@@ -2826,6 +3051,19 @@ export declare const DEFAULT_AUTHORITY_ZONE = "default";
2826
3051
  */
2827
3052
  export declare const DEFAULT_CONVERSATION_KEEP = 0;
2828
3053
 
3054
+ /**
3055
+ * Holds the default provider deadline in milliseconds — `120_000`, the wall-clock bound a call
3056
+ * runs under when `AgentProviderInput.timeout` is omitted, folded with the caller's signal so
3057
+ * whichever trips first cancels the call.
3058
+ */
3059
+ export declare const DEFAULT_PROVIDER_TIMEOUT = 120000;
3060
+
3061
+ /**
3062
+ * Holds the default relay request limit in bytes — `1_048_576`, the byte budget a relay applies
3063
+ * to an inbound body when `RelayOptions.limit` is omitted, refusing a body that reaches it.
3064
+ */
3065
+ export declare const DEFAULT_RELAY_LIMIT = 1048576;
3066
+
2829
3067
  /**
2830
3068
  * Synthesizes the denial {@link ToolResult} an authority-blocked call is fed back with — the
2831
3069
  * call's `id` / `name` keyed back, carrying a denial `error` instead of a value.
@@ -3223,6 +3461,13 @@ export declare interface InstructionManagerOptions {
3223
3461
  */
3224
3462
  export declare function intersectKeys(parent: readonly string[] | undefined, child: readonly string[] | undefined): readonly string[] | undefined;
3225
3463
 
3464
+ /**
3465
+ * Names the status a relay answers for a body that is missing, unreadable, or rejected by
3466
+ * `providerRequestContract` — `400`, carried with no body and reaching the browser as a
3467
+ * `ProviderError` with the `HTTP` code.
3468
+ */
3469
+ export declare const INVALID_RELAY_STATUS = 400;
3470
+
3226
3471
  /**
3227
3472
  * Narrows an unknown caught value to an {@link AgentError} through `instanceof`, so a `catch`
3228
3473
  * can branch on its `code`.
@@ -3312,34 +3557,20 @@ export declare function isConversationError(value: unknown): value is Conversati
3312
3557
  export declare function isConversationSnapshot(value: unknown): value is ConversationSnapshot;
3313
3558
 
3314
3559
  /**
3315
- * Checks whether an `unknown` is structurally a {@link Message} record — the per-message step of
3316
- * the {@link isConversationSnapshot} and {@link isSection} read-boundary narrows, where a present
3317
- * `calls` must be an array of valid {@link import('@orkestrel/tool').ToolCall}s. Total, never
3318
- * throwing, and never an assertion; the conversation analogue of
3319
- * {@link import('@orkestrel/workspace').isFile}.
3560
+ * Checks whether a value satisfies the domain conversation-message contract.
3320
3561
  *
3321
3562
  * @remarks
3322
- * A total guard (it never throws — adversarial input returns `false`). It checks the message's
3323
- * shape: a record with a `string` `id`, a `string` `role`, a `string` `content`, and — when present
3324
- * — a `calls` array every element of which is a valid
3325
- * {@link import('@orkestrel/tool').ToolCall} ({@link isToolCall} — the
3326
- * fail-closed deepening: a tampered `calls` element rejects the message, so the snapshot
3327
- * reads back as absent rather than replaying a malformed call) and an `images` that is an array
3328
- * (an absent optional passes). The `role` is left as a broad `string` here (an open
3329
- * {@link import('./types.js').MessageRole}, so any storage-read role string is accepted
3330
- * defensively rather than rejected against the current literal set). Enough to safely impose the
3331
- * {@link Message} type at
3332
- * a storage boundary without a cast.
3333
- *
3334
- * @param value - The value to test (one element of a snapshot's `messages` / a section's `messages`)
3335
- * @returns True if `value` has the structural shape of a {@link Message}; false otherwise
3563
+ * Roles belong to MessageRole and image elements are strings. Tool arguments may
3564
+ * carry non-JSON values, as the domain type permits; the message wire contract is
3565
+ * narrower. Unreadable fields and hostile inputs return false.
3336
3566
  *
3567
+ * @param value - The unknown message candidate
3568
+ * @returns True if the domain message fields are valid; false otherwise
3337
3569
  * @example
3338
3570
  * ```ts
3339
3571
  * isMessage({ id: '1', role: 'user', content: 'hi' }) // true
3340
- * isMessage({ id: '1', role: 'assistant', content: '', calls: [] }) // true
3341
- * isMessage({ id: '1', role: 'user' }) // false (missing content)
3342
- * isMessage({ id: '1', role: 'assistant', content: '', calls: [null] }) // false (malformed call)
3572
+ * isMessage({ id: '1', role: 'other', content: '' }) // false
3573
+ * isMessage({ id: '1', role: 'user', content: '', images: [1] }) // false
3343
3574
  * ```
3344
3575
  */
3345
3576
  export declare function isMessage(value: unknown): value is Message;
@@ -3362,6 +3593,18 @@ export declare function isMessage(value: unknown): value is Message;
3362
3593
  */
3363
3594
  export declare function isProviderAbortError(value: unknown): value is ProviderAbortError;
3364
3595
 
3596
+ /**
3597
+ * Narrows a caught value to the provider failure class through instanceof.
3598
+ *
3599
+ * @param value - The caught value
3600
+ * @returns True if the value is a provider failure; false otherwise
3601
+ * @example
3602
+ * ```ts
3603
+ * isProviderError(new ProviderError('HTTP', 'unavailable', { status: 503 })) // true
3604
+ * ```
3605
+ */
3606
+ export declare function isProviderError(value: unknown): value is ProviderError;
3607
+
3365
3608
  /**
3366
3609
  * Checks whether an `unknown` is structurally a {@link Section} record — a `string` `id` and
3367
3610
  * `summary` beside a `messages` array of valid {@link Message}s, the per-section step of the
@@ -3403,11 +3646,19 @@ export declare function isSection(value: unknown): value is Section;
3403
3646
  * @example
3404
3647
  * ```ts
3405
3648
  * joinThinking(undefined, 'first') // 'first'
3649
+ * joinThinking('', 'x') // 'x'
3406
3650
  * joinThinking('first', 'second') // 'first\n\nsecond'
3407
3651
  * ```
3408
3652
  */
3409
3653
  export declare function joinThinking(running: string | undefined, next: string): string;
3410
3654
 
3655
+ /**
3656
+ * Bounds the decoded error excerpt's input in bytes — `2048`, the leading bytes of a non-OK
3657
+ * response body handed to the decoder before the read cancels the remainder, so a `ProviderError`
3658
+ * message never carries a longer excerpt.
3659
+ */
3660
+ export declare const MAX_ERROR_BODY_LENGTH = 2048;
3661
+
3411
3662
  /**
3412
3663
  * Implements the {@link ConversationStoreInterface} in memory — a process-lifetime `Map` of
3413
3664
  * {@link ConversationSnapshot}s keyed by conversation id, the default store
@@ -3506,6 +3757,22 @@ export declare interface Message {
3506
3757
  */
3507
3758
  export declare const MESSAGE_TOKEN_OVERHEAD = 4;
3508
3759
 
3760
+ /** Validates and projects conversation messages at a JSON wire boundary. */
3761
+ export declare const messageContract: ContractInterface<Readonly<{
3762
+ id: string;
3763
+ role: "system" | "user" | "assistant" | "tool";
3764
+ content: string;
3765
+ } & {
3766
+ calls?: readonly Readonly<{
3767
+ id: string;
3768
+ name: string;
3769
+ arguments: {
3770
+ readonly [k: string]: JSONValue;
3771
+ };
3772
+ } & {}>[];
3773
+ images?: readonly string[];
3774
+ }>>;
3775
+
3509
3776
  /**
3510
3777
  * Carries the minimal data needed to author a {@link Message} — the `id` is
3511
3778
  * assigned by the layer that stores it, so a caller supplies only role / content
@@ -3562,6 +3829,31 @@ export declare interface MessageManagerInterface {
3562
3829
  /** Names the role a {@link Message} plays in a conversation turn. */
3563
3830
  export declare type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
3564
3831
 
3832
+ /**
3833
+ * Describes a conversation message's JSON wire projection.
3834
+ *
3835
+ * @remarks
3836
+ * The wire is strictly narrower than Message: non-JSON call arguments are refused,
3837
+ * and execution context stays local. The guard refuses extra members; the parser drops them.
3838
+ */
3839
+ export declare const messageShape: ObjectShape< {
3840
+ id: StringShape;
3841
+ role: LiteralShape<readonly ["system", "user", "assistant", "tool"]>;
3842
+ content: StringShape;
3843
+ calls: OptionalShape<ArrayShape<ObjectShape< {
3844
+ id: StringShape;
3845
+ name: StringShape;
3846
+ arguments: ObjectShape<Record<never, never>, JSONShape>;
3847
+ }, boolean | ContractShape>>>;
3848
+ images: OptionalShape<ArrayShape<StringShape>>;
3849
+ }, boolean | ContractShape>;
3850
+
3851
+ /**
3852
+ * Names the status a relay answers for a request body at or above its byte budget — `413`,
3853
+ * carried with no body and answered for an aborted inbound read as well.
3854
+ */
3855
+ export declare const OVERSIZED_RELAY_STATUS = 413;
3856
+
3565
3857
  /**
3566
3858
  * Reports a provider stream cancelled mid-flight by its bound signal — thrown by a
3567
3859
  * {@link ProviderInterface}'s `stream`, carrying the {@link ProviderResult} assembled from
@@ -3571,13 +3863,15 @@ export declare type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
3571
3863
  * Lets a caller recover the partial content (and any tool calls / usage seen so far)
3572
3864
  * on cancellation: `catch` the throw, narrow with {@link isProviderAbortError}, and
3573
3865
  * read `partial`. `code` is the machine-readable condition (`'ABORT'` — the only one this
3574
- * error reports), so a `catch` branches on it rather than on the message string.
3866
+ * error reports), so a `catch` branches on it rather than on the message string. `cause`
3867
+ * holds the failure the cancel superseded when a throw raced the abort — the wire decoder's
3868
+ * {@link ProviderError}, say — and is undefined when the cancel was the only failure.
3575
3869
  */
3576
3870
  export declare class ProviderAbortError extends Error {
3577
3871
  /** Names the machine-readable condition — `'ABORT'`: a stream cancelled mid-flight. */
3578
3872
  readonly code: "ABORT";
3579
3873
  readonly partial: ProviderResult;
3580
- constructor(partial: ProviderResult);
3874
+ constructor(partial: ProviderResult, options?: ErrorOptions);
3581
3875
  }
3582
3876
 
3583
3877
  /**
@@ -3603,6 +3897,47 @@ export declare type ProviderDelta = {
3603
3897
  readonly text: string;
3604
3898
  };
3605
3899
 
3900
+ /**
3901
+ * Reports a coded provider failure with its HTTP status and underlying cause when available.
3902
+ *
3903
+ * @remarks
3904
+ * The provider base throws this error for a non-OK HTTP response, a missing response
3905
+ * body, or a missing settled result when strict assembly is enabled. Concrete wire
3906
+ * decoders also use it for malformed records and relayed provider failures.
3907
+ * `status` is present only for an `HTTP` failure; other codes leave it undefined.
3908
+ */
3909
+ export declare class ProviderError extends Error {
3910
+ /** Names the machine-readable condition — `'HTTP'`: a non-OK response, including a relay refusing an oversized request with 413; `'PROTOCOL'`: a missing response body, a malformed wire record, or a strict stream with no settled result; `'PROVIDER'`: an upstream failure carried by a relay error record. */
3911
+ readonly code: ProviderErrorCode;
3912
+ /** Holds the response status for an HTTP failure, or undefined for other codes. */
3913
+ readonly status: number | undefined;
3914
+ constructor(code: ProviderErrorCode, message: string, options?: ProviderErrorOptions);
3915
+ }
3916
+
3917
+ /** Names the machine-readable provider failure conditions. */
3918
+ export declare type ProviderErrorCode =
3919
+ /** Reports a non-OK HTTP response, including a relay request rejected with status 413. */
3920
+ 'HTTP'
3921
+ /** Reports a missing body, malformed wire record, or missing required settled result. */
3922
+ | 'PROTOCOL'
3923
+ /** Reports an upstream provider failure carried by a relay error record. */
3924
+ | 'PROVIDER';
3925
+
3926
+ /** Carries a provider failure's HTTP status and underlying cause. */
3927
+ export declare interface ProviderErrorOptions {
3928
+ readonly status?: number;
3929
+ readonly cause?: unknown;
3930
+ }
3931
+
3932
+ /** Holds the decoded contribution of a wire record to a provider turn. */
3933
+ export declare interface ProviderIncrement {
3934
+ readonly content: string;
3935
+ readonly thinking: string;
3936
+ readonly tools: readonly ToolCall[];
3937
+ readonly usage?: TokenUsage;
3938
+ readonly result?: ProviderResult;
3939
+ }
3940
+
3606
3941
  /**
3607
3942
  * Defines the pluggable LLM inference boundary — the one contract every agent chunk depends on. A
3608
3943
  * provider turns a conversation (plus optional tools) into either a single assembled {@link
@@ -3659,6 +3994,102 @@ export declare interface ProviderInterface {
3659
3994
  stream(messages: readonly Message[], signal: AbortSignal, tools?: readonly ToolDefinition[], options?: ProviderStreamOptions): AsyncGenerator<ProviderDelta, ProviderResult>;
3660
3995
  }
3661
3996
 
3997
+ /**
3998
+ * Configures a provider's deadline, transport, headers, and context framing.
3999
+ *
4000
+ * @remarks
4001
+ * `timeout` is an integer duration in milliseconds. Default: 120_000.
4002
+ * `fetch` defaults to the global transport bound to its global receiver.
4003
+ * `headers` runs for each request inside its deadline and receives the combined caller
4004
+ * and deadline signal so token requests can share that bound. It overrides the JSON
4005
+ * content type only when it returns that header. `format` is exposed to context assembly.
4006
+ */
4007
+ export declare interface ProviderOptions {
4008
+ readonly timeout?: number;
4009
+ readonly fetch?: typeof globalThis.fetch;
4010
+ readonly headers?: (signal: AbortSignal) => Readonly<Record<string, string>> | Promise<Readonly<Record<string, string>>>;
4011
+ readonly format?: ContextFormat;
4012
+ }
4013
+
4014
+ /** Defines the structural framing seam supplied by a concrete provider. */
4015
+ export declare interface ProviderParserInterface<TRecord = Readonly<Record<string, unknown>>> {
4016
+ /** Parses a decoded chunk into complete records. */
4017
+ parse(chunk: string): readonly TRecord[];
4018
+ /** Clears retained framing state. */
4019
+ clear(): void;
4020
+ }
4021
+
4022
+ /** Carries the conversation and per-call configuration sent to a provider. */
4023
+ export declare interface ProviderRequest {
4024
+ readonly messages: readonly Message[];
4025
+ readonly tools?: readonly ToolDefinition[];
4026
+ readonly options?: ProviderStreamOptions;
4027
+ }
4028
+
4029
+ /** Validates and projects provider requests at a JSON wire boundary. */
4030
+ export declare const providerRequestContract: ContractInterface<Readonly<{
4031
+ messages: readonly Readonly<{
4032
+ id: string;
4033
+ role: "system" | "user" | "assistant" | "tool";
4034
+ content: string;
4035
+ } & {
4036
+ calls?: readonly Readonly<{
4037
+ id: string;
4038
+ name: string;
4039
+ arguments: {
4040
+ readonly [k: string]: JSONValue;
4041
+ };
4042
+ } & {}>[];
4043
+ images?: readonly string[];
4044
+ }>[];
4045
+ } & {
4046
+ tools?: readonly Readonly<{
4047
+ name: string;
4048
+ } & {
4049
+ description?: string;
4050
+ parameters?: {
4051
+ readonly [k: string]: JSONValue;
4052
+ };
4053
+ }>[];
4054
+ options?: Readonly<{} & {
4055
+ think?: boolean;
4056
+ schema?: {
4057
+ readonly [k: string]: JSONValue;
4058
+ };
4059
+ }>;
4060
+ }>>;
4061
+
4062
+ /**
4063
+ * Describes a provider request's JSON wire projection.
4064
+ *
4065
+ * @remarks
4066
+ * The wire is strictly narrower than ProviderRequest: non-JSON arguments, parameters,
4067
+ * or schema members are refused. Execution context stays local; the guard refuses
4068
+ * extra members, and the parser drops them.
4069
+ */
4070
+ export declare const providerRequestShape: ObjectShape< {
4071
+ messages: ArrayShape<ObjectShape< {
4072
+ id: StringShape;
4073
+ role: LiteralShape<readonly ["system", "user", "assistant", "tool"]>;
4074
+ content: StringShape;
4075
+ calls: OptionalShape<ArrayShape<ObjectShape< {
4076
+ id: StringShape;
4077
+ name: StringShape;
4078
+ arguments: ObjectShape<Record<never, never>, JSONShape>;
4079
+ }, boolean | ContractShape>>>;
4080
+ images: OptionalShape<ArrayShape<StringShape>>;
4081
+ }, boolean | ContractShape>>;
4082
+ tools: OptionalShape<ArrayShape<ObjectShape< {
4083
+ name: StringShape;
4084
+ description: OptionalShape<StringShape>;
4085
+ parameters: OptionalShape<ObjectShape<Record<never, never>, JSONShape>>;
4086
+ }, boolean | ContractShape>>>;
4087
+ options: OptionalShape<ObjectShape< {
4088
+ think: OptionalShape<BooleanShape>;
4089
+ schema: OptionalShape<ObjectShape<Record<never, never>, JSONShape>>;
4090
+ }, boolean | ContractShape>>;
4091
+ }, boolean | ContractShape>;
4092
+
3662
4093
  /**
3663
4094
  * Holds a single inference turn's structured outcome — the assembled assistant content,
3664
4095
  * any reasoning the provider separated from it, any tool calls the model requested,
@@ -3684,6 +4115,47 @@ export declare interface ProviderResult {
3684
4115
  readonly usage?: TokenUsage;
3685
4116
  }
3686
4117
 
4118
+ /** Validates and projects provider results at a JSON wire boundary. */
4119
+ export declare const providerResultContract: ContractInterface<Readonly<{
4120
+ content: string;
4121
+ } & {
4122
+ thinking?: string;
4123
+ tools?: readonly Readonly<{
4124
+ id: string;
4125
+ name: string;
4126
+ arguments: {
4127
+ readonly [k: string]: JSONValue;
4128
+ };
4129
+ } & {}>[];
4130
+ usage?: Readonly<{
4131
+ prompt: number;
4132
+ completion: number;
4133
+ total: number;
4134
+ } & {}>;
4135
+ }>>;
4136
+
4137
+ /**
4138
+ * Describes a provider result's JSON wire projection.
4139
+ *
4140
+ * @remarks
4141
+ * The wire is strictly narrower than ProviderResult: non-JSON call arguments are
4142
+ * refused. Execution context stays local; the guard refuses extra members, and the parser drops them.
4143
+ */
4144
+ export declare const providerResultShape: ObjectShape< {
4145
+ content: StringShape;
4146
+ thinking: OptionalShape<StringShape>;
4147
+ tools: OptionalShape<ArrayShape<ObjectShape< {
4148
+ id: StringShape;
4149
+ name: StringShape;
4150
+ arguments: ObjectShape<Record<never, never>, JSONShape>;
4151
+ }, boolean | ContractShape>>>;
4152
+ usage: OptionalShape<ObjectShape< {
4153
+ prompt: NumberShape;
4154
+ completion: NumberShape;
4155
+ total: NumberShape;
4156
+ }, boolean | ContractShape>>;
4157
+ }, boolean | ContractShape>;
4158
+
3687
4159
  /**
3688
4160
  * Carries the per-call options threaded into a {@link ProviderInterface}'s `generate` / `stream` —
3689
4161
  * the bag a caller passes to influence one inference call without reconfiguring the provider
@@ -3707,6 +4179,301 @@ export declare interface ProviderStreamOptions {
3707
4179
  readonly schema?: Readonly<Record<string, unknown>>;
3708
4180
  }
3709
4181
 
4182
+ /**
4183
+ * Decodes UTF-8 chunks with a final flush and releases the stream on every exit.
4184
+ *
4185
+ * @param body - The readable byte stream
4186
+ * @param signal - The optional cancellation bound; abort ends iteration without further chunks
4187
+ * @returns Decoded text chunks, including a held decoder tail
4188
+ * @example
4189
+ * ```ts
4190
+ * const body = new Response('answer').body
4191
+ * if (body !== null) for await (const chunk of readChunks(body)) render(chunk)
4192
+ * ```
4193
+ */
4194
+ export declare function readChunks(body: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<string>;
4195
+
4196
+ /**
4197
+ * Reads a UTF-8 prefix of a byte stream and cancels its remainder.
4198
+ *
4199
+ * @remarks
4200
+ * The `limit` parameter bounds bytes passed to the decoder, including a partial final
4201
+ * character. An omitted limit reads to completion. A source may deliver a chunk larger
4202
+ * than the remaining limit; its unused bytes are discarded without decoding.
4203
+ * The read can overshoot by one source chunk. An abort leaves completion false.
4204
+ *
4205
+ * @param body - The readable byte stream
4206
+ * @param limit - The maximum byte prefix, or undefined for the complete stream
4207
+ * @param signal - The optional cancellation bound; abort returns the decoded prefix
4208
+ * @returns The decoded prefix and whether EOF occurred within the byte budget
4209
+ * @example
4210
+ * ```ts
4211
+ * import { readText } from '@orkestrel/agent'
4212
+ *
4213
+ * const body = new Response('answer').body
4214
+ * if (body !== null) await readText(body, 3) // { text: 'ans', complete: false }
4215
+ * ```
4216
+ */
4217
+ export declare function readText(body: ReadableStream<Uint8Array>, limit?: number, signal?: AbortSignal): Promise<TextRead>;
4218
+
4219
+ /**
4220
+ * Names the relay's newline-delimited JSON content type — `'application/x-ndjson; charset=utf-8'`,
4221
+ * the header a relay response carries beside `cache-control: no-store`.
4222
+ */
4223
+ export declare const RELAY_CONTENT_TYPE = "application/x-ndjson; charset=utf-8";
4224
+
4225
+ /**
4226
+ * Names the public message for an unexpected upstream relay failure — `'relay provider failed'`,
4227
+ * the fixed text every `error` frame carries, so an upstream failure's own message never reaches
4228
+ * the browser.
4229
+ */
4230
+ export declare const RELAY_PROVIDER_MESSAGE = "relay provider failed";
4231
+
4232
+ /** Carries a relay delta, settled result, remote abort, or remote failure. */
4233
+ export declare type RelayFrame = ProviderDelta | {
4234
+ readonly channel: 'result';
4235
+ readonly result: ProviderResult;
4236
+ } | {
4237
+ readonly channel: 'abort';
4238
+ readonly partial: ProviderResult;
4239
+ } | {
4240
+ readonly channel: 'error';
4241
+ readonly message: string;
4242
+ };
4243
+
4244
+ /** Validates and projects channel-discriminated relay frames at a JSON wire boundary. */
4245
+ export declare const relayFrameContract: ContractInterface<Readonly<{
4246
+ channel: "content" | "thinking";
4247
+ text: string;
4248
+ } & {}> | Readonly<{
4249
+ channel: "result";
4250
+ result: Readonly<{
4251
+ content: string;
4252
+ } & {
4253
+ thinking?: string;
4254
+ tools?: readonly Readonly<{
4255
+ id: string;
4256
+ name: string;
4257
+ arguments: {
4258
+ readonly [k: string]: JSONValue;
4259
+ };
4260
+ } & {}>[];
4261
+ usage?: Readonly<{
4262
+ prompt: number;
4263
+ completion: number;
4264
+ total: number;
4265
+ } & {}>;
4266
+ }>;
4267
+ } & {}> | Readonly<{
4268
+ channel: "abort";
4269
+ partial: Readonly<{
4270
+ content: string;
4271
+ } & {
4272
+ thinking?: string;
4273
+ tools?: readonly Readonly<{
4274
+ id: string;
4275
+ name: string;
4276
+ arguments: {
4277
+ readonly [k: string]: JSONValue;
4278
+ };
4279
+ } & {}>[];
4280
+ usage?: Readonly<{
4281
+ prompt: number;
4282
+ completion: number;
4283
+ total: number;
4284
+ } & {}>;
4285
+ }>;
4286
+ } & {}> | Readonly<{
4287
+ channel: "error";
4288
+ message: string;
4289
+ } & {}>>;
4290
+
4291
+ /**
4292
+ * Describes the channel-discriminated JSON relay wire projection.
4293
+ *
4294
+ * @remarks
4295
+ * The wire is strictly narrower than RelayFrame through its result and partial
4296
+ * fields: non-JSON arguments are refused. Execution context stays local; the guard
4297
+ * refuses extra members, and the parser drops them.
4298
+ */
4299
+ export declare const relayFrameShape: UnionShape<readonly [ObjectShape< {
4300
+ channel: LiteralShape<readonly ["content", "thinking"]>;
4301
+ text: StringShape;
4302
+ }, boolean | ContractShape>, ObjectShape< {
4303
+ channel: LiteralShape<readonly ["result"]>;
4304
+ result: ObjectShape< {
4305
+ content: StringShape;
4306
+ thinking: OptionalShape<StringShape>;
4307
+ tools: OptionalShape<ArrayShape<ObjectShape< {
4308
+ id: StringShape;
4309
+ name: StringShape;
4310
+ arguments: ObjectShape<Record<never, never>, JSONShape>;
4311
+ }, boolean | ContractShape>>>;
4312
+ usage: OptionalShape<ObjectShape< {
4313
+ prompt: NumberShape;
4314
+ completion: NumberShape;
4315
+ total: NumberShape;
4316
+ }, boolean | ContractShape>>;
4317
+ }, boolean | ContractShape>;
4318
+ }, boolean | ContractShape>, ObjectShape< {
4319
+ channel: LiteralShape<readonly ["abort"]>;
4320
+ partial: ObjectShape< {
4321
+ content: StringShape;
4322
+ thinking: OptionalShape<StringShape>;
4323
+ tools: OptionalShape<ArrayShape<ObjectShape< {
4324
+ id: StringShape;
4325
+ name: StringShape;
4326
+ arguments: ObjectShape<Record<never, never>, JSONShape>;
4327
+ }, boolean | ContractShape>>>;
4328
+ usage: OptionalShape<ObjectShape< {
4329
+ prompt: NumberShape;
4330
+ completion: NumberShape;
4331
+ total: NumberShape;
4332
+ }, boolean | ContractShape>>;
4333
+ }, boolean | ContractShape>;
4334
+ }, boolean | ContractShape>, ObjectShape< {
4335
+ channel: LiteralShape<readonly ["error"]>;
4336
+ message: StringShape;
4337
+ }, boolean | ContractShape>]>;
4338
+
4339
+ /** Defines a host-independent relay request handler. */
4340
+ export declare type RelayHandler = (request: Request) => Promise<Response>;
4341
+
4342
+ /** Configures the upstream provider, mandatory authorization, and request byte limit. */
4343
+ export declare interface RelayOptions {
4344
+ readonly provider: ProviderInterface;
4345
+ /**
4346
+ * Authorizes the request before its body is read.
4347
+ *
4348
+ * @remarks
4349
+ * The hook must not consume the request body; a body-reading hook locks the stream
4350
+ * and the handler answers with the `400` status. The relay performs no origin or
4351
+ * method check. An application trusting an ambient credential such as a cookie
4352
+ * must compose origin and CSRF middleware before the handler to prevent cross-site calls.
4353
+ */
4354
+ readonly authorize: (request: Request) => boolean | Promise<boolean>;
4355
+ /**
4356
+ * Bounds the request body in bytes; the handler answers with the `413` status
4357
+ * for a body at or above the limit.
4358
+ */
4359
+ readonly limit?: number;
4360
+ }
4361
+
4362
+ /**
4363
+ * Carries provider calls over an authenticated NDJSON relay endpoint.
4364
+ *
4365
+ * @remarks
4366
+ * Tool execution context stays local; calls carry only `id`, `name`, and `arguments`.
4367
+ * The wire body is an owned snapshot of
4368
+ * the projection read through property descriptors, so a serializer reachable only through a
4369
+ * `get` trap or a prototype is never consulted; an own function-valued property such as a
4370
+ * `toJSON` method is a value outside JSON and is refused before fetching, with the clone's
4371
+ * failure as the refusal's `cause`. A remote abort reconstructs a `ProviderAbortError` instance
4372
+ * without aborting the
4373
+ * local signal; the `Agent` runtime treats that instance as an error unless its own bound
4374
+ * signal is aborted.
4375
+ * Content is preserved verbatim, including literal thinking tags.
4376
+ * A refusal reaches the browser as a `ProviderError` instance with the `HTTP` code and status.
4377
+ * This is the browser end alone; {@link createRelay} mounts the server end, and
4378
+ * {@link createRelayProvider}'s example is the browser half of that pair.
4379
+ *
4380
+ * @example
4381
+ * ```ts
4382
+ * import type { ProviderResult } from '@orkestrel/agent'
4383
+ * import { RelayProvider } from '@orkestrel/agent'
4384
+ * // The browser application supplies this parser dependency.
4385
+ * import { createNDJSONParser } from '@orkestrel/ndjson'
4386
+ *
4387
+ * export function ask(bearer: string, signal: AbortSignal): Promise<ProviderResult> {
4388
+ * const browser = new RelayProvider({
4389
+ * url: 'https://relay.example/relay',
4390
+ * parser: createNDJSONParser,
4391
+ * headers: () => ({ authorization: `Bearer ${bearer}` }),
4392
+ * })
4393
+ * return browser.generate([{ id: 'ask', role: 'user', content: 'ping' }], signal)
4394
+ * }
4395
+ * ```
4396
+ */
4397
+ export declare class RelayProvider extends AgentProvider {
4398
+ #private;
4399
+ constructor(options: RelayProviderOptions);
4400
+ /** Identifies the relay backend. */
4401
+ readonly name = "relay";
4402
+ /** Creates fresh framing state for each response. */
4403
+ frame(): ProviderParserInterface;
4404
+ /**
4405
+ * Projects declared request fields and refuses values the JSON wire cannot carry.
4406
+ *
4407
+ * @remarks
4408
+ * The snapshot is taken from property descriptors, so a custom serializer a projected
4409
+ * value carries is ignored rather than consulted and cannot reach the wire.
4410
+ *
4411
+ * @param request - The domain conversation and call configuration
4412
+ * @returns The validated wire request
4413
+ * @throws {ProviderError} Thrown when the snapshot cannot be taken — a hostile read or a
4414
+ * value outside JSON — carrying that failure as its `cause`, and when the snapshot the
4415
+ * projection produced is not a valid wire request
4416
+ */
4417
+ body(request: ProviderRequest): object;
4418
+ /**
4419
+ * Validates a relay frame and translates its channel into the shared stream engine.
4420
+ *
4421
+ * @param record - The framed wire record
4422
+ * @returns A delta contribution or authoritative result
4423
+ * @throws {ProviderAbortError} Thrown for a remote abort carrying its partial
4424
+ * @throws {ProviderError} Thrown for a malformed frame or remote provider failure
4425
+ */
4426
+ read(record: Readonly<Record<string, unknown>>): ProviderIncrement;
4427
+ /**
4428
+ * Recovers an unterminated final frame by completing its NDJSON line.
4429
+ *
4430
+ * @param parser - The call's retained framing state
4431
+ * @returns Records completed by the final newline
4432
+ */
4433
+ finish(parser: ProviderParserInterface): ReadonlyArray<Readonly<Record<string, unknown>>>;
4434
+ }
4435
+
4436
+ /** Configures a relay destination and its fresh structural parser factory. */
4437
+ export declare interface RelayProviderOptions extends ProviderOptions {
4438
+ readonly url: string;
4439
+ /** Creates a fresh parser for each relay response stream. */
4440
+ readonly parser: () => ProviderParserInterface;
4441
+ }
4442
+
4443
+ /**
4444
+ * Streams a provider call as validated NDJSON frames under response backpressure.
4445
+ *
4446
+ * @remarks
4447
+ * Cancellation aborts upstream before returning its iterator. Request listeners are
4448
+ * released on settlement. Unexpected provider failures carry a fixed public message.
4449
+ * An inbound abort leaves the response body neither closed nor errored — a server runtime
4450
+ * cancels that body when the client disconnects — so a consumer that aborts the inbound
4451
+ * signal itself must cancel the body rather than keep reading it.
4452
+ *
4453
+ * @example
4454
+ * ```ts
4455
+ * import type { ProviderInterface } from '@orkestrel/agent'
4456
+ * import { RelayStream } from '@orkestrel/agent'
4457
+ *
4458
+ * export function respond(provider: ProviderInterface, signal: AbortSignal): Response {
4459
+ * return new RelayStream({ provider, request: { messages: [] }, signal }).response
4460
+ * }
4461
+ * ```
4462
+ */
4463
+ export declare class RelayStream {
4464
+ #private;
4465
+ constructor(options: RelayStreamOptions);
4466
+ /** Exposes the pull-driven response for the provider call. */
4467
+ get response(): Response;
4468
+ }
4469
+
4470
+ /** Carries the upstream call and cancellation bound of a relay response stream. */
4471
+ export declare interface RelayStreamOptions {
4472
+ readonly provider: ProviderInterface;
4473
+ readonly request: ProviderRequest;
4474
+ readonly signal: AbortSignal;
4475
+ }
4476
+
3710
4477
  /**
3711
4478
  * Renders a path-addressed text body as a fenced reference block — a `File: <path>` label line
3712
4479
  * over a language-tagged fence, the framing an
@@ -4182,6 +4949,16 @@ export declare interface StreamInterface<T, R> {
4182
4949
  */
4183
4950
  export declare function sumUsage(running: TokenUsage | undefined, next: TokenUsage): TokenUsage;
4184
4951
 
4952
+ /** Carries a decoded stream prefix and whether the stream ended within its byte budget. */
4953
+ export declare interface TextRead {
4954
+ readonly text: string;
4955
+ /**
4956
+ * Reports true only when a read observes the `done` flag before exhausting the
4957
+ * byte budget; an abort reports false.
4958
+ */
4959
+ readonly complete: boolean;
4960
+ }
4961
+
4185
4962
  /**
4186
4963
  * Names the closing tag that ends a {@link THINK_OPEN} reasoning span — `'</think>'`. A span the
4187
4964
  * stream never closes (the model was cut off mid-reasoning) is treated as thinking to its end,
@@ -4294,6 +5071,33 @@ export declare interface ThinkSplitterInterface {
4294
5071
  flush(): string;
4295
5072
  }
4296
5073
 
5074
+ /**
5075
+ * Describes a tool call's JSON wire projection.
5076
+ *
5077
+ * @remarks
5078
+ * The wire is strictly narrower than the domain: non-JSON arguments are refused.
5079
+ * Calls carry only id, name, and arguments; execution context stays local.
5080
+ * The guard refuses every extra member; the contract parser drops extra members.
5081
+ */
5082
+ export declare const toolCallShape: ObjectShape< {
5083
+ id: StringShape;
5084
+ name: StringShape;
5085
+ arguments: ObjectShape<Record<never, never>, JSONShape>;
5086
+ }, boolean | ContractShape>;
5087
+
5088
+ /**
5089
+ * Names the status a relay answers when the `authorize` callback returns anything but `true` or throws —
5090
+ * `401`, carried with no body and reaching the browser as a `ProviderError` with the `HTTP` code.
5091
+ */
5092
+ export declare const UNAUTHORIZED_RELAY_STATUS = 401;
5093
+
5094
+ /**
5095
+ * Names the status a relay answers when the upstream provider call cannot be constructed — `502`,
5096
+ * carried with no body after `provider.stream` was entered and threw before returning its
5097
+ * iterator.
5098
+ */
5099
+ export declare const UPSTREAM_RELAY_STATUS = 502;
5100
+
4297
5101
  /**
4298
5102
  * Names the section header {@link import('./AgentContext.js').AgentContext}'s `build()` renders the
4299
5103
  * active workspace's text files under — `'## Workspace'`, the leading line of the dedicated