Skip to content
This repository was archived by the owner on Feb 16, 2026. It is now read-only.

Commit b68f09d

Browse files
maidacundoArslanSaleemellipsis-dev[bot]
authored
fix: shell_exec tools (#33)
* fix: add lib folder and remove from gitignore * refactor: streamline backend structure and enhance logging - Removed commented-out code and unnecessary imports in main.py for clarity. - Updated logging levels from info to debug in agent.py and panda_agi_client.py for more granular logging. - Refactored token_processor.py to improve error handling and streamline token processing logic. - Introduced ShellOutput model in shell_ops.py to standardize command execution results and improve error reporting. - Updated shell command functions to return ShellOutput, enhancing consistency across shell operations. - Cleaned up event handling in shell tools to remove commented-out event logging. * fix: python code execution in execute_script * fix: remove 'Z' suffix from timestamp generation - Modified the timestamp generation in panda_agi/client/agent.py at line 522 by removing the 'Z' suffix. Changed 'end_timestamp = datetime.now().isoformat() + "Z"' to 'end_timestamp = datetime.now().isoformat()'. * fix: Removed JSONDecodeError --------- Co-authored-by: ArslanSaleem <khan.arslan38@gmail.com> Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
1 parent 768bb1a commit b68f09d

9 files changed

Lines changed: 255 additions & 270 deletions

File tree

examples/ui/backend/main.py

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,16 @@
55
import logging
66
import os
77
import sys
8+
89
from dotenv import load_dotenv
910
from fastapi import FastAPI
1011
from fastapi.middleware.cors import CORSMiddleware
11-
from panda_agi.envs.e2b_env import E2BEnv
12-
import asyncio
12+
from middleware.auth import AuthMiddleware
13+
from routes import agent, auth, conversation, files, health
1314

1415
# Load environment variables from .env file
1516
load_dotenv()
1617

17-
18-
# sandbox = E2BEnv.get_active_sandbox(
19-
# {"conversation_id": "92e5bbdc-c102-45dc-a7df-4fe8e9ef0b5c"}
20-
# )
21-
# env = E2BEnv("/workspace", timeout=100, sandbox=sandbox)
22-
23-
# print(
24-
# "list_files::: -> ",
25-
# asyncio.run(env.path_exists("/images/artistic_panda_portrait.png")),
26-
# )
27-
28-
# Await the async list_files call using asyncio.run
29-
# print(
30-
# "list_files::: -> ",
31-
# asyncio.run(env.mkdir("/workspace/test1", parents=True, exist_ok=True)),
32-
# )
33-
34-
# print("list_files::: -> ", asyncio.run(env.list_files("/workspace", recursive=True)))
35-
36-
37-
# # Add parent directory to path for imports
38-
# sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))
39-
40-
# Import routes
41-
from routes import agent, auth, conversation, files, health
42-
43-
# Import middleware
44-
from middleware.auth import AuthMiddleware
45-
4618
# Configure logging with more explicit settings
4719
logging.basicConfig(
4820
level=logging.DEBUG,

examples/ui/backend/services/chat_env.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from e2b.api.client.models import sandbox
1+
import os
2+
from typing import Any, Dict, Optional
3+
24
from panda_agi.envs import E2BEnv
35
from panda_agi.envs.local_env import LocalEnv
4-
import os
5-
from typing import Dict, Any, Optional
66

77
WORKSPACE_PATH = os.getenv("WORKSPACE_PATH", "./workspace")
88

panda_agi/client/agent.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ async def run_stream(
347347
token_stream
348348
):
349349
if processed_event.get("type") == "conversation_id":
350-
logger.info(
350+
logger.debug(
351351
f"Received conversation_id: {processed_event.get('conversation_id')}"
352352
)
353353
self.conversation_id = processed_event.get("conversation_id")
@@ -519,7 +519,7 @@ async def _handle_tool_execution(
519519
result = await handler.execute(arguments)
520520

521521
# Generate timestamp for tool end
522-
end_timestamp = datetime.utcnow().isoformat() + "Z"
522+
end_timestamp = datetime.now().isoformat()
523523

524524
# Yield tool end event or error event
525525
if result.success:
@@ -636,7 +636,7 @@ async def _execute_collected_tools_and_yield_events(
636636
result = await handler.execute(arguments)
637637

638638
# Generate timestamp for tool end
639-
end_timestamp = datetime.utcnow().isoformat() + "Z"
639+
end_timestamp = datetime.now().isoformat() + "Z"
640640

641641
if result.success:
642642
yield {

panda_agi/client/panda_agi_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ async def send_streaming_request(
115115
# check if chunk is conversation_id
116116
if self.is_chunk_conversation_id(chunk):
117117
self.conversation_id = self._extract_conversation_id(chunk)
118-
logger.info(
118+
logger.debug(
119119
f"[HTTP] Received conversation_id: {self.conversation_id}"
120120
)
121121
yield {

panda_agi/client/token_processor.py

Lines changed: 4 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -66,62 +66,15 @@ async def process_token_stream(
6666
)
6767
)
6868

69-
# Try to parse JSON if the token looks like JSON
7069
try:
71-
token_data = json.loads(token)
72-
73-
# Extract content if it's a structured response
74-
if isinstance(token_data, dict):
75-
content = self._extract_content(token_data)
76-
if content:
77-
self.accumulated_content += content
78-
self.xml_buffer += content
79-
80-
# Check for XML tool calls in the buffer and yield tool events
81-
async for (
82-
tool_event
83-
) in self._process_xml_tools_and_yield_events(content):
84-
logger.info(f"Yielding XML tool call: {tool_event}")
85-
yield tool_event
86-
87-
# Yield structured event
88-
yield {
89-
"type": "token",
90-
"raw_token": token,
91-
"parsed_data": token_data,
92-
"content": content,
93-
"accumulated_content": self.accumulated_content,
94-
}
95-
else:
96-
# Handle non-dict JSON data
97-
self.accumulated_content += str(token_data)
98-
self.xml_buffer += str(token_data)
99-
100-
# Check for XML tool calls and yield tool events
101-
async for (
102-
tool_event
103-
) in self._process_xml_tools_and_yield_events(str(token_data)):
104-
logger.info(f"Yielding XML tool call: {tool_event}")
105-
yield tool_event
106-
107-
yield {
108-
"type": "token",
109-
"raw_token": token,
110-
"parsed_data": token_data,
111-
"content": str(token_data),
112-
"accumulated_content": self.accumulated_content,
113-
}
114-
115-
except json.JSONDecodeError:
116-
# Handle plain text tokens
11770
self.accumulated_content += token
11871
self.xml_buffer += token
11972

12073
# Check for XML tool calls and yield tool events
12174
async for tool_event in self._process_xml_tools_and_yield_events(
12275
token
12376
):
124-
logger.info(f"Yielding XML tool call: {tool_event}")
77+
logger.debug(f"Yielding XML tool call: {tool_event}")
12578
yield tool_event
12679

12780
yield {
@@ -132,6 +85,9 @@ async def process_token_stream(
13285
"accumulated_content": self.accumulated_content,
13386
}
13487

88+
except Exception as e:
89+
logger.error(f"Error processing token: {e}")
90+
13591
except Exception as e:
13692
logger.error(f"Error processing token stream: {e}")
13793
raise e

panda_agi/envs/e2b_env.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
from typing import Any, Dict, List, Optional, Union
44

55
try:
6-
from e2b.sandbox_sync.sandbox_api import SandboxQuery
76
from e2b.sandbox.filesystem.filesystem import FileType
7+
from e2b.sandbox_sync.sandbox_api import SandboxQuery
88
from e2b_code_interpreter import Sandbox
99
except ImportError:
1010
Sandbox = None

panda_agi/tools/base.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,10 @@ def validate_input(self, params: Dict[str, Any]) -> Optional[str]:
7777
async def send_response(self, msg_id: str, result: ToolResult) -> None:
7878
"""Send standardized response message"""
7979

80-
if (
81-
not self.agent
82-
or not self.agent.client
83-
or not self.agent.client.is_connected
84-
):
80+
if not self.agent or not self.agent.client:
8581
self.logger.warning("Cannot send response: agent not connected")
8682
return
8783

88-
# For HTTP-based communication, we'll handle responses differently
89-
# This method is kept for backward compatibility but may need to be updated
90-
# based on the new HTTP streaming architecture
91-
9284
try:
9385
# Log the result for now - in HTTP streaming, tool results are handled differently
9486
self.logger.info(f"Tool result for {self.__class__.__name__}: {result}")

0 commit comments

Comments
 (0)