@hue-run/sdk 0.21.1 → 0.22.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 +246 -52
- package/README.md +54 -13
- package/WORLDS.md +6 -3
- package/dist/ai-sdk.d.ts +23 -1
- package/dist/ai-sdk.js +60 -2
- package/dist/cli/import-formats/adapter.d.ts +80 -0
- package/dist/cli/import-formats/adapter.js +1 -0
- package/dist/cli/import-formats/agent-events.d.ts +5 -0
- package/dist/cli/import-formats/agent-events.js +16 -0
- package/dist/cli/import-formats/atif.d.ts +3 -0
- package/dist/cli/import-formats/atif.js +15 -0
- package/dist/cli/import-formats/braintrust.d.ts +2 -0
- package/dist/cli/import-formats/braintrust.js +222 -0
- package/dist/cli/import-formats/containers.d.ts +32 -0
- package/dist/cli/import-formats/containers.js +399 -0
- package/dist/cli/import-formats/datadog.d.ts +2 -0
- package/dist/cli/import-formats/datadog.js +264 -0
- package/dist/cli/import-formats/helicone.d.ts +2 -0
- package/dist/cli/import-formats/helicone.js +161 -0
- package/dist/cli/import-formats/identity.d.ts +112 -0
- package/dist/cli/import-formats/identity.js +594 -0
- package/dist/cli/import-formats/jaeger.d.ts +3 -0
- package/dist/cli/import-formats/jaeger.js +266 -0
- package/dist/cli/import-formats/langfuse.d.ts +7 -0
- package/dist/cli/import-formats/langfuse.js +510 -0
- package/dist/cli/import-formats/langsmith.d.ts +2 -0
- package/dist/cli/import-formats/langsmith.js +244 -0
- package/dist/cli/import-formats/messages.d.ts +28 -0
- package/dist/cli/import-formats/messages.js +301 -0
- package/dist/cli/import-formats/mlflow.d.ts +2 -0
- package/dist/cli/import-formats/mlflow.js +260 -0
- package/dist/cli/import-formats/openai-agents.d.ts +2 -0
- package/dist/cli/import-formats/openai-agents.js +221 -0
- package/dist/cli/import-formats/opik.d.ts +2 -0
- package/dist/cli/import-formats/opik.js +193 -0
- package/dist/cli/import-formats/otel-family.d.ts +5 -0
- package/dist/cli/import-formats/otel-family.js +17 -0
- package/dist/cli/import-formats/otel-spans.d.ts +94 -0
- package/dist/cli/import-formats/otel-spans.js +262 -0
- package/dist/cli/import-formats/otlp-protobuf.d.ts +35 -0
- package/dist/cli/import-formats/otlp-protobuf.js +486 -0
- package/dist/cli/import-formats/otlp.d.ts +4 -0
- package/dist/cli/import-formats/otlp.js +15 -0
- package/dist/cli/import-formats/phoenix.d.ts +3 -0
- package/dist/cli/import-formats/phoenix.js +256 -0
- package/dist/cli/import-formats/raindrop.d.ts +21 -0
- package/dist/cli/import-formats/raindrop.js +255 -0
- package/dist/cli/import-formats/reader.d.ts +56 -0
- package/dist/cli/import-formats/reader.js +364 -0
- package/dist/cli/import-formats/registry.d.ts +36 -0
- package/dist/cli/import-formats/registry.js +71 -0
- package/dist/cli/import-formats/row-platform-fields.d.ts +32 -0
- package/dist/cli/import-formats/row-platform-fields.js +76 -0
- package/dist/cli/import-formats/rows.d.ts +165 -0
- package/dist/cli/import-formats/rows.js +638 -0
- package/dist/cli/import-formats/transcripts.d.ts +25 -0
- package/dist/cli/import-formats/transcripts.js +498 -0
- package/dist/cli/import-formats/weave.d.ts +2 -0
- package/dist/cli/import-formats/weave.js +159 -0
- package/dist/cli/import-formats/zipkin.d.ts +2 -0
- package/dist/cli/import-formats/zipkin.js +219 -0
- package/dist/cli/import.d.ts +1 -1
- package/dist/cli/import.js +4 -2
- package/dist/cli/traces-import-convert.d.ts +65 -33
- package/dist/cli/traces-import-convert.js +211 -214
- package/dist/cli/traces-import-prepare.d.ts +26 -22
- package/dist/cli/traces-import-prepare.js +51 -122
- package/dist/cli/traces-import.d.ts +4 -4
- package/dist/cli/traces-import.js +63 -11
- 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.22.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
|
|
|
@@ -381,8 +381,8 @@ and Hue never receives or stores them. The command is part of the `hue` executab
|
|
|
381
381
|
# LANGFUSE_PUBLIC_KEY=pk-lf-...
|
|
382
382
|
# LANGFUSE_SECRET_KEY=sk-lf-...
|
|
383
383
|
# LANGFUSE_BASE_URL=https://cloud.langfuse.com
|
|
384
|
-
npx -y @hue-run/sdk@0.
|
|
385
|
-
npx -y @hue-run/sdk@0.
|
|
384
|
+
npx -y @hue-run/sdk@0.22.0 import langfuse --env-path .env.langfuse --from 2026-01-01 --dry-run
|
|
385
|
+
npx -y @hue-run/sdk@0.22.0 import langfuse --env-path .env.langfuse --from 2026-01-01 --media
|
|
386
386
|
```
|
|
387
387
|
|
|
388
388
|
`LANGFUSE_PUBLIC_KEY` and `LANGFUSE_SECRET_KEY` come from the environment or `--env-path`
|
|
@@ -433,10 +433,10 @@ instrumentation scope `@hue-run/sdk/import/langfuse`.
|
|
|
433
433
|
**Environment and Worlds.** A span whose observation, or v1 trace, records an environment also
|
|
434
434
|
carries it as recorded in `hue.import.source_environment`, which marks the trace as imported; one
|
|
435
435
|
that records none carries neither attribute, and the resource never declares
|
|
436
|
-
`deployment.environment.name`, since one import can mix environments.
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
436
|
+
`deployment.environment.name`, since one import can mix environments. Ended traces with a resolved
|
|
437
|
+
user can contribute to that user's World with any environment value or without an environment
|
|
438
|
+
declaration. Traces linked to Hue runs, World instances, or run executions never contribute.
|
|
439
|
+
Hue's evaluation and simulation evidence and deliberately excluded traces also stay excluded.
|
|
440
440
|
|
|
441
441
|
**Ids and resuming.** A Langfuse id that already is an OpenTelemetry id (32 lowercase hex digits for
|
|
442
442
|
a trace, 16 for an observation, as Langfuse's OpenTelemetry SDKs write them) is kept; any other id,
|
|
@@ -503,11 +503,12 @@ stopped.
|
|
|
503
503
|
|
|
504
504
|
## Import a bundle of existing traces
|
|
505
505
|
|
|
506
|
-
`hue traces import` brings historical traces into Hue from exports you already hold:
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
506
|
+
`hue traces import` brings historical traces into Hue from exports you already hold: OpenTelemetry
|
|
507
|
+
exports (OTLP/JSON, binary OTLP and OpenTelemetry Collector files, Jaeger, Zipkin), the exports of
|
|
508
|
+
LLM observability tools (Langfuse, Braintrust, LangSmith, Arize Phoenix, MLflow, Opik, W&B Weave,
|
|
509
|
+
Datadog LLM Observability, Helicone, Raindrop events and spans), OpenAI Agents SDK traces, ATIF trajectories and
|
|
510
|
+
plain chat transcripts. It needs no project key. `prepare` runs on the machine that holds the
|
|
511
|
+
exports and sends nothing; a Hue MCP connection then authorizes the delivery
|
|
511
512
|
(`prepare_trace_import`); `upload` delivers the bundle with that authorization, and
|
|
512
513
|
`get_trace_import` reports what arrived.
|
|
513
514
|
|
|
@@ -518,39 +519,232 @@ npx -y @hue-run/sdk@latest traces import upload ./exports.hue-import --authoriza
|
|
|
518
519
|
|
|
519
520
|
**Prepare.** `prepare <path>` reads a file, a directory tree or a ZIP archive (members are inflated
|
|
520
521
|
in memory; encrypted members, unsafe paths and nested archives are listed, not read) and
|
|
521
|
-
recognizes each file by its content, never by its name.
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
or
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
(`
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
522
|
+
recognizes each file by its content, never by its name. A file may be gzip (every member) or zstd
|
|
523
|
+
(every frame, skippable frames passed over; zstd needs Node.js 22.15 or later) compressed, at most
|
|
524
|
+
64 MiB decompressed, and hold one JSON document, a JSON array of records, JSON Lines or binary OTLP,
|
|
525
|
+
as UTF-8 or as UTF-16 after a byte order mark. Each line of JSON Lines, each record of a JSON array
|
|
526
|
+
that no format reads whole, and each message of a length-prefixed protobuf file is recognized on
|
|
527
|
+
its own. CSV and Parquet are not read: export JSON or JSON Lines.
|
|
528
|
+
|
|
529
|
+
Damage stays local. A gzip or zstd file that breaks off, or holds bytes after its last member or
|
|
530
|
+
frame, is read up to the break and the rest named in `files.notes`; one whose checksum fails is not
|
|
531
|
+
read. A line that is not UTF-8 is named and the other lines read. A bare `NaN`, `Infinity` or
|
|
532
|
+
`-Infinity` (Python's `json.dumps` writes them) is read as null and named in `files.notes`. A value
|
|
533
|
+
nested more than 512 levels deep is named and not read, and JSON text inside a record (metadata,
|
|
534
|
+
tool arguments) nested that deep is kept as the text it is. Past 1,000 records in a row from the
|
|
535
|
+
start of a JSON array that no format reads, the array is reported as unrecognized without reading
|
|
536
|
+
the rest.
|
|
537
|
+
|
|
538
|
+
Every trace becomes gzip OTLP/JSON batches of at most 3 MiB decoded and 900 KiB on the wire,
|
|
539
|
+
written to `--out` (default `<path>.hue-import`, created with mode 0700) beside `manifest.json`,
|
|
540
|
+
which declares each trace's id, span count, batches (by the SHA-256 of each gzip body), large
|
|
541
|
+
values, history owner and origin. A text value over 1 MiB is stored as a value of its own and
|
|
542
|
+
listed in `hue.blobs`, as the exporter lists the values it uploads. Nothing about where a file sat
|
|
543
|
+
or what it was called reaches a span: a renamed, reordered or re-zipped copy of the bundle prepares
|
|
544
|
+
to byte-identical batches and the same manifest digest.
|
|
545
|
+
|
|
546
|
+
**Formats.** Each value is read by the first format whose rule it matches, in the order
|
|
547
|
+
`hue traces --help` lists them; each rule asks for keys the other formats' records lack. The format
|
|
548
|
+
id is the key of the report's `formats`, and every span converted from a source record carries it
|
|
549
|
+
as `hue.import.format`; spans kept as recorded and spans of the documented Langfuse list carry
|
|
550
|
+
none. The last column is where the format finds the trace's end user (written as `user.id`) and
|
|
551
|
+
conversation (`gen_ai.conversation.id`); a tool span, tool row or tool call never names either.
|
|
552
|
+
|
|
553
|
+
| Format id | Source | Recognized by | User and conversation |
|
|
554
|
+
| --- | --- | --- | --- |
|
|
555
|
+
| `otlp_json` | OTLP/JSON trace export: one document, a list of them, or one per line | a `resourceSpans` (or `resource_spans`) list | the spans' own attributes, read as Hue reads them |
|
|
556
|
+
| `otlp_protobuf` | Binary OTLP: one protobuf `ExportTraceServiceRequest` (an OTLP/HTTP body, a `.pb` or `.binpb` file), or Collector file exporter output (`format: proto`, or `compression: zstd` around protobuf or JSON) | content that decodes as an OTLP trace request, or as messages each prefixed with its 4-byte big-endian length | the spans' own attributes |
|
|
557
|
+
| `jaeger_api_v3` | Jaeger API v3 answer and NDJSON stream | `{"result": {"resourceSpans": …}}` (or `result.spans`), the stream's `{"end": true}` and `{"error": {"httpCode": …}}` lines | the spans' own attributes |
|
|
558
|
+
| `jaeger` | Jaeger `/api/traces` answer, the UI's trace download, one trace, or a span with its process | a trace's `spans` holding a span with `spanID`, `operationName` and `startTime` | span tags, kept as attributes |
|
|
559
|
+
| `zipkin` | Zipkin v2 JSON: a list of spans, a list of such lists, one span per line, or one span | hex `traceId` and `id` with a field only a span records (`timestamp`, `duration`, `localEndpoint`, `kind`, `annotations`, `tags`), and none of `type`, `startTime`, `spanId`, `traceID`, `span_id` | span tags, kept as attributes |
|
|
560
|
+
| `phoenix_otlp` | Arize Phoenix `GET /v1/projects/{project}/spans/otlpv1`, or one such span per line | `trace_id`, `span_id` and `start_time_unix_nano` or `end_time_unix_nano`, without `context` or `root_span_id` | the spans' attributes, OpenInference `user.id` and `session.id` among them |
|
|
561
|
+
| `phoenix_spans` | Arize Phoenix `GET /v1/projects/{project}/spans` | `context.trace_id`, `context.span_id` and `start_time` or `span_kind` | the spans' attributes, OpenInference `user.id` and `session.id` among them |
|
|
562
|
+
| `datadog_llmobs` | Datadog LLM Observability export API answer, one span, or one per line | `"type": "span"` with `attributes.span_id` and `attributes.trace_id` | the `user_id`, `user.id` or `usr.id` tag, or `user_id` in `metadata`; `session_id` |
|
|
563
|
+
| `langfuse_observations` | The Langfuse observation list Hue documents | a `data` or `observations` list whose every record is an observation (`id`, `traceId`, `type`, `startTime`) without `projectId` | the observations' `userId` and `sessionId`, as `langfuse.user.id` and `langfuse.session.id` |
|
|
564
|
+
| `langfuse` | Everything Langfuse writes: `GET /api/public/traces/{id}`, v1 trace and observation pages, Observations API v2 pages, `GET /api/public/sessions/{id}`, UI downloads of the traces, observations and events tables, blob-storage files of the `traces`, `observations` and `observations_v2` tables | a trace (`id`, `timestamp`, `bookmarked`, `public`), an observation (`id`, `type`, `startTime`, `traceId`) or a blob-storage observation row (`start_time`, `trace_id`, `parent_observation_id`), alone or in `data`, `observations` or `traces` | the trace's `userId` and `sessionId`, else each observation's |
|
|
565
|
+
| `atif` | ATIF v1.7 and v1.8 exports, embedded subagents included | `schema_version` starting with `ATIF-` | `extra.user_id`; the run's `session_id` |
|
|
566
|
+
| `braintrust` | Braintrust span rows: a UI download, the fetch or query API's answer, `bt sync pull` JSON Lines or a cloud-storage export | `span_id` and `root_span_id`, alone or in `events` or `data` | `metadata` (`userId`, `user_id`; `session_id`, `thread_id`, `conversation_id`, …), Mastra's `resourceId`, an OpenAI Agents row's `group_id` |
|
|
567
|
+
| `langsmith_runs` | LangSmith runs: a `list_runs` dump, the runs query page or its v2 page, a run with its `child_runs`, bulk-export rows converted from Parquet to JSON Lines | `id`, a LangSmith `run_type` (`chain`, `llm`, `tool`, `embedding`, `retriever`, `prompt`, `parser`) and `start_time` or `dotted_order`, alone or in `runs` or `items` | run metadata (`userId`, `user_id`; `thread_id`, `session_id`, `conversation_id`, …) and the v2 `thread_id`; never the run's own `session_id` (the tracing project) or `ls_user_id` |
|
|
568
|
+
| `mlflow_traces` | MLflow `Trace.to_dict()` (`mlflow traces get`, `trace.to_json()`), a list or JSON Lines of them, `mlflow traces search --output json`, MLflow 2's form included | `info` with `trace_id` or `request_id`, and `data.spans`, alone or in `traces` | `mlflow.trace.user` and `mlflow.trace.session` metadata, else a span's `user.id` and `session.id`; never `mlflow.user` |
|
|
569
|
+
| `opik_traces` | The files `opik export … project …` writes, or spans alone (the spans API page or JSON Lines) | `trace` (with `id` and `start_time`) beside `spans`; or a span with `id`, `trace_id`, an Opik `type` (`general`, `tool`, `llm`, `guardrail`) and `start_time`, alone or in `content` | metadata (`userId`, `user_id`, …); the trace's `thread_id`, else its metadata's; never `created_by` |
|
|
570
|
+
| `weave_calls` | W&B Weave calls: the calls stream's JSON Lines, a list of calls, `{"calls": […]}` or `{"call": …}` | `id`, `trace_id`, `op_name` and `started_at` | `attributes` (`userId`, `user_id`, …); `thread_id`, else in `attributes`; never `wb_user_id` |
|
|
571
|
+
| `openai_agents` | OpenAI Agents SDK `Trace.export()` and `Span.export()` records, one per line or in a list, or the `{"data": […]}` body its exporter posts | `"object": "trace"` with `id`, or `"object": "trace.span"` with `trace_id` | the trace metadata's `userId` (or `user_id`); `group_id`, else a conversation field of the metadata |
|
|
572
|
+
| `raindrop` | Raindrop events: elements of a `POST /v1/events/track` payload, or a Query API `GET /v1/events` answer | `event` with `ai_data` (or with `event_id` and `user_id`), or `event_name` with `user_input` and `assistant_output`, alone or in `data` | `user_id`; `convo_id` |
|
|
573
|
+
| `raindrop_spans` | Raindrop's span rows: a Query API `GET /v1/traces?event_id=` answer, one row, or one per line | `trace_id`, `span_id`, `span_name`, `start_time_ns` and a Raindrop `span_type` (`INTERNAL`, `LLM_GENERATION`, `LLM_GENERATION_STREAM`, `TOOL_CALL`), alone or in `data` | the association attributes Raindrop's SDKs stamp on every span (`traceloop.association.properties.user_id` and `convo_id`, `ai.telemetry.metadata.raindrop.*`); the rows name no event, so `--user-key` names a user they lack |
|
|
574
|
+
| `helicone` | Helicone requests: `npx @helicone/export` JSON or JSON Lines (`--include-body` for the bodies), or the `query-clickhouse` API answer | `request_id` and `request_created_at` with `response_status`, `request_user_id` or `request_properties`, alone or in `data` | `request_user_id`, never `helicone_user` (the Helicone account); the `Helicone-Session-Id` property |
|
|
575
|
+
| `openai_chat` | An OpenAI Chat Completions request, or a line of a chat JSONL file (a fine-tuning or eval dataset) | a `messages` list holding a `{role}` message, without `object` and without anything only Anthropic sends | `safety_identifier`, else `user` |
|
|
576
|
+
| `openai_responses` | An OpenAI Responses `response` object, a request (with its `output` when it was logged with it), or a bare list of input and output items | `"object": "response"` with an `output` list; a value of request fields only, with an item list as `input`; or a list of Responses items | `safety_identifier`, else `user`; `conversation` |
|
|
577
|
+
| `anthropic_messages` | An Anthropic Messages request or response | a response (`"type": "message"`, `"role": "assistant"`, `content`, `model`), or a `messages` request carrying something only Anthropic sends (`system`, `anthropic_version`, `stop_sequences`, an `input_schema` tool, a `tool_use` or other Anthropic content block) and nothing only OpenAI sends | `metadata.user_id` |
|
|
578
|
+
|
|
579
|
+
**How each kind of format is converted.** OTLP/JSON, binary OTLP and Jaeger API v3 spans are kept
|
|
580
|
+
exactly as recorded, and the spans of one trace split between files of these formats are read as
|
|
581
|
+
one trace. A trace or span id that is not an OpenTelemetry id (an exporter's UUID, for example) is
|
|
582
|
+
mapped to one derived from it by SHA-256, with the original kept as `hue.import.original_trace_id`
|
|
583
|
+
or `hue.import.original_span_id`.
|
|
584
|
+
|
|
585
|
+
- Jaeger UI JSON, Zipkin v2 and Phoenix spans are written as the OTLP spans they were, as the
|
|
586
|
+
OpenTelemetry Collector converts Jaeger and Zipkin spans. Attributes keep their own names
|
|
587
|
+
(Phoenix's OpenInference attributes among them). The process or local endpoint is the resource.
|
|
588
|
+
The kind, status, scope, events and links come from the tags, references and annotations Jaeger
|
|
589
|
+
and Zipkin write them as, and the source span is kept whole as `hue.import.source_record`. A
|
|
590
|
+
64-bit Jaeger or Zipkin trace id is zero-padded to 128 bits as the Collector pads it, the
|
|
591
|
+
original kept, and a Zipkin server span that shares its client's id becomes the client's child
|
|
592
|
+
under an id derived from it.
|
|
593
|
+
- A Langfuse observation of the documented list becomes one span keeping its whole record
|
|
594
|
+
(`hue.import.source_record`) beside the `langfuse.*` and GenAI attributes Hue reads; an id that
|
|
595
|
+
is no OpenTelemetry id is mapped as `hue import langfuse` maps it, so an export and a live import
|
|
596
|
+
of the same trace agree.
|
|
597
|
+
- An ATIF export becomes one trace: an agent span for the run (`invoke_agent <agent.name>`), a
|
|
598
|
+
model span per agent step with the conversation so far, a tool span per call, and each embedded
|
|
599
|
+
subagent as its own agent span under the call that spawned it, under the instrumentation scope
|
|
600
|
+
`hue.import.atif`. ATIF records instants, not durations, so model and tool spans are points in
|
|
601
|
+
time, and a tool's result is kept as text with no error status of the importer's making.
|
|
602
|
+
- Every other format is read as rows: each record becomes one span of its trace, written by one
|
|
603
|
+
emitter under the GenAI conventions Hue reads. A model call carries `gen_ai.operation.name`
|
|
604
|
+
`chat`, its model, provider, messages and token usage; a tool call `execute_tool` with the tool's
|
|
605
|
+
name, call id, arguments and result; an agent `invoke_agent`. Chat content in the common shapes
|
|
606
|
+
(OpenAI chat messages and choices, OpenAI Responses items, Anthropic content blocks, LangChain
|
|
607
|
+
messages, plain strings) becomes GenAI message parts; any other content is kept as `input.value`
|
|
608
|
+
and `output.value`. An error is an error status with its message. The trace's user and
|
|
609
|
+
conversation go on its root spans (never a tool's), and each span keeps its whole source record
|
|
610
|
+
as `hue.import.source_record`. An attribute the source recorded under its own name (a Raindrop
|
|
611
|
+
span's `gen_ai.*`, for example) is kept as recorded, with none of the same name added beside it,
|
|
612
|
+
unless it names a user or conversation that `--user-key` or `--session-key` replaces.
|
|
613
|
+
- A vendor's own evaluation recorded inside a production trace is read as such, not as the
|
|
614
|
+
agent's work: a Braintrust span with `purpose: "scorer"` or of type `score`, `automation`,
|
|
615
|
+
`facet`, `classifier`, `preprocessor` or `review` (online scoring adds them to production
|
|
616
|
+
traces), and a Langfuse `EVALUATOR` observation. That span and everything beneath it (a judge's
|
|
617
|
+
model call) carry no GenAI operation, model, messages, tool call or usage, their content kept as
|
|
618
|
+
`input.value` and `output.value`, and never name the trace's user or conversation, as a tool's
|
|
619
|
+
subtree never does. The trace's origin is unchanged.
|
|
620
|
+
|
|
621
|
+
Rules shared by the row formats:
|
|
622
|
+
|
|
623
|
+
- Ids: a vendor's 32-hex trace id and 16-hex span id are kept (MLflow's base64 ids are read as the
|
|
624
|
+
hex they encode); any other id is mapped by SHA-256, the original kept as
|
|
625
|
+
`hue.import.original_trace_id` or `hue.import.original_span_id`. A parent
|
|
626
|
+
the export does not hold leaves the span a root of its trace, the original kept as
|
|
627
|
+
`hue.import.original_parent_span_id`. A Raindrop event without an `event_id` and a transcript
|
|
628
|
+
without an id of its own are named by the SHA-256 of the record's canonical JSON, so the same
|
|
629
|
+
record in two files is one trace.
|
|
630
|
+
- Copies: a record exported more than once keeps its latest copy, by the field the format records
|
|
631
|
+
it in (Braintrust's `_xact_id`, Langfuse's `updatedAt`, Opik's `last_updated_at`, Helicone's
|
|
632
|
+
`updated_at`, the ended copy of a LangSmith run, a Weave call, an OpenAI Agents span or a
|
|
633
|
+
Raindrop event). Copies of a span with no such field must agree, or the trace is refused. A
|
|
634
|
+
record identical to one read elsewhere (a repeated line of a chat JSONL file, an overlap of two
|
|
635
|
+
exports) is read once, and the value that added nothing new is named in `files.notes`.
|
|
636
|
+
- Token counts follow the GenAI conventions: input includes cached input and output includes
|
|
637
|
+
reasoning, with the cached, cache-write and reasoning counts also kept on their own. Helicone
|
|
638
|
+
stores `prompt_tokens` without `prompt_cache_read_tokens` and `prompt_cache_write_tokens`, and
|
|
639
|
+
`completion_tokens` without `reasoning_tokens`, so those are added back. LangSmith's cache writes
|
|
640
|
+
are read under `cache_creation`, the v2 API's `cache_write`, or the sum of
|
|
641
|
+
`ephemeral_5m_input_tokens` and `ephemeral_1h_input_tokens` that its Anthropic wrapper records.
|
|
642
|
+
- Kinds a source recorded late: Weave records an op's kind (`attributes.weave.kind`) since January
|
|
643
|
+
2026; an earlier call from an op Weave's integrations patch (`openai.chat.completions.create`,
|
|
644
|
+
`anthropic.Messages.create`, `litellm.completion` and the rest of its model-call ops; MCP
|
|
645
|
+
`call_tool` and CrewAI tools) is read as the kind those integrations give it now.
|
|
646
|
+
- Links: an MLflow span's `links` become span links, to a span of its own trace or of another.
|
|
647
|
+
- Origin: Braintrust experiment rows and dataset records (`dataset_id`), LangSmith runs with a
|
|
648
|
+
`reference_example_id`, MLflow traces tagged `mlflow.eval.requestId` or
|
|
649
|
+
`mlflow.trace.sourceScorer`, Opik traces from an experiment, evaluator, optimization or the
|
|
650
|
+
playground, Weave traces with an `Evaluation.*` op or a scorer as their root (a scorer applied
|
|
651
|
+
inside the application's own op, a guardrail, is a span of its production trace), Datadog
|
|
652
|
+
`experiment` spans and every span ddtrace tags with an `experiment_id`, Helicone requests of an
|
|
653
|
+
experiment or a Helicone evaluator (the `Helicone-Experiment-Id` or `Helicone-Evaluator`
|
|
654
|
+
property, matched without regard to case), and Langfuse's `sdk-experiment` and `langfuse-…`
|
|
655
|
+
environments (in both Langfuse formats) are declared evaluation traffic.
|
|
656
|
+
- Instants: Datadog's `start_ns` and `duration` are nanoseconds, and a `start_ns` too small to be
|
|
657
|
+
nanoseconds is read as milliseconds or microseconds by its size, the span's `duration` in the
|
|
658
|
+
same unit (`start_ns_read_as_ms` and `duration_read_as_ms`, or the `_us` pair). An ISO instant without a zone (LangSmith, Langfuse's ClickHouse
|
|
659
|
+
`YYYY-MM-DD HH:MM:SS.ffffff`) is UTC. Where a source records no instant, a fixed rule fills it
|
|
660
|
+
in, names it on the span (`hue.import.timing`) and counts it in the report (`traces.timing`):
|
|
661
|
+
- a span without a start starts at its end (`start_at_end`), else with its parent
|
|
662
|
+
(`start_from_parent`), else with the trace's earliest instant (`start_from_trace`);
|
|
663
|
+
- a span without an end ends with its last child (`end_from_children`), else at its start
|
|
664
|
+
(`end_at_start`);
|
|
665
|
+
- a trace that records no instant at all is placed at 2000-01-01T00:00:00Z, a millisecond per
|
|
666
|
+
record in source order (`untimed_trace`); plain transcripts record none except a Responses
|
|
667
|
+
object's `created_at`;
|
|
668
|
+
- a format that takes an instant from another field names that too: Braintrust's `created`
|
|
669
|
+
(`start_from_created`), a LangSmith run's `dotted_order` (`start_from_dotted_order`), a
|
|
670
|
+
Helicone request's `delay_ms` (`end_from_latency`) and a Raindrop span's `duration_ns`
|
|
671
|
+
(`end_from_duration`);
|
|
672
|
+
- an event recorded without a time (a Braintrust log row, an MLflow span event) is placed at its
|
|
673
|
+
span's start (`event_at_span_start`).
|
|
674
|
+
|
|
675
|
+
The same rules fill in the instants a Zipkin or Phoenix span was exported without.
|
|
676
|
+
|
|
677
|
+
**History owner.** A trace's owner is read from its spans as Hue reads it: the trace's local roots
|
|
678
|
+
(spans with no parent, or one outside the trace) first, then its other spans, never a tool span or
|
|
679
|
+
anything beneath one, and every span that names one must agree. An explicit
|
|
680
|
+
`hue.world.entity.namespace` and `hue.world.entity.id` wins over a user. A user is the first of
|
|
681
|
+
`user.id`, `enduser.id` and the other attributes and metadata fields Hue reads (OpenTelemetry,
|
|
682
|
+
Vercel AI SDK, OpenLLMetry, Langfuse, LangSmith, Braintrust, Mastra and OpenInference metadata),
|
|
683
|
+
except that `user.id` beside `user.account_uuid` names a Claude Code installation and is passed
|
|
684
|
+
over.
|
|
685
|
+
|
|
686
|
+
**`--user-key` and `--session-key`.** For an export whose user sits under a key of its own,
|
|
687
|
+
`--user-key <key>` names it, and `--session-key <key>` names the conversation the same way. The key
|
|
688
|
+
is one of:
|
|
689
|
+
|
|
690
|
+
- a dotted key such as `app.customer_id`, looked up as an attribute of each span or its resource,
|
|
691
|
+
then in the record's metadata (the exact key, then as a dotted path), then in the record itself;
|
|
692
|
+
- a JSONPath of members and indexes into the source record: `$.metadata.customer.id`,
|
|
693
|
+
`$.metadata["customer.id"]` or `$.tags[0]`;
|
|
694
|
+
- a JSON Pointer into the source record: `/metadata/customer/id`.
|
|
695
|
+
|
|
696
|
+
The key is read on the agent's spans as the owner is: the roots' value when they name one, else the
|
|
697
|
+
other spans', never a tool span's, and spans that disagree name nobody. For a row format (the
|
|
698
|
+
`langfuse` format among them) the key's value is written as the root's `user.id` (or
|
|
699
|
+
`gen_ai.conversation.id`) in place of the user the record names, and no span keeps an attribute it
|
|
700
|
+
recorded that Hue would read another user (or conversation) from, so the trace names the key's
|
|
701
|
+
value, or nobody when its spans disagree. A trace kept as recorded or converted span for span (OTLP,
|
|
702
|
+
Jaeger, Zipkin, Phoenix, the documented Langfuse list, ATIF) that names no owner gains one child
|
|
703
|
+
span of the agent's earliest local root (never a tool span), `hue.import.user` with the single
|
|
704
|
+
attribute `user.id` (or `hue.import.session` with `gen_ai.conversation.id`), so its recorded spans
|
|
705
|
+
keep their bytes and a trace also sent live does not conflict. An owner the spans already name is
|
|
706
|
+
kept, and a trace with no root but tool spans gains nothing.
|
|
707
|
+
|
|
708
|
+
**Limits and refusals.** A malformed record refuses its trace, never the file: an OTLP trace with a
|
|
709
|
+
malformed span (an attribute value of no OTLP shape, a protobuf span that does not decode) or whose
|
|
710
|
+
parents close on themselves is refused rather than imported without it, and the request's other
|
|
711
|
+
traces are read. A page of the documented Langfuse list holding an integer too large to represent
|
|
712
|
+
exactly refuses only the traces of the observations that hold one. The same trace in two files is
|
|
713
|
+
one trace when the copies agree and a refusal when they differ. A trace with more than 100,000
|
|
714
|
+
spans, 512 batches or 10,000 values is refused and named, as is a transcript whose turns together
|
|
715
|
+
repeat more than 64 MiB of conversation (each turn's model span holds the conversation before it).
|
|
716
|
+
An input of more than 25,000 traces, more than 256 MiB decompressed (every trace is held until all
|
|
717
|
+
are read; prepare a larger export in parts, each to its own `--out`), or whose manifest would exceed
|
|
718
|
+
32 MiB (4 MiB compressed), is refused whole. The messages of one length-prefixed protobuf file share
|
|
719
|
+
the 64 MiB a file may decompress to.
|
|
720
|
+
|
|
721
|
+
**Report.** `prepare` reports what it read and what it could not, down to the line; `--json` prints
|
|
722
|
+
the report as one object:
|
|
723
|
+
|
|
724
|
+
- `manifest_digest`, `totals` (traces, batches, spans, blobs, bytes) and `source`, which
|
|
725
|
+
`prepare_trace_import` takes as given;
|
|
726
|
+
- `formats`: the traces prepared per format id;
|
|
727
|
+
- `files.supported`: each file read, with its format and the traces it held;
|
|
728
|
+
- `files.unsupported`: each file of which nothing could be read, with the reason (not JSON, a JSON
|
|
729
|
+
document of no recognized format, an OTLP logs or metrics export, an export page with no
|
|
730
|
+
records, an encrypted or nested ZIP member);
|
|
731
|
+
- `files.skipped`: each line of JSON Lines (`line`), record of a JSON array (`record`) or message
|
|
732
|
+
of a length-prefixed protobuf file (`line`) that could not be read, with the reason, in file
|
|
733
|
+
order; the rest of the file is read, and past 100 in one file the rest are counted in one entry;
|
|
734
|
+
- `files.notes`: what was read with a repair or read once though the input held it more than once
|
|
735
|
+
(a gzip or zstd file read up to a break, `NaN` read as null, a record identical to one read
|
|
736
|
+
elsewhere), with its `line` or `record`; past 100 in one file the rest are counted;
|
|
737
|
+
- `traces.refused`: each trace or record refused, with its `file`, `line`, `record` and `trace_id`
|
|
738
|
+
where known and the reason;
|
|
739
|
+
- `traces.timing`: the traces whose instants a rule supplied, per rule;
|
|
740
|
+
- `traces.without_identity`: the traces without a declared history owner, which import like any
|
|
741
|
+
other trace and can contribute to a World if Hue resolves their owner from the imported records;
|
|
742
|
+
- `traces.by_origin`: the origin each source recorded (`production`, `evaluation`, `simulation` or
|
|
743
|
+
`unknown`); evaluation and simulation traffic is imported and kept out of production history;
|
|
744
|
+
- `traces.remapped`: the traces and spans whose vendor ids were mapped.
|
|
745
|
+
|
|
746
|
+
An existing `--out` directory is accepted only while it holds nothing but an earlier preparation
|
|
747
|
+
and no upload has started in it.
|
|
554
748
|
|
|
555
749
|
**Authorize.** Call `prepare_trace_import` over the Hue MCP with the report's `manifest_digest`,
|
|
556
750
|
`totals` and `source`. It answers the import id, `upload_url` and an `authorization` (`hue_it_` and
|
|
@@ -698,7 +892,7 @@ node packages/sdk-typescript/scripts/verify-package.mjs --artifacts-dir .artifac
|
|
|
698
892
|
# Set project to an existing supported fixture; use the same directory on resume.
|
|
699
893
|
project=/absolute/path/to/supported-fixture
|
|
700
894
|
node packages/sdk-typescript/scripts/verify-setup-live.mjs \
|
|
701
|
-
--archive .artifacts/typescript/hue-run-sdk-0.
|
|
895
|
+
--archive .artifacts/typescript/hue-run-sdk-0.22.0.tgz \
|
|
702
896
|
--origin https://STAGING_ORIGIN \
|
|
703
897
|
--project "$project" --command setup \
|
|
704
898
|
--evidence .context/setup-staging-before-claim.json
|
|
@@ -709,7 +903,7 @@ the private local handoff and finish the real browser claim, then reconcile the
|
|
|
709
903
|
|
|
710
904
|
```sh
|
|
711
905
|
node packages/sdk-typescript/scripts/verify-setup-live.mjs \
|
|
712
|
-
--archive .artifacts/typescript/hue-run-sdk-0.
|
|
906
|
+
--archive .artifacts/typescript/hue-run-sdk-0.22.0.tgz \
|
|
713
907
|
--origin https://STAGING_ORIGIN \
|
|
714
908
|
--project "$project" --command claim \
|
|
715
909
|
--evidence .context/setup-staging-after-claim.json
|
|
@@ -751,10 +945,10 @@ otherwise. Never hand the agent Hue-native tools (`context.tools`, `context.mcp`
|
|
|
751
945
|
production agent lacks. Pin the SDK, so the agent's repository gains no dependency:
|
|
752
946
|
|
|
753
947
|
```sh
|
|
754
|
-
npx -y @hue-run/sdk@0.
|
|
755
|
-
npx -y @hue-run/sdk@0.
|
|
756
|
-
npx -y @hue-run/sdk@0.
|
|
757
|
-
npx -y @hue-run/sdk@0.
|
|
948
|
+
npx -y @hue-run/sdk@0.22.0 eval --case "Refund an eligible charge" --command "node agent.js"
|
|
949
|
+
npx -y @hue-run/sdk@0.22.0 eval --case https://app.hue.run/projects/demo/scenarios/<id> --command "python agent.py" --timeout 120 --baseline <run id>
|
|
950
|
+
npx -y @hue-run/sdk@0.22.0 eval --set "Billing regressions" --scorer-version <id> --command "node agent.js" --save-version
|
|
951
|
+
npx -y @hue-run/sdk@0.22.0 eval --worker --command "node agent.js" --agent-key support-agent --revision <new-agent-revision>
|
|
758
952
|
```
|
|
759
953
|
|
|
760
954
|
One invocation creates one run holding every selected case; it prints the run URL
|
|
@@ -792,7 +986,7 @@ export default function runMyAgent(inputs: JsonValue, context: SimulationTargetC
|
|
|
792
986
|
```
|
|
793
987
|
|
|
794
988
|
```sh
|
|
795
|
-
npx -y @hue-run/sdk@0.
|
|
989
|
+
npx -y @hue-run/sdk@0.22.0 eval --case "Refund an eligible charge" ./hue-agent.ts --content
|
|
796
990
|
```
|
|
797
991
|
|
|
798
992
|
`--scenario` remains an alias for `--case` for existing scripts. Pass one selection flag.
|
package/README.md
CHANGED
|
@@ -552,8 +552,8 @@ the Langfuse project's own keys (`LANGFUSE_PUBLIC_KEY`, `LANGFUSE_SECRET_KEY`, a
|
|
|
552
552
|
`HUE_API_KEY`:
|
|
553
553
|
|
|
554
554
|
```sh
|
|
555
|
-
npx -y @hue-run/sdk@0.
|
|
556
|
-
npx -y @hue-run/sdk@0.
|
|
555
|
+
npx -y @hue-run/sdk@0.22.0 import langfuse --env-path .env.langfuse --from 2026-01-01 --dry-run
|
|
556
|
+
npx -y @hue-run/sdk@0.22.0 import langfuse --env-path .env.langfuse --from 2026-01-01 --media
|
|
557
557
|
```
|
|
558
558
|
|
|
559
559
|
- It reads Langfuse Cloud and self-hosted v4 through the Observations API v2, and self-hosted v3
|
|
@@ -563,8 +563,11 @@ npx -y @hue-run/sdk@0.21.1 import langfuse --env-path .env.langfuse --from 2026-
|
|
|
563
563
|
`langfuse.observation.*` and `langfuse.trace.*` attributes Hue reads, the user, session, release
|
|
564
564
|
and environment, and the model and token counts as GenAI attributes. Hex ids are kept and other
|
|
565
565
|
ids derived from them, so running the same command again resumes an import without duplicates.
|
|
566
|
-
- Langfuse's environment is also sent, as recorded, as `hue.import.source_environment
|
|
567
|
-
traces
|
|
566
|
+
- Langfuse's environment is also sent, as recorded, as `hue.import.source_environment`.
|
|
567
|
+
Ended traces with a resolved user can contribute to that user's World with any environment
|
|
568
|
+
value or without an environment declaration. Traces linked to Hue runs, World instances, or
|
|
569
|
+
run executions never contribute. Hue's evaluation and simulation evidence and deliberately
|
|
570
|
+
excluded traces also stay excluded.
|
|
568
571
|
- Spans are exported by the SDK's transport with its content-capture default; `--no-content`
|
|
569
572
|
sends metadata only.
|
|
570
573
|
- With `--media`, files that Langfuse media references point to are downloaded and uploaded under
|
|
@@ -580,9 +583,7 @@ mapping, media handling, limits and exit codes.
|
|
|
580
583
|
|
|
581
584
|
`hue traces import` brings exports you already hold into Hue in two steps, with no project key.
|
|
582
585
|
`prepare` converts the bundle on your machine and sends nothing; a Hue MCP connection authorizes
|
|
583
|
-
the delivery with `prepare_trace_import`; `upload` delivers it with that authorization
|
|
584
|
-
are files, directories or ZIP archives of OTLP/JSON trace exports, complete Langfuse observation
|
|
585
|
-
exports and text ATIF v1.7 and v1.8 exports, recognized by content:
|
|
586
|
+
the delivery with `prepare_trace_import`; `upload` delivers it with that authorization:
|
|
586
587
|
|
|
587
588
|
```sh
|
|
588
589
|
npx -y @hue-run/sdk@latest traces import prepare ./exports --out ./exports.hue-import --json
|
|
@@ -591,18 +592,37 @@ npx -y @hue-run/sdk@latest traces import prepare ./exports --out ./exports.hue-i
|
|
|
591
592
|
npx -y @hue-run/sdk@latest traces import upload ./exports.hue-import --authorization-file ./authorization.json --json
|
|
592
593
|
```
|
|
593
594
|
|
|
594
|
-
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
595
|
+
- Sources are files, directories or ZIP archives, gzip or zstd compressed or not, holding JSON
|
|
596
|
+
documents, arrays, JSON Lines or binary OTLP. Each file is recognized by its content, never its
|
|
597
|
+
name, in these formats: OTLP/JSON, OTLP protobuf and OpenTelemetry Collector file exports,
|
|
598
|
+
Jaeger, Zipkin v2, Langfuse (API answers, UI downloads and blob-storage files), Braintrust span
|
|
599
|
+
rows, LangSmith runs, Arize Phoenix spans, MLflow traces, Opik exports, W&B Weave calls, Datadog
|
|
600
|
+
LLM Observability spans, OpenAI Agents SDK traces, Raindrop events and span rows, Helicone
|
|
601
|
+
requests, ATIF v1.7 and v1.8, and OpenAI chat, OpenAI Responses and Anthropic Messages
|
|
602
|
+
transcripts. One `prepare` reads up to 256 MiB decompressed; prepare a larger export in parts.
|
|
603
|
+
- `prepare` writes each trace as gzip OTLP/JSON batches beside a manifest. Spans of OTLP exports
|
|
604
|
+
(Jaeger API v3 answers included) are kept as recorded, and Jaeger, Zipkin and Phoenix spans
|
|
605
|
+
become the OTLP spans they were. Every other record becomes the GenAI spans Hue reads, with its
|
|
606
|
+
model and tool calls, token usage and errors, and keeps its whole source record. Each trace's end
|
|
607
|
+
user and conversation are read where the source names them, never from a tool's arguments or
|
|
608
|
+
result, and a converted record carries them as `user.id` and `gen_ai.conversation.id` on the
|
|
609
|
+
trace's root. `--user-key` and `--session-key` name them for an export that records them under
|
|
610
|
+
keys of its own.
|
|
611
|
+
- The report gives the manifest's digest and totals, the traces per format, the files it could not
|
|
612
|
+
read, each line or record of a file it could not read (the rest of the file is read), what it
|
|
613
|
+
read with a repair (a compressed file read up to a break, `NaN` read as null) or read once though
|
|
614
|
+
the input held it twice, the traces refused (a malformed record refuses only its trace), the instants filled in by a fixed rule,
|
|
615
|
+
invalid vendor ids mapped to OpenTelemetry ids, and the traces without a declared history owner,
|
|
616
|
+
read from the spans as Hue reads them. Nothing about a file's name or place reaches a span.
|
|
598
617
|
- `upload` registers the manifest, sends each trace's large values and batches in order, two
|
|
599
618
|
requests at a time, checks every span's receipt, reconciles and completes the import. Interrupted,
|
|
600
619
|
run it again: it resumes from `progress.json` in the bundle. An expired authorization is renewed
|
|
601
620
|
by calling `prepare_trace_import` again with the same digest and totals.
|
|
602
621
|
- The authorization (`hue_it_…`) is read only from the file and never printed.
|
|
603
622
|
|
|
604
|
-
See [Import a bundle of existing traces](CLI.md#import-a-bundle-of-existing-traces) for
|
|
605
|
-
|
|
623
|
+
See [Import a bundle of existing traces](CLI.md#import-a-bundle-of-existing-traces) for how each
|
|
624
|
+
format is recognized and where its user and conversation come from, the report, what Hue refuses
|
|
625
|
+
and the exit codes.
|
|
606
626
|
|
|
607
627
|
## Sub-agents
|
|
608
628
|
|
|
@@ -732,6 +752,27 @@ but those integrations do not receive that call's events. To keep an existing
|
|
|
732
752
|
OpenTelemetry exporter, attach Hue's transport to the same provider using the
|
|
733
753
|
[existing-provider recipe](#existing-opentelemetry-providers).
|
|
734
754
|
|
|
755
|
+
The end user and conversation can also come from AI SDK 7's runtime context. `hueTelemetry(hue)`
|
|
756
|
+
records the call's `runtimeContext.userId` as `user.id`, and `runtimeContext.sessionId` (else
|
|
757
|
+
`threadId`) as `gen_ai.conversation.id`, on every span of the call; a value that is neither a
|
|
758
|
+
non-empty string nor a finite number is ignored. The returned options name those keys in `includeRuntimeContext`,
|
|
759
|
+
because AI SDK withholds runtime context from telemetry unless a key is named there; no other
|
|
760
|
+
runtime-context value is recorded. An enclosing `withSpan`'s `userId` or `sessionId` takes
|
|
761
|
+
precedence:
|
|
762
|
+
|
|
763
|
+
```ts
|
|
764
|
+
const result = await generateText({
|
|
765
|
+
model,
|
|
766
|
+
prompt,
|
|
767
|
+
runtimeContext: { userId: user.id, sessionId: chat.id },
|
|
768
|
+
telemetry: hueTelemetry(hue),
|
|
769
|
+
});
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
For other keys, pass `hueTelemetry(hue, { userKey: "accountId", sessionKey: ["chatId"] })`;
|
|
773
|
+
`false` records none from runtime context. An application that sets its own
|
|
774
|
+
`includeRuntimeContext` keeps these keys by spreading the returned one into it.
|
|
775
|
+
|
|
735
776
|
Reuse the client across server requests. Await stream completion before flushing;
|
|
736
777
|
returning a streaming `Response` does not mean its stream has finished. The
|
|
737
778
|
[Next.js streaming recipe](https://docs.hue.run/integrations/opentelemetry#flush-streamed-responses-in-next-js)
|
package/WORLDS.md
CHANGED
|
@@ -110,9 +110,12 @@ await hue.withSpan("assistant request", () =>
|
|
|
110
110
|
await hue.shutdownSafe();
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
An attached client uses your application's existing OpenTelemetry resource
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
An attached client uses your application's existing OpenTelemetry resource. Ended traces with a
|
|
114
|
+
resolved user can contribute to that user's World with any environment value or without an
|
|
115
|
+
environment declaration. Historical records sent over OTLP follow the same rule. The
|
|
116
|
+
[verified import route](https://docs.hue.run/guides/import-traces) retains the recorded origin and
|
|
117
|
+
follows the same rule after verification. Traces linked to Hue runs, World instances, or run executions never contribute.
|
|
118
|
+
Hue's evaluation and simulation evidence and deliberately excluded traces also stay excluded.
|
|
116
119
|
|
|
117
120
|
Use the same fields with your framework's tool-span hook. A parent-only account label cannot
|
|
118
121
|
resolve several accounts used by different tool calls. Account IDs and resource IDs stay separate;
|
package/dist/ai-sdk.d.ts
CHANGED
|
@@ -1,12 +1,34 @@
|
|
|
1
1
|
import type { TelemetryOptions } from "ai";
|
|
2
2
|
import type { HueClient } from "./client.js";
|
|
3
|
+
/** Options for {@link hueTelemetry}. */
|
|
4
|
+
export interface HueTelemetryOptions {
|
|
5
|
+
/**
|
|
6
|
+
* The runtime-context key whose value names the end user, recorded as `user.id` on the call's
|
|
7
|
+
* spans. `"userId"` by default; `false` records no user from runtime context.
|
|
8
|
+
*/
|
|
9
|
+
userKey?: string | false;
|
|
10
|
+
/**
|
|
11
|
+
* The runtime-context keys whose value names the conversation, recorded as
|
|
12
|
+
* `gen_ai.conversation.id` on the call's spans; the first key with a value wins.
|
|
13
|
+
* `["sessionId", "threadId"]` by default; `false` records no conversation from runtime context.
|
|
14
|
+
*/
|
|
15
|
+
sessionKey?: string | readonly string[] | false;
|
|
16
|
+
}
|
|
3
17
|
/**
|
|
4
18
|
* Per-call telemetry for AI SDK 7: pass as an agent's or generation call's `telemetry` option.
|
|
5
19
|
* Spans come from Hue's tracer, so they parent under `withSpan` and inherit session, user and
|
|
6
20
|
* workspace identifiers; prompt and response recording follow `captureContent`. It does not
|
|
7
21
|
* change global AI SDK integrations.
|
|
8
22
|
*
|
|
23
|
+
* The end user and conversation can also come from the call's AI SDK runtime context: the value
|
|
24
|
+
* under `userKey` (`userId` by default) is recorded as `user.id`, and the first value under
|
|
25
|
+
* `sessionKey` (`sessionId`, then `threadId`) as `gen_ai.conversation.id`, on every span of the
|
|
26
|
+
* call. The returned `includeRuntimeContext` names those keys, which AI SDK otherwise withholds
|
|
27
|
+
* from telemetry; no other runtime-context value is recorded. An enclosing `withSpan`'s
|
|
28
|
+
* `userId` or `sessionId` takes precedence.
|
|
29
|
+
*
|
|
9
30
|
* @throws TypeError when the client is enabled and the installed `ai` major version is below 7;
|
|
10
31
|
* AI SDK 6 applications use `hueExperimentalTelemetry` from `@hue-run/sdk` instead.
|
|
32
|
+
* @throws TypeError when `userKey` or `sessionKey` names an empty key.
|
|
11
33
|
*/
|
|
12
|
-
export declare function hueTelemetry(hue: HueClient): TelemetryOptions;
|
|
34
|
+
export declare function hueTelemetry(hue: HueClient, options?: HueTelemetryOptions): TelemetryOptions;
|