@or3/intern-client 0.1.1

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/dist/index.js ADDED
@@ -0,0 +1,1362 @@
1
+ // src/redaction.ts
2
+ var REDACTED = "[REDACTED]";
3
+ function secretKey(key) {
4
+ return /^(?:authorization|proxy-authorization|cookie|set-cookie|password|passphrase|secret|api[_-]?key)$/i.test(key) || /(?:^|[_-])(?:password|passphrase|secret|token|api[_-]?key)$/i.test(key) || /(?:Password|Passphrase|Secret|Token|ApiKey)$/.test(key);
5
+ }
6
+ function replaceLiteral(value, secret) {
7
+ if (!secret)
8
+ return value;
9
+ return value.split(secret).join(REDACTED);
10
+ }
11
+ function redactString(input, explicitSecrets) {
12
+ let value = input.replace(/\bBearer\s+[^\s"',;]+/gi, `Bearer ${REDACTED}`).replace(/(["']?(?:authorization|api[_-]?key|[a-z0-9_-]*(?:password|passphrase|secret|token))["']?\s*[:=]\s*["']?)([^"',}\s&]+)/gi, `$1${REDACTED}`);
13
+ value = value.replace(/([?&])([^=&#]+)=([^&#]*)/g, (match, prefix, rawKey) => {
14
+ let key = rawKey;
15
+ try {
16
+ key = decodeURIComponent(rawKey);
17
+ } catch {}
18
+ return secretKey(key) ? `${prefix}${rawKey}=${REDACTED}` : match;
19
+ });
20
+ for (const secret of explicitSecrets) {
21
+ value = replaceLiteral(value, secret);
22
+ }
23
+ return value;
24
+ }
25
+ function redactValue(value, explicitSecrets, seen) {
26
+ if (typeof value === "string") {
27
+ return redactString(value, explicitSecrets);
28
+ }
29
+ if (value === null || value === undefined || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
30
+ return value;
31
+ }
32
+ if (value instanceof Error) {
33
+ return {
34
+ name: value.name,
35
+ message: redactString(value.message, explicitSecrets)
36
+ };
37
+ }
38
+ if (Array.isArray(value)) {
39
+ if (seen.has(value))
40
+ return "[Circular]";
41
+ seen.add(value);
42
+ return value.map((item) => redactValue(item, explicitSecrets, seen));
43
+ }
44
+ if (typeof value === "object") {
45
+ if (seen.has(value))
46
+ return "[Circular]";
47
+ seen.add(value);
48
+ const output = {};
49
+ for (const [key, item] of Object.entries(value)) {
50
+ output[key] = secretKey(key) ? REDACTED : redactValue(item, explicitSecrets, seen);
51
+ }
52
+ return output;
53
+ }
54
+ return redactString(String(value), explicitSecrets);
55
+ }
56
+ function redactInternSecrets(value, explicitSecrets = []) {
57
+ return redactValue(value, explicitSecrets.filter(Boolean), new WeakSet);
58
+ }
59
+ function safeInternStringify(value, explicitSecrets = []) {
60
+ try {
61
+ return JSON.stringify(redactInternSecrets(value, explicitSecrets));
62
+ } catch {
63
+ return '"[Unserializable]"';
64
+ }
65
+ }
66
+
67
+ // src/errors.ts
68
+ function safeCause(cause, secrets) {
69
+ if (cause === undefined)
70
+ return;
71
+ const message = cause instanceof Error ? cause.message : typeof cause === "string" ? cause : "Request failed";
72
+ const safe = new Error(String(redactInternSecrets(message, secrets)));
73
+ safe.name = cause instanceof Error ? cause.name : "Error";
74
+ return safe;
75
+ }
76
+
77
+ class InternClientError extends Error {
78
+ code;
79
+ status;
80
+ remoteCode;
81
+ requestId;
82
+ retryable;
83
+ details;
84
+ cause;
85
+ constructor(code, message, options = {}) {
86
+ const secrets = options.secrets ?? [];
87
+ super(String(redactInternSecrets(message, secrets)));
88
+ this.name = "InternClientError";
89
+ this.code = code;
90
+ this.status = options.status;
91
+ this.remoteCode = options.remoteCode;
92
+ this.requestId = options.requestId;
93
+ this.retryable = options.retryable ?? false;
94
+ this.details = options.details === undefined ? undefined : redactInternSecrets(options.details, secrets);
95
+ this.cause = safeCause(options.cause, secrets);
96
+ }
97
+ }
98
+
99
+ class InternUnavailableError extends InternClientError {
100
+ capability;
101
+ constructor(message, options = {}) {
102
+ super("unavailable", message, {
103
+ retryable: false,
104
+ ...options
105
+ });
106
+ this.name = "InternUnavailableError";
107
+ this.capability = options.capability;
108
+ }
109
+ }
110
+ function internOk(value) {
111
+ return { ok: true, value };
112
+ }
113
+ function internErr(error) {
114
+ return { ok: false, error };
115
+ }
116
+ function asInternClientError(error) {
117
+ if (error instanceof InternClientError)
118
+ return error;
119
+ return new InternClientError("protocol", "Unexpected client failure", {
120
+ cause: error
121
+ });
122
+ }
123
+ async function toInternResult(value) {
124
+ try {
125
+ return internOk(await (typeof value === "function" ? value() : value));
126
+ } catch (error) {
127
+ return internErr(asInternClientError(error));
128
+ }
129
+ }
130
+ function requireInternCapability(value, capability) {
131
+ if (value === undefined || value === null || value === false) {
132
+ return internErr(new InternUnavailableError(`The selected host does not advertise ${capability}.`, { capability }));
133
+ }
134
+ return internOk(value);
135
+ }
136
+
137
+ // src/protocol.ts
138
+ class InternProtocolError extends Error {
139
+ code = "protocol";
140
+ path;
141
+ constructor(path, message) {
142
+ super(`${path}: ${message}`);
143
+ this.name = "InternProtocolError";
144
+ this.path = path;
145
+ }
146
+ }
147
+ function record(value, path) {
148
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
149
+ throw new InternProtocolError(path, "expected an object");
150
+ }
151
+ return value;
152
+ }
153
+ function stringAt(input, key, path) {
154
+ const value = input[key];
155
+ if (typeof value !== "string") {
156
+ throw new InternProtocolError(`${path}.${key}`, "expected a string");
157
+ }
158
+ return value;
159
+ }
160
+ function numberAt(input, key, path) {
161
+ const value = input[key];
162
+ if (typeof value !== "number" || !Number.isFinite(value)) {
163
+ throw new InternProtocolError(`${path}.${key}`, "expected a finite number");
164
+ }
165
+ return value;
166
+ }
167
+ function booleanAt(input, key, path) {
168
+ const value = input[key];
169
+ if (typeof value !== "boolean") {
170
+ throw new InternProtocolError(`${path}.${key}`, "expected a boolean");
171
+ }
172
+ return value;
173
+ }
174
+ function optionalString(input, key, path) {
175
+ const value = input[key];
176
+ if (value === undefined)
177
+ return;
178
+ if (typeof value !== "string") {
179
+ throw new InternProtocolError(`${path}.${key}`, "expected a string");
180
+ }
181
+ return value;
182
+ }
183
+ function optionalNumber(input, key, path) {
184
+ const value = input[key];
185
+ if (value === undefined)
186
+ return;
187
+ if (typeof value !== "number" || !Number.isFinite(value)) {
188
+ throw new InternProtocolError(`${path}.${key}`, "expected a finite number");
189
+ }
190
+ return value;
191
+ }
192
+ function optionalBoolean(input, key, path) {
193
+ const value = input[key];
194
+ if (value === undefined)
195
+ return;
196
+ if (typeof value !== "boolean") {
197
+ throw new InternProtocolError(`${path}.${key}`, "expected a boolean");
198
+ }
199
+ return value;
200
+ }
201
+ function parseInternRecord(value, path = "response") {
202
+ return { ...record(value, path) };
203
+ }
204
+ function parseInternHealth(value) {
205
+ const input = record(value, "health");
206
+ return {
207
+ ...input,
208
+ status: stringAt(input, "status", "health"),
209
+ runtimeAvailable: booleanAt(input, "runtimeAvailable", "health"),
210
+ jobRegistryAvailable: booleanAt(input, "jobRegistryAvailable", "health"),
211
+ approvalBrokerAvailable: booleanAt(input, "approvalBrokerAvailable", "health"),
212
+ processId: numberAt(input, "processId", "health"),
213
+ startedAt: stringAt(input, "startedAt", "health")
214
+ };
215
+ }
216
+ function parseInternReadiness(value) {
217
+ const input = record(value, "readiness");
218
+ const findings = input.findings;
219
+ if (findings !== undefined && !Array.isArray(findings)) {
220
+ throw new InternProtocolError("readiness.findings", "expected an array");
221
+ }
222
+ return {
223
+ ...input,
224
+ status: stringAt(input, "status", "readiness"),
225
+ ready: booleanAt(input, "ready", "readiness"),
226
+ summary: input.summary === undefined ? undefined : record(input.summary, "readiness.summary"),
227
+ findings
228
+ };
229
+ }
230
+ function parseInternCapabilities(value) {
231
+ const input = record(value, "capabilities");
232
+ const approvalInput = record(input.approvals, "capabilities.approvals");
233
+ const approvals = {};
234
+ for (const [key, item] of Object.entries(approvalInput)) {
235
+ if (typeof item !== "string") {
236
+ throw new InternProtocolError(`capabilities.approvals.${key}`, "expected a string");
237
+ }
238
+ approvals[key] = item;
239
+ }
240
+ return {
241
+ ...input,
242
+ runtimeProfile: stringAt(input, "runtimeProfile", "capabilities"),
243
+ hosted: booleanAt(input, "hosted", "capabilities"),
244
+ hostId: stringAt(input, "hostId", "capabilities"),
245
+ approvalBroker: record(input.approvalBroker, "capabilities.approvalBroker"),
246
+ approvals,
247
+ execAvailable: booleanAt(input, "execAvailable", "capabilities"),
248
+ sandboxEnabled: booleanAt(input, "sandboxEnabled", "capabilities"),
249
+ sandboxRequired: booleanAt(input, "sandboxRequired", "capabilities"),
250
+ networkPolicy: record(input.networkPolicy, "capabilities.networkPolicy")
251
+ };
252
+ }
253
+ function parseInternRunnerList(value) {
254
+ const input = record(value, "runnerList");
255
+ if (!Array.isArray(input.runners)) {
256
+ throw new InternProtocolError("runnerList.runners", "expected an array");
257
+ }
258
+ const runners = input.runners.map((item, index) => {
259
+ const runner = record(item, `runnerList.runners[${index}]`);
260
+ return {
261
+ ...runner,
262
+ id: stringAt(runner, "id", `runnerList.runners[${index}]`),
263
+ display_name: stringAt(runner, "display_name", `runnerList.runners[${index}]`),
264
+ status: stringAt(runner, "status", `runnerList.runners[${index}]`),
265
+ auth_status: stringAt(runner, "auth_status", `runnerList.runners[${index}]`),
266
+ supports: record(runner.supports, `runnerList.runners[${index}].supports`),
267
+ chat_capabilities: runner.chat_capabilities === undefined ? undefined : record(runner.chat_capabilities, `runnerList.runners[${index}].chat_capabilities`)
268
+ };
269
+ });
270
+ return {
271
+ ...input,
272
+ runners,
273
+ default_runner: optionalString(input, "default_runner", "runnerList")
274
+ };
275
+ }
276
+ function parseInternSession(value) {
277
+ const input = record(value, "session");
278
+ return {
279
+ ...input,
280
+ id: stringAt(input, "id", "session"),
281
+ app_session_key: stringAt(input, "app_session_key", "session"),
282
+ runner_id: stringAt(input, "runner_id", "session"),
283
+ continuation_mode: stringAt(input, "continuation_mode", "session"),
284
+ created_at: numberAt(input, "created_at", "session"),
285
+ updated_at: numberAt(input, "updated_at", "session"),
286
+ native_session_ref: optionalString(input, "native_session_ref", "session"),
287
+ model: optionalString(input, "model", "session"),
288
+ mode: optionalString(input, "mode", "session"),
289
+ isolation: optionalString(input, "isolation", "session"),
290
+ cwd: optionalString(input, "cwd", "session"),
291
+ max_turns: optionalNumber(input, "max_turns", "session"),
292
+ meta: input.meta
293
+ };
294
+ }
295
+ function parseInternSessionList(value) {
296
+ const input = record(value, "sessionList");
297
+ if (!Array.isArray(input.sessions)) {
298
+ throw new InternProtocolError("sessionList.sessions", "expected an array");
299
+ }
300
+ return {
301
+ ...input,
302
+ sessions: input.sessions.map(parseInternSession)
303
+ };
304
+ }
305
+ function parseInternTurn(value) {
306
+ const input = record(value, "turn");
307
+ return {
308
+ ...input,
309
+ id: stringAt(input, "id", "turn"),
310
+ session_id: stringAt(input, "session_id", "turn"),
311
+ sequence: numberAt(input, "sequence", "turn"),
312
+ status: stringAt(input, "status", "turn"),
313
+ continuation_mode: stringAt(input, "continuation_mode", "turn"),
314
+ requested_at: numberAt(input, "requested_at", "turn"),
315
+ started_at: optionalNumber(input, "started_at", "turn"),
316
+ completed_at: optionalNumber(input, "completed_at", "turn"),
317
+ user_message: optionalString(input, "user_message", "turn"),
318
+ final_text: optionalString(input, "final_text", "turn"),
319
+ error: optionalString(input, "error", "turn"),
320
+ runner_run_id: optionalString(input, "runner_run_id", "turn"),
321
+ runner_job_id: optionalString(input, "runner_job_id", "turn"),
322
+ user_message_id: optionalNumber(input, "user_message_id", "turn"),
323
+ assistant_message_id: optionalNumber(input, "assistant_message_id", "turn"),
324
+ model: optionalString(input, "model", "turn"),
325
+ mode: optionalString(input, "mode", "turn"),
326
+ isolation: optionalString(input, "isolation", "turn"),
327
+ cwd: optionalString(input, "cwd", "turn")
328
+ };
329
+ }
330
+ function parseInternEvent(value) {
331
+ const input = record(value, "event");
332
+ return {
333
+ ...input,
334
+ id: numberAt(input, "id", "event"),
335
+ turn_id: stringAt(input, "turn_id", "event"),
336
+ seq: numberAt(input, "seq", "event"),
337
+ ts: numberAt(input, "ts", "event"),
338
+ type: stringAt(input, "type", "event"),
339
+ stream: optionalString(input, "stream", "event"),
340
+ text: optionalString(input, "text", "event"),
341
+ job_id: optionalString(input, "job_id", "event"),
342
+ payload: input.payload
343
+ };
344
+ }
345
+ function parseInternApprovalDecision(value) {
346
+ const input = record(value, "approvalDecision");
347
+ return {
348
+ ...input,
349
+ request_id: numberAt(input, "request_id", "approvalDecision"),
350
+ status: optionalString(input, "status", "approvalDecision"),
351
+ token: optionalString(input, "token", "approvalDecision"),
352
+ allowlist_id: optionalNumber(input, "allowlist_id", "approvalDecision"),
353
+ session_key: optionalString(input, "session_key", "approvalDecision")
354
+ };
355
+ }
356
+ function parseInternTurnList(value) {
357
+ const input = record(value, "turnList");
358
+ if (!Array.isArray(input.turns)) {
359
+ throw new InternProtocolError("turnList.turns", "expected an array");
360
+ }
361
+ return {
362
+ ...input,
363
+ turns: input.turns.map(parseInternTurn)
364
+ };
365
+ }
366
+ function parseInternEventList(value) {
367
+ const input = record(value, "eventList");
368
+ if (!Array.isArray(input.events)) {
369
+ throw new InternProtocolError("eventList.events", "expected an array");
370
+ }
371
+ return {
372
+ ...input,
373
+ events: input.events.map(parseInternEvent)
374
+ };
375
+ }
376
+ function parseInternStartedTurn(value) {
377
+ const input = record(value, "startedTurn");
378
+ return {
379
+ ...input,
380
+ session_id: stringAt(input, "session_id", "startedTurn"),
381
+ turn_id: stringAt(input, "turn_id", "startedTurn"),
382
+ job_id: stringAt(input, "job_id", "startedTurn"),
383
+ status: stringAt(input, "status", "startedTurn")
384
+ };
385
+ }
386
+ function parseInternActionAcknowledgement(value) {
387
+ const input = record(value, "action");
388
+ return {
389
+ ...input,
390
+ status: stringAt(input, "status", "action")
391
+ };
392
+ }
393
+ function parseInternTurnDecision(value) {
394
+ const input = record(value, "turnDecision");
395
+ return {
396
+ ...input,
397
+ status: stringAt(input, "status", "turnDecision"),
398
+ decision: stringAt(input, "decision", "turnDecision"),
399
+ route: optionalString(input, "route", "turnDecision"),
400
+ approval_id: optionalNumber(input, "approval_id", "turnDecision"),
401
+ native_continued: optionalBoolean(input, "native_continued", "turnDecision"),
402
+ fallback_to_token: optionalBoolean(input, "fallback_to_token", "turnDecision"),
403
+ allowlist_session: optionalBoolean(input, "allowlist_session", "turnDecision"),
404
+ allowlist_id: optionalNumber(input, "allowlist_id", "turnDecision"),
405
+ token: optionalString(input, "token", "turnDecision")
406
+ };
407
+ }
408
+ function parseInternArtifact(value) {
409
+ const input = record(value, "artifact");
410
+ return {
411
+ ...input,
412
+ id: stringAt(input, "id", "artifact"),
413
+ mime: stringAt(input, "mime", "artifact"),
414
+ size_bytes: numberAt(input, "size_bytes", "artifact"),
415
+ offset: numberAt(input, "offset", "artifact"),
416
+ read_bytes: numberAt(input, "read_bytes", "artifact"),
417
+ truncated: booleanAt(input, "truncated", "artifact"),
418
+ content: stringAt(input, "content", "artifact")
419
+ };
420
+ }
421
+ function parseInternApproval(value, index) {
422
+ const path = `approvalList.items[${index}]`;
423
+ const input = record(value, path);
424
+ const id = input.id;
425
+ if (typeof id !== "string" && typeof id !== "number" || typeof id === "number" && !Number.isFinite(id)) {
426
+ throw new InternProtocolError(`${path}.id`, "expected an ID");
427
+ }
428
+ return {
429
+ ...input,
430
+ id,
431
+ type: stringAt(input, "type", path),
432
+ status: stringAt(input, "status", path),
433
+ requested_at: numberAt(input, "requested_at", path),
434
+ expires_at: optionalNumber(input, "expires_at", path),
435
+ resolved_at: optionalNumber(input, "resolved_at", path),
436
+ preview: optionalString(input, "preview", path)
437
+ };
438
+ }
439
+ function parseInternApprovalList(value) {
440
+ const input = record(value, "approvalList");
441
+ if (!Array.isArray(input.items)) {
442
+ throw new InternProtocolError("approvalList.items", "expected an array");
443
+ }
444
+ return {
445
+ ...input,
446
+ items: input.items.map(parseInternApproval)
447
+ };
448
+ }
449
+ function parseInternPairResult(value) {
450
+ const input = record(value, "pairResult");
451
+ return {
452
+ ...input,
453
+ certificate: record(input.certificate, "pairResult.certificate"),
454
+ certificate_hash: stringAt(input, "certificate_hash", "pairResult"),
455
+ device: record(input.device, "pairResult.device")
456
+ };
457
+ }
458
+
459
+ // src/sse.ts
460
+ function parseJson(data) {
461
+ if (!data)
462
+ return;
463
+ try {
464
+ return JSON.parse(data);
465
+ } catch {
466
+ return;
467
+ }
468
+ }
469
+ function parseInternSseBlock(block) {
470
+ const data = [];
471
+ const output = { data: "" };
472
+ for (const line of block.split(/\r\n|\r|\n/)) {
473
+ if (!line || line.startsWith(":"))
474
+ continue;
475
+ const separator = line.indexOf(":");
476
+ const field = separator < 0 ? line : line.slice(0, separator);
477
+ const rawValue = separator < 0 ? "" : line.slice(separator + 1);
478
+ const value = rawValue.startsWith(" ") ? rawValue.slice(1) : rawValue;
479
+ switch (field) {
480
+ case "event":
481
+ output.event = value;
482
+ break;
483
+ case "id":
484
+ if (!value.includes("\x00"))
485
+ output.id = value;
486
+ break;
487
+ case "retry": {
488
+ const retry = Number(value);
489
+ if (Number.isInteger(retry) && retry >= 0) {
490
+ output.retry = retry;
491
+ }
492
+ break;
493
+ }
494
+ case "data":
495
+ data.push(value);
496
+ break;
497
+ }
498
+ }
499
+ output.data = data.join(`
500
+ `);
501
+ output.json = parseJson(output.data);
502
+ if (output.id)
503
+ output.cursor = output.id;
504
+ return output;
505
+ }
506
+ function splitSseBuffer(buffer) {
507
+ const blocks = [];
508
+ let start = 0;
509
+ const delimiter = /\r\n\r\n|\n\n|\r\r/g;
510
+ for (let match = delimiter.exec(buffer);match; match = delimiter.exec(buffer)) {
511
+ blocks.push(buffer.slice(start, match.index));
512
+ start = match.index + match[0].length;
513
+ }
514
+ return { blocks, remainder: buffer.slice(start) };
515
+ }
516
+ async function* readInternSseStream(stream, signal) {
517
+ const reader = stream.getReader();
518
+ const decoder = new TextDecoder;
519
+ let buffer = "";
520
+ const abort = () => {
521
+ reader.cancel().catch(() => {
522
+ return;
523
+ });
524
+ };
525
+ signal?.addEventListener("abort", abort, { once: true });
526
+ try {
527
+ while (true) {
528
+ if (signal?.aborted) {
529
+ throw signal.reason ?? new DOMException("Aborted", "AbortError");
530
+ }
531
+ const { done, value } = await reader.read();
532
+ if (done)
533
+ break;
534
+ buffer += decoder.decode(value, { stream: true });
535
+ const { blocks, remainder } = splitSseBuffer(buffer);
536
+ buffer = remainder;
537
+ for (const block of blocks) {
538
+ if (block.trim() && !block.trimStart().startsWith(":")) {
539
+ yield parseInternSseBlock(block);
540
+ }
541
+ }
542
+ }
543
+ buffer += decoder.decode();
544
+ if (buffer.trim() && !buffer.trimStart().startsWith(":")) {
545
+ yield parseInternSseBlock(buffer);
546
+ }
547
+ } finally {
548
+ signal?.removeEventListener("abort", abort);
549
+ reader.releaseLock();
550
+ }
551
+ }
552
+ function internSseEventKey(event) {
553
+ if (event.id)
554
+ return `sse:${event.id}`;
555
+ const payload = event.json && typeof event.json === "object" && !Array.isArray(event.json) ? event.json : undefined;
556
+ if (!payload)
557
+ return;
558
+ if ((typeof payload.id === "string" || typeof payload.id === "number") && String(payload.id) !== "") {
559
+ return `payload:${String(payload.id)}`;
560
+ }
561
+ if (typeof payload.turn_id === "string" && (typeof payload.seq === "string" || typeof payload.seq === "number")) {
562
+ return `turn:${payload.turn_id}:${String(payload.seq)}`;
563
+ }
564
+ return;
565
+ }
566
+ function internSseEventCursor(event) {
567
+ if (event.id)
568
+ return event.id;
569
+ const payload = event.json && typeof event.json === "object" && !Array.isArray(event.json) ? event.json : undefined;
570
+ if (payload && (typeof payload.seq === "string" || typeof payload.seq === "number")) {
571
+ return String(payload.seq);
572
+ }
573
+ return;
574
+ }
575
+
576
+ // src/transport.ts
577
+ function sensitiveQueryKey(key) {
578
+ return /^(?:authorization|password|passphrase|secret|api[_-]?key)$/i.test(key) || /(?:^|[_-])(?:password|passphrase|secret|token|api[_-]?key)$/i.test(key) || /(?:Password|Passphrase|Secret|Token|ApiKey)$/.test(key);
579
+ }
580
+ var DEFAULT_REQUEST_TIMEOUT_MS = 15000;
581
+ var DEFAULT_STREAM_CONNECT_TIMEOUT_MS = 15000;
582
+ function defaultSleep(milliseconds, signal) {
583
+ if (milliseconds <= 0)
584
+ return Promise.resolve();
585
+ return new Promise((resolve, reject) => {
586
+ if (signal?.aborted) {
587
+ reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
588
+ return;
589
+ }
590
+ const timer = globalThis.setTimeout(done, milliseconds);
591
+ function done() {
592
+ signal?.removeEventListener("abort", aborted);
593
+ resolve();
594
+ }
595
+ function aborted() {
596
+ globalThis.clearTimeout(timer);
597
+ signal?.removeEventListener("abort", aborted);
598
+ reject(signal?.reason ?? new DOMException("Aborted", "AbortError"));
599
+ }
600
+ signal?.addEventListener("abort", aborted, { once: true });
601
+ });
602
+ }
603
+ function createClock(input) {
604
+ return {
605
+ now: input?.now ?? (() => Date.now()),
606
+ random: input?.random ?? (() => Math.random()),
607
+ sleep: input?.sleep ?? defaultSleep,
608
+ setTimeout: input?.setTimeout ?? ((callback, milliseconds) => globalThis.setTimeout(callback, milliseconds)),
609
+ clearTimeout: input?.clearTimeout ?? ((handle) => globalThis.clearTimeout(handle))
610
+ };
611
+ }
612
+ function normalizeBaseUrl(value) {
613
+ let url;
614
+ try {
615
+ url = new URL(value.trim());
616
+ } catch {
617
+ throw new InternClientError("validation_failed", "The selected host URL is invalid.");
618
+ }
619
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
620
+ throw new InternClientError("validation_failed", "The selected host must use HTTP or HTTPS.");
621
+ }
622
+ if (url.username || url.password || url.search || url.hash) {
623
+ throw new InternClientError("validation_failed", "Host credentials and query parameters must not appear in the URL.");
624
+ }
625
+ return url.toString().replace(/\/+$/, "");
626
+ }
627
+ function validatePath(path) {
628
+ const trimmed = path.trim();
629
+ if (!trimmed || /^[a-z][a-z\d+.-]*:/i.test(trimmed) || trimmed.startsWith("//")) {
630
+ throw new InternClientError("validation_failed", "Service requests require a relative path.");
631
+ }
632
+ const normalized = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
633
+ let url;
634
+ try {
635
+ url = new URL(normalized, "https://or3.invalid");
636
+ } catch {
637
+ throw new InternClientError("validation_failed", "The service request path is invalid.");
638
+ }
639
+ if (url.hash) {
640
+ throw new InternClientError("validation_failed", "Service request paths must not contain fragments.");
641
+ }
642
+ for (const key of url.searchParams.keys()) {
643
+ if (sensitiveQueryKey(key)) {
644
+ throw new InternClientError("validation_failed", "Credentials and secrets must be sent in headers or request bodies, never query parameters.");
645
+ }
646
+ }
647
+ return `${url.pathname}${url.search}`;
648
+ }
649
+ function appendCursor(path, queryParameter, cursor) {
650
+ const validated = validatePath(path);
651
+ if (cursor === undefined || cursor === "")
652
+ return validated;
653
+ if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(queryParameter)) {
654
+ throw new InternClientError("validation_failed", "The stream cursor parameter is invalid.");
655
+ }
656
+ const url = new URL(validated, "https://or3.invalid");
657
+ url.searchParams.set(queryParameter, cursor);
658
+ return `${url.pathname}${url.search}`;
659
+ }
660
+ function isAbortError(error) {
661
+ return error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
662
+ }
663
+ function isRawBody(value) {
664
+ if (typeof value === "string")
665
+ return true;
666
+ if (value instanceof ArrayBuffer || ArrayBuffer.isView(value))
667
+ return true;
668
+ if (typeof Blob !== "undefined" && value instanceof Blob)
669
+ return true;
670
+ if (typeof FormData !== "undefined" && value instanceof FormData)
671
+ return true;
672
+ if (typeof URLSearchParams !== "undefined" && value instanceof URLSearchParams) {
673
+ return true;
674
+ }
675
+ if (typeof ReadableStream !== "undefined" && value instanceof ReadableStream) {
676
+ return true;
677
+ }
678
+ return false;
679
+ }
680
+ function payloadMessage(payload, fallback) {
681
+ if (payload && typeof payload === "object" && !Array.isArray(payload)) {
682
+ const record2 = payload;
683
+ for (const key of ["message", "error", "detail"]) {
684
+ if (typeof record2[key] === "string" && record2[key].trim()) {
685
+ return record2[key].trim();
686
+ }
687
+ }
688
+ }
689
+ if (typeof payload === "string" && payload.trim())
690
+ return payload.trim();
691
+ return fallback;
692
+ }
693
+ function payloadString(payload, key) {
694
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
695
+ return;
696
+ }
697
+ const value = payload[key];
698
+ if (typeof value === "string" || typeof value === "number") {
699
+ return String(value);
700
+ }
701
+ return;
702
+ }
703
+ function errorCodeForResponse(status, remoteCode) {
704
+ const code = remoteCode?.toLowerCase() ?? "";
705
+ if (status === 503 || code === "capability_unavailable" || code === "runner_disabled" || code === "runner_missing" || code === "runner_auth_missing") {
706
+ return "unavailable";
707
+ }
708
+ if (status === 401)
709
+ return "unauthorized";
710
+ if (status === 403)
711
+ return "forbidden";
712
+ if (status === 404)
713
+ return "not_found";
714
+ if (status === 408 || status === 504 || code === "timeout")
715
+ return "timeout";
716
+ if (status === 409)
717
+ return "conflict";
718
+ if (status === 400 || status === 422)
719
+ return "validation_failed";
720
+ return "http";
721
+ }
722
+ function makeResponseError(response, payload, secrets) {
723
+ const remoteCode = payloadString(payload, "code");
724
+ const requestId = response.headers.get("X-Request-Id") ?? payloadString(payload, "request_id");
725
+ const code = errorCodeForResponse(response.status, remoteCode);
726
+ const options = {
727
+ status: response.status,
728
+ remoteCode,
729
+ requestId,
730
+ retryable: code === "timeout" || code === "offline" || response.status === 429 || response.status >= 500,
731
+ details: {
732
+ status: response.status,
733
+ payload,
734
+ requestId
735
+ },
736
+ secrets
737
+ };
738
+ const message = payloadMessage(payload, `Request failed with status ${response.status}.`);
739
+ return code === "unavailable" ? new InternUnavailableError(message, options) : new InternClientError(code, message, options);
740
+ }
741
+ async function readResponsePayload(response) {
742
+ const text = await response.text().catch(() => "");
743
+ if (!text)
744
+ return;
745
+ try {
746
+ return JSON.parse(text);
747
+ } catch {
748
+ return text;
749
+ }
750
+ }
751
+ function statusAccepted(response, accepted) {
752
+ if (response.ok)
753
+ return true;
754
+ if (Array.isArray(accepted))
755
+ return accepted.includes(response.status);
756
+ return typeof accepted === "function" ? accepted(response.status, response) : false;
757
+ }
758
+ function createAbortScope(externalSignal, timeoutMs, clock) {
759
+ const controller = new AbortController;
760
+ let timeoutHandle;
761
+ let didTimeout = false;
762
+ const externalAbort = () => {
763
+ controller.abort(externalSignal?.reason ?? new DOMException("Aborted", "AbortError"));
764
+ };
765
+ if (externalSignal?.aborted) {
766
+ externalAbort();
767
+ } else {
768
+ externalSignal?.addEventListener("abort", externalAbort, {
769
+ once: true
770
+ });
771
+ }
772
+ if (Number.isFinite(timeoutMs) && timeoutMs > 0) {
773
+ timeoutHandle = clock.setTimeout(() => {
774
+ didTimeout = true;
775
+ controller.abort(new DOMException("Timed out", "TimeoutError"));
776
+ }, timeoutMs);
777
+ }
778
+ const clearTimeout = () => {
779
+ if (timeoutHandle !== undefined) {
780
+ clock.clearTimeout(timeoutHandle);
781
+ timeoutHandle = undefined;
782
+ }
783
+ };
784
+ return {
785
+ signal: controller.signal,
786
+ timedOut: () => didTimeout,
787
+ clearTimeout,
788
+ dispose() {
789
+ clearTimeout();
790
+ externalSignal?.removeEventListener("abort", externalAbort);
791
+ }
792
+ };
793
+ }
794
+ function requestFailure(error, scope, externalSignal, secrets) {
795
+ if (error instanceof InternClientError)
796
+ return error;
797
+ if (scope.timedOut()) {
798
+ return new InternClientError("timeout", "The request timed out.", {
799
+ retryable: true,
800
+ cause: error,
801
+ secrets
802
+ });
803
+ }
804
+ if (externalSignal?.aborted || isAbortError(error)) {
805
+ return new InternClientError("aborted", "The request was stopped.", {
806
+ cause: error,
807
+ secrets
808
+ });
809
+ }
810
+ return new InternClientError("offline", "Could not reach the selected host.", {
811
+ retryable: true,
812
+ cause: error,
813
+ secrets
814
+ });
815
+ }
816
+ function reconnectConfig(input) {
817
+ if (!input)
818
+ return null;
819
+ const options = input === true ? {} : input;
820
+ const finite = (value, fallback) => Number.isFinite(value) ? value : fallback;
821
+ return {
822
+ maxAttempts: Math.min(100, Math.max(0, Math.floor(finite(options.maxAttempts, 5)))),
823
+ minDelayMs: Math.min(60000, Math.max(0, finite(options.minDelayMs, 250))),
824
+ maxDelayMs: Math.min(60000, Math.max(0, finite(options.maxDelayMs, 1e4))),
825
+ factor: Math.min(10, Math.max(1, finite(options.factor, 2))),
826
+ jitter: Math.min(1, Math.max(0, finite(options.jitter, 0.2)))
827
+ };
828
+ }
829
+ function reconnectDelay(attempt, config, random, serverRetry) {
830
+ const exponential = serverRetry ?? Math.min(config.maxDelayMs, config.minDelayMs * config.factor ** Math.max(0, attempt - 1));
831
+ const bounded = Math.min(config.maxDelayMs, Math.max(0, exponential));
832
+ const jittered = bounded * (1 - config.jitter + config.jitter * 2 * Math.min(1, Math.max(0, random)));
833
+ return Math.round(jittered);
834
+ }
835
+ function shouldReconnect(error) {
836
+ return error.retryable || error.code === "offline" || error.code === "timeout" || error.code === "http" && (error.status ?? 0) >= 500;
837
+ }
838
+
839
+ class BoundedEventKeys {
840
+ limit;
841
+ values = new Set;
842
+ order = [];
843
+ constructor(limit) {
844
+ this.limit = limit;
845
+ }
846
+ hasOrAdd(key) {
847
+ if (this.values.has(key))
848
+ return true;
849
+ this.values.add(key);
850
+ this.order.push(key);
851
+ while (this.order.length > this.limit) {
852
+ const oldest = this.order.shift();
853
+ if (oldest !== undefined)
854
+ this.values.delete(oldest);
855
+ }
856
+ return false;
857
+ }
858
+ }
859
+ function createInternTransport(options) {
860
+ const fetchImpl = options.fetch ?? globalThis.fetch;
861
+ if (typeof fetchImpl !== "function") {
862
+ throw new InternUnavailableError("No Fetch-compatible transport is available.", { capability: "fetch" });
863
+ }
864
+ const clock = createClock(options.clock);
865
+ const configuredTimeout = options.defaultTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
866
+ const configuredStreamTimeout = options.streamConnectTimeoutMs ?? DEFAULT_STREAM_CONNECT_TIMEOUT_MS;
867
+ const currentBaseUrl = (explicit) => normalizeBaseUrl(explicit ?? (typeof options.baseUrl === "function" ? options.baseUrl() : options.baseUrl));
868
+ const buildUrl = (path, explicitBaseUrl) => `${currentBaseUrl(explicitBaseUrl)}${validatePath(path)}`;
869
+ async function resolvedHeaders(method, path, requestOptions, accept) {
870
+ const requireAuth = requestOptions.requireAuth !== false;
871
+ const baseUrl = currentBaseUrl(requestOptions.baseUrl);
872
+ const headers = new Headers(requestOptions.headers);
873
+ if (!headers.has("Accept"))
874
+ headers.set("Accept", accept);
875
+ const auth = requireAuth ? await options.resolveAuth?.({
876
+ method,
877
+ path,
878
+ baseUrl,
879
+ requireAuth
880
+ }) : undefined;
881
+ const authHeaders = new Headers(auth?.headers);
882
+ authHeaders.forEach((value, key) => headers.set(key, value));
883
+ const token = auth?.token?.trim();
884
+ if (token) {
885
+ headers.set("Authorization", `${auth?.scheme?.trim() || "Bearer"} ${token}`);
886
+ }
887
+ if (requireAuth && options.resolveAuth && !headers.has("Authorization")) {
888
+ throw new InternClientError("unauthorized", "No credential is available for the selected host.", { status: 401 });
889
+ }
890
+ const secrets = [];
891
+ if (token)
892
+ secrets.push(token);
893
+ for (const [key, value] of headers.entries()) {
894
+ if (/authorization|cookie|secret|password|token|api[_-]?key/i.test(key)) {
895
+ secrets.push(value, value.replace(/^\S+\s+/, ""));
896
+ }
897
+ }
898
+ return { headers, secrets: secrets.filter(Boolean) };
899
+ }
900
+ async function request(path, requestOptions = {}) {
901
+ const method = requestOptions.method ?? (requestOptions.body === undefined ? "GET" : "POST");
902
+ const validatedPath = validatePath(path);
903
+ const { headers, secrets } = await resolvedHeaders(method, validatedPath, requestOptions, "application/json");
904
+ let body;
905
+ if (requestOptions.body !== undefined) {
906
+ if (isRawBody(requestOptions.body)) {
907
+ body = requestOptions.body;
908
+ } else {
909
+ body = JSON.stringify(requestOptions.body);
910
+ if (!headers.has("Content-Type")) {
911
+ headers.set("Content-Type", "application/json");
912
+ }
913
+ }
914
+ }
915
+ const scope = createAbortScope(requestOptions.signal, requestOptions.timeoutMs ?? configuredTimeout, clock);
916
+ try {
917
+ const response = await fetchImpl(buildUrl(validatedPath, requestOptions.baseUrl), {
918
+ method,
919
+ headers,
920
+ body,
921
+ cache: "no-store",
922
+ signal: scope.signal
923
+ });
924
+ await requestOptions.onResponse?.({
925
+ method,
926
+ path: validatedPath,
927
+ response
928
+ });
929
+ if (!statusAccepted(response, requestOptions.acceptedStatuses)) {
930
+ const payload = await readResponsePayload(response);
931
+ throw makeResponseError(response, payload, secrets);
932
+ }
933
+ const responseType = requestOptions.responseType ?? "json";
934
+ let value;
935
+ if (responseType === "void" || response.status === 204) {
936
+ value = undefined;
937
+ } else if (responseType === "text") {
938
+ value = await response.text();
939
+ } else {
940
+ try {
941
+ value = await response.json();
942
+ } catch (error) {
943
+ throw new InternClientError("protocol", "The host returned invalid JSON.", {
944
+ status: response.status,
945
+ cause: error,
946
+ secrets
947
+ });
948
+ }
949
+ }
950
+ if (!requestOptions.parse)
951
+ return value;
952
+ try {
953
+ return requestOptions.parse(value, response);
954
+ } catch (error) {
955
+ if (error instanceof InternClientError)
956
+ throw error;
957
+ throw new InternClientError("protocol", "The host returned an invalid response.", {
958
+ status: response.status,
959
+ details: redactInternSecrets(value, secrets),
960
+ cause: error,
961
+ secrets
962
+ });
963
+ }
964
+ } catch (error) {
965
+ throw requestFailure(error, scope, requestOptions.signal, secrets);
966
+ } finally {
967
+ scope.dispose();
968
+ }
969
+ }
970
+ async function* stream(path, streamOptions = {}) {
971
+ const method = streamOptions.method ?? "GET";
972
+ const reconnect = reconnectConfig(streamOptions.reconnect);
973
+ const resume = streamOptions.resume;
974
+ const queryParameter = resume?.queryParameter ?? "cursor";
975
+ const dedupeInput = streamOptions.dedupe;
976
+ const dedupeOptions = dedupeInput === true ? {} : dedupeInput && typeof dedupeInput === "object" ? dedupeInput : null;
977
+ const eventKeys = dedupeOptions ? new BoundedEventKeys(Math.max(1, Math.floor(dedupeOptions.maxEntries ?? 2048))) : null;
978
+ let cursor = resume?.initialCursor === undefined ? undefined : String(resume.initialCursor);
979
+ let attempt = 0;
980
+ let serverRetry;
981
+ while (true) {
982
+ const attemptPath = appendCursor(path, queryParameter, cursor);
983
+ const attemptHeaders = new Headers(streamOptions.headers);
984
+ if (cursor && resume?.sendLastEventId) {
985
+ attemptHeaders.set("Last-Event-ID", cursor);
986
+ }
987
+ const { headers, secrets } = await resolvedHeaders(method, attemptPath, { ...streamOptions, headers: attemptHeaders }, "text/event-stream");
988
+ let body;
989
+ if (streamOptions.body !== undefined) {
990
+ if (isRawBody(streamOptions.body)) {
991
+ body = streamOptions.body;
992
+ } else {
993
+ body = JSON.stringify(streamOptions.body);
994
+ if (!headers.has("Content-Type")) {
995
+ headers.set("Content-Type", "application/json");
996
+ }
997
+ }
998
+ }
999
+ const scope = createAbortScope(streamOptions.signal, streamOptions.timeoutMs ?? configuredStreamTimeout, clock);
1000
+ let failure;
1001
+ let ended = false;
1002
+ try {
1003
+ const response = await fetchImpl(buildUrl(attemptPath, streamOptions.baseUrl), {
1004
+ method,
1005
+ headers,
1006
+ body,
1007
+ cache: "no-store",
1008
+ signal: scope.signal
1009
+ });
1010
+ scope.clearTimeout();
1011
+ await streamOptions.onResponse?.({
1012
+ method,
1013
+ path: attemptPath,
1014
+ response
1015
+ });
1016
+ if (!statusAccepted(response, streamOptions.acceptedStatuses)) {
1017
+ const payload = await readResponsePayload(response);
1018
+ throw makeResponseError(response, payload, secrets);
1019
+ }
1020
+ if (!response.body) {
1021
+ throw new InternClientError("protocol", "The host did not return an event stream.", { status: response.status, secrets });
1022
+ }
1023
+ for await (const event of readInternSseStream(response.body, scope.signal)) {
1024
+ if (event.retry !== undefined) {
1025
+ serverRetry = event.retry;
1026
+ }
1027
+ const nextCursor = resume?.cursorFromEvent?.(event) ?? internSseEventCursor(event);
1028
+ if (nextCursor !== undefined) {
1029
+ cursor = String(nextCursor);
1030
+ event.cursor = cursor;
1031
+ }
1032
+ const key = dedupeOptions?.key?.(event) ?? internSseEventKey(event);
1033
+ if (key && eventKeys?.hasOrAdd(key))
1034
+ continue;
1035
+ yield event;
1036
+ if (streamOptions.isTerminal?.(event))
1037
+ return;
1038
+ }
1039
+ ended = true;
1040
+ } catch (error) {
1041
+ failure = requestFailure(error, scope, streamOptions.signal, secrets);
1042
+ } finally {
1043
+ scope.dispose();
1044
+ }
1045
+ if (streamOptions.signal?.aborted) {
1046
+ throw failure ?? new InternClientError("aborted", "The stream was stopped.");
1047
+ }
1048
+ if (!reconnect) {
1049
+ if (failure)
1050
+ throw failure;
1051
+ return;
1052
+ }
1053
+ const reconnectFailure = failure ?? new InternClientError("offline", ended ? "The event stream ended before a terminal event." : "The event stream disconnected.", { retryable: true });
1054
+ if (!shouldReconnect(reconnectFailure) || attempt >= reconnect.maxAttempts) {
1055
+ throw reconnectFailure;
1056
+ }
1057
+ attempt += 1;
1058
+ const delay = reconnectDelay(attempt, reconnect, clock.random(), serverRetry);
1059
+ try {
1060
+ await clock.sleep(delay, streamOptions.signal);
1061
+ } catch (error) {
1062
+ throw new InternClientError("aborted", "The stream was stopped.", { cause: error, secrets });
1063
+ }
1064
+ }
1065
+ }
1066
+ return { buildUrl, request, stream };
1067
+ }
1068
+
1069
+ // src/client.ts
1070
+ function pathId(value, label) {
1071
+ const normalized = String(value).trim();
1072
+ if (!normalized) {
1073
+ throw new InternClientError("validation_failed", `${label} is required.`);
1074
+ }
1075
+ return encodeURIComponent(normalized);
1076
+ }
1077
+ function queryPath(path, values) {
1078
+ const query = new URLSearchParams;
1079
+ for (const [key, value] of Object.entries(values)) {
1080
+ if (value !== undefined && value !== "") {
1081
+ query.set(key, String(value));
1082
+ }
1083
+ }
1084
+ const encoded = query.toString();
1085
+ return encoded ? `${path}?${encoded}` : path;
1086
+ }
1087
+ function positiveInteger(value, label) {
1088
+ if (value === undefined)
1089
+ return;
1090
+ if (!Number.isSafeInteger(value) || value <= 0) {
1091
+ throw new InternClientError("validation_failed", `${label} must be a positive integer.`);
1092
+ }
1093
+ return value;
1094
+ }
1095
+ function boundedPositiveInteger(value, label, maximum) {
1096
+ const normalized = positiveInteger(value, label);
1097
+ if (normalized !== undefined && normalized > maximum) {
1098
+ throw new InternClientError("validation_failed", `${label} must not exceed ${maximum}.`);
1099
+ }
1100
+ return normalized;
1101
+ }
1102
+ function appSessionKeyPrefix(value) {
1103
+ if (value === undefined)
1104
+ return;
1105
+ const normalized = value.trim();
1106
+ if (!normalized || new TextEncoder().encode(normalized).byteLength > 256 || /[\0\r\n]/.test(normalized)) {
1107
+ throw new InternClientError("validation_failed", "App session key prefix is invalid.");
1108
+ }
1109
+ return normalized;
1110
+ }
1111
+ function nonNegativeInteger(value, label) {
1112
+ if (value === undefined)
1113
+ return;
1114
+ if (!Number.isSafeInteger(value) || value < 0) {
1115
+ throw new InternClientError("validation_failed", `${label} must be a non-negative integer.`);
1116
+ }
1117
+ return value;
1118
+ }
1119
+ function sessionPath(sessionId) {
1120
+ return `/internal/v1/runner-chat/sessions/${pathId(sessionId, "Session ID")}`;
1121
+ }
1122
+ function turnPath(sessionId, turnId) {
1123
+ return `${sessionPath(sessionId)}/turns/${pathId(turnId, "Turn ID")}`;
1124
+ }
1125
+ function parseTurnStreamEvent(event) {
1126
+ if (event.json === undefined) {
1127
+ return event;
1128
+ }
1129
+ let json;
1130
+ if (typeof event.json.turn_id === "string" && typeof event.json.seq === "number") {
1131
+ json = parseInternEvent(event.json);
1132
+ } else {
1133
+ json = parseInternRecord(event.json, "streamEvent");
1134
+ }
1135
+ return { ...event, json };
1136
+ }
1137
+ function findInternRunner(list, runnerId) {
1138
+ const normalized = runnerId.trim();
1139
+ const runner = list.runners.find((item) => item.id === normalized);
1140
+ if (!runner) {
1141
+ throw new InternUnavailableError(`Runner ${normalized || "(missing)"} is not advertised by the selected host.`, { capability: `runner:${normalized || "unknown"}` });
1142
+ }
1143
+ return runner;
1144
+ }
1145
+ function requireInternRunner(list, runnerId) {
1146
+ const runner = findInternRunner(list, runnerId);
1147
+ if (runner.status !== "available") {
1148
+ throw new InternUnavailableError(`Runner ${runner.id} is advertised but is not available (${runner.status || "unknown status"}).`, {
1149
+ capability: `runner:${runner.id}`,
1150
+ details: {
1151
+ runnerId: runner.id,
1152
+ status: runner.status,
1153
+ authStatus: runner.auth_status
1154
+ }
1155
+ });
1156
+ }
1157
+ return runner;
1158
+ }
1159
+ function createInternClient(options) {
1160
+ const transport = createInternTransport(options);
1161
+ const health = (callOptions = {}) => transport.request("/internal/v1/health", {
1162
+ ...callOptions,
1163
+ method: "GET",
1164
+ parse: parseInternHealth
1165
+ });
1166
+ const readiness = (callOptions = {}) => transport.request("/internal/v1/readiness", {
1167
+ ...callOptions,
1168
+ method: "GET",
1169
+ acceptedStatuses: [503],
1170
+ parse: parseInternReadiness
1171
+ });
1172
+ const capabilities = (input = {}, callOptions = {}) => transport.request(queryPath("/internal/v1/capabilities", {
1173
+ channel: input.channel,
1174
+ trigger: input.trigger
1175
+ }), {
1176
+ ...callOptions,
1177
+ method: "GET",
1178
+ parse: parseInternCapabilities
1179
+ });
1180
+ const appBootstrap = (callOptions = {}) => transport.request("/internal/v1/app/bootstrap", {
1181
+ ...callOptions,
1182
+ method: "GET",
1183
+ parse: (value) => parseInternRecord(value, "appBootstrap")
1184
+ });
1185
+ const listRunners = (callOptions = {}) => transport.request("/internal/v1/chat-runners", {
1186
+ ...callOptions,
1187
+ method: "GET",
1188
+ parse: parseInternRunnerList
1189
+ });
1190
+ const requireRunner = async (runnerId, callOptions = {}) => requireInternRunner(await listRunners(callOptions), runnerId);
1191
+ const listSessions = async (input = {}, callOptions = {}) => transport.request(queryPath("/internal/v1/runner-chat/sessions", {
1192
+ app_session_key_prefix: appSessionKeyPrefix(input.appSessionKeyPrefix),
1193
+ limit: boundedPositiveInteger(input.limit, "Session limit", 100)
1194
+ }), {
1195
+ ...callOptions,
1196
+ method: "GET",
1197
+ parse: parseInternSessionList
1198
+ });
1199
+ const createSession = (input, callOptions = {}) => transport.request("/internal/v1/runner-chat/sessions", {
1200
+ ...callOptions,
1201
+ method: "POST",
1202
+ body: input,
1203
+ parse: parseInternSession
1204
+ });
1205
+ const getSession = async (sessionId, callOptions = {}) => transport.request(sessionPath(sessionId), {
1206
+ ...callOptions,
1207
+ method: "GET",
1208
+ parse: parseInternSession
1209
+ });
1210
+ const listTurns = async (sessionId, input = {}, callOptions = {}) => transport.request(queryPath(`${sessionPath(sessionId)}/turns`, {
1211
+ limit: positiveInteger(input.limit, "Turn limit")
1212
+ }), {
1213
+ ...callOptions,
1214
+ method: "GET",
1215
+ parse: parseInternTurnList
1216
+ });
1217
+ const startTurn = async (sessionId, input, callOptions = {}) => transport.request(`${sessionPath(sessionId)}/turns`, {
1218
+ ...callOptions,
1219
+ method: "POST",
1220
+ body: input,
1221
+ parse: parseInternStartedTurn
1222
+ });
1223
+ const getTurn = async (sessionId, turnId, callOptions = {}) => transport.request(turnPath(sessionId, turnId), {
1224
+ ...callOptions,
1225
+ method: "GET",
1226
+ parse: parseInternTurn
1227
+ });
1228
+ const listTurnEvents = async (sessionId, turnId, input = {}, callOptions = {}) => transport.request(queryPath(`${turnPath(sessionId, turnId)}/events`, {
1229
+ after_seq: nonNegativeInteger(input.afterSeq, "Event cursor"),
1230
+ limit: positiveInteger(input.limit, "Event limit")
1231
+ }), {
1232
+ ...callOptions,
1233
+ method: "GET",
1234
+ parse: parseInternEventList
1235
+ });
1236
+ async function* streamTurn(sessionId, turnId, streamOptions = {}) {
1237
+ const { afterSeq, ...transportOptions } = streamOptions;
1238
+ const stream = transport.stream(`${turnPath(sessionId, turnId)}/stream`, {
1239
+ ...transportOptions,
1240
+ method: "GET",
1241
+ reconnect: transportOptions.reconnect ?? true,
1242
+ dedupe: transportOptions.dedupe ?? true,
1243
+ resume: {
1244
+ initialCursor: nonNegativeInteger(afterSeq, "Event cursor"),
1245
+ queryParameter: "after_seq",
1246
+ cursorFromEvent: (event) => {
1247
+ const seq = event.json?.seq;
1248
+ return typeof seq === "string" || typeof seq === "number" ? seq : undefined;
1249
+ }
1250
+ },
1251
+ isTerminal: (event) => event.event === "done"
1252
+ });
1253
+ for await (const event of stream) {
1254
+ yield parseTurnStreamEvent(event);
1255
+ }
1256
+ }
1257
+ const abortTurn = async (sessionId, turnId, callOptions = {}) => transport.request(`${turnPath(sessionId, turnId)}/abort`, {
1258
+ ...callOptions,
1259
+ method: "POST",
1260
+ parse: parseInternActionAcknowledgement
1261
+ });
1262
+ const decideTurn = async (sessionId, turnId, decision, input = {}, callOptions = {}) => transport.request(`${turnPath(sessionId, turnId)}/${decision}`, {
1263
+ ...callOptions,
1264
+ method: "POST",
1265
+ body: {
1266
+ note: input.note,
1267
+ allow_session: input.allow_session
1268
+ },
1269
+ parse: parseInternTurnDecision
1270
+ });
1271
+ const readArtifact = async (artifactId, input, callOptions = {}) => transport.request(queryPath(`/internal/v1/artifacts/${pathId(artifactId, "Artifact ID")}`, {
1272
+ session_key: input.sessionKey,
1273
+ offset: nonNegativeInteger(input.offset, "Artifact offset"),
1274
+ max_bytes: positiveInteger(input.maxBytes, "Artifact byte limit")
1275
+ }), {
1276
+ ...callOptions,
1277
+ method: "GET",
1278
+ parse: parseInternArtifact
1279
+ });
1280
+ const listApprovals = (input = {}, callOptions = {}) => transport.request(queryPath("/internal/v1/approvals", {
1281
+ status: input.status,
1282
+ type: input.type
1283
+ }), {
1284
+ ...callOptions,
1285
+ method: "GET",
1286
+ parse: parseInternApprovalList
1287
+ });
1288
+ const decideApproval = async (requestId, decision, input = {}, callOptions = {}) => transport.request(`/internal/v1/approvals/${pathId(requestId, "Approval request ID")}/${decision}`, {
1289
+ ...callOptions,
1290
+ method: "POST",
1291
+ body: decision === "approve" ? { note: input.note, allowlist: input.allowlist } : { note: input.note },
1292
+ parse: parseInternApprovalDecision
1293
+ });
1294
+ const pair = (input, callOptions = {}) => transport.request("/internal/v1/secure-connections/pairing/approve", {
1295
+ ...callOptions,
1296
+ method: "POST",
1297
+ body: input,
1298
+ requireAuth: false,
1299
+ parse: parseInternPairResult
1300
+ });
1301
+ return {
1302
+ transport,
1303
+ health,
1304
+ readiness,
1305
+ capabilities,
1306
+ appBootstrap,
1307
+ listRunners,
1308
+ requireRunner,
1309
+ listSessions,
1310
+ createSession,
1311
+ getSession,
1312
+ listTurns,
1313
+ startTurn,
1314
+ getTurn,
1315
+ listTurnEvents,
1316
+ streamTurn,
1317
+ abortTurn,
1318
+ decideTurn,
1319
+ readArtifact,
1320
+ listApprovals,
1321
+ decideApproval,
1322
+ pair
1323
+ };
1324
+ }
1325
+ export {
1326
+ toInternResult,
1327
+ safeInternStringify,
1328
+ requireInternRunner,
1329
+ requireInternCapability,
1330
+ redactInternSecrets,
1331
+ readInternSseStream,
1332
+ parseInternTurnList,
1333
+ parseInternTurnDecision,
1334
+ parseInternTurn,
1335
+ parseInternStartedTurn,
1336
+ parseInternSseBlock,
1337
+ parseInternSessionList,
1338
+ parseInternSession,
1339
+ parseInternRunnerList,
1340
+ parseInternRecord,
1341
+ parseInternReadiness,
1342
+ parseInternPairResult,
1343
+ parseInternHealth,
1344
+ parseInternEventList,
1345
+ parseInternEvent,
1346
+ parseInternCapabilities,
1347
+ parseInternArtifact,
1348
+ parseInternApprovalList,
1349
+ parseInternApprovalDecision,
1350
+ parseInternActionAcknowledgement,
1351
+ internSseEventKey,
1352
+ internSseEventCursor,
1353
+ internOk,
1354
+ internErr,
1355
+ findInternRunner,
1356
+ createInternTransport,
1357
+ createInternClient,
1358
+ asInternClientError,
1359
+ InternUnavailableError,
1360
+ InternProtocolError,
1361
+ InternClientError
1362
+ };