wafer-core 0.1.38__py3-none-any.whl → 0.1.39__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. wafer_core/lib/trace_compare/fusion_analyzer.py +2 -0
  2. wafer_core/rollouts/_logging/__init__.py +5 -1
  3. wafer_core/rollouts/_logging/logging_config.py +95 -3
  4. wafer_core/rollouts/_logging/sample_handler.py +66 -0
  5. wafer_core/rollouts/_pytui/__init__.py +114 -0
  6. wafer_core/rollouts/_pytui/app.py +809 -0
  7. wafer_core/rollouts/_pytui/console.py +291 -0
  8. wafer_core/rollouts/_pytui/renderer.py +210 -0
  9. wafer_core/rollouts/_pytui/spinner.py +73 -0
  10. wafer_core/rollouts/_pytui/terminal.py +489 -0
  11. wafer_core/rollouts/_pytui/text.py +470 -0
  12. wafer_core/rollouts/_pytui/theme.py +241 -0
  13. wafer_core/rollouts/evaluation.py +142 -177
  14. wafer_core/rollouts/progress_app.py +395 -0
  15. wafer_core/rollouts/tui/DESIGN.md +251 -115
  16. wafer_core/rollouts/tui/monitor.py +64 -20
  17. wafer_core/tools/compile/__init__.py +30 -0
  18. wafer_core/tools/compile/compiler.py +314 -0
  19. wafer_core/tools/compile/modal_compile.py +359 -0
  20. wafer_core/tools/compile/tests/__init__.py +1 -0
  21. wafer_core/tools/compile/tests/test_compiler.py +675 -0
  22. wafer_core/tools/compile/tests/test_data/utils.cuh +10 -0
  23. wafer_core/tools/compile/tests/test_data/vector_add.cu +7 -0
  24. wafer_core/tools/compile/tests/test_data/with_header.cu +9 -0
  25. wafer_core/tools/compile/tests/test_modal_integration.py +326 -0
  26. wafer_core/tools/compile/types.py +117 -0
  27. {wafer_core-0.1.38.dist-info → wafer_core-0.1.39.dist-info}/METADATA +1 -1
  28. {wafer_core-0.1.38.dist-info → wafer_core-0.1.39.dist-info}/RECORD +29 -12
  29. wafer_core/rollouts/events.py +0 -240
  30. wafer_core/rollouts/progress_display.py +0 -476
  31. wafer_core/utils/event_streaming.py +0 -63
  32. {wafer_core-0.1.38.dist-info → wafer_core-0.1.39.dist-info}/WHEEL +0 -0
