@okrlinkhub/agent-factory 0.2.11 → 0.2.12

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.
Files changed (69) hide show
  1. package/dist/client/_generated/_ignore.d.ts +1 -0
  2. package/dist/client/_generated/_ignore.d.ts.map +1 -0
  3. package/dist/client/_generated/_ignore.js +3 -0
  4. package/dist/client/_generated/_ignore.js.map +1 -0
  5. package/dist/client/bridge.d.ts +65 -0
  6. package/dist/client/bridge.d.ts.map +1 -0
  7. package/dist/client/bridge.js +192 -0
  8. package/dist/client/bridge.js.map +1 -0
  9. package/dist/client/index.d.ts +516 -0
  10. package/dist/client/index.d.ts.map +1 -0
  11. package/dist/client/index.js +795 -0
  12. package/dist/client/index.js.map +1 -0
  13. package/dist/component/_generated/api.d.ts +46 -0
  14. package/dist/component/_generated/api.d.ts.map +1 -0
  15. package/dist/component/_generated/api.js +31 -0
  16. package/dist/component/_generated/api.js.map +1 -0
  17. package/dist/component/_generated/component.d.ts +1396 -0
  18. package/dist/component/_generated/component.d.ts.map +1 -0
  19. package/dist/component/_generated/component.js +11 -0
  20. package/dist/component/_generated/component.js.map +1 -0
  21. package/dist/component/_generated/dataModel.d.ts +46 -0
  22. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  23. package/dist/component/_generated/dataModel.js +11 -0
  24. package/dist/component/_generated/dataModel.js.map +1 -0
  25. package/dist/component/_generated/server.d.ts +121 -0
  26. package/dist/component/_generated/server.d.ts.map +1 -0
  27. package/dist/component/_generated/server.js +78 -0
  28. package/dist/component/_generated/server.js.map +1 -0
  29. package/dist/component/config.d.ts +254 -0
  30. package/dist/component/config.d.ts.map +1 -0
  31. package/dist/component/config.js +152 -0
  32. package/dist/component/config.js.map +1 -0
  33. package/dist/component/convex.config.d.ts +3 -0
  34. package/dist/component/convex.config.d.ts.map +1 -0
  35. package/dist/component/convex.config.js +3 -0
  36. package/dist/component/convex.config.js.map +1 -0
  37. package/dist/component/identity.d.ts +111 -0
  38. package/dist/component/identity.d.ts.map +1 -0
  39. package/dist/component/identity.js +455 -0
  40. package/dist/component/identity.js.map +1 -0
  41. package/dist/component/lib.d.ts +6 -0
  42. package/dist/component/lib.d.ts.map +1 -0
  43. package/dist/component/lib.js +6 -0
  44. package/dist/component/lib.js.map +1 -0
  45. package/dist/component/providers/fly.d.ts +51 -0
  46. package/dist/component/providers/fly.d.ts.map +1 -0
  47. package/dist/component/providers/fly.js +234 -0
  48. package/dist/component/providers/fly.js.map +1 -0
  49. package/dist/component/pushing.d.ts +256 -0
  50. package/dist/component/pushing.d.ts.map +1 -0
  51. package/dist/component/pushing.js +1009 -0
  52. package/dist/component/pushing.js.map +1 -0
  53. package/dist/component/queue.d.ts +361 -0
  54. package/dist/component/queue.d.ts.map +1 -0
  55. package/dist/component/queue.js +1407 -0
  56. package/dist/component/queue.js.map +1 -0
  57. package/dist/component/scheduler.d.ts +116 -0
  58. package/dist/component/scheduler.d.ts.map +1 -0
  59. package/dist/component/scheduler.js +410 -0
  60. package/dist/component/scheduler.js.map +1 -0
  61. package/dist/component/schema.d.ts +648 -0
  62. package/dist/component/schema.d.ts.map +1 -0
  63. package/dist/component/schema.js +295 -0
  64. package/dist/component/schema.js.map +1 -0
  65. package/dist/react/index.d.ts +2 -0
  66. package/dist/react/index.d.ts.map +1 -0
  67. package/dist/react/index.js +6 -0
  68. package/dist/react/index.js.map +1 -0
  69. package/package.json +1 -1
