@combycode/llm-sdk 3.2.1 → 3.3.0

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 (40) hide show
  1. package/CHANGELOG.md +188 -0
  2. package/dist/catalog/catalog.d.ts +12 -0
  3. package/dist/index.browser.js +3908 -1287
  4. package/dist/index.js +3908 -1287
  5. package/dist/llm/client-internal.d.ts +3 -1
  6. package/dist/llm/client.d.ts +10 -0
  7. package/dist/llm/providers/anthropic/messages.d.ts +32 -7
  8. package/dist/llm/providers/anthropic/response-registry.d.ts +2 -0
  9. package/dist/llm/providers/anthropic/stream-registry.d.ts +2 -0
  10. package/dist/llm/providers/google/generate.d.ts +7 -8
  11. package/dist/llm/providers/google/interactions-registry.d.ts +2 -0
  12. package/dist/llm/providers/google/interactions-stream-registry.d.ts +2 -0
  13. package/dist/llm/providers/google/interactions.d.ts +7 -5
  14. package/dist/llm/providers/google/response-registry.d.ts +2 -0
  15. package/dist/llm/providers/google/stream-registry.d.ts +2 -0
  16. package/dist/llm/providers/openai/completions.d.ts +21 -3
  17. package/dist/llm/providers/openai/response-registry.d.ts +2 -0
  18. package/dist/llm/providers/openai/responses-registry.d.ts +2 -0
  19. package/dist/llm/providers/openai/responses-stream-registry.d.ts +2 -0
  20. package/dist/llm/providers/openai/responses.d.ts +31 -3
  21. package/dist/llm/providers/openai/stream-registry.d.ts +2 -0
  22. package/dist/llm/providers/openrouter/completions.d.ts +11 -7
  23. package/dist/llm/providers/openrouter/response-registry.d.ts +2 -0
  24. package/dist/llm/providers/openrouter/stream-registry.d.ts +2 -0
  25. package/dist/llm/providers/response-registries.d.ts +5 -0
  26. package/dist/llm/providers/xai/completions.d.ts +1 -4
  27. package/dist/llm/providers/xai/responses-registry.d.ts +2 -0
  28. package/dist/llm/providers/xai/responses.d.ts +12 -0
  29. package/dist/llm/providers/xai/stream-registry.d.ts +2 -0
  30. package/dist/plugins/context-guard/facts.d.ts +9 -0
  31. package/dist/plugins/context-guard/tools.d.ts +3 -0
  32. package/dist/plugins/context-guard/types.d.ts +5 -0
  33. package/dist/util/audio-mime.d.ts +16 -0
  34. package/dist/util/compare.d.ts +13 -0
  35. package/dist/wire/interpreter.d.ts +2 -0
  36. package/dist/wire/response-interpreter.d.ts +156 -0
  37. package/dist/wire/response-specs.d.ts +7 -0
  38. package/dist/wire/stream-interpreter.d.ts +94 -0
  39. package/dist/wire/stream-specs.d.ts +8 -0
  40. package/package.json +4 -4
@@ -46,5 +46,7 @@ export interface ClientRouting {
46
46
  readonly cacheName: string;
47
47
  }
48
48
  export declare function buildContext(client: LLMClient, options: ExecuteOptions): RequestContext;
49
- export declare function resolveApi(provider: ProviderName, api?: ApiType | 'auto'): ApiType;
49
+ export declare function resolveApi(provider: ProviderName, api?: ApiType | 'auto',
50
+ /** The catalog's per-model preference, when the model is a known one. */
51
+ preferred?: ApiType | null): ApiType;
50
52
  export declare function resolveAdapter(config: LLMClientConfig, api: ApiType): ProviderAdapter;
