@aigne/cli 1.33.1 → 1.34.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 +24 -0
- package/dist/cli.js +2 -1
- package/dist/commands/app.js +4 -1
- package/dist/commands/connect.js +38 -12
- package/dist/commands/run.js +33 -14
- package/dist/commands/serve-mcp.js +4 -1
- package/dist/commands/test.js +4 -1
- package/dist/tracer/terminal.d.ts +1 -1
- package/dist/tracer/terminal.js +54 -27
- package/dist/utils/load-aigne.d.ts +11 -65
- package/dist/utils/load-aigne.js +32 -266
- package/dist/utils/run-with-aigne.d.ts +3 -5
- package/dist/utils/run-with-aigne.js +17 -14
- package/dist/utils/string-utils.d.ts +1 -0
- package/dist/utils/string-utils.js +4 -0
- package/package.json +8 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.34.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.33.1...cli-v1.34.0) (2025-08-12)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **cli:** add retry functionality and improve error handling for AIGNE Hub ([#348](https://github.com/AIGNE-io/aigne-framework/issues/348)) ([672c93a](https://github.com/AIGNE-io/aigne-framework/commit/672c93abbba8b4b234f6d810536ff4b603a97e1e))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **core:** examples cases that failed when using aigne-hub ([#337](https://github.com/AIGNE-io/aigne-framework/issues/337)) ([0d4a31c](https://github.com/AIGNE-io/aigne-framework/commit/0d4a31c24d9e7d26f00d1accb80719d9ad79a4c6))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Dependencies
|
|
17
|
+
|
|
18
|
+
* The following workspace dependencies were updated
|
|
19
|
+
* dependencies
|
|
20
|
+
* @aigne/agent-library bumped to 1.21.18
|
|
21
|
+
* @aigne/agentic-memory bumped to 1.0.18
|
|
22
|
+
* @aigne/aigne-hub bumped to 0.4.9
|
|
23
|
+
* @aigne/core bumped to 1.49.0
|
|
24
|
+
* @aigne/default-memory bumped to 1.1.0
|
|
25
|
+
* @aigne/openai bumped to 0.11.0
|
|
26
|
+
|
|
3
27
|
## [1.33.1](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.33.0...cli-v1.33.1) (2025-08-12)
|
|
4
28
|
|
|
5
29
|
|
package/dist/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import chalk from "chalk";
|
|
|
4
4
|
import { config } from "dotenv-flow";
|
|
5
5
|
import { hideBin } from "yargs/helpers";
|
|
6
6
|
import { createAIGNECommand } from "./commands/aigne.js";
|
|
7
|
+
import { highlightUrl } from "./utils/string-utils.js";
|
|
7
8
|
config({ silent: true });
|
|
8
9
|
function getAIGNEFilePath() {
|
|
9
10
|
let file = process.argv[2];
|
|
@@ -27,6 +28,6 @@ export default createAIGNECommand({ aigneFilePath })
|
|
|
27
28
|
.parseAsync(hideBin([...process.argv.slice(0, 2), ...process.argv.slice(aigneFilePath ? 3 : 2)]))
|
|
28
29
|
.catch((error) => {
|
|
29
30
|
console.log(""); // Add an empty line for better readability
|
|
30
|
-
console.error(`${chalk.red("Error:")} ${error.message
|
|
31
|
+
console.error(`${chalk.red("Error:")} ${highlightUrl(error.message)}`);
|
|
31
32
|
process.exit(1);
|
|
32
33
|
});
|
package/dist/commands/app.js
CHANGED
|
@@ -130,7 +130,10 @@ function innerZodType(type) {
|
|
|
130
130
|
return type;
|
|
131
131
|
}
|
|
132
132
|
export async function invokeCLIAgentFromDir(options) {
|
|
133
|
-
const aigne = await loadAIGNE(
|
|
133
|
+
const aigne = await loadAIGNE({
|
|
134
|
+
path: options.dir,
|
|
135
|
+
options: { model: options.input.model },
|
|
136
|
+
});
|
|
134
137
|
try {
|
|
135
138
|
const agent = aigne.cli.agents[options.agent];
|
|
136
139
|
assert(agent, `Agent ${options.agent} not found in ${options.dir}`);
|
package/dist/commands/connect.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { AIGNE_ENV_FILE, AIGNE_HUB_URL, connectToAIGNEHub } from "@aigne/aigne-hub";
|
|
3
4
|
import chalk from "chalk";
|
|
4
|
-
import { parse } from "yaml";
|
|
5
|
+
import { parse, stringify } from "yaml";
|
|
5
6
|
import { getUserInfo } from "../utils/aigne-hub-user.js";
|
|
6
|
-
import { AIGNE_ENV_FILE, connectToAIGNEHub, DEFAULT_URL } from "../utils/load-aigne.js";
|
|
7
7
|
const formatNumber = (balance) => {
|
|
8
8
|
const balanceNum = String(balance).split(".")[0];
|
|
9
9
|
return chalk.yellow((balanceNum || "").replace(/\B(?=(\d{3})+(?!\d))/g, ","));
|
|
@@ -36,15 +36,12 @@ export async function displayStatus(statusList) {
|
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
console.log(chalk.cyan("AIGNE Hub Connection Status:\n"));
|
|
39
|
-
const defaultStatus = statusList.find((status) => status.host === "default")?.apiUrl ||
|
|
39
|
+
const defaultStatus = statusList.find((status) => status.host === "default")?.apiUrl || AIGNE_HUB_URL;
|
|
40
40
|
for (const status of statusList.filter((status) => status.host !== "default")) {
|
|
41
|
-
const userInfo = await getUserInfo({ baseUrl: status.apiUrl, apiKey: status.apiKey }).catch((
|
|
42
|
-
console.error(e);
|
|
43
|
-
return null;
|
|
44
|
-
});
|
|
41
|
+
const userInfo = await getUserInfo({ baseUrl: status.apiUrl, apiKey: status.apiKey }).catch(() => null);
|
|
45
42
|
const isConnected = new URL(status.apiUrl).origin === new URL(defaultStatus).origin;
|
|
46
|
-
const statusIcon = isConnected ? chalk.green("✓") :
|
|
47
|
-
const statusText = isConnected ? "Connected" : "
|
|
43
|
+
const statusIcon = isConnected ? chalk.green("✓") : "•";
|
|
44
|
+
const statusText = isConnected ? "Connected" : "Not connected";
|
|
48
45
|
console.log(`${statusIcon} ${chalk.bold(status.host)}`);
|
|
49
46
|
console.log(` Status: ${statusText}`);
|
|
50
47
|
if (userInfo) {
|
|
@@ -56,9 +53,10 @@ export async function displayStatus(statusList) {
|
|
|
56
53
|
if (userInfo?.creditBalance) {
|
|
57
54
|
const balance = formatNumber(userInfo?.creditBalance?.balance);
|
|
58
55
|
const total = formatNumber(userInfo?.creditBalance?.total);
|
|
59
|
-
console.log(`
|
|
56
|
+
console.log(` Credits: ${balance} / ${total}`);
|
|
60
57
|
}
|
|
61
|
-
console.log(`
|
|
58
|
+
console.log(` Payment URL: ${userInfo?.paymentLink ? chalk.green(userInfo.paymentLink) : chalk.red("N/A")}`);
|
|
59
|
+
console.log(` Profile URL: ${userInfo?.profileLink ? chalk.green(userInfo.profileLink) : chalk.red("N/A")}`);
|
|
62
60
|
}
|
|
63
61
|
console.log("");
|
|
64
62
|
}
|
|
@@ -81,6 +79,34 @@ export function createConnectCommand() {
|
|
|
81
79
|
const statusList = await getConnectionStatus();
|
|
82
80
|
await displayStatus(statusList);
|
|
83
81
|
},
|
|
82
|
+
})
|
|
83
|
+
.command({
|
|
84
|
+
command: "switch",
|
|
85
|
+
describe: "Switch to a different AIGNE Hub",
|
|
86
|
+
handler: async (argv) => {
|
|
87
|
+
const url = argv.url;
|
|
88
|
+
console.log("Switching to AIGNE Hub: ", chalk.blue(url));
|
|
89
|
+
if (!url) {
|
|
90
|
+
console.error(chalk.red("✗ Please provide a URL to the AIGNE Hub server"));
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
const data = await readFile(AIGNE_ENV_FILE, "utf8");
|
|
94
|
+
const envs = parse(data);
|
|
95
|
+
let host = "";
|
|
96
|
+
try {
|
|
97
|
+
host = new URL(url).host;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
console.error(chalk.red("✗ Invalid URL"));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
if (!envs[host]) {
|
|
104
|
+
console.error(chalk.red("✗ AIGNE Hub already connected"));
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
await writeFile(AIGNE_ENV_FILE, stringify({ ...envs, default: { AIGNE_HUB_API_URL: envs[host]?.AIGNE_HUB_API_URL } }));
|
|
108
|
+
console.log(chalk.green("✓ Successfully connected to AIGNE Hub"));
|
|
109
|
+
},
|
|
84
110
|
});
|
|
85
111
|
},
|
|
86
112
|
handler: async (argv) => {
|
package/dist/commands/run.js
CHANGED
|
@@ -44,6 +44,7 @@ export function createRunCommand({ aigneFilePath, } = {}) {
|
|
|
44
44
|
if (options.logLevel)
|
|
45
45
|
logger.level = options.logLevel;
|
|
46
46
|
const { cacheDir, dir } = prepareDirs(path, options);
|
|
47
|
+
const originalLog = {};
|
|
47
48
|
const { aigne, agent } = await new Listr([
|
|
48
49
|
{
|
|
49
50
|
title: "Prepare environment",
|
|
@@ -67,24 +68,37 @@ export function createRunCommand({ aigneFilePath, } = {}) {
|
|
|
67
68
|
task: async (ctx, task) => {
|
|
68
69
|
// Load env files in the aigne directory
|
|
69
70
|
config({ path: dir, silent: true });
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
ctx.logs = [];
|
|
72
|
+
for (const method of ["debug", "log", "info", "warn", "error"]) {
|
|
73
|
+
originalLog[method] = console[method];
|
|
74
|
+
console[method] = (...args) => {
|
|
75
|
+
ctx.logs.push(...args);
|
|
76
|
+
task.output = args.join(" ");
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const aigne = await loadAIGNE({
|
|
80
|
+
path: dir,
|
|
81
|
+
options: {
|
|
82
|
+
...options,
|
|
83
|
+
model: options.model || process.env.MODEL,
|
|
84
|
+
aigneHubUrl: options?.aigneHubUrl,
|
|
85
|
+
},
|
|
86
|
+
actionOptions: {
|
|
87
|
+
inquirerPromptFn: (prompt) => {
|
|
88
|
+
if (prompt.type === "input") {
|
|
89
|
+
return task
|
|
90
|
+
.prompt(ListrInquirerPromptAdapter)
|
|
91
|
+
.run(inputInquirer, prompt)
|
|
92
|
+
.then((res) => ({ [prompt.name]: res }));
|
|
93
|
+
}
|
|
77
94
|
return task
|
|
78
95
|
.prompt(ListrInquirerPromptAdapter)
|
|
79
|
-
.run(
|
|
96
|
+
.run(selectInquirer, prompt)
|
|
80
97
|
.then((res) => ({ [prompt.name]: res }));
|
|
81
|
-
}
|
|
82
|
-
return task
|
|
83
|
-
.prompt(ListrInquirerPromptAdapter)
|
|
84
|
-
.run(selectInquirer, prompt)
|
|
85
|
-
.then((res) => ({ [prompt.name]: res }));
|
|
98
|
+
},
|
|
86
99
|
},
|
|
87
100
|
});
|
|
101
|
+
Object.assign(console, originalLog);
|
|
88
102
|
ctx.aigne = aigne;
|
|
89
103
|
},
|
|
90
104
|
},
|
|
@@ -118,7 +132,12 @@ ${aigne.agents.map((agent) => ` - ${agent.name}`).join("\n")}
|
|
|
118
132
|
showErrorMessage: false,
|
|
119
133
|
timer: PRESET_TIMER,
|
|
120
134
|
},
|
|
121
|
-
})
|
|
135
|
+
})
|
|
136
|
+
.run()
|
|
137
|
+
.then((ctx) => {
|
|
138
|
+
ctx.logs.forEach((log) => console.log(log));
|
|
139
|
+
return ctx;
|
|
140
|
+
});
|
|
122
141
|
assert(aigne);
|
|
123
142
|
assert(agent);
|
|
124
143
|
const input = await parseAgentInputByCommander(agent, options);
|
|
@@ -51,7 +51,10 @@ export function createServeMCPCommand({ aigneFilePath, } = {}) {
|
|
|
51
51
|
}
|
|
52
52
|
export async function serveMCPServerFromDir(options) {
|
|
53
53
|
const port = options.port || DEFAULT_PORT();
|
|
54
|
-
const aigne = await loadAIGNE(
|
|
54
|
+
const aigne = await loadAIGNE({
|
|
55
|
+
path: options.dir,
|
|
56
|
+
options: { aigneHubUrl: options.aigneHubUrl },
|
|
57
|
+
});
|
|
55
58
|
await serveMCPServer({
|
|
56
59
|
aigne,
|
|
57
60
|
host: options.host,
|
package/dist/commands/test.js
CHANGED
|
@@ -22,7 +22,10 @@ export function createTestCommand({ aigneFilePath, } = {}) {
|
|
|
22
22
|
handler: async (options) => {
|
|
23
23
|
const path = aigneFilePath || options.path;
|
|
24
24
|
const absolutePath = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
25
|
-
const aigne = await loadAIGNE(
|
|
25
|
+
const aigne = await loadAIGNE({
|
|
26
|
+
path: absolutePath,
|
|
27
|
+
options: { aigneHubUrl: options?.aigneHubUrl },
|
|
28
|
+
});
|
|
26
29
|
assert(aigne.rootDir);
|
|
27
30
|
spawnSync("node", ["--test"], { cwd: aigne.rootDir, stdio: "inherit" });
|
|
28
31
|
},
|
|
@@ -25,7 +25,7 @@ export declare class TerminalTracer {
|
|
|
25
25
|
usage?: boolean;
|
|
26
26
|
time?: boolean;
|
|
27
27
|
input: Message;
|
|
28
|
-
}): string
|
|
28
|
+
}): Promise<string>;
|
|
29
29
|
private marked;
|
|
30
30
|
get outputKey(): string;
|
|
31
31
|
formatRequest(agent: Agent, _context: Context, m?: Message, { running }?: {
|
package/dist/tracer/terminal.js
CHANGED
|
@@ -10,6 +10,7 @@ import * as prompts from "@inquirer/prompts";
|
|
|
10
10
|
import chalk from "chalk";
|
|
11
11
|
import { Marked } from "marked";
|
|
12
12
|
import { AIGNEListr, AIGNEListrRenderer } from "../utils/listr.js";
|
|
13
|
+
import { highlightUrl } from "../utils/string-utils.js";
|
|
13
14
|
import { parseDuration } from "../utils/time.js";
|
|
14
15
|
export class TerminalTracer {
|
|
15
16
|
context;
|
|
@@ -28,6 +29,24 @@ export class TerminalTracer {
|
|
|
28
29
|
: undefined,
|
|
29
30
|
formatResult: (result, options) => [this.formatResult(agent, context, result, options)].filter(Boolean),
|
|
30
31
|
}, [], { concurrent: true });
|
|
32
|
+
const proxiedPrompts = new Proxy({}, {
|
|
33
|
+
get: (_target, prop) => {
|
|
34
|
+
// biome-ignore lint/performance/noDynamicNamespaceImportAccess: we need to access prompts dynamically
|
|
35
|
+
const method = prompts[prop];
|
|
36
|
+
if (typeof method !== "function")
|
|
37
|
+
return undefined;
|
|
38
|
+
return async (config) => {
|
|
39
|
+
const renderer = listr["renderer"] instanceof AIGNEListrRenderer ? listr["renderer"] : undefined;
|
|
40
|
+
await renderer?.pause();
|
|
41
|
+
try {
|
|
42
|
+
return await method({ ...config });
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
await renderer?.resume();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
});
|
|
31
50
|
const onStart = async ({ context, agent, ...event }) => {
|
|
32
51
|
if (agent instanceof UserAgent)
|
|
33
52
|
return;
|
|
@@ -40,7 +59,7 @@ export class TerminalTracer {
|
|
|
40
59
|
};
|
|
41
60
|
this.tasks[contextId] = task;
|
|
42
61
|
const listrTask = {
|
|
43
|
-
title: this.formatTaskTitle(agent, { ...event }),
|
|
62
|
+
title: await this.formatTaskTitle(agent, { ...event }),
|
|
44
63
|
task: (ctx, taskWrapper) => {
|
|
45
64
|
const subtask = taskWrapper.newListr([{ task: () => task.promise }]);
|
|
46
65
|
task.listr.resolve({ subtask, taskWrapper, ctx });
|
|
@@ -61,28 +80,7 @@ export class TerminalTracer {
|
|
|
61
80
|
else {
|
|
62
81
|
listr.add(listrTask);
|
|
63
82
|
}
|
|
64
|
-
return {
|
|
65
|
-
options: {
|
|
66
|
-
prompts: new Proxy({}, {
|
|
67
|
-
get: (_target, prop) => {
|
|
68
|
-
// biome-ignore lint/performance/noDynamicNamespaceImportAccess: we need to access prompts dynamically
|
|
69
|
-
const method = prompts[prop];
|
|
70
|
-
if (typeof method !== "function")
|
|
71
|
-
return undefined;
|
|
72
|
-
return async (config) => {
|
|
73
|
-
const renderer = listr["renderer"] instanceof AIGNEListrRenderer ? listr["renderer"] : undefined;
|
|
74
|
-
await renderer?.pause();
|
|
75
|
-
try {
|
|
76
|
-
return await method({ ...config });
|
|
77
|
-
}
|
|
78
|
-
finally {
|
|
79
|
-
await renderer?.resume();
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
},
|
|
83
|
-
}),
|
|
84
|
-
},
|
|
85
|
-
};
|
|
83
|
+
return { options: { prompts: proxiedPrompts } };
|
|
86
84
|
};
|
|
87
85
|
const onSuccess = async ({ context, agent, output, ...event }) => {
|
|
88
86
|
const contextId = context.id;
|
|
@@ -99,20 +97,49 @@ export class TerminalTracer {
|
|
|
99
97
|
if (model)
|
|
100
98
|
task.extraTitleMetadata.model = model;
|
|
101
99
|
}
|
|
102
|
-
taskWrapper.title = this.formatTaskTitle(agent, {
|
|
100
|
+
taskWrapper.title = await this.formatTaskTitle(agent, {
|
|
101
|
+
...event,
|
|
102
|
+
task,
|
|
103
|
+
usage: true,
|
|
104
|
+
time: true,
|
|
105
|
+
});
|
|
103
106
|
if (!parentContextId || !this.tasks[parentContextId]) {
|
|
104
107
|
Object.assign(ctx, output);
|
|
105
108
|
}
|
|
106
109
|
task.resolve();
|
|
107
110
|
};
|
|
108
111
|
const onError = async ({ context, agent, error, ...event }) => {
|
|
112
|
+
if ("type" in error && error.type === "NOT_ENOUGH") {
|
|
113
|
+
const retry = await proxiedPrompts.select({
|
|
114
|
+
message: highlightUrl(error.message),
|
|
115
|
+
choices: [
|
|
116
|
+
{
|
|
117
|
+
name: "I have bought some credits, try again",
|
|
118
|
+
value: "retry",
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: "Exit",
|
|
122
|
+
value: "exit",
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
});
|
|
126
|
+
console.log("");
|
|
127
|
+
if (retry === "retry") {
|
|
128
|
+
return { retry: true };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
109
131
|
const contextId = context.id;
|
|
110
132
|
const task = this.tasks[contextId];
|
|
111
133
|
if (!task)
|
|
112
134
|
return;
|
|
113
135
|
task.endTime = Date.now();
|
|
114
136
|
const { taskWrapper } = await task.listr.promise;
|
|
115
|
-
taskWrapper.title = this.formatTaskTitle(agent, {
|
|
137
|
+
taskWrapper.title = await this.formatTaskTitle(agent, {
|
|
138
|
+
...event,
|
|
139
|
+
task,
|
|
140
|
+
usage: true,
|
|
141
|
+
time: true,
|
|
142
|
+
});
|
|
116
143
|
task.reject(error);
|
|
117
144
|
};
|
|
118
145
|
const result = await listr.run(() => context.invoke(agent, input, {
|
|
@@ -145,10 +172,10 @@ export class TerminalTracer {
|
|
|
145
172
|
const duration = endTime - startTime;
|
|
146
173
|
return chalk.grey(`[${parseDuration(duration)}]`);
|
|
147
174
|
}
|
|
148
|
-
formatTaskTitle(agent, { task, usage, time, input }) {
|
|
175
|
+
async formatTaskTitle(agent, { task, usage, time, input }) {
|
|
149
176
|
let title = agent.name;
|
|
150
177
|
if (agent.taskTitle) {
|
|
151
|
-
title += ` ${chalk.cyan(agent.renderTaskTitle(input))}`;
|
|
178
|
+
title += ` ${chalk.cyan(await agent.renderTaskTitle(input))}`;
|
|
152
179
|
}
|
|
153
180
|
if (usage && task?.usage)
|
|
154
181
|
title += ` ${this.formatTokenUsage(task.usage, task.extraTitleMetadata)}`;
|
|
@@ -1,72 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AIGNE } from "@aigne/core";
|
|
3
|
-
import
|
|
4
|
-
import { type RunAIGNECommandOptions } from "./run-with-aigne.js";
|
|
5
|
-
export declare const decrypt: (m: string, s: string, i: string) => string;
|
|
6
|
-
export declare const encrypt: (m: string, s: string, i: string) => string;
|
|
7
|
-
export declare const encodeEncryptionKey: (key: string) => string;
|
|
8
|
-
export declare const decodeEncryptionKey: (str: string) => Uint8Array<ArrayBuffer>;
|
|
9
|
-
export declare const AIGNE_ENV_FILE: string;
|
|
1
|
+
import type { LoadCredentialOptions, Model } from "@aigne/aigne-hub";
|
|
2
|
+
import { AIGNE, type ChatModelOptions } from "@aigne/core";
|
|
3
|
+
import type { RunAIGNECommandOptions } from "./run-with-aigne.js";
|
|
10
4
|
export interface RunOptions extends RunAIGNECommandOptions {
|
|
11
5
|
path: string;
|
|
12
6
|
entryAgent?: string;
|
|
13
7
|
cacheDir?: string;
|
|
14
8
|
aigneHubUrl?: string;
|
|
15
9
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
fetchTimeout: number;
|
|
25
|
-
}) => Promise<any>;
|
|
26
|
-
declare function baseWrapSpinner(_: string, waiting: () => Promise<FetchResult>): Promise<FetchResult>;
|
|
27
|
-
interface CreateConnectOptions {
|
|
28
|
-
connectUrl: string;
|
|
29
|
-
openPage?: (url: string) => void;
|
|
30
|
-
fetchInterval?: number;
|
|
31
|
-
retry?: number;
|
|
32
|
-
source?: string;
|
|
33
|
-
connectAction?: string;
|
|
34
|
-
appName?: string;
|
|
35
|
-
appLogo?: string;
|
|
36
|
-
wrapSpinner?: typeof baseWrapSpinner;
|
|
37
|
-
prettyUrl?: (url: string) => string;
|
|
38
|
-
closeOnSuccess?: boolean;
|
|
39
|
-
intervalFetchConfig?: (options: {
|
|
40
|
-
sessionId: string;
|
|
41
|
-
fetchInterval: number;
|
|
42
|
-
fetchTimeout: number;
|
|
43
|
-
}) => Promise<FetchResult>;
|
|
44
|
-
}
|
|
45
|
-
export declare function createConnect({ connectUrl, openPage, fetchInterval, retry, source, connectAction, wrapSpinner, closeOnSuccess, intervalFetchConfig, appName, appLogo, }: CreateConnectOptions): Promise<FetchResult>;
|
|
46
|
-
export declare const DEFAULT_URL = "https://hub.aigne.io/";
|
|
47
|
-
export declare const formatModelName: (models: ReturnType<typeof availableModels>, model: string, inquirerPrompt: typeof inquirer.prompt) => Promise<string>;
|
|
48
|
-
export declare function connectToAIGNEHub(url: string): Promise<{
|
|
49
|
-
apiKey: string;
|
|
50
|
-
url: string;
|
|
51
|
-
} | {
|
|
52
|
-
apiKey: undefined;
|
|
53
|
-
url: undefined;
|
|
54
|
-
}>;
|
|
55
|
-
export declare const checkConnectionStatus: (host: string) => Promise<{
|
|
56
|
-
apiKey: any;
|
|
57
|
-
url: string;
|
|
58
|
-
}>;
|
|
59
|
-
export declare function loadAIGNE(path: string, options?: Pick<RunOptions, "model" | "aigneHubUrl">, actionOptions?: {
|
|
60
|
-
inquirerPromptFn?: (prompt: {
|
|
61
|
-
type: string;
|
|
62
|
-
name: string;
|
|
63
|
-
message: string;
|
|
64
|
-
choices: {
|
|
65
|
-
name: string;
|
|
66
|
-
value: any;
|
|
67
|
-
}[];
|
|
68
|
-
default: any;
|
|
69
|
-
}) => Promise<any>;
|
|
70
|
-
runTest?: boolean;
|
|
10
|
+
export declare function loadAIGNE({ path, options, modelOptions, actionOptions, }: {
|
|
11
|
+
path?: string;
|
|
12
|
+
options?: Model & Pick<RunOptions, "model" | "aigneHubUrl">;
|
|
13
|
+
modelOptions?: ChatModelOptions;
|
|
14
|
+
actionOptions?: {
|
|
15
|
+
inquirerPromptFn?: LoadCredentialOptions["inquirerPromptFn"];
|
|
16
|
+
runTest?: boolean;
|
|
17
|
+
};
|
|
71
18
|
}): Promise<AIGNE<import("@aigne/core").UserContext>>;
|
|
72
|
-
export {};
|
package/dist/utils/load-aigne.js
CHANGED
|
@@ -1,288 +1,54 @@
|
|
|
1
1
|
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
-
import { readFile
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { AIGNE_ENV_FILE, checkConnectionStatus, AIGNE_HUB_URL as DEFAULT_AIGNE_HUB_URL, formatModelName, loadModel, parseModelOption, } from "@aigne/aigne-hub";
|
|
6
6
|
import { AIGNE } from "@aigne/core";
|
|
7
7
|
import { loadAIGNEFile } from "@aigne/core/loader/index.js";
|
|
8
|
-
import { logger } from "@aigne/core/utils/logger.js";
|
|
9
|
-
import { AesCrypter } from "@ocap/mcrypto/lib/crypter/aes-legacy.js";
|
|
10
|
-
import crypto from "crypto";
|
|
11
8
|
import inquirer from "inquirer";
|
|
12
|
-
import open from "open";
|
|
13
|
-
import pWaitFor from "p-wait-for";
|
|
14
|
-
import { joinURL, withQuery } from "ufo";
|
|
15
9
|
import { parse, stringify } from "yaml";
|
|
16
10
|
import { availableMemories } from "../constants.js";
|
|
17
|
-
|
|
18
|
-
const aes = new AesCrypter();
|
|
19
|
-
export const decrypt = (m, s, i) => aes.decrypt(m, crypto.pbkdf2Sync(i, s, 256, 32, "sha512").toString("hex"));
|
|
20
|
-
export const encrypt = (m, s, i) => aes.encrypt(m, crypto.pbkdf2Sync(i, s, 256, 32, "sha512").toString("hex"));
|
|
21
|
-
const escapeFn = (str) => str.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
22
|
-
const unescapeFn = (str) => (str + "===".slice((str.length + 3) % 4)).replace(/-/g, "+").replace(/_/g, "/");
|
|
23
|
-
export const encodeEncryptionKey = (key) => escapeFn(Buffer.from(key).toString("base64"));
|
|
24
|
-
export const decodeEncryptionKey = (str) => new Uint8Array(Buffer.from(unescapeFn(str), "base64"));
|
|
25
|
-
const TEST_ENV = process.env.CI || process.env.NODE_ENV === "test";
|
|
26
|
-
export const AIGNE_ENV_FILE = TEST_ENV
|
|
27
|
-
? join(homedir(), ".aigne", "test-aigne-hub-connected.yaml")
|
|
28
|
-
: join(homedir(), ".aigne", "aigne-hub-connected.yaml");
|
|
29
|
-
const request = async (config) => {
|
|
30
|
-
const headers = {};
|
|
31
|
-
if (config.requestCount !== undefined) {
|
|
32
|
-
headers["X-Request-Count"] = config.requestCount.toString();
|
|
33
|
-
}
|
|
34
|
-
const response = await fetch(config.url, { method: config.method || "GET", headers });
|
|
35
|
-
if (!response.ok)
|
|
36
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
37
|
-
const data = await response.json();
|
|
38
|
-
return { data };
|
|
39
|
-
};
|
|
40
|
-
const WELLKNOWN_SERVICE_PATH_PREFIX = "/.well-known/service";
|
|
41
|
-
const ACCESS_KEY_PREFIX = "/api/access-key";
|
|
42
|
-
const ACCESS_KEY_SESSION_API = `${ACCESS_KEY_PREFIX}/session`;
|
|
43
|
-
export const fetchConfigs = async ({ connectUrl, sessionId, fetchInterval, fetchTimeout, }) => {
|
|
44
|
-
const sessionURL = withQuery(joinURL(connectUrl, ACCESS_KEY_SESSION_API), { sid: sessionId });
|
|
45
|
-
let requestCount = 0;
|
|
46
|
-
const condition = async () => {
|
|
47
|
-
const { data: session } = await request({ url: sessionURL, requestCount });
|
|
48
|
-
requestCount++;
|
|
49
|
-
return Boolean(session.accessKeyId && session.accessKeySecret);
|
|
50
|
-
};
|
|
51
|
-
await pWaitFor(condition, { interval: fetchInterval, timeout: fetchTimeout });
|
|
52
|
-
const { data: session } = await request({ url: sessionURL, requestCount });
|
|
53
|
-
await request({ url: sessionURL, method: "DELETE" });
|
|
54
|
-
return {
|
|
55
|
-
...session,
|
|
56
|
-
accessKeyId: session.accessKeyId,
|
|
57
|
-
accessKeySecret: decrypt(session.accessKeySecret, session.accessKeyId, session.challenge),
|
|
58
|
-
};
|
|
59
|
-
};
|
|
60
|
-
function baseWrapSpinner(_, waiting) {
|
|
61
|
-
return Promise.resolve(waiting());
|
|
62
|
-
}
|
|
63
|
-
export async function createConnect({ connectUrl, openPage, fetchInterval = 3 * 1000, retry = 1500, source = "Blocklet CLI", connectAction = "connect-cli", wrapSpinner = baseWrapSpinner, closeOnSuccess, intervalFetchConfig, appName = "AIGNE CLI", appLogo = "https://www.aigne.io/favicon.ico?imageFilter=resize&w=32", }) {
|
|
64
|
-
try {
|
|
65
|
-
const startSessionURL = joinURL(connectUrl, ACCESS_KEY_SESSION_API);
|
|
66
|
-
const { data: session } = await request({ url: startSessionURL, method: "POST" });
|
|
67
|
-
const token = session.id;
|
|
68
|
-
const pageUrl = withQuery(joinURL(connectUrl, connectAction), {
|
|
69
|
-
__token__: encodeEncryptionKey(token),
|
|
70
|
-
source,
|
|
71
|
-
closeOnSuccess,
|
|
72
|
-
cli: true,
|
|
73
|
-
appName: ` ${appName}`,
|
|
74
|
-
appLogo,
|
|
75
|
-
});
|
|
76
|
-
openPage?.(pageUrl);
|
|
77
|
-
return await wrapSpinner(`Waiting for connection: ${connectUrl}`, async () => {
|
|
78
|
-
const checkAuthorizeStatus = intervalFetchConfig ?? fetchConfigs;
|
|
79
|
-
const authorizeStatus = await checkAuthorizeStatus({
|
|
80
|
-
connectUrl,
|
|
81
|
-
sessionId: token,
|
|
82
|
-
fetchTimeout: retry * fetchInterval,
|
|
83
|
-
fetchInterval: retry,
|
|
84
|
-
});
|
|
85
|
-
return authorizeStatus;
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
catch (e) {
|
|
89
|
-
console.error(e);
|
|
90
|
-
throw e;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
const AGENT_HUB_PROVIDER = "aignehub";
|
|
94
|
-
const DEFAULT_AIGNE_HUB_MODEL = "openai/gpt-4o";
|
|
95
|
-
const DEFAULT_AIGNE_HUB_PROVIDER_MODEL = `${AGENT_HUB_PROVIDER}:${DEFAULT_AIGNE_HUB_MODEL}`;
|
|
96
|
-
export const DEFAULT_URL = "https://hub.aigne.io/";
|
|
97
|
-
export const formatModelName = async (models, model, inquirerPrompt) => {
|
|
98
|
-
if (!model)
|
|
99
|
-
return DEFAULT_AIGNE_HUB_PROVIDER_MODEL;
|
|
100
|
-
const { provider, name } = parseModelOption(model);
|
|
101
|
-
if (!provider) {
|
|
102
|
-
return DEFAULT_AIGNE_HUB_PROVIDER_MODEL;
|
|
103
|
-
}
|
|
104
|
-
const providerName = provider.replace(/-/g, "");
|
|
105
|
-
if (providerName.includes(AGENT_HUB_PROVIDER)) {
|
|
106
|
-
return model;
|
|
107
|
-
}
|
|
108
|
-
const m = findModel(models, providerName);
|
|
109
|
-
if (!m)
|
|
110
|
-
throw new Error(`Unsupported model: ${provider} ${name}`);
|
|
111
|
-
const apiKeyEnvName = Array.isArray(m.apiKeyEnvName) ? m.apiKeyEnvName : [m.apiKeyEnvName];
|
|
112
|
-
if (apiKeyEnvName.some((name) => name && process.env[name])) {
|
|
113
|
-
return model;
|
|
114
|
-
}
|
|
115
|
-
if (TEST_ENV) {
|
|
116
|
-
return `${AGENT_HUB_PROVIDER}:${provider}/${name}`;
|
|
117
|
-
}
|
|
118
|
-
const result = await inquirerPrompt({
|
|
119
|
-
type: "list",
|
|
120
|
-
name: "useAigneHub",
|
|
121
|
-
message: `Seems no API Key configured for ${provider}/${name}, select your preferred way to continue:`,
|
|
122
|
-
choices: [
|
|
123
|
-
{
|
|
124
|
-
name: `Connect to AIGNE Hub to use ${name} (Recommended since free credits available)`,
|
|
125
|
-
value: true,
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
name: `Exit and bring my owner API Key by set ${apiKeyEnvName.join(", ")}`,
|
|
129
|
-
value: false,
|
|
130
|
-
},
|
|
131
|
-
],
|
|
132
|
-
default: true,
|
|
133
|
-
});
|
|
134
|
-
if (!result.useAigneHub)
|
|
135
|
-
return model;
|
|
136
|
-
return `${AGENT_HUB_PROVIDER}:${provider}/${name}`;
|
|
137
|
-
};
|
|
138
|
-
export async function connectToAIGNEHub(url) {
|
|
139
|
-
const { origin, host } = new URL(url);
|
|
140
|
-
const connectUrl = joinURL(origin, WELLKNOWN_SERVICE_PATH_PREFIX);
|
|
141
|
-
const BLOCKLET_JSON_PATH = "__blocklet__.js?type=json";
|
|
142
|
-
const blockletInfo = await fetch(joinURL(origin, BLOCKLET_JSON_PATH));
|
|
143
|
-
const blocklet = await blockletInfo.json();
|
|
144
|
-
const aigneHubMount = (blocklet?.componentMountPoints || []).find((m) => m.did === "z8ia3xzq2tMq8CRHfaXj1BTYJyYnEcHbqP8cJ");
|
|
145
|
-
try {
|
|
146
|
-
const result = await createConnect({
|
|
147
|
-
connectUrl: connectUrl,
|
|
148
|
-
connectAction: "gen-simple-access-key",
|
|
149
|
-
source: `@aigne/cli connect to AIGNE hub`,
|
|
150
|
-
closeOnSuccess: true,
|
|
151
|
-
openPage: (pageUrl) => open(pageUrl),
|
|
152
|
-
});
|
|
153
|
-
const accessKeyOptions = {
|
|
154
|
-
apiKey: result.accessKeySecret,
|
|
155
|
-
url: joinURL(origin, aigneHubMount?.mountPoint || ""),
|
|
156
|
-
};
|
|
157
|
-
// After redirection, write the AIGNE Hub access token
|
|
158
|
-
const aigneDir = join(homedir(), ".aigne");
|
|
159
|
-
if (!existsSync(aigneDir)) {
|
|
160
|
-
mkdirSync(aigneDir, { recursive: true });
|
|
161
|
-
}
|
|
162
|
-
const envs = parse(await readFile(AIGNE_ENV_FILE, "utf8").catch(() => stringify({})));
|
|
163
|
-
await writeFile(AIGNE_ENV_FILE, stringify({
|
|
164
|
-
...envs,
|
|
165
|
-
[host]: {
|
|
166
|
-
AIGNE_HUB_API_KEY: accessKeyOptions.apiKey,
|
|
167
|
-
AIGNE_HUB_API_URL: accessKeyOptions.url,
|
|
168
|
-
},
|
|
169
|
-
default: {
|
|
170
|
-
AIGNE_HUB_API_URL: accessKeyOptions.url,
|
|
171
|
-
},
|
|
172
|
-
})).catch((err) => {
|
|
173
|
-
logger.error("Failed to write AIGNE Hub access token to .aigne/aigne-hub-connected.yaml", err.message);
|
|
174
|
-
throw err;
|
|
175
|
-
});
|
|
176
|
-
return accessKeyOptions;
|
|
177
|
-
}
|
|
178
|
-
catch (error) {
|
|
179
|
-
logger.error("Failed to connect to AIGNE Hub", error.message);
|
|
180
|
-
return { apiKey: undefined, url: undefined };
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
export const checkConnectionStatus = async (host) => {
|
|
184
|
-
// aigne-hub access token
|
|
185
|
-
if (!existsSync(AIGNE_ENV_FILE)) {
|
|
186
|
-
throw new Error("AIGNE_HUB_API_KEY file not found, need to login first");
|
|
187
|
-
}
|
|
188
|
-
const data = await readFile(AIGNE_ENV_FILE, "utf8");
|
|
189
|
-
if (!data.includes("AIGNE_HUB_API_KEY")) {
|
|
190
|
-
throw new Error("AIGNE_HUB_API_KEY key not found, need to login first");
|
|
191
|
-
}
|
|
192
|
-
const envs = parse(data);
|
|
193
|
-
if (!envs[host]) {
|
|
194
|
-
throw new Error("AIGNE_HUB_API_KEY host not found, need to login first");
|
|
195
|
-
}
|
|
196
|
-
const env = envs[host];
|
|
197
|
-
if (!env.AIGNE_HUB_API_KEY) {
|
|
198
|
-
throw new Error("AIGNE_HUB_API_KEY key not found, need to login first");
|
|
199
|
-
}
|
|
200
|
-
return {
|
|
201
|
-
apiKey: env.AIGNE_HUB_API_KEY,
|
|
202
|
-
url: joinURL(env.AIGNE_HUB_API_URL),
|
|
203
|
-
};
|
|
204
|
-
};
|
|
11
|
+
const isTest = process.env.CI || process.env.NODE_ENV === "test";
|
|
205
12
|
const mockInquirerPrompt = (() => Promise.resolve({ useAigneHub: true }));
|
|
206
|
-
|
|
13
|
+
async function prepareAIGNEConfig(options, inquirerPromptFn) {
|
|
207
14
|
const aigneDir = join(homedir(), ".aigne");
|
|
208
15
|
if (!existsSync(aigneDir)) {
|
|
209
16
|
mkdirSync(aigneDir, { recursive: true });
|
|
210
17
|
}
|
|
211
18
|
const envs = parse(await readFile(AIGNE_ENV_FILE, "utf8").catch(() => stringify({})));
|
|
212
|
-
const inquirerPrompt = (
|
|
213
|
-
|
|
214
|
-
const models = availableModels();
|
|
19
|
+
const inquirerPrompt = (inquirerPromptFn ?? inquirer.prompt);
|
|
20
|
+
// get aigne hub url
|
|
215
21
|
const configUrl = options?.aigneHubUrl || process.env.AIGNE_HUB_API_URL;
|
|
216
|
-
const AIGNE_HUB_URL = configUrl || envs?.default?.AIGNE_HUB_API_URL ||
|
|
217
|
-
const connectUrl = joinURL(new URL(AIGNE_HUB_URL).origin, WELLKNOWN_SERVICE_PATH_PREFIX);
|
|
22
|
+
const AIGNE_HUB_URL = configUrl || envs?.default?.AIGNE_HUB_API_URL || DEFAULT_AIGNE_HUB_URL;
|
|
218
23
|
const { host } = new URL(AIGNE_HUB_URL);
|
|
219
|
-
const { aigne } = await loadAIGNEFile(path).catch(() => ({ aigne: null }));
|
|
220
24
|
const result = await checkConnectionStatus(host).catch(() => null);
|
|
221
25
|
const alreadyConnected = Boolean(result?.apiKey);
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
26
|
+
return { AIGNE_HUB_URL, inquirerPrompt: alreadyConnected ? mockInquirerPrompt : inquirerPrompt };
|
|
27
|
+
}
|
|
28
|
+
export async function loadAIGNE({ path, options, modelOptions, actionOptions, }) {
|
|
29
|
+
const { AIGNE_HUB_URL, inquirerPrompt } = await prepareAIGNEConfig(options, actionOptions?.inquirerPromptFn);
|
|
30
|
+
const { temperature, topP, presencePenalty, frequencyPenalty } = options || {};
|
|
31
|
+
let modelName = options?.model || "";
|
|
32
|
+
if (path) {
|
|
33
|
+
const { aigne } = await loadAIGNEFile(path).catch(() => ({ aigne: null }));
|
|
34
|
+
const modelFromPath = `${aigne?.model?.provider ?? ""}:${aigne?.model?.name ?? ""}`;
|
|
35
|
+
modelName = modelName || modelFromPath;
|
|
36
|
+
}
|
|
37
|
+
// format model name
|
|
38
|
+
const formattedModelName = isTest ? modelName : await formatModelName(modelName, inquirerPrompt);
|
|
39
|
+
if (isTest && path && !actionOptions?.runTest) {
|
|
40
|
+
const model = await loadModel(parseModelOption(formattedModelName));
|
|
226
41
|
return await AIGNE.load(path, { loadModel, memories: availableMemories, model });
|
|
227
42
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
type: "list",
|
|
238
|
-
name: "subscribe",
|
|
239
|
-
message: "No LLM API Keys or AIGNE Hub connections found. How would you like to proceed?",
|
|
240
|
-
choices: [
|
|
241
|
-
{
|
|
242
|
-
name: "Connect to the Arcblock official AIGNE Hub (recommended, free credits for new users)",
|
|
243
|
-
value: "official",
|
|
244
|
-
},
|
|
245
|
-
connectUrl.includes(DEFAULT_URL)
|
|
246
|
-
? {
|
|
247
|
-
name: "Connect to your own AIGNE Hub instance (self-hosted)",
|
|
248
|
-
value: "custom",
|
|
249
|
-
}
|
|
250
|
-
: null,
|
|
251
|
-
{
|
|
252
|
-
name: "Exit and configure my own LLM API Keys",
|
|
253
|
-
value: "manual",
|
|
254
|
-
},
|
|
255
|
-
].filter(Boolean),
|
|
256
|
-
default: "official",
|
|
257
|
-
});
|
|
258
|
-
if (subscribe === "custom") {
|
|
259
|
-
const { customUrl } = await inquirerPrompt({
|
|
260
|
-
type: "input",
|
|
261
|
-
name: "customUrl",
|
|
262
|
-
message: "Enter the URL of your AIGNE Hub:",
|
|
263
|
-
validate(input) {
|
|
264
|
-
try {
|
|
265
|
-
const url = new URL(input);
|
|
266
|
-
return url.protocol.startsWith("http")
|
|
267
|
-
? true
|
|
268
|
-
: "Must be a valid URL with http or https";
|
|
269
|
-
}
|
|
270
|
-
catch {
|
|
271
|
-
return "Invalid URL";
|
|
272
|
-
}
|
|
273
|
-
},
|
|
274
|
-
});
|
|
275
|
-
aigneHubUrl = customUrl;
|
|
276
|
-
}
|
|
277
|
-
else if (subscribe === "manual") {
|
|
278
|
-
console.log("You chose to configure your own LLM API Keys. Exiting...");
|
|
279
|
-
process.exit(0);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
credential = await connectToAIGNEHub(aigneHubUrl);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
43
|
+
const model = await loadModel({
|
|
44
|
+
...parseModelOption(formattedModelName),
|
|
45
|
+
temperature,
|
|
46
|
+
topP,
|
|
47
|
+
presencePenalty,
|
|
48
|
+
frequencyPenalty,
|
|
49
|
+
}, modelOptions, { aigneHubUrl: AIGNE_HUB_URL, inquirerPromptFn: actionOptions?.inquirerPromptFn });
|
|
50
|
+
if (path) {
|
|
51
|
+
return await AIGNE.load(path, { loadModel, memories: availableMemories, model });
|
|
285
52
|
}
|
|
286
|
-
|
|
287
|
-
return await AIGNE.load(path, { loadModel, memories: availableMemories, model });
|
|
53
|
+
return new AIGNE({ model });
|
|
288
54
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Agent, AIGNE, type ChatModelOptions, type Message } from "@aigne/core";
|
|
1
|
+
import { type Agent, type 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
4
|
import type { Argv } from "yargs";
|
|
@@ -41,16 +41,14 @@ export declare const createRunAIGNECommand: (yargs: Argv) => Argv<{
|
|
|
41
41
|
force: boolean;
|
|
42
42
|
} & {
|
|
43
43
|
"log-level": LogLevel;
|
|
44
|
+
} & {
|
|
45
|
+
"aigne-hub-url": string | undefined;
|
|
44
46
|
}>;
|
|
45
47
|
export declare function parseAgentInputByCommander(agent: Agent, options?: RunAIGNECommandOptions & {
|
|
46
48
|
inputKey?: string;
|
|
47
49
|
argv?: string[];
|
|
48
50
|
defaultInput?: string | Message;
|
|
49
51
|
}): Promise<Message>;
|
|
50
|
-
export declare const parseModelOption: (model?: string) => {
|
|
51
|
-
provider: string | undefined;
|
|
52
|
-
name: string | undefined;
|
|
53
|
-
};
|
|
54
52
|
export declare function runWithAIGNE(agentCreator: ((aigne: AIGNE) => PromiseOrValue<Agent>) | Agent, { argv, chatLoopOptions, modelOptions, outputKey, }?: {
|
|
55
53
|
argv?: typeof process.argv;
|
|
56
54
|
chatLoopOptions?: ChatLoopOptions;
|
|
@@ -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,
|
|
8
|
-
import { AIAgent,
|
|
7
|
+
import { availableModels, parseModelOption } from "@aigne/aigne-hub";
|
|
8
|
+
import { AIAgent, DEFAULT_OUTPUT_KEY, readAllString, UserAgent, } from "@aigne/core";
|
|
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";
|
|
@@ -14,6 +14,7 @@ import yargs from "yargs";
|
|
|
14
14
|
import { hideBin } from "yargs/helpers";
|
|
15
15
|
import { ZodError, ZodObject, z } from "zod";
|
|
16
16
|
import { TerminalTracer } from "../tracer/terminal.js";
|
|
17
|
+
import { loadAIGNE } from "./load-aigne.js";
|
|
17
18
|
import { DEFAULT_CHAT_INPUT_KEY, runChatLoopInTerminal, } from "./run-chat-loop.js";
|
|
18
19
|
export const createRunAIGNECommand = (yargs) => yargs
|
|
19
20
|
.option("chat", {
|
|
@@ -81,6 +82,10 @@ export const createRunAIGNECommand = (yargs) => yargs
|
|
|
81
82
|
type: "string",
|
|
82
83
|
default: getLevelFromEnv(logger.options.ns) || LogLevel.INFO,
|
|
83
84
|
coerce: customZodError("--log-level", (s) => z.nativeEnum(LogLevel).parse(s)),
|
|
85
|
+
})
|
|
86
|
+
.option("aigne-hub-url", {
|
|
87
|
+
describe: "Custom AIGNE Hub service URL. Used to fetch remote agent definitions or models. ",
|
|
88
|
+
type: "string",
|
|
84
89
|
});
|
|
85
90
|
export async function parseAgentInputByCommander(agent, options = {}) {
|
|
86
91
|
const inputSchemaShape = flat(agent instanceof AIAgent ? agent.inputKey : undefined, agent.inputSchema instanceof ZodObject ? Object.keys(agent.inputSchema.shape) : []);
|
|
@@ -123,24 +128,22 @@ export async function parseAgentInputByCommander(agent, options = {}) {
|
|
|
123
128
|
}
|
|
124
129
|
return input;
|
|
125
130
|
}
|
|
126
|
-
export const parseModelOption = (model) => {
|
|
127
|
-
const { provider, name } = (model || process.env.MODEL)?.match(/(?<provider>[^:]*)(:(?<name>(\S+)))?/)?.groups ?? {};
|
|
128
|
-
return { provider, name };
|
|
129
|
-
};
|
|
130
131
|
export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoopOptions, modelOptions, outputKey, } = {}) {
|
|
131
132
|
await yargs()
|
|
132
133
|
.command("$0", "Run an agent with AIGNE", (yargs) => createRunAIGNECommand(yargs), async (options) => {
|
|
133
134
|
if (options.logLevel) {
|
|
134
135
|
logger.level = options.logLevel;
|
|
135
136
|
}
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
137
|
+
const aigne = await loadAIGNE({
|
|
138
|
+
options: {
|
|
139
|
+
...parseModelOption(options.model),
|
|
140
|
+
temperature: options.temperature,
|
|
141
|
+
topP: options.topP,
|
|
142
|
+
presencePenalty: options.presencePenalty,
|
|
143
|
+
frequencyPenalty: options.frequencyPenalty,
|
|
144
|
+
},
|
|
145
|
+
modelOptions,
|
|
146
|
+
});
|
|
144
147
|
try {
|
|
145
148
|
const agent = typeof agentCreator === "function" ? await agentCreator(aigne) : agentCreator;
|
|
146
149
|
const input = await parseAgentInputByCommander(agent, {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function highlightUrl(str: string): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.34.0",
|
|
4
4
|
"description": "Your command center for agent development",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -51,10 +51,8 @@
|
|
|
51
51
|
"@inquirer/type": "^3.0.8",
|
|
52
52
|
"@listr2/prompt-adapter-inquirer": "^3.0.1",
|
|
53
53
|
"@modelcontextprotocol/sdk": "^1.15.0",
|
|
54
|
-
"@ocap/mcrypto": "^1.21.0",
|
|
55
54
|
"@smithy/node-http-handler": "^4.1.0",
|
|
56
55
|
"chalk": "^5.4.1",
|
|
57
|
-
"crypto": "^1.0.1",
|
|
58
56
|
"detect-port": "^2.1.0",
|
|
59
57
|
"dotenv-flow": "^4.1.0",
|
|
60
58
|
"express": "^5.1.0",
|
|
@@ -64,22 +62,22 @@
|
|
|
64
62
|
"inquirer": "^12.7.0",
|
|
65
63
|
"log-update": "^6.1.0",
|
|
66
64
|
"marked": "^16.0.0",
|
|
65
|
+
"nunjucks": "^3.2.4",
|
|
67
66
|
"open": "10.1.2",
|
|
68
67
|
"openai": "^5.8.3",
|
|
69
|
-
"p-wait-for": "^5.0.2",
|
|
70
68
|
"prettier": "^3.6.2",
|
|
71
69
|
"tar": "^7.4.3",
|
|
72
70
|
"wrap-ansi": "^9.0.0",
|
|
73
71
|
"yaml": "^2.8.0",
|
|
74
72
|
"yargs": "^18.0.0",
|
|
75
73
|
"zod": "^3.25.67",
|
|
76
|
-
"@aigne/agent-library": "^1.21.
|
|
77
|
-
"@aigne/agentic-memory": "^1.0.
|
|
78
|
-
"@aigne/aigne-hub": "^0.4.
|
|
79
|
-
"@aigne/core": "^1.
|
|
74
|
+
"@aigne/agent-library": "^1.21.18",
|
|
75
|
+
"@aigne/agentic-memory": "^1.0.18",
|
|
76
|
+
"@aigne/aigne-hub": "^0.4.9",
|
|
77
|
+
"@aigne/core": "^1.49.0",
|
|
78
|
+
"@aigne/default-memory": "^1.1.0",
|
|
80
79
|
"@aigne/observability-api": "^0.9.0",
|
|
81
|
-
"@aigne/
|
|
82
|
-
"@aigne/openai": "^0.10.17"
|
|
80
|
+
"@aigne/openai": "^0.11.0"
|
|
83
81
|
},
|
|
84
82
|
"devDependencies": {
|
|
85
83
|
"@types/archiver": "^6.0.3",
|