@okrlinkhub/agent-factory 0.1.0

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 (83) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +345 -0
  3. package/dist/client/_generated/_ignore.d.ts +1 -0
  4. package/dist/client/_generated/_ignore.d.ts.map +1 -0
  5. package/dist/client/_generated/_ignore.js +3 -0
  6. package/dist/client/_generated/_ignore.js.map +1 -0
  7. package/dist/client/index.d.ts +320 -0
  8. package/dist/client/index.d.ts.map +1 -0
  9. package/dist/client/index.js +509 -0
  10. package/dist/client/index.js.map +1 -0
  11. package/dist/component/_generated/api.d.ts +44 -0
  12. package/dist/component/_generated/api.d.ts.map +1 -0
  13. package/dist/component/_generated/api.js +31 -0
  14. package/dist/component/_generated/api.js.map +1 -0
  15. package/dist/component/_generated/component.d.ts +694 -0
  16. package/dist/component/_generated/component.d.ts.map +1 -0
  17. package/dist/component/_generated/component.js +11 -0
  18. package/dist/component/_generated/component.js.map +1 -0
  19. package/dist/component/_generated/dataModel.d.ts +46 -0
  20. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  21. package/dist/component/_generated/dataModel.js +11 -0
  22. package/dist/component/_generated/dataModel.js.map +1 -0
  23. package/dist/component/_generated/server.d.ts +121 -0
  24. package/dist/component/_generated/server.d.ts.map +1 -0
  25. package/dist/component/_generated/server.js +78 -0
  26. package/dist/component/_generated/server.js.map +1 -0
  27. package/dist/component/config.d.ts +260 -0
  28. package/dist/component/config.d.ts.map +1 -0
  29. package/dist/component/config.js +154 -0
  30. package/dist/component/config.js.map +1 -0
  31. package/dist/component/convex.config.d.ts +3 -0
  32. package/dist/component/convex.config.d.ts.map +1 -0
  33. package/dist/component/convex.config.js +3 -0
  34. package/dist/component/convex.config.js.map +1 -0
  35. package/dist/component/identity.d.ts +98 -0
  36. package/dist/component/identity.d.ts.map +1 -0
  37. package/dist/component/identity.js +371 -0
  38. package/dist/component/identity.js.map +1 -0
  39. package/dist/component/lib.d.ts +4 -0
  40. package/dist/component/lib.d.ts.map +1 -0
  41. package/dist/component/lib.js +4 -0
  42. package/dist/component/lib.js.map +1 -0
  43. package/dist/component/providers/fly.d.ts +39 -0
  44. package/dist/component/providers/fly.d.ts.map +1 -0
  45. package/dist/component/providers/fly.js +145 -0
  46. package/dist/component/providers/fly.js.map +1 -0
  47. package/dist/component/queue.d.ts +294 -0
  48. package/dist/component/queue.d.ts.map +1 -0
  49. package/dist/component/queue.js +1278 -0
  50. package/dist/component/queue.js.map +1 -0
  51. package/dist/component/scheduler.d.ts +89 -0
  52. package/dist/component/scheduler.d.ts.map +1 -0
  53. package/dist/component/scheduler.js +275 -0
  54. package/dist/component/scheduler.js.map +1 -0
  55. package/dist/component/schema.d.ts +518 -0
  56. package/dist/component/schema.d.ts.map +1 -0
  57. package/dist/component/schema.js +243 -0
  58. package/dist/component/schema.js.map +1 -0
  59. package/dist/react/index.d.ts +2 -0
  60. package/dist/react/index.d.ts.map +1 -0
  61. package/dist/react/index.js +6 -0
  62. package/dist/react/index.js.map +1 -0
  63. package/package.json +102 -0
  64. package/src/client/_generated/_ignore.ts +1 -0
  65. package/src/client/index.test.ts +48 -0
  66. package/src/client/index.ts +586 -0
  67. package/src/client/setup.test.ts +26 -0
  68. package/src/component/_generated/api.ts +60 -0
  69. package/src/component/_generated/component.ts +902 -0
  70. package/src/component/_generated/dataModel.ts +60 -0
  71. package/src/component/_generated/server.ts +156 -0
  72. package/src/component/config.ts +236 -0
  73. package/src/component/convex.config.ts +3 -0
  74. package/src/component/identity.ts +450 -0
  75. package/src/component/lib.test.ts +319 -0
  76. package/src/component/lib.ts +30 -0
  77. package/src/component/providers/fly.ts +226 -0
  78. package/src/component/queue.ts +1544 -0
  79. package/src/component/scheduler.ts +362 -0
  80. package/src/component/schema.ts +336 -0
  81. package/src/component/setup.test.ts +11 -0
  82. package/src/react/index.ts +7 -0
  83. package/src/test.ts +18 -0
