MiddlewareSAFE
🤖 Type-safe, provider-agnostic TypeScript AI SDK for streaming chat, tool calling, agents, and multimodal apps across OpenAI, Anthropic, Gemini, React, Vue, Svelte, and Solid.
Overview
🤖 Type-safe, provider-agnostic TypeScript AI SDK for streaming chat, tool calling, agents, and multimodal apps across OpenAI, Anthropic, Gemini, React, Vue, Svelte, and Solid.
dafe8ab3bd88OBSERVED · 2026-10-08What it tells the agent
The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
---
name: ai-core/middleware
description: >
Chat lifecycle middleware hooks: onConfig, onStart, onChunk,
onBeforeToolCall, onAfterToolCall, onUsage, onFinish, onAbort, onError.
Use for analytics, event firing, tool caching (toolCacheMiddleware),
logging, and tracing. Middleware array in chat() config, left-to-right
execution order. NOT onEnd/onFinish callbacks on chat() — use middleware.
type: sub-skill
library: tanstack-ai
library_version: '0.42.0'
sources:
- 'TanStack/ai:docs/advanced/middleware.md'
- 'TanStack/ai:docs/sandbox/observability.md'
- 'TanStack/ai:docs/persistence/overview.md'
---
# Middleware
> **Dependency note:** This skill builds on ai-core. Read it first for critical rules.
## Setup — Analytics Tracking Middleware
```typescript
import { chat, toServerSentEventsResponse } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { trackAnalytics, reportError } from './analytics'
export async function POST(request: Request) {
const { messages } = await request.json()
const stream = chat({
adapter: openaiText('gpt-5.5'),
messages,
middleware: [
{
onStart: (ctx) => {
console.log('Chat started:', ctx.model)
},
onFinish: (ctx, info) => {
trackAnalytics({ model: ctx.model, tokens: info.usage?.totalTokens })
},
onError: (ctx, info) => {
reportError(info.error)
},
},
],
})
return toServerSentEventsResponse(stream)
}
```
## Hooks Reference
Every hook receives a `ChatMiddlewareContext` as its first argument, which provides
`requestId`, `streamId`, `phase`, `iteration`, `chunkIndex`, `model`, `provider`,
`signal`, `abort()`, `defer()`, and more. `parentRunId` names the run this one continues. `subagentRunId` is set only inside a subagent and names its card.
| Hook | When | Second Argument |
| -------------------------- | -------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
| `onConfig` | Once at startup (`init`) + once per iteration (`beforeModel`) + once at a separate-finalization boundary | `ChatMiddlewareConfig` (return partial to merge) |
| `onStructuredOutputConfig` | Once at the separate-finalization boundary | `StructuredOutputMiddlewareConfig` (return partial) |
| `onStart` | Once after initial `onConfig` | none |
| `onIteration` | Start of each agent loop iteration | `IterationInfo` |
| `onShouldContinue` | Whether to start another agent-loop iteration (AND with strategy; `false` stops) | `AgentLoopState` |
| `onChunk` | Every streamed chunk | `StreamChunk` (return void/chunk/chunk[]/null) |
| `onBeforeToolCall` | Before each tool executes | `ToolCallHookContext` (return decision or void) |
| `onAfterToolCall` | After each tool executes | `AfterToolCallInfo` |
| `onToolPhaseComplete` | After all tool calls in an iteration | `ToolPhaseCompleteInfo` |
| `onUsage` | When `RUN_FINISHED` includes usage data | `UsageInfo` |
| `onFinish` | Run completed normally | `FinishInfo` |
| `onAbort` | Run was aborted | `AbortInfo` |
| `onError` | Unhandled error occurred | `ErrorInfo` |
Terminal hooks (`onFinish`, `onAbort`, `onError`) are **mutually exclusive** -- exactly
one fires per `chat()` invocation.
> **Sampling in `onConfig`:** `temperature`, `topP`, and `maxTokens` are **not**
> first-class fields on `ChatMiddlewareConfig`. To adjust sampling from
> middleware, return a partial that mutates `config.modelOptions` using the
> provider's native key (e.g. OpenAI `temperature` / `max_output_tokens`,
> Anthropic `max_tokens`, Ollama nested `options.num_predict`). Returning a
> top-level `temperature`/`maxTokens` has no effect.
### Phase values
`ctx.phase` is one of:
| Phase | When |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `'init'` | Initial setup (before the first `onConfig` snapshot is built). |
| `'beforeModel'` | Right before each agent-loop adaTrust audit
SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | NA |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- none-observed
- Network
- none-observed
- Shell
- none-observed
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (0)
No findings outside the package's declared scope.
Gates applied: no_behavioural_pass.
dafe8ab3bd88full audit observations/trust-audit/skill/tanstack__middleware.json · Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-08 | dafe8ab3bd88 | SAFE | B | 89 | first audit |
Questions
What does the Middleware skill do?
🤖 Type-safe, provider-agnostic TypeScript AI SDK for streaming chat, tool calling, agents, and multimodal apps across OpenAI, Anthropic, Gemini, React, Vue, Svelte, and Solid.
Is Middleware safe to install?
The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.
What can Middleware access on my machine?
The audit observed no filesystem, network or shell use at all in its source.
How current is this page?
The grade is for one exact copy of the source (dafe8ab3bd88), read on 2026-10-08. The repository is watched, and a new audit runs when it changes — this is the first audit.