Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion apps/client-cli-example/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,51 @@
# AG-UI CLI
# AG-UI CLI Example

A command-line chat interface demonstrating the AG-UI client with a Mastra agent. This example shows how to build an interactive CLI application that streams agent responses and tool calls in real-time.

## Features

- Interactive chat loop with streaming responses
- Real-time tool call visualization (weather and browser tools)
- Message history persistence using LibSQL
- Built with `@ag-ui/client` and `@ag-ui/mastra`

## Prerequisites

- Node.js 22.13.0 or later
- OpenAI API key

## Setup

1. Install dependencies from the repository root:

```bash
pnpm install
```

2. Set your OpenAI API key:
```bash
export OPENAI_API_KEY=your_api_key_here
```

## Usage

Run the CLI:

```bash
pnpm start
```

Try these example prompts:

- "What's the weather in San Francisco?"
- "Browse https://example.com"

Press `Ctrl+D` to quit.

## How It Works

This example uses:

- **MastraAgent**: Wraps a Mastra agent with AG-UI protocol support
- **Event Handlers**: Streams text deltas, tool calls, and results to the console
- **Memory**: Persists conversation history in a local SQLite database
13 changes: 6 additions & 7 deletions apps/client-cli-example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@
"@ag-ui/client": "workspace:*",
"@ag-ui/core": "workspace:*",
"@ag-ui/mastra": "workspace:*",
"@ai-sdk/openai": "1.3.22",
"@mastra/client-js": "0.10.18",
"@mastra/core": "0.12.1",
"@mastra/libsql": "0.12.0",
"@mastra/loggers": "0.10.5",
"@mastra/memory": "0.12.0",
"@mastra/client-js": "1.0.0-beta.2",
"@mastra/core": "1.0.0-beta.2",
"@mastra/libsql": "1.0.0-beta.0",
"@mastra/loggers": "1.0.0-beta.0",
"@mastra/memory": "1.0.0-beta.0",
"open": "^10.1.2",
"zod": "^3.22.4"
"zod": "^4.1.12"
},
"devDependencies": {
"@types/node": "^20",
Expand Down
6 changes: 2 additions & 4 deletions apps/client-cli-example/src/agent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { openai } from "@ai-sdk/openai";
import { Agent } from "@mastra/core/agent";
import { MastraAgent } from "@ag-ui/mastra";
import { Memory } from "@mastra/memory";
Expand All @@ -7,7 +6,6 @@ import { weatherTool } from "./tools/weather.tool";
import { browserTool } from "./tools/browser.tool";

export const agent = new MastraAgent({
// @ts-ignore
agent: new Agent({
name: "AG-UI Agent",
instructions: `
Expand All @@ -26,13 +24,13 @@ export const agent = new MastraAgent({
Use the browserTool to browse the web.

`,
model: openai("gpt-4o-mini"),
model: "openai/gpt-4o-mini",
Copy link
Author

Choose a reason for hiding this comment

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

Mastra now has its own model router so we can remove AI SDK usage

tools: { weatherTool, browserTool },
memory: new Memory({
storage: new LibSQLStore({
id: "mastra-cli-example-db",
Copy link
Author

Choose a reason for hiding this comment

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

url: "file:./mastra.db",
}),
}),
}),
threadId: "1",
});
2 changes: 1 addition & 1 deletion apps/client-cli-example/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as readline from "readline";
import { agent } from "./agent";
import { randomUUID } from "@ag-ui/client";
import { agent } from "./agent";

const rl = readline.createInterface({
input: process.stdin,
Expand Down
6 changes: 3 additions & 3 deletions apps/client-cli-example/src/tools/browser.tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export const browserTool = createTool({
url: z.string().describe("URL to browse"),
}),
outputSchema: z.string(),
execute: async ({ context }) => {
open(context.url);
return `Browsed ${context.url}`;
execute: async (inputData) => {
Copy link
Author

Choose a reason for hiding this comment

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

open(inputData.url);
return `Browsed ${inputData.url}`;
},
});
4 changes: 2 additions & 2 deletions apps/client-cli-example/src/tools/weather.tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export const weatherTool = createTool({
conditions: z.string(),
location: z.string(),
}),
execute: async ({ context }) => {
return await getWeather(context.location);
execute: async (inputData) => {
return await getWeather(inputData.location);
},
});

Expand Down
3 changes: 3 additions & 0 deletions apps/dojo/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,6 @@ dist
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
.vite/

# Mastra files
.mastra
17 changes: 9 additions & 8 deletions apps/dojo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@
"@copilotkit/runtime": "1.10.6",
"@copilotkit/runtime-client-gql": "1.10.6",
"@copilotkit/shared": "1.10.6",
"@copilotkitnext/agent": "0.0.19-alpha.0",
"@copilotkitnext/react": "0.0.19-alpha.0",
"@copilotkitnext/runtime": "0.0.19-alpha.0",
"@copilotkitnext/agent": "0.0.19-alpha.0",
"@mastra/client-js": "^0.15.2",
"@mastra/core": "^0.20.2",
"@mastra/dynamodb": "^0.15.6",
"@mastra/libsql": "^0.15.1",
"@mastra/loggers": "^0.10.15",
"@mastra/memory": "^0.15.6",
"@mastra/client-js": "1.0.0-beta.2",
"@mastra/core": "1.0.0-beta.2",
"@mastra/dynamodb": "1.0.0-beta.0",
"@mastra/libsql": "1.0.0-beta.0",
"@mastra/loggers": "1.0.0-beta.0",
"@mastra/memory": "1.0.0-beta.0",
"@mdx-js/loader": "^3.1.0",
"@mdx-js/mdx": "^3.1.0",
"@mdx-js/react": "^3.1.0",
Expand Down Expand Up @@ -79,7 +79,7 @@
"tailwindcss-animate": "^1.0.7",
"untruncate-json": "^0.0.1",
"uuid": "^11.1.0",
"zod": "^3.25.67"
"zod": "^4.1.12"
},
"peerDependencies": {
"@ag-ui/client": "workspace:*",
Expand All @@ -100,6 +100,7 @@
"concurrently": "^9.2.0",
"eslint": "^9",
"eslint-config-next": "15.2.1",
"mastra": "1.0.0-beta.1",
"tailwindcss": "^4",
"tsx": "^4.7.0",
"typescript": "^5",
Expand Down
3 changes: 1 addition & 2 deletions apps/dojo/src/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { ServerStarterAgent } from "@ag-ui/server-starter";
import { ServerStarterAllFeaturesAgent } from "@ag-ui/server-starter-all-features";
import { MastraClient } from "@mastra/client-js";
import { MastraAgent } from "@ag-ui/mastra";
import { VercelAISDKAgent } from "@ag-ui/vercel-ai-sdk";
import { openai } from "@ai-sdk/openai";
import { LangGraphAgent, LangGraphHttpAgent } from "@ag-ui/langgraph";
import { AgnoAgent } from "@ag-ui/agno";
import { LlamaIndexAgent } from "@ag-ui/llamaindex";
Expand Down Expand Up @@ -119,6 +117,7 @@ export const agentsIntegrations: AgentIntegrationConfig[] = [
},
},
{
// To use this, run "pnpm mastra:dev" in a separate terminal window
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't believe this is valid. I'm pretty sure the mastra:dev script would run the mastra-agent-local agent listed below, but I'm not entirely sure since that's whats bundled into the dojo (and not listed in the exports). This script entry's existence may be entirely invalid.

Regardless, the agent with id mastra is actually located elsewhere in the repo, in integrations/mastra/typescript/examples

Copy link
Author

Choose a reason for hiding this comment

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

As I understand it the local agent one imports the mastra class, the remote one initializes a MastraClient which needs an URL. I got it working like that so that’s why I added the comment

id: "mastra",
agents: async () => {
const mastraClient = new MastraClient({
Expand Down
24 changes: 13 additions & 11 deletions apps/dojo/src/mastra/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { openai } from "@ai-sdk/openai";
import { Agent } from "@mastra/core/agent";
import { Memory } from "@mastra/memory";
import { LibSQLStore } from "@mastra/libsql";
import { DynamoDBStore } from "@mastra/dynamodb";

import { createStep, createWorkflow, Mastra } from "@mastra/core";
import { createTool } from "@mastra/core";
import { Mastra } from "@mastra/core";
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
import { weatherTool } from "./tools";

Expand All @@ -14,11 +12,15 @@ function getStorage(): LibSQLStore | DynamoDBStore {
return new DynamoDBStore({
name: "dynamodb",
config: {
id: "storage-dynamodb",
tableName: process.env.DYNAMODB_TABLE_NAME,
},
});
} else {
return new LibSQLStore({ url: "file::memory:" });
return new LibSQLStore({
id: "storage-memory",
url: "file::memory:"
});
}
}

Expand All @@ -36,7 +38,7 @@ export const mastra = new Mastra({
- Include relevant details like humidity, wind conditions, and precipitation
- Keep responses concise but informative
`,
model: openai("gpt-4o"),
model: "openai/gpt-4o",
tools: { get_weather: weatherTool },
memory: new Memory({
storage: getStorage(),
Expand All @@ -51,7 +53,7 @@ export const mastra = new Mastra({
}),
}),
backend_tool_rendering: new Agent({
name: "Weather Agent",
name: "backend_tool_rendering",
instructions: `
You are a helpful weather assistant that provides accurate weather information.

Expand All @@ -64,7 +66,7 @@ export const mastra = new Mastra({

Use the weatherTool to fetch current weather data.
`,
model: openai("gpt-4o-mini"),
model: "openai/gpt-4o-mini",
tools: { get_weather: weatherTool },
memory: new Memory({
storage: getStorage(),
Expand All @@ -84,7 +86,7 @@ export const mastra = new Mastra({

If you have just created or modified the recipe, just answer in one sentence what you did. dont describe the recipe, just say what you did. Do not mention "working memory", "memory", or "state" in your answer.
`,
model: openai("gpt-4o"),
model: "openai/gpt-4o",
memory: new Memory({
storage: getStorage(),
options: {
Expand Down Expand Up @@ -143,7 +145,7 @@ export const mastra = new Mastra({
instructions: `
You are a helpful assistant for creating haikus.
`,
model: openai("gpt-4o"),
model: "openai/gpt-4o",
tools: {
generate_haiku: createTool({
id: "generate_haiku",
Expand All @@ -158,7 +160,7 @@ export const mastra = new Mastra({
.describe("An array of three lines of the haiku in English"),
}),
outputSchema: z.string(),
execute: async ({ context }) => {
execute: async () => {
return "Haiku generated.";
},
}),
Expand Down
4 changes: 2 additions & 2 deletions apps/dojo/src/mastra/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ export const weatherTool = createTool({
conditions: z.string(),
city: z.string(),
}),
execute: async ({ context }) => {
return await getWeather(context.location);
execute: async (inputData) => {
return await getWeather(inputData.location);
},
});

Expand Down
1 change: 1 addition & 0 deletions integrations/mastra/typescript/examples/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
OPENAI_API_KEY=""
Loading