@openserv-labs/sdk 1.8.2 → 2.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 CHANGED
@@ -6,9 +6,42 @@
6
6
 
7
7
  A powerful TypeScript framework for building non-deterministic AI agents with advanced cognitive capabilities like reasoning, decision-making, and inter-agent collaboration within the OpenServ platform. Built with strong typing, extensible architecture, and a fully autonomous agent runtime.
8
8
 
9
+ ## What's New in v2
10
+
11
+ Version 2.0.0 introduces built-in tunnel support for local development, eliminating the need to deploy your agent to test it with the OpenServ platform.
12
+
13
+ ### Key Changes
14
+
15
+ - **Built-in Tunnel for Local Development** - New `run()` function and `OpenServTunnel` class create a secure WebSocket connection to OpenServ, allowing you to develop and test locally without deploying. No need to configure an Agent Endpoint URL during development.
16
+ - **Automatic Port Fallback** - If your preferred port is busy, the agent automatically finds an available port instead of failing.
17
+ - **Secrets Management** - New `getSecrets()` and `getSecretValue()` methods allow agents to securely access workspace secrets.
18
+ - **Delete File Support** - New `deleteFile()` method for workspace file management.
19
+ - **Increased Request Size Limit** - Body parser limit increased to 10MB for larger payloads.
20
+ - **Enhanced Logging** - Added pino-pretty for more readable log output during development.
21
+
22
+ ### Migration from v1.x
23
+
24
+ The v2 API is backwards compatible. To take advantage of the new tunnel feature for local development, simply replace:
25
+
26
+ ```typescript
27
+ // v1.x - Required deploying to a public URL
28
+ agent.start()
29
+ ```
30
+
31
+ With:
32
+
33
+ ```typescript
34
+ // v2.x - Works locally without deployment
35
+ import { run } from '@openserv-labs/sdk'
36
+ const { stop } = await run(agent)
37
+ ```
38
+
9
39
  ## Table of Contents
10
40
 
