Skip to content

Conversation

@shakibdshy
Copy link

@shakibdshy shakibdshy commented Jan 15, 2026

This PR introduces a new community adapter for Z.AI (Zhipu AI), enabling seamless integration with GLM-4 models in the TanStack AI ecosystem. It also updates all example chat applications to demonstrate and verify the new adapter.

Changes:

1. New Package: @tanstack/ai-zai

  • Created a fully type-safe adapter following the Community Adapters Guide.
  • Supported Models:
    • glm-4.7 (Flagship, high reasoning)
    • glm-4.6 (Balanced)
    • glm-4.6v (Multimodal vision)
  • Features Implemented:
    • Streaming Chat Completions (OpenAI-compatible)
    • Tool Calling & Parallel Tool Execution
    • Web Search Tool Support (Native Z.AI capability)
    • Thinking Mode (Deep reasoning for supported models)
    • Type-safe options for reasoning, tools, and streaming.
  • Testing:
    • Added unit tests (zai-factory.test.ts, model-meta.test.ts)
    • Added comprehensive integration tests (zai-adapter.integration.test.ts) covering streaming, multi-turn chat, tool calling, and error handling.

2. Example Projects Updated

All example chat applications have been updated to support the zai provider and model selection:

  • examples/ts-react-chat:

    • Added zai provider to model-selection.ts.
    • Updated API route to handle Z.AI adapter initialization.
    • Added @tanstack/ai-zai dependency.
  • examples/ts-vue-chat:

    • Added zai provider support in vite.config.ts (API handler).
    • Updated UI model selector.
  • examples/ts-svelte-chat:

    • Updated +server.ts to include zaiText adapter configuration.
    • Added environment variable support for ZAI_API_KEY.
  • examples/ts-solid-chat:

    • Updated api.chat.ts to dynamically switch between Anthropic and Z.AI providers.
  • examples/ts-group-chat:

    • Updated claude-service.ts to fallback to Z.AI if ZAI_API_KEY is present.

3. Infrastructure & Config

  • testing/panel: Updated the testing panel to support Z.AI specific features (Thinking mode toggle, Web Search toggle).
  • Dependencies: Ensured all package.json files are correctly linked to the workspace version of @tanstack/ai-zai.
  • Linting & Types: Fixed all linting issues (ordered dependencies, unused imports) and type errors across the workspace.

Verification:

  • Builds: All packages and examples build successfully (pnpm build).
  • Tests: pnpm run test:pr passes (Sherif, Knip, ESLint, Types, Lib tests).
  • Integration: Confirmed zai-adapter.integration.test.ts passes with valid API key.
  • Examples: Manually verified that all example apps can select and chat with Z.AI models.

Checklist:

  • The new adapter follows the standard directory structure and naming conventions.
  • Model metadata and capabilities are correctly defined in model-meta.ts.
  • Public API is exported via index.ts.
  • Documentation (README) is included in the package.

Summary by CodeRabbit

  • New Features
    • Added Z.AI provider with GLM-4.7, GLM-4.6, and GLM-4.6v models across chat examples and apps; selectable in model menus.
  • Documentation
    • New package README and changelog documenting Z.AI usage, features, and examples.
  • Tests
    • Integration and unit tests added for the Z.AI adapters and factories.
  • Chores
    • Example projects updated to include the Z.AI package and defaults adjusted in the testing panel.

✏️ Tip: You can customize this high-level summary in your review settings.

Add new @tanstack/ai-zai package with Z.AI adapter implementation. Includes:
- Text adapter for GLM-4.7, GLM-4.6V and GLM-4.6 models
- Streaming chat completions with content and tool call chunks
- Error handling and type safety
- Integration with existing TanStack AI ecosystem
- Tests and documentation
- Replace unsafe type assertions with proper type guards and checks
- Simplify error handling logic in mapZAIErrorToStreamChunk
- Update README with clearer OpenAI compatibility details
- Add proper type constraints for ZAITextAdapter model types
- Clean up request header and signal handling
…ion tools

Implement tool support for Z.AI with web search and function tools, including tool conversion utilities and type definitions. Add subpath export for tools in package.json and update documentation with new features.

Add summarization adapter with streaming support and update README with examples for web search, thinking mode, and tool streaming features. Move API key utility to shared client utils.
- Add zai provider to model selection in vue and svelte examples
- Include zai-text in chat server implementations
- Update package.json dependencies for zai integration
- Remove unused ZAITextOptionsMinimal interface
- Add tools entry point in ai-zai vite config
@shakibdshy shakibdshy requested a review from a team January 15, 2026 13:51
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

Adds a new @tanstack/ai-zai package (Z.AI GLM adapters, tools, types, tests, and docs) and wires zaiText provider support into multiple example apps and the testing panel, including package.json dependency updates and model-selection entries.

Changes

Cohort / File(s) Summary
Z.AI Core Adapters & Entry
packages/typescript/ai-zai/src/adapters/index.ts, packages/typescript/ai-zai/src/adapters/text.ts, packages/typescript/ai-zai/src/adapters/summarize.ts, packages/typescript/ai-zai/src/index.ts
New ZAITextAdapter and ZAISummarizeAdapter implementations, factory helpers (createZAIChat, zaiText, createZAISummarize, zaiSummarize) and consolidated package exports.
Model Metadata & Types
packages/typescript/ai-zai/src/model-meta.ts, packages/typescript/ai-zai/src/message-types.ts, packages/typescript/ai-zai/src/text/text-provider-options.ts
Adds GLM model registry (glm-4.7, glm-4.6, glm-4.6v), modality/message metadata types, and comprehensive Z.AI text provider option interfaces.
Tools & Tooling Utilities
packages/typescript/ai-zai/src/tools/*, packages/typescript/ai-zai/src/tools/index.ts, packages/typescript/ai-zai/src/tools/tool-converter.ts, packages/typescript/ai-zai/src/tools/web-search-tool.ts, packages/typescript/ai-zai/src/tools/function-tool.ts, packages/typescript/ai-zai/src/tools/tool-choice.ts
New tool conversion/choice utilities, web-search tool adapter, function-tool normalization, and tools index re-exports.
Client & Conversion Utilities
packages/typescript/ai-zai/src/utils/client.ts, packages/typescript/ai-zai/src/utils/conversion.ts
Z.AI client creation, API key validation, default headers, error→StreamChunk mapping, and tool conversion helpers.
Package Metadata & Build Config
packages/typescript/ai-zai/package.json, packages/typescript/ai-zai/tsconfig.json, packages/typescript/ai-zai/vite.config.ts
New package manifest, exports map (root and ./tools), tsconfig, and vite config for tests/build.
Docs & Changelog
packages/typescript/ai-zai/README.md, packages/typescript/ai-zai/CHANGELOG.md
Comprehensive README and changelog added for the new package.
Tests
packages/typescript/ai-zai/tests/*
Unit and integration tests for adapter behavior, factories, streaming, tool-calling, model metadata.
Examples — Provider & Models
examples/*/src/lib/model-selection.ts, testing/panel/src/lib/model-selection.ts
Add 'zai' to Provider unions and add GLM model options (glm-4.7, glm-4.6, glm-4.6v) across example model-selection lists.
Examples — API Routes / Adapters
examples/ts-react-chat/src/routes/api.tanchat.ts, examples/ts-solid-chat/src/routes/api.chat.ts, examples/ts-svelte-chat/src/routes/api/chat/+server.ts, testing/panel/src/routes/api.chat.ts, examples/ts-group-chat/chat-server/claude-service.ts, examples/ts-vue-chat/vite.config.ts
Import zaiText, add zai provider branches and wiring in adapter selection/config; update prompts/config where applicable.
Examples — Dependencies
examples/ts-group-chat/package.json, examples/ts-react-chat/package.json, examples/ts-solid-chat/package.json, examples/ts-svelte-chat/package.json, examples/ts-vue-chat/package.json, testing/panel/package.json
Add workspace dependency @tanstack/ai-zai to multiple example and testing panel package.json files.
Testing Panel Env
testing/panel/.env.example
Add commented Z.AI API key placeholder entries alongside other provider keys.

Sequence Diagram(s)

sequenceDiagram
    participant User as App / Client
    participant Adapter as ZAITextAdapter
    participant ClientAPI as OpenAI Client (Z.AI endpoint)
    participant Parser as Stream Processor

    User->>Adapter: call chatStream(options)
    Adapter->>Adapter: map options → ZAI request
    Adapter->>ClientAPI: POST /chat/completions (stream=true)
    ClientAPI-->>Adapter: stream of completion chunks
    Adapter->>Parser: process chunks (accumulate deltas, detect tool_calls)
    Parser-->>Adapter: emit StreamChunk events (content, tool_call, done/error)
    Adapter-->>User: yield StreamChunk stream
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Possibly related PRs

Suggested reviewers

  • jherr
  • AlemTuzlak

Poem

