@hue-run/sdk 0.13.1 → 0.13.2

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/CLI.md CHANGED
@@ -42,7 +42,7 @@ project manifest are refused because managers can update ancestor locks; Python
42
42
  The generated `hue.setup.mjs` or `hue_setup.py` always selects `captureContent: false` /
43
43
  `capture_content=False`. For a supported application, setup installs the dependency and adds the
44
44
  managed import and middleware registration to the existing entrypoint; an unreferenced helper is
45
- not a completed integration. TypeScript uses `@hue-run/sdk@0.13.1`, `@opentelemetry/api@1.9.1` and
45
+ not a completed integration. TypeScript uses `@hue-run/sdk@0.13.2`, `@opentelemetry/api@1.9.1` and
46
46
  `@opentelemetry/context-async-hooks@2.11.0`; Python setup uses its separately tested package pin.
47
47
  Content capture requires an ordinary account-managed key and a later explicit application decision.
48
48
 
@@ -469,7 +469,7 @@ node packages/sdk-typescript/scripts/verify-package.mjs --artifacts-dir .artifac
469
469
  # Set project to an existing supported fixture; use the same directory on resume.
470
470
  project=/absolute/path/to/supported-fixture
471
471
  node packages/sdk-typescript/scripts/verify-setup-live.mjs \
472
- --archive .artifacts/typescript/hue-run-sdk-0.13.1.tgz \
472
+ --archive .artifacts/typescript/hue-run-sdk-0.13.2.tgz \
473
473
  --origin https://STAGING_ORIGIN \
474
474
  --project "$project" --command setup \
475
475
  --evidence .context/setup-staging-before-claim.json
@@ -480,7 +480,7 @@ the private local handoff and finish the real browser claim, then reconcile the
480
480
 
481
481
  ```sh
482
482
  node packages/sdk-typescript/scripts/verify-setup-live.mjs \
483
- --archive .artifacts/typescript/hue-run-sdk-0.13.1.tgz \
483
+ --archive .artifacts/typescript/hue-run-sdk-0.13.2.tgz \
484
484
  --origin https://STAGING_ORIGIN \
485
485
  --project "$project" --command claim \
486
486
  --evidence .context/setup-staging-after-claim.json
@@ -523,10 +523,10 @@ production agent lacks. Pin the SDK and bring its `zod` peer along, so the agent
523
523
  gains no dependency:
524
524
 
525
525
  ```sh
526
- npx --yes --package @hue-run/sdk@0.13.1 --package "zod@^4.6.5" hue eval --case "Refund an eligible charge" --command "node agent.js" --env-file .env.hue
527
- npx --yes --package @hue-run/sdk@0.13.1 --package "zod@^4.6.5" hue eval --case https://app.hue.run/projects/demo/scenarios/<id> --command "python agent.py" --timeout 120 --baseline <experiment id>
528
- npx --yes --package @hue-run/sdk@0.13.1 --package "zod@^4.6.5" hue eval --set "Billing regressions" --scorer-version <id> --command "node agent.js" --save-version
529
- npx --yes --package @hue-run/sdk@0.13.1 --package "zod@^4.6.5" hue eval --worker --command "node agent.js" --agent-key support-agent --env-file .env.hue
526
+ npx --yes --package @hue-run/sdk@0.13.2 --package "zod@^4.6.5" hue eval --case "Refund an eligible charge" --command "node agent.js" --env-file .env.hue
527
+ npx --yes --package @hue-run/sdk@0.13.2 --package "zod@^4.6.5" hue eval --case https://app.hue.run/projects/demo/scenarios/<id> --command "python agent.py" --timeout 120 --baseline <experiment id>
528
+ npx --yes --package @hue-run/sdk@0.13.2 --package "zod@^4.6.5" hue eval --set "Billing regressions" --scorer-version <id> --command "node agent.js" --save-version
529
+ npx --yes --package @hue-run/sdk@0.13.2 --package "zod@^4.6.5" hue eval --worker --command "node agent.js" --agent-key support-agent --revision <new-agent-revision> --env-file .env.hue
530
530
  ```
531
531
 
532
532
  Without the second `--package`, `hue eval` exits with `hue eval needs zod`, even for `--help`;
@@ -562,7 +562,7 @@ export default function runMyAgent(inputs: JsonValue, context: SimulationTargetC
562
562
  ```
