Skip to content

feat!: Remove openassistant dependency - #423

Merged
mihajlo-stojkovic merged 22 commits into
mainfrom
chore/remove-openassistant-dep
Mar 19, 2026
Merged

mihajlo-stojkovic merged 22 commits into
mainfrom
chore/remove-openassistant-dep

Conversation

@mihajlo-stojkovic

@mihajlo-stojkovic mihajlo-stojkovic commented Mar 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This PR removes the dependency on @openassistant/* across all AI packages and replaces it with a native implementation built on top of the Vercel AI SDK (ai v5). The result is a leaner, more standard integration that aligns tool definitions and chat transport directly with the AI SDK primitives.

Affected packages: @sqlrooms/ai-core, @sqlrooms/ai, @sqlrooms/ai-rag, @sqlrooms/vega.


Breaking Changes

Tool definition format

Tools must now be created using tool() from the ai package directly. The OpenAssistant-specific format (name, parameters, component) is no longer supported.

Before

tools: {
  myTool: {
    name: 'myTool',
    parameters: MySchema,
    execute: async (params) => ({ llmResult: {...}, additionalData: {...} }),
    component: MyToolResult,
  }
}

After

import {tool} from 'ai';

tools: {
  myTool: tool({
    description: '...',
    inputSchema: MySchema,
    execute: async (params) => ({ success: true, ... }),
  })
}

Tool output format

The { llmResult, additionalData } split is gone. Tool execute functions now return a single flat object. Use toModelOutput if you need to control what the LLM sees vs. what the renderer receives (e.g. to strip large payloads from the model context).

Tool renderers are now separate from tools

The component field on tool definitions has been removed. Renderers are registered separately via the new toolRenderers option on createAiSlice.

Before

createAiSlice({ tools: { query: { ..., component: QueryToolResult } } })

After

import {createDefaultAiToolRenderers} from '@sqlrooms/ai';

createAiSlice({
  tools: { ...createDefaultAiTools(store) },
  toolRenderers: { ...createDefaultAiToolRenderers() },
})

Renamed APIs

Before After
setSessionToolAdditionalData setToolEditState
findToolComponent findToolRenderer
convertToAiSDKTools removed (no longer needed)
QueryToolLlmResult + QueryToolAdditionalData QueryToolOutput
RagToolAdditionalData + RagToolContext RagToolOutput
toolAdditionalData (persisted session field) toolEditState

Removed exports

  • convertToAiSDKTools (@sqlrooms/ai-core / @sqlrooms/ai)
  • createOnToolCompletedHandler (@sqlrooms/ai-core)

New APIs

createDefaultAiToolRenderers() — @sqlrooms/ai

Returns the renderer registry for the built-in tools. Pass it to createAiSlice alongside your own renderers.

import {createDefaultAiToolRenderers} from '@sqlrooms/ai';

createAiSlice({
  toolRenderers: {
    ...createDefaultAiToolRenderers(),
    chart: vegaChartToolRenderer,
  },
})

Convenience renderer re-exports

Each tool package now exports a ready-to-use renderer alias:

Export Package
queryToolRenderer @sqlrooms/ai
ragToolRenderer @sqlrooms/ai-rag
vegaChartToolRenderer @sqlrooms/vega

New types — @sqlrooms/ai-core

ToolRendererProps<TOutput>, ToolRenderer<TOutput>, ToolRendererRegistry, StoredTool, StoredToolSet


Migration Guide

  1. Replace tool definitions — wrap each tool with tool() from ai, rename parameters → inputSchema, flatten the return value.
  2. Split renderers out — move component references into a toolRenderers map and pass it to createAiSlice.
  3. Update type imports — replace QueryToolLlmResult/QueryToolAdditionalData with QueryToolOutput; same for RAG types.
  4. Rename method calls — setSessionToolAdditionalData → setToolEditState, findToolComponent → findToolRenderer.
  5. Persisted state — a migration is included that automatically renames toolAdditionalData → toolEditState in stored sessions. No manual action required.

See the updated examples (examples/ai, examples/ai-core, examples/ai-agent, examples/ai-rag, examples/ai-nextjs) for complete reference implementations.


What's Unchanged

  • The Chat component API and all UI components
  • Provider/model configuration (@sqlrooms/ai-settings, @sqlrooms/ai-config)
  • processAgentStream for the agent-as-tool pattern
  • DuckDB integration and all non-AI packages

Summary by CodeRabbit

  • New Features

    • Pluggable tool renderer system with a Vega chart renderer and configurable query/result renderers.
    • TooltipProvider added around main views for improved tooltip behavior.
  • Refactor

    • Tools now emit simpler, flat outputs; renderers are decoupled from tool definitions.
    • Per-session tool edit state persisted so chart/editor UI preserves edits.
  • Chores

    • Removed legacy tool-conversion utilities and updated related dependencies.

@coderabbitai

coderabbitai Bot commented Mar 10, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an SDK-native tool() pattern and a typed toolRenderers registry to AI slices, flattens tool outputs (removes nested llmResult/additionalData), renames session field toolAdditionalData → toolEditState, and updates transports, components, types, examples, tests, and docs to use renderer-focused flow.

Changes

Cohort / File(s) Summary
Core types & slice
packages/ai-core/src/types.ts, packages/ai-core/src/AiSlice.ts, packages/ai-core/src/index.ts
Added StoredTool/ToolRenderer/ToolRendererRegistry types; made createAiSlice generic over tools; added toolRenderers to state/options; renamed toolAdditionalData → toolEditState; removed convertToAiSDKTools/findToolComponent exports.
Transport & agent wiring
packages/ai-core/src/chatTransport.ts, packages/ai-core/src/agents/AgentUtils.ts
Transport/agent flows now invoke stored tools directly (tools[...].execute); removed conversion/onToolCompleted plumbing; persistence switched to setToolEditState.
Tool rendering & UI components
packages/ai-core/src/components/..., packages/ai-core/src/hooks/useToolGrouping.tsx
Tool rendering switched to registry lookup (ai.toolRenderers); ToolResult/ToolPartRenderer accept explicit props (toolName, input, output, state, errorText); removed per-session toolAdditionalData prop drilling.
Tool builder & defaults
packages/ai/src/tools/*, packages/ai/src/tools/defaultTools.ts, packages/ai/src/index.ts
Migrated to tool({ inputSchema, execute, toModelOutput? }); replaced parameters with inputSchema; added createDefaultAiTools and createDefaultAiToolRenderers; flattened tool outputs.
Packages: RAG, Vega, examples & apps
packages/ai-rag/src/*, packages/vega/src/*, examples/*/src/store.ts, apps/sqlrooms-cli-ui/src/store.ts
Tools converted to tool() API; renderers exported/registered (e.g., ragToolRenderer, VegaChartToolResult); example/app stores now pass toolRenderers into createAiSlice.
Result components across examples
examples/ai-core/src/components/EchoToolResult.tsx, examples/ai-nextjs/src/components/WebSearchToolResult.tsx, examples/app-builder/src/tools/*/*Result.tsx, packages/vega/src/VegaChartToolResult.tsx
Refactored result components to ToolRendererProps<Output> and use output (optional-chained) instead of legacy llmResult/details; Vega result persists edits via toolEditState.
Migrations, schema & tests
packages/ai-config/src/migration/AnalysisSession-v0.26.0.ts, packages/ai-config/src/schema/AnalysisSessionSchema.ts, packages/ai-core/__tests__/*
Renamed persisted session field to toolEditState; migration logic added/updated and unit tests cover migration scenarios.
Build, jest, mocks & deps
multiple package.json, jest configs, packages/*/__tests__/mocks/*
Removed @openassistant/utils usage/mocks and Jest moduleNameMapper overrides; added ai dependency and @sqlrooms/ai-core workspace entries; updated tests/mocks accordingly.
Docs & upgrade guide
packages/ai-core/README.md, docs/upgrade-guide.md, CLAUDE.md
Documented migration to SDK tool() pattern, renderer registry, flattened outputs, new types, toolEditState rename and migration steps.

Sequence Diagram(s)

sequenceDiagram
    participant UI as Client (UI)
    participant Store as AI Store
    participant Transport as Chat Transport
    participant Tool as Tool (AI SDK)
    participant Renderer as Tool Renderer

    UI->>Store: read tools & toolRenderers
    UI->>Transport: emit tool invocation (tool call)
    Transport->>Tool: tool.execute(input)
    Tool-->>Transport: return output
    Transport->>Store: addToolResult / setToolEditState
    UI->>Store: lookup toolRenderers[toolName]
    Store-->>UI: ToolRenderer component
    UI->>Renderer: render with ToolRendererProps(output,input,toolCallId,state)
    Renderer-->>UI: display result
Loading
sequenceDiagram
    participant App as App Init
    participant Renderers as createDefaultAiToolRenderers()
    participant CreateSlice as createAiSlice
    participant Store as AI Store

    App->>Renderers: createDefaultAiToolRenderers()
    Renderers-->>App: renderer registry
    App->>CreateSlice: createAiSlice({ tools, toolRenderers })
    CreateSlice->>Store: initialize state.toolRenderers = merged registry
    Store-->>App: store ready with toolRenderers
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • ilyabo

Poem

🐰 I hopped from nested llmResults into a cleaner glade,
where tools are built with tool() and renderers are arrayed.
I stash edits in toolEditState and show charts with delight,
nibbling flat outputs by day and testing through the night.
Hop, hop — new renderers bloom, the codebase feels light!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.62% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat!: Remove openassistant dependency' directly and clearly summarizes the main change in this PR—removal of the @openassistant/utils dependency and migration to native AI SDK tool implementations.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/remove-openassistant-dep
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@ilyabo

ilyabo commented Mar 10, 2026

Copy link
Copy Markdown
Collaborator

Looks like this includes breaking API changes. Could you add an entry to the upcoming 0.29.0 release in upgrade-guide.md describing what needs to be changed in client apps.

@lixun910

Copy link
Copy Markdown
Collaborator

👍 looks good. Than you, @mihajlo-stojkovic! Some questions:

  1. toModelOutput is in AI SDK v6, maybe it's a good time to upgrade to AI SD V6?
  2. when sending tool results from server to client (chat/route.ts), I saw the following code has been removed. Is it taken care by toModelOutput?
          async onChunk({chunk}) {
            switch (chunk.type) {
              case 'tool-result':
                // Send tool additional data as a data part that will be handled by onData callback
                // This data will be sent to the client but not included in UIMessages
                writer.write({
                  type: 'data-tool-additional-output',
                  transient: true, // Won't be added to message history
                  data: {
                    toolCallId: chunk.toolCallId,
                    toolName: chunk.toolName,
                    output: getToolAdditionalData(chunk.toolCallId),
                    timestamp: new Date().toISOString(),
                  },
                });
                break;
            }
          },
  1. for migration: "a migration is included that automatically renames toolAdditionalData → toolEditState", is it just a rename? if not, we might not need migration?

Thanks! 🚀

@lixun910 lixun910 linked an issue Mar 10, 2026 that may be closed by this pull request
@ilyabo

ilyabo commented Mar 11, 2026

Copy link
Copy Markdown
Collaborator

@copilot This PR separates tool renderers from tools which makes the consumer API more awkward to use. Should we try to find a way to avoid it? What are pro's an cons of them being separate?

@mihajlo-stojkovic
mihajlo-stojkovic marked this pull request as ready for review March 11, 2026 13:45
@mihajlo-stojkovic

Copy link
Copy Markdown
Collaborator Author

Looks like this includes breaking API changes. Could you add an entry to the upcoming 0.29.0 release in upgrade-guide.md describing what needs to be changed in client apps.

Hey @ilyabo! Yeah, removing the dependency on openassistant will result in breaking API changes as the tool type is now different (it's now a native Vercel AI SDK tool type). This is a major breaking change, so I'll add a description for the upgrade process for the 0.29.0 release.

@mihajlo-stojkovic

Copy link
Copy Markdown
Collaborator Author

👍 looks good. Than you, @mihajlo-stojkovic! Some questions:

  1. toModelOutput is in AI SDK v6, maybe it's a good time to upgrade to AI SD V6?
  2. when sending tool results from server to client (chat/route.ts), I saw the following code has been removed. Is it taken care by toModelOutput?
          async onChunk({chunk}) {
            switch (chunk.type) {
              case 'tool-result':
                // Send tool additional data as a data part that will be handled by onData callback
                // This data will be sent to the client but not included in UIMessages
                writer.write({
                  type: 'data-tool-additional-output',
                  transient: true, // Won't be added to message history
                  data: {
                    toolCallId: chunk.toolCallId,
                    toolName: chunk.toolName,
                    output: getToolAdditionalData(chunk.toolCallId),
                    timestamp: new Date().toISOString(),
                  },
                });
                break;
            }
          },
  1. for migration: "a migration is included that automatically renames toolAdditionalData → toolEditState", is it just a rename? if not, we might not need migration?

Thanks! 🚀

Hi @lixun910! Thanks for the kind reply. To address your questions:

  1. Yes, the end goal is to migrate to AI SDK v6, but as a prerequisite and to limit the scope of the PR, I just focused on removing the openassistant dependency for now, enabling an easier upgrade to v6 in the near future. Regarding toModelOutput, it's actually available in v5 as well! Find it here in the Vercel docs.
  2. Let me take a closer look at this. I removed it initially during development, and then didn't get a chance to test that in the NextJS example app, which uses a server-side agent.
  3. Yeah, it's purely a rename. The standalone rename migration only matters if someone ran the v0.26.0 migration during the brief window when the field was still called toolAdditionalData and then persisted that state. But I agree since this is just a rename that it's safe to remove it. I'll do it then.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 11

Caution

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

⚠️ Outside diff range comments (2)
examples/ai-core/package.json (1)

19-33: ⚠️ Potential issue | 🟠 Major

Bump eslint-plugin-react-hooks for React 19.2 and ESLint 9 compatibility.

This example uses React 19.2 with ESLint 9.28.0, but eslint-plugin-react-hooks is pinned to v5.2.0. Version 5.x does not support ESLint 9—update to v6.1.0 or newer (note: v6.0.0 was deprecated on npm).

🔧 Suggested change
-    "eslint-plugin-react-hooks": "^5.2.0",
+    "eslint-plugin-react-hooks": "^6.1.0",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/ai-core/package.json` around lines 19 - 33, Update the devDependency
for eslint-plugin-react-hooks in package.json to a version compatible with
ESLint 9 and React 19 (bump "eslint-plugin-react-hooks" from "5.2.0" to "6.1.0"
or newer); locate the dependency entry `"eslint-plugin-react-hooks": "5.2.0"`
and change its version string to "^6.1.0" (or the latest 6.x patch) so the
project uses a release that supports ESLint 9 and avoids the deprecated 6.0.0
release.
packages/ai-core/src/chatTransport.ts (1)

277-300: ⚠️ Potential issue | 🟠 Major

Fail fast when a tool has neither execute() nor a renderer.

Right now that branch just returns. The tool call stays incomplete, toolCallId -> sessionId is never cleared, and onChatFinish() will keep the analysis open because the assistant tail still contains a tool part.

Proposed fix
         } else {
           // Tool has no execute function - wait for UI component to call addToolResult
           const hasToolRenderer = !!state.ai.findToolRenderer(toolName);
           if (hasToolRenderer && state.ai.waitForToolResult) {
             try {
               await state.ai.waitForToolResult(
                 sessionId,
                 toolCallId,
                 abortController?.signal,
               );
               state.ai.setToolCallSession(toolCallId, undefined);
             } catch (error) {
               if (addToolResult && error instanceof Error) {
                 addToolResult({
                   tool: toolName,
                   toolCallId,
                   state: 'output-error',
                   errorText: error.message,
                 });
               }
               throw error;
             }
+          } else {
+            addToolResult?.({
+              tool: toolName,
+              toolCallId,
+              state: 'output-error',
+              errorText: `Tool "${toolName}" has no execute() and no registered renderer`,
+            });
+            state.ai.setToolCallSession(toolCallId, undefined);
           }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ai-core/src/chatTransport.ts` around lines 277 - 300, The code
currently returns silently when a tool has no renderer, leaving the tool call
mapping and assistant tail open; update the branch after computing
hasToolRenderer to detect the absence of both a renderer and an execute
implementation (lookup the tool by toolName via your AI tool registry accessor),
then immediately clear the mapping with state.ai.setToolCallSession(toolCallId,
undefined), call addToolResult({ tool: toolName, toolCallId, state:
'output-error', errorText: 'Tool has no execute() or renderer' }) if
addToolResult exists, and then throw a descriptive Error (or otherwise reject)
so the caller fails fast instead of returning no-op. Ensure this logic sits
where hasToolRenderer is checked (near state.ai.findToolRenderer /
state.ai.waitForToolResult) so the toolCallId -> sessionId mapping is always
cleared.
🧹 Nitpick comments (7)
packages/ai-core/src/agents/AgentUtils.ts (1)

43-66: Rename the helper/type to match toolEditState.

The implementation now writes through setToolEditState, but the local type and docs still use the removed “additional data” term. In this migration, that mismatch makes the stored payload harder to reason about.

♻️ Suggested rename
-export type AgentToolCallAdditionalData = {
+export type AgentToolCallEditState = {
   agentToolCalls: AgentToolCall[];
   finalOutput?: string;
   timestamp: string;
 };

-export function updateAgentToolCallData(params: {
+export function updateAgentToolCallEditState(params: {
   store: StoreApi<AiSliceState>;
   parentToolCallId: string;
   agentToolCalls: AgentToolCall[];
   sessionId: string;
   finalOutput?: string;
 }): void {
   const {store, parentToolCallId, agentToolCalls, sessionId, finalOutput} =
     params;
   const state = store.getState();
   state.ai.setToolEditState(sessionId, parentToolCallId, {
     agentToolCalls: [...agentToolCalls],
     finalOutput,
     timestamp: new Date().toISOString(),
-  } as AgentToolCallAdditionalData);
+  } as AgentToolCallEditState);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ai-core/src/agents/AgentUtils.ts` around lines 43 - 66, Rename the
AgentToolCallAdditionalData type and any references to "additional data" to
match the new toolEditState terminology and make the stored payload names
consistent with setToolEditState; specifically rename the type
AgentToolCallAdditionalData (and its doc comment) to something like
ToolEditState (or ToolEditStatePayload), update the JSDoc above
updateAgentToolCallData to reference toolEditState, and ensure
updateAgentToolCallData still calls state.ai.setToolEditState with the renamed
type and matching field names (agentToolCalls, finalOutput, timestamp) so the
API and types align.
packages/vega/src/index.ts (1)

22-22: Consider exporting vegaChartToolRenderer here too.

@sqlrooms/ai-rag now exposes a renderer alias, but Vega still makes consumers import the component name directly. Re-exporting a vegaChartToolRenderer alias from the barrel would keep the new tool/renderer API more uniform across packages.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vega/src/index.ts` at line 22, Add a re-export for the renderer
alias so consumers can import vegaChartToolRenderer from the package barrel;
update packages/vega/src/index.ts to export the renderer symbol
(vegaChartToolRenderer) from './VegaChartTool' alongside the existing type
exports (VegaChartToolOptions, VegaChartToolOutput) so the package follows the
new tool/renderer API convention.
examples/ai-rag/src/components/EchoToolResult.tsx (1)

4-9: Share the echo output type with the tool definition.

This renderer owns a local EchoToolOutput shape, while the echo tool in examples/ai-core/src/store.ts independently returns the same object from execute. Keeping those definitions separate makes future tool/result changes easy to desynchronize. Export the output type from one place and reuse it in both files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/ai-rag/src/components/EchoToolResult.tsx` around lines 4 - 9,
EchoToolResult defines a local EchoToolOutput type that duplicates the output
shape returned by the echo tool's execute in the tool definition; export the
output type from the canonical tool module (the echo tool in store.ts) and
remove the local EchoToolOutput here, then import and use that exported type in
the EchoToolResult component signature (FC<ToolRendererProps<...>>), ensuring
both the tool's execute return type and the renderer reference the same exported
type.
examples/app-builder/src/store/store.ts (1)

79-83: Co-locate tool and renderer registration.

toolRenderers now repeats the same keys that already exist in tools. That makes add/rename/remove changes easy to drift, and the failure mode is a working tool with no UI renderer. Consider keeping a single registry and deriving both maps from it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/app-builder/src/store/store.ts` around lines 79 - 83, The code
duplicates keys between the tools map and toolRenderers (toolRenderers: {
listFiles, getFileContent, updateFileContent }), which can drift; instead create
a single registry (e.g., an object or array) that pairs each tool identifier
with its implementation and renderer (reference the existing symbols tools,
toolRenderers, listFilesToolRenderer, getFileContentToolRenderer,
updateFileContentToolRenderer), then derive both the tools map and the
toolRenderers map from that registry so adding/renaming/removing a tool only
requires one change.
examples/ai-nextjs/src/app/lib/tools.ts (1)

3-4: Split this example by runtime boundary.

This module now mixes server-only tools, client-side executors, and React renderers. That makes getClientTools() hand webSearch to the browser and forces server callers of getServerAiSDKTools() to import WebSearchToolResult too. Prefer separate server-tools, client-tools, and tool-renderers modules so the example does not teach cross-bundle leakage.

Also applies to: 53-60

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/ai-nextjs/src/app/lib/tools.ts` around lines 3 - 4, This module
mixes server-only tools, client executors, and React renderers causing
cross-bundle leakage: split into three modules — a server tools module exporting
getServerAiSDKTools (containing server-only tool logic like webSearch), a client
tools/executors module exporting getClientTools (containing browser-safe
executors only), and a renderers module exporting UI
components/ToolRendererRegistry entries (e.g., WebSearchToolResult). Move
WebSearchToolResult and any UI/renderer registrations into the renderers module
and remove UI imports from the server module; update getClientTools and
getServerAiSDKTools to import only from their respective new modules so server
code never imports UI and browser bundles never import server-only code.
packages/ai-rag/src/createRagTool.tsx (2)

89-99: Unused destructured variables query and database.

The variables query and database are destructured from output on line 99 but never used in the component. This appears to be leftover from a previous implementation.

♻️ Proposed fix
-  const {query, results, database} = output;
+  const {results} = output;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ai-rag/src/createRagTool.tsx` around lines 89 - 99, In
RagToolResult, the destructured variables query and database from output are
unused; update the destructuring to only pull the needed property (e.g., const
{results} = output) or reference output.results directly to remove the unused
variables (modify the destructuring in the RagToolResult component to eliminate
query and database).

164-173: Global store access pattern is an established pattern necessary for AI tool execution.

This approach of accessing the store via (globalThis as any).__ROOM_STORE__ is documented throughout the codebase (README.md, RAG_TOOL.md, RAG_INTEGRATION.md) and required by the AI SDK architecture. Since AI tools are callback functions invoked by the AI framework (not controlled by application code), dependency injection isn't feasible. The pattern includes error handling that returns a structured error response when the store is unavailable.

While the pattern is type-unsafe, improving it would require either:

  • Creating a type-safe utility wrapper around the global access
  • Documenting the pattern more explicitly in code comments to clarify why it's necessary
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ai-rag/src/createRagTool.tsx` around lines 164 - 173, The global
store access via (globalThis as any).__ROOM_STORE__ inside the execute function
(signature: execute(params: RagToolParameters): Promise<RagToolOutput>) is an
intentional pattern required by the AI SDK; please add a concise explanatory
comment immediately above the store lookup referencing __ROOM_STORE__, stating
that AI tools are invoked by the framework (not via DI), linking to the
README/RAG_TOOL.md design, and preserving the existing structured error return
when the store is missing—alternatively, if you prefer, replace the direct cast
with a single small helper (e.g., getRoomStore()) that wraps the globalThis
access to centralize the unsafe cast and document the rationale there.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/ai-agent/src/agents/WeatherAgent.ts`:
- Around line 13-16: The nested agent started inside the execute function isn't
receiving the caller's tool-call abortSignal, so parent cancellations don't stop
the inner stream; update the call that starts the inner Agent/session (the
nested Agent invocation used with processAgentStream) to pass
options?.abortSignal through (or combine it with the session-level controller
via AbortSignal.any([...]) if both signals must be honored) so the nested agent
and processAgentStream are aborted when the tool-call is cancelled.

In `@examples/ai-nextjs/src/app/lib/tools.ts`:
- Around line 7-35: Update the repo lint/rule that enforces tool authorship to
match the new tool shape used by tool({ inputSchema, ... }) with separate
renderers instead of the old parameters/component contract: change the rule that
currently requires tools to be "composable functions with name, parameters (Zod
schema), execute, and optional component" to accept the new signature used by
the tool factory (referenced by the tool helper and examples like webSearchTool
and weatherTool) so it validates a Zod schema provided as inputSchema (or
similar property name used by the tool factory), ensures an execute async
function exists, and allows separate renderer components to be defined elsewhere
rather than requiring a component property.

In `@packages/ai-config/src/migration/AnalysisSession-v0.26.0.ts`:
- Around line 65-71: The current presence check uses Array.isArray(d.uiMessages)
which treats explicit null/{} as missing; change it to a key-presence check so
explicit values are considered present: replace the hasUiMessages assignment
(currently referencing d.uiMessages) with a check like "'uiMessages' in d" and
keep hasToolState as-is (it already uses 'toolEditState'/'toolAdditionalData' in
d) so the return condition uses key-presence semantics for both.
- Around line 79-82: The migration is copying legacy toolAdditionalData into
toolEditState but leaves toolAdditionalData on the returned payload, causing
duplication; update the migration so after computing const toolEditState =
(session.toolEditState as UnknownRecord) ?? (session.toolAdditionalData as
UnknownRecord) ?? {} you remove/drop the deprecated toolAdditionalData key from
the object you return (e.g., build the new session by spreading ...session but
explicitly omit toolAdditionalData and set toolEditState), and apply the same
change for the second occurrence referenced around the 165–169 block so the
migrated object no longer contains toolAdditionalData.

In `@packages/ai-core/README.md`:
- Around line 17-21: Add a direct link to the 0.29.0 migration guide in the
README section describing createAiSlice so users can find the breaking-change
checklist; update the paragraph that lists createAiSlice requirements to include
a parenthetical or sentence pointing to the 0.29.0 migration guide and
explicitly mention the key renames/migrations (parameters -> inputSchema,
component -> toolRenderers, toolAdditionalData -> toolEditState) and the need to
adjust ToolSet/toolRenderers usage accordingly (referencing createAiSlice,
toolRenderers, toolAdditionalData, and toolEditState to make it easy to locate
relevant code).

In `@packages/ai-core/src/components/PromptSuggestions.tsx`:
- Around line 188-214: The Button inside TooltipTrigger in PromptSuggestions.tsx
currently uses the title prop which causes duplicate browser tooltips; remove
the title prop and add an aria-label instead that mirrors the tooltip text (use
the same conditional string based on isVisible: 'Hide prompt suggestions' or
'Show prompt suggestions') so the accessible label matches the Tooltip; update
the Button JSX (the element using toggleVisibility, variant="ghost",
size="icon", className={cn(...)} and rendering {icon ?? <Lightbulb ... />}) to
use aria-label rather than title.

In `@packages/ai-core/src/index.ts`:
- Line 8: The upgrade guide is missing a 0.29.0 migration section for
`@sqlrooms/ai-core` breaking changes; add a new "0.29.0 - `@sqlrooms/ai-core`"
subsection in upgrade-guide.md that lists concrete migration steps for clients:
describe switching to the new tool() API, the changed shape of inputSchema (and
how to map previous schemas to the new shape), the flattened tool results format
and how to transform prior nested results, updates to toolRenderers (what
props/signatures changed) and the rename of toolEditState (old name → new name),
and mention exported types AiSliceState and AiSliceOptions are part of the
public surface so consumers should check for API usage; keep each step terse
with example mappings and the old→new identifier references so consumers can
update code.

In `@packages/ai/package.json`:
- Line 30: Update the toModelOutput handler in
packages/ai/src/tools/query/queryTool.ts to accept a destructured parameter ({
output }) instead of (output), then adjust all internal uses to reference the
inner output via that name; additionally, make any calls to
convertToModelMessages() await its result (convertToModelMessages(...) -> await
convertToModelMessages(...)) since it is now async—apply these two changes (wrap
toModelOutput parameter and add await where convertToModelMessages is invoked)
across the file/related call sites so they comply with the ai v6 breaking
changes.

In `@packages/ai/src/tools/query/queryTool.ts`:
- Around line 45-47: The re-export "export {QueryToolResult as
queryToolRenderer}" in queryTool.ts creates a circular dependency with
QueryToolResult.tsx (which imports QueryToolOutput/QueryToolParameters from this
file); fix it by removing that re-export from queryTool.ts and placing it into a
separate module (e.g., create a new renderers file that exports QueryToolResult
as queryToolRenderer) or by adding the export to the package index instead,
ensuring QueryToolResult, queryToolRenderer, QueryToolOutput and
QueryToolParameters remain imported from their original modules without cyclic
imports.

In `@packages/ai/src/tools/query/QueryToolResult.tsx`:
- Around line 1-8: QueryToolResult.tsx currently imports QueryToolParameters and
QueryToolOutput from queryTool.ts which creates a circular dependency because
queryTool.ts imports renderer-side exports; extract the shared types into a new
module (e.g., queryToolTypes.ts) and update both QueryToolResult.tsx and
queryTool.ts to import QueryToolParameters and QueryToolOutput from that new
file, or alternatively move the renderer alias export out of queryTool.ts into
the renderer package so queryTool.ts no longer imports renderer code; ensure you
update all import sites (references to QueryToolParameters, QueryToolOutput, and
any renderer alias export) to the new shared module to break the cycle.
- Around line 66-71: The current code passes sqlQuery into DataTableModal
(props: title, query, tableModal, formatValue), which causes the modal to
re-execute the SQL; instead, change QueryToolResult to pass the persisted result
snapshot (serialized in Apache Arrow format) to DataTableModal (e.g., a prop
named resultArrow or rows) and remove the query prop so the modal renders the
original output without reissuing the statement; update DataTableModal to accept
and deserialize the Arrow payload from the browser <-> DuckDB connector and
render that snapshot (using Arrow utilities) rather than executing sqlQuery,
ensuring all browser/connector serialization uses Apache Arrow format.

---

Outside diff comments:
In `@examples/ai-core/package.json`:
- Around line 19-33: Update the devDependency for eslint-plugin-react-hooks in
package.json to a version compatible with ESLint 9 and React 19 (bump
"eslint-plugin-react-hooks" from "5.2.0" to "6.1.0" or newer); locate the
dependency entry `"eslint-plugin-react-hooks": "5.2.0"` and change its version
string to "^6.1.0" (or the latest 6.x patch) so the project uses a release that
supports ESLint 9 and avoids the deprecated 6.0.0 release.

In `@packages/ai-core/src/chatTransport.ts`:
- Around line 277-300: The code currently returns silently when a tool has no
renderer, leaving the tool call mapping and assistant tail open; update the
branch after computing hasToolRenderer to detect the absence of both a renderer
and an execute implementation (lookup the tool by toolName via your AI tool
registry accessor), then immediately clear the mapping with
state.ai.setToolCallSession(toolCallId, undefined), call addToolResult({ tool:
toolName, toolCallId, state: 'output-error', errorText: 'Tool has no execute()
or renderer' }) if addToolResult exists, and then throw a descriptive Error (or
otherwise reject) so the caller fails fast instead of returning no-op. Ensure
this logic sits where hasToolRenderer is checked (near state.ai.findToolRenderer
/ state.ai.waitForToolResult) so the toolCallId -> sessionId mapping is always
cleared.

---

Nitpick comments:
In `@examples/ai-nextjs/src/app/lib/tools.ts`:
- Around line 3-4: This module mixes server-only tools, client executors, and
React renderers causing cross-bundle leakage: split into three modules — a
server tools module exporting getServerAiSDKTools (containing server-only tool
logic like webSearch), a client tools/executors module exporting getClientTools
(containing browser-safe executors only), and a renderers module exporting UI
components/ToolRendererRegistry entries (e.g., WebSearchToolResult). Move
WebSearchToolResult and any UI/renderer registrations into the renderers module
and remove UI imports from the server module; update getClientTools and
getServerAiSDKTools to import only from their respective new modules so server
code never imports UI and browser bundles never import server-only code.

In `@examples/ai-rag/src/components/EchoToolResult.tsx`:
- Around line 4-9: EchoToolResult defines a local EchoToolOutput type that
duplicates the output shape returned by the echo tool's execute in the tool
definition; export the output type from the canonical tool module (the echo tool
in store.ts) and remove the local EchoToolOutput here, then import and use that
exported type in the EchoToolResult component signature
(FC<ToolRendererProps<...>>), ensuring both the tool's execute return type and
the renderer reference the same exported type.

In `@examples/app-builder/src/store/store.ts`:
- Around line 79-83: The code duplicates keys between the tools map and
toolRenderers (toolRenderers: { listFiles, getFileContent, updateFileContent }),
which can drift; instead create a single registry (e.g., an object or array)
that pairs each tool identifier with its implementation and renderer (reference
the existing symbols tools, toolRenderers, listFilesToolRenderer,
getFileContentToolRenderer, updateFileContentToolRenderer), then derive both the
tools map and the toolRenderers map from that registry so
adding/renaming/removing a tool only requires one change.

In `@packages/ai-core/src/agents/AgentUtils.ts`:
- Around line 43-66: Rename the AgentToolCallAdditionalData type and any
references to "additional data" to match the new toolEditState terminology and
make the stored payload names consistent with setToolEditState; specifically
rename the type AgentToolCallAdditionalData (and its doc comment) to something
like ToolEditState (or ToolEditStatePayload), update the JSDoc above
updateAgentToolCallData to reference toolEditState, and ensure
updateAgentToolCallData still calls state.ai.setToolEditState with the renamed
type and matching field names (agentToolCalls, finalOutput, timestamp) so the
API and types align.

In `@packages/ai-rag/src/createRagTool.tsx`:
- Around line 89-99: In RagToolResult, the destructured variables query and
database from output are unused; update the destructuring to only pull the
needed property (e.g., const {results} = output) or reference output.results
directly to remove the unused variables (modify the destructuring in the
RagToolResult component to eliminate query and database).
- Around line 164-173: The global store access via (globalThis as
any).__ROOM_STORE__ inside the execute function (signature: execute(params:
RagToolParameters): Promise<RagToolOutput>) is an intentional pattern required
by the AI SDK; please add a concise explanatory comment immediately above the
store lookup referencing __ROOM_STORE__, stating that AI tools are invoked by
the framework (not via DI), linking to the README/RAG_TOOL.md design, and
preserving the existing structured error return when the store is
missing—alternatively, if you prefer, replace the direct cast with a single
small helper (e.g., getRoomStore()) that wraps the globalThis access to
centralize the unsafe cast and document the rationale there.

In `@packages/vega/src/index.ts`:
- Line 22: Add a re-export for the renderer alias so consumers can import
vegaChartToolRenderer from the package barrel; update packages/vega/src/index.ts
to export the renderer symbol (vegaChartToolRenderer) from './VegaChartTool'
alongside the existing type exports (VegaChartToolOptions, VegaChartToolOutput)
so the package follows the new tool/renderer API convention.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cebc8589-3ea4-453b-a682-6f8e36295ee9

📥 Commits

Reviewing files that changed from the base of the PR and between d4a1cbb and ce42348.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (64)
  • apps/sqlrooms-cli-ui/src/store.ts
  • examples/ai-agent/src/agents/WeatherAgent.ts
  • examples/ai-agent/src/room.tsx
  • examples/ai-core/package.json
  • examples/ai-core/src/components/EchoToolResult.tsx
  • examples/ai-core/src/room.tsx
  • examples/ai-core/src/store.ts
  • examples/ai-nextjs/README.md
  • examples/ai-nextjs/package.json
  • examples/ai-nextjs/src/app/api/chat/route.ts
  • examples/ai-nextjs/src/app/lib/tools.ts
  • examples/ai-nextjs/src/app/store.ts
  • examples/ai-nextjs/src/components/WebSearchToolResult.tsx
  • examples/ai-nextjs/src/components/room.tsx
  • examples/ai-rag/package.json
  • examples/ai-rag/src/components/EchoToolResult.tsx
  • examples/ai-rag/src/store.ts
  • examples/ai/package.json
  • examples/ai/src/components/EchoToolResult.tsx
  • examples/ai/src/store.ts
  • examples/app-builder/package.json
  • examples/app-builder/src/store/store.ts
  • examples/app-builder/src/tools/getFileContent/GetFileContentToolResult.tsx
  • examples/app-builder/src/tools/getFileContent/getFileContentTool.ts
  • examples/app-builder/src/tools/listFiles/ListFilesToolResult.tsx
  • examples/app-builder/src/tools/listFiles/createListFilesTool.ts
  • examples/app-builder/src/tools/updateFileContent/UpdateFileContentToolResult.tsx
  • examples/app-builder/src/tools/updateFileContent/updateFileContentTool.ts
  • packages/ai-config/src/AiSliceConfig.ts
  • packages/ai-config/src/migration/AnalysisSession-v0.26.0.ts
  • packages/ai-config/src/schema/AnalysisSessionSchema.ts
  • packages/ai-core/README.md
  • packages/ai-core/__tests__/AiSlice.modelSelection.test.ts
  • packages/ai-core/__tests__/migration.test.ts
  • packages/ai-core/__tests__/mocks/openassistant-utils.ts
  • packages/ai-core/jest.config.js
  • packages/ai-core/package.json
  • packages/ai-core/src/AiSlice.ts
  • packages/ai-core/src/agents/AgentUtils.ts
  • packages/ai-core/src/chatTransport.ts
  • packages/ai-core/src/components/AnalysisResult.tsx
  • packages/ai-core/src/components/GroupedMessageParts.tsx
  • packages/ai-core/src/components/MessagePartsList.tsx
  • packages/ai-core/src/components/PromptSuggestions.tsx
  • packages/ai-core/src/components/ToolPartRenderer.tsx
  • packages/ai-core/src/components/tools/ToolResult.tsx
  • packages/ai-core/src/hooks/useToolGrouping.tsx
  • packages/ai-core/src/index.ts
  • packages/ai-core/src/types.ts
  • packages/ai-rag/package.json
  • packages/ai-rag/src/createRagTool.tsx
  • packages/ai-rag/src/index.ts
  • packages/ai/package.json
  • packages/ai/src/index.ts
  • packages/ai/src/tools/commandTools.ts
  • packages/ai/src/tools/defaultTools.ts
  • packages/ai/src/tools/query/QueryToolResult.tsx
  • packages/ai/src/tools/query/queryTool.ts
  • packages/cells/__tests__/mocks/openassistant-utils.js
  • packages/cells/jest.config.js
  • packages/vega/package.json
  • packages/vega/src/VegaChartTool.tsx
  • packages/vega/src/VegaChartToolResult.tsx
  • packages/vega/src/index.ts
💤 Files with no reviewable changes (10)
  • packages/ai-rag/package.json
  • packages/cells/tests/mocks/openassistant-utils.js
  • packages/ai-core/src/components/MessagePartsList.tsx
  • examples/ai-nextjs/package.json
  • packages/ai-core/tests/mocks/openassistant-utils.ts
  • packages/ai-core/src/hooks/useToolGrouping.tsx
  • packages/ai-core/jest.config.js
  • packages/cells/jest.config.js
  • packages/ai-core/src/components/GroupedMessageParts.tsx
  • packages/ai-core/package.json

Comment thread examples/ai-agent/src/agents/WeatherAgent.ts
Comment thread examples/ai-nextjs/src/app/lib/tools.ts
Comment thread packages/ai-config/src/migration/AnalysisSession-v0.26.0.ts Outdated
Comment thread packages/ai-config/src/migration/AnalysisSession-v0.26.0.ts Outdated
Comment thread packages/ai-core/README.md
Comment thread packages/ai-core/src/index.ts
Comment thread packages/ai/package.json Outdated
Comment thread packages/ai/src/tools/query/queryTool.ts Outdated
Comment thread packages/ai/src/tools/query/QueryToolResult.tsx
Comment thread packages/ai/src/tools/query/QueryToolResult.tsx Outdated
Comment thread docs/upgrade-guide.md
Comment on lines +261 to +306
### `@sqlrooms/ai`: Remote transport — drop `data-tool-additional-output` custom chunk (breaking)

If you have a custom Next.js (or other server-side) route that manually wrote `data-tool-additional-output` data chunks to ferry `additionalData` to the client, you can remove that code entirely.

#### Before

```ts
// app/api/chat/route.ts
result.pipeThrough(
new TransformStream({
async onChunk({chunk}) {
if (chunk.type === 'tool-result') {
writer.write({
type: 'data-tool-additional-output',
transient: true,
data: {
toolCallId: chunk.toolCallId,
toolName: chunk.toolName,
output: getToolAdditionalData(chunk.toolCallId),
},
});
}
},
}),
);
```

#### After

Remove the `onChunk` handler. The AI SDK's `toUIMessageStream()` now embeds the full tool `execute()` output directly into the `UIMessage` stream as a `tool-result` part, which the renderer receives via `ToolRendererProps.output`. No side-channel is needed.

```ts
// app/api/chat/route.ts
writer.merge(
result.toUIMessageStream({originalMessages: messages}),
);
```

**Why this works:** Previously, `execute()` returned `{llmResult, additionalData}` — the UI data (`additionalData`) was separate and had to be sent manually. Now `execute()` returns a single flat output object. The AI SDK propagates the full output to the client through the standard `UIMessage` parts, so `ToolRendererProps.output` is populated automatically without any custom data chunks.

### `@sqlrooms/ai-core`: Removed exports

- `convertToAiSDKTools` — removed (tools are now native AI SDK tools)
- `findToolComponent` — replaced by `findToolRenderer`
- `VegaChartToolParametersType` from `@sqlrooms/vega` — removed (use `VegaChartToolParameters` directly)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@lixun910 I decided to add a comment about your second question in the upgrade-guide.md. Basically, I've outlined here why there's no need to transform stream chunks anymore. It's because additionalData is no longer decoupled from the tool response passed to LLM, and we no longer need to populate chunks with additional data.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CLAUDE.md`:
- Around line 213-231: Update the retrieved learning to reflect the AI SDK
migration: replace the old description that says "AI tools must be composable
functions with `name`, `parameters` (Zod schema), `execute`, and optional
`component` properties" with the new SDK conventions—tools are created via the
`tool()` factory (not inline objects), use `inputSchema` (not `parameters`),
return a flat output shape from `execute` (no `llmResult`/`additionalData`
nesting), and register renderers separately via `toolRenderers` in
`createAiSlice` (instead of attaching a `component` to the tool); reference
examples like `tool()`, `inputSchema`, `execute`, `createAiSlice`, and
`createQueryTool` when updating the text.
- Line 226: The tools registration is incorrectly spreading the complete tool
object (myTool) into the tools object; instead register the tool itself — stop
using the spread operator with myTool in the tools initializer and add myTool as
a value (either as a keyed entry like myTool: myTool or by including myTool in
the tools collection/array), keeping createQueryTool(store) as the query entry;
update the object that currently reads tools: { query: createQueryTool(store),
...myTool } to register myTool directly so the tool() object (myTool) is treated
as one tool rather than its internal properties being spread.

In `@docs/upgrade-guide.md`:
- Around line 261-299: The docs currently tell server-side removals for
`data-tool-additional-output` but omit client-side cleanup; update the upgrade
guide to instruct removing any client `onChatData` handlers (e.g., in
chatTransport.ts) that await/branch on parts with type
`'data-tool-additional-output'` and calls like `setToolEditState`, since those
branches are now dead, and note that tool edit state is populated from
`ToolRendererProps.output` instead.

In `@examples/ai-agent/src/agents/WeatherAgent.ts`:
- Around line 29-38: The code is fetching a redundant session-based abort signal
(sessionAbortSignal via currentSession/getAbortController) which binds the Agent
to the currently focused session; remove the sessionAbortSignal logic and any
use of getAbortController/currentSession and instead pass only
options?.abortSignal (or undefined) into the Agent constructor's abortSignal;
update the Agent instantiation (symbol: Agent) to set abortSignal:
options?.abortSignal and remove the conditional combining logic so cancellation
is driven solely by the abort signal provided by tool.execute.

In `@packages/ai-config/src/migration/AnalysisSession-v0.26.0.ts`:
- Around line 68-71: The current check treats the deprecated key
toolAdditionalData as if the new structure exists, so update the detection logic
in AnalysisSession-v0.26.0 by making hasToolState only true when 'toolEditState'
is present (i.e., remove 'toolAdditionalData' from the hasToolState check) so
sessions that still only have toolAdditionalData will not skip the migration;
reference the symbols hasUiMessages, hasToolState, uiMessages,
toolAdditionalData and toolEditState when making this change.
- Around line 76-84: Destructuring removed toolAdditionalData from session but
the fallback for toolEditState still reads session.toolAdditionalData (now
undefined), losing legacy payload; update the toolEditState assignment to fall
back to the captured _legacyToolAdditionalData (i.e., use (session.toolEditState
as UnknownRecord) ?? (_legacyToolAdditionalData as UnknownRecord) ?? {}), or
merge both sources if needed, so legacy toolAdditionalData is preserved when
computing toolEditState.

In `@packages/ai/src/tools/query/queryTool.ts`:
- Around line 127-134: In execute() currently catching errors and returning a
failure result object, re-throw the caught error instead so callers/renderers
can detect and render error states; locate the catch block in the execute()
function (where it returns { success: false, details: ..., error: ..., title:
'Query Result', sqlQuery: params.sqlQuery }) and replace the return with throw
error (or wrap and throw a new Error with context) so failed or aborted queries
are not treated as successful tool results by QueryToolResult.jsx/tsx.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3078d06d-e0ad-411f-bb66-9761e9024638

📥 Commits

Reviewing files that changed from the base of the PR and between ce42348 and e7f011a.

📒 Files selected for processing (10)
  • CLAUDE.md
  • docs/upgrade-guide.md
  • examples/ai-agent/src/agents/WeatherAgent.ts
  • packages/ai-config/src/migration/AnalysisSession-v0.26.0.ts
  • packages/ai-config/src/schema/AnalysisSessionSchema.ts
  • packages/ai-core/README.md
  • packages/ai-core/__tests__/migration.test.ts
  • packages/ai-core/src/components/PromptSuggestions.tsx
  • packages/ai/src/index.ts
  • packages/ai/src/tools/query/queryTool.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/ai-config/src/schema/AnalysisSessionSchema.ts
  • packages/ai-core/tests/migration.test.ts
  • packages/ai-core/README.md

Comment thread CLAUDE.md Outdated
Comment thread CLAUDE.md Outdated
Comment thread docs/upgrade-guide.md
Comment thread examples/ai-agent/src/agents/WeatherAgent.ts Outdated
Comment thread packages/ai-config/src/migration/AnalysisSession-v0.26.0.ts Outdated
Comment thread packages/ai-config/src/migration/AnalysisSession-v0.26.0.ts Outdated
Comment thread packages/ai/src/tools/query/queryTool.ts

@coderabbitai coderabbitai Bot left a comment

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.

Caution

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

⚠️ Outside diff range comments (1)
examples/ai-agent/src/agents/WeatherAgent.ts (1)

13-31: ⚠️ Potential issue | 🟠 Major

Resolve the nested agent from the tool-call session, not the focused one.

Line 18 uses state.ai.getCurrentSession() to pick provider and model. If the user switches chats while this tool is queued or running, the nested agent executes against the wrong session's model configuration. Use getToolCallSession(options.toolCallId) instead (see packages/ai-core/src/agents/AgentUtils.ts:91 for the pattern), and only fall back to the focused session when there is no tool-call context.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/ai-agent/src/agents/WeatherAgent.ts` around lines 13 - 31, The
execute function is using state.ai.getCurrentSession() to pick provider and
model, which causes the nested Agent to use the focused session instead of the
tool-call session; update execute to first resolve the tool-call session via
state.ai.getToolCallSession(options?.toolCallId) (falling back to
state.ai.getCurrentSession() if that returns undefined), and use that session's
modelProvider and model when constructing the createOpenAICompatible(...)
chatModel and new Agent(...) so the nested agent runs with the tool-call session
configuration.
🧹 Nitpick comments (1)
examples/ai-agent/src/agents/WeatherAgent.ts (1)

70-75: Expose only the summary to the model using toModelOutput.

In Vercel AI SDK v5, tools that return objects without toModelOutput send the entire JSON wrapper to the model. Instead, explicitly shape the model-facing output to show only the summary text—this prevents the bookkeeping fields from influencing the model's next action. Add toModelOutput to extract and expose only details:

Suggested shape
   return tool({
     description: 'My weather agent',
     inputSchema: z.object({
       prompt: z.string().describe('The prompt to the agent'),
     }),
+    toModelOutput: ({details}) => ({
+      type: 'text',
+      value: details,
+    }),
     execute: async (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/ai-agent/src/agents/WeatherAgent.ts` around lines 70 - 75, The tool
currently returns a JSON wrapper (success/details) which Vercel AI SDK v5 will
forward whole to the model; add a toModelOutput method on the returned object so
only the summary text is exposed to the model. Locate the object returned in
WeatherAgent (the block returning { success: true, details: resultText }) and
implement toModelOutput() { return { details: resultText } } (or return just the
summary string) so the model receives only the summary field instead of the
bookkeeping fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@examples/ai-agent/src/agents/WeatherAgent.ts`:
- Around line 13-31: The execute function is using state.ai.getCurrentSession()
to pick provider and model, which causes the nested Agent to use the focused
session instead of the tool-call session; update execute to first resolve the
tool-call session via state.ai.getToolCallSession(options?.toolCallId) (falling
back to state.ai.getCurrentSession() if that returns undefined), and use that
session's modelProvider and model when constructing the
createOpenAICompatible(...) chatModel and new Agent(...) so the nested agent
runs with the tool-call session configuration.

---

Nitpick comments:
In `@examples/ai-agent/src/agents/WeatherAgent.ts`:
- Around line 70-75: The tool currently returns a JSON wrapper (success/details)
which Vercel AI SDK v5 will forward whole to the model; add a toModelOutput
method on the returned object so only the summary text is exposed to the model.
Locate the object returned in WeatherAgent (the block returning { success: true,
details: resultText }) and implement toModelOutput() { return { details:
resultText } } (or return just the summary string) so the model receives only
the summary field instead of the bookkeeping fields.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 150377bd-5bc2-43cc-8eb2-292ec6872b2b

📥 Commits

Reviewing files that changed from the base of the PR and between e7f011a and 5419cba.

📒 Files selected for processing (4)
  • CLAUDE.md
  • examples/ai-agent/src/agents/WeatherAgent.ts
  • packages/ai-config/src/migration/AnalysisSession-v0.26.0.ts
  • packages/ai-core/__tests__/migration.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/ai-core/tests/migration.test.ts
  • CLAUDE.md

# Conflicts:
#	packages/vega/package.json
#	pnpm-lock.yaml

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
CLAUDE.md (1)

226-229: Complete the example by adding a renderer for myTool.

The example registers myTool in the tools object (line 226) but doesn't include a corresponding renderer in toolRenderers (lines 227-229). This makes the example incomplete and may confuse developers about whether renderers are required for all tools.

Consider either:

  1. Adding a renderer entry for myTool to demonstrate the complete pattern, or
  2. Adding a clarifying comment explaining that tools can optionally omit renderers if they don't need custom UI rendering.
📚 Proposed documentation improvement

Option 1: Add renderer for myTool (complete example)

 createAiSlice({
   tools: {query: createQueryTool(store), myTool},
   toolRenderers: {
     query: QueryToolResult,  // ToolRenderer<Output, Input>
+    myTool: MyToolResult,    // Renderer for myTool
   },
 });

Option 2: Clarify when renderers are optional

 // Renderers registered separately in createAiSlice
 createAiSlice({
   tools: {query: createQueryTool(store), myTool},
   toolRenderers: {
-    query: QueryToolResult,  // ToolRenderer<Output, Input>
+    query: QueryToolResult,  // ToolRenderer<Output, Input>
+    // Note: myTool omitted - tools without renderers use default display
   },
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CLAUDE.md` around lines 226 - 229, The example registers myTool in the tools
object but omits a corresponding entry in toolRenderers, leaving the example
incomplete; add a renderer entry for myTool inside toolRenderers (e.g., myTool:
MyToolRenderer) and ensure the referenced component (MyToolRenderer or
MyToolResult) is declared/imported and typed consistently (ToolRenderer<Output,
Input>) like QueryToolResult; alternatively, if you prefer to show renderers are
optional, add a short clarifying comment next to toolRenderers stating that
tools may omit a renderer if no custom UI is needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@CLAUDE.md`:
- Around line 226-229: The example registers myTool in the tools object but
omits a corresponding entry in toolRenderers, leaving the example incomplete;
add a renderer entry for myTool inside toolRenderers (e.g., myTool:
MyToolRenderer) and ensure the referenced component (MyToolRenderer or
MyToolResult) is declared/imported and typed consistently (ToolRenderer<Output,
Input>) like QueryToolResult; alternatively, if you prefer to show renderers are
optional, add a short clarifying comment next to toolRenderers stating that
tools may omit a renderer if no custom UI is needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eeca4c60-6157-42a2-877c-8231c3babc9c

📥 Commits

Reviewing files that changed from the base of the PR and between 2446159 and 8e35268.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • CLAUDE.md
  • packages/ai-core/package.json
  • packages/data-table/src/QueryDataTableActionsMenu.tsx
  • packages/notebook/src/cellOperations/AddNewCellDropdown.tsx
  • packages/vega/package.json
  • packages/vega/src/index.ts
💤 Files with no reviewable changes (2)
  • packages/ai-core/package.json
  • packages/data-table/src/QueryDataTableActionsMenu.tsx

Previously the renderer always showed the SQL block and "Show Query
Result" button regardless of success, causing the modal to re-run an
already-failed query. Branch on output.success === false and render
the error/details message instead.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Comment thread packages/ai-core/src/components/PromptSuggestions.tsx Outdated
mihajlo-stojkovic and others added 7 commits March 18, 2026 13:28
Signed-off-by: Ilya Boyandin <[email protected]>
Co-authored-by: Ilya Boyandin <[email protected]>
Co-authored-by: Xun Li <[email protected]>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: dmitriy-kostianetskiy <[email protected]>
Co-authored-by: Dmitriy Kostianetskiy <[email protected]>
# Conflicts:
#	CLAUDE.md
#	CLAUDE.md~main
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
@mihajlo-stojkovic
mihajlo-stojkovic merged commit d6476dd into main Mar 19, 2026
4 checks passed
@mihajlo-stojkovic
mihajlo-stojkovic deleted the chore/remove-openassistant-dep branch March 19, 2026 11:43
dmitriy-kostianetskiy pushed a commit that referenced this pull request Mar 20, 2026
Signed-off-by: Ilya Boyandin <[email protected]>
Co-authored-by: Ilya Boyandin <[email protected]>
Co-authored-by: Ilya Boyandin <[email protected]>
Co-authored-by: Xun Li <[email protected]>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Claude Sonnet 4.6 <[email protected]>
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.

Remove openassistant dependency in favor of native Vercel AI SDK features remove openassistant dependencies

3 participants