@ellipsis-dev/sdk 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +931 -26
- package/dist/index.js +1232 -81
- package/dist/store/index.d.ts +8 -8
- package/dist/store/index.js +1 -1
- package/dist/stream/index.d.ts +2 -2
- package/dist/{types-rf-NzI8E.d.ts → types-CStmnKVu.d.ts} +1406 -1587
- package/package.json +1 -1
- package/schema/frames.schema.json +492 -498
- package/schema/openapi.v1.json +2748 -3202
- package/schema/trigger_fields.schema.json +374 -0
package/dist/index.js
CHANGED
|
@@ -1,97 +1,1248 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
var
|
|
3
|
-
constructor(
|
|
4
|
-
this.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
// The enriched public session (§4.1) — the same lean wire shape the
|
|
8
|
-
// stream's session frames carry.
|
|
9
|
-
async getSession(sessionId) {
|
|
10
|
-
return await this.fetchJson(
|
|
11
|
-
`/sessions/${encodeURIComponent(sessionId)}`
|
|
12
|
-
);
|
|
1
|
+
// src/core/pagination.ts
|
|
2
|
+
var Page = class {
|
|
3
|
+
constructor(response, itemsAttr, fetchNext) {
|
|
4
|
+
this.response = response;
|
|
5
|
+
this.itemsAttr = itemsAttr;
|
|
6
|
+
this.fetchNext = fetchNext;
|
|
13
7
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
params.set("after_seq", String(options.afterSeq));
|
|
20
|
-
if (options.limit != null) params.set("limit", String(options.limit));
|
|
21
|
-
const query = params.toString();
|
|
22
|
-
return await this.fetchJson(
|
|
23
|
-
`/sessions/${encodeURIComponent(sessionId)}/records` + (query ? `?${query}` : "")
|
|
24
|
-
);
|
|
8
|
+
response;
|
|
9
|
+
itemsAttr;
|
|
10
|
+
fetchNext;
|
|
11
|
+
get items() {
|
|
12
|
+
return this.response[this.itemsAttr];
|
|
25
13
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
async getSessionTurns(sessionId) {
|
|
29
|
-
return await this.fetchJson(
|
|
30
|
-
`/sessions/${encodeURIComponent(sessionId)}/turns`
|
|
31
|
-
);
|
|
14
|
+
get hasMore() {
|
|
15
|
+
return this.response.has_more;
|
|
32
16
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
17
|
+
get nextCursor() {
|
|
18
|
+
return this.response.next_cursor ?? null;
|
|
19
|
+
}
|
|
20
|
+
async *[Symbol.asyncIterator]() {
|
|
21
|
+
let page = this;
|
|
22
|
+
for (; ; ) {
|
|
23
|
+
yield* page.items;
|
|
24
|
+
const cursor = page.nextCursor;
|
|
25
|
+
if (!page.hasMore || cursor == null) return;
|
|
26
|
+
page = await this.fetchNext(cursor);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// src/core/sessionHandle.ts
|
|
32
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
33
|
+
"completed",
|
|
34
|
+
"error",
|
|
35
|
+
"cancelled",
|
|
36
|
+
"stopped"
|
|
37
|
+
]);
|
|
38
|
+
var DEFAULT_POLL_INTERVAL_MS = 3e3;
|
|
39
|
+
function isSettled(session) {
|
|
40
|
+
if (TERMINAL_STATUSES.has(session.status)) return true;
|
|
41
|
+
return session.session_state === "idle" || session.session_state === "closed";
|
|
42
|
+
}
|
|
43
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
44
|
+
var SessionHandle = class {
|
|
45
|
+
constructor(sessions, session) {
|
|
46
|
+
this.sessions = sessions;
|
|
47
|
+
this.id = session.id;
|
|
48
|
+
this.session = session;
|
|
49
|
+
}
|
|
50
|
+
sessions;
|
|
51
|
+
id;
|
|
52
|
+
// The latest session snapshot this handle saw.
|
|
53
|
+
session;
|
|
54
|
+
async refresh() {
|
|
55
|
+
this.session = (await this.sessions.get(this.id)).session;
|
|
56
|
+
return this.session;
|
|
57
|
+
}
|
|
58
|
+
// Poll until the session settles (terminal status, or a parked
|
|
59
|
+
// conversation: state idle/closed).
|
|
60
|
+
async wait(options = {}) {
|
|
61
|
+
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
62
|
+
const deadline = options.timeoutMs == null ? null : Date.now() + options.timeoutMs;
|
|
63
|
+
for (; ; ) {
|
|
64
|
+
const session = await this.refresh();
|
|
65
|
+
if (isSettled(session)) return session;
|
|
66
|
+
if (deadline != null && Date.now() >= deadline) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`session ${this.id} not terminal after ${options.timeoutMs}ms`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
await sleep(pollIntervalMs);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Post into the session's inbox (delivered at the next turn boundary;
|
|
75
|
+
// wakes a parked session).
|
|
76
|
+
async send(message, options = {}) {
|
|
77
|
+
const response = await this.sessions.sendMessage(this.id, {
|
|
78
|
+
message,
|
|
79
|
+
idempotency_key: options.idempotencyKey
|
|
80
|
+
});
|
|
81
|
+
return response.message;
|
|
82
|
+
}
|
|
83
|
+
async stop() {
|
|
84
|
+
this.session = (await this.sessions.stop(this.id)).session;
|
|
85
|
+
return this.session;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// src/core/errors.ts
|
|
90
|
+
var EllipsisError = class extends Error {
|
|
91
|
+
};
|
|
92
|
+
var TransportError = class extends EllipsisError {
|
|
93
|
+
};
|
|
94
|
+
var APIError = class extends EllipsisError {
|
|
95
|
+
status;
|
|
96
|
+
code;
|
|
97
|
+
requestId;
|
|
98
|
+
body;
|
|
99
|
+
constructor(args) {
|
|
100
|
+
super(`${args.status} ${args.code ?? "error"}: ${args.message}`);
|
|
101
|
+
this.status = args.status;
|
|
102
|
+
this.code = args.code;
|
|
103
|
+
this.requestId = args.requestId;
|
|
104
|
+
this.body = args.body;
|
|
42
105
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
106
|
+
};
|
|
107
|
+
var AuthenticationError = class extends APIError {
|
|
108
|
+
};
|
|
109
|
+
var ForbiddenError = class extends APIError {
|
|
110
|
+
};
|
|
111
|
+
var NotFoundError = class extends APIError {
|
|
112
|
+
};
|
|
113
|
+
var ConflictError = class extends APIError {
|
|
114
|
+
};
|
|
115
|
+
var UnprocessableError = class extends APIError {
|
|
116
|
+
};
|
|
117
|
+
var RateLimitError = class extends APIError {
|
|
118
|
+
};
|
|
119
|
+
var ServerError = class extends APIError {
|
|
120
|
+
};
|
|
121
|
+
var STATUS_CLASSES = {
|
|
122
|
+
401: AuthenticationError,
|
|
123
|
+
403: ForbiddenError,
|
|
124
|
+
404: NotFoundError,
|
|
125
|
+
409: ConflictError,
|
|
126
|
+
422: UnprocessableError,
|
|
127
|
+
429: RateLimitError
|
|
128
|
+
};
|
|
129
|
+
function apiErrorFor(status, body) {
|
|
130
|
+
let code = null;
|
|
131
|
+
let message = "";
|
|
132
|
+
let requestId = null;
|
|
133
|
+
if (body !== null && typeof body === "object") {
|
|
134
|
+
const error = body.error;
|
|
135
|
+
if (error !== null && typeof error === "object") {
|
|
136
|
+
const info = error;
|
|
137
|
+
if (typeof info.code === "string") code = info.code;
|
|
138
|
+
if (typeof info.message === "string") message = info.message;
|
|
139
|
+
if (typeof info.request_id === "string") requestId = info.request_id;
|
|
140
|
+
} else if ("detail" in body) {
|
|
141
|
+
message = String(body.detail);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (!message) {
|
|
145
|
+
message = body == null ? "no response body" : String(body).slice(0, 500);
|
|
146
|
+
}
|
|
147
|
+
const cls = STATUS_CLASSES[status] ?? (status >= 500 ? ServerError : APIError);
|
|
148
|
+
return new cls({ status, code, message, requestId, body });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// src/core/transport.ts
|
|
152
|
+
var DEFAULT_BASE_URL = "https://api.ellipsis.dev";
|
|
153
|
+
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
154
|
+
var RETRY_STATUSES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
|
|
155
|
+
var MAX_RETRIES = 2;
|
|
156
|
+
function queryScalar(value) {
|
|
157
|
+
if (value instanceof Date) return value.toISOString();
|
|
158
|
+
return String(value);
|
|
159
|
+
}
|
|
160
|
+
function buildQuery(params) {
|
|
161
|
+
const search = new URLSearchParams();
|
|
162
|
+
for (const [key, value] of Object.entries(params)) {
|
|
163
|
+
if (value == null) continue;
|
|
164
|
+
if (Array.isArray(value)) {
|
|
165
|
+
for (const item of value) search.append(key, queryScalar(item));
|
|
166
|
+
} else {
|
|
167
|
+
search.append(key, queryScalar(value));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const rendered = search.toString();
|
|
171
|
+
return rendered ? `?${rendered}` : "";
|
|
172
|
+
}
|
|
173
|
+
function buildBody(body) {
|
|
174
|
+
const out = {};
|
|
175
|
+
for (const [key, value] of Object.entries(body)) {
|
|
176
|
+
if (value == null) continue;
|
|
177
|
+
out[key] = value instanceof Date ? value.toISOString() : value;
|
|
178
|
+
}
|
|
179
|
+
return out;
|
|
180
|
+
}
|
|
181
|
+
function backoffMs(attempt, retryAfter) {
|
|
182
|
+
if (retryAfter != null) {
|
|
183
|
+
const seconds = Number(retryAfter);
|
|
184
|
+
if (!Number.isNaN(seconds)) return Math.max(0, seconds * 1e3);
|
|
185
|
+
}
|
|
186
|
+
return 2 ** attempt * 500 + Math.random() * 250;
|
|
187
|
+
}
|
|
188
|
+
var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
189
|
+
var Transport = class {
|
|
190
|
+
baseUrl;
|
|
191
|
+
headers;
|
|
192
|
+
timeoutMs;
|
|
193
|
+
maxRetries;
|
|
194
|
+
fetchImpl;
|
|
195
|
+
constructor(options) {
|
|
196
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
197
|
+
this.headers = { Authorization: `Bearer ${options.apiKey}` };
|
|
198
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
199
|
+
this.maxRetries = options.maxRetries ?? MAX_RETRIES;
|
|
200
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
201
|
+
}
|
|
202
|
+
async request(method, path, options = {}) {
|
|
203
|
+
const url = this.baseUrl + path + (options.query ?? "");
|
|
204
|
+
const init = { method, headers: { ...this.headers } };
|
|
205
|
+
if (options.body !== void 0) {
|
|
206
|
+
init.headers["Content-Type"] = "application/json";
|
|
207
|
+
init.body = JSON.stringify(options.body);
|
|
208
|
+
}
|
|
209
|
+
for (let attempt = 0; ; attempt++) {
|
|
210
|
+
let response;
|
|
211
|
+
try {
|
|
212
|
+
response = await this.fetchImpl(url, {
|
|
213
|
+
...init,
|
|
214
|
+
signal: AbortSignal.timeout(this.timeoutMs)
|
|
215
|
+
});
|
|
216
|
+
} catch (error) {
|
|
217
|
+
if (attempt < this.maxRetries) {
|
|
218
|
+
await sleep2(backoffMs(attempt, null));
|
|
219
|
+
continue;
|
|
56
220
|
}
|
|
221
|
+
throw new TransportError(String(error));
|
|
57
222
|
}
|
|
223
|
+
if (RETRY_STATUSES.has(response.status) && attempt < this.maxRetries) {
|
|
224
|
+
await sleep2(backoffMs(attempt, response.headers.get("retry-after")));
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (response.status >= 400) {
|
|
228
|
+
let body = null;
|
|
229
|
+
try {
|
|
230
|
+
body = await response.json();
|
|
231
|
+
} catch {
|
|
232
|
+
body = await response.text().catch(() => null);
|
|
233
|
+
}
|
|
234
|
+
throw apiErrorFor(response.status, body);
|
|
235
|
+
}
|
|
236
|
+
if (response.status === 204) return void 0;
|
|
237
|
+
return await response.json();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// src/core/client.ts
|
|
243
|
+
var enc = encodeURIComponent;
|
|
244
|
+
var EllipsisAgentsConfigs = class {
|
|
245
|
+
constructor(transport) {
|
|
246
|
+
this.transport = transport;
|
|
247
|
+
}
|
|
248
|
+
transport;
|
|
249
|
+
/**
|
|
250
|
+
* Create Agent Config
|
|
251
|
+
*
|
|
252
|
+
* Create an agent config via pull request.
|
|
253
|
+
*
|
|
254
|
+
* The PR adds the config file to agents/ on the target
|
|
255
|
+
* repository; the agent goes live when it merges.
|
|
256
|
+
*
|
|
257
|
+
* Accepts an inline config or a gallery template slug. 409 when
|
|
258
|
+
* another live agent already holds the name.
|
|
259
|
+
*/
|
|
260
|
+
async create(options) {
|
|
261
|
+
const path = "/agents/configs";
|
|
262
|
+
const body = buildBody({ config: options.config, path: options.path, repository: options.repository, template_id: options.template_id });
|
|
263
|
+
return await this.transport.request("POST", path, { body });
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Get Agent Config
|
|
267
|
+
*
|
|
268
|
+
* Return one saved agent config, by id or by the agent's name.
|
|
269
|
+
*/
|
|
270
|
+
async get(config_id) {
|
|
271
|
+
const path = `/agents/configs/${enc(config_id)}`;
|
|
272
|
+
return await this.transport.request("GET", path);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* List Agent Configs
|
|
276
|
+
*
|
|
277
|
+
* List saved agent configs.
|
|
278
|
+
*/
|
|
279
|
+
async list() {
|
|
280
|
+
const path = "/agents/configs";
|
|
281
|
+
return await this.transport.request("GET", path);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
var EllipsisAgentsDefaults = class {
|
|
285
|
+
constructor(transport) {
|
|
286
|
+
this.transport = transport;
|
|
287
|
+
}
|
|
288
|
+
transport;
|
|
289
|
+
/**
|
|
290
|
+
* Delete Agent Default
|
|
291
|
+
*
|
|
292
|
+
* Clear a default agent config.
|
|
293
|
+
*
|
|
294
|
+
* Addressed by rung: the account rung (repository omitted) or a
|
|
295
|
+
* repository rung.
|
|
296
|
+
*
|
|
297
|
+
* Refused for sandbox tokens.
|
|
298
|
+
*/
|
|
299
|
+
async delete(options = {}) {
|
|
300
|
+
const path = "/agents/defaults";
|
|
301
|
+
const query = buildQuery({ repository: options.repository });
|
|
302
|
+
await this.transport.request("DELETE", path, { query });
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* List Agent Defaults
|
|
306
|
+
*
|
|
307
|
+
* List default agent configs.
|
|
308
|
+
*
|
|
309
|
+
* The account default and any per-repository defaults.
|
|
310
|
+
*
|
|
311
|
+
* Defaults are addressed by rung: the account rung is repository
|
|
312
|
+
* omitted, a repo rung is "owner/name" — never by row id.
|
|
313
|
+
*/
|
|
314
|
+
async list() {
|
|
315
|
+
const path = "/agents/defaults";
|
|
316
|
+
return await this.transport.request("GET", path);
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Put Agent Default
|
|
320
|
+
*
|
|
321
|
+
* Set a default agent config.
|
|
322
|
+
*
|
|
323
|
+
* Addressed by rung: the account rung (repository omitted) or a
|
|
324
|
+
* repository rung ("owner/name"); the config by id or by the
|
|
325
|
+
* agent's name.
|
|
326
|
+
*
|
|
327
|
+
* Refused for sandbox tokens (potentially prompt-injected code
|
|
328
|
+
* must not repoint the account's ambient default); an unknown or
|
|
329
|
+
* foreign repository is a 404.
|
|
330
|
+
*/
|
|
331
|
+
async set(options) {
|
|
332
|
+
const path = "/agents/defaults";
|
|
333
|
+
const body = buildBody({ config_id: options.config_id, repository: options.repository });
|
|
334
|
+
return await this.transport.request("PUT", path, { body });
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
var EllipsisAgentsTemplates = class {
|
|
338
|
+
constructor(transport) {
|
|
339
|
+
this.transport = transport;
|
|
340
|
+
}
|
|
341
|
+
transport;
|
|
342
|
+
/**
|
|
343
|
+
* Get Agent Template
|
|
344
|
+
*
|
|
345
|
+
* Return one built-in agent template by slug.
|
|
346
|
+
*/
|
|
347
|
+
async get(template_id) {
|
|
348
|
+
const path = `/agents/templates/${enc(template_id)}`;
|
|
349
|
+
return await this.transport.request("GET", path);
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* List Agent Templates
|
|
353
|
+
*
|
|
354
|
+
* List the built-in starter agent templates.
|
|
355
|
+
*
|
|
356
|
+
* Behind auth but not account-scoped — the data is static
|
|
357
|
+
* product content shared by the dashboard, landing site, and CLI.
|
|
358
|
+
*/
|
|
359
|
+
async list() {
|
|
360
|
+
const path = "/agents/templates";
|
|
361
|
+
return await this.transport.request("GET", path);
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
var EllipsisAgents = class {
|
|
365
|
+
constructor(transport) {
|
|
366
|
+
this.transport = transport;
|
|
367
|
+
this.configs = new EllipsisAgentsConfigs(transport);
|
|
368
|
+
this.defaults = new EllipsisAgentsDefaults(transport);
|
|
369
|
+
this.templates = new EllipsisAgentsTemplates(transport);
|
|
370
|
+
}
|
|
371
|
+
transport;
|
|
372
|
+
configs;
|
|
373
|
+
defaults;
|
|
374
|
+
templates;
|
|
375
|
+
};
|
|
376
|
+
var EllipsisAlerts = class {
|
|
377
|
+
constructor(transport) {
|
|
378
|
+
this.transport = transport;
|
|
379
|
+
}
|
|
380
|
+
transport;
|
|
381
|
+
/**
|
|
382
|
+
* Dismiss Alert
|
|
383
|
+
*
|
|
384
|
+
* Dismiss an open alert and return it.
|
|
385
|
+
*
|
|
386
|
+
* 409 when the alert is not open; 404 when it doesn't exist.
|
|
387
|
+
*/
|
|
388
|
+
async dismiss(alert_id) {
|
|
389
|
+
const path = `/alerts/${enc(alert_id)}/dismiss`;
|
|
390
|
+
return await this.transport.request("POST", path);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Get Alert
|
|
394
|
+
*
|
|
395
|
+
* Return one alert by id.
|
|
396
|
+
*
|
|
397
|
+
* 404 if it doesn't exist or belongs to another organization.
|
|
398
|
+
*/
|
|
399
|
+
async get(alert_id) {
|
|
400
|
+
const path = `/alerts/${enc(alert_id)}`;
|
|
401
|
+
return await this.transport.request("GET", path);
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* List Alerts
|
|
405
|
+
*
|
|
406
|
+
* List budget alerts for the organization, newest first.
|
|
407
|
+
*
|
|
408
|
+
* Optionally filtered by status and source.
|
|
409
|
+
*
|
|
410
|
+
* Available to all credential types, so an agent can check "is
|
|
411
|
+
* this org near budget?" mid-task.
|
|
412
|
+
*/
|
|
413
|
+
async list(options = {}) {
|
|
414
|
+
const path = "/alerts";
|
|
415
|
+
const query = buildQuery({ status: options.status, source: options.source, limit: options.limit, cursor: options.cursor });
|
|
416
|
+
const response = await this.transport.request("GET", path, { query });
|
|
417
|
+
return new Page(
|
|
418
|
+
response,
|
|
419
|
+
"alerts",
|
|
420
|
+
(cursor) => this.list({ ...options, cursor })
|
|
58
421
|
);
|
|
59
422
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
423
|
+
};
|
|
424
|
+
var EllipsisAnalytics = class {
|
|
425
|
+
constructor(transport) {
|
|
426
|
+
this.transport = transport;
|
|
427
|
+
}
|
|
428
|
+
transport;
|
|
429
|
+
/**
|
|
430
|
+
* Get Analytics Metrics
|
|
431
|
+
*
|
|
432
|
+
* Return PR and review analytics metrics.
|
|
433
|
+
*
|
|
434
|
+
* The same data as the analytics dashboard.
|
|
435
|
+
*
|
|
436
|
+
* Windowing: pass explicit start/end, or days (default: the last
|
|
437
|
+
* 30 days). account_type in all|user|bot scopes the authors (bot =
|
|
438
|
+
* the apps/agents). Available to all credential types: the
|
|
439
|
+
* responses expose the organization's own GitHub PR/review activity,
|
|
440
|
+
* no secrets.
|
|
441
|
+
*/
|
|
442
|
+
async metrics(options = {}) {
|
|
443
|
+
const path = "/analytics/metrics";
|
|
444
|
+
const query = buildQuery({ days: options.days, start: options.start, end: options.end, repo: options.repo, author: options.author, account_type: options.account_type, status: options.status });
|
|
445
|
+
return await this.transport.request("GET", path, { query });
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Get Analytics Pull Requests
|
|
449
|
+
*
|
|
450
|
+
* Return pull-request analytics.
|
|
451
|
+
*
|
|
452
|
+
* Windowing: pass explicit start/end, or days (default: the last
|
|
453
|
+
* 30 days).
|
|
454
|
+
*/
|
|
455
|
+
async pullRequests(options = {}) {
|
|
456
|
+
const path = "/analytics/pull-requests";
|
|
457
|
+
const query = buildQuery({ days: options.days, start: options.start, end: options.end, account_type: options.account_type, repository_id: options.repository_id, author_id: options.author_id, status: options.status });
|
|
458
|
+
return await this.transport.request("GET", path, { query });
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Get Analytics Reviews
|
|
462
|
+
*
|
|
463
|
+
* Return code-review analytics.
|
|
464
|
+
*
|
|
465
|
+
* account_type scopes reviewers (bot|user|all) — e.g. "what apps
|
|
466
|
+
* review the most PRs?" is the reviewer facets here with
|
|
467
|
+
* account_type=bot. Windowing: pass explicit start/end, or days
|
|
468
|
+
* (default: the last 30 days).
|
|
469
|
+
*/
|
|
470
|
+
async reviews(options = {}) {
|
|
471
|
+
const path = "/analytics/reviews";
|
|
472
|
+
const query = buildQuery({ days: options.days, start: options.start, end: options.end, repo: options.repo, author: options.author, account_type: options.account_type, review_state: options.review_state });
|
|
473
|
+
return await this.transport.request("GET", path, { query });
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
var EllipsisAuthCli = class {
|
|
477
|
+
constructor(transport) {
|
|
478
|
+
this.transport = transport;
|
|
479
|
+
}
|
|
480
|
+
transport;
|
|
481
|
+
/**
|
|
482
|
+
* Cli Auth Poll
|
|
483
|
+
*
|
|
484
|
+
* Poll a device-code auth flow for its token.
|
|
485
|
+
*
|
|
486
|
+
* Unauthenticated; the device code identifies the flow.
|
|
487
|
+
*/
|
|
488
|
+
async poll(options) {
|
|
489
|
+
const path = "/auth/cli/poll";
|
|
490
|
+
const body = buildBody({ device_code: options.device_code });
|
|
491
|
+
return await this.transport.request("POST", path, { body });
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Cli Auth Start
|
|
495
|
+
*
|
|
496
|
+
* Start a device-code auth flow for the CLI.
|
|
497
|
+
*
|
|
498
|
+
* Unauthenticated: the CLI has no credential yet — that's what
|
|
499
|
+
* it's obtaining. The human authorizes out-of-band in the
|
|
500
|
+
* dashboard.
|
|
501
|
+
*/
|
|
502
|
+
async start() {
|
|
503
|
+
const path = "/auth/cli/start";
|
|
504
|
+
return await this.transport.request("POST", path);
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
var EllipsisAuth = class {
|
|
508
|
+
constructor(transport) {
|
|
509
|
+
this.transport = transport;
|
|
510
|
+
this.cli = new EllipsisAuthCli(transport);
|
|
71
511
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
512
|
+
transport;
|
|
513
|
+
cli;
|
|
514
|
+
};
|
|
515
|
+
var EllipsisFiles = class {
|
|
516
|
+
constructor(transport) {
|
|
517
|
+
this.transport = transport;
|
|
518
|
+
}
|
|
519
|
+
transport;
|
|
520
|
+
/**
|
|
521
|
+
* Create File
|
|
522
|
+
*
|
|
523
|
+
* Upload a file that outlives the sandbox.
|
|
524
|
+
*
|
|
525
|
+
* v1: PNG images only, base64 in the JSON body, 10 MiB cap. The
|
|
526
|
+
* primary caller is the in-sandbox `agent file upload` CLI (an
|
|
527
|
+
* agent persisting a screenshot to link on a PR), but all
|
|
528
|
+
* credential types work. Returns the org-membership-gated
|
|
529
|
+
* dashboard URL so callers never hard-code URL shapes.
|
|
530
|
+
*/
|
|
531
|
+
async create(options) {
|
|
532
|
+
const path = "/files";
|
|
533
|
+
const body = buildBody({ content_type: options.content_type, data_b64: options.data_b64, filename: options.filename });
|
|
534
|
+
return await this.transport.request("POST", path, { body });
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Delete File
|
|
538
|
+
*
|
|
539
|
+
* Delete a file.
|
|
540
|
+
*
|
|
541
|
+
* A foreign, missing, or already-deleted id is an
|
|
542
|
+
* indistinguishable 404, so ids can't be enumerated. Sandbox
|
|
543
|
+
* tokens get a 403 (a sandbox token sits next to
|
|
544
|
+
* potentially-untrusted code and must not be able to destroy the
|
|
545
|
+
* account's files — uploading is fine, destruction is not); API
|
|
546
|
+
* keys and user tokens may delete.
|
|
547
|
+
*/
|
|
548
|
+
async delete(file_id) {
|
|
549
|
+
const path = `/files/${enc(file_id)}`;
|
|
550
|
+
await this.transport.request("DELETE", path);
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Get File
|
|
554
|
+
*
|
|
555
|
+
* Return one file's metadata and download link.
|
|
556
|
+
*
|
|
557
|
+
* Includes the gated dashboard URL and a short-lived presigned
|
|
558
|
+
* `download_url`.
|
|
559
|
+
*
|
|
560
|
+
* To fetch the bytes locally, call this and then GET download_url
|
|
561
|
+
* immediately — the JSON API never carries the file. The CLI's
|
|
562
|
+
* `agent file get` wraps exactly that two-step.
|
|
563
|
+
*/
|
|
564
|
+
async get(file_id) {
|
|
565
|
+
const path = `/files/${enc(file_id)}`;
|
|
566
|
+
return await this.transport.request("GET", path);
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* List Files
|
|
570
|
+
*
|
|
571
|
+
* List uploaded files, newest first.
|
|
572
|
+
*
|
|
573
|
+
* Metadata only — download URLs are minted per explicit GET, not
|
|
574
|
+
* per row. session_id scopes the list to one run's uploads.
|
|
575
|
+
*/
|
|
576
|
+
async list(options = {}) {
|
|
577
|
+
const path = "/files";
|
|
578
|
+
const query = buildQuery({ session_id: options.session_id, limit: options.limit, cursor: options.cursor });
|
|
579
|
+
const response = await this.transport.request("GET", path, { query });
|
|
580
|
+
return new Page(
|
|
581
|
+
response,
|
|
582
|
+
"files",
|
|
583
|
+
(cursor) => this.list({ ...options, cursor })
|
|
76
584
|
);
|
|
77
585
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
586
|
+
};
|
|
587
|
+
var EllipsisIntegrationsGithub = class {
|
|
588
|
+
constructor(transport) {
|
|
589
|
+
this.transport = transport;
|
|
590
|
+
}
|
|
591
|
+
transport;
|
|
592
|
+
/**
|
|
593
|
+
* List Github Members
|
|
594
|
+
*
|
|
595
|
+
* List the GitHub organization roster.
|
|
596
|
+
*
|
|
597
|
+
* (Or the account itself for a personal workspace) — the universe of author_id values for
|
|
598
|
+
* /sessions and /sessions/search.
|
|
599
|
+
*
|
|
600
|
+
* Members carry their linked Slack identity when a Slack-GitHub
|
|
601
|
+
* link exists, and /slack/members carries the reverse link.
|
|
602
|
+
*/
|
|
603
|
+
async members() {
|
|
604
|
+
const path = "/integrations/github/members";
|
|
605
|
+
return await this.transport.request("GET", path);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* List Github Repositories
|
|
609
|
+
*
|
|
610
|
+
* List GitHub repositories connected to the installation.
|
|
611
|
+
*/
|
|
612
|
+
async repos() {
|
|
613
|
+
const path = "/integrations/github/repos";
|
|
614
|
+
return await this.transport.request("GET", path);
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
var EllipsisIntegrationsLinear = class {
|
|
618
|
+
constructor(transport) {
|
|
619
|
+
this.transport = transport;
|
|
620
|
+
}
|
|
621
|
+
transport;
|
|
622
|
+
/**
|
|
623
|
+
* List Linear Teams
|
|
624
|
+
*
|
|
625
|
+
* List the teams of the connected Linear workspace.
|
|
626
|
+
*/
|
|
627
|
+
async teams() {
|
|
628
|
+
const path = "/integrations/linear/teams";
|
|
629
|
+
return await this.transport.request("GET", path);
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
var EllipsisIntegrationsSentry = class {
|
|
633
|
+
constructor(transport) {
|
|
634
|
+
this.transport = transport;
|
|
635
|
+
}
|
|
636
|
+
transport;
|
|
637
|
+
/**
|
|
638
|
+
* List Sentry Organizations
|
|
639
|
+
*
|
|
640
|
+
* List the connected Sentry organizations.
|
|
641
|
+
*/
|
|
642
|
+
async organizations() {
|
|
643
|
+
const path = "/integrations/sentry/organizations";
|
|
644
|
+
return await this.transport.request("GET", path);
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
var EllipsisIntegrationsSlack = class {
|
|
648
|
+
constructor(transport) {
|
|
649
|
+
this.transport = transport;
|
|
650
|
+
}
|
|
651
|
+
transport;
|
|
652
|
+
/**
|
|
653
|
+
* List Slack Channels
|
|
654
|
+
*
|
|
655
|
+
* List the channels of the connected Slack workspace, fetched
|
|
656
|
+
* live from the Slack API.
|
|
657
|
+
*/
|
|
658
|
+
async channels() {
|
|
659
|
+
const path = "/integrations/slack/channels";
|
|
660
|
+
return await this.transport.request("GET", path);
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* List Slack Members
|
|
664
|
+
*
|
|
665
|
+
* List the members of the connected Slack workspace, fetched
|
|
666
|
+
* live from the Slack API.
|
|
667
|
+
*/
|
|
668
|
+
async members() {
|
|
669
|
+
const path = "/integrations/slack/members";
|
|
670
|
+
return await this.transport.request("GET", path);
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
var EllipsisIntegrations = class {
|
|
674
|
+
constructor(transport) {
|
|
675
|
+
this.transport = transport;
|
|
676
|
+
this.github = new EllipsisIntegrationsGithub(transport);
|
|
677
|
+
this.linear = new EllipsisIntegrationsLinear(transport);
|
|
678
|
+
this.sentry = new EllipsisIntegrationsSentry(transport);
|
|
679
|
+
this.slack = new EllipsisIntegrationsSlack(transport);
|
|
680
|
+
}
|
|
681
|
+
transport;
|
|
682
|
+
github;
|
|
683
|
+
linear;
|
|
684
|
+
sentry;
|
|
685
|
+
slack;
|
|
686
|
+
/**
|
|
687
|
+
* Get Integrations
|
|
688
|
+
*
|
|
689
|
+
* List connected integrations.
|
|
690
|
+
*
|
|
691
|
+
* A read-only view, so an agent authoring another agent's
|
|
692
|
+
* config can learn which repositories, channels, teams, and
|
|
693
|
+
* organizations it may name before POST /agents/configs.
|
|
694
|
+
*
|
|
695
|
+
* Available to all credential types including sandbox tokens: the
|
|
696
|
+
* responses never include OAuth tokens or any other secret.
|
|
697
|
+
*/
|
|
698
|
+
async list() {
|
|
699
|
+
const path = "/integrations";
|
|
700
|
+
return await this.transport.request("GET", path);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
var EllipsisMemories = class {
|
|
704
|
+
constructor(transport) {
|
|
705
|
+
this.transport = transport;
|
|
706
|
+
}
|
|
707
|
+
transport;
|
|
708
|
+
/**
|
|
709
|
+
* Create Memory
|
|
710
|
+
*
|
|
711
|
+
* Save a memory for future agent sessions.
|
|
712
|
+
*
|
|
713
|
+
* Memories are durable lessons shared across the whole
|
|
714
|
+
* organization — conventions, past decisions, known gotchas that an
|
|
715
|
+
* agent cannot derive from the repository itself. One concise fact
|
|
716
|
+
* per memory; the description is what a reader sees in the index.
|
|
717
|
+
*
|
|
718
|
+
* Creating never overwrites: a path that already exists is a 409, so
|
|
719
|
+
* correcting an existing memory is an explicit edit.
|
|
720
|
+
*/
|
|
721
|
+
async create(options) {
|
|
722
|
+
const path = "/memories";
|
|
723
|
+
const body = buildBody({ content: options.content, description: options.description, path: options.path });
|
|
724
|
+
return await this.transport.request("POST", path, { body });
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Delete Memory
|
|
728
|
+
*
|
|
729
|
+
* Delete a memory that is no longer true.
|
|
730
|
+
*
|
|
731
|
+
* Available to every credential type, agents included — a wrong
|
|
732
|
+
* memory is worse than a missing one. The deleted content is kept in
|
|
733
|
+
* the memory's history for forensics, not for an undo API.
|
|
734
|
+
*/
|
|
735
|
+
async delete(memory_id, options = {}) {
|
|
736
|
+
const path = `/memories/${enc(memory_id)}`;
|
|
737
|
+
const query = buildQuery({ if_sha256: options.if_sha256 });
|
|
738
|
+
await this.transport.request("DELETE", path, { query });
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Edit Memory
|
|
742
|
+
*
|
|
743
|
+
* Correct an existing memory in place.
|
|
744
|
+
*
|
|
745
|
+
* Pass description, content, or both. This never creates a memory (an
|
|
746
|
+
* unknown id is a 404) and never moves one — the path is immutable, so
|
|
747
|
+
* relocating a memory is a delete plus a create.
|
|
748
|
+
*
|
|
749
|
+
* Pass `if_sha256` (from a previous read) to make a concurrent write
|
|
750
|
+
* a 409 instead of silently overwriting it.
|
|
751
|
+
*/
|
|
752
|
+
async edit(memory_id, options = {}) {
|
|
753
|
+
const path = `/memories/${enc(memory_id)}`;
|
|
754
|
+
const body = buildBody({ content: options.content, description: options.description, if_sha256: options.if_sha256 });
|
|
755
|
+
return await this.transport.request("PUT", path, { body });
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Get Memory
|
|
759
|
+
*
|
|
760
|
+
* Read one memory's full content.
|
|
761
|
+
*
|
|
762
|
+
* The id comes from the index returned by listing memories.
|
|
763
|
+
*/
|
|
764
|
+
async get(memory_id) {
|
|
765
|
+
const path = `/memories/${enc(memory_id)}`;
|
|
766
|
+
return await this.transport.request("GET", path);
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* List Memories
|
|
770
|
+
*
|
|
771
|
+
* List the organization's memories as a readable index.
|
|
772
|
+
*
|
|
773
|
+
* Returns the memories rendered as a markdown index (one line per
|
|
774
|
+
* memory, carrying its id, path, and description) plus the same
|
|
775
|
+
* entries structured, each with every field except `content`. Read
|
|
776
|
+
* the index, then fetch the ids whose content you want.
|
|
777
|
+
*/
|
|
778
|
+
async list(options = {}) {
|
|
779
|
+
const path = "/memories";
|
|
780
|
+
const query = buildQuery({ prefix: options.prefix });
|
|
781
|
+
return await this.transport.request("GET", path, { query });
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
var EllipsisModels = class {
|
|
785
|
+
constructor(transport) {
|
|
786
|
+
this.transport = transport;
|
|
787
|
+
}
|
|
788
|
+
transport;
|
|
789
|
+
/**
|
|
790
|
+
* List Supported Models
|
|
791
|
+
*
|
|
792
|
+
* List selectable agent models.
|
|
793
|
+
*
|
|
794
|
+
* Most expensive first, with the platform default flagged.
|
|
795
|
+
*
|
|
796
|
+
* Reads the same registry as the dashboard's rate table, so a
|
|
797
|
+
* client's model picker can never drift from what's offered.
|
|
798
|
+
* Behind auth but not account-scoped — the selectable set is
|
|
799
|
+
* global.
|
|
800
|
+
*/
|
|
801
|
+
async list() {
|
|
802
|
+
const path = "/models";
|
|
803
|
+
return await this.transport.request("GET", path);
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
var EllipsisReviews = class {
|
|
807
|
+
constructor(transport) {
|
|
808
|
+
this.transport = transport;
|
|
809
|
+
}
|
|
810
|
+
transport;
|
|
811
|
+
/**
|
|
812
|
+
* Create Review
|
|
813
|
+
*
|
|
814
|
+
* Run a code review on demand.
|
|
815
|
+
*
|
|
816
|
+
* Reviews an existing PR or a pushed branch (for a branch, the
|
|
817
|
+
* platform finds or creates a draft PR for it, since a code
|
|
818
|
+
* review is structurally about a PR).
|
|
819
|
+
*
|
|
820
|
+
* A review is one pipeline run over one commit range, with one
|
|
821
|
+
* agent session per stage: `review.id` is the run id, and
|
|
822
|
+
* `stages[].session_id` is where a client streams
|
|
823
|
+
* (/sessions/{id}/stream on a stage session), since the review
|
|
824
|
+
* itself is a pipeline rather than one process.
|
|
825
|
+
*/
|
|
826
|
+
async create(options) {
|
|
827
|
+
const path = "/reviews";
|
|
828
|
+
const body = buildBody({ owner: options.owner, post: options.post, pull_request_number: options.pull_request_number, repo: options.repo, scope: options.scope });
|
|
829
|
+
return await this.transport.request("POST", path, { body });
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Get Review
|
|
833
|
+
*
|
|
834
|
+
* Return one review with findings and outcome.
|
|
835
|
+
*
|
|
836
|
+
* Includes its scope, the per-stage sessions, the parsed findings,
|
|
837
|
+
* the finding counters, and the posting outcome.
|
|
838
|
+
*
|
|
839
|
+
* Findings only exist after a stage session finalizes — a running
|
|
840
|
+
* review honestly reports [] / null, which is why a client
|
|
841
|
+
* streams a stage session and then re-fetches the review.
|
|
842
|
+
*/
|
|
843
|
+
async get(review_id) {
|
|
844
|
+
const path = `/reviews/${enc(review_id)}`;
|
|
845
|
+
return await this.transport.request("GET", path);
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* List Reviews
|
|
849
|
+
*
|
|
850
|
+
* List code reviews, newest first.
|
|
851
|
+
*
|
|
852
|
+
* `findings` is omitted (counters only).
|
|
853
|
+
*
|
|
854
|
+
* Webhook-created reviews appear here too, so this answers "show
|
|
855
|
+
* me every review on this PR".
|
|
856
|
+
*/
|
|
857
|
+
async list(options = {}) {
|
|
858
|
+
const path = "/reviews";
|
|
859
|
+
const query = buildQuery({ owner: options.owner, repo: options.repo, pull_request_number: options.pull_request_number, status: options.status, limit: options.limit, cursor: options.cursor });
|
|
860
|
+
const response = await this.transport.request("GET", path, { query });
|
|
861
|
+
return new Page(
|
|
862
|
+
response,
|
|
863
|
+
"reviews",
|
|
864
|
+
(cursor) => this.list({ ...options, cursor })
|
|
92
865
|
);
|
|
93
866
|
}
|
|
94
867
|
};
|
|
868
|
+
var EllipsisSecrets = class {
|
|
869
|
+
constructor(transport) {
|
|
870
|
+
this.transport = transport;
|
|
871
|
+
}
|
|
872
|
+
transport;
|
|
873
|
+
/**
|
|
874
|
+
* Delete Secret
|
|
875
|
+
*
|
|
876
|
+
* Delete a secret by name.
|
|
877
|
+
*
|
|
878
|
+
* Refused for sandbox tokens; mutations require an API key or
|
|
879
|
+
* user token.
|
|
880
|
+
*/
|
|
881
|
+
async delete(name) {
|
|
882
|
+
const path = `/secrets/${enc(name)}`;
|
|
883
|
+
await this.transport.request("DELETE", path);
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* List Secrets
|
|
887
|
+
*
|
|
888
|
+
* List secrets.
|
|
889
|
+
*
|
|
890
|
+
* Values are write-only: the response carries only names and
|
|
891
|
+
* timestamps, never the stored value.
|
|
892
|
+
*/
|
|
893
|
+
async list() {
|
|
894
|
+
const path = "/secrets";
|
|
895
|
+
return await this.transport.request("GET", path);
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Put Secrets
|
|
899
|
+
*
|
|
900
|
+
* Upsert secrets.
|
|
901
|
+
*
|
|
902
|
+
* Returns only the secrets this call wrote, names and timestamps
|
|
903
|
+
* only — values are write-only. Refused for sandbox tokens (held by
|
|
904
|
+
* potentially-untrusted in-sandbox code); mutations require an
|
|
905
|
+
* API key or user token.
|
|
906
|
+
*/
|
|
907
|
+
async set(options) {
|
|
908
|
+
const path = "/secrets";
|
|
909
|
+
const body = buildBody({ secrets: options.secrets });
|
|
910
|
+
return await this.transport.request("PUT", path, { body });
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
var EllipsisSessions = class {
|
|
914
|
+
constructor(transport) {
|
|
915
|
+
this.transport = transport;
|
|
916
|
+
}
|
|
917
|
+
transport;
|
|
918
|
+
/**
|
|
919
|
+
* Get Agent Session Executions
|
|
920
|
+
*
|
|
921
|
+
* Return the session's executions and launch context.
|
|
922
|
+
*
|
|
923
|
+
* Most notably system_prompt_append, the text Ellipsis appends to
|
|
924
|
+
* Claude Code's default system prompt (platform section + response
|
|
925
|
+
* instructions + the config's own instructions).
|
|
926
|
+
*
|
|
927
|
+
* Per execution because each cold wake persists its own launch
|
|
928
|
+
* config (a config edit or replay override between wakes changes
|
|
929
|
+
* it).
|
|
930
|
+
*/
|
|
931
|
+
async executions(session_id) {
|
|
932
|
+
const path = `/sessions/${enc(session_id)}/executions`;
|
|
933
|
+
return await this.transport.request("GET", path);
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Export Agent Session
|
|
937
|
+
*
|
|
938
|
+
* Export the complete session history.
|
|
939
|
+
*
|
|
940
|
+
* The complete, ordered history of the session (agent output, tool calls, thinking,
|
|
941
|
+
* lifecycle events, sandbox output, message events) as an ordered
|
|
942
|
+
* manifest of presigned segment URLs.
|
|
943
|
+
*
|
|
944
|
+
* Segments are gzip members: download in order and concatenate
|
|
945
|
+
* for one file. The JSON API never carries the bytes (same
|
|
946
|
+
* two-step as files). /records is the paged live view of the
|
|
947
|
+
* same data.
|
|
948
|
+
*/
|
|
949
|
+
async export(session_id) {
|
|
950
|
+
const path = `/sessions/${enc(session_id)}/export`;
|
|
951
|
+
return await this.transport.request("GET", path);
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* Get Agent Session
|
|
955
|
+
*
|
|
956
|
+
* Return one session.
|
|
957
|
+
*
|
|
958
|
+
* The public wire shape — the same shape the stream's session
|
|
959
|
+
* frames carry, with attributed_user and stopped_by_user resolved
|
|
960
|
+
* at read time.
|
|
961
|
+
*
|
|
962
|
+
* The heavy near-static blobs (config snapshot, input/output)
|
|
963
|
+
* live on the detail endpoints, not here.
|
|
964
|
+
*/
|
|
965
|
+
async get(session_id) {
|
|
966
|
+
const path = `/sessions/${enc(session_id)}`;
|
|
967
|
+
return await this.transport.request("GET", path);
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Get Agent Session Ide
|
|
971
|
+
*
|
|
972
|
+
* Return the IDE link for the session's sandbox.
|
|
973
|
+
*
|
|
974
|
+
* The membership-gated dashboard page, which performs the sandbox
|
|
975
|
+
* proxy handoff itself.
|
|
976
|
+
*
|
|
977
|
+
* No credential is minted here — the URL grants nothing by
|
|
978
|
+
* possession. 409 when the sandbox isn't running (send the
|
|
979
|
+
* session a message to wake it first). Backs the `agent session
|
|
980
|
+
* ide` CLI verb.
|
|
981
|
+
*/
|
|
982
|
+
async ide(session_id) {
|
|
983
|
+
const path = `/sessions/${enc(session_id)}/ide`;
|
|
984
|
+
return await this.transport.request("GET", path);
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Ingest Agent Session Transcript
|
|
988
|
+
*
|
|
989
|
+
* Append transcript lines to a session's record.
|
|
990
|
+
*
|
|
991
|
+
* The in-sandbox tailer for interactive sessions.
|
|
992
|
+
*
|
|
993
|
+
* A sandbox token may only push its own session's transcript.
|
|
994
|
+
* Idempotent by transcript line uuid; tolerant of malformed lines.
|
|
995
|
+
*/
|
|
996
|
+
async ingestTranscript(session_id, options) {
|
|
997
|
+
const path = `/sessions/${enc(session_id)}/transcript`;
|
|
998
|
+
const body = buildBody({ lines: options.lines, offset: options.offset });
|
|
999
|
+
return await this.transport.request("POST", path, { body });
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* List Agent Sessions
|
|
1003
|
+
*
|
|
1004
|
+
* List cloud agent sessions, newest first.
|
|
1005
|
+
*
|
|
1006
|
+
* Optionally filtered by config (id or `ellipsis.name`), source, time
|
|
1007
|
+
* window, attributed author, repository, and whether the session is
|
|
1008
|
+
* still going.
|
|
1009
|
+
*/
|
|
1010
|
+
async list(options = {}) {
|
|
1011
|
+
const path = "/sessions";
|
|
1012
|
+
const query = buildQuery({ config_id: options.config_id, source: options.source, days: options.days, start: options.start, end: options.end, limit: options.limit, cursor: options.cursor, author_id: options.author_id, repo: options.repo, unfinished: options.unfinished });
|
|
1013
|
+
const response = await this.transport.request("GET", path, { query });
|
|
1014
|
+
return new Page(
|
|
1015
|
+
response,
|
|
1016
|
+
"sessions",
|
|
1017
|
+
(cursor) => this.list({ ...options, cursor })
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* Get Agent Session Output
|
|
1022
|
+
*
|
|
1023
|
+
* Return the session's typed output.
|
|
1024
|
+
*
|
|
1025
|
+
* The payload the agent submitted through its config-declared
|
|
1026
|
+
* output.json_schema, as the raw JSON body with no envelope. 404
|
|
1027
|
+
* while the session is still running (poll GET /sessions/{id}),
|
|
1028
|
+
* when the agent declares no output block, or when no execution
|
|
1029
|
+
* produced output.
|
|
1030
|
+
*/
|
|
1031
|
+
async output(session_id) {
|
|
1032
|
+
const path = `/sessions/${enc(session_id)}/output`;
|
|
1033
|
+
await this.transport.request("GET", path);
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Get Agent Session Port
|
|
1037
|
+
*
|
|
1038
|
+
* Return a preview link for a sandbox port.
|
|
1039
|
+
*
|
|
1040
|
+
* For a dev server running in the session's live sandbox: the
|
|
1041
|
+
* same dashboard page as the IDE, deep-linked to the port.
|
|
1042
|
+
*
|
|
1043
|
+
* Backs `agent session port`.
|
|
1044
|
+
*/
|
|
1045
|
+
async port(session_id, port) {
|
|
1046
|
+
const path = `/sessions/${enc(session_id)}/ports/${enc(String(port))}`;
|
|
1047
|
+
return await this.transport.request("GET", path);
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Get Agent Session Records
|
|
1051
|
+
*
|
|
1052
|
+
* Return the session's stored transcript records, oldest first.
|
|
1053
|
+
*
|
|
1054
|
+
* Pagination is opt-in (cursor/limit); a bare call returns the
|
|
1055
|
+
* full retained transcript. Available to sandbox tokens too: an
|
|
1056
|
+
* agent answering "did X look into Y?" needs to read the session
|
|
1057
|
+
* it found via /sessions/search, and any org member sees the same
|
|
1058
|
+
* transcript in the dashboard (laptop transcripts are redacted
|
|
1059
|
+
* client-side before they are ever uploaded).
|
|
1060
|
+
*/
|
|
1061
|
+
async records(session_id, options = {}) {
|
|
1062
|
+
const path = `/sessions/${enc(session_id)}/records`;
|
|
1063
|
+
const query = buildQuery({ cursor: options.cursor, limit: options.limit });
|
|
1064
|
+
const response = await this.transport.request("GET", path, { query });
|
|
1065
|
+
return new Page(
|
|
1066
|
+
response,
|
|
1067
|
+
"records",
|
|
1068
|
+
(cursor) => this.records(session_id, { ...options, cursor })
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Replay Agent Session
|
|
1073
|
+
*
|
|
1074
|
+
* Replay a session as a new session.
|
|
1075
|
+
*
|
|
1076
|
+
* Reuses the original config snapshot unless config_id is given,
|
|
1077
|
+
* and accepts the same config_override as session start — e.g.
|
|
1078
|
+
* {"claude": {"model": ...}} to replay the same input on a
|
|
1079
|
+
* different model.
|
|
1080
|
+
*/
|
|
1081
|
+
async replay(session_id, options = {}) {
|
|
1082
|
+
const path = `/sessions/${enc(session_id)}/replay`;
|
|
1083
|
+
const body = buildBody({ config_id: options.config_id, config_override: options.config_override, config_override_yaml: options.config_override_yaml, prompt: options.prompt });
|
|
1084
|
+
return await this.transport.request("POST", path, { body });
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Search Sessions
|
|
1088
|
+
*
|
|
1089
|
+
* Search sessions over steps, recaps, and pull requests.
|
|
1090
|
+
*
|
|
1091
|
+
* Grouped by session, over everything a session left behind: step text, recap text, created
|
|
1092
|
+
* PRs, and recap-embedding similarity.
|
|
1093
|
+
*
|
|
1094
|
+
* This is how an agent answers "did Tony look into X?": resolve
|
|
1095
|
+
* the author via /github/members, search, then read the winning
|
|
1096
|
+
* session via /sessions/{id} (recap) and /sessions/{id}/records
|
|
1097
|
+
* (transcript).
|
|
1098
|
+
*/
|
|
1099
|
+
async search(options = {}) {
|
|
1100
|
+
const path = "/sessions/search";
|
|
1101
|
+
const query = buildQuery({ q: options.q, scope: options.scope, source: options.source, author_id: options.author_id, config_id: options.config_id, session_ids: options.session_ids, repo: options.repo, status: options.status, start: options.start, end: options.end, limit: options.limit });
|
|
1102
|
+
return await this.transport.request("GET", path, { query });
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Send Agent Session Message
|
|
1106
|
+
*
|
|
1107
|
+
* Send a message to a session.
|
|
1108
|
+
*
|
|
1109
|
+
* 409 for react/cron, non-interactive, and closed sessions.
|
|
1110
|
+
* Returns the created message so the caller can track it by id; a
|
|
1111
|
+
* retried send with the same idempotency_key returns the original
|
|
1112
|
+
* message.
|
|
1113
|
+
*/
|
|
1114
|
+
async sendMessage(session_id, options) {
|
|
1115
|
+
const path = `/sessions/${enc(session_id)}/messages`;
|
|
1116
|
+
const body = buildBody({ idempotency_key: options.idempotency_key, message: options.message });
|
|
1117
|
+
return await this.transport.request("POST", path, { body });
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* Start Agent Session
|
|
1121
|
+
*
|
|
1122
|
+
* Start a cloud agent session.
|
|
1123
|
+
*
|
|
1124
|
+
* Provide at most one of config_id (an id or an agent name),
|
|
1125
|
+
* config, or
|
|
1126
|
+
* template_id; with none, the account's default-config ladder
|
|
1127
|
+
* resolves the config. 400 when idle_start is combined with
|
|
1128
|
+
* prompt, input, or handoff, or when a handoff is combined with
|
|
1129
|
+
* any config source or override. 422 when the agent declares an
|
|
1130
|
+
* input schema and the request's input is absent or invalid.
|
|
1131
|
+
*/
|
|
1132
|
+
async start(options = {}) {
|
|
1133
|
+
const path = "/sessions";
|
|
1134
|
+
const body = buildBody({ config: options.config, config_id: options.config_id, config_override: options.config_override, config_override_yaml: options.config_override_yaml, force_rebuild: options.force_rebuild, handoff: options.handoff, idle_start: options.idle_start, input: options.input, metadata: options.metadata, prompt: options.prompt, repository: options.repository, template_id: options.template_id });
|
|
1135
|
+
return await this.transport.request("POST", path, { body });
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Stop Agent Session
|
|
1139
|
+
*
|
|
1140
|
+
* Stop an in-flight session and return it.
|
|
1141
|
+
*
|
|
1142
|
+
* stopped_by is recorded only when the caller's credential maps
|
|
1143
|
+
* to a GitHub account.
|
|
1144
|
+
*/
|
|
1145
|
+
async stop(session_id) {
|
|
1146
|
+
const path = `/sessions/${enc(session_id)}/stop`;
|
|
1147
|
+
return await this.transport.request("POST", path);
|
|
1148
|
+
}
|
|
1149
|
+
/**
|
|
1150
|
+
* Sync Agent Session
|
|
1151
|
+
*
|
|
1152
|
+
* Sync a local Claude Code session to Ellipsis.
|
|
1153
|
+
*
|
|
1154
|
+
* Requires a user token (device-flow `agent login`): the user is
|
|
1155
|
+
* part of the sync's idempotency key, so API keys and sandbox
|
|
1156
|
+
* tokens are rejected with a 403 rather than silently attributed.
|
|
1157
|
+
*/
|
|
1158
|
+
async sync(options) {
|
|
1159
|
+
const path = "/sessions/sync";
|
|
1160
|
+
const body = buildBody({ cc_session_id: options.cc_session_id, cwd: options.cwd, git_branch: options.git_branch, reason: options.reason, repo: options.repo, transcript_gzip_b64: options.transcript_gzip_b64 });
|
|
1161
|
+
return await this.transport.request("POST", path, { body });
|
|
1162
|
+
}
|
|
1163
|
+
// ---- lifecycle sugar (hand-written layer over the generated core) ----
|
|
1164
|
+
/** Start a session and return a handle over it. */
|
|
1165
|
+
async run(options) {
|
|
1166
|
+
const response = await this.start(options);
|
|
1167
|
+
return new SessionHandle(this, response.session);
|
|
1168
|
+
}
|
|
1169
|
+
/** A handle over an existing session. */
|
|
1170
|
+
async handle(sessionId) {
|
|
1171
|
+
const response = await this.get(sessionId);
|
|
1172
|
+
return new SessionHandle(this, response.session);
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
var Ellipsis = class {
|
|
1176
|
+
transport;
|
|
1177
|
+
agents;
|
|
1178
|
+
alerts;
|
|
1179
|
+
analytics;
|
|
1180
|
+
auth;
|
|
1181
|
+
files;
|
|
1182
|
+
integrations;
|
|
1183
|
+
memories;
|
|
1184
|
+
models;
|
|
1185
|
+
reviews;
|
|
1186
|
+
secrets;
|
|
1187
|
+
sessions;
|
|
1188
|
+
constructor(options) {
|
|
1189
|
+
this.transport = new Transport(options);
|
|
1190
|
+
this.agents = new EllipsisAgents(this.transport);
|
|
1191
|
+
this.alerts = new EllipsisAlerts(this.transport);
|
|
1192
|
+
this.analytics = new EllipsisAnalytics(this.transport);
|
|
1193
|
+
this.auth = new EllipsisAuth(this.transport);
|
|
1194
|
+
this.files = new EllipsisFiles(this.transport);
|
|
1195
|
+
this.integrations = new EllipsisIntegrations(this.transport);
|
|
1196
|
+
this.memories = new EllipsisMemories(this.transport);
|
|
1197
|
+
this.models = new EllipsisModels(this.transport);
|
|
1198
|
+
this.reviews = new EllipsisReviews(this.transport);
|
|
1199
|
+
this.secrets = new EllipsisSecrets(this.transport);
|
|
1200
|
+
this.sessions = new EllipsisSessions(this.transport);
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Get Budget
|
|
1204
|
+
*
|
|
1205
|
+
* Return the caller's current budget summary.
|
|
1206
|
+
*/
|
|
1207
|
+
async budget() {
|
|
1208
|
+
const path = "/budget";
|
|
1209
|
+
return await this.transport.request("GET", path);
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* Whoami
|
|
1213
|
+
*
|
|
1214
|
+
* Return the identity behind the caller's credential.
|
|
1215
|
+
*/
|
|
1216
|
+
async me() {
|
|
1217
|
+
const path = "/me";
|
|
1218
|
+
return await this.transport.request("GET", path);
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* Get Usage Endpoint
|
|
1222
|
+
*
|
|
1223
|
+
* Return the caller's usage dashboard data.
|
|
1224
|
+
*/
|
|
1225
|
+
async usage() {
|
|
1226
|
+
const path = "/usage";
|
|
1227
|
+
return await this.transport.request("GET", path);
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
95
1230
|
export {
|
|
96
|
-
|
|
1231
|
+
APIError,
|
|
1232
|
+
AuthenticationError,
|
|
1233
|
+
ConflictError,
|
|
1234
|
+
DEFAULT_BASE_URL,
|
|
1235
|
+
Ellipsis,
|
|
1236
|
+
EllipsisError,
|
|
1237
|
+
ForbiddenError,
|
|
1238
|
+
NotFoundError,
|
|
1239
|
+
Page,
|
|
1240
|
+
RateLimitError,
|
|
1241
|
+
ServerError,
|
|
1242
|
+
SessionHandle,
|
|
1243
|
+
TERMINAL_STATUSES,
|
|
1244
|
+
Transport,
|
|
1245
|
+
TransportError,
|
|
1246
|
+
UnprocessableError,
|
|
1247
|
+
isSettled
|
|
97
1248
|
};
|