fix: preserve explicit maxChars=0 (#796) (thanks @gabriel-trigo)
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
- Anthropic: merge consecutive user turns (preserve newest metadata) before validation to avoid “Incorrect role information” errors. (#804 — thanks @ThomsenDrake)
|
- Anthropic: merge consecutive user turns (preserve newest metadata) before validation to avoid “Incorrect role information” errors. (#804 — thanks @ThomsenDrake)
|
||||||
- Discord/Slack: centralize reply-thread planning so auto-thread replies stay in the created thread without parent reply refs.
|
- Discord/Slack: centralize reply-thread planning so auto-thread replies stay in the created thread without parent reply refs.
|
||||||
- Update: run `clawdbot doctor --non-interactive` during updates to avoid TTY hangs. (#781 — thanks @ronyrus)
|
- Update: run `clawdbot doctor --non-interactive` during updates to avoid TTY hangs. (#781 — thanks @ronyrus)
|
||||||
|
- Browser tools: treat explicit `maxChars: 0` as unlimited while keeping the default limit only when omitted. (#796 — thanks @gabriel-trigo)
|
||||||
- Tools: allow Claude/Gemini tool param aliases (`file_path`, `old_string`, `new_string`) while enforcing required params at runtime. (#793 — thanks @hsrvc)
|
- Tools: allow Claude/Gemini tool param aliases (`file_path`, `old_string`, `new_string`) while enforcing required params at runtime. (#793 — thanks @hsrvc)
|
||||||
- Gemini: downgrade tool-call history missing `thought_signature` to avoid INVALID_ARGUMENT errors. (#793 — thanks @hsrvc)
|
- Gemini: downgrade tool-call history missing `thought_signature` to avoid INVALID_ARGUMENT errors. (#793 — thanks @hsrvc)
|
||||||
- Messaging: enforce context isolation for message tool sends across providers (normalized targets + tests). (#793 — thanks @hsrvc)
|
- Messaging: enforce context isolation for message tool sends across providers (normalized targets + tests). (#793 — thanks @hsrvc)
|
||||||
|
|||||||
@@ -89,4 +89,17 @@ describe("browser tool snapshot maxChars", () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("skips the default when maxChars is explicitly zero", async () => {
|
||||||
|
const tool = createBrowserTool();
|
||||||
|
await tool.execute?.(null, {
|
||||||
|
action: "snapshot",
|
||||||
|
format: "ai",
|
||||||
|
maxChars: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(browserClientMocks.browserSnapshot).toHaveBeenCalled();
|
||||||
|
const [, opts] = browserClientMocks.browserSnapshot.mock.calls.at(-1) ?? [];
|
||||||
|
expect(Object.hasOwn(opts ?? {}, "maxChars")).toBe(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -322,6 +322,7 @@ export function createBrowserTool(opts?: {
|
|||||||
params.format === "ai" || params.format === "aria"
|
params.format === "ai" || params.format === "aria"
|
||||||
? (params.format as "ai" | "aria")
|
? (params.format as "ai" | "aria")
|
||||||
: "ai";
|
: "ai";
|
||||||
|
const hasMaxChars = Object.hasOwn(params, "maxChars");
|
||||||
const targetId =
|
const targetId =
|
||||||
typeof params.targetId === "string"
|
typeof params.targetId === "string"
|
||||||
? params.targetId.trim()
|
? params.targetId.trim()
|
||||||
@@ -338,7 +339,9 @@ export function createBrowserTool(opts?: {
|
|||||||
: undefined;
|
: undefined;
|
||||||
const resolvedMaxChars =
|
const resolvedMaxChars =
|
||||||
format === "ai"
|
format === "ai"
|
||||||
? (maxChars ?? DEFAULT_AI_SNAPSHOT_MAX_CHARS)
|
? hasMaxChars
|
||||||
|
? maxChars
|
||||||
|
: DEFAULT_AI_SNAPSHOT_MAX_CHARS
|
||||||
: undefined;
|
: undefined;
|
||||||
const interactive =
|
const interactive =
|
||||||
typeof params.interactive === "boolean"
|
typeof params.interactive === "boolean"
|
||||||
@@ -360,7 +363,9 @@ export function createBrowserTool(opts?: {
|
|||||||
format,
|
format,
|
||||||
targetId,
|
targetId,
|
||||||
limit,
|
limit,
|
||||||
...(resolvedMaxChars ? { maxChars: resolvedMaxChars } : {}),
|
...(typeof resolvedMaxChars === "number"
|
||||||
|
? { maxChars: resolvedMaxChars }
|
||||||
|
: {}),
|
||||||
interactive,
|
interactive,
|
||||||
compact,
|
compact,
|
||||||
depth,
|
depth,
|
||||||
|
|||||||
@@ -1195,6 +1195,7 @@ export function registerBrowserAgentRoutes(
|
|||||||
: "aria";
|
: "aria";
|
||||||
const limitRaw =
|
const limitRaw =
|
||||||
typeof req.query.limit === "string" ? Number(req.query.limit) : undefined;
|
typeof req.query.limit === "string" ? Number(req.query.limit) : undefined;
|
||||||
|
const hasMaxChars = Object.hasOwn(req.query, "maxChars");
|
||||||
const maxCharsRaw =
|
const maxCharsRaw =
|
||||||
typeof req.query.maxChars === "string"
|
typeof req.query.maxChars === "string"
|
||||||
? Number(req.query.maxChars)
|
? Number(req.query.maxChars)
|
||||||
@@ -1207,7 +1208,11 @@ export function registerBrowserAgentRoutes(
|
|||||||
? Math.floor(maxCharsRaw)
|
? Math.floor(maxCharsRaw)
|
||||||
: undefined;
|
: undefined;
|
||||||
const resolvedMaxChars =
|
const resolvedMaxChars =
|
||||||
format === "ai" ? (maxChars ?? DEFAULT_AI_SNAPSHOT_MAX_CHARS) : undefined;
|
format === "ai"
|
||||||
|
? hasMaxChars
|
||||||
|
? maxChars
|
||||||
|
: DEFAULT_AI_SNAPSHOT_MAX_CHARS
|
||||||
|
: undefined;
|
||||||
const interactive = toBoolean(req.query.interactive);
|
const interactive = toBoolean(req.query.interactive);
|
||||||
const compact = toBoolean(req.query.compact);
|
const compact = toBoolean(req.query.compact);
|
||||||
const depth = toNumber(req.query.depth);
|
const depth = toNumber(req.query.depth);
|
||||||
|
|||||||
@@ -687,6 +687,25 @@ describe("browser control server", () => {
|
|||||||
expect(stopped.stopped).toBe(true);
|
expect(stopped.stopped).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("skips default maxChars when explicitly set to zero", async () => {
|
||||||
|
const { startBrowserControlServerFromConfig } = await import("./server.js");
|
||||||
|
await startBrowserControlServerFromConfig();
|
||||||
|
const base = `http://127.0.0.1:${testPort}`;
|
||||||
|
await realFetch(`${base}/start`, { method: "POST" }).then((r) => r.json());
|
||||||
|
|
||||||
|
const snapAi = (await realFetch(
|
||||||
|
`${base}/snapshot?format=ai&maxChars=0`,
|
||||||
|
).then((r) => r.json())) as { ok: boolean; format?: string };
|
||||||
|
expect(snapAi.ok).toBe(true);
|
||||||
|
expect(snapAi.format).toBe("ai");
|
||||||
|
|
||||||
|
const [call] = pwMocks.snapshotAiViaPlaywright.mock.calls.at(-1) ?? [];
|
||||||
|
expect(call).toEqual({
|
||||||
|
cdpUrl: cdpBaseUrl,
|
||||||
|
targetId: "abcd1234",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("validates agent inputs (agent routes)", async () => {
|
it("validates agent inputs (agent routes)", async () => {
|
||||||
const { startBrowserControlServerFromConfig } = await import("./server.js");
|
const { startBrowserControlServerFromConfig } = await import("./server.js");
|
||||||
await startBrowserControlServerFromConfig();
|
await startBrowserControlServerFromConfig();
|
||||||
|
|||||||
Reference in New Issue
Block a user