Summary:
- The branch adds Chat Completions token-cap fields to the Gateway request type, forwards them as agent stream parameters, and documents/tests the behavior.
- Reproducibility: yes. Source inspection gives a high-confidence current-main path: send `max_completion_toke ... tokens` to `/v1/chat/completions` and observe that the current handler never sets `streamParams.maxTokens`.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(gateway): wire max_completion_tokens/max_tokens through openai-http
Validation:
- ClawSweeper review passed for head a9c39f7d4a.
- Required merge gates passed before the squash merge.
Prepared head SHA: a9c39f7d4a
Review: https://github.com/openclaw/openclaw/pull/81013#issuecomment-4430303959
Co-authored-by: Bingsen <dingheng.huang@urbanic.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Matrix outbound markdown was hitting the shared `resolveMarkdownTableMode`
"code" fallback for every send because the Matrix channel plugin never
declared `defaultMarkdownTableMode` in its `messaging` block at
`extensions/matrix/src/channel.ts:452`. Tables were emitted as
`<pre><code>` fenced blocks across every Matrix client.
This change declares `defaultMarkdownTableMode: "bullets"`, matching the
Signal and WhatsApp precedent at `extensions/signal/src/shared.ts:111`
and `extensions/whatsapp/src/shared.ts:261`. The choice matches the
cross-client compatibility profile the issue filer surveyed:
Element X iOS squashes HTML `<table>` and Element X Android drops cell
text entirely (element-hq/element-x-android#1551), while bullet lists
render cleanly across every Matrix client. Operators wanting the
previous fenced-code rendering can set `channels.matrix.markdown.tables:
"code"` explicitly; clients that do render real tables can opt in with
`channels.matrix.markdown.tables: "off"` (markdown-it's `table` rule is
already enabled by default through the markdown-it default preset, so
raw markdown tables flow through to native HTML tables on that path).
Docs and the changelog entry list Matrix alongside Signal and WhatsApp
as a bullet-default channel.
Fixes#78990.
Repair managed npm plugin OpenClaw peer links across doctor, install, and update flows.
- relink `peerDependencies.openclaw` packages under managed npm roots during doctor repair
- make read-only doctor preview broken peer links with a `doctor --fix` hint
- reject target plugin installs when their own peer link cannot be repaired, without blocking unrelated installs for stale sibling packages
- preserve update warning behavior for unrepairable package-local `node_modules`
Verification:
- `pnpm test src/plugins/plugin-peer-link.test.ts src/plugins/install.test.ts src/plugins/install.npm-spec.test.ts src/plugins/update.test.ts src/commands/doctor-plugin-registry.test.ts src/commands/doctor/repair-sequencing.test.ts -- --reporter=verbose`
- `pnpm exec oxfmt --check --threads=1 ...`
- `git diff --check`
- Crabbox/Testbox `tbx_01krde1jx199rnpm2rv1rdcj76`: focused tests + `pnpm check:changed`, exit 0
- Real CLI proof in PR body: read-only `openclaw doctor` warning plus `openclaw doctor --fix` symlink repair
Thanks @TheCrazyLex.
Document agents.defaults.subagents.announceTimeoutMs in the sub-agent and configuration references, and align the exported type comment with the runtime default.
Thanks @akrimm702.
Co-authored-by: AI-HUB <144416483+akrimm702@users.noreply.github.com>
Summary:
- Add `openclaw channels status --channel <name>` filtering through CLI, gateway protocol, and fallback status rendering.
- Document the BlueBubbles-to-iMessage cutover path so operators can probe iMessage without starting both monitors.
- Refresh generated Swift protocol model for the new optional channel status parameter.
Verification:
- `pnpm test src/gateway/server-methods/channels.status.test.ts src/commands/channels.status.command-flow.test.ts src/cli/program/routes.test.ts -- --reporter=verbose`
- `CI=true pnpm check:docs`
- `pnpm protocol:check`
- `git diff --check`
- `node scripts/check-changelog-attributions.mjs`
- CI head `45b27e3866`: focused/docs/protocol shards green locally; GitHub broad/scanner jobs queued for runners at merge attempt time; `Real behavior proof` failure is the maintainer-ignorable external-real-proof complaint.
`session_end` was only fired when a session was replaced, reset, deleted, or
compacted -- the gateway shutdown/restart paths closed the process without
enumerating active sessions, so downstream `session_end` plugins
(e.g. claude-mem) accumulated ghost rows in `active` state across restarts.
Issue reporter saw 11 orphaned sessions cause 63 timeouts/day from agent
pool exhaustion.
Add an in-memory active-session tracker
(`src/gateway/active-sessions-shutdown-tracker.ts`) populated by
`emitGatewaySessionStartPluginHook` and forgotten unconditionally by
`emitGatewaySessionEndPluginHook` (even when no plugin listens), so any
session that has already been finalized through the normal lifecycle is
never re-fired by the shutdown drain. The close handler then calls a new
`drainActiveSessionsForShutdown({ reason })` in `session-reset-service.ts`
between the `gateway:shutdown`/`gateway:pre-restart` lifecycle hooks and
the subsystem teardown steps; the drain races a bounded 2 s total timeout
so a slow plugin cannot block SIGTERM/SIGINT, surfacing the timeout as a
`session-end-drain` warning on the shutdown result.
Extend `PluginHookSessionEndReason` with `"shutdown"` and `"restart"` so
plugins can distinguish a graceful close from a planned restart; the close
handler picks `restart` when `restartExpectedMs` is set and `shutdown`
otherwise. Update `emitGatewaySessionStartPluginHook` to also accept
`storePath`, `sessionFile`, and `agentId` so the shutdown drain can build
the same `session_end` payload shape the normal lifecycle path emits, and
update the existing call sites in `session-reset-service.ts` and
`server-methods/sessions.ts` to pass those fields through.
Tests:
- `src/gateway/active-sessions-shutdown-tracker.test.ts` (new) -- tracker
insert/forget/clear semantics, idempotent re-noting, empty-id guard,
snapshot isolation.
- `src/gateway/drain-active-sessions-for-shutdown.test.ts` (new) -- drain
fires `session_end` with the right reason for every tracked session,
skips sessions already finalized via reset/delete/compaction, and still
forgets sessions even when no `session_end` plugin is registered.
- `src/gateway/server-close.test.ts` -- four new cases covering the
shutdown/restart drain wiring, the bounded timeout warning, and the
drain-skipped-when-no-helper case.
Docs:
- `docs/plugins/hooks.md` documents the new `shutdown`/`restart` values
on `PluginHookSessionEndReason`.
- `docs/automation/hooks.md` documents the post-`gateway:shutdown`
`session_end` drain step and its bounded execution guarantee.
Fixes#57790.
Codex review on PR #78687 [P3] flagged that the docs say next-heartbeat
"waits for the next scheduled tick" while the patched timer collapses
next-heartbeat+sessionKey to an immediate targeted wake. Add a callout
describing the exception and pointing callers who want delayed delivery
back at the no-session-key path.
Refs #78687.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds an optional sessionKey to the WakeParamsSchema and threads it through
the gateway wake handler, CronService.wake(), and the underlying timer.wake()
ops so callers can target a specific session for async-task completion
relays instead of always hitting the agent's main session.
Also adds --session-key to `openclaw system event`.
The schema rejects empty/non-string sessionKey at the gateway boundary;
mismatched session keys (a key that does not belong to the resolving agent)
fall back to the agent's main session inside resolveCronSessionKey, which
is the existing safety path.
Refs #52305 (companion to PR #50818, which closes the related cron-run
remap slice at internal enqueue sites). Doesn't depend on #50818.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Provider applyConfig patches merged during models auth login could replace
agents.defaults.model.primary even without --set-default. Snapshot the prior
defaults.model and restore it after the patch unless the user opts in.
Fixes#78162.
Co-authored-by: Cursor <cursoragent@cursor.com>
Summary:
- Add a plain HTML Control UI fallback when the module app never mounts.
- Document blank-page recovery guidance and keep the fallback retry-friendly.
- Cover the timeout path with iframe-isolated regression tests.
Verification:
- pnpm exec oxfmt --check --threads=1 ui/index.html ui/src/ui/mount-fallback.test.ts
- pnpm test ui/src/ui/app.talk.test.ts ui/src/ui/mount-fallback.test.ts
- pnpm ui:build
- pnpm check:changed
- GitHub CI for 8ef18e8bca completed without failures.
fix(gateway): remove unnecessary type assertion in buildAgentPrompt
fix(gateway): reject unsupported forced tool_choice modes
tool_choice=required and named function tool_choice are now rejected
with invalid_request_error until hard enforcement is implemented
at the agent runtime layer. Only auto and none remain supported.
docs: update Chat Completions tool_choice contract to match rejection behavior
Only auto and none are currently accepted; required and named
function tool_choice are rejected until hard enforcement exists.