@volter/supercode-frontend-vscode 0.1.11
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/NOTICE.md +19 -0
- package/README.md +293 -0
- package/dist/bindings.d.ts +7 -0
- package/dist/bindings.js +5 -0
- package/dist/client.d.ts +11 -0
- package/dist/client.js +5 -0
- package/dist/context.d.ts +6 -0
- package/dist/context.js +14 -0
- package/dist/credential.d.ts +17 -0
- package/dist/credential.js +53 -0
- package/dist/extension.d.ts +39 -0
- package/dist/extension.js +1131 -0
- package/dist/host-controls.d.ts +58 -0
- package/dist/host-controls.js +66 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +5 -0
- package/dist/native-session.d.ts +6 -0
- package/dist/native-session.js +41 -0
- package/dist/proposals.d.ts +24 -0
- package/dist/proposals.js +54 -0
- package/dist/session.d.ts +154 -0
- package/dist/session.js +431 -0
- package/dist/view.d.ts +176 -0
- package/dist/view.js +717 -0
- package/media/anthropic.svg +1 -0
- package/media/google.svg +1 -0
- package/media/icon.png +0 -0
- package/media/openai.svg +1 -0
- package/package.json +200 -0
- package/scripts/pack-extension.mjs +63 -0
- package/vendor/supercode-frontend/README.md +22 -0
- package/vendor/supercode-frontend/client.d.mts +106 -0
- package/vendor/supercode-frontend/client.mjs +300 -0
- package/vendor/supercode-frontend/contract.json +289 -0
- package/vendor/supercode-frontend/generated-client.d.mts +18 -0
- package/vendor/supercode-frontend/generated-client.mjs +20 -0
- package/vendor/supercode-frontend/generated.d.mts +146 -0
- package/vendor/supercode-frontend/generated.mjs +19 -0
- package/vendor/supercode-frontend/package.json +20 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { FRONTEND_METHODS, FRONTEND_SCHEMA } from './generated.mjs';
|
|
2
|
+
import { GeneratedFrontendClient } from './generated-client.mjs';
|
|
3
|
+
|
|
4
|
+
export { FRONTEND_EVENT_METHOD, FRONTEND_METHODS, FRONTEND_SCHEMA } from './generated.mjs';
|
|
5
|
+
export { GeneratedFrontendClient } from './generated-client.mjs';
|
|
6
|
+
|
|
7
|
+
class FrontendEmitter extends GeneratedFrontendClient {
|
|
8
|
+
#listeners = new Map();
|
|
9
|
+
|
|
10
|
+
on(event, listener) {
|
|
11
|
+
if (typeof listener !== 'function') throw new TypeError('listener must be a function');
|
|
12
|
+
const listeners = this.#listeners.get(event) ?? new Set();
|
|
13
|
+
listeners.add(listener);
|
|
14
|
+
this.#listeners.set(event, listeners);
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
off(event, listener) {
|
|
19
|
+
const listeners = this.#listeners.get(event);
|
|
20
|
+
listeners?.delete(listener);
|
|
21
|
+
if (listeners?.size === 0) this.#listeners.delete(event);
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
once(event, listener) {
|
|
26
|
+
const onceListener = (...args) => {
|
|
27
|
+
this.off(event, onceListener);
|
|
28
|
+
listener(...args);
|
|
29
|
+
};
|
|
30
|
+
return this.on(event, onceListener);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
emit(event, ...args) {
|
|
34
|
+
for (const listener of [...(this.#listeners.get(event) ?? [])]) listener(...args);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class FrontendClientError extends Error {
|
|
39
|
+
constructor(error) {
|
|
40
|
+
super(error?.message ?? 'frontend request failed');
|
|
41
|
+
this.name = error?.name ?? 'transport';
|
|
42
|
+
this.code = error?.code ?? null;
|
|
43
|
+
this.operation = error?.operation ?? null;
|
|
44
|
+
this.permission = error?.permission ?? null;
|
|
45
|
+
this.holder = error?.holder ?? null;
|
|
46
|
+
this.expiresAtMs = error?.expiresAtMs ?? null;
|
|
47
|
+
this.extensions = {
|
|
48
|
+
...(error?.extensions && typeof error.extensions === 'object' ? error.extensions : {}),
|
|
49
|
+
...Object.fromEntries(
|
|
50
|
+
Object.entries(error ?? {}).filter(([key]) => !['name', 'message', 'code', 'operation', 'permission', 'holder', 'expiresAtMs', 'extensions'].includes(key)),
|
|
51
|
+
),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function requiredString(value, label) {
|
|
57
|
+
if (typeof value !== 'string' || value.length === 0) throw new TypeError(`${label} must be a non-empty string`);
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function randomClientId() {
|
|
62
|
+
return `ts-${globalThis.crypto.randomUUID()}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function validateDescriptor(descriptor) {
|
|
66
|
+
if (!descriptor || descriptor.schema_version !== 2 || typeof descriptor.session_id !== 'string') {
|
|
67
|
+
throw new FrontendClientError({ name: 'transport', message: `peer is not ${FRONTEND_SCHEMA}` });
|
|
68
|
+
}
|
|
69
|
+
return descriptor;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export class FrontendClient extends FrontendEmitter {
|
|
73
|
+
#baseUrl;
|
|
74
|
+
#token;
|
|
75
|
+
#clientId;
|
|
76
|
+
#permissions;
|
|
77
|
+
#nextId = 1;
|
|
78
|
+
#fetch;
|
|
79
|
+
#eventAbort = null;
|
|
80
|
+
#pendingEventResponse = null;
|
|
81
|
+
#lastSequence = 0;
|
|
82
|
+
|
|
83
|
+
constructor({ baseUrl, token, clientId = randomClientId(), permissions = ['observe', 'interact', 'approve'], fetch = globalThis.fetch }) {
|
|
84
|
+
super();
|
|
85
|
+
this.#baseUrl = requiredString(baseUrl, 'baseUrl').replace(/\/$/, '');
|
|
86
|
+
this.#token = requiredString(token, 'token');
|
|
87
|
+
this.#clientId = requiredString(clientId, 'clientId');
|
|
88
|
+
this.#permissions = [...permissions];
|
|
89
|
+
if (typeof fetch !== 'function') throw new TypeError('fetch implementation is required');
|
|
90
|
+
// Browser-native `window.fetch` performs a receiver brand check. Calling
|
|
91
|
+
// it later as `this.#fetch(...)` would bind `this` to FrontendClient and
|
|
92
|
+
// throw `Illegal invocation`; bind only the native global while leaving
|
|
93
|
+
// injected test/host implementations receiver-neutral.
|
|
94
|
+
this.#fetch = fetch === globalThis.fetch ? fetch.bind(globalThis) : (...args) => fetch(...args);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get clientId() { return this.#clientId; }
|
|
98
|
+
get lastSequence() { return this.#lastSequence; }
|
|
99
|
+
|
|
100
|
+
headers() {
|
|
101
|
+
return {
|
|
102
|
+
authorization: `Bearer ${this.#token}`,
|
|
103
|
+
'content-type': 'application/json',
|
|
104
|
+
'x-supercode-client-id': this.#clientId,
|
|
105
|
+
'x-supercode-permissions': this.#permissions.join(','),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async rpc(method, params = {}, options = {}) {
|
|
110
|
+
const response = await this.#fetch(`${this.#baseUrl}/rpc`, {
|
|
111
|
+
method: 'POST',
|
|
112
|
+
headers: this.headers(),
|
|
113
|
+
body: JSON.stringify({ jsonrpc: '2.0', id: this.#nextId++, method, params }),
|
|
114
|
+
signal: options.signal,
|
|
115
|
+
});
|
|
116
|
+
if (!response.ok) throw new FrontendClientError({ name: 'transport', message: `frontend HTTP ${response.status}` });
|
|
117
|
+
const envelope = await response.json();
|
|
118
|
+
if (envelope.error) throw new FrontendClientError(envelope.error);
|
|
119
|
+
return envelope.result;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async describe(options) { return validateDescriptor(await this.rpc(FRONTEND_METHODS.describe, {}, options)); }
|
|
123
|
+
async attach(limit = 1000, { afterSequence = 0, ...options } = {}) {
|
|
124
|
+
// Establish the live subscription before taking the snapshot. The body
|
|
125
|
+
// stream buffers while the RPC is in flight, so every racing event is in
|
|
126
|
+
// either snapshot.replay or this already-open stream.
|
|
127
|
+
if (!this.#eventAbort) this.#pendingEventResponse = await this.#openEventStream(null, options.signal);
|
|
128
|
+
let snapshot;
|
|
129
|
+
try {
|
|
130
|
+
snapshot = await super.attach(limit, { afterSequence, ...options });
|
|
131
|
+
} catch (error) {
|
|
132
|
+
this.stopEvents();
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
validateDescriptor(snapshot?.descriptor);
|
|
136
|
+
if (!Array.isArray(snapshot.history) || !Array.isArray(snapshot.replay) || !Number.isSafeInteger(snapshot.history_cursor)) {
|
|
137
|
+
throw new FrontendClientError({ name: 'transport', message: 'invalid frontend attachment snapshot' });
|
|
138
|
+
}
|
|
139
|
+
this.#lastSequence = Math.max(this.#lastSequence, afterSequence, snapshot.history_cursor);
|
|
140
|
+
snapshot.replay = snapshot.replay.filter((event) => event.sequence > this.#lastSequence);
|
|
141
|
+
for (const event of snapshot.replay) this.#lastSequence = Math.max(this.#lastSequence, event.sequence);
|
|
142
|
+
return snapshot;
|
|
143
|
+
}
|
|
144
|
+
async #openEventStream(afterSequence, signal) {
|
|
145
|
+
if (this.#eventAbort) throw new FrontendClientError({ name: 'transport', message: 'frontend event stream already active' });
|
|
146
|
+
const controller = new AbortController();
|
|
147
|
+
this.#eventAbort = controller;
|
|
148
|
+
if (signal) signal.addEventListener('abort', () => controller.abort(), { once: true });
|
|
149
|
+
try {
|
|
150
|
+
const suffix = afterSequence === null ? '' : `?after_sequence=${encodeURIComponent(afterSequence)}`;
|
|
151
|
+
const response = await this.#fetch(`${this.#baseUrl}/frontend/events${suffix}`, {
|
|
152
|
+
headers: this.headers(),
|
|
153
|
+
signal: controller.signal,
|
|
154
|
+
});
|
|
155
|
+
if (!response.ok || !response.body) throw new FrontendClientError({ name: 'transport', message: `frontend events HTTP ${response.status}` });
|
|
156
|
+
return response;
|
|
157
|
+
} catch (error) {
|
|
158
|
+
this.#eventAbort = null;
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async startEvents({ afterSequence = this.#lastSequence, signal } = {}) {
|
|
164
|
+
const response = this.#pendingEventResponse ?? await this.#openEventStream(afterSequence, signal);
|
|
165
|
+
this.#pendingEventResponse = null;
|
|
166
|
+
try {
|
|
167
|
+
const decoder = new TextDecoder();
|
|
168
|
+
let pending = '';
|
|
169
|
+
for await (const chunk of response.body) {
|
|
170
|
+
pending += decoder.decode(chunk, { stream: true });
|
|
171
|
+
let boundary;
|
|
172
|
+
while ((boundary = pending.indexOf('\n')) >= 0) {
|
|
173
|
+
const line = pending.slice(0, boundary).replace(/\r$/, '');
|
|
174
|
+
pending = pending.slice(boundary + 1);
|
|
175
|
+
if (!line.startsWith('data: ')) continue;
|
|
176
|
+
const event = JSON.parse(line.slice(6));
|
|
177
|
+
if (!Number.isSafeInteger(event.sequence) || event.sequence <= afterSequence || event.sequence <= this.#lastSequence) continue;
|
|
178
|
+
this.#lastSequence = event.sequence;
|
|
179
|
+
this.emit('event', event);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
} finally {
|
|
183
|
+
this.#eventAbort = null;
|
|
184
|
+
this.#pendingEventResponse = null;
|
|
185
|
+
this.emit('disconnect');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
stopEvents() {
|
|
190
|
+
this.#pendingEventResponse = null;
|
|
191
|
+
this.#eventAbort?.abort();
|
|
192
|
+
}
|
|
193
|
+
async detach(options) {
|
|
194
|
+
const result = await this.rpc(FRONTEND_METHODS.detach, {}, options);
|
|
195
|
+
this.stopEvents();
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
async close(options) {
|
|
199
|
+
const result = await this.rpc(FRONTEND_METHODS.close, {}, options);
|
|
200
|
+
this.stopEvents();
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Header-capable WebSocket binding. The injected factory receives the exact
|
|
206
|
+
* authentication headers; browser-only factories must not move secrets into
|
|
207
|
+
* URLs and should use the HTTP/SSE client until an approved cookie/token
|
|
208
|
+
* bootstrap exists. */
|
|
209
|
+
export class FrontendWebSocketClient extends FrontendEmitter {
|
|
210
|
+
#socket;
|
|
211
|
+
#nextId = 1;
|
|
212
|
+
#pending = new Map();
|
|
213
|
+
#lastSequence = 0;
|
|
214
|
+
|
|
215
|
+
constructor(socket) {
|
|
216
|
+
super();
|
|
217
|
+
if (!socket || typeof socket.send !== 'function' || typeof socket.addEventListener !== 'function') {
|
|
218
|
+
throw new TypeError('an open WebSocket-compatible transport is required');
|
|
219
|
+
}
|
|
220
|
+
this.#socket = socket;
|
|
221
|
+
socket.addEventListener('message', (message) => this.#receive(message.data));
|
|
222
|
+
socket.addEventListener('close', () => this.#disconnect('WebSocket transport closed'));
|
|
223
|
+
socket.addEventListener('error', () => this.#disconnect('WebSocket transport failed'));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
static async connect({ url, token, clientId = randomClientId(), permissions = ['observe', 'interact', 'approve'], webSocketFactory }) {
|
|
227
|
+
requiredString(url, 'url');
|
|
228
|
+
requiredString(token, 'token');
|
|
229
|
+
if (typeof webSocketFactory !== 'function') throw new TypeError('header-capable webSocketFactory is required');
|
|
230
|
+
const socket = await webSocketFactory({
|
|
231
|
+
url,
|
|
232
|
+
headers: {
|
|
233
|
+
authorization: `Bearer ${token}`,
|
|
234
|
+
'x-supercode-client-id': requiredString(clientId, 'clientId'),
|
|
235
|
+
'x-supercode-permissions': [...permissions].join(','),
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
return new FrontendWebSocketClient(socket);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
get lastSequence() { return this.#lastSequence; }
|
|
242
|
+
|
|
243
|
+
#receive(data) {
|
|
244
|
+
let envelope;
|
|
245
|
+
try {
|
|
246
|
+
envelope = JSON.parse(typeof data === 'string' ? data : new TextDecoder().decode(data));
|
|
247
|
+
} catch (error) {
|
|
248
|
+
this.emit('protocolError', error);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (envelope.method === 'frontend.v2.event') {
|
|
252
|
+
const event = envelope.params?.event;
|
|
253
|
+
if (event && Number.isSafeInteger(event.sequence) && event.sequence > this.#lastSequence) {
|
|
254
|
+
this.#lastSequence = event.sequence;
|
|
255
|
+
this.emit('event', event);
|
|
256
|
+
}
|
|
257
|
+
if (envelope.params?.error) this.emit('protocolError', new FrontendClientError(envelope.params.error));
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const pending = this.#pending.get(envelope.id);
|
|
261
|
+
if (!pending) return;
|
|
262
|
+
this.#pending.delete(envelope.id);
|
|
263
|
+
if (envelope.error) pending.reject(new FrontendClientError(envelope.error));
|
|
264
|
+
else pending.resolve(envelope.result);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
#disconnect(message) {
|
|
268
|
+
for (const pending of this.#pending.values()) {
|
|
269
|
+
pending.reject(new FrontendClientError({name:'transport', message}));
|
|
270
|
+
}
|
|
271
|
+
this.#pending.clear();
|
|
272
|
+
this.emit('disconnect');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
rpc(method, params = {}) {
|
|
276
|
+
const id = this.#nextId++;
|
|
277
|
+
return new Promise((resolve, reject) => {
|
|
278
|
+
this.#pending.set(id, {resolve, reject});
|
|
279
|
+
try {
|
|
280
|
+
this.#socket.send(JSON.stringify({jsonrpc:'2.0', id, method, params}));
|
|
281
|
+
} catch (error) {
|
|
282
|
+
this.#pending.delete(id);
|
|
283
|
+
reject(new FrontendClientError({name:'transport', message:String(error)}));
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async describe() { return validateDescriptor(await this.rpc(FRONTEND_METHODS.describe)); }
|
|
289
|
+
async attach(limit = 1000, {afterSequence = 0} = {}) {
|
|
290
|
+
const snapshot = await this.rpc(FRONTEND_METHODS.attach, {limit, after_sequence:afterSequence});
|
|
291
|
+
validateDescriptor(snapshot?.descriptor);
|
|
292
|
+
this.#lastSequence = Math.max(this.#lastSequence, afterSequence, snapshot.history_cursor);
|
|
293
|
+
snapshot.replay = snapshot.replay.filter((event) => event.sequence > this.#lastSequence);
|
|
294
|
+
for (const event of snapshot.replay) this.#lastSequence = Math.max(this.#lastSequence, event.sequence);
|
|
295
|
+
return snapshot;
|
|
296
|
+
}
|
|
297
|
+
async detach() { const result = await this.rpc(FRONTEND_METHODS.detach); this.closeTransport(); return result; }
|
|
298
|
+
async close() { const result = await this.rpc(FRONTEND_METHODS.close); this.closeTransport(); return result; }
|
|
299
|
+
closeTransport() { this.#socket.close(); }
|
|
300
|
+
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "supercode.frontend.contract.v2",
|
|
3
|
+
"version": 2,
|
|
4
|
+
"canonical_sdk": "supercode.sdk.v1",
|
|
5
|
+
"description": "Language-neutral attachment facade over one SDK-owned runtime. Transport and client metadata are envelopes and never canonical session data.",
|
|
6
|
+
"opaque_extensions": {
|
|
7
|
+
"events": "FrontendEvent.payload",
|
|
8
|
+
"requests": "FrontendRequest.payload",
|
|
9
|
+
"compatibility": "FrontendRuntimeDescriptor.extensions",
|
|
10
|
+
"errors": "FrontendError.extensions",
|
|
11
|
+
"rule": "Unknown compatible fields are retained by clients and adapters but never written into canonical sessions, sidecars, reduction logs, or native exports."
|
|
12
|
+
},
|
|
13
|
+
"traced_needs": {
|
|
14
|
+
"source": "scripts/client-protocol-corpus/allowlist.json",
|
|
15
|
+
"families": [
|
|
16
|
+
"identity",
|
|
17
|
+
"history",
|
|
18
|
+
"cursor_replay",
|
|
19
|
+
"sequenced_events",
|
|
20
|
+
"capabilities",
|
|
21
|
+
"requests",
|
|
22
|
+
"semantic_actions",
|
|
23
|
+
"typed_errors",
|
|
24
|
+
"reconnect"
|
|
25
|
+
],
|
|
26
|
+
"excluded_private_protocols": ["codex_app_server", "opencode_http", "goose_acp_extensions", "pi_rpc"]
|
|
27
|
+
},
|
|
28
|
+
"types": {
|
|
29
|
+
"JsonValue": {"kind": "json"},
|
|
30
|
+
"Empty": {"kind": "object", "fields": {}},
|
|
31
|
+
"ChatRole": {"kind": "enum", "values": ["system", "user", "assistant", "tool"]},
|
|
32
|
+
"FunctionCall": {
|
|
33
|
+
"kind": "object",
|
|
34
|
+
"fields": {
|
|
35
|
+
"name": {"type": "string"},
|
|
36
|
+
"arguments": {"type": "string"}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"ToolCall": {
|
|
40
|
+
"kind": "object",
|
|
41
|
+
"fields": {
|
|
42
|
+
"id": {"type": "string"},
|
|
43
|
+
"type": {"type": "string"},
|
|
44
|
+
"function": {"type": "FunctionCall"}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"ChatMessage": {
|
|
48
|
+
"kind": "object",
|
|
49
|
+
"fields": {
|
|
50
|
+
"role": {"type": "ChatRole"},
|
|
51
|
+
"content": {"type": {"kind": "union", "members": ["string", {"kind": "array", "items": "JsonValue"}]}, "optional": true},
|
|
52
|
+
"tool_calls": {"type": {"kind": "array", "items": "ToolCall"}, "optional": true},
|
|
53
|
+
"tool_call_id": {"type": "string", "optional": true},
|
|
54
|
+
"name": {"type": "string", "optional": true}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"FrontendActions": {
|
|
58
|
+
"kind": "object",
|
|
59
|
+
"fields": {
|
|
60
|
+
"submit": {"type": "boolean"},
|
|
61
|
+
"interrupt": {"type": "boolean"},
|
|
62
|
+
"steer": {"type": "boolean"},
|
|
63
|
+
"respond": {"type": "boolean"},
|
|
64
|
+
"detach": {"type": "boolean"},
|
|
65
|
+
"close": {"type": "boolean"}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"FrontendCommandDescriptor": {
|
|
69
|
+
"kind": "object",
|
|
70
|
+
"fields": {
|
|
71
|
+
"name": {"type": "string"},
|
|
72
|
+
"description": {"type": "string", "nullable": true},
|
|
73
|
+
"argument_hint": {"type": "string", "optional": true, "nullable": true}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"FrontendOperationKind": {"kind": "enum", "values": ["prompt", "file", "model", "session", "subagent", "image", "reduction"]},
|
|
77
|
+
"FrontendOperationDescriptor": {
|
|
78
|
+
"kind": "object",
|
|
79
|
+
"fields": {
|
|
80
|
+
"id": {"type": "string"},
|
|
81
|
+
"kind": {"type": "FrontendOperationKind"},
|
|
82
|
+
"command": {"type": "FrontendCommandDescriptor", "nullable": true}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"FrontendDisplayCapabilities": {
|
|
86
|
+
"kind": "object",
|
|
87
|
+
"fields": {
|
|
88
|
+
"event_kinds": {"type": {"kind": "array", "items": "string"}},
|
|
89
|
+
"opaque_fallback": {"type": "boolean"}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"FrontendTurnState": {"kind": "enum", "values": ["idle", "busy"]},
|
|
93
|
+
"FrontendConnectionState": {"kind": "enum", "values": ["connected", "shutting_down"]},
|
|
94
|
+
"FrontendRuntimeDescriptor": {
|
|
95
|
+
"kind": "object",
|
|
96
|
+
"extensible": true,
|
|
97
|
+
"fields": {
|
|
98
|
+
"schema_version": {"type": "u32", "const": 2},
|
|
99
|
+
"session_id": {"type": "string"},
|
|
100
|
+
"source_harness": {"type": "string", "nullable": true},
|
|
101
|
+
"emulation_profile": {"type": "string", "nullable": true},
|
|
102
|
+
"active_modules": {"type": {"kind": "array", "items": "string"}},
|
|
103
|
+
"commands": {"type": {"kind": "array", "items": "FrontendCommandDescriptor"}},
|
|
104
|
+
"operations": {"type": {"kind": "array", "items": "FrontendOperationDescriptor"}},
|
|
105
|
+
"actions": {"type": "FrontendActions"},
|
|
106
|
+
"display": {"type": "FrontendDisplayCapabilities"},
|
|
107
|
+
"model": {"type": "string"},
|
|
108
|
+
"turn_state": {"type": "FrontendTurnState"},
|
|
109
|
+
"connection_state": {"type": "FrontendConnectionState"},
|
|
110
|
+
"extensions": {"type": {"kind": "map", "values": "JsonValue"}, "optional": true}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"FrontendRequestKind": {"kind": "enum", "values": ["approval", "elicitation", "other"]},
|
|
114
|
+
"FrontendRequest": {
|
|
115
|
+
"kind": "object",
|
|
116
|
+
"extensible": true,
|
|
117
|
+
"fields": {
|
|
118
|
+
"id": {"type": "u64"},
|
|
119
|
+
"kind": {"type": "FrontendRequestKind"},
|
|
120
|
+
"payload": {"type": "JsonValue"}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"FrontendRequestEventPayload": {
|
|
124
|
+
"kind": "object",
|
|
125
|
+
"extensible": true,
|
|
126
|
+
"fields": {
|
|
127
|
+
"type": {"type": "string", "const": "request"},
|
|
128
|
+
"request": {"type": "FrontendRequest"}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
"FrontendEventPayload": {"kind": "union", "members": ["FrontendRequestEventPayload", "JsonValue"]},
|
|
132
|
+
"FrontendEvent": {
|
|
133
|
+
"kind": "object",
|
|
134
|
+
"fields": {
|
|
135
|
+
"sequence": {"type": "u64"},
|
|
136
|
+
"kind": {"type": "string"},
|
|
137
|
+
"payload": {"type": "FrontendEventPayload"}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"FrontendAttachSnapshot": {
|
|
141
|
+
"kind": "object",
|
|
142
|
+
"fields": {
|
|
143
|
+
"descriptor": {"type": "FrontendRuntimeDescriptor"},
|
|
144
|
+
"history": {"type": {"kind": "array", "items": "ChatMessage"}},
|
|
145
|
+
"history_cursor": {"type": "u64"},
|
|
146
|
+
"replay": {"type": {"kind": "array", "items": "FrontendEvent"}}
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
"FrontendApprovalDecision": {"kind": "enum", "values": ["deny", "allow", "allow_for_session"]},
|
|
150
|
+
"FrontendElicitationAction": {"kind": "enum", "values": ["accept", "decline", "cancel"]},
|
|
151
|
+
"FrontendResponse": {
|
|
152
|
+
"kind": "tagged_union",
|
|
153
|
+
"tag": "kind",
|
|
154
|
+
"variants": {
|
|
155
|
+
"approval": {
|
|
156
|
+
"request_id": {"type": "u64"},
|
|
157
|
+
"decision": {"type": "FrontendApprovalDecision"}
|
|
158
|
+
},
|
|
159
|
+
"elicitation": {
|
|
160
|
+
"request_id": {"type": "u64"},
|
|
161
|
+
"action": {"type": "FrontendElicitationAction"},
|
|
162
|
+
"content": {"type": "JsonValue", "optional": true, "nullable": true}
|
|
163
|
+
},
|
|
164
|
+
"other": {
|
|
165
|
+
"request_id": {"type": "u64"},
|
|
166
|
+
"action": {"type": "FrontendElicitationAction"},
|
|
167
|
+
"content": {"type": "JsonValue", "optional": true, "nullable": true}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"FrontendOperationInvocation": {
|
|
172
|
+
"kind": "tagged_union",
|
|
173
|
+
"tag": "kind",
|
|
174
|
+
"variants": {
|
|
175
|
+
"prompt": {
|
|
176
|
+
"operation_id": {"type": "string"},
|
|
177
|
+
"arguments": {"type": "string"}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"FrontendOperationResult": {
|
|
182
|
+
"kind": "tagged_union",
|
|
183
|
+
"tag": "kind",
|
|
184
|
+
"variants": {
|
|
185
|
+
"prompt": {"reply": {"type": "string"}}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
"RuntimeControllerLease": {
|
|
189
|
+
"kind": "object",
|
|
190
|
+
"fields": {
|
|
191
|
+
"client_id": {"type": "string"},
|
|
192
|
+
"expires_at_ms": {"type": "u64"}
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
"RuntimeObserverLease": {
|
|
196
|
+
"kind": "object",
|
|
197
|
+
"fields": {
|
|
198
|
+
"client_id": {"type": "string"},
|
|
199
|
+
"last_seen_ms": {"type": "u64"}
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"RuntimeLeaseSnapshot": {
|
|
203
|
+
"kind": "object",
|
|
204
|
+
"fields": {
|
|
205
|
+
"controller": {"type": "RuntimeControllerLease", "nullable": true},
|
|
206
|
+
"observers": {"type": {"kind": "array", "items": "RuntimeObserverLease"}},
|
|
207
|
+
"lease_ttl_ms": {"type": "u64"}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
"FrontendErrorName": {
|
|
211
|
+
"kind": "enum",
|
|
212
|
+
"values": ["unauthenticated", "unauthorized", "controller_required", "lease_expired", "invalid_argument", "not_found", "busy", "unsupported_action", "execution", "transport"]
|
|
213
|
+
},
|
|
214
|
+
"FrontendError": {
|
|
215
|
+
"kind": "object",
|
|
216
|
+
"extensible": true,
|
|
217
|
+
"fields": {
|
|
218
|
+
"name": {"type": "FrontendErrorName"},
|
|
219
|
+
"message": {"type": "string"},
|
|
220
|
+
"code": {"type": "i64", "optional": true},
|
|
221
|
+
"operation": {"type": "string", "optional": true},
|
|
222
|
+
"permission": {"type": "string", "optional": true},
|
|
223
|
+
"holder": {"type": "string", "optional": true, "nullable": true},
|
|
224
|
+
"expiresAtMs": {"type": "u64", "optional": true, "nullable": true},
|
|
225
|
+
"extensions": {"type": {"kind": "map", "values": "JsonValue"}, "optional": true}
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
"AttachParams": {
|
|
229
|
+
"kind": "object",
|
|
230
|
+
"fields": {
|
|
231
|
+
"limit": {"type": "u64"},
|
|
232
|
+
"after_sequence": {"type": "u64", "optional": true}
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
"PromptParams": {"kind": "object", "fields": {"prompt": {"type": "string"}}},
|
|
236
|
+
"MultimodalPromptParams": {
|
|
237
|
+
"kind": "object",
|
|
238
|
+
"fields": {
|
|
239
|
+
"prompt": {"type": "string"},
|
|
240
|
+
"image_urls": {"type": {"kind": "array", "items": "string"}, "optional": true}
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
"RespondParams": {"kind": "object", "fields": {"response": {"type": "FrontendResponse"}}},
|
|
244
|
+
"InvokeParams": {"kind": "object", "fields": {"operation": {"type": "FrontendOperationInvocation"}}},
|
|
245
|
+
"Accepted": {"kind": "object", "fields": {"accepted": {"type": "boolean"}}},
|
|
246
|
+
"Reply": {"kind": "object", "fields": {"reply": {"type": "string"}}},
|
|
247
|
+
"Interrupted": {"kind": "object", "fields": {"interrupted": {"type": "boolean"}}},
|
|
248
|
+
"Queued": {"kind": "object", "fields": {"queued": {"type": "boolean"}}},
|
|
249
|
+
"Closed": {"kind": "object", "fields": {"closed": {"type": "boolean"}}}
|
|
250
|
+
},
|
|
251
|
+
"methods": [
|
|
252
|
+
{"id": "describe", "wire": "frontend.v2.describe", "sdk_action": "resume", "params": "Empty", "result": "FrontendRuntimeDescriptor", "transports": ["local", "http", "websocket", "acp"]},
|
|
253
|
+
{"id": "attach", "wire": "frontend.v2.attach", "sdk_action": "events", "params": "AttachParams", "result": "FrontendAttachSnapshot", "transports": ["local", "http", "websocket", "acp"]},
|
|
254
|
+
{"id": "send_input", "wire": "frontend.v2.send_input", "sdk_action": "input", "params": "MultimodalPromptParams", "result": "Accepted", "transports": ["local", "http", "websocket", "acp"]},
|
|
255
|
+
{"id": "submit", "wire": "frontend.v2.submit", "sdk_action": "input", "params": "MultimodalPromptParams", "result": "Reply", "compatibility": "completion_waiting_alias", "transports": ["local", "http", "websocket", "acp"]},
|
|
256
|
+
{"id": "interrupt", "wire": "frontend.v2.interrupt", "sdk_action": "interrupt", "params": "Empty", "result": "Interrupted", "transports": ["local", "http", "websocket", "acp"]},
|
|
257
|
+
{"id": "steer", "wire": "frontend.v2.steer", "sdk_action": "steer", "params": "PromptParams", "result": "Queued", "transports": ["local", "http", "websocket", "acp"]},
|
|
258
|
+
{"id": "respond", "wire": "frontend.v2.respond", "sdk_action": "respond", "params": "RespondParams", "result": "Accepted", "transports": ["local", "http", "websocket", "acp"]},
|
|
259
|
+
{"id": "invoke", "wire": "frontend.v2.invoke", "sdk_action": "input", "params": "InvokeParams", "result": "FrontendOperationResult", "transports": ["local", "http", "websocket", "acp"]},
|
|
260
|
+
{"id": "lease", "wire": "frontend.v2.lease", "sdk_action": "events", "params": "Empty", "result": "RuntimeLeaseSnapshot", "transports": ["local", "http", "websocket", "acp"]},
|
|
261
|
+
{"id": "acquire_control", "wire": "frontend.v2.acquire_control", "sdk_action": "input", "params": "Empty", "result": "RuntimeLeaseSnapshot", "transports": ["local", "http", "websocket", "acp"]},
|
|
262
|
+
{"id": "take_control", "wire": "frontend.v2.take_control", "sdk_action": "input", "params": "Empty", "result": "RuntimeLeaseSnapshot", "transports": ["local", "http", "websocket", "acp"]},
|
|
263
|
+
{"id": "heartbeat", "wire": "frontend.v2.heartbeat", "sdk_action": "events", "params": "Empty", "result": "RuntimeLeaseSnapshot", "transports": ["local", "http", "websocket", "acp"]},
|
|
264
|
+
{"id": "detach", "wire": "frontend.v2.detach", "sdk_action": "events", "params": "Empty", "result": "RuntimeLeaseSnapshot", "transports": ["local", "http", "websocket", "acp"]},
|
|
265
|
+
{"id": "close", "wire": "frontend.v2.close", "sdk_action": "close", "params": "Empty", "result": "Closed", "transports": ["local", "http", "websocket", "acp"]}
|
|
266
|
+
],
|
|
267
|
+
"events": {
|
|
268
|
+
"wire": "frontend.v2.event",
|
|
269
|
+
"type": "FrontendEvent",
|
|
270
|
+
"ordering": "strictly_increasing_sequence",
|
|
271
|
+
"reconnect": "attach.after_sequence"
|
|
272
|
+
},
|
|
273
|
+
"compatibility_aliases": {
|
|
274
|
+
"frontend.describe": "describe",
|
|
275
|
+
"frontend.attach": "attach",
|
|
276
|
+
"frontend.send_input": "send_input",
|
|
277
|
+
"frontend.invoke": "invoke",
|
|
278
|
+
"frontend.lease": "lease",
|
|
279
|
+
"frontend.acquire_control": "acquire_control",
|
|
280
|
+
"frontend.take_control": "take_control",
|
|
281
|
+
"frontend.heartbeat": "heartbeat",
|
|
282
|
+
"frontend.detach": "detach",
|
|
283
|
+
"frontend.close": "close",
|
|
284
|
+
"submit": "submit",
|
|
285
|
+
"interrupt": "interrupt",
|
|
286
|
+
"steer": "steer",
|
|
287
|
+
"respond": "respond"
|
|
288
|
+
}
|
|
289
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// @generated by sdk/frontend/generate.mjs from contract.json. Do not edit.
|
|
2
|
+
import type { Accepted, Closed, FrontendAttachSnapshot, FrontendOperationInvocation, FrontendOperationResult, FrontendResponse, FrontendRuntimeDescriptor, FrontendWireMethod, Interrupted, Queued, Reply, RuntimeLeaseSnapshot } from './generated.mjs';
|
|
3
|
+
export abstract class GeneratedFrontendClient<Options = unknown> {
|
|
4
|
+
abstract rpc(method: FrontendWireMethod, params?: Record<string, unknown>, options?: Options): Promise<unknown>;
|
|
5
|
+
describe(options?: Options): Promise<FrontendRuntimeDescriptor>;
|
|
6
|
+
attach(limit?: number, options?: Options & {afterSequence?: number}): Promise<FrontendAttachSnapshot>;
|
|
7
|
+
sendInput(prompt: string, options?: Options & {imageUrls?: string[]}): Promise<Accepted>;
|
|
8
|
+
submit(prompt: string, options?: Options & {imageUrls?: string[]}): Promise<Reply>;
|
|
9
|
+
interrupt(options?: Options): Promise<Interrupted>;
|
|
10
|
+
steer(prompt: string, options?: Options): Promise<Queued>;
|
|
11
|
+
respond(response: FrontendResponse, options?: Options): Promise<Accepted>;
|
|
12
|
+
invoke(operation: FrontendOperationInvocation, options?: Options): Promise<FrontendOperationResult>;
|
|
13
|
+
lease(options?: Options): Promise<RuntimeLeaseSnapshot>;
|
|
14
|
+
takeControl(options?: Options): Promise<RuntimeLeaseSnapshot>;
|
|
15
|
+
heartbeat(options?: Options): Promise<RuntimeLeaseSnapshot>;
|
|
16
|
+
detach(options?: Options): Promise<RuntimeLeaseSnapshot>;
|
|
17
|
+
close(options?: Options): Promise<Closed>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// @generated by sdk/frontend/generate.mjs from contract.json. Do not edit.
|
|
2
|
+
import { FRONTEND_METHODS } from './generated.mjs';
|
|
3
|
+
|
|
4
|
+
export class GeneratedFrontendClient {
|
|
5
|
+
rpc() { throw new Error('GeneratedFrontendClient.rpc must be implemented by a transport'); }
|
|
6
|
+
describe(options) { return this.rpc(FRONTEND_METHODS.describe, {}, options); }
|
|
7
|
+
attach(limit = 1000, { afterSequence, ...options } = {}) { return this.rpc(FRONTEND_METHODS.attach, { limit, ...(afterSequence === undefined ? {} : {after_sequence:afterSequence}) }, options); }
|
|
8
|
+
sendInput(prompt, { imageUrls, ...options } = {}) { return this.rpc(FRONTEND_METHODS.send_input, { prompt, ...(imageUrls?.length ? {image_urls:imageUrls} : {}) }, options); }
|
|
9
|
+
submit(prompt, { imageUrls, ...options } = {}) { return this.rpc(FRONTEND_METHODS.submit, { prompt, ...(imageUrls?.length ? {image_urls:imageUrls} : {}) }, options); }
|
|
10
|
+
interrupt(options) { return this.rpc(FRONTEND_METHODS.interrupt, {}, options); }
|
|
11
|
+
steer(prompt, options) { return this.rpc(FRONTEND_METHODS.steer, { prompt }, options); }
|
|
12
|
+
respond(response, options) { return this.rpc(FRONTEND_METHODS.respond, { response }, options); }
|
|
13
|
+
invoke(operation, options) { return this.rpc(FRONTEND_METHODS.invoke, { operation }, options); }
|
|
14
|
+
lease(options) { return this.rpc(FRONTEND_METHODS.lease, {}, options); }
|
|
15
|
+
acquireControl(options) { return this.rpc(FRONTEND_METHODS.acquire_control, {}, options); }
|
|
16
|
+
takeControl(options) { return this.rpc(FRONTEND_METHODS.take_control, {}, options); }
|
|
17
|
+
heartbeat(options) { return this.rpc(FRONTEND_METHODS.heartbeat, {}, options); }
|
|
18
|
+
detach(options) { return this.rpc(FRONTEND_METHODS.detach, {}, options); }
|
|
19
|
+
close(options) { return this.rpc(FRONTEND_METHODS.close, {}, options); }
|
|
20
|
+
}
|