164 lines
6.9 KiB
Markdown
164 lines
6.9 KiB
Markdown
|
|
## Research Inputs
|
|||
|
|
|
|||
|
|
N/A。這是個人工具,不需要市場研究。
|
|||
|
|
|
|||
|
|
## Problem
|
|||
|
|
|
|||
|
|
我同時使用多個 CLI AI 工具(Hermes Agent、OpenCode、Claude Code),這些工具都支援自訂 API base URL 和 model。我的公司有 Cursor 帳號,透過 `agent login` 已在本機完成認證,可以使用 Cursor 提供的多種模型。
|
|||
|
|
|
|||
|
|
目前的問題是:每支 CLI 工具都需要自己買 API key 或設定 provider,但我已經有 Cursor 帳號的額度可以用。我需要一個轉接器,讓這些 CLI 工具能透過 Cursor CLI 的 headless 模式來使用 Cursor 的模型,省去額外的 API 費用。
|
|||
|
|
|
|||
|
|
## Goals
|
|||
|
|
|
|||
|
|
- 本機跑一個 HTTP server,提供 OpenAI-compatible API(`/v1/chat/completions`)
|
|||
|
|
- 收到請求後,spawn Cursor CLI 的 `agent` 子程序來執行
|
|||
|
|
- 將 Cursor CLI 的 streaming JSON 輸出轉換成 OpenAI SSE 格式回傳
|
|||
|
|
- 支援多種 Cursor 模型的選擇
|
|||
|
|
- 零額外認證設定 — 直接使用本機已有的 Cursor 登入狀態
|
|||
|
|
|
|||
|
|
## Non Goals
|
|||
|
|
|
|||
|
|
- 不支援非 OpenAI format 的 CLI 工具
|
|||
|
|
- 不做 API key 管理或多用戶認證
|
|||
|
|
- 不做計量、追蹤、計費功能
|
|||
|
|
- 不做模型負載平衡或 failover
|
|||
|
|
- 不代理 Cursor IDE 的功能,只代理 headless CLI 模式
|
|||
|
|
|
|||
|
|
## Scope
|
|||
|
|
|
|||
|
|
本機 personal proxy server,一個使用者,本機部署。
|
|||
|
|
|
|||
|
|
### In Scope
|
|||
|
|
|
|||
|
|
- OpenAI-compatible API(`/v1/chat/completions`、`/v1/models`)
|
|||
|
|
- SSE streaming response
|
|||
|
|
- 模型選擇(透過 `--model` 參數傳給 Cursor CLI)
|
|||
|
|
- 簡單的 YAML config 檔設定
|
|||
|
|
- 錯誤處理和 CLI 子程序生命週期管理
|
|||
|
|
- health check endpoint
|
|||
|
|
|
|||
|
|
### Out of Scope
|
|||
|
|
|
|||
|
|
- 非 OpenAI format 支援
|
|||
|
|
- 多用戶 / API key 管理
|
|||
|
|
- 計量追蹤
|
|||
|
|
- GUI 介面
|
|||
|
|
- Docker 部署
|
|||
|
|
|
|||
|
|
## Success Metrics
|
|||
|
|
|
|||
|
|
- Hermes Agent、OpenCode、Claude Code 都能透過設定 base URL 指向此 proxy 來使用 Cursor 模型
|
|||
|
|
- streaming 回應的延遲 < 2 秒(不含模型思考時間)
|
|||
|
|
- proxy 啟動後零設定即可使用(只需改 CLI 工具的 config)
|
|||
|
|
|
|||
|
|
## User Stories
|
|||
|
|
|
|||
|
|
1. 作為使用者,我想啟動 proxy server,這樣我的 CLI 工具就能連到它
|
|||
|
|
2. 作為使用者,我想在 Hermes Agent 裡設定 `base_url = http://localhost:8976`,這樣就能用 Cursor 的模型
|
|||
|
|
3. 作為使用者,我想在 CLI 工具裡指定 `model = claude-sonnet-4-20250514`,proxy 會傳給 Cursor CLI
|
|||
|
|
4. 作為使用者,我想看到模型的思考過程即時串流到終端機上
|
|||
|
|
5. 作為使用者,我想透過 `/v1/models` 查看可用的模型列表
|
|||
|
|
6. 作為使用者,我想透過 config 檔設定 proxy 的 port 和其他選項
|
|||
|
|
|
|||
|
|
## Functional Requirements
|
|||
|
|
|
|||
|
|
### FR1: OpenAI-Compatible API
|
|||
|
|
- 支援 `POST /v1/chat/completions`
|
|||
|
|
- 接受 OpenAI 格式的 request body(`model`、`messages`、`stream`)
|
|||
|
|
- 當 `stream: true` 時,回傳 SSE 格式的 `data: {...}\n\n` chunks
|
|||
|
|
- 當 `stream: false` 時,回傳完整的 JSON response
|
|||
|
|
|
|||
|
|
### FR2: Cursor CLI Integration
|
|||
|
|
- 收到請求後,組合 prompt 從 messages 陣列
|
|||
|
|
- spawn `agent -p "{prompt}" --model "{model}" --output-format stream-json` 子程序
|
|||
|
|
- 讀取子程序的 stdout streaming JSON 輸出
|
|||
|
|
- 管理子程序生命週期(啟動、執行、結束、超時 kill)
|
|||
|
|
|
|||
|
|
### FR3: Streaming Response Conversion
|
|||
|
|
- 將 Cursor CLI 的 `stream-json` 輸出轉換成 OpenAI SSE 格式
|
|||
|
|
- 每個 SSE chunk 需包含 `id`、`object: "chat.completion.chunk"`、`choices[0].delta.content`
|
|||
|
|
- 最後一個 chunk 需包含 `finish_reason: "stop"`
|
|||
|
|
|
|||
|
|
### FR4: Model Listing
|
|||
|
|
- 支援 `GET /v1/models`,回傳可用模型列表
|
|||
|
|
- 模型列表從 Cursor CLI 取得(`agent --list-models` 或 config 定義)
|
|||
|
|
|
|||
|
|
### FR5: Configuration
|
|||
|
|
- YAML config 檔(預設 `~/.cursor-adapter/config.yaml`)
|
|||
|
|
- 可設定:port、cursor_cli_path、default_model、timeout
|
|||
|
|
|
|||
|
|
### FR6: Error Handling
|
|||
|
|
- Cursor CLI 超時(可設定,預設 5 分鐘)→ 回傳 504
|
|||
|
|
- Cursor CLI 錯誤 → 回傳 500 + 錯誤訊息
|
|||
|
|
- 無效的 request body → 回傳 400
|
|||
|
|
- model 不存在 → 回傳 404
|
|||
|
|
|
|||
|
|
## Acceptance Criteria
|
|||
|
|
|
|||
|
|
### AC1: Basic Chat Completion
|
|||
|
|
Given proxy 已啟動在 port 8976,When 我用 curl 發送 `POST /v1/chat/completions` 帶上 `{"model": "claude-sonnet-4-20250514", "messages": [{"role": "user", "content": "hello"}], "stream": true}`,Then 收到 SSE streaming response,且內容為 Cursor CLI 的回應轉換成的 OpenAI 格式。
|
|||
|
|
|
|||
|
|
### AC2: Streaming Display
|
|||
|
|
Given CLI 工具連到 proxy 並發送 streaming 請求,When 模型正在生成回應,Then CLI 工具的終端機上即時顯示文字內容(不需要等完整回應)。
|
|||
|
|
|
|||
|
|
### AC3: Model Selection
|
|||
|
|
Given proxy 已啟動,When 請求中指定 `model: "gpt-5.2"`,Then proxy spawn Cursor CLI 時使用 `--model gpt-5.2`。
|
|||
|
|
|
|||
|
|
### AC4: Health Check
|
|||
|
|
Given proxy 已啟動,When 發送 `GET /health`,Then 回傳 `{"status": "ok", "cursor_cli": "available"}`。
|
|||
|
|
|
|||
|
|
### AC5: Model Listing
|
|||
|
|
Given proxy 已啟動,When 發送 `GET /v1/models`,Then 回傳 Cursor 可用的模型列表,格式符合 OpenAI models API。
|
|||
|
|
|
|||
|
|
## Edge Cases
|
|||
|
|
|
|||
|
|
- Cursor CLI 子程序意外崩潰 → proxy 回傳 500,清理資源
|
|||
|
|
- 請求 timeout(模型思考太久)→ proxy kill 子程序,回傳 504
|
|||
|
|
- 並發請求 → 每個請求 spawn 獨立的子程序
|
|||
|
|
- Cursor CLI 未安裝或不在 PATH → proxy 啟動時檢查,啟動失敗時給明確錯誤
|
|||
|
|
- Cursor CLI 未登入 → proxy 回傳錯誤訊息提示先 `agent login`
|
|||
|
|
- messages 陣列為空 → 回傳 400
|
|||
|
|
- stream: false 時,需要等 Cursor CLI 完整輸出後才回傳
|
|||
|
|
|
|||
|
|
## Non Functional Requirements
|
|||
|
|
|
|||
|
|
### NFR1: Performance
|
|||
|
|
- proxy 自身的 overhead < 500ms(不含模型思考時間)
|
|||
|
|
- streaming 的第一個 token 延遲不超過 Cursor CLI 本身的延遲 + 200ms
|
|||
|
|
|
|||
|
|
### NFR2: Reliability
|
|||
|
|
- 並發請求數 ≤ 5(個人使用)
|
|||
|
|
- 子程序超時後正確清理,不留 zombie process
|
|||
|
|
|
|||
|
|
### NFR3: Usability
|
|||
|
|
- 一行命令啟動:`cursor-adapter` 或 `cursor-adapter --port 8976`
|
|||
|
|
- config 檔格式簡單,有合理的預設值
|
|||
|
|
- 啟動時顯示可用模型列表
|
|||
|
|
|
|||
|
|
## Risks
|
|||
|
|
|
|||
|
|
| Risk | Impact | Likelihood | Mitigation |
|
|||
|
|
|------|--------|-----------|------------|
|
|||
|
|
| Cursor CLI output format 變更 | High | Medium | 抽象輸出解析層,方便適配 |
|
|||
|
|
| Cursor CLI 不支援某些模型 | Medium | Low | 啟動時驗證模型可用性 |
|
|||
|
|
| 並發子程序過多導致資源耗盡 | Medium | Low | 限制最大並發數 |
|
|||
|
|
| Cursor 的 headless 模式有限制 | High | Medium | 先用 headless 模式測試,必要時 fallback 到 ACP |
|
|||
|
|
|
|||
|
|
## Assumptions
|
|||
|
|
|
|||
|
|
- Cursor CLI 已安裝且在 PATH 中
|
|||
|
|
- Cursor CLI 已透過 `agent login` 完成認證
|
|||
|
|
- 使用者的 CLI 工具都支援 OpenAI-compatible API format
|
|||
|
|
- 使用者只需要 `/v1/chat/completions` 和 `/v1/models` 兩個 endpoint
|
|||
|
|
|
|||
|
|
## Dependencies
|
|||
|
|
|
|||
|
|
- Cursor CLI(`agent` command)
|
|||
|
|
- Python 3.10+ 或 Node.js 18+(取決於實作語言選擇)
|
|||
|
|
|
|||
|
|
## Open Questions
|
|||
|
|
|
|||
|
|
1. Cursor CLI 的 `--output-format stream-json` 的確切 JSON schema 是什麼?需要實際跑一次來確認
|
|||
|
|
2. Cursor CLI 是否支援同時跑多個 headless 實例?
|
|||
|
|
3. 需要支援 function calling / tool use 嗎?(目前 PRD 不含,但如果 Cursor CLI 支援的話可以加)
|