@hue-run/sdk 0.20.0 → 0.20.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.
@@ -1,3 +1,4 @@
1
+ import { type WorldPreparationProgress } from "./readiness.js";
1
2
  import type { ActionInput, ActionResult, CoverageGapInput, CoverageGapResult, CreateRunInput, Environment, PublishableEnvironmentDefinition, EnvironmentIdentity, EnvironmentPage, EnvironmentPageOptions, EnvironmentRun, EnvironmentSummary, EnvironmentVersion, EnvironmentVersionSummary, FinishRunInput, SealedRun, StepPage, StepPageOptions, WorldEvidence, WorldEvidenceOptions } from "./types.js";
2
3
  import type { PublishableWorldDefinition, WorldVersion } from "./definitions.js";
3
4
  /** Connection and retry options for {@link createEnvironmentClient}. */
@@ -19,13 +20,17 @@ export declare class HueEnvironmentError extends Error {
19
20
  readonly retryAfterMs?: number | undefined;
20
21
  /** The server's `X-Hue-Diagnostic` code, when it is a short snake-case value. */
21
22
  readonly diagnostic?: string | undefined;
23
+ /** Bounded, sanitized progress for a World preparation refusal. */
24
+ readonly preparation?: WorldPreparationProgress | undefined;
22
25
  constructor(
23
26
  /** HTTP status when Hue answered; absent for transport, timeout or parse failure. */
24
27
  status?: number | undefined,
25
28
  /** Hue's `Retry-After` in milliseconds, bounded, when a 429 or 503 carried one. */
26
29
  retryAfterMs?: number | undefined,
27
30
  /** The server's `X-Hue-Diagnostic` code, when it is a short snake-case value. */
28
- diagnostic?: string | undefined);
31
+ diagnostic?: string | undefined,
32
+ /** Bounded, sanitized progress for a World preparation refusal. */
33
+ preparation?: WorldPreparationProgress | undefined);
29
34
  }
30
35
  /** Starts one isolated instance from an immutable World version. */
31
36
  export interface CreateInstanceInput extends Omit<CreateRunInput, "environmentVersionId"> {
@@ -34,7 +39,7 @@ export interface CreateInstanceInput extends Omit<CreateRunInput, "environmentVe
34
39
  }
35
40
  /** A connection failure or a status the client retries; seal polling continues through these. */
36
41
  export declare function isTransientEnvironmentError(error: unknown): boolean;
37
- /** Typed client for authored environments, isolated runs and immutable journals. */
42
+ /** Typed client for authored Worlds, isolated World instances and immutable journals. */
38
43
  export declare class WorldClient {
39
44
  #private;
40
45
  /** Validated Hue origin. */
@@ -79,6 +84,12 @@ export declare class WorldClient {
79
84
  }>;
80
85
  /** Completes or abandons one instance and freezes its evidence. */
81
86
  finishInstance(instanceId: string, input: FinishRunInput): Promise<SealedRun>;
87
+ /** Creates a World identity using the client's resource routes. */
88
+ createWorld(input: EnvironmentIdentity): Promise<EnvironmentSummary>;
89
+ /** Lists active Worlds. */
90
+ listWorlds(page?: EnvironmentPageOptions): Promise<EnvironmentPage>;
91
+ /** Reads a World and its immutable version summaries. */
92
+ getWorld(id: string): Promise<Environment>;
82
93
  /** Creates an environment identity; this non-idempotent registry write is not retried. */
83
94
  createEnvironment(input: EnvironmentIdentity): Promise<EnvironmentSummary>;
84
95
  /** Lists active environment identities. */
@@ -1,3 +1,4 @@
1
+ import { readWorldPreparation, TERMINAL_WORLD_DIAGNOSTICS, } from "./readiness.js";
1
2
  import { validateOptions } from "../config.js";
2
3
  import { aggregateBounds, json, uuid, valueBounds } from "../evals/json.js";
3
4
  /** Sanitized environment API failure that never includes response text or credentials. */
@@ -5,19 +6,23 @@ export class HueEnvironmentError extends Error {
5
6
  status;
6
7
  retryAfterMs;
7
8
  diagnostic;
9
+ preparation;
8
10
  constructor(
9
11
  /** HTTP status when Hue answered; absent for transport, timeout or parse failure. */
10
12
  status,
11
13
  /** Hue's `Retry-After` in milliseconds, bounded, when a 429 or 503 carried one. */
12
14
  retryAfterMs,
13
15
  /** The server's `X-Hue-Diagnostic` code, when it is a short snake-case value. */
14
- diagnostic) {
16
+ diagnostic,
17
+ /** Bounded, sanitized progress for a World preparation refusal. */
18
+ preparation) {
15
19
  super(status
16
20
  ? `Hue environment request failed (HTTP ${status}${diagnostic ? `, ${diagnostic}` : ""})`
17
21
  : "Hue environment connection or response failed");
18
22
  this.status = status;
19
23
  this.retryAfterMs = retryAfterMs;
20
24
  this.diagnostic = diagnostic;
25
+ this.preparation = preparation;
21
26
  this.name = "HueEnvironmentError";
22
27
  }
23
28
  }
@@ -31,7 +36,8 @@ const RETRYABLE = new Set([408, 429, 500, 502, 503, 504]);
31
36
  /** A connection failure or a status the client retries; seal polling continues through these. */
32
37
  export function isTransientEnvironmentError(error) {
33
38
  return (error instanceof HueEnvironmentError &&
34
- (error.status === undefined || RETRYABLE.has(error.status)));
39
+ (error.status === undefined || RETRYABLE.has(error.status)) &&
40
+ !(error.status === 503 && TERMINAL_WORLD_DIAGNOSTICS.has(error.diagnostic ?? "")));
35
41
  }
