@perstack/api-client 0.0.45 → 0.0.48
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 +676 -77
- package/dist/bundle.d.mts +11863 -0
- package/dist/bundle.d.mts.map +1 -0
- package/dist/bundle.mjs +2261 -0
- package/dist/bundle.mjs.map +1 -0
- package/dist/chunk-Bdv87wj9.mjs +42 -0
- package/package.json +29 -21
- package/LICENSE +0 -202
- package/dist/index.d.ts +0 -438
- package/dist/index.js +0 -967
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,126 +1,725 @@
|
|
|
1
1
|
# @perstack/api-client
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
For API reference, see [Registry API](https://github.com/perstack-ai/perstack/blob/main/docs/references/registry-api.md).
|
|
3
|
+
Official TypeScript API client for the Perstack platform.
|
|
6
4
|
|
|
7
5
|
## Installation
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
8
|
npm install @perstack/api-client
|
|
11
|
-
# or
|
|
12
|
-
pnpm add @perstack/api-client
|
|
13
|
-
# or
|
|
14
|
-
yarn add @perstack/api-client
|
|
15
9
|
```
|
|
16
10
|
|
|
17
|
-
##
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { createApiClient } from "@perstack/api-client"
|
|
15
|
+
|
|
16
|
+
const client = createApiClient({
|
|
17
|
+
apiKey: "your-api-key",
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
// List applications
|
|
21
|
+
const result = await client.applications.list()
|
|
22
|
+
if (result.ok) {
|
|
23
|
+
console.log(result.data.data.applications)
|
|
24
|
+
} else {
|
|
25
|
+
console.error(result.error.message)
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
The `createApiClient` function accepts a configuration object:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
interface ApiClientConfig {
|
|
35
|
+
apiKey: string // Required: Your Perstack API key
|
|
36
|
+
baseUrl?: string // Optional: API base URL (default: "https://api.perstack.ai")
|
|
37
|
+
timeout?: number // Optional: Request timeout in milliseconds (default: 30000)
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## API Reference
|
|
42
|
+
|
|
43
|
+
The client provides access to four main API modules:
|
|
44
|
+
|
|
45
|
+
- `client.applications` - Application management
|
|
46
|
+
- `client.env` - Environment configuration (secrets and variables)
|
|
47
|
+
- `client.jobs` - Job execution and monitoring
|
|
48
|
+
- `client.experts` - Expert definitions and versioning
|
|
49
|
+
|
|
50
|
+
### Result Type
|
|
18
51
|
|
|
19
|
-
|
|
52
|
+
All API methods return a discriminated union type for type-safe error handling:
|
|
20
53
|
|
|
21
54
|
```typescript
|
|
22
|
-
|
|
55
|
+
type ApiResult<T> = { ok: true; data: T } | { ok: false; error: ApiError }
|
|
23
56
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
57
|
+
interface ApiError {
|
|
58
|
+
code: number // HTTP status code (0 for network/validation errors)
|
|
59
|
+
message: string // Error message
|
|
60
|
+
reason?: unknown // Additional error details
|
|
61
|
+
aborted?: boolean // True if request was aborted
|
|
62
|
+
}
|
|
28
63
|
```
|
|
29
64
|
|
|
30
|
-
###
|
|
65
|
+
### Request Options
|
|
31
66
|
|
|
32
|
-
|
|
67
|
+
All API methods accept an optional `RequestOptions` object:
|
|
33
68
|
|
|
34
69
|
```typescript
|
|
35
|
-
|
|
36
|
-
|
|
70
|
+
interface RequestOptions {
|
|
71
|
+
signal?: AbortSignal // AbortController signal for cancellation
|
|
72
|
+
}
|
|
73
|
+
```
|
|
37
74
|
|
|
38
|
-
|
|
39
|
-
const expert = await client.registry.experts.get({
|
|
40
|
-
owner: "perstack",
|
|
41
|
-
slug: "software-engineer",
|
|
42
|
-
});
|
|
75
|
+
For streaming endpoints, an extended `StreamRequestOptions` is available:
|
|
43
76
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
});
|
|
77
|
+
```typescript
|
|
78
|
+
interface StreamRequestOptions extends RequestOptions {
|
|
79
|
+
streamIdleTimeout?: number // Idle timeout in ms between chunks (default: client timeout)
|
|
80
|
+
}
|
|
49
81
|
```
|
|
50
82
|
|
|
51
|
-
|
|
83
|
+
---
|
|
52
84
|
|
|
53
|
-
|
|
85
|
+
### Applications API
|
|
54
86
|
|
|
55
|
-
|
|
87
|
+
Manage applications within your organization.
|
|
88
|
+
|
|
89
|
+
#### `client.applications.list(params?, options?)`
|
|
90
|
+
|
|
91
|
+
List all applications with optional filtering and pagination.
|
|
56
92
|
|
|
57
93
|
```typescript
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
94
|
+
const result = await client.applications.list({
|
|
95
|
+
name: "my-app", // Filter by name
|
|
96
|
+
sort: "createdAt", // Sort by: "name" | "createdAt" | "updatedAt"
|
|
97
|
+
order: "desc", // Order: "asc" | "desc"
|
|
98
|
+
take: 10, // Number of results
|
|
99
|
+
skip: 0, // Offset for pagination
|
|
100
|
+
})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### `client.applications.get(id, options?)`
|
|
63
104
|
|
|
64
|
-
|
|
65
|
-
|
|
105
|
+
Get a single application by ID.
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const result = await client.applications.get("app-id")
|
|
109
|
+
if (result.ok) {
|
|
110
|
+
console.log(result.data.data.application)
|
|
111
|
+
}
|
|
66
112
|
```
|
|
67
113
|
|
|
68
|
-
####
|
|
114
|
+
#### `client.applications.create(input, options?)`
|
|
69
115
|
|
|
70
|
-
|
|
116
|
+
Create a new application.
|
|
71
117
|
|
|
72
118
|
```typescript
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
119
|
+
const result = await client.applications.create({
|
|
120
|
+
name: "My Application",
|
|
121
|
+
applicationGroupId: "group-id", // Optional
|
|
122
|
+
})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### `client.applications.update(id, input, options?)`
|
|
126
|
+
|
|
127
|
+
Update an existing application.
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const result = await client.applications.update("app-id", {
|
|
131
|
+
name: "Updated Name",
|
|
132
|
+
status: "active", // "active" | "inactive"
|
|
133
|
+
})
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### `client.applications.delete(id, options?)`
|
|
137
|
+
|
|
138
|
+
Delete an application.
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
const result = await client.applications.delete("app-id")
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### Environment API
|
|
147
|
+
|
|
148
|
+
Manage secrets and environment variables.
|
|
149
|
+
|
|
150
|
+
#### Secrets
|
|
151
|
+
|
|
152
|
+
##### `client.env.secrets.list(options?)`
|
|
153
|
+
|
|
154
|
+
List all secrets.
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
const result = await client.env.secrets.list()
|
|
158
|
+
if (result.ok) {
|
|
159
|
+
for (const secret of result.data.data.secrets) {
|
|
160
|
+
console.log(secret.name) // Secret values are not returned
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
##### `client.env.secrets.get(name, options?)`
|
|
166
|
+
|
|
167
|
+
Get a secret by name.
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
const result = await client.env.secrets.get("API_KEY")
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
##### `client.env.secrets.create(input, options?)`
|
|
174
|
+
|
|
175
|
+
Create a new secret.
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
const result = await client.env.secrets.create({
|
|
179
|
+
name: "API_KEY",
|
|
180
|
+
value: "secret-value",
|
|
181
|
+
})
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
##### `client.env.secrets.update(name, input, options?)`
|
|
185
|
+
|
|
186
|
+
Update an existing secret.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
const result = await client.env.secrets.update("API_KEY", {
|
|
190
|
+
value: "new-secret-value",
|
|
191
|
+
})
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
##### `client.env.secrets.delete(name, options?)`
|
|
195
|
+
|
|
196
|
+
Delete a secret.
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
const result = await client.env.secrets.delete("API_KEY")
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
#### Variables
|
|
203
|
+
|
|
204
|
+
##### `client.env.variables.list(options?)`
|
|
205
|
+
|
|
206
|
+
List all environment variables.
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
const result = await client.env.variables.list()
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
##### `client.env.variables.get(name, options?)`
|
|
213
|
+
|
|
214
|
+
Get a variable by name.
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
const result = await client.env.variables.get("DATABASE_URL")
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
##### `client.env.variables.create(input, options?)`
|
|
221
|
+
|
|
222
|
+
Create a new variable.
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
const result = await client.env.variables.create({
|
|
226
|
+
name: "DATABASE_URL",
|
|
227
|
+
value: "postgres://...",
|
|
228
|
+
})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
##### `client.env.variables.update(name, input, options?)`
|
|
232
|
+
|
|
233
|
+
Update an existing variable.
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
const result = await client.env.variables.update("DATABASE_URL", {
|
|
237
|
+
value: "postgres://new-url...",
|
|
238
|
+
})
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
##### `client.env.variables.delete(name, options?)`
|
|
242
|
+
|
|
243
|
+
Delete a variable.
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
const result = await client.env.variables.delete("DATABASE_URL")
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
### Jobs API
|
|
252
|
+
|
|
253
|
+
Execute and monitor expert jobs.
|
|
254
|
+
|
|
255
|
+
#### `client.jobs.list(params?, options?)`
|
|
256
|
+
|
|
257
|
+
List jobs with optional filtering and pagination.
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
const result = await client.jobs.list({
|
|
261
|
+
take: 20,
|
|
262
|
+
skip: 0,
|
|
263
|
+
sort: "createdAt",
|
|
264
|
+
order: "desc",
|
|
265
|
+
filter: "status:running",
|
|
266
|
+
})
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
#### `client.jobs.get(id, options?)`
|
|
270
|
+
|
|
271
|
+
Get a job by ID.
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
const result = await client.jobs.get("job-id")
|
|
275
|
+
if (result.ok) {
|
|
276
|
+
console.log(result.data.data.job.status)
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
#### `client.jobs.start(input, options?)`
|
|
281
|
+
|
|
282
|
+
Start a new job.
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
const result = await client.jobs.start({
|
|
286
|
+
applicationId: "app-id",
|
|
287
|
+
expertKey: "@org/expert@1.0.0",
|
|
288
|
+
query: "Help me with this task",
|
|
289
|
+
files: ["file1.txt", "file2.txt"], // Optional
|
|
290
|
+
provider: "anthropic",
|
|
291
|
+
model: "claude-sonnet-4-20250514", // Optional
|
|
292
|
+
reasoningBudget: "medium", // Optional: "low" | "medium" | "high"
|
|
293
|
+
maxSteps: 50, // Optional
|
|
294
|
+
maxRetries: 3, // Optional
|
|
295
|
+
})
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
#### `client.jobs.update(id, input, options?)`
|
|
299
|
+
|
|
300
|
+
Update a job's status.
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
const result = await client.jobs.update("job-id", {
|
|
304
|
+
status: "paused",
|
|
305
|
+
})
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
#### `client.jobs.continue(id, input, options?)`
|
|
309
|
+
|
|
310
|
+
Continue a paused job with additional input.
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
const result = await client.jobs.continue("job-id", {
|
|
314
|
+
query: "Continue with this additional context",
|
|
315
|
+
files: ["additional-file.txt"],
|
|
316
|
+
interactiveToolCallResult: true, // Optional: for tool call responses
|
|
317
|
+
provider: "anthropic", // Optional: override provider
|
|
318
|
+
model: "claude-sonnet-4-20250514", // Optional: override model
|
|
319
|
+
maxSteps: 10, // Optional: additional steps limit
|
|
320
|
+
})
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
#### `client.jobs.cancel(id, options?)`
|
|
324
|
+
|
|
325
|
+
Cancel a running job.
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
const result = await client.jobs.cancel("job-id")
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
#### Checkpoints
|
|
332
|
+
|
|
333
|
+
Track job progress through checkpoints.
|
|
334
|
+
|
|
335
|
+
##### `client.jobs.checkpoints.list(jobId, params?, options?)`
|
|
336
|
+
|
|
337
|
+
List checkpoints for a job.
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
const result = await client.jobs.checkpoints.list("job-id", {
|
|
341
|
+
take: 50,
|
|
342
|
+
skip: 0,
|
|
343
|
+
sort: "createdAt",
|
|
344
|
+
order: "asc",
|
|
345
|
+
})
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
##### `client.jobs.checkpoints.get(jobId, checkpointId, options?)`
|
|
349
|
+
|
|
350
|
+
Get a specific checkpoint.
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
const result = await client.jobs.checkpoints.get("job-id", "checkpoint-id")
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
##### `client.jobs.checkpoints.stream(jobId, options?)`
|
|
357
|
+
|
|
358
|
+
Stream checkpoints in real-time using Server-Sent Events (SSE).
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
for await (const checkpoint of client.jobs.checkpoints.stream("job-id")) {
|
|
362
|
+
console.log("Activity:", checkpoint.activity)
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
### Experts API
|
|
369
|
+
|
|
370
|
+
Manage expert definitions and versions.
|
|
371
|
+
|
|
372
|
+
#### `client.experts.list(params?, options?)`
|
|
373
|
+
|
|
374
|
+
List available experts.
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
const result = await client.experts.list({
|
|
378
|
+
filter: "search term",
|
|
379
|
+
category: "coding", // "general" | "coding" | "research" | "writing" | "data" | "automation"
|
|
380
|
+
includeDrafts: false,
|
|
381
|
+
limit: 20,
|
|
382
|
+
offset: 0,
|
|
383
|
+
})
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
#### `client.experts.get(key, options?)`
|
|
387
|
+
|
|
388
|
+
Get an expert definition by key.
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
// Get latest version
|
|
392
|
+
const result = await client.experts.get("@org/expert")
|
|
393
|
+
|
|
394
|
+
// Get specific version
|
|
395
|
+
const result = await client.experts.get("@org/expert@1.0.0")
|
|
396
|
+
|
|
397
|
+
// Get by tag
|
|
398
|
+
const result = await client.experts.get("@org/expert@latest")
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
#### `client.experts.getMeta(key, options?)`
|
|
402
|
+
|
|
403
|
+
Get expert metadata without the full definition.
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
const result = await client.experts.getMeta("@org/expert@1.0.0")
|
|
407
|
+
if (result.ok) {
|
|
408
|
+
console.log("Scope:", result.data.data.scope)
|
|
409
|
+
console.log("Version:", result.data.data.version)
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
#### `client.experts.publish(scopeName, options?)`
|
|
414
|
+
|
|
415
|
+
Publish an expert scope (make it publicly visible).
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
const result = await client.experts.publish("@org/expert")
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
#### `client.experts.unpublish(scopeName, options?)`
|
|
422
|
+
|
|
423
|
+
Unpublish an expert scope (make it private).
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
const result = await client.experts.unpublish("@org/expert")
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
#### `client.experts.yank(key, options?)`
|
|
430
|
+
|
|
431
|
+
Yank (deprecate) a specific version.
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
const result = await client.experts.yank("@org/expert@1.0.0")
|
|
435
|
+
if (result.ok) {
|
|
436
|
+
console.log("Yanked:", result.data.data.yanked)
|
|
437
|
+
console.log("Latest tag updated:", result.data.data.latestTagUpdated)
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
#### Drafts
|
|
442
|
+
|
|
443
|
+
Manage expert draft versions before publishing.
|
|
444
|
+
|
|
445
|
+
##### `client.experts.drafts.list(scopeName, params?, options?)`
|
|
446
|
+
|
|
447
|
+
List drafts for a scope.
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
const result = await client.experts.drafts.list("@org/expert", {
|
|
451
|
+
limit: 10,
|
|
452
|
+
offset: 0,
|
|
453
|
+
})
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
##### `client.experts.drafts.get(scopeName, draftRef, options?)`
|
|
457
|
+
|
|
458
|
+
Get a specific draft.
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
const result = await client.experts.drafts.get("@org/expert", "draft-ref")
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
##### `client.experts.drafts.create(scopeName, input, options?)`
|
|
465
|
+
|
|
466
|
+
Create a new draft.
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
const result = await client.experts.drafts.create("@org/expert", {
|
|
470
|
+
applicationId: "app-id",
|
|
471
|
+
experts: [
|
|
472
|
+
{
|
|
473
|
+
key: "main",
|
|
474
|
+
name: "Main Expert",
|
|
475
|
+
description: "A helpful assistant",
|
|
476
|
+
instruction: "You are a helpful assistant...",
|
|
477
|
+
skills: {},
|
|
478
|
+
delegates: [],
|
|
479
|
+
},
|
|
480
|
+
],
|
|
481
|
+
})
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
##### `client.experts.drafts.update(scopeName, draftRef, input, options?)`
|
|
80
485
|
|
|
81
|
-
|
|
82
|
-
const jobStatus = await client.studio.expertJobs.get({
|
|
83
|
-
id: job.id,
|
|
84
|
-
});
|
|
486
|
+
Update an existing draft.
|
|
85
487
|
|
|
86
|
-
|
|
87
|
-
await client.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
488
|
+
```typescript
|
|
489
|
+
const result = await client.experts.drafts.update("@org/expert", "draft-ref", {
|
|
490
|
+
experts: [
|
|
491
|
+
{
|
|
492
|
+
key: "main",
|
|
493
|
+
name: "Updated Expert",
|
|
494
|
+
instruction: "Updated instructions...",
|
|
495
|
+
},
|
|
496
|
+
],
|
|
497
|
+
})
|
|
93
498
|
```
|
|
94
499
|
|
|
95
|
-
|
|
500
|
+
##### `client.experts.drafts.delete(scopeName, draftRef, options?)`
|
|
96
501
|
|
|
97
|
-
|
|
502
|
+
Delete a draft.
|
|
98
503
|
|
|
99
504
|
```typescript
|
|
100
|
-
|
|
101
|
-
|
|
505
|
+
const result = await client.experts.drafts.delete("@org/expert", "draft-ref")
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
##### `client.experts.drafts.assignVersion(scopeName, draftRef, input, options?)`
|
|
102
509
|
|
|
103
|
-
|
|
104
|
-
await client.studio.workspace.items.create({
|
|
105
|
-
path: "/path/to/file.txt",
|
|
106
|
-
content: "Hello, World!",
|
|
107
|
-
});
|
|
510
|
+
Promote a draft to a versioned release.
|
|
108
511
|
|
|
109
|
-
|
|
110
|
-
await client.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
})
|
|
512
|
+
```typescript
|
|
513
|
+
const result = await client.experts.drafts.assignVersion("@org/expert", "draft-ref", {
|
|
514
|
+
version: "1.0.0",
|
|
515
|
+
tag: "latest", // Optional: assign a tag
|
|
516
|
+
})
|
|
114
517
|
```
|
|
115
518
|
|
|
519
|
+
#### Versions
|
|
520
|
+
|
|
521
|
+
List expert versions.
|
|
522
|
+
|
|
523
|
+
##### `client.experts.versions.list(scopeName, options?)`
|
|
524
|
+
|
|
525
|
+
List all versions for a scope.
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
const result = await client.experts.versions.list("@org/expert")
|
|
529
|
+
if (result.ok) {
|
|
530
|
+
for (const version of result.data.data.versions) {
|
|
531
|
+
console.log(`${version.version}: ${version.tag || "(no tag)"}`)
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
116
538
|
## Error Handling
|
|
117
539
|
|
|
118
|
-
The client
|
|
540
|
+
The client uses a result type pattern for predictable error handling:
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
const result = await client.applications.get("app-id")
|
|
544
|
+
|
|
545
|
+
if (!result.ok) {
|
|
546
|
+
switch (result.error.code) {
|
|
547
|
+
case 401:
|
|
548
|
+
console.error("Authentication failed")
|
|
549
|
+
break
|
|
550
|
+
case 404:
|
|
551
|
+
console.error("Application not found")
|
|
552
|
+
break
|
|
553
|
+
case 0:
|
|
554
|
+
// Network error, timeout, or validation error
|
|
555
|
+
if (result.error.aborted) {
|
|
556
|
+
console.error("Request was cancelled")
|
|
557
|
+
} else {
|
|
558
|
+
console.error("Network error:", result.error.message)
|
|
559
|
+
}
|
|
560
|
+
break
|
|
561
|
+
default:
|
|
562
|
+
console.error(`Error ${result.error.code}: ${result.error.message}`)
|
|
563
|
+
}
|
|
564
|
+
return
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// TypeScript knows result.data exists here
|
|
568
|
+
console.log(result.data.data.application)
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### Request Cancellation
|
|
572
|
+
|
|
573
|
+
Use `AbortController` to cancel requests:
|
|
574
|
+
|
|
575
|
+
```typescript
|
|
576
|
+
const controller = new AbortController()
|
|
577
|
+
|
|
578
|
+
// Cancel after 5 seconds
|
|
579
|
+
setTimeout(() => controller.abort(), 5000)
|
|
580
|
+
|
|
581
|
+
const result = await client.jobs.start(
|
|
582
|
+
{ applicationId: "app-id", expertKey: "@org/expert", provider: "anthropic" },
|
|
583
|
+
{ signal: controller.signal }
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
if (!result.ok && result.error.aborted) {
|
|
587
|
+
console.log("Request was cancelled")
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## SSE Streaming
|
|
594
|
+
|
|
595
|
+
For real-time checkpoint streaming, the client provides an async generator:
|
|
596
|
+
|
|
597
|
+
```typescript
|
|
598
|
+
import { createApiClient } from "@perstack/api-client"
|
|
599
|
+
|
|
600
|
+
const client = createApiClient({ apiKey: "your-api-key" })
|
|
601
|
+
|
|
602
|
+
// Start a job
|
|
603
|
+
const jobResult = await client.jobs.start({
|
|
604
|
+
applicationId: "app-id",
|
|
605
|
+
expertKey: "@org/expert",
|
|
606
|
+
provider: "anthropic",
|
|
607
|
+
})
|
|
608
|
+
|
|
609
|
+
if (!jobResult.ok) {
|
|
610
|
+
throw new Error(jobResult.error.message)
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const jobId = jobResult.data.data.job.id
|
|
614
|
+
|
|
615
|
+
// Stream checkpoints
|
|
616
|
+
for await (const result of client.jobs.checkpoints.stream(jobId)) {
|
|
617
|
+
if (!result.ok) {
|
|
618
|
+
if (result.error.aborted) {
|
|
619
|
+
console.error("Stream timed out or was cancelled")
|
|
620
|
+
} else {
|
|
621
|
+
console.error("Stream error:", result.error.message)
|
|
622
|
+
}
|
|
623
|
+
break
|
|
624
|
+
}
|
|
625
|
+
console.log("Checkpoint:", result.data.id)
|
|
626
|
+
}
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
### Stream Timeout Configuration
|
|
630
|
+
|
|
631
|
+
The streaming endpoints support an idle timeout that aborts the stream if no data is received within the specified period:
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
for await (const result of client.jobs.checkpoints.stream(jobId, {
|
|
635
|
+
streamIdleTimeout: 60000, // 60 second idle timeout
|
|
636
|
+
})) {
|
|
637
|
+
if (!result.ok) {
|
|
638
|
+
if (result.error.aborted) {
|
|
639
|
+
console.error("Stream timed out or was cancelled")
|
|
640
|
+
}
|
|
641
|
+
break
|
|
642
|
+
}
|
|
643
|
+
console.log("Checkpoint:", result.data.id)
|
|
644
|
+
}
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
By default, the stream idle timeout uses the client's configured timeout value (30 seconds if not specified).
|
|
648
|
+
|
|
649
|
+
### Advanced SSE Parsing
|
|
650
|
+
|
|
651
|
+
For custom SSE parsing, the package exports utility functions:
|
|
119
652
|
|
|
120
653
|
```typescript
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
654
|
+
import { parseSSE, parseCheckpointSSE, parseSSEWithSchema } from "@perstack/api-client"
|
|
655
|
+
import { z } from "zod"
|
|
656
|
+
|
|
657
|
+
// Generic SSE parser
|
|
658
|
+
const reader = response.body.getReader()
|
|
659
|
+
for await (const event of parseSSE<MyEventType>(reader)) {
|
|
660
|
+
console.log(event)
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// Checkpoint-specific parser with validation
|
|
664
|
+
for await (const event of parseCheckpointSSE(reader)) {
|
|
665
|
+
if (event.type === "checkpoint") {
|
|
666
|
+
console.log("Checkpoint:", event.data)
|
|
667
|
+
} else if (event.type === "done") {
|
|
668
|
+
console.log("Stream complete:", event.data.status)
|
|
669
|
+
} else if (event.type === "error") {
|
|
670
|
+
console.error("Parse error:", event.data.message)
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Custom schema validation
|
|
675
|
+
const mySchema = z.object({ id: z.string(), value: z.number() })
|
|
676
|
+
for await (const event of parseSSEWithSchema(reader, mySchema)) {
|
|
677
|
+
console.log(event.id, event.value)
|
|
125
678
|
}
|
|
126
679
|
```
|
|
680
|
+
|
|
681
|
+
---
|
|
682
|
+
|
|
683
|
+
## TypeScript Support
|
|
684
|
+
|
|
685
|
+
The package is written in TypeScript and exports all types:
|
|
686
|
+
|
|
687
|
+
```typescript
|
|
688
|
+
import type {
|
|
689
|
+
// Client types
|
|
690
|
+
ApiClient,
|
|
691
|
+
ApiClientConfig,
|
|
692
|
+
ApiResult,
|
|
693
|
+
ApiError,
|
|
694
|
+
RequestOptions,
|
|
695
|
+
StreamRequestOptions,
|
|
696
|
+
|
|
697
|
+
// Application types
|
|
698
|
+
Application,
|
|
699
|
+
ApplicationStatus,
|
|
700
|
+
CreateApplicationInput,
|
|
701
|
+
UpdateApplicationInput,
|
|
702
|
+
ListApplicationsParams,
|
|
703
|
+
|
|
704
|
+
// Job types
|
|
705
|
+
Job,
|
|
706
|
+
JobStatus,
|
|
707
|
+
StartJobInput,
|
|
708
|
+
UpdateJobInput,
|
|
709
|
+
ContinueJobInput,
|
|
710
|
+
Checkpoint,
|
|
711
|
+
CheckpointStatus,
|
|
712
|
+
|
|
713
|
+
// Expert types
|
|
714
|
+
Expert,
|
|
715
|
+
ExpertDefinition,
|
|
716
|
+
ExpertVersion,
|
|
717
|
+
ExpertScope,
|
|
718
|
+
} from "@perstack/api-client"
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
|
|
723
|
+
## License
|
|
724
|
+
|
|
725
|
+
MIT
|