@poncho-ai/browser 0.6.3 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/browser@0.6.3 build /home/runner/work/poncho-ai/poncho-ai/packages/browser
2
+ > @poncho-ai/browser@0.6.5 build /home/runner/work/poncho-ai/poncho-ai/packages/browser
3
3
  > tsup src/index.ts --format esm --dts
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -7,8 +7,8 @@
7
7
  CLI tsup v8.5.1
8
8
  CLI Target: es2022
9
9
  ESM Build start
10
- ESM dist/index.js 44.07 KB
11
- ESM ⚡️ Build success in 79ms
10
+ ESM dist/index.js 45.97 KB
11
+ ESM ⚡️ Build success in 73ms
12
12
  DTS Build start
13
- DTS ⚡️ Build success in 4573ms
14
- DTS dist/index.d.ts 13.72 KB
13
+ DTS ⚡️ Build success in 4746ms
14
+ DTS dist/index.d.ts 13.69 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @poncho-ai/browser
2
2
 
3
+ ## 0.6.5
4
+
5
+ ### Patch Changes
6
+
7
+ - [#42](https://github.com/cesr/poncho-ai/pull/42) [`e58a984`](https://github.com/cesr/poncho-ai/commit/e58a984efaa673b649318102bbf735fb4c2f9172) Thanks [@cesr](https://github.com/cesr)! - Add continuation model and fire-and-forget subagents
8
+
9
+ **Continuation model**: Agents no longer send a synthetic `"Continue"` user message between steps. Instead, the harness injects a transient signal when needed, and the full internal message chain is preserved across continuations so the LLM never loses context. `RunInput` gains `disableSoftDeadline` and `RunResult` gains `continuationMessages`.
10
+
11
+ **Fire-and-forget subagents**: Subagents now run asynchronously in the background. `spawn_subagent` returns immediately with a subagent ID; results are delivered back to the parent conversation as a callback once the subagent completes. Subagents cannot spawn their own subagents. The web UI shows results in a collapsible disclosure and reconnects the live event stream automatically when the parent agent resumes.
12
+
13
+ **Bug fixes**:
14
+ - Fixed a race condition where concurrent runs on the same harness instance could assign a subagent or browser tab to the wrong parent conversation (shared `_currentRunConversationId` field replaced with per-run `ToolContext.conversationId`).
15
+ - Fixed Upstash KV store silently dropping large values by switching from URL-path encoding to request body format for `SET`/`SETEX` commands.
16
+ - Fixed empty assistant content blocks causing Anthropic `text content blocks must be non-empty` errors.
17
+
18
+ **Client**: Added `getConversationStatus()` and `waitForSubagents` option on `sendMessage()`.
19
+
20
+ - Updated dependencies [[`e58a984`](https://github.com/cesr/poncho-ai/commit/e58a984efaa673b649318102bbf735fb4c2f9172)]:
21
+ - @poncho-ai/sdk@1.6.0
22
+
23
+ ## 0.6.4
24
+
25
+ ### Patch Changes
26
+
27
+ - [`b5af10a`](https://github.com/cesr/poncho-ai/commit/b5af10a2f7b0023c683f14cd465105f8ddfff0ee) Thanks [@cesr](https://github.com/cesr)! - Fix browser cookie restore failing with "Invalid parameters" by sanitizing Playwright-format cookies to CDP-compatible format before calling Network.setCookies. Falls back to per-cookie restore when batch call fails.
28
+
3
29
  ## 0.6.3
4
30
 
5
31
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -166,7 +166,7 @@ declare class BrowserSession {
166
166
  private emitStatus;
167
167
  }
168
168
 
169
- declare function createBrowserTools(getSession: () => BrowserSession, getConversationId: () => string): ToolDefinition[];
169
+ declare function createBrowserTools(getSession: () => BrowserSession): ToolDefinition[];
170
170
 
171
171
  /**
172
172
  * Returns a realistic Chrome user-agent string for the host OS.
package/dist/index.js CHANGED
@@ -186,6 +186,24 @@ async function getBrowserManagerCtor() {
186
186
  return BrowserManagerCtor;
187
187
  }
188
188
  var MAX_TABS = 8;
189
+ var VALID_SAME_SITE = ["Strict", "Lax", "None"];
190
+ function sanitizeCookieForCDP(c) {
191
+ const name = typeof c.name === "string" ? c.name : "";
192
+ const value = typeof c.value === "string" ? c.value : "";
193
+ if (!name) return null;
194
+ const out = { name, value };
195
+ if (typeof c.domain === "string" && c.domain) out.domain = c.domain;
196
+ if (typeof c.path === "string") out.path = c.path;
197
+ if (typeof c.secure === "boolean") out.secure = c.secure;
198
+ if (typeof c.httpOnly === "boolean") out.httpOnly = c.httpOnly;
199
+ if (typeof c.expires === "number" && c.expires > 0) {
200
+ out.expires = c.expires;
201
+ }
202
+ if (typeof c.sameSite === "string" && VALID_SAME_SITE.includes(c.sameSite)) {
203
+ out.sameSite = c.sameSite;
204
+ }
205
+ return out;
206
+ }
189
207
  var SAME_TAB_INIT_SCRIPT = `
190
208
  (() => {
191
209
  // Override window.open to navigate in-place
@@ -836,6 +854,10 @@ var BrowserSession = class {
836
854
  tab.frameListeners.add(listener);
837
855
  return () => {
838
856
  tab.frameListeners.delete(listener);
857
+ if (tab.frameListeners.size === 0 && this._screencastConversation === conversationId) {
858
+ this.stopScreencast().catch(() => {
859
+ });
860
+ }
839
861
  };
840
862
  }
841
863
  onStatus(conversationId, listener) {
@@ -941,8 +963,28 @@ var BrowserSession = class {
941
963
  if (!json) return;
942
964
  const state = JSON.parse(json);
943
965
  if (state.cookies?.length) {
944
- await cdp.send("Network.setCookies", { cookies: state.cookies });
945
- console.log(`[poncho][browser] Restored ${state.cookies.length} cookies`);
966
+ const sanitized = state.cookies.map(sanitizeCookieForCDP).filter((c) => c !== null);
967
+ if (sanitized.length) {
968
+ try {
969
+ await cdp.send("Network.setCookies", { cookies: sanitized });
970
+ } catch {
971
+ let restored = 0;
972
+ for (const cookie of sanitized) {
973
+ try {
974
+ await cdp.send("Network.setCookies", { cookies: [cookie] });
975
+ restored++;
976
+ } catch {
977
+ }
978
+ }
979
+ if (restored > 0) {
980
+ console.log(`[poncho][browser] Restored ${restored}/${sanitized.length} cookies (batch failed, fell back to individual)`);
981
+ } else {
982
+ console.warn("[poncho][browser] Could not restore any cookies");
983
+ }
984
+ return;
985
+ }
986
+ console.log(`[poncho][browser] Restored ${sanitized.length} cookies`);
987
+ }
946
988
  }
947
989
  if (state.origins?.length) {
948
990
  const entries = {};
@@ -1033,7 +1075,7 @@ var BrowserSession = class {
1033
1075
  };
1034
1076
 
1035
1077
  // src/tools.ts
1036
- function createBrowserTools(getSession, getConversationId) {
1078
+ function createBrowserTools(getSession) {
1037
1079
  return [
1038
1080
  {
1039
1081
  name: "browser_open",
@@ -1048,9 +1090,9 @@ function createBrowserTools(getSession, getConversationId) {
1048
1090
  },
1049
1091
  required: ["url"]
1050
1092
  },
1051
- handler: async (input) => {
1093
+ handler: async (input, context) => {
1052
1094
  const session = getSession();
1053
- const cid = getConversationId();
1095
+ const cid = context.conversationId ?? "__default__";
1054
1096
  const url = String(input.url ?? "");
1055
1097
  if (!url) throw new Error("url is required");
1056
1098
  const result = await session.open(cid, url);
@@ -1067,9 +1109,9 @@ function createBrowserTools(getSession, getConversationId) {
1067
1109
  type: "object",
1068
1110
  properties: {}
1069
1111
  },
1070
- handler: async () => {
1112
+ handler: async (_input, context) => {
1071
1113
  const session = getSession();
1072
- const snapshot = await session.snapshot(getConversationId());
1114
+ const snapshot = await session.snapshot(context.conversationId ?? "__default__");
1073
1115
  return { snapshot };
1074
1116
  }
1075
1117
  },
@@ -1086,11 +1128,11 @@ function createBrowserTools(getSession, getConversationId) {
1086
1128
  },
1087
1129
  required: ["ref"]
1088
1130
  },
1089
- handler: async (input) => {
1131
+ handler: async (input, context) => {
1090
1132
  const session = getSession();
1091
1133
  const ref = String(input.ref ?? "");
1092
1134
  if (!ref) throw new Error("ref is required");
1093
- await session.click(getConversationId(), ref);
1135
+ await session.click(context.conversationId ?? "__default__", ref);
1094
1136
  return { clicked: ref };
1095
1137
  }
1096
1138
  },
@@ -1111,12 +1153,12 @@ function createBrowserTools(getSession, getConversationId) {
1111
1153
  },
1112
1154
  required: ["text"]
1113
1155
  },
1114
- handler: async (input) => {
1156
+ handler: async (input, context) => {
1115
1157
  const session = getSession();
1116
1158
  const text = String(input.text ?? "");
1117
1159
  if (!text) throw new Error("text is required");
1118
1160
  const exact = input.exact === true;
1119
- await session.clickText(getConversationId(), text, exact);
1161
+ await session.clickText(context.conversationId ?? "__default__", text, exact);
1120
1162
  return { clicked: text, exact };
1121
1163
  }
1122
1164
  },
@@ -1133,11 +1175,11 @@ function createBrowserTools(getSession, getConversationId) {
1133
1175
  },
1134
1176
  required: ["script"]
1135
1177
  },
1136
- handler: async (input) => {
1178
+ handler: async (input, context) => {
1137
1179
  const session = getSession();
1138
1180
  const script = String(input.script ?? "");
1139
1181
  if (!script) throw new Error("script is required");
1140
- const result = await session.executeJs(getConversationId(), script);
1182
+ const result = await session.executeJs(context.conversationId ?? "__default__", script);
1141
1183
  return { result: result ?? null };
1142
1184
  }
1143
1185
  },
@@ -1158,12 +1200,12 @@ function createBrowserTools(getSession, getConversationId) {
1158
1200
  },
1159
1201
  required: ["ref", "text"]
1160
1202
  },
1161
- handler: async (input) => {
1203
+ handler: async (input, context) => {
1162
1204
  const session = getSession();
1163
1205
  const ref = String(input.ref ?? "");
1164
1206
  const text = String(input.text ?? "");
1165
1207
  if (!ref) throw new Error("ref is required");
1166
- await session.type(getConversationId(), ref, text);
1208
+ await session.type(context.conversationId ?? "__default__", ref, text);
1167
1209
  return { typed: text, into: ref };
1168
1210
  }
1169
1211
  },
@@ -1174,9 +1216,9 @@ function createBrowserTools(getSession, getConversationId) {
1174
1216
  type: "object",
1175
1217
  properties: {}
1176
1218
  },
1177
- handler: async () => {
1219
+ handler: async (_input, context) => {
1178
1220
  const session = getSession();
1179
- const result = await session.content(getConversationId());
1221
+ const result = await session.content(context.conversationId ?? "__default__");
1180
1222
  return { url: result.url, title: result.title, text: result.text };
1181
1223
  }
1182
1224
  },
@@ -1187,9 +1229,9 @@ function createBrowserTools(getSession, getConversationId) {
1187
1229
  type: "object",
1188
1230
  properties: {}
1189
1231
  },
1190
- handler: async () => {
1232
+ handler: async (_input, context) => {
1191
1233
  const session = getSession();
1192
- const base64 = await session.screenshot(getConversationId());
1234
+ const base64 = await session.screenshot(context.conversationId ?? "__default__");
1193
1235
  const filePart = {
1194
1236
  type: "file",
1195
1237
  data: base64,
@@ -1217,11 +1259,11 @@ function createBrowserTools(getSession, getConversationId) {
1217
1259
  },
1218
1260
  required: ["direction"]
1219
1261
  },
1220
- handler: async (input) => {
1262
+ handler: async (input, context) => {
1221
1263
  const session = getSession();
1222
1264
  const direction = String(input.direction ?? "down");
1223
1265
  const amount = typeof input.amount === "number" ? input.amount : void 0;
1224
- await session.scroll(getConversationId(), direction, amount);
1266
+ await session.scroll(context.conversationId ?? "__default__", direction, amount);
1225
1267
  return { scrolled: direction, amount: amount ?? "viewport" };
1226
1268
  }
1227
1269
  },
@@ -1237,10 +1279,10 @@ function createBrowserTools(getSession, getConversationId) {
1237
1279
  }
1238
1280
  }
1239
1281
  },
1240
- handler: async (input) => {
1282
+ handler: async (input, context) => {
1241
1283
  const session = getSession();
1242
1284
  const url = input.url ? String(input.url) : void 0;
1243
- const { cleared } = await session.clearCookies(getConversationId(), url);
1285
+ const { cleared } = await session.clearCookies(context.conversationId ?? "__default__", url);
1244
1286
  return { cleared, scope: url ?? "all" };
1245
1287
  }
1246
1288
  },
@@ -1251,9 +1293,9 @@ function createBrowserTools(getSession, getConversationId) {
1251
1293
  type: "object",
1252
1294
  properties: {}
1253
1295
  },
1254
- handler: async () => {
1296
+ handler: async (_input, context) => {
1255
1297
  const session = getSession();
1256
- await session.closeTab(getConversationId());
1298
+ await session.closeTab(context.conversationId ?? "__default__");
1257
1299
  return { closed: true };
1258
1300
  }
1259
1301
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/browser",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "description": "Browser automation for Poncho agents, powered by agent-browser",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "agent-browser": "^0.15.1",
24
- "@poncho-ai/sdk": "1.5.0"
24
+ "@poncho-ai/sdk": "1.6.0"
25
25
  },
26
26
  "devDependencies": {
27
27
  "tsup": "^8.0.0",
package/src/session.ts CHANGED
@@ -62,6 +62,37 @@ async function getBrowserManagerCtor(): Promise<new () => BrowserManagerInstance
62
62
 
63
63
  const MAX_TABS = 8;
64
64
 
65
+ const VALID_SAME_SITE = ["Strict", "Lax", "None"];
66
+
67
+ /**
68
+ * Map a Playwright-format cookie to a CDP-compatible CookieParam, stripping
69
+ * unknown fields and fixing values that newer Chrome versions reject.
70
+ */
71
+ function sanitizeCookieForCDP(c: Record<string, unknown>): Record<string, unknown> | null {
72
+ const name = typeof c.name === "string" ? c.name : "";
73
+ const value = typeof c.value === "string" ? c.value : "";
74
+ if (!name) return null;
75
+
76
+ const out: Record<string, unknown> = { name, value };
77
+
78
+ if (typeof c.domain === "string" && c.domain) out.domain = c.domain;
79
+ if (typeof c.path === "string") out.path = c.path;
80
+ if (typeof c.secure === "boolean") out.secure = c.secure;
81
+ if (typeof c.httpOnly === "boolean") out.httpOnly = c.httpOnly;
82
+
83
+ // Playwright uses -1 for session cookies; CDP expects the field to be
84
+ // absent for session cookies.
85
+ if (typeof c.expires === "number" && c.expires > 0) {
86
+ out.expires = c.expires;
87
+ }
88
+
89
+ if (typeof c.sameSite === "string" && VALID_SAME_SITE.includes(c.sameSite)) {
90
+ out.sameSite = c.sameSite;
91
+ }
92
+
93
+ return out;
94
+ }
95
+
65
96
  /**
66
97
  * Init script that forces new-tab navigations (window.open, target="_blank")
67
98
  * to open in the current tab. Runs before page scripts on every navigation.
@@ -779,7 +810,12 @@ export class BrowserSession {
779
810
  this.tabs.set(conversationId, tab);
780
811
  }
781
812
  tab.frameListeners.add(listener);
782
- return () => { tab!.frameListeners.delete(listener); };
813
+ return () => {
814
+ tab!.frameListeners.delete(listener);
815
+ if (tab!.frameListeners.size === 0 && this._screencastConversation === conversationId) {
816
+ this.stopScreencast().catch(() => {});
817
+ }
818
+ };
783
819
  }
784
820
 
785
821
  onStatus(conversationId: string, listener: StatusListener): () => void {
@@ -896,8 +932,29 @@ export class BrowserSession {
896
932
  origins?: Array<{ origin: string; localStorage: Array<{ name: string; value: string }> }>;
897
933
  };
898
934
  if (state.cookies?.length) {
899
- await cdp.send("Network.setCookies", { cookies: state.cookies });
900
- console.log(`[poncho][browser] Restored ${state.cookies.length} cookies`);
935
+ const sanitized = state.cookies
936
+ .map(sanitizeCookieForCDP)
937
+ .filter((c): c is Record<string, unknown> => c !== null);
938
+ if (sanitized.length) {
939
+ try {
940
+ await cdp.send("Network.setCookies", { cookies: sanitized });
941
+ } catch {
942
+ let restored = 0;
943
+ for (const cookie of sanitized) {
944
+ try {
945
+ await cdp.send("Network.setCookies", { cookies: [cookie] });
946
+ restored++;
947
+ } catch { /* skip this cookie */ }
948
+ }
949
+ if (restored > 0) {
950
+ console.log(`[poncho][browser] Restored ${restored}/${sanitized.length} cookies (batch failed, fell back to individual)`);
951
+ } else {
952
+ console.warn("[poncho][browser] Could not restore any cookies");
953
+ }
954
+ return;
955
+ }
956
+ console.log(`[poncho][browser] Restored ${sanitized.length} cookies`);
957
+ }
901
958
  }
