blob: b60fc73882d1c19043da242b9d1d19c5283819c8 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
use super::*;
use maka_event_log::sessions::SessionMutation;
impl Owner {
pub async fn select_backend(&self, input: SelectBackend) -> Result<MetadataResult, String> {
let runs = self.runs.lock().await;
if runs.closing {
return Ok(MetadataResult::Rejected {
reason: Rejection::Closed,
});
}
if !self.owns(&input.session_id) {
return Ok(MetadataResult::Rejected {
reason: Rejection::SessionUnavailable,
});
}
let session = self.session(&input.session_id).await?;
if session.archived {
return Ok(MetadataResult::Rejected {
reason: Rejection::SessionUnavailable,
});
}
// Replaying the same preference is harmless even if a read marker or
// execution advanced the session revision in the meantime.
if session.configuration.backend.as_ref() == Some(&input.backend) {
return Ok(MetadataResult::Committed {
session: Box::new(crate::service::summary(self, session)),
});
}
let available = match &input.backend {
BackendPreference::Model {
connection_id,
model_id,
..
} => {
let public_guard = self.catalog.snapshot.read().await;
let snapshot = public_guard
.as_ref()
.map_err(|_| "agent_configuration_unavailable")?
.clone();
self.configuration
.catalog()
.await
.map_err(|_| "agent_configuration_unavailable")?
.connections
.iter()
.any(|row| {
row.connection_id == *connection_id
&& row.enabled
&& row.enabled_model_ids.contains(model_id)
&& maka_providers::definition(&row.provider, snapshot.clone()).is_ok()
})
}
BackendPreference::Executor { selection } => self
.settings
.executors
.iter()
.any(|entry| entry.name == selection.executor),
};
if !available {
return Ok(MetadataResult::Rejected {
reason: Rejection::ToolsUnavailable,
});
}
match self
.store
.update_session_metadata(
&input.session_id,
session.revision,
move |configuration: &mut SessionConfiguration| {
configuration.backend = Some(input.backend);
Ok(())
},
)
.await
.map_err(|_| "agent_preference_commit_unknown")?
{
SessionMutation::Committed(session) => Ok(MetadataResult::Committed {
session: Box::new(crate::service::summary(self, session)),
}),
SessionMutation::RevisionConflict { expected, actual } => {
Ok(MetadataResult::RevisionConflict { expected, actual })
}
}
}
pub async fn remembered_backend(
&self,
session: &str,
) -> Result<Option<BackendPreference>, String> {
// Old conversations predate the preference field. Their last admitted
// model is an exact identity to resolve, never a new global default.
let opening = self
.store
.latest_message_opening(session)
.await
.map_err(|_| "agent_history_unavailable")?;
Ok(opening.and_then(|opening| match opening.event.fact {
maka_agent_facts::event::Fact::InvocationOpened {
configuration: Some(configuration),
..
} => configuration.model.map(|model| BackendPreference::Model {
connection_id: model.connection_id,
model_id: model.model,
thinking_level: configuration.thinking_level,
}),
_ => None,
}))
}
}