@@ -0,0 +1,154 @@
1
+ import { v } from "convex/values";
2
+ export const DEFAULT_WORKER_IMAGE = "registry.fly.io/agent-factory-workers:deployment-01KHZQWMNHF3PJGKGM1RJASPRG";
3
+ export const DEFAULT_WORKER_VOLUME_NAME = "openclaw_data";
4
+ export const DEFAULT_WORKER_VOLUME_PATH = "/data";
5
+ export const DEFAULT_WORKER_RUNTIME_ENV = {
6
+ NODE_ENV: "production",
7
+ OPENCLAW_GATEWAY_HOST: "127.0.0.1",
8
+ OPENCLAW_GATEWAY_PORT: "18789",
9
+ OPENCLAW_GATEWAY_URL: "http://127.0.0.1:18789",
10
+ OPENCLAW_STATE_DIR: "/data/.clawdbot",
11
+ OPENCLAW_WORKSPACE_DIR: "/data/workspace",
12
+ OPENCLAW_CONFIG_PATH: "/data/.clawdbot/openclaw.json",
13
+ OPENCLAW_REQUIRE_DATA_MOUNT: "true",
14
+ OPENCLAW_RUN_SETUP: "false",
15
+ OPENCLAW_SETUP_TIMEOUT_MS: "90000",
16
+ OPENCLAW_GATEWAY_COMMAND: "node /app/openclaw.mjs gateway",
17
+ OPENCLAW_GATEWAY_READY_TIMEOUT_MS: "60000",
18
+ OPENCLAW_GATEWAY_READY_POLL_MS: "500",
19
+ OPENCLAW_GATEWAY_READY_REQUIRED: "true",
20
+ };
21
+ export const queuePolicyValidator = v.object({
22
+ defaultPriority: v.number(),
23
+ maxPriority: v.number(),
24
+ claimBatchSize: v.number(),
25
+ });
26
+ export const retryPolicyValidator = v.object({
27
+ maxAttempts: v.number(),
28
+ baseDelayMs: v.number(),
29
+ maxDelayMs: v.number(),
30
+ backoffFactor: v.number(),
31
+ jitterRatio: v.number(),
32
+ });
33
+ export const leasePolicyValidator = v.object({
34
+ leaseMs: v.number(),
35
+ heartbeatIntervalMs: v.number(),
36
+ staleAfterMs: v.number(),
37
+ });
38
+ export const scalingPolicyValidator = v.object({
39
+ minWorkers: v.number(),
40
+ maxWorkers: v.number(),
41
+ queuePerWorkerTarget: v.number(),
42
+ spawnStep: v.number(),
43
+ idleTimeoutMs: v.number(),
44
+ reconcileIntervalMs: v.number(),
45
+ });
46
+ export const hydrationPolicyValidator = v.object({
47
+ memoryWindowDays: v.number(),
48
+ maxContextTokens: v.number(),
49
+ snapshotTtlMs: v.number(),
50
+ rebuildOnDocTypes: v.array(v.string()),
51
+ skillAssetScanMode: v.union(v.literal("manifest_only"), v.literal("manifest_and_assets")),
52
+ });
53
+ export const providerConfigValidator = v.object({
54
+ kind: v.union(v.literal("fly"), v.literal("runpod"), v.literal("ecs")),
55
+ appName: v.string(),
56
+ organizationSlug: v.string(),
57
+ image: v.string(),
58
+ region: v.string(),
59
+ volumeName: v.string(),
60
+ volumePath: v.string(),
61
+ volumeSizeGb: v.number(),
62
+ });
63
+ export const agentFactoryConfigValidator = v.object({
64
+ queue: queuePolicyValidator,
65
+ retry: retryPolicyValidator,
66
+ lease: leasePolicyValidator,
67
+ scaling: scalingPolicyValidator,
68
+ hydration: hydrationPolicyValidator,
69
+ provider: providerConfigValidator,
70
+ });
71
+ export const DEFAULT_CONFIG = {
72
+ queue: {
73
+ defaultPriority: 50,
74
+ maxPriority: 100,
75
+ claimBatchSize: 25,
76
+ },
77
+ retry: {
78
+ maxAttempts: 5,
79
+ baseDelayMs: 1_000,
80
+ maxDelayMs: 120_000,
81
+ backoffFactor: 2,
82
+ jitterRatio: 0.1,
83
+ },
84
+ lease: {
85
+ leaseMs: 360_000,
86
+ heartbeatIntervalMs: 15_000,
87
+ staleAfterMs: 420_000,
88
+ },
89
+ scaling: {
90
+ minWorkers: 0,
91
+ maxWorkers: 1,
92
+ queuePerWorkerTarget: 5,
93
+ spawnStep: 1,
94
+ idleTimeoutMs: 300_000,
95
+ reconcileIntervalMs: 15_000,
96
+ },
97
+ hydration: {
98
+ memoryWindowDays: 2,
99
+ maxContextTokens: 16_000,
100
+ snapshotTtlMs: 300_000,
101
+ rebuildOnDocTypes: ["soul", "user", "identity", "memory_daily", "custom"],
102
+ skillAssetScanMode: "manifest_and_assets",
103
+ },
104
+ provider: {
105
+ kind: "fly",
106
+ appName: "agent-factory-workers",
107
+ organizationSlug: "personal",
108
+ image: DEFAULT_WORKER_IMAGE,
109
+ region: "iad",
110
+ volumeName: DEFAULT_WORKER_VOLUME_NAME,
111
+ volumePath: DEFAULT_WORKER_VOLUME_PATH,
112
+ volumeSizeGb: 10,
113
+ },
114
+ };
115
+ export function mergeWithDefaultConfig(partial) {
116
+ return {
117
+ queue: {
118
+ ...DEFAULT_CONFIG.queue,
119
+ ...(partial?.queue ?? {}),
120
+ },
121
+ retry: {
122
+ ...DEFAULT_CONFIG.retry,
123
+ ...(partial?.retry ?? {}),
124
+ },
125
+ lease: {
126
+ ...DEFAULT_CONFIG.lease,
127
+ ...(partial?.lease ?? {}),
128
+ },
129
+ scaling: {
130
+ ...DEFAULT_CONFIG.scaling,
131
+ ...(partial?.scaling ?? {}),
132
+ },
133
+ hydration: {
134
+ ...DEFAULT_CONFIG.hydration,
135
+ ...(partial?.hydration ?? {}),
136
+ },
137
+ provider: {
138
+ ...DEFAULT_CONFIG.provider,
139
+ ...(partial?.provider ?? {}),
140
+ },
141
+ };
142
+ }
143
+ export function computeRetryDelayMs(attempts, policy, nowMs) {
144
+ const exponent = Math.max(0, attempts - 1);
145
+ const exponential = policy.baseDelayMs * policy.backoffFactor ** exponent;
146
+ const bounded = Math.min(policy.maxDelayMs, Math.max(policy.baseDelayMs, exponential));
147
+ const jitter = Math.floor(bounded * policy.jitterRatio * pseudoRandomFromNow(nowMs, attempts));
148
+ return bounded + jitter;
149
+ }
150
+ function pseudoRandomFromNow(nowMs, attempts) {
151
+ const seed = (nowMs ^ (attempts * 2654435761)) >>> 0;
152
+ return (seed % 10_000) / 10_000;
153
+ }
154
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/component/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AA6DlC,MAAM,CAAC,MAAM,oBAAoB,GAC/B,6EAA6E,CAAC;AAChF,MAAM,CAAC,MAAM,0BAA0B,GAAG,eAAe,CAAC;AAC1D,MAAM,CAAC,MAAM,0BAA0B,GAAG,OAAO,CAAC;AAClD,MAAM,CAAC,MAAM,0BAA0B,GAA2B;IAChE,QAAQ,EAAE,YAAY;IACtB,qBAAqB,EAAE,WAAW;IAClC,qBAAqB,EAAE,OAAO;IAC9B,oBAAoB,EAAE,wBAAwB;IAC9C,kBAAkB,EAAE,iBAAiB;IACrC,sBAAsB,EAAE,iBAAiB;IACzC,oBAAoB,EAAE,+BAA+B;IACrD,2BAA2B,EAAE,MAAM;IACnC,kBAAkB,EAAE,OAAO;IAC3B,yBAAyB,EAAE,OAAO;IAClC,wBAAwB,EAAE,gCAAgC;IAC1D,iCAAiC,EAAE,OAAO;IAC1C,8BAA8B,EAAE,KAAK;IACrC,+BAA+B,EAAE,MAAM;CACxC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE;IAC3B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;CAC3B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE;IACzB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;CACxB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC/B,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;CACzB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE;IAChC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE;IACzB,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE;CAChC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC5B,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC5B,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE;IACzB,iBAAiB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACtC,kBAAkB,EAAE,CAAC,CAAC,KAAK,CACzB,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,EAC1B,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,CACjC;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;CACzB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC;IAClD,KAAK,EAAE,oBAAoB;IAC3B,KAAK,EAAE,oBAAoB;IAC3B,KAAK,EAAE,oBAAoB;IAC3B,OAAO,EAAE,sBAAsB;IAC/B,SAAS,EAAE,wBAAwB;IACnC,QAAQ,EAAE,uBAAuB;CAClC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAuB;IAChD,KAAK,EAAE;QACL,eAAe,EAAE,EAAE;QACnB,WAAW,EAAE,GAAG;QAChB,cAAc,EAAE,EAAE;KACnB;IACD,KAAK,EAAE;QACL,WAAW,EAAE,CAAC;QACd,WAAW,EAAE,KAAK;QAClB,UAAU,EAAE,OAAO;QACnB,aAAa,EAAE,CAAC;QAChB,WAAW,EAAE,GAAG;KACjB;IACD,KAAK,EAAE;QACL,OAAO,EAAE,OAAO;QAChB,mBAAmB,EAAE,MAAM;QAC3B,YAAY,EAAE,OAAO;KACtB;IACD,OAAO,EAAE;QACP,UAAU,EAAE,CAAC;QACb,UAAU,EAAE,CAAC;QACb,oBAAoB,EAAE,CAAC;QACvB,SAAS,EAAE,CAAC;QACZ,aAAa,EAAE,OAAO;QACtB,mBAAmB,EAAE,MAAM;KAC5B;IACD,SAAS,EAAE;QACT,gBAAgB,EAAE,CAAC;QACnB,gBAAgB,EAAE,MAAM;QACxB,aAAa,EAAE,OAAO;QACtB,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC;QACzE,kBAAkB,EAAE,qBAAqB;KAC1C;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,KAAK;QACX,OAAO,EAAE,uBAAuB;QAChC,gBAAgB,EAAE,UAAU;QAC5B,KAAK,EAAE,oBAAoB;QAC3B,MAAM,EAAE,KAAK;QACb,UAAU,EAAE,0BAA0B;QACtC,UAAU,EAAE,0BAA0B;QACtC,YAAY,EAAE,EAAE;KACjB;CACF,CAAC;AAEF,MAAM,UAAU,sBAAsB,CACpC,OAAuD;IAEvD,OAAO;QACL,KAAK,EAAE;YACL,GAAG,cAAc,CAAC,KAAK;YACvB,GAAG,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC;SAC1B;QACD,KAAK,EAAE;YACL,GAAG,cAAc,CAAC,KAAK;YACvB,GAAG,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC;SAC1B;QACD,KAAK,EAAE;YACL,GAAG,cAAc,CAAC,KAAK;YACvB,GAAG,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC;SAC1B;QACD,OAAO,EAAE;YACP,GAAG,cAAc,CAAC,OAAO;YACzB,GAAG,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;SAC5B;QACD,SAAS,EAAE;YACT,GAAG,cAAc,CAAC,SAAS;YAC3B,GAAG,CAAC,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC;SAC9B;QACD,QAAQ,EAAE;YACR,GAAG,cAAc,CAAC,QAAQ;YAC1B,GAAG,CAAC,OAAO,EAAE,QAAQ,IAAI,EAAE,CAAC;SAC7B;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,MAAmB,EACnB,KAAa;IAEb,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;IAC3C,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,aAAa,IAAI,QAAQ,CAAC;IAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;IACvF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CACvB,OAAO,GAAG,MAAM,CAAC,WAAW,GAAG,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,CACpE,CAAC;IACF,OAAO,OAAO,GAAG,MAAM,CAAC;AAC1B,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa,EAAE,QAAgB;IAC1D,MAAM,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,QAAQ,GAAG,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC;IACrD,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC;AAClC,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("convex/server").ComponentDefinition<any>;
2
+ export default _default;
3
+ //# sourceMappingURL=convex.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convex.config.d.ts","sourceRoot":"","sources":["../../src/component/convex.config.ts"],"names":[],"mappings":";AAEA,wBAA+C"}
@@ -0,0 +1,3 @@
1
+ import { defineComponent } from "convex/server";
2
+ export default defineComponent("agentFactory");
3
+ //# sourceMappingURL=convex.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convex.config.js","sourceRoot":"","sources":["../../src/component/convex.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,eAAe,eAAe,CAAC,cAAc,CAAC,CAAC"}
@@ -0,0 +1,98 @@
1
+ export declare const createPairingCode: import("convex/server").RegisteredMutation<"public", {
2
+ ttlMs?: number | undefined;
3
+ nowMs?: number | undefined;
4
+ agentKey: string;
5
+ consumerUserId: string;
6
+ }, Promise<{
7
+ code: string;
8
+ consumerUserId: string;
9
+ agentKey: string;
10
+ status: "pending";
11
+ createdAt: number;
12
+ expiresAt: number;
13
+ usedAt: null;
14
+ telegramUserId: null;
15
+ telegramChatId: null;
16
+ }>>;
17
+ export declare const consumePairingCode: import("convex/server").RegisteredMutation<"public", {
18
+ nowMs?: number | undefined;
19
+ telegramUserId: string;
20
+ telegramChatId: string;
21
+ code: string;
22
+ }, Promise<{
23
+ code: string;
24
+ consumerUserId: string;
25
+ agentKey: string;
26
+ status: "used";
27
+ createdAt: number;
28
+ expiresAt: number;
29
+ usedAt: number;
30
+ telegramUserId: string;
31
+ telegramChatId: string;
32
+ }>>;
33
+ export declare const getPairingCodeStatus: import("convex/server").RegisteredQuery<"public", {
34
+ nowMs?: number | undefined;
35
+ code: string;
36
+ }, Promise<{
37
+ code: string;
38
+ consumerUserId: string;
39
+ agentKey: string;
40
+ status: "pending" | "expired" | "used";
41
+ createdAt: number;
42
+ expiresAt: number;
43
+ usedAt: number | null;
44
+ telegramUserId: string | null;
45
+ telegramChatId: string | null;
46
+ } | null>>;
47
+ export declare const bindUserAgent: import("convex/server").RegisteredMutation<"public", {
48
+ metadata?: Record<string, string> | undefined;
49
+ source?: "manual" | "telegram_pairing" | "api" | undefined;
50
+ telegramUserId?: string | undefined;
51
+ telegramChatId?: string | undefined;
52
+ nowMs?: number | undefined;
53
+ agentKey: string;
54
+ consumerUserId: string;
55
+ }, Promise<{
56
+ consumerUserId: string;
57
+ agentKey: string;
58
+ status: "active" | "revoked";
59
+ source: "manual" | "telegram_pairing" | "api";
60
+ telegramUserId: string | null;
61
+ telegramChatId: string | null;
62
+ metadata: Record<string, string> | null;
63
+ boundAt: number;
64
+ revokedAt: number | null;
65
+ }>>;
66
+ export declare const revokeUserAgentBinding: import("convex/server").RegisteredMutation<"public", {
67
+ nowMs?: number | undefined;
68
+ consumerUserId: string;
69
+ }, Promise<{
70
+ revoked: number;
71
+ }>>;
72
+ export declare const resolveAgentForUser: import("convex/server").RegisteredQuery<"public", {
73
+ consumerUserId: string;
74
+ }, Promise<{
75
+ consumerUserId: string;
76
+ agentKey: string | null;
77
+ }>>;
78
+ export declare const resolveAgentForTelegram: import("convex/server").RegisteredQuery<"public", {
79
+ telegramUserId?: string | undefined;
80
+ telegramChatId?: string | undefined;
81
+ }, Promise<{
82
+ consumerUserId: string | null;
83
+ agentKey: string | null;
84
+ }>>;
85
+ export declare const getUserAgentBinding: import("convex/server").RegisteredQuery<"public", {
86
+ consumerUserId: string;
87
+ }, Promise<{
88
+ consumerUserId: string;
89
+ agentKey: string;
90
+ status: "active" | "revoked";
91
+ source: "manual" | "telegram_pairing" | "api";
92
+ telegramUserId: string | null;
93
+ telegramChatId: string | null;
94
+ metadata: Record<string, string> | null;
95
+ boundAt: number;
96
+ revokedAt: number | null;
97
+ } | null>>;
98
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/component/identity.ts"],"names":[],"mappings":"AAoDA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;GAuE5B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;GAqD7B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;UAwC/B,CAAC;AAEH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;GAcxB,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;GAqBjC,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;GAqB9B,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;GAoDlC,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;UA2B9B,CAAC"}
@@ -0,0 +1,371 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query } from "./_generated/server.js";
3
+ const bindingStatusValidator = v.union(v.literal("active"), v.literal("revoked"));
4
+ const bindingSourceValidator = v.union(v.literal("manual"), v.literal("telegram_pairing"), v.literal("api"));
5
+ const pairingStatusValidator = v.union(v.literal("pending"), v.literal("used"), v.literal("expired"));
6
+ const bindingViewValidator = v.object({
7
+ consumerUserId: v.string(),
8
+ agentKey: v.string(),
9
+ status: bindingStatusValidator,
10
+ source: bindingSourceValidator,
11
+ telegramUserId: v.union(v.null(), v.string()),
12
+ telegramChatId: v.union(v.null(), v.string()),
13
+ metadata: v.union(v.null(), v.record(v.string(), v.string())),
14
+ boundAt: v.number(),
15
+ revokedAt: v.union(v.null(), v.number()),
16
+ });
17
+ const pairingCodeViewValidator = v.object({
18
+ code: v.string(),
19
+ consumerUserId: v.string(),
20
+ agentKey: v.string(),
21
+ status: pairingStatusValidator,
22
+ createdAt: v.number(),
23
+ expiresAt: v.number(),
24
+ usedAt: v.union(v.null(), v.number()),
25
+ telegramUserId: v.union(v.null(), v.string()),
26
+ telegramChatId: v.union(v.null(), v.string()),
27
+ });
28
+ export const createPairingCode = mutation({
29
+ args: {
30
+ consumerUserId: v.string(),
31
+ agentKey: v.string(),
32
+ ttlMs: v.optional(v.number()),
33
+ nowMs: v.optional(v.number()),
34
+ },
35
+ returns: pairingCodeViewValidator,
36
+ handler: async (ctx, args) => {
37
+ const nowMs = args.nowMs ?? Date.now();
38
+ const ttlMs = Math.max(60_000, Math.min(args.ttlMs ?? 15 * 60_000, 24 * 60 * 60 * 1000));
39
+ const expiresAt = nowMs + ttlMs;
40
+ const profile = await ctx.db
41
+ .query("agentProfiles")
42
+ .withIndex("by_agentKey", (q) => q.eq("agentKey", args.agentKey))
43
+ .unique();
44
+ if (!profile || !profile.enabled) {
45
+ throw new Error(`Agent profile '${args.agentKey}' not found or disabled`);
46
+ }
47
+ const pendingCodes = await ctx.db
48
+ .query("pairingCodes")
49
+ .withIndex("by_consumerUserId_and_status", (q) => q.eq("consumerUserId", args.consumerUserId).eq("status", "pending"))
50
+ .collect();
51
+ for (const row of pendingCodes) {
52
+ const nextStatus = (row.expiresAt <= nowMs || row.agentKey === args.agentKey) ? "expired" : "pending";
53
+ if (nextStatus !== row.status) {
54
+ await ctx.db.patch(row._id, { status: nextStatus });
55
+ }
56
+ }
57
+ let code = "";
58
+ let existing = null;
59
+ for (let attempt = 0; attempt < 5; attempt += 1) {
60
+ code = generatePairingCode();
61
+ existing = await ctx.db
62
+ .query("pairingCodes")
63
+ .withIndex("by_code", (q) => q.eq("code", code))
64
+ .unique();
65
+ if (!existing)
66
+ break;
67
+ }
68
+ if (existing) {
69
+ throw new Error("Failed to generate unique pairing code");
70
+ }
71
+ await ctx.db.insert("pairingCodes", {
72
+ code,
73
+ consumerUserId: args.consumerUserId,
74
+ agentKey: args.agentKey,
75
+ status: "pending",
76
+ createdAt: nowMs,
77
+ expiresAt,
78
+ });
79
+ return {
80
+ code,
81
+ consumerUserId: args.consumerUserId,
82
+ agentKey: args.agentKey,
83
+ status: "pending",
84
+ createdAt: nowMs,
85
+ expiresAt,
86
+ usedAt: null,
87
+ telegramUserId: null,
88
+ telegramChatId: null,
89
+ };
90
+ },
91
+ });
92
+ export const consumePairingCode = mutation({
93
+ args: {
94
+ code: v.string(),
95
+ telegramUserId: v.string(),
96
+ telegramChatId: v.string(),
97
+ nowMs: v.optional(v.number()),
98
+ },
99
+ returns: pairingCodeViewValidator,
100
+ handler: async (ctx, args) => {
101
+ const nowMs = args.nowMs ?? Date.now();
102
+ const pairing = await ctx.db
103
+ .query("pairingCodes")
104
+ .withIndex("by_code", (q) => q.eq("code", args.code))
105
+ .unique();
106
+ if (!pairing) {
107
+ throw new Error("Pairing code not found");
108
+ }
109
+ if (pairing.status !== "pending") {
110
+ throw new Error("Pairing code already used or expired");
111
+ }
112
+ if (pairing.expiresAt <= nowMs) {
113
+ await ctx.db.patch(pairing._id, { status: "expired" });
114
+ throw new Error("Pairing code expired");
115
+ }
116
+ await upsertBinding(ctx, {
117
+ consumerUserId: pairing.consumerUserId,
118
+ agentKey: pairing.agentKey,
119
+ source: "telegram_pairing",
120
+ telegramUserId: args.telegramUserId,
121
+ telegramChatId: args.telegramChatId,
122
+ nowMs,
123
+ });
124
+ await ctx.db.patch(pairing._id, {
125
+ status: "used",
126
+ usedAt: nowMs,
127
+ telegramUserId: args.telegramUserId,
128
+ telegramChatId: args.telegramChatId,
129
+ });
130
+ return {
131
+ code: pairing.code,
132
+ consumerUserId: pairing.consumerUserId,
133
+ agentKey: pairing.agentKey,
134
+ status: "used",
135
+ createdAt: pairing.createdAt,
136
+ expiresAt: pairing.expiresAt,
137
+ usedAt: nowMs,
138
+ telegramUserId: args.telegramUserId,
139
+ telegramChatId: args.telegramChatId,
140
+ };
141
+ },
142
+ });
143
+ export const getPairingCodeStatus = query({
144
+ args: {
145
+ code: v.string(),
146
+ nowMs: v.optional(v.number()),
147
+ },
148
+ returns: v.union(v.null(), pairingCodeViewValidator),
149
+ handler: async (ctx, args) => {
150
+ const nowMs = args.nowMs ?? Date.now();
151
+ const pairing = await ctx.db
152
+ .query("pairingCodes")
153
+ .withIndex("by_code", (q) => q.eq("code", args.code))
154
+ .unique();
155
+ if (!pairing)
156
+ return null;
157
+ if (pairing.status === "pending" && pairing.expiresAt <= nowMs) {
158
+ return {
159
+ code: pairing.code,
160
+ consumerUserId: pairing.consumerUserId,
161
+ agentKey: pairing.agentKey,
162
+ status: "expired",
163
+ createdAt: pairing.createdAt,
164
+ expiresAt: pairing.expiresAt,
165
+ usedAt: pairing.usedAt ?? null,
166
+ telegramUserId: pairing.telegramUserId ?? null,
167
+ telegramChatId: pairing.telegramChatId ?? null,
168
+ };
169
+ }
170
+ return {
171
+ code: pairing.code,
172
+ consumerUserId: pairing.consumerUserId,
173
+ agentKey: pairing.agentKey,
174
+ status: pairing.status,
175
+ createdAt: pairing.createdAt,
176
+ expiresAt: pairing.expiresAt,
177
+ usedAt: pairing.usedAt ?? null,
178
+ telegramUserId: pairing.telegramUserId ?? null,
179
+ telegramChatId: pairing.telegramChatId ?? null,
180
+ };
181
+ },
182
+ });
183
+ export const bindUserAgent = mutation({
184
+ args: {
185
+ consumerUserId: v.string(),
186
+ agentKey: v.string(),
187
+ source: v.optional(bindingSourceValidator),
188
+ telegramUserId: v.optional(v.string()),
189
+ telegramChatId: v.optional(v.string()),
190
+ metadata: v.optional(v.record(v.string(), v.string())),
191
+ nowMs: v.optional(v.number()),
192
+ },
193
+ returns: bindingViewValidator,
194
+ handler: async (ctx, args) => {
195
+ return upsertBinding(ctx, args);
196
+ },
197
+ });
198
+ export const revokeUserAgentBinding = mutation({
199
+ args: {
200
+ consumerUserId: v.string(),
201
+ nowMs: v.optional(v.number()),
202
+ },
203
+ returns: v.object({
204
+ revoked: v.number(),
205
+ }),
206
+ handler: async (ctx, args) => {
207
+ const nowMs = args.nowMs ?? Date.now();
208
+ const activeForUser = await ctx.db
209
+ .query("identityBindings")
210
+ .withIndex("by_consumerUserId_and_status", (q) => q.eq("consumerUserId", args.consumerUserId).eq("status", "active"))
211
+ .collect();
212
+ for (const row of activeForUser) {
213
+ await ctx.db.patch(row._id, { status: "revoked", revokedAt: nowMs });
214
+ }
215
+ return { revoked: activeForUser.length };
216
+ },
217
+ });
218
+ export const resolveAgentForUser = query({
219
+ args: {
220
+ consumerUserId: v.string(),
221
+ },
222
+ returns: v.object({
223
+ consumerUserId: v.string(),
224
+ agentKey: v.union(v.null(), v.string()),
225
+ }),
226
+ handler: async (ctx, args) => {
227
+ const active = await ctx.db
228
+ .query("identityBindings")
229
+ .withIndex("by_consumerUserId_and_status", (q) => q.eq("consumerUserId", args.consumerUserId).eq("status", "active"))
230
+ .first();
231
+ return {
232
+ consumerUserId: args.consumerUserId,
233
+ agentKey: active?.agentKey ?? null,
234
+ };
235
+ },
236
+ });
237
+ export const resolveAgentForTelegram = query({
238
+ args: {
239
+ telegramUserId: v.optional(v.string()),
240
+ telegramChatId: v.optional(v.string()),
241
+ },
242
+ returns: v.object({
243
+ consumerUserId: v.union(v.null(), v.string()),
244
+ agentKey: v.union(v.null(), v.string()),
245
+ }),
246
+ handler: async (ctx, args) => {
247
+ let active = null;
248
+ if (args.telegramUserId) {
249
+ const byUser = await ctx.db
250
+ .query("identityBindings")
251
+ .withIndex("by_telegramUserId_and_status", (q) => q.eq("telegramUserId", args.telegramUserId).eq("status", "active"))
252
+ .first();
253
+ if (byUser) {
254
+ active = {
255
+ consumerUserId: byUser.consumerUserId,
256
+ agentKey: byUser.agentKey,
257
+ };
258
+ }
259
+ }
260
+ if (!active && args.telegramChatId) {
261
+ const byChat = await ctx.db
262
+ .query("identityBindings")
263
+ .withIndex("by_telegramChatId_and_status", (q) => q.eq("telegramChatId", args.telegramChatId).eq("status", "active"))
264
+ .first();
265
+ if (byChat) {
266
+ active = {
267
+ consumerUserId: byChat.consumerUserId,
268
+ agentKey: byChat.agentKey,
269
+ };
270
+ }
271
+ }
272
+ return {
273
+ consumerUserId: active?.consumerUserId ?? null,
274
+ agentKey: active?.agentKey ?? null,
275
+ };
276
+ },
277
+ });
278
+ export const getUserAgentBinding = query({
279
+ args: {
280
+ consumerUserId: v.string(),
281
+ },
282
+ returns: v.union(v.null(), bindingViewValidator),
283
+ handler: async (ctx, args) => {
284
+ const active = await ctx.db
285
+ .query("identityBindings")
286
+ .withIndex("by_consumerUserId_and_status", (q) => q.eq("consumerUserId", args.consumerUserId).eq("status", "active"))
287
+ .first();
288
+ if (!active) {
289
+ return null;
290
+ }
291
+ return {
292
+ consumerUserId: active.consumerUserId,
293
+ agentKey: active.agentKey,
294
+ status: active.status,
295
+ source: active.source,
296
+ telegramUserId: active.telegramUserId ?? null,
297
+ telegramChatId: active.telegramChatId ?? null,
298
+ metadata: active.metadata ?? null,
299
+ boundAt: active.boundAt,
300
+ revokedAt: active.revokedAt ?? null,
301
+ };
302
+ },
303
+ });
304
+ function generatePairingCode() {
305
+ return Math.random().toString(36).slice(2, 12).toUpperCase();
306
+ }
307
+ async function upsertBinding(ctx, args) {
308
+ const nowMs = args.nowMs ?? Date.now();
309
+ const profile = await ctx.db
310
+ .query("agentProfiles")
311
+ .withIndex("by_agentKey", (q) => q.eq("agentKey", args.agentKey))
312
+ .unique();
313
+ if (!profile) {
314
+ throw new Error(`Agent profile '${args.agentKey}' not found`);
315
+ }
316
+ const activeForUser = await ctx.db
317
+ .query("identityBindings")
318
+ .withIndex("by_consumerUserId_and_status", (q) => q.eq("consumerUserId", args.consumerUserId).eq("status", "active"))
319
+ .collect();
320
+ for (const row of activeForUser) {
321
+ await ctx.db.patch(row._id, { status: "revoked", revokedAt: nowMs });
322
+ }
323
+ if (args.telegramUserId) {
324
+ const byTelegramUser = await ctx.db
325
+ .query("identityBindings")
326
+ .withIndex("by_telegramUserId_and_status", (q) => q.eq("telegramUserId", args.telegramUserId).eq("status", "active"))
327
+ .collect();
328
+ for (const row of byTelegramUser) {
329
+ if (row.consumerUserId !== args.consumerUserId) {
330
+ await ctx.db.patch(row._id, { status: "revoked", revokedAt: nowMs });
331
+ }
332
+ }
333
+ }
334
+ if (args.telegramChatId) {
335
+ const byTelegramChat = await ctx.db
336
+ .query("identityBindings")
337
+ .withIndex("by_telegramChatId_and_status", (q) => q.eq("telegramChatId", args.telegramChatId).eq("status", "active"))
338
+ .collect();
339
+ for (const row of byTelegramChat) {
340
+ if (row.consumerUserId !== args.consumerUserId) {
341
+ await ctx.db.patch(row._id, { status: "revoked", revokedAt: nowMs });
342
+ }
343
+ }
344
+ }
345
+ const bindingId = await ctx.db.insert("identityBindings", {
346
+ consumerUserId: args.consumerUserId,
347
+ agentKey: args.agentKey,
348
+ status: "active",
349
+ source: args.source ?? "api",
350
+ telegramUserId: args.telegramUserId,
351
+ telegramChatId: args.telegramChatId,
352
+ metadata: args.metadata,
353
+ boundAt: nowMs,
354
+ });
355
+ const created = await ctx.db.get(bindingId);
356
+ if (!created) {
357
+ throw new Error("Failed to create identity binding");
358
+ }
359
+ return {
360
+ consumerUserId: created.consumerUserId,
361
+ agentKey: created.agentKey,
362
+ status: created.status,
363
+ source: created.source,
364
+ telegramUserId: created.telegramUserId ?? null,
365
+ telegramChatId: created.telegramChatId ?? null,
366
+ metadata: created.metadata ?? null,
367
+ boundAt: created.boundAt,
368
+ revokedAt: created.revokedAt ?? null,
369
+ };
370
+ }
371
+ //# sourceMappingURL=identity.js.map