清理策划运行时无锁包装入口

删除无锁 tool-plan request builder wrapper

删除 approval pending 与 submit input parser wrapper

测试改为显式持锁调用 locked 实现及底层严格解析器
This commit is contained in:
2026-08-31 12:50:27 +00:00
parent d7fc4c5b6f
commit bc4aea627f
4 changed files with 117 additions and 125 deletions
@@ -715,36 +715,6 @@ fn build_game_creator_agent_background_tool_plan_request_at(
))
}
pub(in crate::agent) fn build_game_creator_agent_background_tool_plan_request(
root: &Path,
agent_id: &str,
session_id: &str,
run_id: &str,
task: &str,
observations: &[AgentRuntimeToolObservation],
loop_index: usize,
) -> Result<
(
GameCreatorLlmConfig,
String,
LlmRunRequest,
String,
AgentRuntimeToolPlanRequestSnapshot,
),
String,
> {
build_game_creator_agent_background_tool_plan_request_at(
root,
None,
agent_id,
session_id,
run_id,
task,
observations,
loop_index,
)
}
pub(in crate::agent) fn build_game_creator_agent_background_tool_plan_request_locked(
root: &Path,
project_lock: &ProjectWriteLock,
@@ -972,17 +942,20 @@ mod tests {
use crate::{update_manifest_task_status_at, GameCreationAppTaskStatus};
use super::{
acquire_game_creator_agent_provider_plan_project_write_lock_with_wait,
agent_runtime_root_source_at, bind_game_creator_agent_runtime_run_profile_at,
build_game_creator_agent_background_final_reply_request,
build_game_creator_agent_background_tool_plan_request,
build_game_creator_agent_background_tool_plan_request_locked,
game_creator_agent_context_preload_notice,
game_creator_agent_runtime_run_profile_binding_path,
game_creator_project_supervisor_chat_system_prompt, init_local_game_project_at,
new_game_creation_app_seed_tasks, provider_command_exec_contract,
provider_command_start_contract, render_relaxed_autonomous_manifest_ready_task_background_prompt,
provider_command_start_contract,
render_relaxed_autonomous_manifest_ready_task_background_prompt,
required_runtime_prompt_section, start_game_creator_agent_runtime_task_at,
AgentRuntimeGoalContractAcceptanceNodeDraft, AgentRuntimeGoalContractDraft,
AgentRuntimeTaskLink, AgentRuntimeToolObservation, AgentRuntimeToolPlan,
AgentRuntimeToolPlanRequestSnapshot, GameCreatorLlmConfig,
AGENT_RUNTIME_AUTONOMOUS_PRE_MUTATION_LOOP_LIMIT,
AGENT_RUNTIME_COMPLETION_BLOCKER_TOOL_PLAN_PROTOCOL,
AGENT_RUNTIME_PLAN_AUTONOMOUS_PROFILE_UNSUPPORTED_KIND,
@@ -996,6 +969,40 @@ mod tests {
RUNTIME_PROMPT_SUPERVISOR_CHAT_COMPOSITION,
};
fn build_game_creator_agent_background_tool_plan_request_for_test(
root: &std::path::Path,
agent_id: &str,
session_id: &str,
run_id: &str,
task: &str,
observations: &[AgentRuntimeToolObservation],
loop_index: usize,
) -> Result<
(
GameCreatorLlmConfig,
String,
platform_llm::LlmRunRequest,
String,
AgentRuntimeToolPlanRequestSnapshot,
),
String,
> {
let lock = acquire_game_creator_agent_provider_plan_project_write_lock_with_wait(
root,
"test.provider_request.build.tool_plan",
)?;
build_game_creator_agent_background_tool_plan_request_locked(
root,
&lock,
agent_id,
session_id,
run_id,
task,
observations,
loop_index,
)
}
fn native_input_required_fields(
request: &platform_llm::LlmRunRequest,
tool: &str,
@@ -1066,7 +1073,7 @@ mod tests {
summary: "结构化计划更新被 Runtime 拒绝".to_string(),
detail: Some("计划状态回退".to_string()),
};
let (_, _, request, _, _) = build_game_creator_agent_background_tool_plan_request(
let (_, _, request, _, _) = build_game_creator_agent_background_tool_plan_request_for_test(
&root,
&state.agent_id,
&state.session_id,
@@ -1155,16 +1162,17 @@ mod tests {
// Relaxed orchestration does not convert an idle planning counter into
// a tool-removal gate; the Provider remains free to choose its next
// action.
let (_, _, baseline, _, _) = build_game_creator_agent_background_tool_plan_request(
&root,
&state.agent_id,
&state.session_id,
&state.run_id,
&state.current_task,
&[],
1,
)
.expect("build baseline request");
let (_, _, baseline, _, _) =
build_game_creator_agent_background_tool_plan_request_for_test(
&root,
&state.agent_id,
&state.session_id,
&state.run_id,
&state.current_task,
&[],
1,
)
.expect("build baseline request");
assert!(baseline
.function_tools
.iter()
@@ -1175,7 +1183,7 @@ mod tests {
crate::agent::write_game_creator_agent_runtime_state(&root, &idle_state)
.expect("persist idle rounds");
let (_, _, request, _, _) = build_game_creator_agent_background_tool_plan_request(
let (_, _, request, _, _) = build_game_creator_agent_background_tool_plan_request_for_test(
&root,
&state.agent_id,
&state.session_id,
@@ -1256,7 +1264,7 @@ mod tests {
vec!["交付当前 manifest task".to_string()],
)
.expect("start autonomous ready child task");
let (_, _, request, _, _) = build_game_creator_agent_background_tool_plan_request(
let (_, _, request, _, _) = build_game_creator_agent_background_tool_plan_request_for_test(
&root,
agent_id,
&state.session_id,
@@ -1506,7 +1514,7 @@ mod tests {
vec!["冻结 Goal Contract".to_string()],
)
.expect("start trusted root");
let (_, _, request, _, _) = build_game_creator_agent_background_tool_plan_request(
let (_, _, request, _, _) = build_game_creator_agent_background_tool_plan_request_for_test(
&root,
&state.agent_id,
&state.session_id,
@@ -1566,7 +1574,7 @@ mod tests {
)
.expect("start plan root");
let (_, _, first, _, _) = build_game_creator_agent_background_tool_plan_request(
let (_, _, first, _, _) = build_game_creator_agent_background_tool_plan_request_for_test(
&root,
&state.agent_id,
&state.session_id,
@@ -1633,7 +1641,7 @@ mod tests {
},
)
.expect("freeze plan contract");
let (_, _, later, _, _) = build_game_creator_agent_background_tool_plan_request(
let (_, _, later, _, _) = build_game_creator_agent_background_tool_plan_request_for_test(
&root,
&state.agent_id,
&state.session_id,
@@ -1719,7 +1727,7 @@ mod tests {
)
.expect("start supervisor runtime state");
let (_, _, supervisor_request, _, _) =
build_game_creator_agent_background_tool_plan_request(
build_game_creator_agent_background_tool_plan_request_for_test(
&root,
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
&supervisor_state.session_id,
@@ -1865,16 +1873,17 @@ mod tests {
vec!["核对普通说明".to_string()],
)
.expect("start ordinary runtime state");
let (_, _, ordinary_request, _, _) = build_game_creator_agent_background_tool_plan_request(
&root,
"code-prototype",
&ordinary_state.session_id,
&ordinary_state.run_id,
&ordinary_state.current_task,
&[],
0,
)
.expect("build ordinary planning request");
let (_, _, ordinary_request, _, _) =
build_game_creator_agent_background_tool_plan_request_for_test(
&root,
"code-prototype",
&ordinary_state.session_id,
&ordinary_state.run_id,
&ordinary_state.current_task,
&[],
0,
)
.expect("build ordinary planning request");
assert!(ordinary_request.messages[0]
.content
.contains("你正在使用 Genarrative AI 游戏创作多智能体 Runtime"));
@@ -1989,16 +1998,17 @@ mod tests {
vec!["读取需求并准备澄清".to_string()],
)
.expect("start planning child");
let (_, _, planning_request, _, _) = build_game_creator_agent_background_tool_plan_request(
&root,
GAME_CREATOR_PROJECT_PLANNING_AGENT_ID,
&planning_state.session_id,
&planning_state.run_id,
&planning_state.current_task,
&[],
0,
)
.expect("build planning request");
let (_, _, planning_request, _, _) =
build_game_creator_agent_background_tool_plan_request_for_test(
&root,
GAME_CREATOR_PROJECT_PLANNING_AGENT_ID,
&planning_state.session_id,
&planning_state.run_id,
&planning_state.current_task,
&[],
0,
)
.expect("build planning request");
let planning_system_prompt = &planning_request.messages[0].content;
let planning_brief_marker = "你是“立项策划 Agent”(`agentId=project-planning`";
assert!(planning_system_prompt.contains(planning_brief_marker));
@@ -2074,7 +2084,7 @@ mod tests {
)
.expect("start supervisor");
let (_, _, supervisor_request, _, _) =
build_game_creator_agent_background_tool_plan_request(
build_game_creator_agent_background_tool_plan_request_for_test(
&root,
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
&supervisor_state.session_id,
@@ -2183,7 +2193,7 @@ mod tests {
},
];
let (_, _, request, _, request_snapshot) =
build_game_creator_agent_background_tool_plan_request(
build_game_creator_agent_background_tool_plan_request_for_test(
&root,
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
&state.session_id,
@@ -2209,7 +2219,7 @@ mod tests {
),
});
let (_, _, _, _, settled_request_snapshot) =
build_game_creator_agent_background_tool_plan_request(
build_game_creator_agent_background_tool_plan_request_for_test(
&root,
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
&state.session_id,
@@ -216,23 +216,6 @@ pub(crate) fn pending_matches_receipt(
/// Construct the independent planning pending projection after an external
/// acceptance gate has succeeded. M1C-1 does not decide whether the gate
/// passed; the caller must supply that fact and the exact GDD identity.
pub(crate) fn create_plan_gdd_approval_pending_at(
root: &Path,
gdd: &PlanGddV1,
) -> Result<(), PlanningStorageError> {
if !crate::config::game_creator_planning_capability_enabled()
.map_err(|error| approval_error("PLAN_CAPABILITY_DISABLED", error))?
{
return Err(approval_error(
"PLAN_CAPABILITY_DISABLED",
"立项策划能力当前已停用",
));
}
let _lock = acquire_project_write_lock(root, "planning.approval-pending.create")
.map_err(|error| approval_error("PLAN_DURABILITY_FAILED", error))?;
create_plan_gdd_approval_pending_locked(root, gdd)
}
pub(crate) fn create_plan_gdd_approval_pending_locked(
root: &Path,
gdd: &PlanGddV1,
@@ -2712,18 +2712,6 @@ pub(crate) fn canonical_plan_submit_gdd_input_bytes(
Ok(bytes)
}
pub(crate) fn parse_plan_submit_gdd_input_bytes(
bytes: &[u8],
) -> Result<PlanSubmitGddInputV1, PlanningStorageError> {
let value = parse_strict_canonical::<PlanSubmitGddInputV1>(
bytes,
"plan.submit_gdd input",
PLAN_GDD_MAX_BYTES,
)?;
validate_plan_submit_gdd_input(&value)?;
Ok(value)
}
pub(crate) fn validate_plan_gdd_chain(values: &[PlanGddV1]) -> Result<(), PlanningStorageError> {
if values.len() > PLAN_MAX_VERSIONS as usize {
return Err(PlanningStorageError::new(
@@ -5067,22 +5055,23 @@ mod tests {
fn submit_input_has_strict_canonical_parser_and_runtime_field_boundary() {
let value = golden_submit_input();
let bytes = canonical_plan_submit_gdd_input_bytes(&value).expect("submit input bytes");
assert_eq!(
parse_plan_submit_gdd_input_bytes(&bytes).expect("parse input"),
value
);
let parse = |bytes: &[u8]| -> Result<PlanSubmitGddInputV1, PlanningStorageError> {
let value = parse_strict_canonical::<PlanSubmitGddInputV1>(
bytes,
"plan.submit_gdd input",
PLAN_GDD_MAX_BYTES,
)?;
validate_plan_submit_gdd_input(&value)?;
Ok(value)
};
assert_eq!(parse(&bytes).expect("parse input"), value);
let mut newline = bytes.clone();
newline.push(b'\n');
assert_eq!(
parse_plan_submit_gdd_input_bytes(&newline)
.unwrap_err()
.code(),
"PLAN_NON_CANONICAL_BYTES"
);
assert_eq!(parse(&newline).unwrap_err().code(), "PLAN_NON_CANONICAL_BYTES");
let mut object = serde_json::from_slice::<serde_json::Value>(&bytes).expect("input json");
object["projectId"] = serde_json::Value::String("forged-project".to_string());
let forged = serde_json::to_vec(&object).expect("forged input");
assert!(parse_plan_submit_gdd_input_bytes(&forged).is_err());
assert!(parse(&forged).is_err());
}
#[test]
@@ -1896,6 +1896,15 @@ mod tests {
use std::fs;
use std::path::PathBuf;
fn create_plan_gdd_approval_pending_for_test(
root: &std::path::Path,
gdd: &PlanGddV1,
) -> Result<(), PlanningStorageError> {
let _lock = acquire_project_write_lock(root, "test.planning.approval-pending.create")
.map_err(|error| PlanningStorageError::new("PLAN_DURABILITY_FAILED", error))?;
create_plan_gdd_approval_pending_locked(root, gdd)
}
fn valid_input() -> PlanSubmitGddInputV1 {
PlanSubmitGddInputV1 {
schema_version: PLAN_SUBMIT_INPUT_SCHEMA.to_string(),
@@ -3628,7 +3637,7 @@ mod tests {
.expect("read submitted GDD")
.pop()
.expect("GDD exists");
create_plan_gdd_approval_pending_at(&root, &gdd).expect("create approval pending");
create_plan_gdd_approval_pending_for_test(&root, &gdd).expect("create approval pending");
let decision_input = approval_input(
&gdd,
"approve",
@@ -3654,13 +3663,13 @@ mod tests {
.pop()
.expect("GDD exists");
create_plan_gdd_approval_pending_at(&root, &gdd).expect("create approval pending");
create_plan_gdd_approval_pending_for_test(&root, &gdd).expect("create approval pending");
let pending = read_plan_gdd_approval_pending_locked(&root)
.expect("read approval pending")
.expect("pending exists");
assert_eq!(pending.status, "awaiting_decision");
// Recreating the exact card is an idempotent replay.
create_plan_gdd_approval_pending_at(&root, &gdd).expect("replay approval pending");
create_plan_gdd_approval_pending_for_test(&root, &gdd).expect("replay approval pending");
let mut forged_next = gdd.clone();
forged_next.version = 2;
@@ -3669,7 +3678,7 @@ mod tests {
"gdd-approval-00000000-0000-4000-8000-000000000003".to_string();
forged_next.action_fingerprint = "4".repeat(64);
forged_next.fingerprint = plan_gdd_fingerprint(&forged_next).expect("next fingerprint");
let stale = create_plan_gdd_approval_pending_at(&root, &forged_next)
let stale = create_plan_gdd_approval_pending_for_test(&root, &forged_next)
.expect_err("a non-latest GDD cannot receive an approval card");
assert_eq!(stale.code(), "PLAN_STALE_APPROVAL");
@@ -3684,7 +3693,7 @@ mod tests {
)
.expect("commit approval receipt");
assert_eq!(decision.outcome, "committed");
let after_receipt = create_plan_gdd_approval_pending_at(&root, &gdd)
let after_receipt = create_plan_gdd_approval_pending_for_test(&root, &gdd)
.expect_err("a receipt must close awaiting_decision recreation");
assert_eq!(after_receipt.code(), "PLAN_STALE_APPROVAL");
cleanup_fixture(root);
@@ -3698,7 +3707,7 @@ mod tests {
.expect("read submitted GDD")
.pop()
.expect("GDD exists");
create_plan_gdd_approval_pending_at(&root, &gdd).expect("create approval pending");
create_plan_gdd_approval_pending_for_test(&root, &gdd).expect("create approval pending");
let task_path =
game_creator_agent_runtime_task_path(&root, GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID);
@@ -3738,7 +3747,7 @@ mod tests {
.expect("read submitted GDD")
.pop()
.expect("GDD exists");
create_plan_gdd_approval_pending_at(&root, &gdd).expect("create approval pending");
create_plan_gdd_approval_pending_for_test(&root, &gdd).expect("create approval pending");
let _config_guard = crate::tests::write_test_local_config(
r#"{"planning":{"capabilityEnabled":false}}"#.to_string(),
);
@@ -3802,7 +3811,7 @@ mod tests {
assert_eq!(blocker.status, "needs-reconciliation");
assert!(blocker.summary.contains("审批 pending"));
create_plan_gdd_approval_pending_at(&root, &gdd).expect("create approval pending");
create_plan_gdd_approval_pending_for_test(&root, &gdd).expect("create approval pending");
let blocker = plan_gdd_completion_blocker_at_locked(
&root,
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
@@ -3955,7 +3964,7 @@ mod tests {
.expect("read submitted GDD")
.pop()
.expect("GDD exists");
create_plan_gdd_approval_pending_at(&root, &gdd).expect("create approval pending");
create_plan_gdd_approval_pending_for_test(&root, &gdd).expect("create approval pending");
decide_plan_gdd_at(
&root,
&approval_input(
@@ -4089,7 +4098,7 @@ mod tests {
#[test]
fn a_revision_comment_reaches_the_supervisor_conversation_once() {
let (root, gdd, _root_runtime) = acceptance_gate_fixture(true);
create_plan_gdd_approval_pending_at(&root, &gdd).expect("create approval pending");
create_plan_gdd_approval_pending_for_test(&root, &gdd).expect("create approval pending");
decide_plan_gdd_at(
&root,
&approval_input(
@@ -4143,7 +4152,7 @@ mod tests {
.expect("read submitted GDD")
.pop()
.expect("GDD exists");
create_plan_gdd_approval_pending_at(&root, &gdd).expect("create approval pending");
create_plan_gdd_approval_pending_for_test(&root, &gdd).expect("create approval pending");
decide_plan_gdd_at(
&root,
&approval_input(
@@ -4230,7 +4239,8 @@ mod tests {
.expect("read submitted GDD")
.pop()
.expect("GDD exists");
create_plan_gdd_approval_pending_at(&root, &gdd).expect("create approval pending");
create_plan_gdd_approval_pending_for_test(&root, &gdd)
.expect("create approval pending");
let first_input = approval_input(
&gdd,
action,
@@ -4461,7 +4471,7 @@ mod tests {
.expect("read submitted GDD")
.pop()
.expect("GDD exists");
create_plan_gdd_approval_pending_at(&root, &gdd).expect("create approval pending");
create_plan_gdd_approval_pending_for_test(&root, &gdd).expect("create approval pending");
let decision_input = approval_input(
&gdd,
"approve",