🐰 A shiny new adapter hops on by,
Streams and tools beneath Z.AI sky.
Models and types in tidy rows,
Examples learn the way it goes.
Hooray — the rabbit cheers, "let's try!"

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding a new Z.AI adapter package and updating examples to support it.
Description check ✅ Passed The description is comprehensive and well-structured, covering the new adapter features, example updates, testing, and verification with explicit checklist items completed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
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: 7

Caution

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

⚠️ Outside diff range comments (1)
examples/ts-svelte-chat/src/routes/api/chat/+server.ts (1)

27-29: Missing ZAI_API_KEY environment variable setup.

Other adapters have their API keys populated from SvelteKit's environment variables (lines 27-29), but Z.AI is missing. The adapter will fail at runtime if process.env.ZAI_API_KEY isn't set externally.

Proposed fix
 if (env.OPENAI_API_KEY) process.env.OPENAI_API_KEY = env.OPENAI_API_KEY
 if (env.ANTHROPIC_API_KEY) process.env.ANTHROPIC_API_KEY = env.ANTHROPIC_API_KEY
 if (env.GEMINI_API_KEY) process.env.GEMINI_API_KEY = env.GEMINI_API_KEY
+if (env.ZAI_API_KEY) process.env.ZAI_API_KEY = env.ZAI_API_KEY

Also applies to: 50-53

🤖 Fix all issues with AI agents
In `@examples/ts-react-chat/src/lib/model-selection.ts`:
- Around line 94-98: Fix the label typo in the model entry where provider: 'zai'
and model: 'glm-4.6' by changing label from 'Z.A.I - GLM-4.6' to 'Z.AI -
GLM-4.6' so it matches the other Z.AI entries; update the label property in that
object within model-selection.ts.

In `@examples/ts-svelte-chat/src/lib/model-selection.ts`:
- Line 1: The Provider union includes 'zai' but MODEL_OPTIONS does not; add Z.AI
model option objects to the MODEL_OPTIONS array (same shape as other entries:
label, value, provider) so the 'zai' provider appears in the UI selector. Insert
the new Z.AI entries alongside the existing providers (e.g., after the Ollama
section) and ensure each entry sets provider: 'zai' and uses unique value
strings matching the Z.AI model identifiers used elsewhere.

In `@packages/typescript/ai-zai/src/adapters/text.ts`:
- Around line 187-198: The loop handling messages where message.role === 'tool'
currently sets tool_call_id to an empty string when message.toolCallId is
missing, which can cause API errors; update the handling in the messages
iteration (the branch that builds objects with role: 'tool' and tool_call_id) to
validate message.toolCallId and either throw an explicit error or log a warning
and skip the message instead of using an empty string, ensuring the constructed
tool result always includes a valid tool_call_id.

In `@packages/typescript/ai-zai/src/text/text-provider-options.ts`:
- Around line 93-96: The JSDoc for the effort property is out of sync with the
ReasoningEffort type: update the comment on the effort?: ReasoningEffort
declaration to list the actual allowed values (including 'minimal') or remove
'minimal' from the ReasoningEffort type so both match; locate the
ReasoningEffort type definition and the effort property in
text-provider-options.ts and make the two consistent.

