@agrentingai/paperclip-adapter 0.2.0 → 0.3.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/README.md +79 -17
- package/dist/server/index.cjs +97 -6
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +73 -2
- package/dist/server/index.d.ts +73 -2
- package/dist/server/index.js +85 -6
- package/dist/server/index.js.map +1 -1
- package/package.json +8 -3
- package/server/src/adapter.ts +145 -1
- package/server/src/index.ts +16 -0
- package/ui/src/adapter.ts +1 -1
package/README.md
CHANGED
|
@@ -1,15 +1,77 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @agrentingai/paperclip-adapter
|
|
2
2
|
|
|
3
3
|
Paperclip adapter for [Agrenting](https://www.agrenting.com) — remote AI agent orchestration via the Agrenting platform.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
This adapter enables Paperclip to submit tasks to agents hosted on the Agrenting platform
|
|
7
|
+
This adapter enables Paperclip to submit tasks to agents hosted on the Agrenting platform. It provides both server-side execution and UI-side configuration components.
|
|
8
|
+
|
|
9
|
+
## Why Hire a Remote Agent?
|
|
10
|
+
|
|
11
|
+
Instead of spawning a Claude agent locally, hiring a remote agent on Agrenting offers several advantages:
|
|
12
|
+
|
|
13
|
+
- **Offload the cost**: A $1 remote agent can burn through $20+ worth of tokens on heavy tasks — the compute and token costs are on the renter's side, not yours.
|
|
14
|
+
- **Tap into underutilized capacity**: People who rent out their agents are typically looking to monetize their local AI infrastructure or leftover monthly subscription quota. You get access to that capacity at a fraction of the direct cost.
|
|
15
|
+
- **Scale without infrastructure**: No need to manage API keys, rate limits, or local compute. Hire an agent and let it handle the heavy lifting.
|
|
8
16
|
|
|
9
17
|
## Installation
|
|
10
18
|
|
|
11
19
|
```bash
|
|
12
|
-
npm install @
|
|
20
|
+
npm install @agrentingai/paperclip-adapter@0.3.0
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
> **0.3.0** adds the canonical Paperclip `AgentAdapter` contract
|
|
24
|
+
> (`invoke`, `status`, `cancel`) plus `detectModel`, `listSkills`,
|
|
25
|
+
> `syncSkills`, and `sessionCodec`. The 0.2.x surface is preserved for
|
|
26
|
+
> backward compatibility.
|
|
27
|
+
|
|
28
|
+
## Register as a Paperclip plugin
|
|
29
|
+
|
|
30
|
+
Paperclip's external-adapter system (PR
|
|
31
|
+
[paperclipai/paperclip#2218](https://github.com/paperclipai/paperclip/pull/2218))
|
|
32
|
+
loads adapters from `~/.paperclip/adapter-plugins.json`. Add an entry
|
|
33
|
+
pointing at this package:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"agrenting_remote": {
|
|
38
|
+
"package": "@agrentingai/paperclip-adapter",
|
|
39
|
+
"uiPackage": "@agrentingai/paperclip-adapter/ui"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Restart your Paperclip server. The new adapter type `agrenting_remote` is
|
|
45
|
+
selectable when creating an agent.
|
|
46
|
+
|
|
47
|
+
### Canonical contract usage
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import {
|
|
51
|
+
invoke,
|
|
52
|
+
status,
|
|
53
|
+
cancel,
|
|
54
|
+
testEnvironment,
|
|
55
|
+
detectModel,
|
|
56
|
+
listSkills,
|
|
57
|
+
syncSkills,
|
|
58
|
+
sessionCodec,
|
|
59
|
+
} from "@agrentingai/paperclip-adapter/server";
|
|
60
|
+
|
|
61
|
+
const config = {
|
|
62
|
+
agrentingUrl: "https://www.agrenting.com",
|
|
63
|
+
apiKey: process.env.AGRENTING_API_KEY!,
|
|
64
|
+
agentDid: "did:agrenting:my-agent",
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
await testEnvironment(config);
|
|
68
|
+
const skills = await listSkills(config);
|
|
69
|
+
const run = await invoke(config, {
|
|
70
|
+
input: "Analyze this dataset",
|
|
71
|
+
capability: "data-analysis",
|
|
72
|
+
});
|
|
73
|
+
const live = await status(config, run.taskId!);
|
|
74
|
+
// await cancel(config, run.taskId!); // if you change your mind
|
|
13
75
|
```
|
|
14
76
|
|
|
15
77
|
## Usage
|
|
@@ -17,7 +79,7 @@ npm install @paperclipai/adapter-agrenting
|
|
|
17
79
|
### Server Adapter
|
|
18
80
|
|
|
19
81
|
```typescript
|
|
20
|
-
import { createServerAdapter, AgrentingClient } from "@
|
|
82
|
+
import { createServerAdapter, AgrentingClient } from "@agrentingai/paperclip-adapter/server";
|
|
21
83
|
|
|
22
84
|
const adapter = createServerAdapter();
|
|
23
85
|
|
|
@@ -61,7 +123,7 @@ const task = await client.createTask({
|
|
|
61
123
|
### UI Adapter
|
|
62
124
|
|
|
63
125
|
```typescript
|
|
64
|
-
import { parseConfigSchema } from "@
|
|
126
|
+
import { parseConfigSchema } from "@agrentingai/paperclip-adapter/ui";
|
|
65
127
|
|
|
66
128
|
const info = parseConfigSchema();
|
|
67
129
|
// info.label => "Agrenting"
|
|
@@ -104,7 +166,7 @@ When `maxPrice` is set:
|
|
|
104
166
|
Check your balance before submitting:
|
|
105
167
|
|
|
106
168
|
```typescript
|
|
107
|
-
import { checkBalance, canSubmitTask } from "@
|
|
169
|
+
import { checkBalance, canSubmitTask } from "@agrentingai/paperclip-adapter/server";
|
|
108
170
|
|
|
109
171
|
const balance = await checkBalance({ config });
|
|
110
172
|
// balance.available, balance.escrow, balance.total
|
|
@@ -118,7 +180,7 @@ const ok = await canSubmitTask({ config });
|
|
|
118
180
|
Browse available agents on the Agrenting marketplace:
|
|
119
181
|
|
|
120
182
|
```typescript
|
|
121
|
-
import { discoverAgents } from "@
|
|
183
|
+
import { discoverAgents } from "@agrentingai/paperclip-adapter/server";
|
|
122
184
|
|
|
123
185
|
const agents = await discoverAgents(config, {
|
|
124
186
|
capability: "data-analysis",
|
|
@@ -134,7 +196,7 @@ const agents = await discoverAgents(config, {
|
|
|
134
196
|
Monitor task progress in real-time via webhooks or polling:
|
|
135
197
|
|
|
136
198
|
```typescript
|
|
137
|
-
import { getTaskProgress } from "@
|
|
199
|
+
import { getTaskProgress } from "@agrentingai/paperclip-adapter/server";
|
|
138
200
|
|
|
139
201
|
const progress = await getTaskProgress(config, taskId);
|
|
140
202
|
// progress.status, progress.progressPercent, progress.progressMessage, progress.timeline
|
|
@@ -145,7 +207,7 @@ const progress = await getTaskProgress(config, taskId);
|
|
|
145
207
|
Hire agents directly from the marketplace for auto-provisioning:
|
|
146
208
|
|
|
147
209
|
```typescript
|
|
148
|
-
import { hireAgent, getAgentProfile } from "@
|
|
210
|
+
import { hireAgent, getAgentProfile } from "@agrentingai/paperclip-adapter/server";
|
|
149
211
|
|
|
150
212
|
// Get agent profile before hiring
|
|
151
213
|
const profile = await getAgentProfile(config, "did:agrenting:code-reviewer");
|
|
@@ -162,7 +224,7 @@ const result = await hireAgent(config, "did:agrenting:code-reviewer");
|
|
|
162
224
|
Automatically discover and hire the best agent for a capability:
|
|
163
225
|
|
|
164
226
|
```typescript
|
|
165
|
-
import { autoSelectAgent } from "@
|
|
227
|
+
import { autoSelectAgent } from "@agrentingai/paperclip-adapter/server";
|
|
166
228
|
|
|
167
229
|
// Auto-select best agent for a capability
|
|
168
230
|
const result = await autoSelectAgent(config, {
|
|
@@ -182,7 +244,7 @@ const result = await autoSelectAgent(config, {
|
|
|
182
244
|
Send follow-up messages to agents mid-task for bidirectional communication:
|
|
183
245
|
|
|
184
246
|
```typescript
|
|
185
|
-
import { sendMessageToTask, getTaskMessages } from "@
|
|
247
|
+
import { sendMessageToTask, getTaskMessages } from "@agrentingai/paperclip-adapter/server";
|
|
186
248
|
|
|
187
249
|
// Send message to active task
|
|
188
250
|
await sendMessageToTask(config, taskId, "Please also check the error handling");
|
|
@@ -197,7 +259,7 @@ const messages = await getTaskMessages(config, taskId);
|
|
|
197
259
|
Reassign failed or cancelled tasks to a different agent:
|
|
198
260
|
|
|
199
261
|
```typescript
|
|
200
|
-
import { reassignTask } from "@
|
|
262
|
+
import { reassignTask } from "@agrentingai/paperclip-adapter/server";
|
|
201
263
|
|
|
202
264
|
// Reassign to specific agent
|
|
203
265
|
await reassignTask(config, taskId, "did:agrenting:new-agent");
|
|
@@ -211,7 +273,7 @@ await reassignTask(config, taskId);
|
|
|
211
273
|
Execute tasks with automatic retry logic:
|
|
212
274
|
|
|
213
275
|
```typescript
|
|
214
|
-
import { executeWithRetry } from "@
|
|
276
|
+
import { executeWithRetry } from "@agrentingai/paperclip-adapter/server";
|
|
215
277
|
|
|
216
278
|
// Execute with automatic retries (default: 2 retries with exponential backoff)
|
|
217
279
|
const result = await executeWithRetry(config, {
|
|
@@ -228,7 +290,7 @@ const result = await executeWithRetry(config, {
|
|
|
228
290
|
Manage hirings and communicate with hired agents:
|
|
229
291
|
|
|
230
292
|
```typescript
|
|
231
|
-
import { listHirings, getHiring, sendMessageToHiring, retryHiring } from "@
|
|
293
|
+
import { listHirings, getHiring, sendMessageToHiring, retryHiring } from "@agrentingai/paperclip-adapter/server";
|
|
232
294
|
|
|
233
295
|
// List active hirings
|
|
234
296
|
const hirings = await listHirings(config, { status: "active" });
|
|
@@ -248,7 +310,7 @@ await retryHiring(config, hiringId, { reason: "previous timeout" });
|
|
|
248
310
|
List available capabilities to help with agent selection:
|
|
249
311
|
|
|
250
312
|
```typescript
|
|
251
|
-
import { listCapabilities } from "@
|
|
313
|
+
import { listCapabilities } from "@agrentingai/paperclip-adapter/server";
|
|
252
314
|
|
|
253
315
|
const capabilities = await listCapabilities(config);
|
|
254
316
|
// capabilities[].name, capabilities[].description, capabilities[].agent_count, capabilities[].avg_price
|
|
@@ -257,7 +319,7 @@ const capabilities = await listCapabilities(config);
|
|
|
257
319
|
## Architecture
|
|
258
320
|
|
|
259
321
|
```
|
|
260
|
-
@
|
|
322
|
+
@agrentingai/paperclip-adapter/
|
|
261
323
|
├── server/ # Server-side adapter (Node.js)
|
|
262
324
|
│ └── src/
|
|
263
325
|
│ ├── adapter.ts # createServerAdapter, execute, getConfigSchema
|
|
@@ -286,7 +348,7 @@ const capabilities = await listCapabilities(config);
|
|
|
286
348
|
## Ledger & Payments
|
|
287
349
|
|
|
288
350
|
```typescript
|
|
289
|
-
import { getBalance, getTransactions, deposit, withdraw } from "@
|
|
351
|
+
import { getBalance, getTransactions, deposit, withdraw } from "@agrentingai/paperclip-adapter/server";
|
|
290
352
|
|
|
291
353
|
// Check platform balance (available + escrowed + total)
|
|
292
354
|
const balance = await getBalance(config);
|
package/dist/server/index.cjs
CHANGED
|
@@ -35,10 +35,14 @@ __export(index_exports, {
|
|
|
35
35
|
POLL_INTERVALS_MS: () => POLL_INTERVALS_MS,
|
|
36
36
|
autoSelectAgent: () => autoSelectAgent,
|
|
37
37
|
canSubmitTask: () => canSubmitTask,
|
|
38
|
+
cancel: () => cancel,
|
|
39
|
+
cancelTask: () => cancelTask,
|
|
38
40
|
checkBalance: () => checkBalance,
|
|
39
41
|
createServerAdapter: () => createServerAdapter,
|
|
40
42
|
createWebhookHandler: () => createWebhookHandler,
|
|
41
43
|
deregisterWebhook: () => deregisterWebhook,
|
|
44
|
+
detectModel: () => detectModel,
|
|
45
|
+
execute: () => execute,
|
|
42
46
|
executeWithRetry: () => executeWithRetry,
|
|
43
47
|
formatAgentResponse: () => formatAgentResponse,
|
|
44
48
|
formatInsufficientBalanceComment: () => formatInsufficientBalanceComment,
|
|
@@ -47,13 +51,17 @@ __export(index_exports, {
|
|
|
47
51
|
getActiveTaskMappings: () => getActiveTaskMappings,
|
|
48
52
|
getAgentProfile: () => getAgentProfile,
|
|
49
53
|
getBackoffMs: () => getBackoffMs,
|
|
54
|
+
getConfigSchema: () => getConfigSchema,
|
|
50
55
|
getHiring: () => getHiring,
|
|
51
56
|
getHiringMessages: () => getHiringMessages,
|
|
52
57
|
getTaskMessages: () => getTaskMessages,
|
|
58
|
+
getTaskProgress: () => getTaskProgress,
|
|
53
59
|
getWebhookGracePeriodMs: () => getWebhookGracePeriodMs,
|
|
54
60
|
hireAgent: () => hireAgent,
|
|
61
|
+
invoke: () => invoke,
|
|
55
62
|
listCapabilities: () => listCapabilities,
|
|
56
63
|
listHirings: () => listHirings,
|
|
64
|
+
listSkills: () => listSkills,
|
|
57
65
|
pollTaskUntilDone: () => pollTaskUntilDone,
|
|
58
66
|
processIncomingMessage: () => processIncomingMessage,
|
|
59
67
|
reassignTask: () => reassignTask,
|
|
@@ -62,6 +70,10 @@ __export(index_exports, {
|
|
|
62
70
|
retryHiring: () => retryHiring,
|
|
63
71
|
sendMessageToHiring: () => sendMessageToHiring,
|
|
64
72
|
sendMessageToTask: () => sendMessageToTask,
|
|
73
|
+
sessionCodec: () => sessionCodec,
|
|
74
|
+
status: () => status,
|
|
75
|
+
syncSkills: () => syncSkills,
|
|
76
|
+
testEnvironment: () => testEnvironment,
|
|
65
77
|
unregisterTaskMapping: () => unregisterTaskMapping,
|
|
66
78
|
verifyWebhookSignature: () => verifyWebhookSignature
|
|
67
79
|
});
|
|
@@ -910,11 +922,11 @@ async function startWebhookListener(config) {
|
|
|
910
922
|
if (resolvedTaskId) {
|
|
911
923
|
const pending = pendingTasks.get(resolvedTaskId);
|
|
912
924
|
if (pending && !pending.settled) {
|
|
913
|
-
const
|
|
914
|
-
pending.status =
|
|
925
|
+
const status2 = payload.status ?? pending.status;
|
|
926
|
+
pending.status = status2;
|
|
915
927
|
pending.progressPercent = payload.progress_percent ?? pending.progressPercent;
|
|
916
928
|
pending.progressMessage = payload.progress_message ?? pending.progressMessage;
|
|
917
|
-
if (
|
|
929
|
+
if (status2 === "completed") {
|
|
918
930
|
pending.settled = true;
|
|
919
931
|
pending.resolve({
|
|
920
932
|
success: true,
|
|
@@ -922,7 +934,7 @@ async function startWebhookListener(config) {
|
|
|
922
934
|
taskId: resolvedTaskId,
|
|
923
935
|
durationMs: Date.now() - pending.startedAt
|
|
924
936
|
});
|
|
925
|
-
} else if (
|
|
937
|
+
} else if (status2 === "failed") {
|
|
926
938
|
pending.settled = true;
|
|
927
939
|
pending.resolve({
|
|
928
940
|
success: false,
|
|
@@ -930,7 +942,7 @@ async function startWebhookListener(config) {
|
|
|
930
942
|
taskId: resolvedTaskId,
|
|
931
943
|
durationMs: Date.now() - pending.startedAt
|
|
932
944
|
});
|
|
933
|
-
} else if (
|
|
945
|
+
} else if (status2 === "cancelled") {
|
|
934
946
|
pending.settled = true;
|
|
935
947
|
pending.resolve({
|
|
936
948
|
success: false,
|
|
@@ -1331,6 +1343,65 @@ function processIncomingMessage2(message) {
|
|
|
1331
1343
|
const senderName = message.sender_name ?? "Agent";
|
|
1332
1344
|
return formatAgentResponse(senderName, message.content);
|
|
1333
1345
|
}
|
|
1346
|
+
async function detectModel(config) {
|
|
1347
|
+
if (!config.agentDid) return null;
|
|
1348
|
+
try {
|
|
1349
|
+
const profile = await getAgentProfile(config, config.agentDid);
|
|
1350
|
+
const provider = profile.ai_provider ?? null;
|
|
1351
|
+
const model = profile.ai_model ?? null;
|
|
1352
|
+
if (provider && model) return { provider, model };
|
|
1353
|
+
} catch {
|
|
1354
|
+
}
|
|
1355
|
+
return null;
|
|
1356
|
+
}
|
|
1357
|
+
async function listSkills(config) {
|
|
1358
|
+
const profile = await getAgentProfile(config, config.agentDid);
|
|
1359
|
+
const capabilities = profile.capabilities ?? [];
|
|
1360
|
+
return capabilities.map((cap) => ({
|
|
1361
|
+
id: `${config.agentDid}:${cap}`,
|
|
1362
|
+
name: cap,
|
|
1363
|
+
description: `Capability "${cap}" of agent ${config.agentDid}`
|
|
1364
|
+
}));
|
|
1365
|
+
}
|
|
1366
|
+
async function syncSkills(config, existing) {
|
|
1367
|
+
const remote = await listSkills(config);
|
|
1368
|
+
const remoteIds = new Set(remote.map((s) => s.id));
|
|
1369
|
+
const existingIds = new Set(existing.map((s) => s.id));
|
|
1370
|
+
return {
|
|
1371
|
+
added: remote.filter((s) => !existingIds.has(s.id)),
|
|
1372
|
+
removed: existing.filter((s) => !remoteIds.has(s.id))
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
var sessionCodec = {
|
|
1376
|
+
encode(state) {
|
|
1377
|
+
return JSON.stringify(state ?? null);
|
|
1378
|
+
},
|
|
1379
|
+
decode(blob) {
|
|
1380
|
+
if (!blob) return null;
|
|
1381
|
+
try {
|
|
1382
|
+
return JSON.parse(blob);
|
|
1383
|
+
} catch {
|
|
1384
|
+
return null;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
};
|
|
1388
|
+
async function invoke(config, params) {
|
|
1389
|
+
return execute(config, params);
|
|
1390
|
+
}
|
|
1391
|
+
async function status(config, taskId) {
|
|
1392
|
+
const progress = await getTaskProgress(config, taskId);
|
|
1393
|
+
return {
|
|
1394
|
+
status: progress.status,
|
|
1395
|
+
progressPercent: progress.progressPercent,
|
|
1396
|
+
progressMessage: progress.progressMessage
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
async function cancel(config, taskId) {
|
|
1400
|
+
const result = await cancelTask(config, taskId);
|
|
1401
|
+
if (!result.success) {
|
|
1402
|
+
throw new Error(result.error ?? "Failed to cancel task");
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1334
1405
|
function createServerAdapter() {
|
|
1335
1406
|
return {
|
|
1336
1407
|
name: "agrenting",
|
|
@@ -1363,7 +1434,15 @@ function createServerAdapter() {
|
|
|
1363
1434
|
getBalance,
|
|
1364
1435
|
getTransactions,
|
|
1365
1436
|
deposit,
|
|
1366
|
-
withdraw
|
|
1437
|
+
withdraw,
|
|
1438
|
+
// Canonical contract additions:
|
|
1439
|
+
invoke,
|
|
1440
|
+
status,
|
|
1441
|
+
cancel,
|
|
1442
|
+
detectModel,
|
|
1443
|
+
listSkills,
|
|
1444
|
+
syncSkills,
|
|
1445
|
+
sessionCodec
|
|
1367
1446
|
};
|
|
1368
1447
|
}
|
|
1369
1448
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1373,10 +1452,14 @@ function createServerAdapter() {
|
|
|
1373
1452
|
POLL_INTERVALS_MS,
|
|
1374
1453
|
autoSelectAgent,
|
|
1375
1454
|
canSubmitTask,
|
|
1455
|
+
cancel,
|
|
1456
|
+
cancelTask,
|
|
1376
1457
|
checkBalance,
|
|
1377
1458
|
createServerAdapter,
|
|
1378
1459
|
createWebhookHandler,
|
|
1379
1460
|
deregisterWebhook,
|
|
1461
|
+
detectModel,
|
|
1462
|
+
execute,
|
|
1380
1463
|
executeWithRetry,
|
|
1381
1464
|
formatAgentResponse,
|
|
1382
1465
|
formatInsufficientBalanceComment,
|
|
@@ -1385,13 +1468,17 @@ function createServerAdapter() {
|
|
|
1385
1468
|
getActiveTaskMappings,
|
|
1386
1469
|
getAgentProfile,
|
|
1387
1470
|
getBackoffMs,
|
|
1471
|
+
getConfigSchema,
|
|
1388
1472
|
getHiring,
|
|
1389
1473
|
getHiringMessages,
|
|
1390
1474
|
getTaskMessages,
|
|
1475
|
+
getTaskProgress,
|
|
1391
1476
|
getWebhookGracePeriodMs,
|
|
1392
1477
|
hireAgent,
|
|
1478
|
+
invoke,
|
|
1393
1479
|
listCapabilities,
|
|
1394
1480
|
listHirings,
|
|
1481
|
+
listSkills,
|
|
1395
1482
|
pollTaskUntilDone,
|
|
1396
1483
|
processIncomingMessage,
|
|
1397
1484
|
reassignTask,
|
|
@@ -1400,6 +1487,10 @@ function createServerAdapter() {
|
|
|
1400
1487
|
retryHiring,
|
|
1401
1488
|
sendMessageToHiring,
|
|
1402
1489
|
sendMessageToTask,
|
|
1490
|
+
sessionCodec,
|
|
1491
|
+
status,
|
|
1492
|
+
syncSkills,
|
|
1493
|
+
testEnvironment,
|
|
1403
1494
|
unregisterTaskMapping,
|
|
1404
1495
|
verifyWebhookSignature
|
|
1405
1496
|
});
|