@aigne/core 1.6.0 → 1.7.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.
Files changed (82) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/lib/cjs/agents/agent.d.ts +5 -2
  3. package/lib/cjs/agents/agent.js +42 -24
  4. package/lib/cjs/agents/ai-agent.d.ts +8 -8
  5. package/lib/cjs/agents/ai-agent.js +5 -2
  6. package/lib/cjs/agents/mcp-agent.d.ts +11 -0
  7. package/lib/cjs/agents/mcp-agent.js +37 -23
  8. package/lib/cjs/agents/user-agent.d.ts +9 -9
  9. package/lib/cjs/agents/user-agent.js +26 -16
  10. package/lib/cjs/execution-engine/context.d.ts +84 -46
  11. package/lib/cjs/execution-engine/context.js +136 -98
  12. package/lib/cjs/execution-engine/execution-engine.d.ts +16 -47
  13. package/lib/cjs/execution-engine/execution-engine.js +13 -40
  14. package/lib/cjs/execution-engine/message-queue.d.ts +3 -3
  15. package/lib/cjs/execution-engine/message-queue.js +32 -2
  16. package/lib/cjs/execution-engine/usage.d.ts +11 -0
  17. package/lib/cjs/execution-engine/usage.js +10 -0
  18. package/lib/cjs/loader/index.js +1 -1
  19. package/lib/cjs/models/chat-model.d.ts +3 -2
  20. package/lib/cjs/models/chat-model.js +6 -5
  21. package/lib/cjs/models/claude-chat-model.js +10 -7
  22. package/lib/cjs/models/openai-chat-model.js +5 -2
  23. package/lib/cjs/prompt/prompt-builder.d.ts +1 -1
  24. package/lib/cjs/prompt/prompt-builder.js +3 -1
  25. package/lib/cjs/utils/json-schema.js +2 -2
  26. package/lib/cjs/utils/logger.d.ts +3 -15
  27. package/lib/cjs/utils/logger.js +3 -77
  28. package/lib/cjs/utils/mcp-utils.js +1 -5
  29. package/lib/cjs/utils/model-utils.js +2 -2
  30. package/lib/cjs/utils/type-utils.d.ts +1 -0
  31. package/lib/cjs/utils/typed-event-emtter.d.ts +10 -0
  32. package/lib/cjs/utils/typed-event-emtter.js +2 -0
  33. package/lib/dts/agents/agent.d.ts +5 -2
  34. package/lib/dts/agents/ai-agent.d.ts +8 -8
  35. package/lib/dts/agents/mcp-agent.d.ts +11 -0
  36. package/lib/dts/agents/user-agent.d.ts +9 -9
  37. package/lib/dts/execution-engine/context.d.ts +84 -46
  38. package/lib/dts/execution-engine/execution-engine.d.ts +16 -47
  39. package/lib/dts/execution-engine/message-queue.d.ts +3 -3
  40. package/lib/dts/execution-engine/usage.d.ts +11 -0
  41. package/lib/dts/models/chat-model.d.ts +3 -2
  42. package/lib/dts/prompt/prompt-builder.d.ts +1 -1
  43. package/lib/dts/utils/logger.d.ts +3 -15
  44. package/lib/dts/utils/type-utils.d.ts +1 -0
  45. package/lib/dts/utils/typed-event-emtter.d.ts +10 -0
  46. package/lib/esm/agents/agent.d.ts +5 -2
  47. package/lib/esm/agents/agent.js +42 -24
  48. package/lib/esm/agents/ai-agent.d.ts +8 -8
  49. package/lib/esm/agents/ai-agent.js +5 -2
  50. package/lib/esm/agents/mcp-agent.d.ts +11 -0
  51. package/lib/esm/agents/mcp-agent.js +38 -24
  52. package/lib/esm/agents/user-agent.d.ts +9 -9
  53. package/lib/esm/agents/user-agent.js +26 -16
  54. package/lib/esm/execution-engine/context.d.ts +84 -46
  55. package/lib/esm/execution-engine/context.js +135 -98
  56. package/lib/esm/execution-engine/execution-engine.d.ts +16 -47
  57. package/lib/esm/execution-engine/execution-engine.js +14 -38
  58. package/lib/esm/execution-engine/message-queue.d.ts +3 -3
  59. package/lib/esm/execution-engine/message-queue.js +33 -3
  60. package/lib/esm/execution-engine/usage.d.ts +11 -0
  61. package/lib/esm/execution-engine/usage.js +7 -0
  62. package/lib/esm/loader/index.js +2 -2
  63. package/lib/esm/models/chat-model.d.ts +3 -2
  64. package/lib/esm/models/chat-model.js +6 -5
  65. package/lib/esm/models/claude-chat-model.js +10 -7
  66. package/lib/esm/models/openai-chat-model.js +5 -2
  67. package/lib/esm/prompt/prompt-builder.d.ts +1 -1
  68. package/lib/esm/prompt/prompt-builder.js +3 -1
  69. package/lib/esm/utils/json-schema.js +2 -2
  70. package/lib/esm/utils/logger.d.ts +3 -15
  71. package/lib/esm/utils/logger.js +3 -77
  72. package/lib/esm/utils/mcp-utils.js +1 -5
  73. package/lib/esm/utils/model-utils.js +2 -2
  74. package/lib/esm/utils/type-utils.d.ts +1 -0
  75. package/lib/esm/utils/typed-event-emtter.d.ts +10 -0
  76. package/lib/esm/utils/typed-event-emtter.js +1 -0
  77. package/package.json +7 -8
  78. package/lib/cjs/utils/run-chat-loop.d.ts +0 -11
  79. package/lib/cjs/utils/run-chat-loop.js +0 -82
  80. package/lib/dts/utils/run-chat-loop.d.ts +0 -11
  81. package/lib/esm/utils/run-chat-loop.d.ts +0 -11
  82. package/lib/esm/utils/run-chat-loop.js +0 -76
