@unotest/judge 0.24.0 → 0.25.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/dist/cli.js CHANGED
@@ -1,11 +1,15 @@
1
1
  import {
2
+ ConsoleLogger,
3
+ createAuthProbe,
2
4
  createJudgeService,
3
5
  resolveJudgeServerEnv,
4
6
  resolveJudgeServiceEnv,
7
+ resolveLogLevel,
5
8
  startJudgeServer
6
- } from "./chunk-74FL5RWE.js";
9
+ } from "./chunk-ADU4QPCJ.js";
7
10
 
8
11
  // src/cli.ts
12
+ import { JUDGE_ENV } from "@unotest/protocol";
9
13
  async function main(argv = process.argv.slice(2)) {
10
14
  if (argv.includes("--help") || argv.includes("-h")) {
11
15
  printHelp();
@@ -21,12 +25,46 @@ async function main(argv = process.argv.slice(2)) {
21
25
  }
22
26
  const serviceEnv = resolveJudgeServiceEnv(process.env);
23
27
  const serverEnv = resolveJudgeServerEnv(process.env);
24
- const started = await startJudgeServer(createJudgeService(serviceEnv), serverEnv);
25
- console.log(
28
+ const logger = new ConsoleLogger(resolveLogLevel(process.env) ?? "info");
29
+ if (serviceEnv.votes > 1 && process.env[JUDGE_ENV.retries]) {
30
+ logger.warn(
31
+ `${JUDGE_ENV.retries} is ignored while ${JUDGE_ENV.vote}=${serviceEnv.votes}: re-asking on fail biases toward pass, which is what a vote exists to remove`
32
+ );
33
+ }
34
+ const service = createJudgeService(serviceEnv, void 0, logger);
35
+ const probe = createAuthProbe(service);
36
+ const health = await probe.status(true);
37
+ const reason = health.error ?? "the provider rejected the credentials";
38
+ if (argv.includes("--check")) {
39
+ if (health.ok) {
40
+ logger.info(`\u2713 ${serviceEnv.provider} credentials accepted`);
41
+ return;
42
+ }
43
+ logger.error(`\u2717 ${reason}`);
44
+ process.exitCode = 1;
45
+ return;
46
+ }
47
+ if (!health.ok) {
48
+ if (!serverEnv.skipPreflight) {
49
+ logger.error(`\u2717 ${reason}`);
50
+ logger.error(
51
+ ` (set ${JUDGE_ENV.skipPreflight}=1 to start anyway \u2014 the first verdict will fail instead, and /health will keep reporting this)`
52
+ );
53
+ process.exitCode = 1;
54
+ return;
55
+ }
56
+ logger.warn(`! starting with ${JUDGE_ENV.skipPreflight}=1 despite: ${reason}`);
57
+ }
58
+ const started = await startJudgeServer(service, serverEnv, { logger, probe });
59
+ logger.info(
26
60
  `unotest-judge listening on http://${serverEnv.host}:${started.port} (provider: ${serviceEnv.provider}${serviceEnv.model ? `, model: ${serviceEnv.model}` : ""})`
27
61
  );
62
+ installShutdown(started.close, logger);
63
+ }
64
+ function installShutdown(close, logger) {
28
65
  const shutdown = () => {
29
- void started.close().finally(() => process.exit(0));
66
+ logger.debug("unotest-judge shutting down");
67
+ void close().finally(() => process.exit(0));
30
68
  };
31
69
  process.once("SIGINT", shutdown);
32
70
  process.once("SIGTERM", shutdown);
@@ -36,7 +74,10 @@ function printHelp() {
36
74
  [
37
75
  "unotest-judge \u2014 LLM-judge service for @unotest/web's assertJudge",
38
76
  "",
39
- "Usage: npx @unotest/judge [--help] [--version]",
77
+ "Usage: npx @unotest/judge [--check] [--help] [--version]",
78
+ "",
79
+ " --check verify the provider's credentials and exit (0 = usable),",
80
+ " without listening. The same check runs on every start.",
40
81
  "",
41
82
  "Env:",
42
83
  " UNOTEST_JUDGE_PROVIDER fake (deterministic, CI-safe) | vertex (ADC) |",
@@ -50,8 +91,14 @@ function printHelp() {
50
91
  " UNOTEST_JUDGE_VOTE N-call majority vote (default 1 = off)",
51
92
  " UNOTEST_JUDGE_CALL_TIMEOUT_MS per-call budget, ms (default 30000;",
52
93
  " claude 120000)",
94
+ " UNOTEST_JUDGE_LOG_LEVEL silent | error | warn | info (default) | debug;",
95
+ " falls back to UNOTEST_LOG_LEVEL. debug prints the",
96
+ " effective prompt, the judged text and raw replies",
97
+ " \u2014 application content, so opt-in only",
98
+ " UNOTEST_JUDGE_SKIP_PREFLIGHT 1 = start even when the credential check fails",
99
+ " (/health keeps reporting the failure)",
53
100
  " GOOGLE_CLOUD_PROJECT vertex: ADC project",
54
- " GOOGLE_CLOUD_LOCATION vertex: ADC location",
101
+ " GOOGLE_CLOUD_LOCATION vertex: global, or a region (us-central1)",
55
102
  " UNOTEST_JUDGE_ACCESS_TOKEN vertex: static bearer override (skips ADC)",
56
103
  " GEMINI_API_KEY gemini: API key",
57
104
  " OPENAI_API_KEY openai: API key",
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { JudgeRequest, JudgeVerdict } from '@unotest/protocol';
2
- export { JUDGE_ROUTES, JudgeErrorResponse, JudgeRequest, JudgeVerdict } from '@unotest/protocol';
1
+ import { JudgeErrorResponse, JudgeRequest, JudgeVerdict, JudgeHealthResponse } from '@unotest/protocol';
2
+ export { JUDGE_ROUTES, JudgeErrorResponse, JudgeHealthResponse, JudgeRequest, JudgeVerdict } from '@unotest/protocol';
3
3
  import { Server } from 'node:http';
4
4
 
5
5
  declare class JudgeError extends Error {
@@ -13,17 +13,41 @@ declare class JudgeConfigError extends JudgeError {
13
13
  * model backend, or an unparseable model reply. */
14
14
  declare class JudgeProviderError extends JudgeError {
15
15
  }
16
+ /** A provider fault that is expected to pass on its own: rate limit,
17
+ * backend 5xx, connection reset. Separate class so the transport layer can
18
+ * re-send it — a verdict is never retried this way (that is policy.ts's
19
+ * job and a deliberate bias), only the call that never produced one. */
20
+ declare class JudgeTransientError extends JudgeProviderError {
21
+ }
22
+ /** Wire code for an error — one mapping, used by the HTTP route and by the
23
+ * health probe so a fault reads the same whether it arrives as a failed
24
+ * verdict or as a red /health. */
25
+ declare function judgeErrorCode(e: unknown): NonNullable<JudgeErrorResponse["code"]>;
16
26
 
17
27
  interface SingleVerdict {
18
28
  pass: boolean;
19
29
  reasoning: string;
20
30
  /** Model id that produced this verdict (`fake` for the fake provider). */
21
31
  model: string;
32
+ /** The backend's reply as received, before parsing. Carried for debug
33
+ * logging only — set by the verdict parser, so every model-backed
34
+ * provider gets it without plumbing of its own. */
35
+ raw?: string;
22
36
  }
23
37
  interface JudgeProvider {
24
38
  /** One un-retried judgement. Throws JudgeProviderError on transport /
25
39
  * parse faults; a clean `fail` verdict is a RESULT, not an error. */
26
40
  judgeOnce(request: JudgeRequest): Promise<SingleVerdict>;
41
+ /** Prove the credentials work WITHOUT calling the model — a token
42
+ * exchange, a free `GET /models`, a `--version` spawn. Used by the
43
+ * startup preflight and by /health, so a judge that cannot judge says so
44
+ * before a scenario spends five minutes discovering it.
45
+ *
46
+ * Optional by design (ISP): the fake provider has no credentials, and a
47
+ * future provider without a free probe stays honest by omitting it
48
+ * rather than faking a green check. Throws the same typed errors as
49
+ * `judgeOnce` — JudgeConfigError when the operator must act. */
50
+ checkAuth?(): Promise<void>;
27
51
  }
28
52
 
29
53
  declare const FAKE_MODEL_ID = "fake";
@@ -47,12 +71,20 @@ interface VertexProviderOptions {
47
71
  /** Injected fetch (tests). Defaults to global fetch. */
48
72
  fetchImpl?: typeof fetch;
49
73
  }
74
+ /** Exported for unit tests — the URL shape is the whole bug surface here. */
75
+ declare function vertexEndpoint(project: string, location: string, model: string): string;
50
76
  declare class VertexJudgeProvider implements JudgeProvider {
51
77
  private readonly opts;
52
- private readonly fetchImpl;
78
+ private readonly api;
53
79
  private tokenSource;
54
80
  constructor(opts: VertexProviderOptions);
55
81
  judgeOnce(request: JudgeRequest): Promise<SingleVerdict>;
82
+ /** Two credentials, two free probes. ADC: fetching a token exercises the
83
+ * exact thing that dies on an org's daily reauth policy. A static token:
84
+ * Google's own `tokeninfo` says whether it is still alive — and a static
85
+ * token lives about an hour, so "valid when the service started" is not
86
+ * the same question as "valid now". */
87
+ checkAuth(): Promise<void>;
56
88
  private accessToken;
57
89
  }
58
90
 
@@ -66,9 +98,10 @@ interface GeminiProviderOptions {
66
98
  }
67
99
  declare class GeminiJudgeProvider implements JudgeProvider {
68
100
  private readonly opts;
69
- private readonly fetchImpl;
101
+ private readonly api;
70
102
  constructor(opts: GeminiProviderOptions);
71
103
  judgeOnce(request: JudgeRequest): Promise<SingleVerdict>;
104
+ checkAuth(): Promise<void>;
72
105
  }
73
106
 
74
107
  interface OpenAiProviderOptions {
@@ -81,9 +114,11 @@ interface OpenAiProviderOptions {
81
114
  }
82
115
  declare class OpenAiJudgeProvider implements JudgeProvider {
83
116
  private readonly opts;
84
- private readonly fetchImpl;
117
+ private readonly api;
85
118
  constructor(opts: OpenAiProviderOptions);
86
119
  judgeOnce(request: JudgeRequest): Promise<SingleVerdict>;
120
+ /** `GET /models` is free and needs the same key the verdict call uses. */
121
+ checkAuth(): Promise<void>;
87
122
  }
88
123
 
89
124
  interface AnthropicProviderOptions {
@@ -96,19 +131,31 @@ interface AnthropicProviderOptions {
96
131
  }
97
132
  declare class AnthropicJudgeProvider implements JudgeProvider {
98
133
  private readonly opts;
99
- private readonly fetchImpl;
134
+ private readonly api;
100
135
  constructor(opts: AnthropicProviderOptions);
101
136
  judgeOnce(request: JudgeRequest): Promise<SingleVerdict>;
137
+ /** `GET /models` is free and needs the same key the verdict call uses. */
138
+ checkAuth(): Promise<void>;
102
139
  }
103
140
 
104
- interface ExecFileResult {
141
+ interface ProcessResult {
105
142
  stdout: string;
106
143
  stderr: string;
107
144
  }
108
- type ExecFileFn = (file: string, args: string[], opts: {
109
- timeout: number;
145
+ interface RunProcessOptions {
146
+ /** Wall-clock budget; the child is killed past it. */
147
+ timeoutMs: number;
148
+ /** Cap on captured stdout — a runaway child must not eat the service. */
110
149
  maxBuffer: number;
111
- }) => Promise<ExecFileResult>;
150
+ /** Written to the child's stdin, which is then closed. */
151
+ input?: string;
152
+ }
153
+ type RunProcess = (file: string, args: string[], opts: RunProcessOptions) => Promise<ProcessResult>;
154
+ /** Rejects with an Error carrying `code` / `killed` / `stderr`, the same
155
+ * shape `child_process.execFile` uses — callers discriminate on those
156
+ * fields, not on message text. */
157
+ declare const runProcess: RunProcess;
158
+
112
159
  interface ClaudeCliProviderOptions {
113
160
  /** Binary to spawn (UNOTEST_JUDGE_CLAUDE_BIN, default "claude"). */
114
161
  bin: string;
@@ -116,23 +163,96 @@ interface ClaudeCliProviderOptions {
116
163
  model?: string;
117
164
  /** Per-call wall-clock budget, ms. */
118
165
  timeoutMs: number;
119
- /** Injected exec (tests). Defaults to node:child_process execFile. */
120
- execImpl?: ExecFileFn;
166
+ /** Injected process runner (tests). Defaults to a real spawn. */
167
+ runImpl?: RunProcess;
121
168
  }
122
169
  declare class ClaudeCliJudgeProvider implements JudgeProvider {
123
170
  private readonly opts;
171
+ private readonly run;
124
172
  constructor(opts: ClaudeCliProviderOptions);
125
173
  judgeOnce(request: JudgeRequest): Promise<SingleVerdict>;
174
+ /** The binary exists and runs. It cannot prove the session is still
175
+ * authenticated without spending a model call, so that failure stays a
176
+ * first-verdict one — but "claude is not installed on this box" is the
177
+ * common case and it is caught here. */
178
+ checkAuth(): Promise<void>;
126
179
  }
127
180
 
128
181
  declare const VERDICT_PROMPT: (rubric: string, text: string) => string;
129
- /** Parse the model's JSON verdict. Exported for unit tests. */
182
+ /** Parse the model's JSON verdict. Exported for unit tests. `raw` is carried
183
+ * through for debug logging. */
130
184
  declare function parseVerdictReply(text: string, model: string): {
131
185
  pass: boolean;
132
186
  reasoning: string;
187
+ raw: string;
133
188
  };
134
189
 
135
190
  declare function judgeWithRetries(provider: JudgeProvider, request: JudgeRequest, retries: number): Promise<JudgeVerdict>;
191
+ /** `votes` independent calls, majority verdict wins. Calls run CONCURRENTLY:
192
+ * sequential voting would multiply latency by N and blow the client's
193
+ * whole-request budget on a slow provider. `votes` is odd by construction
194
+ * (env validation) — a tie has no honest answer.
195
+ *
196
+ * A ballot that ERRORS is dropped, not fatal: N concurrent calls are N
197
+ * chances to catch a rate limit, so `Promise.all` made the reliability
198
+ * mechanism the least reliable configuration. The vote still has to mean
199
+ * something, so a verdict needs a majority of the REQUESTED votes to have
200
+ * been cast (2 of 3), and a tie among the cast ones — only reachable once
201
+ * a ballot is missing — re-raises the failure instead of picking a side. */
202
+ declare function judgeWithVote(provider: JudgeProvider, request: JudgeRequest, votes: number): Promise<JudgeVerdict>;
203
+
204
+ type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
205
+ declare const LOG_LEVELS: readonly LogLevel[];
206
+ interface Logger {
207
+ error(message: string): void;
208
+ warn(message: string): void;
209
+ info(message: string): void;
210
+ debug(message: string): void;
211
+ }
212
+ declare class ConsoleLogger implements Logger {
213
+ private readonly level;
214
+ private readonly out;
215
+ private readonly err;
216
+ constructor(level: LogLevel, out?: (line: string) => void, err?: (line: string) => void);
217
+ error(message: string): void;
218
+ warn(message: string): void;
219
+ info(message: string): void;
220
+ debug(message: string): void;
221
+ private enabled;
222
+ }
223
+ /** Default for in-process use (@unotest/web's local mode): the consumer owns
224
+ * its own console, the engine must not write to it uninvited. */
225
+ declare const SILENT_LOGGER: Logger;
226
+
227
+ declare class LoggingJudgeProvider implements JudgeProvider {
228
+ private readonly inner;
229
+ private readonly logger;
230
+ private readonly nowFn;
231
+ /** Mirrors the inner provider's capability instead of faking a probe the
232
+ * wrapped one does not have. */
233
+ readonly checkAuth?: () => Promise<void>;
234
+ constructor(inner: JudgeProvider, logger: Logger, nowFn?: () => number);
235
+ judgeOnce(request: JudgeRequest): Promise<SingleVerdict>;
236
+ }
237
+ /** Wrap only when someone is listening — an undecorated provider keeps the
238
+ * stack (and the stack traces) shorter in the common case. */
239
+ declare function withLogging(provider: JudgeProvider, logger: Logger | undefined): JudgeProvider;
240
+
241
+ type Sleep = (ms: number) => Promise<void>;
242
+ interface TransientRetryOptions {
243
+ /** Injected sleep (tests) — keeps the backoff out of the test clock. */
244
+ sleepImpl?: Sleep;
245
+ }
246
+ declare class TransientRetryProvider implements JudgeProvider {
247
+ private readonly inner;
248
+ private readonly opts;
249
+ /** Mirrors the inner provider's capability rather than inventing one. */
250
+ readonly checkAuth?: () => Promise<void>;
251
+ constructor(inner: JudgeProvider, opts?: TransientRetryOptions);
252
+ judgeOnce(request: JudgeRequest): Promise<SingleVerdict>;
253
+ private retry;
254
+ }
255
+ declare function withTransientRetry(provider: JudgeProvider, opts?: TransientRetryOptions): JudgeProvider;
136
256
 
137
257
  type JudgeProviderKind = "fake" | "vertex" | "claude" | "gemini" | "openai" | "anthropic";
138
258
  interface JudgeServiceEnv {
@@ -163,24 +283,68 @@ interface JudgeServerEnv {
163
283
  port: number;
164
284
  /** Optional bearer token the server requires on every /judge call. */
165
285
  token?: string;
286
+ /** Boot without probing the provider's credentials, and answer /health
287
+ * without probing them either. */
288
+ skipPreflight: boolean;
166
289
  }
167
290
  declare function resolveJudgeServerEnv(env: NodeJS.ProcessEnv): JudgeServerEnv;
291
+ /** Log level, or `undefined` when neither variable is set — the caller picks
292
+ * the default, and the two callers differ: the CLI service talks (info),
293
+ * the in-process engine stays quiet. */
294
+ declare function resolveLogLevel(env: NodeJS.ProcessEnv): LogLevel | undefined;
168
295
 
169
296
  interface JudgeService {
170
297
  judge(request: JudgeRequest): Promise<JudgeVerdict>;
298
+ /** The provider's free credential probe, forwarded so the CLI preflight
299
+ * and /health depend on this facade rather than on a concrete provider.
300
+ * Absent when the provider has none (fake). */
301
+ checkAuth?(): Promise<void>;
171
302
  }
172
303
  declare function buildProvider(env: JudgeServiceEnv): JudgeProvider;
173
- declare function createJudgeService(env: JudgeServiceEnv, provider?: JudgeProvider): JudgeService;
304
+ declare function createJudgeService(env: JudgeServiceEnv, provider?: JudgeProvider, logger?: Logger): JudgeService;
174
305
  /** Everything from process-env in one call — the entry point @unotest/web's
175
306
  * local mode uses. Throws JudgeConfigError with an actionable message on
176
- * missing/malformed env. */
307
+ * missing/malformed env. In-process callers own their console, so logging
308
+ * stays silent unless the level was asked for explicitly. */
177
309
  declare function createJudgeServiceFromEnv(env: NodeJS.ProcessEnv): JudgeService;
178
310
 
311
+ interface AuthProbeOptions {
312
+ /** The provider's probe. Absent = the provider has no free check. */
313
+ checkAuth?: () => Promise<void>;
314
+ ttlMs?: number;
315
+ /** Override the clock for deterministic tests. */
316
+ nowFn?: () => number;
317
+ }
318
+ /** The one place that binds a service to its probe. Note what it does NOT
319
+ * take: a "skip" flag. UNOTEST_JUDGE_SKIP_PREFLIGHT waives the STARTUP
320
+ * GATE, not the truth — a waived service still answers /health from a real
321
+ * probe. The alternative was tried and is worse: our own message for a
322
+ * failed preflight suggests that flag, so the operator who sets it is
323
+ * precisely the one whose credentials are dead, and a green /health then
324
+ * hides exactly the fault the flag was reached for. */
325
+ declare function createAuthProbe(service: Pick<JudgeService, "checkAuth">): AuthProbe;
326
+ declare class AuthProbe {
327
+ private readonly opts;
328
+ private cached;
329
+ constructor(opts: AuthProbeOptions);
330
+ /** @param fresh bypass the cache (startup preflight, `--check`). */
331
+ status(fresh?: boolean): Promise<JudgeHealthResponse>;
332
+ private run;
333
+ }
334
+
179
335
  interface StartedJudgeServer {
180
336
  server: Server;
181
337
  port: number;
182
338
  close(): Promise<void>;
183
339
  }
184
- declare function startJudgeServer(service: JudgeService, env: JudgeServerEnv): Promise<StartedJudgeServer>;
340
+ interface JudgeServerDeps {
341
+ logger?: Logger;
342
+ /** Shared with the CLI preflight so a boot check and a /health poll do not
343
+ * probe the provider twice. */
344
+ probe?: AuthProbe;
345
+ /** Override the clock for deterministic tests. */
346
+ nowFn?: () => number;
347
+ }
348
+ declare function startJudgeServer(service: JudgeService, env: JudgeServerEnv, deps?: JudgeServerDeps): Promise<StartedJudgeServer>;
185
349
 
186
- export { AnthropicJudgeProvider, ClaudeCliJudgeProvider, type ExecFileFn, type ExecFileResult, FAKE_MODEL_ID, FakeJudgeProvider, GeminiJudgeProvider, JudgeConfigError, JudgeError, type JudgeProvider, JudgeProviderError, type JudgeProviderKind, type JudgeServerEnv, type JudgeService, type JudgeServiceEnv, OpenAiJudgeProvider, type SingleVerdict, type StartedJudgeServer, VERDICT_PROMPT, VertexJudgeProvider, buildProvider, createJudgeService, createJudgeServiceFromEnv, judgeWithRetries, parseFakeRubric, parseVerdictReply, resolveJudgeServerEnv, resolveJudgeServiceEnv, startJudgeServer };
350
+ export { AnthropicJudgeProvider, AuthProbe, type AuthProbeOptions, ClaudeCliJudgeProvider, ConsoleLogger, FAKE_MODEL_ID, FakeJudgeProvider, GeminiJudgeProvider, JudgeConfigError, JudgeError, type JudgeProvider, JudgeProviderError, type JudgeProviderKind, type JudgeServerDeps, type JudgeServerEnv, type JudgeService, type JudgeServiceEnv, JudgeTransientError, LOG_LEVELS, type LogLevel, type Logger, LoggingJudgeProvider, OpenAiJudgeProvider, type ProcessResult, type RunProcess, type RunProcessOptions, SILENT_LOGGER, type SingleVerdict, type StartedJudgeServer, type TransientRetryOptions, TransientRetryProvider, VERDICT_PROMPT, VertexJudgeProvider, buildProvider, createAuthProbe, createJudgeService, createJudgeServiceFromEnv, judgeErrorCode, judgeWithRetries, judgeWithVote, parseFakeRubric, parseVerdictReply, resolveJudgeServerEnv, resolveJudgeServiceEnv, resolveLogLevel, runProcess, startJudgeServer, vertexEndpoint, withLogging, withTransientRetry };
package/dist/index.js CHANGED
@@ -1,31 +1,48 @@
1
1
  import {
2
2
  AnthropicJudgeProvider,
3
+ AuthProbe,
3
4
  ClaudeCliJudgeProvider,
5
+ ConsoleLogger,
4
6
  FAKE_MODEL_ID,
5
7
  FakeJudgeProvider,
6
8
  GeminiJudgeProvider,
7
9
  JudgeConfigError,
8
10
  JudgeError,
9
11
  JudgeProviderError,
12
+ JudgeTransientError,
13
+ LOG_LEVELS,
14
+ LoggingJudgeProvider,
10
15
  OpenAiJudgeProvider,
16
+ SILENT_LOGGER,
17
+ TransientRetryProvider,
11
18
  VERDICT_PROMPT,
12
19
  VertexJudgeProvider,
13
20
  buildProvider,
21
+ createAuthProbe,
14
22
  createJudgeService,
15
23
  createJudgeServiceFromEnv,
24
+ judgeErrorCode,
16
25
  judgeWithRetries,
26
+ judgeWithVote,
17
27
  parseFakeRubric,
18
28
  parseVerdictReply,
19
29
  resolveJudgeServerEnv,
20
30
  resolveJudgeServiceEnv,
21
- startJudgeServer
22
- } from "./chunk-74FL5RWE.js";
31
+ resolveLogLevel,
32
+ runProcess,
33
+ startJudgeServer,
34
+ vertexEndpoint,
35
+ withLogging,
36
+ withTransientRetry
37
+ } from "./chunk-ADU4QPCJ.js";
23
38
 
24
39
  // src/index.ts
25
40
  import { JUDGE_ROUTES } from "@unotest/protocol";
26
41
  export {
27
42
  AnthropicJudgeProvider,
43
+ AuthProbe,
28
44
  ClaudeCliJudgeProvider,
45
+ ConsoleLogger,
29
46
  FAKE_MODEL_ID,
30
47
  FakeJudgeProvider,
31
48
  GeminiJudgeProvider,
@@ -33,17 +50,30 @@ export {
33
50
  JudgeConfigError,
34
51
  JudgeError,
35
52
  JudgeProviderError,
53
+ JudgeTransientError,
54
+ LOG_LEVELS,
55
+ LoggingJudgeProvider,
36
56
  OpenAiJudgeProvider,
57
+ SILENT_LOGGER,
58
+ TransientRetryProvider,
37
59
  VERDICT_PROMPT,
38
60
  VertexJudgeProvider,
39
61
  buildProvider,
62
+ createAuthProbe,
40
63
  createJudgeService,
41
64
  createJudgeServiceFromEnv,
65
+ judgeErrorCode,
42
66
  judgeWithRetries,
67
+ judgeWithVote,
43
68
  parseFakeRubric,
44
69
  parseVerdictReply,
45
70
  resolveJudgeServerEnv,
46
71
  resolveJudgeServiceEnv,
47
- startJudgeServer
72
+ resolveLogLevel,
73
+ runProcess,
74
+ startJudgeServer,
75
+ vertexEndpoint,
76
+ withLogging,
77
+ withTransientRetry
48
78
  };
49
79
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unotest/judge",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "description": "LLM-judge service for the @unotest ecosystem: judges free-form text (chat replies, generated content) against a natural-language rubric and returns a structured pass/fail verdict with reasoning. Runs as a small HTTP service (`npx @unotest/judge`) or in-process. Providers: deterministic `fake` (CI-safe), Google Vertex AI via ADC, the local Claude Code CLI (subscription auth, no API key), and Gemini / OpenAI / Anthropic APIs via keys — all raw HTTP or a local process, zero provider SDKs. Backs the `assertJudge` DSL assertion of @unotest/web.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -33,7 +33,7 @@
33
33
  ],
34
34
  "dependencies": {
35
35
  "google-auth-library": "^10.0.0",
36
- "@unotest/protocol": "^0.24.0"
36
+ "@unotest/protocol": "^0.25.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/node": "^22.10.0",