[STG-2515] feat(evals): cursor_sdk full-harness adapter#2341
Open
shrey150 wants to merge 5 commits into
Open
Conversation
9eb922a to
a9faa18
Compare
136e248 to
4c77455
Compare
|
a9faa18 to
c9e254d
Compare
4c77455 to
665bc5b
Compare
c9e254d to
0255867
Compare
665bc5b to
28dec25
Compare
Contributor
There was a problem hiding this comment.
All reported issues were addressed across 8 files
Confidence score: 5/5
- Safe to merge after the addressed issues were fixed.
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
0255867 to
69033b7
Compare
28dec25 to
df2e2e2
Compare
69033b7 to
64633ae
Compare
df2e2e2 to
26b3ec0
Compare
64633ae to
e4f238c
Compare
26b3ec0 to
7cb8a7f
Compare
Registers --harness cursor_sdk via @cursor/sdk (Agent.create → send → stream/wait against Cursor's managed local agent). Classification: FULL harness, on the smart tier next to claude_code/codex — 'the same runtime, harness, and models that power Cursor' — not the bare tier, despite being a new SDK. The runner exposes exactly one custom tool (browse, same allowed-command gate as every other external harness) and prompts the agent to use only that tool; the SDK exposes no tool allow-list, so browse-only discipline is prompt + custom-tool based rather than a canUseTool hard gate (recorded in the design doc). cursorAdapter reverse-maps the SDKMessage stream (tool_call/assistant/thinking/usage) into a verifier Trajectory, collapsing running→terminal duplicate tool_call events by call_id. Auth: CURSOR_API_KEY. Live validation pending an API key — implemented and unit-tested against a mocked SDK. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…result + clip tool output
Two comparability bugs in the cursor_sdk custom tool:
- execute() returned the bare output string and discarded `ok` from
runBareBrowseCommand. Since runBareBrowseCommand never throws, the SDK
had no signal a browse command failed, so every tool call read back as
"completed" and cursorAdapter (which derives ok from that status)
recorded every call as ok:true. Return the SDK's own
SDKCustomToolResult shape ({content, isError}, per @cursor/sdk's
options.d.ts) with isError: !ok instead.
- The tool ran runBareBrowseCommand directly, bypassing the 20k output
clip every other harness gets via createBareLoopToolRecorder's
readToolOutputLimit. Apply the same clip here so tool-output sizes are
comparable across all five harnesses.
Also strengthens the test: the previous mock hardcoded tool_call status
"completed" regardless of the tool result. Added a case that fails the
underlying browse command and asserts isError:true out of the custom
tool AND ok:false once that isError flows through a terminal tool_call
event into the recorded trajectory.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…call metric - cursorAdapter: non-terminal (running) tool_call events no longer become trajectory steps — an interrupted run must not surface an in-flight call as a successful step. Reasoning buffered before a running event still carries over to its terminal event. - cursorSdkRunner: cursor_tool_calls counts distinct terminal call_ids, matching the adapter's duplicate collapsing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
e4f238c to
1fbd7c2
Compare
7cb8a7f to
ab81880
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Part 5 of 5 — stacked on #2340 (
openai_agents_sdk) (base:shrey/evals-harness-openai-agents-sdk; GitHub shows only this PR's delta). When the parent merges, retarget this PR's base and rebase.Registers
--harness cursor_sdkvia@cursor/sdk(343K npm dl/wk):Agent.create → send → stream/waitagainst Cursor's managed local agent. Classification: FULL harness, on the smart tier next to claude_code/codex — "the same runtime, harness, and models that power Cursor" — NOT the bare tier, despite being a new SDK. It ships Cursor's complete loop, planning, and tool behaviors, which is exactly what makes it a useful smart-tier comparison point.browse, same allowed-command gate as every other external harness) and prompts the agent to use only that tool. Known limitation (recorded in the design doc): the SDK exposes no tool allow-list, so browse-only discipline is prompt + custom-tool based rather than acanUseTool-style hard gate; the agent's native shell still runs inside the per-run temp cwd.cursorAdapterreverse-maps theSDKMessagestream (tool_call / assistant / thinking / usage) into a verifierTrajectory— only terminal (completed|error)tool_callevents become steps (an interrupted run can't record an in-flight call as a successful step), duplicate terminal events collapse bycall_id, buffered assistant/thinking text folds into the call's reasoning, per-turn usage sums.cursor/composer-2.5default; prefix stripped). No SDK-level turn cap exists — like claude_code, it inherits harness-native limits.CURSOR_API_KEY(the SDK's own env var). Adds the@cursor/sdkdependency (pinned 1.0.23) — this PR carries its own lockfile delta.sdkinjection seam (Agent.create → send → stream/wait mock).External harnesses design + usage:
packages/evals/README.md#external-harnesses(in #2337). Linear: STG-2515.Comparability fixes (2026-07-09 audit)
Two comparability bugs in the custom
browsetool:execute()returned the bare output string and discardedokfromrunBareBrowseCommand. Since that helper never throws, the SDK had no signal a browse command failed — every tool call read back asstatus: "completed", andcursorAdapter(which derivesokfrom that status) recorded every call asok:trueregardless of outcome. Now returns@cursor/sdk's ownSDKCustomToolResultshape ({ content, isError }, peroptions.d.ts) withisError: !ok.runBareBrowseCommanddirectly, bypassing the 20k-char output clip every other harness gets viacreateBareLoopToolRecorder'sreadToolOutputLimit. Now clipped the same way, so tool-output sizes are comparable across all five harnesses.Strengthened the test: the previous mock hardcoded
tool_callstatus"completed"regardless of the tool result. Added a case that fails the underlyingbrowsecommand and assertsisError:trueout of the custom tool, then that it lands asok:falseonce thatisErrorflows through a terminaltool_callevent into the recorded trajectory.Open question for reviewers
@cursor/sdk'soptions.d.tsexposes an undocumentedsandboxOptions: { enabled }toggle onLocalAgentOptionsthat this runner doesn't set. Unknown whether enabling it narrows the shell-gating gap noted above (the SDK has no tool allow-list to hard-disable its native shell/file tools, so browse-only discipline here is prompt + custom-tool based, not a hard gate). Flagging for input before deciding whether to wire it — no doc coverage found beyond the type declaration itself.E2E Test Matrix
@cursor/sdk@1.0.23type declarations (Agent.create/send,Run.stream/wait,SDKMessage,TokenUsage), not from docs alonepnpm exec vitest run(this branch)Test Files 53 passed, Tests 385 passed— addscursorSdkRunner.test.ts(agent creation with gated custom tool wired to a real temp binary, prompt composition = arm prompt + browse-only instruction + task, stream collection, close() on both paths, metrics; plus cursorAdapter mapping tests: reasoning folding, duplicate call_id collapse, usage summing, error tool_calls)tsc --noEmit+ prettier + eslintpnpm exec vitest run(this branch, post-fix, stack tip)Test Files 57 passed, Tests 419 passed— adds the isError/ok:false propagation test, the in-flight (running-only) tool_call exclusion test, and the duplicate-terminal-event metric dedup caseCURSOR_API_KEYpnpm -w exec tsc --noEmit+ prettier + eslint (post-fix)No changeset:
packages/evalsis private.🤖 Generated with Claude Code
Summary by cubic
Adds a full
cursor_sdkharness powered by@cursor/sdkto run Cursor’s managed local agent and feed results into our verifier. Implements STG-2515 and enables smart-tier comparisons with correct tool-failure signaling, terminal-only tool_call handling, and consistent tool-output clipping.New Features
--harness cursor_sdkvia@cursor/sdkand adds it to the bench registry.browsecustom tool with the allowed-command gate; returns SDK-shaped{ content, isError }and clips output to the standard limit.cursorAdapter: only terminal tool_calls become steps, duplicate call_ids deduped, assistant/thinking folded into reasoning, usage summed; adds dedupedcursor_tool_callsand token metrics.@cursor/sdk@1.0.23.Migration
CURSOR_API_KEYto run this harness.cursor/composer-2.5(provider prefix is stripped).Written for commit ab81880. Summary will update on new commits.