@combycode/llm-sdk 3.0.0 → 3.1.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.
@@ -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
@@ -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;
@@ -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.0.0",
3
+ "version": "3.1.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",