In `@packages/typescript/ai-zai/tests/zai-adapter.test.ts`:
- Around line 231-252: The adapter currently drops image parts unconditionally;
update ZAITextAdapter.convertMessagesToInput to check the target model's
capabilities (use the model-meta.ts lookup for model id 'glm-4.6v' or the
adapter's modelId) and only strip image/video parts for text-only models; when
the model's meta contentTypes includes 'image' or 'video', preserve and pass
through those parts in the converted message payload (and add a test case for
'glm-4.6v' that asserts image parts are kept).

In `@testing/panel/.env.example`:
- Line 22: The file ending with the line "# OLLAMA_HOST=http://localhost:11434"
is missing a trailing newline; open the testing/panel/.env.example file and add
a single blank line (a newline character) at EOF so the file ends with an empty
line.
- Around line 5-7: Update the example comment for Z.AI API key to point users
directly to the API key management page: replace the URL comment line
referencing "https://docs.z.ai/" with "https://z.ai/manage-apikey/apikey-list"
(or optionally "https://docs.z.ai/api-reference/" if you prefer linking to
docs); leave the ZAI_API_KEY variable name intact so the example env key remains
unchanged.
🧹 Nitpick comments (13)
packages/typescript/ai-zai/src/text/text-provider-options.ts (1)

168-184: Consider naming consistency for acceptLanguage.

This property uses camelCase while other properties throughout the file use snake_case (e.g., previous_response_id, parallel_tool_calls, tool_choice). If this is intentional because acceptLanguage is a client-side header config rather than an API body parameter, consider adding a brief comment to clarify.

💡 Suggested clarification
   /**
    * Accept-Language header for Z.AI API.
+   * (Client-side configuration, not sent in request body)
    * `@default` 'en-US,en'
    */
   acceptLanguage?: string

Alternatively, rename for consistency:

-  acceptLanguage?: string
+  accept_language?: string
packages/typescript/ai-zai/README.md (1)

17-17: Minor grammar fix: hyphenate compound modifier.

Per static analysis, "AI specific" should be hyphenated when used as a compound modifier.

📝 Suggested fix
-- Supports Zhipu AI specific features like **Web Search**, **Thinking Mode**, and **Tool Streaming**
+- Supports Zhipu AI-specific features like **Web Search**, **Thinking Mode**, and **Tool Streaming**
packages/typescript/ai-zai/src/tools/function-tool.ts (1)

24-31: Note on the as any cast.

The cast on line 29 is necessary due to OpenAI SDK's strict FunctionParameters type. This is acceptable for an adapter conversion layer. If stricter type safety is desired in the future, consider creating a dedicated type that matches OpenAI's expectations exactly.

packages/typescript/ai-zai/src/message-types.ts (1)

36-52: Consider the empty interface lint warnings.

The static analyzer flags ZAIVideoMetadata, ZAIDocumentMetadata, and ZAITextMetadata as empty interfaces equivalent to {}. While this is technically true, these interfaces serve as explicit type placeholders in ZAIMessageMetadataByModality and allow future extension via declaration merging.

If declaration merging isn't needed, you could use type aliases instead:

♻️ Optional: Convert to type aliases
-/**
- * Metadata for Z.AI video content parts.
- * Note: Video support in Z.AI may vary; check current API capabilities.
- */
-export interface ZAIVideoMetadata {}
+/**
+ * Metadata for Z.AI video content parts.
+ * Note: Video support in Z.AI may vary; check current API capabilities.
+ */
+export type ZAIVideoMetadata = Record<string, never>

-/**
- * Metadata for Z.AI document content parts.
- * Note: Direct document support may vary; PDFs often need to be converted to images.
- */
-export interface ZAIDocumentMetadata {}
+/**
+ * Metadata for Z.AI document content parts.
+ * Note: Direct document support may vary; PDFs often need to be converted to images.
+ */
+export type ZAIDocumentMetadata = Record<string, never>

-/**
- * Metadata for Z.AI text content parts.
- * Currently no specific metadata options for text in Z.AI.
- */
-export interface ZAITextMetadata {}
+/**
+ * Metadata for Z.AI text content parts.
+ * Currently no specific metadata options for text in Z.AI.
+ */
+export type ZAITextMetadata = Record<string, never>

If you intend to support declaration merging for future extensibility, keeping interfaces is valid—just suppress the lint rule for these lines.

packages/typescript/ai-zai/tests/model-meta.test.ts (1)

11-22: Consider strengthening the type coverage test.

The current test validates that specific model names are valid Keys, but the assertions on lines 17 and 21 don't add meaningful runtime verification—they're effectively testing constants.

A more robust approach would be to verify completeness by checking that the number of type-safe keys matches the runtime model count:

Optional enhancement
   it('ZAIModelMap includes all supported models', () => {
     type Keys = keyof ZAIModelMap
     const a: Keys = 'glm-4.7'
     const b: Keys = 'glm-4.6v'
     const c: Keys = 'glm-4.6'
 
-    expect([a, b, c].length).toBe(3)
+    // Verify all models are accounted for
+    const typeSafeModels: Keys[] = [a, b, c]
+    expect(typeSafeModels.length).toBe(ZAI_CHAT_MODELS.length)
 
     // `@ts-expect-error` invalid model name is not part of Keys
     const _invalid: Keys = 'not-a-real-model'
-    expect(_invalid).toBe('not-a-real-model')
+    // ts-expect-error above is the actual test; runtime assertion is optional
+    void _invalid
   })
examples/ts-svelte-chat/src/routes/api/chat/+server.ts (1)

106-106: Consider a more targeted type assertion.

The as any cast discards all type information. While dynamic provider selection makes full type safety challenging, a union type or generic approach would preserve some safety.

Alternative approach
-    const options = adapterConfig[provider]() as any
+    const options = adapterConfig[provider]()

If the type errors persist, consider typing adapterConfig with a return type union or using ReturnType<typeof adapterConfig[Provider]>.

packages/typescript/ai-zai/tests/zai-adapter.integration.test.ts (1)

324-380: Consider reducing as any casts for type safety.

Multiple tests use as any casts (lines 290, 353). While acceptable for integration tests, consider:

  1. Extending the adapter's type definitions to support abortController in options
  2. Using type guards instead of casts where possible

This is optional cleanup that could improve maintainability.

examples/ts-solid-chat/src/routes/api.chat.ts (1)

52-74: Consider adding ZAI_API_KEY validation for consistent error messaging.

The Anthropic branch validates the API key and returns a user-friendly error (lines 55-66), but the Z.AI branch relies on the adapter to throw. While functional, this creates inconsistent error experiences.

♻️ Optional: Add similar API key check for zai
          if (provider === 'zai') {
+           if (!process.env.ZAI_API_KEY) {
+             return new Response(
+               JSON.stringify({
+                 error:
+                   'ZAI_API_KEY not configured. Please add it to .env or .env.local',
+               }),
+               {
+                 status: 500,
+                 headers: { 'Content-Type': 'application/json' },
+               },
+             )
+           }
            adapter = zaiText(model)
          } else {
packages/typescript/ai-zai/src/tools/web-search-tool.ts (2)

3-12: Type alias WebSearchTool appears redundant.

The type alias WebSearchTool = ZaiWebSearchTool on line 12 adds no semantic value. Consider removing it to reduce API surface, or if it's intended as a public-facing alias with different semantics, add a clarifying comment.


17-25: Unsafe type cast on tool.metadata without validation.

The cast tool.metadata as ZaiWebSearchTool['web_search'] on line 20 assumes the metadata conforms to the expected shape. If a generic Tool with different metadata is passed, this produces an invalid ZaiWebSearchTool silently.

Consider adding a type guard or runtime check:

♻️ Suggested improvement
+function isWebSearchMetadata(
+  metadata: unknown,
+): metadata is ZaiWebSearchTool['web_search'] {
+  if (metadata === undefined) return true
+  if (typeof metadata !== 'object' || metadata === null) return false
+  const m = metadata as Record<string, unknown>
+  return (
+    (m.enable === undefined || typeof m.enable === 'boolean') &&
+    (m.search_query === undefined || typeof m.search_query === 'string') &&
+    (m.search_result === undefined || typeof m.search_result === 'boolean')
+  )
+}
+
 export function convertWebSearchToolToAdapterFormat(
   tool: Tool,
 ): ZaiWebSearchTool {
-  const metadata = tool.metadata as ZaiWebSearchTool['web_search']
+  const metadata = isWebSearchMetadata(tool.metadata) ? tool.metadata : undefined
   return {
     type: 'web_search',
     web_search: metadata,
   }
 }
packages/typescript/ai-zai/src/model-meta.ts (1)

199-218: Consider DRY improvement for repeated provider options type.

The same intersection type (ZAIBaseOptions & ZAIReasoningOptions & ...) is repeated for all three models in ZAIModelMap. If all models share identical provider options, consider extracting a type alias:

♻️ Suggested simplification
+type ZAICommonProviderOptions = ZAIBaseOptions &
+  ZAIReasoningOptions &
+  ZAIStructuredOutputOptions &
+  ZAIToolsOptions &
+  ZAIStreamingOptions &
+  ZAIMetadataOptions
+
 export type ZAIModelMap = {
-  [GLM_4_7.name]: ZAIBaseOptions &
-    ZAIReasoningOptions &
-    ZAIStructuredOutputOptions &
-    ZAIToolsOptions &
-    ZAIStreamingOptions &
-    ZAIMetadataOptions
-  [GLM_4_6V.name]: ZAIBaseOptions &
-    ZAIReasoningOptions &
-    ZAIStructuredOutputOptions &
-    ZAIToolsOptions &
-    ZAIStreamingOptions &
-    ZAIMetadataOptions
-  [GLM_4_6.name]: ZAIBaseOptions &
-    ZAIReasoningOptions &
-    ZAIStructuredOutputOptions &
-    ZAIToolsOptions &
-    ZAIStreamingOptions &
-    ZAIMetadataOptions
+  [GLM_4_7.name]: ZAICommonProviderOptions
+  [GLM_4_6V.name]: ZAICommonProviderOptions
+  [GLM_4_6.name]: ZAICommonProviderOptions
 }

This also future-proofs the code: if model-specific options diverge later, you can selectively override individual entries.

packages/typescript/ai-zai/src/adapters/text.ts (2)

111-117: Consider avoiding double type casting.

The as any followed by property assignment and then as StreamChunk is fragile. If mapZAIErrorToStreamChunk already returns a properly typed error chunk, consider having it accept the additional metadata as parameters.

♻️ Suggested approach
     } catch (error: unknown) {
-      const chunk = mapZAIErrorToStreamChunk(error) as any
-      chunk.id = fallbackId
-      chunk.model = options.model
-      chunk.timestamp = timestamp
-      yield chunk as StreamChunk
+      yield {
+        ...mapZAIErrorToStreamChunk(error),
+        id: fallbackId,
+        model: options.model,
+        timestamp,
+      } as StreamChunk
     }

304-342: Other finish reasons are mapped to 'stop'.

The logic maps finish_reason to either 'tool_calls' or 'stop', but the API may return other values like 'length' (max tokens reached) or 'content_filter'. Consider preserving the original finish reason when it's not a tool call scenario.

♻️ Preserve original finish reason
         if (choice.finish_reason) {
           const isToolTurn =
             choice.finish_reason === 'tool_calls' || toolCallsInProgress.size > 0

           if (isToolTurn) {
             for (const [index, toolCall] of toolCallsInProgress) {
               yield {
                 type: 'tool_call',
                 id: responseId,
                 model: responseModel,
                 timestamp,
                 index,
                 toolCall: {
                   id: toolCall.id,
                   type: 'function',
                   function: {
                     name: toolCall.name,
                     arguments: toolCall.arguments,
                   },
                 },
               }
             }
           }

           yield {
             type: 'done',
             id: responseId,
             model: responseModel,
             timestamp,
-            finishReason: isToolTurn ? 'tool_calls' : 'stop',
+            finishReason: isToolTurn ? 'tool_calls' : (choice.finish_reason || 'stop'),
             usage: chunk.usage
               ? {
                   promptTokens: chunk.usage.prompt_tokens || 0,
                   completionTokens: chunk.usage.completion_tokens || 0,
                   totalTokens: chunk.usage.total_tokens || 0,
                 }
               : undefined,
           }
         }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e93ce2 and 54bf059.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (40)
  • examples/ts-group-chat/chat-server/claude-service.ts
  • examples/ts-group-chat/package.json
  • examples/ts-react-chat/package.json
  • examples/ts-react-chat/src/lib/model-selection.ts
  • examples/ts-react-chat/src/routes/api.tanchat.ts
  • examples/ts-solid-chat/package.json
  • examples/ts-solid-chat/src/routes/api.chat.ts
  • examples/ts-svelte-chat/package.json
  • examples/ts-svelte-chat/src/lib/model-selection.ts
  • examples/ts-svelte-chat/src/routes/api/chat/+server.ts
  • examples/ts-vue-chat/package.json
  • examples/ts-vue-chat/src/lib/model-selection.ts
  • examples/ts-vue-chat/vite.config.ts
  • packages/typescript/ai-zai/CHANGELOG.md
  • packages/typescript/ai-zai/README.md
  • packages/typescript/ai-zai/package.json
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/src/adapters/summarize.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/src/index.ts
  • packages/typescript/ai-zai/src/message-types.ts
  • packages/typescript/ai-zai/src/model-meta.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
  • packages/typescript/ai-zai/src/tools/index.ts
  • packages/typescript/ai-zai/src/tools/tool-choice.ts
  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • packages/typescript/ai-zai/src/tools/web-search-tool.ts
  • packages/typescript/ai-zai/src/utils/client.ts
  • packages/typescript/ai-zai/src/utils/conversion.ts
  • packages/typescript/ai-zai/tests/model-meta.test.ts
  • packages/typescript/ai-zai/tests/zai-adapter.integration.test.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
  • packages/typescript/ai-zai/tests/zai-factory.test.ts
  • packages/typescript/ai-zai/tsconfig.json
  • packages/typescript/ai-zai/vite.config.ts
  • testing/panel/.env.example
  • testing/panel/package.json
  • testing/panel/src/lib/model-selection.ts
  • testing/panel/src/routes/api.chat.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use tree-shakeable adapter architecture for provider implementations - export specialized adapters (text, embedding, summarize, image) as separate imports from /adapters subpath rather than monolithic adapters
Use Zod for runtime schema validation and type inference, particularly for tool input/output definitions with toolDefinition() and Zod schema inference
Implement isomorphic tool system using toolDefinition() with .server() and .client() implementations for dual-environment execution
Use type-safe per-model configuration with provider options typed based on selected model to ensure compile-time safety
Implement stream processing with StreamProcessor for handling chunked responses and support partial JSON parsing for streaming AI responses

Files:

  • examples/ts-group-chat/chat-server/claude-service.ts
  • examples/ts-svelte-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/tools/index.ts
  • testing/panel/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/tools/tool-choice.ts
  • packages/typescript/ai-zai/tests/zai-factory.test.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
  • examples/ts-vue-chat/vite.config.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
  • examples/ts-react-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/message-types.ts
  • examples/ts-vue-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/tools/web-search-tool.ts
  • examples/ts-solid-chat/src/routes/api.chat.ts
  • packages/typescript/ai-zai/src/utils/conversion.ts
  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • examples/ts-react-chat/src/routes/api.tanchat.ts
  • packages/typescript/ai-zai/src/index.ts
  • testing/panel/src/routes/api.chat.ts
  • packages/typescript/ai-zai/src/utils/client.ts
  • packages/typescript/ai-zai/src/adapters/summarize.ts
  • packages/typescript/ai-zai/tests/zai-adapter.integration.test.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • examples/ts-svelte-chat/src/routes/api/chat/+server.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/vite.config.ts
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/src/model-meta.ts
  • packages/typescript/ai-zai/tests/model-meta.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use camelCase for function and variable names throughout the codebase

Files:

  • examples/ts-group-chat/chat-server/claude-service.ts
  • examples/ts-svelte-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/tools/index.ts
  • testing/panel/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/tools/tool-choice.ts
  • packages/typescript/ai-zai/tests/zai-factory.test.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
  • examples/ts-vue-chat/vite.config.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
  • examples/ts-react-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/message-types.ts
  • examples/ts-vue-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/tools/web-search-tool.ts
  • examples/ts-solid-chat/src/routes/api.chat.ts
  • packages/typescript/ai-zai/src/utils/conversion.ts
  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • examples/ts-react-chat/src/routes/api.tanchat.ts
  • packages/typescript/ai-zai/src/index.ts
  • testing/panel/src/routes/api.chat.ts
  • packages/typescript/ai-zai/src/utils/client.ts
  • packages/typescript/ai-zai/src/adapters/summarize.ts
  • packages/typescript/ai-zai/tests/zai-adapter.integration.test.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • examples/ts-svelte-chat/src/routes/api/chat/+server.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/vite.config.ts
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/src/model-meta.ts
  • packages/typescript/ai-zai/tests/model-meta.test.ts
examples/**

📄 CodeRabbit inference engine (CLAUDE.md)

Examples are not built by Nx and should be run independently from their directories with pnpm dev or pnpm install && pnpm dev

Files:

  • examples/ts-group-chat/chat-server/claude-service.ts
  • examples/ts-svelte-chat/src/lib/model-selection.ts
  • examples/ts-react-chat/package.json
  • examples/ts-vue-chat/vite.config.ts
  • examples/ts-react-chat/src/lib/model-selection.ts
  • examples/ts-vue-chat/src/lib/model-selection.ts
  • examples/ts-solid-chat/src/routes/api.chat.ts
  • examples/ts-react-chat/src/routes/api.tanchat.ts
  • examples/ts-group-chat/package.json
  • examples/ts-svelte-chat/package.json
  • examples/ts-vue-chat/package.json
  • examples/ts-solid-chat/package.json
  • examples/ts-svelte-chat/src/routes/api/chat/+server.ts
**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Write unit tests using Vitest alongside source files with .test.ts naming convention

Files:

  • packages/typescript/ai-zai/tests/zai-factory.test.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
  • packages/typescript/ai-zai/tests/zai-adapter.integration.test.ts
  • packages/typescript/ai-zai/tests/model-meta.test.ts
packages/typescript/*/src/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Export tree-shakeable adapters with clear subpath exports in package.json (e.g., @tanstack/ai/adapters, @tanstack/ai-openai/adapters) to minimize bundle size

Files:

  • packages/typescript/ai-zai/src/index.ts
packages/typescript/*/src/adapters/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Create individual adapter implementations for each provider capability (text, embed, summarize, image) with separate exports to enable tree-shaking

Files:

  • packages/typescript/ai-zai/src/adapters/summarize.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/src/adapters/index.ts
packages/typescript/*/src/model-meta.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Maintain model metadata files that define provider options and capabilities per model for per-model type safety

Files:

  • packages/typescript/ai-zai/src/model-meta.ts
🧠 Learnings (19)
📓 Common learnings
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/index.ts : Export tree-shakeable adapters with clear subpath exports in package.json (e.g., `tanstack/ai/adapters`, `tanstack/ai-openai/adapters`) to minimize bundle size
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/adapters/*.ts : Create individual adapter implementations for each provider capability (text, embed, summarize, image) with separate exports to enable tree-shaking
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Implement framework integrations using the headless `tanstack/ai-client` for state management with framework-specific hooks (useChat) on top
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Use tree-shakeable adapter architecture for provider implementations - export specialized adapters (text, embedding, summarize, image) as separate imports from `/adapters` subpath rather than monolithic adapters
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Implement stream processing with StreamProcessor for handling chunked responses and support partial JSON parsing for streaming AI responses
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Use type-safe per-model configuration with provider options typed based on selected model to ensure compile-time safety

Applied to files:

  • examples/ts-svelte-chat/src/lib/model-selection.ts
  • testing/panel/src/lib/model-selection.ts
  • examples/ts-vue-chat/vite.config.ts
  • examples/ts-react-chat/src/lib/model-selection.ts
  • examples/ts-vue-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • examples/ts-svelte-chat/src/routes/api/chat/+server.ts
  • packages/typescript/ai-zai/src/model-meta.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/model-meta.ts : Maintain model metadata files that define provider options and capabilities per model for per-model type safety

Applied to files:

  • examples/ts-svelte-chat/src/lib/model-selection.ts
  • testing/panel/src/lib/model-selection.ts
  • examples/ts-vue-chat/vite.config.ts
  • examples/ts-react-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/message-types.ts
  • examples/ts-vue-chat/src/lib/model-selection.ts
  • examples/ts-solid-chat/src/routes/api.chat.ts
  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • packages/typescript/ai-zai/src/index.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • examples/ts-svelte-chat/src/routes/api/chat/+server.ts
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/src/model-meta.ts
  • packages/typescript/ai-zai/tests/model-meta.test.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/adapters/*.ts : Create individual adapter implementations for each provider capability (text, embed, summarize, image) with separate exports to enable tree-shaking

Applied to files:

  • examples/ts-svelte-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/tools/index.ts
  • testing/panel/src/lib/model-selection.ts
  • packages/typescript/ai-zai/tests/zai-factory.test.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
  • examples/ts-vue-chat/vite.config.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
  • examples/ts-react-chat/src/lib/model-selection.ts
  • examples/ts-vue-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/tools/web-search-tool.ts
  • examples/ts-solid-chat/src/routes/api.chat.ts
  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • examples/ts-react-chat/src/routes/api.tanchat.ts
  • packages/typescript/ai-zai/src/index.ts
  • packages/typescript/ai-zai/package.json
  • packages/typescript/ai-zai/README.md
  • testing/panel/src/routes/api.chat.ts
  • packages/typescript/ai-zai/src/adapters/summarize.ts
  • packages/typescript/ai-zai/tests/zai-adapter.integration.test.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • packages/typescript/ai-zai/tsconfig.json
  • examples/ts-svelte-chat/src/routes/api/chat/+server.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/CHANGELOG.md
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Use tree-shakeable adapter architecture for provider implementations - export specialized adapters (text, embedding, summarize, image) as separate imports from `/adapters` subpath rather than monolithic adapters

Applied to files:

  • examples/ts-svelte-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/tests/zai-factory.test.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
  • examples/ts-vue-chat/vite.config.ts
  • examples/ts-solid-chat/src/routes/api.chat.ts
  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • examples/ts-react-chat/src/routes/api.tanchat.ts
  • packages/typescript/ai-zai/src/index.ts
  • packages/typescript/ai-zai/package.json
  • testing/panel/src/routes/api.chat.ts
  • packages/typescript/ai-zai/src/adapters/summarize.ts
  • packages/typescript/ai-zai/tests/zai-adapter.integration.test.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • examples/ts-svelte-chat/src/routes/api/chat/+server.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/CHANGELOG.md
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Ensure provider-agnostic design where the core AI SDK remains independent of any specific AI provider implementation

Applied to files:

  • examples/ts-svelte-chat/src/lib/model-selection.ts
  • testing/panel/src/lib/model-selection.ts
  • examples/ts-react-chat/src/lib/model-selection.ts
  • examples/ts-vue-chat/src/lib/model-selection.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/index.ts : Export tree-shakeable adapters with clear subpath exports in package.json (e.g., `tanstack/ai/adapters`, `tanstack/ai-openai/adapters`) to minimize bundle size

Applied to files:

  • packages/typescript/ai-zai/src/tools/index.ts
  • testing/panel/package.json
  • examples/ts-react-chat/package.json
  • packages/typescript/ai-zai/src/tools/tool-choice.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
  • packages/typescript/ai-zai/src/tools/web-search-tool.ts
  • examples/ts-solid-chat/src/routes/api.chat.ts
  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • examples/ts-react-chat/src/routes/api.tanchat.ts
  • packages/typescript/ai-zai/src/index.ts
  • packages/typescript/ai-zai/package.json
  • packages/typescript/ai-zai/README.md
  • examples/ts-group-chat/package.json
  • packages/typescript/ai-zai/src/adapters/summarize.ts
  • examples/ts-svelte-chat/package.json
  • packages/typescript/ai-zai/tests/zai-adapter.integration.test.ts
  • packages/typescript/ai-zai/tsconfig.json
  • examples/ts-vue-chat/package.json
  • examples/ts-solid-chat/package.json
  • examples/ts-svelte-chat/src/routes/api/chat/+server.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/vite.config.ts
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/CHANGELOG.md
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Implement isomorphic tool system using `toolDefinition()` with `.server()` and `.client()` implementations for dual-environment execution

Applied to files:

  • packages/typescript/ai-zai/src/tools/index.ts
  • packages/typescript/ai-zai/src/tools/tool-choice.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
  • packages/typescript/ai-zai/src/tools/web-search-tool.ts
  • packages/typescript/ai-zai/src/tools/tool-converter.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/*/package.json : Use `workspace:*` protocol for internal package dependencies in package.json (e.g., `"tanstack/ai": "workspace:*"`)

Applied to files:

  • testing/panel/package.json
  • examples/ts-react-chat/package.json
  • packages/typescript/ai-zai/package.json
  • examples/ts-group-chat/package.json
  • examples/ts-svelte-chat/package.json
  • examples/ts-vue-chat/package.json
  • examples/ts-solid-chat/package.json
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Use Nx workspace with affected commands to optimize testing and building only changed packages and their dependents

Applied to files:

  • testing/panel/package.json
  • examples/ts-svelte-chat/package.json
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Use Zod for runtime schema validation and type inference, particularly for tool input/output definitions with `toolDefinition()` and Zod schema inference

Applied to files:

  • packages/typescript/ai-zai/src/tools/tool-choice.ts
  • examples/ts-vue-chat/vite.config.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
  • packages/typescript/ai-zai/src/tools/web-search-tool.ts
  • packages/typescript/ai-zai/src/utils/conversion.ts
  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • packages/typescript/ai-zai/tests/zai-adapter.integration.test.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • packages/typescript/ai-zai/tsconfig.json
  • packages/typescript/ai-zai/CHANGELOG.md
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Implement stream processing with StreamProcessor for handling chunked responses and support partial JSON parsing for streaming AI responses

Applied to files:

  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
  • packages/typescript/ai-zai/src/utils/conversion.ts
  • testing/panel/src/routes/api.chat.ts
  • packages/typescript/ai-zai/tests/zai-adapter.integration.test.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
📚 Learning: 2025-12-27T20:22:51.232Z
Learnt from: harry-whorlow
Repo: TanStack/ai PR: 117
File: packages/typescript/ai-ollama/src/meta/model-meta-gpt-oss.ts:92-97
Timestamp: 2025-12-27T20:22:51.232Z
Learning: In the ai-ollama package's model-meta files (packages/typescript/ai-ollama/src/meta/model-meta-*.ts), capability-related comments follow a standard template format across all files for consistency, even if the comment text doesn't precisely match individual model capabilities. This is an intentional design choice to maintain uniformity across the codebase.

Applied to files:

  • examples/ts-react-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/src/message-types.ts
  • examples/ts-vue-chat/src/lib/model-selection.ts
  • packages/typescript/ai-zai/README.md
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • packages/typescript/ai-zai/src/model-meta.ts
  • packages/typescript/ai-zai/tests/model-meta.test.ts
📚 Learning: 2025-12-27T21:39:29.563Z
Learnt from: harry-whorlow
Repo: TanStack/ai PR: 117
File: packages/typescript/ai-ollama/src/meta/model-meta-llama-guard3.ts:70-75
Timestamp: 2025-12-27T21:39:29.563Z
Learning: The standard template comments in ai-ollama model-meta files (like "Models with text, image, audio, video (no document)") should not be modified to match individual model capabilities, as they are intentionally kept uniform across all model-meta-*.ts files for consistency, regardless of what each specific model actually supports.

Applied to files:

  • packages/typescript/ai-zai/src/message-types.ts
  • packages/typescript/ai-zai/src/model-meta.ts
  • packages/typescript/ai-zai/tests/model-meta.test.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Maintain type safety through multimodal content support (image, audio, video, document) with model capability awareness

Applied to files:

  • packages/typescript/ai-zai/src/message-types.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Implement framework integrations using the headless `tanstack/ai-client` for state management with framework-specific hooks (useChat) on top

Applied to files:

  • examples/ts-solid-chat/src/routes/api.chat.ts
  • examples/ts-react-chat/src/routes/api.tanchat.ts
  • packages/typescript/ai-zai/README.md
  • testing/panel/src/routes/api.chat.ts
  • packages/typescript/ai-zai/CHANGELOG.md
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to .eslintrc* : Use ESLint with custom TanStack config for linting all TypeScript and JavaScript files

Applied to files:

  • packages/typescript/ai-zai/package.json
  • examples/ts-svelte-chat/package.json
  • packages/typescript/ai-zai/tsconfig.json
  • packages/typescript/ai-zai/vite.config.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.test.ts : Write unit tests using Vitest alongside source files with `.test.ts` naming convention

Applied to files:

  • packages/typescript/ai-zai/tests/zai-adapter.integration.test.ts
  • packages/typescript/ai-zai/tsconfig.json
  • packages/typescript/ai-zai/vite.config.ts
  • packages/typescript/ai-zai/tests/model-meta.test.ts
📚 Learning: 2025-12-27T19:49:03.849Z
Learnt from: harry-whorlow
Repo: TanStack/ai PR: 117
File: packages/typescript/ai-ollama/src/meta/model-meta-deepseek-coder-v2.ts:7-18
Timestamp: 2025-12-27T19:49:03.849Z
Learning: For Ollama model metadata in the ai-ollama package, always consult https://ollama.com/library/ as the authoritative source for model specifications (size, context window, capabilities) rather than other documentation sources.

Applied to files:

  • packages/typescript/ai-zai/src/model-meta.ts
🧬 Code graph analysis (15)
examples/ts-svelte-chat/src/lib/model-selection.ts (1)
examples/ts-vue-chat/src/lib/model-selection.ts (1)
  • Provider (1-1)
testing/panel/src/lib/model-selection.ts (1)
examples/ts-react-chat/src/lib/model-selection.ts (1)
  • Provider (1-1)
packages/typescript/ai-zai/tests/zai-adapter.test.ts (1)
packages/typescript/ai-zai/src/adapters/text.ts (1)
  • ZAITextAdapter (56-412)
examples/ts-vue-chat/vite.config.ts (2)
examples/ts-svelte-chat/src/lib/model-selection.ts (1)
  • Provider (1-1)
examples/ts-vue-chat/src/lib/model-selection.ts (1)
  • Provider (1-1)
packages/typescript/ai-zai/src/tools/function-tool.ts (2)
packages/python/tanstack-ai/src/tanstack_ai/tool_utils.py (1)
  • tool (12-65)
packages/typescript/ai/src/types.ts (1)
  • JSONSchema (25-64)
examples/ts-react-chat/src/lib/model-selection.ts (1)
testing/panel/src/lib/model-selection.ts (1)
  • Provider (1-1)
examples/ts-vue-chat/src/lib/model-selection.ts (1)
examples/ts-svelte-chat/src/lib/model-selection.ts (1)
  • Provider (1-1)
packages/typescript/ai-zai/src/tools/web-search-tool.ts (1)
packages/python/tanstack-ai/src/tanstack_ai/tool_utils.py (1)
  • tool (12-65)
examples/ts-solid-chat/src/routes/api.chat.ts (3)
packages/typescript/ai-anthropic/src/index.ts (1)
  • anthropicText (8-8)
packages/typescript/ai/src/index.ts (2)
  • chat (3-3)
  • maxIterations (68-68)
examples/ts-solid-chat/src/lib/guitar-tools.ts (1)
  • serverTools (130-136)
packages/typescript/ai-zai/src/utils/conversion.ts (2)
packages/typescript/ai-zai/src/tools/tool-converter.ts (1)
  • convertToolsToProviderFormat (12-24)
packages/typescript/ai/src/types.ts (1)
  • StreamChunk (740-748)
packages/typescript/ai-zai/src/adapters/summarize.ts (4)
packages/typescript/ai-zai/src/adapters/text.ts (1)
  • ZAITextAdapterConfig (31-43)
packages/typescript/ai-zai/src/model-meta.ts (1)
  • ZAI_CHAT_MODELS (193-197)
packages/typescript/ai/src/types.ts (1)
  • StreamChunk (740-748)
packages/typescript/ai-zai/src/utils/client.ts (1)
  • getZAIApiKeyFromEnv (13-30)
packages/typescript/ai-zai/tests/zai-adapter.integration.test.ts (4)
packages/typescript/ai/src/activities/chat/stream/processor.ts (1)
  • process (387-410)
packages/typescript/ai/src/types.ts (1)
  • StreamChunk (740-748)
packages/typescript/ai-zai/src/adapters/index.ts (1)
  • createZAIChat (23-39)
packages/typescript/ai-svelte/src/create-chat.svelte.ts (1)
  • messages (121-123)
examples/ts-svelte-chat/src/routes/api/chat/+server.ts (3)
examples/ts-svelte-chat/src/lib/model-selection.ts (1)
  • Provider (1-1)
examples/ts-vue-chat/src/lib/model-selection.ts (1)
  • Provider (1-1)
packages/typescript/ai/src/index.ts (1)
  • createChatOptions (13-13)
packages/typescript/ai-zai/src/adapters/index.ts (3)
packages/typescript/ai-zai/src/model-meta.ts (1)
  • ZAI_CHAT_MODELS (193-197)
packages/typescript/ai-zai/src/adapters/text.ts (1)
  • ZAITextAdapter (56-412)
packages/typescript/ai-zai/src/utils/client.ts (1)
  • getZAIApiKeyFromEnv (13-30)
packages/typescript/ai-zai/src/model-meta.ts (1)
packages/typescript/ai-zai/src/text/text-provider-options.ts (6)
  • ZAIBaseOptions (4-76)
  • ZAIReasoningOptions (86-114)
  • ZAIStructuredOutputOptions (116-122)
  • ZAIToolsOptions (124-151)
  • ZAIStreamingOptions (153-166)
  • ZAIMetadataOptions (168-184)
🪛 Biome (2.1.2)
packages/typescript/ai-zai/src/message-types.ts

[error] 40-40: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 46-46: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 52-52: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

🪛 dotenv-linter (4.0.0)
testing/panel/.env.example

[warning] 22-22: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

🪛 LanguageTool
packages/typescript/ai-zai/README.md

[grammar] ~17-~17: Use a hyphen to join words.
Context: ...OpenAI-style tools - Supports Zhipu AI specific features like Web Search, *...

(QB_NEW_EN_HYPHEN)

🪛 markdownlint-cli2 (0.18.1)
packages/typescript/ai-zai/README.md

8-8: Bare URL used

(MD034, no-bare-urls)


297-297: Bare URL used

(MD034, no-bare-urls)


298-298: Bare URL used

(MD034, no-bare-urls)


299-299: Bare URL used

(MD034, no-bare-urls)

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

…TextAdapter

add support for image and video content in messages when model supports it
update documentation for model capabilities and tool types
add test case for image content preservation
Copy link
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: 3

🤖 Fix all issues with AI agents
In `@packages/typescript/ai-zai/src/adapters/text.ts`:
- Around line 401-412: Missing null checks: accessing part.source.value for
image/video parts can throw if part.source is undefined; update the branches
that handle part.type === 'image' and part.type === 'video' (the code that calls
parts.push with image_url/video_url) to guard on part.source (and
part.source.value) before referencing it, e.g., only push when part.source &&
part.source.value (or use optional chaining like part.source?.value) and
otherwise skip the part or use a safe fallback, keeping the existing checks for
capabilities.image/capabilities.video intact.

In `@packages/typescript/ai-zai/src/model-meta.ts`:
- Around line 152-161: The GLM_4_6 metadata is inconsistent: the comment says
"Released September 2025" but the object property knowledge_cutoff is
'2024-09-01'; update the metadata so they match (e.g., set
GLM_4_6.knowledge_cutoff to '2025-09-01' if the release date is correct) or
alternatively change the comment to "Released September 2024" to match the
existing knowledge_cutoff; modify the GLM_4_6 definition and its surrounding
comment accordingly.
♻️ Duplicate comments (1)
testing/panel/.env.example (1)

22-22: Add a blank line at EOF.

The missing newline at the end of the file violates the dotenv-linter convention and was flagged in previous reviews.

📝 Proposed fix
 # Ollama (local)
 # OLLAMA_HOST=http://localhost:11434
+
🧹 Nitpick comments (6)
packages/typescript/ai-zai/src/text/text-provider-options.ts (3)

29-33: Consider stronger typing for variables.

Using Record<string, any> reduces type safety. If the prompt template variables have a known structure, consider using a more specific type or generic parameter. If truly dynamic, Record<string, unknown> is slightly safer as it requires explicit type narrowing.

♻️ Suggested improvement
   prompt?: {
     id: string
     version?: string
-    variables?: Record<string, any>
+    variables?: Record<string, unknown>
   }

80-88: Consider exporting helper types for consumer use.

ReasoningEffort and ReasoningSummary are used in the exported ZAIReasoningOptions interface but aren't exported themselves. Consumers building type-safe configurations may need to reference these types directly.

♻️ Suggested improvement
 /**
  * Level of effort to expend on reasoning.
  */
-type ReasoningEffort = 'none' | 'minimal' | 'low' | 'medium' | 'high'
+export type ReasoningEffort = 'none' | 'minimal' | 'low' | 'medium' | 'high'

 /**
  * Detail level for the reasoning summary.
  */
-type ReasoningSummary = 'auto' | 'detailed'
+export type ReasoningSummary = 'auto' | 'detailed'

175-191: Minor naming inconsistency.

acceptLanguage uses camelCase while other properties in this file use snake_case (e.g., previous_response_id, parallel_tool_calls). Consider using accept_language for consistency with the OpenAI-style API convention used elsewhere, unless this specifically maps to an HTTP header pattern in the Z.AI API.

packages/typescript/ai-zai/src/tools/tool-converter.ts (1)

19-27: Consider extracting the magic string 'web_search' to a constant.

The hardcoded string 'web_search' at line 21 could lead to subtle bugs if the tool name changes or is misspelled elsewhere. Consider defining a constant (e.g., WEB_SEARCH_TOOL_NAME) that can be shared across the codebase for consistency.

♻️ Suggested refactor
+const WEB_SEARCH_TOOL_NAME = 'web_search' as const
+
 export function convertToolsToProviderFormat(
   tools: Array<Tool>,
 ): Array<ZaiTool> {
   return tools.map((tool) => {
     // Handle special tool names
-    if (tool.name === 'web_search') {
+    if (tool.name === WEB_SEARCH_TOOL_NAME) {
       return convertWebSearchToolToAdapterFormat(tool)
     }

     // Default to function tool
     return convertFunctionToolToAdapterFormat(tool)
   })
 }
packages/typescript/ai-zai/src/adapters/text.ts (2)

111-117: Avoid as any cast when constructing error chunks.

The as any cast at line 112 followed by property mutations loses type safety. Consider constructing a properly typed error chunk directly instead of mutating a converted result.

♻️ Suggested improvement
     } catch (error: unknown) {
-      const chunk = mapZAIErrorToStreamChunk(error) as any
-      chunk.id = fallbackId
-      chunk.model = options.model
-      chunk.timestamp = timestamp
-      yield chunk as StreamChunk
+      const errorChunk = mapZAIErrorToStreamChunk(error)
+      yield {
+        ...errorChunk,
+        id: fallbackId,
+        model: options.model,
+        timestamp,
+      } as StreamChunk
     }

155-161: Consider extending the request type to avoid as any casts.

The conditional additions of tools and stop use as any casts. While these work, they could be avoided by using a type intersection or explicitly typing the request object to include these optional fields.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 54bf059 and d6c7a64.

📒 Files selected for processing (13)
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/src/adapters/summarize.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/src/model-meta.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
  • packages/typescript/ai-zai/src/tools/tool-choice.ts
  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • packages/typescript/ai-zai/src/tools/web-search-tool.ts
  • packages/typescript/ai-zai/src/utils/client.ts
  • packages/typescript/ai-zai/src/utils/conversion.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
  • testing/panel/.env.example
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/typescript/ai-zai/src/tools/web-search-tool.ts
  • packages/typescript/ai-zai/src/adapters/summarize.ts
  • packages/typescript/ai-zai/src/utils/client.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use tree-shakeable adapter architecture for provider implementations - export specialized adapters (text, embedding, summarize, image) as separate imports from /adapters subpath rather than monolithic adapters
Use Zod for runtime schema validation and type inference, particularly for tool input/output definitions with toolDefinition() and Zod schema inference
Implement isomorphic tool system using toolDefinition() with .server() and .client() implementations for dual-environment execution
Use type-safe per-model configuration with provider options typed based on selected model to ensure compile-time safety
Implement stream processing with StreamProcessor for handling chunked responses and support partial JSON parsing for streaming AI responses

Files:

  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • packages/typescript/ai-zai/src/utils/conversion.ts
  • packages/typescript/ai-zai/src/tools/tool-choice.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/src/model-meta.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use camelCase for function and variable names throughout the codebase

Files:

  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • packages/typescript/ai-zai/src/utils/conversion.ts
  • packages/typescript/ai-zai/src/tools/tool-choice.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/src/model-meta.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
packages/typescript/*/src/adapters/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Create individual adapter implementations for each provider capability (text, embed, summarize, image) with separate exports to enable tree-shaking

Files:

  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
packages/typescript/*/src/model-meta.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Maintain model metadata files that define provider options and capabilities per model for per-model type safety

Files:

  • packages/typescript/ai-zai/src/model-meta.ts
**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Write unit tests using Vitest alongside source files with .test.ts naming convention

Files:

  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/adapters/*.ts : Create individual adapter implementations for each provider capability (text, embed, summarize, image) with separate exports to enable tree-shaking
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/index.ts : Export tree-shakeable adapters with clear subpath exports in package.json (e.g., `tanstack/ai/adapters`, `tanstack/ai-openai/adapters`) to minimize bundle size
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Implement framework integrations using the headless `tanstack/ai-client` for state management with framework-specific hooks (useChat) on top
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/adapters/*.ts : Create individual adapter implementations for each provider capability (text, embed, summarize, image) with separate exports to enable tree-shaking

Applied to files:

  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/src/model-meta.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Implement isomorphic tool system using `toolDefinition()` with `.server()` and `.client()` implementations for dual-environment execution

Applied to files:

  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • packages/typescript/ai-zai/src/utils/conversion.ts
  • packages/typescript/ai-zai/src/tools/tool-choice.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/index.ts : Export tree-shakeable adapters with clear subpath exports in package.json (e.g., `tanstack/ai/adapters`, `tanstack/ai-openai/adapters`) to minimize bundle size

Applied to files:

  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Use Zod for runtime schema validation and type inference, particularly for tool input/output definitions with `toolDefinition()` and Zod schema inference

Applied to files:

  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • packages/typescript/ai-zai/src/utils/conversion.ts
  • packages/typescript/ai-zai/src/tools/tool-choice.ts
  • packages/typescript/ai-zai/src/tools/function-tool.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to packages/typescript/*/src/model-meta.ts : Maintain model metadata files that define provider options and capabilities per model for per-model type safety

Applied to files:

  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • packages/typescript/ai-zai/src/model-meta.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Use tree-shakeable adapter architecture for provider implementations - export specialized adapters (text, embedding, summarize, image) as separate imports from `/adapters` subpath rather than monolithic adapters

Applied to files:

  • packages/typescript/ai-zai/src/tools/tool-converter.ts
  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • packages/typescript/ai-zai/src/adapters/index.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Implement stream processing with StreamProcessor for handling chunked responses and support partial JSON parsing for streaming AI responses

Applied to files:

  • packages/typescript/ai-zai/src/utils/conversion.ts
  • packages/typescript/ai-zai/src/adapters/text.ts
  • packages/typescript/ai-zai/tests/zai-adapter.test.ts
📚 Learning: 2025-12-13T17:09:09.794Z
Learnt from: CR
Repo: TanStack/ai PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T17:09:09.794Z
Learning: Applies to **/*.{ts,tsx} : Use type-safe per-model configuration with provider options typed based on selected model to ensure compile-time safety

Applied to files:

  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • packages/typescript/ai-zai/src/model-meta.ts
📚 Learning: 2025-12-27T20:22:51.232Z
Learnt from: harry-whorlow
Repo: TanStack/ai PR: 117
File: packages/typescript/ai-ollama/src/meta/model-meta-gpt-oss.ts:92-97
Timestamp: 2025-12-27T20:22:51.232Z
Learning: In the ai-ollama package's model-meta files (packages/typescript/ai-ollama/src/meta/model-meta-*.ts), capability-related comments follow a standard template format across all files for consistency, even if the comment text doesn't precisely match individual model capabilities. This is an intentional design choice to maintain uniformity across the codebase.

Applied to files:

  • packages/typescript/ai-zai/src/text/text-provider-options.ts
  • packages/typescript/ai-zai/src/model-meta.ts
📚 Learning: 2025-12-27T21:39:29.563Z
Learnt from: harry-whorlow
Repo: TanStack/ai PR: 117
File: packages/typescript/ai-ollama/src/meta/model-meta-llama-guard3.ts:70-75
Timestamp: 2025-12-27T21:39:29.563Z
Learning: The standard template comments in ai-ollama model-meta files (like "Models with text, image, audio, video (no document)") should not be modified to match individual model capabilities, as they are intentionally kept uniform across all model-meta-*.ts files for consistency, regardless of what each specific model actually supports.

Applied to files:

  • packages/typescript/ai-zai/src/model-meta.ts
📚 Learning: 2025-12-27T19:49:03.849Z
Learnt from: harry-whorlow
Repo: TanStack/ai PR: 117
File: packages/typescript/ai-ollama/src/meta/model-meta-deepseek-coder-v2.ts:7-18
Timestamp: 2025-12-27T19:49:03.849Z
Learning: For Ollama model metadata in the ai-ollama package, always consult https://ollama.com/library/ as the authoritative source for model specifications (size, context window, capabilities) rather than other documentation sources.

Applied to files:

  • packages/typescript/ai-zai/src/model-meta.ts
🧬 Code graph analysis (4)
packages/typescript/ai-zai/src/utils/conversion.ts (2)
packages/typescript/ai-zai/src/tools/tool-converter.ts (1)
  • convertToolsToProviderFormat (16-28)
packages/typescript/ai/src/types.ts (1)
  • StreamChunk (740-748)
packages/typescript/ai-zai/src/adapters/index.ts (3)
packages/typescript/ai-zai/src/model-meta.ts (1)
  • ZAI_CHAT_MODELS (193-197)
packages/typescript/ai-zai/src/adapters/text.ts (1)
  • ZAITextAdapter (56-462)
packages/typescript/ai-zai/src/utils/client.ts (1)
  • getZAIApiKeyFromEnv (13-30)
packages/typescript/ai-zai/src/model-meta.ts (1)
packages/typescript/ai-zai/src/text/text-provider-options.ts (6)
  • ZAIBaseOptions (4-76)
  • ZAIReasoningOptions (93-121)
  • ZAIStructuredOutputOptions (123-129)
  • ZAIToolsOptions (131-158)
  • ZAIStreamingOptions (160-173)
  • ZAIMetadataOptions (175-191)
packages/typescript/ai-zai/tests/zai-adapter.test.ts (4)
packages/typescript/ai-zai/src/adapters/index.ts (1)
  • ZAITextAdapter (5-5)
packages/typescript/ai-zai/src/adapters/text.ts (1)
  • ZAITextAdapter (56-462)
packages/typescript/ai/src/types.ts (2)
  • TextOptions (565-650)
  • StreamChunk (740-748)
packages/typescript/ai-svelte/src/create-chat.svelte.ts (1)
  • messages (121-123)
🪛 dotenv-linter (4.0.0)
testing/panel/.env.example

[warning] 22-22: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

🔇 Additional comments (25)
testing/panel/.env.example (1)

5-7: Nice fix—Z.AI URL now points directly to the API key management page.

This addresses the previous feedback and makes it easier for users to obtain their API keys.

packages/typescript/ai-zai/src/text/text-provider-options.ts (4)

123-129: LGTM!

Clean interface that appropriately reuses OpenAI's ResponseTextConfig type for structured output configuration.


131-158: LGTM!

The tools options interface is well-structured. The explicit string literals in tool_choice alongside the OpenAI type provide good documentation of common options while supporting complex tool choice configurations.


160-173: LGTM!

Streaming options are clearly defined with appropriate defaults documented.


193-203: LGTM!

The composite interface pattern aligns well with the tree-shakeable adapter architecture guidelines. Consumers can use granular option interfaces or the full ZAITextOptions as needed. Based on learnings, this modular approach supports per-model type safety.

packages/typescript/ai-zai/src/tools/tool-choice.ts (1)

1-26: LGTM!

Clean and well-documented type definitions for tool selection. The union type correctly combines literal modes ('auto', 'none') with specific tool configurations.

packages/typescript/ai-zai/src/model-meta.ts (3)

66-107: LGTM!

Well-structured model metadata with proper as const satisfies pattern for type-safe per-model configuration. The GLM-4.7 flagship model definition correctly captures context window, output limits, and supported capabilities.


109-150: LGTM!

GLM-4.6V multimodal model correctly declares ['text', 'image', 'video'] input support, enabling the adapter to conditionally preserve image/video content for this model.


193-236: LGTM!

Exports are well-organized: ZAI_CHAT_MODELS as a readonly array, ZAIModelMap for per-model provider options, ZAIModelInputModalitiesByName for capability lookups, and ZAI_MODEL_META as the complete registry. This follows the model-meta pattern for type-safe per-model configuration. Based on learnings.

packages/typescript/ai-zai/tests/zai-adapter.test.ts (7)

1-50: LGTM!

Clean test setup with proper OpenAI SDK mocking. The openAIState pattern effectively captures constructor options and mock function calls for verification.


52-77: LGTM!

Constructor tests properly verify:

  • Default Z.AI base URL (https://api.z.ai/api/paas/v4)
  • Custom baseURL override
  • Default Accept-Language header
  • API key validation (rejecting Bearer prefix and whitespace)

79-148: LGTM!

Options mapping tests thoroughly cover:

  • Standard parameters (maxTokensmax_tokens, temperature, topP)
  • Streaming defaults (stream: true, stream_options)
  • Tool conversion to OpenAI function format with additionalProperties: false
  • Stop sequences from modelOptions.stopSequences

150-229: LGTM!

Message conversion tests cover key scenarios: simple messages, system prompts concatenation, tool results with tool_call_id, and multi-turn conversations.


231-283: Good addition of multimodal test coverage.

Line 231-252 verifies text-only models (glm-4.7) filter out image parts, while Line 254-283 confirms multimodal models (glm-4.6v) preserve image content with proper OpenAI format conversion (image_url). This addresses the capability-aware content handling.


286-343: LGTM!

Error handling tests properly verify:

  • Network errors yield error chunks (non-throwing behavior)
  • Empty message arrays are handled gracefully
  • Malformed stream chunks don't cause crashes

345-466: LGTM!

Streaming behavior tests comprehensively cover:

  • Content delta accumulation with progressive content field
  • Tool call argument accumulation across chunks
  • Proper done chunk emission with finishReason and usage
  • Request headers passthrough to the underlying client
packages/typescript/ai-zai/src/tools/function-tool.ts (1)

1-35: LGTM!

Clean tool conversion with defensive JSON Schema normalization. Setting additionalProperties: false by default ensures stricter validation, and the fallback to an empty object schema handles tools without explicit input schemas.

packages/typescript/ai-zai/src/utils/conversion.ts (2)

9-15: LGTM!

The double cast (as unknown as) is appropriately documented. This is necessary because ZaiTool includes WebSearchTool which extends beyond OpenAI's type definitions.


17-54: LGTM!

Robust error-to-stream-chunk conversion with thorough extraction of error message and code from various error object shapes (nested error.error, direct properties, numeric status codes, and plain strings).

packages/typescript/ai-zai/src/tools/tool-converter.ts (1)

1-11: LGTM on type definitions and imports.

The ZaiTool union type is well-documented and correctly represents the two tool formats supported by Z.AI. The imports are minimal and appropriate for the module's purpose.

packages/typescript/ai-zai/src/adapters/index.ts (2)

33-66: LGTM on factory functions.

Both createZAIChat and zaiText provide clean, well-documented APIs for instantiating the adapter. The separation between explicit API key (createZAIChat) and environment-based (zaiText) is a good pattern that supports both server-side and development workflows. The apiKey validation at line 38-40 is good defensive coding.

Based on learnings, this aligns with the tree-shakeable adapter architecture guidelines.


3-3: Type-only import may cause issues with typeof usage.

Line 3 imports ZAI_CHAT_MODELS as a type-only import (import type), but line 17 uses typeof ZAI_CHAT_MODELS which requires the value to be available at compile time for type inference. This works in TypeScript because typeof in type position only needs the type information, but the intent could be clearer by importing the value directly if it's used for type derivation.

Verify this compiles correctly:

#!/bin/bash
# Check if the file compiles without errors
cd packages/typescript/ai-zai
cat src/adapters/index.ts | head -20
# Check for any TypeScript errors in this file
npx tsc --noEmit src/adapters/index.ts 2>&1 | head -20 || true

Also applies to: 17-17

packages/typescript/ai-zai/src/adapters/text.ts (3)

56-83: LGTM on class structure and constructor.

The generic type parameters provide good per-model type safety with ResolveProviderOptions and ResolveInputModalities. The constructor properly delegates client creation to createZAIClient, keeping the adapter focused on its core responsibility. This aligns with the tree-shakeable adapter architecture guidelines.


196-209: Good fix for the missing toolCallId validation.

The code now properly throws an error when toolCallId is missing instead of using an empty string fallback. This prevents silent API failures and provides clear error messaging for debugging.


427-461: LGTM on request header and abort signal helpers.

Both getRequestHeaders and getAbortSignal properly handle multiple input formats with appropriate type guards. The fallback chain in getAbortSignal correctly prioritizes abortController.signal over request.signal, which aligns with the TanStack AI conventions noted in the comments.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +302 to +308
if (!toolCallsInProgress.has(index)) {
toolCallsInProgress.set(index, {
id: toolCallDelta.id || '',
name: toolCallDelta.function?.name || '',
arguments: '',
})
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Empty string fallback for tool call id may cause issues.

Similar to the now-fixed toolCallId issue, initializing the tool call id with an empty string (line 304) could propagate invalid data. If the stream never provides the ID, the emitted tool_call chunk will have an empty id, which may cause issues when the tool result needs to be sent back.

🔧 Consider adding validation or logging
             if (!toolCallsInProgress.has(index)) {
               toolCallsInProgress.set(index, {
-                id: toolCallDelta.id || '',
+                id: toolCallDelta.id ?? '',
                 name: toolCallDelta.function?.name || '',
                 arguments: '',
               })
             }

Additionally, consider validating that toolCall.id is non-empty before emitting the tool_call chunk at lines 325-341.

📝 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
if (!toolCallsInProgress.has(index)) {
toolCallsInProgress.set(index, {
id: toolCallDelta.id || '',
name: toolCallDelta.function?.name || '',
arguments: '',
})
}
if (!toolCallsInProgress.has(index)) {
toolCallsInProgress.set(index, {
id: toolCallDelta.id ?? '',
name: toolCallDelta.function?.name || '',
arguments: '',
})
}

Comment on lines +401 to +412
} else if (part.type === 'image' && capabilities.image) {
parts.push({
type: 'image_url',
image_url: { url: part.source.value },
})
} else if (part.type === 'video' && capabilities.video) {
// Assuming Z.AI accepts video_url with the same structure as image_url
// Using 'any' cast because OpenAI types don't include video_url yet
parts.push({
type: 'video_url',
video_url: { url: part.source.value },
} as any)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing null check for part.source could cause runtime errors.

Lines 404 and 411 access part.source.value without verifying that part.source exists. If a content part has type: 'image' but no source property, this will throw a TypeError.

🔧 Add defensive null checks
-        } else if (part.type === 'image' && capabilities.image) {
+        } else if (part.type === 'image' && capabilities.image && part.source?.value) {
           parts.push({
             type: 'image_url',
             image_url: { url: part.source.value },
           })
-        } else if (part.type === 'video' && capabilities.video) {
+        } else if (part.type === 'video' && capabilities.video && part.source?.value) {
           // Assuming Z.AI accepts video_url with the same structure as image_url
           // Using 'any' cast because OpenAI types don't include video_url yet
           parts.push({
             type: 'video_url',
             video_url: { url: part.source.value },
           } as any)
         }
📝 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
} else if (part.type === 'image' && capabilities.image) {
parts.push({
type: 'image_url',
image_url: { url: part.source.value },
})
} else if (part.type === 'video' && capabilities.video) {
// Assuming Z.AI accepts video_url with the same structure as image_url
// Using 'any' cast because OpenAI types don't include video_url yet
parts.push({
type: 'video_url',
video_url: { url: part.source.value },
} as any)
} else if (part.type === 'image' && capabilities.image && part.source?.value) {
parts.push({
type: 'image_url',
image_url: { url: part.source.value },
})
} else if (part.type === 'video' && capabilities.video && part.source?.value) {
// Assuming Z.AI accepts video_url with the same structure as image_url
// Using 'any' cast because OpenAI types don't include video_url yet
parts.push({
type: 'video_url',
video_url: { url: part.source.value },
} as any)
}
🤖 Prompt for AI Agents
In `@packages/typescript/ai-zai/src/adapters/text.ts` around lines 401 - 412,
Missing null checks: accessing part.source.value for image/video parts can throw
if part.source is undefined; update the branches that handle part.type ===
'image' and part.type === 'video' (the code that calls parts.push with
image_url/video_url) to guard on part.source (and part.source.value) before
referencing it, e.g., only push when part.source && part.source.value (or use
optional chaining like part.source?.value) and otherwise skip the part or use a
safe fallback, keeping the existing checks for
capabilities.image/capabilities.video intact.

Comment on lines +152 to +161
/**
* GLM-4.6: Previous flagship model
* Released September 2025
* Enhanced coding and reasoning capabilities
*/
const GLM_4_6 = {
name: 'glm-4.6',
context_window: 128_000,
max_output_tokens: 128_000,
knowledge_cutoff: '2024-09-01',
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent dates in GLM-4.6 metadata.

The comment states "Released September 2025" but knowledge_cutoff is set to '2024-09-01'. Please verify and align these values.

🤖 Prompt for AI Agents
In `@packages/typescript/ai-zai/src/model-meta.ts` around lines 152 - 161, The
GLM_4_6 metadata is inconsistent: the comment says "Released September 2025" but
the object property knowledge_cutoff is '2024-09-01'; update the metadata so
they match (e.g., set GLM_4_6.knowledge_cutoff to '2025-09-01' if the release
date is correct) or alternatively change the comment to "Released September
2024" to match the existing knowledge_cutoff; modify the GLM_4_6 definition and
its surrounding comment accordingly.

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