@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 +217 -5
- package/dist/agent.d.ts +3 -2
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +43 -7
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +18 -4
- package/dist/run.d.ts +58 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +108 -0
- package/dist/tunnel.d.ts +189 -0
- package/dist/tunnel.d.ts.map +1 -0
- package/dist/tunnel.js +803 -0
- package/package.json +5 -1
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
|
|
265
|
-
|
|
|
266
|
-
| `OPENSERV_API_KEY`
|
|
267
|
-
| `OPENAI_API_KEY`
|
|
268
|
-
| `PORT`
|
|
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
|
-
*
|
|
68
|
+
* May change if the preferred port is unavailable.
|
|
69
69
|
*/
|
|
70
|
-
|
|
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
|
package/dist/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,aAAa,EAAE,MAAM,OAAO,CAAA;AAUjD,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,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,sBAAsB,EACtB,qBAAqB,EACrB,yBAAyB,EACzB,gBAAgB,EAEhB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAOlB,YAAY,EACZ,kBAAkB,EAClB,8BAA8B,EAC/B,MAAM,SAAS,CAAA;AAEhB,OAAO,KAAK,EACV,0BAA0B,EAE1B,cAAc,EACf,MAAM,mCAAmC,CAAA;AAI1C,OAAO,MAAM,MAAM,QAAQ,CAAA;AAC3B,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAGL,KAAK,eAAe,EAEpB,SAAS,EACV,MAAM,OAAO,CAAA;AAOd;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,MAAM;IAC5C;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAA;IAEpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IAEnE;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAA;CACxC;AAoBD,qBAAa,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IA0H9B,OAAO,CAAC,OAAO;IAzH3B;;;;OAIG;IACH,OAAO,CAAC,GAAG,CAAqB;IAEhC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAA2B;IAEzC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAqB;IAEnC;;;;OAIG;
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,aAAa,EAAE,MAAM,OAAO,CAAA;AAUjD,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,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,sBAAsB,EACtB,qBAAqB,EACrB,yBAAyB,EACzB,gBAAgB,EAEhB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAOlB,YAAY,EACZ,kBAAkB,EAClB,8BAA8B,EAC/B,MAAM,SAAS,CAAA;AAEhB,OAAO,KAAK,EACV,0BAA0B,EAE1B,cAAc,EACf,MAAM,mCAAmC,CAAA;AAI1C,OAAO,MAAM,MAAM,QAAQ,CAAA;AAC3B,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAGL,KAAK,eAAe,EAEpB,SAAS,EACV,MAAM,OAAO,CAAA;AAOd;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,MAAM;IAC5C;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAA;IAEpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IAEnE;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAA;CACxC;AAoBD,qBAAa,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IA0H9B,OAAO,CAAC,OAAO;IAzH3B;;;;OAIG;IACH,OAAO,CAAC,GAAG,CAAqB;IAEhC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAA2B;IAEzC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAqB;IAEnC;;;;OAIG;IACI,IAAI,EAAE,MAAM,CAAA;IAEnB;;;;OAIG;IACH,SAAS,CAAC,YAAY,EAAE,MAAM,CAAA;IAE9B;;;;OAIG;IACH,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAK;IAExD;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAQ;IAEtB;;;;OAIG;IACH,OAAO,CAAC,SAAS,CAAe;IAEhC;;;;OAIG;IACH,SAAS,CAAC,aAAa,EAAE,aAAa,CAAA;IAEtC;;;;OAIG;IACH,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IAE1B;;;OAGG;IACI,UAAU,EAAE,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAgC;IAE1E;;;;;OAKG;IACH,OAAO,KAAK,WAAW,GAStB;IAED;;;;;;OAMG;IACH,OAAO,KAAK,MAAM,GAWjB;IAED;;;;;;;OAOG;gBACiB,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;IAgD5C,OAAO,CAAC,oBAAoB;IAgB5B;;;;;;;;;;;;;;;;OAgBG;IACH,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,EACpC,IAAI,EACJ,WAAW,EACX,MAAM,EACN,GAAG,EACJ,EAAE;QACD,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,EAAE,MAAM,CAAA;QACnB,MAAM,EAAE,CAAC,CAAA;QACT,GAAG,CACD,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EACd,MAAM,EAAE;YAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM,CAAC,EAAE,YAAY,CAAA;SAAE,EACnD,QAAQ,EAAE,0BAA0B,EAAE,GACrC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;KAC5B,GAAG,IAAI;IAYR;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,CAAC,SAAS,SAAS,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,YAAY,EAAE;SACjF,CAAC,IAAI,MAAM,CAAC,GAAG;YACd,IAAI,EAAE,MAAM,CAAA;YACZ,WAAW,EAAE,MAAM,CAAA;YACnB,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;YACZ,GAAG,CACD,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EACd,MAAM,EAAE;gBAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAAC,MAAM,CAAC,EAAE,YAAY,CAAA;aAAE,EACtD,QAAQ,EAAE,0BAA0B,EAAE,GACrC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;SAC5B;KACF,GAAG,IAAI;IAOR;;;;;;OAMG;IACG,QAAQ,CAAC,MAAM,EAAE,cAAc;IAOrC;;;;;OAKG;IACG,UAAU,CAAC,MAAM,EAAE,gBAAgB;IAOzC;;;;;OAKG;IACG,cAAc,CAAC,MAAM,EAAE,oBAAoB;IAOjD;;;;;;;;;;OAUG;IACG,UAAU,CAAC,MAAM,EAAE,gBAAgB;IA6BzC;;;;;;;OAOG;IACG,UAAU,CAAC,MAAM,EAAE,gBAAgB;IAOzC;;;;;;;;OAQG;IACG,iBAAiB,CAAC,MAAM,EAAE,uBAAuB;IAUvD;;;;;;;;OAQG;IACG,YAAY,CAAC,MAAM,EAAE,kBAAkB;IAU7C;;;;;;;;OAQG;IACG,eAAe,CAAC,MAAM,EAAE,qBAAqB;IAUnD;;;;;;;OAOG;IACG,aAAa,CAAC,MAAM,EAAE,mBAAmB;IAO/C;;;;;;OAMG;IACG,SAAS,CAAC,MAAM,EAAE,eAAe;IAOvC;;;;;;OAMG;IACG,QAAQ,CAAC,MAAM,EAAE,cAAc;IAOrC;;;;;;;OAOG;IACG,eAAe,CAAC,MAAM,EAAE,qBAAqB;IAOnD;;;;;;;;;;;;OAYG;IACG,UAAU,CAAC,MAAM,EAAE,gBAAgB;IAezC;;;;;;;;;;OAUG;IACG,YAAY,CAAC,MAAM,EAAE,kBAAkB;IAY7C;;;;;;;;;;OAUG;IACG,sBAAsB,CAAC,MAAM,EAAE,4BAA4B;IA0BjE;;;;;;;;OAQG;IACG,gBAAgB,CAAC,MAAM,EAAE,sBAAsB;IAUrD;;;;;;;OAOG;IACG,OAAO,CAAC,EAAE,QAAQ,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IA4FnE;;;;OAIG;cACa,MAAM,CAAC,MAAM,EAAE,kBAAkB;IA6BjD;;;;OAIG;cACa,aAAa,CAAC,MAAM,EAAE,8BAA8B;IA+BpE;;;;;;;;;;;;;OAaG;IACG,eAAe,CAAC,GAAG,EAAE;QACzB,MAAM,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAA;QAC5B,IAAI,EAAE;YACJ,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;YAC5B,MAAM,CAAC,EAAE,YAAY,CAAA;YACrB,QAAQ,CAAC,EAAE,0BAA0B,EAAE,CAAA;SACxC,CAAA;KACF;;;IAyBD;;;;;;;OAOG;IACG,eAAe,CAAC,GAAG,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE;IAgB5C;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAuBnB;;;;;;OAMG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqF5B;;;;OAIG;IACG,IAAI;IAQV;;;OAGG;IACH,OAAO,CAAC,WAAW;IAOnB;;;;;;;;;;;;;OAaG;IACG,eAAe,CAAC,WAAW,EAAE,sBAAsB;IASzD;;;;;;;;OAQG;IACH,OAAO,CAAC,yBAAyB;CAsClC"}
|
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
|
-
*
|
|
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
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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; } });
|
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY,
|
|
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 = () =>
|
|
9
|
-
|
|
10
|
-
|
|
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
|
+
}
|