feat: complete Aider Page Data review workflow

This commit is contained in:
john
2026-07-25 09:47:25 +08:00
parent be9c25f1d0
commit 104fb4e370
15 changed files with 914 additions and 30 deletions
+6 -2
View File
@@ -2,7 +2,11 @@ import { ChangeEvent, useCallback, useEffect, useLayoutEffect, useRef, useState,
import { BrainCircuit, Database, Image, ImageOff, ImagePlus } from 'lucide-react';
import { useNetworkStatus } from '../hooks/useNetworkStatus';
import { openAvatarPicker } from '../utils/userAvatar';
import { CHAT_SKILL_OPTIONS, filterChatSkills } from '../utils/chatSkills';
import {
CHAT_SKILL_OPTIONS,
filterChatSkills,
mergeChatSkillPromptWithInput,
} from '../utils/chatSkills';
import { getMessageSaveActions } from '../utils/messageSave';
import { getDisplayText } from '../utils/message';
import {
@@ -1242,7 +1246,7 @@ export function ChatPanel({
onSelect={submitText}
onPrefill={(prompt, skillId) => {
pendingSkillRef.current = skillId ?? null;
setInput(prompt);
setInput((current) => mergeChatSkillPromptWithInput(prompt, current));
}}
/>
)}
+35 -5
View File
@@ -117,6 +117,7 @@ async function waitForAgentRun(runId: string): Promise<AgentRun> {
}
const DIRECT_CHAT_SESSION_POLL_MS = 600;
const AGENT_RUN_STATUS_POLL_MS = 1_500;
const AGENT_RUN_WAIT_TIMEOUT_MS = 16 * 60 * 1000;
async function waitForAgentRunWithDirectChatPreview(
@@ -129,6 +130,8 @@ async function waitForAgentRunWithDirectChatPreview(
): Promise<AgentRun> {
return await new Promise<AgentRun>((resolve, reject) => {
let pollTimer: number | null = null;
let runStatusPollTimer: number | null = null;
let runStatusPollInFlight = false;
let waitTimer: number | null = null;
let pollingSessionId: string | null = null;
let settled = false;
@@ -138,6 +141,7 @@ async function waitForAgentRunWithDirectChatPreview(
if (settled) return;
settled = true;
stopPoll();
stopRunStatusPoll();
if (waitTimer != null) {
window.clearTimeout(waitTimer);
waitTimer = null;
@@ -153,6 +157,13 @@ async function waitForAgentRunWithDirectChatPreview(
}
};
const stopRunStatusPoll = () => {
if (runStatusPollTimer != null) {
window.clearInterval(runStatusPollTimer);
runStatusPollTimer = null;
}
};
const startPolling = (sessionId: string) => {
if (pollingSessionId === sessionId && pollTimer != null) return;
pollingSessionId = sessionId;
@@ -175,9 +186,7 @@ async function waitForAgentRunWithDirectChatPreview(
}, DIRECT_CHAT_SESSION_POLL_MS);
};
unsubscribe = subscribeAgentRunEvents(
runId,
(run) => {
const handleRunStatus = (run: AgentRun) => {
if (run.sessionId) {
handlers.onSessionId?.(run.sessionId);
if (isDirectChatSessionId(run.sessionId)) {
@@ -191,11 +200,32 @@ async function waitForAgentRunWithDirectChatPreview(
if (run.status === 'failed') {
settle(() => reject(new Error(run.error || '后台任务失败,请稍后重试')));
}
},
};
const pollRunStatus = () => {
if (settled || runStatusPollInFlight || handlers.isCancelled?.()) return;
runStatusPollInFlight = true;
void getAgentRun(runId)
.then(handleRunStatus)
.catch(() => {
// SSE remains primary; polling only closes terminal-state gaps.
})
.finally(() => {
runStatusPollInFlight = false;
});
};
unsubscribe = subscribeAgentRunEvents(
runId,
handleRunStatus,
(error) => {
settle(() => reject(error));
void getAgentRun(runId)
.then(handleRunStatus)
.catch(() => settle(() => reject(error)));
},
);
runStatusPollTimer = window.setInterval(pollRunStatus, AGENT_RUN_STATUS_POLL_MS);
pollRunStatus();
waitTimer = window.setTimeout(() => {
void getAgentRun(runId)
+4 -2
View File
@@ -291,6 +291,7 @@ export function resolveAgentRunOptions(
{
taskType = 'code_task',
forceCode = false,
requiredExecutor,
allowAutodetect = clientCodeRunsAutodetectEnabled(),
allowPageDataDevAutodetect = clientPageDataDevAutodetectEnabled(),
userId = null,
@@ -310,8 +311,9 @@ export function resolveAgentRunOptions(
} = {},
): AgentRunCreateOptions {
const normalizedText = String(text ?? '').trim();
const pageDataDevTaskType =
allowPageDataDevAutodetect && resolvePageDataDevTaskType(normalizedText);
const pageDataDevTaskType = allowPageDataDevAutodetect
? resolvePageDataDevTaskType(normalizedText)
: null;
const effectiveTaskType = pageDataDevTaskType ?? taskType;
const shouldUseDeepReasoning =
forceCode ||
+2
View File
@@ -2,6 +2,7 @@ import {
buildChatSkillPrompt,
CHAT_SKILL_DEFINITIONS,
filterChatSkills as filterChatSkillDefinitions,
mergeChatSkillPromptWithInput,
} from '../../chat-skills.mjs';
import { buildPublishSkillPrompt, PUBLISH_SKILL_NAME } from './publishSkill';
@@ -45,3 +46,4 @@ export function filterChatSkills(
}
export { buildPublishSkillPrompt, PUBLISH_SKILL_NAME };
export { mergeChatSkillPromptWithInput };