@aexhq/sdk 0.18.1 → 0.20.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 (47) hide show
  1. package/README.md +2 -2
  2. package/dist/_contracts/models.d.ts +133 -38
  3. package/dist/_contracts/models.js +114 -69
  4. package/dist/_contracts/operations.d.ts +17 -1
  5. package/dist/_contracts/operations.js +50 -0
  6. package/dist/_contracts/provider-support.d.ts +68 -0
  7. package/dist/_contracts/provider-support.js +28 -0
  8. package/dist/_contracts/run-config.d.ts +1 -1
  9. package/dist/_contracts/run-cost.d.ts +27 -0
  10. package/dist/_contracts/run-cost.js +34 -1
  11. package/dist/_contracts/runtime-types.d.ts +32 -0
  12. package/dist/_contracts/submission.d.ts +58 -2
  13. package/dist/_contracts/submission.js +106 -7
  14. package/dist/agents-md.d.ts +3 -3
  15. package/dist/agents-md.js +6 -6
  16. package/dist/agents-md.js.map +1 -1
  17. package/dist/cli.mjs +116 -86
  18. package/dist/cli.mjs.sha256 +1 -1
  19. package/dist/client.d.ts +90 -10
  20. package/dist/client.js +121 -40
  21. package/dist/client.js.map +1 -1
  22. package/dist/fetch-archive.js +1 -1
  23. package/dist/file.d.ts +3 -3
  24. package/dist/file.js +6 -6
  25. package/dist/file.js.map +1 -1
  26. package/dist/index.d.ts +6 -4
  27. package/dist/index.js +3 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/proxy-endpoint.d.ts +2 -2
  30. package/dist/proxy-endpoint.js +1 -1
  31. package/dist/secret.d.ts +102 -0
  32. package/dist/secret.js +148 -0
  33. package/dist/secret.js.map +1 -0
  34. package/dist/skill.d.ts +8 -8
  35. package/dist/skill.js +10 -10
  36. package/dist/skill.js.map +1 -1
  37. package/dist/version.d.ts +1 -1
  38. package/dist/version.js +1 -1
  39. package/docs/cleanup.md +1 -1
  40. package/docs/credentials.md +4 -4
  41. package/docs/events.md +2 -2
  42. package/docs/outputs.md +3 -3
  43. package/docs/provider-runtime-capabilities.md +23 -1
  44. package/docs/quickstart.md +7 -7
  45. package/docs/run-config.md +4 -4
  46. package/docs/skills.md +4 -4
  47. package/package.json +2 -2
@@ -109,6 +109,34 @@ export const PROVIDER_PUBLIC_SUPPORT = {
109
109
  runtimeEvidence: {
110
110
  managed: COMMON_EVIDENCE
111
111
  }
112
+ },
113
+ // Doubao (ByteDance) via the official Ark API — international BytePlus gateway.
114
+ // Wired + parser/routing-verified but not yet proven against a live BytePlus
115
+ // account, so `live-unverified`. Promote to `supported` (and swap COMMON_EVIDENCE
116
+ // for a DOUBAO_MANAGED_EVIDENCE pointer to live-sdk-doubao.test.ts) once the
117
+ // live run passes.
118
+ doubao: {
119
+ displayName: "Doubao",
120
+ status: "live-unverified",
121
+ docsAnchor: "doubao",
122
+ docs: COMMON_DOCS,
123
+ evidence: COMMON_EVIDENCE,
124
+ runtimeEvidence: {
125
+ managed: COMMON_EVIDENCE
126
+ }
127
+ },
128
+ // Doubao (ByteDance) via the official Ark API — China Volcengine gateway.
129
+ // Same wiring as `doubao`; additionally gated on CF Worker egress reaching the
130
+ // Beijing host (see apps/egress-probe). `live-unverified` until proven live.
131
+ "doubao-cn": {
132
+ displayName: "Doubao (China)",
133
+ status: "live-unverified",
134
+ docsAnchor: "doubao-cn",
135
+ docs: COMMON_DOCS,
136
+ evidence: COMMON_EVIDENCE,
137
+ runtimeEvidence: {
138
+ managed: COMMON_EVIDENCE
139
+ }
112
140
  }
113
141
  };
