@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 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
@@ -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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"}