Commit Graph
366 Commits
Author SHA1 Message Date
leokun 17342167ac feat: update desktop settings and server compatibility 2026-09-04 15:33:55 +08:00
leokun 8942287a27 refactor(proxy): change proxy mode from "system" to "default" across the application
- Updated the default proxy mode in `api.ts`, `ProxySettingsCard.tsx`, and `SettingsPage.tsx` to "default".
- Adjusted related translations in `catalog.json`, `en-US.json`, and `zh-CN.json`.
- Modified the `ProxyMode` enum in `settings.rs` to reflect the change from "system" to "default".
- Enhanced proxy handling in the server code to support the new default mode.
2026-09-03 16:32:02 +08:00
leokun 924b5e5926 feat(cursor): cli 接入本地模型路由与配置
- feat(服务配置): 本地响应配置并禁用 HTTP/2 传输
- feat(模型目录): 提供默认模型接口及本地路由凭据
- fix(待办状态): 基于检查点合并增量待办并保留未变更项
- fix(模型参数): 忽略未知参数以兼容新版 Cursor 请求
- test(本地路由): 覆盖模型元数据路由与凭据行为
2026-09-03 16:01:25 +08:00
ProtectCookies a511fb983d Merge branch 'main' of https://github.com/ProtectCookies/cursor-byok 2026-09-03 11:47:10 +08:00
ProtectCookies 49a38ca857 feat(overview): 近4小时/近24小时移入自定义弹层,近4小时支持选择图表粒度
- 主时间栏移除近4小时/近24小时,改为自定义弹层顶部的快捷范围
- 近4小时点击后弹出粒度菜单:1分钟/15分钟/30分钟/1小时
- overview API 新增 bucket_ms 参数,支持客户端指定分桶粒度
- 指定粒度时桶数上限放宽至 1440,未指定时维持原自动逻辑
2026-09-03 11:45:32 +08:00
ProtectCookies e0f9bd6780 fix(desktop): 页面操作栏不再被当作标题栏拖动
.actionRegion 由 drag 改为 no-drag,修复顶部时间条、刷新按钮可拖动窗口、双击触发最大化的问题。
2026-09-03 11:45:17 +08:00
leokun 543f618fee Merge pull request #411 from ProtectCookies/main
feat: Git Commit 信息 BYOK 生成(默认直连,可选本地模型)
2026-09-03 10:44:12 +08:00
ProtectCookies 42811a27f5 feat: 新增 Commit 设置及本地提交信息生成
- 新增 CommitSettingsCard 组件,支持选择生成模型与编辑提示词
- 新增 /settings/commit GET/PUT 接口及 CommitSettings 持久化
- 实现 WriteGitCommitMessage RPC 本地生成,空 model_id 时直连转发
- 新增 NetworkService/IsConnected 探针响应,防止流式生成被中断
- 添加 commit prompt 模板及 proto 消息定义
- 补充 zh-CN / en-US 国际化词条
2026-09-03 10:31:41 +08:00
kevin9327 e4b5e132d6 chore: restore a green make check on main
- output.rs: the read_lints test helper (#398) builds ToolCall without
  the argument_error field added in d83e14a, so the lib-test target
  does not compile
- connect_wire.rs: cursor::router takes NetworkClients since 2dad593
- runtime.rs: clippy::nonminimal_bool from 5cdf642
- update/mod.rs: clippy::needless_return in the Windows arm, ddaa61c
2026-09-03 07:55:51 +09:00
kevin9327andClaude Opus 4.8 a42f84cfe7 fix(conversation): scope completed tool call ids to their round
A provider that reuses a tool call id across two rounds of one run
wedges the run permanently. `ToolDispatcher::start_batch` skips any call
whose id is in `ToolBatchState::completed`, so the second call is never
dispatched and never produces a `ToolCompletion`, while
`tool_round::execute` blocks waiting for `calls.len()` results with no
timeout on that path. The client sees the tool call appear and then
nothing: no completion, no further output, no end-stream frame.

The `completed` set is built once per run and never cleared, so it is
run-scoped. A tool call id is only unique within a round, which the
schema already states as `UNIQUE (round_id, call_id)`; the sibling
runtime completed-map is likewise already cleared per round at
output.rs:615.

Clear `completed` when `ExecuteToolRound` begins a new round, tracked
independently of `active_round` so it does not depend on the order in
which ToolRoundStarted and ExecuteToolRound are observed. Replaying a
round still skips the calls that round already committed.

The practical trigger is openai_chat.rs:196, which synthesizes
`call-{index}` from a per-stream index when a provider omits tool call
ids, so `call-0` recurs on every model call. That file is left alone
here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 07:35:10 +09:00
leokun 8fdcdd7f84 Merge pull request #395 from kevin9327/chore/restore-make-check-green
chore: restore a green `make check` on main
2026-09-03 00:32:31 +08:00
leokun e1d6bd9726 Merge pull request #398 from kevin9327/fix/readlints-drops-extra-paths
fix(tools): report the ReadLints paths that were never checked
2026-09-03 00:31:54 +08:00
Linanwanttodo 147d13f04e perf(desktop): switch to the mimalloc global allocator
glibc keeps freed pages in its arena, so RSS did not fall back after
the webview was destroyed. mimalloc returns freed memory to the OS,
letting the resident footprint settle right after the UI closes.
2026-09-02 18:20:33 +08:00
Linanwanttodo dbec16dd8b perf(desktop): create the main window lazily on demand
The webview used to be built unconditionally at startup and only
hidden on close, so the forwarding gateway kept WebKitWebProcess and
WebKitNetworkProcess resident even when the UI was never used. Now the
window is created only when opened from the tray, closing the window
destroys the webview, and all-windows-closed keeps the process alive in
the tray while the forwarding server keeps running.
2026-09-02 18:20:20 +08:00
leokun 75b7ea9cc8 chore(release): bump desktop to 0.1.6 v0.1.6 2026-09-02 14:03:35 +08:00
leokun 0fd5e9d6f2 fix(desktop): update content security policy to allow HTTPS images
- Modified the content security policy in `tauri.conf.json` to include `https:` in the `img-src` directive, enhancing security by allowing images from secure sources.
2026-09-02 13:56:28 +08:00
leookun ddaa61c827 fix(desktop): update Windows executable in place 2026-09-02 13:02:11 +08:00
leookun 919c1d8032 fix: update ADS_ENDPOINT to production URL
- Changed the `ADS_ENDPOINT` from a local server URL to the production URL for ads.
- Commented out the local server URL for clarity and future reference.
2026-09-02 12:49:57 +08:00
leokun 669f129dcd Merge branch 'main' of github.com:leookun/cursor-byok 2026-09-02 11:03:41 +08:00
leookun f22c7b6680 feat: integrate app version into control service and update ads endpoint
- Added `app_version` field to `ControlService` and updated its initialization to include the app version.
- Modified the `ADS_ENDPOINT` to point to a local server for development purposes.
- Refactored conversation command and output handling to utilize a new `RunFinish` enum for better state management.
- Enhanced the conversation runtime to handle queued user messages after a turn has ended, ensuring smooth transitions between turns.
- Added tests to validate the new behavior of queued messages and transport handling.
2026-09-02 10:23:50 +08:00
leookun 5cdf642dd1 feat: enhance bidi request handling and observability tracing
- Updated the `append` function to include a flag for replacing closing requests, improving request handling.
- Refactored the `run_sse_handler` and `bidi_handler` functions to utilize a new tracing mechanism, enhancing observability.
- Introduced a new `trace_outcome` function to standardize tracing outcomes for requests.
- Removed the `CursorTraceRecorder` in favor of a new `CursorTraceService` for better performance and non-blocking behavior.
- Added tests to validate the new tracing functionality and ensure correct behavior during request processing.
2026-09-02 01:04:54 +08:00
leokun 2dad593263 feat: add resource limits management and network client integration
- Introduced a new module for managing process resource limits, specifically for raising the open file limit on Unix systems.
- Added a `NetworkClients` struct to handle reusable outbound HTTP clients, improving network request management.
- Updated various components, including `ControlService` and `CursorProxy`, to utilize the new network client structure for better client handling.
- Enhanced the API router to accept network clients, ensuring consistent client usage across different services.
- Added tests to validate the integration of network clients and resource limits functionality.
2026-09-01 21:03:02 +08:00
masudranaxpert d7578bcc15 feat(antigravity): add Google Antigravity auth plugin with auto-rotation, model catalog and multi-turn support 2026-09-01 18:23:55 +06:00
leokun 76417e005b feat: add usage snapshot event and enhance compaction logic
- Introduced `UsageSnapshot` event to track token usage during conversation runs.
- Updated `RunEngine` to emit usage snapshots, providing better visibility into token consumption.
- Refactored compaction logic to utilize a new `compaction_estimate` function for improved token budget management.
- Added tests to validate timeout constants for blob synchronization and ensure correct behavior of usage tracking during compaction.
2026-09-01 20:04:35 +08:00
leokun e768980dad feat: enhance reasoning replay functionality and integrate call recording
- Added a new test to validate the projection of reasoning response items to valid input items in the Codex API.
- Introduced `CallRecorder` to track network requests and responses during plugin interactions.
- Updated the `PluginRegistry` and `PluginWorker` to support call recording, ensuring that reasoning items are correctly processed and recorded.
- Refactored the `responses_input` function to handle reasoning items more effectively, improving the overall response handling logic.
2026-09-01 17:43:36 +08:00
leokun 2c63bd845a feat: track interaction events during automatic compaction
- Added tracking for interaction events in the `Output` struct, including `summary_started` and `token_delta`.
- Updated the `run` function to push relevant interaction events to the `interaction_events` vector.
- Enhanced the automatic compaction test to verify the immediate reset of cursor usage and the correct logging of interaction events.
2026-09-01 16:54:45 +08:00
leokun 6e74637c69 Merge branch 'main' of github.com:leookun/cursor-byok 2026-09-01 16:08:34 +08:00
leookun d004139526 feat: implement context usage anchor for improved token estimation
- Introduced `ContextUsageAnchor` struct to track context input tokens and message count for conversations.
- Updated token estimation functions to utilize the context usage anchor, enhancing accuracy in estimating tokens for projected messages.
- Refactored compaction logic to incorporate context usage anchor, allowing for more efficient management of token budgets during model runs.
- Added tests to validate the behavior of the context usage anchor across different scenarios, including model switching and message additions.
2026-09-01 16:07:51 +08:00
leokun 8c6c415a84 feat: enhance token usage merging and total token calculation
- Updated the `merge_usage` function to include `total_tokens` in the usage merging process.
- Implemented logic to calculate `total_tokens` based on the sum of `context_input_tokens` and `output_tokens`.
- Added a new test to verify that streamed usage correctly includes cached input in the total token count.
2026-09-01 11:13:00 +08:00
leokun d83e14af9a refactor: remove retry_count from ProviderConfig and enhance error handling in tool execution
- Removed the `retry_count` field from `ProviderConfig` as it is no longer needed.
- Introduced `argument_error` field in `ToolCall` to capture errors related to tool arguments.
- Updated various components to handle argument errors more gracefully, including in the `ToolDispatcher` and `ConversationOutput`.
- Enhanced tests to validate the new error handling and ensure proper functionality of tool calls.
2026-09-01 10:14:53 +08:00
leokun 29fde7d7c7 feat: enhance context token estimation and compaction logic
- Added `estimate_context_tokens` function to calculate provider-visible context size based on prompt specifications and projected messages.
- Updated `CheckpointBuilder` to record estimated context tokens during message processing.
- Refactored compaction logic to utilize the new token estimation, ensuring proper context management during model runs.
- Introduced tests to validate context estimation and compaction behavior under various scenarios.
2026-09-01 10:10:09 +08:00
kevin9327andClaude Opus 4.8 1269110615 fix(tools): report the ReadLints paths that were never checked
ReadLints accepts an array of paths, but codec::request encodes only
paths[0] into the DiagnosticsArgs exec, and the exec protocol cannot
carry more than one path. Nothing downstream mentions the drop: for
{"paths": ["a.ts", "b.ts", "c.ts"]} the model is handed
"No diagnostics found in a.ts" with is_error false, so it concludes
b.ts and c.ts are clean when neither was ever opened. The existing
truncation notice cannot catch this, since it compares total_diagnostics
against a per-file diagnostics count.

Name the unread paths in the model-facing result, using the bracketed
notice convention already in this file and the ToolCall that output()
is already given (as task() and render::read() already use it).
Single-path calls are unchanged.

This does not close the capability gap. A real fix fans out one
DiagnosticsArgs exec per path and aggregates the results into the
repeated FileDiagnostics that ReadLintsToolSuccess already defines,
which needs multi-exec reservation and a completion barrier because
take_exec drops the pending entry on the first result. That is a
separate change; this one only stops the silent misinformation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-31 20:13:22 +09:00
kevin9327andClaude Opus 4.8 86c3899016 ci: run the Makefile check gates on pull requests
`release.yml` only runs on `v*` tags, so nothing verifies a commit
before it lands on `main`. `main` is currently red on three of the five
gates `make check` defines, which is the drift this is meant to catch.

Adds a single job running the three Rust gates verbatim as the Makefile
spells them:

    cargo fmt --all -- --check
    cargo clippy --workspace --all-targets -- -D warnings
    cargo test --workspace --all-targets

Conventions follow release.yml so the two workflows stay consistent:
ubuntu-22.04, the same apt packages (the workspace includes
apps/desktop/src-tauri, so even `cargo check` needs webkit2gtk),
dtolnay/rust-toolchain@stable and Swatinem/rust-cache@v2 with the same
`. -> target` workspace key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-31 20:02:14 +09:00
kevin9327andClaude Opus 4.8 38a4c3f516 chore: restore a green make check on main
`make check` currently fails on main before any change is made: one
`cargo fmt --all -- --check` diff and four `cargo clippy --workspace
--all-targets -- -D warnings` errors. All five are pre-existing and
none of them change behaviour.

- `server/tests/knowledge_rules.rs:125` — rustfmt wants the long
  `assert!` split across lines. Applied `cargo fmt --all` verbatim.
- `server/src/plugin/data.rs:206,215` — `path` is only read under
  `#[cfg(unix)]`, so every other target sees an unused binding. Added
  a `#[cfg(not(unix))] { let _ = path; }` arm, matching the
  `let _ = error;` idiom already used at line 189 of the same file.
  Windows behaviour is unchanged: these helpers stay no-ops there.
- `server/src/provider/openai_responses.rs:158` — `collapsible_match`.
  Applied clippy's own suggestion (move `thinking_open` into a match
  guard). The match ends in `_ => {}`, so a failed guard falls through
  to a no-op exactly as the inner `if` did.
