@agentforge-ai/cli 0.5.4 → 0.6.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.
- package/LICENSE +197 -0
- package/dist/default/agentforge.config.ts +126 -6
- package/dist/default/convex/agents.ts +15 -21
- package/dist/default/convex/chat.ts +302 -0
- package/dist/default/convex/mastraIntegration.ts +101 -69
- package/dist/default/dashboard/app/routes/chat.tsx +462 -167
- package/dist/default/skills/browser-automation/SKILL.md +137 -0
- package/dist/default/skills/browser-automation/config.json +11 -0
- package/dist/default/skills/browser-automation/index.ts +93 -0
- package/dist/default/skills/skill-creator/SKILL.md +69 -230
- package/dist/index.js +2455 -290
- package/dist/index.js.map +1 -1
- package/package.json +13 -12
- package/templates/default/agentforge.config.ts +126 -6
- package/templates/default/convex/agents.ts +15 -21
- package/templates/default/convex/chat.ts +302 -0
- package/templates/default/convex/mastraIntegration.ts +101 -69
- package/templates/default/dashboard/app/routes/chat.tsx +462 -167
- package/templates/default/skills/browser-automation/SKILL.md +137 -0
- package/templates/default/skills/browser-automation/config.json +11 -0
- package/templates/default/skills/browser-automation/index.ts +93 -0
- package/templates/default/skills/skill-creator/SKILL.md +69 -230
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat Actions for AgentForge
|
|
3
|
+
*
|
|
4
|
+
* This module provides the core chat execution pipeline:
|
|
5
|
+
* 1. User sends a message → stored via mutation
|
|
6
|
+
* 2. Convex action triggers LLM generation via Mastra Agent
|
|
7
|
+
* 3. Assistant response stored back in Convex
|
|
8
|
+
* 4. Real-time subscription updates the UI automatically
|
|
9
|
+
*
|
|
10
|
+
* Uses Mastra-native model routing via Agent.generate() with "provider/model-name" format.
|
|
11
|
+
* Mastra auto-reads provider API keys from environment variables.
|
|
12
|
+
*/
|
|
13
|
+
import { action, mutation, query } from "./_generated/server";
|
|
14
|
+
import { v } from "convex/values";
|
|
15
|
+
import { api } from "./_generated/api";
|
|
16
|
+
import { Agent } from "@mastra/core/agent";
|
|
17
|
+
|
|
18
|
+
// ============================================================
|
|
19
|
+
// Queries
|
|
20
|
+
// ============================================================
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get the current chat state for a thread: messages + thread metadata.
|
|
24
|
+
*/
|
|
25
|
+
export const getThreadMessages = query({
|
|
26
|
+
args: { threadId: v.id("threads") },
|
|
27
|
+
handler: async (ctx, args) => {
|
|
28
|
+
const messages = await ctx.db
|
|
29
|
+
.query("messages")
|
|
30
|
+
.withIndex("byThread", (q) => q.eq("threadId", args.threadId))
|
|
31
|
+
.collect();
|
|
32
|
+
return messages;
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* List all threads for a user, ordered by most recent activity.
|
|
38
|
+
*/
|
|
39
|
+
export const listThreads = query({
|
|
40
|
+
args: {
|
|
41
|
+
userId: v.optional(v.string()),
|
|
42
|
+
agentId: v.optional(v.string()),
|
|
43
|
+
},
|
|
44
|
+
handler: async (ctx, args) => {
|
|
45
|
+
let threads;
|
|
46
|
+
if (args.agentId) {
|
|
47
|
+
threads = await ctx.db
|
|
48
|
+
.query("threads")
|
|
49
|
+
.withIndex("byAgentId", (q) => q.eq("agentId", args.agentId!))
|
|
50
|
+
.collect();
|
|
51
|
+
} else if (args.userId) {
|
|
52
|
+
threads = await ctx.db
|
|
53
|
+
.query("threads")
|
|
54
|
+
.withIndex("byUserId", (q) => q.eq("userId", args.userId!))
|
|
55
|
+
.collect();
|
|
56
|
+
} else {
|
|
57
|
+
threads = await ctx.db.query("threads").collect();
|
|
58
|
+
}
|
|
59
|
+
// Sort by most recently updated
|
|
60
|
+
return threads.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// ============================================================
|
|
65
|
+
// Mutations
|
|
66
|
+
// ============================================================
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create a new chat thread for an agent.
|
|
70
|
+
*/
|
|
71
|
+
export const createThread = mutation({
|
|
72
|
+
args: {
|
|
73
|
+
agentId: v.string(),
|
|
74
|
+
name: v.optional(v.string()),
|
|
75
|
+
userId: v.optional(v.string()),
|
|
76
|
+
},
|
|
77
|
+
handler: async (ctx, args) => {
|
|
78
|
+
const now = Date.now();
|
|
79
|
+
const threadId = await ctx.db.insert("threads", {
|
|
80
|
+
name: args.name || "New Chat",
|
|
81
|
+
agentId: args.agentId,
|
|
82
|
+
userId: args.userId,
|
|
83
|
+
createdAt: now,
|
|
84
|
+
updatedAt: now,
|
|
85
|
+
});
|
|
86
|
+
return threadId;
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Store a user message in a thread (called before triggering LLM).
|
|
92
|
+
*/
|
|
93
|
+
export const addUserMessage = mutation({
|
|
94
|
+
args: {
|
|
95
|
+
threadId: v.id("threads"),
|
|
96
|
+
content: v.string(),
|
|
97
|
+
},
|
|
98
|
+
handler: async (ctx, args) => {
|
|
99
|
+
const messageId = await ctx.db.insert("messages", {
|
|
100
|
+
threadId: args.threadId,
|
|
101
|
+
role: "user",
|
|
102
|
+
content: args.content,
|
|
103
|
+
createdAt: Date.now(),
|
|
104
|
+
});
|
|
105
|
+
await ctx.db.patch(args.threadId, { updatedAt: Date.now() });
|
|
106
|
+
return messageId;
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Store an assistant message in a thread (called after LLM responds).
|
|
112
|
+
*/
|
|
113
|
+
export const addAssistantMessage = mutation({
|
|
114
|
+
args: {
|
|
115
|
+
threadId: v.id("threads"),
|
|
116
|
+
content: v.string(),
|
|
117
|
+
metadata: v.optional(v.any()),
|
|
118
|
+
},
|
|
119
|
+
handler: async (ctx, args) => {
|
|
120
|
+
const messageId = await ctx.db.insert("messages", {
|
|
121
|
+
threadId: args.threadId,
|
|
122
|
+
role: "assistant",
|
|
123
|
+
content: args.content,
|
|
124
|
+
metadata: args.metadata,
|
|
125
|
+
createdAt: Date.now(),
|
|
126
|
+
});
|
|
127
|
+
await ctx.db.patch(args.threadId, { updatedAt: Date.now() });
|
|
128
|
+
return messageId;
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// ============================================================
|
|
133
|
+
// Actions (Node.js runtime — can call external APIs)
|
|
134
|
+
// ============================================================
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Send a message and get an AI response.
|
|
138
|
+
*
|
|
139
|
+
* This is the main chat action. It:
|
|
140
|
+
* 1. Looks up the agent config from the database
|
|
141
|
+
* 2. Stores the user message
|
|
142
|
+
* 3. Builds conversation history from the thread
|
|
143
|
+
* 4. Calls the provider via Mastra Agent.generate()
|
|
144
|
+
* 5. Stores the assistant response
|
|
145
|
+
* 6. Records usage metrics
|
|
146
|
+
*
|
|
147
|
+
* The UI subscribes to `chat.getThreadMessages` which auto-updates
|
|
148
|
+
* when new messages are inserted.
|
|
149
|
+
*/
|
|
150
|
+
export const sendMessage = action({
|
|
151
|
+
args: {
|
|
152
|
+
agentId: v.string(),
|
|
153
|
+
threadId: v.id("threads"),
|
|
154
|
+
content: v.string(),
|
|
155
|
+
userId: v.optional(v.string()),
|
|
156
|
+
},
|
|
157
|
+
handler: async (ctx, args) => {
|
|
158
|
+
// 1. Get agent configuration
|
|
159
|
+
const agent = await ctx.runQuery(api.agents.get, { id: args.agentId });
|
|
160
|
+
if (!agent) {
|
|
161
|
+
throw new Error(`Agent "${args.agentId}" not found. Please create an agent first.`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// 2. Store the user message
|
|
165
|
+
await ctx.runMutation(api.chat.addUserMessage, {
|
|
166
|
+
threadId: args.threadId,
|
|
167
|
+
content: args.content,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// 3. Get conversation history for context
|
|
171
|
+
const history = await ctx.runQuery(api.chat.getThreadMessages, {
|
|
172
|
+
threadId: args.threadId,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Build messages array for the LLM (last 20 messages for context window)
|
|
176
|
+
const conversationMessages = history
|
|
177
|
+
.slice(-20)
|
|
178
|
+
.map((msg: { role: string; content: string }) => ({
|
|
179
|
+
role: msg.role as "user" | "assistant" | "system",
|
|
180
|
+
content: msg.content,
|
|
181
|
+
}));
|
|
182
|
+
|
|
183
|
+
// 4. Call the LLM via Mastra Agent
|
|
184
|
+
let responseText: string;
|
|
185
|
+
let usageData: { promptTokens: number; completionTokens: number; totalTokens: number } | null = null;
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
// Resolve the model provider and ID
|
|
189
|
+
const provider = agent.provider || "openrouter";
|
|
190
|
+
const modelId = agent.model || "openai/gpt-4o-mini";
|
|
191
|
+
const modelKey = `${provider}/${modelId}`;
|
|
192
|
+
|
|
193
|
+
// Generate via Mastra Agent
|
|
194
|
+
const mastraAgent = new Agent({
|
|
195
|
+
name: "agentforge-executor",
|
|
196
|
+
instructions: agent.instructions || "You are a helpful AI assistant built with AgentForge.",
|
|
197
|
+
model: modelKey,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const result = await mastraAgent.generate(conversationMessages);
|
|
201
|
+
|
|
202
|
+
responseText = result.text;
|
|
203
|
+
|
|
204
|
+
// Extract usage if available
|
|
205
|
+
if (result.usage) {
|
|
206
|
+
usageData = {
|
|
207
|
+
promptTokens: result.usage.promptTokens || 0,
|
|
208
|
+
completionTokens: result.usage.completionTokens || 0,
|
|
209
|
+
totalTokens: (result.usage.promptTokens || 0) + (result.usage.completionTokens || 0),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
} catch (error: unknown) {
|
|
213
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
214
|
+
console.error("[chat.sendMessage] Mastra error:", errorMessage);
|
|
215
|
+
|
|
216
|
+
// Store error as assistant message so user sees feedback
|
|
217
|
+
responseText = `I encountered an error while processing your request: ${errorMessage}`;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// 5. Store the assistant response
|
|
221
|
+
await ctx.runMutation(api.chat.addAssistantMessage, {
|
|
222
|
+
threadId: args.threadId,
|
|
223
|
+
content: responseText,
|
|
224
|
+
metadata: usageData ? { usage: usageData } : undefined,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// 6. Record usage metrics (non-blocking, best-effort)
|
|
228
|
+
if (usageData) {
|
|
229
|
+
try {
|
|
230
|
+
await ctx.runMutation(api.usage.record, {
|
|
231
|
+
agentId: args.agentId,
|
|
232
|
+
provider: agent.provider || "openrouter",
|
|
233
|
+
model: agent.model || "unknown",
|
|
234
|
+
promptTokens: usageData.promptTokens,
|
|
235
|
+
completionTokens: usageData.completionTokens,
|
|
236
|
+
totalTokens: usageData.totalTokens,
|
|
237
|
+
userId: args.userId,
|
|
238
|
+
});
|
|
239
|
+
} catch (e) {
|
|
240
|
+
console.error("[chat.sendMessage] Usage recording failed:", e);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// 7. Log the interaction
|
|
245
|
+
try {
|
|
246
|
+
await ctx.runMutation(api.logs.add, {
|
|
247
|
+
level: "info",
|
|
248
|
+
source: "chat",
|
|
249
|
+
message: `Agent "${agent.name}" responded to user message`,
|
|
250
|
+
metadata: {
|
|
251
|
+
agentId: args.agentId,
|
|
252
|
+
threadId: args.threadId,
|
|
253
|
+
usage: usageData,
|
|
254
|
+
},
|
|
255
|
+
userId: args.userId,
|
|
256
|
+
});
|
|
257
|
+
} catch (e) {
|
|
258
|
+
console.error("[chat.sendMessage] Logging failed:", e);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
success: true,
|
|
263
|
+
threadId: args.threadId,
|
|
264
|
+
response: responseText,
|
|
265
|
+
usage: usageData,
|
|
266
|
+
};
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Create a new thread and send the first message in one action.
|
|
272
|
+
* Convenience action for starting a new conversation.
|
|
273
|
+
*/
|
|
274
|
+
export const startNewChat = action({
|
|
275
|
+
args: {
|
|
276
|
+
agentId: v.string(),
|
|
277
|
+
content: v.string(),
|
|
278
|
+
threadName: v.optional(v.string()),
|
|
279
|
+
userId: v.optional(v.string()),
|
|
280
|
+
},
|
|
281
|
+
handler: async (ctx, args) => {
|
|
282
|
+
// Create a new thread
|
|
283
|
+
const threadId = await ctx.runMutation(api.chat.createThread, {
|
|
284
|
+
agentId: args.agentId,
|
|
285
|
+
name: args.threadName || "New Chat",
|
|
286
|
+
userId: args.userId,
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Send the first message
|
|
290
|
+
const result = await ctx.runAction(api.chat.sendMessage, {
|
|
291
|
+
agentId: args.agentId,
|
|
292
|
+
threadId,
|
|
293
|
+
content: args.content,
|
|
294
|
+
userId: args.userId,
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
...result,
|
|
299
|
+
threadId,
|
|
300
|
+
};
|
|
301
|
+
},
|
|
302
|
+
});
|
|
@@ -1,24 +1,38 @@
|
|
|
1
|
-
import { action } from "./_generated/server";
|
|
2
|
-
import { v } from "convex/values";
|
|
3
|
-
import { api } from "./_generated/api";
|
|
4
|
-
|
|
5
1
|
/**
|
|
6
2
|
* Mastra Integration Actions for Convex
|
|
7
|
-
*
|
|
8
|
-
* These actions run in the Node.js runtime and
|
|
9
|
-
*
|
|
3
|
+
*
|
|
4
|
+
* These actions run in the Convex Node.js runtime and execute LLM calls
|
|
5
|
+
* using Mastra-native model routing with OpenRouter as the default provider.
|
|
6
|
+
*
|
|
7
|
+
* Architecture:
|
|
8
|
+
* - For chat: use `chat.sendMessage` (preferred entry point)
|
|
9
|
+
* - For programmatic agent execution: use `mastraIntegration.executeAgent`
|
|
10
|
+
* - Model resolution: uses Mastra Agent with "provider/model-name" format
|
|
10
11
|
*/
|
|
12
|
+
import { action } from "./_generated/server";
|
|
13
|
+
import { v } from "convex/values";
|
|
14
|
+
import { api } from "./_generated/api";
|
|
15
|
+
import { Agent } from "@mastra/core/agent";
|
|
11
16
|
|
|
12
|
-
// Return type for executeAgent
|
|
17
|
+
// Return type for executeAgent
|
|
13
18
|
type ExecuteAgentResult = {
|
|
14
19
|
success: boolean;
|
|
15
20
|
threadId: string;
|
|
16
21
|
sessionId: string;
|
|
17
22
|
response: string;
|
|
18
|
-
usage?:
|
|
23
|
+
usage?: {
|
|
24
|
+
promptTokens: number;
|
|
25
|
+
completionTokens: number;
|
|
26
|
+
totalTokens: number;
|
|
27
|
+
};
|
|
19
28
|
};
|
|
20
29
|
|
|
21
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Execute an agent with a prompt and return the response.
|
|
32
|
+
*
|
|
33
|
+
* This is the programmatic API for agent execution. For chat UI,
|
|
34
|
+
* prefer `chat.sendMessage` which handles thread management automatically.
|
|
35
|
+
*/
|
|
22
36
|
export const executeAgent = action({
|
|
23
37
|
args: {
|
|
24
38
|
agentId: v.string(),
|
|
@@ -30,7 +44,7 @@ export const executeAgent = action({
|
|
|
30
44
|
handler: async (ctx, args): Promise<ExecuteAgentResult> => {
|
|
31
45
|
// Get agent configuration from database
|
|
32
46
|
const agent = await ctx.runQuery(api.agents.get, { id: args.agentId });
|
|
33
|
-
|
|
47
|
+
|
|
34
48
|
if (!agent) {
|
|
35
49
|
throw new Error(`Agent ${args.agentId} not found`);
|
|
36
50
|
}
|
|
@@ -58,50 +72,34 @@ export const executeAgent = action({
|
|
|
58
72
|
threadId,
|
|
59
73
|
agentId: args.agentId,
|
|
60
74
|
userId: args.userId,
|
|
61
|
-
channel: "
|
|
75
|
+
channel: "api",
|
|
62
76
|
});
|
|
63
77
|
|
|
64
78
|
try {
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
// Format model string for Mastra
|
|
70
|
-
const modelString = agent.model.includes("/")
|
|
71
|
-
? agent.model
|
|
72
|
-
: `${agent.provider}/${agent.model}`;
|
|
73
|
-
|
|
74
|
-
// Create Mastra agent
|
|
75
|
-
const mastraAgent = new Agent({
|
|
76
|
-
id: agent.id,
|
|
77
|
-
name: agent.name,
|
|
78
|
-
instructions: agent.instructions,
|
|
79
|
-
model: modelString,
|
|
80
|
-
tools: agent.tools || {},
|
|
81
|
-
...(agent.temperature && { temperature: agent.temperature }),
|
|
82
|
-
...(agent.maxTokens && { maxTokens: agent.maxTokens }),
|
|
83
|
-
...(agent.topP && { topP: agent.topP }),
|
|
84
|
-
});
|
|
79
|
+
// Resolve the model
|
|
80
|
+
const provider = agent.provider || "openrouter";
|
|
81
|
+
const modelId = agent.model || "openai/gpt-4o-mini";
|
|
82
|
+
const modelKey = `${provider}/${modelId}`;
|
|
85
83
|
|
|
86
84
|
// Get conversation history for context
|
|
87
|
-
const messages = await ctx.runQuery(api.messages.list, { threadId })
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// Execute
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
85
|
+
const messages = await ctx.runQuery(api.messages.list, { threadId });
|
|
86
|
+
const conversationMessages = (messages as Array<{ role: string; content: string }>)
|
|
87
|
+
.slice(-20)
|
|
88
|
+
.map((m) => ({
|
|
89
|
+
role: m.role as "user" | "assistant" | "system",
|
|
90
|
+
content: m.content,
|
|
91
|
+
}));
|
|
92
|
+
|
|
93
|
+
// Execute via Mastra Agent
|
|
94
|
+
const mastraAgent = new Agent({
|
|
95
|
+
name: "agentforge-executor",
|
|
96
|
+
instructions: agent.instructions || "You are a helpful AI assistant.",
|
|
97
|
+
model: modelKey,
|
|
99
98
|
});
|
|
100
99
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
: result.text || result.content || JSON.stringify(result);
|
|
100
|
+
const result = await mastraAgent.generate(conversationMessages);
|
|
101
|
+
|
|
102
|
+
const responseContent = result.text;
|
|
105
103
|
|
|
106
104
|
// Add assistant message to thread
|
|
107
105
|
await ctx.runMutation(api.messages.add, {
|
|
@@ -116,17 +114,27 @@ export const executeAgent = action({
|
|
|
116
114
|
status: "completed",
|
|
117
115
|
});
|
|
118
116
|
|
|
119
|
-
//
|
|
120
|
-
|
|
117
|
+
// Build usage data
|
|
118
|
+
const usage = result.usage
|
|
119
|
+
? {
|
|
120
|
+
promptTokens: result.usage.promptTokens || 0,
|
|
121
|
+
completionTokens: result.usage.completionTokens || 0,
|
|
122
|
+
totalTokens:
|
|
123
|
+
(result.usage.promptTokens || 0) +
|
|
124
|
+
(result.usage.completionTokens || 0),
|
|
125
|
+
}
|
|
126
|
+
: undefined;
|
|
127
|
+
|
|
128
|
+
// Record usage
|
|
129
|
+
if (usage) {
|
|
121
130
|
await ctx.runMutation(api.usage.record, {
|
|
122
131
|
agentId: args.agentId,
|
|
123
132
|
sessionId,
|
|
124
|
-
provider: agent.provider,
|
|
125
|
-
model: agent.model,
|
|
126
|
-
promptTokens:
|
|
127
|
-
completionTokens:
|
|
128
|
-
totalTokens:
|
|
129
|
-
cost: result.usage.cost,
|
|
133
|
+
provider: agent.provider || "openrouter",
|
|
134
|
+
model: agent.model || "unknown",
|
|
135
|
+
promptTokens: usage.promptTokens,
|
|
136
|
+
completionTokens: usage.completionTokens,
|
|
137
|
+
totalTokens: usage.totalTokens,
|
|
130
138
|
userId: args.userId,
|
|
131
139
|
});
|
|
132
140
|
}
|
|
@@ -136,10 +144,11 @@ export const executeAgent = action({
|
|
|
136
144
|
threadId: threadId as string,
|
|
137
145
|
sessionId,
|
|
138
146
|
response: responseContent,
|
|
139
|
-
usage
|
|
147
|
+
usage,
|
|
140
148
|
};
|
|
141
149
|
} catch (error: unknown) {
|
|
142
|
-
const errorMessage =
|
|
150
|
+
const errorMessage =
|
|
151
|
+
error instanceof Error ? error.message : String(error);
|
|
143
152
|
|
|
144
153
|
// Update session status to error
|
|
145
154
|
await ctx.runMutation(api.sessions.updateStatus, {
|
|
@@ -147,19 +156,37 @@ export const executeAgent = action({
|
|
|
147
156
|
status: "error",
|
|
148
157
|
});
|
|
149
158
|
|
|
150
|
-
// Add error message
|
|
159
|
+
// Add error message to thread
|
|
151
160
|
await ctx.runMutation(api.messages.add, {
|
|
152
161
|
threadId,
|
|
153
162
|
role: "assistant",
|
|
154
163
|
content: `Error: ${errorMessage}`,
|
|
155
164
|
});
|
|
156
165
|
|
|
166
|
+
// Log the error
|
|
167
|
+
await ctx.runMutation(api.logs.add, {
|
|
168
|
+
level: "error",
|
|
169
|
+
source: "mastraIntegration",
|
|
170
|
+
message: `Agent execution failed: ${errorMessage}`,
|
|
171
|
+
metadata: {
|
|
172
|
+
agentId: args.agentId,
|
|
173
|
+
threadId,
|
|
174
|
+
sessionId,
|
|
175
|
+
},
|
|
176
|
+
userId: args.userId,
|
|
177
|
+
});
|
|
178
|
+
|
|
157
179
|
throw error;
|
|
158
180
|
}
|
|
159
181
|
},
|
|
160
182
|
});
|
|
161
183
|
|
|
162
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Stream agent response (placeholder — streaming requires SSE/WebSocket).
|
|
186
|
+
*
|
|
187
|
+
* For now, this falls back to non-streaming execution.
|
|
188
|
+
* Full streaming support will be added via Convex HTTP actions + SSE.
|
|
189
|
+
*/
|
|
163
190
|
export const streamAgent = action({
|
|
164
191
|
args: {
|
|
165
192
|
agentId: v.string(),
|
|
@@ -168,26 +195,31 @@ export const streamAgent = action({
|
|
|
168
195
|
userId: v.optional(v.string()),
|
|
169
196
|
},
|
|
170
197
|
handler: async (ctx, args): Promise<{ success: boolean; message: string }> => {
|
|
171
|
-
//
|
|
172
|
-
|
|
173
|
-
|
|
198
|
+
// Fall back to non-streaming execution
|
|
199
|
+
const result = await ctx.runAction(api.mastraIntegration.executeAgent, {
|
|
200
|
+
agentId: args.agentId,
|
|
201
|
+
prompt: args.prompt,
|
|
202
|
+
threadId: args.threadId,
|
|
203
|
+
userId: args.userId,
|
|
204
|
+
});
|
|
205
|
+
|
|
174
206
|
return {
|
|
175
|
-
success:
|
|
176
|
-
message:
|
|
207
|
+
success: result.success,
|
|
208
|
+
message: result.response,
|
|
177
209
|
};
|
|
178
210
|
},
|
|
179
211
|
});
|
|
180
212
|
|
|
181
|
-
|
|
213
|
+
/**
|
|
214
|
+
* Execute workflow with multiple agents (placeholder).
|
|
215
|
+
*/
|
|
182
216
|
export const executeWorkflow = action({
|
|
183
217
|
args: {
|
|
184
218
|
workflowId: v.string(),
|
|
185
219
|
input: v.any(),
|
|
186
220
|
userId: v.optional(v.string()),
|
|
187
221
|
},
|
|
188
|
-
handler: async (
|
|
189
|
-
// Placeholder for workflow execution
|
|
190
|
-
// This would orchestrate multiple agents in sequence or parallel
|
|
222
|
+
handler: async (_ctx, _args): Promise<{ success: boolean; message: string }> => {
|
|
191
223
|
return {
|
|
192
224
|
success: true,
|
|
193
225
|
message: "Workflow execution coming soon",
|