| 209 | |
| 210 | // idleTimeoutFromEnv resolves CODEHAMR_IDLE_TIMEOUT to a duration, falling back |
| 211 | // to streamIdleTimeout when unset or unparseable. Accepts a Go duration string |
| 212 | // ("45m", "1h30m") or a bare number read as seconds. Lives here, not in main's |
| 213 | // applyEnvOverrides, because it's purely an llm concern and both Client call |
| 214 | // sites (startup + /models switch) go through New. |
| 215 | func idleTimeoutFromEnv() time.Duration { |
| 216 | v := strings.TrimSpace(os.Getenv("CODEHAMR_IDLE_TIMEOUT")) |
| 217 | if v == "" { |
| 218 | return streamIdleTimeout |
| 219 | } |
| 220 | if d, err := time.ParseDuration(v); err == nil && d > 0 { |
| 221 | return d |
| 222 | } |
| 223 | if n, err := strconv.Atoi(v); err == nil && n > 0 { |
| 224 | // Overflow check: a huge bare-seconds value (e.g. nanoseconds pasted |
| 225 | // where seconds were meant) can wrap the multiply to a small positive |
| 226 | // duration, silently killing every live-but-slow stream mid-prefill. |
| 227 | if d := time.Duration(n) * time.Second; d/time.Second == time.Duration(n) { |
| 228 | return d |
| 229 | } |
| 230 | } |
| 231 | return streamIdleTimeout |
| 232 | } |
| 233 | |
| 234 | // defaultRetryBackoff paces the transparent resends after a transient |
nothing calls this directly
no outgoing calls
no test coverage detected