Commit Graph

9780 Commits

Author SHA1 Message Date
Peter Steinberger
93dc3bb79a perf(test): avoid npm pack in plugin install e2e fixtures 2026-02-14 00:17:49 +00:00
Peter Steinberger
bc3eb98445 fix(cli): avoid runtime import cycle in routed commands 2026-02-14 00:17:29 +00:00
Peter Steinberger
2f49d8858c perf(cli): slim route-first bootstrap with lazy route handlers 2026-02-14 00:12:23 +00:00
Peter Steinberger
fecb3f326e perf(test): trim models/browser suite overhead 2026-02-14 00:08:02 +00:00
Peter Steinberger
cf2524b8b9 refactor(models): share auth helpers and forward-compat list fallbacks 2026-02-14 01:07:35 +01:00
Peter Steinberger
363a56ab87 refactor(telegram): streamline file-ref wrapping and hoist regexes 2026-02-14 01:03:50 +01:00
Peter Steinberger
3a73e2508b perf(gateway): skip idle channel shutdown work 2026-02-13 23:57:03 +00:00
Vincent Koc
a0cbf9002d fix(models): antigravity opus 4.6 availability follow-up (#12845)
* fix(models): antigravity opus 4.6 availability follow-up

* chore(format): apply updated oxfmt config to models files

* fix(models): retain zai glm-5 forward-compat fallback after extraction

* chore(format): apply updated oxfmt config

* fix(models): fail fast on unknown auth login provider

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-14 00:54:46 +01:00
Peter Steinberger
23e8f3a20a perf(test): merge block-streaming scenarios into single fixture run 2026-02-13 23:54:28 +00:00
Glucksberg
9bd2ccb017 feat: add pre-prompt context size diagnostic logging (openclaw#8930) thanks @Glucksberg
Verified:
- pnpm build
- pnpm check
- pnpm test

Co-authored-by: Glucksberg <80581902+Glucksberg@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-13 17:54:22 -06:00
Peter Steinberger
79bd82a35b perf(test): statically import gateway reload deps 2026-02-13 23:52:20 +00:00
Divanoli Mydeen Pitchai
1055e71c4b fix(telegram): auto-wrap .md file references in backticks to prevent URL previews (#8649)
* fix(telegram): auto-wrap file references with TLD extensions to prevent URL previews

Telegram's auto-linker aggressively treats filenames like HEARTBEAT.md,
README.md, main.go, script.py as URLs and generates domain registrar previews.

This fix adds comprehensive protection for file extensions that share TLDs:
- High priority: .md, .go, .py, .pl, .ai, .sh
- Medium priority: .io, .tv, .fm, .am, .at, .be, .cc, .co

Implementation:
- Added wrapFileReferencesInHtml() in format.ts
- Runs AFTER markdown→HTML conversion
- Tokenizes HTML to respect tag boundaries
- Skips content inside <code>, <pre>, <a> tags (no nesting issues)
- Applied to all rendering paths: renderTelegramHtmlText, markdownToTelegramHtml,
  markdownToTelegramChunks, and delivery.ts fallback

Addresses review comments:
- P1: Now handles chunked rendering paths correctly
- P2: No longer wraps inside existing code blocks (token-based parsing)
- No lookbehinds used (broad Node compatibility)

Includes comprehensive test suite in format.wrap-md.test.ts

AI-assisted: true

* fix(telegram): prevent URL previews for file refs with TLD extensions

Two layers were causing spurious link previews for file references like
`README.md`, `backup.sh`, `main.go`:

1. **markdown-it linkify** converts `README.md` to
   `<a href="http://README.md">README.md</a>` (.md = Moldova TLD)
2. **Telegram auto-linker** treats remaining bare text as URLs

## Changes

### Primary fix: suppress auto-linkified file refs in buildTelegramLink
- Added `isAutoLinkedFileRef()` helper that detects when linkify auto-
  generated a link from a bare filename (href = "http://" + label)
- Rejects paths with domain-like segments (dots in non-final path parts)
- Modified `buildTelegramLink()` to return null for these, so file refs
  stay as plain text and get wrapped in `<code>` by the wrapper

### Safety-net: de-linkify in wrapFileReferencesInHtml
- Added pre-pass that catches auto-linkified anchors in pre-rendered HTML
- Handles edge cases where HTML is passed directly (textMode: "html")
- Reuses `isAutoLinkedFileRef()` logic — no duplication

### Bug fixes discovered during review
- **Fixed `isClosing` bug (line 169)**: the check `match[1] === "/"`
  was wrong — the regex `(<\/?)}` captures `<` or `</`, so closing
  tags were never detected. Changed to `match[1] === "</"`. This was
  causing `inCode/inPre/inAnchor` to stay stuck at true after any
  opening tag, breaking file ref wrapping after closing tags.
- **Removed double `wrapFileReferencesInHtml` call**: `renderTelegramHtmlText`
  was calling `markdownToTelegramHtml` (which wraps) then wrapping again.

### Test coverage (+12 tests, 26 total)
- `.sh` filenames (original issue #6932 mentioned backup.sh)
- Auto-linkified anchor replacement
- Auto-linkified path anchor replacement
- Explicit link preservation (different label)
- File ref after closing anchor tag (exercises isClosing fix)
- Multiple file types in single message
- Real URL preservation
- Explicit markdown link preservation
- File ref after real URL in same message
- Chunked output file ref wrapping

Closes #6932

* test(telegram): add comprehensive edge case coverage for file ref wrapping

Add 16 edge case tests covering:
- File refs inside bold/italic tags
- Fenced code blocks (no double-wrap)
- Domain-like paths preserved as links (example.com/README.md)
- GitHub URLs with file paths
- wrapFileRefs: false behavior
- All TLD extensions (.ai, .io, .tv, .fm)
- Non-TLD extensions not wrapped (.png, .css, .js)
- File ref position (start, end, multiple in sequence)
- Nested paths without domain segments
- Version-like paths (v1.0/README.md wraps, example.com/v1.0/README.md links)
- Hyphens and underscores in filenames
- Uppercase extensions

* fix(telegram): use regex literal and depth counters for tag tracking

Code review fixes:
1. Replace RegExp constructor with regex literal for autoLinkedAnchor
   - Avoids double-escaping issues with \s
   - Uses backreference \1 to match href=label pattern directly

2. Replace boolean toggles with depth counters for tag nesting
   - codeDepth, preDepth, anchorDepth track nesting levels
   - Correctly handles nested tags like <pre><code>...</code></pre>
   - Prevents wrapping inside any level of protected tags

Add 4 tests for edge cases:
- Nested code tags (depth tracking)
- Multiple anchor tags in sequence
- Auto-linked anchor with backreference match
- Anchor with different href/label (no match)

* fix(telegram): add escapeHtml and escapeRegex for defense in depth

Code review fixes:
1. Escape filename with escapeHtml() before inserting into <code> tags
   - Prevents HTML injection if regex ever matches unsafe chars
   - Defense in depth (current regex already limits to safe chars)

2. Escape extensions with escapeRegex() before joining into pattern
   - Prevents regex breakage if extensions contain metacharacters
   - Future-proofs against extensions like 'c++' or 'd.ts'

Add tests documenting regex safety boundaries:
- Filenames with special chars (&, <, >) don't match
- Only [a-zA-Z0-9_.\-./] chars are captured

* fix(telegram): catch orphaned single-letter TLD patterns

When text like 'R&D.md' doesn't match the main file pattern (because &
breaks the character class), the 'D.md' part can still be auto-linked
by Telegram as a domain (https://d.md/).

Add second pass to catch orphaned TLD patterns like 'D.md', 'R.io', 'X.ai'
that follow non-alphanumeric characters and wrap them in <code> tags.

Pattern: ([^a-zA-Z0-9]|^)([A-Za-z]\.(?:extensions))(?=[^a-zA-Z0-9/]|$)

Tests added:
- 'wraps orphaned TLD pattern after special character' (R&D.md → R&<code>D.md</code>)
- 'wraps orphaned single-letter TLD patterns' (X.ai, R.io)

* refactor(telegram): remove popular domain TLDs from file extension list

Remove .ai, .io, .tv, .fm from FILE_EXTENSIONS_WITH_TLD because:
- These are commonly used as real domains (x.ai, vercel.io, github.io)
- Rarely used as actual file extensions
- Users are more likely referring to websites than files

Keep: md, sh, py, go, pl (common file extensions, rarely intentional domains)
Keep: am, at, be, cc, co (less common as intentional domain references)

Update tests to reflect the change:
- Add test for supported extensions (.am, .at, .be, .cc, .co)
- Add test verifying popular TLDs stay as links

* fix(telegram): prevent orphaned TLD wrapping inside HTML tags

Code review fixes:

1. Orphaned TLD pass now checks if match is inside HTML tag
   - Uses lastIndexOf('<') vs lastIndexOf('>') to detect tag context
   - Skips wrapping when between < and > (inside attributes)
   - Prevents invalid HTML like <a href="...&<code>D.md</code>">

2. textMode: 'html' now trusts caller markup
   - Returns text unchanged instead of wrapping
   - Caller owns HTML structure in this mode

Tests added:
- 'does not wrap orphaned TLD inside href attributes'
- 'does not wrap orphaned TLD inside any HTML attribute'
- 'does not wrap in HTML mode (trusts caller markup)'

* refactor(telegram): use snapshot for orphaned TLD offset clarity

Use explicit snapshot variable when checking tag positions in orphaned
TLD pass. While JavaScript's replace() doesn't mutate during iteration,
this makes intent explicit and adds test coverage for multi-TLD HTML.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(telegram): prevent orphaned TLD wrapping inside code/pre tags

- Add depth tracking for code/pre tags in orphaned TLD pass
- Fix test to expect valid HTML output
- 55 tests now covering nested tag scenarios

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(telegram): clamp depth counters and add anchor tracking to orphaned pass

- Clamp depth counters at 0 for malformed HTML with stray closing tags
- Add anchor depth tracking to orphaned TLD pass to prevent wrapping
  inside link text (e.g., <a href="...">R&D.md</a>)
- 57 tests covering all edge cases

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(telegram): keep .co domains linked and wrap punctuated file refs

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-14 00:51:47 +01:00
Peter Steinberger
4bef423d83 perf(test): reduce gateway reload waits and trim duplicate invoke coverage 2026-02-13 23:50:08 +00:00
solstead
ab71fdf821 Plugin API: compaction/reset hooks, bootstrap file globs, memory plugin status (#13287)
* feat: add before_compaction and before_reset plugin hooks with session context

- Pass session messages to before_compaction hook
- Add before_reset plugin hook for /new and /reset commands
- Add sessionId to plugin hook agent context

* feat: extraBootstrapFiles config with glob pattern support

Add extraBootstrapFiles to agent defaults config, allowing glob patterns
(e.g. "projects/*/TOOLS.md") to auto-load project-level bootstrap files
into agent context every turn. Missing files silently skipped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(status): show custom memory plugins as enabled, not unavailable

The status command probes memory availability using the built-in
memory-core manager. Custom memory plugins (e.g. via plugin slot)
can't be probed this way, so they incorrectly showed "unavailable".
Now they show "enabled (plugin X)" without the misleading label.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use async fs.glob and capture pre-compaction messages

- Replace globSync (node:fs) with fs.glob (node:fs/promises) to match
  codebase conventions for async file operations
- Capture session.messages BEFORE replaceMessages(limited) so
  before_compaction hook receives the full conversation history,
  not the already-truncated list

* fix: resolve lint errors from CI (oxlint strict mode)

- Add void to fire-and-forget IIFE (no-floating-promises)
- Use String() for unknown catch params in template literals
- Add curly braces to single-statement if (curly rule)

* fix: resolve remaining CI lint errors in workspace.ts

- Remove `| string` from WorkspaceBootstrapFileName union (made all
  typeof members redundant per no-redundant-type-constituents)
- Use type assertion for extra bootstrap file names
- Drop redundant await on fs.glob() AsyncIterable (await-thenable)

* fix: address Greptile review — path traversal guard + fs/promises import

- workspace.ts: use path.resolve() + traversal check in loadExtraBootstrapFiles()
- commands-core.ts: import fs from node:fs/promises, drop fs.promises prefix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve symlinks before workspace boundary check

Greptile correctly identified that symlinks inside the workspace could
point to files outside it, bypassing the path prefix check. Now uses
fs.realpath() to resolve symlinks before verifying the real path stays
within the workspace boundary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address Greptile review — hook reliability and type safety

1. before_compaction: add compactingCount field so plugins know both
   the full pre-compaction message count and the truncated count being
   fed to the compaction LLM. Clarify semantics in comment.

2. loadExtraBootstrapFiles: use path.basename() for the name field
   so "projects/quaid/TOOLS.md" maps to the known "TOOLS.md" type
   instead of an invalid WorkspaceBootstrapFileName cast.

3. before_reset: fire the hook even when no session file exists.
   Previously, short sessions without a persisted file would silently
   skip the hook. Now fires with empty messages array so plugins
   always know a reset occurred.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: validate bootstrap filenames and add compaction hook timeout

- Only load extra bootstrap files whose basename matches a recognized
  workspace filename (AGENTS.md, TOOLS.md, etc.), preventing arbitrary
  files from being injected into agent context.
- Wrap before_compaction hook in a 30-second Promise.race timeout so
  misbehaving plugins cannot stall the compaction pipeline.
- Clarify hook comments: before_compaction is intentionally awaited
  (plugins need messages before they're discarded) but bounded.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: make before_compaction non-blocking, add sessionFile to after_compaction

- before_compaction is now true fire-and-forget — no await, no timeout.
  Plugins that need full conversation data should persist it themselves
  and return quickly, or use after_compaction for async processing.
- after_compaction now includes sessionFile path so plugins can read
  the full JSONL transcript asynchronously. All pre-compaction messages
  are preserved on disk, eliminating the need to block compaction.
- Removes Promise.race timeout pattern that didn't actually cancel
  slow hooks (just raced past them while they continued running).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add sessionFile to before_compaction for parallel processing

The session JSONL already has all messages on disk before compaction
starts. By providing sessionFile in before_compaction, plugins can
read and extract data in parallel with the compaction LLM call rather
than waiting for after_compaction. This is the optimal path for memory
plugins that need the full conversation history.

sessionFile is also kept on after_compaction for plugins that only
need to act after compaction completes (analytics, cleanup, etc.).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: move bootstrap extras into bundled hook

---------

Co-authored-by: Solomon Steadman <solstead@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Clawdbot <clawdbot@alfie.local>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-14 00:45:45 +01:00
Jessy LANGE
3bda3df729 fix(browser): hot-reload profiles added after gateway start (#4841) (#8816)
* fix(browser): hot-reload profiles added after gateway start (#4841)

* style: format files with oxfmt

* Fix hot-reload stale config fields bug in forProfile

* Fix test order-dependency in hot-reload profiles test

* Fix mock reset order to prevent stale cfgProfiles

* Fix config cache blocking hot-reload by clearing cache before loadConfig

* test: improve hot-reload test to properly exercise config cache

- Add simulated cache behavior in mock
- Prime cache before mutating config
- Verify stale value without clearConfigCache
- Verify fresh value after hot-reload

Addresses review comment about test not exercising cache

* test: add hot-reload tests for browser profiles in server context.

* fix(browser): optimize profile hot-reload to avoid global cache clear

* fix(browser): remove unused loadConfig import

* fix(test): execute resetModules before test setup

* feat: implement browser server context with profile hot-reloading and tab management.

* fix(browser): harden profile hot-reload and shutdown cleanup

* test(browser): use toSorted in known-profile names test

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-14 00:44:04 +01:00
Peter Steinberger
d5e25e0ad8 refactor: centralize dispatcher lifecycle ownership 2026-02-14 00:41:37 +01:00
Peter Steinberger
5caf829d28 perf(test): trim duplicate gateway and auto-reply test overhead 2026-02-13 23:40:38 +00:00
Peter Steinberger
ad57e561c6 refactor: unify gateway restart deferral and dispatcher cleanup 2026-02-14 00:38:18 +01:00
Peter Steinberger
51296e770c feat(slack): land thread-ownership from @DarlingtonDeveloper (#15775)
Land PR #15775 by @DarlingtonDeveloper:
- add thread-ownership plugin and Slack message_sending hook wiring
- include regression tests and changelog update

Co-authored-by: Mike <108890394+DarlingtonDeveloper@users.noreply.github.com>
2026-02-13 23:37:05 +00:00
Taylor Asplund
874ff7089c fix: ensure CLI exits after command completion (#12906)
* fix: ensure CLI exits after command completion

The CLI process would hang indefinitely after commands like
`openclaw gateway restart` completed successfully.  Two root causes:

1. `runCli()` returned without calling `process.exit()` after
   `program.parseAsync()` resolved, and Commander.js does not
   force-exit the process.

2. `daemon-cli/register.ts` eagerly called `createDefaultDeps()`
   which imported all messaging-provider modules, creating persistent
   event-loop handles that prevented natural Node exit.

Changes:
- Add `flushAndExit()` helper that drains stdout/stderr before calling
  `process.exit()`, preventing truncated piped output in CI/scripts.
- Call `flushAndExit()` after both `tryRouteCli()` and
  `program.parseAsync()` resolve.
- Remove unnecessary `void createDefaultDeps()` from daemon-cli
  registration — daemon lifecycle commands never use messaging deps.
- Make `serveAcpGateway()` return a promise that resolves on
  intentional shutdown (SIGINT/SIGTERM), so `openclaw acp` blocks
  `parseAsync` for the bridge lifetime and exits cleanly on signal.
- Handle the returned promise in the standalone main-module entry
  point to avoid unhandled rejections.

Fixes #12904

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: refactor CLI lifecycle and lazy outbound deps (#12906) (thanks @DrCrinkle)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-14 00:34:33 +01:00
Peter Steinberger
2378d770d1 perf(test): speed gateway suite resets with unique config roots 2026-02-13 23:33:08 +00:00
Peter Steinberger
e794ef0478 perf(test): reduce hot-suite setup and duplicate test work 2026-02-13 23:30:41 +00:00
Bridgerz
ab4a08a82a fix: defer gateway restart until all replies are sent (#12970)
* fix: defer gateway restart until all replies are sent

Fixes a race condition where gateway config changes (e.g., enabling
plugins via iMessage) trigger an immediate SIGUSR1 restart, killing the
iMessage RPC connection before replies are delivered.

Both restart paths (config watcher and RPC-triggered) now defer until
all queued operations, pending replies, and embedded agent runs complete
(polling every 500ms, 30s timeout). A shared emitGatewayRestart() guard
prevents double SIGUSR1 when both paths fire simultaneously.

Key changes:
- Dispatcher registry tracks active reply dispatchers globally
- markComplete() called in finally block for guaranteed cleanup
- Pre-restart deferral hook registered at gateway startup
- Centralized extractDeliveryInfo() for session key parsing
- Post-restart sentinel messages delivered directly (not via agent)
- config-patch distinguished from config-apply in sentinel kind

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: single-source gateway restart authorization

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-14 00:29:29 +01:00
Peter Steinberger
dc507f3dec perf(test): reduce memory and port probe overhead 2026-02-13 23:22:30 +00:00
Peter Steinberger
1aa746f042 perf(test): lower synthetic payload in embedding batch split case 2026-02-13 23:16:42 +00:00
Peter Steinberger
faeac955b5 perf(test): trim retry-loop work in embedding batch tests 2026-02-13 23:16:42 +00:00
Peter Steinberger
e324cb5b94 perf(test): reduce fixture churn in hot suites 2026-02-13 23:16:41 +00:00
Peter Steinberger
dac8f5ba3f perf(test): trim fixture and import overhead in hot suites 2026-02-13 23:16:41 +00:00
Peter Steinberger
b8703546e9 docs(changelog): note cron delivered-relay regression coverage (#15737) (thanks @brandonwise) 2026-02-14 00:08:56 +01:00
Brandon Wise
b0728e605d fix(cron): skip relay only for explicit delivery config, not legacy payload
Fixes #15692

The previous fix was too broad — it removed the relay for ALL isolated jobs.
This broke backwards compatibility for jobs without explicit delivery config.

The correct behavior is:
- If job.delivery exists → isolated runner handles it via runSubagentAnnounceFlow
- If only legacy payload.deliver fields → relay to main if requested (original behavior)

This addresses Greptile's review feedback about runIsolatedAgentJob being an
injected dependency that might not call runSubagentAnnounceFlow.

Uses resolveCronDeliveryPlan().source to distinguish between explicit delivery
config and legacy payload-only jobs.
2026-02-14 00:08:56 +01:00
Peter Steinberger
45a2cd55cc fix: harden isolated cron announce delivery fallback (#15739) (thanks @widingmarcus-cyber) 2026-02-13 23:49:10 +01:00
Marcus Widing
ea95e88dd6 fix(cron): prevent duplicate delivery for isolated jobs with announce mode
When an isolated cron job delivers its output via deliverOutboundPayloads
or the subagent announce flow, the finish handler in executeJobCore
unconditionally posts a summary to the main agent session and wakes it
via requestHeartbeatNow. The main agent then generates a second response
that is also delivered to the target channel, resulting in duplicate
messages with different content.

Add a `delivered` flag to RunCronAgentTurnResult that is set to true
when the isolated run successfully delivers its output. In executeJobCore,
skip the enqueueSystemEvent + requestHeartbeatNow call when the flag is
set, preventing the main agent from waking up and double-posting.

Fixes #15692
2026-02-13 23:49:10 +01:00
nabbilkhan
207e2c5aff fix: add outbound delivery crash recovery (#15636) (thanks @nabbilkhan) (#15636)
Co-authored-by: Shadow <hi@shadowing.dev>
2026-02-13 15:54:07 -06:00
Peter Steinberger
caebe70e9a perf(test): cut setup/import overhead in hot suites 2026-02-13 21:23:50 +00:00
Peter Steinberger
93dd51bce0 perf(matrix): lazy-load music-metadata parsing 2026-02-13 21:23:50 +00:00
Joseph Krug
4e9f933e88 fix: reset stale execution state after SIGUSR1 in-process restart (#15195)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 676f9ec45135be0d3471bb0444bc2ac7ce7d5224
Co-authored-by: joeykrug <5925937+joeykrug@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-02-13 15:30:09 -05:00
Peter Steinberger
2086cdfb9b perf(test): reduce hot-suite import and setup overhead 2026-02-13 20:26:39 +00:00
Peter Steinberger
1655df7ac0 fix(config): log config overwrite audits 2026-02-13 20:12:41 +00:00
Gustavo Madeira Santana
42eaee8b7e chore: fix root_dir resolution/stale scripts during PR review 2026-02-13 15:09:39 -05:00
Peter Steinberger
6442512954 perf: reduce hotspot test startup and timeout costs 2026-02-13 20:03:01 +00:00
Marcus Castro
31537c669a fix: archive old transcript files on /new and /reset (#14949)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 4724df7dea247970b909ef8d293ba4a612b7b1b4
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-02-13 14:55:16 -05:00
Peter Steinberger
c8b198ab51 perf: speed up gateway missing-tick e2e watchdog 2026-02-13 19:52:45 +00:00
Peter Steinberger
e746a67cc3 perf: speed up telegram media e2e flush timing 2026-02-13 19:52:45 +00:00
Gustavo Madeira Santana
bbca3b191a changelog: add missing attribution 2026-02-13 14:47:51 -05:00
Shadow
8c1e8bb2ff fix: note clawdock zsh compatibility (#15501) (thanks @nkelner) 2026-02-13 13:47:16 -06:00
Nathaniel Kelner
66f6d71ffa Update clawdock-helpers.sh compatibility with Zsh
Unlike Bash, Zsh has several "special" readonly variables (status, pipestatus, etc.) that the shell manages automatically. Shadowing them with local declarations triggers an error.
2026-02-13 13:47:16 -06:00
大猫子
f24d70ec8e fix(providers): switch MiniMax API-key provider to anthropic-messages (#15297)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 0e7f84a2a103135221b73e2c3f300790206fc6f4
Co-authored-by: lailoo <20536249+lailoo@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-02-13 14:44:36 -05:00
Marcus Castro
4225206f0c fix(gateway): normalize session key casing to prevent ghost sessions (#12846)
* 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>
2026-02-13 20:42:24 +01:00
Shadow
f6232bc2b4 CI: close invalid items without response 2026-02-13 13:41:13 -06:00
Peter Steinberger
2b685b08c2 fix: harden matrix multi-account routing (#7286) (thanks @emonty) 2026-02-13 20:39:58 +01:00