563
563
 
564
564
  ```sh
565
- npx --yes --package @hue-run/sdk@0.13.1 --package "zod@^4.6.5" hue eval --case "Refund an eligible charge" ./hue-agent.ts --content --env-file .env.hue
565
+ npx --yes --package @hue-run/sdk@0.13.2 --package "zod@^4.6.5" hue eval --case "Refund an eligible charge" ./hue-agent.ts --content --env-file .env.hue
566
566
  ```
567
567
 
568
568
  `--scenario` remains an alias for `--case` for existing scripts. Pass one selection flag.
@@ -581,9 +581,11 @@ Failing cases print the scorer explanation. An evaluator Hue records as not appl
581
581
  that case's columns and neither passes nor fails it, so in a mixed eval set a case is decided by
582
582
  the evaluators that apply to it; the pass line counts the not-applicable results. A case that no
583
583
  pinned evaluator applies to is an error that names what they need. A result of a pinned Hue judge
584
- (an evaluator of kind `world_judge`) that Hue marks advisory, as it does every judge's today, is
584
+ (an evaluator of kind `world_judge`) that Hue marks advisory is
585
585
  shown in its column, marked `(advisory)`, but never decides a case or the exit code; the pass line
586
- counts advisory failures as not counted, and a case only advisory results ran for is an error. Any
586
+ counts advisory failures as not counted, and a case only advisory results ran for is an error.
587
+ The Answer outcome evaluator uses its required judge to decide answer-only cases; if that judge
588
+ cannot run, the case is inconclusive. Any
587
589
  other evaluator's result, an error, or a metric that carries `passed` is never advisory, whatever
588
590
  its evidence says. A metric name that
589
591
  several evaluators report, such as two judges' `verdict`, gets a column per evaluator, labelled
@@ -629,8 +631,21 @@ script name; `--revision` is sent to Hue as the agent revision of every world.
629
631
 
630
632
  `--worker` registers the adapter through `runLocalAgent()` with key `--agent-key` (default: the
631
633
  adapter filename slug), name `--agent-name` (default: the key), revision `--revision` (default:
632
- `AGENT_REVISION`, then the Git `HEAD` short hash, then `dev`) and capability `environment:v1`
633
- plus any repeated `--capability <value>`, prints the registration and each claimed run with its
634
+ `AGENT_REVISION`, then the Git `HEAD` short hash, then `dev`). Command workers register both
635
+ `environment:v1` and `direct:v1`, plus any repeated `--capability <value>`: the same worker runs
636
+ world cases, answer-only cases and mixed eval sets launched from Hue. Commands keep the launch
637
+ directory for both case kinds, so relative application entry points and configuration work.
638
+ Direct cases receive the task/config on stdin and private files/output through `HUE_CASE_*`,
639
+ without a world token, MCP connection or `HUE_ENVIRONMENT_RUN_ID`. App calls that require a world
640
+ must stay disabled for this handoff; never fall back to live app credentials.
641
+
642
+ Adapter-file workers register `environment:v1` by default. Add `--capability direct:v1` only when
643
+ the adapter also handles `context.mode === "direct"`; its direct context carries `config`, case
644
+ identity, `executionId`, `files`, `outputDirectory` and `signal`, with no world or tools. These
645
+ worker behaviors are added in TypeScript 0.13.2. Upgrading an existing command worker requires a
646
+ new `--revision`, because adding a capability to a previously registered revision is refused.
647
+
648
+ The worker prints the registration and each claimed run with its
634
649
  URL, executes runs launched from Hue until Ctrl+C or `--max-runs <n>`, and prints the verdict table
635
650
  after each run. Selection flags do not apply; Hue chooses the pinned experiment. The worker exits 0
636
651
  when it stops normally. Hue offers a case whose world comes with agent-visible files only to a
package/EVALUATIONS.md CHANGED
@@ -297,12 +297,19 @@ acceptance remains a post-publication Fern gate.
297
297
 
298
298
  ## Direct cases and files
299
299
 
