(t *testing.T)
| 206 | } |
| 207 | |
| 208 | func TestPrimaryRetriesWithBackoff(t *testing.T) { |
| 209 | t.Parallel() |
| 210 | |
| 211 | synctest.Test(t, func(t *testing.T) { |
| 212 | successStream := newStreamBuilder(). |
| 213 | AddContent("Primary success after retries"). |
| 214 | AddStopWithUsage(10, 5). |
| 215 | Build() |
| 216 | primary := &countingProvider{ |
| 217 | id: "primary/counting", failCount: 2, |
| 218 | err: errors.New("503 service unavailable"), stream: successStream, |
| 219 | } |
| 220 | fallback := &countingProvider{ |
| 221 | id: "fallback/should-not-be-called", |
| 222 | stream: newStreamBuilder(). |
| 223 | AddContent("Fallback").AddStopWithUsage(5, 2).Build(), |
| 224 | } |
| 225 | |
| 226 | root := agent.New("root", "test", |
| 227 | agent.WithModel(primary), |
| 228 | agent.WithFallbackModel(fallback), |
| 229 | agent.WithFallbackRetries(3), |
| 230 | ) |
| 231 | |
| 232 | tm := team.New(team.WithAgents(root)) |
| 233 | rt, err := NewLocalRuntime(t.Context(), tm, WithSessionCompaction(false), WithModelStore(mockModelStore{})) |
| 234 | require.NoError(t, err) |
| 235 | |
| 236 | sess := session.New(session.WithUserMessage("test")) |
| 237 | sess.Title = "Primary Retry Test" |
| 238 | |
| 239 | var gotPrimaryContent bool |
| 240 | for ev := range rt.RunStream(t.Context(), sess) { |
| 241 | if choice, ok := ev.(*AgentChoiceEvent); ok && choice.Content == "Primary success after retries" { |
| 242 | gotPrimaryContent = true |
| 243 | } |
| 244 | } |
| 245 | assert.True(t, gotPrimaryContent, "should receive content from primary after retries") |
| 246 | assert.Equal(t, 3, primary.callCount, "primary should be called 3 times (2 failures + 1 success)") |
| 247 | assert.Equal(t, 0, fallback.callCount, "fallback should not be called when primary succeeds on retry") |
| 248 | }) |
| 249 | } |
| 250 | |
| 251 | func TestNoFallbackWhenPrimarySucceeds(t *testing.T) { |
| 252 | t.Parallel() |
nothing calls this directly
no test coverage detected