Commit Graph

262 Commits

Author SHA1 Message Date
cpojer
d0cb8c19b2 chore: wtf. 2026-02-17 13:36:48 +09:00
Sebastian
ed11e93cf2 chore(format) 2026-02-16 23:20:16 -05:00
cpojer
9c5f08244e chore: Format files. 2026-02-17 11:37:11 +09:00
Peter Steinberger
0c1c34c950 refactor(plugins): split before-agent hooks by model and prompt phases 2026-02-17 03:28:20 +01:00
cpojer
ac38d51290 chore: Fix types in tests 7/N. 2026-02-17 11:22:49 +09:00
Peter Steinberger
fb6e415d0c fix(agents): align session lock hold budget with run timeouts 2026-02-17 03:10:36 +01:00
cpojer
01ea808876 chore: Format files. 2026-02-17 10:57:31 +09:00
Gustavo Madeira Santana
a1538ea637 Revert "fix: flatten remaining anyOf/oneOf in Gemini schema cleaning"
This reverts commit 06b961b037.
2026-02-16 20:33:58 -05:00
Peter Steinberger
b9e7299a70 refactor(test): share embedded runner overflow mocks 2026-02-17 00:49:37 +00:00
cpojer
90ef2d6bdf chore: Update formatting. 2026-02-17 09:18:40 +09:00
Peter Steinberger
eaa2f7a7bf fix(ci): restore main lint/typecheck after direct merges 2026-02-16 23:26:11 +00:00
Peter Steinberger
076df941a3 feat: add configurable tool loop detection 2026-02-17 00:17:01 +01:00
artale
a62ff19a66 fix(agent): isolate last-turn total in token usage reporting (#17016)
recordAssistantUsage accumulated cacheRead across the entire multi-turn
run, and totalTokens was clamped to contextTokens. This caused
session_status to report 100% context usage regardless of actual load.

Changes:
- run.ts: capture lastTurnTotal from the most recent model call and
  inject it into the normalized usage before it reaches agentMeta.
- usage-reporting.test.ts: verify usage.total reflects current turn,
  not accumulated total.

Fixes #17016
2026-02-17 00:00:12 +01:00
Vishal Doshi
e91a5b0216 fix: release stale session locks and add watchdog for hung API calls (#18060)
When a model API call hangs indefinitely (e.g. Anthropic quota exceeded
mid-call), the gateway acquires a session .jsonl.lock but the promise
never resolves, so the try/finally block never reaches release(). Since
the owning PID is the gateway itself, stale detection cannot help —
isPidAlive() always returns true.

This commit adds four layers of defense:

1. **In-process lock watchdog** (session-write-lock.ts)
   - Track acquiredAt timestamp on each held lock
   - 60-second interval timer checks all held locks
   - Auto-releases any lock held longer than maxHoldMs (default 5 min)
   - Catches the hung-API-call case that try/finally cannot

2. **Gateway startup cleanup** (server-startup.ts)
   - On boot, scan all agent session directories for *.jsonl.lock files
   - Remove locks with dead PIDs or older than staleMs (30 min)
   - Log each cleaned lock for diagnostics

3. **openclaw doctor stale lock detection** (doctor-session-locks.ts)
   - New health check scans for .jsonl.lock files
   - Reports PID status and age of each lock found
   - In --fix mode, removes stale locks automatically

4. **Transcript error entry on API failure** (attempt.ts)
   - When promptError is set, write an error marker to the session
     transcript before releasing the lock
   - Preserves conversation history even on model API failures

Closes #18060
2026-02-16 23:59:22 +01:00
tian Xiao
edbc68e9f1 feat: support Z.AI tool_stream for real-time tool call streaming
Add support for Z.AI's native tool_stream parameter to enable real-time
visibility into model reasoning and tool call execution.

- Automatically inject tool_stream=true for zai/z-ai providers
- Allow disabling via params.tool_stream: false in model config
- Follows existing pattern of OpenRouter and OpenAI wrappers

This enables Z.AI API features described in:
https://docs.z.ai/api-reference#streaming

AI-assisted: Claude (OpenClaw agent) helped write this implementation.
Testing: lightly tested (code review + pattern matching existing wrappers)

Closes #18135
2026-02-16 23:58:35 +01:00
Ty Sabs
46bf210e04 fix: always drop orphaned OpenAI reasoning blocks in session history
downgradeOpenAIReasoningBlocks was only called on model change, but
orphaned reasoning items (e.g. from an aborted stream) can exist without
a model switch and cause a 400 from the OpenAI Responses API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:55:28 +01:00
artale
4df970d711 fix: improve error for unconfigured local providers (ollama/vllm) (#17328)
When a user sets `agents.defaults.model.primary: "ollama/gemma3:4b"`
but forgets to set OLLAMA_API_KEY, the error is a confusing
"unknown model: ollama/gemma3:4b". The Ollama provider requires any
dummy API key to register (the local server doesn't actually check it),
but this isn't obvious from the error.

Add `buildUnknownModelError()` that detects known local providers
(ollama, vllm) and appends an actionable hint with the env var name
and a link to the relevant docs page.

Before: Unknown model: ollama/gemma3:4b
After:  Unknown model: ollama/gemma3:4b. Ollama requires authentication
        to be registered as a provider. Set OLLAMA_API_KEY="ollama-local"
        (any value works) or run "openclaw configure".
        See: https://docs.openclaw.ai/providers/ollama

Closes #17328
2026-02-16 23:54:31 +01:00
Xinhua Gu
ae0b110e44 fix(security): set 0o600 on remaining session file write paths
Follow-up to #18066 — three session file write sites were missed:

- auto-reply/reply/session.ts: forked session transcript header
- pi-embedded-runner/session-manager-init.ts: session file reset
- gateway/server-methods/sessions.ts: compacted transcript rewrite

All now use mode 0o600 consistent with transcript.ts and chat.ts.
2026-02-16 23:53:28 +01:00
Yaroslav Boiko
838259331f fix(discord): add media dedup production code for messaging tool pipeline
Wire media URL tracking through the embedded agent pipeline so that
media already sent via messaging tools is not delivered again by the
reply dispatcher.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:51:51 +01:00
Sean McLellan
06b961b037 fix: flatten remaining anyOf/oneOf in Gemini schema cleaning
The Cloud Code Assist API rejects anyOf/oneOf in tool schemas, not just
unsupported keywords. The image tool (index 21) had:
  image: { anyOf: [{ type: "string" }, { type: "array" }] }
which caused "JSON schema is invalid" errors when forwarded to Anthropic
via google-antigravity.

simplifyUnionVariants only handles literal unions and single non-null
variants. This adds a fallback in cleanSchemaForGeminiWithDefs that
flattens any remaining anyOf/oneOf to a simple type schema.

Also reverts the previous provider-aware normalizeToolParameters and
sanitizeToolsForGoogle changes, which were incorrect — the cleaning IS
needed for Google's API regardless of which downstream model is used.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:51:41 +01:00
Sean McLellan
1bbf6206d5 fix: exclude google-antigravity from Gemini schema sanitization
google-antigravity serves Anthropic models (e.g. claude-opus-4-6-thinking),
not Gemini. sanitizeToolsForGoogle was stripping JSON Schema keywords
(minimum, maximum, format, etc.) needed for Anthropic's draft 2020-12
compliance, causing "JSON schema is invalid" rejections on tool 21
(web_search).

This was the actual root cause — the earlier normalizeToolParameters
fix was being overridden by this second sanitization pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 23:51:41 +01:00
Nate Fikru
b90eb51520 feat(plugins): add modelOverride/providerOverride to before_agent_start hook
Enable plugins to override the model and provider for agent runs by
returning modelOverride/providerOverride from the before_agent_start
hook. The hook is now invoked early in run.ts (before resolveModel)
so overrides take effect. The result is passed to attempt.ts via
earlyHookResult to prevent double-firing.

This enables security-critical use cases like routing PII-containing
prompts to local models instead of cloud providers.
2026-02-16 23:50:24 +01:00
Vignesh Natarajan
5a26d1c622 Agent: guard reminder promises behind cron scheduling 2026-02-16 14:07:16 -08:00
Shadow
72e228e14b Heartbeat: allow suppressing tool warnings (#18497)
* Heartbeat: allow suppressing tool warnings

* Changelog: note heartbeat tool-warning suppression
2026-02-16 13:29:24 -06:00
Gustavo Madeira Santana
8a67016646 Agents: raise bootstrap total cap and warn on /context truncation (#18229)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: f6620526df
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-02-16 12:04:53 -05:00
Peter Steinberger
f717a13039 refactor(agent): dedupe harness and command workflows 2026-02-16 14:59:30 +00:00
Hongwei Ma
dddb1bc942 fix(telegram): fix streaming with extended thinking models overwriting previous messages/ also happens to Execution error (#17973)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 34b52eead8
Co-authored-by: Marvae <11957602+Marvae@users.noreply.github.com>
Co-authored-by: obviyus <22031114+obviyus@users.noreply.github.com>
Reviewed-by: @obviyus
2026-02-16 18:54:34 +05:30
Shakker
09566b1693 fix(discord): preserve channel session keys via channel_id fallbacks (#17622)
* fix(discord): preserve channel session keys via channel_id fallbacks

* docs(changelog): add discord session continuity note

* Tests: cover discord channel_id fallback

---------

Co-authored-by: Shadow <hi@shadowing.dev>
2026-02-15 20:30:17 -06:00
Peter Steinberger
5fb4032fb6 refactor(test): share overflow compaction mocks 2026-02-15 22:02:09 +00:00
David Harmeyer
7c822d039b feat(plugins): expose llm input/output hook payloads (openclaw#16724) thanks @SecondThread
Verified:
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: SecondThread <18317476+SecondThread@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-15 16:01:00 -06:00
Peter Steinberger
824901083b refactor(pi): dedupe compaction failure 2026-02-15 19:09:05 +00:00
vignesh07
d306d598ce fix(agents): don't force store=true for codex responses 2026-02-14 23:23:14 -08:00
Peter Steinberger
cb2f978ed5 refactor(agents): share model alias line builder 2026-02-15 07:01:29 +00:00
Peter Steinberger
a4bf619522 refactor(agents): share toolResult details stripping 2026-02-15 06:21:13 +00:00
Tyler Yust
b8f66c260d Agents: add nested subagent orchestration controls and reduce subagent token waste (#14447)
* Agents: add subagent orchestration controls

* Agents: add subagent orchestration controls (WIP uncommitted changes)

* feat(subagents): add depth-based spawn gating for sub-sub-agents

* feat(subagents): tool policy, registry, and announce chain for nested agents

* feat(subagents): system prompt, docs, changelog for nested sub-agents

* fix(subagents): prevent model fallback override, show model during active runs, and block context overflow fallback

Bug 1: When a session has an explicit model override (e.g., gpt/openai-codex),
the fallback candidate logic in resolveFallbackCandidates silently appended the
global primary model (opus) as a backstop. On reinjection/steer with a transient
error, the session could fall back to opus which has a smaller context window
and crash. Fix: when storedModelOverride is set, pass fallbacksOverride ?? []
instead of undefined, preventing the implicit primary backstop.

Bug 2: Active subagents showed 'model n/a' in /subagents list because
resolveModelDisplay only read entry.model/modelProvider (populated after run
completes). Fix: fall back to modelOverride/providerOverride fields which are
populated at spawn time via sessions.patch.

Bug 3: Context overflow errors (prompt too long, context_length_exceeded) could
theoretically escape runEmbeddedPiAgent and be treated as failover candidates
in runWithModelFallback, causing a switch to a model with a smaller context
window. Fix: in runWithModelFallback, detect context overflow errors via
isLikelyContextOverflowError and rethrow them immediately instead of trying the
next model candidate.

* fix(subagents): track spawn depth in session store and fix announce routing for nested agents

* Fix compaction status tracking and dedupe overflow compaction triggers

* fix(subagents): enforce depth block via session store and implement cascade kill

* fix: inject group chat context into system prompt

* fix(subagents): always write model to session store at spawn time

* Preserve spawnDepth when agent handler rewrites session entry

* fix(subagents): suppress announce on steer-restart

* fix(subagents): fallback spawned session model to runtime default

* fix(subagents): enforce spawn depth when caller key resolves by sessionId

* feat(subagents): implement active-first ordering for numeric targets and enhance task display

- Added a test to verify that subagents with numeric targets follow an active-first list ordering.
- Updated `resolveSubagentTarget` to sort subagent runs based on active status and recent activity.
- Enhanced task display in command responses to prevent truncation of long task descriptions.
- Introduced new utility functions for compacting task text and managing subagent run states.

* fix(subagents): show model for active runs via run record fallback

When the spawned model matches the agent's default model, the session
store's override fields are intentionally cleared (isDefault: true).
The model/modelProvider fields are only populated after the run
completes. This left active subagents showing 'model n/a'.

Fix: store the resolved model on SubagentRunRecord at registration
time, and use it as a fallback in both display paths (subagents tool
and /subagents command) when the session store entry has no model info.

Changes:
- SubagentRunRecord: add optional model field
- registerSubagentRun: accept and persist model param
- sessions-spawn-tool: pass resolvedModel to registerSubagentRun
- subagents-tool: pass run record model as fallback to resolveModelDisplay
- commands-subagents: pass run record model as fallback to resolveModelDisplay

* feat(chat): implement session key resolution and reset on sidebar navigation

- Added functions to resolve the main session key and reset chat state when switching sessions from the sidebar.
- Updated the `renderTab` function to handle session key changes when navigating to the chat tab.
- Introduced a test to verify that the session resets to "main" when opening chat from the sidebar navigation.

* fix: subagent timeout=0 passthrough and fallback prompt duplication

Bug 1: runTimeoutSeconds=0 now means 'no timeout' instead of applying 600s default
- sessions-spawn-tool: default to undefined (not 0) when neither timeout param
  is provided; use != null check so explicit 0 passes through to gateway
- agent.ts: accept 0 as valid timeout (resolveAgentTimeoutMs already handles
  0 → MAX_SAFE_TIMEOUT_MS)

Bug 2: model fallback no longer re-injects the original prompt as a duplicate
- agent.ts: track fallback attempt index; on retries use a short continuation
  message instead of the full original prompt since the session file already
  contains it from the first attempt
- Also skip re-sending images on fallback retries (already in session)

* feat(subagents): truncate long task descriptions in subagents command output

- Introduced a new utility function to format task previews, limiting their length to improve readability.
- Updated the command handler to use the new formatting function, ensuring task descriptions are truncated appropriately.
- Adjusted related tests to verify that long task descriptions are now truncated in the output.

* refactor(subagents): update subagent registry path resolution and improve command output formatting

- Replaced direct import of STATE_DIR with a utility function to resolve the state directory dynamically.
- Enhanced the formatting of command output for active and recent subagents, adding separators for better readability.
- Updated related tests to reflect changes in command output structure.

* fix(subagent): default sessions_spawn to no timeout when runTimeoutSeconds omitted

The previous fix (75a791106) correctly handled the case where
runTimeoutSeconds was explicitly set to 0 ("no timeout"). However,
when models omit the parameter entirely (which is common since the
schema marks it as optional), runTimeoutSeconds resolved to undefined.

undefined flowed through the chain as:
  sessions_spawn → timeout: undefined (since undefined != null is false)
  → gateway agent handler → agentCommand opts.timeout: undefined
  → resolveAgentTimeoutMs({ overrideSeconds: undefined })
  → DEFAULT_AGENT_TIMEOUT_SECONDS (600s = 10 minutes)

This caused subagents to be killed at exactly 10 minutes even though
the user's intent (via TOOLS.md) was for subagents to run without a
timeout.

Fix: default runTimeoutSeconds to 0 (no timeout) when neither
runTimeoutSeconds nor timeoutSeconds is provided by the caller.
Subagent spawns are long-running by design and should not inherit the
600s agent-command default timeout.

* fix(subagent): accept timeout=0 in agent-via-gateway path (second 600s default)

* fix: thread timeout override through getReplyFromConfig dispatch path

getReplyFromConfig called resolveAgentTimeoutMs({ cfg }) with no override,
always falling back to the config default (600s). Add timeoutOverrideSeconds
to GetReplyOptions and pass it through as overrideSeconds so callers of the
dispatch chain can specify a custom timeout (0 = no timeout).

This complements the existing timeout threading in agentCommand and the
cron isolated-agent runner, which already pass overrideSeconds correctly.

* feat(model-fallback): normalize OpenAI Codex model references and enhance fallback handling

- Added normalization for OpenAI Codex model references, specifically converting "gpt-5.3-codex" to "openai-codex" before execution.
- Updated the `resolveFallbackCandidates` function to utilize the new normalization logic.
- Enhanced tests to verify the correct behavior of model normalization and fallback mechanisms.
- Introduced a new test case to ensure that the normalization process works as expected for various input formats.

* feat(tests): add unit tests for steer failure behavior in openclaw-tools

- Introduced a new test file to validate the behavior of subagents when steer replacement dispatch fails.
- Implemented tests to ensure that the announce behavior is restored correctly and that the suppression reason is cleared as expected.
- Enhanced the subagent registry with a new function to clear steer restart suppression.
- Updated related components to support the new test scenarios.

* fix(subagents): replace stop command with kill in slash commands and documentation

- Updated the `/subagents` command to replace `stop` with `kill` for consistency in controlling sub-agent runs.
- Modified related documentation to reflect the change in command usage.
- Removed legacy timeoutSeconds references from the sessions-spawn-tool schema and tests to streamline timeout handling.
- Enhanced tests to ensure correct behavior of the updated commands and their interactions.

* feat(tests): add unit tests for readLatestAssistantReply function

- Introduced a new test file for the `readLatestAssistantReply` function to validate its behavior with various message scenarios.
- Implemented tests to ensure the function correctly retrieves the latest assistant message and handles cases where the latest message has no text.
- Mocked the gateway call to simulate different message histories for comprehensive testing.

* feat(tests): enhance subagent kill-all cascade tests and announce formatting

- Added a new test to verify that the `kill-all` command cascades through ended parents to active descendants in subagents.
- Updated the subagent announce formatting tests to reflect changes in message structure, including the replacement of "Findings:" with "Result:" and the addition of new expectations for message content.
- Improved the handling of long findings and stats in the announce formatting logic to ensure concise output.
- Refactored related functions to enhance clarity and maintainability in the subagent registry and tools.

* refactor(subagent): update announce formatting and remove unused constants

- Modified the subagent announce formatting to replace "Findings:" with "Result:" and adjusted related expectations in tests.
- Removed constants for maximum announce findings characters and summary words, simplifying the announcement logic.
- Updated the handling of findings to retain full content instead of truncating, ensuring more informative outputs.
- Cleaned up unused imports in the commands-subagents file to enhance code clarity.

* feat(tests): enhance billing error handling in user-facing text

- Added tests to ensure that normal text mentioning billing plans is not rewritten, preserving user context.
- Updated the `isBillingErrorMessage` and `sanitizeUserFacingText` functions to improve handling of billing-related messages.
- Introduced new test cases for various scenarios involving billing messages to ensure accurate processing and output.
- Enhanced the subagent announce flow to correctly manage active descendant runs, preventing premature announcements.

* feat(subagent): enhance workflow guidance and auto-announcement clarity

- Added a new guideline in the subagent system prompt to emphasize trust in push-based completion, discouraging busy polling for status updates.
- Updated documentation to clarify that sub-agents will automatically announce their results, improving user understanding of the workflow.
- Enhanced tests to verify the new guidance on avoiding polling loops and to ensure the accuracy of the updated prompts.

* fix(cron): avoid announcing interim subagent spawn acks

* chore: clean post-rebase imports

* fix(cron): fall back to child replies when parent stays interim

* fix(subagents): make active-run guidance advisory

* fix(subagents): update announce flow to handle active descendants and enhance test coverage

- Modified the announce flow to defer announcements when active descendant runs are present, ensuring accurate status reporting.
- Updated tests to verify the new behavior, including scenarios where no fallback requester is available and ensuring proper handling of finished subagents.
- Enhanced the announce formatting to include an `expectFinal` flag for better clarity in the announcement process.

* fix(subagents): enhance announce flow and formatting for user updates

- Updated the announce flow to provide clearer instructions for user updates based on active subagent runs and requester context.
- Refactored the announcement logic to improve clarity and ensure internal context remains private.
- Enhanced tests to verify the new message expectations and formatting, including updated prompts for user-facing updates.
- Introduced a new function to build reply instructions based on session context, improving the overall announcement process.

* fix: resolve prep blockers and changelog placement (#14447) (thanks @tyler6204)

* fix: restore cron delivery-plan import after rebase (#14447) (thanks @tyler6204)

* fix: resolve test failures from rebase conflicts (#14447) (thanks @tyler6204)

* fix: apply formatting after rebase (#14447) (thanks @tyler6204)
2026-02-14 22:03:45 -08:00
Vignesh Natarajan
909b5411bb fix (agents): force store=true for direct openai responses 2026-02-14 20:45:47 -08:00
Vignesh Natarajan
17588f51f0 fix (agents): return timeout reply on empty timed-out runs 2026-02-14 20:33:12 -08:00
Vignesh Natarajan
2bf330777f fix (sandbox/prompts): align workspace guidance with container workdir 2026-02-14 20:20:42 -08:00
Sebastian
bcadef2e20 test(agents): add payload builder fixture helper 2026-02-14 22:34:48 -05:00
Sebastian
d08ff2c2c9 refactor(agents): extract tool-error warning helpers 2026-02-14 22:34:48 -05:00
Vai
2c8b921054 feat: add messages.suppressToolErrors config option (#16620)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 9ae4394b81
Co-authored-by: vai-oro <258511217+vai-oro@users.noreply.github.com>
Co-authored-by: sebslight <19554889+sebslight@users.noreply.github.com>
Reviewed-by: @sebslight
2026-02-14 22:28:58 -05:00
Peter Steinberger
683aa09b55 refactor(media): harden localRoots bypass (#16739)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 89dce69f50
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete
2026-02-15 03:27:01 +01:00
Tyler Yust
edb06170f5 fix(image): allow workspace and sandbox media paths (#15541) 2026-02-14 17:46:36 -08:00
Peter Steinberger
b744ba3410 refactor(test): share overflow compaction mocks 2026-02-14 23:51:41 +00:00
Bin Deng
c0cd3c3c08 fix: add safety timeout to session.compact() to prevent lane deadlock (#16533)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 21e4045add
Co-authored-by: BinHPdev <219093083+BinHPdev@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-02-14 17:54:12 -05:00
Peter Steinberger
200aa441df test: fix vitest harness typing 2026-02-14 23:25:32 +01:00
Peter Steinberger
e63dcc320b refactor(test): share pi embedded model fixtures 2026-02-14 22:06:04 +00:00
Bruno Škvorc
dbdcbe03e7 fix: preserve bootstrap paths and expose failed mutations (#16131)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 385dcbd8a9
Co-authored-by: Swader <1430603+Swader@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-02-14 17:01:16 -05:00
Peter Steinberger
c06a962bb6 test(e2e): stabilize suite 2026-02-14 22:01:11 +01:00
Michael Verrilli
e6f67d5f31 fix(agent): prevent session lock deadlock on timeout during compaction (#9855)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 64a28900f1
Co-authored-by: mverrilli <816450+mverrilli@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-02-14 14:24:20 -05:00