@combycode/llm-sdk 3.0.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +150 -0
- package/dist/agent/loop-step-state.d.ts +5 -1
- package/dist/catalog/catalog.d.ts +15 -3
- package/dist/helpers/select-model.d.ts +35 -0
- package/dist/index.browser.js +447 -91
- package/dist/index.d.ts +3 -3
- package/dist/index.js +447 -91
- package/dist/llm/client.d.ts +3 -0
- package/dist/llm/providers/_shared/citations.d.ts +25 -0
- package/dist/llm/types/provider.d.ts +5 -0
- package/dist/llm/types/response.d.ts +23 -0
- package/dist/llm/types/stream.d.ts +14 -1
- package/dist/wire/interpreter.d.ts +40 -0
- package/package.json +3 -1
package/dist/llm/client.d.ts
CHANGED
|
@@ -85,6 +85,9 @@ export declare class LLMClient {
|
|
|
85
85
|
* files piped straight to a file / GridFS / HTTP response without buffering. */
|
|
86
86
|
streamFile(file: FileOutput): Promise<FileStream>;
|
|
87
87
|
/** Submit a request. Returns the parsed CompletionResponse. */
|
|
88
|
+
/** Anything the spec left out on purpose reaches the caller as a warning.
|
|
89
|
+
* Said once per request; the build already de-duplicates within one. */
|
|
90
|
+
private reportBuildNotes;
|
|
88
91
|
complete(input: string | ContentPart[] | Message[], options?: ExecuteOptions): Promise<CompletionResponse>;
|
|
89
92
|
/** Run `complete` with a JSON Schema enforced via `structured`. Strips any
|
|
90
93
|
* leading/trailing markdown fences from the model reply, then JSON.parses
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** The sources an answer cited, read from four different wire shapes.
|
|
2
|
+
*
|
|
3
|
+
* `builtinToolCalls` already records what the model INVOKED — that it searched,
|
|
4
|
+
* and for what. This is the other half: what it ended up CITING. They are not
|
|
5
|
+
* the same list. A model can run three searches and cite one page, or open a
|
|
6
|
+
* page and cite nothing, and a caller rendering footnotes needs the second
|
|
7
|
+
* list, not the first.
|
|
8
|
+
*
|
|
9
|
+
* Until now this was only reachable by regexing `response.raw`, which is what
|
|
10
|
+
* the web-search example actually did. That is a per-consumer reimplementation
|
|
11
|
+
* of provider knowledge that belongs in the SDK.
|
|
12
|
+
*
|
|
13
|
+
* This function always returns an array. The RESPONSE FIELD it feeds is
|
|
14
|
+
* optional and omitted when empty, like the `files` / `builtinToolCalls` lines
|
|
15
|
+
* it sits beside -- R3 forbids adding a required field to a response type, so
|
|
16
|
+
* the Python port's always-present array is not available here. Callers read
|
|
17
|
+
* `response.citations ?? []`.
|
|
18
|
+
*/
|
|
19
|
+
import type { Citation } from '../../types/response';
|
|
20
|
+
/** Every source the answer cited, or `[]`.
|
|
21
|
+
*
|
|
22
|
+
* `api` is the wire surface (`'messages' | 'generate' | 'interactions' |
|
|
23
|
+
* 'responses' | 'completions'`). An unknown surface yields `[]` rather than
|
|
24
|
+
* throwing: a response we cannot read citations from is still a valid answer. */
|
|
25
|
+
export declare function extractCitations(api: string, raw: unknown): Citation[];
|
|
@@ -24,6 +24,11 @@ export interface ProviderHttpRequest {
|
|
|
24
24
|
/** Override of the default completion path. Used by providers that route
|
|
25
25
|
* per-API or per-modality. */
|
|
26
26
|
path?: string;
|
|
27
|
+
/** What the build deliberately left out, and why — a hosted tool this provider
|
|
28
|
+
* refuses to run beside the attached content, for instance. The client emits
|
|
29
|
+
* each as `onWarning`, because dropping a capability the caller asked for and
|
|
30
|
+
* saying nothing is how a missing feature gets mistaken for a working one. */
|
|
31
|
+
notes?: string[];
|
|
27
32
|
}
|
|
28
33
|
export interface ProviderAdapter {
|
|
29
34
|
readonly name: ProviderName;
|
|
@@ -20,6 +20,16 @@ export interface CompletionResponse {
|
|
|
20
20
|
* search or code-execution run. A durable trail of what was called (the provider
|
|
21
21
|
* ran them server-side; nothing for the client to execute). Absent when none. */
|
|
22
22
|
builtinToolCalls?: BuiltinToolCall[];
|
|
23
|
+
/** Sources the answer cited, unified across providers.
|
|
24
|
+
*
|
|
25
|
+
* Distinct from `builtinToolCalls`, which records what the model INVOKED: a turn
|
|
26
|
+
* can run three searches and cite one page, or open a page and cite nothing.
|
|
27
|
+
* Rendering footnotes needs this list, not that one.
|
|
28
|
+
*
|
|
29
|
+
* Absent when the model cited nothing — R3: a response type grows by OPTIONAL
|
|
30
|
+
* fields only, so this cannot be the always-present array the Python port
|
|
31
|
+
* exposes. Read it as `response.citations ?? []`. */
|
|
32
|
+
citations?: Citation[];
|
|
23
33
|
/** Inline-moderation outcome, when the `moderation` request option was used.
|
|
24
34
|
* Report-only: present for observability; it never blocks the call. Absent when
|
|
25
35
|
* moderation was not requested. */
|
|
@@ -58,6 +68,19 @@ export interface FileOutput {
|
|
|
58
68
|
* Absent for providers that don't need extra context. */
|
|
59
69
|
ref?: Record<string, unknown>;
|
|
60
70
|
}
|
|
71
|
+
/** A source the answer cited.
|
|
72
|
+
*
|
|
73
|
+
* Four providers report these four different ways — Anthropic on the text block,
|
|
74
|
+
* Google in `groundingMetadata`, OpenAI as annotations, xAI as bare top-level URLs.
|
|
75
|
+
* The differences stop at the adapter. */
|
|
76
|
+
export interface Citation {
|
|
77
|
+
url: string;
|
|
78
|
+
/** Page title, when the provider supplies one. */
|
|
79
|
+
title?: string;
|
|
80
|
+
/** The passage the source supports. Only Anthropic reports this today; absent
|
|
81
|
+
* elsewhere rather than faked from the answer text. */
|
|
82
|
+
text?: string;
|
|
83
|
+
}
|
|
61
84
|
/** A hosted builtin tool the model invoked (provider-run), with its inputs/outputs. */
|
|
62
85
|
export interface BuiltinToolCall {
|
|
63
86
|
/** Unified tool name: `'web_search'` | `'code_interpreter'` | … (normalized from
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Universal streaming event types. */
|
|
2
2
|
import type { ModerationEntry } from '../moderation/types';
|
|
3
3
|
import type { AssistantPhase } from './messages';
|
|
4
|
-
import type { FileOutput, Usage } from './response';
|
|
4
|
+
import type { Citation, FileOutput, Usage } from './response';
|
|
5
5
|
export type MediaStreamType = 'image' | 'audio' | 'video';
|
|
6
6
|
export type StreamEvent =
|
|
7
7
|
/** `itemId` identifies WHICH output item a delta belongs to, when the provider reports
|
|
@@ -62,6 +62,19 @@ export type StreamEvent =
|
|
|
62
62
|
type: 'file';
|
|
63
63
|
file: FileOutput;
|
|
64
64
|
}
|
|
65
|
+
/** The answer cited a source. Emitted as the citation arrives, which is NOT
|
|
66
|
+
* when the search ran: a provider searches early and cites while it writes, so
|
|
67
|
+
* these interleave with `text` deltas. Distinct from `builtin_tool_end`, which
|
|
68
|
+
* reports the search itself.
|
|
69
|
+
*
|
|
70
|
+
* Measured shapes: Anthropic `citations_delta`, OpenAI/xAI Responses
|
|
71
|
+
* `response.output_text.annotation.added`, chat-completions `delta.annotations`,
|
|
72
|
+
* Google's populated `groundingMetadata` chunk. Also collected onto the streamed
|
|
73
|
+
* final response's `citations`, deduped by url. */
|
|
74
|
+
| {
|
|
75
|
+
type: 'citation';
|
|
76
|
+
citation: Citation;
|
|
77
|
+
}
|
|
65
78
|
/** A hosted (provider-run) builtin tool began executing server-side — e.g. the
|
|
66
79
|
* model started a web search or code-execution run. `tool` is the unified name
|
|
67
80
|
* (`'web_search'` | `'code_interpreter'` | …). Informational progress: unlike
|
|
@@ -53,6 +53,13 @@ export type Cond = {
|
|
|
53
53
|
/** Array at `path` contains `value`. */
|
|
54
54
|
| {
|
|
55
55
|
includes: [string, Json];
|
|
56
|
+
}
|
|
57
|
+
/** The request carries a message content part of one of these types
|
|
58
|
+
* (`image` | `audio` | `video` | `document` | `text`). Needed because the
|
|
59
|
+
* parts are nested two levels deep — `messages[].content[].type` — which
|
|
60
|
+
* `includes` cannot reach. */
|
|
61
|
+
| {
|
|
62
|
+
hasPartType: string[];
|
|
56
63
|
} | {
|
|
57
64
|
not: Cond;
|
|
58
65
|
} | {
|
|
@@ -93,10 +100,37 @@ export interface BlockRule {
|
|
|
93
100
|
/** Named cross-field effects run after the block is written. */
|
|
94
101
|
effects?: string[];
|
|
95
102
|
}
|
|
103
|
+
/** A hosted tool this provider refuses to run alongside certain content.
|
|
104
|
+
*
|
|
105
|
+
* Providers reject some combinations outright: Google answers 400 "The mime
|
|
106
|
+
* type: video/mp4 is not supported for code execution" when `code_interpreter`
|
|
107
|
+
* is sent with a PDF or a video. The caller cannot be expected to know that, and
|
|
108
|
+
* the error names a mime type rather than the tool, so it reads as a problem
|
|
109
|
+
* with the attachment.
|
|
110
|
+
*
|
|
111
|
+
* Declared here as data rather than as a provider `if` in the builder: it is one
|
|
112
|
+
* more fact about how this API behaves, and the four other providers stay
|
|
113
|
+
* untouched because their specs simply do not carry the field.
|
|
114
|
+
*
|
|
115
|
+
* A matched constraint DROPS the tool — `hasTool` reports it absent, so the
|
|
116
|
+
* spec's existing `$when` guard omits it with no further edit — and records
|
|
117
|
+
* `why` on the built request so the runtime can say what it did. Dropping
|
|
118
|
+
* quietly would trade a confusing error for a silent loss of a capability the
|
|
119
|
+
* caller asked for, which is worse. */
|
|
120
|
+
export interface ToolConstraint {
|
|
121
|
+
/** Builtin tool type, e.g. `code_interpreter`. */
|
|
122
|
+
tool: string;
|
|
123
|
+
/** When this holds, the tool cannot be sent. */
|
|
124
|
+
conflictsWith: Cond;
|
|
125
|
+
/** Said to the caller, verbatim. */
|
|
126
|
+
why: string;
|
|
127
|
+
}
|
|
96
128
|
export interface WireSpec {
|
|
97
129
|
id: string;
|
|
98
130
|
provider: string;
|
|
99
131
|
api: string;
|
|
132
|
+
/** Tool/content combinations this provider rejects. See `ToolConstraint`. */
|
|
133
|
+
toolConstraints?: ToolConstraint[];
|
|
100
134
|
/** Adapter flavor, for specs shared by several providers (openai|xai|openrouter). */
|
|
101
135
|
flavors?: string[];
|
|
102
136
|
envelope?: {
|
|
@@ -216,6 +250,8 @@ export interface Ctx {
|
|
|
216
250
|
};
|
|
217
251
|
/** Collected multipart fields, when the spec declares a multipart body. */
|
|
218
252
|
multipart?: MultipartField[];
|
|
253
|
+
/** What the build decided to leave out, and why — surfaced to the caller. */
|
|
254
|
+
notes?: string[];
|
|
219
255
|
}
|
|
220
256
|
export interface MultipartField {
|
|
221
257
|
name: string;
|
|
@@ -237,6 +273,10 @@ export declare function evalCond(cond: Cond | undefined, ctx: Ctx, reg: Registry
|
|
|
237
273
|
export declare function resolveVariants(spec: WireSpec, model: string, reg: Registry): Set<string>;
|
|
238
274
|
export interface BuiltRequest {
|
|
239
275
|
body: Record<string, unknown>;
|
|
276
|
+
/** Anything the spec deliberately left out, and why — e.g. a hosted tool this
|
|
277
|
+
* provider will not run beside the attached content. The runtime turns these
|
|
278
|
+
* into `onWarning`; they are never silent. */
|
|
279
|
+
notes?: string[];
|
|
240
280
|
headers?: Record<string, string>;
|
|
241
281
|
path?: string;
|
|
242
282
|
url?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@combycode/llm-sdk",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.1",
|
|
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",
|
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
"prepublishOnly": "bun run build",
|
|
35
35
|
"test": "bun test",
|
|
36
36
|
"test:unit": "bun test tests/unit",
|
|
37
|
+
"test:coverage": "bun test tests/unit --coverage",
|
|
38
|
+
"coverage:gate": "bun run scripts/coverage-gate.ts",
|
|
37
39
|
"test:integration": "bun test tests/integration",
|
|
38
40
|
"test:helpers": "bun test tests/helpers",
|
|
39
41
|
"test:live": "bun test tests/live",
|