Skip to content

feat(agents): split LLM timeout into first-token and idle phases#65898

Closed
kryptt wants to merge 2 commits into
openclaw:mainfrom
kryptt:split-llm-timeouts
Closed

feat(agents): split LLM timeout into first-token and idle phases#65898
kryptt wants to merge 2 commits into
openclaw:mainfrom
kryptt:split-llm-timeouts

Conversation

@kryptt

@kryptt kryptt commented Apr 13, 2026

Copy link
Copy Markdown

Summary

Adds a second, longer timeout window that covers the wait for the first token separately from mid-stream idle gaps. This lets operators set a tight idle timeout for responsive fault detection without killing cold-loading models or upstream routers whose first byte legitimately takes minutes.

  • New config knob: agents.defaults.llm.firstTokenTimeoutSeconds
    • When unset, the first-token wait inherits idleTimeoutSecondsfully backwards-compatible (existing configs behave identically).
    • Set to 0 to disable the first-token timeout without disabling idle.
  • streamWithIdleTimeout signature change: now takes an options object { idleTimeoutMs, firstTokenTimeoutMs?, onIdleTimeout? }. The per-iterator state tracks a firstTokenSeen flag and selects the appropriate window before each next() race.
  • idleTimeoutMs === 0 master off-switch: short-circuits to return baseFn unwrapped (zero overhead when timeouts are disabled).
  • Error messages distinguish the phase:
    • "LLM first-token timeout (Xs): no response from model"
    • "LLM idle timeout (Xs): no response from model"

Motivation

Deployments with local Ollama backends can have cold model loads that legitimately take 2–4 minutes, while mid-stream silence almost always indicates a real fault (network stall, model crash). Previously a single idleTimeoutSeconds had to be generous enough to cover the worst cold-load, which made mid-stream hangs slow to detect. Splitting the two lets both windows be correctly sized.

Example config for a deployment with cold-loading backends + a heartbeat-emitting proxy:

agents:
  defaults:
    llm:
      idleTimeoutSeconds: 30         # catch mid-stream hangs quickly
      firstTokenTimeoutSeconds: 300  # allow cold model loads / warm-up

Test plan

  • pnpm vitest run src/agents/pi-embedded-runner/run/llm-idle-timeout.test.ts — 23 tests pass (8 existing + 15 new/updated)
    • First-token timeout fires when upstream produces no tokens with short firstTokenTimeoutMs
    • Idle timeout fires between chunks with short idleTimeoutMs and long firstTokenTimeoutMs
    • idleTimeoutMs: 0 with a positive firstTokenTimeoutMs disables both phases (master off-switch)
    • resolveLlmFirstTokenTimeoutMs falls back to idle when unset, respects explicit 0, caps at max safe
  • tsc --noEmit clean
  • JSON schema regenerated (config:schema:gen) — new field appears under agents.defaults.llm
  • Existing callers (attempt.ts) updated to the new options-object API

Breaking changes

streamWithIdleTimeout's signature changed from (baseFn, timeoutMs, onIdleTimeout?) to (baseFn, options). The only in-tree caller is attempt.ts (updated). External plugins that wrap the stream function would need to migrate — but this isn't a documented extension point, so in practice this is internal.

The config surface is additive and backwards-compatible.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: M labels Apr 13, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 99367e42e5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

}

// Effective first-token window. Positive override > fallback to idle.
const effectiveFirstTokenMs = firstTokenTimeoutMs > 0 ? firstTokenTimeoutMs : idleTimeoutMs;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Respect explicit first-token timeout disable

resolveLlmFirstTokenTimeoutMs intentionally returns 0 when firstTokenTimeoutSeconds: 0 is configured, but this wrapper immediately maps 0 back to idleTimeoutMs, so the first-token timer still fires. In practice, configs like idleTimeoutSeconds: 30 + firstTokenTimeoutSeconds: 0 will still abort after 30s before the first token, which contradicts the new config contract and schema text that says 0 disables first-token timeout.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5d1e90d. firstTokenTimeoutMs === 0 now truly disables the first-token timer (waits indefinitely for the first chunk; the idle timer still kicks in once chunks start arriving). The resolver returns number | undefined: undefined means inherit-idle, 0 means disabled — preserving the contract the schema text now describes.

@greptile-apps

