use async_trait::async_trait;
use modkit_db::secure::DBRunner;
use modkit_macros::domain_model;
use modkit_security::AccessScope;
use uuid::Uuid;
use crate::domain::error::DomainError;
use crate::infra::db::entity::chat_turn::{Model as TurnModel, TurnState};
#[domain_model]
pub struct CreateTurnParams {
pub id: Uuid,
pub tenant_id: Uuid,
pub chat_id: Uuid,
pub request_id: Uuid,
pub requester_type: String,
pub requester_user_id: Option<Uuid>,
pub reserve_tokens: Option<i64>,
pub max_output_tokens_applied: Option<i32>,
pub reserved_credits_micro: Option<i64>,
pub policy_version_applied: Option<i64>,
pub effective_model: Option<String>,
pub minimal_generation_floor_applied: Option<i32>,
pub web_search_enabled: bool,
}
#[domain_model]
#[allow(clippy::struct_field_names, dead_code)]
pub struct CasCompleteParams {
pub turn_id: Uuid,
pub assistant_message_id: Uuid,
pub provider_response_id: Option<String>,
}
#[domain_model]
pub struct CasTerminalParams {
pub turn_id: Uuid,
pub state: TurnState,
pub error_code: Option<String>,
pub error_detail: Option<String>,
pub assistant_message_id: Option<Uuid>,
pub provider_response_id: Option<String>,
}
#[domain_model]
pub struct UpdatePreflightParams {
pub turn_id: Uuid,
pub reserve_tokens: i64,
pub max_output_tokens_applied: i32,
pub reserved_credits_micro: i64,
pub policy_version_applied: i64,
pub effective_model: String,
pub minimal_generation_floor_applied: i32,
}
#[domain_model]
#[derive(Debug, Clone, Copy)]
pub enum ToolCallType {
WebSearch,
CodeInterpreter,
}
#[async_trait]
#[allow(dead_code)]
pub trait TurnRepository: Send + Sync {
async fn create_turn<C: DBRunner>(
&self,
runner: &C,
scope: &AccessScope,
params: CreateTurnParams,
) -> Result<TurnModel, DomainError>;
async fn find_by_chat_and_request_id<C: DBRunner>(
&self,
runner: &C,
scope: &AccessScope,
chat_id: Uuid,
request_id: Uuid,
) -> Result<Option<TurnModel>, DomainError>;
async fn find_running_by_chat_id<C: DBRunner>(
&self,
runner: &C,
scope: &AccessScope,
chat_id: Uuid,
) -> Result<Option<TurnModel>, DomainError>;
async fn cas_update_state<C: DBRunner>(
&self,
runner: &C,
scope: &AccessScope,
params: CasTerminalParams,
) -> Result<u64, DomainError>;
async fn cas_update_completed<C: DBRunner>(
&self,
runner: &C,
scope: &AccessScope,
params: CasCompleteParams,
) -> Result<u64, DomainError>;
async fn set_assistant_message_id<C: DBRunner>(
&self,
runner: &C,
scope: &AccessScope,
turn_id: Uuid,
assistant_message_id: Uuid,
) -> Result<(), DomainError>;
async fn soft_delete<C: DBRunner>(
&self,
runner: &C,
scope: &AccessScope,
turn_id: Uuid,
replaced_by_request_id: Option<Uuid>,
) -> Result<(), DomainError>;
async fn find_latest_turn<C: DBRunner>(
&self,
runner: &C,
scope: &AccessScope,
chat_id: Uuid,
) -> Result<Option<TurnModel>, DomainError>;
async fn update_progress_at<C: DBRunner>(
&self,
runner: &C,
scope: &AccessScope,
turn_id: Uuid,
) -> Result<u64, DomainError>;
async fn find_orphan_candidates<C: DBRunner>(
&self,
runner: &C,
timeout_secs: u64,
limit: u32,
) -> Result<Vec<TurnModel>, DomainError>;
async fn cas_finalize_orphan<C: DBRunner>(
&self,
runner: &C,
turn_id: Uuid,
timeout_secs: u64,
) -> Result<u64, DomainError>;
async fn find_latest_for_update<C: DBRunner>(
&self,
runner: &C,
scope: &AccessScope,
chat_id: Uuid,
) -> Result<Option<TurnModel>, DomainError>;
async fn update_preflight_fields<C: DBRunner>(
&self,
runner: &C,
scope: &AccessScope,
params: UpdatePreflightParams,
) -> Result<u64, DomainError>;
async fn increment_tool_calls<C: DBRunner>(
&self,
runner: &C,
scope: &AccessScope,
turn_id: Uuid,
tool: ToolCallType,
) -> Result<(), DomainError>;
}