@chatbotkit/agent 1.28.0 → 1.29.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/README.md +67 -0
- package/dist/cjs/agent.cjs +37 -250
- package/dist/cjs/agent.d.ts +9 -53
- package/dist/cjs/execute.cjs +309 -0
- package/dist/cjs/execute.d.ts +56 -0
- package/dist/cjs/index.cjs +9 -4
- package/dist/cjs/index.d.ts +3 -1
- package/dist/cjs/skills.cjs +116 -0
- package/dist/cjs/skills.d.ts +18 -0
- package/dist/esm/agent.d.ts +9 -53
- package/dist/esm/agent.js +35 -248
- package/dist/esm/execute.d.ts +56 -0
- package/dist/esm/execute.js +305 -0
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +3 -1
- package/dist/esm/skills.d.ts +18 -0
- package/dist/esm/skills.js +111 -0
- package/package.json +44 -2
package/README.md
CHANGED
|
@@ -9,6 +9,20 @@
|
|
|
9
9
|
|
|
10
10
|
Build autonomous AI agents that can use custom tools and execute complex tasks with the full power of the ChatBotKit platform.
|
|
11
11
|
|
|
12
|
+
## Why ChatBotKit?
|
|
13
|
+
|
|
14
|
+
**Build lighter, future-proof AI agents.** When you build with ChatBotKit, the heavy lifting happens on our servers—not in your application. This architectural advantage delivers:
|
|
15
|
+
|
|
16
|
+
- 🪶 **Lightweight Agents**: Your agents stay lean because complex AI processing, model orchestration, and tool execution happen server-side. Less code in your app means faster load times and simpler maintenance.
|
|
17
|
+
|
|
18
|
+
- 🛡️ **Robust & Streamlined**: Server-side processing provides a more reliable experience with built-in error handling, automatic retries, and consistent behavior across all platforms.
|
|
19
|
+
|
|
20
|
+
- 🔄 **Backward & Forward Compatible**: As AI technology evolves—new models, new capabilities, new paradigms—your agents automatically benefit. No code changes required on your end.
|
|
21
|
+
|
|
22
|
+
- 🔮 **Future-Proof**: Agents you build today will remain capable tomorrow. When we add support for new AI models or capabilities, your existing agents gain those powers without any updates to your codebase.
|
|
23
|
+
|
|
24
|
+
This means you can focus on building great user experiences while ChatBotKit handles the complexity of the ever-changing AI landscape.
|
|
25
|
+
|
|
12
26
|
## Installation
|
|
13
27
|
|
|
14
28
|
```bash
|
|
@@ -178,6 +192,59 @@ The `execute` mode provides system tools for task management:
|
|
|
178
192
|
- **`progress`** - Track completion status and blockers
|
|
179
193
|
- **`exit`** - Signal task completion with status code
|
|
180
194
|
|
|
195
|
+
### Skills Loading
|
|
196
|
+
|
|
197
|
+
Load skills from local directories and pass them as a feature to the agent. Skills are defined using `SKILL.md` files with front matter containing name and description.
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
import { execute, loadSkills, createSkillsFeature } from '@chatbotkit/agent'
|
|
201
|
+
import { ChatBotKit } from '@chatbotkit/sdk'
|
|
202
|
+
|
|
203
|
+
const client = new ChatBotKit({ secret: process.env.CHATBOTKIT_API_TOKEN })
|
|
204
|
+
|
|
205
|
+
// Load skills from directories
|
|
206
|
+
const skillsResult = await loadSkills(['./skills'], { watch: true })
|
|
207
|
+
|
|
208
|
+
// Create the skills feature for the API
|
|
209
|
+
const skillsFeature = createSkillsFeature(skillsResult.skills)
|
|
210
|
+
|
|
211
|
+
const stream = execute({
|
|
212
|
+
client,
|
|
213
|
+
model: 'gpt-4o',
|
|
214
|
+
messages: [{ type: 'user', text: 'Help me with my task' }],
|
|
215
|
+
extensions: {
|
|
216
|
+
features: [skillsFeature],
|
|
217
|
+
},
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
for await (const event of stream) {
|
|
221
|
+
// Handle events
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Clean up when done
|
|
225
|
+
skillsResult.close()
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### SKILL.md Format
|
|
229
|
+
|
|
230
|
+
Create a `SKILL.md` file in each skill directory:
|
|
231
|
+
|
|
232
|
+
```markdown
|
|
233
|
+
---
|
|
234
|
+
name: My Skill
|
|
235
|
+
description: A brief description of what this skill does
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
# My Skill
|
|
239
|
+
|
|
240
|
+
Additional documentation for the skill...
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
#### Skills API
|
|
244
|
+
|
|
245
|
+
- **`loadSkills(directories, options)`** - Load skills from directories containing SKILL.md files
|
|
246
|
+
- **`createSkillsFeature(skills)`** - Create a feature configuration for the API
|
|
247
|
+
|
|
181
248
|
## Documentation
|
|
182
249
|
|
|
183
250
|
For comprehensive information about the ChatBotKit Agent SDK, including detailed documentation on its functionalities, helper methods, and configuration options, please visit our [type documentation page](https://chatbotkit.github.io/node-sdk/modules/_chatbotkit_agent.html).
|
package/dist/cjs/agent.cjs
CHANGED
|
@@ -1,258 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const channel = `${name}_${randomSuffix}`.padEnd(16, '0');
|
|
14
|
-
channelToTool.set(channel, { name, tool });
|
|
15
|
-
if (!tool.input) {
|
|
16
|
-
return {
|
|
17
|
-
name,
|
|
18
|
-
description: tool.description,
|
|
19
|
-
parameters: ({
|
|
20
|
-
type: 'object',
|
|
21
|
-
properties: {},
|
|
22
|
-
}),
|
|
23
|
-
result: {
|
|
24
|
-
channel,
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
const schema = ((0, zod_to_json_schema_1.zodToJsonSchema)(tool.input, { target: 'openApi3' }));
|
|
29
|
-
const parameters = {
|
|
30
|
-
type: 'object',
|
|
31
|
-
properties: schema.properties || {},
|
|
32
|
-
...(schema.required && schema.required.length > 0
|
|
33
|
-
? { required: schema.required }
|
|
34
|
-
: {}),
|
|
35
|
-
};
|
|
36
|
-
return {
|
|
37
|
-
name,
|
|
38
|
-
description: tool.description,
|
|
39
|
-
parameters: (parameters),
|
|
40
|
-
result: {
|
|
41
|
-
channel,
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
})
|
|
45
|
-
: undefined;
|
|
46
|
-
const stream = client.conversation
|
|
47
|
-
.complete(null, {
|
|
48
|
-
...request,
|
|
49
|
-
functions,
|
|
50
|
-
})
|
|
51
|
-
.stream();
|
|
52
|
-
const toolEventQueue = [];
|
|
53
|
-
const runningTools = new Set();
|
|
54
|
-
const executeToolAsync = async (channel, name, tool, args) => {
|
|
55
|
-
try {
|
|
56
|
-
let parsedArgs = args;
|
|
57
|
-
if (tool.input) {
|
|
58
|
-
const parseResult = tool.input.safeParse(args);
|
|
59
|
-
if (!parseResult.success) {
|
|
60
|
-
const errorMsg = `Invalid arguments: ${parseResult.error.message}`;
|
|
61
|
-
toolEventQueue.push({
|
|
62
|
-
type: 'toolCallError',
|
|
63
|
-
data: { name, error: errorMsg },
|
|
64
|
-
});
|
|
65
|
-
await client.channel.publish(String(channel), {
|
|
66
|
-
message: { error: errorMsg },
|
|
67
|
-
});
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
parsedArgs = parseResult.data;
|
|
71
|
-
}
|
|
72
|
-
const result = await tool.handler(parsedArgs);
|
|
73
|
-
toolEventQueue.push({
|
|
74
|
-
type: 'toolCallEnd',
|
|
75
|
-
data: { name, result },
|
|
76
|
-
});
|
|
77
|
-
await client.channel.publish(String(channel), {
|
|
78
|
-
message: { data: result },
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
catch (error) {
|
|
82
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
83
|
-
toolEventQueue.push({
|
|
84
|
-
type: 'toolCallError',
|
|
85
|
-
data: { name, error: errorMessage },
|
|
86
|
-
});
|
|
87
|
-
await client.channel.publish(String(channel), {
|
|
88
|
-
message: { error: errorMessage },
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
finally {
|
|
92
|
-
runningTools.delete(channel);
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
for await (const event of stream) {
|
|
96
|
-
while (toolEventQueue.length > 0) {
|
|
97
|
-
const toolEvent = toolEventQueue.shift();
|
|
98
|
-
if (toolEvent) {
|
|
99
|
-
yield toolEvent;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
if (event.type === 'waitForChannelMessageBegin' &&
|
|
103
|
-
event.data &&
|
|
104
|
-
'channel' in event.data &&
|
|
105
|
-
'function' in event.data) {
|
|
106
|
-
const channel = (event.data.channel);
|
|
107
|
-
const args = (event.data.function).args;
|
|
108
|
-
const toolInfo = channelToTool.get(String(channel));
|
|
109
|
-
if (toolInfo) {
|
|
110
|
-
const { name, tool } = toolInfo;
|
|
111
|
-
yield {
|
|
112
|
-
type: 'toolCallStart',
|
|
113
|
-
data: {
|
|
114
|
-
name,
|
|
115
|
-
args,
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
const toolPromise = executeToolAsync(channel, name, tool, args);
|
|
119
|
-
runningTools.add(channel);
|
|
120
|
-
toolPromise.catch(() => {
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
yield event;
|
|
3
|
+
exports.loadAgent = loadAgent;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const promises_1 = require("fs/promises");
|
|
6
|
+
const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
function parseAgentFile(content) {
|
|
9
|
+
const frontMatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)/;
|
|
10
|
+
const match = content.match(frontMatterRegex);
|
|
11
|
+
if (!match) {
|
|
12
|
+
return { frontMatter: {}, body: content.trim() };
|
|
125
13
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
14
|
+
let frontMatter = ({});
|
|
15
|
+
try {
|
|
16
|
+
const parsed = js_yaml_1.default.load(match[1]);
|
|
17
|
+
if (typeof parsed === 'object' && parsed !== null) {
|
|
18
|
+
frontMatter = (parsed);
|
|
130
19
|
}
|
|
131
20
|
}
|
|
132
|
-
|
|
133
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
134
|
-
while (toolEventQueue.length > 0) {
|
|
135
|
-
const toolEvent = toolEventQueue.shift();
|
|
136
|
-
if (toolEvent) {
|
|
137
|
-
yield toolEvent;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
21
|
+
catch {
|
|
140
22
|
}
|
|
23
|
+
return { frontMatter, body: match[2].trim() };
|
|
141
24
|
}
|
|
142
|
-
async function
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
};
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
progress: {
|
|
166
|
-
description: 'Update progress on the current task. Use this to track completed steps, report current status, and identify blockers.',
|
|
167
|
-
input: zod_1.z.object({
|
|
168
|
-
completed: zod_1.z
|
|
169
|
-
.array(zod_1.z.string())
|
|
170
|
-
.optional()
|
|
171
|
-
.describe('Steps that have been completed'),
|
|
172
|
-
current: zod_1.z.string().optional().describe('Current step being worked on'),
|
|
173
|
-
blockers: zod_1.z
|
|
174
|
-
.array(zod_1.z.string())
|
|
175
|
-
.optional()
|
|
176
|
-
.describe('Any issues preventing progress'),
|
|
177
|
-
nextSteps: zod_1.z
|
|
178
|
-
.array(zod_1.z.string())
|
|
179
|
-
.optional()
|
|
180
|
-
.describe('Next actions to take'),
|
|
181
|
-
}),
|
|
182
|
-
handler: async (input) => {
|
|
183
|
-
return {
|
|
184
|
-
success: true,
|
|
185
|
-
message: 'Progress updated',
|
|
186
|
-
...input,
|
|
187
|
-
};
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
exit: {
|
|
191
|
-
description: 'Exit the task execution with a status code and optional message. Status code 0 indicates success, non-zero indicates failure. Use this when all the tasks are complete or cannot proceed.',
|
|
192
|
-
input: zod_1.z.object({
|
|
193
|
-
code: zod_1.z
|
|
194
|
-
.number()
|
|
195
|
-
.int()
|
|
196
|
-
.min(0)
|
|
197
|
-
.max(255)
|
|
198
|
-
.describe('Exit status code (0 = success, non-zero = failure)'),
|
|
199
|
-
message: zod_1.z
|
|
200
|
-
.string()
|
|
201
|
-
.optional()
|
|
202
|
-
.describe('Optional message explaining the exit reason'),
|
|
203
|
-
}),
|
|
204
|
-
handler: async (input) => {
|
|
205
|
-
exitResult = { code: input.code, message: input.message };
|
|
206
|
-
return {
|
|
207
|
-
success: true,
|
|
208
|
-
message: `Task exiting with code ${input.code}${input.message ? ': ' + input.message : ''}`,
|
|
209
|
-
};
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
};
|
|
213
|
-
const allTools = { ...systemTools, ...tools };
|
|
214
|
-
const systemInstruction = `
|
|
215
|
-
${options.extensions?.backstory || ''}
|
|
216
|
-
|
|
217
|
-
# Task Execution Guidelines
|
|
218
|
-
|
|
219
|
-
The goal is to complete the assigned task efficiently and effectively. Follow these guidelines:
|
|
220
|
-
|
|
221
|
-
1. **Plan First**: Use the 'plan' function to create a clear strategy before starting work
|
|
222
|
-
2. **Track Progress**: Regularly use the 'progress' function to update status and identify issues
|
|
223
|
-
3. **Use Tools**: Leverage available tools to accomplish each step of your plan
|
|
224
|
-
4. **Exit When Done**: Call the 'exit' function with code 0 when successful, or non-zero code if unable to complete
|
|
225
|
-
5. **Be Autonomous**: Work through the task systematically without waiting for additional input
|
|
226
|
-
`.trim();
|
|
227
|
-
let iteration = 0;
|
|
228
|
-
while (iteration < maxIterations && exitResult === null) {
|
|
229
|
-
iteration++;
|
|
230
|
-
yield { type: 'iteration', data: { iteration } };
|
|
231
|
-
for await (const event of complete({
|
|
232
|
-
...request,
|
|
233
|
-
client,
|
|
234
|
-
messages,
|
|
235
|
-
tools: allTools,
|
|
236
|
-
extensions: {
|
|
237
|
-
...options.extensions,
|
|
238
|
-
backstory: systemInstruction,
|
|
239
|
-
},
|
|
240
|
-
})) {
|
|
241
|
-
yield event;
|
|
242
|
-
}
|
|
243
|
-
if (exitResult) {
|
|
244
|
-
break;
|
|
245
|
-
}
|
|
246
|
-
messages.push({
|
|
247
|
-
type: 'user',
|
|
248
|
-
text: 'Continue with the next step of your plan. If all steps are complete, call exit with the appropriate status code.',
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
if (exitResult === null) {
|
|
252
|
-
exitResult = {
|
|
253
|
-
code: 1,
|
|
254
|
-
message: `Task did not complete within ${maxIterations} iterations`,
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
yield { type: 'exit', data: exitResult };
|
|
25
|
+
async function loadAgent(filePath) {
|
|
26
|
+
const resolvedPath = (0, path_1.resolve)(process.cwd(), filePath);
|
|
27
|
+
const content = await (0, promises_1.readFile)(resolvedPath, 'utf-8');
|
|
28
|
+
const { frontMatter, body } = parseAgentFile(content);
|
|
29
|
+
const name = typeof frontMatter.name === 'string' ? frontMatter.name : undefined;
|
|
30
|
+
const description = typeof frontMatter.description === 'string'
|
|
31
|
+
? frontMatter.description
|
|
32
|
+
: undefined;
|
|
33
|
+
const model = typeof frontMatter.model === 'string' ? frontMatter.model : undefined;
|
|
34
|
+
const botId = typeof frontMatter.botId === 'string' ? frontMatter.botId : undefined;
|
|
35
|
+
const skillsetId = typeof frontMatter.skillsetId === 'string'
|
|
36
|
+
? frontMatter.skillsetId
|
|
37
|
+
: undefined;
|
|
38
|
+
const datasetId = typeof frontMatter.datasetId === 'string'
|
|
39
|
+
? frontMatter.datasetId
|
|
40
|
+
: undefined;
|
|
41
|
+
const frontMatterBackstory = typeof frontMatter.backstory === 'string' ? frontMatter.backstory : '';
|
|
42
|
+
const backstoryParts = [frontMatterBackstory, body].filter(Boolean);
|
|
43
|
+
const backstory = backstoryParts.length > 0 ? backstoryParts.join('\n\n') : undefined;
|
|
44
|
+
return { name, description, backstory, model, botId, skillsetId, datasetId };
|
|
258
45
|
}
|
package/dist/cjs/agent.d.ts
CHANGED
|
@@ -1,54 +1,10 @@
|
|
|
1
|
-
export function
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export type ZodObject = import("zod").ZodObject<any>;
|
|
11
|
-
export type ChatBotKit = import("@chatbotkit/sdk").ChatBotKit;
|
|
12
|
-
export type ConversationCompleteRequest = any;
|
|
13
|
-
export type ConversationCompleteStreamType = any;
|
|
14
|
-
export type ToolDefinition<T extends ZodObject> = {
|
|
15
|
-
description: string;
|
|
16
|
-
input?: T;
|
|
17
|
-
handler: (input: any) => Promise<any>;
|
|
18
|
-
};
|
|
19
|
-
export type Tools = Record<string, ToolDefinition<ZodObject>>;
|
|
20
|
-
export type ExitResult = {
|
|
21
|
-
code: number;
|
|
22
|
-
message?: string;
|
|
23
|
-
};
|
|
24
|
-
export type ToolCallStartEvent = {
|
|
25
|
-
type: "toolCallStart";
|
|
26
|
-
data: {
|
|
27
|
-
name: string;
|
|
28
|
-
args: any;
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
export type ToolCallEndEvent = {
|
|
32
|
-
type: "toolCallEnd";
|
|
33
|
-
data: {
|
|
34
|
-
name: string;
|
|
35
|
-
result: any;
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
export type ToolCallErrorEvent = {
|
|
39
|
-
type: "toolCallError";
|
|
40
|
-
data: {
|
|
41
|
-
name: string;
|
|
42
|
-
error: string;
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
export type IterationEvent = {
|
|
46
|
-
type: "iteration";
|
|
47
|
-
data: {
|
|
48
|
-
iteration: number;
|
|
49
|
-
};
|
|
50
|
-
};
|
|
51
|
-
export type ExitEvent = {
|
|
52
|
-
type: "exit";
|
|
53
|
-
data: ExitResult;
|
|
1
|
+
export function loadAgent(filePath: string): Promise<AgentDefinition>;
|
|
2
|
+
export type AgentDefinition = {
|
|
3
|
+
name?: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
backstory?: string;
|
|
6
|
+
model?: string;
|
|
7
|
+
botId?: string;
|
|
8
|
+
skillsetId?: string;
|
|
9
|
+
datasetId?: string;
|
|
54
10
|
};
|