agent2: Make model of Thread optional (#36395)

Related to #36394 

Release Notes:

- N/A
This commit is contained in:
Bennet Bo Fenner 2025-08-18 11:56:02 +02:00 committed by GitHub
parent 2075627d6c
commit 2eadd5a396
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 195 additions and 138 deletions

View file

@ -469,7 +469,7 @@ pub struct Thread {
profile_id: AgentProfileId,
project_context: Rc<RefCell<ProjectContext>>,
templates: Arc<Templates>,
model: Arc<dyn LanguageModel>,
model: Option<Arc<dyn LanguageModel>>,
project: Entity<Project>,
action_log: Entity<ActionLog>,
}
@ -481,7 +481,7 @@ impl Thread {
context_server_registry: Entity<ContextServerRegistry>,
action_log: Entity<ActionLog>,
templates: Arc<Templates>,
model: Arc<dyn LanguageModel>,
model: Option<Arc<dyn LanguageModel>>,
cx: &mut Context<Self>,
) -> Self {
let profile_id = AgentSettings::get_global(cx).default_profile.clone();
@ -512,12 +512,12 @@ impl Thread {
&self.action_log
}
pub fn model(&self) -> &Arc<dyn LanguageModel> {
&self.model
pub fn model(&self) -> Option<&Arc<dyn LanguageModel>> {
self.model.as_ref()
}
pub fn set_model(&mut self, model: Arc<dyn LanguageModel>) {
self.model = model;
self.model = Some(model);
}
pub fn completion_mode(&self) -> CompletionMode {
@ -575,6 +575,7 @@ impl Thread {
&mut self,
cx: &mut Context<Self>,
) -> Result<mpsc::UnboundedReceiver<Result<AgentResponseEvent>>> {
anyhow::ensure!(self.model.is_some(), "Model not set");
anyhow::ensure!(
self.tool_use_limit_reached,
"can only resume after tool use limit is reached"
@ -584,7 +585,7 @@ impl Thread {
cx.notify();
log::info!("Total messages in thread: {}", self.messages.len());
Ok(self.run_turn(cx))
self.run_turn(cx)
}
/// Sending a message results in the model streaming a response, which could include tool calls.
@ -595,11 +596,13 @@ impl Thread {
id: UserMessageId,
content: impl IntoIterator<Item = T>,
cx: &mut Context<Self>,
) -> mpsc::UnboundedReceiver<Result<AgentResponseEvent>>
) -> Result<mpsc::UnboundedReceiver<Result<AgentResponseEvent>>>
where
T: Into<UserMessageContent>,
{
log::info!("Thread::send called with model: {:?}", self.model.name());
let model = self.model().context("No language model configured")?;
log::info!("Thread::send called with model: {:?}", model.name());
self.advance_prompt_id();
let content = content.into_iter().map(Into::into).collect::<Vec<_>>();
@ -616,10 +619,10 @@ impl Thread {
fn run_turn(
&mut self,
cx: &mut Context<Self>,
) -> mpsc::UnboundedReceiver<Result<AgentResponseEvent>> {
) -> Result<mpsc::UnboundedReceiver<Result<AgentResponseEvent>>> {
self.cancel();
let model = self.model.clone();
let model = self.model.clone().context("No language model configured")?;
let (events_tx, events_rx) = mpsc::unbounded::<Result<AgentResponseEvent>>();
let event_stream = AgentResponseEventStream(events_tx);
let message_ix = self.messages.len().saturating_sub(1);
@ -637,7 +640,7 @@ impl Thread {
);
let request = this.update(cx, |this, cx| {
this.build_completion_request(completion_intent, cx)
})?;
})??;
log::info!("Calling model.stream_completion");
let mut events = model.stream_completion(request, cx).await?;
@ -729,7 +732,7 @@ impl Thread {
.ok();
}),
});
events_rx
Ok(events_rx)
}
pub fn build_system_message(&self) -> LanguageModelRequestMessage {
@ -917,7 +920,7 @@ impl Thread {
status: Some(acp::ToolCallStatus::InProgress),
..Default::default()
});
let supports_images = self.model.supports_images();
let supports_images = self.model().map_or(false, |model| model.supports_images());
let tool_result = tool.run(tool_use.input, tool_event_stream, cx);
log::info!("Running tool {}", tool_use.name);
Some(cx.foreground_executor().spawn(async move {
@ -1005,7 +1008,9 @@ impl Thread {
&self,
completion_intent: CompletionIntent,
cx: &mut App,
) -> LanguageModelRequest {
) -> Result<LanguageModelRequest> {
let model = self.model().context("No language model configured")?;
log::debug!("Building completion request");
log::debug!("Completion intent: {:?}", completion_intent);
log::debug!("Completion mode: {:?}", self.completion_mode);
@ -1021,9 +1026,7 @@ impl Thread {
Some(LanguageModelRequestTool {
name: tool_name,
description: tool.description().to_string(),
input_schema: tool
.input_schema(self.model.tool_input_format())
.log_err()?,
input_schema: tool.input_schema(model.tool_input_format()).log_err()?,
})
})
.collect()
@ -1042,20 +1045,22 @@ impl Thread {
tools,
tool_choice: None,
stop: Vec::new(),
temperature: AgentSettings::temperature_for_model(self.model(), cx),
temperature: AgentSettings::temperature_for_model(&model, cx),
thinking_allowed: true,
};
log::debug!("Completion request built successfully");
request
Ok(request)
}
fn tools<'a>(&'a self, cx: &'a App) -> Result<impl Iterator<Item = &'a Arc<dyn AnyAgentTool>>> {
let model = self.model().context("No language model configured")?;
let profile = AgentSettings::get_global(cx)
.profiles
.get(&self.profile_id)
.context("profile not found")?;
let provider_id = self.model.provider_id();
let provider_id = model.provider_id();
Ok(self
.tools