@agentick/express 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 +329 -0
- package/dist/__tests__/message-flow.integration.spec.d.ts +8 -0
- package/dist/__tests__/message-flow.integration.spec.d.ts.map +1 -0
- package/dist/__tests__/message-flow.integration.spec.jsx +175 -0
- package/dist/__tests__/message-flow.integration.spec.jsx.map +1 -0
- package/dist/index.d.ts +109 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +114 -0
- package/dist/index.js.map +1 -0
- package/dist/router.d.ts +10 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +367 -0
- package/dist/router.js.map +1 -0
- package/dist/types.d.ts +75 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +41 -0
- package/src/index.ts +157 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @agentick/express - Express adapter for Agentick Gateway
|
|
3
|
+
*
|
|
4
|
+
* Provides an Express middleware that delegates to Gateway.
|
|
5
|
+
* This is a thin adapter - all business logic lives in @agentick/gateway.
|
|
6
|
+
*
|
|
7
|
+
* @example Quick start
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import express from "express";
|
|
10
|
+
* import { createAgentickMiddleware } from "@agentick/express";
|
|
11
|
+
* import { createApp } from "@agentick/core";
|
|
12
|
+
*
|
|
13
|
+
* const app = express();
|
|
14
|
+
* app.use(express.json());
|
|
15
|
+
*
|
|
16
|
+
* const agentickApp = createApp(<MyAgent />);
|
|
17
|
+
*
|
|
18
|
+
* app.use("/api", createAgentickMiddleware({
|
|
19
|
+
* apps: { assistant: agentickApp },
|
|
20
|
+
* defaultApp: "assistant",
|
|
21
|
+
* }));
|
|
22
|
+
*
|
|
23
|
+
* const server = app.listen(3000);
|
|
24
|
+
*
|
|
25
|
+
* // Cleanup on shutdown
|
|
26
|
+
* process.on("SIGTERM", () => server.close());
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example With custom methods and auth
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { createAgentickMiddleware, method } from "@agentick/express";
|
|
32
|
+
* import { z } from "zod";
|
|
33
|
+
*
|
|
34
|
+
* app.use("/api", createAgentickMiddleware({
|
|
35
|
+
* apps: { assistant: agentickApp },
|
|
36
|
+
* defaultApp: "assistant",
|
|
37
|
+
* auth: {
|
|
38
|
+
* type: "custom",
|
|
39
|
+
* validate: async (token) => {
|
|
40
|
+
* const user = await verifyToken(token);
|
|
41
|
+
* return user ? { valid: true, user } : { valid: false };
|
|
42
|
+
* },
|
|
43
|
+
* },
|
|
44
|
+
* methods: {
|
|
45
|
+
* tasks: {
|
|
46
|
+
* list: method({
|
|
47
|
+
* schema: z.object({ sessionId: z.string() }),
|
|
48
|
+
* handler: async (params) => todoService.list(params.sessionId),
|
|
49
|
+
* }),
|
|
50
|
+
* },
|
|
51
|
+
* },
|
|
52
|
+
* }));
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* @module @agentick/express
|
|
56
|
+
*/
|
|
57
|
+
import { Router } from "express";
|
|
58
|
+
import { Gateway } from "@agentick/gateway";
|
|
59
|
+
/**
|
|
60
|
+
* Create Express middleware that delegates to Gateway.
|
|
61
|
+
*
|
|
62
|
+
* @param gatewayConfig - Gateway configuration (apps, methods, auth, etc.)
|
|
63
|
+
* @param options - Optional Express-specific options
|
|
64
|
+
* @returns Express Router middleware with attached gateway
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const middleware = createAgentickMiddleware({
|
|
69
|
+
* apps: { assistant: myApp },
|
|
70
|
+
* defaultApp: "assistant",
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* app.use("/api", middleware);
|
|
74
|
+
*
|
|
75
|
+
* // Access gateway for lifecycle management
|
|
76
|
+
* process.on("SIGTERM", () => middleware.gateway.close());
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export function createAgentickMiddleware(gatewayConfig, options = {}) {
|
|
80
|
+
// Create gateway in embedded mode
|
|
81
|
+
const gateway = new Gateway({
|
|
82
|
+
...gatewayConfig,
|
|
83
|
+
embedded: true,
|
|
84
|
+
});
|
|
85
|
+
const router = Router();
|
|
86
|
+
// Attach gateway for lifecycle management
|
|
87
|
+
router.gateway = gateway;
|
|
88
|
+
// Delegate all requests to gateway
|
|
89
|
+
router.use((req, res, next) => {
|
|
90
|
+
// Optionally inject token from custom extractor
|
|
91
|
+
if (options.getToken) {
|
|
92
|
+
const token = options.getToken(req);
|
|
93
|
+
if (token) {
|
|
94
|
+
req.headers.authorization = `Bearer ${token}`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Delegate to gateway
|
|
98
|
+
gateway.handleRequest(req, res).catch(next);
|
|
99
|
+
});
|
|
100
|
+
return router;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get the Gateway instance from middleware for advanced use.
|
|
104
|
+
* Useful for lifecycle management, events, etc.
|
|
105
|
+
*/
|
|
106
|
+
export function createAgentickGateway(gatewayConfig) {
|
|
107
|
+
return new Gateway({
|
|
108
|
+
...gatewayConfig,
|
|
109
|
+
embedded: true,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
// Re-export gateway types for convenience
|
|
113
|
+
export { Gateway, method, } from "@agentick/gateway";
|
|
114
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,OAAO,EAAsB,MAAM,mBAAmB,CAAC;AA2BhE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,wBAAwB,CACtC,aAAoC,EACpC,UAAqC,EAAE;IAEvC,kCAAkC;IAClC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC;QAC1B,GAAG,aAAa;QAChB,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,EAAoB,CAAC;IAE1C,0CAA0C;IAC1C,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IAEzB,mCAAmC;IACnC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QAC7D,gDAAgD;QAChD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACpC,IAAI,KAAK,EAAE,CAAC;gBACV,GAAG,CAAC,OAAO,CAAC,aAAa,GAAG,UAAU,KAAK,EAAE,CAAC;YAChD,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,OAAO,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,aAAoC;IACxE,OAAO,IAAI,OAAO,CAAC;QACjB,GAAG,aAAa;QAChB,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;AACL,CAAC;AAED,0CAA0C;AAC1C,OAAO,EACL,OAAO,EACP,MAAM,GAIP,MAAM,mBAAmB,CAAC"}
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express handler factory for Tentickle (multiplexed sessions).
|
|
3
|
+
*
|
|
4
|
+
* @module @tentickle/express/router
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from "express";
|
|
7
|
+
import type { App } from "@tentickle/core/app";
|
|
8
|
+
import type { TentickleHandlerOptions } from "./types";
|
|
9
|
+
export declare function createTentickleHandler<User = unknown>(app: App, options?: TentickleHandlerOptions<User>): Router;
|
|
10
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAW/C,OAAO,KAAK,EAAE,uBAAuB,EAAoB,MAAM,SAAS,CAAC;AAiCzE,wBAAgB,sBAAsB,CAAC,IAAI,GAAG,OAAO,EACnD,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,uBAAuB,CAAC,IAAI,CAAM,GAC1C,MAAM,CAiXR"}
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express handler factory for Tentickle (multiplexed sessions).
|
|
3
|
+
*
|
|
4
|
+
* @module @tentickle/express/router
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from "express";
|
|
7
|
+
import { createSSEWriter, setSSEHeaders } from "@tentickle/server";
|
|
8
|
+
function parseSubscribeParam(value) {
|
|
9
|
+
if (!value)
|
|
10
|
+
return [];
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
return value
|
|
13
|
+
.flatMap((entry) => String(entry).split(","))
|
|
14
|
+
.map((id) => id.trim())
|
|
15
|
+
.filter(Boolean);
|
|
16
|
+
}
|
|
17
|
+
return String(value)
|
|
18
|
+
.split(",")
|
|
19
|
+
.map((id) => id.trim())
|
|
20
|
+
.filter(Boolean);
|
|
21
|
+
}
|
|
22
|
+
function isSendInput(value) {
|
|
23
|
+
if (!value || typeof value !== "object")
|
|
24
|
+
return false;
|
|
25
|
+
const input = value;
|
|
26
|
+
const hasMessage = !!input.message;
|
|
27
|
+
const hasMessages = Array.isArray(input.messages);
|
|
28
|
+
return (hasMessage && !hasMessages) || (!hasMessage && hasMessages);
|
|
29
|
+
}
|
|
30
|
+
export function createTentickleHandler(app, options = {}) {
|
|
31
|
+
const router = Router();
|
|
32
|
+
const paths = {
|
|
33
|
+
events: options.paths?.events ?? "/events",
|
|
34
|
+
send: options.paths?.send ?? "/send",
|
|
35
|
+
subscribe: options.paths?.subscribe ?? "/subscribe",
|
|
36
|
+
abort: options.paths?.abort ?? "/abort",
|
|
37
|
+
close: options.paths?.close ?? "/close",
|
|
38
|
+
toolResponse: options.paths?.toolResponse ?? "/tool-response",
|
|
39
|
+
channel: options.paths?.channel ?? "/channel",
|
|
40
|
+
};
|
|
41
|
+
const sseKeepaliveInterval = options.sseKeepaliveInterval ?? 15000;
|
|
42
|
+
const connections = new Map();
|
|
43
|
+
const sessionSubscribers = new Map();
|
|
44
|
+
const sessionListeners = new Map();
|
|
45
|
+
// Track channel listeners per session: Map<sessionId, Map<channelName, unsubscribe>>
|
|
46
|
+
const sessionChannelListeners = new Map();
|
|
47
|
+
const getUserContext = async (req) => {
|
|
48
|
+
const user = options.authenticate ? await options.authenticate(req) : undefined;
|
|
49
|
+
const userId = options.getUserId ? await options.getUserId(req, user) : undefined;
|
|
50
|
+
return { user, userId };
|
|
51
|
+
};
|
|
52
|
+
const authorize = async (req, user, sessionId) => {
|
|
53
|
+
if (!options.authorize)
|
|
54
|
+
return true;
|
|
55
|
+
return await options.authorize(user, sessionId, req);
|
|
56
|
+
};
|
|
57
|
+
const ensureSessionListener = (sessionId) => {
|
|
58
|
+
if (sessionListeners.has(sessionId))
|
|
59
|
+
return;
|
|
60
|
+
const session = app.session(sessionId);
|
|
61
|
+
const listener = (event) => {
|
|
62
|
+
const subscribers = sessionSubscribers.get(sessionId);
|
|
63
|
+
if (!subscribers)
|
|
64
|
+
return;
|
|
65
|
+
for (const connectionId of subscribers) {
|
|
66
|
+
const connection = connections.get(connectionId);
|
|
67
|
+
if (!connection || connection.closed)
|
|
68
|
+
continue;
|
|
69
|
+
connection.writer.writeEvent({ ...event, sessionId });
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
session.on("event", listener);
|
|
73
|
+
session.once("close", () => {
|
|
74
|
+
sessionListeners.delete(sessionId);
|
|
75
|
+
sessionSubscribers.delete(sessionId);
|
|
76
|
+
// Clean up channel listeners for this session
|
|
77
|
+
const channelListeners = sessionChannelListeners.get(sessionId);
|
|
78
|
+
if (channelListeners) {
|
|
79
|
+
for (const unsubscribe of channelListeners.values()) {
|
|
80
|
+
unsubscribe();
|
|
81
|
+
}
|
|
82
|
+
sessionChannelListeners.delete(sessionId);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
sessionListeners.set(sessionId, listener);
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Ensure we're subscribed to a specific channel on a session.
|
|
89
|
+
* Channel events are forwarded to all connections subscribed to the session.
|
|
90
|
+
*/
|
|
91
|
+
const ensureChannelListener = (sessionId, channelName) => {
|
|
92
|
+
let channelListeners = sessionChannelListeners.get(sessionId);
|
|
93
|
+
if (!channelListeners) {
|
|
94
|
+
channelListeners = new Map();
|
|
95
|
+
sessionChannelListeners.set(sessionId, channelListeners);
|
|
96
|
+
}
|
|
97
|
+
if (channelListeners.has(channelName))
|
|
98
|
+
return;
|
|
99
|
+
const session = app.session(sessionId);
|
|
100
|
+
const channel = session.channel(channelName);
|
|
101
|
+
const unsubscribe = channel.subscribe((event) => {
|
|
102
|
+
const subscribers = sessionSubscribers.get(sessionId);
|
|
103
|
+
if (!subscribers)
|
|
104
|
+
return;
|
|
105
|
+
const sseEvent = {
|
|
106
|
+
type: "channel",
|
|
107
|
+
sessionId,
|
|
108
|
+
channel: channelName,
|
|
109
|
+
event,
|
|
110
|
+
};
|
|
111
|
+
for (const connectionId of subscribers) {
|
|
112
|
+
const connection = connections.get(connectionId);
|
|
113
|
+
if (!connection || connection.closed)
|
|
114
|
+
continue;
|
|
115
|
+
connection.writer.writeEvent(sseEvent);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
channelListeners.set(channelName, unsubscribe);
|
|
119
|
+
};
|
|
120
|
+
const subscribeConnection = async (connectionId, sessionId, req, user) => {
|
|
121
|
+
const connection = connections.get(connectionId);
|
|
122
|
+
if (!connection || connection.closed)
|
|
123
|
+
return;
|
|
124
|
+
if (!(await authorize(req, user, sessionId))) {
|
|
125
|
+
throw new Error("Unauthorized");
|
|
126
|
+
}
|
|
127
|
+
app.session(sessionId);
|
|
128
|
+
ensureSessionListener(sessionId);
|
|
129
|
+
connection.subscriptions.add(sessionId);
|
|
130
|
+
const subscribers = sessionSubscribers.get(sessionId) ?? new Set();
|
|
131
|
+
subscribers.add(connectionId);
|
|
132
|
+
sessionSubscribers.set(sessionId, subscribers);
|
|
133
|
+
};
|
|
134
|
+
const unsubscribeConnection = (connectionId, sessionId) => {
|
|
135
|
+
const connection = connections.get(connectionId);
|
|
136
|
+
if (!connection)
|
|
137
|
+
return;
|
|
138
|
+
connection.subscriptions.delete(sessionId);
|
|
139
|
+
const subscribers = sessionSubscribers.get(sessionId);
|
|
140
|
+
if (!subscribers)
|
|
141
|
+
return;
|
|
142
|
+
subscribers.delete(connectionId);
|
|
143
|
+
if (subscribers.size === 0) {
|
|
144
|
+
sessionSubscribers.delete(sessionId);
|
|
145
|
+
const listener = sessionListeners.get(sessionId);
|
|
146
|
+
if (listener && app.has(sessionId)) {
|
|
147
|
+
const session = app.session(sessionId);
|
|
148
|
+
session.off("event", listener);
|
|
149
|
+
}
|
|
150
|
+
sessionListeners.delete(sessionId);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
router.get(paths.events, async (req, res, next) => {
|
|
154
|
+
try {
|
|
155
|
+
const { user, userId } = await getUserContext(req);
|
|
156
|
+
req.tentickle = { user, userId };
|
|
157
|
+
setSSEHeaders(res);
|
|
158
|
+
const writer = createSSEWriter(res, { keepaliveInterval: sseKeepaliveInterval });
|
|
159
|
+
const connectionId = `conn-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
160
|
+
const connection = {
|
|
161
|
+
id: connectionId,
|
|
162
|
+
writer,
|
|
163
|
+
subscriptions: new Set(),
|
|
164
|
+
user,
|
|
165
|
+
userId,
|
|
166
|
+
closed: false,
|
|
167
|
+
};
|
|
168
|
+
connections.set(connectionId, connection);
|
|
169
|
+
const initialSubscriptions = parseSubscribeParam(req.query.subscribe);
|
|
170
|
+
for (const sessionId of initialSubscriptions) {
|
|
171
|
+
await subscribeConnection(connectionId, sessionId, req, user);
|
|
172
|
+
}
|
|
173
|
+
writer.writeEvent({
|
|
174
|
+
type: "connection",
|
|
175
|
+
connectionId,
|
|
176
|
+
subscriptions: Array.from(connection.subscriptions),
|
|
177
|
+
});
|
|
178
|
+
req.on("close", () => {
|
|
179
|
+
connection.closed = true;
|
|
180
|
+
for (const sessionId of connection.subscriptions) {
|
|
181
|
+
unsubscribeConnection(connectionId, sessionId);
|
|
182
|
+
}
|
|
183
|
+
connections.delete(connectionId);
|
|
184
|
+
writer.close();
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
next(err);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
router.post(paths.subscribe, async (req, res, next) => {
|
|
192
|
+
try {
|
|
193
|
+
const { user } = await getUserContext(req);
|
|
194
|
+
const { connectionId, add, remove } = req.body ?? {};
|
|
195
|
+
if (!connectionId) {
|
|
196
|
+
res.status(400).json({ error: "INVALID_REQUEST", message: "connectionId is required" });
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
for (const sessionId of add ?? []) {
|
|
200
|
+
await subscribeConnection(connectionId, sessionId, req, user);
|
|
201
|
+
}
|
|
202
|
+
for (const sessionId of remove ?? []) {
|
|
203
|
+
unsubscribeConnection(connectionId, sessionId);
|
|
204
|
+
}
|
|
205
|
+
res.json({ success: true });
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
if (err instanceof Error && err.message === "Unauthorized") {
|
|
209
|
+
res.status(403).json({ error: "UNAUTHORIZED", message: "Unauthorized" });
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
next(err);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
router.post(paths.send, async (req, res, next) => {
|
|
216
|
+
try {
|
|
217
|
+
const { sessionId, ...rest } = req.body ?? {};
|
|
218
|
+
if (!isSendInput(rest)) {
|
|
219
|
+
res.status(400).json({
|
|
220
|
+
error: "INVALID_REQUEST",
|
|
221
|
+
message: "Provide either message or messages (but not both).",
|
|
222
|
+
});
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const handle = app.send(rest, { sessionId });
|
|
226
|
+
setSSEHeaders(res);
|
|
227
|
+
for await (const event of handle) {
|
|
228
|
+
res.write(`data: ${JSON.stringify({ ...event, sessionId: handle.sessionId })}\n\n`);
|
|
229
|
+
}
|
|
230
|
+
res.end();
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
next(err);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
router.post(paths.abort, async (req, res, next) => {
|
|
237
|
+
try {
|
|
238
|
+
const { sessionId, reason } = req.body ?? {};
|
|
239
|
+
if (!sessionId || !app.has(sessionId)) {
|
|
240
|
+
res.status(404).json({ error: "SESSION_NOT_FOUND", message: "Session not found" });
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const session = app.session(sessionId);
|
|
244
|
+
session.interrupt(undefined, reason);
|
|
245
|
+
res.json({ success: true });
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
next(err);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
router.post(paths.close, async (req, res, next) => {
|
|
252
|
+
try {
|
|
253
|
+
const { sessionId } = req.body ?? {};
|
|
254
|
+
if (!sessionId) {
|
|
255
|
+
res.status(400).json({ error: "INVALID_REQUEST", message: "sessionId is required" });
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
await app.close(sessionId);
|
|
259
|
+
res.json({ success: true });
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
next(err);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
router.post(paths.toolResponse, async (req, res, next) => {
|
|
266
|
+
try {
|
|
267
|
+
const { sessionId, toolUseId, response } = req.body ?? {};
|
|
268
|
+
if (!sessionId || !app.has(sessionId)) {
|
|
269
|
+
res.status(404).json({ error: "SESSION_NOT_FOUND", message: "Session not found" });
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (!toolUseId || !response) {
|
|
273
|
+
res
|
|
274
|
+
.status(400)
|
|
275
|
+
.json({ error: "INVALID_REQUEST", message: "toolUseId and response are required" });
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const session = app.session(sessionId);
|
|
279
|
+
await session.submitToolResult(toolUseId, response);
|
|
280
|
+
res.json({ success: true });
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
next(err);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
/**
|
|
287
|
+
* Publish to a session channel.
|
|
288
|
+
* This allows client → server channel communication.
|
|
289
|
+
*/
|
|
290
|
+
router.post(paths.channel, async (req, res, next) => {
|
|
291
|
+
try {
|
|
292
|
+
const { user } = await getUserContext(req);
|
|
293
|
+
const body = req.body;
|
|
294
|
+
if (!body?.sessionId) {
|
|
295
|
+
res.status(400).json({ error: "INVALID_REQUEST", message: "sessionId is required" });
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (!body?.channel) {
|
|
299
|
+
res.status(400).json({ error: "INVALID_REQUEST", message: "channel is required" });
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (!body?.type) {
|
|
303
|
+
res.status(400).json({ error: "INVALID_REQUEST", message: "type is required" });
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
// Authorize access to session
|
|
307
|
+
if (!(await authorize(req, user, body.sessionId))) {
|
|
308
|
+
res.status(403).json({ error: "UNAUTHORIZED", message: "Unauthorized" });
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (!app.has(body.sessionId)) {
|
|
312
|
+
res.status(404).json({ error: "SESSION_NOT_FOUND", message: "Session not found" });
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
const session = app.session(body.sessionId);
|
|
316
|
+
// Publish to the channel
|
|
317
|
+
const event = {
|
|
318
|
+
type: body.type,
|
|
319
|
+
channel: body.channel,
|
|
320
|
+
payload: body.payload,
|
|
321
|
+
id: body.id,
|
|
322
|
+
metadata: {
|
|
323
|
+
timestamp: Date.now(),
|
|
324
|
+
...body.metadata,
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
session.channel(body.channel).publish(event);
|
|
328
|
+
res.json({ success: true });
|
|
329
|
+
}
|
|
330
|
+
catch (err) {
|
|
331
|
+
next(err);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
/**
|
|
335
|
+
* Subscribe to a channel on a session.
|
|
336
|
+
* This ensures server → client channel events are forwarded.
|
|
337
|
+
*/
|
|
338
|
+
router.post(`${paths.channel}/subscribe`, async (req, res, next) => {
|
|
339
|
+
try {
|
|
340
|
+
const { user } = await getUserContext(req);
|
|
341
|
+
const { sessionId, channel: channelName } = req.body ?? {};
|
|
342
|
+
if (!sessionId) {
|
|
343
|
+
res.status(400).json({ error: "INVALID_REQUEST", message: "sessionId is required" });
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (!channelName) {
|
|
347
|
+
res.status(400).json({ error: "INVALID_REQUEST", message: "channel is required" });
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
// Authorize access to session
|
|
351
|
+
if (!(await authorize(req, user, sessionId))) {
|
|
352
|
+
res.status(403).json({ error: "UNAUTHORIZED", message: "Unauthorized" });
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
// Get or create session (creates if doesn't exist)
|
|
356
|
+
app.session(sessionId);
|
|
357
|
+
// Set up channel listener for this session (uses session internally)
|
|
358
|
+
ensureChannelListener(sessionId, channelName);
|
|
359
|
+
res.json({ success: true });
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
next(err);
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
return router;
|
|
366
|
+
}
|
|
367
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express integration types for Tentickle.
|
|
3
|
+
*
|
|
4
|
+
* @module @tentickle/express/types
|
|
5
|
+
*/
|
|
6
|
+
import type { Request } from "express";
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for the Tentickle Express router.
|
|
9
|
+
*/
|
|
10
|
+
export interface TentickleHandlerOptions<User = unknown> {
|
|
11
|
+
/**
|
|
12
|
+
* Extract authentication token from request.
|
|
13
|
+
* Called for each request to get user identity.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* authenticate: (req) => req.headers.authorization?.replace('Bearer ', '')
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
authenticate?: (req: Request) => User | undefined | Promise<User | undefined>;
|
|
21
|
+
/**
|
|
22
|
+
* Authorization hook for session access.
|
|
23
|
+
* Return true to allow, false to deny.
|
|
24
|
+
*/
|
|
25
|
+
authorize?: (user: User | undefined, sessionId: string, req: Request) => boolean | Promise<boolean>;
|
|
26
|
+
/**
|
|
27
|
+
* Extract user ID from request.
|
|
28
|
+
* Called after authenticate, can use req.user if set by auth middleware.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* getUserId: (req) => (req as any).user?.id
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
getUserId?: (req: Request, user?: User) => string | undefined | Promise<string | undefined>;
|
|
36
|
+
/**
|
|
37
|
+
* Custom path prefix for routes.
|
|
38
|
+
* @default ""
|
|
39
|
+
*/
|
|
40
|
+
pathPrefix?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Custom route paths.
|
|
43
|
+
*/
|
|
44
|
+
paths?: {
|
|
45
|
+
/** @default "/events" */
|
|
46
|
+
events?: string;
|
|
47
|
+
/** @default "/send" */
|
|
48
|
+
send?: string;
|
|
49
|
+
/** @default "/subscribe" */
|
|
50
|
+
subscribe?: string;
|
|
51
|
+
/** @default "/abort" */
|
|
52
|
+
abort?: string;
|
|
53
|
+
/** @default "/close" */
|
|
54
|
+
close?: string;
|
|
55
|
+
/** @default "/tool-response" */
|
|
56
|
+
toolResponse?: string;
|
|
57
|
+
/** @default "/channel" */
|
|
58
|
+
channel?: string;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* SSE keepalive interval in milliseconds.
|
|
62
|
+
* @default 15000
|
|
63
|
+
*/
|
|
64
|
+
sseKeepaliveInterval?: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Extended Express Request with Tentickle context.
|
|
68
|
+
*/
|
|
69
|
+
export interface TentickleRequest<User = unknown> extends Request {
|
|
70
|
+
tentickle?: {
|
|
71
|
+
user?: User;
|
|
72
|
+
userId?: string;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC;;GAEG;AACH,MAAM,WAAW,uBAAuB,CAAC,IAAI,GAAG,OAAO;IACrD;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;IAE9E;;;OAGG;IACH,SAAS,CAAC,EAAE,CACV,IAAI,EAAE,IAAI,GAAG,SAAS,EACtB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,OAAO,KACT,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEhC;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAE5F;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,KAAK,CAAC,EAAE;QACN,yBAAyB;QACzB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,uBAAuB;QACvB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,4BAA4B;QAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,wBAAwB;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,wBAAwB;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,gCAAgC;QAChC,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,0BAA0B;QAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IAEF;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,IAAI,GAAG,OAAO,CAAE,SAAQ,OAAO;IAC/D,SAAS,CAAC,EAAE;QACV,IAAI,CAAC,EAAE,IAAI,CAAC;QACZ,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentick/express",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Express middleware and router for Agentick applications",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"src"
|
|
8
|
+
],
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@agentick/gateway": "0.0.1"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/express": "^4.17.21",
|
|
23
|
+
"@types/node": "^22.10.5",
|
|
24
|
+
"@types/supertest": "^6.0.2",
|
|
25
|
+
"express": "^4.21.0",
|
|
26
|
+
"supertest": "^7.0.0",
|
|
27
|
+
"typescript": "^5.7.3",
|
|
28
|
+
"vitest": "^3.0.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"express": "^4.0.0 || ^5.0.0"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc -p tsconfig.build.json",
|
|
35
|
+
"dev": "tsc --watch",
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"clean": "rm -rf dist",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:watch": "vitest"
|
|
40
|
+
}
|
|
41
|
+
}
|