@agentforge-ai/cli 0.4.3 → 0.5.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/default/convex/agents.ts +204 -0
- package/dist/default/convex/apiKeys.ts +133 -0
- package/dist/default/convex/cronJobs.ts +224 -0
- package/dist/default/convex/files.ts +103 -0
- package/dist/default/convex/folders.ts +110 -0
- package/dist/default/convex/heartbeat.ts +371 -0
- package/dist/default/convex/logs.ts +66 -0
- package/dist/default/convex/mastraIntegration.ts +185 -0
- package/dist/default/convex/mcpConnections.ts +127 -0
- package/dist/default/convex/messages.ts +90 -0
- package/dist/default/convex/projects.ts +114 -0
- package/dist/default/convex/schema.ts +150 -83
- package/dist/default/convex/sessions.ts +174 -0
- package/dist/default/convex/settings.ts +79 -0
- package/dist/default/convex/skills.ts +178 -0
- package/dist/default/convex/threads.ts +100 -0
- package/dist/default/convex/usage.ts +195 -0
- package/dist/default/convex/vault.ts +397 -0
- package/dist/default/dashboard/app/main.tsx +7 -3
- package/dist/default/dashboard/app/routes/agents.tsx +103 -161
- package/dist/default/dashboard/app/routes/chat.tsx +163 -317
- package/dist/default/dashboard/app/routes/connections.tsx +247 -386
- package/dist/default/dashboard/app/routes/cron.tsx +127 -286
- package/dist/default/dashboard/app/routes/files.tsx +184 -167
- package/dist/default/dashboard/app/routes/index.tsx +63 -96
- package/dist/default/dashboard/app/routes/projects.tsx +106 -225
- package/dist/default/dashboard/app/routes/sessions.tsx +87 -253
- package/dist/default/dashboard/app/routes/settings.tsx +316 -532
- package/dist/default/dashboard/app/routes/skills.tsx +329 -216
- package/dist/default/dashboard/app/routes/usage.tsx +107 -150
- package/dist/default/dashboard/tsconfig.json +3 -2
- package/dist/default/dashboard/vite.config.ts +6 -0
- package/dist/index.js +256 -49
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/default/convex/agents.ts +204 -0
- package/templates/default/convex/apiKeys.ts +133 -0
- package/templates/default/convex/cronJobs.ts +224 -0
- package/templates/default/convex/files.ts +103 -0
- package/templates/default/convex/folders.ts +110 -0
- package/templates/default/convex/heartbeat.ts +371 -0
- package/templates/default/convex/logs.ts +66 -0
- package/templates/default/convex/mastraIntegration.ts +185 -0
- package/templates/default/convex/mcpConnections.ts +127 -0
- package/templates/default/convex/messages.ts +90 -0
- package/templates/default/convex/projects.ts +114 -0
- package/templates/default/convex/schema.ts +150 -83
- package/templates/default/convex/sessions.ts +174 -0
- package/templates/default/convex/settings.ts +79 -0
- package/templates/default/convex/skills.ts +178 -0
- package/templates/default/convex/threads.ts +100 -0
- package/templates/default/convex/usage.ts +195 -0
- package/templates/default/convex/vault.ts +397 -0
- package/templates/default/dashboard/app/main.tsx +7 -3
- package/templates/default/dashboard/app/routes/agents.tsx +103 -161
- package/templates/default/dashboard/app/routes/chat.tsx +163 -317
- package/templates/default/dashboard/app/routes/connections.tsx +247 -386
- package/templates/default/dashboard/app/routes/cron.tsx +127 -286
- package/templates/default/dashboard/app/routes/files.tsx +184 -167
- package/templates/default/dashboard/app/routes/index.tsx +63 -96
- package/templates/default/dashboard/app/routes/projects.tsx +106 -225
- package/templates/default/dashboard/app/routes/sessions.tsx +87 -253
- package/templates/default/dashboard/app/routes/settings.tsx +316 -532
- package/templates/default/dashboard/app/routes/skills.tsx +329 -216
- package/templates/default/dashboard/app/routes/usage.tsx +107 -150
- package/templates/default/dashboard/tsconfig.json +3 -2
- package/templates/default/dashboard/vite.config.ts +6 -0
|
@@ -1,24 +1,15 @@
|
|
|
1
1
|
import { defineSchema, defineTable } from "convex/server";
|
|
2
2
|
import { v } from "convex/values";
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* AgentForge Database Schema
|
|
6
|
-
*
|
|
7
|
-
* This schema defines all the tables needed for your AgentForge project.
|
|
8
|
-
* Customize it to fit your needs — add new tables, fields, or indexes.
|
|
9
|
-
*
|
|
10
|
-
* IMPORTANT: Index names cannot be "by_id" or "by_creation_time" (reserved by Convex).
|
|
11
|
-
* Use camelCase names like "byAgentId", "byUserId", etc.
|
|
12
|
-
*/
|
|
13
4
|
export default defineSchema({
|
|
14
|
-
//
|
|
5
|
+
// Core agent definitions
|
|
15
6
|
agents: defineTable({
|
|
16
7
|
id: v.string(),
|
|
17
8
|
name: v.string(),
|
|
18
9
|
description: v.optional(v.string()),
|
|
19
10
|
instructions: v.string(),
|
|
20
11
|
model: v.string(),
|
|
21
|
-
provider: v.string(),
|
|
12
|
+
provider: v.string(), // "openai", "openrouter", "anthropic", etc.
|
|
22
13
|
tools: v.optional(v.any()),
|
|
23
14
|
temperature: v.optional(v.number()),
|
|
24
15
|
maxTokens: v.optional(v.number()),
|
|
@@ -32,22 +23,21 @@ export default defineSchema({
|
|
|
32
23
|
.index("byUserId", ["userId"])
|
|
33
24
|
.index("byIsActive", ["isActive"]),
|
|
34
25
|
|
|
35
|
-
//
|
|
26
|
+
// Conversation threads
|
|
36
27
|
threads: defineTable({
|
|
37
28
|
name: v.optional(v.string()),
|
|
38
29
|
agentId: v.string(),
|
|
39
30
|
userId: v.optional(v.string()),
|
|
40
|
-
projectId: v.optional(v.
|
|
41
|
-
status: v.string(),
|
|
31
|
+
projectId: v.optional(v.id("projects")),
|
|
42
32
|
metadata: v.optional(v.any()),
|
|
43
33
|
createdAt: v.number(),
|
|
44
34
|
updatedAt: v.number(),
|
|
45
35
|
})
|
|
46
36
|
.index("byAgentId", ["agentId"])
|
|
47
37
|
.index("byUserId", ["userId"])
|
|
48
|
-
.index("
|
|
38
|
+
.index("byProjectId", ["projectId"]),
|
|
49
39
|
|
|
50
|
-
//
|
|
40
|
+
// Messages in threads
|
|
51
41
|
messages: defineTable({
|
|
52
42
|
threadId: v.id("threads"),
|
|
53
43
|
role: v.union(
|
|
@@ -57,113 +47,143 @@ export default defineSchema({
|
|
|
57
47
|
v.literal("tool")
|
|
58
48
|
),
|
|
59
49
|
content: v.string(),
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
timestamp: v.number(),
|
|
66
|
-
})
|
|
67
|
-
.index("byThreadId", ["threadId"])
|
|
68
|
-
.index("byTimestamp", ["timestamp"]),
|
|
50
|
+
tool_calls: v.optional(v.any()),
|
|
51
|
+
tool_results: v.optional(v.any()),
|
|
52
|
+
metadata: v.optional(v.any()),
|
|
53
|
+
createdAt: v.number(),
|
|
54
|
+
}).index("byThread", ["threadId"]),
|
|
69
55
|
|
|
70
|
-
//
|
|
56
|
+
// Active sessions
|
|
71
57
|
sessions: defineTable({
|
|
72
|
-
|
|
58
|
+
sessionId: v.string(),
|
|
59
|
+
threadId: v.id("threads"),
|
|
73
60
|
agentId: v.string(),
|
|
74
|
-
threadId: v.optional(v.id("threads")),
|
|
75
|
-
status: v.string(),
|
|
76
61
|
userId: v.optional(v.string()),
|
|
62
|
+
status: v.union(
|
|
63
|
+
v.literal("active"),
|
|
64
|
+
v.literal("paused"),
|
|
65
|
+
v.literal("completed"),
|
|
66
|
+
v.literal("error")
|
|
67
|
+
),
|
|
68
|
+
channel: v.optional(v.string()), // "dashboard", "api", "webhook", etc.
|
|
69
|
+
metadata: v.optional(v.any()),
|
|
77
70
|
startedAt: v.number(),
|
|
78
71
|
lastActivityAt: v.number(),
|
|
79
|
-
|
|
72
|
+
completedAt: v.optional(v.number()),
|
|
80
73
|
})
|
|
74
|
+
.index("bySessionId", ["sessionId"])
|
|
75
|
+
.index("byThreadId", ["threadId"])
|
|
81
76
|
.index("byAgentId", ["agentId"])
|
|
82
|
-
.index("
|
|
83
|
-
.index("
|
|
77
|
+
.index("byStatus", ["status"])
|
|
78
|
+
.index("byUserId", ["userId"]),
|
|
84
79
|
|
|
85
|
-
//
|
|
80
|
+
// File storage metadata (files stored in Cloudflare R2)
|
|
86
81
|
files: defineTable({
|
|
87
82
|
name: v.string(),
|
|
88
|
-
|
|
83
|
+
originalName: v.string(),
|
|
89
84
|
mimeType: v.string(),
|
|
90
85
|
size: v.number(),
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
url: v.string(), // Cloudflare R2 URL
|
|
87
|
+
folderId: v.optional(v.id("folders")),
|
|
88
|
+
projectId: v.optional(v.id("projects")),
|
|
93
89
|
userId: v.optional(v.string()),
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
uploadedAt: v.number(),
|
|
91
|
+
metadata: v.optional(v.any()),
|
|
96
92
|
})
|
|
97
93
|
.index("byFolderId", ["folderId"])
|
|
98
|
-
.index("
|
|
99
|
-
.index("
|
|
94
|
+
.index("byProjectId", ["projectId"])
|
|
95
|
+
.index("byUserId", ["userId"]),
|
|
100
96
|
|
|
101
|
-
//
|
|
97
|
+
// Folder organization
|
|
102
98
|
folders: defineTable({
|
|
103
99
|
name: v.string(),
|
|
104
|
-
parentId: v.optional(v.
|
|
100
|
+
parentId: v.optional(v.id("folders")),
|
|
101
|
+
projectId: v.optional(v.id("projects")),
|
|
105
102
|
userId: v.optional(v.string()),
|
|
106
|
-
projectId: v.optional(v.string()),
|
|
107
103
|
createdAt: v.number(),
|
|
104
|
+
updatedAt: v.number(),
|
|
108
105
|
})
|
|
109
106
|
.index("byParentId", ["parentId"])
|
|
107
|
+
.index("byProjectId", ["projectId"])
|
|
110
108
|
.index("byUserId", ["userId"]),
|
|
111
109
|
|
|
112
|
-
//
|
|
110
|
+
// Projects/Workspaces
|
|
113
111
|
projects: defineTable({
|
|
114
112
|
name: v.string(),
|
|
115
113
|
description: v.optional(v.string()),
|
|
116
|
-
status: v.string(),
|
|
117
114
|
userId: v.optional(v.string()),
|
|
118
115
|
settings: v.optional(v.any()),
|
|
119
116
|
createdAt: v.number(),
|
|
120
117
|
updatedAt: v.number(),
|
|
121
|
-
})
|
|
122
|
-
.index("byUserId", ["userId"])
|
|
123
|
-
.index("byStatus", ["status"]),
|
|
118
|
+
}).index("byUserId", ["userId"]),
|
|
124
119
|
|
|
125
|
-
//
|
|
120
|
+
// Skills/Tools marketplace
|
|
126
121
|
skills: defineTable({
|
|
127
122
|
name: v.string(),
|
|
128
|
-
|
|
123
|
+
displayName: v.string(),
|
|
124
|
+
description: v.string(),
|
|
129
125
|
category: v.string(),
|
|
130
126
|
version: v.string(),
|
|
127
|
+
author: v.optional(v.string()),
|
|
128
|
+
repository: v.optional(v.string()),
|
|
129
|
+
documentation: v.optional(v.string()),
|
|
130
|
+
code: v.string(), // The actual skill code
|
|
131
|
+
schema: v.optional(v.any()), // JSON schema for skill parameters
|
|
131
132
|
isInstalled: v.boolean(),
|
|
132
|
-
|
|
133
|
-
agentId: v.optional(v.string()),
|
|
133
|
+
isEnabled: v.boolean(),
|
|
134
134
|
userId: v.optional(v.string()),
|
|
135
|
+
installedAt: v.optional(v.number()),
|
|
135
136
|
createdAt: v.number(),
|
|
136
137
|
updatedAt: v.number(),
|
|
137
138
|
})
|
|
138
|
-
.index("
|
|
139
|
-
.index("
|
|
140
|
-
.index("
|
|
139
|
+
.index("byUserId", ["userId"])
|
|
140
|
+
.index("byIsInstalled", ["isInstalled"])
|
|
141
|
+
.index("byCategory", ["category"]),
|
|
141
142
|
|
|
142
|
-
//
|
|
143
|
+
// Cron jobs/scheduled tasks
|
|
143
144
|
cronJobs: defineTable({
|
|
144
145
|
name: v.string(),
|
|
145
|
-
|
|
146
|
+
description: v.optional(v.string()),
|
|
147
|
+
schedule: v.string(), // Cron expression
|
|
146
148
|
agentId: v.string(),
|
|
147
|
-
|
|
149
|
+
prompt: v.string(), // What to execute
|
|
148
150
|
isEnabled: v.boolean(),
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
lastRun: v.optional(v.number()),
|
|
152
|
+
nextRun: v.optional(v.number()),
|
|
151
153
|
userId: v.optional(v.string()),
|
|
154
|
+
metadata: v.optional(v.any()),
|
|
152
155
|
createdAt: v.number(),
|
|
153
156
|
updatedAt: v.number(),
|
|
154
157
|
})
|
|
155
158
|
.index("byAgentId", ["agentId"])
|
|
159
|
+
.index("byUserId", ["userId"])
|
|
156
160
|
.index("byIsEnabled", ["isEnabled"])
|
|
157
|
-
.index("
|
|
161
|
+
.index("byNextRun", ["nextRun"]),
|
|
162
|
+
|
|
163
|
+
// Cron job execution history
|
|
164
|
+
cronJobRuns: defineTable({
|
|
165
|
+
cronJobId: v.id("cronJobs"),
|
|
166
|
+
status: v.union(
|
|
167
|
+
v.literal("success"),
|
|
168
|
+
v.literal("failed"),
|
|
169
|
+
v.literal("running")
|
|
170
|
+
),
|
|
171
|
+
startedAt: v.number(),
|
|
172
|
+
completedAt: v.optional(v.number()),
|
|
173
|
+
output: v.optional(v.string()),
|
|
174
|
+
error: v.optional(v.string()),
|
|
175
|
+
})
|
|
176
|
+
.index("byCronJobId", ["cronJobId"])
|
|
177
|
+
.index("byStatus", ["status"]),
|
|
158
178
|
|
|
159
|
-
//
|
|
179
|
+
// MCP (Model Context Protocol) connections
|
|
160
180
|
mcpConnections: defineTable({
|
|
161
181
|
name: v.string(),
|
|
162
|
-
|
|
163
|
-
|
|
182
|
+
serverUrl: v.string(),
|
|
183
|
+
protocol: v.string(), // "mcp", "custom"
|
|
164
184
|
isConnected: v.boolean(),
|
|
165
185
|
isEnabled: v.boolean(),
|
|
166
|
-
credentials: v.optional(v.any()),
|
|
186
|
+
credentials: v.optional(v.any()), // Encrypted
|
|
167
187
|
capabilities: v.optional(v.any()),
|
|
168
188
|
userId: v.optional(v.string()),
|
|
169
189
|
lastConnectedAt: v.optional(v.number()),
|
|
@@ -173,9 +193,9 @@ export default defineSchema({
|
|
|
173
193
|
.index("byUserId", ["userId"])
|
|
174
194
|
.index("byIsEnabled", ["isEnabled"]),
|
|
175
195
|
|
|
176
|
-
//
|
|
196
|
+
// API keys and credentials (encrypted)
|
|
177
197
|
apiKeys: defineTable({
|
|
178
|
-
provider: v.string(),
|
|
198
|
+
provider: v.string(), // "openai", "openrouter", "anthropic", etc.
|
|
179
199
|
keyName: v.string(),
|
|
180
200
|
encryptedKey: v.string(),
|
|
181
201
|
isActive: v.boolean(),
|
|
@@ -187,7 +207,7 @@ export default defineSchema({
|
|
|
187
207
|
.index("byUserId", ["userId"])
|
|
188
208
|
.index("byIsActive", ["isActive"]),
|
|
189
209
|
|
|
190
|
-
//
|
|
210
|
+
// Usage tracking for metrics
|
|
191
211
|
usage: defineTable({
|
|
192
212
|
agentId: v.string(),
|
|
193
213
|
sessionId: v.optional(v.string()),
|
|
@@ -196,7 +216,7 @@ export default defineSchema({
|
|
|
196
216
|
promptTokens: v.number(),
|
|
197
217
|
completionTokens: v.number(),
|
|
198
218
|
totalTokens: v.number(),
|
|
199
|
-
cost: v.optional(v.number()),
|
|
219
|
+
cost: v.optional(v.number()), // Estimated cost in USD
|
|
200
220
|
userId: v.optional(v.string()),
|
|
201
221
|
timestamp: v.number(),
|
|
202
222
|
})
|
|
@@ -205,7 +225,7 @@ export default defineSchema({
|
|
|
205
225
|
.index("byTimestamp", ["timestamp"])
|
|
206
226
|
.index("byProvider", ["provider"]),
|
|
207
227
|
|
|
208
|
-
//
|
|
228
|
+
// User settings and configuration
|
|
209
229
|
settings: defineTable({
|
|
210
230
|
userId: v.string(),
|
|
211
231
|
key: v.string(),
|
|
@@ -215,7 +235,7 @@ export default defineSchema({
|
|
|
215
235
|
.index("byUserId", ["userId"])
|
|
216
236
|
.index("byUserIdAndKey", ["userId", "key"]),
|
|
217
237
|
|
|
218
|
-
//
|
|
238
|
+
// System logs for debugging
|
|
219
239
|
logs: defineTable({
|
|
220
240
|
level: v.union(
|
|
221
241
|
v.literal("debug"),
|
|
@@ -223,7 +243,7 @@ export default defineSchema({
|
|
|
223
243
|
v.literal("warn"),
|
|
224
244
|
v.literal("error")
|
|
225
245
|
),
|
|
226
|
-
source: v.string(),
|
|
246
|
+
source: v.string(), // "agent", "system", "api", etc.
|
|
227
247
|
message: v.string(),
|
|
228
248
|
metadata: v.optional(v.any()),
|
|
229
249
|
userId: v.optional(v.string()),
|
|
@@ -231,16 +251,31 @@ export default defineSchema({
|
|
|
231
251
|
})
|
|
232
252
|
.index("byLevel", ["level"])
|
|
233
253
|
.index("bySource", ["source"])
|
|
234
|
-
.index("byTimestamp", ["timestamp"])
|
|
254
|
+
.index("byTimestamp", ["timestamp"])
|
|
255
|
+
.index("byUserId", ["userId"]),
|
|
256
|
+
|
|
257
|
+
// Channels for multi-platform support
|
|
258
|
+
channels: defineTable({
|
|
259
|
+
name: v.string(),
|
|
260
|
+
type: v.string(), // "dashboard", "api", "webhook", "whatsapp", etc.
|
|
261
|
+
isEnabled: v.boolean(),
|
|
262
|
+
configuration: v.optional(v.any()),
|
|
263
|
+
userId: v.optional(v.string()),
|
|
264
|
+
createdAt: v.number(),
|
|
265
|
+
updatedAt: v.number(),
|
|
266
|
+
})
|
|
267
|
+
.index("byType", ["type"])
|
|
268
|
+
.index("byUserId", ["userId"])
|
|
269
|
+
.index("byIsEnabled", ["isEnabled"]),
|
|
235
270
|
|
|
236
|
-
//
|
|
271
|
+
// Heartbeat system for ongoing task tracking
|
|
237
272
|
heartbeats: defineTable({
|
|
238
273
|
agentId: v.string(),
|
|
239
274
|
threadId: v.optional(v.id("threads")),
|
|
240
|
-
status: v.string(),
|
|
275
|
+
status: v.string(), // "active", "waiting", "completed", "error"
|
|
241
276
|
currentTask: v.optional(v.string()),
|
|
242
277
|
pendingTasks: v.array(v.string()),
|
|
243
|
-
context: v.string(),
|
|
278
|
+
context: v.string(), // Markdown-formatted context
|
|
244
279
|
lastCheck: v.number(),
|
|
245
280
|
nextCheck: v.number(),
|
|
246
281
|
metadata: v.optional(v.any()),
|
|
@@ -249,14 +284,14 @@ export default defineSchema({
|
|
|
249
284
|
.index("byStatus", ["status"])
|
|
250
285
|
.index("byNextCheck", ["nextCheck"]),
|
|
251
286
|
|
|
252
|
-
//
|
|
287
|
+
// Secure Vault for encrypted secrets storage
|
|
253
288
|
vault: defineTable({
|
|
254
|
-
name: v.string(),
|
|
255
|
-
category: v.string(),
|
|
256
|
-
provider: v.optional(v.string()),
|
|
257
|
-
encryptedValue: v.string(),
|
|
258
|
-
iv: v.string(),
|
|
259
|
-
maskedValue: v.string(),
|
|
289
|
+
name: v.string(), // Display name (e.g., "OpenAI API Key")
|
|
290
|
+
category: v.string(), // "api_key", "token", "secret", "credential"
|
|
291
|
+
provider: v.optional(v.string()), // Associated provider
|
|
292
|
+
encryptedValue: v.string(), // AES-256-GCM encrypted value
|
|
293
|
+
iv: v.string(), // Initialization vector for decryption
|
|
294
|
+
maskedValue: v.string(), // e.g., "sk-...abc123"
|
|
260
295
|
isActive: v.boolean(),
|
|
261
296
|
expiresAt: v.optional(v.number()),
|
|
262
297
|
lastAccessedAt: v.optional(v.number()),
|
|
@@ -269,4 +304,36 @@ export default defineSchema({
|
|
|
269
304
|
.index("byCategory", ["category"])
|
|
270
305
|
.index("byProvider", ["provider"])
|
|
271
306
|
.index("byIsActive", ["isActive"]),
|
|
307
|
+
|
|
308
|
+
// Audit log for vault access
|
|
309
|
+
vaultAuditLog: defineTable({
|
|
310
|
+
vaultEntryId: v.id("vault"),
|
|
311
|
+
action: v.string(), // "created", "accessed", "updated", "deleted", "auto_captured"
|
|
312
|
+
source: v.string(), // "dashboard", "chat", "api", "agent"
|
|
313
|
+
userId: v.optional(v.string()),
|
|
314
|
+
ipAddress: v.optional(v.string()),
|
|
315
|
+
timestamp: v.number(),
|
|
316
|
+
})
|
|
317
|
+
.index("byVaultEntryId", ["vaultEntryId"])
|
|
318
|
+
.index("byUserId", ["userId"])
|
|
319
|
+
.index("byTimestamp", ["timestamp"]),
|
|
320
|
+
|
|
321
|
+
// Agent instances for multi-agent workflows
|
|
322
|
+
instances: defineTable({
|
|
323
|
+
agentId: v.string(),
|
|
324
|
+
instanceId: v.string(),
|
|
325
|
+
status: v.union(
|
|
326
|
+
v.literal("running"),
|
|
327
|
+
v.literal("stopped"),
|
|
328
|
+
v.literal("error")
|
|
329
|
+
),
|
|
330
|
+
configuration: v.optional(v.any()),
|
|
331
|
+
userId: v.optional(v.string()),
|
|
332
|
+
startedAt: v.number(),
|
|
333
|
+
stoppedAt: v.optional(v.number()),
|
|
334
|
+
})
|
|
335
|
+
.index("byAgentId", ["agentId"])
|
|
336
|
+
.index("byInstanceId", ["instanceId"])
|
|
337
|
+
.index("byStatus", ["status"])
|
|
338
|
+
.index("byUserId", ["userId"]),
|
|
272
339
|
});
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { v } from "convex/values";
|
|
2
|
+
import { mutation, query } from "./_generated/server";
|
|
3
|
+
|
|
4
|
+
// Query: Get all sessions
|
|
5
|
+
export const list = query({
|
|
6
|
+
args: {
|
|
7
|
+
userId: v.optional(v.string()),
|
|
8
|
+
agentId: v.optional(v.string()),
|
|
9
|
+
status: v.optional(v.string()),
|
|
10
|
+
},
|
|
11
|
+
handler: async (ctx, args) => {
|
|
12
|
+
if (args.status) {
|
|
13
|
+
const sessions = await ctx.db
|
|
14
|
+
.query("sessions")
|
|
15
|
+
.withIndex("byStatus", (q) => q.eq("status", args.status! as any))
|
|
16
|
+
.collect();
|
|
17
|
+
|
|
18
|
+
if (args.userId) {
|
|
19
|
+
return sessions.filter((s) => s.userId === args.userId);
|
|
20
|
+
}
|
|
21
|
+
if (args.agentId) {
|
|
22
|
+
return sessions.filter((s) => s.agentId === args.agentId);
|
|
23
|
+
}
|
|
24
|
+
return sessions;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (args.agentId) {
|
|
28
|
+
return await ctx.db
|
|
29
|
+
.query("sessions")
|
|
30
|
+
.withIndex("byAgentId", (q) => q.eq("agentId", args.agentId!))
|
|
31
|
+
.collect();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (args.userId) {
|
|
35
|
+
return await ctx.db
|
|
36
|
+
.query("sessions")
|
|
37
|
+
.withIndex("byUserId", (q) => q.eq("userId", args.userId!))
|
|
38
|
+
.collect();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return await ctx.db.query("sessions").collect();
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Query: Get session by ID
|
|
46
|
+
export const get = query({
|
|
47
|
+
args: { sessionId: v.string() },
|
|
48
|
+
handler: async (ctx, args) => {
|
|
49
|
+
return await ctx.db
|
|
50
|
+
.query("sessions")
|
|
51
|
+
.withIndex("bySessionId", (q) => q.eq("sessionId", args.sessionId!))
|
|
52
|
+
.first();
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Query: Get active sessions
|
|
57
|
+
export const listActive = query({
|
|
58
|
+
args: {
|
|
59
|
+
userId: v.optional(v.string()),
|
|
60
|
+
},
|
|
61
|
+
handler: async (ctx, args) => {
|
|
62
|
+
const sessions = await ctx.db
|
|
63
|
+
.query("sessions")
|
|
64
|
+
.withIndex("byStatus", (q) => q.eq("status", "active"))
|
|
65
|
+
.collect();
|
|
66
|
+
|
|
67
|
+
if (args.userId) {
|
|
68
|
+
return sessions.filter((s) => s.userId === args.userId);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return sessions;
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Mutation: Create a new session
|
|
76
|
+
export const create = mutation({
|
|
77
|
+
args: {
|
|
78
|
+
sessionId: v.string(),
|
|
79
|
+
threadId: v.id("threads"),
|
|
80
|
+
agentId: v.string(),
|
|
81
|
+
userId: v.optional(v.string()),
|
|
82
|
+
channel: v.optional(v.string()),
|
|
83
|
+
metadata: v.optional(v.any()),
|
|
84
|
+
},
|
|
85
|
+
handler: async (ctx, args) => {
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
const sessionId = await ctx.db.insert("sessions", {
|
|
88
|
+
...args,
|
|
89
|
+
status: "active",
|
|
90
|
+
startedAt: now,
|
|
91
|
+
lastActivityAt: now,
|
|
92
|
+
});
|
|
93
|
+
return sessionId;
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Mutation: Update session activity
|
|
98
|
+
export const updateActivity = mutation({
|
|
99
|
+
args: {
|
|
100
|
+
sessionId: v.string(),
|
|
101
|
+
metadata: v.optional(v.any()),
|
|
102
|
+
},
|
|
103
|
+
handler: async (ctx, args) => {
|
|
104
|
+
const session = await ctx.db
|
|
105
|
+
.query("sessions")
|
|
106
|
+
.withIndex("bySessionId", (q) => q.eq("sessionId", args.sessionId!))
|
|
107
|
+
.first();
|
|
108
|
+
|
|
109
|
+
if (!session) {
|
|
110
|
+
throw new Error(`Session ${args.sessionId} not found`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
await ctx.db.patch(session._id, {
|
|
114
|
+
lastActivityAt: Date.now(),
|
|
115
|
+
...(args.metadata && { metadata: args.metadata }),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return session._id;
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Mutation: Update session status
|
|
123
|
+
export const updateStatus = mutation({
|
|
124
|
+
args: {
|
|
125
|
+
sessionId: v.string(),
|
|
126
|
+
status: v.union(
|
|
127
|
+
v.literal("active"),
|
|
128
|
+
v.literal("paused"),
|
|
129
|
+
v.literal("completed"),
|
|
130
|
+
v.literal("error")
|
|
131
|
+
),
|
|
132
|
+
},
|
|
133
|
+
handler: async (ctx, args) => {
|
|
134
|
+
const session = await ctx.db
|
|
135
|
+
.query("sessions")
|
|
136
|
+
.withIndex("bySessionId", (q) => q.eq("sessionId", args.sessionId!))
|
|
137
|
+
.first();
|
|
138
|
+
|
|
139
|
+
if (!session) {
|
|
140
|
+
throw new Error(`Session ${args.sessionId} not found`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const updates: any = {
|
|
144
|
+
status: args.status,
|
|
145
|
+
lastActivityAt: Date.now(),
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
if (args.status === "completed" || args.status === "error") {
|
|
149
|
+
updates.completedAt = Date.now();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
await ctx.db.patch(session._id, updates);
|
|
153
|
+
|
|
154
|
+
return session._id;
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Mutation: Delete session
|
|
159
|
+
export const remove = mutation({
|
|
160
|
+
args: { sessionId: v.string() },
|
|
161
|
+
handler: async (ctx, args) => {
|
|
162
|
+
const session = await ctx.db
|
|
163
|
+
.query("sessions")
|
|
164
|
+
.withIndex("bySessionId", (q) => q.eq("sessionId", args.sessionId!))
|
|
165
|
+
.first();
|
|
166
|
+
|
|
167
|
+
if (!session) {
|
|
168
|
+
throw new Error(`Session ${args.sessionId} not found`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
await ctx.db.delete(session._id);
|
|
172
|
+
return { success: true };
|
|
173
|
+
},
|
|
174
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { v } from "convex/values";
|
|
2
|
+
import { mutation, query } from "./_generated/server";
|
|
3
|
+
|
|
4
|
+
// Query: Get a setting by key
|
|
5
|
+
export const get = query({
|
|
6
|
+
args: { userId: v.string(), key: v.string() },
|
|
7
|
+
handler: async (ctx, args) => {
|
|
8
|
+
const setting = await ctx.db
|
|
9
|
+
.query("settings")
|
|
10
|
+
.withIndex("byUserIdAndKey", (q) =>
|
|
11
|
+
q.eq("userId", args.userId!).eq("key", args.key!)
|
|
12
|
+
)
|
|
13
|
+
.first();
|
|
14
|
+
return setting;
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Query: List all settings for a user
|
|
19
|
+
export const list = query({
|
|
20
|
+
args: { userId: v.optional(v.string()) },
|
|
21
|
+
handler: async (ctx, args) => {
|
|
22
|
+
if (args.userId) {
|
|
23
|
+
return await ctx.db
|
|
24
|
+
.query("settings")
|
|
25
|
+
.withIndex("byUserId", (q) => q.eq("userId", args.userId!))
|
|
26
|
+
.collect();
|
|
27
|
+
}
|
|
28
|
+
return await ctx.db.query("settings").collect();
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Mutation: Set a setting (upsert)
|
|
33
|
+
export const set = mutation({
|
|
34
|
+
args: {
|
|
35
|
+
userId: v.string(),
|
|
36
|
+
key: v.string(),
|
|
37
|
+
value: v.any(),
|
|
38
|
+
},
|
|
39
|
+
handler: async (ctx, args) => {
|
|
40
|
+
const existing = await ctx.db
|
|
41
|
+
.query("settings")
|
|
42
|
+
.withIndex("byUserIdAndKey", (q) =>
|
|
43
|
+
q.eq("userId", args.userId!).eq("key", args.key!)
|
|
44
|
+
)
|
|
45
|
+
.first();
|
|
46
|
+
|
|
47
|
+
if (existing) {
|
|
48
|
+
await ctx.db.patch(existing._id, {
|
|
49
|
+
value: args.value,
|
|
50
|
+
updatedAt: Date.now(),
|
|
51
|
+
});
|
|
52
|
+
return existing._id;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return await ctx.db.insert("settings", {
|
|
56
|
+
userId: args.userId,
|
|
57
|
+
key: args.key,
|
|
58
|
+
value: args.value,
|
|
59
|
+
updatedAt: Date.now(),
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Mutation: Delete a setting
|
|
65
|
+
export const remove = mutation({
|
|
66
|
+
args: { userId: v.string(), key: v.string() },
|
|
67
|
+
handler: async (ctx, args) => {
|
|
68
|
+
const existing = await ctx.db
|
|
69
|
+
.query("settings")
|
|
70
|
+
.withIndex("byUserIdAndKey", (q) =>
|
|
71
|
+
q.eq("userId", args.userId!).eq("key", args.key!)
|
|
72
|
+
)
|
|
73
|
+
.first();
|
|
74
|
+
|
|
75
|
+
if (existing) {
|
|
76
|
+
await ctx.db.delete(existing._id);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
});
|