Loading workspace insights... Statistics interval
7 days30 daysLatest CI Pipeline Executions
aa9b7b8b feat: multi-capability assistants (defineAssistant + useAssistant)
Declare an assistant's capabilities once on the server and consume them
from one typed client hook, over a single endpoint.
Server (`@tanstack/ai/assistant`)
- `defineAssistant(config)`: an inert registry of per-capability callbacks
(chat, image, audio, speech, video, transcription, summarize), each
invoking an existing activity. Exposes one `handler(request)` that parses
the AG-UI request, routes by a `capability` discriminator, and streams the
result back over the existing SSE wire. Nothing is constructed until a
request arrives.
- Every callback — chat and one-shots alike — receives the same validated
AG-UI envelope: `chat` gets `AssistantChatRequest`; one-shots get their
input plus `threadId`/`runId`/`parentRunId`/`state`/`aguiContext`/
`forwardedProps` and the raw `request`, all parsed through the same
request validator (`chatParamsFromRequestBody`). Untrusted input fields
(e.g. `req.prompt`) stay `unknown` so callbacks narrow before use.
Client core (`@tanstack/ai-client/assistant`)
- `AssistantClient` composes one `ChatClient` + one `GenerationClient` per
declared capability behind a single connection. `AssistantSystem<TDef>`
maps declared capabilities to fully-typed surfaces, inferred from the
definition — no call-site generics.
- The imperative methods resolve to their results, so capabilities chain
with a plain `await` instead of reading reactive state (which is stale in
an async closure under React): `assistant.<oneshot>.generate(input)`
resolves to the generation result (`TResult | null`), and
`assistant.chat.sendMessage(...)` resolves to the validated structured
`final` when the chat callback declared an `outputSchema`, otherwise to
the messages array. Reactive `.result`/`.messages`/`.partial`/`.final`
remain for rendering.
Framework hooks
- `useAssistant` for React / Solid / Vue and `createAssistant` for Svelte
(`@tanstack/ai-<fw>/assistant`). Each capability entry is the corresponding
primitive hook's own return (`useChat` / `useGeneration`).
Chat type inference
- `chat()`'s return carries an optional type-only phantom
(`ChatResultMeta<TTools, TSchema, TStream>`), so `assistant.chat` infers
typed `partial`/`final` from an `outputSchema` and types message tool-call
parts from the callback's tools — no client re-declaration. Runtime
unchanged. Client-executed tools still pass through `chat: { tools }` for
their browser implementations (their code can't cross the wire).
Docs (`docs/assistant`): a 3-page section — Overview (what an assistant is,
when to reach for one vs. single hooks, and typed chat/tools/structured
output), Scenarios (sequential pipeline + CMS content workflow, chained via
the resolved `await` returns), and Multiple Assistants (specialized
per-surface assistants across routes, plus composing two assistants together
on one page). Plus an `ai-core/assistant` agent skill, E2E coverage (chat
verified end-to-end; image one-shot skipped pending an aimock media fixture),
and a changeset. ef8c01e8 feat: multi-capability assistants (defineAssistant + useAssistant)
Declare an assistant's capabilities once on the server and consume them
from one typed client hook, over a single endpoint.
Server (`@tanstack/ai/assistant`)
- `defineAssistant(config)`: an inert registry of per-capability callbacks
(chat, image, audio, speech, video, transcription, summarize), each
invoking an existing activity. Exposes one `handler(request)` that parses
the AG-UI request, routes by a `capability` discriminator, and streams the
result back over the existing SSE wire. Nothing is constructed until a
request arrives.
Client core (`@tanstack/ai-client/assistant`)
- `AssistantClient` composes one `ChatClient` + one `GenerationClient` per
declared capability behind a single connection. `AssistantSystem<TDef>`
maps declared capabilities to fully-typed surfaces, inferred from the
definition — no call-site generics.
Framework hooks
- `useAssistant` for React / Solid / Vue and `createAssistant` for Svelte
(`@tanstack/ai-<fw>/assistant`). Each capability entry is the corresponding
primitive hook's own return (`useChat` / `useGeneration`).
Chat type inference
- `chat()`'s return carries an optional type-only phantom
(`ChatResultMeta<TTools, TSchema, TStream>`), so `assistant.chat` infers
typed `partial`/`final` from an `outputSchema` and types message tool-call
parts from the callback's tools — no client re-declaration. Runtime
unchanged. Client-executed tools still pass through `chat: { tools }` for
their browser implementations (their code can't cross the wire).
Docs (`docs/assistant`): a 3-page section — Overview (what an assistant is +
when to reach for one vs. single hooks), Scenarios (sequential pipeline + CMS
content workflow), and Multiple Assistants (specialized per-surface assistants).
Plus an `ai-core/assistant` agent skill, E2E coverage (chat verified
end-to-end; image one-shot skipped pending an aimock media fixture), and a
changeset. 0c1202f6 feat: multi-capability assistants (defineAssistant + useAssistant)
Declare an assistant's capabilities once on the server and consume them
from one typed client hook, over a single endpoint.
Server (`@tanstack/ai/assistant`)
- `defineAssistant(config)`: an inert registry of per-capability callbacks
(chat, image, audio, speech, video, transcription, summarize), each
invoking an existing activity. Exposes one `handler(request)` that parses
the AG-UI request, routes by a `capability` discriminator, and streams the
result back over the existing SSE wire. Nothing is constructed until a
request arrives.
Client core (`@tanstack/ai-client/assistant`)
- `AssistantClient` composes one `ChatClient` + one `GenerationClient` per
declared capability behind a single connection. `AssistantSystem<TDef>`
maps declared capabilities to fully-typed surfaces, inferred from the
definition — no call-site generics.
Framework hooks
- `useAssistant` for React / Solid / Vue and `createAssistant` for Svelte
(`@tanstack/ai-<fw>/assistant`). Each capability entry is the corresponding
primitive hook's own return (`useChat` / `useGeneration`).
Chat type inference
- `chat()`'s return carries an optional type-only phantom
(`ChatResultMeta<TTools, TSchema, TStream>`), so `assistant.chat` infers
typed `partial`/`final` from an `outputSchema` and types message tool-call
parts from the callback's tools — no client re-declaration. Runtime
unchanged. Client-executed tools still pass through `chat: { tools }` for
their browser implementations (their code can't cross the wire).
Also: docs guide (`docs/assistant`), `ai-core/assistant` agent skill, E2E
coverage (chat verified end-to-end; image one-shot skipped pending an aimock
media fixture), and a changeset.