@cursor/july 0.1.9 → 0.1.11
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/AGENTS.md +1 -0
- package/dist/bin/agent-serve.js +26 -3
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +2 -1
- package/dist/channels/github/types.d.ts +4 -0
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/slack/cursor-account.d.ts.map +1 -1
- package/dist/channels/slack/cursor-account.js +1 -1
- package/dist/channels/slack/dispatch.d.ts +13 -0
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +36 -11
- package/dist/channels/slack/eval-directive.d.ts +63 -0
- package/dist/channels/slack/eval-directive.d.ts.map +1 -0
- package/dist/channels/slack/eval-directive.js +283 -0
- 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/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +4 -2
- package/dist/channels/slack/types.d.ts +7 -0
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/connections.d.ts +10 -5
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +10 -5
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.Ciosf24M.js → app.BcXUGca7.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.BIbvK8M1.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BcRDly7n.js → VPLocalSearchBox.CWur6XGZ.js} +1 -1
- package/dist/docs/assets/chunks/{theme.CMpbjdfx.js → theme.BnvulOX2.js} +2 -2
- package/dist/docs/assets/{deployment.md.DC5-ImcM.js → deployment.md.TecHo0_2.js} +3 -3
- package/dist/docs/assets/{deployment.md.DC5-ImcM.lean.js → deployment.md.TecHo0_2.lean.js} +1 -1
- package/dist/docs/assets/guides_mcp-oauth.md.DqmEOQY1.js +29 -0
- package/dist/docs/assets/guides_mcp-oauth.md.DqmEOQY1.lean.js +1 -0
- package/dist/docs/assets/{index.md.COiu-1jL.js → index.md.t0TM2Qzz.js} +3 -3
- package/dist/docs/assets/{index.md.COiu-1jL.lean.js → index.md.t0TM2Qzz.lean.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.D189RBCH.js → reference_cli.md.B74NrVzb.js} +5 -4
- package/dist/docs/assets/{reference_cli.md.D189RBCH.lean.js → reference_cli.md.B74NrVzb.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.zaEYCLHT.js → reference_connections.md.CsSr3rDz.js} +9 -4
- package/dist/docs/assets/{reference_connections.md.zaEYCLHT.lean.js → reference_connections.md.CsSr3rDz.lean.js} +1 -1
- package/dist/docs/assets/reference_prompt.md.BaiweQxE.js +1 -0
- package/dist/docs/assets/reference_prompt.md.BaiweQxE.lean.js +1 -0
- package/dist/docs/assets/{reference_tools.md.CqgJroI0.js → reference_tools.md.BRSDnTbN.js} +16 -3
- package/dist/docs/assets/{reference_tools.md.CqgJroI0.lean.js → reference_tools.md.BRSDnTbN.lean.js} +1 -1
- package/dist/docs/assets/{troubleshooting.md.DkovjS7h.js → troubleshooting.md.CmQkmnzC.js} +1 -1
- package/dist/docs/assets/{troubleshooting.md.DkovjS7h.lean.js → troubleshooting.md.CmQkmnzC.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +7 -7
- package/dist/docs/evals.html +4 -4
- package/dist/docs/example-agents/approval-buddy.html +4 -4
- package/dist/docs/example-agents/benny.html +4 -4
- package/dist/docs/example-agents/bugbot.html +4 -4
- package/dist/docs/example-agents/codebase-wiki.html +4 -4
- package/dist/docs/example-agents/codeowners-review.html +4 -4
- package/dist/docs/example-agents/concierge.html +4 -4
- package/dist/docs/example-agents/fsd.html +4 -4
- package/dist/docs/example-agents/index.html +4 -4
- package/dist/docs/example-agents/knowledge-base.html +4 -4
- package/dist/docs/example-agents/oncall.html +4 -4
- package/dist/docs/example-agents/security-reviewer.html +4 -4
- package/dist/docs/example-agents/slack-agent.html +4 -4
- package/dist/docs/example-agents/weather-agent.html +4 -4
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/cloud-runtime.html +4 -4
- package/dist/docs/guides/github.html +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +53 -0
- package/dist/docs/guides/slack.html +4 -4
- package/dist/docs/guides/webhooks.html +4 -4
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +4 -4
- package/dist/docs/index.html +6 -6
- package/dist/docs/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.html +4 -4
- package/dist/docs/reference/channels.html +4 -4
- package/dist/docs/reference/cli.html +8 -7
- package/dist/docs/reference/connections.html +13 -8
- package/dist/docs/reference/hooks.html +4 -4
- package/dist/docs/reference/http-api.html +4 -4
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +4 -4
- package/dist/docs/reference/prompt.html +33 -0
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +4 -4
- package/dist/docs/reference/skills.html +5 -5
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +20 -7
- package/dist/docs/scaffolding-agents.html +4 -4
- package/dist/docs/storage.html +4 -4
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/evals.d.ts +39 -0
- package/dist/evals.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +7 -4
- package/dist/internal/cli-mcp-oauth.d.ts +16 -0
- package/dist/internal/cli-mcp-oauth.d.ts.map +1 -0
- package/dist/internal/cli-mcp-oauth.js +194 -0
- package/dist/internal/cli-mcp.d.ts +4 -1
- package/dist/internal/cli-mcp.d.ts.map +1 -1
- package/dist/internal/cli-mcp.js +19 -1
- package/dist/internal/corp-ca.d.ts +9 -0
- package/dist/internal/corp-ca.d.ts.map +1 -0
- package/dist/internal/corp-ca.js +44 -0
- package/dist/internal/cursor/account-mcp.d.ts +17 -4
- package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
- package/dist/internal/cursor/account-mcp.js +105 -17
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +64 -10
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +1 -0
- package/dist/internal/logs-client.js +1 -1
- package/dist/internal/mcp-host.d.ts.map +1 -1
- package/dist/internal/mcp-host.js +49 -26
- package/dist/internal/mcp-oauth.d.ts +88 -0
- package/dist/internal/mcp-oauth.d.ts.map +1 -0
- package/dist/internal/mcp-oauth.js +385 -0
- package/dist/internal/resolved-connections.d.ts +6 -0
- package/dist/internal/resolved-connections.d.ts.map +1 -1
- package/dist/internal/resolved-connections.js +10 -3
- package/dist/internal/sdk-runner.d.ts +9 -0
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +28 -2
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +24 -6
- package/dist/internal/session-engine.d.ts +30 -10
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +166 -74
- package/dist/internal/sessions-client.d.ts +16 -2
- package/dist/internal/sessions-client.d.ts.map +1 -1
- package/dist/internal/sessions-client.js +30 -13
- package/dist/internal/storage-coordinator.d.ts +11 -0
- package/dist/internal/storage-coordinator.d.ts.map +1 -1
- package/dist/internal/storage-coordinator.js +30 -0
- package/dist/internal/stream-progress.d.ts.map +1 -1
- package/dist/internal/stream-progress.js +8 -4
- package/dist/internal/turn-governor.d.ts +54 -0
- package/dist/internal/turn-governor.d.ts.map +1 -0
- package/dist/internal/turn-governor.js +111 -0
- package/dist/playground/assets/{index-C0-QEG4O.js → index-BIGLubwK.js} +46 -46
- package/dist/playground/assets/{index-z3JY9O2x.css → index-C17ZQKDG.css} +1 -1
- package/dist/playground/index.html +2 -2
- package/dist/prompt.d.ts +39 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +70 -0
- package/dist/storage-backends/cursor-hosted.d.ts +10 -0
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +14 -0
- package/dist/types.d.ts +93 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -0
- package/docs/README.md +4 -0
- package/docs/deployment.md +6 -1
- package/docs/guides/mcp-oauth.md +157 -0
- package/docs/reference/cli.md +30 -0
- package/docs/reference/connections.md +32 -2
- package/docs/reference/prompt.md +47 -0
- package/docs/reference/tools.md +21 -0
- package/docs/troubleshooting.md +11 -0
- package/package.json +9 -2
- package/skills/create-agent/SKILL.md +7 -3
- package/skills/framework-map/SKILL.md +1 -0
- package/skills/mcp-auth/SKILL.md +138 -0
- package/src/bin/agent-serve.ts +30 -3
- package/src/channels/github/github-channel.ts +2 -0
- package/src/channels/github/types.ts +4 -0
- package/src/channels/slack/cursor-account.ts +2 -0
- package/src/channels/slack/dispatch.ts +49 -0
- package/src/channels/slack/eval-directive.ts +348 -0
- package/src/channels/slack/index.ts +1 -0
- package/src/channels/slack/slack-channel.ts +3 -0
- package/src/channels/slack/types.ts +7 -0
- package/src/connections.ts +10 -5
- package/src/evals.ts +43 -0
- package/src/index.ts +3 -0
- package/src/internal/cli-ax.ts +10 -4
- package/src/internal/cli-mcp-oauth.ts +254 -0
- package/src/internal/cli-mcp.ts +25 -2
- package/src/internal/cursor/account-mcp.ts +153 -41
- package/src/internal/discovery.ts +70 -8
- package/src/internal/distribution.ts +1 -0
- package/src/internal/logs-client.ts +1 -1
- package/src/internal/mcp-host.ts +33 -9
- package/src/internal/mcp-oauth.ts +496 -0
- package/src/internal/resolved-connections.ts +20 -5
- package/src/internal/sdk-runner.ts +37 -1
- package/src/internal/server.ts +28 -6
- package/src/internal/session-engine.ts +192 -76
- package/src/internal/sessions-client.ts +51 -15
- package/src/internal/storage-coordinator.ts +36 -0
- package/src/internal/stream-progress.ts +8 -0
- package/src/internal/turn-governor.ts +145 -0
- package/src/prompt.ts +83 -0
- package/src/storage-backends/cursor-hosted.ts +21 -0
- package/src/types.ts +92 -6
- package/dist/docs/assets/chunks/@localSearchIndexroot.D154Detj.js +0 -1
package/src/bin/agent-serve.ts
CHANGED
|
@@ -51,7 +51,10 @@ import {
|
|
|
51
51
|
cmdStop,
|
|
52
52
|
type DeployCliOptions,
|
|
53
53
|
} from "../internal/cli-deploy.js";
|
|
54
|
-
import {
|
|
54
|
+
import {
|
|
55
|
+
CLI_COMMAND_NAME as CLI,
|
|
56
|
+
packageVersion,
|
|
57
|
+
} from "../internal/distribution.js";
|
|
55
58
|
import { clearTerminal, stdoutPalette } from "../internal/terminal-style.js";
|
|
56
59
|
import { cmdUpdate, warnIfOutdated } from "../internal/update-check.js";
|
|
57
60
|
import type { AgentProject, AgentServeHandle } from "../types.js";
|
|
@@ -93,6 +96,7 @@ Usage:
|
|
|
93
96
|
| --url <baseUrl> [--bearer-token <t>]
|
|
94
97
|
${CLI} mcp install [--name <serverName>] [--print] [--json]
|
|
95
98
|
(same target flags as mcp)
|
|
99
|
+
${CLI} mcp oauth <connection> [--dir <path>] [--store] [--slug <slug>]
|
|
96
100
|
${CLI} eval [--dir <path>] [evalId...] [--list] [--json]
|
|
97
101
|
[--tag <tag>]... [--verbose] [--timeout-ms <n>]
|
|
98
102
|
[--no-stream] [--no-wait]
|
|
@@ -106,6 +110,7 @@ Usage:
|
|
|
106
110
|
${CLI} logout
|
|
107
111
|
${CLI} whoami [--json]
|
|
108
112
|
${CLI} update
|
|
113
|
+
${CLI} version
|
|
109
114
|
${CLI} deploy [--dir <path>] [--slug <slug> | --all] [--team <id>] [--json]
|
|
110
115
|
[--no-wait] [--repo <url>] [--ref <ref>]
|
|
111
116
|
[--path <agentPath>] [--cursor-events-repo <owner/name>]...
|
|
@@ -170,7 +175,9 @@ Commands:
|
|
|
170
175
|
--url targets a running server. stdout is reserved for the
|
|
171
176
|
MCP wire. \`mcp install\` writes the matching entry into
|
|
172
177
|
~/.cursor/mcp.json (--print to preview; --name to override
|
|
173
|
-
the server name).
|
|
178
|
+
the server name). \`mcp oauth <connection>\` runs host PKCE
|
|
179
|
+
for defineConnection({ url, oauth: true }); \`--store\` upserts
|
|
180
|
+
MCP_OAUTH_<NAME>_* secrets on the hosted deployment.
|
|
174
181
|
eval Run filesystem evals under evals/**/*.eval.ts (streams on a TTY).
|
|
175
182
|
Default: ephemeral local harness against evals on disk. Pass
|
|
176
183
|
--prod to kick off the batch on the team's hosted deployment
|
|
@@ -194,6 +201,7 @@ Commands:
|
|
|
194
201
|
whoami Show which Cursor account powers this host (and why).
|
|
195
202
|
update Upgrade this install to the latest published version (detects
|
|
196
203
|
global npm/pnpm/yarn/bun installs and project dependencies).
|
|
204
|
+
version Print the installed ${CLI} version and exit (also --version / -V).
|
|
197
205
|
deploy Deploy onto Cursor's managed agent-serve hosting, then wait for
|
|
198
206
|
the engine to come up. --repo/--ref/--path stay available;
|
|
199
207
|
inside an agent git checkout they are inferred when omitted
|
|
@@ -224,6 +232,7 @@ Agent loop:
|
|
|
224
232
|
${CLI} dev .
|
|
225
233
|
|
|
226
234
|
Options:
|
|
235
|
+
--version, -V Print the installed version and exit.
|
|
227
236
|
--dir Project root (defaults to the current directory).
|
|
228
237
|
--port Port to listen on (default 3000).
|
|
229
238
|
--host Host to bind (default 127.0.0.1).
|
|
@@ -247,6 +256,11 @@ Options:
|
|
|
247
256
|
githubChannel({ cursorAccount }). Admitted callers can drive
|
|
248
257
|
sessions holding the account's repo-scoped GitHub credential,
|
|
249
258
|
so use only behind a trusted boundary (e.g. an SSO proxy).
|
|
259
|
+
--allow-anonymous-cursor-account-mcp
|
|
260
|
+
serve: allow --allow-anonymous together with
|
|
261
|
+
defineConnection({ cursorAccount: true }). Admitted callers
|
|
262
|
+
can drive the account's MCP connectors, so use only behind
|
|
263
|
+
a trusted boundary (e.g. an SSO proxy or hosted alias token).
|
|
250
264
|
--public-url serve: base URL where this host is reachable from outside
|
|
251
265
|
(e.g. https://agent-serve.example.com). Required for peer
|
|
252
266
|
connections (defineConnection({ agent })) on cloud-runtime
|
|
@@ -349,6 +363,10 @@ async function main(argv: string[]): Promise<number> {
|
|
|
349
363
|
process.stdout.write(HELP);
|
|
350
364
|
return command === undefined ? 1 : 0;
|
|
351
365
|
}
|
|
366
|
+
if (command === "version" || command === "--version" || command === "-V") {
|
|
367
|
+
process.stdout.write(`${CLI} ${packageVersion()}\n`);
|
|
368
|
+
return 0;
|
|
369
|
+
}
|
|
352
370
|
|
|
353
371
|
// `session --events` means "dump raw events" (boolean). Rewrite so it does
|
|
354
372
|
// not collide with run/trajectory's `--events <file.ndjson>` string flag.
|
|
@@ -372,6 +390,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
372
390
|
"bearer-token": { type: "string" },
|
|
373
391
|
"allow-anonymous": { type: "boolean", default: false },
|
|
374
392
|
"allow-anonymous-cursor-github": { type: "boolean", default: false },
|
|
393
|
+
"allow-anonymous-cursor-account-mcp": { type: "boolean", default: false },
|
|
375
394
|
"no-schedules": { type: "boolean", default: false },
|
|
376
395
|
"no-playground": { type: "boolean", default: false },
|
|
377
396
|
"no-docs": { type: "boolean", default: false },
|
|
@@ -403,6 +422,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
403
422
|
"mount-path": { type: "string" },
|
|
404
423
|
"base-url": { type: "string" },
|
|
405
424
|
print: { type: "boolean", default: false },
|
|
425
|
+
store: { type: "boolean", default: false },
|
|
406
426
|
transport: { type: "string" },
|
|
407
427
|
prefix: { type: "string" },
|
|
408
428
|
"no-prefix": { type: "boolean", default: false },
|
|
@@ -502,7 +522,8 @@ async function main(argv: string[]): Promise<number> {
|
|
|
502
522
|
|
|
503
523
|
case "mcp": {
|
|
504
524
|
const { cmdMcp } = await import("../internal/cli-mcp.js");
|
|
505
|
-
|
|
525
|
+
const mcpSub = positionals[0];
|
|
526
|
+
return cmdMcp(mcpSub, {
|
|
506
527
|
dir,
|
|
507
528
|
slug: values.slug,
|
|
508
529
|
team: values.team,
|
|
@@ -513,6 +534,8 @@ async function main(argv: string[]): Promise<number> {
|
|
|
513
534
|
name: values.name,
|
|
514
535
|
print: values.print,
|
|
515
536
|
json: values.json,
|
|
537
|
+
store: values.store,
|
|
538
|
+
oauthConnection: mcpSub === "oauth" ? positionals[1] : undefined,
|
|
516
539
|
});
|
|
517
540
|
}
|
|
518
541
|
|
|
@@ -976,6 +999,10 @@ async function main(argv: string[]): Promise<number> {
|
|
|
976
999
|
allowAnonymous: values["allow-anonymous"] === true ? true : undefined,
|
|
977
1000
|
allowAnonymousCursorGithub:
|
|
978
1001
|
values["allow-anonymous-cursor-github"] === true ? true : undefined,
|
|
1002
|
+
allowAnonymousCursorAccountMcp:
|
|
1003
|
+
values["allow-anonymous-cursor-account-mcp"] === true
|
|
1004
|
+
? true
|
|
1005
|
+
: undefined,
|
|
979
1006
|
schedules: values["no-schedules"] === true ? false : undefined,
|
|
980
1007
|
playground: values["no-playground"] === true ? false : undefined,
|
|
981
1008
|
docs: values["no-docs"] === true ? false : undefined,
|
|
@@ -116,6 +116,7 @@ const githubPullRequestPayloadSchema: z.ZodType<GitHubPullRequestPayload> =
|
|
|
116
116
|
title: z.string(),
|
|
117
117
|
body: z.string().nullable().optional(),
|
|
118
118
|
draft: z.boolean().optional(),
|
|
119
|
+
merged: z.boolean().optional(),
|
|
119
120
|
user: z
|
|
120
121
|
.object({
|
|
121
122
|
login: z.string().min(1).optional(),
|
|
@@ -330,6 +331,7 @@ export function parseGitHubPullRequestEvent(args: {
|
|
|
330
331
|
? {}
|
|
331
332
|
: { baseSha: payload.pull_request.base.sha }),
|
|
332
333
|
draft: payload.pull_request.draft ?? false,
|
|
334
|
+
merged: payload.pull_request.merged === true,
|
|
333
335
|
...(payload.pull_request.user?.login === undefined
|
|
334
336
|
? {}
|
|
335
337
|
: { authorLogin: payload.pull_request.user.login }),
|
|
@@ -148,6 +148,8 @@ export type GitHubPullRequestPayload = {
|
|
|
148
148
|
title: string;
|
|
149
149
|
body?: string | null;
|
|
150
150
|
draft?: boolean;
|
|
151
|
+
/** Present on real webhook payloads; false/undefined when not merged. */
|
|
152
|
+
merged?: boolean;
|
|
151
153
|
user?: {
|
|
152
154
|
login?: string;
|
|
153
155
|
id?: number;
|
|
@@ -182,6 +184,8 @@ export interface GitHubPullRequestEvent {
|
|
|
182
184
|
baseRef: string;
|
|
183
185
|
baseSha?: string;
|
|
184
186
|
draft: boolean;
|
|
187
|
+
/** True when the PR was merged (from the webhook payload). */
|
|
188
|
+
merged: boolean;
|
|
185
189
|
authorLogin?: string;
|
|
186
190
|
}
|
|
187
191
|
|
|
@@ -167,6 +167,8 @@ export async function dispatchCursorSlackEnvelope(args: {
|
|
|
167
167
|
credentials: runtime.credentials,
|
|
168
168
|
host: args.host,
|
|
169
169
|
log,
|
|
170
|
+
evalCommandsEnabled: runtime.options.evalCommands !== false,
|
|
171
|
+
cursorAgentName: envelope.agentName,
|
|
170
172
|
...(args.hasContinuationSession === undefined
|
|
171
173
|
? {}
|
|
172
174
|
: { hasContinuationSession: args.hasContinuationSession }),
|
|
@@ -6,6 +6,10 @@ import type { HostContext, JsonValue, SendMessageFn } from "../../types.js";
|
|
|
6
6
|
import { buildSlackBinding, slackContinuationKey } from "./api.js";
|
|
7
7
|
import { firstLineTitle, maybeSetThreadTitle } from "./assistant.js";
|
|
8
8
|
import type { ChannelPostWatcher } from "./channel-watch.js";
|
|
9
|
+
import {
|
|
10
|
+
handleSlackEvalDirective,
|
|
11
|
+
parseSlackEvalDirective,
|
|
12
|
+
} from "./eval-directive.js";
|
|
9
13
|
import type { EventIdDedupe } from "./event-id-dedupe.js";
|
|
10
14
|
import {
|
|
11
15
|
formatSlackContextBlock,
|
|
@@ -82,6 +86,13 @@ export interface SlackInboundDispatchDeps {
|
|
|
82
86
|
) => Promise<string | undefined>;
|
|
83
87
|
/** Cancel the active turn + clear coalesced nudges for this continuation. */
|
|
84
88
|
interruptContinuation?: (continuationToken: string) => Promise<boolean>;
|
|
89
|
+
/**
|
|
90
|
+
* When false, skip the built-in `eval` directive. Defaults to true when
|
|
91
|
+
* `host.evals` is present.
|
|
92
|
+
*/
|
|
93
|
+
evalCommandsEnabled?: boolean;
|
|
94
|
+
/** cursorAccount agent name stripped before `eval` directive parsing. */
|
|
95
|
+
cursorAgentName?: string;
|
|
85
96
|
}
|
|
86
97
|
|
|
87
98
|
function triggeringMergeMessage(
|
|
@@ -114,6 +125,12 @@ export async function dispatchInboundMessage(args: {
|
|
|
114
125
|
interruptContinuation?: (continuationToken: string) => Promise<boolean>;
|
|
115
126
|
log?: SlackLog;
|
|
116
127
|
eventId?: string;
|
|
128
|
+
evalCommandsEnabled?: boolean;
|
|
129
|
+
/**
|
|
130
|
+
* cursorAccount agent display name — stripped before parsing `eval …`
|
|
131
|
+
* (`OncallBuddy eval list`).
|
|
132
|
+
*/
|
|
133
|
+
cursorAgentName?: string;
|
|
117
134
|
}): Promise<void> {
|
|
118
135
|
const { message, kind } = args;
|
|
119
136
|
const log = args.log ?? defaultSlackLog;
|
|
@@ -168,6 +185,34 @@ export async function dispatchInboundMessage(args: {
|
|
|
168
185
|
return;
|
|
169
186
|
}
|
|
170
187
|
|
|
188
|
+
// Built-in eval directive: run playground batches without an agent turn.
|
|
189
|
+
const evalCommandsEnabled = args.evalCommandsEnabled !== false;
|
|
190
|
+
const evalParseOptions =
|
|
191
|
+
args.cursorAgentName === undefined || args.cursorAgentName === ""
|
|
192
|
+
? undefined
|
|
193
|
+
: { agentName: args.cursorAgentName };
|
|
194
|
+
const evalDirective =
|
|
195
|
+
evalCommandsEnabled && args.host.evals !== undefined
|
|
196
|
+
? (parseSlackEvalDirective(message.text, evalParseOptions) ??
|
|
197
|
+
parseSlackEvalDirective(message.markdown, evalParseOptions))
|
|
198
|
+
: null;
|
|
199
|
+
if (evalDirective !== null && args.host.evals !== undefined) {
|
|
200
|
+
log.info("eval directive", {
|
|
201
|
+
kind,
|
|
202
|
+
channel: message.channelId,
|
|
203
|
+
thread_ts: message.threadTs,
|
|
204
|
+
continuation,
|
|
205
|
+
event_id: args.eventId,
|
|
206
|
+
directive: evalDirective.kind,
|
|
207
|
+
});
|
|
208
|
+
await handleSlackEvalDirective({
|
|
209
|
+
directive: evalDirective,
|
|
210
|
+
evals: args.host.evals,
|
|
211
|
+
binding,
|
|
212
|
+
});
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
171
216
|
if (message.ts === message.threadTs) {
|
|
172
217
|
await maybeSetThreadTitle({
|
|
173
218
|
botToken: args.credentials?.botToken,
|
|
@@ -393,6 +438,8 @@ export function dispatchInboundFromEventBody(
|
|
|
393
438
|
credentials: deps.credentials,
|
|
394
439
|
host: deps.host,
|
|
395
440
|
log,
|
|
441
|
+
evalCommandsEnabled: deps.evalCommandsEnabled,
|
|
442
|
+
cursorAgentName: deps.cursorAgentName,
|
|
396
443
|
...(deps.hasContinuationSession === undefined
|
|
397
444
|
? {}
|
|
398
445
|
: { hasContinuationSession: deps.hasContinuationSession }),
|
|
@@ -431,6 +478,8 @@ export function dispatchInboundFromEventBody(
|
|
|
431
478
|
credentials: deps.credentials,
|
|
432
479
|
host: deps.host,
|
|
433
480
|
log,
|
|
481
|
+
evalCommandsEnabled: deps.evalCommandsEnabled,
|
|
482
|
+
cursorAgentName: deps.cursorAgentName,
|
|
434
483
|
...(deps.hasContinuationSession === undefined
|
|
435
484
|
? {}
|
|
436
485
|
: { hasContinuationSession: deps.hasContinuationSession }),
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in Slack `eval` directive — run playground evals from a mention/DM
|
|
3
|
+
* without per-agent custom handlers (parity with CLI / playground runs).
|
|
4
|
+
*
|
|
5
|
+
* Examples (after stripping @mentions / cursorAccount agent name):
|
|
6
|
+
* eval
|
|
7
|
+
* eval triage/open-incidents smoke
|
|
8
|
+
* eval --tag oncall
|
|
9
|
+
* eval list
|
|
10
|
+
* eval status
|
|
11
|
+
* eval help
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { EvalRunSnapshot, HostEvalsApi } from "../../evals.js";
|
|
15
|
+
import {
|
|
16
|
+
EvalRunConflictError,
|
|
17
|
+
EvalRunEmptyError,
|
|
18
|
+
} from "../../internal/eval-run-store.js";
|
|
19
|
+
import { stripLeadingSlackMentions } from "./stop.js";
|
|
20
|
+
import type { SlackBinding } from "./types.js";
|
|
21
|
+
|
|
22
|
+
const EVAL_POLL_MS = 2_000;
|
|
23
|
+
const TYPING_STATUS_MAX = 50;
|
|
24
|
+
|
|
25
|
+
export type SlackEvalDirective =
|
|
26
|
+
| { kind: "help" }
|
|
27
|
+
| { kind: "list" }
|
|
28
|
+
| { kind: "status" }
|
|
29
|
+
| { kind: "run"; filterIds?: string[]; tags?: string[] };
|
|
30
|
+
|
|
31
|
+
function escapeRegExp(value: string): string {
|
|
32
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Normalize inbound Slack text for directive parsing: strip leading
|
|
37
|
+
* `<@U…>` mentions, leading `@U…` markdown mentions, and an optional
|
|
38
|
+
* cursorAccount agentName prefix (`OncallBuddy eval …`).
|
|
39
|
+
*/
|
|
40
|
+
export function normalizeSlackEvalDirectiveBody(
|
|
41
|
+
text: string,
|
|
42
|
+
options?: { agentName?: string }
|
|
43
|
+
): string {
|
|
44
|
+
let body = stripLeadingSlackMentions(text);
|
|
45
|
+
// markdown form from slackTextToMarkdown / cursorAccount envelopes
|
|
46
|
+
while (/^@[A-Za-z0-9._-]+\s+/.test(body)) {
|
|
47
|
+
body = body.replace(/^@[A-Za-z0-9._-]+\s+/, "").trim();
|
|
48
|
+
}
|
|
49
|
+
const agentName = options?.agentName?.trim();
|
|
50
|
+
if (agentName !== undefined && agentName.length > 0) {
|
|
51
|
+
const prefix = new RegExp(`^${escapeRegExp(agentName)}\\s+`, "i");
|
|
52
|
+
body = body.replace(prefix, "").trim();
|
|
53
|
+
}
|
|
54
|
+
return body;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Parse a Slack eval directive. Returns null when the message is not an
|
|
59
|
+
* eval command (falls through to the normal agent handler).
|
|
60
|
+
*/
|
|
61
|
+
export function parseSlackEvalDirective(
|
|
62
|
+
text: string,
|
|
63
|
+
options?: { agentName?: string }
|
|
64
|
+
): SlackEvalDirective | null {
|
|
65
|
+
const body = normalizeSlackEvalDirectiveBody(text, options);
|
|
66
|
+
if (body.length === 0) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const tokens = body.split(/\s+/).filter((t) => t.length > 0);
|
|
70
|
+
if (tokens.length === 0 || !/^eval$/i.test(tokens[0] ?? "")) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const rest = tokens.slice(1);
|
|
75
|
+
if (rest.length === 0) {
|
|
76
|
+
return { kind: "run" };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const head = (rest[0] ?? "").toLowerCase();
|
|
80
|
+
if (
|
|
81
|
+
rest.length === 1 &&
|
|
82
|
+
(head === "help" || head === "-h" || head === "--help")
|
|
83
|
+
) {
|
|
84
|
+
return { kind: "help" };
|
|
85
|
+
}
|
|
86
|
+
if (rest.length === 1 && (head === "list" || head === "ls")) {
|
|
87
|
+
return { kind: "list" };
|
|
88
|
+
}
|
|
89
|
+
if (rest.length === 1 && head === "status") {
|
|
90
|
+
return { kind: "status" };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const filterIds: string[] = [];
|
|
94
|
+
const tags: string[] = [];
|
|
95
|
+
for (let i = 0; i < rest.length; i++) {
|
|
96
|
+
const tok = rest[i] ?? "";
|
|
97
|
+
if (tok === "--tag" || tok === "-t") {
|
|
98
|
+
const value = rest[i + 1];
|
|
99
|
+
if (value === undefined || value.length === 0) {
|
|
100
|
+
return { kind: "help" };
|
|
101
|
+
}
|
|
102
|
+
tags.push(value);
|
|
103
|
+
i += 1;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (tok.startsWith("--tag=")) {
|
|
107
|
+
const value = tok.slice("--tag=".length);
|
|
108
|
+
if (value.length === 0) {
|
|
109
|
+
return { kind: "help" };
|
|
110
|
+
}
|
|
111
|
+
tags.push(value);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (tok.startsWith("-t=") && tok.length > 3) {
|
|
115
|
+
tags.push(tok.slice(3));
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (tok.startsWith("-")) {
|
|
119
|
+
// Unknown flag — surface help rather than treating as an eval id.
|
|
120
|
+
return { kind: "help" };
|
|
121
|
+
}
|
|
122
|
+
filterIds.push(tok);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const run: SlackEvalDirective = { kind: "run" };
|
|
126
|
+
if (filterIds.length > 0) {
|
|
127
|
+
run.filterIds = filterIds;
|
|
128
|
+
}
|
|
129
|
+
if (tags.length > 0) {
|
|
130
|
+
run.tags = tags;
|
|
131
|
+
}
|
|
132
|
+
return run;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** True when either raw Slack text or markdown form is an eval directive. */
|
|
136
|
+
export function isSlackEvalDirective(
|
|
137
|
+
text: string,
|
|
138
|
+
markdown: string,
|
|
139
|
+
options?: { agentName?: string }
|
|
140
|
+
): boolean {
|
|
141
|
+
return (
|
|
142
|
+
parseSlackEvalDirective(text, options) !== null ||
|
|
143
|
+
parseSlackEvalDirective(markdown, options) !== null
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function formatSlackEvalHelp(): string {
|
|
148
|
+
return [
|
|
149
|
+
"*Eval commands* (same batches as the playground / `agentkit eval --prod`):",
|
|
150
|
+
"• `eval` — run all evals",
|
|
151
|
+
"• `eval <id> [id…]` — run specific eval ids",
|
|
152
|
+
"• `eval --tag <tag>` — run evals with a tag (`-t` also works)",
|
|
153
|
+
"• `eval list` — list available evals",
|
|
154
|
+
"• `eval status` — show the active or latest eval run",
|
|
155
|
+
"• `eval help` — this message",
|
|
156
|
+
].join("\n");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function formatSlackEvalList(
|
|
160
|
+
evals: Array<{
|
|
161
|
+
id: string;
|
|
162
|
+
description?: string;
|
|
163
|
+
tags?: string[];
|
|
164
|
+
}>
|
|
165
|
+
): string {
|
|
166
|
+
if (evals.length === 0) {
|
|
167
|
+
return "No evals found under `evals/`.";
|
|
168
|
+
}
|
|
169
|
+
const lines = [`*${evals.length} eval(s):*`];
|
|
170
|
+
for (const item of evals) {
|
|
171
|
+
const tags =
|
|
172
|
+
item.tags === undefined || item.tags.length === 0
|
|
173
|
+
? ""
|
|
174
|
+
: ` _[${item.tags.join(", ")}]_`;
|
|
175
|
+
const desc =
|
|
176
|
+
item.description === undefined || item.description === ""
|
|
177
|
+
? ""
|
|
178
|
+
: ` — ${item.description}`;
|
|
179
|
+
lines.push(`• \`${item.id}\`${tags}${desc}`);
|
|
180
|
+
}
|
|
181
|
+
return lines.join("\n");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function formatSlackEvalRunSummary(run: EvalRunSnapshot): string {
|
|
185
|
+
const { summary } = run;
|
|
186
|
+
const statusLabel =
|
|
187
|
+
run.status === "completed"
|
|
188
|
+
? "completed"
|
|
189
|
+
: run.status === "failed"
|
|
190
|
+
? "failed"
|
|
191
|
+
: "running";
|
|
192
|
+
const lines = [
|
|
193
|
+
`*Eval run* \`${run.runId}\` — *${statusLabel}*`,
|
|
194
|
+
`• ${summary.passed} passed, ${summary.failed} failed, ${summary.total} total` +
|
|
195
|
+
(summary.done < summary.total
|
|
196
|
+
? ` (${summary.done}/${summary.total} done)`
|
|
197
|
+
: ""),
|
|
198
|
+
];
|
|
199
|
+
if (run.error !== undefined && run.error !== "") {
|
|
200
|
+
lines.push(`• error: ${run.error}`);
|
|
201
|
+
}
|
|
202
|
+
for (const c of run.cases) {
|
|
203
|
+
const mark =
|
|
204
|
+
c.status !== "done"
|
|
205
|
+
? c.status === "running"
|
|
206
|
+
? "RUN "
|
|
207
|
+
: "…. "
|
|
208
|
+
: c.ok === true
|
|
209
|
+
? "PASS"
|
|
210
|
+
: "FAIL";
|
|
211
|
+
const dur =
|
|
212
|
+
c.durationMs === undefined
|
|
213
|
+
? ""
|
|
214
|
+
: ` (${(c.durationMs / 1000).toFixed(1)}s)`;
|
|
215
|
+
const err =
|
|
216
|
+
c.ok === false && c.error !== undefined && c.error !== ""
|
|
217
|
+
? ` — ${c.error}`
|
|
218
|
+
: "";
|
|
219
|
+
lines.push(`\`${mark}\` \`${c.id}\`${dur}${err}`);
|
|
220
|
+
}
|
|
221
|
+
return lines.join("\n");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function truncateTyping(status: string): string {
|
|
225
|
+
if (status.length <= TYPING_STATUS_MAX) {
|
|
226
|
+
return status;
|
|
227
|
+
}
|
|
228
|
+
return `${status.slice(0, TYPING_STATUS_MAX - 1)}…`;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
async function sleep(ms: number): Promise<void> {
|
|
232
|
+
await new Promise((resolve) => {
|
|
233
|
+
setTimeout(resolve, ms);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async function safeTyping(
|
|
238
|
+
binding: SlackBinding,
|
|
239
|
+
status: string
|
|
240
|
+
): Promise<void> {
|
|
241
|
+
try {
|
|
242
|
+
await binding.thread.startTyping(truncateTyping(status));
|
|
243
|
+
} catch {
|
|
244
|
+
// best-effort status
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async function safePost(binding: SlackBinding, text: string): Promise<void> {
|
|
249
|
+
try {
|
|
250
|
+
await binding.thread.post(text);
|
|
251
|
+
} catch {
|
|
252
|
+
// best-effort reply
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Handle a parsed Slack eval directive against {@link HostEvalsApi}.
|
|
258
|
+
* Posts results in-thread; does not start an agent turn.
|
|
259
|
+
*/
|
|
260
|
+
export async function handleSlackEvalDirective(args: {
|
|
261
|
+
directive: SlackEvalDirective;
|
|
262
|
+
evals: HostEvalsApi;
|
|
263
|
+
binding: SlackBinding;
|
|
264
|
+
/** Override poll interval (tests). */
|
|
265
|
+
pollMs?: number;
|
|
266
|
+
}): Promise<void> {
|
|
267
|
+
const { directive, evals, binding } = args;
|
|
268
|
+
const pollMs = args.pollMs ?? EVAL_POLL_MS;
|
|
269
|
+
|
|
270
|
+
if (directive.kind === "help") {
|
|
271
|
+
await safePost(binding, formatSlackEvalHelp());
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (directive.kind === "list") {
|
|
276
|
+
const listed = await evals.list();
|
|
277
|
+
await safePost(binding, formatSlackEvalList(listed.evals));
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (directive.kind === "status") {
|
|
282
|
+
const { runs, activeRunId } = await evals.listRunsWithActive();
|
|
283
|
+
const run =
|
|
284
|
+
(activeRunId === undefined ? undefined : await evals.get(activeRunId)) ??
|
|
285
|
+
runs[0];
|
|
286
|
+
if (run === undefined) {
|
|
287
|
+
await safePost(binding, "No eval runs yet. Try `eval list` then `eval`.");
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
await safePost(binding, formatSlackEvalRunSummary(run));
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
await safeTyping(binding, "Starting evals…");
|
|
295
|
+
let run: EvalRunSnapshot;
|
|
296
|
+
try {
|
|
297
|
+
run = await evals.start({
|
|
298
|
+
filterIds: directive.filterIds,
|
|
299
|
+
tags: directive.tags,
|
|
300
|
+
});
|
|
301
|
+
} catch (error) {
|
|
302
|
+
if (error instanceof EvalRunConflictError) {
|
|
303
|
+
const active = await evals.get(error.activeRunId);
|
|
304
|
+
await safePost(
|
|
305
|
+
binding,
|
|
306
|
+
active === undefined
|
|
307
|
+
? `An eval run is already in progress (\`${error.activeRunId}\`).`
|
|
308
|
+
: `An eval run is already in progress:\n${formatSlackEvalRunSummary(active)}`
|
|
309
|
+
);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (error instanceof EvalRunEmptyError) {
|
|
313
|
+
await safePost(
|
|
314
|
+
binding,
|
|
315
|
+
"No matching evals. Try `eval list` or `eval help`."
|
|
316
|
+
);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
320
|
+
await safePost(binding, `Failed to start evals: ${message}`);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
await safePost(
|
|
325
|
+
binding,
|
|
326
|
+
`Started eval run \`${run.runId}\` (${run.summary.total} case(s)).`
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
while (run.status === "running") {
|
|
330
|
+
await safeTyping(
|
|
331
|
+
binding,
|
|
332
|
+
`Evals ${run.summary.done}/${run.summary.total}…`
|
|
333
|
+
);
|
|
334
|
+
await sleep(pollMs);
|
|
335
|
+
const next = await evals.get(run.runId);
|
|
336
|
+
if (next === undefined) {
|
|
337
|
+
await safePost(
|
|
338
|
+
binding,
|
|
339
|
+
`Eval run \`${run.runId}\` disappeared before completion.`
|
|
340
|
+
);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
run = next;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
await safePost(binding, formatSlackEvalRunSummary(run));
|
|
347
|
+
await safeTyping(binding, "Evals done.");
|
|
348
|
+
}
|
|
@@ -29,6 +29,7 @@ export * from "./cursor-account.js";
|
|
|
29
29
|
export * from "./defaults.js";
|
|
30
30
|
export * from "./dispatch.js";
|
|
31
31
|
export * from "./doctor.js";
|
|
32
|
+
export * from "./eval-directive.js";
|
|
32
33
|
export * from "./event-id-dedupe.js";
|
|
33
34
|
export * from "./inbound.js";
|
|
34
35
|
export * from "./init.js";
|
|
@@ -138,6 +138,7 @@ export function slackChannel<const Name extends string = string>(
|
|
|
138
138
|
const engagement = options.engagement ?? {};
|
|
139
139
|
const mentionsEnabled = engagement.mentions !== false;
|
|
140
140
|
const directMessagesEnabled = engagement.directMessages !== false;
|
|
141
|
+
const evalCommandsEnabled = options.evalCommands !== false;
|
|
141
142
|
const channelPosts = engagement.channelPosts;
|
|
142
143
|
if (channelPosts !== undefined) {
|
|
143
144
|
const entries = channelPosts.allow.filter((entry) => entry.trim() !== "");
|
|
@@ -204,6 +205,7 @@ export function slackChannel<const Name extends string = string>(
|
|
|
204
205
|
log: getLog(),
|
|
205
206
|
mentionsEnabled,
|
|
206
207
|
directMessagesEnabled,
|
|
208
|
+
evalCommandsEnabled,
|
|
207
209
|
...(args.hasContinuationSession === undefined
|
|
208
210
|
? {}
|
|
209
211
|
: { hasContinuationSession: args.hasContinuationSession }),
|
|
@@ -342,6 +344,7 @@ export function slackChannel<const Name extends string = string>(
|
|
|
342
344
|
credentials,
|
|
343
345
|
host: args.host,
|
|
344
346
|
log: getLog(),
|
|
347
|
+
evalCommandsEnabled,
|
|
345
348
|
...(args.hasContinuationSession === undefined
|
|
346
349
|
? {}
|
|
347
350
|
: {
|
|
@@ -382,6 +382,13 @@ export interface SlackChannelOptions {
|
|
|
382
382
|
* entry at 50 chars). Defaults to Thinking… / Working on it… / Almost there….
|
|
383
383
|
*/
|
|
384
384
|
loadingMessages?: string[];
|
|
385
|
+
/**
|
|
386
|
+
* Built-in Slack `eval` / `eval list` / `eval status` directive that runs
|
|
387
|
+
* playground eval batches (`host.evals` / `/v1/dev/evals/runs`) without an
|
|
388
|
+
* agent turn. Defaults to `true`. Set `false` to leave `eval …` for the
|
|
389
|
+
* model handler instead.
|
|
390
|
+
*/
|
|
391
|
+
evalCommands?: boolean;
|
|
385
392
|
/** Optional teardown (e.g. stop example-local debouncers). Runs after Socket Mode stops. */
|
|
386
393
|
onStop?: () => void | Promise<void>;
|
|
387
394
|
}
|
package/src/connections.ts
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
* `defineConnection` — authored at `agent/mcp-connections/<name>.ts`.
|
|
3
3
|
*
|
|
4
4
|
* A connection gives tools from an external MCP server. The filename
|
|
5
|
-
* becomes the connection (server) name.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* - the agent-serve host, via `ctx.host.mcp` on in-process tools
|
|
9
|
-
* - channel / schedule handlers, via `args.host.mcp`
|
|
5
|
+
* becomes the connection (server) name. Available to the agent (SDK
|
|
6
|
+
* `mcpServers`), host (`ctx.host.mcp`), and channel/schedule handlers.
|
|
7
|
+
* Pass `hostOnly: true` to keep it off the model (still on `host.mcp`).
|
|
10
8
|
*
|
|
11
9
|
* ```ts
|
|
12
10
|
* import { defineConnection } from "@anysphere/agent-serve/connections";
|
|
@@ -15,6 +13,13 @@
|
|
|
15
13
|
* url: "https://mcp.linear.app/mcp",
|
|
16
14
|
* headers: { authorization: `Bearer ${process.env.LINEAR_TOKEN}` },
|
|
17
15
|
* });
|
|
16
|
+
*
|
|
17
|
+
* // privileged connector, model cannot call directly:
|
|
18
|
+
* export default defineConnection({
|
|
19
|
+
* cursorAccount: true,
|
|
20
|
+
* servers: ["anytool"],
|
|
21
|
+
* hostOnly: true,
|
|
22
|
+
* });
|
|
18
23
|
* ```
|
|
19
24
|
*
|
|
20
25
|
* A **Cursor account MCP connection** exposes the MCP connectors the operator
|