@vicvic-im/agent-bot 0.1.4 → 0.1.5

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.
@@ -10,6 +10,13 @@ export interface VbotState {
10
10
  createdAt: string;
11
11
  lastUsedAt: string;
12
12
  usage: Usage;
13
+ /** 上次从 ACP 读到的模型;仅作重启后的展示缓存,权威值始终来自 agent。 */
14
+ model: CachedModel | null;
15
+ }
16
+ /** 模型缓存:只存展示需要的最小字段,不存 options 列表。 */
17
+ export interface CachedModel {
18
+ value: string;
19
+ label: string;
13
20
  }
14
21
  /** token 的 SHA-256 前 16 位:不落明文 token,且一个 token 稳定对应一个状态文件。 */
15
22
  export declare function tokenHash(token: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"AAWA,OAAO,EAAe,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE7E,0CAA0C;AAC1C,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,8DAA8D;AAC9D,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAWlF;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAwBzD;AAED,gCAAgC;AAChC,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAOhD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAS9C"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"AAWA,OAAO,EAAe,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE7E,0CAA0C;AAC1C,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,8CAA8C;IAC9C,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;CAC3B;AAED,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,8DAA8D;AAC9D,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAYlF;AAUD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAyBzD;AAED,gCAAgC;AAChC,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAOhD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAS9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../src/core/switch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,IAAI,YAAY,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,UAAU,IAAI,IAAI,CAAC;IACnB,SAAS,IAAI,IAAI,CAAC;IAClB,0BAA0B;IAC1B,WAAW,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,YAAY,CAAC;CAClE;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBtF"}
1
+ {"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../src/core/switch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,IAAI,YAAY,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,UAAU,IAAI,IAAI,CAAC;IACnB,SAAS,IAAI,IAAI,CAAC;IAClB,0BAA0B;IAC1B,WAAW,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,YAAY,CAAC;CAClE;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBtF"}
package/dist/index.cjs CHANGED
@@ -361,7 +361,7 @@ var acp = __toESM(require("@agentclientprotocol/sdk"), 1);
361
361
  var EMPTY_USAGE = { used: 0, size: 0, cost: null };
362
362
 
363
363
  // src/version.ts
364
- var VBOT_VERSION = "0.1.4";
364
+ var VBOT_VERSION = "0.1.5";
365
365
 
366
366
  // src/agents/acp.ts
