@aigne/cli 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.8.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.7.0...cli-v1.8.0) (2025-04-27)
4
+
5
+
6
+ ### Features
7
+
8
+ * support TeamAgent and finalize API naming ([#91](https://github.com/AIGNE-io/aigne-framework/issues/91)) ([033d1b6](https://github.com/AIGNE-io/aigne-framework/commit/033d1b6a7dc5460807476abb35a413ba89a2a664))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * upgrade to streamable api for serve mcp command ([#98](https://github.com/AIGNE-io/aigne-framework/issues/98)) ([ae32bda](https://github.com/AIGNE-io/aigne-framework/commit/ae32bda20e57c2a2eb8b49fad034b0b2a5ebb15e))
14
+
15
+
16
+ ### Dependencies
17
+
18
+ * The following workspace dependencies were updated
19
+ * dependencies
20
+ * @aigne/core bumped to 1.12.0
21
+
3
22
  ## [1.7.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.6.0...cli-v1.7.0) (2025-04-23)
4
23
 
5
24
 
@@ -1,5 +1,5 @@
1
1
  import { Command } from "commander";
2
- import pkg from "../../package.json" with { type: "json" };
2
+ import { AIGNE_CLI_VERSION } from "../constants.js";
3
3
  import { asciiLogo } from "../utils/ascii-logo.js";
4
4
  import { createCreateCommand } from "./create.js";
5
5
  import { createRunCommand } from "./run.js";
@@ -10,7 +10,7 @@ export function createAIGNECommand() {
10
10
  return new Command()
11
11
  .name("aigne")
12
12
  .description("CLI for AIGNE framework")
13
- .version(pkg.version)
13
+ .version(AIGNE_CLI_VERSION)
14
14
  .addCommand(createRunCommand())
15
15
  .addCommand(createTestCommand())
16
16
  .addCommand(createCreateCommand())
@@ -2,7 +2,7 @@ import assert from "node:assert";
2
2
  import { cp, mkdir, rm } from "node:fs/promises";
3
3
  import { homedir } from "node:os";
4
4
  import { isAbsolute, join, resolve } from "node:path";
5
- import { ExecutionEngine } from "@aigne/core";
5
+ import { AIGNE } from "@aigne/core";
6
6
  import { loadModel } from "@aigne/core/loader/index.js";
7
7
  import { logger } from "@aigne/core/utils/logger.js";
8
8
  import { isNonNullable } from "@aigne/core/utils/type-utils.js";
@@ -24,7 +24,7 @@ export function createRunCommand() {
24
24
  if (options.verbose)
25
25
  logger.enable("*");
26
26
  const { downloadDir, dir } = prepareDirs(path, options);
27
- const { engine, agent } = await new Listr([
27
+ const { aigne, agent } = await new Listr([
28
28
  {
29
29
  title: "Prepare environment",
30
30
  task: (_, task) => {
@@ -43,30 +43,30 @@ export function createRunCommand() {
43
43
  },
44
44
  },
45
45
  {
46
- title: "Initialize execution engine",
46
+ title: "Initialize AIGNE",
47
47
  task: async (ctx) => {
48
- const engine = await runEngine(dir, options);
49
- ctx.engine = engine;
48
+ const aigne = await loadAIGNE(dir, options);
49
+ ctx.aigne = aigne;
50
50
  },
51
51
  },
52
52
  {
53
53
  task: (ctx) => {
54
- const { engine } = ctx;
55
- assert(engine);
54
+ const { aigne } = ctx;
55
+ assert(aigne);
56
56
  let agent;
57
57
  if (options.agent) {
58
- agent = engine.agents[options.agent];
58
+ agent = aigne.agents[options.agent];
59
59
  if (!agent) {
60
60
  console.error(`Agent "${options.agent}" not found in ${path}`);
61
61
  console.log("Available agents:");
62
- for (const agent of engine.agents) {
62
+ for (const agent of aigne.agents) {
63
63
  console.log(`- ${agent.name}`);
64
64
  }
65
65
  throw new Error(`Agent "${options.agent}" not found in ${path}`);
66
66
  }
67
67
  }
68
68
  else {
69
- agent = engine.agents[0];
69
+ agent = aigne.agents[0];
70
70
  if (!agent)
71
71
  throw new Error(`No agents found in ${path}`);
72
72
  }
@@ -79,23 +79,23 @@ export function createRunCommand() {
79
79
  timer: PRESET_TIMER,
80
80
  },
81
81
  }).run();
82
- assert(engine);
82
+ assert(aigne);
83
83
  assert(agent);
84
- const user = engine.call(agent);
84
+ const user = aigne.invoke(agent);
85
85
  await runChatLoopInTerminal(user);
86
- await engine.shutdown();
86
+ await aigne.shutdown();
87
87
  })
88
88
  .showHelpAfterError(true)
89
89
  .showSuggestionAfterError(true);
90
90
  }
91
- async function runEngine(path, options) {
91
+ async function loadAIGNE(path, options) {
92
92
  if (options.modelName && !options.modelProvider) {
93
93
  throw new Error("please specify --model-provider when using the --model-name option");
94
94
  }
95
95
  const model = options.modelProvider
96
96
  ? await loadModel({ provider: options.modelProvider, name: options.modelName })
97
97
  : undefined;
98
- return await ExecutionEngine.load({ path, model });
98
+ return await AIGNE.load({ path, model });
99
99
  }
100
100
  async function downloadPackage(url, downloadDir) {
101
101
  await rm(downloadDir, { recursive: true, force: true });
@@ -1,5 +1,5 @@
1
1
  import { isAbsolute, resolve } from "node:path";
2
- import { ExecutionEngine } from "@aigne/core";
2
+ import { AIGNE } from "@aigne/core";
3
3
  import { tryOrThrow } from "@aigne/core/utils/type-utils.js";
4
4
  import { Command } from "commander";
5
5
  import { serveMCPServer } from "../utils/serve-mcp.js";
@@ -17,15 +17,23 @@ export function createServeCommand() {
17
17
  .description("Serve the agents in the specified directory as a MCP server")
18
18
  .argument("[path]", "Path to the agents directory", ".")
19
19
  .option("--mcp", "Serve the agents as a MCP server")
20
+ .option("--host <host>", "Host to run the MCP server on, use 0.0.0.0 to publicly expose the server", "localhost")
20
21
  .option("--port <port>", "Port to run the MCP server on", (s) => Number.parseInt(s))
22
+ .option("--pathname <pathname>", "Pathname to the service", "/mcp")
21
23
  .action(async (path, options) => {
22
24
  const absolutePath = isAbsolute(path) ? path : resolve(process.cwd(), path);
23
25
  const port = options.port || DEFAULT_PORT();
24
- const engine = await ExecutionEngine.load({ path: absolutePath });
26
+ const aigne = await AIGNE.load({ path: absolutePath });
25
27
  if (options.mcp)
26
- await serveMCPServer({ engine, port });
28
+ await serveMCPServer({
29
+ aigne,
30
+ host: options.host,
31
+ port,
32
+ pathname: options.pathname,
33
+ });
27
34
  else
28
35
  throw new Error("Default server is not supported yet. Please use --mcp option");
36
+ console.log(`MCP server is running on http://${options.host}:${port}${options.pathname}`);
29
37
  })
30
38
  .showHelpAfterError(true)
31
39
  .showSuggestionAfterError(true);
@@ -0,0 +1 @@
1
+ export declare const AIGNE_CLI_VERSION: string;
@@ -0,0 +1,2 @@
1
+ import pkg from "../package.json" with { type: "json" };
2
+ export const AIGNE_CLI_VERSION = pkg.version;
@@ -1,5 +1,4 @@
1
- import { type Agent, type Context, MESSAGE_KEY, type Message } from "@aigne/core";
2
- import type { ContextUsage } from "@aigne/core/execution-engine/usage";
1
+ import { type Agent, type Context, type ContextUsage, MESSAGE_KEY, type Message } from "@aigne/core";
3
2
  import { type DefaultRenderer, Listr, type ListrRenderer, type ListrTaskWrapper } from "@aigne/listr2";
4
3
  import { promiseWithResolvers } from "../utils/promise-with-resolvers.js";
5
4
  export interface TerminalTracerOptions {
@@ -99,7 +99,7 @@ export class TerminalTracer {
99
99
  context.on("agentSucceed", onAgentSucceed);
100
100
  context.on("agentFailed", onAgentFailed);
101
101
  try {
102
- const stream = await context.call(agent, input, { streaming: true });
102
+ const stream = await context.invoke(agent, input, { streaming: true });
103
103
  const result = await listr.run(stream);
104
104
  return { result, context };
105
105
  }
@@ -129,7 +129,7 @@ export class TerminalTracer {
129
129
  return chalk.grey(`[${parseDuration(duration)}]`);
130
130
  }
131
131
  formatTaskTitle(agent, { task, usage, time } = {}) {
132
- let title = `call agent ${agent.name}`;
132
+ let title = `invoke agent ${agent.name}`;
133
133
  if (usage && task?.usage)
134
134
  title += ` ${this.formatTokenUsage(task.usage, task.extraTitleMetadata)}`;
135
135
  if (time && task?.startTime && task.endTime)
@@ -43,15 +43,15 @@ async function loadAgentV1Package(path) {
43
43
  return definition;
44
44
  }
45
45
  function assistantToAigneV2(agent, project) {
46
- const converter = RUNNABLE_MAP[agent.type];
46
+ const converter = AGENT_MAP[agent.type];
47
47
  if (!converter)
48
- throw new Error(`Unsupported runnable type: ${agent.type}`);
48
+ throw new Error(`Unsupported agent type: ${agent.type}`);
49
49
  return converter(agent, project);
50
50
  }
51
- const RUNNABLE_MAP = {
51
+ const AGENT_MAP = {
52
52
  prompt: (agent) => {
53
53
  if (agent.type !== "prompt")
54
- throw new Error(`Expected runnable type 'prompt', but got '${agent.type}'`);
54
+ throw new Error(`Expected agent type 'prompt', but got '${agent.type}'`);
55
55
  const obj = {
56
56
  name: agent.name || agent.id,
57
57
  description: agent.description,
@@ -68,7 +68,7 @@ const RUNNABLE_MAP = {
68
68
  },
69
69
  function: async (agent) => {
70
70
  if (agent.type !== "function")
71
- throw new Error(`Expected runnable type 'function', but got '${agent.type}'`);
71
+ throw new Error(`Expected agent type 'function', but got '${agent.type}'`);
72
72
  const inputNames = agent.parameters?.map((i) => i.key).filter(Boolean) ?? [];
73
73
  return {
74
74
  content: await formatCode(`\
@@ -88,7 +88,7 @@ agent.output_schema = ${JSON.stringify(convertOutputSchema(agent))};
88
88
  },
89
89
  router: (agent, project) => {
90
90
  if (agent.type !== "router")
91
- throw new Error(`Expected runnable type 'router', but got '${agent.type}'`);
91
+ throw new Error(`Expected agent type 'router', but got '${agent.type}'`);
92
92
  return {
93
93
  content: stringify({
94
94
  name: agent.name || agent.id,
@@ -96,7 +96,7 @@ agent.output_schema = ${JSON.stringify(convertOutputSchema(agent))};
96
96
  instructions: agent.prompt,
97
97
  input_schema: convertInputSchema(agent),
98
98
  output_schema: convertOutputSchema(agent),
99
- tools: agent.routes?.map((i) => {
99
+ skills: agent.routes?.map((i) => {
100
100
  const tool = project.agents.find((j) => j.id === i.id);
101
101
  if (!tool)
102
102
  throw new Error(`Tool ${i.id} not found in project definition`);
@@ -1,5 +1,9 @@
1
- import { type ExecutionEngine } from "@aigne/core";
2
- export declare function serveMCPServer({ engine, port }: {
3
- engine: ExecutionEngine;
1
+ import { type AIGNE } from "@aigne/core";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ export declare function serveMCPServer({ pathname, aigne, host, port, }: {
4
+ pathname?: string;
5
+ aigne: AIGNE;
6
+ host?: string;
4
7
  port: number;
5
8
  }): Promise<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>>;
9
+ export declare function createMcpServer(aigne: AIGNE): McpServer;
@@ -1,23 +1,83 @@
1
1
  import { getMessage } from "@aigne/core";
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
4
- import express from "express";
3
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
+ import express, { Router, json } from "express";
5
5
  import { ZodObject } from "zod";
6
+ import { AIGNE_CLI_VERSION } from "../constants.js";
6
7
  import { promiseWithResolvers } from "./promise-with-resolvers.js";
7
- export async function serveMCPServer({ engine, port }) {
8
+ export async function serveMCPServer({ pathname = "/mcp", aigne, host = "localhost", port, }) {
9
+ const app = express();
10
+ app.use(json());
11
+ const router = Router();
12
+ app.use(router);
13
+ router.post(pathname, async (req, res) => {
14
+ try {
15
+ const server = createMcpServer(aigne);
16
+ const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
17
+ await server.connect(transport);
18
+ await transport.handleRequest(req, res, req.body);
19
+ res.on("close", async () => {
20
+ await transport.close();
21
+ await server.close();
22
+ });
23
+ }
24
+ catch (error) {
25
+ console.error("Error handling MCP request:", error);
26
+ if (!res.headersSent) {
27
+ res.status(500).json({
28
+ jsonrpc: "2.0",
29
+ error: {
30
+ code: -32603,
31
+ message: error.message,
32
+ },
33
+ id: null,
34
+ });
35
+ }
36
+ }
37
+ });
38
+ router.get(pathname, async (_, res) => {
39
+ res.writeHead(405).end(JSON.stringify({
40
+ jsonrpc: "2.0",
41
+ error: {
42
+ code: -32000,
43
+ message: "Method not allowed.",
44
+ },
45
+ id: null,
46
+ }));
47
+ });
48
+ router.delete(pathname, async (_, res) => {
49
+ res.writeHead(405).end(JSON.stringify({
50
+ jsonrpc: "2.0",
51
+ error: {
52
+ code: -32000,
53
+ message: "Method not allowed.",
54
+ },
55
+ id: null,
56
+ }));
57
+ });
58
+ const { promise, resolve, reject } = promiseWithResolvers();
59
+ const httpServer = app.listen(port, host, (error) => {
60
+ if (error)
61
+ reject(error);
62
+ resolve();
63
+ });
64
+ await promise;
65
+ return httpServer;
66
+ }
67
+ export function createMcpServer(aigne) {
8
68
  const server = new McpServer({
9
- name: engine.name || "aigne-mcp-server",
10
- version: "1.0.0",
69
+ name: aigne.name || "aigne-mcp-server",
70
+ version: AIGNE_CLI_VERSION,
11
71
  }, {
12
72
  capabilities: { tools: {} },
13
- instructions: engine.description,
73
+ instructions: aigne.description,
14
74
  });
15
- for (const agent of engine.agents) {
75
+ for (const agent of aigne.agents) {
16
76
  const schema = agent.inputSchema;
17
77
  if (!(schema instanceof ZodObject))
18
78
  throw new Error("Agent input schema must be a ZodObject");
19
79
  server.tool(agent.name, agent.description || "", schema.shape, async (input) => {
20
- const result = await engine.call(agent, input);
80
+ const result = await aigne.invoke(agent, input);
21
81
  return {
22
82
  content: [
23
83
  {
@@ -28,45 +88,5 @@ export async function serveMCPServer({ engine, port }) {
28
88
  };
29
89
  });
30
90
  }
31
- const app = express();
32
- const transports = {};
33
- app.get("/sse", async (req, res) => {
34
- const transport = new SSEServerTransport("/messages", res);
35
- transports[transport.sessionId] = transport;
36
- req.on("close", () => {
37
- delete transports[transport.sessionId];
38
- });
39
- await server.connect(transport);
40
- });
41
- app.post("/messages", async (req, res) => {
42
- const sessionId = req.query.sessionId;
43
- const transport = transports[sessionId];
44
- if (transport) {
45
- await transport.handlePostMessage(req, res);
46
- }
47
- else {
48
- throw new HttpError(400, "No transport found for sessionId");
49
- }
50
- });
51
- app.use(((error, _req, res, _next) => {
52
- console.error("handle route error", { error });
53
- res
54
- .status(error instanceof HttpError ? error.status : 500)
55
- .json({ error: { message: error.message } });
56
- }));
57
- const { promise, resolve, reject } = promiseWithResolvers();
58
- const httpServer = app.listen(port, (error) => {
59
- if (error)
60
- reject(error);
61
- resolve();
62
- });
63
- await promise;
64
- return httpServer;
65
- }
66
- class HttpError extends Error {
67
- status;
68
- constructor(status, message) {
69
- super(message);
70
- this.status = status;
71
- }
91
+ return server;
72
92
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/cli",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "cli for AIGNE framework",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -50,7 +50,7 @@
50
50
  "pretty-error": "^4.0.0",
51
51
  "tar": "^7.4.3",
52
52
  "zod": "^3.24.2",
53
- "@aigne/core": "^1.11.0"
53
+ "@aigne/core": "^1.12.0"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/archiver": "^6.0.3",
@@ -5,7 +5,7 @@ This is the default project template for the Aigne framework, providing a basic
5
5
  ## Template Structure
6
6
 
7
7
  - `aigne.yaml` - Project configuration file that defines the chat model used and references to agents
8
- - `chat.yaml` - Chat agent configuration, including agent instructions and tools used
8
+ - `chat.yaml` - Chat agent configuration, including agent instructions and skills used
9
9
  - `sandbox.js` - JavaScript code execution tool for running JavaScript code within conversations
10
10
  - `sandbox.test.js` - Test file to verify the functionality of the code execution tool
11
11
 
@@ -3,8 +3,6 @@ description: Chat agent
3
3
  instructions: |
4
4
  You are a helpful assistant that can answer questions and provide information on a wide range of topics.
5
5
  Your goal is to assist users in finding the information they need and to engage in friendly conversation.
6
- memory:
7
- subscribeTopic:
8
- - chat
6
+ memory: true
9
7
  tools:
10
8
  - sandbox.js