codemini-cli 0.3.9 → 0.4.0
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 -0
- package/deployment.md +6 -6
- package/package.json +3 -1
- package/src/core/agent-loop.js +87 -11
- package/src/core/chat-runtime.js +50 -5
- package/src/core/command-evaluator.js +66 -0
- package/src/core/command-policy.js +16 -0
- package/src/core/command-risk.js +148 -0
- package/src/core/constants.js +0 -1
- package/src/core/default-system-prompt.js +10 -3
- package/src/core/dream-consolidate.js +54 -14
- package/src/core/dream-evaluator.js +99 -0
- package/src/core/fff-adapter.js +1 -1
- package/src/core/memory-store.js +3 -2
- package/src/core/paths.js +1 -1
- package/src/core/project-index.js +2 -2
- package/src/core/shell-profile.js +5 -1
- package/src/core/tool-output.js +184 -0
- package/src/core/tools.js +100 -155
- package/src/tui/chat-app.js +339 -44
- package/src/tui/tool-activity/presenters/system.js +1 -1
package/src/core/tools.js
CHANGED
|
@@ -23,6 +23,12 @@ import { runDreamConsolidation } from './dream-consolidate.js';
|
|
|
23
23
|
import { normalizePlanState } from './plan-state.js';
|
|
24
24
|
import { normalizeTodos } from './todo-state.js';
|
|
25
25
|
import { createFffAdapter } from './fff-adapter.js';
|
|
26
|
+
import {
|
|
27
|
+
getToolOutputSanitizeOptions,
|
|
28
|
+
sanitizePreviewLines,
|
|
29
|
+
sanitizeTextForModel,
|
|
30
|
+
summarizeRunOutput
|
|
31
|
+
} from './tool-output.js';
|
|
26
32
|
const BACKGROUND_TASK_RECENT_OUTPUT_LIMIT = 80;
|
|
27
33
|
const BACKGROUND_TASK_POLL_MS = 150;
|
|
28
34
|
const MAX_AST_ENCLOSING_BYTES = 300_000;
|
|
@@ -333,11 +339,10 @@ async function webFetchPage(args = {}) {
|
|
|
333
339
|
const html = await page.content();
|
|
334
340
|
const $ = cheerio.load(html);
|
|
335
341
|
const bodyText = $('body').text() || $.root().text();
|
|
336
|
-
const text =
|
|
342
|
+
const text = String(bodyText || '').replace(/[^\S\n]+/g, ' ').replace(/\n{3,}/g, '\n\n').trim();
|
|
337
343
|
const title = trimPreview($('title').first().text() || (await page.title()), 240);
|
|
338
344
|
const description = extractHtmlMeta($, 'description') || extractHtmlMeta($, 'og:description');
|
|
339
345
|
const links = collectPageLinks($, finalUrl, maxLinks);
|
|
340
|
-
const htmlExcerpt = html.length > 4000 ? `${html.slice(0, 4000)}...` : html;
|
|
341
346
|
|
|
342
347
|
return {
|
|
343
348
|
url,
|
|
@@ -345,7 +350,6 @@ async function webFetchPage(args = {}) {
|
|
|
345
350
|
title,
|
|
346
351
|
description,
|
|
347
352
|
text,
|
|
348
|
-
html_excerpt: htmlExcerpt,
|
|
349
353
|
links,
|
|
350
354
|
metadata: {
|
|
351
355
|
status: response?.status?.() ?? null,
|
|
@@ -747,40 +751,6 @@ function findEnclosingSymbolLine(lines, anchorLine) {
|
|
|
747
751
|
return 0;
|
|
748
752
|
}
|
|
749
753
|
|
|
750
|
-
function buildUnifiedDiff(oldContent, newContent, filePath = 'file') {
|
|
751
|
-
const oldLines = splitLines(oldContent);
|
|
752
|
-
const newLines = splitLines(newContent);
|
|
753
|
-
let prefix = 0;
|
|
754
|
-
while (prefix < oldLines.length && prefix < newLines.length && oldLines[prefix] === newLines[prefix]) {
|
|
755
|
-
prefix += 1;
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
let suffix = 0;
|
|
759
|
-
while (
|
|
760
|
-
suffix < oldLines.length - prefix &&
|
|
761
|
-
suffix < newLines.length - prefix &&
|
|
762
|
-
oldLines[oldLines.length - 1 - suffix] === newLines[newLines.length - 1 - suffix]
|
|
763
|
-
) {
|
|
764
|
-
suffix += 1;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
const oldChanged = oldLines.slice(prefix, oldLines.length - suffix);
|
|
768
|
-
const newChanged = newLines.slice(prefix, newLines.length - suffix);
|
|
769
|
-
const oldStart = prefix + 1;
|
|
770
|
-
const newStart = prefix + 1;
|
|
771
|
-
const oldCount = Math.max(1, oldChanged.length);
|
|
772
|
-
const newCount = Math.max(1, newChanged.length);
|
|
773
|
-
|
|
774
|
-
const body = [
|
|
775
|
-
`--- ${filePath}`,
|
|
776
|
-
`+++ ${filePath}`,
|
|
777
|
-
`@@ -${oldStart},${oldCount} +${newStart},${newCount} @@`,
|
|
778
|
-
...oldChanged.map((line) => `-${line}`),
|
|
779
|
-
...newChanged.map((line) => `+${line}`)
|
|
780
|
-
];
|
|
781
|
-
return body.join('\n');
|
|
782
|
-
}
|
|
783
|
-
|
|
784
754
|
async function getFileState(root, relativePath) {
|
|
785
755
|
const target = await resolveInWorkspace(root, relativePath);
|
|
786
756
|
const stat = await fs.stat(target);
|
|
@@ -924,12 +894,15 @@ async function writeFile(root, args) {
|
|
|
924
894
|
}
|
|
925
895
|
const previewStart = Math.max(0, (changeLine || 1) - 1);
|
|
926
896
|
const previewLines = afterLines.slice(previewStart, previewStart + 6);
|
|
897
|
+
const changed = countChangedLines(before, after);
|
|
927
898
|
return {
|
|
928
899
|
ok: true,
|
|
929
900
|
path: rawPath,
|
|
930
901
|
action: normalizedArgs?.append ? 'append' : existed ? 'overwrite' : 'create',
|
|
931
902
|
changed_line: changeLine || Math.max(1, afterLines.length),
|
|
932
|
-
diff_preview: previewLines.map((line, idx) => `${previewStart + idx + 1}| ${line}`).join('\n')
|
|
903
|
+
diff_preview: previewLines.map((line, idx) => `${previewStart + idx + 1}| ${line}`).join('\n'),
|
|
904
|
+
lines_added: changed.added,
|
|
905
|
+
lines_removed: changed.removed
|
|
933
906
|
};
|
|
934
907
|
}
|
|
935
908
|
|
|
@@ -1045,10 +1018,9 @@ function shellCommandForBackgroundTask(command, shellSpec) {
|
|
|
1045
1018
|
}
|
|
1046
1019
|
|
|
1047
1020
|
function appendRecentOutput(task, chunk) {
|
|
1048
|
-
const lines =
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
.filter(Boolean);
|
|
1021
|
+
const lines = sanitizePreviewLines(chunk, { maxLineLength: 220 }).map((line) =>
|
|
1022
|
+
trimLinePreview(line, 220)
|
|
1023
|
+
);
|
|
1052
1024
|
if (lines.length === 0) return;
|
|
1053
1025
|
for (const line of lines) {
|
|
1054
1026
|
backgroundTaskLogCursorCounter += 1;
|
|
@@ -1499,18 +1471,47 @@ async function validateEdit(root, args) {
|
|
|
1499
1471
|
throw new Error(`validate_edit does not support kind: ${kind}`);
|
|
1500
1472
|
}
|
|
1501
1473
|
|
|
1474
|
+
function countChangedLines(beforeContent, afterContent) {
|
|
1475
|
+
const before = splitLines(beforeContent);
|
|
1476
|
+
const after = splitLines(afterContent);
|
|
1477
|
+
const m = before.length;
|
|
1478
|
+
const n = after.length;
|
|
1479
|
+
// LCS via rolling DP — O(m*n) time, O(min(m,n)) space
|
|
1480
|
+
const short = m <= n ? before : after;
|
|
1481
|
+
const long = m <= n ? after : before;
|
|
1482
|
+
const shortLen = short.length;
|
|
1483
|
+
const longLen = long.length;
|
|
1484
|
+
let prev = new Array(longLen + 1).fill(0);
|
|
1485
|
+
let curr = new Array(longLen + 1).fill(0);
|
|
1486
|
+
for (let i = 1; i <= shortLen; i++) {
|
|
1487
|
+
for (let j = 1; j <= longLen; j++) {
|
|
1488
|
+
if (short[i - 1] === long[j - 1]) {
|
|
1489
|
+
curr[j] = prev[j - 1] + 1;
|
|
1490
|
+
} else {
|
|
1491
|
+
curr[j] = Math.max(prev[j], curr[j - 1]);
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
[prev, curr] = [curr, prev];
|
|
1495
|
+
curr.fill(0);
|
|
1496
|
+
}
|
|
1497
|
+
const lcsLen = prev[longLen];
|
|
1498
|
+
return { added: n - lcsLen, removed: m - lcsLen };
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1502
1501
|
function editResult(pathText, action, beforeContent, afterContent, changedLine = 1) {
|
|
1503
1502
|
const afterLines = splitLines(afterContent);
|
|
1504
1503
|
const previewStart = Math.max(0, changedLine - 1);
|
|
1505
1504
|
const diffPreview = afterLines.slice(previewStart, previewStart + 6).map((line, idx) => `${previewStart + idx + 1}| ${line}`).join('\n');
|
|
1505
|
+
const changed = countChangedLines(beforeContent, afterContent);
|
|
1506
1506
|
return {
|
|
1507
1507
|
ok: true,
|
|
1508
1508
|
path: pathText,
|
|
1509
1509
|
action,
|
|
1510
1510
|
changed_line: changedLine,
|
|
1511
1511
|
diff_preview: diffPreview,
|
|
1512
|
-
|
|
1513
|
-
|
|
1512
|
+
new_hash: sha256(afterContent),
|
|
1513
|
+
lines_added: changed.added,
|
|
1514
|
+
lines_removed: changed.removed
|
|
1514
1515
|
};
|
|
1515
1516
|
}
|
|
1516
1517
|
|
|
@@ -1767,7 +1768,7 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1767
1768
|
};
|
|
1768
1769
|
const ensureProjectIndex = async () => {
|
|
1769
1770
|
const eventId = `project-index:${Date.now()}`;
|
|
1770
|
-
const name = 'project_index(.codemini
|
|
1771
|
+
const name = 'project_index(.codemini/project-map.json,.codemini/file-index.json)';
|
|
1771
1772
|
try {
|
|
1772
1773
|
const result = await initializeProjectIndex(workspaceRoot);
|
|
1773
1774
|
if (result?.skipped || !result?.summary) {
|
|
@@ -1799,7 +1800,7 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1799
1800
|
type: 'system_tool:end',
|
|
1800
1801
|
id: eventId,
|
|
1801
1802
|
name,
|
|
1802
|
-
summary: result?.summary || `updated .codemini
|
|
1803
|
+
summary: result?.summary || `updated .codemini for ${relativePath}`
|
|
1803
1804
|
});
|
|
1804
1805
|
return result;
|
|
1805
1806
|
} catch (error) {
|
|
@@ -2210,52 +2211,23 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2210
2211
|
}
|
|
2211
2212
|
}
|
|
2212
2213
|
},
|
|
2213
|
-
|
|
2214
|
+
save_memory: {
|
|
2214
2215
|
type: 'function',
|
|
2215
2216
|
function: {
|
|
2216
|
-
name: '
|
|
2217
|
-
description:
|
|
2218
|
-
|
|
2219
|
-
type: 'object',
|
|
2220
|
-
properties: {
|
|
2221
|
-
content: { type: 'string', description: 'Stable preference or instruction to remember' },
|
|
2222
|
-
kind: { type: 'string', description: 'preference, workflow, constraint, or warning' },
|
|
2223
|
-
summary: { type: 'string', description: 'Short summary for the memory index' },
|
|
2224
|
-
replace_similar: { type: 'boolean', description: 'Replace an existing similar memory when true' }
|
|
2225
|
-
},
|
|
2226
|
-
required: ['content']
|
|
2227
|
-
}
|
|
2228
|
-
}
|
|
2229
|
-
},
|
|
2230
|
-
remember_global: {
|
|
2231
|
-
type: 'function',
|
|
2232
|
-
function: {
|
|
2233
|
-
name: 'remember_global',
|
|
2234
|
-
description: 'Store a durable cross-project workflow, environment fact, or generally reusable lesson that can help across many repositories. Use this for stable habits like preferred search tools or repeatable debugging workflow. Never store secrets.',
|
|
2235
|
-
parameters: {
|
|
2236
|
-
type: 'object',
|
|
2237
|
-
properties: {
|
|
2238
|
-
content: { type: 'string' },
|
|
2239
|
-
kind: { type: 'string' },
|
|
2240
|
-
summary: { type: 'string' },
|
|
2241
|
-
replace_similar: { type: 'boolean' }
|
|
2242
|
-
},
|
|
2243
|
-
required: ['content']
|
|
2244
|
-
}
|
|
2245
|
-
}
|
|
2246
|
-
},
|
|
2247
|
-
remember_project: {
|
|
2248
|
-
type: 'function',
|
|
2249
|
-
function: {
|
|
2250
|
-
name: 'remember_project',
|
|
2251
|
-
description: 'Store a durable project-specific convention, architecture note, key module warning, or local workflow expectation. Use this for repository-specific rules, important files, testing conventions, or architectural boundaries. Never store secrets or transient task state.',
|
|
2217
|
+
name: 'save_memory',
|
|
2218
|
+
description:
|
|
2219
|
+
'Save a durable observation or knowledge to persistent memory. Use this when you notice a reusable pattern, a user correction, a stable preference, a project convention, or a workflow insight. Do NOT use for casual chatter, trivial typos, one-off noise, or secrets. The memory is saved immediately and available in future sessions.',
|
|
2252
2220
|
parameters: {
|
|
2253
2221
|
type: 'object',
|
|
2254
2222
|
properties: {
|
|
2255
|
-
content: { type: 'string' },
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2223
|
+
content: { type: 'string', description: 'The knowledge or observation to remember' },
|
|
2224
|
+
summary: { type: 'string', description: 'Short summary for the memory index (under 80 chars)' },
|
|
2225
|
+
scope: {
|
|
2226
|
+
type: 'string',
|
|
2227
|
+
description: 'Where to store this memory. "user" = personal preferences (language, style, interaction habits). "global" = cross-project knowledge useful in ANY repository (environment quirks, general workflows, tool tips). "project" = specific to THIS repository only (architecture conventions, local config, test commands, file locations). Default: "global".'
|
|
2228
|
+
},
|
|
2229
|
+
kind: { type: 'string', description: 'Memory kind: preference, pattern, correction, observation, decision, failure, win, gap, convention. Default: observation' },
|
|
2230
|
+
replace_similar: { type: 'boolean', description: 'Replace an existing similar memory when true. Default: true.' }
|
|
2259
2231
|
},
|
|
2260
2232
|
required: ['content']
|
|
2261
2233
|
}
|
|
@@ -2305,26 +2277,6 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2305
2277
|
}
|
|
2306
2278
|
}
|
|
2307
2279
|
},
|
|
2308
|
-
capture_memory: {
|
|
2309
|
-
type: 'function',
|
|
2310
|
-
function: {
|
|
2311
|
-
name: 'capture_memory',
|
|
2312
|
-
description:
|
|
2313
|
-
'Capture a high-signal observation into the dream loop inbox during active work. Use this when you notice a reusable pattern, a user correction, a repeated failure with stable fix, a stable preference, or a workflow win. Do NOT use for casual chatter, trivial typos, or one-off noise. This is lightweight — entries land in inbox and are consolidated later.',
|
|
2314
|
-
parameters: {
|
|
2315
|
-
type: 'object',
|
|
2316
|
-
properties: {
|
|
2317
|
-
summary: { type: 'string', description: 'Short high-signal summary of the observation' },
|
|
2318
|
-
details: { type: 'string', description: 'Detailed explanation of the observation' },
|
|
2319
|
-
scope: { type: 'string', description: 'Scope: global, repo, or thread. Default: global' },
|
|
2320
|
-
type: { type: 'string', description: 'Observation type: correction, failure, preference, pattern, win, gap, decision. Default: observation' },
|
|
2321
|
-
tags: { type: 'array', items: { type: 'string' }, description: 'Optional tags for categorization' },
|
|
2322
|
-
suggested_action: { type: 'string', description: 'Optional suggested follow-up action' }
|
|
2323
|
-
},
|
|
2324
|
-
required: ['summary']
|
|
2325
|
-
}
|
|
2326
|
-
}
|
|
2327
|
-
},
|
|
2328
2280
|
dream_consolidate: {
|
|
2329
2281
|
type: 'function',
|
|
2330
2282
|
function: {
|
|
@@ -2584,42 +2536,32 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2584
2536
|
hasPendingApproval: nextPlan?.status === 'pending_approval'
|
|
2585
2537
|
};
|
|
2586
2538
|
},
|
|
2587
|
-
run: (
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
scope: 'global',
|
|
2603
|
-
content: args.content,
|
|
2604
|
-
kind: args.kind,
|
|
2605
|
-
summary: args.summary,
|
|
2606
|
-
replaceSimilar: args.replace_similar !== false,
|
|
2607
|
-
workspaceRoot,
|
|
2608
|
-
config
|
|
2609
|
-
});
|
|
2610
|
-
return { ok: true, scope: 'global', memory: saved };
|
|
2611
|
-
},
|
|
2612
|
-
remember_project: async (args = {}) => {
|
|
2539
|
+
run: Object.assign(
|
|
2540
|
+
(args) => runCommand(workspaceRoot, config, args),
|
|
2541
|
+
{
|
|
2542
|
+
prepareApproval: async (args) => ({
|
|
2543
|
+
command: args?.command || '',
|
|
2544
|
+
risk: args?._risk || 'high',
|
|
2545
|
+
evaluation: args?._evaluation || null
|
|
2546
|
+
})
|
|
2547
|
+
}
|
|
2548
|
+
),
|
|
2549
|
+
save_memory: async (args = {}) => {
|
|
2550
|
+
const rawScope = String(args.scope || 'global').toLowerCase();
|
|
2551
|
+
const memoryScope = rawScope === 'repo' || rawScope === 'project' ? 'project'
|
|
2552
|
+
: rawScope === 'user' ? 'user'
|
|
2553
|
+
: 'global';
|
|
2613
2554
|
const saved = await rememberMemory({
|
|
2614
|
-
scope:
|
|
2555
|
+
scope: memoryScope,
|
|
2615
2556
|
content: args.content,
|
|
2616
|
-
kind: args.kind,
|
|
2617
|
-
summary: args.summary,
|
|
2557
|
+
kind: args.kind || 'observation',
|
|
2558
|
+
summary: args.summary || String(args.content || '').slice(0, 80),
|
|
2559
|
+
source: 'tool',
|
|
2618
2560
|
replaceSimilar: args.replace_similar !== false,
|
|
2619
2561
|
workspaceRoot,
|
|
2620
2562
|
config
|
|
2621
2563
|
});
|
|
2622
|
-
return { ok: true, scope:
|
|
2564
|
+
return { ok: true, scope: memoryScope, memory: saved };
|
|
2623
2565
|
},
|
|
2624
2566
|
list_memory: async (args = {}) => ({
|
|
2625
2567
|
scope: String(args.scope || ''),
|
|
@@ -2634,18 +2576,6 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2634
2576
|
ok: true,
|
|
2635
2577
|
...(await forgetMemory({ scope: args.scope, id: args.id, workspaceRoot }))
|
|
2636
2578
|
}),
|
|
2637
|
-
capture_memory: async (args = {}) => {
|
|
2638
|
-
const entry = await captureToInbox({
|
|
2639
|
-
scope: args.scope,
|
|
2640
|
-
type: args.type,
|
|
2641
|
-
summary: args.summary,
|
|
2642
|
-
details: args.details,
|
|
2643
|
-
suggestedAction: args.suggested_action,
|
|
2644
|
-
tags: args.tags,
|
|
2645
|
-
source: 'tool'
|
|
2646
|
-
});
|
|
2647
|
-
return { ok: true, captured: entry };
|
|
2648
|
-
},
|
|
2649
2579
|
dream_consolidate: async (args = {}) => {
|
|
2650
2580
|
return runDreamConsolidation({
|
|
2651
2581
|
dryRun: args.dry_run === true,
|
|
@@ -2681,7 +2611,7 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2681
2611
|
}
|
|
2682
2612
|
};
|
|
2683
2613
|
|
|
2684
|
-
const
|
|
2614
|
+
const rawFormatters = {
|
|
2685
2615
|
read(result) {
|
|
2686
2616
|
if (typeof result === 'string') return result;
|
|
2687
2617
|
if (!result || typeof result !== 'object') return String(result);
|
|
@@ -2880,9 +2810,11 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2880
2810
|
}
|
|
2881
2811
|
return parts.join('\n');
|
|
2882
2812
|
}
|
|
2813
|
+
const runSummary = summarizeRunOutput(result);
|
|
2814
|
+
if (runSummary) return runSummary;
|
|
2883
2815
|
const command = String(result.command || '').slice(0, 200);
|
|
2884
|
-
const stdout = String(result.stdout || '')
|
|
2885
|
-
const stderr = String(result.stderr || '')
|
|
2816
|
+
const stdout = String(result.stdout || '');
|
|
2817
|
+
const stderr = String(result.stderr || '');
|
|
2886
2818
|
const code = result.code ?? 0;
|
|
2887
2819
|
const parts = [`[exit: ${code}]`];
|
|
2888
2820
|
if (command) parts.push(`command: ${command}`);
|
|
@@ -2903,6 +2835,11 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2903
2835
|
return result?.memory?.content ? `stored project memory: ${result.memory.content}` : JSON.stringify(result);
|
|
2904
2836
|
},
|
|
2905
2837
|
|
|
2838
|
+
save_memory(result) {
|
|
2839
|
+
const scope = result?.scope || 'global';
|
|
2840
|
+
return result?.memory?.content ? `stored ${scope} memory: ${result.memory.content}` : JSON.stringify(result);
|
|
2841
|
+
},
|
|
2842
|
+
|
|
2906
2843
|
list_memory(result) {
|
|
2907
2844
|
if (!result || typeof result !== 'object' || !Array.isArray(result.items)) return JSON.stringify(result);
|
|
2908
2845
|
if (result.items.length === 0) return `No ${result.scope || ''} memories found.`;
|
|
@@ -2938,8 +2875,7 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2938
2875
|
const kind = result.kind || '';
|
|
2939
2876
|
const content = result.content || result.source || '';
|
|
2940
2877
|
const header = `${kind} ${name}`;
|
|
2941
|
-
|
|
2942
|
-
return `${header}\n${content.slice(0, 1200)}\n... [omitted ${content.length - 1600} chars] ...\n${content.slice(-400)}`;
|
|
2878
|
+
return `${header}\n${content}`;
|
|
2943
2879
|
},
|
|
2944
2880
|
|
|
2945
2881
|
web_fetch(result) {
|
|
@@ -2951,7 +2887,9 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2951
2887
|
if (Array.isArray(result.links) && result.links.length > 0) {
|
|
2952
2888
|
lines.push(`links: ${result.links.slice(0, 5).map((item) => item.href).join(', ')}`);
|
|
2953
2889
|
}
|
|
2954
|
-
if (result.text)
|
|
2890
|
+
if (result.text) {
|
|
2891
|
+
lines.push(result.text);
|
|
2892
|
+
}
|
|
2955
2893
|
return lines.join('\n');
|
|
2956
2894
|
},
|
|
2957
2895
|
|
|
@@ -2992,6 +2930,13 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2992
2930
|
}
|
|
2993
2931
|
};
|
|
2994
2932
|
|
|
2933
|
+
const formatters = Object.fromEntries(
|
|
2934
|
+
Object.entries(rawFormatters).map(([name, formatter]) => [
|
|
2935
|
+
name,
|
|
2936
|
+
(result, args) => sanitizeTextForModel(formatter(result, args), getToolOutputSanitizeOptions(name))
|
|
2937
|
+
])
|
|
2938
|
+
);
|
|
2939
|
+
|
|
2995
2940
|
async function dispose() {
|
|
2996
2941
|
if (activeFffAdapter?.dispose) {
|
|
2997
2942
|
try {
|