@nickyzj2023/ai 1.4.2 → 1.4.4
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/dist/cli.mjs +121 -3
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-izgP3Lfk.mjs → src-CuZ-6Jye.mjs} +3 -3
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as get_time_default, c as runAgent, i as get_weather_default, o as defineModel, r as loadMCPTools } from "./src-
|
|
2
|
-
import { compactStr, extractErrorMessage } from "@nickyzj2023/utils";
|
|
1
|
+
import { a as get_time_default, c as runAgent, i as get_weather_default, o as defineModel, r as loadMCPTools } from "./src-CuZ-6Jye.mjs";
|
|
2
|
+
import { compactStr, extractErrorMessage, isObject } from "@nickyzj2023/utils";
|
|
3
3
|
import readline from "node:readline";
|
|
4
4
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { homedir } from "node:os";
|
|
@@ -55,6 +55,121 @@ const ask = (question) => {
|
|
|
55
55
|
});
|
|
56
56
|
};
|
|
57
57
|
/**
|
|
58
|
+
* 询问一个可留空的字段:回车或输入空白时沿用默认值
|
|
59
|
+
* @param question 提问文案
|
|
60
|
+
* @param fallback 默认值
|
|
61
|
+
* @returns 用户输入,空白时返回默认值
|
|
62
|
+
*/
|
|
63
|
+
const askWithDefault = async (question, fallback) => {
|
|
64
|
+
return (await ask(question)).trim() || fallback;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* 交互式录入一个MCP服务器配置
|
|
68
|
+
* @param current 编辑时传入现有服务器,回车表示沿用原值;只传name表示配置缺失、重新录入
|
|
69
|
+
* @returns 录入完成的配置;名称/URL为空或类型非法时返回null
|
|
70
|
+
*/
|
|
71
|
+
const askMcpServer = async (current) => {
|
|
72
|
+
const name = await askWithDefault(`名称 [当前为${current?.name ?? "(新)"}]: `, current?.name);
|
|
73
|
+
if (!name) {
|
|
74
|
+
console.log("名称不能为空,已取消");
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const defaultType = current?.type ?? "streamable_http";
|
|
78
|
+
const typeInput = await askWithDefault(`类型 streamable_http/sse [当前为${defaultType}]: `, defaultType);
|
|
79
|
+
if (typeInput !== "streamable_http" && typeInput !== "sse") {
|
|
80
|
+
console.log("类型无效,已取消");
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const type = typeInput;
|
|
84
|
+
const url = await askWithDefault(`URL [当前为${current?.url ?? "无"}]: `, current?.url);
|
|
85
|
+
if (!url) {
|
|
86
|
+
console.log("URL不能为空,已取消");
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
let headers = current?.headers;
|
|
90
|
+
const headersInput = (await ask(`headers(JSON对象) [当前为${current?.headers ? JSON.stringify(current.headers) : "无"}]: `)).trim();
|
|
91
|
+
if (headersInput) try {
|
|
92
|
+
const parsed = JSON.parse(headersInput);
|
|
93
|
+
if (isObject(parsed)) headers = parsed;
|
|
94
|
+
else console.log("headers需为JSON对象,已回退到原先的值");
|
|
95
|
+
} catch {
|
|
96
|
+
console.log("headers解析失败,已回退到原先的值");
|
|
97
|
+
}
|
|
98
|
+
let ignoredToolNames = current?.ignoredToolNames;
|
|
99
|
+
const ignoredInput = (await ask(`忽略的工具名(逗号分隔) [当前为${current?.ignoredToolNames?.join(",") ?? "无"}]: `)).trim();
|
|
100
|
+
if (ignoredInput) ignoredToolNames = ignoredInput.split(",").map((item) => item.trim()).filter(Boolean);
|
|
101
|
+
return {
|
|
102
|
+
name,
|
|
103
|
+
type,
|
|
104
|
+
url,
|
|
105
|
+
...headers ? { headers } : {},
|
|
106
|
+
...ignoredToolNames?.length ? { ignoredToolNames } : {}
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* 把菜单输入的数字解析成对应的服务器名称
|
|
111
|
+
* @param input 用户输入的数字串
|
|
112
|
+
* @param names 当前菜单的服务器名称列表
|
|
113
|
+
* @returns 对应名称;非整数或越界返回undefined
|
|
114
|
+
*/
|
|
115
|
+
const pickServerName = (input, names) => {
|
|
116
|
+
const index = Number(input) - 1;
|
|
117
|
+
return Number.isInteger(index) ? names[index] : void 0;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* MCP配置菜单:列出现有服务器,数字键编辑、a键添加、d键删除、回车或q结束
|
|
121
|
+
*/
|
|
122
|
+
const configMcp = async (mcpServers) => {
|
|
123
|
+
while (true) {
|
|
124
|
+
const names = Object.keys(mcpServers);
|
|
125
|
+
console.log("\n当前MCP服务器:");
|
|
126
|
+
if (names.length === 0) console.log("(空)");
|
|
127
|
+
else names.forEach((name, i) => {
|
|
128
|
+
const server = mcpServers[name];
|
|
129
|
+
console.log(` ${i + 1}. ${name} ${server ? `(${server.type} ${server.url})` : "(配置缺失)"}`);
|
|
130
|
+
});
|
|
131
|
+
const choice = (await ask("输入数字编辑对应服务器,a添加新服务器,d删除服务器,回车或q结束: ")).trim().toLowerCase();
|
|
132
|
+
if (!choice || choice === "q") break;
|
|
133
|
+
switch (choice) {
|
|
134
|
+
case "a": {
|
|
135
|
+
const result = await askMcpServer();
|
|
136
|
+
if (result) mcpServers[result.name] = result;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
case "d": {
|
|
140
|
+
const target = (await ask("输入要删除的服务器编号: ")).trim();
|
|
141
|
+
const oldName = pickServerName(target, names);
|
|
142
|
+
if (!oldName) {
|
|
143
|
+
console.log("无效编号,请输入列表中的数字");
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
if ((await ask(`确认删除${oldName}?(y/n): `)).trim().toLowerCase() === "y") {
|
|
147
|
+
delete mcpServers[oldName];
|
|
148
|
+
console.log(`已删除${oldName}`);
|
|
149
|
+
} else console.log("已取消删除");
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
default: {
|
|
153
|
+
const oldName = pickServerName(choice, names);
|
|
154
|
+
if (oldName) {
|
|
155
|
+
const server = mcpServers[oldName];
|
|
156
|
+
if (!server) console.log("该服务器配置缺失,将重新录入");
|
|
157
|
+
const result = await askMcpServer({
|
|
158
|
+
name: oldName,
|
|
159
|
+
...server
|
|
160
|
+
});
|
|
161
|
+
if (result) {
|
|
162
|
+
if (result.name !== oldName) console.log(`已重命名 ${oldName} -> ${result.name}`);
|
|
163
|
+
delete mcpServers[oldName];
|
|
164
|
+
mcpServers[result.name] = result;
|
|
165
|
+
}
|
|
166
|
+
} else console.log("无效选择,请输入列表中的数字、a、d或回车");
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
58
173
|
* setup入口:依次询问BASE_URL / MODEL / APIKEY,确认后写入全局配置
|
|
59
174
|
*/
|
|
60
175
|
async function runSetup() {
|
|
@@ -66,11 +181,14 @@ async function runSetup() {
|
|
|
66
181
|
const baseUrl = await ask(`BASE_URL [当前为${config?.baseUrl}]: `) || config?.baseUrl;
|
|
67
182
|
const apiKey = await ask(`APIKEY [当前为${config?.apiKey}]: `) || config?.apiKey;
|
|
68
183
|
const model = await ask(`MODEL [当前为${config?.model}]: `) || config?.model;
|
|
184
|
+
const mcpServers = { ...config?.mcpServers };
|
|
185
|
+
if ((await ask("是否配置MCP服务器?(y/n): ")).trim().toLowerCase() === "y") await configMcp(mcpServers);
|
|
69
186
|
try {
|
|
70
187
|
saveConfig({
|
|
71
188
|
baseUrl,
|
|
72
189
|
apiKey,
|
|
73
|
-
model
|
|
190
|
+
model,
|
|
191
|
+
mcpServers
|
|
74
192
|
});
|
|
75
193
|
console.log(`配置已保存到${getConfigPath()},直接运行ai即可开始对话`);
|
|
76
194
|
} catch (e) {
|
package/dist/index.d.mts
CHANGED
|
@@ -199,7 +199,7 @@ declare class MCPRouter {
|
|
|
199
199
|
/**
|
|
200
200
|
* 把传入的MCPServer列表转换成OpenAI API兼容的tools数组
|
|
201
201
|
*/
|
|
202
|
-
declare const loadMCPTools: (mcpServers
|
|
202
|
+
declare const loadMCPTools: (mcpServers?: Record<string, McpServer>) => Promise<ToolDefinition[]>;
|
|
203
203
|
//#endregion
|
|
204
204
|
//#region src/utils/compact/types.d.ts
|
|
205
205
|
declare namespace Compact {
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as get_time_default, c as runAgent, i as get_weather_default, n as MCPRouter, o as defineModel, r as loadMCPTools, s as defineTool, t as compact } from "./src-
|
|
1
|
+
import { a as get_time_default, c as runAgent, i as get_weather_default, n as MCPRouter, o as defineModel, r as loadMCPTools, s as defineTool, t as compact } from "./src-CuZ-6Jye.mjs";
|
|
2
2
|
export { MCPRouter, compact, defineModel, defineTool, get_time_default as getTime, get_weather_default as getWeather, loadMCPTools, runAgent };
|
|
@@ -273,7 +273,7 @@ var MCPRouter = class {
|
|
|
273
273
|
/**
|
|
274
274
|
* 把传入的MCPServer列表转换成OpenAI API兼容的tools数组
|
|
275
275
|
*/
|
|
276
|
-
const loadMCPTools = async (mcpServers) => {
|
|
276
|
+
const loadMCPTools = async (mcpServers = {}) => {
|
|
277
277
|
router ||= new MCPRouter();
|
|
278
278
|
await Promise.allSettled(Object.entries(mcpServers).map(async ([name, server]) => {
|
|
279
279
|
try {
|
|
@@ -327,7 +327,7 @@ const defaultReplacerOfToolResultContent = async (content, options) => {
|
|
|
327
327
|
content
|
|
328
328
|
}, {
|
|
329
329
|
role: "user",
|
|
330
|
-
content: "
|
|
330
|
+
content: "请用一句话简述上面这条消息(直击要点,不要添加任何前言后语)"
|
|
331
331
|
}];
|
|
332
332
|
let simplifiedContent = "";
|
|
333
333
|
for await (const e of runAgent(model, messages, [])) if (e.type === "content_delta") simplifiedContent += e.delta;
|
|
@@ -358,7 +358,7 @@ const defaultReplacerOfMediaContent = async (content, options) => {
|
|
|
358
358
|
content
|
|
359
359
|
}, {
|
|
360
360
|
role: "user",
|
|
361
|
-
content: "
|
|
361
|
+
content: "请用一句话简述上面这条消息(直击要点,不要添加任何前言后语)"
|
|
362
362
|
}];
|
|
363
363
|
let simplifiedContent = "";
|
|
364
364
|
for await (const e of runAgent(model, messages, [])) if (e.type === "content_delta") simplifiedContent += e.delta;
|