@aigne/cli 1.5.1-4 → 1.6.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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.6.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.5.1...cli-v1.6.0) (2025-04-22)
4
+
5
+
6
+ ### Features
7
+
8
+ * **cli:** add --verbose option for run command ([#82](https://github.com/AIGNE-io/aigne-framework/issues/82)) ([7adf8be](https://github.com/AIGNE-io/aigne-framework/commit/7adf8be34963e714268457ab8b2ffeb945da5721))
9
+
10
+ ## [1.5.1](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.5.0...cli-v1.5.1) (2025-04-22)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * use bunwrapper launch examples ([#79](https://github.com/AIGNE-io/aigne-framework/issues/79)) ([55022e2](https://github.com/AIGNE-io/aigne-framework/commit/55022e20bb253bac608dad3024600da91e093a69))
16
+
3
17
  ## [1.5.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.4.0...cli-v1.5.0) (2025-04-22)
4
18
 
5
19
 
@@ -4,6 +4,7 @@ import { homedir } from "node:os";
4
4
  import { isAbsolute, join, resolve } from "node:path";
5
5
  import { ExecutionEngine } from "@aigne/core";
6
6
  import { loadModel } from "@aigne/core/loader/index.js";
7
+ import { logger } from "@aigne/core/utils/logger.js";
7
8
  import { isNonNullable } from "@aigne/core/utils/type-utils.js";
8
9
  import { Listr, PRESET_TIMER } from "@aigne/listr2";
9
10
  import { Command } from "commander";
@@ -18,7 +19,10 @@ export function createRunCommand() {
18
19
  .option("--download-dir <dir>", "Directory to download the package to (defaults to the ~/.aigne/xxx)")
19
20
  .option("--model-provider <provider>", "Model provider to use, available providers: openai, claude, xai (defaults to the aigne.yaml definition or openai)")
20
21
  .option("--model-name <model>", "Model name to use, available models depend on the provider (defaults to the aigne.yaml definition or gpt-4o-mini)")
22
+ .option("--verbose", "Enable verbose logging", false)
21
23
  .action(async (path, options) => {
24
+ if (options.verbose)
25
+ logger.enable("*");
22
26
  const { downloadDir, dir } = prepareDirs(path, options);
23
27
  const { engine, agent } = await new Listr([
24
28
  {
@@ -78,7 +82,7 @@ export function createRunCommand() {
78
82
  assert(engine);
79
83
  assert(agent);
80
84
  const user = engine.call(agent);
81
- await runChatLoopInTerminal(user, {});
85
+ await runChatLoopInTerminal(user);
82
86
  await engine.shutdown();
83
87
  })
84
88
  .showHelpAfterError(true)
@@ -3,7 +3,6 @@ import type { ContextUsage } from "@aigne/core/execution-engine/usage";
3
3
  import { type DefaultRenderer, Listr, type ListrRenderer, type ListrTaskWrapper } from "@aigne/listr2";
4
4
  import { promiseWithResolvers } from "../utils/promise-with-resolvers.js";
5
5
  export interface TerminalTracerOptions {
6
- verbose?: boolean;
7
6
  aiResponsePrefix?: (context: Context) => string;
8
7
  }
9
8
  export declare class TerminalTracer {
@@ -16,11 +15,6 @@ export declare class TerminalTracer {
16
15
  result: Message;
17
16
  context: Context;
18
17
  }>;
19
- protected wrap(str: string): string;
20
- formatAgentStartedOutput(agent: Agent, data: Message): string;
21
- formatAgentSucceedOutput(agent: Agent, data: Message): string;
22
- formatAgentFailedOutput(agent: Agent, data: Error): string;
23
- formatMessage(data: unknown): string;
24
18
  formatTokenUsage(usage: Partial<ContextUsage>, extra?: {
25
19
  [key: string]: string;
26
20
  }): string;
@@ -1,16 +1,15 @@
1
1
  import { EOL } from "node:os";
2
- import { inspect } from "node:util";
2
+ import { format, inspect } from "node:util";
3
3
  import { ChatModel, MESSAGE_KEY, } from "@aigne/core";
4
+ import { logger } from "@aigne/core/utils/logger.js";
4
5
  import { mergeAgentResponseChunk, readableStreamToAsyncIterator, } from "@aigne/core/utils/stream-utils.js";
5
- import { Listr, ListrDefaultRendererLogLevels, Spinner, figures, } from "@aigne/listr2";
6
+ import { Listr, ListrDefaultRendererLogLevels, Spinner, } from "@aigne/listr2";
7
+ import { markedTerminal } from "@aigne/marked-terminal";
6
8
  import chalk from "chalk";
7
9
  import { Marked } from "marked";
8
- import { markedTerminal } from "marked-terminal";
9
10
  import wrap from "wrap-ansi";
10
- import { z } from "zod";
11
11
  import { promiseWithResolvers } from "../utils/promise-with-resolvers.js";
12
12
  import { parseDuration } from "../utils/time.js";
13
- const DEBUG_DEPTH = z.number().int().default(2).safeParse(Number(process.env.DEBUG_DEPTH)).data;
14
13
  export class TerminalTracer {
15
14
  context;
16
15
  options;
@@ -25,14 +24,11 @@ export class TerminalTracer {
25
24
  const context = this.context.newContext({ reset: true });
26
25
  const listr = new AIGNEListr({
27
26
  formatResult: (result) => {
28
- return [
29
- this.wrap(this.options.aiResponsePrefix?.(context) || ""),
30
- this.wrap(this.formatAIResponse(result)),
31
- ];
27
+ return [this.options.aiResponsePrefix?.(context) || "", this.formatAIResponse(result)];
32
28
  },
33
29
  }, [], {
34
30
  concurrent: true,
35
- forceTTY: process.env.CI === "true",
31
+ forceTTY: true,
36
32
  rendererOptions: {
37
33
  collapseSubtasks: false,
38
34
  writeBottomBarDirectly: true,
@@ -42,7 +38,7 @@ export class TerminalTracer {
42
38
  },
43
39
  },
44
40
  });
45
- const onAgentStarted = async ({ contextId, parentContextId, agent, input, timestamp, }) => {
41
+ const onAgentStarted = async ({ contextId, parentContextId, agent, timestamp, }) => {
46
42
  const task = {
47
43
  ...promiseWithResolvers(),
48
44
  listr: promiseWithResolvers(),
@@ -71,10 +67,6 @@ export class TerminalTracer {
71
67
  else {
72
68
  listr.add(listrTask);
73
69
  }
74
- const { taskWrapper } = await task.listr.promise;
75
- if (this.options.verbose) {
76
- taskWrapper.output = this.formatAgentStartedOutput(agent, input);
77
- }
78
70
  };
79
71
  const onAgentSucceed = async ({ agent, contextId, parentContextId, output, timestamp, }) => {
80
72
  const task = this.tasks[contextId];
@@ -90,9 +82,6 @@ export class TerminalTracer {
90
82
  task.extraTitleMetadata.model = model;
91
83
  }
92
84
  taskWrapper.title = this.formatTaskTitle(agent, { task, usage: true, time: true });
93
- if (this.options.verbose) {
94
- taskWrapper.output = this.formatAgentSucceedOutput(agent, output);
95
- }
96
85
  if (!parentContextId || !this.tasks[parentContextId]) {
97
86
  Object.assign(ctx, output);
98
87
  }
@@ -105,7 +94,6 @@ export class TerminalTracer {
105
94
  task.endTime = timestamp;
106
95
  const { taskWrapper } = await task.listr.promise;
107
96
  taskWrapper.title = this.formatTaskTitle(agent, { task, usage: true, time: true });
108
- taskWrapper.output = this.formatAgentFailedOutput(agent, error);
109
97
  task.reject(error);
110
98
  };
111
99
  context.on("agentStarted", onAgentStarted);
@@ -123,30 +111,6 @@ export class TerminalTracer {
123
111
  context.off("agentFailed", onAgentFailed);
124
112
  }
125
113
  }
126
- wrap(str) {
127
- return wrap(str, process.stdout.columns ?? 80, {
128
- hard: true,
129
- trim: false,
130
- });
131
- }
132
- formatAgentStartedOutput(agent, data) {
133
- return `\
134
- ${chalk.grey(figures.pointer)} call agent ${agent.name} started with input:
135
- ${this.formatMessage(data)}`;
136
- }
137
- formatAgentSucceedOutput(agent, data) {
138
- return `\
139
- ${chalk.grey(figures.tick)} call agent ${agent.name} succeed with output:
140
- ${this.formatMessage(data)}`;
141
- }
142
- formatAgentFailedOutput(agent, data) {
143
- return `\
144
- ${chalk.grey(figures.cross)} call agent ${agent.name} failed with error:
145
- ${this.formatMessage(data)}`;
146
- }
147
- formatMessage(data) {
148
- return inspect(data, { colors: true, depth: DEBUG_DEPTH });
149
- }
150
114
  formatTokenUsage(usage, extra) {
151
115
  const items = [
152
116
  [chalk.yellow(usage.inputTokens), chalk.grey("input tokens")],
@@ -173,7 +137,7 @@ ${this.formatMessage(data)}`;
173
137
  title += ` ${this.formatTimeUsage(task.startTime, task.endTime)}`;
174
138
  return title;
175
139
  }
176
- marked = new Marked().use(markedTerminal());
140
+ marked = new Marked().use(markedTerminal({ forceHyperLink: false }));
177
141
  formatAIResponse({ [MESSAGE_KEY]: msg, ...message } = {}) {
178
142
  const text = msg && typeof msg === "string" ? this.marked.parse(msg, { async: false }).trim() : undefined;
179
143
  const json = Object.keys(message).length > 0 ? inspect(message, { colors: true }) : undefined;
@@ -184,6 +148,7 @@ class AIGNEListr extends Listr {
184
148
  myOptions;
185
149
  result = {};
186
150
  isStreamRunning = false;
151
+ logs = [];
187
152
  constructor(myOptions, ...args) {
188
153
  super(...args);
189
154
  this.myOptions = myOptions;
@@ -197,17 +162,24 @@ class AIGNEListr extends Listr {
197
162
  "",
198
163
  tasks,
199
164
  "",
200
- ...[this.myOptions.formatResult(this.result)].flat(),
165
+ ...this.myOptions.formatResult(this.result).map((i) => this.wrap(i)),
201
166
  this.isStreamRunning ? spinner.fetch() : "",
202
167
  ];
203
- return [l.join(EOL), output];
168
+ return [l.join(EOL), [output, ...this.logs.splice(0)].filter(Boolean).join(EOL)];
204
169
  };
205
170
  // @ts-ignore initialize the renderer
206
171
  this.renderer = renderer;
207
172
  }
208
173
  async run(stream) {
209
- this.add({ task: () => this.extractStream(stream) });
210
- return await super.run().then(() => ({ ...this.result }));
174
+ const originalLog = logger.log;
175
+ try {
176
+ logger.log = (...args) => this.logs.push(format(...args));
177
+ this.add({ task: () => this.extractStream(stream) });
178
+ return await super.run().then(() => ({ ...this.result }));
179
+ }
180
+ finally {
181
+ logger.log = originalLog;
182
+ }
211
183
  }
212
184
  async extractStream(stream) {
213
185
  this.isStreamRunning = true;
@@ -218,4 +190,10 @@ class AIGNEListr extends Listr {
218
190
  this.isStreamRunning = false;
219
191
  return this.result;
220
192
  }
193
+ wrap(str) {
194
+ return wrap(str, process.stdout.columns ?? 80, {
195
+ hard: true,
196
+ trim: false,
197
+ });
198
+ }
221
199
  }
@@ -4,7 +4,6 @@ export interface ChatLoopOptions {
4
4
  welcome?: string;
5
5
  defaultQuestion?: string;
6
6
  inputKey?: string;
7
- verbose?: boolean;
8
7
  skipLoop?: boolean;
9
8
  }
10
9
  export declare function runChatLoopInTerminal(userAgent: input, options?: ChatLoopOptions): Promise<void>;
@@ -1,14 +1,10 @@
1
1
  import { createMessage } from "@aigne/core";
2
- import { logger } from "@aigne/core/utils/logger.js";
3
2
  import { figures } from "@aigne/listr2";
4
3
  import chalk from "chalk";
5
4
  import inquirer from "inquirer";
6
5
  import { TerminalTracer } from "../tracer/terminal.js";
7
6
  export async function runChatLoopInTerminal(userAgent, options = {}) {
8
7
  const { initialCall = process.env.INITIAL_CALL, skipLoop = process.env.SKIP_LOOP === "true" } = options;
9
- options.verbose ??= logger.enabled("aigne:core");
10
- // Disable the logger, use TerminalTracer instead
11
- logger.disable();
12
8
  let prompt;
13
9
  if (options?.welcome)
14
10
  console.log(options.welcome);
@@ -49,7 +45,6 @@ export async function runChatLoopInTerminal(userAgent, options = {}) {
49
45
  }
50
46
  async function callAgent(userAgent, input, options) {
51
47
  const tracer = new TerminalTracer(userAgent.context, {
52
- verbose: options.verbose,
53
48
  aiResponsePrefix: (context) => {
54
49
  return `${chalk.grey(figures.tick)} 🤖 ${tracer.formatTokenUsage(context.usage)}`;
55
50
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/cli",
3
- "version": "1.5.1-4",
3
+ "version": "1.6.0",
4
4
  "description": "cli for AIGNE framework",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -36,6 +36,7 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@aigne/listr2": "^1.0.8",
39
+ "@aigne/marked-terminal": "^7.3.1",
39
40
  "@modelcontextprotocol/sdk": "^1.9.0",
40
41
  "chalk": "^5.4.1",
41
42
  "commander": "^13.1.0",
@@ -44,7 +45,6 @@
44
45
  "gradient-string": "^3.0.0",
45
46
  "inquirer": "^12.5.2",
46
47
  "marked": "^15.0.9",
47
- "marked-terminal": "^7.3.0",
48
48
  "openai": "^4.94.0",
49
49
  "prettier": "^3.5.3",
50
50
  "pretty-error": "^4.0.0",