Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions core/tools/parseArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,38 @@ export function getStringArg(
argName: string,
allowEmpty = false,
): string {
if (!args || !(argName in args) || typeof args[argName] !== "string") {
if (!args || !(argName in args)) {
throw new Error(
`\`${argName}\` argument is required${allowEmpty ? "" : " and must not be empty or whitespace-only"}. (type string)`,
);
}
if (!allowEmpty && !args[argName].trim()) {

let value = args[argName];

// Handle case where JSON was parsed into an object by the tool call parser.
// If the arguments to the tool call are valid JSON (e.g. the model attempts to create a .json file)
// the earlier call to JSON.parse() will have deeply parsed the returned arguments.
// If that has happened, convert back to string.
if (typeof value === "object" && value !== null) {
try {
value = JSON.stringify(value);
return value;
} catch (e) {
//Swallow this, because it might be fine later.
}
}

if (typeof value !== "string") {
throw new Error(
`\`${argName}\` argument is required${allowEmpty ? "" : " and must not be empty or whitespace-only"}. (type string)`,
);
}

if (!allowEmpty && !value.trim()) {
throw new Error(`Argument ${argName} must not be empty or whitespace-only`);
}
return args[argName];

return value;
}

export function getOptionalStringArg(
Expand Down
44 changes: 44 additions & 0 deletions core/tools/parseArgs.vitest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,50 @@ describe("getStringArg", () => {
"`name` argument is required and must not be empty or whitespace-only. (type string)",
);
});

it("should convert parsed JSON object to string for contents parameter", () => {
// This simulates the case where JSON.parse() has converted a JSON string into an object
const args = { contents: { key: "value", number: 123 } };
const result = getStringArg(args, "contents");
expect(result).toBe('{"key":"value","number":123}');
});

it("should convert nested JSON object to string for contents parameter", () => {
const args = {
contents: {
user: {
name: "John",
details: {
age: 30,
preferences: ["coding", "reading"],
},
},
},
};
const result = getStringArg(args, "contents");
const expected =
'{"user":{"name":"John","details":{"age":30,"preferences":["coding","reading"]}}}';
expect(result).toBe(expected);
});

it("should convert JSON array to string for contents parameter", () => {
const args = { contents: ["item1", "item2", { key: "value" }] };
const result = getStringArg(args, "contents");
expect(result).toBe('["item1","item2",{"key":"value"}]');
});

it("should handle contents parameter that is already a string", () => {
const args = { contents: "already a string" };
const result = getStringArg(args, "contents");
expect(result).toBe("already a string");
});

it("should handle contents parameter that is null", () => {
const args = { contents: null };
expect(() => getStringArg(args, "contents")).toThrowError(
"`contents` argument is required and must not be empty or whitespace-only. (type string)",
);
});
});

describe("getOptionalStringArg", () => {
Expand Down
Loading