@combycode/llm-sdk 1.2.0 → 1.4.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.
- package/CHANGELOG.md +41 -0
- package/README.md +24 -0
- package/dist/agent/loop.d.ts +10 -1
- package/dist/helpers/one-shot.d.ts +8 -1
- package/dist/index.browser.js +378 -36
- package/dist/index.d.ts +1 -0
- package/dist/index.js +378 -36
- package/dist/llm/client.d.ts +12 -1
- package/dist/llm/files/retrieve.d.ts +44 -0
- package/dist/llm/providers/anthropic/messages.d.ts +3 -0
- package/dist/llm/providers/builtin-tools.d.ts +15 -0
- package/dist/llm/providers/google/generate.d.ts +7 -0
- package/dist/llm/providers/google/interactions.d.ts +2 -0
- package/dist/llm/providers/openai/completions.d.ts +2 -0
- package/dist/llm/providers/openai/responses.d.ts +8 -1
- package/dist/llm/providers/xai/responses.d.ts +4 -0
- package/dist/llm/types/provider.d.ts +9 -1
- package/dist/llm/types/response.d.ts +4 -0
- package/dist/llm/types/stream.d.ts +9 -1
- package/dist/network/types.d.ts +4 -2
- package/dist/plugins/model-catalog/catalog.d.ts +5 -0
- package/package.json +1 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Retrieve the bytes of a hosted-tool output file (e.g. code-execution files).
|
|
2
|
+
*
|
|
3
|
+
* A `FileOutput` may carry inline base64 `data` (Google), a `url` (OpenAI
|
|
4
|
+
* code-interpreter images), or an `id` fetched from the provider's files API
|
|
5
|
+
* (Anthropic, OpenAI container files). These helpers resolve all three into
|
|
6
|
+
* bytes — buffered (`retrieveFile` → Blob) or streamed (`streamFile` →
|
|
7
|
+
* ReadableStream, for large files piped straight to a sink).
|
|
8
|
+
*
|
|
9
|
+
* All HTTP flows through the injected `EngineFetch` (auth, queue, cost, traces). */
|
|
10
|
+
import type { EngineFetch } from '../../network/types';
|
|
11
|
+
import type { ProviderName } from '../types/provider';
|
|
12
|
+
import type { FileOutput } from '../types/response';
|
|
13
|
+
export interface RetrieveContext {
|
|
14
|
+
provider: ProviderName;
|
|
15
|
+
apiKey: string;
|
|
16
|
+
fetch: EngineFetch;
|
|
17
|
+
/** Provider API base URL; defaults per provider when omitted. */
|
|
18
|
+
baseURL?: string;
|
|
19
|
+
}
|
|
20
|
+
/** A retrieved file's bytes plus the metadata an end user needs to display and
|
|
21
|
+
* open it as an attachment (correct name + type). */
|
|
22
|
+
export interface RetrievedFile {
|
|
23
|
+
blob: Blob;
|
|
24
|
+
/** Filename (from Content-Disposition, else the FileOutput name). */
|
|
25
|
+
name?: string;
|
|
26
|
+
/** MIME type (from Content-Type, else the FileOutput mime). */
|
|
27
|
+
mimeType: string;
|
|
28
|
+
/** Size in bytes. */
|
|
29
|
+
size: number;
|
|
30
|
+
}
|
|
31
|
+
/** A streamed file: its byte stream plus best-effort metadata (from the response
|
|
32
|
+
* headers). The stream itself carries only bytes — name/type/size come from here. */
|
|
33
|
+
export interface FileStream {
|
|
34
|
+
stream: ReadableStream<Uint8Array>;
|
|
35
|
+
name?: string;
|
|
36
|
+
mimeType?: string;
|
|
37
|
+
/** From Content-Length, when the provider sends it. */
|
|
38
|
+
size?: number;
|
|
39
|
+
}
|
|
40
|
+
/** Fetch the whole file as bytes (buffered) plus its name/type/size. */
|
|
41
|
+
export declare function retrieveFile(file: FileOutput, ctx: RetrieveContext): Promise<RetrievedFile>;
|
|
42
|
+
/** Stream the file's bytes (un-buffered) plus best-effort name/type/size. Pipe the
|
|
43
|
+
* stream straight to a file, GridFS, or an HTTP response — nothing is buffered. */
|
|
44
|
+
export declare function streamFile(file: FileOutput, ctx: RetrieveContext): Promise<FileStream>;
|
|
@@ -26,5 +26,8 @@ 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
|
+
/** Stateless — every event is self-contained (code-execution result blocks
|
|
30
|
+
* arrive complete in a single content_block_start). */
|
|
31
|
+
createStreamParser(): (event: SSEEvent) => StreamEvent[];
|
|
29
32
|
private parseUsage;
|
|
30
33
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Hosted server-side tools each provider's chat models support.
|
|
2
|
+
*
|
|
3
|
+
* This is ADAPTER-SOURCED: it reflects what the provider adapters actually map
|
|
4
|
+
* the unified `{ type: 'web_search' | 'code_interpreter' }` builtins onto (each
|
|
5
|
+
* to the provider's native shape), verified by the live tools-parity test. It is
|
|
6
|
+
* applied PROVIDER-LEVEL to tool-capable (chat-family) models at catalog load —
|
|
7
|
+
* a deliberate first pass; a reliable per-model source can refine it later.
|
|
8
|
+
*
|
|
9
|
+
* Coverage (verified live 2026-07):
|
|
10
|
+
* - web_search → anthropic, openai, google, xai, openrouter
|
|
11
|
+
* - code_interpreter → anthropic, openai, google, xai (NOT openrouter: it
|
|
12
|
+
* proxies function tools + its own plugins, but does not route hosted code
|
|
13
|
+
* execution — confirmed against the API). */
|
|
14
|
+
import type { ProviderName } from '../types/provider';
|
|
15
|
+
export declare const PROVIDER_BUILTIN_TOOLS: Record<ProviderName, readonly string[]>;
|
|
@@ -23,5 +23,12 @@ export declare class GoogleAdapter implements ProviderAdapter {
|
|
|
23
23
|
private buildContent;
|
|
24
24
|
parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
|
|
25
25
|
parseStreamEvent(event: SSEEvent): StreamEvent[];
|
|
26
|
+
/** Stateful — Google splits the code-execution marker (`executableCode` /
|
|
27
|
+
* `codeExecutionResult`) and the produced file (`inlineData`) across parts and
|
|
28
|
+
* often across SSE events. The closure remembers "code execution began in this
|
|
29
|
+
* stream" so a later `inlineData` blob is routed to `files` (a code-exec
|
|
30
|
+
* artifact) rather than `media` (conversational output). */
|
|
31
|
+
createStreamParser(): (event: SSEEvent) => StreamEvent[];
|
|
32
|
+
private streamEvents;
|
|
26
33
|
private parseUsage;
|
|
27
34
|
}
|
|
@@ -26,5 +26,7 @@ export declare class GoogleInteractionsAdapter implements ProviderAdapter {
|
|
|
26
26
|
enableStreaming(providerReq: ProviderHttpRequest): void;
|
|
27
27
|
parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
|
|
28
28
|
parseStreamEvent(event: SSEEvent): StreamEvent[];
|
|
29
|
+
/** Stateless — the Interactions adapter surfaces no code-execution file outputs. */
|
|
30
|
+
createStreamParser(): (event: SSEEvent) => StreamEvent[];
|
|
29
31
|
private parseUsage;
|
|
30
32
|
}
|
|
@@ -21,5 +21,7 @@ export declare class OpenAIAdapter implements ProviderAdapter {
|
|
|
21
21
|
enableStreaming(providerReq: ProviderHttpRequest, _req: NormalizedRequest): void;
|
|
22
22
|
parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
|
|
23
23
|
parseStreamEvent(event: SSEEvent): StreamEvent[];
|
|
24
|
+
/** Stateless — Chat Completions has no hosted code-execution file outputs. */
|
|
25
|
+
createStreamParser(): (event: SSEEvent) => StreamEvent[];
|
|
24
26
|
private parseUsage;
|
|
25
27
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import type { SSEEvent } from '../../../network/types';
|
|
6
6
|
import type { ProviderAdapter, ProviderHttpRequest } from '../../types/provider';
|
|
7
7
|
import type { NormalizedRequest } from '../../types/request';
|
|
8
|
-
import { type CompletionResponse, type Usage } from '../../types/response';
|
|
8
|
+
import { type CompletionResponse, type FileOutput, type Usage } from '../../types/response';
|
|
9
9
|
import type { StreamEvent } from '../../types/stream';
|
|
10
10
|
export interface OpenAIResponsesAdapterConfig {
|
|
11
11
|
apiKey: string;
|
|
@@ -25,5 +25,12 @@ export declare class OpenAIResponsesAdapter implements ProviderAdapter {
|
|
|
25
25
|
enableStreaming(providerReq: ProviderHttpRequest): void;
|
|
26
26
|
parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
|
|
27
27
|
parseStreamEvent(event: SSEEvent): StreamEvent[];
|
|
28
|
+
/** Stateless — each output item finalizes with all its file annotations in a
|
|
29
|
+
* single response.output_item.done event. */
|
|
30
|
+
createStreamParser(): (event: SSEEvent) => StreamEvent[];
|
|
31
|
+
/** Hosted code-execution output files from one output item. Overridable so
|
|
32
|
+
* Responses-compatible providers with a different file shape (e.g. xAI, which
|
|
33
|
+
* embeds files in the code-interpreter `logs` payload) can extend it. */
|
|
34
|
+
protected filesFromOutputItem(item: Record<string, unknown>): FileOutput[];
|
|
28
35
|
protected parseUsage(u: Record<string, unknown> | undefined): Usage;
|
|
29
36
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { ProviderAdapter, ProviderHttpRequest } from '../../types/provider';
|
|
9
9
|
import type { NormalizedRequest } from '../../types/request';
|
|
10
|
+
import type { FileOutput } from '../../types/response';
|
|
10
11
|
import { OpenAIResponsesAdapter } from '../openai/responses';
|
|
11
12
|
export interface XAIResponsesAdapterConfig {
|
|
12
13
|
apiKey: string;
|
|
@@ -17,4 +18,7 @@ export declare class XAIResponsesAdapter extends OpenAIResponsesAdapter {
|
|
|
17
18
|
constructor(config: XAIResponsesAdapterConfig);
|
|
18
19
|
baseURL(): string;
|
|
19
20
|
buildRequest(req: NormalizedRequest): ProviderHttpRequest;
|
|
21
|
+
/** xAI embeds code-execution files inline in the `logs` payload — extend the base
|
|
22
|
+
* extraction (which handles OpenAI-style annotations / image URLs) with the xAI shape. */
|
|
23
|
+
protected filesFromOutputItem(item: Record<string, unknown>): FileOutput[];
|
|
20
24
|
}
|
|
@@ -25,8 +25,16 @@ export interface ProviderAdapter {
|
|
|
25
25
|
buildRequest(req: NormalizedRequest): ProviderHttpRequest;
|
|
26
26
|
/** Parse provider's raw HTTP response body to a normalized CompletionResponse. */
|
|
27
27
|
parseResponse(raw: unknown, latencyMs: number): CompletionResponse;
|
|
28
|
-
/** Convert one SSE event from the provider stream into zero or more StreamEvents.
|
|
28
|
+
/** Convert one SSE event from the provider stream into zero or more StreamEvents.
|
|
29
|
+
* Stateless per-event primitive — see `createStreamParser` for the per-stream
|
|
30
|
+
* entry point the client actually calls. */
|
|
29
31
|
parseStreamEvent(event: SSEEvent): StreamEvent[];
|
|
32
|
+
/** Create a per-stream parser. Returns a function that converts each SSE event
|
|
33
|
+
* into zero or more StreamEvents, holding any per-stream state (e.g. whether the
|
|
34
|
+
* turn has begun hosted code execution) in its closure. The client calls this
|
|
35
|
+
* once per `stream()` so each stream gets isolated state. Stateless adapters
|
|
36
|
+
* return `parseStreamEvent` bound to themselves. */
|
|
37
|
+
createStreamParser(): (event: SSEEvent) => StreamEvent[];
|
|
30
38
|
/** Auth headers (Bearer / x-api-key / etc.). */
|
|
31
39
|
authHeaders(): Record<string, string>;
|
|
32
40
|
/** Base URL — provider's domain root. */
|
|
@@ -39,6 +39,10 @@ export interface FileOutput {
|
|
|
39
39
|
url?: string;
|
|
40
40
|
/** What produced it (e.g. 'code_execution'). */
|
|
41
41
|
source?: string;
|
|
42
|
+
/** Provider-specific retrieval hints, used by `retrieveFile`/`streamFile` when the
|
|
43
|
+
* file is fetched by `id` (e.g. OpenAI container files set `{ containerId }`).
|
|
44
|
+
* Absent for providers that don't need extra context. */
|
|
45
|
+
ref?: Record<string, unknown>;
|
|
42
46
|
}
|
|
43
47
|
export type FinishReason = 'stop' | 'tool_use' | 'length' | 'content_filter' | 'error';
|
|
44
48
|
export interface Usage {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Universal streaming event types. */
|
|
2
2
|
import type { ModerationEntry } from '../moderation/types';
|
|
3
|
-
import type { Usage } from './response';
|
|
3
|
+
import type { FileOutput, Usage } from './response';
|
|
4
4
|
export type MediaStreamType = 'image' | 'audio' | 'video';
|
|
5
5
|
export type StreamEvent = {
|
|
6
6
|
type: 'text';
|
|
@@ -41,6 +41,14 @@ export type StreamEvent = {
|
|
|
41
41
|
type: 'media_end';
|
|
42
42
|
mediaId?: string;
|
|
43
43
|
}
|
|
44
|
+
/** A hosted-tool output file (e.g. a code-execution chart/CSV) became available.
|
|
45
|
+
* Carries the `FileOutput` descriptor (id / url / inline data + name / mimeType),
|
|
46
|
+
* not the bytes — fetch those via `retrieveFile` / `streamFile`. The same file
|
|
47
|
+
* is also collected onto the streamed final response's `files`. */
|
|
48
|
+
| {
|
|
49
|
+
type: 'file';
|
|
50
|
+
file: FileOutput;
|
|
51
|
+
}
|
|
44
52
|
/** A moderation result for the input or output. `source` distinguishes a
|
|
45
53
|
* provider-native result from a client-emulated one. Emitted by the moderation
|
|
46
54
|
* option (report-only). */
|
package/dist/network/types.d.ts
CHANGED
|
@@ -15,8 +15,10 @@ export interface HttpRequest {
|
|
|
15
15
|
model: string;
|
|
16
16
|
/** How to parse the response body. Default 'json' (LLM responses, image-gen
|
|
17
17
|
* with b64_json, video-status JSON). Use 'arraybuffer' for binary downloads
|
|
18
|
-
* (TTS audio bytes, video file bytes). 'text' for plain-text responses.
|
|
19
|
-
|
|
18
|
+
* (TTS audio bytes, video file bytes). 'text' for plain-text responses.
|
|
19
|
+
* 'stream' returns the raw `ReadableStream<Uint8Array>` body un-buffered (large
|
|
20
|
+
* file downloads that pipe straight to a sink). */
|
|
21
|
+
responseType?: 'json' | 'arraybuffer' | 'text' | 'stream';
|
|
20
22
|
/** When the request body is already a Uint8Array / ArrayBuffer (binary
|
|
21
23
|
* upload like multipart) the queue should NOT JSON.stringify it. Default
|
|
22
24
|
* false → body is JSON.stringify'd. */
|
|
@@ -140,6 +140,11 @@ export declare class ModelCatalog {
|
|
|
140
140
|
getPreferredApi(provider: string, model: string): ApiType | null;
|
|
141
141
|
supportsApi(provider: string, model: string, api: ApiType): boolean;
|
|
142
142
|
supportsTools(provider: string, model: string): boolean;
|
|
143
|
+
/** Hosted server-side builtin tools this model supports (e.g. `['web_search',
|
|
144
|
+
* 'code_interpreter']`). Empty when unknown or the model isn't tool-capable. */
|
|
145
|
+
builtinToolsFor(provider: string, model: string): string[];
|
|
146
|
+
/** Whether this model supports a specific hosted builtin tool. */
|
|
147
|
+
supportsBuiltinTool(provider: string, model: string, tool: string): boolean;
|
|
143
148
|
supportsPreviousResponseId(provider: string, model: string): boolean;
|
|
144
149
|
/** Server-state retention as a duration string ("30d", "72h"), or null if unsupported. */
|
|
145
150
|
getStateRetention(provider: string, model: string): string | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@combycode/llm-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.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",
|