Repository: assistant-ui/assistant-ui
Pull request #1859: feat: assistant-ui update CLI command
Author: login: Yonom
Created: 2025-04-18T19:05:49Z | Merged: 2025-04-18T19:06:04Z


<!-- ELLIPSIS_HIDDEN -->



> [!IMPORTANT]
> Adds `update` CLI command for package updates and a new tool in the example app with streaming capabilities.
> 
>   - **CLI Command**:
>     - Adds `update` command in `update.ts` to update `@assistant-ui/*` and `assistant-stream` packages to latest versions.
>     - Supports `--dry` option to print command without executing.
>     - Integrated into CLI in `index.ts`.
>   - **Example App**:
>     - Adds `MyToolUI` using `makeAssistantTool` in `assistant.tsx` with parameters `name`, `age`, and `nicknames`.
>     - Implements streaming and logging for parameters.
>   - **Dependencies**:
>     - Adds `semver` and `@types/semver` to `package.json`.
> 
> <sup>This description was created by </sup>[<img alt="Ellipsis" src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=assistant-ui%2Fassistant-ui&utm_source=github&utm_medium=referral)<sup> for 6ec8ad22dbc86ef49b34a6fa31d55da5f6a9ff88. It will automatically update as commits are pushed.</sup>

<!-- ELLIPSIS_HIDDEN -->


Diff:
diff --git a/.changeset/stupid-clocks-write.md b/.changeset/stupid-clocks-write.md
new file mode 100644
index 0000000000..9fdda3d763
--- /dev/null
+++ b/.changeset/stupid-clocks-write.md
@@ -0,0 +1,6 @@
+---
+"@assistant-ui/react": patch
+"assistant-ui": patch
+---
+
+feat: assistant-ui update CLI command
diff --git a/examples/with-ai-sdk/app/assistant.tsx b/examples/with-ai-sdk/app/assistant.tsx
index bcc377c003..5df5b59e67 100644
--- a/examples/with-ai-sdk/app/assistant.tsx
+++ b/examples/with-ai-sdk/app/assistant.tsx
@@ -1,8 +1,46 @@
 "use client";
 
-import { AssistantRuntimeProvider } from "@assistant-ui/react";
+import {
+  AssistantRuntimeProvider,
+  makeAssistantTool,
+} from "@assistant-ui/react";
 import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
 import { Thread } from "@/components/assistant-ui/thread";
