Files
oh-my-pi/packages/coding-agent
roboomp a6a8258945 fix(browser): propagate cmux tab-close into the run body, not only the caller
Codex review of #4502 flagged that a bare `.catch(() => undefined)`
neutralizes the unhandledRejection but leaves the affected `runInTab`
call blocked inside `runCmuxCode` until timeout when the in-flight
code does not make another cmux socket request (e.g. `await
wait(60_000)`). `releaseTab` was signaling the run only by rejecting
an orphaned promise.

Wire the tab-close event all the way into the cmux run body:

- `PendingRun` gains a `closeAc: AbortController` that `releaseTab`
  aborts BEFORE calling `pending.reject`. `wait(...)` (via
  `waitForBrowserRun` -> `untilAborted`), in-flight cmux socket calls
  (via CmuxTab's `#request` -> `untilAborted`), and facade proxies
  (via `bindBrowserRunFacade`) all consume the composed signal, so
  the run body unwinds within a microtask instead of blocking to its
  own timeout.
- `runInTabWithSnapshot`'s cmux branch composes `closeAc.signal` into
  the run's signal (`AbortSignal.any([opts.signal, closeAc.signal])`)
  and now publishes `runCmuxCode(...)`'s outcome to the shared
  `promise` via `.then(resolve, reject)` and returns `await promise`.
  Both branches thus await the same promise, so `pending.reject`
  always has an attached handler (removing the original crash) AND
  the caller sees `Tab "..." was closed` immediately instead of
  waiting on the run's timeout.
- Drop the defensive `promise.catch(() => undefined)` — the promise
  is now actively consumed on both backends.

The new regression test adds a second case that exercises the
reviewer's exact scenario (`await wait(60_000);`) and asserts:
1. `pending.closeAc.signal.aborted` flips from `false` to `true`
   across `releaseTab`, with the tab-close error as its reason.
2. The awaited `runInTab(...)` rejects with `Tab "..." was closed`.
3. No `unhandledRejection` fires.

Verified locally by temporarily removing `closeAc.abort(...)` in
`releaseTab` — the new assertions fail; restoring it makes them pass.

Fixes #4499
2026-07-04 06:24:45 +00:00
..
2026-07-04 05:19:15 +02:00
…

@oh-my-pi/pi-coding-agent

Core implementation package for the omp coding agent in the oh-my-pi monorepo.

For installation, setup, provider configuration, model roles, slash commands, and full CLI reference, see:

Package-specific references:

Memory backends

The agent supports three mutually-exclusive memory backends, selected via the memory.backend setting (Settings → Memory tab, or ~/.omp/config.yml):

  • off (default) — no memory subsystem runs.
  • local — existing rollout-summarisation pipeline; writes memory_summary.md and consolidated artifacts under the agent dir.
  • hindsight — talks to a Hindsight server (Cloud or self-hosted Docker), retains transcripts every Nth user turn, recalls memories on the first turn of a session, and exposes retain, recall, and reflect.

Hindsight quickstart

  1. Run a Hindsight server (Cloud or docker run -p 8888:8888 ghcr.io/vectorize-io/hindsight:latest).
  2. Set memory.backend = "hindsight" and hindsight.apiUrl = "http://localhost:8888" (or your Cloud URL).
  3. Optional environment overrides (env wins over settings):
    • HINDSIGHT_API_URL, HINDSIGHT_API_TOKEN — connection
    • HINDSIGHT_BANK_ID, HINDSIGHT_DYNAMIC_BANK_ID, HINDSIGHT_AGENT_NAME — bank addressing
    • HINDSIGHT_AUTO_RECALL, HINDSIGHT_AUTO_RETAIN, HINDSIGHT_RETAIN_MODE — lifecycle
    • HINDSIGHT_RECALL_BUDGET, HINDSIGHT_RECALL_MAX_TOKENS — recall sizing
    • HINDSIGHT_BANK_MISSION, HINDSIGHT_DEBUG

Switching backends mid-session is honoured on the next system-prompt rebuild and the next /memory slash command. Existing users with memories.enabled = true|false are migrated to memory.backend = "local"|"off" exactly once on first launch.