@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 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.24.1 darwin-arm64 node-v22.17.0
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 TEMPLATEID`](#qcobro-agentseval-templateid)
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 TEMPLATEID`
104
+ ## `qcobro agents:eval`
102
105
 
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.
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 TEMPLATEID
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 — 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.
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:eval <templateId>
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
- /** Prints one evaluation event; returns true if it signals a failure. */
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;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;CAqBnB"}
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. For a " +
10
- "static SMS/VOICE_PRERECORDED render (no conversation), use `agents:preview` instead.";
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
- /** Prints one evaluation event; returns true if it signals a failure. */
51
- printEvent(event) {
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
- this.log(`Error: ${event.message}`);
70
- return true;
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":"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"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qcobro/ctl",
3
- "version": "1.39.3",
3
+ "version": "1.40.0",
4
4
  "description": "Command-line tool for QCobro developers, built on @qcobro/sdk.",
5
5
  "type": "module",
6
6
  "bin": {