- `server/src/store/models.rs:327` — `items_after_test_module`. Moved
  `optional_u64` and `to_i64` above `mod tests`; the bodies are
  untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-31 19:59:28 +09:00
kevin9327 ab4d3adee5 fix(model): stop token accumulation from erasing counts a later call omits
`Usage::add_assign` folds every field through

    fn sum(left: Option<u64>, right: Option<u64>) -> Option<u64> {
        left?.checked_add(right?)
    }

so `sum(Some(900), None)` is `None`, not `Some(900)`. Adding a record that does
not report a field therefore does not leave the running total alone - it wipes
it.

Both accumulators are per-turn and run over every provider call in the turn:
`run/engine.rs::accumulate_usage` (the compaction call plus each model cycle)
and `cursor/conversation/output.rs::turn_usage`, which is what `turn_ended`
reports to Cursor.

Providers report these fields inconsistently *across calls of one turn*, which
is all it takes. `openai_usage` reads `cache_read_tokens` from
`prompt_tokens_details`, an object most OpenAI-compatible gateways omit until
the prompt cache warms: call 1 (cold) yields `None`, call 2 yields
`Some(1024)`, and the turn reports `None`. The same happens to
`reasoning_tokens` when only some cycles reason, and to `total_tokens` on
gateways that omit it from the streaming usage chunk. Any tool-using turn makes
more than one call, so this is the normal case rather than an edge case.

