mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-18 17:04:49 +00:00
Fix SDK tools to respect cwd option
Core tools now properly use the cwd passed to createAgentSession(). Added tool factory functions for SDK users who specify custom cwd with explicit tools. Fixes #279
This commit is contained in:
parent
42bc368e70
commit
face745f3d
16 changed files with 1243 additions and 1044 deletions
|
|
@ -1,82 +1,93 @@
|
|||
import type { AgentTool } from "@mariozechner/pi-ai";
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import { mkdir, writeFile } from "fs/promises";
|
||||
import { dirname, resolve as resolvePath } from "path";
|
||||
import { expandPath } from "./path-utils.js";
|
||||
import { dirname } from "path";
|
||||
import { resolveToCwd } from "./path-utils.js";
|
||||
|
||||
const writeSchema = Type.Object({
|
||||
path: Type.String({ description: "Path to the file to write (relative or absolute)" }),
|
||||
content: Type.String({ description: "Content to write to the file" }),
|
||||
});
|
||||
|
||||
export const writeTool: AgentTool<typeof writeSchema> = {
|
||||
name: "write",
|
||||
label: "write",
|
||||
description:
|
||||
"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
|
||||
parameters: writeSchema,
|
||||
execute: async (_toolCallId: string, { path, content }: { path: string; content: string }, signal?: AbortSignal) => {
|
||||
const absolutePath = resolvePath(expandPath(path));
|
||||
const dir = dirname(absolutePath);
|
||||
export function createWriteTool(cwd: string): AgentTool<typeof writeSchema> {
|
||||
return {
|
||||
name: "write",
|
||||
label: "write",
|
||||
description:
|
||||
"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
|
||||
parameters: writeSchema,
|
||||
execute: async (
|
||||
_toolCallId: string,
|
||||
{ path, content }: { path: string; content: string },
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
const absolutePath = resolveToCwd(path, cwd);
|
||||
const dir = dirname(absolutePath);
|
||||
|
||||
return new Promise<{ content: Array<{ type: "text"; text: string }>; details: undefined }>((resolve, reject) => {
|
||||
// Check if already aborted
|
||||
if (signal?.aborted) {
|
||||
reject(new Error("Operation aborted"));
|
||||
return;
|
||||
}
|
||||
|
||||
let aborted = false;
|
||||
|
||||
// Set up abort handler
|
||||
const onAbort = () => {
|
||||
aborted = true;
|
||||
reject(new Error("Operation aborted"));
|
||||
};
|
||||
|
||||
if (signal) {
|
||||
signal.addEventListener("abort", onAbort, { once: true });
|
||||
}
|
||||
|
||||
// Perform the write operation
|
||||
(async () => {
|
||||
try {
|
||||
// Create parent directories if needed
|
||||
await mkdir(dir, { recursive: true });
|
||||
|
||||
// Check if aborted before writing
|
||||
if (aborted) {
|
||||
return new Promise<{ content: Array<{ type: "text"; text: string }>; details: undefined }>(
|
||||
(resolve, reject) => {
|
||||
// Check if already aborted
|
||||
if (signal?.aborted) {
|
||||
reject(new Error("Operation aborted"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Write the file
|
||||
await writeFile(absolutePath, content, "utf-8");
|
||||
let aborted = false;
|
||||
|
||||
// Check if aborted after writing
|
||||
if (aborted) {
|
||||
return;
|
||||
}
|
||||
// Set up abort handler
|
||||
const onAbort = () => {
|
||||
aborted = true;
|
||||
reject(new Error("Operation aborted"));
|
||||
};
|
||||
|
||||
// Clean up abort handler
|
||||
if (signal) {
|
||||
signal.removeEventListener("abort", onAbort);
|
||||
signal.addEventListener("abort", onAbort, { once: true });
|
||||
}
|
||||
|
||||
resolve({
|
||||
content: [{ type: "text", text: `Successfully wrote ${content.length} bytes to ${path}` }],
|
||||
details: undefined,
|
||||
});
|
||||
} catch (error: any) {
|
||||
// Clean up abort handler
|
||||
if (signal) {
|
||||
signal.removeEventListener("abort", onAbort);
|
||||
}
|
||||
// Perform the write operation
|
||||
(async () => {
|
||||
try {
|
||||
// Create parent directories if needed
|
||||
await mkdir(dir, { recursive: true });
|
||||
|
||||
if (!aborted) {
|
||||
reject(error);
|
||||
}
|
||||
}
|
||||
})();
|
||||
});
|
||||
},
|
||||
};
|
||||
// Check if aborted before writing
|
||||
if (aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Write the file
|
||||
await writeFile(absolutePath, content, "utf-8");
|
||||
|
||||
// Check if aborted after writing
|
||||
if (aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up abort handler
|
||||
if (signal) {
|
||||
signal.removeEventListener("abort", onAbort);
|
||||
}
|
||||
|
||||
resolve({
|
||||
content: [{ type: "text", text: `Successfully wrote ${content.length} bytes to ${path}` }],
|
||||
details: undefined,
|
||||
});
|
||||
} catch (error: any) {
|
||||
// Clean up abort handler
|
||||
if (signal) {
|
||||
signal.removeEventListener("abort", onAbort);
|
||||
}
|
||||
|
||||
if (!aborted) {
|
||||
reject(error);
|
||||
}
|
||||
}
|
||||
})();
|
||||
},
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** Default write tool using process.cwd() - for backwards compatibility */
|
||||
export const writeTool = createWriteTool(process.cwd());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue