feat: render function calls
This commit is contained in:
1 parent
4d878dfb61
commit
6a81529790
2 files changed
+75
-5
No files matched your search
+21
-4
@@ -45,6 +45,25 @@ function makeExecutor(bundle) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a name -> rendered-arguments function for the bundle, used to log
|
||||
* each call. Tools that do not provide a `render` fall back to a plain
|
||||
* JSON rendering of the arguments.
|
||||
*/
|
||||
function makeRenderer(bundle) {
|
||||
const byName = new Map(bundle.map((tool) => [tool.name, tool]));
|
||||
|
||||
return function render(name, args) {
|
||||
const tool = byName.get(name);
|
||||
if (!tool || typeof tool.render !== 'function') return JSON.stringify(args || {});
|
||||
try {
|
||||
return tool.render(args || {});
|
||||
} catch (err) {
|
||||
return JSON.stringify(args || {});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ *
|
||||
* Tool-call extraction
|
||||
* ------------------------------------------------------------------ */
|
||||
@@ -142,6 +161,7 @@ async function run({
|
||||
parameters,
|
||||
}));
|
||||
const execute = makeExecutor(bundle);
|
||||
const render = makeRenderer(bundle);
|
||||
|
||||
const history = Array.isArray(messages) ? messages.slice() : [];
|
||||
|
||||
@@ -188,10 +208,7 @@ async function run({
|
||||
role: 'tool',
|
||||
content: call,
|
||||
});
|
||||
}
|
||||
|
||||
if (calls.length) {
|
||||
console.log('called: ' + calls.map(c => c.tool_name));
|
||||
process.stderr.write(`called: ${call.tool_name} ${render(call.tool_name, call.arguments)}\n`);
|
||||
}
|
||||
|
||||
if (verify && verify()) {
|
||||
|
||||
+54
-1
@@ -149,6 +149,19 @@ function applyEdit(content, { search, replace = '', regex, global }) {
|
||||
return content.slice(0, at) + replace + content.slice(at + search.length);
|
||||
}
|
||||
|
||||
/** Collapse whitespace and clip to `max` characters for single-line output. */
|
||||
function oneLine(value, max = 60) {
|
||||
const text = String(value ?? '').replace(/\s+/g, ' ').trim();
|
||||
return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
|
||||
}
|
||||
|
||||
/** Fallback argument rendering: values joined, JSON for non-strings. */
|
||||
function defaultRender(args) {
|
||||
return Object.values(args ?? {})
|
||||
.map((value) => (typeof value === 'string' ? value : JSON.stringify(value)))
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ *
|
||||
* Tool base class
|
||||
* ------------------------------------------------------------------ */
|
||||
@@ -181,6 +194,16 @@ export class Tool {
|
||||
return this.run(args ?? {});
|
||||
}
|
||||
|
||||
/**
|
||||
* One-line rendering of a call's arguments, used when logging the call.
|
||||
* Subclasses override this when a more legible summary is possible.
|
||||
*/
|
||||
render(args) {
|
||||
// returning all json for all calls bloats
|
||||
return '';
|
||||
//return defaultRender(args);
|
||||
}
|
||||
|
||||
/** Resolve `file` against the root, asserting the given permission. */
|
||||
resolve(file, verb) {
|
||||
const abs = path.resolve(this.root, file);
|
||||
@@ -206,6 +229,11 @@ class ReadFile extends Tool {
|
||||
required: ['path'],
|
||||
};
|
||||
|
||||
render({ path: file, lineStart, lineEnd }) {
|
||||
const range = lineStart || lineEnd ? `:${lineStart ?? 1}-${lineEnd ?? 'eof'}` : '';
|
||||
return `${file}${range}`;
|
||||
}
|
||||
|
||||
run({ path: file, lineStart, lineEnd }) {
|
||||
const abs = this.resolve(file, 'read');
|
||||
|
||||
@@ -236,6 +264,10 @@ class ListDir extends Tool {
|
||||
required: [],
|
||||
};
|
||||
|
||||
render({ path: dir }) {
|
||||
return dir || '.';
|
||||
}
|
||||
|
||||
run({ path: dir }) {
|
||||
const abs = this.resolve(dir || '.', 'read');
|
||||
|
||||
@@ -263,6 +295,10 @@ class FindFiles extends Tool {
|
||||
required: ['pattern'],
|
||||
};
|
||||
|
||||
render({ pattern, path: dir }) {
|
||||
return dir ? `${pattern} in ${dir}` : pattern;
|
||||
}
|
||||
|
||||
run({ pattern, path: dir = '.', limit = 200 }) {
|
||||
const abs = this.resolve(dir, 'read');
|
||||
const match = globToRegExp(pattern);
|
||||
@@ -307,6 +343,10 @@ class SearchFiles extends Tool {
|
||||
required: ['pattern'],
|
||||
};
|
||||
|
||||
render({ pattern, path: dir = '.', glob = '**/*' }) {
|
||||
return `${pattern} in ${dir} (${glob})`;
|
||||
}
|
||||
|
||||
run({
|
||||
pattern,
|
||||
path: dir = '.',
|
||||
@@ -390,6 +430,10 @@ class WriteFile extends Tool {
|
||||
required: ['path', 'content'],
|
||||
};
|
||||
|
||||
render({ path: file }) {
|
||||
return file;
|
||||
}
|
||||
|
||||
run({ path: file, content }) {
|
||||
const abs = this.resolve(file, 'write');
|
||||
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
||||
@@ -415,6 +459,10 @@ class UpdateFile extends Tool {
|
||||
required: ['path', 'search'],
|
||||
};
|
||||
|
||||
render({ path: file, search }) {
|
||||
return `${file}: ${oneLine(search)}`;
|
||||
}
|
||||
|
||||
run({ path: file, search, replace = '', global, regex }) {
|
||||
const abs = this.resolve(file, 'write');
|
||||
const content = fs.readFileSync(abs, 'utf8');
|
||||
@@ -450,6 +498,10 @@ class MultiEdit extends Tool {
|
||||
required: ['path', 'edits'],
|
||||
};
|
||||
|
||||
render({ path: file, edits }) {
|
||||
return `${file} (${Array.isArray(edits) ? edits.length : 0} edits)`;
|
||||
}
|
||||
|
||||
run({ path: file, edits }) {
|
||||
const abs = this.resolve(file, 'write');
|
||||
const original = fs.readFileSync(abs, 'utf8');
|
||||
@@ -504,12 +556,13 @@ function selectDefaults(selection) {
|
||||
* to the resolved scope so it only receives the call arguments.
|
||||
*/
|
||||
function wrap(tool, root) {
|
||||
const { name, description, parameters, scope, handler } = tool;
|
||||
const { name, description, parameters, scope, handler, render } = tool;
|
||||
return {
|
||||
name,
|
||||
description,
|
||||
parameters,
|
||||
handler: (args) => handler(args ?? {}, { root, scope }),
|
||||
render: typeof render === 'function' ? render : defaultRender,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user