修复动作提示缓存缺失降级

角色资产工作流解析在 OSS 缓存未配置时返回默认提示词

补充无 OSS 缓存的 workflow 路由回归测试

同步后端契约文档说明
This commit is contained in:
2026-06-27 17:24:05 +08:00
parent 228d31db31
commit 8324911bbb
3 changed files with 54 additions and 3 deletions
+39
View File
@@ -690,6 +690,45 @@ mod tests {
assert_eq!(body["error"]["details"]["creationTypeId"], "rpg");
}
#[tokio::test]
async fn role_asset_workflow_returns_default_prompts_without_oss_cache() {
let app = build_router(AppState::new(AppConfig::default()).expect("state should build"));
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/api/runtime/custom-world/asset-studio/role/hero-01/workflow")
.header("content-type", "application/json")
.body(Body::from(
serde_json::json!({
"role": {
"id": "hero-01",
"name": "沈砺",
"title": "灰炬向导",
"role": "边路同行者",
"actionDescription": "持灯快步穿过灰烬街巷"
}
})
.to_string(),
))
.expect("workflow request should build"),
)
.await
.expect("workflow request should succeed");
assert_eq!(response.status(), StatusCode::OK);
let body = read_json_response(response).await;
assert_eq!(body["ok"], Value::Bool(true));
assert_eq!(body["cache"], Value::Null);
assert!(
body["workflow"]["animationPromptText"]
.as_str()
.unwrap_or_default()
.contains("持灯快步穿过灰烬街巷")
);
}
#[tokio::test]
async fn healthz_returns_standard_envelope_when_requested() {
let app = build_router(AppState::new(AppConfig::default()).expect("state should build"));
@@ -1124,9 +1124,13 @@ pub async fn resolve_role_asset_workflow(
})?;
let cache_scope_id = trim_optional_text(payload.cache_scope_id.as_deref());
let cache = load_workflow_cache(&state, character_id.as_str(), cache_scope_id.as_deref())
let cache = match load_workflow_cache(&state, character_id.as_str(), cache_scope_id.as_deref())
.await
.map_err(|error| character_animation_error_response(&request_context, error))?;
{
Ok(cache) => cache,
Err(error) if is_missing_oss_config_error(&error) => None,
Err(error) => return Err(character_animation_error_response(&request_context, error)),
};
let workflow = build_role_asset_workflow(payload.role, cache.as_ref());
Ok(json_success_body(
@@ -4133,6 +4137,14 @@ fn require_oss_client(state: &AppState) -> Result<&platform_oss::OssClient, AppE
})
}
fn is_missing_oss_config_error(error: &AppError) -> bool {
error.status_code() == StatusCode::SERVICE_UNAVAILABLE
&& error.details().is_some_and(|details| {
details.get("provider").and_then(Value::as_str) == Some("aliyun-oss")
&& details.get("reason").and_then(Value::as_str) == Some("OSS 未完成环境变量配置")
})
}
fn normalize_required_text(value: &str, fallback: &str) -> String {
let normalized = value
.trim()