open-agents-ai 0.103.54 → 0.103.55

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.
Files changed (2) hide show
  1. package/dist/index.js +151 -27
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -37145,6 +37145,47 @@ function pick(key, variants) {
37145
37145
  narration.lastVariantIdx[key] = idx;
37146
37146
  return variants[idx];
37147
37147
  }
37148
+ function extractSubAgentTopic(args) {
37149
+ const raw = String(args["description"] ?? args["prompt"] ?? "");
37150
+ if (!raw || raw.length < 5)
37151
+ return "";
37152
+ let text = raw.replace(/[#*`_~\[\]]/g, "").replace(/^\d+[.)]\s*/gm, "").trim();
37153
+ const sentEnd = text.search(/[.!?]\s/);
37154
+ if (sentEnd > 10 && sentEnd < 80) {
37155
+ text = text.slice(0, sentEnd);
37156
+ } else if (text.length > 80) {
37157
+ const cut = text.lastIndexOf(" ", 80);
37158
+ text = text.slice(0, cut > 20 ? cut : 80);
37159
+ }
37160
+ if (text.length > 0)
37161
+ text = text.charAt(0).toLowerCase() + text.slice(1);
37162
+ return text;
37163
+ }
37164
+ function extractShellEssence(cmd) {
37165
+ if (!cmd || cmd.length < 3)
37166
+ return "";
37167
+ const npmTest = cmd.match(/npm\s+test\b/);
37168
+ if (npmTest)
37169
+ return "running tests";
37170
+ const npmBuild = cmd.match(/npm\s+run\s+(\S+)/);
37171
+ if (npmBuild)
37172
+ return `running ${npmBuild[1]}`;
37173
+ const gitCmd = cmd.match(/git\s+(commit|push|pull|merge|rebase|checkout|diff|status|log|stash|add)\b/);
37174
+ if (gitCmd)
37175
+ return `git ${gitCmd[1]}`;
37176
+ if (/npm\s+publish/.test(cmd))
37177
+ return "publishing to npm";
37178
+ const nodeScript = cmd.match(/(?:node|tsx?)\s+(\S+)/);
37179
+ if (nodeScript)
37180
+ return `running ${nodeScript[1].split("/").pop()}`;
37181
+ const curlUrl = cmd.match(/curl\s+.*?(https?:\/\/\S{10,40})/);
37182
+ if (curlUrl)
37183
+ return `fetching ${curlUrl[1].replace(/https?:\/\//, "").split("/")[0]}`;
37184
+ const pnpm = cmd.match(/pnpm\s+(-r\s+)?(\S+)/);
37185
+ if (pnpm)
37186
+ return `pnpm ${pnpm[1] || ""}${pnpm[2]}`.trim();
37187
+ return "";
37188
+ }
37148
37189
  function getShellCategory(cmd) {
37149
37190
  if (/npm\s+test|vitest|jest|mocha/.test(cmd))
37150
37191
  return "test";
@@ -37220,24 +37261,35 @@ function emotionColor(emotion, stark = false, autist = false) {
37220
37261
  return "";
37221
37262
  if (Math.random() > (stark ? 0.5 : 0.3))
37222
37263
  return "";
37264
+ const lastEmoKey = narration.lastVariantIdx["_emo_quadrant"] ?? -1;
37223
37265
  if (emotion.valence > 0.5 && emotion.arousal > 0.6) {
37266
+ narration.lastVariantIdx["_emo_quadrant"] = 1;
37267
+ if (lastEmoKey === 1 && Math.random() < 0.5)
37268
+ return "";
37224
37269
  return pick("emo_excited", stark ? [
37225
37270
  "Now we're cooking. ",
37226
37271
  "This is what I'm talking about. ",
37227
- "Brilliant. Absolutely brilliant. ",
37272
+ "Brilliant. ",
37228
37273
  "Watch this. ",
37229
37274
  "We're onto something here. ",
37230
- "I live for this. ",
37231
- "Oh this is good. "
37275
+ "Oh this is good. ",
37276
+ "The pieces are falling into place. ",
37277
+ "This is where it gets interesting. ",
37278
+ "I can feel this coming together. "
37232
37279
  ] : [
37233
37280
  "Feeling good about this. ",
37234
37281
  "On a roll here. ",
37235
37282
  "This is going great. ",
37236
37283
  "Momentum building. ",
37237
- "Loving this. "
37284
+ "Loving this. ",
37285
+ "Making real progress now. ",
37286
+ "Things are clicking. "
37238
37287
  ]);
37239
37288
  }
37240
37289
  if (emotion.valence < -0.3 && emotion.arousal > 0.5) {
37290
+ narration.lastVariantIdx["_emo_quadrant"] = 2;
37291
+ if (lastEmoKey === 2 && Math.random() < 0.5)
37292
+ return "";
37241
37293
  return pick("emo_stressed", stark ? [
37242
37294
  "Fine. The hard way then. ",
37243
37295
  "This is getting personal. ",
@@ -37245,41 +37297,54 @@ function emotionColor(emotion, stark = false, autist = false) {
37245
37297
  "Come on. Think. ",
37246
37298
  "Not today. Not this bug. ",
37247
37299
  "I've beaten worse. ",
37248
- "Pain is just information. "
37300
+ "There's got to be a way. ",
37301
+ "Okay, new angle. "
37249
37302
  ] : [
37250
37303
  "Pushing through. ",
37251
37304
  "Staying focused. ",
37252
37305
  "Not giving up. ",
37253
37306
  "Determined to crack this. ",
37254
- "Bear with me. "
37307
+ "Bear with me. ",
37308
+ "Working through this. ",
37309
+ "Let me rethink this. "
37255
37310
  ]);
37256
37311
  }
37257
37312
  if (emotion.valence > 0.3 && emotion.arousal < 0.3) {
37313
+ narration.lastVariantIdx["_emo_quadrant"] = 3;
37314
+ if (lastEmoKey === 3 && Math.random() < 0.5)
37315
+ return "";
37258
37316
  return pick("emo_calm", stark ? [
37259
37317
  "Clean. Just how I like it. ",
37260
37318
  "Smooth. ",
37261
37319
  "Textbook. ",
37262
37320
  "That's the stuff. ",
37263
- "Effortless. "
37321
+ "Effortless. ",
37322
+ "Exactly as expected. "
37264
37323
  ] : [
37265
37324
  "Nice and steady. ",
37266
37325
  "Smooth sailing. ",
37267
37326
  "Easy does it. ",
37268
- "Taking it easy. "
37327
+ "Taking it easy. ",
37328
+ "Going well. "
37269
37329
  ]);
37270
37330
  }
37271
37331
  if (emotion.valence < -0.2 && emotion.arousal < 0.3) {
37332
+ narration.lastVariantIdx["_emo_quadrant"] = 4;
37333
+ if (lastEmoKey === 4 && Math.random() < 0.5)
37334
+ return "";
37272
37335
  return pick("emo_subdued", stark ? [
37273
37336
  "Careful now. ",
37274
37337
  "One wrong move and this unravels. ",
37275
37338
  "Measured steps. ",
37276
37339
  "Trust the process. ",
37277
- "Precision matters here. "
37340
+ "Precision matters here. ",
37341
+ "Methodical. "
37278
37342
  ] : [
37279
37343
  "Being careful here. ",
37280
37344
  "Treading carefully. ",
37281
37345
  "Let me be precise. ",
37282
- "Taking extra care. "
37346
+ "Taking extra care. ",
37347
+ "One step at a time. "
37283
37348
  ]);
37284
37349
  }
37285
37350
  return "";
@@ -37312,9 +37377,16 @@ function describeToolCall(toolName, args, personality = 2, emotion, stark = fals
37312
37377
  base = pick(poolKey, (FILE_EDIT_VARIANTS[tier] ?? FILE_EDIT_VARIANTS.terse)(file, args));
37313
37378
  break;
37314
37379
  case "shell": {
37315
- const cat = getShellCategory(String(args["command"] ?? ""));
37316
- const pool = SHELL_VARIANTS[cat] ?? SHELL_VARIANTS.generic;
37317
- base = pick(`shell_${cat}_${tier}`, pool[tier] ?? pool.terse);
37380
+ const cmd = String(args["command"] ?? "");
37381
+ const cat = getShellCategory(cmd);
37382
+ const essence = extractShellEssence(cmd);
37383
+ if (essence && tier !== "terse") {
37384
+ const essenceVariants = tier === "chatty" ? [`Alright, ${essence}`, `Let me handle ${essence}`, `Time to ${essence.startsWith("running") ? essence : "run " + essence}`] : [`Now ${essence}`, essence.charAt(0).toUpperCase() + essence.slice(1)];
37385
+ base = pick(`shell_ess_${tier}`, essenceVariants);
37386
+ } else {
37387
+ const pool = SHELL_VARIANTS[cat] ?? SHELL_VARIANTS.generic;
37388
+ base = pick(`shell_${cat}_${tier}`, pool[tier] ?? pool.terse);
37389
+ }
37318
37390
  break;
37319
37391
  }
37320
37392
  case "grep_search":
@@ -37514,9 +37586,47 @@ function extractResultDigest(toolName, content) {
37514
37586
  const exitMatch = text.match(/exit\s*(?:code)?[:\s]*(\d+)/i);
37515
37587
  if (exitMatch && exitMatch[1] !== "0")
37516
37588
  nuggets.push(`exit code ${exitMatch[1]}`);
37589
+ if (nuggets.length === 0) {
37590
+ const contentDigest = extractContentSummary(text, toolName);
37591
+ if (contentDigest)
37592
+ nuggets.push(contentDigest);
37593
+ }
37517
37594
  const digest = nuggets.slice(0, 3).join(", ");
37518
37595
  return digest.length > 100 ? digest.slice(0, 97) + "..." : digest;
37519
37596
  }
37597
+ function extractContentSummary(text, toolName) {
37598
+ let cleaned = text.replace(/^\s*\d+[│|:→]\s*/gm, "").replace(/\d{4}-\d{2}-\d{2}T[\d:.]+Z?\s*/g, "").replace(/^[\s*#=-]+$/gm, "").replace(/```[\s\S]*?```/g, "").replace(/^\s*(import|export|const|let|var|function|class|interface|type)\s/gm, "").replace(/[{}()\[\];]/g, "").trim();
37599
+ const lines = cleaned.split("\n").map((l) => l.trim()).filter((l) => l.length > 10);
37600
+ for (const line of lines) {
37601
+ const wordChars = line.replace(/[^a-zA-Z\s]/g, "").trim();
37602
+ if (wordChars.length < line.length * 0.4)
37603
+ continue;
37604
+ if (/^(\/|\.\/)/.test(line))
37605
+ continue;
37606
+ if (/^\s*[{<]/.test(line))
37607
+ continue;
37608
+ let summary = line;
37609
+ if (summary.length > 80) {
37610
+ const cut = summary.lastIndexOf(" ", 80);
37611
+ summary = summary.slice(0, cut > 20 ? cut : 80);
37612
+ }
37613
+ if (summary.length > 0) {
37614
+ summary = summary.charAt(0).toLowerCase() + summary.slice(1);
37615
+ summary = summary.replace(/[.,;:!?]+$/, "");
37616
+ }
37617
+ return summary;
37618
+ }
37619
+ if (toolName === "sub_agent") {
37620
+ const summaryMatch = text.match(/(?:summary|created|completed|result)[:\s]+(.{10,80}?)(?:\n|$)/i);
37621
+ if (summaryMatch) {
37622
+ let s = summaryMatch[1].trim();
37623
+ if (s.length > 0)
37624
+ s = s.charAt(0).toLowerCase() + s.slice(1);
37625
+ return s;
37626
+ }
37627
+ }
37628
+ return "";
37629
+ }
37520
37630
  function describeToolResult(toolName, success, personality = 2, resultContent, emotion, stark = false) {
37521
37631
  if (toolName === "task_complete")
37522
37632
  return "";
@@ -37532,6 +37642,16 @@ function describeToolResult(toolName, success, personality = 2, resultContent, e
37532
37642
  return "";
37533
37643
  const base = pick(`result_ok_${tier}`, RESULT_SUCCESS_VARIANTS[tier] ?? RESULT_SUCCESS_VARIANTS.terse);
37534
37644
  if (digest && personality >= 2) {
37645
+ if (tier === "chatty" && digest.length > 15) {
37646
+ if (Math.random() < 0.5) {
37647
+ const contentLeads = [
37648
+ `${emo}Interesting, ${digest}`,
37649
+ `${emo}So we've got ${digest}`,
37650
+ `${emo}${digest.charAt(0).toUpperCase() + digest.slice(1)}, that's useful`
37651
+ ];
37652
+ return pick("digest_lead", contentLeads);
37653
+ }
37654
+ }
37535
37655
  const connectors = tier === "chatty" ? [` \u2014 ${digest}`, `, I see ${digest}`, `. Looks like ${digest}`, `, showing ${digest}`] : tier === "conv" ? [` \u2014 ${digest}`, `, ${digest}`, `. Shows ${digest}`] : [`: ${digest}`];
37536
37656
  return emo + base + pick("digest_conn_ok", connectors);
37537
37657
  }
@@ -38657,18 +38777,18 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
38657
38777
  ]
38658
38778
  };
38659
38779
  SUB_AGENT_VARIANTS = {
38660
- terse: () => [`Delegating to sub agent`, `Spawning sub agent`, `Handing off`],
38661
- conv: () => [
38662
- `Handing this off to a sub agent`,
38663
- `Bringing in some help for this`,
38664
- `Delegating this part of the work`
38665
- ],
38666
- chatty: () => [
38667
- `Bringing in reinforcements for this one`,
38668
- `Let me hand this off to a specialist`,
38669
- `Calling in backup on this`,
38670
- `This needs a dedicated agent, passing it along`
38671
- ]
38780
+ terse: (_f, a) => {
38781
+ const topic = extractSubAgentTopic(a);
38782
+ return topic ? [`Sub agent: ${topic}`, `Delegating: ${topic}`] : [`Delegating to sub agent`, `Spawning sub agent`];
38783
+ },
38784
+ conv: (_f, a) => {
38785
+ const topic = extractSubAgentTopic(a);
38786
+ return topic ? [`Handing off to a sub agent to ${topic}`, `Bringing in help to ${topic}`, `Delegating the ${topic} work`] : [`Handing this off to a sub agent`, `Bringing in some help for this`, `Delegating this part of the work`];
38787
+ },
38788
+ chatty: (_f, a) => {
38789
+ const topic = extractSubAgentTopic(a);
38790
+ return topic ? [`Spinning up a sub agent to ${topic}`, `This part needs a specialist, delegating to ${topic}`, `Calling in backup to handle ${topic}`] : [`Bringing in reinforcements for this one`, `Let me hand this off to a specialist`, `Calling in backup on this`];
38791
+ }
38672
38792
  };
38673
38793
  SHELL_VARIANTS = {
38674
38794
  test: {
@@ -48255,8 +48375,12 @@ ${result.text}`;
48255
48375
  if (parsed.summary)
48256
48376
  steering = parsed.summary;
48257
48377
  } catch {
48258
- if (result.summary)
48259
- steering = `USER STEERING: ${result.summary}`;
48378
+ const raw = result.summary || "";
48379
+ const ackMatch = raw.match(/acknowledgment[:\s]*["']?([^"'\n]{5,80})["']?/i) || raw.match(/^([^.!?\n]{5,80}[.!?])/);
48380
+ if (ackMatch)
48381
+ acknowledgment = ackMatch[1].trim();
48382
+ if (raw.length > 10)
48383
+ steering = `USER STEERING: ${raw}`;
48260
48384
  }
48261
48385
  if (voiceEngine?.enabled) {
48262
48386
  writeContent(() => renderVoiceText(acknowledgment));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.103.54",
3
+ "version": "0.103.55",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",