aiexecode 1.0.56 → 1.0.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of aiexecode might be problematic. Click here for more details.
- package/index.js +3 -3
- package/package.json +1 -1
- package/payload_viewer/out/404/index.html +1 -1
- package/payload_viewer/out/404.html +1 -1
- package/payload_viewer/out/index.html +1 -1
- package/payload_viewer/out/index.txt +1 -1
- package/prompts/completion_judge.txt +90 -0
- package/prompts/orchestrator.backup.txt +1 -1
- package/prompts/orchestrator.txt +180 -316
- package/src/ai_based/completion_judge.js +247 -0
- package/src/ai_based/orchestrator.js +20 -4
- package/src/system/ai_request.js +9 -0
- package/src/system/session.js +198 -175
- package/src/system/session_memory.js +16 -37
- package/src/tools/code_editor.js +2 -2
- package/src/tools/response_message.js +2 -2
- package/src/tools/ripgrep.js +12 -39
- package/src/ui/components/HistoryItemDisplay.js +2 -3
- package/src/ui/components/ToolApprovalPrompt.js +1 -4
- package/prompts/verifier.txt +0 -216
- package/src/ai_based/verifier.js +0 -210
- /package/payload_viewer/out/_next/static/{h5BNZL0hrewfv11rqfUcZ → gC8Fl_NIZc7G-mf4T7lFP}/_buildManifest.js +0 -0
- /package/payload_viewer/out/_next/static/{h5BNZL0hrewfv11rqfUcZ → gC8Fl_NIZc7G-mf4T7lFP}/_clientMiddlewareManifest.json +0 -0
- /package/payload_viewer/out/_next/static/{h5BNZL0hrewfv11rqfUcZ → gC8Fl_NIZc7G-mf4T7lFP}/_ssgManifest.js +0 -0
package/src/system/session.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Agent Loop: 계획·실행·검증 사이클을 수행하는 핵심 모듈
|
|
2
2
|
import { orchestrateMission, continueOrchestratorConversation, resetOrchestratorConversation, recordOrchestratorToolResult, getOrchestratorConversation, restoreOrchestratorConversation } from "../ai_based/orchestrator.js";
|
|
3
|
-
import {
|
|
3
|
+
import { judgeMissionCompletion } from "../ai_based/completion_judge.js";
|
|
4
4
|
import { execPythonCode, execShellScript } from "./code_executer.js";
|
|
5
5
|
import { FILE_READER_FUNCTIONS } from "../tools/file_reader.js";
|
|
6
6
|
import { RIPGREP_FUNCTIONS } from "../tools/ripgrep.js";
|
|
@@ -12,7 +12,7 @@ import { clampOutput, formatToolStdout } from "../util/output_formatter.js";
|
|
|
12
12
|
import { buildToolHistoryEntry } from "../util/rag_helper.js";
|
|
13
13
|
import { createSessionData, getLastConversationState, loadPreviousSessions, saveSessionToHistory } from "./session_memory.js";
|
|
14
14
|
import { uiEvents } from "./ui_events.js";
|
|
15
|
-
import { logSystem, logInfo, logSuccess, logWarning, logError, logAssistantMessage, logToolCall, logToolResult, logCodeExecution, logCodeResult, logIteration,
|
|
15
|
+
import { logSystem, logInfo, logSuccess, logWarning, logError, logAssistantMessage, logToolCall, logToolResult, logCodeExecution, logCodeResult, logIteration, logMissionComplete, logConversationRestored } from "./output_helper.js";
|
|
16
16
|
import { requiresApproval, requestApproval } from "./tool_approval.js";
|
|
17
17
|
import { setCurrentSession, saveFileSnapshot, getFileSnapshot } from "./file_integrity.js";
|
|
18
18
|
import { abortCurrentRequest } from "./ai_request.js";
|
|
@@ -23,18 +23,10 @@ import { ERROR_VERBOSITY } from '../config/feature_flags.js';
|
|
|
23
23
|
|
|
24
24
|
const debugLog = createDebugLogger('session.log', 'session');
|
|
25
25
|
|
|
26
|
-
/**
|
|
27
|
-
* Verifier 사용 여부를 제어하는 상수
|
|
28
|
-
* true: Verifier를 통한 검증 사이클 활성화
|
|
29
|
-
* false: Verifier 없이 Orchestrator만 실행 (각 iteration마다 자동으로 다음 단계 진행)
|
|
30
|
-
*/
|
|
31
|
-
const ENABLE_VERIFIER = false;
|
|
32
|
-
|
|
33
26
|
/**
|
|
34
27
|
* 상수 정의
|
|
35
28
|
*/
|
|
36
29
|
const MAX_REASONING_ONLY_RESPONSES = 5;
|
|
37
|
-
const MAX_WHAT_IT_DID_HISTORY = 12;
|
|
38
30
|
const DEFAULT_MAX_ITERATIONS = 50;
|
|
39
31
|
const SUB_MISSION_MAX_LENGTH = 120;
|
|
40
32
|
|
|
@@ -96,13 +88,15 @@ function cleanupExecutionResult(exeResult, rawStdout, rawStderr) {
|
|
|
96
88
|
|
|
97
89
|
/**
|
|
98
90
|
* 메시지 타입 출력을 처리하는 함수
|
|
91
|
+
* @param {Object} output - 메시지 출력 객체
|
|
92
|
+
* @param {boolean} shouldOutput - 메시지를 출력할지 여부 (기본값: false, completion_judge 판단 후 결정)
|
|
99
93
|
*/
|
|
100
|
-
function processMessageOutput(output) {
|
|
94
|
+
function processMessageOutput(output, shouldOutput = false) {
|
|
101
95
|
const rawMessage = output.content?.[0]?.text ?? '';
|
|
102
96
|
const truncatedMessage = clampOutput(rawMessage);
|
|
103
97
|
|
|
104
|
-
// 빈 메시지가 아닐 때만 로그 출력
|
|
105
|
-
if (rawMessage.trim()) {
|
|
98
|
+
// shouldOutput이 true이고 빈 메시지가 아닐 때만 로그 출력
|
|
99
|
+
if (shouldOutput && rawMessage.trim()) {
|
|
106
100
|
logAssistantMessage(truncatedMessage);
|
|
107
101
|
}
|
|
108
102
|
|
|
@@ -309,23 +303,6 @@ async function processCodeExecution(name, argument, toolMap) {
|
|
|
309
303
|
}
|
|
310
304
|
|
|
311
305
|
|
|
312
|
-
/**
|
|
313
|
-
* 검증 결과 상태 맵
|
|
314
|
-
*/
|
|
315
|
-
const VERIFICATION_DECISION_STATUS = {
|
|
316
|
-
'MISSION_COMPLETE': '✅ Complete',
|
|
317
|
-
'SUBMISSION_COMPLETE': '✅ Subtask Complete',
|
|
318
|
-
'IN_PROGRESS': '⏳ In Progress',
|
|
319
|
-
'REPLAN_NEEDED': '🔄 Needs Replanning'
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* 루프 제어 결과 타입 정의
|
|
324
|
-
*/
|
|
325
|
-
const LOOP_CONTROL = {
|
|
326
|
-
CONTINUE: 'continue',
|
|
327
|
-
BREAK: 'break'
|
|
328
|
-
};
|
|
329
306
|
|
|
330
307
|
/**
|
|
331
308
|
* Orchestrator 응답을 처리하는 함수
|
|
@@ -359,6 +336,8 @@ async function processOrchestratorResponses(params) {
|
|
|
359
336
|
let hadAnyFunctionCall = false;
|
|
360
337
|
let stallDetected = false;
|
|
361
338
|
let missionSolved = false;
|
|
339
|
+
let improvementPoints = '';
|
|
340
|
+
let improvementPointsIsAutoGenerated = false;
|
|
362
341
|
|
|
363
342
|
debugLog(`Starting response processing loop...`);
|
|
364
343
|
let loopIteration = 0;
|
|
@@ -416,6 +395,7 @@ async function processOrchestratorResponses(params) {
|
|
|
416
395
|
reasoningOnlyResponses = 0;
|
|
417
396
|
let executedFunctionCall = false;
|
|
418
397
|
let lastOutputType = null;
|
|
398
|
+
let pendingMessageOutput = null; // 출력 대기 중인 MESSAGE 저장
|
|
419
399
|
|
|
420
400
|
// 각 출력 처리
|
|
421
401
|
for (let outputIndex = 0; outputIndex < outputs.length; outputIndex++) {
|
|
@@ -445,11 +425,13 @@ async function processOrchestratorResponses(params) {
|
|
|
445
425
|
let content;
|
|
446
426
|
|
|
447
427
|
if (MESSAGE) {
|
|
448
|
-
debugLog(` Processing MESSAGE output...`);
|
|
449
|
-
|
|
428
|
+
debugLog(` Processing MESSAGE output (without displaying)...`);
|
|
429
|
+
// 출력하지 않고 저장만 함 (shouldOutput = false)
|
|
430
|
+
const { exeResult, content: msgContent } = processMessageOutput(output, false);
|
|
450
431
|
exe_result = exeResult;
|
|
451
432
|
content = msgContent;
|
|
452
|
-
|
|
433
|
+
pendingMessageOutput = output; // 나중에 출력할 수 있도록 저장
|
|
434
|
+
debugLog(` MESSAGE processed (pending): content length ${msgContent?.length || 0}`);
|
|
453
435
|
}
|
|
454
436
|
|
|
455
437
|
if (FUNCTION_CALL) {
|
|
@@ -593,13 +575,101 @@ async function processOrchestratorResponses(params) {
|
|
|
593
575
|
// 완료 조건 체크
|
|
594
576
|
debugLog(`Checking completion conditions...`);
|
|
595
577
|
if (!executedFunctionCall && lastOutputType === 'message') {
|
|
596
|
-
debugLog(`COMPLETION: No function call + message type
|
|
597
|
-
|
|
598
|
-
|
|
578
|
+
debugLog(`COMPLETION: No function call + message type - judging if mission is truly complete`);
|
|
579
|
+
|
|
580
|
+
// 세션 중단 확인 (completion_judge 호출 전)
|
|
581
|
+
if (sessionInterrupted) {
|
|
582
|
+
debugLog(`Session interrupted before judgeMissionCompletion, breaking loop`);
|
|
583
|
+
break;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// LLM을 통해 실제 완료 여부 판단
|
|
587
|
+
let judgement;
|
|
588
|
+
try {
|
|
589
|
+
judgement = await judgeMissionCompletion({
|
|
590
|
+
what_user_requests: mission
|
|
591
|
+
});
|
|
592
|
+
} catch (err) {
|
|
593
|
+
if (err.name === 'AbortError' || sessionInterrupted) {
|
|
594
|
+
debugLog(`judgeMissionCompletion aborted or interrupted: ${err.name}`);
|
|
595
|
+
break;
|
|
596
|
+
}
|
|
597
|
+
throw err;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// 세션 중단 확인 (completion_judge 호출 후)
|
|
601
|
+
if (sessionInterrupted) {
|
|
602
|
+
debugLog(`Session interrupted after judgeMissionCompletion, breaking loop`);
|
|
603
|
+
break;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
debugLog(`Completion judgement: shouldComplete=${judgement.shouldComplete}, reason=${judgement.reason}, whatUserShouldSay=${judgement.whatUserShouldSay}`);
|
|
607
|
+
|
|
608
|
+
missionSolved = judgement.shouldComplete;
|
|
609
|
+
|
|
610
|
+
if (missionSolved) {
|
|
611
|
+
// 미션이 완료되었다고 판단되면 대기 중인 메시지 출력 후 종료
|
|
612
|
+
debugLog(`Mission judged as complete, displaying pending message and breaking loop`);
|
|
613
|
+
if (pendingMessageOutput) {
|
|
614
|
+
processMessageOutput(pendingMessageOutput, true); // 이제 출력
|
|
615
|
+
}
|
|
616
|
+
break;
|
|
617
|
+
} else {
|
|
618
|
+
// 미션이 완료되지 않았다고 판단되면 메시지를 출력하지 않고 계속 진행
|
|
619
|
+
debugLog(`Mission not complete, continuing without displaying message`);
|
|
620
|
+
|
|
621
|
+
// orchestratorConversation에서 방금 추가된 assistant message에 _internal_only 플래그 추가
|
|
622
|
+
const conversation = getOrchestratorConversation();
|
|
623
|
+
for (let i = conversation.length - 1; i >= 0; i--) {
|
|
624
|
+
const entry = conversation[i];
|
|
625
|
+
if (entry.type === 'message' && entry.role === 'assistant') {
|
|
626
|
+
entry._internal_only = true;
|
|
627
|
+
debugLog(`[_internal_only] Marked assistant message at index ${i} as internal-only (not for display)`);
|
|
628
|
+
break;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// whatUserShouldSay를 새로운 사용자 요구사항으로 처리
|
|
633
|
+
if (judgement.whatUserShouldSay && judgement.whatUserShouldSay.trim().length > 0) {
|
|
634
|
+
debugLog(`Treating whatUserShouldSay as new user request: ${judgement.whatUserShouldSay}`);
|
|
635
|
+
// 💬 Auto-continuing 메시지 제거
|
|
636
|
+
|
|
637
|
+
// whatUserShouldSay를 새로운 mission으로 설정하여 루프를 빠져나감
|
|
638
|
+
// 상위 runSession 루프에서 다시 orchestrateMission이 호출될 것임
|
|
639
|
+
improvementPoints = judgement.whatUserShouldSay;
|
|
640
|
+
improvementPointsIsAutoGenerated = true; // auto-generated 플래그 설정
|
|
641
|
+
debugLog(`[_internal_only] Set improvementPointsIsAutoGenerated=true for whatUserShouldSay`);
|
|
642
|
+
missionSolved = false; // 완료되지 않았으므로 상위 루프 계속
|
|
643
|
+
break; // processOrchestratorResponses 루프 종료
|
|
644
|
+
} else {
|
|
645
|
+
// whatUserShouldSay가 없으면 reason을 사용하여 계속 진행
|
|
646
|
+
improvementPoints = judgement.reason;
|
|
647
|
+
debugLog(`Continuing mission with reason: ${judgement.reason}`);
|
|
648
|
+
|
|
649
|
+
// 세션 중단 확인 (continueOrchestratorConversation 호출 전)
|
|
650
|
+
if (sessionInterrupted) {
|
|
651
|
+
debugLog(`Session interrupted before continueOrchestratorConversation, breaking loop`);
|
|
652
|
+
break;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
try {
|
|
656
|
+
orchestratedResponse = await continueOrchestratorConversation();
|
|
657
|
+
debugLog(`Received response with ${orchestratedResponse?.output?.length || 0} outputs`);
|
|
658
|
+
continue; // 루프 처음으로 돌아가서 새 응답 처리
|
|
659
|
+
} catch (err) {
|
|
660
|
+
if (err.name === 'AbortError' || sessionInterrupted) {
|
|
661
|
+
debugLog(`Conversation aborted or interrupted: ${err.name}`);
|
|
662
|
+
break;
|
|
663
|
+
}
|
|
664
|
+
debugLog(`ERROR in continueOrchestratorConversation: ${err.message}`);
|
|
665
|
+
throw err;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
599
669
|
}
|
|
600
670
|
|
|
601
671
|
if (!executedFunctionCall) {
|
|
602
|
-
debugLog(`COMPLETION: No function call executed, breaking loop`);
|
|
672
|
+
debugLog(`COMPLETION: No function call executed (other cases), breaking loop`);
|
|
603
673
|
break;
|
|
604
674
|
}
|
|
605
675
|
|
|
@@ -623,76 +693,20 @@ async function processOrchestratorResponses(params) {
|
|
|
623
693
|
debugLog(` hadAnyFunctionCall: ${hadAnyFunctionCall}`);
|
|
624
694
|
debugLog(` stallDetected: ${stallDetected}`);
|
|
625
695
|
debugLog(` missionSolved: ${missionSolved}`);
|
|
696
|
+
debugLog(` improvementPoints: ${improvementPoints}`);
|
|
697
|
+
debugLog(` improvementPointsIsAutoGenerated: ${improvementPointsIsAutoGenerated}`);
|
|
626
698
|
debugLog(` Total loop iterations: ${loopIteration}`);
|
|
627
699
|
debugLog(` Final toolUsageHistory: ${toolUsageHistory.length} items`);
|
|
628
700
|
|
|
629
701
|
return {
|
|
630
702
|
hadAnyFunctionCall,
|
|
631
703
|
stallDetected,
|
|
632
|
-
missionSolved
|
|
704
|
+
missionSolved,
|
|
705
|
+
improvementPoints,
|
|
706
|
+
improvementPointsIsAutoGenerated
|
|
633
707
|
};
|
|
634
708
|
}
|
|
635
709
|
|
|
636
|
-
/**
|
|
637
|
-
* 검증 결과에 따라 다음 동작을 결정하는 함수
|
|
638
|
-
* @returns {{ loopControl: string, improvementPoints: string, missionSolved: boolean }}
|
|
639
|
-
*/
|
|
640
|
-
function handleVerificationResult(verificationResult) {
|
|
641
|
-
const decision = verificationResult.decision;
|
|
642
|
-
|
|
643
|
-
switch (decision) {
|
|
644
|
-
case 'MISSION_COMPLETE':
|
|
645
|
-
return {
|
|
646
|
-
loopControl: LOOP_CONTROL.BREAK,
|
|
647
|
-
improvementPoints: '',
|
|
648
|
-
missionSolved: true
|
|
649
|
-
};
|
|
650
|
-
|
|
651
|
-
case 'SUBMISSION_COMPLETE':
|
|
652
|
-
uiEvents.addSystemMessage('✅ Sub-mission complete; continuing towards full mission completion.');
|
|
653
|
-
return {
|
|
654
|
-
loopControl: LOOP_CONTROL.CONTINUE,
|
|
655
|
-
improvementPoints: verificationResult.improvement_points || '',
|
|
656
|
-
missionSolved: false
|
|
657
|
-
};
|
|
658
|
-
|
|
659
|
-
case 'IN_PROGRESS':
|
|
660
|
-
return {
|
|
661
|
-
loopControl: LOOP_CONTROL.CONTINUE,
|
|
662
|
-
improvementPoints: verificationResult.improvement_points || '',
|
|
663
|
-
missionSolved: false
|
|
664
|
-
};
|
|
665
|
-
|
|
666
|
-
case 'REPLAN_NEEDED':
|
|
667
|
-
uiEvents.addSystemMessage('🔄 Revisit approach required - will try a different angle next iteration.');
|
|
668
|
-
return {
|
|
669
|
-
loopControl: LOOP_CONTROL.CONTINUE,
|
|
670
|
-
improvementPoints: verificationResult.improvement_points || '',
|
|
671
|
-
missionSolved: false
|
|
672
|
-
};
|
|
673
|
-
|
|
674
|
-
default:
|
|
675
|
-
return {
|
|
676
|
-
loopControl: LOOP_CONTROL.CONTINUE,
|
|
677
|
-
improvementPoints: '',
|
|
678
|
-
missionSolved: false
|
|
679
|
-
};
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
/**
|
|
684
|
-
* 실행 요약을 생성하는 헬퍼 함수
|
|
685
|
-
*/
|
|
686
|
-
function buildExecutionSummary(executionOutputList) {
|
|
687
|
-
return executionOutputList.map((exec_result, index) => {
|
|
688
|
-
const toolName = exec_result.more_info?.name || 'unknown';
|
|
689
|
-
const operationType = exec_result.more_info?.type || 'unknown';
|
|
690
|
-
const stdoutBlock = exec_result.stdout ? `\n\`\`\`\n${exec_result.stdout}\n\`\`\`` : '\n(empty)';
|
|
691
|
-
const stderrBlock = exec_result.stderr ? `\n\`\`\`\n${exec_result.stderr}\n\`\`\`` : '\n(empty)';
|
|
692
|
-
const ragRefLine = exec_result.rag_reference ? `- RAG Reference: ${exec_result.rag_reference}\n` : '';
|
|
693
|
-
return `### Step ${index + 1}\n- Function: \`${toolName}\`\n- Operation Type: \`${operationType}\`\n- Exit Code: ${typeof exec_result.code === 'number' ? exec_result.code : '?'}\n${ragRefLine}- STDOUT:${stdoutBlock}\n- STDERR:${stderrBlock}`;
|
|
694
|
-
}).join('\n\n');
|
|
695
|
-
}
|
|
696
710
|
|
|
697
711
|
|
|
698
712
|
/**
|
|
@@ -710,8 +724,6 @@ function buildExecutionSummary(executionOutputList) {
|
|
|
710
724
|
* @typedef {Object} AgentLoopResult
|
|
711
725
|
* @property {boolean} mission_solved - 미션 완료 여부
|
|
712
726
|
* @property {number} iteration_count - 실행된 반복 횟수
|
|
713
|
-
* @property {Array} verification_memory - 검증 메모리
|
|
714
|
-
* @property {Array} whatItDidHistory - 수행 작업 히스토리
|
|
715
727
|
* @property {Array} toolUsageHistory - 도구 사용 히스토리
|
|
716
728
|
*/
|
|
717
729
|
|
|
@@ -781,13 +793,12 @@ export async function runSession(options) {
|
|
|
781
793
|
}
|
|
782
794
|
|
|
783
795
|
// 메모리 초기화
|
|
784
|
-
const verification_memory = [];
|
|
785
|
-
const whatItDidHistory = [];
|
|
786
796
|
const toolUsageHistory = [];
|
|
787
797
|
|
|
788
798
|
let mission_solved = false;
|
|
789
799
|
let iteration_count = 0;
|
|
790
800
|
let improvement_points = '';
|
|
801
|
+
let improvement_points_is_auto_generated = false; // whatUserShouldSay에서 온 것인지 표시
|
|
791
802
|
|
|
792
803
|
// 대화 상태 복원 또는 리셋
|
|
793
804
|
const conversationState = getLastConversationState(sessionsToUse);
|
|
@@ -797,19 +808,10 @@ export async function runSession(options) {
|
|
|
797
808
|
conversationState.orchestratorConversation,
|
|
798
809
|
conversationState.orchestratorRequestOptions
|
|
799
810
|
);
|
|
800
|
-
if (ENABLE_VERIFIER) {
|
|
801
|
-
restoreVerifierConversation(
|
|
802
|
-
conversationState.verifierConversation,
|
|
803
|
-
conversationState.lastOrchestratorSnapshotLength
|
|
804
|
-
);
|
|
805
|
-
}
|
|
806
811
|
// logSuccess('✓ Conversation state restored');
|
|
807
812
|
} else {
|
|
808
813
|
// logSystem('ℹ Starting with fresh conversation state');
|
|
809
814
|
resetOrchestratorConversation();
|
|
810
|
-
if (ENABLE_VERIFIER) {
|
|
811
|
-
resetVerifierConversation();
|
|
812
|
-
}
|
|
813
815
|
}
|
|
814
816
|
|
|
815
817
|
// Python 사용 가능 여부 확인
|
|
@@ -837,40 +839,68 @@ export async function runSession(options) {
|
|
|
837
839
|
iteration_count++;
|
|
838
840
|
logIteration(iteration_count);
|
|
839
841
|
|
|
840
|
-
// 세션 중단 확인
|
|
841
|
-
if (sessionInterrupted) {
|
|
842
|
-
break;
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
// 세션 중단 확인
|
|
847
|
-
if (sessionInterrupted) {
|
|
848
|
-
break;
|
|
849
|
-
}
|
|
850
|
-
|
|
851
842
|
// 첫 반복에서 improvement_points 설정
|
|
843
|
+
// (이후 반복에서는 processOrchestratorResponses에서 설정된 값 유지)
|
|
852
844
|
if (iteration_count === 1) {
|
|
853
845
|
improvement_points = `${mission}`;
|
|
846
|
+
improvement_points_is_auto_generated = false; // 첫 번째는 실제 사용자 입력
|
|
847
|
+
debugLog(`[ITERATION ${iteration_count}] Setting initial improvement_points: ${improvement_points.substring(0, 100)}`);
|
|
848
|
+
} else if (!improvement_points) {
|
|
849
|
+
// improvementPoints가 설정되지 않았으면 빈 문자열
|
|
850
|
+
improvement_points = '';
|
|
851
|
+
improvement_points_is_auto_generated = false;
|
|
852
|
+
debugLog(`[ITERATION ${iteration_count}] No improvement_points, setting to empty string`);
|
|
853
|
+
} else {
|
|
854
|
+
debugLog(`[ITERATION ${iteration_count}] Using existing improvement_points: ${improvement_points.substring(0, 100)}, isAutoGenerated: ${improvement_points_is_auto_generated}`);
|
|
854
855
|
}
|
|
855
856
|
|
|
856
857
|
// Orchestrator 실행
|
|
858
|
+
debugLog(`[ITERATION ${iteration_count}] Calling orchestrateMission with improvement_points: "${improvement_points.substring(0, 100)}", isAutoGenerated: ${improvement_points_is_auto_generated}`);
|
|
857
859
|
let orchestratedMission;
|
|
858
860
|
try {
|
|
859
861
|
orchestratedMission = await orchestrateMission({
|
|
860
862
|
improvement_points: improvement_points,
|
|
861
|
-
mcpToolSchemas: mcpToolSchemas
|
|
863
|
+
mcpToolSchemas: mcpToolSchemas,
|
|
864
|
+
isAutoGenerated: improvement_points_is_auto_generated
|
|
862
865
|
});
|
|
863
866
|
} catch (err) {
|
|
864
867
|
// AbortError는 중단으로 처리
|
|
865
868
|
if (err.name === 'AbortError' || sessionInterrupted) {
|
|
869
|
+
// 중단 시에도 현재까지의 상태를 저장
|
|
870
|
+
currentSessionData.completed_at = new Date().toISOString();
|
|
871
|
+
currentSessionData.mission_solved = false;
|
|
872
|
+
currentSessionData.iteration_count = iteration_count;
|
|
873
|
+
currentSessionData.toolUsageHistory = toolUsageHistory;
|
|
874
|
+
currentSessionData.orchestratorConversation = getOrchestratorConversation();
|
|
875
|
+
currentSessionData.orchestratorRequestOptions = null;
|
|
876
|
+
|
|
877
|
+
debugLog(`[ITERATION ${iteration_count}] Session aborted during orchestration - saving session to history`);
|
|
878
|
+
await saveSessionToHistory(currentSessionData).catch(saveErr => {
|
|
879
|
+
debugLog(`[ITERATION ${iteration_count}] Failed to save session: ${saveErr.message}`);
|
|
880
|
+
});
|
|
866
881
|
break;
|
|
867
882
|
}
|
|
868
883
|
throw err;
|
|
869
884
|
}
|
|
870
|
-
|
|
885
|
+
// improvement_points_is_auto_generated 플래그 리셋 (다음 iteration을 위해)
|
|
886
|
+
improvement_points_is_auto_generated = false;
|
|
887
|
+
// improvement_points는 여기서 리셋하지 않음 (processOrchestratorResponses에서 설정될 수 있음)
|
|
888
|
+
debugLog(`[ITERATION ${iteration_count}] orchestrateMission completed`)
|
|
871
889
|
|
|
872
890
|
// 세션 중단 확인
|
|
873
891
|
if (sessionInterrupted) {
|
|
892
|
+
// 중단 시에도 현재까지의 상태를 저장
|
|
893
|
+
currentSessionData.completed_at = new Date().toISOString();
|
|
894
|
+
currentSessionData.mission_solved = false;
|
|
895
|
+
currentSessionData.iteration_count = iteration_count;
|
|
896
|
+
currentSessionData.toolUsageHistory = toolUsageHistory;
|
|
897
|
+
currentSessionData.orchestratorConversation = getOrchestratorConversation();
|
|
898
|
+
currentSessionData.orchestratorRequestOptions = null;
|
|
899
|
+
|
|
900
|
+
debugLog(`[ITERATION ${iteration_count}] Session interrupted after orchestration - saving session to history`);
|
|
901
|
+
await saveSessionToHistory(currentSessionData).catch(err => {
|
|
902
|
+
debugLog(`[ITERATION ${iteration_count}] Failed to save session: ${err.message}`);
|
|
903
|
+
});
|
|
874
904
|
break;
|
|
875
905
|
}
|
|
876
906
|
|
|
@@ -905,11 +935,50 @@ export async function runSession(options) {
|
|
|
905
935
|
stallDetected = orchestratorResult.stallDetected;
|
|
906
936
|
mission_solved = orchestratorResult.missionSolved;
|
|
907
937
|
|
|
938
|
+
debugLog(`[ITERATION ${iteration_count}] orchestratorResult.improvementPoints: "${orchestratorResult.improvementPoints || '(empty)'}", isAutoGenerated: ${orchestratorResult.improvementPointsIsAutoGenerated}`);
|
|
939
|
+
|
|
940
|
+
// improvementPoints가 반환된 경우 다음 iteration에 사용
|
|
941
|
+
// 반환되지 않은 경우 리셋
|
|
942
|
+
if (orchestratorResult.improvementPoints) {
|
|
943
|
+
improvement_points = orchestratorResult.improvementPoints;
|
|
944
|
+
improvement_points_is_auto_generated = orchestratorResult.improvementPointsIsAutoGenerated || false;
|
|
945
|
+
debugLog(`[ITERATION ${iteration_count}] Setting improvement_points from orchestratorResult: "${improvement_points.substring(0, 100)}", isAutoGenerated: ${improvement_points_is_auto_generated}`);
|
|
946
|
+
} else {
|
|
947
|
+
improvement_points = '';
|
|
948
|
+
improvement_points_is_auto_generated = false;
|
|
949
|
+
debugLog(`[ITERATION ${iteration_count}] No improvementPoints from orchestratorResult, resetting to empty`);
|
|
950
|
+
}
|
|
951
|
+
|
|
908
952
|
// 세션 중단 확인
|
|
909
953
|
if (sessionInterrupted) {
|
|
954
|
+
// 중단 시에도 현재까지의 상태를 저장
|
|
955
|
+
currentSessionData.completed_at = new Date().toISOString();
|
|
956
|
+
currentSessionData.mission_solved = false;
|
|
957
|
+
currentSessionData.iteration_count = iteration_count;
|
|
958
|
+
currentSessionData.toolUsageHistory = toolUsageHistory;
|
|
959
|
+
currentSessionData.orchestratorConversation = getOrchestratorConversation();
|
|
960
|
+
currentSessionData.orchestratorRequestOptions = null;
|
|
961
|
+
|
|
962
|
+
debugLog(`[ITERATION ${iteration_count}] Session interrupted - saving session to history`);
|
|
963
|
+
await saveSessionToHistory(currentSessionData).catch(err => {
|
|
964
|
+
debugLog(`[ITERATION ${iteration_count}] Failed to save session: ${err.message}`);
|
|
965
|
+
});
|
|
910
966
|
break;
|
|
911
967
|
}
|
|
912
968
|
|
|
969
|
+
// 매 iteration마다 세션 히스토리 저장 (실시간 저장)
|
|
970
|
+
currentSessionData.completed_at = new Date().toISOString();
|
|
971
|
+
currentSessionData.mission_solved = mission_solved;
|
|
972
|
+
currentSessionData.iteration_count = iteration_count;
|
|
973
|
+
currentSessionData.toolUsageHistory = toolUsageHistory;
|
|
974
|
+
currentSessionData.orchestratorConversation = getOrchestratorConversation();
|
|
975
|
+
currentSessionData.orchestratorRequestOptions = null;
|
|
976
|
+
|
|
977
|
+
debugLog(`[ITERATION ${iteration_count}] Saving session to history (real-time save)`);
|
|
978
|
+
await saveSessionToHistory(currentSessionData).catch(err => {
|
|
979
|
+
debugLog(`[ITERATION ${iteration_count}] Failed to save session: ${err.message}`);
|
|
980
|
+
});
|
|
981
|
+
|
|
913
982
|
// 미션 완료 처리
|
|
914
983
|
if (mission_solved) {
|
|
915
984
|
break;
|
|
@@ -925,63 +994,21 @@ export async function runSession(options) {
|
|
|
925
994
|
break;
|
|
926
995
|
}
|
|
927
996
|
|
|
928
|
-
//
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
improvement_points = '';
|
|
932
|
-
continue;
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
// Verifier 실행
|
|
937
|
-
const verification_result = await verifyResult({ what_user_requests: mission });
|
|
938
|
-
uiEvents.addSystemMessage(`${verification_result.decision}`);
|
|
939
|
-
if (false) uiEvents.addSystemMessage(`Verified ${verification_result.improvement_points}`);
|
|
940
|
-
if (verification_result.replan_needed) uiEvents.addSystemMessage(`Verified Re-Plan Required`);
|
|
941
|
-
if (verification_result.what_it_did) {
|
|
942
|
-
whatItDidHistory.push(verification_result.what_it_did);
|
|
943
|
-
if (whatItDidHistory.length > MAX_WHAT_IT_DID_HISTORY) {
|
|
944
|
-
whatItDidHistory.shift();
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
// Verification memory에 추가
|
|
949
|
-
const memoryEntry = {
|
|
950
|
-
timestamp: new Date().toISOString(),
|
|
951
|
-
mission: mission,
|
|
952
|
-
iteration: iteration_count,
|
|
953
|
-
what_it_did: verification_result.what_it_did || '',
|
|
954
|
-
result: verification_result,
|
|
955
|
-
what_it_did_history: [...whatItDidHistory],
|
|
956
|
-
tool_history: [...iterationToolHistory]
|
|
957
|
-
};
|
|
958
|
-
|
|
959
|
-
verification_memory.push(memoryEntry);
|
|
960
|
-
|
|
961
|
-
// 미션 상태에 따른 처리
|
|
962
|
-
const nextAction = handleVerificationResult(verification_result);
|
|
963
|
-
improvement_points = nextAction.improvementPoints;
|
|
964
|
-
mission_solved = nextAction.missionSolved;
|
|
965
|
-
|
|
966
|
-
if (nextAction.loopControl === LOOP_CONTROL.BREAK) {
|
|
967
|
-
break;
|
|
968
|
-
}
|
|
997
|
+
// improvement_points가 설정되어 있으면 다음 iteration 계속 진행
|
|
998
|
+
debugLog(`[ITERATION ${iteration_count}] Continuing with improvement_points: "${improvement_points?.substring(0, 100) || '(empty)'}"`);
|
|
999
|
+
continue;
|
|
969
1000
|
}
|
|
970
1001
|
|
|
971
1002
|
// 대화 상태 저장
|
|
972
1003
|
const finalOrchestratorConversation = getOrchestratorConversation();
|
|
973
|
-
const finalVerifierConversation = ENABLE_VERIFIER ? getVerifierConversation() : [];
|
|
974
1004
|
|
|
975
1005
|
// 결과 반환
|
|
976
1006
|
const result = {
|
|
977
1007
|
mission_solved,
|
|
978
1008
|
iteration_count,
|
|
979
|
-
verification_memory,
|
|
980
|
-
whatItDidHistory,
|
|
981
1009
|
toolUsageHistory,
|
|
982
1010
|
// 대화 상태도 반환하여 저장할 수 있도록 함
|
|
983
1011
|
orchestratorConversation: finalOrchestratorConversation,
|
|
984
|
-
verifierConversation: finalVerifierConversation,
|
|
985
1012
|
|
|
986
1013
|
previousSessions: sessionsToUse
|
|
987
1014
|
};
|
|
@@ -989,21 +1016,17 @@ export async function runSession(options) {
|
|
|
989
1016
|
currentSessionData.completed_at = new Date().toISOString();
|
|
990
1017
|
currentSessionData.mission_solved = result.mission_solved;
|
|
991
1018
|
currentSessionData.iteration_count = result.iteration_count;
|
|
992
|
-
currentSessionData.verification_memory = result.verification_memory;
|
|
993
|
-
currentSessionData.whatItDidHistory = result.whatItDidHistory;
|
|
994
1019
|
currentSessionData.toolUsageHistory = result.toolUsageHistory;
|
|
995
1020
|
// previousSessions는 saveSessionToHistory에서 파일로부터 로드하므로 저장하지 않음 (메모리 누적 방지)
|
|
996
1021
|
// currentSessionData.previousSessions = result.previousSessions;
|
|
997
1022
|
debugLog('[runSession] previousSessions NOT saved to currentSessionData to prevent exponential growth');
|
|
998
1023
|
// 대화 상태 저장
|
|
999
1024
|
currentSessionData.orchestratorConversation = result.orchestratorConversation;
|
|
1000
|
-
currentSessionData.verifierConversation = result.verifierConversation;
|
|
1001
|
-
currentSessionData.lastOrchestratorSnapshotLength = result.orchestratorConversation?.length || 0;
|
|
1002
1025
|
currentSessionData.orchestratorRequestOptions = null; // 필요시 orchestrator에서 가져올 수 있음
|
|
1003
1026
|
|
|
1004
|
-
debugLog(`[runSession] Saving session to history - sessionID: ${currentSessionData.sessionID}`);
|
|
1027
|
+
debugLog(`[runSession] Saving final session to history - sessionID: ${currentSessionData.sessionID}`);
|
|
1005
1028
|
debugLog(`[runSession] Session data size: ${JSON.stringify(currentSessionData).length} bytes`);
|
|
1006
|
-
// 세션 히스토리에 저장
|
|
1029
|
+
// 최종 세션 히스토리에 저장 (중복 저장이지만 최신 상태 보장)
|
|
1007
1030
|
await saveSessionToHistory(currentSessionData);
|
|
1008
1031
|
|
|
1009
1032
|
return currentSessionData;
|
|
@@ -177,14 +177,6 @@ export function buildHistoricalContext(sessions, currentMission) {
|
|
|
177
177
|
contextParts.push(`**Status**: ${session.mission_solved ? '✅ Completed' : '❌ Not completed'}`);
|
|
178
178
|
contextParts.push(`**Iterations**: ${session.iteration_count || 0}`);
|
|
179
179
|
|
|
180
|
-
// 주요 수행 내역
|
|
181
|
-
if (session.whatItDidHistory && session.whatItDidHistory.length > 0) {
|
|
182
|
-
contextParts.push(`**Actions Taken**:`);
|
|
183
|
-
session.whatItDidHistory.slice(-3).forEach(action => {
|
|
184
|
-
contextParts.push(` - ${action}`);
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
|
|
188
180
|
// 도구 사용 통계
|
|
189
181
|
if (session.toolUsageHistory && session.toolUsageHistory.length > 0) {
|
|
190
182
|
const toolCounts = {};
|
|
@@ -194,17 +186,6 @@ export function buildHistoricalContext(sessions, currentMission) {
|
|
|
194
186
|
contextParts.push(`**Tools Used**: ${Object.entries(toolCounts).map(([name, count]) => `${name}(${count})`).join(', ')}`);
|
|
195
187
|
}
|
|
196
188
|
|
|
197
|
-
// 마지막 검증 결과
|
|
198
|
-
if (session.verification_memory && session.verification_memory.length > 0) {
|
|
199
|
-
const lastVerification = session.verification_memory[session.verification_memory.length - 1];
|
|
200
|
-
if (lastVerification.result) {
|
|
201
|
-
contextParts.push(`**Final Decision**: ${lastVerification.result.decision}`);
|
|
202
|
-
if (lastVerification.result.improvement_points) {
|
|
203
|
-
contextParts.push(`**Lessons**: ${lastVerification.result.improvement_points.slice(0, 200)}...`);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
189
|
contextParts.push('');
|
|
209
190
|
});
|
|
210
191
|
|
|
@@ -225,13 +206,9 @@ export function createSessionData(sessionID, mission) {
|
|
|
225
206
|
completed_at: null,
|
|
226
207
|
mission_solved: false,
|
|
227
208
|
iteration_count: 0,
|
|
228
|
-
verification_memory: [],
|
|
229
|
-
whatItDidHistory: [],
|
|
230
209
|
toolUsageHistory: [],
|
|
231
210
|
// 대화 상태 저장
|
|
232
211
|
orchestratorConversation: [],
|
|
233
|
-
verifierConversation: [],
|
|
234
|
-
lastOrchestratorSnapshotLength: 0,
|
|
235
212
|
orchestratorRequestOptions: null
|
|
236
213
|
};
|
|
237
214
|
}
|
|
@@ -250,8 +227,6 @@ export function getLastConversationState(sessions) {
|
|
|
250
227
|
|
|
251
228
|
return {
|
|
252
229
|
orchestratorConversation: lastSession.orchestratorConversation || [],
|
|
253
|
-
verifierConversation: lastSession.verifierConversation || [],
|
|
254
|
-
lastOrchestratorSnapshotLength: lastSession.lastOrchestratorSnapshotLength || 0,
|
|
255
230
|
orchestratorRequestOptions: lastSession.orchestratorRequestOptions || null
|
|
256
231
|
};
|
|
257
232
|
}
|
|
@@ -290,16 +265,12 @@ export function reconstructUIHistory(sessions) {
|
|
|
290
265
|
const conversation = session.orchestratorConversation;
|
|
291
266
|
debugLog(`orchestratorConversation length: ${conversation.length}`);
|
|
292
267
|
|
|
293
|
-
// 현재 세션의 시작 지점:
|
|
268
|
+
// 현재 세션의 시작 지점: 항상 0부터 시작 (각 세션은 독립적)
|
|
294
269
|
let startIndex = 0;
|
|
295
|
-
if (sessionIndex > 0) {
|
|
296
|
-
startIndex = sessions[sessionIndex - 1].lastOrchestratorSnapshotLength || 0;
|
|
297
|
-
debugLog(`Previous session lastOrchestratorSnapshotLength: ${startIndex}`);
|
|
298
|
-
}
|
|
299
270
|
|
|
300
|
-
// 현재 세션의 끝 지점:
|
|
301
|
-
const endIndex =
|
|
302
|
-
debugLog(`Current session
|
|
271
|
+
// 현재 세션의 끝 지점: conversation 전체 길이 사용
|
|
272
|
+
const endIndex = conversation.length;
|
|
273
|
+
debugLog(`Current session conversation length: ${endIndex}`);
|
|
303
274
|
debugLog(`Processing conversation slice [${startIndex}, ${endIndex}]`);
|
|
304
275
|
|
|
305
276
|
// 현재 세션에서 새로 추가된 대화만 추출
|
|
@@ -467,6 +438,12 @@ export function reconstructUIHistory(sessions) {
|
|
|
467
438
|
|
|
468
439
|
// message 타입 처리 (assistant 응답)
|
|
469
440
|
if (item.type === 'message' && item.role === 'assistant' && item.content) {
|
|
441
|
+
// _internal_only 플래그가 있으면 건너뛰기
|
|
442
|
+
if (item._internal_only) {
|
|
443
|
+
debugLog(`[reconstructUIHistory] Skipping assistant message with _internal_only flag`);
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
|
|
470
447
|
const text = item.content[0]?.text || '';
|
|
471
448
|
if (text) {
|
|
472
449
|
uiHistory.push({
|
|
@@ -479,6 +456,12 @@ export function reconstructUIHistory(sessions) {
|
|
|
479
456
|
|
|
480
457
|
// user 메시지 타입 처리
|
|
481
458
|
if (item.role === 'user' && item.content) {
|
|
459
|
+
// _internal_only 플래그가 있으면 건너뛰기
|
|
460
|
+
if (item._internal_only) {
|
|
461
|
+
debugLog(`[reconstructUIHistory] Skipping user message with _internal_only flag`);
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
|
|
482
465
|
const textContent = item.content.find(c => c.type === 'input_text');
|
|
483
466
|
if (textContent && textContent.text) {
|
|
484
467
|
uiHistory.push({
|
|
@@ -491,10 +474,6 @@ export function reconstructUIHistory(sessions) {
|
|
|
491
474
|
}
|
|
492
475
|
}
|
|
493
476
|
|
|
494
|
-
// whatItDidHistory와 verification_memory는 orchestratorConversation에
|
|
495
|
-
// 이미 포함되어 있으므로 중복 추가하지 않음
|
|
496
|
-
|
|
497
|
-
// mission_completed는 UI에서 필터링되므로 추가하지 않음
|
|
498
477
|
});
|
|
499
478
|
|
|
500
479
|
return uiHistory;
|