@combycode/llm-sdk 1.5.1 → 1.6.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 CHANGED
@@ -6,13 +6,120 @@ All notable changes to `@combycode/llm-sdk` are documented here. The format foll
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- ## [1.5.1] - 2026-07-06
9
+ ## [1.6.1] - 2026-07-13
10
+
11
+ ### Fixed
12
+ - **Google gemini-image aspect ratio / size (broken image generation).** The `generateContent` image
13
+ path put `aspectRatio` / `imageSize` under `generationConfig.responseFormat.image`, which the API
14
+ rejects (`Invalid value at 'generation_config.response_format.image.aspect_ratio'`) — so any image
15
+ request that passed an aspect ratio 400'd. They belong under `generationConfig.imageConfig`. Verified
16
+ live: `imageConfig.aspectRatio` returns an image for every ratio. (Regressed into view once the 1.6.0
17
+ catalog started advertising `aspectRatio` media params, so the sandbox began sending it.)
18
+ - **Per-model image sizes in the catalog.** The gemini-image `imageSize` options were a blanket
19
+ `512/1K/2K/4K`, but the models 400 on sizes they don't support. Narrowed per model
20
+ (live-probed + confirmed against the official docs): `gemini-3.1-flash-lite-image` → `1K` only;
21
+ `gemini-3-pro-image` / `nano-banana-pro` → `1K/2K/4K` (no 512); `gemini-3.1-flash-image` keeps all four.
22
+
23
+ ## [1.6.0] - 2026-07-11
24
+
25
+ ### Added
26
+ - **Typed structured-output failure + opt-in repair.** Structured output that can't be parsed now throws
27
+ a typed `InvalidFinalOutputError` (extends `AgentRunError`, carries `reason: 'invalid_final_output'` and
28
+ the model's `rawText`) instead of a bare `SyntaxError`, so callers can `instanceof`/inspect/retry.
29
+ `structuredComplete` gains an opt-in `structured.repairAttempts` (default 0): on a parse failure it
30
+ re-prompts with the error up to N times before throwing. Exports `AgentRunError`,
31
+ `InvalidFinalOutputError`. (`max_steps` / `model_refusal` stay returned results, differentiated by
32
+ `finishReason` / `AgentRunReport.reason`; run-error handler hooks can layer on later.)
33
+ - **`user_profile_id` + Interactions `cached_content`.** Anthropic forwards `providerOptions.userProfileId`
34
+ to the `anthropic-user-profile-id` header; Google Interactions maps `providerOptions.cachedContent` to
35
+ its `cached_content` resource.
36
+ - **Sampling penalties.** `presencePenalty` / `frequencyPenalty` ([-2, 2]) on `complete()` / `stream()`
37
+ (and `NormalizedRequest`), mapped to the providers that accept them — OpenAI/xAI **chat-completions**
38
+ (`presence_penalty` / `frequency_penalty`), OpenRouter (inherited), Google **generateContent**
39
+ (`generationConfig.presencePenalty` / `frequencyPenalty`) and **Interactions** (snake_case). Ignored by
40
+ OpenAI/xAI **Responses** and Anthropic, which don't accept them (verified against the SDK sources — the
41
+ Responses API has no penalty fields). Verified live on OpenAI, Google, and xAI.
42
+ - **Unified `web_fetch` hosted tool.** New `{ type: 'web_fetch' }` builtin that reads a
43
+ user-provided URL, mapped to Anthropic's `web_fetch_20260318` (GA; `params` like `allowed_domains`
44
+ / `blocked_domains` / `citations` / `max_content_tokens` / `max_uses` forwarded verbatim, with
45
+ `allowed_callers: ['direct']` defaulted so it works on chat models) and Google's `urlContext` tool.
46
+ The fetched URL surfaces on `response.builtinToolCalls` (`{ tool: 'web_fetch', url }`) and the
47
+ streamed `builtin_tool_start` / `builtin_tool_end` events, normalized across both providers.
48
+ `capabilities.builtinTools` / `catalog.supportsBuiltinTool()` / `select('web_fetch')` report it on
49
+ Anthropic + Google (OpenAI's `web_search` already opens pages; xAI / OpenRouter expose no fetch
50
+ tool). Verified live on Anthropic and Google.
51
+ - **Builtin-tool call payloads.** `BuiltinToolCall` (and the `builtin_tool_end` stream event) now
52
+ carry what the tool ran: `code` + `output` (stdout) for `code_interpreter`, and `query` (search
53
+ step) or `url` (page-open step) for `web_search` — normalized across every provider (OpenAI/xAI
54
+ `code_interpreter_call.code` + `web_search_call.action` `query`/`queries[]`/`url`, Anthropic
55
+ `server_tool_use.input` streamed via `input_json_delta` and correlated to its `*_tool_result`
56
+ stdout, Google `executableCode`/`codeExecutionResult` + grounding `webSearchQueries`). A single
57
+ OpenAI web search is a multi-step agent: `search` actions carry a query, `open_page`/`find`
58
+ actions carry the URL they read. Available on both `complete()` and streamed responses; verified
59
+ live on all four providers.
60
+
61
+ ### Changed
62
+ - **Anthropic web-search bumped to `web_search_20260318`** (from `web_search_20250305`) and now forwards
63
+ the unified `BuiltinTool.params` verbatim — `allowed_domains`, `blocked_domains`, `user_location`,
64
+ `response_inclusion`, `max_uses` (previously all silently dropped). The new version defaults to
65
+ *programmatic* tool calling (via code execution), which chat models like haiku reject, so the adapter
66
+ sends `allowed_callers: ['direct']` by default to preserve the classic direct-call behaviour; callers
67
+ override any default through `params`. Live-verified across all providers (scenario 27, 5/5).
10
68
 
