agent: Preserve thinking blocks between requests (#29055)
Looks like the required backend component of this was deployed. https://github.com/zed-industries/monorepo/actions/runs/14541199197 Release Notes: - N/A --------- Co-authored-by: Antonio Scandurra <me@as-cii.com> Co-authored-by: Agus Zubiaga <hi@aguz.me> Co-authored-by: Richard Feldman <oss@rtfeldman.com> Co-authored-by: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
f737c4d01e
commit
bafc086d27
13 changed files with 236 additions and 68 deletions
|
@ -336,6 +336,12 @@ pub fn count_anthropic_tokens(
|
|||
MessageContent::Text(text) => {
|
||||
string_contents.push_str(&text);
|
||||
}
|
||||
MessageContent::Thinking { .. } => {
|
||||
// Thinking blocks are not included in the input token count.
|
||||
}
|
||||
MessageContent::RedactedThinking(_) => {
|
||||
// Thinking blocks are not included in the input token count.
|
||||
}
|
||||
MessageContent::Image(image) => {
|
||||
tokens_from_images += image.estimate_tokens();
|
||||
}
|
||||
|
@ -515,6 +521,29 @@ pub fn into_anthropic(
|
|||
None
|
||||
}
|
||||
}
|
||||
MessageContent::Thinking {
|
||||
text: thinking,
|
||||
signature,
|
||||
} => {
|
||||
if !thinking.is_empty() {
|
||||
Some(anthropic::RequestContent::Thinking {
|
||||
thinking,
|
||||
signature: signature.unwrap_or_default(),
|
||||
cache_control,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
MessageContent::RedactedThinking(data) => {
|
||||
if !data.is_empty() {
|
||||
Some(anthropic::RequestContent::RedactedThinking {
|
||||
data: String::from_utf8(data).ok()?,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
MessageContent::Image(image) => Some(anthropic::RequestContent::Image {
|
||||
source: anthropic::ImageSource {
|
||||
source_type: "base64".to_string(),
|
||||
|
@ -637,7 +666,10 @@ pub fn map_to_language_model_completion_events(
|
|||
}
|
||||
ResponseContent::Thinking { thinking } => {
|
||||
return Some((
|
||||
vec![Ok(LanguageModelCompletionEvent::Thinking(thinking))],
|
||||
vec![Ok(LanguageModelCompletionEvent::Thinking {
|
||||
text: thinking,
|
||||
signature: None,
|
||||
})],
|
||||
state,
|
||||
));
|
||||
}
|
||||
|
@ -665,11 +697,22 @@ pub fn map_to_language_model_completion_events(
|
|||
}
|
||||
ContentDelta::ThinkingDelta { thinking } => {
|
||||
return Some((
|
||||
vec![Ok(LanguageModelCompletionEvent::Thinking(thinking))],
|
||||
vec![Ok(LanguageModelCompletionEvent::Thinking {
|
||||
text: thinking,
|
||||
signature: None,
|
||||
})],
|
||||
state,
|
||||
));
|
||||
}
|
||||
ContentDelta::SignatureDelta { signature } => {
|
||||
return Some((
|
||||
vec![Ok(LanguageModelCompletionEvent::Thinking {
|
||||
text: "".to_string(),
|
||||
signature: Some(signature),
|
||||
})],
|
||||
state,
|
||||
));
|
||||
}
|
||||
ContentDelta::SignatureDelta { .. } => {}
|
||||
ContentDelta::InputJsonDelta { partial_json } => {
|
||||
if let Some(tool_use) = state.tool_uses_by_index.get_mut(&index) {
|
||||
tool_use.input_json.push_str(&partial_json);
|
||||
|
|
|
@ -742,9 +742,10 @@ pub fn get_bedrock_tokens(
|
|||
|
||||
for content in message.content {
|
||||
match content {
|
||||
MessageContent::Text(text) => {
|
||||
MessageContent::Text(text) | MessageContent::Thinking { text, .. } => {
|
||||
string_contents.push_str(&text);
|
||||
}
|
||||
MessageContent::RedactedThinking(_) => {}
|
||||
MessageContent::Image(image) => {
|
||||
tokens_from_images += image.estimate_tokens();
|
||||
}
|
||||
|
@ -830,25 +831,36 @@ pub fn map_to_language_model_completion_events(
|
|||
redacted,
|
||||
) => {
|
||||
let thinking_event =
|
||||
LanguageModelCompletionEvent::Thinking(
|
||||
String::from_utf8(
|
||||
LanguageModelCompletionEvent::Thinking {
|
||||
text: String::from_utf8(
|
||||
redacted.into_inner(),
|
||||
)
|
||||
.unwrap_or("REDACTED".to_string()),
|
||||
);
|
||||
signature: None,
|
||||
};
|
||||
|
||||
return Some((
|
||||
Some(Ok(thinking_event)),
|
||||
state,
|
||||
));
|
||||
}
|
||||
ReasoningContentBlockDelta::Signature(_sig) => {
|
||||
ReasoningContentBlockDelta::Signature(
|
||||
signature,
|
||||
) => {
|
||||
return Some((
|
||||
Some(Ok(LanguageModelCompletionEvent::Thinking {
|
||||
text: "".to_string(),
|
||||
signature: Some(signature)
|
||||
})),
|
||||
state,
|
||||
));
|
||||
}
|
||||
ReasoningContentBlockDelta::Text(thoughts) => {
|
||||
let thinking_event =
|
||||
LanguageModelCompletionEvent::Thinking(
|
||||
thoughts.to_string(),
|
||||
);
|
||||
LanguageModelCompletionEvent::Thinking {
|
||||
text: thoughts.to_string(),
|
||||
signature: None
|
||||
};
|
||||
|
||||
return Some((
|
||||
Some(Ok(thinking_event)),
|
||||
|
|
|
@ -424,8 +424,11 @@ impl CopilotChatLanguageModel {
|
|||
let text_content = {
|
||||
let mut buffer = String::new();
|
||||
for string in message.content.iter().filter_map(|content| match content {
|
||||
MessageContent::Text(text) => Some(text.as_str()),
|
||||
MessageContent::Text(text) | MessageContent::Thinking { text, .. } => {
|
||||
Some(text.as_str())
|
||||
}
|
||||
MessageContent::ToolUse(_)
|
||||
| MessageContent::RedactedThinking(_)
|
||||
| MessageContent::ToolResult(_)
|
||||
| MessageContent::Image(_) => None,
|
||||
}) {
|
||||
|
|
|
@ -368,13 +368,15 @@ pub fn into_google(
|
|||
content
|
||||
.into_iter()
|
||||
.filter_map(|content| match content {
|
||||
language_model::MessageContent::Text(text) => {
|
||||
language_model::MessageContent::Text(text)
|
||||
| language_model::MessageContent::Thinking { text, .. } => {
|
||||
if !text.is_empty() {
|
||||
Some(Part::TextPart(google_ai::TextPart { text }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
language_model::MessageContent::RedactedThinking(_) => None,
|
||||
language_model::MessageContent::Image(_) => None,
|
||||
language_model::MessageContent::ToolUse(tool_use) => {
|
||||
Some(Part::FunctionCallPart(google_ai::FunctionCallPart {
|
||||
|
|
|
@ -342,14 +342,16 @@ pub fn into_open_ai(
|
|||
for message in request.messages {
|
||||
for content in message.content {
|
||||
match content {
|
||||
MessageContent::Text(text) => messages.push(match message.role {
|
||||
Role::User => open_ai::RequestMessage::User { content: text },
|
||||
Role::Assistant => open_ai::RequestMessage::Assistant {
|
||||
content: Some(text),
|
||||
tool_calls: Vec::new(),
|
||||
},
|
||||
Role::System => open_ai::RequestMessage::System { content: text },
|
||||
}),
|
||||
MessageContent::Text(text) | MessageContent::Thinking { text, .. } => messages
|
||||
.push(match message.role {
|
||||
Role::User => open_ai::RequestMessage::User { content: text },
|
||||
Role::Assistant => open_ai::RequestMessage::Assistant {
|
||||
content: Some(text),
|
||||
tool_calls: Vec::new(),
|
||||
},
|
||||
Role::System => open_ai::RequestMessage::System { content: text },
|
||||
}),
|
||||
MessageContent::RedactedThinking(_) => {}
|
||||
MessageContent::Image(_) => {}
|
||||
MessageContent::ToolUse(tool_use) => {
|
||||
let tool_call = open_ai::ToolCall {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue