@aexhq/sdk 0.13.6

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 (112) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +160 -0
  3. package/dist/_contracts/connection-ticket.d.ts +21 -0
  4. package/dist/_contracts/connection-ticket.js +49 -0
  5. package/dist/_contracts/event-envelope.d.ts +276 -0
  6. package/dist/_contracts/event-envelope.js +324 -0
  7. package/dist/_contracts/event-stream-client.d.ts +47 -0
  8. package/dist/_contracts/event-stream-client.js +141 -0
  9. package/dist/_contracts/http.d.ts +35 -0
  10. package/dist/_contracts/http.js +114 -0
  11. package/dist/_contracts/index.d.ts +28 -0
  12. package/dist/_contracts/index.js +29 -0
  13. package/dist/_contracts/managed-key.d.ts +74 -0
  14. package/dist/_contracts/managed-key.js +110 -0
  15. package/dist/_contracts/operations.d.ts +237 -0
  16. package/dist/_contracts/operations.js +632 -0
  17. package/dist/_contracts/provider-support.d.ts +220 -0
  18. package/dist/_contracts/provider-support.js +90 -0
  19. package/dist/_contracts/proxy-protocol.d.ts +257 -0
  20. package/dist/_contracts/proxy-protocol.js +234 -0
  21. package/dist/_contracts/proxy-validation.d.ts +19 -0
  22. package/dist/_contracts/proxy-validation.js +51 -0
  23. package/dist/_contracts/run-artifacts.d.ts +47 -0
  24. package/dist/_contracts/run-artifacts.js +101 -0
  25. package/dist/_contracts/run-config.d.ts +304 -0
  26. package/dist/_contracts/run-config.js +659 -0
  27. package/dist/_contracts/run-cost.d.ts +125 -0
  28. package/dist/_contracts/run-cost.js +616 -0
  29. package/dist/_contracts/run-custody.d.ts +226 -0
  30. package/dist/_contracts/run-custody.js +465 -0
  31. package/dist/_contracts/run-record.d.ts +127 -0
  32. package/dist/_contracts/run-record.js +177 -0
  33. package/dist/_contracts/run-retention.d.ts +213 -0
  34. package/dist/_contracts/run-retention.js +484 -0
  35. package/dist/_contracts/run-unit.d.ts +194 -0
  36. package/dist/_contracts/run-unit.js +215 -0
  37. package/dist/_contracts/runner-event.d.ts +114 -0
  38. package/dist/_contracts/runner-event.js +187 -0
  39. package/dist/_contracts/runtime-manifest.d.ts +106 -0
  40. package/dist/_contracts/runtime-manifest.js +98 -0
  41. package/dist/_contracts/runtime-security-profile.d.ts +27 -0
  42. package/dist/_contracts/runtime-security-profile.js +82 -0
  43. package/dist/_contracts/runtime-sizes.d.ts +144 -0
  44. package/dist/_contracts/runtime-sizes.js +136 -0
  45. package/dist/_contracts/runtime-types.d.ts +212 -0
  46. package/dist/_contracts/runtime-types.js +2 -0
  47. package/dist/_contracts/sdk-errors.d.ts +34 -0
  48. package/dist/_contracts/sdk-errors.js +52 -0
  49. package/dist/_contracts/sdk-secrets.d.ts +31 -0
  50. package/dist/_contracts/sdk-secrets.js +220 -0
  51. package/dist/_contracts/side-effect-audit.d.ts +129 -0
  52. package/dist/_contracts/side-effect-audit.js +494 -0
  53. package/dist/_contracts/sse.d.ts +74 -0
  54. package/dist/_contracts/sse.js +0 -0
  55. package/dist/_contracts/stable.d.ts +26 -0
  56. package/dist/_contracts/stable.js +44 -0
  57. package/dist/_contracts/status.d.ts +19 -0
  58. package/dist/_contracts/status.js +61 -0
  59. package/dist/_contracts/submission.d.ts +383 -0
  60. package/dist/_contracts/submission.js +1380 -0
  61. package/dist/agents-md.d.ts +46 -0
  62. package/dist/agents-md.js +83 -0
  63. package/dist/agents-md.js.map +1 -0
  64. package/dist/asset-upload.d.ts +66 -0
  65. package/dist/asset-upload.js +168 -0
  66. package/dist/asset-upload.js.map +1 -0
  67. package/dist/bundle.d.ts +33 -0
  68. package/dist/bundle.js +89 -0
  69. package/dist/bundle.js.map +1 -0
  70. package/dist/cli.mjs +4140 -0
  71. package/dist/cli.mjs.sha256 +1 -0
  72. package/dist/client.d.ts +460 -0
  73. package/dist/client.js +857 -0
  74. package/dist/client.js.map +1 -0
  75. package/dist/fetch-archive.d.ts +16 -0
  76. package/dist/fetch-archive.js +170 -0
  77. package/dist/fetch-archive.js.map +1 -0
  78. package/dist/file.d.ts +57 -0
  79. package/dist/file.js +153 -0
  80. package/dist/file.js.map +1 -0
  81. package/dist/index.d.ts +30 -0
  82. package/dist/index.js +34 -0
  83. package/dist/index.js.map +1 -0
  84. package/dist/mcp-server.d.ts +84 -0
  85. package/dist/mcp-server.js +114 -0
  86. package/dist/mcp-server.js.map +1 -0
  87. package/dist/node-fs.d.ts +12 -0
  88. package/dist/node-fs.js +44 -0
  89. package/dist/node-fs.js.map +1 -0
  90. package/dist/proxy-endpoint.d.ts +131 -0
  91. package/dist/proxy-endpoint.js +147 -0
  92. package/dist/proxy-endpoint.js.map +1 -0
  93. package/dist/skill.d.ts +117 -0
  94. package/dist/skill.js +169 -0
  95. package/dist/skill.js.map +1 -0
  96. package/dist/version.d.ts +9 -0
  97. package/dist/version.js +10 -0
  98. package/dist/version.js.map +1 -0
  99. package/docs/cleanup.md +38 -0
  100. package/docs/credentials.md +153 -0
  101. package/docs/events.md +76 -0
  102. package/docs/mcp.md +47 -0
  103. package/docs/outputs.md +157 -0
  104. package/docs/product-boundaries.md +57 -0
  105. package/docs/provider-runtime-capabilities.md +103 -0
  106. package/docs/quickstart.md +110 -0
  107. package/docs/release.md +99 -0
  108. package/docs/run-config.md +53 -0
  109. package/docs/run-record.md +39 -0
  110. package/docs/skills.md +139 -0
  111. package/docs/testing.md +29 -0
  112. package/package.json +47 -0
@@ -0,0 +1,215 @@
1
+ /**
2
+ * RunUnit — the self-contained read shape of a run.
3
+ *
4
+ * One canonical struct that captures every non-secret artifact persisted
5
+ * for a single run: parsed submission inputs, status/lifecycle, attempts,
6
+ * indexed events, raw-event Storage manifest, outputs (+ capture
7
+ * failures), proxy-call audit log, pinned workspace skills, provider
8
+ * built-in skills, and transient (Anthropic Files) skill records.
9
+ *
10
+ * Wire contract for `GET /api/runs/:runId`, the per-run archive's
11
+ * `run.json`/`submission.json`/`caps.json`, and the SDK/CLI
12
+ * `client.runs.get(runId)` return type.
13
+ *
14
+ * Immutability: every field here is read-only. Edit endpoints do not
15
+ * exist by design.
16
+ *
17
+ * Raw event payloads are not embedded in this struct. They live in
18
+ * private object storage as gzipped JSONL pages and are listed via
19
+ * `rawEventPages` (manifest only; bytes downloaded out-of-band so the
20
+ * detail response stays bounded). The archive zip carries the bytes.
21
+ */
22
+ import { parseMcpServerRef, parseSkillRef } from "./run-config.js";
23
+ import { PLATFORM_PACKAGE_ECOSYSTEMS } from "./submission.js";
24
+ // ---------------------------------------------------------------------------
25
+ // Submission parser
26
+ // ---------------------------------------------------------------------------
27
+ /**
28
+ * Parse a legacy run snapshot jsonb payload into the typed flat
29
+ * submission. Never throws on minor unknown keys so we can
30
+ * forward-compat with worker-side enrichment.
31
+ *
32
+ * Returns a typed shape even for malformed snapshots — the worst case
33
+ * is `{kind: "submission", submission: {model: "", ...}}` with empty
34
+ * defaults — because the dashboard must still render *something* for a
35
+ * buggy historical row rather than 500ing the whole detail page.
36
+ */
37
+ export function parseRunUnitSubmission(input) {
38
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
39
+ return fallbackFlat();
40
+ }
41
+ const value = input;
42
+ if (value.kind === "submission") {
43
+ return parseFlatProjection(value);
44
+ }
45
+ // Snapshot exists but does not match the flat shape — surface as an
46
+ // empty flat submission so consumers can still render lifecycle bits.
47
+ return fallbackFlat();
48
+ }
49
+ function parseFlatProjection(value) {
50
+ const submissionRaw = isRecord(value.submission) ? value.submission : {};
51
+ const outputsRaw = isRecord(submissionRaw.outputs) ? submissionRaw.outputs : {};
52
+ const allowedDirs = toOptionalStringArray(outputsRaw.allowedDirs);
53
+ const deniedDirs = toOptionalStringArray(outputsRaw.deniedDirs);
54
+ const submission = {
55
+ model: typeof submissionRaw.model === "string" ? submissionRaw.model : "",
56
+ ...(typeof submissionRaw.system === "string" ? { system: submissionRaw.system } : {}),
57
+ prompt: toStringArray(submissionRaw.prompt),
58
+ skills: toSkillRefArray(submissionRaw.skills),
59
+ agentsMd: [],
60
+ files: [],
61
+ mcpServers: toMcpServerRefArray(submissionRaw.mcpServers),
62
+ ...(parseEnvironment(submissionRaw.environment)
63
+ ? { environment: parseEnvironment(submissionRaw.environment) }
64
+ : {}),
65
+ ...(parseSecurityProfile(submissionRaw.securityProfile)
66
+ ? { securityProfile: parseSecurityProfile(submissionRaw.securityProfile) }
67
+ : {}),
68
+ ...(isJsonRecord(submissionRaw.metadata) ? { metadata: submissionRaw.metadata } : {}),
69
+ ...(allowedDirs || deniedDirs
70
+ ? {
71
+ outputs: {
72
+ ...(allowedDirs ? { allowedDirs } : {}),
73
+ ...(deniedDirs ? { deniedDirs } : {})
74
+ }
75
+ }
76
+ : {})
77
+ };
78
+ return {
79
+ kind: "submission",
80
+ submission
81
+ };
82
+ }
83
+ function parseSecurityProfile(value) {
84
+ return value === "strict" || value === "standard" || value === "developer" ? value : undefined;
85
+ }
86
+ function fallbackFlat() {
87
+ return {
88
+ kind: "submission",
89
+ submission: {
90
+ model: "",
91
+ prompt: [],
92
+ skills: [],
93
+ agentsMd: [],
94
+ files: [],
95
+ mcpServers: []
96
+ }
97
+ };
98
+ }
99
+ // ---------------------------------------------------------------------------
100
+ // Coercion helpers — deliberately lenient. We never throw on a single
101
+ // malformed sub-field; we collapse it to a safe default and keep going
102
+ // so a dashboard read of a malformed snapshot still surfaces the rest.
103
+ // ---------------------------------------------------------------------------
104
+ function isRecord(value) {
105
+ return typeof value === "object" && value !== null && !Array.isArray(value);
106
+ }
107
+ function isJsonRecord(value) {
108
+ return isRecord(value);
109
+ }
110
+ function toStringArray(value) {
111
+ if (!Array.isArray(value)) {
112
+ return [];
113
+ }
114
+ return value.filter((item) => typeof item === "string");
115
+ }
116
+ function toOptionalStringArray(value) {
117
+ if (!Array.isArray(value) || value.length === 0) {
118
+ return undefined;
119
+ }
120
+ const filtered = value.filter((item) => typeof item === "string");
121
+ return filtered.length === 0 ? undefined : filtered;
122
+ }
123
+ function toSkillRefArray(value) {
124
+ if (!Array.isArray(value)) {
125
+ return [];
126
+ }
127
+ const out = [];
128
+ for (let i = 0; i < value.length; i++) {
129
+ try {
130
+ out.push(parseSkillRef(value[i], `submission.skills[${i}]`));
131
+ }
132
+ catch {
133
+ // Skip malformed entries rather than failing the whole detail
134
+ // read. Worker-side enrichment may add fields we don't recognise.
135
+ }
136
+ }
137
+ return out;
138
+ }
139
+ function toMcpServerRefArray(value) {
140
+ if (!Array.isArray(value)) {
141
+ return [];
142
+ }
143
+ const out = [];
144
+ for (let i = 0; i < value.length; i++) {
145
+ try {
146
+ out.push(parseMcpServerRef(value[i], `submission.mcpServers[${i}]`));
147
+ }
148
+ catch {
149
+ // ignore malformed
150
+ }
151
+ }
152
+ return out;
153
+ }
154
+ function parseEnvironment(value) {
155
+ if (!isRecord(value)) {
156
+ return undefined;
157
+ }
158
+ const env = {};
159
+ if (isRecord(value.networking)) {
160
+ const mode = value.networking.mode;
161
+ const allowedHosts = value.networking.allowedHosts;
162
+ if (mode === "limited" || mode === "open") {
163
+ env.networking = {
164
+ mode,
165
+ ...(Array.isArray(allowedHosts)
166
+ ? { allowedHosts: toStringArray(allowedHosts) }
167
+ : {})
168
+ };
169
+ }
170
+ }
171
+ if (Array.isArray(value.packages)) {
172
+ const pkgs = value.packages
173
+ .filter(isRecord)
174
+ .map((p) => {
175
+ const r = p;
176
+ if (typeof r.name !== "string")
177
+ return null;
178
+ // Snapshots persisted after the ecosystem split carry it verbatim;
179
+ // older snapshots (pre-split) default to `apt` to match the strict
180
+ // parser's unprefixed default.
181
+ const ecosystem = typeof r.ecosystem === "string" &&
182
+ PLATFORM_PACKAGE_ECOSYSTEMS.includes(r.ecosystem)
183
+ ? r.ecosystem
184
+ : "apt";
185
+ return {
186
+ name: r.name,
187
+ ...(typeof r.version === "string" ? { version: r.version } : {}),
188
+ ecosystem
189
+ };
190
+ })
191
+ .filter((p) => p !== null);
192
+ if (pkgs.length > 0) {
193
+ env.packages = pkgs;
194
+ }
195
+ }
196
+ // Lenient pass-through for envVars stored in already-validated
197
+ // snapshots. The strict parser in submission.ts enforces shape /
198
+ // size / reserved-prefix rules at submission time; here we just
199
+ // accept whatever shape was persisted.
200
+ if (isRecord(value.envVars)) {
201
+ const out = {};
202
+ for (const [k, v] of Object.entries(value.envVars)) {
203
+ if (typeof v === "string") {
204
+ out[k] = v;
205
+ }
206
+ }
207
+ if (Object.keys(out).length > 0) {
208
+ env.envVars = out;
209
+ }
210
+ }
211
+ return env.networking || env.packages || env.envVars
212
+ ? env
213
+ : undefined;
214
+ }
215
+ //# sourceMappingURL=run-unit.js.map
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Unified runner event schema. The managed runtime feeds one shape into
3
+ * the hosted aex event pipeline:
4
+ *
5
+ * - **Goose Managed** — the per-run managed runtime POSTs batches of
6
+ * NDJSON events to `/runs/{id}/runner/events`; the Goose adapter
7
+ * translates each event into one or more `RunnerEvent`s.
8
+ *
9
+ * The downstream subscribers (dashboard, SDK `streamEvents`, observable
10
+ * spans) never see runtime-specific wire shapes — they only see
11
+ * `RunnerEvent`s.
12
+ *
13
+ * This is the public event contract consumed by SDK and CLI clients.
14
+ */
15
+ import type { JsonValue } from "./submission.js";
16
+ /**
17
+ * Schema version. Bump when the shape of `RunnerEvent`, its kind set,
18
+ * or the batch envelope changes. Subscribers gate on this so a future
19
+ * v2 wire shape can land behind a feature flag.
20
+ */
21
+ export declare const RUNNER_EVENT_VERSION: 1;
22
+ /**
23
+ * The set of event kinds emitted into the unified stream. Adapters
24
+ * fold runtime-specific events into one of these — anything that
25
+ * doesn't fit is mapped to `notification` so the data is captured
26
+ * even when no UI handler exists yet.
27
+ *
28
+ * - `runtime_started` — either runtime announced "ready" (Fly
29
+ * machine running goose; Anthropic session
30
+ * accepted the first turn).
31
+ * - `assistant_text` — model text delta.
32
+ * - `tool_request` — model emitted a tool_use / function call.
33
+ * - `tool_response` — tool result delivered back to the model.
34
+ * - `skill_loaded` — a skill was loaded (Anthropic Skills API
35
+ * ref OR a workspace folder mount).
36
+ * - `file_uploaded` — a file became available to the agent
37
+ * (Files API id OR workspace path).
38
+ * - `notification` — runtime/extension notification; catch-all
39
+ * for diagnostic data.
40
+ * - `stream_error` — stream-level error (non-fatal). Subscribers
41
+ * may surface this as a UI warning; the run
42
+ * continues unless `runtime_terminal` follows.
43
+ * - `runtime_terminal` — the run reached a terminal state. The
44
+ * adapter MUST emit exactly one of these per
45
+ * run; subscribers gate on it for end-of-stream.
46
+ */
47
+ export declare const RUNNER_EVENT_KINDS: readonly ["runtime_started", "assistant_text", "tool_request", "tool_response", "skill_loaded", "file_uploaded", "notification", "stream_error", "runtime_terminal"];
48
+ export type RunnerEventKind = (typeof RUNNER_EVENT_KINDS)[number];
49
+ /**
50
+ * One event in the unified stream. `seq` is monotonically increasing
51
+ * within a single run (the adapter is responsible for assigning seqs
52
+ * — no two events with the same `seq` for the same `runId`); `tMs` is
53
+ * a millisecond-resolution timestamp that is also monotonically
54
+ * non-decreasing within a single run (an event's `tMs` is never less
55
+ * than the previous event's `tMs`). `data` carries the runtime- and
56
+ * kind-specific payload, JSON-typed so the batch round-trips through
57
+ * the database column without ad-hoc serialization.
58
+ */
59
+ export interface RunnerEvent {
60
+ readonly seq: number;
61
+ readonly tMs: number;
62
+ readonly kind: RunnerEventKind;
63
+ readonly data: Readonly<Record<string, JsonValue>>;
64
+ }
65
+ /**
66
+ * Batch envelope. The runner ships one or more events per POST so the
67
+ * inbox writes them atomically. `events` MUST be sorted by `seq`
68
+ * ascending; api.aex.dev rejects malformed batches before touching
69
+ * Postgres.
70
+ */
71
+ export interface RunnerEventBatch {
72
+ readonly v: typeof RUNNER_EVENT_VERSION;
73
+ readonly runId: string;
74
+ readonly events: readonly RunnerEvent[];
75
+ }
76
+ /**
77
+ * Maximum number of events per batch. Bounds the size of the body
78
+ * api.aex.dev accepts and the size of the downstream Postgres / KV
79
+ * write. Larger streams are split into multiple batches; the runner is
80
+ * responsible for chunking.
81
+ */
82
+ export declare const RUNNER_EVENT_BATCH_MAX_EVENTS: 256;
83
+ /**
84
+ * Validation outcome for an inbound batch. The `ok` branch returns
85
+ * the parsed batch with frozen events; the `error` branch returns the
86
+ * code + a short human message suitable for an HTTP 400 body. Codes
87
+ * are stable strings — the dashboard / SDK may branch on them.
88
+ */
89
+ export type RunnerEventBatchValidation = {
90
+ readonly ok: true;
91
+ readonly batch: RunnerEventBatch;
92
+ } | {
93
+ readonly ok: false;
94
+ readonly code: RunnerEventBatchValidationCode;
95
+ readonly message: string;
96
+ };
97
+ export declare const RUNNER_EVENT_BATCH_VALIDATION_CODES: readonly ["invalid_envelope", "version_mismatch", "missing_run_id", "empty_batch", "batch_too_large", "invalid_event", "seq_not_monotonic", "t_ms_not_monotonic"];
98
+ export type RunnerEventBatchValidationCode = (typeof RUNNER_EVENT_BATCH_VALIDATION_CODES)[number];
99
+ /**
100
+ * Parse + validate an inbound runner event batch (untrusted input).
101
+ * Used at the api.aex.dev ingress so adapters never have to
102
+ * re-check the wire shape, and used by tests to assert the contract.
103
+ *
104
+ * Successful validation guarantees:
105
+ * - top-level envelope matches {@link RunnerEventBatch}
106
+ * - `v === RUNNER_EVENT_VERSION`
107
+ * - `runId` is a non-empty string
108
+ * - `events` is a non-empty array of at most
109
+ * {@link RUNNER_EVENT_BATCH_MAX_EVENTS} entries
110
+ * - each event is a {@link RunnerEvent} with a known `kind`
111
+ * - `seq` is strictly increasing across the batch
112
+ * - `tMs` is non-decreasing across the batch
113
+ */
114
+ export declare function validateRunnerEventBatch(input: unknown): RunnerEventBatchValidation;
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Unified runner event schema. The managed runtime feeds one shape into
3
+ * the hosted aex event pipeline:
4
+ *
5
+ * - **Goose Managed** — the per-run managed runtime POSTs batches of
6
+ * NDJSON events to `/runs/{id}/runner/events`; the Goose adapter
7
+ * translates each event into one or more `RunnerEvent`s.
8
+ *
9
+ * The downstream subscribers (dashboard, SDK `streamEvents`, observable
10
+ * spans) never see runtime-specific wire shapes — they only see
11
+ * `RunnerEvent`s.
12
+ *
13
+ * This is the public event contract consumed by SDK and CLI clients.
14
+ */
15
+ /**
16
+ * Schema version. Bump when the shape of `RunnerEvent`, its kind set,
17
+ * or the batch envelope changes. Subscribers gate on this so a future
18
+ * v2 wire shape can land behind a feature flag.
19
+ */
20
+ export const RUNNER_EVENT_VERSION = 1;
21
+ /**
22
+ * The set of event kinds emitted into the unified stream. Adapters
23
+ * fold runtime-specific events into one of these — anything that
24
+ * doesn't fit is mapped to `notification` so the data is captured
25
+ * even when no UI handler exists yet.
26
+ *
27
+ * - `runtime_started` — either runtime announced "ready" (Fly
28
+ * machine running goose; Anthropic session
29
+ * accepted the first turn).
30
+ * - `assistant_text` — model text delta.
31
+ * - `tool_request` — model emitted a tool_use / function call.
32
+ * - `tool_response` — tool result delivered back to the model.
33
+ * - `skill_loaded` — a skill was loaded (Anthropic Skills API
34
+ * ref OR a workspace folder mount).
35
+ * - `file_uploaded` — a file became available to the agent
36
+ * (Files API id OR workspace path).
37
+ * - `notification` — runtime/extension notification; catch-all
38
+ * for diagnostic data.
39
+ * - `stream_error` — stream-level error (non-fatal). Subscribers
40
+ * may surface this as a UI warning; the run
41
+ * continues unless `runtime_terminal` follows.
42
+ * - `runtime_terminal` — the run reached a terminal state. The
43
+ * adapter MUST emit exactly one of these per
44
+ * run; subscribers gate on it for end-of-stream.
45
+ */
46
+ export const RUNNER_EVENT_KINDS = [
47
+ "runtime_started",
48
+ "assistant_text",
49
+ "tool_request",
50
+ "tool_response",
51
+ "skill_loaded",
52
+ "file_uploaded",
53
+ "notification",
54
+ "stream_error",
55
+ "runtime_terminal"
56
+ ];
57
+ /**
58
+ * Maximum number of events per batch. Bounds the size of the body
59
+ * api.aex.dev accepts and the size of the downstream Postgres / KV
60
+ * write. Larger streams are split into multiple batches; the runner is
61
+ * responsible for chunking.
62
+ */
63
+ export const RUNNER_EVENT_BATCH_MAX_EVENTS = 256;
64
+ export const RUNNER_EVENT_BATCH_VALIDATION_CODES = [
65
+ "invalid_envelope",
66
+ "version_mismatch",
67
+ "missing_run_id",
68
+ "empty_batch",
69
+ "batch_too_large",
70
+ "invalid_event",
71
+ "seq_not_monotonic",
72
+ "t_ms_not_monotonic"
73
+ ];
74
+ /**
75
+ * Parse + validate an inbound runner event batch (untrusted input).
76
+ * Used at the api.aex.dev ingress so adapters never have to
77
+ * re-check the wire shape, and used by tests to assert the contract.
78
+ *
79
+ * Successful validation guarantees:
80
+ * - top-level envelope matches {@link RunnerEventBatch}
81
+ * - `v === RUNNER_EVENT_VERSION`
82
+ * - `runId` is a non-empty string
83
+ * - `events` is a non-empty array of at most
84
+ * {@link RUNNER_EVENT_BATCH_MAX_EVENTS} entries
85
+ * - each event is a {@link RunnerEvent} with a known `kind`
86
+ * - `seq` is strictly increasing across the batch
87
+ * - `tMs` is non-decreasing across the batch
88
+ */
89
+ export function validateRunnerEventBatch(input) {
90
+ if (!isRecord(input)) {
91
+ return invalid("invalid_envelope", "batch must be a JSON object");
92
+ }
93
+ if (input.v !== RUNNER_EVENT_VERSION) {
94
+ return invalid("version_mismatch", `batch.v must equal ${RUNNER_EVENT_VERSION} (got ${JSON.stringify(input.v)})`);
95
+ }
96
+ if (typeof input.runId !== "string" || input.runId.length === 0) {
97
+ return invalid("missing_run_id", "batch.runId must be a non-empty string");
98
+ }
99
+ if (!Array.isArray(input.events) || input.events.length === 0) {
100
+ return invalid("empty_batch", "batch.events must be a non-empty array");
101
+ }
102
+ if (input.events.length > RUNNER_EVENT_BATCH_MAX_EVENTS) {
103
+ return invalid("batch_too_large", `batch.events has ${input.events.length} entries; max is ${RUNNER_EVENT_BATCH_MAX_EVENTS}`);
104
+ }
105
+ let lastSeq = Number.NEGATIVE_INFINITY;
106
+ let lastTMs = Number.NEGATIVE_INFINITY;
107
+ const events = [];
108
+ for (let i = 0; i < input.events.length; i++) {
109
+ const evt = input.events[i];
110
+ if (!isRecord(evt)) {
111
+ return invalid("invalid_event", `events[${i}] must be a JSON object`);
112
+ }
113
+ if (typeof evt.seq !== "number" ||
114
+ !Number.isFinite(evt.seq) ||
115
+ !Number.isInteger(evt.seq) ||
116
+ evt.seq < 0) {
117
+ return invalid("invalid_event", `events[${i}].seq must be a non-negative integer`);
118
+ }
119
+ if (typeof evt.tMs !== "number" ||
120
+ !Number.isFinite(evt.tMs) ||
121
+ !Number.isInteger(evt.tMs) ||
122
+ evt.tMs < 0) {
123
+ return invalid("invalid_event", `events[${i}].tMs must be a non-negative integer`);
124
+ }
125
+ if (typeof evt.kind !== "string" ||
126
+ !RUNNER_EVENT_KINDS.includes(evt.kind)) {
127
+ return invalid("invalid_event", `events[${i}].kind must be one of: ${RUNNER_EVENT_KINDS.join(", ")} (got ${JSON.stringify(evt.kind)})`);
128
+ }
129
+ if (!isRecord(evt.data)) {
130
+ return invalid("invalid_event", `events[${i}].data must be a JSON object`);
131
+ }
132
+ if (!isJsonRecord(evt.data)) {
133
+ return invalid("invalid_event", `events[${i}].data must be JSON-serializable`);
134
+ }
135
+ if (evt.seq <= lastSeq) {
136
+ return invalid("seq_not_monotonic", `events[${i}].seq=${evt.seq} must be strictly greater than the previous seq=${lastSeq}`);
137
+ }
138
+ if (evt.tMs < lastTMs) {
139
+ return invalid("t_ms_not_monotonic", `events[${i}].tMs=${evt.tMs} must be >= the previous tMs=${lastTMs}`);
140
+ }
141
+ lastSeq = evt.seq;
142
+ lastTMs = evt.tMs;
143
+ events.push({
144
+ seq: evt.seq,
145
+ tMs: evt.tMs,
146
+ kind: evt.kind,
147
+ data: Object.freeze({ ...evt.data })
148
+ });
149
+ }
150
+ return {
151
+ ok: true,
152
+ batch: { v: RUNNER_EVENT_VERSION, runId: input.runId, events: Object.freeze(events) }
153
+ };
154
+ }
155
+ function invalid(code, message) {
156
+ return { ok: false, code, message };
157
+ }
158
+ function isRecord(input) {
159
+ return typeof input === "object" && input !== null && !Array.isArray(input);
160
+ }
161
+ function isJsonRecord(input) {
162
+ for (const value of Object.values(input)) {
163
+ if (!isJsonValue(value))
164
+ return false;
165
+ }
166
+ return true;
167
+ }
168
+ function isJsonValue(input) {
169
+ if (input === null)
170
+ return true;
171
+ const t = typeof input;
172
+ if (t === "string" || t === "boolean")
173
+ return true;
174
+ if (t === "number")
175
+ return Number.isFinite(input);
176
+ if (Array.isArray(input))
177
+ return input.every(isJsonValue);
178
+ if (isRecord(input)) {
179
+ for (const v of Object.values(input)) {
180
+ if (!isJsonValue(v))
181
+ return false;
182
+ }
183
+ return true;
184
+ }
185
+ return false;
186
+ }
187
+ //# sourceMappingURL=runner-event.js.map
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Runtime manifest: the per-run, per-provider description of where
3
+ * aex places things inside the agent container, plus the merged
4
+ * env-var bag delivered via `RUNTIME.env` / `RUNTIME.json`.
5
+ *
6
+ * The hosted API computes a manifest at submitRun-response time
7
+ * (from the validated submission + the chosen provider) via
8
+ * {@link buildRuntimeManifest} and echoes it on the wire as
9
+ * `Run.runtimeManifest`, so caller code (anyone rendering catalog markdown
10
+ * pre-submission, or resolving aex's in-container path strings) doesn't
11
+ * have to guess.
12
+ * The managed runtime materialises the actual `RUNTIME.env` / `RUNTIME.json`
13
+ * files in-container from the same provider + envVars inputs, so the
14
+ * SDK-side view and the in-container view describe the same layout.
15
+ *
16
+ * Manifest values are derived, never persisted separately — the source
17
+ * of truth for the customer half remains `submission.environment.envVars`
18
+ * on the run row; the aex half is constant for a given
19
+ * provider+SDK-version pair.
20
+ */
21
+ /**
22
+ * Set of providers whose runtime contract aex models. Today only
23
+ * `"anthropic"` ships; the field is on the manifest so forward-compat
24
+ * consumers can branch on it without us having to silently change
25
+ * what `runtimeManifest` means when we add a second provider.
26
+ */
27
+ export type RuntimeProvider = "anthropic";
28
+ /**
29
+ * The in-container paths the agent and skill code reference at
30
+ * runtime. All fields are absolute, all reflect Anthropic Managed
31
+ * Agents' session-mount rebase rule (every `mount_path` lands under
32
+ * `/mnt/session/uploads/` regardless of the leading slash).
33
+ *
34
+ * `skillsRoot` is the location of Skills API-registered bundles, which
35
+ * the runtime auto-discovers under `/workspace/skills/<name>/` —
36
+ * empirically a separate root from the session-resource mounts, NOT
37
+ * under `/mnt/session/uploads/`.
38
+ */
39
+ export interface RuntimeManifest {
40
+ readonly provider: RuntimeProvider;
41
+ /** Where Skills-API-registered bundles auto-discover (Anthropic). */
42
+ readonly skillsRoot: string;
43
+ /** Parent dir of File mounts: `<filesRoot>/<f_id>/<rel-path>`. */
44
+ readonly filesRoot: string;
45
+ /** Parent dir of non-SKILL.md asset mounts: `<assetsRoot>/<skl_id>/<rel-path>`. */
46
+ readonly assetsRoot: string;
47
+ /** Absolute path of the in-container aex runtime bridge (invoke via `node`). */
48
+ readonly aexCli: string;
49
+ /** Absolute path of the per-run proxy-endpoints manifest. */
50
+ readonly indexJson: string;
51
+ /** Absolute path of the always-mounted aex runtime contract README. */
52
+ readonly readme: string;
53
+ /** Absolute path of the machine-readable manifest mirror. */
54
+ readonly runtimeJson: string;
55
+ /** Absolute path of the POSIX-shell-sourceable runtime env file. */
56
+ readonly runtimeEnv: string;
57
+ /**
58
+ * Merged env-var bag: aex-set runtime keys (with reserved
59
+ * `AEX_` prefix) plus customer-supplied `environment.envVars`.
60
+ * Both `RUNTIME.env` and `RUNTIME.json` are rendered from this
61
+ * exact map; `__KEY__` substitution in agent-facing markdown
62
+ * resolves against this exact map.
63
+ */
64
+ readonly envVars: Readonly<Record<string, string>>;
65
+ }
66
+ /**
67
+ * Managed-runner container paths. Kept here so the BFF, worker, and
68
+ * in-container bridge render identical values; runtime bootstrap constants are
69
+ * validated against these by a regression test
70
+ * (`packages/contracts/test/runtime-manifest.test.ts`).
71
+ */
72
+ declare const ANTHROPIC_PATHS: Readonly<{
73
+ readonly skillsRoot: "/workspace/skills";
74
+ readonly filesRoot: "/mnt/session/uploads/aex/files";
75
+ readonly assetsRoot: "/mnt/session/uploads/aex/assets";
76
+ readonly aexCli: "/mnt/session/uploads/aex/aex";
77
+ readonly indexJson: "/mnt/session/uploads/aex/index.json";
78
+ readonly readme: "/mnt/session/uploads/aex/SKILLS.md";
79
+ readonly runtimeJson: "/mnt/session/uploads/aex/RUNTIME.json";
80
+ readonly runtimeEnv: "/mnt/session/uploads/aex/RUNTIME.env";
81
+ }>;
82
+ /**
83
+ * Container paths exposed for a given provider. Today only
84
+ * `"anthropic"` is recognised; calling with anything else throws so
85
+ * forward-compat surfaces the missing provider entry instead of
86
+ * silently emitting Anthropic paths.
87
+ */
88
+ export declare function runtimePathsFor(provider: RuntimeProvider): typeof ANTHROPIC_PATHS;
89
+ export interface BuildRuntimeManifestInput {
90
+ readonly provider: RuntimeProvider;
91
+ /**
92
+ * Customer-supplied `environment.envVars` from the validated
93
+ * submission. Keys with the reserved `AEX_` prefix are
94
+ * filtered out defensively — the strict submission parser already
95
+ * rejects them, but defence-in-depth means a malformed snapshot
96
+ * (or a future bypass) can't poison the manifest.
97
+ */
98
+ readonly customerEnvVars?: Readonly<Record<string, string>> | undefined;
99
+ }
100
+ /**
101
+ * Build the runtime manifest for a single submission. Pure function:
102
+ * same input → same output → safe to call from the BFF response path
103
+ * and from the worker bootstrap path with identical results.
104
+ */
105
+ export declare function buildRuntimeManifest(input: BuildRuntimeManifestInput): RuntimeManifest;
106
+ export {};