@aigne/cli 1.25.1 → 1.26.1-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 +32 -0
- package/dist/bunwrapper.js +0 -0
- package/dist/cli.js +2 -1
- package/dist/commands/aigne.d.ts +2 -2
- package/dist/commands/aigne.js +18 -11
- package/dist/commands/app.d.ts +2 -0
- package/dist/commands/app.js +98 -0
- package/dist/commands/connect.d.ts +6 -0
- package/dist/commands/connect.js +91 -0
- 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 +6 -3
- package/dist/commands/run.js +96 -81
- 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/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/tracer/terminal.js +43 -19
- package/dist/type.d.ts +5 -0
- package/dist/type.js +1 -0
- package/dist/utils/download.d.ts +3 -1
- package/dist/utils/download.js +2 -2
- package/dist/utils/listr.js +5 -1
- package/dist/utils/load-aigne.d.ts +46 -1
- package/dist/utils/load-aigne.js +123 -91
- package/dist/utils/run-with-aigne.d.ts +26 -2
- package/dist/utils/run-with-aigne.js +80 -57
- package/package.json +41 -29
- package/LICENSE.md +0 -93
package/dist/utils/load-aigne.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import {
|
|
1
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { AIGNE } from "@aigne/core";
|
|
6
|
-
import { loadModel } from "@aigne/core/loader/index.js";
|
|
6
|
+
import { loadAIGNEFile, loadModel } from "@aigne/core/loader/index.js";
|
|
7
|
+
import { logger } from "@aigne/core/utils/logger.js";
|
|
7
8
|
import { AesCrypter } from "@ocap/mcrypto/lib/crypter/aes-legacy.js";
|
|
8
9
|
import crypto from "crypto";
|
|
9
10
|
import inquirer from "inquirer";
|
|
@@ -14,28 +15,40 @@ import { parse, stringify } from "yaml";
|
|
|
14
15
|
import { availableMemories, availableModels } from "../constants.js";
|
|
15
16
|
import { parseModelOption } from "./run-with-aigne.js";
|
|
16
17
|
const aes = new AesCrypter();
|
|
17
|
-
const decrypt = (m, s, i) => aes.decrypt(m, crypto.pbkdf2Sync(i, s, 256, 32, "sha512").toString("hex"));
|
|
18
|
+
export const decrypt = (m, s, i) => aes.decrypt(m, crypto.pbkdf2Sync(i, s, 256, 32, "sha512").toString("hex"));
|
|
19
|
+
export const encrypt = (m, s, i) => aes.encrypt(m, crypto.pbkdf2Sync(i, s, 256, 32, "sha512").toString("hex"));
|
|
18
20
|
const escapeFn = (str) => str.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
19
|
-
const
|
|
21
|
+
const unescapeFn = (str) => (str + "===".slice((str.length + 3) % 4)).replace(/-/g, "+").replace(/_/g, "/");
|
|
22
|
+
export const encodeEncryptionKey = (key) => escapeFn(Buffer.from(key).toString("base64"));
|
|
23
|
+
export const decodeEncryptionKey = (str) => new Uint8Array(Buffer.from(unescapeFn(str), "base64"));
|
|
24
|
+
const TEST_ENV = process.env.CI || process.env.NODE_ENV === "test";
|
|
25
|
+
export const AIGNE_ENV_FILE = TEST_ENV
|
|
26
|
+
? join(homedir(), ".aigne", "test-aigne-hub-connected.yaml")
|
|
27
|
+
: join(homedir(), ".aigne", "aigne-hub-connected.yaml");
|
|
20
28
|
const request = async (config) => {
|
|
21
|
-
const
|
|
22
|
-
if (
|
|
23
|
-
|
|
29
|
+
const headers = {};
|
|
30
|
+
if (config.requestCount !== undefined) {
|
|
31
|
+
headers["X-Request-Count"] = config.requestCount.toString();
|
|
24
32
|
}
|
|
33
|
+
const response = await fetch(config.url, { method: config.method || "GET", headers });
|
|
34
|
+
if (!response.ok)
|
|
35
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
25
36
|
const data = await response.json();
|
|
26
37
|
return { data };
|
|
27
38
|
};
|
|
28
39
|
const WELLKNOWN_SERVICE_PATH_PREFIX = "/.well-known/service";
|
|
29
40
|
const ACCESS_KEY_PREFIX = "/api/access-key";
|
|
30
41
|
const ACCESS_KEY_SESSION_API = `${ACCESS_KEY_PREFIX}/session`;
|
|
31
|
-
const fetchConfigs = async ({ connectUrl, sessionId, fetchInterval, fetchTimeout, }) => {
|
|
42
|
+
export const fetchConfigs = async ({ connectUrl, sessionId, fetchInterval, fetchTimeout, }) => {
|
|
32
43
|
const sessionURL = withQuery(joinURL(connectUrl, ACCESS_KEY_SESSION_API), { sid: sessionId });
|
|
44
|
+
let requestCount = 0;
|
|
33
45
|
const condition = async () => {
|
|
34
|
-
const { data: session } = await request({ url: sessionURL });
|
|
46
|
+
const { data: session } = await request({ url: sessionURL, requestCount });
|
|
47
|
+
requestCount++;
|
|
35
48
|
return Boolean(session.accessKeyId && session.accessKeySecret);
|
|
36
49
|
};
|
|
37
50
|
await pWaitFor(condition, { interval: fetchInterval, timeout: fetchTimeout });
|
|
38
|
-
const { data: session } = await request({ url: sessionURL });
|
|
51
|
+
const { data: session } = await request({ url: sessionURL, requestCount });
|
|
39
52
|
await request({ url: sessionURL, method: "DELETE" });
|
|
40
53
|
return {
|
|
41
54
|
...session,
|
|
@@ -46,7 +59,7 @@ const fetchConfigs = async ({ connectUrl, sessionId, fetchInterval, fetchTimeout
|
|
|
46
59
|
function baseWrapSpinner(_, waiting) {
|
|
47
60
|
return Promise.resolve(waiting());
|
|
48
61
|
}
|
|
49
|
-
async function createConnect({ connectUrl, openPage, fetchInterval = 3 * 1000, retry = 1500, source = "Blocklet CLI", connectAction = "connect-cli", wrapSpinner = baseWrapSpinner, closeOnSuccess, intervalFetchConfig, }) {
|
|
62
|
+
export async function createConnect({ connectUrl, openPage, fetchInterval = 3 * 1000, retry = 1500, source = "Blocklet CLI", connectAction = "connect-cli", wrapSpinner = baseWrapSpinner, closeOnSuccess, intervalFetchConfig, }) {
|
|
50
63
|
try {
|
|
51
64
|
const startSessionURL = joinURL(connectUrl, ACCESS_KEY_SESSION_API);
|
|
52
65
|
const { data: session } = await request({ url: startSessionURL, method: "POST" });
|
|
@@ -80,13 +93,11 @@ const AGENT_HUB_PROVIDER = "aignehub";
|
|
|
80
93
|
const DEFAULT_AIGNE_HUB_MODEL = "openai/gpt-4o";
|
|
81
94
|
const DEFAULT_AIGNE_HUB_PROVIDER_MODEL = `${AGENT_HUB_PROVIDER}:${DEFAULT_AIGNE_HUB_MODEL}`;
|
|
82
95
|
const DEFAULT_URL = "https://hub.aigne.io/";
|
|
83
|
-
const formatModelName = async (models, model, inquirerPrompt) => {
|
|
84
|
-
if (process.env.NODE_ENV === "test")
|
|
85
|
-
return model;
|
|
96
|
+
export const formatModelName = async (models, model, inquirerPrompt) => {
|
|
86
97
|
if (!model)
|
|
87
98
|
return DEFAULT_AIGNE_HUB_PROVIDER_MODEL;
|
|
88
99
|
const { provider, name } = parseModelOption(model);
|
|
89
|
-
if (!provider
|
|
100
|
+
if (!provider) {
|
|
90
101
|
return DEFAULT_AIGNE_HUB_PROVIDER_MODEL;
|
|
91
102
|
}
|
|
92
103
|
const providerName = provider.replace(/-/g, "");
|
|
@@ -99,6 +110,9 @@ const formatModelName = async (models, model, inquirerPrompt) => {
|
|
|
99
110
|
if (m.apiKeyEnvName && process.env[m.apiKeyEnvName]) {
|
|
100
111
|
return model;
|
|
101
112
|
}
|
|
113
|
+
if (TEST_ENV) {
|
|
114
|
+
return `${AGENT_HUB_PROVIDER}:${provider}/${name}`;
|
|
115
|
+
}
|
|
102
116
|
const result = await inquirerPrompt({
|
|
103
117
|
type: "list",
|
|
104
118
|
name: "useAigneHub",
|
|
@@ -119,88 +133,106 @@ const formatModelName = async (models, model, inquirerPrompt) => {
|
|
|
119
133
|
return model;
|
|
120
134
|
return `${AGENT_HUB_PROVIDER}:${provider}/${name}`;
|
|
121
135
|
};
|
|
122
|
-
export async function
|
|
136
|
+
export async function connectToAIGNEHub(url) {
|
|
137
|
+
const { origin, host } = new URL(url);
|
|
138
|
+
const connectUrl = joinURL(origin, WELLKNOWN_SERVICE_PATH_PREFIX);
|
|
139
|
+
const BLOCKLET_JSON_PATH = "__blocklet__.js?type=json";
|
|
140
|
+
const blockletInfo = await fetch(joinURL(origin, BLOCKLET_JSON_PATH));
|
|
141
|
+
const blocklet = await blockletInfo.json();
|
|
142
|
+
const aigneHubMount = (blocklet?.componentMountPoints || []).find((m) => m.did === "z8ia3xzq2tMq8CRHfaXj1BTYJyYnEcHbqP8cJ");
|
|
143
|
+
try {
|
|
144
|
+
const result = await createConnect({
|
|
145
|
+
connectUrl: connectUrl,
|
|
146
|
+
connectAction: "gen-simple-access-key",
|
|
147
|
+
source: `@aigne/cli connect to AIGNE hub`,
|
|
148
|
+
closeOnSuccess: true,
|
|
149
|
+
openPage: (pageUrl) => open(pageUrl),
|
|
150
|
+
});
|
|
151
|
+
const accessKeyOptions = {
|
|
152
|
+
accessKey: result.accessKeySecret,
|
|
153
|
+
url: joinURL(origin, aigneHubMount?.mountPoint || ""),
|
|
154
|
+
};
|
|
155
|
+
// After redirection, write the AIGNE Hub access token
|
|
156
|
+
const aigneDir = join(homedir(), ".aigne");
|
|
157
|
+
if (!existsSync(aigneDir)) {
|
|
158
|
+
mkdirSync(aigneDir, { recursive: true });
|
|
159
|
+
}
|
|
160
|
+
const envs = parse(await readFile(AIGNE_ENV_FILE, "utf8").catch(() => stringify({})));
|
|
161
|
+
await writeFile(AIGNE_ENV_FILE, stringify({
|
|
162
|
+
...envs,
|
|
163
|
+
[host]: {
|
|
164
|
+
AIGNE_HUB_API_KEY: accessKeyOptions.accessKey,
|
|
165
|
+
AIGNE_HUB_API_URL: accessKeyOptions.url,
|
|
166
|
+
},
|
|
167
|
+
})).catch((err) => {
|
|
168
|
+
logger.error("Failed to write AIGNE Hub access token to .aigne/aigne-hub-connected.yaml", err.message);
|
|
169
|
+
throw err;
|
|
170
|
+
});
|
|
171
|
+
return accessKeyOptions;
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
logger.error("Failed to connect to AIGNE Hub", error.message);
|
|
175
|
+
return { accessKey: undefined, url: undefined };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
export async function loadAIGNE(path, options, actionOptions) {
|
|
123
179
|
const models = availableModels();
|
|
124
|
-
const AIGNE_ENV_FILE = join(homedir(), ".aigne", "aigne-hub-connected.yaml");
|
|
125
180
|
const AIGNE_HUB_URL = process.env.AIGNE_HUB_API_URL || DEFAULT_URL;
|
|
126
181
|
const connectUrl = joinURL(new URL(AIGNE_HUB_URL).origin, WELLKNOWN_SERVICE_PATH_PREFIX);
|
|
127
|
-
const inquirerPrompt = (
|
|
182
|
+
const inquirerPrompt = (actionOptions?.inquirerPromptFn ??
|
|
128
183
|
inquirer.prompt);
|
|
184
|
+
const { aigne } = await loadAIGNEFile(path).catch(() => ({ aigne: null }));
|
|
129
185
|
let accessKeyOptions = {};
|
|
130
|
-
const modelName = await formatModelName(models, options?.model || ""
|
|
131
|
-
if (!
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
throw new Error("AIGNE_HUB_API_KEY key not found, need to login first");
|
|
150
|
-
}
|
|
151
|
-
accessKeyOptions = {
|
|
152
|
-
accessKey: env.AIGNE_HUB_API_KEY,
|
|
153
|
-
url: joinURL(env.AIGNE_HUB_API_URL),
|
|
154
|
-
};
|
|
186
|
+
const modelName = await formatModelName(models, options?.model || `${aigne?.model?.provider ?? ""}:${aigne?.model?.name ?? ""}`, inquirerPrompt);
|
|
187
|
+
if (TEST_ENV && !actionOptions?.runTest) {
|
|
188
|
+
const model = await loadModel(models, parseModelOption(modelName), undefined, accessKeyOptions);
|
|
189
|
+
return await AIGNE.load(path, { models, memories: availableMemories, model });
|
|
190
|
+
}
|
|
191
|
+
if ((modelName.toLocaleLowerCase() || "").includes(AGENT_HUB_PROVIDER)) {
|
|
192
|
+
const { host } = new URL(AIGNE_HUB_URL);
|
|
193
|
+
try {
|
|
194
|
+
// aigne-hub access token
|
|
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");
|
|
155
205
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
source: `@aigne/cli connect to AIGNE hub`,
|
|
185
|
-
closeOnSuccess: true,
|
|
186
|
-
openPage: (pageUrl) => open(pageUrl),
|
|
187
|
-
});
|
|
188
|
-
accessKeyOptions = {
|
|
189
|
-
accessKey: result.accessKeySecret,
|
|
190
|
-
url: joinURL(origin, aigneHubMount?.mountPoint || ""),
|
|
191
|
-
};
|
|
192
|
-
// After redirection, write the AIGNE Hub access token
|
|
193
|
-
await appendFile(AIGNE_ENV_FILE, stringify({
|
|
194
|
-
[host]: {
|
|
195
|
-
AIGNE_HUB_API_KEY: accessKeyOptions.accessKey,
|
|
196
|
-
AIGNE_HUB_API_URL: accessKeyOptions.url,
|
|
197
|
-
},
|
|
198
|
-
}));
|
|
199
|
-
}
|
|
200
|
-
catch (error) {
|
|
201
|
-
console.error(error);
|
|
202
|
-
}
|
|
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
|
+
};
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
if (error instanceof Error && error.message.includes("login first")) {
|
|
217
|
+
// If none or invalid, prompt the user to proceed
|
|
218
|
+
const subscribePrompt = await inquirerPrompt({
|
|
219
|
+
type: "list",
|
|
220
|
+
name: "subscribe",
|
|
221
|
+
message: "No LLM API Keys or AIGNE Hub connections found, select your preferred way to continue:",
|
|
222
|
+
choices: [
|
|
223
|
+
{
|
|
224
|
+
name: "Connect to AIGNE Hub with just a few clicks, free credits eligible for new users (Recommended)",
|
|
225
|
+
value: true,
|
|
226
|
+
},
|
|
227
|
+
{ name: "Exit and configure my own LLM API Keys", value: false },
|
|
228
|
+
],
|
|
229
|
+
default: true,
|
|
230
|
+
});
|
|
231
|
+
if (!subscribePrompt.subscribe) {
|
|
232
|
+
console.warn("The AIGNE Hub connection has been cancelled");
|
|
233
|
+
process.exit(0);
|
|
203
234
|
}
|
|
235
|
+
accessKeyOptions = await connectToAIGNEHub(connectUrl);
|
|
204
236
|
}
|
|
205
237
|
}
|
|
206
238
|
}
|
|
@@ -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[];
|
|
@@ -4,67 +4,90 @@ 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
14
|
import { ZodError, ZodObject, z } from "zod";
|
|
15
15
|
import { availableModels } from "../constants.js";
|
|
16
16
|
import { TerminalTracer } from "../tracer/terminal.js";
|
|
17
17
|
import { DEFAULT_CHAT_INPUT_KEY, runChatLoopInTerminal, } from "./run-chat-loop.js";
|
|
18
|
-
export const createRunAIGNECommand = (
|
|
19
|
-
.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.
|
|
25
|
-
.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
.option("
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
.option("
|
|
18
|
+
export const createRunAIGNECommand = (yargs) => yargs
|
|
19
|
+
.option("chat", {
|
|
20
|
+
describe: "Run chat loop in terminal",
|
|
21
|
+
type: "boolean",
|
|
22
|
+
default: false,
|
|
23
|
+
})
|
|
24
|
+
.option("model", {
|
|
25
|
+
describe: `AI model to use in format 'provider[:model]' where model is optional. Examples: 'openai' or 'openai:gpt-4o-mini'. Available providers: ${availableModels()
|
|
26
|
+
.map((i) => i.name.toLowerCase().replace(/ChatModel$/i, ""))
|
|
27
|
+
.join(", ")} (default: openai)`,
|
|
28
|
+
type: "string",
|
|
29
|
+
})
|
|
30
|
+
.option("temperature", {
|
|
31
|
+
describe: "Temperature for the model (controls randomness, higher values produce more random outputs). Range: 0.0-2.0",
|
|
32
|
+
type: "number",
|
|
33
|
+
coerce: customZodError("--temperature", (s) => z.coerce.number().min(0).max(2).parse(s)),
|
|
34
|
+
})
|
|
35
|
+
.option("top-p", {
|
|
36
|
+
describe: "Top P (nucleus sampling) parameter for the model (controls diversity). Range: 0.0-1.0",
|
|
37
|
+
type: "number",
|
|
38
|
+
coerce: customZodError("--top-p", (s) => z.coerce.number().min(0).max(1).parse(s)),
|
|
39
|
+
})
|
|
40
|
+
.option("presence-penalty", {
|
|
41
|
+
describe: "Presence penalty for the model (penalizes repeating the same tokens). Range: -2.0 to 2.0",
|
|
42
|
+
type: "number",
|
|
43
|
+
coerce: customZodError("--presence-penalty", (s) => z.coerce.number().min(-2).max(2).parse(s)),
|
|
44
|
+
})
|
|
45
|
+
.option("frequency-penalty", {
|
|
46
|
+
describe: "Frequency penalty for the model (penalizes frequency of token usage). Range: -2.0 to 2.0",
|
|
47
|
+
type: "number",
|
|
48
|
+
coerce: customZodError("--frequency-penalty", (s) => z.coerce.number().min(-2).max(2).parse(s)),
|
|
49
|
+
})
|
|
50
|
+
.option("input", {
|
|
51
|
+
describe: "Input to the agent, use @<file> to read from a file",
|
|
52
|
+
type: "array",
|
|
53
|
+
alias: "i",
|
|
54
|
+
})
|
|
55
|
+
.option("format", {
|
|
56
|
+
describe: "Input format for the agent (available: text, json, yaml default: text)",
|
|
57
|
+
type: "string",
|
|
58
|
+
})
|
|
59
|
+
.option("output", {
|
|
60
|
+
describe: "Output file to save the result (default: stdout)",
|
|
61
|
+
type: "string",
|
|
62
|
+
alias: "o",
|
|
63
|
+
})
|
|
64
|
+
.option("output-key", {
|
|
65
|
+
describe: "Key in the result to save to the output file",
|
|
66
|
+
type: "string",
|
|
67
|
+
default: DEFAULT_OUTPUT_KEY,
|
|
68
|
+
})
|
|
69
|
+
.option("force", {
|
|
70
|
+
describe: "Truncate the output file if it exists, and create directory if the output path is not exists",
|
|
71
|
+
type: "boolean",
|
|
72
|
+
default: false,
|
|
73
|
+
})
|
|
74
|
+
.option("log-level", {
|
|
75
|
+
describe: `Log level for detailed debugging information. Values: ${Object.values(LogLevel).join(", ")}`,
|
|
76
|
+
type: "string",
|
|
77
|
+
default: getLevelFromEnv(logger.options.ns) || LogLevel.INFO,
|
|
78
|
+
coerce: customZodError("--log-level", (s) => z.nativeEnum(LogLevel).parse(s)),
|
|
79
|
+
});
|
|
36
80
|
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
|
-
});
|
|
81
|
+
const inputSchemaShape = flat(agent instanceof AIAgent ? agent.inputKey : undefined, agent.inputSchema instanceof ZodObject ? Object.keys(agent.inputSchema.shape) : []);
|
|
82
|
+
const parsedInput = await yargs().parseAsync(options.argv ?? process.argv);
|
|
83
|
+
const input = Object.fromEntries(await Promise.all(inputSchemaShape.map(async (key) => {
|
|
84
|
+
const k = `input${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
85
|
+
let value = parsedInput[k];
|
|
86
|
+
if (typeof value === "string" && value.startsWith("@")) {
|
|
87
|
+
value = await readFile(value.slice(1), "utf8");
|
|
88
|
+
}
|
|
89
|
+
return [key, value];
|
|
90
|
+
})));
|
|
68
91
|
const rawInput = options.input ||
|
|
69
92
|
(isatty(process.stdin.fd) || !(await stdinHasData())
|
|
70
93
|
? null
|
|
@@ -96,14 +119,12 @@ export async function parseAgentInputByCommander(agent, options = {}) {
|
|
|
96
119
|
return input;
|
|
97
120
|
}
|
|
98
121
|
export const parseModelOption = (model) => {
|
|
99
|
-
const { provider, name } = (model || process.env.MODEL)?.match(/(?<provider>[^:]
|
|
122
|
+
const { provider, name } = (model || process.env.MODEL)?.match(/(?<provider>[^:]*)(:(?<name>(\S+)))?/)?.groups ?? {};
|
|
100
123
|
return { provider, name };
|
|
101
124
|
};
|
|
102
125
|
export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoopOptions, modelOptions, outputKey, } = {}) {
|
|
103
|
-
await
|
|
104
|
-
.
|
|
105
|
-
.showSuggestionAfterError(true)
|
|
106
|
-
.action(async (options) => {
|
|
126
|
+
await yargs()
|
|
127
|
+
.command("$0", "Run an agent with AIGNE", (yargs) => createRunAIGNECommand(yargs), async (options) => {
|
|
107
128
|
if (options.logLevel) {
|
|
108
129
|
logger.level = options.logLevel;
|
|
109
130
|
}
|
|
@@ -134,6 +155,8 @@ export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoop
|
|
|
134
155
|
await aigne.shutdown();
|
|
135
156
|
}
|
|
136
157
|
})
|
|
158
|
+
.alias("h", "help")
|
|
159
|
+
.alias("v", "version")
|
|
137
160
|
.parseAsync(argv)
|
|
138
161
|
.catch((error) => {
|
|
139
162
|
console.error(`${chalk.red("Error:")} ${error.message}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.1-0",
|
|
4
4
|
"description": "cli for AIGNE framework",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -24,26 +24,60 @@
|
|
|
24
24
|
"bunwrapper": "dist/bunwrapper.js"
|
|
25
25
|
},
|
|
26
26
|
"type": "module",
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"module": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
27
30
|
"exports": {
|
|
31
|
+
".": "./dist/index.js",
|
|
28
32
|
"./*": "./dist/*"
|
|
29
33
|
},
|
|
30
34
|
"typesVersions": {
|
|
31
35
|
"*": {
|
|
36
|
+
".": [
|
|
37
|
+
"./lib/dts/index.d.ts"
|
|
38
|
+
],
|
|
32
39
|
"*": [
|
|
33
40
|
"./dist/*"
|
|
34
41
|
]
|
|
35
42
|
}
|
|
36
43
|
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"lint": "tsc --noEmit",
|
|
46
|
+
"build": "tsc --build tsconfig.build.json",
|
|
47
|
+
"clean": "rimraf dist test/coverage templates/coverage",
|
|
48
|
+
"prepublishOnly": "run-s clean build",
|
|
49
|
+
"test": "run-s test:src test:templates",
|
|
50
|
+
"test:coverage": "run-s test:src:coverage test:templates:coverage",
|
|
51
|
+
"test:src": "bun --cwd test test",
|
|
52
|
+
"test:src:coverage": "bun --cwd test test --coverage --coverage-reporter=lcov --coverage-reporter=text",
|
|
53
|
+
"test:templates": "cd templates && node --test",
|
|
54
|
+
"test:templates:coverage": "cd templates && mkdir -p coverage && node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --test-reporter=spec --test-reporter-destination=stdout"
|
|
55
|
+
},
|
|
37
56
|
"dependencies": {
|
|
57
|
+
"@aigne/agent-library": "workspace:^",
|
|
58
|
+
"@aigne/agentic-memory": "workspace:^",
|
|
59
|
+
"@aigne/aigne-hub": "workspace:^",
|
|
60
|
+
"@aigne/anthropic": "workspace:^",
|
|
61
|
+
"@aigne/bedrock": "workspace:^",
|
|
62
|
+
"@aigne/core": "workspace:^",
|
|
63
|
+
"@aigne/deepseek": "workspace:^",
|
|
64
|
+
"@aigne/default-memory": "workspace:^",
|
|
65
|
+
"@aigne/gemini": "workspace:^",
|
|
38
66
|
"@aigne/listr2": "^1.0.10",
|
|
39
67
|
"@aigne/marked-terminal": "^7.3.2",
|
|
68
|
+
"@aigne/observability-api": "workspace:^",
|
|
69
|
+
"@aigne/ollama": "workspace:^",
|
|
70
|
+
"@aigne/open-router": "workspace:^",
|
|
71
|
+
"@aigne/openai": "workspace:^",
|
|
72
|
+
"@aigne/xai": "workspace:^",
|
|
73
|
+
"@blocklet/aigne-hub": "^0.2.17",
|
|
40
74
|
"@inquirer/prompts": "^7.6.0",
|
|
75
|
+
"@inquirer/type": "^3.0.8",
|
|
41
76
|
"@listr2/prompt-adapter-inquirer": "^3.0.1",
|
|
42
77
|
"@modelcontextprotocol/sdk": "^1.15.0",
|
|
43
78
|
"@ocap/mcrypto": "^1.21.0",
|
|
44
79
|
"@smithy/node-http-handler": "^4.1.0",
|
|
45
80
|
"chalk": "^5.4.1",
|
|
46
|
-
"commander": "^14.0.0",
|
|
47
81
|
"crypto": "^1.0.1",
|
|
48
82
|
"detect-port": "^2.1.0",
|
|
49
83
|
"dotenv-flow": "^4.1.0",
|
|
@@ -61,21 +95,8 @@
|
|
|
61
95
|
"tar": "^7.4.3",
|
|
62
96
|
"wrap-ansi": "^9.0.0",
|
|
63
97
|
"yaml": "^2.8.0",
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"@aigne/agentic-memory": "^1.0.5",
|
|
67
|
-
"@aigne/aigne-hub": "^0.2.1",
|
|
68
|
-
"@aigne/anthropic": "^0.10.1",
|
|
69
|
-
"@aigne/core": "^1.38.1",
|
|
70
|
-
"@aigne/default-memory": "^1.0.5",
|
|
71
|
-
"@aigne/deepseek": "^0.7.5",
|
|
72
|
-
"@aigne/bedrock": "^0.8.5",
|
|
73
|
-
"@aigne/gemini": "^0.8.5",
|
|
74
|
-
"@aigne/ollama": "^0.7.5",
|
|
75
|
-
"@aigne/open-router": "^0.7.5",
|
|
76
|
-
"@aigne/observability-api": "^0.8.1",
|
|
77
|
-
"@aigne/openai": "^0.10.5",
|
|
78
|
-
"@aigne/xai": "^0.7.5"
|
|
98
|
+
"yargs": "^18.0.0",
|
|
99
|
+
"zod": "^3.25.67"
|
|
79
100
|
},
|
|
80
101
|
"devDependencies": {
|
|
81
102
|
"@types/archiver": "^6.0.3",
|
|
@@ -84,21 +105,12 @@
|
|
|
84
105
|
"@types/glob": "^9.0.0",
|
|
85
106
|
"@types/gradient-string": "^1.1.6",
|
|
86
107
|
"@types/node": "^24.0.12",
|
|
108
|
+
"@types/yargs": "^17.0.33",
|
|
87
109
|
"archiver": "^7.0.1",
|
|
110
|
+
"hono": "4.8.4",
|
|
88
111
|
"npm-run-all": "^4.1.5",
|
|
89
112
|
"rimraf": "^6.0.1",
|
|
90
113
|
"typescript": "^5.8.3",
|
|
91
114
|
"ufo": "^1.6.1"
|
|
92
|
-
},
|
|
93
|
-
"scripts": {
|
|
94
|
-
"lint": "tsc --noEmit",
|
|
95
|
-
"build": "tsc --build tsconfig.build.json",
|
|
96
|
-
"clean": "rimraf dist test/coverage templates/coverage",
|
|
97
|
-
"test": "run-s test:src test:templates",
|
|
98
|
-
"test:coverage": "run-s test:src:coverage test:templates:coverage",
|
|
99
|
-
"test:src": "bun --cwd test test",
|
|
100
|
-
"test:src:coverage": "bun --cwd test test --coverage --coverage-reporter=lcov --coverage-reporter=text",
|
|
101
|
-
"test:templates": "cd templates && node --test",
|
|
102
|
-
"test:templates:coverage": "cd templates && mkdir -p coverage && node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --test-reporter=spec --test-reporter-destination=stdout"
|
|
103
115
|
}
|
|
104
|
-
}
|
|
116
|
+
}
|