mirror of
https://github.com/usestrix/strix.git
synced 2026-09-13 23:11:07 +00:00
Merge 7a4c00872b into 8841294d94
This commit is contained in:
commit
12597e1739
5 changed files with 84 additions and 9 deletions
|
|
@ -334,6 +334,13 @@ class BaseAgent(metaclass=AgentMeta):
|
|||
sandbox_mode = os.getenv("STRIX_SANDBOX_MODE", "false").lower() == "true"
|
||||
if not sandbox_mode and self.state.sandbox_id is None:
|
||||
from strix.runtime import get_runtime
|
||||
from strix.telemetry.tracer import get_global_tracer
|
||||
|
||||
tracer = get_global_tracer()
|
||||
if tracer:
|
||||
tracer.update_agent_system_message(
|
||||
self.state.agent_id, "Setting up sandbox environment..."
|
||||
)
|
||||
|
||||
try:
|
||||
runtime = get_runtime()
|
||||
|
|
@ -368,6 +375,9 @@ class BaseAgent(metaclass=AgentMeta):
|
|||
async def _process_iteration(self, tracer: Optional["Tracer"]) -> bool | None:
|
||||
final_response = None
|
||||
|
||||
if tracer:
|
||||
tracer.update_agent_system_message(self.state.agent_id, "Thinking...")
|
||||
|
||||
async for response in self.llm.generate(self.state.get_conversation_history()):
|
||||
final_response = response
|
||||
if tracer and response.content:
|
||||
|
|
@ -409,8 +419,19 @@ class BaseAgent(metaclass=AgentMeta):
|
|||
)
|
||||
|
||||
if actions:
|
||||
if tracer:
|
||||
tool_names = [a.get("toolName") or a.get("tool_name") or "tool" for a in actions]
|
||||
display_names = tool_names[:2]
|
||||
overflow = len(tool_names) - 2
|
||||
suffix = f" +{overflow} more" if overflow > 0 else ""
|
||||
tracer.update_agent_system_message(
|
||||
self.state.agent_id, f"Executing {', '.join(display_names)}{suffix}..."
|
||||
)
|
||||
return await self._execute_actions(actions, tracer)
|
||||
|
||||
if tracer:
|
||||
tracer.update_agent_system_message(self.state.agent_id, "Processing response...")
|
||||
|
||||
return None
|
||||
|
||||
async def _execute_actions(self, actions: list[Any], tracer: Optional["Tracer"]) -> bool:
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ class ThinkRenderer(BaseToolRenderer):
|
|||
text.append("\n ")
|
||||
|
||||
if thought:
|
||||
text.append(thought, style="italic dim")
|
||||
indented_thought = "\n ".join(thought.split("\n"))
|
||||
text.append(indented_thought, style="italic dim")
|
||||
else:
|
||||
text.append("Thinking...", style="italic dim")
|
||||
|
||||
|
|
|
|||
|
|
@ -1243,14 +1243,19 @@ class StrixTUIApp(App): # type: ignore[misc]
|
|||
return (Text(" "), keymap, False)
|
||||
|
||||
if status == "running":
|
||||
sys_msg = agent_data.get("system_message", "")
|
||||
if self._agent_has_real_activity(agent_id):
|
||||
animated_text = Text()
|
||||
animated_text.append_text(self._get_sweep_animation(self._sweep_colors))
|
||||
if sys_msg:
|
||||
animated_text.append(sys_msg, style="dim italic")
|
||||
animated_text.append(" ", style="dim")
|
||||
animated_text.append("esc", style="white")
|
||||
animated_text.append(" ", style="dim")
|
||||
animated_text.append("stop", style="dim")
|
||||
return (animated_text, keymap_styled([("ctrl-q", "quit")]), True)
|
||||
animated_text = self._get_animated_verb_text(agent_id, "Initializing")
|
||||
msg = sys_msg or "Initializing..."
|
||||
animated_text = self._get_animated_verb_text(agent_id, msg)
|
||||
return (animated_text, keymap_styled([("ctrl-q", "quit")]), True)
|
||||
|
||||
return (None, Text(), False)
|
||||
|
|
@ -1683,21 +1688,46 @@ class StrixTUIApp(App): # type: ignore[misc]
|
|||
content = msg_data.get("content", "")
|
||||
metadata = msg_data.get("metadata", {})
|
||||
|
||||
if not content:
|
||||
return None
|
||||
|
||||
if role == "user":
|
||||
if not content:
|
||||
return None
|
||||
return UserMessageRenderer.render_simple(content)
|
||||
|
||||
renderables = []
|
||||
|
||||
if "thinking_blocks" in metadata and metadata["thinking_blocks"]:
|
||||
from strix.interface.tool_components.thinking_renderer import ThinkRenderer
|
||||
|
||||
for block in metadata["thinking_blocks"]:
|
||||
thought = block.get("thinking", "")
|
||||
if thought:
|
||||
renderables.append(
|
||||
ThinkRenderer.render({"args": {"thought": thought}}).renderable
|
||||
)
|
||||
|
||||
if not content and not renderables:
|
||||
return None
|
||||
|
||||
if metadata.get("interrupted"):
|
||||
streaming_result = self._render_streaming_content(content)
|
||||
interrupted_text = Text()
|
||||
interrupted_text.append("\n")
|
||||
interrupted_text.append("⚠ ", style="yellow")
|
||||
interrupted_text.append("Interrupted by user", style="yellow dim")
|
||||
return self._merge_renderables([streaming_result, interrupted_text])
|
||||
return self._merge_renderables([*renderables, streaming_result, interrupted_text])
|
||||
|
||||
return AgentMessageRenderer.render_simple(content)
|
||||
if content:
|
||||
msg_renderable = AgentMessageRenderer.render_simple(content)
|
||||
renderables.append(msg_renderable)
|
||||
|
||||
if not renderables:
|
||||
return None
|
||||
|
||||
if len(renderables) == 1:
|
||||
r = renderables[0]
|
||||
return self._sanitize_text(r) if isinstance(r, Text) else r
|
||||
|
||||
return self._merge_renderables(renderables)
|
||||
|
||||
def _render_tool_content_simple(self, tool_data: dict[str, Any]) -> Any:
|
||||
tool_name = tool_data.get("tool_name", "Unknown Tool")
|
||||
|
|
|
|||
|
|
@ -156,12 +156,21 @@ class LLM:
|
|||
async def generate(
|
||||
self, conversation_history: list[dict[str, Any]]
|
||||
) -> AsyncIterator[LLMResponse]:
|
||||
from strix.telemetry.tracer import get_global_tracer
|
||||
|
||||
tracer = get_global_tracer()
|
||||
if tracer and self.agent_id:
|
||||
tracer.update_agent_system_message(self.agent_id, "Compressing memory...")
|
||||
|
||||
messages = self._prepare_messages(conversation_history)
|
||||
max_retries = int(Config.get("strix_llm_max_retries") or "5")
|
||||
|
||||
for attempt in range(max_retries + 1):
|
||||
try:
|
||||
async for response in self._stream(messages):
|
||||
if tracer and self.agent_id:
|
||||
tracer.update_agent_system_message(self.agent_id, "Waiting for LLM provider...")
|
||||
|
||||
async for response in self._stream(messages, tracer):
|
||||
yield response
|
||||
return # noqa: TRY300
|
||||
except Exception as e: # noqa: BLE001
|
||||
|
|
@ -170,15 +179,23 @@ class LLM:
|
|||
wait = min(90, 2 * (2**attempt))
|
||||
await asyncio.sleep(wait)
|
||||
|
||||
async def _stream(self, messages: list[dict[str, Any]]) -> AsyncIterator[LLMResponse]:
|
||||
async def _stream(
|
||||
self, messages: list[dict[str, Any]], tracer: Any = None
|
||||
) -> AsyncIterator[LLMResponse]:
|
||||
accumulated = ""
|
||||
chunks: list[Any] = []
|
||||
done_streaming = 0
|
||||
first_chunk_received = False
|
||||
|
||||
self._total_stats.requests += 1
|
||||
response = await acompletion(**self._build_completion_args(messages), stream=True)
|
||||
|
||||
async for chunk in response:
|
||||
if not first_chunk_received:
|
||||
first_chunk_received = True
|
||||
if tracer and self.agent_id:
|
||||
tracer.update_agent_system_message(self.agent_id, "Generating response...")
|
||||
|
||||
chunks.append(chunk)
|
||||
if done_streaming:
|
||||
done_streaming += 1
|
||||
|
|
|
|||
|
|
@ -439,6 +439,7 @@ class Tracer:
|
|||
"name": name,
|
||||
"task": task,
|
||||
"status": "running",
|
||||
"system_message": "",
|
||||
"parent_id": parent_id,
|
||||
"created_at": datetime.now(UTC).isoformat(),
|
||||
"updated_at": datetime.now(UTC).isoformat(),
|
||||
|
|
@ -587,6 +588,11 @@ class Tracer:
|
|||
source="strix.agents",
|
||||
)
|
||||
|
||||
def update_agent_system_message(self, agent_id: str, message: str) -> None:
|
||||
if agent_id in self.agents:
|
||||
self.agents[agent_id]["system_message"] = message
|
||||
self.agents[agent_id]["updated_at"] = datetime.now(UTC).isoformat()
|
||||
|
||||
def set_scan_config(self, config: dict[str, Any]) -> None:
|
||||
self.scan_config = config
|
||||
self.run_metadata.update(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue