@poncho-ai/browser 0.6.2 → 0.6.4
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.
- package/.turbo/turbo-build.log +5 -5
- package/.turbo/turbo-test.log +12 -0
- package/CHANGELOG.md +14 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +121 -2
- package/package.json +1 -1
- package/src/session.ts +128 -3
- package/src/tools.ts +24 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @poncho-ai/browser@0.6.
|
|
2
|
+
> @poncho-ai/browser@0.6.4 build /Users/cesar/Dev/latitude/poncho-ai/packages/browser
|
|
3
3
|
> tsup src/index.ts --format esm --dts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
[34mCLI[39m tsup v8.5.1
|
|
8
8
|
[34mCLI[39m Target: es2022
|
|
9
9
|
[34mESM[39m Build start
|
|
10
|
-
[32mESM[39m [1mdist/index.js [22m[
|
|
11
|
-
[32mESM[39m ⚡️ Build success in
|
|
10
|
+
[32mESM[39m [1mdist/index.js [22m[32m45.65 KB[39m
|
|
11
|
+
[32mESM[39m ⚡️ Build success in 112ms
|
|
12
12
|
[34mDTS[39m Build start
|
|
13
|
-
[32mDTS[39m ⚡️ Build success in
|
|
14
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m13.
|
|
13
|
+
[32mDTS[39m ⚡️ Build success in 1828ms
|
|
14
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m13.72 KB[39m
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
> @poncho-ai/browser@0.6.2 test /Users/cesar/Dev/latitude/poncho-ai/packages/browser
|
|
3
|
+
> vitest --passWithNoTests
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[7m[1m[36m RUN [39m[22m[27m [36mv1.6.1[39m [90m/Users/cesar/Dev/latitude/poncho-ai/packages/browser[39m
|
|
7
|
+
|
|
8
|
+
No test files found, exiting with code 0
|
|
9
|
+
[2minclude: [22m[33m**/*.{test,spec}.?(c|m)[jt]s?(x)[39m
|
|
10
|
+
|
|
11
|
+
[2mexclude: [22m[33m**/node_modules/**[2m, [22m**/dist/**[2m, [22m**/cypress/**[2m, [22m**/.{idea,git,cache,output,temp}/**[2m, [22m**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*[39m
|
|
12
|
+
[2mwatch exclude: [22m[33m**/node_modules/**[2m, [22m**/dist/**[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @poncho-ai/browser
|
|
2
2
|
|
|
3
|
+
## 0.6.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`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.
|
|
8
|
+
|
|
9
|
+
## 0.6.3
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [`35f3f54`](https://github.com/cesr/poncho-ai/commit/35f3f54b17ff50253ab01dbcfe19c643dd6c7e00) Thanks [@cesr](https://github.com/cesr)! - Add `browser_clear_cookies` tool for deleting browser cookies
|
|
14
|
+
|
|
15
|
+
Agents with `browser: true` can now call `browser_clear_cookies` to delete cookies from the live browser and persisted storage. Accepts an optional `url` parameter to scope deletion to a specific site (e.g. "https://example.com"); omit to clear all cookies.
|
|
16
|
+
|
|
3
17
|
## 0.6.2
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -147,6 +147,9 @@ declare class BrowserSession {
|
|
|
147
147
|
executeJs(conversationId: string, script: string): Promise<unknown>;
|
|
148
148
|
closeTab(conversationId: string): Promise<void>;
|
|
149
149
|
navigate(conversationId: string, action: string): Promise<void>;
|
|
150
|
+
clearCookies(conversationId: string, url?: string): Promise<{
|
|
151
|
+
cleared: number;
|
|
152
|
+
}>;
|
|
150
153
|
startScreencast(conversationId: string, options?: ScreencastOptions): Promise<void>;
|
|
151
154
|
stopScreencast(): Promise<void>;
|
|
152
155
|
onFrame(conversationId: string, listener: FrameListener): () => void;
|
|
@@ -158,6 +161,7 @@ declare class BrowserSession {
|
|
|
158
161
|
saveState(storagePath: string): Promise<void>;
|
|
159
162
|
private persistStorageState;
|
|
160
163
|
private restoreStorageState;
|
|
164
|
+
private clearPersistedCookies;
|
|
161
165
|
close(): Promise<void>;
|
|
162
166
|
private emitStatus;
|
|
163
167
|
}
|
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
|
|
@@ -739,6 +757,34 @@ var BrowserSession = class {
|
|
|
739
757
|
this.unlock();
|
|
740
758
|
}
|
|
741
759
|
}
|
|
760
|
+
async clearCookies(conversationId, url) {
|
|
761
|
+
await this.lock();
|
|
762
|
+
try {
|
|
763
|
+
const mgr = await this.ensureManager();
|
|
764
|
+
await this.switchToConversation(mgr, conversationId);
|
|
765
|
+
const cdp = await mgr.getCDPSession();
|
|
766
|
+
let cleared = 0;
|
|
767
|
+
if (url) {
|
|
768
|
+
const { cookies } = await cdp.send("Network.getCookies", { urls: [url] });
|
|
769
|
+
cleared = cookies.length;
|
|
770
|
+
for (const cookie of cookies) {
|
|
771
|
+
await cdp.send("Network.deleteCookies", {
|
|
772
|
+
name: cookie.name,
|
|
773
|
+
domain: cookie.domain,
|
|
774
|
+
path: cookie.path
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
} else {
|
|
778
|
+
const { cookies } = await cdp.send("Network.getCookies");
|
|
779
|
+
cleared = cookies.length;
|
|
780
|
+
await cdp.send("Network.clearBrowserCookies");
|
|
781
|
+
}
|
|
782
|
+
await this.clearPersistedCookies(url);
|
|
783
|
+
return { cleared };
|
|
784
|
+
} finally {
|
|
785
|
+
this.unlock();
|
|
786
|
+
}
|
|
787
|
+
}
|
|
742
788
|
// -----------------------------------------------------------------------
|
|
743
789
|
// Screencast (one active at a time, tied to the viewed conversation)
|
|
744
790
|
// -----------------------------------------------------------------------
|
|
@@ -808,6 +854,10 @@ var BrowserSession = class {
|
|
|
808
854
|
tab.frameListeners.add(listener);
|
|
809
855
|
return () => {
|
|
810
856
|
tab.frameListeners.delete(listener);
|
|
857
|
+
if (tab.frameListeners.size === 0 && this._screencastConversation === conversationId) {
|
|
858
|
+
this.stopScreencast().catch(() => {
|
|
859
|
+
});
|
|
860
|
+
}
|
|
811
861
|
};
|
|
812
862
|
}
|
|
813
863
|
onStatus(conversationId, listener) {
|
|
@@ -913,8 +963,28 @@ var BrowserSession = class {
|
|
|
913
963
|
if (!json) return;
|
|
914
964
|
const state = JSON.parse(json);
|
|
915
965
|
if (state.cookies?.length) {
|
|
916
|
-
|
|
917
|
-
|
|
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
|
+
}
|
|
918
988
|
}
|
|
919
989
|
if (state.origins?.length) {
|
|
920
990
|
const entries = {};
|
|
@@ -933,6 +1003,36 @@ var BrowserSession = class {
|
|
|
933
1003
|
console.warn("[poncho][browser] Failed to restore storage state:", err?.message ?? err);
|
|
934
1004
|
}
|
|
935
1005
|
}
|
|
1006
|
+
async clearPersistedCookies(url) {
|
|
1007
|
+
const persistence = this.config.storagePersistence;
|
|
1008
|
+
if (!persistence) return;
|
|
1009
|
+
try {
|
|
1010
|
+
const json = await persistence.load();
|
|
1011
|
+
if (!json) return;
|
|
1012
|
+
const state = JSON.parse(json);
|
|
1013
|
+
if (!state.cookies?.length) return;
|
|
1014
|
+
if (url) {
|
|
1015
|
+
let host;
|
|
1016
|
+
try {
|
|
1017
|
+
host = new URL(url).hostname.toLowerCase();
|
|
1018
|
+
} catch {
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
state.cookies = state.cookies.filter((c) => {
|
|
1022
|
+
const raw = String(c.domain ?? "").toLowerCase();
|
|
1023
|
+
const bare = raw.replace(/^\./, "");
|
|
1024
|
+
if (host === bare) return false;
|
|
1025
|
+
if (raw.startsWith(".") && host.endsWith("." + bare)) return false;
|
|
1026
|
+
return true;
|
|
1027
|
+
});
|
|
1028
|
+
} else {
|
|
1029
|
+
state.cookies = [];
|
|
1030
|
+
}
|
|
1031
|
+
await persistence.save(JSON.stringify(state));
|
|
1032
|
+
} catch (err) {
|
|
1033
|
+
console.warn("[poncho][browser] Failed to clear persisted cookies:", err?.message ?? err);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
936
1036
|
async close() {
|
|
937
1037
|
try {
|
|
938
1038
|
await this.stopScreencast();
|
|
@@ -1167,6 +1267,25 @@ function createBrowserTools(getSession, getConversationId) {
|
|
|
1167
1267
|
return { scrolled: direction, amount: amount ?? "viewport" };
|
|
1168
1268
|
}
|
|
1169
1269
|
},
|
|
1270
|
+
{
|
|
1271
|
+
name: "browser_clear_cookies",
|
|
1272
|
+
description: `Delete browser cookies. By default clears all cookies. Pass a url to only delete cookies that would be sent to that URL (e.g. "https://example.com" removes cookies for example.com and its subdomains). Also removes them from persisted storage so they won't be restored on next launch.`,
|
|
1273
|
+
inputSchema: {
|
|
1274
|
+
type: "object",
|
|
1275
|
+
properties: {
|
|
1276
|
+
url: {
|
|
1277
|
+
type: "string",
|
|
1278
|
+
description: 'Optional URL to scope deletion to (e.g. "https://example.com"). Omit to clear all cookies.'
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
},
|
|
1282
|
+
handler: async (input) => {
|
|
1283
|
+
const session = getSession();
|
|
1284
|
+
const url = input.url ? String(input.url) : void 0;
|
|
1285
|
+
const { cleared } = await session.clearCookies(getConversationId(), url);
|
|
1286
|
+
return { cleared, scope: url ?? "all" };
|
|
1287
|
+
}
|
|
1288
|
+
},
|
|
1170
1289
|
{
|
|
1171
1290
|
name: "browser_close",
|
|
1172
1291
|
description: "Close the browser tab for this conversation. Call this when you're done with browser tasks to free resources.",
|
package/package.json
CHANGED
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.
|
|
@@ -676,6 +707,42 @@ export class BrowserSession {
|
|
|
676
707
|
}
|
|
677
708
|
}
|
|
678
709
|
|
|
710
|
+
async clearCookies(conversationId: string, url?: string): Promise<{ cleared: number }> {
|
|
711
|
+
await this.lock();
|
|
712
|
+
try {
|
|
713
|
+
const mgr = await this.ensureManager();
|
|
714
|
+
await this.switchToConversation(mgr, conversationId);
|
|
715
|
+
const cdp = await mgr.getCDPSession();
|
|
716
|
+
|
|
717
|
+
let cleared = 0;
|
|
718
|
+
|
|
719
|
+
if (url) {
|
|
720
|
+
const { cookies } = (await cdp.send("Network.getCookies", { urls: [url] })) as {
|
|
721
|
+
cookies: Array<{ name: string; domain: string; path: string }>;
|
|
722
|
+
};
|
|
723
|
+
cleared = cookies.length;
|
|
724
|
+
for (const cookie of cookies) {
|
|
725
|
+
await cdp.send("Network.deleteCookies", {
|
|
726
|
+
name: cookie.name,
|
|
727
|
+
domain: cookie.domain,
|
|
728
|
+
path: cookie.path,
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
} else {
|
|
732
|
+
const { cookies } = (await cdp.send("Network.getCookies")) as {
|
|
733
|
+
cookies: Array<unknown>;
|
|
734
|
+
};
|
|
735
|
+
cleared = cookies.length;
|
|
736
|
+
await cdp.send("Network.clearBrowserCookies");
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
await this.clearPersistedCookies(url);
|
|
740
|
+
return { cleared };
|
|
741
|
+
} finally {
|
|
742
|
+
this.unlock();
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
679
746
|
// -----------------------------------------------------------------------
|
|
680
747
|
// Screencast (one active at a time, tied to the viewed conversation)
|
|
681
748
|
// -----------------------------------------------------------------------
|
|
@@ -743,7 +810,12 @@ export class BrowserSession {
|
|
|
743
810
|
this.tabs.set(conversationId, tab);
|
|
744
811
|
}
|
|
745
812
|
tab.frameListeners.add(listener);
|
|
746
|
-
return () => {
|
|
813
|
+
return () => {
|
|
814
|
+
tab!.frameListeners.delete(listener);
|
|
815
|
+
if (tab!.frameListeners.size === 0 && this._screencastConversation === conversationId) {
|
|
816
|
+
this.stopScreencast().catch(() => {});
|
|
817
|
+
}
|
|
818
|
+
};
|
|
747
819
|
}
|
|
748
820
|
|
|
749
821
|
onStatus(conversationId: string, listener: StatusListener): () => void {
|
|
@@ -860,8 +932,29 @@ export class BrowserSession {
|
|
|
860
932
|
origins?: Array<{ origin: string; localStorage: Array<{ name: string; value: string }> }>;
|
|
861
933
|
};
|
|
862
934
|
if (state.cookies?.length) {
|
|
863
|
-
|
|
864
|
-
|
|
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
|
+
}
|
|
865
958
|
}
|
|
866
959
|
if (state.origins?.length) {
|
|
867
960
|
const entries: Record<string, Array<{ name: string; value: string }>> = {};
|
|
@@ -881,6 +974,38 @@ export class BrowserSession {
|
|
|
881
974
|
}
|
|
882
975
|
}
|
|
883
976
|
|
|
977
|
+
private async clearPersistedCookies(url?: string): Promise<void> {
|
|
978
|
+
const persistence = this.config.storagePersistence;
|
|
979
|
+
if (!persistence) return;
|
|
980
|
+
try {
|
|
981
|
+
const json = await persistence.load();
|
|
982
|
+
if (!json) return;
|
|
983
|
+
const state = JSON.parse(json) as {
|
|
984
|
+
cookies?: Array<Record<string, unknown>>;
|
|
985
|
+
origins?: Array<{ origin: string; localStorage: Array<{ name: string; value: string }> }>;
|
|
986
|
+
};
|
|
987
|
+
if (!state.cookies?.length) return;
|
|
988
|
+
|
|
989
|
+
if (url) {
|
|
990
|
+
let host: string;
|
|
991
|
+
try { host = new URL(url).hostname.toLowerCase(); } catch { return; }
|
|
992
|
+
state.cookies = state.cookies.filter((c) => {
|
|
993
|
+
const raw = String(c.domain ?? "").toLowerCase();
|
|
994
|
+
const bare = raw.replace(/^\./, "");
|
|
995
|
+
if (host === bare) return false;
|
|
996
|
+
if (raw.startsWith(".") && host.endsWith("." + bare)) return false;
|
|
997
|
+
return true;
|
|
998
|
+
});
|
|
999
|
+
} else {
|
|
1000
|
+
state.cookies = [];
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
await persistence.save(JSON.stringify(state));
|
|
1004
|
+
} catch (err) {
|
|
1005
|
+
console.warn("[poncho][browser] Failed to clear persisted cookies:", (err as Error)?.message ?? err);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
884
1009
|
async close(): Promise<void> {
|
|
885
1010
|
try { await this.stopScreencast(); } catch { /* */ }
|
|
886
1011
|
await this.persistStorageState();
|
package/src/tools.ts
CHANGED
|
@@ -221,6 +221,30 @@ export function createBrowserTools(
|
|
|
221
221
|
return { scrolled: direction, amount: amount ?? "viewport" };
|
|
222
222
|
},
|
|
223
223
|
},
|
|
224
|
+
{
|
|
225
|
+
name: "browser_clear_cookies",
|
|
226
|
+
description:
|
|
227
|
+
"Delete browser cookies. By default clears all cookies. " +
|
|
228
|
+
"Pass a url to only delete cookies that would be sent to that URL " +
|
|
229
|
+
"(e.g. \"https://example.com\" removes cookies for example.com and its subdomains). " +
|
|
230
|
+
"Also removes them from persisted storage so they won't be restored on next launch.",
|
|
231
|
+
inputSchema: {
|
|
232
|
+
type: "object",
|
|
233
|
+
properties: {
|
|
234
|
+
url: {
|
|
235
|
+
type: "string",
|
|
236
|
+
description:
|
|
237
|
+
"Optional URL to scope deletion to (e.g. \"https://example.com\"). Omit to clear all cookies.",
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
handler: async (input: BrowserToolInput) => {
|
|
242
|
+
const session = getSession();
|
|
243
|
+
const url = input.url ? String(input.url) : undefined;
|
|
244
|
+
const { cleared } = await session.clearCookies(getConversationId(), url);
|
|
245
|
+
return { cleared, scope: url ?? "all" };
|
|
246
|
+
},
|
|
247
|
+
},
|
|
224
248
|
{
|
|
225
249
|
name: "browser_close",
|
|
226
250
|
description:
|