55
66import re
77import time
8- from typing import Any , Dict , List , Optional , Union
8+ from typing import TYPE_CHECKING , Any , Dict , List , Optional , Union
99
1010from .actions import click , press , type_text
1111from .base_agent import BaseAgent
2323)
2424from .snapshot import snapshot
2525
26+ if TYPE_CHECKING :
27+ from .agent_config import AgentConfig
28+ from .tracing import Tracer
29+
2630
2731class SentienceAgent (BaseAgent ):
2832 """
@@ -54,6 +58,8 @@ def __init__(
5458 llm : LLMProvider ,
5559 default_snapshot_limit : int = 50 ,
5660 verbose : bool = True ,
61+ tracer : Optional ["Tracer" ] = None ,
62+ config : Optional ["AgentConfig" ] = None ,
5763 ):
5864 """
5965 Initialize Sentience Agent
@@ -63,11 +69,15 @@ def __init__(
6369 llm: LLM provider (OpenAIProvider, AnthropicProvider, etc.)
6470 default_snapshot_limit: Default maximum elements to include in context (default: 50)
6571 verbose: Print execution logs (default: True)
72+ tracer: Optional Tracer instance for execution tracking (default: None)
73+ config: Optional AgentConfig for advanced configuration (default: None)
6674 """
6775 self .browser = browser
6876 self .llm = llm
6977 self .default_snapshot_limit = default_snapshot_limit
7078 self .verbose = verbose
79+ self .tracer = tracer
80+ self .config = config
7181
7282 # Execution history
7383 self .history : list [dict [str , Any ]] = []
@@ -80,6 +90,9 @@ def __init__(
8090 "by_action" : [],
8191 }
8292
93+ # Step counter for tracing
94+ self ._step_count = 0
95+
8396 def act (
8497 self , goal : str , max_retries : int = 2 , snapshot_options : SnapshotOptions | None = None
8598 ) -> AgentActionResult :
@@ -107,6 +120,21 @@ def act(
107120 print (f"🤖 Agent Goal: { goal } " )
108121 print (f"{ '=' * 70 } " )
109122
123+ # Generate step ID for tracing
124+ self ._step_count += 1
125+ step_id = f"step-{ self ._step_count } "
126+
127+ # Emit step_start trace event if tracer is enabled
128+ if self .tracer :
129+ pre_url = self .browser .page .url if self .browser .page else None
130+ self .tracer .emit_step_start (
131+ step_id = step_id ,
132+ step_index = self ._step_count ,
133+ goal = goal ,
134+ attempt = 0 ,
135+ pre_url = pre_url ,
136+ )
137+
110138 for attempt in range (max_retries + 1 ):
111139 try :
112140 # 1. OBSERVE: Get refined semantic snapshot
@@ -135,6 +163,18 @@ def act(
135163 if snap .status != "success" :
136164 raise RuntimeError (f"Snapshot failed: { snap .error } " )
137165
166+ # Emit snapshot trace event if tracer is enabled
167+ if self .tracer :
168+ self .tracer .emit (
169+ "snapshot" ,
170+ {
171+ "url" : snap .url ,
172+ "element_count" : len (snap .elements ),
173+ "timestamp" : snap .timestamp ,
174+ },
175+ step_id = step_id ,
176+ )
177+
138178 # Apply element filtering based on goal
139179 filtered_elements = self .filter_elements (snap , goal )
140180
@@ -156,6 +196,19 @@ def act(
156196 # 3. THINK: Query LLM for next action
157197 llm_response = self ._query_llm (context , goal )
158198
199+ # Emit LLM query trace event if tracer is enabled
200+ if self .tracer :
201+ self .tracer .emit (
202+ "llm_query" ,
203+ {
204+ "prompt_tokens" : llm_response .prompt_tokens ,
205+ "completion_tokens" : llm_response .completion_tokens ,
206+ "model" : llm_response .model ,
207+ "response" : llm_response .content [:200 ], # Truncate for brevity
208+ },
209+ step_id = step_id ,
210+ )
211+
159212 if self .verbose :
160213 print (f"🧠 LLM Decision: { llm_response .content } " )
161214
@@ -186,6 +239,22 @@ def act(
186239 message = result_dict .get ("message" ),
187240 )
188241
242+ # Emit action execution trace event if tracer is enabled
243+ if self .tracer :
244+ post_url = self .browser .page .url if self .browser .page else None
245+ self .tracer .emit (
246+ "action" ,
247+ {
248+ "action" : result .action ,
249+ "element_id" : result .element_id ,
250+ "success" : result .success ,
251+ "outcome" : result .outcome ,
252+ "duration_ms" : duration_ms ,
253+ "post_url" : post_url ,
254+ },
255+ step_id = step_id ,
256+ )
257+
189258 # 5. RECORD: Track history
190259 self .history .append (
191260 {
@@ -202,9 +271,25 @@ def act(
202271 status = "✅" if result .success else "❌"
203272 print (f"{ status } Completed in { duration_ms } ms" )
204273
274+ # Emit step completion trace event if tracer is enabled
275+ if self .tracer :
276+ self .tracer .emit (
277+ "step_end" ,
278+ {
279+ "success" : result .success ,
280+ "duration_ms" : duration_ms ,
281+ "action" : result .action ,
282+ },
283+ step_id = step_id ,
284+ )
285+
205286 return result
206287
207288 except Exception as e :
289+ # Emit error trace event if tracer is enabled
290+ if self .tracer :
291+ self .tracer .emit_error (step_id = step_id , error = str (e ), attempt = attempt )
292+
208293 if attempt < max_retries :
209294 if self .verbose :
210295 print (f"⚠️ Retry { attempt + 1 } /{ max_retries } : { e } " )
0 commit comments