@agrentingai/paperclip-adapter 0.3.0 → 0.4.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/CHANGELOG.md +86 -0
- package/LICENSE +21 -0
- package/README.md +157 -296
- package/VERSION +1 -0
- package/dist/server/index.cjs +619 -44
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +156 -42
- package/dist/server/index.d.ts +156 -42
- package/dist/server/index.js +610 -44
- package/dist/server/index.js.map +1 -1
- package/dist/ui/index.cjs +1 -1
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.js +1 -1
- package/dist/ui/index.js.map +1 -1
- package/package.json +18 -6
- package/server/src/adapter.test.ts +0 -497
- package/server/src/adapter.ts +0 -1188
- package/server/src/balance-monitor.test.ts +0 -147
- package/server/src/balance-monitor.ts +0 -118
- package/server/src/client.test.ts +0 -949
- package/server/src/client.ts +0 -550
- package/server/src/comment-sync.test.ts +0 -25
- package/server/src/comment-sync.ts +0 -71
- package/server/src/crypto.test.ts +0 -62
- package/server/src/crypto.ts +0 -25
- package/server/src/index.ts +0 -83
- package/server/src/polling.test.ts +0 -208
- package/server/src/polling.ts +0 -183
- package/server/src/types.ts +0 -244
- package/server/src/webhook-handler.test.ts +0 -379
- package/server/src/webhook-handler.ts +0 -292
- package/ui/src/adapter.ts +0 -131
- package/ui/src/index.ts +0 -2
package/dist/server/index.cjs
CHANGED
|
@@ -33,9 +33,12 @@ __export(index_exports, {
|
|
|
33
33
|
AgrentingClient: () => AgrentingClient,
|
|
34
34
|
MAX_POLLS: () => MAX_POLLS,
|
|
35
35
|
POLL_INTERVALS_MS: () => POLL_INTERVALS_MS,
|
|
36
|
+
agentConfigurationDoc: () => agentConfigurationDoc,
|
|
37
|
+
agrentingAppGalleryEntry: () => agrentingAppGalleryEntry,
|
|
36
38
|
autoSelectAgent: () => autoSelectAgent,
|
|
37
39
|
canSubmitTask: () => canSubmitTask,
|
|
38
40
|
cancel: () => cancel,
|
|
41
|
+
cancelHiring: () => cancelHiring,
|
|
39
42
|
cancelTask: () => cancelTask,
|
|
40
43
|
checkBalance: () => checkBalance,
|
|
41
44
|
createServerAdapter: () => createServerAdapter,
|
|
@@ -43,6 +46,7 @@ __export(index_exports, {
|
|
|
43
46
|
deregisterWebhook: () => deregisterWebhook,
|
|
44
47
|
detectModel: () => detectModel,
|
|
45
48
|
execute: () => execute,
|
|
49
|
+
executePaperclip: () => executePaperclip,
|
|
46
50
|
executeWithRetry: () => executeWithRetry,
|
|
47
51
|
formatAgentResponse: () => formatAgentResponse,
|
|
48
52
|
formatInsufficientBalanceComment: () => formatInsufficientBalanceComment,
|
|
@@ -54,14 +58,17 @@ __export(index_exports, {
|
|
|
54
58
|
getConfigSchema: () => getConfigSchema,
|
|
55
59
|
getHiring: () => getHiring,
|
|
56
60
|
getHiringMessages: () => getHiringMessages,
|
|
61
|
+
getPaperclipConfigSchema: () => getPaperclipConfigSchema,
|
|
57
62
|
getTaskMessages: () => getTaskMessages,
|
|
58
63
|
getTaskProgress: () => getTaskProgress,
|
|
59
64
|
getWebhookGracePeriodMs: () => getWebhookGracePeriodMs,
|
|
60
65
|
hireAgent: () => hireAgent,
|
|
61
66
|
invoke: () => invoke,
|
|
67
|
+
label: () => label,
|
|
62
68
|
listCapabilities: () => listCapabilities,
|
|
63
69
|
listHirings: () => listHirings,
|
|
64
70
|
listSkills: () => listSkills,
|
|
71
|
+
paperclipSessionCodec: () => paperclipSessionCodec,
|
|
65
72
|
pollTaskUntilDone: () => pollTaskUntilDone,
|
|
66
73
|
processIncomingMessage: () => processIncomingMessage,
|
|
67
74
|
reassignTask: () => reassignTask,
|
|
@@ -74,6 +81,8 @@ __export(index_exports, {
|
|
|
74
81
|
status: () => status,
|
|
75
82
|
syncSkills: () => syncSkills,
|
|
76
83
|
testEnvironment: () => testEnvironment,
|
|
84
|
+
testPaperclipEnvironment: () => testPaperclipEnvironment,
|
|
85
|
+
type: () => type,
|
|
77
86
|
unregisterTaskMapping: () => unregisterTaskMapping,
|
|
78
87
|
verifyWebhookSignature: () => verifyWebhookSignature
|
|
79
88
|
});
|
|
@@ -82,6 +91,12 @@ module.exports = __toCommonJS(index_exports);
|
|
|
82
91
|
// server/src/client.ts
|
|
83
92
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
84
93
|
var MAX_RETRIES = 3;
|
|
94
|
+
var NonRetryableAgrentingError = class extends Error {
|
|
95
|
+
constructor(message) {
|
|
96
|
+
super(message);
|
|
97
|
+
this.name = "NonRetryableAgrentingError";
|
|
98
|
+
}
|
|
99
|
+
};
|
|
85
100
|
var AgrentingClient = class {
|
|
86
101
|
baseUrl;
|
|
87
102
|
apiKey;
|
|
@@ -128,17 +143,22 @@ var AgrentingClient = class {
|
|
|
128
143
|
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
129
144
|
continue;
|
|
130
145
|
}
|
|
131
|
-
throw new
|
|
146
|
+
throw new NonRetryableAgrentingError(
|
|
132
147
|
`Agrenting API ${response.status}: ${text.slice(0, 500)}`
|
|
133
148
|
);
|
|
134
149
|
}
|
|
135
150
|
const envelope = await response.json();
|
|
136
151
|
if (Array.isArray(envelope.errors) && envelope.errors.length) {
|
|
137
|
-
throw new
|
|
152
|
+
throw new NonRetryableAgrentingError(
|
|
153
|
+
`API errors: ${envelope.errors.join(", ")}`
|
|
154
|
+
);
|
|
138
155
|
}
|
|
139
156
|
return envelope.data ?? envelope;
|
|
140
157
|
} catch (err) {
|
|
141
158
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
159
|
+
if (lastError instanceof NonRetryableAgrentingError) {
|
|
160
|
+
throw lastError;
|
|
161
|
+
}
|
|
142
162
|
if (attempt < MAX_RETRIES) {
|
|
143
163
|
clearTimeout(timer);
|
|
144
164
|
const delayMs = Math.min(1e3 * 2 ** attempt, 3e4);
|
|
@@ -324,12 +344,23 @@ var AgrentingClient = class {
|
|
|
324
344
|
async getAgentProfile(agentDid) {
|
|
325
345
|
return this.request("GET", `/api/v1/agents/${encodeURIComponent(agentDid)}`);
|
|
326
346
|
}
|
|
327
|
-
/**
|
|
328
|
-
*
|
|
347
|
+
/** Create a paid hiring for an agent.
|
|
348
|
+
* Agrenting requires a concrete task, capability, and offered price.
|
|
329
349
|
*/
|
|
330
|
-
async hireAgent(agentDid, options
|
|
331
|
-
const body = {
|
|
332
|
-
|
|
350
|
+
async hireAgent(agentDid, options) {
|
|
351
|
+
const body = {
|
|
352
|
+
task_description: options.taskDescription,
|
|
353
|
+
capability_requested: options.capabilityRequested,
|
|
354
|
+
price: String(options.price),
|
|
355
|
+
delivery_mode: options.deliveryMode ?? "output"
|
|
356
|
+
};
|
|
357
|
+
if (options.repoUrl) body.repo_url = options.repoUrl;
|
|
358
|
+
if (options.repoAccessToken) body.repo_access_token = options.repoAccessToken;
|
|
359
|
+
if (options.clientIdempotencyKey) {
|
|
360
|
+
body.client_idempotency_key = options.clientIdempotencyKey;
|
|
361
|
+
}
|
|
362
|
+
if (options.taskInput) body.task_input = options.taskInput;
|
|
363
|
+
if (options.clientMessage) body.client_message = options.clientMessage;
|
|
333
364
|
return this.request(
|
|
334
365
|
"POST",
|
|
335
366
|
`/api/v1/agents/${encodeURIComponent(agentDid)}/hire`,
|
|
@@ -388,13 +419,11 @@ var AgrentingClient = class {
|
|
|
388
419
|
);
|
|
389
420
|
}
|
|
390
421
|
/** Get messages for a hiring.
|
|
391
|
-
* GET /api/v1/hirings/:id
|
|
422
|
+
* The canonical API includes recent messages in GET /api/v1/hirings/:id.
|
|
392
423
|
*/
|
|
393
424
|
async getHiringMessages(hiringId) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
`/api/v1/hirings/${hiringId}/messages`
|
|
397
|
-
);
|
|
425
|
+
const hiring = await this.getHiring(hiringId);
|
|
426
|
+
return hiring.messages ?? [];
|
|
398
427
|
}
|
|
399
428
|
/** Retry a failed hiring.
|
|
400
429
|
* POST /api/v1/hirings/:id/retry
|
|
@@ -416,6 +445,15 @@ var AgrentingClient = class {
|
|
|
416
445
|
async getHiring(hiringId) {
|
|
417
446
|
return this.request("GET", `/api/v1/hirings/${hiringId}`);
|
|
418
447
|
}
|
|
448
|
+
/** Cancel an active hiring.
|
|
449
|
+
* POST /api/v1/hirings/:id/cancel
|
|
450
|
+
*/
|
|
451
|
+
async cancelHiring(hiringId) {
|
|
452
|
+
return this.request(
|
|
453
|
+
"POST",
|
|
454
|
+
`/api/v1/hirings/${hiringId}/cancel`
|
|
455
|
+
);
|
|
456
|
+
}
|
|
419
457
|
/** List hirings for the authenticated agent.
|
|
420
458
|
* GET /api/v1/hirings
|
|
421
459
|
*/
|
|
@@ -423,9 +461,16 @@ var AgrentingClient = class {
|
|
|
423
461
|
const params = new URLSearchParams();
|
|
424
462
|
if (options.status) params.set("status", options.status);
|
|
425
463
|
if (options.limit) params.set("limit", String(options.limit));
|
|
426
|
-
if (options.offset)
|
|
464
|
+
if (options.offset) {
|
|
465
|
+
const perPage = options.limit ?? 20;
|
|
466
|
+
params.set("page", String(Math.floor(options.offset / perPage) + 1));
|
|
467
|
+
}
|
|
427
468
|
const query = params.toString() ? `?${params}` : "";
|
|
428
|
-
|
|
469
|
+
const result = await this.request(
|
|
470
|
+
"GET",
|
|
471
|
+
`/api/v1/hirings${query}`
|
|
472
|
+
);
|
|
473
|
+
return result.hirings;
|
|
429
474
|
}
|
|
430
475
|
/** List agents filtered by capability for auto-select.
|
|
431
476
|
* GET /api/v1/agents?capability=X
|
|
@@ -438,6 +483,493 @@ var AgrentingClient = class {
|
|
|
438
483
|
}
|
|
439
484
|
};
|
|
440
485
|
|
|
486
|
+
// server/src/paperclip.ts
|
|
487
|
+
var type = "agrenting";
|
|
488
|
+
var label = "Agrenting";
|
|
489
|
+
var agentConfigurationDoc = `# agrenting agent configuration
|
|
490
|
+
|
|
491
|
+
Adapter: agrenting
|
|
492
|
+
|
|
493
|
+
Use when:
|
|
494
|
+
- A Paperclip agent should delegate each heartbeat to a remote agent hired from Agrenting.
|
|
495
|
+
- The operator has an Agrenting user API token and sufficient ledger balance.
|
|
496
|
+
|
|
497
|
+
Core fields:
|
|
498
|
+
- agrentingUrl (required): Agrenting base URL, normally https://agrenting.com
|
|
499
|
+
- apiKey (required, secret): Agrenting user API token (ap_...)
|
|
500
|
+
- agentDid (required): DID of the marketplace agent to hire
|
|
501
|
+
- capabilityRequested (optional): defaults to the first capability on the agent profile
|
|
502
|
+
- price (optional): defaults to the agent's current base price
|
|
503
|
+
- timeoutSec (optional): maximum time to poll a hiring, default 600
|
|
504
|
+
- pollIntervalMs (optional): hiring status poll interval, default 2000
|
|
505
|
+
- deliveryMode (optional): output by default; push requires repository access
|
|
506
|
+
- repoUrl (optional): repository URL used only when deliveryMode is push
|
|
507
|
+
|
|
508
|
+
Recommended API-key scopes:
|
|
509
|
+
- agents:discover, agents:read, hire:create, hirings:read, hirings:cancel
|
|
510
|
+
- add balance:read and artifacts:read when sharing the key with Apps/Claude
|
|
511
|
+
- deposits:create and account:read/account:write are optional elevated scopes
|
|
512
|
+
- set max_price_per_hire on the key to cap paid actions
|
|
513
|
+
|
|
514
|
+
Execution:
|
|
515
|
+
- Each Paperclip run creates one canonical Agrenting hiring.
|
|
516
|
+
- The Paperclip run id is sent as client_idempotency_key so safe retries deduplicate.
|
|
517
|
+
- Paperclip polls the hiring until it completes, fails, is cancelled, or times out.
|
|
518
|
+
- Push delivery can use a repository URL from Paperclip and an Agrenting-stored
|
|
519
|
+
GitHub token. The adapter never stores a repository token in agent config.
|
|
520
|
+
`;
|
|
521
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
522
|
+
"completed",
|
|
523
|
+
"failed",
|
|
524
|
+
"cancelled",
|
|
525
|
+
"disputed",
|
|
526
|
+
"refunded"
|
|
527
|
+
]);
|
|
528
|
+
var DEFAULT_TIMEOUT_SEC = 600;
|
|
529
|
+
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
530
|
+
var MAX_TASK_DESCRIPTION_LENGTH = 5e3;
|
|
531
|
+
function asRecord(value) {
|
|
532
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
return value;
|
|
536
|
+
}
|
|
537
|
+
function nonEmpty(value) {
|
|
538
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
539
|
+
}
|
|
540
|
+
function positiveNumber(value, fallback) {
|
|
541
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
542
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
543
|
+
}
|
|
544
|
+
function configFrom(raw) {
|
|
545
|
+
return {
|
|
546
|
+
agrentingUrl: nonEmpty(raw.agrentingUrl) ?? "https://agrenting.com",
|
|
547
|
+
apiKey: nonEmpty(raw.apiKey) ?? "",
|
|
548
|
+
agentDid: nonEmpty(raw.agentDid) ?? "",
|
|
549
|
+
capabilityRequested: nonEmpty(raw.capabilityRequested) ?? void 0,
|
|
550
|
+
price: nonEmpty(raw.price) ?? void 0,
|
|
551
|
+
timeoutSec: positiveNumber(raw.timeoutSec, DEFAULT_TIMEOUT_SEC),
|
|
552
|
+
pollIntervalMs: positiveNumber(
|
|
553
|
+
raw.pollIntervalMs,
|
|
554
|
+
DEFAULT_POLL_INTERVAL_MS
|
|
555
|
+
),
|
|
556
|
+
deliveryMode: raw.deliveryMode === "push" ? "push" : "output",
|
|
557
|
+
repoUrl: nonEmpty(raw.repoUrl) ?? void 0
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
function taskDescriptionFrom(ctx) {
|
|
561
|
+
const context = ctx.context;
|
|
562
|
+
const title = nonEmpty(context.taskTitle) ?? nonEmpty(context.issueTitle) ?? nonEmpty(context.title);
|
|
563
|
+
const body = nonEmpty(context.paperclipTaskMarkdown) ?? nonEmpty(context.taskBody) ?? nonEmpty(context.taskDescription) ?? nonEmpty(context.issueDescription) ?? nonEmpty(context.prompt) ?? nonEmpty(context.input);
|
|
564
|
+
let description = [title, body].filter(Boolean).join("\n\n").trim();
|
|
565
|
+
if (!description) {
|
|
566
|
+
description = `Continue the assigned Paperclip work for ${ctx.agent.name}.`;
|
|
567
|
+
}
|
|
568
|
+
if (description.length <= MAX_TASK_DESCRIPTION_LENGTH) return description;
|
|
569
|
+
return `${description.slice(0, MAX_TASK_DESCRIPTION_LENGTH - 32)}
|
|
570
|
+
|
|
571
|
+
[truncated by Paperclip adapter]`;
|
|
572
|
+
}
|
|
573
|
+
function capabilityFrom(config, context, profile) {
|
|
574
|
+
return nonEmpty(config.capabilityRequested) ?? nonEmpty(context.capabilityRequested) ?? nonEmpty(context.capability) ?? profile.capabilities.find((capability) => capability.trim().length > 0) ?? null;
|
|
575
|
+
}
|
|
576
|
+
function priceFrom(config, context, profile) {
|
|
577
|
+
return nonEmpty(config.price) ?? nonEmpty(context.price) ?? nonEmpty(context.maxPrice) ?? nonEmpty(profile.base_price);
|
|
578
|
+
}
|
|
579
|
+
function repoUrlFrom(ctx) {
|
|
580
|
+
const workspace = asRecord(ctx.context.paperclipWorkspace);
|
|
581
|
+
return nonEmpty(configFrom(ctx.config).repoUrl) ?? nonEmpty(workspace?.repoUrl) ?? void 0;
|
|
582
|
+
}
|
|
583
|
+
function taskInputFrom(ctx) {
|
|
584
|
+
const input = {
|
|
585
|
+
paperclip_run_id: ctx.runId,
|
|
586
|
+
paperclip_agent_id: ctx.agent.id,
|
|
587
|
+
paperclip_company_id: ctx.agent.companyId
|
|
588
|
+
};
|
|
589
|
+
const mappings = [
|
|
590
|
+
["paperclip_issue_id", ctx.context.issueId ?? ctx.context.taskId],
|
|
591
|
+
["paperclip_project_id", ctx.context.projectId],
|
|
592
|
+
["paperclip_wake_reason", ctx.context.wakeReason]
|
|
593
|
+
];
|
|
594
|
+
for (const [key, value] of mappings) {
|
|
595
|
+
const normalized = nonEmpty(value);
|
|
596
|
+
if (normalized) input[key] = normalized;
|
|
597
|
+
}
|
|
598
|
+
const wake = asRecord(ctx.context.paperclipWake);
|
|
599
|
+
if (wake) input.paperclip_wake = wake;
|
|
600
|
+
return input;
|
|
601
|
+
}
|
|
602
|
+
function outputText(hiring) {
|
|
603
|
+
const output = hiring.task_output;
|
|
604
|
+
if (typeof output === "string" && output.trim()) return output;
|
|
605
|
+
const record = asRecord(output);
|
|
606
|
+
if (record) {
|
|
607
|
+
for (const key of ["result", "output", "text", "summary"]) {
|
|
608
|
+
const direct = nonEmpty(record[key]);
|
|
609
|
+
if (direct) return direct;
|
|
610
|
+
}
|
|
611
|
+
return JSON.stringify(record, null, 2);
|
|
612
|
+
}
|
|
613
|
+
return `Agrenting hiring ${hiring.id} completed.`;
|
|
614
|
+
}
|
|
615
|
+
function firstLine(value) {
|
|
616
|
+
return value.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? "Agrenting hiring completed";
|
|
617
|
+
}
|
|
618
|
+
function sleep(ms) {
|
|
619
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
620
|
+
}
|
|
621
|
+
function resultForFailure(hiring, message) {
|
|
622
|
+
return {
|
|
623
|
+
exitCode: 1,
|
|
624
|
+
signal: null,
|
|
625
|
+
timedOut: false,
|
|
626
|
+
errorMessage: message,
|
|
627
|
+
errorCode: `agrenting_hiring_${hiring.status}`,
|
|
628
|
+
provider: "agrenting",
|
|
629
|
+
biller: "agrenting",
|
|
630
|
+
sessionParams: { hiringId: hiring.id },
|
|
631
|
+
sessionDisplayId: hiring.id,
|
|
632
|
+
resultJson: {
|
|
633
|
+
hiringId: hiring.id,
|
|
634
|
+
status: hiring.status,
|
|
635
|
+
failedReason: hiring.failed_reason ?? null
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
async function executePaperclip(ctx) {
|
|
640
|
+
const config = configFrom(ctx.config);
|
|
641
|
+
if (!config.apiKey || !config.agentDid) {
|
|
642
|
+
return {
|
|
643
|
+
exitCode: 1,
|
|
644
|
+
signal: null,
|
|
645
|
+
timedOut: false,
|
|
646
|
+
errorCode: "agrenting_config_invalid",
|
|
647
|
+
errorMessage: "Agrenting requires apiKey and agentDid."
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
const client = new AgrentingClient(config);
|
|
651
|
+
try {
|
|
652
|
+
const profile = await client.getAgentProfile(config.agentDid);
|
|
653
|
+
const capability = capabilityFrom(config, ctx.context, profile);
|
|
654
|
+
const price = priceFrom(config, ctx.context, profile);
|
|
655
|
+
if (!capability) {
|
|
656
|
+
throw new Error(
|
|
657
|
+
"No capabilityRequested was configured and the Agrenting agent profile has no capabilities."
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
if (!price) {
|
|
661
|
+
throw new Error(
|
|
662
|
+
"No price was configured and the Agrenting agent profile has no base_price."
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
const taskDescription = taskDescriptionFrom(ctx);
|
|
666
|
+
await ctx.onLog(
|
|
667
|
+
"stdout",
|
|
668
|
+
`[agrenting] Hiring ${config.agentDid} for ${capability} at ${price}
|
|
669
|
+
`
|
|
670
|
+
);
|
|
671
|
+
const created = await client.hireAgent(config.agentDid, {
|
|
672
|
+
taskDescription,
|
|
673
|
+
capabilityRequested: capability,
|
|
674
|
+
price,
|
|
675
|
+
deliveryMode: config.deliveryMode,
|
|
676
|
+
clientIdempotencyKey: ctx.runId,
|
|
677
|
+
taskInput: taskInputFrom(ctx),
|
|
678
|
+
repoUrl: repoUrlFrom(ctx)
|
|
679
|
+
});
|
|
680
|
+
const hiringId = created.hiring.id;
|
|
681
|
+
await ctx.onMeta?.({
|
|
682
|
+
adapterType: type,
|
|
683
|
+
command: "POST /api/v1/agents/:did/hire",
|
|
684
|
+
context: { hiringId, agentDid: config.agentDid, capability, price }
|
|
685
|
+
});
|
|
686
|
+
await ctx.onLog(
|
|
687
|
+
"stdout",
|
|
688
|
+
`[agrenting] Hiring ${hiringId} created with status ${created.hiring.status}
|
|
689
|
+
`
|
|
690
|
+
);
|
|
691
|
+
const timeoutMs = (config.timeoutSec ?? DEFAULT_TIMEOUT_SEC) * 1e3;
|
|
692
|
+
const pollIntervalMs = config.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
693
|
+
const deadline = Date.now() + timeoutMs;
|
|
694
|
+
let hiring = created.hiring;
|
|
695
|
+
let lastStatus = hiring.status;
|
|
696
|
+
while (!TERMINAL_STATUSES.has(hiring.status) && Date.now() < deadline) {
|
|
697
|
+
await sleep(Math.min(pollIntervalMs, Math.max(1, deadline - Date.now())));
|
|
698
|
+
hiring = await client.getHiring(hiringId);
|
|
699
|
+
if (hiring.status !== lastStatus) {
|
|
700
|
+
lastStatus = hiring.status;
|
|
701
|
+
await ctx.onLog(
|
|
702
|
+
"stdout",
|
|
703
|
+
`[agrenting] Hiring ${hiringId} is ${hiring.status}
|
|
704
|
+
`
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (!TERMINAL_STATUSES.has(hiring.status)) {
|
|
709
|
+
try {
|
|
710
|
+
await client.cancelHiring(hiringId);
|
|
711
|
+
await ctx.onLog(
|
|
712
|
+
"stderr",
|
|
713
|
+
`[agrenting] Hiring ${hiringId} timed out and was cancelled
|
|
714
|
+
`
|
|
715
|
+
);
|
|
716
|
+
} catch (cancelError) {
|
|
717
|
+
await ctx.onLog(
|
|
718
|
+
"stderr",
|
|
719
|
+
`[agrenting] Hiring ${hiringId} timed out; cancellation failed: ${cancelError instanceof Error ? cancelError.message : String(cancelError)}
|
|
720
|
+
`
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
return {
|
|
724
|
+
exitCode: null,
|
|
725
|
+
signal: null,
|
|
726
|
+
timedOut: true,
|
|
727
|
+
errorCode: "agrenting_hiring_timeout",
|
|
728
|
+
errorMessage: `Agrenting hiring ${hiringId} timed out after ${config.timeoutSec ?? DEFAULT_TIMEOUT_SEC}s.`,
|
|
729
|
+
provider: "agrenting",
|
|
730
|
+
biller: "agrenting",
|
|
731
|
+
sessionParams: { hiringId },
|
|
732
|
+
sessionDisplayId: hiringId
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
if (hiring.status !== "completed") {
|
|
736
|
+
return resultForFailure(
|
|
737
|
+
hiring,
|
|
738
|
+
hiring.failed_reason ?? `Agrenting hiring ended with status ${hiring.status}.`
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
const output = outputText(hiring);
|
|
742
|
+
await ctx.onLog("stdout", `${output}
|
|
743
|
+
`);
|
|
744
|
+
const numericPrice = Number(hiring.price ?? price);
|
|
745
|
+
return {
|
|
746
|
+
exitCode: 0,
|
|
747
|
+
signal: null,
|
|
748
|
+
timedOut: false,
|
|
749
|
+
provider: "agrenting",
|
|
750
|
+
biller: "agrenting",
|
|
751
|
+
billingType: "fixed",
|
|
752
|
+
costUsd: Number.isFinite(numericPrice) ? numericPrice : null,
|
|
753
|
+
sessionParams: { hiringId },
|
|
754
|
+
sessionDisplayId: hiringId,
|
|
755
|
+
summary: firstLine(output),
|
|
756
|
+
resultJson: {
|
|
757
|
+
hiringId,
|
|
758
|
+
status: hiring.status,
|
|
759
|
+
taskOutput: hiring.task_output ?? null
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
} catch (error) {
|
|
763
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
764
|
+
const transient = /\b(429|5\d\d)\b|rate.?limit|temporar|timeout/i.test(message);
|
|
765
|
+
await ctx.onLog("stderr", `[agrenting] ${message}
|
|
766
|
+
`);
|
|
767
|
+
return {
|
|
768
|
+
exitCode: 1,
|
|
769
|
+
signal: null,
|
|
770
|
+
timedOut: false,
|
|
771
|
+
errorCode: "agrenting_hiring_failed",
|
|
772
|
+
errorFamily: transient ? "transient_upstream" : null,
|
|
773
|
+
errorMessage: message,
|
|
774
|
+
provider: "agrenting",
|
|
775
|
+
biller: "agrenting"
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
function summarizeChecks(checks) {
|
|
780
|
+
if (checks.some((check) => check.level === "error")) return "fail";
|
|
781
|
+
if (checks.some((check) => check.level === "warn")) return "warn";
|
|
782
|
+
return "pass";
|
|
783
|
+
}
|
|
784
|
+
async function testPaperclipEnvironment(ctx) {
|
|
785
|
+
const config = configFrom(ctx.config);
|
|
786
|
+
const checks = [];
|
|
787
|
+
let parsedUrl = null;
|
|
788
|
+
try {
|
|
789
|
+
parsedUrl = new URL(config.agrentingUrl);
|
|
790
|
+
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
|
|
791
|
+
parsedUrl = null;
|
|
792
|
+
}
|
|
793
|
+
} catch {
|
|
794
|
+
parsedUrl = null;
|
|
795
|
+
}
|
|
796
|
+
if (!parsedUrl) {
|
|
797
|
+
checks.push({
|
|
798
|
+
code: "agrenting_url_invalid",
|
|
799
|
+
level: "error",
|
|
800
|
+
message: "agrentingUrl must be an http:// or https:// URL."
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
if (!config.apiKey) {
|
|
804
|
+
checks.push({
|
|
805
|
+
code: "agrenting_api_key_missing",
|
|
806
|
+
level: "error",
|
|
807
|
+
message: "Agrenting requires a user API token.",
|
|
808
|
+
hint: "Create an ap_... token in Agrenting and store it as a Paperclip secret."
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
if (!config.agentDid) {
|
|
812
|
+
checks.push({
|
|
813
|
+
code: "agrenting_agent_did_missing",
|
|
814
|
+
level: "error",
|
|
815
|
+
message: "Agrenting requires agentDid."
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
if (!checks.some((check) => check.level === "error")) {
|
|
819
|
+
const client = new AgrentingClient(config);
|
|
820
|
+
let connectionOk = false;
|
|
821
|
+
try {
|
|
822
|
+
await client.listHirings({ limit: 1 });
|
|
823
|
+
connectionOk = true;
|
|
824
|
+
checks.push({
|
|
825
|
+
code: "agrenting_connection_ok",
|
|
826
|
+
level: "info",
|
|
827
|
+
message: "Connected to the authenticated Agrenting hiring API."
|
|
828
|
+
});
|
|
829
|
+
} catch (error) {
|
|
830
|
+
checks.push({
|
|
831
|
+
code: "agrenting_connection_failed",
|
|
832
|
+
level: "error",
|
|
833
|
+
message: "Could not access the authenticated Agrenting hiring API.",
|
|
834
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
if (connectionOk) {
|
|
838
|
+
try {
|
|
839
|
+
const profile = await client.getAgentProfile(config.agentDid);
|
|
840
|
+
checks.push({
|
|
841
|
+
code: "agrenting_agent_profile_ok",
|
|
842
|
+
level: "info",
|
|
843
|
+
message: `Found Agrenting agent ${profile.name} (${profile.did}).`,
|
|
844
|
+
detail: `${profile.capabilities.length} capabilities; base price ${profile.base_price ?? "not reported"}.`
|
|
845
|
+
});
|
|
846
|
+
} catch (error) {
|
|
847
|
+
checks.push({
|
|
848
|
+
code: "agrenting_agent_profile_failed",
|
|
849
|
+
level: "error",
|
|
850
|
+
message: `Could not load Agrenting agent ${config.agentDid}.`,
|
|
851
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
return {
|
|
857
|
+
adapterType: ctx.adapterType,
|
|
858
|
+
status: summarizeChecks(checks),
|
|
859
|
+
checks,
|
|
860
|
+
testedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
function getPaperclipConfigSchema() {
|
|
864
|
+
return {
|
|
865
|
+
fields: [
|
|
866
|
+
{
|
|
867
|
+
key: "agrentingUrl",
|
|
868
|
+
label: "Agrenting URL",
|
|
869
|
+
type: "text",
|
|
870
|
+
required: true,
|
|
871
|
+
default: "https://agrenting.com",
|
|
872
|
+
hint: "Base URL of the Agrenting platform."
|
|
873
|
+
},
|
|
874
|
+
{
|
|
875
|
+
key: "apiKey",
|
|
876
|
+
label: "API token",
|
|
877
|
+
type: "text",
|
|
878
|
+
required: true,
|
|
879
|
+
hint: "Agrenting user API token (ap_...). Stored as a Paperclip secret.",
|
|
880
|
+
meta: { secret: true }
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
key: "agentDid",
|
|
884
|
+
label: "Agent DID",
|
|
885
|
+
type: "text",
|
|
886
|
+
required: true,
|
|
887
|
+
hint: "Marketplace agent DID, for example did:agrenting:code-reviewer."
|
|
888
|
+
},
|
|
889
|
+
{
|
|
890
|
+
key: "capabilityRequested",
|
|
891
|
+
label: "Capability",
|
|
892
|
+
type: "text",
|
|
893
|
+
hint: "Optional default. Falls back to the first capability on the agent profile."
|
|
894
|
+
},
|
|
895
|
+
{
|
|
896
|
+
key: "price",
|
|
897
|
+
label: "Price per hiring (USD)",
|
|
898
|
+
type: "text",
|
|
899
|
+
hint: "Optional. Falls back to the agent's current base price."
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
key: "timeoutSec",
|
|
903
|
+
label: "Timeout seconds",
|
|
904
|
+
type: "number",
|
|
905
|
+
default: DEFAULT_TIMEOUT_SEC
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
key: "pollIntervalMs",
|
|
909
|
+
label: "Poll interval milliseconds",
|
|
910
|
+
type: "number",
|
|
911
|
+
default: DEFAULT_POLL_INTERVAL_MS
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
key: "repoUrl",
|
|
915
|
+
label: "Repository URL",
|
|
916
|
+
type: "text",
|
|
917
|
+
hint: "Optional push target. Push delivery uses a GitHub token already stored in Agrenting."
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
key: "deliveryMode",
|
|
921
|
+
label: "Delivery mode",
|
|
922
|
+
type: "select",
|
|
923
|
+
default: "output",
|
|
924
|
+
options: [
|
|
925
|
+
{ value: "output", label: "Return output" },
|
|
926
|
+
{ value: "push", label: "Push to repository" }
|
|
927
|
+
],
|
|
928
|
+
hint: "Use output unless the hiring also has repository credentials."
|
|
929
|
+
}
|
|
930
|
+
]
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
var paperclipSessionCodec = {
|
|
934
|
+
deserialize(raw) {
|
|
935
|
+
if (typeof raw === "string") {
|
|
936
|
+
try {
|
|
937
|
+
return asRecord(JSON.parse(raw));
|
|
938
|
+
} catch {
|
|
939
|
+
return null;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
return asRecord(raw);
|
|
943
|
+
},
|
|
944
|
+
serialize(params) {
|
|
945
|
+
return params;
|
|
946
|
+
},
|
|
947
|
+
getDisplayId(params) {
|
|
948
|
+
return nonEmpty(params?.hiringId);
|
|
949
|
+
},
|
|
950
|
+
encode(state) {
|
|
951
|
+
return JSON.stringify(state ?? null);
|
|
952
|
+
},
|
|
953
|
+
decode(blob) {
|
|
954
|
+
if (!blob) return null;
|
|
955
|
+
try {
|
|
956
|
+
return JSON.parse(blob);
|
|
957
|
+
} catch {
|
|
958
|
+
return null;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
};
|
|
962
|
+
function createCanonicalServerAdapter() {
|
|
963
|
+
return {
|
|
964
|
+
type,
|
|
965
|
+
execute: executePaperclip,
|
|
966
|
+
testEnvironment: testPaperclipEnvironment,
|
|
967
|
+
sessionCodec: paperclipSessionCodec,
|
|
968
|
+
getConfigSchema: getPaperclipConfigSchema,
|
|
969
|
+
agentConfigurationDoc
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
|
|
441
973
|
// server/src/crypto.ts
|
|
442
974
|
async function verifyWebhookSignature(rawBody, signature, secret) {
|
|
443
975
|
const crypto = await import("crypto");
|
|
@@ -1173,9 +1705,9 @@ async function cancelTask(config, taskId) {
|
|
|
1173
1705
|
var TASK_MAX_RETRIES = 2;
|
|
1174
1706
|
var TASK_RETRY_BASE_DELAY_MS = 1e3;
|
|
1175
1707
|
var TASK_RETRY_MAX_DELAY_MS = 3e4;
|
|
1176
|
-
async function hireAgent(config, agentDid) {
|
|
1708
|
+
async function hireAgent(config, agentDid, options) {
|
|
1177
1709
|
const client = new AgrentingClient(config);
|
|
1178
|
-
return client.hireAgent(agentDid);
|
|
1710
|
+
return client.hireAgent(agentDid, options);
|
|
1179
1711
|
}
|
|
1180
1712
|
async function getAgentProfile(config, agentDid) {
|
|
1181
1713
|
const client = new AgrentingClient(config);
|
|
@@ -1217,6 +1749,10 @@ async function listHirings(config, options) {
|
|
|
1217
1749
|
const client = new AgrentingClient(config);
|
|
1218
1750
|
return client.listHirings(options);
|
|
1219
1751
|
}
|
|
1752
|
+
async function cancelHiring(config, hiringId) {
|
|
1753
|
+
const client = new AgrentingClient(config);
|
|
1754
|
+
return client.cancelHiring(hiringId);
|
|
1755
|
+
}
|
|
1220
1756
|
async function autoSelectAgent(config, options) {
|
|
1221
1757
|
const client = new AgrentingClient(config);
|
|
1222
1758
|
const capabilities = await client.listCapabilities();
|
|
@@ -1242,7 +1778,8 @@ async function autoSelectAgent(config, options) {
|
|
|
1242
1778
|
const minRep = options.minReputation;
|
|
1243
1779
|
filtered = filtered.filter((a) => {
|
|
1244
1780
|
if (!a.reputation_score) return false;
|
|
1245
|
-
|
|
1781
|
+
const reputation = Number(a.reputation_score);
|
|
1782
|
+
return Number.isFinite(reputation) && reputation >= minRep;
|
|
1246
1783
|
});
|
|
1247
1784
|
}
|
|
1248
1785
|
if (filtered.length === 0) {
|
|
@@ -1253,15 +1790,17 @@ async function autoSelectAgent(config, options) {
|
|
|
1253
1790
|
const sortBy = options.sortBy ?? "reputation_score";
|
|
1254
1791
|
if (options.preferAvailable ?? true) {
|
|
1255
1792
|
filtered.sort((a, b) => {
|
|
1256
|
-
const aAvail = a.availability_status === "available" ? 0 : 1;
|
|
1257
|
-
const bAvail = b.availability_status === "available" ? 0 : 1;
|
|
1793
|
+
const aAvail = (a.availability_status ?? a.availability ?? a.status) === "available" ? 0 : 1;
|
|
1794
|
+
const bAvail = (b.availability_status ?? b.availability ?? b.status) === "available" ? 0 : 1;
|
|
1258
1795
|
if (aAvail !== bAvail) return aAvail - bAvail;
|
|
1259
1796
|
return 0;
|
|
1260
1797
|
});
|
|
1261
1798
|
}
|
|
1262
1799
|
filtered.sort((a, b) => {
|
|
1263
1800
|
if (sortBy === "reputation_score") {
|
|
1264
|
-
|
|
1801
|
+
const aReputation = Number(a.reputation_score ?? 0);
|
|
1802
|
+
const bReputation = Number(b.reputation_score ?? 0);
|
|
1803
|
+
return (Number.isFinite(bReputation) ? bReputation : 0) - (Number.isFinite(aReputation) ? aReputation : 0);
|
|
1265
1804
|
}
|
|
1266
1805
|
if (sortBy === "base_price") {
|
|
1267
1806
|
const aPrice = parseFloat(a.base_price ?? "999999");
|
|
@@ -1269,14 +1808,19 @@ async function autoSelectAgent(config, options) {
|
|
|
1269
1808
|
return aPrice - bPrice;
|
|
1270
1809
|
}
|
|
1271
1810
|
if (sortBy === "availability") {
|
|
1272
|
-
const aAvail = a.availability_status === "available" ? 0 : 1;
|
|
1273
|
-
const bAvail = b.availability_status === "available" ? 0 : 1;
|
|
1811
|
+
const aAvail = (a.availability_status ?? a.availability ?? a.status) === "available" ? 0 : 1;
|
|
1812
|
+
const bAvail = (b.availability_status ?? b.availability ?? b.status) === "available" ? 0 : 1;
|
|
1274
1813
|
return aAvail - bAvail;
|
|
1275
1814
|
}
|
|
1276
1815
|
return 0;
|
|
1277
1816
|
});
|
|
1278
1817
|
const selectedAgent = filtered[0];
|
|
1279
|
-
const hireResult = await client.hireAgent(selectedAgent.did
|
|
1818
|
+
const hireResult = await client.hireAgent(selectedAgent.did, {
|
|
1819
|
+
taskDescription: options.taskDescription,
|
|
1820
|
+
capabilityRequested: options.capability,
|
|
1821
|
+
price: selectedAgent.base_price ?? options.maxPrice ?? "0",
|
|
1822
|
+
deliveryMode: "output"
|
|
1823
|
+
});
|
|
1280
1824
|
return {
|
|
1281
1825
|
...hireResult,
|
|
1282
1826
|
selectedAgent
|
|
@@ -1372,19 +1916,7 @@ async function syncSkills(config, existing) {
|
|
|
1372
1916
|
removed: existing.filter((s) => !remoteIds.has(s.id))
|
|
1373
1917
|
};
|
|
1374
1918
|
}
|
|
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
|
-
};
|
|
1919
|
+
var sessionCodec = paperclipSessionCodec;
|
|
1388
1920
|
async function invoke(config, params) {
|
|
1389
1921
|
return execute(config, params);
|
|
1390
1922
|
}
|
|
@@ -1403,11 +1935,15 @@ async function cancel(config, taskId) {
|
|
|
1403
1935
|
}
|
|
1404
1936
|
}
|
|
1405
1937
|
function createServerAdapter() {
|
|
1938
|
+
const canonical = createCanonicalServerAdapter();
|
|
1406
1939
|
return {
|
|
1940
|
+
...canonical,
|
|
1407
1941
|
name: "agrenting",
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1942
|
+
// Legacy helpers remain available under explicit names. The canonical
|
|
1943
|
+
// Paperclip keys above use AdapterExecutionContext and structured tests.
|
|
1944
|
+
legacyExecute: execute,
|
|
1945
|
+
legacyTestEnvironment: testEnvironment,
|
|
1946
|
+
getLegacyConfigSchema: getConfigSchema,
|
|
1411
1947
|
startWebhookListener,
|
|
1412
1948
|
stopWebhookListener,
|
|
1413
1949
|
registerWebhook,
|
|
@@ -1425,6 +1961,7 @@ function createServerAdapter() {
|
|
|
1425
1961
|
sendMessageToHiring,
|
|
1426
1962
|
getHiringMessages,
|
|
1427
1963
|
retryHiring,
|
|
1964
|
+
cancelHiring,
|
|
1428
1965
|
getHiring,
|
|
1429
1966
|
listHirings,
|
|
1430
1967
|
autoSelectAgent,
|
|
@@ -1435,24 +1972,56 @@ function createServerAdapter() {
|
|
|
1435
1972
|
getTransactions,
|
|
1436
1973
|
deposit,
|
|
1437
1974
|
withdraw,
|
|
1438
|
-
//
|
|
1975
|
+
// Legacy pre-0.4 contract additions:
|
|
1439
1976
|
invoke,
|
|
1440
1977
|
status,
|
|
1441
1978
|
cancel,
|
|
1442
|
-
detectModel,
|
|
1443
|
-
listSkills,
|
|
1444
|
-
syncSkills
|
|
1445
|
-
sessionCodec
|
|
1979
|
+
legacyDetectModel: detectModel,
|
|
1980
|
+
legacyListSkills: listSkills,
|
|
1981
|
+
legacySyncSkills: syncSkills
|
|
1446
1982
|
};
|
|
1447
1983
|
}
|
|
1984
|
+
|
|
1985
|
+
// server/src/apps-v2.ts
|
|
1986
|
+
var agrentingAppGalleryEntry = {
|
|
1987
|
+
key: "agrenting",
|
|
1988
|
+
name: "Agrenting",
|
|
1989
|
+
logoUrl: "https://www.google.com/s2/favicons?domain=agrenting.com&sz=64",
|
|
1990
|
+
tagline: "Discover and hire governed remote AI agents.",
|
|
1991
|
+
description: "Give Paperclip agents governed access to discover, hire, monitor, and cancel remote agents in the Agrenting marketplace.",
|
|
1992
|
+
authKind: "api_key",
|
|
1993
|
+
transportTemplate: {
|
|
1994
|
+
transport: "remote_http",
|
|
1995
|
+
url: "https://agrenting.com/mcp/hirer"
|
|
1996
|
+
},
|
|
1997
|
+
credentialFields: [
|
|
1998
|
+
{
|
|
1999
|
+
label: "Agrenting API key",
|
|
2000
|
+
configPath: "credentials.authorization",
|
|
2001
|
+
helpUrl: "https://agrenting.com/dashboard/api-keys",
|
|
2002
|
+
required: true,
|
|
2003
|
+
placement: "header",
|
|
2004
|
+
key: "Authorization",
|
|
2005
|
+
prefix: "Bearer "
|
|
2006
|
+
}
|
|
2007
|
+
],
|
|
2008
|
+
recommendedDefaults: {
|
|
2009
|
+
access: "all_agents",
|
|
2010
|
+
askFirstRiskLevels: ["write", "destructive"]
|
|
2011
|
+
},
|
|
2012
|
+
urlPatterns: ["https://agrenting.com/mcp/hirer*"]
|
|
2013
|
+
};
|
|
1448
2014
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1449
2015
|
0 && (module.exports = {
|
|
1450
2016
|
AgrentingClient,
|
|
1451
2017
|
MAX_POLLS,
|
|
1452
2018
|
POLL_INTERVALS_MS,
|
|
2019
|
+
agentConfigurationDoc,
|
|
2020
|
+
agrentingAppGalleryEntry,
|
|
1453
2021
|
autoSelectAgent,
|
|
1454
2022
|
canSubmitTask,
|
|
1455
2023
|
cancel,
|
|
2024
|
+
cancelHiring,
|
|
1456
2025
|
cancelTask,
|
|
1457
2026
|
checkBalance,
|
|
1458
2027
|
createServerAdapter,
|
|
@@ -1460,6 +2029,7 @@ function createServerAdapter() {
|
|
|
1460
2029
|
deregisterWebhook,
|
|
1461
2030
|
detectModel,
|
|
1462
2031
|
execute,
|
|
2032
|
+
executePaperclip,
|
|
1463
2033
|
executeWithRetry,
|
|
1464
2034
|
formatAgentResponse,
|
|
1465
2035
|
formatInsufficientBalanceComment,
|
|
@@ -1471,14 +2041,17 @@ function createServerAdapter() {
|
|
|
1471
2041
|
getConfigSchema,
|
|
1472
2042
|
getHiring,
|
|
1473
2043
|
getHiringMessages,
|
|
2044
|
+
getPaperclipConfigSchema,
|
|
1474
2045
|
getTaskMessages,
|
|
1475
2046
|
getTaskProgress,
|
|
1476
2047
|
getWebhookGracePeriodMs,
|
|
1477
2048
|
hireAgent,
|
|
1478
2049
|
invoke,
|
|
2050
|
+
label,
|
|
1479
2051
|
listCapabilities,
|
|
1480
2052
|
listHirings,
|
|
1481
2053
|
listSkills,
|
|
2054
|
+
paperclipSessionCodec,
|
|
1482
2055
|
pollTaskUntilDone,
|
|
1483
2056
|
processIncomingMessage,
|
|
1484
2057
|
reassignTask,
|
|
@@ -1491,6 +2064,8 @@ function createServerAdapter() {
|
|
|
1491
2064
|
status,
|
|
1492
2065
|
syncSkills,
|
|
1493
2066
|
testEnvironment,
|
|
2067
|
+
testPaperclipEnvironment,
|
|
2068
|
+
type,
|
|
1494
2069
|
unregisterTaskMapping,
|
|
1495
2070
|
verifyWebhookSignature
|
|
1496
2071
|
});
|