@savantoai/ai-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.
- package/CHANGELOG.md +65 -0
- package/README.md +7 -2
- package/dist/index.cjs +4 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1266 -12
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1266 -12
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,71 @@ under semver, meaning:
|
|
|
30
30
|
caret update. Bumping that range is itself a major-version event for the
|
|
31
31
|
SDK.
|
|
32
32
|
|
|
33
|
+
## 3.1.0 — 2026-05-19
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- Search responses may include `query.truncated` and `query.originalLength` on
|
|
38
|
+
product and post search when the input text was shortened server-side.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- **`POST /recommendations`** response type now uses the standard
|
|
43
|
+
`{ object, requestId, data }` envelope (`object: "recommendations"`).
|
|
44
|
+
Payload fields remain under `data`.
|
|
45
|
+
- **OpenAPI alignment** for non-streaming `POST /chat` and `POST /threads/search`
|
|
46
|
+
(documented envelopes; chat wire format unchanged if you already read `data`).
|
|
47
|
+
- **`POST /threads/search`** list field is `data.items` in generated types (matches
|
|
48
|
+
the handler; replaces any `results` naming in older spec snapshots).
|
|
49
|
+
|
|
50
|
+
### Breaking (TypeScript)
|
|
51
|
+
|
|
52
|
+
- **`Product.stockStatus` and `Product.type`** are strict enums. Values outside
|
|
53
|
+
`instock | outofstock | onbackorder` and `simple | grouped | external | variable`
|
|
54
|
+
are omitted at runtime and absent from the type.
|
|
55
|
+
- Any client code that assumed recommendations returned only `{ data: T }` at the
|
|
56
|
+
top level should use the generated `PostRecommendationsResponse` type (includes
|
|
57
|
+
`object` and `requestId`).
|
|
58
|
+
|
|
59
|
+
## Unreleased
|
|
60
|
+
|
|
61
|
+
### Breaking — streaming chat protocol
|
|
62
|
+
|
|
63
|
+
> The SDK's TypeScript surface is unchanged, but the **wire protocol** for
|
|
64
|
+
> the `/chat` streaming endpoint has been rewritten. Any client code that
|
|
65
|
+
> switches on `chunk.type` (including code generated against earlier
|
|
66
|
+
> versions of this README's example) must be migrated. The SDK is not
|
|
67
|
+
> under semver for the wire protocol — see _Versioning policy_ above —
|
|
68
|
+
> but we're flagging this prominently because real client switches will
|
|
69
|
+
> silently stop matching after this rollout.
|
|
70
|
+
|
|
71
|
+
The `/chat` streaming protocol has been rewritten to a block-based shape.
|
|
72
|
+
The legacy `text_delta`, `product`, `post`, `post_delta`, and `bubble_termination`
|
|
73
|
+
chunk types are gone; the new types are `block_start`, `block_delta`, `block_data`,
|
|
74
|
+
`item_delta`, and `block_end`, plus existing flow-control chunks (`progress`,
|
|
75
|
+
`prompts`, `metadata`, `complete`, `error`, `domain_offer`, `domain_offer_success`,
|
|
76
|
+
`agent_status`, `handoff_ended`, `analytics`, `usage`).
|
|
77
|
+
|
|
78
|
+
Migration cheat-sheet for code switching on `chunk.type`:
|
|
79
|
+
|
|
80
|
+
| Old chunk type | New chunk type |
|
|
81
|
+
| --------------------- | -------------------------------------------------------------- |
|
|
82
|
+
| `text_delta` | `block_delta` (read `chunk.data.content`) |
|
|
83
|
+
| `product` / `post` | `block_data` (full payload) + `block_start` (ordering) |
|
|
84
|
+
| `post_delta` | `item_delta` (read `chunk.data.field` + `chunk.data.delta`) |
|
|
85
|
+
| `bubble_termination` | (removed — single message bubble per turn now) |
|
|
86
|
+
|
|
87
|
+
The SDK's exported `ChatStreamChunk` type is intentionally unchanged
|
|
88
|
+
(`{ type: string; data?: unknown }`) — no SDK regen is required. See
|
|
89
|
+
the [Streaming Chat docs](https://savanto.ai/docs/developers/streaming)
|
|
90
|
+
for the full chunk reference and a worked React example.
|
|
91
|
+
|
|
92
|
+
The streaming `chat.message_sent` webhook payload has also picked up
|
|
93
|
+
`responseMessage.respondedBy` (which domain answered) and
|
|
94
|
+
`responseMessage.composedBlocks` (a tiny `{ type, ids }[]` describing
|
|
95
|
+
the structured blocks the composer wove together for multi-domain answers).
|
|
96
|
+
See the [Webhooks docs](https://savanto.ai/docs/developers/webhooks#chatmessage_sent).
|
|
97
|
+
|
|
33
98
|
## 3.0.0 — 2026-05-12
|
|
34
99
|
|
|
35
100
|
### Breaking (TypeScript)
|
package/README.md
CHANGED
|
@@ -114,7 +114,12 @@ const { data, response } = await chat({
|
|
|
114
114
|
throwOnError: true,
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
// For streaming (NDJSON), read the response body directly
|
|
117
|
+
// For streaming (NDJSON), read the response body directly. The protocol is
|
|
118
|
+
// block-based: text streams as `block_delta` chunks inside an active text
|
|
119
|
+
// block, structured items arrive as `block_data` keyed by item id, and
|
|
120
|
+
// per-field streaming (post summaries, product reasons, etc.) flows through
|
|
121
|
+
// `item_delta`. See https://savanto.ai/docs/developers/streaming for the
|
|
122
|
+
// full chunk-type reference.
|
|
118
123
|
const reader = response.body!.getReader();
|
|
119
124
|
const decoder = new TextDecoder();
|
|
120
125
|
|
|
@@ -124,7 +129,7 @@ while (true) {
|
|
|
124
129
|
const lines = decoder.decode(value).split('\n').filter(Boolean);
|
|
125
130
|
for (const line of lines) {
|
|
126
131
|
const chunk = JSON.parse(line);
|
|
127
|
-
if (chunk.type === '
|
|
132
|
+
if (chunk.type === 'block_delta') process.stdout.write(chunk.data.content);
|
|
128
133
|
}
|
|
129
134
|
}
|
|
130
135
|
```
|
package/dist/index.cjs
CHANGED
|
@@ -325,8 +325,8 @@ const checkForExistence = (options, name) => {
|
|
|
325
325
|
if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) return true;
|
|
326
326
|
return false;
|
|
327
327
|
};
|
|
328
|
-
|
|
329
|
-
for (const auth of security) {
|
|
328
|
+
async function setAuthParams(options) {
|
|
329
|
+
for (const auth of options.security ?? []) {
|
|
330
330
|
if (checkForExistence(options, auth.name)) continue;
|
|
331
331
|
const token = await getAuthToken(auth, options.auth);
|
|
332
332
|
if (!token) continue;
|
|
@@ -344,7 +344,7 @@ const setAuthParams = async ({ security, ...options }) => {
|
|
|
344
344
|
break;
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
|
-
}
|
|
347
|
+
}
|
|
348
348
|
const buildUrl = (options) => getUrl({
|
|
349
349
|
baseUrl: options.baseUrl,
|
|
350
350
|
path: options.path,
|
|
@@ -454,10 +454,7 @@ const createClient = (config = {}) => {
|
|
|
454
454
|
headers: mergeHeaders(_config.headers, options.headers),
|
|
455
455
|
serializedBody: void 0
|
|
456
456
|
};
|
|
457
|
-
if (opts.security) await setAuthParams(
|
|
458
|
-
...opts,
|
|
459
|
-
security: opts.security
|
|
460
|
-
});
|
|
457
|
+
if (opts.security) await setAuthParams(opts);
|
|
461
458
|
if (opts.requestValidator) await opts.requestValidator(opts);
|
|
462
459
|
if (opts.body !== void 0 && opts.bodySerializer) opts.serializedBody = opts.bodySerializer(opts.body);
|
|
463
460
|
if (opts.body === void 0 || opts.serializedBody === "") opts.headers.delete("Content-Type");
|