11
41
  - [OpenServ TypeScript SDK, Autonomous AI Agent Development Framework](#openserv-typescript-sdk-autonomous-ai-agent-development-framework)
42
+ - [What's New in v2](#whats-new-in-v2)
43
+ - [Key Changes](#key-changes)
44
+ - [Migration from v1.x](#migration-from-v1x)
12
45
  - [Table of Contents](#table-of-contents)
13
46
  - [Features](#features)
14
47
  - [Framework Architecture](#framework-architecture)
@@ -39,10 +72,24 @@ A powerful TypeScript framework for building non-deterministic AI agents with ad
39
72
  - [Workspace Management](#workspace-management)
40
73
  - [Get Files](#get-files)
41
74
  - [Upload File](#upload-file)
75
+ - [Delete File](#delete-file)
76
+ - [Secrets Management](#secrets-management)
77
+ - [Get Secrets](#get-secrets)
78
+ - [Get Secret Value](#get-secret-value)
42
79
  - [Integration Management](#integration-management)
43
80
  - [Call Integration](#call-integration)
44
81
  - [MCP](#mcp)
82
+ - [Configure MCP servers](#configure-mcp-servers)
83
+ - [Local (stdio) transport](#local-stdio-transport)
84
+ - [Server-Sent Events (sse) transport](#server-sent-events-sse-transport)
85
+ - [Using MCP tools](#using-mcp-tools)
45
86
  - [Advanced Usage](#advanced-usage)
87
+ - [Local Development with Tunnel](#local-development-with-tunnel)
88
+ - [How It Works](#how-it-works)
89
+ - [Quick Start](#quick-start-1)
90
+ - [Tunnel vs. Deployed Endpoint](#tunnel-vs-deployed-endpoint)
91
+ - [Configuration Options](#configuration-options)
92
+ - [Using the Tunnel Directly](#using-the-tunnel-directly)
46
93
  - [OpenAI Process Runtime](#openai-process-runtime)
47
94
  - [Error Handling](#error-handling)
48
95
  - [Custom Agents](#custom-agents)
@@ -64,6 +111,7 @@ A powerful TypeScript framework for building non-deterministic AI agents with ad
64
111
  - 📝 Strong TypeScript typing with Zod schemas
65
112
  - 📊 Built-in logging and error handling
66
113
  - 🎯 Three levels of control for different development needs
114
+ - 🚇 Built-in tunnel for local development and testing
67
115
 
68
116
  ## Framework Architecture
69
117
 
@@ -257,15 +305,21 @@ agent.addCapabilities([
257
305
 
258
306
  // Start the agent server
259
307
  agent.start()
308
+
309
+ // Or use run() for local development with automatic tunnel management
310
+ // import { run } from '@openserv-labs/sdk'
311
+ // const { stop } = await run(agent)
260
312
  ```
261
313
 
262
314
  ## Environment Variables
263
315
 
264
- | Variable | Description | Required | Default |
265
- | ------------------ | ------------------------------------- | -------- | ------- |
266
- | `OPENSERV_API_KEY` | Your OpenServ API key | Yes | - |
267
- | `OPENAI_API_KEY` | OpenAI API key (for process() method) | No\* | - |
268
- | `PORT` | Server port | No | 7378 |
316
+ | Variable | Description | Required | Default |
317
+ | --------------------- | ------------------------------------------ | -------- | ---------------------------------- |
318
+ | `OPENSERV_API_KEY` | Your OpenServ API key | Yes | - |
319
+ | `OPENAI_API_KEY` | OpenAI API key (for process() method) | No\* | - |
320
+ | `PORT` | Server port | No | 7378 |
321
+ | `OPENSERV_AUTH_TOKEN` | Token for authenticating incoming requests | No | - |
322
+ | `OPENSERV_PROXY_URL` | Custom proxy URL for tunnel connections | No | `https://agents-proxy.openserv.ai` |
269
323
 
270
324
  \*Required if using OpenAI integration features
271
325
 
@@ -528,6 +582,61 @@ await agent.uploadFile({
528
582
  })
529
583
  ```
530
584
 
585
+ #### Delete File
586
+
587
+ ```typescript
588
+ await agent.deleteFile({
589
+ workspaceId: number | string,
590
+ fileId: number
591
+ })
592
+ ```
593
+
594
+ ### Secrets Management
595
+
596
+ Agents can securely access secrets configured in their workspace. Secrets are managed through the OpenServ platform.
597
+
598
+ #### Get Secrets
599
+
600
+ Returns a list of all secrets available to the agent in a workspace.
601
+
602
+ ```typescript
603
+ const secrets = await agent.getSecrets({
604
+ workspaceId: number | string
605
+ })
606
+ // Returns: { id: number, name: string }[]
607
+ ```
608
+
609
+ #### Get Secret Value
610
+
611
+ Retrieves the actual value of a specific secret.
612
+
613
+ ```typescript
614
+ const value = await agent.getSecretValue({
615
+ workspaceId: number | string,
616
+ secretId: number
617
+ })
618
+ // Returns: string
619
+ ```
620
+
621
+ **Example:**
622
+
623
+ ```typescript
624
+ // Get all available secrets
625
+ const secrets = await agent.getSecrets({ workspaceId: 123 })
626
+
627
+ // Find a specific secret by name
628
+ const apiKeySecret = secrets.find(s => s.name === 'EXTERNAL_API_KEY')
629
+
630
+ if (apiKeySecret) {
631
+ // Retrieve the secret value
632
+ const apiKey = await agent.getSecretValue({
633
+ workspaceId: 123,
634
+ secretId: apiKeySecret.id
635
+ })
636
+ // Use the secret value securely
637
+ }
638
+ ```
639
+
531
640
  ### Integration Management
532
641
 
533
642
  #### Call Integration
@@ -633,6 +742,109 @@ You can also access the raw MCP client via `agent.mcpClients['MCP_SERVER_ID']` t
633
742
 
634
743
  ## Advanced Usage
635
744
 
745
+ ### Local Development with Tunnel
746
+
747
+ The SDK provides a built-in tunnel that connects your locally running agent to the OpenServ platform. This eliminates the need to deploy your agent to a public URL during development.
748
+
749
+ #### How It Works
750
+
751
+ When you use the `run()` function or `OpenServTunnel` class:
752
+
753
+ 1. Your agent starts an HTTP server locally (default port 7378)
754
+ 2. A WebSocket connection is established to OpenServ's proxy server
755
+ 3. The proxy authenticates your agent using your `OPENSERV_API_KEY`
756
+ 4. OpenServ routes incoming tasks through the tunnel to your local machine
757
+
758
+ **No Agent Endpoint URL configuration is needed during local development.** The tunnel connection is identified by your API key, which is already associated with your registered agent in the OpenServ platform.
759
+
760
+ #### Quick Start
761
+
762
+ ```typescript
763
+ import { Agent, run } from '@openserv-labs/sdk'
764
+ import { z } from 'zod'
765
+
766
+ const agent = new Agent({
767
+ systemPrompt: 'You are a helpful assistant.'
768
+ })
769
+
770
+ agent.addCapability({
771
+ name: 'greet',
772
+ description: 'Greet someone',
773
+ schema: z.object({ name: z.string() }),
774
+ async run({ args }) {
775
+ return `Hello, ${args.name}!`
776
+ }
777
+ })
778
+
779
+ // Start the agent with automatic tunnel management
780
+ const { tunnel, stop } = await run(agent)
781
+
782
+ // The agent is now connected to OpenServ and ready to receive tasks
783
+
784
+ // To gracefully stop the agent and tunnel:
785
+ await stop()
786
+ ```
787
+
788
+ The `run()` function automatically:
789
+
790
+ - Starts the agent's HTTP server
791
+ - Creates a WebSocket tunnel to the OpenServ proxy
792
+ - Handles reconnection with exponential backoff (up to 10 retries)
793
+ - Registers signal handlers for graceful shutdown (SIGTERM, SIGINT)
794
+
795
+ #### Tunnel vs. Deployed Endpoint
796
+
797
+ | Aspect | Tunnel (Local Development) | Deployed Endpoint (Production) |
798
+ | ----------------- | -------------------------- | ------------------------------ |
799
+ | Setup | Just run your code | Deploy to cloud/server |
800
+ | URL Configuration | Not needed | Set Agent Endpoint in platform |
801
+ | Connection | WebSocket via proxy | Direct HTTP |
802
+ | Use case | Development & testing | Production |
803
+
804
+ #### Configuration Options
805
+
806
+ ```typescript
807
+ const { tunnel, stop } = await run(agent, {
808
+ // Tunnel-specific options
809
+ tunnel: {
810
+ apiKey: 'your-api-key', // Defaults to OPENSERV_API_KEY env var
811
+ proxyUrl: 'custom-proxy-url' // Defaults to OPENSERV_PROXY_URL env var
812
+ },
813
+ // Disable automatic signal handlers if you want to handle shutdown yourself
814
+ handleSignals: false
815
+ })
816
+ ```
817
+
818
+ #### Using the Tunnel Directly
819
+
820
+ For more advanced control, you can use the `OpenServTunnel` class directly:
821
+
822
+ ```typescript
823
+ import { Agent, OpenServTunnel } from '@openserv-labs/sdk'
824
+
825
+ const agent = new Agent({
826
+ systemPrompt: 'You are a helpful assistant.'
827
+ })
828
+
829
+ await agent.start()
830
+
831
+ const tunnel = new OpenServTunnel({
832
+ apiKey: process.env.OPENSERV_API_KEY,
833
+ onConnected: isReconnect => {
834
+ console.log(isReconnect ? 'Reconnected!' : 'Connected!')
835
+ },
836
+ onError: error => {
837
+ console.error('Tunnel error:', error.message)
838
+ }
839
+ })
840
+
841
+ await tunnel.start(agent.port)
842
+
843
+ // Later, to stop:
844
+ await tunnel.stop()
845
+ await agent.stop()
846
+ ```
847
+
636
848
  ### OpenAI Process Runtime
637
849
 
638
850
  The framework includes built-in OpenAI function calling support through the `process()` method:
package/dist/agent.d.ts CHANGED
@@ -65,9 +65,9 @@ export declare class Agent<M extends string = string> {
65
65
  /**
66
66
  * The port number the server will listen on.
67
67
  * Defaults to DEFAULT_PORT (7378) if not specified in options.
68
- * @private
68
+ * May change if the preferred port is unavailable.
69
69
  */
70
- private port;
70
+ port: number;
71
71
  /**
72
72
  * The system prompt used for OpenAI chat completions.
73
73
  * This defines the base behavior and context for the agent.
@@ -405,6 +405,7 @@ export declare class Agent<M extends string = string> {
405
405
  private setupRoutes;
406
406
  /**
407
407
  * Starts the agent's HTTP server.
408
+ * If the preferred port is unavailable, it will find an open port.
408
409
  *
409
410
  * @returns {Promise<void>} Resolves when the server has started
410
411
  * @throws {Error} If server fails to start
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
package/dist/agent.js CHANGED
@@ -58,7 +58,7 @@ class Agent {
58
58
  /**
59
59
  * The port number the server will listen on.
60
60
  * Defaults to DEFAULT_PORT (7378) if not specified in options.
61
- * @private
61
+ * May change if the preferred port is unavailable.
62
62
  */
63
63
  port;
64
64
  /**
@@ -169,7 +169,7 @@ class Agent {
169
169
  'x-openserv-key': this.apiKey
170
170
  }
171
171
  });
172
- this.app.use(express_1.default.json());
172
+ this.app.use(express_1.default.json({ limit: '10mb' }));
173
173
  this.app.use(express_1.default.urlencoded({ extended: false }));
174
174
  this.app.use((0, hpp_1.default)());
175
175
  this.app.use((0, helmet_1.default)());
@@ -737,17 +737,53 @@ class Agent {
737
737
  }
738
738
  /**
739
739
  * Starts the agent's HTTP server.
740
+ * If the preferred port is unavailable, it will find an open port.
740
741
  *
741
742
  * @returns {Promise<void>} Resolves when the server has started
742
743
  * @throws {Error} If server fails to start
743
744
  */
744
745
  async start() {
746
+ const preferredPort = this.port;
747
+ // Try the preferred port first, fallback to an available port if it fails
745
748
  await new Promise((resolve, reject) => {
746
- this.server = this.app.listen(this.port, () => {
747
- logger_1.logger.info(`Agent server started on port ${this.port}`);
748
- resolve();
749
- });
750
- this.server.on('error', reject);
749
+ const tryListen = (port, isRetry) => {
750
+ const server = this.app.listen(port);
751
+ const onListening = () => {
752
+ // Remove the startup handlers once listening succeeds
753
+ server.removeListener('error', errorHandler);
754
+ server.removeListener('listening', onListening);
755
+ if (isRetry) {
756
+ const address = server.address();
757
+ if (address && typeof address === 'object') {
758
+ this.port = address.port;
759
+ logger_1.logger.info(`Port ${preferredPort} was unavailable, using port ${this.port} instead`);
760
+ }
761
+ }
762
+ else {
763
+ logger_1.logger.info(`Agent server started on port ${this.port}`);
764
+ }
765
+ this.server = server;
766
+ resolve();
767
+ };
768
+ const errorHandler = (err) => {
769
+ // Clean up the failed server before handling the error
770
+ server.removeListener('error', errorHandler);
771
+ server.removeListener('listening', onListening);
772
+ // Close the failed server to release resources
773
+ server.close();
774
+ if (err.code === 'EADDRINUSE' && !isRetry) {
775
+ logger_1.logger.warn(`Port ${this.port} is in use, finding an available port...`);
776
+ // Let the OS assign an available port
777
+ tryListen(0, true);
778
+ }
779
+ else {
780
+ reject(err);
781
+ }
782
+ };
783
+ server.on('listening', onListening);
784
+ server.on('error', errorHandler);
785
+ };
786
+ tryListen(this.port, false);
751
787
  });
752
788
  const connectionPromises = Object.values(this.mcpClients).map(client => client.connect());
753
789
  const results = await Promise.allSettled(connectionPromises);
package/dist/index.d.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  export { Agent } from './agent';
2
2
  export type { AgentOptions } from './agent';
3
3
  export { Capability } from './capability';
4
+ export { OpenServTunnel } from './tunnel';
5
+ export type { OpenServTunnelOptions, RequestData, ResponseData, TunnelState, TunnelEvent } from './tunnel';
6
+ export { run } from './run';
7
+ export type { RunOptions, RunResult } from './run';
4
8
  export type { TaskStatus, GetFilesParams, UploadFileParams, DeleteFileParams, MarkTaskAsErroredParams, CompleteTaskParams, SendChatMessageParams, GetTaskDetailParams, GetAgentsParams, GetTasksParams, CreateTaskParams, AddLogToTaskParams, RequestHumanAssistanceParams, UpdateTaskStatusParams, ProcessParams, CapabilityFuncParams, GetChatMessagesParams } from './types';
5
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,YAAY,EACV,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,4BAA4B,EAC5B,sBAAsB,EACtB,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AACzC,YAAY,EACV,qBAAqB,EACrB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,WAAW,EACZ,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAC3B,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAElD,YAAY,EACV,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,4BAA4B,EAC5B,sBAAsB,EACtB,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,SAAS,CAAA"}
package/dist/index.js CHANGED
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Capability = exports.Agent = void 0;
3
+ exports.run = exports.OpenServTunnel = exports.Capability = exports.Agent = void 0;
4
4
  var agent_1 = require("./agent");
5
5
  Object.defineProperty(exports, "Agent", { enumerable: true, get: function () { return agent_1.Agent; } });
6
6
  var capability_1 = require("./capability");
7
7
  Object.defineProperty(exports, "Capability", { enumerable: true, get: function () { return capability_1.Capability; } });
8
+ var tunnel_1 = require("./tunnel");
9
+ Object.defineProperty(exports, "OpenServTunnel", { enumerable: true, get: function () { return tunnel_1.OpenServTunnel; } });
10
+ var run_1 = require("./run");
11
+ Object.defineProperty(exports, "run", { enumerable: true, get: function () { return run_1.run; } });
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY,6CAIrB,CAAA;AAEJ,eAAO,MAAM,MAAM,uCAAiB,CAAA"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY,6CAmBxB,CAAA;AAED,eAAO,MAAM,MAAM,uCAAiB,CAAA"}
package/dist/logger.js CHANGED
@@ -5,9 +5,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.logger = exports.createLogger = void 0;
7
7
  const pino_1 = __importDefault(require("pino"));
8
- const createLogger = () => (0, pino_1.default)({
9
- name: 'openserv-agent',
10
- level: process.env.LOG_LEVEL || 'info'
11
- });
8
+ const createLogger = () => {
9
+ const isPretty = process.env.LOG_PRETTY === 'true' ||
10
+ (process.env.NODE_ENV !== 'production' && process.stdout.isTTY);
11
+ return (0, pino_1.default)({
12
+ name: 'openserv-agent',
13
+ level: process.env.LOG_LEVEL || 'info',
14
+ transport: isPretty
15
+ ? {
16
+ target: 'pino-pretty',
17
+ options: {
18
+ colorize: true,
19
+ translateTime: 'SYS:standard',
20
+ ignore: 'pid,hostname'
21
+ }
22
+ }
23
+ : undefined
24
+ });
25
+ };
12
26
  exports.createLogger = createLogger;
13
27
  exports.logger = (0, exports.createLogger)();
package/dist/run.d.ts ADDED
@@ -0,0 +1,58 @@
1
+ import type { Agent } from './agent';
2
+ import { OpenServTunnel, type OpenServTunnelOptions } from './tunnel';
3
+ export interface RunOptions {
4
+ /**
5
+ * Options for the OpenServ tunnel.
6
+ * If not provided, defaults will be used (API key from env, default proxy URL).
7
+ */
8
+ tunnel?: Omit<OpenServTunnelOptions, 'onConnected' | 'onRequest' | 'onError'>;
9
+ /**
10
+ * Whether to register signal handlers for graceful shutdown (SIGTERM, SIGINT).
11
+ * Defaults to true.
12
+ */
13
+ handleSignals?: boolean;
14
+ }
15
+ export interface RunResult {
16
+ /**
17
+ * The tunnel instance for advanced control.
18
+ */
19
+ tunnel: OpenServTunnel;
20
+ /**
21
+ * Stop the agent and tunnel.
22
+ */
23
+ stop: () => Promise<void>;
24
+ }
25
+ /**
26
+ * Run an agent with automatic tunnel management.
27
+ *
28
+ * This function handles:
29
+ * 1. Starting the agent's HTTP server
30
+ * 2. Creating a tunnel to connect to the OpenServ proxy
31
+ *
32
+ * @param agent - The Agent instance to run
33
+ * @param options - Optional configuration for the tunnel
34
+ * @returns Run result with tunnel and stop function
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * import { Agent, run } from '@openserv-labs/sdk'
39
+ *
40
+ * const agent = new Agent({
41
+ * systemPrompt: 'You are a helpful assistant.'
42
+ * })
43
+ *
44
+ * agent.addCapability({
45
+ * name: 'greet',
46
+ * description: 'Greet someone',
47
+ * schema: z.object({ name: z.string() }),
48
+ * run: async ({ args }) => `Hello, ${args.name}!`
49
+ * })
50
+ *
51
+ * const { stop } = await run(agent)
52
+ *
53
+ * // Later, to stop:
54
+ * await stop()
55
+ * ```
56
+ */
57
+ export declare function run(agent: Agent, options?: RunOptions): Promise<RunResult>;
58
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,UAAU,CAAA;AAMrE,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,aAAa,GAAG,WAAW,GAAG,SAAS,CAAC,CAAA;IAE7E;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,MAAM,EAAE,cAAc,CAAA;IAEtB;;OAEG;IACH,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1B;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CA2EhF"}
package/dist/run.js ADDED
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.run = run;
4
+ const logger_1 = require("./logger");
5
+ const tunnel_1 = require("./tunnel");
6
+ // ============================================================================
7
+ // Main Run Function
8
+ // ============================================================================
9
+ /**
10
+ * Run an agent with automatic tunnel management.
11
+ *
12
+ * This function handles:
13
+ * 1. Starting the agent's HTTP server
14
+ * 2. Creating a tunnel to connect to the OpenServ proxy
15
+ *
16
+ * @param agent - The Agent instance to run
17
+ * @param options - Optional configuration for the tunnel
18
+ * @returns Run result with tunnel and stop function
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * import { Agent, run } from '@openserv-labs/sdk'
23
+ *
24
+ * const agent = new Agent({
25
+ * systemPrompt: 'You are a helpful assistant.'
26
+ * })
27
+ *
28
+ * agent.addCapability({
29
+ * name: 'greet',
30
+ * description: 'Greet someone',
31
+ * schema: z.object({ name: z.string() }),
32
+ * run: async ({ args }) => `Hello, ${args.name}!`
33
+ * })
34
+ *
35
+ * const { stop } = await run(agent)
36
+ *
37
+ * // Later, to stop:
38
+ * await stop()
39
+ * ```
40
+ */
41
+ async function run(agent, options) {
42
+ await agent.start();
43
+ const tunnel = new tunnel_1.OpenServTunnel({
44
+ ...options?.tunnel,
45
+ onConnected: isReconnect => {
46
+ if (!isReconnect) {
47
+ logger_1.logger.info('Agent connected to OpenServ proxy');
48
+ }
49
+ },
50
+ onError: error => {
51
+ logger_1.logger.error(`Tunnel error: ${error.message}`);
52
+ }
53
+ });
54
+ try {
55
+ await tunnel.start(agent.port);
56
+ }
57
+ catch (error) {
58
+ // Clean up the agent if tunnel fails to connect
59
+ await agent.stop();
60
+ throw error;
61
+ }
62
+ let shutdownPromise = null;
63
+ let sigtermHandler = null;
64
+ let sigintHandler = null;
65
+ const stop = async () => {
66
+ // Return existing shutdown promise if already in progress
67
+ // This ensures concurrent callers wait for actual completion
68
+ if (shutdownPromise)
69
+ return shutdownPromise;
70
+ shutdownPromise = (async () => {
71
+ // Remove signal handlers to prevent stale references on repeated run() calls
72
+ if (sigtermHandler) {
73
+ process.removeListener('SIGTERM', sigtermHandler);
74
+ sigtermHandler = null;
75
+ }
76
+ if (sigintHandler) {
77
+ process.removeListener('SIGINT', sigintHandler);
78
+ sigintHandler = null;
79
+ }
80
+ await tunnel.stop();
81
+ await agent.stop();
82
+ })();
83
+ return shutdownPromise;
84
+ };
85
+ // Register signal handlers for graceful shutdown (default: true)
86
+ const handleSignals = options?.handleSignals !== false;
87
+ if (handleSignals) {
88
+ const signalHandler = (signal) => {
89
+ logger_1.logger.info(`Received ${signal}, shutting down gracefully...`);
90
+ stop()
91
+ .then(() => {
92
+ process.exit(0);
93
+ })
94
+ .catch(err => {
95
+ logger_1.logger.error(`Error during shutdown: ${err.message}`);
96
+ process.exit(1);
97
+ });
98
+ };
99
+ sigtermHandler = () => signalHandler('SIGTERM');
100
+ sigintHandler = () => signalHandler('SIGINT');
101
+ process.once('SIGTERM', sigtermHandler);
102
+ process.once('SIGINT', sigintHandler);
103
+ }
104
+ return {
105
+ tunnel,
106
+ stop
107
+ };
108
+ }