fix: prevent JSON event leaking to users and reload skills after AI creation
- OpenCode runtime: stop calling _collect_text fallback on non-text events (step_start, step_finish, etc.) - Both runtimes: guard raw stdout fallback to only apply for non-JSON output - main.py: reload skills after AI responses containing skill-related keywords - main.py: return friendly message instead of empty string for tool-only responses
This commit is contained in:
@@ -259,8 +259,11 @@ class ClaudeCodeRuntime:
|
||||
# Parse the output
|
||||
response_text, session_id, usage = self._parse_output(stdout)
|
||||
|
||||
if not response_text:
|
||||
response_text = stdout # Fallback to raw output
|
||||
if not response_text and stdout.strip():
|
||||
# Only fall back to raw output if it doesn't look like JSON events
|
||||
# (which would leak internal lifecycle data to the user)
|
||||
if not stdout.strip().startswith("{"):
|
||||
response_text = stdout
|
||||
|
||||
# Store session mapping
|
||||
if session_id and conversation_id:
|
||||
@@ -420,7 +423,8 @@ class ClaudeCodeRuntime:
|
||||
try:
|
||||
event = json.loads(line)
|
||||
if isinstance(event, dict):
|
||||
if event.get("type") == "result":
|
||||
event_type = event.get("type", "")
|
||||
if event_type == "result":
|
||||
text_parts.append(event.get("result", ""))
|
||||
session_id = event.get("session_id", session_id)
|
||||
usage = {
|
||||
@@ -430,7 +434,7 @@ class ClaudeCodeRuntime:
|
||||
"duration_api_ms": event.get("duration_api_ms", 0),
|
||||
"is_error": event.get("is_error", False),
|
||||
}
|
||||
elif event.get("type") == "assistant" and "message" in event:
|
||||
elif event_type == "assistant" and "message" in event:
|
||||
# Extract text from content blocks
|
||||
msg = event["message"]
|
||||
if "content" in msg:
|
||||
@@ -438,14 +442,33 @@ class ClaudeCodeRuntime:
|
||||
if block.get("type") == "text":
|
||||
text_parts.append(block.get("text", ""))
|
||||
session_id = event.get("session_id", session_id)
|
||||
# Silently skip non-content events (step_start, step_finish,
|
||||
# system, tool_use, tool_result, etc.) — these are internal
|
||||
# lifecycle events that should never reach the user.
|
||||
except json.JSONDecodeError:
|
||||
# Not JSON — could be plain text mixed in; only include if
|
||||
# it doesn't look like a truncated JSON blob.
|
||||
if not line.startswith("{") and not line.startswith("["):
|
||||
text_parts.append(line)
|
||||
continue
|
||||
|
||||
if text_parts:
|
||||
return "\n".join(text_parts), session_id, usage
|
||||
|
||||
# Fallback: treat as plain text
|
||||
return stdout, None, None
|
||||
# Fallback: treat as plain text, but strip any JSON-like lines
|
||||
# to prevent raw event objects from leaking to the user.
|
||||
plain_lines = []
|
||||
for line in stdout.splitlines():
|
||||
stripped = line.strip()
|
||||
if stripped and not stripped.startswith("{"):
|
||||
plain_lines.append(line)
|
||||
if plain_lines:
|
||||
return "\n".join(plain_lines), None, None
|
||||
|
||||
# Everything was JSON events with no extractable text
|
||||
logger.warning("Claude output contained only non-content JSON events")
|
||||
return "", None, None
|
||||
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# Validation
|
||||
|
||||
Reference in New Issue
Block a user