11
69
  ### Fixed
12
- - **Anthropic file retrieval from the browser** was blocked by CORS. `retrieveFile` /
13
- `streamFile` now send Anthropic's `anthropic-dangerous-direct-browser-access: true` header
14
- when running in a browser (matching the completion adapter), so hosted code-execution files
15
- download directly. No effect on Node/Bun.
70
+ - **xAI `service_tier` maps to xAI's own enum.** The xAI adapter inherited OpenAI's tier map and could
71
+ emit `auto` / `flex` / `scale`, which xAI's API rejects (its `ServiceTier` is `default` | `priority`
72
+ only). It now remaps from the unified tier `standard` `default`, `priority` → `priority`, and any
73
+ value xAI can't honor is omitted (the server picks its default) rather than 400'ing. Live-verified:
74
+ `priority` sent and billed back (`usage.serviceTier`/`pricingTier`), `flex` no longer errors.
75
+ - **Agent loop no longer swallows failed runs into empty text.** `AgentLoop.complete()` and
76
+ `.stream()` caught any mid-run LLM error, set `finishReason:'error'`, and returned an empty
77
+ `CompletionResponse` (or ended the stream) with the error message dropped — so a tool-using
78
+ `complete()` / `delegate()` / `handoff()` returned `""` on an auth failure, rate limit, context
79
+ overflow, etc., while the same call *without* tools threw. Both now **re-throw** the original error
80
+ (preserving `LLMError` kind/status) after finalizing metrics/hooks, matching the no-tools path and
81
+ the raw client stream. `AgentLoop.run()` is unchanged — it still returns an `AgentRunReport` with
82
+ `reason:'error'` + `error` for callers that want partial results. Live-verified (bad key → thrown
83
+ `auth` error, not empty text).
84
+ - **Agent loop now continues stateful turns server-side.** After a tool call the loop stamped its
85
+ assistant turn without provenance, so multi-turn runs on a stateful API always resent the full
86
+ transcript. On Google Interactions that transcript replay is *rejected* (the API requires resuming
87
+ by `previous_interaction_id`), which surfaced as an **empty final answer** on agentic tool use. The
88
+ loop now stamps `id` / `createdAt` / `origin.serverStateId` (via the shared `buildAssistantMessage`),
89
+ so the server-state brain continues by id and sends only the new turn — gated, as before, by catalog
90
+ support, the retention TTL (openai/xai 30d, google 72h), and model binding. Live-verified: Interactions
91
+ agentic round-trip now answers; OpenAI Responses / Anthropic tool loops unchanged.
92
+ - **Google Interactions streaming (opt-in `api: 'interactions'`) brought current with the 2.10 wire.**
93
+ The regenerated Interactions client replaced the old `content.delta` / `interaction.complete` events
94
+ with a step machine — `step.start` / `step.delta` / `step.stop`, `interaction.created` /
95
+ `interaction.completed` / `interaction.status_update` — so the previous parser produced no output.
96
+ The parser now reads `step.delta` payloads (`text`, `thought_summary` → thinking, `arguments_delta`),
97
+ opens/attaches/closes a function call across `step.start` → `arguments_delta` → `step.stop` (the
98
+ `arguments_delta` carries no id, so a per-stream parser correlates it), and finishes on
99
+ `interaction.completed` / `interaction.failed` with usage from `interaction.usage`. Live-verified
100
+ against the 2.10 API (streamed text, tool calls, usage). The default Google path (`generateContent`)
101
+ is unaffected.
102
+ - **OpenAI web-search query precedence.** OpenAI deprecated the singular `web_search_call.action.query`
103
+ in favour of `action.queries[]`; the Responses adapter now prefers the array and falls back to the
104
+ scalar, so `BuiltinToolCall.query` stays populated on the new wire.
105
+ - **Duplicate OpenAI code-execution files.** When code calls `plt.show()` *and* saves the figure,
106
+ OpenAI emits an extra auto-display container file alongside the saved one — surfacing the same
107
+ chart twice on `response.files`. The Responses adapter now drops the auto-display artifact (an
108
+ image citation named after its own file id, with a zero-width span) when the same image was also
109
+ saved, matching ChatGPT's own UI. A display-only run keeps its sole figure; distinct saved files
110
+ are never collapsed. Investigated across providers: only OpenAI has this pattern (Anthropic/xAI
111
+ return only saved files; Google returns one artifact per output) — so the fix is scoped to the
112
+ OpenAI Responses adapter.
113
+
114
+ ## [1.5.1] - 2026-07-06
115
+
116
+ ### Changed
117
+ - `retrieveFile` / `streamFile` now send Anthropic's `anthropic-dangerous-direct-browser-access:
118
+ true` header in the browser, for consistency with the completion adapter. **Note:** this does
119
+ NOT make Anthropic hosted-tool files downloadable from a browser — Anthropic's Files API
120
+ (`GET /v1/files/{id}/content`) does not return CORS headers (unlike `/v1/messages`), so file
121
+ retrieval for Anthropic is **server-side only** (verified against the API + the official docs).
122
+ OpenAI works in-browser; Google and xAI return files inline (no fetch), so they work too.
16
123
 
17
124
  ## [1.5.0] - 2026-07-06
18
125
 
@@ -145,6 +252,8 @@ First public release.
145
252
  - Service tiers end to end (request → bill → cost).
146
253
  - Cross-environment: runs on Node, Bun, and the browser. ESM, zero runtime deps.
147
254
 
255
+ [1.6.1]: https://github.com/combycode/llm-sdk-ts/releases/tag/v1.6.1
256
+ [1.6.0]: https://github.com/combycode/llm-sdk-ts/releases/tag/v1.6.0
148
257
  [1.2.0]: https://github.com/combycode/llm-sdk-ts/releases/tag/v1.2.0
149
258
  [1.1.0]: https://github.com/combycode/llm-sdk-ts/releases/tag/v1.1.0
150
259
  [1.0.0]: https://github.com/combycode/llm-sdk-ts/releases/tag/v1.0.0