@@ -1,240 +0,0 @@
1
- """Unified event emission for TUI consumption.
2
-
3
- All long-running processes (eval, GEPA, RL training) emit structured events
4
- to a JSONL file. The TUI tails this file and renders progress.
5
-
6
- This decouples the process from the UI - the process doesn't know or care
7
- if anyone is watching. Events are always written for later analysis too.
8
-
9
- Event types:
10
- sample_start/end - Evaluation sample lifecycle
11
- turn - Agent turn within a sample
12
- modal_progress - GPU eval phases (compiling, checking, benchmarking)
13
- gepa_iteration - GEPA optimization progress
14
- rl_step - RL training step metrics
15
- log - Generic log message (routed to panes by logger name)
16
-
17
- Usage:
18
- from rollouts.events import EventEmitter, get_emitter
19
-
20
- # In evaluate():
21
- emitter = EventEmitter(output_dir)
22
- emitter.emit("sample_start", id="001", name="Square_matmul", total=10)
23
- # ... do work ...
24
- emitter.emit("sample_end", id="001", score=0.85, time_sec=45.2)
25
-
26
- # In GEPA:
27
- emitter = get_emitter() # Gets from context
28
- emitter.emit("gepa_iteration", iteration=3, evals_used=12, best_score=0.42)
29
-
30
- Tiger Style: Pure data out, no UI code, explicit file handle.
31
- """
32
-
33
- from __future__ import annotations
34
-
35
- import contextvars
36
- import json
37
- import logging
38
- from datetime import datetime, timezone
39
- from pathlib import Path
40
- from typing import Any, TextIO
41
-
42
- logger = logging.getLogger(__name__)
43
-
44
- # Context variable for accessing emitter from anywhere in the call stack
45
- _emitter_ctx: contextvars.ContextVar[EventEmitter | None] = contextvars.ContextVar(
46
- "event_emitter", default=None
47
- )
48
-
49
-
50
- def get_emitter() -> EventEmitter | None:
51
- """Get the current EventEmitter from context.
52
-
53
- Returns None if no emitter is set (events will be silently dropped).
54
- """
55
- return _emitter_ctx.get()
56
-
57
-
58
- def emit_event(event_type: str, **data: Any) -> None:
59
- """Emit an event if an emitter is configured.
60
-
61
- Convenience function that gets emitter from context.
62
- Safe to call even if no emitter is set (no-op).
63
-
64
- Args:
65
- event_type: Event type (sample_start, turn, modal_progress, etc.)
66
- **data: Event data fields
67
- """
68
- emitter = get_emitter()
69
- if emitter is not None:
70
- emitter.emit(event_type, **data)
71
-
72
-
73
- class EventEmitter:
74
- """Writes structured events to JSONL file/stream.
75
-
76
- Thread-safe via flush-after-write. Events include timestamp automatically.
77
-
78
- Can write to:
79
- - File (default): {output_dir}/events.jsonl
80
- - Stdout: For piping to TUI
81
- - Any TextIO stream
82
-
83
- Usage:
84
- # File-based (for local runs)
85
- with EventEmitter(output_dir=Path("./results")) as emitter:
86
- emitter.emit("sample_start", id="001", name="test")
87
-
88
- # Stdout (for piped runs)
89
- with EventEmitter(stream=sys.stdout) as emitter:
90
- emitter.emit("sample_start", id="001", name="test")
91
-
92
- # With context (accessible via get_emitter())
93
- with EventEmitter(output_dir=path).as_context():
94
- emit_event("sample_start", id="001") # Works anywhere in call stack
95
- """
96
-
97
- def __init__(
98
- self,
99
- output_dir: Path | str | None = None,
100
- stream: TextIO | None = None,
101
- events_file: str = "events.jsonl",
102
- ) -> None:
103
- """Initialize emitter.
104
-
105
- Args:
106
- output_dir: Directory to write events.jsonl (mutually exclusive with stream)
107
- stream: Stream to write to (e.g., sys.stdout)
108
- events_file: Filename within output_dir (default: events.jsonl)
109
- """
110
- self._file: TextIO | None = None
111
- self._owns_file = False
112
- self._ctx_token: contextvars.Token | None = None
113
-
114
- if stream is not None:
115
- self._file = stream
116
- self._owns_file = False
117
- elif output_dir is not None:
118
- output_path = Path(output_dir)
119
- output_path.mkdir(parents=True, exist_ok=True)
120
- self._file = open(output_path / events_file, "a")
121
- self._owns_file = True
122
- logger.debug(f"EventEmitter writing to {output_path / events_file}")
123
- else:
124
- # No output configured - events will be dropped
125
- logger.debug("EventEmitter created with no output (events will be dropped)")
126
-
127
- def emit(self, event_type: str, **data: Any) -> None:
128
- """Emit a structured event.
129
-
130
- Args:
131
- event_type: Event type (sample_start, sample_end, turn, modal_progress, etc.)
132
- **data: Event data fields
133
- """
134
- if self._file is None:
135
- return
136
-
137
- event = {
138
- "type": event_type,
139
- "timestamp": datetime.now(timezone.utc).isoformat(),
140
- **data,
141
- }
142
-
143
- try:
144
- self._file.write(json.dumps(event) + "\n")
145
- self._file.flush()
146
- except Exception as e:
147
- logger.warning(f"Failed to emit event: {e}")
148
-
149
- def as_context(self) -> EventEmitter:
150
- """Set this emitter as the context emitter.
151
-
152
- Use as context manager:
153
- with EventEmitter(output_dir=path).as_context():
154
- emit_event("sample_start", ...) # Uses this emitter
155
-
156
- Returns self for chaining.
157
- """
158
- self._ctx_token = _emitter_ctx.set(self)
159
- return self
160
-
161
- def __enter__(self) -> EventEmitter:
162
- return self
163
-
164
- def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
165
- self.close()
166
-
167
- def close(self) -> None:
168
- """Close the emitter and release resources."""
169
- # Reset context if we set it
170
- if self._ctx_token is not None:
171
- _emitter_ctx.reset(self._ctx_token)
172
- self._ctx_token = None
173
-
174
- # Close file if we own it
175
- if self._owns_file and self._file is not None:
176
- self._file.close()
177
- self._file = None
178
-
179
-
180
- class LoggingEventEmitter(EventEmitter):
181
- """EventEmitter that also logs events via Python logging.
182
-
183
- Useful for debugging - events appear in both events.jsonl and logs.
184
- """
185
-
186
- def __init__(
187
- self,
188
- output_dir: Path | str | None = None,
189
- stream: TextIO | None = None,
190
- events_file: str = "events.jsonl",
191
- log_level: int = logging.DEBUG,
192
- ) -> None:
193
- super().__init__(output_dir, stream, events_file)
194
- self._log_level = log_level
195
-
196
- def emit(self, event_type: str, **data: Any) -> None:
197
- super().emit(event_type, **data)
198
- logger.log(self._log_level, f"Event: {event_type} {data}")
199
-
200
-
201
- # ── Event type constants ──────────────────────────────────────────────────────
202
- # Use these for consistency across codebase
203
-
204
-
205
- class EventTypes:
206
- """Standard event type constants."""
207
-
208
- # Eval lifecycle
209
- EVAL_START = "eval_start"
210
- EVAL_END = "eval_end"
211
- SAMPLE_START = "sample_start"
212
- SAMPLE_END = "sample_end"
213
- TURN = "turn"
214
-
215
- # Tool execution (wide events)
216
- TOOL_EXECUTION = "tool_execution"
217
- LLM_CALL = "llm_call"
218
- ASSISTANT_MESSAGE = "assistant_message"
219
-
220
- # GPU/target pool management
221
- GPU_ACQUIRE = "gpu_acquire"
222
- GPU_RELEASE = "gpu_release"
223
-
224
- # Modal/GPU progress
225
- MODAL_PROGRESS = "modal_progress"
226
-
227
- # GEPA
228
- GEPA_START = "gepa_start"
229
- GEPA_ITERATION = "gepa_iteration"
230
- GEPA_ACCEPTED = "gepa_accepted"
231
- GEPA_REJECTED = "gepa_rejected"
232
- GEPA_END = "gepa_end"
233
-
234
- # RL Training
235
- RL_STEP = "rl_step"
236
- RL_CHECKPOINT = "rl_checkpoint"
237
-
238
- # Generic
239
- LOG = "log"
240
- ERROR = "error"