300
- Cases without a simulated world — document workflows whose inputs are a task plus pinned files —
300
+ Cases without a simulated world — answer-only tasks, or document workflows with pinned files —
301
301
  run on the same runner under the same checkpoint rules. They shipped in `@hue-run/sdk` `0.5.0`
302
302
  and require a Hue deployment that serves case `inputFiles` on experiment
303
303
  items, subject `files`, and the artifact reservation, upload, completion and download APIs. The
304
304
  Python SDK has no equivalent.
305
305
 
306
+ The TypeScript 0.13.2 `hue eval --worker --command "…"` wrapper supplies both callbacks, so one
307
+ command worker accepts direct and world cases, including mixed eval sets. It keeps the launch
308
+ directory for relative application entry points; private case inputs/output still use
309
+ `HUE_CASE_*`. An adapter-file worker opts into the direct callback with `--capability direct:v1`
310
+ and must handle `context.mode === "direct"`. Restart an existing environment-only command
311
+ registration with a new `--revision` when upgrading.
312
+
306
313
  On the outbound worker, supply `directTarget` beside or instead of `target`. Supplying
307
314
  `directTarget` registers the `direct:v1` capability and supplying `target` registers
308
315
  `environment:v1` (both strings are exported as `localAgentCapabilities`). Declare the file
package/README.md CHANGED
@@ -647,10 +647,12 @@ their agents with `runLocalAgent()`; setup does not register workers or launch s
647
647
  The `hue eval` command, shipped in TypeScript `0.5.0` (`--case` since `0.6.0`, `--scenario`
648
648
  before), wraps `runSimulation()` and `runLocalAgent()` for an adapter file or a shell command:
649
649
  `hue eval --case "<name>" ./hue-agent.ts --content` creates a fresh run from a published case's
650
- immutable pins, runs the agent in one isolated world per case, waits
650
+ immutable pins, runs the agent with an isolated world when the case pins one, waits
651
651
  for Hue's outcome checks and prints the run URL and per-case PASS/FAIL verdicts with an exit code;
652
- `--worker` registers the same adapter for runs launched from Hue. It needs a Read and
653
- write key in `HUE_API_KEY` (never printed). Content capture stays off unless `--content` is
652
+ `--worker` registers the same adapter for runs launched from Hue. In TypeScript 0.13.2, a
653
+ command worker handles both world and answer-only cases; adapter workers opt into direct cases
654
+ with `--capability direct:v1`. Upgrade an existing command registration under a new `--revision`.
655
+ It needs a Read and write key in `HUE_API_KEY` (never printed). Content capture stays off unless `--content` is
654
656
  passed; the example passes it so case spans carry content. Case outputs, error messages and
655
657
  explanations are stored in Hue either way (`--no-output` keeps them out of a one-shot run's
656
658
  results); a command's stdout is its stored answer, with the credentials `hue eval` handed the case
package/dist/cli/eval.js CHANGED
@@ -60,6 +60,8 @@ Agent (exactly one):
60
60
 
61
61
  Modes:
62
62
  --worker Register the agent and poll for runs launched from Hue
63
+ Commands support cases with or without a world; adapter files
64
+ opt into direct cases with --capability direct:v1
63
65
  --max-runs <n> Stop the worker after n completed runs
64
66
  --agent-key <key> Agent key (default: slug of the adapter filename)
65
67
  --agent-name <name> Agent display name (default: the key)
