@agentick/server 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 +114 -0
- package/dist/auth.d.ts +62 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +51 -0
- package/dist/auth.js.map +1 -0
- package/dist/event-bridge.d.ts +91 -0
- package/dist/event-bridge.d.ts.map +1 -0
- package/dist/event-bridge.js +301 -0
- package/dist/event-bridge.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/session-handler.d.ts +108 -0
- package/dist/session-handler.d.ts.map +1 -0
- package/dist/session-handler.js +197 -0
- package/dist/session-handler.js.map +1 -0
- package/dist/session-store.d.ts +62 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +82 -0
- package/dist/session-store.js.map +1 -0
- package/dist/sse.d.ts +71 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +137 -0
- package/dist/sse.js.map +1 -0
- package/dist/types.d.ts +30 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Agentick Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# @agentick/server
|
|
2
|
+
|
|
3
|
+
Server-side utilities for Agentick applications:
|
|
4
|
+
|
|
5
|
+
- **SSE utilities** - Stream events to clients via Server-Sent Events
|
|
6
|
+
- **Type re-exports** - Convenient imports from `@agentick/shared`
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @agentick/server @agentick/core @agentick/shared
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
For most use cases, use `@agentick/express` instead - it provides a complete handler:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { createApp } from "@agentick/core";
|
|
20
|
+
import { createAgentickHandler } from "@agentick/express";
|
|
21
|
+
|
|
22
|
+
const app = createApp(MyAgent, { model });
|
|
23
|
+
expressApp.use("/api/agent", createAgentickHandler(app));
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Direct Usage
|
|
27
|
+
|
|
28
|
+
If building a custom framework adapter:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { setSSEHeaders, createSSEWriter } from "@agentick/server";
|
|
32
|
+
|
|
33
|
+
// SSE endpoint
|
|
34
|
+
app.get("/events", (req, res) => {
|
|
35
|
+
setSSEHeaders(res);
|
|
36
|
+
const writer = createSSEWriter(res);
|
|
37
|
+
|
|
38
|
+
// Write events
|
|
39
|
+
writer.writeEvent({ type: "connected" });
|
|
40
|
+
|
|
41
|
+
// Keepalive
|
|
42
|
+
const keepalive = setInterval(() => {
|
|
43
|
+
writer.writeComment("keepalive");
|
|
44
|
+
}, 15000);
|
|
45
|
+
|
|
46
|
+
req.on("close", () => {
|
|
47
|
+
clearInterval(keepalive);
|
|
48
|
+
writer.close();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Streaming response
|
|
53
|
+
app.post("/send", async (req, res) => {
|
|
54
|
+
setSSEHeaders(res);
|
|
55
|
+
const writer = createSSEWriter(res);
|
|
56
|
+
|
|
57
|
+
const session = app.getOrCreateSession(req.body.sessionId);
|
|
58
|
+
const handle = session.send(req.body);
|
|
59
|
+
|
|
60
|
+
for await (const event of handle) {
|
|
61
|
+
writer.writeEvent(event);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
writer.close();
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## API Reference
|
|
69
|
+
|
|
70
|
+
### setSSEHeaders(res)
|
|
71
|
+
|
|
72
|
+
Set SSE headers on a response object:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
setSSEHeaders(res);
|
|
76
|
+
// Sets: Content-Type, Cache-Control, Connection, X-Accel-Buffering
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### createSSEWriter(stream)
|
|
80
|
+
|
|
81
|
+
Create an SSE writer for streaming events:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
const writer = createSSEWriter(res);
|
|
85
|
+
|
|
86
|
+
writer.writeEvent({ type: "content_delta", delta: "Hello" });
|
|
87
|
+
writer.writeComment("keepalive");
|
|
88
|
+
writer.writeError({ code: "SESSION_NOT_FOUND", message: "Not found" });
|
|
89
|
+
writer.close();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Type Re-exports
|
|
93
|
+
|
|
94
|
+
For convenience, this package re-exports common types from `@agentick/shared`:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import type {
|
|
98
|
+
SessionResultPayload,
|
|
99
|
+
ToolConfirmationRequest,
|
|
100
|
+
ToolConfirmationResponse,
|
|
101
|
+
SessionState,
|
|
102
|
+
CreateSessionResponse,
|
|
103
|
+
} from "@agentick/server";
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Philosophy
|
|
107
|
+
|
|
108
|
+
This package follows the "primitives, not opinions" philosophy:
|
|
109
|
+
|
|
110
|
+
- **Minimal** - Just SSE utilities and type re-exports
|
|
111
|
+
- **Framework-agnostic** - Works with any HTTP framework
|
|
112
|
+
- **Composable** - Use what you need
|
|
113
|
+
|
|
114
|
+
For a complete server integration, use `@agentick/express`, `@agentick/nestjs`, or build your own using these utilities.
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication utilities for @agentick/server
|
|
3
|
+
*
|
|
4
|
+
* Provides standalone auth functions that can be used by Gateway
|
|
5
|
+
* and framework adapters.
|
|
6
|
+
*
|
|
7
|
+
* @module @agentick/server/auth
|
|
8
|
+
*/
|
|
9
|
+
import type { UserContext } from "@agentick/kernel";
|
|
10
|
+
/**
|
|
11
|
+
* Result returned by auth validation.
|
|
12
|
+
*/
|
|
13
|
+
export interface AuthResult {
|
|
14
|
+
valid: boolean;
|
|
15
|
+
/** User context from token - may be hydrated further */
|
|
16
|
+
user?: UserContext;
|
|
17
|
+
/** Auth metadata */
|
|
18
|
+
metadata?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Base auth options available on all auth types.
|
|
22
|
+
*/
|
|
23
|
+
interface AuthBaseOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Hydrate user context after validation.
|
|
26
|
+
* Called with the auth result - fetch additional data from DB, etc.
|
|
27
|
+
* Return the complete UserContext that will be available in methods.
|
|
28
|
+
*/
|
|
29
|
+
hydrateUser?: (authResult: AuthResult) => Promise<UserContext>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Authentication configuration.
|
|
33
|
+
*/
|
|
34
|
+
export type AuthConfig = ({
|
|
35
|
+
type: "none";
|
|
36
|
+
} & AuthBaseOptions) | ({
|
|
37
|
+
type: "token";
|
|
38
|
+
token: string;
|
|
39
|
+
} & AuthBaseOptions) | ({
|
|
40
|
+
type: "jwt";
|
|
41
|
+
secret: string;
|
|
42
|
+
issuer?: string;
|
|
43
|
+
} & AuthBaseOptions) | ({
|
|
44
|
+
type: "custom";
|
|
45
|
+
validate: (token: string) => Promise<AuthResult>;
|
|
46
|
+
} & AuthBaseOptions);
|
|
47
|
+
/**
|
|
48
|
+
* Extract auth token from a request.
|
|
49
|
+
* Looks for Bearer token in Authorization header.
|
|
50
|
+
*/
|
|
51
|
+
export declare function extractToken(req: {
|
|
52
|
+
headers?: {
|
|
53
|
+
authorization?: string;
|
|
54
|
+
[key: string]: string | string[] | undefined;
|
|
55
|
+
};
|
|
56
|
+
}): string | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Validate an auth token against the configured auth method.
|
|
59
|
+
*/
|
|
60
|
+
export declare function validateAuth(token: string | undefined, config: AuthConfig | undefined): Promise<AuthResult>;
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,wDAAwD;IACxD,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,UAAU,eAAe;IACvB;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CAChE;AAED;;GAEG;AACH,MAAM,MAAM,UAAU,GAClB,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,eAAe,CAAC,GACpC,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,eAAe,CAAC,GACpD,CAAC;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,eAAe,CAAC,GACpE,CAAC;IACC,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CAClD,GAAG,eAAe,CAAC,CAAC;AAEzB;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE;IAChC,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAA;KAAE,CAAC;CACpF,GAAG,MAAM,GAAG,SAAS,CAMrB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,MAAM,EAAE,UAAU,GAAG,SAAS,GAC7B,OAAO,CAAC,UAAU,CAAC,CA6BrB"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication utilities for @agentick/server
|
|
3
|
+
*
|
|
4
|
+
* Provides standalone auth functions that can be used by Gateway
|
|
5
|
+
* and framework adapters.
|
|
6
|
+
*
|
|
7
|
+
* @module @agentick/server/auth
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Extract auth token from a request.
|
|
11
|
+
* Looks for Bearer token in Authorization header.
|
|
12
|
+
*/
|
|
13
|
+
export function extractToken(req) {
|
|
14
|
+
const auth = req.headers?.authorization;
|
|
15
|
+
if (typeof auth === "string" && auth.startsWith("Bearer ")) {
|
|
16
|
+
return auth.slice(7);
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Validate an auth token against the configured auth method.
|
|
22
|
+
*/
|
|
23
|
+
export async function validateAuth(token, config) {
|
|
24
|
+
// No auth configured
|
|
25
|
+
if (!config || config.type === "none") {
|
|
26
|
+
return { valid: true };
|
|
27
|
+
}
|
|
28
|
+
// Token required but not provided
|
|
29
|
+
if (!token) {
|
|
30
|
+
return { valid: false };
|
|
31
|
+
}
|
|
32
|
+
let result;
|
|
33
|
+
if (config.type === "token") {
|
|
34
|
+
result = { valid: token === config.token };
|
|
35
|
+
}
|
|
36
|
+
else if (config.type === "custom") {
|
|
37
|
+
result = await config.validate(token);
|
|
38
|
+
}
|
|
39
|
+
else if (config.type === "jwt") {
|
|
40
|
+
result = { valid: false };
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
result = { valid: false };
|
|
44
|
+
}
|
|
45
|
+
// Run hydrateUser hook if configured and auth succeeded
|
|
46
|
+
if (result.valid && config.hydrateUser) {
|
|
47
|
+
result.user = await config.hydrateUser(result);
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAuCH;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,GAE5B;IACC,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,EAAE,aAAa,CAAC;IACxC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3D,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAyB,EACzB,MAA8B;IAE9B,qBAAqB;IACrB,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACtC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC;IAED,kCAAkC;IAClC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC1B,CAAC;IAED,IAAI,MAAkB,CAAC;IAEvB,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC5B,MAAM,GAAG,EAAE,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC;IAC7C,CAAC;SAAM,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACpC,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC;SAAM,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACjC,MAAM,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;IAED,wDAAwD;IACxD,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvC,MAAM,CAAC,IAAI,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Bridge - Routes events between transport and sessions.
|
|
3
|
+
*
|
|
4
|
+
* The bridge has two modes:
|
|
5
|
+
* 1. With transport adapter (e.g., Socket.IO): Delegates connection management to the adapter
|
|
6
|
+
* 2. Without transport adapter (HTTP/SSE): Manages connections internally
|
|
7
|
+
*
|
|
8
|
+
* @module @tentickle/server/event-bridge
|
|
9
|
+
*/
|
|
10
|
+
import type { EventBridge, EventBridgeConfig, ServerConnection } from "./types.js";
|
|
11
|
+
/**
|
|
12
|
+
* Event Bridge implementation.
|
|
13
|
+
*
|
|
14
|
+
* @example With HTTP/SSE (manages connections internally)
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const bridge = createEventBridge({ sessionHandler });
|
|
17
|
+
*
|
|
18
|
+
* // Register connections from SSE endpoint
|
|
19
|
+
* bridge.registerConnection(connection);
|
|
20
|
+
*
|
|
21
|
+
* // Handle events from POST endpoint
|
|
22
|
+
* await bridge.handleEvent(connectionId, event);
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example With Socket.IO (delegates to adapter)
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const adapter = createSocketIOAdapter({
|
|
28
|
+
* io,
|
|
29
|
+
* onEvent: (connection, event) => bridge.handleEvent(connection, event),
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* const bridge = createEventBridge({
|
|
33
|
+
* sessionHandler,
|
|
34
|
+
* transport: adapter,
|
|
35
|
+
* });
|
|
36
|
+
* // No need to call registerConnection - adapter handles it
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare class EventBridgeImpl implements EventBridge {
|
|
40
|
+
private readonly logger;
|
|
41
|
+
private readonly sessionHandler;
|
|
42
|
+
private readonly transport?;
|
|
43
|
+
private readonly validateEvent?;
|
|
44
|
+
private readonly connections;
|
|
45
|
+
private readonly sessionConnections;
|
|
46
|
+
private readonly activeStreams;
|
|
47
|
+
constructor(config: EventBridgeConfig);
|
|
48
|
+
/**
|
|
49
|
+
* Whether this bridge manages connections internally.
|
|
50
|
+
* False when a transport adapter handles connection management.
|
|
51
|
+
*/
|
|
52
|
+
private get managesConnections();
|
|
53
|
+
/**
|
|
54
|
+
* Register a connection.
|
|
55
|
+
* Only needed when NOT using a transport adapter.
|
|
56
|
+
*/
|
|
57
|
+
registerConnection(connection: ServerConnection): void;
|
|
58
|
+
/**
|
|
59
|
+
* Unregister a connection.
|
|
60
|
+
* Only needed when NOT using a transport adapter.
|
|
61
|
+
*/
|
|
62
|
+
unregisterConnection(connectionId: string): void;
|
|
63
|
+
/**
|
|
64
|
+
* Handle an incoming event.
|
|
65
|
+
*
|
|
66
|
+
* Accepts either:
|
|
67
|
+
* - connectionId (string) - looks up connection internally (HTTP/SSE mode)
|
|
68
|
+
* - connection (ServerConnection) - uses directly (transport adapter mode)
|
|
69
|
+
*/
|
|
70
|
+
handleEvent(connectionOrId: string | ServerConnection, event: {
|
|
71
|
+
channel: string;
|
|
72
|
+
type: string;
|
|
73
|
+
payload: unknown;
|
|
74
|
+
id?: string;
|
|
75
|
+
}): Promise<void>;
|
|
76
|
+
private handleMessage;
|
|
77
|
+
private handleControl;
|
|
78
|
+
private handleToolConfirmation;
|
|
79
|
+
private startStreaming;
|
|
80
|
+
/**
|
|
81
|
+
* Classify an error into a protocol error code.
|
|
82
|
+
*/
|
|
83
|
+
private classifyError;
|
|
84
|
+
private sendToSession;
|
|
85
|
+
destroy(): void;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Create an event bridge.
|
|
89
|
+
*/
|
|
90
|
+
export declare function createEventBridge(config: EventBridgeConfig): EventBridge;
|
|
91
|
+
//# sourceMappingURL=event-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bridge.d.ts","sourceRoot":"","sources":["../src/event-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EAEjB,gBAAgB,EAGjB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,eAAgB,YAAW,WAAW;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAyB;IACpD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAqC;IAGpE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAuC;IACnE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAkC;IAGrE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiC;gBAEnD,MAAM,EAAE,iBAAiB;IAMrC;;;OAGG;IACH,OAAO,KAAK,kBAAkB,GAE7B;IAED;;;OAGG;IACH,kBAAkB,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI;IAgBtD;;;OAGG;IACH,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAmBhD;;;;;;OAMG;IACG,WAAW,CACf,cAAc,EAAE,MAAM,GAAG,gBAAgB,EACzC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GACtE,OAAO,CAAC,IAAI,CAAC;YAwCF,aAAa;YAeb,aAAa;YA6Bb,sBAAsB;YAiBtB,cAAc;IA0D5B;;OAEG;IACH,OAAO,CAAC,aAAa;YAoBP,aAAa;IA2B3B,OAAO,IAAI,IAAI;CAiBhB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,WAAW,CAExE"}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Bridge - Routes events between transport and sessions.
|
|
3
|
+
*
|
|
4
|
+
* The bridge has two modes:
|
|
5
|
+
* 1. With transport adapter (e.g., Socket.IO): Delegates connection management to the adapter
|
|
6
|
+
* 2. Without transport adapter (HTTP/SSE): Manages connections internally
|
|
7
|
+
*
|
|
8
|
+
* @module @tentickle/server/event-bridge
|
|
9
|
+
*/
|
|
10
|
+
import { FrameworkChannels, ErrorCodes } from "@tentickle/shared";
|
|
11
|
+
import { Logger } from "@tentickle/core/core";
|
|
12
|
+
/**
|
|
13
|
+
* Event Bridge implementation.
|
|
14
|
+
*
|
|
15
|
+
* @example With HTTP/SSE (manages connections internally)
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const bridge = createEventBridge({ sessionHandler });
|
|
18
|
+
*
|
|
19
|
+
* // Register connections from SSE endpoint
|
|
20
|
+
* bridge.registerConnection(connection);
|
|
21
|
+
*
|
|
22
|
+
* // Handle events from POST endpoint
|
|
23
|
+
* await bridge.handleEvent(connectionId, event);
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example With Socket.IO (delegates to adapter)
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const adapter = createSocketIOAdapter({
|
|
29
|
+
* io,
|
|
30
|
+
* onEvent: (connection, event) => bridge.handleEvent(connection, event),
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* const bridge = createEventBridge({
|
|
34
|
+
* sessionHandler,
|
|
35
|
+
* transport: adapter,
|
|
36
|
+
* });
|
|
37
|
+
* // No need to call registerConnection - adapter handles it
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export class EventBridgeImpl {
|
|
41
|
+
logger = Logger.for("EventBridge");
|
|
42
|
+
sessionHandler;
|
|
43
|
+
transport;
|
|
44
|
+
validateEvent;
|
|
45
|
+
// Internal connection tracking - only used when no transport adapter
|
|
46
|
+
connections = new Map();
|
|
47
|
+
sessionConnections = new Map();
|
|
48
|
+
// Active streams for abort handling
|
|
49
|
+
activeStreams = new Map();
|
|
50
|
+
constructor(config) {
|
|
51
|
+
this.sessionHandler = config.sessionHandler;
|
|
52
|
+
this.transport = config.transport;
|
|
53
|
+
this.validateEvent = config.validateEvent;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Whether this bridge manages connections internally.
|
|
57
|
+
* False when a transport adapter handles connection management.
|
|
58
|
+
*/
|
|
59
|
+
get managesConnections() {
|
|
60
|
+
return !this.transport;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Register a connection.
|
|
64
|
+
* Only needed when NOT using a transport adapter.
|
|
65
|
+
*/
|
|
66
|
+
registerConnection(connection) {
|
|
67
|
+
if (!this.managesConnections) {
|
|
68
|
+
// Transport adapter handles connection tracking
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.connections.set(connection.id, connection);
|
|
72
|
+
let sessionConns = this.sessionConnections.get(connection.sessionId);
|
|
73
|
+
if (!sessionConns) {
|
|
74
|
+
sessionConns = new Set();
|
|
75
|
+
this.sessionConnections.set(connection.sessionId, sessionConns);
|
|
76
|
+
}
|
|
77
|
+
sessionConns.add(connection.id);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Unregister a connection.
|
|
81
|
+
* Only needed when NOT using a transport adapter.
|
|
82
|
+
*/
|
|
83
|
+
unregisterConnection(connectionId) {
|
|
84
|
+
if (!this.managesConnections) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const connection = this.connections.get(connectionId);
|
|
88
|
+
if (!connection)
|
|
89
|
+
return;
|
|
90
|
+
const sessionConns = this.sessionConnections.get(connection.sessionId);
|
|
91
|
+
if (sessionConns) {
|
|
92
|
+
sessionConns.delete(connectionId);
|
|
93
|
+
if (sessionConns.size === 0) {
|
|
94
|
+
this.sessionConnections.delete(connection.sessionId);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
this.connections.delete(connectionId);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Handle an incoming event.
|
|
101
|
+
*
|
|
102
|
+
* Accepts either:
|
|
103
|
+
* - connectionId (string) - looks up connection internally (HTTP/SSE mode)
|
|
104
|
+
* - connection (ServerConnection) - uses directly (transport adapter mode)
|
|
105
|
+
*/
|
|
106
|
+
async handleEvent(connectionOrId, event) {
|
|
107
|
+
// Resolve connection
|
|
108
|
+
const connection = typeof connectionOrId === "string"
|
|
109
|
+
? this.connections.get(connectionOrId)
|
|
110
|
+
: connectionOrId;
|
|
111
|
+
if (!connection) {
|
|
112
|
+
this.logger.warn({ connectionOrId }, "Event from unknown connection");
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (this.validateEvent) {
|
|
116
|
+
try {
|
|
117
|
+
await this.validateEvent(connection, event);
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
this.logger.warn({ err, connectionId: connection.id, channel: event.channel, type: event.type }, "Event validation failed");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Route by channel
|
|
125
|
+
switch (event.channel) {
|
|
126
|
+
case FrameworkChannels.MESSAGES:
|
|
127
|
+
await this.handleMessage(connection, event);
|
|
128
|
+
break;
|
|
129
|
+
case FrameworkChannels.CONTROL:
|
|
130
|
+
await this.handleControl(connection, event);
|
|
131
|
+
break;
|
|
132
|
+
case FrameworkChannels.TOOL_CONFIRMATION:
|
|
133
|
+
await this.handleToolConfirmation(connection, event);
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
this.logger.warn({ channel: event.channel }, "Unknown channel");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async handleMessage(connection, event) {
|
|
140
|
+
if (event.type !== "message")
|
|
141
|
+
return;
|
|
142
|
+
const message = event.payload;
|
|
143
|
+
const session = this.sessionHandler.getSession(connection.sessionId);
|
|
144
|
+
if (!session) {
|
|
145
|
+
this.logger.warn({ sessionId: connection.sessionId }, "Session not found");
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
await session.queueMessage(message);
|
|
149
|
+
}
|
|
150
|
+
async handleControl(connection, event) {
|
|
151
|
+
const session = this.sessionHandler.getSession(connection.sessionId);
|
|
152
|
+
if (!session) {
|
|
153
|
+
this.logger.warn({ sessionId: connection.sessionId }, "Session not found");
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (event.type === "tick") {
|
|
157
|
+
const props = event.payload?.props;
|
|
158
|
+
const inspection = session.inspect();
|
|
159
|
+
const hasQueuedMessages = inspection.queuedMessages.length > 0;
|
|
160
|
+
const hasProps = props != null &&
|
|
161
|
+
(typeof props !== "object" || Object.keys(props).length > 0);
|
|
162
|
+
if (!hasQueuedMessages && !hasProps) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
await this.startStreaming(connection.sessionId, props);
|
|
166
|
+
}
|
|
167
|
+
else if (event.type === "abort") {
|
|
168
|
+
this.activeStreams.get(connection.sessionId)?.();
|
|
169
|
+
const reason = event.payload?.reason;
|
|
170
|
+
session.interrupt(undefined, reason);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async handleToolConfirmation(connection, event) {
|
|
174
|
+
if (event.type !== "response")
|
|
175
|
+
return;
|
|
176
|
+
const session = this.sessionHandler.getSession(connection.sessionId);
|
|
177
|
+
if (!session)
|
|
178
|
+
return;
|
|
179
|
+
session.channel("tool_confirmation").publish({
|
|
180
|
+
type: "response",
|
|
181
|
+
id: event.id,
|
|
182
|
+
channel: "tool_confirmation",
|
|
183
|
+
payload: event.payload,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
async startStreaming(sessionId, props) {
|
|
187
|
+
// Abort existing stream
|
|
188
|
+
this.activeStreams.get(sessionId)?.();
|
|
189
|
+
let aborted = false;
|
|
190
|
+
this.activeStreams.set(sessionId, () => { aborted = true; });
|
|
191
|
+
const session = this.sessionHandler.getSession(sessionId);
|
|
192
|
+
if (!session) {
|
|
193
|
+
this.logger.warn({ sessionId }, "Session not found");
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const handle = session.tick(props);
|
|
197
|
+
try {
|
|
198
|
+
for await (const event of handle) {
|
|
199
|
+
if (aborted)
|
|
200
|
+
break;
|
|
201
|
+
await this.sendToSession(sessionId, {
|
|
202
|
+
channel: FrameworkChannels.EVENTS,
|
|
203
|
+
type: event.type,
|
|
204
|
+
payload: event,
|
|
205
|
+
});
|
|
206
|
+
if (event.type === "result") {
|
|
207
|
+
await this.sendToSession(sessionId, {
|
|
208
|
+
channel: FrameworkChannels.RESULT,
|
|
209
|
+
type: "result",
|
|
210
|
+
payload: event.result,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
if (!aborted) {
|
|
217
|
+
const err = error;
|
|
218
|
+
const errorPayload = {
|
|
219
|
+
code: this.classifyError(err),
|
|
220
|
+
message: err.message,
|
|
221
|
+
details: err.cause ? { cause: String(err.cause) } : undefined,
|
|
222
|
+
};
|
|
223
|
+
await this.sendToSession(sessionId, {
|
|
224
|
+
channel: FrameworkChannels.EVENTS,
|
|
225
|
+
type: "error",
|
|
226
|
+
payload: errorPayload,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
finally {
|
|
231
|
+
void handle.result.catch((err) => {
|
|
232
|
+
this.logger.error({ err, sessionId }, "Session result failed");
|
|
233
|
+
});
|
|
234
|
+
this.activeStreams.delete(sessionId);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Classify an error into a protocol error code.
|
|
239
|
+
*/
|
|
240
|
+
classifyError(error) {
|
|
241
|
+
const message = error.message.toLowerCase();
|
|
242
|
+
if (message.includes("session not found") || message.includes("sessionnotfound")) {
|
|
243
|
+
return ErrorCodes.SESSION_NOT_FOUND;
|
|
244
|
+
}
|
|
245
|
+
if (message.includes("session closed") || message.includes("sessionclosed")) {
|
|
246
|
+
return ErrorCodes.SESSION_CLOSED;
|
|
247
|
+
}
|
|
248
|
+
if (message.includes("timeout") || error.name === "TimeoutError") {
|
|
249
|
+
return ErrorCodes.TIMEOUT;
|
|
250
|
+
}
|
|
251
|
+
if (message.includes("invalid") || message.includes("validation")) {
|
|
252
|
+
return ErrorCodes.INVALID_MESSAGE;
|
|
253
|
+
}
|
|
254
|
+
// Default to a generic error - could add more codes as needed
|
|
255
|
+
return "EXECUTION_ERROR";
|
|
256
|
+
}
|
|
257
|
+
async sendToSession(sessionId, event) {
|
|
258
|
+
// Delegate to transport adapter if available
|
|
259
|
+
if (this.transport) {
|
|
260
|
+
await this.transport.sendToSession(sessionId, event);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
// Otherwise use internal tracking
|
|
264
|
+
const connectionIds = this.sessionConnections.get(sessionId);
|
|
265
|
+
if (!connectionIds)
|
|
266
|
+
return;
|
|
267
|
+
for (const id of connectionIds) {
|
|
268
|
+
const conn = this.connections.get(id);
|
|
269
|
+
if (!conn)
|
|
270
|
+
continue;
|
|
271
|
+
void conn.send(event).catch((err) => {
|
|
272
|
+
this.logger.warn({ connectionId: id, err }, "Connection send failed");
|
|
273
|
+
// Drop the connection; it can reconnect via a new SSE/WebSocket connection.
|
|
274
|
+
conn.close();
|
|
275
|
+
this.unregisterConnection(id);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
destroy() {
|
|
280
|
+
// Abort all streams
|
|
281
|
+
for (const abort of this.activeStreams.values()) {
|
|
282
|
+
abort();
|
|
283
|
+
}
|
|
284
|
+
this.activeStreams.clear();
|
|
285
|
+
// Close internal connections
|
|
286
|
+
for (const conn of this.connections.values()) {
|
|
287
|
+
conn.close();
|
|
288
|
+
}
|
|
289
|
+
this.connections.clear();
|
|
290
|
+
this.sessionConnections.clear();
|
|
291
|
+
// Cleanup transport
|
|
292
|
+
this.transport?.destroy();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Create an event bridge.
|
|
297
|
+
*/
|
|
298
|
+
export function createEventBridge(config) {
|
|
299
|
+
return new EventBridgeImpl(config);
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=event-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bridge.js","sourceRoot":"","sources":["../src/event-bridge.ts"],"names":[],"mappings":"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"}
|