@circuitorg/agent-sdk 1.0.12 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -11
- package/index.d.ts +49 -6
- package/index.js +1 -1
- package/package.json +2 -2
- package/utils/auth-loader.cjs +13 -3
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ A TypeScript SDK for building automated agents to deploy on Circuit. Features a
|
|
|
8
8
|
|
|
9
9
|
## ✨ Features
|
|
10
10
|
|
|
11
|
-
- **🎯 Simple API**: Only 2 main methods - `
|
|
11
|
+
- **🎯 Simple API**: Only 2 main methods - `sendLog()` and `signAndSend()`
|
|
12
12
|
- **🔒 Type Safety**: Network parameter determines valid request shapes automatically
|
|
13
13
|
- **🚀 Cross-Chain**: Unified interface for EVM and Solana networks
|
|
14
14
|
|
|
@@ -36,10 +36,10 @@ const sdk = new AgentSdk({
|
|
|
36
36
|
|
|
37
37
|
## 🎯 Core SDK API (Only 2 Methods!)
|
|
38
38
|
|
|
39
|
-
### 1. Add
|
|
39
|
+
### 1. Add Logs to Timeline
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
|
-
await sdk.
|
|
42
|
+
await sdk.sendLog({
|
|
43
43
|
type: "observe",
|
|
44
44
|
shortMessage: "Starting swap operation"
|
|
45
45
|
});
|
|
@@ -104,14 +104,14 @@ const executionFunction: ExecutionFunctionContract = async (request) => {
|
|
|
104
104
|
// Get user's wallet address (use vitalik.eth for demo if no address provided)
|
|
105
105
|
const userAddress = request.sessionWalletAddress
|
|
106
106
|
|
|
107
|
-
await sdk.
|
|
107
|
+
await sdk.sendLog({
|
|
108
108
|
type: "observe",
|
|
109
109
|
shortMessage: `🚀 Agent SDK v1.0 demo - Hello ${userAddress}`
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
return { success: true};
|
|
113
113
|
} catch (error) {
|
|
114
|
-
await sdk.
|
|
114
|
+
await sdk.sendLog({
|
|
115
115
|
type: "error",
|
|
116
116
|
shortMessage: `Agent execution error: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
117
117
|
});
|
|
@@ -126,7 +126,7 @@ const stopFunction: StopFunctionContract = async (request) => {
|
|
|
126
126
|
});
|
|
127
127
|
|
|
128
128
|
try {
|
|
129
|
-
await sdk.
|
|
129
|
+
await sdk.sendLog({
|
|
130
130
|
type: "observe",
|
|
131
131
|
shortMessage: "🛑 Agent stopping with new SDK v1.0"
|
|
132
132
|
});
|
|
@@ -287,7 +287,7 @@ const executionFunction: ExecutionFunctionContract = async (request) => {
|
|
|
287
287
|
});
|
|
288
288
|
|
|
289
289
|
try {
|
|
290
|
-
await sdk.
|
|
290
|
+
await sdk.sendLog({
|
|
291
291
|
type: "observe",
|
|
292
292
|
shortMessage:
|
|
293
293
|
"🚀 Starting Agent SDK v1.0 comprehensive demo -- live test",
|
|
@@ -305,7 +305,7 @@ const executionFunction: ExecutionFunctionContract = async (request) => {
|
|
|
305
305
|
pepeBalance.decimals
|
|
306
306
|
);
|
|
307
307
|
|
|
308
|
-
await sdk.
|
|
308
|
+
await sdk.sendLog({
|
|
309
309
|
type: "observe",
|
|
310
310
|
shortMessage: `PEPE Balance (Arbitrum): ${pepeBalanceFormatted} PEPE`,
|
|
311
311
|
});
|
|
@@ -334,7 +334,7 @@ const executionFunction: ExecutionFunctionContract = async (request) => {
|
|
|
334
334
|
});
|
|
335
335
|
|
|
336
336
|
|
|
337
|
-
await sdk.
|
|
337
|
+
await sdk.sendLog({
|
|
338
338
|
type: "observe",
|
|
339
339
|
shortMessage:
|
|
340
340
|
"✅ Agent SDK v1.0 comprehensive demo completed successfully!",
|
|
@@ -344,7 +344,7 @@ const executionFunction: ExecutionFunctionContract = async (request) => {
|
|
|
344
344
|
} catch (error) {
|
|
345
345
|
console.error("💥 Agent execution error:", error);
|
|
346
346
|
|
|
347
|
-
await sdk.
|
|
347
|
+
await sdk.sendLog({
|
|
348
348
|
type: "error",
|
|
349
349
|
shortMessage: `Agent execution error: ${
|
|
350
350
|
error instanceof Error ? error.message : "Unknown error"
|
|
@@ -375,7 +375,7 @@ const stopFunction: StopFunctionContract = async (request) => {
|
|
|
375
375
|
});
|
|
376
376
|
|
|
377
377
|
try {
|
|
378
|
-
await sdk.
|
|
378
|
+
await sdk.sendLog({
|
|
379
379
|
type: "observe",
|
|
380
380
|
shortMessage: "🛑 Agent stopping with new SDK v1.0",
|
|
381
381
|
});
|
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
|
-
/**
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
/**
|
|
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,19 @@ 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
|
+
|
|
139
162
|
/**
|
|
140
163
|
* Main AgentSdk class with simplified API surface
|
|
141
164
|
*/
|
|
@@ -295,6 +318,13 @@ declare class AgentSdk {
|
|
|
295
318
|
* Send logs to the agent timeline (migrated from AgentToolset)
|
|
296
319
|
*/
|
|
297
320
|
private _sendLog;
|
|
321
|
+
/**
|
|
322
|
+
* Internal method to update job status. Used by the Agent wrapper for automatic tracking.
|
|
323
|
+
*
|
|
324
|
+
* This method is not intended for direct use by agent developers - job status tracking
|
|
325
|
+
* is handled automatically by the Agent wrapper.
|
|
326
|
+
*/
|
|
327
|
+
_updateJobStatus(request: UpdateJobStatusRequest): Promise<UpdateJobStatusResponse>;
|
|
298
328
|
}
|
|
299
329
|
|
|
300
330
|
/**
|
|
@@ -358,6 +388,7 @@ declare class APIClient {
|
|
|
358
388
|
declare const AgentRequestSchema: z.ZodObject<{
|
|
359
389
|
sessionId: z.ZodNumber;
|
|
360
390
|
sessionWalletAddress: z.ZodString;
|
|
391
|
+
jobId: z.ZodOptional<z.ZodString>;
|
|
361
392
|
otherParameters: z.ZodOptional<z.ZodObject<{}, z.core.$strip>>;
|
|
362
393
|
}, z.core.$strip>;
|
|
363
394
|
/**
|
|
@@ -505,7 +536,7 @@ interface AgentConfig {
|
|
|
505
536
|
*
|
|
506
537
|
* Exposes the following endpoints:
|
|
507
538
|
* - `POST /execute` — required, calls your execution function
|
|
508
|
-
* - `POST /stop`
|
|
539
|
+
* - `POST /stop` — always available, uses provided or default stop function
|
|
509
540
|
* - `GET /health` — always available, uses provided or default health check
|
|
510
541
|
*/
|
|
511
542
|
declare class Agent {
|
|
@@ -518,6 +549,18 @@ declare class Agent {
|
|
|
518
549
|
* @param config - Execution function is required; chat/stop/health are optional.
|
|
519
550
|
*/
|
|
520
551
|
constructor(config: AgentConfig);
|
|
552
|
+
/**
|
|
553
|
+
* Default stop function when no custom stop function is provided.
|
|
554
|
+
*/
|
|
555
|
+
private defaultStopFunction;
|
|
556
|
+
/**
|
|
557
|
+
* Execute a function with automatic job status tracking.
|
|
558
|
+
*/
|
|
559
|
+
private executeWithJobTracking;
|
|
560
|
+
/**
|
|
561
|
+
* Update job status using the AgentSdk.
|
|
562
|
+
*/
|
|
563
|
+
private updateJobStatus;
|
|
521
564
|
private setupRoutes;
|
|
522
565
|
private getPortFromPackageJson;
|
|
523
566
|
run(port?: number): {
|
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||!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}}}),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}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 i={...e,headers:s},o=`https://agents-to-api-proxy.circuit-0bc.workers.dev${t}`;r=await n.fetch(o,i)}else{this.logging("Using HTTP fallback to:",this.baseUrl);const n=`${this.baseUrl}${t}`,i={...e,headers:s};r=await fetch(n,i)}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("===================");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"}}}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,n="Unknown error";if(t instanceof Error){n=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:n,errorDetails:{message:r||n,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 n=t.message.match(/HTTP (\d+): (.+)/);n&&(e=Number.parseInt(n[1]),s=n[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"}`}}}};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 n=new AgentSdk({sessionId:t}),i={jobId:e,status:s,...r&&{errorMessage:r}};await n._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})}export{APIClient,Agent,AgentSdk,getChainIdFromNetwork,isEthereumNetwork,isSolanaNetwork};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@circuitorg/agent-sdk",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "typescript sdk for the Agent Toolset Service",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -65,6 +65,6 @@
|
|
|
65
65
|
},
|
|
66
66
|
"repository": {
|
|
67
67
|
"type": "git",
|
|
68
|
-
"url": "git+https://github.com/circuitorg/
|
|
68
|
+
"url": "git+https://github.com/circuitorg/agent-sdk-typescript.git"
|
|
69
69
|
}
|
|
70
70
|
}
|
package/utils/auth-loader.cjs
CHANGED
|
@@ -4,18 +4,28 @@
|
|
|
4
4
|
function loadAuthFromFileSystem() {
|
|
5
5
|
try {
|
|
6
6
|
// Check if we're in a Node.js environment
|
|
7
|
-
if (typeof process === 'undefined'
|
|
7
|
+
if (typeof process === 'undefined') {
|
|
8
8
|
return undefined;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
// Use dynamic require to avoid bundler processing
|
|
12
12
|
const fs = eval("require")('fs');
|
|
13
13
|
const path = eval("require")('path');
|
|
14
|
+
const os = eval("require")('os');
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
// Use os.homedir() for cross-platform compatibility (works on Windows, Mac, Linux)
|
|
17
|
+
const homeDir = os.homedir();
|
|
18
|
+
|
|
19
|
+
// Try main config directory first (matches CLI behavior)
|
|
20
|
+
let authPath = path.join(homeDir, '.config', 'circuit', 'auth.json');
|
|
16
21
|
|
|
17
22
|
if (!fs.existsSync(authPath)) {
|
|
18
|
-
|
|
23
|
+
// Try fallback directory (matches CLI fallback behavior)
|
|
24
|
+
authPath = path.join(homeDir, '.circuit', 'auth.json');
|
|
25
|
+
|
|
26
|
+
if (!fs.existsSync(authPath)) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
19
29
|
}
|
|
20
30
|
|
|
21
31
|
const authContent = fs.readFileSync(authPath, 'utf-8');
|