@aigne/cli 1.74.0-beta.1 → 1.74.0-beta.2
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/README.md +153 -14
- package/dist/commands/aigne.cjs +3 -4
- package/dist/commands/aigne.mjs +3 -4
- package/dist/commands/aigne.mjs.map +1 -1
- package/dist/commands/app/agent.cjs +2 -27
- package/dist/commands/app/agent.mjs +2 -26
- package/dist/commands/app/agent.mjs.map +1 -1
- package/dist/commands/create.cjs +1 -1
- package/dist/commands/create.mjs +1 -1
- package/dist/commands/eval.cjs +42 -3
- package/dist/commands/eval.mjs +43 -4
- package/dist/commands/eval.mjs.map +1 -1
- package/dist/commands/explain.cjs +340 -0
- package/dist/commands/explain.mjs +340 -0
- package/dist/commands/explain.mjs.map +1 -0
- package/dist/commands/hub.cjs +111 -14
- package/dist/commands/hub.mjs +111 -14
- package/dist/commands/hub.mjs.map +1 -1
- package/dist/commands/observe.cjs +44 -1
- package/dist/commands/observe.mjs +44 -1
- package/dist/commands/observe.mjs.map +1 -1
- package/dist/commands/run-skill.cjs +29 -13
- package/dist/commands/run-skill.mjs +29 -13
- package/dist/commands/run-skill.mjs.map +1 -1
- package/dist/commands/run.cjs +5 -4
- package/dist/commands/run.mjs +5 -4
- package/dist/commands/run.mjs.map +1 -1
- package/dist/commands/serve-mcp.cjs +49 -4
- package/dist/commands/serve-mcp.mjs +49 -3
- package/dist/commands/serve-mcp.mjs.map +1 -1
- package/dist/commands/shell.cjs +106 -0
- package/dist/commands/shell.mjs +105 -0
- package/dist/commands/shell.mjs.map +1 -0
- package/dist/shell/repl.cjs +544 -0
- package/dist/shell/repl.mjs +543 -0
- package/dist/shell/repl.mjs.map +1 -0
- package/dist/shell/tools/ask-user.cjs +191 -0
- package/dist/shell/tools/ask-user.mjs +187 -0
- package/dist/shell/tools/ask-user.mjs.map +1 -0
- package/dist/shell/tools/index.cjs +2 -0
- package/dist/shell/tools/index.mjs +4 -0
- package/dist/shell/tools/render.cjs +189 -0
- package/dist/shell/tools/render.mjs +186 -0
- package/dist/shell/tools/render.mjs.map +1 -0
- package/dist/tracer/terminal.cjs +120 -133
- package/dist/tracer/terminal.mjs +121 -134
- package/dist/tracer/terminal.mjs.map +1 -1
- package/dist/ui/utils/terminal-select.cjs +73 -0
- package/dist/ui/utils/terminal-select.mjs +72 -0
- package/dist/ui/utils/terminal-select.mjs.map +1 -0
- package/dist/utils/agent-v1.cjs +2 -2
- package/dist/utils/agent-v1.mjs +2 -2
- package/dist/utils/aigne-hub/credential.cjs +3 -3
- package/dist/utils/aigne-hub/credential.mjs +3 -3
- package/dist/utils/aigne-hub/model.cjs +2 -2
- package/dist/utils/aigne-hub/model.mjs +1 -1
- package/dist/utils/ascii-logo.cjs +12 -13
- package/dist/utils/ascii-logo.d.cts.map +1 -1
- package/dist/utils/ascii-logo.d.mts.map +1 -1
- package/dist/utils/ascii-logo.mjs +12 -13
- package/dist/utils/ascii-logo.mjs.map +1 -1
- package/dist/utils/evaluation/evaluator.cjs +1 -1
- package/dist/utils/evaluation/evaluator.mjs +1 -1
- package/dist/utils/evaluation/reporter.cjs +78 -1
- package/dist/utils/evaluation/reporter.mjs +76 -1
- package/dist/utils/evaluation/reporter.mjs.map +1 -1
- package/dist/utils/exit-codes.cjs +73 -0
- package/dist/utils/exit-codes.d.cts +52 -0
- package/dist/utils/exit-codes.d.cts.map +1 -0
- package/dist/utils/exit-codes.d.mts +52 -0
- package/dist/utils/exit-codes.d.mts.map +1 -0
- package/dist/utils/exit-codes.mjs +71 -0
- package/dist/utils/exit-codes.mjs.map +1 -0
- package/dist/utils/output.cjs +61 -0
- package/dist/utils/output.d.cts +43 -0
- package/dist/utils/output.d.cts.map +1 -0
- package/dist/utils/output.d.mts +43 -0
- package/dist/utils/output.d.mts.map +1 -0
- package/dist/utils/output.mjs +56 -0
- package/dist/utils/output.mjs.map +1 -0
- package/dist/utils/run-chat-loop.cjs +1 -1
- package/dist/utils/run-chat-loop.mjs +1 -1
- package/dist/utils/run-with-aigne.cjs +10 -3
- package/dist/utils/run-with-aigne.d.cts.map +1 -1
- package/dist/utils/run-with-aigne.d.mts.map +1 -1
- package/dist/utils/run-with-aigne.mjs +10 -3
- package/dist/utils/run-with-aigne.mjs.map +1 -1
- package/dist/utils/serve-mcp.cjs +1 -1
- package/dist/utils/serve-mcp.mjs +1 -1
- package/dist/utils/view.cjs +34 -0
- package/dist/utils/view.d.cts +47 -0
- package/dist/utils/view.d.cts.map +1 -0
- package/dist/utils/view.d.mts +47 -0
- package/dist/utils/view.d.mts.map +1 -0
- package/dist/utils/view.mjs +33 -0
- package/dist/utils/view.mjs.map +1 -0
- package/dist/utils/yargs.cjs +27 -5
- package/dist/utils/yargs.d.cts +13 -0
- package/dist/utils/yargs.d.cts.map +1 -1
- package/dist/utils/yargs.d.mts +14 -1
- package/dist/utils/yargs.d.mts.map +1 -1
- package/dist/utils/yargs.mjs +32 -10
- package/dist/utils/yargs.mjs.map +1 -1
- package/package.json +21 -17
- package/dist/commands/app/app.cjs +0 -92
- package/dist/commands/app/app.mjs +0 -90
- package/dist/commands/app/app.mjs.map +0 -1
- package/dist/commands/app/cli.cjs +0 -6
- package/dist/commands/app/cli.d.cts +0 -1
- package/dist/commands/app/cli.d.mts +0 -1
- package/dist/commands/app/cli.mjs +0 -8
- package/dist/commands/app/cli.mjs.map +0 -1
- package/dist/commands/app/upgrade.cjs +0 -243
- package/dist/commands/app/upgrade.mjs +0 -240
- package/dist/commands/app/upgrade.mjs.map +0 -1
- package/dist/commands/app.cjs +0 -53
- package/dist/commands/app.mjs +0 -53
- package/dist/commands/app.mjs.map +0 -1
- package/dist/commands/deploy.cjs +0 -237
- package/dist/commands/deploy.mjs +0 -237
- package/dist/commands/deploy.mjs.map +0 -1
- package/dist/utils/listr.cjs +0 -226
- package/dist/utils/listr.d.cts +0 -71
- package/dist/utils/listr.d.cts.map +0 -1
- package/dist/utils/listr.d.mts +0 -71
- package/dist/utils/listr.d.mts.map +0 -1
- package/dist/utils/listr.mjs +0 -222
- package/dist/utils/listr.mjs.map +0 -1
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_utils_aigne_hub_model = require('../utils/aigne-hub/model.cjs');
|
|
3
|
+
const require_terminal_input = require('../ui/utils/terminal-input.cjs');
|
|
4
|
+
const require_terminal = require('../tracer/terminal.cjs');
|
|
5
|
+
let chalk = require("chalk");
|
|
6
|
+
chalk = require_rolldown_runtime.__toESM(chalk);
|
|
7
|
+
let node_path = require("node:path");
|
|
8
|
+
let _aigne_core = require("@aigne/core");
|
|
9
|
+
let _aigne_core_loader = require("@aigne/core/loader");
|
|
10
|
+
|
|
11
|
+
//#region src/shell/repl.ts
|
|
12
|
+
/**
|
|
13
|
+
* Get the prompt string based on current shell state
|
|
14
|
+
*/
|
|
15
|
+
function getPrompt(state) {
|
|
16
|
+
if (state.config?.prompt) return state.config.prompt.replace("{mode}", state.mode).replace("{agent}", state.agent?.name || "");
|
|
17
|
+
if (state.mode === "agent" && state.agent?.name) return `aigne [${state.agent.name}]>`;
|
|
18
|
+
return "aigne>";
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Create or recreate UserAgent for the current agent
|
|
22
|
+
* Call this when agent changes or when clearing conversation
|
|
23
|
+
*/
|
|
24
|
+
function resetUserAgent(state) {
|
|
25
|
+
state.userAgent = state.aigne.invoke(state.agent);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Helper to resolve path
|
|
29
|
+
*/
|
|
30
|
+
function resolvePath(path) {
|
|
31
|
+
return (0, node_path.isAbsolute)(path) ? path : (0, node_path.resolve)(process.cwd(), path);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* /load command - Load an agent from a path
|
|
35
|
+
*/
|
|
36
|
+
async function handleLoad(args, state) {
|
|
37
|
+
if (args.length === 0) return { message: `${chalk.default.red("Error:")} No path specified.\nUsage: /load <path>` };
|
|
38
|
+
const path = resolvePath(args[0]);
|
|
39
|
+
try {
|
|
40
|
+
const agent = await (0, _aigne_core_loader.loadAgent)(path, { model: (modelOptions) => require_utils_aigne_hub_model.loadChatModel({ ...modelOptions }) });
|
|
41
|
+
const name = agent.name || args[0] || "unnamed";
|
|
42
|
+
state.loadedAgents.set(name, {
|
|
43
|
+
agent,
|
|
44
|
+
path
|
|
45
|
+
});
|
|
46
|
+
state.agent = agent;
|
|
47
|
+
state.mode = "agent";
|
|
48
|
+
resetUserAgent(state);
|
|
49
|
+
return { message: chalk.default.green(`Loaded: ${name}`) };
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return { message: `${chalk.default.red("Error:")} Failed to load agent from ${path}\n${error instanceof Error ? error.message : String(error)}` };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* /list command - List all loaded agents
|
|
56
|
+
*/
|
|
57
|
+
function handleList(_args, state) {
|
|
58
|
+
if (state.loadedAgents.size === 0) return { message: chalk.default.gray("No agents loaded. Use /load <path> to load an agent.") };
|
|
59
|
+
const lines = ["Loaded agents:"];
|
|
60
|
+
for (const [name, { path }] of state.loadedAgents) {
|
|
61
|
+
const prefix = state.mode === "agent" && state.agent?.name === name ? chalk.default.green("* ") : " ";
|
|
62
|
+
lines.push(`${prefix}${name} ${chalk.default.gray(`(${path})`)}`);
|
|
63
|
+
}
|
|
64
|
+
return { message: lines.join("\n") };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* /switch command - Switch to a different loaded agent
|
|
68
|
+
*/
|
|
69
|
+
function handleSwitch(args, state) {
|
|
70
|
+
if (state.loadedAgents.size === 0) return { message: chalk.default.gray("No agents loaded. Use /load <path> to load an agent first.") };
|
|
71
|
+
const name = args[0];
|
|
72
|
+
if (!name) {
|
|
73
|
+
const lines = ["Available agents:"];
|
|
74
|
+
let i = 1;
|
|
75
|
+
for (const [agentName] of state.loadedAgents) {
|
|
76
|
+
lines.push(` ${i}. ${agentName}`);
|
|
77
|
+
i++;
|
|
78
|
+
}
|
|
79
|
+
lines.push("\nUsage: /switch <name>");
|
|
80
|
+
return { message: lines.join("\n") };
|
|
81
|
+
}
|
|
82
|
+
const loaded = state.loadedAgents.get(name);
|
|
83
|
+
if (!loaded) return { message: `${chalk.default.red("Agent not found:")} ${name}` };
|
|
84
|
+
state.agent = loaded.agent;
|
|
85
|
+
state.mode = "agent";
|
|
86
|
+
resetUserAgent(state);
|
|
87
|
+
return { message: chalk.default.green(`Switched to: ${name}`) };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* /unload command - Unload an agent
|
|
91
|
+
*/
|
|
92
|
+
function handleUnload(args, state) {
|
|
93
|
+
if (state.loadedAgents.size === 0) return { message: chalk.default.gray("No agents loaded.") };
|
|
94
|
+
const name = args[0];
|
|
95
|
+
if (!name) return { message: `${chalk.default.red("Error:")} No agent name specified.\nUsage: /unload <name>` };
|
|
96
|
+
if (!state.loadedAgents.has(name)) return { message: `${chalk.default.red("Agent not found:")} ${name}` };
|
|
97
|
+
const isCurrentAgent = state.mode === "agent" && state.agent?.name === name;
|
|
98
|
+
state.loadedAgents.delete(name);
|
|
99
|
+
if (isCurrentAgent) {
|
|
100
|
+
const remaining = state.loadedAgents.values().next();
|
|
101
|
+
if (!remaining.done && remaining.value) state.agent = remaining.value.agent;
|
|
102
|
+
else {
|
|
103
|
+
state.agent = state.defaultAgent;
|
|
104
|
+
state.mode = "direct";
|
|
105
|
+
}
|
|
106
|
+
resetUserAgent(state);
|
|
107
|
+
}
|
|
108
|
+
return { message: chalk.default.green(`Unloaded: ${name}`) };
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* /info command - Show current agent info
|
|
112
|
+
*/
|
|
113
|
+
function handleInfo(_args, state) {
|
|
114
|
+
const lines = [];
|
|
115
|
+
lines.push(`${chalk.default.cyan("Current Mode:")} ${state.mode}`);
|
|
116
|
+
if (state.mode === "agent" && state.agent) {
|
|
117
|
+
lines.push(`${chalk.default.cyan("Agent:")} ${state.agent.name || "unnamed"}`);
|
|
118
|
+
if (state.agent instanceof _aigne_core.AIAgent && state.agent.instructions) {
|
|
119
|
+
const instructions = typeof state.agent.instructions === "string" ? state.agent.instructions : "function-based instructions";
|
|
120
|
+
lines.push(`${chalk.default.cyan("Instructions:")} ${instructions.slice(0, 100)}...`);
|
|
121
|
+
}
|
|
122
|
+
} else lines.push(`${chalk.default.cyan("Agent:")} default assistant (direct mode)`);
|
|
123
|
+
lines.push(`${chalk.default.cyan("Loaded Agents:")} ${state.loadedAgents.size}`);
|
|
124
|
+
return { message: lines.join("\n") };
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* /mode command - Display or switch mode
|
|
128
|
+
*/
|
|
129
|
+
function handleMode(args, state) {
|
|
130
|
+
if (args.length === 0) return { message: `${chalk.default.cyan("Current mode:")} ${state.mode}\n\nAvailable modes:\n direct - Direct LLM conversation\n agent - Conversation through loaded agent` };
|
|
131
|
+
const targetMode = args[0]?.toLowerCase();
|
|
132
|
+
if (targetMode === "direct") {
|
|
133
|
+
state.mode = "direct";
|
|
134
|
+
state.agent = state.defaultAgent;
|
|
135
|
+
resetUserAgent(state);
|
|
136
|
+
return { message: chalk.default.green("Switched to direct mode.") };
|
|
137
|
+
}
|
|
138
|
+
if (targetMode === "agent") {
|
|
139
|
+
if (state.loadedAgents.size === 0) return { message: `${chalk.default.red("Error:")} No agents loaded. Use /load <path> first.` };
|
|
140
|
+
if (state.mode === "agent" && state.agent !== state.defaultAgent) return { message: chalk.default.gray("Already in agent mode.") };
|
|
141
|
+
const firstAgent = state.loadedAgents.values().next().value;
|
|
142
|
+
if (firstAgent) {
|
|
143
|
+
state.agent = firstAgent.agent;
|
|
144
|
+
state.mode = "agent";
|
|
145
|
+
resetUserAgent(state);
|
|
146
|
+
return { message: chalk.default.green(`Switched to agent mode with: ${firstAgent.agent.name}`) };
|
|
147
|
+
}
|
|
148
|
+
return { message: `${chalk.default.red("Error:")} No agents loaded.` };
|
|
149
|
+
}
|
|
150
|
+
return { message: `${chalk.default.red("Error:")} Unknown mode: ${targetMode}\nAvailable modes: direct, agent` };
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* /run command - Run an agent from a path (single execution)
|
|
154
|
+
*/
|
|
155
|
+
async function handleRun(args, state) {
|
|
156
|
+
if (args.length === 0) return { message: `${chalk.default.red("Error:")} No path specified.\nUsage: /run <path> [input]` };
|
|
157
|
+
const path = resolvePath(args[0]);
|
|
158
|
+
const input = args.slice(1).join(" ");
|
|
159
|
+
try {
|
|
160
|
+
const agent = await (0, _aigne_core_loader.loadAgent)(path, { model: (modelOptions) => require_utils_aigne_hub_model.loadChatModel({ ...modelOptions }) });
|
|
161
|
+
const { aigne } = state;
|
|
162
|
+
const tracer = new require_terminal.TerminalTracer(aigne.newContext(), {});
|
|
163
|
+
const message = input ? { message: input } : {};
|
|
164
|
+
await tracer.run(agent, message);
|
|
165
|
+
return {};
|
|
166
|
+
} catch (error) {
|
|
167
|
+
return { message: `${chalk.default.red("Error:")} Failed to run agent from ${path}\n${error instanceof Error ? error.message : String(error)}` };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* /eval command - Placeholder for agent evaluation
|
|
172
|
+
*/
|
|
173
|
+
function handleEval(args, _state) {
|
|
174
|
+
if (args.length === 0) return { message: `${chalk.default.red("Error:")} Missing arguments.\nUsage: /eval <agent> --dataset <path>\n\nFor full evaluation, use: aigne eval <path> --agent <name> --dataset <path>` };
|
|
175
|
+
return { message: `${chalk.default.yellow("Note:")} Full evaluation is better done via CLI.\nRun: ${chalk.default.cyan("aigne eval")} ${args.join(" ")}` };
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* CLI command documentation for /explain
|
|
179
|
+
*/
|
|
180
|
+
const CLI_COMMAND_DOCS = {
|
|
181
|
+
run: {
|
|
182
|
+
purpose: "Run an AIGNE agent from a directory or URL",
|
|
183
|
+
usage: "aigne run [path] [--input <message>] [--model <model>] [--interactive] [--json]",
|
|
184
|
+
examples: [
|
|
185
|
+
"aigne run ./my-agent",
|
|
186
|
+
"aigne run ./my-agent --input 'Hello'",
|
|
187
|
+
"aigne run ./my-agent --interactive"
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
eval: {
|
|
191
|
+
purpose: "Evaluate an AIGNE agent against test cases",
|
|
192
|
+
usage: "aigne eval [path] --agent <name> --dataset <path> [--output <path>]",
|
|
193
|
+
examples: ["aigne eval . --agent my-agent --dataset tests.json", "aigne eval . --agent my-agent --dataset tests.json --output results.csv"]
|
|
194
|
+
},
|
|
195
|
+
skill: {
|
|
196
|
+
purpose: "Run Agent Skills from specified directories",
|
|
197
|
+
usage: "aigne skill <paths..> [--input <message>] [--interactive]",
|
|
198
|
+
examples: ["aigne skill ./skill1 ./skill2", "aigne skill ./my-skill --interactive"]
|
|
199
|
+
},
|
|
200
|
+
test: {
|
|
201
|
+
purpose: "Run agent tests in the specified directory",
|
|
202
|
+
usage: "aigne test [--filter <pattern>] [--json]",
|
|
203
|
+
examples: ["aigne test", "aigne test --filter 'my-test'"]
|
|
204
|
+
},
|
|
205
|
+
create: {
|
|
206
|
+
purpose: "Create a new AIGNE agent project",
|
|
207
|
+
usage: "aigne create [path] [--template <name>]",
|
|
208
|
+
examples: ["aigne create my-agent", "aigne create my-agent --template chatbot"]
|
|
209
|
+
},
|
|
210
|
+
"serve-mcp": {
|
|
211
|
+
purpose: "Serve agents as an MCP (Model Context Protocol) server",
|
|
212
|
+
usage: "aigne serve-mcp [path] [--host <host>] [--port <port>]",
|
|
213
|
+
examples: ["aigne serve-mcp .", "aigne serve-mcp ./my-agent --port 8080"]
|
|
214
|
+
},
|
|
215
|
+
hub: {
|
|
216
|
+
purpose: "Manage AIGNE Hub connections",
|
|
217
|
+
usage: "aigne hub <command>",
|
|
218
|
+
examples: [
|
|
219
|
+
"aigne hub list",
|
|
220
|
+
"aigne hub connect",
|
|
221
|
+
"aigne hub status"
|
|
222
|
+
]
|
|
223
|
+
},
|
|
224
|
+
shell: {
|
|
225
|
+
purpose: "Start an interactive shell for LLM conversation",
|
|
226
|
+
usage: "aigne shell [--model <model>]",
|
|
227
|
+
examples: ["aigne shell", "aigne shell --model gpt-4"]
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
/**
|
|
231
|
+
* /explain command - Show CLI command documentation
|
|
232
|
+
*/
|
|
233
|
+
function handleExplain(args, _state) {
|
|
234
|
+
if (args.length === 0) {
|
|
235
|
+
const lines$1 = [chalk.default.bold("Available commands:")];
|
|
236
|
+
for (const [name, doc$1] of Object.entries(CLI_COMMAND_DOCS)) lines$1.push(` ${chalk.default.cyan(name.padEnd(12))} ${doc$1.purpose}`);
|
|
237
|
+
lines$1.push("");
|
|
238
|
+
lines$1.push("Use /explain <command> for detailed documentation.");
|
|
239
|
+
return { message: lines$1.join("\n") };
|
|
240
|
+
}
|
|
241
|
+
const cmdName = args[0]?.toLowerCase();
|
|
242
|
+
const doc = CLI_COMMAND_DOCS[cmdName];
|
|
243
|
+
if (!doc) return { message: `${chalk.default.red("Error:")} unknown command: ${cmdName}\n\nAvailable commands: ${Object.keys(CLI_COMMAND_DOCS).join(", ")}` };
|
|
244
|
+
const lines = [
|
|
245
|
+
`${chalk.default.bold("COMMAND")} aigne ${cmdName}`,
|
|
246
|
+
"",
|
|
247
|
+
chalk.default.bold("PURPOSE"),
|
|
248
|
+
` ${doc.purpose}`,
|
|
249
|
+
"",
|
|
250
|
+
chalk.default.bold("USAGE"),
|
|
251
|
+
` ${doc.usage}`
|
|
252
|
+
];
|
|
253
|
+
if (doc.examples?.length) {
|
|
254
|
+
lines.push("", chalk.default.bold("EXAMPLES"));
|
|
255
|
+
for (const ex of doc.examples) lines.push(` ${chalk.default.gray("$")} ${ex}`);
|
|
256
|
+
}
|
|
257
|
+
return { message: lines.join("\n") };
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* /sessions command - List available sessions
|
|
261
|
+
*/
|
|
262
|
+
function handleSessions(_args, state) {
|
|
263
|
+
if (!state.sessionId) return { message: chalk.default.yellow("Session history not configured. Start shell with history enabled to use this feature.") };
|
|
264
|
+
return { message: [
|
|
265
|
+
chalk.default.bold("Current Session:"),
|
|
266
|
+
` ${chalk.default.cyan("ID:")} ${state.sessionId}`,
|
|
267
|
+
"",
|
|
268
|
+
chalk.default.gray("Note: Full session listing requires AFS History provider.")
|
|
269
|
+
].join("\n") };
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* /history command - Show conversation history
|
|
273
|
+
*/
|
|
274
|
+
function handleHistory(args, state) {
|
|
275
|
+
if (!state.sessionId) return { message: chalk.default.yellow("Session history not configured. Start shell with history enabled to use this feature.") };
|
|
276
|
+
const count = args[0] ? Number.parseInt(args[0], 10) : 10;
|
|
277
|
+
if (Number.isNaN(count)) return { message: `${chalk.default.red("Error:")} Invalid count: ${args[0]}\nUsage: /history [count]` };
|
|
278
|
+
return { message: chalk.default.gray(`Showing last ${count} messages (feature requires AFS History).`) };
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* /restore command - Restore a previous session
|
|
282
|
+
*/
|
|
283
|
+
function handleRestore(args, state) {
|
|
284
|
+
if (args.length === 0) return { message: `${chalk.default.red("Error:")} No session ID specified.\nUsage: /restore <sessionId>` };
|
|
285
|
+
if (!state.sessionId) return { message: chalk.default.yellow("Session history not configured. Cannot restore sessions without history provider.") };
|
|
286
|
+
const sessionId = args[0];
|
|
287
|
+
return { message: chalk.default.yellow(`Session restore not yet implemented. Requested session: ${sessionId}`) };
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* /export command - Export conversation
|
|
291
|
+
*/
|
|
292
|
+
function handleExport(args, state) {
|
|
293
|
+
const format = args[0] || "json";
|
|
294
|
+
const path = args[1];
|
|
295
|
+
if (!state.sessionId) return { message: chalk.default.yellow("Session history not configured. Nothing to export.") };
|
|
296
|
+
return { message: [
|
|
297
|
+
chalk.default.bold("Export Options:"),
|
|
298
|
+
` Format: ${format} (json, markdown, text)`,
|
|
299
|
+
` Path: ${path || "(stdout)"}`,
|
|
300
|
+
"",
|
|
301
|
+
"Usage: /export [format] [path]"
|
|
302
|
+
].join("\n") };
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* /clear command - Clear conversation history
|
|
306
|
+
*/
|
|
307
|
+
function handleClear(_args, state) {
|
|
308
|
+
if (state.sessionId) state.sessionId = crypto.randomUUID();
|
|
309
|
+
resetUserAgent(state);
|
|
310
|
+
return { message: chalk.default.green("Conversation cleared.") };
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* /model command - Display or change model
|
|
314
|
+
*/
|
|
315
|
+
async function handleModel(args, state) {
|
|
316
|
+
const { aigne } = state;
|
|
317
|
+
if (args.length === 0) {
|
|
318
|
+
const model = aigne.model;
|
|
319
|
+
if (!model) return { message: chalk.default.yellow("No model configured.") };
|
|
320
|
+
try {
|
|
321
|
+
const credential = await model.credential;
|
|
322
|
+
const modelName = credential?.model || "default";
|
|
323
|
+
const lines = [chalk.default.bold("Current Model:"), ` ${chalk.default.cyan("Model:")} ${modelName}`];
|
|
324
|
+
if (credential?.apiKey) {
|
|
325
|
+
const masked = `${credential.apiKey.slice(0, 4)}...${credential.apiKey.slice(-4)}`;
|
|
326
|
+
lines.push(` ${chalk.default.cyan("API Key:")} ${masked}`);
|
|
327
|
+
}
|
|
328
|
+
return { message: lines.join("\n") };
|
|
329
|
+
} catch {
|
|
330
|
+
return { message: `${chalk.default.cyan("Model:")} configured (details unavailable)` };
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return { message: chalk.default.yellow("Changing model at runtime is not yet supported.\nRestart shell with: aigne shell --model " + args[0]) };
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Help command categories with their commands
|
|
337
|
+
*/
|
|
338
|
+
const HELP_CATEGORIES = [
|
|
339
|
+
{
|
|
340
|
+
name: "Commands",
|
|
341
|
+
commands: [{
|
|
342
|
+
cmd: "/help",
|
|
343
|
+
desc: "Show this help message"
|
|
344
|
+
}, {
|
|
345
|
+
cmd: "/exit",
|
|
346
|
+
desc: "Exit the shell",
|
|
347
|
+
alias: "/quit"
|
|
348
|
+
}]
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
name: "Agent Operations",
|
|
352
|
+
commands: [
|
|
353
|
+
{
|
|
354
|
+
cmd: "/load <path>",
|
|
355
|
+
desc: "Load an agent from a path"
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
cmd: "/list",
|
|
359
|
+
desc: "List loaded agents"
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
cmd: "/switch <name>",
|
|
363
|
+
desc: "Switch to a different agent"
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
cmd: "/unload <name>",
|
|
367
|
+
desc: "Unload an agent"
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
cmd: "/info",
|
|
371
|
+
desc: "Show current agent info"
|
|
372
|
+
}
|
|
373
|
+
]
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
name: "Mode",
|
|
377
|
+
commands: [
|
|
378
|
+
{
|
|
379
|
+
cmd: "/mode",
|
|
380
|
+
desc: "Show current mode"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
cmd: "/mode direct",
|
|
384
|
+
desc: "Switch to direct LLM mode"
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
cmd: "/mode agent",
|
|
388
|
+
desc: "Switch to agent mode"
|
|
389
|
+
}
|
|
390
|
+
]
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
name: "CLI Bridge",
|
|
394
|
+
commands: [
|
|
395
|
+
{
|
|
396
|
+
cmd: "/run <path>",
|
|
397
|
+
desc: "Run an agent (single execution)"
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
cmd: "/eval <path>",
|
|
401
|
+
desc: "Evaluate an agent"
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
cmd: "/explain <cmd>",
|
|
405
|
+
desc: "Explain CLI command"
|
|
406
|
+
}
|
|
407
|
+
]
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
name: "Session",
|
|
411
|
+
commands: [
|
|
412
|
+
{
|
|
413
|
+
cmd: "/sessions",
|
|
414
|
+
desc: "List available sessions"
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
cmd: "/history [n]",
|
|
418
|
+
desc: "Show conversation history"
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
cmd: "/restore <id>",
|
|
422
|
+
desc: "Restore a previous session"
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
cmd: "/export",
|
|
426
|
+
desc: "Export conversation"
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
cmd: "/clear",
|
|
430
|
+
desc: "Clear conversation"
|
|
431
|
+
}
|
|
432
|
+
]
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
name: "Settings",
|
|
436
|
+
commands: [{
|
|
437
|
+
cmd: "/model",
|
|
438
|
+
desc: "Show current model info"
|
|
439
|
+
}]
|
|
440
|
+
}
|
|
441
|
+
];
|
|
442
|
+
/**
|
|
443
|
+
* Generate help message based on state config
|
|
444
|
+
*/
|
|
445
|
+
function generateHelp(state) {
|
|
446
|
+
const hiddenCommands = new Set(state.config?.commands?.hide || []);
|
|
447
|
+
const lines = [];
|
|
448
|
+
for (const category of HELP_CATEGORIES) {
|
|
449
|
+
const visibleCommands = category.commands.filter((c) => {
|
|
450
|
+
const baseCmd = c.cmd.split(" ")[0];
|
|
451
|
+
return !hiddenCommands.has(baseCmd);
|
|
452
|
+
});
|
|
453
|
+
if (visibleCommands.length === 0) continue;
|
|
454
|
+
lines.push(chalk.default.bold(`${category.name}:`));
|
|
455
|
+
for (const c of visibleCommands) {
|
|
456
|
+
const alias = c.alias ? ` ${chalk.default.gray(`(or ${c.alias})`)}` : "";
|
|
457
|
+
lines.push(` ${chalk.default.cyan(c.cmd.padEnd(18))}${alias} ${c.desc}`);
|
|
458
|
+
}
|
|
459
|
+
lines.push("");
|
|
460
|
+
}
|
|
461
|
+
lines.push(chalk.default.bold("Tips:"));
|
|
462
|
+
lines.push(" - Type your message and press Enter to chat");
|
|
463
|
+
lines.push(" - Press Ctrl+C to cancel current input");
|
|
464
|
+
lines.push(" - Press Ctrl+D to exit");
|
|
465
|
+
return lines.join("\n").trim();
|
|
466
|
+
}
|
|
467
|
+
const SLASH_COMMANDS = {
|
|
468
|
+
"/exit": () => ({ exit: true }),
|
|
469
|
+
"/quit": () => ({ exit: true }),
|
|
470
|
+
"/help": (_args, state) => ({ message: generateHelp(state) }),
|
|
471
|
+
"/load": handleLoad,
|
|
472
|
+
"/list": handleList,
|
|
473
|
+
"/switch": handleSwitch,
|
|
474
|
+
"/unload": handleUnload,
|
|
475
|
+
"/info": handleInfo,
|
|
476
|
+
"/mode": handleMode,
|
|
477
|
+
"/run": handleRun,
|
|
478
|
+
"/eval": handleEval,
|
|
479
|
+
"/explain": handleExplain,
|
|
480
|
+
"/sessions": handleSessions,
|
|
481
|
+
"/history": handleHistory,
|
|
482
|
+
"/restore": handleRestore,
|
|
483
|
+
"/export": handleExport,
|
|
484
|
+
"/clear": handleClear,
|
|
485
|
+
"/model": handleModel
|
|
486
|
+
};
|
|
487
|
+
/**
|
|
488
|
+
* Parse and execute a slash command if the input starts with /
|
|
489
|
+
* Returns undefined if not a slash command
|
|
490
|
+
*/
|
|
491
|
+
async function parseSlashCommand(input, state) {
|
|
492
|
+
const trimmed = input.trim();
|
|
493
|
+
if (!trimmed.startsWith("/")) return void 0;
|
|
494
|
+
const parts = trimmed.split(/\s+/);
|
|
495
|
+
let cmd = parts[0]?.toLowerCase() ?? "";
|
|
496
|
+
const args = parts.slice(1);
|
|
497
|
+
if (state.config?.commands?.alias && cmd in state.config.commands.alias) {
|
|
498
|
+
const aliasTarget = state.config.commands.alias[cmd];
|
|
499
|
+
if (aliasTarget) {
|
|
500
|
+
const aliasParts = aliasTarget.split(/\s+/);
|
|
501
|
+
cmd = aliasParts[0]?.toLowerCase() ?? "";
|
|
502
|
+
args.unshift(...aliasParts.slice(1));
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const handler = SLASH_COMMANDS[cmd];
|
|
506
|
+
if (handler) return await handler(args, state);
|
|
507
|
+
return { message: `Unknown command: ${cmd}. Type /help for available commands.` };
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Call the agent with user input and display response
|
|
511
|
+
*/
|
|
512
|
+
async function callAgent(state, userMessage) {
|
|
513
|
+
const { userAgent } = state;
|
|
514
|
+
const input = { message: userMessage };
|
|
515
|
+
const tracer = new require_terminal.TerminalTracer(userAgent.context, { suppressToolCallLogs: true });
|
|
516
|
+
try {
|
|
517
|
+
await tracer.run(userAgent, input);
|
|
518
|
+
} catch (error) {
|
|
519
|
+
console.error(chalk.default.red(`\nError: ${error instanceof Error ? error.message : String(error)}`));
|
|
520
|
+
if (error instanceof Error && error.stack) console.error(chalk.default.gray(error.stack));
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Run the shell REPL loop
|
|
525
|
+
*/
|
|
526
|
+
async function runShellLoop(state) {
|
|
527
|
+
for (;;) {
|
|
528
|
+
const input = await require_terminal_input.terminalInput({
|
|
529
|
+
message: getPrompt(state),
|
|
530
|
+
clear: true
|
|
531
|
+
});
|
|
532
|
+
if (!input?.trim()) continue;
|
|
533
|
+
const cmdResult = await parseSlashCommand(input, state);
|
|
534
|
+
if (cmdResult) {
|
|
535
|
+
if (cmdResult.message) console.log(cmdResult.message);
|
|
536
|
+
if (cmdResult.exit) break;
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
await callAgent(state, input.trim());
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
//#endregion
|
|
544
|
+
exports.runShellLoop = runShellLoop;
|