@chatbotkit/cli 1.20.0 → 1.21.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 +78 -20
- package/bin/cbk.js +7 -2
- package/dist/cjs/command/agent/index.cjs +100 -0
- package/dist/cjs/command/agent/index.d.ts +3 -0
- package/dist/cjs/command/api/conversation/index.cjs +13 -8
- package/dist/cjs/command/api/conversation/index.d.ts +0 -2
- package/dist/cjs/command/api/conversation/message/index.cjs +9 -4
- package/dist/cjs/command/api/dataset/index.cjs +9 -4
- package/dist/cjs/command/api/index.cjs +10 -5
- package/dist/cjs/command/api/index.d.ts +1 -0
- package/dist/cjs/command/api/partner/index.cjs +7 -2
- package/dist/cjs/command/api/partner/user/index.cjs +9 -4
- package/dist/cjs/command/api/skillset/index.cjs +9 -4
- package/dist/cjs/command/chat/index.cjs +34 -9
- package/dist/cjs/index.cjs +6 -4
- package/dist/cjs/output.cjs +4 -0
- package/dist/cjs/solution/index.cjs +3 -3
- package/dist/cjs/spinner.cjs +56 -0
- package/dist/cjs/spinner.d.ts +15 -0
- package/dist/cjs/tools.cjs +197 -0
- package/dist/cjs/tools.d.ts +9 -0
- package/dist/esm/command/agent/index.d.ts +3 -0
- package/dist/esm/command/agent/index.js +97 -0
- package/dist/esm/command/api/conversation/index.d.ts +0 -2
- package/dist/esm/command/api/conversation/index.js +12 -7
- package/dist/esm/command/api/conversation/message/index.js +9 -4
- package/dist/esm/command/api/dataset/index.js +9 -4
- package/dist/esm/command/api/index.d.ts +1 -0
- package/dist/esm/command/api/index.js +10 -5
- package/dist/esm/command/api/partner/index.js +7 -2
- package/dist/esm/command/api/partner/user/index.js +9 -4
- package/dist/esm/command/api/skillset/index.js +9 -4
- package/dist/esm/command/chat/index.js +34 -9
- package/dist/esm/index.js +2 -0
- package/dist/esm/output.js +4 -0
- package/dist/esm/spinner.d.ts +15 -0
- package/dist/esm/spinner.js +52 -0
- package/dist/esm/tools.d.ts +9 -0
- package/dist/esm/tools.js +192 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +76 -5
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tools = void 0;
|
|
4
|
+
exports.getTools = getTools;
|
|
5
|
+
exports.getToolNames = getToolNames;
|
|
6
|
+
const child_process_1 = require("child_process");
|
|
7
|
+
const promises_1 = require("fs/promises");
|
|
8
|
+
const util_1 = require("util");
|
|
9
|
+
const zod_1 = require("zod");
|
|
10
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
11
|
+
exports.tools = {
|
|
12
|
+
read: {
|
|
13
|
+
description: 'Read the contents of a file',
|
|
14
|
+
default: true,
|
|
15
|
+
input: zod_1.z.object({
|
|
16
|
+
path: zod_1.z.string().describe('The file path to read'),
|
|
17
|
+
}),
|
|
18
|
+
handler: async (input) => {
|
|
19
|
+
try {
|
|
20
|
+
const content = await (0, promises_1.readFile)(input.path, 'utf-8');
|
|
21
|
+
return { success: true, content };
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return {
|
|
25
|
+
success: false,
|
|
26
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
write: {
|
|
32
|
+
description: 'Write content to a file',
|
|
33
|
+
default: true,
|
|
34
|
+
input: zod_1.z.object({
|
|
35
|
+
path: zod_1.z.string().describe('The file path to write to'),
|
|
36
|
+
content: zod_1.z.string().describe('The content to write'),
|
|
37
|
+
}),
|
|
38
|
+
handler: async (input) => {
|
|
39
|
+
try {
|
|
40
|
+
await (0, promises_1.writeFile)(input.path, input.content, 'utf-8');
|
|
41
|
+
return { success: true };
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
edit: {
|
|
52
|
+
description: 'Edit a file by replacing an exact string occurrence with a new string. Only one occurrence must exist.',
|
|
53
|
+
default: true,
|
|
54
|
+
input: zod_1.z.object({
|
|
55
|
+
path: zod_1.z.string().describe('The file path to edit'),
|
|
56
|
+
oldString: zod_1.z
|
|
57
|
+
.string()
|
|
58
|
+
.describe('The exact string to find and replace (must match exactly)'),
|
|
59
|
+
newString: zod_1.z.string().describe('The new string to replace with'),
|
|
60
|
+
}),
|
|
61
|
+
handler: async (input) => {
|
|
62
|
+
try {
|
|
63
|
+
const content = await (0, promises_1.readFile)(input.path, 'utf-8');
|
|
64
|
+
const occurrences = content.split(input.oldString).length - 1;
|
|
65
|
+
if (occurrences === 0) {
|
|
66
|
+
return {
|
|
67
|
+
success: false,
|
|
68
|
+
error: 'String not found in file',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (occurrences > 1) {
|
|
72
|
+
return {
|
|
73
|
+
success: false,
|
|
74
|
+
error: `Multiple occurrences found (${occurrences}). The old string must match exactly one location.`,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const newContent = content.replace(input.oldString, input.newString);
|
|
78
|
+
await (0, promises_1.writeFile)(input.path, newContent, 'utf-8');
|
|
79
|
+
const oldPreview = input.oldString.length > 100
|
|
80
|
+
? input.oldString.substring(0, 100) + '...'
|
|
81
|
+
: input.oldString;
|
|
82
|
+
const newPreview = input.newString.length > 100
|
|
83
|
+
? input.newString.substring(0, 100) + '...'
|
|
84
|
+
: input.newString;
|
|
85
|
+
return {
|
|
86
|
+
success: true,
|
|
87
|
+
message: `Successfully replaced:\n OLD: ${oldPreview}\n NEW: ${newPreview}`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
find: {
|
|
99
|
+
description: 'Search for files matching a pattern',
|
|
100
|
+
default: true,
|
|
101
|
+
input: zod_1.z.object({
|
|
102
|
+
pattern: zod_1.z.string().describe('The glob pattern to search for'),
|
|
103
|
+
directory: zod_1.z
|
|
104
|
+
.string()
|
|
105
|
+
.optional()
|
|
106
|
+
.describe('The directory to search in (defaults to current)'),
|
|
107
|
+
}),
|
|
108
|
+
handler: async (input) => {
|
|
109
|
+
try {
|
|
110
|
+
const dir = input.directory || '.';
|
|
111
|
+
const { stdout } = await execAsync(`find ${dir} -name "${input.pattern}"`);
|
|
112
|
+
const files = stdout.trim().split('\n').filter(Boolean);
|
|
113
|
+
return { success: true, files };
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
return {
|
|
117
|
+
success: false,
|
|
118
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
exec: {
|
|
124
|
+
description: 'Execute a shell command (non-interactive only). Commands timeout after the specified duration (default 30 seconds). Use only for commands that run and exit automatically.',
|
|
125
|
+
default: true,
|
|
126
|
+
input: zod_1.z.object({
|
|
127
|
+
command: zod_1.z.string().describe('The command to execute'),
|
|
128
|
+
timeout: zod_1.z
|
|
129
|
+
.number()
|
|
130
|
+
.default(30)
|
|
131
|
+
.describe('Timeout in seconds. The command will be killed if it runs longer than this.'),
|
|
132
|
+
}),
|
|
133
|
+
handler: async (input) => {
|
|
134
|
+
const timeoutMs = input.timeout * 1000;
|
|
135
|
+
return new Promise((resolve) => {
|
|
136
|
+
const childProcess = (0, child_process_1.spawn)('sh', ['-c', input.command], {
|
|
137
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
138
|
+
timeout: timeoutMs,
|
|
139
|
+
});
|
|
140
|
+
let stdout = '';
|
|
141
|
+
let stderr = '';
|
|
142
|
+
let timedOut = false;
|
|
143
|
+
childProcess.stdout.on('data', (data) => {
|
|
144
|
+
stdout += data.toString();
|
|
145
|
+
});
|
|
146
|
+
childProcess.stderr.on('data', (data) => {
|
|
147
|
+
stderr += data.toString();
|
|
148
|
+
});
|
|
149
|
+
childProcess.on('close', (code) => {
|
|
150
|
+
if (timedOut) {
|
|
151
|
+
resolve({
|
|
152
|
+
success: false,
|
|
153
|
+
error: `Command timed out after ${timeoutMs / 1000} seconds. This may indicate an interactive command.`,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
else if (code === 0) {
|
|
157
|
+
resolve({ success: true, stdout, stderr });
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
resolve({
|
|
161
|
+
success: false,
|
|
162
|
+
error: `Command exited with code ${code}`,
|
|
163
|
+
stdout,
|
|
164
|
+
stderr,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
childProcess.on('error', (error) => {
|
|
169
|
+
resolve({
|
|
170
|
+
success: false,
|
|
171
|
+
error: error.message,
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
setTimeout(() => {
|
|
175
|
+
if (!childProcess.killed) {
|
|
176
|
+
timedOut = true;
|
|
177
|
+
childProcess.kill('SIGTERM');
|
|
178
|
+
setTimeout(() => {
|
|
179
|
+
if (!childProcess.killed) {
|
|
180
|
+
childProcess.kill('SIGKILL');
|
|
181
|
+
}
|
|
182
|
+
}, 2000);
|
|
183
|
+
}
|
|
184
|
+
}, timeoutMs);
|
|
185
|
+
});
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
function getTools(selectedTools) {
|
|
190
|
+
if (!selectedTools || selectedTools.length === 0) {
|
|
191
|
+
return Object.fromEntries(Object.entries(exports.tools).filter(([, tool]) => tool.default));
|
|
192
|
+
}
|
|
193
|
+
return Object.fromEntries(Object.entries(exports.tools).filter(([name]) => selectedTools.includes(name)));
|
|
194
|
+
}
|
|
195
|
+
function getToolNames() {
|
|
196
|
+
return Object.keys(exports.tools);
|
|
197
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function getTools(selectedTools?: Array<keyof typeof tools>): typeof tools;
|
|
2
|
+
export function getToolNames(): Array<keyof typeof tools>;
|
|
3
|
+
export const tools: Record<string, {
|
|
4
|
+
description: string;
|
|
5
|
+
input: z.ZodObject<any>;
|
|
6
|
+
handler: (input: any) => Promise<any>;
|
|
7
|
+
default?: boolean;
|
|
8
|
+
}>;
|
|
9
|
+
import { z } from 'zod';
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { getRUNAS_USERID, getSECRET } from '../../env.js';
|
|
2
|
+
import { print, printError } from '../../output.js';
|
|
3
|
+
import { Spinner } from '../../spinner.js';
|
|
4
|
+
import { getToolNames, getTools } from '../../tools.js';
|
|
5
|
+
import { execute } from '@chatbotkit/agent';
|
|
6
|
+
import { ChatBotKit } from '@chatbotkit/sdk';
|
|
7
|
+
import { Command, Option } from 'commander';
|
|
8
|
+
import { existsSync, readFileSync } from 'fs';
|
|
9
|
+
import { resolve } from 'path';
|
|
10
|
+
function getClient() {
|
|
11
|
+
return new ChatBotKit({
|
|
12
|
+
secret: getSECRET(),
|
|
13
|
+
runAsUserId: getRUNAS_USERID(),
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export const command = new Command()
|
|
17
|
+
.name('agent')
|
|
18
|
+
.description('Run an agent as a background worker with a prompt')
|
|
19
|
+
.addOption(new Option('-b, --bot <bot>', 'Bot id'))
|
|
20
|
+
.addOption(new Option('-m, --model <model>', 'Model name'))
|
|
21
|
+
.addOption(new Option('-p, --prompt <prompt>', 'The prompt to execute (or path to a file containing the prompt)').makeOptionMandatory())
|
|
22
|
+
.addOption(new Option('-t, --tools <tools...>', 'Specific tools to enable').choices(getToolNames()))
|
|
23
|
+
.addOption(new Option('-i, --max-iterations <maxIterations>', 'Maximum number of iterations')
|
|
24
|
+
.default(50)
|
|
25
|
+
.argParser((value) => parseInt(value, 10)))
|
|
26
|
+
.action(async (options) => {
|
|
27
|
+
const client = getClient();
|
|
28
|
+
const tools = getTools(options.tools);
|
|
29
|
+
let prompt = options.prompt;
|
|
30
|
+
{
|
|
31
|
+
const filePath = resolve(process.cwd(), options.prompt);
|
|
32
|
+
if (existsSync(filePath)) {
|
|
33
|
+
try {
|
|
34
|
+
prompt = readFileSync(filePath, 'utf-8');
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
printError(error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const isInteractive = process.stdout.isTTY;
|
|
42
|
+
const spinner = isInteractive ? new Spinner() : null;
|
|
43
|
+
let exitResult = null;
|
|
44
|
+
let hasOutput = false;
|
|
45
|
+
for await (const { type, data } of execute({
|
|
46
|
+
client,
|
|
47
|
+
botId: options.bot,
|
|
48
|
+
model: options.model,
|
|
49
|
+
messages: [{ type: 'user', text: prompt }],
|
|
50
|
+
tools,
|
|
51
|
+
maxIterations: options.maxIterations,
|
|
52
|
+
})) {
|
|
53
|
+
if (type === 'iteration') {
|
|
54
|
+
if (spinner) {
|
|
55
|
+
if (spinner.isSpinning) {
|
|
56
|
+
spinner.stop();
|
|
57
|
+
}
|
|
58
|
+
const iterationNum = data.iteration - 1;
|
|
59
|
+
console.log(`\n╭─ Iteration ${iterationNum} ─╮`);
|
|
60
|
+
spinner.start();
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
print({ iteration: data.iteration - 1 });
|
|
64
|
+
}
|
|
65
|
+
hasOutput = false;
|
|
66
|
+
}
|
|
67
|
+
else if (type === 'token') {
|
|
68
|
+
if (spinner && spinner.isSpinning) {
|
|
69
|
+
spinner.stop();
|
|
70
|
+
}
|
|
71
|
+
if (!hasOutput && isInteractive) {
|
|
72
|
+
process.stdout.write('> ');
|
|
73
|
+
hasOutput = true;
|
|
74
|
+
}
|
|
75
|
+
process.stdout.write(data.token);
|
|
76
|
+
}
|
|
77
|
+
else if (type === 'exit') {
|
|
78
|
+
exitResult = data;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (spinner && spinner.isSpinning) {
|
|
82
|
+
spinner.stop();
|
|
83
|
+
}
|
|
84
|
+
process.stdout.write('\n\n');
|
|
85
|
+
if (exitResult) {
|
|
86
|
+
print({
|
|
87
|
+
status: exitResult.code === 0 ? 'success' : 'failed',
|
|
88
|
+
exitCode: exitResult.code,
|
|
89
|
+
...(exitResult.message && { message: exitResult.message }),
|
|
90
|
+
});
|
|
91
|
+
process.exit(exitResult.code);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
printError(new Error('Task ended without exit signal'));
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
export default command;
|
|
@@ -28,7 +28,7 @@ export const conversationList = new Command()
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
|
-
|
|
31
|
+
const conversationFetch = new Command()
|
|
32
32
|
.name('fetch')
|
|
33
33
|
.description('Fetch conversation')
|
|
34
34
|
.argument('<conversationId>', 'Conversation ID')
|
|
@@ -37,7 +37,7 @@ export const conversationFetch = new Command()
|
|
|
37
37
|
const conversation = await client.fetch(conversationId);
|
|
38
38
|
print(conversation);
|
|
39
39
|
});
|
|
40
|
-
|
|
40
|
+
const conversationDelete = new Command()
|
|
41
41
|
.name('delete')
|
|
42
42
|
.description('Delete conversation')
|
|
43
43
|
.argument('<conversationId>', 'Conversation ID')
|
|
@@ -45,11 +45,16 @@ export const conversationDelete = new Command()
|
|
|
45
45
|
const client = getClient();
|
|
46
46
|
await client.delete(conversationId);
|
|
47
47
|
});
|
|
48
|
+
const commands = {
|
|
49
|
+
list: conversationList,
|
|
50
|
+
fetch: conversationFetch,
|
|
51
|
+
delete: conversationDelete,
|
|
52
|
+
message,
|
|
53
|
+
};
|
|
48
54
|
export const command = new Command()
|
|
49
55
|
.name('conversation')
|
|
50
|
-
.description('Conversation tools for ChatBotKit')
|
|
51
|
-
|
|
52
|
-
.addCommand(
|
|
53
|
-
|
|
54
|
-
.addCommand(message);
|
|
56
|
+
.description('Conversation tools for ChatBotKit');
|
|
57
|
+
for (const cmd of Object.values(commands)) {
|
|
58
|
+
command.addCommand(cmd);
|
|
59
|
+
}
|
|
55
60
|
export default command;
|
|
@@ -47,10 +47,15 @@ export const messageDelete = new Command()
|
|
|
47
47
|
const client = getClient();
|
|
48
48
|
await client.delete(conversationId, messageId);
|
|
49
49
|
});
|
|
50
|
+
const commands = {
|
|
51
|
+
list: messageList,
|
|
52
|
+
fetch: messageFetch,
|
|
53
|
+
delete: messageDelete,
|
|
54
|
+
};
|
|
50
55
|
export const command = new Command()
|
|
51
56
|
.name('message')
|
|
52
|
-
.description('Message tools for ChatBotKit')
|
|
53
|
-
|
|
54
|
-
.addCommand(
|
|
55
|
-
|
|
57
|
+
.description('Message tools for ChatBotKit');
|
|
58
|
+
for (const cmd of Object.values(commands)) {
|
|
59
|
+
command.addCommand(cmd);
|
|
60
|
+
}
|
|
56
61
|
export default command;
|
|
@@ -44,10 +44,15 @@ export const datasetDelete = new Command()
|
|
|
44
44
|
const client = getClient();
|
|
45
45
|
await client.delete(datasetId);
|
|
46
46
|
});
|
|
47
|
+
const commands = {
|
|
48
|
+
list: datasetList,
|
|
49
|
+
fetch: datasetFetch,
|
|
50
|
+
delete: datasetDelete,
|
|
51
|
+
};
|
|
47
52
|
export const command = new Command()
|
|
48
53
|
.name('dataset')
|
|
49
|
-
.description('Dataset tools for ChatBotKit')
|
|
50
|
-
|
|
51
|
-
.addCommand(
|
|
52
|
-
|
|
54
|
+
.description('Dataset tools for ChatBotKit');
|
|
55
|
+
for (const cmd of Object.values(commands)) {
|
|
56
|
+
command.addCommand(cmd);
|
|
57
|
+
}
|
|
53
58
|
export default command;
|
|
@@ -4,13 +4,18 @@ import dataset from './dataset/index.js';
|
|
|
4
4
|
import partner from './partner/index.js';
|
|
5
5
|
import skillset from './skillset/index.js';
|
|
6
6
|
import { Command, Option } from 'commander';
|
|
7
|
+
const commands = {
|
|
8
|
+
conversation,
|
|
9
|
+
dataset,
|
|
10
|
+
skillset,
|
|
11
|
+
partner,
|
|
12
|
+
};
|
|
7
13
|
export const command = new Command()
|
|
8
14
|
.name('api')
|
|
9
|
-
.description('API tools for ChatBotKit')
|
|
10
|
-
|
|
11
|
-
.addCommand(
|
|
12
|
-
|
|
13
|
-
.addCommand(partner);
|
|
15
|
+
.description('API tools for ChatBotKit');
|
|
16
|
+
for (const cmd of Object.values(commands)) {
|
|
17
|
+
command.addCommand(cmd);
|
|
18
|
+
}
|
|
14
19
|
command
|
|
15
20
|
.addOption(new Option('-o, --output <format>', 'Output format').choices([
|
|
16
21
|
'yaml',
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import user from './user/index.js';
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
+
const commands = {
|
|
4
|
+
user,
|
|
5
|
+
};
|
|
3
6
|
export const command = new Command()
|
|
4
7
|
.name('partner')
|
|
5
|
-
.description('Partner tools for ChatBotKit')
|
|
6
|
-
|
|
8
|
+
.description('Partner tools for ChatBotKit');
|
|
9
|
+
for (const cmd of Object.values(commands)) {
|
|
10
|
+
command.addCommand(cmd);
|
|
11
|
+
}
|
|
7
12
|
export default command;
|
|
@@ -44,10 +44,15 @@ export const userDelete = new Command()
|
|
|
44
44
|
const client = getClient();
|
|
45
45
|
await client.delete(userId);
|
|
46
46
|
});
|
|
47
|
+
const commands = {
|
|
48
|
+
list: userList,
|
|
49
|
+
fetch: userFetch,
|
|
50
|
+
delete: userDelete,
|
|
51
|
+
};
|
|
47
52
|
export const command = new Command()
|
|
48
53
|
.name('user')
|
|
49
|
-
.description('User tools for ChatBotKit')
|
|
50
|
-
|
|
51
|
-
.addCommand(
|
|
52
|
-
|
|
54
|
+
.description('User tools for ChatBotKit');
|
|
55
|
+
for (const cmd of Object.values(commands)) {
|
|
56
|
+
command.addCommand(cmd);
|
|
57
|
+
}
|
|
53
58
|
export default command;
|
|
@@ -44,10 +44,15 @@ export const skillsetDelete = new Command()
|
|
|
44
44
|
const client = getClient();
|
|
45
45
|
await client.delete(skillsetId);
|
|
46
46
|
});
|
|
47
|
+
const commands = {
|
|
48
|
+
list: skillsetList,
|
|
49
|
+
fetch: skillsetFetch,
|
|
50
|
+
delete: skillsetDelete,
|
|
51
|
+
};
|
|
47
52
|
export const command = new Command()
|
|
48
53
|
.name('skillset')
|
|
49
|
-
.description('Skillset tools for ChatBotKit')
|
|
50
|
-
|
|
51
|
-
.addCommand(
|
|
52
|
-
|
|
54
|
+
.description('Skillset tools for ChatBotKit');
|
|
55
|
+
for (const cmd of Object.values(commands)) {
|
|
56
|
+
command.addCommand(cmd);
|
|
57
|
+
}
|
|
53
58
|
export default command;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { getRUNAS_USERID, getSECRET } from '../../env.js';
|
|
2
|
-
import {
|
|
2
|
+
import { Spinner } from '../../spinner.js';
|
|
3
|
+
import { getToolNames, getTools } from '../../tools.js';
|
|
4
|
+
import { complete } from '@chatbotkit/agent';
|
|
5
|
+
import { ChatBotKit } from '@chatbotkit/sdk';
|
|
3
6
|
import { Command, Option } from 'commander';
|
|
4
7
|
import readline from 'readline/promises';
|
|
5
8
|
function getClient() {
|
|
6
|
-
return new
|
|
9
|
+
return new ChatBotKit({
|
|
7
10
|
secret: getSECRET(),
|
|
8
11
|
runAsUserId: getRUNAS_USERID(),
|
|
9
12
|
});
|
|
@@ -11,28 +14,50 @@ function getClient() {
|
|
|
11
14
|
export const command = new Command()
|
|
12
15
|
.name('chat')
|
|
13
16
|
.description('Start a chat session')
|
|
14
|
-
.addOption(new Option('-
|
|
15
|
-
.
|
|
17
|
+
.addOption(new Option('-b, --bot <bot>', 'Bot id'))
|
|
18
|
+
.addOption(new Option('-m, --model <model>', 'Model name'))
|
|
19
|
+
.addOption(new Option('-t, --tools <tools...>', 'Specific tools to enable').choices(getToolNames()))
|
|
20
|
+
.action(async (options) => {
|
|
16
21
|
const client = getClient();
|
|
17
22
|
const rl = readline.createInterface({
|
|
18
23
|
input: process.stdin,
|
|
19
24
|
output: process.stdout,
|
|
20
25
|
});
|
|
21
26
|
const messages = [];
|
|
27
|
+
const tools = getTools(options.tools);
|
|
28
|
+
const colors = {
|
|
29
|
+
reset: '\x1b[0m',
|
|
30
|
+
bold: '\x1b[1m',
|
|
31
|
+
cyan: '\x1b[36m',
|
|
32
|
+
green: '\x1b[32m',
|
|
33
|
+
};
|
|
22
34
|
for (;;) {
|
|
23
|
-
|
|
35
|
+
process.stdout.write('\n');
|
|
36
|
+
const user = await rl.question(`${colors.cyan}●${colors.reset} ${colors.bold}You${colors.reset}\n\n> `);
|
|
24
37
|
messages.push({ type: 'user', text: user });
|
|
25
|
-
process.stdout.write(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
process.stdout.write(`\n${colors.green}●${colors.reset} ${colors.bold}Assistant${colors.reset}\n\n `);
|
|
39
|
+
const spinner = new Spinner('');
|
|
40
|
+
spinner.start();
|
|
41
|
+
let firstToken = true;
|
|
42
|
+
for await (const { type, data } of complete({
|
|
43
|
+
client,
|
|
44
|
+
botId: options.bot,
|
|
45
|
+
model: options.model,
|
|
46
|
+
messages,
|
|
47
|
+
tools,
|
|
48
|
+
})) {
|
|
29
49
|
if (type === 'token') {
|
|
50
|
+
if (firstToken) {
|
|
51
|
+
spinner.stop();
|
|
52
|
+
firstToken = false;
|
|
53
|
+
}
|
|
30
54
|
process.stdout.write(data.token);
|
|
31
55
|
}
|
|
32
56
|
else if (type === 'result') {
|
|
33
57
|
messages.push({ type: 'bot', text: data.text });
|
|
34
58
|
}
|
|
35
59
|
}
|
|
60
|
+
spinner.stop();
|
|
36
61
|
process.stdout.write('\n');
|
|
37
62
|
}
|
|
38
63
|
});
|
package/dist/esm/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import agent from './command/agent/index.js';
|
|
1
2
|
import command from './command/api/index.js';
|
|
2
3
|
import chat from './command/chat/index.js';
|
|
3
4
|
import solution from './command/solution/index.js';
|
|
@@ -6,6 +7,7 @@ export default async function cbk(argv = process.argv) {
|
|
|
6
7
|
const program = new Command();
|
|
7
8
|
program.name('cbk').description('Command line tools for ChatBotKit');
|
|
8
9
|
program.addCommand(command);
|
|
10
|
+
program.addCommand(agent);
|
|
9
11
|
program.addCommand(chat);
|
|
10
12
|
program.addCommand(solution);
|
|
11
13
|
program.parse(argv);
|
package/dist/esm/output.js
CHANGED
|
@@ -26,10 +26,14 @@ export function print(input) {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
export function printError(error) {
|
|
29
|
+
if (error?.code === 'ABORT_ERR' || error?.name === 'AbortError') {
|
|
30
|
+
process.exit(130);
|
|
31
|
+
}
|
|
29
32
|
if (error instanceof CommandError) {
|
|
30
33
|
console.error(error.message);
|
|
31
34
|
}
|
|
32
35
|
else {
|
|
33
36
|
console.error(error);
|
|
34
37
|
}
|
|
38
|
+
process.exit(1);
|
|
35
39
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export class Spinner {
|
|
2
|
+
constructor(text?: string, options?: {
|
|
3
|
+
frames?: string[] | undefined;
|
|
4
|
+
interval?: number | undefined;
|
|
5
|
+
});
|
|
6
|
+
text: string;
|
|
7
|
+
frames: string[];
|
|
8
|
+
interval: number;
|
|
9
|
+
frameIndex: number;
|
|
10
|
+
intervalId: NodeJS.Timeout | null;
|
|
11
|
+
isSpinning: boolean;
|
|
12
|
+
start(): void;
|
|
13
|
+
stop(keepText?: boolean): void;
|
|
14
|
+
setText(text: string): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export class Spinner {
|
|
2
|
+
constructor(text = '', options = {}) {
|
|
3
|
+
this.text = text;
|
|
4
|
+
this.frames = options.frames || [
|
|
5
|
+
'⠋',
|
|
6
|
+
'⠙',
|
|
7
|
+
'⠹',
|
|
8
|
+
'⠸',
|
|
9
|
+
'⠼',
|
|
10
|
+
'⠴',
|
|
11
|
+
'⠦',
|
|
12
|
+
'⠧',
|
|
13
|
+
'⠇',
|
|
14
|
+
'⠏',
|
|
15
|
+
];
|
|
16
|
+
this.interval = options.interval || 80;
|
|
17
|
+
this.frameIndex = 0;
|
|
18
|
+
this.intervalId = null;
|
|
19
|
+
this.isSpinning = false;
|
|
20
|
+
}
|
|
21
|
+
start() {
|
|
22
|
+
if (this.isSpinning) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
this.isSpinning = true;
|
|
26
|
+
this.frameIndex = 0;
|
|
27
|
+
this.intervalId = setInterval(() => {
|
|
28
|
+
const frame = this.frames[this.frameIndex];
|
|
29
|
+
process.stdout.write(`\r${this.text}${frame} `);
|
|
30
|
+
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
31
|
+
}, this.interval);
|
|
32
|
+
}
|
|
33
|
+
stop(keepText = true) {
|
|
34
|
+
if (!this.isSpinning) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.isSpinning = false;
|
|
38
|
+
if (this.intervalId) {
|
|
39
|
+
clearInterval(this.intervalId);
|
|
40
|
+
this.intervalId = null;
|
|
41
|
+
}
|
|
42
|
+
if (keepText) {
|
|
43
|
+
process.stdout.write(`\r${this.text}`);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
process.stdout.write('\r' + ' '.repeat(this.text.length + 2) + '\r');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
setText(text) {
|
|
50
|
+
this.text = text;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function getTools(selectedTools?: Array<keyof typeof tools>): typeof tools;
|
|
2
|
+
export function getToolNames(): Array<keyof typeof tools>;
|
|
3
|
+
export const tools: Record<string, {
|
|
4
|
+
description: string;
|
|
5
|
+
input: z.ZodObject<any>;
|
|
6
|
+
handler: (input: any) => Promise<any>;
|
|
7
|
+
default?: boolean;
|
|
8
|
+
}>;
|
|
9
|
+
import { z } from 'zod';
|