@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/README.md +76 -0
- package/dist/index.js +1362 -0
- package/package.json +34 -0
- package/src/client.ts +676 -0
- package/src/errors.ts +131 -0
- package/src/index.ts +6 -0
- package/src/protocol.ts +692 -0
- package/src/redaction.ts +114 -0
- package/src/sse.ts +151 -0
- package/src/transport.ts +915 -0
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@or3/intern-client",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/Saluana/or3-intern.git",
|
|
7
|
+
"directory": "clients/typescript"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"private": false,
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./src/index.ts",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./src/index.ts",
|
|
21
|
+
"import": "./dist/index.js",
|
|
22
|
+
"default": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "bun build ./src/index.ts --target=node --format=esm --outfile=./dist/index.js",
|
|
27
|
+
"test": "bun test",
|
|
28
|
+
"prepack": "bun run build"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public",
|
|
32
|
+
"provenance": true
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InternClientError,
|
|
3
|
+
InternUnavailableError,
|
|
4
|
+
} from './errors';
|
|
5
|
+
import {
|
|
6
|
+
parseInternActionAcknowledgement,
|
|
7
|
+
parseInternApprovalDecision,
|
|
8
|
+
parseInternApprovalList,
|
|
9
|
+
parseInternArtifact,
|
|
10
|
+
parseInternCapabilities,
|
|
11
|
+
parseInternEvent,
|
|
12
|
+
parseInternEventList,
|
|
13
|
+
parseInternHealth,
|
|
14
|
+
parseInternPairResult,
|
|
15
|
+
parseInternReadiness,
|
|
16
|
+
parseInternRecord,
|
|
17
|
+
parseInternRunnerList,
|
|
18
|
+
parseInternSession,
|
|
19
|
+
parseInternSessionList,
|
|
20
|
+
parseInternStartedTurn,
|
|
21
|
+
parseInternTurn,
|
|
22
|
+
parseInternTurnDecision,
|
|
23
|
+
parseInternTurnList,
|
|
24
|
+
type CreateInternSessionInput,
|
|
25
|
+
type InternActionAcknowledgement,
|
|
26
|
+
type InternApprovalDecision,
|
|
27
|
+
type InternApprovalDecisionAction,
|
|
28
|
+
type InternApprovalInput,
|
|
29
|
+
type InternApprovalList,
|
|
30
|
+
type InternArtifact,
|
|
31
|
+
type InternCapabilities,
|
|
32
|
+
type InternEvent,
|
|
33
|
+
type InternEventList,
|
|
34
|
+
type InternHealth,
|
|
35
|
+
type InternPairInput,
|
|
36
|
+
type InternPairResult,
|
|
37
|
+
type InternReadiness,
|
|
38
|
+
type InternRunner,
|
|
39
|
+
type InternRunnerList,
|
|
40
|
+
type InternSession,
|
|
41
|
+
type InternSessionList,
|
|
42
|
+
type InternStartedTurn,
|
|
43
|
+
type InternTurn,
|
|
44
|
+
type InternTurnDecision,
|
|
45
|
+
type InternTurnDecisionAction,
|
|
46
|
+
type InternTurnList,
|
|
47
|
+
type StartInternTurnInput,
|
|
48
|
+
type UnknownRecord,
|
|
49
|
+
} from './protocol';
|
|
50
|
+
import type { InternSseEvent } from './sse';
|
|
51
|
+
import {
|
|
52
|
+
createInternTransport,
|
|
53
|
+
type InternRequestOptions,
|
|
54
|
+
type InternStreamOptions,
|
|
55
|
+
type InternTransport,
|
|
56
|
+
type InternTransportOptions,
|
|
57
|
+
} from './transport';
|
|
58
|
+
|
|
59
|
+
export type InternCallOptions = Omit<
|
|
60
|
+
InternRequestOptions<never>,
|
|
61
|
+
| 'method'
|
|
62
|
+
| 'body'
|
|
63
|
+
| 'responseType'
|
|
64
|
+
| 'acceptedStatuses'
|
|
65
|
+
| 'parse'
|
|
66
|
+
>;
|
|
67
|
+
|
|
68
|
+
export interface InternCapabilitiesInput {
|
|
69
|
+
channel?: string;
|
|
70
|
+
trigger?: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface InternTurnListInput {
|
|
74
|
+
limit?: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface InternSessionListInput {
|
|
78
|
+
appSessionKeyPrefix?: string;
|
|
79
|
+
limit?: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface InternEventListInput {
|
|
83
|
+
afterSeq?: number;
|
|
84
|
+
limit?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface InternArtifactInput {
|
|
88
|
+
sessionKey: string;
|
|
89
|
+
offset?: number;
|
|
90
|
+
maxBytes?: number;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface InternApprovalListInput {
|
|
94
|
+
status?: string;
|
|
95
|
+
type?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface InternTurnStreamOptions
|
|
99
|
+
extends Omit<
|
|
100
|
+
InternStreamOptions<UnknownRecord>,
|
|
101
|
+
'method' | 'body' | 'resume' | 'isTerminal'
|
|
102
|
+
> {
|
|
103
|
+
afterSeq?: number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export type InternTurnStreamEvent = InternSseEvent<
|
|
107
|
+
InternEvent | UnknownRecord
|
|
108
|
+
>;
|
|
109
|
+
|
|
110
|
+
export interface InternClient {
|
|
111
|
+
readonly transport: InternTransport;
|
|
112
|
+
health(options?: InternCallOptions): Promise<InternHealth>;
|
|
113
|
+
readiness(options?: InternCallOptions): Promise<InternReadiness>;
|
|
114
|
+
capabilities(
|
|
115
|
+
input?: InternCapabilitiesInput,
|
|
116
|
+
options?: InternCallOptions
|
|
117
|
+
): Promise<InternCapabilities>;
|
|
118
|
+
appBootstrap(options?: InternCallOptions): Promise<UnknownRecord>;
|
|
119
|
+
listRunners(options?: InternCallOptions): Promise<InternRunnerList>;
|
|
120
|
+
requireRunner(
|
|
121
|
+
runnerId: string,
|
|
122
|
+
options?: InternCallOptions
|
|
123
|
+
): Promise<InternRunner>;
|
|
124
|
+
listSessions(
|
|
125
|
+
input?: InternSessionListInput,
|
|
126
|
+
options?: InternCallOptions
|
|
127
|
+
): Promise<InternSessionList>;
|
|
128
|
+
createSession(
|
|
129
|
+
input: CreateInternSessionInput,
|
|
130
|
+
options?: InternCallOptions
|
|
131
|
+
): Promise<InternSession>;
|
|
132
|
+
getSession(
|
|
133
|
+
sessionId: string,
|
|
134
|
+
options?: InternCallOptions
|
|
135
|
+
): Promise<InternSession>;
|
|
136
|
+
listTurns(
|
|
137
|
+
sessionId: string,
|
|
138
|
+
input?: InternTurnListInput,
|
|
139
|
+
options?: InternCallOptions
|
|
140
|
+
): Promise<InternTurnList>;
|
|
141
|
+
startTurn(
|
|
142
|
+
sessionId: string,
|
|
143
|
+
input: StartInternTurnInput,
|
|
144
|
+
options?: InternCallOptions
|
|
145
|
+
): Promise<InternStartedTurn>;
|
|
146
|
+
getTurn(
|
|
147
|
+
sessionId: string,
|
|
148
|
+
turnId: string,
|
|
149
|
+
options?: InternCallOptions
|
|
150
|
+
): Promise<InternTurn>;
|
|
151
|
+
listTurnEvents(
|
|
152
|
+
sessionId: string,
|
|
153
|
+
turnId: string,
|
|
154
|
+
input?: InternEventListInput,
|
|
155
|
+
options?: InternCallOptions
|
|
156
|
+
): Promise<InternEventList>;
|
|
157
|
+
streamTurn(
|
|
158
|
+
sessionId: string,
|
|
159
|
+
turnId: string,
|
|
160
|
+
options?: InternTurnStreamOptions
|
|
161
|
+
): AsyncIterable<InternTurnStreamEvent>;
|
|
162
|
+
abortTurn(
|
|
163
|
+
sessionId: string,
|
|
164
|
+
turnId: string,
|
|
165
|
+
options?: InternCallOptions
|
|
166
|
+
): Promise<InternActionAcknowledgement>;
|
|
167
|
+
decideTurn(
|
|
168
|
+
sessionId: string,
|
|
169
|
+
turnId: string,
|
|
170
|
+
decision: InternTurnDecisionAction,
|
|
171
|
+
input?: InternApprovalInput,
|
|
172
|
+
options?: InternCallOptions
|
|
173
|
+
): Promise<InternTurnDecision>;
|
|
174
|
+
readArtifact(
|
|
175
|
+
artifactId: string,
|
|
176
|
+
input: InternArtifactInput,
|
|
177
|
+
options?: InternCallOptions
|
|
178
|
+
): Promise<InternArtifact>;
|
|
179
|
+
listApprovals(
|
|
180
|
+
input?: InternApprovalListInput,
|
|
181
|
+
options?: InternCallOptions
|
|
182
|
+
): Promise<InternApprovalList>;
|
|
183
|
+
decideApproval(
|
|
184
|
+
requestId: string | number,
|
|
185
|
+
decision: InternApprovalDecisionAction,
|
|
186
|
+
input?: InternApprovalInput,
|
|
187
|
+
options?: InternCallOptions
|
|
188
|
+
): Promise<InternApprovalDecision>;
|
|
189
|
+
pair(
|
|
190
|
+
input: InternPairInput,
|
|
191
|
+
options?: InternCallOptions
|
|
192
|
+
): Promise<InternPairResult>;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function pathId(value: string | number, label: string): string {
|
|
196
|
+
const normalized = String(value).trim();
|
|
197
|
+
if (!normalized) {
|
|
198
|
+
throw new InternClientError(
|
|
199
|
+
'validation_failed',
|
|
200
|
+
`${label} is required.`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
return encodeURIComponent(normalized);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function queryPath(
|
|
207
|
+
path: string,
|
|
208
|
+
values: Record<string, string | number | boolean | undefined>
|
|
209
|
+
): string {
|
|
210
|
+
const query = new URLSearchParams();
|
|
211
|
+
for (const [key, value] of Object.entries(values)) {
|
|
212
|
+
if (value !== undefined && value !== '') {
|
|
213
|
+
query.set(key, String(value));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const encoded = query.toString();
|
|
217
|
+
return encoded ? `${path}?${encoded}` : path;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function positiveInteger(
|
|
221
|
+
value: number | undefined,
|
|
222
|
+
label: string
|
|
223
|
+
): number | undefined {
|
|
224
|
+
if (value === undefined) return undefined;
|
|
225
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
226
|
+
throw new InternClientError(
|
|
227
|
+
'validation_failed',
|
|
228
|
+
`${label} must be a positive integer.`
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
return value;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function boundedPositiveInteger(
|
|
235
|
+
value: number | undefined,
|
|
236
|
+
label: string,
|
|
237
|
+
maximum: number
|
|
238
|
+
): number | undefined {
|
|
239
|
+
const normalized = positiveInteger(value, label);
|
|
240
|
+
if (normalized !== undefined && normalized > maximum) {
|
|
241
|
+
throw new InternClientError(
|
|
242
|
+
'validation_failed',
|
|
243
|
+
`${label} must not exceed ${maximum}.`
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
return normalized;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function appSessionKeyPrefix(
|
|
250
|
+
value: string | undefined
|
|
251
|
+
): string | undefined {
|
|
252
|
+
if (value === undefined) return undefined;
|
|
253
|
+
const normalized = value.trim();
|
|
254
|
+
if (
|
|
255
|
+
!normalized ||
|
|
256
|
+
new TextEncoder().encode(normalized).byteLength > 256 ||
|
|
257
|
+
/[\0\r\n]/.test(normalized)
|
|
258
|
+
) {
|
|
259
|
+
throw new InternClientError(
|
|
260
|
+
'validation_failed',
|
|
261
|
+
'App session key prefix is invalid.'
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
return normalized;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function nonNegativeInteger(
|
|
268
|
+
value: number | undefined,
|
|
269
|
+
label: string
|
|
270
|
+
): number | undefined {
|
|
271
|
+
if (value === undefined) return undefined;
|
|
272
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
273
|
+
throw new InternClientError(
|
|
274
|
+
'validation_failed',
|
|
275
|
+
`${label} must be a non-negative integer.`
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
return value;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function sessionPath(sessionId: string): string {
|
|
282
|
+
return `/internal/v1/runner-chat/sessions/${pathId(
|
|
283
|
+
sessionId,
|
|
284
|
+
'Session ID'
|
|
285
|
+
)}`;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function turnPath(sessionId: string, turnId: string): string {
|
|
289
|
+
return `${sessionPath(sessionId)}/turns/${pathId(turnId, 'Turn ID')}`;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function parseTurnStreamEvent(
|
|
293
|
+
event: InternSseEvent<UnknownRecord>
|
|
294
|
+
): InternTurnStreamEvent {
|
|
295
|
+
if (event.json === undefined) {
|
|
296
|
+
return event as InternTurnStreamEvent;
|
|
297
|
+
}
|
|
298
|
+
let json: InternEvent | UnknownRecord;
|
|
299
|
+
if (
|
|
300
|
+
typeof event.json.turn_id === 'string' &&
|
|
301
|
+
typeof event.json.seq === 'number'
|
|
302
|
+
) {
|
|
303
|
+
json = parseInternEvent(event.json);
|
|
304
|
+
} else {
|
|
305
|
+
json = parseInternRecord(event.json, 'streamEvent');
|
|
306
|
+
}
|
|
307
|
+
return { ...event, json };
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function findInternRunner(
|
|
311
|
+
list: InternRunnerList,
|
|
312
|
+
runnerId: string
|
|
313
|
+
): InternRunner {
|
|
314
|
+
const normalized = runnerId.trim();
|
|
315
|
+
const runner = list.runners.find((item) => item.id === normalized);
|
|
316
|
+
if (!runner) {
|
|
317
|
+
throw new InternUnavailableError(
|
|
318
|
+
`Runner ${normalized || '(missing)'} is not advertised by the selected host.`,
|
|
319
|
+
{ capability: `runner:${normalized || 'unknown'}` }
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
return runner;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export function requireInternRunner(
|
|
326
|
+
list: InternRunnerList,
|
|
327
|
+
runnerId: string
|
|
328
|
+
): InternRunner {
|
|
329
|
+
const runner = findInternRunner(list, runnerId);
|
|
330
|
+
if (runner.status !== 'available') {
|
|
331
|
+
throw new InternUnavailableError(
|
|
332
|
+
`Runner ${runner.id} is advertised but is not available (${runner.status || 'unknown status'}).`,
|
|
333
|
+
{
|
|
334
|
+
capability: `runner:${runner.id}`,
|
|
335
|
+
details: {
|
|
336
|
+
runnerId: runner.id,
|
|
337
|
+
status: runner.status,
|
|
338
|
+
authStatus: runner.auth_status,
|
|
339
|
+
},
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
return runner;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export function createInternClient(
|
|
347
|
+
options: InternTransportOptions
|
|
348
|
+
): InternClient {
|
|
349
|
+
const transport = createInternTransport(options);
|
|
350
|
+
|
|
351
|
+
const health = (callOptions: InternCallOptions = {}) =>
|
|
352
|
+
transport.request('/internal/v1/health', {
|
|
353
|
+
...callOptions,
|
|
354
|
+
method: 'GET',
|
|
355
|
+
parse: parseInternHealth,
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
const readiness = (callOptions: InternCallOptions = {}) =>
|
|
359
|
+
transport.request('/internal/v1/readiness', {
|
|
360
|
+
...callOptions,
|
|
361
|
+
method: 'GET',
|
|
362
|
+
acceptedStatuses: [503],
|
|
363
|
+
parse: parseInternReadiness,
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
const capabilities = (
|
|
367
|
+
input: InternCapabilitiesInput = {},
|
|
368
|
+
callOptions: InternCallOptions = {}
|
|
369
|
+
) =>
|
|
370
|
+
transport.request(
|
|
371
|
+
queryPath('/internal/v1/capabilities', {
|
|
372
|
+
channel: input.channel,
|
|
373
|
+
trigger: input.trigger,
|
|
374
|
+
}),
|
|
375
|
+
{
|
|
376
|
+
...callOptions,
|
|
377
|
+
method: 'GET',
|
|
378
|
+
parse: parseInternCapabilities,
|
|
379
|
+
}
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
const appBootstrap = (callOptions: InternCallOptions = {}) =>
|
|
383
|
+
transport.request('/internal/v1/app/bootstrap', {
|
|
384
|
+
...callOptions,
|
|
385
|
+
method: 'GET',
|
|
386
|
+
parse: (value) => parseInternRecord(value, 'appBootstrap'),
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
const listRunners = (callOptions: InternCallOptions = {}) =>
|
|
390
|
+
transport.request('/internal/v1/chat-runners', {
|
|
391
|
+
...callOptions,
|
|
392
|
+
method: 'GET',
|
|
393
|
+
parse: parseInternRunnerList,
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const requireRunner = async (
|
|
397
|
+
runnerId: string,
|
|
398
|
+
callOptions: InternCallOptions = {}
|
|
399
|
+
) => requireInternRunner(await listRunners(callOptions), runnerId);
|
|
400
|
+
|
|
401
|
+
const listSessions = async (
|
|
402
|
+
input: InternSessionListInput = {},
|
|
403
|
+
callOptions: InternCallOptions = {}
|
|
404
|
+
) =>
|
|
405
|
+
transport.request(
|
|
406
|
+
queryPath('/internal/v1/runner-chat/sessions', {
|
|
407
|
+
app_session_key_prefix: appSessionKeyPrefix(
|
|
408
|
+
input.appSessionKeyPrefix
|
|
409
|
+
),
|
|
410
|
+
limit: boundedPositiveInteger(
|
|
411
|
+
input.limit,
|
|
412
|
+
'Session limit',
|
|
413
|
+
100
|
|
414
|
+
),
|
|
415
|
+
}),
|
|
416
|
+
{
|
|
417
|
+
...callOptions,
|
|
418
|
+
method: 'GET',
|
|
419
|
+
parse: parseInternSessionList,
|
|
420
|
+
}
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
const createSession = (
|
|
424
|
+
input: CreateInternSessionInput,
|
|
425
|
+
callOptions: InternCallOptions = {}
|
|
426
|
+
) =>
|
|
427
|
+
transport.request('/internal/v1/runner-chat/sessions', {
|
|
428
|
+
...callOptions,
|
|
429
|
+
method: 'POST',
|
|
430
|
+
body: input,
|
|
431
|
+
parse: parseInternSession,
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
const getSession = async (
|
|
435
|
+
sessionId: string,
|
|
436
|
+
callOptions: InternCallOptions = {}
|
|
437
|
+
) =>
|
|
438
|
+
transport.request(sessionPath(sessionId), {
|
|
439
|
+
...callOptions,
|
|
440
|
+
method: 'GET',
|
|
441
|
+
parse: parseInternSession,
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
const listTurns = async (
|
|
445
|
+
sessionId: string,
|
|
446
|
+
input: InternTurnListInput = {},
|
|
447
|
+
callOptions: InternCallOptions = {}
|
|
448
|
+
) =>
|
|
449
|
+
transport.request(
|
|
450
|
+
queryPath(`${sessionPath(sessionId)}/turns`, {
|
|
451
|
+
limit: positiveInteger(input.limit, 'Turn limit'),
|
|
452
|
+
}),
|
|
453
|
+
{
|
|
454
|
+
...callOptions,
|
|
455
|
+
method: 'GET',
|
|
456
|
+
parse: parseInternTurnList,
|
|
457
|
+
}
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
const startTurn = async (
|
|
461
|
+
sessionId: string,
|
|
462
|
+
input: StartInternTurnInput,
|
|
463
|
+
callOptions: InternCallOptions = {}
|
|
464
|
+
) =>
|
|
465
|
+
transport.request(`${sessionPath(sessionId)}/turns`, {
|
|
466
|
+
...callOptions,
|
|
467
|
+
method: 'POST',
|
|
468
|
+
body: input,
|
|
469
|
+
parse: parseInternStartedTurn,
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
const getTurn = async (
|
|
473
|
+
sessionId: string,
|
|
474
|
+
turnId: string,
|
|
475
|
+
callOptions: InternCallOptions = {}
|
|
476
|
+
) =>
|
|
477
|
+
transport.request(turnPath(sessionId, turnId), {
|
|
478
|
+
...callOptions,
|
|
479
|
+
method: 'GET',
|
|
480
|
+
parse: parseInternTurn,
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
const listTurnEvents = async (
|
|
484
|
+
sessionId: string,
|
|
485
|
+
turnId: string,
|
|
486
|
+
input: InternEventListInput = {},
|
|
487
|
+
callOptions: InternCallOptions = {}
|
|
488
|
+
) =>
|
|
489
|
+
transport.request(
|
|
490
|
+
queryPath(`${turnPath(sessionId, turnId)}/events`, {
|
|
491
|
+
after_seq: nonNegativeInteger(
|
|
492
|
+
input.afterSeq,
|
|
493
|
+
'Event cursor'
|
|
494
|
+
),
|
|
495
|
+
limit: positiveInteger(input.limit, 'Event limit'),
|
|
496
|
+
}),
|
|
497
|
+
{
|
|
498
|
+
...callOptions,
|
|
499
|
+
method: 'GET',
|
|
500
|
+
parse: parseInternEventList,
|
|
501
|
+
}
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
async function* streamTurn(
|
|
505
|
+
sessionId: string,
|
|
506
|
+
turnId: string,
|
|
507
|
+
streamOptions: InternTurnStreamOptions = {}
|
|
508
|
+
): AsyncIterable<InternTurnStreamEvent> {
|
|
509
|
+
const { afterSeq, ...transportOptions } = streamOptions;
|
|
510
|
+
const stream = transport.stream<UnknownRecord>(
|
|
511
|
+
`${turnPath(sessionId, turnId)}/stream`,
|
|
512
|
+
{
|
|
513
|
+
...transportOptions,
|
|
514
|
+
method: 'GET',
|
|
515
|
+
reconnect: transportOptions.reconnect ?? true,
|
|
516
|
+
dedupe: transportOptions.dedupe ?? true,
|
|
517
|
+
resume: {
|
|
518
|
+
initialCursor: nonNegativeInteger(
|
|
519
|
+
afterSeq,
|
|
520
|
+
'Event cursor'
|
|
521
|
+
),
|
|
522
|
+
queryParameter: 'after_seq',
|
|
523
|
+
cursorFromEvent: (event) => {
|
|
524
|
+
const seq = event.json?.seq;
|
|
525
|
+
return typeof seq === 'string' ||
|
|
526
|
+
typeof seq === 'number'
|
|
527
|
+
? seq
|
|
528
|
+
: undefined;
|
|
529
|
+
},
|
|
530
|
+
},
|
|
531
|
+
isTerminal: (event) => event.event === 'done',
|
|
532
|
+
}
|
|
533
|
+
);
|
|
534
|
+
for await (const event of stream) {
|
|
535
|
+
yield parseTurnStreamEvent(event);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
const abortTurn = async (
|
|
540
|
+
sessionId: string,
|
|
541
|
+
turnId: string,
|
|
542
|
+
callOptions: InternCallOptions = {}
|
|
543
|
+
) =>
|
|
544
|
+
transport.request(`${turnPath(sessionId, turnId)}/abort`, {
|
|
545
|
+
...callOptions,
|
|
546
|
+
method: 'POST',
|
|
547
|
+
parse: parseInternActionAcknowledgement,
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
const decideTurn = async (
|
|
551
|
+
sessionId: string,
|
|
552
|
+
turnId: string,
|
|
553
|
+
decision: InternTurnDecisionAction,
|
|
554
|
+
input: InternApprovalInput = {},
|
|
555
|
+
callOptions: InternCallOptions = {}
|
|
556
|
+
) =>
|
|
557
|
+
transport.request(
|
|
558
|
+
`${turnPath(sessionId, turnId)}/${decision}`,
|
|
559
|
+
{
|
|
560
|
+
...callOptions,
|
|
561
|
+
method: 'POST',
|
|
562
|
+
body: {
|
|
563
|
+
note: input.note,
|
|
564
|
+
allow_session: input.allow_session,
|
|
565
|
+
},
|
|
566
|
+
parse: parseInternTurnDecision,
|
|
567
|
+
}
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
const readArtifact = async (
|
|
571
|
+
artifactId: string,
|
|
572
|
+
input: InternArtifactInput,
|
|
573
|
+
callOptions: InternCallOptions = {}
|
|
574
|
+
) =>
|
|
575
|
+
transport.request(
|
|
576
|
+
queryPath(
|
|
577
|
+
`/internal/v1/artifacts/${pathId(
|
|
578
|
+
artifactId,
|
|
579
|
+
'Artifact ID'
|
|
580
|
+
)}`,
|
|
581
|
+
{
|
|
582
|
+
session_key: input.sessionKey,
|
|
583
|
+
offset: nonNegativeInteger(
|
|
584
|
+
input.offset,
|
|
585
|
+
'Artifact offset'
|
|
586
|
+
),
|
|
587
|
+
max_bytes: positiveInteger(
|
|
588
|
+
input.maxBytes,
|
|
589
|
+
'Artifact byte limit'
|
|
590
|
+
),
|
|
591
|
+
}
|
|
592
|
+
),
|
|
593
|
+
{
|
|
594
|
+
...callOptions,
|
|
595
|
+
method: 'GET',
|
|
596
|
+
parse: parseInternArtifact,
|
|
597
|
+
}
|
|
598
|
+
);
|
|
599
|
+
|
|
600
|
+
const listApprovals = (
|
|
601
|
+
input: InternApprovalListInput = {},
|
|
602
|
+
callOptions: InternCallOptions = {}
|
|
603
|
+
) =>
|
|
604
|
+
transport.request(
|
|
605
|
+
queryPath('/internal/v1/approvals', {
|
|
606
|
+
status: input.status,
|
|
607
|
+
type: input.type,
|
|
608
|
+
}),
|
|
609
|
+
{
|
|
610
|
+
...callOptions,
|
|
611
|
+
method: 'GET',
|
|
612
|
+
parse: parseInternApprovalList,
|
|
613
|
+
}
|
|
614
|
+
);
|
|
615
|
+
|
|
616
|
+
const decideApproval = async (
|
|
617
|
+
requestId: string | number,
|
|
618
|
+
decision: InternApprovalDecisionAction,
|
|
619
|
+
input: InternApprovalInput = {},
|
|
620
|
+
callOptions: InternCallOptions = {}
|
|
621
|
+
) =>
|
|
622
|
+
transport.request(
|
|
623
|
+
`/internal/v1/approvals/${pathId(
|
|
624
|
+
requestId,
|
|
625
|
+
'Approval request ID'
|
|
626
|
+
)}/${decision}`,
|
|
627
|
+
{
|
|
628
|
+
...callOptions,
|
|
629
|
+
method: 'POST',
|
|
630
|
+
body:
|
|
631
|
+
decision === 'approve'
|
|
632
|
+
? { note: input.note, allowlist: input.allowlist }
|
|
633
|
+
: { note: input.note },
|
|
634
|
+
parse: parseInternApprovalDecision,
|
|
635
|
+
}
|
|
636
|
+
);
|
|
637
|
+
|
|
638
|
+
const pair = (
|
|
639
|
+
input: InternPairInput,
|
|
640
|
+
callOptions: InternCallOptions = {}
|
|
641
|
+
) =>
|
|
642
|
+
transport.request(
|
|
643
|
+
'/internal/v1/secure-connections/pairing/approve',
|
|
644
|
+
{
|
|
645
|
+
...callOptions,
|
|
646
|
+
method: 'POST',
|
|
647
|
+
body: input,
|
|
648
|
+
requireAuth: false,
|
|
649
|
+
parse: parseInternPairResult,
|
|
650
|
+
}
|
|
651
|
+
);
|
|
652
|
+
|
|
653
|
+
return {
|
|
654
|
+
transport,
|
|
655
|
+
health,
|
|
656
|
+
readiness,
|
|
657
|
+
capabilities,
|
|
658
|
+
appBootstrap,
|
|
659
|
+
listRunners,
|
|
660
|
+
requireRunner,
|
|
661
|
+
listSessions,
|
|
662
|
+
createSession,
|
|
663
|
+
getSession,
|
|
664
|
+
listTurns,
|
|
665
|
+
startTurn,
|
|
666
|
+
getTurn,
|
|
667
|
+
listTurnEvents,
|
|
668
|
+
streamTurn,
|
|
669
|
+
abortTurn,
|
|
670
|
+
decideTurn,
|
|
671
|
+
readArtifact,
|
|
672
|
+
listApprovals,
|
|
673
|
+
decideApproval,
|
|
674
|
+
pair,
|
|
675
|
+
};
|
|
676
|
+
}
|