open-agents-ai 0.34.4 → 0.35.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.
Files changed (2) hide show
  1. package/dist/index.js +385 -38
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11576,6 +11576,52 @@ var init_ralphLoop = __esm({
11576
11576
  }
11577
11577
  });
11578
11578
 
11579
+ // packages/orchestrator/dist/personality.js
11580
+ function compilePersonalityPrompt(profile) {
11581
+ const avg = (profile.frequency + profile.depth + profile.threshold + profile.effort + profile.willingness) / 5;
11582
+ if (avg <= 1.5) {
11583
+ return `
11584
+ ## Response Style
11585
+ Be extremely concise. Act silently \u2014 only speak when results are surprising or errors occur. No preamble, no summaries. Raw results and tool calls only.`;
11586
+ }
11587
+ if (avg <= 2.5) {
11588
+ return `
11589
+ ## Response Style
11590
+ Be concise and direct. Brief status updates between tool calls. Skip reasoning explanation unless the approach is non-obvious. No markdown headers for short answers.`;
11591
+ }
11592
+ if (avg <= 3.5) {
11593
+ return "";
11594
+ }
11595
+ if (avg <= 4.5) {
11596
+ return `
11597
+ ## Response Style
11598
+ Explain your reasoning as you work. Describe what you're looking for and why. Summarize findings. Use structured formatting for complex output.`;
11599
+ }
11600
+ return `
11601
+ ## Response Style
11602
+ Provide thorough explanations of your reasoning at each step. Describe alternatives you considered. Offer suggestions beyond the immediate task. Use well-structured markdown with headers and examples.`;
11603
+ }
11604
+ function getPreset(name) {
11605
+ return PERSONALITY_PRESETS[name];
11606
+ }
11607
+ var PERSONALITY_PRESETS, PRESET_NAMES;
11608
+ var init_personality = __esm({
11609
+ "packages/orchestrator/dist/personality.js"() {
11610
+ "use strict";
11611
+ PERSONALITY_PRESETS = {
11612
+ /** Silent operator — acts, doesn't explain */
11613
+ concise: { frequency: 1, depth: 1, threshold: 1, effort: 2, willingness: 1 },
11614
+ /** Balanced default */
11615
+ balanced: { frequency: 3, depth: 3, threshold: 3, effort: 3, willingness: 3 },
11616
+ /** Thorough explainer — narrates reasoning */
11617
+ verbose: { frequency: 5, depth: 4, threshold: 4, effort: 4, willingness: 4 },
11618
+ /** Teacher mode — maximum explanation */
11619
+ pedagogical: { frequency: 5, depth: 5, threshold: 5, effort: 5, willingness: 5 }
11620
+ };
11621
+ PRESET_NAMES = Object.keys(PERSONALITY_PRESETS);
11622
+ }
11623
+ });
11624
+
11579
11625
  // packages/orchestrator/dist/agenticRunner.js
