Commit Graph

1457 Commits (2937c4861ffc8b2f4734fd653c3951614ce36886)

Author SHA1 Message Date
Peter Steinberger 1ae5e9a26b feat: add docs search command 2026-01-07 02:03:06 +01:00
Erik cd4e2023ab fix(agent): capture compaction retry AbortError for model fallback
Wrap waitForCompactionRetry() in try/catch to capture AbortError
that was escaping and bypassing the model fallback mechanism.

When a timeout fires, session.abort() causes both session.prompt()
and waitForCompactionRetry() to throw AbortError. Previously only
the prompt error was captured, allowing the compaction error to
escape to model-fallback.ts where it was immediately re-thrown
(line 199: isAbortError check), bypassing fallback model attempts.

Fixes #313
2026-01-07 01:44:37 +01:00
Peter Steinberger 0116184b1c docs: recommend WSL2 for Windows installs 2026-01-07 01:21:36 +01:00
Peter Steinberger 62112d9978 feat: add onboarding doc links 2026-01-07 01:19:31 +01:00
Peter Steinberger 19c95d0ff7 fix(auth): serialize profile stats updates 2026-01-07 01:06:51 +01:00
Peter Steinberger 96d72ff91e fix(auth): lock auth profile updates 2026-01-07 01:00:47 +01:00
Muhammed Mukhthar CM eb5f758f6b fix(auth): improve multi-account round-robin rotation and 429 handling
This commit fixes several issues with multi-account OAuth rotation that
were causing slow responses and inefficient account cycling.

## Changes

### 1. Fix usageStats race condition (auth-profiles.ts)

The `markAuthProfileUsed`, `markAuthProfileCooldown`, `markAuthProfileGood`,
and `clearAuthProfileCooldown` functions were using a stale in-memory store
passed as a parameter. Long-running sessions would overwrite usageStats
updates from concurrent sessions when saving.

**Fix:** Re-read the store from disk before each update to get fresh
usageStats from other sessions, then merge the update.

### 2. Capture AbortError from waitForCompactionRetry (pi-embedded-runner.ts)

When a request timed out, `session.abort()` was called which throws an
`AbortError`. The code structure was:

```javascript
try {
  await session.prompt(params.prompt);
} catch (err) {
  promptError = err;  // Catches AbortError here
}
await waitForCompactionRetry();  // But THIS also throws AbortError!
```

The second `AbortError` from `waitForCompactionRetry()` escaped and
bypassed the rotation/fallback logic entirely.

**Fix:** Wrap `waitForCompactionRetry()` in its own try/catch to capture
the error as `promptError`, enabling proper timeout handling.

Root cause analysis and fix proposed by @erikpr1994 in #313.

Fixes #313

### 3. Fail fast on 429 rate limits (pi-ai patch)

The pi-ai library was retrying 429 errors up to 3 times with exponential
backoff before throwing. This meant a rate-limited account would waste
30+ seconds retrying before our rotation code could try the next account.

**Fix:** Patch google-gemini-cli.js to:
- Throw immediately on first 429 (no retries)
- Not catch and retry 429 errors in the network error handler

This allows the caller to rotate to the next account instantly on rate limit.

