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
package/src/router.ts ADDED
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Kompass Capability Router
3
+ *
4
+ * The core product logic. Given a task, figure out the best way to get it done.
5
+ *
6
+ * kompass.do("get DeFi yield data") →
7
+ * 1. Parse intent → what capability is needed
8
+ * 2. Search all sources → where can I get it
9
+ * 3. Rank options → cost, speed, reliability, reputation
10
+ * 4. Execute via right protocol → ACP, x402, MCP, skill, A2A
11
+ * 5. Return result
12
+ */
13
+
14
+ import type { UnifiedAgent } from "./sources/types.js";
15
+ import { Aggregator } from "./aggregator.js";
16
+ import { rankAgents, parseIntent, type MatchResult } from "./matching.js";
17
+ import { ProtocolBridge, type BridgeHireResult } from "./bridge.js";
18
+
19
+ export type CostPreference = "cheapest" | "balanced" | "best-quality";
20
+
21
+ export interface DoOptions {
22
+ /** What you want done — natural language */
23
+ task: string;
24
+ /** Cost preference */
25
+ costPreference?: CostPreference;
26
+ /** Max budget in USD (e.g., 1.0 = $1) */
27
+ maxBudgetUSD?: number;
28
+ /** Prefer specific protocol */
29
+ preferProtocol?: string;
30
+ /** Prefer specific source */
31
+ preferSource?: string;
32
+ /** Timeout per capability in ms */
33
+ timeout?: number;
34
+ /** Return options without executing (dry run) */
35
+ dryRun?: boolean;
36
+ /** Additional payload to send to the capability */
37
+ payload?: Record<string, unknown>;
38
+ }
39
+
40
+ export interface CapabilityOption {
41
+ agent: UnifiedAgent;
42
+ scores: MatchResult["scores"];
43
+ estimatedCost: number | null;
44
+ protocol: string;
45
+ source: string;
46
+ why: string;
47
+ }
48
+
49
+ export interface DoResult {
50
+ success: boolean;
51
+ /** The task that was requested */
52
+ task: string;
53
+ /** All options found across protocols */
54
+ options: CapabilityOption[];
55
+ /** The option that was selected and executed */
56
+ selected: CapabilityOption | null;
57
+ /** Result from executing the selected option */
58
+ execution: BridgeHireResult | null;
59
+ /** Discovery metadata */
60
+ discovery: {
61
+ sourcesQueried: number;
62
+ totalFound: number;
63
+ queryTimeMs: number;
64
+ };
65
+ /** Why this option was selected */
66
+ reasoning: string;
67
+ }
68
+
69
+ export class CapabilityRouter {
70
+ private aggregator: Aggregator;
71
+ private bridge: ProtocolBridge;
72
+
73
+ constructor(aggregator: Aggregator, bridge: ProtocolBridge) {
74
+ this.aggregator = aggregator;
75
+ this.bridge = bridge;
76
+ }
77
+
78
+ async do(options: DoOptions): Promise<DoResult> {
79
+ const { task, dryRun = false } = options;
80
+
81
+ // 1. Search all sources
82
+ const searchResult = await this.aggregator.search(task, {
83
+ limit: 30,
84
+ timeout: options.timeout ?? 15000,
85
+ });
86
+
87
+ if (searchResult.agents.length === 0) {
88
+ return {
89
+ success: false,
90
+ task,
91
+ options: [],
92
+ selected: null,
93
+ execution: null,
94
+ discovery: {
95
+ sourcesQueried: searchResult.sources.length,
96
+ totalFound: 0,
97
+ queryTimeMs: searchResult.queryTimeMs,
98
+ },
99
+ reasoning: "No capabilities found for this task across any registry.",
100
+ };
101
+ }
102
+
103
+ // 2. Rank with multi-layer matching
104
+ const ranked = rankAgents(searchResult.agents, task);
105
+
106
+ // 3. Build options with cost estimates
107
+ const capabilityOptions = ranked.map((r) => this.buildOption(r, options));
108
+
109
+ // 4. Filter by budget
110
+ const affordable = options.maxBudgetUSD
111
+ ? capabilityOptions.filter(
112
+ (o) => o.estimatedCost === null || o.estimatedCost <= options.maxBudgetUSD!
113
+ )
114
+ : capabilityOptions;
115
+
116
+ // 5. Apply preference-based reranking
117
+ const reranked = this.applyPreferences(affordable.length > 0 ? affordable : capabilityOptions, options);
118
+
119
+ // 6. Select best option
120
+ const selected = reranked[0] ?? null;
121
+
122
+ if (!selected) {
123
+ return {
124
+ success: false,
125
+ task,
126
+ options: capabilityOptions,
127
+ selected: null,
128
+ execution: null,
129
+ discovery: {
130
+ sourcesQueried: searchResult.sources.length,
131
+ totalFound: searchResult.totalFound,
132
+ queryTimeMs: searchResult.queryTimeMs,
133
+ },
134
+ reasoning: options.maxBudgetUSD
135
+ ? `Found ${capabilityOptions.length} options but none within budget ($${options.maxBudgetUSD}).`
136
+ : "No suitable options found after ranking.",
137
+ };
138
+ }
139
+
140
+ // 7. Execute (unless dry run)
141
+ let execution: BridgeHireResult | null = null;
142
+
143
+ if (!dryRun) {
144
+ execution = await this.bridge.hire(selected.agent, {
145
+ task,
146
+ timeout: options.timeout,
147
+ payload: options.payload,
148
+ });
149
+ }
150
+
151
+ const reasoning = this.explainChoice(selected, reranked, options);
152
+
153
+ return {
154
+ success: dryRun ? true : (execution?.success ?? false),
155
+ task,
156
+ options: capabilityOptions.slice(0, 10), // Top 10 options
157
+ selected,
158
+ execution,
159
+ discovery: {
160
+ sourcesQueried: searchResult.sources.length,
161
+ totalFound: searchResult.totalFound,
162
+ queryTimeMs: searchResult.queryTimeMs,
163
+ },
164
+ reasoning,
165
+ };
166
+ }
167
+
168
+ private buildOption(match: MatchResult, options: DoOptions): CapabilityOption {
169
+ const agent = match.agent;
170
+ let estimatedCost: number | null = null;
171
+
172
+ if (agent.pricing?.amount) {
173
+ estimatedCost = parseFloat(agent.pricing.amount);
174
+ } else if (agent.pricing?.model === "free") {
175
+ estimatedCost = 0;
176
+ }
177
+
178
+ let why = "";
179
+ if (match.scores.structured > 10) why += "Strong capability match. ";
180
+ if (match.scores.bm25 > 5) why += "High text relevance. ";
181
+ if (match.scores.multiCriteria > 15) why += "Good reputation/trust signals. ";
182
+ if (estimatedCost === 0) why += "Free. ";
183
+ if (estimatedCost !== null && estimatedCost > 0 && estimatedCost < 0.05) why += "Very affordable. ";
184
+
185
+ return {
186
+ agent,
187
+ scores: match.scores,
188
+ estimatedCost,
189
+ protocol: agent.protocol,
190
+ source: agent.source,
191
+ why: why.trim() || "General match.",
192
+ };
193
+ }
194
+
195
+ private applyPreferences(options: CapabilityOption[], doOptions: DoOptions): CapabilityOption[] {
196
+ let sorted = [...options];
197
+
198
+ // Protocol preference
199
+ if (doOptions.preferProtocol) {
200
+ sorted.sort((a, b) => {
201
+ const aMatch = a.protocol === doOptions.preferProtocol ? 1 : 0;
202
+ const bMatch = b.protocol === doOptions.preferProtocol ? 1 : 0;
203
+ return bMatch - aMatch;
204
+ });
205
+ }
206
+
207
+ // Source preference
208
+ if (doOptions.preferSource) {
209
+ sorted.sort((a, b) => {
210
+ const aMatch = a.source === doOptions.preferSource ? 1 : 0;
211
+ const bMatch = b.source === doOptions.preferSource ? 1 : 0;
212
+ return bMatch - aMatch;
213
+ });
214
+ }
215
+
216
+ // Cost preference reranking
217
+ switch (doOptions.costPreference) {
218
+ case "cheapest":
219
+ sorted.sort((a, b) => {
220
+ const aCost = a.estimatedCost ?? Infinity;
221
+ const bCost = b.estimatedCost ?? Infinity;
222
+ return aCost - bCost;
223
+ });
224
+ break;
225
+
226
+ case "best-quality":
227
+ // Already sorted by score, but boost high-reputation agents
228
+ sorted.sort((a, b) => {
229
+ const aRep = a.agent.reputation?.score ?? 0;
230
+ const bRep = b.agent.reputation?.score ?? 0;
231
+ return bRep - aRep || b.scores.total - a.scores.total;
232
+ });
233
+ break;
234
+
235
+ case "balanced":
236
+ default:
237
+ // Default: score-based with cost as tiebreaker
238
+ sorted.sort((a, b) => {
239
+ if (Math.abs(b.scores.total - a.scores.total) > 5) {
240
+ return b.scores.total - a.scores.total;
241
+ }
242
+ const aCost = a.estimatedCost ?? 1;
243
+ const bCost = b.estimatedCost ?? 1;
244
+ return aCost - bCost;
245
+ });
246
+ break;
247
+ }
248
+
249
+ return sorted;
250
+ }
251
+
252
+ private explainChoice(
253
+ selected: CapabilityOption,
254
+ alternatives: CapabilityOption[],
255
+ options: DoOptions
256
+ ): string {
257
+ const parts: string[] = [];
258
+
259
+ parts.push(
260
+ `Selected "${selected.agent.name}" via ${selected.protocol.toUpperCase()} from ${selected.source}.`
261
+ );
262
+
263
+ if (selected.estimatedCost !== null) {
264
+ parts.push(
265
+ selected.estimatedCost === 0
266
+ ? "This option is free."
267
+ : `Estimated cost: $${selected.estimatedCost}.`
268
+ );
269
+ }
270
+
271
+ parts.push(selected.why);
272
+
273
+ if (alternatives.length > 1) {
274
+ parts.push(`${alternatives.length - 1} other options available.`);
275
+ }
276
+
277
+ return parts.join(" ");
278
+ }
279
+ }
package/src/simple.ts ADDED
@@ -0,0 +1,366 @@
1
+ /**
2
+ * Kompass Simplified API
3
+ *
4
+ * Dead-simple interface for agent-to-agent commerce.
5
+ * Wraps ACP escrow + Kompass intelligence (reputation, x402, intent routing).
6
+ *
7
+ * Usage:
8
+ * const kompass = await KompassSimple.create({ privateKey, network: "base-sepolia" });
9
+ * const result = await kompass.hireAgent({ task: "Find best yield on Base", maxBudget: 1_000_000n });
10
+ */
11
+
12
+ import type { Address, Hex } from "viem";
13
+ import { createPublicClient, http } from "viem";
14
+ import { baseSepolia, base } from "viem/chains";
15
+ import { privateKeyToAccount } from "viem/accounts";
16
+ import { AcpEscrowBackend, type AcpBackendConfig } from "./backends/acp.js";
17
+ import type {
18
+ EscrowBackend,
19
+ AgentSearchResult,
20
+ JobResult,
21
+ IncomingJob,
22
+ } from "./backends/types.js";
23
+ import { getReputation } from "./reputation.js";
24
+ import type { KompassConfig, ReputationSummary } from "./types.js";
25
+
26
+ // ── Config ───────────────────────────────────────────────
27
+
28
+ export interface KompassSimpleConfig {
29
+ /** Agent's private key */
30
+ privateKey: string;
31
+ /** Network: "base-sepolia" or "base" */
32
+ network?: "base-sepolia" | "base";
33
+ /** ACP entity/session key address (from ACP registration) */
34
+ acpEntityAddress?: string;
35
+ /** ACP wallet address */
36
+ acpWalletAddress?: string;
37
+ /** Kompass indexer URL for ENS discovery + reputation */
38
+ indexerUrl?: string;
39
+ /** ERC-8004 reputation registry address */
40
+ reputationRegistryAddress?: Address;
41
+ /** Custom RPC URL */
42
+ rpcUrl?: string;
43
+ }
44
+
45
+ // ── Hire Options ─────────────────────────────────────────
46
+
47
+ export interface HireOptions {
48
+ /** What you want done — natural language task description */
49
+ task: string;
50
+ /** Max budget in USDC base units (6 decimals). 1_000_000 = $1 */
51
+ maxBudget?: bigint;
52
+ /** Minimum ERC-8004 reputation score to trust an agent */
53
+ minReputation?: number;
54
+ /** Search query override (defaults to task) */
55
+ searchQuery?: string;
56
+ /** Specific offering ID if known */
57
+ offeringId?: string;
58
+ /** Additional requirements to send to the agent */
59
+ requirements?: Record<string, unknown>;
60
+ /** Timeout in ms for waiting for deliverable (default 5 min) */
61
+ timeoutMs?: number;
62
+ }
63
+
64
+ export interface HireResult {
65
+ agent: AgentSearchResult;
66
+ jobId: string;
67
+ deliverable: unknown;
68
+ phase: string;
69
+ reputationChecked: boolean;
70
+ txHash?: string;
71
+ }
72
+
73
+ // ── Accept Options ───────────────────────────────────────
74
+
75
+ export interface AcceptJobsOptions {
76
+ /** What capabilities this agent offers */
77
+ capabilities: string[];
78
+ /** Handler called when a job comes in — return the deliverable */
79
+ handler: (job: IncomingJob) => Promise<unknown>;
80
+ }
81
+
82
+ // ── Orchestrate Options ──────────────────────────────────
83
+
84
+ export interface OrchestrateOptions {
85
+ /** High-level intent — will be decomposed into multiple agent hires */
86
+ intent: string;
87
+ /** Risk tolerance for DeFi intents */
88
+ riskTolerance?: "conservative" | "balanced" | "aggressive";
89
+ /** Total budget across all steps */
90
+ budget?: bigint;
91
+ /** Minimum reputation for any hired agent */
92
+ minReputation?: number;
93
+ }
94
+
95
+ export interface OrchestrateResult {
96
+ intent: string;
97
+ steps: {
98
+ role: string;
99
+ agent: AgentSearchResult | null;
100
+ result: HireResult | null;
101
+ skipped: boolean;
102
+ reason?: string;
103
+ }[];
104
+ totalCostUSDC: number;
105
+ completedSteps: number;
106
+ }
107
+
108
+ // ── Main Class ───────────────────────────────────────────
109
+
110
+ export class KompassSimple {
111
+ private backend: EscrowBackend;
112
+ private config: KompassSimpleConfig;
113
+ private kompassConfig: KompassConfig | null = null;
114
+
115
+ private constructor(config: KompassSimpleConfig, backend: EscrowBackend) {
116
+ this.config = config;
117
+ this.backend = backend;
118
+ }
119
+
120
+ /**
121
+ * Create and initialize a Kompass instance.
122
+ *
123
+ * @example
124
+ * const kompass = await KompassSimple.create({
125
+ * privateKey: "0x...",
126
+ * network: "base-sepolia",
127
+ * acpEntityAddress: "0x...",
128
+ * acpWalletAddress: "0x...",
129
+ * });
130
+ */
131
+ static async create(config: KompassSimpleConfig): Promise<KompassSimple> {
132
+ const account = privateKeyToAccount(config.privateKey as Hex);
133
+ const chain = config.network === "base" ? base : baseSepolia;
134
+ const rpcUrl = config.rpcUrl ?? (config.network === "base" ? "https://mainnet.base.org" : "https://sepolia.base.org");
135
+
136
+ // Create ACP backend
137
+ const acpConfig: AcpBackendConfig = {
138
+ privateKey: config.privateKey,
139
+ walletAddress: (config.acpWalletAddress ?? account.address) as Address,
140
+ entityAddress: (config.acpEntityAddress ?? account.address) as Address,
141
+ network: config.network ?? "base-sepolia",
142
+ rpcUrl,
143
+ };
144
+
145
+ const backend = new AcpEscrowBackend(acpConfig);
146
+ await backend.init();
147
+
148
+ const instance = new KompassSimple(config, backend);
149
+
150
+ // Set up Kompass config for reputation queries if registry address provided
151
+ if (config.reputationRegistryAddress) {
152
+ const publicClient = createPublicClient({
153
+ chain,
154
+ transport: http(rpcUrl),
155
+ });
156
+ instance.kompassConfig = {
157
+ publicClient,
158
+ escrowAddress: "0x0000000000000000000000000000000000000000" as Address,
159
+ registryAddress: "0x0000000000000000000000000000000000000000" as Address,
160
+ reputationRegistryAddress: config.reputationRegistryAddress,
161
+ indexerUrl: config.indexerUrl ?? "",
162
+ } as KompassConfig;
163
+ }
164
+
165
+ return instance;
166
+ }
167
+
168
+ /**
169
+ * Hire an agent to do a task.
170
+ *
171
+ * Under the hood:
172
+ * 1. Searches ACP marketplace for matching agents
173
+ * 2. Checks ERC-8004 reputation (if configured)
174
+ * 3. Creates an ACP job and waits for delivery
175
+ * 4. Returns the deliverable
176
+ *
177
+ * @example
178
+ * const result = await kompass.hireAgent({
179
+ * task: "Find the best yield for 1000 USDC on Base",
180
+ * maxBudget: 1_000_000n,
181
+ * });
182
+ * console.log(result.deliverable);
183
+ */
184
+ async hireAgent(options: HireOptions): Promise<HireResult> {
185
+ const query = options.searchQuery ?? options.task;
186
+
187
+ // 1. Discover agents on ACP
188
+ const agents = await this.backend.browseAgents(query, {
189
+ limit: 10,
190
+ sortBy: "successRate",
191
+ onlineOnly: true,
192
+ });
193
+
194
+ if (agents.length === 0) {
195
+ throw new Error(`No agents found for: "${query}"`);
196
+ }
197
+
198
+ // 2. Check reputation (if configured)
199
+ let reputationChecked = false;
200
+ let filteredAgents = agents;
201
+
202
+ if (this.kompassConfig && options.minReputation !== undefined) {
203
+ filteredAgents = [];
204
+ for (const agent of agents) {
205
+ try {
206
+ const rep = await this.checkReputation(agent.address);
207
+ const score = Number(rep.summaryValue);
208
+ if (score >= options.minReputation || Number(rep.count) === 0) {
209
+ filteredAgents.push(agent);
210
+ }
211
+ } catch {
212
+ // If reputation check fails, include the agent (permissive)
213
+ filteredAgents.push(agent);
214
+ }
215
+ }
216
+ reputationChecked = true;
217
+
218
+ if (filteredAgents.length === 0) {
219
+ throw new Error(
220
+ `No agents meet reputation threshold (${options.minReputation}). Found ${agents.length} agents but none passed.`
221
+ );
222
+ }
223
+ }
224
+
225
+ // 3. Select best agent (first match after filtering)
226
+ const agent = filteredAgents[0];
227
+ const offering = agent.offerings[0];
228
+
229
+ if (!offering) {
230
+ throw new Error(`Agent "${agent.name}" has no offerings`);
231
+ }
232
+
233
+ // 4. Create job on ACP
234
+ const requirements = {
235
+ description: options.task,
236
+ ...options.requirements,
237
+ };
238
+
239
+ const job = await this.backend.hireAgent(
240
+ agent,
241
+ options.offeringId ?? offering.id,
242
+ requirements,
243
+ options.maxBudget
244
+ );
245
+
246
+ // 5. Wait for result
247
+ const result = await this.backend.waitForResult(
248
+ job.jobId,
249
+ options.timeoutMs ?? 300_000
250
+ );
251
+
252
+ return {
253
+ agent,
254
+ jobId: result.jobId,
255
+ deliverable: result.deliverable,
256
+ phase: result.phase,
257
+ reputationChecked,
258
+ txHash: result.txHash,
259
+ };
260
+ }
261
+
262
+ /**
263
+ * Start accepting jobs from other agents.
264
+ *
265
+ * Registers on ACP and listens for incoming jobs matching your capabilities.
266
+ * When a job arrives, your handler is called. Return the deliverable and
267
+ * the SDK handles ACP delivery automatically.
268
+ *
269
+ * @example
270
+ * await kompass.acceptJobs({
271
+ * capabilities: ["defi-research", "yield-analysis"],
272
+ * handler: async (job) => {
273
+ * const report = await doResearch(job.description);
274
+ * return report;
275
+ * },
276
+ * });
277
+ */
278
+ async acceptJobs(options: AcceptJobsOptions): Promise<void> {
279
+ await this.backend.acceptJobs(options.capabilities, options.handler);
280
+ }
281
+
282
+ /**
283
+ * Orchestrate a multi-agent pipeline for a complex intent.
284
+ *
285
+ * Decomposes the intent into specialist roles (research, data, risk, execution),
286
+ * hires an agent for each role via ACP, chains results, and returns the combined output.
287
+ *
288
+ * @example
289
+ * const result = await kompass.orchestrate({
290
+ * intent: "Find best yield for 1000 USDC on Base",
291
+ * riskTolerance: "balanced",
292
+ * budget: 5_000_000n,
293
+ * });
294
+ */
295
+ async orchestrate(options: OrchestrateOptions): Promise<OrchestrateResult> {
296
+ const roles = ["research", "premium-data", "risk", "execution"];
297
+ const perStepBudget = options.budget
298
+ ? options.budget / BigInt(roles.length)
299
+ : 1_000_000n;
300
+
301
+ const steps: OrchestrateResult["steps"] = [];
302
+ let totalCost = 0;
303
+
304
+ for (const role of roles) {
305
+ try {
306
+ const result = await this.hireAgent({
307
+ task: `[${role}] ${options.intent}`,
308
+ searchQuery: role === "premium-data" ? "data analytics" : role,
309
+ maxBudget: perStepBudget,
310
+ minReputation: options.minReputation,
311
+ timeoutMs: 120_000,
312
+ });
313
+
314
+ steps.push({
315
+ role,
316
+ agent: result.agent,
317
+ result,
318
+ skipped: false,
319
+ });
320
+
321
+ totalCost += Number(perStepBudget) / 1e6;
322
+ } catch (err) {
323
+ steps.push({
324
+ role,
325
+ agent: null,
326
+ result: null,
327
+ skipped: true,
328
+ reason: err instanceof Error ? err.message : String(err),
329
+ });
330
+ }
331
+ }
332
+
333
+ return {
334
+ intent: options.intent,
335
+ steps,
336
+ totalCostUSDC: totalCost,
337
+ completedSteps: steps.filter((s) => !s.skipped).length,
338
+ };
339
+ }
340
+
341
+ /**
342
+ * Check an agent's ERC-8004 on-chain reputation.
343
+ */
344
+ async checkReputation(agentAddress: Address): Promise<ReputationSummary> {
345
+ if (!this.kompassConfig) {
346
+ throw new Error("Reputation checking requires reputationRegistryAddress in config");
347
+ }
348
+ // Use agent address as ID (simplified — in production, look up erc8004Id)
349
+ return getReputation(this.kompassConfig, 0n);
350
+ }
351
+
352
+ /**
353
+ * Search for agents on ACP marketplace.
354
+ */
355
+ async discover(query: string, options?: { limit?: number }): Promise<AgentSearchResult[]> {
356
+ return this.backend.browseAgents(query, {
357
+ limit: options?.limit ?? 20,
358
+ sortBy: "successRate",
359
+ });
360
+ }
361
+
362
+ /** Get the backend name */
363
+ get backendName(): string {
364
+ return this.backend.name();
365
+ }
366
+ }