@agentforge-ai/cli 0.3.2 → 0.4.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/dist/default/.env.example +35 -6
- package/dist/default/README.md +89 -9
- package/dist/default/convex/schema.ts +248 -4
- package/dist/default/package.json +5 -3
- package/dist/default/skills/skill-creator/SKILL.md +270 -0
- package/dist/default/skills/skill-creator/config.json +11 -0
- package/dist/default/skills/skill-creator/index.ts +392 -0
- package/dist/default/src/agent.ts +45 -5
- package/dist/index.js +1452 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/templates/default/.env.example +35 -6
- package/templates/default/README.md +89 -9
- package/templates/default/convex/schema.ts +248 -4
- package/templates/default/package.json +5 -3
- package/templates/default/skills/skill-creator/SKILL.md +270 -0
- package/templates/default/skills/skill-creator/config.json +11 -0
- package/templates/default/skills/skill-creator/index.ts +392 -0
- package/templates/default/src/agent.ts +45 -5
|
@@ -1,19 +1,53 @@
|
|
|
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
|
+
*/
|
|
4
13
|
export default defineSchema({
|
|
14
|
+
// ─── Agent Definitions ───────────────────────────────────────────────
|
|
5
15
|
agents: defineTable({
|
|
6
16
|
id: v.string(),
|
|
7
17
|
name: v.string(),
|
|
18
|
+
description: v.optional(v.string()),
|
|
8
19
|
instructions: v.string(),
|
|
9
20
|
model: v.string(),
|
|
21
|
+
provider: v.string(),
|
|
10
22
|
tools: v.optional(v.any()),
|
|
11
|
-
|
|
23
|
+
temperature: v.optional(v.number()),
|
|
24
|
+
maxTokens: v.optional(v.number()),
|
|
25
|
+
topP: v.optional(v.number()),
|
|
26
|
+
isActive: v.boolean(),
|
|
27
|
+
createdAt: v.number(),
|
|
28
|
+
updatedAt: v.number(),
|
|
29
|
+
userId: v.optional(v.string()),
|
|
30
|
+
})
|
|
31
|
+
.index("byAgentId", ["id"])
|
|
32
|
+
.index("byUserId", ["userId"])
|
|
33
|
+
.index("byIsActive", ["isActive"]),
|
|
12
34
|
|
|
35
|
+
// ─── Conversation Threads ────────────────────────────────────────────
|
|
13
36
|
threads: defineTable({
|
|
14
37
|
name: v.optional(v.string()),
|
|
15
|
-
|
|
38
|
+
agentId: v.string(),
|
|
39
|
+
userId: v.optional(v.string()),
|
|
40
|
+
projectId: v.optional(v.string()),
|
|
41
|
+
status: v.string(),
|
|
42
|
+
metadata: v.optional(v.any()),
|
|
43
|
+
createdAt: v.number(),
|
|
44
|
+
updatedAt: v.number(),
|
|
45
|
+
})
|
|
46
|
+
.index("byAgentId", ["agentId"])
|
|
47
|
+
.index("byUserId", ["userId"])
|
|
48
|
+
.index("byStatus", ["status"]),
|
|
16
49
|
|
|
50
|
+
// ─── Messages ────────────────────────────────────────────────────────
|
|
17
51
|
messages: defineTable({
|
|
18
52
|
threadId: v.id("threads"),
|
|
19
53
|
role: v.union(
|
|
@@ -23,6 +57,216 @@ export default defineSchema({
|
|
|
23
57
|
v.literal("tool")
|
|
24
58
|
),
|
|
25
59
|
content: v.string(),
|
|
26
|
-
|
|
27
|
-
|
|
60
|
+
toolCalls: v.optional(v.any()),
|
|
61
|
+
toolResults: v.optional(v.any()),
|
|
62
|
+
tokenUsage: v.optional(v.any()),
|
|
63
|
+
model: v.optional(v.string()),
|
|
64
|
+
provider: v.optional(v.string()),
|
|
65
|
+
timestamp: v.number(),
|
|
66
|
+
})
|
|
67
|
+
.index("byThreadId", ["threadId"])
|
|
68
|
+
.index("byTimestamp", ["timestamp"]),
|
|
69
|
+
|
|
70
|
+
// ─── Sessions ────────────────────────────────────────────────────────
|
|
71
|
+
sessions: defineTable({
|
|
72
|
+
name: v.string(),
|
|
73
|
+
agentId: v.string(),
|
|
74
|
+
threadId: v.optional(v.id("threads")),
|
|
75
|
+
status: v.string(),
|
|
76
|
+
userId: v.optional(v.string()),
|
|
77
|
+
startedAt: v.number(),
|
|
78
|
+
lastActivityAt: v.number(),
|
|
79
|
+
metadata: v.optional(v.any()),
|
|
80
|
+
})
|
|
81
|
+
.index("byAgentId", ["agentId"])
|
|
82
|
+
.index("byUserId", ["userId"])
|
|
83
|
+
.index("byStatus", ["status"]),
|
|
84
|
+
|
|
85
|
+
// ─── Files ───────────────────────────────────────────────────────────
|
|
86
|
+
files: defineTable({
|
|
87
|
+
name: v.string(),
|
|
88
|
+
folderId: v.optional(v.string()),
|
|
89
|
+
mimeType: v.string(),
|
|
90
|
+
size: v.number(),
|
|
91
|
+
storageId: v.optional(v.string()),
|
|
92
|
+
url: v.optional(v.string()),
|
|
93
|
+
userId: v.optional(v.string()),
|
|
94
|
+
projectId: v.optional(v.string()),
|
|
95
|
+
createdAt: v.number(),
|
|
96
|
+
})
|
|
97
|
+
.index("byFolderId", ["folderId"])
|
|
98
|
+
.index("byUserId", ["userId"])
|
|
99
|
+
.index("byProjectId", ["projectId"]),
|
|
100
|
+
|
|
101
|
+
// ─── Folders ─────────────────────────────────────────────────────────
|
|
102
|
+
folders: defineTable({
|
|
103
|
+
name: v.string(),
|
|
104
|
+
parentId: v.optional(v.string()),
|
|
105
|
+
userId: v.optional(v.string()),
|
|
106
|
+
projectId: v.optional(v.string()),
|
|
107
|
+
createdAt: v.number(),
|
|
108
|
+
})
|
|
109
|
+
.index("byParentId", ["parentId"])
|
|
110
|
+
.index("byUserId", ["userId"]),
|
|
111
|
+
|
|
112
|
+
// ─── Projects / Workspaces ───────────────────────────────────────────
|
|
113
|
+
projects: defineTable({
|
|
114
|
+
name: v.string(),
|
|
115
|
+
description: v.optional(v.string()),
|
|
116
|
+
status: v.string(),
|
|
117
|
+
userId: v.optional(v.string()),
|
|
118
|
+
settings: v.optional(v.any()),
|
|
119
|
+
createdAt: v.number(),
|
|
120
|
+
updatedAt: v.number(),
|
|
121
|
+
})
|
|
122
|
+
.index("byUserId", ["userId"])
|
|
123
|
+
.index("byStatus", ["status"]),
|
|
124
|
+
|
|
125
|
+
// ─── Skills ──────────────────────────────────────────────────────────
|
|
126
|
+
skills: defineTable({
|
|
127
|
+
name: v.string(),
|
|
128
|
+
description: v.optional(v.string()),
|
|
129
|
+
category: v.string(),
|
|
130
|
+
version: v.string(),
|
|
131
|
+
isInstalled: v.boolean(),
|
|
132
|
+
configuration: v.optional(v.any()),
|
|
133
|
+
agentId: v.optional(v.string()),
|
|
134
|
+
userId: v.optional(v.string()),
|
|
135
|
+
createdAt: v.number(),
|
|
136
|
+
updatedAt: v.number(),
|
|
137
|
+
})
|
|
138
|
+
.index("byAgentId", ["agentId"])
|
|
139
|
+
.index("byCategory", ["category"])
|
|
140
|
+
.index("byIsInstalled", ["isInstalled"]),
|
|
141
|
+
|
|
142
|
+
// ─── Cron Jobs ───────────────────────────────────────────────────────
|
|
143
|
+
cronJobs: defineTable({
|
|
144
|
+
name: v.string(),
|
|
145
|
+
schedule: v.string(),
|
|
146
|
+
agentId: v.string(),
|
|
147
|
+
action: v.string(),
|
|
148
|
+
isEnabled: v.boolean(),
|
|
149
|
+
lastRunAt: v.optional(v.number()),
|
|
150
|
+
nextRunAt: v.optional(v.number()),
|
|
151
|
+
userId: v.optional(v.string()),
|
|
152
|
+
createdAt: v.number(),
|
|
153
|
+
updatedAt: v.number(),
|
|
154
|
+
})
|
|
155
|
+
.index("byAgentId", ["agentId"])
|
|
156
|
+
.index("byIsEnabled", ["isEnabled"])
|
|
157
|
+
.index("byUserId", ["userId"]),
|
|
158
|
+
|
|
159
|
+
// ─── MCP Connections ─────────────────────────────────────────────────
|
|
160
|
+
mcpConnections: defineTable({
|
|
161
|
+
name: v.string(),
|
|
162
|
+
type: v.string(),
|
|
163
|
+
endpoint: v.string(),
|
|
164
|
+
isConnected: v.boolean(),
|
|
165
|
+
isEnabled: v.boolean(),
|
|
166
|
+
credentials: v.optional(v.any()),
|
|
167
|
+
capabilities: v.optional(v.any()),
|
|
168
|
+
userId: v.optional(v.string()),
|
|
169
|
+
lastConnectedAt: v.optional(v.number()),
|
|
170
|
+
createdAt: v.number(),
|
|
171
|
+
updatedAt: v.number(),
|
|
172
|
+
})
|
|
173
|
+
.index("byUserId", ["userId"])
|
|
174
|
+
.index("byIsEnabled", ["isEnabled"]),
|
|
175
|
+
|
|
176
|
+
// ─── API Keys ────────────────────────────────────────────────────────
|
|
177
|
+
apiKeys: defineTable({
|
|
178
|
+
provider: v.string(),
|
|
179
|
+
keyName: v.string(),
|
|
180
|
+
encryptedKey: v.string(),
|
|
181
|
+
isActive: v.boolean(),
|
|
182
|
+
userId: v.optional(v.string()),
|
|
183
|
+
createdAt: v.number(),
|
|
184
|
+
lastUsedAt: v.optional(v.number()),
|
|
185
|
+
})
|
|
186
|
+
.index("byProvider", ["provider"])
|
|
187
|
+
.index("byUserId", ["userId"])
|
|
188
|
+
.index("byIsActive", ["isActive"]),
|
|
189
|
+
|
|
190
|
+
// ─── Usage Tracking ──────────────────────────────────────────────────
|
|
191
|
+
usage: defineTable({
|
|
192
|
+
agentId: v.string(),
|
|
193
|
+
sessionId: v.optional(v.string()),
|
|
194
|
+
provider: v.string(),
|
|
195
|
+
model: v.string(),
|
|
196
|
+
promptTokens: v.number(),
|
|
197
|
+
completionTokens: v.number(),
|
|
198
|
+
totalTokens: v.number(),
|
|
199
|
+
cost: v.optional(v.number()),
|
|
200
|
+
userId: v.optional(v.string()),
|
|
201
|
+
timestamp: v.number(),
|
|
202
|
+
})
|
|
203
|
+
.index("byAgentId", ["agentId"])
|
|
204
|
+
.index("byUserId", ["userId"])
|
|
205
|
+
.index("byTimestamp", ["timestamp"])
|
|
206
|
+
.index("byProvider", ["provider"]),
|
|
207
|
+
|
|
208
|
+
// ─── Settings ────────────────────────────────────────────────────────
|
|
209
|
+
settings: defineTable({
|
|
210
|
+
userId: v.string(),
|
|
211
|
+
key: v.string(),
|
|
212
|
+
value: v.any(),
|
|
213
|
+
updatedAt: v.number(),
|
|
214
|
+
})
|
|
215
|
+
.index("byUserId", ["userId"])
|
|
216
|
+
.index("byUserIdAndKey", ["userId", "key"]),
|
|
217
|
+
|
|
218
|
+
// ─── System Logs ─────────────────────────────────────────────────────
|
|
219
|
+
logs: defineTable({
|
|
220
|
+
level: v.union(
|
|
221
|
+
v.literal("debug"),
|
|
222
|
+
v.literal("info"),
|
|
223
|
+
v.literal("warn"),
|
|
224
|
+
v.literal("error")
|
|
225
|
+
),
|
|
226
|
+
source: v.string(),
|
|
227
|
+
message: v.string(),
|
|
228
|
+
metadata: v.optional(v.any()),
|
|
229
|
+
userId: v.optional(v.string()),
|
|
230
|
+
timestamp: v.number(),
|
|
231
|
+
})
|
|
232
|
+
.index("byLevel", ["level"])
|
|
233
|
+
.index("bySource", ["source"])
|
|
234
|
+
.index("byTimestamp", ["timestamp"]),
|
|
235
|
+
|
|
236
|
+
// ─── Heartbeat (Task Continuation) ───────────────────────────────────
|
|
237
|
+
heartbeats: defineTable({
|
|
238
|
+
agentId: v.string(),
|
|
239
|
+
threadId: v.optional(v.id("threads")),
|
|
240
|
+
status: v.string(),
|
|
241
|
+
currentTask: v.optional(v.string()),
|
|
242
|
+
pendingTasks: v.array(v.string()),
|
|
243
|
+
context: v.string(),
|
|
244
|
+
lastCheck: v.number(),
|
|
245
|
+
nextCheck: v.number(),
|
|
246
|
+
metadata: v.optional(v.any()),
|
|
247
|
+
})
|
|
248
|
+
.index("byAgentId", ["agentId"])
|
|
249
|
+
.index("byStatus", ["status"])
|
|
250
|
+
.index("byNextCheck", ["nextCheck"]),
|
|
251
|
+
|
|
252
|
+
// ─── Secure Vault ────────────────────────────────────────────────────
|
|
253
|
+
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(),
|
|
260
|
+
isActive: v.boolean(),
|
|
261
|
+
expiresAt: v.optional(v.number()),
|
|
262
|
+
lastAccessedAt: v.optional(v.number()),
|
|
263
|
+
accessCount: v.number(),
|
|
264
|
+
userId: v.optional(v.string()),
|
|
265
|
+
createdAt: v.number(),
|
|
266
|
+
updatedAt: v.number(),
|
|
267
|
+
})
|
|
268
|
+
.index("byUserId", ["userId"])
|
|
269
|
+
.index("byCategory", ["category"])
|
|
270
|
+
.index("byProvider", ["provider"])
|
|
271
|
+
.index("byIsActive", ["isActive"]),
|
|
28
272
|
});
|
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
"dev": "agentforge run",
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"convex:dev": "npx convex dev",
|
|
10
|
-
"convex:deploy": "npx convex deploy"
|
|
10
|
+
"convex:deploy": "npx convex deploy",
|
|
11
|
+
"dashboard": "agentforge dashboard"
|
|
11
12
|
},
|
|
12
13
|
"dependencies": {
|
|
13
|
-
"@agentforge-ai/core": "^0.3.
|
|
14
|
-
"convex": "^1.17.0"
|
|
14
|
+
"@agentforge-ai/core": "^0.3.2",
|
|
15
|
+
"convex": "^1.17.0",
|
|
16
|
+
"zod": "^3.23.0"
|
|
15
17
|
},
|
|
16
18
|
"devDependencies": {
|
|
17
19
|
"typescript": "^5.5.0"
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# Skill Creator
|
|
2
|
+
|
|
3
|
+
**Built-in AgentForge Skill** — Create, manage, and discover skills for your agents.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Skill Creator is a default skill that ships with every AgentForge project. It allows you to:
|
|
8
|
+
|
|
9
|
+
1. **Create new skills** from natural language descriptions
|
|
10
|
+
2. **Browse example skills** to understand the skill format
|
|
11
|
+
3. **Validate skills** before installing them
|
|
12
|
+
4. **Generate skill code** using your connected LLM
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
### Via CLI
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Create a new skill interactively
|
|
20
|
+
agentforge skills create
|
|
21
|
+
|
|
22
|
+
# Ask the agent to create a skill
|
|
23
|
+
agentforge chat my-agent
|
|
24
|
+
> Create a skill that can fetch weather data for any city
|
|
25
|
+
|
|
26
|
+
# List available example skills
|
|
27
|
+
agentforge skills search examples
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Via Dashboard
|
|
31
|
+
|
|
32
|
+
Navigate to **Skills** in the sidebar, then click **"Create Skill"** to use the visual skill builder.
|
|
33
|
+
|
|
34
|
+
### Via Agent Chat
|
|
35
|
+
|
|
36
|
+
When chatting with an agent that has the Skill Creator tool enabled, simply ask:
|
|
37
|
+
|
|
38
|
+
> "Create a skill that can [description of what you want]"
|
|
39
|
+
|
|
40
|
+
The agent will generate the skill definition, validate it, and offer to install it.
|
|
41
|
+
|
|
42
|
+
## Skill Format
|
|
43
|
+
|
|
44
|
+
Every AgentForge skill is a directory with the following structure:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
skills/
|
|
48
|
+
my-skill/
|
|
49
|
+
SKILL.md # Documentation and instructions
|
|
50
|
+
index.ts # Main skill entry point
|
|
51
|
+
config.json # Skill metadata and configuration
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### config.json
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"name": "my-skill",
|
|
59
|
+
"version": "1.0.0",
|
|
60
|
+
"description": "What this skill does",
|
|
61
|
+
"category": "utility",
|
|
62
|
+
"author": "Your Name",
|
|
63
|
+
"tools": ["tool-name-1", "tool-name-2"],
|
|
64
|
+
"dependencies": [],
|
|
65
|
+
"agentInstructions": "Additional instructions for agents using this skill"
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### index.ts
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { z } from 'zod';
|
|
73
|
+
|
|
74
|
+
export const tools = [
|
|
75
|
+
{
|
|
76
|
+
name: 'my-tool',
|
|
77
|
+
description: 'What this tool does',
|
|
78
|
+
inputSchema: z.object({
|
|
79
|
+
param1: z.string().describe('Description of param1'),
|
|
80
|
+
}),
|
|
81
|
+
outputSchema: z.object({
|
|
82
|
+
result: z.string(),
|
|
83
|
+
}),
|
|
84
|
+
handler: async (input: { param1: string }) => {
|
|
85
|
+
// Your tool logic here
|
|
86
|
+
return { result: `Processed: ${input.param1}` };
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
export default { tools };
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Example Skills
|
|
95
|
+
|
|
96
|
+
### 1. Web Search Skill
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// skills/web-search/index.ts
|
|
100
|
+
import { z } from 'zod';
|
|
101
|
+
|
|
102
|
+
export const tools = [
|
|
103
|
+
{
|
|
104
|
+
name: 'web-search',
|
|
105
|
+
description: 'Search the web for information',
|
|
106
|
+
inputSchema: z.object({
|
|
107
|
+
query: z.string().describe('Search query'),
|
|
108
|
+
maxResults: z.number().optional().default(5),
|
|
109
|
+
}),
|
|
110
|
+
outputSchema: z.object({
|
|
111
|
+
results: z.array(z.object({
|
|
112
|
+
title: z.string(),
|
|
113
|
+
url: z.string(),
|
|
114
|
+
snippet: z.string(),
|
|
115
|
+
})),
|
|
116
|
+
}),
|
|
117
|
+
handler: async (input) => {
|
|
118
|
+
// Implement with your preferred search API
|
|
119
|
+
const response = await fetch(
|
|
120
|
+
`https://api.search.example/search?q=${encodeURIComponent(input.query)}&limit=${input.maxResults}`
|
|
121
|
+
);
|
|
122
|
+
const data = await response.json();
|
|
123
|
+
return { results: data.results };
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
];
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 2. Calculator Skill
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
// skills/calculator/index.ts
|
|
133
|
+
import { z } from 'zod';
|
|
134
|
+
|
|
135
|
+
export const tools = [
|
|
136
|
+
{
|
|
137
|
+
name: 'calculate',
|
|
138
|
+
description: 'Evaluate a mathematical expression',
|
|
139
|
+
inputSchema: z.object({
|
|
140
|
+
expression: z.string().describe('Math expression to evaluate (e.g., "2 + 2 * 3")'),
|
|
141
|
+
}),
|
|
142
|
+
outputSchema: z.object({
|
|
143
|
+
result: z.number(),
|
|
144
|
+
expression: z.string(),
|
|
145
|
+
}),
|
|
146
|
+
handler: async (input) => {
|
|
147
|
+
const result = Function('"use strict"; return (' + input.expression + ')')();
|
|
148
|
+
return { result: Number(result), expression: input.expression };
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
];
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 3. File Reader Skill
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// skills/file-reader/index.ts
|
|
158
|
+
import { z } from 'zod';
|
|
159
|
+
import { readFile } from 'fs/promises';
|
|
160
|
+
|
|
161
|
+
export const tools = [
|
|
162
|
+
{
|
|
163
|
+
name: 'read-file',
|
|
164
|
+
description: 'Read the contents of a file',
|
|
165
|
+
inputSchema: z.object({
|
|
166
|
+
path: z.string().describe('Path to the file'),
|
|
167
|
+
encoding: z.string().optional().default('utf-8'),
|
|
168
|
+
}),
|
|
169
|
+
outputSchema: z.object({
|
|
170
|
+
content: z.string(),
|
|
171
|
+
size: z.number(),
|
|
172
|
+
}),
|
|
173
|
+
handler: async (input) => {
|
|
174
|
+
const content = await readFile(input.path, input.encoding as BufferEncoding);
|
|
175
|
+
return { content, size: content.length };
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
];
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 4. JSON Transformer Skill
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// skills/json-transformer/index.ts
|
|
185
|
+
import { z } from 'zod';
|
|
186
|
+
|
|
187
|
+
export const tools = [
|
|
188
|
+
{
|
|
189
|
+
name: 'transform-json',
|
|
190
|
+
description: 'Transform JSON data using a jq-like expression',
|
|
191
|
+
inputSchema: z.object({
|
|
192
|
+
data: z.string().describe('JSON string to transform'),
|
|
193
|
+
path: z.string().describe('Dot-notation path to extract (e.g., "users.0.name")'),
|
|
194
|
+
}),
|
|
195
|
+
outputSchema: z.object({
|
|
196
|
+
result: z.any(),
|
|
197
|
+
}),
|
|
198
|
+
handler: async (input) => {
|
|
199
|
+
const obj = JSON.parse(input.data);
|
|
200
|
+
const parts = input.path.split('.');
|
|
201
|
+
let current: any = obj;
|
|
202
|
+
for (const part of parts) {
|
|
203
|
+
current = current?.[part] ?? current?.[Number(part)];
|
|
204
|
+
}
|
|
205
|
+
return { result: current };
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
];
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### 5. HTTP Request Skill
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// skills/http-request/index.ts
|
|
215
|
+
import { z } from 'zod';
|
|
216
|
+
|
|
217
|
+
export const tools = [
|
|
218
|
+
{
|
|
219
|
+
name: 'http-request',
|
|
220
|
+
description: 'Make an HTTP request to any URL',
|
|
221
|
+
inputSchema: z.object({
|
|
222
|
+
url: z.string().url().describe('URL to request'),
|
|
223
|
+
method: z.enum(['GET', 'POST', 'PUT', 'DELETE']).default('GET'),
|
|
224
|
+
headers: z.record(z.string()).optional(),
|
|
225
|
+
body: z.string().optional(),
|
|
226
|
+
}),
|
|
227
|
+
outputSchema: z.object({
|
|
228
|
+
status: z.number(),
|
|
229
|
+
body: z.string(),
|
|
230
|
+
headers: z.record(z.string()),
|
|
231
|
+
}),
|
|
232
|
+
handler: async (input) => {
|
|
233
|
+
const response = await fetch(input.url, {
|
|
234
|
+
method: input.method,
|
|
235
|
+
headers: input.headers,
|
|
236
|
+
body: input.body,
|
|
237
|
+
});
|
|
238
|
+
const body = await response.text();
|
|
239
|
+
const headers: Record<string, string> = {};
|
|
240
|
+
response.headers.forEach((v, k) => { headers[k] = v; });
|
|
241
|
+
return { status: response.status, body, headers };
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
];
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Creating Skills with AI
|
|
248
|
+
|
|
249
|
+
When you ask an agent to create a skill, the Skill Creator tool will:
|
|
250
|
+
|
|
251
|
+
1. **Parse your request** — Understand what the skill should do
|
|
252
|
+
2. **Generate the code** — Create `index.ts` with proper Zod schemas
|
|
253
|
+
3. **Create metadata** — Generate `config.json` with name, description, category
|
|
254
|
+
4. **Write documentation** — Generate `SKILL.md` with usage instructions
|
|
255
|
+
5. **Validate** — Ensure the skill compiles and schemas are correct
|
|
256
|
+
6. **Install** — Save to your `skills/` directory and register with Convex
|
|
257
|
+
|
|
258
|
+
## Categories
|
|
259
|
+
|
|
260
|
+
Skills are organized by category:
|
|
261
|
+
|
|
262
|
+
| Category | Description | Examples |
|
|
263
|
+
|----------|-------------|---------|
|
|
264
|
+
| `utility` | General-purpose tools | Calculator, JSON transformer |
|
|
265
|
+
| `web` | Web interaction | HTTP requests, web search, scraping |
|
|
266
|
+
| `file` | File operations | Read, write, transform files |
|
|
267
|
+
| `data` | Data processing | CSV parsing, data analysis |
|
|
268
|
+
| `integration` | External services | Slack, GitHub, email |
|
|
269
|
+
| `ai` | AI-powered tools | Summarization, translation |
|
|
270
|
+
| `custom` | User-defined | Anything else |
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "skill-creator",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Built-in skill for creating, managing, and discovering AgentForge skills. Allows agents to generate new skills from natural language descriptions.",
|
|
5
|
+
"category": "utility",
|
|
6
|
+
"author": "AgentForge",
|
|
7
|
+
"isBuiltIn": true,
|
|
8
|
+
"tools": ["create-skill", "list-examples", "validate-skill"],
|
|
9
|
+
"dependencies": [],
|
|
10
|
+
"agentInstructions": "You have access to the Skill Creator tool. When a user asks you to create a skill, use the create-skill tool to generate the skill code, config, and documentation. You can also use list-examples to show available example skills, and validate-skill to check if a skill definition is valid."
|
|
11
|
+
}
|