open-research 1.0.0 → 1.0.1
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/dist/chunk-3GZIDCV2.js +185 -0
- package/dist/{chunk-TQSQRNX6.js → chunk-3KZN54JZ.js} +23 -34
- package/dist/{chunk-I5NVYKG7.js → chunk-4HCPHCC2.js} +4 -0
- package/dist/chunk-77Q5B5H7.js +27 -0
- package/dist/chunk-GVEVKDGV.js +68 -0
- package/dist/{chunk-ZUSIRA5S.js → chunk-HRVDYJEC.js} +1 -1
- package/dist/cli.js +656 -204
- package/dist/gemini-login-EYY3EFH4.js +94 -0
- package/dist/{manager-queue-F4VVZMTE.js → manager-queue-FBAUCAGI.js} +4 -1
- package/dist/{query-agent-LRUUJR4F.js → query-agent-WM6UNZ37.js} +5 -2
- package/dist/{relevance-agent-CCN7JGTM.js → relevance-agent-H3U6TROD.js} +4 -1
- package/dist/{sessions-GRES2MUV.js → sessions-KL4LUGD7.js} +2 -2
- package/dist/{web-search-B7D5WMHU.js → web-search-TKBFSU3M.js} +4 -2
- package/package.json +1 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readJsonFile,
|
|
3
|
+
writeJsonFile
|
|
4
|
+
} from "./chunk-77Q5B5H7.js";
|
|
5
|
+
import {
|
|
6
|
+
getOpenResearchAuthFile,
|
|
7
|
+
getOpenResearchGeminiAuthFile,
|
|
8
|
+
getOpenResearchRoot
|
|
9
|
+
} from "./chunk-4HCPHCC2.js";
|
|
10
|
+
|
|
11
|
+
// src/lib/auth/store.ts
|
|
12
|
+
import fs from "fs/promises";
|
|
13
|
+
var AUTH_FILE_MODE = 384;
|
|
14
|
+
async function ensureCliHome(options) {
|
|
15
|
+
const root = getOpenResearchRoot(options);
|
|
16
|
+
await fs.mkdir(root, { recursive: true, mode: 448 });
|
|
17
|
+
return root;
|
|
18
|
+
}
|
|
19
|
+
async function saveStoredAuth(auth, options) {
|
|
20
|
+
await ensureCliHome(options);
|
|
21
|
+
const authFile = getOpenResearchAuthFile(options);
|
|
22
|
+
await writeJsonFile(authFile, auth, AUTH_FILE_MODE);
|
|
23
|
+
await fs.chmod(authFile, AUTH_FILE_MODE);
|
|
24
|
+
return authFile;
|
|
25
|
+
}
|
|
26
|
+
async function loadStoredAuth(options) {
|
|
27
|
+
const authFile = getOpenResearchAuthFile(options);
|
|
28
|
+
return readJsonFile(authFile, null);
|
|
29
|
+
}
|
|
30
|
+
async function clearStoredAuth(options) {
|
|
31
|
+
const authFile = getOpenResearchAuthFile(options);
|
|
32
|
+
await fs.rm(authFile, { force: true });
|
|
33
|
+
}
|
|
34
|
+
async function saveGeminiAuth(auth, options) {
|
|
35
|
+
await ensureCliHome(options);
|
|
36
|
+
const authFile = getOpenResearchGeminiAuthFile(options);
|
|
37
|
+
await writeJsonFile(authFile, auth, AUTH_FILE_MODE);
|
|
38
|
+
await fs.chmod(authFile, AUTH_FILE_MODE);
|
|
39
|
+
return authFile;
|
|
40
|
+
}
|
|
41
|
+
async function loadGeminiAuth(options) {
|
|
42
|
+
const authFile = getOpenResearchGeminiAuthFile(options);
|
|
43
|
+
return readJsonFile(authFile, null);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/lib/auth/gemini-oauth.ts
|
|
47
|
+
var GEMINI_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
48
|
+
var GEMINI_TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
49
|
+
var GEMINI_USERINFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo";
|
|
50
|
+
var GEMINI_CODE_ASSIST_URL = "https://cloudcode-pa.googleapis.com";
|
|
51
|
+
var GEMINI_CLIENT_ID = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com";
|
|
52
|
+
var GEMINI_CLIENT_SECRET = "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";
|
|
53
|
+
var GEMINI_SCOPES = "https://www.googleapis.com/auth/cloud-platform openid email profile";
|
|
54
|
+
function getGeminiRedirectUri(port) {
|
|
55
|
+
return `http://127.0.0.1:${port}/oauth2callback`;
|
|
56
|
+
}
|
|
57
|
+
function buildGeminiAuthorizationUrl(input) {
|
|
58
|
+
const params = new URLSearchParams({
|
|
59
|
+
client_id: GEMINI_CLIENT_ID,
|
|
60
|
+
response_type: "code",
|
|
61
|
+
redirect_uri: getGeminiRedirectUri(input.port),
|
|
62
|
+
scope: GEMINI_SCOPES,
|
|
63
|
+
state: input.state,
|
|
64
|
+
access_type: "offline",
|
|
65
|
+
prompt: "consent"
|
|
66
|
+
});
|
|
67
|
+
return `${GEMINI_AUTH_URL}?${params}`;
|
|
68
|
+
}
|
|
69
|
+
async function exchangeGeminiCodeForTokens(code, redirectUri) {
|
|
70
|
+
const response = await fetch(GEMINI_TOKEN_URL, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
73
|
+
body: new URLSearchParams({
|
|
74
|
+
client_id: GEMINI_CLIENT_ID,
|
|
75
|
+
client_secret: GEMINI_CLIENT_SECRET,
|
|
76
|
+
code,
|
|
77
|
+
grant_type: "authorization_code",
|
|
78
|
+
redirect_uri: redirectUri
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
if (!response.ok) {
|
|
82
|
+
const text = await response.text();
|
|
83
|
+
throw new Error(`Gemini token exchange failed: ${response.status} ${text}`);
|
|
84
|
+
}
|
|
85
|
+
return response.json();
|
|
86
|
+
}
|
|
87
|
+
async function refreshGeminiAccessToken(refreshToken) {
|
|
88
|
+
const response = await fetch(GEMINI_TOKEN_URL, {
|
|
89
|
+
method: "POST",
|
|
90
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
91
|
+
body: new URLSearchParams({
|
|
92
|
+
client_id: GEMINI_CLIENT_ID,
|
|
93
|
+
client_secret: GEMINI_CLIENT_SECRET,
|
|
94
|
+
refresh_token: refreshToken,
|
|
95
|
+
grant_type: "refresh_token"
|
|
96
|
+
})
|
|
97
|
+
});
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
const text = await response.text();
|
|
100
|
+
throw new Error(`Gemini token refresh failed: ${response.status} ${text}`);
|
|
101
|
+
}
|
|
102
|
+
return response.json();
|
|
103
|
+
}
|
|
104
|
+
async function getGeminiUserEmail(accessToken) {
|
|
105
|
+
const response = await fetch(`${GEMINI_USERINFO_URL}?alt=json`, {
|
|
106
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
107
|
+
});
|
|
108
|
+
if (!response.ok) return "unknown";
|
|
109
|
+
const data = await response.json();
|
|
110
|
+
return data.email ?? "unknown";
|
|
111
|
+
}
|
|
112
|
+
async function loadCodeAssistProject(accessToken) {
|
|
113
|
+
const response = await fetch(`${GEMINI_CODE_ASSIST_URL}/v1internal:loadCodeAssist`, {
|
|
114
|
+
method: "POST",
|
|
115
|
+
headers: {
|
|
116
|
+
Authorization: `Bearer ${accessToken}`,
|
|
117
|
+
"Content-Type": "application/json"
|
|
118
|
+
},
|
|
119
|
+
body: JSON.stringify({
|
|
120
|
+
metadata: {
|
|
121
|
+
ideType: "IDE_UNSPECIFIED",
|
|
122
|
+
platform: "PLATFORM_UNSPECIFIED",
|
|
123
|
+
pluginType: "GEMINI"
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
});
|
|
127
|
+
if (!response.ok) {
|
|
128
|
+
const text = await response.text();
|
|
129
|
+
throw new Error(`loadCodeAssist failed: ${response.status} ${text}`);
|
|
130
|
+
}
|
|
131
|
+
const data = await response.json();
|
|
132
|
+
const project = data.cloudaicompanionProject;
|
|
133
|
+
if (typeof project === "string") return project;
|
|
134
|
+
if (project && typeof project === "object" && "id" in project) return project.id;
|
|
135
|
+
if (data.allowedTiers?.length) {
|
|
136
|
+
return onboardUser(accessToken);
|
|
137
|
+
}
|
|
138
|
+
throw new Error("Could not determine Gemini project ID. You may need a Google AI subscription.");
|
|
139
|
+
}
|
|
140
|
+
async function onboardUser(accessToken) {
|
|
141
|
+
const response = await fetch(`${GEMINI_CODE_ASSIST_URL}/v1internal:onboardUser`, {
|
|
142
|
+
method: "POST",
|
|
143
|
+
headers: {
|
|
144
|
+
Authorization: `Bearer ${accessToken}`,
|
|
145
|
+
"Content-Type": "application/json"
|
|
146
|
+
},
|
|
147
|
+
body: JSON.stringify({})
|
|
148
|
+
});
|
|
149
|
+
if (!response.ok) {
|
|
150
|
+
throw new Error(`Gemini onboarding failed: ${response.status}`);
|
|
151
|
+
}
|
|
152
|
+
const data = await response.json();
|
|
153
|
+
if (data.done && data.response?.cloudaicompanionProject) {
|
|
154
|
+
return data.response.cloudaicompanionProject;
|
|
155
|
+
}
|
|
156
|
+
if (data.name) {
|
|
157
|
+
for (let i = 0; i < 10; i++) {
|
|
158
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
159
|
+
const poll = await fetch(`${GEMINI_CODE_ASSIST_URL}/v1internal/${data.name}`, {
|
|
160
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
161
|
+
});
|
|
162
|
+
if (!poll.ok) continue;
|
|
163
|
+
const result = await poll.json();
|
|
164
|
+
if (result.done && result.response?.cloudaicompanionProject) {
|
|
165
|
+
return result.response.cloudaicompanionProject;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
throw new Error("Gemini onboarding timed out. Try again.");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export {
|
|
173
|
+
saveStoredAuth,
|
|
174
|
+
loadStoredAuth,
|
|
175
|
+
clearStoredAuth,
|
|
176
|
+
saveGeminiAuth,
|
|
177
|
+
loadGeminiAuth,
|
|
178
|
+
GEMINI_CODE_ASSIST_URL,
|
|
179
|
+
getGeminiRedirectUri,
|
|
180
|
+
buildGeminiAuthorizationUrl,
|
|
181
|
+
exchangeGeminiCodeForTokens,
|
|
182
|
+
refreshGeminiAccessToken,
|
|
183
|
+
getGeminiUserEmail,
|
|
184
|
+
loadCodeAssistProject
|
|
185
|
+
};
|
|
@@ -1,38 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readJsonFile,
|
|
3
|
+
writeJsonFile
|
|
4
|
+
} from "./chunk-77Q5B5H7.js";
|
|
1
5
|
import {
|
|
2
6
|
getOpenResearchConfigFile
|
|
3
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-4HCPHCC2.js";
|
|
8
|
+
import {
|
|
9
|
+
getProviderCatalog
|
|
10
|
+
} from "./chunk-GVEVKDGV.js";
|
|
4
11
|
|
|
5
12
|
// src/lib/config/store.ts
|
|
6
13
|
import { z } from "zod";
|
|
7
|
-
|
|
8
|
-
// src/lib/fs/json.ts
|
|
9
|
-
import fs from "fs/promises";
|
|
10
|
-
import path from "path";
|
|
11
|
-
async function readJsonFile(filePath, fallback) {
|
|
12
|
-
try {
|
|
13
|
-
const raw = await fs.readFile(filePath, "utf8");
|
|
14
|
-
return JSON.parse(raw);
|
|
15
|
-
} catch (error) {
|
|
16
|
-
const code = typeof error === "object" && error && "code" in error ? String(error.code) : "";
|
|
17
|
-
if (code === "ENOENT") {
|
|
18
|
-
return fallback;
|
|
19
|
-
}
|
|
20
|
-
throw error;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
async function writeJsonFile(filePath, value, mode) {
|
|
24
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
25
|
-
await fs.writeFile(filePath, JSON.stringify(value, null, 2), {
|
|
26
|
-
encoding: "utf8",
|
|
27
|
-
mode
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// src/lib/config/store.ts
|
|
32
14
|
var themeValues = ["dark", "light"];
|
|
15
|
+
var providerValues = ["openai", "gemini"];
|
|
33
16
|
var openAIProviderConfigSchema = z.object({
|
|
34
17
|
apiKey: z.string().optional()
|
|
35
18
|
}).optional();
|
|
19
|
+
var geminiProviderConfigSchema = z.object({
|
|
20
|
+
apiKey: z.string().optional()
|
|
21
|
+
}).optional();
|
|
36
22
|
var openResearchConfigSchema = z.object({
|
|
37
23
|
version: z.literal(1),
|
|
38
24
|
defaults: z.object({
|
|
@@ -41,15 +27,18 @@ var openResearchConfigSchema = z.object({
|
|
|
41
27
|
editPolicy: z.literal("mixed")
|
|
42
28
|
}),
|
|
43
29
|
theme: z.enum(themeValues).default("dark"),
|
|
30
|
+
activeProvider: z.enum(providerValues).default("openai"),
|
|
44
31
|
lastWorkspace: z.string().nullable(),
|
|
45
32
|
providers: z.object({
|
|
46
|
-
openai: openAIProviderConfigSchema
|
|
33
|
+
openai: openAIProviderConfigSchema,
|
|
34
|
+
gemini: geminiProviderConfigSchema
|
|
47
35
|
}).optional(),
|
|
48
36
|
apiKeys: z.object({
|
|
49
37
|
openai: z.string().optional(),
|
|
50
38
|
semanticScholar: z.string().optional(),
|
|
51
39
|
openAlex: z.string().optional(),
|
|
52
|
-
brave: z.string().optional()
|
|
40
|
+
brave: z.string().optional(),
|
|
41
|
+
gemini: z.string().optional()
|
|
53
42
|
}).optional()
|
|
54
43
|
});
|
|
55
44
|
var DEFAULT_OPEN_RESEARCH_CONFIG = {
|
|
@@ -60,9 +49,11 @@ var DEFAULT_OPEN_RESEARCH_CONFIG = {
|
|
|
60
49
|
editPolicy: "mixed"
|
|
61
50
|
},
|
|
62
51
|
theme: "dark",
|
|
52
|
+
activeProvider: "openai",
|
|
63
53
|
lastWorkspace: null,
|
|
64
54
|
providers: {
|
|
65
|
-
openai: {}
|
|
55
|
+
openai: {},
|
|
56
|
+
gemini: {}
|
|
66
57
|
},
|
|
67
58
|
apiKeys: {}
|
|
68
59
|
};
|
|
@@ -235,10 +226,10 @@ async function executeFetchUrl(args, signal) {
|
|
|
235
226
|
}
|
|
236
227
|
|
|
237
228
|
// src/lib/fs/pdf.ts
|
|
238
|
-
import
|
|
229
|
+
import fs from "fs/promises";
|
|
239
230
|
async function extractPdfText(filePath, options) {
|
|
240
231
|
const pdfjs = await import("pdfjs-dist/legacy/build/pdf.mjs");
|
|
241
|
-
const buffer = await
|
|
232
|
+
const buffer = await fs.readFile(filePath);
|
|
242
233
|
const document = await pdfjs.getDocument({ data: new Uint8Array(buffer) }).promise;
|
|
243
234
|
const totalPages = document.numPages;
|
|
244
235
|
const start = Math.max(1, options?.startPage ?? 1);
|
|
@@ -433,7 +424,7 @@ async function extractWithTarget(input, provider) {
|
|
|
433
424
|
{ role: "system", content: systemPrompt },
|
|
434
425
|
{ role: "user", content: truncatedContent }
|
|
435
426
|
],
|
|
436
|
-
model:
|
|
427
|
+
model: getProviderCatalog(provider.kind).backgroundModel,
|
|
437
428
|
temperature: 0,
|
|
438
429
|
maxTokens: 1500,
|
|
439
430
|
jsonSchema: EXTRACTION_SCHEMA
|
|
@@ -496,8 +487,6 @@ function formatExtractionResults(sources) {
|
|
|
496
487
|
}
|
|
497
488
|
|
|
498
489
|
export {
|
|
499
|
-
readJsonFile,
|
|
500
|
-
writeJsonFile,
|
|
501
490
|
extractPdfText,
|
|
502
491
|
themeValues,
|
|
503
492
|
getConfiguredOpenAIApiKey,
|
|
@@ -10,6 +10,9 @@ function getOpenResearchRoot(options) {
|
|
|
10
10
|
function getOpenResearchAuthFile(options) {
|
|
11
11
|
return path.join(getOpenResearchRoot(options), "auth.json");
|
|
12
12
|
}
|
|
13
|
+
function getOpenResearchGeminiAuthFile(options) {
|
|
14
|
+
return path.join(getOpenResearchRoot(options), "gemini-auth.json");
|
|
15
|
+
}
|
|
13
16
|
function getOpenResearchConfigFile(options) {
|
|
14
17
|
return path.join(getOpenResearchRoot(options), "config.json");
|
|
15
18
|
}
|
|
@@ -29,6 +32,7 @@ function getWorkspaceSessionsDir(workspaceDir) {
|
|
|
29
32
|
export {
|
|
30
33
|
getOpenResearchRoot,
|
|
31
34
|
getOpenResearchAuthFile,
|
|
35
|
+
getOpenResearchGeminiAuthFile,
|
|
32
36
|
getOpenResearchConfigFile,
|
|
33
37
|
getOpenResearchSkillsDir,
|
|
34
38
|
getWorkspaceMetaDir,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/lib/fs/json.ts
|
|
2
|
+
import fs from "fs/promises";
|
|
3
|
+
import path from "path";
|
|
4
|
+
async function readJsonFile(filePath, fallback) {
|
|
5
|
+
try {
|
|
6
|
+
const raw = await fs.readFile(filePath, "utf8");
|
|
7
|
+
return JSON.parse(raw);
|
|
8
|
+
} catch (error) {
|
|
9
|
+
const code = typeof error === "object" && error && "code" in error ? String(error.code) : "";
|
|
10
|
+
if (code === "ENOENT") {
|
|
11
|
+
return fallback;
|
|
12
|
+
}
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function writeJsonFile(filePath, value, mode) {
|
|
17
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
18
|
+
await fs.writeFile(filePath, JSON.stringify(value, null, 2), {
|
|
19
|
+
encoding: "utf8",
|
|
20
|
+
mode
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
readJsonFile,
|
|
26
|
+
writeJsonFile
|
|
27
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// src/lib/llm/provider-catalog.ts
|
|
2
|
+
var OPENAI_PROVIDER_MODELS = [
|
|
3
|
+
"gpt-5.4",
|
|
4
|
+
"gpt-5.4-mini",
|
|
5
|
+
"o3",
|
|
6
|
+
"o4-mini"
|
|
7
|
+
];
|
|
8
|
+
var OPENAI_CATALOG = {
|
|
9
|
+
family: "openai",
|
|
10
|
+
displayName: "OpenAI",
|
|
11
|
+
models: OPENAI_PROVIDER_MODELS,
|
|
12
|
+
defaultModel: "gpt-5.4",
|
|
13
|
+
backgroundModel: "gpt-5.4-mini"
|
|
14
|
+
};
|
|
15
|
+
var GEMINI_PROVIDER_MODELS = [
|
|
16
|
+
"gemini-3.1-pro-preview",
|
|
17
|
+
"gemini-3-flash-preview"
|
|
18
|
+
];
|
|
19
|
+
var GEMINI_CATALOG = {
|
|
20
|
+
family: "gemini",
|
|
21
|
+
displayName: "Gemini",
|
|
22
|
+
models: GEMINI_PROVIDER_MODELS,
|
|
23
|
+
defaultModel: "gemini-3.1-pro-preview",
|
|
24
|
+
backgroundModel: "gemini-3-flash-preview"
|
|
25
|
+
};
|
|
26
|
+
function getProviderCatalog(providerKind) {
|
|
27
|
+
switch (providerKind) {
|
|
28
|
+
case "gemini_auth":
|
|
29
|
+
case "gemini_api_key":
|
|
30
|
+
return GEMINI_CATALOG;
|
|
31
|
+
case "openai_auth":
|
|
32
|
+
case "openai_api_key":
|
|
33
|
+
default:
|
|
34
|
+
return OPENAI_CATALOG;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function getAvailableModels(providerKind) {
|
|
38
|
+
return getProviderCatalog(providerKind).models;
|
|
39
|
+
}
|
|
40
|
+
function isSupportedModel(model, providerKind) {
|
|
41
|
+
if (!model) return false;
|
|
42
|
+
return getAvailableModels(providerKind).includes(model);
|
|
43
|
+
}
|
|
44
|
+
function getDefaultModel(providerKind) {
|
|
45
|
+
return getProviderCatalog(providerKind).defaultModel;
|
|
46
|
+
}
|
|
47
|
+
function selectModelForTask(providerKind, requestedModel, task) {
|
|
48
|
+
const catalog = getProviderCatalog(providerKind);
|
|
49
|
+
const selected = isSupportedModel(requestedModel, providerKind) ? requestedModel : catalog.defaultModel;
|
|
50
|
+
switch (task) {
|
|
51
|
+
case "conversation":
|
|
52
|
+
return selected;
|
|
53
|
+
case "compaction":
|
|
54
|
+
return selected.includes("5.4") || selected.includes("pro") ? catalog.backgroundModel : selected;
|
|
55
|
+
case "memory":
|
|
56
|
+
case "workspace":
|
|
57
|
+
return catalog.backgroundModel;
|
|
58
|
+
default:
|
|
59
|
+
return selected;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
getProviderCatalog,
|
|
65
|
+
getAvailableModels,
|
|
66
|
+
getDefaultModel,
|
|
67
|
+
selectModelForTask
|
|
68
|
+
};
|