aiexecode 1.0.57 → 1.0.59
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/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 +84 -0
- package/prompts/orchestrator.backup.txt +1 -1
- package/prompts/orchestrator.txt +180 -316
- package/src/ai_based/completion_judge.js +240 -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/{PfR4y62gDrU8vjS4Mtpci → 9Xb8vkstjgOP7B6qfVD-9}/_buildManifest.js +0 -0
- /package/payload_viewer/out/_next/static/{PfR4y62gDrU8vjS4Mtpci → 9Xb8vkstjgOP7B6qfVD-9}/_clientMiddlewareManifest.json +0 -0
- /package/payload_viewer/out/_next/static/{PfR4y62gDrU8vjS4Mtpci → 9Xb8vkstjgOP7B6qfVD-9}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import dotenv from "dotenv";
|
|
2
|
+
import { request, isContextWindowError, getModelForProvider } from "../system/ai_request.js";
|
|
3
|
+
import { getOrchestratorConversation } from "./orchestrator.js";
|
|
4
|
+
import { createSystemMessage } from "../util/prompt_loader.js";
|
|
5
|
+
import { createDebugLogger } from "../util/debug_log.js";
|
|
6
|
+
|
|
7
|
+
dotenv.config({ quiet: true });
|
|
8
|
+
|
|
9
|
+
const debugLog = createDebugLogger('completion_judge.log', 'completion_judge');
|
|
10
|
+
|
|
11
|
+
export const completionJudgmentSchema = {
|
|
12
|
+
name: "completion_judgment",
|
|
13
|
+
schema: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: {
|
|
16
|
+
should_complete: {
|
|
17
|
+
type: "boolean",
|
|
18
|
+
description: "Whether the mission is truly complete (true) or should continue (false). If whatUserShouldSay is hard to determine, set this to true."
|
|
19
|
+
},
|
|
20
|
+
whatUserShouldSay: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "The most appropriate thing the user should say next, as if you (the assistant) were the user observing the current situation. Put yourself in the user's shoes and determine what would be the most natural and helpful thing to say to guide the agent forward. MUST be a single, clear, decisive instruction without hedging words like 'maybe', 'perhaps', 'consider', 'you could', or offering multiple options. Pick the MOST important next step and state it with strong conviction. Empty string if mission is complete or if it's genuinely unclear what the user should say."
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
required: ["should_complete", "whatUserShouldSay"],
|
|
26
|
+
additionalProperties: false
|
|
27
|
+
},
|
|
28
|
+
strict: true
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// systemMessage는 judgeMissionCompletion 호출 시 동적으로 생성됨
|
|
32
|
+
|
|
33
|
+
const completionJudgeConversation = [];
|
|
34
|
+
let lastOrchestratorSnapshotLength = 0;
|
|
35
|
+
|
|
36
|
+
function cloneMessage(message) {
|
|
37
|
+
return JSON.parse(JSON.stringify(message));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
async function createCompletionJudgeRequestOptions() {
|
|
42
|
+
const model = await getModelForProvider();
|
|
43
|
+
return {
|
|
44
|
+
taskName: 'completion_judge',
|
|
45
|
+
model,
|
|
46
|
+
isGpt5Model: model.startsWith("gpt-5")
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Completion judge conversation을 초기화하거나 시스템 프롬프트를 업데이트합니다.
|
|
52
|
+
* 매 요청마다 프롬프트 파일을 새로 읽어서 변경사항을 즉시 반영합니다.
|
|
53
|
+
*/
|
|
54
|
+
async function ensureCompletionJudgeConversationInitialized(templateVars = {}) {
|
|
55
|
+
// 매번 최신 시스템 프롬프트를 로드
|
|
56
|
+
const systemMessage = await createSystemMessage("completion_judge.txt", templateVars);
|
|
57
|
+
|
|
58
|
+
const systemMessageEntry = {
|
|
59
|
+
role: "system",
|
|
60
|
+
content: [
|
|
61
|
+
{
|
|
62
|
+
type: "input_text",
|
|
63
|
+
text: systemMessage.content
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// conversation이 비어있으면 새로 추가
|
|
69
|
+
if (!completionJudgeConversation.length) {
|
|
70
|
+
completionJudgeConversation.push(systemMessageEntry);
|
|
71
|
+
} else {
|
|
72
|
+
// conversation이 있으면 첫 번째 system 메시지를 업데이트
|
|
73
|
+
if (completionJudgeConversation[0]?.role === "system") {
|
|
74
|
+
completionJudgeConversation[0] = systemMessageEntry;
|
|
75
|
+
} else {
|
|
76
|
+
// system 메시지가 맨 앞에 없으면 추가
|
|
77
|
+
completionJudgeConversation.unshift(systemMessageEntry);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function syncOrchestratorConversation() {
|
|
83
|
+
const sourceConversation = getOrchestratorConversation();
|
|
84
|
+
if (!Array.isArray(sourceConversation) || !sourceConversation.length) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for (let i = lastOrchestratorSnapshotLength; i < sourceConversation.length; i++) {
|
|
89
|
+
const entry = sourceConversation[i];
|
|
90
|
+
if (!entry) continue;
|
|
91
|
+
|
|
92
|
+
// Completion judge는 자체 system 메시지를 유지하므로, Orchestrator의 system 메시지는 제외
|
|
93
|
+
if (entry.role === "system") continue;
|
|
94
|
+
|
|
95
|
+
// reasoning과 message를 모두 그대로 복사
|
|
96
|
+
// ai_request.js에서 이미 reasoning-message 쌍이 유지되고 있음
|
|
97
|
+
completionJudgeConversation.push(cloneMessage(entry));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
lastOrchestratorSnapshotLength = sourceConversation.length;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function trimCompletionJudgeConversation() {
|
|
104
|
+
for (let i = 1; i < completionJudgeConversation.length - 1; i++) {
|
|
105
|
+
const candidate = completionJudgeConversation[i];
|
|
106
|
+
if (candidate?.role !== "system") {
|
|
107
|
+
completionJudgeConversation.splice(i, 1);
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function dispatchCompletionJudgeRequest(options) {
|
|
115
|
+
if (!options) {
|
|
116
|
+
throw new Error('Completion judge request options not initialized.');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
while (true) {
|
|
120
|
+
const { model, isGpt5Model, taskName } = options;
|
|
121
|
+
const requestPayload = {
|
|
122
|
+
model,
|
|
123
|
+
input: completionJudgeConversation,
|
|
124
|
+
text: {
|
|
125
|
+
format: {
|
|
126
|
+
type: "json_schema",
|
|
127
|
+
name: completionJudgmentSchema.name,
|
|
128
|
+
strict: completionJudgmentSchema.strict,
|
|
129
|
+
schema: completionJudgmentSchema.schema
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
reasoning: {},
|
|
133
|
+
tool_choice: "none",
|
|
134
|
+
tools: [],
|
|
135
|
+
top_p: 1,
|
|
136
|
+
store: true
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
if (!isGpt5Model) {
|
|
140
|
+
requestPayload.temperature = 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
return await request(taskName, requestPayload);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
// AbortError는 즉시 전파 (세션 중단)
|
|
147
|
+
if (error.name === 'AbortError') {
|
|
148
|
+
debugLog(`[dispatchCompletionJudgeRequest] Request aborted by user`);
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!isContextWindowError(error)) {
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const trimmed = trimCompletionJudgeConversation();
|
|
157
|
+
if (!trimmed) {
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function resetCompletionJudgeConversation() {
|
|
165
|
+
completionJudgeConversation.length = 0;
|
|
166
|
+
lastOrchestratorSnapshotLength = 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function getCompletionJudgeConversation() {
|
|
170
|
+
return completionJudgeConversation;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function restoreCompletionJudgeConversation(savedConversation, savedSnapshotLength = 0) {
|
|
174
|
+
completionJudgeConversation.length = 0;
|
|
175
|
+
if (Array.isArray(savedConversation)) {
|
|
176
|
+
completionJudgeConversation.push(...savedConversation);
|
|
177
|
+
}
|
|
178
|
+
lastOrchestratorSnapshotLength = savedSnapshotLength;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Orchestrator가 function call 없이 message만 반환했을 때,
|
|
183
|
+
* 실제로 미션이 완료되었는지 판단하는 함수
|
|
184
|
+
*
|
|
185
|
+
* @param {Object} templateVars - 시스템 프롬프트 템플릿 변수 (예: mission)
|
|
186
|
+
* @returns {Promise<{shouldComplete: boolean, whatUserShouldSay: string}>}
|
|
187
|
+
*/
|
|
188
|
+
export async function judgeMissionCompletion(templateVars = {}) {
|
|
189
|
+
debugLog(`[judgeMissionCompletion] Called with templateVars: ${JSON.stringify(Object.keys(templateVars))}`);
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
const requestOptions = await createCompletionJudgeRequestOptions();
|
|
193
|
+
|
|
194
|
+
// Completion judge 자체 system 메시지 초기화 (템플릿 변수 전달)
|
|
195
|
+
await ensureCompletionJudgeConversationInitialized(templateVars);
|
|
196
|
+
// Orchestrator의 대화 내용 동기화 (system 메시지 제외)
|
|
197
|
+
syncOrchestratorConversation();
|
|
198
|
+
|
|
199
|
+
debugLog(`[judgeMissionCompletion] Sending request with ${completionJudgeConversation.length} conversation entries`);
|
|
200
|
+
|
|
201
|
+
const response = await dispatchCompletionJudgeRequest(requestOptions);
|
|
202
|
+
|
|
203
|
+
debugLog(`[judgeMissionCompletion] Received response, parsing output_text`);
|
|
204
|
+
|
|
205
|
+
// Completion judge 자신의 응답은 히스토리에 추가하지 않음 (Orchestrator와 동일한 히스토리 유지)
|
|
206
|
+
// 대화 기록 초기화 (다음 판단을 위해)
|
|
207
|
+
resetCompletionJudgeConversation();
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
const judgment = JSON.parse(response.output_text);
|
|
211
|
+
debugLog(`[judgeMissionCompletion] Parsed judgment: ${JSON.stringify(judgment)}`);
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
shouldComplete: judgment.should_complete === true,
|
|
215
|
+
whatUserShouldSay: judgment.whatUserShouldSay || ""
|
|
216
|
+
};
|
|
217
|
+
} catch (parseError) {
|
|
218
|
+
debugLog(`[judgeMissionCompletion] Parse error: ${parseError.message}`);
|
|
219
|
+
throw new Error('Completion judge response did not include valid JSON output_text.');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
} catch (error) {
|
|
223
|
+
debugLog(`[judgeMissionCompletion] ERROR: ${error.message}, error.name: ${error.name}`);
|
|
224
|
+
|
|
225
|
+
// 에러 발생 시 대화 기록 초기화
|
|
226
|
+
resetCompletionJudgeConversation();
|
|
227
|
+
|
|
228
|
+
// AbortError는 즉시 전파 (세션 중단)
|
|
229
|
+
if (error.name === 'AbortError') {
|
|
230
|
+
debugLog(`[judgeMissionCompletion] AbortError detected, propagating to caller`);
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 다른 에러 발생 시 안전하게 계속 진행
|
|
235
|
+
return {
|
|
236
|
+
shouldComplete: false,
|
|
237
|
+
whatUserShouldSay: ""
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -351,10 +351,16 @@ export async function continueOrchestratorConversation() {
|
|
|
351
351
|
|
|
352
352
|
|
|
353
353
|
// 탐색 기반으로 현재 상황을 분석하고, 다음에 취할 행동을 AI에게 결정받습니다.
|
|
354
|
-
export async function orchestrateMission({ improvement_points = '', mcpToolSchemas = [] }) {
|
|
354
|
+
export async function orchestrateMission({ improvement_points = '', mcpToolSchemas = [], isAutoGenerated = false }) {
|
|
355
355
|
const taskName = 'orchestrator';
|
|
356
356
|
|
|
357
|
+
debugLog(`[orchestrateMission] Called with improvement_points: "${improvement_points?.substring(0, 100) || '(empty)'}", isAutoGenerated: ${isAutoGenerated}`);
|
|
357
358
|
const improvementPointsText = typeof improvement_points === 'string' && improvement_points.trim().length ? improvement_points : '';
|
|
359
|
+
debugLog(`[orchestrateMission] improvementPointsText after processing: "${improvementPointsText.substring(0, 100) || '(empty)'}"`);
|
|
360
|
+
if (isAutoGenerated) {
|
|
361
|
+
debugLog(`[orchestrateMission] This is an auto-generated user message (from completion_judge)`);
|
|
362
|
+
}
|
|
363
|
+
|
|
358
364
|
|
|
359
365
|
// Python 사용 가능 여부 확인
|
|
360
366
|
const hasPython = process.app_custom?.systemInfo?.commands?.hasPython || false;
|
|
@@ -411,8 +417,8 @@ export async function orchestrateMission({ improvement_points = '', mcpToolSchem
|
|
|
411
417
|
|
|
412
418
|
await ensureConversationInitialized();
|
|
413
419
|
|
|
414
|
-
|
|
415
|
-
|
|
420
|
+
debugLog(`[orchestrateMission] Adding user message to conversation: "${improvementPointsText.substring(0, 100)}"`);
|
|
421
|
+
const userMessage = {
|
|
416
422
|
role: "user",
|
|
417
423
|
content: [
|
|
418
424
|
{
|
|
@@ -420,9 +426,19 @@ export async function orchestrateMission({ improvement_points = '', mcpToolSchem
|
|
|
420
426
|
text: improvementPointsText
|
|
421
427
|
}
|
|
422
428
|
]
|
|
423
|
-
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
// Auto-generated user message인 경우 _internal_only 플래그 추가
|
|
432
|
+
if (isAutoGenerated) {
|
|
433
|
+
userMessage._internal_only = true;
|
|
434
|
+
debugLog(`[_internal_only] Marked user message as internal-only (auto-generated from completion_judge)`);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
orchestratorConversation.push(userMessage);
|
|
438
|
+
debugLog(`[orchestrateMission] Conversation length after adding user message: ${orchestratorConversation.length}`);
|
|
424
439
|
|
|
425
440
|
const response = await dispatchOrchestratorRequest({ toolChoice: "required" });
|
|
426
441
|
appendResponseToConversation(response);
|
|
442
|
+
debugLog(`[orchestrateMission] Conversation length after response: ${orchestratorConversation.length}`);
|
|
427
443
|
return response;
|
|
428
444
|
}
|
package/src/system/ai_request.js
CHANGED
|
@@ -494,6 +494,15 @@ export async function request(taskName, requestPayload) {
|
|
|
494
494
|
// requestPayload를 deep copy하여 원본 보호
|
|
495
495
|
let payloadCopy = JSON.parse(JSON.stringify(requestPayload));
|
|
496
496
|
|
|
497
|
+
// _internal_only 속성 제거 (API 요청에 무효한 속성)
|
|
498
|
+
if (payloadCopy.input && Array.isArray(payloadCopy.input)) {
|
|
499
|
+
for (const msg of payloadCopy.input) {
|
|
500
|
+
if (msg._internal_only) {
|
|
501
|
+
delete msg._internal_only;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
497
506
|
// function_call_output의 output에서 original_result 제거
|
|
498
507
|
if (false && payloadCopy.input && Array.isArray(payloadCopy.input)) {
|
|
499
508
|
for (const msg of payloadCopy.input) {
|