@aigencydev/cli 0.3.6 → 0.3.8
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.
- package/dist/agent/history.js +1 -1
- package/dist/agent/loop.js +13 -0
- package/dist/tools/assert-done.js +91 -0
- package/dist/tools/edit-file-multi.js +205 -0
- package/dist/tools/edit-file.js +20 -0
- package/dist/tools/registry.js +4 -0
- package/dist/ui/App.js +35 -8
- package/dist/ui/MessageList.js +10 -2
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/agent/history.js
CHANGED
package/dist/agent/loop.js
CHANGED
|
@@ -2,6 +2,7 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import { openStream, sendToolResult } from "../api-client/stream.js";
|
|
3
3
|
import { dispatchLocalTool, hasLocalTool } from "../tools/registry.js";
|
|
4
4
|
import { prepareChunk } from "./chunker.js";
|
|
5
|
+
import { loadPersistedTaskList } from "./task-list.js";
|
|
5
6
|
import { log } from "../utils/logger.js";
|
|
6
7
|
import { runHooks } from "../config/hooks.js";
|
|
7
8
|
function generateRequestId() {
|
|
@@ -145,6 +146,17 @@ export async function runAgentLoop(params) {
|
|
|
145
146
|
break;
|
|
146
147
|
}
|
|
147
148
|
};
|
|
149
|
+
let persistedTasks = [];
|
|
150
|
+
if (params.sessionId) {
|
|
151
|
+
try {
|
|
152
|
+
const persisted = await loadPersistedTaskList(params.sessionId);
|
|
153
|
+
if (persisted?.tasks) {
|
|
154
|
+
persistedTasks = persisted.tasks;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
}
|
|
159
|
+
}
|
|
148
160
|
try {
|
|
149
161
|
await openStream(params.accessToken, {
|
|
150
162
|
request_id: requestId,
|
|
@@ -156,6 +168,7 @@ export async function runAgentLoop(params) {
|
|
|
156
168
|
model: params.model,
|
|
157
169
|
chat_history: streamHistory,
|
|
158
170
|
compacted_summary: params.priorInsights,
|
|
171
|
+
current_tasks: persistedTasks,
|
|
159
172
|
}, onEvent, params.signal);
|
|
160
173
|
}
|
|
161
174
|
catch (err) {
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { getTaskList } from "../agent/task-list.js";
|
|
2
|
+
export const assertDoneHandler = async (params, ctx) => {
|
|
3
|
+
const start = Date.now();
|
|
4
|
+
const userGoal = String(params.user_goal || "").trim();
|
|
5
|
+
const outputsRaw = params.outputs_delivered;
|
|
6
|
+
const remainingRaw = params.remaining;
|
|
7
|
+
const confidence = String(params.confidence || "").toLowerCase();
|
|
8
|
+
const outputs = Array.isArray(outputsRaw)
|
|
9
|
+
? outputsRaw.map(String).filter((s) => s.length > 0)
|
|
10
|
+
: [];
|
|
11
|
+
const remaining = Array.isArray(remainingRaw)
|
|
12
|
+
? remainingRaw.map(String).filter((s) => s.length > 0)
|
|
13
|
+
: [];
|
|
14
|
+
if (!userGoal) {
|
|
15
|
+
return {
|
|
16
|
+
success: false,
|
|
17
|
+
output: "",
|
|
18
|
+
error: "assert_done: user_goal parametresi zorunlu. Kullanıcının ana hedefini tek cümlede yaz.",
|
|
19
|
+
duration: Date.now() - start,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const reasons = [];
|
|
23
|
+
if (remaining.length > 0) {
|
|
24
|
+
reasons.push(`LLM kendi beyanında ${remaining.length} eksik madde saydı: ${remaining.slice(0, 3).join(", ")}`);
|
|
25
|
+
}
|
|
26
|
+
if (outputs.length === 0) {
|
|
27
|
+
reasons.push("outputs_delivered boş — kullanıcıya teslim edilen somut çıktı yok");
|
|
28
|
+
}
|
|
29
|
+
if (ctx.sessionId) {
|
|
30
|
+
const state = getTaskList(ctx.sessionId);
|
|
31
|
+
const incomplete = state.tasks.filter((t) => t.status !== "completed");
|
|
32
|
+
if (incomplete.length > 0) {
|
|
33
|
+
reasons.push(`Task listesinde ${incomplete.length}/${state.tasks.length} görev hala pending/in_progress: ${incomplete
|
|
34
|
+
.slice(0, 3)
|
|
35
|
+
.map((t) => t.content)
|
|
36
|
+
.join(", ")}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (confidence === "low") {
|
|
40
|
+
reasons.push("confidence=low — kendi bile işin bittiğinden emin değilsin, gate açılmaz");
|
|
41
|
+
}
|
|
42
|
+
if (reasons.length > 0) {
|
|
43
|
+
const output = [
|
|
44
|
+
"## Done Gate REDDETTİ",
|
|
45
|
+
"",
|
|
46
|
+
`Kullanıcı hedefi: ${userGoal}`,
|
|
47
|
+
"",
|
|
48
|
+
"### Reddedilme nedenleri",
|
|
49
|
+
...reasons.map((r, i) => `${i + 1}. ${r}`),
|
|
50
|
+
"",
|
|
51
|
+
"### Şimdi yapman gereken",
|
|
52
|
+
"- Eksik kalan işleri bitir",
|
|
53
|
+
"- write_tasks ile task state'i güncelle",
|
|
54
|
+
"- Tekrar assert_done çağır",
|
|
55
|
+
"",
|
|
56
|
+
"ASLA final agent_message yazma — önce bu gate yeşile dönmeli.",
|
|
57
|
+
].join("\n");
|
|
58
|
+
return {
|
|
59
|
+
success: false,
|
|
60
|
+
output,
|
|
61
|
+
error: `Done gate reddetti: ${reasons.length} eksiklik`,
|
|
62
|
+
metadata: {
|
|
63
|
+
gate_passed: false,
|
|
64
|
+
reasons,
|
|
65
|
+
outputs_count: outputs.length,
|
|
66
|
+
remaining_count: remaining.length,
|
|
67
|
+
},
|
|
68
|
+
approvalState: 2,
|
|
69
|
+
duration: Date.now() - start,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
success: true,
|
|
74
|
+
output: [
|
|
75
|
+
"## Done Gate YEŞİL ✓",
|
|
76
|
+
"",
|
|
77
|
+
`Kullanıcı hedefi: ${userGoal}`,
|
|
78
|
+
"",
|
|
79
|
+
`Teslim edilen çıktılar (${outputs.length}):`,
|
|
80
|
+
...outputs.map((o) => `- ${o}`),
|
|
81
|
+
"",
|
|
82
|
+
"Bu turda final mesajı yazabilirsin. Kullanıcıya nasıl çalıştıracağını söylemeyi unutma.",
|
|
83
|
+
].join("\n"),
|
|
84
|
+
metadata: {
|
|
85
|
+
gate_passed: true,
|
|
86
|
+
outputs_count: outputs.length,
|
|
87
|
+
},
|
|
88
|
+
approvalState: 2,
|
|
89
|
+
duration: Date.now() - start,
|
|
90
|
+
};
|
|
91
|
+
};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { checkWritePath } from "../security/sandbox.js";
|
|
3
|
+
import { simpleDiff, summarizeDiff } from "./diff.js";
|
|
4
|
+
import { captureCheckpoint } from "../agent/checkpoints.js";
|
|
5
|
+
export const editFileMultiTool = async (params, ctx) => {
|
|
6
|
+
const start = Date.now();
|
|
7
|
+
const rawPath = (params.path || params.filePath || "");
|
|
8
|
+
const editsRaw = params.edits;
|
|
9
|
+
if (!rawPath) {
|
|
10
|
+
return {
|
|
11
|
+
success: false,
|
|
12
|
+
output: "",
|
|
13
|
+
error: "path parametresi eksik",
|
|
14
|
+
duration: Date.now() - start,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
if (!Array.isArray(editsRaw) || editsRaw.length === 0) {
|
|
18
|
+
return {
|
|
19
|
+
success: false,
|
|
20
|
+
output: "",
|
|
21
|
+
error: "edits parametresi dolu bir dizi olmalı: [{ old_string, new_string }, ...]",
|
|
22
|
+
duration: Date.now() - start,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const edits = [];
|
|
26
|
+
for (let i = 0; i < editsRaw.length; i++) {
|
|
27
|
+
const e = editsRaw[i];
|
|
28
|
+
if (typeof e !== "object" || e === null) {
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
output: "",
|
|
32
|
+
error: `edits[${i}]: obje olmalı`,
|
|
33
|
+
duration: Date.now() - start,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const obj = e;
|
|
37
|
+
if (typeof obj.old_string !== "string" || obj.old_string.length === 0) {
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
output: "",
|
|
41
|
+
error: `edits[${i}].old_string boş olamaz`,
|
|
42
|
+
duration: Date.now() - start,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (typeof obj.new_string !== "string") {
|
|
46
|
+
return {
|
|
47
|
+
success: false,
|
|
48
|
+
output: "",
|
|
49
|
+
error: `edits[${i}].new_string string olmalı`,
|
|
50
|
+
duration: Date.now() - start,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
edits.push({
|
|
54
|
+
old_string: obj.old_string,
|
|
55
|
+
new_string: obj.new_string,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (edits.length > 20) {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
output: "",
|
|
62
|
+
error: `edits dizisi en fazla 20 eleman içerebilir (şu an ${edits.length}). Çok fazla değişiklik için write_file kullan.`,
|
|
63
|
+
duration: Date.now() - start,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (ctx.mode === "plan") {
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
output: "",
|
|
70
|
+
error: "Plan modunda dosya düzenleme yasak. /mode accept_edits ile değiştirin.",
|
|
71
|
+
duration: Date.now() - start,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const check = checkWritePath(rawPath, ctx.cwd);
|
|
75
|
+
if (!check.ok || !check.realPath) {
|
|
76
|
+
return {
|
|
77
|
+
success: false,
|
|
78
|
+
output: "",
|
|
79
|
+
error: check.message || "Yol reddedildi",
|
|
80
|
+
duration: Date.now() - start,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
let originalContent;
|
|
84
|
+
try {
|
|
85
|
+
originalContent = await fs.readFile(check.realPath, "utf8");
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
output: "",
|
|
91
|
+
error: `Dosya okunamadı: ${check.displayPath}`,
|
|
92
|
+
duration: Date.now() - start,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
let working = originalContent;
|
|
96
|
+
const failures = [];
|
|
97
|
+
for (let i = 0; i < edits.length; i++) {
|
|
98
|
+
const e = edits[i];
|
|
99
|
+
const firstIdx = working.indexOf(e.old_string);
|
|
100
|
+
if (firstIdx === -1) {
|
|
101
|
+
failures.push({
|
|
102
|
+
index: i,
|
|
103
|
+
reason: `old_string dosyada bulunamadı: ${e.old_string.slice(0, 60)}...`,
|
|
104
|
+
});
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const secondIdx = working.indexOf(e.old_string, firstIdx + 1);
|
|
108
|
+
if (secondIdx !== -1) {
|
|
109
|
+
failures.push({
|
|
110
|
+
index: i,
|
|
111
|
+
reason: `old_string birden fazla yerde geçiyor (${e.old_string.slice(0, 60)}...). Daha fazla bağlam ekle.`,
|
|
112
|
+
});
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
working =
|
|
116
|
+
working.slice(0, firstIdx) +
|
|
117
|
+
e.new_string +
|
|
118
|
+
working.slice(firstIdx + e.old_string.length);
|
|
119
|
+
}
|
|
120
|
+
if (failures.length > 0) {
|
|
121
|
+
return {
|
|
122
|
+
success: false,
|
|
123
|
+
output: "",
|
|
124
|
+
error: `${failures.length}/${edits.length} edit başarısız (atomik rollback): ${failures
|
|
125
|
+
.map((f) => `[${f.index}] ${f.reason}`)
|
|
126
|
+
.join("; ")}`,
|
|
127
|
+
metadata: { failed_indices: failures.map((f) => f.index) },
|
|
128
|
+
duration: Date.now() - start,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (working === originalContent) {
|
|
132
|
+
return {
|
|
133
|
+
success: false,
|
|
134
|
+
output: "",
|
|
135
|
+
error: "Hiçbir edit dosyayı değiştirmedi (tüm old_string → new_string çifti aynı?)",
|
|
136
|
+
duration: Date.now() - start,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const diff = summarizeDiff(originalContent, working);
|
|
140
|
+
const previewLines = simpleDiff(originalContent, working, 20);
|
|
141
|
+
let approvalState = 2;
|
|
142
|
+
if (ctx.mode === "default") {
|
|
143
|
+
if (!ctx.requestPermission) {
|
|
144
|
+
return {
|
|
145
|
+
success: false,
|
|
146
|
+
output: "",
|
|
147
|
+
error: "Permission callback yok",
|
|
148
|
+
duration: Date.now() - start,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const resp = await ctx.requestPermission({
|
|
152
|
+
toolName: "edit_file_multi",
|
|
153
|
+
severity: "medium",
|
|
154
|
+
title: `${edits.length} edit: ${check.displayPath}`,
|
|
155
|
+
description: `+${diff.added} -${diff.removed} satır (${edits.length} ayrı değişiklik)`,
|
|
156
|
+
preview: previewLines,
|
|
157
|
+
});
|
|
158
|
+
if (resp.decision === "reject") {
|
|
159
|
+
return {
|
|
160
|
+
success: false,
|
|
161
|
+
output: "",
|
|
162
|
+
error: "Kullanıcı reddetti",
|
|
163
|
+
approvalState: 0,
|
|
164
|
+
duration: Date.now() - start,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (resp.decision === "cancel") {
|
|
168
|
+
return {
|
|
169
|
+
success: false,
|
|
170
|
+
output: "",
|
|
171
|
+
error: "İşlem iptal edildi",
|
|
172
|
+
approvalState: 0,
|
|
173
|
+
duration: Date.now() - start,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
approvalState = 1;
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
if (ctx.sessionId && ctx.projectRoot) {
|
|
180
|
+
await captureCheckpoint(ctx.sessionId, check.realPath, "edit", ctx.projectRoot);
|
|
181
|
+
}
|
|
182
|
+
await fs.writeFile(check.realPath, working, "utf8");
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
return {
|
|
186
|
+
success: false,
|
|
187
|
+
output: "",
|
|
188
|
+
error: `Yazma hatası: ${err.message.slice(0, 120)}`,
|
|
189
|
+
approvalState,
|
|
190
|
+
duration: Date.now() - start,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
success: true,
|
|
195
|
+
output: `${edits.length} edit uygulandı: ${check.displayPath} (+${diff.added} -${diff.removed})`,
|
|
196
|
+
metadata: {
|
|
197
|
+
path: check.displayPath,
|
|
198
|
+
edit_count: edits.length,
|
|
199
|
+
added: diff.added,
|
|
200
|
+
removed: diff.removed,
|
|
201
|
+
},
|
|
202
|
+
approvalState,
|
|
203
|
+
duration: Date.now() - start,
|
|
204
|
+
};
|
|
205
|
+
};
|
package/dist/tools/edit-file.js
CHANGED
|
@@ -2,6 +2,11 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import { checkWritePath } from "../security/sandbox.js";
|
|
3
3
|
import { simpleDiff, summarizeDiff } from "./diff.js";
|
|
4
4
|
import { captureCheckpoint } from "../agent/checkpoints.js";
|
|
5
|
+
const editCountByFile = new Map();
|
|
6
|
+
const EDIT_SAME_FILE_THRESHOLD = 5;
|
|
7
|
+
export function resetEditCounter() {
|
|
8
|
+
editCountByFile.clear();
|
|
9
|
+
}
|
|
5
10
|
export const editFileTool = async (params, ctx) => {
|
|
6
11
|
const start = Date.now();
|
|
7
12
|
const rawPath = (params.path || params.filePath || "");
|
|
@@ -56,6 +61,21 @@ export const editFileTool = async (params, ctx) => {
|
|
|
56
61
|
duration: Date.now() - start,
|
|
57
62
|
};
|
|
58
63
|
}
|
|
64
|
+
const prevCount = editCountByFile.get(check.realPath) || 0;
|
|
65
|
+
const newCount = prevCount + 1;
|
|
66
|
+
editCountByFile.set(check.realPath, newCount);
|
|
67
|
+
if (newCount >= EDIT_SAME_FILE_THRESHOLD) {
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
output: "",
|
|
71
|
+
error: `Bu dosyaya (${check.displayPath}) ${newCount}. kez edit_file çağırıyorsun. ` +
|
|
72
|
+
`Parça parça micro-edit verimsiz — tüm dosyayı TEK SEFERDE write_file ile yeniden yaz. ` +
|
|
73
|
+
`Rich Content Schema'ya göre 300+ satırlık gerçek içerik üret, küçük class değişiklikleriyle oyalanma.`,
|
|
74
|
+
metadata: { edit_count: newCount, suggestion: "use_write_file" },
|
|
75
|
+
approvalState: 0,
|
|
76
|
+
duration: Date.now() - start,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
59
79
|
let existing;
|
|
60
80
|
try {
|
|
61
81
|
existing = await fs.readFile(check.realPath, "utf8");
|
package/dist/tools/registry.js
CHANGED
|
@@ -3,16 +3,19 @@ import { listFilesTool } from "./list-files.js";
|
|
|
3
3
|
import { searchFilesTool } from "./search-files.js";
|
|
4
4
|
import { writeFileTool } from "./write-file.js";
|
|
5
5
|
import { editFileTool } from "./edit-file.js";
|
|
6
|
+
import { editFileMultiTool } from "./edit-file-multi.js";
|
|
6
7
|
import { bashTool } from "./bash.js";
|
|
7
8
|
import { saveMemoryToolHandler, readMemoryToolHandler, deleteMemoryToolHandler, } from "./memory-tools.js";
|
|
8
9
|
import { writeTasksHandler, readTasksHandler } from "./task-tools.js";
|
|
9
10
|
import { verifyProjectHandler } from "./verify-project.js";
|
|
11
|
+
import { assertDoneHandler } from "./assert-done.js";
|
|
10
12
|
const HANDLERS = {
|
|
11
13
|
read_file: readFileTool,
|
|
12
14
|
list_files: listFilesTool,
|
|
13
15
|
search_files: searchFilesTool,
|
|
14
16
|
write_file: writeFileTool,
|
|
15
17
|
edit_file: editFileTool,
|
|
18
|
+
edit_file_multi: editFileMultiTool,
|
|
16
19
|
bash_execute: bashTool,
|
|
17
20
|
save_memory: saveMemoryToolHandler,
|
|
18
21
|
read_memory: readMemoryToolHandler,
|
|
@@ -20,6 +23,7 @@ const HANDLERS = {
|
|
|
20
23
|
write_tasks: writeTasksHandler,
|
|
21
24
|
read_tasks: readTasksHandler,
|
|
22
25
|
verify_project: verifyProjectHandler,
|
|
26
|
+
assert_done: assertDoneHandler,
|
|
23
27
|
};
|
|
24
28
|
export function hasLocalTool(name) {
|
|
25
29
|
return name in HANDLERS;
|
package/dist/ui/App.js
CHANGED
|
@@ -111,7 +111,7 @@ export function App({ session, initialMode, initialModel, cwd, projectRoot, init
|
|
|
111
111
|
if (cmd === "help") {
|
|
112
112
|
pushMessage({
|
|
113
113
|
kind: "info",
|
|
114
|
-
content: "Komutlar: /clear /help /mode /cost /undo /exit",
|
|
114
|
+
content: "Komutlar: /clear /help /mode /cost /undo /continue /exit",
|
|
115
115
|
});
|
|
116
116
|
pushMessage({
|
|
117
117
|
kind: "info",
|
|
@@ -119,6 +119,13 @@ export function App({ session, initialMode, initialModel, cwd, projectRoot, init
|
|
|
119
119
|
});
|
|
120
120
|
return true;
|
|
121
121
|
}
|
|
122
|
+
if (cmd === "continue" || cmd === "devam") {
|
|
123
|
+
pushMessage({
|
|
124
|
+
kind: "info",
|
|
125
|
+
content: "Kaldığın yerden devam ediliyor...",
|
|
126
|
+
});
|
|
127
|
+
return "Kaldığım yerden devam ediyorum. Önce read_tasks ile mevcut plana bak, pending ve in_progress task'leri sıraya göre tamamla. Tüm task'lar completed olana kadar durma.";
|
|
128
|
+
}
|
|
122
129
|
if (cmd === "undo") {
|
|
123
130
|
void (async () => {
|
|
124
131
|
const cp = await findLatestCheckpoint(sessionIdRef.current, projectRoot);
|
|
@@ -169,12 +176,21 @@ export function App({ session, initialMode, initialModel, cwd, projectRoot, init
|
|
|
169
176
|
return true;
|
|
170
177
|
}, [exit, mode, projectRoot, pushMessage, tokensLimit, tokensUsed]);
|
|
171
178
|
const handleSubmit = useCallback(async (value) => {
|
|
179
|
+
let effectivePrompt = value;
|
|
172
180
|
if (value.startsWith("/")) {
|
|
173
|
-
handleSlashCommand(value);
|
|
174
|
-
|
|
181
|
+
const slashResult = handleSlashCommand(value);
|
|
182
|
+
if (slashResult === true) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (typeof slashResult === "string") {
|
|
186
|
+
effectivePrompt = slashResult;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
175
191
|
}
|
|
176
|
-
pushMessage({ kind: "user", content:
|
|
177
|
-
void recorderRef.current.userMessage(
|
|
192
|
+
pushMessage({ kind: "user", content: effectivePrompt });
|
|
193
|
+
void recorderRef.current.userMessage(effectivePrompt);
|
|
178
194
|
setBusy(true);
|
|
179
195
|
const controller = new AbortController();
|
|
180
196
|
abortRef.current = controller;
|
|
@@ -251,7 +267,18 @@ export function App({ session, initialMode, initialModel, cwd, projectRoot, init
|
|
|
251
267
|
case "agent_message":
|
|
252
268
|
if (!event.delta) {
|
|
253
269
|
setThinking("");
|
|
254
|
-
|
|
270
|
+
const incomplete = taskList.filter((t) => t.status !== "completed");
|
|
271
|
+
const warning = incomplete.length > 0
|
|
272
|
+
? `${incomplete.length} görev yarım kaldı: ${incomplete
|
|
273
|
+
.slice(0, 3)
|
|
274
|
+
.map((t) => t.content)
|
|
275
|
+
.join(" · ")}${incomplete.length > 3 ? " · …" : ""}`
|
|
276
|
+
: undefined;
|
|
277
|
+
pushMessage({
|
|
278
|
+
kind: "assistant",
|
|
279
|
+
content: event.content,
|
|
280
|
+
completionWarning: warning,
|
|
281
|
+
});
|
|
255
282
|
void recorderRef.current.assistantMessage(event.content);
|
|
256
283
|
}
|
|
257
284
|
break;
|
|
@@ -279,7 +306,7 @@ export function App({ session, initialMode, initialModel, cwd, projectRoot, init
|
|
|
279
306
|
};
|
|
280
307
|
const result = await runAgentLoop({
|
|
281
308
|
accessToken: session.access_token,
|
|
282
|
-
prompt:
|
|
309
|
+
prompt: effectivePrompt,
|
|
283
310
|
history: historyRef.current,
|
|
284
311
|
mode,
|
|
285
312
|
model,
|
|
@@ -293,7 +320,7 @@ export function App({ session, initialMode, initialModel, cwd, projectRoot, init
|
|
|
293
320
|
settings,
|
|
294
321
|
priorInsights: memorySummary,
|
|
295
322
|
});
|
|
296
|
-
historyRef.current.push({ role: "user", content:
|
|
323
|
+
historyRef.current.push({ role: "user", content: effectivePrompt });
|
|
297
324
|
if (result.finalMessage) {
|
|
298
325
|
historyRef.current.push({
|
|
299
326
|
role: "assistant",
|
package/dist/ui/MessageList.js
CHANGED
|
@@ -55,11 +55,19 @@ function MessageItem({ message }) {
|
|
|
55
55
|
message.content)));
|
|
56
56
|
}
|
|
57
57
|
if (message.kind === "assistant") {
|
|
58
|
-
return (React.createElement(Box,
|
|
58
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
59
59
|
React.createElement(Text, { color: color },
|
|
60
60
|
prefix,
|
|
61
61
|
" ",
|
|
62
|
-
safeContent)
|
|
62
|
+
safeContent),
|
|
63
|
+
message.completionWarning && (React.createElement(Box, { marginTop: 1, marginLeft: 2, paddingX: 1, borderStyle: "round", borderColor: palette.warning, flexDirection: "column" },
|
|
64
|
+
React.createElement(Text, { color: palette.warning, bold: true },
|
|
65
|
+
symbols.warning,
|
|
66
|
+
" Yar\u0131m i\u015F uyar\u0131s\u0131"),
|
|
67
|
+
React.createElement(Text, { color: palette.textSecondary }, message.completionWarning),
|
|
68
|
+
React.createElement(Text, { color: palette.textFaint },
|
|
69
|
+
symbols.arrow,
|
|
70
|
+
" \"devam et\" yazarak ajan\u0131 yeniden tetikle")))));
|
|
63
71
|
}
|
|
64
72
|
return (React.createElement(Box, null,
|
|
65
73
|
React.createElement(Text, { color: color },
|
package/dist/version.js
CHANGED