Summary:
- The branch adds a config-aware tool auth helper, routes image/PDF/media generation preflight and list selection through it, threads `workspaceDir`, and adds focused regression tests plus a changelog entry.
- Reproducibility: yes. by source inspection. Current main gates affected media/PDF/generation preflight paths on env/profile auth while the runtime auth contract already accepts usable `models.providers.*.apiKey`.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(tools): fall back to config apiKey in capability preflight
- PR branch already contained follow-up commit before automerge: fix(tools): honor config apiKey in media tool preflight
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8557…
Validation:
- ClawSweeper review passed for head b8c9242d77.
- Required merge gates passed before the squash merge.
Prepared head SHA: b8c9242d77
Review: https://github.com/openclaw/openclaw/pull/85570#issuecomment-4523770355
Co-authored-by: Mason Huang <masonxhuang@tencent.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: hxy91819
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Summary:
- Adds an optional archive-error callback for session transcript archiving, wires `/new` reset rotation to log previous-transcript archive failures, adds regression coverage, and updates the changelog.
- Reproducibility: yes. source-reproducible. Current main catches and ignores `archiveFileOnDisk` failures ins ... and the source PR proof exercises the same rename failure boundary with a real filesystem permission error.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 9d5f4c0c70.
- Required merge gates passed before the squash merge.
Prepared head SHA: 9d5f4c0c70
Review: https://github.com/openclaw/openclaw/pull/85586#issuecomment-4523917139
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- This PR routes bare `openclaw` to classic onboarding for missing, empty, or metadata-only configs; keeps aut ... cs/changelog/tests; and narrows a Docker E2E boundary-check exception for an existing source-checkout lane.
- Reproducibility: not applicable. this is a feature/default-routing PR rather than a bug report. The branch p ... ill includes a fresh-state terminal run reaching `OpenClaw setup` and tests for the relevant config states.
Automerge notes:
- PR branch already contained follow-up commit before automerge: feat: start onboarding for fresh CLI installs
Validation:
- ClawSweeper review passed for head f4b2572f2e.
- Required merge gates passed before the squash merge.
Prepared head SHA: f4b2572f2e
Review: https://github.com/openclaw/openclaw/pull/85519#issuecomment-4522938004
Co-authored-by: FullerStackDev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Prepack npm GitHub/git source update specs into temporary tarballs before the staged global npm install. Extends coverage to hosted GitHub HTTPS URLs without a `.git` suffix.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
The CONNECT handler pipes clientSocket and upstreamSocket together but
only registers an error handler on upstreamSocket. If the client
disconnects abruptly (ECONNRESET), the unhandled error event on
clientSocket causes the Node process to crash.
Add a clientSocket error handler that logs the event and destroys the
upstream socket. Also change clientSocket.end() to clientSocket.destroy()
in the upstream error handler since destroy() is more appropriate for
error cleanup of piped sockets.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix(agents): handle parallel tool call deltas in openai-completions stream
The OpenAI completions streaming parser tracked only a single
`currentBlock` for tool calls and ignored `toolCall.index`. When the
API sends multiple `delta.tool_calls` entries (e.g., parallel tool
call scaffolding from kimi-for-coding), the parser created a new
block for every entry with a differing `id`, spawning phantom tool
calls with empty names and misrouting arguments.
Replace single-block tracking with Maps keyed by `index` and `id`,
matching the correct logic already present in the bundled
`@earendil-works/pi-ai` dependency. This ensures parallel and
interleaved tool call deltas accumulate to the correct block.
Fixes phantom "unknown" tool calls and empty arguments on
parameterized tools for providers that emit multiple tool_call
indices in streaming deltas.
* fix(agents): finalize tool-call blocks in place to keep maps live
ClawSweeper review [P1]: finishCurrentBlock() and finishAllToolCallBlocks()
were creating new block objects and replacing them in output.content,
but toolCallBlocksByIndex / toolCallBlocksById still pointed at the old
objects. Later deltas for those indices would mutate detached blocks,
causing argument loss and incorrect contentIndex in stream events.
Fix by finalizing arguments in place on the existing block objects.
Add regression test for parallel tool calls with split indices:
- two tool-call slots introduced in one chunk
- argument deltas arriving for each index in subsequent chunks
* fix(agents): keep byte counters out of emitted tool-call blocks
ClawSweeper review [P2]: partialArgsBytes was being stored directly on
the tool-call block objects pushed into output.content, exposing parser
scratch state to emitted stream events and final transcripts.
Replace the inline field with a WeakMap keyed by block object, keeping
byte tracking internal to the parser without polluting the public block
shape.
* refactor(agents): extract ToolCallBlock type for map declarations
ClawSweeper review [P1]: NonNullable<typeof currentBlock> at the map
declaration point was unreliable because currentBlock is initialized to
null and flow-narrowed. Define a local ToolCallBlock alias and use it
for toolCallBlocksByIndex, toolCallBlocksById, and toolCallBlockBytes
to give the maps a precise, stable type.
* fix(agents): iterate typed tool-call map in finishAllToolCallBlocks
ClawSweeper review [P1]: output.content elements are typed as
Record<string, unknown>, so block.partialArgs remained unknown even
after checking block.type === "toolCall". Latest CI failed strict
type checking at parseStreamingJson(block.partialArgs).
Fix by iterating toolCallBlocksByIndex.values() instead — the Map
values are already typed as ToolCallBlock, so partialArgs is known
to be a string and parseStreamingJson compiles cleanly.
* fix(security): escape entry.id in HTML export to prevent attribute XSS
Apply escapeHtmlAttr to entry.id in renderEntry and renderCopyLinkButton
to prevent attribute injection via crafted entry IDs in HTML exports.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* chore: remove proof helper scripts from branch
ClawSweeper P2: committed proof scripts can provide false-positive
validation. Proof output is in the PR body instead.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
---------
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Replace empty .catch(() => {}) on two failDelivery calls with
log.warn() so delivery queue mark-failed errors leave a diagnostic
trail instead of being silently discarded.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
`parseSlashCommandActionArgs` used a naive `startsWith` against the
configured slash prefix. When a skill name shares a prefix with a
built-in command (e.g. a skill named `config-check` vs the built-in
`/config`), the longer name was captured by the shorter built-in
handler and surfaced as an invalid action:
⚠️ /config is disabled. Set commands.config=true to enable.
Any skill whose name starts with a built-in command prefix
(`config-*`, `debug-*`, `models-*`, etc.) was unreachable via slash
invocation from any channel.
Fix: after the prefix match, require that the next character is
whitespace, a colon, or end-of-string. Otherwise the prefix
collided with a longer command name and we return `no-match` so the
longer handler — or the skill router — gets a chance to claim it.
Adds a regression test file `commands-slash-parse.test.ts` covering:
- `/config-check <args>` returns null (the reported case)
- `/configfoo` (no separator) returns null
- `/modelsy` returns null for the `/models` prefix
- `/config:json` still matches (colon is a valid boundary)
- `/config show enabled` still parses cleanly (whitespace boundary)
- empty body still returns the default action
Fixes#84572.
Co-authored-by: infracore <infracore@users.noreply.github.com>
* fix(tui): dismiss watchdog notice when response actually arrives
The streaming watchdog renders 'This response is taking longer than
expected. Send another message to continue.' after 30s without a chat
delta. If a delta or final then arrives — common for runs that are slow
but not stuck — the notice stays in the log alongside the recovered
response and contradicts what the user sees.
Track the notice by runId in the chat log via a new `addPendingSystem`
+ `dismissPendingSystem` pair (mirroring the existing pendingUsers
pattern) and dismiss it from `handleChatEvent` whenever any further chat
event for that run is processed. The watchdog's internal cleanup
(`activeChatRunId` reset, status idle, history reload) is unchanged.
Refs #67052, #69081 (closed). Prior attempt #69026 raised the threshold
and suppressed the notice entirely; this is the narrower fix that keeps
the warning useful for genuinely stuck runs.
* fix(tui): adapt pending notice to repeatable system entries
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
The SIGTERM handler's fire-and-forget IIFE can reject if the graceful
drain or tunnel-teardown throws. Without a catch, this becomes an
unhandled promise rejection. Add .catch() that logs the error and
falls back to a hard stop request. Same treatment for SIGUSR1.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>