36
42
  /** A `Retry-After` longer than this waits this long: Hue asks for a second, never minutes. */
37
43
  const MAX_RETRY_AFTER_MS = 10_000;
@@ -59,7 +65,7 @@ const REQUEST_BOUNDS = { ...valueBounds, bytes: 1024 * 1024 };
59
65
  * definition without relaxing action/run request envelopes.
60
66
  */
61
67
  const ENVIRONMENT_PUBLICATION_BOUNDS = aggregateBounds(240_000 + 32);
62
- /** Typed client for authored environments, isolated runs and immutable journals. */
68
+ /** Typed client for authored Worlds, isolated World instances and immutable journals. */
63
69
  export class WorldClient {
64
70
  /** Validated Hue origin. */
65
71
  baseUrl;
@@ -106,8 +112,9 @@ export class WorldClient {
106
112
  throw new HueEnvironmentError();
107
113
  }
108
114
  if (!response.ok) {
109
- await response.body?.cancel();
110
- throw new HueEnvironmentError(response.status, response.status === 429 || response.status === 503 ? retryAfterMillis(response) : undefined, diagnosticOf(response));
115
+ const diagnostic = diagnosticOf(response);
116
+ const preparation = await readWorldPreparation(response, diagnostic);
117
+ throw new HueEnvironmentError(response.status, response.status === 429 || response.status === 503 ? retryAfterMillis(response) : undefined, diagnostic, preparation);
111
118
  }
112
119
  try {
113
120
  const reader = response.body?.getReader();
@@ -246,6 +253,18 @@ export class WorldClient {
246
253
  finishInstance(instanceId, input) {
247
254
  return this.finishRun(instanceId, input);
248
255
  }
256
+ /** Creates a World identity using the client's resource routes. */
257
+ createWorld(input) {
258
+ return this.createEnvironment(input);
259
+ }
260
+ /** Lists active Worlds. */
261
+ listWorlds(page) {
262
+ return this.listEnvironments(page);
263
+ }
264
+ /** Reads a World and its immutable version summaries. */
265
+ getWorld(id) {
266
+ return this.getEnvironment(id);
267
+ }
249
268
  /** Creates an environment identity; this non-idempotent registry write is not retried. */
250
269
  createEnvironment(input) {
251
270
  return this.requestOnce("POST", "/environments", input);
@@ -1,3 +1,5 @@
1
+ import type { WorldModelProcessing, WorldPreparationProgress } from "./readiness.js";
2
+ export type { WorldModelProcessing, WorldPreparationProgress } from "./readiness.js";
1
3
  /** Project-scoped identity of the user or entity represented by a World model. */
2
4
  export interface WorldEntity {
3
5
  /** Identifier namespace, such as the application's user namespace. */
@@ -21,8 +23,10 @@ export interface WorldModel {
21
23
  lastUsedAt: string | null;
22
24
  /** Committed evidence sequence used for reconstruction. */
23
25
  evidenceCutoff: number;
24
- /** Publication or erasure state. */
26
+ /** Legacy retention or erasure state. Read `processing` for current indexing progress. */
25
27
  status: "ready" | "preparing" | "erased";
28
+ /** Retained and indexed progress, when reported by Hue. */
29
+ processing?: WorldModelProcessing;
26
30
  }
27
31
  /** One app account bound to a World model. */
28
32
  export interface WorldModelAccount {
@@ -53,7 +57,7 @@ export interface StartingWorld {
53
57
  evidenceCutoff: number;
54
58
  /** Immutable starting-state digest, or null while preparation is incomplete. */
55
59
  digest: string | null;
56
- /** Publication or erasure state. */
60
+ /** Starting-state preparation status. */
57
61
  status: "ready" | "preparing";
58
62
  }
59
63
  /** Bounded pagination over World models or their accounts. */
@@ -109,6 +113,8 @@ export interface WorldModelResult {
109
113
  export interface StartingWorldResult {
110
114
  /** Immutable starting state, or an explicit preparing state. */
111
115
  world: StartingWorld;
116
+ /** Progress of this requested starting World, when reported by Hue. */
117
+ preparation?: WorldPreparationProgress;
112
118
  }
113
119
  /** Acknowledgement that the World model has been erased. */
114
120
  export interface ErasedWorldModel {
@@ -1,5 +1,5 @@
1
1
  import { WorldClient, type WorldClientOptions } from "./client.js";
2
- import type { CreateWorldModelInput, WorldModelResult, StartingWorldResult, ErasedWorldModel, ReproduceWorldInstanceInput, StartingWorld, StartWorldInstanceInput, WorldModelAccountPage, WorldModelPage, WorldModelPageOptions } from "./model-types.js";
2
+ import type { CreateWorldModelInput, WorldModelResult, StartingWorldResult, ErasedWorldModel, ReproduceWorldInstanceInput, StartingWorld, StartWorldInstanceInput, WorldModelAccountPage, WorldModelPage, WorldModelPageOptions, WorldPreparationProgress } from "./model-types.js";
3
3
  import type { WorldHandoff } from "./types.js";
4
4
  /** Reconstructed starting World and its isolated runtime connection. */
5
5
  export interface WorldInstanceResult {
@@ -7,6 +7,8 @@ export interface WorldInstanceResult {
7
7
  world: StartingWorld;
8
8
  /** Fresh, instance-scoped connection and credentials. */
9
9
  instance: WorldHandoff;
10
+ /** Progress of this requested starting World, when reported by Hue. */
11
+ preparation?: WorldPreparationProgress;
10
12
  }
11
13
  /** Project-key client for entity histories, reconstructed Worlds and isolated instances. */
12
14
  export declare class WorldModelClient extends WorldClient {
@@ -0,0 +1,18 @@
1
+ /** Progress of one requested starting World. */
2
+ export interface WorldPreparationProgress {
3
+ /** Whether the request is preparing, usable, or waiting for changed evidence or dependencies. */
4
+ state: "preparing" | "insufficient_evidence" | "processing_limit" | "dependency_unavailable" | "ready";
5
+ /** Evidence cutoff selected for this request. */
6
+ selectedEvidenceCutoff: number;
7
+ /** Latest retained evidence cutoff. */
8
+ retainedEvidenceCutoff: number;
9
+ /** Latest indexed evidence cutoff for the current interpretation. */
10
+ readyEvidenceCutoff: number;
11
+ /** Whether retained evidence is still waiting for indexing. */
12
+ pendingEvidence: boolean;
13
+ }
14
+ /** Retained and indexed progress of an entity history. */
15
+ export interface WorldModelProcessing extends Omit<WorldPreparationProgress, "state" | "selectedEvidenceCutoff"> {
16
+ /** Indexing progress; a requested represented time may still lack required evidence. */
17
+ state: "indexed" | "preparing" | "insufficient_evidence" | "processing_limit" | "dependency_unavailable";
18
+ }
@@ -0,0 +1,69 @@
1
+ const diagnosticStates = {
2
+ world_preparing: "preparing",
3
+ world_insufficient_evidence: "insufficient_evidence",
4
+ world_processing_limit: "processing_limit",
5
+ world_dependency_unavailable: "dependency_unavailable",
6
+ };
7
+ /** @internal Only numeric progress and an allowlisted state cross the error boundary. */
8
+ export async function readWorldPreparation(response, diagnostic) {
9
+ if (response.status !== 503 || diagnostic === undefined || !(diagnostic in diagnosticStates)) {
10
+ await response.body?.cancel().catch(() => { });
11
+ return undefined;
12
+ }
13
+ const reader = response.body?.getReader();
14
+ if (!reader)
15
+ return undefined;
16
+ try {
17
+ const chunks = [];
18
+ let size = 0;
19
+ for (;;) {
20
+ const { done, value } = await reader.read();
21
+ if (done)
22
+ break;
23
+ size += value.byteLength;
24
+ if (size > 16 * 1024)
25
+ return undefined;
26
+ chunks.push(value);
27
+ }
28
+ const body = JSON.parse(Buffer.concat(chunks).toString("utf8"));
29
+ if (!body || typeof body !== "object" || !("preparation" in body))
30
+ return undefined;
31
+ const value = body.preparation;
32
+ if (!value || typeof value !== "object")
33
+ return undefined;
34
+ const { state, selectedEvidenceCutoff: selected, retainedEvidenceCutoff: retained, readyEvidenceCutoff: ready, pendingEvidence, } = value;
35
+ const expectedState = diagnosticStates[diagnostic];
36
+ if (expectedState === undefined ||
37
+ state !== expectedState ||
38
+ !Number.isSafeInteger(selected) ||
39
+ !Number.isSafeInteger(retained) ||
40
+ !Number.isSafeInteger(ready) ||
41
+ typeof selected !== "number" ||
42
+ typeof retained !== "number" ||
43
+ typeof ready !== "number" ||
44
+ selected < 0 ||
45
+ ready < 0 ||
46
+ selected > retained ||
47
+ ready > retained ||
48
+ pendingEvidence !== retained > ready)
49
+ return undefined;
50
+ return {
51
+ state: expectedState,
52
+ selectedEvidenceCutoff: selected,
53
+ retainedEvidenceCutoff: retained,
54
+ readyEvidenceCutoff: ready,
55
+ pendingEvidence,
56
+ };
57
+ }
58
+ catch {
59
+ return undefined;
60
+ }
61
+ finally {
62
+ await reader.cancel().catch(() => { });
63
+ }
64
+ }
65
+ /** @internal These failures require changed evidence or processing, not another identical call. */
66
+ export const TERMINAL_WORLD_DIAGNOSTICS = new Set([
67
+ "world_insufficient_evidence",
68
+ "world_processing_limit",
69
+ ]);
@@ -16,8 +16,9 @@ export declare function worldNow(source?: WorldHandoff | Record<string, string |
16
16
  /** Variables that authenticate against Hue's control plane rather than a simulated provider. */
17
17
  export declare const HUE_CONTROL_PLANE_VARIABLES: readonly string[];
18
18
  /** Prefixes of the Hue control-plane credentials the server issues: project and setup keys,
19
- * attempt grants, the project MCP key, invocation and installation tokens, and OAuth tokens and
20
- * secrets. World tokens (`hue_world_`) and MCP capabilities (`hue_sim_`) are what the agent holds. */
19
+ * attempt grants, the project MCP key, invocation and installation tokens, OAuth tokens, trace
20
+ * import authorizations and secrets. World tokens (`hue_world_`) and MCP capabilities
21
+ * (`hue_sim_`) are what the agent holds. */
21
22
  export declare const HUE_CONTROL_PLANE_CREDENTIAL_PREFIXES: readonly string[];
22
23
  /** True for a control-plane variable by name, or for a value carrying a Hue control-plane
23
24
  * credential anywhere in it, including wrapped, percent-encoded or JSON-Unicode-escaped values. */
@@ -53,8 +53,9 @@ export const HUE_CONTROL_PLANE_VARIABLES = [
53
53
  "HUE_SERVICE_KEY",
54
54
  ];
55
55
  /** Prefixes of the Hue control-plane credentials the server issues: project and setup keys,
56
- * attempt grants, the project MCP key, invocation and installation tokens, and OAuth tokens and
57
- * secrets. World tokens (`hue_world_`) and MCP capabilities (`hue_sim_`) are what the agent holds. */
56
+ * attempt grants, the project MCP key, invocation and installation tokens, OAuth tokens, trace
57
+ * import authorizations and secrets. World tokens (`hue_world_`) and MCP capabilities
58
+ * (`hue_sim_`) are what the agent holds. */
58
59
  export const HUE_CONTROL_PLANE_CREDENTIAL_PREFIXES = [
59
60
  "hue_sk_",
60
61
  "hue_attempt_",
@@ -64,6 +65,7 @@ export const HUE_CONTROL_PLANE_CREDENTIAL_PREFIXES = [
64
65
  "hue_install_",
65
66
  "hue_at_",
66
67
  "hue_rt_",
68
+ "hue_it_",
67
69
  "hue_oauth_",
68
70
  ];
69
71
  /** A Hue credential anywhere in a value, including JSON Unicode escapes, not inside a longer word. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hue-run/sdk",
3
- "version": "0.20.0",
3
+ "version": "0.20.2",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "publishConfig": {