fix: use lazy logging with %s formatting in logger calls
Replace f-string interpolation in logger calls with lazy %-style formatting across 10 files (38 instances). This follows Python logging best practices — the message is only formatted if the log level is enabled, avoiding unnecessary string concatenation overhead. Files changed: - trajectory_compressor.py (6) - mini_swe_runner.py (2) - agent/tool_executor.py (1) - agent/model_metadata.py (1) - agent/agent_runtime_helpers.py (3) - agent/chat_completion_helpers.py (3) - agent/conversation_loop.py (8) - tools/skills_hub.py (2) - tools/environments/docker.py (10) - gateway/kanban_watchers.py (2)
This commit is contained in:
parent
2bf2bc141d
commit
9eb8e20c68
|
|
@ -151,7 +151,7 @@ def convert_to_trajectory_format(agent, messages: List[Dict[str, Any]], user_que
|
|||
except json.JSONDecodeError:
|
||||
# This shouldn't happen since we validate and retry during conversation,
|
||||
# but if it does, log warning and use empty dict
|
||||
logger.warning(f"Unexpected invalid JSON in trajectory conversion: {tool_call['function']['arguments'][:100]}")
|
||||
logger.warning("Unexpected invalid JSON in trajectory conversion: %s", tool_call['function']['arguments'][:100])
|
||||
arguments = {}
|
||||
|
||||
tool_call_json = {
|
||||
|
|
@ -1210,7 +1210,7 @@ def recover_with_credential_pool(
|
|||
refreshed_id,
|
||||
)
|
||||
return False, has_retried_429
|
||||
_ra().logger.info(f"Credential auth failure — refreshed pool entry {getattr(refreshed, 'id', '?')}")
|
||||
_ra().logger.info("Credential auth failure — refreshed pool entry %s", getattr(refreshed, 'id', '?'))
|
||||
agent._swap_credential(refreshed)
|
||||
return True, has_retried_429
|
||||
# Refresh failed — rotate to next credential instead of giving up.
|
||||
|
|
@ -1835,7 +1835,7 @@ def dump_api_request_debug(
|
|||
return dump_file
|
||||
except Exception as dump_error:
|
||||
if agent.verbose_logging:
|
||||
logger.warning(f"Failed to dump API request debug payload: {dump_error}")
|
||||
logger.warning("Failed to dump API request debug payload: %s", dump_error)
|
||||
return None
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2383,7 +2383,7 @@ def handle_max_iterations(agent, messages: list, api_call_count: int) -> str:
|
|||
final_response = "I reached the iteration limit and couldn't generate a summary."
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to get summary response: {e}")
|
||||
logger.warning("Failed to get summary response: %s", e)
|
||||
final_response = f"I reached the maximum iterations ({agent.max_iterations}) but couldn't summarize. Error: {str(e)}"
|
||||
finally:
|
||||
from agent import relay_llm
|
||||
|
|
@ -2424,7 +2424,7 @@ def cleanup_task_resources(agent, task_id: str) -> None:
|
|||
_ra().cleanup_vm(task_id)
|
||||
except Exception as e:
|
||||
if agent.verbose_logging:
|
||||
logger.warning(f"Failed to cleanup VM for task {task_id}: {e}")
|
||||
logger.warning("Failed to cleanup VM for task %s: %s", task_id, e)
|
||||
try:
|
||||
headed = False
|
||||
try:
|
||||
|
|
@ -2442,7 +2442,7 @@ def cleanup_task_resources(agent, task_id: str) -> None:
|
|||
_ra().cleanup_browser(task_id)
|
||||
except Exception as e:
|
||||
if agent.verbose_logging:
|
||||
logger.warning(f"Failed to cleanup browser for task {task_id}: {e}")
|
||||
logger.warning("Failed to cleanup browser for task %s: %s", task_id, e)
|
||||
|
||||
|
||||
def _build_partial_stream_stub(
|
||||
|
|
|
|||
|
|
@ -2672,7 +2672,7 @@ def run_conversation(
|
|||
# Terminal — flush buffered retry trace so user sees what happened.
|
||||
agent._flush_status_buffer()
|
||||
agent._emit_status(f"❌ Max retries ({max_retries}) exceeded for invalid responses. Giving up.")
|
||||
logger.error(f"{agent.log_prefix}Invalid API response after {max_retries} retries.")
|
||||
logger.error("%sInvalid API response after %d retries.", agent.log_prefix, max_retries)
|
||||
agent._persist_session(messages, conversation_history)
|
||||
_final_response = f"Invalid API response after {max_retries} retries: {_failure_hint}"
|
||||
return {
|
||||
|
|
@ -2687,7 +2687,7 @@ def run_conversation(
|
|||
# Backoff before retry — jittered exponential: 5s base, 120s cap
|
||||
wait_time = jittered_backoff(retry_count, base_delay=5.0, max_delay=120.0)
|
||||
agent._buffer_vprint(f"⏳ Retrying in {wait_time:.1f}s ({_failure_hint})...")
|
||||
logger.warning(f"Invalid API response (retry {retry_count}/{max_retries}): {', '.join(error_details)} | Provider: {provider_name}")
|
||||
logger.warning("Invalid API response (retry %d/%d): %s | Provider: %s", retry_count, max_retries, ', '.join(error_details), provider_name)
|
||||
|
||||
# Sleep in small increments to stay responsive to interrupts
|
||||
sleep_end = time.time() + wait_time
|
||||
|
|
@ -4599,7 +4599,7 @@ def run_conversation(
|
|||
agent._flush_status_buffer()
|
||||
agent._vprint(f"{agent.log_prefix}❌ Max compression attempts ({max_compression_attempts}) reached for payload-too-large error.", force=True)
|
||||
agent._vprint(f"{agent.log_prefix} 💡 Try /new to start a fresh conversation, or /compress to retry compression.", force=True)
|
||||
logger.error(f"{agent.log_prefix}413 compression failed after {max_compression_attempts} attempts.")
|
||||
logger.error("%s413 compression failed after %d attempts.", agent.log_prefix, max_compression_attempts)
|
||||
agent._persist_session(messages, conversation_history)
|
||||
_final_response = f"Request payload too large: max compression attempts ({max_compression_attempts}) reached."
|
||||
return {
|
||||
|
|
@ -4668,7 +4668,7 @@ def run_conversation(
|
|||
agent._flush_status_buffer()
|
||||
agent._vprint(f"{agent.log_prefix}❌ Payload too large and cannot compress further.", force=True)
|
||||
agent._vprint(f"{agent.log_prefix} 💡 Try /new to start a fresh conversation, or /compress to retry compression.", force=True)
|
||||
logger.error(f"{agent.log_prefix}413 payload too large. Cannot compress further.")
|
||||
logger.error("%s413 payload too large. Cannot compress further.", agent.log_prefix)
|
||||
agent._persist_session(messages, conversation_history)
|
||||
_final_response = "Request payload too large (413). Cannot compress further."
|
||||
return {
|
||||
|
|
@ -4741,7 +4741,7 @@ def run_conversation(
|
|||
agent._flush_status_buffer()
|
||||
agent._vprint(f"{agent.log_prefix}❌ Max compression attempts ({max_compression_attempts}) reached.", force=True)
|
||||
agent._vprint(f"{agent.log_prefix} 💡 Try /new to start a fresh conversation, or /compress to retry compression.", force=True)
|
||||
logger.error(f"{agent.log_prefix}Context compression failed after {max_compression_attempts} attempts.")
|
||||
logger.error("%sContext compression failed after %d attempts.", agent.log_prefix, max_compression_attempts)
|
||||
agent._persist_session(messages, conversation_history)
|
||||
_final_response = f"Context length exceeded: max compression attempts ({max_compression_attempts}) reached."
|
||||
return {
|
||||
|
|
@ -4860,7 +4860,7 @@ def run_conversation(
|
|||
agent._flush_status_buffer()
|
||||
agent._vprint(f"{agent.log_prefix}❌ Max compression attempts ({max_compression_attempts}) reached.", force=True)
|
||||
agent._vprint(f"{agent.log_prefix} 💡 Try /new to start a fresh conversation, or /compress to retry compression.", force=True)
|
||||
logger.error(f"{agent.log_prefix}Context compression failed after {max_compression_attempts} attempts.")
|
||||
logger.error("%sContext compression failed after %d attempts.", agent.log_prefix, max_compression_attempts)
|
||||
agent._persist_session(messages, conversation_history)
|
||||
_final_response = f"Context length exceeded: max compression attempts ({max_compression_attempts}) reached."
|
||||
return {
|
||||
|
|
@ -4918,7 +4918,7 @@ def run_conversation(
|
|||
agent._flush_status_buffer()
|
||||
agent._vprint(f"{agent.log_prefix}❌ Context length exceeded and cannot compress further.", force=True)
|
||||
agent._vprint(f"{agent.log_prefix} 💡 The conversation has accumulated too much content. Try /new to start fresh, or /compress to manually trigger compression.", force=True)
|
||||
logger.error(f"{agent.log_prefix}Context length exceeded: {new_tokens:,} tokens. Cannot compress further.")
|
||||
logger.error("%sContext length exceeded: %s tokens. Cannot compress further.", agent.log_prefix, f"{new_tokens:,}")
|
||||
agent._persist_session(messages, conversation_history)
|
||||
_final_response = f"Context length exceeded ({new_tokens:,} tokens). Cannot compress further."
|
||||
return {
|
||||
|
|
@ -5184,7 +5184,7 @@ def run_conversation(
|
|||
f"{agent.log_prefix} for localhost, or add the server's cert to your trust store.",
|
||||
force=True,
|
||||
)
|
||||
logger.error(f"{agent.log_prefix}Non-retryable client error: {api_error}")
|
||||
logger.error("%sNon-retryable client error: %s", agent.log_prefix, api_error)
|
||||
# Skip session persistence when the error is likely
|
||||
# context-overflow related (status 400 + large session).
|
||||
# Persisting the failed user message would make the
|
||||
|
|
|
|||
|
|
@ -1084,7 +1084,7 @@ def fetch_model_metadata(force_refresh: bool = False) -> Dict[str, Dict[str, Any
|
|||
return cache
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to fetch model metadata from OpenRouter: {e}")
|
||||
logger.warning("Failed to fetch model metadata from OpenRouter: %s", e)
|
||||
if _model_metadata_cache:
|
||||
return _model_metadata_cache
|
||||
disk_cache = _load_model_metadata_disk_cache()
|
||||
|
|
|
|||
|
|
@ -1038,7 +1038,7 @@ class GatewayKanbanWatchersMixin:
|
|||
# Read max_spawn config to limit concurrent kanban tasks
|
||||
max_spawn = kanban_cfg.get("max_spawn", None)
|
||||
if max_spawn is not None:
|
||||
logger.info(f"kanban dispatcher: max_spawn={max_spawn}")
|
||||
logger.info("kanban dispatcher: max_spawn=%s", max_spawn)
|
||||
|
||||
# Cap the number of simultaneously running tasks so slow workers
|
||||
# (local LLMs, resource-constrained hosts) don't pile up and time
|
||||
|
|
@ -1063,7 +1063,7 @@ class GatewayKanbanWatchersMixin:
|
|||
)
|
||||
max_in_progress = None
|
||||
else:
|
||||
logger.info(f"kanban dispatcher: max_in_progress={max_in_progress}")
|
||||
logger.info("kanban dispatcher: max_in_progress=%s", max_in_progress)
|
||||
|
||||
raw_failure_limit = kanban_cfg.get("failure_limit", _kb.DEFAULT_FAILURE_LIMIT)
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -467,7 +467,7 @@ Complete the user's task step by step."""
|
|||
|
||||
response = self.client.chat.completions.create(**api_kwargs)
|
||||
except Exception as e:
|
||||
self.logger.error(f"API call failed: {e}")
|
||||
self.logger.error("API call failed: %s", e)
|
||||
break
|
||||
|
||||
assistant_message = response.choices[0].message
|
||||
|
|
@ -607,7 +607,7 @@ Complete the user's task step by step."""
|
|||
print(f"✅ Task {i} completed (api_calls={result['api_calls']})")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error on task {i}: {e}")
|
||||
self.logger.error("Error on task %s: %s", i, e)
|
||||
error_result = {
|
||||
"conversations": [],
|
||||
"completed": False,
|
||||
|
|
|
|||
|
|
@ -886,10 +886,10 @@ class DockerEnvironment(BaseEnvironment):
|
|||
self._container_name: str = ""
|
||||
self._image_uses_s6_init: bool = False
|
||||
self._all_run_args: list[str] = []
|
||||
logger.info(f"DockerEnvironment volumes: {volumes}")
|
||||
logger.info("DockerEnvironment volumes: %s", volumes)
|
||||
# Ensure volumes is a list (config.yaml could be malformed)
|
||||
if volumes is not None and not isinstance(volumes, list):
|
||||
logger.warning(f"docker_volumes config is not a list: {volumes!r}")
|
||||
logger.warning("docker_volumes config is not a list: %r", volumes)
|
||||
volumes = []
|
||||
|
||||
# Fail fast if Docker is not available.
|
||||
|
|
@ -933,7 +933,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
workspace_explicitly_mounted = False
|
||||
for vol in (volumes or []):
|
||||
if not isinstance(vol, str):
|
||||
logger.warning(f"Docker volume entry is not a string: {vol!r}")
|
||||
logger.warning("Docker volume entry is not a string: %r", vol)
|
||||
continue
|
||||
vol = vol.strip()
|
||||
if not vol:
|
||||
|
|
@ -943,7 +943,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
if ":/workspace" in vol:
|
||||
workspace_explicitly_mounted = True
|
||||
else:
|
||||
logger.warning(f"Docker volume '{vol}' missing colon, skipping")
|
||||
logger.warning("Docker volume '%s' missing colon, skipping", vol)
|
||||
|
||||
host_cwd_abs = os.path.abspath(os.path.expanduser(host_cwd)) if host_cwd else ""
|
||||
bind_host_cwd = (
|
||||
|
|
@ -953,7 +953,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
and not workspace_explicitly_mounted
|
||||
)
|
||||
if auto_mount_cwd and host_cwd and not os.path.isdir(host_cwd_abs):
|
||||
logger.debug(f"Skipping docker cwd mount: host_cwd is not a valid directory: {host_cwd}")
|
||||
logger.debug("Skipping docker cwd mount: host_cwd is not a valid directory: %s", host_cwd)
|
||||
|
||||
self._workspace_dir: Optional[str] = None
|
||||
self._home_dir: Optional[str] = None
|
||||
|
|
@ -982,7 +982,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
])
|
||||
|
||||
if bind_host_cwd:
|
||||
logger.info(f"Mounting configured host cwd to /workspace: {host_cwd_abs}")
|
||||
logger.info("Mounting configured host cwd to /workspace: %s", host_cwd_abs)
|
||||
volume_args = ["-v", f"{host_cwd_abs}:/workspace", *volume_args]
|
||||
elif workspace_explicitly_mounted:
|
||||
logger.debug("Skipping docker cwd mount: /workspace already mounted by user config")
|
||||
|
|
@ -1298,7 +1298,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
run_exec=image_uses_s6_init,
|
||||
)
|
||||
|
||||
logger.info(f"Docker volume_args: {volume_args}")
|
||||
logger.info("Docker volume_args: %s", volume_args)
|
||||
# User-supplied extra docker run flags (docker_extra_args in config.yaml).
|
||||
# Appended last so they can override defaults if needed.
|
||||
validated_extra = []
|
||||
|
|
@ -1336,7 +1336,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
+ env_args
|
||||
+ validated_extra
|
||||
)
|
||||
logger.info(f"Docker run_args: {all_run_args}")
|
||||
logger.info("Docker run_args: %s", all_run_args)
|
||||
|
||||
# Start the container directly via `docker run -d`.
|
||||
container_name = f"hermes-{uuid.uuid4().hex[:8]}"
|
||||
|
|
@ -1465,7 +1465,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
image,
|
||||
"sleep", "infinity", # no fixed lifetime — idle reaper handles cleanup
|
||||
]
|
||||
logger.debug(f"Starting container: {' '.join(run_cmd)}")
|
||||
logger.debug("Starting container: %s", ' '.join(run_cmd))
|
||||
try:
|
||||
result = subprocess.run(
|
||||
run_cmd,
|
||||
|
|
@ -1494,7 +1494,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
)
|
||||
raise
|
||||
self._container_id = result.stdout.strip()
|
||||
logger.info(f"Started container {container_name} ({self._container_id[:12]})")
|
||||
logger.info("Started container %s (%s)", container_name, self._container_id[:12])
|
||||
|
||||
# Build the init-time env forwarding args used to seed the snapshot.
|
||||
self._init_env_args = self._build_init_env_args()
|
||||
|
|
|
|||
|
|
@ -464,7 +464,7 @@ class GitHubAuth:
|
|||
if resp.status_code == 201:
|
||||
return resp.json().get("token")
|
||||
except Exception as e:
|
||||
logger.debug(f"GitHub App auth failed: {e}")
|
||||
logger.debug("GitHub App auth failed: %s", e)
|
||||
|
||||
return None
|
||||
|
||||
|
|
@ -625,7 +625,7 @@ class GitHubSource(SkillSource):
|
|||
if query_lower in searchable:
|
||||
results.append(skill)
|
||||
except Exception as e:
|
||||
logger.debug(f"Failed to search {tap['repo']}: {e}")
|
||||
logger.debug("Failed to search %s: %s", tap['repo'], e)
|
||||
continue
|
||||
|
||||
# Deduplicate by identifier, preferring higher trust levels.
|
||||
|
|
|
|||
|
|
@ -663,7 +663,7 @@ Write only the summary, starting with "[CONTEXT SUMMARY]:" prefix."""
|
|||
|
||||
except Exception as e:
|
||||
metrics.summarization_errors += 1
|
||||
self.logger.warning(f"Summarization attempt {attempt + 1} failed: {e}")
|
||||
self.logger.warning("Summarization attempt %d failed: %s", attempt + 1, e)
|
||||
|
||||
if attempt < self.config.max_retries - 1:
|
||||
time.sleep(jittered_backoff(attempt + 1, base_delay=self.config.retry_delay, max_delay=30.0))
|
||||
|
|
@ -732,7 +732,7 @@ Write only the summary, starting with "[CONTEXT SUMMARY]:" prefix."""
|
|||
|
||||
except Exception as e:
|
||||
metrics.summarization_errors += 1
|
||||
self.logger.warning(f"Summarization attempt {attempt + 1} failed: {e}")
|
||||
self.logger.warning("Summarization attempt %d failed: %s", attempt + 1, e)
|
||||
|
||||
if attempt < self.config.max_retries - 1:
|
||||
await asyncio.sleep(jittered_backoff(attempt + 1, base_delay=self.config.retry_delay, max_delay=30.0))
|
||||
|
|
@ -1087,7 +1087,7 @@ Write only the summary, starting with "[CONTEXT SUMMARY]:" prefix."""
|
|||
jsonl_files = sorted(input_dir.glob("*.jsonl"))
|
||||
|
||||
if not jsonl_files:
|
||||
self.logger.warning(f"No JSONL files found in {input_dir}")
|
||||
self.logger.warning("No JSONL files found in %s", input_dir)
|
||||
return
|
||||
|
||||
# Load ALL entries from all files
|
||||
|
|
@ -1103,7 +1103,7 @@ Write only the summary, starting with "[CONTEXT SUMMARY]:" prefix."""
|
|||
entry = json.loads(line)
|
||||
all_entries.append((file_path, line_num, entry))
|
||||
except json.JSONDecodeError as e:
|
||||
self.logger.warning(f"Skipping invalid JSON at {file_path}:{line_num}: {e}")
|
||||
self.logger.warning("Skipping invalid JSON at %s:%s: %s", file_path, line_num, e)
|
||||
|
||||
total_entries = len(all_entries)
|
||||
|
||||
|
|
@ -1172,7 +1172,7 @@ Write only the summary, starting with "[CONTEXT SUMMARY]:" prefix."""
|
|||
)
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
self.logger.warning(f"Timeout processing entry from {file_path}:{entry_idx} (>{self.config.per_trajectory_timeout}s)")
|
||||
self.logger.warning("Timeout processing entry from %s:%s (>%ss)", file_path, entry_idx, self.config.per_trajectory_timeout)
|
||||
|
||||
async with progress_lock:
|
||||
self.aggregate_metrics.trajectories_failed += 1
|
||||
|
|
@ -1188,7 +1188,7 @@ Write only the summary, starting with "[CONTEXT SUMMARY]:" prefix."""
|
|||
results[file_path][entry_idx] = None
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error processing entry from {file_path}:{entry_idx}: {e}")
|
||||
self.logger.error("Error processing entry from %s:%s: %s", file_path, entry_idx, e)
|
||||
|
||||
async with progress_lock:
|
||||
self.aggregate_metrics.trajectories_failed += 1
|
||||
|
|
|
|||
Loading…
Reference in New Issue