Allow plugin subagent runs to pass provider/model overrides through the typed runtime, gateway validation, and ingress agent path. Apply explicit per-run overrides without persisting them to session state, and cover the gateway + agent behavior with regressions.
Regeneration-Prompt: |
PR #48277 already forwarded provider and model from plugin subagent runtime calls, but review found two contract gaps: the typed plugin runtime did not declare those fields, and the gateway agent RPC rejected them because the schema and handler path did not accept or propagate them. Make the override path end-to-end valid without broad refactors.
Keep the change additive. Extend the plugin runtime and gateway agent request types just enough to carry provider/model overrides. Ensure gateway ingress passes those fields into the existing agent command path, and let agent runs honor explicit per-call overrides without persisting them as session overrides. Add focused regression coverage for the gateway forwarding path and for non-persistent per-run overrides.
* fix(agents): rephrase session reset prompt to avoid Azure content filter
Azure OpenAI's content filter flags the phrase 'Execute your Session
Startup sequence now' as potentially harmful, causing /new and /reset
to return 400 for all Azure-hosted deployments.
Replace 'Execute ... now' with 'Run your Session Startup sequence' in
session-reset-prompt.ts and post-compaction-context.ts. The semantics
are identical but the softer phrasing avoids the false-positive.
Closes#42769
* ci: retrigger checks (windows shard timeout)
* fix: add changelog for Azure startup prompt fix (#43403) (thanks @xingsy97)
---------
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(gateway): normalize session key casing to prevent ghost sessions on Linux
On case-sensitive filesystems (Linux), mixed-case session keys like
agent:ops:MySession and agent:ops:mysession resolve to different store
entries, creating ghost duplicates that never converge.
Core changes in session-utils.ts:
- resolveSessionStoreKey: lowercase all session key components
- canonicalizeSpawnedByForAgent: accept cfg, resolve main-alias references
via canonicalizeMainSessionAlias after lowercasing
- loadSessionEntry: return legacyKey only when it differs from canonicalKey
- resolveGatewaySessionStoreTarget: scan store for case-insensitive matches;
add optional scanLegacyKeys param to skip disk reads for read-only callers
- Export findStoreKeysIgnoreCase for use by write-path consumers
- Compare global/unknown sentinels case-insensitively in all canonicalization
functions
sessions-resolve.ts:
- Make resolveSessionKeyFromResolveParams async for inline migration
- Check canonical key first (fast path), then fall back to legacy scan
- Delete ALL legacy case-variant keys in a single updateSessionStore pass
Fixes#12603
* fix(gateway): propagate canonical keys and clean up all case variants on write paths
- agent.ts: use canonicalizeSpawnedByForAgent (with cfg) instead of raw
toLowerCase; use findStoreKeysIgnoreCase to delete all legacy variants
on store write; pass canonicalKey to addChatRun, registerAgentRunContext,
resolveSendPolicy, and agentCommand
- sessions.ts: replace single-key migration with full case-variant cleanup
via findStoreKeysIgnoreCase in patch/reset/delete/compact handlers; add
case-insensitive fallback in preview (store already loaded); make
sessions.resolve handler async; pass scanLegacyKeys: false in preview
- server-node-events.ts: use findStoreKeysIgnoreCase to clean all legacy
variants on voice.transcript and agent.request write paths; pass
canonicalKey to addChatRun and agentCommand
* test(gateway): add session key case-normalization tests
Cover the case-insensitive session key canonicalization logic:
- resolveSessionStoreKey normalizes mixed-case bare and prefixed keys
- resolveSessionStoreKey resolves mixed-case main aliases (MAIN, Main)
- resolveGatewaySessionStoreTarget includes legacy mixed-case store keys
- resolveGatewaySessionStoreTarget collects all case-variant duplicates
- resolveGatewaySessionStoreTarget finds legacy main alias keys with
customized mainKey configuration
All 5 tests fail before the production changes, pass after.
* fix: clean legacy session alias cleanup gaps (openclaw#12846) thanks @mcaxtr
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Small model testing showed the label did not meaningfully help:
- Sub-3B models fail regardless of format
- 8B models untested with label specifically
- Frontier models never needed it
The bracket convention [Wed 2026-01-28 22:30 EST] matches existing
channel envelope format and is widely present in training data.
Saves ~2-3 tokens per message vs the labeled version.
Changes [Wed 2026-01-28 20:30 EST] to [Current Date: Wed 2026-01-28 20:30 EST].
Tested with qwen3-1.7B: even with DOW in the timestamp, the model
ignored it and tried to compute the day using Zeller's Congruence.
The "Current Date:" semantic label is widely present in training data
and gives small models the best chance of recognizing the timestamp
as authoritative context rather than metadata to parse.
Cost: ~18 tokens per message. Prevents hallucination spirals that
burn hundreds or thousands of tokens on date derivation.
Changes [2026-01-28 20:30 EST] to [Wed 2026-01-28 20:30 EST].
Costs ~1 extra token but provides day-of-week for smaller models
that can't derive DOW from a date. Frontier models already handle
it, but this is cheap insurance for 7B-class models.
Replace verbose formatUserTime (Wednesday, January 28th, 2026 — 8:30 PM)
with the same formatZonedTimestamp used by channel envelopes (2026-01-28
20:30 EST). This:
- Saves ~4 tokens per message (~7 vs ~11)
- Uses globally unambiguous YYYY-MM-DD 24h format
- Removes 12/24h config option (always 24h, agent-facing)
- Anchors envelope detection to the actual format function — if channels
change their timestamp format, our injection + detection change too
- Adds test that compares injection output to formatZonedTimestamp directly
Exported formatZonedTimestamp from auto-reply/envelope.ts for reuse.
Messages arriving through the gateway agent method (TUI, web, spawned
subagents, sessions_send, heartbeats) now get a timestamp prefix
automatically. This gives all agent contexts date/time awareness
without modifying the system prompt (which is cached for stability).
Channel messages (Discord, Telegram, etc.) already have timestamps
via envelope formatting in a separate code path and never reach
the agent handler, so there is no double-stamping risk.
Cron jobs also inject their own 'Current time:' prefix and are
detected and skipped.
Extracted as a pure function (injectTimestamp) with 12 unit tests
covering: timezone handling, 12/24h format, midnight boundaries,
envelope detection, cron detection, and empty messages.
Integration test verifies the agent handler wires it in correctly.
Closes#3658
Refs: #1897, #1928, #2108
- Add resumeArgs to DEFAULT_CLAUDE_BACKEND for proper --resume flag usage
- Fix gateway not preserving cliSessionIds/claudeCliSessionId in nextEntry
- Add test for CLI session ID preservation in gateway agent handler
- Update docs with new resumeArgs default