@terreno/mcp 57.12.0 → 57.13.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/dist/docs/upgrades/57.13.0.md +75 -0
- package/dist/docs/versioned/next/explanation/README.md +1 -1
- package/dist/docs/versioned/next/explanation/agent-ui-blocks.md +69 -9
- package/dist/docs/versioned/next/explanation/example-coverage.md +3 -3
- package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +12 -0
- package/dist/docs/versioned/next/how-to/README.md +2 -0
- package/dist/docs/versioned/next/how-to/agent-ui-blocks.md +187 -3
- package/dist/docs/versioned/next/how-to/circleci.md +2 -0
- package/dist/docs/versioned/next/how-to/preview-demo.md +5 -5
- package/dist/docs/versioned/next/how-to/rate-limiting.md +17 -0
- package/dist/docs/versioned/next/how-to/test-ui-accessibility.md +35 -0
- package/dist/docs/versioned/next/implementationPlans/agent-ui-rich-replies.md +359 -0
- package/dist/docs/versioned/next/reference/README.md +1 -1
- package/dist/docs/versioned/next/reference/admin-backend.md +26 -0
- package/dist/docs/versioned/next/reference/admin-frontend.md +15 -0
- package/dist/docs/versioned/next/reference/ai.md +55 -3
- package/dist/docs/versioned/next/reference/api.md +4 -0
- package/dist/docs/versioned/next/reference/blocks.md +243 -11
- package/dist/docs/versioned/next/reference/environment-variables.md +3 -0
- package/dist/docs/versioned/next/reference/ui.md +212 -10
- package/dist/docs/versioned/next/tasks/agent-ui-rich-replies.md +188 -0
- package/package.json +3 -3
- package/src/docs/upgrades/57.13.0.md +75 -0
- package/src/docs/versioned/next/explanation/README.md +1 -1
- package/src/docs/versioned/next/explanation/agent-ui-blocks.md +69 -9
- package/src/docs/versioned/next/explanation/example-coverage.md +3 -3
- package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +12 -0
- package/src/docs/versioned/next/how-to/README.md +2 -0
- package/src/docs/versioned/next/how-to/agent-ui-blocks.md +187 -3
- package/src/docs/versioned/next/how-to/circleci.md +2 -0
- package/src/docs/versioned/next/how-to/preview-demo.md +5 -5
- package/src/docs/versioned/next/how-to/rate-limiting.md +17 -0
- package/src/docs/versioned/next/how-to/test-ui-accessibility.md +35 -0
- package/src/docs/versioned/next/implementationPlans/agent-ui-rich-replies.md +359 -0
- package/src/docs/versioned/next/reference/README.md +1 -1
- package/src/docs/versioned/next/reference/admin-backend.md +26 -0
- package/src/docs/versioned/next/reference/admin-frontend.md +15 -0
- package/src/docs/versioned/next/reference/ai.md +55 -3
- package/src/docs/versioned/next/reference/api.md +4 -0
- package/src/docs/versioned/next/reference/blocks.md +243 -11
- package/src/docs/versioned/next/reference/environment-variables.md +3 -0
- package/src/docs/versioned/next/reference/ui.md +212 -10
- package/src/docs/versioned/next/tasks/agent-ui-rich-replies.md +188 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Task List: Agent UI Rich Replies
|
|
2
|
+
|
|
3
|
+
**Status:** approved 2026-10-07. Start with T1 (or T19, which is independent).
|
|
4
|
+
**IP:** [`docs/implementationPlans/agent-ui-rich-replies.md`](../implementationPlans/agent-ui-rich-replies.md). The contracts, acceptance criteria (AC1–AC14, including AC6b), and open questions are there.
|
|
5
|
+
**Supporting skills:** `terreno-ui`, `terreno-backend-api`, `ai-prompt-governance`, `update-docs`, `verify-ui-changes`, `backend-test-env`.
|
|
6
|
+
|
|
7
|
+
Two write chains share files, so their tasks are ordered.
|
|
8
|
+
|
|
9
|
+
- **Contract chain:** T1 → T2 → T5 → T6 → T7 → T8 → T9. These write `blocks/src/schema.ts`, `limits.ts`, `lint.ts`, `prompt.ts`, fixtures, and `docs/reference/blocks.md`.
|
|
10
|
+
- **Renderer chain:** T1 → T3 → T10 → T11 → T12 → T13 → T14. These write `ui/src/blocks/blockRenderers.tsx`, `BlocksView.test.tsx`, `demo/stories/BlocksView.stories.tsx`, and the BlocksView section of `docs/reference/ui.md`.
|
|
11
|
+
|
|
12
|
+
Each renderer task also waits for its own contract task. T4 sits in the renderer chain between T3 and T10 because it also edits `docs/reference/ui.md`. Every contract task that adds fixtures also edits `blocks/src/parse.test.ts` (`expectedInvalid`); invalid cases that need validate options go in `blocks/src/lint.test.ts`. Fixtures under `valid/` use `data:image` or `file:` image sources.
|
|
13
|
+
|
|
14
|
+
### Phase 1: Tracer
|
|
15
|
+
|
|
16
|
+
- [x] **T1** — Stepper block round trips through a host callback
|
|
17
|
+
- Depends on: none
|
|
18
|
+
- Files: `blocks/src/schema.ts`, `blocks/src/limits.ts`, `blocks/src/errors.ts` (`OUT_OF_RANGE`), `blocks/src/lint.ts` (stepper `callback.name` in `UNKNOWN_HOST_ACTION`; reserved `<id>_increase` / `<id>_decrease` in `DUPLICATE_ID`), `blocks/src/fixtures/valid/stepper*.yaml`, `blocks/src/fixtures/invalid/stepper*.yaml`, `blocks/src/parse.test.ts`, `blocks/src/lint.test.ts`, `blocks/src/index.ts`; `ui/src/blocks/blockRenderers.tsx`, `ui/src/blocks/BlocksView.test.tsx`; `ai/src/service/agentBlocks.ts` (`findAgentBlock`), `ai/src/service/agentBlocks.test.ts`, `ai/src/service/scaleStepper.ts`, `ai/src/service/scaleStepper.test.ts`, `ai/src/types/index.ts` (`handles?`, `logResponse?` on host actions), `ai/src/routes/gptActions.ts` (honour `logResponse: false`), `ai/src/routes/gptActions.test.ts`, `ai/src/index.ts`; `docs/reference/blocks.md`, `docs/reference/ai.md`, `docs/reference/ui.md`.
|
|
19
|
+
- Delivers:
|
|
20
|
+
- The `stepper` contract from the IP.
|
|
21
|
+
- The renderer: − value +, unit, `itemsTitle`, an items grid formatted with `decimals`, and the note. It emits the callback with `{...payload, value}`. Buttons are disabled at the bounds, while pending, and when the callback is not in `hostActions`.
|
|
22
|
+
- `scaleStepperHostAction`: payload `z.object({value: z.number()}).passthrough()`. It reads the agent's stepper through `findAgentBlock`: `history.prompts[n]` (`msg-<n>`), or the only prompt holding that stepper id (409 when there are several, 404 when none). It checks `value` and returns `{replace: "block", blocks: {v: 1, blocks: [stepper]}}`.
|
|
23
|
+
- The `logResponse` host-action option. With it off, the log keeps the ids-only prompt plus `value`, with no response.
|
|
24
|
+
- Acceptance: AC4; AC5; the stepper rows of AC1 and AC2. `bun test blocks/`, `cd ui && bun test src/blocks`, and `cd ai && bun test --preload ./src/tests/bunSetup.ts src/service/scaleStepper.test.ts src/routes/gptActions.test.ts` are green.
|
|
25
|
+
|
|
26
|
+
- [x] **T2** — Prompt offers the new blocks by default, with an opt-out
|
|
27
|
+
- Depends on: T1
|
|
28
|
+
- Files: `blocks/src/prompt.ts`, `blocks/src/prompt.test.ts`, `blocks/src/validate.ts` (`stepperActions`), `blocks/src/lint.ts`; `ai/src/types/index.ts` (`uiBlocks.richBlocks`), `ai/src/service/prompts.ts`, `ai/src/service/chatTurn.ts` (derive `stepperActions` and `checklistActions` from the host actions' `handles`; pass `richBlocks`), `ai/src/routes/gpt.test.ts`; `docs/reference/blocks.md`, `docs/reference/ai.md`.
|
|
29
|
+
- Delivers: the default-on table in the IP. It adds the `richBlocks` plumbing (default `true` in both `uiBlocks` and `blocksPromptSection`), the stepper gate (a `handles: "stepper"` action), and the `checklistActions` list that T5 uses. With `richBlocks: false`, the prompt text is byte-identical to `master`, even with a stepper action registered. Later contract tasks add their prompt line under `richBlocks`.
|
|
30
|
+
- Acceptance: the AC3 `false` case, the default-on check, and the stepper line; a chat-turn test where a stepper naming a non-stepper action fails `UNKNOWN_HOST_ACTION`. The full on-case snapshot is T9's.
|
|
31
|
+
|
|
32
|
+
### Phase 2: Tables
|
|
33
|
+
|
|
34
|
+
- [x] **T3** — Table block renders typed columns
|
|
35
|
+
- Depends on: T1
|
|
36
|
+
- Files: `ui/src/DataTable.tsx` (number and date cells), `ui/src/DataTable.test.tsx`, `ui/src/blocks/blockRenderers.tsx`, `ui/src/blocks/BlocksView.test.tsx`, `docs/reference/ui.md` (DataTable and BlocksView sections).
|
|
37
|
+
- Delivers: right-aligned `number` cells and Luxon `DATE_MED` `date` cells in `DataTable`. The `table` block maps the dataset column types to these cells, measures its width with `onLayout`, and splits the width evenly, at least 96 per column, scrolling sideways past that.
|
|
38
|
+
- Acceptance: AC9 (table half); the new tests fail on `master`.
|
|
39
|
+
|
|
40
|
+
- [x] **T4** — Markdown tables in `text` get theme styling
|
|
41
|
+
- Depends on: T3 (shares `docs/reference/ui.md`; T10 follows T4 for the same reason)
|
|
42
|
+
- Files: `ui/src/MarkdownView.tsx`, `ui/src/MarkdownView.test.tsx`, `docs/reference/ui.md` (MarkdownView section only).
|
|
43
|
+
- Delivers: `border.default` cell borders, a bold header on `surface.secondaryLight`, and horizontal scroll when the table is wide.
|
|
44
|
+
- Acceptance: AC9 (markdown half); the test fails on `master`.
|
|
45
|
+
|
|
46
|
+
### Phase 3: Contracts
|
|
47
|
+
|
|
48
|
+
- [x] **T5** — `checklist` contract
|
|
49
|
+
- Depends on: T2
|
|
50
|
+
- Files: `blocks/src/schema.ts`, `blocks/src/limits.ts`, `blocks/src/lint.ts` (item ids; reserved `<id>_<item id>` element ids; checklist `callback.name` against `checklistActions`), `blocks/src/prompt.ts`, `blocks/src/fixtures/{valid,invalid}/checklist*.yaml`, `blocks/src/parse.test.ts`, `docs/reference/blocks.md`.
|
|
51
|
+
- Delivers: the `checklist` schema from the IP, including the optional `callback`. Its prompt line sits under `richBlocks` and names the checklist action when there is one.
|
|
52
|
+
- Acceptance: the checklist rows of AC1 and AC3; `bun test blocks/`.
|
|
53
|
+
|
|
54
|
+
- [x] **T6** — `gallery` contract
|
|
55
|
+
- Depends on: T5
|
|
56
|
+
- Files: `blocks/src/schema.ts`, `blocks/src/limits.ts`, `blocks/src/lint.ts` (image hosts per tile), `blocks/src/prompt.ts`, `blocks/src/fixtures/{valid,invalid}/gallery*.yaml`, `blocks/src/parse.test.ts`, `docs/reference/blocks.md`.
|
|
57
|
+
- Delivers: the `gallery` schema. `IMAGE_HOST_NOT_ALLOWED` names the tile path (`blocks[0].images[2].src`).
|
|
58
|
+
- Acceptance: the gallery rows of AC1 and AC3; an invalid fixture with a disallowed host.
|
|
59
|
+
|
|
60
|
+
- [x] **T7** — `list` contract
|
|
61
|
+
- Depends on: T6
|
|
62
|
+
- Files: `blocks/src/schema.ts`, `blocks/src/limits.ts`, `blocks/src/lint.ts`, `blocks/src/prompt.ts`, `blocks/src/fixtures/{valid,invalid}/list*.yaml`, `blocks/src/parse.test.ts`, `docs/reference/blocks.md`.
|
|
63
|
+
- Delivers: the `list` schema. The optional image on each item goes through image-host lint.
|
|
64
|
+
- Acceptance: the list rows of AC1 and AC3.
|
|
65
|
+
|
|
66
|
+
- [x] **T8** — `card.eyebrow` contract
|
|
67
|
+
- Depends on: T7
|
|
68
|
+
- Files: `blocks/src/schema.ts`, `blocks/src/limits.ts`, `blocks/src/prompt.ts`, `blocks/src/fixtures/{valid,invalid}/card-eyebrow*.yaml`, `blocks/src/parse.test.ts`, `docs/reference/blocks.md`.
|
|
69
|
+
- Delivers: an optional `eyebrow` (1–60) on `card`.
|
|
70
|
+
- Acceptance: the eyebrow rows of AC1 and AC3.
|
|
71
|
+
|
|
72
|
+
- [x] **T9** — `copy` action contract and `blockPlainText`
|
|
73
|
+
- Depends on: T8
|
|
74
|
+
- Files: `blocks/src/schema.ts`, `blocks/src/errors.ts` (`COPY_TARGET_INVALID`), `blocks/src/lint.ts` (exactly one of `text` / `target`, as `open` does), `blocks/src/prompt.ts`, `blocks/src/plainText.ts`, `blocks/src/plainText.test.ts`, `blocks/src/index.ts`, `blocks/src/fixtures/{valid,invalid}/copy*.yaml`, `blocks/src/parse.test.ts`, `docs/reference/blocks.md`.
|
|
75
|
+
- Delivers: the `copy` action kind, target lint, and `blockPlainText` as the IP table describes it.
|
|
76
|
+
- Acceptance: the copy rows of AC1, AC2, and AC3; the full AC3 `richBlocks`-on snapshot. `plainText.test.ts` covers every row of the IP table.
|
|
77
|
+
|
|
78
|
+
### Phase 4: Renderers
|
|
79
|
+
|
|
80
|
+
- [x] **T10** — Checklist renders and toggles
|
|
81
|
+
- Depends on: T3, T4, T5
|
|
82
|
+
- Files: `ui/src/blocks/blockRenderers.tsx`, `ui/src/blocks/useChecklistState.ts`, `ui/src/blocks/BlocksView.tsx`, `ui/src/blocks/BlocksView.test.tsx`, `demo/stories/BlocksView.stories.tsx`, `docs/reference/ui.md`.
|
|
83
|
+
- Delivers: a `CheckBox` row per item (meta, bold text, detail) and the "n of m" counter. With a callback in `hostActions`, a tick emits `{...payload, itemId, checked, state}`, disables the whole checklist while a tick is pending (so a second tick cannot send a stale `state`), and shows the returned block. Without one, ticks are local for each rendered document.
|
|
84
|
+
- Acceptance: AC6.
|
|
85
|
+
|
|
86
|
+
- [x] **T11** — Gallery renders
|
|
87
|
+
- Depends on: T6, T10
|
|
88
|
+
- Files: `ui/src/blocks/blockRenderers.tsx`, `ui/src/blocks/BlocksView.test.tsx`, `demo/stories/BlocksView.stories.tsx`, `docs/reference/ui.md`.
|
|
89
|
+
- Delivers: one row of 4:3 `Image` tiles up to 3, a 3-column grid above that, captions, `file:` ids through `useResolvedImages`, and sideways scroll on narrow screens.
|
|
90
|
+
- Acceptance: AC7 (gallery).
|
|
91
|
+
|
|
92
|
+
- [x] **T12** — List renders
|
|
93
|
+
- Depends on: T7, T11
|
|
94
|
+
- Files: `ui/src/blocks/blockRenderers.tsx`, `ui/src/blocks/BlocksView.test.tsx`, `demo/stories/BlocksView.stories.tsx`, `docs/reference/ui.md`.
|
|
95
|
+
- Delivers: for each item, a 3:4 thumbnail on the left, a bold title, muted text, and the meta.
|
|
96
|
+
- Acceptance: AC7 (list).
|
|
97
|
+
|
|
98
|
+
- [x] **T13** — Card eyebrow renders
|
|
99
|
+
- Depends on: T8, T12
|
|
100
|
+
- Files: `ui/src/blocks/blockRenderers.tsx`, `ui/src/blocks/BlocksView.test.tsx`, `docs/reference/ui.md`.
|
|
101
|
+
- Delivers: small, muted eyebrow text above the card title.
|
|
102
|
+
- Acceptance: AC7 (eyebrow).
|
|
103
|
+
|
|
104
|
+
- [x] **T14** — Copy action writes the clipboard
|
|
105
|
+
- Depends on: T9, T13
|
|
106
|
+
- Files: `ui/src/blocks/BlocksView.tsx`, `ui/src/blocks/blockRenderers.tsx`, `ui/src/blocks/BlocksView.test.tsx`, `docs/reference/ui.md`.
|
|
107
|
+
- Delivers: a copy button builds its text with `blockPlainText` from the current block (override and toggles applied), writes it with `expo-clipboard`, and shows "Copied" in a polite live region for 2 s. It never calls `onAction`.
|
|
108
|
+
- Acceptance: AC8.
|
|
109
|
+
|
|
110
|
+
### Phase 5: The roast reply end to end
|
|
111
|
+
|
|
112
|
+
- [x] **T15** — Sunday roast golden document and playground story
|
|
113
|
+
- Depends on: T14
|
|
114
|
+
- Files: `blocks/src/fixtures/golden/sunday-roast.yaml`, `blocks/src/golden.test.ts` (validate with `hostActions: ["scaleStepper"]`, `stepperActions: ["scaleStepper"]`, `imageHosts: ["images.example.com"]`), `demo/stories/BlocksPlayground.stories.tsx` (a roast preset).
|
|
115
|
+
- Delivers: the GPT-6 demo reply as one document: the title; the gallery; the summary card with an eyebrow; the menu list; the stepper and copy card; the checklist with its first item checked; the USDA note as `context`; the tips as `text`; and follow-up `reply` buttons. It also includes the GPT-5.6 "How much lamb?" table as a `table` block. Images use `https://images.example.com/...` and validate only with `imageHosts`, so the file lives under `golden/`, not `valid/`.
|
|
116
|
+
- Acceptance: AC10; a playground screenshot under `/opt/cursor/artifacts/`.
|
|
117
|
+
|
|
118
|
+
- [x] **T16** — Example app runs the roast reply against the real callback route
|
|
119
|
+
- Depends on: T15, T20, T21
|
|
120
|
+
- Files:
|
|
121
|
+
- `example-backend/src/ai/hostActions.ts`: register `scaleStepper: scaleStepperHostAction` and `toggleChecklist: toggleChecklistHostAction` (`richBlocks` is on by default).
|
|
122
|
+
- `example-frontend/app/(tabs)/ai.tsx`: add `scaleStepper` and `toggleChecklist` to `hostActions`.
|
|
123
|
+
- `example-frontend/e2e/helpers/seedGptHistory.ts` (new): `POST /gpt/histories` as the logged-in user, with the roast document as the assistant prompt.
|
|
124
|
+
- `example-frontend/e2e/helpers/mockGpt.ts`: the mocked stream returns the seeded `historyId`, and `/gpt/actions` is no longer mocked for this spec.
|
|
125
|
+
- `example-frontend/e2e/ai-chat.spec.ts`.
|
|
126
|
+
- `docs/explanation/example-coverage.md`.
|
|
127
|
+
- Delivers: the seeded roast document uses `file:` ids from a test `PhotoLibraryEntry`. Playwright presses + (5 → 6, the quantities change) and ticks a checklist item, both through the real `POST /gpt/actions`, then presses copy. Only the signed-URL image download is stubbed.
|
|
128
|
+
- Acceptance: AC11.
|
|
129
|
+
|
|
130
|
+
- [x] **T17** — Model smoke: a real model writes the roast reply
|
|
131
|
+
- Depends on: T15, T20
|
|
132
|
+
- Files: `example-backend/src/scripts/blocksSmoke.ts`, `example-backend/package.json` and root `package.json` (`blocks:smoke` script).
|
|
133
|
+
- Delivers: a script that runs the post's prompt through `AIService` with the opted-in blocks prompt and checks the reply. It skips cleanly when no model key is set.
|
|
134
|
+
- Acceptance: AC12.
|
|
135
|
+
|
|
136
|
+
- [x] **T18** — Docs sweep, changelog, rules
|
|
137
|
+
- Depends on: T15, T20, T21
|
|
138
|
+
- Files:
|
|
139
|
+
- `docs/explanation/agent-ui-blocks.md`: the catalog list, adding the missing `callout`, `image`, `details`, and `html`; why the stepper is a callback; the default-on rollout and the `richBlocks: false` opt-out for shipped native builds.
|
|
140
|
+
- `docs/how-to/agent-ui-blocks.md`: a section "Add a stepper callback", including the warning that stored history prompts are owner-writable, so a handler whose numbers matter must use its own data.
|
|
141
|
+
- `changelog/unreleased/agent-ui-rich-replies.md`, with a "Behaviour change" note: hosts with `uiBlocks` get the new blocks in the prompt by default; set `uiBlocks.richBlocks: false` to keep the old catalog.
|
|
142
|
+
- `.rulesync/rules/ui/00-ui.md` and `.rulesync/rules/ai/00-ai.md`, then `bun run rules`.
|
|
143
|
+
- Delivers: docs a stranger can follow to build the roast reply without reading the PR.
|
|
144
|
+
- Acceptance: AC13.
|
|
145
|
+
|
|
146
|
+
- [x] **T19** — Generated photo library: generate images once and store them
|
|
147
|
+
- Depends on: none
|
|
148
|
+
- Files: `example-backend/src/models/photoLibraryEntry.ts`, `example-backend/src/types/models/photoLibraryEntryTypes.ts`, `example-backend/src/scripts/photoPrompts.ts`, `example-backend/src/scripts/generatePhotoLibrary.ts`, `example-backend/src/scripts/generatePhotoLibrary.test.ts`, `knip.jsonc` (script entry), `example-backend/package.json` (`photos:generate`).
|
|
149
|
+
- Delivers: the `PhotoLibraryEntry` model and the `photos:generate` script from the IP. It runs AI SDK `generateImage` with the Vertex image model, then `FileStorageService.upload`, then upserts by `prompt`. It validates the required env up front, skips existing prompts, and takes `--force`. Supporting skill: `mongoose-schema-safety`.
|
|
150
|
+
- Acceptance: AC14 (generation half), using a fake image model and fake storage.
|
|
151
|
+
|
|
152
|
+
- [x] **T20** — `findPhotos` tool and photo URLs in the example app
|
|
153
|
+
- Depends on: T19
|
|
154
|
+
- Files: `example-backend/src/ai/tools.ts` (`findPhotos`), `example-backend/src/ai/tools.test.ts`, `example-backend/src/api/photoLibrary.ts` (`modelRouter` with instance action `url`), `example-backend/src/api/photoLibrary.test.ts`, `example-backend/src/server.ts` (register it), `example-frontend/store/openApiSdk.ts` (regenerated with `bun run sdk`), `example-frontend/app/(tabs)/ai.tsx` (`resolveImage`), `docs/how-to/agent-ui-blocks.md` ("Give the agent photos"; T18 follows it).
|
|
155
|
+
- Delivers: `findPhotos({query, count})` returns `{src: "file:<id>", alt}` from the library. `GET /photoLibrary/:id/url` returns a signed URL to any authenticated user. The example chat resolves `file:` ids through the generated hook. Supporting skills: `model-router-actions`, `generate-sdk`.
|
|
156
|
+
- Acceptance: AC14 (tool and route half).
|
|
157
|
+
|
|
158
|
+
- [x] **T21** — Checklist ticks round trip through a host callback
|
|
159
|
+
- Depends on: T10
|
|
160
|
+
- Files: `ai/src/service/toggleChecklist.ts`, `ai/src/service/toggleChecklist.test.ts`, `ai/src/routes/gptActions.test.ts`, `ai/src/index.ts`, `docs/reference/ai.md`.
|
|
161
|
+
- Delivers: `toggleChecklistHostAction` from the IP, built on `findAgentBlock`.
|
|
162
|
+
- Acceptance: AC6b.
|
|
163
|
+
|
|
164
|
+
### Phase 6: Playground follow-up (D7)
|
|
165
|
+
|
|
166
|
+
- [x] **T22** — Every block type has a playground preset
|
|
167
|
+
- Depends on: T15
|
|
168
|
+
- Files: `demo/stories/BlocksPlayground.stories.tsx`, `demo/story-config/BlocksPlayground.config.tsx`, a demo test that every schema block type appears in a preset and every preset validates.
|
|
169
|
+
- Delivers: one preset per block type plus "All blocks", covering every action kind and the segmented control.
|
|
170
|
+
- Acceptance: the coverage test fails when a block type has no preset; every preset validates; runtime screenshots at 1280 and 390.
|
|
171
|
+
|
|
172
|
+
- [x] **T23** — Stepper and checklist callbacks run in the playground
|
|
173
|
+
- Depends on: T22
|
|
174
|
+
- Files: `blocks/src/hostActionLogic.ts` (or similar) + tests + `blocks/src/index.ts`, `ai/src/service/scaleStepper.ts`, `ai/src/service/toggleChecklist.ts`, `demo/stories/BlocksPlayground.stories.tsx`, `docs/reference/blocks.md`.
|
|
175
|
+
- Delivers: pure `scaleStepperBlock` and `applyChecklistState` in `@terreno/blocks`, used by both host actions and the playground; other actions show a toast.
|
|
176
|
+
- Acceptance: in the playground, + shows 6 and "2.4 kg", a tick shows "2 of 8", a reply button shows a toast; ai host-action tests unchanged and green.
|
|
177
|
+
|
|
178
|
+
- [x] **T24** — Checklist rows read bold title, then time, then description
|
|
179
|
+
- Depends on: none
|
|
180
|
+
- Files: `ui/src/blocks/blockRenderers.tsx`, `ui/src/blocks/BlocksView.test.tsx`, `docs/reference/ui.md`.
|
|
181
|
+
- Delivers: the row order from D7, test IDs unchanged.
|
|
182
|
+
- Acceptance: a test asserts the order; the e2e roast spec still passes.
|
|
183
|
+
|
|
184
|
+
- [x] **T25** — Demo blocks use real photos
|
|
185
|
+
- Depends on: T22
|
|
186
|
+
- Files: `demo/assets/blocks/*.jpg`, `demo/assets/blocks/ATTRIBUTION.md`, `demo/stories/BlocksView.stories.tsx`, `demo/stories/BlocksPlayground.stories.tsx`.
|
|
187
|
+
- Delivers: gallery, list, and image presets and stories show bundled public-domain photos through `file:` ids and `resolveImage`.
|
|
188
|
+
- Acceptance: in the browser every photo loads (`naturalWidth` 800); attribution lists each source and license.
|
package/package.json
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"@modelcontextprotocol/node": "^2.0.0",
|
|
12
12
|
"@modelcontextprotocol/server": "^2.0.0",
|
|
13
13
|
"@sentry/bun": "^10.39.0",
|
|
14
|
-
"@terreno/api": "57.
|
|
15
|
-
"@terreno/blocks": "57.
|
|
14
|
+
"@terreno/api": "57.13.0",
|
|
15
|
+
"@terreno/blocks": "57.13.0",
|
|
16
16
|
"express": "^5.2.1",
|
|
17
17
|
"luxon": "^3.7.2",
|
|
18
18
|
"minisearch": "^7.2.0",
|
|
@@ -105,5 +105,5 @@
|
|
|
105
105
|
"test:coverage": "bun run ../scripts/check-coverage.ts"
|
|
106
106
|
},
|
|
107
107
|
"type": "module",
|
|
108
|
-
"version": "57.
|
|
108
|
+
"version": "57.13.0"
|
|
109
109
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Upgrading to 57.13.0
|
|
2
|
+
|
|
3
|
+
**Action required:** Yes
|
|
4
|
+
**Affected packages:** @terreno/ai, @terreno/ui
|
|
5
|
+
|
|
6
|
+
## Summary
|
|
7
|
+
|
|
8
|
+
Agent replies can use rich blocks (stepper, checklist, gallery, list, card eyebrow, copy), and hosts with `uiBlocks` on offer them in the prompt by default. `DataTable` number and date columns render differently, `neutral500` is a slightly darker gray, and the admin Roles screen groups permissions by resource. `@terreno/api` adds a per-route rate limiter, and `DocumentStorageApp` can be opened to signed-in non-admins. Action is required only for hosts with `uiBlocks` on that still have native builds from before this release.
|
|
9
|
+
|
|
10
|
+
## Breaking changes
|
|
11
|
+
|
|
12
|
+
### Rich blocks are offered in the chat prompt by default
|
|
13
|
+
|
|
14
|
+
**What changed**
|
|
15
|
+
|
|
16
|
+
With `uiBlocks` on, the chat system prompt now offers `checklist`, `gallery`, `list`, card `eyebrow`, and `copy`, plus `stepper` when a host action has `handles: "stepper"`. A native build shipped before 57.13.0 cannot render those blocks and shows an error banner for a reply that uses them.
|
|
17
|
+
|
|
18
|
+
**Why**
|
|
19
|
+
|
|
20
|
+
Rich blocks make agent replies more useful, so new hosts get them without extra setup.
|
|
21
|
+
|
|
22
|
+
**Migration**
|
|
23
|
+
|
|
24
|
+
Keep the old catalog until every shipped native build is on 57.13.0 or later:
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// Before
|
|
28
|
+
addGptRoutes(router, {aiService, uiBlocks: {hostActions}});
|
|
29
|
+
|
|
30
|
+
// After (until old native builds age out)
|
|
31
|
+
addGptRoutes(router, {aiService, uiBlocks: {hostActions, richBlocks: false}});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
With `richBlocks: false` the prompt is the same as before. Validation accepts the new blocks either way.
|
|
35
|
+
|
|
36
|
+
### `DataTable` number and date cells
|
|
37
|
+
|
|
38
|
+
**What changed**
|
|
39
|
+
|
|
40
|
+
`columnType: "number"` columns right-align cells and header. `columnType: "date"` cells format an ISO string or `Date` as Luxon `DATE_MED` (date only, local zone). Strings that are not ISO dates show as before.
|
|
41
|
+
|
|
42
|
+
**Why**
|
|
43
|
+
|
|
44
|
+
Numbers line up by digit, and raw ISO timestamps were hard to read.
|
|
45
|
+
|
|
46
|
+
**Migration**
|
|
47
|
+
|
|
48
|
+
To keep the old look for a column, render it with `customColumnComponentMap`:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// Before
|
|
52
|
+
{columnType: "date", title: "Created", width: 150}
|
|
53
|
+
|
|
54
|
+
// After (keep the raw value)
|
|
55
|
+
{columnType: "rawDate", title: "Created", width: 150}
|
|
56
|
+
// with customColumnComponentMap={{rawDate: ({cellData}) => <Text>{String(cellData.value)}</Text>}}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Deprecations
|
|
60
|
+
|
|
61
|
+
None
|
|
62
|
+
|
|
63
|
+
## New capabilities
|
|
64
|
+
|
|
65
|
+
- `createRouteRateLimitMiddleware({name, max, windowMs, store?, keyBy?})` from `@terreno/api` for a fixed-window limit on one route.
|
|
66
|
+
- `DocumentStorageApp` `access: "authenticated"` (non-admins see only `users/<userId>/`) and `uploadRateLimit`.
|
|
67
|
+
- `scaleStepperHostAction`, `toggleChecklistHostAction`, `findAgentBlock`, and `runBufferedChatTurn` from `@terreno/ai`.
|
|
68
|
+
- `SegmentedControl` `size="sm"`; `Box` `accessibilityState` and `accessibilityLiveRegion`.
|
|
69
|
+
- The `neutral500` primitive is `#949494`. Override it with `setPrimitives({neutral500: "#9A9A9A"})` to keep the old gray.
|
|
70
|
+
|
|
71
|
+
## Verification
|
|
72
|
+
|
|
73
|
+
- `bun run compile` and `bun run lint` at the app root
|
|
74
|
+
- Send a chat prompt that asks for a checklist; on a current build it renders, and with `richBlocks: false` the agent replies with the old block types
|
|
75
|
+
- Open a screen with a `DataTable` date column and check the dates read as `Oct 10, 2026`
|
|
@@ -19,7 +19,7 @@ Understanding-oriented documentation: concepts, architecture, and context.
|
|
|
19
19
|
- [Durable agent harness](durable-agent-harness.md) — Phases, checkpoints, and why the audit span shares the checkpoint transaction
|
|
20
20
|
- [AI-powered workflows](ai-workflows.md) — Autonomous documentation, testing, and maintenance workflows
|
|
21
21
|
- [Agent UI Asks](agent-ui-asks.md) — Why agent questions are client-side tool calls, the pause and resume round trip, why cards carry exact answers, the watch paths, asks vs blocks
|
|
22
|
-
- [Agent UI blocks](agent-ui-blocks.md) — Why chat replies use a closed YAML catalog instead of free-form UI
|
|
22
|
+
- [Agent UI blocks](agent-ui-blocks.md) — Why chat replies use a closed YAML catalog instead of free-form UI, why steppers and checklists call the server, and the rich-blocks rollout
|
|
23
23
|
- [Authentication architecture](authentication.md) — Better Auth, JWT, and optional MCP service tokens
|
|
24
24
|
- [Organization tenancy](organizations.md) — Optional Membership-backed tenancy, context, and isolation boundaries
|
|
25
25
|
- [Configuration system](configuration-system.md) — Runtime configuration with database persistence
|
|
@@ -9,19 +9,79 @@ in [Agent UI Asks](agent-ui-asks.md).
|
|
|
9
9
|
The design record is
|
|
10
10
|
[agent-ui-blocks.md](../implementationPlans/agent-ui-blocks.md). Pick executes that work as
|
|
11
11
|
Phase 5 of [Agent UI Asks](../implementationPlans/agent-ui-asks.md).
|
|
12
|
+
The stepper, checklist, gallery, list, card eyebrow, and copy additions are recorded in
|
|
13
|
+
`docs/implementationPlans/agent-ui-rich-replies.md`.
|
|
12
14
|
|
|
13
15
|
## Why a closed catalog
|
|
14
16
|
|
|
15
17
|
An agent that can emit arbitrary components can also emit styles, scripts, and layout the
|
|
16
18
|
app theme does not own. The catalog is the list of `@terreno/ui` components the chat can
|
|
17
|
-
paint
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
paint. Unknown keys and unknown block types fail validation, so a reply cannot smuggle a
|
|
20
|
+
`style` object or a hex color.
|
|
21
|
+
|
|
22
|
+
| Group | Blocks | Notes |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| Text | `heading`, `text`, `context`, `callout`, `details` | `text` is markdown, including GFM tables |
|
|
25
|
+
| Values | `metric`, `badge`, `divider` | |
|
|
26
|
+
| Data | `chart`, `table` | Read an inline or `ref` dataset |
|
|
27
|
+
| Media | `image`, `gallery`, `list` | Sources are `data:image`, `file:`, or an allowed `https` host |
|
|
28
|
+
| Interactive | `actions` (`button`, `segmented`), `stepper`, `checklist` | Button actions: `reply`, `open`, `select`, `callback`, `copy` |
|
|
29
|
+
| Layout | `columns`, `card` (optional `title` and `eyebrow`) | Leaf blocks only inside |
|
|
30
|
+
| Escape hatch | `html` | Only with `uiBlocks.html`; sanitized before storage |
|
|
31
|
+
|
|
32
|
+
Field rules for each block are in the [reference](../reference/blocks.md).
|
|
21
33
|
|
|
22
34
|
The same pure functions run wherever a document is checked. `parseBlocks` and
|
|
23
|
-
`validateBlocks` live in `@terreno/blocks`, which has no React and no Express. The renderer
|
|
24
|
-
|
|
35
|
+
`validateBlocks` live in `@terreno/blocks`, which has no React and no Express. The renderer,
|
|
36
|
+
the chat route, and the `terreno-blocks` CLI all call them; none grows a second grammar.
|
|
37
|
+
|
|
38
|
+
## Why interactive blocks call the server
|
|
39
|
+
|
|
40
|
+
A stepper that rescales a shopping list, or a checklist that remembers ticks, needs logic.
|
|
41
|
+
Terreno does not give the document a shared `state` with `{{formula}}` bindings, and it does
|
|
42
|
+
not run scripted html. Both need an expression language the theme and the validator cannot
|
|
43
|
+
see into. Instead, an interactive block names a host callback, as a callback button does:
|
|
44
|
+
|
|
45
|
+
| Interaction | Who runs it | Result |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| Stepper − / + | Host action with `handles: "stepper"`, through `POST /gpt/actions` | The replacement stepper, swapped in by block id |
|
|
48
|
+
| Checklist tick | Host action with `handles: "checklist"`, or the device when the checklist has no callback | The replacement checklist, or a local tick |
|
|
49
|
+
| `copy` button | The device | Text on the clipboard; nothing reaches the server |
|
|
50
|
+
|
|
51
|
+
The cost is one round trip per tap. The view disables the block while the call is pending, so
|
|
52
|
+
fast taps are dropped, not queued, and a checklist tick cannot send ticks that miss the one
|
|
53
|
+
before it. The gain is that the agent writes plain data, and the app's code decides what a
|
|
54
|
+
tap means. `scaleStepperHostAction` and `toggleChecklistHostAction` in `@terreno/ai` cover the
|
|
55
|
+
common case. They read the block the agent wrote from the stored history and never trust the
|
|
56
|
+
tap request's copy of it. The history owner can still edit stored prompts, so an app whose
|
|
57
|
+
numbers matter (prices, stock) registers its own action over its own data.
|
|
58
|
+
|
|
59
|
+
Overrides live in client memory. A reload shows the agent's original block again.
|
|
60
|
+
|
|
61
|
+
## Why photos come from a stored library
|
|
62
|
+
|
|
63
|
+
A model cannot make a photo while it writes a reply, and an `https` image needs an
|
|
64
|
+
`imageHosts` allowlist the model cannot know. The example app generates a photo library once
|
|
65
|
+
per environment with the Vertex image model, stores it through `FileStorageService`, and gives
|
|
66
|
+
the agent a `findPhotos` tool that returns `file:` ids. The reply cites ids; the client
|
|
67
|
+
resolves each id to a signed URL. Generation cost and latency stay out of the chat turn, and
|
|
68
|
+
every photo the user sees was made and stored ahead of time. See
|
|
69
|
+
[Give the agent photos](../how-to/agent-ui-blocks.md#give-the-agent-photos).
|
|
70
|
+
|
|
71
|
+
## Rollout: rich blocks are on by default
|
|
72
|
+
|
|
73
|
+
`uiBlocks.richBlocks` defaults to `true`. The prompt then offers `checklist`, `gallery`,
|
|
74
|
+
`list`, `card.eyebrow`, and `copy`, and offers `stepper` when a host action has
|
|
75
|
+
`handles: "stepper"`. A stepper without such an action would have dead buttons, so the
|
|
76
|
+
prompt does not mention it.
|
|
77
|
+
|
|
78
|
+
The server and the web client upgrade together. A native build already in the app stores
|
|
79
|
+
does not know the new blocks: a reply that uses them fails its validation and shows the
|
|
80
|
+
error banner with the raw YAML. A host with such builds sets `uiBlocks.richBlocks: false`
|
|
81
|
+
until they update. The prompt is then the same as before rich blocks. Validation still
|
|
82
|
+
accepts the new blocks, so a stored reply that uses them still renders on new clients.
|
|
83
|
+
A client-declared catalog version, so the server picks blocks per client, would remove that
|
|
84
|
+
manual step; it is not built yet.
|
|
25
85
|
|
|
26
86
|
## Why the whole reply is YAML
|
|
27
87
|
|
|
@@ -49,9 +109,9 @@ another, which makes a small document able to expand in ways the limits cannot s
|
|
|
49
109
|
|
|
50
110
|
| Layer | Owns |
|
|
51
111
|
| --- | --- |
|
|
52
|
-
| `@terreno/blocks` | Schema, parse, partial parse, validate, JSON Schema, prompt section, CLI, limits, error codes |
|
|
53
|
-
| `@terreno/ui` | `BlocksView`
|
|
54
|
-
| `@terreno/ai` | When `uiBlocks` is on: the chat system prompt, the post-stream `{blocks}` check, `AIDataset` storage, and `POST /gpt/actions`. `AIService.generateBlocks` returns one validated document outside a chat turn. |
|
|
112
|
+
| `@terreno/blocks` | Schema, parse, partial parse, validate, JSON Schema, prompt section, `blockPlainText`, CLI, limits, error codes |
|
|
113
|
+
| `@terreno/ui` | `BlocksView` renders every block in the catalog. A select action changes the target chart or table dataset in that view. A segmented control starts on the option that matches that dataset. A callback button or stepper stays disabled when `hostActions` is set and does not include its name; a checklist with such a callback ticks locally instead. A `copy` button writes the clipboard on the device. `GPTChat` `uiBlocks` renders assistant messages through `BlocksView`, including a spinner while the reply is still streaming, and swaps a block when a callback returns `{replace: "block"}`. A `file:` image stays as alt text until `resolveImage` returns a URL. |
|
|
114
|
+
| `@terreno/ai` | When `uiBlocks` is on: the chat system prompt, the post-stream `{blocks}` check, `AIDataset` storage, and `POST /gpt/actions`. The opt-in `scaleStepperHostAction` and `toggleChecklistHostAction`. `AIService.generateBlocks` returns one validated document outside a chat turn. |
|
|
55
115
|
|
|
56
116
|
Asks use the same package under `src/asks/`. A block shows something. An ask collects an
|
|
57
117
|
answer and returns it to the agent.
|
|
@@ -16,14 +16,14 @@ that file (and its imports) to a working example. Gaps stay explicit.
|
|
|
16
16
|
| Admin panel (embedded) | yes — Admin plugin registration in `example-backend/src/server.ts` | yes — `example-frontend/app/admin/` | Expo routes wrap `@terreno/admin-frontend` screens. |
|
|
17
17
|
| Admin SPA | yes — `AdminSpaServeApp` in `example-backend/src/server.ts` | n/a | Standalone SPA is served from the backend; not a frontend route. |
|
|
18
18
|
| AI streaming chat | yes — `example-backend/src/api/ai.ts` (`addGptRoutes`) | yes — `example-frontend/app/(tabs)/ai.tsx` (`GPTChat`, optional `mascot`) | Empty-chat mascot is consumer-owned; the example fox is not a framework default. |
|
|
19
|
-
| UI blocks | yes — `uiBlocks` with `repair: true` and `
|
|
19
|
+
| UI blocks | yes — `uiBlocks` with `repair: true`, `exportDataset`, and the opt-in `scaleStepper` and `toggleChecklist` callbacks in `example-backend/src/ai/hostActions.ts`, wired from `example-backend/src/api/ai.ts`; `todoStats` in `example-backend/src/ai/tools.ts` stores a `ref` dataset; `findPhotos` in the same file cites the generated photo library, and `example-backend/src/api/photoLibrary.ts` signs its URLs | yes — `example-frontend/app/(tabs)/ai.tsx` (`uiBlocks`, dataset and action hooks, `hostActions` includes `exportDataset`, `scaleStepper`, and `toggleChecklist`, `resolveImage` resolves `file:` photo ids through `useLazyPhotoLibraryUrlQuery`) | e2e mocks a document with one inline and one `ref` chart. A second e2e test stores the Sunday roast reply (`blocks/src/fixtures/golden/sunday-roast.yaml` with `file:` photo ids) in a real `GptHistory`, streams it from the mocked model, and runs the stepper and checklist through the real `POST /gpt/actions`; photo URLs come from the real `GET /photoLibrary/:id/url`, and only the image download is stubbed (`example-frontend/e2e/helpers/seedGptHistory.ts`). Steps: [agent-ui-blocks.md](../how-to/agent-ui-blocks.md). |
|
|
20
20
|
| Agent asks | yes — `asks: {approvals}` in `example-backend/src/api/ai.ts`, with the per-request `deleteCompletedTodos` approval tool from `example-backend/src/api/todoTools.ts`; it also passes `chat` to `addGptHistoryRoutes` for the headless `pendingAsks` and `turn` endpoints; keyless scripted agent with short compact-surface replies in `example-backend/src/api/demoAgent.ts` | yes — `example-frontend/app/(tabs)/ai.tsx` (`onAskSubmit`, `askErrors`), helpers in `example-frontend/lib/gptAsks.ts` | Without `GEMINI_API_KEY`, "Help me pick a plan" asks a `choice` in chat, "Pick toppings" asks a `select: "many"` `choice` with an Other field, "Send the weekly report" and "Archive old chats" ask a `confirm` (the second `destructive`), "Draft an announcement" asks a `markdown` edit of a draft, "Fill in the invoice details" asks a `form` with eight typed fields, "Upload a receipt" asks for `files`, sent as uploads when `GCS_BUCKET` is set and as data URLs otherwise, and "Delete my completed todos" calls `deleteCompletedTodos`, which runs only after the user approves the server's destructive approval card. e2e: `example-frontend/e2e/ai-chat.spec.ts`. Small clients: the curl walkthrough in the how-to and the demo's watch-sized `SimpleAskCard` story. Steps: [agent-ui-asks.md](../how-to/agent-ui-asks.md). |
|
|
21
21
|
| AI structured output | no | no | `@terreno/ai` supports structured generation; the example only streams chat. Recorded gap — not claimed by a current tutorial. |
|
|
22
22
|
| Feature flags + live updates | yes — `FeatureFlagsApp` in `example-backend/src/server.ts`, seed `example-backend/src/scripts/seed-feature-flags.ts` | yes — `useTerrenoFeatureFlags` in `example-frontend/app/_layout.tsx` | Socket-backed live updates share the realtime connection. |
|
|
23
23
|
| Websockets / realtime | yes — `RealtimeApp` in `example-backend/src/server.ts`, `example-backend/src/websockets.ts` | yes — `useSocketConnection` in `example-frontend/app/_layout.tsx` | Sync deltas also use the socket (`SyncApp` + `@terreno/syncdb`). |
|
|
24
|
-
| Consent forms | yes — `example-backend/src/consentDefinitions.ts`, seed scripts | yes — `example-frontend/app/(tabs)/
|
|
24
|
+
| Consent forms | yes — `example-backend/src/consentDefinitions.ts`, seed scripts | yes — `example-frontend/app/(tabs)/documents.tsx` (Consents section), admin `example-frontend/app/admin/consent-forms/` | First-login flow is covered by e2e (`example-frontend/e2e/consents.spec.ts`). |
|
|
25
25
|
| Product announcements | yes — `AnnouncementsApp` in `example-backend/src/server.ts`, release upload token via `ANNOUNCEMENTS_UPLOAD_TOKEN`, seed `example-backend/src/scripts/seed-announcements.ts`, sample release pack `example-backend/announcements/releases/1.14.0/` with `bun run announcements:pack` | yes — `AnnouncementNavigator` in `example-frontend/app/_layout.tsx` and admin announcement routes | Release packs support multiple Markdown surfaces and idempotent draft or explicit live API import. |
|
|
26
|
-
| File upload / GCS | yes — `example-backend/src/api/settings.ts`, AI file routes in `example-backend/src/api/ai.ts`, `file-uploads` flag in `example-backend/src/api/fileUploads.ts` | yes — `example-frontend/app/(tabs)/
|
|
26
|
+
| File upload / GCS | yes — `example-backend/src/api/settings.ts`, AI file routes in `example-backend/src/api/ai.ts`, `file-uploads` flag in `example-backend/src/api/fileUploads.ts` | yes — `example-frontend/app/(tabs)/documents.tsx` (Files section, every signed-in user, 1 upload / IP / min), `example-frontend/app/(tabs)/ai.tsx`, `example-frontend/app/gcs-settings.tsx` | The `file-uploads` feature flag hides upload controls and rejects uploads when off. A missing flag leaves uploads enabled. Deployed bucket is terraform-managed (`google_storage_bucket.example_documents`). |
|
|
27
27
|
| Better Auth | yes — `example-backend/src/utils/betterAuthConfig.ts`, `BetterAuthApp` in `example-backend/src/server.ts` | yes — `example-frontend/app/login.tsx`, `example-frontend/lib/betterAuth.ts` | Default `AUTH_PROVIDER` is `better-auth`. |
|
|
28
28
|
| syncdb local-first | yes — `SyncApp` in `example-backend/src/server.ts` | yes — `example-frontend/store/syncdb.ts`, `example-frontend/app/(tabs)/index.tsx` | PR #869 closed without merge; `@terreno/syncdb` shipped on the launch line and is the example todos path. |
|
|
29
29
|
| SyncDB diagnostics | n/a | yes — `debug` registration in `example-frontend/store/syncdb.ts`, debugger UI at `example-frontend/app/syncdb-debug.tsx` | `terreno-mcp-local` can inspect, snapshot/compare/merge, mutate, flush, reconcile/resync, and exercise offline/conflict paths against the running development client. |
|
|
@@ -1319,6 +1319,18 @@ One easy-to-use harness inside `@terreno/ai` that runs long-lived agentic work d
|
|
|
1319
1319
|
|
|
1320
1320
|
---
|
|
1321
1321
|
|
|
1322
|
+
## agent-ui-rich-replies
|
|
1323
|
+
|
|
1324
|
+
**Title:** `Agent UI Rich Replies: steppers, checklists, galleries, and copy`
|
|
1325
|
+
|
|
1326
|
+
**Labels:** `area:dx`, `type:feature`
|
|
1327
|
+
**Project fields:** Area=`dx`, Target=`Next`, Impact=`Feature`, IP=`agent-ui-rich-replies`, Status=`Planned`
|
|
1328
|
+
|
|
1329
|
+
- **Implementation plan:** [agent-ui-rich-replies.md](https://github.com/TerrenoLabs/terreno/blob/master/docs/implementationPlans/agent-ui-rich-replies.md)
|
|
1330
|
+
- **Tasks:** [agent-ui-rich-replies.md](https://github.com/TerrenoLabs/terreno/blob/master/docs/tasks/agent-ui-rich-replies.md)
|
|
1331
|
+
|
|
1332
|
+
---
|
|
1333
|
+
|
|
1322
1334
|
# Shipped, umbrella, and declined IPs
|
|
1323
1335
|
|
|
1324
1336
|
Tracking issues created for IPs that previously lacked a `**Roadmap issue:**` header.
|
|
@@ -53,6 +53,8 @@ Problem-oriented, practical steps. Use these when you know what you want to do.
|
|
|
53
53
|
- [Add a GPT chat mascot](add-gpt-chat-mascot.md) — Optional consumer-owned character on empty `GPTChat`
|
|
54
54
|
- [Add agent asks to a chat](agent-ui-asks.md) — Turn on `asks`, show and answer them in `GPTChat`, try the keyless demo agent, and answer asks from an Apple Watch or another small client
|
|
55
55
|
- [Validate a block document locally](agent-ui-blocks.md) — `terreno-blocks validate` for a whole-reply YAML document
|
|
56
|
+
- [Add a stepper callback](agent-ui-blocks.md#add-a-stepper-callback) — `scaleStepperHostAction` or your own `handles: "stepper"` action; checklist ticks, copy buttons, the `richBlocks: false` opt-out, and the `blocks:smoke` model check are on the same page
|
|
57
|
+
- [Give the agent photos](agent-ui-blocks.md#give-the-agent-photos) — Generate a stored photo library once and let the agent cite it with `findPhotos`
|
|
56
58
|
|
|
57
59
|
## Admin
|
|
58
60
|
|