修复游戏聊天续写来源匹配
Steer 目标增加 Runtime source 精确匹配 游戏聊天仅续写同来源 Run 并保留跨入口任务隔离 补充模型与 AppSurface 回归夹具和项目记忆
This commit is contained in:
@@ -5628,6 +5628,7 @@ export function App({
|
||||
PROJECT_SUPERVISOR_AGENT_ID,
|
||||
sessionId,
|
||||
submissionRunProfile,
|
||||
'project-supervisor-game-chat',
|
||||
)
|
||||
: null;
|
||||
let autoPreviewAfterRevision = 0;
|
||||
|
||||
@@ -725,6 +725,7 @@ export function matchingAgentRuntimeForSteer(
|
||||
requestedRunProfile: NonNullable<
|
||||
AgentRuntimeState['runProfile']
|
||||
> = 'standard',
|
||||
requestedSource?: string,
|
||||
) {
|
||||
if (!sessionId) {
|
||||
return null;
|
||||
@@ -735,6 +736,7 @@ export function matchingAgentRuntimeForSteer(
|
||||
runtime?.agentId === agentId &&
|
||||
runtime.sessionId === sessionId &&
|
||||
(runtime.runProfile ?? 'standard') === requestedRunProfile &&
|
||||
(!requestedSource || runtime.source === requestedSource) &&
|
||||
isAgentRuntimeSteerableState(runtime),
|
||||
) ?? null
|
||||
);
|
||||
@@ -834,6 +836,7 @@ export async function submitProjectSupervisorRuntimeTask({
|
||||
PROJECT_SUPERVISOR_AGENT_ID,
|
||||
sessionId,
|
||||
runProfile,
|
||||
source,
|
||||
);
|
||||
if (steerRuntime) {
|
||||
const steer = await invoke<AgentRuntimeSteerResult>(
|
||||
@@ -1330,7 +1333,9 @@ export function projectSupervisorCollaboratingAgentRuntimes(
|
||||
const runtimesByAgentId = new Map<string, AgentRuntimeState>();
|
||||
for (const runtime of Object.values(runtimeByAgentId)) {
|
||||
const isVisibleChildSource =
|
||||
['agent-delegate', 'agent-delegate-retry'].includes(runtime?.source ?? '') ||
|
||||
['agent-delegate', 'agent-delegate-retry'].includes(
|
||||
runtime?.source ?? '',
|
||||
) ||
|
||||
(supervisorRuntime.source === 'project-supervisor-game-chat' &&
|
||||
runtime?.source === 'agent-ready-task-scheduler');
|
||||
if (
|
||||
|
||||
@@ -82,7 +82,8 @@ describe('Game Chat stream identity and source', () => {
|
||||
eventPath: 'events.jsonl',
|
||||
} satisfies AgentRuntimeResult;
|
||||
const invoke = vi.fn(
|
||||
async (_command: string, _args?: Record<string, unknown>) => runtimeResult,
|
||||
async (_command: string, _args?: Record<string, unknown>) =>
|
||||
runtimeResult,
|
||||
);
|
||||
|
||||
await submitProjectSupervisorRuntimeTask({
|
||||
@@ -116,6 +117,7 @@ describe('Game Chat stream identity and source', () => {
|
||||
...runtimeResult.state,
|
||||
runId: 'steer-run',
|
||||
runProfile: 'autonomous-game-build',
|
||||
source: 'project-supervisor-game-chat',
|
||||
status: 'running',
|
||||
phase: 'planning',
|
||||
} satisfies AgentRuntimeState;
|
||||
@@ -157,6 +159,24 @@ describe('Game Chat stream identity and source', () => {
|
||||
runProfile: 'autonomous-game-build',
|
||||
});
|
||||
expect(invoke.mock.calls[0]?.[1]).not.toHaveProperty('source');
|
||||
|
||||
invoke.mockClear();
|
||||
await submitProjectSupervisorRuntimeTask({
|
||||
invoke,
|
||||
projectPath: '/tmp/game-chat',
|
||||
sessionId: 'session-provider-retry',
|
||||
prompt: 'continue from the app',
|
||||
runtime: {
|
||||
...steerRuntime,
|
||||
source: 'project-supervisor-cli',
|
||||
},
|
||||
runProfile: 'autonomous-game-build',
|
||||
source: 'project-supervisor-game-chat',
|
||||
});
|
||||
expect(invoke).toHaveBeenCalledWith(
|
||||
'start_game_creator_supervisor_runtime_task',
|
||||
expect.objectContaining({ source: 'project-supervisor-game-chat' }),
|
||||
);
|
||||
});
|
||||
|
||||
test('game-chat hydration keeps identical text from a different runtime response identity', () => {
|
||||
@@ -178,10 +198,9 @@ describe('Game Chat stream identity and source', () => {
|
||||
},
|
||||
];
|
||||
|
||||
expect(mergeGameChatRuntimeResponseMessagesIntoHistory(history, pending)).toEqual([
|
||||
pending[0],
|
||||
history[0],
|
||||
]);
|
||||
expect(
|
||||
mergeGameChatRuntimeResponseMessagesIntoHistory(history, pending),
|
||||
).toEqual([pending[0], history[0]]);
|
||||
expect(
|
||||
mergeGameChatRuntimeResponseMessagesIntoHistory(history, [
|
||||
{ ...pending[0], messageId: 'persisted-message-1' },
|
||||
|
||||
@@ -471,9 +471,7 @@ function createProjectSupervisorRuntimeHarness({
|
||||
currentProjectMessages.push({
|
||||
schemaVersion: 'game-creator-conversation.v1',
|
||||
...message,
|
||||
...(args?.messageId
|
||||
? { messageId: String(args.messageId) }
|
||||
: {}),
|
||||
...(args?.messageId ? { messageId: String(args.messageId) } : {}),
|
||||
updatedAt:
|
||||
typeof message.updatedAt === 'number'
|
||||
? message.updatedAt
|
||||
@@ -517,6 +515,7 @@ function createProjectSupervisorRuntimeHarness({
|
||||
currentRuntime = runtimeState({
|
||||
runId,
|
||||
runProfile: args?.runProfile,
|
||||
source: args?.source,
|
||||
status: 'running',
|
||||
phase: 'planning',
|
||||
currentTask: String(args?.task ?? ''),
|
||||
|
||||
@@ -92,7 +92,7 @@ function gameChatRuntimeEvent({
|
||||
runId,
|
||||
source:
|
||||
agentId === 'project-supervisor'
|
||||
? 'project-supervisor'
|
||||
? 'project-supervisor-game-chat'
|
||||
: 'agent-delegate',
|
||||
eventId,
|
||||
eventType,
|
||||
@@ -114,7 +114,7 @@ function gameChatRuntimeState(
|
||||
taskId: 'project-supervisor',
|
||||
sessionId: 'game-chat-supervisor-session',
|
||||
runId: 'game-chat-supervisor-run',
|
||||
source: 'project-supervisor',
|
||||
source: 'project-supervisor-game-chat',
|
||||
status: 'running',
|
||||
phase: 'execution',
|
||||
currentTask: '生成首版游戏',
|
||||
|
||||
@@ -3772,6 +3772,7 @@
|
||||
- Provider action 安全持久化补充:pending / provider action 的泄密检测不能因裸自然语言短语 `api key` 直接拒绝,否则 `agent.delegate` 中“不要暴露 External Editor API Key”等安全约束会被误报并阻断首批协作。赋值形式只允许完整匹配受控的“未配置 / 不可用 / 禁止读取”等状态或固定无密钥降级说明,不能用 `starts_with` 放行 `none-but-secret`、`not configured; actual value ...` 等安全前缀后的凭据;`**API Key**:`、`` `API Key`: ``、`API Key(生产):` 等装饰或限定标签也必须识别为赋值。结构化字段标记 `apiKey / api_key`、`Authorization / Cookie`、`token / Bearer` 以及已知 secret token 形状仍必须检测并失败关闭。
|
||||
- Windows retry 扫描补充:`Path::strip_prefix(root)` 在 Windows 上得到的相对 `Path` 转字符串后使用反斜杠,不能直接传给只接受 portable `/` 的 Runtime JSON sidecar 读取器;否则 Runner 重启或显式 `--agent-resume` 扫描已到期 retry 时会报“项目文件路径不能包含反斜杠”,任务持续停在 `waiting-for-provider-retry`。目录扫描应按路径组件重组成 `/` 分隔的 UTF-8 相对路径,不要放宽全局路径校验。
|
||||
- 恢复交互:`needs-reconciliation` 即使没有 `pendingToolAction`,也必须提供显式“已核对,结束旧任务”;它只取消旧 run,不直接 retry。若取消后仍有 pending task,由 Runner 自动继续;只有队列为空且旧 run 已取消时,才允许创建新的 retry run,避免重复执行同一用户输入。自主构建 Supervisor 的 retry 不能改写为普通 `agent-background-task` source,必须从已验证的原 Run Profile 绑定恢复 `project-supervisor-gui / project-supervisor-cli` 可信来源;不得只信可追加的 task journal。
|
||||
- Steer source:前端选择可 steer Runtime 时不能只比较 Agent、Session 和 Run Profile,还必须在调用方声明 source 时精确比较持久 `source`。例如 game-chat 只能 steer `project-supervisor-game-chat`,不能把同 Session/Profile 的 `project-supervisor-cli` run 当成目标;source 不一致时应按当前入口新建或排队自己的 run,不能先调用后端再把“steer source 与当前 Run 不一致”暴露给用户。
|
||||
- 验证:前端回归同时覆盖零历史、无 Session 的初始空态、无 active Session 索引但存在持久 `needs-reconciliation` 总控 Runtime 的恢复展示,以及“先取消、队列为空后才重试”;真实 Windows 运行全部 tool-plan handoff 测试,确保相对句柄 rename、覆盖安装、回读和清理均通过。Responses 回归覆盖 system / user / assistant 文本分别序列化,并保留 user `input_text + input_image`;Runtime 回归覆盖“无效计划 → repair transport 等待 → steer → 新 cursor 再修复”,断言 cursor `0 / 1` 各有一条审计且不冲突。
|
||||
|
||||
## 固定画布产物返工不能变成任意覆盖,design-foundation 不能越权修程序
|
||||
|
||||
Reference in New Issue
Block a user