@agentpress/sdk 0.2.70
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 +402 -0
- package/dist/index.cjs +368 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +306 -0
- package/dist/index.d.ts +306 -0
- package/dist/index.mjs +335 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
# @agentpress/sdk
|
|
2
|
+
|
|
3
|
+
Zero-dependency TypeScript SDK for the AgentPress webhook API.
|
|
4
|
+
|
|
5
|
+
- **Package:** `@agentpress/sdk` (npm, public)
|
|
6
|
+
- **Output:** Dual ESM (`.mjs`) + CJS (`.cjs`)
|
|
7
|
+
- **Node:** >= 22.0.0
|
|
8
|
+
- **Dependencies:** None (uses `node:crypto` for HMAC-SHA256)
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @agentpress/sdk
|
|
14
|
+
# or
|
|
15
|
+
bun add @agentpress/sdk
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { AgentPress } from "@agentpress/sdk";
|
|
22
|
+
|
|
23
|
+
const client = new AgentPress({
|
|
24
|
+
webhookSecret: "whsec_your_secret_here",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Send a webhook
|
|
28
|
+
await client.webhooks.send({
|
|
29
|
+
action: "my_action",
|
|
30
|
+
payload: { eventType: "test", data: { key: "value" } },
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Constructor Options
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
const client = new AgentPress({
|
|
38
|
+
webhookSecret: "whsec_...", // Required for send/verify (must start with "whsec_")
|
|
39
|
+
baseUrl: "https://api.agent.press", // Default
|
|
40
|
+
timeout: 30_000, // Default, in milliseconds
|
|
41
|
+
org: "default-org", // Default org slug
|
|
42
|
+
apiKey: "sk_...", // Optional, reserved for future API auth
|
|
43
|
+
onRequest: (url, init) => {}, // Optional hook, called before every request
|
|
44
|
+
onResponse: (url, response) => {}, // Optional hook, receives a cloned Response
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
All options are optional. `webhookSecret` is required only when calling `send`, `verify`, or `verifyOrThrow`.
|
|
49
|
+
|
|
50
|
+
**Validation rules:**
|
|
51
|
+
- `webhookSecret` must start with `"whsec_"` or a `ConfigurationError` is thrown
|
|
52
|
+
- `timeout` must be a positive finite number
|
|
53
|
+
- Trailing slashes on `baseUrl` are stripped automatically
|
|
54
|
+
|
|
55
|
+
## API Reference
|
|
56
|
+
|
|
57
|
+
The client exposes two namespaces: `client.webhooks` and `client.actions`.
|
|
58
|
+
|
|
59
|
+
### client.webhooks.send(params)
|
|
60
|
+
|
|
61
|
+
Signs and sends an arbitrary webhook payload via HMAC-SHA256.
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
const response = await client.webhooks.send({
|
|
65
|
+
action: "my_webhook_action",
|
|
66
|
+
payload: {
|
|
67
|
+
eventType: "order.completed",
|
|
68
|
+
externalId: "order-456",
|
|
69
|
+
data: { total: 99.99 },
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Endpoint:** `POST {baseUrl}/webhooks/actions/{org}/{action}`
|
|
75
|
+
|
|
76
|
+
**Params (`WebhookSendParams`):**
|
|
77
|
+
|
|
78
|
+
| Field | Type | Description |
|
|
79
|
+
|-------|------|-------------|
|
|
80
|
+
| `action` | `string` | Webhook action identifier (used in URL path) |
|
|
81
|
+
| `payload` | `Record<string, unknown>` | Arbitrary JSON payload to sign and send |
|
|
82
|
+
|
|
83
|
+
**Returns (`WebhookResponse`):**
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
{
|
|
87
|
+
success: boolean;
|
|
88
|
+
actionId?: string; // ID of created action
|
|
89
|
+
alreadyExists?: boolean; // Duplicate externalId
|
|
90
|
+
skipped?: boolean;
|
|
91
|
+
data?: Record<string, unknown>;
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Throws:** `ConfigurationError` (missing secret), `HttpError` (non-2xx), `TimeoutError`
|
|
96
|
+
|
|
97
|
+
**Signing details:** Each request gets three headers automatically:
|
|
98
|
+
- `svix-id` -- unique message ID (`msg_<uuid>`)
|
|
99
|
+
- `svix-timestamp` -- Unix seconds
|
|
100
|
+
- `svix-signature` -- `v1,<base64 HMAC-SHA256>`
|
|
101
|
+
|
|
102
|
+
The signature input is `${msgId}.${timestamp}.${body}`.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### client.webhooks.verify(params)
|
|
107
|
+
|
|
108
|
+
Verifies an inbound Svix webhook signature. Returns `true` if valid, `false` if invalid or expired.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const isValid = client.webhooks.verify({
|
|
112
|
+
payload: rawRequestBody, // string or Buffer
|
|
113
|
+
headers: {
|
|
114
|
+
"svix-id": req.headers["svix-id"],
|
|
115
|
+
"svix-timestamp": req.headers["svix-timestamp"],
|
|
116
|
+
"svix-signature": req.headers["svix-signature"],
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
if (!isValid) {
|
|
121
|
+
return new Response("Unauthorized", { status: 401 });
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Params (`WebhookVerifyParams`):**
|
|
126
|
+
|
|
127
|
+
| Field | Type | Description |
|
|
128
|
+
|-------|------|-------------|
|
|
129
|
+
| `payload` | `string \| Buffer` | Raw request body |
|
|
130
|
+
| `headers["svix-id"]` | `string` | Message ID header |
|
|
131
|
+
| `headers["svix-timestamp"]` | `string` | Unix timestamp header |
|
|
132
|
+
| `headers["svix-signature"]` | `string` | Signature header (may contain space-separated signatures) |
|
|
133
|
+
|
|
134
|
+
**Verification rules:**
|
|
135
|
+
- Timestamp must be within 5 minutes of current time (replay protection)
|
|
136
|
+
- Uses timing-safe comparison (`timingSafeEqual`)
|
|
137
|
+
- Supports multiple space-separated signatures in the header (any match = valid)
|
|
138
|
+
|
|
139
|
+
**Throws:** `ConfigurationError` if `webhookSecret` was not provided
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### client.webhooks.verifyOrThrow(params)
|
|
144
|
+
|
|
145
|
+
Same as `verify` but throws `WebhookSignatureError` on invalid signature. Useful in middleware.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
try {
|
|
149
|
+
client.webhooks.verifyOrThrow({
|
|
150
|
+
payload: rawBody,
|
|
151
|
+
headers: {
|
|
152
|
+
"svix-id": headers["svix-id"],
|
|
153
|
+
"svix-timestamp": headers["svix-timestamp"],
|
|
154
|
+
"svix-signature": headers["svix-signature"],
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
// Signature is valid, proceed
|
|
158
|
+
} catch (error) {
|
|
159
|
+
if (error instanceof WebhookSignatureError) {
|
|
160
|
+
return new Response("Invalid signature", { status: 401 });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### client.webhooks.constructEvent(params)
|
|
166
|
+
|
|
167
|
+
Verify and parse an inbound webhook from AgentPress in one step. Combines signature verification with JSON parsing and returns a typed `ActionCallbackPayload`. This is the recommended way to handle incoming webhooks.
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { AgentPress, type ActionCallbackPayload } from "@agentpress/sdk";
|
|
171
|
+
|
|
172
|
+
const client = new AgentPress({ webhookSecret: "whsec_..." });
|
|
173
|
+
|
|
174
|
+
// Express example
|
|
175
|
+
app.post("/webhooks/agentpress", express.raw({ type: "application/json" }), (req, res) => {
|
|
176
|
+
const event = client.webhooks.constructEvent({
|
|
177
|
+
payload: req.body, // raw body string or Buffer
|
|
178
|
+
headers: {
|
|
179
|
+
"svix-id": req.headers["svix-id"] as string,
|
|
180
|
+
"svix-timestamp": req.headers["svix-timestamp"] as string,
|
|
181
|
+
"svix-signature": req.headers["svix-signature"] as string,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
console.log(event.status); // "completed" | "failed" | ...
|
|
186
|
+
console.log(event.agentResponse); // { text: "...", toolCalls: [...] }
|
|
187
|
+
|
|
188
|
+
res.status(200).json({ received: true });
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Params:** Same as `verify` / `verifyOrThrow` (`WebhookVerifyParams`).
|
|
193
|
+
|
|
194
|
+
**Returns (`ActionCallbackPayload`):**
|
|
195
|
+
|
|
196
|
+
| Field | Type | Description |
|
|
197
|
+
|-------|------|-------------|
|
|
198
|
+
| `actionId` | `string` | Action identifier |
|
|
199
|
+
| `status` | `ActionStatus` | `"completed"`, `"failed"`, `"rejected"`, etc. |
|
|
200
|
+
| `actionType` | `string` | The action type (e.g., `"order.created"`) |
|
|
201
|
+
| `completedAt` | `string` | ISO 8601 timestamp |
|
|
202
|
+
| `sourceData` | `Record<string, unknown>` | Original data from the inbound webhook |
|
|
203
|
+
| `externalId` | `string \| null` | External system identifier |
|
|
204
|
+
| `userId` | `string \| null` | AgentPress user ID |
|
|
205
|
+
| `threadId` | `string \| null` | Thread ID if a conversation was created |
|
|
206
|
+
| `agentResponse` | `AgentResponse` | Agent's text response and tool call results |
|
|
207
|
+
| `errorMessage` | `string \| null` | Error details if the action failed |
|
|
208
|
+
| `rejectionReason` | `string \| null` | Reason if rejected by a human reviewer |
|
|
209
|
+
|
|
210
|
+
**Throws:** `WebhookSignatureError` (invalid/expired signature), `ConfigurationError` (missing secret), `AgentPressError` (invalid JSON)
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
### client.actions.approve(actionId, params)
|
|
215
|
+
|
|
216
|
+
Approve a staged action, optionally modifying the tool call arguments before execution.
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
// Approve as-is
|
|
220
|
+
await client.actions.approve("act_123", {
|
|
221
|
+
action: "my_webhook_action",
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Approve with modified arguments
|
|
225
|
+
await client.actions.approve("act_123", {
|
|
226
|
+
action: "my_webhook_action",
|
|
227
|
+
editedToolCall: {
|
|
228
|
+
toolName: "sendEmail",
|
|
229
|
+
arguments: { subject: "Updated subject" },
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Endpoint:** `POST {baseUrl}/webhooks/actions/{org}/{action}/manage/{actionId}/approve`
|
|
235
|
+
|
|
236
|
+
**Params:**
|
|
237
|
+
|
|
238
|
+
| Field | Type | Description |
|
|
239
|
+
|-------|------|-------------|
|
|
240
|
+
| `actionId` | `string` | Action ID (first positional argument) |
|
|
241
|
+
| `params.action` | `string` | Webhook action identifier (from callback's `webhookAction` field) |
|
|
242
|
+
| `params.editedToolCall` | `object` (optional) | Modified tool call to use instead of the original |
|
|
243
|
+
|
|
244
|
+
**Returns (`ActionManageResponse`):**
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
{
|
|
248
|
+
success: boolean;
|
|
249
|
+
actionId: string;
|
|
250
|
+
status: ActionStatus;
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Throws:** `ConfigurationError` (missing secret), `HttpError` (non-2xx), `TimeoutError`
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
### client.actions.reject(actionId, params)
|
|
259
|
+
|
|
260
|
+
Reject a staged action with an optional reason.
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
await client.actions.reject("act_456", {
|
|
264
|
+
action: "my_webhook_action",
|
|
265
|
+
reason: "Insufficient context to proceed",
|
|
266
|
+
});
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**Endpoint:** `POST {baseUrl}/webhooks/actions/{org}/{action}/manage/{actionId}/reject`
|
|
270
|
+
|
|
271
|
+
**Params:**
|
|
272
|
+
|
|
273
|
+
| Field | Type | Description |
|
|
274
|
+
|-------|------|-------------|
|
|
275
|
+
| `actionId` | `string` | Action ID (first positional argument) |
|
|
276
|
+
| `params.action` | `string` | Webhook action identifier (from callback's `webhookAction` field) |
|
|
277
|
+
| `params.reason` | `string` (optional) | Reason for rejection |
|
|
278
|
+
|
|
279
|
+
**Returns:** `ActionManageResponse` (same as `approve`)
|
|
280
|
+
|
|
281
|
+
**Throws:** `ConfigurationError` (missing secret), `HttpError` (non-2xx), `TimeoutError`
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Error Handling
|
|
286
|
+
|
|
287
|
+
All errors extend `AgentPressError`. Import and use `instanceof` for specific handling.
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
import {
|
|
291
|
+
AgentPress,
|
|
292
|
+
AgentPressError,
|
|
293
|
+
ConfigurationError,
|
|
294
|
+
HttpError,
|
|
295
|
+
TimeoutError,
|
|
296
|
+
WebhookSignatureError,
|
|
297
|
+
} from "@agentpress/sdk";
|
|
298
|
+
|
|
299
|
+
try {
|
|
300
|
+
await client.webhooks.send({ action: "test", payload: {} });
|
|
301
|
+
} catch (error) {
|
|
302
|
+
if (error instanceof HttpError) {
|
|
303
|
+
// Non-2xx response from the server
|
|
304
|
+
console.log(error.statusCode); // e.g. 400, 404, 500
|
|
305
|
+
console.log(error.responseBody); // Raw response text
|
|
306
|
+
console.log(error.url); // Full request URL
|
|
307
|
+
} else if (error instanceof TimeoutError) {
|
|
308
|
+
// Request exceeded the configured timeout
|
|
309
|
+
} else if (error instanceof ConfigurationError) {
|
|
310
|
+
// Missing webhookSecret, invalid timeout, etc.
|
|
311
|
+
} else if (error instanceof WebhookSignatureError) {
|
|
312
|
+
// Only from verifyOrThrow -- invalid or expired signature
|
|
313
|
+
} else if (error instanceof AgentPressError) {
|
|
314
|
+
// Base class: fetch failures, unexpected non-JSON responses
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Error hierarchy:**
|
|
320
|
+
|
|
321
|
+
```
|
|
322
|
+
AgentPressError (base)
|
|
323
|
+
ConfigurationError -- invalid options or missing webhookSecret
|
|
324
|
+
HttpError -- non-2xx response (has statusCode, responseBody, url)
|
|
325
|
+
TimeoutError -- request exceeded timeout
|
|
326
|
+
WebhookSignatureError -- invalid/expired signature (from verifyOrThrow only)
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Exported Types
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
import type {
|
|
333
|
+
ActionCallbackPayload, // Inbound webhook payload from constructEvent()
|
|
334
|
+
ActionEventType, // "action.pending_approval" | "action.approved" | ...
|
|
335
|
+
ActionManageResponse, // Response from actions.approve() / actions.reject()
|
|
336
|
+
ActionStatus, // "pending" | "staged" | "approved" | "rejected" | "completed" | "failed" | "expired"
|
|
337
|
+
AgentPressOptions, // Constructor options
|
|
338
|
+
AgentResponse, // Agent text response + tool calls
|
|
339
|
+
ApproveActionParams, // actions.approve() params
|
|
340
|
+
RejectActionParams, // actions.reject() params
|
|
341
|
+
StagedToolCall, // Tool call awaiting approval
|
|
342
|
+
ToolCallResult, // Individual tool call (name, arguments, result)
|
|
343
|
+
WebhookResponse, // Response from send
|
|
344
|
+
WebhookSendParams, // send params
|
|
345
|
+
WebhookVerifyParams, // verify / verifyOrThrow / constructEvent params
|
|
346
|
+
} from "@agentpress/sdk";
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Full Example: Receiving Action Callbacks
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
import express from "express";
|
|
353
|
+
import { AgentPress, WebhookSignatureError, type ActionCallbackPayload } from "@agentpress/sdk";
|
|
354
|
+
|
|
355
|
+
const app = express();
|
|
356
|
+
const client = new AgentPress({ webhookSecret: process.env.WEBHOOK_SECRET });
|
|
357
|
+
|
|
358
|
+
// Recommended: use constructEvent() for verify + parse in one step
|
|
359
|
+
app.post("/webhooks/agentpress", express.raw({ type: "application/json" }), (req, res) => {
|
|
360
|
+
let event: ActionCallbackPayload;
|
|
361
|
+
try {
|
|
362
|
+
event = client.webhooks.constructEvent({
|
|
363
|
+
payload: req.body,
|
|
364
|
+
headers: {
|
|
365
|
+
"svix-id": req.headers["svix-id"] as string,
|
|
366
|
+
"svix-timestamp": req.headers["svix-timestamp"] as string,
|
|
367
|
+
"svix-signature": req.headers["svix-signature"] as string,
|
|
368
|
+
},
|
|
369
|
+
});
|
|
370
|
+
} catch (error) {
|
|
371
|
+
if (error instanceof WebhookSignatureError) {
|
|
372
|
+
return res.status(401).json({ error: "Invalid signature" });
|
|
373
|
+
}
|
|
374
|
+
throw error;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// event is fully typed as ActionCallbackPayload
|
|
378
|
+
console.log(`Action ${event.actionId} ${event.status}`);
|
|
379
|
+
if (event.agentResponse.text) {
|
|
380
|
+
console.log("Agent said:", event.agentResponse.text);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
res.json({ received: true });
|
|
384
|
+
});
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## File Structure
|
|
388
|
+
|
|
389
|
+
```
|
|
390
|
+
packages/sdk/src/
|
|
391
|
+
index.ts -- Public barrel export
|
|
392
|
+
client.ts -- AgentPress class, option validation + resolution
|
|
393
|
+
http.ts -- HttpClient (fetch wrapper with timeout, hooks, error parsing)
|
|
394
|
+
errors.ts -- Error class hierarchy
|
|
395
|
+
types.ts -- All exported types and interfaces
|
|
396
|
+
utils.ts -- randomMessageId() helper (msg_<uuid>)
|
|
397
|
+
actions/
|
|
398
|
+
client.ts -- ActionsClient (approve, reject)
|
|
399
|
+
webhooks/
|
|
400
|
+
client.ts -- WebhooksClient (send, verify, verifyOrThrow, constructEvent)
|
|
401
|
+
signing.ts -- HMAC-SHA256 Svix-compatible sign + verify functions
|
|
402
|
+
```
|