@@ -0,0 +1,795 @@
1
+ import { actionGeneric, httpActionGeneric, mutationGeneric, queryGeneric, } from "convex/server";
2
+ import { v } from "convex/values";
3
+ import { providerConfigValidator, scalingPolicyValidator, } from "../component/config.js";
4
+ const pushPeriodicityValidator = v.union(v.literal("manual"), v.literal("daily"), v.literal("weekly"), v.literal("monthly"));
5
+ const pushSuggestedTimeValidator = v.union(v.object({
6
+ kind: v.literal("daily"),
7
+ time: v.string(),
8
+ }), v.object({
9
+ kind: v.literal("weekly"),
10
+ weekday: v.number(),
11
+ time: v.string(),
12
+ }), v.object({
13
+ kind: v.literal("monthly"),
14
+ dayOfMonth: v.union(v.number(), v.literal("last")),
15
+ time: v.string(),
16
+ }));
17
+ const pushScheduleValidator = v.union(v.object({
18
+ kind: v.literal("manual"),
19
+ }), v.object({
20
+ kind: v.literal("daily"),
21
+ time: v.string(),
22
+ }), v.object({
23
+ kind: v.literal("weekly"),
24
+ weekday: v.number(),
25
+ time: v.string(),
26
+ }), v.object({
27
+ kind: v.literal("monthly"),
28
+ dayOfMonth: v.union(v.number(), v.literal("last")),
29
+ time: v.string(),
30
+ }));
31
+ export { bridgeFunctionKeyFromToolName, executeBridgeFunction, isBridgeToolName, maybeExecuteBridgeToolCall, resolveBridgeRuntimeConfig, } from "./bridge.js";
32
+ export function exposeApi(component, options) {
33
+ return {
34
+ queueStats: queryGeneric({
35
+ args: {},
36
+ handler: async (ctx) => {
37
+ await options.auth(ctx, { type: "read" });
38
+ return await ctx.runQuery(component.lib.queueStats, {});
39
+ },
40
+ }),
41
+ getProviderRuntimeConfig: queryGeneric({
42
+ args: {},
43
+ handler: async (ctx) => {
44
+ await options.auth(ctx, { type: "read" });
45
+ return await ctx.runQuery(component.queue.getProviderRuntimeConfig, {});
46
+ },
47
+ }),
48
+ setProviderRuntimeConfig: mutationGeneric({
49
+ args: {
50
+ providerConfig: providerConfigValidator,
51
+ },
52
+ handler: async (ctx, args) => {
53
+ await options.auth(ctx, { type: "write" });
54
+ await ctx.runMutation(component.queue.upsertProviderRuntimeConfig, args);
55
+ return null;
56
+ },
57
+ }),
58
+ enqueue: mutationGeneric({
59
+ args: {
60
+ conversationId: v.string(),
61
+ agentKey: v.string(),
62
+ provider: v.string(),
63
+ providerUserId: v.string(),
64
+ messageText: v.string(),
65
+ externalMessageId: v.optional(v.string()),
66
+ rawUpdateJson: v.optional(v.string()),
67
+ metadata: v.optional(v.record(v.string(), v.string())),
68
+ priority: v.optional(v.number()),
69
+ providerConfig: v.optional(providerConfigValidator),
70
+ },
71
+ handler: async (ctx, args) => {
72
+ await options.auth(ctx, {
73
+ type: "write",
74
+ conversationId: args.conversationId,
75
+ agentKey: args.agentKey,
76
+ });
77
+ return await ctx.runMutation(component.lib.enqueue, {
78
+ conversationId: args.conversationId,
79
+ agentKey: args.agentKey,
80
+ payload: {
81
+ provider: args.provider,
82
+ providerUserId: args.providerUserId,
83
+ messageText: args.messageText,
84
+ externalMessageId: args.externalMessageId,
85
+ rawUpdateJson: args.rawUpdateJson,
86
+ metadata: args.metadata,
87
+ },
88
+ priority: args.priority,
89
+ providerConfig: args.providerConfig ?? options.providerConfig,
90
+ });
91
+ },
92
+ }),
93
+ workerStats: queryGeneric({
94
+ args: {},
95
+ handler: async (ctx) => {
96
+ await options.auth(ctx, { type: "read" });
97
+ return await ctx.runQuery(component.lib.workerStats, {});
98
+ },
99
+ }),
100
+ workerClaim: mutationGeneric({
101
+ args: {
102
+ workerId: v.string(),
103
+ conversationId: v.optional(v.string()),
104
+ },
105
+ handler: async (ctx, args) => {
106
+ await options.auth(ctx, { type: "write" });
107
+ const { conversationId: _, ...claimArgs } = args;
108
+ return await ctx.runMutation(component.queue.claimNextJob, claimArgs);
109
+ },
110
+ }),
111
+ workerHeartbeat: mutationGeneric({
112
+ args: {
113
+ workerId: v.string(),
114
+ messageId: v.string(),
115
+ leaseId: v.string(),
116
+ },
117
+ handler: async (ctx, args) => {
118
+ await options.auth(ctx, { type: "write" });
119
+ return await ctx.runMutation(component.queue.heartbeatJob, args);
120
+ },
121
+ }),
122
+ workerComplete: mutationGeneric({
123
+ args: {
124
+ workerId: v.string(),
125
+ messageId: v.string(),
126
+ leaseId: v.string(),
127
+ },
128
+ handler: async (ctx, args) => {
129
+ await options.auth(ctx, { type: "write" });
130
+ return await ctx.runMutation(component.queue.completeJob, {
131
+ ...args,
132
+ providerConfig: options.providerConfig,
133
+ });
134
+ },
135
+ }),
136
+ workerFail: mutationGeneric({
137
+ args: {
138
+ workerId: v.string(),
139
+ messageId: v.string(),
140
+ leaseId: v.string(),
141
+ errorMessage: v.string(),
142
+ },
143
+ handler: async (ctx, args) => {
144
+ await options.auth(ctx, { type: "write" });
145
+ return await ctx.runMutation(component.queue.failJob, {
146
+ ...args,
147
+ providerConfig: options.providerConfig,
148
+ });
149
+ },
150
+ }),
151
+ workerHydrationBundle: queryGeneric({
152
+ args: {
153
+ messageId: v.string(),
154
+ workspaceId: v.string(),
155
+ },
156
+ handler: async (ctx, args) => {
157
+ await options.auth(ctx, { type: "read" });
158
+ return await ctx.runQuery(component.queue.getHydrationBundleForClaimedJob, args);
159
+ },
160
+ }),
161
+ workerConversationHasQueued: queryGeneric({
162
+ args: {
163
+ conversationId: v.string(),
164
+ },
165
+ handler: async (ctx, args) => {
166
+ await options.auth(ctx, { type: "read" });
167
+ return await ctx.runQuery(component.queue.hasQueuedJobsForConversation, args);
168
+ },
169
+ }),
170
+ workerAppendConversationMessages: mutationGeneric({
171
+ args: {
172
+ conversationId: v.string(),
173
+ workspaceId: v.optional(v.string()),
174
+ messages: v.array(v.object({
175
+ role: v.union(v.literal("system"), v.literal("user"), v.literal("assistant"), v.literal("tool")),
176
+ content: v.string(),
177
+ at: v.optional(v.number()),
178
+ })),
179
+ },
180
+ handler: async (ctx, args) => {
181
+ await options.auth(ctx, { type: "write", conversationId: args.conversationId });
182
+ return await ctx.runMutation(component.lib.appendConversationMessages, args);
183
+ },
184
+ }),
185
+ workerControlState: queryGeneric({
186
+ args: {
187
+ workerId: v.string(),
188
+ },
189
+ handler: async (ctx, args) => {
190
+ await options.auth(ctx, { type: "read" });
191
+ return await ctx.runQuery(component.queue.getWorkerControlState, args);
192
+ },
193
+ }),
194
+ workerPrepareSnapshotUpload: mutationGeneric({
195
+ args: {
196
+ workerId: v.string(),
197
+ workspaceId: v.string(),
198
+ agentKey: v.string(),
199
+ conversationId: v.optional(v.string()),
200
+ reason: v.union(v.literal("drain"), v.literal("signal"), v.literal("manual")),
201
+ },
202
+ handler: async (ctx, args) => {
203
+ await options.auth(ctx, { type: "write" });
204
+ return await ctx.runMutation(component.queue.prepareDataSnapshotUpload, args);
205
+ },
206
+ }),
207
+ workerFinalizeSnapshotUpload: mutationGeneric({
208
+ args: {
209
+ workerId: v.string(),
210
+ snapshotId: v.string(),
211
+ storageId: v.string(),
212
+ sha256: v.string(),
213
+ sizeBytes: v.number(),
214
+ },
215
+ handler: async (ctx, args) => {
216
+ await options.auth(ctx, { type: "write" });
217
+ return await ctx.runMutation(component.queue.finalizeDataSnapshotUpload, args);
218
+ },
219
+ }),
220
+ workerFailSnapshotUpload: mutationGeneric({
221
+ args: {
222
+ workerId: v.string(),
223
+ snapshotId: v.string(),
224
+ error: v.string(),
225
+ },
226
+ handler: async (ctx, args) => {
227
+ await options.auth(ctx, { type: "write" });
228
+ return await ctx.runMutation(component.queue.failDataSnapshotUpload, args);
229
+ },
230
+ }),
231
+ workerLatestSnapshotForRestore: queryGeneric({
232
+ args: {
233
+ workspaceId: v.string(),
234
+ agentKey: v.string(),
235
+ conversationId: v.optional(v.string()),
236
+ },
237
+ handler: async (ctx, args) => {
238
+ await options.auth(ctx, { type: "read" });
239
+ return await ctx.runQuery(component.queue.getLatestDataSnapshotForRestore, args);
240
+ },
241
+ }),
242
+ workerGenerateMediaUploadUrl: mutationGeneric({
243
+ args: {},
244
+ handler: async (ctx) => {
245
+ await options.auth(ctx, { type: "write" });
246
+ return await ctx.runMutation(component.queue.generateMediaUploadUrl, {});
247
+ },
248
+ }),
249
+ workerGetStorageFileUrl: queryGeneric({
250
+ args: {
251
+ storageId: v.string(),
252
+ },
253
+ handler: async (ctx, args) => {
254
+ await options.auth(ctx, { type: "read" });
255
+ return await ctx.runQuery(component.queue.getStorageFileUrl, args);
256
+ },
257
+ }),
258
+ workerAttachMessageMetadata: mutationGeneric({
259
+ args: {
260
+ messageId: v.string(),
261
+ metadata: v.record(v.string(), v.string()),
262
+ },
263
+ handler: async (ctx, args) => {
264
+ await options.auth(ctx, { type: "write" });
265
+ return await ctx.runMutation(component.queue.attachMessageMetadata, args);
266
+ },
267
+ }),
268
+ seedDefaultAgent: mutationGeneric({
269
+ args: {},
270
+ handler: async (ctx) => {
271
+ await options.auth(ctx, { type: "read" });
272
+ return await ctx.runMutation(component.lib.configureAgent, {
273
+ agentKey: "default",
274
+ version: "1.0.0",
275
+ soulMd: "# Soul",
276
+ clientMd: "# Client",
277
+ skills: ["agent-bridge"],
278
+ secretsRef: ["telegram.botToken"],
279
+ enabled: true,
280
+ });
281
+ },
282
+ }),
283
+ importSecret: mutationGeneric({
284
+ args: {
285
+ secretRef: v.string(),
286
+ plaintextValue: v.string(),
287
+ metadata: v.optional(v.record(v.string(), v.string())),
288
+ },
289
+ handler: async (ctx, args) => {
290
+ await options.auth(ctx, { type: "read" });
291
+ return await ctx.runMutation(component.lib.importSecret, args);
292
+ },
293
+ }),
294
+ secretStatus: queryGeneric({
295
+ args: {
296
+ secretRefs: v.array(v.string()),
297
+ },
298
+ handler: async (ctx, args) => {
299
+ await options.auth(ctx, { type: "read" });
300
+ return await ctx.runQuery(component.lib.secretStatus, {
301
+ secretRefs: args.secretRefs,
302
+ });
303
+ },
304
+ }),
305
+ startWorkers: actionGeneric({
306
+ args: {
307
+ flyApiToken: v.optional(v.string()),
308
+ convexUrl: v.optional(v.string()),
309
+ workspaceId: v.optional(v.string()),
310
+ scalingPolicy: v.optional(scalingPolicyValidator),
311
+ },
312
+ handler: async (ctx, args) => {
313
+ await options.auth(ctx, { type: "read" });
314
+ return await ctx.runAction(component.lib.reconcileWorkers, {
315
+ flyApiToken: args.flyApiToken,
316
+ convexUrl: args.convexUrl,
317
+ workspaceId: args.workspaceId,
318
+ scalingPolicy: args.scalingPolicy,
319
+ providerConfig: options.providerConfig,
320
+ });
321
+ },
322
+ }),
323
+ checkIdleShutdowns: actionGeneric({
324
+ args: {
325
+ flyApiToken: v.optional(v.string()),
326
+ },
327
+ handler: async (ctx, args) => {
328
+ await options.auth(ctx, { type: "read" });
329
+ return await ctx.runAction(component.lib.checkIdleShutdowns, {
330
+ flyApiToken: args.flyApiToken,
331
+ providerConfig: options.providerConfig,
332
+ });
333
+ },
334
+ }),
335
+ deleteFlyVolume: actionGeneric({
336
+ args: {
337
+ appName: v.string(),
338
+ volumeId: v.string(),
339
+ flyApiToken: v.optional(v.string()),
340
+ },
341
+ handler: async (ctx, args) => {
342
+ await options.auth(ctx, { type: "read" });
343
+ return await ctx.runAction(component.lib.deleteFlyVolume, args);
344
+ },
345
+ }),
346
+ recoverQueue: actionGeneric({
347
+ args: {
348
+ nowMs: v.optional(v.number()),
349
+ releaseLimit: v.optional(v.number()),
350
+ workspaceId: v.optional(v.string()),
351
+ scalingPolicy: v.optional(scalingPolicyValidator),
352
+ },
353
+ handler: async (ctx, args) => {
354
+ await options.auth(ctx, { type: "read" });
355
+ const released = await ctx.runMutation(component.lib.releaseStuckJobs, {
356
+ nowMs: args.nowMs,
357
+ limit: args.releaseLimit,
358
+ });
359
+ const reconcile = await ctx.runAction(component.lib.reconcileWorkers, {
360
+ workspaceId: args.workspaceId,
361
+ scalingPolicy: args.scalingPolicy,
362
+ providerConfig: options.providerConfig,
363
+ });
364
+ return {
365
+ released,
366
+ reconcile,
367
+ };
368
+ },
369
+ }),
370
+ bindUserAgent: mutationGeneric({
371
+ args: {
372
+ consumerUserId: v.string(),
373
+ agentKey: v.string(),
374
+ source: v.optional(v.union(v.literal("manual"), v.literal("telegram_pairing"), v.literal("api"))),
375
+ telegramUserId: v.optional(v.string()),
376
+ telegramChatId: v.optional(v.string()),
377
+ metadata: v.optional(v.record(v.string(), v.string())),
378
+ },
379
+ handler: async (ctx, args) => {
380
+ await options.auth(ctx, { type: "read" });
381
+ return await ctx.runMutation(component.lib.bindUserAgent, args);
382
+ },
383
+ }),
384
+ revokeUserAgentBinding: mutationGeneric({
385
+ args: {
386
+ consumerUserId: v.string(),
387
+ },
388
+ handler: async (ctx, args) => {
389
+ await options.auth(ctx, { type: "read" });
390
+ return await ctx.runMutation(component.lib.revokeUserAgentBinding, args);
391
+ },
392
+ }),
393
+ myAgentKey: queryGeneric({
394
+ args: {
395
+ consumerUserId: v.optional(v.string()),
396
+ },
397
+ handler: async (ctx, args) => {
398
+ const authUserId = await options.auth(ctx, { type: "read" });
399
+ const consumerUserId = args.consumerUserId ?? authUserId;
400
+ return await ctx.runQuery(component.lib.resolveAgentForUser, {
401
+ consumerUserId,
402
+ });
403
+ },
404
+ }),
405
+ getUserAgentBinding: queryGeneric({
406
+ args: {
407
+ consumerUserId: v.string(),
408
+ },
409
+ handler: async (ctx, args) => {
410
+ await options.auth(ctx, { type: "read" });
411
+ return await ctx.runQuery(component.lib.getUserAgentBinding, args);
412
+ },
413
+ }),
414
+ resolveAgentForTelegram: queryGeneric({
415
+ args: {
416
+ telegramUserId: v.optional(v.string()),
417
+ telegramChatId: v.optional(v.string()),
418
+ },
419
+ handler: async (ctx, args) => {
420
+ await options.auth(ctx, { type: "read" });
421
+ return await ctx.runQuery(component.lib.resolveAgentForTelegram, args);
422
+ },
423
+ }),
424
+ createPairingCode: mutationGeneric({
425
+ args: {
426
+ consumerUserId: v.string(),
427
+ agentKey: v.string(),
428
+ ttlMs: v.optional(v.number()),
429
+ },
430
+ handler: async (ctx, args) => {
431
+ await options.auth(ctx, { type: "read" });
432
+ return await ctx.runMutation(component.lib.createPairingCode, args);
433
+ },
434
+ }),
435
+ consumePairingCode: mutationGeneric({
436
+ args: {
437
+ code: v.string(),
438
+ telegramUserId: v.string(),
439
+ telegramChatId: v.string(),
440
+ },
441
+ handler: async (ctx, args) => {
442
+ await options.auth(ctx, { type: "read" });
443
+ return await ctx.runMutation(component.lib.consumePairingCode, args);
444
+ },
445
+ }),
446
+ getPairingCodeStatus: queryGeneric({
447
+ args: {
448
+ code: v.string(),
449
+ },
450
+ handler: async (ctx, args) => {
451
+ await options.auth(ctx, { type: "read" });
452
+ return await ctx.runQuery(component.lib.getPairingCodeStatus, args);
453
+ },
454
+ }),
455
+ configureTelegramWebhook: actionGeneric({
456
+ args: {
457
+ convexSiteUrl: v.string(),
458
+ secretRef: v.optional(v.string()),
459
+ },
460
+ handler: async (ctx, args) => {
461
+ await options.auth(ctx, { type: "read" });
462
+ return await ctx.runAction(component.lib.configureTelegramWebhook, args);
463
+ },
464
+ }),
465
+ createPushTemplate: mutationGeneric({
466
+ args: {
467
+ companyId: v.string(),
468
+ templateKey: v.string(),
469
+ title: v.string(),
470
+ text: v.string(),
471
+ periodicity: pushPeriodicityValidator,
472
+ suggestedTimes: v.array(pushSuggestedTimeValidator),
473
+ enabled: v.optional(v.boolean()),
474
+ actorUserId: v.string(),
475
+ },
476
+ handler: async (ctx, args) => {
477
+ await options.auth(ctx, { type: "write" });
478
+ return await ctx.runMutation(component.lib.createPushTemplate, args);
479
+ },
480
+ }),
481
+ updatePushTemplate: mutationGeneric({
482
+ args: {
483
+ templateId: v.string(),
484
+ title: v.optional(v.string()),
485
+ text: v.optional(v.string()),
486
+ periodicity: v.optional(pushPeriodicityValidator),
487
+ suggestedTimes: v.optional(v.array(pushSuggestedTimeValidator)),
488
+ enabled: v.optional(v.boolean()),
489
+ actorUserId: v.string(),
490
+ },
491
+ handler: async (ctx, args) => {
492
+ await options.auth(ctx, { type: "write" });
493
+ return await ctx.runMutation(component.lib.updatePushTemplate, args);
494
+ },
495
+ }),
496
+ deletePushTemplate: mutationGeneric({
497
+ args: {
498
+ templateId: v.string(),
499
+ },
500
+ handler: async (ctx, args) => {
501
+ await options.auth(ctx, { type: "write" });
502
+ return await ctx.runMutation(component.lib.deletePushTemplate, args);
503
+ },
504
+ }),
505
+ listPushTemplatesByCompany: queryGeneric({
506
+ args: {
507
+ companyId: v.string(),
508
+ includeDisabled: v.optional(v.boolean()),
509
+ },
510
+ handler: async (ctx, args) => {
511
+ await options.auth(ctx, { type: "read" });
512
+ return await ctx.runQuery(component.lib.listPushTemplatesByCompany, args);
513
+ },
514
+ }),
515
+ createPushJobFromTemplate: mutationGeneric({
516
+ args: {
517
+ companyId: v.string(),
518
+ consumerUserId: v.string(),
519
+ templateId: v.string(),
520
+ timezone: v.string(),
521
+ schedule: v.optional(pushScheduleValidator),
522
+ enabled: v.optional(v.boolean()),
523
+ },
524
+ handler: async (ctx, args) => {
525
+ await options.auth(ctx, { type: "write" });
526
+ return await ctx.runMutation(component.lib.createPushJobFromTemplate, args);
527
+ },
528
+ }),
529
+ createPushJobCustom: mutationGeneric({
530
+ args: {
531
+ companyId: v.string(),
532
+ consumerUserId: v.string(),
533
+ title: v.string(),
534
+ text: v.string(),
535
+ periodicity: pushPeriodicityValidator,
536
+ timezone: v.string(),
537
+ schedule: pushScheduleValidator,
538
+ enabled: v.optional(v.boolean()),
539
+ },
540
+ handler: async (ctx, args) => {
541
+ await options.auth(ctx, { type: "write" });
542
+ return await ctx.runMutation(component.lib.createPushJobCustom, args);
543
+ },
544
+ }),
545
+ updatePushJob: mutationGeneric({
546
+ args: {
547
+ jobId: v.string(),
548
+ title: v.optional(v.string()),
549
+ text: v.optional(v.string()),
550
+ periodicity: v.optional(pushPeriodicityValidator),
551
+ timezone: v.optional(v.string()),
552
+ schedule: v.optional(pushScheduleValidator),
553
+ enabled: v.optional(v.boolean()),
554
+ },
555
+ handler: async (ctx, args) => {
556
+ await options.auth(ctx, { type: "write" });
557
+ return await ctx.runMutation(component.lib.updatePushJob, args);
558
+ },
559
+ }),
560
+ deletePushJob: mutationGeneric({
561
+ args: {
562
+ jobId: v.string(),
563
+ },
564
+ handler: async (ctx, args) => {
565
+ await options.auth(ctx, { type: "write" });
566
+ return await ctx.runMutation(component.lib.deletePushJob, args);
567
+ },
568
+ }),
569
+ setPushJobEnabled: mutationGeneric({
570
+ args: {
571
+ jobId: v.string(),
572
+ enabled: v.boolean(),
573
+ },
574
+ handler: async (ctx, args) => {
575
+ await options.auth(ctx, { type: "write" });
576
+ return await ctx.runMutation(component.lib.setPushJobEnabled, args);
577
+ },
578
+ }),
579
+ listPushJobsForUser: queryGeneric({
580
+ args: {
581
+ consumerUserId: v.string(),
582
+ includeDisabled: v.optional(v.boolean()),
583
+ },
584
+ handler: async (ctx, args) => {
585
+ await options.auth(ctx, { type: "read" });
586
+ return await ctx.runQuery(component.lib.listPushJobsForUser, args);
587
+ },
588
+ }),
589
+ triggerPushJobNow: mutationGeneric({
590
+ args: {
591
+ jobId: v.string(),
592
+ },
593
+ handler: async (ctx, args) => {
594
+ await options.auth(ctx, { type: "write" });
595
+ return await ctx.runMutation(component.lib.triggerPushJobNow, {
596
+ ...args,
597
+ providerConfig: options.providerConfig,
598
+ });
599
+ },
600
+ }),
601
+ dispatchDuePushJobs: mutationGeneric({
602
+ args: {
603
+ nowMs: v.optional(v.number()),
604
+ limit: v.optional(v.number()),
605
+ },
606
+ handler: async (ctx, args) => {
607
+ await options.auth(ctx, { type: "write" });
608
+ return await ctx.runMutation(component.lib.dispatchDuePushJobs, {
609
+ ...args,
610
+ providerConfig: options.providerConfig,
611
+ });
612
+ },
613
+ }),
614
+ sendBroadcastToAllActiveAgents: mutationGeneric({
615
+ args: {
616
+ companyId: v.string(),
617
+ title: v.string(),
618
+ text: v.string(),
619
+ requestedBy: v.string(),
620
+ },
621
+ handler: async (ctx, args) => {
622
+ await options.auth(ctx, { type: "write" });
623
+ return await ctx.runMutation(component.lib.sendBroadcastToAllActiveAgents, {
624
+ ...args,
625
+ providerConfig: options.providerConfig,
626
+ });
627
+ },
628
+ }),
629
+ listPushDispatchesByJob: queryGeneric({
630
+ args: {
631
+ jobId: v.string(),
632
+ limit: v.optional(v.number()),
633
+ },
634
+ handler: async (ctx, args) => {
635
+ await options.auth(ctx, { type: "read" });
636
+ return await ctx.runQuery(component.lib.listPushDispatchesByJob, args);
637
+ },
638
+ }),
639
+ };
640
+ }
641
+ /**
642
+ * Register a Telegram webhook ingress route.
643
+ * The route only enqueues jobs in Convex and does not process messages.
644
+ */
645
+ export function registerRoutes(http, component, { pathPrefix = "/agent-factory", resolveAgentKey, resolveAgentKeyFromBinding = true, fallbackAgentKey = "default", requireBindingForTelegram = false, providerConfig, } = {}) {
646
+ http.route({
647
+ path: `${pathPrefix}/telegram/webhook`,
648
+ method: "POST",
649
+ handler: httpActionGeneric(async (ctx, request) => {
650
+ const update = (await request.json());
651
+ const message = update.message;
652
+ if (!message?.chat?.id || !message?.from?.id) {
653
+ return new Response(JSON.stringify({ ok: true, ignored: true }), {
654
+ status: 200,
655
+ headers: { "Content-Type": "application/json" },
656
+ });
657
+ }
658
+ const telegramUserId = String(message.from.id);
659
+ const telegramChatId = String(message.chat.id);
660
+ const text = typeof message.text === "string" ? message.text.trim() : "";
661
+ const caption = typeof message.caption === "string" ? message.caption.trim() : "";
662
+ const hasPhoto = Array.isArray(message.photo) && message.photo.length > 0;
663
+ const hasVideo = !!message.video;
664
+ const hasAudio = !!message.audio || !!message.voice;
665
+ const startCommandCode = text ? parseStartCommandCode(text) : null;
666
+ const isStartCommand = text.trimStart().startsWith("/start");
667
+ if (startCommandCode) {
668
+ try {
669
+ const pairing = await ctx.runMutation(component.lib.consumePairingCode, {
670
+ code: startCommandCode,
671
+ telegramUserId,
672
+ telegramChatId,
673
+ });
674
+ return new Response(JSON.stringify({
675
+ ok: true,
676
+ pairing: {
677
+ status: pairing.status,
678
+ consumerUserId: pairing.consumerUserId,
679
+ agentKey: pairing.agentKey,
680
+ },
681
+ }), {
682
+ status: 200,
683
+ headers: { "Content-Type": "application/json" },
684
+ });
685
+ }
686
+ catch (error) {
687
+ return new Response(JSON.stringify({
688
+ ok: true,
689
+ pairing: {
690
+ status: "failed",
691
+ error: error instanceof Error ? error.message : String(error),
692
+ },
693
+ }), {
694
+ status: 200,
695
+ headers: { "Content-Type": "application/json" },
696
+ });
697
+ }
698
+ }
699
+ if (isStartCommand) {
700
+ return new Response(JSON.stringify({
701
+ ok: true,
702
+ pairing: {
703
+ status: "failed",
704
+ error: "missing or invalid pairing code in /start command",
705
+ },
706
+ }), {
707
+ status: 200,
708
+ headers: { "Content-Type": "application/json" },
709
+ });
710
+ }
711
+ const mapped = resolveAgentKeyFromBinding
712
+ ? await ctx.runQuery(component.lib.resolveAgentForTelegram, {
713
+ telegramUserId,
714
+ telegramChatId,
715
+ })
716
+ : { consumerUserId: null, agentKey: null };
717
+ const configuredAgentKey = resolveAgentKey ? resolveAgentKey(update) : null;
718
+ const agentKey = configuredAgentKey ?? mapped.agentKey ?? fallbackAgentKey;
719
+ if (!agentKey || (requireBindingForTelegram && !configuredAgentKey && !mapped.agentKey)) {
720
+ return new Response(JSON.stringify({ ok: false, error: "no active binding for telegram user" }), {
721
+ status: 403,
722
+ headers: { "Content-Type": "application/json" },
723
+ });
724
+ }
725
+ const messageText = text ||
726
+ caption ||
727
+ (hasPhoto && hasVideo && hasAudio
728
+ ? "[telegram media] photo + video + audio message"
729
+ : hasPhoto && hasVideo
730
+ ? "[telegram media] photo + video message"
731
+ : hasPhoto && hasAudio
732
+ ? "[telegram media] photo + audio message"
733
+ : hasVideo && hasAudio
734
+ ? "[telegram media] video + audio message"
735
+ : hasPhoto
736
+ ? "[telegram media] photo message"
737
+ : hasVideo
738
+ ? "[telegram media] video message"
739
+ : hasAudio
740
+ ? "[telegram media] audio message"
741
+ : "");
742
+ if (!messageText) {
743
+ return new Response(JSON.stringify({ ok: true, ignored: true }), {
744
+ status: 200,
745
+ headers: { "Content-Type": "application/json" },
746
+ });
747
+ }
748
+ const metadata = {
749
+ telegramChatId,
750
+ telegramUserId,
751
+ };
752
+ if (hasPhoto) {
753
+ metadata.telegramMediaType = "photo";
754
+ const largestPhoto = message.photo?.[message.photo.length - 1];
755
+ if (largestPhoto?.file_id) {
756
+ metadata.telegramPhotoFileId = largestPhoto.file_id;
757
+ }
758
+ }
759
+ if (message.audio?.file_id) {
760
+ metadata.telegramMediaType = hasPhoto ? "photo+audio" : hasVideo ? "video+audio" : "audio";
761
+ metadata.telegramAudioFileId = message.audio.file_id;
762
+ }
763
+ if (message.voice?.file_id) {
764
+ metadata.telegramMediaType = hasPhoto ? "photo+voice" : hasVideo ? "video+voice" : "voice";
765
+ metadata.telegramVoiceFileId = message.voice.file_id;
766
+ }
767
+ if (message.video?.file_id) {
768
+ metadata.telegramMediaType = hasPhoto ? "photo+video" : "video";
769
+ metadata.telegramVideoFileId = message.video.file_id;
770
+ }
771
+ await ctx.runMutation(component.lib.enqueue, {
772
+ conversationId: `telegram:${telegramChatId}`,
773
+ agentKey,
774
+ payload: {
775
+ provider: "telegram",
776
+ providerUserId: telegramUserId,
777
+ messageText,
778
+ externalMessageId: String(message.message_id ?? update.update_id ?? ""),
779
+ rawUpdateJson: JSON.stringify(update),
780
+ metadata,
781
+ },
782
+ providerConfig,
783
+ });
784
+ return new Response(JSON.stringify({ ok: true }), {
785
+ status: 202,
786
+ headers: { "Content-Type": "application/json" },
787
+ });
788
+ }),
789
+ });
790
+ }
791
+ function parseStartCommandCode(messageText) {
792
+ const match = messageText.match(/^\/start(?:@\w+)?\s+([A-Za-z0-9_-]{4,128})\s*$/);
793
+ return match ? match[1] : null;
794
+ }
795
+ //# sourceMappingURL=index.js.map