@qcobro/ctl 1.27.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/README.md +290 -0
- package/bin/dev.js +7 -0
- package/bin/run.js +9 -0
- package/dist/AuthenticatedCommand.d.ts +13 -0
- package/dist/AuthenticatedCommand.d.ts.map +1 -0
- package/dist/AuthenticatedCommand.js +32 -0
- package/dist/AuthenticatedCommand.js.map +1 -0
- package/dist/BaseCommand.d.ts +22 -0
- package/dist/BaseCommand.d.ts.map +1 -0
- package/dist/BaseCommand.js +33 -0
- package/dist/BaseCommand.js.map +1 -0
- package/dist/commands/agents/create.d.ts +25 -0
- package/dist/commands/agents/create.d.ts.map +1 -0
- package/dist/commands/agents/create.js +96 -0
- package/dist/commands/agents/create.js.map +1 -0
- package/dist/commands/agents/eval.d.ts +15 -0
- package/dist/commands/agents/eval.d.ts.map +1 -0
- package/dist/commands/agents/eval.js +70 -0
- package/dist/commands/agents/eval.js.map +1 -0
- package/dist/commands/agents/preview.d.ts +12 -0
- package/dist/commands/agents/preview.d.ts.map +1 -0
- package/dist/commands/agents/preview.js +35 -0
- package/dist/commands/agents/preview.js.map +1 -0
- package/dist/commands/agents/sync.d.ts +10 -0
- package/dist/commands/agents/sync.d.ts.map +1 -0
- package/dist/commands/agents/sync.js +39 -0
- package/dist/commands/agents/sync.js.map +1 -0
- package/dist/commands/mcp/configure.d.ts +20 -0
- package/dist/commands/mcp/configure.d.ts.map +1 -0
- package/dist/commands/mcp/configure.js +75 -0
- package/dist/commands/mcp/configure.js.map +1 -0
- package/dist/commands/portfolios/get.d.ts +10 -0
- package/dist/commands/portfolios/get.d.ts.map +1 -0
- package/dist/commands/portfolios/get.js +28 -0
- package/dist/commands/portfolios/get.js.map +1 -0
- package/dist/commands/portfolios/list.d.ts +10 -0
- package/dist/commands/portfolios/list.d.ts.map +1 -0
- package/dist/commands/portfolios/list.js +30 -0
- package/dist/commands/portfolios/list.js.map +1 -0
- package/dist/commands/portfolios/sync.d.ts +12 -0
- package/dist/commands/portfolios/sync.d.ts.map +1 -0
- package/dist/commands/portfolios/sync.js +41 -0
- package/dist/commands/portfolios/sync.js.map +1 -0
- package/dist/commands/workspaces/active.d.ts +7 -0
- package/dist/commands/workspaces/active.d.ts.map +1 -0
- package/dist/commands/workspaces/active.js +24 -0
- package/dist/commands/workspaces/active.js.map +1 -0
- package/dist/commands/workspaces/list.d.ts +7 -0
- package/dist/commands/workspaces/list.d.ts.map +1 -0
- package/dist/commands/workspaces/list.js +18 -0
- package/dist/commands/workspaces/list.js.map +1 -0
- package/dist/commands/workspaces/login.d.ts +8 -0
- package/dist/commands/workspaces/login.d.ts.map +1 -0
- package/dist/commands/workspaces/login.js +64 -0
- package/dist/commands/workspaces/login.js.map +1 -0
- package/dist/commands/workspaces/logout.d.ts +10 -0
- package/dist/commands/workspaces/logout.d.ts.map +1 -0
- package/dist/commands/workspaces/logout.js +23 -0
- package/dist/commands/workspaces/logout.js.map +1 -0
- package/dist/commands/workspaces/use.d.ts +10 -0
- package/dist/commands/workspaces/use.d.ts.map +1 -0
- package/dist/commands/workspaces/use.js +29 -0
- package/dist/commands/workspaces/use.js.map +1 -0
- package/dist/config/addWorkspace.d.ts +21 -0
- package/dist/config/addWorkspace.d.ts.map +1 -0
- package/dist/config/addWorkspace.js +27 -0
- package/dist/config/addWorkspace.js.map +1 -0
- package/dist/config/getActiveWorkspace.d.ts +4 -0
- package/dist/config/getActiveWorkspace.d.ts.map +1 -0
- package/dist/config/getActiveWorkspace.js +5 -0
- package/dist/config/getActiveWorkspace.js.map +1 -0
- package/dist/config/getConfig.d.ts +4 -0
- package/dist/config/getConfig.d.ts.map +1 -0
- package/dist/config/getConfig.js +10 -0
- package/dist/config/getConfig.js.map +1 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +9 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/removeWorkspace.d.ts +4 -0
- package/dist/config/removeWorkspace.d.ts.map +1 -0
- package/dist/config/removeWorkspace.js +5 -0
- package/dist/config/removeWorkspace.js.map +1 -0
- package/dist/config/saveConfig.d.ts +4 -0
- package/dist/config/saveConfig.d.ts.map +1 -0
- package/dist/config/saveConfig.js +10 -0
- package/dist/config/saveConfig.js.map +1 -0
- package/dist/config/schemas.d.ts +18 -0
- package/dist/config/schemas.d.ts.map +1 -0
- package/dist/config/schemas.js +22 -0
- package/dist/config/schemas.js.map +1 -0
- package/dist/config/setActiveWorkspace.d.ts +4 -0
- package/dist/config/setActiveWorkspace.d.ts.map +1 -0
- package/dist/config/setActiveWorkspace.js +8 -0
- package/dist/config/setActiveWorkspace.js.map +1 -0
- package/dist/config/types.d.ts +4 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/constants.d.ts +9 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +11 -0
- package/dist/constants.js.map +1 -0
- package/dist/mcpConfigure/paths.d.ts +9 -0
- package/dist/mcpConfigure/paths.d.ts.map +1 -0
- package/dist/mcpConfigure/paths.js +20 -0
- package/dist/mcpConfigure/paths.js.map +1 -0
- package/dist/mcpConfigure/writeClaudeConfig.d.ts +33 -0
- package/dist/mcpConfigure/writeClaudeConfig.d.ts.map +1 -0
- package/dist/mcpConfigure/writeClaudeConfig.js +44 -0
- package/dist/mcpConfigure/writeClaudeConfig.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# ctl
|
|
2
|
+
|
|
3
|
+
Command-Line for QCobro
|
|
4
|
+
|
|
5
|
+
[](https://npmjs.org/package/@qcobro/ctl)
|
|
6
|
+
[](https://github.com/fonoster/qcobro/blob/main/package.json)
|
|
7
|
+
|
|
8
|
+
Use this tool to manage your QCobro resources from the command line, without going through
|
|
9
|
+
the operator console: sync a portfolio, create an agent template, or configure an MCP client
|
|
10
|
+
like Claude Desktop to use [`@qcobro/mcp`](../mcp).
|
|
11
|
+
|
|
12
|
+
It's built on [`@qcobro/sdk`](../sdk), so every command talks to the same QCobro API the SDK
|
|
13
|
+
and the console use, with the same client-side input validation.
|
|
14
|
+
|
|
15
|
+
## Setup
|
|
16
|
+
|
|
17
|
+
Link a workspace before running any authenticated command. You'll need a workspace API key
|
|
18
|
+
(an `accessKeyId` + `accessKeySecret`) — create one from the QCobro console's API Keys page —
|
|
19
|
+
and the `accessKeyId` of the workspace that key acts in.
|
|
20
|
+
|
|
21
|
+
```sh-session
|
|
22
|
+
$ qcobro workspaces:login
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
<!-- toc -->
|
|
26
|
+
|
|
27
|
+
- [Usage](#usage)
|
|
28
|
+
- [Commands](#commands)
|
|
29
|
+
<!-- tocstop -->
|
|
30
|
+
|
|
31
|
+
# Usage
|
|
32
|
+
|
|
33
|
+
<!-- usage -->
|
|
34
|
+
|
|
35
|
+
```sh-session
|
|
36
|
+
$ npm install -g @qcobro/ctl
|
|
37
|
+
$ qcobro COMMAND
|
|
38
|
+
running command...
|
|
39
|
+
$ qcobro (--version)
|
|
40
|
+
@qcobro/ctl/1.24.1 darwin-arm64 node-v22.17.0
|
|
41
|
+
$ qcobro --help [COMMAND]
|
|
42
|
+
USAGE
|
|
43
|
+
$ qcobro COMMAND
|
|
44
|
+
...
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
<!-- usagestop -->
|
|
48
|
+
|
|
49
|
+
# Commands
|
|
50
|
+
|
|
51
|
+
<!-- commands -->
|
|
52
|
+
|
|
53
|
+
- [`qcobro agents:create`](#qcobro-agentscreate)
|
|
54
|
+
- [`qcobro agents:eval TEMPLATEID`](#qcobro-agentseval-templateid)
|
|
55
|
+
- [`qcobro mcp:configure`](#qcobro-mcpconfigure)
|
|
56
|
+
- [`qcobro portfolios:get ID`](#qcobro-portfoliosget-id)
|
|
57
|
+
- [`qcobro portfolios:list`](#qcobro-portfolioslist)
|
|
58
|
+
- [`qcobro portfolios:sync`](#qcobro-portfoliossync)
|
|
59
|
+
- [`qcobro workspaces:active`](#qcobro-workspacesactive)
|
|
60
|
+
- [`qcobro workspaces:list`](#qcobro-workspaceslist)
|
|
61
|
+
- [`qcobro workspaces:login`](#qcobro-workspaceslogin)
|
|
62
|
+
- [`qcobro workspaces:logout WORKSPACEACCESSKEYID`](#qcobro-workspaceslogout-workspaceaccesskeyid)
|
|
63
|
+
- [`qcobro workspaces:use WORKSPACEACCESSKEYID`](#qcobro-workspacesuse-workspaceaccesskeyid)
|
|
64
|
+
|
|
65
|
+
## `qcobro agents:create`
|
|
66
|
+
|
|
67
|
+
create an agent template in the active workspace
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
USAGE
|
|
71
|
+
$ qcobro agents:create --type VOICE_AI|VOICE_PRERECORDED|SMS|EMAIL|WHATSAPP --name <value> [--voice <value>]
|
|
72
|
+
[--language <value>] [--system-prompt <value>] [--first-message <value>] [--script <value>] [--fonoster-app-name
|
|
73
|
+
<value>] [--message-body <value>] [--sender-id <value>] [--subject <value>] [--max-replies <value>] [--template-name
|
|
74
|
+
<value>]
|
|
75
|
+
|
|
76
|
+
FLAGS
|
|
77
|
+
--first-message=<value> opening line (VOICE_AI, optional)
|
|
78
|
+
--fonoster-app-name=<value> Fonoster application name (voice types)
|
|
79
|
+
--language=<value> language code (voice channel types)
|
|
80
|
+
--max-replies=<value> reply cap per gestión (EMAIL, WHATSAPP)
|
|
81
|
+
--message-body=<value> message text (SMS, EMAIL)
|
|
82
|
+
--name=<value> (required) template name
|
|
83
|
+
--script=<value> full TTS script (VOICE_PRERECORDED)
|
|
84
|
+
--sender-id=<value> sender identifier (SMS, optional)
|
|
85
|
+
--subject=<value> email subject (EMAIL)
|
|
86
|
+
--system-prompt=<value> AI persona/instructions (VOICE_AI, EMAIL, WHATSAPP)
|
|
87
|
+
--template-name=<value> Meta template name (WHATSAPP)
|
|
88
|
+
--type=<option> (required) agent channel type
|
|
89
|
+
<options: VOICE_AI|VOICE_PRERECORDED|SMS|EMAIL|WHATSAPP>
|
|
90
|
+
--voice=<value> voice identifier (voice channel types)
|
|
91
|
+
|
|
92
|
+
DESCRIPTION
|
|
93
|
+
create an agent template in the active workspace
|
|
94
|
+
|
|
95
|
+
EXAMPLES
|
|
96
|
+
$ qcobro agents:create --type VOICE_AI --name "Cobranza suave" --voice sofia --system-prompt "Sé amable y directo." --language es
|
|
97
|
+
|
|
98
|
+
$ qcobro agents:create --type SMS --name "Recordatorio" --message-body "Hola {{firstName}}, tienes un saldo pendiente."
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## `qcobro agents:eval TEMPLATEID`
|
|
102
|
+
|
|
103
|
+
re-attempt an agent template's Fonoster sync and report the resulting status. This validates the template's configuration and its sync with Fonoster — QCobro has no conversational-intelligence evaluation feature today, so this does not test conversation behavior. Only VOICE_AI templates sync with Fonoster; other channel types are a no-op that leaves the template unchanged.
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
USAGE
|
|
107
|
+
$ qcobro agents:eval TEMPLATEID
|
|
108
|
+
|
|
109
|
+
ARGUMENTS
|
|
110
|
+
TEMPLATEID the agent template id
|
|
111
|
+
|
|
112
|
+
DESCRIPTION
|
|
113
|
+
re-attempt an agent template's Fonoster sync and report the resulting status. This validates the template's
|
|
114
|
+
configuration and its sync with Fonoster — QCobro has no conversational-intelligence evaluation feature today, so this
|
|
115
|
+
does not test conversation behavior. Only VOICE_AI templates sync with Fonoster; other channel types are a no-op that
|
|
116
|
+
leaves the template unchanged.
|
|
117
|
+
|
|
118
|
+
EXAMPLES
|
|
119
|
+
$ qcobro agents:eval <templateId>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## `qcobro mcp:configure`
|
|
123
|
+
|
|
124
|
+
configure an MCP client to use @qcobro/mcp
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
USAGE
|
|
128
|
+
$ qcobro mcp:configure [-c claude] [--url <value>] [--access-key-id <value>] [--access-key-secret <value>]
|
|
129
|
+
[--workspace <value>]
|
|
130
|
+
|
|
131
|
+
FLAGS
|
|
132
|
+
-c, --client=<option> [default: claude] MCP client to configure
|
|
133
|
+
<options: claude>
|
|
134
|
+
--access-key-id=<value> workspace API key id (overrides active workspace)
|
|
135
|
+
--access-key-secret=<value> workspace API key secret (overrides active workspace)
|
|
136
|
+
--url=<value> [default: https://api.qcobro.com] QCobro API base URL
|
|
137
|
+
--workspace=<value> workspace to act in, its accessKeyId (overrides active workspace)
|
|
138
|
+
|
|
139
|
+
DESCRIPTION
|
|
140
|
+
configure an MCP client to use @qcobro/mcp
|
|
141
|
+
|
|
142
|
+
EXAMPLES
|
|
143
|
+
$ qcobro mcp:configure
|
|
144
|
+
|
|
145
|
+
$ qcobro mcp:configure --client claude
|
|
146
|
+
|
|
147
|
+
$ qcobro mcp:configure --access-key-id <id> --access-key-secret <secret> --workspace <workspaceAccessKeyId>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## `qcobro portfolios:get ID`
|
|
151
|
+
|
|
152
|
+
display a single portfolio
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
USAGE
|
|
156
|
+
$ qcobro portfolios:get ID
|
|
157
|
+
|
|
158
|
+
ARGUMENTS
|
|
159
|
+
ID the portfolio id
|
|
160
|
+
|
|
161
|
+
DESCRIPTION
|
|
162
|
+
display a single portfolio
|
|
163
|
+
|
|
164
|
+
EXAMPLES
|
|
165
|
+
$ qcobro portfolios:get <id>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## `qcobro portfolios:list`
|
|
169
|
+
|
|
170
|
+
display the active workspace's portfolios
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
USAGE
|
|
174
|
+
$ qcobro portfolios:list [--include-archived]
|
|
175
|
+
|
|
176
|
+
FLAGS
|
|
177
|
+
--include-archived include archived portfolios
|
|
178
|
+
|
|
179
|
+
DESCRIPTION
|
|
180
|
+
display the active workspace's portfolios
|
|
181
|
+
|
|
182
|
+
EXAMPLES
|
|
183
|
+
$ qcobro portfolios:list
|
|
184
|
+
|
|
185
|
+
$ qcobro portfolios:list --include-archived
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## `qcobro portfolios:sync`
|
|
189
|
+
|
|
190
|
+
synchronize a batch of account rows into a portfolio, from a JSON file
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
USAGE
|
|
194
|
+
$ qcobro portfolios:sync --portfolio-id <value> --file <value> [--mode APPEND_ONLY|UPDATE_EXISTING|REPLACE]
|
|
195
|
+
|
|
196
|
+
FLAGS
|
|
197
|
+
--file=<value> (required) path to a JSON file containing an array of account rows
|
|
198
|
+
--mode=<option> [default: APPEND_ONLY] merge strategy
|
|
199
|
+
<options: APPEND_ONLY|UPDATE_EXISTING|REPLACE>
|
|
200
|
+
--portfolio-id=<value> (required) the portfolio id
|
|
201
|
+
|
|
202
|
+
DESCRIPTION
|
|
203
|
+
synchronize a batch of account rows into a portfolio, from a JSON file
|
|
204
|
+
|
|
205
|
+
EXAMPLES
|
|
206
|
+
$ qcobro portfolios:sync --portfolio-id <id> --file rows.json --mode APPEND_ONLY
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## `qcobro workspaces:active`
|
|
210
|
+
|
|
211
|
+
display the active QCobro workspace
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
USAGE
|
|
215
|
+
$ qcobro workspaces:active
|
|
216
|
+
|
|
217
|
+
DESCRIPTION
|
|
218
|
+
display the active QCobro workspace
|
|
219
|
+
|
|
220
|
+
EXAMPLES
|
|
221
|
+
$ qcobro workspaces:active
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## `qcobro workspaces:list`
|
|
225
|
+
|
|
226
|
+
display all linked QCobro workspaces
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
USAGE
|
|
230
|
+
$ qcobro workspaces:list
|
|
231
|
+
|
|
232
|
+
DESCRIPTION
|
|
233
|
+
display all linked QCobro workspaces
|
|
234
|
+
|
|
235
|
+
EXAMPLES
|
|
236
|
+
$ qcobro workspaces:list
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## `qcobro workspaces:login`
|
|
240
|
+
|
|
241
|
+
link a QCobro workspace to the local environment
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
USAGE
|
|
245
|
+
$ qcobro workspaces:login
|
|
246
|
+
|
|
247
|
+
DESCRIPTION
|
|
248
|
+
link a QCobro workspace to the local environment
|
|
249
|
+
|
|
250
|
+
EXAMPLES
|
|
251
|
+
$ qcobro workspaces:login
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## `qcobro workspaces:logout WORKSPACEACCESSKEYID`
|
|
255
|
+
|
|
256
|
+
unlink a QCobro workspace from the local environment
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
USAGE
|
|
260
|
+
$ qcobro workspaces:logout WORKSPACEACCESSKEYID
|
|
261
|
+
|
|
262
|
+
ARGUMENTS
|
|
263
|
+
WORKSPACEACCESSKEYID the workspace to unlink (its accessKeyId)
|
|
264
|
+
|
|
265
|
+
DESCRIPTION
|
|
266
|
+
unlink a QCobro workspace from the local environment
|
|
267
|
+
|
|
268
|
+
EXAMPLES
|
|
269
|
+
$ qcobro workspaces:logout WO6ueex0qan9ojhf820wgiae3qi5luy08y
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## `qcobro workspaces:use WORKSPACEACCESSKEYID`
|
|
273
|
+
|
|
274
|
+
set a linked workspace as the active one
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
USAGE
|
|
278
|
+
$ qcobro workspaces:use WORKSPACEACCESSKEYID
|
|
279
|
+
|
|
280
|
+
ARGUMENTS
|
|
281
|
+
WORKSPACEACCESSKEYID the workspace to activate (its accessKeyId)
|
|
282
|
+
|
|
283
|
+
DESCRIPTION
|
|
284
|
+
set a linked workspace as the active one
|
|
285
|
+
|
|
286
|
+
EXAMPLES
|
|
287
|
+
$ qcobro workspaces:use WO6ueex0qan9ojhf820wgiae3qi5luy08y
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
<!-- commandsstop -->
|
package/bin/dev.js
ADDED
package/bin/run.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// The following code suppresses the warning about the punycode deprecated module.
|
|
4
|
+
// This is a temporary workaround until this get's fixed upstream.
|
|
5
|
+
process.removeAllListeners("warning");
|
|
6
|
+
process.on("warning", () => {});
|
|
7
|
+
|
|
8
|
+
const { execute } = await import("@oclif/core");
|
|
9
|
+
await execute({ dir: import.meta.url });
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
import { Client } from "@qcobro/sdk";
|
|
3
|
+
import { BaseCommand } from "./BaseCommand.js";
|
|
4
|
+
/**
|
|
5
|
+
* Base class for commands that need an authenticated `@qcobro/sdk` `Client`.
|
|
6
|
+
* Constructs the client from the active workspace's stored credentials, the
|
|
7
|
+
* same way `@qcobro/mcp`'s `createClient` util does (`loginWithApiKey` then
|
|
8
|
+
* `useWorkspace`) — see `mods/mcp/src/utils/createClient.ts`.
|
|
9
|
+
*/
|
|
10
|
+
export declare abstract class AuthenticatedCommand<T extends typeof Command> extends BaseCommand<T> {
|
|
11
|
+
protected createSdkClient(): Promise<Client>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=AuthenticatedCommand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthenticatedCommand.d.ts","sourceRoot":"","sources":["../src/AuthenticatedCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAI/C;;;;;GAKG;AACH,8BAAsB,oBAAoB,CAAC,CAAC,SAAS,OAAO,OAAO,CAAE,SAAQ,WAAW,CAAC,CAAC,CAAC;cACzE,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;CAyBnD"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Client } from "@qcobro/sdk";
|
|
2
|
+
import { BaseCommand } from "./BaseCommand.js";
|
|
3
|
+
import { getActiveWorkspace, getConfig } from "./config/index.js";
|
|
4
|
+
import { CONFIG_FILE } from "./constants.js";
|
|
5
|
+
/**
|
|
6
|
+
* Base class for commands that need an authenticated `@qcobro/sdk` `Client`.
|
|
7
|
+
* Constructs the client from the active workspace's stored credentials, the
|
|
8
|
+
* same way `@qcobro/mcp`'s `createClient` util does (`loginWithApiKey` then
|
|
9
|
+
* `useWorkspace`) — see `mods/mcp/src/utils/createClient.ts`.
|
|
10
|
+
*/
|
|
11
|
+
export class AuthenticatedCommand extends BaseCommand {
|
|
12
|
+
async createSdkClient() {
|
|
13
|
+
const workspaces = getConfig(CONFIG_FILE);
|
|
14
|
+
const activeWorkspace = getActiveWorkspace(workspaces);
|
|
15
|
+
if (!activeWorkspace) {
|
|
16
|
+
this.error("No active workspace found. Run `qcobro workspaces:login` first.", { exit: 1 });
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const client = new Client({ endpoint: activeWorkspace.endpoint });
|
|
20
|
+
await client.loginWithApiKey({
|
|
21
|
+
accessKeyId: activeWorkspace.accessKeyId,
|
|
22
|
+
accessKeySecret: activeWorkspace.accessKeySecret
|
|
23
|
+
});
|
|
24
|
+
client.useWorkspace(activeWorkspace.workspaceAccessKeyId);
|
|
25
|
+
return client;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return this.error("Failed to initialize the SDK client. Try `qcobro workspaces:login` again.", { exit: 1 });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=AuthenticatedCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthenticatedCommand.js","sourceRoot":"","sources":["../src/AuthenticatedCommand.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,OAAgB,oBAA+C,SAAQ,WAAc;IAC/E,KAAK,CAAC,eAAe;QAC7B,MAAM,UAAU,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QAC1C,MAAM,eAAe,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAEvD,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,IAAI,CAAC,KAAK,CAAC,iEAAiE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7F,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,QAAQ,EAAE,eAAe,CAAC,QAAQ,EAAE,CAAC,CAAC;YAElE,MAAM,MAAM,CAAC,eAAe,CAAC;gBAC3B,WAAW,EAAE,eAAe,CAAC,WAAW;gBACxC,eAAe,EAAE,eAAe,CAAC,eAAe;aACjD,CAAC,CAAC;YACH,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,oBAAoB,CAAC,CAAC;YAE1D,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,KAAK,CACf,2EAA2E,EAC3E,EAAE,IAAI,EAAE,CAAC,EAAE,CACZ,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Command, Interfaces } from "@oclif/core";
|
|
2
|
+
export type Args<T extends typeof Command> = Interfaces.InferredArgs<T["args"]>;
|
|
3
|
+
/**
|
|
4
|
+
* Base class every `@qcobro/ctl` command extends. Provides shared flag
|
|
5
|
+
* parsing (`baseFlags`, inherited by every command via `Flags<T>`) and a
|
|
6
|
+
* single place to hook error handling, mirroring `@fonoster/ctl`'s
|
|
7
|
+
* `BaseCommand`. QCobro's SDK talks tRPC over HTTPS with no insecure-channel
|
|
8
|
+
* concept, so — unlike Fonoster's version — no `--insecure` flag is defined
|
|
9
|
+
* here.
|
|
10
|
+
*/
|
|
11
|
+
export declare abstract class BaseCommand<T extends typeof Command> extends Command {
|
|
12
|
+
static readonly baseFlags: {};
|
|
13
|
+
protected flags: Flags<T>;
|
|
14
|
+
protected args: Args<T>;
|
|
15
|
+
init(): Promise<void>;
|
|
16
|
+
protected catch(err: Error & {
|
|
17
|
+
exitCode?: number;
|
|
18
|
+
}): Promise<unknown>;
|
|
19
|
+
protected finally(err: Error | undefined): Promise<unknown>;
|
|
20
|
+
}
|
|
21
|
+
export type Flags<T extends typeof Command> = Interfaces.InferredFlags<(typeof BaseCommand)["baseFlags"] & T["flags"]>;
|
|
22
|
+
//# sourceMappingURL=BaseCommand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseCommand.d.ts","sourceRoot":"","sources":["../src/BaseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,MAAM,IAAI,CAAC,CAAC,SAAS,OAAO,OAAO,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAEhF;;;;;;;GAOG;AACH,8BAAsB,WAAW,CAAC,CAAC,SAAS,OAAO,OAAO,CAAE,SAAQ,OAAO;IACzE,MAAM,CAAC,QAAQ,CAAC,SAAS,KAAM;IAE/B,SAAS,CAAC,KAAK,EAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,SAAS,CAAC,IAAI,EAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAEZ,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;cAalB,KAAK,CAAC,GAAG,EAAE,KAAK,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;cAI3D,OAAO,CAAC,GAAG,EAAE,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;CAGlE;AAED,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,OAAO,OAAO,IAAI,UAAU,CAAC,aAAa,CACpE,CAAC,OAAO,WAAW,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAC/C,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
/**
|
|
3
|
+
* Base class every `@qcobro/ctl` command extends. Provides shared flag
|
|
4
|
+
* parsing (`baseFlags`, inherited by every command via `Flags<T>`) and a
|
|
5
|
+
* single place to hook error handling, mirroring `@fonoster/ctl`'s
|
|
6
|
+
* `BaseCommand`. QCobro's SDK talks tRPC over HTTPS with no insecure-channel
|
|
7
|
+
* concept, so — unlike Fonoster's version — no `--insecure` flag is defined
|
|
8
|
+
* here.
|
|
9
|
+
*/
|
|
10
|
+
export class BaseCommand extends Command {
|
|
11
|
+
static baseFlags = {};
|
|
12
|
+
flags;
|
|
13
|
+
args;
|
|
14
|
+
async init() {
|
|
15
|
+
await super.init();
|
|
16
|
+
const { args, flags } = await this.parse({
|
|
17
|
+
flags: this.ctor.flags,
|
|
18
|
+
baseFlags: super.ctor.baseFlags,
|
|
19
|
+
enableJsonFlag: this.ctor.enableJsonFlag,
|
|
20
|
+
args: this.ctor.args,
|
|
21
|
+
strict: this.ctor.strict
|
|
22
|
+
});
|
|
23
|
+
this.flags = flags;
|
|
24
|
+
this.args = args;
|
|
25
|
+
}
|
|
26
|
+
async catch(err) {
|
|
27
|
+
return super.catch(err);
|
|
28
|
+
}
|
|
29
|
+
async finally(err) {
|
|
30
|
+
return super.finally(err);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=BaseCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseCommand.js","sourceRoot":"","sources":["../src/BaseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAc,MAAM,aAAa,CAAC;AAIlD;;;;;;;GAOG;AACH,MAAM,OAAgB,WAAsC,SAAQ,OAAO;IACzE,MAAM,CAAU,SAAS,GAAG,EAAE,CAAC;IAErB,KAAK,CAAY;IACjB,IAAI,CAAW;IAElB,KAAK,CAAC,IAAI;QACf,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC;YACvC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK;YACtB,SAAS,EAAG,KAAK,CAAC,IAA2B,CAAC,SAAS;YACvD,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc;YACxC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI;YACpB,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;SACzB,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,GAAG,KAAiB,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAe,CAAC;IAC9B,CAAC;IAES,KAAK,CAAC,KAAK,CAAC,GAAkC;QACtD,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAES,KAAK,CAAC,OAAO,CAAC,GAAsB;QAC5C,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Interfaces } from "@oclif/core";
|
|
2
|
+
import { AuthenticatedCommand } from "../../AuthenticatedCommand.js";
|
|
3
|
+
export default class Create extends AuthenticatedCommand<typeof Create> {
|
|
4
|
+
static readonly description = "create an agent template in the active workspace";
|
|
5
|
+
static readonly examples: string[];
|
|
6
|
+
static readonly flags: {
|
|
7
|
+
type: Interfaces.OptionFlag<string, Interfaces.CustomOptions>;
|
|
8
|
+
name: Interfaces.OptionFlag<string, Interfaces.CustomOptions>;
|
|
9
|
+
voice: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
10
|
+
language: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
11
|
+
"system-prompt": Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
12
|
+
"first-message": Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
13
|
+
script: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
14
|
+
"fonoster-app-name": Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
15
|
+
"message-body": Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
16
|
+
"sender-id": Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
17
|
+
subject: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
18
|
+
"max-replies": Interfaces.OptionFlag<number | undefined, Interfaces.CustomOptions>;
|
|
19
|
+
"template-name": Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
|
|
20
|
+
};
|
|
21
|
+
run(): Promise<void>;
|
|
22
|
+
private buildPayload;
|
|
23
|
+
private required;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/agents/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,UAAU,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,oBAAoB,CAAC,OAAO,MAAM,CAAC;IACrE,gBAAyB,WAAW,sDAAsD;IAC1F,gBAAyB,QAAQ,WAG/B;IACF,gBAAyB,KAAK;;;;;;;;;;;;;;MAsB5B;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAUjC,OAAO,CAAC,YAAY;IAuDpB,OAAO,CAAC,QAAQ;CAIjB"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Flags } from "@oclif/core";
|
|
2
|
+
import { AuthenticatedCommand } from "../../AuthenticatedCommand.js";
|
|
3
|
+
export default class Create extends AuthenticatedCommand {
|
|
4
|
+
static description = "create an agent template in the active workspace";
|
|
5
|
+
static examples = [
|
|
6
|
+
'<%= config.bin %> <%= command.id %> --type VOICE_AI --name "Cobranza suave" --voice sofia --system-prompt "Sé amable y directo." --language es',
|
|
7
|
+
'<%= config.bin %> <%= command.id %> --type SMS --name "Recordatorio" --message-body "Hola {{firstName}}, tienes un saldo pendiente."'
|
|
8
|
+
];
|
|
9
|
+
static flags = {
|
|
10
|
+
type: Flags.string({
|
|
11
|
+
description: "agent channel type",
|
|
12
|
+
options: ["VOICE_AI", "VOICE_PRERECORDED", "SMS", "EMAIL", "WHATSAPP"],
|
|
13
|
+
required: true
|
|
14
|
+
}),
|
|
15
|
+
name: Flags.string({ description: "template name", required: true }),
|
|
16
|
+
// Voice (VOICE_AI, VOICE_PRERECORDED)
|
|
17
|
+
voice: Flags.string({ description: "voice identifier (voice channel types)" }),
|
|
18
|
+
language: Flags.string({ description: "language code (voice channel types)" }),
|
|
19
|
+
"system-prompt": Flags.string({
|
|
20
|
+
description: "AI persona/instructions (VOICE_AI, EMAIL, WHATSAPP)"
|
|
21
|
+
}),
|
|
22
|
+
"first-message": Flags.string({ description: "opening line (VOICE_AI, optional)" }),
|
|
23
|
+
script: Flags.string({ description: "full TTS script (VOICE_PRERECORDED)" }),
|
|
24
|
+
"fonoster-app-name": Flags.string({ description: "Fonoster application name (voice types)" }),
|
|
25
|
+
// Text (SMS, EMAIL, WHATSAPP)
|
|
26
|
+
"message-body": Flags.string({ description: "message text (SMS, EMAIL)" }),
|
|
27
|
+
"sender-id": Flags.string({ description: "sender identifier (SMS, optional)" }),
|
|
28
|
+
subject: Flags.string({ description: "email subject (EMAIL)" }),
|
|
29
|
+
"max-replies": Flags.integer({ description: "reply cap per gestión (EMAIL, WHATSAPP)" }),
|
|
30
|
+
"template-name": Flags.string({ description: "Meta template name (WHATSAPP)" })
|
|
31
|
+
};
|
|
32
|
+
async run() {
|
|
33
|
+
const { flags } = await this.parse(Create);
|
|
34
|
+
const client = await this.createSdkClient();
|
|
35
|
+
const payload = this.buildPayload(flags);
|
|
36
|
+
const created = await client.agentTemplates.create(payload);
|
|
37
|
+
this.log(`Created agent template ${created.id} (${created.type}) "${created.name}".`);
|
|
38
|
+
}
|
|
39
|
+
buildPayload(flags) {
|
|
40
|
+
const base = { name: flags.name };
|
|
41
|
+
switch (flags.type) {
|
|
42
|
+
case "VOICE_AI":
|
|
43
|
+
return {
|
|
44
|
+
...base,
|
|
45
|
+
type: "VOICE_AI",
|
|
46
|
+
voice: this.required(flags.voice, "--voice"),
|
|
47
|
+
systemPrompt: this.required(flags["system-prompt"], "--system-prompt"),
|
|
48
|
+
firstMessage: flags["first-message"],
|
|
49
|
+
language: this.required(flags.language, "--language"),
|
|
50
|
+
fonosterAppName: flags["fonoster-app-name"]
|
|
51
|
+
};
|
|
52
|
+
case "VOICE_PRERECORDED":
|
|
53
|
+
return {
|
|
54
|
+
...base,
|
|
55
|
+
type: "VOICE_PRERECORDED",
|
|
56
|
+
voice: this.required(flags.voice, "--voice"),
|
|
57
|
+
script: this.required(flags.script, "--script"),
|
|
58
|
+
language: this.required(flags.language, "--language"),
|
|
59
|
+
fonosterAppName: flags["fonoster-app-name"]
|
|
60
|
+
};
|
|
61
|
+
case "SMS":
|
|
62
|
+
return {
|
|
63
|
+
...base,
|
|
64
|
+
type: "SMS",
|
|
65
|
+
messageBody: this.required(flags["message-body"], "--message-body"),
|
|
66
|
+
senderId: flags["sender-id"]
|
|
67
|
+
};
|
|
68
|
+
case "EMAIL":
|
|
69
|
+
return {
|
|
70
|
+
...base,
|
|
71
|
+
type: "EMAIL",
|
|
72
|
+
subject: this.required(flags.subject, "--subject"),
|
|
73
|
+
messageBody: this.required(flags["message-body"], "--message-body"),
|
|
74
|
+
systemPrompt: this.required(flags["system-prompt"], "--system-prompt"),
|
|
75
|
+
maxReplies: flags["max-replies"]
|
|
76
|
+
};
|
|
77
|
+
case "WHATSAPP":
|
|
78
|
+
return {
|
|
79
|
+
...base,
|
|
80
|
+
type: "WHATSAPP",
|
|
81
|
+
templateName: this.required(flags["template-name"], "--template-name"),
|
|
82
|
+
messageBody: this.required(flags["message-body"], "--message-body"),
|
|
83
|
+
systemPrompt: this.required(flags["system-prompt"], "--system-prompt"),
|
|
84
|
+
maxReplies: flags["max-replies"]
|
|
85
|
+
};
|
|
86
|
+
default:
|
|
87
|
+
return this.error(`Unknown agent type: ${flags.type}`, { exit: 1 });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
required(value, flagName) {
|
|
91
|
+
if (!value)
|
|
92
|
+
this.error(`Missing required flag ${flagName} for this agent type.`, { exit: 1 });
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/agents/create.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AuthenticatedCommand } from "../../AuthenticatedCommand.js";
|
|
2
|
+
export default class Eval extends AuthenticatedCommand<typeof Eval> {
|
|
3
|
+
static readonly description: string;
|
|
4
|
+
static readonly examples: string[];
|
|
5
|
+
static readonly flags: {
|
|
6
|
+
"template-id": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
scenarios: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
private buildInput;
|
|
12
|
+
/** Prints one evaluation event; returns true if it signals a failure. */
|
|
13
|
+
private printEvent;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=eval.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval.d.ts","sourceRoot":"","sources":["../../../src/commands/agents/eval.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,oBAAoB,CAAC,OAAO,IAAI,CAAC;IACjE,gBAAyB,WAAW,SAKqD;IACzF,gBAAyB,QAAQ,WAG/B;IACF,gBAAyB,KAAK;;;;MAQ5B;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAYjC,OAAO,CAAC,UAAU;IAqBlB,yEAAyE;IACzE,OAAO,CAAC,UAAU;CAkBnB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { Flags } from "@oclif/core";
|
|
3
|
+
import { parse as parseYaml } from "yaml";
|
|
4
|
+
import { AuthenticatedCommand } from "../../AuthenticatedCommand.js";
|
|
5
|
+
export default class Eval extends AuthenticatedCommand {
|
|
6
|
+
static description = "evaluate a VOICE_AI/EMAIL/WHATSAPP agent's conversation logic — either an existing " +
|
|
7
|
+
"template plus a scenarios file, or a standalone YAML eval template (agent definition " +
|
|
8
|
+
"plus its own embedded scenarios) that is never created. Streams each turn's result as " +
|
|
9
|
+
"it happens, then a final pass/fail summary; exits non-zero when the run fails. For a " +
|
|
10
|
+
"static SMS/VOICE_PRERECORDED render (no conversation), use `agents:preview` instead.";
|
|
11
|
+
static examples = [
|
|
12
|
+
"<%= config.bin %> <%= command.id %> --template-id <id> --scenarios scenarios.yaml",
|
|
13
|
+
"<%= config.bin %> <%= command.id %> --file eval-template.yaml"
|
|
14
|
+
];
|
|
15
|
+
static flags = {
|
|
16
|
+
"template-id": Flags.string({ description: "an existing agent template id" }),
|
|
17
|
+
scenarios: Flags.string({
|
|
18
|
+
description: "path to a YAML file with the scenarios to run (used with --template-id)"
|
|
19
|
+
}),
|
|
20
|
+
file: Flags.string({
|
|
21
|
+
description: "path to a standalone YAML eval template (agent definition + embedded scenarios)"
|
|
22
|
+
})
|
|
23
|
+
};
|
|
24
|
+
async run() {
|
|
25
|
+
const { flags } = await this.parse(Eval);
|
|
26
|
+
const client = await this.createSdkClient();
|
|
27
|
+
let anyFailed = false;
|
|
28
|
+
for await (const event of client.agentEvaluations.evaluate(this.buildInput(flags))) {
|
|
29
|
+
anyFailed = this.printEvent(event) || anyFailed;
|
|
30
|
+
}
|
|
31
|
+
if (anyFailed)
|
|
32
|
+
this.exit(1);
|
|
33
|
+
}
|
|
34
|
+
buildInput(flags) {
|
|
35
|
+
if (flags.file) {
|
|
36
|
+
return { yaml: readFileSync(flags.file, "utf8") };
|
|
37
|
+
}
|
|
38
|
+
if (flags["template-id"] && flags.scenarios) {
|
|
39
|
+
const parsed = parseYaml(readFileSync(flags.scenarios, "utf8"));
|
|
40
|
+
const scenarios = Array.isArray(parsed)
|
|
41
|
+
? parsed
|
|
42
|
+
: (parsed.scenarios ?? parsed);
|
|
43
|
+
return {
|
|
44
|
+
agentTemplateId: flags["template-id"],
|
|
45
|
+
scenarios: scenarios
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return this.error("Provide --file, or both --template-id and --scenarios.", { exit: 1 });
|
|
49
|
+
}
|
|
50
|
+
/** Prints one evaluation event; returns true if it signals a failure. */
|
|
51
|
+
printEvent(event) {
|
|
52
|
+
if (event.type === "turn") {
|
|
53
|
+
const verdict = event.result.passed === undefined ? "" : event.result.passed ? " ✓" : " ✗";
|
|
54
|
+
const detail = event.result.action ?? event.result.aiResponse ?? event.result.input;
|
|
55
|
+
this.log(`[${event.scenarioRef}] turn ${event.result.turnIndex}: ${detail}${verdict}`);
|
|
56
|
+
return event.result.passed === false;
|
|
57
|
+
}
|
|
58
|
+
if (event.type === "scenarioSummary") {
|
|
59
|
+
this.log(`[${event.scenarioRef}] scenario ${event.overallPassed ? "PASSED" : "FAILED"}`);
|
|
60
|
+
return !event.overallPassed;
|
|
61
|
+
}
|
|
62
|
+
if (event.type === "summary") {
|
|
63
|
+
this.log(`Overall: ${event.verdict.toUpperCase()} (${event.scenarios.length} scenario(s))`);
|
|
64
|
+
return event.verdict === "fail";
|
|
65
|
+
}
|
|
66
|
+
this.log(`Error: ${event.message}`);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=eval.js.map
|