feat(ai): unify model discovery and effort handling

This commit is contained in:
Guoyu Su authored and GitHub committed 2026-07-28 21:37:55 +08:00
1 parent c54b95e274
commit c7e7b7c9d9
41 files changed
+3291 -634

No files matched your search

+2
View File
@@ -603,6 +603,7 @@ async fn main() {
.route("/ai/config", post(routes::ai::save_ai_config).get(routes::ai::load_ai_config))
.route("/ai/provider-config", post(routes::ai::save_ai_provider_config))
.route("/ai/provider-configs", get(routes::ai::load_ai_provider_configs))
.route("/ai/chat-selection", post(routes::ai::save_ai_chat_selection).get(routes::ai::load_ai_chat_selection))
.route("/ai/configs", post(routes::ai::save_ai_configs).get(routes::ai::load_ai_configs))
.route("/ai/default-config", post(routes::ai::set_default_ai_config))
.route("/ai/config-item", post(routes::ai::save_ai_config_item))
@@ -616,6 +617,7 @@ async fn main() {
.route("/ai/cancel-stream", post(routes::ai::ai_cancel_stream))
.route("/ai/test-connection", post(routes::ai::ai_test_connection))
.route("/ai/models", post(routes::ai::ai_list_models))
.route("/ai/model-effort", post(routes::ai::ai_resolve_model_effort))
// Prompt templates
.route(
"/prompt-templates",
+39 -2
View File
@@ -10,8 +10,8 @@ use serde::Deserialize;
use dbx_core::agent_events::AgentEvent;
use dbx_core::agent_loop::{run_agent_loop, AgentLoopContext};
use dbx_core::ai::{
AiCompletionRequest, AiConfig, AiConfigItem, AiConversation, AiModelInfo, AiProvider, AiStreamChunk,
AiTestConnectionResult,
AiChatSelectionState, AiCompletionRequest, AiConfig, AiConfigItem, AiConversation, AiEffortCapability, AiModelInfo,
AiProvider, AiStreamChunk, AiTestConnectionResult,
};
use dbx_core::models::connection::DatabaseType;
@@ -66,6 +66,19 @@ pub struct AiListModelsRequest {
pub config: AiConfig,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AiResolveModelEffortRequest {
pub config: AiConfig,
pub model_id: String,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SaveAiChatSelectionRequest {
pub selection: AiChatSelectionState,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AiCancelStreamRequest {
@@ -149,6 +162,21 @@ pub async fn load_ai_provider_configs(
Ok(Json(configs))
}
pub async fn save_ai_chat_selection(
State(state): State<Arc<WebState>>,
Json(body): Json<SaveAiChatSelectionRequest>,
) -> Result<Json<()>, AppError> {
state.app.storage.save_ai_chat_selection(&body.selection).await.map_err(AppError::from)?;
Ok(Json(()))
}
pub async fn load_ai_chat_selection(
State(state): State<Arc<WebState>>,
) -> Result<Json<Option<AiChatSelectionState>>, AppError> {
let selection = state.app.storage.load_ai_chat_selection().await.map_err(AppError::from)?;
Ok(Json(selection))
}
// ---------------------------------------------------------------------------
// Multi-config
// ---------------------------------------------------------------------------
@@ -265,6 +293,14 @@ pub async fn ai_list_models(Json(body): Json<AiListModelsRequest>) -> Result<Jso
Ok(Json(result))
}
pub async fn ai_resolve_model_effort(
Json(body): Json<AiResolveModelEffortRequest>,
) -> Result<Json<AiEffortCapability>, AppError> {
reject_web_unsupported_ai_provider(&body.config)?;
let result = dbx_core::ai::resolve_model_effort_core(&body.config, &body.model_id).await.map_err(AppError::from)?;
Ok(Json(result))
}
// ---------------------------------------------------------------------------
// AI cancel stream
// ---------------------------------------------------------------------------
@@ -437,6 +473,7 @@ mod tests {
proxy_url: String::new(),
enable_thinking: true,
reasoning_level: AiReasoningLevel::Default,
runtime_effort: None,
context_window: None,
codex_cli_path: None,
codex_cli_env: Default::default(),