@aexhq/sdk 0.46.4-canary → 0.50.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 (337) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +38 -0
  3. package/README.md +23 -31
  4. package/dist/client/aex.d.ts +33 -0
  5. package/dist/client/aex.js +98 -0
  6. package/dist/client/aex.js.map +1 -0
  7. package/dist/client/credentials.d.ts +25 -0
  8. package/dist/client/credentials.js +97 -0
  9. package/dist/client/credentials.js.map +1 -0
  10. package/dist/client/routing.d.ts +7 -0
  11. package/dist/client/routing.js +29 -0
  12. package/dist/client/routing.js.map +1 -0
  13. package/dist/downloads/download.d.ts +25 -0
  14. package/dist/downloads/download.js +53 -0
  15. package/dist/downloads/download.js.map +1 -0
  16. package/dist/generated/errors.d.ts +12 -0
  17. package/dist/generated/errors.js +81 -0
  18. package/dist/generated/errors.js.map +1 -0
  19. package/dist/generated/resources.d.ts +730 -0
  20. package/dist/generated/resources.js +606 -0
  21. package/dist/generated/resources.js.map +1 -0
  22. package/dist/generated/routes.d.ts +42 -0
  23. package/dist/generated/routes.js +2101 -0
  24. package/dist/generated/routes.js.map +1 -0
  25. package/dist/index.d.ts +20 -50
  26. package/dist/index.js +11 -62
  27. package/dist/index.js.map +1 -1
  28. package/dist/observations/stream.d.ts +1 -0
  29. package/dist/observations/stream.js +18 -0
  30. package/dist/observations/stream.js.map +1 -0
  31. package/dist/transport/errors.d.ts +60 -0
  32. package/dist/transport/errors.js +107 -0
  33. package/dist/transport/errors.js.map +1 -0
  34. package/dist/transport/pagination.d.ts +8 -0
  35. package/dist/transport/pagination.js +34 -0
  36. package/dist/transport/pagination.js.map +1 -0
  37. package/dist/transport/retry.d.ts +21 -0
  38. package/dist/transport/retry.js +37 -0
  39. package/dist/transport/retry.js.map +1 -0
  40. package/dist/transport/transport.d.ts +25 -0
  41. package/dist/transport/transport.js +28 -0
  42. package/dist/transport/transport.js.map +1 -0
  43. package/package.json +63 -30
  44. package/dist/_contracts/account-operations.d.ts +0 -101
  45. package/dist/_contracts/account-operations.js +0 -242
  46. package/dist/_contracts/account-types.d.ts +0 -461
  47. package/dist/_contracts/account-types.js +0 -1
  48. package/dist/_contracts/api-key.d.ts +0 -61
  49. package/dist/_contracts/api-key.js +0 -101
  50. package/dist/_contracts/api-routes.d.ts +0 -20
  51. package/dist/_contracts/api-routes.js +0 -109
  52. package/dist/_contracts/archive-limits.d.ts +0 -3
  53. package/dist/_contracts/archive-limits.js +0 -23
  54. package/dist/_contracts/asset-authoring.d.ts +0 -22
  55. package/dist/_contracts/asset-authoring.js +0 -106
  56. package/dist/_contracts/asset-bundle.d.ts +0 -64
  57. package/dist/_contracts/asset-bundle.js +0 -263
  58. package/dist/_contracts/asset-upload-helper.d.ts +0 -31
  59. package/dist/_contracts/asset-upload-helper.js +0 -84
  60. package/dist/_contracts/billing-admission.d.ts +0 -29
  61. package/dist/_contracts/billing-admission.js +0 -28
  62. package/dist/_contracts/bundle-manifest.d.ts +0 -89
  63. package/dist/_contracts/bundle-manifest.js +0 -158
  64. package/dist/_contracts/canonical-sha256.d.ts +0 -8
  65. package/dist/_contracts/canonical-sha256.js +0 -8
  66. package/dist/_contracts/connection-ticket.d.ts +0 -22
  67. package/dist/_contracts/connection-ticket.js +0 -54
  68. package/dist/_contracts/continuation-event.d.ts +0 -31
  69. package/dist/_contracts/continuation-event.js +0 -6
  70. package/dist/_contracts/contract-parse-error.d.ts +0 -12
  71. package/dist/_contracts/contract-parse-error.js +0 -51
  72. package/dist/_contracts/error-codes.d.ts +0 -26
  73. package/dist/_contracts/error-codes.js +0 -116
  74. package/dist/_contracts/error-factory.d.ts +0 -32
  75. package/dist/_contracts/error-factory.js +0 -174
  76. package/dist/_contracts/event-envelope.d.ts +0 -471
  77. package/dist/_contracts/event-envelope.js +0 -501
  78. package/dist/_contracts/event-stream-client.d.ts +0 -122
  79. package/dist/_contracts/event-stream-client.js +0 -445
  80. package/dist/_contracts/event-view.d.ts +0 -44
  81. package/dist/_contracts/event-view.js +0 -69
  82. package/dist/_contracts/failure-class.d.ts +0 -29
  83. package/dist/_contracts/failure-class.js +0 -73
  84. package/dist/_contracts/http.d.ts +0 -135
  85. package/dist/_contracts/http.js +0 -434
  86. package/dist/_contracts/ids.d.ts +0 -66
  87. package/dist/_contracts/ids.js +0 -119
  88. package/dist/_contracts/index.d.ts +0 -42
  89. package/dist/_contracts/index.js +0 -52
  90. package/dist/_contracts/internal.d.ts +0 -55
  91. package/dist/_contracts/internal.js +0 -113
  92. package/dist/_contracts/models.d.ts +0 -30
  93. package/dist/_contracts/models.js +0 -28
  94. package/dist/_contracts/operation-core.d.ts +0 -36
  95. package/dist/_contracts/operation-core.js +0 -70
  96. package/dist/_contracts/operations.d.ts +0 -218
  97. package/dist/_contracts/operations.js +0 -1496
  98. package/dist/_contracts/otlp-projection.d.ts +0 -78
  99. package/dist/_contracts/otlp-projection.js +0 -171
  100. package/dist/_contracts/post-hook.d.ts +0 -31
  101. package/dist/_contracts/post-hook.js +0 -61
  102. package/dist/_contracts/provider-fault.d.ts +0 -34
  103. package/dist/_contracts/provider-fault.js +0 -68
  104. package/dist/_contracts/retry-core.d.ts +0 -29
  105. package/dist/_contracts/retry-core.js +0 -79
  106. package/dist/_contracts/runner-event.d.ts +0 -117
  107. package/dist/_contracts/runner-event.js +0 -172
  108. package/dist/_contracts/runtime-kind.d.ts +0 -60
  109. package/dist/_contracts/runtime-kind.js +0 -70
  110. package/dist/_contracts/runtime-manifest.d.ts +0 -121
  111. package/dist/_contracts/runtime-manifest.js +0 -83
  112. package/dist/_contracts/runtime-security-profile.d.ts +0 -26
  113. package/dist/_contracts/runtime-security-profile.js +0 -73
  114. package/dist/_contracts/runtime-sizes.d.ts +0 -104
  115. package/dist/_contracts/runtime-sizes.js +0 -111
  116. package/dist/_contracts/runtime-types.d.ts +0 -618
  117. package/dist/_contracts/runtime-types.js +0 -58
  118. package/dist/_contracts/schemas/asset-bundle.d.ts +0 -70
  119. package/dist/_contracts/schemas/asset-bundle.js +0 -107
  120. package/dist/_contracts/schemas/asset-ref.d.ts +0 -61
  121. package/dist/_contracts/schemas/asset-ref.js +0 -118
  122. package/dist/_contracts/schemas/bundle-manifest.d.ts +0 -66
  123. package/dist/_contracts/schemas/bundle-manifest.js +0 -77
  124. package/dist/_contracts/schemas/index.d.ts +0 -32
  125. package/dist/_contracts/schemas/index.js +0 -30
  126. package/dist/_contracts/schemas/mcp-server.d.ts +0 -99
  127. package/dist/_contracts/schemas/mcp-server.js +0 -209
  128. package/dist/_contracts/schemas/models.d.ts +0 -29
  129. package/dist/_contracts/schemas/models.js +0 -51
  130. package/dist/_contracts/schemas/numeric.d.ts +0 -18
  131. package/dist/_contracts/schemas/numeric.js +0 -28
  132. package/dist/_contracts/schemas/post-hook.d.ts +0 -45
  133. package/dist/_contracts/schemas/post-hook.js +0 -68
  134. package/dist/_contracts/schemas/response-assets.d.ts +0 -75
  135. package/dist/_contracts/schemas/response-assets.js +0 -81
  136. package/dist/_contracts/schemas/response-billing.d.ts +0 -208
  137. package/dist/_contracts/schemas/response-billing.js +0 -139
  138. package/dist/_contracts/schemas/response-common.d.ts +0 -132
  139. package/dist/_contracts/schemas/response-common.js +0 -162
  140. package/dist/_contracts/schemas/response-identity.d.ts +0 -648
  141. package/dist/_contracts/schemas/response-identity.js +0 -131
  142. package/dist/_contracts/schemas/response-mcp-servers.d.ts +0 -51
  143. package/dist/_contracts/schemas/response-mcp-servers.js +0 -32
  144. package/dist/_contracts/schemas/response-secrets.d.ts +0 -50
  145. package/dist/_contracts/schemas/response-secrets.js +0 -32
  146. package/dist/_contracts/schemas/response-sessions-internal.d.ts +0 -200
  147. package/dist/_contracts/schemas/response-sessions-internal.js +0 -142
  148. package/dist/_contracts/schemas/response-sessions.d.ts +0 -1598
  149. package/dist/_contracts/schemas/response-sessions.js +0 -377
  150. package/dist/_contracts/schemas/response-webhooks.d.ts +0 -76
  151. package/dist/_contracts/schemas/response-webhooks.js +0 -42
  152. package/dist/_contracts/schemas/response-workspace.d.ts +0 -225
  153. package/dist/_contracts/schemas/response-workspace.js +0 -99
  154. package/dist/_contracts/schemas/runtime-kind.d.ts +0 -31
  155. package/dist/_contracts/schemas/runtime-kind.js +0 -29
  156. package/dist/_contracts/schemas/runtime-security-profile.d.ts +0 -28
  157. package/dist/_contracts/schemas/runtime-security-profile.js +0 -26
  158. package/dist/_contracts/schemas/runtime-sizes.d.ts +0 -70
  159. package/dist/_contracts/schemas/runtime-sizes.js +0 -127
  160. package/dist/_contracts/schemas/session-limits.d.ts +0 -34
  161. package/dist/_contracts/schemas/session-limits.js +0 -39
  162. package/dist/_contracts/schemas/session-machine.d.ts +0 -23
  163. package/dist/_contracts/schemas/session-machine.js +0 -24
  164. package/dist/_contracts/schemas/session-request-config.d.ts +0 -58
  165. package/dist/_contracts/schemas/session-request-config.js +0 -134
  166. package/dist/_contracts/schemas/session-webhook.d.ts +0 -11
  167. package/dist/_contracts/schemas/session-webhook.js +0 -38
  168. package/dist/_contracts/schemas/side-effect-audit.d.ts +0 -98
  169. package/dist/_contracts/schemas/side-effect-audit.js +0 -102
  170. package/dist/_contracts/schemas/submission-assets.d.ts +0 -117
  171. package/dist/_contracts/schemas/submission-assets.js +0 -147
  172. package/dist/_contracts/schemas/submission-body.d.ts +0 -251
  173. package/dist/_contracts/schemas/submission-body.js +0 -378
  174. package/dist/_contracts/schemas/submission-environment.d.ts +0 -79
  175. package/dist/_contracts/schemas/submission-environment.js +0 -179
  176. package/dist/_contracts/schemas/submission-request.d.ts +0 -158
  177. package/dist/_contracts/schemas/submission-request.js +0 -49
  178. package/dist/_contracts/schemas/submission-secrets.d.ts +0 -47
  179. package/dist/_contracts/schemas/submission-secrets.js +0 -108
  180. package/dist/_contracts/schemas/wire.d.ts +0 -118
  181. package/dist/_contracts/schemas/wire.js +0 -171
  182. package/dist/_contracts/schemas/workspace-resources.d.ts +0 -50
  183. package/dist/_contracts/schemas/workspace-resources.js +0 -87
  184. package/dist/_contracts/sdk-errors.d.ts +0 -212
  185. package/dist/_contracts/sdk-errors.js +0 -313
  186. package/dist/_contracts/sdk-secrets.d.ts +0 -67
  187. package/dist/_contracts/sdk-secrets.js +0 -427
  188. package/dist/_contracts/session-archive.d.ts +0 -16
  189. package/dist/_contracts/session-archive.js +0 -92
  190. package/dist/_contracts/session-artifacts.d.ts +0 -189
  191. package/dist/_contracts/session-artifacts.js +0 -264
  192. package/dist/_contracts/session-config.d.ts +0 -373
  193. package/dist/_contracts/session-config.js +0 -562
  194. package/dist/_contracts/session-cost-types.d.ts +0 -211
  195. package/dist/_contracts/session-cost-types.js +0 -69
  196. package/dist/_contracts/session-cost.d.ts +0 -8
  197. package/dist/_contracts/session-cost.js +0 -582
  198. package/dist/_contracts/session-custody.d.ts +0 -165
  199. package/dist/_contracts/session-custody.js +0 -345
  200. package/dist/_contracts/session-file-query.d.ts +0 -14
  201. package/dist/_contracts/session-file-query.js +0 -178
  202. package/dist/_contracts/session-record.d.ts +0 -112
  203. package/dist/_contracts/session-record.js +0 -165
  204. package/dist/_contracts/session-retention.d.ts +0 -201
  205. package/dist/_contracts/session-retention.js +0 -450
  206. package/dist/_contracts/side-effect-audit.d.ts +0 -126
  207. package/dist/_contracts/side-effect-audit.js +0 -520
  208. package/dist/_contracts/sse.d.ts +0 -74
  209. package/dist/_contracts/sse.js +0 -227
  210. package/dist/_contracts/stable.d.ts +0 -45
  211. package/dist/_contracts/stable.js +0 -62
  212. package/dist/_contracts/status.d.ts +0 -25
  213. package/dist/_contracts/status.js +0 -57
  214. package/dist/_contracts/submission-limits.d.ts +0 -61
  215. package/dist/_contracts/submission-limits.js +0 -60
  216. package/dist/_contracts/submission.d.ts +0 -547
  217. package/dist/_contracts/submission.js +0 -812
  218. package/dist/_contracts/suggest.d.ts +0 -15
  219. package/dist/_contracts/suggest.js +0 -53
  220. package/dist/_contracts/testing/response-bindings.d.ts +0 -45
  221. package/dist/_contracts/testing/response-bindings.js +0 -256
  222. package/dist/_contracts/testing/wire-conformance-entry.d.ts +0 -10
  223. package/dist/_contracts/testing/wire-conformance-entry.js +0 -8
  224. package/dist/_contracts/testing/wire-conformance.d.ts +0 -169
  225. package/dist/_contracts/testing/wire-conformance.js +0 -276
  226. package/dist/_contracts/turn-trace.d.ts +0 -28
  227. package/dist/_contracts/turn-trace.js +0 -1
  228. package/dist/_contracts/unknown-field-error.d.ts +0 -13
  229. package/dist/_contracts/unknown-field-error.js +0 -21
  230. package/dist/_contracts/value-guards.d.ts +0 -20
  231. package/dist/_contracts/value-guards.js +0 -34
  232. package/dist/_contracts/webhook-verify.d.ts +0 -34
  233. package/dist/_contracts/webhook-verify.js +0 -93
  234. package/dist/_contracts/wire-observer.d.ts +0 -49
  235. package/dist/_contracts/wire-observer.js +0 -34
  236. package/dist/_contracts/workflow-status.d.ts +0 -7
  237. package/dist/_contracts/workflow-status.js +0 -43
  238. package/dist/_contracts/workspace-resources.d.ts +0 -98
  239. package/dist/_contracts/workspace-resources.js +0 -39
  240. package/dist/archive-limits.d.ts +0 -1
  241. package/dist/archive-limits.js +0 -2
  242. package/dist/archive-limits.js.map +0 -1
  243. package/dist/asset-upload.d.ts +0 -47
  244. package/dist/asset-upload.js +0 -269
  245. package/dist/asset-upload.js.map +0 -1
  246. package/dist/bundle.d.ts +0 -9
  247. package/dist/bundle.js +0 -20
  248. package/dist/bundle.js.map +0 -1
  249. package/dist/canonical-zip.d.ts +0 -68
  250. package/dist/canonical-zip.js +0 -355
  251. package/dist/canonical-zip.js.map +0 -1
  252. package/dist/cli.mjs +0 -12048
  253. package/dist/cli.mjs.sha256 +0 -1
  254. package/dist/client-types.d.ts +0 -192
  255. package/dist/client-types.js +0 -2
  256. package/dist/client-types.js.map +0 -1
  257. package/dist/client.d.ts +0 -464
  258. package/dist/client.js +0 -1207
  259. package/dist/client.js.map +0 -1
  260. package/dist/event-projection.d.ts +0 -22
  261. package/dist/event-projection.js +0 -380
  262. package/dist/event-projection.js.map +0 -1
  263. package/dist/fetch-archive.d.ts +0 -16
  264. package/dist/fetch-archive.js +0 -252
  265. package/dist/fetch-archive.js.map +0 -1
  266. package/dist/file.d.ts +0 -96
  267. package/dist/file.js +0 -272
  268. package/dist/file.js.map +0 -1
  269. package/dist/instructions.d.ts +0 -20
  270. package/dist/instructions.js +0 -40
  271. package/dist/instructions.js.map +0 -1
  272. package/dist/legacy-session-provider-fault.d.ts +0 -7
  273. package/dist/legacy-session-provider-fault.js +0 -38
  274. package/dist/legacy-session-provider-fault.js.map +0 -1
  275. package/dist/mcp-server.d.ts +0 -84
  276. package/dist/mcp-server.js +0 -117
  277. package/dist/mcp-server.js.map +0 -1
  278. package/dist/node-fs.d.ts +0 -29
  279. package/dist/node-fs.js +0 -19
  280. package/dist/node-fs.js.map +0 -1
  281. package/dist/node-walk.d.ts +0 -69
  282. package/dist/node-walk.js +0 -151
  283. package/dist/node-walk.js.map +0 -1
  284. package/dist/path-basename.d.ts +0 -5
  285. package/dist/path-basename.js +0 -9
  286. package/dist/path-basename.js.map +0 -1
  287. package/dist/retry.d.ts +0 -70
  288. package/dist/retry.js +0 -155
  289. package/dist/retry.js.map +0 -1
  290. package/dist/secret.d.ts +0 -65
  291. package/dist/secret.js +0 -110
  292. package/dist/secret.js.map +0 -1
  293. package/dist/session-validate.d.ts +0 -100
  294. package/dist/session-validate.js +0 -303
  295. package/dist/session-validate.js.map +0 -1
  296. package/dist/skill.d.ts +0 -99
  297. package/dist/skill.js +0 -169
  298. package/dist/skill.js.map +0 -1
  299. package/dist/submission-wire.d.ts +0 -13
  300. package/dist/submission-wire.js +0 -69
  301. package/dist/submission-wire.js.map +0 -1
  302. package/dist/tool.d.ts +0 -41
  303. package/dist/tool.js +0 -76
  304. package/dist/tool.js.map +0 -1
  305. package/dist/version.d.ts +0 -9
  306. package/dist/version.js +0 -10
  307. package/dist/version.js.map +0 -1
  308. package/docs/authentication.md +0 -125
  309. package/docs/billing.md +0 -164
  310. package/docs/cleanup.md +0 -27
  311. package/docs/concepts/agent-tools.md +0 -47
  312. package/docs/concepts/composition.md +0 -60
  313. package/docs/concepts/providers-and-runtimes.md +0 -121
  314. package/docs/concepts/sessions.md +0 -51
  315. package/docs/concepts/subagents.md +0 -35
  316. package/docs/credentials.md +0 -116
  317. package/docs/defaults.md +0 -51
  318. package/docs/errors.md +0 -258
  319. package/docs/events.md +0 -143
  320. package/docs/files.md +0 -130
  321. package/docs/limits-and-quotas.md +0 -114
  322. package/docs/limits.md +0 -51
  323. package/docs/mcp.md +0 -47
  324. package/docs/networking.md +0 -114
  325. package/docs/provider-runtime-capabilities.md +0 -32
  326. package/docs/public-surface.json +0 -73
  327. package/docs/quickstart.md +0 -135
  328. package/docs/release.md +0 -44
  329. package/docs/retries.md +0 -108
  330. package/docs/secrets.md +0 -141
  331. package/docs/session-config.md +0 -51
  332. package/docs/session-record.md +0 -58
  333. package/docs/skills.md +0 -65
  334. package/docs/telemetry.md +0 -66
  335. package/docs/testing.md +0 -35
  336. package/docs/vision-skills.md +0 -94
  337. package/docs/webhooks.md +0 -143
@@ -1,562 +0,0 @@
1
- /**
2
- * Session-request config and composition refs for the public SDK/CLI surface.
3
- *
4
- * Public composition concepts:
5
- *
6
- * - `SkillRef` is the PUBLIC wire-level reference to a workspace skill: just
7
- * `{ kind:"skill", name }`. The binding is BY NAME and mutable — the session
8
- * resolves the name to the workspace skill's current bytes at submit time.
9
- * It travels in `submission.skills` (NOT `submission.tools`).
10
- *
11
- * - `McpServerRef` is the non-secret part of an MCP server declaration:
12
- * `name` and `url`. Bearer / cookie / per-request headers travel in
13
- * the session's vaulted `secrets.mcpServers` block keyed by the same
14
- * `name`, and never enter the hashed submission payload or the
15
- * session snapshot.
16
- *
17
- * - `SessionRequestConfig` is the credential-free set of session parameters that
18
- * can be persisted to disk (e.g. `aex start --config session.json`) or
19
- * returned from ordinary application helper functions. It excludes
20
- * `secrets`/`idempotencyKey`/`signal`; strings are already resolved at
21
- * the call site before submission.
22
- *
23
- * - Skill bundle validation lives here so the SDK (zipping locally),
24
- * hosted API (server-side unzip + manifest extraction) and runtime
25
- * mount layer share a single source of truth for
26
- * the limits, the path normaliser, and the manifest invariants. The
27
- * DB CHECK constraints on `skill_bundles.manifest` mirror these.
28
- *
29
- * Keep this as the public source of truth for the SDK/CLI composition
30
- * boundary.
31
- */
32
- import { rethrowContractParseError, withContractParseError } from "./contract-parse-error.js";
33
- import { ASSET_ID_PATTERN, MOUNT_PATH_MAX_LENGTH, MOUNT_PATH_PATTERN, assertValidMountPath, normalizeAssetRef, parseAssetRefWire } from "./schemas/asset-ref.js";
34
- import { MCP_SERVER_NAME_PATTERN, REMOTE_MCP_STDIO_REJECTED_MESSAGE, normalizeMcpServerRef, parseMcpServerRefWire, rejectStdioMcpShape } from "./schemas/mcp-server.js";
35
- import { parseSessionRequestConfigWire } from "./schemas/session-request-config.js";
36
- // ---------------------------------------------------------------------------
37
- // Skill ID + name format
38
- // ---------------------------------------------------------------------------
39
- /**
40
- * Mirrors the server-side CHECK constraint
41
- * `skill_bundles_id_format_chk = check (id ~ '^skl_[A-Za-z0-9_-]{8,128}$')`
42
- * on persisted skill bundles. Keep the two in lockstep.
43
- */
44
- export const SKILL_ID_PATTERN = /^skl_[A-Za-z0-9_-]{8,128}$/;
45
- /**
46
- * Human-readable, workspace-scoped name. Lowercase, kebab-friendly,
47
- * 1..128 chars. The DB enforces the length bound via
48
- * `skill_bundles_name_len_chk`; this regex tightens the SDK/CLI input
49
- * surface so callers fail at the boundary rather than in the BFF.
50
- */
51
- export const SKILL_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,127}$/;
52
- /**
53
- * Provider-safe submitted tool name. Tool names share the same lowercase
54
- * kebab/underscore envelope as skills. Submission parsing rejects `__`
55
- * because SessionDO reserves that separator for MCP namespace routing.
56
- */
57
- export const TOOL_NAME_PATTERN = SKILL_NAME_PATTERN;
58
- /**
59
- * Names reserved by the skills subsystem and therefore usable as neither a
60
- * skill name nor a custom tool name. `skills` is the injected meta-tool (see
61
- * {@link SKILLS_TOOL_NAME} in `submission.ts`); `skill` is its singular. Both
62
- * the SDK factories and the BFF `parseSkills` / `parseTools` reject these.
63
- */
64
- export const SKILL_RESERVED_NAMES = new Set(["skills", "skill"]);
65
- // ---------------------------------------------------------------------------
66
- // Runtime asset archive limits
67
- // ---------------------------------------------------------------------------
68
- /**
69
- * One honest envelope for every file, skill, tool, or instruction archive that
70
- * the managed runtime mounts. Raw asset storage is a broader concept and may
71
- * have a different quota; these limits describe usable runtime inputs.
72
- */
73
- export const ASSET_ARCHIVE_LIMITS = {
74
- /**
75
- * 16 MiB. Sized to the SHARED api Lambda (512 MB) that `GetObject`s and
76
- * DEFLATE-decompresses every pinned archive on every submit, NOT to the
77
- * single-tenant sandbox. Raisable once that preflight moves off shared infra.
78
- */
79
- maxCompressedBytes: 16 * 1024 * 1024,
80
- maxDecompressedBytes: 128 * 1024 * 1024,
81
- maxEntries: 1_000,
82
- maxMetadataBytes: 8 * 1024 * 1024
83
- };
84
- /** Skill-specific authoring constraints layered on the shared asset envelope. */
85
- export const SKILL_BUNDLE_LIMITS = {
86
- /** Compressed (.zip) ceiling. */
87
- maxCompressedBytes: ASSET_ARCHIVE_LIMITS.maxCompressedBytes,
88
- /** Sum of uncompressed file sizes. */
89
- maxDecompressedBytes: ASSET_ARCHIVE_LIMITS.maxDecompressedBytes,
90
- /** Number of regular file entries (directories don't count). */
91
- maxFiles: ASSET_ARCHIVE_LIMITS.maxEntries,
92
- /** Single-entry path length cap: `PATH_MAX`, the only real ceiling. */
93
- maxPathLength: 4096,
94
- /** Stored file mode for ordinary files. */
95
- defaultFileMode: 0o644,
96
- /** Stored directory mode. */
97
- defaultDirMode: 0o755
98
- };
99
- /** Content-hash format: `sha256:<64 lowercase hex>`. */
100
- export { CANONICAL_SHA256_DIGEST_PATTERN as INLINE_CONTENT_HASH_PATTERN } from "./canonical-sha256.js";
101
- /**
102
- * Checks the `AssetRef` discriminator on an already typed file reference.
103
- *
104
- * This compatibility predicate is not full validation for an untrusted value;
105
- * use the owning parser when the complete asset-ref shape must be validated.
106
- */
107
- export function isAssetRef(ref) {
108
- return ref.kind === "asset";
109
- }
110
- /**
111
- * Asset ids are storage-neutral product ids. Current uploads derive the id from
112
- * the content digest (`asset_<sha256hex>`), but callers must treat it as opaque.
113
- *
114
- * Declared in `schemas/asset-ref.ts` next to the schema that enforces it — this
115
- * module imports that one, so it cannot live here without a cycle.
116
- */
117
- export { ASSET_ID_PATTERN };
118
- /** @deprecated Use `isAssetRef`. This direct alias remains for public compatibility. */
119
- export const isFileAssetRef = isAssetRef;
120
- /**
121
- * The default mount DIRECTORY a `File` unzips into when the caller does not set
122
- * `mountPath`. `/workspace` is also the agent's default working directory, so a
123
- * file handed with no `mountPath` lands directly in the agent's cwd (e.g.
124
- * `/workspace/source-video-subtitles.srt`).
125
- */
126
- export const DEFAULT_FILE_MOUNT_PATH = "/workspace";
127
- /**
128
- * A `mountPath` is an ABSOLUTE container directory under the workspace, and
129
- * {@link assertValidMountPath} is the assert the SDK `File` builders and the BFF
130
- * asset-ref parser share so both reject the same malformed input.
131
- *
132
- * All three are declared in `schemas/asset-ref.ts`, next to the schema that
133
- * enforces them — this module imports that one, so they cannot live here without
134
- * a cycle.
135
- */
136
- export { MOUNT_PATH_PATTERN, MOUNT_PATH_MAX_LENGTH, assertValidMountPath };
137
- /**
138
- * Common parser for any `kind: "asset"` ref (file / tool bundle).
139
- */
140
- export function parseAssetRefFields(record, path) {
141
- return withContractParseError("parseAssetRefFields", () => normalizeAssetRef(parseAssetRefWire(record, path)));
142
- }
143
- export class SkillBundleValidationError extends Error {
144
- constructor(message) {
145
- super(message);
146
- this.name = "SkillBundleValidationError";
147
- }
148
- }
149
- /**
150
- * Reject input paths that try to escape the bundle root or smuggle
151
- * platform-specific syntax. Returns the canonical forward-slash
152
- * relative path; never returns paths starting or ending with `/`.
153
- *
154
- * Rejects:
155
- * - empty strings and pure whitespace
156
- * - absolute paths (`/foo`, `C:\foo`, `\\server\share`)
157
- * - backslash separators (Windows)
158
- * - `..` segments anywhere in the path
159
- * - `.` segments anywhere except a leading bare `.`
160
- * - paths whose length exceeds `SKILL_BUNDLE_LIMITS.maxPathLength` (PATH_MAX, 4096)
161
- * - NUL bytes
162
- *
163
- * There is deliberately NO nesting-depth cap (review-2026-07-25 plan 04): traversal is
164
- * already dead structurally via the segment rules above, so a depth limit refused
165
- * legitimate layouts while protecting nothing.
166
- */
167
- export function normaliseSkillBundlePath(input) {
168
- if (typeof input !== "string") {
169
- throw new SkillBundleValidationError("bundle entry path must be a string");
170
- }
171
- if (input.length === 0 || input.trim().length === 0) {
172
- throw new SkillBundleValidationError("bundle entry path must be non-empty");
173
- }
174
- if (input.length > SKILL_BUNDLE_LIMITS.maxPathLength) {
175
- throw new SkillBundleValidationError(`bundle entry path exceeds maxPathLength (${SKILL_BUNDLE_LIMITS.maxPathLength}): ${input}`);
176
- }
177
- if (input.includes("\0")) {
178
- throw new SkillBundleValidationError(`bundle entry path contains NUL byte: ${JSON.stringify(input)}`);
179
- }
180
- if (input.includes("\\")) {
181
- throw new SkillBundleValidationError(`bundle entry path uses backslash separator: ${input}`);
182
- }
183
- if (/^[A-Za-z]:[\\/]/.test(input)) {
184
- throw new SkillBundleValidationError(`bundle entry path uses a drive letter: ${input}`);
185
- }
186
- if (input.startsWith("/")) {
187
- throw new SkillBundleValidationError(`bundle entry path must be relative: ${input}`);
188
- }
189
- // Reject trailing slash so callers cannot disguise directory entries
190
- // as files. The manifest is files-only.
191
- if (input.endsWith("/")) {
192
- throw new SkillBundleValidationError(`bundle entry path must not end with '/': ${input}`);
193
- }
194
- const segments = input.split("/");
195
- for (const segment of segments) {
196
- if (segment === "..") {
197
- throw new SkillBundleValidationError(`bundle entry path contains '..' segment: ${input}`);
198
- }
199
- if (segment === "." || segment === "") {
200
- throw new SkillBundleValidationError(`bundle entry path contains empty or '.' segment: ${input}`);
201
- }
202
- }
203
- // NO nesting-depth cap (review-2026-07-25 plan 04). Traversal is already dead
204
- // STRUCTURALLY above — `..`, `.`, empty, absolute, drive-letter and backslash
205
- // segments are each rejected outright — so a depth bound protected nothing and
206
- // only refused legitimately deep trees.
207
- return input;
208
- }
209
- /**
210
- * Validate one manifest entry: normalises the path, bounds the size,
211
- * and sanitises the mode to one of {defaultFileMode, defaultDirMode}.
212
- * The bundle is files-only, so any non-regular-file entry is rejected
213
- * upstream by the caller (zip parser must skip symlinks, device files,
214
- * etc. before reaching this function).
215
- */
216
- export function parseSkillBundleEntry(input) {
217
- try {
218
- const path = normaliseSkillBundlePath(input.path);
219
- if (!Number.isFinite(input.size) || !Number.isInteger(input.size) || input.size < 0) {
220
- throw new SkillBundleValidationError(`bundle entry size must be a non-negative integer (${path})`);
221
- }
222
- if (input.size > SKILL_BUNDLE_LIMITS.maxDecompressedBytes) {
223
- throw new SkillBundleValidationError(`bundle entry size exceeds maxDecompressedBytes (${SKILL_BUNDLE_LIMITS.maxDecompressedBytes}): ${path}`);
224
- }
225
- // Sanitise the stored mode. Executable bit is implied by runtime
226
- // convention; we never persist arbitrary chmod from the user's FS.
227
- const mode = (input.mode ?? SKILL_BUNDLE_LIMITS.defaultFileMode) & 0o777;
228
- if (mode !== SKILL_BUNDLE_LIMITS.defaultFileMode && mode !== SKILL_BUNDLE_LIMITS.defaultDirMode) {
229
- return { path, size: input.size, mode: SKILL_BUNDLE_LIMITS.defaultFileMode };
230
- }
231
- return { path, size: input.size, mode };
232
- }
233
- catch (error) {
234
- rethrowContractParseError(error, "parseSkillBundleEntry");
235
- }
236
- }
237
- /** @deprecated Use {@link parseSkillBundleEntry}; this compatibility wrapper is identical. */
238
- export function validateSkillBundleEntry(input) {
239
- return parseSkillBundleEntry(input);
240
- }
241
- /**
242
- * Validate a full **skill bundle** manifest. Enforces:
243
- * - entries is a non-empty array
244
- * - `SKILL.md` exists at the bundle root (this is what makes a
245
- * bundle a skill rather than a plain workspace file)
246
- * - file count <= maxFiles
247
- * - total uncompressed size <= maxDecompressedBytes
248
- * - per-entry validation (see `validateSkillBundleEntry`)
249
- * - no duplicate paths
250
- *
251
- * In this public surface, **skill** means "Claude Skill" — bundles without
252
- * `SKILL.md` are not skills and must go
253
- * through workspace instructions or file uploads instead.
254
- *
255
- * Returns a canonical manifest with totals computed.
256
- */
257
- export function parseSkillBundleManifest(input) {
258
- try {
259
- if (!Array.isArray(input) || input.length === 0) {
260
- throw new SkillBundleValidationError("bundle manifest must be a non-empty array of entries");
261
- }
262
- if (input.length > SKILL_BUNDLE_LIMITS.maxFiles) {
263
- throw new SkillBundleValidationError(`bundle exceeds maxFiles (${SKILL_BUNDLE_LIMITS.maxFiles}): got ${input.length}`);
264
- }
265
- const seen = new Set();
266
- const entries = [];
267
- let totalSize = 0;
268
- let hasSkillMd = false;
269
- for (const raw of input) {
270
- const entry = parseSkillBundleEntry(raw);
271
- if (seen.has(entry.path)) {
272
- throw new SkillBundleValidationError(`bundle manifest contains duplicate path: ${entry.path}`);
273
- }
274
- seen.add(entry.path);
275
- if (entry.path === "SKILL.md") {
276
- hasSkillMd = true;
277
- }
278
- totalSize += entry.size;
279
- if (totalSize > SKILL_BUNDLE_LIMITS.maxDecompressedBytes) {
280
- throw new SkillBundleValidationError(`bundle total size exceeds maxDecompressedBytes (${SKILL_BUNDLE_LIMITS.maxDecompressedBytes})`);
281
- }
282
- entries.push(entry);
283
- }
284
- if (!hasSkillMd) {
285
- throw new SkillBundleValidationError("skill bundle manifest must contain a 'SKILL.md' entry at the bundle root. " +
286
- "If you want to upload an instructions file or generic agent context, use " +
287
- "workspace instructions or File instead.");
288
- }
289
- return { entries, totalSize, fileCount: entries.length };
290
- }
291
- catch (error) {
292
- rethrowContractParseError(error, "parseSkillBundleManifest");
293
- }
294
- }
295
- /** @deprecated Use {@link parseSkillBundleManifest}; this compatibility wrapper is identical. */
296
- export function validateSkillBundleManifest(input) {
297
- return parseSkillBundleManifest(input);
298
- }
299
- /**
300
- * Returns true when the manifest carries a `SKILL.md` entry at the
301
- * bundle root. The presence of this file is Anthropic's
302
- * skill-auto-discovery signal — bundles that have it are treated as
303
- * Claude skills and mounted accordingly; bundles that don't are still
304
- * usable agent context (AGENTS.md, settings files, folders of helper
305
- * data) but the agent won't pick them up via the skills mechanism.
306
- *
307
- * The check is intentionally a separate, callable predicate (rather
308
- * than baked into `validateSkillBundleManifest`) so the storage and
309
- * the attach layers can remain independent.
310
- */
311
- export function hasSkillMdAtRoot(manifest) {
312
- return manifest.entries.some((entry) => entry.path === "SKILL.md");
313
- }
314
- // ---------------------------------------------------------------------------
315
- // McpServerRef (non-secret) + SessionConfigMcpServer (with optional headers)
316
- // ---------------------------------------------------------------------------
317
- /**
318
- * Remote MCP transports Aex accepts. Both are over HTTP — `http`
319
- * is the streamable-HTTP transport, `sse` is the event-stream
320
- * transport. `stdio` is explicitly NOT a value here: local-process
321
- * MCP is not implemented.
322
- */
323
- export const REMOTE_MCP_TRANSPORTS = ["http", "sse"];
324
- /**
325
- * Canonical error string for any attempt to declare a stdio-shaped MCP
326
- * server (`transport: "stdio"`, or a stdio-only field like `command` /
327
- * `args` / `env`). Pinned in source so every surface — shared parser,
328
- * SDK builder, CLI flag parser, dashboard form — surfaces the same
329
- * message and a user can find it via grep.
330
- *
331
- * Declared in `schemas/mcp-server.ts` alongside the shape gate that raises it.
332
- */
333
- export { REMOTE_MCP_STDIO_REJECTED_MESSAGE };
334
- /** Declared in `schemas/mcp-server.ts`, next to the schema that enforces it. */
335
- export { MCP_SERVER_NAME_PATTERN };
336
- /**
337
- * Parse the non-secret half of an MCP server declaration mounted at `path`.
338
- *
339
- * SSRF guard at the parser boundary (C4) — the platform MCP proxy relies on
340
- * this validation; each branch of {@link denyReasonForMcpHost} maps to an SSRF
341
- * regression test case.
342
- */
343
- export function parseMcpServerRef(input, path) {
344
- return withContractParseError("parseMcpServerRef", () => normalizeMcpServerRef(parseMcpServerRefWire(input, path, MCP_WIRE_POLICY)));
345
- }
346
- export { rejectStdioMcpShape };
347
- /**
348
- * The canonical private/unroutable address set — the union resolved once so the
349
- * SDK, the CLI, and the platform admission path refuse the same bytes.
350
- */
351
- const EGRESS_DENIED_RANGES = [
352
- { cidr: "0.0.0.0/8", family: 4, reason: "must not target unroutable IPv4 (0.0.0.0/8)" },
353
- { cidr: "10.0.0.0/8", family: 4, reason: "must not target RFC1918 IPv4 (10.0.0.0/8)" },
354
- { cidr: "127.0.0.0/8", family: 4, reason: "must not target loopback IPv4 (127.0.0.0/8)" },
355
- {
356
- cidr: "169.254.0.0/16",
357
- family: 4,
358
- reason: "must not target link-local IPv4 (169.254.0.0/16) — cloud metadata range"
359
- },
360
- { cidr: "100.64.0.0/10", family: 4, reason: "must not target CGNAT IPv4 (100.64.0.0/10)" },
361
- { cidr: "198.18.0.0/15", family: 4, reason: "must not target benchmark IPv4 (198.18.0.0/15)" },
362
- { cidr: "172.16.0.0/12", family: 4, reason: "must not target RFC1918 IPv4 (172.16.0.0/12)" },
363
- { cidr: "192.168.0.0/16", family: 4, reason: "must not target RFC1918 IPv4 (192.168.0.0/16)" },
364
- { cidr: "224.0.0.0/3", family: 4, reason: "must not target multicast/reserved IPv4 (224.0.0.0/3)" },
365
- {
366
- cidr: "::/128",
367
- family: 6,
368
- reason: "must not target unspecified IPv6 (::)",
369
- match: (host) => host === "::"
370
- },
371
- {
372
- cidr: "::1/128",
373
- family: 6,
374
- reason: "must not target loopback IPv6 (::1)",
375
- match: (host) => host === "::1" || host === "0:0:0:0:0:0:0:1"
376
- },
377
- {
378
- cidr: "fe80::/10",
379
- family: 6,
380
- reason: "must not target link-local IPv6 (fe80::/10)",
381
- match: (host) => /^fe[89ab][0-9a-f]?:/.test(host)
382
- },
383
- {
384
- cidr: "fc00::/7",
385
- family: 6,
386
- reason: "must not target unique-local IPv6 (fc00::/7)",
387
- match: (host) => /^f[cd][0-9a-f]{0,2}:/.test(host)
388
- },
389
- {
390
- cidr: "64:ff9b::/96",
391
- family: 6,
392
- reason: "must not target IPv6 NAT64 prefix (64:ff9b::/96)",
393
- match: (host) => host.startsWith("64:ff9b::")
394
- }
395
- ];
396
- // NOTE — `::ffff:0:0/96` is deliberately ABSENT from the table above. Go's
397
- // `net.IPNet.Contains` degrades an IPv4-mapped `/96` to IPv4 `0.0.0.0/0`, so
398
- // adding it to the egress proxy's deny_ranges would block ALL IPv4. It is also
399
- // unnecessary: IPv4-mapped literals are folded to IPv4 and classified by the
400
- // IPv4 rules above (see the `::ffff:` branch in the IP-literal classifier).
401
- /** IPv4 dotted-quad → uint32, or null when `host` is not a dotted-quad. */
402
- function ipv4ToUint32(host) {
403
- if (!/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(host))
404
- return null;
405
- const octets = host.split(".").map((o) => Number.parseInt(o, 10));
406
- if (octets.some((o) => o > 255))
407
- return null;
408
- return ((octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3]) >>> 0;
409
- }
410
- /** Whether `value` (uint32) falls inside the IPv4 `cidr`. */
411
- function ipv4InCidr(value, cidr) {
412
- const [network, prefixText] = cidr.split("/");
413
- const base = ipv4ToUint32(network);
414
- if (base === null)
415
- return false;
416
- const prefix = Number.parseInt(prefixText, 10);
417
- const mask = prefix === 0 ? 0 : (0xffffffff << (32 - prefix)) >>> 0;
418
- return (value & mask) === (base & mask);
419
- }
420
- /**
421
- * Reasons an IP-literal host should be refused. Returns null when the
422
- * literal is a routable public address (or not an IP literal at all — name
423
- * resolution is the caller's concern). This numeric-range deny-list is kept
424
- * in parity across the public contract parser and platform shared parser so
425
- * the MCP parser, the egress proxy handlers, and `submission.parseProxyBaseUrl`
426
- * classify the same bytes.
427
- *
428
- * `host` is the already-bracket-stripped, lowercased hostname.
429
- *
430
- * NOTE — residual DNS-rebind gap: this denies IP *literals* only. A name
431
- * that resolves to a private/metadata IP is NOT caught here (we don't
432
- * resolve at parse time). Closing that requires resolve-then-pin at egress;
433
- * that pinning is deferred. The host's outbound fetch still refuses RFC1918
434
- * at connect, but not loopback/169.254/CGNAT/ULA — which is exactly why the
435
- * literal checks below exist as defense in depth.
436
- */
437
- function denyReasonForHostIp(host) {
438
- // IPv4-mapped / IPv4-compatible IPv6 literals decode to an embedded IPv4 —
439
- // classify that IPv4 so a mapped form can't smuggle a private target. Two
440
- // shapes reach us: the dotted-quad form a caller may type (`::ffff:127.0.0.1`)
441
- // and the hex form `new URL().hostname` normalises it to (`::ffff:7f00:1`),
442
- // where the two trailing hextets ARE the four IPv4 octets.
443
- const mappedDotted = /^::(?:ffff:)?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/.exec(host);
444
- if (mappedDotted) {
445
- return denyReasonForV4(mappedDotted[1]);
446
- }
447
- const mappedHex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(host);
448
- if (mappedHex) {
449
- const hi = Number.parseInt(mappedHex[1], 16);
450
- const lo = Number.parseInt(mappedHex[2], 16);
451
- const dotted = `${hi >> 8}.${hi & 0xff}.${lo >> 8}.${lo & 0xff}`;
452
- return denyReasonForV4(dotted);
453
- }
454
- const v4 = denyReasonForV4(host);
455
- if (v4)
456
- return v4;
457
- for (const range of EGRESS_DENIED_RANGES) {
458
- if (range.family === 6 && range.match?.(host) === true)
459
- return range.reason;
460
- }
461
- return null;
462
- }
463
- /**
464
- * IPv4-literal deny-list, derived from {@link EGRESS_DENIED_RANGES}. Returns
465
- * null when `host` is not a dotted-quad or
466
- * is a routable public IPv4. Split out of {@link denyReasonForHostIp} so the
467
- * IPv4-mapped IPv6 branch reuses the exact same ranges.
468
- */
469
- function denyReasonForV4(host) {
470
- const value = ipv4ToUint32(host);
471
- if (value === null)
472
- return null;
473
- for (const range of EGRESS_DENIED_RANGES) {
474
- if (range.family === 4 && ipv4InCidr(value, range.cidr))
475
- return range.reason;
476
- }
477
- return null;
478
- }
479
- /**
480
- * Reasons an MCP server URL should be refused at parse time. Returns null
481
- * when the URL is acceptable. Hostnames are lowercased; numeric ranges
482
- * are checked literally so the catch covers both names ("localhost") and
483
- * IP literals ("127.0.0.1") symmetrically. The numeric-range checks
484
- * delegate to {@link denyReasonForHostIp} (shared with the platform proxy).
485
- *
486
- * Surface tracked by server-side SSRF regression coverage.
487
- */
488
- function denyReasonForMcpHost(parsed) {
489
- // `new URL("https://[fe80::1]/").hostname` returns `[fe80::1]` WITH
490
- // the brackets on Node 22; strip them so the IPv6 checks match either
491
- // shape symmetrically.
492
- const host = parsed.hostname.toLowerCase().replace(/^\[|\]$/g, "");
493
- // Loopback name (covers `localhost` + `localhost.localdomain` etc.)
494
- if (host === "localhost" || host.endsWith(".localhost")) {
495
- return "must not target a loopback hostname";
496
- }
497
- const ipDenial = denyReasonForHostIp(host);
498
- if (ipDenial)
499
- return ipDenial;
500
- // Port constraint: https must be on 443 (defense in depth — non-standard
501
- // https ports often indicate internal services). http allowance keeps
502
- // the existing local-dev pattern (e.g. host.docker.internal:8787) usable.
503
- if (parsed.protocol === "https:" && parsed.port !== "" && parsed.port !== "443") {
504
- return `must use port 443 for https (got ${parsed.port})`;
505
- }
506
- return null;
507
- }
508
- function parseRemoteMcpTransport(input, field) {
509
- if (input === undefined) {
510
- return undefined;
511
- }
512
- if (typeof input !== "string" || !REMOTE_MCP_TRANSPORTS.includes(input)) {
513
- throw new Error(`${field} must be one of: ${REMOTE_MCP_TRANSPORTS.join(", ")} (got ${JSON.stringify(input)})`);
514
- }
515
- return input;
516
- }
517
- /**
518
- * The two rules the MCP schemas defer back to this module for.
519
- *
520
- * Injected rather than imported the other way around because
521
- * `scripts/cicd/check-contract-parity.mjs` locates the SSRF deny-list INSIDE
522
- * this file — it slices from `denyReasonForHostIp` to `parseRemoteMcpTransport`
523
- * and byte-compares that region against `platform/packages/shared/src/blueprint.ts`.
524
- * Moving either function into `schemas/` would break the only check that keeps
525
- * the two deny-lists identical.
526
- */
527
- const MCP_WIRE_POLICY = {
528
- denyReasonForHost: denyReasonForMcpHost,
529
- parseTransport: parseRemoteMcpTransport
530
- };
531
- // ---------------------------------------------------------------------------
532
- // Session request config parser (used by CLI to load `session.json`)
533
- // ---------------------------------------------------------------------------
534
- /**
535
- * Parse a session request config from JSON. Defensive — used by the host CLI to
536
- * load `--config session.json`. Throws with the JSON path that failed so
537
- * a user can fix their file. Headers are preserved here and split out
538
- * later by the SDK normalisation step.
539
- */
540
- export function parseSessionRequestConfig(input) {
541
- return withContractParseError("parseSessionRequestConfig", () => parseSessionRequestConfigWire(input, MCP_WIRE_POLICY));
542
- }
543
- export function normaliseSessionRequestConfig(config) {
544
- const prompt = typeof config.prompt === "string" ? [config.prompt] : config.prompt;
545
- const mcpServers = [];
546
- const mcpServerSecrets = [];
547
- for (const entry of config.mcpServers ?? []) {
548
- mcpServers.push({ name: entry.name, url: entry.url });
549
- if (entry.headers !== undefined) {
550
- mcpServerSecrets.push({ name: entry.name, url: entry.url, headers: entry.headers });
551
- }
552
- }
553
- return {
554
- model: config.model,
555
- ...(config.system !== undefined ? { system: config.system } : {}),
556
- prompt,
557
- mcpServers,
558
- ...(config.environment !== undefined ? { environment: config.environment } : {}),
559
- ...(config.metadata !== undefined ? { metadata: config.metadata } : {}),
560
- mcpServerSecrets
561
- };
562
- }