@qcobro/ctl 1.39.3 → 1.40.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 +64 -9
- package/dist/commands/agents/eval.d.ts +6 -1
- package/dist/commands/agents/eval.d.ts.map +1 -1
- package/dist/commands/agents/eval.js +44 -15
- package/dist/commands/agents/eval.js.map +1 -1
- package/dist/resolveInputFile.d.ts +14 -0
- package/dist/resolveInputFile.d.ts.map +1 -0
- package/dist/resolveInputFile.js +24 -0
- package/dist/resolveInputFile.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ $ qcobro workspaces:login
|
|
|
24
24
|
|
|
25
25
|
<!-- toc -->
|
|
26
26
|
|
|
27
|
+
- [ctl](#ctl)
|
|
27
28
|
- [Usage](#usage)
|
|
28
29
|
- [Commands](#commands)
|
|
29
30
|
<!-- tocstop -->
|
|
@@ -37,7 +38,7 @@ $ npm install -g @qcobro/ctl
|
|
|
37
38
|
$ qcobro COMMAND
|
|
38
39
|
running command...
|
|
39
40
|
$ qcobro (--version)
|
|
40
|
-
@qcobro/ctl/1.
|
|
41
|
+
@qcobro/ctl/1.39.3 darwin-arm64 node-v22.17.0
|
|
41
42
|
$ qcobro --help [COMMAND]
|
|
42
43
|
USAGE
|
|
43
44
|
$ qcobro COMMAND
|
|
@@ -51,7 +52,9 @@ USAGE
|
|
|
51
52
|
<!-- commands -->
|
|
52
53
|
|
|
53
54
|
- [`qcobro agents:create`](#qcobro-agentscreate)
|
|
54
|
-
- [`qcobro agents:eval
|
|
55
|
+
- [`qcobro agents:eval`](#qcobro-agentseval)
|
|
56
|
+
- [`qcobro agents:preview`](#qcobro-agentspreview)
|
|
57
|
+
- [`qcobro agents:sync TEMPLATEID`](#qcobro-agentssync-templateid)
|
|
55
58
|
- [`qcobro mcp:configure`](#qcobro-mcpconfigure)
|
|
56
59
|
- [`qcobro portfolios:get ID`](#qcobro-portfoliosget-id)
|
|
57
60
|
- [`qcobro portfolios:list`](#qcobro-portfolioslist)
|
|
@@ -98,25 +101,77 @@ EXAMPLES
|
|
|
98
101
|
$ qcobro agents:create --type SMS --name "Recordatorio" --message-body "Hola {{firstName}}, tienes un saldo pendiente."
|
|
99
102
|
```
|
|
100
103
|
|
|
101
|
-
## `qcobro agents:eval
|
|
104
|
+
## `qcobro agents:eval`
|
|
102
105
|
|
|
103
|
-
|
|
106
|
+
evaluate a VOICE_AI/EMAIL/WHATSAPP agent's conversation logic — either an existing template plus a scenarios file, or a standalone YAML eval template (agent definition plus its own embedded scenarios) that is never created. Streams each turn's result as it happens, then a final pass/fail summary; exits non-zero when the run fails. Pass --json to stream the raw events as JSONL instead. For a static SMS/VOICE_PRERECORDED render (no conversation), use `agents:preview` instead.
|
|
104
107
|
|
|
105
108
|
```
|
|
106
109
|
USAGE
|
|
107
|
-
$ qcobro agents:eval
|
|
110
|
+
$ qcobro agents:eval [--template-id <value>] [--scenarios <value>] [--file <value>] [--json]
|
|
111
|
+
|
|
112
|
+
FLAGS
|
|
113
|
+
--file=<value> path to a standalone YAML eval template (agent definition + embedded scenarios)
|
|
114
|
+
--json emit each evaluation event as a JSON line (JSONL) on stdout instead of human-readable output
|
|
115
|
+
--scenarios=<value> path to a YAML file with the scenarios to run (used with --template-id)
|
|
116
|
+
--template-id=<value> an existing agent template id
|
|
117
|
+
|
|
118
|
+
DESCRIPTION
|
|
119
|
+
evaluate a VOICE_AI/EMAIL/WHATSAPP agent's conversation logic — either an existing template plus a scenarios file, or
|
|
120
|
+
a standalone YAML eval template (agent definition plus its own embedded scenarios) that is never created. Streams each
|
|
121
|
+
turn's result as it happens, then a final pass/fail summary; exits non-zero when the run fails. Pass --json to stream
|
|
122
|
+
the raw events as JSONL instead. For a static SMS/VOICE_PRERECORDED render (no conversation), use `agents:preview`
|
|
123
|
+
instead.
|
|
124
|
+
|
|
125
|
+
EXAMPLES
|
|
126
|
+
$ qcobro agents:eval --template-id <id> --scenarios scenarios.yaml
|
|
127
|
+
|
|
128
|
+
$ qcobro agents:eval --file eval-template.yaml
|
|
129
|
+
|
|
130
|
+
$ qcobro agents:eval --file eval-template.yaml --json | jq
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## `qcobro agents:preview`
|
|
134
|
+
|
|
135
|
+
render an SMS/VOICE_PRERECORDED agent template's message body or script against a sample account — no conversation, no streaming. Accepts an existing template id or a standalone YAML definition. For VOICE_AI/EMAIL/WHATSAPP, use `agents:eval` instead.
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
USAGE
|
|
139
|
+
$ qcobro agents:preview --account <value> [--template-id <value>] [--file <value>]
|
|
140
|
+
|
|
141
|
+
FLAGS
|
|
142
|
+
--account=<value> (required) path to a JSON file with the sample account fields
|
|
143
|
+
--file=<value> path to a standalone YAML SMS/VOICE_PRERECORDED definition
|
|
144
|
+
--template-id=<value> an existing agent template id
|
|
145
|
+
|
|
146
|
+
DESCRIPTION
|
|
147
|
+
render an SMS/VOICE_PRERECORDED agent template's message body or script against a sample account — no conversation, no
|
|
148
|
+
streaming. Accepts an existing template id or a standalone YAML definition. For VOICE_AI/EMAIL/WHATSAPP, use
|
|
149
|
+
`agents:eval` instead.
|
|
150
|
+
|
|
151
|
+
EXAMPLES
|
|
152
|
+
$ qcobro agents:preview --template-id <id> --account account.json
|
|
153
|
+
|
|
154
|
+
$ qcobro agents:preview --file sms-draft.yaml --account account.json
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## `qcobro agents:sync TEMPLATEID`
|
|
158
|
+
|
|
159
|
+
re-attempt an agent template's Fonoster sync and report the resulting status. This validates the template's configuration and its sync with Fonoster — it does not test conversation behavior (see `agents:eval` for that). Only VOICE_AI templates sync with Fonoster; other channel types are a no-op that leaves the template unchanged.
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
USAGE
|
|
163
|
+
$ qcobro agents:sync TEMPLATEID
|
|
108
164
|
|
|
109
165
|
ARGUMENTS
|
|
110
166
|
TEMPLATEID the agent template id
|
|
111
167
|
|
|
112
168
|
DESCRIPTION
|
|
113
169
|
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 —
|
|
115
|
-
|
|
116
|
-
leaves the template unchanged.
|
|
170
|
+
configuration and its sync with Fonoster — it does not test conversation behavior (see `agents:eval` for that). Only
|
|
171
|
+
VOICE_AI templates sync with Fonoster; other channel types are a no-op that leaves the template unchanged.
|
|
117
172
|
|
|
118
173
|
EXAMPLES
|
|
119
|
-
$ qcobro agents:
|
|
174
|
+
$ qcobro agents:sync <templateId>
|
|
120
175
|
```
|
|
121
176
|
|
|
122
177
|
## `qcobro mcp:configure`
|
|
@@ -6,10 +6,15 @@ export default class Eval extends AuthenticatedCommand<typeof Eval> {
|
|
|
6
6
|
"template-id": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
7
|
scenarios: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
8
|
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
10
|
};
|
|
10
11
|
run(): Promise<void>;
|
|
11
12
|
private buildInput;
|
|
12
|
-
/**
|
|
13
|
+
/** Resolves a `--file` / `--scenarios` path, failing the command cleanly if it is missing. */
|
|
14
|
+
private resolvePath;
|
|
15
|
+
/** Whether an event signals a failed turn / scenario / run. */
|
|
16
|
+
private failed;
|
|
17
|
+
/** Renders one evaluation event (human or JSONL); returns true if it signals a failure. */
|
|
13
18
|
private printEvent;
|
|
14
19
|
}
|
|
15
20
|
//# sourceMappingURL=eval.d.ts.map
|
|
@@ -1 +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;
|
|
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;AAGrE,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,oBAAoB,CAAC,OAAO,IAAI,CAAC;IACjE,gBAAyB,WAAW,SAMwB;IAC5D,gBAAyB,QAAQ,WAI/B;IACF,gBAAyB,KAAK;;;;;MAa5B;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAYjC,OAAO,CAAC,UAAU;IAqBlB,8FAA8F;IAC9F,OAAO,CAAC,WAAW;IAQnB,+DAA+D;IAC/D,OAAO,CAAC,MAAM;IAOd,2FAA2F;IAC3F,OAAO,CAAC,UAAU;CAqBnB"}
|
|
@@ -2,15 +2,18 @@ import { readFileSync } from "node:fs";
|
|
|
2
2
|
import { Flags } from "@oclif/core";
|
|
3
3
|
import { parse as parseYaml } from "yaml";
|
|
4
4
|
import { AuthenticatedCommand } from "../../AuthenticatedCommand.js";
|
|
5
|
+
import { resolveInputFile } from "../../resolveInputFile.js";
|
|
5
6
|
export default class Eval extends AuthenticatedCommand {
|
|
6
7
|
static description = "evaluate a VOICE_AI/EMAIL/WHATSAPP agent's conversation logic — either an existing " +
|
|
7
8
|
"template plus a scenarios file, or a standalone YAML eval template (agent definition " +
|
|
8
9
|
"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.
|
|
10
|
-
"
|
|
10
|
+
"it happens, then a final pass/fail summary; exits non-zero when the run fails. Pass " +
|
|
11
|
+
"--json to stream the raw events as JSONL instead. For a static SMS/VOICE_PRERECORDED " +
|
|
12
|
+
"render (no conversation), use `agents:preview` instead.";
|
|
11
13
|
static examples = [
|
|
12
14
|
"<%= config.bin %> <%= command.id %> --template-id <id> --scenarios scenarios.yaml",
|
|
13
|
-
"<%= config.bin %> <%= command.id %> --file eval-template.yaml"
|
|
15
|
+
"<%= config.bin %> <%= command.id %> --file eval-template.yaml",
|
|
16
|
+
"<%= config.bin %> <%= command.id %> --file eval-template.yaml --json | jq"
|
|
14
17
|
];
|
|
15
18
|
static flags = {
|
|
16
19
|
"template-id": Flags.string({ description: "an existing agent template id" }),
|
|
@@ -19,6 +22,10 @@ export default class Eval extends AuthenticatedCommand {
|
|
|
19
22
|
}),
|
|
20
23
|
file: Flags.string({
|
|
21
24
|
description: "path to a standalone YAML eval template (agent definition + embedded scenarios)"
|
|
25
|
+
}),
|
|
26
|
+
json: Flags.boolean({
|
|
27
|
+
description: "emit each evaluation event as a JSON line (JSONL) on stdout instead of human-readable output",
|
|
28
|
+
default: false
|
|
22
29
|
})
|
|
23
30
|
};
|
|
24
31
|
async run() {
|
|
@@ -26,17 +33,17 @@ export default class Eval extends AuthenticatedCommand {
|
|
|
26
33
|
const client = await this.createSdkClient();
|
|
27
34
|
let anyFailed = false;
|
|
28
35
|
for await (const event of client.agentEvaluations.evaluate(this.buildInput(flags))) {
|
|
29
|
-
anyFailed = this.printEvent(event) || anyFailed;
|
|
36
|
+
anyFailed = this.printEvent(event, flags.json) || anyFailed;
|
|
30
37
|
}
|
|
31
38
|
if (anyFailed)
|
|
32
39
|
this.exit(1);
|
|
33
40
|
}
|
|
34
41
|
buildInput(flags) {
|
|
35
42
|
if (flags.file) {
|
|
36
|
-
return { yaml: readFileSync(flags.file, "utf8") };
|
|
43
|
+
return { yaml: readFileSync(this.resolvePath(flags.file), "utf8") };
|
|
37
44
|
}
|
|
38
45
|
if (flags["template-id"] && flags.scenarios) {
|
|
39
|
-
const parsed = parseYaml(readFileSync(flags.scenarios, "utf8"));
|
|
46
|
+
const parsed = parseYaml(readFileSync(this.resolvePath(flags.scenarios), "utf8"));
|
|
40
47
|
const scenarios = Array.isArray(parsed)
|
|
41
48
|
? parsed
|
|
42
49
|
: (parsed.scenarios ?? parsed);
|
|
@@ -47,8 +54,31 @@ export default class Eval extends AuthenticatedCommand {
|
|
|
47
54
|
}
|
|
48
55
|
return this.error("Provide --file, or both --template-id and --scenarios.", { exit: 1 });
|
|
49
56
|
}
|
|
50
|
-
/**
|
|
51
|
-
|
|
57
|
+
/** Resolves a `--file` / `--scenarios` path, failing the command cleanly if it is missing. */
|
|
58
|
+
resolvePath(input) {
|
|
59
|
+
try {
|
|
60
|
+
return resolveInputFile(input);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
return this.error(err instanceof Error ? err.message : String(err), { exit: 1 });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Whether an event signals a failed turn / scenario / run. */
|
|
67
|
+
failed(event) {
|
|
68
|
+
if (event.type === "turn")
|
|
69
|
+
return event.result.passed === false;
|
|
70
|
+
if (event.type === "scenarioSummary")
|
|
71
|
+
return !event.overallPassed;
|
|
72
|
+
if (event.type === "summary")
|
|
73
|
+
return event.verdict === "fail";
|
|
74
|
+
return true; // error
|
|
75
|
+
}
|
|
76
|
+
/** Renders one evaluation event (human or JSONL); returns true if it signals a failure. */
|
|
77
|
+
printEvent(event, asJson) {
|
|
78
|
+
if (asJson) {
|
|
79
|
+
this.log(JSON.stringify(event));
|
|
80
|
+
return this.failed(event);
|
|
81
|
+
}
|
|
52
82
|
if (event.type === "turn") {
|
|
53
83
|
const verdict = event.result.passed === undefined ? "" : event.result.passed ? " ✓" : " ✗";
|
|
54
84
|
const detail = event.result.action ?? event.result.aiResponse ?? event.result.input;
|
|
@@ -56,18 +86,17 @@ export default class Eval extends AuthenticatedCommand {
|
|
|
56
86
|
if (event.result.passed === false && event.result.errorMessage) {
|
|
57
87
|
this.log(` ↳ ${event.result.errorMessage}`);
|
|
58
88
|
}
|
|
59
|
-
return event.result.passed === false;
|
|
60
89
|
}
|
|
61
|
-
if (event.type === "scenarioSummary") {
|
|
90
|
+
else if (event.type === "scenarioSummary") {
|
|
62
91
|
this.log(`[${event.scenarioRef}] scenario ${event.overallPassed ? "PASSED" : "FAILED"}`);
|
|
63
|
-
return !event.overallPassed;
|
|
64
92
|
}
|
|
65
|
-
if (event.type === "summary") {
|
|
93
|
+
else if (event.type === "summary") {
|
|
66
94
|
this.log(`Overall: ${event.verdict.toUpperCase()} (${event.scenarios.length} scenario(s))`);
|
|
67
|
-
return event.verdict === "fail";
|
|
68
95
|
}
|
|
69
|
-
|
|
70
|
-
|
|
96
|
+
else {
|
|
97
|
+
this.log(`Error: ${event.message}`);
|
|
98
|
+
}
|
|
99
|
+
return this.failed(event);
|
|
71
100
|
}
|
|
72
101
|
}
|
|
73
102
|
//# sourceMappingURL=eval.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eval.js","sourceRoot":"","sources":["../../../src/commands/agents/eval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"eval.js","sourceRoot":"","sources":["../../../src/commands/agents/eval.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a user-supplied input path (e.g. `agents:eval --file` / `--scenarios`) and
|
|
3
|
+
* asserts the file exists before anything tries to read it.
|
|
4
|
+
*
|
|
5
|
+
* - An absolute path is checked as given.
|
|
6
|
+
* - A relative path is resolved against `cwd` (i.e. treated as `./<path>`) first, so
|
|
7
|
+
* `evals/x.yaml` and `./evals/x.yaml` behave identically.
|
|
8
|
+
*
|
|
9
|
+
* Throws an `Error` whose message names the path the user typed — and, for a relative
|
|
10
|
+
* path, the absolute path it resolved to — so a typo fails loudly instead of surfacing
|
|
11
|
+
* as a bare `ENOENT` (or, on a streaming command, as no output at all).
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveInputFile(input: string, cwd?: string): string;
|
|
14
|
+
//# sourceMappingURL=resolveInputFile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveInputFile.d.ts","sourceRoot":"","sources":["../src/resolveInputFile.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,MAAM,CAUnF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { isAbsolute, resolve } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Resolves a user-supplied input path (e.g. `agents:eval --file` / `--scenarios`) and
|
|
5
|
+
* asserts the file exists before anything tries to read it.
|
|
6
|
+
*
|
|
7
|
+
* - An absolute path is checked as given.
|
|
8
|
+
* - A relative path is resolved against `cwd` (i.e. treated as `./<path>`) first, so
|
|
9
|
+
* `evals/x.yaml` and `./evals/x.yaml` behave identically.
|
|
10
|
+
*
|
|
11
|
+
* Throws an `Error` whose message names the path the user typed — and, for a relative
|
|
12
|
+
* path, the absolute path it resolved to — so a typo fails loudly instead of surfacing
|
|
13
|
+
* as a bare `ENOENT` (or, on a streaming command, as no output at all).
|
|
14
|
+
*/
|
|
15
|
+
export function resolveInputFile(input, cwd = process.cwd()) {
|
|
16
|
+
const absolute = isAbsolute(input) ? input : resolve(cwd, input);
|
|
17
|
+
if (!existsSync(absolute)) {
|
|
18
|
+
throw new Error(isAbsolute(input)
|
|
19
|
+
? `File not found: ${input}`
|
|
20
|
+
: `File not found: ${input} (resolved to ${absolute})`);
|
|
21
|
+
}
|
|
22
|
+
return absolute;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=resolveInputFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveInputFile.js","sourceRoot":"","sources":["../src/resolveInputFile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEhD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,MAAc,OAAO,CAAC,GAAG,EAAE;IACzE,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACjE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,UAAU,CAAC,KAAK,CAAC;YACf,CAAC,CAAC,mBAAmB,KAAK,EAAE;YAC5B,CAAC,CAAC,mBAAmB,KAAK,iBAAiB,QAAQ,GAAG,CACzD,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|