codemini-cli 0.2.0 → 0.2.2
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/README.md +44 -20
- package/package.json +4 -2
- package/src/cli.js +1 -1
- package/src/commands/chat.js +1 -0
- package/src/core/ast.js +310 -0
- package/src/core/chat-runtime.js +37 -15
- package/src/core/checkpoint-store.js +2 -1
- package/src/core/command-loader.js +3 -4
- package/src/core/config-store.js +6 -3
- package/src/core/default-system-prompt.js +1 -1
- package/src/core/paths.js +52 -58
- package/src/core/project-index.js +510 -0
- package/src/core/shell-profile.js +1 -1
- package/src/core/task-store.js +3 -2
- package/src/core/tools.js +173 -6
- package/src/tui/chat-app.js +221 -47
package/src/tui/chat-app.js
CHANGED
|
@@ -63,6 +63,7 @@ const TUI_COPY = {
|
|
|
63
63
|
waitingForInput: '等待输入',
|
|
64
64
|
ready: '就绪',
|
|
65
65
|
noMessagesYet: '还没有消息',
|
|
66
|
+
taskCompleted: '已完成任务',
|
|
66
67
|
code: '代码',
|
|
67
68
|
codeActivity: '代码活动',
|
|
68
69
|
textNotes: '说明文本',
|
|
@@ -140,6 +141,10 @@ const TUI_COPY = {
|
|
|
140
141
|
doingCodeGeneration: '正在生成代码',
|
|
141
142
|
doneSkill: '已完成技能',
|
|
142
143
|
doingSkill: '正在执行技能',
|
|
144
|
+
doneProjectIndex: '已初始化项目索引',
|
|
145
|
+
doingProjectIndex: '正在初始化项目索引',
|
|
146
|
+
doneFileIndex: '已刷新文件索引',
|
|
147
|
+
doingFileIndex: '正在刷新文件索引',
|
|
143
148
|
toolFailed: (name) => `工具执行失败: ${name}`,
|
|
144
149
|
waitingModelContinue: (detail) => `${detail},等待模型继续`,
|
|
145
150
|
waitingModelAdjust: (detail) => `${detail},等待模型调整`
|
|
@@ -189,6 +194,7 @@ const TUI_COPY = {
|
|
|
189
194
|
waitingForInput: 'waiting for input',
|
|
190
195
|
ready: 'ready',
|
|
191
196
|
noMessagesYet: 'No messages yet',
|
|
197
|
+
taskCompleted: 'Task completed',
|
|
192
198
|
code: 'code',
|
|
193
199
|
codeActivity: 'CODE ACTIVITY',
|
|
194
200
|
textNotes: 'NOTES',
|
|
@@ -266,6 +272,10 @@ const TUI_COPY = {
|
|
|
266
272
|
doingCodeGeneration: 'Generating code',
|
|
267
273
|
doneSkill: 'Completed skill',
|
|
268
274
|
doingSkill: 'Running skill',
|
|
275
|
+
doneProjectIndex: 'Project index initialized',
|
|
276
|
+
doingProjectIndex: 'Initializing project index',
|
|
277
|
+
doneFileIndex: 'File index refreshed',
|
|
278
|
+
doingFileIndex: 'Refreshing file index',
|
|
269
279
|
toolFailed: (name) => `Tool failed: ${name}`,
|
|
270
280
|
waitingModelContinue: (detail) => `${detail}, waiting for model to continue`,
|
|
271
281
|
waitingModelAdjust: (detail) => `${detail}, waiting for model to adjust`
|
|
@@ -431,6 +441,12 @@ function getActivityDisplayParts(activity) {
|
|
|
431
441
|
secondary: `(${activity?.name || 'unknown'})`
|
|
432
442
|
};
|
|
433
443
|
}
|
|
444
|
+
if ((activity?.type || 'tool') === 'system_tool') {
|
|
445
|
+
return {
|
|
446
|
+
primary: 'Index',
|
|
447
|
+
secondary: parsed.target ? `(${parsed.target})` : parsed.base ? `(${parsed.base})` : ''
|
|
448
|
+
};
|
|
449
|
+
}
|
|
434
450
|
const labels = {
|
|
435
451
|
read: 'Read',
|
|
436
452
|
edit: 'Edit',
|
|
@@ -455,8 +471,32 @@ function getActivityDisplayParts(activity) {
|
|
|
455
471
|
};
|
|
456
472
|
}
|
|
457
473
|
|
|
474
|
+
export function isIndexSystemToolName(name) {
|
|
475
|
+
const parsed = parseToolDisplayName(name);
|
|
476
|
+
return parsed.base === 'project_index' || parsed.base === 'file_index';
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export function shouldShowCompletionFooter(msg) {
|
|
480
|
+
return Boolean(msg && msg.label === 'coder' && !msg.loading && !(msg.phase || '').trim());
|
|
481
|
+
}
|
|
482
|
+
|
|
458
483
|
function describeToolActivity(name, copy, { done = false, blocked = false } = {}) {
|
|
459
484
|
const parsed = parseToolDisplayName(name);
|
|
485
|
+
if (parsed.base === 'project_index') {
|
|
486
|
+
return blocked
|
|
487
|
+
? `${copy.toolActivity.blocked}: project index`
|
|
488
|
+
: done
|
|
489
|
+
? copy.toolActivity.doneProjectIndex
|
|
490
|
+
: copy.toolActivity.doingProjectIndex;
|
|
491
|
+
}
|
|
492
|
+
if (parsed.base === 'file_index') {
|
|
493
|
+
const safeTarget = trimText(parsed.target || '.codemini-project/file-index.json', 72);
|
|
494
|
+
return blocked
|
|
495
|
+
? `${copy.toolActivity.blocked}: ${safeTarget}`
|
|
496
|
+
: done
|
|
497
|
+
? `${copy.toolActivity.doneFileIndex}: ${safeTarget}`
|
|
498
|
+
: `${copy.toolActivity.doingFileIndex}: ${safeTarget}`;
|
|
499
|
+
}
|
|
460
500
|
if (parsed.base === 'run' || parsed.base === 'start_service') {
|
|
461
501
|
const intent = classifyCommandIntent(parsed.target);
|
|
462
502
|
const target = parsed.target || intent.kind || 'command';
|
|
@@ -765,8 +805,11 @@ function PlanStrip({ planState, copy }) {
|
|
|
765
805
|
);
|
|
766
806
|
}
|
|
767
807
|
|
|
768
|
-
function Header({ sessionId, model, shellName }) {
|
|
808
|
+
function Header({ sessionId, model, shellName, safeMode = true }) {
|
|
769
809
|
const shortSession = String(sessionId || '').slice(-12) || '-';
|
|
810
|
+
const modeValue = safeMode ? 'SAFE' : 'OPEN';
|
|
811
|
+
const modeColor = safeMode ? 'greenBright' : 'redBright';
|
|
812
|
+
const modeTextColor = safeMode ? 'black' : 'white';
|
|
770
813
|
return h(
|
|
771
814
|
Box,
|
|
772
815
|
{ width: '100%', justifyContent: 'center', marginTop: 1, marginBottom: 2 },
|
|
@@ -781,12 +824,6 @@ function Header({ sessionId, model, shellName }) {
|
|
|
781
824
|
alignItems: 'center',
|
|
782
825
|
minWidth: 88
|
|
783
826
|
},
|
|
784
|
-
h(
|
|
785
|
-
Box,
|
|
786
|
-
{ width: '100%', justifyContent: 'space-between', marginBottom: 1 },
|
|
787
|
-
h(Text, { color: 'cyan' }, 'CLI'),
|
|
788
|
-
h(Text, { color: 'greenBright' }, 'SAFE')
|
|
789
|
-
),
|
|
790
827
|
...BANNER.map((line, idx) =>
|
|
791
828
|
h(
|
|
792
829
|
Box,
|
|
@@ -801,8 +838,9 @@ function Header({ sessionId, model, shellName }) {
|
|
|
801
838
|
Box,
|
|
802
839
|
{ flexDirection: 'row', justifyContent: 'center' },
|
|
803
840
|
h(StatusPill, { label: 'MODEL', value: model, color: 'cyanBright', textColor: 'black' }),
|
|
804
|
-
h(StatusPill, { label: 'SHELL', value: shellName || 'powershell', color: '
|
|
805
|
-
h(StatusPill, { label: 'SESSION', value: shortSession, color: 'magentaBright', textColor: 'black' })
|
|
841
|
+
h(StatusPill, { label: 'SHELL', value: shellName || 'powershell', color: 'yellowBright', textColor: 'black' }),
|
|
842
|
+
h(StatusPill, { label: 'SESSION', value: shortSession, color: 'magentaBright', textColor: 'black' }),
|
|
843
|
+
h(StatusPill, { label: 'MODE', value: modeValue, color: modeColor, textColor: modeTextColor })
|
|
806
844
|
)
|
|
807
845
|
)
|
|
808
846
|
);
|
|
@@ -878,9 +916,16 @@ export function parsePlanProgressLine(text) {
|
|
|
878
916
|
};
|
|
879
917
|
}
|
|
880
918
|
|
|
881
|
-
function
|
|
919
|
+
function getTailPreviewWindow(text, maxLines = 3) {
|
|
882
920
|
const source = String(text || '');
|
|
883
|
-
if (!source.trim()) return [];
|
|
921
|
+
if (!source.trim()) return { lines: [], startLine: 1 };
|
|
922
|
+
const sliceTail = (lines) => {
|
|
923
|
+
const tail = lines.slice(-Math.max(1, maxLines));
|
|
924
|
+
return {
|
|
925
|
+
lines: tail,
|
|
926
|
+
startLine: Math.max(1, lines.length - tail.length + 1)
|
|
927
|
+
};
|
|
928
|
+
};
|
|
884
929
|
|
|
885
930
|
const lines = source.split('\n').map((line) => line.replace(/\r$/, ''));
|
|
886
931
|
let insideFence = false;
|
|
@@ -908,21 +953,21 @@ function getTailPreviewLines(text, maxLines = 3) {
|
|
|
908
953
|
if (insideFence) {
|
|
909
954
|
const codeLines = fenceLines.filter((line) => line.trim().length > 0);
|
|
910
955
|
if (codeLines.length > 0) {
|
|
911
|
-
return codeLines
|
|
956
|
+
return sliceTail(codeLines);
|
|
912
957
|
}
|
|
913
958
|
}
|
|
914
959
|
|
|
915
960
|
const closedFenceLines = latestClosedFenceLines.filter((line) => line.trim().length > 0);
|
|
916
961
|
if (closedFenceLines.length > 0) {
|
|
917
|
-
return closedFenceLines
|
|
962
|
+
return sliceTail(closedFenceLines);
|
|
918
963
|
}
|
|
919
964
|
|
|
920
965
|
const tailLines = source
|
|
921
966
|
.split('\n')
|
|
922
967
|
.map((line) => line.replace(/\r$/, ''))
|
|
923
968
|
.filter((line) => line.trim().length > 0);
|
|
924
|
-
if (tailLines.length === 0) return [];
|
|
925
|
-
return tailLines
|
|
969
|
+
if (tailLines.length === 0) return { lines: [], startLine: 1 };
|
|
970
|
+
return sliceTail(tailLines);
|
|
926
971
|
}
|
|
927
972
|
|
|
928
973
|
function collectPreviewStrings(value, out = []) {
|
|
@@ -954,7 +999,6 @@ function collectPreviewStrings(value, out = []) {
|
|
|
954
999
|
function extractPreviewTextFromRawArguments(raw) {
|
|
955
1000
|
const source = String(raw || '');
|
|
956
1001
|
if (!source.trim()) return '';
|
|
957
|
-
|
|
958
1002
|
const contentMatch = source.match(/"(content|new_content|new_text|patch|code|body|script|source|value)"\s*:\s*"([\s\S]*)$/);
|
|
959
1003
|
if (!contentMatch) return '';
|
|
960
1004
|
|
|
@@ -962,7 +1006,7 @@ function extractPreviewTextFromRawArguments(raw) {
|
|
|
962
1006
|
.replace(/\\n/g, '\n')
|
|
963
1007
|
.replace(/\\"/g, '"')
|
|
964
1008
|
.replace(/\\\\/g, '\\')
|
|
965
|
-
.replace(/"
|
|
1009
|
+
.replace(/"\s*[,}\]]*\s*$/g, '')
|
|
966
1010
|
.trim();
|
|
967
1011
|
}
|
|
968
1012
|
|
|
@@ -973,40 +1017,76 @@ function compactPreviewLine(line, maxChars = 56) {
|
|
|
973
1017
|
return `${text.slice(0, Math.max(1, maxChars - 3))}...`;
|
|
974
1018
|
}
|
|
975
1019
|
|
|
1020
|
+
function extractPreviewLinesFromTool(tool, maxLines = 3) {
|
|
1021
|
+
const previewSource =
|
|
1022
|
+
typeof tool?.arguments === 'string'
|
|
1023
|
+
? (() => {
|
|
1024
|
+
const parsedArguments = safeJsonParse(tool.arguments);
|
|
1025
|
+
if (parsedArguments) {
|
|
1026
|
+
const parsedPreview = collectPreviewStrings(parsedArguments);
|
|
1027
|
+
if (parsedPreview.length > 0) return parsedPreview;
|
|
1028
|
+
}
|
|
1029
|
+
const rawArgumentPreview = extractPreviewTextFromRawArguments(tool.arguments);
|
|
1030
|
+
return rawArgumentPreview ? [rawArgumentPreview] : [];
|
|
1031
|
+
})()
|
|
1032
|
+
: collectPreviewStrings(tool?.arguments || tool?.content || tool?.summary || []);
|
|
1033
|
+
|
|
1034
|
+
if (previewSource.length === 0) return { lines: [], startLine: 1 };
|
|
1035
|
+
const combined = previewSource.join('\n');
|
|
1036
|
+
const previewWindow = getTailPreviewWindow(combined, maxLines);
|
|
1037
|
+
return {
|
|
1038
|
+
lines: previewWindow.lines.map((line) => compactPreviewLine(line)),
|
|
1039
|
+
startLine: previewWindow.startLine
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
|
|
976
1043
|
function getLatestToolPreviewLines(msg, maxLines = 3) {
|
|
977
|
-
const toolCalls = [
|
|
978
|
-
...(Array.isArray(msg?.pendingToolCalls) ? msg.pendingToolCalls : []),
|
|
979
|
-
...(Array.isArray(msg?.toolCalls) ? msg.toolCalls : [])
|
|
980
|
-
];
|
|
981
1044
|
const codeTools = new Set(['edit', 'write', 'patch', 'generate_diff']);
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1045
|
+
const extractFromCalls = (calls) => {
|
|
1046
|
+
for (let index = calls.length - 1; index >= 0; index -= 1) {
|
|
1047
|
+
const tool = calls[index];
|
|
1048
|
+
const parsed = parseToolDisplayName(tool?.name);
|
|
1049
|
+
if (!codeTools.has(parsed.base)) continue;
|
|
1050
|
+
const previewWindow = extractPreviewLinesFromTool(tool, maxLines);
|
|
1051
|
+
if (previewWindow.lines.length > 0) return previewWindow;
|
|
1052
|
+
}
|
|
1053
|
+
return { lines: [], startLine: 1 };
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
const pendingCodeCalls = (Array.isArray(msg?.pendingToolCalls) ? msg.pendingToolCalls : []).filter((tool) =>
|
|
1057
|
+
codeTools.has(parseToolDisplayName(tool?.name).base)
|
|
1058
|
+
);
|
|
1059
|
+
if (pendingCodeCalls.length > 0) {
|
|
1060
|
+
const latestPendingPreview = extractPreviewLinesFromTool(pendingCodeCalls.at(-1), maxLines);
|
|
1061
|
+
if (latestPendingPreview.lines.length > 0) return latestPendingPreview;
|
|
1062
|
+
return { lines: [], startLine: 1 };
|
|
995
1063
|
}
|
|
996
|
-
|
|
1064
|
+
|
|
1065
|
+
const toolCalls = (Array.isArray(msg?.toolCalls) ? msg.toolCalls : []).filter(
|
|
1066
|
+
(tool) => tool?.status === 'running' && codeTools.has(parseToolDisplayName(tool?.name).base)
|
|
1067
|
+
);
|
|
1068
|
+
if (toolCalls.length > 0) {
|
|
1069
|
+
return extractFromCalls(toolCalls);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
return { lines: [], startLine: 1 };
|
|
997
1073
|
}
|
|
998
1074
|
|
|
999
1075
|
export function getGeneratingCodePlaceholderRows(msg, copy, contentWidth = 72) {
|
|
1000
1076
|
const liveStatus = String(msg?.liveStatus || '').trim();
|
|
1001
1077
|
if (!msg?.loading || (msg?.phase !== 'generating' && msg?.phase !== 'tooling')) return [];
|
|
1002
|
-
if (liveStatus !== String(copy?.runtime?.generatingCode || '').trim()) return [];
|
|
1003
1078
|
|
|
1004
|
-
const
|
|
1005
|
-
if (
|
|
1079
|
+
const previewWindow = getLatestToolPreviewLines(msg, 3);
|
|
1080
|
+
if (previewWindow.lines.length === 0) return [];
|
|
1081
|
+
const hasRunningCodeTool = (Array.isArray(msg?.toolCalls) ? msg.toolCalls : []).some(
|
|
1082
|
+
(tool) => tool?.status === 'running' && new Set(['edit', 'write', 'patch', 'generate_diff']).has(parseToolDisplayName(tool?.name).base)
|
|
1083
|
+
);
|
|
1084
|
+
const isCodeGenerationStatus = liveStatus === String(copy?.runtime?.generatingCode || '').trim();
|
|
1085
|
+
if (!isCodeGenerationStatus && !(msg?.phase === 'tooling' && hasRunningCodeTool)) return [];
|
|
1006
1086
|
|
|
1007
|
-
return
|
|
1087
|
+
return previewWindow.lines.map((line, idx) => ({
|
|
1008
1088
|
kind: 'code-placeholder',
|
|
1009
|
-
lineNo:
|
|
1089
|
+
lineNo: previewWindow.startLine + idx,
|
|
1010
1090
|
text: line,
|
|
1011
1091
|
color: 'gray'
|
|
1012
1092
|
}));
|
|
@@ -1321,7 +1401,7 @@ export function insertRowsAfterLastCodeRow(rows, extraRows) {
|
|
|
1321
1401
|
|
|
1322
1402
|
let insertIndex = -1;
|
|
1323
1403
|
for (let index = source.length - 1; index >= 0; index -= 1) {
|
|
1324
|
-
if (source[index]?.kind === 'code') {
|
|
1404
|
+
if (source[index]?.kind === 'code' || source[index]?.kind === 'code-placeholder') {
|
|
1325
1405
|
insertIndex = index + 1;
|
|
1326
1406
|
break;
|
|
1327
1407
|
}
|
|
@@ -1498,10 +1578,18 @@ function buildMessageRows(msg, showToolDetails, contentWidth = 72, copy) {
|
|
|
1498
1578
|
};
|
|
1499
1579
|
|
|
1500
1580
|
if (Array.isArray(msg?.segments) && msg.segments.length > 0) {
|
|
1501
|
-
const totalTools = msg.segments.filter(
|
|
1581
|
+
const totalTools = msg.segments.filter(
|
|
1582
|
+
(segment) =>
|
|
1583
|
+
segment.type === 'tool' ||
|
|
1584
|
+
segment.type === 'skill' ||
|
|
1585
|
+
(segment.type === 'system_tool' && (showToolDetails || !isIndexSystemToolName(segment.name)))
|
|
1586
|
+
).length;
|
|
1502
1587
|
let toolIndex = 0;
|
|
1503
1588
|
for (const segment of msg.segments) {
|
|
1504
|
-
if (segment.type === 'tool' || segment.type === 'skill') {
|
|
1589
|
+
if (segment.type === 'tool' || segment.type === 'skill' || segment.type === 'system_tool') {
|
|
1590
|
+
if (segment.type === 'system_tool' && !showToolDetails && isIndexSystemToolName(segment.name)) {
|
|
1591
|
+
continue;
|
|
1592
|
+
}
|
|
1505
1593
|
pushActivityRows(segment, toolIndex, totalTools);
|
|
1506
1594
|
toolIndex += 1;
|
|
1507
1595
|
} else {
|
|
@@ -1548,6 +1636,10 @@ function renderMessageRow(msg, row, idx, loaderTick) {
|
|
|
1548
1636
|
? row.status === 'error'
|
|
1549
1637
|
? 'redBright'
|
|
1550
1638
|
: 'cyanBright'
|
|
1639
|
+
: activity.type === 'system_tool'
|
|
1640
|
+
? row.status === 'error' || row.status === 'blocked'
|
|
1641
|
+
? 'redBright'
|
|
1642
|
+
: 'blueBright'
|
|
1551
1643
|
: row.status === 'error' || row.status === 'blocked'
|
|
1552
1644
|
? 'redBright'
|
|
1553
1645
|
: 'cyanBright';
|
|
@@ -1783,7 +1875,14 @@ function MessageBubble({ msg, loaderTick, showToolDetails, rowWindow = null, con
|
|
|
1783
1875
|
? h(Text, { color: 'blueBright' }, autoSkillBadge)
|
|
1784
1876
|
: h(Text, { color: theme.chrome }, ' ')
|
|
1785
1877
|
),
|
|
1786
|
-
...rendered
|
|
1878
|
+
...rendered,
|
|
1879
|
+
shouldShowCompletionFooter(msg)
|
|
1880
|
+
? h(
|
|
1881
|
+
Box,
|
|
1882
|
+
{ marginTop: 1, marginLeft: 1, key: `row-completion-${msg.id}` },
|
|
1883
|
+
h(Text, { color: 'gray', dimColor: true }, copy.generic.taskCompleted)
|
|
1884
|
+
)
|
|
1885
|
+
: null
|
|
1787
1886
|
)
|
|
1788
1887
|
);
|
|
1789
1888
|
}
|
|
@@ -2017,7 +2116,7 @@ function makeIdleStatus(copy, snapshot, variant = 'ready') {
|
|
|
2017
2116
|
);
|
|
2018
2117
|
}
|
|
2019
2118
|
|
|
2020
|
-
export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName = 'powershell', version = '' }) {
|
|
2119
|
+
export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName = 'powershell', version = '', safeMode = true }) {
|
|
2021
2120
|
const copy = getCopy(language);
|
|
2022
2121
|
const stdoutCols = Number(process.stdout?.columns || 120);
|
|
2023
2122
|
const [inputValue, setInputValue] = useState('');
|
|
@@ -2060,6 +2159,23 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
2060
2159
|
const messagesRef = useRef([]);
|
|
2061
2160
|
const pendingQueueRef = useRef([]);
|
|
2062
2161
|
const deltaBufferRef = useRef('');
|
|
2162
|
+
|
|
2163
|
+
useEffect(() => {
|
|
2164
|
+
const rawStartupActivities = runtime.consumeStartupEvents?.();
|
|
2165
|
+
const startupActivities = Array.isArray(rawStartupActivities) ? rawStartupActivities : [];
|
|
2166
|
+
if (startupActivities.length === 0) return;
|
|
2167
|
+
setMessages((prev) => [
|
|
2168
|
+
...prev,
|
|
2169
|
+
{
|
|
2170
|
+
id: nextId(),
|
|
2171
|
+
label: 'system',
|
|
2172
|
+
text: '',
|
|
2173
|
+
color: 'yellowBright',
|
|
2174
|
+
toolCalls: startupActivities,
|
|
2175
|
+
segments: startupActivities
|
|
2176
|
+
}
|
|
2177
|
+
]);
|
|
2178
|
+
}, [runtime]);
|
|
2063
2179
|
const deltaFlushTimerRef = useRef(null);
|
|
2064
2180
|
const escSeqRef = useRef('');
|
|
2065
2181
|
const planTextBufferRef = useRef('');
|
|
@@ -2191,6 +2307,7 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
2191
2307
|
prev.map((m) => {
|
|
2192
2308
|
if (m.id !== targetId) return m;
|
|
2193
2309
|
const toolCalls = Array.isArray(m.toolCalls) ? [...m.toolCalls] : [];
|
|
2310
|
+
const pendingToolCalls = Array.isArray(m.pendingToolCalls) ? [...m.pendingToolCalls] : [];
|
|
2194
2311
|
const activityType = toolEvent.type || 'tool';
|
|
2195
2312
|
const idx = findActivityUpdateIndex(toolCalls, toolEvent);
|
|
2196
2313
|
const startedAt = toolEvent.status === 'running' ? Date.now() : undefined;
|
|
@@ -2243,7 +2360,16 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
2243
2360
|
: {})
|
|
2244
2361
|
};
|
|
2245
2362
|
}
|
|
2246
|
-
|
|
2363
|
+
const shouldClearPending =
|
|
2364
|
+
activityType === 'tool' && ['running', 'done', 'blocked', 'error'].includes(toolEvent.status);
|
|
2365
|
+
const nextPendingToolCalls = shouldClearPending
|
|
2366
|
+
? pendingToolCalls.filter((entry) => {
|
|
2367
|
+
if (!entry) return false;
|
|
2368
|
+
if (toolEvent.id && entry.id) return entry.id !== toolEvent.id;
|
|
2369
|
+
return parseToolDisplayName(entry.name).base !== parseToolDisplayName(toolEvent.name).base;
|
|
2370
|
+
})
|
|
2371
|
+
: pendingToolCalls;
|
|
2372
|
+
return { ...m, toolCalls, segments, pendingToolCalls: nextPendingToolCalls };
|
|
2247
2373
|
})
|
|
2248
2374
|
);
|
|
2249
2375
|
};
|
|
@@ -2582,6 +2708,54 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
2582
2708
|
arguments: event.arguments
|
|
2583
2709
|
});
|
|
2584
2710
|
}
|
|
2711
|
+
if (event?.type === 'system_tool:start') {
|
|
2712
|
+
ensureActiveAssistant();
|
|
2713
|
+
const detail = describeToolActivity(event.name, copy);
|
|
2714
|
+
setRuntimeStatus(makeStatus(copy.runtime.toolRunning, detail, 'blueBright'));
|
|
2715
|
+
setInputStage('tooling');
|
|
2716
|
+
updateActivityStatusOnActiveAssistant({
|
|
2717
|
+
type: 'system_tool',
|
|
2718
|
+
id: event.id,
|
|
2719
|
+
name: event.name,
|
|
2720
|
+
status: 'running',
|
|
2721
|
+
summary: event.summary
|
|
2722
|
+
});
|
|
2723
|
+
setActiveAssistantMeta({ loading: true, phase: 'tooling', liveStatus: detail });
|
|
2724
|
+
}
|
|
2725
|
+
if (event?.type === 'system_tool:end') {
|
|
2726
|
+
const detail = describeToolActivity(event.name, copy, { done: true });
|
|
2727
|
+
setRuntimeStatus(makeStatus(copy.runtime.toolCompleted, copy.toolActivity.waitingModelContinue(detail), 'blueBright'));
|
|
2728
|
+
setInputStage('thinking');
|
|
2729
|
+
updateActivityStatusOnActiveAssistant({
|
|
2730
|
+
type: 'system_tool',
|
|
2731
|
+
id: event.id,
|
|
2732
|
+
name: event.name,
|
|
2733
|
+
status: 'done',
|
|
2734
|
+
summary: event.summary
|
|
2735
|
+
});
|
|
2736
|
+
setActiveAssistantMeta({
|
|
2737
|
+
loading: true,
|
|
2738
|
+
phase: 'thinking',
|
|
2739
|
+
liveStatus: copy.toolActivity.waitingModelContinue(detail)
|
|
2740
|
+
});
|
|
2741
|
+
}
|
|
2742
|
+
if (event?.type === 'system_tool:error') {
|
|
2743
|
+
const detail = copy.toolActivity.toolFailed(event.name);
|
|
2744
|
+
setRuntimeStatus(makeStatus(copy.runtime.toolFailed, event.summary || detail, 'redBright'));
|
|
2745
|
+
setInputStage('thinking');
|
|
2746
|
+
updateActivityStatusOnActiveAssistant({
|
|
2747
|
+
type: 'system_tool',
|
|
2748
|
+
id: event.id,
|
|
2749
|
+
name: event.name,
|
|
2750
|
+
status: 'error',
|
|
2751
|
+
summary: event.summary
|
|
2752
|
+
});
|
|
2753
|
+
setActiveAssistantMeta({
|
|
2754
|
+
loading: true,
|
|
2755
|
+
phase: 'thinking',
|
|
2756
|
+
liveStatus: copy.toolActivity.waitingModelAdjust(detail)
|
|
2757
|
+
});
|
|
2758
|
+
}
|
|
2585
2759
|
if (event?.type === 'skill:start') {
|
|
2586
2760
|
ensureActiveAssistant();
|
|
2587
2761
|
const detail = describeSkillActivity(event.name, copy);
|
|
@@ -3087,7 +3261,7 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
3087
3261
|
return h(
|
|
3088
3262
|
Box,
|
|
3089
3263
|
{ flexDirection: 'column' },
|
|
3090
|
-
h(Header, { sessionId: displaySessionId, model: displayModel, shellName }),
|
|
3264
|
+
h(Header, { sessionId: displaySessionId, model: displayModel, shellName, safeMode }),
|
|
3091
3265
|
h(MessageList, {
|
|
3092
3266
|
messages: visibleMessages,
|
|
3093
3267
|
loaderTick,
|