Files
Genarrative/apps/ai-game-creator-shell/src/features/app-shell/developerAgentControls.ts
T
suzmii c2354f855f 收敛 AGC 官方 LLM Router 账号链路
新增 llm_router_account 表、procedures 与客户端绑定
api-server 改为 New API 管理员流程签发独立 Router 账号
Router 成功后执行幂等后置泥点扣费
生产外锁定非生产 Router 控制面为 loopback
AGC 正式模式清除手工 Provider 凭据并锁定官方代理
AGC 状态面只返回账号凭据与官方路由安全元数据
后台数据库表查询适配账号凭据状态展示
补充 AGC 与后端测试、环境示例和架构文档
修正 dev-stack 状态路径按仓库脚本位置解析
2026-09-01 12:03:07 +08:00

984 lines
31 KiB
TypeScript

import { type FormEvent } from 'react';
import { resolveTauriInvoke } from '../../app/tauri';
import type {
AgentChatPendingRuntimeRun,
AgentConversationSessionRecord,
AgentGoalMutationResult,
AgentRuntimeContextCompactionResult,
AgentRuntimeResult,
AgentRuntimeUserInputRequest,
LauncherAgentChatAgent,
LocalConversationResult,
TauriInvoke,
} from '../../app/types';
import {
agentGoalStatusIsPaused,
agentGoalStatusIsTerminal,
agentRuntimeCancelStatus,
agentRuntimeConversationStatus,
agentRuntimeStartStatus,
agentRuntimeStateFromResult,
createAgentChatRunId,
isAgentRuntimeTerminalState,
mergeAgentGoalRecordFromRuntime,
parseAgentGoalItems,
} from '../agent-runtime';
import type { DeveloperAgentState } from './useDeveloperAgentState';
type DeveloperAgentControlOptions = {
state: DeveloperAgentState;
validateAgentChatProjectPath: (projectPath?: string) => string | null;
selectedLauncherAgentChatAgent: (
agentId?: string,
) => LauncherAgentChatAgent | null;
selectedLauncherAgentChatSession: (
sessionId?: string | null,
) => AgentConversationSessionRecord | null;
agentChatSessionInvokeArgs: (sessionId: string | null) => {
sessionId?: string;
};
updateAgentChatSessionMessageCount: (
sessionId: string | null,
messageCount: number,
) => void;
getCurrentAgentChatLlmWarning: (
agent?: LauncherAgentChatAgent | null,
) => string | null;
setAgentChatPendingRuntimeRun: (
pendingRun: AgentChatPendingRuntimeRun | null,
) => void;
};
export function createDeveloperAgentControls({
state,
validateAgentChatProjectPath,
selectedLauncherAgentChatAgent,
selectedLauncherAgentChatSession,
agentChatSessionInvokeArgs,
updateAgentChatSessionMessageCount,
getCurrentAgentChatLlmWarning,
setAgentChatPendingRuntimeRun,
}: DeveloperAgentControlOptions) {
const {
agentChatMessages,
setAgentChatMessages,
agentChatSelectedSessionId,
setAgentChatConversationPath,
setAgentChatInteractionMode,
setAgentChatStatus,
agentChatBusy,
agentChatBackgroundBusy,
setAgentChatBackgroundBusy,
agentChatRuntime,
setAgentChatRuntime,
setAgentChatActiveRuntime,
setAgentChatRuntimeError,
agentChatGoal,
setAgentChatGoal,
agentChatGoalError,
setAgentChatGoalError,
agentChatGoalDialog,
setAgentChatGoalDialog,
setAgentChatGoalDialogError,
agentChatLoadVersionRef,
agentChatProjectPathRef,
agentChatSelectedAgentIdRef,
agentChatSelectedSessionIdRef,
agentChatActiveSessionIdRef,
agentChatPendingRuntimeRunRef,
} = state;
function applyAgentChatGoalMutationResult(result: AgentGoalMutationResult) {
const runtimeState = agentRuntimeStateFromResult(result.runtime);
setAgentChatGoal(result.goal);
setAgentChatGoalError('');
setAgentChatRuntime(runtimeState);
if (
agentChatActiveSessionIdRef.current === null ||
agentChatActiveSessionIdRef.current === result.goal.sessionId
) {
setAgentChatActiveRuntime(runtimeState);
}
setAgentChatRuntimeError('');
return runtimeState;
}
async function refreshAgentChatConversationAfterGoalMutation(
invoke: TauriInvoke,
projectPathForChat: string,
agentId: string,
sessionId: string,
saveVersion: number,
) {
const conversation = await invoke<LocalConversationResult>(
'read_local_conversation',
{
projectPath: projectPathForChat,
agentId,
sessionId,
},
);
if (
agentChatLoadVersionRef.current !== saveVersion ||
agentChatProjectPathRef.current.trim() !== projectPathForChat ||
agentChatSelectedAgentIdRef.current !== agentId ||
agentChatSelectedSessionIdRef.current !== sessionId
) {
return null;
}
setAgentChatMessages(conversation.messages);
setAgentChatConversationPath(conversation.path);
updateAgentChatSessionMessageCount(sessionId, conversation.messages.length);
return conversation;
}
function openAgentChatGoalDialog(mode: 'create' | 'edit') {
const projectPathForChat = validateAgentChatProjectPath();
const agent = selectedLauncherAgentChatAgent();
const session = selectedLauncherAgentChatSession();
const sessionId = agentChatSelectedSessionId;
if (
!projectPathForChat ||
!agent ||
!sessionId ||
agentChatBusy ||
agentChatBackgroundBusy
) {
if (!sessionId) {
setAgentChatStatus('请先读取并选择 Agent Session');
}
return;
}
if (session?.archivedAt !== null && session?.archivedAt !== undefined) {
setAgentChatStatus('已归档会话只能查看 Goal');
return;
}
if (agentChatGoalError) {
setAgentChatStatus(agentChatGoalError);
return;
}
if (mode === 'edit' && !agentChatGoal) {
setAgentChatStatus('当前 Session 没有可编辑的持久目标');
return;
}
if (
mode === 'create' &&
agentChatGoal &&
!agentGoalStatusIsTerminal(agentChatGoal.status)
) {
setAgentChatStatus('当前 Session 已有未结束的持久目标');
return;
}
const goal = mode === 'edit' ? agentChatGoal : null;
setAgentChatInteractionMode('goal');
setAgentChatGoalDialogError('');
setAgentChatGoalDialog({
mode,
projectPath: projectPathForChat,
agentId: agent.id,
sessionId,
goalId: goal?.goalId ?? null,
expectedRevision: goal?.revision ?? null,
outcome: goal?.outcome ?? '',
constraintsText: goal?.constraints.join('\n') ?? '',
verificationText: goal?.verification.join('\n') ?? '',
});
}
async function handleAgentChatGoalDialogSubmit(
event: FormEvent<HTMLFormElement>,
) {
event.preventDefault();
const dialog = agentChatGoalDialog;
if (!dialog || agentChatBusy || agentChatBackgroundBusy) {
return;
}
if (
agentChatProjectPathRef.current.trim() !== dialog.projectPath ||
agentChatSelectedAgentIdRef.current !== dialog.agentId ||
agentChatSelectedSessionIdRef.current !== dialog.sessionId
) {
setAgentChatGoalDialogError('Agent 或 Session 已变化,请关闭后重新打开');
return;
}
const outcome = dialog.outcome.trim();
const constraints = parseAgentGoalItems(dialog.constraintsText);
const verification = parseAgentGoalItems(dialog.verificationText);
if (!outcome) {
setAgentChatGoalDialogError('Outcome 不能为空');
return;
}
if ([...outcome].length > 4_000) {
setAgentChatGoalDialogError('Outcome 不能超过 4000 个字符');
return;
}
if (constraints.length > 8 || verification.length > 8) {
setAgentChatGoalDialogError('Constraints 和 Verification 各最多 8 条');
return;
}
if (
[...constraints, ...verification].some((item) => [...item].length > 1_000)
) {
setAgentChatGoalDialogError('每条约束或完成标准不能超过 1000 个字符');
return;
}
if (
new Set(constraints).size !== constraints.length ||
new Set(verification).size !== verification.length
) {
setAgentChatGoalDialogError('Constraints 或 Verification 不能重复');
return;
}
const llmWarning = getCurrentAgentChatLlmWarning(
selectedLauncherAgentChatAgent(dialog.agentId),
);
if (llmWarning) {
setAgentChatGoalDialogError(llmWarning);
return;
}
const invoke = resolveTauriInvoke();
if (!invoke) {
setAgentChatGoalDialogError('需要在 Tauri App 内运行');
return;
}
const saveVersion = agentChatLoadVersionRef.current + 1;
agentChatLoadVersionRef.current = saveVersion;
const previousPendingRun = agentChatPendingRuntimeRunRef.current;
setAgentChatBackgroundBusy(true);
setAgentChatGoalDialogError('');
setAgentChatStatus(
dialog.mode === 'create' ? '正在开始持久目标' : '正在更新持久目标',
);
try {
const result =
dialog.mode === 'create'
? await invoke<AgentGoalMutationResult>(
'start_game_creator_agent_goal',
{
projectPath: dialog.projectPath,
agentId: dialog.agentId,
sessionId: dialog.sessionId,
outcome,
constraints,
verification,
runId: createAgentChatRunId('launcher-agent-goal'),
},
)
: await invoke<AgentGoalMutationResult>(
'edit_game_creator_agent_goal',
{
projectPath: dialog.projectPath,
agentId: dialog.agentId,
sessionId: dialog.sessionId,
goalId: dialog.goalId,
expectedRevision: dialog.expectedRevision,
outcome,
constraints,
verification,
},
);
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
if (
result.goal.agentId !== dialog.agentId ||
result.goal.sessionId !== dialog.sessionId ||
(dialog.mode === 'edit' && result.goal.goalId !== dialog.goalId)
) {
throw new Error('Goal command 返回了错误的 Agent 或 Session 身份');
}
const runtimeState = applyAgentChatGoalMutationResult(result);
const conversation = await refreshAgentChatConversationAfterGoalMutation(
invoke,
dialog.projectPath,
dialog.agentId,
dialog.sessionId,
saveVersion,
);
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
if (agentGoalStatusIsPaused(result.goal.status)) {
if (
agentChatPendingRuntimeRunRef.current?.runId === result.goal.runId
) {
setAgentChatPendingRuntimeRun(null);
}
} else if (!agentGoalStatusIsTerminal(result.goal.status)) {
setAgentChatPendingRuntimeRun({
projectPath: dialog.projectPath,
agentId: dialog.agentId,
sessionId: dialog.sessionId,
runId: result.goal.runId || runtimeState.runId,
messageCount:
conversation?.messages.length ?? agentChatMessages.length,
});
}
setAgentChatGoalDialog(null);
setAgentChatGoalDialogError('');
setAgentChatStatus(
dialog.mode === 'create'
? `已开始持久目标:${result.goal.goalId}`
: `持久目标已更新到 Revision ${result.goal.revision}${
result.providerInterrupted ? ',智能服务已中断并重新规划' : ''
}`,
);
} catch (error) {
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
setAgentChatPendingRuntimeRun(previousPendingRun);
const message = error instanceof Error ? error.message : String(error);
setAgentChatGoalDialogError(message);
setAgentChatStatus(`持久目标操作失败:${message}`);
} finally {
if (agentChatLoadVersionRef.current === saveVersion) {
setAgentChatBackgroundBusy(false);
}
}
}
async function handleAgentChatGoalControl(
operation: 'pause' | 'resume' | 'clear',
) {
const projectPathForChat = validateAgentChatProjectPath();
const agent = selectedLauncherAgentChatAgent();
const session = selectedLauncherAgentChatSession();
const sessionId = agentChatSelectedSessionId;
const goal = agentChatGoal;
if (
!projectPathForChat ||
!agent ||
!sessionId ||
!goal ||
agentChatBusy ||
agentChatBackgroundBusy
) {
return;
}
if (session?.archivedAt !== null && session?.archivedAt !== undefined) {
setAgentChatStatus('已归档会话只能查看 Goal');
return;
}
if (goal.agentId !== agent.id || goal.sessionId !== sessionId) {
setAgentChatStatus('当前 Goal 与 Agent Session 身份不匹配,请刷新');
return;
}
const invoke = resolveTauriInvoke();
if (!invoke) {
setAgentChatStatus('需要在 Tauri App 内运行');
return;
}
const saveVersion = agentChatLoadVersionRef.current + 1;
agentChatLoadVersionRef.current = saveVersion;
setAgentChatBackgroundBusy(true);
setAgentChatStatus(
operation === 'pause'
? '正在暂停持久目标'
: operation === 'resume'
? '正在恢复持久目标'
: '正在清理持久目标',
);
try {
const args = {
projectPath: projectPathForChat,
agentId: agent.id,
sessionId,
goalId: goal.goalId,
expectedRevision: goal.revision,
};
const result =
operation === 'pause'
? await invoke<AgentGoalMutationResult>(
'pause_game_creator_agent_goal',
args,
)
: operation === 'resume'
? await invoke<AgentGoalMutationResult>(
'resume_game_creator_agent_goal',
args,
)
: await invoke<AgentGoalMutationResult>(
'clear_game_creator_agent_goal',
args,
);
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
if (
result.goal.goalId !== goal.goalId ||
result.goal.agentId !== agent.id ||
result.goal.sessionId !== sessionId
) {
throw new Error('Goal command 返回了错误的 Goal 身份');
}
applyAgentChatGoalMutationResult(result);
if (operation === 'pause') {
if (agentChatPendingRuntimeRunRef.current?.runId === goal.runId) {
setAgentChatPendingRuntimeRun(null);
}
} else if (operation === 'resume') {
setAgentChatPendingRuntimeRun({
projectPath: projectPathForChat,
agentId: agent.id,
sessionId,
runId: result.goal.runId,
messageCount: agentChatMessages.length,
});
} else if (result.goal.status === 'cleared') {
if (agentChatPendingRuntimeRunRef.current?.runId === goal.runId) {
setAgentChatPendingRuntimeRun(null);
}
} else {
setAgentChatPendingRuntimeRun({
projectPath: projectPathForChat,
agentId: agent.id,
sessionId,
runId: result.goal.runId,
messageCount: agentChatMessages.length,
});
}
setAgentChatStatus(
operation === 'pause'
? result.goal.status === 'paused'
? '持久目标已暂停'
: '持久目标正在安全边界暂停'
: operation === 'resume'
? '持久目标已恢复,同一 Run 正在继续'
: `持久目标清理状态:${result.goal.status}`,
);
} catch (error) {
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
setAgentChatStatus(
`持久目标操作失败:${
error instanceof Error ? error.message : String(error)
}`,
);
} finally {
if (agentChatLoadVersionRef.current === saveVersion) {
setAgentChatBackgroundBusy(false);
}
}
}
async function handleAgentChatCompactContext() {
const projectPathForChat = validateAgentChatProjectPath();
const agent = selectedLauncherAgentChatAgent();
const selectedSession = selectedLauncherAgentChatSession();
if (
!projectPathForChat ||
!agent ||
!selectedSession ||
selectedSession.archivedAt
) {
setAgentChatStatus('请选择可写的 Agent Session');
return;
}
const invoke = resolveTauriInvoke();
if (!invoke) {
setAgentChatStatus('上下文压缩需要在 Tauri App 内运行');
return;
}
setAgentChatBackgroundBusy(true);
setAgentChatStatus('正在压缩当前 Agent Session 的旧上下文');
try {
const result = await invoke<AgentRuntimeContextCompactionResult>(
'compact_game_creator_agent_runtime_context',
{
projectPath: projectPathForChat,
agentId: agent.id,
sessionId: selectedSession.sessionId,
},
);
const runtime = await invoke<AgentRuntimeResult>(
'read_game_creator_agent_runtime',
{
projectPath: projectPathForChat,
agentId: agent.id,
sessionId: selectedSession.sessionId,
},
);
setAgentChatRuntime((current) =>
agentRuntimeStateFromResult(runtime, current),
);
setAgentChatStatus(
result.reused
? `上下文已是最新压缩 revision ${result.revision}`
: `上下文压缩完成:revision ${result.revision},预计 ${result.estimatedTokensBefore} -> ${result.estimatedTokensAfter} tokens`,
);
} catch (error) {
setAgentChatStatus(
`上下文压缩失败:${
error instanceof Error ? error.message : String(error)
}`,
);
} finally {
setAgentChatBackgroundBusy(false);
}
}
async function handleAgentChatCancelRuntimeTask(runId: string) {
const projectPathForChat = validateAgentChatProjectPath();
const agent = selectedLauncherAgentChatAgent();
const selectedSession = selectedLauncherAgentChatSession();
if (
!projectPathForChat ||
!agent ||
!runId ||
agentChatBusy ||
agentChatBackgroundBusy
) {
return;
}
if (selectedSession && selectedSession.archivedAt !== null) {
setAgentChatStatus('已归档会话只能查看 Runtime 历史');
return;
}
const invoke = resolveTauriInvoke();
if (!invoke) {
setAgentChatStatus('需要在 Tauri App 内运行');
return;
}
const saveVersion = agentChatLoadVersionRef.current + 1;
agentChatLoadVersionRef.current = saveVersion;
setAgentChatBackgroundBusy(true);
setAgentChatStatus('正在取消 Agent 后台任务');
try {
const runtime = await invoke<AgentRuntimeResult>(
'cancel_game_creator_agent_runtime_task',
{
projectPath: projectPathForChat,
agentId: agent.id,
runId,
},
);
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
const runtimeState = agentRuntimeStateFromResult(runtime);
setAgentChatRuntime(runtimeState);
setAgentChatActiveRuntime(runtimeState);
setAgentChatGoal((current) =>
mergeAgentGoalRecordFromRuntime(current, runtimeState),
);
setAgentChatRuntimeError('');
setAgentChatStatus(agentRuntimeCancelStatus(runtimeState, runId));
} catch (error) {
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
setAgentChatStatus(
error instanceof Error ? error.message : String(error),
);
} finally {
if (agentChatLoadVersionRef.current === saveVersion) {
setAgentChatBackgroundBusy(false);
}
}
}
async function handleAgentChatRetryRuntimeTask(runId: string) {
const projectPathForChat = validateAgentChatProjectPath();
const agent = selectedLauncherAgentChatAgent();
const selectedSession = selectedLauncherAgentChatSession();
const sessionIdForTask = agentChatSelectedSessionId;
if (
!projectPathForChat ||
!agent ||
!runId ||
agentChatBusy ||
agentChatBackgroundBusy
) {
return;
}
if (selectedSession && selectedSession.archivedAt !== null) {
setAgentChatStatus('已归档会话不能重试任务');
return;
}
if (
agentGoalStatusIsPaused(agentChatGoal?.status) ||
agentGoalStatusIsPaused(agentChatRuntime?.goalStatus) ||
agentGoalStatusIsPaused(agentChatRuntime?.status) ||
agentGoalStatusIsPaused(agentChatRuntime?.phase)
) {
setAgentChatStatus('持久目标已暂停,请先恢复 Goal');
return;
}
const llmWarning = getCurrentAgentChatLlmWarning(agent);
if (llmWarning) {
setAgentChatStatus(llmWarning);
return;
}
const invoke = resolveTauriInvoke();
if (!invoke) {
setAgentChatStatus('需要在 Tauri App 内运行');
return;
}
const saveVersion = agentChatLoadVersionRef.current + 1;
agentChatLoadVersionRef.current = saveVersion;
setAgentChatBackgroundBusy(true);
setAgentChatStatus('正在重试 Agent 后台任务');
try {
const runtime = await invoke<AgentRuntimeResult>(
'retry_game_creator_agent_runtime_task',
{
projectPath: projectPathForChat,
agentId: agent.id,
runId,
nextRunId: createAgentChatRunId('launcher-agent-retry'),
},
);
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
const runtimeState = agentRuntimeStateFromResult(runtime);
setAgentChatRuntime(runtimeState);
setAgentChatActiveRuntime(runtimeState);
setAgentChatGoal((current) =>
mergeAgentGoalRecordFromRuntime(current, runtimeState),
);
setAgentChatRuntimeError('');
const conversation = await invoke<LocalConversationResult>(
'read_local_conversation',
{
projectPath: projectPathForChat,
agentId: agent.id,
...agentChatSessionInvokeArgs(sessionIdForTask),
},
);
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
setAgentChatMessages(conversation.messages);
setAgentChatStatus(agentRuntimeStartStatus(runtime));
} catch (error) {
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
setAgentChatStatus(
error instanceof Error ? error.message : String(error),
);
} finally {
if (agentChatLoadVersionRef.current === saveVersion) {
setAgentChatBackgroundBusy(false);
}
}
}
async function handleAgentChatConfirmRuntimeTask(
runId: string,
actionId: string,
) {
const projectPathForChat = validateAgentChatProjectPath();
const agent = selectedLauncherAgentChatAgent();
const selectedSession = selectedLauncherAgentChatSession();
const sessionIdForTask = agentChatSelectedSessionId;
if (
!projectPathForChat ||
!agent ||
!runId ||
!actionId ||
agentChatBusy ||
agentChatBackgroundBusy
) {
return;
}
if (selectedSession && selectedSession.archivedAt !== null) {
setAgentChatStatus('已归档会话不能确认工具动作');
return;
}
const llmWarning = getCurrentAgentChatLlmWarning(agent);
if (llmWarning) {
setAgentChatStatus(llmWarning);
return;
}
const invoke = resolveTauriInvoke();
if (!invoke) {
setAgentChatStatus('需要在 Tauri App 内运行');
return;
}
const saveVersion = agentChatLoadVersionRef.current + 1;
agentChatLoadVersionRef.current = saveVersion;
setAgentChatBackgroundBusy(true);
setAgentChatStatus('正在确认并继续 Agent 后台任务');
try {
const runtime = await invoke<AgentRuntimeResult>(
'confirm_game_creator_agent_runtime_task',
{
projectPath: projectPathForChat,
agentId: agent.id,
runId,
actionId,
note: '开发者已确认待执行工具动作',
},
);
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
const runtimeState = agentRuntimeStateFromResult(runtime);
setAgentChatRuntime(runtimeState);
setAgentChatActiveRuntime(runtimeState);
setAgentChatGoal((current) =>
mergeAgentGoalRecordFromRuntime(current, runtimeState),
);
setAgentChatRuntimeError('');
const conversation = await invoke<LocalConversationResult>(
'read_local_conversation',
{
projectPath: projectPathForChat,
agentId: agent.id,
...agentChatSessionInvokeArgs(sessionIdForTask),
},
);
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
setAgentChatMessages(conversation.messages);
setAgentChatStatus(agentRuntimeStartStatus(runtime));
} catch (error) {
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
setAgentChatStatus(
error instanceof Error ? error.message : String(error),
);
} finally {
if (agentChatLoadVersionRef.current === saveVersion) {
setAgentChatBackgroundBusy(false);
}
}
}
async function handleAgentChatRejectRuntimeTask(
runId: string,
actionId: string,
) {
const projectPathForChat = validateAgentChatProjectPath();
const agent = selectedLauncherAgentChatAgent();
const selectedSession = selectedLauncherAgentChatSession();
const sessionIdForTask = agentChatSelectedSessionId;
if (
!projectPathForChat ||
!agent ||
!runId ||
!actionId ||
agentChatBusy ||
agentChatBackgroundBusy
) {
return;
}
if (selectedSession && selectedSession.archivedAt !== null) {
setAgentChatStatus('已归档会话不能拒绝工具动作');
return;
}
const llmWarning = getCurrentAgentChatLlmWarning(agent);
if (llmWarning) {
setAgentChatStatus(llmWarning);
return;
}
const invoke = resolveTauriInvoke();
if (!invoke) {
setAgentChatStatus('需要在 Tauri App 内运行');
return;
}
const saveVersion = agentChatLoadVersionRef.current + 1;
agentChatLoadVersionRef.current = saveVersion;
setAgentChatBackgroundBusy(true);
setAgentChatStatus('正在拒绝工具动作并继续 Agent 后台任务');
try {
const runtime = await invoke<AgentRuntimeResult>(
'reject_game_creator_agent_runtime_task',
{
projectPath: projectPathForChat,
agentId: agent.id,
runId,
actionId,
note: '开发者拒绝待执行工具动作',
},
);
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
const runtimeState = agentRuntimeStateFromResult(runtime);
setAgentChatRuntime(runtimeState);
setAgentChatActiveRuntime(runtimeState);
setAgentChatGoal((current) =>
mergeAgentGoalRecordFromRuntime(current, runtimeState),
);
setAgentChatRuntimeError('');
const conversation = await invoke<LocalConversationResult>(
'read_local_conversation',
{
projectPath: projectPathForChat,
agentId: agent.id,
...agentChatSessionInvokeArgs(sessionIdForTask),
},
);
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
setAgentChatMessages(conversation.messages);
setAgentChatStatus(agentRuntimeStartStatus(runtime));
} catch (error) {
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
setAgentChatStatus(
error instanceof Error ? error.message : String(error),
);
} finally {
if (agentChatLoadVersionRef.current === saveVersion) {
setAgentChatBackgroundBusy(false);
}
}
}
async function handleAgentChatSubmitUserInput(
request: AgentRuntimeUserInputRequest,
responseId: string,
answers: Record<string, string>,
) {
const projectPathForChat = validateAgentChatProjectPath();
const agent = selectedLauncherAgentChatAgent();
const selectedSession = selectedLauncherAgentChatSession();
const sessionIdForTask = agentChatSelectedSessionId;
const currentRequest = agentChatRuntime?.userInputRequest;
if (
!projectPathForChat ||
!agent ||
!sessionIdForTask ||
!responseId ||
agentChatBusy ||
agentChatBackgroundBusy
) {
return;
}
if (selectedSession && selectedSession.archivedAt !== null) {
setAgentChatStatus('已归档会话不能回答 Agent 问题');
return;
}
if (
request.agentId !== agent.id ||
request.sessionId !== sessionIdForTask ||
request.runId !== agentChatRuntime?.runId ||
currentRequest?.requestId !== request.requestId ||
currentRequest?.actionId !== request.actionId
) {
setAgentChatRuntimeError('待回答请求已变更,请刷新 Runtime 状态');
return;
}
const invoke = resolveTauriInvoke();
if (!invoke) {
setAgentChatStatus('需要在 Tauri App 内运行');
return;
}
const saveVersion = agentChatLoadVersionRef.current + 1;
agentChatLoadVersionRef.current = saveVersion;
const previousPendingRun = agentChatPendingRuntimeRunRef.current;
setAgentChatPendingRuntimeRun({
projectPath: projectPathForChat,
agentId: agent.id,
sessionId: sessionIdForTask,
runId: request.runId,
messageCount: agentChatMessages.length,
});
setAgentChatBackgroundBusy(true);
setAgentChatRuntimeError('');
setAgentChatStatus('正在提交回答并继续当前 Run');
try {
const result = await invoke<AgentRuntimeResult>(
'answer_game_creator_agent_runtime_user_input',
{
projectPath: projectPathForChat,
agentId: agent.id,
runId: request.runId,
actionId: request.actionId,
requestId: request.requestId,
responseId,
answers,
},
);
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
const runtimeState = agentRuntimeStateFromResult(
result,
agentChatRuntime,
);
if (
runtimeState.agentId !== agent.id ||
runtimeState.sessionId !== sessionIdForTask ||
runtimeState.runId !== request.runId
) {
throw new Error('Agent 回答后 Runtime 身份不匹配');
}
setAgentChatRuntime(runtimeState);
if (
agentChatActiveSessionIdRef.current === null ||
agentChatActiveSessionIdRef.current === sessionIdForTask
) {
setAgentChatActiveRuntime(runtimeState);
}
setAgentChatGoal((current) =>
mergeAgentGoalRecordFromRuntime(current, runtimeState),
);
const conversation = await invoke<LocalConversationResult>(
'read_local_conversation',
{
projectPath: projectPathForChat,
agentId: agent.id,
sessionId: sessionIdForTask,
},
);
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
setAgentChatMessages(conversation.messages);
setAgentChatConversationPath(conversation.path);
updateAgentChatSessionMessageCount(
sessionIdForTask,
conversation.messages.length,
);
setAgentChatPendingRuntimeRun(
isAgentRuntimeTerminalState(runtimeState)
? null
: {
projectPath: projectPathForChat,
agentId: agent.id,
sessionId: sessionIdForTask,
runId: request.runId,
messageCount: conversation.messages.length,
},
);
setAgentChatRuntimeError('');
setAgentChatStatus(agentRuntimeConversationStatus(runtimeState));
} catch (error) {
if (agentChatLoadVersionRef.current !== saveVersion) {
return;
}
setAgentChatPendingRuntimeRun(previousPendingRun);
const message = error instanceof Error ? error.message : String(error);
setAgentChatRuntimeError(message);
setAgentChatStatus(`回答提交失败:${message}`);
} finally {
if (agentChatLoadVersionRef.current === saveVersion) {
setAgentChatBackgroundBusy(false);
}
}
}
return {
openAgentChatGoalDialog,
handleAgentChatGoalDialogSubmit,
handleAgentChatGoalControl,
handleAgentChatCompactContext,
handleAgentChatCancelRuntimeTask,
handleAgentChatRetryRuntimeTask,
handleAgentChatConfirmRuntimeTask,
handleAgentChatRejectRuntimeTask,
handleAgentChatSubmitUserInput,
};
}