@hue-run/sdk 0.9.0 → 0.10.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/CLI.md +100 -29
- package/ENVIRONMENTS.md +44 -9
- package/EVALUATIONS.md +39 -19
- package/README.md +51 -22
- package/dist/cli/eval-direct.d.ts +12 -1
- package/dist/cli/eval-direct.js +145 -33
- package/dist/cli/eval.d.ts +28 -1
- package/dist/cli/eval.js +469 -72
- package/dist/evals/checkpoint.d.ts +15 -1
- package/dist/evals/checkpoint.js +34 -3
- package/dist/evals/client.d.ts +19 -3
- package/dist/evals/client.js +82 -34
- package/dist/evals/environment-target.d.ts +18 -3
- package/dist/evals/environment-target.js +22 -10
- package/dist/evals/exit-cleanup.d.ts +4 -0
- package/dist/evals/exit-cleanup.js +26 -0
- package/dist/evals/files.d.ts +59 -1
- package/dist/evals/files.js +187 -27
- package/dist/evals/local-worker.d.ts +21 -3
- package/dist/evals/local-worker.js +14 -0
- package/dist/evals/runner.d.ts +45 -0
- package/dist/evals/runner.js +164 -13
- package/dist/evals/scenarios.d.ts +7 -5
- package/dist/evals/scenarios.js +71 -14
- package/dist/evals/simulation.d.ts +17 -4
- package/dist/evals/simulation.js +8 -0
- package/dist/evals/types.d.ts +4 -0
- package/dist/evals/verdicts.d.ts +15 -2
- package/dist/evals/verdicts.js +43 -9
- package/dist/evals.d.ts +4 -3
- package/dist/evals.js +2 -2
- package/dist/inline-files.d.ts +4 -0
- package/dist/inline-files.js +40 -17
- package/dist/snapshot.d.ts +2 -2
- package/dist/snapshot.js +47 -12
- package/dist/transport.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
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.
|
|
45
|
+
not a completed integration. TypeScript uses `@hue-run/sdk@0.10.0`, `@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
|
|
|
@@ -305,7 +305,7 @@ node packages/sdk-typescript/scripts/verify-package.mjs --artifacts-dir .artifac
|
|
|
305
305
|
# Set project to an existing supported fixture; use the same directory on resume.
|
|
306
306
|
project=/absolute/path/to/supported-fixture
|
|
307
307
|
node packages/sdk-typescript/scripts/verify-setup-live.mjs \
|
|
308
|
-
--archive .artifacts/typescript/hue-run-sdk-0.
|
|
308
|
+
--archive .artifacts/typescript/hue-run-sdk-0.10.0.tgz \
|
|
309
309
|
--origin https://STAGING_ORIGIN \
|
|
310
310
|
--project "$project" --command setup \
|
|
311
311
|
--evidence .context/setup-staging-before-claim.json
|
|
@@ -316,7 +316,7 @@ the private local handoff and finish the real browser claim, then reconcile the
|
|
|
316
316
|
|
|
317
317
|
```sh
|
|
318
318
|
node packages/sdk-typescript/scripts/verify-setup-live.mjs \
|
|
319
|
-
--archive .artifacts/typescript/hue-run-sdk-0.
|
|
319
|
+
--archive .artifacts/typescript/hue-run-sdk-0.10.0.tgz \
|
|
320
320
|
--origin https://STAGING_ORIGIN \
|
|
321
321
|
--project "$project" --command claim \
|
|
322
322
|
--evidence .context/setup-staging-after-claim.json
|
|
@@ -351,8 +351,11 @@ the CLI never prints it. The optional `zod` peer of `@hue-run/sdk/evals` must be
|
|
|
351
351
|
Write an adapter module that hands the case inputs and the world's tools or MCP connection to
|
|
352
352
|
the real agent. The module exports `default` or `runMyAgent`; `context` is the SDK's
|
|
353
353
|
`SimulationTargetContext` (`world`, `mcp`, `tools`, `config`, `item`, `executionId`,
|
|
354
|
-
`environmentRunId`, `signal`; `world` carries the provider mirror URLs,
|
|
355
|
-
`mcpConfig` where Hue's simulation gateway serves the world)
|
|
354
|
+
`environmentRunId`, `files`, `outputDirectory`, `signal`; `world` carries the provider mirror URLs,
|
|
355
|
+
the world token, `env` and `mcpConfig` where Hue's simulation gateway serves the world). When the
|
|
356
|
+
case also pins input files, `files` holds verified copies of its agent-visible ones (see
|
|
357
|
+
[Evaluate a document eval set](#evaluate-a-document-eval-set)); return
|
|
358
|
+
`withFiles(output, files)` from `@hue-run/sdk/evals` to upload documents the agent produced:
|
|
356
359
|
|
|
357
360
|
```ts
|
|
358
361
|
// hue-agent.ts: erasable TypeScript only; Node.js 24 and Bun strip the types natively.
|
|
@@ -368,27 +371,35 @@ export default function runMyAgent(inputs: JsonValue, context: SimulationTargetC
|
|
|
368
371
|
```
|
|
369
372
|
|
|
370
373
|
```sh
|
|
371
|
-
hue eval --case "Refund an eligible charge" ./hue-agent.ts --env-file .env.hue
|
|
372
|
-
hue eval --case https://app.hue.run/projects/demo/scenarios/<id> ./hue-agent.ts --baseline <run id>
|
|
373
|
-
hue eval --set "Billing regressions" --scorer-version <id> ./hue-agent.ts --save-version
|
|
374
|
+
hue eval --case "Refund an eligible charge" ./hue-agent.ts --content --env-file .env.hue
|
|
375
|
+
hue eval --case https://app.hue.run/projects/demo/scenarios/<id> ./hue-agent.ts --content --baseline <run id>
|
|
376
|
+
hue eval --set "Billing regressions" --scorer-version <id> ./hue-agent.ts --content --save-version
|
|
374
377
|
hue eval --case "Refund an eligible charge" --command "python agent.py" --timeout 120 --content
|
|
375
|
-
hue eval --worker ./hue-agent.ts --agent-key support-agent --env-file .env.hue
|
|
378
|
+
hue eval --worker ./hue-agent.ts --agent-key support-agent --content --env-file .env.hue
|
|
376
379
|
```
|
|
377
380
|
|
|
378
381
|
`--scenario` remains an alias for `--case` for existing scripts. Pass one selection flag.
|
|
379
382
|
|
|
380
|
-
The one-shot mode resolves the selection (`--case` by name, ID or URL
|
|
381
|
-
|
|
383
|
+
The one-shot mode resolves the selection (`--case` by name, or by the ID or URL of the published
|
|
384
|
+
case or of the case conversion that published it, among the project's first 1,000 Scenarios;
|
|
385
|
+
`--set` by name, ID or URL with explicit `--scorer-version` pins; or `--dataset-version` with `--scorer-version`),
|
|
382
386
|
creates a fresh run from those immutable pins named `<agent key> @ <revision>` (a commit hash is
|
|
383
387
|
shortened to 7 characters)
|
|
384
388
|
(`--name` overrides), prints `Run: <url>` and `Experiment: <id>` as soon as the experiment exists,
|
|
385
389
|
one line per case event (world created, agent started, world sealed), then
|
|
386
390
|
`Waiting for Hue checks...` and a table with one row per case: boolean metrics as `PASS`/`FAIL`,
|
|
387
391
|
numbers as values, text and category metrics as-is, an overall result per case and a pass count.
|
|
388
|
-
Failing cases print the scorer explanation.
|
|
392
|
+
Failing cases print the scorer explanation. An evaluator Hue records as not applicable to a case
|
|
393
|
+
(its outcome scoring has no outcome criteria or conversion rubric to grade there) shows `n/a` in
|
|
394
|
+
that case's columns and neither passes nor fails it, so in a mixed eval set a case is decided by
|
|
395
|
+
the evaluators that apply to it; the pass line counts the not-applicable results. A case that no
|
|
396
|
+
pinned evaluator applies to is an error that names what they need. `--baseline <experiment id|url>` adds improvement,
|
|
389
397
|
regression and unchanged counts with per-case deltas. `--json` prints one JSON document
|
|
390
398
|
(`experimentId`, `runId`, `runUrl`, `complete`, `cases`, `totals`, optional `baseline`) on stdout
|
|
391
|
-
and sends progress to stderr
|
|
399
|
+
and sends progress to stderr; each case lists its not-applicable evaluator versions in
|
|
400
|
+
`notApplicable`, and `totals.notApplicable` counts them; a case failed for its telemetry has `state: "error"`,
|
|
401
|
+
`passed: false` and
|
|
402
|
+
`telemetry: { code: "telemetry_not_accepted", issues: [{ signal, kind, status?, count }] }`. `--wait <seconds>` (default 300) bounds the verdict wait because
|
|
392
403
|
Hue-owned `world_outcome` checks are graded after the world seals. An experiment always covers
|
|
393
404
|
every case of the saved version; there is no case subset.
|
|
394
405
|
|
|
@@ -399,35 +410,83 @@ every case of the saved version; there is no case subset.
|
|
|
399
410
|
`HUE_EXECUTION_ID`, `HUE_ENVIRONMENT_RUN_ID`, `HUE_CASE_ID` and `HUE_CASE_KEY`, and
|
|
400
411
|
`{"inputs": ..., "config": ...}` on stdin. The child does not receive `HUE_API_KEY`, `HUE_MCP_KEY`
|
|
401
412
|
or any other Hue control-plane credential unless `--allow-hue-credentials` is passed; the rest of
|
|
402
|
-
the parent environment (model keys, application settings) is inherited.
|
|
413
|
+
the parent environment (model keys, application settings) is inherited. `HUE_CASE_DIR`,
|
|
414
|
+
`HUE_CASE_INPUTS` and `HUE_CASE_OUTPUT_DIR` name a private case directory with the layout direct
|
|
415
|
+
cases use: the case inputs, verified copies of the case's agent-visible pinned files under
|
|
416
|
+
`files/<role>/`, and `output/`, whose files are uploaded after the world seals (the command still
|
|
417
|
+
starts in the current directory). The case directory never holds the world token and is removed
|
|
418
|
+
after the case. Its stdout is the answer
|
|
403
419
|
(JSON when it parses, otherwise trimmed text; empty means no output); a non-zero exit or the
|
|
404
|
-
per-case `--timeout` (default 600 seconds) is a target failure.
|
|
420
|
+
per-case `--timeout` (default 600 seconds) is a target failure. A timed-out or interrupted command
|
|
421
|
+
is stopped as a whole process group on macOS and Linux: SIGTERM, then SIGKILL for anything still
|
|
422
|
+
running 5 seconds later, including an agent a compound command started after its shell exited;
|
|
423
|
+
the case settles only once nothing in the group is left. A command that exits normally but leaves
|
|
424
|
+
processes in its group has them stopped the same way before its answer and files are read. A
|
|
425
|
+
second Ctrl+C during that grace kills the group at once, removes the world case's files, the MCP
|
|
426
|
+
configuration file and the checkpoint locks, and exits with 130. The world token is never logged.
|
|
405
427
|
A world created while the deployment's simulation gateway is off gets the legacy `hue_sim_`
|
|
406
428
|
capability under the same `HUE_MCP_*` names. The agent key defaults to the slug of the command's
|
|
407
429
|
script name; `--revision` is sent to Hue as the agent revision of every world.
|
|
408
430
|
|
|
409
431
|
`--worker` registers the adapter through `runLocalAgent()` with key `--agent-key` (default: the
|
|
410
432
|
adapter filename slug), name `--agent-name` (default: the key), revision `--revision` (default:
|
|
411
|
-
`AGENT_REVISION`, then the Git `HEAD` short hash, then `dev`) and capability `environment:v1
|
|
412
|
-
prints the registration and each claimed run with its
|
|
413
|
-
Ctrl+C or `--max-runs <n>`, and prints the verdict table
|
|
414
|
-
apply; Hue chooses the pinned experiment. The worker exits 0
|
|
433
|
+
`AGENT_REVISION`, then the Git `HEAD` short hash, then `dev`) and capability `environment:v1`
|
|
434
|
+
plus any repeated `--capability <value>`, prints the registration and each claimed run with its
|
|
435
|
+
URL, executes runs launched from Hue until Ctrl+C or `--max-runs <n>`, and prints the verdict table
|
|
436
|
+
after each run. Selection flags do not apply; Hue chooses the pinned experiment. The worker exits 0
|
|
437
|
+
when it stops normally. Hue offers a case whose world comes with agent-visible files only to a
|
|
438
|
+
registration that declares `environment-files:v1` and `input:<extension>` for each file type, for
|
|
439
|
+
example `--capability environment-files:v1 --capability input:pdf`; the adapter or command then
|
|
440
|
+
receives the files as described above. Hue keeps each registered revision's capabilities fixed,
|
|
441
|
+
so declare new ones under a new `--revision`. A world pinned to provider profiles, a Gmail world
|
|
442
|
+
for example, needs a reviewed `attemptBaselineV2` (see
|
|
443
|
+
[Pinned provider-profile preflight](ENVIRONMENTS.md#pinned-provider-profile-preflight)); `--worker`
|
|
444
|
+
registers none, so put `"attemptBaselineV2"` in the run's configuration JSON when you launch the
|
|
445
|
+
run from Hue.
|
|
415
446
|
|
|
416
447
|
A Scenario or eval set whose dataset version is not saved cannot back an experiment: the command
|
|
417
448
|
exits 1 and asks for **Save eval-set version** in Hue or `--save-version`, which freezes that
|
|
418
449
|
version at its current revision. Connection settings are `HUE_API_KEY` and `HUE_BASE_URL`
|
|
419
450
|
(default `https://app.hue.run`), loaded from `--env-file <path>` (or its alias `--env-path`) first when given; `--origin`
|
|
420
|
-
overrides the origin. Telemetry content capture stays off unless `--content` is passed;
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
451
|
+
overrides the origin. Telemetry content capture stays off unless `--content` is passed; the
|
|
452
|
+
examples pass it so the run's case spans carry content. Model and tool spans inside the agent come
|
|
453
|
+
only from the agent's own instrumentation. Case outputs, error messages and explanations are
|
|
454
|
+
stored in Hue whether or not `--content` is passed, so a case's answer can be graded and read on
|
|
455
|
+
its run page. A `--command`'s stdout is its answer unless it writes a result file, and is stored,
|
|
456
|
+
so it must not print credentials or debug logs there; before storing, `hue eval` replaces the
|
|
457
|
+
credentials it handed the case (the world token and MCP headers, a legacy MCP token, attempt
|
|
458
|
+
bearers) and every Hue control-plane credential in its environment with `[redacted]`, in the
|
|
459
|
+
answer, an adapter's thrown message and name, generated file names and the local checkpoint.
|
|
460
|
+
`--no-output` keeps outputs, error messages and explanations out of a one-shot run's stored
|
|
461
|
+
results; with `--content` the case span still carries the output. `--worker` always stores them, because a run launched from Hue is read
|
|
462
|
+
on its run page (that is `runLocalAgent()`'s contract), and refuses `--no-output`. An interrupted
|
|
463
|
+
one-shot run keeps the choice it started with, so one run never mixes stored and unstored outputs:
|
|
464
|
+
rerunning it with other `--no-output` or `--content` flags is refused with the flags it started
|
|
465
|
+
with. Resume a run that an earlier SDK started without `--content` by passing `--no-output`.
|
|
466
|
+
|
|
467
|
+
Files the agent writes to `output/` are uploaded as generated documents with or without
|
|
468
|
+
`--no-output`, and they are not redacted the way the answer is: `hue eval` replaces the same
|
|
469
|
+
credentials only in the UTF-8 `.txt`, `.csv` and `.json` documents it collects, while PDF, Office
|
|
470
|
+
and image documents, and files an adapter returns by `path`, are uploaded as written. A direct
|
|
471
|
+
case also keeps the agent's raw `output/` files on disk under its checkpoint directory
|
|
472
|
+
(`.hue/eval/<agent-key>/<project>/direct/<experiment>/files/`). Never write credentials to
|
|
473
|
+
`output/`.
|
|
474
|
+
|
|
475
|
+
Trace evidence is required for every case: when Hue does not accept a case's traces or logs, the
|
|
476
|
+
case is completed as failed (error `TelemetryNotAccepted`, evidence omitted as
|
|
477
|
+
`telemetry_not_accepted`, no output or generated files attached) instead of being left started,
|
|
478
|
+
and the run goes on. Stderr names the case as it completes, with the export
|
|
479
|
+
issue counts, for example
|
|
480
|
+
`[refund] telemetry not accepted, case failed: telemetry_not_accepted: traces failed 1 (HTTP 400)`;
|
|
481
|
+
the case counts as an error in the table and JSON whatever its scores, and the command exits 1.
|
|
482
|
+
Counts carry signals, kinds, HTTP statuses and record numbers only, never content or credentials.
|
|
425
483
|
Resumable checkpoints live in `.hue/eval/<agent-key>/<project id>/` (a `.gitignore` is written
|
|
426
484
|
inside `.hue/eval/`); `--checkpoint-dir` overrides the root. Rerunning the same selection resumes
|
|
427
485
|
an interrupted run without invoking the agent again; a different selection is refused until the
|
|
428
486
|
unfinished one is resumed or its directory is removed.
|
|
429
487
|
|
|
430
|
-
Exit codes: `0` every case passed, `1` a case failed, errored
|
|
488
|
+
Exit codes: `0` every case passed the evaluators that apply to it, `1` a case failed, errored
|
|
489
|
+
(including one no pinned evaluator applies to), was skipped or Hue's checks were
|
|
431
490
|
still pending at `--wait`, `2` usage or configuration error (including a missing key), `130`
|
|
432
491
|
interrupted. On Node.js 22, load TypeScript adapters with `NODE_OPTIONS=--experimental-strip-types`;
|
|
433
492
|
non-erasable syntax (enums, parameter properties, namespaces) needs a loader such as `--import tsx`
|
|
@@ -445,8 +504,8 @@ published version, beside or instead of explicit `--scorer-version` IDs.
|
|
|
445
504
|
```sh
|
|
446
505
|
hue eval --set gia-d1-citation --scorer gia-d1-citation \
|
|
447
506
|
--command "pnpm --filter @august/frontend run hue:gia-agent" \
|
|
448
|
-
--revision prompt-v10 --wait 1800 --json --env-file .env.hue
|
|
449
|
-
hue eval --set gia-d1-citation --set-version 1 --scorer gia-d1-citation ./hue-agent.ts --baseline <experiment id>
|
|
507
|
+
--revision prompt-v10 --wait 1800 --content --json --env-file .env.hue
|
|
508
|
+
hue eval --set gia-d1-citation --set-version 1 --scorer gia-d1-citation ./hue-agent.ts --content --baseline <experiment id>
|
|
450
509
|
```
|
|
451
510
|
|
|
452
511
|
For each case the command is spawned once **inside a private case directory** with
|
|
@@ -469,6 +528,17 @@ the command's stdout is the output (JSON when it parses). A single generated fil
|
|
|
469
528
|
document by default. Model and provider credentials stay in the command's own environment; the
|
|
470
529
|
scoped case files are copies under `--checkpoint-dir` (default `.hue/eval/<agent-key>/<project>/direct/<experiment>`).
|
|
471
530
|
|
|
531
|
+
The same collection serves world cases, and it does not trust paths the agent controls. `output/`
|
|
532
|
+
must be a real directory, and a helper name, when present, a regular file; a symlink, FIFO or
|
|
533
|
+
directory in either place is the case's error. Symlinks and other special files among the
|
|
534
|
+
documents are skipped, as are hidden and lock entries. Every file is opened without following a
|
|
535
|
+
final symlink or blocking, must be the regular file the listing saw and within its limit (4 MiB
|
|
536
|
+
for a helper, 25 MiB for a document, checked before reading), and its upload is staged from the
|
|
537
|
+
bytes read. A file or directory that vanished or changed while it was collected, more than 32
|
|
538
|
+
documents or more than 1024 entries is the case's error too. A hard link is an ordinary file and
|
|
539
|
+
is collected like one: an agent running as your user could copy the file just as well, so run an
|
|
540
|
+
agent that must not reach your files under another account or in a sandbox.
|
|
541
|
+
|
|
472
542
|
An adapter file works too: it is called with `(inputs, context)` where `context.mode` is
|
|
473
543
|
`"direct"` and `context` carries `config`, `item`, `executionId`, `files` (agent-visible pinned
|
|
474
544
|
files on disk), `outputDirectory` and `signal`. Return a JSON value, or `withFiles(output, files)`
|
|
@@ -478,5 +548,6 @@ Code evaluators pinned to the run are **not** executed on your machine: the CLI
|
|
|
478
548
|
deferred (`deferUnboundLocalScorers`) and Hue's grading executor scores the uploaded documents;
|
|
479
549
|
evaluator-only pinned files such as a legal corpus are never downloaded. `Waiting for Hue
|
|
480
550
|
checks...` then covers that grading, so size `--wait` to the evaluator's runtime. The
|
|
481
|
-
`--json` document gains `"mode": "direct"` and `"deferredScorerVersionIds"`. Exit codes, `--baseline
|
|
482
|
-
and checkpoints behave as for Scenarios
|
|
551
|
+
`--json` document gains `"mode": "direct"` and `"deferredScorerVersionIds"`. Exit codes, `--baseline`,
|
|
552
|
+
`--content`, `--no-output` and checkpoints behave as for Scenarios; generated documents are
|
|
553
|
+
uploaded with or without them.
|
package/ENVIRONMENTS.md
CHANGED
|
@@ -62,7 +62,7 @@ to the callback and is never written to checkpoints.
|
|
|
62
62
|
|
|
63
63
|
### Published pins and verdicts
|
|
64
64
|
|
|
65
|
-
`
|
|
65
|
+
`definition: { kind: "pins", datasetVersionId, scorerVersionIds, config?, name? }` runs already
|
|
66
66
|
published immutable pins, such as a Scenario's frozen case and Hue-owned outcome checks or a saved
|
|
67
67
|
eval set with explicitly chosen scorer versions. `resolveScenarioPins(client, selector)` reads
|
|
68
68
|
those pins from a Scenario ID, its Hue URL or its name (`listScenarios` and `getScenario` expose
|
|
@@ -76,9 +76,11 @@ bound `local_code` pins.
|
|
|
76
76
|
Hue grades `world_outcome` pins after the world seals, so the runner's report precedes the
|
|
77
77
|
verdicts. `waitForResults(client, { runId, scorerVersionIds, subjectIds, timeoutMillis })` polls
|
|
78
78
|
until every item has a terminal result for every pin or the budget elapses (`complete: false`);
|
|
79
|
-
`summarizeVerdicts` turns results into per-case rows with `passed` and totals;
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
`summarizeVerdicts` turns results into per-case rows with `passed` and totals; a result Hue marks
|
|
80
|
+
`notApplicable` (the evaluator has no outcome criteria or conversion rubric to grade in that case)
|
|
81
|
+
neither passes nor fails its case and is listed in the row's `notApplicable`, and a case no pinned
|
|
82
|
+
evaluator applies to is an error. `compareVerdicts` diffs two summaries by case key, and
|
|
83
|
+
`collectExperimentVerdicts` combines those reads for one experiment. The `hue eval` command uses the same path; see
|
|
82
84
|
[Evaluate an agent against a case](CLI.md#evaluate-an-agent-against-a-case).
|
|
83
85
|
|
|
84
86
|
### Pinned provider-profile preflight
|
|
@@ -223,6 +225,8 @@ its own Gmail MCP or REST client, the mirror URL, the world token where the Goog
|
|
|
223
225
|
import {
|
|
224
226
|
agentEnvironment,
|
|
225
227
|
createEnvironmentClient,
|
|
228
|
+
HueEnvironmentError,
|
|
229
|
+
isTransientEnvironmentError,
|
|
226
230
|
worldHandoff,
|
|
227
231
|
writeMcpConfig,
|
|
228
232
|
} from "@hue-run/sdk/environment";
|
|
@@ -252,12 +256,22 @@ try {
|
|
|
252
256
|
);
|
|
253
257
|
const sealDeadline = Date.now() + 30_000;
|
|
254
258
|
let sealed = false;
|
|
255
|
-
while (Date.now() < sealDeadline) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
+
while (!sealed && Date.now() < sealDeadline) {
|
|
260
|
+
let wait = 250;
|
|
261
|
+
try {
|
|
262
|
+
// The deadline also ends a read that hangs, with the client's retries inside it.
|
|
263
|
+
const state = await environmentClient.getRun(run.id, {
|
|
264
|
+
signal: AbortSignal.timeout(Math.max(0, sealDeadline - Date.now())),
|
|
265
|
+
});
|
|
266
|
+
sealed = state.status !== "open";
|
|
267
|
+
} catch (error) {
|
|
268
|
+
if (!isTransientEnvironmentError(error)) throw error; // a refusal such as 404 is final
|
|
269
|
+
wait = Math.max(wait, (error as HueEnvironmentError).retryAfterMs ?? 0);
|
|
259
270
|
}
|
|
260
|
-
|
|
271
|
+
if (!sealed)
|
|
272
|
+
await new Promise((resolve) =>
|
|
273
|
+
setTimeout(resolve, Math.min(wait, Math.max(0, sealDeadline - Date.now()))),
|
|
274
|
+
);
|
|
261
275
|
}
|
|
262
276
|
if (!sealed) throw new Error("World was not sealed after its completion grace");
|
|
263
277
|
}
|
|
@@ -272,6 +286,27 @@ world token, so an adapter that read `HUE_MCP_URL` and `HUE_MCP_TOKEN` keeps wor
|
|
|
272
286
|
no Hue-native `tools` (Hue refuses them); a world created while the gateway is off keeps its tools
|
|
273
287
|
and the `hue_sim_` capability and emits a one-time `DeprecationWarning`.
|
|
274
288
|
|
|
289
|
+
A case pinned to a world may also pin input files. Before the case's execution starts, the
|
|
290
|
+
helpers download each agent-visible file (`source`, `attached_template`, `attached_reference`,
|
|
291
|
+
`original`), verify its size and SHA-256 against the case manifest and hand the verified copies to
|
|
292
|
+
the callback as `context.files` beside `context.world`, in a private directory (mode 0700, files
|
|
293
|
+
0600), with a private `context.outputDirectory`. Evaluator-only files (`org_template`,
|
|
294
|
+
`evaluator_reference`) never reach the agent; a local code evaluator's copies are checked before
|
|
295
|
+
the execution starts but saved only after the agent finished. Bytes that differ from the manifest raise
|
|
296
|
+
`CaseFileError` with code `case_file_mismatch`; a name that is not one safe file name (a path
|
|
297
|
+
separator, `.` or `..`, a C0 or C1 control character, a character Windows reserves such as `:` or
|
|
298
|
+
`?`, a Windows device name such as `CON`, a trailing dot or space, more than 200 bytes) raises
|
|
299
|
+
`case_file_name_refused`. Either stops the run before an
|
|
300
|
+
execution or world exists for the case. Return `withFiles(output, files)` to upload what the agent
|
|
301
|
+
produced: the files are published and linked to the execution as `artifactIds` and
|
|
302
|
+
`primaryArtifactId`, within the limits of direct cases (at most 32 files, 25 MiB each, the
|
|
303
|
+
accepted document types). The world token is never written into the case directory, which is
|
|
304
|
+
removed when the case ends; only staged outputs an interrupted upload resumes from are kept until
|
|
305
|
+
it does. `hue eval --command` receives the same files through
|
|
306
|
+
`HUE_CASE_DIR`, `HUE_CASE_INPUTS` and `HUE_CASE_OUTPUT_DIR`. A `runLocalAgent` worker is offered
|
|
307
|
+
such cases only when it declares `environment-files:v1` and `input:<extension>` for each file
|
|
308
|
+
type; see [EVALUATIONS.md](EVALUATIONS.md#direct-cases-and-files).
|
|
309
|
+
|
|
275
310
|
A refusal such as 409 `simulation_gateway_required` exposes its validated server code as `HueEnvironmentError.diagnostic`.
|
|
276
311
|
|
|
277
312
|
`agentEnvironment` removes Hue control-plane credentials from the child by default: `HUE_API_KEY`,
|
package/EVALUATIONS.md
CHANGED
|
@@ -18,7 +18,8 @@ import { builtins, createEvaluationClient, runExperiment, rescore } from "@hue-r
|
|
|
18
18
|
|
|
19
19
|
const connection = { apiKey: process.env.HUE_API_KEY! };
|
|
20
20
|
const client = createEvaluationClient(connection);
|
|
21
|
-
|
|
21
|
+
// captureContent: false sends metadata only.
|
|
22
|
+
const hue = createHue({ ...connection, serviceName: "evaluation-demo", captureContent: true });
|
|
22
23
|
|
|
23
24
|
// Registry writes use optimistic revisions; they do not have automatic retries.
|
|
24
25
|
const dataset = await client.createDataset({ name: "Greetings", slug: "greetings" });
|
|
@@ -115,7 +116,7 @@ Both choices are required and independent:
|
|
|
115
116
|
|
|
116
117
|
Frozen dataset inputs/references already exist on Hue. Their presence is independent of these switches. No output is inferred from telemetry. JavaScript `undefined` means unavailable output; JSON `null`, false, zero and empty string remain present values. Historical subjects with unavailable output produce skipped results without executing a scorer callback. A failed quality metric remains `state:"scored"` with `passed:false`. Target errors and scorer errors remain separate. Target error types are generalized to `TargetError`; when content is enabled, bounded messages may be stored. Never put credentials in error messages, output, custom metric values, names or metadata.
|
|
117
118
|
|
|
118
|
-
`traceEvidence:{mode:"required"}` waits for trace and log export acknowledgement after the root span ends. The explicit alternative `{mode:"omit",reason:"..."}` stores the omission reason and declared trace ID without a fake snapshot. It can complete despite an export failure; export diagnostics remain available on the Hue client. There is no automatic fallback to omission.
|
|
119
|
+
`traceEvidence:{mode:"required"}` waits for trace and log export acknowledgement after the root span ends. The explicit alternative `{mode:"omit",reason:"..."}` stores the omission reason and declared trace ID without a fake snapshot. It can complete despite an export failure; export diagnostics remain available on the Hue client. There is no automatic fallback to omission. When required telemetry is not accepted, the runner by default keeps the saved outcome, leaves the execution started and rejects (`traceNotAccepted: "stop"`). With `traceNotAccepted: "fail_case"` it instead completes that case as failed (a `TelemetryNotAccepted` error, the evidence omitted with a reason starting `telemetry_not_accepted`, and no output or generated files attached, so no scorer can pass it), calls `onTelemetryNotAccepted(entry)` once, as soon as it completes the case (a resumed call only lists it), lists it in `report.telemetryNotAccepted` with sanitized issue counts, and goes on; `hue eval` uses this. A scorer that grades only the world can still score such a case, so treat a listed case as failed whatever its results say, as `hue eval` does.
|
|
119
120
|
|
|
120
121
|
## Local scorers
|
|
121
122
|
|
|
@@ -192,7 +193,7 @@ The runner stops scheduling more cases after an operational failure and waits fo
|
|
|
192
193
|
|
|
193
194
|
## Verification boundaries
|
|
194
195
|
|
|
195
|
-
`scripts/verify-package.mjs` installs a real packed tarball outside the monorepo and runs HTTP contract tests against a synthetic service plus actual OpenTelemetry exporters. It checks two configurations, rescoring without target invocation, absent/null output, upload resume, uncertain execution, exclusive checkpoints, source/metric contracts, content policy and terminating schema workers. It also exercises the local worker's ready, incomplete and uncertain provider-attempt control-plane paths, but does not call an issued provider facade. `scripts/verify-file-cases.mjs` runs against the same installed consumer: pinned input download and verification, artifact publication of a generated document, file-aware local scoring during the run and again on a later rescore,
|
|
196
|
+
`scripts/verify-package.mjs` installs a real packed tarball outside the monorepo and runs HTTP contract tests against a synthetic service plus actual OpenTelemetry exporters. It checks two configurations, rescoring without target invocation, absent/null output, upload resume, uncertain execution, exclusive checkpoints, source/metric contracts, content policy and terminating schema workers. It also exercises the local worker's ready, incomplete and uncertain provider-attempt control-plane paths, but does not call an issued provider facade. `scripts/verify-file-cases.mjs` runs against the same installed consumer: pinned input download and verification, artifact publication of a generated document, file-aware local scoring during the run and again on a later rescore, a declared file the target could not deliver recorded as the target's own error, and a worker world case that receives its agent-visible files with the world, uploads the returned document and refuses altered bytes as `case_file_mismatch`. `scripts/verify-evaluation-api.mjs` is a separate opt-in acceptance against a real Hue receiver/API; it creates synthetic datasets/scorers/experiments in the project associated with the supplied development key.
|
|
196
197
|
|
|
197
198
|
## Outbound local agent worker
|
|
198
199
|
|
|
@@ -215,7 +216,8 @@ import { createEvaluationClient, runLocalAgent } from "@hue-run/sdk/evals";
|
|
|
215
216
|
import { runMyAgent } from "./agent.js"; // Your existing application entry point.
|
|
216
217
|
|
|
217
218
|
const connection = { apiKey: process.env.HUE_API_KEY! };
|
|
218
|
-
|
|
219
|
+
// captureContent: false sends metadata only.
|
|
220
|
+
const hue = createHue({ ...connection, serviceName: "local-worker", captureContent: true });
|
|
219
221
|
try {
|
|
220
222
|
await runLocalAgent({
|
|
221
223
|
client: createEvaluationClient(connection),
|
|
@@ -233,7 +235,9 @@ try {
|
|
|
233
235
|
|
|
234
236
|
The callback receives cloned inputs, local tools, and an allowlisted context containing
|
|
235
237
|
`config`, `item: {id, externalKey}`, `executionId`, `environmentRunId`,
|
|
236
|
-
`trace: {traceId,spanId}
|
|
238
|
+
`trace: {traceId,spanId}`, a short-lived `mcp` capability, `files` (verified copies of the case's
|
|
239
|
+
agent-visible input files, empty when it has none) and a private `outputDirectory`; return
|
|
240
|
+
`withFiles(output, files)` to upload generated files, as for direct cases. Expected outcomes, case metadata
|
|
237
241
|
and original source pins remain private to grading. Pass the tools or scoped MCP capability into
|
|
238
242
|
the agent's actual tool boundary; their presence does not redirect provider calls. Capabilities
|
|
239
243
|
are not written to checkpoints. `maxRuns` limits completed runs for one-shot workers, while
|
|
@@ -260,8 +264,8 @@ installed-registry-package to hosted-facade acceptance remains a post-publicatio
|
|
|
260
264
|
## Direct cases and files
|
|
261
265
|
|
|
262
266
|
Cases without a simulated world — document workflows whose inputs are a task plus pinned files —
|
|
263
|
-
run on the same runner under the same checkpoint rules.
|
|
264
|
-
|
|
267
|
+
run on the same runner under the same checkpoint rules. They shipped in `@hue-run/sdk` `0.5.0`
|
|
268
|
+
and require a Hue deployment that serves case `inputFiles` on experiment
|
|
265
269
|
items, subject `files`, and the artifact reservation, upload, completion and download APIs. The
|
|
266
270
|
Python SDK has no equivalent.
|
|
267
271
|
|
|
@@ -270,7 +274,14 @@ On the outbound worker, supply `directTarget` beside or instead of `target`. Sup
|
|
|
270
274
|
`environment:v1` (both strings are exported as `localAgentCapabilities`). Declare the file
|
|
271
275
|
capabilities the agent accepts and returns — `input:docx`, `input:pdf`, `output:docx` and so on — so
|
|
272
276
|
Hue matches them against each case's `hue.requiredCapabilities` metadata and offers only matching
|
|
273
|
-
cases.
|
|
277
|
+
cases. A case pinned to a world whose manifest also holds agent-visible files is offered only to a
|
|
278
|
+
registration that declares `environment-files:v1` (`localAgentCapabilities.environmentFiles`)
|
|
279
|
+
and `input:<extension>` for each file; `target` then receives them as `context.files` with the
|
|
280
|
+
world, as described in
|
|
281
|
+
[ENVIRONMENTS.md](ENVIRONMENTS.md#worlds-served-by-the-simulation-gateway). The worker never adds
|
|
282
|
+
`environment-files:v1` itself: Hue keeps each registered revision's capabilities fixed, so declare
|
|
283
|
+
it under a new revision. `registeredCapabilities` refuses a registration that names a capability
|
|
284
|
+
without its callback.
|
|
274
285
|
|
|
275
286
|
```ts
|
|
276
287
|
import { basename } from "node:path";
|
|
@@ -312,16 +323,23 @@ The direct callback receives cloned inputs and an allowlisted context of `config
|
|
|
312
323
|
plus the worker's `signal` when one was supplied. Expected outcomes and case metadata stay with
|
|
313
324
|
grading, as they do for world cases.
|
|
314
325
|
|
|
315
|
-
Before an execution exists, `runExperiment` downloads
|
|
326
|
+
Before an execution exists, `runExperiment` downloads the pinned input files named by the frozen
|
|
316
327
|
case's `inputFiles` and verifies byte count and SHA-256. A download failure is an SDK failure and
|
|
317
|
-
consumes no execution slot;
|
|
318
|
-
|
|
319
|
-
|
|
328
|
+
consumes no execution slot; bytes that differ from the manifest raise `CaseFileError` with the
|
|
329
|
+
stable code `case_file_mismatch`, and a download stops one byte past the pinned size. A file
|
|
330
|
+
already saved with the pinned identity is reused instead of downloaded again. The target sees only the agent-visible roles — `source`,
|
|
331
|
+
`attached_template`, `attached_reference` and `original` — as `context.files`; evaluator-only
|
|
320
332
|
`org_template` and `evaluator_reference` files (an organization's template, a legal corpus, an
|
|
321
|
-
answer key) reach scorers but not the agent
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
333
|
+
answer key) reach scorers but not the agent. They are fetched only when a bound code evaluator
|
|
334
|
+
runs in this process: checked with the others before the execution starts but not kept, then
|
|
335
|
+
downloaded again and saved after the target finished, so they are not on disk while the agent
|
|
336
|
+
runs. An agent running as the same operating-system user
|
|
337
|
+
as the runner can still read whatever the runner can; run it under another account when local
|
|
338
|
+
evaluator material must stay out of its reach. Verified copies live under `filesDirectory` (default
|
|
339
|
+
`<checkpointDirectory>/files`, created mode 0700), evaluator-only files apart from the agent's, and
|
|
340
|
+
each case gets its own private `context.outputDirectory` to write into. The files of a case pinned
|
|
341
|
+
to a world are removed when it ends, except staged outputs an interrupted upload resumes from;
|
|
342
|
+
those of a direct case stay for inspection.
|
|
325
343
|
|
|
326
344
|
Return generated documents by wrapping the output in `withFiles(output, files)`. Each entry names a
|
|
327
345
|
`path` or in-memory `bytes`, a `filename`, a Hue-accepted `contentType` and at most one `primary`.
|
|
@@ -329,9 +347,11 @@ The runner copies them next to its checkpoint, publishes them through the artifa
|
|
|
329
347
|
upload and verified completion APIs with stable per-execution keys, and completes the execution with
|
|
330
348
|
`artifactIds` and `primaryArtifactId`, so the subject's frozen manifest holds inputs and outputs
|
|
331
349
|
together. Generated files are always uploaded regardless of `persistResultContent`: they are the
|
|
332
|
-
execution's evidence. A declared
|
|
333
|
-
|
|
334
|
-
|
|
350
|
+
execution's evidence. A declared `path` is read once, as a regular file (a symlink, FIFO or device
|
|
351
|
+
is refused) whose size is checked before reading, and staged owner-only from those bytes. A
|
|
352
|
+
declared file that cannot be read, exceeds 25 MiB, repeats a filename or has an unsupported
|
|
353
|
+
content type is saved as the target's error (`TargetError`), not as an uncertain execution. A
|
|
354
|
+
files directory must be owned by the current user and closed to everyone else (mode 0700). A crash after the target finished resumes from the staged files without invoking the
|
|
335
355
|
target again; if result content is not persisted, the JSON output cannot be reconstructed and the
|
|
336
356
|
case is reported as uncertain.
|
|
337
357
|
|
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ import { createHue, HueExportError } from "@hue-run/sdk";
|
|
|
35
35
|
const hue = createHue({
|
|
36
36
|
apiKey: process.env.HUE_API_KEY!, // a project service key, on the server only
|
|
37
37
|
serviceName: "my-agent",
|
|
38
|
-
captureContent:
|
|
38
|
+
captureContent: true, // required: true records content; false sends metadata only
|
|
39
39
|
onExportIssue: (issue) => console.error(issue), // sanitized counts, never server bodies
|
|
40
40
|
});
|
|
41
41
|
|
|
@@ -58,6 +58,11 @@ try {
|
|
|
58
58
|
await hue.shutdown(); // flushes and releases providers owned by this client
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
`captureContent` is required. The example sets `true`, the recommended choice: trace inspection,
|
|
62
|
+
evaluations and judges read the prompts, responses and tool inputs/outputs it records. Choose
|
|
63
|
+
`false` for metadata only when a policy forbids sending that content; see
|
|
64
|
+
[Privacy and content](#privacy-and-content).
|
|
65
|
+
|
|
61
66
|
The default destination is `https://app.hue.run`. Data goes to
|
|
62
67
|
`/api/v1/otlp/v1/traces` and `/api/v1/otlp/v1/logs` with a Bearer project key.
|
|
63
68
|
Set `baseUrl` only for another Hue deployment. It must be an origin without an API path; a trailing slash is accepted.
|
|
@@ -287,6 +292,12 @@ outputs and exports through Hue's attached processors keeps the label.
|
|
|
287
292
|
|
|
288
293
|
## Privacy and content
|
|
289
294
|
|
|
295
|
+
Set `captureContent: true` for full traces: prompts and messages, responses and tool inputs/outputs,
|
|
296
|
+
alongside model, usage, timing and errors. Trace inspection, evaluations and judges read that
|
|
297
|
+
content. Choose `false`, metadata-only mode, when your users decline or an application or data
|
|
298
|
+
policy forbids sending that content to another service. `redact` and the credential filtering
|
|
299
|
+
described below apply in both modes.
|
|
300
|
+
|
|
290
301
|
`captureContent: false` disables manual input/output/messages/tool content and
|
|
291
302
|
removes recognized GenAI, Vercel, OpenInference and OpenLLMetry content attributes,
|
|
292
303
|
legacy GenAI content events, log bodies, status messages and exception text before
|
|
@@ -306,12 +317,18 @@ an OpenAI hosted MCP tool. Before export, and before `redact`, Hue replaces the
|
|
|
306
317
|
credential-like fields including `authorization`, `authorization_token`, `headers`, `api_key`,
|
|
307
318
|
`access_token`, `x-api-key`, and keys ending in `token`, `secret`, `password`, `apikey` or
|
|
308
319
|
`credential` (case-insensitively, ignoring `-` and `_`) with `"[redacted]"` in recorded tool definitions
|
|
309
|
-
(`gen_ai.tool.definitions`, `ai.prompt.tools`, `llm.tools.*.tool.json_schema`) and in the
|
|
310
|
-
and `mcp_servers` entries of
|
|
311
|
-
`output.value` or `llm.invocation_parameters
|
|
320
|
+
(`gen_ai.tool.definitions`, `ai.prompt.tools`, `llm.tools.*.tool.json_schema`) and in the
|
|
321
|
+
top-level `tools` and `mcp_servers` entries of any JSON object recorded as `input.value`,
|
|
322
|
+
`output.value` or `llm.invocation_parameters`, whether or not it is a provider request; nothing
|
|
323
|
+
else in that object changes. Parameters named in a JSON Schema `properties`
|
|
312
324
|
object keep their schemas, so a tool that takes a `headers` argument is still described. A
|
|
313
325
|
definition nested more than 256 levels deep rejects its record. Sensitive `default`, `const`,
|
|
314
|
-
`examples` and `enum` values under credential-named schema parameters are redacted too.
|
|
326
|
+
`examples` and `enum` values under credential-named schema parameters are redacted too. A `url`
|
|
327
|
+
or `server_url` field (named like the credential fields, so `serverUrl` too) that has userinfo, a
|
|
328
|
+
query or a fragment loses its userinfo and fragment, and each query value becomes `[redacted]`
|
|
329
|
+
under its original name; the result is serialized as WHATWG `URL` does (lowercase scheme and
|
|
330
|
+
host, IDN hosts in Punycode, default ports dropped, dot segments resolved). A URL with none of
|
|
331
|
+
them is exported as recorded, and a value `URL` cannot parse becomes `"[redacted]"`.
|
|
315
332
|
|
|
316
333
|
With `captureContent: false`, export removes tool definitions but keeps a summary of them on the
|
|
317
334
|
same record: `hue.tool.names` lists each definition's `name` (Chat Completions `function.name`,
|
|
@@ -324,12 +341,18 @@ rotates. Only definitions another integration recorded can be summarized: `hueTe
|
|
|
324
341
|
inputs and exports through Hue's attached processors gets the summary.
|
|
325
342
|
Recorded messages can inline files: GenAI `blob` parts in `gen_ai.input.messages` /
|
|
326
343
|
`gen_ai.output.messages` (what the AI SDK 7 adapter records for a file part) and AI SDK 6 `file`
|
|
327
|
-
parts in `ai.prompt.messages`. A span whose messages exceed 256 KiB would be rejected, so
|
|
328
|
-
|
|
329
|
-
`sha256`
|
|
330
|
-
`
|
|
344
|
+
parts in `ai.prompt.messages`. A span whose messages exceed 256 KiB would be rejected, so when a
|
|
345
|
+
record is queued Hue replaces the `content`/`data` of any such part longer than 64 KiB with the
|
|
346
|
+
file's `sha256` and `size`, both of the file's own bytes whatever its media type (base64 content
|
|
347
|
+
and `;base64` `data:` URLs decoded, other `data:` URLs percent-decoded, anything else as UTF-8 text), keeping the part's other fields such as `type`, `mime_type` and `mediaType`. Smaller inline
|
|
331
348
|
files are exported as recorded. The digest matches `hue.recordFile`'s `hue.file.sha256` for the same
|
|
332
|
-
bytes, so a file can be recognized wherever it appears.
|
|
349
|
+
bytes, so a file can be recognized wherever it appears. The replacement happens before the record is
|
|
350
|
+
charged to the queue budget, so a large file does not drop its span. It is bounded: a message
|
|
351
|
+
attribute longer than 8 MiB of text is left unchanged, and the default 8 MiB `maxQueueBytes` then
|
|
352
|
+
drops the span. Base64 grows a file by a third, so that ceiling is an inline file of about 6 MiB.
|
|
353
|
+
The same message text is hashed once per record, and a record inspects at most 16 MiB of message
|
|
354
|
+
text in all; messages past that are charged as recorded. With `captureContent: false` the messages,
|
|
355
|
+
which export removes, are neither hashed nor charged.
|
|
333
356
|
|
|
334
357
|
Manual helpers encode JSON values without converting null into absence. Unknown
|
|
335
358
|
outputs and usage remain absent. This SDK does not estimate tokens or cost. A thrown
|
|
@@ -361,7 +384,7 @@ import { createHue, createHueTransport } from "@hue-run/sdk";
|
|
|
361
384
|
const transport = createHueTransport({
|
|
362
385
|
apiKey: process.env.HUE_API_KEY!,
|
|
363
386
|
serviceName: "existing-app",
|
|
364
|
-
captureContent: false
|
|
387
|
+
captureContent: true, // false sends metadata only
|
|
365
388
|
});
|
|
366
389
|
const tracerProvider = new TracerProvider({ spanProcessors: [transport.spanProcessor] });
|
|
367
390
|
const loggerProvider = new LoggerProvider({ processors: [transport.logRecordProcessor] });
|
|
@@ -576,9 +599,9 @@ an uncertain preparation. See the
|
|
|
576
599
|
an issued facade endpoint or the official Gmail service, and do not claim universal provider
|
|
577
600
|
parity.
|
|
578
601
|
|
|
579
|
-
|
|
580
|
-
verifies the case's pinned input files, hands them to the agent, and
|
|
581
|
-
returns as verified Hue artifacts for scoring. See
|
|
602
|
+
The `directTarget` callback, shipped in TypeScript `0.5.0`, extends the same worker to cases
|
|
603
|
+
without a world: the runner verifies the case's pinned input files, hands them to the agent, and
|
|
604
|
+
uploads the documents it returns as verified Hue artifacts for scoring. See
|
|
582
605
|
[direct cases and files](EVALUATIONS.md#direct-cases-and-files).
|
|
583
606
|
|
|
584
607
|
Scorer deferral shipped in TypeScript `0.3.1`. Only built-ins
|
|
@@ -591,17 +614,23 @@ their agents with `runLocalAgent()`; setup does not register workers or launch s
|
|
|
591
614
|
|
|
592
615
|
### Command-line evaluation
|
|
593
616
|
|
|
594
|
-
The
|
|
595
|
-
|
|
596
|
-
|
|
617
|
+
The `hue eval` command, shipped in TypeScript `0.5.0` (`--case` since `0.6.0`, `--scenario`
|
|
618
|
+
before), wraps `runSimulation()` and `runLocalAgent()` for an adapter file or a shell command:
|
|
619
|
+
`hue eval --case "<name>" ./hue-agent.ts --content` creates a fresh run from a published case's
|
|
620
|
+
immutable pins, runs the agent in one isolated world per case, waits
|
|
597
621
|
for Hue's outcome checks and prints the run URL and per-case PASS/FAIL verdicts with an exit code;
|
|
598
622
|
`--worker` registers the same adapter for runs launched from Hue. It needs a Read and
|
|
599
|
-
write key in `HUE_API_KEY` (never printed)
|
|
600
|
-
|
|
623
|
+
write key in `HUE_API_KEY` (never printed). Content capture stays off unless `--content` is
|
|
624
|
+
passed; the example passes it so case spans carry content. Case outputs, error messages and
|
|
625
|
+
explanations are stored in Hue either way (`--no-output` keeps them out of a one-shot run's
|
|
626
|
+
results); a command's stdout is its stored answer, with the credentials `hue eval` handed the case
|
|
627
|
+
replaced by `[redacted]`.
|
|
628
|
+
Instrument the agent itself for its model and tool spans. See
|
|
629
|
+
[Evaluate an agent against a case](CLI.md#evaluate-an-agent-against-a-case).
|
|
601
630
|
Eval sets whose cases pin files instead of a world run as direct cases through `runExperiment()`:
|
|
602
|
-
`hue eval --set <slug> --scorer <slug> --command "…"` hands the agent each case's
|
|
603
|
-
private directory, uploads the documents it writes and waits for Hue's grading
|
|
604
|
-
them. See [Evaluate a document eval set](CLI.md#evaluate-a-document-eval-set).
|
|
631
|
+
`hue eval --set <slug> --scorer <slug> --command "…" --content` hands the agent each case's
|
|
632
|
+
pinned files in a private directory, uploads the documents it writes and waits for Hue's grading
|
|
633
|
+
executor to score them. See [Evaluate a document eval set](CLI.md#evaluate-a-document-eval-set).
|
|
605
634
|
|
|
606
635
|
## Managed targets
|
|
607
636
|
|
|
@@ -38,10 +38,21 @@ export declare function stageDirectCase(root: string, input: {
|
|
|
38
38
|
executionId: string;
|
|
39
39
|
files: LocalFile[];
|
|
40
40
|
}): Promise<DirectCaseLayout>;
|
|
41
|
+
/** Test seams: `beforeEntry` runs before each listed entry is examined, `afterListing` between
|
|
42
|
+
* the listing and the reads. */
|
|
43
|
+
export interface CollectionSeams {
|
|
44
|
+
beforeEntry?: (name: string) => Promise<void>;
|
|
45
|
+
afterListing?: () => Promise<void>;
|
|
46
|
+
}
|
|
41
47
|
/**
|
|
42
48
|
* Turns the output folder into the target's result. Every regular file, in subdirectories too,
|
|
43
49
|
* becomes a generated file; an unsupported extension is the agent's error rather than a silently
|
|
44
50
|
* dropped document. `fallbackOutput` (for example the command's stdout) is used when no JSON
|
|
45
51
|
* output or summary file was written.
|
|
52
|
+
*
|
|
53
|
+
* Nothing here trusts a path the agent could have changed: the output directory must be a real
|
|
54
|
+
* directory, every file is opened without following a final symlink or blocking on a FIFO, must
|
|
55
|
+
* be the regular file the listing saw and within its size limit, and the result carries the bytes
|
|
56
|
+
* read from that open file. `seams` are for tests only.
|
|
46
57
|
*/
|
|
47
|
-
export declare function collectDirectOutputs(outputDirectory: string, fallbackOutput?: JsonValue): Promise<TargetResult>;
|
|
58
|
+
export declare function collectDirectOutputs(outputDirectory: string, fallbackOutput?: JsonValue, seams?: CollectionSeams): Promise<TargetResult>;
|