//! df-ai: AI 编排 — LLM Provider、Agent 协调、上下文管理、流式处理、工具注册

pub mod ai_tools;
// 声明式工具注册宏 `declare_tool!`(tool_registry 拆分第一步基础设施)。
// macro_rules + #[macro_export]:零新依赖,展开为等价 `register` 调用,与现有 48 工具并存。
// 试点:list_projects 已迁至声明式(commands/ai/tools/list_projects.rs),验证可行+零回归。
#[macro_use]
pub mod ai_tools_decl;
pub mod anthropic_compat;
pub mod anthropic_helpers;
pub mod context;
pub mod context_helpers;
pub mod memory_adapter;
// 多 Agent 协作调度中心(Phase 1 规则驱动, Phase 2 LLM 扩展)。
pub mod coordinator;
// 会话意图识别层(纯函数,不接入 agentic loop)。依据 docs/02-架构设计/构想审查/
// 意图识别层论证-2026-06-19.md。提供 recognize / tool_subset_for / suggested_model_tier。
// 待 Phase B+C 完成 + 模型模态管理落地后再接入 agentic loop。
pub mod git_worktree;
pub mod intent;
pub mod model_fetch;
// model_fetch 的纯逻辑子模块(URL 拼接 / 噪音过滤 / 响应反序列化),
// crate 内复用,private mod — 外部经 model_fetch 间接访问,无直接路径需求。
mod model_fetch_helpers;
pub mod model_probe;
// model_probe 的纯逻辑子模块(预设表加载 / 启发式推断 / 词素判定),
// crate 内复用,private mod — 外部经 model_probe 间接访问,无直接路径需求。
mod model_probe_helpers;
// 单对话并行多轮 Phase 0a · 0.8 plan_hint 纯函数(扩 intent::tool_subset_for 编排语义)。
// 依据 docs/02-架构设计/单对话并行多轮-Phase0落地路线图-2026-06-20.md 第 0.8 节。
// 纯函数(零 IO 零状态),Phase 1 接入主 loop,LLM 调度留 Phase 2。
pub mod plan_hint;
pub mod openai_compat;
pub mod openai_helpers;
// Phase 0 (B 路线): Plan-driven 规划骨架(维度 0.8 Plan/SubTask 结构 + 0.7 规划校验/Kahn 分层)。
// 纯函数模块(零 IO 零状态)。依据 docs/02-架构设计/单对话并行多轮-{设计,Phase0落地路线图}-2026-06-20.md。
// Phase 1(plan_hint 接入主 loop)/Phase 2(planning)/Phase 3(并行 execution) 接入后续。
pub mod planner;
// Phase 2: Plan DAG 分层执行器(骨架,PLAN_EXECUTION_ENABLED 门控默认关)。
// 按 Plan::to_layers 层间串行/层内并行调度子任务。
// 依据 docs/02-架构设计/单对话并行多轮-设计-2026-06-20.md。
pub mod persona;
pub mod plan_executor;
pub mod provider;
pub mod router;
// 流前重试退避对外复用。complete() 的 retry_with_backoff 仍 crate 内用,
// stream_recv/agentic 流前重试需复用 backoff_delay(jitter)+is_status_retryable(Fatal 分类)
// 避免重写退避/分类逻辑。改 pub mod 后对外仅暴露纯函数 + 常量。
pub mod retry;
pub mod sse_parser;
pub mod namespace_store;

use provider::LlmProvider;
use reqwest::Client;

// df-ai-core 直接暴露，供需要直接引用 trait crate 的下游（可选）。
pub use df_ai_core;

/// SW-260618-10: 构建 Provider 共用的 reqwest Client（OpenAI/Anthropic Provider::new DRY）。
///
/// connect_timeout 30s 防连接阶段静默 hang（网络静默断）；不设总 timeout——reqwest 的
/// `.timeout()` 会限制整个响应 body 时长，流式长生成任务会被误砍。读取阶段中途静默由上层
/// stream_llm 的 idle timeout 兜底。builder 失败回退 `Client::new()` 保可用（warn 日志）。
pub(crate) fn build_provider_client() -> Client {
    Client::builder()
        .connect_timeout(std::time::Duration::from_secs(30))
        .build()
        .unwrap_or_else(|e| {
            tracing::warn!("reqwest builder 失败，回退默认 client: {}", e);
            Client::new()
        })
}

/// 按 provider_type 构建 LLM Provider 实例（统一选择逻辑，消除调用方重复 match）
///
/// `anthropic` 协议走 AnthropicCompatProvider（GLM 订阅端点 / Claude 官方），
/// 其余（openai / glm / deepseek 等 OpenAI 兼容）走 OpenAICompatProvider。
/// 调用方（AI Chat 的 run_agentic_loop、df-nodes 的 AiNode）统一引用此工厂，
/// 新增 provider 只改这一处。
pub fn build_provider(
    provider_type: &str,
    base_url: &str,
    api_key: &str,
    model: &str,
) -> Box<dyn LlmProvider> {
    match provider_type {
        "anthropic" => Box::new(anthropic_compat::AnthropicCompatProvider::new(
            base_url, api_key, model,
        )),
        _ => Box::new(openai_compat::OpenAICompatProvider::new(
            base_url, api_key, model,
        )),
    }
}