Treat an unreported count as zero and keep the field unknown only when neither
side reported it. `checked_add` also becomes `saturating_add`: with the new
rule, silently turning an overflow into `None` would be the same erasure by
another route, and token counts never approach `u64::MAX` anyway.
`context_input_tokens` is untouched.

Before (with `left?.checked_add(right?)` restored):
  cargo test -p cursor-server --lib model::observability
  -> 2 failed: assertion `left == right` failed: left: None, right: Some(900)
After:
  cargo test -p cursor-server --lib model::observability -> 3 passed
2026-08-31 19:39:02 +09:00
kevin9327 24c41d0347 fix(tools): keep result truncation inside its byte budget and terminating
`truncate_text` looks for a fixed point where the kept prefix length equals the
byte count printed in its own truncation notice. Two things go wrong when the
limit is small, and both are reachable because two call sites pass a *remaining*
budget rather than a constant:

* `gate_grep_content` -> `truncate_text("Grep", .., budget.content_bytes)`
* `gate_mcp` -> `truncate_text("MCP text", .., remaining_text)`

1. The loop can spin forever. `notice.len()` grows with the decimal digit count
   of `shown`, so `kept.len()` alternates between two values across a power-of-
   ten boundary and never equals `shown`. With `tool_name = "Grep"` this happens
   at `limit` 78 and 170; with `"MCP text"` at 82 and 174. The conversation task
   then spins at 100% CPU and the turn never completes. `truncate_middle` in
   `model/tool_result_replay.rs` already guards against exactly this.