@@ -88,6 +88,16 @@ export declare class LLMClient {
88
88
  /** Anything the spec left out on purpose reaches the caller as a warning.
89
89
  * Said once per request; the build already de-duplicates within one. */
90
90
  private reportBuildNotes;
91
+ /** Drop `thinking: { mode: 'off' }` where the model cannot honour it, and say
92
+ * so. Returns the note, or null when there was nothing to adjust.
93
+ *
94
+ * Dropped rather than sent: the wire spec turns `off` into a real field
95
+ * (`thinkingBudget: 0` on 2.5, `thinkingLevel: MINIMAL` on 3.x), and the
96
+ * models flagged here answer 400 to it. The caller gets a request that works
97
+ * plus a warning that their instruction could not be followed, instead of a
98
+ * failed call — or, worse, the silence this replaced, where `off` was
99
+ * accepted, nothing was emitted, and the model reasoned anyway. */
100
+ private limitThinking;
91
101
  complete(input: string | ContentPart[] | Message[], options?: ExecuteOptions): Promise<CompletionResponse>;
92
102
  /** Run `complete` with a JSON Schema enforced via `structured`. Strips any
93
103
  * leading/trailing markdown fences from the model reply, then JSON.parses
@@ -7,12 +7,37 @@ import type { SSEEvent } from '../../../network/types';
7
7
  import type { ContentPart } from '../../types/messages';
8
8
  import type { ProviderAdapter, ProviderHttpRequest } from '../../types/provider';
9
9
  import type { NormalizedRequest } from '../../types/request';
10
- import { type CompletionResponse } from '../../types/response';
10
+ import { type CompletionResponse, type FileOutput, type Usage } from '../../types/response';
11
11
  import type { StreamEvent } from '../../types/stream';
12
12
  export interface AnthropicAdapterConfig {
13
13
  apiKey: string;
14
14
  baseURL?: string;
15
15
  }
16
+ /** Billed tier (response usage.service_tier) → {raw, catalog key}. Identity:
17
+ * the catalog is keyed by Anthropic's own billed names (standard|priority|batch). */
18
+ export declare function anthropicBilledTier(raw: unknown): {
19
+ serviceTier?: string;
20
+ pricingTier?: string;
21
+ };
22
+ /** Extract hosted code-execution output files from one content block. Shared by
23
+ * the buffered (`parseResponse`) and streamed (`content_block_start`) paths so
24
+ * both surface the exact same `FileOutput[]`. The current tool
25
+ * (code_execution_20260521) emits `bash_code_execution_tool_result` →
26
+ * `bash_code_execution_result` → `content[]` of `bash_code_execution_output`;
27
+ * older tool versions emit the `code_execution_*` equivalents. Both carry
28
+ * `file_id`. (`text_editor_code_execution_tool_result` blocks are file
29
+ * create/view/edit markers with no downloadable id, so they are not surfaced.) */
30
+ export declare function filesFromCodeExecBlock(block: Record<string, unknown>): FileOutput[];
31
+ /** Builtin-tool payload from a `server_tool_use` input: the code (code execution)
32
+ * or the query (web search). Shared by the buffered + streamed paths. */
33
+ export declare function builtinInputPayload(tool: string, input: Record<string, unknown> | undefined): {
34
+ code?: string;
35
+ query?: string;
36
+ url?: string;
37
+ };
38
+ /** stdout from a code-execution `*_tool_result` block's content, if present. */
39
+ export declare function resultStdout(content: unknown): string | undefined;
40
+ export declare function anthropicUsage(u: Record<string, unknown> | undefined): Usage;
16
41
  export declare class AnthropicAdapter implements ProviderAdapter {
17
42
  readonly name: "anthropic";
18
43
  protected readonly apiKey: string;
@@ -42,12 +67,12 @@ export declare class AnthropicAdapter implements ProviderAdapter {
42
67
  }, _req: NormalizedRequest, forceCache?: boolean): Record<string, unknown>;
43
68
  private buildContentPart;
44
69
  parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
70
+ /** Stateless entry, as the ProviderAdapter interface requires: a fresh spec
71
+ * run per event, so nothing correlates across events. */
45
72
  parseStreamEvent(event: SSEEvent): StreamEvent[];
46
- /** Stateful Anthropic streams `server_tool_use` input via `input_json_delta`
47
- * (empty at block start) and returns the result in a separate `*_tool_result`
48
- * block. The closure accumulates each call's input (code / query) and attaches it
49
- * to the matching `builtin_tool_end`. */
73
+ /** Stateful, and the one callers should use. Anthropic streams a
74
+ * `server_tool_use` input via `input_json_delta` and returns the result in a
75
+ * separate `*_tool_result` block, so the input has to be carried between
76
+ * them; the spec's `state` is where that lives now. */
50
77
  createStreamParser(): (event: SSEEvent) => StreamEvent[];
51
- private streamEvents;
52
- private parseUsage;
53
78
  }
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const ANTHROPIC_RESPONSE_REGISTRY: Registry;
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const ANTHROPIC_STREAM_REGISTRY: Registry;
@@ -3,12 +3,15 @@ import type { SSEEvent } from '../../../network/types';
3
3
  import type { ContentPart } from '../../types/messages';
