akseljoonas HF Staff commited on
Commit
93bf088
·
1 Parent(s): 63e9959
agent/core/agent_loop.py CHANGED
@@ -11,6 +11,7 @@ from litellm import (
11
  acompletion,
12
  )
13
 
 
14
  from agent.core.session import Event, OpType, Session
15
 
16
  ToolCall = ChatCompletionMessageToolCall
@@ -35,6 +36,7 @@ class Handlers:
35
  iteration = 0
36
  while iteration < max_iterations:
37
  messages = session.context_manager.get_messages()
 
38
 
39
  try:
40
  response: ModelResponse = await acompletion(
@@ -65,9 +67,12 @@ class Handlers:
65
  break
66
 
67
  for tool_call in tool_calls:
 
68
  result = await session.tool_executor.execute_tool(tool_call)
69
-
70
- tool_output = Message(role="tool", content=result.output)
 
 
71
  session.context_manager.add_message(tool_output)
72
 
73
  await session.send_event(
@@ -80,8 +85,13 @@ class Handlers:
80
  iteration += 1
81
 
82
  except Exception as e:
 
 
83
  await session.send_event(
84
- Event(event_type="error", data={"error": str(e)})
 
 
 
85
  )
86
  break
87
 
@@ -132,7 +142,9 @@ class Handlers:
132
 
133
 
134
  async def submission_loop(
135
- submission_queue: asyncio.Queue, event_queue: asyncio.Queue, config=None
 
 
136
  ) -> None:
137
  """
138
  Main agent loop - processes submissions and dispatches to handlers.
 
11
  acompletion,
12
  )
13
 
14
+ from agent.config import Config
15
  from agent.core.session import Event, OpType, Session
16
 
17
  ToolCall = ChatCompletionMessageToolCall
 
36
  iteration = 0
37
  while iteration < max_iterations:
38
  messages = session.context_manager.get_messages()
39
+ print(f"Messages: {messages}")
40
 
41
  try:
42
  response: ModelResponse = await acompletion(
 
67
  break
68
 
69
  for tool_call in tool_calls:
70
+ print(f"Executing tool: {tool_call.function.name}")
71
  result = await session.tool_executor.execute_tool(tool_call)
72
+ print(result)
73
+ tool_output = Message(
74
+ role="tool", content=result.output, success=result.success
75
+ )
76
  session.context_manager.add_message(tool_output)
77
 
78
  await session.send_event(
 
85
  iteration += 1
86
 
87
  except Exception as e:
88
+ import traceback
89
+
90
  await session.send_event(
91
+ Event(
92
+ event_type="error",
93
+ data={"error": traceback.print_exc() + str(e)},
94
+ )
95
  )
96
  break
97
 
 
142
 
143
 
144
  async def submission_loop(
145
+ submission_queue: asyncio.Queue,
146
+ event_queue: asyncio.Queue,
147
+ config: Config | None = None,
148
  ) -> None:
149
  """
150
  Main agent loop - processes submissions and dispatches to handlers.
agent/core/executor.py CHANGED
@@ -2,20 +2,26 @@
2
  Task execution engine
3
  """
4
 
5
- from typing import Any, Dict, List
6
 
7
  from litellm import ChatCompletionMessageToolCall
 
8
 
9
  ToolCall = ChatCompletionMessageToolCall
10
 
11
 
 
 
 
 
 
12
  class ToolExecutor:
13
  """Executes planned tasks using available tools"""
14
 
15
  def __init__(self, tools: List[Any] = None):
16
  self.tools = tools or []
17
 
18
- async def execute_tool(self, tool_call: ToolCall) -> Dict[str, Any]:
19
  """Execute a single step in the plan"""
20
  # TODO: Implement step execution
21
- return {"status": "success", "result": None}
 
2
  Task execution engine
3
  """
4
 
5
+ from typing import Any, List
6
 
7
  from litellm import ChatCompletionMessageToolCall
8
+ from pydantic import BaseModel
9
 
10
  ToolCall = ChatCompletionMessageToolCall
11
 
12
 
13
+ class ToolResult(BaseModel):
14
+ output: str
15
+ success: bool
16
+
17
+
18
  class ToolExecutor:
19
  """Executes planned tasks using available tools"""
20
 
21
  def __init__(self, tools: List[Any] = None):
22
  self.tools = tools or []
23
 
24
+ async def execute_tool(self, tool_call: ToolCall) -> ToolResult:
25
  """Execute a single step in the plan"""
26
  # TODO: Implement step execution
27
+ return ToolResult(output="", success=True)
agent/core/session.py CHANGED
@@ -4,9 +4,9 @@ from typing import Any, Literal
4
 
5
  from pydantic import BaseModel
6
 
 
7
  from agent.context_manager.manager import ContextManager
8
  from agent.core import ToolExecutor
9
- from agent.config import Config
10
 
11
 
12
  class OpType(Enum):
@@ -44,7 +44,9 @@ class Session:
44
  self.tool_executor = ToolExecutor()
45
  self.event_queue = event_queue
46
  self.config = config or Config(
47
- model_name="gpt-3.5-turbo", tools=[], system_prompt_path=""
 
 
48
  )
49
  self.is_running = True
50
  self.current_task: asyncio.Task | None = None
 
4
 
5
  from pydantic import BaseModel
6
 
7
+ from agent.config import Config
8
  from agent.context_manager.manager import ContextManager
9
  from agent.core import ToolExecutor
 
10
 
11
 
12
  class OpType(Enum):
 
44
  self.tool_executor = ToolExecutor()
45
  self.event_queue = event_queue
46
  self.config = config or Config(
47
+ model_name="anthropic/claude-sonnet-4-5-20250929",
48
+ tools=[],
49
+ system_prompt_path="",
50
  )
51
  self.is_running = True
52
  self.current_task: asyncio.Task | None = None
agent/main.py CHANGED
@@ -1,11 +1,12 @@
1
  """
2
- Simple runner for the agent with a single dummy input
3
  """
4
 
5
  import asyncio
6
  from dataclasses import dataclass
7
  from typing import Any, Optional
8
 
 
9
  from agent.core.agent_loop import submission_loop
10
  from agent.core.session import OpType
11
 
@@ -26,63 +27,127 @@ class Submission:
26
  operation: Operation
27
 
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  async def main():
30
- """Run agent with a single dummy input"""
31
 
32
- print("🚀 Starting agent...")
 
 
 
33
 
34
  # Create queues for communication
35
  submission_queue = asyncio.Queue()
36
  event_queue = asyncio.Queue()
37
 
 
 
 
 
38
  # Start agent loop in background
39
- agent_task = asyncio.create_task(submission_loop(submission_queue, event_queue))
40
-
41
- # Wait a moment for agent to initialize
42
- await asyncio.sleep(0.1)
43
-
44
- # Submit dummy input
45
- print("\n📝 Submitting dummy input...")
46
- dummy_submission = Submission(
47
- id="sub_1",
48
- operation=Operation(
49
- op_type=OpType.USER_INPUT,
50
- data={"text": "Hello! What tools do you have available?"},
51
- ),
52
  )
53
- await submission_queue.put(dummy_submission)
54
 
55
- # Listen for events
56
- print("\n👂 Listening for events...\n")
57
- events_received = 0
58
- max_events = 10 # Safety limit
59
 
60
- while events_received < max_events:
61
- try:
62
- event = await asyncio.wait_for(event_queue.get(), timeout=2.0)
63
- events_received += 1
64
 
65
- # Display event
66
- if event.event_type == "assistant_message":
67
- msg = event.data.get("message", {})
68
- content = msg.get("content", "")
69
- print(f"🤖 Assistant: {content}")
70
- elif event.event_type == "tool_output":
71
- msg = event.data.get("message", {})
72
- content = msg.get("content", "")
73
- print(f"🔧 Tool output: {content}")
74
- elif event.event_type == "turn_complete":
75
- print(f"✅ Turn complete: {event.data}")
 
76
  break
77
- elif event.event_type == "error":
78
- print(f"❌ Error: {event.data}")
 
79
  break
80
- else:
81
- print(f"📨 Event: {event.event_type} - {event.data}")
82
 
83
- except asyncio.TimeoutError:
84
- print("⏱️ No more events, timing out...")
85
- break
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
  # Shutdown
88
  print("\n🛑 Shutting down agent...")
@@ -91,18 +156,15 @@ async def main():
91
  )
92
  await submission_queue.put(shutdown_submission)
93
 
94
- # Wait for shutdown event
95
- try:
96
- event = await asyncio.wait_for(event_queue.get(), timeout=1.0)
97
- print(f"✅ {event.event_type}")
98
- except asyncio.TimeoutError:
99
- pass
100
 
101
- # Wait for agent task to complete
102
- await agent_task
103
-
104
- print("\n✨ Done!")
105
 
106
 
107
  if __name__ == "__main__":
108
- asyncio.run(main())
 
 
 
 
1
  """
2
+ Interactive CLI chat with the agent
3
  """
4
 
5
  import asyncio
6
  from dataclasses import dataclass
7
  from typing import Any, Optional
8
 
9
+ from agent.config import Config
10
  from agent.core.agent_loop import submission_loop
11
  from agent.core.session import OpType
12
 
 
27
  operation: Operation
28
 
29
 
30
+ async def event_listener(
31
+ event_queue: asyncio.Queue, turn_complete_event: asyncio.Event
32
+ ) -> None:
33
+ """Background task that listens for events and displays them"""
34
+ while True:
35
+ try:
36
+ event = await event_queue.get()
37
+
38
+ # Display event
39
+ if event.event_type == "assistant_message":
40
+ msg = event.data.get("message", {})
41
+ content = msg.get("content", "")
42
+ if content:
43
+ print(f"\n🤖 Assistant: {content}")
44
+ elif event.event_type == "tool_output":
45
+ msg = event.data.get("message", {})
46
+ content = msg.get("content", "")
47
+ if content:
48
+ print(
49
+ f"🔧 Tool: {content[:200]}{'...' if len(content) > 200 else ''}"
50
+ )
51
+ elif event.event_type == "turn_complete":
52
+ print("✅ Turn complete\n")
53
+ turn_complete_event.set()
54
+ elif event.event_type == "error":
55
+ import traceback
56
+
57
+ traceback.print_exc()
58
+ print(f"❌ Error: {event.data.get('error', 'Unknown error')}")
59
+ turn_complete_event.set()
60
+ elif event.event_type == "shutdown":
61
+ print("🛑 Agent shutdown")
62
+ break
63
+ elif event.event_type == "processing":
64
+ print("⏳ Processing...", flush=True)
65
+ # Silently ignore other events
66
+
67
+ except asyncio.CancelledError:
68
+ break
69
+ except Exception as e:
70
+ print(f"⚠️ Event listener error: {e}")
71
+
72
+
73
+ async def get_user_input() -> str:
74
+ """Get user input asynchronously"""
75
+ loop = asyncio.get_event_loop()
76
+ return await loop.run_in_executor(None, input, "You: ")
77
+
78
+
79
  async def main():
80
+ """Interactive chat with the agent"""
81
 
82
+ print("=" * 60)
83
+ print("🤖 Interactive Agent Chat")
84
+ print("=" * 60)
85
+ print("Type your messages below. Type 'exit', 'quit', or '/quit' to end.\n")
86
 
87
  # Create queues for communication
88
  submission_queue = asyncio.Queue()
89
  event_queue = asyncio.Queue()
90
 
91
+ # Event to signal turn completion
92
+ turn_complete_event = asyncio.Event()
93
+ turn_complete_event.set() # Ready for first input
94
+
95
  # Start agent loop in background
96
+ agent_task = asyncio.create_task(
97
+ submission_loop(
98
+ submission_queue,
99
+ event_queue,
100
+ config=Config(
101
+ model_name="anthropic/claude-sonnet-4-5-20250929",
102
+ tools=[],
103
+ system_prompt_path="",
104
+ ),
105
+ )
 
 
 
106
  )
 
107
 
108
+ # Start event listener in background
109
+ listener_task = asyncio.create_task(
110
+ event_listener(event_queue, turn_complete_event)
111
+ )
112
 
113
+ # Wait for agent to initialize
114
+ await asyncio.sleep(0.2)
 
 
115
 
116
+ submission_id = 0
117
+
118
+ try:
119
+ while True:
120
+ # Wait for previous turn to complete
121
+ await turn_complete_event.wait()
122
+ turn_complete_event.clear()
123
+
124
+ # Get user input
125
+ try:
126
+ user_input = await get_user_input()
127
+ except EOFError:
128
  break
129
+
130
+ # Check for exit commands
131
+ if user_input.strip().lower() in ["exit", "quit", "/quit", "/exit"]:
132
  break
 
 
133
 
134
+ # Skip empty input
135
+ if not user_input.strip():
136
+ turn_complete_event.set()
137
+ continue
138
+
139
+ # Submit to agent
140
+ submission_id += 1
141
+ submission = Submission(
142
+ id=f"sub_{submission_id}",
143
+ operation=Operation(
144
+ op_type=OpType.USER_INPUT, data={"text": user_input}
145
+ ),
146
+ )
147
+ await submission_queue.put(submission)
148
+
149
+ except KeyboardInterrupt:
150
+ print("\n\n⚠️ Interrupted by user")
151
 
152
  # Shutdown
153
  print("\n🛑 Shutting down agent...")
 
156
  )
157
  await submission_queue.put(shutdown_submission)
158
 
159
+ # Wait for tasks to complete
160
+ await asyncio.wait_for(agent_task, timeout=2.0)
161
+ listener_task.cancel()
 
 
 
162
 
163
+ print("✨ Goodbye!\n")
 
 
 
164
 
165
 
166
  if __name__ == "__main__":
167
+ try:
168
+ asyncio.run(main())
169
+ except KeyboardInterrupt:
170
+ print("\n\n✨ Goodbye!")