fix: Redis bool storage, tool tracking matching, e2e fixture scope
Build and Push / build (release) Successful in 53s
Build and Push / build (release) Successful in 53s
- Convert booleans to strings for Redis hset (Redis doesn't accept bool) - Extract capability from delegate_to_X tool names for tracking - Use loop_scope="module" for pytest-asyncio module-scoped fixtures - Add note about using venv for tests in AGENTS.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,10 @@ class PerformanceBenchmark(BaseModel):
|
||||
data = self.model_dump()
|
||||
data["timestamp"] = self.timestamp.isoformat()
|
||||
data["metadata"] = json.dumps(self.metadata)
|
||||
# Convert booleans to strings (Redis doesn't accept bool type)
|
||||
for key, value in data.items():
|
||||
if isinstance(value, bool):
|
||||
data[key] = str(value)
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
@@ -54,6 +58,10 @@ class PerformanceBenchmark(BaseModel):
|
||||
"""Reconstruct from Redis dict."""
|
||||
data["timestamp"] = datetime.fromisoformat(data["timestamp"])
|
||||
data["metadata"] = json.loads(data.get("metadata", "{}"))
|
||||
# Convert string booleans back to bool
|
||||
for key in ["success", "was_recommended", "was_actually_used"]:
|
||||
if key in data and isinstance(data[key], str):
|
||||
data[key] = data[key] == "True"
|
||||
return cls(**data)
|
||||
|
||||
|
||||
|
||||
@@ -43,6 +43,16 @@ class ToolCallTracker:
|
||||
conversation_id=conversation_id,
|
||||
)
|
||||
|
||||
def _extract_capability(self, tool_name: str) -> str:
|
||||
"""
|
||||
Extract capability name from tool name.
|
||||
|
||||
Tool names like 'delegate_to_librarian' map to capability 'librarian'.
|
||||
"""
|
||||
if tool_name.startswith("delegate_to_"):
|
||||
return tool_name.replace("delegate_to_", "")
|
||||
return tool_name
|
||||
|
||||
async def track_call(self, tool_name: str, duration: float):
|
||||
"""
|
||||
Record a tool call with timing.
|
||||
@@ -56,8 +66,9 @@ class ToolCallTracker:
|
||||
self.actual_calls[tool_name] = []
|
||||
self.actual_calls[tool_name].append(duration)
|
||||
|
||||
# Check if tool was recommended
|
||||
was_recommended = tool_name in self.recommended_capabilities
|
||||
# Check if tool was recommended (normalize tool name to capability)
|
||||
capability = self._extract_capability(tool_name)
|
||||
was_recommended = capability in self.recommended_capabilities
|
||||
|
||||
if not was_recommended:
|
||||
logger.warning(
|
||||
@@ -98,8 +109,12 @@ class ToolCallTracker:
|
||||
Called after Tatlock completes its response to identify
|
||||
tools that were recommended but never used.
|
||||
"""
|
||||
# Normalize actual tool names to capabilities for comparison
|
||||
used_capabilities = {
|
||||
self._extract_capability(tool) for tool in self.actual_calls.keys()
|
||||
}
|
||||
# Find tools that were recommended but not used
|
||||
unused_tools = self.recommended_capabilities - set(self.actual_calls.keys())
|
||||
unused_tools = self.recommended_capabilities - used_capabilities
|
||||
|
||||
if unused_tools:
|
||||
logger.info(
|
||||
@@ -145,7 +160,11 @@ class ToolCallTracker:
|
||||
Dict with tracking statistics
|
||||
"""
|
||||
total_calls = sum(len(durations) for durations in self.actual_calls.values())
|
||||
unused = self.recommended_capabilities - set(self.actual_calls.keys())
|
||||
# Normalize actual tool names to capabilities for comparison
|
||||
used_capabilities = {
|
||||
self._extract_capability(tool) for tool in self.actual_calls.keys()
|
||||
}
|
||||
unused = self.recommended_capabilities - used_capabilities
|
||||
|
||||
return {
|
||||
"recommended_capabilities": list(self.recommended_capabilities),
|
||||
@@ -154,11 +173,11 @@ class ToolCallTracker:
|
||||
"total_calls": total_calls,
|
||||
"accuracy": {
|
||||
"recommended_and_used": len(
|
||||
self.recommended_capabilities & set(self.actual_calls.keys())
|
||||
self.recommended_capabilities & used_capabilities
|
||||
),
|
||||
"recommended_but_unused": len(unused),
|
||||
"not_recommended_but_used": len(
|
||||
set(self.actual_calls.keys()) - self.recommended_capabilities
|
||||
used_capabilities - self.recommended_capabilities
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user