@cursor/july 0.1.15 → 0.1.17
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/README.md +9 -4
- package/dist/bin/agent-serve.js +60 -2
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +13 -3
- package/dist/channels/slack/auth.d.ts +7 -1
- package/dist/channels/slack/auth.d.ts.map +1 -1
- package/dist/channels/slack/auth.js +14 -0
- package/dist/channels/slack/blocks.d.ts +61 -0
- package/dist/channels/slack/blocks.d.ts.map +1 -0
- package/dist/channels/slack/blocks.js +90 -0
- package/dist/channels/slack/defaults.d.ts +2 -0
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +29 -3
- package/dist/channels/slack/dispatch.d.ts +3 -17
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/index.d.ts +1 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +1 -0
- package/dist/channels/slack/interactive.d.ts +39 -3
- package/dist/channels/slack/interactive.d.ts.map +1 -1
- package/dist/channels/slack/interactive.js +152 -7
- package/dist/channels/slack/manifest.d.ts +3 -0
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +3 -0
- package/dist/channels/slack/setup.d.ts +4 -1
- package/dist/channels/slack/setup.d.ts.map +1 -1
- package/dist/channels/slack/setup.js +16 -2
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +24 -3
- package/dist/channels/slack/types.d.ts +77 -0
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/connections.d.ts +4 -1
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +4 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +3 -3
- package/dist/docs/assets/{app.DpdGZTLe.js → app.BbEXr2KO.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DCBsrfwP.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.IB-0QqIT.js → VPLocalSearchBox.DBEi4HDp.js} +1 -1
- package/dist/docs/assets/chunks/{theme.-fYBoNtR.js → theme.DGfptcHw.js} +2 -2
- package/dist/docs/assets/{example-agents_index.md.BPXjUtRB.js → example-agents_index.md.D2PEVSXl.js} +2 -2
- package/dist/docs/assets/{example-agents_index.md.BPXjUtRB.lean.js → example-agents_index.md.D2PEVSXl.lean.js} +1 -1
- package/dist/docs/assets/example-agents_security-reviewer.md.BZSNycMf.js +19 -0
- package/dist/docs/assets/{example-agents_security-reviewer.md.CE9v-aKm.lean.js → example-agents_security-reviewer.md.BZSNycMf.lean.js} +1 -1
- package/dist/docs/assets/{guides_mcp-oauth.md.DqmEOQY1.js → guides_mcp-oauth.md.Dd8EgSem.js} +3 -2
- package/dist/docs/assets/{guides_mcp-oauth.md.DqmEOQY1.lean.js → guides_mcp-oauth.md.Dd8EgSem.lean.js} +1 -1
- package/dist/docs/assets/{guides_slack.md.FWale6Ip.js → guides_slack.md.D_xFKlnF.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.CsSr3rDz.js → reference_connections.md.B9Q3TOve.js} +12 -5
- package/dist/docs/assets/{reference_connections.md.CsSr3rDz.lean.js → reference_connections.md.B9Q3TOve.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +3 -3
- package/dist/docs/concepts.html +3 -3
- package/dist/docs/deployment.html +3 -3
- package/dist/docs/evals.html +3 -3
- package/dist/docs/example-agents/approval-buddy.html +3 -3
- package/dist/docs/example-agents/benny.html +3 -3
- package/dist/docs/example-agents/bugbot.html +3 -3
- package/dist/docs/example-agents/codebase-wiki.html +3 -3
- package/dist/docs/example-agents/codeowners-review.html +3 -3
- package/dist/docs/example-agents/concierge.html +3 -3
- package/dist/docs/example-agents/fsd.html +3 -3
- package/dist/docs/example-agents/index.html +5 -5
- package/dist/docs/example-agents/knowledge-base.html +3 -3
- package/dist/docs/example-agents/oncall.html +3 -3
- package/dist/docs/example-agents/security-reviewer.html +14 -14
- package/dist/docs/example-agents/slack-agent.html +3 -3
- package/dist/docs/example-agents/weather-agent.html +3 -3
- package/dist/docs/guides/agent-to-agent.html +3 -3
- package/dist/docs/guides/cloud-runtime.html +3 -3
- package/dist/docs/guides/github.html +3 -3
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/mcp-oauth.html +6 -5
- package/dist/docs/guides/slack.html +5 -5
- package/dist/docs/guides/webhooks.html +3 -3
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +3 -3
- package/dist/docs/quickstart.html +3 -3
- package/dist/docs/reference/agent-config.html +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +3 -3
- package/dist/docs/reference/connections.html +14 -7
- package/dist/docs/reference/hooks.html +3 -3
- package/dist/docs/reference/http-api.html +3 -3
- package/dist/docs/reference/instructions.html +3 -3
- package/dist/docs/reference/playground.html +3 -3
- package/dist/docs/reference/project-layout.html +3 -3
- package/dist/docs/reference/prompt.html +3 -3
- package/dist/docs/reference/schedules.html +3 -3
- package/dist/docs/reference/sessions.html +3 -3
- package/dist/docs/reference/skills.html +3 -3
- package/dist/docs/reference/subagents.html +3 -3
- package/dist/docs/reference/tools.html +3 -3
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +3 -3
- package/dist/docs/troubleshooting.html +3 -3
- package/dist/evals/assertions.d.ts +190 -0
- package/dist/evals/assertions.d.ts.map +1 -0
- package/dist/evals/assertions.js +461 -0
- package/dist/evals/expect.d.ts +95 -0
- package/dist/evals/expect.d.ts.map +1 -0
- package/dist/evals/expect.js +194 -0
- package/dist/evals/judge.d.ts +133 -0
- package/dist/evals/judge.d.ts.map +1 -0
- package/dist/evals/judge.js +228 -0
- package/dist/evals/loaders.d.ts +51 -0
- package/dist/evals/loaders.d.ts.map +1 -0
- package/dist/evals/loaders.js +124 -0
- package/dist/evals/matchers.d.ts +95 -0
- package/dist/evals/matchers.d.ts.map +1 -0
- package/dist/evals/matchers.js +145 -0
- package/dist/evals/reporters.d.ts +70 -0
- package/dist/evals/reporters.d.ts.map +1 -0
- package/dist/evals/reporters.js +221 -0
- package/dist/evals/results.d.ts +103 -0
- package/dist/evals/results.d.ts.map +1 -0
- package/dist/evals/results.js +28 -0
- package/dist/evals/run-facts.d.ts +77 -0
- package/dist/evals/run-facts.d.ts.map +1 -0
- package/dist/evals/run-facts.js +187 -0
- package/dist/evals.d.ts +136 -31
- package/dist/evals.d.ts.map +1 -1
- package/dist/evals.js +76 -12
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/cli-ax.d.ts +27 -0
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +90 -12
- package/dist/internal/cli-mcp.d.ts +8 -0
- package/dist/internal/cli-mcp.d.ts.map +1 -1
- package/dist/internal/cli-mcp.js +98 -0
- package/dist/internal/cli-slack.d.ts +29 -1
- package/dist/internal/cli-slack.d.ts.map +1 -1
- package/dist/internal/cli-slack.js +777 -12
- package/dist/internal/deploy-client.d.ts +7 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +9 -0
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +29 -9
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +2 -0
- package/dist/internal/eval-judge-model.d.ts +59 -0
- package/dist/internal/eval-judge-model.d.ts.map +1 -0
- package/dist/internal/eval-judge-model.js +131 -0
- package/dist/internal/eval-run-store.d.ts.map +1 -1
- package/dist/internal/eval-run-store.js +12 -20
- package/dist/internal/eval-runner.d.ts +31 -25
- package/dist/internal/eval-runner.d.ts.map +1 -1
- package/dist/internal/eval-runner.js +332 -128
- package/dist/internal/evals-client.d.ts.map +1 -1
- package/dist/internal/evals-client.js +7 -3
- package/dist/internal/local-env.d.ts +8 -0
- package/dist/internal/local-env.d.ts.map +1 -0
- package/dist/internal/local-env.js +47 -0
- package/dist/internal/playground/static.d.ts +3 -0
- package/dist/internal/playground/static.d.ts.map +1 -1
- package/dist/internal/playground/static.js +3 -0
- package/dist/internal/run-client.d.ts +15 -0
- package/dist/internal/run-client.d.ts.map +1 -1
- package/dist/internal/run-client.js +3 -2
- package/dist/internal/sdk-runner.d.ts +36 -1
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +65 -25
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +10 -1
- package/dist/internal/session-engine.d.ts +18 -5
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +72 -19
- package/dist/internal/slack-provision-client.d.ts +130 -0
- package/dist/internal/slack-provision-client.d.ts.map +1 -0
- package/dist/internal/slack-provision-client.js +284 -0
- package/dist/playground/assets/cursor-icons-16-f_W_ogc-.woff2 +0 -0
- package/dist/playground/assets/index-CidizGZv.css +1 -0
- package/dist/playground/assets/index-DNqirsrK.js +85 -0
- package/dist/playground/index.html +2 -2
- package/dist/types.d.ts +70 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +26 -0
- package/docs/example-agents/index.md +1 -1
- package/docs/example-agents/security-reviewer.md +23 -21
- package/docs/guides/mcp-oauth.md +10 -5
- package/docs/guides/slack.md +3 -2
- package/docs/reference/connections.md +28 -18
- package/package.json +20 -2
- package/skills/create-agent/SKILL.md +15 -7
- package/skills/debug/SKILL.md +3 -1
- package/skills/mcp-auth/SKILL.md +1 -1
- package/skills/setup-slack/SKILL.md +173 -11
- package/src/bin/agent-serve.ts +63 -2
- package/src/channels/slack/api.ts +16 -3
- package/src/channels/slack/auth.ts +16 -1
- package/src/channels/slack/blocks.ts +139 -0
- package/src/channels/slack/defaults.ts +32 -4
- package/src/channels/slack/dispatch.ts +3 -18
- package/src/channels/slack/index.ts +1 -0
- package/src/channels/slack/interactive.ts +183 -19
- package/src/channels/slack/manifest.ts +3 -0
- package/src/channels/slack/setup.ts +16 -2
- package/src/channels/slack/slack-channel.ts +37 -6
- package/src/channels/slack/types.ts +89 -0
- package/src/connections.ts +4 -1
- package/src/evals/assertions.ts +704 -0
- package/src/evals/expect.ts +272 -0
- package/src/evals/judge.ts +346 -0
- package/src/evals/loaders.ts +113 -0
- package/src/evals/matchers.ts +246 -0
- package/src/evals/reporters.ts +274 -0
- package/src/evals/results.ts +132 -0
- package/src/evals/run-facts.ts +274 -0
- package/src/evals.ts +249 -42
- package/src/index.ts +2 -0
- package/src/internal/cli-ax.ts +134 -15
- package/src/internal/cli-mcp.ts +118 -5
- package/src/internal/cli-slack.ts +993 -15
- package/src/internal/deploy-client.ts +10 -0
- package/src/internal/discovery.ts +31 -5
- package/src/internal/distribution.ts +2 -0
- package/src/internal/eval-judge-model.ts +148 -0
- package/src/internal/eval-run-store.ts +10 -14
- package/src/internal/eval-runner.ts +466 -215
- package/src/internal/evals-client.ts +14 -2
- package/src/internal/local-env.ts +53 -0
- package/src/internal/playground/static.ts +3 -0
- package/src/internal/run-client.ts +17 -1
- package/src/internal/sdk-runner.ts +103 -22
- package/src/internal/server.ts +10 -0
- package/src/internal/session-engine.ts +89 -21
- package/src/internal/slack-provision-client.ts +438 -0
- package/src/types.ts +92 -4
- package/dist/channels/slack/post-update-delivery.d.ts +0 -85
- package/dist/channels/slack/post-update-delivery.d.ts.map +0 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.D2d8CfFS.js +0 -1
- package/dist/docs/assets/example-agents_security-reviewer.md.CE9v-aKm.js +0 -19
- package/dist/internal/json-dir-store.d.ts +0 -32
- package/dist/internal/json-dir-store.d.ts.map +0 -1
- package/dist/internal/persistence-coordinator.d.ts +0 -127
- package/dist/internal/persistence-coordinator.d.ts.map +0 -1
- package/dist/persistence.d.ts +0 -184
- package/dist/persistence.d.ts.map +0 -1
- package/dist/playground/assets/cursor-icons-16-CQ50JpfO.woff2 +0 -0
- package/dist/playground/assets/index-BVMOoiek.js +0 -86
- package/dist/playground/assets/index-DYmP4b--.css +0 -1
- /package/dist/docs/assets/{guides_slack.md.FWale6Ip.lean.js → guides_slack.md.D_xFKlnF.lean.js} +0 -0
|
@@ -529,6 +529,16 @@ export class AgentServeDeployClient {
|
|
|
529
529
|
return `${this.backendUrl}${engineAlias}`;
|
|
530
530
|
}
|
|
531
531
|
|
|
532
|
+
/**
|
|
533
|
+
* Stable remote MCP gateway URL for a deployment, on the user-API-key
|
|
534
|
+
* surface (headless / CLI, `agentkit login` credential). The gateway
|
|
535
|
+
* mints/refreshes engineAccess server-side and proxies `/v1/mcp` to the
|
|
536
|
+
* pod, so a signed-in client never sees a pod hostname or port token.
|
|
537
|
+
*/
|
|
538
|
+
mcpGatewayUrl(teamId: number, slug: string): string {
|
|
539
|
+
return `${this.backendUrl}/internal/agent-serve/mcp/${teamId}/${encodeURIComponent(slug)}`;
|
|
540
|
+
}
|
|
541
|
+
|
|
532
542
|
private async request(args: {
|
|
533
543
|
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
534
544
|
path: string;
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
type ChannelDefinition,
|
|
30
30
|
type ConnectionDefinition,
|
|
31
31
|
type ConnectionTransport,
|
|
32
|
+
cursorAccountServersHasMixedWildcard,
|
|
32
33
|
DEFAULT_MODEL,
|
|
33
34
|
type Diagnostic,
|
|
34
35
|
type DiscoveredAB,
|
|
@@ -43,6 +44,7 @@ import {
|
|
|
43
44
|
type InstructionsDefinition,
|
|
44
45
|
MAX_RUNNING_TURNS_LIMIT,
|
|
45
46
|
type ModelSetting,
|
|
47
|
+
normalizeCursorAccountServers,
|
|
46
48
|
type ResolvedAgent,
|
|
47
49
|
type ScheduleDefinition,
|
|
48
50
|
type SeedFile,
|
|
@@ -368,11 +370,23 @@ async function loadAgent(
|
|
|
368
370
|
// `send({ cloud })` merges it under cloudOverride for handoff sessions.
|
|
369
371
|
const cloud = config?.cloud;
|
|
370
372
|
const localCwd = resolveAgentCwd(ctx, config?.local?.cwd);
|
|
373
|
+
const localWorkspaceDir = resolveAgentCwd(ctx, config?.local?.workspaceDir);
|
|
374
|
+
const localSandbox = config?.local?.sandbox === true;
|
|
375
|
+
if (localCwd !== undefined && localWorkspaceDir !== undefined) {
|
|
376
|
+
ctx.diagnostics.push({
|
|
377
|
+
severity: "warning",
|
|
378
|
+
path: displayPath(ctx, join(agentDir, "agent.ts")),
|
|
379
|
+
message:
|
|
380
|
+
"local.workspaceDir pins every session to one directory, so local.cwd is unused. Drop one of them.",
|
|
381
|
+
});
|
|
382
|
+
}
|
|
371
383
|
const local =
|
|
372
|
-
localCwd === undefined
|
|
384
|
+
localCwd === undefined && localWorkspaceDir === undefined && !localSandbox
|
|
373
385
|
? undefined
|
|
374
386
|
: {
|
|
375
387
|
cwd: localCwd,
|
|
388
|
+
workspaceDir: localWorkspaceDir,
|
|
389
|
+
sandbox: localSandbox,
|
|
376
390
|
};
|
|
377
391
|
const hosting = resolveHosting(ctx, agentDir, config?.hosting);
|
|
378
392
|
const concurrency = resolveConcurrency(ctx, agentDir, config?.concurrency);
|
|
@@ -889,11 +903,10 @@ function connectionTransport(
|
|
|
889
903
|
connection: ConnectionDefinition
|
|
890
904
|
): ConnectionTransport | undefined {
|
|
891
905
|
if ("cursorAccount" in connection && connection.cursorAccount === true) {
|
|
906
|
+
const servers = normalizeCursorAccountServers(connection.servers);
|
|
892
907
|
return {
|
|
893
908
|
cursorAccount: true,
|
|
894
|
-
...(
|
|
895
|
-
? {}
|
|
896
|
-
: { servers: connection.servers }),
|
|
909
|
+
...(servers === undefined ? {} : { servers }),
|
|
897
910
|
};
|
|
898
911
|
}
|
|
899
912
|
if ("agent" in connection && !isBlank(connection.agent)) {
|
|
@@ -1035,6 +1048,19 @@ async function loadConnections(
|
|
|
1035
1048
|
});
|
|
1036
1049
|
continue;
|
|
1037
1050
|
}
|
|
1051
|
+
if (
|
|
1052
|
+
"cursorAccount" in connection &&
|
|
1053
|
+
connection.cursorAccount === true &&
|
|
1054
|
+
cursorAccountServersHasMixedWildcard(connection.servers)
|
|
1055
|
+
) {
|
|
1056
|
+
ctx.diagnostics.push({
|
|
1057
|
+
severity: "error",
|
|
1058
|
+
path: displayPath(ctx, entryPath),
|
|
1059
|
+
message:
|
|
1060
|
+
'Cursor account MCP connection `servers` cannot mix `"*"` with connector names. Use `"*"` / `["*"]` (or omit `servers`) for every connected server, or list only concrete connector names.',
|
|
1061
|
+
});
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1038
1064
|
const transport = connectionTransport(connection);
|
|
1039
1065
|
if (transport === undefined) {
|
|
1040
1066
|
ctx.diagnostics.push({
|
|
@@ -1055,7 +1081,7 @@ async function loadConnections(
|
|
|
1055
1081
|
severity: "error",
|
|
1056
1082
|
path: displayPath(ctx, entryPath),
|
|
1057
1083
|
message:
|
|
1058
|
-
|
|
1084
|
+
'Cursor account MCP connection `servers` must be a non-empty list of connector names, `"*"` / `["*"]` for every connected server, or omitted for the same all-connectors behavior.',
|
|
1059
1085
|
});
|
|
1060
1086
|
continue;
|
|
1061
1087
|
}
|
|
@@ -102,6 +102,8 @@ export const AUTHORING_ENTRY_FILES: ReadonlyArray<
|
|
|
102
102
|
["hooks", "hooks.js"],
|
|
103
103
|
["prompt", "prompt.js"],
|
|
104
104
|
["evals", "evals.js"],
|
|
105
|
+
["evals/reporters", "evals/reporters.js"],
|
|
106
|
+
["evals/loaders", "evals/loaders.js"],
|
|
105
107
|
["ab", "ab.js"],
|
|
106
108
|
["storage", "storage.js"],
|
|
107
109
|
["storage/file-kv", "storage-backends/file-kv.js"],
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The model call behind `t.judge.*`.
|
|
3
|
+
*
|
|
4
|
+
* Grading is completion-only in intent: the judge reads a prompt and returns a
|
|
5
|
+
* choice. It is nonetheless a real SDK session, and its prompt embeds output
|
|
6
|
+
* from the agent under test — attacker-controlled text in exactly the way a
|
|
7
|
+
* prompt injection needs. A reply that talks the judge into running a tool would
|
|
8
|
+
* do so on the machine running the eval CLI, under the runner's credentials.
|
|
9
|
+
*
|
|
10
|
+
* The session is therefore confined on every axis the SDK exposes:
|
|
11
|
+
*
|
|
12
|
+
* - `sandboxOptions.enabled` so any tool call the judge is talked into is
|
|
13
|
+
* confined rather than run directly against the host.
|
|
14
|
+
* - `mcpServers: {}` so no MCP surface is reachable.
|
|
15
|
+
* - `settingSources: []` plus an empty temp `cwd`, so there is no repo to act on
|
|
16
|
+
* and no ambient `AGENTS.md` / `.cursor` rule can steer a verdict.
|
|
17
|
+
*
|
|
18
|
+
* The prompt side is hardened separately: `evals/judge.ts` fences untrusted
|
|
19
|
+
* content behind a per-call boundary. Both halves matter — this one limits blast
|
|
20
|
+
* radius, that one removes the instruction channel.
|
|
21
|
+
*
|
|
22
|
+
* Grading also declines outright when the credential's backend and the SDK's
|
|
23
|
+
* backend disagree, rather than sending a key somewhere it was not minted for
|
|
24
|
+
* (see {@link assertJudgeBackendMatch}).
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
28
|
+
import { tmpdir } from "node:os";
|
|
29
|
+
import { join } from "node:path";
|
|
30
|
+
import type { EvalJudgeCaller } from "../evals/judge.js";
|
|
31
|
+
import { EvalJudgeUnavailableError } from "../evals/judge.js";
|
|
32
|
+
import type { ModelSetting } from "../types.js";
|
|
33
|
+
import {
|
|
34
|
+
DEFAULT_CURSOR_BACKEND_URL,
|
|
35
|
+
resolveApiKey,
|
|
36
|
+
SIGN_IN_HINT,
|
|
37
|
+
} from "./cursor/credentials.js";
|
|
38
|
+
|
|
39
|
+
/** Env override for the default judge model (below `evals.config.ts`). */
|
|
40
|
+
export const EVAL_JUDGE_MODEL_ENV = "AGENTKIT_EVAL_JUDGE_MODEL";
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Backend the Cursor SDK will actually talk to.
|
|
44
|
+
*
|
|
45
|
+
* `Agent.create` takes a credential but no backend, so the SDK picks its own
|
|
46
|
+
* host from `CURSOR_API_BASE_URL`. Kept next to {@link assertJudgeBackendMatch}
|
|
47
|
+
* so the two stay in step if the SDK's resolution changes.
|
|
48
|
+
*/
|
|
49
|
+
function sdkBackendUrl(): string {
|
|
50
|
+
const configured = process.env.CURSOR_API_BASE_URL?.trim();
|
|
51
|
+
return trimTrailingSlash(
|
|
52
|
+
configured === undefined || configured === ""
|
|
53
|
+
? DEFAULT_CURSOR_BACKEND_URL
|
|
54
|
+
: configured
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function trimTrailingSlash(url: string): string {
|
|
59
|
+
return url.replace(/\/+$/, "");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Refuse to grade when the judge credential belongs to a different backend than
|
|
64
|
+
* the SDK will send it to.
|
|
65
|
+
*
|
|
66
|
+
* `resolveApiKey` resolves against `AGENT_SERVE_CURSOR_BACKEND_URL`, which the
|
|
67
|
+
* SDK does not read. When only that override is set, the key and the judge
|
|
68
|
+
* prompt — which embeds agent output — would go to the default host instead of
|
|
69
|
+
* the intended one. There is no backend field on `AgentOptions` to reconcile
|
|
70
|
+
* them, so the honest move is to decline rather than send a credential
|
|
71
|
+
* somewhere it was not minted for.
|
|
72
|
+
*/
|
|
73
|
+
export function assertJudgeBackendMatch(
|
|
74
|
+
credentialBackendUrl: string,
|
|
75
|
+
sdkBackend: string = sdkBackendUrl()
|
|
76
|
+
): void {
|
|
77
|
+
const credentialBackend = trimTrailingSlash(credentialBackendUrl);
|
|
78
|
+
if (credentialBackend === sdkBackend) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
throw new EvalJudgeUnavailableError(
|
|
82
|
+
`eval judge credential is scoped to ${credentialBackend}, but the Cursor SDK would send it to ${sdkBackend}. ` +
|
|
83
|
+
"Set CURSOR_API_BASE_URL to the same backend (the SDK does not read AGENT_SERVE_CURSOR_BACKEND_URL)."
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Resolve the judge model, innermost first: per-call → per-eval →
|
|
89
|
+
* `evals.config.ts` → {@link EVAL_JUDGE_MODEL_ENV}.
|
|
90
|
+
*/
|
|
91
|
+
export function resolveJudgeModel(layers: {
|
|
92
|
+
call?: ModelSetting;
|
|
93
|
+
evalLevel?: ModelSetting;
|
|
94
|
+
config?: ModelSetting;
|
|
95
|
+
env?: string | undefined;
|
|
96
|
+
}): ModelSetting | undefined {
|
|
97
|
+
const envModel = layers.env?.trim();
|
|
98
|
+
return (
|
|
99
|
+
layers.call ??
|
|
100
|
+
layers.evalLevel ??
|
|
101
|
+
layers.config ??
|
|
102
|
+
(envModel === undefined || envModel === "" ? undefined : envModel)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Ask the judge model for a grade.
|
|
108
|
+
*
|
|
109
|
+
* Throws {@link EvalJudgeUnavailableError} when no credentials are available so
|
|
110
|
+
* the runner can skip the eval visibly instead of reporting a spurious failure.
|
|
111
|
+
*/
|
|
112
|
+
export const callJudgeModel: EvalJudgeCaller = async ({ prompt, model }) => {
|
|
113
|
+
const resolved = await resolveApiKey();
|
|
114
|
+
if (resolved === undefined) {
|
|
115
|
+
throw new EvalJudgeUnavailableError(
|
|
116
|
+
`no Cursor credentials for the eval judge. ${SIGN_IN_HINT}`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
assertJudgeBackendMatch(resolved.backendUrl);
|
|
120
|
+
// Imported lazily so a tree of fully deterministic evals never loads the SDK.
|
|
121
|
+
const { Agent } = await import("@cursor/sdk");
|
|
122
|
+
const cwd = await mkdtemp(join(tmpdir(), "agentkit-eval-judge-"));
|
|
123
|
+
const agent = await Agent.create({
|
|
124
|
+
apiKey: resolved.apiKey,
|
|
125
|
+
model: typeof model === "string" ? { id: model } : model,
|
|
126
|
+
// See the module comment: grading embeds untrusted agent output, so the
|
|
127
|
+
// session gets no MCP surface, no ambient settings, an empty working
|
|
128
|
+
// directory, and a sandbox around anything it does attempt.
|
|
129
|
+
mcpServers: {},
|
|
130
|
+
local: {
|
|
131
|
+
cwd,
|
|
132
|
+
settingSources: [],
|
|
133
|
+
sandboxOptions: { enabled: true },
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
try {
|
|
137
|
+
const run = await agent.send(prompt);
|
|
138
|
+
const result = await run.wait();
|
|
139
|
+
if (result.status === "error" || result.status === "cancelled") {
|
|
140
|
+
const detail = result.error?.message ?? result.result ?? result.status;
|
|
141
|
+
throw new Error(`eval judge run failed: ${detail}`);
|
|
142
|
+
}
|
|
143
|
+
return result.result ?? "";
|
|
144
|
+
} finally {
|
|
145
|
+
agent.close();
|
|
146
|
+
await rm(cwd, { recursive: true, force: true }).catch(() => undefined);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
@@ -173,6 +173,8 @@ export class EvalRunStore {
|
|
|
173
173
|
summary: {
|
|
174
174
|
passed: 0,
|
|
175
175
|
failed: 0,
|
|
176
|
+
scored: 0,
|
|
177
|
+
skipped: 0,
|
|
176
178
|
total: cases.length,
|
|
177
179
|
done: 0,
|
|
178
180
|
},
|
|
@@ -474,6 +476,9 @@ export class EvalRunStore {
|
|
|
474
476
|
const alreadyCounted = c.status === "done";
|
|
475
477
|
c.status = "done";
|
|
476
478
|
c.ok = result.ok;
|
|
479
|
+
c.verdict = result.verdict;
|
|
480
|
+
c.skipReason = result.skipReason;
|
|
481
|
+
c.metadata = result.metadata;
|
|
477
482
|
c.assertions = result.assertions;
|
|
478
483
|
c.durationMs = result.durationMs;
|
|
479
484
|
c.logs = result.logs;
|
|
@@ -502,11 +507,8 @@ export class EvalRunStore {
|
|
|
502
507
|
return;
|
|
503
508
|
}
|
|
504
509
|
run.summary.done += 1;
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
} else {
|
|
508
|
-
run.summary.failed += 1;
|
|
509
|
-
}
|
|
510
|
+
const verdict = result.verdict ?? (result.ok ? "passed" : "failed");
|
|
511
|
+
run.summary[verdict] = (run.summary[verdict] ?? 0) + 1;
|
|
510
512
|
}
|
|
511
513
|
}
|
|
512
514
|
|
|
@@ -539,18 +541,12 @@ function markCancelledRun(run: EvalRunSnapshot): void {
|
|
|
539
541
|
}
|
|
540
542
|
|
|
541
543
|
function reconcileRunSummary(run: EvalRunSnapshot): void {
|
|
542
|
-
|
|
543
|
-
let failed = 0;
|
|
544
|
+
const counts = { passed: 0, failed: 0, scored: 0, skipped: 0 };
|
|
544
545
|
for (const c of run.cases) {
|
|
545
|
-
|
|
546
|
-
passed += 1;
|
|
547
|
-
} else {
|
|
548
|
-
failed += 1;
|
|
549
|
-
}
|
|
546
|
+
counts[c.verdict ?? (c.ok === true ? "passed" : "failed")] += 1;
|
|
550
547
|
}
|
|
551
548
|
run.summary = {
|
|
552
|
-
|
|
553
|
-
failed,
|
|
549
|
+
...counts,
|
|
554
550
|
total: run.cases.length,
|
|
555
551
|
done: run.cases.length,
|
|
556
552
|
};
|