luisejdm commited on
Commit
9113b4c
·
1 Parent(s): 93d9662

Add agent file

Browse files
Files changed (1) hide show
  1. agent.py +106 -0
agent.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from model import ModelRunner
6
+ from parsing import parse_response
7
+ from tools import ToolRegistry
8
+ import time
9
+
10
+
11
+ @dataclass
12
+ class Agent:
13
+ runner: ModelRunner
14
+ tools: ToolRegistry
15
+ system_prompt: str
16
+
17
+ def run(
18
+ self,
19
+ task: str,
20
+ max_steps: int = 5,
21
+ temperature: float = 0.3,
22
+ verbose: bool = False,
23
+ ) -> tuple[str | None, list[dict]]:
24
+ messages = [
25
+ {"role": "system", "content": self.system_prompt},
26
+ {"role": "user", "content": task},
27
+ ]
28
+ trace: list[dict] = []
29
+
30
+ for step in range(1, max_steps + 1):
31
+ time.sleep(1.5)
32
+ response = self.runner.generate(messages, temperature=temperature)
33
+ if verbose:
34
+ print(f"[step {step}] {response}")
35
+ messages.append({"role": "assistant", "content": response})
36
+
37
+ kind, payload = parse_response(response)
38
+
39
+ if kind == "final":
40
+ tool_succeeded = any(
41
+ entry.get("type") == "action" for entry in trace
42
+ )
43
+ if not tool_succeeded:
44
+ trace.append({
45
+ "step": step,
46
+ "type": "blocked_final",
47
+ "content": payload,
48
+ })
49
+ messages.append({
50
+ "role": "user",
51
+ "content": (
52
+ "You cannot give a FINAL answer without first calling a tool. "
53
+ "Call the appropriate tool first before answering."
54
+ ),
55
+ })
56
+ continue
57
+ trace.append({"step": step, "type": "final", "content": payload})
58
+ return payload, trace
59
+
60
+ if kind == "action":
61
+ name, args = payload
62
+ try:
63
+ result = self.tools.execute(name, *args)
64
+ result_text = (
65
+ f"${float(result):.2f}"
66
+ if isinstance(result, (int, float))
67
+ else str(result)
68
+ )
69
+ observation = f"Tool result: {result_text}"
70
+ trace.append({
71
+ "step": step,
72
+ "type": "action",
73
+ "tool": name,
74
+ "args": args,
75
+ "result": result_text,
76
+ })
77
+ except KeyError as error:
78
+ observation = f"Error: {error}"
79
+ trace.append({
80
+ "step": step,
81
+ "type": "error",
82
+ "tool": name,
83
+ "args": args,
84
+ "error": str(error),
85
+ })
86
+ except Exception as error:
87
+ observation = f"Error: {error}"
88
+ trace.append({
89
+ "step": step,
90
+ "type": "error",
91
+ "tool": name,
92
+ "args": args,
93
+ "error": str(error),
94
+ })
95
+ messages.append({"role": "user", "content": observation})
96
+ else:
97
+ trace.append({"step": step, "type": "unknown", "raw": payload})
98
+ messages.append({
99
+ "role": "user",
100
+ "content": (
101
+ "Invalid format. Respond with exactly one line starting with "
102
+ "ACTION: tool_name(ARGS) or FINAL: <answer>."
103
+ ),
104
+ })
105
+
106
+ return None, trace