1
This commit is contained in:
112
server-rs/crates/platform-agent/src/puzzle_phase1_agent.rs
Normal file
112
server-rs/crates/platform-agent/src/puzzle_phase1_agent.rs
Normal file
@@ -0,0 +1,112 @@
|
||||
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",
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user