codemini-cli 0.6.3 → 0.6.4
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/codemini-web/dist/assets/{AboutDialog-jgqGjQgl.js → AboutDialog-MRopwNIL.js} +2 -2
- package/codemini-web/dist/assets/CodeWikiPanel-UpK5xGE3.js +1 -0
- package/codemini-web/dist/assets/ConfigDialog-CNl28wsj.js +1 -0
- package/codemini-web/dist/assets/GitDiffDialog-gSysUg2J.js +3 -0
- package/codemini-web/dist/assets/{MemoryDialog-BhxQgG0I.js → MemoryDialog-DFUmo3Kl.js} +3 -3
- package/codemini-web/dist/assets/MessageBubble-CGnnViv0.js +12 -0
- package/codemini-web/dist/assets/PatchDiff-B8rwvEg5.js +230 -0
- package/codemini-web/dist/assets/ProjectSelector-BF59M1zb.js +1 -0
- package/codemini-web/dist/assets/{SkillDialog-DxS43NpR.js → SkillDialog-CQTjbSiw.js} +4 -4
- package/codemini-web/dist/assets/SoulDialog-BLjUGqqB.js +1 -0
- package/codemini-web/dist/assets/chevron-right--85xg7qk.js +1 -0
- package/codemini-web/dist/assets/{chunk-BO2N2NFS-Budy_hfO.js → chunk-BO2N2NFS-6uELoidu.js} +6 -6
- package/codemini-web/dist/assets/{highlighted-body-OFNGDK62-CQS1PAvD.js → highlighted-body-OFNGDK62-gb1UMBZ5.js} +1 -1
- package/codemini-web/dist/assets/index-1xqD0R5t.css +2 -0
- package/codemini-web/dist/assets/index-CDXQGwPs.js +65 -0
- package/codemini-web/dist/assets/{input-CNQgbKe6.js → input-Ca8O_061.js} +1 -1
- package/codemini-web/dist/assets/lib-BXWizt13.js +1 -0
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-ROliF8Yd.js +1 -0
- package/codemini-web/dist/assets/{pencil-Ce_LFiEh.js → pencil-BhT11Ztp.js} +1 -1
- package/codemini-web/dist/assets/{refresh-cw-BKL-AZu5.js → refresh-cw-D7R5Lth6.js} +1 -1
- package/codemini-web/dist/assets/select-DBvcHBzs.js +1 -0
- package/codemini-web/dist/assets/{trash-2-KmAlCwXd.js → trash-2-BfNZcWfX.js} +1 -1
- package/codemini-web/dist/index.html +2 -2
- package/codemini-web/lib/runtime-bridge.js +325 -296
- package/codemini-web/server.js +310 -243
- package/package.json +1 -1
- package/src/core/agent-loop.js +188 -97
- package/src/core/chat-runtime.js +674 -571
- package/src/core/config-store.js +11 -3
- package/src/core/git-oplog-change-tracker.js +387 -0
- package/src/core/non-git-backup.js +116 -0
- package/src/core/paths.js +123 -123
- package/src/core/session-store.js +148 -99
- package/src/core/tools.js +499 -456
- package/src/tui/chat-app.js +196 -56
- package/codemini-web/dist/assets/CodeWikiPanel-EPuoerNv.js +0 -1
- package/codemini-web/dist/assets/ConfigDialog-B5IGZCc9.js +0 -1
- package/codemini-web/dist/assets/GitDiffDialog-Bb_Tw5ZK.js +0 -222
- package/codemini-web/dist/assets/MessageBubble-wUff4GP4.js +0 -6
- package/codemini-web/dist/assets/ProjectSelector-C0leTf6f.js +0 -1
- package/codemini-web/dist/assets/SoulDialog-XDTEGWvH.js +0 -1
- package/codemini-web/dist/assets/chevron-right-Dbzw7YzA.js +0 -1
- package/codemini-web/dist/assets/index-D0EGtNPr.js +0 -65
- package/codemini-web/dist/assets/index-wOUf3WkN.css +0 -2
- package/codemini-web/dist/assets/lib-BOngVP_M.js +0 -11
- package/codemini-web/dist/assets/lib-DrOTTm_N.js +0 -1
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-DrBu5KyC.js +0 -1
- package/codemini-web/dist/assets/select-BZXfigic.js +0 -1
package/package.json
CHANGED
package/src/core/agent-loop.js
CHANGED
|
@@ -236,7 +236,7 @@ async function checkAutoDreamThreshold(config) {
|
|
|
236
236
|
|
|
237
237
|
// ─── Exported helpers ────────────────────────────────────────────────
|
|
238
238
|
|
|
239
|
-
function extractFileChange(toolName, result) {
|
|
239
|
+
function extractFileChange(toolName, result) {
|
|
240
240
|
if (!result || typeof result !== 'object') return null;
|
|
241
241
|
const FILE_TOOLS = new Set(['edit', 'write', 'delete']);
|
|
242
242
|
if (!FILE_TOOLS.has(toolName)) return null;
|
|
@@ -252,56 +252,90 @@ function extractFileChange(toolName, result) {
|
|
|
252
252
|
const isCreate = action === 'create';
|
|
253
253
|
const added = Number(result.lines_added || 0);
|
|
254
254
|
const removed = Number(result.lines_removed || 0);
|
|
255
|
-
return {
|
|
256
|
-
path: String(result.path || ''),
|
|
257
|
-
action: isCreate ? 'create' : 'edit',
|
|
258
|
-
linesAdded: added,
|
|
259
|
-
linesRemoved: removed,
|
|
260
|
-
changedLine: Number(result.changed_line || 0),
|
|
261
|
-
diffPreview: String(result.diff_preview || '')
|
|
262
|
-
};
|
|
263
|
-
}
|
|
255
|
+
return {
|
|
256
|
+
path: String(result.path || ''),
|
|
257
|
+
action: isCreate ? 'create' : 'edit',
|
|
258
|
+
linesAdded: added,
|
|
259
|
+
linesRemoved: removed,
|
|
260
|
+
changedLine: Number(result.changed_line || 0),
|
|
261
|
+
diffPreview: String(result.diff_preview || '')
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
264
267
|
|
|
265
|
-
return null;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
268
|
function normalizeFileChange(change) {
|
|
269
|
-
if (!change || typeof change !== 'object') return null;
|
|
270
|
-
const path = String(change.path || '').trim();
|
|
271
|
-
if (!path) return null;
|
|
272
|
-
const action = String(change.action || '').trim();
|
|
273
|
-
return {
|
|
274
|
-
path,
|
|
275
|
-
action: action === 'create' || action === 'delete' ? action : 'edit',
|
|
269
|
+
if (!change || typeof change !== 'object') return null;
|
|
270
|
+
const path = String(change.path || '').trim();
|
|
271
|
+
if (!path) return null;
|
|
272
|
+
const action = String(change.action || '').trim();
|
|
273
|
+
return {
|
|
274
|
+
path,
|
|
275
|
+
action: action === 'create' || action === 'delete' ? action : 'edit',
|
|
276
276
|
linesAdded: Number(change.linesAdded || 0),
|
|
277
277
|
linesRemoved: Number(change.linesRemoved || 0),
|
|
278
278
|
changedLine: Number(change.changedLine || 0),
|
|
279
|
-
diffPreview: String(change.diffPreview || '')
|
|
279
|
+
diffPreview: String(change.diffPreview || ''),
|
|
280
|
+
changeSetId: String(change.changeSetId || ''),
|
|
281
|
+
patchRef: String(change.patchRef || '')
|
|
280
282
|
};
|
|
281
283
|
}
|
|
282
|
-
|
|
283
|
-
function fileChangeFingerprint(change) {
|
|
284
|
-
return JSON.stringify({
|
|
285
|
-
path: change.path,
|
|
286
|
-
action: change.action,
|
|
287
|
-
linesAdded: Number(change.linesAdded || 0),
|
|
288
|
-
linesRemoved: Number(change.linesRemoved || 0),
|
|
289
|
-
changedLine: Number(change.changedLine || 0),
|
|
290
|
-
diffPreview: String(change.diffPreview || '')
|
|
284
|
+
|
|
285
|
+
function fileChangeFingerprint(change) {
|
|
286
|
+
return JSON.stringify({
|
|
287
|
+
path: change.path,
|
|
288
|
+
action: change.action,
|
|
289
|
+
linesAdded: Number(change.linesAdded || 0),
|
|
290
|
+
linesRemoved: Number(change.linesRemoved || 0),
|
|
291
|
+
changedLine: Number(change.changedLine || 0),
|
|
292
|
+
diffPreview: String(change.diffPreview || ''),
|
|
293
|
+
changeSetId: String(change.changeSetId || ''),
|
|
294
|
+
patchRef: String(change.patchRef || '')
|
|
291
295
|
});
|
|
292
296
|
}
|
|
293
|
-
|
|
297
|
+
|
|
294
298
|
function appendUniqueFileChange(message, fileChange) {
|
|
295
|
-
const existing = Array.isArray(message.file_changes) ? message.file_changes : [];
|
|
296
|
-
const nextKey = fileChangeFingerprint(fileChange);
|
|
297
|
-
if (existing.some((change) => fileChangeFingerprint(normalizeFileChange(change) || {}) === nextKey)) {
|
|
298
|
-
message.file_changes = existing;
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
299
|
+
const existing = Array.isArray(message.file_changes) ? message.file_changes : [];
|
|
300
|
+
const nextKey = fileChangeFingerprint(fileChange);
|
|
301
|
+
if (existing.some((change) => fileChangeFingerprint(normalizeFileChange(change) || {}) === nextKey)) {
|
|
302
|
+
message.file_changes = existing;
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
301
305
|
message.file_changes = [...existing, fileChange];
|
|
302
306
|
}
|
|
303
|
-
|
|
304
|
-
|
|
307
|
+
|
|
308
|
+
function normalizeFileChanges(changes) {
|
|
309
|
+
return (Array.isArray(changes) ? changes : [changes])
|
|
310
|
+
.map(normalizeFileChange)
|
|
311
|
+
.filter(Boolean);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function extractToolResultMeta(toolName, result) {
|
|
315
|
+
if (!result || typeof result !== 'object') return null;
|
|
316
|
+
if (!['edit', 'write', 'delete'].includes(String(toolName || ''))) return null;
|
|
317
|
+
const meta = {};
|
|
318
|
+
for (const key of [
|
|
319
|
+
'path',
|
|
320
|
+
'action',
|
|
321
|
+
'changed_line',
|
|
322
|
+
'lines_added',
|
|
323
|
+
'lines_removed',
|
|
324
|
+
'backupPath',
|
|
325
|
+
'backupRelativePath',
|
|
326
|
+
'backupCreated',
|
|
327
|
+
'backupReused',
|
|
328
|
+
'backupSkipped',
|
|
329
|
+
'backupError',
|
|
330
|
+
'backupReason',
|
|
331
|
+
'non_git_backup'
|
|
332
|
+
]) {
|
|
333
|
+
if (result[key] !== undefined && result[key] !== null && result[key] !== '') meta[key] = result[key];
|
|
334
|
+
}
|
|
335
|
+
return Object.keys(meta).length ? meta : null;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export const trimInline = _trimInline;
|
|
305
339
|
|
|
306
340
|
function normalizeAssistantText(value) {
|
|
307
341
|
return String(value || '').trim();
|
|
@@ -537,7 +571,7 @@ function formatToolResult(toolResult, toolName, args, toolFormatters, toolResult
|
|
|
537
571
|
|
|
538
572
|
// ─── Main agent loop ────────────────────────────────────────────────
|
|
539
573
|
|
|
540
|
-
export async function runAgentLoop({
|
|
574
|
+
export async function runAgentLoop({
|
|
541
575
|
systemPrompt,
|
|
542
576
|
userPrompt,
|
|
543
577
|
model,
|
|
@@ -547,16 +581,19 @@ export async function runAgentLoop({
|
|
|
547
581
|
maxSteps = 8,
|
|
548
582
|
initialMessages = [],
|
|
549
583
|
onEvent,
|
|
550
|
-
executionMode = '
|
|
584
|
+
executionMode = 'normal',
|
|
585
|
+
approvalMode = 'review',
|
|
586
|
+
projectIsGit = false,
|
|
551
587
|
alwaysAllowTools = [],
|
|
552
588
|
requestToolApproval,
|
|
553
589
|
toolResultMaxChars = 12000,
|
|
554
590
|
toolFormatters = {},
|
|
555
591
|
deferredDefinitions = {},
|
|
556
|
-
signal,
|
|
557
|
-
skipAnalysisNudge = false,
|
|
558
|
-
config = {}
|
|
559
|
-
|
|
592
|
+
signal,
|
|
593
|
+
skipAnalysisNudge = false,
|
|
594
|
+
config = {},
|
|
595
|
+
changeTracker = null
|
|
596
|
+
}) {
|
|
560
597
|
const messages = [];
|
|
561
598
|
if (systemPrompt) {
|
|
562
599
|
messages.push({ role: 'system', content: systemPrompt });
|
|
@@ -579,7 +616,7 @@ export async function runAgentLoop({
|
|
|
579
616
|
const activeTools = [...toolDefinitions];
|
|
580
617
|
|
|
581
618
|
async function maybeRunAutoDream(stepNumber = 0, { force = false } = {}) {
|
|
582
|
-
if (executionMode === 'plan') return;
|
|
619
|
+
if ((executionMode === 'auto' ? 'normal' : executionMode) === 'plan') return;
|
|
583
620
|
const interval = Math.max(1, Number(config?.memory?.auto_dream_check_interval_steps || 20));
|
|
584
621
|
const normalizedStep = Math.max(1, Number(stepNumber || 1));
|
|
585
622
|
if (!force && lastAutoDreamCheckStep > 0 && normalizedStep - lastAutoDreamCheckStep < interval) return;
|
|
@@ -635,13 +672,13 @@ export async function runAgentLoop({
|
|
|
635
672
|
const assistantText = completion.text || '';
|
|
636
673
|
lastAssistantText = assistantText || lastAssistantText;
|
|
637
674
|
|
|
638
|
-
const assistantMessage = completion?.assistantMessage
|
|
639
|
-
? {
|
|
640
|
-
...completion.assistantMessage,
|
|
641
|
-
role: 'assistant',
|
|
642
|
-
content: completion.assistantMessage.content ?? completion?.content ?? assistantText
|
|
643
|
-
}
|
|
644
|
-
: { role: 'assistant', content: completion?.content ?? assistantText };
|
|
675
|
+
const assistantMessage = completion?.assistantMessage
|
|
676
|
+
? {
|
|
677
|
+
...completion.assistantMessage,
|
|
678
|
+
role: 'assistant',
|
|
679
|
+
content: completion.assistantMessage.content ?? completion?.content ?? assistantText
|
|
680
|
+
}
|
|
681
|
+
: { role: 'assistant', content: completion?.content ?? assistantText };
|
|
645
682
|
if (!Array.isArray(assistantMessage.tool_calls) && toolCalls.length > 0) {
|
|
646
683
|
assistantMessage.tool_calls = toolCalls.map((tc) => ({
|
|
647
684
|
id: tc.id,
|
|
@@ -654,11 +691,11 @@ export async function runAgentLoop({
|
|
|
654
691
|
onEvent({
|
|
655
692
|
type: 'assistant:response',
|
|
656
693
|
step: step + 1,
|
|
657
|
-
text: assistantText,
|
|
658
|
-
toolCalls: toolCalls.map((tc) => tc.name),
|
|
659
|
-
usage: completion.usage || null,
|
|
660
|
-
assistantMessage
|
|
661
|
-
});
|
|
694
|
+
text: assistantText,
|
|
695
|
+
toolCalls: toolCalls.map((tc) => tc.name),
|
|
696
|
+
usage: completion.usage || null,
|
|
697
|
+
assistantMessage
|
|
698
|
+
});
|
|
662
699
|
}
|
|
663
700
|
|
|
664
701
|
if (toolCalls.length === 0) {
|
|
@@ -687,7 +724,14 @@ export async function runAgentLoop({
|
|
|
687
724
|
|
|
688
725
|
pendingSummaryNudges = 0;
|
|
689
726
|
|
|
690
|
-
|
|
727
|
+
const workMode = executionMode === 'auto' ? 'normal' : executionMode;
|
|
728
|
+
const normalizedApprovalMode = ['review', 'auto', 'full_access'].includes(String(approvalMode || '').toLowerCase())
|
|
729
|
+
? String(approvalMode || '').toLowerCase()
|
|
730
|
+
: executionMode === 'auto'
|
|
731
|
+
? 'auto'
|
|
732
|
+
: 'review';
|
|
733
|
+
|
|
734
|
+
if (workMode === 'plan') {
|
|
691
735
|
const plannedLines = callsToPlanSummary(toolCalls);
|
|
692
736
|
finalText = [
|
|
693
737
|
assistantText || '',
|
|
@@ -713,17 +757,21 @@ export async function runAgentLoop({
|
|
|
713
757
|
});
|
|
714
758
|
|
|
715
759
|
// Approval checks first — must be done synchronously before any execution
|
|
716
|
-
const approvalResults = new Map();
|
|
717
|
-
for (const { call, toolName, displayName, args } of callsWithMeta) {
|
|
718
|
-
let approved = true;
|
|
719
|
-
let approvalArgs = args;
|
|
720
|
-
let preflightErrorContent = '';
|
|
721
|
-
const isSafeModeRun = toolName === 'run'
|
|
722
|
-
&& config?.policy?.safe_mode !== false
|
|
723
|
-
&& requiresApprovalEvaluation(args?.command || '', config?.shell?.default);
|
|
724
|
-
const
|
|
725
|
-
|
|
726
|
-
|
|
760
|
+
const approvalResults = new Map();
|
|
761
|
+
for (const { call, toolName, displayName, args } of callsWithMeta) {
|
|
762
|
+
let approved = true;
|
|
763
|
+
let approvalArgs = args;
|
|
764
|
+
let preflightErrorContent = '';
|
|
765
|
+
const isSafeModeRun = toolName === 'run'
|
|
766
|
+
&& config?.policy?.safe_mode !== false
|
|
767
|
+
&& requiresApprovalEvaluation(args?.command || '', config?.shell?.default);
|
|
768
|
+
const isFileWriteTool = toolName === 'edit' || toolName === 'write' || toolName === 'delete';
|
|
769
|
+
const needsApproval = normalizedApprovalMode === 'full_access'
|
|
770
|
+
? false
|
|
771
|
+
: normalizedApprovalMode === 'auto'
|
|
772
|
+
? ((!projectIsGit && isFileWriteTool) || isSafeModeRun)
|
|
773
|
+
: (toolName === 'delete' || isSafeModeRun || !alwaysAllowSet.has(toolName));
|
|
774
|
+
if (needsApproval) {
|
|
727
775
|
approved = false;
|
|
728
776
|
const handler = toolHandlers[toolName];
|
|
729
777
|
if (toolName === 'delete' && typeof handler?.prepareApproval === 'function') {
|
|
@@ -749,10 +797,10 @@ export async function runAgentLoop({
|
|
|
749
797
|
});
|
|
750
798
|
approvalArgs = { ...args, _risk: evaluation.risk, _evaluation: evaluation };
|
|
751
799
|
/* LLM says low-risk + allow → auto-approve, skip confirmation panel */
|
|
752
|
-
if (
|
|
753
|
-
approvalResults.set(call.id, { approved: true, args: approvalArgs });
|
|
754
|
-
continue;
|
|
755
|
-
}
|
|
800
|
+
if (normalizedApprovalMode !== 'review' && evaluation.risk === 'low' && evaluation.recommendation === 'allow') {
|
|
801
|
+
approvalResults.set(call.id, { approved: true, args: approvalArgs });
|
|
802
|
+
continue;
|
|
803
|
+
}
|
|
756
804
|
} catch (_) {
|
|
757
805
|
approvalArgs = { ...args, _risk: 'high', _evaluation: null };
|
|
758
806
|
}
|
|
@@ -862,9 +910,16 @@ export async function runAgentLoop({
|
|
|
862
910
|
};
|
|
863
911
|
}
|
|
864
912
|
|
|
865
|
-
let
|
|
866
|
-
|
|
867
|
-
|
|
913
|
+
let captureScope = null;
|
|
914
|
+
if (!isReadOnly && changeTracker && typeof changeTracker.begin === 'function') {
|
|
915
|
+
try {
|
|
916
|
+
captureScope = await changeTracker.begin({ toolName, args: effectiveArgs });
|
|
917
|
+
} catch {}
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
let toolResult;
|
|
921
|
+
try {
|
|
922
|
+
toolResult = await handler(effectiveArgs);
|
|
868
923
|
} catch (error) {
|
|
869
924
|
const durationMs = Date.now() - startedAt;
|
|
870
925
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -885,13 +940,42 @@ export async function runAgentLoop({
|
|
|
885
940
|
};
|
|
886
941
|
}
|
|
887
942
|
|
|
888
|
-
const durationMs = Date.now() - startedAt;
|
|
889
|
-
const summary = summarizeToolResult(toolResult);
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
943
|
+
const durationMs = Date.now() - startedAt;
|
|
944
|
+
const summary = summarizeToolResult(toolResult);
|
|
945
|
+
const resultMeta = extractToolResultMeta(toolName, toolResult);
|
|
946
|
+
/* 提取文件改动统计 */
|
|
947
|
+
const declaredFileChange = extractFileChange(toolName, toolResult);
|
|
948
|
+
let fileChanges = [];
|
|
949
|
+
let fileChange = null;
|
|
950
|
+
if (!isReadOnly && changeTracker && typeof changeTracker.capture === 'function' && captureScope) {
|
|
951
|
+
try {
|
|
952
|
+
const captured = await changeTracker.capture(captureScope, {
|
|
953
|
+
toolName,
|
|
954
|
+
toolCallId: call.id,
|
|
955
|
+
summary,
|
|
956
|
+
args: effectiveArgs,
|
|
957
|
+
declaredFileChanges: normalizeFileChanges(declaredFileChange)
|
|
958
|
+
});
|
|
959
|
+
const capturedChanges = normalizeFileChanges(captured);
|
|
960
|
+
if (capturedChanges.length) {
|
|
961
|
+
fileChanges = capturedChanges;
|
|
962
|
+
fileChange = fileChanges[0] || null;
|
|
963
|
+
}
|
|
964
|
+
} catch (error) {
|
|
965
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
966
|
+
if (onEvent) {
|
|
967
|
+
onEvent({
|
|
968
|
+
type: 'system_tool:error',
|
|
969
|
+
id: `change-oplog-${call.id}`,
|
|
970
|
+
name: 'change_oplog',
|
|
971
|
+
summary: message
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
if (onEvent) {
|
|
977
|
+
onEvent({ type: 'tool:end', name: displayName, id: call.id, arguments: effectiveArgs, durationMs, summary, fileChange, fileChanges, resultMeta });
|
|
978
|
+
}
|
|
895
979
|
|
|
896
980
|
// Auto-capture non-throwing tool failures (e.g. shell non-zero exit)
|
|
897
981
|
if (toolResult && typeof toolResult === 'object') {
|
|
@@ -928,7 +1012,7 @@ export async function runAgentLoop({
|
|
|
928
1012
|
// P0: Persist to disk if still large
|
|
929
1013
|
formatted = await storeResultIfNeeded(call.id, formatted, toolResult);
|
|
930
1014
|
|
|
931
|
-
return { callId: call.id, content: formatted, durationMs, summary, status: 'done', fileChange };
|
|
1015
|
+
return { callId: call.id, content: formatted, durationMs, summary, status: 'done', fileChange, fileChanges, resultMeta };
|
|
932
1016
|
}
|
|
933
1017
|
|
|
934
1018
|
// Separate read-only and write calls, preserving order
|
|
@@ -972,15 +1056,17 @@ export async function runAgentLoop({
|
|
|
972
1056
|
continue;
|
|
973
1057
|
}
|
|
974
1058
|
|
|
975
|
-
attachToolCallSessionMeta(assistantMessage, call.id, { durationMs: entry.durationMs, summary: entry.summary || '', status: entry.status || 'done', fileChange: entry.fileChange });
|
|
1059
|
+
attachToolCallSessionMeta(assistantMessage, call.id, { durationMs: entry.durationMs, summary: entry.summary || '', status: entry.status || 'done', fileChange: entry.fileChange, fileChanges: entry.fileChanges, resultMeta: entry.resultMeta });
|
|
976
1060
|
messages.push({
|
|
977
|
-
role: 'tool',
|
|
978
|
-
tool_call_id: call.id,
|
|
979
|
-
content: entry.content,
|
|
980
|
-
tool_duration_ms: entry.durationMs,
|
|
1061
|
+
role: 'tool',
|
|
1062
|
+
tool_call_id: call.id,
|
|
1063
|
+
content: entry.content,
|
|
1064
|
+
tool_duration_ms: entry.durationMs,
|
|
981
1065
|
tool_summary: entry.summary || '',
|
|
982
1066
|
tool_status: entry.status || 'done',
|
|
983
|
-
...(entry.
|
|
1067
|
+
...(entry.resultMeta ? { tool_result_meta: entry.resultMeta } : {}),
|
|
1068
|
+
...(entry.fileChange ? { tool_file_change: entry.fileChange } : {}),
|
|
1069
|
+
...(Array.isArray(entry.fileChanges) && entry.fileChanges.length > 0 ? { tool_file_changes: entry.fileChanges } : {})
|
|
984
1070
|
});
|
|
985
1071
|
if (onEvent) {
|
|
986
1072
|
onEvent({ type: 'tool:result', name: displayName, id: call.id, arguments: args, content: entry.content });
|
|
@@ -1017,16 +1103,21 @@ function callsToPlanSummary(toolCalls = []) {
|
|
|
1017
1103
|
});
|
|
1018
1104
|
}
|
|
1019
1105
|
|
|
1020
|
-
function attachToolCallSessionMeta(assistantMessage, callId, meta = {}) {
|
|
1021
|
-
if (!assistantMessage || !Array.isArray(assistantMessage.tool_calls)) return;
|
|
1022
|
-
const call = assistantMessage.tool_calls.find((tc) => String(tc?.id || '') === String(callId || ''));
|
|
1023
|
-
if (!call) return;
|
|
1024
|
-
if (Number.isFinite(Number(meta.durationMs))) call.durationMs = Number(meta.durationMs);
|
|
1106
|
+
function attachToolCallSessionMeta(assistantMessage, callId, meta = {}) {
|
|
1107
|
+
if (!assistantMessage || !Array.isArray(assistantMessage.tool_calls)) return;
|
|
1108
|
+
const call = assistantMessage.tool_calls.find((tc) => String(tc?.id || '') === String(callId || ''));
|
|
1109
|
+
if (!call) return;
|
|
1110
|
+
if (Number.isFinite(Number(meta.durationMs))) call.durationMs = Number(meta.durationMs);
|
|
1025
1111
|
if (typeof meta.summary === 'string' && meta.summary.trim()) call.summary = meta.summary.trim();
|
|
1026
1112
|
if (typeof meta.status === 'string' && meta.status.trim()) call.status = meta.status.trim();
|
|
1113
|
+
if (meta.resultMeta && typeof meta.resultMeta === 'object') call.resultMeta = meta.resultMeta;
|
|
1027
1114
|
const fileChange = normalizeFileChange(meta.fileChange);
|
|
1028
1115
|
if (fileChange) {
|
|
1029
1116
|
call.fileChange = fileChange;
|
|
1030
|
-
|
|
1117
|
+
}
|
|
1118
|
+
const fileChanges = normalizeFileChanges(meta.fileChanges && meta.fileChanges.length ? meta.fileChanges : fileChange);
|
|
1119
|
+
if (fileChanges.length) {
|
|
1120
|
+
call.fileChanges = fileChanges;
|
|
1121
|
+
for (const change of fileChanges) appendUniqueFileChange(assistantMessage, change);
|
|
1031
1122
|
}
|
|
1032
1123
|
}
|