Skip to content
Open
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
19 changes: 18 additions & 1 deletion src/parse-sdk-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,28 @@ export function parseSdkOptions(options: ClaudeOptions): ParsedSdkOptions {
};
}

// Parse and validate maxTurns
let maxTurns: number | undefined;
if (options.maxTurns) {
const parsed = parseInt(options.maxTurns, 10);
if (Number.isNaN(parsed)) {
throw new Error(
`Invalid max_turns value: "${options.maxTurns}". Must be a valid integer.`,
);
}
if (parsed < 0) {
throw new Error(
`Invalid max_turns value: "${options.maxTurns}". Must be a non-negative integer.`,
);
}
maxTurns = parsed;
}

// Build SDK options - use merged tools from both direct options and claudeArgs
const sdkOptions: SdkOptions = {
// Direct options from ClaudeOptions inputs
model: options.model,
maxTurns: options.maxTurns ? parseInt(options.maxTurns, 10) : undefined,
maxTurns,
allowedTools:
mergedAllowedTools.length > 0 ? mergedAllowedTools : undefined,
disallowedTools:
Expand Down
50 changes: 50 additions & 0 deletions test/parse-sdk-options.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,56 @@ describe("parseSdkOptions", () => {
});
});

describe("maxTurns validation", () => {
test("should parse valid maxTurns value", () => {
const options: ClaudeOptions = {
maxTurns: "5",
};

const result = parseSdkOptions(options);

expect(result.sdkOptions.maxTurns).toBe(5);
});

test("should return undefined maxTurns when not provided", () => {
const options: ClaudeOptions = {};

const result = parseSdkOptions(options);

expect(result.sdkOptions.maxTurns).toBeUndefined();
});

test("should throw error for non-numeric maxTurns", () => {
const options: ClaudeOptions = {
maxTurns: "abc",
};

expect(() => parseSdkOptions(options)).toThrow(
'Invalid max_turns value: "abc". Must be a valid integer.',
);
});

test("should throw error for negative maxTurns", () => {
const options: ClaudeOptions = {
maxTurns: "-5",
};

expect(() => parseSdkOptions(options)).toThrow(
'Invalid max_turns value: "-5". Must be a non-negative integer.',
);
});

test("should parse maxTurns with leading/trailing text as NaN and throw", () => {
const options: ClaudeOptions = {
maxTurns: "ten",
};

expect(() => parseSdkOptions(options)).toThrow(
'Invalid max_turns value: "ten". Must be a valid integer.',
);
});
});

describe("other extraArgs passthrough", () => {
test("should pass through json-schema in extraArgs", () => {
const options: ClaudeOptions = {
Expand Down