@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
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FIFO admission of model turns under `concurrency.maxRunningTurns`
|
|
3
|
+
* (see {@link AgentConcurrencyOptions}). One governor per session engine:
|
|
4
|
+
* every turn acquires a slot before its SDK run starts and releases it when
|
|
5
|
+
* the run settles, so at most `maxRunningTurns` turns execute at once and
|
|
6
|
+
* the rest wait in arrival order instead of failing.
|
|
7
|
+
*
|
|
8
|
+
* Waiting is cancellable: the engine passes the turn's abort signal, so a
|
|
9
|
+
* follow-up that preempts a queued turn (or an explicit `interrupt()`)
|
|
10
|
+
* removes the waiter without ever running it.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { AgentConcurrencyOptions } from "../types.js";
|
|
14
|
+
|
|
15
|
+
export interface TurnPermit {
|
|
16
|
+
/** Return the slot. Idempotent; wakes the oldest waiter, if any. */
|
|
17
|
+
release(): void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AcquireTurnSlotArgs {
|
|
21
|
+
sessionId: string;
|
|
22
|
+
/** Abort waiting (preemption / interrupt). Ignored once a slot is held. */
|
|
23
|
+
signal?: AbortSignal;
|
|
24
|
+
/**
|
|
25
|
+
* Called synchronously when the turn must wait, with its 1-based
|
|
26
|
+
* position among waiting turns at enqueue time.
|
|
27
|
+
*/
|
|
28
|
+
onQueued?: (position: number) => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface TurnWaiter {
|
|
32
|
+
sessionId: string;
|
|
33
|
+
grant: (permit: TurnPermit) => void;
|
|
34
|
+
cancel: () => void;
|
|
35
|
+
cleanup: () => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class TurnGovernor {
|
|
39
|
+
/** The configured ceiling, or undefined for unlimited. */
|
|
40
|
+
readonly maxRunningTurns: number | undefined;
|
|
41
|
+
private running = 0;
|
|
42
|
+
private readonly waiters: TurnWaiter[] = [];
|
|
43
|
+
/** Sessions currently waiting for a slot (at most one turn per session). */
|
|
44
|
+
private readonly queuedSessions = new Set<string>();
|
|
45
|
+
|
|
46
|
+
constructor(concurrency: AgentConcurrencyOptions | undefined) {
|
|
47
|
+
this.maxRunningTurns = concurrency?.maxRunningTurns;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** True when a `maxRunningTurns` ceiling is configured. */
|
|
51
|
+
get limited(): boolean {
|
|
52
|
+
return this.maxRunningTurns !== undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** True while `sessionId` has a turn waiting for a slot. */
|
|
56
|
+
isQueued(sessionId: string): boolean {
|
|
57
|
+
return this.queuedSessions.has(sessionId);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Turns currently waiting for a slot. */
|
|
61
|
+
get queuedCount(): number {
|
|
62
|
+
return this.waiters.length;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Turns currently holding a slot. */
|
|
66
|
+
get runningCount(): number {
|
|
67
|
+
return this.running;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Acquire a turn slot. Resolves with a permit once a slot is free (FIFO
|
|
72
|
+
* behind earlier waiters), or with `undefined` when the abort signal
|
|
73
|
+
* fires while waiting — the turn must then settle as cancelled without
|
|
74
|
+
* running. Unlimited governors grant immediately.
|
|
75
|
+
*/
|
|
76
|
+
acquire(args: AcquireTurnSlotArgs): Promise<TurnPermit | undefined> {
|
|
77
|
+
const limit = this.maxRunningTurns;
|
|
78
|
+
if (limit === undefined) {
|
|
79
|
+
return Promise.resolve(NO_OP_PERMIT);
|
|
80
|
+
}
|
|
81
|
+
if (this.running < limit && this.waiters.length === 0) {
|
|
82
|
+
return Promise.resolve(this.grantSlot());
|
|
83
|
+
}
|
|
84
|
+
// Saturated. A turn that is already preempted never enqueues.
|
|
85
|
+
if (args.signal?.aborted === true) {
|
|
86
|
+
return Promise.resolve(undefined);
|
|
87
|
+
}
|
|
88
|
+
return new Promise<TurnPermit | undefined>((resolve) => {
|
|
89
|
+
const waiter: TurnWaiter = {
|
|
90
|
+
sessionId: args.sessionId,
|
|
91
|
+
grant: (permit) => resolve(permit),
|
|
92
|
+
cancel: () => resolve(undefined),
|
|
93
|
+
cleanup: () => {
|
|
94
|
+
this.queuedSessions.delete(args.sessionId);
|
|
95
|
+
args.signal?.removeEventListener("abort", onAbort);
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const onAbort = (): void => {
|
|
99
|
+
const index = this.waiters.indexOf(waiter);
|
|
100
|
+
if (index === -1) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
this.waiters.splice(index, 1);
|
|
104
|
+
waiter.cleanup();
|
|
105
|
+
waiter.cancel();
|
|
106
|
+
};
|
|
107
|
+
this.waiters.push(waiter);
|
|
108
|
+
this.queuedSessions.add(args.sessionId);
|
|
109
|
+
args.signal?.addEventListener("abort", onAbort, { once: true });
|
|
110
|
+
args.onQueued?.(this.waiters.length);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Take a slot and build its (idempotent) release handle. */
|
|
115
|
+
private grantSlot(): TurnPermit {
|
|
116
|
+
this.running += 1;
|
|
117
|
+
let released = false;
|
|
118
|
+
return {
|
|
119
|
+
release: () => {
|
|
120
|
+
if (released) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
released = true;
|
|
124
|
+
this.running -= 1;
|
|
125
|
+
this.wakeNextWaiter();
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private wakeNextWaiter(): void {
|
|
131
|
+
const limit = this.maxRunningTurns;
|
|
132
|
+
if (limit === undefined || this.running >= limit) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const waiter = this.waiters.shift();
|
|
136
|
+
if (waiter === undefined) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
waiter.cleanup();
|
|
140
|
+
waiter.grant(this.grantSlot());
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Permit handed out by unlimited governors. */
|
|
145
|
+
const NO_OP_PERMIT: TurnPermit = { release: () => {} };
|
package/src/prompt.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dedented multi-line strings for prompts, errors, and tool descriptions.
|
|
3
|
+
*
|
|
4
|
+
* Indent the body to match surrounding TypeScript; the common leading
|
|
5
|
+
* whitespace is stripped. A leading newline after `` prompt` `` is dropped so
|
|
6
|
+
* the usual multiline form stays flush in source.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { prompt } from "@cursor/july";
|
|
10
|
+
*
|
|
11
|
+
* export default defineTool({
|
|
12
|
+
* description: prompt`
|
|
13
|
+
* Deploy Anyship services for a merged PR.
|
|
14
|
+
* Enforces HITL outside business hours.
|
|
15
|
+
* `,
|
|
16
|
+
* // ...
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* throw new Error(prompt`
|
|
20
|
+
* It is outside business hours.
|
|
21
|
+
* Use request_author_approval.
|
|
22
|
+
* `);
|
|
23
|
+
*
|
|
24
|
+
* // GitHub channel `context` wants string[]:
|
|
25
|
+
* context: prompt.lines`
|
|
26
|
+
* Merged PR detected: ${url}.
|
|
27
|
+
*
|
|
28
|
+
* Run the deploy flow.
|
|
29
|
+
* `
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
function dedentLines(
|
|
34
|
+
strings: TemplateStringsArray,
|
|
35
|
+
values: readonly unknown[]
|
|
36
|
+
): string[] {
|
|
37
|
+
let text = "";
|
|
38
|
+
for (let i = 0; i < strings.length; i++) {
|
|
39
|
+
text += strings[i] ?? "";
|
|
40
|
+
if (i < values.length) {
|
|
41
|
+
text += String(values[i]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Common form is prompt`\n …\n`; drop the opening newline only.
|
|
45
|
+
if (text.startsWith("\n")) {
|
|
46
|
+
text = text.slice(1);
|
|
47
|
+
}
|
|
48
|
+
text = text.replace(/(?:\n[ \t]*)+$/u, "");
|
|
49
|
+
|
|
50
|
+
const lines = text.split("\n");
|
|
51
|
+
let minIndent = Number.POSITIVE_INFINITY;
|
|
52
|
+
for (const line of lines) {
|
|
53
|
+
if (line.trim() === "") {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const indent = /^[ \t]*/u.exec(line)?.[0]?.length ?? 0;
|
|
57
|
+
if (indent < minIndent) {
|
|
58
|
+
minIndent = indent;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!Number.isFinite(minIndent)) {
|
|
62
|
+
minIndent = 0;
|
|
63
|
+
}
|
|
64
|
+
return lines.map((line) => (line.trim() === "" ? "" : line.slice(minIndent)));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type PromptTag = {
|
|
68
|
+
(strings: TemplateStringsArray, ...values: unknown[]): string;
|
|
69
|
+
/** Same as {@link prompt}, but as separate lines (e.g. GitHub `context`). */
|
|
70
|
+
lines(strings: TemplateStringsArray, ...values: unknown[]): string[];
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/** Dedented multi-line string (blank lines preserved). */
|
|
74
|
+
export const prompt: PromptTag = Object.assign(
|
|
75
|
+
function prompt(strings: TemplateStringsArray, ...values: unknown[]): string {
|
|
76
|
+
return dedentLines(strings, values).join("\n");
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
lines(strings: TemplateStringsArray, ...values: unknown[]): string[] {
|
|
80
|
+
return dedentLines(strings, values);
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
);
|
|
@@ -80,9 +80,29 @@ export interface CursorHostedStorageOptions {
|
|
|
80
80
|
fetch?: typeof fetch;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Marker stamped on {@link cursorHostedStorage} so the engine can prefer
|
|
85
|
+
* durable Bugbot rows for `GET /v1/sessions` (survives `defineStorage` spread).
|
|
86
|
+
* Explicit `unique symbol` annotation required for `--isolatedDeclarations`
|
|
87
|
+
* (TS9010).
|
|
88
|
+
*/
|
|
89
|
+
export const CURSOR_HOSTED_STORAGE: unique symbol = Symbol.for(
|
|
90
|
+
"@cursor/july.storage.cursor-hosted"
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
/** True when `value` is (or was built from) {@link cursorHostedStorage}. */
|
|
94
|
+
export function isCursorHostedStorage(value: unknown): boolean {
|
|
95
|
+
return (
|
|
96
|
+
typeof value === "object" &&
|
|
97
|
+
value !== null &&
|
|
98
|
+
(value as Record<symbol, unknown>)[CURSOR_HOSTED_STORAGE] === true
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
83
102
|
type CursorHostedStorageMethods = Required<
|
|
84
103
|
Pick<StorageConfig, "put" | "get" | "delete" | "list">
|
|
85
104
|
> & {
|
|
105
|
+
readonly [CURSOR_HOSTED_STORAGE]: true;
|
|
86
106
|
evals: StorageEvalsTable;
|
|
87
107
|
abs: StorageABTable;
|
|
88
108
|
};
|
|
@@ -155,6 +175,7 @@ export function cursorHostedStorage(
|
|
|
155
175
|
options: CursorHostedStorageOptions = {}
|
|
156
176
|
): CursorHostedStorageMethods {
|
|
157
177
|
return {
|
|
178
|
+
[CURSOR_HOSTED_STORAGE]: true,
|
|
158
179
|
async put(key, value): Promise<void> {
|
|
159
180
|
await storageRpc(options, "/internal/agent-serve/storage/kv/put", {
|
|
160
181
|
key,
|
package/src/types.ts
CHANGED
|
@@ -194,8 +194,45 @@ export interface AgentConfig {
|
|
|
194
194
|
* it and sends it with the deployment request. Ignored by local serving.
|
|
195
195
|
*/
|
|
196
196
|
hosting?: AgentHostingOptions;
|
|
197
|
+
/**
|
|
198
|
+
* Engine-wide turn admission limits. See {@link AgentConcurrencyOptions}.
|
|
199
|
+
*/
|
|
200
|
+
concurrency?: AgentConcurrencyOptions;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Turn admission limits on {@link AgentConfig.concurrency}.
|
|
205
|
+
*
|
|
206
|
+
* ```ts
|
|
207
|
+
* export default defineAgent({
|
|
208
|
+
* // At most 3 sessions run a model turn at once; the rest queue FIFO.
|
|
209
|
+
* concurrency: { maxRunningTurns: 3 },
|
|
210
|
+
* });
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
export interface AgentConcurrencyOptions {
|
|
214
|
+
/**
|
|
215
|
+
* Max model turns running at once across **all** of this agent's
|
|
216
|
+
* sessions. When every slot is busy, newly admitted turns queue FIFO
|
|
217
|
+
* (surfaced as a durable `turn.queued` event and `queued: true` on
|
|
218
|
+
* `GET /v1/sessions`) instead of failing; each queued turn starts as
|
|
219
|
+
* soon as a slot frees. Positive integer, hard-capped at
|
|
220
|
+
* {@link MAX_RUNNING_TURNS_LIMIT}. Omit for unlimited.
|
|
221
|
+
*
|
|
222
|
+
* A queued turn still counts as `running` for busy semantics
|
|
223
|
+
* (follow-ups preempt it; direct tool calls get `SessionBusyError`),
|
|
224
|
+
* and a follow-up that preempts a queued turn re-queues at the back.
|
|
225
|
+
*/
|
|
226
|
+
maxRunningTurns?: number;
|
|
197
227
|
}
|
|
198
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Hard ceiling for {@link AgentConcurrencyOptions.maxRunningTurns}.
|
|
231
|
+
* Matches the eval harness ceiling: each running turn issues model
|
|
232
|
+
* provider requests, so unbounded parallelism is never meaningful.
|
|
233
|
+
*/
|
|
234
|
+
export const MAX_RUNNING_TURNS_LIMIT = 200;
|
|
235
|
+
|
|
199
236
|
/**
|
|
200
237
|
* Managed-hosting block on {@link AgentConfig.hosting}.
|
|
201
238
|
*/
|
|
@@ -367,6 +404,12 @@ export interface HostContext {
|
|
|
367
404
|
* Slack follow-ups coalesce and drain at turn boundaries.
|
|
368
405
|
*/
|
|
369
406
|
slackNudges?: SlackNudgeHostApi;
|
|
407
|
+
/**
|
|
408
|
+
* Playground eval batches (`/v1/dev/evals*`). Present once the serve host
|
|
409
|
+
* has attached an {@link import("./evals.js").HostEvalsApi}. Used by the
|
|
410
|
+
* built-in Slack `eval` directive and available to tools/handlers.
|
|
411
|
+
*/
|
|
412
|
+
evals?: import("./evals.js").HostEvalsApi;
|
|
370
413
|
/**
|
|
371
414
|
* Author-facing durable JSON KV (`agentkit/v1/{agent}/kv/…`). Backed by
|
|
372
415
|
* `agent/storage.ts` (`defineStorage`) when authored; otherwise files
|
|
@@ -531,6 +574,8 @@ export type ConnectionTransport =
|
|
|
531
574
|
type?: "http" | "sse";
|
|
532
575
|
url: string;
|
|
533
576
|
headers?: Record<string, string>;
|
|
577
|
+
/** Host PKCE OAuth; `agentkit mcp oauth <name>`. No Authorization header. */
|
|
578
|
+
oauth?: true;
|
|
534
579
|
}
|
|
535
580
|
| {
|
|
536
581
|
/** Slug of a peer agent mounted on the same serve host. */
|
|
@@ -578,13 +623,18 @@ export function isSymbolicConnectionTransport(
|
|
|
578
623
|
export type ConnectionConfig = ConnectionTransport & {
|
|
579
624
|
/** Documentation only; shown in `info` output. */
|
|
580
625
|
description?: string;
|
|
626
|
+
/**
|
|
627
|
+
* Omit from SDK `mcpServers` (model never sees it). Still available on
|
|
628
|
+
* `host.mcp` for server tools / channel handlers. Does not affect
|
|
629
|
+
* cloud-native account connectors provisioned by the platform.
|
|
630
|
+
*/
|
|
631
|
+
hostOnly?: boolean;
|
|
581
632
|
};
|
|
582
633
|
|
|
583
634
|
/**
|
|
584
|
-
* An MCP connection is
|
|
585
|
-
*
|
|
586
|
-
*
|
|
587
|
-
* - channel / schedule handlers (`args.host.mcp`)
|
|
635
|
+
* An MCP connection is available to the agent (SDK `mcpServers`), host
|
|
636
|
+
* (`ctx.host.mcp`), and channel/schedule handlers — unless `hostOnly`,
|
|
637
|
+
* which keeps it off the model surface only.
|
|
588
638
|
*/
|
|
589
639
|
export type ConnectionDefinition = ConnectionConfig &
|
|
590
640
|
BrandedDefinition<"connection">;
|
|
@@ -671,6 +721,15 @@ export type SessionEventPayload =
|
|
|
671
721
|
data: { sdkAgentId: string; url?: string };
|
|
672
722
|
}
|
|
673
723
|
| { type: "message.received"; data: { text: string } }
|
|
724
|
+
| {
|
|
725
|
+
/**
|
|
726
|
+
* The turn was admitted while every {@link AgentConcurrencyOptions.maxRunningTurns}
|
|
727
|
+
* slot was busy; it waits FIFO and `turn.started` follows once a slot
|
|
728
|
+
* frees. `position` is 1-based among waiting turns at enqueue time.
|
|
729
|
+
*/
|
|
730
|
+
type: "turn.queued";
|
|
731
|
+
data: { position: number; maxRunningTurns: number };
|
|
732
|
+
}
|
|
674
733
|
| { type: "turn.started"; data: Record<string, never> }
|
|
675
734
|
| { type: "step.started"; data: { stepId: number } }
|
|
676
735
|
| { type: "step.completed"; data: { stepId: number; durationMs: number } }
|
|
@@ -872,8 +931,14 @@ export interface SessionSummary {
|
|
|
872
931
|
mode: SessionMode;
|
|
873
932
|
title?: string;
|
|
874
933
|
turnCount: number;
|
|
875
|
-
/** True while a turn is executing right now. */
|
|
934
|
+
/** True while a turn is executing right now (including queued turns). */
|
|
876
935
|
running: boolean;
|
|
936
|
+
/**
|
|
937
|
+
* True while the session's admitted turn is waiting for a
|
|
938
|
+
* {@link AgentConcurrencyOptions.maxRunningTurns} slot (subset of
|
|
939
|
+
* {@link running}). Omitted when the agent has no turn limit.
|
|
940
|
+
*/
|
|
941
|
+
queued?: boolean;
|
|
877
942
|
createdAt: string;
|
|
878
943
|
updatedAt: string;
|
|
879
944
|
/** `<channelId>:<key>` wire token, or null when not addressable. */
|
|
@@ -886,6 +951,13 @@ export interface SessionSummary {
|
|
|
886
951
|
externalUrl?: string;
|
|
887
952
|
}
|
|
888
953
|
|
|
954
|
+
/**
|
|
955
|
+
* Where `GET /v1/sessions` loaded rows from.
|
|
956
|
+
* - `cursor-hosted` — durable Bugbot `agent_serve_kv` via `cursorHostedStorage`
|
|
957
|
+
* - `local` — the serve process `--state-root` session store
|
|
958
|
+
*/
|
|
959
|
+
export type SessionListSource = "cursor-hosted" | "local";
|
|
960
|
+
|
|
889
961
|
/**
|
|
890
962
|
* A session handle scoped to the channel that owns it. This is what channel
|
|
891
963
|
* route handlers get back from `send()` / `getSession()`.
|
|
@@ -1622,6 +1694,7 @@ export interface DiscoveredConnection {
|
|
|
1622
1694
|
name: string;
|
|
1623
1695
|
transport: ConnectionTransport;
|
|
1624
1696
|
description?: string;
|
|
1697
|
+
hostOnly?: boolean;
|
|
1625
1698
|
}
|
|
1626
1699
|
|
|
1627
1700
|
export interface DiscoveredChannel {
|
|
@@ -1676,6 +1749,8 @@ export interface ResolvedAgent {
|
|
|
1676
1749
|
local?: AgentLocalOptions;
|
|
1677
1750
|
/** Managed-hosting declarations from {@link AgentConfig.hosting}. */
|
|
1678
1751
|
hosting?: AgentHostingOptions;
|
|
1752
|
+
/** Validated turn admission limits from {@link AgentConfig.concurrency}. */
|
|
1753
|
+
concurrency?: AgentConcurrencyOptions;
|
|
1679
1754
|
tools: DiscoveredTool[];
|
|
1680
1755
|
skills: DiscoveredSkill[];
|
|
1681
1756
|
connections: DiscoveredConnection[];
|
|
@@ -1727,6 +1802,8 @@ export interface AgentProjectInfo {
|
|
|
1727
1802
|
local?: { cwd?: string };
|
|
1728
1803
|
/** Managed-hosting declarations when authored (egress allowlist, expected secrets). */
|
|
1729
1804
|
hosting?: { egressDomains?: string[]; secretNames?: string[] };
|
|
1805
|
+
/** Turn admission limits when authored (`concurrency` on `agent.ts`). */
|
|
1806
|
+
concurrency?: { maxRunningTurns?: number };
|
|
1730
1807
|
/**
|
|
1731
1808
|
* The agent's own MCP surface (mounted at `<base>/v1/mcp`): other agents
|
|
1732
1809
|
* and MCP clients delegate to this agent through these tools.
|
|
@@ -1741,7 +1818,7 @@ export interface AgentProjectInfo {
|
|
|
1741
1818
|
inputSchema: JsonSchemaObject;
|
|
1742
1819
|
}>;
|
|
1743
1820
|
skills: Array<{ name: string; description: string }>;
|
|
1744
|
-
connections: Array<{ name: string; transport: string }>;
|
|
1821
|
+
connections: Array<{ name: string; transport: string; hostOnly?: boolean }>;
|
|
1745
1822
|
subagents: Array<{
|
|
1746
1823
|
name: string;
|
|
1747
1824
|
description?: string;
|
|
@@ -1897,6 +1974,15 @@ export interface ServeOptions {
|
|
|
1897
1974
|
* SSO/Okta proxy in front of the host).
|
|
1898
1975
|
*/
|
|
1899
1976
|
allowAnonymousCursorGithub?: boolean;
|
|
1977
|
+
/**
|
|
1978
|
+
* Allow {@link allowAnonymous} together with
|
|
1979
|
+
* `defineConnection({ cursorAccount: true })`. Without this opt-in, `serve`
|
|
1980
|
+
* refuses to start because every admitted anonymous caller could drive the
|
|
1981
|
+
* signed-in account's MCP connectors. Set it only when the network boundary
|
|
1982
|
+
* already authenticates callers (e.g. an SSO/Okta proxy, or the hosted
|
|
1983
|
+
* agent-serve alias token).
|
|
1984
|
+
*/
|
|
1985
|
+
allowAnonymousCursorAccountMcp?: boolean;
|
|
1900
1986
|
/**
|
|
1901
1987
|
* Public base URL where this server is reachable from outside the host
|
|
1902
1988
|
* (e.g. `https://agents.example.com`). Used to resolve peer
|