@aigne/cli 1.11.9 → 1.13.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 +46 -0
- package/dist/commands/run.js +6 -4
- package/dist/tracer/terminal.d.ts +2 -0
- package/dist/tracer/terminal.js +22 -6
- package/dist/utils/run-with-aigne.d.ts +16 -7
- package/dist/utils/run-with-aigne.js +118 -18
- package/package.json +12 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.13.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.12.0...cli-v1.13.0) (2025-06-24)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* support observability for cli and blocklet ([#155](https://github.com/AIGNE-io/aigne-framework/issues/155)) ([5baa705](https://github.com/AIGNE-io/aigne-framework/commit/5baa705a33cfdba1efc5ccbe18674c27513ca97d))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @aigne/agent-library bumped to 1.15.0
|
|
16
|
+
* @aigne/anthropic bumped to 0.3.4
|
|
17
|
+
* @aigne/bedrock bumped to 0.3.4
|
|
18
|
+
* @aigne/core bumped to 1.22.0
|
|
19
|
+
* @aigne/deepseek bumped to 0.3.4
|
|
20
|
+
* @aigne/gemini bumped to 0.3.4
|
|
21
|
+
* @aigne/ollama bumped to 0.3.4
|
|
22
|
+
* @aigne/open-router bumped to 0.3.4
|
|
23
|
+
* @aigne/openai bumped to 0.3.4
|
|
24
|
+
* @aigne/xai bumped to 0.3.4
|
|
25
|
+
|
|
26
|
+
## [1.12.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.11.9...cli-v1.12.0) (2025-06-20)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Features
|
|
30
|
+
|
|
31
|
+
* **cli:** support pass named input to agent by --input-xxx ([#167](https://github.com/AIGNE-io/aigne-framework/issues/167)) ([cda5bb6](https://github.com/AIGNE-io/aigne-framework/commit/cda5bb6baab680787de1a042664fe34c17a84bb1))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Dependencies
|
|
35
|
+
|
|
36
|
+
* The following workspace dependencies were updated
|
|
37
|
+
* dependencies
|
|
38
|
+
* @aigne/agent-library bumped to 1.14.0
|
|
39
|
+
* @aigne/anthropic bumped to 0.3.3
|
|
40
|
+
* @aigne/bedrock bumped to 0.3.3
|
|
41
|
+
* @aigne/core bumped to 1.21.0
|
|
42
|
+
* @aigne/deepseek bumped to 0.3.3
|
|
43
|
+
* @aigne/gemini bumped to 0.3.3
|
|
44
|
+
* @aigne/ollama bumped to 0.3.3
|
|
45
|
+
* @aigne/open-router bumped to 0.3.3
|
|
46
|
+
* @aigne/openai bumped to 0.3.3
|
|
47
|
+
* @aigne/xai bumped to 0.3.3
|
|
48
|
+
|
|
3
49
|
## [1.11.9](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.11.8...cli-v1.11.9) (2025-06-19)
|
|
4
50
|
|
|
5
51
|
|
package/dist/commands/run.js
CHANGED
|
@@ -10,14 +10,15 @@ import { Listr, PRESET_TIMER } from "@aigne/listr2";
|
|
|
10
10
|
import { availableMemories, availableModels } from "../constants.js";
|
|
11
11
|
import { isV1Package, toAIGNEPackage } from "../utils/agent-v1.js";
|
|
12
12
|
import { downloadAndExtract } from "../utils/download.js";
|
|
13
|
-
import { createRunAIGNECommand, parseModelOption, runAgentWithAIGNE, } from "../utils/run-with-aigne.js";
|
|
13
|
+
import { createRunAIGNECommand, parseAgentInputByCommander, parseModelOption, runAgentWithAIGNE, } from "../utils/run-with-aigne.js";
|
|
14
14
|
export function createRunCommand() {
|
|
15
15
|
return createRunAIGNECommand()
|
|
16
16
|
.description("Run AIGNE from the specified agent")
|
|
17
|
-
.
|
|
17
|
+
.option("--url, --path <path_or_url>", "Path to the agents directory or URL to aigne project", ".")
|
|
18
18
|
.option("--entry-agent <entry-agent>", "Name of the agent to run (defaults to the first agent found)")
|
|
19
19
|
.option("--cache-dir <dir>", "Directory to download the package to (defaults to the ~/.aigne/xxx)")
|
|
20
|
-
.action(async (
|
|
20
|
+
.action(async (options) => {
|
|
21
|
+
const { path } = options;
|
|
21
22
|
if (options.logLevel)
|
|
22
23
|
logger.level = options.logLevel;
|
|
23
24
|
const { cacheDir, dir } = prepareDirs(path, options);
|
|
@@ -78,8 +79,9 @@ export function createRunCommand() {
|
|
|
78
79
|
}).run();
|
|
79
80
|
assert(aigne);
|
|
80
81
|
assert(agent);
|
|
82
|
+
const input = await parseAgentInputByCommander(agent, options);
|
|
81
83
|
try {
|
|
82
|
-
await runAgentWithAIGNE(aigne, agent, { ...options });
|
|
84
|
+
await runAgentWithAIGNE(aigne, agent, { ...options, input });
|
|
83
85
|
}
|
|
84
86
|
finally {
|
|
85
87
|
await aigne.shutdown();
|
|
@@ -4,6 +4,7 @@ import { type Listr } from "@aigne/listr2";
|
|
|
4
4
|
import { type AIGNEListrTaskWrapper } from "../utils/listr.js";
|
|
5
5
|
export interface TerminalTracerOptions {
|
|
6
6
|
printRequest?: boolean;
|
|
7
|
+
outputKey?: string;
|
|
7
8
|
}
|
|
8
9
|
export declare class TerminalTracer {
|
|
9
10
|
readonly context: Context;
|
|
@@ -24,6 +25,7 @@ export declare class TerminalTracer {
|
|
|
24
25
|
time?: boolean;
|
|
25
26
|
}): string;
|
|
26
27
|
private marked;
|
|
28
|
+
get outputKey(): string;
|
|
27
29
|
formatRequest(agent: Agent, _context: Context, m?: Message): string | undefined;
|
|
28
30
|
formatResult(agent: Agent, context: Context, m?: Message): string;
|
|
29
31
|
}
|
package/dist/tracer/terminal.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EOL } from "node:os";
|
|
2
2
|
import { inspect } from "node:util";
|
|
3
|
-
import { AIAgent, ChatModel, } from "@aigne/core";
|
|
3
|
+
import { AIAgent, ChatModel, DEFAULT_OUTPUT_KEY, } from "@aigne/core";
|
|
4
4
|
import { LogLevel, logger } from "@aigne/core/utils/logger.js";
|
|
5
5
|
import { promiseWithResolvers } from "@aigne/core/utils/promise.js";
|
|
6
6
|
import { omit } from "@aigne/core/utils/type-utils.js";
|
|
@@ -19,6 +19,7 @@ export class TerminalTracer {
|
|
|
19
19
|
}
|
|
20
20
|
tasks = {};
|
|
21
21
|
async run(agent, input) {
|
|
22
|
+
await this.context.observer?.serve();
|
|
22
23
|
const context = this.context.newContext({ reset: true });
|
|
23
24
|
const listr = new AIGNEListr({
|
|
24
25
|
formatRequest: () => this.options.printRequest ? this.formatRequest(agent, context, input) : undefined,
|
|
@@ -86,7 +87,7 @@ export class TerminalTracer {
|
|
|
86
87
|
context.on("agentSucceed", onAgentSucceed);
|
|
87
88
|
context.on("agentFailed", onAgentFailed);
|
|
88
89
|
try {
|
|
89
|
-
const result = await listr.run(() => context.invoke(agent, input, { streaming: true }));
|
|
90
|
+
const result = await listr.run(() => context.invoke(agent, input, { streaming: true, newContext: false }));
|
|
90
91
|
return { result, context };
|
|
91
92
|
}
|
|
92
93
|
finally {
|
|
@@ -121,7 +122,19 @@ export class TerminalTracer {
|
|
|
121
122
|
title += ` ${this.formatTimeUsage(task.startTime, task.endTime)}`;
|
|
122
123
|
return title;
|
|
123
124
|
}
|
|
124
|
-
marked = new Marked().use(
|
|
125
|
+
marked = new Marked().use({
|
|
126
|
+
// marked-terminal does not support code block meta, so we need to strip it
|
|
127
|
+
walkTokens: (token) => {
|
|
128
|
+
if (token.type === "code") {
|
|
129
|
+
if (typeof token.lang === "string") {
|
|
130
|
+
token.lang = token.lang.trim().split(/\s+/)[0];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
}, markedTerminal({ forceHyperLink: false }));
|
|
135
|
+
get outputKey() {
|
|
136
|
+
return this.options.outputKey || DEFAULT_OUTPUT_KEY;
|
|
137
|
+
}
|
|
125
138
|
formatRequest(agent, _context, m = {}) {
|
|
126
139
|
if (!logger.enabled(LogLevel.INFO))
|
|
127
140
|
return;
|
|
@@ -134,16 +147,19 @@ export class TerminalTracer {
|
|
|
134
147
|
return [prefix, [text, json].filter(Boolean).join(EOL)].join(" ");
|
|
135
148
|
}
|
|
136
149
|
formatResult(agent, context, m = {}) {
|
|
150
|
+
const { isTTY } = process.stdout;
|
|
137
151
|
const outputKey = agent instanceof AIAgent ? agent.outputKey : undefined;
|
|
138
152
|
const prefix = logger.enabled(LogLevel.INFO)
|
|
139
153
|
? `${chalk.grey(figures.tick)} 🤖 ${this.formatTokenUsage(context.usage)}`
|
|
140
154
|
: null;
|
|
141
155
|
const msg = outputKey ? m[outputKey] : undefined;
|
|
142
156
|
const message = outputKey ? omit(m, outputKey) : m;
|
|
143
|
-
const text = msg && typeof msg === "string"
|
|
144
|
-
|
|
145
|
-
|
|
157
|
+
const text = msg && typeof msg === "string"
|
|
158
|
+
? isTTY
|
|
159
|
+
? this.marked.parse(msg, { async: false }).trim()
|
|
160
|
+
: msg
|
|
146
161
|
: undefined;
|
|
162
|
+
const json = Object.keys(message).length > 0 ? inspect(message, { colors: isTTY }) : undefined;
|
|
147
163
|
return [prefix, text, json].filter(Boolean).join(EOL);
|
|
148
164
|
}
|
|
149
165
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AIGNE, type Agent, type ChatModelOptions } from "@aigne/core";
|
|
1
|
+
import { AIGNE, type Agent, 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 { Command } from "commander";
|
|
@@ -10,23 +10,32 @@ export interface RunAIGNECommandOptions {
|
|
|
10
10
|
topP?: number;
|
|
11
11
|
presencePenalty?: number;
|
|
12
12
|
frequencyPenalty?: number;
|
|
13
|
-
input?: string;
|
|
13
|
+
input?: string[];
|
|
14
|
+
format?: "text" | "json" | "yaml";
|
|
15
|
+
output?: string;
|
|
14
16
|
logLevel?: LogLevel;
|
|
17
|
+
force?: boolean;
|
|
15
18
|
}
|
|
16
19
|
export declare const createRunAIGNECommand: (name?: string) => Command;
|
|
20
|
+
export declare function parseAgentInputByCommander(agent: Agent, options?: RunAIGNECommandOptions & {
|
|
21
|
+
inputKey?: string;
|
|
22
|
+
argv?: string[];
|
|
23
|
+
}): Promise<Message>;
|
|
17
24
|
export declare const parseModelOption: (model?: string) => {
|
|
18
25
|
provider: string | undefined;
|
|
19
26
|
name: string | undefined;
|
|
20
27
|
};
|
|
21
|
-
export declare function runWithAIGNE(agentCreator: ((aigne: AIGNE) => PromiseOrValue<Agent>) | Agent, { argv, chatLoopOptions, modelOptions, }?: {
|
|
28
|
+
export declare function runWithAIGNE(agentCreator: ((aigne: AIGNE) => PromiseOrValue<Agent>) | Agent, { argv, chatLoopOptions, modelOptions, outputKey, }?: {
|
|
22
29
|
argv?: typeof process.argv;
|
|
23
30
|
chatLoopOptions?: ChatLoopOptions;
|
|
24
31
|
modelOptions?: ChatModelOptions;
|
|
32
|
+
outputKey?: string;
|
|
25
33
|
}): Promise<void>;
|
|
26
|
-
export declare function runAgentWithAIGNE(aigne: AIGNE, agent: Agent, { chatLoopOptions, modelOptions, ...options }?: {
|
|
34
|
+
export declare function runAgentWithAIGNE(aigne: AIGNE, agent: Agent, { outputKey, chatLoopOptions, modelOptions, ...options }?: {
|
|
35
|
+
outputKey?: string;
|
|
27
36
|
chatLoopOptions?: ChatLoopOptions;
|
|
28
37
|
modelOptions?: ChatModelOptions;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
input?: Message;
|
|
39
|
+
} & Omit<RunAIGNECommandOptions, "input">): Promise<{
|
|
40
|
+
result: Message;
|
|
32
41
|
} | undefined>;
|
|
@@ -1,18 +1,24 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
1
2
|
import { fstat } from "node:fs";
|
|
3
|
+
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
4
|
+
import { dirname, isAbsolute, join } from "node:path";
|
|
2
5
|
import { isatty } from "node:tty";
|
|
3
6
|
import { promisify } from "node:util";
|
|
4
|
-
import {
|
|
7
|
+
import { exists } from "@aigne/agent-library/utils/fs.js";
|
|
8
|
+
import { AIGNE, DEFAULT_OUTPUT_KEY, UserAgent, readAllString, } from "@aigne/core";
|
|
5
9
|
import { loadModel } from "@aigne/core/loader/index.js";
|
|
6
10
|
import { LogLevel, getLevelFromEnv, logger } from "@aigne/core/utils/logger.js";
|
|
7
|
-
import {
|
|
8
|
-
import { tryOrThrow } from "@aigne/core/utils/type-utils.js";
|
|
11
|
+
import { isEmpty, isNonNullable, tryOrThrow, } from "@aigne/core/utils/type-utils.js";
|
|
9
12
|
import { Command } from "commander";
|
|
10
13
|
import PrettyError from "pretty-error";
|
|
11
|
-
import {
|
|
14
|
+
import { parse } from "yaml";
|
|
15
|
+
import { ZodError, ZodObject, z } from "zod";
|
|
12
16
|
import { availableModels } from "../constants.js";
|
|
13
17
|
import { TerminalTracer } from "../tracer/terminal.js";
|
|
14
18
|
import { DEFAULT_CHAT_INPUT_KEY, runChatLoopInTerminal, } from "./run-chat-loop.js";
|
|
15
19
|
export const createRunAIGNECommand = (name = "run") => new Command(name)
|
|
20
|
+
.allowUnknownOption(true)
|
|
21
|
+
.allowExcessArguments(true)
|
|
16
22
|
.description("Run agent with AIGNE in terminal")
|
|
17
23
|
.option("--chat", "Run chat loop in terminal", false)
|
|
18
24
|
.option("--model <provider[:model]>", `AI model to use in format 'provider[:model]' where model is optional. Examples: 'openai' or 'openai:gpt-4o-mini'. Available providers: ${availableModels.map((i) => i.name.toLowerCase().replace(/ChatModel$/i, "")).join(", ")} (default: openai)`)
|
|
@@ -20,13 +26,73 @@ export const createRunAIGNECommand = (name = "run") => new Command(name)
|
|
|
20
26
|
.option("--top-p <top-p>", "Top P (nucleus sampling) parameter for the model (controls diversity). Range: 0.0-1.0", customZodError("--top-p", (s) => z.coerce.number().min(0).max(1).parse(s)))
|
|
21
27
|
.option("--presence-penalty <presence-penalty>", "Presence penalty for the model (penalizes repeating the same tokens). Range: -2.0 to 2.0", customZodError("--presence-penalty", (s) => z.coerce.number().min(-2).max(2).parse(s)))
|
|
22
28
|
.option("--frequency-penalty <frequency-penalty>", "Frequency penalty for the model (penalizes frequency of token usage). Range: -2.0 to 2.0", customZodError("--frequency-penalty", (s) => z.coerce.number().min(-2).max(2).parse(s)))
|
|
23
|
-
.option("--input -i <input
|
|
29
|
+
.option("--input -i <input...>", "Input to the agent, use @<file> to read from a file")
|
|
30
|
+
.option("--format <format>", "Input format for the agent (available: text, json, yaml default: text)")
|
|
31
|
+
.option("--output -o <output>", "Output file to save the result (default: stdout)")
|
|
32
|
+
.option("--output-key <output-key>", "Key in the result to save to the output file", DEFAULT_OUTPUT_KEY)
|
|
33
|
+
.option("--force", "Truncate the output file if it exists, and create directory if the output path is not exists", false)
|
|
24
34
|
.option("--log-level <level>", `Log level for detailed debugging information. Values: ${Object.values(LogLevel).join(", ")}`, customZodError("--log-level", (s) => z.nativeEnum(LogLevel).parse(s)), getLevelFromEnv(logger.options.ns) || LogLevel.INFO);
|
|
35
|
+
export async function parseAgentInputByCommander(agent, options = {}) {
|
|
36
|
+
const cmd = new Command()
|
|
37
|
+
.description(`Run agent ${agent.name} with AIGNE`)
|
|
38
|
+
.allowUnknownOption(true)
|
|
39
|
+
.allowExcessArguments(true);
|
|
40
|
+
const inputSchemaShape = agent.inputSchema instanceof ZodObject ? Object.keys(agent.inputSchema.shape) : [];
|
|
41
|
+
for (const option of inputSchemaShape) {
|
|
42
|
+
cmd.option(`--input-${option} <${option}>`);
|
|
43
|
+
}
|
|
44
|
+
const input = await new Promise((resolve, reject) => {
|
|
45
|
+
cmd
|
|
46
|
+
.action(async (agentInputOptions) => {
|
|
47
|
+
try {
|
|
48
|
+
const input = Object.fromEntries((await Promise.all(Object.entries(agentInputOptions).map(async ([key, value]) => {
|
|
49
|
+
let k = key.replace(/^input/, "");
|
|
50
|
+
k = k.charAt(0).toLowerCase() + k.slice(1);
|
|
51
|
+
if (!k)
|
|
52
|
+
return null;
|
|
53
|
+
if (typeof value === "string" && value.startsWith("@")) {
|
|
54
|
+
value = await readFile(value.slice(1), "utf8");
|
|
55
|
+
}
|
|
56
|
+
return [k, value];
|
|
57
|
+
}))).filter(isNonNullable));
|
|
58
|
+
resolve(input);
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
reject(error);
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
.parseAsync(options.argv ?? process.argv)
|
|
65
|
+
.catch((error) => reject(error));
|
|
66
|
+
});
|
|
67
|
+
const rawInput = options.input ||
|
|
68
|
+
(isatty(process.stdin.fd) || !(await stdinHasData())
|
|
69
|
+
? null
|
|
70
|
+
: [await readAllString(process.stdin)]);
|
|
71
|
+
if (rawInput?.length) {
|
|
72
|
+
for (let raw of rawInput) {
|
|
73
|
+
if (raw.startsWith("@")) {
|
|
74
|
+
raw = await readFile(raw.slice(1), "utf8");
|
|
75
|
+
}
|
|
76
|
+
if (options.format === "json") {
|
|
77
|
+
Object.assign(input, JSON.parse(raw));
|
|
78
|
+
}
|
|
79
|
+
else if (options.format === "yaml") {
|
|
80
|
+
Object.assign(input, parse(raw));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
Object.assign(input, typeof options.inputKey === "string"
|
|
84
|
+
? { [options.inputKey]: raw }
|
|
85
|
+
: { [DEFAULT_CHAT_INPUT_KEY]: raw });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return input;
|
|
90
|
+
}
|
|
25
91
|
export const parseModelOption = (model) => {
|
|
26
92
|
const { provider, name } = model?.match(/(?<provider>[^:]+)(:(?<name>(\S+)))?/)?.groups ?? {};
|
|
27
93
|
return { provider, name };
|
|
28
94
|
};
|
|
29
|
-
export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoopOptions, modelOptions, } = {}) {
|
|
95
|
+
export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoopOptions, modelOptions, outputKey, } = {}) {
|
|
30
96
|
await createRunAIGNECommand()
|
|
31
97
|
.showHelpAfterError(true)
|
|
32
98
|
.showSuggestionAfterError(true)
|
|
@@ -44,7 +110,23 @@ export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoop
|
|
|
44
110
|
const aigne = new AIGNE({ model });
|
|
45
111
|
try {
|
|
46
112
|
const agent = typeof agentCreator === "function" ? await agentCreator(aigne) : agentCreator;
|
|
47
|
-
await
|
|
113
|
+
const input = await parseAgentInputByCommander(agent, {
|
|
114
|
+
...options,
|
|
115
|
+
inputKey: chatLoopOptions?.inputKey,
|
|
116
|
+
});
|
|
117
|
+
if (isEmpty(input)) {
|
|
118
|
+
const defaultInput = chatLoopOptions?.initialCall || chatLoopOptions?.defaultQuestion;
|
|
119
|
+
Object.assign(input, typeof defaultInput === "string"
|
|
120
|
+
? { [chatLoopOptions?.inputKey || DEFAULT_CHAT_INPUT_KEY]: defaultInput }
|
|
121
|
+
: defaultInput);
|
|
122
|
+
}
|
|
123
|
+
await runAgentWithAIGNE(aigne, agent, {
|
|
124
|
+
...options,
|
|
125
|
+
outputKey,
|
|
126
|
+
chatLoopOptions,
|
|
127
|
+
modelOptions,
|
|
128
|
+
input,
|
|
129
|
+
});
|
|
48
130
|
}
|
|
49
131
|
finally {
|
|
50
132
|
await aigne.shutdown();
|
|
@@ -59,7 +141,24 @@ export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoop
|
|
|
59
141
|
function customZodError(label, fn) {
|
|
60
142
|
return ((...args) => tryOrThrow(() => fn(...args), (e) => new Error(`${label} ${e instanceof ZodError ? e.issues[0]?.message : e.message}`)));
|
|
61
143
|
}
|
|
62
|
-
export async function runAgentWithAIGNE(aigne, agent, { chatLoopOptions, modelOptions, ...options } = {}) {
|
|
144
|
+
export async function runAgentWithAIGNE(aigne, agent, { outputKey, chatLoopOptions, modelOptions, ...options } = {}) {
|
|
145
|
+
if (options.output) {
|
|
146
|
+
const outputPath = isAbsolute(options.output)
|
|
147
|
+
? options.output
|
|
148
|
+
: join(process.cwd(), options.output);
|
|
149
|
+
if (await exists(outputPath)) {
|
|
150
|
+
const s = await stat(outputPath);
|
|
151
|
+
if (!s.isFile())
|
|
152
|
+
throw new Error(`Output path ${outputPath} is not a file`);
|
|
153
|
+
if (s.size > 0 && !options.force) {
|
|
154
|
+
throw new Error(`Output file ${outputPath} already exists. Use --force to overwrite.`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
159
|
+
}
|
|
160
|
+
await writeFile(outputPath, "", "utf8");
|
|
161
|
+
}
|
|
63
162
|
if (options.chat) {
|
|
64
163
|
if (!isatty(process.stdout.fd)) {
|
|
65
164
|
throw new Error("--chat mode requires a TTY terminal");
|
|
@@ -70,19 +169,20 @@ export async function runAgentWithAIGNE(aigne, agent, { chatLoopOptions, modelOp
|
|
|
70
169
|
});
|
|
71
170
|
return;
|
|
72
171
|
}
|
|
73
|
-
const input = options.input ||
|
|
74
|
-
(isatty(process.stdin.fd) || !(await stdinHasData())
|
|
75
|
-
? null
|
|
76
|
-
: await readAllString(process.stdin)) ||
|
|
77
|
-
chatLoopOptions?.initialCall ||
|
|
78
|
-
chatLoopOptions?.defaultQuestion ||
|
|
79
|
-
{};
|
|
80
172
|
const tracer = new TerminalTracer(aigne.newContext(), {
|
|
81
173
|
printRequest: logger.enabled(LogLevel.INFO),
|
|
174
|
+
outputKey,
|
|
82
175
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
176
|
+
assert(options.input);
|
|
177
|
+
const { result } = await tracer.run(agent, options.input);
|
|
178
|
+
if (options.output) {
|
|
179
|
+
const message = result[outputKey || DEFAULT_OUTPUT_KEY];
|
|
180
|
+
const content = typeof message === "string" ? message : JSON.stringify(result, null, 2);
|
|
181
|
+
const path = isAbsolute(options.output) ? options.output : join(process.cwd(), options.output);
|
|
182
|
+
await mkdir(dirname(path), { recursive: true });
|
|
183
|
+
await writeFile(path, content, "utf8");
|
|
184
|
+
}
|
|
185
|
+
return { result };
|
|
86
186
|
}
|
|
87
187
|
async function stdinHasData() {
|
|
88
188
|
const stats = await promisify(fstat)(0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "cli for AIGNE framework",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -49,17 +49,18 @@
|
|
|
49
49
|
"pretty-error": "^4.0.0",
|
|
50
50
|
"tar": "^7.4.3",
|
|
51
51
|
"wrap-ansi": "^9.0.0",
|
|
52
|
+
"yaml": "^2.7.1",
|
|
52
53
|
"zod": "^3.24.4",
|
|
53
|
-
"@aigne/agent-library": "^1.
|
|
54
|
-
"@aigne/
|
|
55
|
-
"@aigne/
|
|
56
|
-
"@aigne/core": "^1.
|
|
57
|
-
"@aigne/
|
|
58
|
-
"@aigne/
|
|
59
|
-
"@aigne/ollama": "^0.3.
|
|
60
|
-
"@aigne/open-router": "^0.3.
|
|
61
|
-
"@aigne/openai": "^0.3.
|
|
62
|
-
"@aigne/xai": "^0.3.
|
|
54
|
+
"@aigne/agent-library": "^1.15.0",
|
|
55
|
+
"@aigne/anthropic": "^0.3.4",
|
|
56
|
+
"@aigne/bedrock": "^0.3.4",
|
|
57
|
+
"@aigne/core": "^1.22.0",
|
|
58
|
+
"@aigne/deepseek": "^0.3.4",
|
|
59
|
+
"@aigne/gemini": "^0.3.4",
|
|
60
|
+
"@aigne/ollama": "^0.3.4",
|
|
61
|
+
"@aigne/open-router": "^0.3.4",
|
|
62
|
+
"@aigne/openai": "^0.3.4",
|
|
63
|
+
"@aigne/xai": "^0.3.4"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
66
|
"@types/archiver": "^6.0.3",
|