@aigne/cli 1.29.0 → 1.30.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/CHANGELOG.md +46 -0
- package/dist/commands/aigne.js +2 -0
- package/dist/commands/app.d.ts +4 -1
- package/dist/commands/app.js +47 -19
- package/dist/commands/connect.d.ts +7 -0
- package/dist/commands/connect.js +14 -5
- package/dist/constants.d.ts +0 -2
- package/dist/constants.js +0 -76
- package/dist/tracer/terminal.js +3 -1
- package/dist/utils/listr.d.ts +1 -0
- package/dist/utils/listr.js +35 -21
- package/dist/utils/load-aigne.d.ts +7 -3
- package/dist/utils/load-aigne.js +41 -33
- package/dist/utils/run-with-aigne.js +8 -4
- package/package.json +8 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.30.1](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.30.0...cli-v1.30.1) (2025-08-04)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **cli:** persist prompts log and improve terminal output ([#307](https://github.com/AIGNE-io/aigne-framework/issues/307)) ([ac8116f](https://github.com/AIGNE-io/aigne-framework/commit/ac8116fc46f26169e7619860c392fb9f66bc3fee))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @aigne/agent-library bumped to 1.21.10
|
|
16
|
+
* @aigne/agentic-memory bumped to 1.0.10
|
|
17
|
+
* @aigne/aigne-hub bumped to 0.4.1
|
|
18
|
+
* @aigne/openai bumped to 0.10.10
|
|
19
|
+
* @aigne/core bumped to 1.43.0
|
|
20
|
+
* @aigne/default-memory bumped to 1.0.10
|
|
21
|
+
|
|
22
|
+
## [1.30.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.29.0...cli-v1.30.0) (2025-08-01)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* **cli:** add `--model` option for aigne applications ([#302](https://github.com/AIGNE-io/aigne-framework/issues/302)) ([5d63743](https://github.com/AIGNE-io/aigne-framework/commit/5d63743b8a47be64fd49245983f4f2f9da3197a0))
|
|
28
|
+
* **cli:** add `upgrade` command for aigne app ([#299](https://github.com/AIGNE-io/aigne-framework/issues/299)) ([1bf461a](https://github.com/AIGNE-io/aigne-framework/commit/1bf461ab644b2d810ef81cd3092475496dfc7ddc))
|
|
29
|
+
* support google model and skip check mode when connected to Hub ([#300](https://github.com/AIGNE-io/aigne-framework/issues/300)) ([e992c0f](https://github.com/AIGNE-io/aigne-framework/commit/e992c0f3335a7c512fa807d5b8ad10c9c3bf2351))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Bug Fixes
|
|
33
|
+
|
|
34
|
+
* **cli:** indicator not responsive in macos terminal ([#304](https://github.com/AIGNE-io/aigne-framework/issues/304)) ([336f75b](https://github.com/AIGNE-io/aigne-framework/commit/336f75b8a7dfaf28d78e9a4cfcb4ac8c6a29c469))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### Dependencies
|
|
38
|
+
|
|
39
|
+
* The following workspace dependencies were updated
|
|
40
|
+
* dependencies
|
|
41
|
+
* @aigne/agent-library bumped to 1.21.9
|
|
42
|
+
* @aigne/agentic-memory bumped to 1.0.9
|
|
43
|
+
* @aigne/aigne-hub bumped to 0.4.0
|
|
44
|
+
* @aigne/openai bumped to 0.10.9
|
|
45
|
+
* @aigne/core bumped to 1.42.0
|
|
46
|
+
* @aigne/default-memory bumped to 1.0.9
|
|
47
|
+
* @aigne/observability-api bumped to 0.9.0
|
|
48
|
+
|
|
3
49
|
## [1.29.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.28.0...cli-v1.29.0) (2025-07-31)
|
|
4
50
|
|
|
5
51
|
|
package/dist/commands/aigne.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
1
2
|
import yargs from "yargs";
|
|
2
3
|
import { AIGNE_CLI_VERSION } from "../constants.js";
|
|
3
4
|
import { asciiLogo } from "../utils/ascii-logo.js";
|
|
@@ -10,6 +11,7 @@ import { createServeMCPCommand } from "./serve-mcp.js";
|
|
|
10
11
|
import { createTestCommand } from "./test.js";
|
|
11
12
|
export function createAIGNECommand(options) {
|
|
12
13
|
console.log(asciiLogo);
|
|
14
|
+
console.log(`${chalk.grey("TIPS:")} use ${chalk.greenBright("aigne observe")} to start the observability server.\n`);
|
|
13
15
|
return yargs()
|
|
14
16
|
.scriptName("aigne")
|
|
15
17
|
.usage("CLI for AIGNE framework")
|
package/dist/commands/app.d.ts
CHANGED
|
@@ -7,13 +7,16 @@ export declare function invokeCLIAgentFromDir(options: {
|
|
|
7
7
|
input: Message & {
|
|
8
8
|
input?: string[];
|
|
9
9
|
format?: "yaml" | "json";
|
|
10
|
+
model?: string;
|
|
10
11
|
};
|
|
11
12
|
}): Promise<void>;
|
|
12
|
-
export declare function loadApplication({ name, dir, }: {
|
|
13
|
+
export declare function loadApplication({ name, dir, forceUpgrade, }: {
|
|
13
14
|
name: string;
|
|
14
15
|
dir?: string;
|
|
16
|
+
forceUpgrade?: boolean;
|
|
15
17
|
}): Promise<{
|
|
16
18
|
aigne: AIGNE;
|
|
17
19
|
dir: string;
|
|
18
20
|
version: string;
|
|
21
|
+
isCache?: boolean;
|
|
19
22
|
}>;
|
package/dist/commands/app.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
|
-
import {
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
3
|
import { readFile, stat, writeFile } from "node:fs/promises";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { extname, join } from "node:path";
|
|
6
6
|
import { isatty } from "node:tty";
|
|
7
|
+
import { loadModel } from "@aigne/aigne-hub";
|
|
7
8
|
import { AIAgent, AIGNE, readAllString } from "@aigne/core";
|
|
8
9
|
import { pick } from "@aigne/core/utils/type-utils.js";
|
|
9
10
|
import { Listr, PRESET_TIMER } from "@aigne/listr2";
|
|
10
11
|
import { joinURL } from "ufo";
|
|
11
12
|
import { parse } from "yaml";
|
|
12
13
|
import { ZodObject, ZodString } from "zod";
|
|
13
|
-
import { availableModels } from "../constants.js";
|
|
14
14
|
import { downloadAndExtract } from "../utils/download.js";
|
|
15
15
|
import { loadAIGNE } from "../utils/load-aigne.js";
|
|
16
16
|
import { runAgentWithAIGNE, stdinHasData } from "../utils/run-with-aigne.js";
|
|
@@ -29,8 +29,14 @@ export function createAppCommands() {
|
|
|
29
29
|
describe: app.describe,
|
|
30
30
|
aliases: app.aliases,
|
|
31
31
|
builder: async (yargs) => {
|
|
32
|
-
const { aigne, dir, version } = await loadApplication({ name: app.name });
|
|
33
|
-
yargs
|
|
32
|
+
const { aigne, dir, version, isCache } = await loadApplication({ name: app.name });
|
|
33
|
+
yargs
|
|
34
|
+
.option("model", {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "Model to use for the application, example: openai:gpt-4.1 or google:gemini-2.5-flash",
|
|
37
|
+
})
|
|
38
|
+
.command(serveMcpCommandModule({ name: app.name, dir }))
|
|
39
|
+
.command(upgradeCommandModule({ name: app.name, dir, isLatest: !isCache, version }));
|
|
34
40
|
for (const agent of aigne.cli?.agents ?? []) {
|
|
35
41
|
yargs.command(agentCommandModule({ dir, agent }));
|
|
36
42
|
}
|
|
@@ -64,6 +70,20 @@ const serveMcpCommandModule = ({ name, dir, }) => ({
|
|
|
64
70
|
await serveMCPServerFromDir({ ...options, dir });
|
|
65
71
|
},
|
|
66
72
|
});
|
|
73
|
+
const upgradeCommandModule = ({ name, dir, isLatest, version, }) => ({
|
|
74
|
+
command: "upgrade",
|
|
75
|
+
describe: `Upgrade ${name} to the latest version`,
|
|
76
|
+
handler: async () => {
|
|
77
|
+
if (!isLatest) {
|
|
78
|
+
const result = await loadApplication({ name, dir, forceUpgrade: true });
|
|
79
|
+
if (version !== result.version) {
|
|
80
|
+
console.log(`\n✅ Upgraded ${name} to version ${version}`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
console.log(`\n✅ ${name} is already at the latest version (${version})`);
|
|
85
|
+
},
|
|
86
|
+
});
|
|
67
87
|
const agentCommandModule = ({ dir, agent, }) => {
|
|
68
88
|
const inputSchema = agent.inputSchema instanceof ZodObject ? agent.inputSchema.shape : {};
|
|
69
89
|
return {
|
|
@@ -99,7 +119,7 @@ const agentCommandModule = ({ dir, agent, }) => {
|
|
|
99
119
|
};
|
|
100
120
|
};
|
|
101
121
|
export async function invokeCLIAgentFromDir(options) {
|
|
102
|
-
const aigne = await loadAIGNE(options.dir);
|
|
122
|
+
const aigne = await loadAIGNE(options.dir, { model: options.input.model });
|
|
103
123
|
try {
|
|
104
124
|
const agent = aigne.cli.agents[options.agent];
|
|
105
125
|
assert(agent, `Agent ${options.agent} not found in ${options.dir}`);
|
|
@@ -158,27 +178,28 @@ async function readFileAsInput(value, { format } = {}) {
|
|
|
158
178
|
}
|
|
159
179
|
return value;
|
|
160
180
|
}
|
|
161
|
-
export async function loadApplication({ name, dir, }) {
|
|
181
|
+
export async function loadApplication({ name, dir, forceUpgrade = false, }) {
|
|
162
182
|
name = `@aigne/${name}`;
|
|
163
183
|
dir ??= join(homedir(), ".aigne", "registry.npmjs.org", name);
|
|
164
|
-
const check = await isInstallationAvailable(dir);
|
|
184
|
+
const check = forceUpgrade ? undefined : await isInstallationAvailable(dir);
|
|
165
185
|
if (check?.available) {
|
|
166
186
|
return {
|
|
167
|
-
aigne: await AIGNE.load(dir, {
|
|
187
|
+
aigne: await AIGNE.load(dir, { loadModel }),
|
|
168
188
|
dir,
|
|
169
189
|
version: check.version,
|
|
190
|
+
isCache: true,
|
|
170
191
|
};
|
|
171
192
|
}
|
|
172
193
|
const result = await new Listr([
|
|
173
194
|
{
|
|
174
|
-
title:
|
|
195
|
+
title: `Fetching ${name} metadata`,
|
|
175
196
|
task: async (ctx) => {
|
|
176
197
|
const info = await getNpmTgzInfo(name);
|
|
177
198
|
Object.assign(ctx, info);
|
|
178
199
|
},
|
|
179
200
|
},
|
|
180
201
|
{
|
|
181
|
-
title:
|
|
202
|
+
title: `Downloading ${name}`,
|
|
182
203
|
skip: (ctx) => ctx.version === check?.version,
|
|
183
204
|
task: async (ctx) => {
|
|
184
205
|
await downloadAndExtract(ctx.url, dir, { strip: 1 });
|
|
@@ -186,7 +207,6 @@ export async function loadApplication({ name, dir, }) {
|
|
|
186
207
|
},
|
|
187
208
|
{
|
|
188
209
|
title: "Installing dependencies",
|
|
189
|
-
skip: (ctx) => ctx.version === check?.version,
|
|
190
210
|
task: async () => {
|
|
191
211
|
await installDependencies(dir);
|
|
192
212
|
},
|
|
@@ -199,7 +219,7 @@ export async function loadApplication({ name, dir, }) {
|
|
|
199
219
|
},
|
|
200
220
|
}).run();
|
|
201
221
|
return {
|
|
202
|
-
aigne: await AIGNE.load(dir, {
|
|
222
|
+
aigne: await AIGNE.load(dir, { loadModel }),
|
|
203
223
|
dir,
|
|
204
224
|
version: result.version,
|
|
205
225
|
};
|
|
@@ -219,14 +239,22 @@ async function isInstallationAvailable(dir, { cacheTimeMs = NPM_PACKAGE_CACHE_TI
|
|
|
219
239
|
return { version, available };
|
|
220
240
|
}
|
|
221
241
|
async function installDependencies(dir) {
|
|
222
|
-
|
|
223
|
-
cwd: dir,
|
|
224
|
-
|
|
242
|
+
await new Promise((resolve, reject) => {
|
|
243
|
+
const child = spawn("npm", ["install", "--omit", "dev"], { cwd: dir, stdio: "pipe" });
|
|
244
|
+
let stderr = "";
|
|
245
|
+
child.stderr.on("data", (data) => {
|
|
246
|
+
stderr += data.toString();
|
|
247
|
+
});
|
|
248
|
+
child.on("error", (error) => reject(error));
|
|
249
|
+
child.on("exit", (code) => {
|
|
250
|
+
if (code === 0)
|
|
251
|
+
resolve();
|
|
252
|
+
else {
|
|
253
|
+
console.error(stderr);
|
|
254
|
+
reject(new Error(`npm install failed with code ${code}`));
|
|
255
|
+
}
|
|
256
|
+
});
|
|
225
257
|
});
|
|
226
|
-
if (status !== 0) {
|
|
227
|
-
console.error(stderr.toString());
|
|
228
|
-
throw new Error(`Failed to install dependencies in ${dir}`);
|
|
229
|
-
}
|
|
230
258
|
await writeFile(join(dir, ".aigne-cli.json"), JSON.stringify({ installedAt: Date.now() }, null, 2));
|
|
231
259
|
}
|
|
232
260
|
async function getNpmTgzInfo(name) {
|
|
@@ -2,5 +2,12 @@ import type { CommandModule } from "yargs";
|
|
|
2
2
|
interface ConnectOptions {
|
|
3
3
|
url?: string;
|
|
4
4
|
}
|
|
5
|
+
interface StatusInfo {
|
|
6
|
+
host: string;
|
|
7
|
+
apiUrl: string;
|
|
8
|
+
apiKey: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function getConnectionStatus(): Promise<StatusInfo[]>;
|
|
11
|
+
export declare function displayStatus(statusList: StatusInfo[]): Promise<void>;
|
|
5
12
|
export declare function createConnectCommand(): CommandModule<unknown, ConnectOptions>;
|
|
6
13
|
export {};
|
package/dist/commands/connect.js
CHANGED
|
@@ -4,7 +4,11 @@ import chalk from "chalk";
|
|
|
4
4
|
import { parse } from "yaml";
|
|
5
5
|
import { getUserInfo } from "../utils/aigne-hub-user.js";
|
|
6
6
|
import { AIGNE_ENV_FILE, connectToAIGNEHub } from "../utils/load-aigne.js";
|
|
7
|
-
|
|
7
|
+
const formatNumber = (balance) => {
|
|
8
|
+
const balanceNum = String(balance).split(".")[0];
|
|
9
|
+
return chalk.yellow((balanceNum || "").replace(/\B(?=(\d{3})+(?!\d))/g, ","));
|
|
10
|
+
};
|
|
11
|
+
export async function getConnectionStatus() {
|
|
8
12
|
if (!existsSync(AIGNE_ENV_FILE)) {
|
|
9
13
|
return [];
|
|
10
14
|
}
|
|
@@ -25,7 +29,7 @@ async function getConnectionStatus() {
|
|
|
25
29
|
return [];
|
|
26
30
|
}
|
|
27
31
|
}
|
|
28
|
-
async function displayStatus(statusList) {
|
|
32
|
+
export async function displayStatus(statusList) {
|
|
29
33
|
if (statusList.length === 0) {
|
|
30
34
|
console.log(chalk.yellow("No AIGNE Hub connections found."));
|
|
31
35
|
console.log("Use 'aigne connect <url>' to connect to a hub.");
|
|
@@ -46,11 +50,16 @@ async function displayStatus(statusList) {
|
|
|
46
50
|
console.log(` Status: ${statusText}`);
|
|
47
51
|
if (userInfo) {
|
|
48
52
|
console.log(` User: ${userInfo?.user.fullName}`);
|
|
49
|
-
console.log(`
|
|
53
|
+
console.log(` User DID: ${userInfo?.user.did}`);
|
|
54
|
+
if (userInfo?.user.email) {
|
|
55
|
+
console.log(` Email: ${userInfo?.user.email}`);
|
|
56
|
+
}
|
|
50
57
|
if (userInfo?.creditBalance) {
|
|
51
|
-
|
|
58
|
+
const balance = formatNumber(userInfo?.creditBalance?.balance);
|
|
59
|
+
const total = formatNumber(userInfo?.creditBalance?.total);
|
|
60
|
+
console.log(` Plan: ${balance} / ${total}`);
|
|
52
61
|
}
|
|
53
|
-
console.log(` Billing URL: ${userInfo?.paymentLink}`);
|
|
62
|
+
console.log(` Billing URL: ${userInfo?.paymentLink ? chalk.green(userInfo.paymentLink) : chalk.red("N/A")}`);
|
|
54
63
|
}
|
|
55
64
|
console.log("");
|
|
56
65
|
}
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { LoadableModel } from "@aigne/core/loader/index.js";
|
|
2
1
|
import { DefaultMemory } from "@aigne/default-memory";
|
|
3
2
|
export declare const AIGNE_CLI_VERSION: any;
|
|
4
|
-
export declare function availableModels(): LoadableModel[];
|
|
5
3
|
export declare const availableMemories: (typeof DefaultMemory)[];
|
package/dist/constants.js
CHANGED
|
@@ -1,82 +1,6 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { AgenticMemory } from "@aigne/agentic-memory";
|
|
3
|
-
import { AIGNEHubChatModel } from "@aigne/aigne-hub";
|
|
4
|
-
import { AnthropicChatModel } from "@aigne/anthropic";
|
|
5
|
-
import { BedrockChatModel } from "@aigne/bedrock";
|
|
6
|
-
import { DeepSeekChatModel } from "@aigne/deepseek";
|
|
7
3
|
import { DefaultMemory } from "@aigne/default-memory";
|
|
8
|
-
import { GeminiChatModel } from "@aigne/gemini";
|
|
9
|
-
import { OllamaChatModel } from "@aigne/ollama";
|
|
10
|
-
import { OpenRouterChatModel } from "@aigne/open-router";
|
|
11
|
-
import { OpenAIChatModel } from "@aigne/openai";
|
|
12
|
-
import { XAIChatModel } from "@aigne/xai";
|
|
13
|
-
import { NodeHttpHandler, streamCollector } from "@smithy/node-http-handler";
|
|
14
|
-
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
15
4
|
const require = createRequire(import.meta.url);
|
|
16
5
|
export const AIGNE_CLI_VERSION = require("../package.json").version;
|
|
17
|
-
export function availableModels() {
|
|
18
|
-
const proxy = ["HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy", "ALL_PROXY", "all_proxy"]
|
|
19
|
-
.map((i) => process.env[i])
|
|
20
|
-
.filter(Boolean)[0];
|
|
21
|
-
const httpAgent = proxy ? new HttpsProxyAgent(proxy) : undefined;
|
|
22
|
-
const clientOptions = {
|
|
23
|
-
fetchOptions: {
|
|
24
|
-
// @ts-ignore
|
|
25
|
-
agent: httpAgent,
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
return [
|
|
29
|
-
{
|
|
30
|
-
name: OpenAIChatModel.name,
|
|
31
|
-
apiKeyEnvName: "OPENAI_API_KEY",
|
|
32
|
-
create: (params) => new OpenAIChatModel({ ...params, clientOptions }),
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: AnthropicChatModel.name,
|
|
36
|
-
apiKeyEnvName: "ANTHROPIC_API_KEY",
|
|
37
|
-
create: (params) => new AnthropicChatModel({ ...params, clientOptions }),
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
name: BedrockChatModel.name,
|
|
41
|
-
apiKeyEnvName: "AWS_ACCESS_KEY_ID",
|
|
42
|
-
create: (params) => new BedrockChatModel({
|
|
43
|
-
...params,
|
|
44
|
-
clientOptions: {
|
|
45
|
-
requestHandler: NodeHttpHandler.create({ httpAgent, httpsAgent: httpAgent }),
|
|
46
|
-
streamCollector,
|
|
47
|
-
},
|
|
48
|
-
}),
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
name: DeepSeekChatModel.name,
|
|
52
|
-
apiKeyEnvName: "DEEPSEEK_API_KEY",
|
|
53
|
-
create: (params) => new DeepSeekChatModel({ ...params, clientOptions }),
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
name: GeminiChatModel.name,
|
|
57
|
-
apiKeyEnvName: "GEMINI_API_KEY",
|
|
58
|
-
create: (params) => new GeminiChatModel({ ...params, clientOptions }),
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: OllamaChatModel.name,
|
|
62
|
-
apiKeyEnvName: "OLLAMA_API_KEY",
|
|
63
|
-
create: (params) => new OllamaChatModel({ ...params, clientOptions }),
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
name: OpenRouterChatModel.name,
|
|
67
|
-
apiKeyEnvName: "OPEN_ROUTER_API_KEY",
|
|
68
|
-
create: (params) => new OpenRouterChatModel({ ...params, clientOptions }),
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
name: XAIChatModel.name,
|
|
72
|
-
apiKeyEnvName: "XAI_API_KEY",
|
|
73
|
-
create: (params) => new XAIChatModel({ ...params, clientOptions }),
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
name: AIGNEHubChatModel.name,
|
|
77
|
-
apiKeyEnvName: "AIGNE_HUB_API_KEY",
|
|
78
|
-
create: (params) => new AIGNEHubChatModel({ ...params, clientOptions }),
|
|
79
|
-
},
|
|
80
|
-
];
|
|
81
|
-
}
|
|
82
6
|
export const availableMemories = [DefaultMemory, AgenticMemory];
|
package/dist/tracer/terminal.js
CHANGED
|
@@ -70,9 +70,11 @@ export class TerminalTracer {
|
|
|
70
70
|
return undefined;
|
|
71
71
|
return async (config) => {
|
|
72
72
|
const { taskWrapper } = await task.listr.promise;
|
|
73
|
-
|
|
73
|
+
const result = await taskWrapper
|
|
74
74
|
.prompt(ListrInquirerPromptAdapter)
|
|
75
75
|
.run(method, config);
|
|
76
|
+
console.log(`${chalk.blue("✔")} ${chalk.bold(config.message)} ${result}`);
|
|
77
|
+
return result;
|
|
76
78
|
};
|
|
77
79
|
},
|
|
78
80
|
}),
|
package/dist/utils/listr.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ export declare class AIGNEListrRenderer extends DefaultRenderer {
|
|
|
37
37
|
get _options(): AIGNEListrRendererOptions;
|
|
38
38
|
get _spinner(): Spinner;
|
|
39
39
|
update(): void;
|
|
40
|
+
private isPreviousPrompt;
|
|
40
41
|
create({ running, ...options }: Parameters<DefaultRenderer["create"]>[0] & {
|
|
41
42
|
running?: boolean;
|
|
42
43
|
}): string;
|
package/dist/utils/listr.js
CHANGED
|
@@ -47,21 +47,26 @@ export class AIGNEListr extends Listr {
|
|
|
47
47
|
}
|
|
48
48
|
async run(stream) {
|
|
49
49
|
const originalLog = logger.logMessage;
|
|
50
|
+
const originalConsole = { ...console };
|
|
50
51
|
try {
|
|
51
52
|
this.ctx = {};
|
|
52
53
|
this.spinner.start();
|
|
53
|
-
logger.logMessage = (...args) => this.logs.push(format(...args));
|
|
54
54
|
if (logger.enabled(LogLevel.INFO)) {
|
|
55
55
|
const request = this.myOptions.formatRequest();
|
|
56
56
|
if (request)
|
|
57
57
|
console.log(request);
|
|
58
58
|
}
|
|
59
|
+
logger.logMessage = (...args) => this.logs.push(format(...args));
|
|
60
|
+
for (const method of ["debug", "log", "info", "warn", "error"]) {
|
|
61
|
+
console[method] = (...args) => this.logs.push(format(...args));
|
|
62
|
+
}
|
|
59
63
|
const _stream = await stream();
|
|
60
64
|
this.add({ task: () => this.extractStream(_stream) });
|
|
61
65
|
return await super.run().then(() => ({ ...this.result }));
|
|
62
66
|
}
|
|
63
67
|
finally {
|
|
64
68
|
logger.logMessage = originalLog;
|
|
69
|
+
Object.assign(console, originalConsole);
|
|
65
70
|
this.spinner.stop();
|
|
66
71
|
}
|
|
67
72
|
}
|
|
@@ -92,35 +97,44 @@ export class AIGNEListrRenderer extends DefaultRenderer {
|
|
|
92
97
|
update() {
|
|
93
98
|
this._updater(this.create({ running: true }));
|
|
94
99
|
}
|
|
100
|
+
isPreviousPrompt = false;
|
|
95
101
|
create({ running = false, ...options }) {
|
|
96
102
|
const logs = this._options.aigne?.getStdoutLogs?.();
|
|
97
103
|
if (logs?.length) {
|
|
98
104
|
this._updater.clear();
|
|
99
105
|
this._logger.toStdout(logs.join(EOL));
|
|
100
106
|
}
|
|
101
|
-
let
|
|
102
|
-
const bottomBar = this._options.aigne?.getBottomBarLogs?.({ running });
|
|
103
|
-
if (bottomBar?.length) {
|
|
104
|
-
tasks += EOL.repeat(2);
|
|
105
|
-
const output = [...bottomBar, running ? this._spinner.fetch() : ""]
|
|
106
|
-
.map((i) => this._wrap(i))
|
|
107
|
-
.join(EOL);
|
|
108
|
-
// If the task is not running, we show all lines
|
|
109
|
-
if (!running) {
|
|
110
|
-
tasks += output;
|
|
111
|
-
}
|
|
112
|
-
// For running tasks, we only show the last few lines
|
|
113
|
-
else {
|
|
114
|
-
const { rows } = process.stdout;
|
|
115
|
-
const lines = rows - tasks.split(EOL).length - 2;
|
|
116
|
-
tasks += output.split(EOL).slice(-Math.max(4, lines)).join(EOL);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
107
|
+
let buffer = "";
|
|
119
108
|
const prompt = super["renderPrompt"]();
|
|
120
109
|
if (prompt.length) {
|
|
121
|
-
|
|
110
|
+
buffer += prompt.join(EOL);
|
|
111
|
+
this.isPreviousPrompt = true;
|
|
112
|
+
}
|
|
113
|
+
// Skip a frame if previous render was a prompt, and reset the flag
|
|
114
|
+
else if (this.isPreviousPrompt) {
|
|
115
|
+
this.isPreviousPrompt = false;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
buffer += super.create({ ...options, prompt: false });
|
|
119
|
+
const bottomBar = this._options.aigne?.getBottomBarLogs?.({ running });
|
|
120
|
+
if (bottomBar?.length) {
|
|
121
|
+
buffer += EOL.repeat(2);
|
|
122
|
+
const output = [...bottomBar, running ? this._spinner.fetch() : ""]
|
|
123
|
+
.map((i) => this._wrap(i))
|
|
124
|
+
.join(EOL);
|
|
125
|
+
// If the task is not running, we show all lines
|
|
126
|
+
if (!running) {
|
|
127
|
+
buffer += output;
|
|
128
|
+
}
|
|
129
|
+
// For running tasks, we only show the last few lines
|
|
130
|
+
else {
|
|
131
|
+
const { rows } = process.stdout;
|
|
132
|
+
const lines = rows - buffer.split(EOL).length - 2;
|
|
133
|
+
buffer += output.split(EOL).slice(-Math.max(4, lines)).join(EOL);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
122
136
|
}
|
|
123
|
-
return
|
|
137
|
+
return buffer;
|
|
124
138
|
}
|
|
125
139
|
_wrap(str) {
|
|
126
140
|
return wrap(str, process.stdout.columns ?? 80, {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { availableModels } from "@aigne/aigne-hub";
|
|
1
2
|
import { AIGNE } from "@aigne/core";
|
|
2
|
-
import type { LoadableModel } from "@aigne/core/loader/index.js";
|
|
3
3
|
import inquirer from "inquirer";
|
|
4
4
|
import { type RunAIGNECommandOptions } from "./run-with-aigne.js";
|
|
5
5
|
export declare const decrypt: (m: string, s: string, i: string) => string;
|
|
@@ -40,7 +40,7 @@ interface CreateConnectOptions {
|
|
|
40
40
|
}) => Promise<FetchResult>;
|
|
41
41
|
}
|
|
42
42
|
export declare function createConnect({ connectUrl, openPage, fetchInterval, retry, source, connectAction, wrapSpinner, closeOnSuccess, intervalFetchConfig, }: CreateConnectOptions): Promise<FetchResult>;
|
|
43
|
-
export declare const formatModelName: (models:
|
|
43
|
+
export declare const formatModelName: (models: ReturnType<typeof availableModels>, model: string, inquirerPrompt: typeof inquirer.prompt) => Promise<string>;
|
|
44
44
|
export declare function connectToAIGNEHub(url: string): Promise<{
|
|
45
45
|
accessKey: string;
|
|
46
46
|
url: string;
|
|
@@ -48,7 +48,11 @@ export declare function connectToAIGNEHub(url: string): Promise<{
|
|
|
48
48
|
accessKey: undefined;
|
|
49
49
|
url: undefined;
|
|
50
50
|
}>;
|
|
51
|
-
export declare
|
|
51
|
+
export declare const checkConnectionStatus: (host: string) => Promise<{
|
|
52
|
+
apiKey: any;
|
|
53
|
+
url: string;
|
|
54
|
+
}>;
|
|
55
|
+
export declare function loadAIGNE(path: string, options?: Pick<RunOptions, "model">, actionOptions?: {
|
|
52
56
|
inquirerPromptFn?: (prompt: {
|
|
53
57
|
type: string;
|
|
54
58
|
name: string;
|
package/dist/utils/load-aigne.js
CHANGED
|
@@ -2,8 +2,9 @@ import { existsSync, mkdirSync } from "node:fs";
|
|
|
2
2
|
import { readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
+
import { availableModels, findModel, loadModel } from "@aigne/aigne-hub";
|
|
5
6
|
import { AIGNE } from "@aigne/core";
|
|
6
|
-
import { loadAIGNEFile
|
|
7
|
+
import { loadAIGNEFile } from "@aigne/core/loader/index.js";
|
|
7
8
|
import { logger } from "@aigne/core/utils/logger.js";
|
|
8
9
|
import { AesCrypter } from "@ocap/mcrypto/lib/crypter/aes-legacy.js";
|
|
9
10
|
import crypto from "crypto";
|
|
@@ -12,7 +13,7 @@ import open from "open";
|
|
|
12
13
|
import pWaitFor from "p-wait-for";
|
|
13
14
|
import { joinURL, withQuery } from "ufo";
|
|
14
15
|
import { parse, stringify } from "yaml";
|
|
15
|
-
import { availableMemories
|
|
16
|
+
import { availableMemories } from "../constants.js";
|
|
16
17
|
import { parseModelOption } from "./run-with-aigne.js";
|
|
17
18
|
const aes = new AesCrypter();
|
|
18
19
|
export const decrypt = (m, s, i) => aes.decrypt(m, crypto.pbkdf2Sync(i, s, 256, 32, "sha512").toString("hex"));
|
|
@@ -104,10 +105,11 @@ export const formatModelName = async (models, model, inquirerPrompt) => {
|
|
|
104
105
|
if (providerName.includes(AGENT_HUB_PROVIDER)) {
|
|
105
106
|
return model;
|
|
106
107
|
}
|
|
107
|
-
const m = models
|
|
108
|
+
const m = findModel(models, providerName);
|
|
108
109
|
if (!m)
|
|
109
110
|
throw new Error(`Unsupported model: ${provider} ${name}`);
|
|
110
|
-
|
|
111
|
+
const apiKeyEnvName = Array.isArray(m.apiKeyEnvName) ? m.apiKeyEnvName : [m.apiKeyEnvName];
|
|
112
|
+
if (apiKeyEnvName.some((name) => name && process.env[name])) {
|
|
111
113
|
return model;
|
|
112
114
|
}
|
|
113
115
|
if (TEST_ENV) {
|
|
@@ -123,7 +125,7 @@ export const formatModelName = async (models, model, inquirerPrompt) => {
|
|
|
123
125
|
value: true,
|
|
124
126
|
},
|
|
125
127
|
{
|
|
126
|
-
name: `Exit and bring my owner API Key by set ${
|
|
128
|
+
name: `Exit and bring my owner API Key by set ${apiKeyEnvName.join(", ")}`,
|
|
127
129
|
value: false,
|
|
128
130
|
},
|
|
129
131
|
],
|
|
@@ -175,42 +177,48 @@ export async function connectToAIGNEHub(url) {
|
|
|
175
177
|
return { accessKey: undefined, url: undefined };
|
|
176
178
|
}
|
|
177
179
|
}
|
|
180
|
+
export const checkConnectionStatus = async (host) => {
|
|
181
|
+
// aigne-hub access token
|
|
182
|
+
if (!existsSync(AIGNE_ENV_FILE)) {
|
|
183
|
+
throw new Error("AIGNE_HUB_API_KEY file not found, need to login first");
|
|
184
|
+
}
|
|
185
|
+
const data = await readFile(AIGNE_ENV_FILE, "utf8");
|
|
186
|
+
if (!data.includes("AIGNE_HUB_API_KEY")) {
|
|
187
|
+
throw new Error("AIGNE_HUB_API_KEY key not found, need to login first");
|
|
188
|
+
}
|
|
189
|
+
const envs = parse(data);
|
|
190
|
+
if (!envs[host]) {
|
|
191
|
+
throw new Error("AIGNE_HUB_API_KEY host not found, need to login first");
|
|
192
|
+
}
|
|
193
|
+
const env = envs[host];
|
|
194
|
+
if (!env.AIGNE_HUB_API_KEY) {
|
|
195
|
+
throw new Error("AIGNE_HUB_API_KEY key not found, need to login first");
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
apiKey: env.AIGNE_HUB_API_KEY,
|
|
199
|
+
url: joinURL(env.AIGNE_HUB_API_URL),
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
const mockInquirerPrompt = (() => Promise.resolve({ useAigneHub: true }));
|
|
178
203
|
export async function loadAIGNE(path, options, actionOptions) {
|
|
179
204
|
const models = availableModels();
|
|
180
205
|
const AIGNE_HUB_URL = process.env.AIGNE_HUB_API_URL || DEFAULT_URL;
|
|
181
206
|
const connectUrl = joinURL(new URL(AIGNE_HUB_URL).origin, WELLKNOWN_SERVICE_PATH_PREFIX);
|
|
182
207
|
const inquirerPrompt = (actionOptions?.inquirerPromptFn ??
|
|
183
208
|
inquirer.prompt);
|
|
209
|
+
const { host } = new URL(AIGNE_HUB_URL);
|
|
184
210
|
const { aigne } = await loadAIGNEFile(path).catch(() => ({ aigne: null }));
|
|
185
|
-
|
|
186
|
-
const
|
|
211
|
+
const result = await checkConnectionStatus(host).catch(() => null);
|
|
212
|
+
const alreadyConnected = Boolean(result?.apiKey);
|
|
213
|
+
const modelName = await formatModelName(models, options?.model || `${aigne?.model?.provider ?? ""}:${aigne?.model?.name ?? ""}`, alreadyConnected ? mockInquirerPrompt : inquirerPrompt);
|
|
214
|
+
let credential = {};
|
|
187
215
|
if (TEST_ENV && !actionOptions?.runTest) {
|
|
188
|
-
const model = await loadModel(
|
|
189
|
-
return await AIGNE.load(path, {
|
|
216
|
+
const model = await loadModel(parseModelOption(modelName));
|
|
217
|
+
return await AIGNE.load(path, { loadModel, memories: availableMemories, model });
|
|
190
218
|
}
|
|
191
219
|
if ((modelName.toLocaleLowerCase() || "").includes(AGENT_HUB_PROVIDER)) {
|
|
192
|
-
const { host } = new URL(AIGNE_HUB_URL);
|
|
193
220
|
try {
|
|
194
|
-
|
|
195
|
-
if (!existsSync(AIGNE_ENV_FILE)) {
|
|
196
|
-
throw new Error("AIGNE_HUB_API_KEY file not found, need to login first");
|
|
197
|
-
}
|
|
198
|
-
const data = await readFile(AIGNE_ENV_FILE, "utf8");
|
|
199
|
-
if (!data.includes("AIGNE_HUB_API_KEY")) {
|
|
200
|
-
throw new Error("AIGNE_HUB_API_KEY key not found, need to login first");
|
|
201
|
-
}
|
|
202
|
-
const envs = parse(data);
|
|
203
|
-
if (!envs[host]) {
|
|
204
|
-
throw new Error("AIGNE_HUB_API_KEY host not found, need to login first");
|
|
205
|
-
}
|
|
206
|
-
const env = envs[host];
|
|
207
|
-
if (!env.AIGNE_HUB_API_KEY) {
|
|
208
|
-
throw new Error("AIGNE_HUB_API_KEY key not found, need to login first");
|
|
209
|
-
}
|
|
210
|
-
accessKeyOptions = {
|
|
211
|
-
accessKey: env.AIGNE_HUB_API_KEY,
|
|
212
|
-
url: joinURL(env.AIGNE_HUB_API_URL),
|
|
213
|
-
};
|
|
221
|
+
credential = await checkConnectionStatus(host);
|
|
214
222
|
}
|
|
215
223
|
catch (error) {
|
|
216
224
|
if (error instanceof Error && error.message.includes("login first")) {
|
|
@@ -232,10 +240,10 @@ export async function loadAIGNE(path, options, actionOptions) {
|
|
|
232
240
|
console.warn("The AIGNE Hub connection has been cancelled");
|
|
233
241
|
process.exit(0);
|
|
234
242
|
}
|
|
235
|
-
|
|
243
|
+
credential = await connectToAIGNEHub(connectUrl);
|
|
236
244
|
}
|
|
237
245
|
}
|
|
238
246
|
}
|
|
239
|
-
const model = await loadModel(
|
|
240
|
-
return await AIGNE.load(path, {
|
|
247
|
+
const model = await loadModel(parseModelOption(modelName), undefined, credential);
|
|
248
|
+
return await AIGNE.load(path, { loadModel, memories: availableMemories, model });
|
|
241
249
|
}
|
|
@@ -4,8 +4,8 @@ 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 { availableModels, loadModel } from "@aigne/aigne-hub";
|
|
7
8
|
import { AIAgent, AIGNE, DEFAULT_OUTPUT_KEY, readAllString, UserAgent, } from "@aigne/core";
|
|
8
|
-
import { loadModel } from "@aigne/core/loader/index.js";
|
|
9
9
|
import { getLevelFromEnv, LogLevel, logger } from "@aigne/core/utils/logger.js";
|
|
10
10
|
import { flat, isEmpty, tryOrThrow } from "@aigne/core/utils/type-utils.js";
|
|
11
11
|
import chalk from "chalk";
|
|
@@ -13,7 +13,6 @@ import { parse } from "yaml";
|
|
|
13
13
|
import yargs from "yargs";
|
|
14
14
|
import { hideBin } from "yargs/helpers";
|
|
15
15
|
import { ZodError, ZodObject, z } from "zod";
|
|
16
|
-
import { availableModels } from "../constants.js";
|
|
17
16
|
import { TerminalTracer } from "../tracer/terminal.js";
|
|
18
17
|
import { DEFAULT_CHAT_INPUT_KEY, runChatLoopInTerminal, } from "./run-chat-loop.js";
|
|
19
18
|
export const createRunAIGNECommand = (yargs) => yargs
|
|
@@ -24,7 +23,12 @@ export const createRunAIGNECommand = (yargs) => yargs
|
|
|
24
23
|
})
|
|
25
24
|
.option("model", {
|
|
26
25
|
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) =>
|
|
26
|
+
.map((i) => {
|
|
27
|
+
if (typeof i.name === "string") {
|
|
28
|
+
return i.name.toLowerCase().replace(/ChatModel$/i, "");
|
|
29
|
+
}
|
|
30
|
+
return i.name.map((n) => n.toLowerCase().replace(/ChatModel$/i, ""));
|
|
31
|
+
})
|
|
28
32
|
.join(", ")} (default: openai)`,
|
|
29
33
|
type: "string",
|
|
30
34
|
})
|
|
@@ -129,7 +133,7 @@ export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoop
|
|
|
129
133
|
if (options.logLevel) {
|
|
130
134
|
logger.level = options.logLevel;
|
|
131
135
|
}
|
|
132
|
-
const model = await loadModel(
|
|
136
|
+
const model = await loadModel({
|
|
133
137
|
...parseModelOption(options.model),
|
|
134
138
|
temperature: options.temperature,
|
|
135
139
|
topP: options.topP,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.1",
|
|
4
4
|
"description": "cli for AIGNE framework",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -70,20 +70,13 @@
|
|
|
70
70
|
"yaml": "^2.8.0",
|
|
71
71
|
"yargs": "^18.0.0",
|
|
72
72
|
"zod": "^3.25.67",
|
|
73
|
-
"@aigne/
|
|
74
|
-
"@aigne/
|
|
75
|
-
"@aigne/
|
|
76
|
-
"@aigne/
|
|
77
|
-
"@aigne/
|
|
78
|
-
"@aigne/
|
|
79
|
-
"@aigne/
|
|
80
|
-
"@aigne/default-memory": "^1.0.8",
|
|
81
|
-
"@aigne/gemini": "^0.8.8",
|
|
82
|
-
"@aigne/observability-api": "^0.8.2",
|
|
83
|
-
"@aigne/ollama": "^0.7.8",
|
|
84
|
-
"@aigne/open-router": "^0.7.8",
|
|
85
|
-
"@aigne/openai": "^0.10.8",
|
|
86
|
-
"@aigne/xai": "^0.7.8"
|
|
73
|
+
"@aigne/aigne-hub": "^0.4.1",
|
|
74
|
+
"@aigne/agent-library": "^1.21.10",
|
|
75
|
+
"@aigne/openai": "^0.10.10",
|
|
76
|
+
"@aigne/default-memory": "^1.0.10",
|
|
77
|
+
"@aigne/agentic-memory": "^1.0.10",
|
|
78
|
+
"@aigne/observability-api": "^0.9.0",
|
|
79
|
+
"@aigne/core": "^1.43.0"
|
|
87
80
|
},
|
|
88
81
|
"devDependencies": {
|
|
89
82
|
"@types/archiver": "^6.0.3",
|