akseljoonas HF Staff commited on
Commit
a96af97
·
1 Parent(s): 3d0a369

Live research stats: tool count, tokens, elapsed time in header

Browse files
agent/tools/research_tool.py CHANGED
@@ -221,7 +221,25 @@ async def research_handler(
221
  except Exception:
222
  pass
223
 
224
- await _log("Starting research sub-agent...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
  # Run the research loop (max 20 iterations — research should be focused)
227
  max_iterations = 20
@@ -239,11 +257,16 @@ async def research_handler(
239
  logger.error("Research sub-agent LLM error: %s", e)
240
  return f"Research agent LLM error: {e}", False
241
 
 
 
 
 
242
  choice = response.choices[0]
243
  msg = choice.message
244
 
245
  # If no tool calls, we have our final answer
246
  if not msg.tool_calls:
 
247
  await _log("Research complete.")
248
  content = msg.content or "Research completed but no summary generated."
249
  return content, True
@@ -285,6 +308,8 @@ async def research_handler(
285
  output, _success = await session.tool_router.call_tool(
286
  tool_name, tool_args, session=session
287
  )
 
 
288
  # Truncate tool output for the research context
289
  if len(output) > 8000:
290
  output = output[:4800] + "\n...(truncated)...\n" + output[-3200:]
 
221
  except Exception:
222
  pass
223
 
224
+ import time as _time
225
+
226
+ _start = _time.monotonic()
227
+ _tool_uses = 0
228
+ _total_tokens = 0
229
+
230
+ def _format_stats() -> str:
231
+ elapsed = _time.monotonic() - _start
232
+ if elapsed < 60:
233
+ time_str = f"{elapsed:.0f}s"
234
+ else:
235
+ time_str = f"{elapsed / 60:.0f}m {elapsed % 60:.0f}s"
236
+ if _total_tokens >= 1000:
237
+ tok_str = f"{_total_tokens / 1000:.1f}k"
238
+ else:
239
+ tok_str = str(_total_tokens)
240
+ return f"{_tool_uses} tool uses · {tok_str} tokens · {time_str}"
241
+
242
+ await _log("stats:" + _format_stats())
243
 
244
  # Run the research loop (max 20 iterations — research should be focused)
245
  max_iterations = 20
 
257
  logger.error("Research sub-agent LLM error: %s", e)
258
  return f"Research agent LLM error: {e}", False
259
 
260
+ # Track tokens
261
+ if response.usage:
262
+ _total_tokens += response.usage.total_tokens
263
+
264
  choice = response.choices[0]
265
  msg = choice.message
266
 
267
  # If no tool calls, we have our final answer
268
  if not msg.tool_calls:
269
+ await _log("stats:" + _format_stats())
270
  await _log("Research complete.")
271
  content = msg.content or "Research completed but no summary generated."
272
  return content, True
 
308
  output, _success = await session.tool_router.call_tool(
309
  tool_name, tool_args, session=session
310
  )
311
+ _tool_uses += 1
312
+ await _log("stats:" + _format_stats())
313
  # Truncate tool output for the research context
314
  if len(output) > 8000:
315
  output = output[:4800] + "\n...(truncated)...\n" + output[-3200:]
agent/utils/terminal_display.py CHANGED
@@ -65,37 +65,55 @@ def print_tool_output(output: str, success: bool, truncate: bool = True) -> None
65
 
66
 
67
  class SubAgentDisplay:
68
- """Rolling 2-line gray display of the last 2 sub-agent tool calls."""
69
 
70
  _MAX_VISIBLE = 2
71
 
72
  def __init__(self):
73
  self._calls: list[str] = []
 
74
  self._lines_on_screen = 0
75
 
76
- def update(self, tool_desc: str) -> None:
 
 
 
 
 
 
77
  self._calls.append(tool_desc)
78
- visible = self._calls[-self._MAX_VISIBLE:]
79
- self._redraw(visible)
80
 
81
  def clear(self) -> None:
 
 
 
 
 
 
82
  if self._lines_on_screen > 0:
83
  f = _console.file
84
  for _ in range(self._lines_on_screen):
85
  f.write("\033[A\033[K")
86
  f.flush()
87
- self._lines_on_screen = 0
88
- self._calls = []
89
 
90
- def _redraw(self, visible: list[str]) -> None:
91
  f = _console.file
92
- if self._lines_on_screen > 0:
93
- for _ in range(self._lines_on_screen):
94
- f.write("\033[A\033[K")
 
 
 
 
 
 
95
  for desc in visible:
96
- f.write(f"{_I} \033[2m{desc}\033[0m\n")
 
 
97
  f.flush()
98
- self._lines_on_screen = len(visible)
99
 
100
 
101
  _subagent_display = SubAgentDisplay()
@@ -104,13 +122,12 @@ _subagent_display = SubAgentDisplay()
104
  def print_tool_log(tool: str, log: str) -> None:
105
  """Handle tool log events — sub-agent calls get the rolling display."""
106
  if tool == "research":
107
- if log == "Starting research sub-agent...":
108
- _subagent_display.clear()
109
- _console.print(f"{_I}[tool.name]▸ research[/tool.name]")
110
  elif log == "Research complete.":
111
  _subagent_display.clear()
112
  else:
113
- _subagent_display.update(log)
114
  else:
115
  _console.print(f"{_I}[dim]{tool}: {log}[/dim]")
116
 
 
65
 
66
 
67
  class SubAgentDisplay:
68
+ """Live-updating display: header with stats + rolling 2-line tool calls."""
69
 
70
  _MAX_VISIBLE = 2
71
 
72
  def __init__(self):
73
  self._calls: list[str] = []
74
+ self._stats: str = ""
75
  self._lines_on_screen = 0
76
 
77
+ def set_stats(self, stats: str) -> None:
78
+ """Update the stats line and redraw."""
79
+ self._stats = stats
80
+ self._redraw()
81
+
82
+ def add_call(self, tool_desc: str) -> None:
83
+ """Add a tool call and redraw."""
84
  self._calls.append(tool_desc)
85
+ self._redraw()
 
86
 
87
  def clear(self) -> None:
88
+ self._erase()
89
+ self._lines_on_screen = 0
90
+ self._calls = []
91
+ self._stats = ""
92
+
93
+ def _erase(self) -> None:
94
  if self._lines_on_screen > 0:
95
  f = _console.file
96
  for _ in range(self._lines_on_screen):
97
  f.write("\033[A\033[K")
98
  f.flush()
 
 
99
 
100
+ def _redraw(self) -> None:
101
  f = _console.file
102
+ self._erase()
103
+ lines = []
104
+ # Header: ▸ research (stats)
105
+ header = f"{_I}\033[1;36m▸ research\033[0m"
106
+ if self._stats:
107
+ header += f" \033[2m({self._stats})\033[0m"
108
+ lines.append(header)
109
+ # Last 2 tool calls, gray
110
+ visible = self._calls[-self._MAX_VISIBLE:]
111
  for desc in visible:
112
+ lines.append(f"{_I} \033[2m{desc}\033[0m")
113
+ for line in lines:
114
+ f.write(line + "\n")
115
  f.flush()
116
+ self._lines_on_screen = len(lines)
117
 
118
 
119
  _subagent_display = SubAgentDisplay()
 
122
  def print_tool_log(tool: str, log: str) -> None:
123
  """Handle tool log events — sub-agent calls get the rolling display."""
124
  if tool == "research":
125
+ if log.startswith("stats:"):
126
+ _subagent_display.set_stats(log[6:])
 
127
  elif log == "Research complete.":
128
  _subagent_display.clear()
129
  else:
130
+ _subagent_display.add_call(log)
131
  else:
132
  _console.print(f"{_I}[dim]{tool}: {log}[/dim]")
133