antpath 0.10.14 → 0.11.0

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.
Files changed (77) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +16 -8
  3. package/dist/_shared/blueprint.d.ts +93 -108
  4. package/dist/_shared/blueprint.js +144 -78
  5. package/dist/_shared/cleanup-policy.d.ts +2 -2
  6. package/dist/_shared/cleanup-policy.js +2 -5
  7. package/dist/_shared/http.d.ts +2 -2
  8. package/dist/_shared/index.d.ts +7 -1
  9. package/dist/_shared/index.js +6 -1
  10. package/dist/_shared/mcp-proxy-url.d.ts +55 -0
  11. package/dist/_shared/mcp-proxy-url.js +65 -0
  12. package/dist/_shared/operations.d.ts +55 -8
  13. package/dist/_shared/operations.js +163 -20
  14. package/dist/_shared/provider-proxy-url.d.ts +64 -0
  15. package/dist/_shared/provider-proxy-url.js +73 -0
  16. package/dist/_shared/proxy-validation.d.ts +1 -1
  17. package/dist/_shared/proxy-validation.js +2 -2
  18. package/dist/_shared/run-unit.d.ts +23 -36
  19. package/dist/_shared/run-unit.js +30 -46
  20. package/dist/_shared/runner-event.d.ts +120 -0
  21. package/dist/_shared/runner-event.js +193 -0
  22. package/dist/_shared/runner-job.d.ts +159 -0
  23. package/dist/_shared/runner-job.js +54 -0
  24. package/dist/_shared/runtime-manifest.d.ts +191 -0
  25. package/dist/_shared/runtime-manifest.js +221 -0
  26. package/dist/_shared/runtime-types.d.ts +7 -16
  27. package/dist/_shared/sse.d.ts +74 -0
  28. package/dist/_shared/sse.js +0 -0
  29. package/dist/_shared/stable.d.ts +15 -10
  30. package/dist/_shared/stable.js +15 -10
  31. package/dist/_shared/submission.d.ts +199 -73
  32. package/dist/_shared/submission.js +409 -210
  33. package/dist/_shared/telemetry.d.ts +2 -2
  34. package/dist/_shared/telemetry.js +2 -2
  35. package/dist/_shared/template/index.d.ts +0 -1
  36. package/dist/_shared/template/index.js +0 -1
  37. package/dist/agents-md.d.ts +25 -67
  38. package/dist/agents-md.js +35 -121
  39. package/dist/agents-md.js.map +1 -1
  40. package/dist/asset-upload.d.ts +34 -0
  41. package/dist/asset-upload.js +34 -0
  42. package/dist/asset-upload.js.map +1 -1
  43. package/dist/blueprint.d.ts +3 -3
  44. package/dist/bundle.d.ts +2 -2
  45. package/dist/bundle.js +1 -1
  46. package/dist/cli.mjs +559 -105
  47. package/dist/cli.mjs.sha256 +1 -1
  48. package/dist/client.d.ts +53 -22
  49. package/dist/client.js +196 -130
  50. package/dist/client.js.map +1 -1
  51. package/dist/file.d.ts +28 -94
  52. package/dist/file.js +35 -175
  53. package/dist/file.js.map +1 -1
  54. package/dist/index.d.ts +5 -5
  55. package/dist/index.js +4 -0
  56. package/dist/index.js.map +1 -1
  57. package/dist/mcp-server.d.ts +10 -2
  58. package/dist/mcp-server.js +17 -2
  59. package/dist/mcp-server.js.map +1 -1
  60. package/dist/skill.d.ts +44 -214
  61. package/dist/skill.js +50 -284
  62. package/dist/skill.js.map +1 -1
  63. package/dist/version.d.ts +1 -1
  64. package/dist/version.js +1 -1
  65. package/dist/version.js.map +1 -1
  66. package/docs/cleanup.md +1 -1
  67. package/docs/credentials.md +2 -2
  68. package/docs/events.md +8 -8
  69. package/docs/outputs.md +2 -0
  70. package/docs/quickstart.md +18 -2
  71. package/docs/skills.md +1 -3
  72. package/docs/templates.md +6 -5
  73. package/package.json +2 -1
  74. package/dist/_shared/secrets.d.ts +0 -7
  75. package/dist/_shared/secrets.js +0 -20
  76. package/dist/_shared/template/mapper.d.ts +0 -11
  77. package/dist/_shared/template/mapper.js +0 -70
