Skip to content

feat(ai): add typed runtime context#628

Open
AlemTuzlak wants to merge 1 commit into
mainfrom
feat/typed-runtime-context-pr
Open

feat(ai): add typed runtime context#628
AlemTuzlak wants to merge 1 commit into
mainfrom
feat/typed-runtime-context-pr

Conversation

@AlemTuzlak
Copy link
Copy Markdown
Contributor

@AlemTuzlak AlemTuzlak commented May 22, 2026

Summary

  • Adds typed runtime context generics for chat, server/client tools, middleware, ChatClient, and framework useChat wrappers without breaking untyped middleware/tools.
  • Threads server context through chat() and client-local context through ChatClient so tool and middleware implementations can access typed runtime data.
  • Adds docs, e2e coverage for server/client/client-forwarded context, and a playable ts-react-chat runtime context route.

Test Plan

  • git diff --cached --check
  • pnpm --filter @tanstack/ai-event-client build
  • pnpm --filter @tanstack/ai test:types
  • pnpm --filter @tanstack/ai build
  • pnpm --filter @tanstack/ai-client test:types
  • pnpm --filter @tanstack/ai test:lib -- run tests/tool-context.test.ts tests/tool-calls-context.test.ts tests/tool-call-manager-context.test.ts tests/middleware-context.test.ts tests/type-check.test.ts
  • pnpm --filter @tanstack/ai-client test:lib -- run tests/chat-client-context.test.ts tests/tool-types.test.ts
  • pnpm --filter @tanstack/ai-client build
  • pnpm --filter @tanstack/ai-react test:types
  • pnpm --filter @tanstack/ai-solid test:types
  • pnpm --filter @tanstack/ai-vue test:types
  • pnpm --filter @tanstack/ai-svelte test:types
  • pnpm --filter @tanstack/ai-preact test:types
  • pnpm --filter @tanstack/ai-code-mode test:types
  • pnpm --filter @tanstack/ai-react test:lib -- run tests/use-chat-types.test.ts
  • pnpm --filter @tanstack/ai-svelte test:lib -- run tests/create-chat-types.test.ts
  • pnpm --filter @tanstack/ai-utils build
  • pnpm --filter @tanstack/openai-base build
  • Provider adapter builds required by the e2e dev server: @tanstack/ai-openai, @tanstack/ai-anthropic, @tanstack/ai-gemini, @tanstack/ai-grok, @tanstack/ai-groq, @tanstack/ai-elevenlabs, @tanstack/ai-ollama, @tanstack/ai-openrouter
  • pnpm --filter @tanstack/ai-e2e test:e2e -- tests/tools-test/runtime-context.spec.ts

Notes: Vite/svelte-check emitted the existing missing .svelte-kit/tsconfig.json warning for examples/ts-svelte-chat; the commands above exited successfully where listed.

Summary by CodeRabbit

  • New Features

    • Typed client-local runtime context support across chat APIs and UI helpers (including updateContext/update options).
    • Tools and middleware can declare and receive strongly-typed per-request context.
  • Documentation

    • New Runtime Context guide, migration notes, and API docs updated with examples and handoff patterns.
  • Examples

    • Runtime Context demo page and tooling added to example apps and route tree.
  • Tests

    • Extensive unit/type tests and E2E fixtures/specs validating context propagation.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

📝 Walkthrough

Walkthrough

Adds a generic, typed runtime context channel (TContext) across core types, tool/middleware APIs, chat engine, ChatClient, framework hooks, documentation, examples, E2E fixtures, and tests; context is request-local and not automatically serialized to the model or to the server unless explicitly forwarded/mapped.

Changes

Typed Runtime Context Implementation

