@nickyzj2023/ai 1.1.2 → 1.2.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/README.md +7 -2
- package/dist/cli.mjs +140 -36
- package/dist/index.d.mts +16 -4
- package/dist/index.mjs +1 -1
- package/dist/{src-DzLCCWBV.mjs → src-BJFCp7ur.mjs} +60 -35
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -46,10 +46,15 @@ for await (const e of runAgent(model, messages, tools)) {
|
|
|
46
46
|
### 在终端里使用
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
#
|
|
50
|
-
|
|
49
|
+
# 首次使用:交互式配置BASE_URL / APIKEY / MODEL / ...
|
|
50
|
+
ai setup
|
|
51
|
+
|
|
52
|
+
# 启动对话
|
|
53
|
+
ai
|
|
51
54
|
```
|
|
52
55
|
|
|
56
|
+
配置保存在 `~/.@nickyzj2023/ai/config.json`,任意目录下执行`ai`都能读取到
|
|
57
|
+
|
|
53
58
|
## License
|
|
54
59
|
|
|
55
60
|
ISC
|
package/dist/cli.mjs
CHANGED
|
@@ -1,7 +1,83 @@
|
|
|
1
|
-
import { i as defineModel, n as get_weather_default, o as runAgent, r as get_time_default } from "./src-
|
|
2
|
-
import {
|
|
3
|
-
import { loadEnvFile } from "node:process";
|
|
1
|
+
import { i as defineModel, n as get_weather_default, o as runAgent, r as get_time_default } from "./src-BJFCp7ur.mjs";
|
|
2
|
+
import { extractErrorMessage } from "@nickyzj2023/utils";
|
|
4
3
|
import readline from "node:readline";
|
|
4
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
//#region src/utils/config.ts
|
|
8
|
+
/**
|
|
9
|
+
* 获取全局配置文件路径(Windows/macOS/Linux通用)
|
|
10
|
+
* @returns (Windows下)C:/Users/Administrator/.@nickyzj2023/ai/config.json
|
|
11
|
+
*/
|
|
12
|
+
const getConfigPath = () => {
|
|
13
|
+
return join(homedir(), ".@nickyzj2023", "ai", "config.json");
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* 读取配置文件
|
|
17
|
+
* @returns 正常返回Config,配置不存在或损坏时返回null
|
|
18
|
+
*/
|
|
19
|
+
const loadConfig = () => {
|
|
20
|
+
try {
|
|
21
|
+
const config = JSON.parse(readFileSync(getConfigPath(), "utf8"));
|
|
22
|
+
if (typeof config.baseUrl !== "string" || typeof config.apiKey !== "string" || typeof config.model !== "string") return null;
|
|
23
|
+
return config;
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* 将配置写回全局文件(自动创建目录)
|
|
30
|
+
* @remarks 写入失败会抛异常
|
|
31
|
+
*/
|
|
32
|
+
const saveConfig = (config) => {
|
|
33
|
+
const configPath = getConfigPath();
|
|
34
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
35
|
+
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
|
36
|
+
};
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/interfaces/setup.ts
|
|
39
|
+
/**
|
|
40
|
+
* 临时创建readline接口,问答结束就关闭
|
|
41
|
+
* @param question 提问
|
|
42
|
+
* @returns 用户输入的回答
|
|
43
|
+
*/
|
|
44
|
+
const ask = (question) => {
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
const rl = readline.createInterface({
|
|
47
|
+
input: process.stdin,
|
|
48
|
+
output: process.stdout
|
|
49
|
+
});
|
|
50
|
+
rl.question(question, (answer) => {
|
|
51
|
+
rl.close();
|
|
52
|
+
resolve(answer);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* setup入口:依次询问BASE_URL / MODEL / APIKEY,确认后写入全局配置
|
|
58
|
+
*/
|
|
59
|
+
async function runSetup() {
|
|
60
|
+
const config = loadConfig();
|
|
61
|
+
if (config) {
|
|
62
|
+
console.log(`当前配置:BASE_URL ${config.baseUrl},APIKEY ${config.apiKey},MODEL ${config.model}`);
|
|
63
|
+
console.log("直接回车可沿用当前值。\n");
|
|
64
|
+
}
|
|
65
|
+
const baseUrl = await ask(`BASE_URL [当前为${config?.baseUrl}]: `) || config?.baseUrl;
|
|
66
|
+
const apiKey = await ask(`APIKEY [当前为${config?.apiKey}]: `) || config?.apiKey;
|
|
67
|
+
const model = await ask(`MODEL [当前为${config?.model}]: `) || config?.model;
|
|
68
|
+
try {
|
|
69
|
+
saveConfig({
|
|
70
|
+
baseUrl,
|
|
71
|
+
apiKey,
|
|
72
|
+
model
|
|
73
|
+
});
|
|
74
|
+
console.log(`配置已保存到${getConfigPath()},直接运行ai即可开始对话`);
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.error(`保存配置失败:${extractErrorMessage(e)}`);
|
|
77
|
+
process.exitCode = 1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
5
81
|
//#region src/interfaces/tui.ts
|
|
6
82
|
var TUI = class {
|
|
7
83
|
rl = null;
|
|
@@ -94,39 +170,67 @@ var TUI = class {
|
|
|
94
170
|
};
|
|
95
171
|
//#endregion
|
|
96
172
|
//#region src/cli.ts
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (!model.apiKey) {
|
|
104
|
-
console.error("请先在环境变量或.env文件中填入APIKEY(目前仅支持DeepSeek)");
|
|
105
|
-
process.exit(1);
|
|
106
|
-
}
|
|
107
|
-
const messages = [];
|
|
108
|
-
const tools = [get_weather_default, get_time_default];
|
|
109
|
-
const tui = new TUI(async (input) => {
|
|
110
|
-
messages.push({
|
|
111
|
-
role: "user",
|
|
112
|
-
content: input
|
|
113
|
-
});
|
|
114
|
-
for await (const e of runAgent(model, messages, tools)) switch (e.type) {
|
|
115
|
-
case "reasoning_delta":
|
|
116
|
-
tui.printReasoning(e.delta);
|
|
117
|
-
break;
|
|
118
|
-
case "content_delta":
|
|
119
|
-
tui.printContent(e.delta);
|
|
120
|
-
break;
|
|
121
|
-
case "tool_call":
|
|
122
|
-
tui.printToolCall(e.name, e.args);
|
|
123
|
-
break;
|
|
124
|
-
case "tool_result":
|
|
125
|
-
tui.printToolResult(e.name, e.result);
|
|
126
|
-
break;
|
|
127
|
-
case "done": tui.printFinish(e.finishReason, e.usage);
|
|
173
|
+
/** 启动交互对话:配置来自全局配置文件,环境变量可临时覆盖 */
|
|
174
|
+
const startChat = () => {
|
|
175
|
+
const config = loadConfig();
|
|
176
|
+
if (!config) {
|
|
177
|
+
console.error("请先运行 `ai setup` 配置一个模型");
|
|
178
|
+
process.exit(1);
|
|
128
179
|
}
|
|
129
|
-
|
|
130
|
-
|
|
180
|
+
const model = defineModel(config);
|
|
181
|
+
const messages = [];
|
|
182
|
+
const tools = [get_weather_default, get_time_default];
|
|
183
|
+
const tui = new TUI(async (input) => {
|
|
184
|
+
messages.push({
|
|
185
|
+
role: "user",
|
|
186
|
+
content: input
|
|
187
|
+
});
|
|
188
|
+
for await (const e of runAgent(model, messages, tools)) switch (e.type) {
|
|
189
|
+
case "reasoning_delta":
|
|
190
|
+
tui.printReasoning(e.delta);
|
|
191
|
+
break;
|
|
192
|
+
case "content_delta":
|
|
193
|
+
tui.printContent(e.delta);
|
|
194
|
+
break;
|
|
195
|
+
case "tool_call":
|
|
196
|
+
tui.printToolCall(e.name, e.args);
|
|
197
|
+
break;
|
|
198
|
+
case "tool_result":
|
|
199
|
+
tui.printToolResult(e.name, e.result);
|
|
200
|
+
break;
|
|
201
|
+
case "error":
|
|
202
|
+
tui.printContent(e.message);
|
|
203
|
+
break;
|
|
204
|
+
case "done": tui.printFinish(e.finishReason, e.usage);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
tui.start();
|
|
208
|
+
};
|
|
209
|
+
/** 打印命令用法 */
|
|
210
|
+
const printHelp = () => {
|
|
211
|
+
console.log(`用法: ai [命令]
|
|
212
|
+
|
|
213
|
+
命令:
|
|
214
|
+
--help 显示帮助
|
|
215
|
+
setup 交互式配置模型APIKEY / BASE_URL / MODEL(保存到 ~/.@nickyzj2023/ai/config.json)
|
|
216
|
+
|
|
217
|
+
不带命令则启动对话`);
|
|
218
|
+
};
|
|
219
|
+
const command = process.argv[2];
|
|
220
|
+
switch (command) {
|
|
221
|
+
case void 0:
|
|
222
|
+
startChat();
|
|
223
|
+
break;
|
|
224
|
+
case "setup":
|
|
225
|
+
await runSetup();
|
|
226
|
+
break;
|
|
227
|
+
case "--help":
|
|
228
|
+
case "-h":
|
|
229
|
+
printHelp();
|
|
230
|
+
break;
|
|
231
|
+
default:
|
|
232
|
+
console.error(`未知命令:${command}(可以运行ai --help查看用法)`);
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
131
235
|
//#endregion
|
|
132
236
|
export {};
|
package/dist/index.d.mts
CHANGED
|
@@ -150,8 +150,8 @@ declare const _default$1: ToolDefinition;
|
|
|
150
150
|
//#endregion
|
|
151
151
|
//#region src/utils/compact/types.d.ts
|
|
152
152
|
declare namespace Compact {
|
|
153
|
-
type ReplacerOfToolResultContent = (content: Message["content"]) => Message["content"];
|
|
154
|
-
type ReplacerOfMediaContent = (content: Message["content"]) => Message["content"];
|
|
153
|
+
type ReplacerOfToolResultContent = (content: Message["content"], options?: Record<string, any>) => Promise<Message["content"]> | Message["content"];
|
|
154
|
+
type ReplacerOfMediaContent = (content: Message["content"], options?: Record<string, any>) => Promise<Message["content"]> | Message["content"];
|
|
155
155
|
type SummarizeOptions = {
|
|
156
156
|
/** 用什么模型总结 */
|
|
157
157
|
model: Model;
|
|
@@ -180,8 +180,16 @@ declare namespace Compact {
|
|
|
180
180
|
}
|
|
181
181
|
//#endregion
|
|
182
182
|
//#region src/utils/compact/strategy.d.ts
|
|
183
|
-
declare const softDeleteToolResults: (messages: Message[],
|
|
184
|
-
|
|
183
|
+
declare const softDeleteToolResults: (messages: Message[], options: {
|
|
184
|
+
replacer?: Compact.ReplacerOfToolResultContent;
|
|
185
|
+
mark: string;
|
|
186
|
+
model?: Model;
|
|
187
|
+
}) => Promise<Message[]>;
|
|
188
|
+
declare const softDeleteOldMediaMessages: (messages: Message[], options: {
|
|
189
|
+
replacer?: Compact.ReplacerOfMediaContent;
|
|
190
|
+
mark: string;
|
|
191
|
+
model?: Model;
|
|
192
|
+
}) => Promise<Message[]>;
|
|
185
193
|
/**
|
|
186
194
|
* 清理软删除后残留的占位消息(信息在软删除时已丢失,此时删除不损失任何额外信息)
|
|
187
195
|
* @param messages 可压缩区消息数组,直接原地删除
|
|
@@ -229,6 +237,10 @@ declare const compact: ((messages: Message[], model: Model, options?: {
|
|
|
229
237
|
* @default (content) => "(已被丢弃)"
|
|
230
238
|
*/
|
|
231
239
|
replacerOfMediaContent?: Compact.ReplacerOfMediaContent;
|
|
240
|
+
/**
|
|
241
|
+
* 用于标记哪些消息被软删除了
|
|
242
|
+
*/
|
|
243
|
+
softDeletedMessageMark?: string;
|
|
232
244
|
/**
|
|
233
245
|
* 上下文>总上下文*ratio时清理软删除残留的占位消息
|
|
234
246
|
* @default 0.7
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as defineTool, i as defineModel, n as get_weather_default, o as runAgent, r as get_time_default, t as compact } from "./src-
|
|
1
|
+
import { a as defineTool, i as defineModel, n as get_weather_default, o as runAgent, r as get_time_default, t as compact } from "./src-BJFCp7ur.mjs";
|
|
2
2
|
export { compact, defineModel, defineTool, get_time_default as getTime, get_weather_default as getWeather, runAgent };
|
|
@@ -130,7 +130,7 @@ async function* runAgent(model, messages, tools) {
|
|
|
130
130
|
if (!tool) result = `不存在工具“${name}”`;
|
|
131
131
|
else {
|
|
132
132
|
const [error, response] = await to(tool.execute(JSON.parse(args)));
|
|
133
|
-
result = error ? `工具“${name}”执行出错:${error.message}` :
|
|
133
|
+
result = error ? `工具“${name}”执行出错:${error.message}` : JSON.stringify(response);
|
|
134
134
|
}
|
|
135
135
|
messages.push({
|
|
136
136
|
role: "tool",
|
|
@@ -212,27 +212,12 @@ const estimateTokens = (messages) => {
|
|
|
212
212
|
};
|
|
213
213
|
//#endregion
|
|
214
214
|
//#region src/tools/get-time.ts
|
|
215
|
-
const weekdayNames = {
|
|
216
|
-
Sunday: "星期日",
|
|
217
|
-
Monday: "星期一",
|
|
218
|
-
Tuesday: "星期二",
|
|
219
|
-
Wednesday: "星期三",
|
|
220
|
-
Thursday: "星期四",
|
|
221
|
-
Friday: "星期五",
|
|
222
|
-
Saturday: "星期六"
|
|
223
|
-
};
|
|
224
215
|
var get_time_default = defineTool("get_time", "查询指定时区的当前时间", { timezone: {
|
|
225
216
|
type: "string",
|
|
226
217
|
description: "完整的IANA时区名称,如Europe/Amsterdam。用户未明确提及时,传入对方语言对应的时区,例如对方使用中文时可传入Asia/Shanghai。",
|
|
227
218
|
required: true
|
|
228
219
|
} }, async ({ timezone }) => {
|
|
229
|
-
|
|
230
|
-
const pad = (n) => String(n).padStart(2, "0");
|
|
231
|
-
return [
|
|
232
|
-
`时区:${data.timeZone}${data.dstActive ? "(夏令时已生效)" : ""}`,
|
|
233
|
-
`日期:${data.year}-${pad(data.month)}-${pad(data.day)}(${weekdayNames[data.dayOfWeek] ?? data.dayOfWeek})`,
|
|
234
|
-
`时间:${pad(data.hour)}:${pad(data.minute)}:${pad(data.seconds)}`
|
|
235
|
-
].join("\n");
|
|
220
|
+
return fetcher("https://timeapi.io/api", { params: { timezone } }).get("/time/current/zone");
|
|
236
221
|
});
|
|
237
222
|
//#endregion
|
|
238
223
|
//#region src/tools/get-weather.ts
|
|
@@ -241,16 +226,7 @@ var get_weather_default = defineTool("get_weather", "查询指定城市的天气
|
|
|
241
226
|
description: "城市名,如shanghai、tokyo",
|
|
242
227
|
required: true
|
|
243
228
|
} }, async ({ city }) => {
|
|
244
|
-
|
|
245
|
-
const nearestArea = data.nearest_area[0];
|
|
246
|
-
const currentCondition = data.current_condition[0];
|
|
247
|
-
return [
|
|
248
|
-
`位置:${nearestArea.country[0].value}-${nearestArea.region[0].value}-${nearestArea.areaName[0].value}`,
|
|
249
|
-
`当前温度: ${currentCondition.temp_C}°C`,
|
|
250
|
-
`体感温度: ${currentCondition.FeelsLikeC}°C`,
|
|
251
|
-
`天气状况: ${currentCondition.weatherDesc[0].value}`,
|
|
252
|
-
`湿度: ${currentCondition.humidity}%`
|
|
253
|
-
].join("\n");
|
|
229
|
+
return fetcher("https://wttr.in", { params: { format: "j1" } }).get(`/${city}`);
|
|
254
230
|
});
|
|
255
231
|
//#endregion
|
|
256
232
|
//#region src/utils/compact/helper.ts
|
|
@@ -278,16 +254,52 @@ const findToolGroupRange = (messages, toolIndex) => {
|
|
|
278
254
|
};
|
|
279
255
|
//#endregion
|
|
280
256
|
//#region src/utils/compact/strategy.ts
|
|
281
|
-
|
|
257
|
+
/** 默认的软删除多模态消息策略:让大模型精简消息内容 */
|
|
258
|
+
const defaultReplacerOfToolResultContent = async (content, options) => {
|
|
259
|
+
const { mark, model } = options ?? {};
|
|
260
|
+
const messages = [{
|
|
261
|
+
role: "user",
|
|
262
|
+
content
|
|
263
|
+
}, {
|
|
264
|
+
role: "user",
|
|
265
|
+
content: "请用一两句话对上条消息做个“省流”"
|
|
266
|
+
}];
|
|
267
|
+
let simplifiedContent = mark;
|
|
268
|
+
for await (const e of runAgent(model, messages, [])) if (e.type === "content_delta") simplifiedContent += e.delta;
|
|
269
|
+
return simplifiedContent;
|
|
270
|
+
};
|
|
271
|
+
const softDeleteToolResults = async (messages, options) => {
|
|
272
|
+
const { replacer = defaultReplacerOfToolResultContent, mark, model } = options ?? {};
|
|
273
|
+
if (!replacer && !model) return [];
|
|
282
274
|
const softDeleted = [];
|
|
283
|
-
for (const message of messages) if (message?.role === "tool") {
|
|
284
|
-
|
|
275
|
+
for (const message of messages) if (message?.role === "tool" && typeof message.content === "string") {
|
|
276
|
+
if (message.content.startsWith(mark)) continue;
|
|
277
|
+
message.content = await replacer(message.content, {
|
|
278
|
+
mark,
|
|
279
|
+
model
|
|
280
|
+
});
|
|
285
281
|
softDeleted.push(message);
|
|
286
282
|
}
|
|
287
283
|
if (softDeleted.length > 0) logger(`软删除了${softDeleted.length}条工具调用结果消息`);
|
|
288
284
|
return softDeleted;
|
|
289
285
|
};
|
|
290
|
-
|
|
286
|
+
/** 默认的软删除多模态消息策略:让大模型精简消息内容 */
|
|
287
|
+
const defaultReplacerOfMediaContent = async (content, options) => {
|
|
288
|
+
const { mark, model } = options ?? {};
|
|
289
|
+
const messages = [{
|
|
290
|
+
role: "user",
|
|
291
|
+
content
|
|
292
|
+
}, {
|
|
293
|
+
role: "user",
|
|
294
|
+
content: "请用一两句话描述上方的多模态消息"
|
|
295
|
+
}];
|
|
296
|
+
let simplifiedContent = mark;
|
|
297
|
+
for await (const e of runAgent(model, messages, [])) if (e.type === "content_delta") simplifiedContent += e.delta;
|
|
298
|
+
return simplifiedContent;
|
|
299
|
+
};
|
|
300
|
+
const softDeleteOldMediaMessages = async (messages, options) => {
|
|
301
|
+
const { replacer = defaultReplacerOfMediaContent, mark, model } = options ?? {};
|
|
302
|
+
if (!replacer && !model) return [];
|
|
291
303
|
const mediaTypes = [
|
|
292
304
|
"image_url",
|
|
293
305
|
"input_audio",
|
|
@@ -295,7 +307,10 @@ const softDeleteOldMediaMessages = (messages, replacer) => {
|
|
|
295
307
|
];
|
|
296
308
|
const softDeleted = [];
|
|
297
309
|
for (const message of messages) if (message && Array.isArray(message.content) && message.content.some((part) => mediaTypes.includes(part.type))) {
|
|
298
|
-
message.content = replacer(message.content
|
|
310
|
+
message.content = await replacer(message.content, {
|
|
311
|
+
mark,
|
|
312
|
+
model
|
|
313
|
+
});
|
|
299
314
|
softDeleted.push(message);
|
|
300
315
|
}
|
|
301
316
|
if (softDeleted.length > 0) logger(`软删除了${softDeleted.length}条旧图片/音频/视频消息`);
|
|
@@ -393,7 +408,7 @@ const hardDeleteOldMessages = (messages) => {
|
|
|
393
408
|
* 自动优化上下文,类似AI Coding Agent的/compact命令
|
|
394
409
|
*/
|
|
395
410
|
const compact = Object.assign(async (messages, model, options) => {
|
|
396
|
-
const { usage, keepCount = 10, ratioToCompactToolResult = .5, replacerOfToolResultContent
|
|
411
|
+
const { usage, keepCount = 10, ratioToCompactToolResult = .5, replacerOfToolResultContent, ratioToCompactMedia = .6, replacerOfMediaContent, ratioToClearSoftDeletedMessages = .7, softDeletedMessageMark = "[已简化]", ratioToSummarize = .8, summarizeOptions } = options ?? {};
|
|
397
412
|
const context = model?.context ?? 131072;
|
|
398
413
|
const tokens = usage?.total_tokens ?? estimateTokens(messages);
|
|
399
414
|
const result = {
|
|
@@ -413,11 +428,21 @@ const compact = Object.assign(async (messages, model, options) => {
|
|
|
413
428
|
const reserved = messages.slice(endIndex);
|
|
414
429
|
const softDeleted = /* @__PURE__ */ new Set();
|
|
415
430
|
if (tokens > context * ratioToCompactToolResult) {
|
|
416
|
-
|
|
431
|
+
const softDeletedMessages = await softDeleteToolResults(compressible, {
|
|
432
|
+
replacer: replacerOfToolResultContent,
|
|
433
|
+
mark: softDeletedMessageMark,
|
|
434
|
+
model
|
|
435
|
+
});
|
|
436
|
+
for (const message of softDeletedMessages) softDeleted.add(message);
|
|
417
437
|
result.hasCompactedToolResult = true;
|
|
418
438
|
}
|
|
419
439
|
if (tokens > context * ratioToCompactMedia) {
|
|
420
|
-
|
|
440
|
+
const softDeletedMessages = await softDeleteOldMediaMessages(compressible, {
|
|
441
|
+
replacer: replacerOfMediaContent,
|
|
442
|
+
mark: softDeletedMessageMark,
|
|
443
|
+
model
|
|
444
|
+
});
|
|
445
|
+
for (const message of softDeletedMessages) softDeleted.add(message);
|
|
421
446
|
result.hasCompactedMedia = true;
|
|
422
447
|
}
|
|
423
448
|
if (tokens > context * ratioToClearSoftDeletedMessages) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nickyzj2023/ai",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "我的“pi”,参考了pi-from-scratch",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.mjs",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"access": "public"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@biomejs/biome": "^2.5.
|
|
30
|
-
"@types/node": "^26.4.
|
|
29
|
+
"@biomejs/biome": "^2.5.12",
|
|
30
|
+
"@types/node": "^26.4.1",
|
|
31
31
|
"tsdown": "^0.22.14",
|
|
32
32
|
"typescript": "^7.0.2"
|
|
33
33
|
},
|