114
142
  export function providerPublicSupport(provider) {
@@ -251,7 +251,7 @@ export declare function rejectStdioMcpShape(record: Record<string, unknown>): vo
251
251
  /**
252
252
  * Plain JSON accepted by `aex run --config <path>`. This is not a
253
253
  * platform object; it is only the non-secret run parameters that the CLI folds
254
- * into the normal `submitRun` request.
254
+ * into the normal `submit` request.
255
255
  */
256
256
  export interface RunRequestConfig {
257
257
  readonly model: RunModel;
@@ -92,6 +92,21 @@ export interface RunCostManagedKeyBudgetTelemetry {
92
92
  readonly chargedCreditUnits?: number;
93
93
  readonly releasedCreditUnits?: number;
94
94
  }
95
+ /**
96
+ * The basis for a {@link RunCostTelemetry.billedCostUsd}: an honest marker of
97
+ * whether the figure is a settle-time ESTIMATE or has been RECONCILED against
98
+ * authoritative actuals. Deliberately carries NO rate-card version or unit
99
+ * rates — the platform's public-safe convention treats `rateCard`/`margin` as
100
+ * private tokens (run-cost.test.ts privateCostFieldPattern), so the version the
101
+ * figure was derived under stays internal (recorded only in the platform's
102
+ * internal raw-usage export).
103
+ */
104
+ export declare const RUN_COST_BASIS_STATUSES: readonly ["estimated", "reconciled"];
105
+ export type RunCostBasisStatus = (typeof RUN_COST_BASIS_STATUSES)[number];
106
+ export interface RunCostBasis {
107
+ readonly currency: "USD";
108
+ readonly status: RunCostBasisStatus;
109
+ }
95
110
  export interface RunCostTelemetry {
96
111
  readonly schemaVersion: typeof RUN_COST_TELEMETRY_SCHEMA_VERSION;
97
112
  readonly runId?: string;
@@ -108,6 +123,18 @@ export interface RunCostTelemetry {
108
123
  readonly storage?: RunCostStorageTelemetry;
109
124
  readonly proxy?: RunCostProxyTelemetry;
110
125
  readonly managedKey?: RunCostManagedKeyBudgetTelemetry;
126
+ /**
127
+ * Customer-facing AEX cost of serving this run, USD — a REPORTED ESTIMATE,
128
+ * not a charge (telemetry/showback only; no invoicing or credit deduction).
129
+ * = rawCostUsd × marginMultiplier (margin currently a global 1.0). EXCLUDES
130
+ * the customer's BYOK provider spend. The raw (pre-margin) figure is kept
131
+ * internal and never appears on this public-safe shape. A plain number, so it
132
+ * passes the run-record public-safe archive scan. Absent when the run incurred
133
+ * no priced AEX usage.
134
+ */
135
+ readonly billedCostUsd?: number;
136
+ /** Currency + estimate/reconciled basis for {@link billedCostUsd}. */
137
+ readonly costBasis?: RunCostBasis;
111
138
  }
112
139
  export type RunCostTelemetryInput = Omit<RunCostTelemetry, "schemaVersion">;
113
140
  export interface RunCostTelemetryFromUsageSamplesInput {
@@ -96,6 +96,16 @@ const RUN_USAGE_SAMPLE_METRIC_UNITS = {
96
96
  "managed_key.charged_credit_units": "credit_unit",
97
97
  "managed_key.released_credit_units": "credit_unit"
98
98
  };
99
+ /**
100
+ * The basis for a {@link RunCostTelemetry.billedCostUsd}: an honest marker of
101
+ * whether the figure is a settle-time ESTIMATE or has been RECONCILED against
102
+ * authoritative actuals. Deliberately carries NO rate-card version or unit
103
+ * rates — the platform's public-safe convention treats `rateCard`/`margin` as
104
+ * private tokens (run-cost.test.ts privateCostFieldPattern), so the version the
105
+ * figure was derived under stays internal (recorded only in the platform's
106
+ * internal raw-usage export).
107
+ */
108
+ export const RUN_COST_BASIS_STATUSES = ["estimated", "reconciled"];
99
109
  export function buildRunUsageSample(input) {
100
110
  const metric = normalizeUsageSampleMetric(input.metric);
101
111
  const expectedUnit = RUN_USAGE_SAMPLE_METRIC_UNITS[metric];
@@ -134,7 +144,9 @@ export function buildRunCostTelemetry(input) {
134
144
  ...(input.providerUsage ? { providerUsage: input.providerUsage.map(normalizeProviderUsage) } : {}),
135
145
  ...(input.storage ? { storage: normalizeStorage(input.storage) } : {}),
136
146
  ...(input.proxy ? { proxy: normalizeProxy(input.proxy) } : {}),
137
- ...(input.managedKey ? { managedKey: normalizeManagedKey(input.managedKey) } : {})
147
+ ...(input.managedKey ? { managedKey: normalizeManagedKey(input.managedKey) } : {}),
148
+ ...(input.billedCostUsd !== undefined ? { billedCostUsd: nonNegativeFinite(input.billedCostUsd, "billedCostUsd") } : {}),
149
+ ...(input.costBasis ? { costBasis: normalizeCostBasis(input.costBasis) } : {})
138
150
  });
139
151
  }
140
152
  export function buildRunCostTelemetryFromUsageSamples(input) {
@@ -318,6 +330,11 @@ export function mergeRunCostTelemetry(base, next) {
318
330
  const storage = sumStorage(base.storage, patch.storage);
319
331
  const proxy = sumProxy(base.proxy, patch.proxy);
320
332
  const managedKey = mergeManagedKey(base.managedKey, patch.managedKey);
333
+ // Derived cost fields are LAST-WRITER-WINS (a re-derivation supersedes the
334
+ // prior estimate), not summed — they are projections of the whole sample set,
335
+ // not additive metrics.
336
+ const billedCostUsd = patch.billedCostUsd ?? base.billedCostUsd;
337
+ const costBasis = patch.costBasis ?? base.costBasis;
321
338
  if (runId)
322
339
  merged.runId = runId;
323
340
  if (provider)
@@ -346,6 +363,10 @@ export function mergeRunCostTelemetry(base, next) {
346
363
  merged.proxy = proxy;
347
364
  if (managedKey)
348
365
  merged.managedKey = managedKey;
366
+ if (billedCostUsd !== undefined)
367
+ merged.billedCostUsd = billedCostUsd;
368
+ if (costBasis)
369
+ merged.costBasis = costBasis;
349
370
  return buildRunCostTelemetry(merged);
350
371
  }
351
372
  function normalizeDurations(input) {
@@ -470,6 +491,18 @@ function normalizeSummaryStatus(input) {
470
491
  }
471
492
  return input;
472
493
  }
494
+ function normalizeCostBasis(input) {
495
+ if (!input || typeof input !== "object") {
496
+ throw new Error("run cost basis must be an object");
497
+ }
498
+ if (input.currency !== "USD") {
499
+ throw new Error(`run cost basis currency ${String(input.currency)} is not supported`);
500
+ }
501
+ if (!isStringIn(input.status, RUN_COST_BASIS_STATUSES)) {
502
+ throw new Error(`run cost basis status ${String(input.status)} is not supported`);
503
+ }
504
+ return Object.freeze({ currency: "USD", status: input.status });
505
+ }
473
506
  function addProviderUsage(usageByKey, input, sample, field) {
474
507
  const provider = sample.provider ?? input.provider;
475
508
  if (!provider) {
@@ -210,3 +210,35 @@ export interface FileRecord {
210
210
  readonly deletedAt?: string | null;
211
211
  readonly [key: string]: unknown;
212
212
  }
213
+ /**
214
+ * Wire-level record for a workspace secret as returned by the BFF.
215
+ *
216
+ * Workspace secrets share the lifecycle SEMANTIC of skills/files: a
217
+ * `Secret.value(...)` is per-run and gone at terminal; PROMOTING it (or
218
+ * `aex.secrets.set`) persists a named, searchable workspace secret. The
219
+ * identity is the `name` (the handle a `Secret.ref` points at); the value
220
+ * rotates under that stable name, bumping `version`.
221
+ *
222
+ * This record is METADATA ONLY — it never carries the secret value. The value
223
+ * is write-only on create/rotate and readable solely via the audited
224
+ * {@link SecretReveal} path.
225
+ */
226
+ export interface SecretRecord {
227
+ readonly id: string;
228
+ readonly name: string;
229
+ readonly version: number;
230
+ readonly state: "ready";
231
+ readonly createdAt?: string;
232
+ readonly updatedAt?: string;
233
+ readonly deletedAt?: string | null;
234
+ readonly [key: string]: unknown;
235
+ }
236
+ /**
237
+ * Value-bearing result of an audited `aex.secrets.reveal`. The ONLY wire shape
238
+ * that carries a workspace secret value back to the caller. Reveal is a logged
239
+ * action (POST, not GET) so a value read is always attributable.
240
+ */
241
+ export interface SecretReveal {
242
+ readonly name: string;
243
+ readonly value: string;
244
+ }
@@ -105,7 +105,7 @@ export declare function packageInstallString(pkg: PlatformPackage): string;
105
105
  * runtime; provider selection only decides which upstream model route
106
106
  * the managed provider-proxy uses.
107
107
  */
108
- export declare const RUN_PROVIDERS: readonly ["anthropic", "deepseek", "openai", "gemini", "mistral", "openrouter"];
108
+ export declare const RUN_PROVIDERS: readonly ["anthropic", "deepseek", "openai", "gemini", "mistral", "openrouter", "doubao", "doubao-cn"];
109
109
  export type RunProvider = (typeof RUN_PROVIDERS)[number];
110
110
  export declare const DEFAULT_RUN_PROVIDER: RunProvider;
111
111
  /**
@@ -133,6 +133,10 @@ export declare const Providers: {
133
133
  readonly MISTRAL: "mistral";
134
134
  /** OpenRouter — OpenAI-compatible aggregator routing to many upstream models. */
135
135
  readonly OPENROUTER: "openrouter";
136
+ /** Doubao (ByteDance) via the official international BytePlus ModelArk gateway. */
137
+ readonly DOUBAO: "doubao";
138
+ /** Doubao (ByteDance) via the official China Volcengine Ark gateway. */
139
+ readonly DOUBAO_CN: "doubao-cn";
136
140
  };
137
141
  /**
138
142
  * Customer-facing runtime selector. Optional on the wire; absent resolves
@@ -194,6 +198,15 @@ export interface PlatformInlineSecrets {
194
198
  readonly apiKey?: string;
195
199
  readonly mcpServers?: readonly PlatformMcpServerSecret[];
196
200
  readonly proxyEndpointAuth?: readonly PlatformProxyEndpointAuth[];
201
+ /**
202
+ * Per-run env-var secret VALUES, keyed by env name. Each entry pairs with a
203
+ * `submission.secretEnv[<envName>] = { ephemeral: true }` declaration. Lives
204
+ * in the secrets channel so it is vaulted and excluded from the idempotency
205
+ * hash; the runtime injects it as the named env var and it is deleted at the
206
+ * run's terminal. Workspace `{ ref }` bindings resolve server-side and never
207
+ * appear here.
208
+ */
209
+ readonly envSecrets?: Readonly<Record<string, string>>;
197
210
  }
198
211
  /**
199
212
  * Per-run named HTTP proxy endpoint. The `authShape` describes how the
@@ -219,6 +232,21 @@ export interface PlatformProxyEndpoint {
219
232
  readonly retry?: ProxyRetryPolicy;
220
233
  }
221
234
  export declare const SECRETS_KEY = "secrets";
235
+ /** POSIX-style env var name a `secretEnv` entry binds to (e.g. `SERPER_API_KEY`). */
236
+ export declare const SECRET_ENV_NAME_PATTERN: RegExp;
237
+ /** Workspace secret handle a `secretEnv` ref points at (and the name `secret.upload` persists to). */
238
+ export declare const SECRET_HANDLE_PATTERN: RegExp;
239
+ /**
240
+ * One `submission.secretEnv` entry — VALUE-FREE, so it rides the (hashed)
241
+ * submission safely. `{ ref }` resolves a workspace secret server-side;
242
+ * `{ ephemeral: true }` pairs with a `secrets.envSecrets[<envName>]` value
243
+ * (per-run, vaulted, deleted at the run's terminal).
244
+ */
245
+ export type PlatformSecretEnvEntry = {
246
+ readonly ref: string;
247
+ } | {
248
+ readonly ephemeral: true;
249
+ };
222
250
  export declare const PROXY_ENDPOINT_NAME_PATTERN: RegExp;
223
251
  export declare const RESERVED_PROXY_ENDPOINT_NAMES: Set<string>;
224
252
  export declare const deniedSecretFields: Set<string>;
@@ -228,6 +256,16 @@ export declare function parseProxyMethods(input: unknown, field: string): readon
228
256
  export declare function parseProxyPathPrefixes(input: unknown, field: string): readonly string[];
229
257
  export declare function parseProxyAllowedHeaders(input: unknown, field: string, authShape: ProxyAuthShape): readonly string[] | undefined;
230
258
  export declare function crossValidateProxyEndpointsAndAuth(endpoints: readonly PlatformProxyEndpoint[] | undefined, auth: readonly PlatformProxyEndpointAuth[] | undefined): void;
259
+ /**
260
+ * Cross-check `submission.secretEnv` declarations against `secrets.envSecrets`
261
+ * values. Mirrors {@link crossValidateProxyEndpointsAndAuth}:
262
+ *
263
+ * - `{ ephemeral: true }` MUST have a matching `secrets.envSecrets` value.
264
+ * - `{ ref }` MUST NOT supply a value (the value lives in the workspace store).
265
+ * - every `secrets.envSecrets` value MUST have a matching `{ ephemeral: true }`
266
+ * declaration (no orphan values that would never be injected).
267
+ */
268
+ export declare function crossValidateSecretEnvAndValues(secretEnv: Readonly<Record<string, PlatformSecretEnvEntry>> | undefined, envSecrets: Readonly<Record<string, string>> | undefined): void;
231
269
  export declare function parseInlineSecrets(input: unknown): PlatformInlineSecrets;
232
270
  /**
233
271
  * The proxy body-redactor refuses to mask any derived target string shorter
@@ -263,6 +301,15 @@ export interface PlatformSubmission {
263
301
  readonly agentsMd: readonly AgentsMdRef[];
264
302
  readonly files: readonly FileRef[];
265
303
  readonly mcpServers: readonly McpServerRef[];
304
+ /**
305
+ * Env-var secret bindings — VALUE-FREE declarations keyed by env name. Each
306
+ * value is `{ ref }` (resolve a workspace secret server-side) or
307
+ * `{ ephemeral: true }` (value supplied in `secrets.envSecrets`, vaulted and
308
+ * deleted at terminal). The runtime injects the resolved value as the named
309
+ * env var. Lifecycle parity with skills/files: per-run by default, persisted
310
+ * only when promoted to the workspace store.
311
+ */
312
+ readonly secretEnv?: Readonly<Record<string, PlatformSecretEnvEntry>>;
266
313
  readonly environment?: PlatformEnvironment;
267
314
  readonly securityProfile?: RuntimeSecurityProfileName;
268
315
  readonly metadata?: Record<string, JsonValue>;
@@ -369,6 +416,15 @@ export interface PlatformRunSubmissionRequest {
369
416
  * for repair until this budget is exhausted.
370
417
  */
371
418
  readonly postHook?: PlatformPostHook;
419
+ /**
420
+ * Lineage parent (agent-session §9). When present the server admits this
421
+ * run as a CHILD of `parentRunId`: it walks the parent's lineage, enforces
422
+ * the max-subagent-depth + per-root concurrency caps, and persists
423
+ * `parent_run_id` + a server-derived `depth`. The client may name a parent
424
+ * but NEVER the depth — depth is computed server-side from the parent row,
425
+ * so a forged value cannot bypass the cap.
426
+ */
427
+ readonly parentRunId?: string;
372
428
  }
373
429
  /**
374
430
  * Wire shape posted by the SDK and CLI. `workspaceId` is **omitted by
@@ -466,7 +522,7 @@ export declare class RuntimeValidationError extends Error {
466
522
  }
467
523
  /**
468
524
  * Walk the parsed submission and collect features that the active managed
469
- * runtime cannot serve. Provider-hosted skill refs (`Skill.provider(...)`) are
525
+ * runtime cannot serve. Provider-hosted skill refs (`kind:"provider"`) are
470
526
  * rejected now that new submissions only dispatch through managed runs.
471
527
  */
472
528
  export declare function collectManagedUnsupportedFeatures(req: PlatformRunSubmissionRequest): string[];
@@ -80,7 +80,9 @@ export const RUN_PROVIDERS = [
80
80
  "openai",
81
81
  "gemini",
82
82
  "mistral",
83
- "openrouter"
83
+ "openrouter",
84
+ "doubao",
85
+ "doubao-cn"
84
86
  ];
85
87
  export const DEFAULT_RUN_PROVIDER = "anthropic";
86
88
  /**
@@ -107,7 +109,11 @@ export const Providers = {
107
109
  /** Mistral. */
108
110
  MISTRAL: "mistral",
109
111
  /** OpenRouter — OpenAI-compatible aggregator routing to many upstream models. */
110
- OPENROUTER: "openrouter"
112
+ OPENROUTER: "openrouter",
113
+ /** Doubao (ByteDance) via the official international BytePlus ModelArk gateway. */
114
+ DOUBAO: "doubao",
115
+ /** Doubao (ByteDance) via the official China Volcengine Ark gateway. */
116
+ DOUBAO_CN: "doubao-cn"
111
117
  };
112
118
  /**
113
119
  * Customer-facing runtime selector. Optional on the wire; absent resolves
@@ -126,6 +132,10 @@ export function checkRuntimeSupported(provider, runtime) {
126
132
  return { ok: true };
127
133
  }
128
134
  export const SECRETS_KEY = "secrets";
135
+ /** POSIX-style env var name a `secretEnv` entry binds to (e.g. `SERPER_API_KEY`). */
136
+ export const SECRET_ENV_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
137
+ /** Workspace secret handle a `secretEnv` ref points at (and the name `secret.upload` persists to). */
138
+ export const SECRET_HANDLE_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
129
139
  export const PROXY_ENDPOINT_NAME_PATTERN = /^[a-z][a-z0-9_-]{0,62}$/;
130
140
  export const RESERVED_PROXY_ENDPOINT_NAMES = new Set(["proxy", "aex", "internal", "admin"]);
131
141
  /**
@@ -633,9 +643,40 @@ export function crossValidateProxyEndpointsAndAuth(endpoints, auth) {
633
643
  }
634
644
  }
635
645
  }
646
+ /**
647
+ * Cross-check `submission.secretEnv` declarations against `secrets.envSecrets`
648
+ * values. Mirrors {@link crossValidateProxyEndpointsAndAuth}:
649
+ *
650
+ * - `{ ephemeral: true }` MUST have a matching `secrets.envSecrets` value.
651
+ * - `{ ref }` MUST NOT supply a value (the value lives in the workspace store).
652
+ * - every `secrets.envSecrets` value MUST have a matching `{ ephemeral: true }`
653
+ * declaration (no orphan values that would never be injected).
654
+ */
655
+ export function crossValidateSecretEnvAndValues(secretEnv, envSecrets) {
656
+ const declarations = secretEnv ?? {};
657
+ const values = envSecrets ?? {};
658
+ for (const [envName, entry] of Object.entries(declarations)) {
659
+ const hasValue = Object.prototype.hasOwnProperty.call(values, envName);
660
+ if ("ref" in entry) {
661
+ if (hasValue) {
662
+ throw new Error(`submission.secretEnv[${envName}] is a workspace ref and must not supply a value in secrets.envSecrets[${envName}]; the value resolves server-side`);
663
+ }
664
+ continue;
665
+ }
666
+ if (!hasValue) {
667
+ throw new Error(`submission.secretEnv[${envName}] is ephemeral but has no matching secrets.envSecrets[${envName}] value`);
668
+ }
669
+ }
670
+ for (const envName of Object.keys(values)) {
671
+ const entry = declarations[envName];
672
+ if (!entry || !("ephemeral" in entry)) {
673
+ throw new Error(`secrets.envSecrets[${envName}] has no matching submission.secretEnv[${envName}] ephemeral declaration`);
674
+ }
675
+ }
676
+ }
636
677
  export function parseInlineSecrets(input) {
637
678
  const value = requireRecord(input, "secrets");
638
- const allowedTopLevel = new Set(["apiKey", "mcpServers", "proxyEndpointAuth"]);
679
+ const allowedTopLevel = new Set(["apiKey", "mcpServers", "proxyEndpointAuth", "envSecrets"]);
639
680
  for (const key of Object.keys(value)) {
640
681
  if (key.startsWith("__aex_")) {
641
682
  // Platform-internal namespace (e.g. __aex_proxy_token). The BFF
@@ -651,12 +692,30 @@ export function parseInlineSecrets(input) {
651
692
  const apiKey = value.apiKey !== undefined ? requireString(value.apiKey, "secrets.apiKey") : undefined;
652
693
  const mcpServers = parseMcpServerSecrets(value.mcpServers);
653
694
  const proxyEndpointAuth = parseProxyEndpointAuth(value.proxyEndpointAuth);
695
+ const envSecrets = parseEnvSecrets(value.envSecrets);
654
696
  return {
655
697
  ...(apiKey !== undefined ? { apiKey } : {}),
656
698
  ...(mcpServers ? { mcpServers } : {}),
657
- ...(proxyEndpointAuth ? { proxyEndpointAuth } : {})
699
+ ...(proxyEndpointAuth ? { proxyEndpointAuth } : {}),
700
+ ...(envSecrets ? { envSecrets } : {})
658
701
  };
659
702
  }
703
+ function parseEnvSecrets(input) {
704
+ if (input === undefined || input === null)
705
+ return undefined;
706
+ const value = requireRecord(input, "secrets.envSecrets");
707
+ const out = {};
708
+ for (const [envName, entry] of Object.entries(value)) {
709
+ if (!SECRET_ENV_NAME_PATTERN.test(envName)) {
710
+ throw new Error(`secrets.envSecrets key "${envName}" must be a valid env var name matching ${SECRET_ENV_NAME_PATTERN.source}`);
711
+ }
712
+ if (typeof entry !== "string" || entry.length === 0) {
713
+ throw new Error(`secrets.envSecrets.${envName} must be a non-empty string`);
714
+ }
715
+ out[envName] = entry;
716
+ }
717
+ return Object.keys(out).length > 0 ? out : undefined;
718
+ }
660
719
  function parseMcpServerSecrets(input) {
661
720
  if (input === undefined) {
662
721
  return undefined;
@@ -917,6 +976,7 @@ export function parseRunSubmissionRequest(input, options = {}) {
917
976
  "timeout",
918
977
  "postHook",
919
978
  "proxyEndpoints",
979
+ "parentRunId",
920
980
  SECRETS_KEY
921
981
  ]);
922
982
  for (const key of Object.keys(value)) {
@@ -949,6 +1009,9 @@ export function parseRunSubmissionRequest(input, options = {}) {
949
1009
  }
950
1010
  const runtimeSize = parseRuntimeSize(value.runtimeSize);
951
1011
  const timeoutMs = parseRunTimeout(value.timeout);
1012
+ // Lineage parent only. `depth` is NEVER accepted from the wire — the server
1013
+ // derives it from the parent row (a forged depth must not bypass the cap).
1014
+ const parentRunId = optionalString(value.parentRunId, "submission.parentRunId");
952
1015
  const postHook = parsePostHook(value.postHook, "submission.postHook");
953
1016
  const proxyEndpoints = parseProxyEndpoints(value.proxyEndpoints);
954
1017
  const secrets = parseInlineSecrets(value.secrets);
@@ -956,6 +1019,7 @@ export function parseRunSubmissionRequest(input, options = {}) {
956
1019
  crossValidateProxyEndpointsAndAuth(proxyEndpoints, secrets.proxyEndpointAuth);
957
1020
  const submission = parseSubmission(value.submission);
958
1021
  assertRunModelMatchesProvider(provider, submission.model);
1022
+ crossValidateSecretEnvAndValues(submission.secretEnv, secrets.envSecrets);
959
1023
  // mcpServers names must agree across the submission half and the
960
1024
  // secrets half — every secrets.mcpServers[i].name MUST resolve to a
961
1025
  // submission.mcpServers entry (no orphan secrets) AND the URL must
@@ -999,6 +1063,7 @@ export function parseRunSubmissionRequest(input, options = {}) {
999
1063
  ...(timeoutMs !== undefined ? { timeoutMs } : {}),
1000
1064
  ...(postHook !== undefined ? { postHook } : {}),
1001
1065
  ...(proxyEndpoints ? { proxyEndpoints } : {}),
1066
+ ...(parentRunId !== undefined ? { parentRunId } : {}),
1002
1067
  secrets
1003
1068
  };
1004
1069
  }
@@ -1051,6 +1116,7 @@ export function parseSubmission(input) {
1051
1116
  "agentsMd",
1052
1117
  "files",
1053
1118
  "mcpServers",
1119
+ "secretEnv",
1054
1120
  "environment",
1055
1121
  "securityProfile",
1056
1122
  "metadata",
@@ -1071,6 +1137,7 @@ export function parseSubmission(input) {
1071
1137
  const agentsMd = parseAgentsMd(value.agentsMd);
1072
1138
  const files = parseFiles(value.files);
1073
1139
  const mcpServers = parseMcpServers(value.mcpServers);
1140
+ const secretEnv = parseSecretEnv(value.secretEnv);
1074
1141
  const environment = parseEnvironment(value.environment);
1075
1142
  const securityProfile = parseRuntimeSecurityProfile(value.securityProfile);
1076
1143
  const metadata = optionalJsonRecord(value.metadata, "submission.metadata");
@@ -1086,6 +1153,7 @@ export function parseSubmission(input) {
1086
1153
  agentsMd,
1087
1154
  files,
1088
1155
  mcpServers,
1156
+ ...(secretEnv ? { secretEnv } : {}),
1089
1157
  ...(environment ? { environment } : {}),
1090
1158
  ...(securityProfile ? { securityProfile } : {}),
1091
1159
  ...(metadata ? { metadata } : {}),
@@ -1095,6 +1163,37 @@ export function parseSubmission(input) {
1095
1163
  ...(platform ? { platform } : {})
1096
1164
  };
1097
1165
  }
1166
+ function parseSecretEnv(input) {
1167
+ if (input === undefined || input === null)
1168
+ return undefined;
1169
+ const value = requireRecord(input, "submission.secretEnv");
1170
+ const out = {};
1171
+ for (const [envName, entry] of Object.entries(value)) {
1172
+ if (!SECRET_ENV_NAME_PATTERN.test(envName)) {
1173
+ throw new Error(`submission.secretEnv key "${envName}" must be a valid env var name matching ${SECRET_ENV_NAME_PATTERN.source}`);
1174
+ }
1175
+ const path = `submission.secretEnv.${envName}`;
1176
+ const record = requireRecord(entry, path);
1177
+ const keys = Object.keys(record);
1178
+ if (keys.length !== 1 || (!("ref" in record) && !("ephemeral" in record))) {
1179
+ throw new Error(`${path} must be exactly one of { ref } or { ephemeral: true }`);
1180
+ }
1181
+ if ("ref" in record) {
1182
+ const handle = requireString(record.ref, `${path}.ref`);
1183
+ if (!SECRET_HANDLE_PATTERN.test(handle)) {
1184
+ throw new Error(`${path}.ref handle must match ${SECRET_HANDLE_PATTERN.source}`);
1185
+ }
1186
+ out[envName] = { ref: handle };
1187
+ }
1188
+ else {
1189
+ if (record.ephemeral !== true) {
1190
+ throw new Error(`${path}.ephemeral must be the literal true`);
1191
+ }
1192
+ out[envName] = { ephemeral: true };
1193
+ }
1194
+ }
1195
+ return Object.keys(out).length > 0 ? out : undefined;
1196
+ }
1098
1197
  function parsePlatformConfig(input) {
1099
1198
  if (input === undefined || input === null)
1100
1199
  return undefined;
@@ -1478,15 +1577,15 @@ export class RuntimeValidationError extends Error {
1478
1577
  }
1479
1578
  /**
1480
1579
  * Walk the parsed submission and collect features that the active managed
1481
- * runtime cannot serve. Provider-hosted skill refs (`Skill.provider(...)`) are
1580
+ * runtime cannot serve. Provider-hosted skill refs (`kind:"provider"`) are
1482
1581
  * rejected now that new submissions only dispatch through managed runs.
1483
1582
  */
1484
1583
  export function collectManagedUnsupportedFeatures(req) {
1485
1584
  const features = [];
1486
1585
  for (const skill of req.submission.skills) {
1487
1586
  if (skill.kind === "provider") {
1488
- const versionSuffix = skill.version ? `, "${skill.version}"` : "";
1489
- features.push(`Skill.provider("${skill.vendor}", "${skill.skillId}"${versionSuffix})`);
1587
+ const versionSuffix = skill.version ? `@${skill.version}` : "";
1588
+ features.push(`provider skill "${skill.vendor}/${skill.skillId}${versionSuffix}" (kind:"provider")`);
1490
1589
  }
1491
1590
  }
1492
1591
  return features;
@@ -5,9 +5,9 @@ import type { AgentsMdRef } from "./_contracts/index.js";
5
5
  * behaviour).
6
6
  *
7
7
  * const rules = await AgentsMd.fromContent("# Be helpful", { name: "rules" });
8
- * await client.submitRun({ agentsMd: [rules], ... });
8
+ * await client.submit({ agentsMd: [rules], ... });
9
9
  *
10
- * `client.submitRun` materializes the bytes to the hosted asset store before
10
+ * `client.submit` materializes the bytes to the hosted asset store before
11
11
  * the run lands. Asset deduplication handles repeated uploads automatically.
12
12
  */
13
13
  export declare class AgentsMd {
@@ -30,7 +30,7 @@ export declare class AgentsMd {
30
30
  }): Promise<AgentsMd>;
31
31
  /**
32
32
  * Internal: yield the draft's zipped bytes + metadata so
33
- * `client.submitRun` can upload it as an asset.
33
+ * `client.submit` can upload it as an asset.
34
34
  */
35
35
  _takeDraftBundle(): {
36
36
  name: string;
package/dist/agents-md.js CHANGED
@@ -7,9 +7,9 @@ import { strToU8, zipSync } from "fflate";
7
7
  * behaviour).
8
8
  *
9
9
  * const rules = await AgentsMd.fromContent("# Be helpful", { name: "rules" });
10
- * await client.submitRun({ agentsMd: [rules], ... });
10
+ * await client.submit({ agentsMd: [rules], ... });
11
11
  *
12
- * `client.submitRun` materializes the bytes to the hosted asset store before
12
+ * `client.submit` materializes the bytes to the hosted asset store before
13
13
  * the run lands. Asset deduplication handles repeated uploads automatically.
14
14
  */
15
15
  export class AgentsMd {
@@ -53,12 +53,12 @@ export class AgentsMd {
53
53
  }
54
54
  /**
55
55
  * Internal: yield the draft's zipped bytes + metadata so
56
- * `client.submitRun` can upload it as an asset.
56
+ * `client.submit` can upload it as an asset.
57
57
  */
58
58
  _takeDraftBundle() {
59
59
  if (this.#consumed) {
60
- throw new Error("AgentsMd: cannot reuse a consumed AgentsMd in submitRun. Build a fresh one " +
61
- "via AgentsMd.fromContent(...) / AgentsMd.fromPath(...) per submitRun call.");
60
+ throw new Error("AgentsMd: cannot reuse a consumed AgentsMd in submit. Build a fresh one " +
61
+ "via AgentsMd.fromContent(...) / AgentsMd.fromPath(...) per submit call.");
62
62
  }
63
63
  if (this.#ref.kind !== "draft" || !this.#zipBytes) {
64
64
  return undefined;
@@ -73,7 +73,7 @@ export class AgentsMd {
73
73
  toJSON() {
74
74
  if (this.#ref.kind === "draft") {
75
75
  throw new Error("AgentsMd: draft AgentsMd cannot be JSON-serialised — it only becomes a wire " +
76
- "ref when client.submitRun uploads the bytes as an asset.");
76
+ "ref when client.submit uploads the bytes as an asset.");
77
77
  }
78
78
  return this.#ref;
79
79
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agents-md.js","sourceRoot":"","sources":["../src/agents-md.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agents-md.js","sourceRoot":"","sources":["../src/agents-md.ts"],"names":[],"mappings":"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"}