aiexecode 1.0.126 → 1.0.127
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 +134 -20
- 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 +4 -0
- package/prompts/orchestrator.txt +53 -0
- package/src/commands/bg.js +129 -0
- package/src/frontend/App.js +100 -1
- package/src/frontend/components/BackgroundProcessList.js +175 -0
- package/src/system/ai_request.js +0 -19
- package/src/system/background_process.js +317 -0
- package/src/system/code_executer.js +469 -57
- package/src/system/output_helper.js +52 -9
- package/src/system/session.js +73 -10
- package/src/util/exit_handler.js +8 -0
- /package/payload_viewer/out/_next/static/{Ciog50_gZfMGwKNqVaI0v → 42iEoi-1o5MxNIZ1SWSvV}/_buildManifest.js +0 -0
- /package/payload_viewer/out/_next/static/{Ciog50_gZfMGwKNqVaI0v → 42iEoi-1o5MxNIZ1SWSvV}/_clientMiddlewareManifest.json +0 -0
- /package/payload_viewer/out/_next/static/{Ciog50_gZfMGwKNqVaI0v → 42iEoi-1o5MxNIZ1SWSvV}/_ssgManifest.js +0 -0
|
@@ -1,35 +1,70 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Output Helper - UI 이벤트 발생
|
|
3
|
+
* Pipe mode에서는 stderr로 출력하거나 무시
|
|
3
4
|
*/
|
|
4
5
|
|
|
5
6
|
import { uiEvents } from './ui_events.js';
|
|
6
7
|
|
|
8
|
+
// Pipe mode 감지
|
|
9
|
+
const isPipeMode = () => process.app_custom?.pipeMode === true;
|
|
10
|
+
|
|
7
11
|
export function logSystem(message) {
|
|
8
|
-
|
|
12
|
+
if (isPipeMode()) {
|
|
13
|
+
console.error(`[SYSTEM] ${message}`);
|
|
14
|
+
} else {
|
|
15
|
+
uiEvents.addSystemMessage(message);
|
|
16
|
+
}
|
|
9
17
|
}
|
|
10
18
|
|
|
11
19
|
export function logError(message) {
|
|
12
|
-
|
|
20
|
+
if (isPipeMode()) {
|
|
21
|
+
console.error(`[ERROR] ${message}`);
|
|
22
|
+
} else {
|
|
23
|
+
uiEvents.addErrorMessage(message);
|
|
24
|
+
}
|
|
13
25
|
}
|
|
14
26
|
|
|
15
27
|
export function logAssistantMessage(message) {
|
|
16
|
-
|
|
28
|
+
if (isPipeMode()) {
|
|
29
|
+
console.error(`[ASSISTANT] ${message}`);
|
|
30
|
+
} else {
|
|
31
|
+
uiEvents.addAssistantMessage(message);
|
|
32
|
+
}
|
|
17
33
|
}
|
|
18
34
|
|
|
19
35
|
export function logToolCall(toolName, args) {
|
|
20
|
-
|
|
36
|
+
if (isPipeMode()) {
|
|
37
|
+
console.error(`[TOOL] ${toolName}`);
|
|
38
|
+
} else {
|
|
39
|
+
uiEvents.startToolExecution(toolName, args);
|
|
40
|
+
}
|
|
21
41
|
}
|
|
22
42
|
|
|
23
43
|
export function logToolResult(toolName, stdout, originalResult = null, toolInput = null, fileSnapshot = null) {
|
|
24
|
-
|
|
44
|
+
if (isPipeMode()) {
|
|
45
|
+
// Pipe mode에서는 도구 결과를 간략하게 stderr로
|
|
46
|
+
const preview = stdout?.substring(0, 200) || '';
|
|
47
|
+
console.error(`[TOOL_RESULT] ${toolName}: ${preview}${stdout?.length > 200 ? '...' : ''}`);
|
|
48
|
+
} else {
|
|
49
|
+
uiEvents.addToolResult(toolName, { stdout, originalResult, fileSnapshot }, toolInput);
|
|
50
|
+
}
|
|
25
51
|
}
|
|
26
52
|
|
|
27
53
|
export function logCodeExecution(language, code) {
|
|
28
|
-
|
|
54
|
+
if (isPipeMode()) {
|
|
55
|
+
console.error(`[CODE] ${language}`);
|
|
56
|
+
} else {
|
|
57
|
+
uiEvents.startCodeExecution(language, code);
|
|
58
|
+
}
|
|
29
59
|
}
|
|
30
60
|
|
|
31
61
|
export function logCodeResult(stdout, stderr, exitCode) {
|
|
32
|
-
|
|
62
|
+
if (isPipeMode()) {
|
|
63
|
+
if (stdout) console.error(`[CODE_STDOUT] ${stdout.substring(0, 200)}${stdout.length > 200 ? '...' : ''}`);
|
|
64
|
+
if (stderr) console.error(`[CODE_STDERR] ${stderr.substring(0, 200)}${stderr.length > 200 ? '...' : ''}`);
|
|
65
|
+
} else {
|
|
66
|
+
uiEvents.addCodeResult(stdout, stderr, exitCode);
|
|
67
|
+
}
|
|
33
68
|
}
|
|
34
69
|
|
|
35
70
|
export function logIteration(iterationNumber) {
|
|
@@ -38,9 +73,17 @@ export function logIteration(iterationNumber) {
|
|
|
38
73
|
}
|
|
39
74
|
|
|
40
75
|
export function logMissionComplete() {
|
|
41
|
-
|
|
76
|
+
if (isPipeMode()) {
|
|
77
|
+
console.error('[COMPLETE] Mission completed');
|
|
78
|
+
} else {
|
|
79
|
+
uiEvents.missionCompleted(0);
|
|
80
|
+
}
|
|
42
81
|
}
|
|
43
82
|
|
|
44
83
|
export function logConversationRestored(count) {
|
|
45
|
-
|
|
84
|
+
if (isPipeMode()) {
|
|
85
|
+
console.error(`[RESTORED] ${count} conversation(s) restored`);
|
|
86
|
+
} else {
|
|
87
|
+
uiEvents.conversationRestored(count);
|
|
88
|
+
}
|
|
46
89
|
}
|
package/src/system/session.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Agent Loop: 계획·실행·검증 사이클을 수행하는 핵심 모듈
|
|
2
2
|
import { orchestrateMission, continueOrchestratorConversation, resetOrchestratorConversation, recordOrchestratorToolResult, getOrchestratorConversation, restoreOrchestratorConversation } from "../ai_based/orchestrator.js";
|
|
3
3
|
import { judgeMissionCompletion } from "../ai_based/completion_judge.js";
|
|
4
|
-
import { execPythonCode, execShellScript } from "./code_executer.js";
|
|
4
|
+
import { execPythonCode, execShellScript, resetShellCwd } from "./code_executer.js";
|
|
5
|
+
import { runInBackground, getBackgroundProcess } from "./background_process.js";
|
|
5
6
|
import { FILE_READER_FUNCTIONS } from "../tools/file_reader.js";
|
|
6
7
|
import { RIPGREP_FUNCTIONS } from "../tools/ripgrep.js";
|
|
7
8
|
import { GLOB_FUNCTIONS } from "../tools/glob.js";
|
|
@@ -30,6 +31,47 @@ import {
|
|
|
30
31
|
|
|
31
32
|
const debugLog = createDebugLogger('session.log', 'session');
|
|
32
33
|
|
|
34
|
+
// Pipe mode helper: UI 이벤트를 조건부로 처리
|
|
35
|
+
const isPipeMode = () => process.app_custom?.pipeMode === true;
|
|
36
|
+
|
|
37
|
+
// Pipe mode에서는 stderr로 출력, 일반 모드에서는 uiEvents 사용
|
|
38
|
+
const safeUiEvents = {
|
|
39
|
+
addSystemMessage: (msg) => {
|
|
40
|
+
if (isPipeMode()) {
|
|
41
|
+
console.error(`[SYSTEM] ${msg}`);
|
|
42
|
+
} else {
|
|
43
|
+
uiEvents.addSystemMessage(msg);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
addErrorMessage: (msg) => {
|
|
47
|
+
if (isPipeMode()) {
|
|
48
|
+
console.error(`[ERROR] ${msg}`);
|
|
49
|
+
} else {
|
|
50
|
+
uiEvents.addErrorMessage(msg);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
sessionStart: (msg) => {
|
|
54
|
+
if (!isPipeMode()) {
|
|
55
|
+
uiEvents.sessionStart(msg);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
sessionEnd: () => {
|
|
59
|
+
if (!isPipeMode()) {
|
|
60
|
+
uiEvents.sessionEnd();
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
on: (event, handler) => {
|
|
64
|
+
if (!isPipeMode()) {
|
|
65
|
+
uiEvents.on(event, handler);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
off: (event, handler) => {
|
|
69
|
+
if (!isPipeMode()) {
|
|
70
|
+
uiEvents.off(event, handler);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
33
75
|
|
|
34
76
|
/**
|
|
35
77
|
* 서브미션 이름을 추론하는 헬퍼 함수
|
|
@@ -397,7 +439,7 @@ async function processOrchestratorResponses(params) {
|
|
|
397
439
|
debugLog(`No processable output, reasoningOnlyResponses: ${reasoningOnlyResponses}`);
|
|
398
440
|
if (reasoningOnlyResponses >= MAX_REASONING_ONLY_RESPONSES) {
|
|
399
441
|
debugLog(`Reached MAX_REASONING_ONLY_RESPONSES (${MAX_REASONING_ONLY_RESPONSES}), treating as stall`);
|
|
400
|
-
|
|
442
|
+
safeUiEvents.addSystemMessage('⚠ Orchestrator stalled (reasoning only) - treating as completion');
|
|
401
443
|
stallDetected = true;
|
|
402
444
|
break;
|
|
403
445
|
}
|
|
@@ -816,14 +858,14 @@ export async function runSession(options) {
|
|
|
816
858
|
if (!sessionInterrupted) {
|
|
817
859
|
sessionInterrupted = true;
|
|
818
860
|
abortCurrentRequest(); // API 요청 즉시 중단
|
|
819
|
-
|
|
861
|
+
safeUiEvents.addErrorMessage('Session interrupted by user');
|
|
820
862
|
debugLog('[runSession] Session interrupted by user');
|
|
821
863
|
}
|
|
822
864
|
};
|
|
823
|
-
|
|
865
|
+
safeUiEvents.on('session:interrupt', handleInterrupt);
|
|
824
866
|
|
|
825
867
|
// 세션 시작 알림
|
|
826
|
-
|
|
868
|
+
safeUiEvents.sessionStart('Running agent session...');
|
|
827
869
|
|
|
828
870
|
// catch 블록에서도 접근 가능하도록 try 블록 밖에서 선언
|
|
829
871
|
let currentSessionData = null;
|
|
@@ -917,6 +959,11 @@ export async function runSession(options) {
|
|
|
917
959
|
updateCurrentTodos([]);
|
|
918
960
|
debugLog(`[runSession] Starting fresh session - no todos in memory`);
|
|
919
961
|
}
|
|
962
|
+
|
|
963
|
+
// 새 세션 시작 시 쉘의 작업 디렉토리를 프로젝트 루트로 리셋
|
|
964
|
+
// (이전 미션에서 cd한 디렉토리가 남아있지 않도록)
|
|
965
|
+
await resetShellCwd();
|
|
966
|
+
debugLog(`[runSession] Shell cwd reset to: ${process.cwd()}`);
|
|
920
967
|
}
|
|
921
968
|
|
|
922
969
|
// Python 사용 가능 여부 확인
|
|
@@ -932,7 +979,23 @@ export async function runSession(options) {
|
|
|
932
979
|
...TODO_WRITE_FUNCTIONS,
|
|
933
980
|
...SKILL_FUNCTIONS, // 스킬 호출 도구
|
|
934
981
|
...mcpToolFunctions,
|
|
935
|
-
"bash": async (args) =>
|
|
982
|
+
"bash": async (args) => {
|
|
983
|
+
if (args.background) {
|
|
984
|
+
// 백그라운드 실행
|
|
985
|
+
const result = await runInBackground(args.script);
|
|
986
|
+
return {
|
|
987
|
+
stdout: `Background process started: ${result.id} (pid: ${result.pid})`,
|
|
988
|
+
stderr: '',
|
|
989
|
+
code: 0,
|
|
990
|
+
background: true,
|
|
991
|
+
processId: result.id,
|
|
992
|
+
pid: result.pid
|
|
993
|
+
};
|
|
994
|
+
} else {
|
|
995
|
+
// 일반 실행
|
|
996
|
+
return execShellScript(args.script);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
936
999
|
};
|
|
937
1000
|
|
|
938
1001
|
// Python이 있는 경우에만 Python 관련 도구 추가
|
|
@@ -1132,7 +1195,7 @@ export async function runSession(options) {
|
|
|
1132
1195
|
const message = stallDetected
|
|
1133
1196
|
? '⚠ Session ended due to orchestrator stall'
|
|
1134
1197
|
: '✅ No function calls detected - mission complete';
|
|
1135
|
-
|
|
1198
|
+
safeUiEvents.addSystemMessage(message);
|
|
1136
1199
|
debugLog(`[ITERATION ${iteration_count}] ${message}`);
|
|
1137
1200
|
|
|
1138
1201
|
// completion_judge 없이 종료되는 경우에도 Todos와 TrimmedFileReads 저장
|
|
@@ -1252,7 +1315,7 @@ export async function runSession(options) {
|
|
|
1252
1315
|
consolidatedErrorMessage = `[Session] ${userFriendlyMessage}`;
|
|
1253
1316
|
}
|
|
1254
1317
|
|
|
1255
|
-
|
|
1318
|
+
safeUiEvents.addErrorMessage(consolidatedErrorMessage);
|
|
1256
1319
|
|
|
1257
1320
|
// 에러 발생 시에도 Todos와 TrimmedFileReads 저장 시도
|
|
1258
1321
|
if (currentSessionData) {
|
|
@@ -1270,9 +1333,9 @@ export async function runSession(options) {
|
|
|
1270
1333
|
return null;
|
|
1271
1334
|
} finally {
|
|
1272
1335
|
// 세션 중단 이벤트 리스너 제거
|
|
1273
|
-
|
|
1336
|
+
safeUiEvents.off('session:interrupt', handleInterrupt);
|
|
1274
1337
|
|
|
1275
1338
|
// 세션 종료 알림
|
|
1276
|
-
|
|
1339
|
+
safeUiEvents.sessionEnd();
|
|
1277
1340
|
}
|
|
1278
1341
|
}
|
package/src/util/exit_handler.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { uiEvents } from '../system/ui_events.js';
|
|
2
|
+
import { closePersistentShell } from '../system/code_executer.js';
|
|
3
|
+
import { killAllBackgroundProcesses } from '../system/background_process.js';
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* Unified exit handler for the application
|
|
@@ -17,6 +19,12 @@ export async function performExit(options = {}) {
|
|
|
17
19
|
uiEvents.addSystemMessage(`Goodbye! Session ID: ${sessionID}`);
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
// 백그라운드 프로세스 정리
|
|
23
|
+
await killAllBackgroundProcesses();
|
|
24
|
+
|
|
25
|
+
// PersistentShell 정리
|
|
26
|
+
await closePersistentShell();
|
|
27
|
+
|
|
20
28
|
// MCP Integration 정리
|
|
21
29
|
if (mcpIntegration) {
|
|
22
30
|
await mcpIntegration.cleanup();
|
|
File without changes
|
|
File without changes
|
|
File without changes
|