feat(ai-chat-ref): add undo action + button to demo agent
Wire a typed action on the main `aiChat` agent in
references/ai-chat — `actionSchema` accepts `{ type: "undo" }` and
`onAction` calls `chat.history.slice(0, -2)` to drop the last
user/assistant exchange. Adds an Undo button to the chat input row
that calls `transport.sendAction(chatId, { type: "undo" })` and
optimistically updates local `useChat` state via `setMessages`.
Exercises the new TRI-9118 action semantics end-to-end through the
demo UI: clicking Undo emits a `chat action` span (not `chat turn`),
fires only `onAction()`, no `run()` / `streamText` / turn lifecycle
hooks. The next message turn sees the truncated server-side history.
This commit is contained in:
@@ -937,6 +937,24 @@ export function Chat({
|
||||
Stop
|
||||
</button>
|
||||
)}
|
||||
{/* Undo — server-side `chat.history.slice(0, -2)` via the
|
||||
`undo` action, optimistically reflected in the local
|
||||
`useChat` state. Drops the last user / assistant exchange.
|
||||
Only meaningful when there's at least one full exchange
|
||||
and the chat isn't currently streaming. */}
|
||||
{status !== "streaming" && messages.length >= 2 && (
|
||||
<button
|
||||
type="button"
|
||||
disabled={isReadOnly}
|
||||
onClick={() => {
|
||||
void transport.sendAction(chatId, { type: "undo" });
|
||||
setMessages((prev) => prev.slice(0, -2));
|
||||
}}
|
||||
className="rounded-lg bg-amber-500 px-4 py-2 text-sm font-medium text-white hover:bg-amber-600 disabled:opacity-50"
|
||||
>
|
||||
Undo
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -401,6 +401,21 @@ export const aiChat = chat
|
||||
},
|
||||
// #endregion
|
||||
|
||||
// #region actionSchema + onAction — typed actions for state-only mutations
|
||||
// Actions are not turns: only `hydrateMessages` and `onAction` fire,
|
||||
// no `run()` invocation, no model call. The `undo` action drops the
|
||||
// last user/assistant exchange so the next message turn sees a
|
||||
// truncated history.
|
||||
actionSchema: z.discriminatedUnion("type", [
|
||||
z.object({ type: z.literal("undo") }),
|
||||
]),
|
||||
onAction: async ({ action }) => {
|
||||
if (action.type === "undo") {
|
||||
chat.history.slice(0, -2);
|
||||
}
|
||||
},
|
||||
// #endregion
|
||||
|
||||
// #region onTurnComplete — persist + background self-review via chat.inject()
|
||||
onTurnComplete: async ({
|
||||
chatId,
|
||||
|
||||
Reference in New Issue
Block a user