* fix(cli): shell completion omitted command aliases like capability, chat, and cron create
* fix(cli): route the dead exec-approvals root alias and single-source alias path expansion
* fix(cli): complete nested aliases in Bash
Co-authored-by: Jack-dev-ops <chen.zegui@xydigit.com>
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: Jack-dev-ops <chen.zegui@xydigit.com>
Preserve fullOutputPath plus partial-spill metadata when oversized tool-result details are summarized for persistence. This keeps aggregate elision from relabeling capped or source-truncated web_fetch spill files as complete after reload.
Write truncated web_fetch extracted content to owner-only private temp files using the shared Full output footer contract. Spills use the wrapped untrusted-content form, cap recoverable content at 2,000,000 chars, and label capped or source-truncated spills as partial instead of full output.
Keep aggregate elision recoverable by preserving existing spill pointers only when the original model-visible footer already disclosed the path. This commit also keeps partial-spill markers honest, handles JSON-escaped footers, and resolves full-clear markers from the original tool-result message after partial aggregate shrinking.
Summary:
- The PR replaces QA Lab suite gateway `fetchJson` success-path `response.json()` with shared `readProviderJsonResponse` and adds an oversized-response regression test.
- PR surface: Source +1, Tests +33. Total +34 across 2 files.
- Reproducibility: yes. Current main still has the unbounded `response.json()` success path in `fetchJson`, an ... l proof for oversized streamed bodies, early cancellation, normal parsing, and the focused regression test.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(scripts): satisfy oxlint in qa-lab suite gateway bound proof
- PR branch already contained follow-up commit before automerge: fix(qa-lab): bound suite runtime gateway JSON response reads
- PR branch already contained follow-up commit before automerge: chore: drop local proof script from qa-lab gateway bound PR
Validation:
- ClawSweeper review passed for head 8c0eb49fcb.
- Required merge gates passed before the squash merge.
Prepared head SHA: 8c0eb49fcb
Review: https://github.com/openclaw/openclaw/pull/99165#issuecomment-4868175663
Co-authored-by: NIO <nocodet@mail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
* fix(infra): formatDuration rolls over near-boundary values to the next unit
The raw float was checked against the boundary before rounding, so values
like 59.5s, 59m30s, and 23h59m30s rounded up to "60 seconds", "60 minutes",
and "24 hours" in session maintenance warning messages instead of "1 minute",
"1 hour", and "1 day". Round first, then check the unit boundary.
Closes#99978
* fix(infra): fix formatDuration progressive rollover in session maintenance warning
Round seconds first, then promote to the next unit only when the
rounded lower unit reaches its overflow threshold (60s->min, 60m->hr,
24h->day). The previous approach compared raw milliseconds against the
unit boundary before rounding, causing half-unit values like 30s, 30m,
and 12h to promote one unit too early.
Closes#99978
* test(infra): expose formatDuration via testing export for direct verification
* ci: retrigger checks
* ci: retrigger checks
* test(infra): keep duration formatter private
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Allow busy TUI sessions to forward prompts into the configured queue while
keeping queued-turn admission, cancellation, restart, and transcript ownership
consistent across the TUI, Gateway, and followup queue.
Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix(agents): use CJK-aware token estimation for tool results
Preserve the conservative 2 chars/token ratio for non-CJK tool results,
while using the accurate 4 chars/token ratio for CJK-heavy tool results.
This avoids false context-overflow errors for CJK content without changing
behavior for Latin/ASCII tool results.
- Add estimateCjkRatio() helper to cjk-chars.ts
- Choose tool-result chars-per-token based on CJK ratio (threshold 0.5)
- Add regression tests for CJK, mixed, and non-CJK tool results
* fix(agents): cover JSON and fallback payloads in CJK ratio pass
* test(agents): fix type cast for non-serializable tool-result regression
* fix(agents): make CJK tool-result estimates monotonic
---------
Co-authored-by: moguangyu5-design <moguangyu5-design@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Expose an opt-in Doctor lint finding for Linux Gateway hosts where a loaded user-level systemd gateway unit has systemd lingering disabled.\n\nValidation:\n- Targeted Doctor health contribution tests passed locally.\n- Exact-head hosted checks passed on 65ec5a0acf, including QA Smoke CI, Real behavior proof, security/CodeQL, check-shrinkwrap, and selected CI shards.\n- Crabbox Azure proof exercised a loaded user systemd gateway unit with Linger=no and observed the expected lint warning.\n\nCo-authored-by: giodl73-repo <166990625+giodl73-repo@users.noreply.github.com>
The non-interactive permission failure surfaces as acpx's
PermissionPromptUnavailableError, not AcpRuntimeError; acpx 0.11.2 throws
it unwrapped (isGenericInternalAcpErrorMessage only matches "Internal
error"). Matches the corrected fact in the acp-agents-setup rewrite.
Pre-commit hook bypassed with formatting proof: repo oxfmt + Mintlify
accordion repair already run on the file (worktree has no node_modules).
* fix(gateway): truncateCloseReason drops partial UTF-8 code point instead of emitting mojibake
Buffer.subarray at a raw byte offset can cut inside a multi-byte UTF-8
sequence. Node decodes the dangling continuation bytes as U+FFFD (3 bytes
each), so the re-encoded result can exceed the intended maxBytes cap —
violating the RFC 6455 close-reason size contract and surfacing garbled
text to clients.
Back up from the cut point to the nearest UTF-8 sequence start before
slicing (UTF-8 continuation bytes match 10xxxxxx; skip them).
Closes#99976
* fix(lint): remove unnecessary non-null assertion on Buffer index
* ci: retrigger checks
Fix qa-channel final reply preview delivery when a harness or plugin path calls deliver without dispatcher metadata. Verified with remote Testbox proof plus hosted PR checks.
* feat(slack): add ignoreOtherMentions channel config
Mirrors the existing Discord `ignoreOtherMentions` option for Slack
channels. When set on a channel entry, drop channel/group/MPIM messages
that mention another user or subteam but not this bot — the inverse of
`requireMention`. Useful in busy channels where the bot would otherwise
reply to side conversations.
Implementation lives in `prepareSlackMessage` right after the
`allowBots: "mentions"` bot-drop gate and before the `shouldRequireMention`
non-mention drop, so it integrates with the new `messageIngress` ingress
pipeline. The gate is conditional on `canDetectMention` (botUserId
resolvable via `auth.test` or explicit mention regexes configured) to
avoid false drops when we have no reliable way to tell bot vs non-bot
mentions apart.
Slack implicit mentions (thread participation) are intentionally NOT
respected here — they fire for every message in a bot-participated
thread, so honoring them would defeat the feature in any active thread.
The gate matches on `wasMentioned` (explicit) and `hasAnyMention`, with
the existing `shouldBypassMention` override (e.g. authorized commands)
also respected.
Includes config types, zod schema, channel-config resolution,
prepare-message implementation, full test coverage in
`prepare.test.ts`, regenerated channel + docs baselines, and Slack
docs entry.
* refactor(slack): harden other-mention filtering
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Type.Record(Type.String(), Type.Any()) serializes via TypeBox to an empty nested value schema (patternProperties: { "^.*$": {} }). AWS Bedrock's strict tool-schema validation rejects the empty sub-schema, breaking all agent turns for Bedrock-backed Anthropic users with Feishu bitable tools enabled.
Replace the three affected free-form field maps (create_record, update_record, create_field) with an explicit non-empty FlexibleFieldValue value schema that still accepts any JSON value. Type.Unknown() is avoided because it also serializes to an empty schema. Adds regression coverage asserting the emitted value schema is non-empty.
Co-authored-by: TwinsLee <1460694+TwinsLee@users.noreply.github.com>
Tool calls in Control UI chat rendered as triple-nested cards: activity
group card + tool-shell bubble chrome + gradient summary pill with a
0 8px 22px drop shadow. Collapsed rows now render as flat single-line
rows with ellipsis, the activity group uses a flat header plus a left
rule, and expanded detail keeps soft tinted blocks without card chrome.
Also deletes the dead legacy .chat-tool-card__details/__output CSS and
the unused renderToolCardSidebar path with its never-taken
renderToolDataBlock branches.
Closes#99760
Keep moved Control UI browser layout tests routed in both UI Vitest configs and stabilize chat suite-order assertions. Verified with Testbox UI proof and changed gate; final PR CI remains the merge gate.
* refactor(models): remove redundant generation model ref alias
* refactor(types): remove redundant local aliases
* refactor(types): preserve shipped model ref type
The claude-cli (claude-stdio) live-session backend emits native
reasoning on stream-json (`thinking_delta` + a snapshot `thinking`
block), but the CLI parser had no thinking handling at all, so it was
silently dropped on every surface in every /reasoning mode.
- cli-output.ts: parse thinking_delta/snapshot into stream:"thinking"
with replace-style per-content-block-index dedupe
(assembleThinkingTextByIndex), robust to tool-interleaved multi-block
turns (snapshot replaces per-index rather than assuming a streamed
prefix). signature_delta/redacted_thinking stay skipped.
- agent-runner-cli-dispatch.ts: bridge stream:"thinking" into
onReasoningStream via a new createReasoningTextBridge (mirrors the
existing assistant-text bridge), replacing the old
assistant-text-as-reasoning heuristic. Track the final reasoning
snapshot and, when present, prepend a durable
`{text, isReasoning: true}` payload before the answer — mirroring
the embedded-runner durable reasoning payload
(embedded-agent-runner/run/payloads.ts).
- agent-runner-execution.ts: thread isReasoningSnapshot through to
onReasoningStream, still passing requiresReasoningProgressOptIn:true
so CLI reasoning rides the exact same channel gates as embedded
reasoning (Discord/Telegram): /reasoning off -> nothing on any
surface, stream -> window preview only, on -> durable payload too.
The bridge is suppressed under the same conditions as the assistant
bridge (e.g. silentExpected follow-ups), so no durable payload is
synthesized for turns that are expected to stay silent.
Supersedes this branch's prior commit (a straight port of
af7eb48e05's emit-always model, no gating and no durable mode) with
the above gated/durable design per product decision.
Also, in cli-output.ts: reset the per-content-block-index thinking
tracker on every new Anthropic message (message_start, or a fresh
top-level "assistant" snapshot's message.id) instead of leaving it
scoped to the whole CLI turn. Content-block indices restart at 0 per
Anthropic message, so a tool round-trip within one turn (message A:
thinking + tool_use; tool result fed back; message B: a fresh
message_start) was letting message A's stale index-0 thinking text
bleed into message B's index-0 delta.
And in agent-runner-cli-dispatch.ts: attach the durable reasoning
payload whenever any thinking was bridged, not only when the CLI also
produced a visible final answer, so a thinking-only turn (no visible
reply) doesn't silently drop its reasoning.
Round 2: the durable `{isReasoning: true}` payload synthesized above
was also reaching the QUEUED FOLLOW-UP delivery path
(followup-runner.ts -> resolveFollowupDeliveryPayloads) with no gate
at all, so a claude-cli queued follow-up with /reasoning off would
leak internal reasoning to the channel as an ordinary visible message.
resolveFollowupDeliveryPayloads (followup-delivery.ts) now takes a
reasoningPayloadsEnabled flag and drops isReasoning payloads unless
it is true; followup-runner.ts threads opts?.reasoningPayloadsEnabled
through at both call sites, from the same GetReplyOptions the direct
path already reads (dispatch-from-config.ts:2054). This makes the
queued-follow-up path apply the identical isReasoning/
reasoningPayloadsEnabled gate that direct dispatch already enforces
(dispatch-from-config.ts:3347, :3537) — no new mechanism, CLI
follow-ups now go through the exact same gate embedded follow-ups do.
Scope note: routeReply's own unconditional suppression of isReasoning
payloads on the origin-routing branch (route-reply.ts:131,
shouldSuppressReasoningPayload) is pre-existing, shared with the
embedded runner, and unchanged by this commit — that gate governs
whether a kept-and-routed reasoning payload is actually rendered on a
cross-channel queued follow-up, and is out of scope here. This commit
closes the leak (off -> never eligible on any path); it does not
change what happens to an eligible payload once it reaches routeReply.
Co-Authored-By: Claude <noreply@anthropic.com>