agent.libx.js 0.89.4 → 0.89.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.
package/dist/cli.d.ts CHANGED
@@ -23,6 +23,25 @@ interface SessionMeta {
23
23
  costUsd?: number;
24
24
  /** Sticky: true if any turn's usage was estimated (streamed without provider usage) → cost is approximate. */
25
25
  costEstimated?: boolean;
26
+ /** Per-turn forensic log: timing, outcome, usage, and provider error per turn — for investigating a reported issue. */
27
+ events?: TurnEvent[];
28
+ }
29
+ /** One turn's diagnostics, captured for offline forensics (mirrors what the footer prints, but persisted). */
30
+ interface TurnEvent {
31
+ ts: number;
32
+ durationMs: number;
33
+ model: string;
34
+ finishReason: string;
35
+ steps: number;
36
+ tools: number;
37
+ tokens?: number;
38
+ costUsd?: number;
39
+ estimated?: boolean;
40
+ error?: {
41
+ message: string;
42
+ statusCode?: number;
43
+ code?: string;
44
+ };
26
45
  }
27
46
  interface SessionData {
28
47
  meta: SessionMeta;
@@ -145,6 +164,7 @@ declare function expandMentions(fs: IFilesystem, line: string): Promise<{
145
164
  }>;
146
165
  /** The headless `--output-format json` result object for a turn. */
147
166
  declare function jsonResult(res: RunResult, session: SessionData): {
167
+ error?: any;
148
168
  ok: boolean;
149
169
  finishReason: "error" | "budget" | "stop" | "max_steps" | "timeout" | "loop" | "max_tool_calls" | "aborted";
150
170
  text: string;
package/dist/cli.js CHANGED
@@ -2805,7 +2805,7 @@ var Agent = class _Agent {
2805
2805
  } catch (err2) {
2806
2806
  if (err2?.code === "budget") return kill("budget");
2807
2807
  if (o.signal?.aborted) return kill("aborted");
2808
- log3.error("chat() failed", err2);
2808
+ log3.error(`chat() failed: ${err2?.message ?? err2}`, err2);
2809
2809
  return { text: "", steps, finishReason: "error", messages: this.transcript, usage, usageEstimated, error: err2 };
2810
2810
  }
2811
2811
  if (o.signal?.aborted) return kill("aborted");
@@ -2869,12 +2869,14 @@ var Agent = class _Agent {
2869
2869
  }
2870
2870
  async dispatch(tc) {
2871
2871
  const tool = this.activeTools.find((t) => t.name === tc.function.name);
2872
- if (!tool) return `Error: unknown tool '${tc.function.name}'`;
2873
2872
  let args = {};
2873
+ let earlyError;
2874
+ if (!tool) earlyError = `Error: unknown tool '${tc.function.name}'`;
2874
2875
  try {
2875
2876
  args = tc.function.arguments ? JSON.parse(tc.function.arguments) : {};
2876
2877
  } catch (e) {
2877
- return `Error: invalid JSON arguments for ${tc.function.name}: ${String(e)}`;
2878
+ args = tc.function.arguments;
2879
+ earlyError ??= `Error: invalid JSON arguments for ${tc.function.name}: ${String(e)}`;
2878
2880
  }
2879
2881
  const hooks = this.activeHooks;
2880
2882
  const call = { name: tc.function.name, args };
@@ -2887,6 +2889,12 @@ var Agent = class _Agent {
2887
2889
  return blocked;
2888
2890
  }
2889
2891
  this.options.host?.notify?.({ kind: "tool_use", id: tc.id ?? "", name: tc.function.name, input: args });
2892
+ if (earlyError) {
2893
+ log3.debug(`${tc.function.name} -> ${earlyError}`);
2894
+ await hooks?.postToolUse?.(call, earlyError, meta);
2895
+ this.options.host?.notify?.({ kind: "tool_result", id: tc.id ?? "", output: earlyError, isError: true });
2896
+ return earlyError;
2897
+ }
2890
2898
  let result;
2891
2899
  let threw = false;
2892
2900
  try {
@@ -4641,7 +4649,7 @@ function completePath(listDir, ref) {
4641
4649
  import { emitKeypressEvents } from "readline";
4642
4650
 
4643
4651
  // cli/bidi.ts
4644
- var RTL_RE = /[֐-׿؀-ۿ܀-ݏݐ-ݿࢠ-ࣿיִ-﷿ﹰ-]/;
4652
+ var RTL_RE = /[\u0590-\u05ff\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb1d-\ufdff\ufe70-\ufeff]/;
4645
4653
  var needsBidi = (s) => RTL_RE.test(s);
4646
4654
  function classify(c) {
4647
4655
  if (c >= 1425 && c <= 1469) return "NSM";
@@ -5927,6 +5935,22 @@ function resolveModelOrNewest(model) {
5927
5935
  return fallback;
5928
5936
  }
5929
5937
  var ENV_KEY_ALIASES = { google: ["GEMINI_API_KEY"] };
5938
+ function loadInstallEnv() {
5939
+ let dir = dirname3(import.meta.path);
5940
+ for (let i = 0; i < 5 && !existsSync7(join8(dir, "package.json")); i++) dir = dirname3(dir);
5941
+ for (const name of [".env", ".env.local"]) {
5942
+ const file = join8(dir, name);
5943
+ if (!existsSync7(file)) continue;
5944
+ for (const line of readFileSync5(file, "utf8").split("\n")) {
5945
+ const m = line.match(/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
5946
+ if (!m || m[1] in process.env) continue;
5947
+ let val = m[2].trim();
5948
+ if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) val = val.slice(1, -1);
5949
+ else val = val.replace(/\s+#.*$/, "").trim();
5950
+ process.env[m[1]] = val;
5951
+ }
5952
+ }
5953
+ }
5930
5954
  function apiKeysFromEnv() {
5931
5955
  const e = process.env, keys = {};
5932
5956
  for (const provider of listProviders()) {
@@ -6118,6 +6142,9 @@ function costOf(pricing, promptTokens = 0, completionTokens = 0) {
6118
6142
  function turnCost(model, usage) {
6119
6143
  return costOf(getModelInfo(model)?.pricing, usage?.promptTokens ?? 0, usage?.completionTokens ?? 0);
6120
6144
  }
6145
+ function errInfo(e) {
6146
+ return { message: String(e?.message ?? e), statusCode: e?.statusCode, code: e?.code };
6147
+ }
6121
6148
  function fmtUsd(n) {
6122
6149
  return n >= 1 ? `$${n.toFixed(2)}` : `$${n.toFixed(4)}`;
6123
6150
  }
@@ -6342,7 +6369,8 @@ function jsonResult(res, session) {
6342
6369
  steps: res.steps,
6343
6370
  tools: res.messages.slice(lastUser).filter((m) => m.role === "tool").length,
6344
6371
  usage: res.usage,
6345
- sessionId: session.meta.id
6372
+ sessionId: session.meta.id,
6373
+ ...res.finishReason === "error" && res.error ? { error: res.error?.message ?? String(res.error) } : {}
6346
6374
  };
6347
6375
  }
6348
6376
  async function readMultiline(readLine) {
@@ -6385,6 +6413,12 @@ async function runTurn(agent, store, session, task, cp, cwd = process.cwd()) {
6385
6413
  spinner.stop();
6386
6414
  err(red(` error: ${e?.message ?? e}
6387
6415
  `));
6416
+ (session.meta.events ??= []).push({ ts: t0, durationMs: Date.now() - t0, model: agent.options.model, finishReason: "error", steps: 0, tools: 0, error: errInfo(e) });
6417
+ session.meta.updated = Date.now();
6418
+ try {
6419
+ store.save(session);
6420
+ } catch {
6421
+ }
6388
6422
  return { ok: false };
6389
6423
  } finally {
6390
6424
  spinner.stop();
@@ -6399,8 +6433,13 @@ async function runTurn(agent, store, session, task, cp, cwd = process.cwd()) {
6399
6433
  const lastUser = res.messages.map((m2) => m2.role).lastIndexOf("user");
6400
6434
  const tools = res.messages.slice(lastUser).filter((m2) => m2.role === "tool").length;
6401
6435
  const ok = res.finishReason === "stop";
6402
- err("\n" + (ok ? green(" \u2713 done") : red(` \u2717 ${res.finishReason}`)) + dim(` \xB7 ${res.steps} steps \xB7 ${tools} tools \xB7 ${tok}${secs}s
6436
+ const shortId = session.meta.id.slice(-10);
6437
+ err("\n" + (ok ? green(" \u2713 done") : red(` \u2717 ${res.finishReason}`)) + dim(` \xB7 ${res.steps} steps \xB7 ${tools} tools \xB7 ${tok}${secs}s \xB7 ${shortId}
6403
6438
  `));
6439
+ if (res.finishReason === "error" && res.error) {
6440
+ const e = res.error;
6441
+ err(red(` ${e?.message ?? e}`) + (e?.statusCode ? dim(` (${e.statusCode}${e.code ? " " + e.code : ""})`) : "") + "\n");
6442
+ }
6404
6443
  session.messages = agent.transcript;
6405
6444
  session.meta.turns += 1;
6406
6445
  session.meta.tokens = (session.meta.tokens ?? 0) + (res.usage?.totalTokens ?? 0);
@@ -6408,6 +6447,9 @@ async function runTurn(agent, store, session, task, cp, cwd = process.cwd()) {
6408
6447
  if (res.usageEstimated) session.meta.costEstimated = true;
6409
6448
  session.meta.updated = Date.now();
6410
6449
  session.meta.model = agent.options.model;
6450
+ const ev = { ts: t0, durationMs: Date.now() - t0, model: agent.options.model, finishReason: res.finishReason, steps: res.steps, tools, tokens: res.usage?.totalTokens, costUsd: cost, estimated: res.usageEstimated };
6451
+ if (res.finishReason === "error" && res.error) ev.error = errInfo(res.error);
6452
+ (session.meta.events ??= []).push(ev);
6411
6453
  if (!session.meta.title) session.meta.title = titleOf(agent.transcript);
6412
6454
  try {
6413
6455
  store.save(session);
@@ -6439,7 +6481,10 @@ function startSession(args, store, agent, cwd) {
6439
6481
  `));
6440
6482
  }
6441
6483
  const now = Date.now();
6442
- return { meta: { id: args.sessionId ?? store.newId(now), created: now, updated: now, cwd, model: agent.options.model, turns: 0, title: "" }, messages: [] };
6484
+ const id = args.sessionId ?? store.newId(now);
6485
+ if (!args.task) err(dim(` session ${id}
6486
+ `));
6487
+ return { meta: { id, created: now, updated: now, cwd, model: agent.options.model, turns: 0, title: "" }, messages: [] };
6443
6488
  }
6444
6489
  var AGENTS_MD_TEMPLATE = `# ${"${name}"}
6445
6490
 
@@ -7214,7 +7259,7 @@ ${extra}` : body, checkpoints, cwd);
7214
7259
  }
7215
7260
  });
7216
7261
  }
7217
- const promptStr = bold(cyan("agent \u203A "));
7262
+ const promptStr = bold(cyan("agentx \u203A "));
7218
7263
  const contPrompt = dim(" \u2026 \u203A ");
7219
7264
  const classifyPaste = pastePathClassifier(cwd);
7220
7265
  const releaseStdin = () => {
@@ -7376,6 +7421,7 @@ async function main() {
7376
7421
  if (!id) process.exit(0);
7377
7422
  args.resume = id;
7378
7423
  }
7424
+ loadInstallEnv();
7379
7425
  const apiKeys = { ...cfg.apiKeys, ...apiKeysFromEnv() };
7380
7426
  if (!Object.keys(apiKeys).length) {
7381
7427
  console.error(red("No provider key found. Set ANTHROPIC_API_KEY (or OPENAI_API_KEY / GOOGLE_API_KEY / GROQ_API_KEY), e.g. in .env."));