microscopic-jackal-24676
08/23/2026, 2:57 PMlimited-student-10747
08/23/2026, 3:06 PMlimited-student-10747
08/23/2026, 3:10 PMfresh-machine-37269
08/23/2026, 3:10 PMfresh-machine-37269
08/23/2026, 3:26 PMenhancement + performance (the repo's issue-readiness-check workflow will auto-apply ready-for-dev since the body has ### Desired Behavior with a checklist of ### Acceptance Criteria). The acceptance criteria cover the key points you asked for: the tests must fail on the pre-fix branches (pre-#4570 lifecycle-lock, pre-#4481 bashevent glob/eval-loop, pre-#4417 ConversationInfo GC wedge, pre-#4473 LLM global-config serialization) and pass on current main, with any obvious main perf defects fixed in the course of deploying them.
One accurate nuance I baked in: software-agent-sdk does not currently use release-please itself — its release path is prepare-release.yml → create-release.yml → pypi-release.yml. (release-please lives in OpenHands/OpenHands and downstream repos like automation.) So the issue asks to wire the gate into `prepare-release`/`create-release`, "or the equivalent release-please path if the SDK later adopts it."
Relevant context I found and referenced: existing stress suite tests/agent_server/stress/ (opt-in, -m stress, with budgets.py and a agent-server-stress-tests CI job), existing complementary issue #4477 ("Add cheap load tests for concurrent conversations"), and the deadlock/perf issues #4514/#4513/#4548/#4569.
On the PostHog p50/p95 question: short answer — not with what's captured today.
There are two layers, and neither currently emits per-operation latency:
• Agent-server telemetry (in software-agent-sdk, openhands-agent-server/openhands/agent_server/telemetry/): emits agent_server.conversation_created/finished/failed with a duration_bucket, but durations are deliberately bucketized to coarse bins (`DURATION_BOUNDS = 1,5,15,60,300,1800`s) and raw counts/durations are never reported (re-identification/privacy policy in `models.py`/`sanitizer.py`). That gives a coarse histogram of whole-conversation duration — not precise p50/p95, and it has no per-operation timing at all (no TTFT, tool-call latency, event-search latency, or db write/hydration path).
• Canvas/frontend telemetry (OpenHands/OpenHands src/services/telemetry.ts): tracks funnel/product events (conversation_start_requested, user_message_sent, automation_executed, backend_added, etc.). These are action/funnel events with no duration-style numeric properties, so they can't produce p50/p95 either.
So while PostHog can compute percentile aggregations over a numeric event property, that data doesn't exist in the current schemas. To get p50/p95 on the operations Jamie cited (switch-chat, db write/hydration, create chat, tool execution, TTFT), you'd need to add per-operation timing instrumentation — best done server/SDK-side (that's where those operations actually run), e.g. OpenTelemetry/OpenInference spans that also emit a numeric duration_ms property to PostHog. That's a natural companion to the load-test issue, and emitting a raw numeric duration is a deliberate departure from the current bucketed/privacy-constrained policy, so worth calling out explicitly rather than assuming it falls out.limited-student-10747
08/23/2026, 3:34 PMfresh-machine-37269
08/23/2026, 3:36 PMenhancement + performance, with a body that satisfies the repo's ready-for-dev readiness check (### Desired Behavior + ### Acceptance Criteria checklist), so the ready-for-dev label will be auto-applied.
The acceptance criteria enumerate the specific operations behind each previously-observed deadlock/slowness issue, so coverage is explicit rather than "add some timing." For each one I named a metric and the historical issue it maps to:
• Conversation create/delete/close — global _lifecycle_lock wedge (#4514 → #4570, #4569)
• Event service load / runtime hydration — _prepare_persisted_runtime under the lock (#4514, #4513, #4548)
• Bash event search / listing — event-loop `glob`/`scandir` (#4480 → #4481)
• ConversationInfo composition — GC wedge (#4417)
• LLM call concurrency — global-config serialization (#4473 / OpenHands#16459)
• switch_llm on the state lock (#3485 → #3486)
• stats_callback stats streaming state-lock re-acquisition (#3348 → #3349)
• subscribe_to_events initial push — wedged WS subscriber (#3118 → #3201)
• ACP restart loopback secret lookup (#3737)
• Model-info discovery — synchronous timeout-less probe (#3912)
• Summary caching (#4483), idle eviction (#4202), plus the earlier perf batch (#3168 lease renewal, #3165 autosave batching, #3162 pub/sub, #3156 condensation, #3163 file-store LRU, #3169 execution thread pool)
Two design points I made explicit in the issue because they're load-bearing:
1. Emit raw numeric durations (not the current coarse duration_bucket) plus a "stuck"/timeout terminal value, so a deadlock is distinguishable from slow — and flag that this is a deliberate departure from the current bucketed/privacy-constrained `models.py`/`sanitizer.py` policy that needs an explicit allowlist decision.
2. Tie each metric back to the load-test gate in #4588 so the new timing data (not ad-hoc assertions) back the release gate where practical.microscopic-jackal-24676
08/23/2026, 3:56 PMmicroscopic-jackal-24676
08/23/2026, 3:58 PMlimited-student-10747
08/23/2026, 3:59 PMmicroscopic-jackal-24676
08/24/2026, 2:06 AMevent_search / `bash_event_search`— sync executor scans; needs a sync-timer variant plus a decision on the count/fan-out magnitude (raw counts are re-identifying).
• llm_call / switch_llm config serialization— the SDK`LLM`has no telemetry tap today; needs a cross-package sink hook and a contention/lock-wait timer (wire time =/= lock-wait time).
• Lease renewal / autosave / pub/sub / condensation— background loops and cross-module fan-out; needs a defined per-iteration operation boundary and the same cross-package hook.microscopic-jackal-24676
08/24/2026, 2:13 AMdefault_stuck_budget_ms @ 20s. If anything takes longer than that it's declared jammed or locked. Maybe if another issue gets opened to plumb in the remaining timing instrumentation, some consideration can also be paid to exactly what the budget_ms should be on a per call site basis.