@combycode/llm-sdk 1.5.0 → 1.6.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.
@@ -7,8 +7,19 @@ import type { LLMClientConfig } from './client-config';
7
7
  import type { ContentPart, Message } from './types/messages';
8
8
  import type { ExecuteOptions } from './types/options';
9
9
  import type { ApiType, ProviderAdapter, ProviderName } from './types/provider';
10
+ import type { CompletionResponse } from './types/response';
10
11
  export declare const PRIORITY_INTERACTIVE = 1;
11
12
  export declare const PRIORITY_BACKGROUND = 2;
13
+ /** Build a history assistant message from a response, stamped with provenance
14
+ * (id, createdAt, origin). On a stateful API (responses / interactions) the origin
15
+ * carries the server-state id so a later turn can continue server-side instead of
16
+ * resending the transcript. Shared by `LLMClient.assistantMessage` (manual multi-turn)
17
+ * and the agent loop (so its tool turns also chain server-side). */
18
+ export declare function buildAssistantMessage(response: CompletionResponse, origin: {
19
+ provider: ProviderName;
20
+ model: string;
21
+ api: ApiType;
22
+ }): Message;
12
23
  export declare function normalizeInput(input: string | ContentPart[] | Message[]): Message[];
13
24
  /** Lift any role:'system' messages out of the input array.
14
25
  * Anthropic and some other providers expect `system` as a top-level
@@ -0,0 +1,24 @@
1
+ /** Typed errors for abnormal agent-run / structured-output outcomes.
2
+ *
3
+ * `AgentRunError` is the shared base so callers can differentiate the failure
4
+ * reason (`error.reason` or `instanceof`). Today only `invalid_final_output` is an
5
+ * exception; `max_steps` / `model_refusal` remain returned results (differentiated
6
+ * by `finishReason` / `AgentRunReport.reason`). A future run-error-handler config
7
+ * can add `MaxStepsError` / `ModelRefusalError` under this base without a break. */
8
+ export declare class AgentRunError extends Error {
9
+ /** Machine-readable failure reason (e.g. `'invalid_final_output'`). */
10
+ readonly reason: string;
11
+ constructor(reason: string, message: string, options?: {
12
+ cause?: unknown;
13
+ });
14
+ }
15
+ /** The model's final output could not be parsed / validated against the requested
16
+ * JSON schema. Carries the raw text so a caller can inspect, log, or retry. */
17
+ export declare class InvalidFinalOutputError extends AgentRunError {
18
+ readonly reason: "invalid_final_output";
19
+ /** The raw model output that failed to parse. */
20
+ readonly rawText: string;
21
+ constructor(rawText: string, options?: {
22
+ cause?: unknown;
23
+ });
24
+ }
@@ -26,8 +26,11 @@ export declare class AnthropicAdapter implements ProviderAdapter {
26
26
  private buildContentPart;
27
27
  parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
28
28
  parseStreamEvent(event: SSEEvent): StreamEvent[];
29
- /** Statelessevery event is self-contained (code-execution result blocks
30
- * arrive complete in a single content_block_start). */
29
+ /** StatefulAnthropic streams `server_tool_use` input via `input_json_delta`
30
+ * (empty at block start) and returns the result in a separate `*_tool_result`
31
+ * block. The closure accumulates each call's input (code / query) and attaches it
32
+ * to the matching `builtin_tool_end`. */
31
33
  createStreamParser(): (event: SSEEvent) => StreamEvent[];
34
+ private streamEvents;
32
35
  private parseUsage;
33
36
  }
@@ -10,6 +10,9 @@
10
10
  * - web_search → anthropic, openai, google, xai, openrouter
11
11
  * - code_interpreter → anthropic, openai, google, xai (NOT openrouter: it
12
12
  * proxies function tools + its own plugins, but does not route hosted code
13
- * execution — confirmed against the API). */
13
+ * execution — confirmed against the API).
14
+ * - web_fetch → anthropic (web_fetch_20260318), google (urlContext).
15
+ * OpenAI has no separate fetch tool (its web_search does page-open); xAI /
16
+ * openrouter expose none. */
14
17
  import type { ProviderName } from '../types/provider';
