@agentforge-ai/cli 0.5.5 → 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.
@@ -3,17 +3,17 @@
3
3
  *
4
4
  * This module provides the core chat execution pipeline:
5
5
  * 1. User sends a message → stored via mutation
6
- * 2. Convex action triggers LLM generation via OpenRouter (AI SDK)
6
+ * 2. Convex action triggers LLM generation via Mastra Agent
7
7
  * 3. Assistant response stored back in Convex
8
8
  * 4. Real-time subscription updates the UI automatically
9
9
  *
10
- * Uses the Vercel AI SDK with OpenRouter as an OpenAI-compatible provider.
11
- * No dynamic imports of @mastra/core we use the AI SDK directly in Convex
12
- * Node.js actions for maximum reliability.
10
+ * Uses Mastra-native model routing via Agent.generate() with "provider/model-name" format.
11
+ * Mastra auto-reads provider API keys from environment variables.
13
12
  */
14
13
  import { action, mutation, query } from "./_generated/server";
15
14
  import { v } from "convex/values";
16
15
  import { api } from "./_generated/api";
16
+ import { Agent } from "@mastra/core/agent";
17
17
 
18
18
  // ============================================================
19
19
  // Queries
@@ -140,7 +140,7 @@ export const addAssistantMessage = mutation({
140
140
  * 1. Looks up the agent config from the database
141
141
  * 2. Stores the user message
142
142
  * 3. Builds conversation history from the thread
143
- * 4. Calls OpenRouter (or other provider) via the AI SDK
143
+ * 4. Calls the provider via Mastra Agent.generate()
144
144
  * 5. Stores the assistant response
145
145
  * 6. Records usage metrics
146
146
  *
@@ -180,54 +180,25 @@ export const sendMessage = action({
180
180
  content: msg.content,
181
181
  }));
182
182
 
183
- // 4. Call the LLM via AI SDK
183
+ // 4. Call the LLM via Mastra Agent
184
184
  let responseText: string;
185
185
  let usageData: { promptTokens: number; completionTokens: number; totalTokens: number } | null = null;
186
186
 
187
187
  try {
188
- // Dynamically import the AI SDK (available in Convex Node.js actions)
189
- const { generateText } = await import("ai");
190
- const { createOpenAI } = await import("@ai-sdk/openai");
191
-
192
188
  // Resolve the model provider and ID
193
189
  const provider = agent.provider || "openrouter";
194
190
  const modelId = agent.model || "openai/gpt-4o-mini";
191
+ const modelKey = `${provider}/${modelId}`;
195
192
 
196
- // Create the appropriate provider instance
197
- let model;
198
- if (provider === "openrouter") {
199
- const openrouter = createOpenAI({
200
- baseURL: "https://openrouter.ai/api/v1",
201
- apiKey: process.env.OPENROUTER_API_KEY,
202
- });
203
- model = openrouter(modelId);
204
- } else if (provider === "openai") {
205
- const openai = createOpenAI({
206
- apiKey: process.env.OPENAI_API_KEY,
207
- });
208
- model = openai(modelId);
209
- } else {
210
- // Default to OpenRouter for any provider — it routes to all models
211
- const openrouter = createOpenAI({
212
- baseURL: "https://openrouter.ai/api/v1",
213
- apiKey: process.env.OPENROUTER_API_KEY,
214
- });
215
- // Use provider/model format for OpenRouter routing
216
- const routerModelId = modelId.includes("/")
217
- ? modelId
218
- : `${provider}/${modelId}`;
219
- model = openrouter(routerModelId);
220
- }
221
-
222
- // Generate the response
223
- const result = await generateText({
224
- model,
225
- system: agent.instructions || "You are a helpful AI assistant built with AgentForge.",
226
- messages: conversationMessages,
227
- ...(agent.temperature != null && { temperature: agent.temperature }),
228
- ...(agent.maxTokens != null && { maxTokens: agent.maxTokens }),
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,
229
198
  });
230
199
 
200
+ const result = await mastraAgent.generate(conversationMessages);
201
+
231
202
  responseText = result.text;
232
203
 
233
204
  // Extract usage if available
@@ -240,7 +211,7 @@ export const sendMessage = action({
240
211
  }
241
212
  } catch (error: unknown) {
242
213
  const errorMessage = error instanceof Error ? error.message : String(error);
243
- console.error("[chat.sendMessage] LLM error:", errorMessage);
214
+ console.error("[chat.sendMessage] Mastra error:", errorMessage);
244
215
 
245
216
  // Store error as assistant message so user sees feedback
246
217
  responseText = `I encountered an error while processing your request: ${errorMessage}`;
@@ -2,20 +2,17 @@
2
2
  * Mastra Integration Actions for Convex
3
3
  *
4
4
  * These actions run in the Convex Node.js runtime and execute LLM calls
5
- * using the Vercel AI SDK with OpenRouter as the default provider.
5
+ * using Mastra-native model routing with OpenRouter as the default provider.
6
6
  *
7
7
  * Architecture:
8
8
  * - For chat: use `chat.sendMessage` (preferred entry point)
9
9
  * - For programmatic agent execution: use `mastraIntegration.executeAgent`
10
- * - Model resolution: uses AI SDK providers directly (OpenRouter, OpenAI, etc.)
11
- *
12
- * This replaces the previous broken approach of dynamically importing
13
- * @mastra/core inside Convex actions. The AI SDK is the correct way to
14
- * call LLMs from Convex Node.js actions.
10
+ * - Model resolution: uses Mastra Agent with "provider/model-name" format
15
11
  */
16
12
  import { action } from "./_generated/server";
17
13
  import { v } from "convex/values";
18
14
  import { api } from "./_generated/api";
15
+ import { Agent } from "@mastra/core/agent";
19
16
 
20
17
  // Return type for executeAgent
21
18
  type ExecuteAgentResult = {
@@ -30,54 +27,6 @@ type ExecuteAgentResult = {
30
27
  };
31
28
  };
32
29
 
33
- /**
34
- * Resolve a model instance from provider + modelId using the AI SDK.
35
- *
36
- * Supports: openrouter, openai, anthropic, google, venice, custom.
37
- * Falls back to OpenRouter for unknown providers (it routes to all models).
38
- */
39
- async function resolveModel(provider: string, modelId: string) {
40
- const { createOpenAI } = await import("@ai-sdk/openai");
41
-
42
- switch (provider) {
43
- case "openai": {
44
- const openai = createOpenAI({
45
- apiKey: process.env.OPENAI_API_KEY,
46
- });
47
- return openai(modelId);
48
- }
49
-
50
- case "anthropic": {
51
- const { createAnthropic } = await import("@ai-sdk/anthropic");
52
- const anthropic = createAnthropic({
53
- apiKey: process.env.ANTHROPIC_API_KEY,
54
- });
55
- return anthropic(modelId);
56
- }
57
-
58
- case "google": {
59
- const { createGoogleGenerativeAI } = await import("@ai-sdk/google");
60
- const google = createGoogleGenerativeAI({
61
- apiKey: process.env.GEMINI_API_KEY,
62
- });
63
- return google(modelId);
64
- }
65
-
66
- case "openrouter":
67
- default: {
68
- // OpenRouter is OpenAI-compatible and routes to all providers
69
- const openrouter = createOpenAI({
70
- baseURL: "https://openrouter.ai/api/v1",
71
- apiKey: process.env.OPENROUTER_API_KEY,
72
- });
73
- const routerModelId = modelId.includes("/")
74
- ? modelId
75
- : `${provider}/${modelId}`;
76
- return openrouter(routerModelId);
77
- }
78
- }
79
- }
80
-
81
30
  /**
82
31
  * Execute an agent with a prompt and return the response.
83
32
  *
@@ -127,12 +76,10 @@ export const executeAgent = action({
127
76
  });
128
77
 
129
78
  try {
130
- const { generateText } = await import("ai");
131
-
132
79
  // Resolve the model
133
80
  const provider = agent.provider || "openrouter";
134
81
  const modelId = agent.model || "openai/gpt-4o-mini";
135
- const model = await resolveModel(provider, modelId);
82
+ const modelKey = `${provider}/${modelId}`;
136
83
 
137
84
  // Get conversation history for context
138
85
  const messages = await ctx.runQuery(api.messages.list, { threadId });
@@ -143,15 +90,15 @@ export const executeAgent = action({
143
90
  content: m.content,
144
91
  }));
145
92
 
146
- // Execute the LLM call
147
- const result = await generateText({
148
- model,
149
- system: agent.instructions || "You are a helpful AI assistant.",
150
- messages: conversationMessages,
151
- ...(agent.temperature != null && { temperature: agent.temperature }),
152
- ...(agent.maxTokens != null && { maxTokens: agent.maxTokens }),
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,
153
98
  });
154
99
 
100
+ const result = await mastraAgent.generate(conversationMessages);
101
+
155
102
  const responseContent = result.text;
156
103
 
157
104
  // Add assistant message to thread
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge-ai/cli",
3
- "version": "0.5.5",
3
+ "version": "0.6.0",
4
4
  "description": "CLI tool for creating, running, and managing AgentForge projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -3,17 +3,17 @@
3
3
  *
4
4
  * This module provides the core chat execution pipeline:
5
5
  * 1. User sends a message → stored via mutation
6
- * 2. Convex action triggers LLM generation via OpenRouter (AI SDK)
6
+ * 2. Convex action triggers LLM generation via Mastra Agent
7
7
  * 3. Assistant response stored back in Convex
8
8
  * 4. Real-time subscription updates the UI automatically
9
9
  *
10
- * Uses the Vercel AI SDK with OpenRouter as an OpenAI-compatible provider.
11
- * No dynamic imports of @mastra/core we use the AI SDK directly in Convex
12
- * Node.js actions for maximum reliability.
10
+ * Uses Mastra-native model routing via Agent.generate() with "provider/model-name" format.
11
+ * Mastra auto-reads provider API keys from environment variables.
13
12
  */
14
13
  import { action, mutation, query } from "./_generated/server";
15
14
  import { v } from "convex/values";
16
15
  import { api } from "./_generated/api";
16
+ import { Agent } from "@mastra/core/agent";
17
17
 
18
18
  // ============================================================
19
19
  // Queries
@@ -140,7 +140,7 @@ export const addAssistantMessage = mutation({
140
140
  * 1. Looks up the agent config from the database
141
141
  * 2. Stores the user message
142
142
  * 3. Builds conversation history from the thread
143
- * 4. Calls OpenRouter (or other provider) via the AI SDK
143
+ * 4. Calls the provider via Mastra Agent.generate()
144
144
  * 5. Stores the assistant response
145
145
  * 6. Records usage metrics
146
146
  *
@@ -180,54 +180,25 @@ export const sendMessage = action({
180
180
  content: msg.content,
181
181
  }));
182
182
 
183
- // 4. Call the LLM via AI SDK
183
+ // 4. Call the LLM via Mastra Agent
184
184
  let responseText: string;
185
185
  let usageData: { promptTokens: number; completionTokens: number; totalTokens: number } | null = null;
186
186
 
187
187
  try {
188
- // Dynamically import the AI SDK (available in Convex Node.js actions)
189
- const { generateText } = await import("ai");
190
- const { createOpenAI } = await import("@ai-sdk/openai");
191
-
192
188
  // Resolve the model provider and ID
193
189
  const provider = agent.provider || "openrouter";
194
190
  const modelId = agent.model || "openai/gpt-4o-mini";
191
+ const modelKey = `${provider}/${modelId}`;
195
192
 
196
- // Create the appropriate provider instance
197
- let model;
198
- if (provider === "openrouter") {
199
- const openrouter = createOpenAI({
200
- baseURL: "https://openrouter.ai/api/v1",
201
- apiKey: process.env.OPENROUTER_API_KEY,
202
- });
203
- model = openrouter(modelId);
204
- } else if (provider === "openai") {
205
- const openai = createOpenAI({
206
- apiKey: process.env.OPENAI_API_KEY,
207
- });
208
- model = openai(modelId);
209
- } else {
210
- // Default to OpenRouter for any provider — it routes to all models
211
- const openrouter = createOpenAI({
212
- baseURL: "https://openrouter.ai/api/v1",
213
- apiKey: process.env.OPENROUTER_API_KEY,
214
- });
215
- // Use provider/model format for OpenRouter routing
216
- const routerModelId = modelId.includes("/")
217
- ? modelId
218
- : `${provider}/${modelId}`;
219
- model = openrouter(routerModelId);
220
- }
221
-
222
- // Generate the response
223
- const result = await generateText({
224
- model,
225
- system: agent.instructions || "You are a helpful AI assistant built with AgentForge.",
226
- messages: conversationMessages,
227
- ...(agent.temperature != null && { temperature: agent.temperature }),
228
- ...(agent.maxTokens != null && { maxTokens: agent.maxTokens }),
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,
229
198
  });
230
199
 
200
+ const result = await mastraAgent.generate(conversationMessages);
201
+
231
202
  responseText = result.text;
232
203
 
233
204
  // Extract usage if available
@@ -240,7 +211,7 @@ export const sendMessage = action({
240
211
  }
241
212
  } catch (error: unknown) {
242
213
  const errorMessage = error instanceof Error ? error.message : String(error);
243
- console.error("[chat.sendMessage] LLM error:", errorMessage);
214
+ console.error("[chat.sendMessage] Mastra error:", errorMessage);
244
215
 
245
216
  // Store error as assistant message so user sees feedback
246
217
  responseText = `I encountered an error while processing your request: ${errorMessage}`;
@@ -2,20 +2,17 @@
2
2
  * Mastra Integration Actions for Convex
3
3
  *
4
4
  * These actions run in the Convex Node.js runtime and execute LLM calls
5
- * using the Vercel AI SDK with OpenRouter as the default provider.
5
+ * using Mastra-native model routing with OpenRouter as the default provider.
6
6
  *
7
7
  * Architecture:
8
8
  * - For chat: use `chat.sendMessage` (preferred entry point)
9
9
  * - For programmatic agent execution: use `mastraIntegration.executeAgent`
10
- * - Model resolution: uses AI SDK providers directly (OpenRouter, OpenAI, etc.)
11
- *
12
- * This replaces the previous broken approach of dynamically importing
13
- * @mastra/core inside Convex actions. The AI SDK is the correct way to
14
- * call LLMs from Convex Node.js actions.
10
+ * - Model resolution: uses Mastra Agent with "provider/model-name" format
15
11
  */
16
12
  import { action } from "./_generated/server";
17
13
  import { v } from "convex/values";
18
14
  import { api } from "./_generated/api";
15
+ import { Agent } from "@mastra/core/agent";
19
16
 
20
17
  // Return type for executeAgent
21
18
  type ExecuteAgentResult = {
@@ -30,54 +27,6 @@ type ExecuteAgentResult = {
30
27
  };
31
28
  };
32
29
 
33
- /**
34
- * Resolve a model instance from provider + modelId using the AI SDK.
35
- *
36
- * Supports: openrouter, openai, anthropic, google, venice, custom.
37
- * Falls back to OpenRouter for unknown providers (it routes to all models).
38
- */
39
- async function resolveModel(provider: string, modelId: string) {
40
- const { createOpenAI } = await import("@ai-sdk/openai");
41
-
42
- switch (provider) {
43
- case "openai": {
44
- const openai = createOpenAI({
45
- apiKey: process.env.OPENAI_API_KEY,
46
- });
47
- return openai(modelId);
48
- }
49
-
50
- case "anthropic": {
51
- const { createAnthropic } = await import("@ai-sdk/anthropic");
52
- const anthropic = createAnthropic({
53
- apiKey: process.env.ANTHROPIC_API_KEY,
54
- });
55
- return anthropic(modelId);
56
- }
57
-
58
- case "google": {
59
- const { createGoogleGenerativeAI } = await import("@ai-sdk/google");
60
- const google = createGoogleGenerativeAI({
61
- apiKey: process.env.GEMINI_API_KEY,
62
- });
63
- return google(modelId);
64
- }
65
-
66
- case "openrouter":
67
- default: {
68
- // OpenRouter is OpenAI-compatible and routes to all providers
69
- const openrouter = createOpenAI({
70
- baseURL: "https://openrouter.ai/api/v1",
71
- apiKey: process.env.OPENROUTER_API_KEY,
72
- });
73
- const routerModelId = modelId.includes("/")
74
- ? modelId
75
- : `${provider}/${modelId}`;
76
- return openrouter(routerModelId);
77
- }
78
- }
79
- }
80
-
81
30
  /**
82
31
  * Execute an agent with a prompt and return the response.
83
32
  *
@@ -127,12 +76,10 @@ export const executeAgent = action({
127
76
  });
128
77
 
129
78
  try {
130
- const { generateText } = await import("ai");
131
-
132
79
  // Resolve the model
133
80
  const provider = agent.provider || "openrouter";
134
81
  const modelId = agent.model || "openai/gpt-4o-mini";
135
- const model = await resolveModel(provider, modelId);
82
+ const modelKey = `${provider}/${modelId}`;
136
83
 
137
84
  // Get conversation history for context
138
85
  const messages = await ctx.runQuery(api.messages.list, { threadId });
@@ -143,15 +90,15 @@ export const executeAgent = action({
143
90
  content: m.content,
144
91
  }));
145
92
 
146
- // Execute the LLM call
147
- const result = await generateText({
148
- model,
149
- system: agent.instructions || "You are a helpful AI assistant.",
150
- messages: conversationMessages,
151
- ...(agent.temperature != null && { temperature: agent.temperature }),
152
- ...(agent.maxTokens != null && { maxTokens: agent.maxTokens }),
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,
153
98
  });
154
99
 
100
+ const result = await mastraAgent.generate(conversationMessages);
101
+
155
102
  const responseContent = result.text;
156
103
 
157
104
  // Add assistant message to thread