greptile-apps Bot commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Splits the single idleTimeoutSeconds LLM timeout into two phases: a firstTokenTimeoutMs window (before first token) and an idleTimeoutMs window (mid-stream), with a new agents.defaults.llm.firstTokenTimeoutSeconds config knob. The change is backwards-compatible — when firstTokenTimeoutSeconds is unset, the first-token phase inherits idleTimeoutSeconds.

Confidence Score: 5/5

Safe to merge; only P2 findings (doc clarity, parameter shadowing) with no logic or data-integrity issues.

All remaining findings are P2: a misleading 'Set to 0 to disable' doc comment (actual behavior is fallback to idle, not true disable) and a parameter-name shadow introduced by the options-object refactor. Core logic, timer lifecycle, config schema, and test coverage are all correct.

src/config/types.agent-defaults.ts (doc clarity on firstTokenTimeoutSeconds: 0 semantics) and src/agents/pi-embedded-runner/run/llm-idle-timeout.ts (inner options parameter shadowing).

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/config/types.agent-defaults.ts
Line: 333

Comment:
**Misleading "disable" wording for `firstTokenTimeoutSeconds: 0`**

Setting `firstTokenTimeoutSeconds: 0` does not disable the first-token timeout — it falls back to using `idleTimeoutSeconds` for that phase (because `streamWithIdleTimeout` treats `firstTokenTimeoutMs === 0` the same as "unset"). An operator wanting an unlimited first-token wait (e.g. for extreme cold starts) while keeping idle protection would set this to 0 expecting no cap, but still receive an `idleTimeoutSeconds`-bounded first-token window.

The description should clarify the actual semantics, e.g.:

