@rudra-js/a2ui 0.8.1 → 0.8.3

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.
Files changed (2) hide show
  1. package/README.md +63 -42
  2. package/package.json +7 -7
package/README.md CHANGED
@@ -8,28 +8,40 @@ It is not a hosted platform, a visual or low-code app builder, or a workspace yo
8
8
 
9
9
  This package puts that block inside the interfaces an [A2UI](https://a2ui.org) agent builds. It
10
10
  adds one component, `RudraRecommendations`, to the catalog your A2UI renderer draws from. The agent
11
- places it and hints at what the shopper is looking at. Your server still picks the products and
12
- builds the block with `@rudra-js/core`, and the browser renders it with `@rudra-js/react`.
11
+ places it and passes hints about what the shopper is looking at. Your server still picks the
12
+ products and builds the block with `@rudra-js/core`. The browser renders it with `@rudra-js/react`.
13
13
 
14
- It works with version 0.9 of the A2UI protocol, through `@a2ui/react` and `@a2ui/web_core` 0.14.
14
+ It works with version 0.9 of the A2UI protocol, using `@a2ui/react` and `@a2ui/web_core` 0.14.
15
15
 
16
16
  ## Install
17
17
 
18
18
  ```sh
19
- npm install @rudra-js/a2ui @rudra-js/core @rudra-js/react @rudra-js/attested @a2ui/react @a2ui/web_core react react-dom
19
+ npm install @rudra-js/a2ui@latest @rudra-js/core@latest @rudra-js/react@latest @rudra-js/attested@latest @a2ui/react@0.14 @a2ui/web_core@0.14 react react-dom
20
20
  ```
21
21
 
22
- Everything but zod is a peer dependency, so your app holds one copy of each. On pnpm, read
23
- [zod](#zod) first.
22
+ Use the same command to install and to upgrade, whether or not your app already uses rudra-js or A2UI.
23
+ If your app has `@rudra-js/anthropic`, add `@rudra-js/anthropic@latest` to that command.
24
24
 
25
- Keep `skipLibCheck: true`. Without it, A2UI's own declarations fail to typecheck: they need `"dom"`
26
- in `lib`, and two of their imports have no file extension, which `nodenext` refuses.
25
+ The `@rudra-js` packages are released together. Each one's peer range for the others starts at its
26
+ own version. For a package name with no version, npm stays inside the range your `package.json`
27
+ already has. Without `@latest`, an app on an older core can get an `ERESOLVE` error. `react`
28
+ and `react-dom` have no version, so npm and pnpm keep a React 18 app on 18.
29
+
30
+ Everything except zod is a peer dependency, so your app holds one copy of each. npm and pnpm
31
+ install peers for you. List them anyway, because your code imports most of them itself.
32
+ pnpm only lets your code import what your `package.json` names. Yarn doesn't install peers, so on Yarn you
33
+ need the whole list. Yarn also moves a name with no version to its latest release. So on Yarn, if your app
34
+ already has React, leave out `react` and `react-dom`. On pnpm, read [zod](#zod) first.
35
+
36
+ Keep `skipLibCheck: true` in your `tsconfig.json`. Without it, A2UI's own type declarations fail
37
+ to typecheck. They need `"dom"` in `lib`. Two of their imports also have no file extension, which
38
+ `nodenext` refuses.
27
39
 
28
40
  ## Three pieces
29
41
 
30
42
  ### The catalog your agent is prompted with
31
43
 
32
- Put `agentCatalog.toJson()` in your agent's prompt and have it create surfaces with
44
+ Put `agentCatalog.toJson()` in your agent's prompt. Have the agent create surfaces with
33
45
  `catalogId: agentCatalog.id`. If you have catalog instructions of your own, join them to
34
46
  `RUDRA_RECOMMENDATIONS_INSTRUCTIONS`.
35
47
 
@@ -47,13 +59,16 @@ export const agentCatalog = new Catalog(
47
59
  );
48
60
  ```
49
61
 
50
- The first `toJson()` logs one "Recursive reference detected" warning per hint. It's harmless.
62
+ The first `toJson()` call logs one "Recursive reference detected" warning per hint. It's harmless.
51
63
 
52
64
  ### Your endpoint
53
65
 
54
- `shopperFor` and `candidatesFor` stand for the session and catalog code you already have.
55
- `provider: null` calls no model, so pass your own provider. In the default cohort mode the model
56
- never sees `searchQuery`, so the agent's search only counts with `generation: 'per-shopper'`.
66
+ `shopperFor` and `candidatesFor` stand in for the session and catalog code you already have.
67
+ `provider: null` calls no model, so pass your own provider.
68
+
69
+ `generation` defaults to `'cohort'`, which shares one block design between shoppers who look alike. In
70
+ that mode the model never sees `searchQuery`. The agent's search only matters with
71
+ `generation: 'per-shopper'`.
57
72
 
58
73
  ```ts
59
74
  import { createComponentGenerator, parseTrackingInput } from '@rudra-js/core';
@@ -92,11 +107,12 @@ export async function POST(request: Request): Promise<Response> {
92
107
  ```
93
108
 
94
109
  - `parseRecommendationRequest` accepts only `currentSku`, `currentCategory`, `searchQuery` and
95
- `maxItems`. Anything else is a 400.
96
- - `fitRecommendationRequest` drops a SKU or category none of your candidates has.
97
- - Pick candidates on your side, not from the hints. Each new category, `maxItems` or candidate set
98
- is a new model call, and with `per-shopper` so is each shopper and each new SKU or search, so
99
- rate-limit the endpoint (see [SECURITY.md](https://github.com/clivedsouza1010/rudra-js/blob/main/SECURITY.md)).
110
+ `maxItems`. Anything else gets a 400.
111
+ - `fitRecommendationRequest` drops a SKU or category that none of your candidates has.
112
+ - Pick candidates on your side, not from the hints.
113
+ - Each new category, `maxItems` or candidate set means a new model call. With `per-shopper`, so
114
+ does each shopper and each new SKU or search. Rate-limit the endpoint (see
115
+ [SECURITY.md](https://github.com/clivedsouza1010/rudra-js/blob/main/SECURITY.md)).
100
116
  - Send back `input.candidates` and `input.bundles`, not your raw catalog.
101
117
 
102
118
  ### The browser
@@ -131,51 +147,56 @@ const shopCatalog = new Catalog<ReactCatalogComponent>(
131
147
  export const processor = new MessageProcessor<ReactCatalogComponent>([shopCatalog]);
132
148
  ```
133
149
 
134
- Give the browser catalog the same id as the agent catalog, because A2UI looks it up by the
135
- `catalogId` the agent sends. Render the processor's surfaces with `A2uiSurface`. The options take
136
- `loadRecommendations`, `placeholder`, `onError`, and every `RudraComponent` prop except `spec`,
137
- `products` and `bundles`.
150
+ Give the browser catalog the same id as the agent catalog. A2UI looks it up by the `catalogId` the
151
+ agent sends. Render the processor's surfaces with `A2uiSurface`.
152
+
153
+ `createRudraRecommendationsComponent` takes `loadRecommendations`, `placeholder` and `onError`. It
154
+ also takes every `RudraComponent` prop except `spec`, `products` and `bundles`.
138
155
 
139
156
  ## What the component does
140
157
 
141
- - It reads each hint as a literal or from the agent's data model (`{ "path": "/viewing/sku" }`),
142
- and sends only the four. It leaves out a blank one, and one the server would turn away, like a
143
- `maxItems` of 40. A literal of the wrong type, like a numeric SKU, makes A2UI refuse the agent's
144
- whole message.
145
- - It asks once the hints hold still for 300 ms, and keeps the last block up until the next one
146
- arrives. `signal` aborts when the hints change or the component unmounts.
147
- - It checks the result against core's schemas before rendering any of it.
148
- - It shows `placeholder` until the first load. On a failed load, a bad result or a render error it
149
- shows nothing and calls `onError`.
158
+ - It reads each hint either as a literal value or from the agent's data model, like
159
+ `{ "path": "/viewing/sku" }`. It sends only the four hints the endpoint accepts.
160
+ - It leaves out a hint that is blank, or one the server would turn away, like a `maxItems` of 40.
161
+ - A literal of the wrong type, like a numeric SKU, makes A2UI refuse the agent's whole message.
162
+ - It waits until the hints stop changing for 300 ms, then calls `loadRecommendations`.
163
+ - It keeps showing the last block until the next one arrives.
164
+ - `signal` aborts when the hints change or the component unmounts.
165
+ - It checks the result against core's schemas before it renders any of it.
166
+ - It shows `placeholder` until the first load finishes.
167
+ - If a load fails or the result fails the schema check, it shows nothing and calls `onError`. It
168
+ does the same if the block throws while rendering.
150
169
  - Each component on a surface sends its own request.
151
170
 
152
171
  ## Where it runs
153
172
 
154
- `@rudra-js/a2ui` holds `createRudraRecommendationsComponent` and its types, and loads only in the
173
+ `@rudra-js/a2ui` holds `createRudraRecommendationsComponent` and its types. It loads only in the
155
174
  browser, because `@a2ui/react` needs a DOM. The agent catalog and your endpoint import from
156
- `@rudra-js/a2ui/server`, which runs anywhere. In Next.js a `'use client'` file still runs on the
157
- server for the first render, so load the one that imports `@rudra-js/a2ui` from a client component
158
- with `next/dynamic` and `ssr: false`.
175
+ `@rudra-js/a2ui/server`, which runs anywhere.
176
+
177
+ In Next.js, a `'use client'` file still runs on the server for the first render. Load the file
178
+ that imports `@rudra-js/a2ui` through `next/dynamic` with `ssr: false`, and make that call from a
179
+ client component.
159
180
 
160
- A2UI renders on the client, so a crawler won't see a block an agent places. For a product page,
181
+ A2UI renders in the browser, so a crawler won't see a block an agent places. For a product page,
161
182
  render `RudraComponent` on the server, as the
162
183
  [`@rudra-js/react` README](https://github.com/clivedsouza1010/rudra-js/tree/main/packages/react)
163
184
  describes.
164
185
 
165
186
  ## zod
166
187
 
167
- A2UI's schemas are zod 3, so this package depends on zod 3 while the rest of rudra-js uses zod 4.
168
- npm installs both, each where its package finds it, and you don't need either one yourself.
188
+ A2UI's schemas use zod 3, so this package depends on zod 3. The rest of rudra-js uses zod 4. npm
189
+ installs both, each where its own package finds it. With npm, you don't need either one yourself.
169
190
 
170
- On pnpm, `@a2ui/react` gets core's zod 4 as its zod peer, and the browser example stops
171
- typechecking (TS2344). If your app has no zod of its own, add zod 3:
191
+ On pnpm, `@a2ui/react` gets core's zod 4 as its zod peer. Then the browser example fails to
192
+ typecheck with TS2344. If your app has no zod of its own, add zod 3:
172
193
 
173
194
  ```sh
174
195
  pnpm add zod@^3.25.76
175
196
  ```
176
197
 
177
- If your app uses zod 4, drop the peer from `@a2ui/react` in `.pnpmfile.cjs`, and pnpm gives it
178
- the zod 3 it depends on:
198
+ If your app uses zod 4, remove the zod peer from `@a2ui/react` in `.pnpmfile.cjs`. pnpm then gives
199
+ it the zod 3 it depends on:
179
200
 
180
201
  ```js
181
202
  module.exports = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rudra-js/a2ui",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "description": "A2UI component for rudra-js: lets an A2UI agent place a product-recommendation block whose products, prices and wording come from your shop, not from the agent",
5
5
  "keywords": [
6
6
  "rudra-js",
@@ -62,19 +62,19 @@
62
62
  "peerDependencies": {
63
63
  "@a2ui/react": "^0.14.0",
64
64
  "@a2ui/web_core": "^0.14.0",
65
- "@rudra-js/core": "^0.8.1",
66
- "@rudra-js/react": "^0.8.1",
65
+ "@rudra-js/core": "^0.8.3",
66
+ "@rudra-js/react": "^0.8.3",
67
67
  "react": "^18.2.0 || ^19.0.0"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@a2ui/react": "0.14.0",
71
71
  "@a2ui/web_core": "0.14.0",
72
- "@rudra-js/core": "0.8.1",
73
- "@rudra-js/react": "0.8.1",
72
+ "@rudra-js/core": "0.8.3",
73
+ "@rudra-js/react": "0.8.3",
74
74
  "@types/react": "^19.3.0",
75
75
  "@types/react-dom": "^19.3.0",
76
76
  "jsdom": "^27.4.0",
77
- "react": "^19.3.0",
78
- "react-dom": "^19.3.0"
77
+ "react": "^19.3.1",
78
+ "react-dom": "^19.3.1"
79
79
  }
80
80
  }