@aigne/cli 1.26.1-1 → 1.27.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 +20 -0
- package/dist/cli.js +1 -2
- package/dist/commands/aigne.d.ts +2 -2
- package/dist/commands/aigne.js +12 -17
- package/dist/commands/connect.d.ts +2 -6
- package/dist/commands/connect.js +28 -33
- package/dist/commands/create.d.ts +2 -6
- package/dist/commands/create.js +58 -62
- package/dist/commands/observe.d.ts +2 -7
- package/dist/commands/observe.js +13 -22
- package/dist/commands/run.d.ts +3 -6
- package/dist/commands/run.js +81 -96
- package/dist/commands/serve-mcp.d.ts +3 -10
- package/dist/commands/serve-mcp.js +23 -41
- package/dist/commands/test.d.ts +3 -7
- package/dist/commands/test.js +14 -20
- package/dist/utils/aigne-hub-user.d.ts +16 -0
- package/dist/utils/aigne-hub-user.js +12 -0
- package/dist/utils/download.d.ts +1 -3
- package/dist/utils/download.js +2 -2
- package/dist/utils/run-with-aigne.d.ts +2 -26
- package/dist/utils/run-with-aigne.js +56 -79
- package/package.json +9 -11
- package/dist/commands/app.d.ts +0 -2
- package/dist/commands/app.js +0 -98
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.27.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.26.0...cli-v1.27.0) (2025-07-30)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* support aigne connect command and add test ([#283](https://github.com/AIGNE-io/aigne-framework/issues/283)) ([387d22d](https://github.com/AIGNE-io/aigne-framework/commit/387d22d5cacf20abe02a13deaca1f36987d48ba5))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **cli:** replace external dependency with built-in user subscription API ([#292](https://github.com/AIGNE-io/aigne-framework/issues/292)) ([67de7fa](https://github.com/AIGNE-io/aigne-framework/commit/67de7fa521626ee7266c6c527e4eafc227bafa48))
|
|
14
|
+
* support aigne connect status more info ([#290](https://github.com/AIGNE-io/aigne-framework/issues/290)) ([04c5a06](https://github.com/AIGNE-io/aigne-framework/commit/04c5a0625938a7c1ca1d6fd997f6e9047d425ea0))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Dependencies
|
|
18
|
+
|
|
19
|
+
* The following workspace dependencies were updated
|
|
20
|
+
* dependencies
|
|
21
|
+
* @aigne/aigne-hub bumped to 0.3.0
|
|
22
|
+
|
|
3
23
|
## [1.26.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.25.1...cli-v1.26.0) (2025-07-28)
|
|
4
24
|
|
|
5
25
|
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { existsSync, realpathSync, statSync } from "node:fs";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { config } from "dotenv-flow";
|
|
5
|
-
import { hideBin } from "yargs/helpers";
|
|
6
5
|
import { createAIGNECommand } from "./commands/aigne.js";
|
|
7
6
|
config({ silent: true });
|
|
8
7
|
function getAIGNEFilePath() {
|
|
@@ -17,7 +16,7 @@ function getAIGNEFilePath() {
|
|
|
17
16
|
}
|
|
18
17
|
const aigneFilePath = getAIGNEFilePath();
|
|
19
18
|
createAIGNECommand({ aigneFilePath })
|
|
20
|
-
.parseAsync(
|
|
19
|
+
.parseAsync(["", "", ...process.argv.slice(aigneFilePath ? 3 : 2)])
|
|
21
20
|
.catch((error) => {
|
|
22
21
|
console.log(""); // Add an empty line for better readability
|
|
23
22
|
console.error(`${chalk.red("Error:")} ${error.message}`);
|
package/dist/commands/aigne.d.ts
CHANGED
package/dist/commands/aigne.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Command } from "commander";
|
|
2
2
|
import { AIGNE_CLI_VERSION } from "../constants.js";
|
|
3
3
|
import { asciiLogo } from "../utils/ascii-logo.js";
|
|
4
|
-
import { createAppCommands } from "./app.js";
|
|
5
4
|
import { createConnectCommand } from "./connect.js";
|
|
6
5
|
import { createCreateCommand } from "./create.js";
|
|
7
6
|
import { createObservabilityCommand } from "./observe.js";
|
|
@@ -10,20 +9,16 @@ import { createServeMCPCommand } from "./serve-mcp.js";
|
|
|
10
9
|
import { createTestCommand } from "./test.js";
|
|
11
10
|
export function createAIGNECommand(options) {
|
|
12
11
|
console.log(asciiLogo);
|
|
13
|
-
return
|
|
14
|
-
.
|
|
15
|
-
.
|
|
12
|
+
return new Command()
|
|
13
|
+
.name("aigne")
|
|
14
|
+
.description("CLI for AIGNE framework")
|
|
16
15
|
.version(AIGNE_CLI_VERSION)
|
|
17
|
-
.
|
|
18
|
-
.
|
|
19
|
-
.
|
|
20
|
-
.
|
|
21
|
-
.
|
|
22
|
-
.
|
|
23
|
-
.
|
|
24
|
-
.
|
|
25
|
-
.alias("help", "h")
|
|
26
|
-
.alias("version", "v")
|
|
27
|
-
.showHelpOnFail(true)
|
|
28
|
-
.strict();
|
|
16
|
+
.addCommand(createRunCommand(options), { isDefault: true })
|
|
17
|
+
.addCommand(createTestCommand(options))
|
|
18
|
+
.addCommand(createCreateCommand())
|
|
19
|
+
.addCommand(createServeMCPCommand(options))
|
|
20
|
+
.addCommand(createObservabilityCommand())
|
|
21
|
+
.addCommand(createConnectCommand())
|
|
22
|
+
.showHelpAfterError(true)
|
|
23
|
+
.showSuggestionAfterError(true);
|
|
29
24
|
}
|
|
@@ -1,6 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
url?: string;
|
|
4
|
-
}
|
|
5
|
-
export declare function createConnectCommand(): CommandModule<{}, ConnectOptions>;
|
|
6
|
-
export {};
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export declare function createConnectCommand(): Command;
|
package/dist/commands/connect.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { getUserInfo } from "@blocklet/aigne-hub/api/user";
|
|
4
3
|
import chalk from "chalk";
|
|
4
|
+
import { Command } from "commander";
|
|
5
5
|
import { parse } from "yaml";
|
|
6
|
+
import { getUserInfo } from "../utils/aigne-hub-user.js";
|
|
6
7
|
import { AIGNE_ENV_FILE, connectToAIGNEHub } from "../utils/load-aigne.js";
|
|
7
8
|
async function getConnectionStatus() {
|
|
8
9
|
if (!existsSync(AIGNE_ENV_FILE)) {
|
|
@@ -56,36 +57,30 @@ async function displayStatus(statusList) {
|
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
export function createConnectCommand() {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
console.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
catch (error) {
|
|
86
|
-
console.error(chalk.red("✗ Failed to connect to AIGNE Hub:"), error.message);
|
|
87
|
-
process.exit(1);
|
|
88
|
-
}
|
|
89
|
-
},
|
|
90
|
-
};
|
|
60
|
+
const connectCommand = new Command("connect")
|
|
61
|
+
.description("Manage AIGNE Hub connections")
|
|
62
|
+
.showHelpAfterError(true)
|
|
63
|
+
.showSuggestionAfterError(true);
|
|
64
|
+
connectCommand
|
|
65
|
+
.command("status")
|
|
66
|
+
.description("Show current connection status")
|
|
67
|
+
.action(async () => {
|
|
68
|
+
const statusList = await getConnectionStatus();
|
|
69
|
+
await displayStatus(statusList);
|
|
70
|
+
});
|
|
71
|
+
connectCommand
|
|
72
|
+
.option("--url <url>", "URL to the AIGNE Hub server")
|
|
73
|
+
.action(async (options) => {
|
|
74
|
+
const url = options.url || "https://hub.aigne.io/";
|
|
75
|
+
console.log(chalk.blue(`Connecting to AIGNE Hub: ${url}`));
|
|
76
|
+
try {
|
|
77
|
+
await connectToAIGNEHub(url);
|
|
78
|
+
console.log(chalk.green("✓ Successfully connected to AIGNE Hub"));
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error(chalk.red("✗ Failed to connect to AIGNE Hub:"), error.message);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
return connectCommand;
|
|
91
86
|
}
|
|
@@ -1,6 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
path: string;
|
|
4
|
-
}
|
|
5
|
-
export declare function createCreateCommand(): CommandModule<{}, CreateOptions>;
|
|
6
|
-
export {};
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export declare function createCreateCommand(): Command;
|
package/dist/commands/create.js
CHANGED
|
@@ -1,73 +1,69 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync } from "node:fs";
|
|
2
2
|
import { cp } from "node:fs/promises";
|
|
3
3
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
4
|
+
import { Command } from "commander";
|
|
4
5
|
import inquirer from "inquirer";
|
|
5
6
|
export function createCreateCommand() {
|
|
6
|
-
return
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
message: "Project name:",
|
|
23
|
-
default: path !== "." ? path : "my-aigne-project",
|
|
24
|
-
validate: (input) => {
|
|
25
|
-
if (input.trim() === "")
|
|
26
|
-
return "Project name cannot be empty.";
|
|
27
|
-
return true;
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
]);
|
|
31
|
-
path = answers.projectName;
|
|
32
|
-
}
|
|
33
|
-
path = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
34
|
-
const isPathNotEmpty = existsSync(path) && readdirSync(path).length > 0;
|
|
35
|
-
if (isPathNotEmpty) {
|
|
36
|
-
const answers = await inquirer.prompt([
|
|
37
|
-
{
|
|
38
|
-
type: "confirm",
|
|
39
|
-
name: "overwrite",
|
|
40
|
-
message: `The directory "${path}" is not empty. Do you want to remove its contents?`,
|
|
41
|
-
default: false,
|
|
7
|
+
return new Command("create")
|
|
8
|
+
.description("Create a new aigne project with agent config files")
|
|
9
|
+
.argument("[path]", "Path to create the project directory", ".")
|
|
10
|
+
.action(async (_path) => {
|
|
11
|
+
let path = _path;
|
|
12
|
+
if (path === ".") {
|
|
13
|
+
const answers = await inquirer.prompt([
|
|
14
|
+
{
|
|
15
|
+
type: "input",
|
|
16
|
+
name: "projectName",
|
|
17
|
+
message: "Project name:",
|
|
18
|
+
default: _path !== "." ? _path : "my-aigne-project",
|
|
19
|
+
validate: (input) => {
|
|
20
|
+
if (input.trim() === "")
|
|
21
|
+
return "Project name cannot be empty.";
|
|
22
|
+
return true;
|
|
42
23
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
24
|
+
},
|
|
25
|
+
]);
|
|
26
|
+
path = answers.projectName;
|
|
27
|
+
}
|
|
28
|
+
path = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
29
|
+
const isPathNotEmpty = existsSync(path) && readdirSync(path).length > 0;
|
|
30
|
+
if (isPathNotEmpty) {
|
|
31
|
+
const answers = await inquirer.prompt([
|
|
51
32
|
{
|
|
52
|
-
type: "
|
|
53
|
-
name: "
|
|
54
|
-
message: "
|
|
55
|
-
|
|
56
|
-
default: "default",
|
|
33
|
+
type: "confirm",
|
|
34
|
+
name: "overwrite",
|
|
35
|
+
message: `The directory "${path}" is not empty. Do you want to remove its contents?`,
|
|
36
|
+
default: false,
|
|
57
37
|
},
|
|
58
38
|
]);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
throw new Error(`Template "${template}" not found.`);
|
|
63
|
-
const files = readdirSync(templatePath);
|
|
64
|
-
for (const file of files) {
|
|
65
|
-
const source = join(templatePath, file);
|
|
66
|
-
const destination = join(path, file);
|
|
67
|
-
await cp(source, destination, { recursive: true, force: true });
|
|
39
|
+
if (!answers.overwrite) {
|
|
40
|
+
console.log("Operation cancelled.");
|
|
41
|
+
process.exit(0);
|
|
68
42
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
43
|
+
}
|
|
44
|
+
const templates = [{ name: "default" }];
|
|
45
|
+
const { template } = await inquirer.prompt([
|
|
46
|
+
{
|
|
47
|
+
type: "list",
|
|
48
|
+
name: "template",
|
|
49
|
+
message: "Select a template:",
|
|
50
|
+
choices: templates.map((t) => t.name),
|
|
51
|
+
default: "default",
|
|
52
|
+
},
|
|
53
|
+
]);
|
|
54
|
+
mkdirSync(path, { recursive: true });
|
|
55
|
+
const templatePath = join(import.meta.dirname, "../../templates", template);
|
|
56
|
+
if (!existsSync(templatePath))
|
|
57
|
+
throw new Error(`Template "${template}" not found.`);
|
|
58
|
+
const files = readdirSync(templatePath);
|
|
59
|
+
for (const file of files) {
|
|
60
|
+
const source = join(templatePath, file);
|
|
61
|
+
const destination = join(path, file);
|
|
62
|
+
await cp(source, destination, { recursive: true, force: true });
|
|
63
|
+
}
|
|
64
|
+
console.log("\n✅ AIGNE project created successfully!");
|
|
65
|
+
console.log(`\nTo use your new agent, run:\n cd ${relative(process.cwd(), path)} && aigne run`);
|
|
66
|
+
})
|
|
67
|
+
.showHelpAfterError(true)
|
|
68
|
+
.showSuggestionAfterError(true);
|
|
73
69
|
}
|
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
host: string;
|
|
4
|
-
port?: number;
|
|
5
|
-
}
|
|
6
|
-
export declare function createObservabilityCommand(): CommandModule<{}, ServeMCPOptions>;
|
|
7
|
-
export {};
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export declare function createObservabilityCommand(): Command;
|
package/dist/commands/observe.js
CHANGED
|
@@ -2,6 +2,7 @@ import { tryOrThrow } from "@aigne/core/utils/type-utils.js";
|
|
|
2
2
|
import { startObservabilityCLIServer } from "@aigne/observability-api/cli";
|
|
3
3
|
import getObservabilityDbPath from "@aigne/observability-api/db-path";
|
|
4
4
|
import chalk from "chalk";
|
|
5
|
+
import { Command } from "commander";
|
|
5
6
|
import detectPort from "detect-port";
|
|
6
7
|
const DEFAULT_PORT = () => tryOrThrow(() => {
|
|
7
8
|
const { PORT } = process.env;
|
|
@@ -13,26 +14,16 @@ const DEFAULT_PORT = () => tryOrThrow(() => {
|
|
|
13
14
|
return port;
|
|
14
15
|
}, (error) => new Error(`parse PORT error ${error.message}`));
|
|
15
16
|
export function createObservabilityCommand() {
|
|
16
|
-
return
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
describe: "Port to run the observability server on",
|
|
29
|
-
});
|
|
30
|
-
},
|
|
31
|
-
handler: async (options) => {
|
|
32
|
-
const port = await detectPort(options.port || DEFAULT_PORT());
|
|
33
|
-
const dbUrl = getObservabilityDbPath();
|
|
34
|
-
console.log("Observability database path:", chalk.greenBright(dbUrl));
|
|
35
|
-
await startObservabilityCLIServer({ port, dbUrl });
|
|
36
|
-
},
|
|
37
|
-
};
|
|
17
|
+
return new Command("observe")
|
|
18
|
+
.description("Start the observability server")
|
|
19
|
+
.option("--host <host>", "Host to run the observability server on, use 0.0.0.0 to publicly expose the server", "localhost")
|
|
20
|
+
.option("--port <port>", "Port to run the observability server on", (s) => Number.parseInt(s))
|
|
21
|
+
.action(async (options) => {
|
|
22
|
+
const port = await detectPort(options.port || DEFAULT_PORT());
|
|
23
|
+
const dbUrl = getObservabilityDbPath();
|
|
24
|
+
console.log("Observability database path:", chalk.greenBright(dbUrl));
|
|
25
|
+
await startObservabilityCLIServer({ port, dbUrl });
|
|
26
|
+
})
|
|
27
|
+
.showHelpAfterError(true)
|
|
28
|
+
.showSuggestionAfterError(true);
|
|
38
29
|
}
|
package/dist/commands/run.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function createRunCommand({ aigneFilePath
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
export declare function createRunCommand({ aigneFilePath }?: {
|
|
3
3
|
aigneFilePath?: string;
|
|
4
|
-
}):
|
|
5
|
-
export declare function getLocalPackagePathFromUrl(url: string, { subdir }?: {
|
|
6
|
-
subdir?: string;
|
|
7
|
-
}): string;
|
|
4
|
+
}): Command;
|
package/dist/commands/run.js
CHANGED
|
@@ -12,109 +12,94 @@ import { isV1Package, toAIGNEPackage } from "../utils/agent-v1.js";
|
|
|
12
12
|
import { downloadAndExtract } from "../utils/download.js";
|
|
13
13
|
import { loadAIGNE } from "../utils/load-aigne.js";
|
|
14
14
|
import { createRunAIGNECommand, parseAgentInputByCommander, runAgentWithAIGNE, } from "../utils/run-with-aigne.js";
|
|
15
|
-
export function createRunCommand({ aigneFilePath
|
|
16
|
-
return
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (options.logLevel)
|
|
40
|
-
logger.level = options.logLevel;
|
|
41
|
-
const { cacheDir, dir } = prepareDirs(path, options);
|
|
42
|
-
const { aigne, agent } = await new Listr([
|
|
43
|
-
{
|
|
44
|
-
title: "Prepare environment",
|
|
45
|
-
task: (_, task) => {
|
|
46
|
-
if (cacheDir) {
|
|
47
|
-
return task.newListr([
|
|
48
|
-
{
|
|
49
|
-
title: "Download package",
|
|
50
|
-
task: () => downloadPackage(path, cacheDir),
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
title: "Extract package",
|
|
54
|
-
task: () => extractPackage(cacheDir, dir),
|
|
55
|
-
},
|
|
56
|
-
]);
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
title: "Initialize AIGNE",
|
|
62
|
-
task: async (ctx, task) => {
|
|
63
|
-
// Load env files in the aigne directory
|
|
64
|
-
config({ path: dir, silent: true });
|
|
65
|
-
const aigne = await loadAIGNE(dir, { ...options, model: options.model || process.env.MODEL }, {
|
|
66
|
-
inquirerPromptFn: (prompt) => {
|
|
67
|
-
return task
|
|
68
|
-
.prompt(ListrInquirerPromptAdapter)
|
|
69
|
-
.run(select, prompt)
|
|
70
|
-
.then((res) => ({ [prompt.name]: res }));
|
|
15
|
+
export function createRunCommand({ aigneFilePath } = {}) {
|
|
16
|
+
return createRunAIGNECommand()
|
|
17
|
+
.description("Run AIGNE from the specified agent")
|
|
18
|
+
.option("--url, --path <path_or_url>", "Path to the agents directory or URL to aigne project", ".")
|
|
19
|
+
.option("--entry-agent <entry-agent>", "Name of the agent to run (defaults to the first agent found)")
|
|
20
|
+
.option("--cache-dir <dir>", "Directory to download the package to (defaults to the ~/.aigne/xxx)")
|
|
21
|
+
.action(async (options) => {
|
|
22
|
+
const path = aigneFilePath || options.path;
|
|
23
|
+
if (options.logLevel)
|
|
24
|
+
logger.level = options.logLevel;
|
|
25
|
+
const { cacheDir, dir } = prepareDirs(path, options);
|
|
26
|
+
const { aigne, agent } = await new Listr([
|
|
27
|
+
{
|
|
28
|
+
title: "Prepare environment",
|
|
29
|
+
task: (_, task) => {
|
|
30
|
+
if (cacheDir) {
|
|
31
|
+
return task.newListr([
|
|
32
|
+
{
|
|
33
|
+
title: "Download package",
|
|
34
|
+
task: () => downloadPackage(path, cacheDir),
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
title: "Extract package",
|
|
38
|
+
task: () => extractPackage(cacheDir, dir),
|
|
71
39
|
},
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
},
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
75
42
|
},
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
title: "Initialize AIGNE",
|
|
46
|
+
task: async (ctx, task) => {
|
|
47
|
+
// Load env files in the aigne directory
|
|
48
|
+
config({ path: dir, silent: true });
|
|
49
|
+
const aigne = await loadAIGNE(dir, { ...options, model: options.model || process.env.MODEL }, {
|
|
50
|
+
inquirerPromptFn: (prompt) => {
|
|
51
|
+
return task
|
|
52
|
+
.prompt(ListrInquirerPromptAdapter)
|
|
53
|
+
.run(select, prompt)
|
|
54
|
+
.then((res) => ({ [prompt.name]: res }));
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
ctx.aigne = aigne;
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
task: (ctx) => {
|
|
62
|
+
const { aigne } = ctx;
|
|
63
|
+
assert(aigne);
|
|
64
|
+
let entryAgent;
|
|
65
|
+
if (options.entryAgent) {
|
|
66
|
+
entryAgent = aigne.agents[options.entryAgent];
|
|
67
|
+
if (!entryAgent) {
|
|
68
|
+
throw new Error(`\
|
|
85
69
|
Agent "${options.entryAgent}" not found in ${aigne.rootDir}
|
|
86
70
|
|
|
87
71
|
Available agents:
|
|
88
72
|
${aigne.agents.map((agent) => ` - ${agent.name}`).join("\n")}
|
|
89
73
|
`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
entryAgent = aigne.agents[0];
|
|
94
|
-
if (!entryAgent)
|
|
95
|
-
throw new Error(`No any agent found in ${aigne.rootDir}`);
|
|
96
74
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
timer: PRESET_TIMER,
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
entryAgent = aigne.agents[0];
|
|
78
|
+
if (!entryAgent)
|
|
79
|
+
throw new Error(`No any agent found in ${aigne.rootDir}`);
|
|
80
|
+
}
|
|
81
|
+
ctx.agent = entryAgent;
|
|
105
82
|
},
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
83
|
+
},
|
|
84
|
+
], {
|
|
85
|
+
rendererOptions: {
|
|
86
|
+
collapseSubtasks: false,
|
|
87
|
+
showErrorMessage: false,
|
|
88
|
+
timer: PRESET_TIMER,
|
|
89
|
+
},
|
|
90
|
+
}).run();
|
|
91
|
+
assert(aigne);
|
|
92
|
+
assert(agent);
|
|
93
|
+
const input = await parseAgentInputByCommander(agent, options);
|
|
94
|
+
try {
|
|
95
|
+
await runAgentWithAIGNE(aigne, agent, { ...options, input });
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
await aigne.shutdown();
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
.showHelpAfterError(true)
|
|
102
|
+
.showSuggestionAfterError(true);
|
|
118
103
|
}
|
|
119
104
|
async function downloadPackage(url, cacheDir) {
|
|
120
105
|
await rm(cacheDir, { recursive: true, force: true });
|
|
@@ -136,7 +121,7 @@ function prepareDirs(path, options) {
|
|
|
136
121
|
if (!path.startsWith("http")) {
|
|
137
122
|
dir = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
138
123
|
}
|
|
139
|
-
else if (options
|
|
124
|
+
else if (options.cacheDir) {
|
|
140
125
|
dir = isAbsolute(options.cacheDir)
|
|
141
126
|
? options.cacheDir
|
|
142
127
|
: resolve(process.cwd(), options.cacheDir);
|
|
@@ -148,7 +133,7 @@ function prepareDirs(path, options) {
|
|
|
148
133
|
}
|
|
149
134
|
return { cacheDir, dir };
|
|
150
135
|
}
|
|
151
|
-
|
|
136
|
+
function getLocalPackagePathFromUrl(url, { subdir } = {}) {
|
|
152
137
|
const root = [homedir(), ".aigne", subdir].filter(isNonNullable);
|
|
153
138
|
const u = new URL(url);
|
|
154
139
|
return join(...root, u.hostname, u.pathname);
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
path: string;
|
|
4
|
-
host: string;
|
|
5
|
-
port?: number;
|
|
6
|
-
pathname: string;
|
|
7
|
-
}
|
|
8
|
-
export declare function createServeMCPCommand({ aigneFilePath, }?: {
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export declare function createServeMCPCommand({ aigneFilePath }?: {
|
|
9
3
|
aigneFilePath?: string;
|
|
10
|
-
}):
|
|
11
|
-
export {};
|
|
4
|
+
}): Command;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isAbsolute, resolve } from "node:path";
|
|
2
2
|
import { tryOrThrow } from "@aigne/core/utils/type-utils.js";
|
|
3
|
+
import { Command } from "commander";
|
|
3
4
|
import { loadAIGNE } from "../utils/load-aigne.js";
|
|
4
5
|
import { serveMCPServer } from "../utils/serve-mcp.js";
|
|
5
6
|
const DEFAULT_PORT = () => tryOrThrow(() => {
|
|
@@ -11,45 +12,26 @@ const DEFAULT_PORT = () => tryOrThrow(() => {
|
|
|
11
12
|
throw new Error(`Invalid PORT: ${PORT}`);
|
|
12
13
|
return port;
|
|
13
14
|
}, (error) => new Error(`parse PORT error ${error.message}`));
|
|
14
|
-
export function createServeMCPCommand({ aigneFilePath
|
|
15
|
-
return
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
describe: "Pathname to the service",
|
|
37
|
-
type: "string",
|
|
38
|
-
default: "/mcp",
|
|
39
|
-
});
|
|
40
|
-
},
|
|
41
|
-
handler: async (options) => {
|
|
42
|
-
const path = aigneFilePath || options.path;
|
|
43
|
-
const absolutePath = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
44
|
-
const port = options.port || DEFAULT_PORT();
|
|
45
|
-
const aigne = await loadAIGNE(absolutePath);
|
|
46
|
-
await serveMCPServer({
|
|
47
|
-
aigne,
|
|
48
|
-
host: options.host,
|
|
49
|
-
port,
|
|
50
|
-
pathname: options.pathname,
|
|
51
|
-
});
|
|
52
|
-
console.log(`MCP server is running on http://${options.host}:${port}${options.pathname}`);
|
|
53
|
-
},
|
|
54
|
-
};
|
|
15
|
+
export function createServeMCPCommand({ aigneFilePath } = {}) {
|
|
16
|
+
return new Command("serve-mcp")
|
|
17
|
+
.description("Serve the agents in the specified directory as a MCP server (streamable http)")
|
|
18
|
+
.option("--url, --path <path_or_url>", "Path to the agents directory or URL to aigne project", ".")
|
|
19
|
+
.option("--host <host>", "Host to run the MCP server on, use 0.0.0.0 to publicly expose the server", "localhost")
|
|
20
|
+
.option("--port <port>", "Port to run the MCP server on", (s) => Number.parseInt(s))
|
|
21
|
+
.option("--pathname <pathname>", "Pathname to the service", "/mcp")
|
|
22
|
+
.action(async (options) => {
|
|
23
|
+
const path = aigneFilePath || options.path;
|
|
24
|
+
const absolutePath = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
25
|
+
const port = options.port || DEFAULT_PORT();
|
|
26
|
+
const aigne = await loadAIGNE(absolutePath);
|
|
27
|
+
await serveMCPServer({
|
|
28
|
+
aigne,
|
|
29
|
+
host: options.host,
|
|
30
|
+
port,
|
|
31
|
+
pathname: options.pathname,
|
|
32
|
+
});
|
|
33
|
+
console.log(`MCP server is running on http://${options.host}:${port}${options.pathname}`);
|
|
34
|
+
})
|
|
35
|
+
.showHelpAfterError(true)
|
|
36
|
+
.showSuggestionAfterError(true);
|
|
55
37
|
}
|
package/dist/commands/test.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
path: string;
|
|
4
|
-
}
|
|
5
|
-
export declare function createTestCommand({ aigneFilePath, }?: {
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export declare function createTestCommand({ aigneFilePath }?: {
|
|
6
3
|
aigneFilePath?: string;
|
|
7
|
-
}):
|
|
8
|
-
export {};
|
|
4
|
+
}): Command;
|
package/dist/commands/test.js
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
3
|
import { isAbsolute, resolve } from "node:path";
|
|
4
|
+
import { Command } from "commander";
|
|
4
5
|
import { loadAIGNE } from "../utils/load-aigne.js";
|
|
5
|
-
export function createTestCommand({ aigneFilePath
|
|
6
|
-
return
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const path = aigneFilePath || options.path;
|
|
19
|
-
const absolutePath = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
20
|
-
const aigne = await loadAIGNE(absolutePath);
|
|
21
|
-
assert(aigne.rootDir);
|
|
22
|
-
spawnSync("node", ["--test"], { cwd: aigne.rootDir, stdio: "inherit" });
|
|
23
|
-
},
|
|
24
|
-
};
|
|
6
|
+
export function createTestCommand({ aigneFilePath } = {}) {
|
|
7
|
+
return new Command("test")
|
|
8
|
+
.description("Run tests in the specified agents directory")
|
|
9
|
+
.option("--url, --path <path_or_url>", "Path to the agents directory or URL to aigne project", ".")
|
|
10
|
+
.action(async (options) => {
|
|
11
|
+
const path = aigneFilePath || options.path;
|
|
12
|
+
const absolutePath = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
13
|
+
const aigne = await loadAIGNE(absolutePath);
|
|
14
|
+
assert(aigne.rootDir);
|
|
15
|
+
spawnSync("node", ["--test"], { cwd: aigne.rootDir, stdio: "inherit" });
|
|
16
|
+
})
|
|
17
|
+
.showHelpAfterError(true)
|
|
18
|
+
.showSuggestionAfterError(true);
|
|
25
19
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface UserInfoResult {
|
|
2
|
+
user: Record<string, any>;
|
|
3
|
+
enableCredit: boolean;
|
|
4
|
+
creditBalance: {
|
|
5
|
+
balance: string;
|
|
6
|
+
total: string;
|
|
7
|
+
grantCount: number;
|
|
8
|
+
pendingCredit: string;
|
|
9
|
+
} | null;
|
|
10
|
+
paymentLink: string | null;
|
|
11
|
+
profileLink: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function getUserInfo({ baseUrl, accessKey, }: {
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
accessKey: string;
|
|
16
|
+
}): Promise<UserInfoResult>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { joinURL } from "ufo";
|
|
2
|
+
export async function getUserInfo({ baseUrl, accessKey, }) {
|
|
3
|
+
const response = await fetch(joinURL(baseUrl, "/api/user/info"), {
|
|
4
|
+
headers: {
|
|
5
|
+
Authorization: `Bearer ${accessKey}`,
|
|
6
|
+
},
|
|
7
|
+
});
|
|
8
|
+
if (!response.ok)
|
|
9
|
+
throw new Error(`Failed to fetch user info: ${response.statusText}`);
|
|
10
|
+
const data = await response.json();
|
|
11
|
+
return data;
|
|
12
|
+
}
|
package/dist/utils/download.d.ts
CHANGED
package/dist/utils/download.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Readable } from "node:stream";
|
|
2
2
|
import { finished } from "node:stream/promises";
|
|
3
3
|
import { x } from "tar";
|
|
4
|
-
export async function downloadAndExtract(url, dir
|
|
4
|
+
export async function downloadAndExtract(url, dir) {
|
|
5
5
|
const response = await fetch(url).catch((error) => {
|
|
6
6
|
throw new Error(`Failed to download package from ${url}: ${error.message}`);
|
|
7
7
|
});
|
|
@@ -12,7 +12,7 @@ export async function downloadAndExtract(url, dir, options = {}) {
|
|
|
12
12
|
throw new Error(`Failed to download package from ${url}: Unexpected to get empty response`);
|
|
13
13
|
}
|
|
14
14
|
try {
|
|
15
|
-
await finished(Readable.fromWeb(response.body).pipe(x({ C: dir
|
|
15
|
+
await finished(Readable.fromWeb(response.body).pipe(x({ C: dir })));
|
|
16
16
|
}
|
|
17
17
|
catch (error) {
|
|
18
18
|
error.message = `Failed to extract package from ${url}: ${error.message}`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Agent, AIGNE, type ChatModelOptions, type Message } from "@aigne/core";
|
|
2
2
|
import { LogLevel } from "@aigne/core/utils/logger.js";
|
|
3
3
|
import { type PromiseOrValue } from "@aigne/core/utils/type-utils.js";
|
|
4
|
-
import
|
|
4
|
+
import { Command } from "commander";
|
|
5
5
|
import { type ChatLoopOptions } from "./run-chat-loop.js";
|
|
6
6
|
export interface RunAIGNECommandOptions {
|
|
7
7
|
chat?: boolean;
|
|
@@ -17,31 +17,7 @@ export interface RunAIGNECommandOptions {
|
|
|
17
17
|
logLevel?: LogLevel;
|
|
18
18
|
force?: boolean;
|
|
19
19
|
}
|
|
20
|
-
export declare const createRunAIGNECommand: (
|
|
21
|
-
chat: boolean;
|
|
22
|
-
} & {
|
|
23
|
-
model: string | undefined;
|
|
24
|
-
} & {
|
|
25
|
-
temperature: number | undefined;
|
|
26
|
-
} & {
|
|
27
|
-
"top-p": number | undefined;
|
|
28
|
-
} & {
|
|
29
|
-
"presence-penalty": number | undefined;
|
|
30
|
-
} & {
|
|
31
|
-
"frequency-penalty": number | undefined;
|
|
32
|
-
} & {
|
|
33
|
-
input: (string | number)[] | undefined;
|
|
34
|
-
} & {
|
|
35
|
-
format: string | undefined;
|
|
36
|
-
} & {
|
|
37
|
-
output: string | undefined;
|
|
38
|
-
} & {
|
|
39
|
-
"output-key": string;
|
|
40
|
-
} & {
|
|
41
|
-
force: boolean;
|
|
42
|
-
} & {
|
|
43
|
-
"log-level": LogLevel;
|
|
44
|
-
}>;
|
|
20
|
+
export declare const createRunAIGNECommand: (name?: string) => Command;
|
|
45
21
|
export declare function parseAgentInputByCommander(agent: Agent, options?: RunAIGNECommandOptions & {
|
|
46
22
|
inputKey?: string;
|
|
47
23
|
argv?: string[];
|
|
@@ -4,90 +4,67 @@ import { dirname, isAbsolute, join } from "node:path";
|
|
|
4
4
|
import { isatty } from "node:tty";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
import { exists } from "@aigne/agent-library/utils/fs.js";
|
|
7
|
-
import {
|
|
7
|
+
import { AIGNE, DEFAULT_OUTPUT_KEY, readAllString, UserAgent, } from "@aigne/core";
|
|
8
8
|
import { loadModel } from "@aigne/core/loader/index.js";
|
|
9
9
|
import { getLevelFromEnv, LogLevel, logger } from "@aigne/core/utils/logger.js";
|
|
10
|
-
import {
|
|
10
|
+
import { isEmpty, isNonNullable, tryOrThrow, } from "@aigne/core/utils/type-utils.js";
|
|
11
11
|
import chalk from "chalk";
|
|
12
|
+
import { Command } from "commander";
|
|
12
13
|
import { parse } from "yaml";
|
|
13
|
-
import yargs from "yargs";
|
|
14
14
|
import { ZodError, ZodObject, z } from "zod";
|
|
15
15
|
import { availableModels } from "../constants.js";
|
|
16
16
|
import { TerminalTracer } from "../tracer/terminal.js";
|
|
17
17
|
import { DEFAULT_CHAT_INPUT_KEY, runChatLoopInTerminal, } from "./run-chat-loop.js";
|
|
18
|
-
export const createRunAIGNECommand = (
|
|
19
|
-
.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
.option("
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
.option("
|
|
36
|
-
describe: "Top P (nucleus sampling) parameter for the model (controls diversity). Range: 0.0-1.0",
|
|
37
|
-
type: "number",
|
|
38
|
-
coerce: customZodError("--top-p", (s) => z.coerce.number().min(0).max(1).parse(s)),
|
|
39
|
-
})
|
|
40
|
-
.option("presence-penalty", {
|
|
41
|
-
describe: "Presence penalty for the model (penalizes repeating the same tokens). Range: -2.0 to 2.0",
|
|
42
|
-
type: "number",
|
|
43
|
-
coerce: customZodError("--presence-penalty", (s) => z.coerce.number().min(-2).max(2).parse(s)),
|
|
44
|
-
})
|
|
45
|
-
.option("frequency-penalty", {
|
|
46
|
-
describe: "Frequency penalty for the model (penalizes frequency of token usage). Range: -2.0 to 2.0",
|
|
47
|
-
type: "number",
|
|
48
|
-
coerce: customZodError("--frequency-penalty", (s) => z.coerce.number().min(-2).max(2).parse(s)),
|
|
49
|
-
})
|
|
50
|
-
.option("input", {
|
|
51
|
-
describe: "Input to the agent, use @<file> to read from a file",
|
|
52
|
-
type: "array",
|
|
53
|
-
alias: "i",
|
|
54
|
-
})
|
|
55
|
-
.option("format", {
|
|
56
|
-
describe: "Input format for the agent (available: text, json, yaml default: text)",
|
|
57
|
-
type: "string",
|
|
58
|
-
})
|
|
59
|
-
.option("output", {
|
|
60
|
-
describe: "Output file to save the result (default: stdout)",
|
|
61
|
-
type: "string",
|
|
62
|
-
alias: "o",
|
|
63
|
-
})
|
|
64
|
-
.option("output-key", {
|
|
65
|
-
describe: "Key in the result to save to the output file",
|
|
66
|
-
type: "string",
|
|
67
|
-
default: DEFAULT_OUTPUT_KEY,
|
|
68
|
-
})
|
|
69
|
-
.option("force", {
|
|
70
|
-
describe: "Truncate the output file if it exists, and create directory if the output path is not exists",
|
|
71
|
-
type: "boolean",
|
|
72
|
-
default: false,
|
|
73
|
-
})
|
|
74
|
-
.option("log-level", {
|
|
75
|
-
describe: `Log level for detailed debugging information. Values: ${Object.values(LogLevel).join(", ")}`,
|
|
76
|
-
type: "string",
|
|
77
|
-
default: getLevelFromEnv(logger.options.ns) || LogLevel.INFO,
|
|
78
|
-
coerce: customZodError("--log-level", (s) => z.nativeEnum(LogLevel).parse(s)),
|
|
79
|
-
});
|
|
18
|
+
export const createRunAIGNECommand = (name = "run") => new Command(name)
|
|
19
|
+
.allowUnknownOption(true)
|
|
20
|
+
.allowExcessArguments(true)
|
|
21
|
+
.description("Run agent with AIGNE in terminal")
|
|
22
|
+
.option("--chat", "Run chat loop in terminal", false)
|
|
23
|
+
.option("--model <provider[:model]>", `AI model to use in format 'provider[:model]' where model is optional. Examples: 'openai' or 'openai:gpt-4o-mini'. Available providers: ${availableModels()
|
|
24
|
+
.map((i) => i.name.toLowerCase().replace(/ChatModel$/i, ""))
|
|
25
|
+
.join(", ")} (default: openai)`)
|
|
26
|
+
.option("--temperature <temperature>", "Temperature for the model (controls randomness, higher values produce more random outputs). Range: 0.0-2.0", customZodError("--temperature", (s) => z.coerce.number().min(0).max(2).parse(s)))
|
|
27
|
+
.option("--top-p <top-p>", "Top P (nucleus sampling) parameter for the model (controls diversity). Range: 0.0-1.0", customZodError("--top-p", (s) => z.coerce.number().min(0).max(1).parse(s)))
|
|
28
|
+
.option("--presence-penalty <presence-penalty>", "Presence penalty for the model (penalizes repeating the same tokens). Range: -2.0 to 2.0", customZodError("--presence-penalty", (s) => z.coerce.number().min(-2).max(2).parse(s)))
|
|
29
|
+
.option("--frequency-penalty <frequency-penalty>", "Frequency penalty for the model (penalizes frequency of token usage). Range: -2.0 to 2.0", customZodError("--frequency-penalty", (s) => z.coerce.number().min(-2).max(2).parse(s)))
|
|
30
|
+
.option("--input -i <input...>", "Input to the agent, use @<file> to read from a file")
|
|
31
|
+
.option("--format <format>", "Input format for the agent (available: text, json, yaml default: text)")
|
|
32
|
+
.option("--output -o <output>", "Output file to save the result (default: stdout)")
|
|
33
|
+
.option("--output-key <output-key>", "Key in the result to save to the output file", DEFAULT_OUTPUT_KEY)
|
|
34
|
+
.option("--force", "Truncate the output file if it exists, and create directory if the output path is not exists", false)
|
|
35
|
+
.option("--log-level <level>", `Log level for detailed debugging information. Values: ${Object.values(LogLevel).join(", ")}`, customZodError("--log-level", (s) => z.nativeEnum(LogLevel).parse(s)), getLevelFromEnv(logger.options.ns) || LogLevel.INFO);
|
|
80
36
|
export async function parseAgentInputByCommander(agent, options = {}) {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
37
|
+
const cmd = new Command()
|
|
38
|
+
.description(`Run agent ${agent.name} with AIGNE`)
|
|
39
|
+
.allowUnknownOption(true)
|
|
40
|
+
.allowExcessArguments(true);
|
|
41
|
+
const inputSchemaShape = agent.inputSchema instanceof ZodObject ? Object.keys(agent.inputSchema.shape) : [];
|
|
42
|
+
for (const option of inputSchemaShape) {
|
|
43
|
+
cmd.option(`--input-${option} <${option}>`);
|
|
44
|
+
}
|
|
45
|
+
const input = await new Promise((resolve, reject) => {
|
|
46
|
+
cmd
|
|
47
|
+
.action(async (agentInputOptions) => {
|
|
48
|
+
try {
|
|
49
|
+
const input = Object.fromEntries((await Promise.all(Object.entries(agentInputOptions).map(async ([key, value]) => {
|
|
50
|
+
let k = key.replace(/^input/, "");
|
|
51
|
+
k = k.charAt(0).toLowerCase() + k.slice(1);
|
|
52
|
+
if (!k)
|
|
53
|
+
return null;
|
|
54
|
+
if (typeof value === "string" && value.startsWith("@")) {
|
|
55
|
+
value = await readFile(value.slice(1), "utf8");
|
|
56
|
+
}
|
|
57
|
+
return [k, value];
|
|
58
|
+
}))).filter(isNonNullable));
|
|
59
|
+
resolve(input);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
reject(error);
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
.parseAsync(options.argv ?? process.argv)
|
|
66
|
+
.catch((error) => reject(error));
|
|
67
|
+
});
|
|
91
68
|
const rawInput = options.input ||
|
|
92
69
|
(isatty(process.stdin.fd) || !(await stdinHasData())
|
|
93
70
|
? null
|
|
@@ -123,8 +100,10 @@ export const parseModelOption = (model) => {
|
|
|
123
100
|
return { provider, name };
|
|
124
101
|
};
|
|
125
102
|
export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoopOptions, modelOptions, outputKey, } = {}) {
|
|
126
|
-
await
|
|
127
|
-
.
|
|
103
|
+
await createRunAIGNECommand()
|
|
104
|
+
.showHelpAfterError(true)
|
|
105
|
+
.showSuggestionAfterError(true)
|
|
106
|
+
.action(async (options) => {
|
|
128
107
|
if (options.logLevel) {
|
|
129
108
|
logger.level = options.logLevel;
|
|
130
109
|
}
|
|
@@ -155,8 +134,6 @@ export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoop
|
|
|
155
134
|
await aigne.shutdown();
|
|
156
135
|
}
|
|
157
136
|
})
|
|
158
|
-
.alias("h", "help")
|
|
159
|
-
.alias("v", "version")
|
|
160
137
|
.parseAsync(argv)
|
|
161
138
|
.catch((error) => {
|
|
162
139
|
console.error(`${chalk.red("Error:")} ${error.message}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.0",
|
|
4
4
|
"description": "cli for AIGNE framework",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -44,7 +44,6 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@aigne/listr2": "^1.0.10",
|
|
46
46
|
"@aigne/marked-terminal": "^7.3.2",
|
|
47
|
-
"@blocklet/aigne-hub": "^0.2.17",
|
|
48
47
|
"@inquirer/prompts": "^7.6.0",
|
|
49
48
|
"@inquirer/type": "^3.0.8",
|
|
50
49
|
"@listr2/prompt-adapter-inquirer": "^3.0.1",
|
|
@@ -52,6 +51,7 @@
|
|
|
52
51
|
"@ocap/mcrypto": "^1.21.0",
|
|
53
52
|
"@smithy/node-http-handler": "^4.1.0",
|
|
54
53
|
"chalk": "^5.4.1",
|
|
54
|
+
"commander": "^14.0.0",
|
|
55
55
|
"crypto": "^1.0.1",
|
|
56
56
|
"detect-port": "^2.1.0",
|
|
57
57
|
"dotenv-flow": "^4.1.0",
|
|
@@ -69,22 +69,21 @@
|
|
|
69
69
|
"tar": "^7.4.3",
|
|
70
70
|
"wrap-ansi": "^9.0.0",
|
|
71
71
|
"yaml": "^2.8.0",
|
|
72
|
-
"yargs": "^18.0.0",
|
|
73
72
|
"zod": "^3.25.67",
|
|
73
|
+
"@aigne/agent-library": "^1.21.6",
|
|
74
|
+
"@aigne/aigne-hub": "^0.3.0",
|
|
74
75
|
"@aigne/agentic-memory": "^1.0.6",
|
|
75
|
-
"@aigne/aigne-hub": "^0.2.2",
|
|
76
76
|
"@aigne/anthropic": "^0.10.2",
|
|
77
|
-
"@aigne/agent-library": "^1.21.6",
|
|
78
77
|
"@aigne/bedrock": "^0.8.6",
|
|
79
|
-
"@aigne/core": "^1.39.0",
|
|
80
78
|
"@aigne/deepseek": "^0.7.6",
|
|
81
79
|
"@aigne/default-memory": "^1.0.6",
|
|
80
|
+
"@aigne/gemini": "^0.8.6",
|
|
82
81
|
"@aigne/observability-api": "^0.8.2",
|
|
83
|
-
"@aigne/ollama": "^0.7.6",
|
|
84
82
|
"@aigne/open-router": "^0.7.6",
|
|
85
|
-
"@aigne/
|
|
86
|
-
"@aigne/
|
|
87
|
-
"@aigne/openai": "^0.10.6"
|
|
83
|
+
"@aigne/ollama": "^0.7.6",
|
|
84
|
+
"@aigne/core": "^1.39.0",
|
|
85
|
+
"@aigne/openai": "^0.10.6",
|
|
86
|
+
"@aigne/xai": "^0.7.6"
|
|
88
87
|
},
|
|
89
88
|
"devDependencies": {
|
|
90
89
|
"@types/archiver": "^6.0.3",
|
|
@@ -93,7 +92,6 @@
|
|
|
93
92
|
"@types/glob": "^9.0.0",
|
|
94
93
|
"@types/gradient-string": "^1.1.6",
|
|
95
94
|
"@types/node": "^24.0.12",
|
|
96
|
-
"@types/yargs": "^17.0.33",
|
|
97
95
|
"archiver": "^7.0.1",
|
|
98
96
|
"hono": "4.8.4",
|
|
99
97
|
"npm-run-all": "^4.1.5",
|
package/dist/commands/app.d.ts
DELETED
package/dist/commands/app.js
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert";
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { mkdir, readFile, stat } from "node:fs/promises";
|
|
4
|
-
import { homedir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import { AIGNE } from "@aigne/core";
|
|
7
|
-
import { joinURL } from "ufo";
|
|
8
|
-
import { ZodObject, ZodString } from "zod";
|
|
9
|
-
import { availableModels } from "../constants.js";
|
|
10
|
-
import { downloadAndExtract } from "../utils/download.js";
|
|
11
|
-
import { runAgentWithAIGNE } from "../utils/run-with-aigne.js";
|
|
12
|
-
const NPM_PACKAGE_CACHE_TIME_MS = 1000 * 60 * 60 * 24; // 1 day
|
|
13
|
-
export function createAppCommands() {
|
|
14
|
-
return [
|
|
15
|
-
{
|
|
16
|
-
command: "doc-smith",
|
|
17
|
-
describe: "Generate professional documents by doc-smith",
|
|
18
|
-
aliases: ["docsmith", "doc"],
|
|
19
|
-
builder: async (yargs) => {
|
|
20
|
-
const aigne = await loadApplication({ name: "doc-smith" });
|
|
21
|
-
for (const agent of aigne.agents) {
|
|
22
|
-
yargs.command(agent.name, agent.description || "", (yargs) => {
|
|
23
|
-
const options = Object.entries(agent.inputSchema instanceof ZodObject ? agent.inputSchema.shape : {});
|
|
24
|
-
for (const [option, config] of options) {
|
|
25
|
-
yargs.option(option, {
|
|
26
|
-
// TODO: support more types
|
|
27
|
-
type: config instanceof ZodString ? "string" : "string",
|
|
28
|
-
description: config.description,
|
|
29
|
-
});
|
|
30
|
-
if (!(config.isNullable() || config.isOptional())) {
|
|
31
|
-
yargs.demandOption(option);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}, async (argv) => {
|
|
35
|
-
try {
|
|
36
|
-
await runAgentWithAIGNE(aigne, agent, { input: argv });
|
|
37
|
-
}
|
|
38
|
-
finally {
|
|
39
|
-
await aigne.shutdown();
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
yargs.version('hello world');
|
|
44
|
-
return yargs.demandCommand();
|
|
45
|
-
},
|
|
46
|
-
handler: () => { },
|
|
47
|
-
},
|
|
48
|
-
];
|
|
49
|
-
}
|
|
50
|
-
async function loadApplication({ name }) {
|
|
51
|
-
const info = await shouldDownloadNewVersion(name);
|
|
52
|
-
if (info.shouldDownload) {
|
|
53
|
-
assert(info.url, "Package URL should be defined when downloading");
|
|
54
|
-
// TODO: clean up old versions
|
|
55
|
-
await mkdir(info.dir, { recursive: true });
|
|
56
|
-
await downloadAndExtract(info.url.toString(), info.dir, { strip: 1 });
|
|
57
|
-
spawnSync("npm", ["install", "--omit", "dev"], { cwd: info.dir, stdio: "inherit" });
|
|
58
|
-
}
|
|
59
|
-
return AIGNE.load(info.dir, { models: availableModels() });
|
|
60
|
-
}
|
|
61
|
-
async function shouldDownloadNewVersion(name, { cacheTimeMs = NPM_PACKAGE_CACHE_TIME_MS } = {}) {
|
|
62
|
-
const nameWithOrg = `@aigne/${name}`;
|
|
63
|
-
const dir = join(homedir(), ".aigne", "registry.npmjs.org", nameWithOrg);
|
|
64
|
-
const s = await stat(join(dir, "package.json")).catch((error) => {
|
|
65
|
-
if (error.code === "ENOENT") {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
throw error;
|
|
69
|
-
});
|
|
70
|
-
if (!s)
|
|
71
|
-
return {
|
|
72
|
-
shouldDownload: true,
|
|
73
|
-
dir,
|
|
74
|
-
url: await getNpmTgzInfo(nameWithOrg).then((info) => info.tarballUrl),
|
|
75
|
-
};
|
|
76
|
-
const lastModified = s.mtimeMs;
|
|
77
|
-
const now = Date.now();
|
|
78
|
-
if (now - lastModified > cacheTimeMs) {
|
|
79
|
-
const version = JSON.parse(await readFile(join(dir, "package.json"), "utf-8")).version;
|
|
80
|
-
const latest = await getNpmTgzInfo(`@aigne/${name}`);
|
|
81
|
-
if (version !== latest.version) {
|
|
82
|
-
return { shouldDownload: true, url: latest.tarballUrl, dir };
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return { shouldDownload: false, dir };
|
|
86
|
-
}
|
|
87
|
-
async function getNpmTgzInfo(name) {
|
|
88
|
-
const res = await fetch(joinURL("https://registry.npmjs.org", name));
|
|
89
|
-
if (!res.ok)
|
|
90
|
-
throw new Error(`Failed to fetch package info for ${name}: ${res.statusText}`);
|
|
91
|
-
const data = await res.json();
|
|
92
|
-
const latestVersion = data["dist-tags"].latest;
|
|
93
|
-
const tarballUrl = data.versions[latestVersion].dist.tarball;
|
|
94
|
-
return {
|
|
95
|
-
version: latestVersion,
|
|
96
|
-
tarballUrl,
|
|
97
|
-
};
|
|
98
|
-
}
|