+import { z } from "zod";
+
+const MyToolUI = makeAssistantTool({
+  toolName: "my_tool",
+  parameters: z.object({
+    name: z.string(),
+    age: z.number(),
+    nicknames: z.array(z.string()),
+  }),
+  streamCall: async (reader) => {
+    reader.args.streamText("name").pipeTo(
+      new WritableStream({
+        write: (value) => console.log("NAME UPDATE", value),
+      }),
+    );
+
+    const test = await reader.args.get("name");
+    console.log(test);
+
+    reader.args.streamValues("age").pipeTo(
+      new WritableStream({
+        write: (value) => console.log("AGE UPDATE", value),
+      }),
+    );
+
+    const test2 = await reader.args.get("age");
+    console.log(test2);
+
+    for await (const nickname of reader.args.forEach("nicknames")) {
+      console.log("NICKNAME", nickname);
+    }
+
+    console.log(await reader.result.get());
+  },
+});
 
 export const Assistant = () => {
   const runtime = useChatRuntime({
@@ -13,6 +51,7 @@ export const Assistant = () => {
     <AssistantRuntimeProvider runtime={runtime}>
       <div className="grid h-dvh gap-x-2 px-4 py-4">
         <Thread />
+        <MyToolUI />
       </div>
     </AssistantRuntimeProvider>
   );
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 8a0d95e169..7439c91cfa 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -11,7 +11,8 @@
     "debug": "^4.4.0",
     "detect-package-manager": "^3.0.2",
     "glob": "^11.0.1",
-    "jscodeshift": "^17.3.0"
+    "jscodeshift": "^17.3.0",
+    "semver": "^7.7.1"
   },
   "devDependencies": {
     "@assistant-ui/tsbuildutils": "workspace:*",
@@ -21,6 +22,7 @@
     "@types/debug": "^4.1.12",
     "@types/jscodeshift": "^17.3.0",
     "@types/node": "^22.14.1",
+    "@types/semver": "^7.7.0",
     "eslint-config-next": "15.3.1",
     "tsx": "^4.19.3"
   },
diff --git a/packages/cli/src/commands/update.ts b/packages/cli/src/commands/update.ts
new file mode 100644
index 0000000000..b4f9799737
--- /dev/null
+++ b/packages/cli/src/commands/update.ts
@@ -0,0 +1,60 @@
+import { Command } from "commander";
+import fs from "fs";
+import path from "path";
+import chalk from "chalk";
+import { detect } from "detect-package-manager";
+import { sync as spawnSync } from "cross-spawn";
+
+export const update = new Command()
+  .name("update")
+  .description(
+    "Update all '@assistant-ui/*' and 'assistant-stream' packages in package.json to latest versions using your package manager.",
+  )
+  .option("--dry", "Print the package manager command instead of running it.")
+  .action(async (opts) => {
+    const packageJsonPath = path.join(process.cwd(), "package.json");
+    if (!fs.existsSync(packageJsonPath)) {
+      console.error(
+        chalk.red("No package.json found in the current directory."),
+      );
+      process.exit(1);
+    }
+    const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
+    const sections = ["dependencies", "devDependencies"];
+    const targets: string[] = [];
+    for (const section of sections) {
+      if (!pkg[section]) continue;
+      for (const dep in pkg[section]) {
+        if (dep.startsWith("@assistant-ui/") || dep === "assistant-stream") {
+          targets.push(dep);
+        }
+      }
+    }
+    if (!targets.length) {
+      console.log(chalk.yellow("No matching packages found to update."));
+      return;
+    }
+    const pm = await detect({ cwd: process.cwd() });
+    let cmd: string;
+    if (pm === "yarn") {
+      cmd = `yarn add ${targets.map((d) => `${d}@latest`).join(" ")}`;
+    } else if (pm === "pnpm") {
+      cmd = `pnpm add ${targets.map((d) => `${d}@latest`).join(" ")}`;
+    } else if (pm === "bun") {
+      cmd = `bun add ${targets.map((d) => `${d}@latest`).join(" ")}`;
+    } else {
+      cmd = `npm install ${targets.map((d) => `${d}@latest`).join(" ")}`;
+    }
+    if (opts.dry) {
+      console.log(chalk.blue("\nDry run: would run the following command:"));
+      console.log(cmd);
+      return;
+    }
+    console.log(chalk.blue(`\nRunning: ${cmd}`));
+    const result = spawnSync(cmd, { shell: true, stdio: "inherit" });
+    if (result.status !== 0) {
+      console.error(chalk.red("Package manager update failed."));
+      process.exit(result.status || 1);
+    }
+    console.log(chalk.green("\nAll packages updated to latest version!"));
+  });
diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts
index d6634b4711..c20bbab3fd 100644
--- a/packages/cli/src/index.ts
+++ b/packages/cli/src/index.ts
@@ -5,6 +5,7 @@ import { create } from "./commands/create";
 import { add } from "./commands/add";
 import { codemodCommand, upgradeCommand } from "./commands/upgrade";
 import { init } from "./commands/init";
+import { update } from "./commands/update";
 
 process.on("SIGINT", () => process.exit(0));
 process.on("SIGTERM", () => process.exit(0));
@@ -19,6 +20,7 @@ function main() {
   program.addCommand(init);
   program.addCommand(codemodCommand);
   program.addCommand(upgradeCommand);
+  program.addCommand(update);
 
   program.parse();
 }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8c87986858..58d1f96369 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1314,6 +1314,9 @@ importers:
       jscodeshift:
         specifier: ^17.3.0
         version: 17.3.0
+      semver:
+        specifier: ^7.7.1
+        version: 7.7.1
     devDependencies:
       '@assistant-ui/tsbuildutils':
         specifier: workspace:*
@@ -1336,6 +1339,9 @@ importers:
       '@types/node':
         specifier: ^22.14.1
         version: 22.14.1
+      '@types/semver':
+        specifier: ^7.7.0
+        version: 7.7.0
       eslint-config-next:
         specifier: 15.3.1
         version: 15.3.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.8.3)
@@ -4252,6 +4258,9 @@ packages:
   '@types/retry@0.12.0':
     resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==}
 
+  '@types/semver@7.7.0':
+    resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==}
+
   '@types/shimmer@1.2.0':
     resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==}
 
@@ -11297,6 +11306,8 @@ snapshots:
 
   '@types/retry@0.12.0': {}
 
