@proveanything/smartlinks 1.7.6 → 1.7.9

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/docs/ai.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SmartLinks AI
2
2
 
3
- Complete guide to using AI capabilities in the SmartLinks SDK, including chat completions, RAG (Retrieval-Augmented Generation), and voice integration.
3
+ Build AI-powered SmartLinks experiences with a practical SDK guide for responses, chat, product assistants, streaming, voice, and real-world integration patterns.
4
4
 
5
5
  ---
6
6
 
@@ -9,6 +9,7 @@ Complete guide to using AI capabilities in the SmartLinks SDK, including chat co
9
9
  - [Overview](#overview)
10
10
  - [Quick Start](#quick-start)
11
11
  - [Authentication](#authentication)
12
+ - [Responses API](#responses-api)
12
13
  - [Chat Completions](#chat-completions)
13
14
  - [RAG: Product Assistants](#rag-product-assistants)
14
15
  - [Voice Integration](#voice-integration)
@@ -25,12 +26,32 @@ Complete guide to using AI capabilities in the SmartLinks SDK, including chat co
25
26
 
26
27
  ## Overview
27
28
 
28
- SmartLinks AI provides four main capabilities:
29
+ This guide is written for SDK users building real products, not backend operators. It focuses on the public SDK surface, recommended starting points, and examples you can adapt directly.
29
30
 
30
- 1. **Chat Completions** - OpenAI-compatible text generation with streaming and tool calling
31
- 2. **RAG (Retrieval-Augmented Generation)** - Document-grounded Q&A for product assistants
32
- 3. **Voice Integration** - Voice-to-text and text-to-voice for hands-free interaction
33
- 4. **Podcast Generation** - NotebookLM-style multi-voice conversational podcasts from documents
31
+ ### Start with the path that matches your job
32
+
33
+ | If you want to... | Start here |
34
+ |---|---|
35
+ | Build a new AI workflow | Use [Responses API](#responses-api) |
36
+ | Add compatibility with existing chat clients | Use [Chat Completions](#chat-completions) |
37
+ | Build a product/manual assistant | Use [RAG: Product Assistants](#rag-product-assistants) |
38
+ | Add spoken input/output | Use [Voice Integration](#voice-integration) |
39
+ | Add progressive rendering | Use [Streaming Responses](#streaming-responses) or [Streaming Chat](#streaming-chat) |
40
+
41
+ ### Recommended starting points
42
+
43
+ - New AI features: start with `ai.chat.responses.create(...)`
44
+ - Product/manual assistants: start with `ai.public.chat(...)`
45
+ - Existing OpenAI-style clients: use `ai.chat.completions.create(...)`
46
+ - Real-time voice: use `ai.public.getToken(...)` and your provider's live client
47
+
48
+ SmartLinks AI provides five main capabilities:
49
+
50
+ 1. **Responses API** - Preferred API for agentic workflows, multimodal inputs, and tool-driven responses
51
+ 2. **Chat Completions** - OpenAI-compatible text generation with streaming and tool calling
52
+ 3. **RAG (Retrieval-Augmented Generation)** - Document-grounded Q&A for product assistants
53
+ 4. **Voice Integration** - Voice-to-text and text-to-voice for hands-free interaction
54
+ 5. **Podcast Generation** - NotebookLM-style multi-voice conversational podcasts from documents
34
55
 
35
56
  ### Key Features
36
57
 
@@ -40,6 +61,7 @@ SmartLinks AI provides four main capabilities:
40
61
  - ✅ Session management for conversations
41
62
  - ✅ Voice input/output helpers
42
63
  - ✅ Tool/function calling support
64
+ - ✅ OpenAI-style Responses API support
43
65
  - ✅ Document indexing and retrieval
44
66
  - ✅ Customizable assistant behavior
45
67
 
@@ -47,6 +69,10 @@ SmartLinks AI provides four main capabilities:
47
69
 
48
70
  ## Quick Start
49
71
 
72
+ If you're only reading one section, start here. The three snippets below cover the most common public SDK use cases.
73
+
74
+ ### 1. Generate a response
75
+
50
76
  ```typescript
51
77
  import { initializeApi, ai } from '@proveanything/smartlinks';
52
78
 
@@ -56,15 +82,44 @@ initializeApi({
56
82
  apiKey: process.env.SMARTLINKS_API_KEY // Required for admin endpoints
57
83
  });
58
84
 
59
- // Simple chat completion
60
- const response = await ai.chat.completions.create('my-collection', {
85
+ // Preferred: create a response
86
+ const response = await ai.chat.responses.create('my-collection', {
61
87
  model: 'google/gemini-2.5-flash',
62
- messages: [
63
- { role: 'user', content: 'Hello!' }
64
- ]
88
+ input: 'Summarize the key safety steps for descaling a coffee maker.'
65
89
  });
66
90
 
67
- console.log(response.choices[0].message.content);
91
+ console.log(response.output_text);
92
+ ```
93
+
94
+ ### 2. Build a product assistant
95
+
96
+ ```typescript
97
+ import { initializeApi, ai } from '@proveanything/smartlinks';
98
+
99
+ initializeApi({ baseURL: 'https://smartlinks.app/api/v1' });
100
+
101
+ const answer = await ai.public.chat('my-collection', {
102
+ productId: 'coffee-maker-deluxe',
103
+ userId: 'user-123',
104
+ message: 'How do I descale this machine?'
105
+ });
106
+
107
+ console.log(answer.message);
108
+ ```
109
+
110
+ ### 3. Stream output into your UI
111
+
112
+ ```typescript
113
+ const stream = await ai.chat.responses.create('my-collection', {
114
+ input: 'Write a launch checklist for a new product page.',
115
+ stream: true
116
+ });
117
+
118
+ for await (const event of stream) {
119
+ if (event.type === 'response.output_text.delta') {
120
+ updateUi(event.delta);
121
+ }
122
+ }
68
123
  ```
69
124
 
70
125
  ---
@@ -90,7 +145,7 @@ Public endpoints don't require an API key but are rate-limited by `userId`:
90
145
 
91
146
  ```typescript
92
147
  // No API key needed
93
- const response = await ai.publicApi.chat({
148
+ const response = await ai.public.chat('my-collection', {
94
149
  productId: 'coffee-maker',
95
150
  userId: 'user-123',
96
151
  message: 'How do I clean this?'
@@ -99,9 +154,108 @@ const response = await ai.publicApi.chat({
99
154
 
100
155
  ---
101
156
 
157
+ ## Responses API
158
+
159
+ The Responses API is the recommended starting point for new integrations. Use it when you want a single endpoint for structured input, tool use, and streaming output.
160
+
161
+ ### Basic Response
162
+
163
+ ```typescript
164
+ const response = await ai.chat.responses.create('my-collection', {
165
+ model: 'google/gemini-2.5-flash',
166
+ input: 'Write a friendly two-sentence welcome for a product assistant.'
167
+ });
168
+
169
+ console.log(response.output_text);
170
+ ```
171
+
172
+ ### Multimessage Input
173
+
174
+ ```typescript
175
+ const response = await ai.chat.responses.create('my-collection', {
176
+ model: 'google/gemini-2.5-flash',
177
+ input: [
178
+ {
179
+ role: 'system',
180
+ content: [
181
+ { type: 'input_text', text: 'You are a concise support assistant.' }
182
+ ]
183
+ },
184
+ {
185
+ role: 'user',
186
+ content: [
187
+ { type: 'input_text', text: 'Give me three troubleshooting steps for a grinder that will not start.' }
188
+ ]
189
+ }
190
+ ]
191
+ });
192
+
193
+ console.log(response.output_text);
194
+ ```
195
+
196
+ ### Streaming Responses
197
+
198
+ When you pass `stream: true`, the SDK returns an `AsyncIterable` of SSE events instead of a final JSON object. You do not need to parse raw SSE frames yourself — just iterate with `for await...of`.
199
+
200
+ ```typescript
201
+ const result = await ai.chat.responses.create('my-collection', {
202
+ input: 'Summarize the manual',
203
+ stream: true
204
+ });
205
+
206
+ for await (const event of result) {
207
+ if (event.type === 'response.output_text.delta') {
208
+ process.stdout.write(event.delta);
209
+ }
210
+ }
211
+ ```
212
+
213
+ If you omit `stream: true`, the same method returns the final `ResponsesResult` object instead.
214
+
215
+ ```typescript
216
+ const stream = await ai.chat.responses.create('my-collection', {
217
+ model: 'google/gemini-2.5-flash',
218
+ input: 'Explain how to descale an espresso machine step by step.',
219
+ stream: true
220
+ });
221
+
222
+ for await (const event of stream) {
223
+ if (event.type === 'response.output_text.delta') {
224
+ process.stdout.write(event.delta);
225
+ }
226
+ }
227
+ ```
228
+
229
+ ### Tool Calling
230
+
231
+ ```typescript
232
+ const response = await ai.chat.responses.create('my-collection', {
233
+ model: 'google/gemini-2.5-flash',
234
+ input: 'What is the weather in Paris?',
235
+ tools: [
236
+ {
237
+ type: 'function',
238
+ name: 'get_weather',
239
+ description: 'Get the current weather for a city',
240
+ parameters: {
241
+ type: 'object',
242
+ properties: {
243
+ location: { type: 'string' }
244
+ },
245
+ required: ['location']
246
+ }
247
+ }
248
+ ]
249
+ });
250
+
251
+ console.log(response.output);
252
+ ```
253
+
254
+ ---
255
+
102
256
  ## Chat Completions
103
257
 
104
- OpenAI-compatible chat completions with streaming and tool calling support.
258
+ OpenAI-compatible chat completions with streaming and tool calling support. Use this for compatibility with existing Chat Completions integrations; prefer the Responses API for new agentic features.
105
259
 
106
260
  ### Basic Chat
107
261
 
@@ -122,6 +276,12 @@ console.log(response.choices[0].message.content);
122
276
 
123
277
  Stream responses in real-time for better UX:
124
278
 
279
+ - Set `stream: true`
280
+ - The SDK returns an `AsyncIterable<ChatCompletionChunk>`
281
+ - Iterate over chunks with `for await...of`
282
+ - Read incremental text from `chunk.choices[0]?.delta?.content`
283
+ - If `stream` is omitted or `false`, the method returns the normal `ChatCompletionResponse`
284
+
125
285
  ```typescript
126
286
  const stream = await ai.chat.completions.create('my-collection', {
127
287
  model: 'google/gemini-2.5-flash',
@@ -188,6 +348,15 @@ if (toolCall) {
188
348
  // List all available models
189
349
  const models = await ai.models.list('my-collection');
190
350
 
351
+ // Or filter by provider / capability
352
+ const openAiModels = await ai.models.list('my-collection', {
353
+ provider: 'openai'
354
+ });
355
+
356
+ const visionModels = await ai.models.list('my-collection', {
357
+ capability: 'vision'
358
+ });
359
+
191
360
  models.data.forEach(model => {
192
361
  console.log(`${model.name}`);
193
362
  console.log(` Provider: ${model.provider}`);
@@ -200,13 +369,18 @@ const model = await ai.models.get('my-collection', 'google/gemini-2.5-flash');
200
369
  console.log(model.capabilities); // ['text', 'vision', 'audio', 'code']
201
370
  ```
202
371
 
372
+ Use `ai.models.list(collectionId)` as the source of truth for what your collection can use at runtime. The public docs provide recommendations, but actual availability depends on the SmartLinks model catalog exposed to that collection.
373
+
203
374
  **Recommended Models:**
204
375
 
205
376
  | Model | Use Case | Speed | Cost |
206
377
  |-------|----------|-------|------|
207
- | `google/gemini-2.5-flash-lite` | Simple Q&A | Fastest | Lowest |
208
- | `google/gemini-2.5-flash` | General purpose | Fast | Low |
209
- | `google/gemini-2.5-pro` | Complex reasoning | Slower | Higher |
378
+ | `openai/gpt-5.4` | Default for new agentic and structured-output workflows | Balanced | Medium |
379
+ | `openai/gpt-5-mini` | Lower-cost general purpose and JSON tasks | Fast | Low |
380
+ | `google/gemini-2.5-flash` | Fast multimodal and cost-sensitive general use | Fast | Low |
381
+ | `google/gemini-2.5-pro` | Complex reasoning and heavier multimodal tasks | Slower | Higher |
382
+
383
+ If you want a safe default for most new work, start with `openai/gpt-5.4`. If you want a lower-cost fallback, use `openai/gpt-5-mini` or `google/gemini-2.5-flash` depending on your latency and pricing goals.
210
384
 
211
385
  ---
212
386
 
@@ -268,7 +442,7 @@ Users can chat with the product assistant without authentication:
268
442
 
269
443
  ```typescript
270
444
  // First question
271
- const response = await ai.publicApiApi.chat('my-collection', {
445
+ const response = await ai.public.chat('my-collection', {
272
446
  productId: 'coffee-maker-deluxe',
273
447
  userId: 'user-123',
274
448
  message: 'How do I descale my coffee maker?'
@@ -328,8 +502,31 @@ console.log('Rate-limited users:', stats.rateLimitedUsers);
328
502
 
329
503
  Enable voice input and output for hands-free interaction.
330
504
 
505
+ ### Voice Patterns
506
+
507
+ The SDK supports three practical voice patterns:
508
+
509
+ | Pattern | Best For | SDK Building Blocks |
510
+ |---------|----------|---------------------|
511
+ | Voice → Text → AI → Text | Manual helper Q&A, troubleshooting steps | `ai.voice.listen()` + `ai.public.chat()` |
512
+ | Voice → Text → AI → Voice | Hands-free assistants, accessibility | `ai.voice.listen()` + `ai.public.chat()` + `ai.voice.speak()` or `ai.tts.generate()` |
513
+ | Real-time Voice | Low-latency spoken conversation | `ai.public.getToken()` + Gemini Live client |
514
+
515
+ ### Current SDK Support
516
+
517
+ - `ai.voice.listen()` and `ai.voice.speak()` are browser helpers built on the Web Speech APIs.
518
+ - `ai.public.getToken()` generates ephemeral tokens for Gemini Live sessions.
519
+ - `ai.tts.generate()` supports server-side text-to-speech generation.
520
+ - The SDK does not currently expose a first-class transcription endpoint like Whisper; if you need that flow, implement it as your own backend endpoint and feed the transcribed text into `ai.public.chat()` or `ai.chat.responses.create()`.
521
+
522
+ ### Recommended Approach
523
+
524
+ For product assistants and RAG-backed support, start with Voice → Text → AI → Text/Voice. It gives you the best control over retrieval, session history, and cost. Use Gemini Live when low-latency spoken conversation matters more than deep document grounding.
525
+
331
526
  ### Browser Voice Helpers
332
527
 
528
+ These helpers are browser-only and rely on native speech recognition / speech synthesis support.
529
+
333
530
  ```typescript
334
531
  // Check if voice is supported
335
532
  if (ai.voice.isSupported()) {
@@ -396,7 +593,7 @@ class ProductVoiceAssistant {
396
593
  }
397
594
 
398
595
  async getRemainingQuestions(): Promise<number> {
399
- const status = await ai.publicApiApi.getRateLimit(this.collectionId, this.userId);
596
+ const status = await ai.public.getRateLimit(this.collectionId, this.userId);
400
597
  return status.remaining;
401
598
  }
402
599
  }
@@ -417,9 +614,11 @@ console.log(`${remaining} questions remaining`);
417
614
 
418
615
  Generate ephemeral tokens for Gemini Live (multimodal voice):
419
616
 
617
+ Use this path for real-time voice sessions. The SDK only issues the short-lived token; the actual live connection is made with the provider client.
618
+
420
619
  ```typescript
421
620
  // Generate token for voice session
422
- const token = await ai.publicApi.getToken('my-collection', {
621
+ const token = await ai.public.getToken('my-collection', {
423
622
  settings: {
424
623
  ttl: 3600, // 1 hour
425
624
  voice: 'alloy',
@@ -434,6 +633,17 @@ console.log('Expires at:', new Date(token.expiresAt));
434
633
  // (See Google's Gemini documentation)
435
634
  ```
436
635
 
636
+ ### Voice + RAG Guidance
637
+
638
+ For document-grounded assistants, prefer this pattern:
639
+
640
+ 1. Capture voice with `ai.voice.listen()` or your own transcription flow.
641
+ 2. Send the transcribed text to `ai.public.chat()`.
642
+ 3. Render the text response for readability.
643
+ 4. Optionally speak the answer with `ai.voice.speak()` or `ai.tts.generate()`.
644
+
645
+ This is usually a better fit for manuals and procedural guidance than trying to use a live voice session as the primary retrieval layer.
646
+
437
647
  ---
438
648
 
439
649
  ## Podcast Generation
@@ -917,7 +1127,7 @@ const audioBlob = await ai.tts.generate('my-collection', {
917
1127
 
918
1128
  ### Public Endpoints
919
1129
 
920
- #### `ai.publicApi.chat(collectionId, request)`
1130
+ #### `ai.public.chat(collectionId, request)`
921
1131
 
922
1132
  Chat with product assistant (no auth required).
923
1133
 
@@ -930,7 +1140,7 @@ Chat with product assistant (no auth required).
930
1140
 
931
1141
  ---
932
1142
 
933
- #### `ai.publicApi.getSession(collectionId, sessionId)`
1143
+ #### `ai.public.getSession(collectionId, sessionId)`
934
1144
 
935
1145
  Get conversation history.
936
1146
 
@@ -938,7 +1148,7 @@ Get conversation history.
938
1148
 
939
1149
  ---
940
1150
 
941
- #### `ai.publicApi.clearSession(collectionId, sessionId)`
1151
+ #### `ai.public.clearSession(collectionId, sessionId)`
942
1152
 
943
1153
  Clear conversation history.
944
1154
 
@@ -946,7 +1156,7 @@ Clear conversation history.
946
1156
 
947
1157
  ---
948
1158
 
949
- #### `ai.publicApi.getRateLimit(collectionId, userId)`
1159
+ #### `ai.public.getRateLimit(collectionId, userId)`
950
1160
 
951
1161
  Check rate limit status.
952
1162
 
@@ -954,7 +1164,7 @@ Check rate limit status.
954
1164
 
955
1165
  ---
956
1166
 
957
- #### `ai.publicApi.getToken(collectionId, request)`
1167
+ #### `ai.public.getToken(collectionId, request)`
958
1168
 
959
1169
  Generate ephemeral token for Gemini Live.
960
1170
 
@@ -985,7 +1195,7 @@ async function createProductFAQ() {
985
1195
  });
986
1196
 
987
1197
  // 3. Answer user questions
988
- const answer = await ai.publicApi.chat(collectionId, {
1198
+ const answer = await ai.public.chat(collectionId, {
989
1199
  productId,
990
1200
  userId: 'user-123',
991
1201
  message: 'How do I make espresso?'
@@ -1032,7 +1242,7 @@ async function chatConversation() {
1032
1242
  const productId = 'coffee-maker-deluxe';
1033
1243
 
1034
1244
  // Question 1
1035
- const a1 = await ai.publicApi.chat(collectionId, {
1245
+ const a1 = await ai.public.chat(collectionId, {
1036
1246
  productId,
1037
1247
  userId,
1038
1248
  message: 'How do I clean the machine?',
@@ -1041,7 +1251,7 @@ async function chatConversation() {
1041
1251
  console.log('A1:', a1.message);
1042
1252
 
1043
1253
  // Question 2 (references previous context)
1044
- const a2 = await ai.publicApi.chat(collectionId, {
1254
+ const a2 = await ai.public.chat(collectionId, {
1045
1255
  productId,
1046
1256
  userId,
1047
1257
  message: 'How often should I do that?',
@@ -1050,7 +1260,7 @@ async function chatConversation() {
1050
1260
  console.log('A2:', a2.message);
1051
1261
 
1052
1262
  // Get full history
1053
- const session = await ai.publicApi.getSession(collectionId, sessionId);
1263
+ const session = await ai.public.getSession(collectionId, sessionId);
1054
1264
  console.log('Full conversation:', session.messages);
1055
1265
  }
1056
1266
  ```
@@ -1075,7 +1285,7 @@ export function useProductAssistant(
1075
1285
  setError(null);
1076
1286
 
1077
1287
  try {
1078
- const response = await ai.publicApi.chat(collectionId, {
1288
+ const response = await ai.public.chat(collectionId, {
1079
1289
  productId,
1080
1290
  userId,
1081
1291
  message
@@ -1251,7 +1461,7 @@ import { SmartLinksAIError } from '@proveanything/smartlinks';
1251
1461
 
1252
1462
  async function robustChat() {
1253
1463
  try {
1254
- const response = await ai.publicApi.chat('my-collection', {
1464
+ const response = await ai.public.chat('my-collection', {
1255
1465
  productId: 'coffee-maker',
1256
1466
  userId: 'user-123',
1257
1467
  message: 'Help!'
@@ -1295,7 +1505,7 @@ async function chatWithRetry(
1295
1505
 
1296
1506
  while (retries < maxRetries) {
1297
1507
  try {
1298
- return await ai.publicApi.chat('my-collection', request);
1508
+ return await ai.public.chat('my-collection', request);
1299
1509
  } catch (error) {
1300
1510
  if (error instanceof SmartLinksAIError && error.isRateLimitError()) {
1301
1511
  if (retries === maxRetries - 1) throw error;
@@ -1345,7 +1555,7 @@ X-RateLimit-Reset: 1707300000000
1345
1555
 
1346
1556
  ```typescript
1347
1557
  // Check rate limit status before making requests
1348
- const status = await ai.publicApi.getRateLimit('my-collection', 'user-123');
1558
+ const status = await ai.public.getRateLimit('my-collection', 'user-123');
1349
1559
 
1350
1560
  console.log('Used:', status.used);
1351
1561
  console.log('Remaining:', status.remaining);
@@ -1353,7 +1563,7 @@ console.log('Resets at:', new Date(status.resetAt));
1353
1563
 
1354
1564
  if (status.remaining > 0) {
1355
1565
  // Safe to make request
1356
- await ai.publicApi.chat(/* ... */);
1566
+ await ai.public.chat(/* ... */);
1357
1567
  } else {
1358
1568
  // Show user when they can ask again
1359
1569
  console.log('Rate limit reached. Try again at:', status.resetAt);
@@ -1375,23 +1585,27 @@ console.log('Rate limit reset for user-123');
1375
1585
  ### 1. Choose the Right Model
1376
1586
 
1377
1587
  ```typescript
1378
- // For simple Q&A (fast, cheap)
1379
- await ai.chat.completions.create('my-collection', {
1380
- model: 'google/gemini-2.5-flash-lite',
1381
- messages: [...]
1588
+ // For most new workflows (recommended default)
1589
+ await ai.chat.responses.create('my-collection', {
1590
+ model: 'openai/gpt-5.4',
1591
+ input: 'Create a concise onboarding checklist.'
1382
1592
  });
1383
1593
 
1384
- // For general use (balanced)
1385
- await ai.chat.completions.create('my-collection', {
1386
- model: 'google/gemini-2.5-flash',
1387
- messages: [...]
1594
+ // For lower-cost structured or JSON-oriented work
1595
+ await ai.chat.responses.create('my-collection', {
1596
+ model: 'openai/gpt-5-mini',
1597
+ input: 'Return a color palette as JSON.'
1388
1598
  });
1389
1599
 
1390
- // For complex reasoning (powerful)
1600
+ // For fast multimodal or cost-sensitive general use
1391
1601
  await ai.chat.completions.create('my-collection', {
1392
- model: 'google/gemini-2.5-pro',
1602
+ model: 'google/gemini-2.5-flash',
1393
1603
  messages: [...]
1394
1604
  });
1605
+
1606
+ // When you need the actual available catalog for this collection
1607
+ const available = await ai.models.list('my-collection');
1608
+ console.log(available.data.map(model => model.id));
1395
1609
  ```
1396
1610
 
1397
1611
  ### 2. Use Streaming for Long Responses
@@ -1443,7 +1657,7 @@ Show clear feedback to users:
1443
1657
 
1444
1658
  ```typescript
1445
1659
  try {
1446
- await ai.publicApi.chat('my-collection', {...});
1660
+ await ai.public.chat('my-collection', {...});
1447
1661
  } catch (error) {
1448
1662
  if (error instanceof SmartLinksAIError && error.isRateLimitError()) {
1449
1663
  const resetTime = new Date(error.resetAt!);
@@ -1649,7 +1863,7 @@ interface AIContentResponse {
1649
1863
 
1650
1864
  /**
1651
1865
  * Pre-built RAG configuration. When provided, the assistant can use
1652
- * SL.ai.public.chat() to ground answers in indexed product documents.
1866
+ * SL.ai.public.chat() to ground answers in indexed product documents.
1653
1867
  */
1654
1868
  ragHint?: {
1655
1869
  /** The product ID whose indexed documents should be queried */
@@ -1669,7 +1883,7 @@ interface AIContentResponse {
1669
1883
  /**
1670
1884
  * How the assistant should use this content:
1671
1885
  * - 'context' (default): inject text into the system prompt
1672
- * - 'rag': use ragHint to query indexed docs via SL.ai.public.chat()
1886
+ * - 'rag': use ragHint to query indexed docs via SL.ai.public.chat()
1673
1887
  * - 'hybrid': inject text as context AND ground answers via RAG
1674
1888
  */
1675
1889
  strategy?: 'context' | 'rag' | 'hybrid';