2. When the notice itself does not fit, `available` saturates to 0 and the
   function returns the ~68 byte notice alone, i.e. *more* than `limit`.
   `gate_grep_content` then evaluates `budget.content_bytes -= <68 bytes>` on a
   budget of at most 68, which panics with "attempt to subtract with overflow"
   in debug/test builds and wraps in release, silently disabling the 32 KiB
   content cap for the rest of the result.

Both are ordinary Grep results away: 16 matches of ~2 KiB leave a two-digit
remainder of the 32 KiB budget, and the next match then hits the small-limit
path.

Fix: return a plain prefix when the notice cannot fit, and stop as soon as the
kept length repeats a previous value. The reported byte count is then off by one
at most in that rare oscillating case, and the result is guaranteed to be at
most `limit` bytes. Every constant-limit call site is unaffected: their notices
always fit and their limits do not oscillate. `budget.content_bytes` now uses
`saturating_sub`, matching every other subtraction in this file.

Verified against the unfixed function:
  cargo test -p cursor-server --lib gate::tests::truncate_text_never_exceeds_its_limit
  -> FAILED: limit 1 produced 67 bytes
  cargo test -p cursor-server --lib gate::tests::grep_content_gate_survives
  -> FAILED: panicked at gate.rs:261: attempt to subtract with overflow
  cargo test -p cursor-server --lib gate::tests::truncate_text_terminates
  -> never returns (killed after 45s)
  cargo test -p cursor-server --lib gate::tests::grep_content_gate_terminates
  -> never returns (killed after 60s)