15
18
  export declare const PROVIDER_BUILTIN_TOOLS: Record<ProviderName, readonly string[]>;
@@ -25,8 +25,18 @@ export declare class GoogleInteractionsAdapter implements ProviderAdapter {
25
25
  private toolCallNames;
26
26
  enableStreaming(providerReq: ProviderHttpRequest): void;
27
27
  parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
28
+ /** Translate one Interactions SSE event to unified events. The 2.10 wire is a
29
+ * step machine (verified live): `step.start` opens a typed step (`model_output`,
30
+ * `function_call`, `thought`…), `step.delta` streams its payload (`{type:'text'}`,
31
+ * `{type:'arguments_delta'}`, `{type:'thought_summary'}`, internal
32
+ * `thought_signature`), `step.stop` closes it, and `interaction.completed` /
33
+ * `interaction.failed` finish the turn (usage under `interaction.usage`). A
34
+ * function call's `arguments_delta` carries no id, so we correlate it to the
35
+ * currently-open call id held in `state`. */
36
+ private streamEvents;
28
37
  parseStreamEvent(event: SSEEvent): StreamEvent[];
29
- /** Stateless the Interactions adapter surfaces no code-execution file outputs. */
38
+ /** Per-stream stateful parser correlates a function call's streamed arguments
39
+ * and end to the call opened by its `step.start`. */
30
40
  createStreamParser(): (event: SSEEvent) => StreamEvent[];
31
41
  private parseUsage;
32
42
  }
