dramatically improve LLM traces and fixed bug with Bedrock translation from claude code

This commit is contained in:
Salman Paracha 2025-10-23 22:16:05 -07:00
parent 0ee0912a73
commit 43def45746
8 changed files with 151 additions and 61 deletions

View file

@ -21,10 +21,29 @@ impl fmt::Display for SupportedAPIs {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SupportedAPIs::OpenAIChatCompletions(api) => {
write!(f, "OpenAI API ({})", api.endpoint())
write!(f, "OpenAI ({})", api.endpoint())
}
SupportedAPIs::AnthropicMessagesAPI(api) => {
write!(f, "Anthropic API ({})", api.endpoint())
write!(f, "Anthropic AI ({})", api.endpoint())
}
}
}
}
impl fmt::Display for SupportedUpstreamAPIs {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SupportedUpstreamAPIs::OpenAIChatCompletions(api) => {
write!(f, "OpenAI ({})", api.endpoint())
}
SupportedUpstreamAPIs::AnthropicMessagesAPI(api) => {
write!(f, "Anthropic ({})", api.endpoint())
}
SupportedUpstreamAPIs::AmazonBedrockConverse(api) => {
write!(f, "Amazon Bedrock ({})", api.endpoint())
}
SupportedUpstreamAPIs::AmazonBedrockConverseStream(api) => {
write!(f, "Amazon Bedrock ({})", api.endpoint())
}
}
}

View file

@ -380,6 +380,16 @@ impl TryFrom<(SseEvent, &SupportedAPIs, &SupportedUpstreamAPIs)> for SseEvent {
transformed_event.sse_transform_buffer = format!("\n"); // suppress the event upstream for OpenAI
}
}
(
SupportedAPIs::AnthropicMessagesAPI(_),
SupportedUpstreamAPIs::AnthropicMessagesAPI(_),
) => {
// When both client and upstream are Anthropic, suppress event-only lines
// because the data line transformation already includes the event line
if transformed_event.is_event_only() && transformed_event.event.is_some() {
transformed_event.sse_transform_buffer = String::new(); // suppress duplicate event line
}
}
_ => {
// Other combinations can be handled here as needed
}

View file

@ -97,21 +97,24 @@ impl TryFrom<AnthropicMessagesRequest> for ConverseRequest {
});
// Convert tools and tool choice to ToolConfiguration
let tool_config = if req.tools.is_some() || req.tool_choice.is_some() {
let tools = req.tools.map(|anthropic_tools| {
anthropic_tools
.into_iter()
.map(|tool| BedrockTool::ToolSpec {
tool_spec: ToolSpecDefinition {
name: tool.name,
description: tool.description,
input_schema: ToolInputSchema {
json: tool.input_schema,
},
// Only include toolConfig if we have actual tools (Bedrock requires at least 1 tool)
let tool_config = req.tools.and_then(|anthropic_tools| {
if anthropic_tools.is_empty() {
return None;
}
let tools = anthropic_tools
.into_iter()
.map(|tool| BedrockTool::ToolSpec {
tool_spec: ToolSpecDefinition {
name: tool.name,
description: tool.description,
input_schema: ToolInputSchema {
json: tool.input_schema,
},
})
.collect()
});
},
})
.collect();
let tool_choice = req.tool_choice.map(|choice| {
match choice.kind {
@ -136,10 +139,11 @@ impl TryFrom<AnthropicMessagesRequest> for ConverseRequest {
}
});
Some(ToolConfiguration { tools, tool_choice })
} else {
None
};
Some(ToolConfiguration {
tools: Some(tools),
tool_choice,
})
});
Ok(ConverseRequest {
model_id: req.model,