@@ -1,3 +1,4 @@
1
+ import { iterateSse } from "./sse.js";
1
2
  /**
2
3
  * The single source of truth for SDK<->BFF transport. The SDK class
3
4
  * AND the CLI subcommands both call these functions; neither
@@ -11,12 +12,6 @@
11
12
  * `references/development-principles.md` (Agent-first surface design,
12
13
  * Concrete rule 3).
13
14
  */
14
- export async function submitRun(http, request) {
15
- return http.request("/api/runs", {
16
- method: "POST",
17
- body: JSON.stringify(request)
18
- });
19
- }
20
15
  export async function getRun(http, runId) {
21
16
  const result = await http.request(`/api/runs/${encodeURIComponent(runId)}`);
22
17
  return hasRun(result) ? result.run : result;
@@ -26,7 +21,7 @@ export async function getRun(http, runId) {
26
21
  * parsed submission inputs, attempts, indexed events (with
27
22
  * pagination cursor for large runs), raw-event Storage manifest,
28
23
  * outputs, capture failures, proxy-call audit, pinned skills,
29
- * provider skills, transient skills.
24
+ * provider skills, inline skills.
30
25
  *
31
26
  * Backed by the same `GET /api/runs/:runId` endpoint that
32
27
  * `getRun` calls; this variant just narrows the return type to
@@ -40,6 +35,154 @@ export async function listRunEvents(http, runId) {
40
35
  const result = await http.request(`/api/runs/${encodeURIComponent(runId)}/events`);
41
36
  return result.events;
42
37
  }
38
+ /**
39
+ * Open the `GET /api/runs/:runId/events/stream` SSE endpoint and yield
40
+ * each `event: run_event` frame as a parsed `RunEvent`. The iterator
41
+ * completes when the server emits `event: terminal`, when the caller's
42
+ * AbortSignal fires, or when the underlying stream closes.
43
+ *
44
+ * The caller controls reconnection — this function deliberately does
45
+ * NOT auto-reconnect. The SDK wraps it with a backoff loop and falls
46
+ * back to polling when SSE is unavailable; the CLI tails events with
47
+ * the same reconnect contract.
48
+ *
49
+ * Cursor semantics: the dashboard sends each event frame with `id: <cursor>`
50
+ * which natively maps to `Last-Event-ID` on reconnect, AND embeds the
51
+ * cursor inside the JSON payload as `.cursor` so non-EventSource
52
+ * consumers can read it. We surface both.
53
+ */
54
+ export async function* streamRunEventsSse(http, runId, options = {}) {
55
+ const headers = {
56
+ accept: "text/event-stream"
57
+ };
58
+ if (options.cursor) {
59
+ // Both the header and the query-string carry the cursor — the
60
+ // header wins server-side, but some intermediaries strip
61
+ // `Last-Event-ID`, so we belt-and-braces it.
62
+ headers["last-event-id"] = options.cursor;
63
+ }
64
+ const query = {};
65
+ if (options.cursor)
66
+ query.cursor = options.cursor;
67
+ let outcome = {
68
+ kind: "disconnected",
69
+ nextCursor: options.cursor
70
+ };
71
+ let download;
72
+ try {
73
+ const init = { method: "GET", headers };
74
+ if (options.signal)
75
+ init.signal = options.signal;
76
+ download = await http.download(`/api/runs/${encodeURIComponent(runId)}/events/stream`, init, query);
77
+ }
78
+ catch (err) {
79
+ return {
80
+ kind: options.signal?.aborted ? "aborted" : "disconnected",
81
+ nextCursor: options.cursor,
82
+ error: err instanceof Error ? err.message : String(err)
83
+ };
84
+ }
85
+ const body = download.response.body;
86
+ if (!body) {
87
+ return {
88
+ kind: "disconnected",
89
+ nextCursor: options.cursor,
90
+ error: "SSE response body was empty"
91
+ };
92
+ }
93
+ let cursor = options.cursor;
94
+ try {
95
+ for await (const frame of iterateSse(body, options.signal)) {
96
+ options.onFrame?.(frame);
97
+ if (frame.id)
98
+ cursor = frame.id;
99
+ switch (frame.event) {
100
+ case "run_event": {
101
+ const event = parseRunEventFrame(frame.data);
102
+ if (event) {
103
+ // The dashboard duplicates the cursor inside the data
104
+ // payload — prefer it if present, since it survives proxies
105
+ // that strip the `id:` line.
106
+ const payloadCursor = readStringField(event, "cursor");
107
+ if (payloadCursor)
108
+ cursor = payloadCursor;
109
+ yield event;
110
+ }
111
+ break;
112
+ }
113
+ case "terminal": {
114
+ const status = readStringField(parseJsonObject(frame.data) ?? {}, "status");
115
+ outcome = {
116
+ kind: "terminal",
117
+ nextCursor: cursor,
118
+ ...(status ? { terminalStatus: status } : {})
119
+ };
120
+ return outcome;
121
+ }
122
+ case "gone": {
123
+ outcome = {
124
+ kind: "disconnected",
125
+ nextCursor: cursor,
126
+ error: "run no longer exists"
127
+ };
128
+ return outcome;
129
+ }
130
+ case "error": {
131
+ const message = readStringField(parseJsonObject(frame.data) ?? {}, "message") ?? "SSE stream reported an error";
132
+ outcome = {
133
+ kind: "disconnected",
134
+ nextCursor: cursor,
135
+ error: message
136
+ };
137
+ return outcome;
138
+ }
139
+ // `ready` and `ping` are no-ops — they keep proxies alive and
140
+ // surface the initial cursor; consumers see them via `onFrame`.
141
+ }
142
+ }
143
+ }
144
+ catch (err) {
145
+ return {
146
+ kind: options.signal?.aborted ? "aborted" : "disconnected",
147
+ nextCursor: cursor,
148
+ error: err instanceof Error ? err.message : String(err)
149
+ };
150
+ }
151
+ // Stream ended without a terminal frame (server closed unexpectedly).
152
+ return {
153
+ kind: options.signal?.aborted ? "aborted" : "disconnected",
154
+ nextCursor: cursor
155
+ };
156
+ }
157
+ function parseRunEventFrame(data) {
158
+ const parsed = parseJsonObject(data);
159
+ if (!parsed)
160
+ return null;
161
+ // Run events always carry id + type; reject malformed frames.
162
+ const id = readStringField(parsed, "id");
163
+ const type = readStringField(parsed, "type");
164
+ if (!id || !type)
165
+ return null;
166
+ return parsed;
167
+ }
168
+ function parseJsonObject(data) {
169
+ if (data.length === 0)
170
+ return null;
171
+ try {
172
+ const value = JSON.parse(data);
173
+ if (value && typeof value === "object" && !Array.isArray(value)) {
174
+ return value;
175
+ }
176
+ return null;
177
+ }
178
+ catch {
179
+ return null;
180
+ }
181
+ }
182
+ function readStringField(obj, field) {
183
+ const value = obj[field];
184
+ return typeof value === "string" ? value : undefined;
185
+ }
43
186
  export async function listOutputs(http, runId) {
44
187
  const result = await http.request(`/api/runs/${encodeURIComponent(runId)}/outputs`);
45
188
  return result.outputs;
@@ -73,22 +216,22 @@ export async function downloadRunArchive(http, runId) {
73
216
  return response;
74
217
  }
75
218
  // ===========================================================================
76
- // Flat (Skill / McpServer / Blueprint) operations
219
+ // Run submission operations (Skill / McpServer / Blueprint composition)
77
220
  // ===========================================================================
78
- export async function submitRunFlat(http, request) {
221
+ export async function submitRun(http, request) {
79
222
  return http.request("/api/runs", {
80
223
  method: "POST",
81
224
  body: JSON.stringify(request)
82
225
  });
83
226
  }
84
227
  /**
85
- * Multipart variant of `submitRunFlat` for runs that carry transient
228
+ * Multipart variant of `submitRun` for runs that carry transient
86
229
  * (per-run) skill bundles and/or transient AgentsMd content.
87
230
  *
88
231
  * The JSON submission travels as the `submission` part; each
89
- * `TransientSkillRef.slot` in `request.submission.skills` MUST be
232
+ * `InlineSkillRef.slot` in `request.submission.skills` MUST be
90
233
  * mirrored by exactly one `skill:<slot>` part with the bundle bytes.
91
- * Each `TransientAgentsMdRef.slot` in `request.submission.agentsMd`
234
+ * Each `InlineAgentsMdRef.slot` in `request.submission.agentsMd`
92
235
  * MUST be mirrored by exactly one `agentsmd:<slot>` part with the
93
236
  * markdown text.
94
237
  *
@@ -97,12 +240,12 @@ export async function submitRunFlat(http, request) {
97
240
  *
98
241
  * At least one of `bundles` or `agentsMdParts` must be non-empty.
99
242
  */
100
- export async function submitRunFlatMultipart(http, request, bundles, agentsMdParts, fileParts) {
243
+ export async function submitRunMultipart(http, request, bundles, agentsMdParts, fileParts) {
101
244
  const hasBundles = Array.isArray(bundles) && bundles.length > 0;
102
245
  const hasAgentsMd = Array.isArray(agentsMdParts) && agentsMdParts.length > 0;
103
246
  const hasFiles = Array.isArray(fileParts) && fileParts.length > 0;
104
247
  if (!hasBundles && !hasAgentsMd && !hasFiles) {
105
- throw new Error("submitRunFlatMultipart: bundles, agentsMdParts, or fileParts must be non-empty");
248
+ throw new Error("submitRunMultipart: bundles, agentsMdParts, or fileParts must be non-empty");
106
249
  }
107
250
  const form = new FormData();
108
251
  // Submission rides as a typed JSON Blob so the BFF reads
@@ -112,10 +255,10 @@ export async function submitRunFlatMultipart(http, request, bundles, agentsMdPar
112
255
  const seen = new Set();
113
256
  for (const bundle of bundles) {
114
257
  if (typeof bundle.slot !== "string" || !bundle.slot) {
115
- throw new Error("submitRunFlatMultipart: each bundle must have a non-empty slot id");
258
+ throw new Error("submitRunMultipart: each bundle must have a non-empty slot id");
116
259
  }
117
260
  if (seen.has(bundle.slot)) {
118
- throw new Error(`submitRunFlatMultipart: duplicate transient skill slot "${bundle.slot}"`);
261
+ throw new Error(`submitRunMultipart: duplicate inline skill slot "${bundle.slot}"`);
119
262
  }
120
263
  seen.add(bundle.slot);
121
264
  const blob = toBlob(bundle.bytes, "application/zip");
@@ -123,11 +266,11 @@ export async function submitRunFlatMultipart(http, request, bundles, agentsMdPar
123
266
  }
124
267
  for (const part of agentsMdParts ?? []) {
125
268
  if (typeof part.slot !== "string" || !part.slot) {
126
- throw new Error("submitRunFlatMultipart: each agentsMd part must have a non-empty slot id");
269
+ throw new Error("submitRunMultipart: each agentsMd part must have a non-empty slot id");
127
270
  }
128
271
  const partKey = `agentsmd:${part.slot}`;
129
272
  if (seen.has(partKey)) {
130
- throw new Error(`submitRunFlatMultipart: duplicate agentsMd slot "${part.slot}"`);
273
+ throw new Error(`submitRunMultipart: duplicate agentsMd slot "${part.slot}"`);
131
274
  }
132
275
  seen.add(partKey);
133
276
  const blob = new Blob([part.content], { type: "text/plain" });
@@ -135,11 +278,11 @@ export async function submitRunFlatMultipart(http, request, bundles, agentsMdPar
135
278
  }
136
279
  for (const part of fileParts ?? []) {
137
280
  if (typeof part.slot !== "string" || !part.slot) {
138
- throw new Error("submitRunFlatMultipart: each file part must have a non-empty slot id");
281
+ throw new Error("submitRunMultipart: each file part must have a non-empty slot id");
139
282
  }
140
283
  const partKey = `file:${part.slot}`;
141
284
  if (seen.has(partKey)) {
142
- throw new Error(`submitRunFlatMultipart: duplicate file slot "${part.slot}"`);
285
+ throw new Error(`submitRunMultipart: duplicate file slot "${part.slot}"`);
143
286
  }
144
287
  seen.add(partKey);
145
288
  const blob = toBlob(part.bytes, "application/zip");
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Per-run Antpath provider proxy URL + bearer minting types.
3
+ *
4
+ * The provider proxy is the second of Antpath's two
5
+ * runtime-independent proxies (the other is the MCP proxy in
6
+ * `./mcp-proxy-url.ts`). It sits between the self-hosted runner and
7
+ * the customer's provider API — today that's DeepSeek's
8
+ * Anthropic-compatible endpoint, but the route is namespaced so
9
+ * additional providers slot in without a wire-format change.
10
+ *
11
+ * The runner container sees only `ANTHROPIC_BASE_URL=<proxy-url>` and
12
+ * `ANTHROPIC_AUTH_TOKEN=<scoped-bearer>`; the real provider key + base
13
+ * URL stay in the run Vault bundle. See
14
+ * `references/deepseek-runtime-mcp-plan.md` (Provider proxy +
15
+ * Security requirements).
16
+ */
17
+ import type { RunProvider } from "./submission.js";
18
+ /**
19
+ * Platform-reserved key under which the per-run provider proxy bearer
20
+ * is folded into the Vault bundle. Distinct from
21
+ * `__antpath_proxy_token` (customer-declared HTTP proxy) and
22
+ * `__antpath_mcp_proxy_token` (MCP proxy) so the three capabilities
23
+ * are revoked independently. The shared `parseInlineSecrets` rejects
24
+ * any inbound submission whose `secrets` carries a key with the
25
+ * `__antpath_` prefix; only the BFF mutates this after the parser.
26
+ */
27
+ export declare const PROVIDER_PROXY_BEARER_BUNDLE_KEY = "__antpath_provider_proxy_token";
28
+ /**
29
+ * Output of the per-run provider proxy bearer mint. Same primitive
30
+ * (high-entropy random + peppered SHA-256) as the customer-proxy +
31
+ * MCP-proxy mints; persisted in dedicated columns / Vault keys so
32
+ * the three capabilities don't share a fate.
33
+ */
34
+ export interface MintedProviderProxyBearer {
35
+ readonly plaintext: string;
36
+ readonly hash: string;
37
+ readonly expiresAt: Date;
38
+ }
39
+ /**
40
+ * DeepSeek's documented Anthropic-compatibility endpoint. Used by the
41
+ * provider proxy as the default upstream when the customer does not
42
+ * supply `secrets.deepseek.baseUrl`. Subject to DeepSeek's own
43
+ * upstream changes — see `references/deepseek-runtime-mcp-plan.md`
44
+ * (Source facts to re-check).
45
+ */
46
+ export declare const DEEPSEEK_ANTHROPIC_COMPAT_DEFAULT_BASE_URL = "https://api.deepseek.com/anthropic";
47
+ /**
48
+ * Canonical URL path of the per-run provider proxy endpoint. The BFF
49
+ * route lives at `/api/runs/[runId]/provider-proxy/[providerName]`;
50
+ * the runner / runtime receives the absolute URL from
51
+ * {@link buildProviderProxyUrl}.
52
+ */
53
+ export declare function providerProxyPath(runId: string, provider: RunProvider): string;
54
+ /**
55
+ * Build the absolute per-run, per-provider proxy URL. `baseUrl` is the
56
+ * configured Antpath API plane root (e.g. `https://api.antpath.ai`);
57
+ * the function strips any trailing slash and appends the canonical
58
+ * provider proxy path.
59
+ */
60
+ export declare function buildProviderProxyUrl(args: {
61
+ readonly baseUrl: string;
62
+ readonly runId: string;
63
+ readonly provider: RunProvider;
64
+ }): string;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Per-run Antpath provider proxy URL + bearer minting types.
3
+ *
4
+ * The provider proxy is the second of Antpath's two
5
+ * runtime-independent proxies (the other is the MCP proxy in
6
+ * `./mcp-proxy-url.ts`). It sits between the self-hosted runner and
7
+ * the customer's provider API — today that's DeepSeek's
8
+ * Anthropic-compatible endpoint, but the route is namespaced so
9
+ * additional providers slot in without a wire-format change.
10
+ *
11
+ * The runner container sees only `ANTHROPIC_BASE_URL=<proxy-url>` and
12
+ * `ANTHROPIC_AUTH_TOKEN=<scoped-bearer>`; the real provider key + base
13
+ * URL stay in the run Vault bundle. See
14
+ * `references/deepseek-runtime-mcp-plan.md` (Provider proxy +
15
+ * Security requirements).
16
+ */
17
+ /**
18
+ * Platform-reserved key under which the per-run provider proxy bearer
19
+ * is folded into the Vault bundle. Distinct from
20
+ * `__antpath_proxy_token` (customer-declared HTTP proxy) and
21
+ * `__antpath_mcp_proxy_token` (MCP proxy) so the three capabilities
22
+ * are revoked independently. The shared `parseInlineSecrets` rejects
23
+ * any inbound submission whose `secrets` carries a key with the
24
+ * `__antpath_` prefix; only the BFF mutates this after the parser.
25
+ */
26
+ export const PROVIDER_PROXY_BEARER_BUNDLE_KEY = "__antpath_provider_proxy_token";
27
+ /**
28
+ * DeepSeek's documented Anthropic-compatibility endpoint. Used by the
29
+ * provider proxy as the default upstream when the customer does not
30
+ * supply `secrets.deepseek.baseUrl`. Subject to DeepSeek's own
31
+ * upstream changes — see `references/deepseek-runtime-mcp-plan.md`
32
+ * (Source facts to re-check).
33
+ */
34
+ export const DEEPSEEK_ANTHROPIC_COMPAT_DEFAULT_BASE_URL = "https://api.deepseek.com/anthropic";
35
+ /**
36
+ * Canonical URL path of the per-run provider proxy endpoint. The BFF
37
+ * route lives at `/api/runs/[runId]/provider-proxy/[providerName]`;
38
+ * the runner / runtime receives the absolute URL from
39
+ * {@link buildProviderProxyUrl}.
40
+ */
41
+ export function providerProxyPath(runId, provider) {
42
+ if (!runId || typeof runId !== "string") {
43
+ throw new Error("providerProxyPath: runId must be a non-empty string");
44
+ }
45
+ if (provider !== "anthropic" && provider !== "deepseek") {
46
+ throw new Error(`providerProxyPath: unsupported provider ${JSON.stringify(provider)}`);
47
+ }
48
+ return `/api/runs/${encodeURIComponent(runId)}/provider-proxy/${provider}`;
49
+ }
50
+ /**
51
+ * Build the absolute per-run, per-provider proxy URL. `baseUrl` is the
52
+ * configured Antpath API plane root (e.g. `https://api.antpath.ai`);
53
+ * the function strips any trailing slash and appends the canonical
54
+ * provider proxy path.
55
+ */
56
+ export function buildProviderProxyUrl(args) {
57
+ if (!args.baseUrl || typeof args.baseUrl !== "string") {
58
+ throw new Error("buildProviderProxyUrl: baseUrl must be a non-empty string");
59
+ }
60
+ let parsedBase;
61
+ try {
62
+ parsedBase = new URL(args.baseUrl);
63
+ }
64
+ catch {
65
+ throw new Error(`buildProviderProxyUrl: baseUrl is not a valid URL: ${args.baseUrl}`);
66
+ }
67
+ if (parsedBase.protocol !== "https:" && parsedBase.protocol !== "http:") {
68
+ throw new Error(`buildProviderProxyUrl: baseUrl protocol must be http or https (got ${parsedBase.protocol})`);
69
+ }
70
+ const trimmedBase = `${parsedBase.origin}${parsedBase.pathname.replace(/\/+$/, "")}`;
71
+ return `${trimmedBase}${providerProxyPath(args.runId, args.provider)}`;
72
+ }
73
+ //# sourceMappingURL=provider-proxy-url.js.map
@@ -14,6 +14,6 @@ export declare function validateProxyAuth(endpoints: readonly PlatformProxyEndpo
14
14
  * caller is hand-rolling networking.
15
15
  */
16
16
  export declare function buildPlatformAllowedHosts(input: {
17
- readonly dashboardBaseUrl: string;
17
+ readonly baseUrl: string;
18
18
  readonly extraHosts?: readonly string[];
19
19
  }): readonly string[];
@@ -37,10 +37,10 @@ export function validateProxyAuth(endpoints, auth) {
37
37
  export function buildPlatformAllowedHosts(input) {
38
38
  const result = [];
39
39
  try {
40
- result.push(new URL(input.dashboardBaseUrl).host);
40
+ result.push(new URL(input.baseUrl).host);
41
41
  }
42
42
  catch {
43
- throw new Error("buildPlatformAllowedHosts: dashboardBaseUrl must be an absolute URL");
43
+ throw new Error("buildPlatformAllowedHosts: baseUrl must be an absolute URL");
44
44
  }
45
45
  for (const host of input.extraHosts ?? []) {
46
46
  if (!result.includes(host))
@@ -19,36 +19,16 @@
19
19
  * `rawEventPages` (manifest only; bytes downloaded out-of-band so the
20
20
  * detail response stays bounded). The archive zip carries the bytes.
21
21
  */
22
- import type { JsonValue, PlatformCleanupPolicy, PlatformFlatSubmission, PlatformProxyEndpoint, PlatformTemplateSubmission } from "./submission.js";
22
+ import type { JsonValue, PlatformCleanupPolicy, PlatformSubmission, PlatformProxyEndpoint } from "./submission.js";
23
23
  /**
24
- * Parsed view of `runs.template_snapshot` jsonb. Two historical shapes
25
- * coexist in storage:
26
- *
27
- * - `kind: "flat"` (current): {kind:"flat", submission, cleanup?}
28
- * written by `insertRunWithSkillSnapshots` for all new runs.
29
- * - legacy template-shaped: {template, executionPayloadSecretId,
30
- * variables?, cleanup?} written by `insertRun` before the flat
31
- * pivot.
32
- *
33
- * The parser tolerates both and returns a discriminated union so
34
- * consumers branch mechanically. New work targets `kind: "flat"`.
35
- *
36
- * Note on legacy redaction: historic template-shaped snapshots have
37
- * `system` and `messages` replaced with `"[redacted]"` by
38
- * `redactTemplateForMetadata`. That redaction predates the raw-event /
39
- * raw-input policy update and we do not retroactively un-redact data we
40
- * never stored. Flat-shape snapshots are verbatim.
24
+ * Parsed view of `runs.template_snapshot` jsonb. Stored shape is
25
+ * `{kind:"submission", submission, cleanup?}` written by
26
+ * `insertRunWithSkillSnapshots` for all runs.
41
27
  */
42
- export type RunUnitSubmission = RunUnitFlatSubmission | RunUnitTemplateSubmission;
28
+ export type RunUnitSubmission = RunUnitFlatSubmission;
43
29
  export interface RunUnitFlatSubmission {
44
- readonly kind: "flat";
45
- readonly submission: PlatformFlatSubmission;
46
- readonly cleanup?: PlatformCleanupPolicy;
47
- }
48
- export interface RunUnitTemplateSubmission {
49
- readonly kind: "template";
50
- readonly template: PlatformTemplateSubmission;
51
- readonly variables?: Record<string, JsonValue>;
30
+ readonly kind: "submission";
31
+ readonly submission: PlatformSubmission;
52
32
  readonly cleanup?: PlatformCleanupPolicy;
53
33
  }
54
34
  export interface RunUnitAttempt {
@@ -157,7 +137,7 @@ export interface RunUnitProviderSkill {
157
137
  readonly skillId: string;
158
138
  readonly version?: string;
159
139
  }
160
- export interface RunUnitTransientSkill {
140
+ export interface RunUnitInlineSkill {
161
141
  readonly id: string;
162
142
  readonly slotId: string;
163
143
  readonly skillName: string;
@@ -190,17 +170,24 @@ export interface RunUnit {
190
170
  readonly proxyCalls: RunUnitProxyCallPage;
191
171
  readonly skillSnapshots: readonly RunUnitSkillSnapshot[];
192
172
  readonly providerSkills: readonly RunUnitProviderSkill[];
193
- readonly transientSkills: readonly RunUnitTransientSkill[];
173
+ readonly inlineSkills: readonly RunUnitInlineSkill[];
174
+ /**
175
+ * Per-run, per-provider runtime manifest — derived from the validated
176
+ * submission + the chosen provider (`buildRuntimeManifest`). Tells
177
+ * SDK consumers where antpath placed things in-container and what
178
+ * env vars the agent will see. Undefined on responses from BFFs
179
+ * that predate Phase 2 of the runtime-environment rollout.
180
+ */
181
+ readonly runtimeManifest?: import("./runtime-manifest.js").RuntimeManifest;
194
182
  }
195
183
  /**
196
- * Parse a `runs.template_snapshot` jsonb payload into the typed
197
- * discriminated union. Tolerates both flat and legacy template shapes;
198
- * never throws on minor unknown keys so we can forward-compat with
199
- * worker-side enrichment.
184
+ * Parse a `runs.template_snapshot` jsonb payload into the typed flat
185
+ * submission. Never throws on minor unknown keys so we can
186
+ * forward-compat with worker-side enrichment.
200
187
  *
201
188
  * Returns a typed shape even for malformed snapshots — the worst case
202
- * is `{kind: "flat", submission: {model: "", ...}}` with empty defaults
203
- * — because the dashboard must still render *something* for a buggy
204
- * historical row rather than 500ing the whole detail page.
189
+ * is `{kind: "submission", submission: {model: "", ...}}` with empty
190
+ * defaults — because the dashboard must still render *something* for a
191
+ * buggy historical row rather than 500ing the whole detail page.
205
192
  */
206
193
  export declare function parseRunUnitSubmission(input: unknown): RunUnitSubmission;
@@ -24,29 +24,25 @@ import { parseMcpServerRef, parseSkillRef } from "./blueprint.js";
24
24
  // Submission parser
25
25
  // ---------------------------------------------------------------------------
26
26
  /**
27
- * Parse a `runs.template_snapshot` jsonb payload into the typed
28
- * discriminated union. Tolerates both flat and legacy template shapes;
29
- * never throws on minor unknown keys so we can forward-compat with
30
- * worker-side enrichment.
27
+ * Parse a `runs.template_snapshot` jsonb payload into the typed flat
28
+ * submission. Never throws on minor unknown keys so we can
29
+ * forward-compat with worker-side enrichment.
31
30
  *
32
31
  * Returns a typed shape even for malformed snapshots — the worst case
33
- * is `{kind: "flat", submission: {model: "", ...}}` with empty defaults
34
- * — because the dashboard must still render *something* for a buggy
35
- * historical row rather than 500ing the whole detail page.
32
+ * is `{kind: "submission", submission: {model: "", ...}}` with empty
33
+ * defaults — because the dashboard must still render *something* for a
34
+ * buggy historical row rather than 500ing the whole detail page.
36
35
  */
37
36
  export function parseRunUnitSubmission(input) {
38
37
  if (!input || typeof input !== "object" || Array.isArray(input)) {
39
38
  return fallbackFlat();
40
39
  }
41
40
  const value = input;
42
- if (value.kind === "flat") {
41
+ if (value.kind === "submission") {
43
42
  return parseFlatProjection(value);
44
43
  }
45
- if (isRecord(value.template)) {
46
- return parseTemplateProjection(value);
47
- }
48
- // Snapshot exists but matches neither shape — surface as an empty
49
- // flat submission so consumers can still render lifecycle bits.
44
+ // Snapshot exists but does not match the flat shape — surface as an
45
+ // empty flat submission so consumers can still render lifecycle bits.
50
46
  return fallbackFlat();
51
47
  }
52
48
  function parseFlatProjection(value) {
@@ -69,36 +65,14 @@ function parseFlatProjection(value) {
69
65
  : {})
70
66
  };
71
67
  return {
72
- kind: "flat",
68
+ kind: "submission",
73
69
  submission,
74
70
  ...(cleanup ? { cleanup } : {})
75
71
  };
76
72
  }
77
- function parseTemplateProjection(value) {
78
- const templateRaw = value.template;
79
- const template = {
80
- name: typeof templateRaw.name === "string" ? templateRaw.name : "",
81
- model: typeof templateRaw.model === "string" ? templateRaw.model : "",
82
- templateHash: typeof templateRaw.templateHash === "string" ? templateRaw.templateHash : "",
83
- messages: toStringArray(templateRaw.messages),
84
- ...(typeof templateRaw.system === "string" ? { system: templateRaw.system } : {}),
85
- ...(isJsonRecord(templateRaw.metadata) ? { metadata: templateRaw.metadata } : {}),
86
- ...(parseEnvironment(templateRaw.environment)
87
- ? { environment: parseEnvironment(templateRaw.environment) }
88
- : {})
89
- };
90
- const variables = isJsonRecord(value.variables) ? value.variables : undefined;
91
- const cleanup = parseCleanup(value.cleanup);
92
- return {
93
- kind: "template",
94
- template,
95
- ...(variables ? { variables } : {}),
96
- ...(cleanup ? { cleanup } : {})
97
- };
98
- }
99
73
  function fallbackFlat() {
100
74
  return {
101
- kind: "flat",
75
+ kind: "submission",
102
76
  submission: {
103
77
  model: "",
104
78
  prompt: [],
@@ -140,7 +114,7 @@ function toSkillRefArray(value) {
140
114
  const out = [];
141
115
  for (let i = 0; i < value.length; i++) {
142
116
  try {
143
- out.push(parseSkillRef(value[i], `submission.skills[${i}]`, { allowTransient: true }));
117
+ out.push(parseSkillRef(value[i], `submission.skills[${i}]`));
144
118
  }
145
119
  catch {
146
120
  // Skip malformed entries rather than failing the whole detail
@@ -195,7 +169,22 @@ function parseEnvironment(value) {
195
169
  env.packages = pkgs;
196
170
  }
197
171
  }
198
- return env.networking || env.packages
172
+ // Lenient pass-through for envVars stored in already-validated
173
+ // snapshots. The strict parser in submission.ts enforces shape /
174
+ // size / reserved-prefix rules at submission time; here we just
175
+ // accept whatever shape was persisted.
176
+ if (isRecord(value.envVars)) {
177
+ const out = {};
178
+ for (const [k, v] of Object.entries(value.envVars)) {
179
+ if (typeof v === "string") {
180
+ out[k] = v;
181
+ }
182
+ }
183
+ if (Object.keys(out).length > 0) {
184
+ env.envVars = out;
185
+ }
186
+ }
187
+ return env.networking || env.packages || env.envVars
199
188
  ? env
200
189
  : undefined;
201
190
  }
@@ -204,14 +193,9 @@ function parseCleanup(value) {
204
193
  return undefined;
205
194
  }
206
195
  const session = value.session;
207
- const claudeSession = value.claudeSession;
208
- const out = {};
209
196
  if (session === "retain" || session === "delete") {
210
- out.session = session;
211
- }
212
- if (claudeSession === "retain" || claudeSession === "delete") {
213
- out.claudeSession = claudeSession;
197
+ return { session };
214
198
  }
215
- return out.session || out.claudeSession ? out : undefined;
199
+ return undefined;
216
200
  }
217
201
  //# sourceMappingURL=run-unit.js.map