@@ -0,0 +1,12 @@
1
+ /** xAI service-tier mapping — provider-specific, kept out of the SDK core.
2
+ *
3
+ * xAI's `ServiceTier` enum accepts only `SERVICE_TIER_DEFAULT` / `SERVICE_TIER_PRIORITY`
4
+ * (verified against the xai-sdk proto). The OpenAI-inherited map emits `auto` / `flex` /
5
+ * `scale`, which xAI rejects — so the xAI adapter remaps here instead of inheriting.
6
+ * `standard` → xAI's `default`; anything xAI can't honor is omitted (the server then
7
+ * uses its own default tier). The billed response value (`default` / `priority`) parses
8
+ * correctly through the shared `openaiBilledTier` (`default` → `standard`), so only the
9
+ * request direction needs an xAI-specific map. */
10
+ import type { ServiceTier } from '../../types/tiers';
11
+ /** unified → xAI request `service_tier` (`default` | `priority`), or `undefined` to omit. */
12
+ export declare function xaiRequestTier(t?: ServiceTier): 'default' | 'priority' | undefined;
@@ -20,6 +20,12 @@ export interface ExecuteOptions {
20
20
  maxTokens?: number;
21
21
  temperature?: number;
22
22
  topP?: number;
23
+ /** Penalise tokens by prior presence ([-2, 2]). Honoured by OpenAI/xAI chat-completions,
24
+ * OpenRouter, and Google (generateContent + Interactions); ignored by OpenAI/xAI Responses
25
+ * and Anthropic, which don't accept it. */
26
+ presencePenalty?: number;
27
+ /** Penalise tokens by prior frequency ([-2, 2]). Same provider support as `presencePenalty`. */
28
+ frequencyPenalty?: number;
23
29
  stop?: string[];
24
30
  tools?: Tool[];
25
31
  toolChoice?: ToolChoice;
@@ -27,6 +33,10 @@ export interface ExecuteOptions {
27
33
  schema: Record<string, unknown>;
28
34
  name?: string;
29
35
  strict?: boolean;
36
+ /** Opt-in repair: if the model's final output fails to parse, re-prompt this
37
+ * many times with the parse error before throwing `InvalidFinalOutputError`.
38
+ * Default 0 (throw immediately). Honoured by `LLMClient.structuredComplete`. */
39
+ repairAttempts?: number;
30
40
  };
31
41
  audio?: AudioOptions;
32
42
  outputModalities?: Array<'text' | 'audio'>;
@@ -18,6 +18,10 @@ export interface NormalizedRequest {
18
18
  maxTokens?: number;
19
19
  temperature?: number;
20
20
  topP?: number;
21
+ /** Penalise tokens by prior presence (OpenAI/xAI chat-completions, OpenRouter, Google). */
22
+ presencePenalty?: number;
23
+ /** Penalise tokens by prior frequency (OpenAI/xAI chat-completions, OpenRouter, Google). */
24
+ frequencyPenalty?: number;
21
25
  stop?: string[];
22
26
  tools?: Tool[];
23
27
  toolChoice?: ToolChoice;
@@ -25,6 +29,8 @@ export interface NormalizedRequest {
25
29
  schema: Record<string, unknown>;
26
30
  name?: string;
27
31
  strict?: boolean;
32
+ /** Opt-in repair-retry count for `structuredComplete` (default 0). */
33
+ repairAttempts?: number;
28
34
  };
29
35
  thinking?: ThinkingConfig;
30
36
  cache?: CacheConfig;
@@ -48,13 +48,23 @@ export interface FileOutput {
48
48
  * Absent for providers that don't need extra context. */
49
49
  ref?: Record<string, unknown>;
50
50
  }
51
- /** A hosted builtin tool the model invoked (provider-run). */
51
+ /** A hosted builtin tool the model invoked (provider-run), with its inputs/outputs. */
52
52
  export interface BuiltinToolCall {
53
53
  /** Unified tool name: `'web_search'` | `'code_interpreter'` | … (normalized from
54
54
  * each provider's native name — e.g. Anthropic `code_execution`). */
55
55
  tool: string;
56
56
  /** Provider call id, when available (correlates the stream start/end events). */
57
57
  id?: string;
58
+ /** `code_interpreter`: the code the model executed. */
59
+ code?: string;
60
+ /** `code_interpreter`: the code's textual output (stdout / logs). */
61
+ output?: string;
62
+ /** `web_search`: the query the model searched for (the first, if it issued several).
63
+ * Absent for page-open/read steps — see `url`. */
64
+ query?: string;
65
+ /** `web_search`: the URL the model opened/read (OpenAI/xAI `open_page`/`find`
66
+ * actions, which carry a URL instead of a query). Absent for plain searches. */
67
+ url?: string;
58
68
  }
59
69
  export type FinishReason = 'stop' | 'tool_use' | 'length' | 'content_filter' | 'error';
60
70
  export interface Usage {
@@ -60,11 +60,17 @@ export type StreamEvent = {
60
60
  tool: string;
61
61
  id?: string;
62
62
  }
63
- /** A hosted builtin tool finished executing server-side. */
63
+ /** A hosted builtin tool finished executing server-side. Carries its inputs/outputs
64
+ * (`code` + `output` for code execution, `query` for web search) — the same payload
65
+ * the client collects onto `response.builtinToolCalls`. */
64
66
  | {
65
67
  type: 'builtin_tool_end';
66
68
  tool: string;
67
69
  id?: string;
70
+ code?: string;
71
+ output?: string;
72
+ query?: string;
73
+ url?: string;
68
74
  }
69
75
  /** A moderation result for the input or output. `source` distinguishes a
70
76
  * provider-native result from a client-emulated one. Emitted by the moderation
@@ -8,7 +8,7 @@ export interface FunctionTool {
8
8
  cache?: boolean;
9
9
  }
10
10
  export interface BuiltinTool {
11
- type: 'image_generation' | 'web_search' | 'code_interpreter' | 'file_search' | 'mcp';
11
+ type: 'image_generation' | 'web_search' | 'web_fetch' | 'code_interpreter' | 'file_search' | 'mcp';
12
12
  params?: Record<string, unknown>;
13
13
  }
14
14
  /** Typed shape for an `mcp` builtin's `params` (OpenAI hosted MCP tool). The
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@combycode/llm-sdk",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Unified, pluggable AI SDK for accessing the LLMs of every major provider (Anthropic, OpenAI, Google, xAI, OpenRouter) through one API. Cross-environment: Node, Bun, and the browser.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",