agent-Specialization/easyagent/src/tools/read_file.js

104 lines
3.1 KiB
JavaScript

'use strict';
const fs = require('fs');
const path = require('path');
function resolvePath(workspace, p) {
if (path.isAbsolute(p)) return p;
return path.join(workspace, p);
}
function readLines(content) {
return content.split(/\r?\n/);
}
function applyMaxChars(text, maxChars) {
if (!maxChars || text.length <= maxChars) return { text, truncated: false };
return { text: text.slice(0, maxChars), truncated: true };
}
function readFileTool(workspace, args) {
const target = resolvePath(workspace, args.path);
const type = args.type || 'read';
try {
const raw = fs.readFileSync(target, 'utf8');
if (type === 'read') {
const lines = readLines(raw);
const start = Math.max(1, args.start_line || 1);
const end = Math.min(lines.length, args.end_line || lines.length);
const slice = lines.slice(start - 1, end).join('\n');
const capped = applyMaxChars(slice, args.max_chars);
return {
success: true,
type: 'read',
path: target,
line_start: start,
line_end: end,
content: capped.text,
truncated: capped.truncated,
};
}
if (type === 'search') {
const lines = readLines(raw);
const query = args.query || '';
const caseSensitive = !!args.case_sensitive;
const maxMatches = args.max_matches || 20;
const before = args.context_before || 0;
const after = args.context_after || 0;
const matches = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const hay = caseSensitive ? line : line.toLowerCase();
const needle = caseSensitive ? query : query.toLowerCase();
if (!needle) break;
if (hay.includes(needle)) {
const start = Math.max(0, i - before);
const end = Math.min(lines.length - 1, i + after);
const snippet = lines.slice(start, end + 1).join('\n');
matches.push({
id: `match_${matches.length + 1}`,
line_start: start + 1,
line_end: end + 1,
hits: [i + 1],
snippet,
});
if (matches.length >= maxMatches) break;
}
}
return {
success: true,
type: 'search',
path: target,
query,
case_sensitive: caseSensitive,
matches,
};
}
if (type === 'extract') {
const lines = readLines(raw);
const segments = Array.isArray(args.segments) ? args.segments : [];
const extracted = segments.map((seg, idx) => {
const start = Math.max(1, seg.start_line || 1);
const end = Math.min(lines.length, seg.end_line || lines.length);
return {
label: seg.label || `segment_${idx + 1}`,
line_start: start,
line_end: end,
content: lines.slice(start - 1, end).join('\n'),
};
});
return {
success: true,
type: 'extract',
path: target,
segments: extracted,
};
}
return { success: false, error: '未知 read_file type' };
} catch (err) {
return { success: false, error: err.message || String(err) };
}
}
module.exports = { readFileTool, resolvePath };