hybrid 1.3.0 → 1.3.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/dist/{index-CWnGnicw.d.cts → index-OIwixwWD.d.cts} +4 -4
- package/dist/{index-CWnGnicw.d.ts → index-OIwixwWD.d.ts} +4 -4
- package/dist/index.cjs +253 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +253 -4
- package/dist/index.js.map +1 -1
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.d.cts +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.js.map +1 -1
- package/package.json +8 -6
- package/src/core/agent.ts +2 -2
- package/src/core/tool.ts +10 -10
- package/src/index.ts +2 -2
- package/src/lib/jwt.ts +4 -4
- package/src/server/listen.ts +35 -1
|
@@ -27,7 +27,7 @@ type DefaultRuntimeExtension = Record<string, never>;
|
|
|
27
27
|
/**
|
|
28
28
|
* Configuration interface for creating custom tools that integrate with AI SDK.
|
|
29
29
|
*/
|
|
30
|
-
interface ToolConfig<TInput extends z.ZodTypeAny = z.ZodTypeAny, TOutput extends z.ZodTypeAny = z.ZodTypeAny, TRuntimeExtension = DefaultRuntimeExtension> {
|
|
30
|
+
interface ToolConfig<TInput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny> = z.ZodTypeAny, TOutput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny> = z.ZodTypeAny, TRuntimeExtension = DefaultRuntimeExtension> {
|
|
31
31
|
/** Unique identifier for the tool */
|
|
32
32
|
id: string;
|
|
33
33
|
/** Human-readable description of what the tool does */
|
|
@@ -47,7 +47,7 @@ interface ToolConfig<TInput extends z.ZodTypeAny = z.ZodTypeAny, TOutput extends
|
|
|
47
47
|
* Internal tool interface used throughout the agent framework.
|
|
48
48
|
* Similar to ToolConfig but without the ID field, used after tool creation.
|
|
49
49
|
*/
|
|
50
|
-
interface Tool<TInput extends z.ZodTypeAny = z.ZodTypeAny, TOutput extends z.ZodTypeAny = z.ZodTypeAny, TRuntimeExtension = DefaultRuntimeExtension> {
|
|
50
|
+
interface Tool<TInput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny> = z.ZodTypeAny, TOutput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny> = z.ZodTypeAny, TRuntimeExtension = DefaultRuntimeExtension> {
|
|
51
51
|
/** Human-readable description of what the tool does */
|
|
52
52
|
description: string;
|
|
53
53
|
/** Zod schema for validating tool input */
|
|
@@ -65,12 +65,12 @@ interface Tool<TInput extends z.ZodTypeAny = z.ZodTypeAny, TOutput extends z.Zod
|
|
|
65
65
|
* Factory function to create tools with custom runtime extensions.
|
|
66
66
|
* Provides proper type inference for input/output schemas and runtime extensions.
|
|
67
67
|
*/
|
|
68
|
-
declare function toolFactory<TRuntimeExtension = DefaultRuntimeExtension>(): <TInput extends z.ZodTypeAny
|
|
68
|
+
declare function toolFactory<TRuntimeExtension = DefaultRuntimeExtension>(): <TInput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny>, TOutput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny> = z.ZodTypeAny>(config: ToolConfig<TInput, TOutput, TRuntimeExtension>) => Tool<TInput, TOutput, TRuntimeExtension>;
|
|
69
69
|
/**
|
|
70
70
|
* Default tool factory with no runtime extensions.
|
|
71
71
|
* Type-safe at creation time with proper schema inference.
|
|
72
72
|
*/
|
|
73
|
-
declare const createTool: <TInput extends z.ZodTypeAny
|
|
73
|
+
declare const createTool: <TInput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny>, TOutput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny> = z.ZodTypeAny>(config: ToolConfig<TInput, TOutput, DefaultRuntimeExtension>) => Tool<TInput, TOutput, DefaultRuntimeExtension>;
|
|
74
74
|
|
|
75
75
|
declare const SUPPORTED_CHAINS: {
|
|
76
76
|
readonly mainnet: {
|
|
@@ -27,7 +27,7 @@ type DefaultRuntimeExtension = Record<string, never>;
|
|
|
27
27
|
/**
|
|
28
28
|
* Configuration interface for creating custom tools that integrate with AI SDK.
|
|
29
29
|
*/
|
|
30
|
-
interface ToolConfig<TInput extends z.ZodTypeAny = z.ZodTypeAny, TOutput extends z.ZodTypeAny = z.ZodTypeAny, TRuntimeExtension = DefaultRuntimeExtension> {
|
|
30
|
+
interface ToolConfig<TInput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny> = z.ZodTypeAny, TOutput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny> = z.ZodTypeAny, TRuntimeExtension = DefaultRuntimeExtension> {
|
|
31
31
|
/** Unique identifier for the tool */
|
|
32
32
|
id: string;
|
|
33
33
|
/** Human-readable description of what the tool does */
|
|
@@ -47,7 +47,7 @@ interface ToolConfig<TInput extends z.ZodTypeAny = z.ZodTypeAny, TOutput extends
|
|
|
47
47
|
* Internal tool interface used throughout the agent framework.
|
|
48
48
|
* Similar to ToolConfig but without the ID field, used after tool creation.
|
|
49
49
|
*/
|
|
50
|
-
interface Tool<TInput extends z.ZodTypeAny = z.ZodTypeAny, TOutput extends z.ZodTypeAny = z.ZodTypeAny, TRuntimeExtension = DefaultRuntimeExtension> {
|
|
50
|
+
interface Tool<TInput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny> = z.ZodTypeAny, TOutput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny> = z.ZodTypeAny, TRuntimeExtension = DefaultRuntimeExtension> {
|
|
51
51
|
/** Human-readable description of what the tool does */
|
|
52
52
|
description: string;
|
|
53
53
|
/** Zod schema for validating tool input */
|
|
@@ -65,12 +65,12 @@ interface Tool<TInput extends z.ZodTypeAny = z.ZodTypeAny, TOutput extends z.Zod
|
|
|
65
65
|
* Factory function to create tools with custom runtime extensions.
|
|
66
66
|
* Provides proper type inference for input/output schemas and runtime extensions.
|
|
67
67
|
*/
|
|
68
|
-
declare function toolFactory<TRuntimeExtension = DefaultRuntimeExtension>(): <TInput extends z.ZodTypeAny
|
|
68
|
+
declare function toolFactory<TRuntimeExtension = DefaultRuntimeExtension>(): <TInput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny>, TOutput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny> = z.ZodTypeAny>(config: ToolConfig<TInput, TOutput, TRuntimeExtension>) => Tool<TInput, TOutput, TRuntimeExtension>;
|
|
69
69
|
/**
|
|
70
70
|
* Default tool factory with no runtime extensions.
|
|
71
71
|
* Type-safe at creation time with proper schema inference.
|
|
72
72
|
*/
|
|
73
|
-
declare const createTool: <TInput extends z.ZodTypeAny
|
|
73
|
+
declare const createTool: <TInput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny>, TOutput extends z.ZodTypeAny | z.ZodEffects<z.ZodTypeAny> = z.ZodTypeAny>(config: ToolConfig<TInput, TOutput, DefaultRuntimeExtension>) => Tool<TInput, TOutput, DefaultRuntimeExtension>;
|
|
74
74
|
|
|
75
75
|
declare const SUPPORTED_CHAINS: {
|
|
76
76
|
readonly mainnet: {
|
package/dist/index.cjs
CHANGED
|
@@ -81,16 +81,16 @@ var import_chains = require("viem/chains");
|
|
|
81
81
|
// src/lib/jwt.ts
|
|
82
82
|
var import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
|
|
83
83
|
var JWT_SECRET = (() => {
|
|
84
|
-
const secret = process.env.
|
|
84
|
+
const secret = process.env.XMTP_ENCRYPTION_KEY;
|
|
85
85
|
const nodeEnv = process.env.NODE_ENV || "development";
|
|
86
86
|
if (nodeEnv === "production" && !secret) {
|
|
87
87
|
throw new Error(
|
|
88
|
-
"
|
|
88
|
+
"XMTP_ENCRYPTION_KEY environment variable is required in production. Generate a secure random secret for JWT token signing."
|
|
89
89
|
);
|
|
90
90
|
}
|
|
91
91
|
if (!secret) {
|
|
92
92
|
console.warn(
|
|
93
|
-
"\u26A0\uFE0F [SECURITY] Using fallback JWT secret for development. Set
|
|
93
|
+
"\u26A0\uFE0F [SECURITY] Using fallback JWT secret for development. Set XMTP_ENCRYPTION_KEY environment variable for production."
|
|
94
94
|
);
|
|
95
95
|
return "fallback-secret-for-dev-only";
|
|
96
96
|
}
|
|
@@ -129,6 +129,221 @@ function generateXMTPToolsToken(payload) {
|
|
|
129
129
|
var BG_STARTED = Symbol("BG_STARTED");
|
|
130
130
|
var BG_STATE = Symbol("BG_STATE");
|
|
131
131
|
var BG_STOP = Symbol("BG_STOP");
|
|
132
|
+
function sleep(ms, signal) {
|
|
133
|
+
return new Promise((resolve, reject) => {
|
|
134
|
+
if (signal?.aborted) {
|
|
135
|
+
reject(new Error("AbortError"));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const timeout = setTimeout(resolve, ms);
|
|
139
|
+
if (signal) {
|
|
140
|
+
signal.addEventListener(
|
|
141
|
+
"abort",
|
|
142
|
+
() => {
|
|
143
|
+
clearTimeout(timeout);
|
|
144
|
+
reject(new Error("AbortError"));
|
|
145
|
+
},
|
|
146
|
+
{ once: true }
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
function createBackgroundMessageProcessor(opts) {
|
|
152
|
+
if (!opts?.agent || !opts?.xmtpClient) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
"createBackgroundMessageProcessor: agent and xmtpClient are required"
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
const intervalMs = Math.max(250, opts.intervalMs ?? 5e3);
|
|
158
|
+
const baseBackoffMs = Math.max(100, opts.backoffMs ?? 1e3);
|
|
159
|
+
const maxBackoffMs = Math.max(baseBackoffMs, opts.maxBackoffMs ?? 3e4);
|
|
160
|
+
if (!globalThis[BG_STARTED]) {
|
|
161
|
+
;
|
|
162
|
+
globalThis[BG_STARTED] = true;
|
|
163
|
+
const state = {
|
|
164
|
+
running: true,
|
|
165
|
+
lastStartAt: Date.now(),
|
|
166
|
+
consecutiveErrors: 0,
|
|
167
|
+
messagesProcessed: 0,
|
|
168
|
+
listenerRunning: false
|
|
169
|
+
};
|
|
170
|
+
globalThis[BG_STATE] = state;
|
|
171
|
+
const ac = new AbortController();
|
|
172
|
+
const signal = ac.signal;
|
|
173
|
+
const stop = () => {
|
|
174
|
+
if (!state.running) return;
|
|
175
|
+
state.running = false;
|
|
176
|
+
ac.abort();
|
|
177
|
+
console.log("[XMTP Background] Stopping message processor...");
|
|
178
|
+
};
|
|
179
|
+
globalThis[BG_STOP] = stop;
|
|
180
|
+
process.once("SIGINT", stop);
|
|
181
|
+
process.once("SIGTERM", stop);
|
|
182
|
+
const publicClient = (0, import_viem.createPublicClient)({
|
|
183
|
+
chain: import_chains.base,
|
|
184
|
+
transport: (0, import_viem.http)()
|
|
185
|
+
});
|
|
186
|
+
const listener = new import_xmtp.MessageListener({
|
|
187
|
+
publicClient,
|
|
188
|
+
xmtpClient: opts.xmtpClient,
|
|
189
|
+
filter: opts.messageFilter,
|
|
190
|
+
heartbeatInterval: 5 * 60 * 1e3,
|
|
191
|
+
// 5 minutes
|
|
192
|
+
conversationCheckInterval: 30 * 1e3
|
|
193
|
+
// 30 seconds
|
|
194
|
+
});
|
|
195
|
+
listener.on("message", async (messageEvent) => {
|
|
196
|
+
try {
|
|
197
|
+
console.log(
|
|
198
|
+
`[XMTP Background] Processing message: ${messageEvent.message.content}`
|
|
199
|
+
);
|
|
200
|
+
console.log(
|
|
201
|
+
`[XMTP Background] Sender: ${messageEvent.sender?.address || "unknown"}`
|
|
202
|
+
);
|
|
203
|
+
console.log(
|
|
204
|
+
`[XMTP Background] Conversation: ${messageEvent.message.conversationId}`
|
|
205
|
+
);
|
|
206
|
+
const messages = [
|
|
207
|
+
{
|
|
208
|
+
id: (0, import_node_crypto.randomUUID)(),
|
|
209
|
+
role: "user",
|
|
210
|
+
parts: [
|
|
211
|
+
{
|
|
212
|
+
type: "text",
|
|
213
|
+
text: messageEvent.message.content?.toString() || ""
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
}
|
|
217
|
+
];
|
|
218
|
+
const serviceUrl = process.env.AGENT_URL || "http://localhost:8454";
|
|
219
|
+
const serviceToken = generateXMTPToolsToken({
|
|
220
|
+
action: "send",
|
|
221
|
+
conversationId: messageEvent.message.conversationId,
|
|
222
|
+
content: messageEvent.message.content?.toString() || ""
|
|
223
|
+
});
|
|
224
|
+
const serviceClient = (0, import_xmtp.createAuthenticatedXmtpClient)(
|
|
225
|
+
serviceUrl,
|
|
226
|
+
serviceToken
|
|
227
|
+
);
|
|
228
|
+
const baseRuntime = {
|
|
229
|
+
chatId: messageEvent.message.conversationId,
|
|
230
|
+
messages,
|
|
231
|
+
conversation: messageEvent.conversation,
|
|
232
|
+
message: messageEvent.message,
|
|
233
|
+
parentMessage: messageEvent.parentMessage,
|
|
234
|
+
rootMessage: messageEvent.rootMessage,
|
|
235
|
+
sender: messageEvent.sender,
|
|
236
|
+
subjects: messageEvent.subjects,
|
|
237
|
+
xmtpClient: serviceClient
|
|
238
|
+
};
|
|
239
|
+
const runtime = await opts.agent.createRuntimeContext(baseRuntime);
|
|
240
|
+
console.log("[XMTP Background] Calling agent to process message...");
|
|
241
|
+
const result = await opts.agent.generate(messages, { runtime });
|
|
242
|
+
if (result.text) {
|
|
243
|
+
await messageEvent.conversation.send(result.text);
|
|
244
|
+
console.log(`[XMTP Background] Agent response sent: ${result.text}`);
|
|
245
|
+
}
|
|
246
|
+
state.messagesProcessed++;
|
|
247
|
+
state.lastOkAt = Date.now();
|
|
248
|
+
state.consecutiveErrors = 0;
|
|
249
|
+
console.log(
|
|
250
|
+
`[XMTP Background] Message processed successfully. Total: ${state.messagesProcessed}`
|
|
251
|
+
);
|
|
252
|
+
} catch (error) {
|
|
253
|
+
state.lastErrAt = Date.now();
|
|
254
|
+
state.consecutiveErrors++;
|
|
255
|
+
console.error("[XMTP Background] Error processing message:", error);
|
|
256
|
+
try {
|
|
257
|
+
await messageEvent.conversation.send(
|
|
258
|
+
"Sorry, I encountered an error processing your message."
|
|
259
|
+
);
|
|
260
|
+
} catch (sendError) {
|
|
261
|
+
console.error(
|
|
262
|
+
"[XMTP Background] Failed to send error message:",
|
|
263
|
+
sendError
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
listener.on("error", (error) => {
|
|
269
|
+
state.lastErrAt = Date.now();
|
|
270
|
+
state.consecutiveErrors++;
|
|
271
|
+
console.error("[XMTP Background] Message listener error:", error);
|
|
272
|
+
});
|
|
273
|
+
listener.on("started", () => {
|
|
274
|
+
state.listenerRunning = true;
|
|
275
|
+
console.log("[XMTP Background] Message listener started");
|
|
276
|
+
});
|
|
277
|
+
listener.on("stopped", () => {
|
|
278
|
+
state.listenerRunning = false;
|
|
279
|
+
console.log("[XMTP Background] Message listener stopped");
|
|
280
|
+
});
|
|
281
|
+
listener.on("heartbeat", (stats) => {
|
|
282
|
+
console.log(
|
|
283
|
+
`[XMTP Background] Heartbeat - Messages: ${stats.messageCount}, Conversations: ${stats.conversationCount}`
|
|
284
|
+
);
|
|
285
|
+
});
|
|
286
|
+
(async function supervise() {
|
|
287
|
+
let nextDelay = intervalMs;
|
|
288
|
+
while (state.running) {
|
|
289
|
+
try {
|
|
290
|
+
if (!state.listenerRunning) {
|
|
291
|
+
console.log("[XMTP Background] Starting message listener...");
|
|
292
|
+
await listener.start();
|
|
293
|
+
}
|
|
294
|
+
if (state.listenerRunning) {
|
|
295
|
+
state.lastOkAt = Date.now();
|
|
296
|
+
state.consecutiveErrors = 0;
|
|
297
|
+
nextDelay = intervalMs;
|
|
298
|
+
} else {
|
|
299
|
+
throw new Error("Message listener is not running");
|
|
300
|
+
}
|
|
301
|
+
} catch (error) {
|
|
302
|
+
state.lastErrAt = Date.now();
|
|
303
|
+
state.consecutiveErrors += 1;
|
|
304
|
+
const backoff = Math.min(
|
|
305
|
+
maxBackoffMs,
|
|
306
|
+
baseBackoffMs * 2 ** (state.consecutiveErrors - 1)
|
|
307
|
+
);
|
|
308
|
+
nextDelay = backoff;
|
|
309
|
+
console.error("[XMTP Background] Supervisor error:", error);
|
|
310
|
+
try {
|
|
311
|
+
if (state.listenerRunning) {
|
|
312
|
+
await listener.stop();
|
|
313
|
+
}
|
|
314
|
+
await sleep(1e3);
|
|
315
|
+
} catch (restartError) {
|
|
316
|
+
console.error(
|
|
317
|
+
"[XMTP Background] Error restarting listener:",
|
|
318
|
+
restartError
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
await sleep(nextDelay, signal);
|
|
324
|
+
} catch (error) {
|
|
325
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
if (state.listenerRunning) {
|
|
333
|
+
console.log("[XMTP Background] Stopping message listener...");
|
|
334
|
+
await listener.stop();
|
|
335
|
+
}
|
|
336
|
+
} catch (error) {
|
|
337
|
+
console.error("[XMTP Background] Error stopping listener:", error);
|
|
338
|
+
}
|
|
339
|
+
console.log("[XMTP Background] Supervisor stopped");
|
|
340
|
+
})();
|
|
341
|
+
console.log(
|
|
342
|
+
"[XMTP Background] Message processor started (always-on, in-process)"
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
return async (_c, next) => next();
|
|
346
|
+
}
|
|
132
347
|
function getBgState() {
|
|
133
348
|
return globalThis[BG_STATE];
|
|
134
349
|
}
|
|
@@ -138,6 +353,12 @@ function stopBackground() {
|
|
|
138
353
|
}
|
|
139
354
|
|
|
140
355
|
// src/server/listen.ts
|
|
356
|
+
function createHonoMiddleware(client) {
|
|
357
|
+
return async (c, next) => {
|
|
358
|
+
c.set("xmtpClient", client);
|
|
359
|
+
return next();
|
|
360
|
+
};
|
|
361
|
+
}
|
|
141
362
|
async function listen({
|
|
142
363
|
agent,
|
|
143
364
|
port,
|
|
@@ -148,6 +369,33 @@ async function listen({
|
|
|
148
369
|
const context = {
|
|
149
370
|
agent
|
|
150
371
|
};
|
|
372
|
+
const { XMTP_WALLET_KEY, XMTP_ENCRYPTION_KEY } = process.env;
|
|
373
|
+
if (!XMTP_WALLET_KEY) {
|
|
374
|
+
throw new Error("XMTP_WALLET_KEY must be set");
|
|
375
|
+
}
|
|
376
|
+
if (!XMTP_ENCRYPTION_KEY) {
|
|
377
|
+
throw new Error("XMTP_ENCRYPTION_KEY must be set");
|
|
378
|
+
}
|
|
379
|
+
const cloudflareStoragePath = (0, import_utils.getCloudflareStoragePath)("xmtp");
|
|
380
|
+
const xmtpClient = await (0, import_xmtp2.createXMTPClient)(XMTP_WALLET_KEY, {
|
|
381
|
+
persist: true,
|
|
382
|
+
storagePath: cloudflareStoragePath
|
|
383
|
+
});
|
|
384
|
+
app.use(createHonoMiddleware(xmtpClient));
|
|
385
|
+
app.use(
|
|
386
|
+
createBackgroundMessageProcessor({
|
|
387
|
+
agent,
|
|
388
|
+
xmtpClient,
|
|
389
|
+
messageFilter: filter,
|
|
390
|
+
// Use the provided filter
|
|
391
|
+
intervalMs: 5e3,
|
|
392
|
+
// Check every 5 seconds
|
|
393
|
+
backoffMs: 1e3,
|
|
394
|
+
// Start with 1 second backoff
|
|
395
|
+
maxBackoffMs: 3e4
|
|
396
|
+
// Max 30 seconds backoff
|
|
397
|
+
})
|
|
398
|
+
);
|
|
151
399
|
const xmtpPlugin = (0, import_xmtp2.XMTPPlugin)({
|
|
152
400
|
filter
|
|
153
401
|
});
|
|
@@ -206,7 +454,8 @@ async function listen({
|
|
|
206
454
|
fetch: app.fetch,
|
|
207
455
|
port: httpPort
|
|
208
456
|
});
|
|
209
|
-
console.log(`\u2705
|
|
457
|
+
console.log(`\u2705 Hybrid server running on port ${httpPort}`);
|
|
458
|
+
console.log(`\u{1F3A7} Background message listener is active`);
|
|
210
459
|
} catch (error) {
|
|
211
460
|
if (error.code === "EADDRINUSE") {
|
|
212
461
|
console.error(
|