367
367
  var AgentAbortError = class extends Error {
@@ -424,6 +424,11 @@ var AcpAgent = class {
424
424
  const label = options.find((entry) => entry.value === value)?.label ?? value;
425
425
  return { value, label, options };
426
426
  }
427
+ // 不跑 prompt 也能读模型:session/new|resume|load 的 configOptions 里带 model 项。
428
+ async warmup(savedSessionId) {
429
+ await this.start();
430
+ await this.ensureSession(savedSessionId);
431
+ }
427
432
  resetSession() {
428
433
  this.session = null;
429
434
  }
@@ -760,7 +765,7 @@ var HELP_ROWS = [
760
765
  ["/stop", "Abort the current request"],
761
766
  ["/status", "Show agent, session and queue status"],
762
767
  ["/agent [name]", "Show or switch agent backend"],
763
- ["/model [name]", "Show or switch model"],
768
+ ["/model [name]", "Show or switch model (/model list for all)"],
764
769
  ["/cost", "Show context usage and cost"],
765
770
  ["/version", "Show vbot version"],
766
771
  ["/help", "Show this help"]
@@ -768,6 +773,7 @@ var HELP_ROWS = [
768
773
  var HELP_FOOTER = "Other /commands are sent to the agent as prompts.";
769
774
  var NEW_BUSY_TEXT = "Cannot reset the session while a request is running. Use /stop first.";
770
775
  var MODEL_BUSY_TEXT = "Cannot switch model while a request is running. Use /stop first.";
776
+ var INLINE_OPTION_LIMIT = 8;
771
777
  var HELP_TEXT = [
772
778
  table(
773
779
  ["Command", "Description"],
@@ -831,9 +837,11 @@ function compactPath(path) {
831
837
  function modelText(runtime) {
832
838
  const current = runtime.agent().currentModel();
833
839
  if (current) return current.label;
840
+ const cached = runtime.state().model;
841
+ if (cached) return `${cached.label} (last known)`;
834
842
  const configured = runtime.config().agent.model;
835
843
  if (configured) return `${configured} (configured, not applied yet)`;
836
- return "unknown (session not started)";
844
+ return "unknown (send /model list)";
837
845
  }
838
846
  function handleSlashCommand(runtime, text, send) {
839
847
  const [rawCommand, ...args] = text.split(/\s+/);
@@ -923,7 +931,11 @@ function handleAgent(runtime, args, send) {
923
931
  async function handleModel(runtime, args, send) {
924
932
  const model = args.join(" ").trim();
925
933
  if (!model) {
926
- send(modelReport(runtime));
934
+ await reportModel(runtime, send, false);
935
+ return;
936
+ }
937
+ if (model.toLowerCase() === "list") {
938
+ await reportModel(runtime, send, true);
927
939
  return;
928
940
  }
929
941
  if (runtime.queue().status().busy) {
@@ -938,7 +950,12 @@ async function handleModel(runtime, args, send) {
938
950
  runtime.saveConfig();
939
951
  return accepted;
940
952
  });
941
- const applied = runtime.agent().currentModel()?.label ?? model;
953
+ const applied = runtime.agent().currentModel();
954
+ if (applied) {
955
+ runtime.state().model = { value: applied.value, label: applied.label };
956
+ runtime.saveState();
957
+ }
958
+ const label = applied?.label ?? model;
942
959
  if (!supported) {
943
960
  send(
944
961
  `Model saved: ${model}. This agent does not expose a runtime model option; it will be used on the next session if supported.`
@@ -946,34 +963,83 @@ async function handleModel(runtime, args, send) {
946
963
  return;
947
964
  }
948
965
  send(
949
- hadSession ? `Model switched to: ${applied}` : `Model set to: ${applied}. It will apply when the session starts.`
966
+ hadSession ? `Model switched to: ${label}` : `Model set to: ${label}. It will apply when the session starts.`
950
967
  );
951
968
  }
952
- function modelReport(runtime) {
953
- const current = runtime.agent().currentModel();
954
- if (!current) {
955
- const configured = runtime.config().agent.model;
956
- const hint = configured ? `Configured: ${configured}
957
-
958
- The agent has not reported a model yet; it becomes visible after the first message.` : "This agent does not expose a runtime model option, or the session has not started.";
959
- return `Current: unknown
960
-
961
- ${hint}`;
969
+ async function reportModel(runtime, send, wantList) {
970
+ const live = runtime.agent().currentModel();
971
+ if (live) {
972
+ send(renderModel(live, wantList));
973
+ return;
974
+ }
975
+ const cached = runtime.state().model;
976
+ if (cached && !wantList) {
977
+ send(renderCachedModel(cached));
978
+ return;
979
+ }
980
+ const name = runtime.config().agent.name;
981
+ send(`Reading ${wantList ? "model list" : "model"} from ${name}... (starting the agent)`);
982
+ try {
983
+ await runtime.serialize(
984
+ () => runtime.agent().warmup(runtime.state().acpSessionId ?? void 0)
985
+ );
986
+ } catch (error) {
987
+ const reason = error instanceof Error ? error.message : String(error);
988
+ send(`Could not read the model from ${name}: ${reason}`);
989
+ if (cached) send(renderCachedModel(cached));
990
+ return;
991
+ }
992
+ const refreshed = runtime.agent().currentModel();
993
+ if (refreshed) {
994
+ runtime.state().model = { value: refreshed.value, label: refreshed.label };
995
+ runtime.saveState();
996
+ send(renderModel(refreshed, wantList));
997
+ return;
998
+ }
999
+ send(cached ? renderCachedModel(cached) : unknownModelText(runtime));
1000
+ }
1001
+ function renderModel(model, wantList) {
1002
+ const lines = [`Current: ${model.label}`];
1003
+ const total = model.options.length;
1004
+ if (total === 0) {
1005
+ lines.push("", "This agent does not expose a model list.");
1006
+ return lines.join("\n");
962
1007
  }
963
- const lines = [`Current: ${current.label}`];
964
- if (current.options.length > 0) {
1008
+ if (wantList || total <= INLINE_OPTION_LIMIT) {
965
1009
  lines.push(
966
1010
  "",
967
1011
  table(
968
1012
  ["Model", ""],
969
- current.options.map((option) => [
1013
+ model.options.map((option) => [
970
1014
  option.label,
971
- option.value === current.value ? "\u2190 current" : ""
1015
+ option.value === model.value ? "\u2190 current" : ""
972
1016
  ])
973
1017
  )
974
1018
  );
975
- }
976
- lines.push("", "Switch: /model <name>");
1019
+ lines.push("", "Switch: /model <name>");
1020
+ return lines.join("\n");
1021
+ }
1022
+ lines.push(
1023
+ "",
1024
+ table(["Model", ""], [[model.label, "\u2190 current"]]),
1025
+ "",
1026
+ `${total} models available \xB7 Switch: /model <name> \xB7 List: /model list`
1027
+ );
1028
+ return lines.join("\n");
1029
+ }
1030
+ function renderCachedModel(cached) {
1031
+ return [
1032
+ `Current: ${cached.label} (last known)`,
1033
+ "",
1034
+ "Cached from the last session; the agent has not started in this process yet.",
1035
+ "Send /model list to read the live value from the agent."
1036
+ ].join("\n");
1037
+ }
1038
+ function unknownModelText(runtime) {
1039
+ const configured = runtime.config().agent.model;
1040
+ const lines = ["Current: unknown"];
1041
+ if (configured) lines.push("", `Configured: ${configured}`);
1042
+ lines.push("", "This agent does not expose a runtime model option.");
977
1043
  return lines.join("\n");
978
1044
  }
979
1045
  function statusText(runtime) {
@@ -1050,9 +1116,16 @@ function emptyState(token, agent, cwd) {
1050
1116
  cwd,
1051
1117
  createdAt: now,
1052
1118
  lastUsedAt: now,
1053
- usage: { ...EMPTY_USAGE }
1119
+ usage: { ...EMPTY_USAGE },
1120
+ model: null
1054
1121
  };
1055
1122
  }
1123
+ function parseCachedModel(value) {
1124
+ if (!value || typeof value !== "object") return null;
1125
+ const record = value;
1126
+ if (typeof record.value !== "string" || typeof record.label !== "string") return null;
1127
+ return { value: record.value, label: record.label };
1128
+ }
1056
1129
  function loadState(token) {
1057
1130
  const path = statePath(token);
1058
1131
  if (!(0, import_node_fs3.existsSync)(path)) return null;
@@ -1067,7 +1140,8 @@ function loadState(token) {
1067
1140
  cwd: typeof parsed.cwd === "string" ? parsed.cwd : process.cwd(),
1068
1141
  createdAt: typeof parsed.createdAt === "string" ? parsed.createdAt : (/* @__PURE__ */ new Date()).toISOString(),
1069
1142
  lastUsedAt: typeof parsed.lastUsedAt === "string" ? parsed.lastUsedAt : (/* @__PURE__ */ new Date()).toISOString(),
1070
- usage: parsed.usage && typeof parsed.usage === "object" ? { ...EMPTY_USAGE, ...parsed.usage } : { ...EMPTY_USAGE }
1143
+ usage: parsed.usage && typeof parsed.usage === "object" ? { ...EMPTY_USAGE, ...parsed.usage } : { ...EMPTY_USAGE },
1144
+ model: parseCachedModel(parsed.model)
1071
1145
  };
1072
1146
  } catch {
1073
1147
  return null;
@@ -1354,6 +1428,7 @@ async function switchAgent(ctx, name) {
1354
1428
  ctx.state.agent = name;
1355
1429
  ctx.state.acpSessionId = null;
1356
1430
  ctx.state.usage = { ...EMPTY_USAGE };
1431
+ ctx.state.model = null;
1357
1432
  ctx.saveConfig();
1358
1433
  ctx.saveState();
1359
1434
  await previous.close().catch(() => void 0);
@@ -1508,6 +1583,8 @@ async function processPrompt(ctx, item, signal) {
1508
1583
  });
1509
1584
  ctx.state.acpSessionId = result.sessionId;
1510
1585
  ctx.state.usage = result.usage;
1586
+ const model = ctx.getAgent().currentModel();
1587
+ if (model) ctx.state.model = { value: model.value, label: model.label };
1511
1588
  ctx.saveState();
1512
1589
  for (const chunk of splitMessage(result.text || "(no output)")) {
1513
1590
  await item.reply(chunk);