Skip to content
Open
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
10 changes: 10 additions & 0 deletions typescript-sdk/apps/client-cli-example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,30 @@
"clean": "rm -rf dist"
},
"dependencies": {
"@ag-ui/agno": "workspace:*",
"@ag-ui/client": "workspace:*",
"@ag-ui/core": "workspace:*",
"@ag-ui/crewai": "workspace:*",
"@ag-ui/langgraph": "workspace:*",
"@ag-ui/llamaindex": "workspace:*",
"@ag-ui/mastra": "workspace:*",
"@ag-ui/pydantic-ai": "workspace:*",
"@ag-ui/vercel-ai-sdk": "workspace:*",
"@ai-sdk/openai": "^1.3.22",
"@mastra/client-js": "^0.10.9",
"@mastra/core": "^0.10.10",
"@mastra/libsql": "^0.11.0",
"@mastra/loggers": "^0.10.3",
"@mastra/memory": "^0.11.1",
"inquirer": "^12.6.3",
"open": "^10.1.2",
"yargs": "^18.0.0",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/inquirer": "^9.0.8",
"@types/node": "^20",
"@types/yargs": "^17.0.33",
"tsx": "^4.7.0",
"typescript": "^5"
}
Expand Down
60 changes: 60 additions & 0 deletions typescript-sdk/apps/client-cli-example/src/agents/loadAgent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { agentRegistry } from "./registry";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import inquirer from "inquirer";

export async function loadAgentFromCLI() {
// 1. Parse CLI args
const argv = yargs(hideBin(process.argv))
.option("agent", { type: "string", describe: "Agent/framework to use" })
// Do not add all possible config fields as yargs options; we'll check argv directly
.help()
.parseSync();

// 2. Determine agent type
let agentType = argv.agent;
if (!agentType) {
agentType = (
await inquirer.prompt([
{
type: "list",
name: "agentType",
message: "Select an agent/framework:",
choices: Object.keys(agentRegistry).map((key) => ({
name: agentRegistry[key].label,
value: key,
})),
},
])
).agentType;
}

const agentEntry = agentRegistry[agentType as keyof typeof agentRegistry];
if (!agentEntry) throw new Error(`Unknown agent type: ${agentType}`);

// 3. Gather config (from CLI args or prompt for missing)
const config: Record<string, any> = {};
for (const field of agentEntry.required) {
if (argv[field]) {
config[field] = argv[field];
} else {
config[field] = (
await inquirer.prompt([
{ type: "input", name: field, message: `Enter value for ${field}:` },
])
)[field];
}
}
// Optionally gather optional fields if provided via CLI
if (agentEntry.optional) {
for (const field of agentEntry.optional) {
if (argv[field]) {
config[field] = argv[field];
}
}
}

// 4. Instantiate agent
const agent = new agentEntry.AgentClass(config);
return agent;
}
68 changes: 68 additions & 0 deletions typescript-sdk/apps/client-cli-example/src/agents/registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { LangGraphAgent } from "@ag-ui/langgraph";
import { CrewAIAgent } from "@ag-ui/crewai";
import { AgnoAgent } from "@ag-ui/agno";
import { LlamaIndexAgent } from "@ag-ui/llamaindex";
import { MastraAgent } from "@ag-ui/mastra";
import { PydanticAIAgent } from "@ag-ui/pydantic-ai";
// import { VercelAISDKAgent } from "@ag-ui/vercel-ai-sdk";

// Type for agent registry entries
export interface AgentRegistryEntry {
label: string;
AgentClass: any;
required: string[];
optional?: string[];
description: string;
}

export const agentRegistry: Record<string, AgentRegistryEntry> = {
langgraph: {
label: "LangGraph",
AgentClass: LangGraphAgent,
required: ["graphId", "deploymentUrl"],
optional: ["langsmithApiKey"],
description: "Connects to a LangGraph deployment.",
},
crewai: {
label: "CrewAI",
AgentClass: CrewAIAgent,
required: ["url"],
optional: ["headers"],
description: "Connects to a CrewAI FastAPI server.",
},
agno: {
label: "Agno",
AgentClass: AgnoAgent,
required: ["url"],
optional: ["headers"],
description: "Connects to an Agno agent server.",
},
llamaindex: {
label: "LlamaIndex",
AgentClass: LlamaIndexAgent,
required: ["url"],
optional: ["headers"],
description: "Connects to a LlamaIndex FastAPI server.",
},
mastra: {
label: "Mastra",
AgentClass: MastraAgent,
required: ["agent"],
optional: ["resourceId"],
description: "Connects to a local or remote Mastra agent.",
},
pydanticai: {
label: "PydanticAI",
AgentClass: PydanticAIAgent,
required: ["model"],
optional: ["maxSteps", "toolChoice"],
description: "Connects to a PydanticAI model.",
},
// vercelai: {
// label: "Vercel AI SDK",
// AgentClass: VercelAISDKAgent,
// required: ["model"],
// optional: ["maxSteps", "toolChoice"],
// description: "Connects to a Vercel AI SDK model.",
// },
};
18 changes: 10 additions & 8 deletions typescript-sdk/apps/client-cli-example/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import * as readline from "readline";
import { agent } from "./agent";
import { randomUUID } from "node:crypto";
import { loadAgentFromCLI } from "./agents/loadAgent";
import { AbstractAgent } from "@ag-ui/client";

const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
async function chatLoop(agent: AbstractAgent) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

async function chatLoop() {
console.log("🤖 AG-UI chat started! Type your messages and press Enter. Press Ctrl+D to quit.\n");

return new Promise<void>((resolve) => {
Expand Down Expand Up @@ -75,7 +76,8 @@ async function chatLoop() {
}

async function main() {
await chatLoop();
const agent = await loadAgentFromCLI();
await chatLoop(agent);
}

main().catch(console.error);
main();
Loading