@circuitorg/agent-sdk 1.0.13 → 1.1.1

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 (4) hide show
  1. package/README.md +245 -2
  2. package/index.d.ts +406 -7
  3. package/index.js +1 -1
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -2,15 +2,16 @@
2
2
 
3
3
  > **Clean, type-safe TypeScript SDK for building cross-chain agents on the circuit platform**
4
4
 
5
- A TypeScript SDK for building automated agents to deploy on Circuit. Features a simple API surface with just **2 main methods** and full type safety.
5
+ A TypeScript SDK for building automated agents to deploy on Circuit. Features a simple API surface with just **3 main methods** and full type safety.
6
6
 
7
7
  > **💡 Best used with [Circuit Agents CLI](https://github.com/circuitorg/agents-cli)** - Deploy, manage, and test your agents with ease
8
8
 
9
9
  ## ✨ Features
10
10
 
11
- - **đŸŽ¯ Simple API**: Only 2 main methods - `sendLog()` and `signAndSend()`
11
+ - **đŸŽ¯ Simple API**: Only 3 main methods - `sendLog()`, `signAndSend()`, and `swidge.*` (swap/bridge)
12
12
  - **🔒 Type Safety**: Network parameter determines valid request shapes automatically
13
13
  - **🚀 Cross-Chain**: Unified interface for EVM and Solana networks
14
+ - **🌉 Cross-Chain Swaps**: Built-in Swidge integration for seamless token swaps and bridges
14
15
 
15
16
  ## 🚀 Quick Start
16
17
  ### Install the SDK
@@ -84,6 +85,248 @@ await sdk.signAndSend({
84
85
  ```
85
86
 
86
87
 
88
+ ## 🌉 Cross-Chain Swaps with Swidge
89
+
90
+ The SDK includes built-in Swidge integration for seamless cross-chain token swaps and bridges.
91
+
92
+ Swidge provides a unified interface that handles both **swapping** (exchanging tokens within the same network) and **bridging** (moving tokens across different networks) through a single, easy-to-use API. Whether you're doing a simple token swap on Ethereum or bridging assets across chains, the same quote-and-execute pattern works for everything.
93
+
94
+ ### 3. Cross-Chain Swaps & Bridges
95
+
96
+ #### Get a Quote
97
+
98
+ ```typescript
99
+ // 🌉 Bridge USDC: Polygon → Arbitrum
100
+ const bridgeQuote = await sdk.swidge.quote({
101
+ from: { network: "ethereum:137", address: request.sessionWalletAddress },
102
+ to: { network: "ethereum:42161", address: request.sessionWalletAddress },
103
+ amount: "50000000", // $50 USDC (6 decimals)
104
+ fromToken: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", // USDC on Polygon
105
+ toToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
106
+ slippage: "2.0", // 2% slippage for cross-chain (default: 0.5%)
107
+ priceImpact: "1.0" // 1% max price impact (default: 0.5%)
108
+ });
109
+
110
+ // 🔄 Swap USDC → ETH on same chain (using defaults)
111
+ const swapQuote = await sdk.swidge.quote({
112
+ from: { network: "ethereum:42161", address: request.sessionWalletAddress },
113
+ to: { network: "ethereum:42161", address: request.sessionWalletAddress },
114
+ amount: "100000000", // $100 USDC (6 decimals)
115
+ fromToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC
116
+ // toToken omitted = native ETH (default behavior)
117
+ // slippage defaults to "0.5", priceImpact defaults to "0.5"
118
+ });
119
+
120
+ if (quote.success) {
121
+ console.log(`💰 You'll receive: ${quote.data.assetRecieve.amountFormatted}`);
122
+ console.log(`💸 Total fees: ${quote.data.fees.map(f => f.name).join(", ")}`);
123
+ } else if (quote.error) {
124
+ // Check for specific error types
125
+ if (quote.error === QUOTE_RESULT.WALLET_NOT_FOUND) {
126
+ console.log("👛 Wallet not found");
127
+ } else if (quote.error === QUOTE_RESULT.WALLET_MISMATCH) {
128
+ console.log("🔐 Wallet address doesn't match session");
129
+ } else {
130
+ console.log("❓ Quote not available for this swap");
131
+ }
132
+ }
133
+ ```
134
+
135
+ #### Execute a Swap
136
+
137
+ ```typescript
138
+ // 1ī¸âƒŖ Get a quote first
139
+ let quoteRequest = {
140
+ from: { network: "ethereum:42161", address: request.sessionWalletAddress },
141
+ to: { network: "ethereum:1", address: request.sessionWalletAddress },
142
+ amount: "100000000", // $100 USDC
143
+ fromToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
144
+ priceImpact: "0.1", // Conservative price impact setting
145
+ slippage: "5.0"
146
+ };
147
+
148
+ let quote = await sdk.swidge.quote(quoteRequest);
149
+
150
+ // 2ī¸âƒŖ Handle quote failures with retry logic
151
+ if (quote.error === QUOTE_RESULT.NO_QUOTE_PROVIDED) {
152
+ console.log(`❓ Quote not available, increasing price impact and retrying...`)
153
+ // Retry with more permissive parameters
154
+ quoteRequest.priceImpact = "10.0";
155
+ quoteRequest.slippage = "10.0";
156
+ quote = await sdk.swidge.quote(quoteRequest);
157
+ }
158
+
159
+ // 3ī¸âƒŖ Execute the swap if quote succeeded
160
+ if (quote.success && quote.data) {
161
+ console.log(`💰 Expected to receive: ${quote.data.assetRecieve.amountFormatted}`);
162
+ console.log(`💸 Fees: ${quote.data.fees.map(f => `${f.name}: ${f.amountFormatted}`).join(", ")}`);
163
+
164
+ const result = await sdk.swidge.execute(quote.data);
165
+
166
+ if (result.success && result.data) {
167
+ console.log(`🎉 Status: ${result.data.status}`);
168
+
169
+ if (result.data.status === "success") {
170
+ console.log(`📤 Sent: ${result.data.in.txs[0]}`);
171
+ console.log(`đŸ“Ĩ Received: ${result.data.out.txs[0]}`);
172
+ console.log("✅ Cross-chain swap completed!");
173
+ } else if (result.data.status === "failure") {
174
+ console.log("❌ Transaction failed");
175
+ } else if (result.data.status === "refund") {
176
+ console.log("â†Šī¸ Transaction was refunded");
177
+ } else if (result.data.status === "delayed") {
178
+ console.log("⏰ Transaction is delayed");
179
+ }
180
+ } else {
181
+ console.log(`❌ Execute failed: ${result.error}`);
182
+ }
183
+ } else {
184
+ console.log(`❌ Quote failed after retry: ${quote.error}`);
185
+ return { success: false };
186
+ }
187
+ ```
188
+
189
+ ### Swidge API Reference
190
+
191
+ #### `sdk.swidge.quote(request: SwidgeQuoteRequest): Promise<SwidgeQuoteResponse>`
192
+
193
+ Get pricing and routing information for token swaps between networks or within the same network.
194
+
195
+ **Parameters:**
196
+ ```typescript
197
+ {
198
+ from: { network: SwidgeNetwork, address: string },
199
+ to: { network: SwidgeNetwork, address: string },
200
+ amount: string, // Amount in token's smallest unit
201
+ fromToken?: string, // Source token contract (omit for native tokens)
202
+ toToken?: string, // Destination token contract (omit for native tokens)
203
+ slippage?: string, // Slippage tolerance % (default: "0.5")
204
+ priceImpact?: string // Max price impact % (default: "0.5")
205
+ }
206
+ ```
207
+
208
+ **Returns:**
209
+ ```typescript
210
+ {
211
+ success: boolean,
212
+ data?: {
213
+ engine: "relay",
214
+ assetSend: {
215
+ network: SwidgeNetwork,
216
+ address: string,
217
+ token: string | null,
218
+ amount: string,
219
+ amountFormatted: string,
220
+ amountUsd: string,
221
+ // ... additional fields
222
+ },
223
+ assetRecieve: {
224
+ network: SwidgeNetwork,
225
+ address: string,
226
+ token: string | null,
227
+ amount: string,
228
+ amountFormatted: string,
229
+ amountUsd: string,
230
+ // ... additional fields
231
+ },
232
+ priceImpact: {
233
+ usd?: string,
234
+ percentage?: string
235
+ },
236
+ fees: Array<{
237
+ name: string,
238
+ amount?: string,
239
+ amountFormatted?: string,
240
+ amountUsd?: string
241
+ }>,
242
+ steps: Array<SwidgeUnsignedStep> // Transaction steps to execute
243
+ },
244
+ error?: string,
245
+ errorDetails?: {
246
+ message: string,
247
+ status?: number,
248
+ statusText?: string
249
+ }
250
+ }
251
+ ```
252
+
253
+ **Error Handling with QUOTE_RESULT:**
254
+
255
+ The SDK exports a `QUOTE_RESULT` constant that provides type-safe error checking with full IntelliSense support:
256
+
257
+ ```typescript
258
+ import { QUOTE_RESULT } from "@circuitorg/agent-sdk";
259
+
260
+ // Use QUOTE_RESULT constants instead of hardcoded strings
261
+ if (quote.error === QUOTE_RESULT.WALLET_NOT_FOUND) {
262
+ // Handle wallet not found
263
+ } else if (quote.error === QUOTE_RESULT.WALLET_MISMATCH) {
264
+ // Handle wallet mismatch
265
+ }
266
+ ```
267
+
268
+ **Possible Error Responses:**
269
+ - `QUOTE_RESULT.FOUND` - Success case (not an error)
270
+ - `QUOTE_RESULT.NO_QUOTE_PROVIDED` - Generic API error
271
+ - `QUOTE_RESULT.WALLET_NOT_FOUND` - Wallet address not found
272
+ - `QUOTE_RESULT.WALLET_MISMATCH` - From wallet does not match session wallet
273
+
274
+ #### `sdk.swidge.execute(quoteData: SwidgeExecuteRequest): Promise<SwidgeExecuteResponse>`
275
+
276
+ Execute a cross-chain swap or bridge using a complete quote from `sdk.swidge.quote()`.
277
+
278
+ Pass the entire `quote.data` object returned from `quote()` - the SDK handles all transaction signing, broadcasting, and cross-chain coordination.
279
+
280
+ **Parameters:**
281
+ ```typescript
282
+ // The complete quote.data object from sdk.swidge.quote()
283
+ {
284
+ engine: "relay",
285
+ assetSend: SwidgeQuoteAsset,
286
+ assetRecieve: SwidgeQuoteAsset,
287
+ priceImpact: SwidgePriceImpact,
288
+ fees: SwidgeFee[],
289
+ steps: SwidgeUnsignedStep[] // Contains transaction details for each step
290
+ }
291
+ ```
292
+
293
+ **Returns:**
294
+ ```typescript
295
+ {
296
+ success: boolean,
297
+ data?: {
298
+ status: "success" | "failure" | "refund" | "delayed",
299
+ in: {
300
+ network: string,
301
+ txs: string[] // Transaction hashes for sending side
302
+ },
303
+ out: {
304
+ network: string,
305
+ txs: string[] // Transaction hashes for receiving side
306
+ },
307
+ lastUpdated: number // Timestamp of last status update
308
+ },
309
+ error?: string,
310
+ errorDetails?: {
311
+ message: string,
312
+ status?: number,
313
+ statusText?: string
314
+ }
315
+ }
316
+ ```
317
+
318
+ **Execution Flow:**
319
+ 1. SDK signs and broadcasts transactions from the `steps` array
320
+ 2. Monitors cross-chain execution progress
321
+ 3. Returns final status once complete (never returns "pending" or "waiting")
322
+
323
+ **Status Meanings:**
324
+ - `"success"` - All transactions completed successfully
325
+ - `"failure"` - One or more transactions failed
326
+ - `"refund"` - Transaction was refunded (e.g., due to timeout or failure)
327
+ - `"delayed"` - Transaction is taking longer than expected but still processing
328
+
329
+
87
330
  ## 🔧 Examples
88
331
 
89
332
  ### Barebones Agent
package/index.d.ts CHANGED
@@ -33,12 +33,22 @@ type SignAndSendRequest = {
33
33
  * Standard response from signAndSend operations
34
34
  */
35
35
  type SignAndSendResponse = {
36
- /** Internal transaction ID for tracking */
37
- internalTransactionId: number;
38
- /** Transaction hash once broadcast */
39
- txHash: string;
40
- /** Optional transaction URL (explorer link) */
36
+ /** Whether the operation was successful */
37
+ success: boolean;
38
+ /** Internal transaction ID for tracking (only present on success) */
39
+ internalTransactionId?: number;
40
+ /** Transaction hash once broadcast (only present on success) */
41
+ txHash?: string;
42
+ /** Optional transaction URL (explorer link) (only present on success) */
41
43
  transactionUrl?: string;
44
+ /** Error message (only present on failure) */
45
+ error?: string;
46
+ /** Detailed error information (only present on failure) */
47
+ errorDetails?: {
48
+ message: string;
49
+ status?: number;
50
+ statusText?: string;
51
+ };
42
52
  };
43
53
  /**
44
54
  * EIP712 TypedData schema for typed message signing
@@ -136,6 +146,237 @@ interface SDKConfig {
136
146
  baseUrl?: string;
137
147
  }
138
148
 
149
+ /**
150
+ * Job status tracking types for Event invocation support
151
+ */
152
+ interface UpdateJobStatusRequest {
153
+ jobId: string;
154
+ status: "pending" | "success" | "failed";
155
+ errorMessage?: string;
156
+ }
157
+ interface UpdateJobStatusResponse {
158
+ status: number;
159
+ message: string;
160
+ }
161
+
162
+ /**
163
+ * Swidge (cross-chain swap) type definitions for agent operations
164
+ * These schemas exactly match the execution-layer-sdk for zero friction
165
+ */
166
+
167
+ declare const SwidgeQuoteRequestSchema: z.ZodObject<{
168
+ from: z.ZodObject<{
169
+ address: z.ZodString;
170
+ network: z.ZodUnion<readonly [z.ZodLiteral<"solana">, z.ZodTemplateLiteral<`ethereum:${number}`>]>;
171
+ }, z.core.$strip>;
172
+ to: z.ZodObject<{
173
+ address: z.ZodString;
174
+ network: z.ZodUnion<readonly [z.ZodLiteral<"solana">, z.ZodTemplateLiteral<`ethereum:${number}`>]>;
175
+ }, z.core.$strip>;
176
+ fromToken: z.ZodOptional<z.ZodString>;
177
+ toToken: z.ZodOptional<z.ZodString>;
178
+ amount: z.ZodString;
179
+ priceImpact: z.ZodOptional<z.ZodString>;
180
+ slippage: z.ZodOptional<z.ZodString>;
181
+ }, z.core.$strip>;
182
+ type SwidgeQuoteRequest = z.infer<typeof SwidgeQuoteRequestSchema>;
183
+ /**
184
+ * Execute request schema - takes the complete quote response from quote() method
185
+ */
186
+ declare const SwidgeExecuteRequestSchema: z.ZodObject<{
187
+ engine: z.ZodLiteral<"relay">;
188
+ assetSend: z.ZodObject<{
189
+ network: z.ZodUnion<readonly [z.ZodLiteral<"solana">, z.ZodTemplateLiteral<`ethereum:${number}`>]>;
190
+ address: z.ZodString;
191
+ token: z.ZodNullable<z.ZodString>;
192
+ name: z.ZodOptional<z.ZodString>;
193
+ symbol: z.ZodOptional<z.ZodString>;
194
+ decimals: z.ZodOptional<z.ZodNumber>;
195
+ amount: z.ZodOptional<z.ZodString>;
196
+ minimumAmount: z.ZodOptional<z.ZodString>;
197
+ amountFormatted: z.ZodOptional<z.ZodString>;
198
+ amountUsd: z.ZodOptional<z.ZodString>;
199
+ }, z.core.$strip>;
200
+ assetRecieve: z.ZodObject<{
201
+ network: z.ZodUnion<readonly [z.ZodLiteral<"solana">, z.ZodTemplateLiteral<`ethereum:${number}`>]>;
202
+ address: z.ZodString;
203
+ token: z.ZodNullable<z.ZodString>;
204
+ name: z.ZodOptional<z.ZodString>;
205
+ symbol: z.ZodOptional<z.ZodString>;
206
+ decimals: z.ZodOptional<z.ZodNumber>;
207
+ amount: z.ZodOptional<z.ZodString>;
208
+ minimumAmount: z.ZodOptional<z.ZodString>;
209
+ amountFormatted: z.ZodOptional<z.ZodString>;
210
+ amountUsd: z.ZodOptional<z.ZodString>;
211
+ }, z.core.$strip>;
212
+ priceImpact: z.ZodObject<{
213
+ usd: z.ZodOptional<z.ZodString>;
214
+ percentage: z.ZodOptional<z.ZodString>;
215
+ }, z.core.$strip>;
216
+ fees: z.ZodArray<z.ZodObject<{
217
+ name: z.ZodString;
218
+ amount: z.ZodOptional<z.ZodString>;
219
+ amountFormatted: z.ZodOptional<z.ZodString>;
220
+ amountUsd: z.ZodOptional<z.ZodString>;
221
+ }, z.core.$strip>>;
222
+ steps: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
223
+ type: z.ZodLiteral<"transaction">;
224
+ description: z.ZodString;
225
+ transactionDetails: z.ZodUnion<readonly [z.ZodObject<{
226
+ type: z.ZodLiteral<"evm">;
227
+ from: z.ZodString;
228
+ to: z.ZodString;
229
+ chainId: z.ZodNumber;
230
+ value: z.ZodNumber;
231
+ data: z.ZodString;
232
+ gas: z.ZodNumber;
233
+ maxFeePerGas: z.ZodNumber;
234
+ maxPriorityFeePerGas: z.ZodNumber;
235
+ }, z.core.$strip>, z.ZodObject<{
236
+ type: z.ZodLiteral<"solana">;
237
+ instructions: z.ZodArray<z.ZodObject<{
238
+ programId: z.ZodString;
239
+ keys: z.ZodArray<z.ZodObject<{
240
+ pubkey: z.ZodString;
241
+ isSigner: z.ZodBoolean;
242
+ isWritable: z.ZodBoolean;
243
+ }, z.core.$strip>>;
244
+ data: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>]>;
245
+ }, z.core.$strip>>;
246
+ addressLookupTableAddresses: z.ZodArray<z.ZodString>;
247
+ }, z.core.$strip>]>;
248
+ metadata: z.ZodRecord<z.ZodString, z.ZodString>;
249
+ }, z.core.$strip>, z.ZodObject<{
250
+ type: z.ZodLiteral<"signature">;
251
+ description: z.ZodString;
252
+ signatureData: z.ZodString;
253
+ metadata: z.ZodRecord<z.ZodString, z.ZodString>;
254
+ }, z.core.$strip>], "type">>;
255
+ }, z.core.$strip>;
256
+ /**
257
+ * Quote result constants - type QUOTE_RESULT. to see available options
258
+ * These match the exact error strings returned by the swidge API
259
+ */
260
+ declare const QUOTE_RESULT: {
261
+ readonly FOUND: "QUOTE_FOUND";
262
+ readonly NO_QUOTE_PROVIDED: "No quote provided";
263
+ readonly WALLET_NOT_FOUND: "Wallet not found";
264
+ readonly WALLET_MISMATCH: "From wallet does not match session wallet";
265
+ };
266
+ /**
267
+ * Type for quote result values
268
+ */
269
+ type SwidgeQuoteResult = (typeof QUOTE_RESULT)[keyof typeof QUOTE_RESULT];
270
+ /**
271
+ * Swidge quote response wrapper
272
+ */
273
+ declare const SwidgeQuoteResponseWrapperSchema: z.ZodObject<{
274
+ success: z.ZodBoolean;
275
+ data: z.ZodOptional<z.ZodObject<{
276
+ engine: z.ZodLiteral<"relay">;
277
+ assetSend: z.ZodObject<{
278
+ network: z.ZodUnion<readonly [z.ZodLiteral<"solana">, z.ZodTemplateLiteral<`ethereum:${number}`>]>;
279
+ address: z.ZodString;
280
+ token: z.ZodNullable<z.ZodString>;
281
+ name: z.ZodOptional<z.ZodString>;
282
+ symbol: z.ZodOptional<z.ZodString>;
283
+ decimals: z.ZodOptional<z.ZodNumber>;
284
+ amount: z.ZodOptional<z.ZodString>;
285
+ minimumAmount: z.ZodOptional<z.ZodString>;
286
+ amountFormatted: z.ZodOptional<z.ZodString>;
287
+ amountUsd: z.ZodOptional<z.ZodString>;
288
+ }, z.core.$strip>;
289
+ assetRecieve: z.ZodObject<{
290
+ network: z.ZodUnion<readonly [z.ZodLiteral<"solana">, z.ZodTemplateLiteral<`ethereum:${number}`>]>;
291
+ address: z.ZodString;
292
+ token: z.ZodNullable<z.ZodString>;
293
+ name: z.ZodOptional<z.ZodString>;
294
+ symbol: z.ZodOptional<z.ZodString>;
295
+ decimals: z.ZodOptional<z.ZodNumber>;
296
+ amount: z.ZodOptional<z.ZodString>;
297
+ minimumAmount: z.ZodOptional<z.ZodString>;
298
+ amountFormatted: z.ZodOptional<z.ZodString>;
299
+ amountUsd: z.ZodOptional<z.ZodString>;
300
+ }, z.core.$strip>;
301
+ priceImpact: z.ZodObject<{
302
+ usd: z.ZodOptional<z.ZodString>;
303
+ percentage: z.ZodOptional<z.ZodString>;
304
+ }, z.core.$strip>;
305
+ fees: z.ZodArray<z.ZodObject<{
306
+ name: z.ZodString;
307
+ amount: z.ZodOptional<z.ZodString>;
308
+ amountFormatted: z.ZodOptional<z.ZodString>;
309
+ amountUsd: z.ZodOptional<z.ZodString>;
310
+ }, z.core.$strip>>;
311
+ steps: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
312
+ type: z.ZodLiteral<"transaction">;
313
+ description: z.ZodString;
314
+ transactionDetails: z.ZodUnion<readonly [z.ZodObject<{
315
+ type: z.ZodLiteral<"evm">;
316
+ from: z.ZodString;
317
+ to: z.ZodString;
318
+ chainId: z.ZodNumber;
319
+ value: z.ZodNumber;
320
+ data: z.ZodString;
321
+ gas: z.ZodNumber;
322
+ maxFeePerGas: z.ZodNumber;
323
+ maxPriorityFeePerGas: z.ZodNumber;
324
+ }, z.core.$strip>, z.ZodObject<{
325
+ type: z.ZodLiteral<"solana">;
326
+ instructions: z.ZodArray<z.ZodObject<{
327
+ programId: z.ZodString;
328
+ keys: z.ZodArray<z.ZodObject<{
329
+ pubkey: z.ZodString;
330
+ isSigner: z.ZodBoolean;
331
+ isWritable: z.ZodBoolean;
332
+ }, z.core.$strip>>;
333
+ data: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>]>;
334
+ }, z.core.$strip>>;
335
+ addressLookupTableAddresses: z.ZodArray<z.ZodString>;
336
+ }, z.core.$strip>]>;
337
+ metadata: z.ZodRecord<z.ZodString, z.ZodString>;
338
+ }, z.core.$strip>, z.ZodObject<{
339
+ type: z.ZodLiteral<"signature">;
340
+ description: z.ZodString;
341
+ signatureData: z.ZodString;
342
+ metadata: z.ZodRecord<z.ZodString, z.ZodString>;
343
+ }, z.core.$strip>], "type">>;
344
+ }, z.core.$strip>>;
345
+ error: z.ZodOptional<z.ZodString>;
346
+ errorDetails: z.ZodOptional<z.ZodObject<{
347
+ message: z.ZodString;
348
+ status: z.ZodOptional<z.ZodNumber>;
349
+ statusText: z.ZodOptional<z.ZodString>;
350
+ }, z.core.$strip>>;
351
+ }, z.core.$strip>;
352
+ /**
353
+ * Swidge execute response wrapper
354
+ */
355
+ declare const SwidgeExecuteResponseWrapperSchema: z.ZodObject<{
356
+ success: z.ZodBoolean;
357
+ data: z.ZodOptional<z.ZodObject<{
358
+ status: z.ZodUnion<readonly [z.ZodLiteral<"success">, z.ZodLiteral<"failure">, z.ZodLiteral<"refund">, z.ZodLiteral<"delayed">]>;
359
+ in: z.ZodObject<{
360
+ network: z.ZodString;
361
+ txs: z.ZodArray<z.ZodString>;
362
+ }, z.core.$strip>;
363
+ out: z.ZodObject<{
364
+ network: z.ZodString;
365
+ txs: z.ZodArray<z.ZodString>;
366
+ }, z.core.$strip>;
367
+ lastUpdated: z.ZodNumber;
368
+ }, z.core.$strip>>;
369
+ error: z.ZodOptional<z.ZodString>;
370
+ errorDetails: z.ZodOptional<z.ZodObject<{
371
+ message: z.ZodString;
372
+ status: z.ZodOptional<z.ZodNumber>;
373
+ statusText: z.ZodOptional<z.ZodString>;
374
+ }, z.core.$strip>>;
375
+ }, z.core.$strip>;
376
+ type SwidgeQuoteResponse = z.infer<typeof SwidgeQuoteResponseWrapperSchema>;
377
+ type SwidgeExecuteRequest = z.infer<typeof SwidgeExecuteRequestSchema>;
378
+ type SwidgeExecuteResponse = z.infer<typeof SwidgeExecuteResponseWrapperSchema>;
379
+
139
380
  /**
140
381
  * Main AgentSdk class with simplified API surface
141
382
  */
@@ -279,6 +520,132 @@ declare class AgentSdk {
279
520
  * ```
280
521
  */
281
522
  signMessage(request: SignMessageRequest): Promise<SignMessageResponse>;
523
+ /**
524
+ * 🌉 Swidge: Cross-chain swaps & bridges made simple
525
+ *
526
+ * Bridge assets between chains or swap tokens on the same network. Supports all major
527
+ * EVM chains (Ethereum, Arbitrum, Polygon, etc.) and Solana with automatic routing,
528
+ * and competitive fees.
529
+ *
530
+ */
531
+ readonly swidge: {
532
+ /**
533
+ * 🌉 Get a cross-chain swap or bridge quote
534
+ *
535
+ * Get pricing and routing info for swapping tokens between networks or within the same network.
536
+ * Perfect for bridging assets across chains or swapping tokens on the same chain.
537
+ *
538
+ * âš ī¸ **Important Notes:**
539
+ * - **Small amounts may fail**: Use at least $10-20 worth to avoid fee/slippage issues
540
+ * - **Slippage matters**: Default is 0.5% for most cases, increase to 1-2% for volatile pairs
541
+ * - **Different networks = bridge**: Same network = swap
542
+ * - **Native tokens**: Omit `fromToken`/`toToken` for ETH, SOL, etc.
543
+ *
544
+ * @param request Quote parameters
545
+ * @param request.from Source wallet `{ network, address }`
546
+ * @param request.to Destination wallet `{ network, address }`
547
+ * @param request.amount Amount in token's smallest unit (wei for ETH, lamports for SOL)
548
+ * @param request.fromToken Source token contract address (optional, omit for native tokens like ETH/SOL)
549
+ * @param request.toToken Destination token contract address (optional, omit for native tokens like ETH/SOL)
550
+ * @param request.slippage Slippage tolerance % as string (e.g., "2.0" = 2%, default: "0.5")
551
+ * @param request.priceImpact Max price impact % as string (e.g., "1.0" = 1%, default: "0.5")
552
+ * @returns Quote with fees, price impact, and transaction steps
553
+ *
554
+ * @example
555
+ * ```ts
556
+ * // 🌉 Bridge USDC: Polygon → Arbitrum
557
+ * const bridgeQuote = await sdk.swidge.quote({
558
+ * from: { network: "ethereum:137", address: request.sessionWalletAddress },
559
+ * to: { network: "ethereum:42161", address: request.sessionWalletAddress },
560
+ * amount: "50000000", // $50 USDC (6 decimals)
561
+ * fromToken: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", // USDC on Polygon
562
+ * toToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
563
+ * slippage: "2.0", // 2% slippage for cross-chain (default: 0.5%)
564
+ * priceImpact: "1.0" // 1% max price impact (default: 0.5%)
565
+ * });
566
+ *
567
+ * // 🔄 Swap USDC → ETH on same chain (using defaults)
568
+ * const swapQuote = await sdk.swidge.quote({
569
+ * from: { network: "ethereum:42161", address: request.sessionWalletAddress },
570
+ * to: { network: "ethereum:42161", address: request.sessionWalletAddress },
571
+ * amount: "100000000", // $100 USDC (6 decimals)
572
+ * fromToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC
573
+ * // toToken omitted = native ETH (default behavior)
574
+ * // slippage defaults to "0.5", priceImpact defaults to "0.5"
575
+ * });
576
+ *
577
+ * if (quote.success) {
578
+ * console.log(`💰 You'll receive: ${quote.data.assetRecieve.amountFormatted}`);
579
+ * console.log(`💸 Total fees: ${quote.data.fees.map(f => f.name).join(", ")}`);
580
+ * } else if (quote.error) {
581
+ * // Check for specific error types
582
+ * if (quote.error === QUOTE_RESULT.WALLET_NOT_FOUND) {
583
+ * console.log("👛 Wallet not found");
584
+ * } else if (quote.error === QUOTE_RESULT.WALLET_MISMATCH) {
585
+ * console.log("🔐 Wallet address doesn't match session");
586
+ * } else {
587
+ * console.log("❓ Quote not available for this swap");
588
+ * }
589
+ * }
590
+ * ```
591
+ */
592
+ quote: (request: SwidgeQuoteRequest) => Promise<SwidgeQuoteResponse>;
593
+ /**
594
+ * 🚀 Execute a cross-chain swap or bridge
595
+ *
596
+ * Takes your quote and makes it happen! Just pass the complete quote object from
597
+ * `sdk.swidge.quote()` and let the magic happen. Signs transactions, broadcasts them,
598
+ * and waits for completion.
599
+ *
600
+ * âš ī¸ **What happens:**
601
+ * - Signs transactions using your wallet's policy engine
602
+ * - Broadcasts to the blockchain(s)
603
+ * - Waits for cross-chain completion (this may take some time depending on network status)
604
+ * - Returns final status with transaction hashes
605
+ *
606
+ * 💡 **Pro tip**: The backend handles all the complexity - you just pass the quote!
607
+ *
608
+ * @param quote Complete quote object from `sdk.swidge.quote()`
609
+ * @returns Execution result with status and transaction details
610
+ *
611
+ * @example
612
+ * ```ts
613
+ * // 1ī¸âƒŖ Get a quote first
614
+ * const quote = await sdk.swidge.quote({
615
+ * from: { network: "ethereum:137", address: request.sessionWalletAddress },
616
+ * to: { network: "ethereum:42161", address: request.sessionWalletAddress },
617
+ * amount: "50000000", // $50 USDC
618
+ * fromToken: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
619
+ * toToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
620
+ * slippage: "2.0", // priceImpact defaults to "0.5"
621
+ * });
622
+ *
623
+ * // 2ī¸âƒŖ Execute the swap
624
+ * if (quote.success && quote.data) {
625
+ * const result = await sdk.swidge.execute(quote.data);
626
+ *
627
+ * if (result.success && result.data) {
628
+ * console.log(`🎉 Status: ${result.data.status}`);
629
+ *
630
+ * if (result.data.status === "success") {
631
+ * console.log(`📤 Sent: ${result.data.in.txs[0]}`);
632
+ * console.log(`đŸ“Ĩ Received: ${result.data.out.txs[0]}`);
633
+ * console.log("✅ Cross-chain swap completed!");
634
+ * } else if (result.data.status === "failure") {
635
+ * console.log("❌ Transaction failed");
636
+ * } else if (result.data.status === "refund") {
637
+ * console.log("â†Šī¸ Transaction was refunded");
638
+ * } else if (result.data.status === "delayed") {
639
+ * console.log("⏰ Transaction is delayed");
640
+ * }
641
+ * } else {
642
+ * console.log(`❌ Execute failed: ${result.error}`);
643
+ * }
644
+ * }
645
+ * ```
646
+ */
647
+ execute: (executeQuote: SwidgeExecuteRequest) => Promise<SwidgeExecuteResponse>;
648
+ };
282
649
  /**
283
650
  * Handle EVM transaction signing and broadcasting
284
651
  */
@@ -295,6 +662,21 @@ declare class AgentSdk {
295
662
  * Send logs to the agent timeline (migrated from AgentToolset)
296
663
  */
297
664
  private _sendLog;
665
+ /**
666
+ * Internal method to update job status. Used by the Agent wrapper for automatic tracking.
667
+ *
668
+ * This method is not intended for direct use by agent developers - job status tracking
669
+ * is handled automatically by the Agent wrapper.
670
+ */
671
+ _updateJobStatus(request: UpdateJobStatusRequest): Promise<UpdateJobStatusResponse>;
672
+ /**
673
+ * Handle swidge quote requests
674
+ */
675
+ private handleSwidgeQuote;
676
+ /**
677
+ * Handle swidge execute requests
678
+ */
679
+ private handleSwidgeExecute;
298
680
  }
299
681
 
300
682
  /**
@@ -326,6 +708,10 @@ declare class APIClient {
326
708
  private getAuthHeaders;
327
709
  private loadAuthConfig;
328
710
  private logging;
711
+ /**
712
+ * Mask sensitive headers and filter out noise headers for logging
713
+ */
714
+ private sanitizeHeaders;
329
715
  /**
330
716
  * Perform a JSON HTTP request.
331
717
  *
@@ -358,6 +744,7 @@ declare class APIClient {
358
744
  declare const AgentRequestSchema: z.ZodObject<{
359
745
  sessionId: z.ZodNumber;
360
746
  sessionWalletAddress: z.ZodString;
747
+ jobId: z.ZodOptional<z.ZodString>;
361
748
  otherParameters: z.ZodOptional<z.ZodObject<{}, z.core.$strip>>;
362
749
  }, z.core.$strip>;
363
750
  /**
@@ -505,7 +892,7 @@ interface AgentConfig {
505
892
  *
506
893
  * Exposes the following endpoints:
507
894
  * - `POST /execute` — required, calls your execution function
508
- * - `POST /stop` and `DELETE /` — optional, when a `stopFunction` is provided
895
+ * - `POST /stop` — always available, uses provided or default stop function
509
896
  * - `GET /health` — always available, uses provided or default health check
510
897
  */
511
898
  declare class Agent {
@@ -518,6 +905,18 @@ declare class Agent {
518
905
  * @param config - Execution function is required; chat/stop/health are optional.
519
906
  */
520
907
  constructor(config: AgentConfig);
908
+ /**
909
+ * Default stop function when no custom stop function is provided.
910
+ */
911
+ private defaultStopFunction;
912
+ /**
913
+ * Execute a function with automatic job status tracking.
914
+ */
915
+ private executeWithJobTracking;
916
+ /**
917
+ * Update job status using the AgentSdk.
918
+ */
919
+ private updateJobStatus;
521
920
  private setupRoutes;
522
921
  private getPortFromPackageJson;
523
922
  run(port?: number): {
@@ -552,4 +951,4 @@ declare function isSolanaNetwork(network: Network): network is "solana";
552
951
  */
553
952
  declare function getChainIdFromNetwork(network: `ethereum:${number}`): number;
554
953
 
555
- export { APIClient, Agent, AgentSdk, type ExecutionFunctionContract, type Network, type SDKConfig, type SignAndSendRequest, type SignAndSendResponse, type SignMessageRequest, type SignMessageResponse, type StopFunctionContract, getChainIdFromNetwork, isEthereumNetwork, isSolanaNetwork };
954
+ export { APIClient, Agent, AgentSdk, type ExecutionFunctionContract, type Network, QUOTE_RESULT, type SDKConfig, type SignAndSendRequest, type SignAndSendResponse, type SignMessageRequest, type SignMessageResponse, type StopFunctionContract, type SwidgeExecuteResponse, type SwidgeQuoteRequest, type SwidgeQuoteResponse, type SwidgeQuoteResult, getChainIdFromNetwork, isEthereumNetwork, isSolanaNetwork };
package/index.js CHANGED
@@ -1 +1 @@
1
- var __getOwnPropNames=Object.getOwnPropertyNames,__require=(t=>"undefined"!=typeof require?require:"undefined"!=typeof Proxy?new Proxy(t,{get:(t,e)=>("undefined"!=typeof require?require:t)[e]}):t)(function(t){if("undefined"!=typeof require)return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')}),__commonJS=(t,e)=>function(){return e||(0,t[__getOwnPropNames(t)[0]])((e={exports:{}}).exports,e),e.exports},require_auth_loader=__commonJS({"src/utils/auth-loader.cjs"(exports,module){function loadAuthFromFileSystem(){try{if("undefined"==typeof process)return;const fs=eval("require")("fs"),path=eval("require")("path"),os=eval("require")("os"),homeDir=os.homedir();let authPath=path.join(homeDir,".config","circuit","auth.json");if(!fs.existsSync(authPath)&&(authPath=path.join(homeDir,".circuit","auth.json"),!fs.existsSync(authPath)))return;const authContent=fs.readFileSync(authPath,"utf-8");return JSON.parse(authContent)}catch(t){return}}module.exports={loadAuthFromFileSystem:loadAuthFromFileSystem}}}),API_BASE_URL_LOCAL="https://agents.circuit.org",APIClient=class{config;baseUrl;isCloudflareWorker(){return"undefined"!=typeof globalThis&&void 0!==globalThis.Cloudflare}hasServiceBinding(){let t=!1;return this.isCloudflareWorker()&&(void 0!==globalThis.AGENTS_TO_API_PROXY||void 0!==globalThis.__AGENT_ENV__&&globalThis.__AGENT_ENV__?.AGENTS_TO_API_PROXY)&&(t=!0),this.config.verbose,t}constructor(t){this.config=t,this.baseUrl=t.baseUrl||API_BASE_URL_LOCAL}getAgentSlug(){return"undefined"!=typeof process&&process.env?.CIRCUIT_AGENT_SLUG?process.env.CIRCUIT_AGENT_SLUG:void 0!==globalThis.CIRCUIT_AGENT_SLUG?globalThis.CIRCUIT_AGENT_SLUG:void 0}getAuthHeaders(){const t={};t["X-Session-Id"]=this.config.sessionId.toString();const e=this.getAgentSlug();if(e&&(t["X-Agent-Slug"]=e),!this.hasServiceBinding())try{const e=this.loadAuthConfig();e?.sessionToken&&(t.Authorization=`Bearer ${e.sessionToken}`)}catch(t){}return t}loadAuthConfig(){try{const{loadAuthFromFileSystem:t}=require_auth_loader();return t()}catch(t){this.config.verbose}}logging(t,e){this.config.verbose}async makeRequest(t,e={}){const s={...{"Content-Type":"application/json",...this.getAuthHeaders()},...e.headers};let r;if(this.logging("=== REQUEST DETAILS ==="),this.logging("Endpoint:",t),this.logging("Method:",e.method||"GET"),this.logging("Headers:",s),this.logging("Body:",e.body),this.logging("Session ID:",this.config.sessionId),this.logging("Agent Slug:",this.getAgentSlug()||"not set"),this.logging("Using Service Binding:",this.hasServiceBinding()),this.logging("====================="),this.hasServiceBinding()){let n;if(void 0!==globalThis.AGENTS_TO_API_PROXY)n=globalThis.AGENTS_TO_API_PROXY;else{if(void 0===globalThis.__AGENT_ENV__||!globalThis.__AGENT_ENV__?.AGENTS_TO_API_PROXY)throw new Error("Service binding detected but not accessible");n=globalThis.__AGENT_ENV__.AGENTS_TO_API_PROXY}this.logging("Using service binding AGENTS_TO_API_PROXY"),this.logging("Service binding type:",typeof n);const o={...e,headers:s},i=`https://agents-to-api-proxy.circuit-0bc.workers.dev${t}`;r=await n.fetch(i,o)}else{this.logging("Using HTTP fallback to:",this.baseUrl);const n=`${this.baseUrl}${t}`,o={...e,headers:s};r=await fetch(n,o)}if(this.logging("=== RESPONSE DETAILS ==="),this.logging("Status:",r.status),this.logging("Status Text:",r.statusText),this.logging("Response Headers:",Object.fromEntries(r.headers.entries())),this.logging("======================"),!r.ok){const t=await r.json().catch(()=>({}));throw this.logging("=== ERROR RESPONSE ==="),this.logging("Error Data:",t),this.logging("===================="),new Error(t.message||`HTTP ${r.status}: ${r.statusText}`)}const n=await r.json();return this.logging("=== SUCCESS RESPONSE ==="),this.logging("Response Data:",n),this.logging("======================"),n}async get(t){return this.makeRequest(t,{method:"GET"})}async post(t,e){return this.makeRequest(t,{method:"POST",body:e?JSON.stringify(e):void 0})}};function isEthereumNetwork(t){return t.startsWith("ethereum:")}function isSolanaNetwork(t){return"solana"===t}function getChainIdFromNetwork(t){return Number(t.split(":")[1])}var AgentSdk=class{client;config;constructor(t){this.config=t,this.client=new APIClient(t)}logging(t,e){this.config.verbose}async sendLog(t){this.logging("=== ADD MESSAGE ==="),this.logging("Message:",t),this.logging("==================="),await this.t([t])}async signAndSend(t){if(this.logging("=== SIGN AND SEND ==="),this.logging("Request:",t),this.logging("Testing mode:",this.config.testing),this.logging("===================="),this.config.testing)return{internalTransactionId:123,txHash:isEthereumNetwork(t.network)?"0xTEST":"TEST_SOL_TX",transactionUrl:void 0};if(isEthereumNetwork(t.network)){const e=getChainIdFromNetwork(t.network);if("toAddress"in t.request)return this.handleEvmTransaction({chainId:e,toAddress:t.request.toAddress,data:t.request.data,valueWei:t.request.value,message:t.message})}if(isSolanaNetwork(t.network)&&"hexTransaction"in t.request)return this.handleSolanaTransaction({hexTransaction:t.request.hexTransaction,message:t.message});throw new Error(`Unsupported network: ${t.network}`)}async signMessage(t){if(this.logging("=== SIGN MESSAGE ==="),this.logging("Request:",t),this.logging("Testing mode:",this.config.testing),this.logging("===================="),this.config.testing)return{v:27,r:"0xTEST_R",s:"0xTEST_S",formattedSignature:"0xTEST_FORMATTED",type:"evm"};if(isEthereumNetwork(t.network))return this.handleEvmSignMessage(t);throw new Error(`Unsupported network: ${t.network}`)}async handleEvmTransaction(t){const e=await this.client.post("/v1/transactions/evm",t),s=await this.client.post(`/v1/transactions/evm/${e.internalTransactionId}/broadcast`);return{internalTransactionId:e.internalTransactionId,txHash:s.txHash,transactionUrl:s.transactionUrl}}async handleSolanaTransaction(t){const e=await this.client.post("/v1/transactions/solana",t),s=await this.client.post(`/v1/transactions/solana/${e.internalTransactionId}/broadcast`);return{internalTransactionId:e.internalTransactionId,txHash:s.txHash,transactionUrl:s.transactionUrl}}async handleEvmSignMessage(t){return await this.client.post("/v1/messages/evm",{messageType:t.request.messageType,data:t.request.data,chainId:t.request.chainId})}async t(t){return this.config.testing?{status:200,message:"Logs added successfully (TESTING)"}:this.client.post("/v1/logs",t)}};import{zValidator}from"@hono/zod-validator";import{Hono}from"hono";import{cors}from"hono/cors";import{z}from"zod";var AgentRequestSchema=z.object({sessionId:z.number(),sessionWalletAddress:z.string(),otherParameters:z.object().optional()}),AgentResponseSchema=z.object({success:z.boolean(),error:z.string().optional(),message:z.string().optional()}),HealthResponseSchema=z.object({status:z.string()}),Agent=class{app;executionFunction;stopFunction;healthCheckFunction;constructor(t){this.app=new Hono,this.executionFunction=t.executionFunction,this.stopFunction=t.stopFunction,this.healthCheckFunction=t.healthCheckFunction||(async()=>({status:"healthy"})),this.app.use("*",cors()),this.setupRoutes()}setupRoutes(){this.app.post("/execute",zValidator("json",AgentRequestSchema),async t=>{try{const e=t.req.valid("json"),s=await this.executionFunction(e);return t.json(s)}catch(e){return t.json({success:!1,error:e instanceof Error?e.message:"Unknown error",message:"Execution failed"},500)}}),this.stopFunction&&(this.app.post("/stop",zValidator("json",AgentRequestSchema),async t=>{try{const e=t.req.valid("json"),s=await(this.stopFunction?.(e));return t.json(s)}catch(e){return t.json({success:!1,error:e instanceof Error?e.message:"Unknown error",message:"Stop operation failed"},500)}}),this.app.delete("/",zValidator("json",AgentRequestSchema),async t=>{try{const e=t.req.valid("json"),s=await(this.stopFunction?.(e));return t.json(s)}catch(e){return t.json({success:!1,error:e instanceof Error?e.message:"Unknown error",message:"Stop operation failed"},500)}})),this.app.get("/health",async t=>{try{const e=await(this.healthCheckFunction?.());return t.json(e)}catch(e){return t.json({status:"unhealthy",error:e instanceof Error?e.message:"Unknown error",timestamp:(new Date).toISOString()},500)}})}getPortFromPackageJson(){try{const t=__require("fs"),e=__require("path").join(process.cwd(),"package.json");if(t.existsSync(e)){const s=JSON.parse(t.readFileSync(e,"utf-8"));if(s.circuit?.port)return Number.parseInt(s.circuit.port,10)}}catch(t){}return null}run(port){const isCloudflareWorker="undefined"!=typeof globalThis&&void 0!==globalThis.Cloudflare;if(isCloudflareWorker)return this.getWorkerExport();const bunEnv=globalThis.Bun?.env,envPort=process.env.AGENT_PORT||bunEnv?.AGENT_PORT,packageJsonPort=this.getPortFromPackageJson();let finalPort=port;!finalPort&&envPort&&(finalPort=Number.parseInt(envPort,10)),!finalPort&&packageJsonPort&&(finalPort=packageJsonPort),finalPort||(finalPort=3e3);try{const req=eval("require"),{serve:serve}=req("@hono/node-server");serve({fetch:this.app.fetch,port:finalPort})}catch(t){process.exit(1)}}getWorkerExport(){return{fetch:async(t,e,s)=>(e&&"undefined"!=typeof globalThis&&(globalThis.__AGENT_ENV__=e),this.app.fetch(t,e,s))}}};function createAgentHandler(t,e,s){return new Agent({executionFunction:t,stopFunction:e,healthCheckFunction:s})}export{APIClient,Agent,AgentSdk,getChainIdFromNetwork,isEthereumNetwork,isSolanaNetwork};
1
+ var __getOwnPropNames=Object.getOwnPropertyNames,__require=(t=>"undefined"!=typeof require?require:"undefined"!=typeof Proxy?new Proxy(t,{get:(t,e)=>("undefined"!=typeof require?require:t)[e]}):t)(function(t){if("undefined"!=typeof require)return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')}),__commonJS=(t,e)=>function(){return e||(0,t[__getOwnPropNames(t)[0]])((e={exports:{}}).exports,e),e.exports},require_auth_loader=__commonJS({"src/utils/auth-loader.cjs"(exports,module){function loadAuthFromFileSystem(){try{if("undefined"==typeof process)return;const fs=eval("require")("fs"),path=eval("require")("path"),os=eval("require")("os"),homeDir=os.homedir();let authPath=path.join(homeDir,".config","circuit","auth.json");if(!fs.existsSync(authPath)&&(authPath=path.join(homeDir,".circuit","auth.json"),!fs.existsSync(authPath)))return;const authContent=fs.readFileSync(authPath,"utf-8");return JSON.parse(authContent)}catch(t){return}}module.exports={loadAuthFromFileSystem:loadAuthFromFileSystem}}}),API_BASE_URL_LOCAL="https://agents.circuit.org",APIClient=class{config;baseUrl;isCloudflareWorker(){return"undefined"!=typeof globalThis&&void 0!==globalThis.Cloudflare}hasServiceBinding(){let t=!1;return this.isCloudflareWorker()&&(void 0!==globalThis.AGENTS_TO_API_PROXY||void 0!==globalThis.__AGENT_ENV__&&globalThis.__AGENT_ENV__?.AGENTS_TO_API_PROXY)&&(t=!0),this.config.verbose,t}constructor(t){this.config=t,this.baseUrl=t.baseUrl||API_BASE_URL_LOCAL}getAgentSlug(){return"undefined"!=typeof process&&process.env?.CIRCUIT_AGENT_SLUG?process.env.CIRCUIT_AGENT_SLUG:void 0!==globalThis.CIRCUIT_AGENT_SLUG?globalThis.CIRCUIT_AGENT_SLUG:void 0}getAuthHeaders(){const t={};t["X-Session-Id"]=this.config.sessionId.toString();const e=this.getAgentSlug();if(e&&(t["X-Agent-Slug"]=e),!this.hasServiceBinding())try{const e=this.loadAuthConfig();e?.sessionToken&&(t.Authorization=`Bearer ${e.sessionToken}`)}catch(t){}return t}loadAuthConfig(){try{const{loadAuthFromFileSystem:t}=require_auth_loader();return t()}catch(t){this.config.verbose}}logging(t,e){this.config.verbose}sanitizeHeaders(t){const e={},s=new Set(["report-to","server-timing","server"]),r=t&&"object"==typeof t?t:{};for(const[t,a]of Object.entries(r)){if("string"!=typeof a)continue;const r=t.toLowerCase();s.has(r)||(e[t]="authorization"===r?a.startsWith("Bearer ")?`Bearer ${a.slice(7,14)}***`:"***":a)}return e}async makeRequest(t,e={}){const s={...{"Content-Type":"application/json",...this.getAuthHeaders()},...e.headers};let r;if(this.logging("=== REQUEST DETAILS ==="),this.logging("Endpoint:",t),this.logging("Method:",e.method||"GET"),this.logging("Headers:",this.sanitizeHeaders(s)),this.logging("Body:",e.body),this.logging("Session ID:",this.config.sessionId),this.logging("Agent Slug:",this.getAgentSlug()||"not set"),this.logging("Using Service Binding:",this.hasServiceBinding()),this.logging("====================="),this.hasServiceBinding()){let a;if(void 0!==globalThis.AGENTS_TO_API_PROXY)a=globalThis.AGENTS_TO_API_PROXY;else{if(void 0===globalThis.__AGENT_ENV__||!globalThis.__AGENT_ENV__?.AGENTS_TO_API_PROXY)throw new Error("Service binding detected but not accessible");a=globalThis.__AGENT_ENV__.AGENTS_TO_API_PROXY}this.logging("Using service binding AGENTS_TO_API_PROXY"),this.logging("Service binding type:",typeof a);const i={...e,headers:s},n=`https://agents-to-api-proxy.circuit-0bc.workers.dev${t}`;r=await a.fetch(n,i)}else{this.logging("Using HTTP fallback to:",this.baseUrl);const a=`${this.baseUrl}${t}`,i={...e,headers:s};r=await fetch(a,i)}if(this.logging("=== RESPONSE DETAILS ==="),this.logging("Status:",r.status),this.logging("Status Text:",r.statusText),this.logging("Response Headers:",this.sanitizeHeaders(Object.fromEntries(r.headers.entries()))),this.logging("======================"),!r.ok){const t=await r.json().catch(()=>({}));throw this.logging("=== ERROR RESPONSE ==="),this.logging("Error Data:",t),this.logging("===================="),new Error(t.message||`HTTP ${r.status}: ${r.statusText}`)}const a=await r.json();return this.logging("=== SUCCESS RESPONSE ==="),this.logging("Response Data:",a),this.logging("======================"),a}async get(t){return this.makeRequest(t,{method:"GET"})}async post(t,e){return this.makeRequest(t,{method:"POST",body:e?JSON.stringify(e):void 0})}};function isEthereumNetwork(t){return t.startsWith("ethereum:")}function isSolanaNetwork(t){return"solana"===t}function getChainIdFromNetwork(t){return Number(t.split(":")[1])}var AgentSdk=class{client;config;constructor(t){this.config=t,this.client=new APIClient(t)}logging(t,e){this.config.verbose}async sendLog(t){this.logging("=== ADD MESSAGE ==="),this.logging("Message:",t),this.logging("===================");try{await this._sendLog([t])}catch(t){this.logging("=== SEND LOG ERROR ==="),this.logging("Error:",t),this.logging("======================")}}async signAndSend(t){this.logging("=== SIGN AND SEND ==="),this.logging("Request:",t),this.logging("Testing mode:",this.config.testing),this.logging("====================");try{if(this.config.testing)return{success:!0,internalTransactionId:123,txHash:isEthereumNetwork(t.network)?"0xTEST":"TEST_SOL_TX",transactionUrl:void 0};if(isEthereumNetwork(t.network)){const e=getChainIdFromNetwork(t.network);if("toAddress"in t.request)return await this.handleEvmTransaction({chainId:e,toAddress:t.request.toAddress,data:t.request.data,valueWei:t.request.value,message:t.message})}return isSolanaNetwork(t.network)&&"hexTransaction"in t.request?await this.handleSolanaTransaction({hexTransaction:t.request.hexTransaction,message:t.message}):{success:!1,error:`Unsupported network: ${t.network}`,errorDetails:{message:`Unsupported network: ${t.network}`}}}catch(t){return this.logging("=== SIGN AND SEND ERROR ==="),this.logging("Error:",t),this.logging("==========================="),{success:!1,error:t instanceof Error?t.message:"Unknown error",errorDetails:{message:t instanceof Error?t.message:"Unknown error"}}}}async signMessage(t){this.logging("=== SIGN MESSAGE ==="),this.logging("Request:",t),this.logging("Testing mode:",this.config.testing),this.logging("====================");try{return this.config.testing?{v:27,r:"0xTEST_R",s:"0xTEST_S",formattedSignature:"0xTEST_FORMATTED",type:"evm"}:isEthereumNetwork(t.network)?await this.handleEvmSignMessage(t):{v:0,r:"0x0",s:"0x0",formattedSignature:"0x0",type:"evm"}}catch(t){return this.logging("=== SIGN MESSAGE ERROR ==="),this.logging("Error:",t),this.logging("=========================="),{v:0,r:"0x0",s:"0x0",formattedSignature:"0x0",type:"evm"}}}swidge={quote:async t=>this.handleSwidgeQuote(t),execute:async t=>this.handleSwidgeExecute(t)};async handleEvmTransaction(t){try{const e=await this.client.post("/v1/transactions/evm",t),s=await this.client.post(`/v1/transactions/evm/${e.internalTransactionId}/broadcast`);return{success:!0,internalTransactionId:e.internalTransactionId,txHash:s.txHash,transactionUrl:s.transactionUrl}}catch(t){this.logging("=== EVM TRANSACTION ERROR ==="),this.logging("Error:",t),this.logging("=============================");let e,s,r,a="Unknown error";if(t instanceof Error){a=t.message;const i=t.message.match(/HTTP (\d+): (.+)/);i&&(e=Number.parseInt(i[1]),s=i[2]),t.message.includes("Failed to estimate gas")&&(r=t.message)}return{success:!1,error:a,errorDetails:{message:r||a,status:e,statusText:s}}}}async handleSolanaTransaction(t){try{const e=await this.client.post("/v1/transactions/solana",t),s=await this.client.post(`/v1/transactions/solana/${e.internalTransactionId}/broadcast`);return{success:!0,internalTransactionId:e.internalTransactionId,txHash:s.txHash,transactionUrl:s.transactionUrl}}catch(t){this.logging("=== SOLANA TRANSACTION ERROR ==="),this.logging("Error:",t),this.logging("================================");let e,s,r="Unknown error";if(t instanceof Error){r=t.message;const a=t.message.match(/HTTP (\d+): (.+)/);a&&(e=Number.parseInt(a[1]),s=a[2])}return{success:!1,error:r,errorDetails:{message:r,status:e,statusText:s}}}}async handleEvmSignMessage(t){try{return await this.client.post("/v1/messages/evm",{messageType:t.request.messageType,data:t.request.data,chainId:t.request.chainId})}catch(t){return this.logging("=== EVM SIGN MESSAGE ERROR ==="),this.logging("Error:",t),this.logging("=============================="),{v:0,r:"0x0",s:"0x0",formattedSignature:"0x0",type:"evm"}}}async _sendLog(t){return this.config.testing?{status:200,message:"Logs added successfully (TESTING)"}:this.client.post("/v1/logs",t)}async _updateJobStatus(t){if(this.logging("UPDATE_JOB_STATUS",t),this.config.testing)return{status:200,message:"Job status updated successfully (TESTING)"};try{return await this.client.post(`/v1/jobs/${t.jobId}/status`,t)}catch(t){return this.logging("=== UPDATE JOB STATUS ERROR ==="),this.logging("Error:",t),this.logging("==============================="),{status:400,message:`Failed to update job status: ${t instanceof Error?t.message:"Unknown error"}`}}}async handleSwidgeQuote(t){this.logging("=== SWIDGE QUOTE ==="),this.logging("Request:",t),this.logging("Testing mode:",this.config.testing),this.logging("===================");try{return this.config.testing?{success:!0,data:{engine:"relay",assetSend:{network:t.from.network,address:t.from.address,token:t.fromToken||null,amount:t.amount,amountFormatted:"1.0",amountUsd:"100.00"},assetRecieve:{network:t.to.network,address:t.to.address,token:t.toToken||null,amount:"950000000000000000",amountFormatted:"0.95",amountUsd:"95.00"},priceImpact:{percentage:"0.5",usd:"5.00"},fees:[{name:"gas",amount:"21000000000000000",amountFormatted:"0.021",amountUsd:"2.10"}],steps:[{type:"transaction",description:"Test swap transaction",transactionDetails:{type:"evm",from:"0xtest",to:"0xtest",chainId:1,value:0,data:"0x",gas:21e3,maxFeePerGas:2e10,maxPriorityFeePerGas:1e9},metadata:{requestId:"test-request-id"}}]}}:{success:!0,data:await this.client.post("/v1/swidge/quote",t)}}catch(t){this.logging("=== SWIDGE QUOTE ERROR ==="),this.logging("Error:",t),this.logging("=========================");let e,s,r="Failed to get swidge quote";if(t instanceof Error){r=t.message;const a=t.message.match(/HTTP (\d+): (.+)/);a&&(e=Number.parseInt(a[1]),s=a[2])}return{success:!1,error:r,errorDetails:{message:r,status:e,statusText:s}}}}async handleSwidgeExecute(t){this.logging("=== SWIDGE EXECUTE ==="),this.logging("Quote:",t),this.logging("Testing mode:",this.config.testing),this.logging("=====================");try{if(this.config.testing)return{success:!0,data:{status:"success",in:{network:t.assetSend.network,txs:["0xtest_in_tx"]},out:{network:t.assetRecieve.network,txs:["0xtest_out_tx"]},lastUpdated:Date.now()}};this.logging("Making execute request to /v1/swidge/execute");const e=await this.client.post("/v1/swidge/execute",t);return this.logging("Execute response received:",JSON.stringify(e,null,2)),{success:!0,data:e}}catch(t){this.logging("=== SWIDGE EXECUTE ERROR ==="),this.logging("Error:",t),this.logging("============================");let e,s,r="Failed to execute swidge swap";if(t instanceof Error){r=t.message;const a=t.message.match(/HTTP (\d+): (.+)/);a&&(e=Number.parseInt(a[1]),s=a[2])}return{success:!1,error:r,errorDetails:{message:r,status:e,statusText:s}}}}};import{zValidator}from"@hono/zod-validator";import{Hono}from"hono";import{cors}from"hono/cors";import{z}from"zod";var AgentRequestSchema=z.object({sessionId:z.number(),sessionWalletAddress:z.string(),jobId:z.string().optional(),otherParameters:z.object().optional()}),AgentResponseSchema=z.object({success:z.boolean(),error:z.string().optional(),message:z.string().optional()}),HealthResponseSchema=z.object({status:z.string()}),Agent=class{app;executionFunction;stopFunction;healthCheckFunction;constructor(t){this.app=new Hono,this.executionFunction=t.executionFunction,this.stopFunction=t.stopFunction,this.healthCheckFunction=t.healthCheckFunction||(async()=>({status:"healthy"})),this.app.use("*",cors()),this.setupRoutes()}defaultStopFunction=async t=>({success:!0,message:`Agent stopped for session ${t.sessionId}`});async executeWithJobTracking(t,e){try{const s=await e(t);if(t.jobId&&s.success)try{await this.updateJobStatus(t.sessionId,t.jobId,"success")}catch(t){}else if(t.jobId&&!s.success)try{const e=s.error||s.message||"Function returned failure";await this.updateJobStatus(t.sessionId,t.jobId,"failed",e)}catch(t){}return s}catch(e){if(t.jobId)try{const s=e instanceof Error?e.message:"Unknown error";await this.updateJobStatus(t.sessionId,t.jobId,"failed",s)}catch(t){}return{success:!1,error:e instanceof Error?e.message:"Unknown error",message:"Function execution failed"}}}async updateJobStatus(t,e,s,r){try{const a=new AgentSdk({sessionId:t}),i={jobId:e,status:s,...r&&{errorMessage:r}};await a._updateJobStatus(i)}catch(t){}}setupRoutes(){this.app.post("/execute",zValidator("json",AgentRequestSchema),async t=>{try{const e=t.req.valid("json"),s=await this.executeWithJobTracking(e,this.executionFunction);return t.json(s)}catch(e){return t.json({success:!1,error:e instanceof Error?e.message:"Unknown error",message:"Execution failed"},500)}}),this.app.post("/stop",zValidator("json",AgentRequestSchema),async t=>{try{const e=t.req.valid("json"),s=this.stopFunction||this.defaultStopFunction,r=await this.executeWithJobTracking(e,s);return t.json(r)}catch(e){return t.json({success:!1,error:e instanceof Error?e.message:"Unknown error",message:"Stop operation failed"},500)}}),this.app.get("/health",async t=>{try{const e=await(this.healthCheckFunction?.());return t.json(e)}catch(e){return t.json({status:"unhealthy",error:e instanceof Error?e.message:"Unknown error",timestamp:(new Date).toISOString()},500)}})}getPortFromPackageJson(){try{const t=__require("fs"),e=__require("path").join(process.cwd(),"package.json");if(t.existsSync(e)){const s=JSON.parse(t.readFileSync(e,"utf-8"));if(s.circuit?.port)return Number.parseInt(s.circuit.port,10)}}catch(t){}return null}run(port){const isCloudflareWorker="undefined"!=typeof globalThis&&void 0!==globalThis.Cloudflare;if(isCloudflareWorker)return this.getWorkerExport();const bunEnv=globalThis.Bun?.env,envPort=process.env.AGENT_PORT||bunEnv?.AGENT_PORT,packageJsonPort=this.getPortFromPackageJson();let finalPort=port;!finalPort&&envPort&&(finalPort=Number.parseInt(envPort,10)),!finalPort&&packageJsonPort&&(finalPort=packageJsonPort),finalPort||(finalPort=3e3);try{const req=eval("require"),{serve:serve}=req("@hono/node-server");serve({fetch:this.app.fetch,port:finalPort})}catch(t){process.exit(1)}}getWorkerExport(){return{fetch:async(t,e,s)=>(e&&"undefined"!=typeof globalThis&&(globalThis.__AGENT_ENV__=e),this.app.fetch(t,e,s))}}};function createAgentHandler(t,e,s){return new Agent({executionFunction:t,stopFunction:e,healthCheckFunction:s})}import{z as z2}from"zod";var zEthereumNetwork=z2.templateLiteral(["ethereum:",z2.coerce.number().int().nonnegative()]),SwidgeNetworkSchema=z2.union([z2.literal("solana"),zEthereumNetwork]),SwidgeWalletSchema=z2.object({address:z2.string(),network:SwidgeNetworkSchema}),SwidgeQuoteRequestSchema=z2.object({from:SwidgeWalletSchema,to:SwidgeWalletSchema,fromToken:z2.string().optional(),toToken:z2.string().optional(),amount:z2.string(),priceImpact:z2.string().optional(),slippage:z2.string().optional()}),SwidgeQuoteAssetSchema=z2.object({network:SwidgeNetworkSchema,address:z2.string(),token:z2.string().nullable(),name:z2.string().optional(),symbol:z2.string().optional(),decimals:z2.number().optional(),amount:z2.string().optional(),minimumAmount:z2.string().optional(),amountFormatted:z2.string().optional(),amountUsd:z2.string().optional()}),SwidgePriceImpactSchema=z2.object({usd:z2.string().optional(),percentage:z2.string().optional()}),SwidgeFeeSchema=z2.object({name:z2.string(),amount:z2.string().optional(),amountFormatted:z2.string().optional(),amountUsd:z2.string().optional()}),SwidgeSolanaInstructionSchema=z2.object({programId:z2.string(),keys:z2.array(z2.object({pubkey:z2.string(),isSigner:z2.boolean(),isWritable:z2.boolean()})),data:z2.union([z2.string(),z2.instanceof(Buffer)])}),SwidgeEvmTransactionDetailsSchema=z2.object({type:z2.literal("evm"),from:z2.string().regex(/^0x[a-fA-F0-9]{40}$/),to:z2.string().regex(/^0x[a-fA-F0-9]{40}$/),chainId:z2.number(),value:z2.number(),data:z2.string().regex(/^0x[a-fA-F0-9]*$/),gas:z2.number(),maxFeePerGas:z2.number(),maxPriorityFeePerGas:z2.number()}),SwidgeSolanaTransactionDetailsSchema=z2.object({type:z2.literal("solana"),instructions:z2.array(SwidgeSolanaInstructionSchema),addressLookupTableAddresses:z2.array(z2.string())}),zTransactionStep=z2.object({type:z2.literal("transaction"),description:z2.string(),transactionDetails:z2.union([SwidgeEvmTransactionDetailsSchema,SwidgeSolanaTransactionDetailsSchema]),metadata:z2.record(z2.string(),z2.string())}),zUnsignedSignatureStep=z2.object({type:z2.literal("signature"),description:z2.string(),signatureData:z2.string(),metadata:z2.record(z2.string(),z2.string())}),SwidgeUnsignedStepSchema=z2.discriminatedUnion("type",[zTransactionStep,zUnsignedSignatureStep]),SwidgeQuoteDataSchema=z2.object({engine:z2.literal("relay"),assetSend:SwidgeQuoteAssetSchema,assetRecieve:SwidgeQuoteAssetSchema,priceImpact:SwidgePriceImpactSchema,fees:z2.array(SwidgeFeeSchema),steps:z2.array(SwidgeUnsignedStepSchema)}),SwidgeStatusInfoSchema=z2.object({network:z2.string(),txs:z2.array(z2.string())}),SwidgeExecuteResponseSchema=z2.object({status:z2.union([z2.literal("success"),z2.literal("failure"),z2.literal("refund"),z2.literal("delayed")]),in:SwidgeStatusInfoSchema,out:SwidgeStatusInfoSchema,lastUpdated:z2.number()}),QUOTE_RESULT={FOUND:"QUOTE_FOUND",NO_QUOTE_PROVIDED:"No quote provided",WALLET_NOT_FOUND:"Wallet not found",WALLET_MISMATCH:"From wallet does not match session wallet"},SwidgeSDKResponseSchema=t=>z2.object({success:z2.boolean(),data:t.optional(),error:z2.string().optional(),errorDetails:z2.object({message:z2.string(),status:z2.number().optional(),statusText:z2.string().optional()}).optional()}),SwidgeQuoteResponseWrapperSchema=SwidgeSDKResponseSchema(SwidgeQuoteDataSchema),SwidgeExecuteResponseWrapperSchema=SwidgeSDKResponseSchema(SwidgeExecuteResponseSchema);export{APIClient,Agent,AgentSdk,QUOTE_RESULT,getChainIdFromNetwork,isEthereumNetwork,isSolanaNetwork};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@circuitorg/agent-sdk",
3
- "version": "1.0.13",
3
+ "version": "1.1.1",
4
4
  "description": "typescript sdk for the Agent Toolset Service",
5
5
  "type": "module",
6
6
  "main": "index.js",