feat: add workflow-wave-plan skill and A2UI debug logging

- Add CSV Wave planning and execution skill (explore via wave → conflict
  resolution → execution CSV with linked exploration context)
- Add debug NDJSON logging for A2UI submit-all and multi-answer polling
This commit is contained in:
catlog22
2026-02-28 11:40:28 +08:00
parent 0a37bc3eaf
commit 67e78b132c
3 changed files with 920 additions and 54 deletions

View File

@@ -611,8 +611,29 @@ export function handleAnswer(answer: QuestionAnswer): boolean {
* @returns True if answer was processed
*/
export function handleMultiAnswer(compositeId: string, answers: QuestionAnswer[]): boolean {
const handleStartTime = Date.now();
// DEBUG: NDJSON log for handleMultiAnswer start
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level: 'DEBUG',
hid: 'H3',
event: 'handle_multi_answer_start',
compositeId,
answerCount: answers.length
}));
const pending = getPendingQuestion(compositeId);
if (!pending) {
// DEBUG: NDJSON log for missing pending question
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level: 'DEBUG',
hid: 'H3',
event: 'handle_multi_answer_no_pending',
compositeId,
elapsedMs: Date.now() - handleStartTime
}));
return false;
}
@@ -625,6 +646,17 @@ export function handleMultiAnswer(compositeId: string, answers: QuestionAnswer[]
});
removePendingQuestion(compositeId);
// DEBUG: NDJSON log for handleMultiAnswer complete
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level: 'DEBUG',
hid: 'H3',
event: 'handle_multi_answer_complete',
compositeId,
elapsedMs: Date.now() - handleStartTime
}));
return true;
}
@@ -637,9 +669,24 @@ export function handleMultiAnswer(compositeId: string, answers: QuestionAnswer[]
*/
function startAnswerPolling(questionId: string, isComposite: boolean = false): void {
const pollPath = `/api/a2ui/answer?questionId=${encodeURIComponent(questionId)}&composite=${isComposite}`;
const startTime = Date.now();
// DEBUG: NDJSON log for polling start
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level: 'DEBUG',
hid: 'H1',
event: 'polling_start',
questionId,
isComposite,
port: DASHBOARD_PORT,
firstPollDelayMs: POLL_INTERVAL_MS
}));
console.error(`[A2UI-Poll] Starting polling for questionId=${questionId}, composite=${isComposite}, port=${DASHBOARD_PORT}`);
let pollCount = 0;
const poll = () => {
// Stop if the question was already resolved or timed out
if (!hasPendingQuestion(questionId)) {
@@ -647,6 +694,20 @@ function startAnswerPolling(questionId: string, isComposite: boolean = false): v
return;
}
pollCount++;
const pollStartTime = Date.now();
// DEBUG: NDJSON log for each poll attempt
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level: 'DEBUG',
hid: 'H1',
event: 'poll_attempt',
questionId,
pollCount,
elapsedMs: pollStartTime - startTime
}));
const req = http.get({ hostname: '127.0.0.1', port: DASHBOARD_PORT, path: pollPath, timeout: 2000 }, (res) => {
let data = '';
res.on('data', (chunk: Buffer) => { data += chunk.toString(); });
@@ -667,6 +728,20 @@ function startAnswerPolling(questionId: string, isComposite: boolean = false): v
console.error(`[A2UI-Poll] Answer received for questionId=${questionId}:`, JSON.stringify(parsed).slice(0, 200));
// DEBUG: NDJSON log for answer received
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level: 'DEBUG',
hid: 'H1',
event: 'answer_received',
questionId,
pollCount,
elapsedMs: Date.now() - startTime,
pollLatencyMs: Date.now() - pollStartTime,
isComposite,
answerPreview: JSON.stringify(parsed).slice(0, 100)
}));
if (isComposite && Array.isArray(parsed.answers)) {
const ok = handleMultiAnswer(questionId, parsed.answers as QuestionAnswer[]);
console.error(`[A2UI-Poll] handleMultiAnswer result: ${ok}`);