Note: We submitted this fix upstream (https://github.com/badlogic/pi-mono/pull/504)
but it was closed without merging. Keeping as a local patch for now.

## Testing

With 6 Antigravity accounts configured:
- Accounts rotate properly based on lastUsed (round-robin)
- 429s trigger immediate rotation to next account
- usageStats persist correctly across concurrent sessions
- Cooldown tracking works as expected

## Before/After

**Before:** Multiple 429 retries on same account, 30-90s delays
**After:** Instant rotation on 429, responses in seconds
2026-01-07 00:56:32 +01:00
VAC ff200e3993 fix(discord): handle voice messages with empty content
Discord voice messages have empty `content` with the audio in attachments.
The nullish coalescing operator (`??`) doesn't fall through on empty strings,
so voice messages were being dropped as 'empty content'.

Changed to logical OR (`||`) so empty string falls through to media placeholder.
2026-01-06 23:35:30 +00:00
Peter Steinberger 7214cf39ec fix: prefer home linuxbrew paths 2026-01-07 00:18:07 +01:00
Peter Steinberger b57d36f49c fix(sessions_spawn): hard-fail invalid model overrides 2026-01-06 23:17:35 +00:00
Azade 0429a4b63b test(sessions_spawn): add test for model parameter 2026-01-06 23:17:35 +00:00
Azade 274f408e6f feat(sessions_spawn): add model parameter for sub-agent model override 2026-01-06 23:17:35 +00:00
Peter Steinberger 02c9cf0ff4 chore: remove duplicate daemon runtime imports 2026-01-07 00:14:08 +01:00
Peter Steinberger dd0d23cd96 test(commands): add /stop native regression 2026-01-06 23:11:57 +00:00
Peter Steinberger e0efcda77f fix(commands): wire /stop across chat commands 2026-01-06 23:11:57 +00:00
Nacho Iacovino 0df7c3addf feat(telegram): add /stop command to abort running agent
Adds a /stop command that:
- Can interrupt a running agent session mid-execution
- Works in both DMs and group chats (including forum topics)
- Uses grammy's bot.command() to run before the main message handler
- Returns status: stopped, stop requested, or nothing running

Also fixes session key lookup in pi-embedded-runner to use sessionKey
instead of sessionId, ensuring /stop finds the correct active run.
2026-01-06 23:11:57 +00:00
Peter Steinberger 5bc3f13b46 feat: colorize models auth key labels 2026-01-07 00:10:01 +01:00
Peter Steinberger b357746e1c feat: add richer color to models output 2026-01-07 00:07:50 +01:00
Peter Steinberger 79f813e18e style: format lint offenders 2026-01-07 00:04:44 +01:00
Peter Steinberger 0ad74ee941 test: mock select prompt in doctor tests 2026-01-07 00:01:50 +01:00
Peter Steinberger 55278c1c71 feat: add daemon runtime prompts 2026-01-06 23:51:00 +01:00
Peter Steinberger c920ee1166 Merge branch 'pr-335-merge' 2026-01-06 23:45:35 +01:00
Peter Steinberger 5939363eed fix: include telegram group sender in envelope headers 2026-01-06 22:34:02 +00:00
Peter Steinberger 8d50d08936 style: format daemon runtime changes 2026-01-06 23:29:38 +01:00
Peter Steinberger 8911a79d7f docs: rewrite cron jobs guide and heartbeat notes 2026-01-06 22:28:42 +00:00
Peter Steinberger 707f7918bc feat: add gateway daemon runtime selector 2026-01-06 23:27:58 +01:00
Peter Steinberger 18c43fe462 fix: bootstrap linuxbrew for skills 2026-01-06 23:27:38 +01:00
Peter Steinberger 39d2ba78b7 fix(cli): harden pairing provider parse 2026-01-06 22:17:18 +00:00
Peter Steinberger 0931a65ab2
fix: auto-recover from Gemini session corruption
Auto-merge after checks.
2026-01-06 22:12:05 +00:00
Peter Steinberger fec7f37271 merge upstream/main 2026-01-06 23:09:01 +01:00
Peter Steinberger 86b56b2308 fix: harden gemini session reset 2026-01-06 23:06:01 +01:00
Peter Steinberger 2771001720 fix(state): auto-migrate legacy agent dir 2026-01-06 22:04:23 +00:00
Peter Steinberger 7aa7fa79d0 feat: update heartbeat defaults 2026-01-06 21:54:42 +00:00
Peter Steinberger dba09058f5 fix(agents): default agent dir to multi-agent path 2026-01-06 21:54:42 +00:00
Peter Steinberger 96164b5955 fix: improve socket error handling 2026-01-06 22:43:29 +01:00
Emanuel Stadler fb17a32283 feat: enhance error handling for socket connection errors
- Added `isError` property to `EmbeddedPiRunResult` and reply items to indicate error states.
- Updated error handling in `runReplyAgent` to provide more informative messages for specific socket connection errors.
2026-01-06 22:19:37 +01:00
James Groat 9b6e2478f5 fix(browser): add profile param to tabs routes and browser-tool
- tabs.ts now uses getProfileContext like other routes
- browser-tool threads profile param through all actions
- add tests for profile query param on /tabs endpoints
- update docs with browser tool profile parameter
2026-01-06 21:54:46 +01:00
James Groat 40758b16a9 fix(browser-cli): rename --profile to --browser-profile to avoid conflict with global --profile flag 2026-01-06 21:54:46 +01:00
minghinmatthewlam 2dd6b3aeb2
fix: write auth profiles to multi-agent path during onboarding
- Onboarding now writes auth profiles under ~/.clawdbot/agents/main/agent so the gateway sees credentials on first start.
- Hardened onboarding test to ignore legacy env vars.

Thanks @minghinmatthewlam!
2026-01-06 20:53:18 +00:00
Peter Steinberger 84c8209158 fix(slack): clear assistant thread status after replies 2026-01-06 21:41:30 +01:00
Shadow 8ebc789d25 Slack: send assistant thread status while typing 2026-01-06 21:34:52 +01:00
Shadow 9b22e1f6e9
feat(commands): unify chat commands (#275)
* Chat commands: registry, access groups, Carbon

* Chat commands: clear native commands on disable

* fix(commands): align command surface typing

* docs(changelog): note commands registry (PR #275)

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-01-06 20:17:56 +00:00
Peter Steinberger 1bf44bf30c feat(models): show auth overview 2026-01-06 20:07:04 +00:00
Peter Steinberger 118c1e1042 fix: keep oauth profile stable 2026-01-06 19:43:28 +00:00
Peter Steinberger 67bda21811 fix: preserve markdown fences when chunking 2026-01-06 20:23:41 +01:00
Peter Steinberger 31dbc62bdd fix(telegram): prevent stuck typing after tool runs 2026-01-06 18:56:43 +00:00
Peter Steinberger 369af5fc58 style(agents): format usage helper 2026-01-06 19:54:50 +01:00
Peter Steinberger d07e78855c fix(workspace): align clawd + bootstrap 2026-01-06 19:54:50 +01:00
Abhi bdf597eb95
fix(telegram): stop typing after tool results (#322)
Thanks @AbhisekBasu1.
2026-01-06 18:54:08 +00:00
Peter Steinberger 2f24ea492b fix: restore Anthropic token accounting 2026-01-06 18:52:01 +00:00
Peter Steinberger 9fb37cbf93 style: format whatsapp inbound allowlist 2026-01-06 18:33:37 +00:00
Peter Steinberger dbfa316d19 feat: multi-agent routing + multi-account providers 2026-01-06 18:33:37 +00:00
Peter Steinberger c47aff5244 fix(onboard): clarify DM policy keys 2026-01-06 18:09:21 +01:00
Peter Steinberger 4933905366 fix(onboard): configure DM policies 2026-01-06 18:09:21 +01:00
Onur 6cf3570c5b
feat(agent): add skipBootstrap config to skip bootstrap file creation (#292) 2026-01-06 11:02:51 -06:00
Peter Steinberger b081f45b17 fix(onboard): explain DM pairing defaults 2026-01-06 17:58:06 +01:00
Muhammed Mukhthar CM 4bb53e19f9
fix(build): import tool-display.json instead of fs.readFileSync (#312) 2026-01-06 10:55:02 -06:00
Peter Steinberger 967cef80bc fix(security): lock down inbound DMs by default 2026-01-06 17:51:56 +01:00
Peter Steinberger 11b6fddcbf
Merge pull request #283 from Oncomatic/jarvis/telegram-media-error-notify
fix(telegram): notify user when media exceeds size limit
2026-01-06 15:18:52 +00:00
Peter Steinberger 3ff17b70ea chore: changelog for #293 2026-01-06 15:32:06 +01:00
Palash Oswal b91012b697
fix(cli): don't force localhost gateway url in remote mode
Fixes remote gateway setup (remote mode) by not overriding url; adds regression tests. Thanks @oswalpalash.
2026-01-06 14:30:45 +00:00
Simon Kelly 5aa1ed2c96
fix(slack): use named import for @slack/bolt App class (#299)
* fix(slack): use named import for @slack/bolt App class

The default import `import bolt from '@slack/bolt'` followed by
`const { App } = bolt` doesn't work correctly in Bun due to ESM/CJS
interop issues. The default export comes through as a function rather
than the module object.

Switching to a named import `import { App } from '@slack/bolt'`
resolves the issue and allows the Slack provider to start successfully.

* fix(slack): align Bolt mock with named App export

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-01-06 14:22:14 +00:00
VAC eadb923000 fix: auto-recover from Gemini session corruption
Detect the Gemini API error 'function call turn comes immediately after
a user turn or after a function response turn' which indicates corrupted
session history.

When detected:
- Delete the corrupted transcript file
- Remove the session entry from the store
- Return a user-friendly message asking them to retry

This prevents the error loop where every subsequent message fails with
the same error until manual intervention.

Fixes #296
2026-01-06 07:25:15 -05:00
Manuel Hettich aae5926db9 fix(telegram): notify user when media exceeds size limit
When a file exceeds mediaMaxMb, send a friendly error message
instead of silently dropping the upload.

---
🤖 Authored by Jarvis (AI assistant)
2026-01-06 08:45:07 +00:00
Peter Steinberger 3693449d7e feat: sandbox session tool visibility 2026-01-06 08:40:30 +00:00
Peter Steinberger 5926a98c52 fix(configure): don’t write auth.order by default 2026-01-06 09:25:36 +01:00
Peter Steinberger f2d353459f test(auth): stop prioritizing lastGood 2026-01-06 09:25:33 +01:00
Peter Steinberger ed2075ce69 test(gateway): deflake cron finished event wait 2026-01-06 09:25:31 +01:00
Muhammed Mukhthar CM 9e49c762e0
fix(auth): prioritize round-robin over lastGood for multi-account rotation (#281)
* fix(auth): prioritize round-robin over lastGood for multi-account rotation

When multiple OAuth accounts are configured, the round-robin rotation was
not working because lastGood was always prioritized, defeating the sort by
lastUsed.

Changes:
- Remove lastGood prioritization in resolveAuthProfileOrder
- Always apply orderProfilesByMode (sorts by lastUsed, oldest first)
- Only respect configuredOrder when explicitly set in config
- preferredProfile still takes priority for explicit user choice

Tested with 2 Google Antigravity accounts - verified alternating usage.

Follow-up to PR #269.

* style: fix formatting
2026-01-06 08:16:35 +00:00
Peter Steinberger cf1a1d107e fix: add OpenAI Codex OAuth to configure 2026-01-06 09:13:51 +01:00
Muhammed Mukhthar CM 42d1c2448e
fix(cron-tool): use generic object schema for job/patch to fix Claude via Antigravity (#280) 2026-01-06 02:13:09 -06:00
Peter Steinberger c27dd75135 build(control-ui): prefer bun for UI build 2026-01-06 09:08:25 +01:00
Peter Steinberger a279bcfeb1 feat: add sessions_spawn sub-agent tool 2026-01-06 08:41:45 +01:00
Peter Steinberger 952657d55c feat(tui): add /elev alias 2026-01-06 08:41:04 +01:00
Ayaan Zaidi 7a48b908e4
refactor: replace tsx with bun for TypeScript execution (#278) 2026-01-06 07:14:08 +00:00
Peter Steinberger dbb51006cd feat: unify group policy allowlists 2026-01-06 06:40:42 +00:00
Peter Steinberger 51e8bbd2a8 style: normalize type definitions 2026-01-06 07:21:10 +01:00
Peter Steinberger aa16b679ad fix: improve auth profile failover 2026-01-06 07:18:06 +01:00
Peter Steinberger a7b5753dc4
Merge pull request #269 from mukhtharcm/feat/multi-account-roundrobin
feat: Multi-account OAuth with round-robin rotation
2026-01-06 06:13:19 +00:00
Peter Steinberger b5c604b7b7 fix: require slash for control commands 2026-01-06 07:05:17 +01:00
Peter Steinberger 7d896b5f67 fix: doctor memory hint 2026-01-06 06:01:24 +00:00
Shadow 91cb2c02a7
fix: allow optional reply body 2026-01-05 23:47:33 -06:00
Shadow 69f285c5ca
chore: fixed CI 2026-01-05 23:36:48 -06:00
Peter Steinberger b759cb6f37 feat(providers): normalize location parsing 2026-01-06 06:31:09 +01:00
Nacho Iacovino 255e77f530 feat(telegram): parse location and venue messages
- Add TelegramLocation, TelegramVenue, and TelegramMessageWithLocation types
- Add formatLocationMessage() to convert location/venue shares to text
- Add extractLocationData() for structured location access in ctxPayload
- Handle both raw location pins and venue shares (places with names)
- Include location in reply-to context for quoted messages

Location messages now appear as:
- [Location: lat, lon ±accuracy] for raw pins
- [Venue: Name - Address (lat, lon)] for places

ctxPayload includes LocationLat, LocationLon, LocationAccuracy,
VenueName, and VenueAddress fields for programmatic access.
2026-01-06 06:31:09 +01:00
Muhammed Mukhthar CM 18c7795ee0 feat: treat timeout as rate limit for profile rotation
Antigravity rate limits cause requests to hang indefinitely rather than
returning 429 errors. This change detects timeouts and treats them as
potential rate limits:

- Added timedOut flag to track timeout-triggered aborts
- Timeout now triggers profile cooldown + rotation
- Logs: "Profile X timed out (possible rate limit). Trying next account..."

This ensures automatic failover when Antigravity hangs due to rate limiting.
2026-01-06 05:20:01 +00:00
Muhammed Mukhthar CM ce6c7737c1 feat: add round-robin rotation and cooldown for auth profiles
Adds usage tracking to auth profiles for automatic rotation:

- ProfileUsageStats type with lastUsed, cooldownUntil, errorCount
- markAuthProfileUsed(): tracks successful usage, resets errors
- markAuthProfileCooldown(): applies exponential backoff (1/5/25/60min)
- isProfileInCooldown(): checks if profile should be skipped
- orderProfilesByMode(): now sorts by lastUsed (oldest first)

On auth/rate-limit failures, profiles are marked for cooldown before
rotation. On success, usage is recorded for round-robin ordering.

This enables automatic load distribution across multiple accounts
(e.g., Antigravity 5-hour rate limit windows).
2026-01-06 05:17:59 +00:00
Muhammed Mukhthar CM 06df6a955a feat: use email-based profile IDs for OAuth providers
Changes writeOAuthCredentials and applyAuthProfileConfig calls to use
the email from OAuth response as part of the profile ID instead of
hardcoded ":default".

This enables multiple accounts per provider - each login creates a
separate profile (e.g., google-antigravity:user@gmail.com) instead
of overwriting the same :default profile.

Affected files:
- src/commands/onboard-auth.ts (generic writeOAuthCredentials)
- src/commands/configure.ts (Antigravity flow)
- src/wizard/onboarding.ts (Antigravity flow)
2026-01-06 05:17:59 +00:00
Shadow 88cb13dc82
Auto-reply: fix typing stop race (#270) 2026-01-05 22:57:04 -06:00
Peter Steinberger 35a2140e48 fix: clean up poll merge 2026-01-06 04:51:05 +00:00
Peter Steinberger 0b27964693 feat: unify poll support
Co-authored-by: DBH <5251425+dbhurley@users.noreply.github.com>
2026-01-06 04:51:05 +00:00
Asleep 8880128ebf
Format messages so they work with Gemini API (#266)
* fix: Gemini stops working after one message in a session

* fix: small issue in test file

* test: cover google role-merge behavior

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-01-06 04:45:40 +00:00
DBH 2737e17c67
feat: Add WhatsApp poll support (#248)
Implements issue #123 - WhatsApp Poll Support

## Gateway Protocol
- Add `poll` RPC method with params: to, question, options (2-12), selectableCount

## ActiveWebListener
- Add `sendPoll(to, poll)` method to interface
- Implementation uses Baileys poll message type

## CLI Command
- `clawdbot poll --to <jid> -q <question> -o <opt1> -o <opt2> [-s count]`
- Supports --dry-run, --json, --verbose flags
- Validates 2-12 options

## Changes
- src/gateway/protocol/schema.ts: Add PollParamsSchema
- src/gateway/protocol/index.ts: Export validator and types
- src/web/active-listener.ts: Add sendPoll to interface
- src/web/inbound.ts: Implement sendPoll using Baileys
- src/web/outbound.ts: Add sendPollWhatsApp function
- src/gateway/server-methods/send.ts: Add poll handler
- src/commands/poll.ts: New CLI command
- src/cli/program.ts: Register poll command

Closes #123
2026-01-06 04:44:15 +00:00
Peter Steinberger ea6ee16461 chore: fix lint warnings 2026-01-06 05:41:24 +01:00
Peter Steinberger 77789cb9a8 fix: improve compaction queueing and oauth flows 2026-01-06 05:41:24 +01:00
Marcus Neves 9ab0b88ac6
feat(whatsapp,telegram): add groupPolicy config option (#216)
Co-authored-by: Marcus Neves <conhecendo.contato@gmail.com>
Co-authored-by: Shadow <hi@shadowing.dev>
2026-01-05 22:41:19 -06:00
Peter Steinberger 53c9feb597 test: cover slack thread reply routing 2026-01-06 05:11:06 +01:00
Steve Caldwell 7034d4f807 fix(slack): preserve thread context in auto-replies
When replying to a message in a Slack thread, the response now stays
in the thread instead of going to the channel root.

Only threads replies when the incoming message was already in a thread
(has thread_ts). Top-level messages get top-level replies.

Fixes #250
2026-01-06 05:09:04 +01:00
Ayaan Zaidi bd735182b6
feat(telegram): support media groups (multi-image messages) (#220) 2026-01-05 22:04:33 -06:00
VACInc fb2513e265
fix(discord): Use channel ID for DMs instead of user ID (#261)
Co-authored-by: VAC <vac@vacs-mac-mini.localdomain>
2026-01-05 22:02:33 -06:00