Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions src/OpenDeepWiki/Agents/AgentFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,25 @@ public class AgentFactory(IOptions<AiRequestOptions> options)

/// <summary>
/// Creates an HttpClient with the full handler chain:
/// FinishReasonNormalizingHandler -> LoggingHttpHandler -> HttpClientHandler
/// ThoughtSignatureHandler -> FinishReasonNormalizingHandler -> LoggingHttpHandler
/// -> HttpClientHandler
///
/// FinishReasonNormalizingHandler is outermost so it transforms the SSE response
/// AFTER LoggingHttpHandler's retry logic has delivered the final response.
/// This ensures Gemini's non-OpenAI finish_reason values (STOP, MAX_TOKENS,
/// SAFETY, etc.) are mapped to the OpenAI SDK's expected set before deserialization.
/// FinishReasonNormalizingHandler sits above LoggingHttpHandler so it transforms the
/// SSE response AFTER the retry logic has delivered the final response. This ensures
/// Gemini's non-OpenAI finish_reason values (STOP, MAX_TOKENS, SAFETY, etc.) are
/// mapped to the OpenAI SDK's expected set before deserialization.
///
/// ThoughtSignatureHandler is outermost so it sees the request before it is sent and
/// the response after everything below has settled. It carries Gemini 3's
/// thought_signature from one turn to the next, which the OpenAI SDK would otherwise
/// drop, making the second call of any tool conversation fail with 400.
/// </summary>
private static HttpClient CreateHttpClient()
{
var handler = new FinishReasonNormalizingHandler(
new LoggingHttpHandler(
new HttpClientHandler()));
return new HttpClient(handler)
return new HttpClient(new ThoughtSignatureHandler(handler))
{
Timeout = TimeSpan.FromSeconds(300)
};
Expand Down
Loading