展示Agent循环轮次进度
新增 Agent Runtime loopIteration、maxLoopIterations 和 toolActionBudget 观测字段 在 Runtime 面板、主 Agent 卡片、agent.run_status 和连续上下文展示 loop 进度 补充前端状态展示测试、Rust JSON 与 prompt 上下文断言 同步 AI 游戏创作 App 技术方案和项目决策记录
This commit is contained in:
@@ -411,6 +411,9 @@ async fn run_game_creator_agent_background_task(
|
||||
let mut final_reply = None;
|
||||
|
||||
for loop_index in 0..AGENT_RUNTIME_BACKGROUND_LOOP_LIMIT {
|
||||
runtime.loop_iteration = (loop_index + 1) as u32;
|
||||
runtime.max_loop_iterations = AGENT_RUNTIME_BACKGROUND_LOOP_LIMIT as u32;
|
||||
runtime.tool_action_budget = AGENT_RUNTIME_BACKGROUND_TOOL_ACTION_LIMIT as u32;
|
||||
runtime = match advance_game_creator_agent_runtime_turn_at(
|
||||
&root,
|
||||
runtime,
|
||||
@@ -2157,11 +2160,14 @@ fn format_agent_runtime_status_observation(result: &AgentRuntimeResult) -> Strin
|
||||
.filter(|value| !value.trim().is_empty())
|
||||
.unwrap_or_else(|| "-".to_string());
|
||||
format!(
|
||||
"agentId: {}\nstatus: {}\nphase: {}\nrunId: {}\n当前目标: {}\n当前任务: {}\n当前动作: {}\n等待: {}\n下一步: {}\n计划: {}\n任务队列: {}\n最近任务: {}\n最近工具: {}\n错误: {}",
|
||||
"agentId: {}\nstatus: {}\nphase: {}\nrunId: {}\n循环轮次: {}/{}\n每轮工具预算: {}\n当前目标: {}\n当前任务: {}\n当前动作: {}\n等待: {}\n下一步: {}\n计划: {}\n任务队列: {}\n最近任务: {}\n最近工具: {}\n错误: {}",
|
||||
state.agent_id,
|
||||
state.status,
|
||||
state.phase,
|
||||
state.run_id,
|
||||
state.loop_iteration,
|
||||
state.max_loop_iterations,
|
||||
state.tool_action_budget,
|
||||
current_goal,
|
||||
current_task,
|
||||
current_action,
|
||||
@@ -2525,6 +2531,9 @@ fn default_game_creator_agent_runtime_state(agent_id: &str, run_id: &str) -> Age
|
||||
current_action: "等待输入".to_string(),
|
||||
waiting_on: "开发者输入".to_string(),
|
||||
next_step: "等待输入".to_string(),
|
||||
loop_iteration: 0,
|
||||
max_loop_iterations: AGENT_RUNTIME_BACKGROUND_LOOP_LIMIT as u32,
|
||||
tool_action_budget: AGENT_RUNTIME_BACKGROUND_TOOL_ACTION_LIMIT as u32,
|
||||
plan: vec![
|
||||
"读取项目上下文".to_string(),
|
||||
"按角色职责推理".to_string(),
|
||||
@@ -2601,6 +2610,12 @@ fn normalize_game_creator_agent_runtime_state(state: &mut AgentRuntimeState, age
|
||||
if state.next_step.trim().is_empty() {
|
||||
state.next_step = agent_runtime_next_step_for_phase(&state.phase).to_string();
|
||||
}
|
||||
if state.max_loop_iterations == 0 {
|
||||
state.max_loop_iterations = AGENT_RUNTIME_BACKGROUND_LOOP_LIMIT as u32;
|
||||
}
|
||||
if state.tool_action_budget == 0 {
|
||||
state.tool_action_budget = AGENT_RUNTIME_BACKGROUND_TOOL_ACTION_LIMIT as u32;
|
||||
}
|
||||
if state.plan.is_empty() {
|
||||
state.plan = vec![
|
||||
"读取项目上下文".to_string(),
|
||||
@@ -3290,6 +3305,12 @@ fn render_agent_runtime_prompt_context(root: &Path, agent_id: &str) -> Result<St
|
||||
redact_agent_runtime_project_paths(root, &state.next_step, 160)
|
||||
));
|
||||
}
|
||||
if state.loop_iteration > 0 {
|
||||
lines.push(format!(
|
||||
"循环轮次:{}/{};每轮工具预算:{}",
|
||||
state.loop_iteration, state.max_loop_iterations, state.tool_action_budget
|
||||
));
|
||||
}
|
||||
if runtime.task_queue.total > 0 {
|
||||
lines.push(format!(
|
||||
"任务队列:{}",
|
||||
|
||||
@@ -162,6 +162,12 @@ struct AgentRuntimeState {
|
||||
#[serde(default)]
|
||||
next_step: String,
|
||||
#[serde(default)]
|
||||
loop_iteration: u32,
|
||||
#[serde(default)]
|
||||
max_loop_iterations: u32,
|
||||
#[serde(default)]
|
||||
tool_action_budget: u32,
|
||||
#[serde(default)]
|
||||
plan: Vec<String>,
|
||||
#[serde(default)]
|
||||
observations: Vec<String>,
|
||||
|
||||
@@ -1142,6 +1142,9 @@ async fn role_agent_legacy_alias_maps_to_canonical_task_runtime_and_route() {
|
||||
.expect("parse runtime wire json");
|
||||
assert_eq!(runtime_wire["currentGoal"], "排队规划美术资产");
|
||||
assert_eq!(runtime_wire["waitingOn"], "Agent 输出计划或回复");
|
||||
assert_eq!(runtime_wire["loopIteration"], 0);
|
||||
assert_eq!(runtime_wire["maxLoopIterations"], 3);
|
||||
assert_eq!(runtime_wire["toolActionBudget"], 3);
|
||||
assert_eq!(runtime_wire["taskQueue"]["total"], 1);
|
||||
assert_eq!(runtime_wire["taskQueue"]["running"], 1);
|
||||
assert_eq!(
|
||||
@@ -1153,6 +1156,9 @@ async fn role_agent_legacy_alias_maps_to_canonical_task_runtime_and_route() {
|
||||
assert_eq!(alias_read.state.agent_id, "art-asset-plan");
|
||||
assert_eq!(alias_read.state.current_goal, "排队规划美术资产");
|
||||
assert_eq!(alias_read.state.waiting_on, "Agent 输出计划或回复");
|
||||
assert_eq!(alias_read.state.loop_iteration, 0);
|
||||
assert_eq!(alias_read.state.max_loop_iterations, 3);
|
||||
assert_eq!(alias_read.state.tool_action_budget, 3);
|
||||
assert_eq!(alias_read.task_queue.total, 1);
|
||||
assert_eq!(alias_read.task_queue.running, 1);
|
||||
assert!(alias_read
|
||||
@@ -1971,6 +1977,7 @@ async fn background_agent_runtime_plan_request_includes_same_agent_continuity_co
|
||||
assert!(second_design_request.contains("# Agent Runtime 连续上下文"));
|
||||
assert!(second_design_request.contains("当前状态:status=running"));
|
||||
assert!(second_design_request.contains("runId=design-continuity-second"));
|
||||
assert!(second_design_request.contains("循环轮次:1/3;每轮工具预算:3"));
|
||||
assert!(second_design_request.contains(
|
||||
"任务队列:total=2 pending=0 running=1 completed=1 failed=0 latest=design-continuity-second"
|
||||
));
|
||||
@@ -4185,6 +4192,8 @@ async fn background_agent_runtime_can_read_other_agent_status() {
|
||||
assert!(final_request.contains("agentId: art-director"));
|
||||
assert!(final_request.contains("status: running"));
|
||||
assert!(final_request.contains("phase: action"));
|
||||
assert!(final_request.contains("循环轮次: 0/3"));
|
||||
assert!(final_request.contains("每轮工具预算: 3"));
|
||||
assert!(final_request.contains("当前目标: 生成角色规范图"));
|
||||
assert!(final_request.contains("当前任务: 生成角色规范图"));
|
||||
assert!(final_request.contains("当前动作: 正在生成角色规范图"));
|
||||
|
||||
@@ -241,6 +241,9 @@ interface AgentRuntimeState {
|
||||
currentAction: string;
|
||||
waitingOn?: string;
|
||||
nextStep?: string;
|
||||
loopIteration?: number;
|
||||
maxLoopIterations?: number;
|
||||
toolActionBudget?: number;
|
||||
plan: string[];
|
||||
observations: string[];
|
||||
recentToolCalls?: AgentRuntimeToolCallRecord[];
|
||||
@@ -537,6 +540,9 @@ function normalizeAgentRuntimeState(
|
||||
waitingOn:
|
||||
state.waitingOn ?? agentRuntimeWaitingOnFromPhase(state.phase),
|
||||
nextStep: state.nextStep ?? agentRuntimeNextStepFromPhase(state.phase),
|
||||
loopIteration: state.loopIteration ?? previous?.loopIteration ?? 0,
|
||||
maxLoopIterations: state.maxLoopIterations ?? previous?.maxLoopIterations ?? 3,
|
||||
toolActionBudget: state.toolActionBudget ?? previous?.toolActionBudget ?? 3,
|
||||
recentToolCalls: state.recentToolCalls ?? previous?.recentToolCalls ?? [],
|
||||
toolPolicy: state.toolPolicy ?? previous?.toolPolicy ?? {
|
||||
allowedTools: state.allowedTools ?? [],
|
||||
@@ -646,6 +652,21 @@ function formatAgentRuntimeTaskQueue(
|
||||
return `任务队列:${parts.join(' · ')}`;
|
||||
}
|
||||
|
||||
function formatAgentRuntimeLoopProgress(
|
||||
runtime: Pick<
|
||||
AgentRuntimeState,
|
||||
'loopIteration' | 'maxLoopIterations' | 'toolActionBudget'
|
||||
>,
|
||||
) {
|
||||
const loopIteration = runtime.loopIteration ?? 0;
|
||||
if (loopIteration <= 0) {
|
||||
return null;
|
||||
}
|
||||
return `Loop:${loopIteration}/${runtime.maxLoopIterations ?? 3} · 工具预算 ${
|
||||
runtime.toolActionBudget ?? 3
|
||||
}`;
|
||||
}
|
||||
|
||||
function AgentRuntimeStatusPanel({
|
||||
runtime,
|
||||
error,
|
||||
@@ -673,6 +694,7 @@ function AgentRuntimeStatusPanel({
|
||||
const recentTasks = (runtime.recentTasks ?? []).slice(-3).reverse();
|
||||
const toolPolicy = runtime.toolPolicy;
|
||||
const taskQueueSummary = formatAgentRuntimeTaskQueue(runtime.taskQueue);
|
||||
const loopProgress = formatAgentRuntimeLoopProgress(runtime);
|
||||
const nextStep = runtime.nextStep ?? agentRuntimeNextStepFromPhase(runtime.phase);
|
||||
const currentGoal = runtime.currentGoal ?? runtime.currentTask;
|
||||
const waitingOn = runtime.waitingOn ?? agentRuntimeWaitingOnFromPhase(runtime.phase);
|
||||
@@ -689,6 +711,7 @@ function AgentRuntimeStatusPanel({
|
||||
<small>{runtime.currentAction}</small>
|
||||
{waitingOn ? <small>{`等待:${waitingOn}`}</small> : null}
|
||||
{nextStep ? <small>{`下一步:${nextStep}`}</small> : null}
|
||||
{loopProgress ? <small>{loopProgress}</small> : null}
|
||||
{taskQueueSummary ? <small>{taskQueueSummary}</small> : null}
|
||||
{toolPolicy ? (
|
||||
<small>
|
||||
@@ -876,6 +899,9 @@ interface AgentStatusCard {
|
||||
runtimeNextStep: string | null;
|
||||
runtimeTask: string | null;
|
||||
runtimeRunId: string | null;
|
||||
runtimeLoopIteration: number | null;
|
||||
runtimeMaxLoopIterations: number | null;
|
||||
runtimeToolActionBudget: number | null;
|
||||
runtimeTaskQueue: AgentRuntimeTaskQueueSummary | null;
|
||||
runtimeRecentTasks: AgentRuntimeTaskRecord[];
|
||||
}
|
||||
@@ -10197,6 +10223,9 @@ export function deriveAgentStatusCards(
|
||||
: null,
|
||||
runtimeTask: runtime?.currentTask ?? null,
|
||||
runtimeRunId: runtime?.runId ?? null,
|
||||
runtimeLoopIteration: runtime?.loopIteration ?? null,
|
||||
runtimeMaxLoopIterations: runtime?.maxLoopIterations ?? null,
|
||||
runtimeToolActionBudget: runtime?.toolActionBudget ?? null,
|
||||
runtimeTaskQueue: runtime?.taskQueue ?? null,
|
||||
runtimeRecentTasks: runtime?.recentTasks ?? [],
|
||||
};
|
||||
@@ -10230,6 +10259,9 @@ function sameAgentStatusCard(left: AgentStatusCard, right: AgentStatusCard) {
|
||||
left.runtimeNextStep === right.runtimeNextStep &&
|
||||
left.runtimeTask === right.runtimeTask &&
|
||||
left.runtimeRunId === right.runtimeRunId &&
|
||||
left.runtimeLoopIteration === right.runtimeLoopIteration &&
|
||||
left.runtimeMaxLoopIterations === right.runtimeMaxLoopIterations &&
|
||||
left.runtimeToolActionBudget === right.runtimeToolActionBudget &&
|
||||
sameAgentRuntimeTaskQueue(left.runtimeTaskQueue, right.runtimeTaskQueue) &&
|
||||
left.hasRecentEvidence === right.hasRecentEvidence &&
|
||||
left.taskGraphState === right.taskGraphState &&
|
||||
@@ -11028,8 +11060,15 @@ function formatAgentCardRuntimeStatus(agent: AgentStatusCard) {
|
||||
if (!agent.runtimeStatus) {
|
||||
return null;
|
||||
}
|
||||
const loopProgress =
|
||||
agent.runtimeLoopIteration && agent.runtimeLoopIteration > 0
|
||||
? `Loop ${agent.runtimeLoopIteration}/${
|
||||
agent.runtimeMaxLoopIterations ?? 3
|
||||
}`
|
||||
: null;
|
||||
return [
|
||||
`Runtime:${agent.runtimeStatus} / ${agent.runtimePhase ?? '-'}`,
|
||||
loopProgress,
|
||||
agent.runtimeAction,
|
||||
agent.runtimeWaitingOn ? `等待 ${agent.runtimeWaitingOn}` : null,
|
||||
agent.runtimeNextStep ? `下一步 ${agent.runtimeNextStep}` : null,
|
||||
|
||||
@@ -515,6 +515,9 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
phase: 'planning',
|
||||
currentTask: '补齐主角规范图资产列表',
|
||||
currentAction: '拆解素材规格',
|
||||
loopIteration: 2,
|
||||
maxLoopIterations: 3,
|
||||
toolActionBudget: 3,
|
||||
plan: ['读取项目上下文'],
|
||||
observations: ['已创建本轮 Agent Runtime run。'],
|
||||
allowedTools: ['conversation.read'],
|
||||
@@ -555,6 +558,9 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
runtimeAction: '拆解素材规格',
|
||||
runtimeTask: '补齐主角规范图资产列表',
|
||||
runtimeRunId: 'runtime-art-asset-plan-1',
|
||||
runtimeLoopIteration: 2,
|
||||
runtimeMaxLoopIterations: 3,
|
||||
runtimeToolActionBudget: 3,
|
||||
runtimeTaskQueue,
|
||||
runtimeRecentTasks: [runtimeTask],
|
||||
});
|
||||
@@ -1381,6 +1387,9 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
currentGoal: '完成角色规范阶段',
|
||||
currentAction: '调用工具 file.read',
|
||||
waitingOn: '工具观察结果',
|
||||
loopIteration: 1,
|
||||
maxLoopIterations: 3,
|
||||
toolActionBudget: 3,
|
||||
plan: ['读取项目笔记', '结合观察修正建议', '回复开发者'],
|
||||
observations: ['思考摘要:需要先看项目笔记', 'file.read:ok · 已读取 game/notes.txt'],
|
||||
recentToolCalls: [
|
||||
@@ -1565,6 +1574,7 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
expect(screen.getByText('当前目标:完成角色规范阶段')).not.toBeNull();
|
||||
expect(screen.getByText('调用工具 file.read')).not.toBeNull();
|
||||
expect(screen.getByText('等待:工具观察结果')).not.toBeNull();
|
||||
expect(screen.getByText('Loop:1/3 · 工具预算 3')).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(
|
||||
/任务队列:pending 0 · running 1 · completed 0 · failed 0 · total 1 · latest launcher-agent-task-/,
|
||||
@@ -1631,6 +1641,9 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
phase: 'planning',
|
||||
currentTask: '正在处理上一条任务',
|
||||
currentAction: '生成 Agent 工具计划',
|
||||
loopIteration: 1,
|
||||
maxLoopIterations: 3,
|
||||
toolActionBudget: 3,
|
||||
plan: ['读取上下文', '回复开发者'],
|
||||
observations: ['上一条任务正在运行。'],
|
||||
taskQueue: {
|
||||
@@ -1759,6 +1772,7 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '后台运行' }));
|
||||
|
||||
expect(await screen.findByText('正在处理上一条任务')).not.toBeNull();
|
||||
expect(screen.getByText('Loop:1/3 · 工具预算 3')).not.toBeNull();
|
||||
expect(
|
||||
screen.getByText(/已加入后台队列:launcher-agent-task-/),
|
||||
).not.toBeNull();
|
||||
@@ -13347,6 +13361,9 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
currentGoal: '补齐第一关节奏目标',
|
||||
currentAction: '整理目标和约束',
|
||||
waitingOn: 'Agent 输出计划或回复',
|
||||
loopIteration: 2,
|
||||
maxLoopIterations: 3,
|
||||
toolActionBudget: 3,
|
||||
plan: ['读取项目上下文'],
|
||||
observations: ['已创建本轮 Agent Runtime run。'],
|
||||
taskQueue: {
|
||||
@@ -13414,7 +13431,7 @@ describe('AI 游戏创作 App 界面边界', () => {
|
||||
name: /拆解创作方向/,
|
||||
});
|
||||
expect(designCard.textContent).toContain(
|
||||
'Runtime:running / planning · 整理目标和约束 · 等待 Agent 输出计划或回复 · 下一步 等待 Agent 输出计划或回复 · run runtime-design-director-1',
|
||||
'Runtime:running / planning · Loop 2/3 · 整理目标和约束 · 等待 Agent 输出计划或回复 · 下一步 等待 Agent 输出计划或回复 · run runtime-design-director-1',
|
||||
);
|
||||
expect(designCard.textContent).toContain(
|
||||
'当前目标:补齐第一关节奏目标',
|
||||
|
||||
@@ -4061,6 +4061,7 @@
|
||||
- 2026-07-10 调整:Agent Runtime state 新增 `toolPolicy`,从项目权限策略派生工具级 `allowedTools`、`autoTools`、`confirmTools` 和 `deniedTools`。后台 planning prompt 必须带入该快照,让 Agent 在规划阶段知道工具策略;执行阶段仍由 Runtime 白名单和项目权限 gate 决定。`blackboard.write` 继承 `memory.write` 策略,`agent.message` 继承 `conversation.write` 策略,`agent.delegate` 使用独立 `agent.delegate` 策略。
|
||||
- 2026-07-10 调整:Agent Runtime state 新增 `recentToolCalls`,后台 loop 每次执行白名单工具后记录最近 20 条结构化动作,包含 tool、status、reason、summary、detail 和 updatedAt。状态面板展示最近动作时使用该字段,不解析 observation 文本;写入前继续过滤敏感上下文,不保存原始密钥或任意未过滤输入。
|
||||
- 2026-07-10 调整:Agent Runtime state 新增 `currentGoal` 和 `waitingOn`。`currentGoal` 固定表达本轮任务目标,`waitingOn` 表达当前等待 LLM、工具观察、开发者输入或失败处理;后台任务生命周期、`agent.run_status` observation、下一轮 planning prompt、开发单 Agent 对话页、项目内 Agent 对话弹窗和主窗口 Agent 状态列表都必须展示同一份目标 / 等待状态。
|
||||
- 2026-07-10 调整:Agent Runtime state 新增 `loopIteration / maxLoopIterations / toolActionBudget`。后台 Agent loop 每轮规划前刷新当前轮次、最大轮次和每轮工具动作预算;开发窗口 Runtime 面板、主窗口 Agent 状态列表、`agent.run_status` observation 和下一轮 planning prompt 都展示该进度,字段只做运行观测,不改变 loop 上限或权限 gate。
|
||||
- 2026-07-10 调整:开发单 Agent 对话页和项目内 Agent 对话弹窗的 Runtime 面板接入 `recentEvents`,展示最近 `thinking_summary / plan / action / observation / response / error` 事件,避免只从当前状态、observation 字符串或最近工具动作里倒推 Agent loop。
|
||||
- 2026-07-10 调整:Agent Runtime state / result 新增 `taskQueue` 观测摘要,从 `.agent/runtime/tasks/<agentId>.jsonl` 中每个 `runId` 的最新记录汇总 `total / pending / running / completed / failed / latestRunId`。开发窗口 Runtime 面板、主窗口 Agent 状态列表、`agent.run_status` observation 和下一轮 planning prompt 都使用该字段判断同一 Agent 是否仍有排队任务;它不是新的调度器、SQLite 或跨重启独立 worker。
|
||||
- 2026-07-10 调整:Agent Runtime V1 后台工具箱新增只读 `task.list`。Agent 可自行读取 `.agent/manifest.json` 的 seed task 状态、依赖、产物交接和按依赖计算的 `readyTaskIds`,用于判断下一步任务;该工具必须受 `task.list` 项目权限策略保护,策略要求确认或拒绝时不得把任务图细节放进 observation。
|
||||
|
||||
@@ -36,6 +36,7 @@ Agent Runtime 负责:
|
||||
- 2026-07-10 补充:Agent Runtime state 新增 `toolPolicy`,按当前项目 `.agent/policy.json` 派生工具级 `allowedTools / autoTools / confirmTools / deniedTools` 快照;后台 planning prompt 会带入该快照,让 Agent 在规划时知道哪些工具会自动执行、需要确认或被拒绝。`blackboard.write` 继承 `memory.write` 策略,`agent.message` 继承 `conversation.write` 策略,`agent.delegate` 使用独立 `agent.delegate` 策略;实际执行仍以 Runtime 的白名单和项目权限 gate 为准。
|
||||
- 2026-07-10 补充:Agent Runtime state 新增 `recentToolCalls`,每次后台工具执行后记录最近 20 条结构化工具动作,包含 tool、status、reason、summary、detail 和 updatedAt;开发窗口、项目内 Agent 对话弹窗和主窗口 Agent 状态列表可直接展示“最近动作”,不再只能从 observation 字符串里猜测 action / observation 对应关系。字段只保存过滤后的摘要和观察细节,不保存原始 API Key 或任意未过滤输入。
|
||||
- 2026-07-10 补充:Agent Runtime state 新增 `currentGoal` 和 `waitingOn`,把本轮目标与当前等待对象从 `currentTask / currentAction / nextStep` 中显式拆出来;后台任务启动、工具 observation、完成和失败都会刷新该状态,开发窗口、项目内 Agent 对话弹窗、主窗口 Agent 状态列表、`agent.run_status` observation 和下一轮 planning prompt 都展示同一份目标 / 等待信息,避免开发者只能从动作文本里猜 Agent 卡在 LLM、工具、同伴还是人工输入。
|
||||
- 2026-07-10 补充:Agent Runtime state 新增 `loopIteration / maxLoopIterations / toolActionBudget`,结构化记录后台 Agent loop 当前轮次、最大轮次和每轮工具动作预算;开发窗口 Runtime 面板、主窗口 Agent 状态列表、`agent.run_status` observation 和下一轮 planning prompt 都展示该进度,帮助判断 Agent 是刚开始规划、正在 replan,还是接近本轮 loop 上限。该字段只做运行观测,不改变后台 loop 的执行上限或工具权限。
|
||||
- 2026-07-10 补充:`recentEvents` 接入前端归一态和 Runtime 状态面板,事件事实源仍是 `.agent/runtime/events/<agentId>.jsonl`;面板按时间展示最近 `thinking_summary / plan / action / observation / response / error` 事件,现在能同时看到 Agent 的计划、最近观察、最近事件、最近工具动作和任务队列。
|
||||
- 2026-07-10 补充:Agent Runtime state / result 新增 `taskQueue`,从 `.agent/runtime/tasks/<agentId>.jsonl` 中每个 `runId` 的最新记录汇总 `total / pending / running / completed / failed / latestRunId`;开发窗口 Runtime 面板、主窗口 Agent 状态列表、`agent.run_status` observation 和下一轮 planning prompt 都读取该摘要,用于判断同一 Agent 是否仍有排队任务。该字段是运行观测摘要,不新增调度器、SQLite 或独立 worker。
|
||||
- 2026-07-10 补充:单 Agent 聊天和后台 planning prompt 会读取同一个 Agent 的 Runtime 连续上下文,把本 Agent 最近 status / phase / runId / 当前任务 / 下一步、最近回复、计划、观察、最近 3 条工具动作、最近事件、最近 3 条任务记录和工具策略摘要带入下一轮推理;上下文按规范 taskId 隔离,不读取其他 Agent 的 runtime 文件,并在进入 prompt 前过滤密钥和本机绝对路径。新后台 run 启动时会继承本 Agent 上次 `recentToolCalls` 和 `lastResponse`,让多轮任务不丢失结构化行动证据。
|
||||
@@ -297,7 +298,7 @@ game-project/
|
||||
- loop 每次运行会写 `.agent/run.latest.json` 和 `.agent/runs/<runId>.json`,记录 `Planner` / `Orchestrator` agenda / 16 个组内角色 brief 或 carry-over / 6 个 `GroupCoordinator` 汇总 / `Generator` / 6 个专业组交接 / `Evaluator` 质量评审 / `ArtifactWriter` / `Playtest` step、每步 `toolCalls`、输入文件、输出文件、状态、轮次、maxPasses、toolCallCount、maxToolCalls、stopReason、nextStep 和错误摘要;Planner、角色 agent 和 Generator 的 `inputPaths` 必须包含对应记忆文件、`.agent/conversations/project.jsonl`、`.agent/conversations/agents/`、`.agent/manifest.json` 和 agenda 等上下文来源,其中角色 agent 必须包含自己的 `memory/agents/<group>/<role>.md` 和 `memory/blackboard.md`;conversation 输入只取最近少量 project / agent 对话摘要,不读取全量历史;每个 step 必须带 phase、taskId、group 和 role,`.agent/run.latest.json.taskGraph` 必须记录 goal、readyTaskIds、activeTaskIds、carriedTaskIds、repairFocus、repairRoutes 和当前任务状态;`.agent/run.latest.json.passPlans` 必须按轮记录 mode、summary、activeTaskIds、carriedTaskIds、dependencyWaves、repairFocus 和 repairRoutes,作为 `/trace` 与开发窗口判断编排 loop 是否真实发生的直接证据;`run.latest.json` 是当前指针,`.agent/runs/` 保留历史 run trace;开发窗口读取 latest 展示编排过程,并复用 `file.list/read` 按文件修改时间先载入最近 20 个历史 run,滚动时再按批次读取剩余历史,普通用户窗口不展示。
|
||||
- `.agent/run.latest.json` 的 `artifacts` 使用结构化记录,包含相对路径、字节数和 `fnv1a64:` checksum;除最终本地产物外,也会收集 `.agent/passes/pass-N/` 快照,便于确认返工前后的产物差异。
|
||||
- 通过 Evaluator 和 `game.static_smoke` 后,Agent loop 会把本次 runId、状态、轮次、下一步、active / carry-over 任务和最终本地产物摘要追加到 `memory/session.md` 与 `memory/project.md`,把重要跨 agent 决策 / 依赖 / 风险摘要追加到 `memory/blackboard.md`,并把各角色本轮成功产出的角色摘要追加到 `memory/agents/<group>/<role>.md`;下一次 Planner、组内角色和 Generator 会通过记忆输入自然读取上一轮稳定原型状态,而不只依赖开发窗口 trace。
|
||||
- 单 agent 对话入口读取对应 agent conversation;用户提交后先追加用户消息,再调用 `chat_with_game_creator_role_agent` / `chat_with_game_creator_role_agent_stream` 让对应 `agentLlm.<agentId>` 结合项目上下文、Agent 私有记忆和本 Agent 历史对话生成回复,随后把回复写入对应 `.agent/conversations/agents/<agentId>.jsonl`。这里的 `<agentId>` 以任务 `taskId` 为规范值,Tauri 只兼容旧 `group-role` 别名并映射到 taskId。每轮对话会同步写 `.agent/runtime/agents/<agentId>.json` 和 `.agent/runtime/events/<agentId>.jsonl`,字段包含 `agentId`、`taskId`、`sessionId`、`runId`、`source`、`status`、`phase`、`currentTask`、`currentGoal`、`currentAction`、`waitingOn`、`nextStep`、`plan`、`observations`、`recentToolCalls`、`toolPolicy`、`allowedTools`、`lastResponse` 和 `error`;流式事件会把最新 `runtimeState` 回传给界面。Runtime state 写入使用临时文件替换,event JSONL 读取会跳过坏行;`currentTask`、`currentGoal`、event detail、`lastResponse` 和 `agent.db` 摘要复用敏感上下文过滤,不保存明显 API Key / Bearer / Cookie 片段。单 agent 面板可把当前输入手动追加到对应 `memory/agents/<group>/<role>.md`,写入前复用 `memory.write` 项目策略和本地项目锁;最近对话可作为本次生成 prompt 上下文读取,但只有经过显式总结、用户显式手动沉淀或生成 loop 成功沉淀的稳定结论,才追加到 `memory/blackboard.md` 或 `memory/agents/<group>/<role>.md`。
|
||||
- 单 agent 对话入口读取对应 agent conversation;用户提交后先追加用户消息,再调用 `chat_with_game_creator_role_agent` / `chat_with_game_creator_role_agent_stream` 让对应 `agentLlm.<agentId>` 结合项目上下文、Agent 私有记忆和本 Agent 历史对话生成回复,随后把回复写入对应 `.agent/conversations/agents/<agentId>.jsonl`。这里的 `<agentId>` 以任务 `taskId` 为规范值,Tauri 只兼容旧 `group-role` 别名并映射到 taskId。每轮对话会同步写 `.agent/runtime/agents/<agentId>.json` 和 `.agent/runtime/events/<agentId>.jsonl`,字段包含 `agentId`、`taskId`、`sessionId`、`runId`、`source`、`status`、`phase`、`currentTask`、`currentGoal`、`currentAction`、`waitingOn`、`nextStep`、`loopIteration`、`maxLoopIterations`、`toolActionBudget`、`plan`、`observations`、`recentToolCalls`、`toolPolicy`、`allowedTools`、`lastResponse` 和 `error`;流式事件会把最新 `runtimeState` 回传给界面。Runtime state 写入使用临时文件替换,event JSONL 读取会跳过坏行;`currentTask`、`currentGoal`、event detail、`lastResponse` 和 `agent.db` 摘要复用敏感上下文过滤,不保存明显 API Key / Bearer / Cookie 片段。单 agent 面板可把当前输入手动追加到对应 `memory/agents/<group>/<role>.md`,写入前复用 `memory.write` 项目策略和本地项目锁;最近对话可作为本次生成 prompt 上下文读取,但只有经过显式总结、用户显式手动沉淀或生成 loop 成功沉淀的稳定结论,才追加到 `memory/blackboard.md` 或 `memory/agents/<group>/<role>.md`。
|
||||
- 生成 loop 中的角色 brief 也写同一套 Agent Runtime state / event:active 角色用 `source=generate-draft` 和当前 `runId` 标记正在读取上下文、调用角色专属 LLM 或本地编排、生成 brief、完成或失败;carry-over 角色同样写入开始 / 完成事件,但不会伪装成重新调用 LLM。主窗口 Agent 状态列表、开发单 Agent 聊天页和项目内单 Agent 对话弹窗只读展示当前 Agent 的 runtime 状态、最近 task/run、阶段、当前目标、动作、等待对象、下一步、计划、观测和最近工具动作;这只是 V1 可观测性,不代表已经有独立后台常驻进程或可中断任意上游 LLM 请求。
|
||||
- `.agent/agent.db` 当前作为最小本地项目索引文件使用 JSONL:初始化写入 `project.init`,每次 `game.generate_draft` 追加目标、标题、本地产物路径、checkpoint 和 diff 摘要,上传 / 登记 / 画板导入资产时追加 `asset.register` 或 `asset.update`;v1 不引入 SQLite 依赖。
|
||||
- `game.generate_draft`、资产登记 / 导入、记忆写入、预览状态写入、checkpoint / restore、agent 生命周期控制、画板资源回流 / 生成和 policy 写入会先按 `.agent/policy.json` 判断本次命令是否被项目策略拒绝,再拿项目级 `.agent/project.lock` 串行化;锁只保护同一本地项目,v1 不做后台锁管理。`confirmCommands` 可把索引、状态读取、资产登记、checkpoint、预览、agent 生命周期、画板资源回流 / 生成、memory 读写删除和 conversation 读写等命令转成项目策略确认,命中时用户确认后才执行;用户可用 `/policy-confirm 命令` 加入确认列表,用 `/policy-auto 命令` 移除确认项。
|
||||
|
||||
Reference in New Issue
Block a user