@hue-run/sdk 0.19.1 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CLI.md +27 -10
  2. package/ENVIRONMENTS.md +5 -2
  3. package/EVALUATIONS.md +6 -1
  4. package/README.md +2 -2
  5. package/WORLDS.md +122 -0
  6. package/dist/cli/eval.d.ts +4 -0
  7. package/dist/cli/eval.js +434 -186
  8. package/dist/cli/listen.js +1 -1
  9. package/dist/environment/client.d.ts +2 -95
  10. package/dist/environment/client.js +2 -283
  11. package/dist/environment/tools.d.ts +2 -35
  12. package/dist/environment/tools.js +2 -30
  13. package/dist/environment/types.d.ts +2 -623
  14. package/dist/environment/types.js +2 -1
  15. package/dist/environment/world.d.ts +2 -65
  16. package/dist/environment/world.js +2 -171
  17. package/dist/environment.d.ts +7 -7
  18. package/dist/environment.js +3 -3
  19. package/dist/evals/attempt.d.ts +1 -1
  20. package/dist/evals/client.d.ts +3 -2
  21. package/dist/evals/client.js +2 -1
  22. package/dist/evals/environment-target.d.ts +3 -3
  23. package/dist/evals/environment-target.js +3 -3
  24. package/dist/evals/failure.js +1 -1
  25. package/dist/evals/local-worker.d.ts +8 -3
  26. package/dist/evals/local-worker.js +10 -2
  27. package/dist/evals/simulation.d.ts +6 -3
  28. package/dist/evals/simulation.js +2 -1
  29. package/dist/evals/types.d.ts +2 -2
  30. package/dist/version.d.ts +1 -1
  31. package/dist/version.js +1 -1
  32. package/dist/world/client.d.ts +150 -0
  33. package/dist/world/client.js +368 -0
  34. package/dist/world/definitions.d.ts +47 -0
  35. package/dist/world/definitions.js +1 -0
  36. package/dist/world/model-types.d.ts +117 -0
  37. package/dist/world/model-types.js +1 -0
  38. package/dist/world/models.d.ts +40 -0
  39. package/dist/world/models.js +56 -0
  40. package/dist/world/tools.d.ts +35 -0
  41. package/dist/world/tools.js +30 -0
  42. package/dist/world/types.d.ts +625 -0
  43. package/dist/world/types.js +1 -0
  44. package/dist/world/world.d.ts +65 -0
  45. package/dist/world/world.js +175 -0
  46. package/dist/world.d.ts +13 -0
  47. package/dist/world.js +5 -0
  48. package/package.json +8 -2
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.19.1`, `@opentelemetry/api@1.9.1` and
45
+ not a completed integration. TypeScript uses `@hue-run/sdk@0.20.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
 
@@ -379,8 +379,8 @@ and Hue never receives or stores them. The command is part of the `hue` executab
379
379
  # LANGFUSE_PUBLIC_KEY=pk-lf-...
380
380
  # LANGFUSE_SECRET_KEY=sk-lf-...
381
381
  # LANGFUSE_BASE_URL=https://cloud.langfuse.com
382
- npx -y @hue-run/sdk@0.19.1 import langfuse --env-path .env.langfuse --from 2026-01-01 --dry-run
383
- npx -y @hue-run/sdk@0.19.1 import langfuse --env-path .env.langfuse --from 2026-01-01 --media
382
+ npx -y @hue-run/sdk@0.20.0 import langfuse --env-path .env.langfuse --from 2026-01-01 --dry-run
383
+ npx -y @hue-run/sdk@0.20.0 import langfuse --env-path .env.langfuse --from 2026-01-01 --media
384
384
  ```
385
385
 
386
386
  `LANGFUSE_PUBLIC_KEY` and `LANGFUSE_SECRET_KEY` come from the environment or `--env-path`
@@ -595,7 +595,7 @@ node packages/sdk-typescript/scripts/verify-package.mjs --artifacts-dir .artifac
595
595
  # Set project to an existing supported fixture; use the same directory on resume.
596
596
  project=/absolute/path/to/supported-fixture
597
597
  node packages/sdk-typescript/scripts/verify-setup-live.mjs \
598
- --archive .artifacts/typescript/hue-run-sdk-0.19.1.tgz \
598
+ --archive .artifacts/typescript/hue-run-sdk-0.20.0.tgz \
599
599
  --origin https://STAGING_ORIGIN \
600
600
  --project "$project" --command setup \
601
601
  --evidence .context/setup-staging-before-claim.json
@@ -606,7 +606,7 @@ the private local handoff and finish the real browser claim, then reconcile the
606
606
 
607
607
  ```sh