@@ -75,16 +75,18 @@ export class ClaudeChatModel extends ChatModel {
75
75
  let text = "";
76
76
  const toolCalls = [];
77
77
  let usage;
78
+ let model;
78
79
  for await (const chunk of stream) {
79
80
  if (chunk.type === "message_start") {
81
+ model ??= chunk.message.model;
80
82
  const { input_tokens, output_tokens } = chunk.message.usage;
81
83
  usage = {
82
- promptTokens: input_tokens,
83
- completionTokens: output_tokens,
84
+ inputTokens: input_tokens,
85
+ outputTokens: output_tokens,
84
86
  };
85
87
  }
86
88
  if (chunk.type === "message_delta" && usage) {
87
- usage.completionTokens = chunk.usage.output_tokens;
89
+ usage.outputTokens = chunk.usage.output_tokens;
88
90
  }
89
91
  logs.push(JSON.stringify(chunk));
90
92
  // handle streaming text
@@ -109,7 +111,7 @@ export class ClaudeChatModel extends ChatModel {
109
111
  call.args += chunk.delta.partial_json;
110
112
  }
111
113
  }
112
- const result = { usage, text };
114
+ const result = { usage, model, text };
113
115
  if (toolCalls.length) {
114
116
  result.toolCalls = toolCalls
115
117
  .map(({ args, ...c }) => ({
@@ -125,7 +127,7 @@ export class ClaudeChatModel extends ChatModel {
125
127
  return result;
126
128
  }
127
129
  catch (error) {
128
- logger.debug("Failed to process Claude stream", { error, logs });
130
+ logger.core("Failed to process Claude stream", { error, logs });
129
131
  throw error;
130
132
  }
131
133
  }
@@ -154,9 +156,10 @@ export class ClaudeChatModel extends ChatModel {
154
156
  throw new Error("Json tool not found");
155
157
  return {
156
158
  json: jsonTool.input,
159
+ model: result.model,
157
160
  usage: {
158
- promptTokens: result.usage.input_tokens,
159
- completionTokens: result.usage.output_tokens,
161
+ inputTokens: result.usage.input_tokens,
162
+ outputTokens: result.usage.output_tokens,
160
163
  },
161
164
  };
162
165
  }
@@ -72,8 +72,10 @@ export class OpenAIChatModel extends ChatModel {
72
72
  let text = "";
73
73
  const toolCalls = [];
74
74
  let usage;
75
+ let model;
75
76
  for await (const chunk of res) {
76
77
  const choice = chunk.choices?.[0];
78
+ model ??= chunk.model;
77
79
  if (choice?.delta.tool_calls?.length) {
78
80
  for (const call of choice.delta.tool_calls) {
79
81
  toolCalls[call.index] ??= {
@@ -95,13 +97,14 @@ export class OpenAIChatModel extends ChatModel {
95
97
  text += choice.delta.content;
96
98
  if (chunk.usage) {
97
99
  usage = {
98
- promptTokens: chunk.usage.prompt_tokens,
99
- completionTokens: chunk.usage.completion_tokens,
100
+ inputTokens: chunk.usage.prompt_tokens,
101
+ outputTokens: chunk.usage.completion_tokens,
100
102
  };
101
103
  }
102
104
  }
103
105
  const result = {
104
106
  usage,
107
+ model,
105
108
  };
106
109
  if (input.responseFormat?.type === "json_schema" && text) {
107
110
  result.json = parseJSON(text);
@@ -7,7 +7,7 @@ import type { ChatModel, ChatModelInput } from "../models/chat-model.js";
7
7
  import { ChatMessagesTemplate } from "./template.js";
8
8
  export declare const MESSAGE_KEY = "$message";
9
9
  export declare const DEFAULT_MAX_HISTORY_MESSAGES = 10;
10
- export declare function createMessage(message: string | object): Message;
10
+ export declare function createMessage<I extends Message>(message: string | I): I;
11
11
  export declare function getMessage(input: Message): string | undefined;
12
12
  export interface PromptBuilderOptions {
13
13
  instructions?: string | ChatMessagesTemplate;
@@ -7,7 +7,9 @@ import { AgentMessageTemplate, ChatMessagesTemplate, SystemMessageTemplate, User
7
7
  export const MESSAGE_KEY = "$message";
8
8
  export const DEFAULT_MAX_HISTORY_MESSAGES = 10;
9
9
  export function createMessage(message) {
10
- return { [MESSAGE_KEY]: message };
10
+ return typeof message === "string"
11
+ ? { [MESSAGE_KEY]: message }
12
+ : { ...message };
11
13
  }
12
14
  export function getMessage(input) {
13
15
  const userInputMessage = input[MESSAGE_KEY];
@@ -23,8 +23,8 @@ export function parseJSON(json) {
23
23
  return JSON.parse(json);
24
24
  }
25
25
  catch (error) {
26
- logger.debug("Failed to parse JSON", { json, error });
27
- throw new Error(`Failed to parse JSON ${error.message}`);
26
+ logger.core("Failed to parse JSON", { json, error });
27
+ throw error;
28
28
  }
29
29
  }
30
30
  /**
@@ -1,20 +1,8 @@
1
- import debug, { type Debugger } from "debug";
2
- import type { Ora } from "ora";
3
- interface DebugWithSpinner extends Debugger {
4
- spinner<T>(promise: Promise<T>, message?: string, callback?: (result: T) => void, options?: {
5
- disabled?: boolean;
6
- }): Promise<T>;
7
- extend: (namespace: string) => DebugWithSpinner;
8
- }
9
- declare function spinner<T>(promise: Promise<T>, message?: string, callback?: (result: T) => void): Promise<T>;
1
+ import debug from "debug";
10
2
  export declare const logger: debug.Debug & {
11
3
  debug: debug.Debug;
12
4
  default: debug.Debug;
13
5
  } & {
14
- globalSpinner: Ora | undefined;
15
- base: DebugWithSpinner;
16
- debug: DebugWithSpinner;
17
- spinner: typeof spinner;
18
- setSpinner: (spinner: Ora) => void;
6
+ core: debug.Debugger;
7
+ mcp: debug.Debugger;
19
8
  };
20
- export {};
@@ -1,80 +1,6 @@
1
1
  import debug from "debug";
2
- debug.log = (...args) => {
3
- const { isSpinning } = globalSpinner ?? {};
4
- if (isSpinning)
5
- globalSpinner?.stop();
6
- console.log(...args);
7
- if (isSpinning)
8
- globalSpinner?.start();
9
- };
10
- function createDebugger(namespace) {
11
- const i = debug(namespace);
12
- function overrideExtend(debug) {
13
- const originalExtend = debug.extend;
14
- debug.extend = (namespace) => {
15
- const extended = originalExtend.call(debug, namespace);
16
- overrideExtend(extended);
17
- extended.spinner = async (promise, message, callback, options) => {
18
- if (!extended.enabled || options?.disabled)
19
- return promise;
20
- return spinner(promise, message, callback);
21
- };
22
- return extended;
23
- };
24
- }
25
- overrideExtend(i);
26
- return i;
27
- }
28
- let globalSpinner;
29
- const globalSpinnerTasks = [];
30
- async function spinner(promise, message, callback) {
31
- const task = { promise, message, callback };
32
- globalSpinnerTasks.push(task);
33
- globalSpinner?.start(message || " ");
34
- await promise
35
- .then((result) => {
36
- task.result = result;
37
- task.status = "succeed";
38
- })
39
- .catch(() => {
40
- task.status = "fail";
41
- });
42
- // Once the promise resolves or rejects, it updates the spinner status and processes
43
- // all completed tasks in a Last-In-First-Out (LIFO) order.
44
- for (;;) {
45
- const task = globalSpinnerTasks.at(-1);
46
- if (!task)
47
- break;
48
- // Recover spinner state for last running task
49
- if (!task.status) {
50
- globalSpinner?.start(task.message || " ");
51
- break;
52
- }
53
- globalSpinnerTasks.pop();
54
- if (task.message) {
55
- if (task.status === "fail")
56
- globalSpinner?.fail(task.message);
57
- else
58
- globalSpinner?.succeed(task.message);
59
- }
60
- else {
61
- globalSpinner?.stop();
62
- }
63
- // NOTE: This is a workaround to make sure the spinner stops spinning before the next tick
64
- await new Promise((resolve) => setTimeout(resolve, 10));
65
- if (task.status === "succeed")
66
- task.callback?.(task.result);
67
- }
68
- return promise;
69
- }
70
- const base = createDebugger("aigne");
2
+ const base = debug("aigne");
71
3
  export const logger = Object.assign(debug, {
72
- globalSpinner,
73
- base,
74
- debug: base.extend("core"),
75
- spinner,
76
- setSpinner: (spinner) => {
77
- globalSpinner = spinner;
78
- logger.globalSpinner = spinner;
79
- },
4
+ core: base.extend("core"),
5
+ mcp: base.extend("mcp"),
80
6
  });
@@ -28,11 +28,7 @@ export function promptFromMCPPrompt(prompt, options) {
28
28
  }
29
29
  export function resourceFromMCPResource(resource, options) {
30
30
  const [uri, variables] = isResourceTemplate(resource)
31
- ? [
32
- resource.uriTemplate,
33
- // TODO: use template.variableNames when it's available https://github.com/modelcontextprotocol/typescript-sdk/pull/188
34
- new UriTemplate(resource.uriTemplate).parts.flatMap((i) => (typeof i === "object" ? i.names : [])),
35
- ]
31
+ ? [resource.uriTemplate, new UriTemplate(resource.uriTemplate).variableNames]
36
32
  : [resource.uri, []];
37
33
  return new MCPResource({
38
34
  ...options,
@@ -1,6 +1,6 @@
1
1
  export function mergeUsage(...usages) {
2
2
  return {
3
- promptTokens: usages.reduce((acc, usage) => (usage ? acc + usage.promptTokens : acc), 0),
4
- completionTokens: usages.reduce((acc, usage) => (usage ? acc + usage.completionTokens : acc), 0),
3
+ inputTokens: usages.reduce((acc, usage) => (usage ? acc + usage.inputTokens : acc), 0),
4
+ outputTokens: usages.reduce((acc, usage) => (usage ? acc + usage.outputTokens : acc), 0),
5
5
  };
6
6
  }
@@ -1,6 +1,7 @@
1
1
  import { type ZodType } from "zod";
2
2
  export type PromiseOrValue<T> = T | Promise<T>;
3
3
  export type Nullish<T> = T | null | undefined;
4
+ export type OmitPropertiesFromArrayFirstElement<T extends unknown[], K extends string | number | symbol> = T extends [infer U, ...infer Rest] ? [Omit<U, K>, ...Rest] : never;
4
5
  export declare function isNil(value: unknown): value is null | undefined;
5
6
  export declare function isEmpty(obj: unknown): boolean;
6
7
  export declare function isNonNullable<T>(value: T): value is NonNullable<T>;
@@ -0,0 +1,10 @@
1
+ type EventMap<T> = Record<keyof T, unknown[]>;
2
+ export type Args<K, T> = K extends keyof T ? T[K] : never;
3
+ export type Listener<K, T> = K extends keyof T ? T[K] extends unknown[] ? (...args: T[K]) => void : never : never;
4
+ export interface TypedEventEmitter<T extends EventMap<T>, E extends EventMap<E> = T> {
5
+ emit<K extends keyof E>(eventName: K, ...args: Args<K, E>): boolean;
6
+ on<K extends keyof T>(eventName: K, listener: Listener<K, T>): this;
7
+ once<K extends keyof T>(eventName: K, listener: Listener<K, T>): this;
8
+ off<K extends keyof T>(eventName: K, listener: Listener<K, T>): this;
9
+ }
10
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/core",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "AIGNE core library for building AI-powered applications",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -60,14 +60,14 @@
60
60
  },
61
61
  "dependencies": {
62
62
  "@aigne/json-schema-to-zod": "^1.3.3",
63
- "@modelcontextprotocol/sdk": "^1.8.0",
63
+ "@modelcontextprotocol/sdk": "^1.9.0",
64
64
  "@types/debug": "^4.1.12",
65
65
  "debug": "^4.4.0",
66
- "inquirer": "^12.5.0",
66
+ "inquirer": "^12.5.2",
67
67
  "mustache": "^4.2.0",
68
68
  "nanoid": "^5.1.5",
69
- "ora": "^8.2.0",
70
69
  "p-retry": "^6.2.1",
70
+ "uuid": "^11.1.0",
71
71
  "yaml": "^2.7.1",
72
72
  "zod": "^3.24.2",
73
73
  "zod-to-json-schema": "^3.24.5"
@@ -80,17 +80,16 @@
80
80
  "devDependencies": {
81
81
  "@anthropic-ai/sdk": "^0.39.0",
82
82
  "@google/generative-ai": "^0.24.0",
83
- "@types/bun": "^1.2.8",
83
+ "@types/bun": "^1.2.9",
84
84
  "@types/express": "^5.0.1",
85
85
  "@types/mustache": "^4.2.5",
86
86
  "@types/node": "^22.14.0",
87
87
  "detect-port": "^2.1.0",
88
88
  "express": "^5.1.0",
89
89
  "npm-run-all": "^4.1.5",
90
- "openai": "^4.91.1",
90
+ "openai": "^4.93.0",
91
91
  "rimraf": "^6.0.1",
92
- "typescript": "^5.8.2",
93
- "@aigne/test-utils": "^1.0.0"
92
+ "typescript": "^5.8.3"
94
93
  },
95
94
  "scripts": {
96
95
  "lint": "tsc --noEmit",
@@ -1,11 +0,0 @@
1
- import type { Message } from "../agents/agent.js";
2
- import type { UserAgent } from "../agents/user-agent.js";
3
- export interface ChatLoopOptions {
4
- log?: typeof console.log;
5
- initialCall?: Message | string;
6
- welcome?: string;
7
- defaultQuestion?: string;
8
- onResponse?: (response: Message) => void;
9
- inputKey?: string;
10
- }
11
- export declare function runChatLoopInTerminal(userAgent: UserAgent, { log, ...options }?: ChatLoopOptions): Promise<void>;
@@ -1,82 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.runChatLoopInTerminal = runChatLoopInTerminal;
7
- const inquirer_1 = __importDefault(require("inquirer"));
8
- const ora_1 = __importDefault(require("ora"));
9
- const logger_js_1 = require("./logger.js");
10
- async function runChatLoopInTerminal(userAgent, { log = console.log.bind(console), ...options } = {}) {
11
- logger_js_1.logger.setSpinner((0, ora_1.default)());
12
- let isLoopExited = false;
13
- let prompt;
14
- if (options?.welcome)
15
- log(options.welcome);
16
- if (options?.initialCall) {
17
- await callAgent(userAgent, options.initialCall, { ...options, log });
18
- }
19
- (async () => {
20
- for await (const output of userAgent.stream) {
21
- if (isLoopExited)
22
- return;
23
- if (options?.onResponse)
24
- options.onResponse(output.message);
25
- else
26
- log(output);
27
- prompt?.ui.close();
28
- }
29
- })();
30
- for (let i = 0;; i++) {
31
- prompt = inquirer_1.default.prompt([
32
- {
33
- type: "input",
34
- name: "question",
35
- message: "💬",
36
- default: i === 0 ? options?.defaultQuestion : undefined,
37
- },
38
- ]);
39
- let question;
40
- try {
41
- question = (await prompt).question;
42
- }
43
- catch {
44
- // ignore abort error from inquirer
45
- }
46
- if (!question?.trim())
47
- continue;
48
- const cmd = COMMANDS[question.trim()];
49
- if (cmd) {
50
- const result = cmd();
51
- if (result.message)
52
- log(result.message);
53
- if (result?.exit)
54
- break;
55
- continue;
56
- }
57
- await callAgent(userAgent, question, { ...options, log });
58
- }
59
- isLoopExited = true;
60
- }
61
- async function callAgent(agent, input, options) {
62
- try {
63
- const response = await logger_js_1.logger.spinner(agent.call(options.inputKey && typeof input === "string" ? { [options.inputKey]: input } : input), "🤖");
64
- if (options?.onResponse)
65
- options.onResponse(response);
66
- else
67
- options.log(response);
68
- }
69
- catch (error) {
70
- options.log(`ERROR: ${error.message}`);
71
- }
72
- }
73
- const COMMANDS = {
74
- "/exit": () => ({ exit: true }),
75
- "/help": () => ({
76
- message: `\
77
- Commands:
78
- /exit - exit the chat loop
79
- /help - show this help message
80
- `,
81
- }),
82
- };
@@ -1,11 +0,0 @@
1
- import type { Message } from "../agents/agent.js";
2
- import type { UserAgent } from "../agents/user-agent.js";
3
- export interface ChatLoopOptions {
4
- log?: typeof console.log;
5
- initialCall?: Message | string;
6
- welcome?: string;
7
- defaultQuestion?: string;
8
- onResponse?: (response: Message) => void;
9
- inputKey?: string;
10
- }
11
- export declare function runChatLoopInTerminal(userAgent: UserAgent, { log, ...options }?: ChatLoopOptions): Promise<void>;
@@ -1,11 +0,0 @@
1
- import type { Message } from "../agents/agent.js";
2
- import type { UserAgent } from "../agents/user-agent.js";
3
- export interface ChatLoopOptions {
4
- log?: typeof console.log;
5
- initialCall?: Message | string;
6
- welcome?: string;
7
- defaultQuestion?: string;
8
- onResponse?: (response: Message) => void;
9
- inputKey?: string;
10
- }
11
- export declare function runChatLoopInTerminal(userAgent: UserAgent, { log, ...options }?: ChatLoopOptions): Promise<void>;
@@ -1,76 +0,0 @@
1
- import inquirer from "inquirer";
2
- import ora from "ora";
3
- import { logger } from "./logger.js";
4
- export async function runChatLoopInTerminal(userAgent, { log = console.log.bind(console), ...options } = {}) {
5
- logger.setSpinner(ora());
6
- let isLoopExited = false;
7
- let prompt;
8
- if (options?.welcome)
9
- log(options.welcome);
10
- if (options?.initialCall) {
11
- await callAgent(userAgent, options.initialCall, { ...options, log });
12
- }
13
- (async () => {
14
- for await (const output of userAgent.stream) {
15
- if (isLoopExited)
16
- return;
17
- if (options?.onResponse)
18
- options.onResponse(output.message);
19
- else
20
- log(output);
21
- prompt?.ui.close();
22
- }
23
- })();
24
- for (let i = 0;; i++) {
25
- prompt = inquirer.prompt([
26
- {
27
- type: "input",
28
- name: "question",
29
- message: "💬",
30
- default: i === 0 ? options?.defaultQuestion : undefined,
31
- },
32
- ]);
33
- let question;
34
- try {
35
- question = (await prompt).question;
36
- }
37
- catch {
38
- // ignore abort error from inquirer
39
- }
40
- if (!question?.trim())
41
- continue;
42
- const cmd = COMMANDS[question.trim()];
43
- if (cmd) {
44
- const result = cmd();
45
- if (result.message)
46
- log(result.message);
47
- if (result?.exit)
48
- break;
49
- continue;
50
- }
51
- await callAgent(userAgent, question, { ...options, log });
52
- }
53
- isLoopExited = true;
54
- }
55
- async function callAgent(agent, input, options) {
56
- try {
57
- const response = await logger.spinner(agent.call(options.inputKey && typeof input === "string" ? { [options.inputKey]: input } : input), "🤖");
58
- if (options?.onResponse)
59
- options.onResponse(response);
60
- else
61
- options.log(response);
62
- }
63
- catch (error) {
64
- options.log(`ERROR: ${error.message}`);
65
- }
66
- }
67
- const COMMANDS = {
68
- "/exit": () => ({ exit: true }),
69
- "/help": () => ({
70
- message: `\
71
- Commands:
72
- /exit - exit the chat loop
73
- /help - show this help message
74
- `,
75
- }),
76
- };