Skip to content

Commit 06f86e9

Browse files
committed
Add Gemini computer use support (Fixes #148)
1 parent bef13de commit 06f86e9

File tree

14 files changed

+182
-0
lines changed

14 files changed

+182
-0
lines changed

packages/browseros/chromium_patches/chrome/browser/resources/settings/nxtscape_page/models_data.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ index 0000000000000..36638c1910a09
88
+export interface ModelInfo {
99
+ model_id: string;
1010
+ context_length: number;
11+
+ requires_computer_use?: boolean;
1112
+}
1213
+
1314
+export interface ModelsData {
@@ -66,6 +67,7 @@ index 0000000000000..36638c1910a09
6667
+ { model_id: 'gemini-2.5-pro-preview-05-06', context_length: 1048576 },
6768
+ { model_id: 'gemini-2.5-pro-preview-06-05', context_length: 1048576 },
6869
+ { model_id: 'gemini-2.5-pro', context_length: 1048576 },
70+
+ { model_id: 'gemini-2.5-computer-use-preview-10-2025', context_length: 1048576, requires_computer_use: true },
6971
+ { model_id: 'gemini-2.0-flash-exp', context_length: 1048576 },
7072
+ { model_id: 'gemini-2.0-flash', context_length: 1048576 },
7173
+ { model_id: 'gemini-2.0-flash-001', context_length: 1048576 },
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright 2024 The Chromium Authors
2+
# Use of this source code is governed by a BSD-style license that can be
3+
# found in the LICENSE file.
4+
5+
import("//ui/webui/resources/tools/generate_grd.gni")
6+
7+
generate_grd("build") {
8+
grd_prefix = "ai_side_panel"
9+
out_grd = "$target_gen_dir/resources.grd"
10+
11+
input_files = [
12+
"manifest.json",
13+
"background.js",
14+
"content.js",
15+
"sidepanel.html",
16+
"sidepanel.js",
17+
"options.html",
18+
"options.js",
19+
"Readability.js",
20+
"buildDomTree.js",
21+
"assets/icon16.png",
22+
"assets/icon48.png",
23+
"assets/icon128.png",
24+
]
25+
26+
input_files_base_dir = rebase_path(".", "//")
27+
}

packages/browseros/resources/files/ai_side_panel/Readability.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
1.76 KB
Loading
354 Bytes
Loading
695 Bytes
Loading

packages/browseros/resources/files/ai_side_panel/background.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
importScripts("computer_use_patch.js");
2+
importScripts("background.js");

packages/browseros/resources/files/ai_side_panel/buildDomTree.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
(() => {
2+
const existing = globalThis.fetch;
3+
if (!existing || existing.__browserosComputerUsePatched) return;
4+
5+
const originalFetch = existing.bind(globalThis);
6+
const computerUseModels = new Set(["gemini-2.5-computer-use-preview-10-2025"]);
7+
8+
const normalizePayload = (payload) => {
9+
if (!payload || typeof payload !== "object") return null;
10+
if (!computerUseModels.has(payload.model)) return null;
11+
12+
const tools = Array.isArray(payload.tools) ? payload.tools.slice() : [];
13+
const hasTool = tools.some((tool) => tool && typeof tool === "object" && "computer_use" in tool);
14+
15+
if (!hasTool) {
16+
tools.push({ computer_use: { environment: "ENVIRONMENT_BROWSER" } });
17+
payload.tools = tools;
18+
return payload;
19+
}
20+
21+
return payload;
22+
};
23+
24+
const updateInit = (init) => {
25+
if (!init || typeof init !== "object") return null;
26+
if (!init.body) return null;
27+
28+
if (typeof init.body === "string") {
29+
try {
30+
const payload = JSON.parse(init.body);
31+
const updated = normalizePayload(payload);
32+
if (updated) {
33+
return { ...init, body: JSON.stringify(updated) };
34+
}
35+
} catch {
36+
return null;
37+
}
38+
} else if (typeof init.body === "object") {
39+
const updated = normalizePayload(init.body);
40+
if (updated) {
41+
return { ...init, body: JSON.stringify(updated) };
42+
}
43+
}
44+
45+
return null;
46+
};
47+
48+
const wrappedFetch = (...args) => {
49+
const [input, init] = args;
50+
const nextInit = updateInit(init);
51+
52+
if (nextInit) {
53+
return originalFetch(input, nextInit);
54+
}
55+
56+
return originalFetch(...args);
57+
};
58+
59+
wrappedFetch.__browserosComputerUsePatched = true;
60+
globalThis.fetch = wrappedFetch;
61+
})();

0 commit comments

Comments
 (0)