Repository navigation
[EPIC-V][LOU-V7.2] createAgent retry policy, fallbackModels and typed retry/fallback events - #86
Merged
Merged
Conversation
…allback events
- createAgent({ retry?: WithRetryOptions | false, fallbackModels?: string[] }):
model strings (and env-picked models) are resolved with maxRetries: 0 and
wrapped in withRetry (default { maxRetries: 2 }); fallbackModels are
resolved the same way and composed with withFallback. A provider instance
is wrapped only when retry is set.
- aiSdkProvider passes maxRetries to generateText/streamText
(config.maxRetries ?? 2), so retries no longer stack under createAgent.
- New typed stream events provider.retry and provider.fallback. A streaming
run attaches a per-call listener to each request (symbol-keyed, internal
providers/providerEvents.ts); withRetry/withFallback report to it, so the
events reach agent.stream(), session.stream(), AgentExecutor.stream() and
sub-agent streams without touching AgentExecutor. Schema version stays 1.
- Docs (configuration, providers, streaming), llms-full.txt, CHANGELOG.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bY29ibQgv3MDdjAbUT4YR
…fallback # Conflicts: # docs/streaming.md # llms-full.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
createAgent({ retry?: WithRetryOptions | false, fallbackModels?: readonly string[] }).provider/modelstrings, or picked from the environment, are resolved withmaxRetries: 0and wrapped inwithRetry(…, retry ?? { maxRetries: 2 }).retry: falseskips the wrapper.fallbackModelsare resolved with the same resolver (resolveProviderSpec, with errors prefixedcreateAgent:) when the agent is created. They are composed aswithFallback([withRetry(primary), withRetry(fb1), ...]).provideris wrapped only whenretryis set. It keeps its own retry behaviour otherwise.fallbackModelswork with it too.aiSdkProviderpassesmaxRetries: config.maxRetries ?? 2togenerateText/streamText. Direct users keep theaidefault of 2. Providers thatcreateAgentresolves get 0, so retries happen in one place and can be observed.src/execution/agentEvents.ts:provider.retry:{ attempt, maxRetries, delayMs, error: { message, category? }, provider }.categoryis left out when it is'unknown'.provider.fallback:{ from, to, error: { message } }.agentRun.ts) attaches a listener to each model request. It is keyed by a symbol and lives in the internal modulesrc/providers/providerEvents.ts, which is not re-exported.withRetry/withFallbackreport to the listener of the call they handle, in addition to their ownonRetry/onFallback.agent.stream(),session.stream(),AgentExecutor.stream()and sub-agent streams (tagged withsubagent), for anywithRetry/withFallbackprovider.AgentExecutor.tsis unchanged, andsend()behaves as before.v.llms-full.txtis regenerated, and CHANGELOG.md has an Added entry plus a Changed entry on retries no longer stacking.Why
LOU-V7.2 (Epic V) brings this to parity with eve's gateway fallbacks and open-harness
withRetry, and finishes LOU-V7. Before this change theaiSDK's 2 internal retries ran inside everywithRetryattempt (retries stacked), and you could not see retries or fallbacks from a run.Acceptance criteria
createAgent({ retry, fallbackModels }):retrydefaults to{ maxRetries: 2 }(same number of calls as today's implicitairetries) andfalsedisables it.fallbackModelsare resolved with the same resolver and tried in order viawithFallback. Works withmodelstrings and with a user-suppliedprovider.aiSdkProviderpassesconfig.maxRetries ?? 2, andcreateAgent-wrapped providers get 0. This is in the CHANGELOG.provider.retry/provider.fallbackevents are emitted intoagent.stream()andsession.stream().send()callers read the result as before.AgentExecutor.tsis not modified, and the schema version is not bumped because the change is additive.src/createAgentResilience.test.ts(8 tests):provider.retryand returns the final result (stream()andsend());retry: falsefails fast;fallbackModelsswitches models and emitsprovider.fallback;agent.stream()andsession.stream();retryis set.aiSdkProviderunit test on themaxRetriesit passes to theaicalls, and type tests for the new events inagentEvents.test-d.ts.How verified
npx tsc --noEmitexited 0.npm run lintreported0 errors, 433 warnings. The changed files add no new warnings; the only warning in them is the existingas anyin aiSdkProvider.ts.npm run test:typesreportedType Errors no errors.npx vitest run:Test Files 141 passed (141),Tests 2065 passed | 3 skipped (2068).npm run build && npm run build --workspace=packages/create-loushy-agentexited 0.npm run docs:verify-snippets -- --skip-build:all 97 snippet(s) type-check against src/; 6 also run cleanly.npm run docs:llms:checkexited 0.npm run test:coverage(141 files, 2065 tests passed) andnpm run fallowboth exited 0. Fallow reportsNo issues found; the only duplicate it lists was already in untouched files (OpenAIProvider.ts/AnthropicProvider.ts).🤖 Generated with Claude Code
https://claude.ai/code/session_016bY29ibQgv3MDdjAbUT4YR
Generated by Claude Code