Commit Graph

5086 Commits

Author SHA1 Message Date
Akari
455bc1ebba fix: use last API call's cache tokens for context-size display (#13698) (#13805)
The UsageAccumulator sums cacheRead/cacheWrite across all API calls
within a single turn. With Anthropic prompt caching, each call reports
cacheRead ≈ current_context_size, so after N tool-call round-trips the
accumulated total becomes N × actual_context, which gets clamped to
contextWindow (200k) by deriveSessionTotalTokens().

Fix: track the most recent API call's cache fields separately and use
them in toNormalizedUsage() for context-size reporting. This makes
/status Context display accurate while preserving accumulated output
token counts.

Fixes #13698
Fixes #13782

Co-authored-by: akari-musubi <259925157+akari-musubi@users.noreply.github.com>
2026-02-12 08:01:36 -06:00
Kyle Chen
4c350bc4c8 Fix: Prevent file descriptor leaks in child process cleanup (#13565)
* fix: prevent FD leaks in child process cleanup

- Destroy stdio streams (stdin/stdout/stderr) after process exit
- Remove event listeners to prevent memory leaks
- Clean up child process reference in moveToFinished()
- Also fixes model override handling in agent.ts

Fixes EBADF errors caused by accumulating file descriptors
from sub-agent spawns.

* Fix: allow stdin destroy in process registry cleanup

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-12 08:01:33 -06:00
jg-noncelogic
6f74786384 fix(antigravity): opus 4.6 forward-compat model + thinking signature sanitization bypass (#14218)
Two fixes for Google Antigravity (Cloud Code Assist) reliability:

1. Forward-compat model fallback: pi-ai's model registry doesn't include
   claude-opus-4-6-thinking. Add resolveAntigravityOpus46ForwardCompatModel()
   that clones the opus-4-5 template so the correct api ("google-gemini-cli")
   and baseUrl are preserved. Fixes #13765.

2. Fix thinking.signature rejection: The API returns Claude thinking blocks
   without signatures, then rejects them on replay. The existing sanitizer
   strips unsigned blocks, but the orphaned-user-message path in attempt.ts
   bypassed it by reading directly from disk. Now applies
   sanitizeAntigravityThinkingBlocks at that code path.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 08:01:28 -06:00
Taras Lukavyi
d85150357f feat: support .agents/skills/ directory for cross-agent skill discovery (#9966)
Adds loading from two .agents/skills/ locations:
- ~/.agents/skills/ (personal/user-level, source "agents-skills-personal")
- {workspace}/.agents/skills/ (project-level, source "agents-skills-project")

Precedence: extra < bundled < managed < personal .agents/skills < project .agents/skills < workspace.

Closes #8822
2026-02-12 07:56:19 -06:00
taw0002
dcb921944a fix: prevent double compaction caused by cache-ttl entry bypassing guard (#13514)
Move appendCacheTtlTimestamp() to after prompt + compaction retry
completes instead of before. The previous placement inserted a custom
entry (openclaw.cache-ttl) between compaction and the next prompt,
which broke pi-coding-agent's prepareCompaction() guard — the guard
only checks if the last entry is type 'compaction', and the cache-ttl
custom entry made it type 'custom', allowing an immediate second
compaction at very low token counts (e.g. 5,545 tokens) that nuked
all preserved context.

Fixes #9282
Relates to #12170
2026-02-12 07:55:32 -06:00
0xRain
21d7203fa9 fix(daemon): suppress EPIPE error in restartLaunchAgent stdout write (#14343)
After a successful launchctl kickstart, the stdout.write() for the
status message may fail with EPIPE if the receiving end has already
closed. Catch and ignore EPIPE specifically; re-throw other errors.

Closes #14234

Co-authored-by: Echo Ito <echoito@MacBook-Air.local>
2026-02-12 07:55:29 -06:00
brandonwise
7f6f7f598c fix: ignore meta field changes in config file watcher (#13460)
Prevents infinite restart loop when gateway updates meta.lastTouchedAt
and meta.lastTouchedVersion on startup.

Fixes #13458
2026-02-12 07:55:26 -06:00
Coy Geek
647d929c9d fix: Unauthenticated Nostr profile API allows remote config tampering (#13719)
* fix(an-07): apply security fix

Generated by staged fix workflow.

* fix(an-07): apply security fix

Generated by staged fix workflow.

* fix(an-07): satisfy lint in plugin auth regression test

Replace unsafe unknown-to-string coercion in the gateway plugin auth test helper with explicit string/null/JSON handling so pnpm check passes.
2026-02-12 07:55:22 -06:00
0xRain
acb9cbb898 fix(gateway): drain active turns before restart to prevent message loss (#13931)
* fix(gateway): drain active turns before restart to prevent message loss

On SIGUSR1 restart, the gateway now waits up to 30s for in-flight agent
turns to complete before tearing down the server. This prevents buffered
messages from being dropped when config.patch or update triggers a restart
while agents are mid-turn.

Changes:
- command-queue.ts: add getActiveTaskCount() and waitForActiveTasks()
  helpers to track and wait on active lane tasks
- run-loop.ts: on restart signal, drain active tasks before server.close()
  with a 30s timeout; extend force-exit timer accordingly
- command-queue.test.ts: update imports for new exports

Fixes #13883

* fix(queue): snapshot active tasks for restart drain

---------

Co-authored-by: Elonito <0xRaini@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-12 07:55:19 -06:00
niceysam
f7e05d0136 fix: exclude maxTokens from config redaction + honor deleteAfterRun on skipped cron jobs (#13342)
* fix: exclude maxTokens and token-count fields from config redaction

The /token/i regex in SENSITIVE_KEY_PATTERNS falsely matched fields like
maxTokens, maxOutputTokens, maxCompletionTokens etc. These are numeric
config fields for token counts, not sensitive credentials.

Added a whitelist (SENSITIVE_KEY_WHITELIST) that explicitly excludes
known token-count field names from redaction. This prevents config
corruption when maxTokens gets replaced with __OPENCLAW_REDACTED__
during config round-trips.

Fixes #13236

* fix: honor deleteAfterRun for one-shot 'at' jobs with 'skipped' status

Previously, deleteAfterRun only triggered when result.status was 'ok'.
For one-shot 'at' jobs, a 'skipped' status (e.g. empty heartbeat file)
would leave the job in state but disabled, never getting cleaned up.

Now deleteAfterRun also triggers on 'skipped' status for 'at' jobs,
since a skipped one-shot job has no meaningful retry path.

Fixes #13249

* Cron: format timer.ts

---------

Co-authored-by: nice03 <niceyslee@gmail.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-12 07:55:05 -06:00
asklee-klawd
f8c91b3c5f fix: prevent undefined token in gateway auth config (#13809)
- Guard against undefined/empty token in buildGatewayAuthConfig
- Automatically generate random token when token param is undefined, empty, or whitespace
- Prevents JSON.stringify from writing literal string "undefined" to config
- Add tests for undefined, empty, and whitespace token cases

Fixes #13756

Co-authored-by: Klawd Asklee <klawdebot@gmail.com>
2026-02-12 07:45:38 -06:00
Keshav Rao
2ef4ac08cf fix(gateway): handle async EPIPE on stdout/stderr during shutdown (#13414)
* fix(gateway): handle async EPIPE on stdout/stderr during shutdown

The console capture forward() wrapper catches synchronous EPIPE errors,
but when the receiving pipe closes during shutdown Node emits the error
asynchronously on the stream. Without a listener this becomes an
uncaught exception that crashes the gateway, causing macOS launchd to
permanently unload the service.

Add error listeners on process.stdout and process.stderr inside
enableConsoleCapture() that silently swallow EPIPE/EIO (matching the
existing isEpipeError helper) and re-throw anything else.

Closes #13367

* guard stream error listeners against repeated enableConsoleCapture() calls

Use a separate streamErrorHandlersInstalled flag in loggingState so that
test resets of consolePatched don't cause listener accumulation on
process.stdout/stderr.
2026-02-12 07:45:36 -06:00
0xRain
94bc62ad46 fix(media): strip MEDIA: lines with local paths instead of leaking as text (#14399)
When internal tools (e.g. TTS) emit MEDIA:/tmp/... with absolute paths,
isValidMedia() correctly rejects them for security. However, the rejected
MEDIA: line was kept as visible text in the output, leaking the path to
the user.

Now strip MEDIA: lines that look like local paths even when the path
is invalid, so they never appear as user-visible text.

Closes #14365

Co-authored-by: Echo Ito <echoito@MacBook-Air.local>
2026-02-12 07:45:22 -06:00
Cathryn Lavery
94d6858160 fix(gateway): auto-generate token during gateway install to prevent launchd restart loop (#13813)
When the gateway is installed as a macOS launch agent and no token is
configured, the service enters an infinite restart loop because launchd
does not inherit shell environment variables. Auto-generate a token
during `gateway install` when auth mode is `token` and no token exists,
matching the existing pattern in doctor.ts and configure.gateway.ts.

The token is persisted to the config file and embedded in the plist
EnvironmentVariables for belt-and-suspenders reliability.

Relates-to: #5103, #2433, #1690, #7749
2026-02-12 07:45:09 -06:00
大猫子
8dd60fc7d9 feat(telegram): render blockquotes as native <blockquote> tags (#14608) (#14626)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 4a967c51f560fea33694a980bda0d76be6385c71
Co-authored-by: lailoo <20536249+lailoo@users.noreply.github.com>
Co-authored-by: sebslight <19554889+sebslight@users.noreply.github.com>
Reviewed-by: @sebslight
2026-02-12 08:11:57 -05:00
Tomsun28
540996f10f feat(provider): Z.AI endpoints + model catalog (#13456) (thanks @tomsun28) (#13456)
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-12 07:01:48 -06:00
vignesh07
b094491cf5 fix(config): restore schema.ts schema helper types after hints refactor 2026-02-12 01:19:46 -08:00
vignesh07
fa427f63b8 refactor(config): restore schema.ts to use schema.hints 2026-02-12 01:19:46 -08:00
hyf0-agent
5c32989f53 perf: use JSON.parse instead of JSON5.parse for sessions.json (~35x faster) (#14530)
Co-authored-by: hyf0-agent <hyf0-agent@users.noreply.github.com>
2026-02-12 17:10:21 +09:00
0xRain
4b86c9e555 fix(telegram): surface REACTION_INVALID as non-fatal warning (#14340)
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-12 00:28:47 -06:00
J. Brandon Johnson
472808a207 fix(tests): update thread ID handling in Slack message collection tests (#14108)
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-12 00:13:15 -06:00
NM
3696b15abc fix(slack): change default replyToMode from "off" to "all" (#14364)
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-12 00:13:07 -06:00
0xRain
bbfaac88ff fix(telegram): handle no-text message in model picker editMessageText (#14397)
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-12 00:12:46 -06:00
WalterSumbon
39e3d58fe1 fix: prevent cron jobs from skipping execution when nextRunAtMs advances (#14068)
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-11 23:33:22 -06:00
大猫子
a88ea42ec7 fix(cron): prevent one-shot at jobs from re-firing on restart after skip/error (#13845) (#13878)
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-11 23:33:15 -06:00
0xRain
b0dfb83952 fix(cron): use requested agentId for isolated job auth resolution (#13983)
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-11 23:32:45 -06:00
Karim Naguib
7a0591ef87 fix(whatsapp): allow media-only sends and normalize leading blank payloads (#14408)
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-11 23:21:21 -06:00
Marcus Castro
186dc0363f fix: default MIME type for WhatsApp voice messages when Baileys omits it (#14444) 2026-02-11 23:09:09 -06:00
Ajay Rajnikanth
e24d023080 fix(whatsapp): convert Markdown bold/strikethrough to WhatsApp formatting (#14285)
* fix(whatsapp): convert Markdown bold/strikethrough to WhatsApp formatting

* refactor: Move `escapeRegExp` utility function to `utils.js`.

---------

Co-authored-by: Luna AI <luna@coredirection.ai>
2026-02-11 23:09:02 -06:00
石川 諒
04e3a66f90 fix(cron): pass agentId to runHeartbeatOnce for main-session jobs (#14140)
* fix(cron): pass agentId to runHeartbeatOnce for main-session jobs

Main-session cron jobs with agentId always ran the heartbeat under
the default agent, ignoring the job's agent binding. enqueueSystemEvent
correctly routed the system event to the bound agent's session, but
runHeartbeatOnce was called without agentId, so the heartbeat ran under
the default agent and never picked up the event.

Thread agentId from job.agentId through the CronServiceDeps type,
timer execution, and the gateway wrapper so heartbeat-runner uses the
correct agent.

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

* cron: add heartbeat agentId propagation regression test (#14140) (thanks @ishikawa-pro)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-02-11 22:22:29 -06:00
MarvinDontPanic
04f695e562 fix(cron): isolate schedule errors to prevent one bad job from breaking all jobs (#14385)
Previously, if one cron job had a malformed schedule expression (e.g. invalid cron syntax),
the error would propagate up and break the entire scheduler loop. This meant one misconfigured
job could prevent ALL cron jobs from running.

Changes:
- Wrap per-job schedule computation in try/catch in recomputeNextRuns()
- Track consecutive schedule errors via new scheduleErrorCount field
- Log warnings for schedule errors with job ID and name
- Auto-disable jobs after 3 consecutive schedule errors (with error-level log)
- Clear error count when schedule computation succeeds
- Continue processing other jobs even when one fails

This ensures the scheduler is resilient to individual job misconfigurations while still
providing visibility into problems through logging.

Co-authored-by: Marvin <numegilagent@gmail.com>
2026-02-11 22:17:07 -06:00
Tom Ron
ace5e33cee fix(cron): re-arm timer when onTimer fires during active job execution (#14233)
* fix(cron): re-arm timer when onTimer fires during active job execution

When a cron job takes longer than MAX_TIMER_DELAY_MS (60s), the clamped
timer fires while state.running is still true.  The early return in
onTimer() previously exited without re-arming the timer, leaving no
setTimeout scheduled.  This silently kills the cron scheduler until the
next gateway restart.

The fix calls armTimer(state) before the early return so the scheduler
continues ticking even when a job is in progress.

This is the likely root cause of recurring cron jobs silently skipping,
as reported in #12025.  One-shot (kind: 'at') jobs were unaffected
because they typically complete within a single timer cycle.

Includes a regression test that simulates a slow job exceeding the
timer clamp period and verifies the next occurrence still fires.

* fix: update tests for timer re-arm behavior

- Update existing regression test to expect timer re-arm with non-zero
  delay instead of no timer at all
- Simplify new test to directly verify state.timer is set after onTimer
  returns early due to running guard

* fix: use fixed 60s delay for re-arm to prevent zero-delay hot-loop

When the running guard re-arms the timer, use MAX_TIMER_DELAY_MS
directly instead of calling armTimer() which can compute a zero delay
for past-due jobs.  This prevents a tight spin while still keeping the
scheduler alive.

* style: add curly braces to satisfy eslint(curly) rule
2026-02-11 22:13:27 -06:00
Xinhua Gu
dd6047d998 fix(cron): prevent duplicate fires when multiple jobs trigger simultaneously (#14256)
The `computeNextRunAtMs` function used `nowSecondMs - 1` as the
reference time for croner's `nextRun()`, which caused it to return the
current second as a valid next-run time. When a job fired at e.g.
11:00:00.500, computing the next run still yielded 11:00:00.000 (same
second, already elapsed), causing the scheduler to immediately re-fire
the job in a tight loop (15-21x observed in the wild).

Fix: use `nowSecondMs` directly (no `-1` lookback) and change the
return guard from `>=` to `>` so next-run is always strictly after
the current second.

Fixes #14164
2026-02-11 22:04:17 -06:00
Rodrigo Uroz
b912d3992d (fix): handle Cloudflare 521 and transient 5xx errors gracefully (#13500)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: a8347e95c55c6244bbf2e9066c8bf77bf62de6c9
Co-authored-by: rodrigouroz <384037+rodrigouroz@users.noreply.github.com>
Co-authored-by: Takhoffman <781889+Takhoffman@users.noreply.github.com>
Reviewed-by: @Takhoffman
2026-02-11 21:42:33 -06:00
Jake
631102e714 fix(agents): scope process/exec tools to sessionKey for isolation (#4887)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 5d30672e756cc10a6cda90f5bc55cf4812b7d1d6
Co-authored-by: mcinteerj <3613653+mcinteerj@users.noreply.github.com>
Co-authored-by: Takhoffman <781889+Takhoffman@users.noreply.github.com>
Reviewed-by: @Takhoffman
2026-02-11 19:55:12 -06:00
Vignesh Natarajan
36e27ad561 Memory: make qmd search-mode flags compatible 2026-02-11 17:51:08 -08:00
Vignesh Natarajan
6d9d4d04ed Memory/QMD: add configurable search mode 2026-02-11 17:51:08 -08:00
0xRain
1d2c5783fd fix(agents): enable tool call ID sanitization for Anthropic provider (#13830)
Co-authored-by: 0xRaini <0xRaini@users.noreply.github.com>
2026-02-12 08:42:24 +09:00
0xRain
43818e1583 fix(agents): re-run tool_use pairing repair after history truncation (#13926)
Co-authored-by: 0xRaini <0xRaini@users.noreply.github.com>
2026-02-12 08:42:05 +09:00
0xRain
729181bd06 fix(agents): exclude rate limit errors from context overflow classification (#13747)
Co-authored-by: 0xRaini <rain@0xRaini.dev>
2026-02-12 08:40:09 +09:00
Vignesh Natarajan
2f1f82674a Memory/QMD: harden no-results parsing 2026-02-11 15:39:28 -08:00
Vignesh Natarajan
3d343932cf Memory/QMD: treat plain-text no-results as empty 2026-02-11 15:39:28 -08:00
buddyh
4baa43384a fix(media): guard local media reads + accept all path types in MEDIA directive 2026-02-11 15:01:18 -08:00
ENCHIGO
029b77c85b onboard: support custom provider in non-interactive flow (#14223)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 5b98d6514e73f7ee934a350f3b38619c70f49aed
Co-authored-by: ENCHIGO <38551565+ENCHIGO@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-02-11 14:48:45 -05:00
Claude Code
a67752e6be fix(discord): use partial mock for @buape/carbon in slash test
Replace the full manual mock with importOriginal spread so new SDK
exports are available automatically. Only ChannelType, MessageType,
and Client are overridden — the rest come from the real module.

Prevents CI breakage when @buape/carbon adds exports (e.g. the
recent StringSelectMenu failure that blocked unrelated PRs).

Closes #13244
2026-02-11 13:10:37 -06:00
Kyle Tse
4200782a5d fix(heartbeat): honor heartbeat.model config for heartbeat turns (#14103)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: f46080b0adb882c4d18af7ac0e80055505ff640c
Co-authored-by: shtse8 <8020099+shtse8@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-02-11 14:00:40 -05:00
0xRain
93411b74a0 fix(cli): exit with non-zero code when configure/agents-add wizards are cancelled (#14156)
* fix(cli): exit with non-zero code when configure/agents-add wizards are cancelled

Follow-up to the onboard cancel fix. The configure wizard and
agents add wizard also caught WizardCancelledError and exited with
code 0, which signals success to callers. Change to exit(1) for
consistency — user cancellation is not a successful completion.

This ensures scripts that chain these commands with set -e will
correctly stop when the user cancels.

* fix(cli): make wizard cancellations exit non-zero (#14156) (thanks @0xRaini)

---------

Co-authored-by: Rain <rain@Rains-MBA-M4.local>
Co-authored-by: Sebastian <19554889+sebslight@users.noreply.github.com>
2026-02-11 13:07:30 -05:00
Dario Zhang
e85bbe01f2 fix: report subagent timeout as 'timed out' instead of 'completed successfully' (#13996)
* fix: report subagent timeout as 'timed out' instead of 'completed successfully'

* fix: propagate subagent timeout status across agent.wait (#13996) (thanks @dario-github)

---------

Co-authored-by: Sebastian <19554889+sebslight@users.noreply.github.com>
2026-02-11 12:55:30 -05:00
0xRain
6d723c9f8a fix(agents): honor heartbeat.model override instead of session model (#14181)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: f19b789057e03d424ee20baf3c678475ad94f72f
Co-authored-by: 0xRaini <190923101+0xRaini@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-02-11 12:46:51 -05:00
Shadow
e95f41b5df Discord: honor explicit thread type 2026-02-11 11:23:19 -06:00