codemini-cli 0.2.5 → 0.2.6
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/package.json +1 -1
- package/src/cli.js +1 -1
- package/src/core/provider/openai-compatible.js +34 -1
- package/src/core/shell-profile.js +4 -0
- package/src/tui/chat-app.js +44 -3
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { handleConfig } from './commands/config.js';
|
|
|
4
4
|
import { handleDoctor } from './commands/doctor.js';
|
|
5
5
|
import { handleSkill } from './commands/skill.js';
|
|
6
6
|
|
|
7
|
-
const VERSION = '0.2.
|
|
7
|
+
const VERSION = '0.2.6';
|
|
8
8
|
|
|
9
9
|
function printHelp() {
|
|
10
10
|
console.log(`codemini ${VERSION}
|
|
@@ -36,6 +36,38 @@ function isMiniMaxModel(model) {
|
|
|
36
36
|
return String(model || '').toLowerCase().includes('minimax');
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
function normalizeToolCallArguments(argumentsText) {
|
|
40
|
+
const raw = typeof argumentsText === 'string' ? argumentsText : JSON.stringify(argumentsText ?? {});
|
|
41
|
+
try {
|
|
42
|
+
const parsed = JSON.parse(raw);
|
|
43
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
44
|
+
return JSON.stringify(parsed);
|
|
45
|
+
}
|
|
46
|
+
} catch {}
|
|
47
|
+
return '{}';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function sanitizeGatewayMessages(messages) {
|
|
51
|
+
const source = Array.isArray(messages) ? messages : [];
|
|
52
|
+
return source
|
|
53
|
+
.filter((message) => message && typeof message === 'object')
|
|
54
|
+
.map((message) => {
|
|
55
|
+
if (!Array.isArray(message.tool_calls) || message.tool_calls.length === 0) {
|
|
56
|
+
return message;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
...message,
|
|
60
|
+
tool_calls: message.tool_calls.map((toolCall) => ({
|
|
61
|
+
...toolCall,
|
|
62
|
+
function: {
|
|
63
|
+
...toolCall?.function,
|
|
64
|
+
arguments: normalizeToolCallArguments(toolCall?.function?.arguments)
|
|
65
|
+
}
|
|
66
|
+
}))
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
39
71
|
function sanitizeMiniMaxMessages(messages) {
|
|
40
72
|
const source = Array.isArray(messages) ? messages : [];
|
|
41
73
|
const out = [];
|
|
@@ -64,10 +96,11 @@ function sanitizeMiniMaxMessages(messages) {
|
|
|
64
96
|
}
|
|
65
97
|
|
|
66
98
|
function buildPayload({ model, temperature, messages, tools, stream = false }) {
|
|
99
|
+
const sanitizedMessages = sanitizeGatewayMessages(messages);
|
|
67
100
|
const payload = {
|
|
68
101
|
model,
|
|
69
102
|
temperature,
|
|
70
|
-
messages: isMiniMaxModel(model) ? sanitizeMiniMaxMessages(
|
|
103
|
+
messages: isMiniMaxModel(model) ? sanitizeMiniMaxMessages(sanitizedMessages) : sanitizedMessages
|
|
71
104
|
};
|
|
72
105
|
if (stream) {
|
|
73
106
|
payload.stream = true;
|
|
@@ -142,6 +142,10 @@ Some tools are loaded on demand. If a needed tool is not listed, call tool_searc
|
|
|
142
142
|
|
|
143
143
|
# Doing tasks
|
|
144
144
|
|
|
145
|
+
- You are a terminal-first CLI coding agent, not a generic chat assistant
|
|
146
|
+
- The user shares your workspace with you; prefer inspecting the project yourself before asking them to paste files that should be discoverable
|
|
147
|
+
- Before substantial tool work, send a short progress update to the user about what you are about to inspect or do
|
|
148
|
+
- Do not jump straight into tools without a brief user-facing note when the task is actionable
|
|
145
149
|
- Search or read before editing unless the exact target is already known
|
|
146
150
|
- If a command or tool is blocked or fails, inspect the error and retry with allowed commands or tools
|
|
147
151
|
- For AST-scoped edits, if edit rejects due to missing or stale ast_target, fix arguments and retry
|
package/src/tui/chat-app.js
CHANGED
|
@@ -375,6 +375,39 @@ function isCodeGenerationActivityName(name) {
|
|
|
375
375
|
return String(name || '').trim() === 'Code generation';
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
+
export function buildPreToolNotice(name, copy) {
|
|
379
|
+
const parsed = parseToolDisplayName(name);
|
|
380
|
+
const base = parsed.base;
|
|
381
|
+
const target = parsed.target ? trimText(parsed.target, 48) : '';
|
|
382
|
+
const isEnglish = String(copy?.roleLabels?.coder || '').trim() === 'CODER' && String(copy?.roleLabels?.you || '').trim() === 'YOU';
|
|
383
|
+
|
|
384
|
+
if (isEnglish) {
|
|
385
|
+
if (base === 'read') return target ? `I'll inspect ${target} first.` : `I'll inspect the relevant file first.`;
|
|
386
|
+
if (base === 'list' || base === 'glob') return target ? `I'll inspect the ${target} directory first.` : `I'll inspect the relevant directory first.`;
|
|
387
|
+
if (base === 'grep') return `I'll search the relevant code first.`;
|
|
388
|
+
if (base === 'edit' || base === 'write' || base === 'patch' || base === 'generate_diff') {
|
|
389
|
+
return `I'll inspect the current code first, then make the change.`;
|
|
390
|
+
}
|
|
391
|
+
if (base === 'run') return `I'll verify the current project state first.`;
|
|
392
|
+
return `I'll check the relevant project context first.`;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (base === 'read') return target ? `我先查看 ${target} 的内容。` : '我先查看相关文件内容。';
|
|
396
|
+
if (base === 'list' || base === 'glob') return target ? `我先查看 ${target} 目录里的内容。` : '我先查看相关目录内容。';
|
|
397
|
+
if (base === 'grep') return '我先搜索相关代码位置。';
|
|
398
|
+
if (base === 'edit' || base === 'write' || base === 'patch' || base === 'generate_diff') return '我先确认当前代码上下文,再动手修改。';
|
|
399
|
+
if (base === 'run') return '我先检查当前项目状态。';
|
|
400
|
+
return '我先查看相关上下文。';
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export function shouldInjectPreToolNotice(msg) {
|
|
404
|
+
if (!msg) return false;
|
|
405
|
+
const text = String(msg.text || '').trim();
|
|
406
|
+
const segments = Array.isArray(msg.segments) ? msg.segments : [];
|
|
407
|
+
const hasTextSegment = segments.some((segment) => segment?.type === 'text' && String(segment.text || '').trim());
|
|
408
|
+
return !text && !hasTextSegment;
|
|
409
|
+
}
|
|
410
|
+
|
|
378
411
|
function formatDurationMs(ms) {
|
|
379
412
|
const safeMs = Math.max(0, Number(ms) || 0);
|
|
380
413
|
return `${(safeMs / 1000).toFixed(1)}s`;
|
|
@@ -2280,11 +2313,12 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
2280
2313
|
} else {
|
|
2281
2314
|
segments.push({ type: 'text', text: delta });
|
|
2282
2315
|
}
|
|
2283
|
-
const nextText = `${m.text}${delta}`;
|
|
2316
|
+
const nextText = m.syntheticPrelude ? delta : `${m.text}${delta}`;
|
|
2284
2317
|
return {
|
|
2285
2318
|
...m,
|
|
2286
2319
|
text: nextText,
|
|
2287
|
-
segments
|
|
2320
|
+
segments,
|
|
2321
|
+
syntheticPrelude: false
|
|
2288
2322
|
};
|
|
2289
2323
|
})
|
|
2290
2324
|
);
|
|
@@ -2634,8 +2668,15 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
2634
2668
|
prev.map((m) => {
|
|
2635
2669
|
if (m.id !== targetId) return m;
|
|
2636
2670
|
const nextMessage = isCodeActivityName(event.name) ? finishCodeGeneration(m, finishedAt) : m;
|
|
2671
|
+
const withPrelude = shouldInjectPreToolNotice(nextMessage)
|
|
2672
|
+
? {
|
|
2673
|
+
...nextMessage,
|
|
2674
|
+
text: buildPreToolNotice(event.name, copy),
|
|
2675
|
+
syntheticPrelude: true
|
|
2676
|
+
}
|
|
2677
|
+
: nextMessage;
|
|
2637
2678
|
return {
|
|
2638
|
-
...
|
|
2679
|
+
...withPrelude,
|
|
2639
2680
|
loading: true,
|
|
2640
2681
|
phase: 'tooling',
|
|
2641
2682
|
liveStatus: detail
|