Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Commit ·
a96af97
1
Parent(s): 3d0a369
Live research stats: tool count, tokens, elapsed time in header
Browse files- agent/tools/research_tool.py +26 -1
- agent/utils/terminal_display.py +33 -16
agent/tools/research_tool.py
CHANGED
|
@@ -221,7 +221,25 @@ async def research_handler(
|
|
| 221 |
except Exception:
|
| 222 |
pass
|
| 223 |
|
| 224 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
"""
|
| 69 |
|
| 70 |
_MAX_VISIBLE = 2
|
| 71 |
|
| 72 |
def __init__(self):
|
| 73 |
self._calls: list[str] = []
|
|
|
|
| 74 |
self._lines_on_screen = 0
|
| 75 |
|
| 76 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
self._calls.append(tool_desc)
|
| 78 |
-
|
| 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
|
| 91 |
f = _console.file
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
for desc in visible:
|
| 96 |
-
|
|
|
|
|
|
|
| 97 |
f.flush()
|
| 98 |
-
self._lines_on_screen = len(
|
| 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
|
| 108 |
-
_subagent_display.
|
| 109 |
-
_console.print(f"{_I}[tool.name]▸ research[/tool.name]")
|
| 110 |
elif log == "Research complete.":
|
| 111 |
_subagent_display.clear()
|
| 112 |
else:
|
| 113 |
-
_subagent_display.
|
| 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 |
|