@aigne/cli 1.11.7 → 1.12.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 +64 -0
- package/dist/commands/run.js +6 -4
- package/dist/tracer/terminal.d.ts +4 -2
- package/dist/tracer/terminal.js +31 -14
- package/dist/utils/run-chat-loop.d.ts +3 -2
- package/dist/utils/run-chat-loop.js +2 -4
- package/dist/utils/run-with-aigne.d.ts +16 -7
- package/dist/utils/run-with-aigne.js +116 -19
- package/dist/utils/serve-mcp.js +3 -2
- package/package.json +12 -11
- package/templates/default/chat.yaml +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,69 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.12.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.11.9...cli-v1.12.0) (2025-06-20)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **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))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @aigne/agent-library bumped to 1.14.0
|
|
16
|
+
* @aigne/anthropic bumped to 0.3.3
|
|
17
|
+
* @aigne/bedrock bumped to 0.3.3
|
|
18
|
+
* @aigne/core bumped to 1.21.0
|
|
19
|
+
* @aigne/deepseek bumped to 0.3.3
|
|
20
|
+
* @aigne/gemini bumped to 0.3.3
|
|
21
|
+
* @aigne/ollama bumped to 0.3.3
|
|
22
|
+
* @aigne/open-router bumped to 0.3.3
|
|
23
|
+
* @aigne/openai bumped to 0.3.3
|
|
24
|
+
* @aigne/xai bumped to 0.3.3
|
|
25
|
+
|
|
26
|
+
## [1.11.9](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.11.8...cli-v1.11.9) (2025-06-19)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Bug Fixes
|
|
30
|
+
|
|
31
|
+
* use `inputKey` instead of implicit $message for AIAgent ([#165](https://github.com/AIGNE-io/aigne-framework/issues/165)) ([8b6e589](https://github.com/AIGNE-io/aigne-framework/commit/8b6e5896bba8209fd2eecb0f5b9263618bffdaf8))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Dependencies
|
|
35
|
+
|
|
36
|
+
* The following workspace dependencies were updated
|
|
37
|
+
* dependencies
|
|
38
|
+
* @aigne/agent-library bumped to 1.13.2
|
|
39
|
+
* @aigne/anthropic bumped to 0.3.2
|
|
40
|
+
* @aigne/bedrock bumped to 0.3.2
|
|
41
|
+
* @aigne/core bumped to 1.20.1
|
|
42
|
+
* @aigne/deepseek bumped to 0.3.2
|
|
43
|
+
* @aigne/gemini bumped to 0.3.2
|
|
44
|
+
* @aigne/ollama bumped to 0.3.2
|
|
45
|
+
* @aigne/open-router bumped to 0.3.2
|
|
46
|
+
* @aigne/openai bumped to 0.3.2
|
|
47
|
+
* @aigne/xai bumped to 0.3.2
|
|
48
|
+
|
|
49
|
+
## [1.11.8](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.11.7...cli-v1.11.8) (2025-06-17)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
### Dependencies
|
|
53
|
+
|
|
54
|
+
* The following workspace dependencies were updated
|
|
55
|
+
* dependencies
|
|
56
|
+
* @aigne/agent-library bumped to 1.13.1
|
|
57
|
+
* @aigne/anthropic bumped to 0.3.1
|
|
58
|
+
* @aigne/bedrock bumped to 0.3.1
|
|
59
|
+
* @aigne/core bumped to 1.20.0
|
|
60
|
+
* @aigne/deepseek bumped to 0.3.1
|
|
61
|
+
* @aigne/gemini bumped to 0.3.1
|
|
62
|
+
* @aigne/ollama bumped to 0.3.1
|
|
63
|
+
* @aigne/open-router bumped to 0.3.1
|
|
64
|
+
* @aigne/openai bumped to 0.3.1
|
|
65
|
+
* @aigne/xai bumped to 0.3.1
|
|
66
|
+
|
|
3
67
|
## [1.11.7](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.11.6...cli-v1.11.7) (2025-06-16)
|
|
4
68
|
|
|
5
69
|
|
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,8 +25,9 @@ export declare class TerminalTracer {
|
|
|
24
25
|
time?: boolean;
|
|
25
26
|
}): string;
|
|
26
27
|
private marked;
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
get outputKey(): string;
|
|
29
|
+
formatRequest(agent: Agent, _context: Context, m?: Message): string | undefined;
|
|
30
|
+
formatResult(agent: Agent, context: Context, m?: Message): string;
|
|
29
31
|
}
|
|
30
32
|
type Task = ReturnType<typeof promiseWithResolvers<void>> & {
|
|
31
33
|
listr: ReturnType<typeof promiseWithResolvers<{
|
package/dist/tracer/terminal.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { EOL } from "node:os";
|
|
2
2
|
import { inspect } from "node:util";
|
|
3
|
-
import { ChatModel,
|
|
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
|
-
import {
|
|
6
|
+
import { omit } from "@aigne/core/utils/type-utils.js";
|
|
7
7
|
import { figures } from "@aigne/listr2";
|
|
8
8
|
import { markedTerminal } from "@aigne/marked-terminal";
|
|
9
9
|
import chalk from "chalk";
|
|
@@ -21,8 +21,8 @@ export class TerminalTracer {
|
|
|
21
21
|
async run(agent, input) {
|
|
22
22
|
const context = this.context.newContext({ reset: true });
|
|
23
23
|
const listr = new AIGNEListr({
|
|
24
|
-
formatRequest: () => this.options.printRequest ? this.formatRequest(context, input) : undefined,
|
|
25
|
-
formatResult: (result) => [this.formatResult(context, result)].filter(Boolean),
|
|
24
|
+
formatRequest: () => this.options.printRequest ? this.formatRequest(agent, context, input) : undefined,
|
|
25
|
+
formatResult: (result) => [this.formatResult(agent, context, result)].filter(Boolean),
|
|
26
26
|
}, [], { concurrent: true });
|
|
27
27
|
const onAgentStarted = async ({ contextId, parentContextId, agent, timestamp, }) => {
|
|
28
28
|
const task = {
|
|
@@ -121,27 +121,44 @@ export class TerminalTracer {
|
|
|
121
121
|
title += ` ${this.formatTimeUsage(task.startTime, task.endTime)}`;
|
|
122
122
|
return title;
|
|
123
123
|
}
|
|
124
|
-
marked = new Marked().use(
|
|
125
|
-
|
|
124
|
+
marked = new Marked().use({
|
|
125
|
+
// marked-terminal does not support code block meta, so we need to strip it
|
|
126
|
+
walkTokens: (token) => {
|
|
127
|
+
if (token.type === "code") {
|
|
128
|
+
if (typeof token.lang === "string") {
|
|
129
|
+
token.lang = token.lang.trim().split(/\s+/)[0];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
}, markedTerminal({ forceHyperLink: false }));
|
|
134
|
+
get outputKey() {
|
|
135
|
+
return this.options.outputKey || DEFAULT_OUTPUT_KEY;
|
|
136
|
+
}
|
|
137
|
+
formatRequest(agent, _context, m = {}) {
|
|
126
138
|
if (!logger.enabled(LogLevel.INFO))
|
|
127
139
|
return;
|
|
128
140
|
const prefix = `${chalk.grey(figures.pointer)} 💬 `;
|
|
129
|
-
const
|
|
130
|
-
const
|
|
141
|
+
const inputKey = agent instanceof AIAgent ? agent.inputKey : undefined;
|
|
142
|
+
const msg = inputKey ? m[inputKey] : undefined;
|
|
143
|
+
const message = inputKey ? omit(m, inputKey) : m;
|
|
131
144
|
const text = msg && typeof msg === "string" ? this.marked.parse(msg, { async: false }).trim() : undefined;
|
|
132
145
|
const json = Object.keys(message).length > 0 ? inspect(message, { colors: true }) : undefined;
|
|
133
146
|
return [prefix, [text, json].filter(Boolean).join(EOL)].join(" ");
|
|
134
147
|
}
|
|
135
|
-
formatResult(context, m = {}) {
|
|
148
|
+
formatResult(agent, context, m = {}) {
|
|
149
|
+
const { isTTY } = process.stdout;
|
|
150
|
+
const outputKey = agent instanceof AIAgent ? agent.outputKey : undefined;
|
|
136
151
|
const prefix = logger.enabled(LogLevel.INFO)
|
|
137
152
|
? `${chalk.grey(figures.tick)} 🤖 ${this.formatTokenUsage(context.usage)}`
|
|
138
153
|
: null;
|
|
139
|
-
const msg = m[
|
|
140
|
-
const message =
|
|
141
|
-
const text = msg && typeof msg === "string"
|
|
142
|
-
|
|
143
|
-
|
|
154
|
+
const msg = outputKey ? m[outputKey] : undefined;
|
|
155
|
+
const message = outputKey ? omit(m, outputKey) : m;
|
|
156
|
+
const text = msg && typeof msg === "string"
|
|
157
|
+
? isTTY
|
|
158
|
+
? this.marked.parse(msg, { async: false }).trim()
|
|
159
|
+
: msg
|
|
144
160
|
: undefined;
|
|
161
|
+
const json = Object.keys(message).length > 0 ? inspect(message, { colors: isTTY }) : undefined;
|
|
145
162
|
return [prefix, text, json].filter(Boolean).join(EOL);
|
|
146
163
|
}
|
|
147
164
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Message, UserAgent } from "@aigne/core";
|
|
2
|
+
export declare const DEFAULT_CHAT_INPUT_KEY = "message";
|
|
2
3
|
export interface ChatLoopOptions {
|
|
3
4
|
initialCall?: Message | string;
|
|
4
5
|
welcome?: string;
|
|
@@ -6,4 +7,4 @@ export interface ChatLoopOptions {
|
|
|
6
7
|
inputKey?: string;
|
|
7
8
|
skipLoop?: boolean;
|
|
8
9
|
}
|
|
9
|
-
export declare function runChatLoopInTerminal(userAgent: UserAgent, options?: ChatLoopOptions): Promise<void>;
|
|
10
|
+
export declare function runChatLoopInTerminal(userAgent: UserAgent<any, any>, options?: ChatLoopOptions): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createMessage } from "@aigne/core";
|
|
2
1
|
import inquirer from "inquirer";
|
|
3
2
|
import { TerminalTracer } from "../tracer/terminal.js";
|
|
3
|
+
export const DEFAULT_CHAT_INPUT_KEY = "message";
|
|
4
4
|
export async function runChatLoopInTerminal(userAgent, options = {}) {
|
|
5
5
|
const { initialCall = process.env.INITIAL_CALL, skipLoop = process.env.SKIP_LOOP === "true" } = options;
|
|
6
6
|
let prompt;
|
|
@@ -43,9 +43,7 @@ export async function runChatLoopInTerminal(userAgent, options = {}) {
|
|
|
43
43
|
}
|
|
44
44
|
async function callAgent(userAgent, input, options) {
|
|
45
45
|
const tracer = new TerminalTracer(userAgent.context);
|
|
46
|
-
await tracer.run(userAgent, options.inputKey
|
|
47
|
-
? { [options.inputKey]: input }
|
|
48
|
-
: createMessage(input));
|
|
46
|
+
await tracer.run(userAgent, typeof input === "string" ? { [options.inputKey || DEFAULT_CHAT_INPUT_KEY]: input } : input);
|
|
49
47
|
}
|
|
50
48
|
const COMMANDS = {
|
|
51
49
|
"/exit": () => ({ exit: true }),
|
|
@@ -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
|
-
import { runChatLoopInTerminal } from "./run-chat-loop.js";
|
|
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,20 @@ 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
|
+
Object.assign(input, chatLoopOptions?.initialCall || chatLoopOptions?.defaultQuestion);
|
|
119
|
+
}
|
|
120
|
+
await runAgentWithAIGNE(aigne, agent, {
|
|
121
|
+
...options,
|
|
122
|
+
outputKey,
|
|
123
|
+
chatLoopOptions,
|
|
124
|
+
modelOptions,
|
|
125
|
+
input,
|
|
126
|
+
});
|
|
48
127
|
}
|
|
49
128
|
finally {
|
|
50
129
|
await aigne.shutdown();
|
|
@@ -59,7 +138,24 @@ export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoop
|
|
|
59
138
|
function customZodError(label, fn) {
|
|
60
139
|
return ((...args) => tryOrThrow(() => fn(...args), (e) => new Error(`${label} ${e instanceof ZodError ? e.issues[0]?.message : e.message}`)));
|
|
61
140
|
}
|
|
62
|
-
export async function runAgentWithAIGNE(aigne, agent, { chatLoopOptions, modelOptions, ...options } = {}) {
|
|
141
|
+
export async function runAgentWithAIGNE(aigne, agent, { outputKey, chatLoopOptions, modelOptions, ...options } = {}) {
|
|
142
|
+
if (options.output) {
|
|
143
|
+
const outputPath = isAbsolute(options.output)
|
|
144
|
+
? options.output
|
|
145
|
+
: join(process.cwd(), options.output);
|
|
146
|
+
if (await exists(outputPath)) {
|
|
147
|
+
const s = await stat(outputPath);
|
|
148
|
+
if (!s.isFile())
|
|
149
|
+
throw new Error(`Output path ${outputPath} is not a file`);
|
|
150
|
+
if (s.size > 0 && !options.force) {
|
|
151
|
+
throw new Error(`Output file ${outputPath} already exists. Use --force to overwrite.`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
156
|
+
}
|
|
157
|
+
await writeFile(outputPath, "", "utf8");
|
|
158
|
+
}
|
|
63
159
|
if (options.chat) {
|
|
64
160
|
if (!isatty(process.stdout.fd)) {
|
|
65
161
|
throw new Error("--chat mode requires a TTY terminal");
|
|
@@ -70,19 +166,20 @@ export async function runAgentWithAIGNE(aigne, agent, { chatLoopOptions, modelOp
|
|
|
70
166
|
});
|
|
71
167
|
return;
|
|
72
168
|
}
|
|
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
169
|
const tracer = new TerminalTracer(aigne.newContext(), {
|
|
81
170
|
printRequest: logger.enabled(LogLevel.INFO),
|
|
171
|
+
outputKey,
|
|
82
172
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
173
|
+
assert(options.input);
|
|
174
|
+
const { result } = await tracer.run(agent, options.input);
|
|
175
|
+
if (options.output) {
|
|
176
|
+
const message = result[outputKey || DEFAULT_OUTPUT_KEY];
|
|
177
|
+
const content = typeof message === "string" ? message : JSON.stringify(result, null, 2);
|
|
178
|
+
const path = isAbsolute(options.output) ? options.output : join(process.cwd(), options.output);
|
|
179
|
+
await mkdir(dirname(path), { recursive: true });
|
|
180
|
+
await writeFile(path, content, "utf8");
|
|
181
|
+
}
|
|
182
|
+
return { result };
|
|
86
183
|
}
|
|
87
184
|
async function stdinHasData() {
|
|
88
185
|
const stats = await promisify(fstat)(0);
|
package/dist/utils/serve-mcp.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AIAgent } from "@aigne/core";
|
|
2
2
|
import { promiseWithResolvers } from "@aigne/core/utils/promise.js";
|
|
3
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
4
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
@@ -82,7 +82,8 @@ export function createMcpServer(aigne) {
|
|
|
82
82
|
content: [
|
|
83
83
|
{
|
|
84
84
|
type: "text",
|
|
85
|
-
text:
|
|
85
|
+
text: (agent instanceof AIAgent && result[agent.outputKey]) ||
|
|
86
|
+
JSON.stringify(result),
|
|
86
87
|
},
|
|
87
88
|
],
|
|
88
89
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.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/deepseek": "^0.3.
|
|
57
|
-
"@aigne/
|
|
58
|
-
"@aigne/
|
|
59
|
-
"@aigne/
|
|
60
|
-
"@aigne/
|
|
61
|
-
"@aigne/
|
|
62
|
-
"@aigne/
|
|
54
|
+
"@aigne/agent-library": "^1.14.0",
|
|
55
|
+
"@aigne/anthropic": "^0.3.3",
|
|
56
|
+
"@aigne/bedrock": "^0.3.3",
|
|
57
|
+
"@aigne/deepseek": "^0.3.3",
|
|
58
|
+
"@aigne/core": "^1.21.0",
|
|
59
|
+
"@aigne/ollama": "^0.3.3",
|
|
60
|
+
"@aigne/gemini": "^0.3.3",
|
|
61
|
+
"@aigne/open-router": "^0.3.3",
|
|
62
|
+
"@aigne/xai": "^0.3.3",
|
|
63
|
+
"@aigne/openai": "^0.3.3"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
66
|
"@types/archiver": "^6.0.3",
|
|
@@ -3,6 +3,7 @@ description: Chat agent
|
|
|
3
3
|
instructions: |
|
|
4
4
|
You are a helpful assistant that can answer questions and provide information on a wide range of topics.
|
|
5
5
|
Your goal is to assist users in finding the information they need and to engage in friendly conversation.
|
|
6
|
+
input_key: message
|
|
6
7
|
memory: true
|
|
7
8
|
tools:
|
|
8
9
|
- sandbox.js
|