+  '@types/semver@7.7.0': {}
+
   '@types/shimmer@1.2.0': {}
 
   '@types/tedious@4.0.14':


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR adds a new CLI command ("update") to update assistant-ui packages and integrates a corresponding tool into the assistant UI example.  
- Adds an import and registration of the update command in the CLI entry point  
- Implements the update command with detection of the package manager and dry run support  
- Integrates a new tool UI using makeAssistantTool in the assistant example  
- Adds a changeset for the update feature

### Reviewed Changes

Copilot reviewed 4 out of 6 changed files in this pull request and generated 1 comment.

| File                                     | Description                                                 |
| ---------------------------------------- | ----------------------------------------------------------- |
| packages/cli/src/index.ts                | Registers the new update command in the CLI application     |
| packages/cli/src/commands/update.ts      | Implements update command using package manager detection     |
| examples/with-ai-sdk/app/assistant.tsx   | Integrates a new tool UI using makeAssistantTool              |
| .changeset/stupid-clocks-write.md        | Adds a changeset entry for the assistant-ui update CLI command |

<details>
<summary>Files not reviewed (2)</summary>

* **packages/cli/package.json**: Language not supported
* **pnpm-lock.yaml**: Language not supported
</details>

<details>
<summary>Comments suppressed due to low confidence (3)</summary>

