* fix(openai-completions): seal native reasoning before the answer
deepseek-style providers stream reasoning via reasoning_content deltas
then switch to the answer via content deltas with no boundary event.
thinking_end was only emitted by the end-of-stream finishBlock loop, so
it landed after the answer's text_delta and channels merged the answer
into the reasoning block.
Seal the open native thinking block when visible text (or a tool call)
begins so thinking_end precedes the answer; tag-based <think> reasoning
is unaffected (closed by the partitioner). finishBlock is now idempotent
so the end-of-stream loop never re-emits thinking_end.
* fix(openai-completions): preserve co-streamed reasoning
* fix(openai-completions): order co-streamed reasoning
* fix(openai-completions): seal co-streamed reasoning
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix(docs): show inline read_when hints in docs:list
* test(scripts): use shared temp directory helper
* test(scripts): route docs list helper test
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Bundles only isolated low-risk Node shards, keeps stateful suites isolated, and right-sizes Blacksmith runners to reduce runner-registration bursts. Exact-head CI run 27932220655 passed the changed CI planning lanes; its two remaining agent test reds match latest main baseline run 27929063460 and are unrelated to this CI-only diff.
* fix(gateway): accept port for health and probe
* fix(gateway): repair health port override
* fix(gateway): repair health port override
* fix(gateway): accept port for health and probe
---------
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Move Canvas, Discord, Slack, voice-call, and WhatsApp skill docs from the root bundled skill tree into their owning plugin packages, with manifest skills declarations and docs/test path updates.
Validation:
- node --import tsx scripts/sync-plugin-versions.ts --check
- node scripts/run-vitest.mjs src/skills/loading/env-path-guidance.test.ts
- autoreview clean
- Crabbox Azure pnpm check:changed run_59ba76511d57 / lease cbx_cbc6750dad72
- wrapper prepare passed pnpm install --frozen-lockfile, pnpm build, and pnpm check before the oversized full local pnpm test was stopped
Follow-up: #95132 remains as the stacked PR for the rest of the starter-skill/Sherpa/ClawHub work.
* fix(config): add "stdio" to McpServerSchema transport union
Add z.literal("stdio") to the transport union so that
config validate accepts transport: "stdio" on command-bearing
MCP servers, matching the runtime behavior.
Fixes#95082
* fix(config): align McpServerConfig transport type and add schema coverage
- Widened McpServerConfig.transport to include "stdio"
- Added schema test for command-bearing server with explicit stdio transport
- Added schema test rejecting unsupported transport values
* fix(config): constrain transport stdio to command-bearing MCP servers
* fix(config): align stdio refine with runtime trimmed command check
The Subagents section of docs/plugins/hooks.md listed subagent_ended
but did not describe its payload. Plugin authors reaching for
agentId (as on subagent_spawned) silently got undefined because
PluginHookSubagentEndedEvent uses targetSessionKey as its identity
field and has no agentId/childSessionKey.
Document all fields from PluginHookSubagentEndedEvent and explicitly
note the missing identity fields so handlers can correlate events
correctly.
Closes#95186
Co-authored-by: MaHaoHao-ch <MaHaoHao-ch@users.noreply.github.com>
* fix(ssh): reject hostnames with stray leading or trailing colons in parseSshTarget
parseSshTarget would previously return host values like "host:" or ":22"
when the input had a trailing colon with no port, or a leading colon with
no host. These values flow directly into SSH config HostName fields and the
ssh CLI argv, which causes connections to fail.
Add a guard that rejects host parts starting or ending with ":" before
the existing "-" prefix check. Existing valid inputs ("host", "host:22",
"user@host:22") are unaffected.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(ssh): validate stray-colon host in explicit-port parse branch
---------
Co-authored-by: Claude <noreply@anthropic.com>
estimateTokens charged 4800 chars per image in the toolResult branch but
counted only text in the user branch, so image blocks in recent user turns
scored zero. findCutPoint never reached keepRecentTokens and left the cut at
the earliest point, so image-heavy sessions compacted to a no-op and looped on
context overflow. Fold the per-image accounting into one shared helper used by
both branches.
Wake the isolated polling drain immediately after a worker-spooled
update is written to channel_ingress_events, instead of waiting for
the next drain interval.
- Add requestImmediateDrain() calls after worker write and spooled message
- Track pending drain requests while drain is active (fix race condition)
- Add regression test for updates arriving during active drain
Fixes#86957.
* fix(googlechat): sanitize internal tool-trace lines from outbound text (#90684)
Google Chat ran only sanitizeForPlainText() on outbound text, so internal
assistant trace lines leaked to users — most visibly the
`⚠️🛠️ <command> (agent) failed` banner emitted for benign non-zero shell
exits (e.g. a grep with no match, exit 1). The turn succeeds but the user
gets an alarming "failed" message.
Apply sanitizeAssistantVisibleText() before sanitizeForPlainText() in the
googlechat outbound sanitizeText hook, mirroring Discord and WhatsApp. The
hook runs pre-chunking in the shared deliver path, covering all text sends.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(googlechat): sanitize internal tool-trace lines from outbound text (#90684)
---------
Co-authored-by: Claude Code <claude@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>