@root-signals/scorable-cli 0.12.0 → 0.14.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.
Files changed (91) hide show
  1. package/README.md +60 -0
  2. package/dist/client.d.ts +1 -0
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +1 -0
  5. package/dist/commands/auth/index.d.ts.map +1 -1
  6. package/dist/commands/auth/index.js +68 -1
  7. package/dist/commands/evaluator/create.d.ts.map +1 -1
  8. package/dist/commands/evaluator/create.js +11 -5
  9. package/dist/commands/evaluator/duplicate.d.ts.map +1 -1
  10. package/dist/commands/evaluator/duplicate.js +5 -2
  11. package/dist/commands/evaluator/execute-by-name.d.ts +2 -0
  12. package/dist/commands/evaluator/execute-by-name.d.ts.map +1 -1
  13. package/dist/commands/evaluator/execute-by-name.js +27 -2
  14. package/dist/commands/evaluator/execute.d.ts +2 -0
  15. package/dist/commands/evaluator/execute.d.ts.map +1 -1
  16. package/dist/commands/evaluator/execute.js +27 -2
  17. package/dist/commands/evaluator/export-yaml.d.ts.map +1 -1
  18. package/dist/commands/evaluator/export-yaml.js +10 -1
  19. package/dist/commands/evaluator/import-yaml.d.ts.map +1 -1
  20. package/dist/commands/evaluator/import-yaml.js +10 -1
  21. package/dist/commands/evaluator/list.d.ts.map +1 -1
  22. package/dist/commands/evaluator/list.js +5 -0
  23. package/dist/commands/evaluator/update.d.ts.map +1 -1
  24. package/dist/commands/evaluator/update.js +11 -5
  25. package/dist/commands/execution-log/list.d.ts.map +1 -1
  26. package/dist/commands/execution-log/list.js +5 -0
  27. package/dist/commands/judge/create.d.ts.map +1 -1
  28. package/dist/commands/judge/create.js +12 -5
  29. package/dist/commands/judge/duplicate.d.ts.map +1 -1
  30. package/dist/commands/judge/duplicate.js +5 -2
  31. package/dist/commands/judge/exec-openai-generic.d.ts.map +1 -1
  32. package/dist/commands/judge/exec-openai-generic.js +21 -11
  33. package/dist/commands/judge/exec-openai.d.ts.map +1 -1
  34. package/dist/commands/judge/exec-openai.js +21 -11
  35. package/dist/commands/judge/execute-by-name.d.ts +2 -0
  36. package/dist/commands/judge/execute-by-name.d.ts.map +1 -1
  37. package/dist/commands/judge/execute-by-name.js +27 -2
  38. package/dist/commands/judge/execute.d.ts +2 -0
  39. package/dist/commands/judge/execute.d.ts.map +1 -1
  40. package/dist/commands/judge/execute.js +27 -2
  41. package/dist/commands/judge/generate.d.ts.map +1 -1
  42. package/dist/commands/judge/generate.js +9 -4
  43. package/dist/commands/judge/list.d.ts.map +1 -1
  44. package/dist/commands/judge/list.js +5 -0
  45. package/dist/commands/judge/update.d.ts.map +1 -1
  46. package/dist/commands/judge/update.js +12 -5
  47. package/dist/commands/otel-filter/create.d.ts.map +1 -1
  48. package/dist/commands/otel-filter/create.js +6 -6
  49. package/dist/commands/project/create.d.ts +3 -0
  50. package/dist/commands/project/create.d.ts.map +1 -0
  51. package/dist/commands/project/create.js +31 -0
  52. package/dist/commands/project/delete.d.ts +3 -0
  53. package/dist/commands/project/delete.d.ts.map +1 -0
  54. package/dist/commands/project/delete.js +37 -0
  55. package/dist/commands/project/get.d.ts +3 -0
  56. package/dist/commands/project/get.d.ts.map +1 -0
  57. package/dist/commands/project/get.js +23 -0
  58. package/dist/commands/project/index.d.ts +3 -0
  59. package/dist/commands/project/index.d.ts.map +1 -0
  60. package/dist/commands/project/index.js +17 -0
  61. package/dist/commands/project/list.d.ts +3 -0
  62. package/dist/commands/project/list.d.ts.map +1 -0
  63. package/dist/commands/project/list.js +39 -0
  64. package/dist/commands/project/set-default.d.ts +3 -0
  65. package/dist/commands/project/set-default.d.ts.map +1 -0
  66. package/dist/commands/project/set-default.js +23 -0
  67. package/dist/commands/project/update.d.ts +3 -0
  68. package/dist/commands/project/update.d.ts.map +1 -0
  69. package/dist/commands/project/update.js +37 -0
  70. package/dist/commands/prompt-test/init.d.ts.map +1 -1
  71. package/dist/commands/prompt-test/init.js +9 -2
  72. package/dist/commands/prompt-test/run.d.ts +1 -1
  73. package/dist/commands/prompt-test/run.d.ts.map +1 -1
  74. package/dist/commands/prompt-test/run.js +9 -2
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +2 -0
  77. package/dist/lib/filter-yaml.d.ts +8 -0
  78. package/dist/lib/filter-yaml.d.ts.map +1 -1
  79. package/dist/lib/filter-yaml.js +1 -1
  80. package/dist/lib/project-id.d.ts +9 -0
  81. package/dist/lib/project-id.d.ts.map +1 -0
  82. package/dist/lib/project-id.js +23 -0
  83. package/dist/output.d.ts +2 -1
  84. package/dist/output.d.ts.map +1 -1
  85. package/dist/output.js +71 -12
  86. package/dist/types.d.ts +1 -0
  87. package/dist/types.d.ts.map +1 -1
  88. package/dist/utils.d.ts +9 -0
  89. package/dist/utils.d.ts.map +1 -1
  90. package/dist/utils.js +27 -7
  91. package/package.json +4 -4
