Output returns the truncated output suitable for LLM consumption, along with truncation metadata. If the total output fits within the head buffer alone, the full output is returned with nil truncation info. Otherwise the head and tail are joined with an omission marker and long lines are truncated.
()
| 207 | // tail are joined with an omission marker and long lines are |
| 208 | // truncated. |
| 209 | func (b *HeadTailBuffer) Output() (string, *workspacesdk.ProcessTruncation) { |
| 210 | b.mu.Lock() |
| 211 | head := make([]byte, len(b.head)) |
| 212 | copy(head, b.head) |
| 213 | tail := b.tailBytes() |
| 214 | total := b.totalBytes |
| 215 | headFull := b.headFull |
| 216 | b.mu.Unlock() |
| 217 | |
| 218 | storedLen := len(head) + len(tail) |
| 219 | |
| 220 | // If everything fits, no head/tail split is needed. |
| 221 | if !headFull || len(tail) == 0 { |
| 222 | out := truncateLines(string(head)) |
| 223 | if total == 0 { |
| 224 | return "", nil |
| 225 | } |
| 226 | return out, nil |
| 227 | } |
| 228 | |
| 229 | // We have both head and tail data, meaning the total |
| 230 | // output exceeded the head capacity. Build the |
| 231 | // combined output with an omission marker. |
| 232 | omitted := total - storedLen |
| 233 | headStr := truncateLines(string(head)) |
| 234 | tailStr := truncateLines(string(tail)) |
| 235 | |
| 236 | var sb strings.Builder |
| 237 | _, _ = sb.WriteString(headStr) |
| 238 | if omitted > 0 { |
| 239 | _, _ = sb.WriteString(fmt.Sprintf( |
| 240 | "\n\n... [omitted %d bytes] ...\n\n", |
| 241 | omitted, |
| 242 | )) |
| 243 | } else { |
| 244 | // Head and tail are contiguous but were stored |
| 245 | // separately because the head filled up. |
| 246 | _, _ = sb.WriteString("\n") |
| 247 | } |
| 248 | _, _ = sb.WriteString(tailStr) |
| 249 | result := sb.String() |
| 250 | |
| 251 | return result, &workspacesdk.ProcessTruncation{ |
| 252 | OriginalBytes: total, |
| 253 | RetainedBytes: len(result), |
| 254 | OmittedBytes: omitted, |
| 255 | Strategy: "head_tail", |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | // truncateLines scans the input line by line and truncates |
| 260 | // any line longer than MaxLineLength. |