Repository navigation
Meridian reliability: make concurrent RLM subagents production-safe over Claude Max #22
Description
Activity
Status: all three P0 implementation slices are up and reviewed.
- feat(agent): stable child-scoped provider identity for RLM subagents, side questions, and auxiliary requests #23 → PR fix(coding-agent): scope provider identity to the agent that owns each request #31 (child-scoped provider identity): CI green, reviewed, CLEAN. The live meridian extension needs no changes.
- fix(agent): kind-aware retry with Retry-After and jitter; implement dead maxRetryDelayMs; stop SDK-times-session retry multiplication #24 → PR fix(agent): kind-aware retry with Retry-After and a real delay cap #30 (kind-aware retry): reviewed, rebased onto current
pylon, plus a reviewer follow-up commit — Meridian delivers mid-stream waits aserror.retry_after(seconds) in the SSE frame since headers are already on the wire, and the anthropic provider now prefers that in-frame value; without it the Retry-After honoring was nearly inert for streaming clients. - Rate-limit responses carry no Retry-After, and [1m] benching is profile-wide — one RLM child's 429 cold-caches every concurrent sibling rynfar/meridian#901 → feat: emit Retry-After and scope [1m] rate-limit benching per session rynfar/meridian#907 (emit Retry-After; per-session
[1m]benching): CI green, reviewed. Bench scoping split by trigger: Extra Usage exhaustion stays profile-wide (subscription fact), plain rate limits are session-scoped.
Merge-order note for #30/#31: both touch
agent-session.ts,side-question.ts, and the.pylonledgers; whichever merges second needs a rebase.Remaining, deliberately queued to avoid stacking more unmerged branches on
agent-session.ts: #25 (requestAbort cascade), #26 (cache-prefix stability), and rynfar/meridian#902 (parent-tree cancellation, blocked on theparent_session_idwire contract deferred from #23).All sequenced work has landed. Merged:
- feat(agent): stable child-scoped provider identity for RLM subagents, side questions, and auxiliary requests #23 → PR fix(coding-agent): scope provider identity to the agent that owns each request #31 (child-scoped provider identity)
- fix(agent): kind-aware retry with Retry-After and jitter; implement dead maxRetryDelayMs; stop SDK-times-session retry multiplication #24 → PR fix(agent): kind-aware retry with Retry-After and a real delay cap #30 (kind-aware retry, Retry-After incl. in-frame SSE variant, dead maxRetryDelayMs implemented, retry demultiplication)
- fix(agent): requestAbort() must cascade to active RLM child runs #25 → PR fix(coding-agent): cancelling a turn now stops its subagents #35 (requestAbort cascades to RLM children; deliberate reversal of upstream PR make ctrl+c cancel active turns deterministically PrimeIntellect-ai/prime-agent#346 semantics, recorded in the ledger)
- perf(agent): keep the prompt-cache prefix stable across harness updates, date flips, and tool refreshes #26 → PR perf(coding-agent): keep the prompt-cache prefix stable across harness updates, date flips, and tool refreshes #36 (stable cache prefix; volatile content placement is a per-model contract via
appendOnlyHistoryfor session-cached backends) - feat(agent): expose parent session identity to child extension contexts for RLM trees #34 → PR feat(coding-agent): expose the spawning session's identity to child extension contexts #38 (parent session identity for extensions, immediate-parent semantics)
- Rate-limit responses carry no Retry-After, and [1m] benching is profile-wide — one RLM child's 429 cold-caches every concurrent sibling rynfar/meridian#901 → feat: emit Retry-After and scope [1m] rate-limit benching per session rynfar/meridian#907 (Retry-After emission; session-scoped [1m] benching)
- Parent-to-child cancellation: session-tree registry and abort propagation for RLM subagent trees rynfar/meridian#902 → feat: cancel RLM subagent trees when the parent request aborts rynfar/meridian#912 (live session-tree registry; parent abort propagates to descendant requests; POST /v1/sessions/:key/cancel)
- Ledger state flip in PR docs: mark turn-scoped subagent cancellation as shipped #40.
Extension contract v2 is deployed to the maintainer's
~/.prime/agent/extensions/meridian.ts:appendOnlyHistory: trueon the model entry and guardedparent_session_idstamping.Remaining deployment note: merged is not yet running — Meridian needs a release published and the global install updated, and the Prime Agent fork has no release pipeline by design (see PYLON.md release boundary), so running builds must come from the fork source until that is designed. Deferred items are recorded on the individual PRs. Closing.
Umbrella for making Meridian (the Claude Agent SDK proxy at
rynfar/meridian) a production-safe provider for Prime Agent, including concurrent RLM subagents. Meridian's README currently rates Prime Agent "single-agent verified" with these failure modes: overload amplification, expensive cache churn after fresh-session replay, loss of child-task context during recovery, undelivered tool envelopes, incomplete parent-to-child cancellation.Measured evidence (Meridian telemetry, real prime traffic 2026-08-17/18)
cache_miss: Cache hit rate 0% on resume (expected >50%)diagnostics on continuations.resume=false(full fresh replay) one second later; a dozen requests failed in ~15s.ENVELOPE VIOLATION [undelivered_tool_use]on theipythontool, two coinciding with upstream 529s.Root causes on the Prime Agent side (verified in this repo)
metadata.user_idfromctx.sessionManager.getSessionId()inbefore_provider_request. Inline RLM children reuse the parent's extension runner (packages/coding-agent/src/core/agent-session.tsinline child construction copiesonPayload: this.agent.onPayload; the rootstreamFn/onPayloadinpackages/coding-agent/src/core/sdk.tscloses over the rootextensionRunnerRef), so every inline child request is stamped with the parent's session key. Interleaved parent/child histories on one proxy session key force a fresh-session replay nearly every round.SessionManager.sessionIdalso mutates on fork/branch/load, and compaction/branch-summarization/refinementcompleteSimplecalls bypassonPayloadentirely (unkeyed). → feat(agent): stable child-scoped provider identity for RLM subagents, side questions, and auxiliary requests #23_isRetryableErrortreats everystopReason === "error"as retryable; fixed 2s/4s/8s backoff, no jitter, noRetry-After) stacks on the Anthropic SDK's ownmaxRetries, ≈4 × (1 + sdkRetries)requests per failed turn per agent, times N concurrent children.maxRetryDelayMsis declared and threaded but never read by any provider (dead code). → fix(agent): kind-aware retry with Retry-After and jitter; implement dead maxRetryDelayMs; stop SDK-times-session retry multiplication #24requestAbort()does not call_cancelActiveRlmChildRuns()(onlyabort()does), and every user-facing cancel path usesrequestAbort(). Orphaned children keep consuming the Max subscription. → fix(agent): requestAbort() must cascade to active RLM child runs #25Current date:are serialized into the system prompt;cache_controlrides the last tool definition so tool-set changes/reordering invalidate the tool cache. → perf(agent): keep the prompt-cache prefix stable across harness updates, date flips, and tool refreshes #26Meridian-side work (tracked in rynfar/meridian, cross-linked)
Retry-Afteron 429/503 and scope[1m]rate-limit benching per session instead of profile-wide (today one child's rate limit downgrades and cold-caches every sibling).metadata.user_id.tool_useblocks (Fresh replay drops every assistant tool_use block, so a thinking-plus-tool-call turn becomes an empty turn rynfar/meridian#888) — the mechanism behind lost child-task context after recovery.Sequencing
maxRetryDelayMs, stop retry multiplication (P0)requestAbort()to RLM children (P1)Per PYLON.md, each item needs an upstream-overlap check and a
.pylon/features.yamldecision before landing.