4
4
  import type { ProviderAdapter, ProviderHttpRequest } from '../../types/provider';
5
5
  import type { NormalizedRequest } from '../../types/request';
6
- import { type CompletionResponse } from '../../types/response';
6
+ import { type CompletionResponse, type Usage } from '../../types/response';
7
7
  import type { StreamEvent } from '../../types/stream';
8
8
  export interface GoogleAdapterConfig {
9
9
  apiKey: string;
10
10
  baseURL?: string;
11
11
  }
12
+ /** generateContent token usage. Exported so the spec-driven parser runs this
13
+ * and not a second copy of it. */
14
+ export declare function googleUsage(u: Record<string, unknown> | undefined): Usage;
12
15
  export declare class GoogleAdapter implements ProviderAdapter {
13
16
  readonly name: "google";
14
17
  private readonly apiKey;
@@ -36,13 +39,9 @@ export declare class GoogleAdapter implements ProviderAdapter {
36
39
  content: string | ContentPart[];
37
40
  }): Record<string, unknown>;
38
41
  parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
42
+ /** Stateless entry, as the ProviderAdapter interface requires: a fresh spec
43
+ * run per event, so nothing correlates across events. */
39
44
  parseStreamEvent(event: SSEEvent): StreamEvent[];
40
- /** Stateful Google splits the code-execution marker (`executableCode` /
41
- * `codeExecutionResult`) and the produced file (`inlineData`) across parts and
42
- * often across SSE events. The closure remembers "code execution began in this
43
- * stream" so a later `inlineData` blob is routed to `files` (a code-exec
44
- * artifact) rather than `media` (conversational output). */
45
+ /** Stateful, and the one callers should use. The code-execution flag latches across chunks and decides whether inlineData is an artifact or media. */
45
46
  createStreamParser(): (event: SSEEvent) => StreamEvent[];
46
- private streamEvents;
47
- private parseUsage;
48
47
  }
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const GOOGLE_INTERACTIONS_REGISTRY: Registry;
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const GOOGLE_INTERACTIONS_STREAM_REGISTRY: Registry;
@@ -6,12 +6,15 @@ import type { SSEEvent } from '../../../network/types';
6
6
  import type { Message } from '../../types/messages';
7
7
  import type { ProviderAdapter, ProviderHttpRequest } from '../../types/provider';
8
8
  import type { NormalizedRequest } from '../../types/request';
9
- import { type CompletionResponse } from '../../types/response';
9
+ import { type CompletionResponse, type Usage } from '../../types/response';
10
10
  import type { StreamEvent } from '../../types/stream';
11
11
  export interface GoogleInteractionsAdapterConfig {
12
12
  apiKey: string;
13
13
  baseURL?: string;
14
14
  }
