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