@proveanything/smartlinks 1.7.2 → 1.7.4
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/dist/api/comms.d.ts +1 -1
- package/dist/api/comms.js +2 -2
- package/dist/api/proof.d.ts +38 -0
- package/dist/api/proof.js +40 -0
- package/dist/docs/API_SUMMARY.md +10 -3
- package/dist/docs/ai.md +289 -0
- package/dist/docs/comms.md +1 -1
- package/dist/docs/scanner-container.md +556 -0
- package/dist/http.js +30 -1
- package/dist/openapi.yaml +77 -33
- package/dist/types/comms.d.ts +1 -1
- package/docs/API_SUMMARY.md +10 -3
- package/docs/ai.md +289 -0
- package/docs/comms.md +1 -1
- package/docs/scanner-container.md +556 -0
- package/openapi.yaml +77 -33
- package/package.json +1 -1
package/dist/openapi.yaml
CHANGED
|
@@ -2138,6 +2138,39 @@ paths:
|
|
|
2138
2138
|
description: Unauthorized
|
|
2139
2139
|
404:
|
|
2140
2140
|
description: Not found
|
|
2141
|
+
/admin/collection/{collectionId}/comm.send:
|
|
2142
|
+
post:
|
|
2143
|
+
tags:
|
|
2144
|
+
- comms
|
|
2145
|
+
summary: Send a single transactional message to one contact using a template.
|
|
2146
|
+
operationId: comms_sendTransactional
|
|
2147
|
+
security:
|
|
2148
|
+
- bearerAuth: []
|
|
2149
|
+
parameters:
|
|
2150
|
+
- name: collectionId
|
|
2151
|
+
in: path
|
|
2152
|
+
required: true
|
|
2153
|
+
schema:
|
|
2154
|
+
type: string
|
|
2155
|
+
responses:
|
|
2156
|
+
200:
|
|
2157
|
+
description: Success
|
|
2158
|
+
content:
|
|
2159
|
+
application/json:
|
|
2160
|
+
schema:
|
|
2161
|
+
$ref: "#/components/schemas/TransactionalSendResult"
|
|
2162
|
+
400:
|
|
2163
|
+
description: Bad request
|
|
2164
|
+
401:
|
|
2165
|
+
description: Unauthorized
|
|
2166
|
+
404:
|
|
2167
|
+
description: Not found
|
|
2168
|
+
requestBody:
|
|
2169
|
+
required: true
|
|
2170
|
+
content:
|
|
2171
|
+
application/json:
|
|
2172
|
+
schema:
|
|
2173
|
+
$ref: "#/components/schemas/TransactionalSendRequest"
|
|
2141
2174
|
/admin/collection/{collectionId}/comm.settings:
|
|
2142
2175
|
patch:
|
|
2143
2176
|
tags:
|
|
@@ -2421,39 +2454,6 @@ paths:
|
|
|
2421
2454
|
application/json:
|
|
2422
2455
|
schema:
|
|
2423
2456
|
$ref: "#/components/schemas/CommsRecipientsWithoutActionQuery"
|
|
2424
|
-
/admin/collection/{collectionId}/comm/send:
|
|
2425
|
-
post:
|
|
2426
|
-
tags:
|
|
2427
|
-
- comms
|
|
2428
|
-
summary: Send a single transactional message to one contact using a template.
|
|
2429
|
-
operationId: comms_sendTransactional
|
|
2430
|
-
security:
|
|
2431
|
-
- bearerAuth: []
|
|
2432
|
-
parameters:
|
|
2433
|
-
- name: collectionId
|
|
2434
|
-
in: path
|
|
2435
|
-
required: true
|
|
2436
|
-
schema:
|
|
2437
|
-
type: string
|
|
2438
|
-
responses:
|
|
2439
|
-
200:
|
|
2440
|
-
description: Success
|
|
2441
|
-
content:
|
|
2442
|
-
application/json:
|
|
2443
|
-
schema:
|
|
2444
|
-
$ref: "#/components/schemas/TransactionalSendResult"
|
|
2445
|
-
400:
|
|
2446
|
-
description: Bad request
|
|
2447
|
-
401:
|
|
2448
|
-
description: Unauthorized
|
|
2449
|
-
404:
|
|
2450
|
-
description: Not found
|
|
2451
|
-
requestBody:
|
|
2452
|
-
required: true
|
|
2453
|
-
content:
|
|
2454
|
-
application/json:
|
|
2455
|
-
schema:
|
|
2456
|
-
$ref: "#/components/schemas/TransactionalSendRequest"
|
|
2457
2457
|
/admin/collection/{collectionId}/contacts:
|
|
2458
2458
|
get:
|
|
2459
2459
|
tags:
|
|
@@ -5203,6 +5203,50 @@ paths:
|
|
|
5203
5203
|
description: Unauthorized
|
|
5204
5204
|
404:
|
|
5205
5205
|
description: Not found
|
|
5206
|
+
/admin/collection/{collectionId}/products/{productId}/proofs/{proofId}/migrate:
|
|
5207
|
+
post:
|
|
5208
|
+
tags:
|
|
5209
|
+
- proof
|
|
5210
|
+
summary: proof.migrate
|
|
5211
|
+
operationId: proof_migrate
|
|
5212
|
+
security:
|
|
5213
|
+
- bearerAuth: []
|
|
5214
|
+
parameters:
|
|
5215
|
+
- name: collectionId
|
|
5216
|
+
in: path
|
|
5217
|
+
required: true
|
|
5218
|
+
schema:
|
|
5219
|
+
type: string
|
|
5220
|
+
- name: productId
|
|
5221
|
+
in: path
|
|
5222
|
+
required: true
|
|
5223
|
+
schema:
|
|
5224
|
+
type: string
|
|
5225
|
+
- name: proofId
|
|
5226
|
+
in: path
|
|
5227
|
+
required: true
|
|
5228
|
+
schema:
|
|
5229
|
+
type: string
|
|
5230
|
+
responses:
|
|
5231
|
+
200:
|
|
5232
|
+
description: Success
|
|
5233
|
+
content:
|
|
5234
|
+
application/json:
|
|
5235
|
+
schema:
|
|
5236
|
+
$ref: "#/components/schemas/ProofResponse"
|
|
5237
|
+
400:
|
|
5238
|
+
description: Bad request
|
|
5239
|
+
401:
|
|
5240
|
+
description: Unauthorized
|
|
5241
|
+
404:
|
|
5242
|
+
description: Not found
|
|
5243
|
+
requestBody:
|
|
5244
|
+
required: true
|
|
5245
|
+
content:
|
|
5246
|
+
application/json:
|
|
5247
|
+
schema:
|
|
5248
|
+
type: object
|
|
5249
|
+
additionalProperties: true
|
|
5206
5250
|
/admin/collection/{collectionId}/proof/findByUser/{userId}:
|
|
5207
5251
|
get:
|
|
5208
5252
|
tags:
|
package/dist/types/comms.d.ts
CHANGED
|
@@ -280,7 +280,7 @@ export interface SubscriptionsResolveResponse {
|
|
|
280
280
|
* No broadcast record is created; the send is logged directly to the
|
|
281
281
|
* contact's communication history with sourceType: 'transactional'.
|
|
282
282
|
*
|
|
283
|
-
* POST /admin/collection/:collectionId/comm
|
|
283
|
+
* POST /admin/collection/:collectionId/comm.send
|
|
284
284
|
*/
|
|
285
285
|
export interface TransactionalSendRequest {
|
|
286
286
|
/** CRM contact UUID */
|
package/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.4 | Generated: 2026-03-10T14:18:07.271Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -3006,7 +3006,7 @@ export interface SubscriptionsResolveResponse {
|
|
|
3006
3006
|
* No broadcast record is created; the send is logged directly to the
|
|
3007
3007
|
* contact's communication history with sourceType: 'transactional'.
|
|
3008
3008
|
*
|
|
3009
|
-
* POST /admin/collection/:collectionId/comm
|
|
3009
|
+
* POST /admin/collection/:collectionId/comm.send
|
|
3010
3010
|
*/
|
|
3011
3011
|
export interface TransactionalSendRequest {
|
|
3012
3012
|
/** CRM contact UUID */
|
|
@@ -5978,7 +5978,7 @@ Analytics: Recipients who performed an action, optionally with outcome. POST /ad
|
|
|
5978
5978
|
|
|
5979
5979
|
**sendTransactional**(collectionId: string,
|
|
5980
5980
|
body: TransactionalSendRequest) → `Promise<TransactionalSendResult>`
|
|
5981
|
-
Send a single transactional message to one contact using a template. No broadcast record is created. The send is logged to the contact's communication history with sourceType: 'transactional'. POST /admin/collection/:collectionId/comm
|
|
5981
|
+
Send a single transactional message to one contact using a template. No broadcast record is created. The send is logged to the contact's communication history with sourceType: 'transactional'. POST /admin/collection/:collectionId/comm.send ```typescript const result = await comms.sendTransactional(collectionId, { contactId: 'e4f2a1b0-...', templateId: 'warranty-update', channel: 'preferred', props: { claimRef: 'CLM-0042', decision: 'approved' }, include: { productId: 'prod-abc123', appCase: 'c9d1e2f3-...' }, ref: 'warranty-decision-notification', appId: 'warrantyApp', }) if (result.ok) { console.log(`Sent via ${result.channel}`, result.messageId) } else { console.error('Send failed:', result.error) } ```
|
|
5982
5982
|
|
|
5983
5983
|
**logCommunicationEvent**(collectionId: string,
|
|
5984
5984
|
body: LogCommunicationEventBody) → `Promise<AppendResult>`
|
|
@@ -6470,6 +6470,13 @@ Find proofs for a product (admin only). POST /admin/collection/:collectionId/pro
|
|
|
6470
6470
|
batchId: string) → `Promise<ProofResponse[]>`
|
|
6471
6471
|
Get proofs for a batch (admin only). GET /admin/collection/:collectionId/product/:productId/batch/:batchId/proof
|
|
6472
6472
|
|
|
6473
|
+
**migrate**(collectionId: string,
|
|
6474
|
+
productId: string,
|
|
6475
|
+
proofId: string,
|
|
6476
|
+
/** The destination product ID */
|
|
6477
|
+
data: { targetProductId: string }) → `Promise<ProofResponse>`
|
|
6478
|
+
Migrate a proof to a different product within the same collection (admin only). Because the Firestore ledger document ID is `{productId}-{proofId}`, a proof cannot simply be re-assigned to another product by updating a field — the document must be re-keyed. This endpoint handles that atomically: 1. Reads the source ledger document (`{sourceProductId}-{proofId}`). 2. Writes a new document (`{targetProductId}-{proofId}`) with `productId` and `proofGroup` updated. The short `proofId` (nanoid) is unchanged. 3. Writes a migration history entry to the new document's `history` subcollection (snapshot of the original proof + migration metadata). 4. Copies all subcollections — `assets`, `attestations`, `history` — from the old document to the new one. 5. Deletes the old subcollections and then the old document. Repeated migrations are safe — each one appends a history record; no migration metadata is stored on the proof document itself. ```typescript const migrated = await proof.migrate('coll_123', 'prod_old', 'proof_abc', { targetProductId: 'prod_new', }) console.log(migrated.productId) // 'prod_new' ```
|
|
6479
|
+
|
|
6473
6480
|
### qr
|
|
6474
6481
|
|
|
6475
6482
|
**lookupShortCode**(shortId: string, code: string) → `Promise<QrShortCodeLookupResponse>`
|
package/docs/ai.md
CHANGED
|
@@ -19,6 +19,7 @@ Complete guide to using AI capabilities in the SmartLinks SDK, including chat co
|
|
|
19
19
|
- [Error Handling](#error-handling)
|
|
20
20
|
- [Rate Limiting](#rate-limiting)
|
|
21
21
|
- [Best Practices](#best-practices)
|
|
22
|
+
- [Providing Content to the AI Assistant](#providing-content-to-the-ai-assistant)
|
|
22
23
|
|
|
23
24
|
---
|
|
24
25
|
|
|
@@ -1547,6 +1548,294 @@ console.log('Estimated cost: $', cost.toFixed(4));
|
|
|
1547
1548
|
|
|
1548
1549
|
---
|
|
1549
1550
|
|
|
1551
|
+
## Providing Content to the AI Assistant
|
|
1552
|
+
|
|
1553
|
+
The portal's built-in AI assistant can discuss the content currently visible to the user. To make this work, your app must supply contextual content when the assistant requests it. There are three extraction methods, tried in priority order:
|
|
1554
|
+
|
|
1555
|
+
| Priority | Method | When Used |
|
|
1556
|
+
|----------|--------|-----------|
|
|
1557
|
+
| 1 | **Direct prop callback** | Container/widget rendered in the parent React context |
|
|
1558
|
+
| 2 | **PostMessage protocol** | App rendered in an iframe |
|
|
1559
|
+
| 3 | **DOM text fallback** | Neither of the above responded |
|
|
1560
|
+
|
|
1561
|
+
This section covers **methods 1 and 2** — the ones you implement in your app.
|
|
1562
|
+
|
|
1563
|
+
### Method 1: Direct Prop (`onRequestAIContent`)
|
|
1564
|
+
|
|
1565
|
+
When your app is rendered as a **container** (a direct component in the parent's React tree), the framework passes an `onRequestAIContent` prop to your exported component. You do **not** call this prop yourself — the framework calls it when the AI assistant needs context.
|
|
1566
|
+
|
|
1567
|
+
Structure your component to make current state accessible when the callback fires:
|
|
1568
|
+
|
|
1569
|
+
```tsx
|
|
1570
|
+
import { useEffect, useRef } from 'react';
|
|
1571
|
+
|
|
1572
|
+
export function PublicContainer(props) {
|
|
1573
|
+
const { onRequestAIContent, appId, ...rest } = props;
|
|
1574
|
+
|
|
1575
|
+
// Keep a ref to the latest content so the callback always returns fresh data
|
|
1576
|
+
const currentContentRef = useRef(null);
|
|
1577
|
+
|
|
1578
|
+
useEffect(() => {
|
|
1579
|
+
currentContentRef.current = buildCurrentContent();
|
|
1580
|
+
}, [relevantState]);
|
|
1581
|
+
|
|
1582
|
+
return <div data-app-container={appId}>{/* your UI */}</div>;
|
|
1583
|
+
}
|
|
1584
|
+
```
|
|
1585
|
+
|
|
1586
|
+
The framework registers the content provider internally via `useAIContentExtraction.registerContentProvider()`. Your component just needs to respond when the callback is invoked.
|
|
1587
|
+
|
|
1588
|
+
### Method 2: PostMessage Protocol (Iframes)
|
|
1589
|
+
|
|
1590
|
+
For iframe-embedded apps the framework sends a `postMessage` request and expects a response within **500 ms**. If your app doesn't reply in time the framework falls back to DOM text extraction.
|
|
1591
|
+
|
|
1592
|
+
**Request sent by the framework to your iframe:**
|
|
1593
|
+
|
|
1594
|
+
```typescript
|
|
1595
|
+
{
|
|
1596
|
+
type: 'smartlinks:request-ai-content',
|
|
1597
|
+
requestId: 'ai-content-1709834567890-abc123' // unique per request
|
|
1598
|
+
}
|
|
1599
|
+
```
|
|
1600
|
+
|
|
1601
|
+
**Response your app must send back:**
|
|
1602
|
+
|
|
1603
|
+
```typescript
|
|
1604
|
+
{
|
|
1605
|
+
type: 'smartlinks:ai-content-response',
|
|
1606
|
+
requestId: 'ai-content-1709834567890-abc123', // echo back the requestId
|
|
1607
|
+
content: AIContentResponse
|
|
1608
|
+
}
|
|
1609
|
+
```
|
|
1610
|
+
|
|
1611
|
+
**Minimal implementation:**
|
|
1612
|
+
|
|
1613
|
+
```typescript
|
|
1614
|
+
window.addEventListener('message', async (event) => {
|
|
1615
|
+
if (event.data?.type === 'smartlinks:request-ai-content') {
|
|
1616
|
+
const content = await gatherAIContent();
|
|
1617
|
+
|
|
1618
|
+
window.parent.postMessage({
|
|
1619
|
+
type: 'smartlinks:ai-content-response',
|
|
1620
|
+
requestId: event.data.requestId,
|
|
1621
|
+
content,
|
|
1622
|
+
}, '*');
|
|
1623
|
+
}
|
|
1624
|
+
});
|
|
1625
|
+
|
|
1626
|
+
async function gatherAIContent(): Promise<AIContentResponse> {
|
|
1627
|
+
return {
|
|
1628
|
+
text: 'The user is viewing the warranty registration form...',
|
|
1629
|
+
contentLabel: 'Warranty Registration',
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
```
|
|
1633
|
+
|
|
1634
|
+
### The `AIContentResponse` Interface
|
|
1635
|
+
|
|
1636
|
+
```typescript
|
|
1637
|
+
interface AIContentResponse {
|
|
1638
|
+
/**
|
|
1639
|
+
* Plain text or markdown for the AI to use as context.
|
|
1640
|
+
* Injected into the system prompt. Max recommended: ~4000 characters.
|
|
1641
|
+
*/
|
|
1642
|
+
text: string;
|
|
1643
|
+
|
|
1644
|
+
/**
|
|
1645
|
+
* Optional structured metadata (key-value pairs).
|
|
1646
|
+
* Not used directly in prompts but available for custom providers.
|
|
1647
|
+
*/
|
|
1648
|
+
metadata?: Record<string, unknown>;
|
|
1649
|
+
|
|
1650
|
+
/**
|
|
1651
|
+
* Pre-built RAG configuration. When provided, the assistant can use
|
|
1652
|
+
* SL.ai.public.chat() to ground answers in indexed product documents.
|
|
1653
|
+
*/
|
|
1654
|
+
ragHint?: {
|
|
1655
|
+
/** The product ID whose indexed documents should be queried */
|
|
1656
|
+
productId: string;
|
|
1657
|
+
/** Optional session ID for multi-turn RAG conversations */
|
|
1658
|
+
sessionId?: string;
|
|
1659
|
+
/** Optional context hint to help scope the RAG query */
|
|
1660
|
+
context?: string;
|
|
1661
|
+
};
|
|
1662
|
+
|
|
1663
|
+
/**
|
|
1664
|
+
* Human-readable label shown in context-update messages
|
|
1665
|
+
* (e.g. "Product Manual", "FAQ").
|
|
1666
|
+
*/
|
|
1667
|
+
contentLabel?: string;
|
|
1668
|
+
|
|
1669
|
+
/**
|
|
1670
|
+
* How the assistant should use this content:
|
|
1671
|
+
* - 'context' (default): inject text into the system prompt
|
|
1672
|
+
* - 'rag': use ragHint to query indexed docs via SL.ai.public.chat()
|
|
1673
|
+
* - 'hybrid': inject text as context AND ground answers via RAG
|
|
1674
|
+
*/
|
|
1675
|
+
strategy?: 'context' | 'rag' | 'hybrid';
|
|
1676
|
+
}
|
|
1677
|
+
```
|
|
1678
|
+
|
|
1679
|
+
### Response Strategies
|
|
1680
|
+
|
|
1681
|
+
#### `context` (Default)
|
|
1682
|
+
|
|
1683
|
+
Return readable text. The assistant injects it into the system prompt as background knowledge. Good for descriptions, summaries, structured data, and FAQs.
|
|
1684
|
+
|
|
1685
|
+
```typescript
|
|
1686
|
+
return {
|
|
1687
|
+
text: `
|
|
1688
|
+
## Wine Details
|
|
1689
|
+
- **Name**: 2023 Château Margaux
|
|
1690
|
+
- **Region**: Bordeaux, France
|
|
1691
|
+
- **Tasting Notes**: Dark fruit, cedar, tobacco
|
|
1692
|
+
- **Food Pairing**: Lamb, aged cheese
|
|
1693
|
+
`,
|
|
1694
|
+
contentLabel: 'Wine Information',
|
|
1695
|
+
strategy: 'context',
|
|
1696
|
+
};
|
|
1697
|
+
```
|
|
1698
|
+
|
|
1699
|
+
#### `rag`
|
|
1700
|
+
|
|
1701
|
+
Tell the assistant to query pre-indexed documents via SmartLinks RAG. The `text` field is minimal — the real knowledge comes from the indexed docs. Good for product manuals, large document sets, and technical specs.
|
|
1702
|
+
|
|
1703
|
+
```typescript
|
|
1704
|
+
return {
|
|
1705
|
+
text: 'The user is viewing the espresso machine product page.',
|
|
1706
|
+
contentLabel: 'Product Assistant',
|
|
1707
|
+
strategy: 'rag',
|
|
1708
|
+
ragHint: {
|
|
1709
|
+
productId: 'espresso-machine-pro',
|
|
1710
|
+
sessionId: `rag-session-${userId}`,
|
|
1711
|
+
context: 'User is on the troubleshooting section',
|
|
1712
|
+
},
|
|
1713
|
+
};
|
|
1714
|
+
```
|
|
1715
|
+
|
|
1716
|
+
When the assistant receives a `rag` strategy it routes the question through `SL.ai.public.chat()`:
|
|
1717
|
+
|
|
1718
|
+
```typescript
|
|
1719
|
+
const response = await SL.ai.public.chat(collectionId, {
|
|
1720
|
+
productId: ragHint.productId,
|
|
1721
|
+
userId: currentUserId,
|
|
1722
|
+
message: userQuestion,
|
|
1723
|
+
sessionId: ragHint.sessionId,
|
|
1724
|
+
});
|
|
1725
|
+
```
|
|
1726
|
+
|
|
1727
|
+
#### `hybrid`
|
|
1728
|
+
|
|
1729
|
+
Combines both — the `text` is injected as additional context **and** the user's questions are also grounded via RAG. Good for museum exhibits, guided experiences, or any scenario with rich metadata alongside large document sets.
|
|
1730
|
+
|
|
1731
|
+
```typescript
|
|
1732
|
+
return {
|
|
1733
|
+
text: `
|
|
1734
|
+
## Exhibit: The Starry Night
|
|
1735
|
+
- **Artist**: Vincent van Gogh
|
|
1736
|
+
- **Year**: 1889
|
|
1737
|
+
- **Current Location**: Gallery 3, East Wing
|
|
1738
|
+
- **Audio Guide**: Available in 12 languages
|
|
1739
|
+
`,
|
|
1740
|
+
contentLabel: 'Museum Exhibit',
|
|
1741
|
+
strategy: 'hybrid',
|
|
1742
|
+
ragHint: {
|
|
1743
|
+
productId: 'starry-night-exhibit',
|
|
1744
|
+
context: 'Art history and technique questions',
|
|
1745
|
+
},
|
|
1746
|
+
};
|
|
1747
|
+
```
|
|
1748
|
+
|
|
1749
|
+
### Content Extraction Examples
|
|
1750
|
+
|
|
1751
|
+
#### Museum Guide App
|
|
1752
|
+
|
|
1753
|
+
```typescript
|
|
1754
|
+
async function gatherAIContent(): Promise<AIContentResponse> {
|
|
1755
|
+
const exhibit = getCurrentExhibit();
|
|
1756
|
+
|
|
1757
|
+
return {
|
|
1758
|
+
text: `
|
|
1759
|
+
Exhibit: "${exhibit.title}" by ${exhibit.artist}
|
|
1760
|
+
Period: ${exhibit.period}
|
|
1761
|
+
Medium: ${exhibit.medium}
|
|
1762
|
+
Description: ${exhibit.curatorNotes}
|
|
1763
|
+
Related works in this gallery: ${exhibit.relatedWorks.join(', ')}
|
|
1764
|
+
`.trim(),
|
|
1765
|
+
contentLabel: `Exhibit: ${exhibit.title}`,
|
|
1766
|
+
strategy: 'hybrid',
|
|
1767
|
+
ragHint: {
|
|
1768
|
+
productId: exhibit.smartlinksProductId,
|
|
1769
|
+
context: `Art history, technique, and visitor information for ${exhibit.title}`,
|
|
1770
|
+
},
|
|
1771
|
+
metadata: {
|
|
1772
|
+
exhibitId: exhibit.id,
|
|
1773
|
+
gallery: exhibit.gallery,
|
|
1774
|
+
audioGuideAvailable: exhibit.hasAudioGuide,
|
|
1775
|
+
},
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1778
|
+
```
|
|
1779
|
+
|
|
1780
|
+
#### Wine Product App
|
|
1781
|
+
|
|
1782
|
+
```typescript
|
|
1783
|
+
async function gatherAIContent(): Promise<AIContentResponse> {
|
|
1784
|
+
const wine = getCurrentWine();
|
|
1785
|
+
const reviews = await fetchRecentReviews(wine.id, 5);
|
|
1786
|
+
|
|
1787
|
+
return {
|
|
1788
|
+
text: `
|
|
1789
|
+
Wine: ${wine.name} (${wine.vintage})
|
|
1790
|
+
Winery: ${wine.winery}
|
|
1791
|
+
Region: ${wine.region}, ${wine.country}
|
|
1792
|
+
Grape: ${wine.grape}
|
|
1793
|
+
ABV: ${wine.abv}%
|
|
1794
|
+
Price: ${wine.price}
|
|
1795
|
+
Tasting Notes: ${wine.tastingNotes}
|
|
1796
|
+
|
|
1797
|
+
Recent Reviews:
|
|
1798
|
+
${reviews.map(r => `- "${r.text}" (${r.rating}/5)`).join('\n')}
|
|
1799
|
+
`.trim(),
|
|
1800
|
+
contentLabel: 'Wine Details',
|
|
1801
|
+
strategy: 'context',
|
|
1802
|
+
};
|
|
1803
|
+
}
|
|
1804
|
+
```
|
|
1805
|
+
|
|
1806
|
+
#### Equipment Manual App (RAG-only)
|
|
1807
|
+
|
|
1808
|
+
```typescript
|
|
1809
|
+
async function gatherAIContent(): Promise<AIContentResponse> {
|
|
1810
|
+
const equipment = getCurrentEquipment();
|
|
1811
|
+
|
|
1812
|
+
return {
|
|
1813
|
+
text: `User is viewing: ${equipment.name} (Model: ${equipment.modelNumber})`,
|
|
1814
|
+
contentLabel: `${equipment.name} Assistant`,
|
|
1815
|
+
strategy: 'rag',
|
|
1816
|
+
ragHint: {
|
|
1817
|
+
productId: equipment.smartlinksProductId,
|
|
1818
|
+
sessionId: `manual-${equipment.id}-${Date.now()}`,
|
|
1819
|
+
context: 'Technical manual, troubleshooting, and maintenance',
|
|
1820
|
+
},
|
|
1821
|
+
};
|
|
1822
|
+
}
|
|
1823
|
+
```
|
|
1824
|
+
|
|
1825
|
+
### Timing & Lifecycle
|
|
1826
|
+
|
|
1827
|
+
- **On navigation**: When the user navigates to a new product/proof/app, the assistant automatically requests fresh content and injects a context-update system message.
|
|
1828
|
+
- **On first message**: If no content has been gathered yet, the assistant requests it before the first AI call.
|
|
1829
|
+
- **On manual refresh**: The assistant can re-request content at any time (e.g. if the user's view within the app has changed).
|
|
1830
|
+
|
|
1831
|
+
Content is requested **lazily** — your handler is only called when the AI assistant is active and needs context. If the user never opens the assistant, your handler is never called.
|
|
1832
|
+
|
|
1833
|
+
### Method 3: DOM Fallback (Automatic)
|
|
1834
|
+
|
|
1835
|
+
If your app doesn't implement either of the above, the framework extracts `innerText` from the DOM element with `data-app-container="{appId}"`, truncated to ~4000 characters. This is a **last resort** — content quality is much lower than a structured response. Implementing Method 1 or 2 is strongly recommended.
|
|
1836
|
+
|
|
1837
|
+
---
|
|
1838
|
+
|
|
1550
1839
|
## Related Documentation
|
|
1551
1840
|
|
|
1552
1841
|
- [API Summary](./API_SUMMARY.md) - Complete API reference
|
package/docs/comms.md
CHANGED
|
@@ -19,7 +19,7 @@ This guide covers the full communications surface of the SDK: transactional send
|
|
|
19
19
|
|
|
20
20
|
Sends a single message to one contact using a template. No broadcast record is created. The send is logged to the contact's communication history with `sourceType: 'transactional'`.
|
|
21
21
|
|
|
22
|
-
**Endpoint:** `POST /admin/collection/:collectionId/comm
|
|
22
|
+
**Endpoint:** `POST /admin/collection/:collectionId/comm.send`
|
|
23
23
|
|
|
24
24
|
```typescript
|
|
25
25
|
import { comms } from '@proveanything/smartlinks'
|