@aigne/cli 1.2.0 → 1.3.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 +9 -0
- package/dist/commands/run.js +109 -35
- package/dist/utils/agent-v1.d.ts +134 -0
- package/dist/utils/agent-v1.js +209 -0
- package/dist/utils/run-chat-loop.d.ts +1 -0
- package/dist/utils/run-chat-loop.js +5 -3
- package/package.json +7 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.3.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.2.0...cli-v1.3.0) (2025-04-17)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **ci:** support coverage examples with model matrix ([#59](https://github.com/AIGNE-io/aigne-framework/issues/59)) ([1edd704](https://github.com/AIGNE-io/aigne-framework/commit/1edd70426b80a69e3751b2d5fe818297711d0777))
|
|
9
|
+
* **cli:** support convert agents from studio ([#64](https://github.com/AIGNE-io/aigne-framework/issues/64)) ([f544bc7](https://github.com/AIGNE-io/aigne-framework/commit/f544bc77a2fb07e034b317ceb6a46aadd35830c9))
|
|
10
|
+
* **cli:** support model and download customization for aigne run ([#61](https://github.com/AIGNE-io/aigne-framework/issues/61)) ([51f6619](https://github.com/AIGNE-io/aigne-framework/commit/51f6619e6c591a84f1f2339b26ef66d89fa9486e))
|
|
11
|
+
|
|
3
12
|
## [1.2.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.1.0...cli-v1.2.0) (2025-04-15)
|
|
4
13
|
|
|
5
14
|
|
package/dist/commands/run.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { mkdir, rm } from "node:fs/promises";
|
|
3
|
-
import {
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { cp, mkdir, rm } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
4
|
import { isAbsolute, join, resolve } from "node:path";
|
|
5
5
|
import { ExecutionEngine } from "@aigne/core";
|
|
6
|
+
import { loadModel } from "@aigne/core/loader/index.js";
|
|
7
|
+
import { isNonNullable } from "@aigne/core/utils/type-utils.js";
|
|
8
|
+
import { Listr, PRESET_TIMER } from "@aigne/listr2";
|
|
6
9
|
import { Command } from "commander";
|
|
10
|
+
import { isV1Package, toAIGNEPackage } from "../utils/agent-v1.js";
|
|
7
11
|
import { downloadAndExtract } from "../utils/download.js";
|
|
8
12
|
import { runChatLoopInTerminal } from "../utils/run-chat-loop.js";
|
|
9
13
|
export function createRunCommand() {
|
|
@@ -11,47 +15,117 @@ export function createRunCommand() {
|
|
|
11
15
|
.description("Run a chat loop with the specified agent")
|
|
12
16
|
.argument("[path]", "Path to the agents directory or URL to aigne project", ".")
|
|
13
17
|
.option("--agent <agent>", "Name of the agent to use (defaults to the first agent found)")
|
|
18
|
+
.option("--download-dir <dir>", "Directory to download the package to (defaults to the ~/.aigne/xxx)")
|
|
19
|
+
.option("--model-provider <provider>", "Model provider to use, available providers: openai, claude, xai (defaults to the aigne.yaml definition or openai)")
|
|
20
|
+
.option("--model-name <model>", "Model name to use, available models depend on the provider (defaults to the aigne.yaml definition or gpt-4o-mini)")
|
|
14
21
|
.action(async (path, options) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
const { downloadDir, dir } = prepareDirs(path, options);
|
|
23
|
+
const { engine, agent } = await new Listr([
|
|
24
|
+
{
|
|
25
|
+
title: "Prepare environment",
|
|
26
|
+
task: (_, task) => {
|
|
27
|
+
if (downloadDir) {
|
|
28
|
+
return task.newListr([
|
|
29
|
+
{
|
|
30
|
+
title: "Download package",
|
|
31
|
+
task: () => downloadPackage(path, downloadDir),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
title: "Extract package",
|
|
35
|
+
task: () => extractPackage(downloadDir, dir),
|
|
36
|
+
},
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
title: "Initialize execution engine",
|
|
43
|
+
task: async (ctx) => {
|
|
44
|
+
const engine = await runEngine(dir, options);
|
|
45
|
+
ctx.engine = engine;
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
task: (ctx) => {
|
|
50
|
+
const { engine } = ctx;
|
|
51
|
+
assert(engine);
|
|
52
|
+
let agent;
|
|
53
|
+
if (options.agent) {
|
|
54
|
+
agent = engine.agents[options.agent];
|
|
55
|
+
if (!agent) {
|
|
56
|
+
console.error(`Agent "${options.agent}" not found in ${path}`);
|
|
57
|
+
console.log("Available agents:");
|
|
58
|
+
for (const agent of engine.agents) {
|
|
59
|
+
console.log(`- ${agent.name}`);
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`Agent "${options.agent}" not found in ${path}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
agent = engine.agents[0];
|
|
66
|
+
if (!agent)
|
|
67
|
+
throw new Error(`No agents found in ${path}`);
|
|
68
|
+
}
|
|
69
|
+
ctx.agent = agent;
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
], {
|
|
73
|
+
rendererOptions: {
|
|
74
|
+
collapseSubtasks: false,
|
|
75
|
+
timer: PRESET_TIMER,
|
|
76
|
+
},
|
|
77
|
+
}).run();
|
|
78
|
+
assert(engine);
|
|
79
|
+
assert(agent);
|
|
80
|
+
const user = engine.call(agent);
|
|
81
|
+
await runChatLoopInTerminal(user, {});
|
|
82
|
+
await engine.shutdown();
|
|
21
83
|
})
|
|
22
84
|
.showHelpAfterError(true)
|
|
23
85
|
.showSuggestionAfterError(true);
|
|
24
86
|
}
|
|
25
|
-
async function runEngine(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
87
|
+
async function runEngine(path, options) {
|
|
88
|
+
if (options.modelName && !options.modelProvider) {
|
|
89
|
+
throw new Error("please specify --model-provider when using the --model-name option");
|
|
90
|
+
}
|
|
91
|
+
const model = options.modelProvider
|
|
92
|
+
? await loadModel({ provider: options.modelProvider, name: options.modelName })
|
|
93
|
+
: undefined;
|
|
94
|
+
return await ExecutionEngine.load({ path, model });
|
|
95
|
+
}
|
|
96
|
+
async function downloadPackage(url, downloadDir) {
|
|
97
|
+
await rm(downloadDir, { recursive: true, force: true });
|
|
98
|
+
await mkdir(downloadDir, { recursive: true });
|
|
99
|
+
await downloadAndExtract(url, downloadDir);
|
|
100
|
+
}
|
|
101
|
+
async function extractPackage(downloadDir, dir) {
|
|
102
|
+
if (await isV1Package(downloadDir)) {
|
|
103
|
+
await toAIGNEPackage(downloadDir, dir);
|
|
38
104
|
}
|
|
39
105
|
else {
|
|
40
|
-
|
|
41
|
-
if (!agent)
|
|
42
|
-
throw new Error(`No agents found in ${originalPath}`);
|
|
106
|
+
await cp(downloadDir, dir, { recursive: true, force: true });
|
|
43
107
|
}
|
|
44
|
-
const user = engine.call(agent);
|
|
45
|
-
await runChatLoopInTerminal(user, {});
|
|
46
108
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
await runEngine(url, dir, options);
|
|
109
|
+
function prepareDirs(path, options) {
|
|
110
|
+
let dir;
|
|
111
|
+
let downloadDir;
|
|
112
|
+
if (!path.startsWith("http")) {
|
|
113
|
+
dir = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
53
114
|
}
|
|
54
|
-
|
|
55
|
-
|
|
115
|
+
else if (options.downloadDir) {
|
|
116
|
+
dir = isAbsolute(options.downloadDir)
|
|
117
|
+
? options.downloadDir
|
|
118
|
+
: resolve(process.cwd(), options.downloadDir);
|
|
119
|
+
downloadDir = join(dir, ".download");
|
|
56
120
|
}
|
|
121
|
+
else {
|
|
122
|
+
dir = getLocalPackagePathFromUrl(path);
|
|
123
|
+
downloadDir = getLocalPackagePathFromUrl(path, { subdir: ".download" });
|
|
124
|
+
}
|
|
125
|
+
return { downloadDir, dir };
|
|
126
|
+
}
|
|
127
|
+
function getLocalPackagePathFromUrl(url, { subdir } = {}) {
|
|
128
|
+
const root = [homedir(), ".aigne", subdir].filter(isNonNullable);
|
|
129
|
+
const u = new URL(url);
|
|
130
|
+
return join(...root, u.hostname, u.pathname);
|
|
57
131
|
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
export declare function isV1Package(src: string): Promise<boolean>;
|
|
2
|
+
export declare function toAIGNEPackage(src: string, dst: string): Promise<void>;
|
|
3
|
+
export type Parameter = {
|
|
4
|
+
id: string;
|
|
5
|
+
key?: string;
|
|
6
|
+
hidden?: boolean;
|
|
7
|
+
required?: boolean;
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
} & ({
|
|
10
|
+
type?: "string" | "number" | "boolean" | "language";
|
|
11
|
+
} | {
|
|
12
|
+
type?: "select";
|
|
13
|
+
options?: {
|
|
14
|
+
id: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
value?: string;
|
|
17
|
+
}[];
|
|
18
|
+
});
|
|
19
|
+
export interface VariableTypeBase {
|
|
20
|
+
id: string;
|
|
21
|
+
name?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
required?: boolean;
|
|
24
|
+
hidden?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export type OutputVariable = VariableTypeBase & ({
|
|
27
|
+
type?: undefined;
|
|
28
|
+
} | {
|
|
29
|
+
type: "string";
|
|
30
|
+
defaultValue?: string;
|
|
31
|
+
} | {
|
|
32
|
+
type: "number";
|
|
33
|
+
defaultValue?: number;
|
|
34
|
+
} | {
|
|
35
|
+
type: "boolean";
|
|
36
|
+
defaultValue?: boolean;
|
|
37
|
+
} | {
|
|
38
|
+
type: "object";
|
|
39
|
+
properties?: OutputVariable[];
|
|
40
|
+
} | {
|
|
41
|
+
type: "array";
|
|
42
|
+
element?: OutputVariable;
|
|
43
|
+
});
|
|
44
|
+
export type AgentV1 = {
|
|
45
|
+
id: string;
|
|
46
|
+
name?: string;
|
|
47
|
+
description?: string;
|
|
48
|
+
parameters?: Parameter[];
|
|
49
|
+
outputVariables?: OutputVariable[];
|
|
50
|
+
} & ({
|
|
51
|
+
type: "prompt";
|
|
52
|
+
prompts?: Prompt[];
|
|
53
|
+
temperature?: number;
|
|
54
|
+
topP?: number;
|
|
55
|
+
presencePenalty?: number;
|
|
56
|
+
frequencyPenalty?: number;
|
|
57
|
+
maxTokens?: number;
|
|
58
|
+
model?: string;
|
|
59
|
+
} | {
|
|
60
|
+
type: "router";
|
|
61
|
+
defaultToolId?: string;
|
|
62
|
+
prompt?: string;
|
|
63
|
+
decisionType?: "ai";
|
|
64
|
+
routes?: Tool[];
|
|
65
|
+
temperature?: number;
|
|
66
|
+
topP?: number;
|
|
67
|
+
presencePenalty?: number;
|
|
68
|
+
frequencyPenalty?: number;
|
|
69
|
+
maxTokens?: number;
|
|
70
|
+
model?: string;
|
|
71
|
+
} | {
|
|
72
|
+
type: "image";
|
|
73
|
+
prompt?: string;
|
|
74
|
+
model?: string;
|
|
75
|
+
n?: number;
|
|
76
|
+
quality?: string;
|
|
77
|
+
style?: string;
|
|
78
|
+
size?: string;
|
|
79
|
+
modelSettings?: {
|
|
80
|
+
[key: string]: unknown;
|
|
81
|
+
};
|
|
82
|
+
} | {
|
|
83
|
+
type: "api";
|
|
84
|
+
requestParameters?: {
|
|
85
|
+
id: string;
|
|
86
|
+
key?: string;
|
|
87
|
+
value?: string;
|
|
88
|
+
}[];
|
|
89
|
+
requestMethod?: string;
|
|
90
|
+
requestUrl?: string;
|
|
91
|
+
requestHeaders: {
|
|
92
|
+
id: string;
|
|
93
|
+
key?: string;
|
|
94
|
+
value?: string;
|
|
95
|
+
}[];
|
|
96
|
+
} | {
|
|
97
|
+
type: "function";
|
|
98
|
+
code?: string;
|
|
99
|
+
} | {
|
|
100
|
+
type: "callAgent";
|
|
101
|
+
agents?: Tool[];
|
|
102
|
+
});
|
|
103
|
+
export interface ProjectDefinitionV1 {
|
|
104
|
+
project: {
|
|
105
|
+
name?: string;
|
|
106
|
+
description?: string;
|
|
107
|
+
};
|
|
108
|
+
agents: AgentV1[];
|
|
109
|
+
}
|
|
110
|
+
export type Prompt = {
|
|
111
|
+
type: "message";
|
|
112
|
+
data: PromptMessage;
|
|
113
|
+
visibility?: "hidden";
|
|
114
|
+
} | {
|
|
115
|
+
type: "executeBlock";
|
|
116
|
+
visibility?: "hidden";
|
|
117
|
+
};
|
|
118
|
+
export type PromptMessage = {
|
|
119
|
+
id: string;
|
|
120
|
+
role: Role;
|
|
121
|
+
content?: string;
|
|
122
|
+
name?: string;
|
|
123
|
+
};
|
|
124
|
+
export type Role = "system" | "user" | "assistant";
|
|
125
|
+
export type Tool = {
|
|
126
|
+
blockletDid?: string;
|
|
127
|
+
projectId?: string;
|
|
128
|
+
id: string;
|
|
129
|
+
from?: "assistant" | "blockletAPI" | "knowledge";
|
|
130
|
+
parameters?: {
|
|
131
|
+
[key: string]: unknown;
|
|
132
|
+
};
|
|
133
|
+
functionName?: string;
|
|
134
|
+
};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { readFile, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { glob } from "glob";
|
|
4
|
+
import { parse, stringify } from "yaml";
|
|
5
|
+
export async function isV1Package(src) {
|
|
6
|
+
return stat(join(src, "project.yaml"))
|
|
7
|
+
.then((res) => res.isFile())
|
|
8
|
+
.catch((error) => {
|
|
9
|
+
if (error.code === "ENOENT")
|
|
10
|
+
return false;
|
|
11
|
+
throw error;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export async function toAIGNEPackage(src, dst) {
|
|
15
|
+
const definition = await loadAgentV1Package(src);
|
|
16
|
+
const aigne = {
|
|
17
|
+
chat_model: {
|
|
18
|
+
name: "gpt-4o-mini", // TODO: get from config
|
|
19
|
+
},
|
|
20
|
+
agents: [],
|
|
21
|
+
};
|
|
22
|
+
for (const agent of definition.agents) {
|
|
23
|
+
const { content } = await assistantToAigneV2(agent, definition);
|
|
24
|
+
const filename = getAgentFilename(agent);
|
|
25
|
+
await writeFile(join(dst, filename), content);
|
|
26
|
+
aigne.agents.push(filename);
|
|
27
|
+
}
|
|
28
|
+
await writeFile(join(dst, "aigne.yaml"), stringify(aigne));
|
|
29
|
+
}
|
|
30
|
+
async function loadAgentV1Package(path) {
|
|
31
|
+
const agentFilePaths = await glob("prompts/**/*.yaml", {
|
|
32
|
+
cwd: path,
|
|
33
|
+
});
|
|
34
|
+
const project = parse(await readFile(join(path, "project.yaml"), "utf8"));
|
|
35
|
+
const definition = {
|
|
36
|
+
project,
|
|
37
|
+
agents: [],
|
|
38
|
+
};
|
|
39
|
+
for (const filename of agentFilePaths) {
|
|
40
|
+
const agent = parse(await readFile(join(path, filename), "utf8"));
|
|
41
|
+
definition.agents.push(agent);
|
|
42
|
+
}
|
|
43
|
+
return definition;
|
|
44
|
+
}
|
|
45
|
+
function assistantToAigneV2(agent, project) {
|
|
46
|
+
const converter = RUNNABLE_MAP[agent.type];
|
|
47
|
+
if (!converter)
|
|
48
|
+
throw new Error(`Unsupported runnable type: ${agent.type}`);
|
|
49
|
+
return converter(agent, project);
|
|
50
|
+
}
|
|
51
|
+
const RUNNABLE_MAP = {
|
|
52
|
+
prompt: (agent) => {
|
|
53
|
+
if (agent.type !== "prompt")
|
|
54
|
+
throw new Error(`Expected runnable type 'prompt', but got '${agent.type}'`);
|
|
55
|
+
const obj = {
|
|
56
|
+
name: agent.name || agent.id,
|
|
57
|
+
description: agent.description,
|
|
58
|
+
input_schema: convertInputSchema(agent),
|
|
59
|
+
output_schema: convertOutputSchema(agent),
|
|
60
|
+
instructions: agent.prompts
|
|
61
|
+
?.filter((i) => i.visibility !== "hidden" && i.type === "message")
|
|
62
|
+
.map((i) => i.data.content) // TODO: should support multiple messages with different roles
|
|
63
|
+
.join("\n"),
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
content: stringify(obj),
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
function: async (agent) => {
|
|
70
|
+
if (agent.type !== "function")
|
|
71
|
+
throw new Error(`Expected runnable type 'function', but got '${agent.type}'`);
|
|
72
|
+
const inputNames = agent.parameters?.map((i) => i.key).filter(Boolean) ?? [];
|
|
73
|
+
return {
|
|
74
|
+
content: await formatCode(`\
|
|
75
|
+
export default async function agent({${inputNames.join(", ")}}) {
|
|
76
|
+
${agent.code}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
agent.agent_name = ${JSON.stringify(agent.name || agent.id)};
|
|
80
|
+
|
|
81
|
+
agent.description = ${agent.description ? JSON.stringify(agent.description) : "undefined"};
|
|
82
|
+
|
|
83
|
+
agent.input_schema = ${JSON.stringify(convertInputSchema(agent))};
|
|
84
|
+
|
|
85
|
+
agent.output_schema = ${JSON.stringify(convertOutputSchema(agent))};
|
|
86
|
+
`),
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
router: (agent, project) => {
|
|
90
|
+
if (agent.type !== "router")
|
|
91
|
+
throw new Error(`Expected runnable type 'router', but got '${agent.type}'`);
|
|
92
|
+
return {
|
|
93
|
+
content: stringify({
|
|
94
|
+
name: agent.name || agent.id,
|
|
95
|
+
description: agent.description,
|
|
96
|
+
instructions: agent.prompt,
|
|
97
|
+
input_schema: convertInputSchema(agent),
|
|
98
|
+
output_schema: convertOutputSchema(agent),
|
|
99
|
+
tools: agent.routes?.map((i) => {
|
|
100
|
+
const tool = project.agents.find((j) => j.id === i.id);
|
|
101
|
+
if (!tool)
|
|
102
|
+
throw new Error(`Tool ${i.id} not found in project definition`);
|
|
103
|
+
return getAgentFilename(tool);
|
|
104
|
+
}),
|
|
105
|
+
tool_choice: "router",
|
|
106
|
+
}),
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
function getAgentFilename(agent) {
|
|
111
|
+
switch (agent.type) {
|
|
112
|
+
case "prompt":
|
|
113
|
+
case "router":
|
|
114
|
+
return `${agent.name || agent.id}.yaml`;
|
|
115
|
+
case "function":
|
|
116
|
+
return `${agent.name || agent.id}.js`;
|
|
117
|
+
default:
|
|
118
|
+
throw new Error(`Unsupported agent type: ${agent.type}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async function formatCode(code) {
|
|
122
|
+
const [prettier, typescriptPlugin, estreePlugin] = await Promise.all([
|
|
123
|
+
import("prettier"),
|
|
124
|
+
import("prettier/plugins/typescript"),
|
|
125
|
+
import("prettier/plugins/estree"),
|
|
126
|
+
]);
|
|
127
|
+
return prettier.format(code, {
|
|
128
|
+
parser: "typescript",
|
|
129
|
+
plugins: [typescriptPlugin, estreePlugin.default],
|
|
130
|
+
printWidth: 120,
|
|
131
|
+
useTabs: false,
|
|
132
|
+
tabWidth: 2,
|
|
133
|
+
trailingComma: "es5",
|
|
134
|
+
bracketSameLine: true,
|
|
135
|
+
semi: true,
|
|
136
|
+
singleQuote: true,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function convertInputSchema(agent) {
|
|
140
|
+
const parameters = (agent.parameters ?? []).filter((i) => !!i.key && !i.hidden);
|
|
141
|
+
const properties = parameters.map((i) => [i.key, parameterToJsonSchema(i)]);
|
|
142
|
+
return {
|
|
143
|
+
type: "object",
|
|
144
|
+
properties: Object.fromEntries(properties),
|
|
145
|
+
required: parameters.filter((i) => i.required).map((i) => i.key),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function parameterToJsonSchema(parameter) {
|
|
149
|
+
switch (parameter.type) {
|
|
150
|
+
case undefined:
|
|
151
|
+
case "string":
|
|
152
|
+
case "language":
|
|
153
|
+
return {
|
|
154
|
+
type: "string",
|
|
155
|
+
description: parameter.placeholder,
|
|
156
|
+
};
|
|
157
|
+
case "select":
|
|
158
|
+
return {
|
|
159
|
+
type: "string",
|
|
160
|
+
enum: parameter.options?.map((i) => i.value),
|
|
161
|
+
description: parameter.placeholder,
|
|
162
|
+
};
|
|
163
|
+
case "number":
|
|
164
|
+
case "boolean":
|
|
165
|
+
return {
|
|
166
|
+
type: parameter.type,
|
|
167
|
+
description: parameter.placeholder,
|
|
168
|
+
};
|
|
169
|
+
default:
|
|
170
|
+
throw new Error(`Unsupported parameter type: ${parameter.type}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function convertOutputSchema(agent) {
|
|
174
|
+
const outputs = agent.outputVariables?.filter((i) => !!i.name && !i.hidden) ?? [];
|
|
175
|
+
const properties = outputs
|
|
176
|
+
.map((i) => [i.name, variableTypeToJsonSchema(i)])
|
|
177
|
+
.filter((i) => !!i[1]);
|
|
178
|
+
return {
|
|
179
|
+
type: "object",
|
|
180
|
+
properties: Object.fromEntries(properties),
|
|
181
|
+
required: outputs.filter((i) => i.required).map((i) => i.name),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function variableTypeToJsonSchema(output) {
|
|
185
|
+
if (output.type === "object") {
|
|
186
|
+
if (!output.properties)
|
|
187
|
+
return undefined;
|
|
188
|
+
return {
|
|
189
|
+
type: "object",
|
|
190
|
+
properties: Object.fromEntries(output.properties
|
|
191
|
+
.filter((i) => !!i.name)
|
|
192
|
+
.map((i) => [i.name, variableTypeToJsonSchema(i)])
|
|
193
|
+
.filter((i) => !!i[1])),
|
|
194
|
+
required: output.properties.filter((i) => i.required && i.name).map((i) => i.name),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
if (output.type === "array") {
|
|
198
|
+
if (!output.element)
|
|
199
|
+
return undefined;
|
|
200
|
+
return {
|
|
201
|
+
type: "array",
|
|
202
|
+
items: variableTypeToJsonSchema(output.element),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
type: output.type || "string",
|
|
207
|
+
description: output.description,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
@@ -6,14 +6,17 @@ import chalk from "chalk";
|
|
|
6
6
|
import inquirer from "inquirer";
|
|
7
7
|
import { TerminalTracer } from "../tracer/terminal.js";
|
|
8
8
|
export async function runChatLoopInTerminal(userAgent, options = {}) {
|
|
9
|
+
const { initialCall = process.env.INITIAL_CALL, skipLoop = process.env.SKIP_LOOP === "true" } = options;
|
|
9
10
|
options.verbose ??= logger.enabled("aigne:core");
|
|
10
11
|
// Disable the logger, use TerminalTracer instead
|
|
11
12
|
logger.disable();
|
|
12
13
|
let prompt;
|
|
13
14
|
if (options?.welcome)
|
|
14
15
|
console.log(options.welcome);
|
|
15
|
-
if (
|
|
16
|
-
await callAgent(userAgent,
|
|
16
|
+
if (initialCall) {
|
|
17
|
+
await callAgent(userAgent, initialCall, { ...options });
|
|
18
|
+
if (skipLoop)
|
|
19
|
+
return;
|
|
17
20
|
}
|
|
18
21
|
for (let i = 0;; i++) {
|
|
19
22
|
prompt = inquirer.prompt([
|
|
@@ -51,7 +54,6 @@ async function callAgent(userAgent, input, options) {
|
|
|
51
54
|
? { [options.inputKey]: input }
|
|
52
55
|
: createMessage(input));
|
|
53
56
|
console.log(`
|
|
54
|
-
${chalk.grey(figures.tick)} 💬 ${inspect(input, { colors: true })}
|
|
55
57
|
${chalk.grey(figures.tick)} 🤖 ${tracer.formatTokenUsage(context.usage)}
|
|
56
58
|
${formatAIResponse(result)}
|
|
57
59
|
`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1-0",
|
|
4
4
|
"description": "cli for AIGNE framework",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -39,20 +39,23 @@
|
|
|
39
39
|
"chalk": "^5.4.1",
|
|
40
40
|
"commander": "^13.1.0",
|
|
41
41
|
"express": "^5.1.0",
|
|
42
|
+
"glob": "^11.0.1",
|
|
42
43
|
"gradient-string": "^3.0.0",
|
|
43
44
|
"inquirer": "^12.5.2",
|
|
44
|
-
"openai": "^4.
|
|
45
|
+
"openai": "^4.94.0",
|
|
46
|
+
"prettier": "^3.5.3",
|
|
45
47
|
"pretty-error": "^4.0.0",
|
|
46
48
|
"tar": "^7.4.3",
|
|
47
49
|
"zod": "^3.24.2",
|
|
48
|
-
"@aigne/core": "^1.
|
|
50
|
+
"@aigne/core": "^1.8.0"
|
|
49
51
|
},
|
|
50
52
|
"devDependencies": {
|
|
51
53
|
"@types/archiver": "^6.0.3",
|
|
52
54
|
"@types/bun": "^1.2.9",
|
|
53
55
|
"@types/express": "^5.0.1",
|
|
56
|
+
"@types/glob": "^8.1.0",
|
|
54
57
|
"@types/gradient-string": "^1.1.6",
|
|
55
|
-
"@types/node": "^22.14.
|
|
58
|
+
"@types/node": "^22.14.1",
|
|
56
59
|
"archiver": "^7.0.1",
|
|
57
60
|
"detect-port": "^2.1.0",
|
|
58
61
|
"npm-run-all": "^4.1.5",
|