@hue-run/sdk 0.19.0 → 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.
- package/CLI.md +27 -10
- package/ENVIRONMENTS.md +5 -2
- package/EVALUATIONS.md +6 -1
- package/README.md +12 -4
- package/WORLDS.md +122 -0
- package/dist/blobs.d.ts +2 -1
- package/dist/blobs.js +7 -5
- package/dist/cli/eval.d.ts +4 -0
- package/dist/cli/eval.js +434 -186
- package/dist/cli/listen.js +1 -1
- package/dist/environment/client.d.ts +2 -95
- package/dist/environment/client.js +2 -283
- package/dist/environment/tools.d.ts +2 -35
- package/dist/environment/tools.js +2 -30
- package/dist/environment/types.d.ts +2 -623
- package/dist/environment/types.js +2 -1
- package/dist/environment/world.d.ts +2 -65
- package/dist/environment/world.js +2 -171
- package/dist/environment.d.ts +7 -7
- package/dist/environment.js +3 -3
- package/dist/evals/attempt.d.ts +1 -1
- package/dist/evals/client.d.ts +3 -2
- package/dist/evals/client.js +2 -1
- package/dist/evals/environment-target.d.ts +3 -3
- package/dist/evals/environment-target.js +3 -3
- package/dist/evals/failure.js +1 -1
- package/dist/evals/local-worker.d.ts +8 -3
- package/dist/evals/local-worker.js +10 -2
- package/dist/evals/simulation.d.ts +6 -3
- package/dist/evals/simulation.js +2 -1
- package/dist/evals/types.d.ts +2 -2
- package/dist/inline-files.d.ts +21 -4
- package/dist/inline-files.js +100 -14
- package/dist/large-media.d.ts +2 -1
- package/dist/large-media.js +7 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/world/client.d.ts +150 -0
- package/dist/world/client.js +368 -0
- package/dist/world/definitions.d.ts +47 -0
- package/dist/world/definitions.js +1 -0
- package/dist/world/model-types.d.ts +117 -0
- package/dist/world/model-types.js +1 -0
- package/dist/world/models.d.ts +40 -0
- package/dist/world/models.js +56 -0
- package/dist/world/tools.d.ts +35 -0
- package/dist/world/tools.js +30 -0
- package/dist/world/types.d.ts +625 -0
- package/dist/world/types.js +1 -0
- package/dist/world/world.d.ts +65 -0
- package/dist/world/world.js +175 -0
- package/dist/world.d.ts +13 -0
- package/dist/world.js +5 -0
- package/package.json +8 -2
package/dist/cli/listen.js
CHANGED
|
@@ -5,7 +5,7 @@ import { request as httpsRequest } from "node:https";
|
|
|
5
5
|
import { isIP } from "node:net";
|
|
6
6
|
import { resolve } from "node:path";
|
|
7
7
|
import { parseArgs, parseEnv } from "node:util";
|
|
8
|
-
import { HUE_CONTROL_PLANE_VARIABLES } from "../
|
|
8
|
+
import { HUE_CONTROL_PLANE_VARIABLES } from "../world/world.js";
|
|
9
9
|
import { scrubCredentialText } from "../tool-definitions.js";
|
|
10
10
|
import { sdkVersion } from "../version.js";
|
|
11
11
|
import { envFileArgument, envFileOptions } from "./env-file.js";
|
|
@@ -1,95 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export interface EnvironmentClientOptions {
|
|
4
|
-
/** Project service key sent as a bearer token; server-side only. */
|
|
5
|
-
apiKey: string;
|
|
6
|
-
/** Hue origin; defaults to `https://app.hue.run`. */
|
|
7
|
-
baseUrl?: string;
|
|
8
|
-
/** Per-request deadline in milliseconds. */
|
|
9
|
-
timeoutMillis?: number;
|
|
10
|
-
/** Attempts for idempotent run mutations, 1–10; defaults to 4. */
|
|
11
|
-
maxAttempts?: number;
|
|
12
|
-
}
|
|
13
|
-
/** Sanitized environment API failure that never includes response text or credentials. */
|
|
14
|
-
export declare class HueEnvironmentError extends Error {
|
|
15
|
-
/** HTTP status when Hue answered; absent for transport, timeout or parse failure. */
|
|
16
|
-
readonly status?: number | undefined;
|
|
17
|
-
/** Hue's `Retry-After` in milliseconds, bounded, when a 429 or 503 carried one. */
|
|
18
|
-
readonly retryAfterMs?: number | undefined;
|
|
19
|
-
/** The server's `X-Hue-Diagnostic` code, when it is a short snake-case value. */
|
|
20
|
-
readonly diagnostic?: string | undefined;
|
|
21
|
-
constructor(
|
|
22
|
-
/** HTTP status when Hue answered; absent for transport, timeout or parse failure. */
|
|
23
|
-
status?: number | undefined,
|
|
24
|
-
/** Hue's `Retry-After` in milliseconds, bounded, when a 429 or 503 carried one. */
|
|
25
|
-
retryAfterMs?: number | undefined,
|
|
26
|
-
/** The server's `X-Hue-Diagnostic` code, when it is a short snake-case value. */
|
|
27
|
-
diagnostic?: string | undefined);
|
|
28
|
-
}
|
|
29
|
-
/** A connection failure or a status the client retries; seal polling continues through these. */
|
|
30
|
-
export declare function isTransientEnvironmentError(error: unknown): boolean;
|
|
31
|
-
/** Typed client for authored environments, isolated runs and immutable journals. */
|
|
32
|
-
export declare class EnvironmentClient {
|
|
33
|
-
#private;
|
|
34
|
-
/** Validated Hue origin. */
|
|
35
|
-
readonly baseUrl: string;
|
|
36
|
-
private readonly timeoutMillis;
|
|
37
|
-
private readonly maxAttempts;
|
|
38
|
-
constructor(options: EnvironmentClientOptions);
|
|
39
|
-
private send;
|
|
40
|
-
private request;
|
|
41
|
-
private requestOnce;
|
|
42
|
-
private page;
|
|
43
|
-
/** Creates an environment identity; this non-idempotent registry write is not retried. */
|
|
44
|
-
createEnvironment(input: EnvironmentIdentity): Promise<EnvironmentSummary>;
|
|
45
|
-
/** Lists active environment identities. */
|
|
46
|
-
listEnvironments(page?: EnvironmentPageOptions): Promise<EnvironmentPage>;
|
|
47
|
-
/** Reads one environment and its immutable version summaries. */
|
|
48
|
-
getEnvironment(id: string): Promise<Environment>;
|
|
49
|
-
/** Publishes an immutable definition; this non-idempotent registry write is not retried. */
|
|
50
|
-
publishVersion(environmentId: string, definition: PublishableEnvironmentDefinition): Promise<EnvironmentVersionSummary>;
|
|
51
|
-
/** Reads a full immutable environment version and generated action catalog. */
|
|
52
|
-
getVersion(id: string): Promise<EnvironmentVersion>;
|
|
53
|
-
/** Creates or recovers one fresh isolated world using a stable idempotency key. */
|
|
54
|
-
createRun(input: CreateRunInput): Promise<EnvironmentRun>;
|
|
55
|
-
/** Reads authoritative current or sealed world state. */
|
|
56
|
-
getRun(runId: string, options?: {
|
|
57
|
-
signal?: AbortSignal;
|
|
58
|
-
}): Promise<{
|
|
59
|
-
id: string;
|
|
60
|
-
environmentVersionId: string;
|
|
61
|
-
executionId: string | null;
|
|
62
|
-
seed: string;
|
|
63
|
-
status: "open" | "completed" | "abandoned" | "expired";
|
|
64
|
-
stepCount: number;
|
|
65
|
-
maxSteps: number;
|
|
66
|
-
clockNs: string;
|
|
67
|
-
expiresAt: string;
|
|
68
|
-
createdAt: string;
|
|
69
|
-
sealedAt: string | null;
|
|
70
|
-
stateDigest: string;
|
|
71
|
-
finalState?: import("./types.js").JsonValue;
|
|
72
|
-
worldId?: string;
|
|
73
|
-
lifecycle?: import("./types.js").WorldLifecycle;
|
|
74
|
-
completingUntil?: string | null;
|
|
75
|
-
traceExternalId?: string | null;
|
|
76
|
-
surfaces?: import("./types.js").WorldSurface[];
|
|
77
|
-
flags?: import("./types.js").WorldFlag[];
|
|
78
|
-
connection?: null;
|
|
79
|
-
validity: "environment_incomplete" | "not_assessed";
|
|
80
|
-
coverageGap: import("./types.js").CoverageGap | null;
|
|
81
|
-
}>;
|
|
82
|
-
/** Record a known coverage gap with durable identity; retries reuse the exact request. */
|
|
83
|
-
recordCoverageGap(runId: string, input: CoverageGapInput): Promise<CoverageGapResult>;
|
|
84
|
-
/** Invokes an action; repeating an invocation identity replays its recorded result. */
|
|
85
|
-
act(runId: string, input: ActionInput): Promise<ActionResult>;
|
|
86
|
-
/** Pages the immutable journal by step ordinal. */
|
|
87
|
-
listSteps(runId: string, page?: StepPageOptions): Promise<StepPage>;
|
|
88
|
-
/** Seals a world as completed or abandoned and freezes its evidence. */
|
|
89
|
-
finishRun(runId: string, input: FinishRunInput): Promise<SealedRun>;
|
|
90
|
-
/** Reads a sealed world's evaluator-only evidence with the project key; a world token never
|
|
91
|
-
* can. An open world answers 409 until it is sealed. */
|
|
92
|
-
getEvidence(runId: string, options?: WorldEvidenceOptions): Promise<WorldEvidence>;
|
|
93
|
-
}
|
|
94
|
-
/** Creates a typed simulated-environment client. */
|
|
95
|
-
export declare function createEnvironmentClient(options: EnvironmentClientOptions): EnvironmentClient;
|
|
1
|
+
/** Compatibility entry point. Use the world module. */
|
|
2
|
+
export * from "../world/client.js";
|
|
@@ -1,283 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/** Sanitized environment API failure that never includes response text or credentials. */
|
|
4
|
-
export class HueEnvironmentError extends Error {
|
|
5
|
-
status;
|
|
6
|
-
retryAfterMs;
|
|
7
|
-
diagnostic;
|
|
8
|
-
constructor(
|
|
9
|
-
/** HTTP status when Hue answered; absent for transport, timeout or parse failure. */
|
|
10
|
-
status,
|
|
11
|
-
/** Hue's `Retry-After` in milliseconds, bounded, when a 429 or 503 carried one. */
|
|
12
|
-
retryAfterMs,
|
|
13
|
-
/** The server's `X-Hue-Diagnostic` code, when it is a short snake-case value. */
|
|
14
|
-
diagnostic) {
|
|
15
|
-
super(status
|
|
16
|
-
? `Hue environment request failed (HTTP ${status}${diagnostic ? `, ${diagnostic}` : ""})`
|
|
17
|
-
: "Hue environment connection or response failed");
|
|
18
|
-
this.status = status;
|
|
19
|
-
this.retryAfterMs = retryAfterMs;
|
|
20
|
-
this.diagnostic = diagnostic;
|
|
21
|
-
this.name = "HueEnvironmentError";
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
const DIAGNOSTIC = /^[a-z_]{1,64}$/;
|
|
25
|
-
/** The response's diagnostic code, or undefined when absent or invalid. */
|
|
26
|
-
function diagnosticOf(response) {
|
|
27
|
-
const value = response.headers.get("x-hue-diagnostic");
|
|
28
|
-
return value !== null && DIAGNOSTIC.test(value) ? value : undefined;
|
|
29
|
-
}
|
|
30
|
-
const RETRYABLE = new Set([408, 429, 500, 502, 503, 504]);
|
|
31
|
-
/** A connection failure or a status the client retries; seal polling continues through these. */
|
|
32
|
-
export function isTransientEnvironmentError(error) {
|
|
33
|
-
return (error instanceof HueEnvironmentError &&
|
|
34
|
-
(error.status === undefined || RETRYABLE.has(error.status)));
|
|
35
|
-
}
|
|
36
|
-
/** A `Retry-After` longer than this waits this long: Hue asks for a second, never minutes. */
|
|
37
|
-
const MAX_RETRY_AFTER_MS = 10_000;
|
|
38
|
-
const TRACEPARENT = /^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$/;
|
|
39
|
-
/** Version 00 with real identifiers: an all-zero trace or span ID is invalid, and Hue refuses it. */
|
|
40
|
-
function validTraceparent(value) {
|
|
41
|
-
if (!TRACEPARENT.test(value))
|
|
42
|
-
return false;
|
|
43
|
-
const [, traceId, spanId] = value.split("-");
|
|
44
|
-
return !/^0+$/.test(traceId) && !/^0+$/.test(spanId);
|
|
45
|
-
}
|
|
46
|
-
/** Whole seconds only, as Hue sends them; a date or garbage is ignored. */
|
|
47
|
-
function retryAfterMillis(response) {
|
|
48
|
-
const header = response.headers.get("retry-after");
|
|
49
|
-
if (header === null || !/^\d{1,6}$/.test(header.trim()))
|
|
50
|
-
return undefined;
|
|
51
|
-
return Math.min(Number(header.trim()) * 1000, MAX_RETRY_AFTER_MS);
|
|
52
|
-
}
|
|
53
|
-
const MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
|
|
54
|
-
const REQUEST_BOUNDS = { ...valueBounds, bytes: 1024 * 1024 };
|
|
55
|
-
/** The server bounds JSON inside each entity independently, then permits the parsed
|
|
56
|
-
* definition to contain up to 240 KB. The publication wrapper adds one node/depth
|
|
57
|
-
* level and a small fixed byte prefix. Aggregate bounds cover every server-valid
|
|
58
|
-
* definition without relaxing action/run request envelopes.
|
|
59
|
-
*/
|
|
60
|
-
const ENVIRONMENT_PUBLICATION_BOUNDS = aggregateBounds(240_000 + 32);
|
|
61
|
-
/** Typed client for authored environments, isolated runs and immutable journals. */
|
|
62
|
-
export class EnvironmentClient {
|
|
63
|
-
/** Validated Hue origin. */
|
|
64
|
-
baseUrl;
|
|
65
|
-
#apiKey;
|
|
66
|
-
timeoutMillis;
|
|
67
|
-
maxAttempts;
|
|
68
|
-
constructor(options) {
|
|
69
|
-
const validated = validateOptions({
|
|
70
|
-
...options,
|
|
71
|
-
serviceName: "hue-environments",
|
|
72
|
-
captureContent: false,
|
|
73
|
-
});
|
|
74
|
-
this.baseUrl = validated.baseUrl;
|
|
75
|
-
this.#apiKey = validated.apiKey;
|
|
76
|
-
this.timeoutMillis = validated.timeoutMillis;
|
|
77
|
-
const attempts = options.maxAttempts ?? 4;
|
|
78
|
-
if (!Number.isInteger(attempts) || attempts < 1 || attempts > 10)
|
|
79
|
-
throw new RangeError("maxAttempts must be 1–10");
|
|
80
|
-
this.maxAttempts = attempts;
|
|
81
|
-
}
|
|
82
|
-
async send(method, path, payload, options = {}) {
|
|
83
|
-
let response;
|
|
84
|
-
try {
|
|
85
|
-
const timeout = AbortSignal.timeout(this.timeoutMillis);
|
|
86
|
-
response = await fetch(`${this.baseUrl}/api/v1${path}`, {
|
|
87
|
-
method,
|
|
88
|
-
headers: {
|
|
89
|
-
Authorization: `Bearer ${this.#apiKey}`,
|
|
90
|
-
...(payload ? { "Content-Type": "application/json" } : {}),
|
|
91
|
-
},
|
|
92
|
-
body: payload,
|
|
93
|
-
redirect: "error",
|
|
94
|
-
signal: options.signal ? AbortSignal.any([options.signal, timeout]) : timeout,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
catch {
|
|
98
|
-
throw new HueEnvironmentError();
|
|
99
|
-
}
|
|
100
|
-
if (!response.ok) {
|
|
101
|
-
await response.body?.cancel();
|
|
102
|
-
throw new HueEnvironmentError(response.status, response.status === 429 || response.status === 503 ? retryAfterMillis(response) : undefined, diagnosticOf(response));
|
|
103
|
-
}
|
|
104
|
-
try {
|
|
105
|
-
const reader = response.body?.getReader();
|
|
106
|
-
if (!reader)
|
|
107
|
-
throw new Error("Missing response");
|
|
108
|
-
const chunks = [];
|
|
109
|
-
let size = 0;
|
|
110
|
-
try {
|
|
111
|
-
for (;;) {
|
|
112
|
-
const { done, value } = await reader.read();
|
|
113
|
-
if (done)
|
|
114
|
-
break;
|
|
115
|
-
size += value.byteLength;
|
|
116
|
-
if (size > MAX_RESPONSE_BYTES)
|
|
117
|
-
throw new Error("Oversized response");
|
|
118
|
-
chunks.push(value);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
finally {
|
|
122
|
-
await reader.cancel();
|
|
123
|
-
}
|
|
124
|
-
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
throw new HueEnvironmentError();
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
async request(method, path, body, options = {}) {
|
|
131
|
-
// Serialize once: a body this client cannot encode is a caller error that no retry fixes.
|
|
132
|
-
const payload = body === undefined
|
|
133
|
-
? undefined
|
|
134
|
-
: JSON.stringify(json(Object.fromEntries(Object.entries(body).filter(([, value]) => value !== undefined)), REQUEST_BOUNDS));
|
|
135
|
-
for (let attempt = 1;; attempt++) {
|
|
136
|
-
try {
|
|
137
|
-
return await this.send(method, path, payload, options);
|
|
138
|
-
}
|
|
139
|
-
catch (error) {
|
|
140
|
-
if (!(error instanceof HueEnvironmentError))
|
|
141
|
-
throw error;
|
|
142
|
-
if (options.signal?.aborted)
|
|
143
|
-
throw error;
|
|
144
|
-
if (!isTransientEnvironmentError(error) || attempt >= this.maxAttempts)
|
|
145
|
-
throw error;
|
|
146
|
-
// Hue's admission refusals say how long to wait; anything else backs off.
|
|
147
|
-
const backoff = Math.min(100 * 2 ** (attempt - 1), 2000);
|
|
148
|
-
const wait = error.retryAfterMs ?? backoff + Math.random() * backoff;
|
|
149
|
-
await new Promise((resolve, reject) => {
|
|
150
|
-
const timer = setTimeout(() => {
|
|
151
|
-
options.signal?.removeEventListener("abort", abort);
|
|
152
|
-
resolve();
|
|
153
|
-
}, wait);
|
|
154
|
-
const abort = () => {
|
|
155
|
-
clearTimeout(timer);
|
|
156
|
-
options.signal?.removeEventListener("abort", abort);
|
|
157
|
-
reject(new HueEnvironmentError());
|
|
158
|
-
};
|
|
159
|
-
if (options.signal?.aborted)
|
|
160
|
-
abort();
|
|
161
|
-
else
|
|
162
|
-
options.signal?.addEventListener("abort", abort, { once: true });
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
requestOnce(method, path, body, bounds = REQUEST_BOUNDS) {
|
|
168
|
-
const payload = body === undefined
|
|
169
|
-
? undefined
|
|
170
|
-
: JSON.stringify(json(Object.fromEntries(Object.entries(body).filter(([, value]) => value !== undefined)), bounds));
|
|
171
|
-
return this.send(method, path, payload);
|
|
172
|
-
}
|
|
173
|
-
page(options = {}) {
|
|
174
|
-
const query = new URLSearchParams();
|
|
175
|
-
if (options.after)
|
|
176
|
-
query.set("after", uuid(options.after));
|
|
177
|
-
if (options.limit !== undefined) {
|
|
178
|
-
if (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > 100)
|
|
179
|
-
throw new RangeError("Page limit must be 1–100");
|
|
180
|
-
query.set("limit", String(options.limit));
|
|
181
|
-
}
|
|
182
|
-
return query.size ? `?${query}` : "";
|
|
183
|
-
}
|
|
184
|
-
/** Creates an environment identity; this non-idempotent registry write is not retried. */
|
|
185
|
-
createEnvironment(input) {
|
|
186
|
-
return this.requestOnce("POST", "/environments", input);
|
|
187
|
-
}
|
|
188
|
-
/** Lists active environment identities. */
|
|
189
|
-
listEnvironments(page) {
|
|
190
|
-
return this.request("GET", `/environments${this.page(page)}`);
|
|
191
|
-
}
|
|
192
|
-
/** Reads one environment and its immutable version summaries. */
|
|
193
|
-
getEnvironment(id) {
|
|
194
|
-
return this.request("GET", `/environments/${uuid(id)}`);
|
|
195
|
-
}
|
|
196
|
-
/** Publishes an immutable definition; this non-idempotent registry write is not retried. */
|
|
197
|
-
publishVersion(environmentId, definition) {
|
|
198
|
-
return this.requestOnce("POST", `/environments/${uuid(environmentId)}/versions`, { definition }, ENVIRONMENT_PUBLICATION_BOUNDS);
|
|
199
|
-
}
|
|
200
|
-
/** Reads a full immutable environment version and generated action catalog. */
|
|
201
|
-
getVersion(id) {
|
|
202
|
-
return this.request("GET", `/environment-versions/${uuid(id)}`);
|
|
203
|
-
}
|
|
204
|
-
/** Creates or recovers one fresh isolated world using a stable idempotency key. */
|
|
205
|
-
createRun(input) {
|
|
206
|
-
if (input.maxSteps !== undefined &&
|
|
207
|
-
(!Number.isInteger(input.maxSteps) || input.maxSteps < 1 || input.maxSteps > 500))
|
|
208
|
-
throw new RangeError("maxSteps must be 1–500");
|
|
209
|
-
if (input.ttlSeconds !== undefined &&
|
|
210
|
-
(!Number.isInteger(input.ttlSeconds) || input.ttlSeconds < 1 || input.ttlSeconds > 86_400))
|
|
211
|
-
throw new RangeError("ttlSeconds must be 1–86400");
|
|
212
|
-
if (input.seed !== undefined && !/^[a-f0-9]{32}$/.test(input.seed))
|
|
213
|
-
throw new TypeError("Seed must be 32 lowercase hexadecimal characters");
|
|
214
|
-
if (input.traceparent !== undefined && !validTraceparent(input.traceparent))
|
|
215
|
-
throw new TypeError("traceparent must be a version-00 W3C trace context");
|
|
216
|
-
if (input.agentRevision !== undefined &&
|
|
217
|
-
(typeof input.agentRevision !== "string" ||
|
|
218
|
-
input.agentRevision.length < 1 ||
|
|
219
|
-
input.agentRevision.length > 256))
|
|
220
|
-
throw new RangeError("agentRevision must be 1–256 characters");
|
|
221
|
-
return this.request("POST", "/environment-runs", {
|
|
222
|
-
...input,
|
|
223
|
-
environmentVersionId: uuid(input.environmentVersionId),
|
|
224
|
-
...(input.executionId === undefined ? {} : { executionId: uuid(input.executionId) }),
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
/** Reads authoritative current or sealed world state. */
|
|
228
|
-
async getRun(runId, options = {}) {
|
|
229
|
-
const run = await this.request("GET", `/environment-runs/${uuid(runId)}`, undefined, options);
|
|
230
|
-
return { validity: "not_assessed", coverageGap: null, ...run };
|
|
231
|
-
}
|
|
232
|
-
/** Record a known coverage gap with durable identity; retries reuse the exact request. */
|
|
233
|
-
recordCoverageGap(runId, input) {
|
|
234
|
-
uuid(input.idempotencyKey);
|
|
235
|
-
if (!input.args || typeof input.args !== "object" || Array.isArray(input.args))
|
|
236
|
-
throw new TypeError("Coverage gap arguments must be a JSON object");
|
|
237
|
-
json(input.args, { ...valueBounds, bytes: 16_000 });
|
|
238
|
-
return this.request("POST", `/environment-runs/${uuid(runId)}/coverage-gap`, input);
|
|
239
|
-
}
|
|
240
|
-
/** Invokes an action; repeating an invocation identity replays its recorded result. */
|
|
241
|
-
act(runId, input) {
|
|
242
|
-
return this.request("POST", `/environment-runs/${uuid(runId)}/actions`, {
|
|
243
|
-
...input,
|
|
244
|
-
args: input.args ?? {},
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
/** Pages the immutable journal by step ordinal. */
|
|
248
|
-
listSteps(runId, page = {}) {
|
|
249
|
-
const query = new URLSearchParams();
|
|
250
|
-
if (page.after !== undefined) {
|
|
251
|
-
if (!Number.isInteger(page.after) || page.after < -1)
|
|
252
|
-
throw new RangeError("Step cursor must be an ordinal");
|
|
253
|
-
query.set("after", String(page.after));
|
|
254
|
-
}
|
|
255
|
-
if (page.limit !== undefined) {
|
|
256
|
-
if (!Number.isInteger(page.limit) || page.limit < 1 || page.limit > 100)
|
|
257
|
-
throw new RangeError("Page limit must be 1–100");
|
|
258
|
-
query.set("limit", String(page.limit));
|
|
259
|
-
}
|
|
260
|
-
return this.request("GET", `/environment-runs/${uuid(runId)}/steps${query.size ? `?${query}` : ""}`);
|
|
261
|
-
}
|
|
262
|
-
/** Seals a world as completed or abandoned and freezes its evidence. */
|
|
263
|
-
finishRun(runId, input) {
|
|
264
|
-
return this.request("POST", `/environment-runs/${uuid(runId)}/finish`, input);
|
|
265
|
-
}
|
|
266
|
-
/** Reads a sealed world's evaluator-only evidence with the project key; a world token never
|
|
267
|
-
* can. An open world answers 409 until it is sealed. */
|
|
268
|
-
getEvidence(runId, options = {}) {
|
|
269
|
-
const query = new URLSearchParams();
|
|
270
|
-
if (options.section !== undefined) {
|
|
271
|
-
if (!["all", "start", "end", "diff", "ledger"].includes(options.section))
|
|
272
|
-
throw new TypeError("Evidence section must be all, start, end, diff or ledger");
|
|
273
|
-
query.set("section", options.section);
|
|
274
|
-
}
|
|
275
|
-
if (options.bodies !== undefined)
|
|
276
|
-
query.set("bodies", options.bodies ? "true" : "false");
|
|
277
|
-
return this.request("GET", `/environment-runs/${uuid(runId)}/evidence${query.size ? `?${query}` : ""}`);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
/** Creates a typed simulated-environment client. */
|
|
281
|
-
export function createEnvironmentClient(options) {
|
|
282
|
-
return new EnvironmentClient(options);
|
|
283
|
-
}
|
|
1
|
+
/** Compatibility entry point. Use the world module. */
|
|
2
|
+
export * from "../world/client.js";
|
|
@@ -1,35 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import type { EnvironmentClient } from "./client.js";
|
|
4
|
-
import type { ActionSchema, EnvironmentRun, JsonValue, Observation } from "./types.js";
|
|
5
|
-
/** Framework-neutral callable generated from one environment action. */
|
|
6
|
-
export interface EnvironmentTool {
|
|
7
|
-
/** Tool name. */
|
|
8
|
-
name: string;
|
|
9
|
-
/** Agent-visible description. */
|
|
10
|
-
description?: string;
|
|
11
|
-
/** JSON Schema input contract. */
|
|
12
|
-
inputSchema: ActionSchema;
|
|
13
|
-
/** Executes the action and resolves with the world's observation. */
|
|
14
|
-
execute(args?: Record<string, JsonValue>): Promise<Observation>;
|
|
15
|
-
}
|
|
16
|
-
/** Dependencies and tracing context for {@link bindEnvironmentTools}. */
|
|
17
|
-
export interface BindEnvironmentToolsOptions {
|
|
18
|
-
/** Hue client used to record each action as tool telemetry. */
|
|
19
|
-
hue: HueClient;
|
|
20
|
-
/** Environment client bound to the same Hue origin. */
|
|
21
|
-
client: Pick<EnvironmentClient, "act">;
|
|
22
|
-
/** Fresh environment run whose closed catalog becomes callables. */
|
|
23
|
-
run: EnvironmentRun;
|
|
24
|
-
/** Optional parent span context for generated tool spans. */
|
|
25
|
-
parentContext?: Context;
|
|
26
|
-
/** Optional durable invocation-ID factory for caller-owned resume state. */
|
|
27
|
-
invocationId?(action: string): string;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Binds a run's generated catalog to plain local callables without changing the agent
|
|
31
|
-
* framework. Each call is recorded through {@link HueClient.tool}. Catalog entries that
|
|
32
|
-
* include `mcp` stamp `mcp.server.name` / `mcp.server.version` and `hue.mcp.provider` /
|
|
33
|
-
* `hue.mcp.surface` so a generic verb is attributed to that MCP server and Hue surface.
|
|
34
|
-
*/
|
|
35
|
-
export declare function bindEnvironmentTools(options: BindEnvironmentToolsOptions): Record<string, EnvironmentTool>;
|
|
1
|
+
/** Compatibility entry point. Use the world module. */
|
|
2
|
+
export * from "../world/tools.js";
|
|
@@ -1,30 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* Binds a run's generated catalog to plain local callables without changing the agent
|
|
4
|
-
* framework. Each call is recorded through {@link HueClient.tool}. Catalog entries that
|
|
5
|
-
* include `mcp` stamp `mcp.server.name` / `mcp.server.version` and `hue.mcp.provider` /
|
|
6
|
-
* `hue.mcp.surface` so a generic verb is attributed to that MCP server and Hue surface.
|
|
7
|
-
*/
|
|
8
|
-
export function bindEnvironmentTools(options) {
|
|
9
|
-
const tools = {};
|
|
10
|
-
for (const action of options.run.actions) {
|
|
11
|
-
tools[action.name] = {
|
|
12
|
-
name: action.name,
|
|
13
|
-
...(action.description === undefined ? {} : { description: action.description }),
|
|
14
|
-
inputSchema: action.inputSchema,
|
|
15
|
-
execute: async (args = {}) => {
|
|
16
|
-
const invocationId = options.invocationId?.(action.name) ?? randomUUID();
|
|
17
|
-
const execute = async () => (await options.client.act(options.run.id, {
|
|
18
|
-
invocationId,
|
|
19
|
-
action: action.name,
|
|
20
|
-
args,
|
|
21
|
-
})).observation;
|
|
22
|
-
return options.hue.tool(action.name, args, execute, {
|
|
23
|
-
parentContext: options.parentContext,
|
|
24
|
-
...(action.mcp === undefined ? {} : { mcp: action.mcp }),
|
|
25
|
-
});
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
return tools;
|
|
30
|
-
}
|
|
1
|
+
/** Compatibility entry point. Use the world module. */
|
|
2
|
+
export * from "../world/tools.js";
|