@agentick/gateway 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +477 -0
- package/dist/agent-registry.d.ts +51 -0
- package/dist/agent-registry.d.ts.map +1 -0
- package/dist/agent-registry.js +78 -0
- package/dist/agent-registry.js.map +1 -0
- package/dist/app-registry.d.ts +51 -0
- package/dist/app-registry.d.ts.map +1 -0
- package/dist/app-registry.js +78 -0
- package/dist/app-registry.js.map +1 -0
- package/dist/bin.d.ts +8 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +37 -0
- package/dist/bin.js.map +1 -0
- package/dist/gateway.d.ts +165 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +1339 -0
- package/dist/gateway.js.map +1 -0
- package/dist/http-transport.d.ts +65 -0
- package/dist/http-transport.d.ts.map +1 -0
- package/dist/http-transport.js +517 -0
- package/dist/http-transport.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.d.ts +162 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +16 -0
- package/dist/protocol.js.map +1 -0
- package/dist/session-manager.d.ts +101 -0
- package/dist/session-manager.d.ts.map +1 -0
- package/dist/session-manager.js +208 -0
- package/dist/session-manager.js.map +1 -0
- package/dist/testing.d.ts +92 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +129 -0
- package/dist/testing.js.map +1 -0
- package/dist/transport-protocol.d.ts +162 -0
- package/dist/transport-protocol.d.ts.map +1 -0
- package/dist/transport-protocol.js +16 -0
- package/dist/transport-protocol.js.map +1 -0
- package/dist/transport.d.ts +115 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +56 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +314 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +37 -0
- package/dist/types.js.map +1 -0
- package/dist/websocket-server.d.ts +87 -0
- package/dist/websocket-server.d.ts.map +1 -0
- package/dist/websocket-server.js +245 -0
- package/dist/websocket-server.js.map +1 -0
- package/dist/ws-transport.d.ts +17 -0
- package/dist/ws-transport.d.ts.map +1 -0
- package/dist/ws-transport.js +174 -0
- package/dist/ws-transport.js.map +1 -0
- package/package.json +51 -0
- package/src/__tests__/custom-methods.spec.ts +220 -0
- package/src/__tests__/gateway-methods.spec.ts +262 -0
- package/src/__tests__/gateway.spec.ts +404 -0
- package/src/__tests__/guards.spec.ts +235 -0
- package/src/__tests__/protocol.spec.ts +58 -0
- package/src/__tests__/session-manager.spec.ts +220 -0
- package/src/__tests__/ws-transport.spec.ts +246 -0
- package/src/app-registry.ts +103 -0
- package/src/bin.ts +38 -0
- package/src/gateway.ts +1712 -0
- package/src/http-transport.ts +623 -0
- package/src/index.ts +94 -0
- package/src/session-manager.ts +272 -0
- package/src/testing.ts +236 -0
- package/src/transport-protocol.ts +249 -0
- package/src/transport.ts +191 -0
- package/src/types.ts +392 -0
- package/src/websocket-server.ts +303 -0
- package/src/ws-transport.ts +205 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Protocol Types
|
|
3
|
+
*
|
|
4
|
+
* Defines the WebSocket message protocol between clients and the gateway.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Client → Gateway Messages
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
export interface ConnectMessage {
|
|
12
|
+
type: "connect";
|
|
13
|
+
clientId: string;
|
|
14
|
+
token?: string;
|
|
15
|
+
metadata?: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface RequestMessage {
|
|
19
|
+
type: "req";
|
|
20
|
+
id: string;
|
|
21
|
+
method: GatewayMethod;
|
|
22
|
+
params: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface PingMessage {
|
|
26
|
+
type: "ping";
|
|
27
|
+
timestamp: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type ClientMessage = ConnectMessage | RequestMessage | PingMessage;
|
|
31
|
+
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// Gateway → Client Messages
|
|
34
|
+
// ============================================================================
|
|
35
|
+
|
|
36
|
+
export interface ConnectedMessage {
|
|
37
|
+
type: "connected";
|
|
38
|
+
gatewayId: string;
|
|
39
|
+
apps: string[];
|
|
40
|
+
sessions: string[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ResponseMessage {
|
|
44
|
+
type: "res";
|
|
45
|
+
id: string;
|
|
46
|
+
ok: boolean;
|
|
47
|
+
payload?: unknown;
|
|
48
|
+
error?: {
|
|
49
|
+
code: string;
|
|
50
|
+
message: string;
|
|
51
|
+
details?: unknown;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface EventMessage {
|
|
56
|
+
type: "event";
|
|
57
|
+
event: GatewayEventType;
|
|
58
|
+
sessionId: string;
|
|
59
|
+
data: unknown;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface PongMessage {
|
|
63
|
+
type: "pong";
|
|
64
|
+
timestamp: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface ErrorMessage {
|
|
68
|
+
type: "error";
|
|
69
|
+
code: string;
|
|
70
|
+
message: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export type GatewayMessage =
|
|
74
|
+
| ConnectedMessage
|
|
75
|
+
| ResponseMessage
|
|
76
|
+
| EventMessage
|
|
77
|
+
| PongMessage
|
|
78
|
+
| ErrorMessage;
|
|
79
|
+
|
|
80
|
+
// ============================================================================
|
|
81
|
+
// RPC Methods
|
|
82
|
+
// ============================================================================
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Built-in gateway methods with autocomplete support.
|
|
86
|
+
*/
|
|
87
|
+
export type BuiltInMethod =
|
|
88
|
+
| "send" // Send message to session
|
|
89
|
+
| "abort" // Abort current execution
|
|
90
|
+
| "status" // Get gateway/session status
|
|
91
|
+
| "history" // Get conversation history
|
|
92
|
+
| "reset" // Reset a session
|
|
93
|
+
| "close" // Close a session
|
|
94
|
+
| "apps" // List available apps
|
|
95
|
+
| "sessions" // List sessions
|
|
96
|
+
| "subscribe" // Subscribe to session events
|
|
97
|
+
| "unsubscribe"; // Unsubscribe from events
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Gateway method - built-in methods or custom method strings.
|
|
101
|
+
* The (string & {}) allows any string while preserving autocomplete for built-in methods.
|
|
102
|
+
*/
|
|
103
|
+
export type GatewayMethod = BuiltInMethod | (string & {});
|
|
104
|
+
|
|
105
|
+
// ============================================================================
|
|
106
|
+
// Event Types
|
|
107
|
+
// ============================================================================
|
|
108
|
+
|
|
109
|
+
export type GatewayEventType =
|
|
110
|
+
| "content_delta"
|
|
111
|
+
| "content_block_start"
|
|
112
|
+
| "content_block_end"
|
|
113
|
+
| "tool_call_start"
|
|
114
|
+
| "tool_call_delta"
|
|
115
|
+
| "tool_result"
|
|
116
|
+
| "message_start"
|
|
117
|
+
| "message_end"
|
|
118
|
+
| "error";
|
|
119
|
+
|
|
120
|
+
// ============================================================================
|
|
121
|
+
// Method Parameters
|
|
122
|
+
// ============================================================================
|
|
123
|
+
|
|
124
|
+
export interface SendParams {
|
|
125
|
+
sessionId: string;
|
|
126
|
+
message: string;
|
|
127
|
+
attachments?: Array<{
|
|
128
|
+
type: "image" | "file";
|
|
129
|
+
data: string;
|
|
130
|
+
mimeType: string;
|
|
131
|
+
name?: string;
|
|
132
|
+
}>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface AbortParams {
|
|
136
|
+
sessionId: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface StatusParams {
|
|
140
|
+
sessionId?: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface HistoryParams {
|
|
144
|
+
sessionId: string;
|
|
145
|
+
limit?: number;
|
|
146
|
+
before?: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface ResetParams {
|
|
150
|
+
sessionId: string;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface CloseParams {
|
|
154
|
+
sessionId: string;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface SubscribeParams {
|
|
158
|
+
sessionId: string;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export interface UnsubscribeParams {
|
|
162
|
+
sessionId: string;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ============================================================================
|
|
166
|
+
// Response Payloads
|
|
167
|
+
// ============================================================================
|
|
168
|
+
|
|
169
|
+
export interface StatusPayload {
|
|
170
|
+
gateway: {
|
|
171
|
+
id: string;
|
|
172
|
+
uptime: number;
|
|
173
|
+
clients: number;
|
|
174
|
+
sessions: number;
|
|
175
|
+
apps: string[];
|
|
176
|
+
};
|
|
177
|
+
session?: {
|
|
178
|
+
id: string;
|
|
179
|
+
appId: string;
|
|
180
|
+
messageCount: number;
|
|
181
|
+
createdAt: string;
|
|
182
|
+
lastActivityAt: string;
|
|
183
|
+
isActive: boolean;
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface HistoryPayload {
|
|
188
|
+
messages: Array<{
|
|
189
|
+
id: string;
|
|
190
|
+
role: "user" | "assistant" | "system";
|
|
191
|
+
content: string;
|
|
192
|
+
timestamp: string;
|
|
193
|
+
toolCalls?: Array<{
|
|
194
|
+
name: string;
|
|
195
|
+
input: unknown;
|
|
196
|
+
output?: unknown;
|
|
197
|
+
}>;
|
|
198
|
+
}>;
|
|
199
|
+
hasMore: boolean;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface AppsPayload {
|
|
203
|
+
apps: Array<{
|
|
204
|
+
id: string;
|
|
205
|
+
name: string;
|
|
206
|
+
description?: string;
|
|
207
|
+
isDefault: boolean;
|
|
208
|
+
}>;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export interface SessionsPayload {
|
|
212
|
+
sessions: Array<{
|
|
213
|
+
id: string;
|
|
214
|
+
appId: string;
|
|
215
|
+
createdAt: string;
|
|
216
|
+
lastActivityAt: string;
|
|
217
|
+
messageCount: number;
|
|
218
|
+
}>;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ============================================================================
|
|
222
|
+
// Session Key Format
|
|
223
|
+
// ============================================================================
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Session keys follow the format: [app:]name
|
|
227
|
+
*
|
|
228
|
+
* Examples:
|
|
229
|
+
* - "main" → default app, "main" session
|
|
230
|
+
* - "chat:main" → "chat" app, "main" session
|
|
231
|
+
* - "research:task-123" → "research" app, "task-123" session
|
|
232
|
+
* - "whatsapp:+1234567890" → WhatsApp channel session
|
|
233
|
+
*/
|
|
234
|
+
export interface SessionKey {
|
|
235
|
+
appId: string;
|
|
236
|
+
sessionName: string;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export function parseSessionKey(key: string, defaultApp: string): SessionKey {
|
|
240
|
+
const parts = key.split(":");
|
|
241
|
+
if (parts.length === 1) {
|
|
242
|
+
return { appId: defaultApp, sessionName: parts[0] };
|
|
243
|
+
}
|
|
244
|
+
return { appId: parts[0], sessionName: parts.slice(1).join(":") };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function formatSessionKey(key: SessionKey): string {
|
|
248
|
+
return `${key.appId}:${key.sessionName}`;
|
|
249
|
+
}
|
package/src/transport.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Transport Interface
|
|
3
|
+
*
|
|
4
|
+
* Abstracts the transport layer (WebSocket, HTTP/SSE) from gateway business logic.
|
|
5
|
+
* This allows the same GatewayCore to serve clients via different protocols.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Message } from "@agentick/shared";
|
|
9
|
+
import { validateAuth, type AuthResult } from "@agentick/server";
|
|
10
|
+
import type { GatewayMessage, ClientMessage } from "./transport-protocol.js";
|
|
11
|
+
import type { AuthConfig, ClientState, UserContext } from "./types.js";
|
|
12
|
+
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Transport Interface
|
|
15
|
+
// ============================================================================
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A connected client from the transport's perspective.
|
|
19
|
+
*/
|
|
20
|
+
export interface TransportClient {
|
|
21
|
+
/** Unique client identifier */
|
|
22
|
+
readonly id: string;
|
|
23
|
+
|
|
24
|
+
/** Client state (auth, subscriptions, etc.) */
|
|
25
|
+
readonly state: ClientState;
|
|
26
|
+
|
|
27
|
+
/** Send a message to this client */
|
|
28
|
+
send(message: GatewayMessage): void;
|
|
29
|
+
|
|
30
|
+
/** Close the connection */
|
|
31
|
+
close(code?: number, reason?: string): void;
|
|
32
|
+
|
|
33
|
+
/** Check if connected */
|
|
34
|
+
readonly isConnected: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Events emitted by a transport.
|
|
39
|
+
*/
|
|
40
|
+
export interface TransportEvents {
|
|
41
|
+
/** Client connected (may not be authenticated yet) */
|
|
42
|
+
connection: (client: TransportClient) => void;
|
|
43
|
+
|
|
44
|
+
/** Client disconnected */
|
|
45
|
+
disconnect: (clientId: string, reason?: string) => void;
|
|
46
|
+
|
|
47
|
+
/** Message received from authenticated client */
|
|
48
|
+
message: (clientId: string, message: ClientMessage) => void;
|
|
49
|
+
|
|
50
|
+
/** Transport error */
|
|
51
|
+
error: (error: Error) => void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Transport configuration.
|
|
56
|
+
*/
|
|
57
|
+
export interface TransportConfig {
|
|
58
|
+
/** Port to listen on */
|
|
59
|
+
port: number;
|
|
60
|
+
|
|
61
|
+
/** Host to bind to */
|
|
62
|
+
host: string;
|
|
63
|
+
|
|
64
|
+
/** Authentication configuration */
|
|
65
|
+
auth?: AuthConfig;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Direct send handler for HTTP transport.
|
|
69
|
+
* Called instead of routing through message handler when streaming response is needed.
|
|
70
|
+
* Accepts full Message object to support multimodal content (images, audio, video, docs).
|
|
71
|
+
*/
|
|
72
|
+
onDirectSend?: (
|
|
73
|
+
sessionId: string,
|
|
74
|
+
message: Message,
|
|
75
|
+
) => AsyncIterable<{ type: string; data?: unknown }>;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Method invocation handler for HTTP transport.
|
|
79
|
+
* Called to execute custom gateway methods.
|
|
80
|
+
* Returns the method result directly (no streaming).
|
|
81
|
+
*/
|
|
82
|
+
onInvoke?: (
|
|
83
|
+
method: string,
|
|
84
|
+
params: Record<string, unknown>,
|
|
85
|
+
user?: UserContext,
|
|
86
|
+
) => Promise<unknown>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Transport type identifier */
|
|
90
|
+
export type TransportType = "websocket" | "http" | "sse";
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Transport interface - abstracts WebSocket vs HTTP/SSE.
|
|
94
|
+
*/
|
|
95
|
+
export interface Transport {
|
|
96
|
+
/** Transport type identifier */
|
|
97
|
+
readonly type: TransportType;
|
|
98
|
+
|
|
99
|
+
/** Start the transport server */
|
|
100
|
+
start(): Promise<void>;
|
|
101
|
+
|
|
102
|
+
/** Stop the transport server */
|
|
103
|
+
stop(): Promise<void>;
|
|
104
|
+
|
|
105
|
+
/** Register event handlers */
|
|
106
|
+
on<K extends keyof TransportEvents>(event: K, handler: TransportEvents[K]): void;
|
|
107
|
+
|
|
108
|
+
/** Get a client by ID */
|
|
109
|
+
getClient(id: string): TransportClient | undefined;
|
|
110
|
+
|
|
111
|
+
/** Get all connected clients */
|
|
112
|
+
getClients(): TransportClient[];
|
|
113
|
+
|
|
114
|
+
/** Get authenticated clients */
|
|
115
|
+
getAuthenticatedClients(): TransportClient[];
|
|
116
|
+
|
|
117
|
+
/** Broadcast to all authenticated clients */
|
|
118
|
+
broadcast(message: GatewayMessage): void;
|
|
119
|
+
|
|
120
|
+
/** Send to clients subscribed to a session */
|
|
121
|
+
sendToSubscribers(sessionId: string, message: GatewayMessage): void;
|
|
122
|
+
|
|
123
|
+
/** Number of connected clients */
|
|
124
|
+
readonly clientCount: number;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ============================================================================
|
|
128
|
+
// Base Transport Implementation (shared logic)
|
|
129
|
+
// ============================================================================
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Base class with shared transport functionality.
|
|
133
|
+
*/
|
|
134
|
+
export abstract class BaseTransport implements Transport {
|
|
135
|
+
/** Transport type - must be set by subclass */
|
|
136
|
+
abstract readonly type: TransportType;
|
|
137
|
+
|
|
138
|
+
protected clients = new Map<string, TransportClient>();
|
|
139
|
+
protected handlers: Partial<TransportEvents> = {};
|
|
140
|
+
protected config: TransportConfig;
|
|
141
|
+
protected clientIdCounter = 0;
|
|
142
|
+
|
|
143
|
+
constructor(config: TransportConfig) {
|
|
144
|
+
this.config = config;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
abstract start(): Promise<void>;
|
|
148
|
+
abstract stop(): Promise<void>;
|
|
149
|
+
|
|
150
|
+
on<K extends keyof TransportEvents>(event: K, handler: TransportEvents[K]): void {
|
|
151
|
+
this.handlers[event] = handler;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
getClient(id: string): TransportClient | undefined {
|
|
155
|
+
return this.clients.get(id);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
getClients(): TransportClient[] {
|
|
159
|
+
return Array.from(this.clients.values());
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
getAuthenticatedClients(): TransportClient[] {
|
|
163
|
+
return this.getClients().filter((c) => c.state.authenticated);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
broadcast(message: GatewayMessage): void {
|
|
167
|
+
for (const client of this.getAuthenticatedClients()) {
|
|
168
|
+
client.send(message);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
sendToSubscribers(sessionId: string, message: GatewayMessage): void {
|
|
173
|
+
for (const client of this.getAuthenticatedClients()) {
|
|
174
|
+
if (client.state.subscriptions.has(sessionId)) {
|
|
175
|
+
client.send(message);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
get clientCount(): number {
|
|
181
|
+
return this.clients.size;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
protected generateClientId(): string {
|
|
185
|
+
return `client-${++this.clientIdCounter}`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
protected validateAuth(token?: string): Promise<AuthResult> {
|
|
189
|
+
return validateAuth(token, this.config.auth);
|
|
190
|
+
}
|
|
191
|
+
}
|