kompass-sdk 0.1.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.
Files changed (205) hide show
  1. package/dist/a2a/agent-card.d.ts +13 -0
  2. package/dist/a2a/agent-card.d.ts.map +1 -0
  3. package/dist/a2a/agent-card.js +52 -0
  4. package/dist/a2a/agent-card.js.map +1 -0
  5. package/dist/a2a/bridge.d.ts +52 -0
  6. package/dist/a2a/bridge.d.ts.map +1 -0
  7. package/dist/a2a/bridge.js +123 -0
  8. package/dist/a2a/bridge.js.map +1 -0
  9. package/dist/a2a/client.d.ts +34 -0
  10. package/dist/a2a/client.d.ts.map +1 -0
  11. package/dist/a2a/client.js +65 -0
  12. package/dist/a2a/client.js.map +1 -0
  13. package/dist/a2a/server.d.ts +17 -0
  14. package/dist/a2a/server.d.ts.map +1 -0
  15. package/dist/a2a/server.js +194 -0
  16. package/dist/a2a/server.js.map +1 -0
  17. package/dist/abi.d.ts +1068 -0
  18. package/dist/abi.d.ts.map +1 -0
  19. package/dist/abi.js +1372 -0
  20. package/dist/abi.js.map +1 -0
  21. package/dist/adapters/agentkit.d.ts +41 -0
  22. package/dist/adapters/agentkit.d.ts.map +1 -0
  23. package/dist/adapters/agentkit.js +67 -0
  24. package/dist/adapters/agentkit.js.map +1 -0
  25. package/dist/adapters/generic.d.ts +35 -0
  26. package/dist/adapters/generic.d.ts.map +1 -0
  27. package/dist/adapters/generic.js +47 -0
  28. package/dist/adapters/generic.js.map +1 -0
  29. package/dist/adapters/index.d.ts +5 -0
  30. package/dist/adapters/index.d.ts.map +1 -0
  31. package/dist/adapters/index.js +5 -0
  32. package/dist/adapters/index.js.map +1 -0
  33. package/dist/adapters/langchain.d.ts +26 -0
  34. package/dist/adapters/langchain.d.ts.map +1 -0
  35. package/dist/adapters/langchain.js +228 -0
  36. package/dist/adapters/langchain.js.map +1 -0
  37. package/dist/adapters/openclaw.d.ts +18 -0
  38. package/dist/adapters/openclaw.d.ts.map +1 -0
  39. package/dist/adapters/openclaw.js +168 -0
  40. package/dist/adapters/openclaw.js.map +1 -0
  41. package/dist/aggregator.d.ts +36 -0
  42. package/dist/aggregator.d.ts.map +1 -0
  43. package/dist/aggregator.js +168 -0
  44. package/dist/aggregator.js.map +1 -0
  45. package/dist/backends/acp.d.ts +29 -0
  46. package/dist/backends/acp.d.ts.map +1 -0
  47. package/dist/backends/acp.js +126 -0
  48. package/dist/backends/acp.js.map +1 -0
  49. package/dist/backends/types.d.ts +59 -0
  50. package/dist/backends/types.d.ts.map +1 -0
  51. package/dist/backends/types.js +2 -0
  52. package/dist/backends/types.js.map +1 -0
  53. package/dist/bridge.d.ts +35 -0
  54. package/dist/bridge.d.ts.map +1 -0
  55. package/dist/bridge.js +192 -0
  56. package/dist/bridge.js.map +1 -0
  57. package/dist/cli.d.ts +12 -0
  58. package/dist/cli.d.ts.map +1 -0
  59. package/dist/cli.js +331 -0
  60. package/dist/cli.js.map +1 -0
  61. package/dist/discover.d.ts +15 -0
  62. package/dist/discover.d.ts.map +1 -0
  63. package/dist/discover.js +163 -0
  64. package/dist/discover.js.map +1 -0
  65. package/dist/escrow.d.ts +45 -0
  66. package/dist/escrow.d.ts.map +1 -0
  67. package/dist/escrow.js +243 -0
  68. package/dist/escrow.js.map +1 -0
  69. package/dist/index.d.ts +63 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +145 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/intents.d.ts +28 -0
  74. package/dist/intents.d.ts.map +1 -0
  75. package/dist/intents.js +111 -0
  76. package/dist/intents.js.map +1 -0
  77. package/dist/matching.d.ts +29 -0
  78. package/dist/matching.d.ts.map +1 -0
  79. package/dist/matching.js +147 -0
  80. package/dist/matching.js.map +1 -0
  81. package/dist/pipelineAbi.d.ts +113 -0
  82. package/dist/pipelineAbi.d.ts.map +1 -0
  83. package/dist/pipelineAbi.js +74 -0
  84. package/dist/pipelineAbi.js.map +1 -0
  85. package/dist/pipelines.d.ts +42 -0
  86. package/dist/pipelines.d.ts.map +1 -0
  87. package/dist/pipelines.js +185 -0
  88. package/dist/pipelines.js.map +1 -0
  89. package/dist/registry.d.ts +36 -0
  90. package/dist/registry.d.ts.map +1 -0
  91. package/dist/registry.js +187 -0
  92. package/dist/registry.js.map +1 -0
  93. package/dist/reputation.d.ts +10 -0
  94. package/dist/reputation.d.ts.map +1 -0
  95. package/dist/reputation.js +33 -0
  96. package/dist/reputation.js.map +1 -0
  97. package/dist/router.d.ts +72 -0
  98. package/dist/router.d.ts.map +1 -0
  99. package/dist/router.js +190 -0
  100. package/dist/router.js.map +1 -0
  101. package/dist/simple.d.ts +160 -0
  102. package/dist/simple.d.ts.map +1 -0
  103. package/dist/simple.js +237 -0
  104. package/dist/simple.js.map +1 -0
  105. package/dist/sources/a2a-wellknown.d.ts +8 -0
  106. package/dist/sources/a2a-wellknown.d.ts.map +1 -0
  107. package/dist/sources/a2a-wellknown.js +104 -0
  108. package/dist/sources/a2a-wellknown.js.map +1 -0
  109. package/dist/sources/acp.d.ts +7 -0
  110. package/dist/sources/acp.d.ts.map +1 -0
  111. package/dist/sources/acp.js +86 -0
  112. package/dist/sources/acp.js.map +1 -0
  113. package/dist/sources/adp.d.ts +7 -0
  114. package/dist/sources/adp.d.ts.map +1 -0
  115. package/dist/sources/adp.js +59 -0
  116. package/dist/sources/adp.js.map +1 -0
  117. package/dist/sources/erc8004.d.ts +7 -0
  118. package/dist/sources/erc8004.d.ts.map +1 -0
  119. package/dist/sources/erc8004.js +150 -0
  120. package/dist/sources/erc8004.js.map +1 -0
  121. package/dist/sources/index.d.ts +17 -0
  122. package/dist/sources/index.d.ts.map +1 -0
  123. package/dist/sources/index.js +35 -0
  124. package/dist/sources/index.js.map +1 -0
  125. package/dist/sources/kompass-registry.d.ts +8 -0
  126. package/dist/sources/kompass-registry.d.ts.map +1 -0
  127. package/dist/sources/kompass-registry.js +62 -0
  128. package/dist/sources/kompass-registry.js.map +1 -0
  129. package/dist/sources/l402-directory.d.ts +7 -0
  130. package/dist/sources/l402-directory.d.ts.map +1 -0
  131. package/dist/sources/l402-directory.js +42 -0
  132. package/dist/sources/l402-directory.js.map +1 -0
  133. package/dist/sources/mcp-registry.d.ts +8 -0
  134. package/dist/sources/mcp-registry.d.ts.map +1 -0
  135. package/dist/sources/mcp-registry.js +85 -0
  136. package/dist/sources/mcp-registry.js.map +1 -0
  137. package/dist/sources/skills.d.ts +8 -0
  138. package/dist/sources/skills.d.ts.map +1 -0
  139. package/dist/sources/skills.js +153 -0
  140. package/dist/sources/skills.js.map +1 -0
  141. package/dist/sources/types.d.ts +72 -0
  142. package/dist/sources/types.d.ts.map +1 -0
  143. package/dist/sources/types.js +8 -0
  144. package/dist/sources/types.js.map +1 -0
  145. package/dist/sources/x402-ecosystem.d.ts +7 -0
  146. package/dist/sources/x402-ecosystem.d.ts.map +1 -0
  147. package/dist/sources/x402-ecosystem.js +78 -0
  148. package/dist/sources/x402-ecosystem.js.map +1 -0
  149. package/dist/types.d.ts +133 -0
  150. package/dist/types.d.ts.map +1 -0
  151. package/dist/types.js +2 -0
  152. package/dist/types.js.map +1 -0
  153. package/dist/unified.d.ts +90 -0
  154. package/dist/unified.d.ts.map +1 -0
  155. package/dist/unified.js +107 -0
  156. package/dist/unified.js.map +1 -0
  157. package/dist/x402.d.ts +30 -0
  158. package/dist/x402.d.ts.map +1 -0
  159. package/dist/x402.js +79 -0
  160. package/dist/x402.js.map +1 -0
  161. package/package.json +61 -0
  162. package/scripts/bootstrap-agents.mjs +246 -0
  163. package/src/.gitkeep +0 -0
  164. package/src/a2a/agent-card.ts +66 -0
  165. package/src/a2a/bridge.ts +168 -0
  166. package/src/a2a/client.ts +92 -0
  167. package/src/a2a/server.ts +234 -0
  168. package/src/abi.ts +1373 -0
  169. package/src/adapters/agentkit.ts +83 -0
  170. package/src/adapters/generic.ts +62 -0
  171. package/src/adapters/index.ts +4 -0
  172. package/src/adapters/langchain.ts +282 -0
  173. package/src/adapters/openclaw.ts +203 -0
  174. package/src/aggregator.ts +203 -0
  175. package/src/backends/acp.ts +199 -0
  176. package/src/backends/types.ts +78 -0
  177. package/src/bridge.ts +263 -0
  178. package/src/cli.ts +397 -0
  179. package/src/discover.ts +187 -0
  180. package/src/escrow.ts +284 -0
  181. package/src/index.ts +245 -0
  182. package/src/intents.ts +166 -0
  183. package/src/matching.ts +192 -0
  184. package/src/pipelineAbi.ts +74 -0
  185. package/src/pipelines.ts +253 -0
  186. package/src/registry.ts +232 -0
  187. package/src/reputation.ts +43 -0
  188. package/src/router.ts +279 -0
  189. package/src/simple.ts +366 -0
  190. package/src/sources/a2a-wellknown.ts +120 -0
  191. package/src/sources/acp.ts +91 -0
  192. package/src/sources/adp.ts +64 -0
  193. package/src/sources/erc8004.ts +166 -0
  194. package/src/sources/index.ts +52 -0
  195. package/src/sources/kompass-registry.ts +67 -0
  196. package/src/sources/l402-directory.ts +51 -0
  197. package/src/sources/mcp-registry.ts +104 -0
  198. package/src/sources/skills.ts +161 -0
  199. package/src/sources/types.ts +82 -0
  200. package/src/sources/x402-ecosystem.ts +86 -0
  201. package/src/types.ts +147 -0
  202. package/src/unified.ts +155 -0
  203. package/src/x402.ts +122 -0
  204. package/tests/pipelineFlow.test.ts +239 -0
  205. package/tsconfig.json +20 -0
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Kompass Aggregator
3
+ * Searches all source adapters in parallel, deduplicates, and ranks results.
4
+ */
5
+
6
+ import type { SourceAdapter, UnifiedAgent, SourceSearchOptions } from "./sources/types.js";
7
+
8
+ export interface AggregatorOptions extends SourceSearchOptions {
9
+ /** Only search these sources (by name) */
10
+ sources?: string[];
11
+ /** Minimum relevance score to include (0-100) */
12
+ minScore?: number;
13
+ }
14
+
15
+ export interface AggregatorResult {
16
+ agents: UnifiedAgent[];
17
+ sources: { name: string; count: number; durationMs: number; error?: string }[];
18
+ totalFound: number;
19
+ deduplicated: number;
20
+ queryTimeMs: number;
21
+ }
22
+
23
+ export class Aggregator {
24
+ private adapters: SourceAdapter[];
25
+
26
+ constructor(adapters: SourceAdapter[]) {
27
+ this.adapters = adapters;
28
+ }
29
+
30
+ async search(query: string, options?: AggregatorOptions): Promise<AggregatorResult> {
31
+ const startTime = Date.now();
32
+ const limit = options?.limit ?? 50;
33
+ const timeout = options?.timeout ?? 15000;
34
+
35
+ // Filter adapters by source name if specified
36
+ const activeAdapters = options?.sources
37
+ ? this.adapters.filter((a) => options.sources!.includes(a.name))
38
+ : this.adapters;
39
+
40
+ // Fan out to all sources in parallel
41
+ const promises = activeAdapters.map(async (adapter) => {
42
+ const adapterStart = Date.now();
43
+ try {
44
+ const results = await adapter.search(query, { limit, timeout });
45
+ return {
46
+ name: adapter.name,
47
+ displayName: adapter.displayName,
48
+ results,
49
+ durationMs: Date.now() - adapterStart,
50
+ error: undefined as string | undefined,
51
+ };
52
+ } catch (err) {
53
+ return {
54
+ name: adapter.name,
55
+ displayName: adapter.displayName,
56
+ results: [] as UnifiedAgent[],
57
+ durationMs: Date.now() - adapterStart,
58
+ error: err instanceof Error ? err.message : String(err),
59
+ };
60
+ }
61
+ });
62
+
63
+ const settled = await Promise.allSettled(promises);
64
+ const sourceResults = settled.map((s) =>
65
+ s.status === "fulfilled" ? s.value : { name: "unknown", displayName: "Unknown", results: [], durationMs: 0, error: "Promise rejected" }
66
+ );
67
+
68
+ // Flatten all results
69
+ const allAgents = sourceResults.flatMap((s) => s.results);
70
+ const totalFound = allAgents.length;
71
+
72
+ // Deduplicate
73
+ const deduped = this.deduplicate(allAgents);
74
+ const deduplicated = totalFound - deduped.length;
75
+
76
+ // Score and rank
77
+ const scored = this.scoreAndRank(deduped, query);
78
+
79
+ // Apply minimum score filter
80
+ const filtered = options?.minScore
81
+ ? scored.filter((a) => (a as any)._score >= options.minScore!)
82
+ : scored;
83
+
84
+ return {
85
+ agents: filtered.slice(0, limit),
86
+ sources: sourceResults.map((s) => ({
87
+ name: s.name,
88
+ count: s.results.length,
89
+ durationMs: s.durationMs,
90
+ error: s.error,
91
+ })),
92
+ totalFound,
93
+ deduplicated,
94
+ queryTimeMs: Date.now() - startTime,
95
+ };
96
+ }
97
+
98
+ async healthCheck(): Promise<{ name: string; displayName: string; healthy: boolean }[]> {
99
+ const results = await Promise.allSettled(
100
+ this.adapters.map(async (adapter) => ({
101
+ name: adapter.name,
102
+ displayName: adapter.displayName,
103
+ healthy: await adapter.ping(),
104
+ }))
105
+ );
106
+
107
+ return results.map((r) =>
108
+ r.status === "fulfilled" ? r.value : { name: "unknown", displayName: "Unknown", healthy: false }
109
+ );
110
+ }
111
+
112
+ private deduplicate(agents: UnifiedAgent[]): UnifiedAgent[] {
113
+ const seen = new Map<string, UnifiedAgent>();
114
+
115
+ for (const agent of agents) {
116
+ // Generate dedup keys from endpoints
117
+ const keys = [
118
+ agent.endpoints.mcp,
119
+ agent.endpoints.a2a,
120
+ agent.endpoints.x402,
121
+ agent.endpoints.http,
122
+ agent.endpoints.acp?.walletAddress,
123
+ ].filter(Boolean);
124
+
125
+ let existingKey: string | undefined;
126
+ for (const key of keys) {
127
+ if (seen.has(key!)) {
128
+ existingKey = key!;
129
+ break;
130
+ }
131
+ }
132
+
133
+ if (existingKey) {
134
+ // Merge: keep richer data
135
+ const existing = seen.get(existingKey)!;
136
+ existing.categories = [...new Set([...existing.categories, ...agent.categories])];
137
+ existing.capabilities = [...new Set([...existing.capabilities, ...agent.capabilities])];
138
+ if (!existing.reputation && agent.reputation) existing.reputation = agent.reputation;
139
+ if (!existing.pricing && agent.pricing) existing.pricing = agent.pricing;
140
+ if (agent.description.length > existing.description.length) existing.description = agent.description;
141
+ } else {
142
+ // New agent
143
+ for (const key of keys) {
144
+ if (key) seen.set(key, agent);
145
+ }
146
+ // Also key by name for simple dedup
147
+ if (!seen.has(agent.name.toLowerCase())) {
148
+ seen.set(agent.name.toLowerCase(), agent);
149
+ }
150
+ }
151
+ }
152
+
153
+ // Return unique agents
154
+ const uniqueAgents = new Map<string, UnifiedAgent>();
155
+ for (const agent of seen.values()) {
156
+ uniqueAgents.set(agent.id, agent);
157
+ }
158
+ return Array.from(uniqueAgents.values());
159
+ }
160
+
161
+ private scoreAndRank(agents: UnifiedAgent[], query: string): UnifiedAgent[] {
162
+ const queryLower = query.toLowerCase();
163
+ const queryTerms = queryLower.split(/\s+/).filter((t) => t.length > 2);
164
+
165
+ return agents
166
+ .map((agent) => {
167
+ let score = 0;
168
+ const searchText = `${agent.name} ${agent.description} ${agent.categories.join(" ")} ${agent.capabilities.join(" ")}`.toLowerCase();
169
+
170
+ // Term matching (BM25-lite)
171
+ for (const term of queryTerms) {
172
+ if (agent.name.toLowerCase().includes(term)) score += 10;
173
+ if (agent.description.toLowerCase().includes(term)) score += 5;
174
+ if (agent.categories.some((c) => c.includes(term))) score += 8;
175
+ if (agent.capabilities.some((c) => c.toLowerCase().includes(term))) score += 3;
176
+ }
177
+
178
+ // Reputation bonus
179
+ if (agent.reputation) {
180
+ score += Math.min(agent.reputation.score * 2, 20);
181
+ score += Math.min(agent.reputation.count, 10);
182
+ }
183
+
184
+ // Verified bonus
185
+ if (agent.verified) score += 5;
186
+
187
+ // Has pricing info bonus (transparency)
188
+ if (agent.pricing && agent.pricing.model !== "unknown") score += 3;
189
+
190
+ // Has multiple endpoints bonus (more interoperable)
191
+ const endpointCount = Object.values(agent.endpoints).filter(Boolean).length;
192
+ score += endpointCount * 2;
193
+
194
+ // Protocol diversity bonus
195
+ if (agent.protocol === "mcp") score += 2; // MCP is most interoperable
196
+ if (agent.protocol === "a2a") score += 2;
197
+
198
+ (agent as any)._score = score;
199
+ return agent;
200
+ })
201
+ .sort((a, b) => ((b as any)._score ?? 0) - ((a as any)._score ?? 0));
202
+ }
203
+ }
@@ -0,0 +1,199 @@
1
+ import AcpClient, {
2
+ AcpContractClientV2,
3
+ baseSepoliaAcpConfigV2,
4
+ baseAcpConfigV2,
5
+ type AcpAgent,
6
+ type AcpJob,
7
+ } from "@virtuals-protocol/acp-node";
8
+ import type { Address, Hex } from "viem";
9
+ import type {
10
+ EscrowBackend,
11
+ AgentSearchResult,
12
+ AgentOffering,
13
+ JobResult,
14
+ BrowseOptions,
15
+ IncomingJob,
16
+ } from "./types.js";
17
+
18
+ export interface AcpBackendConfig {
19
+ /** Private key for the agent wallet (whitelisted on ACP) */
20
+ privateKey: string;
21
+ /** Agent's wallet address on ACP */
22
+ walletAddress: Address;
23
+ /** Entity/session key address from ACP registration */
24
+ entityAddress: Address;
25
+ /** Network: "base-sepolia" or "base" */
26
+ network?: "base-sepolia" | "base";
27
+ /** Custom RPC URL */
28
+ rpcUrl?: string;
29
+ }
30
+
31
+ export class AcpEscrowBackend implements EscrowBackend {
32
+ private client!: AcpClient;
33
+ private config: AcpBackendConfig;
34
+ private jobHandlers = new Map<string, (job: IncomingJob) => Promise<unknown>>();
35
+
36
+ constructor(config: AcpBackendConfig) {
37
+ this.config = config;
38
+ }
39
+
40
+ name(): string {
41
+ return "virtuals-acp";
42
+ }
43
+
44
+ async init(): Promise<void> {
45
+ const acpConfig =
46
+ this.config.network === "base"
47
+ ? baseAcpConfigV2
48
+ : baseSepoliaAcpConfigV2;
49
+
50
+ const contractClient = await (AcpContractClientV2 as any).build(
51
+ this.config.privateKey,
52
+ this.config.entityAddress,
53
+ this.config.walletAddress,
54
+ this.config.rpcUrl,
55
+ acpConfig
56
+ );
57
+
58
+ this.client = new AcpClient({
59
+ acpContractClient: contractClient,
60
+ walletAddress: this.config.walletAddress as string,
61
+ entityAddress: this.config.entityAddress as string,
62
+ onNewTask: (job: any) => this.handleIncomingJob(job),
63
+ } as any);
64
+
65
+ await this.client.init();
66
+ }
67
+
68
+ async browseAgents(
69
+ query: string,
70
+ options?: BrowseOptions
71
+ ): Promise<AgentSearchResult[]> {
72
+ const agents = await this.client.browseAgents({
73
+ keyword: query,
74
+ onlineStatus: options?.onlineOnly ? "online" : "all",
75
+ limit: options?.limit ?? 20,
76
+ sortBy: options?.sortBy === "successRate" ? "successRate" : undefined,
77
+ } as any);
78
+
79
+ return (agents ?? []).map((agent: AcpAgent) =>
80
+ this.mapAcpAgent(agent)
81
+ );
82
+ }
83
+
84
+ async hireAgent(
85
+ agent: AgentSearchResult,
86
+ offeringId: string,
87
+ requirements: Record<string, unknown>,
88
+ _budget?: bigint
89
+ ): Promise<JobResult> {
90
+ const job = await (this.client as any).initiateJob({
91
+ providerAddress: agent.address,
92
+ jobOfferingId: offeringId,
93
+ requirements,
94
+ skipEvaluation: true,
95
+ });
96
+
97
+ return {
98
+ jobId: (job as any).id ?? String(job),
99
+ phase: "REQUEST",
100
+ deliverable: null,
101
+ };
102
+ }
103
+
104
+ async waitForResult(
105
+ jobId: string,
106
+ timeoutMs = 300_000
107
+ ): Promise<JobResult> {
108
+ const start = Date.now();
109
+ const pollInterval = 5_000;
110
+
111
+ while (Date.now() - start < timeoutMs) {
112
+ const job = await this.client.getJobById(Number(jobId));
113
+ const phase = (job as any)?.phase ?? (job as any)?.status;
114
+
115
+ if (phase === "COMPLETED" || phase === "completed") {
116
+ return {
117
+ jobId,
118
+ phase: "COMPLETED",
119
+ deliverable: (job as any)?.deliverable ?? (job as any)?.result,
120
+ txHash: (job as any)?.txHash,
121
+ };
122
+ }
123
+
124
+ if (phase === "CANCELLED" || phase === "REJECTED" || phase === "EXPIRED") {
125
+ return {
126
+ jobId,
127
+ phase,
128
+ deliverable: null,
129
+ };
130
+ }
131
+
132
+ await new Promise((r) => setTimeout(r, pollInterval));
133
+ }
134
+
135
+ throw new Error(`Timeout waiting for job ${jobId} (${timeoutMs}ms)`);
136
+ }
137
+
138
+ async acceptJobs(
139
+ capabilities: string[],
140
+ handler: (job: IncomingJob) => Promise<unknown>
141
+ ): Promise<void> {
142
+ for (const cap of capabilities) {
143
+ this.jobHandlers.set(cap, handler);
144
+ }
145
+ // The onNewTask callback set during init() will dispatch to handlers
146
+ console.log(`[ACP] Listening for jobs: ${capabilities.join(", ")}`);
147
+ }
148
+
149
+ private async handleIncomingJob(acpJob: AcpJob): Promise<void> {
150
+ const job: IncomingJob = {
151
+ jobId: (acpJob as any).id,
152
+ description: (acpJob as any).requirement?.description ?? "",
153
+ requirements: (acpJob as any).requirement ?? {},
154
+ budget: BigInt((acpJob as any).price ?? 0),
155
+ clientAddress: (acpJob as any).clientAddress as Address,
156
+ };
157
+
158
+ // Find a matching handler
159
+ for (const [, handler] of this.jobHandlers) {
160
+ try {
161
+ const result = await handler(job);
162
+ // Deliver the result back through ACP
163
+ await (acpJob as any).deliver?.({
164
+ content: typeof result === "string" ? result : JSON.stringify(result),
165
+ contentType: "application/json",
166
+ });
167
+ return;
168
+ } catch (err) {
169
+ console.error(`[ACP] Handler failed for job ${job.jobId}:`, err);
170
+ }
171
+ }
172
+ }
173
+
174
+ private mapAcpAgent(agent: AcpAgent): AgentSearchResult {
175
+ const offerings: AgentOffering[] = ((agent as any).jobOfferings ?? []).map(
176
+ (o: any) => ({
177
+ id: o.id,
178
+ name: o.name ?? o.title ?? "Service",
179
+ description: o.description ?? "",
180
+ price: BigInt(o.price ?? 0),
181
+ currency: "USDC",
182
+ })
183
+ );
184
+
185
+ return {
186
+ id: (agent as any).id ?? (agent as any).walletAddress,
187
+ name: (agent as any).name ?? "Unknown Agent",
188
+ address: ((agent as any).walletAddress ?? (agent as any).contractAddress) as Address,
189
+ description: (agent as any).description ?? "",
190
+ categories: (agent as any).tags ?? (agent as any).categories ?? [],
191
+ offerings,
192
+ metrics: {
193
+ successRate: (agent as any).metrics?.successRate,
194
+ completedJobs: (agent as any).metrics?.completedJobs,
195
+ },
196
+ source: "acp",
197
+ };
198
+ }
199
+ }
@@ -0,0 +1,78 @@
1
+ import type { Address, Hex } from "viem";
2
+
3
+ /**
4
+ * Abstraction over escrow backends (Kompass native or Virtuals ACP).
5
+ * The simplified SDK uses this interface so it can swap backends
6
+ * without changing any user-facing code.
7
+ */
8
+
9
+ export interface AgentSearchResult {
10
+ id: string;
11
+ name: string;
12
+ address: Address;
13
+ description: string;
14
+ categories: string[];
15
+ offerings: AgentOffering[];
16
+ metrics?: {
17
+ successRate?: number;
18
+ completedJobs?: number;
19
+ };
20
+ source: "acp" | "kompass";
21
+ }
22
+
23
+ export interface AgentOffering {
24
+ id: string;
25
+ name: string;
26
+ description: string;
27
+ price: bigint;
28
+ currency: string;
29
+ }
30
+
31
+ export interface JobResult {
32
+ jobId: string;
33
+ phase: string;
34
+ deliverable: unknown;
35
+ txHash?: string;
36
+ }
37
+
38
+ export interface EscrowBackend {
39
+ /** Initialize the backend (auth, websocket connections, etc.) */
40
+ init(): Promise<void>;
41
+
42
+ /** Search for agents that can do a task */
43
+ browseAgents(query: string, options?: BrowseOptions): Promise<AgentSearchResult[]>;
44
+
45
+ /** Create and fund a job with an agent */
46
+ hireAgent(
47
+ agent: AgentSearchResult,
48
+ offeringId: string,
49
+ requirements: Record<string, unknown>,
50
+ budget?: bigint
51
+ ): Promise<JobResult>;
52
+
53
+ /** Poll/wait for a job to complete */
54
+ waitForResult(jobId: string, timeoutMs?: number): Promise<JobResult>;
55
+
56
+ /** Register as a seller and listen for incoming jobs */
57
+ acceptJobs(
58
+ capabilities: string[],
59
+ handler: (job: IncomingJob) => Promise<unknown>
60
+ ): Promise<void>;
61
+
62
+ /** Get the backend name */
63
+ name(): string;
64
+ }
65
+
66
+ export interface BrowseOptions {
67
+ limit?: number;
68
+ sortBy?: "successRate" | "completedJobs" | "recent";
69
+ onlineOnly?: boolean;
70
+ }
71
+
72
+ export interface IncomingJob {
73
+ jobId: string;
74
+ description: string;
75
+ requirements: Record<string, unknown>;
76
+ budget: bigint;
77
+ clientAddress: Address;
78
+ }