15
+ /** Interactions token usage. Exported so the spec-driven parser runs this and
16
+ * not a second copy of it. */
17
+ export declare function googleInteractionsUsage(u: Record<string, unknown> | undefined): Usage;
15
18
  export declare class GoogleInteractionsAdapter implements ProviderAdapter {
16
19
  readonly name: "google";
17
20
  private readonly apiKey;
@@ -37,10 +40,9 @@ export declare class GoogleInteractionsAdapter implements ProviderAdapter {
37
40
  * `interaction.failed` finish the turn (usage under `interaction.usage`). A
38
41
  * function call's `arguments_delta` carries no id, so we correlate it to the
39
42
  * currently-open call id held in `state`. */
40
- private streamEvents;
43
+ /** Stateless entry, as the ProviderAdapter interface requires: a fresh spec
44
+ * run per event, so nothing correlates across events. */
41
45
  parseStreamEvent(event: SSEEvent): StreamEvent[];
42
- /** Per-stream stateful parser correlates a function call's streamed arguments
43
- * and end to the call opened by its `step.start`. */
46
+ /** Stateful, and the one callers should use. The open call's id is carried between its fragments and its close. */
44
47
  createStreamParser(): (event: SSEEvent) => StreamEvent[];
45
- private parseUsage;
46
48
  }
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const GOOGLE_RESPONSE_REGISTRY: Registry;
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const GOOGLE_STREAM_REGISTRY: Registry;
@@ -4,7 +4,7 @@ import type { Registry } from '../../../wire/interpreter';
4
4
  import type { ContentPart } from '../../types/messages';
5
5
  import type { ProviderAdapter, ProviderHttpRequest } from '../../types/provider';
6
6
  import type { NormalizedRequest } from '../../types/request';
7
- import { type CompletionResponse } from '../../types/response';
7
+ import { type CompletionResponse, type Usage } from '../../types/response';
8
8
  import type { StreamEvent } from '../../types/stream';
9
9
  export interface OpenAIAdapterConfig {
10
10
  apiKey: string;
@@ -15,7 +15,16 @@ export interface OpenAIAdapterConfig {
15
15
  * for backends that omit ids), stable across the stream's chunks. */
16
16
  export interface OpenAIStreamState {
17
17
  toolIdByIndex: Map<number, string>;
18
+ /** Open audio output: gpt-audio streams its reply as `delta.audio`, and the
19
+ * media_start/chunk/end trio has to be paired across events. */
20
+ audio?: {
21
+ open: boolean;
22
+ id?: string;
23
+ };
18
24
  }
25
+ /** Token usage, from either Chat Completions or Responses naming. Exported so
26
+ * the spec-driven parser calls the same code rather than a second copy. */
27
+ export declare function openaiUsage(u: Record<string, unknown> | undefined): Usage;
19
28
  export declare class OpenAIAdapter implements ProviderAdapter {
20
29
  readonly name: ProviderAdapter['name'];
21
30
  protected readonly apiKey: string;
@@ -46,10 +55,19 @@ export declare class OpenAIAdapter implements ProviderAdapter {
46
55
  }): Record<string, unknown>[];
47
56
  private buildMessage;
48
57
  enableStreaming(providerReq: ProviderHttpRequest, _req: NormalizedRequest): void;
58
+ /** The response spec this adapter parses with. Overridden by OpenRouter,
59
+ * which is Chat Completions plus one rule. */
60
+ protected responseSpecId(): string;
61
+ protected responseRegistry(): Registry;
49
62
  parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
50
- parseStreamEvent(event: SSEEvent, state?: OpenAIStreamState): StreamEvent[];
51
63
  /** Per-stream: correlates streamed tool-call fragments by index and synthesizes
52
64
  * a stable id for backends that omit tool-call ids (see `parseStreamEvent`). */
65
+ /** Stateless entry, as the ProviderAdapter interface requires: a fresh spec
66
+ * run per event, so nothing correlates across events. */
67
+ parseStreamEvent(event: SSEEvent): StreamEvent[];
68
+ /** Stateful, and the one callers should use. Tool-call fragments correlate by index because only the first carries an id. */
53
69
  createStreamParser(): (event: SSEEvent) => StreamEvent[];
54
- private parseUsage;
70
+ /** Overridden by OpenRouter, which appends its `:online` web-search pair. */
71
+ protected streamSpecId(): string;
72
+ protected streamRegistry(): Registry;
55
73
  }
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const OPENAI_RESPONSE_REGISTRY: Registry;
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const OPENAI_RESPONSES_REGISTRY: Registry;
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const OPENAI_RESPONSES_STREAM_REGISTRY: Registry;
@@ -3,16 +3,32 @@
3
3
  * Modern API: input (not messages), instructions (not system role),
4
4
  * output items (not choices), function_call/function_call_output for tools. */
5
5
  import type { SSEEvent } from '../../../network/types';
6
- import type { AssistantPhase, Message } from '../../types/messages';
6
+ import type { Message, ToolCaller } from '../../types/messages';
7
7
  import type { Registry } from '../../../wire/interpreter';
8
8
  import type { ProviderAdapter, ProviderHttpRequest } from '../../types/provider';
9
9
  import type { NormalizedRequest } from '../../types/request';
10
- import { type CompletionResponse, type FileOutput, type Usage } from '../../types/response';
10
+ import { type BuiltinToolCall, type CompletionResponse, type FileOutput, type Usage } from '../../types/response';
11
11
  import type { StreamEvent } from '../../types/stream';
12
12
  export interface OpenAIResponsesAdapterConfig {
13
13
  apiKey: string;
14
14
  baseURL?: string;
15
15
  }
16
+ export declare function fromWireCaller(raw: unknown): ToolCaller | undefined;
17
+ export declare function builtinCallFromResponsesItem(item: Record<string, unknown>): BuiltinToolCall | null;
18
+ /** Extract hosted code-execution output files from one Responses output item.
19
+ * Shared by the buffered (`parseResponse`) and streamed (`response.output_item.done`)
20
+ * paths so both surface the exact same `FileOutput[]`. Two sources:
21
+ * - `message` items → `container_file_citation` annotations (downloadable
22
+ * container files, fetched by file id from `/v1/containers/{cid}/files/{id}`);
23
+ * - `code_interpreter_call` items → image outputs returned by URL.
24
+ *
25
+ * Dedup: `plt.show()` makes OpenAI emit an auto-display container file ALONGSIDE the
26
+ * explicitly-saved one. When the same image was also saved, we drop the display
27
+ * duplicate (matches ChatGPT's own UI); a display-only run keeps its sole figure. */
28
+ export declare function filesFromResponsesOutputItem(item: Record<string, unknown>): FileOutput[];
29
+ /** Responses-API token usage. Exported so the spec-driven parser runs this and
30
+ * not a second copy of it. */
31
+ export declare function openaiResponsesUsage(u: Record<string, unknown> | undefined): Usage;
16
32
  export declare class OpenAIResponsesAdapter implements ProviderAdapter {
17
33
  readonly name: ProviderAdapter['name'];
18
34
  protected readonly apiKey: string;
@@ -33,11 +49,23 @@ export declare class OpenAIResponsesAdapter implements ProviderAdapter {
33
49
  /** Reached through the wire registry while building the request. */
34
50
  buildInputItems(msg: Message, toolNames?: Map<string, string>): unknown[];
35
51
  enableStreaming(providerReq: ProviderHttpRequest): void;
52
+ /** Overridden by xAI, whose Responses API is this one. */
53
+ protected responseSpecId(): string;
54
+ /** Overridden alongside the spec id: xAI extends file extraction, so its
55
+ * registry supplies a different `oaiRespFiles` -- the parse-side twin of its
56
+ * `filesFromOutputItem` override. */
57
+ protected responseRegistry(): Registry;
36
58
  parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
37
- parseStreamEvent(event: SSEEvent, phaseByItem?: Map<string, AssistantPhase>): StreamEvent[];
38
59
  /** Stateless — each output item finalizes with all its file annotations in a
39
60
  * single response.output_item.done event. */
61
+ /** Stateless entry, as the ProviderAdapter interface requires: a fresh spec
62
+ * run per event, so nothing correlates across events. */
63
+ parseStreamEvent(event: SSEEvent): StreamEvent[];
64
+ /** Stateful, and the one callers should use. `phase` is announced once when an item is added but belongs on every text delta of that item, and the spec's state is where that is remembered. */
40
65
  createStreamParser(): (event: SSEEvent) => StreamEvent[];
66
+ /** Overridden by xAI, which extends file extraction. */
67
+ protected streamSpecId(): string;
68
+ protected streamRegistry(): Registry;
41
69
  /** Hosted code-execution output files from one output item. Overridable so
42
70
  * Responses-compatible providers with a different file shape (e.g. xAI, which
43
71
  * embeds files in the code-interpreter `logs` payload) can extend it. */
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const OPENAI_STREAM_REGISTRY: Registry;
@@ -1,9 +1,7 @@
1
1
  /** OpenRouter provider adapter — OpenAI-compatible with extensions. */
2
- import type { SSEEvent } from '../../../network/types';
3
2
  import type { ProviderAdapter } from '../../types/provider';
4
- import type { CompletionResponse } from '../../types/response';
5
- import type { StreamEvent } from '../../types/stream';
6
3
  import { OpenAIAdapter } from '../openai/completions';
4
+ import type { Registry } from '../../../wire/interpreter';
7
5
  export interface OpenRouterAdapterConfig {
8
6
  apiKey: string;
9
7
  baseURL?: string;
@@ -17,8 +15,14 @@ export declare class OpenRouterAdapter extends OpenAIAdapter {
17
15
  * rename, the reasoning strip, the tier remap, the routing passthrough — is the
18
16
  * `openrouter` overlay in the shared spec. Naming the flavor IS the override now. */
19
17
  protected readonly wireFlavor: string;
20
- parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
21
- /** Stateful emit a single `web_search` builtin-tool pair the first time
22
- * `url_citation` annotations appear in the stream (the `:online` search signal). */
23
- createStreamParser(): (event: SSEEvent) => StreamEvent[];
18
+ /** The `:online` web-search rule that used to live in an override is the
19
+ * `openrouter` delta of the shared response spec. Naming the spec IS the
20
+ * override now, exactly as `wireFlavor` is for the request side. */
21
+ protected responseSpecId(): string;
22
+ protected responseRegistry(): Registry;
23
+ /** The `:online` web-search pair is the `openrouter` delta of the shared
24
+ * stream spec, so naming the spec IS the override -- as it already is for the
25
+ * request side and the buffered response. */
26
+ protected streamSpecId(): string;
27
+ protected streamRegistry(): Registry;
24
28
  }
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const OPENROUTER_RESPONSE_REGISTRY: Registry;
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const OPENROUTER_STREAM_REGISTRY: Registry;
@@ -0,0 +1,5 @@
1
+ import type { Registry } from '../../wire/interpreter';
2
+ export declare const RESPONSE_REGISTRIES: Record<string, Registry>;
3
+ /** Every name any response registry supplies. For checks that only ask "does
4
+ * this resolve anywhere", never for dispatch. */
5
+ export declare function allResponseNames(): Set<string>;
@@ -4,11 +4,9 @@
4
4
  * - Reasoning via model variant (grok-*-reasoning), not reasoning param
5
5
  * - Returns reasoning_content in message (plain text, unlike OpenAI which hides it)
6
6
  */
7
- import type { SSEEvent } from '../../../network/types';
8
7
  import type { ProviderAdapter } from '../../types/provider';
9
8
  import type { CompletionResponse } from '../../types/response';
10
- import type { StreamEvent } from '../../types/stream';
11
- import { OpenAIAdapter, type OpenAIStreamState } from '../openai/completions';
9
+ import { OpenAIAdapter } from '../openai/completions';
12
10
  export interface XAIAdapterConfig {
13
11
  apiKey: string;
14
12
  baseURL?: string;
@@ -22,5 +20,4 @@ export declare class XAIAdapter extends OpenAIAdapter {
22
20
  * `xai` overlay in the shared spec. Naming the flavor IS the override now. */
23
21
  protected readonly wireFlavor: string;
24
22
  parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
25
- parseStreamEvent(event: SSEEvent, state?: OpenAIStreamState): StreamEvent[];
26
23
  }
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const XAI_RESPONSES_REGISTRY: Registry;
@@ -8,11 +8,23 @@
8
8
  import type { ProviderAdapter } from '../../types/provider';
9
9
  import type { FileOutput } from '../../types/response';
10
10
  import { OpenAIResponsesAdapter } from '../openai/responses';
11
+ import type { Registry } from '../../../wire/interpreter';
11
12
  export interface XAIResponsesAdapterConfig {
12
13
  apiKey: string;
13
14
  baseURL?: string;
14
15
  }
16
+ /** xAI returns code-execution output files INLINE inside the `code_interpreter_call`
17
+ * `logs` payload (a JSON string: `{stdout, output_files:[{file_name, mime_type, data:[…bytes]}]}`),
18
+ * not as OpenAI-style `container_file_citation` annotations. Requires the request to
19
+ * ask for them via `include: ['code_interpreter_call.outputs']`. */
20
+ export declare function xaiCodeExecFiles(item: Record<string, unknown>): FileOutput[];
15
21
  export declare class XAIResponsesAdapter extends OpenAIResponsesAdapter {
22
+ /** Identical to OpenAI's by inheritance, but addressed by its own id so the
23
+ * target has a spec of its own rather than a special case in the lookup. */
24
+ protected responseSpecId(): string;
25
+ protected responseRegistry(): Registry;
26
+ protected streamSpecId(): string;
27
+ protected streamRegistry(): Registry;
16
28
  readonly name: ProviderAdapter['name'];
17
29
  constructor(config: XAIResponsesAdapterConfig);
18
30
  baseURL(): string;
@@ -0,0 +1,2 @@
1
+ import type { Registry } from '../../../wire/interpreter';
2
+ export declare const XAI_STREAM_REGISTRY: Registry;
@@ -3,6 +3,15 @@
3
3
  * in this shape; consumers (renderFactsLayer, snapshots) read them. */
4
4
  export declare const FACT_CATEGORIES: readonly ["name", "date", "time", "path", "url", "email", "phone", "address", "amount", "number", "identifier", "other"];
5
5
  export type FactCategory = (typeof FACT_CATEGORIES)[number];
6
+ /** Narrow a parsed category to the union, falling back to `other`.
7
+ *
8
+ * Categories are read back out of a system prompt or off a fact-extract tool's
9
+ * JSON, so the string is model-influenced rather than ours. Casting it into
10
+ * `FactCategory` would type a value the union does not contain, and every
11
+ * consumer that switches on the category would then meet a branch it was
12
+ * compiled believing could not happen. `other` is the union's catch-all and is
13
+ * what an unrecognised category means. */
14
+ export declare function toFactCategory(raw: string): FactCategory;
6
15
  export interface ExtractedFact {
7
16
  /** Short descriptive label. Lowercase, snake_or_dotted notation. */
8
17
  key: string;
@@ -30,6 +30,9 @@ export declare class StrategyToolsImpl implements StrategyTools {
30
30
  middle: HistoryEntry[];
31
31
  old: HistoryEntry[];
32
32
  };
33
+ /** What the request weighs right now, including any compaction already
34
+ * applied in this call. */
35
+ measureCurrent(): number;
33
36
  measure(items: readonly HistoryEntry[] | Message[]): number;
34
37
  extractFacts(entries: readonly HistoryEntry[], categories?: string[]): Promise<ExtractedFact[]>;
35
38
  summarize(entries: readonly HistoryEntry[], maxLength: number, focus?: string): Promise<string>;
@@ -82,6 +82,11 @@ export interface StrategyTools {
82
82
  old: HistoryEntry[];
83
83
  };
84
84
  measure(items: readonly HistoryEntry[] | Message[]): number;
85
+ /** Tokens in the request AS IT STANDS, after whatever this strategy has
86
+ * already done to it. `ReactContext.current` is the count that TRIGGERED
87
+ * the compaction and no mutation updates it, so it is the wrong number to
88
+ * judge the compaction by. */
89
+ measureCurrent(): number;
85
90
  extractFacts(entries: readonly HistoryEntry[], categories?: string[]): Promise<ExtractedFact[]>;
86
91
  summarize(entries: readonly HistoryEntry[], maxLength: number, focus?: string): Promise<string>;
87
92
  replaceRange(from: number, to: number, replacement: Message): void;
@@ -0,0 +1,16 @@
1
+ /** Detect an audio clip's MIME type from its leading magic bytes.
2
+ *
3
+ * Same problem as `sniffImageMime`, from the opposite direction. OpenAI's chat
4
+ * completions return `message.audio` as `{ id, data, expires_at, transcript }`
5
+ * and NO `format` field, so the adapter's `audio/${format ?? 'wav'}` fell through
6
+ * to the default every single time: request mp3, receive mp3 bytes (`ID3...`),
7
+ * and get told it is `audio/wav`. Anything that trusts the label — an <audio>
8
+ * element, a file written to disk, a follow-up upload with a strict validator —
9
+ * is then working from a lie.
10
+ *
11
+ * The bytes are the only honest source here, and the caller's requested format is
12
+ * not available at parse time.
13
+ *
14
+ * Returns the CONTAINER, which is what a player needs: Opus arrives inside Ogg
15
+ * and is reported as `audio/ogg`. */
16
+ export declare function sniffAudioMime(b: Uint8Array): string | undefined;
@@ -0,0 +1,13 @@
1
+ /** Ordering that does not depend on where the process is running.
2
+ *
3
+ * `String.prototype.localeCompare` with no locale argument reads the HOST's
4
+ * default locale, so the same inputs sort differently on different machines:
5
+ * under `sv-SE` or `tr-TR`, `ünique` sorts after `user-name` rather than next
6
+ * to `unique`. That is fine for a list shown to a person and wrong for
7
+ * anything whose order becomes bytes — a rendered system prompt changes
8
+ * content with the host's locale, which breaks reproducibility and misses the
9
+ * provider's prompt cache on a prefix that should have been identical.
10
+ *
11
+ * Codepoint order is not "nicer" than collation. It is the same everywhere,
12
+ * which is the only property these call sites actually need. */
13
+ export declare function byCodepoint(a: string, b: string): number;
@@ -270,6 +270,8 @@ export interface Registry {
270
270
  }
271
271
  export declare function getPath(root: any, path: string): any;
272
272
  export declare function evalCond(cond: Cond | undefined, ctx: Ctx, reg: Registry): boolean;
273
+ export declare const OMIT: unique symbol;
274
+ export declare function evalTemplate(tpl: Json, ctx: Ctx, reg: Registry): Json | typeof OMIT;
273
275
  export declare function resolveVariants(spec: WireSpec, model: string, reg: Registry): Set<string>;
274
276
  export interface BuiltRequest {
275
277
  body: Record<string, unknown>;