(ctx context.Context, providers []string, req cliproxyexecutor.Request, opts cliproxyexecutor.Options, maxRetryCredentials int)
| 2672 | } |
| 2673 | |
| 2674 | func (m *Manager) executeStreamMixedOnce(ctx context.Context, providers []string, req cliproxyexecutor.Request, opts cliproxyexecutor.Options, maxRetryCredentials int) (*cliproxyexecutor.StreamResult, error) { |
| 2675 | if len(providers) == 0 { |
| 2676 | return nil, &Error{Code: "provider_not_found", Message: "no provider supplied"} |
| 2677 | } |
| 2678 | routeModel := req.Model |
| 2679 | opts = ensureRequestedModelMetadata(opts, routeModel) |
| 2680 | homeMode := m.HomeEnabled() |
| 2681 | homeAuthCount := 1 |
| 2682 | tried := make(map[string]struct{}) |
| 2683 | attempted := make(map[string]struct{}) |
| 2684 | var lastErr error |
| 2685 | for { |
| 2686 | if !homeMode && maxRetryCredentials > 0 && len(attempted) >= maxRetryCredentials { |
| 2687 | if lastErr != nil { |
| 2688 | return nil, lastErr |
| 2689 | } |
| 2690 | return nil, &Error{Code: "auth_not_found", Message: "no auth available"} |
| 2691 | } |
| 2692 | pickOpts := opts |
| 2693 | if homeMode { |
| 2694 | pickOpts = withHomeAuthCount(opts, homeAuthCount) |
| 2695 | } |
| 2696 | auth, executor, provider, errPick := m.pickNextMixed(ctx, providers, routeModel, pickOpts, tried) |
| 2697 | if errPick != nil { |
| 2698 | if shouldReturnLastErrorOnPickFailure(homeMode, lastErr, errPick) { |
| 2699 | return nil, lastErr |
| 2700 | } |
| 2701 | return nil, errPick |
| 2702 | } |
| 2703 | |
| 2704 | entry := logEntryWithRequestID(ctx) |
| 2705 | debugLogAuthSelection(entry, auth, provider, req.Model) |
| 2706 | publishSelectedAuthMetadata(opts.Metadata, auth.ID) |
| 2707 | |
| 2708 | tried[auth.ID] = struct{}{} |
| 2709 | execCtx := ctx |
| 2710 | if rt := m.roundTripperFor(auth); rt != nil { |
| 2711 | execCtx = context.WithValue(execCtx, roundTripperContextKey{}, rt) |
| 2712 | execCtx = context.WithValue(execCtx, "cliproxy.roundtripper", rt) |
| 2713 | } |
| 2714 | models, pooled, aliasResult := m.preparedExecutionModelsWithAlias(auth, routeModel) |
| 2715 | if len(models) == 0 { |
| 2716 | continue |
| 2717 | } |
| 2718 | attempted[auth.ID] = struct{}{} |
| 2719 | var errPrepare error |
| 2720 | auth, errPrepare = m.prepareRequestAuth(execCtx, executor, auth) |
| 2721 | if errPrepare != nil { |
| 2722 | result := Result{AuthID: auth.ID, Provider: provider, Model: routeModel, Success: false, Error: &Error{Message: errPrepare.Error()}} |
| 2723 | if se, ok := errors.AsType[cliproxyexecutor.StatusError](errPrepare); ok && se != nil { |
| 2724 | result.Error.HTTPStatus = se.StatusCode() |
| 2725 | } |
| 2726 | m.MarkResult(execCtx, result) |
| 2727 | lastErr = errPrepare |
| 2728 | continue |
| 2729 | } |
| 2730 | execReq := sanitizeDownstreamWebsocketFallbackRequest(execCtx, auth, req) |
| 2731 | streamResult, errStream := m.executeStreamWithModelPool(execCtx, executor, auth, provider, execReq, opts, routeModel, models, pooled, aliasResult) |
no test coverage detected