**examples/with-ai-sdk/app/assistant.tsx:25**
* [nitpick] Rename the variable 'test' to a more descriptive name like 'nameValue' to improve readability.
```
const test = await reader.args.get("name");
```
**examples/with-ai-sdk/app/assistant.tsx:34**
* [nitpick] Rename the variable 'test2' to a more descriptive name like 'ageValue' to better convey its purpose.
```
const test2 = await reader.args.get("age");
```
**examples/with-ai-sdk/app/assistant.tsx:37**
* [nitpick] Verify that 'reader.args.forEach' returns an async iterable; if not, consider using an alternative asynchronous iteration method.
```
for await (const nickname of reader.args.forEach("nicknames")) {
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T19:06:21Z
user: login: greptile-apps[bot]
body: 
## PR Summary

Added a new CLI command 'update' for managing @assistant-ui/* packages and enhanced the assistant tool UI with streaming data capabilities.

- Added `packages/cli/src/commands/update.ts` with package manager detection (npm, yarn, pnpm, bun) and automatic updates
- Added `--dry` flag option in update command for command preview without execution
- Added streaming data handling in `examples/with-ai-sdk/app/assistant.tsx` for name, age, and nicknames parameters
- Added 'semver' dependency in `packages/cli/package.json` for version management
- Integrated update command registration in `packages/cli/src/index.ts` following existing command structure

<sub>4 file(s) reviewed, 1 comment(s)</sub>
<sub>[Edit PR Review Bot Settings](https://app.greptile.com/review/github) | [Greptile](https://greptile.com?utm_source=greptile_expert&utm_medium=github&utm_campaign=code_reviews&utm_content=assistant-ui_1859)</sub>
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T19:06:34Z
user: login: ellipsis-dev[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T19:08:14Z
user: login: cubic-dev-ai[bot]
body: mrge found 1 issue across 5 files. View it in [mrge.io](https://mrge.io/pr/assistant-ui/assistant-ui/pull/1859)
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T19:08:22Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 0e639b5c572351be0d7915182446856a7727289e and 6ec8ad22dbc86ef49b34a6fa31d55da5f6a9ff88.

</details>

<details>
<summary>⛔ Files ignored due to path filters (2)</summary>

* `.changeset/stupid-clocks-write.md` is excluded by `!.changeset/**`
* `pnpm-lock.yaml` is excluded by `!**/pnpm-lock.yaml`

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `examples/with-ai-sdk/app/assistant.tsx` (2 hunks)
* `packages/cli/package.json` (2 hunks)
* `packages/cli/src/commands/update.ts` (1 hunks)
* `packages/cli/src/index.ts` (2 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (2)</summary>

<details>
<summary>packages/cli/src/index.ts (1)</summary><blockquote>

<details>
<summary>packages/cli/src/commands/update.ts (1)</summary>

* `update` (8-60)

</details>

</blockquote></details>
<details>
<summary>examples/with-ai-sdk/app/assistant.tsx (2)</summary><blockquote>

<details>
<summary>packages/react/src/model-context/index.ts (1)</summary>

* `makeAssistantTool` (1-1)

</details>
<details>
<summary>python/assistant-stream/src/assistant_stream/create_run.py (1)</summary>

* `reader` (54-56)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>packages/cli/src/commands/update.ts</summary>

[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.


(lint/style/useNodejsImportProtocol)

---

[error] 3-3: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.


(lint/style/useNodejsImportProtocol)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (10)</summary><blockquote>

<details>
<summary>packages/cli/package.json (2)</summary>

`14-15`: **Added semver dependency.**

The `semver` package has been added as a dependency to support semantic versioning checks in the new `update` command.

---

`25-25`: **Added corresponding type definitions for semver.**

The TypeScript type definitions for `semver` have been added as a dev dependency to provide proper typing support.

</details>
<details>
<summary>examples/with-ai-sdk/app/assistant.tsx (2)</summary>

`3-9`: **Added necessary imports for the new tool.**

The imports have been properly added for `AssistantRuntimeProvider`, `makeAssistantTool` from the `@assistant-ui/react` package, and `z` from the `zod` package required for parameter validation.

---

`54-54`: **Successfully integrated the new tool component.**

The `MyToolUI` component has been properly added to the Assistant's render output within the `AssistantRuntimeProvider` alongside the existing `Thread` component.

</details>
<details>
<summary>packages/cli/src/index.ts (2)</summary>

`8-8`: **Added import for the new update command.**

The import statement correctly references the new update command module.

---

`23-23`: **Registered the update command with the CLI program.**

The update command has been properly registered with the CLI program alongside existing commands.

</details>
<details>
<summary>packages/cli/src/commands/update.ts (4)</summary>

`8-13`: **Well-defined command with clear description and options.**

The update command is properly defined with a descriptive name, helpful description, and a dry run option that provides flexibility to users.

---

`14-36`: **Effective package detection and validation logic.**

The implementation correctly:
1. Checks for the existence of package.json
2. Parses the file to extract dependencies
3. Identifies relevant packages (@assistant-ui/* and assistant-stream)
4. Handles the case when no matching packages are found

---

`37-47`: **Comprehensive package manager detection and command building.**

The code properly:
1. Detects the user's package manager (yarn, pnpm, bun, or npm)
2. Builds the appropriate update command for each package manager
3. Formats the command to update all matching packages to their latest versions

---

`48-59`: **Robust execution handling with appropriate user feedback.**

The implementation includes:
1. Clear dry run output when the `--dry` option is used
2. Informative messaging when executing the command
3. Proper error handling for command execution failures
4. Success confirmation upon completion

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T19:10:12Z

Review comments:
diff_hunk: @@ -1,8 +1,46 @@
 "use client";
 
-import { AssistantRuntimeProvider } from "@assistant-ui/react";
+import {
+  AssistantRuntimeProvider,
+  makeAssistantTool,
+} from "@assistant-ui/react";
 import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
 import { Thread } from "@/components/assistant-ui/thread";
+import { z } from "zod";
+
+const MyToolUI = makeAssistantTool({
+  toolName: "my_tool",
+  parameters: z.object({
+    name: z.string(),
+    age: z.number(),
+    nicknames: z.array(z.string()),
+  }),
+  streamCall: async (reader) => {
+    reader.args.streamText("name").pipeTo(
+      new WritableStream({
+        write: (value) => console.log("NAME UPDATE", value),
+      }),
+    );
path: examples/with-ai-sdk/app/assistant.tsx
user: login: greptile-apps[bot]
body: style: These stream handlers only log to console. Need to implement actual functionality or remove debug logging for production.
created_at: 2025-04-18T19:06:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,60 @@
+import { Command } from "commander";
+import fs from "fs";
+import path from "path";
+import chalk from "chalk";
+import { detect } from "detect-package-manager";
+import { sync as spawnSync } from "cross-spawn";
+
+export const update = new Command()
+  .name("update")
+  .description(
+    "Update all '@assistant-ui/*' and 'assistant-stream' packages in package.json to latest versions using your package manager.",
+  )
+  .option("--dry", "Print the package manager command instead of running it.")
+  .action(async (opts) => {
+    const packageJsonPath = path.join(process.cwd(), "package.json");
+    if (!fs.existsSync(packageJsonPath)) {
+      console.error(
+        chalk.red("No package.json found in the current directory."),
+      );
+      process.exit(1);
+    }
+    const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
path: packages/cli/src/commands/update.ts
user: login: Copilot
body: Wrap the JSON.parse call in a try-catch block to gracefully handle malformed package.json files and provide a clear error message.
```suggestion
    let pkg;
    try {
      pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
    } catch (error) {
      console.error(
        chalk.red("Failed to parse package.json. Please ensure it contains valid JSON."),
      );
      process.exit(1);
    }