@@ -600,9 +602,11 @@ function redacting(adapter) {
600
602
  function parentEnvironment(allowHueCredentials) {
601
603
  // A world variable left in this process's environment belongs to another world: only the
602
604
  // current case's world sets them, whether or not the case has one.
603
- return withoutWorldVariables(allowHueCredentials
605
+ const parent = withoutWorldVariables(allowHueCredentials
604
606
  ? Object.fromEntries(Object.entries(process.env).filter((entry) => entry[1] !== undefined))
605
607
  : stripHueControlPlaneCredentials(process.env));
608
+ delete parent.HUE_ENVIRONMENT_RUN_ID;
609
+ return parent;
606
610
  }
607
611
  function commandAdapter(command, timeoutSeconds, options) {
608
612
  return async (inputs, context) => {
@@ -683,7 +687,7 @@ function directCommandAdapter(command, timeoutSeconds, options) {
683
687
  files: context.files,
684
688
  });
685
689
  const stdout = await spawnAgentCommand(command, {
686
- cwd: layout.caseDirectory,
690
+ cwd: options.workingDirectory ?? layout.caseDirectory,
687
691
  env: {
688
692
  ...parentEnvironment(options.allowHueCredentials),
689
693
  HUE_CASE_DIR: layout.caseDirectory,
@@ -1286,7 +1290,7 @@ async function runDirect(run, connection) {
1286
1290
  telemetryNotAccepted: report.telemetryNotAccepted,
1287
1291
  }, run.baselineId, output, signal);
1288
1292
  }
1289
- async function runWorker(values, connection, adapter, agent, hue, output, signal) {
1293
+ async function runWorker(values, connection, agents, agent, hue, output, signal) {
1290
1294
  const client = new ObservedClient(connection);
1291
1295
  const environmentClient = createEnvironmentClient(connection);
1292
1296
  const wait = integer("wait", values.wait, 300, 0, 86_400);
@@ -1305,6 +1309,9 @@ async function runWorker(values, connection, adapter, agent, hue, output, signal
1305
1309
  output.log(`Claimed run ${claim.runId}: ${new URL(`/experiments/${claim.experimentId}`, connection.baseUrl).toString()}`);
1306
1310
  };
1307
1311
  const telemetry = telemetryReporter(output);
1312
+ // A command can use the same stdin contract for both case kinds. Existing adapter files
1313
+ // may require a world, so their direct context remains an explicit capability opt-in.
1314
+ const direct = values.command !== undefined || values.capability?.includes("direct:v1");
1308
1315
  await runLocalAgent({
1309
1316
  client,
1310
1317
  environmentClient,
@@ -1339,7 +1346,7 @@ async function runWorker(values, connection, adapter, agent, hue, output, signal
1339
1346
  },
1340
1347
  target(inputs, tools, context) {
1341
1348
  output.log(`[${context.item.externalKey}] agent started`);
1342
- return adapter(inputs, {
1349
+ return agents.simulation(inputs, {
1343
1350
  config: context.config,
1344
1351
  item: context.item,
1345
1352
  executionId: context.executionId,
@@ -1355,6 +1362,22 @@ async function runWorker(values, connection, adapter, agent, hue, output, signal
1355
1362
  signal: context.signal ?? signal,
1356
1363
  });
1357
1364
  },
1365
+ ...(direct
1366
+ ? {
1367
+ directTarget(inputs, context) {
1368
+ output.log(`[${context.item.externalKey}] agent started`);
1369
+ return agents.direct(inputs, {
1370
+ mode: "direct",
1371
+ config: context.config,
1372
+ item: context.item,
1373
+ executionId: context.executionId,
1374
+ files: context.files,
1375
+ outputDirectory: context.outputDirectory,
1376
+ signal: context.signal ?? signal,
1377
+ });
1378
+ },
1379
+ }
1380
+ : {}),
1358
1381
  async onCompleted(report) {
1359
1382
  output.log(`Run ${report.runId} completed: ${report.subjectIds.length} case${report.subjectIds.length === 1 ? "" : "s"}`);
1360
1383
  telemetry.rest(report.telemetryNotAccepted);
@@ -1490,6 +1513,9 @@ export async function runEvalCommand(argv) {
1490
1513
  direct: redacting(loaded ??
1491
1514
  directCommandAdapter(values.command, timeout, {
1492
1515
  allowHueCredentials: values["allow-hue-credentials"],
1516
+ // A worker's single command must resolve relative entry points the same way for
1517
+ // direct and world cases. One-shot direct runs keep their private-directory cwd.
1518
+ ...(values.worker ? { workingDirectory: process.cwd() } : {}),
1493
1519
  })),
1494
1520
  };
1495
1521
  hue = createHue({
@@ -1500,7 +1526,7 @@ export async function runEvalCommand(argv) {
1500
1526
  timeoutMillis: CASE_TRACE_EXPORT_MILLIS,
1501
1527
  });
1502
1528
  return values.worker
1503
- ? await runWorker(values, connection, agents.simulation, agent, hue, output, controller.signal)
1529
+ ? await runWorker(values, connection, agents, agent, hue, output, controller.signal)
1504
1530
  : await runOnce(values, connection, agents, agent, hue, output, controller.signal);
1505
1531
  }
1506
1532
  catch (error) {
@@ -110,7 +110,7 @@ export declare class EvaluationClient {
110
110
  createScorer(input: TaggedIdentity): Promise<Scorer>;
111
111
  /** Renames a scorer or replaces its tags by name; the same values again change nothing. */
112
112
  updateScorer(id: string, input: IdentityUpdate): Promise<Scorer>;
113
- /** Lists the project's tags in the order they were created. */
113
+ /** Lists the project's tags in its order: as people arranged them in Hue, then newer tags. */
114
114
  listTags(): Promise<{
115
115
  /** The project's tags. */
116
116
  items: Tag[];
@@ -451,7 +451,7 @@ export class EvaluationClient {
451
451
  updateScorer(id, input) {
452
452
  return this.request("PATCH", `/scorers/${uuid(id)}`, withTagNames(input), undefined, undefined, true);
453
453
  }
454
- /** Lists the project's tags in the order they were created. */
454
+ /** Lists the project's tags in its order: as people arranged them in Hue, then newer tags. */
455
455
  listTags() {
456
456
  return this.request("GET", "/tags");
457
457
  }
@@ -142,12 +142,17 @@ const sdkScorerPublication = z.union([
142
142
  }),
143
143
  z.strictObject({
144
144
  kind: z.literal("world_outcome"),
145
- entry: z.literal("hue.outcome_assertions.v2"),
145
+ entry: z.enum([
146
+ "hue.outcome_assertions.v2",
147
+ "hue.outcome_assertions.v4",
148
+ "hue.outcome_assertions.v5",
149
+ "hue.outcome_assertions.v6",
150
+ ]),
146
151
  metrics: fixedMetrics(outcomeAssertionMetrics),
147
152
  }),
148
153
  z.strictObject({
149
154
  kind: z.literal("world_outcome"),
150
- entry: z.literal("hue.outcome_assertions.v3"),
155
+ entry: z.enum(["hue.outcome_assertions.v3", "hue.answer_outcome.v1", "hue.answer_outcome.v2"]),
151
156
  metrics: fixedMetrics(outcomeAssertionV3Metrics),
152
157
  config: z.strictObject({ judge: outcomeJudgeConfig }),
153
158
  }),
@@ -275,6 +275,25 @@ export type ScorerDefinition = {
275
275
  /** The judge every case scored by this version uses. */
276
276
  judge: OutcomeJudgeConfig;
277
277
  };
278
+ } | {
279
+ /** A case's reviewed assertions, scored inside Hue from gateway evidence. */
280
+ kind: "world_outcome";
281
+ /** Versioned gateway-ledger assertion semantics. */
282
+ entry: "hue.outcome_assertions.v4" | "hue.outcome_assertions.v5" | "hue.outcome_assertions.v6";
283
+ /** `task_success` and the fixed assertion counts defined by the entry. */
284
+ metrics: MetricDefinition[];
285
+ } | {
286
+ /** An answer-only case, scored inside Hue without world evidence. */
287
+ kind: "world_outcome";
288
+ /** Versioned answer semantics; the pinned judge is required to decide the case. */
289
+ entry: "hue.answer_outcome.v1" | "hue.answer_outcome.v2";
290
+ /** The assertion and judge counts defined by the entry. */
291
+ metrics: MetricDefinition[];
292
+ /** The judge pin used to score the answer. */
293
+ config: {
294
+ /** The required judge every case scored by this version uses. */
295
+ judge: OutcomeJudgeConfig;
296
+ };
278
297
  } | {
279
298
  /** Scored by a person in Hue; the local runner defers it. */
280
299
  kind: "manual";
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Package version shared by the instrumentation scope and the export User-Agent. */
2
- export declare const sdkVersion = "0.13.1";
2
+ export declare const sdkVersion = "0.13.2";
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // Generated by scripts/write-version.mjs from package.json; do not edit by hand.
2
2
  /** Package version shared by the instrumentation scope and the export User-Agent. */
3
- export const sdkVersion = "0.13.1";
3
+ export const sdkVersion = "0.13.2";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hue-run/sdk",
3
- "version": "0.13.1",
3
+ "version": "0.13.2",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "publishConfig": {