@aigne/cli 1.27.0 → 1.27.1-1
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/dist/cli.d.ts +6 -1
- package/dist/cli.js +3 -2
- package/dist/commands/aigne.d.ts +2 -2
- package/dist/commands/aigne.js +17 -12
- package/dist/commands/app.d.ts +2 -0
- package/dist/commands/app.js +203 -0
- package/dist/commands/connect.d.ts +6 -2
- package/dist/commands/connect.js +32 -27
- package/dist/commands/create.d.ts +6 -2
- package/dist/commands/create.js +62 -58
- package/dist/commands/observe.d.ts +7 -2
- package/dist/commands/observe.js +22 -13
- package/dist/commands/run.d.ts +3 -3
- package/dist/commands/run.js +94 -79
- package/dist/commands/serve-mcp.d.ts +10 -3
- package/dist/commands/serve-mcp.js +41 -23
- package/dist/commands/test.d.ts +7 -3
- package/dist/commands/test.js +20 -14
- package/dist/utils/download.d.ts +3 -1
- package/dist/utils/download.js +2 -2
- package/dist/utils/run-with-aigne.d.ts +27 -2
- package/dist/utils/run-with-aigne.js +82 -58
- package/package.json +9 -8
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
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";
|
|
5
6
|
import { createAIGNECommand } from "./commands/aigne.js";
|
|
6
7
|
config({ silent: true });
|
|
7
8
|
function getAIGNEFilePath() {
|
|
@@ -15,8 +16,8 @@ function getAIGNEFilePath() {
|
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
const aigneFilePath = getAIGNEFilePath();
|
|
18
|
-
createAIGNECommand({ aigneFilePath })
|
|
19
|
-
.parseAsync([
|
|
19
|
+
export default createAIGNECommand({ aigneFilePath })
|
|
20
|
+
.parseAsync(hideBin([...process.argv.slice(0, 2), ...process.argv.slice(aigneFilePath ? 3 : 2)]))
|
|
20
21
|
.catch((error) => {
|
|
21
22
|
console.log(""); // Add an empty line for better readability
|
|
22
23
|
console.error(`${chalk.red("Error:")} ${error.message}`);
|
package/dist/commands/aigne.d.ts
CHANGED
package/dist/commands/aigne.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import yargs from "yargs";
|
|
2
2
|
import { AIGNE_CLI_VERSION } from "../constants.js";
|
|
3
3
|
import { asciiLogo } from "../utils/ascii-logo.js";
|
|
4
|
+
import { createAppCommands } from "./app.js";
|
|
4
5
|
import { createConnectCommand } from "./connect.js";
|
|
5
6
|
import { createCreateCommand } from "./create.js";
|
|
6
7
|
import { createObservabilityCommand } from "./observe.js";
|
|
@@ -9,16 +10,20 @@ import { createServeMCPCommand } from "./serve-mcp.js";
|
|
|
9
10
|
import { createTestCommand } from "./test.js";
|
|
10
11
|
export function createAIGNECommand(options) {
|
|
11
12
|
console.log(asciiLogo);
|
|
12
|
-
return
|
|
13
|
-
.
|
|
14
|
-
.
|
|
13
|
+
return yargs()
|
|
14
|
+
.scriptName("aigne")
|
|
15
|
+
.usage("CLI for AIGNE framework")
|
|
15
16
|
.version(AIGNE_CLI_VERSION)
|
|
16
|
-
.
|
|
17
|
-
.
|
|
18
|
-
.
|
|
19
|
-
.
|
|
20
|
-
.
|
|
21
|
-
.
|
|
22
|
-
.
|
|
23
|
-
.
|
|
17
|
+
.command(createRunCommand(options))
|
|
18
|
+
.command(createTestCommand(options))
|
|
19
|
+
.command(createCreateCommand())
|
|
20
|
+
.command(createServeMCPCommand(options))
|
|
21
|
+
.command(createObservabilityCommand())
|
|
22
|
+
.command(createConnectCommand())
|
|
23
|
+
.command(createAppCommands())
|
|
24
|
+
.help()
|
|
25
|
+
.alias("help", "h")
|
|
26
|
+
.alias("version", "v")
|
|
27
|
+
.showHelpOnFail(true)
|
|
28
|
+
.strict();
|
|
24
29
|
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { extname, join } from "node:path";
|
|
6
|
+
import { isatty } from "node:tty";
|
|
7
|
+
import { AIAgent, AIGNE, readAllString } from "@aigne/core";
|
|
8
|
+
import { pick } from "@aigne/core/utils/type-utils.js";
|
|
9
|
+
import { Listr, PRESET_TIMER } from "@aigne/listr2";
|
|
10
|
+
import { joinURL } from "ufo";
|
|
11
|
+
import { parse } from "yaml";
|
|
12
|
+
import { ZodObject } from "zod";
|
|
13
|
+
import { availableModels } from "../constants.js";
|
|
14
|
+
import { downloadAndExtract } from "../utils/download.js";
|
|
15
|
+
import { loadAIGNE } from "../utils/load-aigne.js";
|
|
16
|
+
import { runAgentWithAIGNE, stdinHasData } from "../utils/run-with-aigne.js";
|
|
17
|
+
const NPM_PACKAGE_CACHE_TIME_MS = 1000 * 60 * 60 * 24; // 1 day
|
|
18
|
+
const builtinApps = [
|
|
19
|
+
{
|
|
20
|
+
name: "doc-smith",
|
|
21
|
+
describe: "Generate professional documents by doc-smith",
|
|
22
|
+
aliases: ["docsmith", "doc"],
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
export function createAppCommands() {
|
|
26
|
+
return builtinApps.map((app) => ({
|
|
27
|
+
command: app.name,
|
|
28
|
+
describe: app.describe,
|
|
29
|
+
aliases: app.aliases,
|
|
30
|
+
builder: async (yargs) => {
|
|
31
|
+
const { aigne, dir, version } = await loadApplication({ name: "doc-smith" });
|
|
32
|
+
for (const agent of aigne.agents) {
|
|
33
|
+
const inputSchema = Object.entries(agent.inputSchema instanceof ZodObject ? agent.inputSchema.shape : {});
|
|
34
|
+
yargs.command(agent.name, agent.description || "", (yargs) => {
|
|
35
|
+
for (const [option, config] of inputSchema) {
|
|
36
|
+
yargs.option(option, {
|
|
37
|
+
// TODO: support more types
|
|
38
|
+
type: "string",
|
|
39
|
+
description: config.description,
|
|
40
|
+
});
|
|
41
|
+
if (!(config.isNullable() || config.isOptional())) {
|
|
42
|
+
yargs.demandOption(option);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
yargs
|
|
46
|
+
.option("input", {
|
|
47
|
+
type: "array",
|
|
48
|
+
description: "Input to the agent, use @<file> to read from a file",
|
|
49
|
+
alias: ["i"],
|
|
50
|
+
})
|
|
51
|
+
.option("format", {
|
|
52
|
+
type: "string",
|
|
53
|
+
description: 'Input format, can be "json" or "yaml"',
|
|
54
|
+
choices: ["json", "yaml"],
|
|
55
|
+
});
|
|
56
|
+
}, async (argv) => {
|
|
57
|
+
try {
|
|
58
|
+
const aigne = await loadAIGNE(dir);
|
|
59
|
+
const _agent = aigne.agents[agent.name];
|
|
60
|
+
assert(_agent, `Agent ${agent.name} not found in ${app.name}`);
|
|
61
|
+
const input = pick(argv, inputSchema.map(([key]) => key));
|
|
62
|
+
const rawInput = argv.input ||
|
|
63
|
+
(isatty(process.stdin.fd) || !(await stdinHasData())
|
|
64
|
+
? null
|
|
65
|
+
: [await readAllString(process.stdin)].filter(Boolean));
|
|
66
|
+
if (rawInput) {
|
|
67
|
+
for (let raw of rawInput) {
|
|
68
|
+
let format = argv.format;
|
|
69
|
+
if (raw.startsWith("@")) {
|
|
70
|
+
raw = await readFile(raw.slice(1), "utf8");
|
|
71
|
+
if (!format) {
|
|
72
|
+
const ext = extname(raw);
|
|
73
|
+
if (ext === ".json")
|
|
74
|
+
format = "json";
|
|
75
|
+
else if (ext === ".yaml" || ext === ".yml")
|
|
76
|
+
format = "yaml";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const inputKey = agent instanceof AIAgent ? agent.inputKey : undefined;
|
|
80
|
+
if (format === "json") {
|
|
81
|
+
Object.assign(input, JSON.parse(raw));
|
|
82
|
+
}
|
|
83
|
+
else if (format === "yaml") {
|
|
84
|
+
Object.assign(input, parse(raw));
|
|
85
|
+
}
|
|
86
|
+
else if (inputKey) {
|
|
87
|
+
Object.assign(input, { [inputKey]: raw });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
await runAgentWithAIGNE(aigne, _agent, { input });
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
await aigne.shutdown();
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
yargs.version(`${app.name} v${version}`);
|
|
99
|
+
return yargs.demandCommand();
|
|
100
|
+
},
|
|
101
|
+
handler: () => { },
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
async function loadApplication({ name, }) {
|
|
105
|
+
name = `@aigne/${name}`;
|
|
106
|
+
const dir = join(homedir(), ".aigne", "registry.npmjs.org", name);
|
|
107
|
+
const check = await isInstallationAvailable(dir);
|
|
108
|
+
if (check?.available) {
|
|
109
|
+
return {
|
|
110
|
+
aigne: await AIGNE.load(dir, { models: availableModels() }),
|
|
111
|
+
dir,
|
|
112
|
+
version: check.version,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const result = await new Listr([
|
|
116
|
+
{
|
|
117
|
+
title: "Fetching application metadata",
|
|
118
|
+
task: async (ctx) => {
|
|
119
|
+
const info = await getNpmTgzInfo(name);
|
|
120
|
+
Object.assign(ctx, info);
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
title: "Downloading application",
|
|
125
|
+
skip: (ctx) => ctx.version === check?.version,
|
|
126
|
+
task: async (ctx) => {
|
|
127
|
+
await downloadApplication({ url: ctx.url, dir });
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
title: "Installing dependencies",
|
|
132
|
+
skip: (ctx) => ctx.version === check?.version,
|
|
133
|
+
task: async () => {
|
|
134
|
+
await installDependencies(dir);
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
], {
|
|
138
|
+
rendererOptions: {
|
|
139
|
+
collapseSubtasks: false,
|
|
140
|
+
showErrorMessage: false,
|
|
141
|
+
timer: PRESET_TIMER,
|
|
142
|
+
},
|
|
143
|
+
}).run();
|
|
144
|
+
return {
|
|
145
|
+
aigne: await AIGNE.load(dir, { models: availableModels() }),
|
|
146
|
+
dir,
|
|
147
|
+
version: result.version,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
async function isInstallationAvailable(dir, { cacheTimeMs = NPM_PACKAGE_CACHE_TIME_MS } = {}) {
|
|
151
|
+
const s = await stat(join(dir, "package.json")).catch((error) => {
|
|
152
|
+
if (error.code === "ENOENT") {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
throw error;
|
|
156
|
+
});
|
|
157
|
+
if (!s)
|
|
158
|
+
return null;
|
|
159
|
+
const version = safeParseJSON(await readFile(join(dir, "package.json"), "utf-8"))?.version;
|
|
160
|
+
if (!version)
|
|
161
|
+
return null;
|
|
162
|
+
const installedAt = safeParseJSON(await readFile(join(dir, ".aigne-cli.json"), "utf-8").catch(() => "{}"))?.installedAt;
|
|
163
|
+
if (!installedAt)
|
|
164
|
+
return null;
|
|
165
|
+
const now = Date.now();
|
|
166
|
+
const available = installedAt ? now - installedAt < cacheTimeMs : false;
|
|
167
|
+
return { version, available };
|
|
168
|
+
}
|
|
169
|
+
async function downloadApplication({ url, dir }) {
|
|
170
|
+
await mkdir(dir, { recursive: true });
|
|
171
|
+
await downloadAndExtract(url, dir, { strip: 1 });
|
|
172
|
+
}
|
|
173
|
+
async function installDependencies(dir) {
|
|
174
|
+
const { stderr, status } = spawnSync("npm", ["install", "--omit", "dev"], {
|
|
175
|
+
cwd: dir,
|
|
176
|
+
stdio: "pipe",
|
|
177
|
+
});
|
|
178
|
+
if (status !== 0) {
|
|
179
|
+
console.error(stderr.toString());
|
|
180
|
+
throw new Error(`Failed to install dependencies in ${dir}`);
|
|
181
|
+
}
|
|
182
|
+
await writeFile(join(dir, ".aigne-cli.json"), JSON.stringify({ installedAt: Date.now() }, null, 2));
|
|
183
|
+
}
|
|
184
|
+
async function getNpmTgzInfo(name) {
|
|
185
|
+
const res = await fetch(joinURL("https://registry.npmjs.org", name));
|
|
186
|
+
if (!res.ok)
|
|
187
|
+
throw new Error(`Failed to fetch package info for ${name}: ${res.statusText}`);
|
|
188
|
+
const data = await res.json();
|
|
189
|
+
const latestVersion = data["dist-tags"].latest;
|
|
190
|
+
const url = data.versions[latestVersion].dist.tarball;
|
|
191
|
+
return {
|
|
192
|
+
version: latestVersion,
|
|
193
|
+
url,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function safeParseJSON(raw) {
|
|
197
|
+
try {
|
|
198
|
+
return JSON.parse(raw);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { CommandModule } from "yargs";
|
|
2
|
+
interface ConnectOptions {
|
|
3
|
+
url?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function createConnectCommand(): CommandModule<unknown, ConnectOptions>;
|
|
6
|
+
export {};
|
package/dist/commands/connect.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import chalk from "chalk";
|
|
4
|
-
import { Command } from "commander";
|
|
5
4
|
import { parse } from "yaml";
|
|
6
5
|
import { getUserInfo } from "../utils/aigne-hub-user.js";
|
|
7
6
|
import { AIGNE_ENV_FILE, connectToAIGNEHub } from "../utils/load-aigne.js";
|
|
@@ -57,30 +56,36 @@ async function displayStatus(statusList) {
|
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
58
|
export function createConnectCommand() {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
console.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
59
|
+
return {
|
|
60
|
+
command: "connect [url]",
|
|
61
|
+
describe: "Manage AIGNE Hub connections",
|
|
62
|
+
builder: (yargs) => {
|
|
63
|
+
return yargs
|
|
64
|
+
.positional("url", {
|
|
65
|
+
describe: "URL to the AIGNE Hub server",
|
|
66
|
+
type: "string",
|
|
67
|
+
default: "https://hub.aigne.io/",
|
|
68
|
+
})
|
|
69
|
+
.command({
|
|
70
|
+
command: "status",
|
|
71
|
+
describe: "Show current connection status",
|
|
72
|
+
handler: async () => {
|
|
73
|
+
const statusList = await getConnectionStatus();
|
|
74
|
+
await displayStatus(statusList);
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
handler: async (argv) => {
|
|
79
|
+
const url = argv.url || "https://hub.aigne.io/";
|
|
80
|
+
console.log(chalk.blue(`Connecting to AIGNE Hub: ${url}`));
|
|
81
|
+
try {
|
|
82
|
+
await connectToAIGNEHub(url);
|
|
83
|
+
console.log(chalk.green("✓ Successfully connected to AIGNE Hub"));
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
console.error(chalk.red("✗ Failed to connect to AIGNE Hub:"), error.message);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
};
|
|
86
91
|
}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { CommandModule } from "yargs";
|
|
2
|
+
interface CreateOptions {
|
|
3
|
+
path: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function createCreateCommand(): CommandModule<unknown, CreateOptions>;
|
|
6
|
+
export {};
|
package/dist/commands/create.js
CHANGED
|
@@ -1,69 +1,73 @@
|
|
|
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";
|
|
5
4
|
import inquirer from "inquirer";
|
|
6
5
|
export function createCreateCommand() {
|
|
7
|
-
return
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
6
|
+
return {
|
|
7
|
+
command: "create [path]",
|
|
8
|
+
describe: "Create a new aigne project with agent config files",
|
|
9
|
+
builder: (yargs) => {
|
|
10
|
+
return yargs.positional("path", {
|
|
11
|
+
describe: "Path to create the project directory",
|
|
12
|
+
type: "string",
|
|
13
|
+
default: ".",
|
|
14
|
+
});
|
|
15
|
+
},
|
|
16
|
+
handler: async ({ path }) => {
|
|
17
|
+
if (path === ".") {
|
|
18
|
+
const answers = await inquirer.prompt([
|
|
19
|
+
{
|
|
20
|
+
type: "input",
|
|
21
|
+
name: "projectName",
|
|
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
|
+
},
|
|
23
29
|
},
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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,
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
if (!answers.overwrite) {
|
|
45
|
+
console.log("Operation cancelled.");
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const templates = [{ name: "default" }];
|
|
50
|
+
const { template } = await inquirer.prompt([
|
|
32
51
|
{
|
|
33
|
-
type: "
|
|
34
|
-
name: "
|
|
35
|
-
message:
|
|
36
|
-
|
|
52
|
+
type: "list",
|
|
53
|
+
name: "template",
|
|
54
|
+
message: "Select a template:",
|
|
55
|
+
choices: templates.map((t) => t.name),
|
|
56
|
+
default: "default",
|
|
37
57
|
},
|
|
38
58
|
]);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
59
|
+
mkdirSync(path, { recursive: true });
|
|
60
|
+
const templatePath = join(import.meta.dirname, "../../templates", template);
|
|
61
|
+
if (!existsSync(templatePath))
|
|
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 });
|
|
42
68
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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);
|
|
69
|
+
console.log("\n✅ AIGNE project created successfully!");
|
|
70
|
+
console.log(`\nTo use your new agent, run:\n cd ${relative(process.cwd(), path)} && aigne run`);
|
|
71
|
+
},
|
|
72
|
+
};
|
|
69
73
|
}
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { CommandModule } from "yargs";
|
|
2
|
+
interface ServeMCPOptions {
|
|
3
|
+
host: string;
|
|
4
|
+
port?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function createObservabilityCommand(): CommandModule<unknown, ServeMCPOptions>;
|
|
7
|
+
export {};
|
package/dist/commands/observe.js
CHANGED
|
@@ -2,7 +2,6 @@ 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";
|
|
6
5
|
import detectPort from "detect-port";
|
|
7
6
|
const DEFAULT_PORT = () => tryOrThrow(() => {
|
|
8
7
|
const { PORT } = process.env;
|
|
@@ -14,16 +13,26 @@ const DEFAULT_PORT = () => tryOrThrow(() => {
|
|
|
14
13
|
return port;
|
|
15
14
|
}, (error) => new Error(`parse PORT error ${error.message}`));
|
|
16
15
|
export function createObservabilityCommand() {
|
|
17
|
-
return
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
16
|
+
return {
|
|
17
|
+
command: "observe",
|
|
18
|
+
describe: "Start the observability server",
|
|
19
|
+
builder: (yargs) => {
|
|
20
|
+
return yargs
|
|
21
|
+
.option("host", {
|
|
22
|
+
type: "string",
|
|
23
|
+
describe: "Host to run the observability server on, use 0.0.0.0 to publicly expose the server",
|
|
24
|
+
default: "localhost",
|
|
25
|
+
})
|
|
26
|
+
.option("port", {
|
|
27
|
+
type: "number",
|
|
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
|
+
};
|
|
29
38
|
}
|
package/dist/commands/run.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function createRunCommand({ aigneFilePath }?: {
|
|
1
|
+
import type { CommandModule } from "yargs";
|
|
2
|
+
export declare function createRunCommand({ aigneFilePath, }?: {
|
|
3
3
|
aigneFilePath?: string;
|
|
4
|
-
}):
|
|
4
|
+
}): CommandModule;
|
package/dist/commands/run.js
CHANGED
|
@@ -12,94 +12,109 @@ 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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
15
|
+
export function createRunCommand({ aigneFilePath, } = {}) {
|
|
16
|
+
return {
|
|
17
|
+
command: "run [path]",
|
|
18
|
+
describe: "Run AIGNE from the specified agent",
|
|
19
|
+
builder: (yargs) => {
|
|
20
|
+
return createRunAIGNECommand(yargs)
|
|
21
|
+
.positional("path", {
|
|
22
|
+
describe: "Path to the agents directory or URL to aigne project",
|
|
23
|
+
type: "string",
|
|
24
|
+
default: ".",
|
|
25
|
+
alias: ["url"],
|
|
26
|
+
})
|
|
27
|
+
.option("entry-agent", {
|
|
28
|
+
describe: "Name of the agent to run (defaults to the first agent found)",
|
|
29
|
+
type: "string",
|
|
30
|
+
})
|
|
31
|
+
.option("cache-dir", {
|
|
32
|
+
describe: "Directory to download the package to (defaults to the ~/.aigne/xxx)",
|
|
33
|
+
type: "string",
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
handler: async (argv) => {
|
|
37
|
+
const options = argv;
|
|
38
|
+
const path = aigneFilePath || options.path;
|
|
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
|
+
},
|
|
42
59
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
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 }));
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
ctx.aigne = aigne;
|
|
74
|
+
},
|
|
58
75
|
},
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
throw new Error(`\
|
|
76
|
+
{
|
|
77
|
+
task: (ctx) => {
|
|
78
|
+
const { aigne } = ctx;
|
|
79
|
+
assert(aigne);
|
|
80
|
+
let entryAgent;
|
|
81
|
+
if (options.entryAgent) {
|
|
82
|
+
entryAgent = aigne.agents[options.entryAgent];
|
|
83
|
+
if (!entryAgent) {
|
|
84
|
+
throw new Error(`\
|
|
69
85
|
Agent "${options.entryAgent}" not found in ${aigne.rootDir}
|
|
70
86
|
|
|
71
87
|
Available agents:
|
|
72
88
|
${aigne.agents.map((agent) => ` - ${agent.name}`).join("\n")}
|
|
73
89
|
`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
entryAgent = aigne.agents[0];
|
|
94
|
+
if (!entryAgent)
|
|
95
|
+
throw new Error(`No any agent found in ${aigne.rootDir}`);
|
|
74
96
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
97
|
+
ctx.agent = entryAgent;
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
], {
|
|
101
|
+
rendererOptions: {
|
|
102
|
+
collapseSubtasks: false,
|
|
103
|
+
showErrorMessage: false,
|
|
104
|
+
timer: PRESET_TIMER,
|
|
82
105
|
},
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
await runAgentWithAIGNE(aigne, agent, { ...options, input });
|
|
96
|
-
}
|
|
97
|
-
finally {
|
|
98
|
-
await aigne.shutdown();
|
|
99
|
-
}
|
|
100
|
-
})
|
|
101
|
-
.showHelpAfterError(true)
|
|
102
|
-
.showSuggestionAfterError(true);
|
|
106
|
+
}).run();
|
|
107
|
+
assert(aigne);
|
|
108
|
+
assert(agent);
|
|
109
|
+
const input = await parseAgentInputByCommander(agent, options);
|
|
110
|
+
try {
|
|
111
|
+
await runAgentWithAIGNE(aigne, agent, { ...options, input });
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
await aigne.shutdown();
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
};
|
|
103
118
|
}
|
|
104
119
|
async function downloadPackage(url, cacheDir) {
|
|
105
120
|
await rm(cacheDir, { recursive: true, force: true });
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { CommandModule } from "yargs";
|
|
2
|
+
interface ServeMCPOptions {
|
|
3
|
+
path: string;
|
|
4
|
+
host: string;
|
|
5
|
+
port?: number;
|
|
6
|
+
pathname: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function createServeMCPCommand({ aigneFilePath, }?: {
|
|
3
9
|
aigneFilePath?: string;
|
|
4
|
-
}):
|
|
10
|
+
}): CommandModule<unknown, ServeMCPOptions>;
|
|
11
|
+
export {};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { isAbsolute, resolve } from "node:path";
|
|
2
2
|
import { tryOrThrow } from "@aigne/core/utils/type-utils.js";
|
|
3
|
-
import { Command } from "commander";
|
|
4
3
|
import { loadAIGNE } from "../utils/load-aigne.js";
|
|
5
4
|
import { serveMCPServer } from "../utils/serve-mcp.js";
|
|
6
5
|
const DEFAULT_PORT = () => tryOrThrow(() => {
|
|
@@ -12,26 +11,45 @@ const DEFAULT_PORT = () => tryOrThrow(() => {
|
|
|
12
11
|
throw new Error(`Invalid PORT: ${PORT}`);
|
|
13
12
|
return port;
|
|
14
13
|
}, (error) => new Error(`parse PORT error ${error.message}`));
|
|
15
|
-
export function createServeMCPCommand({ aigneFilePath } = {}) {
|
|
16
|
-
return
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
14
|
+
export function createServeMCPCommand({ aigneFilePath, } = {}) {
|
|
15
|
+
return {
|
|
16
|
+
command: "serve-mcp",
|
|
17
|
+
describe: "Serve the agents in the specified directory as a MCP server (streamable http)",
|
|
18
|
+
builder: (yargs) => {
|
|
19
|
+
return yargs
|
|
20
|
+
.option("path", {
|
|
21
|
+
describe: "Path to the agents directory or URL to aigne project",
|
|
22
|
+
type: "string",
|
|
23
|
+
default: ".",
|
|
24
|
+
alias: ["url"],
|
|
25
|
+
})
|
|
26
|
+
.option("host", {
|
|
27
|
+
describe: "Host to run the MCP server on, use 0.0.0.0 to publicly expose the server",
|
|
28
|
+
type: "string",
|
|
29
|
+
default: "localhost",
|
|
30
|
+
})
|
|
31
|
+
.option("port", {
|
|
32
|
+
describe: "Port to run the MCP server on",
|
|
33
|
+
type: "number",
|
|
34
|
+
})
|
|
35
|
+
.option("pathname", {
|
|
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
|
+
};
|
|
37
55
|
}
|
package/dist/commands/test.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { CommandModule } from "yargs";
|
|
2
|
+
interface TestOptions {
|
|
3
|
+
path: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function createTestCommand({ aigneFilePath, }?: {
|
|
3
6
|
aigneFilePath?: string;
|
|
4
|
-
}):
|
|
7
|
+
}): CommandModule<unknown, TestOptions>;
|
|
8
|
+
export {};
|
package/dist/commands/test.js
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
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";
|
|
5
4
|
import { loadAIGNE } from "../utils/load-aigne.js";
|
|
6
|
-
export function createTestCommand({ aigneFilePath } = {}) {
|
|
7
|
-
return
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
5
|
+
export function createTestCommand({ aigneFilePath, } = {}) {
|
|
6
|
+
return {
|
|
7
|
+
command: "test",
|
|
8
|
+
describe: "Run tests in the specified agents directory",
|
|
9
|
+
builder: (yargs) => {
|
|
10
|
+
return yargs.option("path", {
|
|
11
|
+
describe: "Path to the agents directory or URL to aigne project",
|
|
12
|
+
type: "string",
|
|
13
|
+
default: ".",
|
|
14
|
+
alias: ["url"],
|
|
15
|
+
});
|
|
16
|
+
},
|
|
17
|
+
handler: async (options) => {
|
|
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
|
+
};
|
|
19
25
|
}
|
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, options = {}) {
|
|
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) {
|
|
|
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, ...options })));
|
|
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 type { Argv } from "yargs";
|
|
5
5
|
import { type ChatLoopOptions } from "./run-chat-loop.js";
|
|
6
6
|
export interface RunAIGNECommandOptions {
|
|
7
7
|
chat?: boolean;
|
|
@@ -17,7 +17,31 @@ export interface RunAIGNECommandOptions {
|
|
|
17
17
|
logLevel?: LogLevel;
|
|
18
18
|
force?: boolean;
|
|
19
19
|
}
|
|
20
|
-
export declare const createRunAIGNECommand: (
|
|
20
|
+
export declare const createRunAIGNECommand: (yargs: Argv) => Argv<{
|
|
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
|
+
}>;
|
|
21
45
|
export declare function parseAgentInputByCommander(agent: Agent, options?: RunAIGNECommandOptions & {
|
|
22
46
|
inputKey?: string;
|
|
23
47
|
argv?: string[];
|
|
@@ -41,3 +65,4 @@ export declare function runAgentWithAIGNE(aigne: AIGNE, agent: Agent, { outputKe
|
|
|
41
65
|
} & Omit<RunAIGNECommandOptions, "input">): Promise<{
|
|
42
66
|
result: Message;
|
|
43
67
|
} | undefined>;
|
|
68
|
+
export declare function stdinHasData(): Promise<boolean>;
|
|
@@ -4,67 +4,91 @@ 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 { AIGNE, DEFAULT_OUTPUT_KEY, readAllString, UserAgent, } from "@aigne/core";
|
|
7
|
+
import { AIAgent, 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 { flat, isEmpty, tryOrThrow } from "@aigne/core/utils/type-utils.js";
|
|
11
11
|
import chalk from "chalk";
|
|
12
|
-
import { Command } from "commander";
|
|
13
12
|
import { parse } from "yaml";
|
|
13
|
+
import yargs from "yargs";
|
|
14
|
+
import { hideBin } from "yargs/helpers";
|
|
14
15
|
import { ZodError, ZodObject, z } from "zod";
|
|
15
16
|
import { availableModels } from "../constants.js";
|
|
16
17
|
import { TerminalTracer } from "../tracer/terminal.js";
|
|
17
18
|
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("
|
|
19
|
+
export const createRunAIGNECommand = (yargs) => yargs
|
|
20
|
+
.option("chat", {
|
|
21
|
+
describe: "Run chat loop in terminal",
|
|
22
|
+
type: "boolean",
|
|
23
|
+
default: false,
|
|
24
|
+
})
|
|
25
|
+
.option("model", {
|
|
26
|
+
describe: `AI model to use in format 'provider[:model]' where model is optional. Examples: 'openai' or 'openai:gpt-4o-mini'. Available providers: ${availableModels()
|
|
27
|
+
.map((i) => i.name.toLowerCase().replace(/ChatModel$/i, ""))
|
|
28
|
+
.join(", ")} (default: openai)`,
|
|
29
|
+
type: "string",
|
|
30
|
+
})
|
|
31
|
+
.option("temperature", {
|
|
32
|
+
describe: "Temperature for the model (controls randomness, higher values produce more random outputs). Range: 0.0-2.0",
|
|
33
|
+
type: "number",
|
|
34
|
+
coerce: customZodError("--temperature", (s) => z.coerce.number().min(0).max(2).parse(s)),
|
|
35
|
+
})
|
|
36
|
+
.option("top-p", {
|
|
37
|
+
describe: "Top P (nucleus sampling) parameter for the model (controls diversity). Range: 0.0-1.0",
|
|
38
|
+
type: "number",
|
|
39
|
+
coerce: customZodError("--top-p", (s) => z.coerce.number().min(0).max(1).parse(s)),
|
|
40
|
+
})
|
|
41
|
+
.option("presence-penalty", {
|
|
42
|
+
describe: "Presence penalty for the model (penalizes repeating the same tokens). Range: -2.0 to 2.0",
|
|
43
|
+
type: "number",
|
|
44
|
+
coerce: customZodError("--presence-penalty", (s) => z.coerce.number().min(-2).max(2).parse(s)),
|
|
45
|
+
})
|
|
46
|
+
.option("frequency-penalty", {
|
|
47
|
+
describe: "Frequency penalty for the model (penalizes frequency of token usage). Range: -2.0 to 2.0",
|
|
48
|
+
type: "number",
|
|
49
|
+
coerce: customZodError("--frequency-penalty", (s) => z.coerce.number().min(-2).max(2).parse(s)),
|
|
50
|
+
})
|
|
51
|
+
.option("input", {
|
|
52
|
+
describe: "Input to the agent, use @<file> to read from a file",
|
|
53
|
+
type: "array",
|
|
54
|
+
alias: "i",
|
|
55
|
+
})
|
|
56
|
+
.option("format", {
|
|
57
|
+
describe: "Input format for the agent (available: text, json, yaml default: text)",
|
|
58
|
+
type: "string",
|
|
59
|
+
})
|
|
60
|
+
.option("output", {
|
|
61
|
+
describe: "Output file to save the result (default: stdout)",
|
|
62
|
+
type: "string",
|
|
63
|
+
alias: "o",
|
|
64
|
+
})
|
|
65
|
+
.option("output-key", {
|
|
66
|
+
describe: "Key in the result to save to the output file",
|
|
67
|
+
type: "string",
|
|
68
|
+
default: DEFAULT_OUTPUT_KEY,
|
|
69
|
+
})
|
|
70
|
+
.option("force", {
|
|
71
|
+
describe: "Truncate the output file if it exists, and create directory if the output path is not exists",
|
|
72
|
+
type: "boolean",
|
|
73
|
+
default: false,
|
|
74
|
+
})
|
|
75
|
+
.option("log-level", {
|
|
76
|
+
describe: `Log level for detailed debugging information. Values: ${Object.values(LogLevel).join(", ")}`,
|
|
77
|
+
type: "string",
|
|
78
|
+
default: getLevelFromEnv(logger.options.ns) || LogLevel.INFO,
|
|
79
|
+
coerce: customZodError("--log-level", (s) => z.nativeEnum(LogLevel).parse(s)),
|
|
80
|
+
});
|
|
36
81
|
export async function parseAgentInputByCommander(agent, options = {}) {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
});
|
|
82
|
+
const inputSchemaShape = flat(agent instanceof AIAgent ? agent.inputKey : undefined, agent.inputSchema instanceof ZodObject ? Object.keys(agent.inputSchema.shape) : []);
|
|
83
|
+
const parsedInput = await yargs().parseAsync(options.argv ?? process.argv);
|
|
84
|
+
const input = Object.fromEntries(await Promise.all(inputSchemaShape.map(async (key) => {
|
|
85
|
+
const k = `input${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
86
|
+
let value = parsedInput[k];
|
|
87
|
+
if (typeof value === "string" && value.startsWith("@")) {
|
|
88
|
+
value = await readFile(value.slice(1), "utf8");
|
|
89
|
+
}
|
|
90
|
+
return [key, value];
|
|
91
|
+
})));
|
|
68
92
|
const rawInput = options.input ||
|
|
69
93
|
(isatty(process.stdin.fd) || !(await stdinHasData())
|
|
70
94
|
? null
|
|
@@ -100,10 +124,8 @@ export const parseModelOption = (model) => {
|
|
|
100
124
|
return { provider, name };
|
|
101
125
|
};
|
|
102
126
|
export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoopOptions, modelOptions, outputKey, } = {}) {
|
|
103
|
-
await
|
|
104
|
-
.
|
|
105
|
-
.showSuggestionAfterError(true)
|
|
106
|
-
.action(async (options) => {
|
|
127
|
+
await yargs()
|
|
128
|
+
.command("$0", "Run an agent with AIGNE", (yargs) => createRunAIGNECommand(yargs), async (options) => {
|
|
107
129
|
if (options.logLevel) {
|
|
108
130
|
logger.level = options.logLevel;
|
|
109
131
|
}
|
|
@@ -134,7 +156,9 @@ export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoop
|
|
|
134
156
|
await aigne.shutdown();
|
|
135
157
|
}
|
|
136
158
|
})
|
|
137
|
-
.
|
|
159
|
+
.alias("h", "help")
|
|
160
|
+
.alias("v", "version")
|
|
161
|
+
.parseAsync(hideBin(argv))
|
|
138
162
|
.catch((error) => {
|
|
139
163
|
console.error(`${chalk.red("Error:")} ${error.message}`);
|
|
140
164
|
process.exit(1);
|
|
@@ -186,7 +210,7 @@ export async function runAgentWithAIGNE(aigne, agent, { outputKey, chatLoopOptio
|
|
|
186
210
|
}
|
|
187
211
|
return { result };
|
|
188
212
|
}
|
|
189
|
-
async function stdinHasData() {
|
|
213
|
+
export async function stdinHasData() {
|
|
190
214
|
const stats = await promisify(fstat)(0);
|
|
191
215
|
return stats.isFIFO() || stats.isFile();
|
|
192
216
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/cli",
|
|
3
|
-
"version": "1.27.
|
|
3
|
+
"version": "1.27.1-1",
|
|
4
4
|
"description": "cli for AIGNE framework",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -51,7 +51,6 @@
|
|
|
51
51
|
"@ocap/mcrypto": "^1.21.0",
|
|
52
52
|
"@smithy/node-http-handler": "^4.1.0",
|
|
53
53
|
"chalk": "^5.4.1",
|
|
54
|
-
"commander": "^14.0.0",
|
|
55
54
|
"crypto": "^1.0.1",
|
|
56
55
|
"detect-port": "^2.1.0",
|
|
57
56
|
"dotenv-flow": "^4.1.0",
|
|
@@ -69,21 +68,22 @@
|
|
|
69
68
|
"tar": "^7.4.3",
|
|
70
69
|
"wrap-ansi": "^9.0.0",
|
|
71
70
|
"yaml": "^2.8.0",
|
|
71
|
+
"yargs": "^18.0.0",
|
|
72
72
|
"zod": "^3.25.67",
|
|
73
|
-
"@aigne/agent-library": "^1.21.6",
|
|
74
|
-
"@aigne/aigne-hub": "^0.3.0",
|
|
75
73
|
"@aigne/agentic-memory": "^1.0.6",
|
|
76
|
-
"@aigne/
|
|
74
|
+
"@aigne/agent-library": "^1.21.6",
|
|
77
75
|
"@aigne/bedrock": "^0.8.6",
|
|
76
|
+
"@aigne/aigne-hub": "^0.3.0",
|
|
77
|
+
"@aigne/core": "^1.39.0",
|
|
78
78
|
"@aigne/deepseek": "^0.7.6",
|
|
79
|
+
"@aigne/anthropic": "^0.10.2",
|
|
79
80
|
"@aigne/default-memory": "^1.0.6",
|
|
80
81
|
"@aigne/gemini": "^0.8.6",
|
|
81
82
|
"@aigne/observability-api": "^0.8.2",
|
|
82
83
|
"@aigne/open-router": "^0.7.6",
|
|
83
|
-
"@aigne/ollama": "^0.7.6",
|
|
84
|
-
"@aigne/core": "^1.39.0",
|
|
85
84
|
"@aigne/openai": "^0.10.6",
|
|
86
|
-
"@aigne/xai": "^0.7.6"
|
|
85
|
+
"@aigne/xai": "^0.7.6",
|
|
86
|
+
"@aigne/ollama": "^0.7.6"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
89
|
"@types/archiver": "^6.0.3",
|
|
@@ -92,6 +92,7 @@
|
|
|
92
92
|
"@types/glob": "^9.0.0",
|
|
93
93
|
"@types/gradient-string": "^1.1.6",
|
|
94
94
|
"@types/node": "^24.0.12",
|
|
95
|
+
"@types/yargs": "^17.0.33",
|
|
95
96
|
"archiver": "^7.0.1",
|
|
96
97
|
"hono": "4.8.4",
|
|
97
98
|
"npm-run-all": "^4.1.5",
|