@agrentingai/paperclip-adapter 0.2.2 → 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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agrentingai/paperclip-adapter",
3
- "version": "0.2.2",
4
- "description": "Paperclip adapter for Agrenting — remote AI agent orchestration via the Agrenting platform",
3
+ "version": "0.3.0",
4
+ "description": "Paperclip adapter for Agrenting — remote AI agent orchestration via the Agrenting platform. Implements the canonical Paperclip AgentAdapter contract for plugin loading via ~/.paperclip/adapter-plugins.json.",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  "./server": {
@@ -30,9 +30,11 @@
30
30
  },
31
31
  "keywords": [
32
32
  "paperclip",
33
+ "paperclipai",
33
34
  "agrenting",
34
35
  "adapter",
35
- "ai-agents"
36
+ "ai-agents",
37
+ "agent-adapter"
36
38
  ],
37
39
  "author": "AgRenting",
38
40
  "license": "MIT",
@@ -40,6 +42,10 @@
40
42
  "type": "git",
41
43
  "url": "git+https://github.com/AgRenting/paperclip-adapter.git"
42
44
  },
45
+ "bugs": {
46
+ "url": "https://github.com/AgRenting/paperclip-adapter/issues"
47
+ },
48
+ "homepage": "https://agrenting.com/docs/platform/paperclip-adapter",
43
49
  "engines": {
44
50
  "node": ">=20.0.0"
45
51
  },
@@ -1003,9 +1003,145 @@ export function processIncomingMessage(
1003
1003
  return formatAgentResponse(senderName, message.content);
1004
1004
  }
1005
1005
 
1006
+ // ─── Canonical Paperclip adapter contract ──────────────────────────────────
1007
+ // Matches the canonical adapter shape Paperclip expects per
1008
+ // `paperclipai/paperclip/doc/SPEC-implementation.md` and the reference
1009
+ // `NousResearch/hermes-paperclip-adapter`. These named exports let the
1010
+ // package load via `~/.paperclip/adapter-plugins.json`.
1011
+
1012
+ /** Paperclip skill shape (subset of the canonical Paperclip Skill). */
1013
+ export interface PaperclipSkill {
1014
+ id: string;
1015
+ name: string;
1016
+ description?: string;
1017
+ }
1018
+
1019
+ /**
1020
+ * Detect a sensible default model/provider for the configured Agrenting agent.
1021
+ * Paperclip calls this to pre-populate the adapter UI when an agent is
1022
+ * created. Returns null if no info is available.
1023
+ */
1024
+ export async function detectModel(
1025
+ config: Pick<AgrentingAdapterConfig, "agrentingUrl" | "apiKey" | "agentDid">
1026
+ ): Promise<{ provider: string; model: string } | null> {
1027
+ if (!config.agentDid) return null;
1028
+ try {
1029
+ const profile = await getAgentProfile(config as AgrentingAdapterConfig, config.agentDid);
1030
+ const provider = (profile as { ai_provider?: string }).ai_provider ?? null;
1031
+ const model = (profile as { ai_model?: string }).ai_model ?? null;
1032
+ if (provider && model) return { provider, model };
1033
+ } catch {
1034
+ // Surface as "no detection" rather than a hard error — Paperclip falls
1035
+ // back to user input.
1036
+ }
1037
+ return null;
1038
+ }
1039
+
1040
+ /**
1041
+ * Enumerate the configured Agrenting agent's capabilities and map them to
1042
+ * Paperclip's Skill shape.
1043
+ */
1044
+ export async function listSkills(
1045
+ config: AgrentingAdapterConfig
1046
+ ): Promise<PaperclipSkill[]> {
1047
+ const profile = await getAgentProfile(config, config.agentDid);
1048
+ const capabilities = profile.capabilities ?? [];
1049
+ return capabilities.map((cap) => ({
1050
+ id: `${config.agentDid}:${cap}`,
1051
+ name: cap,
1052
+ description: `Capability "${cap}" of agent ${config.agentDid}`,
1053
+ }));
1054
+ }
1055
+
1056
+ /**
1057
+ * Reconcile the agent's current capabilities against Paperclip's local skill
1058
+ * registry. Returns sets to add and remove.
1059
+ */
1060
+ export async function syncSkills(
1061
+ config: AgrentingAdapterConfig,
1062
+ existing: PaperclipSkill[]
1063
+ ): Promise<{ added: PaperclipSkill[]; removed: PaperclipSkill[] }> {
1064
+ const remote = await listSkills(config);
1065
+ const remoteIds = new Set(remote.map((s) => s.id));
1066
+ const existingIds = new Set(existing.map((s) => s.id));
1067
+ return {
1068
+ added: remote.filter((s) => !existingIds.has(s.id)),
1069
+ removed: existing.filter((s) => !remoteIds.has(s.id)),
1070
+ };
1071
+ }
1072
+
1073
+ /**
1074
+ * Session codec — Paperclip uses this to serialise session state across
1075
+ * heartbeats. Hirings carry no rich session state, so we pass JSON through.
1076
+ */
1077
+ export const sessionCodec = {
1078
+ encode(state: unknown): string {
1079
+ return JSON.stringify(state ?? null);
1080
+ },
1081
+ decode(blob: string | null | undefined): unknown {
1082
+ if (!blob) return null;
1083
+ try {
1084
+ return JSON.parse(blob);
1085
+ } catch {
1086
+ return null;
1087
+ }
1088
+ },
1089
+ };
1090
+
1091
+ /**
1092
+ * Canonical `AgentAdapter.invoke`. Forwards to {@link execute}.
1093
+ */
1094
+ export async function invoke(
1095
+ config: AgrentingAdapterConfig,
1096
+ params: {
1097
+ input: string;
1098
+ capability: string;
1099
+ instructions?: string;
1100
+ maxPrice?: string;
1101
+ paymentType?: string;
1102
+ }
1103
+ ): Promise<AgrentingExecutionResult> {
1104
+ return execute(config, params);
1105
+ }
1106
+
1107
+ /**
1108
+ * Canonical `AgentAdapter.status`. Returns the current run status.
1109
+ */
1110
+ export async function status(
1111
+ config: AgrentingAdapterConfig,
1112
+ taskId: string
1113
+ ): Promise<{
1114
+ status: AgrentingTaskStatus;
1115
+ progressPercent: number;
1116
+ progressMessage?: string;
1117
+ }> {
1118
+ const progress = await getTaskProgress(config, taskId);
1119
+ return {
1120
+ status: progress.status,
1121
+ progressPercent: progress.progressPercent,
1122
+ progressMessage: progress.progressMessage,
1123
+ };
1124
+ }
1125
+
1126
+ /**
1127
+ * Canonical `AgentAdapter.cancel`. Cancels a running task; throws on failure
1128
+ * so Paperclip can treat the call as a void Promise.
1129
+ */
1130
+ export async function cancel(
1131
+ config: AgrentingAdapterConfig,
1132
+ taskId: string
1133
+ ): Promise<void> {
1134
+ const result = await cancelTask(config, taskId);
1135
+ if (!result.success) {
1136
+ throw new Error(result.error ?? "Failed to cancel task");
1137
+ }
1138
+ }
1139
+
1006
1140
  /**
1007
1141
  * Create the server-side adapter module.
1008
- * This is the entry point for Paperclip's server adapter registry.
1142
+ * Backward-compat convenience for callers that prefer a single bundle. New
1143
+ * Paperclip plugin loaders should use the named exports directly via
1144
+ * `~/.paperclip/adapter-plugins.json`.
1009
1145
  */
1010
1146
  export function createServerAdapter() {
1011
1147
  return {
@@ -1040,5 +1176,13 @@ export function createServerAdapter() {
1040
1176
  getTransactions,
1041
1177
  deposit,
1042
1178
  withdraw,
1179
+ // Canonical contract additions:
1180
+ invoke,
1181
+ status,
1182
+ cancel,
1183
+ detectModel,
1184
+ listSkills,
1185
+ syncSkills,
1186
+ sessionCodec,
1043
1187
  };
1044
1188
  }
@@ -42,7 +42,23 @@ export {
42
42
  listHirings,
43
43
  autoSelectAgent,
44
44
  executeWithRetry,
45
+ // Canonical Paperclip AgentAdapter contract (for `~/.paperclip/adapter-plugins.json`).
46
+ // See `paperclipai/paperclip/doc/SPEC-implementation.md` and the reference
47
+ // `NousResearch/hermes-paperclip-adapter`.
48
+ execute,
49
+ testEnvironment,
50
+ getConfigSchema,
51
+ cancelTask,
52
+ getTaskProgress,
53
+ invoke,
54
+ status,
55
+ cancel,
56
+ detectModel,
57
+ listSkills,
58
+ syncSkills,
59
+ sessionCodec,
45
60
  } from "./adapter.js";
61
+ export type { PaperclipSkill } from "./adapter.js";
46
62
  export type {
47
63
  AgrentingAdapterConfig,
48
64
  AgrentingExecutionResult,