After: cargo test -p cursor-server --lib tools::tool_call_result::gate -> 4 passed
2026-08-31 19:35:39 +09:00
kevin9327 b6fc7326e7 fix(provider): keep OpenAI Chat tool calls that finish with reason "stop"
`map_finish` matched `"stop" | "content_filter"` before the `has_tools`
fallback, so the fallback only ever applied to finish reasons the adapter did
not recognise. When an OpenAI-compatible server streams tool calls and then
reports `finish_reason: "stop"` the adapter yielded `Done(Stop)` even though
`ToolCallStart` / `ToolCallEnd` had already been emitted.

`run/model_cycle.rs` rejects that combination:

    let has_tool_calls = !calls.is_empty();
    if matches!(finish_reason, FinishReason::ToolUse) != has_tool_calls {
        return Err(failure(RunFailure::Protocol(
            "finish reason and tool calls disagree".into()), ...));
    }

so the whole turn fails with a protocol error and the tool never runs. Servers
that report `"stop"` alongside `tool_calls` are common in BYOK setups
(llama.cpp, Ollama's OpenAI shim, several proxies), which makes those models
unusable for anything agentic.

Move the `has_tools` arm ahead of `"stop" | "content_filter"` so an observed
tool call outranks the label the provider attached to the stop. This matches
the two sibling adapters (`anthropic.rs` checks `_ if saw_tool` before every
reason except `Length`, `openai_responses.rs` derives the reason from
`saw_tool` alone) and this adapter's own `[DONE]` fallback, which already
infers `ToolUse` from `!tools.is_empty()`. `"length"` still wins so a
truncated response is still reported as truncated, and behaviour with no tool
calls is byte-for-byte unchanged.

Before (with the arm restored):
  cargo test -p cursor-server --lib provider::openai_chat
  -> observed_tool_calls_outrank_a_stop_finish_reason FAILED
     assertion `left == right` failed: left: Stop, right: ToolUse
After:
  cargo test -p cursor-server --lib provider::openai_chat -> 3 passed
2026-08-31 19:26:38 +09:00
kevin9327 e87abace8b fix(tests): acknowledge conversation Blob writes in the local rules test
`local_markdown_rules_land_in_the_request_context_message` never finishes:
`cargo test --workspace` fails on `main` with

    panicked at server\tests\local_rules_context.rs:64:14:
    run finishes within timeout: Elapsed(())

The Run publishes the conversation checkpoint by asking the client to write
Blobs, and it does not continue until every `KvServerMessage` is answered
with a `SetBlobResult`. The test drained the output stream without replying,
so the Run stalled after the first frame, the provider was never invoked, and
none of the assertions the test exists for were ever reached.

Answer the Blob writes the way every other transport test already does
(`error_lifecycle.rs`, `conversation_delivery.rs`, `interrupt.rs`). With the
acknowledgement in place the Run reaches `EndStream` in ~0.3s and the original
assertions run and pass, so `merge_local_rules` is now genuinely covered:
exactly one `request-context:` message is projected and it carries
`<user_rule>Always answer in haiku.</user_rule>`.

No production code changes.

Before: `cargo test -p cursor-server --test local_rules_context`
        -> FAILED (0 passed; 1 failed) after a 5s timeout
After:  `cargo test -p cursor-server --test local_rules_context`
        -> ok (1 passed; 0 failed) in 0.28s
2026-08-31 19:20:30 +09:00
leokun ee2592c469 Merge branch 'main' of github.com:leookun/cursor-byok 2026-08-31 16:15:58 +08:00
leokun 49c1fb6378 feat: add Task tool functionality
- Introduced a new `Task` presentation type in the `ToolCallStream` to handle task-related projections.
- Implemented the `TaskProjection` struct with fields for description, prompt, subagent type, model, resume, and environment.
- Added a `project` method to `TaskProjection` to process task-related events and generate interaction updates.
- Created a `task_partial` function to format task updates for the agent server message.
- Included unit tests to verify the correct behavior of task description projections.
2026-08-31 16:15:42 +08:00
leokun 788868f8b9 Merge pull request #385 from kevin9327/fix/runtime-user-message-injection-leak
fix(conversation): clear pending runtime user-message injections
2026-08-31 16:14:27 +08:00
leokun 4c3fe230ce Merge remote-tracking branch 'origin/main' into pr-385-merge
# Conflicts:
#	server/tests/interrupt.rs
2026-08-31 16:12:11 +08:00
leokun ac14245d19 Merge pull request #383 from kevin9327/fix/editnotebook-empty-old-string
fix(tools): reject empty old_string in EditNotebook
2026-08-31 16:06:42 +08:00
leokun 84addec26a Merge pull request #384 from kevin9327/fix/bash-shell-alias
fix(tools): complete the bash shell alias in the tool codec
2026-08-31 16:06:18 +08:00
leokun 5de547041c Merge branch 'main' of github.com:leookun/cursor-byok 2026-08-31 15:38:11 +08:00
leokun 8bd0d70add fix: plugin effort compress 2026-08-31 15:38:02 +08:00
leokun 3ac4402a86 Update cursor.md 2026-08-31 15:18:43 +08:00
leokun e535a98945 Update cursor.md 2026-08-31 15:10:37 +08:00
leokun 45e694fd63 Merge pull request #386 from kevin9327/fix/empty-tool-arguments
fix: handle tool calls with empty arguments
2026-08-31 13:57:45 +08:00
leookun 9120b90be7 chore: remove deprecated server_backup files
- Deleted unused build script, Cargo.toml, and migration files to clean up the project structure.
- Removed prompt files related to cursor tools and agent modes to streamline the codebase.
- This cleanup helps improve maintainability and reduces clutter in the repository.
2026-08-30 23:54:19 +08:00