```
created_at: 2025-04-18T19:06:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,8 +1,46 @@
 "use client";
 
-import { AssistantRuntimeProvider } from "@assistant-ui/react";
+import {
+  AssistantRuntimeProvider,
+  makeAssistantTool,
+} from "@assistant-ui/react";
 import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
 import { Thread } from "@/components/assistant-ui/thread";
+import { z } from "zod";
+
+const MyToolUI = makeAssistantTool({
+  toolName: "my_tool",
+  parameters: z.object({
+    name: z.string(),
+    age: z.number(),
+    nicknames: z.array(z.string()),
+  }),
+  streamCall: async (reader) => {
+    reader.args.streamText("name").pipeTo(
path: examples/with-ai-sdk/app/assistant.tsx
user: login: ellipsis-dev[bot]
body: Consider awaiting the promise returned by `pipeTo` to catch any streaming errors.
created_at: 2025-04-18T19:08:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,60 @@
+import { Command } from "commander";
+import fs from "fs";
+import path from "path";
+import chalk from "chalk";
+import { detect } from "detect-package-manager";
+import { sync as spawnSync } from "cross-spawn";
+
+export const update = new Command()
+  .name("update")
+  .description(
+    "Update all '@assistant-ui/*' and 'assistant-stream' packages in package.json to latest versions using your package manager.",
+  )
+  .option("--dry", "Print the package manager command instead of running it.")
+  .action(async (opts) => {
+    const packageJsonPath = path.join(process.cwd(), "package.json");
+    if (!fs.existsSync(packageJsonPath)) {
+      console.error(
+        chalk.red("No package.json found in the current directory."),
+      );
+      process.exit(1);
+    }
+    const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
path: packages/cli/src/commands/update.ts
user: login: ellipsis-dev[bot]
body: Wrap `JSON.parse` in a `try/catch` to handle corrupted `package.json` files gracefully.
created_at: 2025-04-18T19:08:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,8 +1,46 @@
 "use client";
 
-import { AssistantRuntimeProvider } from "@assistant-ui/react";
+import {
+  AssistantRuntimeProvider,
+  makeAssistantTool,
+} from "@assistant-ui/react";
 import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
 import { Thread } from "@/components/assistant-ui/thread";
+import { z } from "zod";
+
+const MyToolUI = makeAssistantTool({
+  toolName: "my_tool",
+  parameters: z.object({
+    name: z.string(),
+    age: z.number(),
+    nicknames: z.array(z.string()),
+  }),
+  streamCall: async (reader) => {
+    reader.args.streamText("name").pipeTo(
+      new WritableStream({
+        write: (value) => console.log("NAME UPDATE", value),
+      }),
+    );
+
+    const test = await reader.args.get("name");
path: examples/with-ai-sdk/app/assistant.tsx
user: login: ellipsis-dev[bot]
body: Rename `test` and `test2` to more descriptive names to clarify their purpose. Consider removing console logs if they're only for temporary debugging.
created_at: 2025-04-18T19:08:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,8 +1,46 @@
 "use client";
 
-import { AssistantRuntimeProvider } from "@assistant-ui/react";
+import {
+  AssistantRuntimeProvider,
+  makeAssistantTool,
+} from "@assistant-ui/react";
 import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
 import { Thread } from "@/components/assistant-ui/thread";
+import { z } from "zod";
+
+const MyToolUI = makeAssistantTool({
+  toolName: "my_tool",
+  parameters: z.object({
+    name: z.string(),
+    age: z.number(),
+    nicknames: z.array(z.string()),
+  }),
+  streamCall: async (reader) => {
+    reader.args.streamText("name").pipeTo(
+      new WritableStream({
+        write: (value) => console.log("NAME UPDATE", value),
+      }),
+    );
+
+    const test = await reader.args.get("name");
path: examples/with-ai-sdk/app/assistant.tsx
user: login: cubic-dev-ai[bot]
body: Non-descriptive variable names used for retrieved values
created_at: 2025-04-18T19:08:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,8 +1,46 @@
 "use client";
 
-import { AssistantRuntimeProvider } from "@assistant-ui/react";
+import {
+  AssistantRuntimeProvider,
+  makeAssistantTool,
+} from "@assistant-ui/react";
 import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
 import { Thread } from "@/components/assistant-ui/thread";
+import { z } from "zod";
+
+const MyToolUI = makeAssistantTool({
+  toolName: "my_tool",
+  parameters: z.object({
+    name: z.string(),
+    age: z.number(),
+    nicknames: z.array(z.string()),
+  }),
+  streamCall: async (reader) => {
+    reader.args.streamText("name").pipeTo(
+      new WritableStream({
+        write: (value) => console.log("NAME UPDATE", value),
+      }),
+    );
+
+    const test = await reader.args.get("name");
+    console.log(test);
+
+    reader.args.streamValues("age").pipeTo(
+      new WritableStream({
+        write: (value) => console.log("AGE UPDATE", value),
+      }),
+    );
+
+    const test2 = await reader.args.get("age");
+    console.log(test2);
+
+    for await (const nickname of reader.args.forEach("nicknames")) {
+      console.log("NICKNAME", nickname);
+    }
+
+    console.log(await reader.result.get());
+  },
+});
path: examples/with-ai-sdk/app/assistant.tsx
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Well-structured assistant tool implementation.**

The `MyToolUI` tool is well-defined using `makeAssistantTool` with:
- A clear tool name
- Properly validated parameters using zod schema
- A comprehensive `streamCall` handler that demonstrates various streaming capabilities

The handler correctly demonstrates:
1. Streaming text updates for the `name` parameter
2. Fetching current parameter values
3. Streaming numeric values for the `age` parameter
4. Iterating over array values for the `nicknames` parameter
5. Retrieving the final result


Consider adding error handling for the streams and result retrieval to make the example more robust:

```diff
  streamCall: async (reader) => {
+   try {
      reader.args.streamText("name").pipeTo(
        new WritableStream({
          write: (value) => console.log("NAME UPDATE", value),
        }),
      );

      // Rest of the implementation...

      console.log(await reader.result.get());
+   } catch (error) {
+     console.error("Error in tool execution:", error);
+   }
  },
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-18T19:10:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,60 @@
+import { Command } from "commander";
+import fs from "fs";
+import path from "path";
+import chalk from "chalk";
+import { detect } from "detect-package-manager";
+import { sync as spawnSync } from "cross-spawn";
+
path: packages/cli/src/commands/update.ts
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Correct imports for the update command implementation.**

