idleTimeoutFromEnv resolves CODEHAMR_IDLE_TIMEOUT to a duration, falling back to streamIdleTimeout when unset or unparseable. Accepts a Go duration string ("45m", "1h30m") or a bare number read as seconds. Lives here, not in main's applyEnvOverrides, because it's purely an llm concern and both Clien
()
| 190 | // looping model emits frames and resets the watchdog every time, so it slips |
| 191 | // straight past; runaway/failure nudges and Ctrl+C own that. CODEHAMR_IDLE_TIMEOUT |
| 192 | // overrides the default (Go duration like "90m", or a bare number = seconds). |
| 193 | const streamIdleTimeout = time.Hour |
| 194 | |
| 195 | // idleTimeoutFromEnv resolves CODEHAMR_IDLE_TIMEOUT to a duration, falling back |
| 196 | // to streamIdleTimeout when unset or unparseable. Accepts a Go duration string |
| 197 | // ("45m", "1h30m") or a bare number read as seconds. Lives here, not in main's |
| 198 | // applyEnvOverrides, because it's purely an llm concern and both Client call |
| 199 | // sites (startup + /models switch) go through New. |
| 200 | func idleTimeoutFromEnv() time.Duration { |
| 201 | v := strings.TrimSpace(os.Getenv("CODEHAMR_IDLE_TIMEOUT")) |
| 202 | if v == "" { |
| 203 | return streamIdleTimeout |
| 204 | } |
| 205 | if d, err := time.ParseDuration(v); err == nil && d > 0 { |
| 206 | return d |
| 207 | } |
| 208 | if n, err := strconv.Atoi(v); err == nil && n > 0 { |
| 209 | // Overflow check: a huge bare-seconds value (e.g. nanoseconds pasted |
| 210 | // where seconds were meant) can wrap the multiply to a small positive |
| 211 | // duration, silently killing every live-but-slow stream mid-prefill. |
| 212 | if d := time.Duration(n) * time.Second; d/time.Second == time.Duration(n) { |
no outgoing calls