```suggestion
   * Set to 0 to remove the dedicated first-token window (the first-token phase
   * will then use `idleTimeoutSeconds`, same as when this field is unset).
   * To wait indefinitely for the first token, set a very large value instead.
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run/llm-idle-timeout.ts
Line: 124

Comment:
**`options` parameter shadows the outer `options: StreamIdleTimeoutOptions`**

The inner function returned by `streamWithIdleTimeout` reuses `options` as the name of the `StreamFn` call-site parameter, shadowing the outer `options: StreamIdleTimeoutOptions`. There is no runtime bug (the outer `options` is fully destructured at the top of the function), but the shadowing is new — introduced because the outer positional arguments were collapsed into an `options` object in this PR. If someone adds code inside the inner closure expecting `options` to refer to timeout config, they'll silently pick up the stream-call options instead.

```suggestion
  return (model, context, streamCallOptions) => {
```

and update the one use inside the body:

```ts
const maybeStream = baseFn(model, context, streamCallOptions);
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat(agents): split LLM timeout into fir..." | Re-trigger Greptile

Comment thread src/config/types.agent-defaults.ts Outdated
* may legitimately take much longer than mid-stream token gaps.
* When unset, the first-token wait inherits `idleTimeoutSeconds`
* (backwards-compatible behavior).
* Set to 0 to disable the first-token timeout without disabling idle.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Misleading "disable" wording for firstTokenTimeoutSeconds: 0

Setting firstTokenTimeoutSeconds: 0 does not disable the first-token timeout — it falls back to using idleTimeoutSeconds for that phase (because streamWithIdleTimeout treats firstTokenTimeoutMs === 0 the same as "unset"). An operator wanting an unlimited first-token wait (e.g. for extreme cold starts) while keeping idle protection would set this to 0 expecting no cap, but still receive an idleTimeoutSeconds-bounded first-token window.

The description should clarify the actual semantics, e.g.:

Suggested change
* Set to 0 to disable the first-token timeout without disabling idle.
* Set to 0 to remove the dedicated first-token window (the first-token phase
* will then use `idleTimeoutSeconds`, same as when this field is unset).
* To wait indefinitely for the first token, set a very large value instead.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/config/types.agent-defaults.ts
Line: 333

Comment:
**Misleading "disable" wording for `firstTokenTimeoutSeconds: 0`**

Setting `firstTokenTimeoutSeconds: 0` does not disable the first-token timeout — it falls back to using `idleTimeoutSeconds` for that phase (because `streamWithIdleTimeout` treats `firstTokenTimeoutMs === 0` the same as "unset"). An operator wanting an unlimited first-token wait (e.g. for extreme cold starts) while keeping idle protection would set this to 0 expecting no cap, but still receive an `idleTimeoutSeconds`-bounded first-token window.

The description should clarify the actual semantics, e.g.:

```suggestion
   * Set to 0 to remove the dedicated first-token window (the first-token phase
   * will then use `idleTimeoutSeconds`, same as when this field is unset).
   * To wait indefinitely for the first token, set a very large value instead.
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5d1e90d. firstTokenTimeoutSeconds: 0 now genuinely disables the first-token timer (waits indefinitely for the first chunk). Updated docstring to describe the new contract: leave unset to inherit idleTimeoutSeconds, set to a positive value for a dedicated window, set to 0 to wait indefinitely for the first chunk.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-flagged on the rebased commit, but the underlying semantics were already corrected: firstTokenTimeoutSeconds: 0 now genuinely disables the first-token timer (waits indefinitely for the first chunk; idle timer still applies after the first chunk arrives). Tightened the docstring in 668f3dc to spell that out explicitly so it can't be re-misread.


// Effective first-token window. Positive override > fallback to idle.
const effectiveFirstTokenMs = firstTokenTimeoutMs > 0 ? firstTokenTimeoutMs : idleTimeoutMs;

return (model, context, options) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 options parameter shadows the outer options: StreamIdleTimeoutOptions

The inner function returned by streamWithIdleTimeout reuses options as the name of the StreamFn call-site parameter, shadowing the outer options: StreamIdleTimeoutOptions. There is no runtime bug (the outer options is fully destructured at the top of the function), but the shadowing is new — introduced because the outer positional arguments were collapsed into an options object in this PR. If someone adds code inside the inner closure expecting options to refer to timeout config, they'll silently pick up the stream-call options instead.

Suggested change
return (model, context, options) => {
return (model, context, streamCallOptions) => {

and update the one use inside the body:

const maybeStream = baseFn(model, context, streamCallOptions);
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run/llm-idle-timeout.ts
Line: 124

Comment:
**`options` parameter shadows the outer `options: StreamIdleTimeoutOptions`**

The inner function returned by `streamWithIdleTimeout` reuses `options` as the name of the `StreamFn` call-site parameter, shadowing the outer `options: StreamIdleTimeoutOptions`. There is no runtime bug (the outer `options` is fully destructured at the top of the function), but the shadowing is new — introduced because the outer positional arguments were collapsed into an `options` object in this PR. If someone adds code inside the inner closure expecting `options` to refer to timeout config, they'll silently pick up the stream-call options instead.

```suggestion
  return (model, context, streamCallOptions) => {
```

and update the one use inside the body:

```ts
const maybeStream = baseFn(model, context, streamCallOptions);
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5d1e90d. Renamed the inner closure parameter to streamCallOptions and updated the body — no more shadowing.

@kryptt kryptt force-pushed the split-llm-timeouts branch from 99367e4 to 5d1e90d Compare April 13, 2026 12:25

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5d1e90d6b8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

(error) => idleTimeoutTrigger?.(error),
);
firstTokenTimeoutMs,
onIdleTimeout: (error) => idleTimeoutTrigger?.(error),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve timeout phase when surfacing timeout errors

This callback collapses both timeout phases into a single idle signal: streamWithIdleTimeout now invokes it for first-token and mid-stream idle timeouts, but attempt.ts only records idleTimedOut, so downstream error handling cannot tell which phase actually failed. In practice, a run that times out on firstTokenTimeoutSeconds (for example idle=30s, first-token=10s) is still reported as an idle-timeout case and points users at agents.defaults.llm.idleTimeoutSeconds, which does not fix the configured first-token limit; propagate the timeout phase (or split callbacks/flags) so retries and user guidance target the correct setting.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 668f3dc. Added llmTimeoutPhase: "first-token" | "idle" | null to EmbeddedRunAttemptResult. The idleTimeoutTrigger callback now records the phase by inspecting the error message (streamWithIdleTimeout already labels phase in the message text). The user-facing error in run.ts now points at agents.defaults.llm.firstTokenTimeoutSeconds for first-token timeouts and agents.defaults.llm.idleTimeoutSeconds for mid-stream idle timeouts. Retry/failover logic still keys off the idleTimedOut boolean so both phases stay eligible for the same-model retry — both warrant a retry. Added a parallel test in run.timeout-triggered-compaction.test.ts.

Adds a second, longer timeout window that covers the wait for the first
token separately from mid-stream idle gaps. This allows operators to
set a tight idle timeout for responsive mid-stream fault detection
without killing cold-loading models or upstream routers that only
produce their first byte after a long warm-up.

- New `agents.defaults.llm.firstTokenTimeoutSeconds` config knob.
  When unset, the first-token wait inherits `idleTimeoutSeconds`
  (backwards-compatible: existing configs behave identically).
- `streamWithIdleTimeout` now takes an options object
  `{ idleTimeoutMs, firstTokenTimeoutMs?, onIdleTimeout? }` and tracks
  a per-iterator `firstTokenSeen` flag; the appropriate window is
  selected before each `next()` race.
- `idleTimeoutMs === 0` remains the master off-switch and now short-
  circuits by returning `baseFn` unwrapped.
- Error messages distinguish the phase:
  "LLM first-token timeout (Xs): ..." vs "LLM idle timeout (Xs): ...".

Motivation: deployments with local Ollama backends can have cold
model loads that legitimately take minutes, while mid-stream silence
almost always indicates a real fault. Previously a single idle timeout
had to be generous enough for the worst cold-load, which made
mid-stream hangs slow to detect.

Tests: covers first-token timeout firing with short idle, idle
timeout firing after first chunk with long first-token window, `0`
disable semantics, and `resolveLlmFirstTokenTimeoutMs` fallback rules.
@kryptt kryptt force-pushed the split-llm-timeouts branch from 5d1e90d to 668f3dc Compare April 13, 2026 12:45
@kryptt kryptt requested a review from a team as a code owner April 13, 2026 12:45
kryptt added a commit to kryptt/ollama-router that referenced this pull request Apr 13, 2026
When the agent streams from a model the backend hasn't loaded yet,
Ollama goes silent while it maps the weights — often for minutes.
Any downstream idle-timeout short enough to catch real mid-stream
hangs (~30s) will trip during this load. Raising the idle timeout
to cover cold-load worst-case (5m+) makes mid-stream fault detection
unbearably slow.

Fix: inject protocol-appropriate keepalive chunks during the load,
gated by positive evidence the model wasn't already hot.

Flow:
1. On streaming chat/completion requests, call /api/ps on the chosen
   backend (PREFLIGHT_TIMEOUT=10s). If the model is loaded, proxy
   normally — zero overhead.
2. If not loaded, commit to 200 OK and run the heartbeat path:
   emit no-op keepalive chunks every LOADING_HEARTBEAT=15s while
   waiting for upstream headers + first body byte, bounded by
   LOADING_MAX_WAIT=300s.
3. Once real bytes flow, stop heartbeating and stream through.
4. If upstream errors *after* we committed 200, emit an in-band
   error per protocol (Ollama: done:true+error; OpenAI SSE:
   {error} + [DONE]; Anthropic: event: error).

Protocol coverage:
- Ollama /api/chat + /api/generate (NDJSON, empty-content chunks)
- OpenAI /v1/chat/completions + /v1/completions (SSE comment lines)
- Anthropic /v1/messages (SSE comment lines)

Heartbeat format is spec-compliant no-op in every case — SSE comments
are ignored by EventSource/httpx_sse/OpenAI+Anthropic SDKs; Ollama
NDJSON uses valid chunks with empty content and done:false so
python-ollama, ollama-js, etc. just skip them.

Knobs (all in seconds, env vars on the Deployment):
  OLLAMA_ROUTER_LOADING_HEARTBEAT  (default 15)
  OLLAMA_ROUTER_PREFLIGHT_TIMEOUT  (default 10)
  OLLAMA_ROUTER_LOADING_MAX_WAIT   (default 300)

Honesty property: heartbeats only ever fire when /api/ps said the
model wasn't loaded at request start. If the model then fails to load,
upstream returns an error body, the heartbeat stops naturally, and
the in-band error encoder surfaces the failure to the client. The
pathological "upstream hangs forever after preflight succeeds"
window is bounded by LOADING_MAX_WAIT.

17 new tests cover protocol classification, heartbeat payload shape,
preflight matching (name/model/prefix), and end-to-end heartbeat with
a mock backend.

Companion change on the client side (PR openclaw/openclaw#65898)
splits idleTimeoutSeconds into idleTimeoutSeconds + firstTokenTimeoutSeconds,
so deployments without this router still get a sane cold-load window.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c9b4c65821

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +1540 to +1541
"The model did not produce its first token before the LLM first-token timeout. " +
"Please try again, or increase `agents.defaults.llm.firstTokenTimeoutSeconds` in your config (set to 0 to wait indefinitely for the first token).";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep timeout leak detection aligned with first-token errors

This new first-token timeout text does not match the timeout leak pattern used by QA character eval (extensions/qa-lab/src/character-eval.ts only matches model did not produce a response before the LLM idle timeout). In scenarios where a run times out before the first token, the failure text can now pass through detectTranscriptFailure unclassified, so eval runs may be marked clean even though a timeout error leaked into the transcript. Please update the timeout detection/matching path to treat first-token and idle timeout messages consistently.

Useful? React with 👍 / 👎.

@clawsweeper

clawsweeper Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

Keep this PR open because the first-token/idle split is still a meaningful unsolved capability, but the current branch is not merge-ready: it conflicts with current timeout plumbing, reintroduces a retired config subtree, and still lacks real behavior proof.

Canonical path: Close this stale PR. The latest review rated it F, the branch still lacks merge-ready proof, and there has been no human follow-up after the durable review.

So I’m closing this here because the remaining work is already tracked in the canonical issue.

Review details

Best possible solution:

Close this stale PR. The latest review rated it F, the branch still lacks merge-ready proof, and there has been no human follow-up after the durable review.

Do we have a high-confidence way to reproduce the issue?

Not applicable as a strict bug reproduction: this PR adds a new two-phase timeout capability. The claimed deployment scenario is plausible from source, but the PR does not include real slow-model/proxy proof.

Is this the best way to solve the issue?

No, not as currently shaped. The split is useful, but the implementation needs a current-main rebase, preserved timeout/abort contracts, and a maintainer-approved config surface before it is the best solution.

Security review:

Security review cleared: The diff does not touch dependency sources, workflows, secrets, package resolution, or other supply-chain surfaces; the concerns are compatibility and availability, not security.

AGENTS.md: found and applied where relevant.

What I checked:

  • stale F-rated PR: PR was opened 2026-04-13T10:56:24Z, is older than 30 days, and the latest review rated it F.
  • proof blocker: real behavior proof is mock_only and proof tier is F, so this branch is not merge-ready without contributor follow-up.
  • no human follow-up: live comments and timeline hydrated by apply contain no non-automation activity after the ClawSweeper review.

Likely related people:

  • steipete: Current-main blame and history around the timeout resolver, abort wrapper, deprecation docs, and QA timeout handling point to recent work by Peter Steinberger on this surface. (role: recent area contributor; confidence: high; commits: 506c2ee18186, d9dc75774bcb, 7e2a1db53b8d; files: src/agents/embedded-agent-runner/run/llm-idle-timeout.ts, docs/gateway/doctor.md, extensions/qa-lab/src/character-eval.ts)
  • ImLukeF: Recent history on the old pi embedded runner timeout file includes LLM timeout default and explicit run-timeout policy commits. (role: adjacent timeout contributor; confidence: medium; commits: ddefce3c1868, 7f2814fc4a76; files: src/agents/pi-embedded-runner/run/llm-idle-timeout.ts)
  • Ayaan Zaidi: History shows work unifying the idle timeout with the runner abort path and later idle-timeout fallback work in related merged history. (role: introduced/maintained timeout behavior; confidence: medium; commits: 179f713c88c6, f7e9d80536ad; files: src/agents/pi-embedded-runner/run/llm-idle-timeout.ts, src/agents/embedded-agent-runner/run/llm-idle-timeout.ts)
  • Liu Yuan: The available history shows the initial LLM idle timeout implementation was authored in commit 84b72e6. (role: introduced behavior; confidence: medium; commits: 84b72e66b918; files: src/agents/pi-embedded-runner/run/llm-idle-timeout.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against e0018382eb00.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. labels May 20, 2026
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label May 20, 2026
@clawsweeper

clawsweeper Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat.

Where did the egg go?
  • The egg game starts only after the PR passes the real-behavior proof check.
  • Before that, no creature or rarity is rolled. The treat waits for real proof.
  • This is still just collectible flavor: proof affects review readiness, not creature quality.

@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Jun 5, 2026
@clawsweeper

clawsweeper Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper applied the proposed close for this PR.

@clawsweeper clawsweeper Bot closed this Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling extensions: codex merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: M stale Marked as stale due to inactivity status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant