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.
- package/dist/a2a/agent-card.d.ts +13 -0
- package/dist/a2a/agent-card.d.ts.map +1 -0
- package/dist/a2a/agent-card.js +52 -0
- package/dist/a2a/agent-card.js.map +1 -0
- package/dist/a2a/bridge.d.ts +52 -0
- package/dist/a2a/bridge.d.ts.map +1 -0
- package/dist/a2a/bridge.js +123 -0
- package/dist/a2a/bridge.js.map +1 -0
- package/dist/a2a/client.d.ts +34 -0
- package/dist/a2a/client.d.ts.map +1 -0
- package/dist/a2a/client.js +65 -0
- package/dist/a2a/client.js.map +1 -0
- package/dist/a2a/server.d.ts +17 -0
- package/dist/a2a/server.d.ts.map +1 -0
- package/dist/a2a/server.js +194 -0
- package/dist/a2a/server.js.map +1 -0
- package/dist/abi.d.ts +1068 -0
- package/dist/abi.d.ts.map +1 -0
- package/dist/abi.js +1372 -0
- package/dist/abi.js.map +1 -0
- package/dist/adapters/agentkit.d.ts +41 -0
- package/dist/adapters/agentkit.d.ts.map +1 -0
- package/dist/adapters/agentkit.js +67 -0
- package/dist/adapters/agentkit.js.map +1 -0
- package/dist/adapters/generic.d.ts +35 -0
- package/dist/adapters/generic.d.ts.map +1 -0
- package/dist/adapters/generic.js +47 -0
- package/dist/adapters/generic.js.map +1 -0
- package/dist/adapters/index.d.ts +5 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +5 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/langchain.d.ts +26 -0
- package/dist/adapters/langchain.d.ts.map +1 -0
- package/dist/adapters/langchain.js +228 -0
- package/dist/adapters/langchain.js.map +1 -0
- package/dist/adapters/openclaw.d.ts +18 -0
- package/dist/adapters/openclaw.d.ts.map +1 -0
- package/dist/adapters/openclaw.js +168 -0
- package/dist/adapters/openclaw.js.map +1 -0
- package/dist/aggregator.d.ts +36 -0
- package/dist/aggregator.d.ts.map +1 -0
- package/dist/aggregator.js +168 -0
- package/dist/aggregator.js.map +1 -0
- package/dist/backends/acp.d.ts +29 -0
- package/dist/backends/acp.d.ts.map +1 -0
- package/dist/backends/acp.js +126 -0
- package/dist/backends/acp.js.map +1 -0
- package/dist/backends/types.d.ts +59 -0
- package/dist/backends/types.d.ts.map +1 -0
- package/dist/backends/types.js +2 -0
- package/dist/backends/types.js.map +1 -0
- package/dist/bridge.d.ts +35 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +192 -0
- package/dist/bridge.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +331 -0
- package/dist/cli.js.map +1 -0
- package/dist/discover.d.ts +15 -0
- package/dist/discover.d.ts.map +1 -0
- package/dist/discover.js +163 -0
- package/dist/discover.js.map +1 -0
- package/dist/escrow.d.ts +45 -0
- package/dist/escrow.d.ts.map +1 -0
- package/dist/escrow.js +243 -0
- package/dist/escrow.js.map +1 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +145 -0
- package/dist/index.js.map +1 -0
- package/dist/intents.d.ts +28 -0
- package/dist/intents.d.ts.map +1 -0
- package/dist/intents.js +111 -0
- package/dist/intents.js.map +1 -0
- package/dist/matching.d.ts +29 -0
- package/dist/matching.d.ts.map +1 -0
- package/dist/matching.js +147 -0
- package/dist/matching.js.map +1 -0
- package/dist/pipelineAbi.d.ts +113 -0
- package/dist/pipelineAbi.d.ts.map +1 -0
- package/dist/pipelineAbi.js +74 -0
- package/dist/pipelineAbi.js.map +1 -0
- package/dist/pipelines.d.ts +42 -0
- package/dist/pipelines.d.ts.map +1 -0
- package/dist/pipelines.js +185 -0
- package/dist/pipelines.js.map +1 -0
- package/dist/registry.d.ts +36 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +187 -0
- package/dist/registry.js.map +1 -0
- package/dist/reputation.d.ts +10 -0
- package/dist/reputation.d.ts.map +1 -0
- package/dist/reputation.js +33 -0
- package/dist/reputation.js.map +1 -0
- package/dist/router.d.ts +72 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +190 -0
- package/dist/router.js.map +1 -0
- package/dist/simple.d.ts +160 -0
- package/dist/simple.d.ts.map +1 -0
- package/dist/simple.js +237 -0
- package/dist/simple.js.map +1 -0
- package/dist/sources/a2a-wellknown.d.ts +8 -0
- package/dist/sources/a2a-wellknown.d.ts.map +1 -0
- package/dist/sources/a2a-wellknown.js +104 -0
- package/dist/sources/a2a-wellknown.js.map +1 -0
- package/dist/sources/acp.d.ts +7 -0
- package/dist/sources/acp.d.ts.map +1 -0
- package/dist/sources/acp.js +86 -0
- package/dist/sources/acp.js.map +1 -0
- package/dist/sources/adp.d.ts +7 -0
- package/dist/sources/adp.d.ts.map +1 -0
- package/dist/sources/adp.js +59 -0
- package/dist/sources/adp.js.map +1 -0
- package/dist/sources/erc8004.d.ts +7 -0
- package/dist/sources/erc8004.d.ts.map +1 -0
- package/dist/sources/erc8004.js +150 -0
- package/dist/sources/erc8004.js.map +1 -0
- package/dist/sources/index.d.ts +17 -0
- package/dist/sources/index.d.ts.map +1 -0
- package/dist/sources/index.js +35 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/sources/kompass-registry.d.ts +8 -0
- package/dist/sources/kompass-registry.d.ts.map +1 -0
- package/dist/sources/kompass-registry.js +62 -0
- package/dist/sources/kompass-registry.js.map +1 -0
- package/dist/sources/l402-directory.d.ts +7 -0
- package/dist/sources/l402-directory.d.ts.map +1 -0
- package/dist/sources/l402-directory.js +42 -0
- package/dist/sources/l402-directory.js.map +1 -0
- package/dist/sources/mcp-registry.d.ts +8 -0
- package/dist/sources/mcp-registry.d.ts.map +1 -0
- package/dist/sources/mcp-registry.js +85 -0
- package/dist/sources/mcp-registry.js.map +1 -0
- package/dist/sources/skills.d.ts +8 -0
- package/dist/sources/skills.d.ts.map +1 -0
- package/dist/sources/skills.js +153 -0
- package/dist/sources/skills.js.map +1 -0
- package/dist/sources/types.d.ts +72 -0
- package/dist/sources/types.d.ts.map +1 -0
- package/dist/sources/types.js +8 -0
- package/dist/sources/types.js.map +1 -0
- package/dist/sources/x402-ecosystem.d.ts +7 -0
- package/dist/sources/x402-ecosystem.d.ts.map +1 -0
- package/dist/sources/x402-ecosystem.js +78 -0
- package/dist/sources/x402-ecosystem.js.map +1 -0
- package/dist/types.d.ts +133 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/unified.d.ts +90 -0
- package/dist/unified.d.ts.map +1 -0
- package/dist/unified.js +107 -0
- package/dist/unified.js.map +1 -0
- package/dist/x402.d.ts +30 -0
- package/dist/x402.d.ts.map +1 -0
- package/dist/x402.js +79 -0
- package/dist/x402.js.map +1 -0
- package/package.json +61 -0
- package/scripts/bootstrap-agents.mjs +246 -0
- package/src/.gitkeep +0 -0
- package/src/a2a/agent-card.ts +66 -0
- package/src/a2a/bridge.ts +168 -0
- package/src/a2a/client.ts +92 -0
- package/src/a2a/server.ts +234 -0
- package/src/abi.ts +1373 -0
- package/src/adapters/agentkit.ts +83 -0
- package/src/adapters/generic.ts +62 -0
- package/src/adapters/index.ts +4 -0
- package/src/adapters/langchain.ts +282 -0
- package/src/adapters/openclaw.ts +203 -0
- package/src/aggregator.ts +203 -0
- package/src/backends/acp.ts +199 -0
- package/src/backends/types.ts +78 -0
- package/src/bridge.ts +263 -0
- package/src/cli.ts +397 -0
- package/src/discover.ts +187 -0
- package/src/escrow.ts +284 -0
- package/src/index.ts +245 -0
- package/src/intents.ts +166 -0
- package/src/matching.ts +192 -0
- package/src/pipelineAbi.ts +74 -0
- package/src/pipelines.ts +253 -0
- package/src/registry.ts +232 -0
- package/src/reputation.ts +43 -0
- package/src/router.ts +279 -0
- package/src/simple.ts +366 -0
- package/src/sources/a2a-wellknown.ts +120 -0
- package/src/sources/acp.ts +91 -0
- package/src/sources/adp.ts +64 -0
- package/src/sources/erc8004.ts +166 -0
- package/src/sources/index.ts +52 -0
- package/src/sources/kompass-registry.ts +67 -0
- package/src/sources/l402-directory.ts +51 -0
- package/src/sources/mcp-registry.ts +104 -0
- package/src/sources/skills.ts +161 -0
- package/src/sources/types.ts +82 -0
- package/src/sources/x402-ecosystem.ts +86 -0
- package/src/types.ts +147 -0
- package/src/unified.ts +155 -0
- package/src/x402.ts +122 -0
- package/tests/pipelineFlow.test.ts +239 -0
- package/tsconfig.json +20 -0
package/src/unified.ts
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KompassUnified — Universal Agent Discovery + Coordination
|
|
3
|
+
*
|
|
4
|
+
* The Google for AI agents. One API that searches across ALL registries
|
|
5
|
+
* and lets you hire any agent regardless of protocol.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const kompass = await KompassUnified.create({ network: "base-sepolia" });
|
|
9
|
+
* const agents = await kompass.find("yield optimization");
|
|
10
|
+
* const result = await kompass.hire(agents[0], "Find best yield on Base");
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { createAllSources, type SourceAdapter, type UnifiedAgent } from "./sources/index.js";
|
|
14
|
+
import { Aggregator, type AggregatorOptions, type AggregatorResult } from "./aggregator.js";
|
|
15
|
+
import { rankAgents, type MatchResult } from "./matching.js";
|
|
16
|
+
import { ProtocolBridge, type BridgeHireOptions, type BridgeHireResult } from "./bridge.js";
|
|
17
|
+
import { CapabilityRouter, type DoOptions, type DoResult } from "./router.js";
|
|
18
|
+
|
|
19
|
+
export interface UnifiedConfig {
|
|
20
|
+
/** Network for on-chain sources */
|
|
21
|
+
network?: "base" | "base-sepolia";
|
|
22
|
+
/** Which sources to enable (default: all) */
|
|
23
|
+
enabledSources?: string[];
|
|
24
|
+
/** ACP backend instance (for hiring via ACP) */
|
|
25
|
+
acpBackend?: any;
|
|
26
|
+
/** Kompass SDK config (for kompass-registry source) */
|
|
27
|
+
kompassConfig?: any;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface FindOptions {
|
|
31
|
+
/** Max results */
|
|
32
|
+
limit?: number;
|
|
33
|
+
/** Filter by source */
|
|
34
|
+
sources?: string[];
|
|
35
|
+
/** Timeout per source in ms */
|
|
36
|
+
timeout?: number;
|
|
37
|
+
/** Minimum match score (0-100) */
|
|
38
|
+
minScore?: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface FindResult extends AggregatorResult {
|
|
42
|
+
/** Agents re-ranked by multi-layer matching */
|
|
43
|
+
ranked: MatchResult[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class KompassUnified {
|
|
47
|
+
private aggregator: Aggregator;
|
|
48
|
+
private bridge: ProtocolBridge;
|
|
49
|
+
private router: CapabilityRouter;
|
|
50
|
+
private adapters: SourceAdapter[];
|
|
51
|
+
|
|
52
|
+
private constructor(adapters: SourceAdapter[], bridge: ProtocolBridge) {
|
|
53
|
+
this.adapters = adapters;
|
|
54
|
+
this.aggregator = new Aggregator(adapters);
|
|
55
|
+
this.bridge = bridge;
|
|
56
|
+
this.router = new CapabilityRouter(this.aggregator, this.bridge);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static async create(config?: UnifiedConfig): Promise<KompassUnified> {
|
|
60
|
+
const adapters = createAllSources({
|
|
61
|
+
erc8004Network: config?.network ?? "base-sepolia",
|
|
62
|
+
kompassConfig: config?.kompassConfig,
|
|
63
|
+
enabledSources: config?.enabledSources,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const bridge = new ProtocolBridge({
|
|
67
|
+
acpBackend: config?.acpBackend,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return new KompassUnified(adapters, bridge);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Search for agents across all registries.
|
|
75
|
+
* Returns results ranked by multi-layer matching (structured + BM25 + multi-criteria).
|
|
76
|
+
*/
|
|
77
|
+
async find(query: string, options?: FindOptions): Promise<FindResult> {
|
|
78
|
+
const aggregatorResult = await this.aggregator.search(query, {
|
|
79
|
+
limit: (options?.limit ?? 20) * 2, // Over-fetch for re-ranking
|
|
80
|
+
sources: options?.sources,
|
|
81
|
+
timeout: options?.timeout,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Re-rank with multi-layer matching
|
|
85
|
+
const ranked = rankAgents(aggregatorResult.agents, query);
|
|
86
|
+
|
|
87
|
+
// Apply limit and min score
|
|
88
|
+
const filtered = options?.minScore
|
|
89
|
+
? ranked.filter((r) => r.scores.total >= options.minScore!)
|
|
90
|
+
: ranked;
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
...aggregatorResult,
|
|
94
|
+
agents: filtered.slice(0, options?.limit ?? 20).map((r) => r.agent),
|
|
95
|
+
ranked: filtered.slice(0, options?.limit ?? 20),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Hire a specific agent via its native protocol.
|
|
101
|
+
* The bridge routes to ACP, x402, MCP, A2A, HTTP, or L402 automatically.
|
|
102
|
+
*/
|
|
103
|
+
async hire(agent: UnifiedAgent, task: string, options?: Partial<BridgeHireOptions>): Promise<BridgeHireResult> {
|
|
104
|
+
return this.bridge.hire(agent, { task, ...options });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Find the best agent for a task and hire it.
|
|
109
|
+
* One function: discover → rank → hire.
|
|
110
|
+
*/
|
|
111
|
+
async findAndHire(
|
|
112
|
+
query: string,
|
|
113
|
+
task: string,
|
|
114
|
+
options?: FindOptions & Partial<BridgeHireOptions>
|
|
115
|
+
): Promise<{ discovery: FindResult; hire: BridgeHireResult }> {
|
|
116
|
+
const discovery = await this.find(query, options);
|
|
117
|
+
|
|
118
|
+
if (discovery.agents.length === 0) {
|
|
119
|
+
throw new Error(`No agents found for: "${query}"`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const bestAgent = discovery.agents[0];
|
|
123
|
+
const hireResult = await this.hire(bestAgent, task, options);
|
|
124
|
+
|
|
125
|
+
return { discovery, hire: hireResult };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Check health of all discovery sources.
|
|
130
|
+
*/
|
|
131
|
+
async sources(): Promise<{ name: string; displayName: string; healthy: boolean }[]> {
|
|
132
|
+
return this.aggregator.healthCheck();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get any job done. The core Kompass function.
|
|
137
|
+
*
|
|
138
|
+
* Discovers the right capability across all protocols, picks the best option,
|
|
139
|
+
* executes via the right payment rail, and returns the result.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* const result = await kompass.do({ task: "get DeFi yield data for Base" });
|
|
143
|
+
* console.log(result.execution?.deliverable);
|
|
144
|
+
*/
|
|
145
|
+
async do(options: DoOptions): Promise<DoResult> {
|
|
146
|
+
return this.router.do(options);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get the number of registered source adapters.
|
|
151
|
+
*/
|
|
152
|
+
get sourceCount(): number {
|
|
153
|
+
return this.adapters.length;
|
|
154
|
+
}
|
|
155
|
+
}
|
package/src/x402.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { PaymentMode } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export interface X402PaymentRequirement {
|
|
4
|
+
protocol: PaymentMode | "unknown";
|
|
5
|
+
amount?: string;
|
|
6
|
+
asset?: string;
|
|
7
|
+
payTo?: string;
|
|
8
|
+
facilitator?: string;
|
|
9
|
+
network?: string;
|
|
10
|
+
scheme?: string;
|
|
11
|
+
raw: unknown;
|
|
12
|
+
rawBody?: string;
|
|
13
|
+
rawHeaders: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface X402PaymentRequestContext {
|
|
17
|
+
url: string;
|
|
18
|
+
init: RequestInit;
|
|
19
|
+
response: Response;
|
|
20
|
+
requirement: X402PaymentRequirement;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface X402PaymentResponse {
|
|
24
|
+
headers?: HeadersInit;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface X402ClientOptions {
|
|
28
|
+
fetchFn?: typeof fetch;
|
|
29
|
+
parseRequirement?: (response: Response) => Promise<X402PaymentRequirement>;
|
|
30
|
+
onPaymentRequired: (context: X402PaymentRequestContext) => Promise<X402PaymentResponse>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function headersToObject(headers: Headers): Record<string, string> {
|
|
34
|
+
return Object.fromEntries(headers.entries());
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function detectProtocol(raw: unknown): X402PaymentRequirement["protocol"] {
|
|
38
|
+
if (raw && typeof raw === "object") {
|
|
39
|
+
const protocol = Reflect.get(raw, "protocol");
|
|
40
|
+
if (protocol === "x402" || protocol === "escrow" || protocol === "hybrid") {
|
|
41
|
+
return protocol;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return "unknown";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function parseX402Requirement(response: Response): Promise<X402PaymentRequirement> {
|
|
48
|
+
const rawHeaders = headersToObject(response.headers);
|
|
49
|
+
const headerPayload =
|
|
50
|
+
response.headers.get("x-payment-requirement") ??
|
|
51
|
+
response.headers.get("x-payment-requirements") ??
|
|
52
|
+
response.headers.get("x-402-payment-requirement");
|
|
53
|
+
|
|
54
|
+
let raw: unknown = headerPayload ?? {};
|
|
55
|
+
let rawBody: string | undefined;
|
|
56
|
+
|
|
57
|
+
if (headerPayload) {
|
|
58
|
+
try {
|
|
59
|
+
raw = JSON.parse(headerPayload);
|
|
60
|
+
} catch {
|
|
61
|
+
raw = { value: headerPayload };
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
rawBody = await response.clone().text();
|
|
65
|
+
try {
|
|
66
|
+
raw = JSON.parse(rawBody);
|
|
67
|
+
} catch {
|
|
68
|
+
raw = { value: rawBody };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const payload = raw && typeof raw === "object" ? raw as Record<string, unknown> : {};
|
|
73
|
+
const accepts = Array.isArray(payload.accepts) ? payload.accepts[0] : undefined;
|
|
74
|
+
const requirement = (accepts && typeof accepts === "object" ? accepts : payload) as Record<string, unknown>;
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
protocol: detectProtocol(requirement),
|
|
78
|
+
amount: typeof requirement.amount === "string" ? requirement.amount : undefined,
|
|
79
|
+
asset: typeof requirement.asset === "string" ? requirement.asset : undefined,
|
|
80
|
+
payTo: typeof requirement.payTo === "string" ? requirement.payTo : undefined,
|
|
81
|
+
facilitator: typeof requirement.facilitator === "string" ? requirement.facilitator : undefined,
|
|
82
|
+
network: typeof requirement.network === "string" ? requirement.network : undefined,
|
|
83
|
+
scheme: typeof requirement.scheme === "string" ? requirement.scheme : undefined,
|
|
84
|
+
raw,
|
|
85
|
+
rawBody,
|
|
86
|
+
rawHeaders,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function mergeHeaders(base?: HeadersInit, extra?: HeadersInit): Headers {
|
|
91
|
+
const headers = new Headers(base);
|
|
92
|
+
if (!extra) return headers;
|
|
93
|
+
const extraHeaders = new Headers(extra);
|
|
94
|
+
extraHeaders.forEach((value, key) => headers.set(key, value));
|
|
95
|
+
return headers;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function requestWithX402(
|
|
99
|
+
url: string,
|
|
100
|
+
init: RequestInit,
|
|
101
|
+
options: X402ClientOptions
|
|
102
|
+
): Promise<Response> {
|
|
103
|
+
const fetchFn = options.fetchFn ?? fetch;
|
|
104
|
+
const firstResponse = await fetchFn(url, init);
|
|
105
|
+
|
|
106
|
+
if (firstResponse.status !== 402) {
|
|
107
|
+
return firstResponse;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const requirement = await (options.parseRequirement ?? parseX402Requirement)(firstResponse);
|
|
111
|
+
const payment = await options.onPaymentRequired({
|
|
112
|
+
url,
|
|
113
|
+
init,
|
|
114
|
+
response: firstResponse,
|
|
115
|
+
requirement,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return fetchFn(url, {
|
|
119
|
+
...init,
|
|
120
|
+
headers: mergeHeaders(init.headers, payment.headers),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { encodeAbiParameters, encodeEventTopics, keccak256, toHex, type Address, type Hex } from "viem";
|
|
3
|
+
import { routeYieldIntent } from "../src/intents.js";
|
|
4
|
+
import { buildYieldPipelinePlan, createYieldPipeline } from "../src/pipelines.js";
|
|
5
|
+
import { PipelineOrchestratorAbi } from "../src/pipelineAbi.js";
|
|
6
|
+
import type { AgentProfile, KompassConfig } from "../src/types.js";
|
|
7
|
+
|
|
8
|
+
const RESEARCH_AGENT = "0x1000000000000000000000000000000000000001" as Address;
|
|
9
|
+
const DATA_AGENT = "0x1000000000000000000000000000000000000002" as Address;
|
|
10
|
+
const RISK_AGENT = "0x1000000000000000000000000000000000000003" as Address;
|
|
11
|
+
const EXECUTION_AGENT = "0x1000000000000000000000000000000000000004" as Address;
|
|
12
|
+
const PIPELINE_ADDRESS = "0x2000000000000000000000000000000000000001" as Address;
|
|
13
|
+
const TOKEN_ADDRESS = "0x2000000000000000000000000000000000000002" as Address;
|
|
14
|
+
|
|
15
|
+
function makeAgent(overrides: Partial<AgentProfile> & Pick<AgentProfile, "id" | "agentType" | "categories">): AgentProfile {
|
|
16
|
+
return {
|
|
17
|
+
id: overrides.id,
|
|
18
|
+
ensNode: "0x1111111111111111111111111111111111111111111111111111111111111111",
|
|
19
|
+
ensName: "",
|
|
20
|
+
agentType: overrides.agentType,
|
|
21
|
+
categories: overrides.categories,
|
|
22
|
+
pricingModel: "fixed",
|
|
23
|
+
pricingRate: "0",
|
|
24
|
+
pricingToken: TOKEN_ADDRESS,
|
|
25
|
+
erc8004Id: "1",
|
|
26
|
+
identityVerification: "agent-registration[0xregistry][1]",
|
|
27
|
+
identityVerified: true,
|
|
28
|
+
paymentMode: "escrow",
|
|
29
|
+
endpointMcp: "",
|
|
30
|
+
endpointA2a: "",
|
|
31
|
+
endpointX402: "",
|
|
32
|
+
x402Enabled: false,
|
|
33
|
+
evaluatorDomains: "",
|
|
34
|
+
description: "Kompass test agent",
|
|
35
|
+
registered: true,
|
|
36
|
+
registeredAt: 1n,
|
|
37
|
+
updatedAt: 1n,
|
|
38
|
+
...overrides,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function createPipelineCreatedLog(pipelineId: bigint, client: Address, intentHash: Hex) {
|
|
43
|
+
const topics = encodeEventTopics({
|
|
44
|
+
abi: PipelineOrchestratorAbi,
|
|
45
|
+
eventName: "PipelineCreated",
|
|
46
|
+
args: {
|
|
47
|
+
pipelineId,
|
|
48
|
+
client,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const data = encodeAbiParameters([{ name: "intentHash", type: "bytes32" }], [intentHash]);
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
address: PIPELINE_ADDRESS,
|
|
56
|
+
topics,
|
|
57
|
+
data,
|
|
58
|
+
blockHash: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" as Hex,
|
|
59
|
+
blockNumber: 1n,
|
|
60
|
+
transactionHash: "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" as Hex,
|
|
61
|
+
transactionIndex: 0,
|
|
62
|
+
logIndex: 0,
|
|
63
|
+
removed: false,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
describe("Kompass pipeline flow", () => {
|
|
68
|
+
const agents: AgentProfile[] = [
|
|
69
|
+
makeAgent({
|
|
70
|
+
id: RESEARCH_AGENT,
|
|
71
|
+
ensName: "research.kompass.eth",
|
|
72
|
+
agentType: "provider",
|
|
73
|
+
categories: "defi,analytics,yield,research",
|
|
74
|
+
paymentMode: "hybrid",
|
|
75
|
+
pricingRate: "1250000",
|
|
76
|
+
}),
|
|
77
|
+
makeAgent({
|
|
78
|
+
id: DATA_AGENT,
|
|
79
|
+
ensName: "data.kompass.eth",
|
|
80
|
+
agentType: "provider",
|
|
81
|
+
categories: "data,analytics,signals",
|
|
82
|
+
paymentMode: "x402",
|
|
83
|
+
endpointX402: "https://api.kompass.test",
|
|
84
|
+
x402Enabled: true,
|
|
85
|
+
pricingRate: "500000",
|
|
86
|
+
}),
|
|
87
|
+
makeAgent({
|
|
88
|
+
id: RISK_AGENT,
|
|
89
|
+
ensName: "risk.kompass.eth",
|
|
90
|
+
agentType: "evaluator",
|
|
91
|
+
categories: "risk,security,defi",
|
|
92
|
+
paymentMode: "hybrid",
|
|
93
|
+
pricingRate: "1000000",
|
|
94
|
+
}),
|
|
95
|
+
makeAgent({
|
|
96
|
+
id: EXECUTION_AGENT,
|
|
97
|
+
ensName: "execute.kompass.eth",
|
|
98
|
+
agentType: "provider",
|
|
99
|
+
categories: "yield,swap,bridge,defi",
|
|
100
|
+
paymentMode: "escrow",
|
|
101
|
+
pricingRate: "1500000",
|
|
102
|
+
}),
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
it("routes the intent and keeps x402 premium data offchain", () => {
|
|
106
|
+
const route = routeYieldIntent(agents, {
|
|
107
|
+
amount: 1_000_000_000n,
|
|
108
|
+
riskTolerance: "balanced",
|
|
109
|
+
chain: "Base",
|
|
110
|
+
stablecoin: "USDC",
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
expect(route.missingCapabilities).toEqual([]);
|
|
114
|
+
expect(route.recommendedAgents).toHaveLength(4);
|
|
115
|
+
|
|
116
|
+
const plan = buildYieldPipelinePlan(route, { token: TOKEN_ADDRESS });
|
|
117
|
+
|
|
118
|
+
expect(plan.offchainSteps).toHaveLength(1);
|
|
119
|
+
expect(plan.offchainSteps[0].role).toBe("premium-data");
|
|
120
|
+
expect(plan.offchainSteps[0].endpointX402).toBe("https://api.kompass.test");
|
|
121
|
+
|
|
122
|
+
expect(plan.subtasks).toHaveLength(3);
|
|
123
|
+
expect(plan.subtasks.map((step) => step.role)).toEqual(["research", "risk", "execution"]);
|
|
124
|
+
expect(plan.subtasks[0].evaluator).toBe(RISK_AGENT);
|
|
125
|
+
expect(plan.subtasks[1].dependencies).toEqual([0]);
|
|
126
|
+
expect(plan.subtasks[2].dependencies).toEqual([1]);
|
|
127
|
+
expect(plan.subtasks[2].evaluator).toBe(RISK_AGENT);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("creates, funds, and activates the escrow-capable pipeline sequence", async () => {
|
|
131
|
+
const route = routeYieldIntent(agents, {
|
|
132
|
+
amount: 1_000_000_000n,
|
|
133
|
+
riskTolerance: "balanced",
|
|
134
|
+
chain: "Base",
|
|
135
|
+
stablecoin: "USDC",
|
|
136
|
+
});
|
|
137
|
+
const plan = buildYieldPipelinePlan(route, { token: TOKEN_ADDRESS });
|
|
138
|
+
const pipelineId = 42n;
|
|
139
|
+
|
|
140
|
+
const writeContract = vi
|
|
141
|
+
.fn()
|
|
142
|
+
.mockResolvedValueOnce("0x0000000000000000000000000000000000000000000000000000000000000001")
|
|
143
|
+
.mockResolvedValueOnce("0x0000000000000000000000000000000000000000000000000000000000000002")
|
|
144
|
+
.mockResolvedValueOnce("0x0000000000000000000000000000000000000000000000000000000000000003")
|
|
145
|
+
.mockResolvedValueOnce("0x0000000000000000000000000000000000000000000000000000000000000004")
|
|
146
|
+
.mockResolvedValueOnce("0x0000000000000000000000000000000000000000000000000000000000000005")
|
|
147
|
+
.mockResolvedValueOnce("0x0000000000000000000000000000000000000000000000000000000000000006")
|
|
148
|
+
.mockResolvedValueOnce("0x0000000000000000000000000000000000000000000000000000000000000007");
|
|
149
|
+
|
|
150
|
+
const waitForTransactionReceipt = vi.fn(async ({ hash }: { hash: Hex }) => {
|
|
151
|
+
if (hash === "0x0000000000000000000000000000000000000000000000000000000000000001") {
|
|
152
|
+
return {
|
|
153
|
+
logs: [createPipelineCreatedLog(pipelineId, RESEARCH_AGENT, plan.intentHash)],
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return { logs: [] };
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const config: KompassConfig = {
|
|
160
|
+
escrowAddress: "0x3000000000000000000000000000000000000001",
|
|
161
|
+
registryAddress: "0x3000000000000000000000000000000000000002",
|
|
162
|
+
reputationRegistryAddress: "0x3000000000000000000000000000000000000003",
|
|
163
|
+
pipelineAddress: PIPELINE_ADDRESS,
|
|
164
|
+
paymentTokenAddress: TOKEN_ADDRESS,
|
|
165
|
+
indexerUrl: "http://localhost:42069/graphql",
|
|
166
|
+
walletClient: {
|
|
167
|
+
writeContract,
|
|
168
|
+
} as unknown as KompassConfig["walletClient"],
|
|
169
|
+
publicClient: {
|
|
170
|
+
waitForTransactionReceipt,
|
|
171
|
+
} as unknown as KompassConfig["publicClient"],
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const result = await createYieldPipeline(config, route);
|
|
175
|
+
|
|
176
|
+
expect(result.pipelineId).toBe(pipelineId);
|
|
177
|
+
expect(result.approveTxHash).toBe("0x0000000000000000000000000000000000000000000000000000000000000005");
|
|
178
|
+
expect(result.fundTxHash).toBe("0x0000000000000000000000000000000000000000000000000000000000000006");
|
|
179
|
+
expect(result.activateTxHash).toBe("0x0000000000000000000000000000000000000000000000000000000000000007");
|
|
180
|
+
|
|
181
|
+
expect(writeContract).toHaveBeenCalledTimes(7);
|
|
182
|
+
expect(writeContract.mock.calls[0][0]).toMatchObject({
|
|
183
|
+
address: PIPELINE_ADDRESS,
|
|
184
|
+
functionName: "createPipeline",
|
|
185
|
+
args: [TOKEN_ADDRESS, keccak256(toHex(route.summary))],
|
|
186
|
+
});
|
|
187
|
+
expect(writeContract.mock.calls[1][0]).toMatchObject({
|
|
188
|
+
address: PIPELINE_ADDRESS,
|
|
189
|
+
functionName: "addSubTask",
|
|
190
|
+
});
|
|
191
|
+
expect(writeContract.mock.calls[1][0].args.slice(0, 4)).toEqual([
|
|
192
|
+
pipelineId,
|
|
193
|
+
RESEARCH_AGENT,
|
|
194
|
+
RISK_AGENT,
|
|
195
|
+
1_250_000n,
|
|
196
|
+
]);
|
|
197
|
+
expect(writeContract.mock.calls[1][0].args[5]).toEqual([]);
|
|
198
|
+
|
|
199
|
+
expect(writeContract.mock.calls[2][0]).toMatchObject({
|
|
200
|
+
address: PIPELINE_ADDRESS,
|
|
201
|
+
functionName: "addSubTask",
|
|
202
|
+
});
|
|
203
|
+
expect(writeContract.mock.calls[2][0].args.slice(0, 4)).toEqual([
|
|
204
|
+
pipelineId,
|
|
205
|
+
RISK_AGENT,
|
|
206
|
+
RISK_AGENT,
|
|
207
|
+
1_000_000n,
|
|
208
|
+
]);
|
|
209
|
+
expect(writeContract.mock.calls[2][0].args[5]).toEqual([0n]);
|
|
210
|
+
|
|
211
|
+
expect(writeContract.mock.calls[3][0]).toMatchObject({
|
|
212
|
+
address: PIPELINE_ADDRESS,
|
|
213
|
+
functionName: "addSubTask",
|
|
214
|
+
});
|
|
215
|
+
expect(writeContract.mock.calls[3][0].args.slice(0, 4)).toEqual([
|
|
216
|
+
pipelineId,
|
|
217
|
+
EXECUTION_AGENT,
|
|
218
|
+
RISK_AGENT,
|
|
219
|
+
1_500_000n,
|
|
220
|
+
]);
|
|
221
|
+
expect(writeContract.mock.calls[3][0].args[5]).toEqual([1n]);
|
|
222
|
+
expect(writeContract.mock.calls[4][0]).toMatchObject({
|
|
223
|
+
address: TOKEN_ADDRESS,
|
|
224
|
+
functionName: "approve",
|
|
225
|
+
args: [PIPELINE_ADDRESS, 3_750_000n],
|
|
226
|
+
});
|
|
227
|
+
expect(writeContract.mock.calls[5][0]).toMatchObject({
|
|
228
|
+
address: PIPELINE_ADDRESS,
|
|
229
|
+
functionName: "fundPipeline",
|
|
230
|
+
args: [pipelineId],
|
|
231
|
+
});
|
|
232
|
+
expect(writeContract.mock.calls[6][0]).toMatchObject({
|
|
233
|
+
address: PIPELINE_ADDRESS,
|
|
234
|
+
functionName: "activateNextTasks",
|
|
235
|
+
args: [pipelineId],
|
|
236
|
+
});
|
|
237
|
+
expect(waitForTransactionReceipt).toHaveBeenCalledTimes(7);
|
|
238
|
+
});
|
|
239
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
+
"module": "ES2022",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"declarationMap": true,
|
|
9
|
+
"sourceMap": true,
|
|
10
|
+
"outDir": "./dist",
|
|
11
|
+
"rootDir": "./src",
|
|
12
|
+
"strict": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true,
|
|
16
|
+
"resolveJsonModule": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*.ts"],
|
|
19
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
20
|
+
}
|