@circuitorg/agent-sdk 1.0.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/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # Circuit Agent SDK - Typescript
2
+
3
+ > **Clean, type-safe TypeScript SDK for building cross-chain agents on the circuit platform**
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.
6
+
7
+ > **💡 Best used with [Circuit Agents CLI](https://github.com/circuitorg/agents-cli)** - Deploy, manage, and test your agents with ease
8
+
9
+ ## ✨ Features
10
+
11
+ - **🎯 Simple API**: Only 2 main methods - `addMessage()` and `signAndSend()`
12
+ - **🔒 Type Safety**: Network parameter determines valid request shapes automatically
13
+ - **🚀 Cross-Chain**: Unified interface for EVM and Solana networks
14
+
15
+ ## 🚀 Quick Start
16
+ ### Install the SDK
17
+ ```bash
18
+ npm install @circuitorg/agents-sdk
19
+ # or
20
+ yarn add @circuitorg/agents-sdk
21
+ # or
22
+ bun add @circuitorg/agents-sdk
23
+ ```
24
+
25
+ ### Sample SDK Usage
26
+ >**NOTE:** The fastest, and recommended, way to get started is to setup an agent via the circuit [CLI](https://github.com/circuitorg/agents-cli)'s 'circuit agent init' command. This will setup a sample agent directory with the necessary agent wireframe, and configure the cli to allow you for easy testing and deployment. You just simply need to add in your secret formula to the execution and stop functions.
27
+
28
+ ```typescript
29
+ import { AgentSdk } from "@circuitorg/agents-sdk";
30
+
31
+ // Initialize the sdk
32
+ const sdk = new AgentSdk({
33
+ sessionId: 123,
34
+ });
35
+ ```
36
+
37
+ ## 🎯 Core SDK API (Only 2 Methods!)
38
+
39
+ ### 1. Add Messages to Timeline
40
+
41
+ ```typescript
42
+ await sdk.addMessage({
43
+ type: "observe",
44
+ shortMessage: "Starting swap operation"
45
+ });
46
+ ```
47
+
48
+ ### 2. Sign & Send Transactions
49
+
50
+ #### Ethereum (any EVM chain)
51
+
52
+ ```typescript
53
+ // Native ETH transfer
54
+ await sdk.signAndSend({
55
+ network: "ethereum:1", // Chain ID in network string
56
+ request: {
57
+ toAddress: "0x742d35cc6634C0532925a3b8D65e95f32B6b5582" as `0x${string}`,
58
+ data: "0x" as `0x${string}`,
59
+ value: "1000000000000000000" // 1 ETH in wei
60
+ },
61
+ message: "Sending 1 ETH"
62
+ });
63
+
64
+ // Contract interaction
65
+ await sdk.signAndSend({
66
+ network: "ethereum:42161", // Arbitrum
67
+ request: {
68
+ toAddress: "0xTokenContract..." as `0x${string}`,
69
+ data: "0xa9059cbb..." as `0x${string}`, // encoded transfer()
70
+ value: "0"
71
+ }
72
+ });
73
+ ```
74
+
75
+ #### Solana
76
+
77
+ ```typescript
78
+ await sdk.signAndSend({
79
+ network: "solana",
80
+ request: {
81
+ hexTransaction: "010001030a0b..." // serialized VersionedTransaction
82
+ }
83
+ });
84
+ ```
85
+
86
+
87
+ ## 🔧 Sample Agent Structure
88
+
89
+ ### SDK Configuration
90
+
91
+ ```typescript
92
+ import { Agent, AgentSdk, ExecutionFunctionContract, StopFunctionContract } from "@circuitorg/agents-sdk";
93
+
94
+ // Agent execution function using the new AgentSdk v1.0 API
95
+ const executionFunction: ExecutionFunctionContract = async (request) => {
96
+ console.log(`🚀 Agent execution called for session ${request.sessionId}`);
97
+
98
+ const sdk = new AgentSdk({
99
+ sessionId: request.sessionId,
100
+ });
101
+
102
+ try {
103
+ // Get user's wallet address (use vitalik.eth for demo if no address provided)
104
+ const userAddress = request.sessionWalletAddress
105
+
106
+ await sdk.addMessage({
107
+ type: "observe",
108
+ shortMessage: `🚀 Agent SDK v1.0 demo - Hello ${userAddress}`
109
+ });
110
+
111
+ return { success: true};
112
+ } catch (error) {
113
+ await sdk.addMessage({
114
+ type: "error",
115
+ shortMessage: `Agent execution error: ${error instanceof Error ? error.message : 'Unknown error'}`
116
+ });
117
+ return { success: false, error: error instanceof Error ? error.message : "Unknown error" };
118
+ }
119
+ };
120
+
121
+ const stopFunction: StopFunctionContract = async (request) => {
122
+ const sdk = new AgentSdk({
123
+ sessionId: request.sessionId,
124
+ testing: true
125
+ });
126
+
127
+ try {
128
+ await sdk.addMessage({
129
+ type: "observe",
130
+ shortMessage: "🛑 Agent stopping with new SDK v1.0"
131
+ });
132
+ return { success: true };
133
+ } catch (error) {
134
+ return { success: false, error: error instanceof Error ? error.message : "Unknown error" };
135
+ }
136
+ };
137
+
138
+ // DONT MODIFY BELOW THIS
139
+ const agent = new Agent({ executionFunction, stopFunction });
140
+
141
+ // Start the server for local development
142
+ agent.run();
143
+
144
+ // Export the agent for Cloudflare Workers
145
+ export default agent.getWorkerExport();
146
+
147
+ ```
148
+
149
+
package/index.d.ts ADDED
@@ -0,0 +1,475 @@
1
+ import * as hono from 'hono';
2
+ import { z } from 'zod';
3
+
4
+ /**
5
+ * Core type definitions for the Agent SDK
6
+ */
7
+
8
+ /**
9
+ * Configuration for the SDK client
10
+ */
11
+ interface SDKConfig {
12
+ /** Session ID for the current agent instance */
13
+ sessionId: number;
14
+ /** Enable verbose logging for debugging */
15
+ verbose?: boolean;
16
+ /** Enable testing mode to return mock responses */
17
+ testing?: boolean;
18
+ /** Optional base URL for local development (auto-detected if omitted) */
19
+ baseUrl?: string;
20
+ }
21
+
22
+ /**
23
+ * Network type definitions and guard functions
24
+ */
25
+ type Network = `ethereum:${number}` | "solana";
26
+ /**
27
+ * Type guard to check if network is Ethereum-based
28
+ * @param network - Network to check
29
+ * @returns true if network is ethereum:chainId format
30
+ */
31
+ declare function isEthereumNetwork(network: Network): network is `ethereum:${number}`;
32
+ /**
33
+ * Type guard to check if network is Solana
34
+ * @param network - Network to check
35
+ * @returns true if network is "solana"
36
+ */
37
+ declare function isSolanaNetwork(network: Network): network is "solana";
38
+ /**
39
+ * Extract chain ID from Ethereum network string
40
+ * @param network - Ethereum network string
41
+ * @returns Chain ID as number
42
+ */
43
+ declare function getChainIdFromNetwork(network: `ethereum:${number}`): number;
44
+
45
+ /**
46
+ * Request type definitions with conditional shapes based on network
47
+ */
48
+
49
+ /**
50
+ * Main signAndSend request type with network-specific conditional shapes
51
+ */
52
+ type SignAndSendRequest = {
53
+ network: Network;
54
+ /** Optional short message to be attached to the transaction for observability */
55
+ message?: string;
56
+ } & ({
57
+ network: `ethereum:${number}`;
58
+ request: {
59
+ toAddress: `0x${string}`;
60
+ data: `0x${string}`;
61
+ value: string;
62
+ };
63
+ } | {
64
+ network: "solana";
65
+ request: {
66
+ hexTransaction: string;
67
+ };
68
+ });
69
+ /**
70
+ * Message request for addMessage function
71
+ */
72
+ type AddMessageRequest = {
73
+ type: "observe" | "validate" | "reflect" | "error" | "warning";
74
+ shortMessage: string;
75
+ };
76
+
77
+ /**
78
+ * Response type definitions
79
+ */
80
+ /**
81
+ * Standard response from signAndSend operations
82
+ */
83
+ type SignAndSendResponse = {
84
+ /** Internal transaction ID for tracking */
85
+ internalTransactionId: number;
86
+ /** Transaction hash once broadcast */
87
+ txHash: string;
88
+ /** Optional transaction URL (explorer link) */
89
+ transactionUrl?: string;
90
+ };
91
+
92
+ /**
93
+ * Main AgentSdk class with simplified API surface
94
+ */
95
+
96
+ /**
97
+ * Main SDK entrypoint used by agents to interact with the Circuit backend.
98
+ *
99
+ * Provides a minimal, type-safe surface with two core methods that cover the
100
+ * majority of agent interactions:
101
+ *
102
+ * - `addMessage()` — emit timeline messages for observability and UX
103
+ * - `signAndSend()` — sign and broadcast transactions across networks
104
+ *
105
+ * Quick start:
106
+ * ```ts
107
+ * import { AgentSdk } from "@circuit/agent-sdk";
108
+ *
109
+ * const sdk = new AgentSdk({
110
+ * sessionId: 12345,
111
+ * });
112
+ *
113
+ * await sdk.addMessage({ type: "observe", shortMessage: "Starting" });
114
+ * const tx = await sdk.signAndSend({
115
+ * network: "ethereum:42161",
116
+ * request: {
117
+ * toAddress: "0xabc..." as `0x${string}`,
118
+ * data: "0x" as `0x${string}`,
119
+ * value: "0"
120
+ * },
121
+ * message: "Funding user"
122
+ * });
123
+ * ```
124
+ */
125
+ declare class AgentSdk {
126
+ private client;
127
+ private config;
128
+ /**
129
+ * Create a new `AgentSdk` instance.
130
+ *
131
+ * @param config - SDK configuration
132
+ * @param config.sessionId - Numeric session identifier that scopes auth and actions
133
+ * @param config.verbose - When true, prints detailed request/response logs
134
+ * @param config.testing - When true, short-circuits network calls with mock values
135
+ * @param config.baseUrl - Override API base URL (detected automatically otherwise)
136
+ * @example
137
+ * ```ts
138
+ * const sdk = new AgentSdk({ sessionId: 42, verbose: true });
139
+ * ```
140
+ */
141
+ constructor(config: SDKConfig);
142
+ private log;
143
+ /**
144
+ * Add a message to the agent timeline.
145
+ *
146
+ * Messages show up in session traces and UIs and are useful for observability,
147
+ * human-in-the-loop reviews, and debugging.
148
+ *
149
+ * @param message - Timeline message
150
+ * @param message.type - One of: `"observe" | "validate" | "reflect" | "error" | "warning"`
151
+ * @param message.shortMessage - Short, human-readable message (<= 250 chars)
152
+ * @returns Resolves when the message is accepted by the backend
153
+ * @example
154
+ * ```ts
155
+ * await sdk.addMessage({ type: "observe", shortMessage: "Starting swap" });
156
+ * ```
157
+ */
158
+ addMessage(message: AddMessageRequest): Promise<void>;
159
+ /**
160
+ * Sign and broadcast a transaction on the specified network.
161
+ *
162
+ * The backend performs validation and policy checks; you only need to provide
163
+ * the minimal request shape for the selected network.
164
+ *
165
+ * @param request - Network-specific transaction input
166
+ * @param request.network - `"solana"` or `"ethereum:${number}"`
167
+ * @param request.message - Optional human-readable context message (short), stored with the transaction
168
+ * @param request.request - Transaction payload
169
+ * - For Ethereum: `{ toAddress, data, value }`
170
+ * - `toAddress`: recipient contract or EOA as `0x${string}`
171
+ * - `data`: calldata as `0x${string}` (use `"0x"` for simple transfers)
172
+ * - `value`: stringified wei amount
173
+ * - For Solana: `{ hexTransaction }`
174
+ * - `hexTransaction`: serialized `VersionedTransaction` as hex string
175
+ * @returns Promise resolving to `{ internalTransactionId, txHash, transactionUrl? }`
176
+ * @throws Error if the network is unsupported or the backend rejects the request
177
+ * @example
178
+ * ```ts
179
+ * // Ethereum (Arbitrum) native transfer
180
+ * await sdk.signAndSend({
181
+ * network: "ethereum:42161",
182
+ * request: {
183
+ * toAddress: "0xabc..." as `0x${string}`,
184
+ * data: "0x" as `0x${string}`,
185
+ * value: "1000000000000000" // 0.001 ETH
186
+ * },
187
+ * message: "Self-transfer demo"
188
+ * });
189
+ *
190
+ * // Solana
191
+ * await sdk.signAndSend({
192
+ * network: "solana",
193
+ * request: { hexTransaction: "01ab..." },
194
+ * message: "Swap with Jupiter"
195
+ * });
196
+ * ```
197
+ */
198
+ signAndSend(request: SignAndSendRequest): Promise<SignAndSendResponse>;
199
+ /**
200
+ * Handle EVM transaction signing and broadcasting
201
+ */
202
+ private handleEvmTransaction;
203
+ /**
204
+ * Handle Solana transaction signing and broadcasting
205
+ */
206
+ private handleSolanaTransaction;
207
+ /**
208
+ * Send messages to the agent timeline (migrated from AgentToolset)
209
+ */
210
+ private messageSend;
211
+ }
212
+
213
+ /**
214
+ * Low-level HTTP client used internally by the SDK.
215
+ *
216
+ * - Automatically detects Cloudflare Worker environment and uses service bindings
217
+ * - Falls back to HTTP requests for standard environments
218
+ * - For local development, automatically reads auth token from ~/.config/circuit/auth.json
219
+ * - Adds session ID and agent slug headers automatically
220
+ * - Emits verbose request/response logs when `SDKConfig.verbose` is enabled
221
+ *
222
+ * Although exported for advanced scenarios, most users should interact with
223
+ * higher-level abstractions like `AgentSdk` and `AgentUtils`.
224
+ */
225
+ declare class APIClient {
226
+ private config;
227
+ private baseUrl;
228
+ private isCloudflareWorker;
229
+ private hasServiceBinding;
230
+ /**
231
+ * Create an API client.
232
+ * @param config - SDK configuration
233
+ * @param config.sessionId - Numeric session identifier propagated as header
234
+ * @param config.baseUrl - Override base URL for local development (auto-detected if omitted)
235
+ * @param config.verbose - Enable detailed logs for debugging
236
+ */
237
+ constructor(config: SDKConfig);
238
+ private getAgentSlug;
239
+ private getAuthHeaders;
240
+ private loadAuthConfig;
241
+ private log;
242
+ /**
243
+ * Perform a JSON HTTP request.
244
+ *
245
+ * Automatically uses service bindings when available, otherwise falls back to HTTP.
246
+ * Throws with a helpful message when the response is not ok.
247
+ *
248
+ * @param endpoint - API path beginning with `/v1/...`
249
+ * @param options - Fetch options (method, headers, body)
250
+ * @returns Parsed JSON response
251
+ * @throws Error when `response.ok` is false
252
+ */
253
+ private makeRequest;
254
+ /**
255
+ * HTTP GET convenience method.
256
+ * @param endpoint - API path beginning with `/v1/...`
257
+ */
258
+ get<T>(endpoint: string): Promise<T>;
259
+ /**
260
+ * HTTP POST convenience method sending a JSON body.
261
+ * @param endpoint - API path beginning with `/v1/...`
262
+ * @param data - Optional JSON payload to serialize
263
+ */
264
+ post<T>(endpoint: string, data?: any): Promise<T>;
265
+ }
266
+
267
+ /**
268
+ * Request object for agent functions containing session and wallet information.
269
+ * Provided to your `execution`, `chat`, and `stop` handlers.
270
+ */
271
+ declare const AgentRequestSchema: z.ZodObject<{
272
+ sessionId: z.ZodNumber;
273
+ sessionWalletAddress: z.ZodString;
274
+ otherParameters: z.ZodOptional<z.ZodObject<{}, z.core.$strip>>;
275
+ }, z.core.$strip>;
276
+ /**
277
+ * Standard response format for agent functions (execute and stop commands).
278
+ */
279
+ declare const AgentResponseSchema: z.ZodObject<{
280
+ success: z.ZodBoolean;
281
+ error: z.ZodOptional<z.ZodString>;
282
+ message: z.ZodOptional<z.ZodString>;
283
+ }, z.core.$strip>;
284
+ /**
285
+ * Health check response format.
286
+ */
287
+ declare const HealthResponseSchema: z.ZodObject<{
288
+ status: z.ZodString;
289
+ }, z.core.$strip>;
290
+ type AgentRequest = z.infer<typeof AgentRequestSchema>;
291
+ type AgentResponse = z.infer<typeof AgentResponseSchema>;
292
+ type HealthResponse = z.infer<typeof HealthResponseSchema>;
293
+ /**
294
+ * Contract for agent execution functions. Called to perform the agent's main task.
295
+ * @param request - Contains session info and wallet address to operate with
296
+ * @returns Promise resolving to a success/error response
297
+ * @example
298
+ * ```typescript
299
+ * // Execution function implementation
300
+ * const executionFunction: ExecutionFunctionContract = async (request) => {
301
+ * const agentToolset = new AgentToolset({ sessionId: request.sessionId });
302
+ *
303
+ * try {
304
+ * // Send status message
305
+ * await agentToolset.messageSend([{
306
+ * type: "observe",
307
+ * shortMessage: "Starting agent execution..."
308
+ * }]);
309
+ *
310
+ * // Example: Send a transaction
311
+ * const { txResult, broadcastResult } = await agentToolset.transactionSignAndBroadcast({
312
+ * chainId: 1,
313
+ * toAddress: request.sessionWalletAddress,
314
+ * data: "0x",
315
+ * valueWei: "1000000000000000000" // 1 ETH
316
+ * });
317
+ *
318
+ * if (broadcastResult.status === "broadcasted") {
319
+ * return {
320
+ * success: true,
321
+ * message: "Transaction executed successfully"
322
+ * };
323
+ * }
324
+ *
325
+ * return {
326
+ * success: false,
327
+ * error: "Transaction failed to broadcast",
328
+ * message: "Execution failed"
329
+ * };
330
+ * } catch (error) {
331
+ * return {
332
+ * success: false,
333
+ * error: error instanceof Error ? error.message : "Unknown error",
334
+ * message: "Execution failed"
335
+ * };
336
+ * }
337
+ * };
338
+ * ```
339
+ */
340
+ type ExecutionFunctionContract = (request: AgentRequest) => Promise<AgentResponse>;
341
+ /**
342
+ * Contract for agent stop/winddown function. Called to gracefully shut down and
343
+ * run cleanup logic (e.g. withdrawing positions, updating schedules).
344
+ * @param request - Contains session information and wallet address to operate with
345
+ * @returns Promise resolving to a success/error response
346
+ * @example
347
+ * ```typescript
348
+ * // Winddown function implementation
349
+ * const stopFunction: StopFunctionContract = async (request) => {
350
+ * const agentToolset = new AgentToolset({ sessionId: request.sessionId });
351
+ *
352
+ * try {
353
+ * // Notify about shutdown
354
+ * await agentToolset.messageSend([{
355
+ * type: "observe",
356
+ * shortMessage: "Agent shutting down...",
357
+ * longMessage: "Cleaning up resources and saving state"
358
+ * }]);
359
+ *
360
+ * // Example: Update sleep interval before shutdown
361
+ * await agentToolset.sessionUpdateSleepInterval({
362
+ * sleepMinutes: 60 // Set longer interval during inactive period
363
+ * });
364
+ *
365
+ * // Example: Final status message
366
+ * await agentToolset.messageSend([{
367
+ * type: "observe",
368
+ * shortMessage: "Shutdown complete",
369
+ * longMessage: `Agent ${request.sessionId} successfully shut down`
370
+ * }]);
371
+ *
372
+ * return {
373
+ * success: true,
374
+ * message: "Agent stopped successfully"
375
+ * };
376
+ * } catch (error) {
377
+ * return {
378
+ * success: false,
379
+ * error: error instanceof Error ? error.message : "Failed to clean up",
380
+ * message: "Stop operation failed"
381
+ * };
382
+ * }
383
+ * };
384
+ * ```
385
+ */
386
+ type StopFunctionContract = (request: AgentRequest) => Promise<AgentResponse>;
387
+ /**
388
+ * Contract for agent chat functions. Handle interactive messaging with the agent.
389
+ * @param request - Contains session information and wallet address to operate with
390
+ * @returns Promise resolving to a success/error response
391
+ * @example
392
+ * ```typescript
393
+ * // Chat function implementation
394
+ * const chatFunction: ChatFunctionContract = async (request) => {
395
+ * const agentToolset = new AgentToolset({ sessionId: request.sessionId });
396
+ *
397
+ * await agentToolset.messageSend([{
398
+ * type: "observe",
399
+ * shortMessage: "Processing chat message",
400
+ * longMessage: `Received message for wallet ${request.sessionWalletAddress}`
401
+ * }]);
402
+ *
403
+ * return {
404
+ * success: true,
405
+ * message: "Chat message processed"
406
+ * };
407
+ * };
408
+ * ```
409
+ */
410
+ type ChatFunctionContract = (request: AgentRequest) => Promise<AgentResponse>;
411
+ /**
412
+ * Contract for agent health check functions. Handle health status requests.
413
+ * @returns Promise resolving to an object with a status field
414
+ * @example
415
+ * ```typescript
416
+ * // Health check function implementation
417
+ * const healthCheckFunction: HealthCheckFunctionContract = async () => {
418
+ * // Check database connection, external services, etc.
419
+ * const isHealthy = await checkSystemHealth();
420
+ *
421
+ * return {
422
+ * status: isHealthy ? "healthy" : "unhealthy",
423
+ * // Optional additional fields
424
+ * uptime: process.uptime(),
425
+ * timestamp: new Date().toISOString()
426
+ * };
427
+ * };
428
+ * ```
429
+ */
430
+ type HealthCheckFunctionContract = () => Promise<HealthResponse>;
431
+ /**
432
+ * Configuration object for creating a new agent
433
+ */
434
+ interface AgentConfig {
435
+ /** Main execution function that implements the agent's core logic */
436
+ executionFunction: ExecutionFunctionContract;
437
+ /** Optional chat function for handling interactive messaging */
438
+ chatFunction?: ChatFunctionContract;
439
+ /** Optional winddown function for cleanup operations, this is called when the agent is stopped */
440
+ stopFunction?: StopFunctionContract;
441
+ /** Optional health check function for monitoring agent health status */
442
+ healthCheckFunction?: HealthCheckFunctionContract;
443
+ }
444
+ /**
445
+ * HTTP server wrapper for agent functions.
446
+ *
447
+ * Exposes the following endpoints:
448
+ * - `POST /execute` — required, calls your execution function
449
+ * - `POST /chat` — optional, when a `chatFunction` is provided
450
+ * - `POST /stop` and `DELETE /` — optional, when a `stopFunction` is provided
451
+ * - `GET /health` — always available, uses provided or default health check
452
+ */
453
+ declare class Agent {
454
+ private app;
455
+ private executionFunction;
456
+ private chatFunction?;
457
+ private stopFunction?;
458
+ private healthCheckFunction?;
459
+ /**
460
+ * Create a new `Agent` with the provided handlers.
461
+ * @param config - Execution function is required; chat/stop/health are optional.
462
+ */
463
+ constructor(config: AgentConfig);
464
+ private setupRoutes;
465
+ private getPortFromPackageJson;
466
+ run(port?: number): {
467
+ fetch: (request: Request, Env?: unknown, executionCtx?: hono.ExecutionContext) => Response | Promise<Response>;
468
+ } | undefined;
469
+ /** Get the worker export for Cloudflare Workers environments. */
470
+ getWorkerExport(): {
471
+ fetch: (request: Request, Env?: unknown, executionCtx?: hono.ExecutionContext) => Response | Promise<Response>;
472
+ };
473
+ }
474
+
475
+ export { APIClient, type AddMessageRequest, Agent, AgentSdk, type ExecutionFunctionContract, type Network, type SDKConfig, type SignAndSendRequest, type SignAndSendResponse, type StopFunctionContract, getChainIdFromNetwork, isEthereumNetwork, isSolanaNetwork };
package/index.js ADDED
@@ -0,0 +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||!process.env?.HOME)return;const fs=eval("require")("fs"),path=eval("require")("path"),authPath=path.join(process.env.HOME,".config","circuit","auth.json");if(!fs.existsSync(authPath))return;const authContent=fs.readFileSync(authPath,"utf-8");return JSON.parse(authContent)}catch(t){return}}module.exports={loadAuthFromFileSystem:loadAuthFromFileSystem}}});import{z}from"zod";var API_BASE_URL_LOCAL="https://agents.circuit.org",MessageTypeSchema=z.enum(["observe","validate","reflect","error","warning"]),MessageSchema=z.object({type:MessageTypeSchema,shortMessage:z.string().max(250)}),MessagesRequestSchema=z.array(MessageSchema),MessagesResponseSchema=z.object({status:z.number(),message:z.string()}),TransactionSendRequestSchema=z.object({chainId:z.number(),toAddress:z.string(),data:z.string(),valueWei:z.string(),message:z.string().max(250).optional(),gas:z.number().optional(),maxFeePerGas:z.string().optional(),maxPriorityFeePerGas:z.string().optional()}),SolanaTransactionRequestSchema=z.object({hexTransaction:z.string(),message:z.string().max(250).optional()}),APIClient=class{config;baseUrl;isCloudflareWorker(){return"undefined"!=typeof globalThis&&void 0!==globalThis.Cloudflare}hasServiceBinding(){return this.isCloudflareWorker()&&void 0!==globalThis.AGENT_TOOLSET_SERVICE}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}}log(t,e){this.config.verbose}async makeRequest(t,e={}){const s={...{"Content-Type":"application/json",...this.getAuthHeaders()},...e.headers};let r;if(this.log("=== REQUEST DETAILS ==="),this.log("Endpoint:",t),this.log("Method:",e.method||"GET"),this.log("Headers:",s),this.log("Body:",e.body),this.log("Session ID:",this.config.sessionId),this.log("Agent Slug:",this.getAgentSlug()||"not set"),this.log("Using Service Binding:",this.hasServiceBinding()),this.log("====================="),this.hasServiceBinding()){const n=globalThis.AGENT_TOOLSET_SERVICE,o=`https://agents.circuit.org${t}`,a={...e,headers:s};r=await n.fetch(o,a)}else{const n=`${this.baseUrl}${t}`,o={...e,headers:s};r=await fetch(n,o)}if(this.log("=== RESPONSE DETAILS ==="),this.log("Status:",r.status),this.log("Status Text:",r.statusText),this.log("Response Headers:",Object.fromEntries(r.headers.entries())),this.log("======================"),!r.ok){const t=await r.json().catch(()=>({}));throw this.log("=== ERROR RESPONSE ==="),this.log("Error Data:",t),this.log("===================="),new Error(t.message||`HTTP ${r.status}: ${r.statusText}`)}const n=await r.json();return this.log("=== SUCCESS RESPONSE ==="),this.log("Response Data:",n),this.log("======================"),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)}log(t,e){this.config.verbose}async addMessage(t){this.log("=== ADD MESSAGE ==="),this.log("Message:",t),this.log("===================");const e=[{type:t.type,shortMessage:t.shortMessage}];await this.messageSend(e)}async signAndSend(t){if(this.log("=== SIGN AND SEND ==="),this.log("Request:",t),this.log("Testing mode:",this.config.testing),this.log("===================="),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 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 messageSend(t){return this.config.testing?{status:200,message:"Messages added successfully (TESTING)"}:this.client.post("/v1/messages",t)}};import{zValidator}from"@hono/zod-validator";import{Hono}from"hono";import{cors}from"hono/cors";import{z as z2}from"zod";var AgentRequestSchema=z2.object({sessionId:z2.number(),sessionWalletAddress:z2.string(),otherParameters:z2.object().optional()}),AgentResponseSchema=z2.object({success:z2.boolean(),error:z2.string().optional(),message:z2.string().optional()}),HealthResponseSchema=z2.object({status:z2.string()}),Agent=class{app;executionFunction;chatFunction;stopFunction;healthCheckFunction;constructor(t){this.app=new Hono,this.executionFunction=t.executionFunction,this.chatFunction=t.chatFunction,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.chatFunction&&this.app.post("/chat",zValidator("json",AgentRequestSchema),async t=>{try{const e=t.req.valid("json"),s=await(this.chatFunction?.(e));return t.json(s)}catch(e){return t.json({success:!1,error:e instanceof Error?e.message:"Unknown error",message:"Chat 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:this.app.fetch}}};function createAgentHandler(t,e,s,r){return new Agent({executionFunction:t,chatFunction:e,stopFunction:s,healthCheckFunction:r})}export{APIClient,Agent,AgentSdk,getChainIdFromNetwork,isEthereumNetwork,isSolanaNetwork};
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@circuitorg/agent-sdk",
3
+ "version": "1.0.0",
4
+ "description": "typescript sdk for the Agent Toolset Service",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "types": "index.d.ts",
8
+ "scripts": {
9
+ "build": "tsup",
10
+ "postbuild": "cp package.json dist && cp README.md dist",
11
+ "dev": "tsup --watch",
12
+ "test": "jest --passWithNoTests",
13
+ "test:package": "./scripts/test-package.sh",
14
+ "test:install": "./scripts/test-install.sh",
15
+ "typecheck": "tsc --noEmit",
16
+ "lint": "biome check .",
17
+ "lint:fix": "biome check --write .",
18
+ "format": "biome format --write ."
19
+ },
20
+ "keywords": [
21
+ "agent",
22
+ "toolset",
23
+ "sdk",
24
+ "blockchain",
25
+ "transactions"
26
+ ],
27
+ "author": "circuitorg",
28
+ "license": "MIT",
29
+ "bugs": {
30
+ "url": "https://github.com/circuitorg/agents-sdk/issues"
31
+ },
32
+ "homepage": "https://github.com/circuitorg/agents-sdk#readme",
33
+ "sideEffects": false,
34
+ "browser": {
35
+ "ws": "./src/stubs/ws-stub.js",
36
+ "@solana/rpc-subscriptions": "./src/stubs/subscriptions-stub.js",
37
+ "@solana/rpc-subscriptions-spec": "./src/stubs/subscriptions-stub.js",
38
+ "@solana/rpc-subscriptions-channel-websocket": "./src/stubs/subscriptions-stub.js",
39
+ "@solana/subscribable": "./src/stubs/subscriptions-stub.js",
40
+ "@solana/transaction-confirmation": "./src/stubs/subscriptions-stub.js"
41
+ },
42
+ "dependencies": {
43
+ "@hono/zod-validator": "^0.7.2",
44
+ "@solana-program/system": "^0.7.0",
45
+ "@solana/kit": "^2.3.0",
46
+ "@solana/transactions": "^2.3.0",
47
+ "hono": "^4.9.1",
48
+ "zod": "^4.0.17"
49
+ },
50
+ "optionalDependencies": {
51
+ "@hono/node-server": "^1.18.2",
52
+ "@solana-program/token": "0.5.1",
53
+ "@solana-program/token-2022": "0.4.2"
54
+ },
55
+ "devDependencies": {
56
+ "@biomejs/biome": "^1.7.0",
57
+ "@types/jest": "29.5.14",
58
+ "@types/node": "^20.19.7",
59
+ "dts-bundle-generator": "^9.5.1",
60
+ "esbuild": "^0.25.9",
61
+ "jest": "29.7.0",
62
+ "terser": "^5.43.1",
63
+ "tsup": "^8.5.0",
64
+ "typescript": "5.8.3"
65
+ },
66
+ "repository": {
67
+ "type": "git",
68
+ "url": "git+https://github.com/circuitorg/agents-sdk.git"
69
+ }
70
+ }
@@ -0,0 +1,5 @@
1
+ export default {};
2
+ export const createSolanaRpcSubscriptions = () => {
3
+ throw new Error("Subscriptions disabled in SDK");
4
+ };
5
+
@@ -0,0 +1,3 @@
1
+ export default {};
2
+ export const WebSocket = undefined;
3
+
@@ -0,0 +1,29 @@
1
+ // This file is intentionally in JavaScript to avoid TypeScript/bundler transformations
2
+ // It provides a way to load auth config from the file system in Node.js environments
3
+
4
+ function loadAuthFromFileSystem() {
5
+ try {
6
+ // Check if we're in a Node.js environment
7
+ if (typeof process === 'undefined' || !process.env?.HOME) {
8
+ return undefined;
9
+ }
10
+
11
+ // Use dynamic require to avoid bundler processing
12
+ const fs = eval("require")('fs');
13
+ const path = eval("require")('path');
14
+
15
+ const authPath = path.join(process.env.HOME, '.config', 'circuit', 'auth.json');
16
+
17
+ if (!fs.existsSync(authPath)) {
18
+ return undefined;
19
+ }
20
+
21
+ const authContent = fs.readFileSync(authPath, 'utf-8');
22
+ return JSON.parse(authContent);
23
+ } catch (error) {
24
+ // Silently fail if we can't read the auth config
25
+ return undefined;
26
+ }
27
+ }
28
+
29
+ module.exports = { loadAuthFromFileSystem };