113 lines
3.5 KiB
Rust
113 lines
3.5 KiB
Rust
use async_trait::async_trait;
|
|
|
|
use crate::{
|
|
callbacks::CreativeAgentCallbacks, error::PlatformAgentError,
|
|
function_agent::FunctionAgentLimits,
|
|
};
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
pub struct PuzzlePhase1AgentInput {
|
|
pub session_id: String,
|
|
pub user_text: String,
|
|
pub image_urls: Vec<String>,
|
|
pub limits: FunctionAgentLimits,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
pub struct PuzzlePhase1AgentOutput {
|
|
pub session_id: String,
|
|
pub model: String,
|
|
pub final_message: String,
|
|
pub tool_call_count: usize,
|
|
}
|
|
|
|
#[async_trait]
|
|
pub trait CreativeAgentExecutor: Send + Sync {
|
|
async fn run_puzzle_phase1(
|
|
&self,
|
|
input: PuzzlePhase1AgentInput,
|
|
callbacks: CreativeAgentCallbacks,
|
|
) -> Result<PuzzlePhase1AgentOutput, PlatformAgentError>;
|
|
}
|
|
|
|
#[derive(Clone, Debug, Default)]
|
|
pub struct MockLangChainRustAgentExecutor;
|
|
|
|
#[async_trait]
|
|
impl CreativeAgentExecutor for MockLangChainRustAgentExecutor {
|
|
async fn run_puzzle_phase1(
|
|
&self,
|
|
input: PuzzlePhase1AgentInput,
|
|
callbacks: CreativeAgentCallbacks,
|
|
) -> Result<PuzzlePhase1AgentOutput, PlatformAgentError> {
|
|
input.limits.validate()?;
|
|
if input.session_id.trim().is_empty() {
|
|
return Err(PlatformAgentError::InvalidInput(
|
|
"creative session_id 不能为空".to_string(),
|
|
));
|
|
}
|
|
if input.user_text.trim().is_empty() && input.image_urls.is_empty() {
|
|
return Err(PlatformAgentError::InvalidInput(
|
|
"创意 Agent 输入文本和图片不能同时为空".to_string(),
|
|
));
|
|
}
|
|
|
|
callbacks.stage("perceiving");
|
|
callbacks.stage("thinking");
|
|
callbacks.stage("remembering");
|
|
callbacks.stage("selecting_puzzle_template");
|
|
callbacks.stage("waiting_template_confirmation");
|
|
|
|
Ok(PuzzlePhase1AgentOutput {
|
|
session_id: input.session_id,
|
|
model: crate::apimart_gpt5_adapter::CREATIVE_AGENT_GPT5_MODEL.to_string(),
|
|
final_message: "已完成创意 Agent Phase 1 mock 执行,可进入模板确认。".to_string(),
|
|
tool_call_count: 0,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use super::*;
|
|
|
|
#[tokio::test]
|
|
async fn mock_executor_keeps_gpt5_model_and_emits_stages() {
|
|
let events = Arc::new(Mutex::new(Vec::new()));
|
|
let events_clone = events.clone();
|
|
let callbacks = CreativeAgentCallbacks::new(move |event| {
|
|
events_clone.lock().expect("events lock").push(event.label);
|
|
});
|
|
|
|
let output = MockLangChainRustAgentExecutor
|
|
.run_puzzle_phase1(
|
|
PuzzlePhase1AgentInput {
|
|
session_id: "creative-session-test".to_string(),
|
|
user_text: "做一个家庭纪念拼图".to_string(),
|
|
image_urls: vec!["https://example.com/ref.png".to_string()],
|
|
limits: FunctionAgentLimits::default(),
|
|
},
|
|
callbacks,
|
|
)
|
|
.await
|
|
.expect("mock executor should succeed");
|
|
|
|
assert_eq!(
|
|
output.model,
|
|
crate::apimart_gpt5_adapter::CREATIVE_AGENT_GPT5_MODEL
|
|
);
|
|
assert_eq!(
|
|
events.lock().expect("events lock").as_slice(),
|
|
[
|
|
"perceiving",
|
|
"thinking",
|
|
"remembering",
|
|
"selecting_puzzle_template",
|
|
"waiting_template_confirmation",
|
|
]
|
|
);
|
|
}
|
|
}
|