Layer / File(s) Summary
Documentation and guides
docs/advanced/*, docs/api/*, docs/migration/*, docs/tools/*, docs/config.json
Adds Runtime Context guide, updates middleware docs to show ChatMiddleware<TContext> and ctx.defer(...), updates API docs to expose context option across clients/frameworks, and adds migration notes about mapping forwarded props into runtime context.
Core types
packages/typescript/ai/src/types.ts
Introduces ToolExecutionContext<TContext>, generic Tool<TContext>, AnyTool, extends TextOptions<TContext> with context?: TContext.
Tool definition builders
packages/typescript/ai/src/activities/chat/tools/tool-definition.ts
.server<TContext>() and .client<TContext>() builders added; ClientTool/ServerTool/ToolDefinitionInstance generics updated to accept TContext and thread typed context into execute signatures.
Tool calls & manager
packages/typescript/ai/src/activities/chat/tools/tool-calls.ts
ToolCallManager<TContext> and executeToolCalls<TContext> accept optional userContext and construct ToolExecutionContext<TContext> for tool invocations.
Middleware runner & types
packages/typescript/ai/src/activities/chat/middleware/*
ChatMiddlewareContext<TContext> and ChatMiddleware<TContext> generics added; MiddlewareRunner<TContext> threads typed ctx through all lifecycle hooks.
Chat activity & engine
packages/typescript/ai/src/activities/chat/index.ts
TextActivityOptions/TextEngine parameterized by TContext; createChatOptions and chat() infer TContext from tools/middleware and pass runtime context into execution pipeline.
ChatClient & client inference
packages/typescript/ai-client/src/*
ChatClient<TTools, TContext> stores instance context, new type utilities InferredClientContext, ClientContextOptionFromTools, and ChatClientOptions<TTools, TContext> added; createChatClientOptions updated.
Framework integrations
packages/typescript/ai-*/src/*
React/Preact/Vue/Solid/Svelte hooks and APIs updated to infer TContext, construct ChatClient<TTools,TContext>, and sync options.context; Svelte exposes updateContext.
Examples & E2E
examples/ts-react-chat/*, testing/e2e/*
Adds runtime-context example page, inspect tools, route registration, E2E adapters, fixtures, and Playwright tests validating client/server/forwarded-props mapping into server context.
Tests
packages/typescript/ai/tests/*, packages/typescript/ai-client/tests/*, packages/typescript/ai-react/tests/*
Unit and type-check tests verifying context inference, propagation through middleware/tool execution, ChatClient behavior, and compile-time requirement enforcement for merged/widened tool arrays.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • TanStack/ai#600: Both PRs touch the chat middleware type system and related middleware phases.

Suggested reviewers

  • crutchcorn
  • tombeckenham

"A context so typed, so fine and clean,
Tools receive what they mean,
From client to server, no cast required—
TypeScript smiles, the types conferred!" 🐰

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/typed-runtime-context-pr

@AlemTuzlak AlemTuzlak force-pushed the feat/typed-runtime-context-pr branch from 5b10d74 to fd36fac Compare May 22, 2026 16:46
@github-actions
Copy link
Copy Markdown
Contributor

🚀 Changeset Version Preview

3 package(s) bumped directly, 16 bumped as dependents.

🟩 Patch bumps

Package Version Reason
@tanstack/ai 0.21.2 → 0.21.3 Changeset
@tanstack/ai-client 0.11.6 → 0.11.7 Changeset
@tanstack/ai-event-client 0.3.9 → 0.3.10 Changeset
@tanstack/ai-code-mode 0.1.19 → 0.1.20 Dependent
@tanstack/ai-code-mode-skills 0.1.19 → 0.1.20 Dependent
@tanstack/ai-devtools-core 0.3.36 → 0.3.37 Dependent
@tanstack/ai-fal 0.7.12 → 0.7.13 Dependent
@tanstack/ai-isolate-cloudflare 0.2.10 → 0.2.11 Dependent
@tanstack/ai-isolate-node 0.1.19 → 0.1.20 Dependent
@tanstack/ai-isolate-quickjs 0.1.19 → 0.1.20 Dependent
@tanstack/ai-preact 0.6.31 → 0.6.32 Dependent
@tanstack/ai-react 0.11.6 → 0.11.7 Dependent
@tanstack/ai-solid 0.10.6 → 0.10.7 Dependent
@tanstack/ai-svelte 0.10.6 → 0.10.7 Dependent
@tanstack/ai-vue 0.10.7 → 0.10.8 Dependent
@tanstack/ai-vue-ui 0.2.2 → 0.2.3 Dependent
@tanstack/preact-ai-devtools 0.1.40 → 0.1.41 Dependent
@tanstack/react-ai-devtools 0.2.40 → 0.2.41 Dependent
@tanstack/solid-ai-devtools 0.2.40 → 0.2.41 Dependent

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/typescript/ai/src/activities/chat/middleware/types.ts (1)

384-387: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Propagate TContext into onStructuredOutputConfig (and its runner)

packages/typescript/ai/src/activities/chat/middleware/types.ts still types onStructuredOutputConfig as ctx: ChatMiddlewareContext (non-generic), and packages/typescript/ai/src/activities/chat/middleware/compose.ts still types runOnStructuredOutputConfig as ctx: ChatMiddlewareContext, dropping the TContext parameter from ChatMiddleware<TContext> for this hook.

Update both signatures to use ChatMiddlewareContext<TContext> so the hook receives the correctly typed context.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/typescript/ai/src/activities/chat/middleware/types.ts` around lines
384 - 387, Update the generic context propagation for the structured-output
hook: change the type of onStructuredOutputConfig in the
ChatMiddleware<TContext> interface to accept ctx:
ChatMiddlewareContext<TContext> (not the non-generic ChatMiddlewareContext), and
likewise update the runner function runOnStructuredOutputConfig in compose (and
any helper/runner types it uses) to accept ctx: ChatMiddlewareContext<TContext>
so the TContext parameter is preserved and the hook receives the correctly typed
context.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/ts-react-chat/src/routes/api.tanchat.ts`:
- Around line 164-166: The console.log in the onStart middleware is emitting raw
PII (ctx.context.userId and ctx.context.tenantId); change the log to avoid raw
identifiers by applying a deterministic mask or hash instead (e.g., introduce a
helper like hashIdentifier(id: string) or redactIdentifier(id: string) and call
it for ctx.context.userId and ctx.context.tenantId before logging), or drop
those fields entirely and only log non-PII such as ctx.context.loyaltyTier;
update the console.log invocation in the onStart handler to use the new helper
or redacted values.

In `@examples/ts-react-chat/src/routes/example.runtime-context.tsx`:
- Around line 198-203: The ReactMarkdown instance in example.runtime-context.tsx
incorrectly places the remark plugin remarkGfm in the rehypePlugins list; move
remarkGfm into the remarkPlugins prop so it's applied by remark instead of
rehype (locate the ReactMarkdown component where rehypePlugins is defined and
change the plugin arrays accordingly, keeping rehypeRaw, rehypeSanitize,
rehypeHighlight in rehypePlugins and adding remarkGfm to remarkPlugins).

---

Outside diff comments:
In `@packages/typescript/ai/src/activities/chat/middleware/types.ts`:
- Around line 384-387: Update the generic context propagation for the
structured-output hook: change the type of onStructuredOutputConfig in the
ChatMiddleware<TContext> interface to accept ctx:
ChatMiddlewareContext<TContext> (not the non-generic ChatMiddlewareContext), and
likewise update the runner function runOnStructuredOutputConfig in compose (and
any helper/runner types it uses) to accept ctx: ChatMiddlewareContext<TContext>
so the TContext parameter is preserved and the hook receives the correctly typed
context.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 601a7093-ba6a-4a21-874d-32f0d2abde34

📥 Commits

Reviewing files that changed from the base of the PR and between e144a53 and 5b10d74.

📒 Files selected for processing (60)
  • docs/advanced/middleware.md
  • docs/advanced/runtime-context.md
  • docs/api/ai-client.md
  • docs/api/ai-preact.md
  • docs/api/ai-react.md
  • docs/api/ai-solid.md
  • docs/api/ai-svelte.md
  • docs/api/ai-vue.md
  • docs/api/ai.md
  • docs/config.json
  • docs/migration/ag-ui-compliance.md
  • docs/migration/migration-from-vercel-ai.md
  • docs/tools/client-tools.md
  • docs/tools/server-tools.md
  • examples/ts-code-mode-web/src/lib/execute-prompt.ts
  • examples/ts-code-mode-web/src/lib/structured-output.ts
  • examples/ts-react-chat/src/components/Header.tsx
  • examples/ts-react-chat/src/lib/guitar-tools.ts
  • examples/ts-react-chat/src/routeTree.gen.ts
  • examples/ts-react-chat/src/routes/api.tanchat.ts
  • examples/ts-react-chat/src/routes/example.runtime-context.tsx
  • packages/typescript/ai-client/src/chat-client.ts
  • packages/typescript/ai-client/src/index.ts
  • packages/typescript/ai-client/src/types.ts
  • packages/typescript/ai-client/tests/chat-client-context.test.ts
  • packages/typescript/ai-client/tests/tool-types.test.ts
  • packages/typescript/ai-code-mode/src/types.ts
  • packages/typescript/ai-code-mode/tests/create-code-mode-tool.test.ts
  • packages/typescript/ai-preact/src/types.ts
  • packages/typescript/ai-preact/src/use-chat.ts
  • packages/typescript/ai-react/src/types.ts
  • packages/typescript/ai-react/src/use-chat.ts
  • packages/typescript/ai-react/tests/use-chat-types.test.ts
  • packages/typescript/ai-solid/src/types.ts
  • packages/typescript/ai-solid/src/use-chat.ts
  • packages/typescript/ai-svelte/src/create-chat.svelte.ts
  • packages/typescript/ai-svelte/src/types.ts
  • packages/typescript/ai-svelte/tests/create-chat-types.test.ts
  • packages/typescript/ai-vue/src/types.ts
  • packages/typescript/ai-vue/src/use-chat.ts
  • packages/typescript/ai/src/activities/chat/index.ts
  • packages/typescript/ai/src/activities/chat/middleware/compose.ts
  • packages/typescript/ai/src/activities/chat/middleware/types.ts
  • packages/typescript/ai/src/activities/chat/tools/tool-calls.ts
  • packages/typescript/ai/src/activities/chat/tools/tool-definition.ts
  • packages/typescript/ai/src/types.ts
  • packages/typescript/ai/src/utilities/chat-params.ts
  • packages/typescript/ai/tests/middleware-context.test.ts
  • packages/typescript/ai/tests/tool-call-manager-context.test.ts
  • packages/typescript/ai/tests/tool-calls-context.test.ts
  • packages/typescript/ai/tests/tool-context.test.ts
  • packages/typescript/ai/tests/type-check.test.ts
  • testing/e2e/fixtures/tools-test/client-context.json
  • testing/e2e/fixtures/tools-test/client-server-context.json
  • testing/e2e/fixtures/tools-test/server-context.json
  • testing/e2e/src/lib/tools-test-tools.ts
  • testing/e2e/src/routes/api.tools-test.ts
  • testing/e2e/src/routes/tools-test.tsx
  • testing/e2e/tests/tools-test/helpers.ts
  • testing/e2e/tests/tools-test/runtime-context.spec.ts

Comment on lines +164 to +166
console.log(
`[runtime-context] onStart user=${ctx.context.userId} tenant=${ctx.context.tenantId} tier=${ctx.context.loyaltyTier}`,
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid logging raw runtime identifiers in middleware logs.

userId and tenantId are written directly to server logs here. Please redact, hash, or drop these fields to reduce PII exposure risk.

🔧 Suggested change
   onStart(ctx) {
-    console.log(
-      `[runtime-context] onStart user=${ctx.context.userId} tenant=${ctx.context.tenantId} tier=${ctx.context.loyaltyTier}`,
-    )
+    console.log(
+      `[runtime-context] onStart tier=${ctx.context.loyaltyTier} source=${ctx.context.requestSource}`,
+    )
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log(
`[runtime-context] onStart user=${ctx.context.userId} tenant=${ctx.context.tenantId} tier=${ctx.context.loyaltyTier}`,
)
console.log(
`[runtime-context] onStart tier=${ctx.context.loyaltyTier} source=${ctx.context.requestSource}`,
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/ts-react-chat/src/routes/api.tanchat.ts` around lines 164 - 166, The
console.log in the onStart middleware is emitting raw PII (ctx.context.userId
and ctx.context.tenantId); change the log to avoid raw identifiers by applying a
deterministic mask or hash instead (e.g., introduce a helper like
hashIdentifier(id: string) or redactIdentifier(id: string) and call it for
ctx.context.userId and ctx.context.tenantId before logging), or drop those
fields entirely and only log non-PII such as ctx.context.loyaltyTier; update the
console.log invocation in the onStart handler to use the new helper or redacted
values.

Comment on lines +198 to +203
rehypePlugins={[
rehypeRaw,
rehypeSanitize,
rehypeHighlight,
remarkGfm,
]}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify ReactMarkdown plugin wiring in the new runtime-context route.
rg -n -C3 "ReactMarkdown|rehypePlugins|remarkPlugins|remarkGfm" examples/ts-react-chat/src/routes/example.runtime-context.tsx

Repository: TanStack/ai

Length of output: 1150


Fix ReactMarkdown plugin wiring: remarkGfm is passed via rehypePlugins
In examples/ts-react-chat/src/routes/example.runtime-context.tsx (ReactMarkdown around lines 198-203), remarkGfm (from remark-gfm) is a remark plugin but is included in rehypePlugins. Move it to remarkPlugins so GFM features work.

🔧 Suggested change
                       <ReactMarkdown
                         rehypePlugins={[
                           rehypeRaw,
                           rehypeSanitize,
                           rehypeHighlight,
-                          remarkGfm,
                         ]}
+                        remarkPlugins={[remarkGfm]}
                       >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
rehypePlugins={[
rehypeRaw,
rehypeSanitize,
rehypeHighlight,
remarkGfm,
]}
<ReactMarkdown
rehypePlugins={[
rehypeRaw,
rehypeSanitize,
rehypeHighlight,
]}
remarkPlugins={[remarkGfm]}
>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/ts-react-chat/src/routes/example.runtime-context.tsx` around lines
198 - 203, The ReactMarkdown instance in example.runtime-context.tsx incorrectly
places the remark plugin remarkGfm in the rehypePlugins list; move remarkGfm
into the remarkPlugins prop so it's applied by remark instead of rehype (locate
the ReactMarkdown component where rehypePlugins is defined and change the plugin
arrays accordingly, keeping rehypeRaw, rehypeSanitize, rehypeHighlight in
rehypePlugins and adding remarkGfm to remarkPlugins).

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented May 22, 2026

View your CI Pipeline Execution ↗ for commit fd36fac

Command Status Duration Result
nx run-many --targets=build --exclude=examples/... ✅ Succeeded 1m 7s View ↗

☁️ Nx Cloud last updated this comment at 2026-05-22 16:48:29 UTC

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 22, 2026

Open in StackBlitz

@tanstack/ai

npm i https://pkg.pr.new/@tanstack/ai@628

@tanstack/ai-anthropic

npm i https://pkg.pr.new/@tanstack/ai-anthropic@628

@tanstack/ai-client

npm i https://pkg.pr.new/@tanstack/ai-client@628

@tanstack/ai-code-mode

npm i https://pkg.pr.new/@tanstack/ai-code-mode@628

@tanstack/ai-code-mode-skills

npm i https://pkg.pr.new/@tanstack/ai-code-mode-skills@628

@tanstack/ai-devtools-core

npm i https://pkg.pr.new/@tanstack/ai-devtools-core@628

@tanstack/ai-elevenlabs

npm i https://pkg.pr.new/@tanstack/ai-elevenlabs@628

@tanstack/ai-event-client

npm i https://pkg.pr.new/@tanstack/ai-event-client@628

@tanstack/ai-fal

npm i https://pkg.pr.new/@tanstack/ai-fal@628

@tanstack/ai-gemini

npm i https://pkg.pr.new/@tanstack/ai-gemini@628

@tanstack/ai-grok

npm i https://pkg.pr.new/@tanstack/ai-grok@628

@tanstack/ai-groq

npm i https://pkg.pr.new/@tanstack/ai-groq@628

@tanstack/ai-isolate-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-isolate-cloudflare@628

@tanstack/ai-isolate-node

npm i https://pkg.pr.new/@tanstack/ai-isolate-node@628

@tanstack/ai-isolate-quickjs

npm i https://pkg.pr.new/@tanstack/ai-isolate-quickjs@628

@tanstack/ai-ollama

npm i https://pkg.pr.new/@tanstack/ai-ollama@628

@tanstack/ai-openai

npm i https://pkg.pr.new/@tanstack/ai-openai@628

@tanstack/ai-openrouter

npm i https://pkg.pr.new/@tanstack/ai-openrouter@628

@tanstack/ai-preact

npm i https://pkg.pr.new/@tanstack/ai-preact@628

@tanstack/ai-react

npm i https://pkg.pr.new/@tanstack/ai-react@628

@tanstack/ai-react-ui

npm i https://pkg.pr.new/@tanstack/ai-react-ui@628

@tanstack/ai-solid

npm i https://pkg.pr.new/@tanstack/ai-solid@628

@tanstack/ai-solid-ui

npm i https://pkg.pr.new/@tanstack/ai-solid-ui@628

@tanstack/ai-svelte

npm i https://pkg.pr.new/@tanstack/ai-svelte@628

@tanstack/ai-utils

npm i https://pkg.pr.new/@tanstack/ai-utils@628

@tanstack/ai-vue

npm i https://pkg.pr.new/@tanstack/ai-vue@628

@tanstack/ai-vue-ui

npm i https://pkg.pr.new/@tanstack/ai-vue-ui@628

@tanstack/openai-base

npm i https://pkg.pr.new/@tanstack/openai-base@628

@tanstack/preact-ai-devtools

npm i https://pkg.pr.new/@tanstack/preact-ai-devtools@628

@tanstack/react-ai-devtools

npm i https://pkg.pr.new/@tanstack/react-ai-devtools@628

@tanstack/solid-ai-devtools

npm i https://pkg.pr.new/@tanstack/solid-ai-devtools@628

commit: fd36fac

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/typescript/ai/src/activities/chat/middleware/types.ts (1)

349-387: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

onStructuredOutputConfig still drops typed runtime context

ChatMiddleware<TContext> threads TContext through other hooks, but onStructuredOutputConfig keeps ctx: ChatMiddlewareContext (unknown context), so typed context is lost exactly in this phase.

Proposed fix
   onStructuredOutputConfig?: (
-    ctx: ChatMiddlewareContext,
+    ctx: ChatMiddlewareContext<TContext>,
     config: StructuredOutputMiddlewareConfig,
   ) =>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/typescript/ai/src/activities/chat/middleware/types.ts` around lines
349 - 387, The onStructuredOutputConfig hook currently types its context as
ChatMiddlewareContext (losing the generic TContext); update the signature on
ChatMiddleware<TContext> so onStructuredOutputConfig receives ctx:
ChatMiddlewareContext<TContext> (and keep the existing
StructuredOutputMiddlewareConfig type for the second parameter) so the generic
runtime context is preserved through this hook; locate the ChatMiddleware
interface and change the onStructuredOutputConfig parameter type accordingly
(referencing ChatMiddleware, onStructuredOutputConfig, ChatMiddlewareContext,
and StructuredOutputMiddlewareConfig).
🧹 Nitpick comments (1)
packages/typescript/ai/tests/middleware-context.test.ts (1)

47-47: ⚡ Quick win

Assert reference identity instead of deep equality.

Line 47 currently checks structural equality, so it won’t fail if middleware/tool receive cloned context objects. If the contract is “same runtime context instance,” assert identity with toBe.

Proposed change
-    expect(seen).toEqual([context, context])
+    expect(seen).toHaveLength(2)
+    expect(seen[0]).toBe(context)
+    expect(seen[1]).toBe(context)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/typescript/ai/tests/middleware-context.test.ts` at line 47, The test
currently uses structural equality (expect(seen).toEqual([context, context]))
which allows cloned objects to pass; change it to assert reference identity by
replacing that assertion with identity checks such as
expect(seen[0]).toBe(context) and expect(seen[1]).toBe(context) so both captured
entries are the exact same runtime context instance.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@testing/e2e/tests/tools-test/helpers.ts`:
- Around line 94-107: The current page.evaluate in helpers.ts treats any
non-empty `#messages-json-content` as a started run and causes false positives
when fixtures are preloaded; update the check to compare the current messages
array length against the prior message count captured before clicking so we only
return true when a new run actually produced additional messages. Concretely: in
runTest() capture the preClickCount by parsing
document.getElementById('messages-json-content')?.textContent (default []), then
call page.evaluate with that preClickCount and inside the evaluated function
parse the messages once, return true if metadata.getAttribute('data-is-loading')
=== 'true' OR (Array.isArray(messages) && messages.length > preClickCount);
reference page.evaluate, '`#messages-json-content`', and the runTest() caller to
locate and implement this change.

---

Outside diff comments:
In `@packages/typescript/ai/src/activities/chat/middleware/types.ts`:
- Around line 349-387: The onStructuredOutputConfig hook currently types its
context as ChatMiddlewareContext (losing the generic TContext); update the
signature on ChatMiddleware<TContext> so onStructuredOutputConfig receives ctx:
ChatMiddlewareContext<TContext> (and keep the existing
StructuredOutputMiddlewareConfig type for the second parameter) so the generic
runtime context is preserved through this hook; locate the ChatMiddleware
interface and change the onStructuredOutputConfig parameter type accordingly
(referencing ChatMiddleware, onStructuredOutputConfig, ChatMiddlewareContext,
and StructuredOutputMiddlewareConfig).

---

Nitpick comments:
In `@packages/typescript/ai/tests/middleware-context.test.ts`:
- Line 47: The test currently uses structural equality
(expect(seen).toEqual([context, context])) which allows cloned objects to pass;
change it to assert reference identity by replacing that assertion with identity
checks such as expect(seen[0]).toBe(context) and expect(seen[1]).toBe(context)
so both captured entries are the exact same runtime context instance.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6bb95160-469b-4912-9470-f4089a8b533b

📥 Commits

Reviewing files that changed from the base of the PR and between 5b10d74 and fd36fac.

📒 Files selected for processing (60)
  • docs/advanced/middleware.md
  • docs/advanced/runtime-context.md
  • docs/api/ai-client.md
  • docs/api/ai-preact.md
  • docs/api/ai-react.md
  • docs/api/ai-solid.md
  • docs/api/ai-svelte.md
  • docs/api/ai-vue.md
  • docs/api/ai.md
  • docs/config.json
  • docs/migration/ag-ui-compliance.md
  • docs/migration/migration-from-vercel-ai.md
  • docs/tools/client-tools.md
  • docs/tools/server-tools.md
  • examples/ts-code-mode-web/src/lib/execute-prompt.ts
  • examples/ts-code-mode-web/src/lib/structured-output.ts
  • examples/ts-react-chat/src/components/Header.tsx
  • examples/ts-react-chat/src/lib/guitar-tools.ts
  • examples/ts-react-chat/src/routeTree.gen.ts
  • examples/ts-react-chat/src/routes/api.tanchat.ts
  • examples/ts-react-chat/src/routes/example.runtime-context.tsx
  • packages/typescript/ai-client/src/chat-client.ts
  • packages/typescript/ai-client/src/index.ts
  • packages/typescript/ai-client/src/types.ts
  • packages/typescript/ai-client/tests/chat-client-context.test.ts
  • packages/typescript/ai-client/tests/tool-types.test.ts
  • packages/typescript/ai-code-mode/src/types.ts
  • packages/typescript/ai-code-mode/tests/create-code-mode-tool.test.ts
  • packages/typescript/ai-preact/src/types.ts
  • packages/typescript/ai-preact/src/use-chat.ts
  • packages/typescript/ai-react/src/types.ts
  • packages/typescript/ai-react/src/use-chat.ts
  • packages/typescript/ai-react/tests/use-chat-types.test.ts
  • packages/typescript/ai-solid/src/types.ts
  • packages/typescript/ai-solid/src/use-chat.ts
  • packages/typescript/ai-svelte/src/create-chat.svelte.ts
  • packages/typescript/ai-svelte/src/types.ts
  • packages/typescript/ai-svelte/tests/create-chat-types.test.ts
  • packages/typescript/ai-vue/src/types.ts
  • packages/typescript/ai-vue/src/use-chat.ts
  • packages/typescript/ai/src/activities/chat/index.ts
  • packages/typescript/ai/src/activities/chat/middleware/compose.ts
  • packages/typescript/ai/src/activities/chat/middleware/types.ts
  • packages/typescript/ai/src/activities/chat/tools/tool-calls.ts
  • packages/typescript/ai/src/activities/chat/tools/tool-definition.ts
  • packages/typescript/ai/src/types.ts
  • packages/typescript/ai/src/utilities/chat-params.ts
  • packages/typescript/ai/tests/middleware-context.test.ts
  • packages/typescript/ai/tests/tool-call-manager-context.test.ts
  • packages/typescript/ai/tests/tool-calls-context.test.ts
  • packages/typescript/ai/tests/tool-context.test.ts
  • packages/typescript/ai/tests/type-check.test.ts
  • testing/e2e/fixtures/tools-test/client-context.json
  • testing/e2e/fixtures/tools-test/client-server-context.json
  • testing/e2e/fixtures/tools-test/server-context.json
  • testing/e2e/src/lib/tools-test-tools.ts
  • testing/e2e/src/routes/api.tools-test.ts
  • testing/e2e/src/routes/tools-test.tsx
  • testing/e2e/tests/tools-test/helpers.ts
  • testing/e2e/tests/tools-test/runtime-context.spec.ts
✅ Files skipped from review due to trivial changes (14)
  • testing/e2e/fixtures/tools-test/client-server-context.json
  • docs/tools/server-tools.md
  • testing/e2e/tests/tools-test/runtime-context.spec.ts
  • docs/migration/ag-ui-compliance.md
  • packages/typescript/ai-code-mode/tests/create-code-mode-tool.test.ts
  • docs/api/ai-vue.md
  • docs/api/ai-react.md
  • docs/api/ai-solid.md
  • examples/ts-code-mode-web/src/lib/structured-output.ts
  • docs/migration/migration-from-vercel-ai.md
  • docs/advanced/middleware.md
  • docs/api/ai-preact.md
  • docs/tools/client-tools.md
  • examples/ts-react-chat/src/routeTree.gen.ts

Comment on lines +94 to +107
const started = await page.evaluate(() => {
const metadata = document.getElementById('test-metadata')
if (metadata?.getAttribute('data-is-loading') === 'true') {
return true
}

const text =
document.getElementById('messages-json-content')?.textContent || '[]'
try {
return Array.isArray(JSON.parse(text)) && JSON.parse(text).length > 0
} catch {
return false
}
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Prevent false-positive test start detection with preloaded history.

Line 103 treats any non-empty #messages-json-content as “started”. With preloaded fixtures, messages can already be non-empty before clicking, so runTest() can return before a new run actually begins.

Suggested fix
 export async function runTest(page: Page): Promise<void> {
+  const initialMessageCount = await page.evaluate(() => {
+    const text =
+      document.getElementById('messages-json-content')?.textContent || '[]'
+    try {
+      const parsed = JSON.parse(text)
+      return Array.isArray(parsed) ? parsed.length : 0
+    } catch {
+      return 0
+    }
+  })
+
   for (let attempt = 0; attempt < 5; attempt++) {
     await page.click('`#run-test-button`')
     await page.waitForTimeout(300)
 
-    const started = await page.evaluate(() => {
+    const started = await page.evaluate((baselineCount: number) => {
       const metadata = document.getElementById('test-metadata')
       if (metadata?.getAttribute('data-is-loading') === 'true') {
         return true
       }
 
       const text =
         document.getElementById('messages-json-content')?.textContent || '[]'
       try {
-        return Array.isArray(JSON.parse(text)) && JSON.parse(text).length > 0
+        const parsed = JSON.parse(text)
+        return Array.isArray(parsed) && parsed.length > baselineCount
       } catch {
         return false
       }
-    })
+    }, initialMessageCount)
 
     if (started) {
       return
     }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@testing/e2e/tests/tools-test/helpers.ts` around lines 94 - 107, The current
page.evaluate in helpers.ts treats any non-empty `#messages-json-content` as a
started run and causes false positives when fixtures are preloaded; update the
check to compare the current messages array length against the prior message
count captured before clicking so we only return true when a new run actually
produced additional messages. Concretely: in runTest() capture the preClickCount
by parsing document.getElementById('messages-json-content')?.textContent
(default []), then call page.evaluate with that preClickCount and inside the
evaluated function parse the messages once, return true if
metadata.getAttribute('data-is-loading') === 'true' OR (Array.isArray(messages)
&& messages.length > preClickCount); reference page.evaluate,
'`#messages-json-content`', and the runTest() caller to locate and implement this
change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant