Skip to content

Commit cbfff99

Browse files
committed
Implement hybrid top-N analyze_papes
1 parent 9c81764 commit cbfff99

52 files changed

Lines changed: 4170 additions & 189 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
# Optional: AutoResearch setup can write this for you on first run.
22
SEMANTIC_SCHOLAR_API_KEY=
3+
# Required if the primary provider is OpenAI API or PDF analysis mode is set to Responses API.
4+
OPENAI_API_KEY=

README.ko.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ npm link
1313
autoresearch
1414
```
1515

16-
선택 사항: Semantic Scholar API key를 `.env`에 넣을 수 있습니다.
16+
필수: Semantic Scholar API key를 `.env`에 넣어야 합니다. (또는 첫 실행 setup wizard에서 입력)
17+
선택: 기본 provider를 `OpenAI API`로 선택하거나 PDF 분석을 `Responses API`로 설정할 경우 `OPENAI_API_KEY`도 필요합니다.
1718

1819
```bash
1920
cp .env.example .env
2021
echo 'SEMANTIC_SCHOLAR_API_KEY=your_key_here' >> .env
22+
echo 'OPENAI_API_KEY=your_openai_key_here' >> .env
2123
```
2224

2325
개발 모드:
@@ -33,8 +35,21 @@ npm run dev
3335
1. 빈 프로젝트에서 `autoresearch`를 실행합니다.
3436
2. `.autoresearch/config.yaml`이 없으면 setup wizard가 자동 시작됩니다.
3537
3. wizard가 설정/스캐폴드를 만든 뒤 대시보드로 진입합니다.
36-
4. setup wizard는 선택적으로 Semantic Scholar API key를 묻고, 입력한 값은 `.env`에 기록합니다.
37-
5. 실행 시 AutoResearch는 `process.env` 또는 `.env``SEMANTIC_SCHOLAR_API_KEY`를 읽습니다.
38+
4. setup wizard는 Semantic Scholar API key를 필수로 묻고, 입력한 값은 `.env`에 기록합니다.
39+
5. setup wizard에서 기본 LLM provider를 선택합니다.
40+
- `codex`: 메인 워크플로를 Codex ChatGPT 로그인으로 실행
41+
- `api`: 메인 워크플로를 OpenAI API 모델로 실행 (`OPENAI_API_KEY` 필요)
42+
6. setup wizard에서 PDF 분석 모드도 선택합니다.
43+
- `codex`: PDF를 로컬에서 텍스트 추출 후 Codex로 분석
44+
- `api`: PDF를 Responses API로 직접 전달해 분석 (`OPENAI_API_KEY` 필요)
45+
7. 기본 provider로 `api`를 선택하면 setup wizard와 `/settings`에서 OpenAI API 모델도 선택할 수 있습니다.
46+
- 현재 카탈로그: `gpt-5.4`, `gpt-5`, `gpt-5-mini`, `gpt-4.1`, `gpt-4o`, `gpt-4o-mini`
47+
8. PDF 분석에서 `api`를 선택하면 setup wizard와 `/settings`에서 Responses API PDF 모델도 선택할 수 있습니다.
48+
- 현재 카탈로그: `gpt-5.4`, `gpt-5`, `gpt-5-mini`, `gpt-4.1`, `gpt-4o`, `gpt-4o-mini`
49+
9. `/model`은 현재 기본 provider를 따릅니다.
50+
- Codex provider: Codex 모델 선택기
51+
- OpenAI API provider: OpenAI API 모델 선택기
52+
10. 실행 시 AutoResearch는 `process.env` 또는 `.env``SEMANTIC_SCHOLAR_API_KEY`, `OPENAI_API_KEY`를 읽습니다.
3853

3954
## CLI 정책
4055

README.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ npm link
1313
autoresearch
1414
```
1515

16-
Optional: set your Semantic Scholar API key in `.env`.
16+
Required: set your Semantic Scholar API key in `.env` (or enter it during first-run setup).
17+
Optional: if you choose `OpenAI API` as the primary provider or `Responses API PDF analysis`, also set `OPENAI_API_KEY`.
1718

1819
```bash
1920
cp .env.example .env
2021
echo 'SEMANTIC_SCHOLAR_API_KEY=your_key_here' >> .env
22+
echo 'OPENAI_API_KEY=your_openai_key_here' >> .env
2123
```
2224

2325
Development mode:
@@ -33,8 +35,21 @@ Without `npm link`, you can still run `node dist/cli/main.js`.
3335
1. Run `autoresearch` in an empty project.
3436
2. If `.autoresearch/config.yaml` is missing, setup wizard starts automatically.
3537
3. Wizard creates scaffold/config and opens the dashboard.
36-
4. Setup wizard asks for an optional Semantic Scholar API key and writes it to `.env`.
37-
5. At runtime, AutoResearch reads `SEMANTIC_SCHOLAR_API_KEY` from `process.env` or `.env`.
38+
4. Setup wizard requires a Semantic Scholar API key and writes it to `.env`.
39+
5. Setup wizard lets you choose the primary LLM provider:
40+
- `codex`: use Codex ChatGPT login for the main workflow
41+
- `api`: use OpenAI API models for the main workflow (`OPENAI_API_KEY` required)
42+
6. Setup wizard also lets you choose PDF analysis mode:
43+
- `codex`: download/extract PDF text locally, then analyze with Codex
44+
- `api`: send the PDF directly to the Responses API (requires `OPENAI_API_KEY`)
45+
7. If you choose `api` as the primary provider, setup wizard and `/settings` also let you choose the OpenAI API model.
46+
- Current catalog: `gpt-5.4`, `gpt-5`, `gpt-5-mini`, `gpt-4.1`, `gpt-4o`, `gpt-4o-mini`
47+
8. If you choose `api` for PDF analysis, setup wizard and `/settings` also let you choose the Responses API PDF model.
48+
- Current catalog: `gpt-5.4`, `gpt-5`, `gpt-5-mini`, `gpt-4.1`, `gpt-4o`, `gpt-4o-mini`
49+
9. `/model` follows the active primary provider:
50+
- Codex provider: Codex model selector
51+
- OpenAI API provider: OpenAI API model selector
52+
10. At runtime, AutoResearch reads `SEMANTIC_SCHOLAR_API_KEY` and `OPENAI_API_KEY` from `process.env` or `.env`.
3853

3954
## CLI Policy
4055

src/app.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
ensureScaffold,
44
hasSemanticScholarApiKey,
55
loadConfig,
6+
resolveOpenAiApiKey,
67
resolveAppPaths,
78
resolveSemanticScholarApiKey,
89
runSetupWizard,
@@ -14,19 +15,19 @@ import { CodexCliClient } from "./integrations/codex/codexCliClient.js";
1415
import { AgentOrchestrator } from "./core/agents/agentOrchestrator.js";
1516
import { launchTerminalApp } from "./tui/TerminalApp.js";
1617
import { InMemoryEventStream } from "./core/events.js";
17-
import { CodexLLMClient } from "./core/llm/client.js";
18+
import { CodexLLMClient, OpenAiResponsesLLMClient, RoutedLLMClient } from "./core/llm/client.js";
1819
import { LocalAciAdapter } from "./tools/aciLocalAdapter.js";
1920
import { SemanticScholarClient } from "./tools/semanticScholar.js";
2021
import { DefaultNodeRegistry } from "./core/stateGraph/nodeRegistry.js";
2122
import { CheckpointStore } from "./core/stateGraph/checkpointStore.js";
2223
import { StateGraphRuntime } from "./core/stateGraph/runtime.js";
2324
import { askLine } from "./utils/prompt.js";
2425
import { AppConfig } from "./types.js";
26+
import { ResponsesPdfAnalysisClient } from "./integrations/openai/responsesPdfAnalysisClient.js";
27+
import { OpenAiResponsesTextClient } from "./integrations/openai/responsesTextClient.js";
2528

2629
export async function runAutoresearchApp(): Promise<void> {
2730
const paths = resolveAppPaths(process.cwd());
28-
await ensureScaffold(paths);
29-
3031
const firstRunSetup = !(await configExists(paths));
3132
let config;
3233
if (firstRunSetup) {
@@ -36,14 +37,21 @@ export async function runAutoresearchApp(): Promise<void> {
3637
} else {
3738
config = await loadConfig(paths);
3839
}
40+
await ensureScaffold(paths);
3941

4042
const runStore = new RunStore(paths);
4143
const codex = new CodexCliClient(paths.cwd, {
4244
model: config.providers.codex.model || "gpt-5.3-codex",
4345
reasoningEffort: config.providers.codex.reasoning_effort || "xhigh",
4446
fastMode: config.providers.codex.fast_mode === true
4547
});
46-
const titleGenerator = new TitleGenerator(codex);
48+
const openAiText = new OpenAiResponsesTextClient(() => resolveOpenAiApiKey(paths.cwd), {
49+
model: config.providers.openai.model,
50+
reasoningEffort: config.providers.openai.reasoning_effort
51+
});
52+
const titleGenerator = new TitleGenerator(() =>
53+
config.providers.llm_mode === "openai_api" ? openAiText : codex
54+
);
4755
const initialRunId = await maybeCreateInitialRun({
4856
firstRunSetup,
4957
runStore,
@@ -52,14 +60,19 @@ export async function runAutoresearchApp(): Promise<void> {
5260
});
5361

5462
const eventStream = new InMemoryEventStream();
55-
const llm = new CodexLLMClient(codex);
63+
const codexLlm = new CodexLLMClient(codex);
64+
const openAiLlm = new OpenAiResponsesLLMClient(openAiText);
65+
const llm = new RoutedLLMClient(() =>
66+
config.providers.llm_mode === "openai_api" ? openAiLlm : codexLlm
67+
);
5668
const aci = new LocalAciAdapter();
5769
const semanticScholarApiKey = await resolveSemanticScholarApiKey(paths.cwd);
5870
const semanticScholar = new SemanticScholarClient({
5971
apiKey: semanticScholarApiKey,
6072
perSecondLimit: config.papers.per_second_limit,
6173
maxRetries: 3
6274
});
75+
const responsesPdfAnalysis = new ResponsesPdfAnalysisClient(() => resolveOpenAiApiKey(paths.cwd));
6376

6477
const nodeRegistry = new DefaultNodeRegistry({
6578
config,
@@ -68,7 +81,8 @@ export async function runAutoresearchApp(): Promise<void> {
6881
llm,
6982
codex,
7083
aci,
71-
semanticScholar
84+
semanticScholar,
85+
responsesPdfAnalysis
7286
});
7387

7488
const checkpointStore = new CheckpointStore(paths);
@@ -80,6 +94,7 @@ export async function runAutoresearchApp(): Promise<void> {
8094
runStore,
8195
titleGenerator,
8296
codex,
97+
openAiTextClient: openAiText,
8398
eventStream,
8499
orchestrator,
85100
initialRunId,

0 commit comments

Comments
 (0)