Self-learning reviewer edits existing skills via targeted patches: it quotes the exact live text (or appends a section) and the service composes the full body inside the receipt-pinned read that hash-binds the proposal — untouched content survives by construction, and patches auto-apply through the scanner-gated pipeline. Full-body rewrites and oversized-skill edits stay pending for the operator. The review prompt shifts to active capture within the existing evidence gates, and shallow same-sender turns accumulate per session (provider-identity scoped, zero-iteration and duplicate-run contracts honored, aborted provenance carried, bounded state) so quick corrections get reviewed with their own transcripts. Replaces closed#119856.
formatInvalidConfigLogMessage used \\n (literal backslash-n) in a
template literal, producing literal text instead of a line break in
gateway startup logs. The sibling createInvalidConfigError already used
a real newline. Operators saw a single-line message with \n text
instead of a readable multi-line block.
Fixes#119870
Co-authored-by: ruel225 <ruel225@users.noreply.github.com>
Emit usage once at the shared plugin completion boundary and expose host-derived plugin identity only on OTel usage spans. Preserve aggregate metric labels and cover the redacted Gateway path end to end.
Refs #98968
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: ZengWen-DT <ceng.wen@xydigit.com>
Room-event turns now send the persisted attributed chat line as the active model body, so the turn replays byte-identically and the provider prefix cache survives ambient traffic. The room-event context block keeps only the marker, room backlog, and reply-policy directive: the duplicate marker, bare inbound_event_kind line, and Current event copy of the chatter are gone, and the dead Current event goal anchor is removed from inbound-meta. Net -18 production LOC; quiet-room behavior unchanged (message tool still required for visible replies).
Deletes the deterministic regex capture path that templated raw chat text into skill proposals (junk like a proposal whose whole procedure was one slugified user message). All autonomous learning now flows through the isolated experience reviewer: it sees a bounded workspace skill list, prefers revising pending proposals or updating the governing skill over creating new ones, and treats durable user corrections as first-class evidence. Update proposals are reviewer-only (explicit opt-in) and never auto-apply, since the reviewer drafts them without the live skill body. Removes the producerless pending-suggestion session machinery. Regression test proves the junk path is gone; real-Telegram E2E verdict in the PR body.
Defer Telegram final-mode text until speech settles, then deliver one captioned voice note or a proven-safe text fallback.
Co-authored-by: Jerry-Xin <jerryxin0@gmail.com>
…is live
Generated assistant media is stored with a null messageId and a transient
retention class until the assistant turn commits its transcript message and
attaches the record. The managed outgoing media GC reaped transient records
purely by age, so any turn still in flight past the 15 minute TTL had its
media records and files deleted before finalization; the later attach is
silently ineffective and the committed message keeps a permanently dead
media URL.
Cleanup now accepts a hasActiveSessionRun probe and skips the transient age
reap while the owning session still has a registered chat run. Both GC entry
points, the chat.history sweep and the maintenance sweep, supply the probe
from the gateway's registered chat run map, which spans admission through
finalization. Sessions without a live run keep the existing TTL behavior.
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
The compare-and-swap revision option was parsed with raw Number(), so
hexadecimal (0x2) and scientific (1e2) values were silently accepted
and used as the CAS revision even though the validation message
requires a non-negative integer. Delegate to the shared
parseStrictNonNegativeInteger helper used across the CLI so
non-decimal input fails fast and no write is attempted.
The skipped malformed transcript row warning prints the total count
followed by a row-number sample capped at 20, with no indication the
list is partial, so messages like "Skipped 25 ... rows 1, ..., 20"
read as if every skipped row were listed. Append an ellipsis when the
count exceeds the retained sample.
* fix: remove bodyless 400/413 from overflow patterns to prevent false compaction
PR #67024 fixed the failover classification path (errors.ts) to not
classify bodyless 400/422 as 'format' errors. However, the compaction
trigger path (isContextOverflow in overflow.ts) still has the pattern
/^4(?:00|13)\s*(?:status code)?\s*\(no body\)/i in OVERFLOW_PATTERNS.
This means a bodyless 400 from any provider triggers compaction via
checkCompaction() -> isContextOverflow(), even though PR #67024
ensured the failover reason is null (not 'format'). The two paths are
independent: failover classification and compaction triggering use
separate functions.
A bodyless 400 cannot be a context overflow — real overflow errors
from all major providers include a descriptive body. A bare 400 with
no body is a transient/malformed error that should surface to the
user, not trigger a compaction loop.
Remove the Cerebras-specific pattern from OVERFLOW_PATTERNS. If
Cerebras returns bodyless 400/413 for actual overflow, it should be
handled with a more specific pattern or NON_OVERFLOW_PATTERNS exclusion.
AI-assisted.
* fix(ai): avoid compacting on bodyless 400 errors
---------
Co-authored-by: lykeion-dev <lykeion-dev@users.noreply.github.com>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
Classify direct and nested checkout roots through Git worktree registration before recursive orphan cleanup, including unborn and canonicalized paths. Fail closed when checkout metadata cannot be inspected.
Punchcard-Session: amber-meadow-timber-8r
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix(diagnostics-otel): harness.run root span adopts diagnostic trace context
Fall back to internalOrTrustedParentContext when there is no active
tracked parent, so the openclaw.harness.run root span (and its whole
OTel subtree) adopts the diagnostic traceId instead of minting a new
OTel root. This lets spans propagated via the diagnostic traceparent
(e.g. a2a-gateway a2a.call / downstream a2a.task) share one trace with
the run internals.
* fix(diagnostics-otel): propagate exported span context
Co-authored-by: HughTang <44694613+HughTang@users.noreply.github.com>
* fix(diagnostics): break propagation import cycle
* fix(diagnostics): preserve trace propagation contracts
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix(ui): preserve chat history and active run timing
* test(ui): prove reconnect preserves active timer
* fix(gateway): keep recovery fallback within budget
* test(gateway): keep chat abort coverage within lint budget