902
959
  if (state.origins?.length) {
903
960
  const entries: Record<string, Array<{ name: string; value: string }>> = {};
package/src/tools.ts CHANGED
@@ -1,11 +1,10 @@
1
- import type { ToolDefinition, FileContentPart } from "@poncho-ai/sdk";
1
+ import type { ToolContext, ToolDefinition, FileContentPart } from "@poncho-ai/sdk";
2
2
  import type { BrowserSession } from "./session.js";
3
3
 
4
4
  type BrowserToolInput = Record<string, unknown>;
5
5
 
6
6
  export function createBrowserTools(
7
7
  getSession: () => BrowserSession,
8
- getConversationId: () => string,
9
8
  ): ToolDefinition[] {
10
9
  return [
11
10
  {
@@ -22,9 +21,9 @@ export function createBrowserTools(
22
21
  },
23
22
  required: ["url"],
24
23
  },
25
- handler: async (input: BrowserToolInput) => {
24
+ handler: async (input: BrowserToolInput, context: ToolContext) => {
26
25
  const session = getSession();
27
- const cid = getConversationId();
26
+ const cid = context.conversationId ?? "__default__";
28
27
  const url = String(input.url ?? "");
29
28
  if (!url) throw new Error("url is required");
30
29
  const result = await session.open(cid, url);
@@ -44,9 +43,9 @@ export function createBrowserTools(
44
43
  type: "object",
45
44
  properties: {},
46
45
  },
47
- handler: async () => {
46
+ handler: async (_input: BrowserToolInput, context: ToolContext) => {
48
47
  const session = getSession();
49
- const snapshot = await session.snapshot(getConversationId());
48
+ const snapshot = await session.snapshot(context.conversationId ?? "__default__");
50
49
  return { snapshot };
51
50
  },
52
51
  },
@@ -65,11 +64,11 @@ export function createBrowserTools(
65
64
  },
66
65
  required: ["ref"],
67
66
  },
68
- handler: async (input: BrowserToolInput) => {
67
+ handler: async (input: BrowserToolInput, context: ToolContext) => {
69
68
  const session = getSession();
70
69
  const ref = String(input.ref ?? "");
71
70
  if (!ref) throw new Error("ref is required");
72
- await session.click(getConversationId(), ref);
71
+ await session.click(context.conversationId ?? "__default__", ref);
73
72
  return { clicked: ref };
74
73
  },
75
74
  },
@@ -94,12 +93,12 @@ export function createBrowserTools(
94
93
  },
95
94
  required: ["text"],
96
95
  },
97
- handler: async (input: BrowserToolInput) => {
96
+ handler: async (input: BrowserToolInput, context: ToolContext) => {
98
97
  const session = getSession();
99
98
  const text = String(input.text ?? "");
100
99
  if (!text) throw new Error("text is required");
101
100
  const exact = input.exact === true;
102
- await session.clickText(getConversationId(), text, exact);
101
+ await session.clickText(context.conversationId ?? "__default__", text, exact);
103
102
  return { clicked: text, exact };
104
103
  },
105
104
  },
@@ -121,11 +120,11 @@ export function createBrowserTools(
121
120
  },
122
121
  required: ["script"],
123
122
  },
124
- handler: async (input: BrowserToolInput) => {
123
+ handler: async (input: BrowserToolInput, context: ToolContext) => {
125
124
  const session = getSession();
126
125
  const script = String(input.script ?? "");
127
126
  if (!script) throw new Error("script is required");
128
- const result = await session.executeJs(getConversationId(), script);
127
+ const result = await session.executeJs(context.conversationId ?? "__default__", script);
129
128
  return { result: result ?? null };
130
129
  },
131
130
  },
@@ -148,12 +147,12 @@ export function createBrowserTools(
148
147
  },
149
148
  required: ["ref", "text"],
150
149
  },
151
- handler: async (input: BrowserToolInput) => {
150
+ handler: async (input: BrowserToolInput, context: ToolContext) => {
152
151
  const session = getSession();
153
152
  const ref = String(input.ref ?? "");
154
153
  const text = String(input.text ?? "");
155
154
  if (!ref) throw new Error("ref is required");
156
- await session.type(getConversationId(), ref, text);
155
+ await session.type(context.conversationId ?? "__default__", ref, text);
157
156
  return { typed: text, into: ref };
158
157
  },
159
158
  },
@@ -167,9 +166,9 @@ export function createBrowserTools(
167
166
  type: "object",
168
167
  properties: {},
169
168
  },
170
- handler: async () => {
169
+ handler: async (_input: BrowserToolInput, context: ToolContext) => {
171
170
  const session = getSession();
172
- const result = await session.content(getConversationId());
171
+ const result = await session.content(context.conversationId ?? "__default__");
173
172
  return { url: result.url, title: result.title, text: result.text };
174
173
  },
175
174
  },
@@ -182,9 +181,9 @@ export function createBrowserTools(
182
181
  type: "object",
183
182
  properties: {},
184
183
  },
185
- handler: async () => {
184
+ handler: async (_input: BrowserToolInput, context: ToolContext) => {
186
185
  const session = getSession();
187
- const base64 = await session.screenshot(getConversationId());
186
+ const base64 = await session.screenshot(context.conversationId ?? "__default__");
188
187
  const filePart: FileContentPart = {
189
188
  type: "file",
190
189
  data: base64,
@@ -213,11 +212,11 @@ export function createBrowserTools(
213
212
  },
214
213
  required: ["direction"],
215
214
  },
216
- handler: async (input: BrowserToolInput) => {
215
+ handler: async (input: BrowserToolInput, context: ToolContext) => {
217
216
  const session = getSession();
218
217
  const direction = String(input.direction ?? "down") as "up" | "down";
219
218
  const amount = typeof input.amount === "number" ? input.amount : undefined;
220
- await session.scroll(getConversationId(), direction, amount);
219
+ await session.scroll(context.conversationId ?? "__default__", direction, amount);
221
220
  return { scrolled: direction, amount: amount ?? "viewport" };
222
221
  },
223
222
  },
@@ -238,10 +237,10 @@ export function createBrowserTools(
238
237
  },
239
238
  },
240
239
  },
241
- handler: async (input: BrowserToolInput) => {
240
+ handler: async (input: BrowserToolInput, context: ToolContext) => {
242
241
  const session = getSession();
243
242
  const url = input.url ? String(input.url) : undefined;
244
- const { cleared } = await session.clearCookies(getConversationId(), url);
243
+ const { cleared } = await session.clearCookies(context.conversationId ?? "__default__", url);
245
244
  return { cleared, scope: url ?? "all" };
246
245
  },
247
246
  },
@@ -253,9 +252,9 @@ export function createBrowserTools(
253
252
  type: "object",
254
253
  properties: {},
255
254
  },
256
- handler: async () => {
255
+ handler: async (_input: BrowserToolInput, context: ToolContext) => {
257
256
  const session = getSession();
258
- await session.closeTab(getConversationId());
257
+ await session.closeTab(context.conversationId ?? "__default__");
259
258
  return { closed: true };
260
259
  },
261
260
  },