Skip to content

Commit a2fc7bd

Browse files
author
balogh.adam@icloud.com
committed
package
1 parent 7377767 commit a2fc7bd

5 files changed

Lines changed: 104 additions & 20 deletions

File tree

examples/llm_chat.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ async function main() {
2626
});
2727

2828
console.log(`Response: ${result.chatOutput?.content}`);
29-
console.log(`Payment hash: ${result.paymentHash}`);
29+
console.log(`Payment hash: ${result.transactionHash}`);
3030
}
3131

3232
main().catch((err) => {

package-lock.json

Lines changed: 62 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
"testEnvironment": "node"
5353
},
5454
"dependencies": {
55+
"@x402/core": "^2.11.0",
56+
"@x402/evm": "^2.11.0",
57+
"@x402/fetch": "^2.11.0",
5558
"undici": "^6.21.0",
5659
"viem": "^2.21.0",
5760
"x402-fetch": "^1.2.0"

src/llm.ts

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { createSigner, wrapFetchWithPayment } from "x402-fetch";
1+
import { wrapFetchWithPayment } from "@x402/fetch";
2+
import { x402Client } from "@x402/core/client";
3+
import { UptoEvmScheme } from "@x402/evm";
4+
import { registerExactEvmScheme } from "@x402/evm/exact/client";
5+
import { privateKeyToAccount } from "viem/accounts";
26
import type { Agent } from "undici";
37
import {
48
ChatParams,
@@ -34,7 +38,7 @@ export interface LLMConfig {
3438
* `llmServerUrl` on the `Client` to override with a hardcoded URL.
3539
*/
3640
export class LLM {
37-
private signerPromise?: Promise<unknown>;
41+
private x402ClientInstance?: x402Client;
3842

3943
constructor(private readonly config: LLMConfig) {}
4044

@@ -200,29 +204,26 @@ export class LLM {
200204
return payload;
201205
}
202206

203-
private async getSigner(): Promise<unknown> {
204-
if (!this.signerPromise) {
205-
this.signerPromise = createSigner(
206-
this.config.network,
207-
this.config.privateKey,
208-
);
207+
private getX402Client(): x402Client {
208+
if (!this.x402ClientInstance) {
209+
const account = privateKeyToAccount(this.config.privateKey);
210+
const client = new x402Client();
211+
registerExactEvmScheme(client, { signer: account });
212+
// The TEE may quote the "upto" scheme — register it on EVM networks too.
213+
client.register("eip155:*", new UptoEvmScheme(account));
214+
this.x402ClientInstance = client;
209215
}
210-
return this.signerPromise;
216+
return this.x402ClientInstance;
211217
}
212218

213219
/**
214220
* Build a paid fetch that injects the TEE's pinned TLS dispatcher into every
215221
* request (including x402 payment retries).
216222
*/
217-
private async buildPaidFetch(dispatcher: Agent): Promise<typeof fetch> {
218-
const signer = await this.getSigner();
223+
private buildPaidFetch(dispatcher: Agent): typeof fetch {
219224
const baseFetch: typeof fetch = ((input: any, init?: any) =>
220225
fetch(input, { ...(init ?? {}), dispatcher } as any)) as typeof fetch;
221-
return wrapFetchWithPayment(
222-
baseFetch,
223-
signer as any,
224-
this.config.maxPaymentValue,
225-
) as typeof fetch;
226+
return wrapFetchWithPayment(baseFetch, this.getX402Client()) as typeof fetch;
226227
}
227228

228229
/**
@@ -261,7 +262,7 @@ export class LLM {
261262
): Promise<{ response: Response; tee: ActiveTEE }> {
262263
const tee = await this.config.connection.ensureConnected();
263264
const url = `${trimSlash(tee.endpoint)}${path}`;
264-
const paidFetch = await this.buildPaidFetch(tee.dispatcher);
265+
const paidFetch = this.buildPaidFetch(tee.dispatcher);
265266

266267
let response: Response;
267268
try {

src/teeRegistry.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,20 @@ export class TEERegistry {
9393
return [];
9494
}
9595

96+
console.debug(
97+
`[TEERegistry] getActiveTEEs(type=${teeType}) returned ${teeInfos.length} entries`,
98+
);
99+
96100
const out: TEEEndpoint[] = [];
97101
for (const tee of teeInfos) {
98102
if (
99103
!tee.endpoint ||
100104
!tee.tlsCertificate ||
101105
tee.tlsCertificate === "0x"
102106
) {
107+
console.debug(
108+
`[TEERegistry] skipping TEE (endpoint=${tee.endpoint || "<empty>"}, certLen=${tee.tlsCertificate?.length ?? 0})`,
109+
);
103110
continue;
104111
}
105112
out.push({
@@ -109,6 +116,10 @@ export class TEERegistry {
109116
paymentAddress: tee.paymentAddress,
110117
});
111118
}
119+
console.debug(
120+
`[TEERegistry] ${out.length} usable TEEs:`,
121+
out.map((t) => ({ teeId: t.teeId, endpoint: t.endpoint })),
122+
);
112123
return out;
113124
}
114125

@@ -118,7 +129,14 @@ export class TEERegistry {
118129
*/
119130
async getLLMTEE(): Promise<TEEEndpoint | null> {
120131
const tees = await this.getActiveTEEsByType(TEE_TYPE_LLM_PROXY);
121-
if (tees.length === 0) return null;
122-
return tees[Math.floor(Math.random() * tees.length)];
132+
if (tees.length === 0) {
133+
console.debug("[TEERegistry] getLLMTEE: no active LLM proxy TEEs found");
134+
return null;
135+
}
136+
const picked = tees[Math.floor(Math.random() * tees.length)];
137+
console.debug(
138+
`[TEERegistry] getLLMTEE: picked ${picked.teeId} @ ${picked.endpoint}`,
139+
);
140+
return picked;
123141
}
124142
}

0 commit comments

Comments
 (0)