608
608
  node packages/sdk-typescript/scripts/verify-setup-live.mjs \
609
- --archive .artifacts/typescript/hue-run-sdk-0.19.1.tgz \
609
+ --archive .artifacts/typescript/hue-run-sdk-0.20.0.tgz \
610
610
  --origin https://STAGING_ORIGIN \
611
611
  --project "$project" --command claim \
612
612
  --evidence .context/setup-staging-after-claim.json
@@ -648,10 +648,10 @@ otherwise. Never hand the agent Hue-native tools (`context.tools`, `context.mcp`
648
648
  production agent lacks. Pin the SDK, so the agent's repository gains no dependency:
649
649
 
650
650
  ```sh
651
- npx -y @hue-run/sdk@0.19.1 eval --case "Refund an eligible charge" --command "node agent.js"
652
- npx -y @hue-run/sdk@0.19.1 eval --case https://app.hue.run/projects/demo/scenarios/<id> --command "python agent.py" --timeout 120 --baseline <run id>
653
- npx -y @hue-run/sdk@0.19.1 eval --set "Billing regressions" --scorer-version <id> --command "node agent.js" --save-version
654
- npx -y @hue-run/sdk@0.19.1 eval --worker --command "node agent.js" --agent-key support-agent --revision <new-agent-revision>
651
+ npx -y @hue-run/sdk@0.20.0 eval --case "Refund an eligible charge" --command "node agent.js"
652
+ npx -y @hue-run/sdk@0.20.0 eval --case https://app.hue.run/projects/demo/scenarios/<id> --command "python agent.py" --timeout 120 --baseline <run id>
653
+ npx -y @hue-run/sdk@0.20.0 eval --set "Billing regressions" --scorer-version <id> --command "node agent.js" --save-version
654
+ npx -y @hue-run/sdk@0.20.0 eval --worker --command "node agent.js" --agent-key support-agent --revision <new-agent-revision>
655
655
  ```
656
656
 
657
657
  One invocation creates one run holding every selected case; it prints the run URL
@@ -689,7 +689,7 @@ export default function runMyAgent(inputs: JsonValue, context: SimulationTargetC
689
689
  ```
690
690
 
691
691
  ```sh
692
- npx -y @hue-run/sdk@0.19.1 eval --case "Refund an eligible charge" ./hue-agent.ts --content
692
+ npx -y @hue-run/sdk@0.20.0 eval --case "Refund an eligible charge" ./hue-agent.ts --content
693
693
  ```
694
694
 
695
695
  `--scenario` remains an alias for `--case` for existing scripts. Pass one selection flag.
@@ -731,6 +731,23 @@ former; a case failed for its telemetry has `state: "error"`,
731
731
  Hue-owned `world_outcome` checks are graded after the world seals. An experiment always covers
732
732
  every case of the saved version; there is no case subset.
733
733
 
734
+ `--judges` requests the run's pinned
735
+ `llm_judge` evaluators after outputs upload, before verdict polling. It is off by default and
736
+ works in direct, simulation and worker modes. Requests use the project's hosted judge budget;
737
+ Hue applies its admission controls to new jobs. An accepted request remains replayable if the
738
+ budget is later disabled. Cases without stored output are excluded, and combining
739
+ `--judges` with `--no-output` is refused. `--check` creates no judge jobs.
740
+
741
+ With `--judges --wait 0`, the CLI requests the jobs and returns their current verdict state;
742
+ pending jobs continue in Hue. Uploaded outputs are checkpointed before the attempt or worker
743
+ queue is marked completed. If this handoff or dispatch fails, or its acknowledgement is lost,
744
+ rerun the unchanged command with the same checkpoint directory. The CLI resumes judging the uploaded
745
+ outputs without invoking the agent, using the same idempotency keys. After dispatch succeeds,
746
+ the next ordinary invocation starts a new run as usual.
747
+
748
+ `--worker --judges` discards cancelled or released handoffs. Once judge requests succeed, a
749
+ verdict-read failure is logged and the worker keeps accepting runs.
750
+
734
751
  `--command "<shell command>"` spawns the command once per case with the world's environment
735
752
  (`HUE_WORLD_ID`, `HUE_WORLD_TOKEN`, `HUE_WORLD_NOW` (the world's clock at creation, RFC 3339; `worldNow()` reads it and returns
736
753
  `null` without it, so fall back explicitly with `worldNow() ?? new Date()`), one `HUE_SIM_<SURFACE ID>_URL` per provider
package/ENVIRONMENTS.md CHANGED
@@ -1,6 +1,6 @@
1
- # Simulated environments
1
+ # Simulated worlds: compatible client
2
2
 
3
- The provider-aware environment APIs shipped in TypeScript `0.3.0` and are publicly available:
3
+ The provider-aware APIs shipped in TypeScript `0.3.0` and are publicly available:
4
4
 
5
5
  ```bash
6
6
  npm install @hue-run/sdk zod
@@ -10,6 +10,9 @@ Your agent runs in your process while a disposable simulated world runs in Hue.
10
10
  authoritative and records an ordered journal; Hue does not execute your agent code or provider
11
11
  credentials.
12
12
 
13
+ The `environment` module and its exported names remain supported for existing integrations.
14
+ The canonical client names for the next release are documented in [Worlds](WORLDS.md).
15
+
13
16
  ## Run a definition like a test
14
17
 
15
18
  `runSimulation` is the one-shot developer path. It calls your existing callback directly, so
package/EVALUATIONS.md CHANGED
@@ -104,6 +104,11 @@ resolution, a fresh linked world per case, local and hosted MCP tools, finalizat
104
104
  evidence and scoring while retaining this runner's checkpoint guarantees. See
105
105
  [Simulated environments](ENVIRONMENTS.md#run-a-definition-like-a-test).
106
106
 
107
+ The `onUploaded` callback in `runSimulation` and `runLocalAgent` supports durable
108
+ application handoffs after outputs upload and before the attempt or worker queue is marked
109
+ completed. A callback failure stops completion and preserves the uploaded work for recovery.
110
+ The callback may run again after an interruption, so make its writes idempotent.
111
+
107
112
  Cases whose inputs are a task plus pinned documents, and rescoring over documents a run already
108
113
  saved, use the same runner without a world. See [Direct cases and files](#direct-cases-and-files).
109
114
 
@@ -179,7 +184,7 @@ Scorer deferral shipped in TypeScript `0.3.1`: the local runner executes only th
179
184
 
180
185
  `world_outcome` pins (`hue.conversion_outcome.v1` and `.v2`, and the `hue.outcome_assertions.v2` and `.v3` case-outcome evaluators, `.v3` with its pinned judge in `config.judge`) run inside Hue and need no local callback or executable source digest. A supporting server owns their execution from saved world evidence. Legacy `local_code` pins still require the exact registered callback; changing the worker cannot convert those immutable pins into hosted ones.
181
186
 
182
- Manual results require a human session. Hosted model-judge dispatch is an explicit separate API operation: inspect `getJudgeBudget()`, then call `createJudgeJobs(runId,{idempotencyKey,jobs:[{evaluationItemId,scorerVersionId}]})`. `listJudgeJobs`, `getJudgeJob` and `cancelJudgeJob` expose job progress and cancellation requests. These methods never claim that local execution has hosted provenance. Hosted job endpoints are covered by HTTP contract tests here; live hosted model execution is a separate platform acceptance phase. `listResults` and `getResult` read recorded local or hosted results.
187
+ Manual results require a human session. Hosted model-judge dispatch is explicit: call `createJudgeJobs(runId,{idempotencyKey,jobs:[{evaluationItemId,scorerVersionId}]})`. Hue checks the project's budget when admitting new requests. `getJudgeBudget()` reports its current state, but replay an interrupted request with the same key and body even if that state changed. The [`hue eval --judges`](./CLI.md#evaluate-an-agent-against-a-case) option performs this dispatch after outputs upload; it is off by default. `listJudgeJobs`, `getJudgeJob` and `cancelJudgeJob` expose job progress and cancellation requests. These methods never claim that local execution has hosted provenance. Hosted job endpoints are covered by HTTP contract tests here; live hosted model execution is a separate platform acceptance phase. `listResults` and `getResult` read recorded local or hosted results.
183
188
 
184
189
  When present, the budget's `authentication` reports credential resolution only. An
185
190
  `available` status or `configured: true` does not prove that a provider accepted the
package/README.md CHANGED
@@ -536,8 +536,8 @@ the Langfuse project's own keys (`LANGFUSE_PUBLIC_KEY`, `LANGFUSE_SECRET_KEY`, a
536
536
  `HUE_API_KEY`:
537
537
 
538
538
  ```sh
539
- npx -y @hue-run/sdk@0.19.1 import langfuse --env-path .env.langfuse --from 2026-01-01 --dry-run
540
- npx -y @hue-run/sdk@0.19.1 import langfuse --env-path .env.langfuse --from 2026-01-01 --media
539
+ npx -y @hue-run/sdk@0.20.0 import langfuse --env-path .env.langfuse --from 2026-01-01 --dry-run
540
+ npx -y @hue-run/sdk@0.20.0 import langfuse --env-path .env.langfuse --from 2026-01-01 --media
541
541
  ```
542
542
 
543
543
  - It reads Langfuse Cloud and self-hosted v4 through the Observations API v2, and self-hosted v3
package/WORLDS.md ADDED
@@ -0,0 +1,122 @@
1
+ # Simulated worlds
2
+
3
+ The World clients require a Hue deployment that serves the canonical World and instance routes.
4
+ The [compatible environment client](ENVIRONMENTS.md) remains supported.
5
+
6
+ Your agent runs locally against an isolated hosted instance of a simulated world:
7
+
8
+ ```bash
9
+ npm install @hue-run/sdk zod
10
+ ```
11
+
12
+ Your agent runs in your process while a disposable simulated world runs in Hue. The world is
13
+ authoritative and records an ordered journal; Hue does not execute your agent code or provider
14
+ credentials.
15
+
16
+ A World is a reconstructed starting state. An instance is an isolated running copy of that
17
+ state. Starting another instance does not share the first instance's changes. The handoff's
18
+ legacy `worldId` field identifies the runtime instance, not a durable World model.
19
+
20
+ ## Reconstruct a user's World
21
+
22
+ The World model client requires the corresponding service routes. An entity's
23
+ namespace and full ID bind its history to the project identified by the service key.
24
+
25
+ ```ts
26
+ import { WorldModelClient } from "@hue-run/sdk/world";
27
+
28
+ const models = new WorldModelClient({ apiKey: process.env.HUE_API_KEY! });
29
+ const { worldModel } = await models.createModel({
30
+ entity: { namespace: "user", id: "user-123" },
31
+ });
32
+ const { world, instance } = await models.startInstance(worldModel.id, {
33
+ idempotencyKey: "review-user-123-at-t2",
34
+ at: "2026-10-17T12:00:00Z",
35
+ ttlSeconds: 600,
36
+ });
37
+ ```
38
+
39
+ `world.at` is the represented time. `world.evidenceCutoff` names the committed evidence used to
40
+ reconstruct it, including qualifying evidence from traces recorded later. A subsequent start
41
+ with a new idempotency key uses the latest completed reconstruction. Retrying the same key
42
+ replays the original start. `instance.id` identifies the isolated running copy.
43
+
44
+ `materialize(modelId, { at })` reconstructs without starting an instance.
45
+ `reproduceInstance(instance.id, { idempotencyKey })` starts a fresh isolated instance from the
46
+ original starting World. It does not copy the earlier instance's mutations or reuse its token.
47
+ Erased or unavailable starting data fails explicitly. `eraseModel(modelId)` revokes the model
48
+ and prevents its starting Worlds from being reproduced.
49
+
50
+ Materialization, instance creation and reproduction wait up to two minutes when Hue explicitly
51
+ reports that the World is preparing. Retries preserve the same request bytes and identity.
52
+ Other failures keep the client's `maxAttempts` limit. Pass `{ signal }` as the last options
53
+ argument to cancel a preparation wait or an active request.
54
+
55
+ `listModels` and `listAccounts` accept `after` and `limit` for pagination. Use each account's
56
+ `providerInstanceKey` to distinguish connections, including several accounts for one app.
57
+
58
+ ## Capture user and account identity
59
+
60
+ Automatic World capture requires a compatible service.
61
+ Your existing tracing remains valid without these attributes; unresolved identity does not become
62
+ World state.
63
+
64
+ Record the complete user ID on the request's root span with `userId`. For another entity kind,
65
+ set both `hue.world.entity.namespace` and `hue.world.entity.id` on that root. Tool observations
66
+ need an explicit connection binding on the actual tool span:
67
+
68
+ | Attribute | Value |
69
+ | --- | --- |
70
+ | `hue.connection.provider_id` | Registered app ID, such as `google.gmail`. |
71
+ | `hue.connection.account_id` | Your stable account or connection ID, scoped to this user and project. |
72
+ | `hue.connection.generation` | Positive integer identifying that connection generation. Increment when the connection is replaced. |
73
+ | `hue.connection.scope` | Optional app partition, such as a workspace. Keep it stable. |
74
+ | `hue.connection.principal` | The app's acting identity when its simulation requires one. |
75
+
76
+ For example, attach the binding inside an existing tool callback. `searchThreads` below is your
77
+ application's tool implementation:
78
+
79
+ ```ts
80
+ import { trace } from "@opentelemetry/api";
81
+ import { createHue } from "@hue-run/sdk";
82
+
83
+ const hue = createHue({
84
+ serviceName: "assistant",
85
+ apiKey: process.env.HUE_API_KEY!,
86
+ resourceAttributes: { "deployment.environment.name": "production" },
87
+ });
88
+
89
+ await hue.withSpan("assistant request", () =>
90
+ hue.tool("search_threads", { query: "project update" }, async () => {
91
+ trace.getSpan(hue.getContext())?.setAttributes({
92
+ "hue.connection.provider_id": "google.gmail",
93
+ "hue.connection.account_id": "connection-work",
94
+ "hue.connection.generation": 1,
95
+ "hue.connection.principal": "owner@example.test",
96
+ });
97
+ return searchThreads({ query: "project update" });
98
+ }, { mcp: { name: "gmail", provider: "google.gmail", surface: "mcp" } }),
99
+ { userId: "user-123" },
100
+ );
101
+ await hue.shutdownSafe();
102
+ ```
103
+
104
+ An attached client uses your application's existing OpenTelemetry resource; configure production
105
+ provenance there. Mark faithful production traffic accurately. Eval, simulation and excluded
106
+ traffic cannot populate a live user's World. Historical imports require separate trusted admission.
107
+
108
+ Use the same fields with your framework's tool-span hook. A parent-only account label cannot
109
+ resolve several accounts used by different tool calls. Account IDs and resource IDs stay separate;
110
+ a tool argument or matching email address alone does not establish a binding. Do not record
111
+ OAuth tokens or provider credentials in these fields.
112
+
113
+ ## Publish an authored World
114
+
115
+ `createWorldClient` also publishes authored definitions and starts instances from their
116
+ immutable versions. Use `WorldDefinitionV2` and `WorldProviderInstance` for arbitrary registered
117
+ apps and multiple accounts of the same app. The deployment validates each app's JSON
118
+ configuration and supported dialects.
119
+
120
+ The [compatible client guide](ENVIRONMENTS.md) covers authored definitions, action catalogs,
121
+ instance journals and simulation runners. Its examples use the retained environment client;
122
+ the canonical client uses the same request bodies through World and instance routes.
@@ -1,3 +1,4 @@
1
+ import { EvaluationClient } from "../evals/client.js";
1
2
  import type { ExperimentCase, LocalFile } from "../evals/types.js";
2
3
  import { TargetResult } from "../evals/types.js";
3
4
  import { type SimulationTargetContext } from "../evals/simulation.js";
@@ -51,6 +52,9 @@ export declare function spawnAgentCommand(command: string, options: {
51
52
  }): Promise<string>;
52
53
  export declare function renderTable(verdicts: ExperimentVerdicts, output: Output): void;
53
54
  export declare function explain(error: unknown): string;
55
+ /** Requests only the run's pinned model judges. Stable batches let an interrupted CLI resume
56
+ * dispatch without creating a second paid job for the same scoring item and evaluator. */
57
+ export declare function dispatchPinnedJudges(client: Pick<EvaluationClient, "getExperiment" | "listEvaluationItems" | "createJudgeJobs">, experimentId: string, subjectIds: string[], signal?: AbortSignal): Promise<number>;
54
58
  /**
55
59
  * `hue eval`: runs a local adapter or command against a Scenario or eval set through
56
60
  * `runSimulation`, or registers it as an outbound worker through `runLocalAgent`.