@hue-run/sdk 0.7.0 → 0.8.1
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 -14
- package/ENVIRONMENTS.md +63 -1
- package/README.md +121 -5
- package/dist/ai-sdk.d.ts +3 -3
- package/dist/ai-sdk.js +3 -3
- package/dist/cli/env-file.d.ts +22 -0
- package/dist/cli/env-file.js +21 -0
- package/dist/cli/eval.js +100 -30
- package/dist/cli/login.d.ts +1 -1
- package/dist/cli/login.js +9 -4
- package/dist/client.d.ts +31 -3
- package/dist/client.js +199 -7
- package/dist/config.d.ts +2 -0
- package/dist/config.js +2 -0
- package/dist/environment/client.d.ts +16 -2
- package/dist/environment/client.js +46 -3
- package/dist/environment/tools.d.ts +2 -2
- package/dist/environment/tools.js +2 -2
- package/dist/environment/types.d.ts +134 -4
- package/dist/environment/world.d.ts +50 -0
- package/dist/environment/world.js +105 -0
- package/dist/environment.d.ts +2 -0
- package/dist/environment.js +1 -0
- package/dist/evals/environment-target.d.ts +53 -2
- package/dist/evals/environment-target.js +114 -10
- package/dist/evals/local-worker.d.ts +12 -5
- package/dist/evals/local-worker.js +13 -5
- package/dist/evals/runner.d.ts +1 -1
- package/dist/evals/runner.js +2 -2
- package/dist/evals/simulation.d.ts +14 -5
- package/dist/evals/simulation.js +26 -8
- package/dist/experimental-telemetry.d.ts +3 -2
- package/dist/experimental-telemetry.js +3 -2
- package/dist/inline-files.d.ts +10 -0
- package/dist/inline-files.js +86 -0
- package/dist/privacy.js +54 -5
- package/dist/provider-tools.d.ts +39 -0
- package/dist/provider-tools.js +222 -0
- package/dist/tool-definitions.d.ts +20 -0
- package/dist/tool-definitions.js +274 -0
- package/dist/transport.js +4 -2
- package/dist/types.d.ts +76 -3
- 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.8.1`, `@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
|
|
|
@@ -157,9 +157,13 @@ project. Run them separately with different keys if you want to revoke either us
|
|
|
157
157
|
```sh
|
|
158
158
|
hue login # one key for both uses into ./.env.hue
|
|
159
159
|
hue login --keys coding-agent --gitignore # only HUE_MCP_KEY; add .env.hue to .gitignore
|
|
160
|
-
hue login --origin https://staging.hue.run --env-
|
|
160
|
+
hue login --origin https://staging.hue.run --env-path .env.staging
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
+
`--env-path <path>` writes another env file, creating it when missing. `--env-file <path>` is
|
|
164
|
+
accepted too, but Node 22 and 24 read that flag from the whole command line and exit with
|
|
165
|
+
`node: <path>: not found` before `hue` runs when the file does not exist yet.
|
|
166
|
+
|
|
163
167
|
The env file is written with mode `0600` through a temporary file and an atomic rename. Other
|
|
164
168
|
lines are preserved; a symlink or a non-regular file is refused; an existing different value is
|
|
165
169
|
replaced only with `--force`. Empty values, whitespace and URLs are refused before any request.
|
|
@@ -301,7 +305,7 @@ node packages/sdk-typescript/scripts/verify-package.mjs --artifacts-dir .artifac
|
|
|
301
305
|
# Set project to an existing supported fixture; use the same directory on resume.
|
|
302
306
|
project=/absolute/path/to/supported-fixture
|
|
303
307
|
node packages/sdk-typescript/scripts/verify-setup-live.mjs \
|
|
304
|
-
--archive .artifacts/typescript/hue-run-sdk-0.
|
|
308
|
+
--archive .artifacts/typescript/hue-run-sdk-0.8.1.tgz \
|
|
305
309
|
--origin https://STAGING_ORIGIN \
|
|
306
310
|
--project "$project" --command setup \
|
|
307
311
|
--evidence .context/setup-staging-before-claim.json
|
|
@@ -312,7 +316,7 @@ the private local handoff and finish the real browser claim, then reconcile the
|
|
|
312
316
|
|
|
313
317
|
```sh
|
|
314
318
|
node packages/sdk-typescript/scripts/verify-setup-live.mjs \
|
|
315
|
-
--archive .artifacts/typescript/hue-run-sdk-0.
|
|
319
|
+
--archive .artifacts/typescript/hue-run-sdk-0.8.1.tgz \
|
|
316
320
|
--origin https://STAGING_ORIGIN \
|
|
317
321
|
--project "$project" --command claim \
|
|
318
322
|
--evidence .context/setup-staging-after-claim.json
|
|
@@ -346,8 +350,9 @@ the CLI never prints it. The optional `zod` peer of `@hue-run/sdk/evals` must be
|
|
|
346
350
|
|
|
347
351
|
Write an adapter module that hands the case inputs and the world's tools or MCP connection to
|
|
348
352
|
the real agent. The module exports `default` or `runMyAgent`; `context` is the SDK's
|
|
349
|
-
`SimulationTargetContext` (`
|
|
350
|
-
`signal`
|
|
353
|
+
`SimulationTargetContext` (`world`, `mcp`, `tools`, `config`, `item`, `executionId`,
|
|
354
|
+
`environmentRunId`, `signal`; `world` carries the provider mirror URLs, the world token, `env` and
|
|
355
|
+
`mcpConfig` where Hue's simulation gateway serves the world):
|
|
351
356
|
|
|
352
357
|
```ts
|
|
353
358
|
// hue-agent.ts: erasable TypeScript only; Node.js 24 and Bun strip the types natively.
|
|
@@ -374,7 +379,8 @@ hue eval --worker ./hue-agent.ts --agent-key support-agent --env-file .env.hue
|
|
|
374
379
|
|
|
375
380
|
The one-shot mode resolves the selection (`--case` by name, ID or URL; `--set` by name, ID or
|
|
376
381
|
URL with explicit `--scorer-version` pins; or `--dataset-version` with `--scorer-version`),
|
|
377
|
-
creates a fresh run from those immutable pins named `<
|
|
382
|
+
creates a fresh run from those immutable pins named `<agent key> @ <revision>` (a commit hash is
|
|
383
|
+
shortened to 7 characters)
|
|
378
384
|
(`--name` overrides), prints `Run: <url>` and `Experiment: <id>` as soon as the experiment exists,
|
|
379
385
|
one line per case event (world created, agent started, world sealed), then
|
|
380
386
|
`Waiting for Hue checks...` and a table with one row per case: boolean metrics as `PASS`/`FAIL`,
|
|
@@ -386,12 +392,19 @@ and sends progress to stderr. `--wait <seconds>` (default 300) bounds the verdic
|
|
|
386
392
|
Hue-owned `world_outcome` checks are graded after the world seals. An experiment always covers
|
|
387
393
|
every case of the saved version; there is no case subset.
|
|
388
394
|
|
|
389
|
-
`--command "<shell command>"` spawns the command once per case with
|
|
390
|
-
`
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
+
`--command "<shell command>"` spawns the command once per case with the world's environment
|
|
396
|
+
(`HUE_WORLD_ID`, `HUE_WORLD_TOKEN`, one `HUE_SIM_<SURFACE ID>_URL` per provider mirror,
|
|
397
|
+
`HUE_MCP_CONFIG` naming an owner-only `mcpServers` file that is removed after the case, and
|
|
398
|
+
`HUE_MCP_URL`, `HUE_MCP_TOKEN`, `HUE_MCP_EXPIRES_AT` for the first MCP mirror), plus
|
|
399
|
+
`HUE_EXECUTION_ID`, `HUE_ENVIRONMENT_RUN_ID`, `HUE_CASE_ID` and `HUE_CASE_KEY`, and
|
|
400
|
+
`{"inputs": ..., "config": ...}` on stdin. The child does not receive `HUE_API_KEY`, `HUE_MCP_KEY`
|
|
401
|
+
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. Its stdout is the answer
|
|
403
|
+
(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. The world token is never logged.
|
|
405
|
+
A world created while the deployment's simulation gateway is off gets the legacy `hue_sim_`
|
|
406
|
+
capability under the same `HUE_MCP_*` names. The agent key defaults to the slug of the command's
|
|
407
|
+
script name; `--revision` is sent to Hue as the agent revision of every world.
|
|
395
408
|
|
|
396
409
|
`--worker` registers the adapter through `runLocalAgent()` with key `--agent-key` (default: the
|
|
397
410
|
adapter filename slug), name `--agent-name` (default: the key), revision `--revision` (default:
|
|
@@ -403,7 +416,7 @@ apply; Hue chooses the pinned experiment. The worker exits 0 when it stops norma
|
|
|
403
416
|
A Scenario or eval set whose dataset version is not saved cannot back an experiment: the command
|
|
404
417
|
exits 1 and asks for **Save eval-set version** in Hue or `--save-version`, which freezes that
|
|
405
418
|
version at its current revision. Connection settings are `HUE_API_KEY` and `HUE_BASE_URL`
|
|
406
|
-
(default `https://app.hue.run`), loaded from `--env-file <path>` first when given; `--origin`
|
|
419
|
+
(default `https://app.hue.run`), loaded from `--env-file <path>` (or its alias `--env-path`) first when given; `--origin`
|
|
407
420
|
overrides the origin. Telemetry content capture stays off unless `--content` is passed; in
|
|
408
421
|
one-shot mode it also decides whether case outputs, error messages and explanations are persisted
|
|
409
422
|
to Hue. `--worker` always persists them, because a run launched from Hue is read on its run page:
|
package/ENVIRONMENTS.md
CHANGED
|
@@ -183,7 +183,8 @@ await client.finishRun(run.id, { idempotencyKey: randomUUID(), status: "complete
|
|
|
183
183
|
```
|
|
184
184
|
|
|
185
185
|
Each bound call is an ordinary `hue.tool` span. When the catalog names an MCP server, the span
|
|
186
|
-
also carries `mcp.server.name
|
|
186
|
+
also carries `mcp.server.name`, plus `hue.mcp.provider` and `hue.mcp.surface` when the catalog
|
|
187
|
+
entry includes them. Wrap any MCP client the same way, using `serverInfo` from
|
|
187
188
|
`initialize` — this is not specific to Hue-hosted Gmail or Slack:
|
|
188
189
|
|
|
189
190
|
```ts
|
|
@@ -196,6 +197,67 @@ An observation with `status: "error"` is a recorded world answer, not a transpor
|
|
|
196
197
|
Run mutations retry with stable invocation/idempotency identities. Registry writes do not retry
|
|
197
198
|
automatically because identity creation and publication have no request key.
|
|
198
199
|
|
|
200
|
+
## Worlds served by the simulation gateway
|
|
201
|
+
|
|
202
|
+
Where a Hue deployment has the simulation gateway on, `createRun` returns the World API handoff
|
|
203
|
+
beside the run: `token` (a `hue_world_…` credential that lives exactly as long as the world),
|
|
204
|
+
`surfaces[]` (one mirror URL per pinned provider surface, such as the Gmail MCP and REST mirrors),
|
|
205
|
+
`env` (`HUE_WORLD_ID`, `HUE_WORLD_TOKEN`, `BAGGAGE`, `TRACEPARENT` and one
|
|
206
|
+
`HUE_SIM_<SURFACE ID>_URL` per surface) and `mcpConfig` (the common `mcpServers` shape with the
|
|
207
|
+
token in the `Authorization` header). The agent is pointed at the mirrors by configuration only:
|
|
208
|
+
its own Gmail MCP or REST client, the mirror URL, the world token where the Google credential went.
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
import {
|
|
212
|
+
agentEnvironment,
|
|
213
|
+
createEnvironmentClient,
|
|
214
|
+
worldHandoff,
|
|
215
|
+
writeMcpConfig,
|
|
216
|
+
} from "@hue-run/sdk/environment";
|
|
217
|
+
|
|
218
|
+
const run = await environmentClient.createRun({
|
|
219
|
+
idempotencyKey: `execution:${executionId}`,
|
|
220
|
+
environmentVersionId,
|
|
221
|
+
executionId,
|
|
222
|
+
ttlSeconds: 600,
|
|
223
|
+
traceparent: `00-${span.traceId}-${span.spanId}-01`, // parents the world span on the case span
|
|
224
|
+
agentRevision: "my-agent@1.4.2", // joins the world's fingerprint
|
|
225
|
+
});
|
|
226
|
+
const world = worldHandoff(run); // null for a world created while the gateway is off
|
|
227
|
+
const child = agentEnvironment(world!, { parent: process.env }); // no HUE_API_KEY in the agent
|
|
228
|
+
const config = await writeMcpConfig(world!); // owner-only mcp.json; dispose after the run
|
|
229
|
+
try {
|
|
230
|
+
await spawnAgent({ env: child, mcpConfigPath: config.path });
|
|
231
|
+
} finally {
|
|
232
|
+
await config.dispose();
|
|
233
|
+
await environmentClient.finishRun(run.id, {
|
|
234
|
+
idempotencyKey: `execution:${executionId}:completed`,
|
|
235
|
+
status: "completed",
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
`runSimulation`, `runLocalAgent` and `hue eval` do this for you: they create the world with the
|
|
241
|
+
execution, the stable key, the case span's context and the agent revision, pass the handoff as
|
|
242
|
+
`context.world`, and finish before returning so telemetry is flushed and the execution completed
|
|
243
|
+
afterwards. For one compatibility release `context.mcp` is the world's first MCP mirror with the
|
|
244
|
+
world token, so an adapter that read `HUE_MCP_URL` and `HUE_MCP_TOKEN` keeps working;
|
|
245
|
+
`agentEnvironment` sets those names too unless `legacyMcpVariables: false`. A gateway world binds
|
|
246
|
+
no Hue-native `tools` (Hue refuses them); a world created while the gateway is off keeps its tools
|
|
247
|
+
and the `hue_sim_` capability and emits a one-time `DeprecationWarning`.
|
|
248
|
+
|
|
249
|
+
`agentEnvironment` removes Hue control-plane credentials from the child by default: `HUE_API_KEY`,
|
|
250
|
+
`HUE_MCP_KEY` and any variable whose value is a `hue_sk_`, `hue_mcp_` or `hue_attempt_`
|
|
251
|
+
credential. Pass `includeHueCredentials: true` only for an agent that must call Hue's own API.
|
|
252
|
+
Nothing in these helpers logs the token; keep it out of your own logs and checkpoints.
|
|
253
|
+
|
|
254
|
+
Finish answers `lifecycle: "completing"` with `sealedAt: null` for a gateway world: the seal
|
|
255
|
+
follows a 5 s grace so in-flight writes land, and a late finish answers 409, which the helpers
|
|
256
|
+
treat as the seal they can no longer change. `getEvidence(runId, { section, bodies })` reads the
|
|
257
|
+
sealed world's evaluator-only evidence (start and end state, the diff, the call ledger, coverage,
|
|
258
|
+
fingerprint) with the project key; a world token can never read it. The client honors Hue's
|
|
259
|
+
`Retry-After` on 429 and 503.
|
|
260
|
+
|
|
199
261
|
## Coverage gaps
|
|
200
262
|
|
|
201
263
|
A provider adapter can record a known valid provider request that the environment cannot
|
package/README.md
CHANGED
|
@@ -131,22 +131,82 @@ await hue.model(
|
|
|
131
131
|
);
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
+
Tools the provider runs itself, such as OpenAI hosted MCP, web search, file search and code
|
|
135
|
+
interpreter, or Anthropic's MCP connector and server tools, never pass through `hue.tool()`. Inside
|
|
136
|
+
the same `hue.model()` callback, hand the response to `hue.recordProviderToolCalls`:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
await hue.model(
|
|
140
|
+
"gpt-5-mini",
|
|
141
|
+
async (span) => {
|
|
142
|
+
const response = await openai.responses.create(request);
|
|
143
|
+
span.setOutput(response.output_text);
|
|
144
|
+
hue.recordProviderToolCalls(response, { request });
|
|
145
|
+
return response;
|
|
146
|
+
},
|
|
147
|
+
{ provider: "openai" },
|
|
148
|
+
);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Each OpenAI Responses `mcp_call`, `web_search_call`, `file_search_call` or `code_interpreter_call`
|
|
152
|
+
item, and each Anthropic `mcp_tool_use` or `server_tool_use` block with its result, becomes an
|
|
153
|
+
`execute_tool {name}` child span with `gen_ai.tool.type` `extension`, `gen_ai.tool.call.id` and,
|
|
154
|
+
for MCP calls, `mcp.server.name` (the provider's label). Arguments and results follow
|
|
155
|
+
`captureContent`; a failed call carries `error.type` (`mcp_error`, the provider's status or error
|
|
156
|
+
code) and ERROR status. An `mcp_list_tools` item becomes a `tools/list` child span with that
|
|
157
|
+
server's `gen_ai.tool.definitions`. Pass the request so each server's host is recorded as
|
|
158
|
+
`server.address` (only server URLs are read, never credentials), and `servers` to record a
|
|
159
|
+
server's real `name`, `version`, Hue `provider` and `surface` under its label. `provider` defaults
|
|
160
|
+
to the enclosing `model()` call's provider (`openai` or `anthropic`). The spans have no duration of
|
|
161
|
+
their own: the provider ran the tools inside the model request.
|
|
162
|
+
|
|
134
163
|
The span is named `{operation} {model}` (`operation` defaults to `chat`) with
|
|
135
164
|
`gen_ai.operation.name`, `gen_ai.request.model` and `gen_ai.provider.name`. Like `withSpan`, the
|
|
136
|
-
options come after the callback and also accept `name`, `sessionId`, `userId`, `input` (recorded as
|
|
137
|
-
`gen_ai.input.messages`) and `parentContext`.
|
|
165
|
+
options come after the callback and also accept `name`, `sessionId`, `userId`, `workspaceId`, `input` (recorded as
|
|
166
|
+
`gen_ai.input.messages`) and `parentContext`. When you send system instructions or tools separately
|
|
167
|
+
from the messages, pass `systemInstructions` (for example `[{ type: "text", content: instructions }]`)
|
|
168
|
+
and `tools` (for example `[{ type: "function", name, description, parameters }]`); they are recorded
|
|
169
|
+
as `gen_ai.system_instructions` and `gen_ai.tool.definitions` under the same `captureContent` rule
|
|
170
|
+
as the messages. `recordMessages` also accepts `systemInstructions` for its log record. `setUsage` records
|
|
138
171
|
nonnegative integer `gen_ai.usage.input_tokens` / `output_tokens`; other values are omitted and
|
|
139
172
|
counted as instrumentation failures. Unknown usage stays absent. `hue.tool(name, input, execute)`
|
|
140
173
|
creates an `execute_tool {name}` span with `gen_ai.tool.name`, arguments and result; an optional
|
|
141
174
|
fourth argument `{ callId }` records the provider's tool call id as `gen_ai.tool.call.id`. When the
|
|
142
175
|
tool came from an MCP server, pass `{ mcp: client.getServerVersion() }` (the MCP `initialize`
|
|
143
176
|
`serverInfo`) to record `mcp.server.name` and `mcp.server.version` so a generic verb such as
|
|
144
|
-
`get_thread` is attributed to that server.
|
|
177
|
+
`get_thread` is attributed to that server. When the server is a Hue surface, `mcp.provider` and
|
|
178
|
+
`mcp.surface` (for example `google.gmail` and `google.gmail/mcp`) record `hue.mcp.provider` and
|
|
179
|
+
`hue.mcp.surface`. A blank, over-256-character or otherwise invalid label is omitted and counted as
|
|
180
|
+
an instrumentation failure; the tool still runs. Content
|
|
145
181
|
helpers (`setInput`, `setOutput`, `tool` arguments and results, `recordMessages`,
|
|
146
182
|
`SpanOptions.input`) accept any value and encode plain JSON data (`JsonValue`) at runtime; a value
|
|
147
183
|
that is not JSON, such as a `Date` or a class instance, is omitted with an instrumentation failure
|
|
148
184
|
while the callback result is returned unchanged.
|
|
149
185
|
|
|
186
|
+
## Files
|
|
187
|
+
|
|
188
|
+
Record a file the work read, received or produced with `hue.recordFile`. It adds a `hue.file`
|
|
189
|
+
event to the active span (or the span of an explicit context passed second), keyed by the file's
|
|
190
|
+
SHA-256, so a trace can be linked to the same file elsewhere without exporting its bytes:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
import { readFile } from "node:fs/promises";
|
|
194
|
+
|
|
195
|
+
await hue.withSpan("review contract", async () => {
|
|
196
|
+
const pdf = await readFile("contract.pdf");
|
|
197
|
+
hue.recordFile({ role: "input", mediaType: "application/pdf", data: pdf, name: "contract.pdf" });
|
|
198
|
+
// ...
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
`data` up to 25 MiB is hashed and measured locally and never exported; larger data is omitted and
|
|
203
|
+
counted as an instrumentation failure, so pass `sha256` (and `byteSize`) instead when you already
|
|
204
|
+
have them. The event carries `hue.file.sha256`, `hue.file.role` (`input`,
|
|
205
|
+
`attachment` or `output`), `hue.file.media_type` and `hue.file.size`. It is metadata, so it is
|
|
206
|
+
recorded in both capture modes, while `hue.file.name` is recorded only when `captureContent` is
|
|
207
|
+
true. An invalid record, or one without an active span, is omitted and counted as an
|
|
208
|
+
instrumentation failure.
|
|
209
|
+
|
|
150
210
|
## Vercel AI SDK 6
|
|
151
211
|
|
|
152
212
|
AI SDK 6 accepts a per-call tracer through `experimental_telemetry`. Pass
|
|
@@ -216,6 +276,15 @@ instrumentations can use `hue.tracer` directly or explicitly attach the processo
|
|
|
216
276
|
below. Instrumentations that only use a global provider need your application's
|
|
217
277
|
normal OTel setup; Hue does not silently replace it.
|
|
218
278
|
|
|
279
|
+
Provider-executed tools, such as OpenAI hosted MCP (`openai.tools.mcp`), appear as
|
|
280
|
+
`execute_tool mcp.<name>` spans with `gen_ai.tool.type` `extension`. The server is named only
|
|
281
|
+
by `serverLabel` inside the recorded result, so before export the TypeScript SDK copies it to
|
|
282
|
+
`mcp.server.name`, and a result with an MCP `error` sets ERROR status and `error.type`
|
|
283
|
+
`mcp_error`. Metadata-only export keeps these two attributes while stripping arguments and
|
|
284
|
+
results. The label can only be read when AI SDK recorded the result: `hueTelemetry(hue)` with
|
|
285
|
+
`captureContent: false` records none, whereas an application whose AI SDK integration records
|
|
286
|
+
outputs and exports through Hue's attached processors keeps the label.
|
|
287
|
+
|
|
219
288
|
## Privacy and content
|
|
220
289
|
|
|
221
290
|
`captureContent: false` disables manual input/output/messages/tool content and
|
|
@@ -232,6 +301,36 @@ attributes, resources, event/link attributes and log bodies. Return a string.
|
|
|
232
301
|
Invalid/oversized helper content is omitted with an instrumentation failure; the span can still be delivered. Export-time redactor failures reject the affected record and are reported by flush. Shared resources are redacted once per
|
|
233
302
|
export batch. Do not put user content or secrets in span names or scope names.
|
|
234
303
|
|
|
304
|
+
Hosted tools carry credentials in their definitions, such as the `authorization` and `headers` of
|
|
305
|
+
an OpenAI hosted MCP tool. Before export, and before `redact`, Hue replaces the values of
|
|
306
|
+
credential-like fields including `authorization`, `authorization_token`, `headers`, `api_key`,
|
|
307
|
+
`access_token`, `x-api-key`, and keys ending in `token`, `secret`, `password`, `apikey` or
|
|
308
|
+
`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 `tools`
|
|
310
|
+
and `mcp_servers` entries of a raw provider request or response recorded as `input.value`,
|
|
311
|
+
`output.value` or `llm.invocation_parameters`. Parameters named in a JSON Schema `properties`
|
|
312
|
+
object keep their schemas, so a tool that takes a `headers` argument is still described. A
|
|
313
|
+
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.
|
|
315
|
+
|
|
316
|
+
With `captureContent: false`, export removes tool definitions but keeps a summary of them on the
|
|
317
|
+
same record: `hue.tool.names` lists each definition's `name` (Chat Completions `function.name`,
|
|
318
|
+
or the `type` of an unnamed built-in tool such as `mcp`) in order, and
|
|
319
|
+
`hue.tool.definitions.sha256` is the lowercase hex SHA-256 of the
|
|
320
|
+
[RFC 8785](https://www.rfc-editor.org/rfc/rfc8785) canonical JSON of the credential-scrubbed
|
|
321
|
+
definition list. The digest is the same in both SDKs and does not change when a credential
|
|
322
|
+
rotates. Only definitions another integration recorded can be summarized: `hueTelemetry(hue)` with
|
|
323
|
+
`captureContent: false` records none, whereas an application whose AI SDK integration records
|
|
324
|
+
inputs and exports through Hue's attached processors gets the summary.
|
|
325
|
+
Recorded messages can inline files: GenAI `blob` parts in `gen_ai.input.messages` /
|
|
326
|
+
`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 before
|
|
328
|
+
export Hue replaces the `content`/`data` of any such part longer than 64 KiB with the file's
|
|
329
|
+
`sha256` (of the decoded bytes for base64 and `data:` URLs, of the UTF-8 text otherwise) and
|
|
330
|
+
`size`, keeping the part's other fields such as `type`, `mime_type` and `mediaType`. Smaller inline
|
|
331
|
+
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.
|
|
333
|
+
|
|
235
334
|
Manual helpers encode JSON values without converting null into absence. Unknown
|
|
236
335
|
outputs and usage remain absent. This SDK does not estimate tokens or cost. A thrown
|
|
237
336
|
application error marks the span with `error.type` (the error's `name`), an ERROR status and an
|
|
@@ -281,7 +380,9 @@ For external parent context pass `parentContext` to `withSpan`. Across processes
|
|
|
281
380
|
speak W3C `traceparent` only and never include the API key or baggage. Hue registers no global
|
|
282
381
|
propagator, so `propagation.inject()` from `@opentelemetry/api` is a no-op unless your
|
|
283
382
|
application configured one. `getContext()` exposes the helper's current context for APIs taking
|
|
284
|
-
an explicit context. Session
|
|
383
|
+
an explicit context. Session, user and workspace identifiers (`sessionId` as
|
|
384
|
+
`gen_ai.conversation.id`, `userId` as `user.id`, and `workspaceId` as `hue.workspace.id` for the
|
|
385
|
+
application workspace or tenant) are inherited within a client callback and are
|
|
285
386
|
stamped only on spans created through Hue's tracer (helpers and the AI SDK adapters); spans from
|
|
286
387
|
other instrumentations on a shared provider carry them only if that instrumentation sets them.
|
|
287
388
|
Separate requests require separate callbacks.
|
|
@@ -358,13 +459,28 @@ tick, the transport queues a placeholder: an ordinary OTLP span whose parent is
|
|
|
358
459
|
with its name, kind, start time and current attributes, an end time of 0,
|
|
359
460
|
`hue.span_type = "pending_span"` and `hue.pending_parent_id` (the running span's own parent,
|
|
360
461
|
omitted for a root). Hue shows the span as running and replaces the placeholder when the real span
|
|
361
|
-
arrives.
|
|
462
|
+
arrives.
|
|
463
|
+
|
|
464
|
+
The placeholder then waits for the next batch export like any queued span: up to 500 ms until the
|
|
465
|
+
next tick, then the 1 s batch delay when nothing else is queued, so it usually reaches Hue within
|
|
466
|
+
about 1.5 s of its span starting. It goes out sooner when a batch is already scheduled, for example
|
|
467
|
+
because another span has just ended, and at once for a full batch or `flush()`. It goes out later
|
|
468
|
+
while an earlier export is still in flight, because the next batch is scheduled only after that
|
|
469
|
+
export finishes. A placeholder whose span has ended by the time it is exported is not sent, so a
|
|
470
|
+
short span may send none and appear in Hue only when it finishes.
|
|
362
471
|
|
|
363
472
|
- Only spans from the client's tracer (`withSpan`, `tool`, `model`, `hue.tracer` and the AI SDK
|
|
364
473
|
adapters) and spans with a `gen_ai.`, `ai.`, `llm.` or `traceloop.` attribute at start, or a
|
|
365
474
|
name starting with `ai.`, are announced. HTTP, database and other framework spans are not.
|
|
366
475
|
- Placeholder attributes follow `captureContent` and `redact` like the real span. Tool
|
|
367
476
|
definitions, system instructions and any value over 64 KiB are left out.
|
|
477
|
+
- The transport builds each placeholder from the running span itself, so code in a wrapping
|
|
478
|
+
processor's `onEnd` never runs on it. If a wrapper forwards `onStart` to Hue but scrubs
|
|
479
|
+
attributes, renames the span or drops it in `onEnd`, a placeholder exported while the span is
|
|
480
|
+
still open is sent anyway: it has the span's original name, and its attributes as set on the span
|
|
481
|
+
with `captureContent` and `redact` applied. Scrub with `redact`, which applies to placeholders
|
|
482
|
+
too, or before the value is set on the span; do not forward `onStart` for spans you rename or
|
|
483
|
+
drop; or turn live spans off with `liveSpans: false`.
|
|
368
484
|
- Placeholders are advisory. They are queued only while the queue is under a quarter of its
|
|
369
485
|
record and byte budgets, and skipped silently otherwise. While queued they count in
|
|
370
486
|
`pendingSpans` and `pendingBytes`, but never as accepted, rejected, failed or dropped records.
|
package/dist/ai-sdk.d.ts
CHANGED
|
@@ -2,9 +2,9 @@ import type { TelemetryOptions } from "ai";
|
|
|
2
2
|
import type { HueClient } from "./client.js";
|
|
3
3
|
/**
|
|
4
4
|
* Per-call telemetry for AI SDK 7: pass as an agent's or generation call's `telemetry` option.
|
|
5
|
-
* Spans come from Hue's tracer, so they parent under `withSpan` and inherit session
|
|
6
|
-
* identifiers; prompt and response recording follow `captureContent`. It does not
|
|
7
|
-
* AI SDK integrations.
|
|
5
|
+
* Spans come from Hue's tracer, so they parent under `withSpan` and inherit session, user and
|
|
6
|
+
* workspace identifiers; prompt and response recording follow `captureContent`. It does not
|
|
7
|
+
* change global AI SDK integrations.
|
|
8
8
|
*
|
|
9
9
|
* @throws TypeError when the client is enabled and the installed `ai` major version is below 7;
|
|
10
10
|
* AI SDK 6 applications use `hueExperimentalTelemetry` from `@hue-run/sdk` instead.
|
package/dist/ai-sdk.js
CHANGED
|
@@ -21,9 +21,9 @@ function aiMajor() {
|
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Per-call telemetry for AI SDK 7: pass as an agent's or generation call's `telemetry` option.
|
|
24
|
-
* Spans come from Hue's tracer, so they parent under `withSpan` and inherit session
|
|
25
|
-
* identifiers; prompt and response recording follow `captureContent`. It does not
|
|
26
|
-
* AI SDK integrations.
|
|
24
|
+
* Spans come from Hue's tracer, so they parent under `withSpan` and inherit session, user and
|
|
25
|
+
* workspace identifiers; prompt and response recording follow `captureContent`. It does not
|
|
26
|
+
* change global AI SDK integrations.
|
|
27
27
|
*
|
|
28
28
|
* @throws TypeError when the client is enabled and the installed `ai` major version is below 7;
|
|
29
29
|
* AI SDK 6 applications use `hueExperimentalTelemetry` from `@hue-run/sdk` instead.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node 22 and 24 scan the whole command line for `--env-file`, including arguments meant for the
|
|
3
|
+
* script, and exit with "node: <path>: not found" before the CLI runs when that file does not
|
|
4
|
+
* exist. `--env-path` is the same option under a name Node ignores, so a command such as
|
|
5
|
+
* `hue login` can name a file it is about to create.
|
|
6
|
+
*/
|
|
7
|
+
export declare const envFileOptions: {
|
|
8
|
+
readonly "env-file": {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
};
|
|
11
|
+
readonly "env-path": {
|
|
12
|
+
readonly type: "string";
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The env file named by `--env-path` or `--env-file`; throws when both name different files,
|
|
17
|
+
* comparing them as resolved from `cwd`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function envFileArgument(values: {
|
|
20
|
+
"env-file"?: string | undefined;
|
|
21
|
+
"env-path"?: string | undefined;
|
|
22
|
+
}, cwd: string): string | undefined;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
/**
|
|
3
|
+
* Node 22 and 24 scan the whole command line for `--env-file`, including arguments meant for the
|
|
4
|
+
* script, and exit with "node: <path>: not found" before the CLI runs when that file does not
|
|
5
|
+
* exist. `--env-path` is the same option under a name Node ignores, so a command such as
|
|
6
|
+
* `hue login` can name a file it is about to create.
|
|
7
|
+
*/
|
|
8
|
+
export const envFileOptions = {
|
|
9
|
+
"env-file": { type: "string" },
|
|
10
|
+
"env-path": { type: "string" },
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* The env file named by `--env-path` or `--env-file`; throws when both name different files,
|
|
14
|
+
* comparing them as resolved from `cwd`.
|
|
15
|
+
*/
|
|
16
|
+
export function envFileArgument(values, cwd) {
|
|
17
|
+
const { "env-file": file, "env-path": path } = values;
|
|
18
|
+
if (file !== undefined && path !== undefined && resolve(cwd, file) !== resolve(cwd, path))
|
|
19
|
+
throw new Error("Pass one of --env-file and --env-path, not both.");
|
|
20
|
+
return path ?? file;
|
|
21
|
+
}
|