@nickyzj2023/ai 1.6.0 → 1.6.1

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 CHANGED
@@ -71,6 +71,9 @@ ai setup
71
71
 
72
72
  # 启动对话
73
73
  ai
74
+
75
+ # 直接开聊,本质是“ai->输入提示词->回车”的语法糖
76
+ ai 你好
74
77
  ```
75
78
 
76
79
  配置保存在 `~/.@nickyzj2023/ai/config.json`,任意目录下执行`ai`都能读取到
package/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as runAgent, n as get_weather_default, r as get_time_default } from "./src-CKKPKPMG.mjs";
1
+ import { i as runAgent, n as get_weather_default, r as get_time_default } from "./src-BzQy5h8z.mjs";
2
2
  import { t as defineModel } from "./helper-juLVGxlQ.mjs";
3
3
  import { n as loadMCPTools } from "./mcp-DcntQg-a.mjs";
4
4
  import { compactStr, extractErrorMessage, isObject } from "@nickyzj2023/utils";
@@ -308,6 +308,8 @@ var TUI = class {
308
308
  md = null;
309
309
  /** 是否允许输入 */
310
310
  isBusy = false;
311
+ /** 是否正停在提示符上等输入(决定printNotice要不要重绘提示符) */
312
+ isPrompting = false;
311
313
  /** 上次打印内容所属的状态(reasoning/content/tool)
312
314
  * 用于在新的状态开始时改变样式、打印前缀
313
315
  */
@@ -319,19 +321,28 @@ var TUI = class {
319
321
  constructor(onPrompt) {
320
322
  this.onPrompt = onPrompt;
321
323
  }
322
- /** 启动TUI */
323
- start() {
324
+ /**
325
+ * 启动TUI
326
+ * @param initialPrompt 传入时先替用户发出这一轮(ai “提示词”的快捷方式),之后照常等输入
327
+ */
328
+ start(initialPrompt) {
324
329
  this.rl = readline.createInterface({
325
330
  input: process.stdin,
326
331
  output: process.stdout
327
332
  });
328
333
  process.stdin.on("keypress", this.onKeypress);
329
- this.prompting();
330
334
  this.rl.on("close", () => {
331
335
  process.stdin.off("keypress", this.onKeypress);
332
336
  this.rl?.close();
333
337
  this.rl = null;
334
338
  });
339
+ if (initialPrompt) {
340
+ process.stdout.write(`> ${initialPrompt}\n`);
341
+ this.submit({
342
+ text: initialPrompt,
343
+ images: []
344
+ });
345
+ } else this.prompting();
335
346
  }
336
347
  /** 监听用户的特定按键 */
337
348
  onKeypress = (_str, key) => {
@@ -341,7 +352,9 @@ var TUI = class {
341
352
  /** 监听用户输入 */
342
353
  prompting() {
343
354
  if (this.isBusy) return;
355
+ this.isPrompting = true;
344
356
  this.rl?.question("> ", async (answer) => {
357
+ this.isPrompting = false;
345
358
  await this.clipboardTask;
346
359
  const text = answer.trim();
347
360
  const images = this.pendingImages;
@@ -350,15 +363,22 @@ var TUI = class {
350
363
  this.prompting();
351
364
  return;
352
365
  }
353
- this.isBusy = true;
354
- await this.onPrompt?.({
366
+ await this.submit({
355
367
  text,
356
368
  images
357
369
  });
358
- this.isBusy = false;
359
- this.prompting();
360
370
  });
361
371
  }
372
+ /**
373
+ * 走完整的一轮:把输入交给调用方,结束后继续等用户输入
374
+ * @remarks 提示词来源可以是用户敲的,也可以是start()传进来的initialPrompt
375
+ */
376
+ async submit(input) {
377
+ this.isBusy = true;
378
+ await this.onPrompt?.(input);
379
+ this.isBusy = false;
380
+ this.prompting();
381
+ }
362
382
  /** 读取剪贴板图片,推入待发送列表 */
363
383
  async attachImage() {
364
384
  const image = await readClipboardImage();
@@ -401,6 +421,27 @@ var TUI = class {
401
421
  if (!process.stdout.isTTY) return text;
402
422
  return `\x1b[${ansiCode}m${text}\x1b[0m`;
403
423
  }
424
+ /** 把一个Agent事件分发到对应的print方法上 */
425
+ render(event) {
426
+ switch (event.type) {
427
+ case "reasoning_delta":
428
+ this.printReasoning(event.delta);
429
+ break;
430
+ case "content_delta":
431
+ this.printContent(event.delta);
432
+ break;
433
+ case "tool_call":
434
+ this.printToolCall(event.name, event.args);
435
+ break;
436
+ case "tool_result":
437
+ this.printToolResult(event.name, event.result);
438
+ break;
439
+ case "error":
440
+ this.printContent(event.message);
441
+ break;
442
+ case "done": this.printFinish(event.finishReason, event.usage);
443
+ }
444
+ }
404
445
  /** 流式打印AI思考内容(灰色) */
405
446
  printReasoning(delta) {
406
447
  if (this.preparePrint("reasoning_delta")) delta = `[思考内容] ${delta.replaceAll("\n", "")}`;
@@ -432,10 +473,10 @@ var TUI = class {
432
473
  this.preparePrint("done");
433
474
  process.stdout.write(this.colorize(`[本轮结束:${finishReason}] ${usage ? `输入${humanizeNumber(usage.prompt_tokens)},输出${humanizeNumber(usage.completion_tokens)},总共${humanizeNumber(usage.total_tokens)}` : ""}${usage?.speed ? `,速度${usage.speed}/秒` : ""}${finishReason === "stop" ? "\n\n" : "\n"}`, "90"));
434
475
  }
435
- /** 打印一行黄字提示,并重绘当前输入行 */
476
+ /** 打印一行黄字提示,正停在提示符上时顺便重绘输入行 */
436
477
  printNotice(message) {
437
478
  process.stdout.write(`${this.colorize(message, "93")}\n`);
438
- this.rl?.prompt(true);
479
+ if (this.isPrompting) this.rl?.prompt(true);
439
480
  }
440
481
  };
441
482
  //#endregion
@@ -454,8 +495,11 @@ const buildUserContent = (text, images) => {
454
495
  content.push(...images);
455
496
  return content;
456
497
  };
457
- /** 启动交互对话:配置来自全局配置文件,环境变量可临时覆盖 */
458
- const startChat = async () => {
498
+ /**
499
+ * 启动交互对话:配置来自全局配置文件,环境变量可临时覆盖
500
+ * @param prompt 带上提示词时,先自动发出这一轮,之后照常继续对话
501
+ */
502
+ const startChat = async (prompt) => {
459
503
  const config = loadConfig();
460
504
  if (!config) {
461
505
  console.error("请先运行 `ai setup` 配置一个模型");
@@ -483,38 +527,23 @@ const startChat = async () => {
483
527
  get_time_default,
484
528
  ...await mcpLoading
485
529
  ];
486
- for await (const e of runAgent(model, messages, tools)) switch (e.type) {
487
- case "reasoning_delta":
488
- tui.printReasoning(e.delta);
489
- break;
490
- case "content_delta":
491
- tui.printContent(e.delta);
492
- break;
493
- case "tool_call":
494
- tui.printToolCall(e.name, e.args);
495
- break;
496
- case "tool_result":
497
- tui.printToolResult(e.name, e.result);
498
- break;
499
- case "error":
500
- tui.printContent(e.message);
501
- break;
502
- case "done": tui.printFinish(e.finishReason, e.usage);
503
- }
530
+ for await (const e of runAgent(model, messages, tools)) tui.render(e);
504
531
  });
505
- tui.start();
532
+ tui.start(prompt);
506
533
  };
507
534
  /** 打印命令用法 */
508
535
  const printHelp = () => {
509
- console.log(`用法: ai [命令]
536
+ console.log(`用法: ai [命令/提示词]
510
537
 
511
538
  命令:
512
539
  --help 显示帮助
513
540
  setup 交互式配置模型APIKEY / BASE_URL / MODEL(保存到 ~/.@nickyzj2023/ai/config.json)
514
541
 
515
- 不带命令则启动对话`);
542
+ 带上提示词时,启动对话的同时先把这段提示词发出去(如\`ai 明天适合洗车吗\`)
543
+ 不带参数则直接进入对话`);
516
544
  };
517
- const command = process.argv[2];
545
+ const args = process.argv.slice(2);
546
+ const command = args[0];
518
547
  switch (command) {
519
548
  case void 0:
520
549
  startChat();
@@ -527,8 +556,11 @@ switch (command) {
527
556
  printHelp();
528
557
  break;
529
558
  default:
530
- console.error(`未知命令:${command}(可以运行ai --help查看用法)`);
531
- process.exit(1);
559
+ if (command.startsWith("-")) {
560
+ console.error(`未知命令:${command}(可以运行ai --help查看用法)`);
561
+ process.exit(1);
562
+ }
563
+ startChat(args.join(" ").trim() || void 0);
532
564
  }
533
565
  //#endregion
534
566
  export {};
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { a as stream, i as runAgent, n as get_weather_default, r as get_time_default, t as compact } from "./src-CKKPKPMG.mjs";
1
+ import { a as stream, i as runAgent, n as get_weather_default, r as get_time_default, t as compact } from "./src-BzQy5h8z.mjs";
2
2
  import { i as estimateTokens, n as defineTool, r as estimateTextTokens, t as defineModel } from "./helper-juLVGxlQ.mjs";
3
3
  export { compact, defineModel, defineTool, estimateTextTokens, estimateTokens, get_time_default as getTime, get_weather_default as getWeather, runAgent, stream };
@@ -308,7 +308,7 @@ const summarizeMessages = async (compressible, options) => {
308
308
  logger("消息太少,无需总结");
309
309
  return 0;
310
310
  }
311
- beforeSummarize?.(summarizable);
311
+ await beforeSummarize?.(summarizable);
312
312
  const count = summarizable.length;
313
313
  summarizable.push({
314
314
  role: "system",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nickyzj2023/ai",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "我的“pi”,参考了pi-from-scratch",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",