回退外部生成任务分支改动

恢复外部生成 worker 的 master 行为

恢复画布生成任务默认入队标识

移除 Agent 自定义任务标识入口
This commit is contained in:
2026-07-15 13:30:58 +08:00
parent 9ff8e0a297
commit 9a6bf8d86d
3 changed files with 15 additions and 147 deletions
@@ -12,7 +12,6 @@ use module_editor_agent::{
use platform_llm::LlmMessage;
use serde::Serialize;
use serde_json::{json, Value};
use sha2::{Digest, Sha256};
use shared_contracts::assets::{
EditorBackgroundMusicGenerateRequest, EditorSoundEffectGenerateRequest,
EditorVideoGenerateRequest,
@@ -57,7 +56,7 @@ use crate::editor_agent::utils::{
use crate::editor_agent::{context, display_args, reconcile};
use crate::editor_generation_config::EditorGenerationPricingConfig;
use crate::editor_generation_queue::{
enqueue_editor_generation_job_with_identity, EDITOR_BACKGROUND_MUSIC_GENERATION_JOB_KIND,
enqueue_editor_generation_job, EDITOR_BACKGROUND_MUSIC_GENERATION_JOB_KIND,
EDITOR_ICON_SPRITESHEET_GENERATION_JOB_KIND, EDITOR_IMAGE_EDIT_JOB_KIND,
EDITOR_IMAGE_GENERATION_JOB_KIND, EDITOR_SOUND_EFFECT_GENERATION_JOB_KIND,
EDITOR_VIDEO_GENERATION_JOB_KIND,
@@ -845,21 +844,15 @@ pub async fn confirm_editor_agent_tool_call(
AppError::from_status(axum::http::StatusCode::INTERNAL_SERVER_ERROR)
.with_details(json!({"message": format!("failed to serialize tool payload: {error}")}))
})?;
let (job_id, dedupe_key) = editor_agent_tool_job_identity(
conversation.conversation_id.as_str(),
message_id,
tool_name.as_str(),
);
let job = enqueue_editor_generation_job_with_identity(
let job = enqueue_editor_generation_job(
&state,
&request_context,
conversation.owner_user_id.as_str(),
job_kind,
conversation.project_id.clone(),
request_label,
u64::from(price_mud_points),
&payload,
job_id,
dedupe_key,
)
.await?;
let message = &mut document.messages[message_id];
@@ -881,16 +874,6 @@ fn parse_confirm_tool_args<T: serde::de::DeserializeOwned>(value: &Value) -> Res
.map_err(|error| editor_agent_bad_request(format!("invalid tool call args: {error}")))
}
fn editor_agent_tool_job_identity(
conversation_id: &str,
message_id: usize,
tool_name: &str,
) -> (String, String) {
let dedupe_key = format!("editor-agent:{conversation_id}:{message_id}:{tool_name}");
let digest = Sha256::digest(dedupe_key.as_bytes());
(format!("task-editor-agent-{digest:x}"), dedupe_key)
}
async fn load_editor_agent_project(
state: &AppState,
conversation: &EditorAgentConversationRecord,
@@ -47,41 +47,12 @@ where
T: Serialize,
{
let job_id = build_prefixed_uuid_id("task-");
enqueue_editor_generation_job_with_identity(
state,
owner_user_id,
job_kind,
source_entity_id,
request_label,
price_mud_points,
payload,
job_id.clone(),
format!("editor-canvas:{job_kind}:{job_id}"),
)
.await
}
#[allow(clippy::too_many_arguments)]
pub(crate) async fn enqueue_editor_generation_job_with_identity<T>(
state: &AppState,
owner_user_id: &str,
job_kind: &str,
source_entity_id: impl Into<String>,
request_label: impl Into<String>,
price_mud_points: u64,
payload: &T,
job_id: String,
dedupe_key: String,
) -> Result<ExternalGenerationJobRecord, AppError>
where
T: Serialize,
{
let request_payload_json = serialize_editor_generation_job_payload(payload)?;
let now_micros = current_utc_micros();
state
.spacetime_client()
.enqueue_external_generation_job(ExternalGenerationJobEnqueueRecordInput {
dedupe_key,
dedupe_key: format!("editor-canvas:{job_kind}:{job_id}"),
job_id,
job_kind: job_kind.to_string(),
owner_user_id: owner_user_id.to_string(),
@@ -675,9 +675,7 @@ async fn process_external_generation_job_once(
)
.await
{
Ok(result) => {
complete_editor_generation_job(&state, &worker_id, &job, result.0).await
}
Ok(_) => complete_editor_generation_job(&state, &worker_id, &job).await,
Err(error) => {
let message = error.body_text();
fail_job(&state, &worker_id, &job, message.clone()).await?;
@@ -705,9 +703,7 @@ async fn process_external_generation_job_once(
)
.await
{
Ok(result) => {
complete_editor_generation_job(&state, &worker_id, &job, result.0).await
}
Ok(_) => complete_editor_generation_job(&state, &worker_id, &job).await,
Err(error) => {
let message = error.body_text();
fail_job(&state, &worker_id, &job, message.clone()).await?;
@@ -736,9 +732,7 @@ async fn process_external_generation_job_once(
)
.await
{
Ok(result) => {
complete_editor_generation_job(&state, &worker_id, &job, result.0).await
}
Ok(_) => complete_editor_generation_job(&state, &worker_id, &job).await,
Err(error) => {
let message = error.body_text();
fail_job(&state, &worker_id, &job, message.clone()).await?;
@@ -839,9 +833,7 @@ async fn process_external_generation_job_once(
)
.await
{
Ok(result) => {
complete_editor_generation_job(&state, &worker_id, &job, result.0).await
}
Ok(_) => complete_editor_generation_job(&state, &worker_id, &job).await,
Err(response) => {
let message = response_error_message(response).await;
fail_job(&state, &worker_id, &job, message.clone()).await?;
@@ -870,9 +862,7 @@ async fn process_external_generation_job_once(
)
.await
{
Ok(result) => {
complete_editor_generation_job(&state, &worker_id, &job, result.0).await
}
Ok(_) => complete_editor_generation_job(&state, &worker_id, &job).await,
Err(response) => {
let message = response_error_message(response).await;
fail_job(&state, &worker_id, &job, message.clone()).await?;
@@ -901,9 +891,7 @@ async fn process_external_generation_job_once(
)
.await
{
Ok(result) => {
complete_editor_generation_job(&state, &worker_id, &job, result.0).await
}
Ok(_) => complete_editor_generation_job(&state, &worker_id, &job).await,
Err(response) => {
let message = response_error_message(response).await;
fail_job(&state, &worker_id, &job, message.clone()).await?;
@@ -932,9 +920,7 @@ async fn process_external_generation_job_once(
)
.await
{
Ok(result) => {
complete_editor_generation_job(&state, &worker_id, &job, result.0).await
}
Ok(_) => complete_editor_generation_job(&state, &worker_id, &job).await,
Err(response) => {
let message = response_error_message(response).await;
fail_job(&state, &worker_id, &job, message.clone()).await?;
@@ -1039,9 +1025,7 @@ async fn complete_editor_generation_job(
state: &AppState,
worker_id: &str,
job: &ExternalGenerationJobRecord,
result: serde_json::Value,
) -> Result<(), String> {
let result = compact_editor_generation_result(result);
complete_job(
state,
worker_id,
@@ -1050,7 +1034,6 @@ async fn complete_editor_generation_job(
json!({
"sourceModule": job.source_module.clone(),
"sourceEntityId": job.source_entity_id.clone(),
"response": result,
})
.to_string(),
),
@@ -1058,26 +1041,6 @@ async fn complete_editor_generation_job(
.await
}
fn compact_editor_generation_result(mut result: serde_json::Value) -> serde_json::Value {
let Some(object) = result.as_object_mut() else {
return result;
};
object.remove("project");
object.remove("asset");
object.remove("spritesheetAsset");
for field in ["resource", "spritesheetResource"] {
let Some(resource) = object
.get_mut(field)
.and_then(serde_json::Value::as_object_mut)
else {
continue;
};
resource
.retain(|key, _| matches!(key.as_str(), "resourceId" | "objectKey" | "assetObjectId"));
}
result
}
async fn complete_editor_generation_job_with_response(
state: &AppState,
worker_id: &str,
@@ -1097,14 +1060,11 @@ fn editor_generation_result_payload_json(
job: &ExternalGenerationJobRecord,
response: &Value,
) -> String {
let warning = extract_editor_generation_slice_warning(response);
let response = compact_editor_generation_spritesheet_result(response);
let mut payload = json!({
"sourceModule": job.source_module.clone(),
"sourceEntityId": job.source_entity_id.clone(),
"response": response,
});
if let Some(warning) = warning
if let Some(warning) = extract_editor_generation_slice_warning(response)
&& let Some(object) = payload.as_object_mut()
{
object.insert("warning".to_string(), warning);
@@ -1112,30 +1072,6 @@ fn editor_generation_result_payload_json(
payload.to_string()
}
fn compact_editor_generation_spritesheet_result(response: &Value) -> Value {
let data = response.get("data").unwrap_or(response);
let mut result = serde_json::Map::new();
for field in [
"spritesheetImageSrc",
"spritesheetWidth",
"spritesheetHeight",
"taskId",
] {
if let Some(value) = data.get(field) {
result.insert(field.to_string(), value.clone());
}
}
if let Some(resource) = data.get("spritesheetResource") {
let resource = compact_editor_generation_result(json!({
"spritesheetResource": resource,
}));
if let Some(resource) = resource.get("spritesheetResource") {
result.insert("spritesheetResource".to_string(), resource.clone());
}
}
Value::Object(result)
}
fn extract_editor_generation_slice_warning(response: &Value) -> Option<Value> {
let data = response.get("data").unwrap_or(response);
let warning = data.get("sliceWarning")?;
@@ -1398,16 +1334,7 @@ mod tests {
fn editor_generation_result_payload_keeps_only_lightweight_slice_warning() {
let job = external_generation_job_record_fixture(Some("lease-1"));
let response = json!({
"spritesheetImageSrc": "/api/assets/object/spritesheet.png",
"spritesheetWidth": 512,
"spritesheetHeight": 512,
"taskId": "task-1",
"spritesheetResource": {
"resourceId": "resource-1",
"objectKey": "spritesheet.png",
"assetObjectId": "asset-object-1",
"imageSrc": "data:image/png;base64,SHOULD_NOT_PERSIST"
},
"spritesheetImageSrc": "data:image/png;base64,SHOULD_NOT_PERSIST",
"iconImageSrcs": [{"imageSrc": "data:image/png;base64,SHOULD_NOT_PERSIST"}],
"sliceWarning": {
"code": "insufficient-connected-components",
@@ -1421,20 +1348,6 @@ mod tests {
assert_eq!(payload["sourceModule"], json!("puzzle"));
assert_eq!(payload["sourceEntityId"], json!("session-1:puzzle-level-1"));
assert_eq!(
payload["response"],
json!({
"spritesheetImageSrc": "/api/assets/object/spritesheet.png",
"spritesheetWidth": 512,
"spritesheetHeight": 512,
"taskId": "task-1",
"spritesheetResource": {
"resourceId": "resource-1",
"objectKey": "spritesheet.png",
"assetObjectId": "asset-object-1"
}
})
);
assert_eq!(
payload["warning"],
json!({
@@ -1442,7 +1355,8 @@ mod tests {
"reason": "连通域数量不足"
})
);
assert!(!payload.to_string().contains("data:image"));
assert!(payload.get("spritesheetImageSrc").is_none());
assert!(payload.get("iconImageSrcs").is_none());
}
#[test]