Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1cdc116
feat(ai-harness): first-party plugins in @tanstack/ai-harness/plugins
AlemTuzlak Oct 13, 2026
84c6153
docs(ai-harness): say that a tool with no rule runs in plan mode
AlemTuzlak Oct 13, 2026
397f183
feat(ai-harness): providerKeys() plugin lets each user connect their …
AlemTuzlak Oct 13, 2026
d323e93
Merge remote-tracking branch 'origin/feat/harness-core' into feat/har…
AlemTuzlak Oct 13, 2026
a96cddf
Merge remote-tracking branch 'origin/feat/harness-plugins' into feat/…
AlemTuzlak Oct 13, 2026
cee77b5
Merge remote-tracking branch 'origin/feat/harness-core' into feat/har…
AlemTuzlak Oct 13, 2026
6b253fd
Merge branch 'feat/harness-plugins' into feat/harness-provider-keys
AlemTuzlak Oct 13, 2026
d6d6f8d
test(ai-e2e): read the key from the adapter factory, aimock redacts t…
AlemTuzlak Oct 13, 2026
29bb0a4
fix(ai-persistence): store a tool result once when a run resumes from…
PatrM Oct 14, 2026
761a652
fix(openai-base): report Responses cache write tokens in usage (#1774)
tombeckenham Oct 14, 2026
6a9f0b1
fix(ai-opencode, ai-sandbox): end the run when a teardown step does n…
tombeckenham Oct 14, 2026
3170517
feat(ai): check tool input after approval edits and middleware, just …
AlemTuzlak Oct 14, 2026
eb69ad0
Merge remote-tracking branch 'origin/feat/harness-core' into feat/har…
AlemTuzlak Oct 14, 2026
9bdd860
fix(ai-harness): adopt object params from #1779
AlemTuzlak Oct 14, 2026
b113c45
docs(ai-harness): answer permission questions with onEvent
AlemTuzlak Oct 14, 2026
aea1f8a
ci: apply automated fixes
autofix-ci[bot] Oct 14, 2026
e773248
Merge remote-tracking branch 'origin/feat/harness-plugins' into feat/…
AlemTuzlak Oct 14, 2026
1d6615b
fix(ai-harness, ai-e2e): adopt object params from #1779
AlemTuzlak Oct 14, 2026
3c8a8cb
docs(ai-harness): answer the /connect question with onEvent
AlemTuzlak Oct 14, 2026
5225695
docs(ai-harness): answer each open permission question once
AlemTuzlak Oct 14, 2026
c1df197
Merge remote-tracking branch 'origin/feat/harness-plugins' into feat/…
AlemTuzlak Oct 14, 2026
30fa651
fix(ai, ai-persistence): close subagent budget and continue edges (#1…
tombeckenham Oct 15, 2026
ee374b4
fix(ai-compaction, openai-base): do not save a failed native compact …
tombeckenham Oct 15, 2026
ef6c44f
feat(ai-client): publish observable client snapshots (#1232)
AlemTuzlak Oct 15, 2026
5f95dbd
fix(ai): report evaluate usage when answer mapping fails (#1742)
ktrz Oct 15, 2026
f68da51
fix(ai): file each model call on its own assistant message (#1776)
tombeckenham Oct 15, 2026
4298480
fix(ai): keep REASONING_MESSAGE_START metadata on the assistant messa…
tombeckenham Oct 15, 2026
85c2956
feat(openai-base, ai-openrouter, ai-groq, ai-utils): send json_object…
tombeckenham Oct 15, 2026
786b993
Merge remote-tracking branch 'origin/feat/harness-core' into feat/har…
AlemTuzlak Oct 15, 2026
5fb4f24
test(ai-harness): pass thread id to inbox.get in provider-keys test
jherr Oct 15, 2026
4c7a59d
Merge feat/harness-core into feat/harness-provider-keys
Copilot Oct 15, 2026
fb39ded
Merge remote-tracking branch 'origin/main' into feat/harness-provider…
Copilot Oct 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .changeset/ai-client-store-snapshot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
'@tanstack/ai-client': minor
'@tanstack/ai-react': minor
'@tanstack/ai-solid': minor
'@tanstack/ai-vue': minor
'@tanstack/ai-svelte': minor
'@tanstack/ai-angular': minor
'@tanstack/ai-preact': minor
'@tanstack/ai-octane': minor
'@tanstack/ai-remix': minor
---

Hold client UI state in a TanStack Store atom. Framework hooks read `getSnapshot()` instead of copying fields through change callbacks. React `useChat()` first commits `initialMessages` and `initialResumeSnapshot`, then applies browser persistence after attach. This timing applies to client-only rendering and keeps the server snapshot stable during SSR hydration. Until the stored transcript is applied, `isHydrating` is `true`.

The snapshot `messages` and `queue` arrays are frozen in every adapter. An in-place change such as `messages.push()` throws a `TypeError`. Use `setMessages` to change messages. The hook return types now show this: `messages` and `queue` are `ReadonlyArray`, and so is `RealtimeClientState.messages`. If you pass `messages` to your own component or function, type that parameter as `ReadonlyArray<UIMessage>`.

Snapshot message `parts` are frozen at runtime too, but their TypeScript type stays mutable, because a readonly part list is not assignable to `UIMessage`. Tool `input`, `output`, and subagent transcripts on a snapshot are copies.

A message or part that did not change keeps the same object from one snapshot to the next. Memoized message rows do not render again when a different message streams.

`ChatClient` adds `subscribeSnapshot` / `getSnapshot`. The live connection method stays `subscribe()`. Generation, video, realtime, and BYOK clients expose `subscribe` / `getSnapshot`. `AudioRecorder.subscribe` still passes the new state value.

`RealtimeClient` behavior changes: when `connect()` connects, it clears the messages and the pending user and assistant transcripts from the previous session. A transcript that arrives while the microphone starts is kept. A failed connection keeps the previous transcript. `interrupt()` now clears `pendingAssistantTranscript`.

`setMessages` accepts the hook's readonly `messages`, including nested subagent cards. A listener that throws does not skip the other listeners in any client, and it does not leave `isLoading` stuck. The error goes to `reportError` in the browser and to `console.error` in other runtimes.
5 changes: 5 additions & 0 deletions .changeset/ai-harness-provider-keys.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai-harness': minor
---

Add the `providerKeys({ providers })` plugin to `@tanstack/ai-harness/plugins`. Users of a shipped harness connect their own model provider in the app, with no `.env` file. It adds `/connect:<id>`, `/disconnect:<id>`, and `/keys`. `/connect:<id>` runs the provider's `signIn` when it has one, else it opens `keyUrl` when set and asks the user to paste the key as a secret question. The key is saved in the credential store of the user, and a `keyedAdapter(...)` for that provider uses it. `/keys` and the plugin state show where each key comes from: a saved key (the last 4 characters only), the env var, or no key.
5 changes: 5 additions & 0 deletions .changeset/evaluate-usage-on-failure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai': patch
---

`decide()` now reports token usage when the provider answered but the answers cannot be mapped, for example when an answer is missing, has the wrong type, or has no probability for its value. Before, `decide()` threw without reporting the usage that the provider already billed. The `onUsage` middleware hook and the `evaluate:usage` event now get that usage once, before `onError` runs. `onFinish` still does not run for a failed call, and `decide()` throws the mapping error. If an `onUsage` hook throws, that error is thrown instead, as it is for a successful call. The mapping error is still logged.
17 changes: 17 additions & 0 deletions .changeset/json-schema-tool-input.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@tanstack/ai': minor
---

Check a raw JSON Schema tool input before the tool runs. This covers plain JSON Schema tools and every MCP tool.

Behavior change:

- A tool with a JSON Schema `inputSchema` now gets a tool error (state `output-error`) when the input does not fit the schema. The tool does not run. Before, any input ran.
- The check runs at the same place as the Standard Schema check: after approval edits and middleware `onBeforeToolCall`.
- The draft comes from `$schema` (draft-04, draft-07, 2019-09, 2020-12). With no `$schema`, the check uses 2020-12. `format` is not checked.
- OpenAPI 3.0 schemas work: `nullable: true` lets the field be `null`, and a boolean `exclusiveMinimum` or `exclusiveMaximum` works in every draft.
- The error names each failed location (up to 10) and shows the received arguments: `Input validation failed for tool <name>: #/count: ...`.
- A schema that the check cannot use, such as one with a remote `$ref`, gives a tool error on each call.
- The check uses `@cfworker/json-schema`. It does not compile code, so it runs on Cloudflare Workers.

Migration: if a JSON Schema tool must accept input that its schema rejects, widen the schema.
6 changes: 6 additions & 0 deletions .changeset/native-compact-retry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@tanstack/ai-compaction': patch
'@tanstack/openai-base': patch
---

A failed native `compact` is not saved as the checkpoint or the durable compaction record. The next process calls `compact` again. A compact result keeps image files, documents, and audio, and sends those parts back on the next request.
6 changes: 6 additions & 0 deletions .changeset/opencode-teardown-bounded.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@tanstack/ai-opencode': patch
'@tanstack/ai-sandbox': patch
---

`RUN_FINISHED` now arrives when a teardown step does not settle. The OpenCode adapter gives each teardown step (session dispose, server dispose, tool bridge close) one second and logs a step that fails. The host tool bridge's `close()` now closes open connections, so an agent that holds a request open on the bridge no longer blocks the end of a Claude Code, Codex, or OpenCode run.
5 changes: 5 additions & 0 deletions .changeset/persistence-resume-tool-results.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai-persistence': patch
---

Store a tool result once when a run resumes from a client-tool interrupt. The client posts earlier tool results under interrupt snapshot ids the store never saw, so `withPersistence` appended a second copy and the next provider request failed.
19 changes: 19 additions & 0 deletions .changeset/raw-tool-arguments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
'@tanstack/ai': minor
'@tanstack/openai-base': patch
'@tanstack/ai-openrouter': patch
'@tanstack/ai-bedrock': patch
'@tanstack/ai-mistral': patch
'@tanstack/ai-gemini': patch
'@tanstack/ai-ollama': patch
'@tanstack/ai-anthropic': patch
---

Keep the provider's raw tool argument string for replay.

- Adapters now send the raw argument string as `args` on `TOOL_CALL_END`.
- The tool call in the history keeps that exact string when it is the same JSON value as the parsed input, so the next request sends the provider's own bytes back (for example `1.50`, or an id past `Number.MAX_SAFE_INTEGER`). When the parsed input differs, only the changed values are written again.
- The `TOOL_CALL_END` that reaches the client carries the same string in `metadata.tanstack.args`, so the client history matches the server history. It no longer also carries `metadata.tanstack.input`: in-process `chat()` and `StreamProcessor` parse `input` from `args`. Run the client and the server on the same release: an older client ignores `args`, so it builds the tool input from the streamed deltas only, and a tool call with no deltas (for example an Anthropic server tool) gets no input.
- History converters for Bedrock and the Gemini Interactions API send malformed tool arguments as `{}` instead of failing the request.
- Gemini Interactions: the initial `step.arguments` snapshot goes out as a `TOOL_CALL_ARGS` delta only when no argument deltas follow, so the deltas always add up to the final arguments.
- Malformed tool arguments are no longer turned into `{}` by an adapter. The tool gets a "Failed to parse tool arguments as JSON" error that the model can repair. Mistral still ends the run with an error on malformed arguments, as before.
5 changes: 5 additions & 0 deletions .changeset/reasoning-start-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai': patch
---

Keep custom metadata from `REASONING_MESSAGE_START` on the assistant `UIMessage`. The thinking text was already kept. Metadata that arrived only on the start event was dropped.
5 changes: 5 additions & 0 deletions .changeset/responses-cache-write-tokens.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/openai-base': patch
---

Responses API usage now reports `promptTokensDetails.cacheWriteTokens` from `input_tokens_details.cache_write_tokens`, the same as the Chat Completions path.
5 changes: 5 additions & 0 deletions .changeset/stream-message-ownership.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai': patch
---

File each model call on its own assistant message. Reasoning that arrives before the call's text id, a tool call whose parent id is new, and a signature that names an earlier step stay on the message that owns them.
12 changes: 12 additions & 0 deletions .changeset/structured-output-json-object.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@tanstack/ai-utils': minor
'@tanstack/openai-base': minor
'@tanstack/ai-openrouter': minor
'@tanstack/ai-groq': minor
---

Structured output sends `response_format: { type: "json_object" }` for OpenRouter and Groq models that declare a response format without strict structured outputs. These models reject strict `json_schema`. In JSON mode the adapter adds the schema as a system prompt. `await chat({ outputSchema })` checks the reply when the schema is a Standard Schema, such as Zod. Other models keep strict `json_schema`.

`modelOptions` can set `json_object` for any model. On the OpenAI-base adapters (OpenAI, Grok, Groq and others), a `json_object` in `modelOptions` was replaced by strict `json_schema`. It is now sent as given, with the schema in a system prompt. In JSON mode, `supportsCombinedToolsAndSchema()` returns `false`. Tools and the schema then go out in separate requests, so the tool-calling turns do not get the schema prompt.

OpenRouter catalog ids with a `:variant`, such as `google/gemma-4-26b-a4b-it:free`, now match their own catalog entry. Before, only the id without the variant was checked.
11 changes: 11 additions & 0 deletions .changeset/subagent-budget-edges.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@tanstack/ai': patch
'@tanstack/ai-persistence': patch
---

Fix subagent limit and continue edges.

- A background `start` that throws gives the `maxCalls` slot back. `maxConcurrent` counts that child until `done` settles. `start` now returns `done`.
- A schema result that is not an object does not drop `sessionId` or `background`. A top-level `anyOf` schema still shows those fields.
- A suspended child with no stored `base` keeps its transcript.
- When the parent deadline is already past, the model gets `subagent limit reached (no time left)`.
12 changes: 12 additions & 0 deletions .changeset/tool-input-coercion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@tanstack/ai': minor
---

Repair common model mistakes in a tool input before the final input check.

- When a JSON Schema tool's input (and every MCP tool's input) fails the check, it is repaired and checked again: `"5"` as `5` (decimal text only), `"true"` as `true`, `5` as `"5"` for a string, and `null` as `""`, `0`, or `false` for a required field. A `null` for an optional field that does not allow `null` is removed. The repair follows unions, `$ref`, `if`/`then`/`else`, `prefixItems`, `patternProperties`, and `additionalProperties`.
- A Standard Schema runs first as written. When it fails and the schema can export JSON Schema (Zod, ArkType, Valibot), the input is repaired and the schema runs again. A failure reports the issues of the first run.
- The received arguments do not change. The tool gets the repaired copy.
- New `chat({ repairToolInput })` option. `false` turns the repair off. A function replaces the built-in repair: it gets `{ tool, toolCall, input, error }` and returns the input to check again, or `undefined` to send the validation error to the model.

Behavior change: a call that failed the check only because of these mistakes now runs with the repaired input.
22 changes: 22 additions & 0 deletions .changeset/tool-input-final-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
'@tanstack/ai': minor
---

Check a tool input at the last moment, just before the tool runs or the client gets the call.

Behavior change:

- The tool's Standard Schema `inputSchema` now checks the input after approval `editedArgs` and after middleware `onBeforeToolCall`. Before, a `transformArgs` value reached `execute` or the client without a check. An input that does not fit the schema now becomes a tool error (state `output-error`), and the tool does not run. An approval edit is also still checked when the run resumes.
- `onBeforeToolCall` gets the parsed input before the schema check. It has no schema defaults or transforms yet, and it can be invalid.
- Async Standard Schema input validators are awaited. Before, every call to such a tool failed with an input validation error.
- `onBeforeToolCall` now also runs for a client tool before the server sends the call to the client. This includes a client request at an interrupt boundary. It does not run while a call waits for approval or for a denied call. When the client result comes back, the result is kept, with no second hook run and no second check. `otelMiddleware` records no `execute_tool` span for a client tool, because the server does not run it.
- A validation error after the hook runs `onAfterToolCall` with `ok: false`.
- The tool error that the model sees now also shows the arguments that the model sent. When an approval edit or middleware changed them, the error says so.
- While a call waits for approval, an approved client tool in the same batch is now sent to the client. Before, it waited for the next round trip.
- When the only call that waits for approval fails its input check, the other calls of the batch now run. Before, they got no result.

Migration:

- If a middleware `transformArgs` or an approval edit sends a value that the schema rejects, make the value fit the schema, or widen the schema.
- If `onBeforeToolCall` reads `hookCtx.args`, check its shape first. Do not expect schema defaults there.
- If a middleware counts or blocks calls in `onBeforeToolCall` and must see only server tools, return early when `hookCtx.tool?.execute` is missing.
4 changes: 4 additions & 0 deletions docs/adapters/groq.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,10 @@ Creates a Groq summarization adapter with an explicit API key.

Creates a Groq transcription (speech-to-text) adapter. The short form reads `GROQ_API_KEY` from the environment; the `create*` form takes an explicit API key. Supported models: `whisper-large-v3-turbo`, `whisper-large-v3`.

## Structured output

Some Groq models, for example `llama-3.3-70b-versatile`, reject strict JSON schema. For these models, `chat({ outputSchema })` sends `json_object` and adds your schema to the system prompt. Read [When strict JSON schema is rejected](../structured-outputs/overview.md#when-strict-json-schema-is-rejected).

## Limitations

- **Text-to-Speech**: Groq does not currently expose a TTS adapter. Use OpenAI, Gemini, ElevenLabs, or fal for speech generation.
Expand Down
21 changes: 21 additions & 0 deletions docs/adapters/openrouter.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,27 @@ export async function POST(request: Request) {
}
```

## JSON mode

Some OpenRouter models reject strict JSON schema. For these models, `chat({ outputSchema })` sends `json_object` and adds your schema to the system prompt.

To send JSON mode to any other model, set `modelOptions.responseFormat`:

```typescript
import { chat } from "@tanstack/ai";
import { openRouterText } from "@tanstack/ai-openrouter";
import { z } from "zod";

const person = await chat({
adapter: openRouterText("openai/gpt-5.6-sol"),
messages: [{ role: "user", content: "Return Ada Lovelace, age 36." }],
modelOptions: { responseFormat: { type: "json_object" } },
outputSchema: z.object({ name: z.string(), age: z.number() }),
});
```

Read [When strict JSON schema is rejected](../structured-outputs/overview.md#when-strict-json-schema-is-rejected).

## Tools and structured output together

You can pass both `tools` and `outputSchema` on one `chat()` call. For some
Expand Down
21 changes: 20 additions & 1 deletion docs/advanced/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,26 @@ system prompt, is in [Apply Answers](../interrupts/apply-answers).

### onBeforeToolCall

Called before each tool executes. The first middleware that returns a non-void decision short-circuits — remaining middleware are skipped for that tool call.
Called before a server tool runs, and before a client tool goes to the client. The first middleware that returns a non-void decision skips the remaining middleware for that call.

Each tool call goes through these steps:

1. The engine parses the JSON arguments from the model.
2. `onBeforeToolCall` gets the parsed input.
3. The tool's `inputSchema` checks the final input. An async validator is awaited. A schema transform applies once, here.
4. The server tool runs, or the client gets the call, with the checked input.

The schema checks the input after your hook:

- `hookCtx.args` has no schema defaults or transforms yet, and it can be invalid. Check its shape before you read it.
- A `transformArgs` value or an in-place edit must fit the schema. If it does not fit, the call gets a tool error, `onAfterToolCall` runs with `ok: false`, and the tool does not run.

When the hook runs:

- A client tool runs the hook before the server sends the call to the client. The hook does not run when the client result comes back.
- A client tool gets `onAfterToolCall` only when the hook skips the call or the schema check fails. The result from the client does not run it. If your middleware pairs the two hooks, return early when `hookCtx.tool?.execute` is missing.
- A call that waits for approval does not run the hook. A denied call does not run it either.
- After approval, the hook gets the approved input, including any `editedArgs`. See [Tool Approval](../interrupts/tool-approval).

```typescript
import { type ChatMiddleware } from "@tanstack/ai";
Expand Down
4 changes: 2 additions & 2 deletions docs/api/ai-angular.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ import type {
type TSchema = any;

interface InjectChatResult {
messages: Signal<UIMessage[]>;
messages: Signal<ReadonlyArray<UIMessage>>;
sendMessage: (
content: string | MultimodalContent,
options?: SendMessageOptions,
Expand All @@ -171,7 +171,7 @@ interface InjectChatResult {
reload: () => Promise<void>;
stop: () => void;
clear: () => void;
setMessages: (messages: UIMessage[]) => void;
setMessages: (messages: ReadonlyArray<UIMessage>) => void;
isLoading: Signal<boolean>;
error: Signal<Error | undefined>;
status: Signal<ChatClientState>;
Expand Down
52 changes: 51 additions & 1 deletion docs/api/ai-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,56 @@ Stop tailing and drop the connection. Keeps messages, the run pointer and the ru
id, so a later `attach()` continues where it left off. See
[Lifecycle](#lifecycle-attach-and-detach).

#### `getSnapshot()`

Returns the current `ChatClientSnapshot`. The field names are
`messages`, `status`, `isLoading`, `error`, `queue`, `runId`, `isSubscribed`,
`connectionStatus`, `sessionGenerating`, `hasOlderMessages`, `isHydrating`,
and `interruptState`. The snapshot object, `messages`, `queue`, and their
entries are frozen copies. `interruptState` is not copied. In-place
`messages.push` throws. Use `setMessages`.

`subscribeSnapshot(listener)` returns an unsubscribe function. It does not
fire with the current value. Read `getSnapshot()` first. This is not
`subscribe()`, which starts the live connection loop.

```typescript
import { ChatClient, fetchServerSentEvents } from "@tanstack/ai-client";

const client = new ChatClient({
connection: fetchServerSentEvents("/api/chat"),
});

function logSnapshot() {
const snapshot = client.getSnapshot();
console.log(snapshot.status, snapshot.messages.length);
}

logSnapshot();

const unsubscribe = client.subscribeSnapshot(() => {
logSnapshot();
});

client.attach();
client.sendMessage("Hello");
```

`GenerationClient`, `VideoGenerationClient`, `RealtimeClient`, and
`ByokClient` use `subscribe(listener)` / `getSnapshot()`. The listener takes
no argument. Call `getSnapshot()` inside it. A listener that throws does not
skip the other listeners. The error goes to `reportError` in the browser and
to `console.error` in other runtimes.

When `RealtimeClient.connect()` connects, it clears the previous transcript.
A transcript that arrives while the microphone starts is kept. A failed
connection keeps the previous transcript. Snapshot `parts` are frozen at
runtime, but their TypeScript type stays mutable. Tool `input`, `output`, and
subagent transcripts on a snapshot are copies.

`AudioRecorder.subscribe` still passes the new state:
`subscribe((state) => ...)`. `getSnapshot()` returns that same state value.

#### `stop()`

Stops the current response generation. It aborts the in-flight request.
Expand All @@ -296,7 +346,7 @@ import { client } from "./client";
client.clear();
```

#### `setMessagesManually(messages: UIMessage[])`
#### `setMessagesManually(messages: ReadonlyArray<UIMessage>)`

Manually sets the messages array.

Expand Down
Loading