When the conversation context exceeds the model's limit, instead of
throwing an opaque error or returning raw JSON, we now:
1. Detect context overflow errors (413, request_too_large, etc.)
2. Return a user-friendly message explaining the issue
3. Suggest using /new or /reset to start fresh
This prevents the assistant from becoming completely unresponsive
when context grows too large (e.g., from many screenshots or long
tool outputs).
Addresses issue #394
Claude API on Vertex AI (Cloud Code Assist) rejects nested anyOf schemas
as invalid JSON Schema draft 2020-12. This change:
- Add tryFlattenLiteralAnyOf() to convert Type.Union([Type.Literal(...)])
patterns from anyOf with const values to flat enum arrays
- Update stringEnum helper in bash-tools to use Type.Unsafe with flat enum
- Flatten BrowserActSchema from discriminated union to single object
- Simplify TelegramToolSchema to use Type.String() for IDs
Fixes 400 errors when sending messages through WhatsApp/Telegram providers.
Add 5 tests for agent-specific tool restrictions:
- Apply global tool policy when no agent-specific policy exists
- Apply agent-specific tool policy
- Allow different tool policies for different agents
- Combine global and agent-specific deny lists
- Work with sandbox tools filtering
All tests pass.
Add 6 tests for agent-specific sandbox configuration:
- Use global sandbox config when no agent-specific config exists
- Override with agent-specific sandbox mode 'off'
- Use agent-specific sandbox mode 'all'
- Use agent-specific scope
- Use agent-specific workspaceRoot
- Prefer agent config over global for multiple agents
All tests pass.
Add 7 tests for resolveAgentConfig():
- Return undefined when no agents config exists
- Return undefined when agent id does not exist
- Return basic agent config (name, workspace, agentDir, model)
- Return agent-specific sandbox config
- Return agent-specific tools config
- Return both sandbox and tools config
- Normalize agent id
All tests pass.
Changes to defaultSandboxConfig():
- Add optional agentId parameter
- Load routing.agents[agentId].sandbox if available
- Prefer agent-specific settings over global agent.sandbox
Update callers in resolveSandboxContext() and
ensureSandboxWorkspaceForSession() to extract agentId
from sessionKey and pass it to defaultSandboxConfig().
This enables per-agent sandbox modes (e.g., main: off, family: all).
Return newly added fields from routing.agents config:
- sandbox: agent-specific sandbox configuration
- tools: agent-specific tool restrictions
This makes per-agent sandbox and tool settings accessible
to other parts of the codebase.
Add source profiles anthropic:claude-cli and openai-codex:codex-cli; surface them in onboarding/configure.
Co-authored-by: pepicrft <pepicrft@users.noreply.github.com>
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
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