@@ -1,6 +1,10 @@
1
1
  import ora from "ora";
2
+ import { z } from "zod";
2
3
  import { requireApiKey, getSdkClient } from "../../auth.js";
3
4
  import { printSuccess, printError, printJson, handleSdkError } from "../../output.js";
5
+ import { parseJsonArg } from "../../utils.js";
6
+ import { resolveProjectIdValue, PROJECT_ID_FLAG_DESC } from "../../lib/project-id.js";
7
+ const EvaluatorRefsSchema = z.array(z.object({ id: z.string() }).passthrough());
4
8
  export function registerCreateCommand(judge) {
5
9
  judge
6
10
  .command("create")
@@ -9,20 +13,23 @@ export function registerCreateCommand(judge) {
9
13
  .requiredOption("--intent <intent>", "The intent for the new judge")
10
14
  .option("--stage <stage>", "The stage for the new judge")
11
15
  .option("--evaluator-references <json>", 'JSON string for evaluator references. E.g., \'[{"id": "eval-id"}]\'')
16
+ .option("--project-id <uuid>", PROJECT_ID_FLAG_DESC)
12
17
  .action(async (opts) => {
13
18
  const apiKey = await requireApiKey();
14
19
  const payload = { name: opts.name, intent: opts.intent };
15
20
  if (opts.stage)
16
21
  payload.stage = opts.stage;
17
22
  if (opts.evaluatorReferences) {
18
- try {
19
- payload.evaluator_references = JSON.parse(opts.evaluatorReferences);
20
- }
21
- catch {
22
- printError("Invalid JSON format for --evaluator-references.");
23
+ const r = parseJsonArg(opts.evaluatorReferences, EvaluatorRefsSchema);
24
+ if (!r.ok) {
25
+ printError('Invalid JSON format for --evaluator-references. Expected an array of objects with an "id" string.');
23
26
  return;
24
27
  }
28
+ payload.evaluator_references = r.value;
25
29
  }
30
+ const projectId = resolveProjectIdValue(opts.projectId);
31
+ if (projectId !== undefined)
32
+ payload.projectId = projectId;
26
33
  const spinner = ora("Creating...").start();
27
34
  try {
28
35
  const client = getSdkClient(apiKey);
@@ -1 +1 @@
1
- {"version":3,"file":"duplicate.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/duplicate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAkB7D"}
1
+ {"version":3,"file":"duplicate.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/duplicate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAuB7D"}
@@ -1,16 +1,19 @@
1
1
  import ora from "ora";
2
2
  import { requireApiKey, getSdkClient } from "../../auth.js";
3
3
  import { printSuccess, printJson, handleSdkError } from "../../output.js";
4
+ import { resolveProjectIdValue, PROJECT_ID_FLAG_DESC } from "../../lib/project-id.js";
4
5
  export function registerDuplicateCommand(judge) {
5
6
  judge
6
7
  .command("duplicate <judgeId>")
7
8
  .description("Duplicate an existing judge")
8
- .action(async (judgeId) => {
9
+ .option("--project-id <uuid>", PROJECT_ID_FLAG_DESC)
10
+ .action(async (judgeId, opts) => {
9
11
  const apiKey = await requireApiKey();
10
12
  const spinner = ora("Duplicating...").start();
11
13
  try {
12
14
  const client = getSdkClient(apiKey);
13
- const result = await client.judges.duplicate(judgeId);
15
+ const projectId = resolveProjectIdValue(opts.projectId);
16
+ const result = await client.judges.duplicate(judgeId, projectId !== undefined ? { projectId } : {});
14
17
  spinner.stop();
15
18
  printSuccess(`Judge ${judgeId} duplicated successfully!`);
16
19
  printJson(result);
@@ -1 +1 @@
1
- {"version":3,"file":"exec-openai-generic.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/exec-openai-generic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CA6CrE"}
1
+ {"version":3,"file":"exec-openai-generic.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/exec-openai-generic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAwDrE"}
@@ -1,6 +1,11 @@
1
+ import { z } from "zod";
1
2
  import { requireApiKey } from "../../auth.js";
2
3
  import { printInfo, printSuccess, printError, printWarning, printJson, handleSdkError, } from "../../output.js";
4
+ import { parseJsonArg } from "../../utils.js";
5
+ import { resolveProjectIdValue, PROJECT_ID_FLAG_DESC } from "../../lib/project-id.js";
3
6
  import { apiRequest } from "../../client.js";
7
+ const MessagesSchema = z.array(z.object({ role: z.string() }).passthrough());
8
+ const ExtraBodySchema = z.record(z.string(), z.unknown());
4
9
  export function registerExecOpenaiGenericCommand(judge) {
5
10
  judge
6
11
  .command("exec-openai-generic")
@@ -8,32 +13,37 @@ export function registerExecOpenaiGenericCommand(judge) {
8
13
  .requiredOption("--model <model>", "Judge ID (or name) to use as the 'model' field")
9
14
  .requiredOption("--messages <json>", "JSON string of the messages payload")
10
15
  .option("--extra-body <json>", "Optional JSON string for extra_body parameters")
16
+ .option("--project-id <uuid>", PROJECT_ID_FLAG_DESC)
11
17
  .action(async (opts) => {
12
18
  const apiKey = await requireApiKey();
13
- let messages;
14
- try {
15
- messages = JSON.parse(opts.messages);
16
- }
17
- catch {
18
- printError("Invalid JSON for --messages. Aborting.");
19
+ const messagesResult = parseJsonArg(opts.messages, MessagesSchema);
20
+ if (!messagesResult.ok) {
21
+ printError("Invalid JSON for --messages. Expected an array of objects each with a string `role`. Aborting.");
19
22
  return;
20
23
  }
21
- const payload = { model: opts.model, messages };
24
+ const payload = {
25
+ model: opts.model,
26
+ messages: messagesResult.value,
27
+ };
22
28
  if (opts.extraBody) {
23
- try {
24
- payload["extra_body"] = JSON.parse(opts.extraBody);
29
+ const extraResult = parseJsonArg(opts.extraBody, ExtraBodySchema);
30
+ if (extraResult.ok) {
31
+ payload["extra_body"] = extraResult.value;
25
32
  }
26
- catch {
27
- printWarning("Invalid JSON for --extra-body. Skipping.");
33
+ else {
34
+ printWarning("Invalid JSON for --extra-body (expected an object). Skipping.");
28
35
  }
29
36
  }
30
37
  printInfo(`Executing a Judge using generic OpenAI endpoint. Judge ID/Name: ${opts.model}`);
31
38
  printInfo("Attempting to execute with OpenAI compatible payload:");
32
39
  printJson(payload);
40
+ const projectId = resolveProjectIdValue(opts.projectId);
41
+ const headers = projectId !== undefined ? { "X-Project-Id": projectId } : undefined;
33
42
  try {
34
43
  const result = await apiRequest("POST", "judges/openai/chat/completions", {
35
44
  payload,
36
45
  apiKey,
46
+ headers,
37
47
  });
38
48
  if (result) {
39
49
  printSuccess("OpenAI compatible execution successful!");
@@ -1 +1 @@
1
- {"version":3,"file":"exec-openai.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/exec-openai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAwD9D"}
1
+ {"version":3,"file":"exec-openai.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/exec-openai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAiE9D"}
@@ -1,6 +1,11 @@
1
+ import { z } from "zod";
1
2
  import { requireApiKey } from "../../auth.js";
2
3
  import { printInfo, printSuccess, printError, printWarning, printJson, handleSdkError, } from "../../output.js";
4
+ import { parseJsonArg } from "../../utils.js";
5
+ import { resolveProjectIdValue, PROJECT_ID_FLAG_DESC } from "../../lib/project-id.js";
3
6
  import { apiRequest } from "../../client.js";
7
+ const MessagesSchema = z.array(z.object({ role: z.string() }).passthrough());
8
+ const ExtraBodySchema = z.record(z.string(), z.unknown());
4
9
  export function registerExecOpenaiCommand(judge) {
5
10
  judge
6
11
  .command("exec-openai <judgeIdInPath>")
@@ -8,32 +13,37 @@ export function registerExecOpenaiCommand(judge) {
8
13
  .requiredOption("--model <model>", "LLM model for judge execution (e.g., gpt-5.5)")
9
14
  .requiredOption("--messages <json>", "JSON string of the messages payload")
10
15
  .option("--extra-body <json>", "Optional JSON string for extra_body parameters")
16
+ .option("--project-id <uuid>", PROJECT_ID_FLAG_DESC)
11
17
  .action(async (judgeIdInPath, opts) => {
12
18
  const apiKey = await requireApiKey();
13
- let messages;
14
- try {
15
- messages = JSON.parse(opts.messages);
16
- }
17
- catch {
18
- printError("Invalid JSON for --messages. Aborting.");
19
+ const messagesResult = parseJsonArg(opts.messages, MessagesSchema);
20
+ if (!messagesResult.ok) {
21
+ printError("Invalid JSON for --messages. Expected an array of objects each with a string `role`. Aborting.");
19
22
  return;
20
23
  }
21
- const payload = { model: opts.model, messages };
24
+ const payload = {
25
+ model: opts.model,
26
+ messages: messagesResult.value,
27
+ };
22
28
  if (opts.extraBody) {
23
- try {
24
- payload["extra_body"] = JSON.parse(opts.extraBody);
29
+ const extraResult = parseJsonArg(opts.extraBody, ExtraBodySchema);
30
+ if (extraResult.ok) {
31
+ payload["extra_body"] = extraResult.value;
25
32
  }
26
- catch {
27
- printWarning("Invalid JSON for --extra-body. Skipping.");
33
+ else {
34
+ printWarning("Invalid JSON for --extra-body (expected an object). Skipping.");
28
35
  }
29
36
  }
30
37
  printInfo(`Executing Judge ID (via path): ${judgeIdInPath} using OpenAI chat completions format.`);
31
38
  printInfo("Attempting to execute with OpenAI compatible payload:");
32
39
  printJson(payload);
40
+ const projectId = resolveProjectIdValue(opts.projectId);
41
+ const headers = projectId !== undefined ? { "X-Project-Id": projectId } : undefined;
33
42
  try {
34
43
  const result = await apiRequest("POST", `judges/${judgeIdInPath}/openai/chat/completions`, {
35
44
  payload,
36
45
  apiKey,
46
+ headers,
37
47
  });
38
48
  if (result) {
39
49
  printSuccess("OpenAI compatible execution successful!");
@@ -4,12 +4,14 @@ export declare function executeJudgeByName(judgeName: string, opts: {
4
4
  request?: string;
5
5
  response?: string;
6
6
  turns?: string;
7
+ tools?: string;
7
8
  contexts?: string;
8
9
  expectedOutput?: string;
9
10
  tag?: string[];
10
11
  userId?: string;
11
12
  sessionId?: string;
12
13
  systemPrompt?: string;
14
+ projectId?: string;
13
15
  }, readStdin?: typeof readStdinDefault): Promise<void>;
14
16
  export declare function registerExecuteByNameCommand(judge: Command): void;
15
17
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"execute-by-name.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/execute-by-name.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,iBAAe,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAIjD;AAED,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IACJ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,EACD,SAAS,0BAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CA6Df;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAkEjE"}
1
+ {"version":3,"file":"execute-by-name.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/execute-by-name.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,iBAAe,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAIjD;AAED,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IACJ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,EACD,SAAS,0BAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CA8Ef;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CA2EjE"}
@@ -1,7 +1,8 @@
1
1
  import ora from "ora";
2
2
  import { requireApiKey, getSdkClient } from "../../auth.js";
3
3
  import { printSuccess, printError, printJson, handleSdkError } from "../../output.js";
4
- import { isTurnArray, isStringArray } from "../../utils.js";
4
+ import { isTurnArray, isToolCatalog, isStringArray } from "../../utils.js";
5
+ import { resolveProjectIdValue, PROJECT_ID_FLAG_DESC } from "../../lib/project-id.js";
5
6
  async function readStdinDefault() {
6
7
  const chunks = [];
7
8
  for await (const chunk of process.stdin)
@@ -47,6 +48,20 @@ export async function executeJudgeByName(judgeName, opts, readStdin = readStdinD
47
48
  return;
48
49
  }
49
50
  }
51
+ if (opts.tools) {
52
+ try {
53
+ const parsed = JSON.parse(opts.tools);
54
+ if (!isToolCatalog(parsed)) {
55
+ printError("Invalid JSON for --tools. Expected array of tool objects.");
56
+ return;
57
+ }
58
+ payload.tools = parsed;
59
+ }
60
+ catch {
61
+ printError("Invalid JSON for --tools.");
62
+ return;
63
+ }
64
+ }
50
65
  if (opts.contexts) {
51
66
  try {
52
67
  const parsed = JSON.parse(opts.contexts);
@@ -61,6 +76,9 @@ export async function executeJudgeByName(judgeName, opts, readStdin = readStdinD
61
76
  return;
62
77
  }
63
78
  }
79
+ const projectId = resolveProjectIdValue(opts.projectId);
80
+ if (projectId !== undefined)
81
+ payload.projectId = projectId;
64
82
  const spinner = ora("Running judge...").start();
65
83
  try {
66
84
  const client = getSdkClient(apiKey);
@@ -86,7 +104,9 @@ export function registerExecuteByNameCommand(judge) {
86
104
  .option("--user-id <id>", "User identifier for tracking purposes")
87
105
  .option("--session-id <id>", "Session identifier for tracking purposes")
88
106
  .option("--system-prompt <text>", "System prompt that was used for the LLM call")
89
- .option("--turns <json>", 'JSON array of conversation turns. E.g., \'[{"role":"user","content":"Hello"}]\'')
107
+ .option("--turns <json>", 'JSON array of conversation turns. Roles: user|assistant|tool. Assistant turns may carry `tool_calls`; tool results use a `tool` role with `tool_call_id`. E.g., \'[{"role":"user","content":"Hello"}]\'')
108
+ .option("--tools <json>", "JSON array of OpenAI-style tool definitions available to the agent.")
109
+ .option("--project-id <uuid>", PROJECT_ID_FLAG_DESC)
90
110
  .addHelpText("after", `
91
111
  Examples:
92
112
  # Evaluate a customer service response
@@ -104,6 +124,11 @@ Examples:
104
124
  $ scorable judge execute-by-name "Customer Service Judge" \\
105
125
  --turns '[{"role":"user","content":"I haven\\'t received my refund and it\\'s been 10 days."},{"role":"assistant","content":"Thank you for contacting us. I will investigate this immediately and provide an update within 24 hours."}]'
106
126
 
127
+ # Tool-aware evaluation: assistant tool_calls + tool-role result + tool catalog
128
+ $ scorable judge execute-by-name "Agent Quality Judge" \\
129
+ --turns '[{"role":"user","content":"What is the weather in Paris?"},{"role":"assistant","content":null,"tool_calls":[{"id":"call_1","type":"function","function":{"name":"get_weather","arguments":"{\\"city\\":\\"Paris\\"}"}}]},{"role":"tool","tool_call_id":"call_1","content":"{\\"temp\\":12}"},{"role":"assistant","content":"It is 12C in Paris."}]' \\
130
+ --tools '[{"type":"function","function":{"name":"get_weather","description":"Get weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}}}}}]'
131
+
107
132
  # Pipe the LLM response from stdin
108
133
  $ echo "We offer a 30-day money-back guarantee on all purchases." | \\
109
134
  scorable judge execute-by-name "Custom Returns Policy Judge" --request "Do you offer refunds?"`)
@@ -4,12 +4,14 @@ export declare function executeJudge(judgeId: string, opts: {
4
4
  request?: string;
5
5
  response?: string;
6
6
  turns?: string;
7
+ tools?: string;
7
8
  contexts?: string;
8
9
  expectedOutput?: string;
9
10
  tag?: string[];
10
11
  userId?: string;
11
12
  sessionId?: string;
12
13
  systemPrompt?: string;
14
+ projectId?: string;
13
15
  }, readStdin?: typeof readStdinDefault): Promise<void>;
14
16
  export declare function registerExecuteCommand(judge: Command): void;
15
17
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/execute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,iBAAe,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAIjD;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IACJ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,EACD,SAAS,0BAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CA6Df;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAyE3D"}
1
+ {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/execute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,iBAAe,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAIjD;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IACJ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,EACD,SAAS,0BAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CA8Ef;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAkF3D"}
@@ -1,7 +1,8 @@
1
1
  import ora from "ora";
2
2
  import { requireApiKey, getSdkClient } from "../../auth.js";
3
3
  import { printSuccess, printError, printJson, handleSdkError } from "../../output.js";
4
- import { isTurnArray, isStringArray } from "../../utils.js";
4
+ import { isTurnArray, isToolCatalog, isStringArray } from "../../utils.js";
5
+ import { resolveProjectIdValue, PROJECT_ID_FLAG_DESC } from "../../lib/project-id.js";
5
6
  async function readStdinDefault() {
6
7
  const chunks = [];
7
8
  for await (const chunk of process.stdin)
@@ -47,6 +48,20 @@ export async function executeJudge(judgeId, opts, readStdin = readStdinDefault)
47
48
  return;
48
49
  }
49
50
  }
51
+ if (opts.tools) {
52
+ try {
53
+ const parsed = JSON.parse(opts.tools);
54
+ if (!isToolCatalog(parsed)) {
55
+ printError("Invalid JSON for --tools. Expected array of tool objects.");
56
+ return;
57
+ }
58
+ payload.tools = parsed;
59
+ }
60
+ catch {
61
+ printError("Invalid JSON for --tools.");
62
+ return;
63
+ }
64
+ }
50
65
  if (opts.contexts) {
51
66
  try {
52
67
  const parsed = JSON.parse(opts.contexts);
@@ -61,6 +76,9 @@ export async function executeJudge(judgeId, opts, readStdin = readStdinDefault)
61
76
  return;
62
77
  }
63
78
  }
79
+ const projectId = resolveProjectIdValue(opts.projectId);
80
+ if (projectId !== undefined)
81
+ payload.projectId = projectId;
64
82
  const spinner = ora("Running judge...").start();
65
83
  try {
66
84
  const client = getSdkClient(apiKey);
@@ -86,7 +104,9 @@ export function registerExecuteCommand(judge) {
86
104
  .option("--user-id <id>", "User identifier for tracking purposes")
87
105
  .option("--session-id <id>", "Session identifier for tracking purposes")
88
106
  .option("--system-prompt <text>", "System prompt that was used for the LLM call")
89
- .option("--turns <json>", 'JSON array of conversation turns. E.g., \'[{"role":"user","content":"Hello"}]\'')
107
+ .option("--turns <json>", 'JSON array of conversation turns. Roles: user|assistant|tool. Assistant turns may carry `tool_calls`; tool results use a `tool` role with `tool_call_id`. E.g., \'[{"role":"user","content":"Hello"}]\'')
108
+ .option("--tools <json>", "JSON array of OpenAI-style tool definitions available to the agent.")
109
+ .option("--project-id <uuid>", PROJECT_ID_FLAG_DESC)
90
110
  .addHelpText("after", `
91
111
  Examples:
92
112
  # Evaluate a customer service response about return policy
@@ -104,6 +124,11 @@ Examples:
104
124
  $ scorable judge execute <judgeId> \\
105
125
  --turns '[{"role":"user","content":"Hello, I need help with my order"},{"role":"assistant","content":"I\\'d be happy to help! What\\'s your order number?"},{"role":"user","content":"It\\'s ORDER-12345"},{"role":"assistant","content":"I found your order. It\\'s currently in transit."}]'
106
126
 
127
+ # Tool-aware evaluation: assistant tool_calls, tool-role result, and tool catalog
128
+ $ scorable judge execute <judgeId> \\
129
+ --turns '[{"role":"user","content":"What is the weather in Paris?"},{"role":"assistant","content":null,"tool_calls":[{"id":"call_1","type":"function","function":{"name":"get_weather","arguments":"{\\"city\\":\\"Paris\\"}"}}]},{"role":"tool","tool_call_id":"call_1","content":"{\\"temp\\":12}"},{"role":"assistant","content":"It is 12C in Paris."}]' \\
130
+ --tools '[{"type":"function","function":{"name":"get_weather","description":"Get weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}}}}}]'
131
+
107
132
  # With tracking metadata and tags
108
133
  $ scorable judge execute <judgeId> \\
109
134
  --request "How do I reset my password?" \\
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAepC,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CA8I5D"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAkJ5D"}
@@ -1,7 +1,10 @@
1
1
  import ora from "ora";
2
2
  import chalk from "chalk";
3
+ import { z } from "zod";
3
4
  import { requireApiKey, getSdkClient } from "../../auth.js";
4
5
  import { printSuccess, printError, printWarning, printInfo, printJson, handleSdkError, } from "../../output.js";
6
+ import { parseJsonArg } from "../../utils.js";
7
+ import { resolveProjectIdValue, PROJECT_ID_FLAG_DESC } from "../../lib/project-id.js";
5
8
  import { CliError } from "../../types.js";
6
9
  import { uploadFile } from "../file/upload.js";
7
10
  export function registerGenerateCommand(judge) {
@@ -26,6 +29,7 @@ offer to connect the guest with a human agent when uncertain."`)
26
29
  .option("--context-aware", "Enable context-aware evaluators for RAG applications (hallucination detection, context drift, etc.)", false)
27
30
  .option("--file <path>", "Path to a file (PDF, PNG, JPG) to upload and attach as context for the judge")
28
31
  .option("--file-id <id>", "ID of an already-uploaded file to use as context for the judge")
32
+ .option("--project-id <uuid>", PROJECT_ID_FLAG_DESC)
29
33
  .action(async (opts) => {
30
34
  const acceptedVisibilities = ["private", "public"];
31
35
  const visibility = opts.visibility;
@@ -40,13 +44,12 @@ offer to connect the guest with a human agent when uncertain."`)
40
44
  const apiKey = await requireApiKey();
41
45
  let extra_contexts;
42
46
  if (opts.extraContexts) {
43
- try {
44
- extra_contexts = JSON.parse(opts.extraContexts);
45
- }
46
- catch {
47
+ const r = parseJsonArg(opts.extraContexts, z.record(z.string(), z.string()));
48
+ if (!r.ok) {
47
49
  printError("Invalid --extra-contexts JSON: must be a key-value object.");
48
50
  throw new CliError(1, "Invalid extra-contexts JSON");
49
51
  }
52
+ extra_contexts = r.value;
50
53
  }
51
54
  const spinner = ora("Generating judge (this may take a moment)...").start();
52
55
  try {
@@ -56,6 +59,7 @@ offer to connect the guest with a human agent when uncertain."`)
56
59
  fileId = uploaded.id;
57
60
  }
58
61
  const client = getSdkClient(apiKey);
62
+ const projectId = resolveProjectIdValue(opts.projectId);
59
63
  const result = (await client.judges.generate({
60
64
  intent: opts.intent,
61
65
  visibility: visibility,
@@ -66,6 +70,7 @@ offer to connect the guest with a human agent when uncertain."`)
66
70
  file_id: fileId,
67
71
  extra_contexts: extra_contexts ?? null,
68
72
  enable_context_aware_evaluators: opts.contextAware || undefined,
73
+ ...(projectId !== undefined ? { projectId } : {}),
69
74
  ...(opts.reasoningEffort && {
70
75
  generating_model_params: {
71
76
  reasoning_effort: opts.reasoningEffort,
@@ -1 +1 @@
1
- {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CA4CxD"}
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAgDxD"}
@@ -1,6 +1,7 @@
1
1
  import ora from "ora";
2
2
  import { requireApiKey, getSdkClient } from "../../auth.js";
3
3
  import { printMessage, printJudgeTable, handleSdkError } from "../../output.js";
4
+ import { resolveProjectIdValue, PROJECT_ID_FLAG_DESC } from "../../lib/project-id.js";
4
5
  export function registerListCommand(judge) {
5
6
  judge
6
7
  .command("list")
@@ -10,6 +11,7 @@ export function registerListCommand(judge) {
10
11
  .option("--search <term>", "A search term to filter by")
11
12
  .option("--name <name>", "Filter by exact judge name")
12
13
  .option("--ordering <field>", "Which field to use for ordering the results")
14
+ .option("--project-id <uuid>", PROJECT_ID_FLAG_DESC)
13
15
  .action(async (opts) => {
14
16
  const apiKey = await requireApiKey();
15
17
  const params = {};
@@ -23,6 +25,9 @@ export function registerListCommand(judge) {
23
25
  params.name = opts.name;
24
26
  if (opts.ordering !== undefined)
25
27
  params.ordering = opts.ordering;
28
+ const projectId = resolveProjectIdValue(opts.projectId);
29
+ if (projectId !== undefined)
30
+ params.projectId = projectId;
26
31
  const spinner = ora("Fetching...").start();
27
32
  try {
28
33
  const client = getSdkClient(apiKey);
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAkD1D"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/commands/judge/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CA8D1D"}
@@ -1,6 +1,10 @@
1
1
  import ora from "ora";
2
+ import { z } from "zod";
2
3
  import { requireApiKey, getSdkClient } from "../../auth.js";
3
4
  import { printInfo, printSuccess, printError, printJson, handleSdkError } from "../../output.js";
5
+ import { parseJsonArg } from "../../utils.js";
6
+ import { resolveProjectIdValue, PROJECT_ID_FLAG_DESC } from "../../lib/project-id.js";
7
+ const EvaluatorRefsSchema = z.array(z.object({ id: z.string() }).passthrough());
4
8
  export function registerUpdateCommand(judge) {
5
9
  judge
6
10
  .command("update <judgeId>")
@@ -8,6 +12,7 @@ export function registerUpdateCommand(judge) {
8
12
  .option("--name <name>", "The new name for the judge")
9
13
  .option("--stage <stage>", "The new stage for the judge")
10
14
  .option("--evaluator-references <json>", 'JSON string to update evaluator references. Use "[]" to clear.')
15
+ .option("--project-id <uuid>", "Move the judge to this project (within the same organization). " + PROJECT_ID_FLAG_DESC)
11
16
  .action(async (judgeId, opts) => {
12
17
  const apiKey = await requireApiKey();
13
18
  const payload = {};
@@ -16,14 +21,16 @@ export function registerUpdateCommand(judge) {
16
21
  if (opts.stage !== undefined)
17
22
  payload.stage = opts.stage;
18
23
  if (opts.evaluatorReferences !== undefined) {
19
- try {
20
- payload.evaluator_references = JSON.parse(opts.evaluatorReferences);
21
- }
22
- catch {
23
- printError("Invalid JSON format for --evaluator-references.");
24
+ const r = parseJsonArg(opts.evaluatorReferences, EvaluatorRefsSchema);
25
+ if (!r.ok) {
26
+ printError('Invalid JSON format for --evaluator-references. Expected an array of objects with an "id" string.');
24
27
  return;
25
28
  }
29
+ payload.evaluator_references = r.value;
26
30
  }
31
+ const projectId = resolveProjectIdValue(opts.projectId);
32
+ if (projectId !== undefined)
33
+ payload.projectId = projectId;
27
34
  if (Object.keys(payload).length === 0) {
28
35
  printInfo("No update parameters provided. Aborting.");
29
36
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/otel-filter/create.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI,CA6J/D"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/otel-filter/create.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI,CA+J/D"}
@@ -3,7 +3,8 @@ import ora from "ora";
3
3
  import { requireApiKey } from "../../auth.js";
4
4
  import { apiRequest } from "../../client.js";
5
5
  import { printSuccess, printError, printJson, handleSdkError } from "../../output.js";
6
- import { loadFilterYaml } from "../../lib/filter-yaml.js";
6
+ import { loadFilterYaml, Match } from "../../lib/filter-yaml.js";
7
+ import { parseJsonArg } from "../../utils.js";
7
8
  export function registerCreateCommand(otelFilter) {
8
9
  otelFilter
9
10
  .command("create")
@@ -71,13 +72,12 @@ YAML manifest (only needed for custom extractor_rules):
71
72
  }
72
73
  let filterCriteria;
73
74
  if (opts.filterCriteria) {
74
- try {
75
- filterCriteria = JSON.parse(opts.filterCriteria);
76
- }
77
- catch {
78
- printError("Invalid JSON for --filter-criteria.");
75
+ const r = parseJsonArg(opts.filterCriteria, Match);
76
+ if (!r.ok) {
77
+ printError('Invalid JSON for --filter-criteria. Expected {"conditions":[{column,operator,value?,key?},...]}.');
79
78
  process.exit(1);
80
79
  }
80
+ filterCriteria = r.value;
81
81
  }
82
82
  let samplingRate;
83
83
  if (opts.samplingRate !== undefined) {
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function registerCreateCommand(project: Command): void;
3
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/project/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA8B5D"}
@@ -0,0 +1,31 @@
1
+ import ora from "ora";
2
+ import { requireApiKey, getSdkClient } from "../../auth.js";
3
+ import { printSuccess, printJson, handleSdkError } from "../../output.js";
4
+ export function registerCreateCommand(project) {
5
+ project
6
+ .command("create")
7
+ .description("Create a new project")
8
+ .requiredOption("--name <name>", "Project name")
9
+ .option("--description <text>", "Project description")
10
+ .option("--is-default", "Mark this project as the org default (atomically clears any previous default).", false)
11
+ .action(async (opts) => {
12
+ const apiKey = await requireApiKey();
13
+ const payload = { name: opts.name };
14
+ if (opts.description !== undefined)
15
+ payload.description = opts.description;
16
+ if (opts.isDefault)
17
+ payload.is_default = true;
18
+ const spinner = ora("Creating...").start();
19
+ try {
20
+ const client = getSdkClient(apiKey);
21
+ const result = await client.projects.create(payload);
22
+ spinner.stop();
23
+ printSuccess("Project created successfully!");
24
+ printJson(result);
25
+ }
26
+ catch (e) {
27
+ spinner.stop();
28
+ handleSdkError(e);
29
+ }
30
+ });
31
+ }
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function registerDeleteCommand(project: Command): void;
3
+ //# sourceMappingURL=delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/project/delete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoC5D"}
@@ -0,0 +1,37 @@
1
+ import ora from "ora";
2
+ import { requireApiKey, getSdkClient } from "../../auth.js";
3
+ import { printSuccess, handleSdkError } from "../../output.js";
4
+ import { CliError } from "../../types.js";
5
+ export function registerDeleteCommand(project) {
6
+ project
7
+ .command("delete <projectId>")
8
+ .description("Delete a project by its ID")
9
+ .option("--yes", "Skip confirmation prompt")
10
+ .action(async (projectId, opts) => {
11
+ const apiKey = await requireApiKey();
12
+ if (!opts.yes) {
13
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
14
+ throw new CliError(1, "Refusing to prompt for confirmation in a non-interactive environment. Pass --yes to skip the prompt.");
15
+ }
16
+ const { confirm } = await import("@inquirer/prompts");
17
+ const ok = await confirm({
18
+ message: "Are you sure you want to delete this project?",
19
+ default: false,
20
+ });
21
+ if (!ok) {
22
+ throw new CliError(1, "Aborted");
23
+ }
24
+ }
25
+ const spinner = ora("Deleting...").start();
26
+ try {
27
+ const client = getSdkClient(apiKey);
28
+ await client.projects.delete(projectId);
29
+ spinner.stop();
30
+ printSuccess(`Project ${projectId} deleted successfully.`);
31
+ }
32
+ catch (e) {
33
+ spinner.stop();
34
+ handleSdkError(e);
35
+ }
36
+ });
37
+ }