@opengeni/sdk 0.46.0 → 0.48.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.
- package/README.md +1 -1
- package/dist/{chunk-QKV5OCLJ.js → chunk-MBGBLVUV.js} +346 -72
- package/dist/chunk-MBGBLVUV.js.map +1 -0
- package/dist/client.d.ts +27 -5
- package/dist/core.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/stream.d.ts +15 -0
- package/dist/transcription.d.ts +2 -2
- package/dist/types.d.ts +80 -10
- package/dist/workspace-control-stream.d.ts +1 -1
- package/package.json +1 -1
- package/src/client.ts +344 -60
- package/src/index.ts +9 -0
- package/src/stream.ts +102 -4
- package/src/transcription.ts +2 -2
- package/src/types.ts +89 -7
- package/src/workspace-control-stream.ts +15 -5
- package/dist/chunk-QKV5OCLJ.js.map +0 -1
package/src/stream.ts
CHANGED
|
@@ -29,13 +29,25 @@ export type StreamSessionEventsOptions = {
|
|
|
29
29
|
reconnectDelayMs?: number;
|
|
30
30
|
/** Backoff ceiling. Defaults to 10s. */
|
|
31
31
|
maxReconnectDelayMs?: number;
|
|
32
|
+
/** Random backoff spread as a fraction of the delay. Defaults to 0.2. */
|
|
33
|
+
reconnectJitterRatio?: number;
|
|
32
34
|
/**
|
|
33
35
|
* Give up after this many consecutive failed reconnect attempts (i.e. N
|
|
34
36
|
* reconnects = N+1 total open-stream calls). Defaults to unlimited.
|
|
35
37
|
*/
|
|
36
38
|
maxReconnectAttempts?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Notify the consumer as soon as the SSE response body is open. This callback
|
|
41
|
+
* is deliberately synchronous and non-blocking: use it to start projection
|
|
42
|
+
* reconciliation without delaying consumption of live event bytes.
|
|
43
|
+
*/
|
|
44
|
+
onOpen?: (() => void) | undefined;
|
|
37
45
|
/** Await authoritative client reconciliation before exposing `live`. */
|
|
38
46
|
beforeLive?: (() => void | Promise<void>) | undefined;
|
|
47
|
+
/** Maximum reconciliation time before reconnecting. Defaults to 15s. */
|
|
48
|
+
beforeLiveTimeoutMs?: number;
|
|
49
|
+
/** Maximum time without any SSE bytes before reconnecting. Defaults to 45s. */
|
|
50
|
+
heartbeatTimeoutMs?: number;
|
|
39
51
|
onStateChange?: (state: StreamConnectionState) => void;
|
|
40
52
|
};
|
|
41
53
|
|
|
@@ -62,6 +74,9 @@ export async function* streamSessionEvents(
|
|
|
62
74
|
const reconnect = options.reconnect ?? true;
|
|
63
75
|
const baseDelayMs = options.reconnectDelayMs ?? 500;
|
|
64
76
|
const maxDelayMs = options.maxReconnectDelayMs ?? 10_000;
|
|
77
|
+
const jitterRatio = options.reconnectJitterRatio ?? 0.2;
|
|
78
|
+
const beforeLiveTimeoutMs = options.beforeLiveTimeoutMs ?? 15_000;
|
|
79
|
+
const heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? 45_000;
|
|
65
80
|
const maxAttempts = options.maxReconnectAttempts ?? Number.POSITIVE_INFINITY;
|
|
66
81
|
let cursor = options.after ?? 0;
|
|
67
82
|
let failedAttempts = 0;
|
|
@@ -77,9 +92,16 @@ export async function* streamSessionEvents(
|
|
|
77
92
|
everConnected = true;
|
|
78
93
|
failedAttempts = 0;
|
|
79
94
|
delayMs = baseDelayMs;
|
|
80
|
-
|
|
95
|
+
try {
|
|
96
|
+
options.onOpen?.();
|
|
97
|
+
} catch {
|
|
98
|
+
// A notification observer cannot own or interrupt the event transport.
|
|
99
|
+
}
|
|
100
|
+
await runBeforeLive(options.beforeLive, beforeLiveTimeoutMs, signal);
|
|
81
101
|
options.onStateChange?.("live");
|
|
82
|
-
for await (const message of parseSseStream(
|
|
102
|
+
for await (const message of parseSseStream(
|
|
103
|
+
withStreamInactivityTimeout(body, heartbeatTimeoutMs, signal),
|
|
104
|
+
)) {
|
|
83
105
|
// Re-check after every yield resumption: an abort from the consumer
|
|
84
106
|
// must not let already-buffered events keep flowing.
|
|
85
107
|
if (signal?.aborted) {
|
|
@@ -108,7 +130,7 @@ export async function* streamSessionEvents(
|
|
|
108
130
|
// progress (servers legitimately cycle long SSE connections); pace
|
|
109
131
|
// empty closes so a misbehaving server is not hammered in a hot loop.
|
|
110
132
|
if (cursor === cursorAtOpen) {
|
|
111
|
-
await sleep(baseDelayMs, signal);
|
|
133
|
+
await sleep(jitteredDelay(baseDelayMs, jitterRatio), signal);
|
|
112
134
|
}
|
|
113
135
|
continue;
|
|
114
136
|
} catch (error) {
|
|
@@ -125,11 +147,87 @@ export async function* streamSessionEvents(
|
|
|
125
147
|
);
|
|
126
148
|
}
|
|
127
149
|
}
|
|
128
|
-
await sleep(delayMs, signal);
|
|
150
|
+
await sleep(jitteredDelay(delayMs, jitterRatio), signal);
|
|
129
151
|
delayMs = Math.min(Math.max(delayMs * 2, baseDelayMs), maxDelayMs);
|
|
130
152
|
}
|
|
131
153
|
}
|
|
132
154
|
|
|
155
|
+
export async function runBeforeLive(
|
|
156
|
+
beforeLive: (() => void | Promise<void>) | undefined,
|
|
157
|
+
timeoutMs: number,
|
|
158
|
+
signal: AbortSignal | undefined,
|
|
159
|
+
): Promise<void> {
|
|
160
|
+
if (!beforeLive) return;
|
|
161
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
162
|
+
let abortListener: (() => void) | undefined;
|
|
163
|
+
const timeout = new Promise<never>((_resolve, reject) => {
|
|
164
|
+
timer = setTimeout(
|
|
165
|
+
() => reject(new TypeError(`stream reconciliation timed out after ${timeoutMs}ms`)),
|
|
166
|
+
timeoutMs,
|
|
167
|
+
);
|
|
168
|
+
if (signal) {
|
|
169
|
+
abortListener = () => reject(new DOMException("Aborted", "AbortError"));
|
|
170
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
try {
|
|
174
|
+
await Promise.race([Promise.resolve().then(beforeLive), timeout]);
|
|
175
|
+
} finally {
|
|
176
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
177
|
+
if (signal && abortListener) signal.removeEventListener("abort", abortListener);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function jitteredDelay(delayMs: number, ratio: number): number {
|
|
182
|
+
if (delayMs <= 0 || ratio <= 0) return delayMs;
|
|
183
|
+
const boundedRatio = Math.min(ratio, 1);
|
|
184
|
+
const spread = delayMs * boundedRatio;
|
|
185
|
+
return Math.max(0, delayMs - spread + Math.random() * spread * 2);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function withStreamInactivityTimeout(
|
|
189
|
+
stream: ReadableStream<Uint8Array>,
|
|
190
|
+
timeoutMs: number,
|
|
191
|
+
signal: AbortSignal | undefined,
|
|
192
|
+
): ReadableStream<Uint8Array> {
|
|
193
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0) {
|
|
194
|
+
throw new RangeError("stream heartbeat timeout must be a positive safe integer");
|
|
195
|
+
}
|
|
196
|
+
const reader = stream.getReader();
|
|
197
|
+
return new ReadableStream<Uint8Array>({
|
|
198
|
+
pull: async (controller) => {
|
|
199
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
200
|
+
let abortListener: (() => void) | undefined;
|
|
201
|
+
try {
|
|
202
|
+
const result = await Promise.race([
|
|
203
|
+
reader.read(),
|
|
204
|
+
new Promise<never>((_resolve, reject) => {
|
|
205
|
+
timer = setTimeout(
|
|
206
|
+
() => reject(new TypeError(`event stream heartbeat timed out after ${timeoutMs}ms`)),
|
|
207
|
+
timeoutMs,
|
|
208
|
+
);
|
|
209
|
+
if (signal) {
|
|
210
|
+
abortListener = () => reject(new DOMException("Aborted", "AbortError"));
|
|
211
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
212
|
+
}
|
|
213
|
+
}),
|
|
214
|
+
]);
|
|
215
|
+
if (result.done) controller.close();
|
|
216
|
+
else controller.enqueue(result.value);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
void reader.cancel(error).catch(() => {});
|
|
219
|
+
controller.error(error);
|
|
220
|
+
} finally {
|
|
221
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
222
|
+
if (signal && abortListener) signal.removeEventListener("abort", abortListener);
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
cancel: async (reason) => {
|
|
226
|
+
await reader.cancel(reason);
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
133
231
|
/**
|
|
134
232
|
* Yield the durable events with `fromExclusive < sequence <= toInclusive`,
|
|
135
233
|
* in order. Sequences are contiguous, so every one of them must exist in the
|
package/src/transcription.ts
CHANGED
|
@@ -159,7 +159,7 @@ export type TranscriptionResultMetadata = {
|
|
|
159
159
|
export type TranscriptionDiagnostic = {
|
|
160
160
|
operation: "start" | "session" | "cancel" | "close";
|
|
161
161
|
code: TranscriptionErrorCode;
|
|
162
|
-
/**
|
|
162
|
+
/** Exact diagnostic detail forwarded by React without content rewriting. */
|
|
163
163
|
detail: string;
|
|
164
164
|
};
|
|
165
165
|
|
|
@@ -231,7 +231,7 @@ export type TranscriptionEventListener = (event: TranscriptionEvent) => void;
|
|
|
231
231
|
export type TranscriptionAdapterStartContext = {
|
|
232
232
|
/** Aborted on local cancellation, policy replacement, timeout, or unmount. */
|
|
233
233
|
signal: AbortSignal;
|
|
234
|
-
/** Non-UI observability seam; callers receive
|
|
234
|
+
/** Non-UI observability seam; callers receive the exact provider detail. */
|
|
235
235
|
reportDiagnostic: (diagnostic: TranscriptionDiagnostic) => void;
|
|
236
236
|
};
|
|
237
237
|
|
package/src/types.ts
CHANGED
|
@@ -1587,6 +1587,8 @@ export type FsListResponse = {
|
|
|
1587
1587
|
revision: number;
|
|
1588
1588
|
truncated: boolean;
|
|
1589
1589
|
};
|
|
1590
|
+
export type FsListBatchRequest = { requests: FsListRequest[] };
|
|
1591
|
+
export type FsListBatchResponse = { results: FsListResponse[] };
|
|
1590
1592
|
export type FsReadRequest = {
|
|
1591
1593
|
path: string;
|
|
1592
1594
|
encoding?: FsEncoding;
|
|
@@ -1695,6 +1697,16 @@ export type GitDiffRequest = {
|
|
|
1695
1697
|
maxBytesPerFile?: number;
|
|
1696
1698
|
};
|
|
1697
1699
|
export type GitDiffResponse = { files: GitFileDiff[]; revision: number };
|
|
1700
|
+
export type GitReadBatchItemRequest = {
|
|
1701
|
+
status: GitStatusRequest;
|
|
1702
|
+
diff?: GitDiffRequest;
|
|
1703
|
+
};
|
|
1704
|
+
export type GitReadBatchRequest = { requests: GitReadBatchItemRequest[] };
|
|
1705
|
+
export type GitReadBatchItemResponse = {
|
|
1706
|
+
status: GitStatusResponse;
|
|
1707
|
+
diff?: GitDiffResponse;
|
|
1708
|
+
};
|
|
1709
|
+
export type GitReadBatchResponse = { results: GitReadBatchItemResponse[] };
|
|
1698
1710
|
export type GitLogRequest = {
|
|
1699
1711
|
path?: string;
|
|
1700
1712
|
ref?: string;
|
|
@@ -1755,6 +1767,9 @@ export type WorkspaceCaptureRepo = {
|
|
|
1755
1767
|
behind: number;
|
|
1756
1768
|
status: GitFileStatus[];
|
|
1757
1769
|
diff: GitFileDiff[];
|
|
1770
|
+
/** Current branch vs the remote default branch. Absent on legacy captures or
|
|
1771
|
+
* repositories whose remote default ref could not be resolved. */
|
|
1772
|
+
branchDiff?: GitFileDiff[] | undefined;
|
|
1758
1773
|
};
|
|
1759
1774
|
export type WorkspaceCaptureDegradedReason =
|
|
1760
1775
|
| "repository_discovery_command_failed"
|
|
@@ -1875,7 +1890,7 @@ export type SessionStructuredCapabilities = {
|
|
|
1875
1890
|
|
|
1876
1891
|
export type ScheduledTaskStatus = "active" | "paused";
|
|
1877
1892
|
|
|
1878
|
-
export type ScheduledTaskRunMode = "new_session_per_run" | "reusable_session";
|
|
1893
|
+
export type ScheduledTaskRunMode = "new_session_per_run" | "reusable_session" | "existing_session";
|
|
1879
1894
|
|
|
1880
1895
|
export type ScheduledTaskOverlapPolicy = "allow_concurrent" | "skip" | "buffer_one";
|
|
1881
1896
|
|
|
@@ -1931,6 +1946,7 @@ export type ScheduledTask = {
|
|
|
1931
1946
|
createdBy?: TurnInitiator | undefined;
|
|
1932
1947
|
createdByContext?: TurnInitiatorContext | undefined;
|
|
1933
1948
|
personalConnections?: McpPersonalConnectionSummary[] | undefined;
|
|
1949
|
+
targetSessionId: string | null;
|
|
1934
1950
|
reusableSessionId: string | null;
|
|
1935
1951
|
variableSetId: string | null;
|
|
1936
1952
|
/** @deprecated use variableSetId */
|
|
@@ -2038,8 +2054,14 @@ export const KNOWN_PERMISSIONS = [
|
|
|
2038
2054
|
"connections:write",
|
|
2039
2055
|
"environments:manage",
|
|
2040
2056
|
"environments:use",
|
|
2057
|
+
"variable-sets:list",
|
|
2058
|
+
"variable-sets:read",
|
|
2059
|
+
"variable-sets:write",
|
|
2041
2060
|
"variable-sets:manage",
|
|
2042
2061
|
"variable-sets:use",
|
|
2062
|
+
"secrets:list",
|
|
2063
|
+
"secrets:read",
|
|
2064
|
+
"secrets:write",
|
|
2043
2065
|
"mcp_servers:attach",
|
|
2044
2066
|
"toolspace:call",
|
|
2045
2067
|
"goals:manage",
|
|
@@ -2075,6 +2097,8 @@ export type FirstPartyMcpToolName =
|
|
|
2075
2097
|
| "sandbox_swap"
|
|
2076
2098
|
| "run_on"
|
|
2077
2099
|
| "sandbox_provision"
|
|
2100
|
+
| "connected_machine_remove"
|
|
2101
|
+
| "connected_machine_remove"
|
|
2078
2102
|
| "rig_list"
|
|
2079
2103
|
| "rig_get"
|
|
2080
2104
|
| "rig_propose_change"
|
|
@@ -2091,6 +2115,7 @@ export type FirstPartyMcpToolName =
|
|
|
2091
2115
|
| "set_other_session_title"
|
|
2092
2116
|
| "variable_set_list"
|
|
2093
2117
|
| "environment_list"
|
|
2118
|
+
| "variable_set_get_variable"
|
|
2094
2119
|
| "variable_set_set_variable"
|
|
2095
2120
|
| "environment_set_variable"
|
|
2096
2121
|
| "github_connect_link"
|
|
@@ -2736,6 +2761,8 @@ export type WorkspaceSettings = {
|
|
|
2736
2761
|
maxNestedAgentDepth?: number | null | undefined;
|
|
2737
2762
|
/** Default for new Codex sessions; absent ⇒ remote_v2. */
|
|
2738
2763
|
codexCompactionDefault?: "remote_v2" | "portable" | undefined;
|
|
2764
|
+
/** Whether agents may invoke the built-in structured human-input tool. */
|
|
2765
|
+
agentHumanInputEnabled?: boolean | undefined;
|
|
2739
2766
|
slackReactionSummon?: WorkspaceSlackReactionSummonSettings | undefined;
|
|
2740
2767
|
[key: string]: unknown;
|
|
2741
2768
|
};
|
|
@@ -2767,6 +2794,7 @@ export type UpdateWorkspaceSettingsRequest = {
|
|
|
2767
2794
|
transcription?: WorkspaceTranscriptionPolicy | undefined;
|
|
2768
2795
|
maxNestedAgentDepth?: number | null | undefined;
|
|
2769
2796
|
codexCompactionDefault?: "remote_v2" | "portable" | undefined;
|
|
2797
|
+
agentHumanInputEnabled?: boolean | undefined;
|
|
2770
2798
|
slackReactionSummon?: WorkspaceSlackReactionSummonSettings | undefined;
|
|
2771
2799
|
[key: string]: unknown;
|
|
2772
2800
|
};
|
|
@@ -3179,6 +3207,7 @@ export type CreateScheduledTaskRequest = {
|
|
|
3179
3207
|
name: string;
|
|
3180
3208
|
schedule: ScheduledTaskScheduleSpec;
|
|
3181
3209
|
runMode?: ScheduledTaskRunMode | undefined;
|
|
3210
|
+
targetSessionId?: string | null | undefined;
|
|
3182
3211
|
overlapPolicy?: ScheduledTaskOverlapPolicy | undefined;
|
|
3183
3212
|
agentConfig: ScheduledTaskAgentConfigInput;
|
|
3184
3213
|
status?: ScheduledTaskStatus | undefined;
|
|
@@ -3194,6 +3223,7 @@ export type UpdateScheduledTaskRequest = {
|
|
|
3194
3223
|
name?: string | undefined;
|
|
3195
3224
|
schedule?: ScheduledTaskScheduleSpec | undefined;
|
|
3196
3225
|
runMode?: ScheduledTaskRunMode | undefined;
|
|
3226
|
+
targetSessionId?: string | null | undefined;
|
|
3197
3227
|
overlapPolicy?: ScheduledTaskOverlapPolicy | undefined;
|
|
3198
3228
|
agentConfig?: ScheduledTaskAgentConfigInput | undefined;
|
|
3199
3229
|
status?: ScheduledTaskStatus | undefined;
|
|
@@ -3227,11 +3257,7 @@ export type ScheduledTaskRun = {
|
|
|
3227
3257
|
|
|
3228
3258
|
// --- VariableSets -------------------------------------------------------------
|
|
3229
3259
|
|
|
3230
|
-
/**
|
|
3231
|
-
* Variable values are write-only by design: the API never returns a value, so
|
|
3232
|
-
* reads expose name + version metadata only. Values are decrypted exclusively
|
|
3233
|
-
* inside the worker at sandbox materialization time.
|
|
3234
|
-
*/
|
|
3260
|
+
/** Generic variable-set reads expose name + version metadata only. */
|
|
3235
3261
|
export type VariableSetVariableMetadata = {
|
|
3236
3262
|
name: string;
|
|
3237
3263
|
version: number;
|
|
@@ -3239,6 +3265,14 @@ export type VariableSetVariableMetadata = {
|
|
|
3239
3265
|
updatedAt: string;
|
|
3240
3266
|
};
|
|
3241
3267
|
|
|
3268
|
+
/** Dedicated permissioned plaintext response; never embedded in metadata reads. */
|
|
3269
|
+
export type VariableSetSecret = {
|
|
3270
|
+
variableSetId: string;
|
|
3271
|
+
name: string;
|
|
3272
|
+
version: number;
|
|
3273
|
+
value: string;
|
|
3274
|
+
};
|
|
3275
|
+
|
|
3242
3276
|
export type VariableSet = {
|
|
3243
3277
|
id: string;
|
|
3244
3278
|
accountId: string;
|
|
@@ -3412,12 +3446,14 @@ export type FileAsset = {
|
|
|
3412
3446
|
/** Mirrors the closed, provider-neutral retained-output contract. */
|
|
3413
3447
|
export const RETAINED_OUTPUT_DEFAULT_PAGE_BYTES = 256 * 1024;
|
|
3414
3448
|
export const RETAINED_OUTPUT_MAX_PAGE_BYTES = 1024 * 1024;
|
|
3449
|
+
export const COMPUTER_SCREENSHOT_MAX_BYTES = 32 * 1024 * 1024;
|
|
3415
3450
|
|
|
3416
3451
|
export type RetainedOutputKind =
|
|
3417
3452
|
| "tool_result"
|
|
3418
3453
|
| "assistant_completion"
|
|
3419
3454
|
| "internal_update"
|
|
3420
3455
|
| "event_media"
|
|
3456
|
+
| "computer_screenshot"
|
|
3421
3457
|
| "file";
|
|
3422
3458
|
|
|
3423
3459
|
export type RetainedOutputUnavailableReason =
|
|
@@ -3428,6 +3464,9 @@ export type RetainedOutputUnavailableReason =
|
|
|
3428
3464
|
| "deleted"
|
|
3429
3465
|
| "missing_storage"
|
|
3430
3466
|
| "storage_write_failed"
|
|
3467
|
+
| "quota_exceeded"
|
|
3468
|
+
| "invalid_content"
|
|
3469
|
+
| "oversized"
|
|
3431
3470
|
| "unsupported";
|
|
3432
3471
|
|
|
3433
3472
|
export type RetainedArtifactReference = {
|
|
@@ -3438,7 +3477,10 @@ export type RetainedArtifactReference = {
|
|
|
3438
3477
|
originalBytes: number;
|
|
3439
3478
|
sha256: string;
|
|
3440
3479
|
retainedAt: string;
|
|
3441
|
-
|
|
3480
|
+
dimensions?: { width: number; height: number } | undefined;
|
|
3481
|
+
retention:
|
|
3482
|
+
| { policy: "workspace_file"; expiresAt: null }
|
|
3483
|
+
| { policy: "session_screenshot"; expiresAt: string };
|
|
3442
3484
|
retrieval: {
|
|
3443
3485
|
method: "GET";
|
|
3444
3486
|
path: string;
|
|
@@ -3470,6 +3512,18 @@ export type RetainedArtifactContent = {
|
|
|
3470
3512
|
acceptRanges: "bytes";
|
|
3471
3513
|
};
|
|
3472
3514
|
|
|
3515
|
+
export type RetainedScreenshotDownloadOptions = {
|
|
3516
|
+
signal?: AbortSignal | undefined;
|
|
3517
|
+
/** Retry transient range failures; bounded to 0..3, default 2. */
|
|
3518
|
+
maxRetries?: number | undefined;
|
|
3519
|
+
};
|
|
3520
|
+
|
|
3521
|
+
export type RetainedScreenshotDownload = {
|
|
3522
|
+
metadata: RetainedArtifactMetadata;
|
|
3523
|
+
/** Null when metadata truth says the screenshot is unavailable. */
|
|
3524
|
+
bytes: Uint8Array | null;
|
|
3525
|
+
};
|
|
3526
|
+
|
|
3473
3527
|
export type CreateFileUploadRequest = {
|
|
3474
3528
|
filename: string;
|
|
3475
3529
|
contentType: string;
|
|
@@ -3505,6 +3559,8 @@ export type UploadFileInput = {
|
|
|
3505
3559
|
contentType: string;
|
|
3506
3560
|
data: FileUploadData;
|
|
3507
3561
|
sha256?: string | undefined;
|
|
3562
|
+
/** Optional deadline for the signed object-storage PUT. */
|
|
3563
|
+
timeoutMs?: number | undefined;
|
|
3508
3564
|
};
|
|
3509
3565
|
|
|
3510
3566
|
// --- Documents -------------------------------------------------------------------
|
|
@@ -4478,6 +4534,32 @@ export type MachineMetricsSeriesResponse = {
|
|
|
4478
4534
|
samples: MetricSample[];
|
|
4479
4535
|
};
|
|
4480
4536
|
|
|
4537
|
+
/** POST /v1/workspaces/:ws/enrollments/:id/revoke body. */
|
|
4538
|
+
export type RemoveEnrollmentRequest = {
|
|
4539
|
+
expectedUpdatedAt?: string;
|
|
4540
|
+
idempotencyKey?: string;
|
|
4541
|
+
};
|
|
4542
|
+
|
|
4543
|
+
/** Typed removal/revocation outcome. Blocked outcomes preserve the exact
|
|
4544
|
+
* dependency and the action needed to make removal safe. */
|
|
4545
|
+
export type RemoveEnrollmentResponse = {
|
|
4546
|
+
revoked: boolean;
|
|
4547
|
+
outcome: "removed" | "already_removed" | "blocked";
|
|
4548
|
+
enrollmentId: string;
|
|
4549
|
+
machineName: string | null;
|
|
4550
|
+
lastSeenAt: string | null;
|
|
4551
|
+
revokedAt: string | null;
|
|
4552
|
+
code:
|
|
4553
|
+
| "active_route"
|
|
4554
|
+
| "active_commands"
|
|
4555
|
+
| "active_lease"
|
|
4556
|
+
| "recovery_pending"
|
|
4557
|
+
| "not_selfhosted"
|
|
4558
|
+
| null;
|
|
4559
|
+
message: string;
|
|
4560
|
+
action: string;
|
|
4561
|
+
};
|
|
4562
|
+
|
|
4481
4563
|
/** POST /v1/workspaces/:ws/sessions/:sessionId/active-sandbox — swap a session's
|
|
4482
4564
|
* active sandbox. `target` is a `MachineView.sandboxId`, or "session"/"default"
|
|
4483
4565
|
* to swap back to the session's own group box. */
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { isAbortError, isRetryableStreamError, OpenGeniStreamError } from "./errors";
|
|
2
2
|
import { parseSseStream } from "./sse";
|
|
3
|
-
import
|
|
3
|
+
import {
|
|
4
|
+
jitteredDelay,
|
|
5
|
+
runBeforeLive,
|
|
6
|
+
type StreamSessionEventsOptions,
|
|
7
|
+
withStreamInactivityTimeout,
|
|
8
|
+
} from "./stream";
|
|
4
9
|
import type { WorkspaceControlEvent } from "./types";
|
|
5
10
|
|
|
6
11
|
export type WorkspaceControlStreamTransport = {
|
|
@@ -24,6 +29,9 @@ export async function* streamWorkspaceControlEvents(
|
|
|
24
29
|
const reconnect = options.reconnect ?? true;
|
|
25
30
|
const baseDelayMs = options.reconnectDelayMs ?? 500;
|
|
26
31
|
const maxDelayMs = options.maxReconnectDelayMs ?? 10_000;
|
|
32
|
+
const jitterRatio = options.reconnectJitterRatio ?? 0.2;
|
|
33
|
+
const beforeLiveTimeoutMs = options.beforeLiveTimeoutMs ?? 15_000;
|
|
34
|
+
const heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? 45_000;
|
|
27
35
|
const maxAttempts = options.maxReconnectAttempts ?? Number.POSITIVE_INFINITY;
|
|
28
36
|
let cursor = options.after ?? 0;
|
|
29
37
|
let failures = 0;
|
|
@@ -39,9 +47,11 @@ export async function* streamWorkspaceControlEvents(
|
|
|
39
47
|
everConnected = true;
|
|
40
48
|
failures = 0;
|
|
41
49
|
delayMs = baseDelayMs;
|
|
42
|
-
await options.beforeLive
|
|
50
|
+
await runBeforeLive(options.beforeLive, beforeLiveTimeoutMs, signal);
|
|
43
51
|
options.onStateChange?.("live");
|
|
44
|
-
for await (const message of parseSseStream(
|
|
52
|
+
for await (const message of parseSseStream(
|
|
53
|
+
withStreamInactivityTimeout(body, heartbeatTimeoutMs, signal),
|
|
54
|
+
)) {
|
|
45
55
|
if (signal?.aborted) return;
|
|
46
56
|
const event = parseWorkspaceControlEvent(message.data);
|
|
47
57
|
if (!event || event.sequence <= cursor) continue;
|
|
@@ -49,7 +59,7 @@ export async function* streamWorkspaceControlEvents(
|
|
|
49
59
|
yield event;
|
|
50
60
|
}
|
|
51
61
|
if (!reconnect) return;
|
|
52
|
-
if (cursor === cursorAtOpen) await sleep(baseDelayMs, signal);
|
|
62
|
+
if (cursor === cursorAtOpen) await sleep(jitteredDelay(baseDelayMs, jitterRatio), signal);
|
|
53
63
|
continue;
|
|
54
64
|
} catch (error) {
|
|
55
65
|
if (signal?.aborted || isAbortError(error)) return;
|
|
@@ -63,7 +73,7 @@ export async function* streamWorkspaceControlEvents(
|
|
|
63
73
|
);
|
|
64
74
|
}
|
|
65
75
|
}
|
|
66
|
-
await sleep(delayMs, signal);
|
|
76
|
+
await sleep(jitteredDelay(delayMs, jitterRatio), signal);
|
|
67
77
|
delayMs = Math.min(Math.max(delayMs * 2, baseDelayMs), maxDelayMs);
|
|
68
78
|
}
|
|
69
79
|
}
|