Download framework/streaming.py from rohanjain2312/Self-Healing-Code-Agent: direct link, hf CLI and curl.
- Browser
- Download file 5.97 kB
-
https://huggingface.co/spaces/rohanjain2312/Self-Healing-Code-Agent/resolve/main/framework/streaming.py
- Command line
-
hf download hf://spaces/rohanjain2312/Self-Healing-Code-Agent/framework/streaming.py
-
curl -L -o streaming.py https://huggingface.co/spaces/rohanjain2312/Self-Healing-Code-Agent/resolve/main/framework/streaming.py
5.97 kB
| """ | |
| Streaming adapter — converts agent event streams into UI-consumable formats. | |
| Provides: | |
| - async generator that yields formatted event dicts for Gradio | |
| - timeline formatter that converts events to human-readable log entries | |
| - code snapshot extractor for live code display | |
| - learning log extractor for live lesson display | |
| This layer is stateless — it transforms event streams without buffering state. | |
| The UI layer owns all display state. | |
| """ | |
| import logging | |
| from typing import Any, AsyncGenerator | |
| from agent.events import ( | |
| CODE_GENERATED, | |
| FAILURE, | |
| LEARNING_UPDATE, | |
| SUCCESS, | |
| STEP, | |
| DIAGNOSIS, | |
| TESTS_GENERATED, | |
| SPEC_TESTS_GENERATED, | |
| REPAIR_REVIEW, | |
| TOOL_USE, | |
| CRITIC_REVIEW, | |
| PARALLEL_REPAIR, | |
| ) | |
| logger = logging.getLogger(__name__) | |
| # Events that are shown in the public timeline (others are internal) | |
| # Public set — importable by demo and test modules | |
| PUBLIC_EVENT_TYPES = { | |
| STEP, | |
| CODE_GENERATED, | |
| FAILURE, | |
| LEARNING_UPDATE, | |
| SUCCESS, | |
| DIAGNOSIS, | |
| TESTS_GENERATED, | |
| SPEC_TESTS_GENERATED, | |
| REPAIR_REVIEW, | |
| TOOL_USE, | |
| CRITIC_REVIEW, | |
| PARALLEL_REPAIR, | |
| } | |
| def _trunc(s: str, n: int) -> str: | |
| """Return s truncated to n chars with ellipsis if needed.""" | |
| return s if len(s) <= n else s[:n - 1] + "\u2026" | |
| def format_event_for_timeline(event: dict[str, Any]) -> str: | |
| """ | |
| Convert a single event dict to a concise human-readable timeline entry. | |
| Returns "" for event types that should be suppressed (STEP, unknown). | |
| All lines are capped at 100 characters. | |
| """ | |
| event_type = event.get("type", "unknown") | |
| iteration = event.get("iteration", 0) | |
| payload = event.get("payload", {}) | |
| if not isinstance(payload, dict): | |
| payload = {} | |
| n = iteration # short alias for f-strings | |
| if event_type == STEP: | |
| return "" # too noisy — suppress | |
| if event_type == CODE_GENERATED: | |
| code = payload.get("code", "") | |
| return _trunc(f"[iter {n}] \u2713 Code generated ({len(code)} chars)", 100) | |
| if event_type == TESTS_GENERATED: | |
| count = payload.get("test_count", "?") | |
| return _trunc(f"[iter {n}] \u2713 {count} adversarial tests ready", 100) | |
| if event_type == SPEC_TESTS_GENERATED: | |
| count = payload.get("test_count", "?") | |
| return _trunc(f"[iter {n}] \u2713 {count} spec tests ready", 100) | |
| if event_type == FAILURE: | |
| assertions = payload.get("failed_assertions", []) | |
| summary = assertions[0] if assertions else payload.get("summary", "") | |
| return _trunc(f"[iter {n}] \u2717 {_trunc(summary, 80)}", 100) | |
| if event_type == DIAGNOSIS: | |
| category = payload.get("failure_category", "unknown") | |
| root_cause = payload.get("root_cause", "") | |
| return _trunc(f"[iter {n}] \u2192 [{category}] {_trunc(root_cause, 80)}", 100) | |
| if event_type == LEARNING_UPDATE: | |
| count = len(payload.get("lessons", [])) | |
| return _trunc(f"[iter {n}] \U0001f4dd {count} lesson(s) logged", 100) | |
| if event_type == SUCCESS: | |
| return f"[iter {n}] \u2713 All tests passed" | |
| if event_type == TOOL_USE: | |
| tool_name = payload.get("tool_name", "unknown") | |
| result = payload.get("result", "").replace("\n", " ") | |
| return _trunc(f"[iter {n}] \U0001f527 {tool_name}: {_trunc(result, 60)}", 100) | |
| if event_type == CRITIC_REVIEW: | |
| verdict = payload.get("verdict", "unknown").upper() | |
| confidence = payload.get("confidence", 0.0) | |
| issues = payload.get("issues", []) | |
| line = f"[iter {n}] \U0001f50d Critic: {verdict} ({confidence:.0%})" | |
| if issues: | |
| line += f" \u2014 {_trunc(issues[0], 50)}" | |
| return _trunc(line, 100) | |
| if event_type == PARALLEL_REPAIR: | |
| strategy = payload.get("strategy_name", "unknown") | |
| spec = payload.get("spec_passed", False) | |
| adv = payload.get("adv_passed", False) | |
| return _trunc(f"[iter {n}] \u26a1 [{strategy}] spec={spec} adv={adv}", 100) | |
| if event_type == REPAIR_REVIEW: | |
| category = payload.get("failure_category", "?") | |
| confidence = payload.get("confidence", 0.0) | |
| return _trunc( | |
| f"[iter {n}] \u23f8 Human review \u2014 [{category}] confidence {confidence:.0%}", | |
| 100, | |
| ) | |
| return "" # suppress unknown event types | |
| async def stream_events_for_ui( | |
| event_stream: AsyncGenerator[dict[str, Any], None], | |
| include_internal: bool = False, | |
| ) -> AsyncGenerator[dict[str, Any], None]: | |
| """ | |
| Filter and enrich events for UI consumption. | |
| Strips events that are not meant for public display. | |
| Adds a formatted 'display_text' field for simple rendering. | |
| """ | |
| async for event in event_stream: | |
| if event is None: | |
| break | |
| event_type = event.get("type", "") | |
| if not include_internal and event_type not in PUBLIC_EVENT_TYPES: | |
| continue | |
| enriched = { | |
| **event, | |
| "display_text": format_event_for_timeline(event), | |
| } | |
| yield enriched | |
| def extract_latest_code(events: list[dict[str, Any]]) -> str: | |
| """Return the most recently generated code from a list of events.""" | |
| for event in reversed(events): | |
| if event.get("type") == CODE_GENERATED: | |
| return event.get("payload", {}).get("code", "") | |
| return "" | |
| def extract_learning_log(events: list[dict[str, Any]]) -> list[str]: | |
| """Return the most recent set of lessons from a list of events.""" | |
| for event in reversed(events): | |
| if event.get("type") == LEARNING_UPDATE: | |
| return event.get("payload", {}).get("lessons", []) | |
| return [] | |
| def build_timeline_text(events: list[dict[str, Any]]) -> str: | |
| """Convert a full event list to a multi-line timeline string for display.""" | |
| lines = [ | |
| format_event_for_timeline(e) | |
| for e in events | |
| if e.get("type") in PUBLIC_EVENT_TYPES | |
| ] | |
| return "\n".join(line for line in lines if line) | |