code-yeongyu / code-yeongyu/senpi
[Bug]: provider stream-start timeout escapes as uncaughtException and exits OmO
- Dominant language
- TypeScript
- Stars
- 429
- Forks
- 98
- Avg merge
- 5h 3m
- Merged PRs (30d)
- 526
Description
## Summary
When the provider does not emit the first stream event before the configured 90-second deadline, OmO exits because `StreamStartTimeoutError` reaches the process as an uncaught exception.
This report is specifically about the process-level crash. #723 covered retry/cache-billing behavior after a stream-start timeout, not an uncaught exception terminating OmO.
## Observed behavior
`OmO` printed the following and exited:
```text
OmO exiting due to uncaughtException:
StreamStartTimeoutError: Provider stream start timed out after 90000ms
at makeTimeoutError (file://$HOME/.bun/install/global/node_modules/@code-yeongyu/senpi/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js:552:27)
at Timeout.onIdleDeadline (file://$HOME/.bun/install/global/node_modules/@code-yeongyu/senpi/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js:588:31)
at listOnTimeout (node:internal/timers:605:17)
at process.processTimers (node:internal/timers:541:7)
```
## Expected behavior
A provider stream-start timeout should be surfaced as a handled/recoverable provider error (or an orderly failed turn) without terminating the entire OmO process through `uncaughtException`.
## Steps to reproduce
1. Start `omo` and submit a provider-backed turn.
2. Let the provider fail to emit its first stream event before the 90,000 ms stream-start deadline.
3. Observe that the timeout escapes the agent loop and terminates OmO.
I observed this once. A deterministic way to force the provider-side delay is not yet known.
## Environment
- OmO: `5.0.0-0.beta.24`
- Embedded Senpi engine: `2026.8.28`
- `@earendil-works/pi-agent-core`: `2026.8.28`
- Bun: `1.4.0`
- Node.js: `v24.18.0`
- OS: macOS 27.0 (arm64)
- OmO executable: Bun global installation (`$HOME/.bun/bin/omo`)
## Additional context
The installed `createAssistantEventReader` sets a stream-start timer and calls `onIdleTimeout(makeTimeoutError(...))` when no first event arrives. The failure appears to escape the surrounding turn/process boundary rather than being converted into a handled turn error.
Contributor guide
Research direction
The issue points to createAssistantEventReader and the installed dist/agent-loop.js; start by tracing the stream-start timer and onIdleTimeout path during a provider-backed turn. Reproduce the 90-second delay if possible and verify the timeout becomes a handled failed turn without an uncaughtException or process exit.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- bun, node.js, typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100