@cursor/july 0.1.1 → 0.1.3
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 +40 -7
- package/README.md +33 -24
- package/dist/bin/agent-serve.d.ts +3 -1
- package/dist/bin/agent-serve.d.ts.map +1 -1
- package/dist/bin/agent-serve.js +466 -140
- package/dist/channels/github/api.d.ts.map +1 -1
- package/dist/channels/github/api.js +31 -14
- package/dist/channels/github/cursor-account.d.ts +43 -0
- package/dist/channels/github/cursor-account.d.ts.map +1 -0
- package/dist/channels/github/cursor-account.js +95 -0
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +46 -9
- package/dist/channels/github/index.d.ts +2 -2
- package/dist/channels/github/index.js +2 -2
- package/dist/channels/github/types.d.ts +17 -0
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.d.ts +8 -2
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +8 -0
- package/dist/channels/slack/types.d.ts +24 -3
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/channels/slack/types.js +15 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +8 -8
- package/dist/docs/assets/{ab.md.COdXkces.js → ab.md.BMCZ6Hd7.js} +3 -3
- package/dist/docs/assets/{ab.md.COdXkces.lean.js → ab.md.BMCZ6Hd7.lean.js} +1 -1
- package/dist/docs/assets/{app.DqfFEmJd.js → app.BR0RbIdx.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DtIOQzGj.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BaLEdS15.js → VPLocalSearchBox.qjsVTneI.js} +1 -1
- package/dist/docs/assets/chunks/{theme.CZRvu_0q.js → theme.2Kg8jIp_.js} +2 -2
- package/dist/docs/assets/{deployment.md.Dx1TYNk5.js → deployment.md.DTKwE15Z.js} +3 -3
- package/dist/docs/assets/{deployment.md.Dx1TYNk5.lean.js → deployment.md.DTKwE15Z.lean.js} +1 -1
- package/dist/docs/assets/{evals.md.DPZ_MAnI.js → evals.md.DAgEc_hL.js} +3 -3
- package/dist/docs/assets/{guides_agent-to-agent.md.CrtrsySy.js → guides_agent-to-agent.md.Bpzgq2Pq.js} +1 -1
- package/dist/docs/assets/{guides_cloud-runtime.md.CYlNMTNp.js → guides_cloud-runtime.md.gVzabdQL.js} +1 -1
- package/dist/docs/assets/{guides_github.md.DwbKhCeS.js → guides_github.md.DOOCpqsW.js} +11 -4
- package/dist/docs/assets/{guides_github.md.DwbKhCeS.lean.js → guides_github.md.DOOCpqsW.lean.js} +1 -1
- package/dist/docs/assets/{guides_human-in-the-loop.md.Dvuctx7s.js → guides_human-in-the-loop.md.DlUqsp1S.js} +2 -2
- package/dist/docs/assets/{guides_slack.md.bv41fHfW.js → guides_slack.md.CCwqHvSV.js} +4 -4
- package/dist/docs/assets/{guides_slack.md.bv41fHfW.lean.js → guides_slack.md.CCwqHvSV.lean.js} +1 -1
- package/dist/docs/assets/{guides_webhooks.md.hFTik3lf.js → guides_webhooks.md.B1EswtUu.js} +2 -2
- package/dist/docs/assets/index.md.m81y7TY7.js +20 -0
- package/dist/docs/assets/{index.md.BPKcj5AI.lean.js → index.md.m81y7TY7.lean.js} +1 -1
- package/dist/docs/assets/quickstart.md.BU6Iwi_9.js +204 -0
- package/dist/docs/assets/quickstart.md.BU6Iwi_9.lean.js +1 -0
- package/dist/docs/assets/{reference_agent-config.md.Bpd7HQwf.js → reference_agent-config.md.DrW2JUM8.js} +4 -4
- package/dist/docs/assets/{reference_agent-config.md.Bpd7HQwf.lean.js → reference_agent-config.md.DrW2JUM8.lean.js} +1 -1
- package/dist/docs/assets/{reference_channels.md.D7JTR03W.js → reference_channels.md.DdmiKgqf.js} +4 -4
- package/dist/docs/assets/{reference_channels.md.D7JTR03W.lean.js → reference_channels.md.DdmiKgqf.lean.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.DA730zCu.js → reference_cli.md.Bv6pOxcF.js} +11 -6
- package/dist/docs/assets/{reference_cli.md.DA730zCu.lean.js → reference_cli.md.Bv6pOxcF.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.C3vNH_DE.js → reference_connections.md.zaEYCLHT.js} +1 -1
- package/dist/docs/assets/{reference_hooks.md.BCEc3MyM.js → reference_hooks.md.DyLVfE1O.js} +1 -1
- package/dist/docs/assets/{reference_hooks.md.BCEc3MyM.lean.js → reference_hooks.md.DyLVfE1O.lean.js} +1 -1
- package/dist/docs/assets/{reference_http-api.md.DBAahtdz.js → reference_http-api.md.Dx_nmDG6.js} +1 -1
- package/dist/docs/assets/{reference_instructions.md.BC05LEQ8.js → reference_instructions.md.CgoV-YEb.js} +9 -7
- package/dist/docs/assets/{reference_instructions.md.BC05LEQ8.lean.js → reference_instructions.md.CgoV-YEb.lean.js} +1 -1
- package/dist/docs/assets/{reference_schedules.md.D7qijxLk.js → reference_schedules.md.w_F2mXB6.js} +2 -2
- package/dist/docs/assets/{reference_skills.md.VQnlBT3Q.js → reference_skills.md.B_jHN7JL.js} +3 -3
- package/dist/docs/assets/{reference_skills.md.VQnlBT3Q.lean.js → reference_skills.md.B_jHN7JL.lean.js} +1 -1
- package/dist/docs/assets/{reference_subagents.md.CIRAVcPK.js → reference_subagents.md.zWAMNfi1.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.DF5kwlt0.js → reference_tools.md.CqgJroI0.js} +2 -2
- package/dist/docs/assets/scaffolding-agents.md.C3pTrmoE.js +1 -0
- package/dist/docs/assets/scaffolding-agents.md.C3pTrmoE.lean.js +1 -0
- package/dist/docs/assets/storage.md.CVnInNiN.js +17 -0
- package/dist/docs/assets/storage.md.CVnInNiN.lean.js +1 -0
- 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 +7 -7
- package/dist/docs/guides/agent-to-agent.html +6 -6
- package/dist/docs/guides/cloud-runtime.html +5 -5
- package/dist/docs/guides/github.html +14 -7
- package/dist/docs/guides/human-in-the-loop.html +6 -6
- package/dist/docs/guides/slack.html +8 -8
- package/dist/docs/guides/webhooks.html +6 -6
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +5 -5
- package/dist/docs/index.html +7 -7
- package/dist/docs/quickstart.html +195 -26
- package/dist/docs/reference/agent-config.html +7 -7
- package/dist/docs/reference/channels.html +8 -8
- package/dist/docs/reference/cli.html +14 -9
- package/dist/docs/reference/connections.html +5 -5
- package/dist/docs/reference/hooks.html +5 -5
- package/dist/docs/reference/http-api.html +6 -6
- package/dist/docs/reference/instructions.html +13 -11
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +4 -4
- package/dist/docs/reference/schedules.html +7 -7
- package/dist/docs/reference/sessions.html +4 -4
- package/dist/docs/reference/skills.html +6 -6
- package/dist/docs/reference/subagents.html +6 -6
- package/dist/docs/reference/tools.html +7 -7
- package/dist/docs/scaffolding-agents.html +5 -5
- package/dist/docs/storage.html +41 -0
- package/dist/docs/troubleshooting.html +4 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/internal/chat-client.d.ts +29 -3
- package/dist/internal/chat-client.d.ts.map +1 -1
- package/dist/internal/chat-client.js +180 -27
- package/dist/internal/cli-ax.d.ts +75 -2
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +600 -52
- package/dist/internal/cli-cursor.d.ts.map +1 -1
- package/dist/internal/cli-cursor.js +8 -36
- package/dist/internal/cli-deploy.d.ts +108 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -0
- package/dist/internal/cli-deploy.js +1009 -0
- package/dist/internal/cursor/backend-client.d.ts +10 -1
- package/dist/internal/cursor/backend-client.d.ts.map +1 -1
- package/dist/internal/cursor/backend-client.js +79 -1
- package/dist/internal/cursor/credentials.d.ts +9 -0
- package/dist/internal/cursor/credentials.d.ts.map +1 -1
- package/dist/internal/cursor/credentials.js +12 -0
- package/dist/internal/cursor/github-credentials.d.ts +44 -0
- package/dist/internal/cursor/github-credentials.d.ts.map +1 -0
- package/dist/internal/cursor/github-credentials.js +195 -0
- package/dist/internal/deploy-client.d.ts +184 -0
- package/dist/internal/deploy-client.d.ts.map +1 -0
- package/dist/internal/deploy-client.js +395 -0
- package/dist/internal/deploy-source.d.ts +35 -0
- package/dist/internal/deploy-source.d.ts.map +1 -0
- package/dist/internal/deploy-source.js +118 -0
- package/dist/internal/discovery.d.ts +11 -0
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +116 -19
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +1 -0
- package/dist/internal/eval-run-store.d.ts +22 -3
- package/dist/internal/eval-run-store.d.ts.map +1 -1
- package/dist/internal/eval-run-store.js +39 -20
- package/dist/internal/eval-runner.d.ts +2 -0
- package/dist/internal/eval-runner.d.ts.map +1 -1
- package/dist/internal/eval-runner.js +2 -0
- package/dist/internal/event-mapper.d.ts +54 -1
- package/dist/internal/event-mapper.d.ts.map +1 -1
- package/dist/internal/event-mapper.js +151 -41
- package/dist/internal/handleAgentServeTrigger.d.ts.map +1 -1
- package/dist/internal/handleAgentServeTrigger.js +10 -12
- package/dist/internal/host-platforms.d.ts +7 -2
- package/dist/internal/host-platforms.d.ts.map +1 -1
- package/dist/internal/host-platforms.js +15 -10
- package/dist/internal/hosting.d.ts +37 -0
- package/dist/internal/hosting.d.ts.map +1 -0
- package/dist/internal/hosting.js +67 -0
- package/dist/internal/init-project.d.ts +88 -1
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +221 -31
- package/dist/internal/install-cursor-skills.d.ts +64 -0
- package/dist/internal/install-cursor-skills.d.ts.map +1 -0
- package/dist/internal/install-cursor-skills.js +274 -0
- package/dist/internal/logs-client.d.ts +60 -0
- package/dist/internal/logs-client.d.ts.map +1 -0
- package/dist/internal/logs-client.js +311 -0
- package/dist/internal/open-browser.d.ts +5 -0
- package/dist/internal/open-browser.d.ts.map +1 -0
- package/dist/internal/open-browser.js +34 -0
- package/dist/internal/playground/toolchain.d.ts.map +1 -1
- package/dist/internal/playground/toolchain.js +16 -11
- package/dist/internal/playground-proxy.d.ts +69 -0
- package/dist/internal/playground-proxy.d.ts.map +1 -0
- package/dist/internal/playground-proxy.js +468 -0
- package/dist/internal/prompt-context.d.ts +35 -0
- package/dist/internal/prompt-context.d.ts.map +1 -0
- package/dist/internal/prompt-context.js +71 -0
- package/dist/internal/reminder-runner.d.ts +7 -0
- package/dist/internal/reminder-runner.d.ts.map +1 -1
- package/dist/internal/reminder-runner.js +50 -6
- package/dist/internal/reminder-store.d.ts +2 -0
- package/dist/internal/reminder-store.d.ts.map +1 -1
- package/dist/internal/reminder-store.js +18 -0
- package/dist/internal/request-headers.d.ts +11 -0
- package/dist/internal/request-headers.d.ts.map +1 -0
- package/dist/internal/request-headers.js +14 -0
- package/dist/internal/resolve-prod-target.d.ts +42 -0
- package/dist/internal/resolve-prod-target.d.ts.map +1 -0
- package/dist/internal/resolve-prod-target.js +111 -0
- package/dist/internal/run-client.d.ts +2 -2
- package/dist/internal/run-client.d.ts.map +1 -1
- package/dist/internal/run-client.js +38 -23
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +182 -45
- package/dist/internal/session-engine.d.ts +50 -1
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +267 -23
- package/dist/internal/sessions-client.d.ts +21 -0
- package/dist/internal/sessions-client.d.ts.map +1 -0
- package/dist/internal/sessions-client.js +168 -0
- package/dist/internal/storage-coordinator.d.ts +139 -0
- package/dist/internal/storage-coordinator.d.ts.map +1 -0
- package/dist/internal/storage-coordinator.js +499 -0
- package/dist/internal/stream-progress.d.ts.map +1 -1
- package/dist/internal/stream-progress.js +31 -3
- package/dist/internal/terminal-style.d.ts +22 -0
- package/dist/internal/terminal-style.d.ts.map +1 -0
- package/dist/internal/terminal-style.js +49 -0
- package/dist/internal/trajectory.d.ts +10 -5
- package/dist/internal/trajectory.d.ts.map +1 -1
- package/dist/internal/trajectory.js +82 -10
- package/dist/internal/workspace.d.ts +11 -0
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +38 -4
- package/dist/playground/assets/cursor-icons-outline-BxTT_FVJ.woff2 +0 -0
- package/dist/playground/assets/index-D-vo2lV_.css +1 -0
- package/dist/playground/assets/index-x60b9q2j.js +312 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage.d.ts +204 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +153 -0
- package/dist/types.d.ts +70 -4
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +3 -2
- package/docs/guides/github.md +43 -8
- package/docs/guides/slack.md +1 -1
- package/docs/quickstart.md +350 -57
- package/docs/reference/cli.md +51 -3
- package/docs/reference/instructions.md +8 -6
- package/docs/scaffolding-agents.md +1 -1
- package/docs/storage.md +98 -0
- package/package.json +10 -1
- package/skills/ab/SKILL.md +8 -8
- package/skills/create-agent/SKILL.md +28 -22
- package/skills/debug/SKILL.md +11 -11
- package/skills/evals/SKILL.md +16 -16
- package/skills/framework-map/SKILL.md +6 -6
- package/skills/github/SKILL.md +22 -14
- package/skills/hillclimb/SKILL.md +10 -10
- package/skills/setup-slack/SKILL.md +13 -13
- package/src/bin/agent-serve.ts +552 -179
- package/src/channels/github/api.ts +42 -23
- package/src/channels/github/cursor-account.ts +165 -0
- package/src/channels/github/github-channel.ts +66 -6
- package/src/channels/github/index.ts +2 -2
- package/src/channels/github/types.ts +19 -0
- package/src/channels/slack/slack-channel.ts +17 -3
- package/src/channels/slack/types.ts +44 -3
- package/src/index.ts +13 -0
- package/src/internal/chat-client.ts +252 -37
- package/src/internal/cli-ax.ts +722 -72
- package/src/internal/cli-cursor.ts +14 -42
- package/src/internal/cli-deploy.ts +1319 -0
- package/src/internal/cursor/backend-client.ts +103 -1
- package/src/internal/cursor/credentials.ts +14 -0
- package/src/internal/cursor/github-credentials.ts +248 -0
- package/src/internal/deploy-client.ts +632 -0
- package/src/internal/deploy-source.ts +133 -0
- package/src/internal/discovery.ts +141 -17
- package/src/internal/distribution.ts +1 -0
- package/src/internal/eval-run-store.ts +50 -20
- package/src/internal/eval-runner.ts +5 -0
- package/src/internal/event-mapper.ts +222 -42
- package/src/internal/handleAgentServeTrigger.ts +10 -12
- package/src/internal/host-platforms.ts +28 -11
- package/src/internal/hosting.ts +77 -0
- package/src/internal/init-project.ts +333 -51
- package/src/internal/install-cursor-skills.ts +327 -0
- package/src/internal/logs-client.ts +442 -0
- package/src/internal/open-browser.ts +41 -0
- package/src/internal/playground/toolchain.ts +15 -13
- package/src/internal/playground-proxy.ts +576 -0
- package/src/internal/prompt-context.ts +95 -0
- package/src/internal/reminder-runner.ts +50 -6
- package/src/internal/reminder-store.ts +21 -0
- package/src/internal/request-headers.ts +23 -0
- package/src/internal/resolve-prod-target.ts +150 -0
- package/src/internal/run-client.ts +39 -36
- package/src/internal/server.ts +223 -28
- package/src/internal/session-engine.ts +307 -10
- package/src/internal/sessions-client.ts +182 -0
- package/src/internal/storage-coordinator.ts +615 -0
- package/src/internal/stream-progress.ts +36 -2
- package/src/internal/terminal-style.ts +74 -0
- package/src/internal/trajectory.ts +91 -13
- package/src/internal/workspace.ts +42 -4
- package/src/storage.ts +325 -0
- package/src/types.ts +82 -8
- package/dist/docs/assets/chunks/@localSearchIndexroot.CcVk1uKq.js +0 -1
- package/dist/docs/assets/index.md.BPKcj5AI.js +0 -20
- package/dist/docs/assets/quickstart.md.tVPiGK_L.js +0 -35
- package/dist/docs/assets/quickstart.md.tVPiGK_L.lean.js +0 -1
- package/dist/docs/assets/scaffolding-agents.md.CyYfWGdc.js +0 -1
- package/dist/docs/assets/scaffolding-agents.md.CyYfWGdc.lean.js +0 -1
- package/dist/playground/assets/cursor-icons-outline-oY2V_mvK.woff2 +0 -0
- package/dist/playground/assets/index-1K-hG-7p.css +0 -1
- package/dist/playground/assets/index-FlWjhg3x.js +0 -79
- /package/dist/docs/assets/{evals.md.DPZ_MAnI.lean.js → evals.md.DAgEc_hL.lean.js} +0 -0
- /package/dist/docs/assets/{guides_agent-to-agent.md.CrtrsySy.lean.js → guides_agent-to-agent.md.Bpzgq2Pq.lean.js} +0 -0
- /package/dist/docs/assets/{guides_cloud-runtime.md.CYlNMTNp.lean.js → guides_cloud-runtime.md.gVzabdQL.lean.js} +0 -0
- /package/dist/docs/assets/{guides_human-in-the-loop.md.Dvuctx7s.lean.js → guides_human-in-the-loop.md.DlUqsp1S.lean.js} +0 -0
- /package/dist/docs/assets/{guides_webhooks.md.hFTik3lf.lean.js → guides_webhooks.md.B1EswtUu.lean.js} +0 -0
- /package/dist/docs/assets/{reference_connections.md.C3vNH_DE.lean.js → reference_connections.md.zaEYCLHT.lean.js} +0 -0
- /package/dist/docs/assets/{reference_http-api.md.DBAahtdz.lean.js → reference_http-api.md.Dx_nmDG6.lean.js} +0 -0
- /package/dist/docs/assets/{reference_schedules.md.D7qijxLk.lean.js → reference_schedules.md.w_F2mXB6.lean.js} +0 -0
- /package/dist/docs/assets/{reference_subagents.md.CIRAVcPK.lean.js → reference_subagents.md.zWAMNfi1.lean.js} +0 -0
- /package/dist/docs/assets/{reference_tools.md.DF5kwlt0.lean.js → reference_tools.md.CqgJroI0.lean.js} +0 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Infer `agentkit deploy` git source fields from a local checkout.
|
|
3
|
+
*
|
|
4
|
+
* From an agent directory inside a git repo with an `origin` remote, the
|
|
5
|
+
* CLI can fill `--repo` / `--ref` / `--path` so `agentkit deploy` (no
|
|
6
|
+
* flags) is enough. Explicit flags always win.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { execFile } from "node:child_process";
|
|
10
|
+
import { relative, resolve, sep } from "node:path";
|
|
11
|
+
import { promisify } from "node:util";
|
|
12
|
+
|
|
13
|
+
const execFileAsync = promisify(execFile);
|
|
14
|
+
|
|
15
|
+
/** Injectable git runner (cwd + args → stdout, or undefined on failure). */
|
|
16
|
+
export type GitRunner = (
|
|
17
|
+
args: readonly string[],
|
|
18
|
+
cwd: string
|
|
19
|
+
) => Promise<string | undefined>;
|
|
20
|
+
|
|
21
|
+
export interface InferredDeploySource {
|
|
22
|
+
gitRepoUrl?: string;
|
|
23
|
+
gitRef?: string;
|
|
24
|
+
/** Agent directory relative to the repo root (posix). Omitted at root. */
|
|
25
|
+
agentPath?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const defaultGitRunner: GitRunner = async (args, cwd) => {
|
|
29
|
+
try {
|
|
30
|
+
const { stdout } = await execFileAsync("git", [...args], { cwd });
|
|
31
|
+
const trimmed = stdout.trim();
|
|
32
|
+
return trimmed === "" ? undefined : trimmed;
|
|
33
|
+
} catch {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Normalize a git remote URL to the https form the control plane accepts
|
|
40
|
+
* (`https://host/owner/repo`, no `.git` suffix). Returns undefined for
|
|
41
|
+
* unrecognized shapes.
|
|
42
|
+
*/
|
|
43
|
+
export function httpsGitRepoUrlFromRemote(remote: string): string | undefined {
|
|
44
|
+
let url = remote.trim();
|
|
45
|
+
if (url === "") {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
if (url.startsWith("git@")) {
|
|
49
|
+
// git@host:owner/repo.git → https://host/owner/repo.git
|
|
50
|
+
url = `https://${url.slice("git@".length).replace(":", "/")}`;
|
|
51
|
+
} else if (url.startsWith("ssh://git@")) {
|
|
52
|
+
url = `https://${url.slice("ssh://git@".length)}`;
|
|
53
|
+
} else if (!/^https?:\/\//i.test(url)) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let parsed: URL;
|
|
58
|
+
try {
|
|
59
|
+
parsed = new URL(url);
|
|
60
|
+
} catch {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
const path = parsed.pathname
|
|
64
|
+
.replace(/\.git$/i, "")
|
|
65
|
+
.replace(/\/+$/, "")
|
|
66
|
+
.replace(/^\/+/, "");
|
|
67
|
+
if (path === "" || !path.includes("/")) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
// Use hostname (not host) so ssh://git@github.com:22/… does not keep :22.
|
|
71
|
+
return `https://${parsed.hostname}/${path}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Path of `dir` relative to `gitRoot`, using `/` separators. Undefined when
|
|
76
|
+
* `dir` is outside the root; omitted (undefined) when `dir` *is* the root
|
|
77
|
+
* so the control plane treats the agent as living at the repo root.
|
|
78
|
+
*/
|
|
79
|
+
export function agentPathRelativeToGitRoot(
|
|
80
|
+
dir: string,
|
|
81
|
+
gitRoot: string
|
|
82
|
+
): string | undefined {
|
|
83
|
+
const absDir = resolve(dir);
|
|
84
|
+
const absRoot = resolve(gitRoot);
|
|
85
|
+
const rel = relative(absRoot, absDir);
|
|
86
|
+
if (rel === "") {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
// Outside the repo (or a Windows drive mismatch) → cannot infer.
|
|
90
|
+
if (rel.startsWith("..") || rel.split(sep).includes("..")) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
return rel.split(sep).join("/");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Probe the git checkout containing `dir` for deploy source fields.
|
|
98
|
+
* Missing pieces stay undefined (static deploy / server defaults).
|
|
99
|
+
*/
|
|
100
|
+
export async function inferDeployGitSource(
|
|
101
|
+
dir: string,
|
|
102
|
+
options?: { git?: GitRunner }
|
|
103
|
+
): Promise<InferredDeploySource> {
|
|
104
|
+
const git = options?.git ?? defaultGitRunner;
|
|
105
|
+
const absDir = resolve(dir);
|
|
106
|
+
|
|
107
|
+
const gitRoot = await git(["rev-parse", "--show-toplevel"], absDir);
|
|
108
|
+
if (gitRoot === undefined) {
|
|
109
|
+
return {};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const remote = await git(["remote", "get-url", "origin"], gitRoot);
|
|
113
|
+
const gitRepoUrl =
|
|
114
|
+
remote === undefined ? undefined : httpsGitRepoUrlFromRemote(remote);
|
|
115
|
+
|
|
116
|
+
const branch = await git(["rev-parse", "--abbrev-ref", "HEAD"], gitRoot);
|
|
117
|
+
let gitRef: string | undefined;
|
|
118
|
+
if (branch !== undefined && branch !== "HEAD") {
|
|
119
|
+
gitRef = branch;
|
|
120
|
+
} else {
|
|
121
|
+
// Detached HEAD — pin the exact commit so the control plane still
|
|
122
|
+
// has something concrete to build.
|
|
123
|
+
gitRef = await git(["rev-parse", "HEAD"], gitRoot);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const agentPath = agentPathRelativeToGitRoot(absDir, gitRoot);
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
gitRepoUrl,
|
|
130
|
+
gitRef,
|
|
131
|
+
agentPath,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
@@ -19,8 +19,10 @@ import {
|
|
|
19
19
|
import { pathToFileURL } from "node:url";
|
|
20
20
|
import { type ABConfigFile, resolveABMaxPlaygroundSessions } from "../ab.js";
|
|
21
21
|
import { httpChannel } from "../channels.js";
|
|
22
|
+
import type { StorageDefinition } from "../storage.js";
|
|
22
23
|
import {
|
|
23
24
|
type AgentConfigDefinition,
|
|
25
|
+
type AgentHostingOptions,
|
|
24
26
|
type AgentProject,
|
|
25
27
|
type AgentProjectInfo,
|
|
26
28
|
type ChannelDefinition,
|
|
@@ -51,8 +53,15 @@ import { registerAuthoredModuleLoaders } from "./authored-loaders.js";
|
|
|
51
53
|
import { getDefinitionKind } from "./brand.js";
|
|
52
54
|
import { isValidCron } from "./cron.js";
|
|
53
55
|
import { parseFrontmatter } from "./frontmatter.js";
|
|
56
|
+
import {
|
|
57
|
+
isReservedSecretName,
|
|
58
|
+
MAX_EGRESS_DOMAINS,
|
|
59
|
+
validateEgressDomain,
|
|
60
|
+
validateSecretName,
|
|
61
|
+
} from "./hosting.js";
|
|
54
62
|
import { toolInputJsonSchema } from "./json-schema.js";
|
|
55
63
|
import { MCP_ENDPOINT_PATH, mcpEndpointToolNames } from "./mcp-endpoint.js";
|
|
64
|
+
import { withIdentityPreamble } from "./workspace.js";
|
|
56
65
|
|
|
57
66
|
const MODULE_EXTENSIONS = new Set([".ts", ".mts", ".js", ".mjs"]);
|
|
58
67
|
const NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
@@ -97,23 +106,26 @@ export async function isAgentProjectDir(dir: string): Promise<boolean> {
|
|
|
97
106
|
return hasFlatLayoutMarkers(resolved);
|
|
98
107
|
}
|
|
99
108
|
|
|
109
|
+
/** One immediate child agent directory under a multi-agent parent. */
|
|
110
|
+
export interface ChildAgentDir {
|
|
111
|
+
slug: string;
|
|
112
|
+
dir: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
100
115
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* multi-agent serving, where one server hosts many agents under
|
|
105
|
-
* `/<slug>/...`. Throws when no child projects are found.
|
|
116
|
+
* List agent projects directly under `rootDir` (one level deep) without
|
|
117
|
+
* loading them. Empty when the path is missing or has no child agents.
|
|
118
|
+
* Slug rules match {@link loadAgentProjects} / multi-agent serve.
|
|
106
119
|
*/
|
|
107
|
-
export async function
|
|
108
|
-
rootDir: string
|
|
109
|
-
|
|
110
|
-
): Promise<Array<{ slug: string; project: AgentProject }>> {
|
|
120
|
+
export async function listChildAgentDirs(
|
|
121
|
+
rootDir: string
|
|
122
|
+
): Promise<ChildAgentDir[]> {
|
|
111
123
|
const resolved = resolve(rootDir);
|
|
112
124
|
if (!(await isDirectory(resolved))) {
|
|
113
|
-
|
|
125
|
+
return [];
|
|
114
126
|
}
|
|
115
127
|
|
|
116
|
-
const results:
|
|
128
|
+
const results: ChildAgentDir[] = [];
|
|
117
129
|
const seenSlugs = new Set<string>();
|
|
118
130
|
for (const entry of await sortedEntries(resolved)) {
|
|
119
131
|
if (!entry.isDirectory() || entry.name.startsWith(".")) {
|
|
@@ -131,14 +143,40 @@ export async function loadAgentProjects(
|
|
|
131
143
|
throw new Error(`Duplicate agent slug "${slug}" under ${resolved}.`);
|
|
132
144
|
}
|
|
133
145
|
seenSlugs.add(slug);
|
|
134
|
-
results.push({ slug,
|
|
146
|
+
results.push({ slug, dir: childDir });
|
|
135
147
|
}
|
|
148
|
+
return results;
|
|
149
|
+
}
|
|
136
150
|
|
|
137
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Discover the agent projects directly under `rootDir` (one level deep):
|
|
153
|
+
* each immediate child directory that is itself an agent project becomes a
|
|
154
|
+
* mounted agent, keyed by a slug derived from its directory name. Used for
|
|
155
|
+
* multi-agent serving, where one server hosts many agents under
|
|
156
|
+
* `/<slug>/...`. Throws when no child projects are found.
|
|
157
|
+
*/
|
|
158
|
+
export async function loadAgentProjects(
|
|
159
|
+
rootDir: string,
|
|
160
|
+
options: LoadAgentProjectOptions = {}
|
|
161
|
+
): Promise<Array<{ slug: string; project: AgentProject }>> {
|
|
162
|
+
const resolved = resolve(rootDir);
|
|
163
|
+
if (!(await isDirectory(resolved))) {
|
|
164
|
+
throw new Error(`Agent projects directory does not exist: ${resolved}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const children = await listChildAgentDirs(resolved);
|
|
168
|
+
if (children.length === 0) {
|
|
138
169
|
throw new Error(
|
|
139
170
|
`No agent projects found directly under ${resolved}. Each agent should be a subdirectory with its own agent/ directory (or flat-layout markers).`
|
|
140
171
|
);
|
|
141
172
|
}
|
|
173
|
+
const results: Array<{ slug: string; project: AgentProject }> = [];
|
|
174
|
+
for (const child of children) {
|
|
175
|
+
results.push({
|
|
176
|
+
slug: child.slug,
|
|
177
|
+
project: await loadAgentProject(child.dir, options),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
142
180
|
return results;
|
|
143
181
|
}
|
|
144
182
|
|
|
@@ -233,6 +271,7 @@ export async function loadAgentProject(
|
|
|
233
271
|
const hooks = await loadHooks(ctx, join(agentDir, "hooks"));
|
|
234
272
|
const abs = await loadABs(ctx, agentDir);
|
|
235
273
|
const abConfig = await loadABConfig(ctx, agentDir);
|
|
274
|
+
const storage = await loadStorage(ctx, agentDir);
|
|
236
275
|
|
|
237
276
|
if (agentDir !== rootDir) {
|
|
238
277
|
await warnUnknownSlots(ctx, agentDir);
|
|
@@ -248,7 +287,8 @@ export async function loadAgentProject(
|
|
|
248
287
|
schedules,
|
|
249
288
|
hooks,
|
|
250
289
|
abs,
|
|
251
|
-
|
|
290
|
+
abConfig,
|
|
291
|
+
storage,
|
|
252
292
|
diagnostics,
|
|
253
293
|
};
|
|
254
294
|
}
|
|
@@ -277,12 +317,19 @@ async function loadAgent(
|
|
|
277
317
|
options: { name: string; isRoot: boolean }
|
|
278
318
|
): Promise<ResolvedAgent> {
|
|
279
319
|
const config = await loadAgentConfig(ctx, agentDir, options.isRoot);
|
|
280
|
-
const
|
|
320
|
+
const name = config?.name ?? options.name;
|
|
321
|
+
const authoredInstructions = await loadInstructions(
|
|
281
322
|
ctx,
|
|
282
323
|
agentDir,
|
|
283
324
|
config,
|
|
284
325
|
options.isRoot
|
|
285
326
|
);
|
|
327
|
+
// Root agents without authored instructions stay undefined (diagnostic
|
|
328
|
+
// already recorded). Subagents still get the identity line alone.
|
|
329
|
+
const instructions =
|
|
330
|
+
authoredInstructions === undefined && options.isRoot
|
|
331
|
+
? undefined
|
|
332
|
+
: withIdentityPreamble(name, authoredInstructions);
|
|
286
333
|
|
|
287
334
|
// Subagents run as Cursor SDK custom subagents (prompt + description +
|
|
288
335
|
// model); their other slots are inert today, so don't load them — just
|
|
@@ -290,7 +337,7 @@ async function loadAgent(
|
|
|
290
337
|
if (!options.isRoot) {
|
|
291
338
|
await warnUnsupportedSubagentSlots(ctx, agentDir);
|
|
292
339
|
return {
|
|
293
|
-
name
|
|
340
|
+
name,
|
|
294
341
|
...(config?.description === undefined
|
|
295
342
|
? {}
|
|
296
343
|
: { description: config.description }),
|
|
@@ -324,6 +371,7 @@ async function loadAgent(
|
|
|
324
371
|
: {
|
|
325
372
|
cwd: localCwd,
|
|
326
373
|
};
|
|
374
|
+
const hosting = resolveHosting(ctx, agentDir, config?.hosting);
|
|
327
375
|
|
|
328
376
|
if (runtime === "cloud") {
|
|
329
377
|
warnCloudRuntimeLimitations(ctx, agentDir, {
|
|
@@ -336,7 +384,7 @@ async function loadAgent(
|
|
|
336
384
|
}
|
|
337
385
|
|
|
338
386
|
return {
|
|
339
|
-
name
|
|
387
|
+
name,
|
|
340
388
|
description: config?.description,
|
|
341
389
|
// Root agents always get a concrete model: authored value or DEFAULT_MODEL.
|
|
342
390
|
model: isValidModelSetting(config?.model) ? config.model : DEFAULT_MODEL,
|
|
@@ -344,6 +392,7 @@ async function loadAgent(
|
|
|
344
392
|
runtime,
|
|
345
393
|
cloud,
|
|
346
394
|
local,
|
|
395
|
+
hosting,
|
|
347
396
|
tools,
|
|
348
397
|
skills,
|
|
349
398
|
connections,
|
|
@@ -367,6 +416,59 @@ function resolveAgentCwd(
|
|
|
367
416
|
return isAbsolute(trimmed) ? trimmed : resolve(ctx.rootDir, trimmed);
|
|
368
417
|
}
|
|
369
418
|
|
|
419
|
+
/**
|
|
420
|
+
* Validate the authored `hosting` block against the same grammar the
|
|
421
|
+
* backend enforces on deploy. Violations are warning diagnostics (reported
|
|
422
|
+
* by `agentkit validate`), not hard failures: the backend stays
|
|
423
|
+
* authoritative and `agentkit deploy` re-checks before any network call.
|
|
424
|
+
*/
|
|
425
|
+
function resolveHosting(
|
|
426
|
+
ctx: DiscoveryContext,
|
|
427
|
+
agentDir: string,
|
|
428
|
+
hosting: AgentHostingOptions | undefined
|
|
429
|
+
): AgentHostingOptions | undefined {
|
|
430
|
+
if (hosting === undefined) {
|
|
431
|
+
return undefined;
|
|
432
|
+
}
|
|
433
|
+
const agentPath = displayPath(ctx, join(agentDir, "agent.ts"));
|
|
434
|
+
const warn = (message: string): void => {
|
|
435
|
+
ctx.diagnostics.push({ severity: "warning", path: agentPath, message });
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
const egressDomains = hosting.egressDomains ?? [];
|
|
439
|
+
for (const domain of egressDomains) {
|
|
440
|
+
const domainError = validateEgressDomain(domain);
|
|
441
|
+
if (domainError !== undefined) {
|
|
442
|
+
warn(`hosting.egressDomains: ${domainError}`);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (egressDomains.length > MAX_EGRESS_DOMAINS) {
|
|
446
|
+
warn(
|
|
447
|
+
`hosting.egressDomains lists ${egressDomains.length} domains; deploys are capped at ${MAX_EGRESS_DOMAINS}.`
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
for (const name of hosting.secretNames ?? []) {
|
|
452
|
+
const nameError = validateSecretName(name);
|
|
453
|
+
if (nameError !== undefined) {
|
|
454
|
+
warn(`hosting.secretNames: ${nameError}`);
|
|
455
|
+
} else if (isReservedSecretName(name)) {
|
|
456
|
+
warn(
|
|
457
|
+
`hosting.secretNames: ${JSON.stringify(name)} is platform-reserved (CURSOR_*) and injected automatically; it cannot be set with \`secrets set\`.`
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
return {
|
|
463
|
+
...(hosting.egressDomains === undefined
|
|
464
|
+
? {}
|
|
465
|
+
: { egressDomains: [...hosting.egressDomains] }),
|
|
466
|
+
...(hosting.secretNames === undefined
|
|
467
|
+
? {}
|
|
468
|
+
: { secretNames: [...hosting.secretNames] }),
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
|
|
370
472
|
async function loadAgentConfig(
|
|
371
473
|
ctx: DiscoveryContext,
|
|
372
474
|
agentDir: string,
|
|
@@ -1323,6 +1425,22 @@ async function loadABConfig(
|
|
|
1323
1425
|
}
|
|
1324
1426
|
}
|
|
1325
1427
|
|
|
1428
|
+
// ============================================================================
|
|
1429
|
+
// Storage (agent/storage.ts)
|
|
1430
|
+
// ============================================================================
|
|
1431
|
+
|
|
1432
|
+
async function loadStorage(
|
|
1433
|
+
ctx: DiscoveryContext,
|
|
1434
|
+
agentDir: string
|
|
1435
|
+
): Promise<StorageDefinition | undefined> {
|
|
1436
|
+
const path = await findModuleFile(agentDir, "storage");
|
|
1437
|
+
if (path === undefined) {
|
|
1438
|
+
return undefined;
|
|
1439
|
+
}
|
|
1440
|
+
const definition = await importDefault(ctx, path, "storage");
|
|
1441
|
+
return definition as StorageDefinition | undefined;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1326
1444
|
function resolveABName(definition: unknown, fallback: string): string {
|
|
1327
1445
|
if (
|
|
1328
1446
|
typeof definition === "object" &&
|
|
@@ -1410,6 +1528,7 @@ export function projectInfo(project: AgentProject): AgentProjectInfo {
|
|
|
1410
1528
|
cloud:
|
|
1411
1529
|
agent.cloud === undefined ? undefined : toPublicCloudInfo(agent.cloud),
|
|
1412
1530
|
local: agent.local,
|
|
1531
|
+
hosting: agent.hosting,
|
|
1413
1532
|
mcp: { path: MCP_ENDPOINT_PATH, tools: mcpEndpointToolNames(project) },
|
|
1414
1533
|
instructions:
|
|
1415
1534
|
agent.instructions === undefined
|
|
@@ -1496,6 +1615,10 @@ export function projectInfo(project: AgentProject): AgentProjectInfo {
|
|
|
1496
1615
|
durableSnapshots: project.abConfig?.persistSnapshots !== undefined,
|
|
1497
1616
|
},
|
|
1498
1617
|
}),
|
|
1618
|
+
storage:
|
|
1619
|
+
project.storage === undefined
|
|
1620
|
+
? undefined
|
|
1621
|
+
: { name: project.storage.name },
|
|
1499
1622
|
diagnostics: project.diagnostics,
|
|
1500
1623
|
};
|
|
1501
1624
|
}
|
|
@@ -1515,6 +1638,7 @@ async function importDefault(
|
|
|
1515
1638
|
| "schedule"
|
|
1516
1639
|
| "hook"
|
|
1517
1640
|
| "ab"
|
|
1641
|
+
| "storage"
|
|
1518
1642
|
): Promise<unknown> {
|
|
1519
1643
|
let mod: Record<string, unknown>;
|
|
1520
1644
|
try {
|
|
@@ -62,9 +62,21 @@ export class EvalRunStore {
|
|
|
62
62
|
|
|
63
63
|
constructor(
|
|
64
64
|
private readonly projectRoot: string,
|
|
65
|
-
private readonly logger: (line: string) => void
|
|
65
|
+
private readonly logger: (line: string) => void,
|
|
66
|
+
/**
|
|
67
|
+
* Project-wide sink from `agent/storage.ts` (`defineStorage`),
|
|
68
|
+
* used when `evals.config.ts` sets no `persistRuns` of its own.
|
|
69
|
+
*/
|
|
70
|
+
private readonly fallbackPersistence?: EvalRunPersistence
|
|
66
71
|
) {}
|
|
67
72
|
|
|
73
|
+
/** `evals.config.ts` `persistRuns` wins; `defineStorage` is fallback. */
|
|
74
|
+
private resolvePersist(
|
|
75
|
+
config: Partial<EvalConfigFile>
|
|
76
|
+
): EvalRunPersistence | undefined {
|
|
77
|
+
return config.persistRuns ?? this.fallbackPersistence;
|
|
78
|
+
}
|
|
79
|
+
|
|
68
80
|
async list(): Promise<{
|
|
69
81
|
evals: Array<{
|
|
70
82
|
id: string;
|
|
@@ -74,7 +86,7 @@ export class EvalRunStore {
|
|
|
74
86
|
}>;
|
|
75
87
|
config: EvalListConfig;
|
|
76
88
|
}> {
|
|
77
|
-
await this.
|
|
89
|
+
await this.hydrate();
|
|
78
90
|
const { evals, config } = await discoverEvals(this.projectRoot);
|
|
79
91
|
return {
|
|
80
92
|
evals: evals.map((e) => ({
|
|
@@ -85,18 +97,21 @@ export class EvalRunStore {
|
|
|
85
97
|
: { description: e.definition.description }),
|
|
86
98
|
...(e.definition.tags === undefined ? {} : { tags: e.definition.tags }),
|
|
87
99
|
})),
|
|
88
|
-
config: snapshotListConfig(
|
|
100
|
+
config: snapshotListConfig(
|
|
101
|
+
config,
|
|
102
|
+
this.resolvePersist(config) !== undefined
|
|
103
|
+
),
|
|
89
104
|
};
|
|
90
105
|
}
|
|
91
106
|
|
|
92
107
|
async get(runId: string): Promise<EvalRunSnapshot | undefined> {
|
|
93
|
-
await this.
|
|
108
|
+
await this.hydrate();
|
|
94
109
|
return this.runs.get(runId);
|
|
95
110
|
}
|
|
96
111
|
|
|
97
112
|
/** Newest-first snapshots for playground rehydrate after navigation/reload. */
|
|
98
113
|
async listRuns(): Promise<EvalRunSnapshot[]> {
|
|
99
|
-
await this.
|
|
114
|
+
await this.hydrate();
|
|
100
115
|
return this.sortedRuns();
|
|
101
116
|
}
|
|
102
117
|
|
|
@@ -109,7 +124,7 @@ export class EvalRunStore {
|
|
|
109
124
|
runs: EvalRunSnapshot[];
|
|
110
125
|
activeRunId?: string;
|
|
111
126
|
}> {
|
|
112
|
-
await this.
|
|
127
|
+
await this.hydrate();
|
|
113
128
|
const activeRunId = this.activeRunId;
|
|
114
129
|
return {
|
|
115
130
|
runs: this.sortedRuns(),
|
|
@@ -122,7 +137,7 @@ export class EvalRunStore {
|
|
|
122
137
|
}
|
|
123
138
|
|
|
124
139
|
async start(input: StartEvalRunInput = {}): Promise<EvalRunSnapshot> {
|
|
125
|
-
await this.
|
|
140
|
+
await this.hydrate();
|
|
126
141
|
if (this.activeRunId !== undefined) {
|
|
127
142
|
const active = this.runs.get(this.activeRunId);
|
|
128
143
|
if (active !== undefined && active.status === "running") {
|
|
@@ -160,12 +175,15 @@ export class EvalRunStore {
|
|
|
160
175
|
done: 0,
|
|
161
176
|
},
|
|
162
177
|
cases,
|
|
163
|
-
config: snapshotRunConfig(
|
|
178
|
+
config: snapshotRunConfig(
|
|
179
|
+
config,
|
|
180
|
+
this.resolvePersist(config) !== undefined
|
|
181
|
+
),
|
|
164
182
|
};
|
|
165
183
|
this.runs.set(runId, snapshot);
|
|
166
184
|
this.activeRunId = runId;
|
|
167
185
|
await this.pruneOldRuns(config);
|
|
168
|
-
await this.enqueuePersist(snapshot, config
|
|
186
|
+
await this.enqueuePersist(snapshot, this.resolvePersist(config));
|
|
169
187
|
this.logger(
|
|
170
188
|
`[agent-serve] eval run ${runId}: starting ${cases.length} case(s)`
|
|
171
189
|
);
|
|
@@ -189,7 +207,14 @@ export class EvalRunStore {
|
|
|
189
207
|
);
|
|
190
208
|
}
|
|
191
209
|
|
|
192
|
-
|
|
210
|
+
/**
|
|
211
|
+
* Hydrate playground eval history from durable persistence
|
|
212
|
+
* (`evals.config.ts` `persistRuns`, else the `defineStorage`
|
|
213
|
+
* fallback). Called eagerly from the serve startup restore step —
|
|
214
|
+
* alongside session restore — and lazily as a safety net by every read.
|
|
215
|
+
* Idempotent; concurrent callers share one pass.
|
|
216
|
+
*/
|
|
217
|
+
async hydrate(): Promise<void> {
|
|
193
218
|
if (this.hydrated) {
|
|
194
219
|
return;
|
|
195
220
|
}
|
|
@@ -202,7 +227,7 @@ export class EvalRunStore {
|
|
|
202
227
|
private async hydrateFromPersistence(): Promise<void> {
|
|
203
228
|
try {
|
|
204
229
|
const { config } = await discoverEvals(this.projectRoot);
|
|
205
|
-
const persist = config
|
|
230
|
+
const persist = this.resolvePersist(config);
|
|
206
231
|
if (persist === undefined) {
|
|
207
232
|
this.hydrated = true;
|
|
208
233
|
return;
|
|
@@ -260,7 +285,7 @@ export class EvalRunStore {
|
|
|
260
285
|
continue;
|
|
261
286
|
}
|
|
262
287
|
this.runs.delete(stale.runId);
|
|
263
|
-
await this.persistDelete(stale.runId, config
|
|
288
|
+
await this.persistDelete(stale.runId, this.resolvePersist(config));
|
|
264
289
|
}
|
|
265
290
|
}
|
|
266
291
|
|
|
@@ -375,7 +400,8 @@ export class EvalRunStore {
|
|
|
375
400
|
}
|
|
376
401
|
if (
|
|
377
402
|
event.type === "message.completed" &&
|
|
378
|
-
typeof event.data?.text === "string"
|
|
403
|
+
typeof event.data?.text === "string" &&
|
|
404
|
+
event.data.parentCallId === undefined
|
|
379
405
|
) {
|
|
380
406
|
c.finalText = event.data.text;
|
|
381
407
|
}
|
|
@@ -384,7 +410,7 @@ export class EvalRunStore {
|
|
|
384
410
|
this.applyCaseResult(runId, result);
|
|
385
411
|
const run = this.runs.get(runId);
|
|
386
412
|
if (run !== undefined) {
|
|
387
|
-
void this.enqueuePersist(run, opts.config
|
|
413
|
+
void this.enqueuePersist(run, this.resolvePersist(opts.config));
|
|
388
414
|
}
|
|
389
415
|
},
|
|
390
416
|
});
|
|
@@ -394,7 +420,7 @@ export class EvalRunStore {
|
|
|
394
420
|
}
|
|
395
421
|
run.status = "completed";
|
|
396
422
|
run.finishedAt = new Date().toISOString();
|
|
397
|
-
await this.enqueuePersist(run, opts.config
|
|
423
|
+
await this.enqueuePersist(run, this.resolvePersist(opts.config));
|
|
398
424
|
this.logger(
|
|
399
425
|
`[agent-serve] eval run ${runId}: done — ${run.summary.passed} passed, ${run.summary.failed} failed`
|
|
400
426
|
);
|
|
@@ -406,7 +432,7 @@ export class EvalRunStore {
|
|
|
406
432
|
run.status = "failed";
|
|
407
433
|
run.finishedAt = new Date().toISOString();
|
|
408
434
|
run.error = error instanceof Error ? error.message : String(error);
|
|
409
|
-
await this.enqueuePersist(run, opts.config
|
|
435
|
+
await this.enqueuePersist(run, this.resolvePersist(opts.config));
|
|
410
436
|
this.logger(`[agent-serve] eval run ${runId}: failed — ${run.error}`);
|
|
411
437
|
} finally {
|
|
412
438
|
if (this.activeRunId === runId) {
|
|
@@ -467,21 +493,25 @@ function markInterruptedRun(run: EvalRunSnapshot): void {
|
|
|
467
493
|
}
|
|
468
494
|
}
|
|
469
495
|
|
|
470
|
-
function snapshotListConfig(
|
|
496
|
+
function snapshotListConfig(
|
|
497
|
+
config: Partial<EvalConfigFile>,
|
|
498
|
+
durableRuns: boolean
|
|
499
|
+
): EvalListConfig {
|
|
471
500
|
return {
|
|
472
501
|
...(config.maxConcurrency === undefined
|
|
473
502
|
? {}
|
|
474
503
|
: { maxConcurrency: config.maxConcurrency }),
|
|
475
504
|
...(config.timeoutMs === undefined ? {} : { timeoutMs: config.timeoutMs }),
|
|
476
505
|
maxPlaygroundRuns: resolveEvalMaxPlaygroundRuns(config.maxPlaygroundRuns),
|
|
477
|
-
durableRuns
|
|
506
|
+
durableRuns,
|
|
478
507
|
};
|
|
479
508
|
}
|
|
480
509
|
|
|
481
510
|
function snapshotRunConfig(
|
|
482
|
-
config: Partial<EvalConfigFile
|
|
511
|
+
config: Partial<EvalConfigFile>,
|
|
512
|
+
durableRuns: boolean
|
|
483
513
|
): EvalRunSnapshot["config"] {
|
|
484
|
-
const list = snapshotListConfig(config);
|
|
514
|
+
const list = snapshotListConfig(config, durableRuns);
|
|
485
515
|
return {
|
|
486
516
|
...(list.maxConcurrency === undefined
|
|
487
517
|
? {}
|
|
@@ -76,6 +76,8 @@ export interface RunEvalsOptions extends EvalSelectionOptions {
|
|
|
76
76
|
baseUrl: string;
|
|
77
77
|
timeoutMs?: number;
|
|
78
78
|
bearerToken?: string;
|
|
79
|
+
/** Extra request headers (e.g. hosted engineAccess). */
|
|
80
|
+
headers?: Record<string, string>;
|
|
79
81
|
verbose?: boolean;
|
|
80
82
|
onEvent?: (event: SessionEvent) => void;
|
|
81
83
|
/** Fired when a case begins executing (after concurrency slot acquired). */
|
|
@@ -240,6 +242,7 @@ export async function runDiscoveredEvals(
|
|
|
240
242
|
baseUrl: options.baseUrl,
|
|
241
243
|
defaultTimeoutMs,
|
|
242
244
|
bearerToken: options.bearerToken,
|
|
245
|
+
headers: options.headers,
|
|
243
246
|
verbose: Boolean(options.verbose),
|
|
244
247
|
onEvent: (event) => {
|
|
245
248
|
options.onCaseEvent?.(discovered.id, event);
|
|
@@ -268,6 +271,7 @@ async function runOneEval(
|
|
|
268
271
|
baseUrl: string;
|
|
269
272
|
defaultTimeoutMs: number;
|
|
270
273
|
bearerToken?: string;
|
|
274
|
+
headers?: Record<string, string>;
|
|
271
275
|
verbose: boolean;
|
|
272
276
|
onEvent?: (event: SessionEvent) => void;
|
|
273
277
|
}
|
|
@@ -330,6 +334,7 @@ async function runOneEval(
|
|
|
330
334
|
// Keep defineEval traffic out of live defineAB enrollment/metrics.
|
|
331
335
|
purpose: "eval",
|
|
332
336
|
bearerToken: opts.bearerToken,
|
|
337
|
+
headers: opts.headers,
|
|
333
338
|
workspaceDir: options.workspaceDir,
|
|
334
339
|
workspaceFiles: options.workspaceFiles,
|
|
335
340
|
timeoutMs,
|