@acruxcoreai/mcp-server 0.2.0 → 0.3.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/CHANGELOG.md CHANGED
@@ -7,6 +7,22 @@ package follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## 0.3.0 — 2026-10-22
11
+
12
+ ### Added
13
+
14
+ - `judge_prompt` on `run_experiment` and `optimize_prompt`: the name or UUID of one of your
15
+ prompts that grades instead of the built-in judge. The optimizer also reads it.
16
+ - `get_optimize_report` returns `judgePromptVersionId`, the judge prompt version that graded
17
+ the run, or `null` for the built-in judge.
18
+ - `get_optimize_report` returns `rejectedRewrites`, why each dropped rewrite was dropped, and
19
+ its summary says how many there were.
20
+
21
+ ### Fixed
22
+
23
+ - `run_experiment` failed on every call with `judge_model is required`: it sent no judge model.
24
+ It now takes a required `judge_model`, like `optimize_prompt`.
25
+
10
26
  ## 0.2.0 — 2026-10-22
11
27
 
12
28
  ### Added
package/dist/bin.js CHANGED
@@ -826,21 +826,29 @@ var evaluationTools = [
826
826
  title: "Create and start an experiment run",
827
827
  toolset: "evaluations",
828
828
  readOnlyHint: false,
829
- description: "Create an experiment over a dataset and immediately start a run of it. The grid is every (version x model) pair you list. When `prompt` is given, a baseline cell for its production alias is added automatically unless that version is already in the grid. Returns as soon as the run is queued \u2014 the worker executes it asynchronously, so poll get_experiment_run for results. Note the judge model (gpt-4o-mini by default) must itself be registered in the gateway or every score fails.",
829
+ description: "Create an experiment over a dataset and immediately start a run of it. The grid is every (version x model) pair you list. When `prompt` is given, a baseline cell for its production alias is added automatically unless that version is already in the grid. Returns as soon as the run is queued \u2014 the worker executes it asynchronously, so poll get_experiment_run for results. `judge_model` scores every answer and must be registered in the gateway (see list_models). `judge_prompt` grades with one of your prompts instead of the built-in judge.",
830
830
  inputSchema: {
831
831
  dataset_id: import_zod2.z.string().uuid().describe("Dataset to evaluate against."),
832
832
  version_ids: import_zod2.z.array(import_zod2.z.string().uuid()).min(1).describe("Prompt-version UUIDs to sweep. At least one."),
833
833
  models: import_zod2.z.array(import_zod2.z.string().min(1)).min(1).describe("Gateway model public names to sweep."),
834
834
  prompt: import_zod2.z.string().optional().describe("Prompt name or UUID under test \u2014 enables the automatic baseline cell."),
835
835
  name: import_zod2.z.string().optional().describe("Experiment name, for the run history."),
836
- alias: import_zod2.z.string().optional().describe('Which alias the automatic baseline points at. Default "production".')
836
+ alias: import_zod2.z.string().optional().describe('Which alias the automatic baseline points at. Default "production".'),
837
+ judge_model: import_zod2.z.string().min(1).describe("Gateway model that scores every answer. Required."),
838
+ judge_prompt: import_zod2.z.string().min(1).optional().describe(
839
+ "Name or UUID of a team prompt that grades instead of the built-in judge. The run uses its production version (else its latest). Default: the built-in judge."
840
+ )
837
841
  },
838
842
  async handler(args, { client, config }) {
839
843
  const body = {
840
844
  dataset_id: args.dataset_id,
841
845
  version_ids: args.version_ids,
842
- models: args.models
846
+ models: args.models,
847
+ judge_model: args.judge_model
843
848
  };
849
+ if (args.judge_prompt !== void 0) {
850
+ body.judge_prompt_id = await resolvePromptRef(client, args.judge_prompt);
851
+ }
844
852
  if (args.name !== void 0) body.name = args.name;
845
853
  if (args.alias !== void 0) body.alias = args.alias;
846
854
  if (args.prompt !== void 0) body.prompt_id = await resolvePromptRef(client, args.prompt);
@@ -907,7 +915,7 @@ var evaluationTools = [
907
915
  title: "Start an optimizer run for a prompt",
908
916
  toolset: "evaluations",
909
917
  readOnlyHint: false,
910
- description: 'Ask the optimizer to improve a prompt against a dataset. An optimizer model drafts up to `draft_count` rewrites of the version behind `alias` (default "production"), then every rewrite and that baseline run over the dataset on each of `models`, and `judge_model` scores every answer. Returns the run id as soon as the run is queued \u2014 drafting and scoring take minutes, so poll get_optimize_report. Nothing is promoted automatically: a rewrite only ships when promote_optimize_candidate is called. The dataset\'s examples need `criteria`, or the judge has nothing to grade against. Every model named here must be registered in the gateway (see list_models).',
918
+ description: 'Ask the optimizer to improve a prompt against a dataset. An optimizer model drafts `draft_count` rewrites of the version behind `alias` (default "production"), then every rewrite and that baseline run over the dataset on each of `models`, and `judge_model` scores every answer. Returns the run id as soon as the run is queued \u2014 drafting and scoring take minutes, so poll get_optimize_report. Nothing is promoted automatically: a rewrite only ships when promote_optimize_candidate is called. The dataset\'s examples need `criteria`, or the built-in judge has nothing to grade against. `judge_prompt` grades with one of your prompts instead, and the optimizer reads it too, so the rewrites aim at that rubric. Every model named here must be registered in the gateway (see list_models).',
911
919
  inputSchema: {
912
920
  prompt: import_zod2.z.string().min(1).describe("Prompt name or UUID to improve."),
913
921
  dataset_id: import_zod2.z.string().uuid().describe("Dataset whose examples the rewrites are scored on."),
@@ -916,7 +924,10 @@ var evaluationTools = [
916
924
  optimizer_model: import_zod2.z.string().min(1).optional().describe("Gateway model that writes the rewrites. Default: the first entry of `models`."),
917
925
  draft_count: import_zod2.z.number().int().min(1).max(6).optional().describe("How many rewrites to draft, 1 to 6. Default 3."),
918
926
  alias: import_zod2.z.string().min(1).optional().describe('Alias whose version is the baseline to beat. Default "production".'),
919
- optimizer_prompt: import_zod2.z.string().optional().describe("Name or UUID of a team prompt to use as the optimizer's instructions.")
927
+ optimizer_prompt: import_zod2.z.string().optional().describe("Name or UUID of a team prompt to use as the optimizer's instructions."),
928
+ judge_prompt: import_zod2.z.string().min(1).optional().describe(
929
+ "Name or UUID of a team prompt that grades instead of the built-in judge. The run uses its production version (else its latest). Default: the built-in judge."
930
+ )
920
931
  },
921
932
  async handler(args, { client, config }) {
922
933
  const promptId = await resolvePromptRef(client, args.prompt);
@@ -931,6 +942,9 @@ var evaluationTools = [
931
942
  if (args.optimizer_prompt !== void 0) {
932
943
  body.optimizer_prompt_id = await resolvePromptRef(client, args.optimizer_prompt);
933
944
  }
945
+ if (args.judge_prompt !== void 0) {
946
+ body.judge_prompt_id = await resolvePromptRef(client, args.judge_prompt);
947
+ }
934
948
  const result = await client.post(`/prompts/${promptId}/optimize`, body);
935
949
  const warning = result.prompt_mismatch_warning ? " Warning: some dataset examples were built from a different prompt \u2014 see prompt_mismatch_warning." : "";
936
950
  return okResult(
@@ -999,12 +1013,17 @@ var evaluationTools = [
999
1013
  });
1000
1014
  const best = bestCandidate(candidates);
1001
1015
  const winners = candidates.filter((candidate) => candidate.beatsBaseline).length;
1002
- const summary = best ? `Optimize run ${run_id} succeeded. ${winners} of ${candidates.length} rewrite(s) beat the baseline. Recommended: ${best.label} (candidate_id ${best.candidateId}), ` + best.scores.map((score) => `${formatDelta(score.scoreDelta)} on ${score.model}`).join(", ") + ". Promote it with promote_optimize_candidate only if the user agrees." : `Optimize run ${run_id} succeeded, but none of its ${candidates.length} rewrite(s) beat the baseline. Nothing is worth promoting; keep the current version.`;
1016
+ const rejected = report?.optimizerRejections ?? [];
1017
+ const rejectedNote = rejected.length > 0 ? ` ${rejected.length} more rewrite(s) were dropped before scoring: ${rejected.join(" | ")}.` : "";
1018
+ const summary = (best ? `Optimize run ${run_id} succeeded. ${winners} of ${candidates.length} rewrite(s) beat the baseline. Recommended: ${best.label} (candidate_id ${best.candidateId}), ` + best.scores.map((score) => `${formatDelta(score.scoreDelta)} on ${score.model}`).join(", ") + ". Promote it with promote_optimize_candidate only if the user agrees." : `Optimize run ${run_id} succeeded, but none of its ${candidates.length} rewrite(s) beat the baseline. Nothing is worth promoting; keep the current version.`) + rejectedNote;
1003
1019
  const payload = {
1004
1020
  runId: run_id,
1005
1021
  status: run.status,
1006
1022
  judgeModel: report?.judge?.model ?? null,
1023
+ // Null means the built-in judge graded the run.
1024
+ judgePromptVersionId: report?.judge?.promptVersionId ?? null,
1007
1025
  recommended: best?.candidateId ?? null,
1026
+ rejectedRewrites: rejected,
1008
1027
  baseline: (report?.cells ?? []).filter((cell) => cell.isProductionBaseline).map((cell) => ({
1009
1028
  label: cell.variantLabel,
1010
1029
  model: cell.model,
@@ -1629,7 +1648,7 @@ function selectTools(config) {
1629
1648
  }
1630
1649
 
1631
1650
  // src/server.ts
1632
- var SERVER_VERSION = "0.2.0";
1651
+ var SERVER_VERSION = "0.3.0";
1633
1652
  function buildInstructions(toolNames, readOnly) {
1634
1653
  const parts = [
1635
1654
  `AcruxCore is an LLM-ops platform: a prompt registry, a versioned tool catalog, an AI gateway, tracing, and evaluation.