| 294 | // bashOutputHead / bashOutputTail bound what headTailBuffer retains: first 1MB |
| 295 | // plus last 1MB of combined output. Far above ctx.Truncate's ~24KB relevance |
| 296 | // threshold (nothing the model would ever see is dropped), small enough that a |
| 297 | // firehose command can't OOM the process. |
| 298 | const ( |
| 299 | bashOutputHead = 1 << 20 |
| 300 | bashOutputTail = 1 << 20 |
| 301 | ) |
| 302 | |
| 303 | // headTailBuffer is an io.Writer keeping the first bashOutputHead and the last |
| 304 | // bashOutputTail bytes written, discarding the middle. The tail is a fixed ring |
| 305 | // so a firehose costs a bounded copy, never an allocation per write. |
| 306 | type headTailBuffer struct { |
| 307 | head []byte |
| 308 | ring []byte |
| 309 | pos int // next write index in ring |
| 310 | tailBytes int64 // total bytes routed to the ring |
| 311 | } |
| 312 | |
| 313 | func (w *headTailBuffer) Write(p []byte) (int, error) { |
| 314 | n := len(p) |
| 315 | if room := bashOutputHead - len(w.head); room > 0 { |
| 316 | take := min(room, len(p)) |
| 317 | w.head = append(w.head, p[:take]...) |