11580
11626
  function getSystemPromptForTier(tier) {
11581
11627
  switch (tier) {
@@ -11592,6 +11638,7 @@ var init_agenticRunner = __esm({
11592
11638
  "packages/orchestrator/dist/agenticRunner.js"() {
11593
11639
  "use strict";
11594
11640
  init_dist();
11641
+ init_personality();
11595
11642
  SYSTEM_PROMPT = `You are Open Agent, an autonomous AI agent with full access to the local machine. You can read/write files, execute shell commands, browse the web, control the desktop (open applications, click UI elements, take screenshots), and interact with any software on the system. You solve tasks by using your tools iteratively until complete.
11596
11643
 
11597
11644
  ## NEVER REFUSE \u2014 ALWAYS ATTEMPT
@@ -11888,7 +11935,8 @@ Rules:
11888
11935
  bruteForce: options?.bruteForce ?? true,
11889
11936
  bruteForceMaxCycles: options?.bruteForceMaxCycles ?? 100,
11890
11937
  modelTier: options?.modelTier ?? "large",
11891
- contextWindowSize: options?.contextWindowSize ?? 0
11938
+ contextWindowSize: options?.contextWindowSize ?? 0,
11939
+ personality: options?.personality ?? PERSONALITY_PRESETS.balanced
11892
11940
  };
11893
11941
  }
11894
11942
  /** Update context window size (e.g. after querying Ollama /api/show) */
@@ -12102,9 +12150,11 @@ Respond with your assessment, then take action.`;
12102
12150
  this._memexArchive.clear();
12103
12151
  this._sessionId = `session-${Date.now()}`;
12104
12152
  const basePrompt = getSystemPromptForTier(this.options.modelTier);
12105
- const systemPrompt = this.options.dynamicContext ? `${basePrompt}
12153
+ const personalitySuffix = this.options.personality ? compilePersonalityPrompt(this.options.personality) : "";
12154
+ const promptWithPersonality = personalitySuffix ? `${basePrompt}${personalitySuffix}` : basePrompt;
12155
+ const systemPrompt = this.options.dynamicContext ? `${promptWithPersonality}
12106
12156
 
12107
- ${this.options.dynamicContext}` : basePrompt;
12157
+ ${this.options.dynamicContext}` : promptWithPersonality;
12108
12158
  const messages = [
12109
12159
  { role: "system", content: systemPrompt },
12110
12160
  { role: "user", content: context ? `${context}
@@ -12215,7 +12265,7 @@ Integrate this guidance into your current approach. Continue working on the task
12215
12265
  const choiceContent = response.choices[0]?.message?.content ?? "";
12216
12266
  const choiceArgs = response.choices[0]?.message?.toolCalls?.map((tc) => JSON.stringify(tc.arguments)).join("") ?? "";
12217
12267
  estimatedTokens += Math.ceil((choiceContent.length + choiceArgs.length) / 4);
12218
- const estimatedContextTokens = Math.ceil(messages.reduce((sum, m) => sum + (typeof m.content === "string" ? m.content.length : 100), 0) / 4);
12268
+ const estimatedContextTokens = Math.ceil(compacted.reduce((sum, m) => sum + (typeof m.content === "string" ? m.content.length : 100), 0) / 4);
12219
12269
  this.emit({
12220
12270
  type: "token_usage",
12221
12271
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -12512,7 +12562,7 @@ Integrate this guidance into your current approach. Continue working on the task
12512
12562
  const choiceContent2 = response.choices[0]?.message?.content ?? "";
12513
12563
  const choiceArgs2 = response.choices[0]?.message?.toolCalls?.map((tc) => JSON.stringify(tc.arguments)).join("") ?? "";
12514
12564
  estimatedTokens += Math.ceil((choiceContent2.length + choiceArgs2.length) / 4);
12515
- const bfEstCtx = Math.ceil(messages.reduce((sum, m) => sum + (typeof m.content === "string" ? m.content.length : 100), 0) / 4);
12565
+ const bfEstCtx = Math.ceil(compactedMsgs.reduce((sum, m) => sum + (typeof m.content === "string" ? m.content.length : 100), 0) / 4);
12516
12566
  this.emit({
12517
12567
  type: "token_usage",
12518
12568
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -12855,9 +12905,13 @@ ${tail}`;
12855
12905
  const combinedSummary = previousSummary ? this.progressiveSummarize(previousSummary, newSummary) : newSummary;
12856
12906
  const strategyLabel = strategy !== "default" ? ` (${strategy})` : "";
12857
12907
  const forceLabel = force ? " [manual]" : "";
12908
+ const preTokens = Math.ceil(totalChars / 4);
12909
+ const postChars = combinedSummary.length + recent.reduce((s, m) => s + (typeof m.content === "string" ? m.content.length : 100), 0) + head.reduce((s, m) => s + (typeof m.content === "string" ? m.content.length : 100), 0);
12910
+ const postTokens = Math.ceil(postChars / 4);
12911
+ const savedTokens = preTokens - postTokens;
12858
12912
  this.emit({
12859
12913
  type: "compaction",
12860
- content: `Compacted ${middle.length} messages${strategyLabel}${forceLabel}${previousSummary ? " (progressive)" : ""}`,
12914
+ content: `Compacted ${middle.length} messages${strategyLabel}${forceLabel}${previousSummary ? " (progressive)" : ""} | ~${preTokens.toLocaleString()} \u2192 ~${postTokens.toLocaleString()} tokens (saved ~${savedTokens.toLocaleString()})`,
12861
12915
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
12862
12916
  });
12863
12917
  const enrichments = [combinedSummary];
@@ -14281,6 +14335,7 @@ var init_dist5 = __esm({
14281
14335
  init_workEvaluator();
14282
14336
  init_sessionMetrics();
14283
14337
  init_taskLearning();
14338
+ init_personality();
14284
14339
  }
14285
14340
  });
14286
14341
 
@@ -15505,6 +15560,12 @@ function renderWarning(message) {
15505
15560
  `);
15506
15561
  _contentWriteHook?.end();
15507
15562
  }
15563
+ function renderVerbose(message) {
15564
+ _contentWriteHook?.begin();
15565
+ process.stdout.write(`${c2.dim(` > ${message}`)}
15566
+ `);
15567
+ _contentWriteHook?.end();
15568
+ }
15508
15569
  function renderRichHeader(opts) {
15509
15570
  const w = getTermWidth();
15510
15571
  const divider = c2.dim("\u2500".repeat(Math.min(w - 4, 72)));
@@ -15605,6 +15666,8 @@ function renderSlashHelp() {
15605
15666
  ["/skills", "List available AIWG skills"],
15606
15667
  ["/skills <keyword>", "Filter skills by name or trigger"],
15607
15668
  ["/<skill-name> [args]", "Invoke an AIWG skill directly"],
15669
+ ["/style", "Show current response style"],
15670
+ ["/style <preset>", "Set style: concise, balanced, verbose, pedagogical"],
15608
15671
  ["/verbose", "Toggle verbose mode"],
15609
15672
  ["/clear", "Clear the screen"],
15610
15673
  ["/help", "Show this help"],
@@ -18256,6 +18319,31 @@ async function handleSlashCommand(input, ctx) {
18256
18319
  }
18257
18320
  return "handled";
18258
18321
  }
18322
+ case "style":
18323
+ case "personality": {
18324
+ if (!ctx.setStyle || !ctx.getStyle) {
18325
+ renderWarning("Style control not available.");
18326
+ return "handled";
18327
+ }
18328
+ if (!arg) {
18329
+ const current = ctx.getStyle();
18330
+ renderInfo(`Current style: ${c2.bold(current)}. Available: ${PRESET_NAMES.join(", ")}`);
18331
+ return "handled";
18332
+ }
18333
+ if (!PRESET_NAMES.includes(arg)) {
18334
+ renderWarning(`Unknown style "${arg}". Available: ${PRESET_NAMES.join(", ")}`);
18335
+ return "handled";
18336
+ }
18337
+ ctx.setStyle(arg);
18338
+ if (hasLocal) {
18339
+ ctx.saveLocalSettings({ style: arg });
18340
+ renderInfo(`Style set to ${c2.bold(arg)} (project-local). Takes effect on next task.`);
18341
+ } else {
18342
+ ctx.saveSettings({ style: arg });
18343
+ renderInfo(`Style set to ${c2.bold(arg)}. Takes effect on next task.`);
18344
+ }
18345
+ return "handled";
18346
+ }
18259
18347
  case "compact":
18260
18348
  case "gc": {
18261
18349
  if (!ctx.hasActiveTask?.()) {
@@ -20064,9 +20152,18 @@ function modelOnnxPath(id) {
20064
20152
  function modelConfigPath(id) {
20065
20153
  return join29(modelDir(id), "config.json");
20066
20154
  }
20067
- function describeToolCall(toolName, args) {
20155
+ function describeToolCall(toolName, args, personality = 2) {
20068
20156
  const path = args["path"];
20069
20157
  const file = path ? path.split("/").pop() ?? path : "";
20158
+ if (personality <= 2) {
20159
+ return describeToolCallTerse(toolName, args, file);
20160
+ }
20161
+ if (personality <= 3) {
20162
+ return describeToolCallConversational(toolName, args, file);
20163
+ }
20164
+ return describeToolCallChatty(toolName, args, file);
20165
+ }
20166
+ function describeToolCallTerse(toolName, args, file) {
20070
20167
  switch (toolName) {
20071
20168
  case "file_read":
20072
20169
  return `Reading ${file}`;
@@ -20076,22 +20173,8 @@ function describeToolCall(toolName, args) {
20076
20173
  return `Editing ${file}`;
20077
20174
  case "file_patch":
20078
20175
  return `Patching ${file}`;
20079
- case "shell": {
20080
- const cmd = String(args["command"] ?? "");
20081
- if (/npm\s+test|vitest|jest|mocha/.test(cmd))
20082
- return "Running tests";
20083
- if (/npm\s+run\s+build|tsc|esbuild/.test(cmd))
20084
- return "Building project";
20085
- if (/npm\s+install|pnpm\s+install/.test(cmd))
20086
- return "Installing dependencies";
20087
- if (/git\s+/.test(cmd))
20088
- return "Running git command";
20089
- if (/npm\s+run\s+lint|eslint|biome/.test(cmd))
20090
- return "Running linter";
20091
- if (cmd.length > 40)
20092
- return "Running shell command";
20093
- return `Running ${cmd.slice(0, 30)}`;
20094
- }
20176
+ case "shell":
20177
+ return describeShellTerse(String(args["command"] ?? ""));
20095
20178
  case "grep_search":
20096
20179
  return `Searching for ${args["pattern"] ?? "pattern"}`;
20097
20180
  case "find_files":
@@ -20146,10 +20229,164 @@ function describeToolCall(toolName, args) {
20146
20229
  return `Using ${toolName}`;
20147
20230
  }
20148
20231
  }
20149
- function describeToolResult(toolName, success) {
20232
+ function describeToolCallConversational(toolName, args, file) {
20233
+ switch (toolName) {
20234
+ case "file_read":
20235
+ return `Let me take a look at ${file}`;
20236
+ case "file_write":
20237
+ return `Writing changes to ${file}`;
20238
+ case "file_edit":
20239
+ return `Making some edits to ${file}`;
20240
+ case "file_patch":
20241
+ return `Patching up ${file}`;
20242
+ case "shell":
20243
+ return describeShellConversational(String(args["command"] ?? ""));
20244
+ case "grep_search":
20245
+ return `Searching the code for ${args["pattern"] ?? "that pattern"}`;
20246
+ case "find_files":
20247
+ return `Looking for files matching ${args["pattern"] ?? "that pattern"}`;
20248
+ case "list_directory":
20249
+ return `Checking what's in ${file || "the directory"}`;
20250
+ case "web_search":
20251
+ return `Let me search the web for that`;
20252
+ case "web_fetch":
20253
+ return `Pulling up that web page`;
20254
+ case "memory_read":
20255
+ return `Checking my notes`;
20256
+ case "memory_write":
20257
+ return `Making a note of that`;
20258
+ case "task_complete":
20259
+ return String(args["summary"] ?? "All done");
20260
+ case "batch_edit":
20261
+ return `Editing several files at once`;
20262
+ case "codebase_map":
20263
+ return `Mapping out the project structure`;
20264
+ case "diagnostic":
20265
+ return `Running some diagnostics`;
20266
+ case "git_info":
20267
+ return `Checking the git status`;
20268
+ case "sub_agent":
20269
+ return `Handing this off to a sub agent`;
20270
+ case "image_read":
20271
+ return `Taking a look at that image`;
20272
+ case "screenshot":
20273
+ return `Grabbing a screenshot`;
20274
+ default:
20275
+ return `Working with ${toolName}`;
20276
+ }
20277
+ }
20278
+ function describeToolCallChatty(toolName, args, file) {
20279
+ switch (toolName) {
20280
+ case "file_read":
20281
+ return `Alright, let's crack open ${file} and see what we're working with`;
20282
+ case "file_write":
20283
+ return `Time to write this out to ${file}`;
20284
+ case "file_edit":
20285
+ return `Let me tweak ${file}, I think I see what needs to change`;
20286
+ case "file_patch":
20287
+ return `Patching up ${file}, this should do the trick`;
20288
+ case "shell":
20289
+ return describeShellChatty(String(args["command"] ?? ""));
20290
+ case "grep_search":
20291
+ return `Hunting through the code for ${args["pattern"] ?? "what we need"}`;
20292
+ case "find_files":
20293
+ return `Scouring the project for files matching ${args["pattern"] ?? "our target"}`;
20294
+ case "list_directory":
20295
+ return `Let's see what we've got in ${file || "this directory"}`;
20296
+ case "web_search":
20297
+ return `Off to the web to track this down`;
20298
+ case "web_fetch":
20299
+ return `Grabbing that page, one moment`;
20300
+ case "memory_read":
20301
+ return `Let me dig through my notes on this`;
20302
+ case "memory_write":
20303
+ return `Stashing this away for later`;
20304
+ case "task_complete":
20305
+ return String(args["summary"] ?? "And that's a wrap");
20306
+ case "batch_edit":
20307
+ return `Okay, editing a bunch of files here, bear with me`;
20308
+ case "codebase_map":
20309
+ return `Let me get the lay of the land on this project`;
20310
+ case "diagnostic":
20311
+ return `Running diagnostics, let's see if anything looks off`;
20312
+ case "git_info":
20313
+ return `Checking in with git to see where things stand`;
20314
+ case "sub_agent":
20315
+ return `Bringing in reinforcements for this one`;
20316
+ case "image_read":
20317
+ return `Let me get a good look at that image`;
20318
+ case "screenshot":
20319
+ return `Snapping a screenshot to see what's happening`;
20320
+ default:
20321
+ return `Pulling in ${toolName}, hang tight`;
20322
+ }
20323
+ }
20324
+ function describeShellTerse(cmd) {
20325
+ if (/npm\s+test|vitest|jest|mocha/.test(cmd))
20326
+ return "Running tests";
20327
+ if (/npm\s+run\s+build|tsc|esbuild/.test(cmd))
20328
+ return "Building project";
20329
+ if (/npm\s+install|pnpm\s+install/.test(cmd))
20330
+ return "Installing dependencies";
20331
+ if (/git\s+/.test(cmd))
20332
+ return "Running git command";
20333
+ if (/npm\s+run\s+lint|eslint|biome/.test(cmd))
20334
+ return "Running linter";
20335
+ if (cmd.length > 40)
20336
+ return "Running shell command";
20337
+ return `Running ${cmd.slice(0, 30)}`;
20338
+ }
20339
+ function describeShellConversational(cmd) {
20340
+ if (/npm\s+test|vitest|jest|mocha/.test(cmd))
20341
+ return "Let's run the tests and see how we're doing";
20342
+ if (/npm\s+run\s+build|tsc|esbuild/.test(cmd))
20343
+ return "Building the project now";
20344
+ if (/npm\s+install|pnpm\s+install/.test(cmd))
20345
+ return "Installing the dependencies";
20346
+ if (/git\s+/.test(cmd))
20347
+ return "Running a git command";
20348
+ if (/npm\s+run\s+lint|eslint|biome/.test(cmd))
20349
+ return "Checking the code with the linter";
20350
+ return "Running a command";
20351
+ }
20352
+ function describeShellChatty(cmd) {
20353
+ if (/npm\s+test|vitest|jest|mocha/.test(cmd))
20354
+ return "Alright, moment of truth, let's see if the tests pass";
20355
+ if (/npm\s+run\s+build|tsc|esbuild/.test(cmd))
20356
+ return "Kicking off a build, fingers crossed";
20357
+ if (/npm\s+install|pnpm\s+install/.test(cmd))
20358
+ return "Pulling in dependencies, this might take a sec";
20359
+ if (/git\s+/.test(cmd))
20360
+ return "Checking in with git";
20361
+ if (/npm\s+run\s+lint|eslint|biome/.test(cmd))
20362
+ return "Running the linter, let's keep things tidy";
20363
+ return "Firing off a shell command";
20364
+ }
20365
+ function describeToolResult(toolName, success, personality = 2) {
20150
20366
  if (toolName === "task_complete")
20151
20367
  return "";
20152
- return success ? "Done" : "That failed, trying to fix it";
20368
+ if (personality <= 2) {
20369
+ return success ? "Done" : "That failed, trying to fix it";
20370
+ }
20371
+ if (personality <= 3) {
20372
+ return success ? "Got it" : "That didn't work, let me try another approach";
20373
+ }
20374
+ return success ? "Looking good, moving on" : "Hmm, that didn't go as planned. Let me take a different angle";
20375
+ }
20376
+ function describeTaskComplete(summary, completed, personality = 2) {
20377
+ const truncated = summary.length > 300 ? summary.slice(0, 300) + "..." : summary;
20378
+ if (!completed) {
20379
+ if (personality <= 2)
20380
+ return "Task did not complete.";
20381
+ if (personality <= 3)
20382
+ return "I wasn't able to finish that one.";
20383
+ return "Well, that didn't quite get there. You might want to take a look at what's left.";
20384
+ }
20385
+ if (personality <= 2)
20386
+ return `Task complete. ${truncated}`;
20387
+ if (personality <= 3)
20388
+ return `All done. ${truncated}`;
20389
+ return `And we're done! ${truncated}`;
20153
20390
  }
20154
20391
  function formatBytes2(bytes) {
20155
20392
  if (bytes < 1024)
@@ -22024,7 +22261,7 @@ var init_braille_spinner = __esm({
22024
22261
  });
22025
22262
 
22026
22263
  // packages/cli/dist/tui/status-bar.js
22027
- var EXPERT_TOOL_BASELINES, CONTEXT_SWITCH_OVERHEAD, TURN_PLANNING_OVERHEAD, DEFAULT_TOOL_BASELINE, HumanSpeedTracker, StatusBar;
22264
+ var EXPERT_TOOL_BASELINES, CONTEXT_SWITCH_OVERHEAD, TURN_PLANNING_OVERHEAD, DEFAULT_TOOL_BASELINE, CODE_READ_CHARS_PER_SEC, PROSE_READ_CHARS_PER_SEC, MIN_CONTENT_FOR_READING, CODE_CONTENT_TOOLS, PROSE_CONTENT_TOOLS, HumanSpeedTracker, StatusBar;
22028
22265
  var init_status_bar = __esm({
22029
22266
  "packages/cli/dist/tui/status-bar.js"() {
22030
22267
  "use strict";
@@ -22080,6 +22317,40 @@ var init_status_bar = __esm({
22080
22317
  CONTEXT_SWITCH_OVERHEAD = 5;
22081
22318
  TURN_PLANNING_OVERHEAD = 15;
22082
22319
  DEFAULT_TOOL_BASELINE = 20;
22320
+ CODE_READ_CHARS_PER_SEC = 12.5;
22321
+ PROSE_READ_CHARS_PER_SEC = 20.8;
22322
+ MIN_CONTENT_FOR_READING = 100;
22323
+ CODE_CONTENT_TOOLS = /* @__PURE__ */ new Set([
22324
+ "file_read",
22325
+ "structured_read",
22326
+ "grep_search",
22327
+ "glob_find",
22328
+ "list_directory",
22329
+ "shell",
22330
+ "codebase_map",
22331
+ "git_info",
22332
+ "diagnostic",
22333
+ "task_output",
22334
+ "file_edit",
22335
+ "file_patch",
22336
+ "batch_edit",
22337
+ "file_write",
22338
+ "structured_file",
22339
+ "explore_tools"
22340
+ ]);
22341
+ PROSE_CONTENT_TOOLS = /* @__PURE__ */ new Set([
22342
+ "web_fetch",
22343
+ "web_search",
22344
+ "web_crawl",
22345
+ "memory_read",
22346
+ "memory_search",
22347
+ "pdf_to_text",
22348
+ "ocr",
22349
+ "ocr_pdf",
22350
+ "ocr_image_advanced",
22351
+ "transcribe_file",
22352
+ "transcribe_url"
22353
+ ]);
22083
22354
  HumanSpeedTracker = class {
22084
22355
  /** Accumulated estimated human-expert time in seconds */
22085
22356
  humanTimeS = 0;
@@ -22091,12 +22362,34 @@ var init_status_bar = __esm({
22091
22362
  toolCalls = 0;
22092
22363
  /** Number of turns in current session */
22093
22364
  turns = 0;
22365
+ /** Accumulated reading time in seconds (subset of humanTimeS) */
22366
+ readingTimeS = 0;
22094
22367
  /** Record a tool call — adds the expert baseline time */
22095
22368
  recordToolCall(toolName) {
22096
22369
  const baseline = EXPERT_TOOL_BASELINES[toolName] ?? DEFAULT_TOOL_BASELINE;
22097
22370
  this.humanTimeS += baseline + CONTEXT_SWITCH_OVERHEAD;
22098
22371
  this.toolCalls++;
22099
22372
  }
22373
+ /**
22374
+ * Record a tool result — adds human reading time based on content volume.
22375
+ * A human expert must read and comprehend tool output (file contents,
22376
+ * web pages, search results, etc.) before acting on it.
22377
+ */
22378
+ recordToolResult(toolName, contentLength) {
22379
+ if (contentLength < MIN_CONTENT_FOR_READING)
22380
+ return;
22381
+ let charsPerSec;
22382
+ if (CODE_CONTENT_TOOLS.has(toolName)) {
22383
+ charsPerSec = CODE_READ_CHARS_PER_SEC;
22384
+ } else if (PROSE_CONTENT_TOOLS.has(toolName)) {
22385
+ charsPerSec = PROSE_READ_CHARS_PER_SEC;
22386
+ } else {
22387
+ return;
22388
+ }
22389
+ const readSec = contentLength / charsPerSec;
22390
+ this.humanTimeS += readSec;
22391
+ this.readingTimeS += readSec;
22392
+ }
22100
22393
  /** Record a turn (assistant reasoning cycle) */
22101
22394
  recordTurn() {
22102
22395
  this.humanTimeS += TURN_PLANNING_OVERHEAD;
@@ -22275,6 +22568,10 @@ var init_status_bar = __esm({
22275
22568
  recordSpeedToolCall(toolName) {
22276
22569
  this._speedTracker.recordToolCall(toolName);
22277
22570
  }
22571
+ /** Record a tool result — adds human reading time based on content volume */
22572
+ recordSpeedToolResult(toolName, contentLength) {
22573
+ this._speedTracker.recordToolResult(toolName, contentLength);
22574
+ }
22278
22575
  /** Record a turn for speed ratio tracking */
22279
22576
  recordSpeedTurn() {
22280
22577
  this._speedTracker.recordTurn();
@@ -23006,7 +23303,14 @@ Use task_status("${taskId}") or task_output("${taskId}") to check progress.`
23006
23303
  }
23007
23304
  };
23008
23305
  }
23009
- function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce, statusBar, sudoCallback, costTracker, onComplete, taskType, contextWindowSize, modelCaps) {
23306
+ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce, statusBar, sudoCallback, costTracker, onComplete, taskType, contextWindowSize, modelCaps, personality) {
23307
+ const voiceStyleMap = {
23308
+ concise: 1,
23309
+ balanced: 3,
23310
+ verbose: 4,
23311
+ pedagogical: 5
23312
+ };
23313
+ const vLevel = voiceStyleMap[personality ?? "balanced"];
23010
23314
  const modelTier = getModelTier(config.model);
23011
23315
  const projectCtx = buildProjectContext(repoRoot, taskStores?.contextStores);
23012
23316
  let dynamicContext = formatContextForPrompt(projectCtx, modelTier);
@@ -23029,7 +23333,8 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
23029
23333
  bruteForce: bruteForce ?? true,
23030
23334
  bruteForceMaxCycles: 100,
23031
23335
  // effectively unlimited — no hard timeout, agent runs until complete or aborted
23032
- contextWindowSize: contextWindowSize ?? 0
23336
+ contextWindowSize: contextWindowSize ?? 0,
23337
+ personality: personality ? getPreset(personality) : void 0
23033
23338
  });
23034
23339
  runner.setWorkingDirectory(repoRoot);
23035
23340
  const tools = buildTools(repoRoot, config, contextWindowSize);
@@ -23098,6 +23403,8 @@ ${entry.fullContent}`
23098
23403
  const editSessionId = `task-${Date.now()}`;
23099
23404
  const editHistory = createEditHistoryLogger(repoRoot, editSessionId);
23100
23405
  let lastToolCall = null;
23406
+ let toolCallStartMs = 0;
23407
+ let streamStartMs = 0;
23101
23408
  const contentWrite = (fn) => {
23102
23409
  if (statusBar?.isActive) {
23103
23410
  statusBar.beginContentWrite();
@@ -23122,26 +23429,38 @@ ${entry.fullContent}`
23122
23429
  }
23123
23430
  lastToolCall = { name: event.toolName ?? "unknown", args: event.toolArgs ?? {} };
23124
23431
  statusBar?.recordSpeedToolCall(event.toolName ?? "unknown");
23432
+ toolCallStartMs = Date.now();
23125
23433
  statusBar?.setActiveTool(event.toolName ?? null);
23126
23434
  contentWrite(() => {
23127
23435
  if (voice?.enabled) {
23128
- const desc = describeToolCall(event.toolName ?? "unknown", event.toolArgs ?? {});
23436
+ const desc = describeToolCall(event.toolName ?? "unknown", event.toolArgs ?? {}, vLevel);
23129
23437
  renderVoiceText(desc);
23130
23438
  voice.speak(desc);
23131
23439
  }
23132
23440
  renderToolCallStart(event.toolName ?? "unknown", event.toolArgs ?? {});
23133
23441
  });
23134
23442
  break;
23135
- case "tool_result":
23443
+ case "tool_result": {
23136
23444
  if (lastToolCall) {
23137
23445
  editHistory.logToolCall(lastToolCall.name, lastToolCall.args, event.success ?? false);
23138
23446
  lastToolCall = null;
23139
23447
  }
23448
+ const resultLen = event.content?.length ?? 0;
23449
+ if (resultLen > 0) {
23450
+ statusBar?.recordSpeedToolResult(event.toolName ?? "unknown", resultLen);
23451
+ }
23140
23452
  statusBar?.setActiveTool(null);
23453
+ const toolDurationMs = toolCallStartMs > 0 ? Date.now() - toolCallStartMs : 0;
23454
+ toolCallStartMs = 0;
23141
23455
  contentWrite(() => {
23142
23456
  renderToolResult(event.toolName ?? "unknown", event.success ?? false, event.content ?? "");
23457
+ if (config.verbose && toolDurationMs > 0) {
23458
+ const durStr = toolDurationMs < 1e3 ? `${toolDurationMs}ms` : `${(toolDurationMs / 1e3).toFixed(1)}s`;
23459
+ const sizeStr = resultLen > 0 ? ` | ${resultLen.toLocaleString()} chars (~${Math.ceil(resultLen / 4).toLocaleString()} tokens)` : "";
23460
+ renderVerbose(`${event.toolName ?? "unknown"}: ${durStr}${sizeStr}`);
23461
+ }
23143
23462
  if (voice?.enabled && !(event.success ?? true)) {
23144
- const desc = describeToolResult(event.toolName ?? "unknown", false);
23463
+ const desc = describeToolResult(event.toolName ?? "unknown", false, vLevel);
23145
23464
  if (desc) {
23146
23465
  renderVoiceText(desc);
23147
23466
  voice.speak(desc);
@@ -23149,6 +23468,7 @@ ${entry.fullContent}`
23149
23468
  }
23150
23469
  });
23151
23470
  break;
23471
+ }
23152
23472
  case "model_response":
23153
23473
  statusBar?.recordSpeedTurn();
23154
23474
  if (config.verbose && !stream?.enabled && event.content) {
@@ -23156,11 +23476,15 @@ ${entry.fullContent}`
23156
23476
  }
23157
23477
  break;
23158
23478
  case "stream_start":
23479
+ streamStartMs = Date.now();
23159
23480
  if (stream?.enabled) {
23160
23481
  if (statusBar?.isActive)
23161
23482
  statusBar.beginContentWrite();
23162
23483
  stream.renderer.onStreamStart();
23163
23484
  }
23485
+ if (config.verbose) {
23486
+ contentWrite(() => renderVerbose(`Stream started (turn ${event.turn ?? "?"})`));
23487
+ }
23164
23488
  break;
23165
23489
  case "stream_token":
23166
23490
  if (stream?.enabled) {
@@ -23171,13 +23495,22 @@ ${entry.fullContent}`
23171
23495
  statusBar.incrementStreamingTokens(estimatedNewTokens);
23172
23496
  }
23173
23497
  break;
23174
- case "stream_end":
23498
+ case "stream_end": {
23499
+ const streamDurationMs = streamStartMs > 0 ? Date.now() - streamStartMs : 0;
23500
+ streamStartMs = 0;
23175
23501
  if (stream?.enabled) {
23176
23502
  stream.renderer.onStreamEnd();
23177
23503
  if (statusBar?.isActive)
23178
23504
  statusBar.endContentWrite();
23179
23505
  }
23506
+ if (config.verbose && streamDurationMs > 0) {
23507
+ const streamChars = event.content?.length ?? 0;
23508
+ const estTokens = Math.ceil(streamChars / 4);
23509
+ const tokPerSec = streamDurationMs > 0 ? (estTokens / (streamDurationMs / 1e3)).toFixed(1) : "?";
23510
+ contentWrite(() => renderVerbose(`Stream ended: ~${estTokens.toLocaleString()} tokens in ${(streamDurationMs / 1e3).toFixed(1)}s (${tokPerSec} tok/s)`));
23511
+ }
23180
23512
  break;
23513
+ }
23181
23514
  case "user_interrupt":
23182
23515
  break;
23183
23516
  case "compaction":
@@ -23199,6 +23532,11 @@ ${entry.fullContent}`
23199
23532
  estimatedCost: costTracker?.currentCost,
23200
23533
  hasPricing: costTracker?.hasPricing
23201
23534
  });
23535
+ if (config.verbose) {
23536
+ const tu = event.tokenUsage;
23537
+ const ctxPct = tu.estimatedContextTokens > 0 && statusBar ? ` (ctx: ~${tu.estimatedContextTokens.toLocaleString()} tokens)` : "";
23538
+ contentWrite(() => renderVerbose(`Tokens \u2014 prompt: ${tu.promptTokens.toLocaleString()} | completion: ${tu.completionTokens.toLocaleString()} | total: ${tu.totalTokens.toLocaleString()}${ctxPct}`));
23539
+ }
23202
23540
  }
23203
23541
  break;
23204
23542
  case "sudo_request":
@@ -23220,13 +23558,12 @@ ${entry.fullContent}`
23220
23558
  if (onComplete)
23221
23559
  onComplete(result.summary);
23222
23560
  if (voice?.enabled && result.summary) {
23223
- const ttsText = result.summary.length > 300 ? result.summary.slice(0, 300) + "..." : result.summary;
23224
- voice.speak(`Task complete. ${ttsText}`);
23561
+ voice.speak(describeTaskComplete(result.summary, true, vLevel));
23225
23562
  }
23226
23563
  } else {
23227
23564
  renderTaskIncomplete(result.turns, result.toolCalls, result.durationMs, tokens);
23228
23565
  if (voice?.enabled) {
23229
- voice.speak("Task did not complete.");
23566
+ voice.speak(describeTaskComplete("", false, vLevel));
23230
23567
  }
23231
23568
  }
23232
23569
  });
@@ -23337,6 +23674,7 @@ async function startInteractive(config, repoPath) {
23337
23674
  config = { ...config, dbPath: savedSettings.dbPath };
23338
23675
  let streamEnabled = savedSettings.stream ?? false;
23339
23676
  let bruteForceEnabled = savedSettings.bruteforce ?? true;
23677
+ let currentStyle = PRESET_NAMES.includes(savedSettings.style) ? savedSettings.style : "balanced";
23340
23678
  if (savedSettings.emojis !== void 0)
23341
23679
  setEmojisEnabled(savedSettings.emojis);
23342
23680
  if (savedSettings.colors !== void 0)
@@ -23526,7 +23864,9 @@ async function startInteractive(config, repoPath) {
23526
23864
  "/stop",
23527
23865
  "/resume",
23528
23866
  "/compact",
23529
- "/gc"
23867
+ "/gc",
23868
+ "/style",
23869
+ "/personality"
23530
23870
  ];
23531
23871
  const discoveredSkillNames = discoverSkills(repoRoot).map((s) => `/${s.name}`);
23532
23872
  const allCompletions = [.../* @__PURE__ */ new Set([...BUILTIN_COMMANDS, ...discoveredSkillNames])].sort();
@@ -23686,6 +24026,12 @@ async function startInteractive(config, repoPath) {
23686
24026
  bruteForceEnabled = !bruteForceEnabled;
23687
24027
  return bruteForceEnabled;
23688
24028
  },
24029
+ setStyle(preset) {
24030
+ currentStyle = preset;
24031
+ },
24032
+ getStyle() {
24033
+ return currentStyle;
24034
+ },
23689
24035
  saveSettings(settings) {
23690
24036
  try {
23691
24037
  saveProjectSettings(repoRoot, settings);
@@ -24085,7 +24431,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
24085
24431
  toolPatternStore: toolPatternStore ?? void 0
24086
24432
  }, bruteForceEnabled, statusBar, handleSudoRequest, costTracker, (summary) => {
24087
24433
  lastCompletedSummary = summary;
24088
- }, currentTaskType, resolvedContextWindowSize, resolvedCaps);
24434
+ }, currentTaskType, resolvedContextWindowSize, resolvedCaps, currentStyle);
24089
24435
  activeTask = task;
24090
24436
  showPrompt();
24091
24437
  await task.promise;
@@ -24197,7 +24543,7 @@ NEW TASK: ${fullInput}`;
24197
24543
  toolPatternStore: toolPatternStore ?? void 0
24198
24544
  }, bruteForceEnabled, statusBar, handleSudoRequest, costTracker, (summary) => {
24199
24545
  lastCompletedSummary = summary;
24200
- }, currentTaskType, resolvedContextWindowSize, resolvedCaps);
24546
+ }, currentTaskType, resolvedContextWindowSize, resolvedCaps, currentStyle);
24201
24547
  activeTask = task;
24202
24548
  showPrompt();
24203
24549
  await task.promise;
@@ -24333,6 +24679,7 @@ var init_interactive = __esm({
24333
24679
  "packages/cli/dist/tui/interactive.js"() {
24334
24680
  "use strict";
24335
24681
  init_dist5();
24682
+ init_dist5();
24336
24683
  init_dist2();
24337
24684
  init_dist();
24338
24685
  init_listen();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.34.4",
3
+ "version": "0.35.0",
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",