Skip to content

feat: expose maxEmptyRetries and maxEmptyRetryTimeMs settings - #3

Open
nsluss wants to merge 2529 commits into
mainfrom
noah/empty-retry-settings
Open

feat: expose maxEmptyRetries and maxEmptyRetryTimeMs settings#3
nsluss wants to merge 2529 commits into
mainfrom
noah/empty-retry-settings

Conversation

@nsluss

@nsluss nsluss commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

Plumb retry settings for empty response handling through to the Agent.

Changes

  • Add maxEmptyRetries and maxEmptyRetryTimeMs to getRetrySettings() return type
  • Pass these settings to Agent constructor in createAgentSession()
  • Defaults: maxEmptyRetries=3, maxEmptyRetryTimeMs=15000

Example config

Noah's current settings:

[retry]
maxEmptyRetries = 8
maxEmptyRetryTimeMs = 60000

This allows users to tune how aggressively punkin retries on empty responses before giving up.

badlogic and others added 30 commits February 5, 2026 13:11
feat(coding-agent): display name of selected model in modelSelectors
Use hosted-git-info library for robust parsing of SSH URLs (git@host:path
and ssh://) in addition to HTTPS. SSH and HTTPS URLs for the same repo
are now properly deduplicated.
feat(coding-agent): add SSH URL support for git packages
fix(coding-agent): exit early for help/version/export/list-models (fixes #1277)
- Add adaptive thinking mode (type: 'adaptive') for Opus 4.6+
- Add effort parameter ('low', 'medium', 'high', 'max') for adaptive thinking
- thinkingEnabled now auto-detects: adaptive for 4.6+, budget-based for older
- streamSimple/completeSimple map ThinkingLevel to effort levels for Opus 4.6
- Add tests for Opus 4.6 adaptive thinking and GPT-5.3 Codex
- Update @anthropic-ai/sdk to 0.73.0
- Update @aws-sdk/client-bedrock-runtime to 3.983.0
- Update @google/genai to 1.40.0
- Remove fast-xml-parser override (no longer needed)
- anthropic: claude-opus-4-5 → claude-opus-4-6
- openai-codex: gpt-5.2-codex → gpt-5.3-codex
- amazon-bedrock: us.anthropic.claude-opus-4-20250514-v1:0 → us.anthropic.claude-opus-4-6-v1:0
- vercel-ai-gateway: anthropic/claude-opus-4.5 → anthropic/claude-opus-4-6
- opencode: claude-opus-4-5 → claude-opus-4-6
…and add EU profile

- Remove :0 suffix from Opus 4.6 Bedrock model IDs (not valid for this model)
- Fix us/eu Opus 4.6 cache pricing (0.5/6.25 instead of 1.5/18.75)
- Add missing eu.anthropic.claude-opus-4-6-v1 inference profile
- Fix coding-agent default Bedrock model ID to match catalog
cartazio and others added 28 commits March 5, 2026 23:37
…pgrades

Empty turns (agent-loop, turn-boundary, turn-boundary-types):
- Skip turn_end for truly empty aborted turns (content.length === 0)
- Add isEmpty flag to TurnEndMessage for tool-call-only turns
- Render "(empty)" marker in close bracket — only for fully empty turns
- Fix: tool-call-only turns were incorrectly marked isEmpty

Turn counter persistence (session-manager, session-hook, agent-session):
- Persist turnNumber in TurnBoundaryEntry
- initializeTurnCounterFromEntries() reconstructs counter on session load
- Old entries fall back to boundary.turn (backwards compat)
- Fixes turn brackets disappearing after compaction/branching

Footer (footer-data-provider, footer.ts):
- getRepoCommit() + getRepoState() (clean/staged/dirty)
- New 4-line layout: pwd | @commit state | stats | extensions + build info
- Build info (version, commit, timestamp) right-aligned on line 4

native-ui (ffi, view, render, demo):
- createMenuBar() — HIG-compliant App/File/Edit/View/Window/Help
- createVibrancyView() — NSVisualEffectView frosted glass
- vibrancy() View primitive + render case
- Demo: sidebar uses vibrancy, spacer in header

models.generated: gpt-5.4, gpt-5.4-pro, gpt-5.3-codex, mercury-2; cost corrections

docs: EMPTY-TURNS-ANALYSIS.md, EMPTY-TURNS-FIX.md, TURN-COUNTER-FIX.md
…ounce, retry logic

Implements all fixes from HANDOFF-harness-thinking-abort-fixes:

1. Suppress empty-aborted assistant messages from persisting to transcript
   - These ghost entries cause visual cutoffs and display thrash
   - Skip appendMessage if stopReason='aborted' && content.length=0

2. Squiggle-wins policy: if text contains <squiggle>, skip rendering thinking blocks
   - Prevents duplicate CoT display (provider thinking + user-authored squiggle)
   - Display-only; transcript normalization separate

3. Abort debounce in interactive mode (150ms time-gate)
   - Absorbs rapid fire empty message_end events from context switches
   - Prevents visual churn from quick user input sequences

4. Anthropic provider retry logic with CSPRNG equal-jitter backoff
   - MAX_RETRIES=3, BASE_DELAY=1s, exponential with cap
   - Guards: no retry after abort, no retry after content emitted
   - Error classification: 429/50x, rate_limit, overloaded, timeout patterns

5. Remove debug console.error from turn boundary injection
   - Confirmed working in prior session, logging no longer needed

6. Model metadata updates (Gemini 3.1 Flash Lite, Mistral naming)
OpenRouter expects reasoning in nested format: { reasoning: { effort: 'high' } }
not OpenAI-style { reasoning_effort: 'high' }

Changes:
- openai-completions.ts: add thinkingFormat='openrouter' case to buildParams
- generate-models.ts: mark OpenRouter models with compat.thinkingFormat when reasoning=true
- models.generated.ts: regenerated with compat fields for ~20 OpenRouter reasoning models

Impact: Unblocks all OpenRouter reasoning models (DeepSeek-R1, Qwen, etc)
Prior: reasoning calls failed silently due to format mismatch
Now: reasoning_effort correctly routed to nested reasoning object

Related: HANDOFF-provider-metadata_v2_20260303T2335NYC.md (Phase 1)
Add topP, topK, minP, frequencyPenalty, presencePenalty, seed to StreamOptions.
Wire through openai-completions provider with provider-specific defaults.

Support matrix (from API docs):
- OpenAI: topP ✅ freq/pres penalties ✅ seed ✅ (no topK)
- Anthropic: topP ✅ topK ✅ (no penalties, seed)
- Mistral: all 6 params ✅
- Groq: topP ✅ topK ✅ seed ✅ (limited penalties)
- Z.ai: topP ✅ only

Impact: Developers can now control sampling behavior per model.
Unsupported params silently skipped (no API errors).

Next: Phase 2.5 adds sampling.toml with vendor defaults/ranges.
Then: Phase 3 (Anthropic beta headers), Phase 4 (OpenRouter metadata)
Parse anthropic-models.toml and map beta headers to each Anthropic model.
Add AnthropicCompat interface with supportedBetas array.
Regenerate models with beta capability metadata.

Beta headers now available per-model:
- Opus 4.6: 12 betas including 1M context, computer-use-v3, fast-mode
- Sonnet 4.6: extended thinking, computer-use-v3, 1M context
- Opus 4.5: computer-use-v3
- Sonnet 4.5/Haiku: computer-use-v2

Impact: Enables feature detection for extended capabilities.
Harness can route requests to correct model + beta headers.

Next: Phase 4 (OpenRouter metadata extraction)
- Add SamplingSettings and AnthropicFeatureSettings to settings schema
- Wire sampling options (temperature, topP, topK, minP, penalties, seed) through Agent to providers
- Wire Anthropic feature toggles (interleavedThinking, context1M, beta headers) to stream options
- Add favoriteModels/recentModels tracking (auto-record on model switch)
- Create sampling.toml vendor metadata with defaults and ranges
- Preserve sampling/Anthropic options through buildBaseOptions
- Deduplicate Anthropic beta headers across OAuth/API key/Copilot auth paths
- Extend StreamOptions with interleavedThinking, context1M, anthropicBetaHeaders fields
- Add AgentSamplingOptions and AgentAnthropicOptions types in agent-core
- Map Anthropic feature toggles to beta header prefixes in SDK createAgentSession
- Sort models: current → favorites → recents → provider order
- Show ★ star indicator for favorite models
- Add Ctrl+F keybind to toggle favorite for selected model
- Display hint for favorite toggle in model selector UI
- Favorites/recents loaded from SettingsManager on mount
- Add temperature and top-p dropdowns to /settings
- Add interleaved thinking and context 1M toggles
- Fix model selector favorite toggle to preserve selection
- Wire settings changes through to Agent at runtime
Interleaved thinking should always be on - not a user choice.
Logs stream lifecycle events to stderr when enabled:
- Stream start/end
- Event counts
- stop_reason from API
- Retry attempts
- Error paths
Anthropic/OpenRouter occasionally return empty responses after tool results.
- Retry with random jitter (up to 1s) to avoid thundering herd
- Configurable via settings: maxEmptyRetries (default: 3), maxEmptyRetryTimeMs (default: 15s)
- Convert to error after limits exhausted - empty is never valid
Added to all three auth paths (API key, OAuth, Copilot):
- Connection: close header to force server to close connection
- fetchOptions: { keepalive: false } to prevent client-side connection pooling

This should prevent connection reuse bugs that may cause empty responses.
Covers OpenRouter and all OpenAI-compatible providers.
…pection CLI

Bug fixes:
- max_tokens: read per-model limits from ~/.agent/settings.toml
  [modelMaxTokens.anthropic] instead of hardcoded model.maxTokens/3
  (~1.3K). Fallback: 128K for Opus 4.6, 64K for all others.
  max_tokens is a per-turn output cap, not context window.
- budget_tokens: only set when explicitly configured via
  thinkingBudgetTokens. Was silently defaulting to 1024 (minimum),
  starving the model of thinking capacity.
- Wire maxEmptyRetries/maxEmptyRetryTimeMs from AgentOptions through
  to AgentLoopConfig for empty response retry control.

New features:
- --dump-settings-template: print ~/.agent/settings_template.toml
- --promote-settings: print effective merged settings as TOML candidate
- SettingsManager.getResolvedSettings(): expose merged settings

Files: agent.ts, anthropic.ts, args.ts, settings-manager.ts, main.ts
Plumb retry settings for empty response handling through to the Agent.

- Add maxEmptyRetries and maxEmptyRetryTimeMs to getRetrySettings() return type
- Pass these settings to Agent constructor in createAgentSession()
- Defaults: maxEmptyRetries=3, maxEmptyRetryTimeMs=15000

Example config (Noah's current settings):
  [retry]
  maxEmptyRetries = 8
  maxEmptyRetryTimeMs = 60000
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.