All necessary imports are included for implementing the update command functionality.


Use the Node.js protocol prefix for built-in modules as recommended by static analysis:

```diff
import { Command } from "commander";
-import fs from "fs";
-import path from "path";
+import fs from "node:fs";
+import path from "node:path";
import chalk from "chalk";
import { detect } from "detect-package-manager";
import { sync as spawnSync } from "cross-spawn";
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

`````suggestion
import { Command } from "commander";
import fs from "node:fs";
import path from "node:path";
import chalk from "chalk";
import { detect } from "detect-package-manager";
import { sync as spawnSync } from "cross-spawn";
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.


(lint/style/useNodejsImportProtocol)

---

[error] 3-3: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.


(lint/style/useNodejsImportProtocol)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-18T19:10:12Z
author_association: CONTRIBUTOR

PR comments:
user: login: vercel[bot]
created_at: 2025-04-18T19:05:52Z
body: [vc]: #paXpklCMMbZaR1npNAanarJF1zkwrB037anMH9oawOU=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJhc3Npc3RhbnQtdWkiLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vYXNzaXN0YW50LXVpL2Fzc2lzdGFudC11aS9ESEt4RnNydGpydTFmVnZtTk1EdnFzNVd0dW5UIiwicHJldmlld1VybCI6ImFzc2lzdGFudC11aS1naXQtc2YtYnJhbmNoLTQ4LWFzc2lzdGFudC11aS52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6ImFzc2lzdGFudC11aS1naXQtc2YtYnJhbmNoLTQ4LWFzc2lzdGFudC11aS52ZXJjZWwuYXBwIn0sInJvb3REaXJlY3RvcnkiOiJhcHBzL2RvY3MifV19
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **assistant-ui** | ✅ Ready ([Inspect](https://vercel.com/assistant-ui/assistant-ui/DHKxFsrtjru1fVvmNMDvqs5WtunT)) | [Visit Preview](https://assistant-ui-git-sf-branch-48-assistant-ui.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/assistant-ui-git-sf-branch-48-assistant-ui.vercel.app?via=pr-comment-feedback-link) | Apr 18, 2025 7:11pm |


author_association: NONE
user: login: changeset-bot[bot]
created_at: 2025-04-18T19:05:53Z
body: ###  🦋  Changeset detected

Latest commit: 6ec8ad22dbc86ef49b34a6fa31d55da5f6a9ff88

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 2 packages</summary>

  | Name                | Type  |
| ------------------- | ----- |
| @assistant-ui/react | Patch |
| assistant-ui        | Patch |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/assistant-ui/assistant-ui/new/sf-branch-48?filename=.changeset/selfish-onions-teach.md&value=---%0A%22assistant-ui%22%3A%20patch%0A%22with-ai-sdk%22%3A%20patch%0A---%0A%0Afeat%3A%20assistant-ui%20update%20CLI%20command%0A)


author_association: NONE
user: login: entelligence-ai-pr-reviews[bot]
created_at: 2025-04-18T19:06:05Z
body: LGTM :+1:
author_association: CONTRIBUTOR
user: login: trag-bot[bot]
created_at: 2025-04-18T19:06:17Z
body: ### Pull request summary

- Added a new CLI command to update all `@assistant-ui/*` and `assistant-stream` packages in `package.json` to their latest versions.
- Implemented a tool UI component using `makeAssistantTool` to handle parameters like `name`, `age`, and `nicknames` with streaming capabilities.
- Integrated the new tool UI component into the existing Assistant component for enhanced functionality.
- Updated the `package.json` to include the `semver` package for version management.
- Added type definitions for `semver` to improve TypeScript support.
- Enhanced the command-line interface to support a dry run option, allowing users to preview the update command without executing it.
- Improved error handling for scenarios where no `package.json` is found or no matching packages are available for update.
- Updated the lock file to reflect the addition of the `semver` package and its dependencies.
author_association: NONE
user: login: promptless[bot]
created_at: 2025-04-18T19:06:38Z
body: 📝 Documentation updates detected! You can review documentation updates [here](https://app.gopromptless.ai/change-history/28850270-ce63-4226-a7b2-388cc66ef8dd)
author_association: CONTRIBUTOR
user: login: coderabbitai[bot]
created_at: 2025-04-18T19:10:08Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

The changes introduce a new assistant tool, `MyToolUI`, in the example application by utilizing the `makeAssistantTool` function from the `@assistant-ui/react` package. This tool is configured with a `zod`-validated schema for its parameters and implements a `streamCall` handler to process streamed input arguments, logging updates and iterating over array inputs. The `MyToolUI` component is rendered within the `AssistantRuntimeProvider` alongside the existing `Thread` component in the main assistant UI.

In the CLI package, the `semver` library and its TypeScript type definitions are added as dependencies. A new CLI command, `update`, is implemented using the `commander` library. This command scans the project's `package.json` for dependencies matching specific patterns, detects the user's package manager, and constructs the appropriate update command. It supports a `--dry` run option and handles scenarios where no matching packages are found or when `package.json` is missing. The new `update` command is registered with the CLI program and is available alongside existing commands.

<!-- walkthrough_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!WARNING]
> There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
> 
> <details>
> <summary>🔧 ESLint</summary>
> 
> > If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
> 
> <details>
> <summary>examples/with-ai-sdk/app/assistant.tsx</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.24.0
> 
> ESLint couldn't find the config "next/core-web-vitals" to extend from. Please check that the name of the config is correct.
> 
> The config "next/core-web-vitals" was referenced from the config file in "".
> 
> If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.
> 
> 
> </details>
> 
> <details>
> <summary>packages/cli/src/commands/update.ts</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.24.0
> 
> ESLint couldn't find the config "next/core-web-vitals" to extend from. Please check that the name of the config is correct.
> 
> The config "next/core-web-vitals" was referenced from the config file in "".
> 
> If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.
> 
> 
> </details>
> 
> <details>
> <summary>packages/cli/src/index.ts</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.24.0
> 
> ESLint couldn't find the config "next/core-web-vitals" to extend from. Please check that the name of the config is correct.
> 
> The config "next/core-web-vitals" was referenced from the config file in "".
> 
> If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.
> 
> 
> </details>
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=assistant-ui/assistant-ui&utm_content=1859):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR