@tangle-network/sandbox 0.60.16-develop.20261006041203.03ae563 → 0.60.16-develop.20261006051703.cde74c0

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.
@@ -181,6 +181,66 @@ interface SessionSummaryList {
181
181
  items: SessionSummary[];
182
182
  nextCursor: string | null;
183
183
  }
184
+ /**
185
+ * One agent session file the platform captured from a cloud sandbox of a run
186
+ * (`GET /v1/run-sessions/{runId}`). Files outlive the sandbox; the stored
187
+ * bytes are redacted, and `sourceSha256` names the bytes as captured.
188
+ */
189
+ interface RunSessionFile {
190
+ runId: string;
191
+ sandboxId: string;
192
+ /** The sidecar session the file was captured from. */
193
+ sessionId: string;
194
+ /** `native/<executionId>/<attempt>/<storePath>`, `events/<executionId>.ndjson` or `capture.json`. */
195
+ path: string;
196
+ harness: string | null;
197
+ format: string | null;
198
+ contentType: string;
199
+ /** `withheld`: captured but not stored (`unscannable_binary` or `too_large`). */
200
+ state: "stored" | "withheld";
201
+ withheldReason: string | null;
202
+ sourceSha256: string;
203
+ sourceBytes: number;
204
+ storedSha256: string | null;
205
+ storedBytes: number | null;
206
+ redactionVersion: string | null;
207
+ redactionCount: number | null;
208
+ updatedAt: string;
209
+ }
210
+ /** The final capture of one sandbox, sealed before the sandbox was deleted. */
211
+ interface RunSessionSeal {
212
+ runId: string;
213
+ sandboxId: string;
214
+ /** Whether the sandbox was running when its final capture was taken. */
215
+ runtime: "running" | "not_running";
216
+ /** True when the final capture named no gap. */
217
+ complete: boolean;
218
+ missing: string[];
219
+ storedFiles: number;
220
+ withheldFiles: number;
221
+ storedBytes: number;
222
+ workspaceSnapshot: string | null;
223
+ sealedAt: string;
224
+ }
225
+ /**
226
+ * One page of a run's captured files (`GET /v1/run-sessions/{runId}`), in
227
+ * sandbox, session and path order. Every sandbox's seal comes with the first
228
+ * page; later pages carry an empty `seals`.
229
+ */
230
+ interface RunSessionList {
231
+ runId: string;
232
+ files: RunSessionFile[];
233
+ seals: RunSessionSeal[];
234
+ /** Pass as `cursor` for the next page; null on the last page. */
235
+ nextCursor: string | null;
236
+ }
237
+ /** Query params for {@link IntelligenceClient.listRunSessionFiles}. */
238
+ interface ListRunSessionFilesParams {
239
+ /** Files per page, clamped server-side to `[1, 5000]` (default 1000). */
240
+ limit?: number;
241
+ /** Opaque cursor from the prior page's `nextCursor`. */
242
+ cursor?: string;
243
+ }
184
244
  /** Query params for {@link IntelligenceClient.listTraces}. */
185
245
  interface ListTracesParams {
186
246
  /** Page size, clamped server-side to `[1, 200]` (default 50). */
@@ -260,6 +320,20 @@ interface IntelligenceClient {
260
320
  getRun(runId: string): Promise<Run>;
261
321
  /** List the spans pivoted to this run (by `run_id`), bounded window. */
262
322
  getRunTraces(runId: string): Promise<RunSpanWindow>;
323
+ /**
324
+ * List one page of the agent session files the platform captured from this
325
+ * run's cloud sandboxes; the first page also carries each sandbox's final
326
+ * seal. A run is the sandbox's create `metadata.run`, or the sandbox id when
327
+ * the sandbox named no run.
328
+ */
329
+ listRunSessionFiles(runId: string, params?: ListRunSessionFilesParams): Promise<RunSessionList>;
330
+ /**
331
+ * Async iterator over every captured file of a run, following `nextCursor`
332
+ * page by page. Seals are on the first page of {@link listRunSessionFiles}.
333
+ */
334
+ iterateRunSessionFiles(runId: string, params?: ListRunSessionFilesParams): AsyncGenerator<RunSessionFile, void, unknown>;
335
+ /** Download one captured file's stored (redacted) bytes. */
336
+ downloadRunSessionFile(runId: string, file: Pick<RunSessionFile, "sandboxId" | "sessionId" | "path">): Promise<Uint8Array>;
263
337
  /** List tenant-wide session summaries (one row per session), newest first. */
264
338
  listSessions(params?: ListSessionsParams): Promise<SessionSummaryList>;
265
339
  /** List one session's traces as the trace-summary shape, keyset-paginated. */
@@ -289,4 +363,4 @@ interface IntelligenceClient {
289
363
  */
290
364
  declare function createIntelligenceClient(config: IntelligenceClientConfig): IntelligenceClient;
291
365
  //#endregion
292
- export { DEFAULT_INTELLIGENCE_BASE_URL, GetSessionTracesParams, GetTraceSpansParams, IntelligenceClient, IntelligenceClientConfig, ListRunsParams, ListSessionsParams, ListTracesParams, NanoString, Run, RunList, RunSpanWindow, SerializedSpan, SessionSummary, SessionSummaryList, SpanPage, TraceStatus, TraceSummary, TraceSummaryList, createIntelligenceClient };
366
+ export { DEFAULT_INTELLIGENCE_BASE_URL, GetSessionTracesParams, GetTraceSpansParams, IntelligenceClient, IntelligenceClientConfig, ListRunSessionFilesParams, ListRunsParams, ListSessionsParams, ListTracesParams, NanoString, Run, RunList, RunSessionFile, RunSessionList, RunSessionSeal, RunSpanWindow, SerializedSpan, SessionSummary, SessionSummaryList, SpanPage, TraceStatus, TraceSummary, TraceSummaryList, createIntelligenceClient };
@@ -67,37 +67,51 @@ function createIntelligenceClient(config) {
67
67
  * an `AbortController` timeout that surfaces as `TimeoutError`, and a
68
68
  * transport failure wrapped as `NetworkError`. Never reuses the sandbox
69
69
  * `baseUrl` — this is the intelligence host.
70
+ *
71
+ * The timeout covers `read` as well, so a server that sends its headers
72
+ * and then stalls the body still times out. A caller that hands the body
73
+ * stream on (the NDJSON export) returns the response from `read` and owns
74
+ * the stream's pace from there.
70
75
  */
71
- async function request(path) {
76
+ async function request(path, read) {
72
77
  const url = `${baseUrl}${path}`;
73
78
  const controller = new AbortController();
74
79
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
75
80
  try {
76
- return await globalThis.fetch(url, {
77
- headers: {
78
- Authorization: `Bearer ${apiKey}`,
79
- Accept: "application/json"
80
- },
81
- signal: controller.signal
82
- });
81
+ let response;
82
+ try {
83
+ response = await globalThis.fetch(url, {
84
+ headers: {
85
+ Authorization: `Bearer ${apiKey}`,
86
+ Accept: "application/json"
87
+ },
88
+ signal: controller.signal
89
+ });
90
+ } catch (err) {
91
+ if (controller.signal.aborted || err instanceof Error && err.name === "AbortError") throw new TimeoutError(timeoutMs);
92
+ throw new NetworkError(`Failed to connect to Intelligence API: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : void 0, {
93
+ endpoint: path,
94
+ origin: "sandbox-api"
95
+ });
96
+ }
97
+ return await read(response);
83
98
  } catch (err) {
84
- if (err instanceof Error && err.name === "AbortError") throw new TimeoutError(timeoutMs);
85
- throw new NetworkError(`Failed to connect to Intelligence API: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : void 0, {
86
- endpoint: path,
87
- origin: "sandbox-api"
88
- });
99
+ if (controller.signal.aborted && !(err instanceof TimeoutError)) throw new TimeoutError(timeoutMs);
100
+ throw err;
89
101
  } finally {
90
102
  clearTimeout(timeoutId);
91
103
  }
92
104
  }
93
105
  /** GET a JSON route, raising the SDK's typed error on a non-2xx response. */
94
106
  async function getJson(path) {
95
- const response = await request(path);
96
- const body = await response.text();
97
- if (!response.ok) throw parseErrorResponse(response.status, body, {
98
- method: "GET",
99
- path
100
- }, response.headers);
107
+ const body = await request(path, async (response) => {
108
+ const text = await response.text();
109
+ if (!response.ok) throw parseErrorResponse(response.status, text, {
110
+ method: "GET",
111
+ path
112
+ }, response.headers);
113
+ return text;
114
+ });
101
115
  return JSON.parse(body);
102
116
  }
103
117
  async function listTraces(params = {}) {
@@ -121,7 +135,7 @@ function createIntelligenceClient(config) {
121
135
  }
122
136
  async function exportTraceSpansNdjson(traceId) {
123
137
  const path = `/v1/traces/${encodeURIComponent(traceId)}/spans.ndjson`;
124
- const response = await request(path);
138
+ const response = await request(path, async (served) => served);
125
139
  if (!response.ok) {
126
140
  const body = await response.text();
127
141
  throw parseErrorResponse(response.status, body, {
@@ -154,6 +168,40 @@ function createIntelligenceClient(config) {
154
168
  async function getRunTraces(runId) {
155
169
  return getJson(`/v1/runs/${encodeURIComponent(runId)}/traces`);
156
170
  }
171
+ async function listRunSessionFiles(runId, params = {}) {
172
+ const search = new URLSearchParams();
173
+ appendParam(search, "limit", params.limit);
174
+ appendParam(search, "cursor", params.cursor);
175
+ const suffix = search.size > 0 ? `?${search}` : "";
176
+ return getJson(`/v1/run-sessions/${encodeURIComponent(runId)}${suffix}`);
177
+ }
178
+ async function* iterateRunSessionFiles(runId, params = {}) {
179
+ let cursor = params.cursor;
180
+ for (;;) {
181
+ const page = await listRunSessionFiles(runId, {
182
+ ...params,
183
+ cursor
184
+ });
185
+ for (const file of page.files) yield file;
186
+ if (!page.nextCursor) return;
187
+ cursor = page.nextCursor;
188
+ }
189
+ }
190
+ async function downloadRunSessionFile(runId, file) {
191
+ const search = new URLSearchParams({
192
+ sandboxId: file.sandboxId,
193
+ sessionId: file.sessionId,
194
+ path: file.path
195
+ });
196
+ const path = `/v1/run-sessions/${encodeURIComponent(runId)}/content?${search}`;
197
+ return request(path, async (response) => {
198
+ if (!response.ok) throw parseErrorResponse(response.status, await response.text(), {
199
+ method: "GET",
200
+ path
201
+ }, response.headers);
202
+ return new Uint8Array(await response.arrayBuffer());
203
+ });
204
+ }
157
205
  async function listSessions(params = {}) {
158
206
  const search = new URLSearchParams();
159
207
  appendParam(search, "limit", params.limit);
@@ -214,6 +262,9 @@ function createIntelligenceClient(config) {
214
262
  listRuns,
215
263
  getRun,
216
264
  getRunTraces,
265
+ listRunSessionFiles,
266
+ iterateRunSessionFiles,
267
+ downloadRunSessionFile,
217
268
  listSessions,
218
269
  getSessionTraces,
219
270
  iterateTraceSpans,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox",
3
- "version": "0.60.16-develop.20261006041203.03ae563",
3
+ "version": "0.60.16-develop.20261006051703.cde74c0",
4
4
  "description": "Client SDK for the Tangle Sandbox platform - build AI agent applications with dev containers",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -151,11 +151,11 @@
151
151
  "ws": "^8.20.0",
152
152
  "yjs": "13.6.30",
153
153
  "@products/sandbox-test-utils": "0.0.0",
154
- "@repo/shared": "0.0.0",
155
- "@tangle-network/agent-profile-materialize": "0.20.9",
156
- "@tangle-network/sdk": "3.3.41",
157
154
  "@tangle-network/cli-agent-registry": "0.5.0",
155
+ "@tangle-network/agent-profile-materialize": "0.20.9",
158
156
  "@tangle-network/runtime-contracts": "0.14.0",
157
+ "@repo/shared": "0.0.0",
158
+ "@tangle-network/sdk": "3.3.41",
159
159
  "@tangle-network/sse-core": "0.0.0"
160
160
  },
161
161
  "scripts": {