refactor: remove temporary API payload logging and enhance session log structure
- Eliminated the `_log_api_payload` method used for temporary debugging, streamlining the codebase. - Updated the `_save_session_log` method to save the full raw session, including all messages and metadata, improving the clarity and completeness of session logs. - Adjusted session log entry to include additional context such as `base_url` and `platform` for better tracking.
This commit is contained in:
parent
3976962621
commit
3555c6173d
1 changed files with 15 additions and 91 deletions
106
run_agent.py
106
run_agent.py
|
|
@ -2021,66 +2021,6 @@ class AIAgent:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"⚠️ Failed to save trajectory: {e}")
|
print(f"⚠️ Failed to save trajectory: {e}")
|
||||||
|
|
||||||
def _log_api_payload(self, turn_number: int, api_kwargs: Dict[str, Any], response=None):
|
|
||||||
"""
|
|
||||||
[TEMPORARY DEBUG] Log the full API payload and response token metrics
|
|
||||||
for each agent turn to a per-session JSONL file for inspection.
|
|
||||||
|
|
||||||
Writes one JSON line per turn to logs/payload_<session_id>.jsonl.
|
|
||||||
Tool schemas are summarized (just names) to keep logs readable.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
turn_number: Which API call this is (1-indexed)
|
|
||||||
api_kwargs: The full kwargs dict being passed to chat.completions.create
|
|
||||||
response: The API response object (optional, added after the call completes)
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
payload_log_file = self.logs_dir / f"payload_{self.session_id}.jsonl"
|
|
||||||
|
|
||||||
# Build a serializable copy of the request payload
|
|
||||||
payload = {
|
|
||||||
"turn": turn_number,
|
|
||||||
"timestamp": datetime.now().isoformat(),
|
|
||||||
"model": api_kwargs.get("model"),
|
|
||||||
"max_tokens": api_kwargs.get("max_tokens"),
|
|
||||||
"extra_body": api_kwargs.get("extra_body"),
|
|
||||||
"num_tools": len(api_kwargs.get("tools") or []),
|
|
||||||
"tool_names": [t["function"]["name"] for t in (api_kwargs.get("tools") or [])],
|
|
||||||
"messages": api_kwargs.get("messages", []),
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add response token metrics if available
|
|
||||||
if response is not None:
|
|
||||||
try:
|
|
||||||
usage_raw = response.usage.model_dump() if hasattr(response.usage, 'model_dump') else {}
|
|
||||||
payload["response"] = {
|
|
||||||
# Core token counts
|
|
||||||
"prompt_tokens": usage_raw.get("prompt_tokens"),
|
|
||||||
"completion_tokens": usage_raw.get("completion_tokens"),
|
|
||||||
"total_tokens": usage_raw.get("total_tokens"),
|
|
||||||
# Completion breakdown (reasoning tokens, etc.)
|
|
||||||
"completion_tokens_details": usage_raw.get("completion_tokens_details"),
|
|
||||||
# Prompt breakdown (cached tokens, etc.)
|
|
||||||
"prompt_tokens_details": usage_raw.get("prompt_tokens_details"),
|
|
||||||
# Cost tracking
|
|
||||||
"cost": usage_raw.get("cost"),
|
|
||||||
"is_byok": usage_raw.get("is_byok"),
|
|
||||||
"cost_details": usage_raw.get("cost_details"),
|
|
||||||
# Provider info (top-level field from OpenRouter)
|
|
||||||
"provider": getattr(response, 'provider', None),
|
|
||||||
"response_model": getattr(response, 'model', None),
|
|
||||||
}
|
|
||||||
except Exception:
|
|
||||||
payload["response"] = {"error": "failed to extract usage"}
|
|
||||||
|
|
||||||
with open(payload_log_file, "a", encoding="utf-8") as f:
|
|
||||||
f.write(json.dumps(payload, ensure_ascii=False, default=str) + "\n")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
# Silent fail - don't interrupt the agent for debug logging
|
|
||||||
if self.verbose_logging:
|
|
||||||
logging.warning(f"Failed to log API payload: {e}")
|
|
||||||
|
|
||||||
def _mask_api_key_for_logs(self, key: Optional[str]) -> Optional[str]:
|
def _mask_api_key_for_logs(self, key: Optional[str]) -> Optional[str]:
|
||||||
if not key:
|
if not key:
|
||||||
return None
|
return None
|
||||||
|
|
@ -2172,48 +2112,35 @@ class AIAgent:
|
||||||
|
|
||||||
def _save_session_log(self, messages: List[Dict[str, Any]] = None):
|
def _save_session_log(self, messages: List[Dict[str, Any]] = None):
|
||||||
"""
|
"""
|
||||||
Save the current session trajectory to the logs directory.
|
Save the full raw session to a JSON file.
|
||||||
|
|
||||||
Automatically called after each conversation turn to maintain
|
Stores every message exactly as the agent sees it: user messages,
|
||||||
a complete log of the session for debugging and inspection.
|
assistant messages (with reasoning, finish_reason, tool_calls),
|
||||||
|
tool responses (with tool_call_id, tool_name), and injected system
|
||||||
Args:
|
messages (compression summaries, todo snapshots, etc.).
|
||||||
messages: Message history to save (uses self._session_messages if not provided)
|
|
||||||
|
Overwritten after each turn so it always reflects the latest state.
|
||||||
"""
|
"""
|
||||||
messages = messages or self._session_messages
|
messages = messages or self._session_messages
|
||||||
if not messages:
|
if not messages:
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Extract the actual user query for the trajectory format.
|
|
||||||
# Skip prefill messages (they're ephemeral and shouldn't appear in trajectories)
|
|
||||||
# so the first user message we find is the real task prompt.
|
|
||||||
first_user_query = ""
|
|
||||||
start_idx = len(self.prefill_messages) if self.prefill_messages else 0
|
|
||||||
for msg in messages[start_idx:]:
|
|
||||||
if msg.get("role") == "user":
|
|
||||||
first_user_query = msg.get("content", "")
|
|
||||||
break
|
|
||||||
|
|
||||||
# Convert to trajectory format
|
|
||||||
trajectory = self._convert_to_trajectory_format(messages, first_user_query, True)
|
|
||||||
|
|
||||||
# Build the session log entry
|
|
||||||
entry = {
|
entry = {
|
||||||
"session_id": self.session_id,
|
"session_id": self.session_id,
|
||||||
"model": self.model,
|
"model": self.model,
|
||||||
|
"base_url": self.base_url,
|
||||||
|
"platform": self.platform,
|
||||||
"session_start": self.session_start.isoformat(),
|
"session_start": self.session_start.isoformat(),
|
||||||
"last_updated": datetime.now().isoformat(),
|
"last_updated": datetime.now().isoformat(),
|
||||||
"message_count": len(messages),
|
"message_count": len(messages),
|
||||||
"conversations": trajectory,
|
"messages": messages,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Write to session log file (overwrite with latest state)
|
|
||||||
with open(self.session_log_file, "w", encoding="utf-8") as f:
|
with open(self.session_log_file, "w", encoding="utf-8") as f:
|
||||||
json.dump(entry, f, indent=2, ensure_ascii=False)
|
json.dump(entry, f, indent=2, ensure_ascii=False, default=str)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Silent fail - don't interrupt the user experience for logging issues
|
|
||||||
if self.verbose_logging:
|
if self.verbose_logging:
|
||||||
logging.warning(f"Failed to save session log: {e}")
|
logging.warning(f"Failed to save session log: {e}")
|
||||||
|
|
||||||
|
|
@ -2584,9 +2511,6 @@ class AIAgent:
|
||||||
resp_model = getattr(response, 'model', 'N/A') if response else 'N/A'
|
resp_model = getattr(response, 'model', 'N/A') if response else 'N/A'
|
||||||
logging.debug(f"API Response received - Model: {resp_model}, Usage: {response.usage if hasattr(response, 'usage') else 'N/A'}")
|
logging.debug(f"API Response received - Model: {resp_model}, Usage: {response.usage if hasattr(response, 'usage') else 'N/A'}")
|
||||||
|
|
||||||
# [DEBUG] Log the full API payload + response token metrics
|
|
||||||
self._log_api_payload(api_call_count, api_kwargs, response=response)
|
|
||||||
|
|
||||||
# Validate response has valid choices before proceeding
|
# Validate response has valid choices before proceeding
|
||||||
if response is None or not hasattr(response, 'choices') or response.choices is None or len(response.choices) == 0:
|
if response is None or not hasattr(response, 'choices') or response.choices is None or len(response.choices) == 0:
|
||||||
# Stop spinner before printing error messages
|
# Stop spinner before printing error messages
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue