@hue-run/sdk 0.27.0 on Node.js 22 or 24 and Bun 1.4. For installation and a runnable first trace, use the TypeScript guide. See compatibility for supported runtimes and integration versions. Use Quickstart for the available package release.
Imports
The package is ESM; CommonJS applications on Node.js 22.12 or later load every entry point with
require(). The SDK runs on the server. It does not call a model provider for you or create model spans for uninstrumented provider calls. Every exported type, option and member carries API documentation in the published declarations.
Create a tracing client
createHue(options: HueOptions | ExistingHueProviders): HueClient and new HueClient(options) accept the same configuration. HueOptions is SharedHueOptions, the options every client and transport accepts, plus enabled, apiKey and serviceName.
HueOptions
Invalid configuration throws
TypeError. Environment variables are read by your application and passed to the client; these constructors do not automatically load an environment file, and OTEL_EXPORTER_OTLP_* variables do not reach Hue’s exporters. Owned providers export the OpenTelemetry default resource (telemetry.sdk.language, telemetry.sdk.name, telemetry.sdk.version) beside service.name, service.version and resourceAttributes. Export requests carry a hue-sdk-typescript/<version> User-Agent.
ExistingHueProviders
UsecreateHueTransport(options: HueOptions): HueTransport when your application owns OpenTelemetry setup. Attach its spanProcessor and logRecordProcessor during provider construction, then pass:
tracerProvider is a FlushableTracerProvider and loggerProvider a FlushableLoggerProvider: the OpenTelemetry API provider types plus forceFlush(): Promise<void>, which the OpenTelemetry SDK providers satisfy. Your application owns their resources, registration and shutdown; resourceAttributes is ignored with a warning issue in this mode. Hue never replaces the global tracer provider, logger provider or context manager. See the complete existing-provider recipe.
Trace application work
The signatures below use types exported by@hue-run/sdk and standard OpenTelemetry types.
withSpan returns the callback’s result, ends the span after the callback settles, and records then rethrows an escaping application error. Consume streams inside the callback if their work belongs to that span. A returned streaming Response is not evidence that the stream has finished.
tool runs execute inside a span named execute_tool {name} with gen_ai.tool.name, records input and a defined result as gen_ai.tool.call.arguments / gen_ai.tool.call.result according to your content policy, and returns the tool result. An undefined result omits result content. options.parentContext supplies an explicit parent for the tool span. ToolOptions extends Pick<SpanOptions, "parentContext"> with callId, the provider-issued tool-call id recorded as gen_ai.tool.call.id, and mcp, an McpServerInfo (the MCP initialize serverInfo, passed as client.getServerVersion() after connect) recorded as mcp.server.name / mcp.server.version so a generic tool name is attributed to the server that handled the call. When the server is a Hue surface, McpServerInfo also takes provider and surface (for example google.gmail and google.gmail/mcp), recorded as hue.mcp.provider / hue.mcp.surface. A blank, over-256-character or otherwise invalid label is omitted and counted as an instrumentation failure; the tool still runs.
ToolOptions.endpoint takes a ToolEndpoint with the actual HTTP(S) URL used by the tool:
method records the actual method when known, with no default. The option records routing evidence supplied by your application; it makes no request and never infers a URL from a tool or server label.
model runs callback inside a GenAI client span for one direct provider call, named {operation} {model} unless options.name is given, with gen_ai.operation.name, gen_ai.request.model and gen_ai.provider.name. The argument order matches withSpan. Inside it, the handle’s setInput and setOutput record gen_ai.input.messages / gen_ai.output.messages, which should use the GenAI semantic-convention message shape; recordMessages inside the callback inherits the request metadata. When you send system instructions or tools separately from the messages, pass them as systemInstructions and tools in ModelOptions.
Content helpers (setInput, setOutput, tool arguments and results, recordMessages and SpanOptions.input) accept unknown and encode plain JSON data (JsonValue) at runtime. A value that is not JSON, such as a Date or a class instance, is omitted with an instrumentation failure while the callback result is returned unchanged.
recordMessages emits a correlated gen_ai.client.inference.operation.details log record with the messages, and optional systemInstructions as gen_ai.system_instructions, in its body. gen_ai.operation.name, gen_ai.provider.name and gen_ai.request.model are set as record attributes from the caller’s operation, provider and model or from the enclosing model() span, and gen_ai.conversation.id from the active session. With content capture enabled, it requires an active span or explicit span context. With capture disabled, it emits nothing. Use logs or span attributes for the same content event to avoid storing duplicate copies.
recordError marks a span failed the way every helper does: error.type (the error’s name), an ERROR status without a description and an exception event carrying only exception.type. Exception messages and stack traces are never recorded, whatever captureContent is.
inject writes W3C traceparent for the active span into a carrier, never the API key or baggage, and also propagates when the client is disabled or closed. extract reads W3C trace context from a carrier for use as parentContext. Hue registers no global propagator.
SpanOptions and context
Session, user and workspace identifiers must contain 1–4096 valid characters.
hue.tracer is an OpenTelemetry tracer that preserves Hue’s local async context; spans other instrumentations create through it parent under withSpan and inherit identifiers. hue.getContext() supplies the helper’s current context to an integration that accepts an explicit parent. When your application has registered a context manager, withSpan, tool, model and hue.tracer.startActiveSpan also make their span the active OpenTelemetry span while the callback runs; Hue registers none itself.
ModelOptions
ModelOptions extends the sessionId, userId, workspaceId, input and parentContext members of SpanOptions.
Labels must be non-empty strings of at most 256 characters; other values fall back to
"unknown" or "chat" and count as instrumentation failures.
HueSpan
The callback receivesspan (the underlying OpenTelemetry span), context, traceId, spanId, setInput(value: unknown), setOutput(value: unknown) and setUsage(usage: TokenUsage). Inside model(), setInput and setOutput record gen_ai.input.messages and gen_ai.output.messages; elsewhere they record input.value and output.value. TokenUsage is { inputTokens?: number; outputTokens?: number }, recorded as gen_ai.usage.input_tokens and gen_ai.usage.output_tokens; invalid values are omitted and counted as instrumentation failures. IDs are all zeros for a disabled client.
Use span.setAttribute(...), span.addEvent(...) and the other standard OpenTelemetry APIs for additional metadata. Hue does not estimate absent token counts or cost. Captured JSON null, false, 0 and "" remain present values; they are distinct from an omitted field. When uploads are available, helper content can serialize up to 1 GB and 1,048,576 values; otherwise it is bounded by the receiver’s inline limit.
Provider-executed tools
Tools the provider runs itself, such as OpenAI hosted MCP, web search, file search and code interpreter, or Anthropic’s MCP connector and server tools, never pass throughhue.tool(). Inside the same model() callback, hand the response to recordProviderToolCalls:
mcp_call, web_search_call, file_search_call or code_interpreter_call item, and each Anthropic mcp_tool_use or server_tool_use block with its result, becomes an execute_tool {name} child span with gen_ai.tool.type extension, gen_ai.tool.call.id and, for MCP calls, mcp.server.name (the provider’s label). Arguments and results follow captureContent; a failed call carries error.type (mcp_error, or the provider’s status or error code) and an ERROR status. An OpenAI mcp_list_tools item becomes a tools/list child span with that server’s gen_ai.tool.definitions. The spans have no duration of their own: the provider ran the tools inside the model request. Unreadable items are skipped and counted as instrumentation failures; nothing is thrown.
ProviderToolCallOptions extends Pick<SpanOptions, "parentContext">:
Composio and Pipedream
Since0.24.0, instrumentComposio(hue, composio) and instrumentPipedream(hue, pipedream) patch the client instance you already hold and return it, so each composio.tools.execute(slug, params), Tool Router session.execute(slug, arguments) or pipedream.actions.run({ id, ... }) call records its own execute_tool {tool} span under the active span, even inside a wrapper tool. The span carries hue.integration.platform (composio or pipedream), hue.integration.version when the call pins a version, the platform’s REST request fields as gen_ai.tool.call.arguments and the SDK’s response as gen_ai.tool.call.result; content follows captureContent and the redactor. Credential fields such as Composio customAuthParams are never recorded, a disabled client is returned untouched, and the SDK takes no dependency on @composio/core or @pipedream/sdk.
ToolOptions.integration, a ToolIntegration with platform, optional toolkit and optional version, to hue.tool(); it is recorded as hue.integration.platform, hue.integration.toolkit and hue.integration.version.
Files
recordFile adds a hue.file event to the active span, or to the span of an explicit context passed second, for a file the work read, received or produced. Files are linked by content hash. Set upload: true to attach supplied bytes, or the file at path, to the span:
FileRecord has role ("input" given to the agent, "attachment" from a tool or message, or "output" produced by the agent), mediaType, and one of data (a Uint8Array, or a string hashed as UTF-8), path or sha256, with optional byteSize, name and upload. data up to 25 MiB is hashed and measured locally; larger data is omitted and counted as an instrumentation failure, so pass sha256 and byteSize when you already have them. A supplied sha256 or byteSize must match data. path, in place of data (not both), names a regular file up to 1 GB: up to 25 MiB it is read as data is, and a larger file is hashed now and, with upload: true, streamed from disk when it uploads, only if it still has its recorded size and SHA-256. A path that is not a regular file, or a file over 1 GB, is omitted and counted. upload defaults to false. With upload: true, supplied data or path, captureContent: true and an ordinary project key, export adds a hue.blobs entry to the same span, keyed event:hue.file:<sha256>, and the bytes upload after the span is sent. An upload that is not made counts in uploadFallbacks, and the event remains. See Images, documents and audio.
The event carries hue.file.sha256, hue.file.role, hue.file.media_type and, when known, hue.file.size. It is metadata, so it is recorded in both capture modes; hue.file.name is recorded only when captureContent is true. A name must be nonblank after trimming, at most 256 UTF-16 code units and well-formed Unicode, with no C0 control characters (U+0000–U+001F) or DEL (U+007F). An invalid name is omitted and counted as an instrumentation failure, and the event remains; before 0.17.0 tabs, newlines and DEL were accepted. An invalid record, or one without an active span, is omitted and counted as an instrumentation failure.
new Attachment(options: AttachmentOptions) places a file in any value Hue records: a withSpan() input or output, model() messages, a tool’s arguments or result, recordMessages() messages or a span attribute. AttachmentOptions takes exactly one of data (an ArrayBufferView, an ArrayBuffer, or a base64 string or data: URL) and path, plus contentType and an optional name. data is limited to 25 MiB. path names a regular file up to 1 GB; over 25 MiB it is hashed when the attachment is created and streamed from disk when it uploads, only if it still has its recorded size and SHA-256. The attachment exposes readonly contentType, name (when valid), sha256 and size (both undefined when invalid). It is recorded as a GenAI blob part in digest form, and its bytes upload after its record is sent. An invalid attachment is recorded as null and counted as an instrumentation failure. See Attach a file anywhere.
Vercel AI SDK adapter
hueTelemetry(hue: HueClient, options?: HueTelemetryOptions): TelemetryOptions enables telemetry, sets recordInputs and recordOutputs from hue.captureContent, and configures the AI SDK OpenTelemetry integration with hue.tracer and usage reporting.
It also records the end user and conversation from the call’s AI SDK runtime context: runtimeContext.userId as user.id, and sessionId, else threadId, as gen_ai.conversation.id, on every span of the call. It ignores a value that is not a string or finite number of 1–4096 valid characters, and an enclosing withSpan’s userId or sessionId takes precedence. AI SDK withholds runtime context from telemetry unless includeRuntimeContext names the key, so the returned options name these keys there; no other runtime-context value is recorded. To keep your own includeRuntimeContext, spread the returned one into it.
HueTelemetryOptions names other runtime-context keys. userKey?: string | false names the user’s key, "userId" by default. sessionKey?: string | readonly string[] | false names the conversation’s keys, of which the first with a value wins, ["sessionId", "threadId"] by default. false records none, and an empty key throws a TypeError.
Supported peer ranges are ai@^7.0.0 and @ai-sdk/otel@^1.0.0; keep your installed AI SDK version and add an OTel peer in its supported range. Compatibility lists the tested AI SDK and OTel pairs; other releases in range are not individually verified.
hueTelemetry reads the installed ai major version once per process and throws a TypeError below 7. For AI SDK 6, use hueExperimentalTelemetry from the core entry point instead:
hueExperimentalTelemetry(hue: HueClient): ExperimentalTelemetrySettings returns { isEnabled, recordInputs, recordOutputs, tracer }: isEnabled mirrors the client’s enabled flag, the record flags mirror captureContent, and tracer is Hue’s tracer, so AI SDK 6 spans parent under withSpan and inherit identifiers. It needs no @ai-sdk/otel peer. Do not upgrade an existing app’s AI SDK just to install Hue. For an app that already emits OpenTelemetry spans, assess the existing-provider path and its installed OpenTelemetry versions using the compatibility guide.
Provider-executed tools, such as OpenAI hosted MCP (openai.tools.mcp), appear as execute_tool mcp.<name> spans with gen_ai.tool.type extension. The server is named only by serverLabel inside the recorded result, so before export the SDK copies it to mcp.server.name, and a result carrying an MCP error sets an ERROR status and error.type mcp_error. Both attributes survive metadata-only export. The label can only be read when AI SDK recorded the result: hueTelemetry(hue) with captureContent: false records none, whereas an application whose AI SDK integration records outputs and exports through Hue’s attached processors keeps the label.
AI SDK per-call integrations replace the global integrations for that call. If your app already has telemetry, preserve its setup and attach Hue to the existing provider. See OpenTelemetry and the Example chatbot.
Content policy
See Data privacy for runnable email-masking examples and the correct attachment point for each integration.captureContent: falsedisables Hue helper content and removes recognized GenAI, Vercel AI SDK, OpenInference, OpenLLMetry and Langfuse content, legacy GenAI content events, log bodies, status messages and exception text before Hue exports records, including records from other instrumentations on a shared provider. The exportedcontentPrefixesarray lists the attribute keys, and their dotted children, that are removed; the compatibility matrix reproduces it. It does not classify every custom attribute name.captureContent: truepermits supplied content. Received content is stored by Hue; the SDK does not set a retention timer. Helpers still omit exception messages and stack traces.- With
captureContent: false, a record whose tool definitions are removed keeps a summary of them:hue.tool.nameslists each definition’sname(Chat Completionsfunction.name, or thetypeof an unnamed built-in tool such asmcp) in order, andhue.tool.definitions.sha256is the lowercase hex SHA-256 of the RFC 8785 canonical JSON of the credential-scrubbed definition list. The digest does not change when a credential rotates. Only definitions another integration recorded can be summarized:hueTelemetry(hue)withcaptureContent: falserecords none. - Hosted tools carry credentials in their definitions, such as the
authorizationandheadersof an OpenAI hosted MCP tool. Before export, and beforeredact, Hue replaces the values of credential-like fields (authorization,authorization_token,headers,api_key,access_token,x-api-key, and keys ending intoken,secret,password,apikeyorcredential, case-insensitively and ignoring-and_) with"[redacted]"ingen_ai.tool.definitions,ai.prompt.toolsandllm.tools.*.tool.json_schema, and in thetoolsandmcp_serversentries of a raw provider request or response recorded asinput.value,output.valueorllm.invocation_parameters. Parameters named in a JSON Schemapropertiesobject keep their schemas, so a tool that takes aheadersargument is still described. A definition nested more than 256 levels deep rejects its record. - A span’s own string attributes over Hue’s inline limit upload separately, up to 1,000,000,000 bytes, and keep a 16 KiB prefix. Inline media in the span attributes and log records that automatic capture reads uploads and leaves its digest in place; text media over 64 KiB keeps a 16 KiB UTF-8 prefix. Resources, links and span events never upload: inline media there up to 64 KiB stays as recorded and larger media becomes its digest. An
Attachment(up to 25 MiB) uploads at its position, andrecordFileuploads supplied data up to 25 MiB only withupload: true. Uploads run in the background after their record is sent. A value refused when its record is exported falls back to a cut, to the digest without ahue.blobsentry in recorded messages, or to the inline bytes elsewhere; one whose upload fails afterwards keeps its prefix or digest and its entry. Both count inuploadFallbacks. Nothing uploads withcaptureContent: falseor a setup credential. redact(value, path)transforms supported strings in attributes, resources, event/link attributes and log bodies before Hue exports them. It must return a string. A redactor failure rejects the affected record and becomes an export issue.- This policy applies to Hue’s export path. Another exporter and arbitrary span/scope names remain your application’s responsibility.
Flush, shutdown and diagnostics
checkConnection() returns a ProjectConnection, { id, name, organizationId, slug }, for the project associated with the key. It throws HueConnectionError on rejected authentication, network failure or an invalid response; status carries the HTTP status when Hue answered, and cause carries the underlying network, timeout or parsing error. Its message is fixed and safe to log. It sends no trace.
flush() sends traces and logs, then waits for the uploads queued before it. Concurrent callers receive serialized drains that include their preceding emissions. Rejections, failed exports, queue drops and invalid acknowledgements throw HueExportError, whose issues and report contain sanitized diagnostics. A later non-overlapping flush reports new failures; counters remain cumulative. Overlapping calls also observe failures from shared in-flight work.
ExportReport contains acceptedSpans, acceptedLogs, rejectedSpans, rejectedLogs, failedSpans, failedLogs, pendingSpans, pendingLogs, droppedSpans, droppedLogs, pendingBytes, instrumentationFailures, uploadedValues and uploadFallbacks. Accepted, rejected, failed, dropped, instrumentation and upload counts are cumulative; pending counts and bytes describe current queued/in-flight records. getIssues() returns the latest 128 ExportIssue values with sequence, signal (a Signal: "traces" or "logs"), kind, count, optional status and a sanitized message. Kinds are rejected, failed, dropped, invalid and warning. A warning with no rejection does not fail a flush.
The transport’s spanProcessor and logRecordProcessor receive RecordValue records, the ReadableSpan or ReadableLogRecord the OpenTelemetry SDK hands to a processor. The exporter plumbing behind them is internal and not part of the published declarations; read getReport(), getIssues() and getFailureSequence() instead.
shutdown() stops new Hue helpers and flushes. It closes providers that Hue created; borrowed providers remain usable. Repeated calls share the same shutdown promise. If your application supplied the providers, close those providers and then call transport.shutdown() during process shutdown. Reuse a shared client across server requests.
Queues are in memory and bounded to 2,048 records per signal, including exports in flight. Export requests are sized from each record’s own encoding and split at 1 MiB. Retryable failures use the OpenTelemetry retry policy; partial rejections are not retried wholesale. An acknowledgement means collector receipt, not that every span of a distributed trace has arrived. Stop producing spans before shutdown.
Live spans
OpenTelemetry exports a span only when it ends, so a long streamed turn would otherwise stay invisible until it finishes. When a Hue or AI span is still open at the transport’s next 500 ms tick, the transport queues a placeholder: an ordinary OTLP span whose parent is the running span, with its name, kind, start time and current attributes and an end time of 0. Hue shows the span, and its trace, as running and replaces the placeholder when the finished span arrives. A placeholder whose span has ended by the time it is exported is not sent. A placeholder usually reaches Hue about 1.5 s after its span starts: up to 500 ms until the next tick, then about 1 s while the export queue batches it. It arrives sooner when a batch is already scheduled and later while an earlier export is still in flight, because the next 1 s batch is scheduled only after that export finishes. A span shorter than about 1.5 s therefore usually never shows as running and appears only when it ends.- Only spans from the client’s tracer (
withSpan,tool,model,hue.tracerand the AI SDK adapters) and spans with agen_ai.,ai.,llm.ortraceloop.attribute at start, or a name starting withai., are announced. HTTP, database and other framework spans are not. - Placeholder attributes follow
captureContentandredactlike the finished span. Tool definitions, system instructions and any value over 64 KiB are left out. - A span processor that scrubs, renames or drops spans in
onEndnever sees placeholders: the transport builds each one from the running span’s current name and attributes. If a wrapper forwardsonStartto Hue and the span is still open when its placeholder is exported, Hue receives the span’s original name and its attributes afterredact, even when the wrapper later edits, renames or drops the finished span. Remove sensitive attribute values withredactor where you record them.redactdoes not change span names, so keep a sensitive value out of the name where you create the span, or turn live spans off withliveSpans: false. - Placeholders are advisory. They are queued only while the queue is under a quarter of its record and byte budgets, and skipped silently otherwise. While queued they count in
pendingSpansandpendingBytes, but never as accepted, rejected, failed or dropped records. Losing only placeholders records awarningissue and does not makeflush()throw. - Completed spans are exported in separate requests before placeholders, so their rejections stay visible. If the first trace acknowledgement lacks
Hue-Pending-Spans: 1, the transport records onewarningissue and stops sending placeholders for that client; the receiver gets at most one placeholder request. - Opt out with
liveSpans: false. - With an existing provider, announcements start in
spanProcessor.onStart. A wrapping processor that forwardsonStartshould forwardonEndfor the same spans; a placeholder already sent for a span that never reaches Hue keeps it showing as running until Hue marks the trace stalled.
Trace verification
verifyTrace(traceId: string, options?: VerifyTraceOptions): Promise<TraceVerification>. VerifyTraceOptions has expectedSpanIds, requiredFields (an array of TraceReceiptField: "input", "output", "model", "usage" or "session") and timeoutMillis. TraceVerification is { verified: boolean; receipt: TraceReceipt | null; project?: ProjectConnection }; project is set when Hue reported the trace missing and names the project the key searched. A receipt contains traceId, spanCount, revision, fields (Record<TraceReceiptField, boolean>), matchedSpanIds, missingSpanIds, and traceUrl. verified requires a stored receipt, every supplied expected span, and every required field. Timeout returns verified: false with the latest partial receipt, or null if none arrived; a null receipt with project means no trace with that ID exists in that project, so check which key the process loaded. Other failures throw exported HueTraceVerificationError, with code and optional HTTP status, without response bodies or credentials. A disabled client rejects with HueConnectionError.
Trace IDs are 32 lowercase hexadecimal characters; expected span IDs are 16. All IDs must be nonzero. Supply at most 100 unique expected span IDs and unique required field names. The timeout defaults to 10,000 ms and must be positive, finite, and at most 60,000 ms. The receipt response is limited to 64 KiB.
Missing spans or required fields keep polling until the deadline. Only recognized trace-not-found responses, HTTP 429, and HTTP 503 are retried; connection failures, unsupported endpoints, redirects, and malformed responses raise a safe typed error. Verification reads stored normalized field presence across the trace, including supported correlated logs. It does not inspect values or prove that unlisted application operations were instrumented.
Flush the owning providers before verification; this method never flushes implicitly.
Evaluation client
createEvaluationClient(options: EvaluationClientOptions): EvaluationClient and new EvaluationClient(options) accept required apiKey, optional baseUrl (default https://app.hue.run), optional timeoutMillis (default 10000, range 100–60000) and optional maxAttempts (default 4, range 1–10): the bounded attempts for a read, an update or a keyed mutation after a transient failure, described under experiments, saved subjects and results; 1 sends every such request once. checkConnection() returns the key’s project. Evaluation registry writes require a Read and write key.
Methods below return promises. PageOptions is { after?: string; limit?: number }, with a supplied limit from 1 through 100. Paged responses are Page<T>, { items, nextCursor }; pass a non-null cursor as the next after. IDs are UUIDs. Identity is { name, slug, description? }. listEvalSets, listEvaluators, listDatasets and listScorers accept RegistryPageOptions, PageOptions plus includeArchived?: boolean, which includes archived identities so callers can diagnose slug conflicts explicitly, and tags?: string[], which keeps identities carrying any of the named tags.
Evaluation responses are limited to 4 MiB. listCases(versionId, page?) includes case content, so a valid row limit can still produce an oversized response when cases are large. Request a smaller page, such as { limit: 1 }, and follow nextCursor; the client does not automatically split or retry an oversized page. Request bodies are limited to 1 MiB.
Evaluation types
@hue-run/sdk/evals exports these types for method inputs and results.
Eval sets, evaluators, runs and scoring
Use these product-named methods in new code. They call the same v1 endpoints as the dataset, scorer, experiment and evaluation-run methods in the next sections and return the product fields, such asevalSetId, evalSetVersionId, evaluatorVersionId, runId and scoringId, alongside the v1 fields. The earlier method names are deprecated but remain callable for at least two more 0.MINOR releases.
CI evaluation invocations
An invocation freezes the selected cases, evaluator versions, configuration and gate policy for one CI check. TheseEvaluationClient methods recover the server’s saved decision. Every method returns Promise<EvalInvocation> and accepts an optional final AbortSignal. See Run in CI for the CLI and GitHub Action.
policy.thresholds contains { evaluatorVersionId, metric, operator: "gte" | "lte", value } checks on each applicable required result. Optional policy.baselineComparisons contains { evaluatorVersionId, metric, operator, tolerance } checks on paired case means; tolerance is finite and nonnegative. Each receipt comparison includes those rule fields plus candidateMean, baselineMean, passed and caseIds. The server alone decides the verdict.
Each control input requires its own stable idempotencyKey. Retry with the original key and body, including the original deadline. Recover by key before resolving versions or choosing a new deadline. Read the saved verdict instead of deriving a new one from later scores.
Tags
Tags group eval sets, evaluators and runs, for example by the area of the agent they test. Methods take tag names: a name the project has no tag for creates one, and names match without case.createEvalSet, createEvaluator and createRun accept tags; updateEvalSet, updateEvaluator and updateRun replace an item’s tags with the names you pass ([] clears them); listEvalSets and listEvaluators keep items carrying any of the named tags; and listTags() returns the project’s tags. Responses carry each item’s tags as Tag values. A run also shows its eval set’s tags in evalSetTags; they are not its own, so updateRun leaves them unchanged. The dataset, scorer and experiment methods take the same tags.
Datasets and scorer definitions
CaseWrite requires expectedRevision, externalKey and inputs; expected and metadata are optional. Omit expected to declare no reference; expected: null is a present reference. Freeze the dataset and publish scorer definitions before creating an experiment.
ScorerDefinition and metrics
Each
MetricDefinition has a name and type: boolean, text, number (optional min/max), or category (required categories: string[]). An optional description (1–500 characters) is shown with the metric’s check in Hue’s run view. Returned metrics must match the pinned definitions exactly.
An OutcomeJudgeConfig pins a hue.outcome_assertions.v3 judge: model (provider-prefixed), provider, template (the SHA-256 of the judge template), samples (1–9, majority decides), temperature (0–2), maxOutputTokens and timeoutMs.
Hosted config is a JudgeConfig with required model, provider, rubric, bindings (an array of { name, path, required }), maxOutputTokens and timeoutMs; temperature is optional. A declaration identifies the requested evaluation policy; the server validates supported values and project execution settings when it is used.
Experiments, saved subjects and results
StartExecution requires idempotencyKey; optional fields are traceExternalId, previousExecutionId and allowUncertainRetry. CompleteExecution requires idempotencyKey and a terminal state (succeeded, error or cancelled); optional fields are output, error (a TypedError), expectedTraceRevision, traceEvidence (required or omit) and omissionReason. Completion contains executionId, subjectId, nullable traceSnapshotId and evaluationItemId. Use these low-level methods only with a known recovery decision; see recovery.
Each submitted Result requires evaluationItemId, scorerVersionId and the Score fields described below; a local-code result also carries its sourceDigest. A scored result contains metrics: [{ name, value, passed? }] and a nonempty explanation or an evidence value. Error results contain error: { type, message? }; skipped results contain an explanation.
On the evaluation client, a read, an update that sets given fields (updateEvalSet, updateEvaluator, updateRun and their dataset, scorer and experiment forms), or a mutation the server deduplicates by the idempotencyKey in its body (the local worker’s register, claim, heartbeat, completion and capability routes included), is sent again after a connection failure, a timeout or a 408 or 5xx that carried no Retry-After, up to maxAttempts (default 4, 1–10) times with a jittered backoff. isTransientApiError(error) names those failures. Any other mutation is sent once: reuse a saved idempotency key with the same intended mutation after a lost response. HueApiError.status distinguishes an HTTP rejection from a connection/response failure, HueApiError.diagnostic carries Hue’s X-Hue-Diagnostic code when it sent one, and retryAfterSeconds the wait of a refusal Hue timed; errors do not echo server bodies.
Hosted judge jobs
getJudgeBudget() returns a JudgeBudget with the hosted judge configuration and admission controls, and the organization’s monthly AI budget as the optional organizationBudget. createJudgeJobs(runId, { idempotencyKey, jobs: [{ evaluationItemId, scorerVersionId }] }) returns job IDs. Inspect JudgeJob values with listJudgeJobs(runId, page?) or getJudgeJob(jobId), and request cancellation with cancelJudgeJob(jobId, reason).
Submitting hosted jobs is an explicit platform operation and draws on that budget. SDK method availability does not establish that a hosted provider is configured or that the budget has room. Local runners leave hosted and manual scorer pins for their owning workflows.
Artifacts
runExperiment uses these methods to publish generated files; you rarely call them directly.
ArtifactReservation has id, filename, declaredContentType, declaredBytes, declaredSha256, state (reserved, verifying, ready, rejected, cancelled or abandoned; only ready artifacts are verified and downloadable), copyState (none, started or acknowledged), verifiedBytes and verifiedSha256 (null until ready) and failureCode. ArtifactUpload is { uploadUrl, method: "PUT", headers?, expiresAt }; omitted or null headers mean the file content type only.
Recorded media
client.media is a MediaClient that reads recorded files back by SHA-256 with a Read or Read and write key; a snapshot’s pinned copy needs Read and write. See Read recorded media back.
Published scenarios and eval sets
A published Scenario is a case converted from a trace, with immutable pins to a frozen dataset version, an environment version and one scorer version. The evaluation client reads them withlistCaseConversions(page?), a page of CaseConversionSummary values (drafts and published), and getCaseConversion(id), a CaseConversion. Both need a Read and write key.
These
@hue-run/sdk/evals functions resolve a selector to the pins an experiment or runSimulation needs.
ScenarioClient is the subset of EvaluationClient these resolvers use: listCaseConversions, getCaseConversion, getDataset, getDatasetVersion and listDatasets. ScenarioPins contains scenarioId (null for an eval set), name, datasetId, datasetVersionId, scorerVersionIds (exactly one for a published Scenario), environmentVersionId (null when the selection pins none), saved (whether the version is frozen; experiments require a saved version) and revision, the version’s current revision for freezing a draft.
Run locally and rescore
@hue-run/sdk/evals.
runExperiment additionally requires hue, experimentId, traceEvidence and target(inputs, context), where context is a RunExperimentTargetContext. The target may return a JSON value, a TargetResult from withFiles, undefined, or a promise of any of these. Evidence must be { mode: "required" } or { mode: "omit", reason: "..." }. Telemetry and evaluation clients must use the same project and origin.
For required trace evidence, traceNotAccepted defaults to "stop": a rejected export stops the runner. Choose "fail_case" to complete that case as failed without its output or generated files and continue with other cases. onTelemetryNotAccepted(entry) reports each newly failed case before continuing. The RunnerReport.telemetryNotAccepted array contains TelemetryNotAccepted entries with caseId, caseKey, executionId and issues. Each TelemetryIssueCount records the signal (traces or logs), kind (rejected, failed, dropped or invalid), optional HTTP status and record count; it contains no captured content. Choose "pending" to complete a case whose telemetry Hue did not accept in time in its true state with its trace evidence pending: Hue attaches the trace once it holds every span the case ended, or records the evidence as omitted a day later. RunnerReport.tracePending lists those cases as TracePending entries with caseId, caseKey, executionId and, when the checkpoint recorded it, spanCount.
rescore additionally requires runId and has no target callback. Create its evaluation run from existing subject IDs first. Both return a RunnerReport, { runId, subjectIds, resultIds, deferredScorerVersionIds }.
With persistResultContent: false, completions and checkpoints omit raw output, target error messages, scorer evidence and arbitrary explanations. Declared metric values remain stored, including text metrics. Already stored dataset inputs/references are independent of this setting. Historical scoring skips unavailable output; it does not rerun a target to reconstruct it.
File-based cases
RunExperimentTargetContext is what the runExperiment target receives for one frozen case:
To save generated documents, return
withFiles(output, files): it takes a JSON output (or undefined when the target produced only files) and an OutputFile[], and returns a TargetResult with readonly output and files. Generated files are uploaded regardless of persistResultContent, and local scorers receive every input and generated file in ScoreContext.files as LocalFile entries, generated ones with role: "output". rescore downloads a subject’s frozen files for code evaluators.
Local scorer exports
JSON Schema scoring uses
ajv, a separate optional peer dependency (8.17 or later) loaded inside a worker only when builtins.jsonSchema scores a case; without it that scorer reports SchemaValidatorUnavailable. The tracing core depends only on @opentelemetry/* packages.
ScoreContext contains inputs, hasOutput, hasExpected, optional output/expected, metadata, executionState and, when the runner requires environment evidence, environment (an EnvironmentEvidence). With environment evidence present, a local_code scorer runs even when no output is stored. When required evidence cannot be read, local_code results record an EnvironmentEvidenceUnavailable error; an instance marked environment_incomplete produces a skipped result with the fixed explanation Environment incomplete: provider behavior is not implemented. A Score is scored with declared metrics and explanation/evidence, error with a typed error, or skipped with an explanation. A failed quality metric is still scored, with passed: false.
Custom callbacks run locally, without a general execution timeout or side-effect cancellation. The source digest is a caller declaration, not attestation of dependencies or closures. Hosted judge pins must be dispatched through judge jobs; scoreLocally does not execute them.
Recovery errors
UncertainExecutionErrorexposescaseIdand optionalexecutionId: no durable outcome is available, so the runner refuses to repeat potentially completed work.OutcomeSerializationErrorexposesexecutionId: the target returned, but its outcome could not be saved as JSON. The runner does not invoke it again.TargetCancelledErroris thrown byrunExperiment()andrunSimulation()when cooperative caller cancellation stops target execution; the run stays open, and rerunning with the same checkpoint directory retries the interrupted case as a new attempt.TargetOutcomeUncertainErrorexposesexecutionId: the target or its simulated instance may have committed but acknowledgement is unavailable, so a resume will not invoke the target again.TargetTimeoutErroris thrown to a target still running five seconds past its instance’sexpiresAt, through thesignalin its context; the case ends as anerrorof typeTargetTimeoutand the instance is sealed abandoned.TraceExportUnacknowledgedErroris thrown by a resumed case whose saved outcome still waits for a trace export Hue never acknowledged; it is that case’s own state on resume, and the cases beside it still run.- Required trace export failures surface through
HueExportErroror recovery checks. Each export issue names the traces of the records it concerned, so a failure marks only the case whose trace it names; one naming no trace is decided by the case’s trace receipt. A new empty exporter cannot prove receipt of an earlier trace.
.lock file. Removing a lock never authorizes another target invocation.
When a target’s outcome is uncertain, restarting the runner will not repeat it. Investigate side effects first. The low-level startExecution API requires an explicit previousExecutionId for a replacement attempt and allowUncertainRetry: true to replace a still-started attempt. The convenience runner does not automatically adopt an externally created attempt; use a new experiment for an intentional fresh target run. Required evidence never silently changes to omitted evidence after an export failure.
For a runnable experiment and historical rescore, see the public Local evaluations.
Wait for results and verdicts
Scorers that Hue executes grade after the runner returns, so a caller that wants per-case verdicts waits for them. These functions are exported from@hue-run/sdk/evals.
VerdictClient is the subset of EvaluationClient that waitForResults uses: listEvaluationItems, listResults and getResult. collectExperimentVerdicts also needs getExperiment, listExperimentItems and getSubject.
WaitForResultsOptions requires runId (for example report.runId) and scorerVersionIds. Optional fields are subjectIds (restrict the wait, for example to report.subjectIds; defaults to every item), timeoutMillis (overall budget, default 300000; 0 reads once), pollIntervalMillis (default 2000; integer 250–60000) and signal. CollectExperimentVerdictsOptions takes the same optional fields with experimentId in place of runId and scorerVersionIds. Runs of more than 5,000 items throw RangeError.
Run a local agent worker
runLocalAgent starts an outbound-only worker for one fixed local TypeScript agent entry point. Hue chooses only the registered key and revision; no command or source is received from the cloud. The worker is exported from @hue-run/sdk/evals and uses the same provider-aware instance lifecycle as runSimulation. A matching Hue API deployment is required.
Register the process first with registerLocalAgent(input: LocalAgentRegistration), which returns a RegisteredLocalAgent. The worker then claims queued runs as a LocalAgentClaim. Candidate callbacks receive a LocalAgentTargetContext: case identity and cloned task inputs only, not expected criteria, case metadata or environment pins. Like SimulationTargetContext, it carries an optional world and an optional mcp. The worker sends the registered agent.revision as the agent revision of every instance it creates.
RunLocalAgentOptions
LocalAgentDirectContext carries config (cloned), item identity only (id and externalKey), executionId, trace ({ traceId, spanId }), files (verified LocalFile copies of the case’s agent-visible input files), outputDirectory (a private scratch directory; return generated files with withFiles) and optional signal. Expected outcomes and case metadata stay with grading.
Hue offers a worker only the cases whose capabilities its registration declares. localAgentCapabilities is { environment: "environment:v1", direct: "direct:v1" }. registeredCapabilities({ agent, target?, directTarget? }) returns the registration’s capabilities: the declared agent.capabilities plus one per supplied callback. It throws TypeError when neither callback is supplied or a declared environment:v1 or direct:v1 capability has no matching callback.
Run a simulation
runSimulation runs an existing agent callback against one fresh hosted instance per case. It owns immutable resolution, execution linkage, finalization, scoring and resumable uploads, and it is exported from @hue-run/sdk/evals. The environment client comes from @hue-run/sdk/environment and must use the same Hue origin as the evaluation client. Agents that call simulated apps through their own clients receive a World handoff instead of local tools.
Provider-profile preflight is a control-plane contract. Hue does not serve hosted Gmail or Slack provider calls through it, and the options, methods and credential types below do not establish provider parity. Agents reach simulated apps through a World’s URLs instead.
RunSimulationOptions
SimulationReport extends RunnerReport with experimentId, the fresh experiment created for this invocation, and runUrl, the browser URL joining task, trace, instance evidence and scoring. Invalid bounds throw RangeError; mismatched origins and an unfinished checkpointed definition or agent revision throw Error.
SimulationDefinition
SimulationDefinition is a union of an app-authored reference, already published pins and a repository-authored definition. SimulationScenario is a deprecated alias for SimulationDefinition.
RepositorySimulationCase is { externalKey, inputs, expected?, metadata? }: a stable key unique within the dataset, the JSON inputs passed to the target, an optional reference output and optional caller-owned metadata. RepositorySimulationScorer is an Identity plus scorer, a ScorerDefinition to publish or a LocalScorer bound to its source digest. Stable slugs reuse matching immutable content digests; changed definitions publish new versions. Unsupported or server-only scorer kinds throw TypeError before any write.
SimulationTargetContext
SimulationProgress
Progress events carry no target output, credentials or other sensitive content.Attempt preflight
An experiment whoseconfig carries an immutable AttemptBaselineV2 can require strict provider-profile preflight before the callback runs. runSimulation performs it when requestedProviders and mcpSurface are supplied; the evaluation-client methods and validators below are exported for adapters that drive it directly.
The runtime validators are
zod schemas (z.ZodType) for the types of the same name: actualAgentManifestV2, expectedAgentManifestV2, surfaceBindingV2, dependencyProviderV2, dependencyManifestV2, attemptBaselineV2, prepareAttemptInputV2, preflightFindingV2, preflightReportV2, parityEvidenceV2, attemptIdentityV2, attemptConnectionBundleV2 and attemptBindingRead. They reject unknown keys, check digests against immutable contents and, for connection bundles, require the parity digests to match the bundle’s own evidence and attempt identity.
World client
createWorldClient(options: WorldClientOptions): WorldClient uses the canonical World and instance routes. The compatible EnvironmentClient below keeps the original routes. Both require a Hue deployment serving their routes and use the same connection options and handoff helpers.
Reconstructed Worlds
new WorldModelClient(options: WorldClientOptions) reads the retained history of a WorldEntity, { namespace, id }, scoped to the project key. A WorldModel records that identity, its committed evidenceCutoff and its status. Account bindings are WorldModelAccount values, including a full accountId, connection generation and optional scope; multiple bindings can belong to the same app.
When Hue reports progress,
WorldModel.processing contains WorldModelProcessing: its indexing state, retained and ready evidence cutoffs, and whether evidence is pending. StartingWorldResult.preparation and HueWorldError.preparation optionally contain WorldPreparationProgress, which also names the selected evidence cutoff. Error progress includes only validated fields from at most 16 KiB of response data; unrelated response content is discarded.
If a response carries world_insufficient_evidence or world_processing_limit, the client stops retrying that request. Other transient diagnostics retain the retry behavior below.
Materialization, instance creation and reproduction wait up to 120 seconds only after HTTP 503 with X-Hue-Diagnostic: world_preparing, separately from ordinary maxAttempts. Retries preserve the serialized body and idempotency identity. Pass { signal } to cancel the wait or an active request. Other failures retain the configured attempt limit; a preparing or incomplete World is not a usable starting state.
Compatible environment client
createEnvironmentClient(options: EnvironmentClientOptions): EnvironmentClient and new EnvironmentClient(options) create a typed client for authored Worlds, isolated instances and immutable journals.
Run mutations retry on transport failure and on HTTP 408, 429, 500, 502, 503 and 504 with exponential backoff, reusing the same invocation or idempotency identity. When a 429 or 503 carries
Retry-After, the client waits that long instead, at most 10 seconds. createEnvironment and publishVersion are non-idempotent registry writes and are not retried. Failures throw HueEnvironmentError, whose fixed message never includes response text or credentials; status carries the HTTP status when Hue answered and is absent for transport, timeout or parse failure, and retryAfterMs carries Hue’s bounded Retry-After from a 429 or 503. Responses are limited to 4 MiB and request bodies to 1 MiB; a published definition may contain up to 240 KB.
Worlds and versions
EnvironmentIdentity is { name, slug, description? }; EnvironmentSummary adds id and archivedAt (null while active), and Environment adds versions. EnvironmentVersionSummary is { id, version, contentDigest, createdAt }, where contentDigest is the canonical digest of the stored, defaulted definition; EnvironmentVersion adds environmentId, the stored definition and the generated actions. EnvironmentPage is { items, nextCursor } and EnvironmentPageOptions is { after?, limit? } with a limit from 1 through 100.
EnvironmentDefinition
EnvironmentDefinition is the complete V1 World definition stored as an immutable version. EnvironmentDefinitionV1 is that same V1 document. publishVersion and EnvironmentVersion.definition accept a PublishableEnvironmentDefinition, the union of EnvironmentDefinitionV1 and EnvironmentDefinitionV2. Narrow definition.schemaVersion === 1 before reading V1-only fields. Use EnvironmentDefinitionV2 only when supplying providerInstances.
Each
EnvironmentActionDeclaration has a unique name, an optional agent-visible description, flat params, semantics and an optional observation whose only V1 projection is "identity". An EnvironmentActionParameter has name, type ("string", "number", "boolean" or "string[]"), required (default true), optional description and optional enum. semantics.entry is a SemanticEntry, a versioned deterministic semantic implemented by Hue’s environment kernel: hue.collection.get@1, hue.collection.list@1, hue.collection.search@1, hue.collection.create@1, hue.collection.update@1, hue.gmail.search_messages@1, hue.gmail.get_message@1, hue.gmail.get_thread@1, hue.gmail.create_draft@1, hue.gmail.update_draft@1, hue.slack.search@1, hue.slack.read_channel@1, hue.slack.read_thread@1, hue.slack.draft@1 or hue.slack.destination@1. semantics.config is an EnvironmentSemanticConfig: the primary collection plus optional draftsCollection, slackActorId, slackWorkspaceId, mailboxAddress, idParam, queryParam, fields, filter ({ field, param }), limit, set, setFromParams, idPrefix, guards ({ field, equals, error } entries, default []) and notFoundError (default "not_found").
Publishing generates one ActionDefinition per action: name, description? and inputSchema, an ActionSchema. That is the JSON Schema subset { type: "object", properties, required, additionalProperties: false } whose properties are scalar types with an optional enum or bounded string arrays with maxItems and item maxLength. Unknown action arguments are rejected.
EnvironmentDefinitionV2 extends that V1 document with schemaVersion: 2 and providerInstances: GmailProviderInstance[]. Each GmailProviderInstance supplies providerInstanceKey, providerId: "google.gmail", syntheticPrincipalId and a GmailMailboxConfiguration. That configuration is either GmailMailboxConfigurationV1 (kind: "gmail_mailbox/v1", messagesCollection, draftsCollection, mailboxAddress) or GmailMailboxConfigurationV2 (kind: "gmail_mailbox/v2" with the additional labelsCollection). These are SDK configuration types; they do not establish that a hosted provider is available. Hue canonicalizes syntheticPrincipalId to a lowercase UUID. These bindings are immutable attempt-profile inputs; they do not establish hosted Gmail calls.
Limits: 500 actions per instance, an 86,400-second lease, 240 KB per published definition, 64 collections, 2,000 entities, 8 MiB of evidence, 16,000-byte coverage-gap arguments, 4 MiB responses and 1 MiB request bodies.
isTransientEnvironmentError(error) reports whether an environment error is a connection failure or a retryable HTTP status (408, 429, 500, 502, 503, 504). It classifies a failure; calling it does not retry an action.
Runs, actions and journals
CreateRunInput requires idempotencyKey and, unless the execution’s case pins a World model reference, environmentVersionId; optional fields are executionId (the target execution linked to this instance, required without environmentVersionId), seed (32 lowercase hexadecimal characters), maxSteps (1–500), ttlSeconds (1–86400), traceparent (the case span’s version-00 W3C trace context, whose trace ID must be the trace the execution declared; the instance span is parented on it) and agentRevision (1–256 characters, part of the instance’s fingerprint). Invalid bounds throw RangeError or TypeError before any request. ActionInput is { invocationId, action, args? }; omitted args means an empty object. FinishRunInput is { idempotencyKey, status }, completed for accepted outcomes and abandoned for failures or cancellation. StepPageOptions is { after?, limit? }: after is the last seen ordinal (-1 starts at the first step) and limit is 1–100.
Bind local tools
bindEnvironmentTools binds a run’s generated catalog to plain local callables without changing the agent framework. BindEnvironmentToolsOptions requires hue, the client that records each action as tool telemetry, client, an environment client bound to the same Hue origin (only act is used), and run, the fresh EnvironmentRun whose closed catalog becomes callables. parentContext supplies an optional parent span context for the generated tool spans; invocationId(action) is an optional durable invocation-ID factory for caller-owned resume state, and without it each call uses a random UUID.
Each EnvironmentTool has name, description?, inputSchema (the action’s ActionSchema) and execute(args?), which runs the action inside hue.tool(name, args, ...) and resolves with the instance’s Observation. When the catalog entry names its MCP server, the tool span also carries mcp.server.name and mcp.server.version, plus hue.mcp.provider and hue.mcp.surface when the entry includes them. Transport failures reject with HueEnvironmentError.
World handoff
Where Hue’s simulation gateway serves an instance,createRun also returns its handoff: a world token and one mirror URL per pinned provider surface, such as a Gmail MCP or REST mirror. Point the agent’s own provider client at the mirror and pass the world token where the provider credential would go; the project key stays with the runner. worldHandoff returns null for an instance created while a deployment’s gateway is off.
runSimulation, runLocalAgent and hue eval do this for you. They create each instance with the execution, a stable idempotency key, the case span’s trace context and the agent revision, pass the handoff as context.world, and finish the instance before completing the execution. To drive an instance yourself:
Finishing a gateway instance answers
lifecycle: "completing" with sealedAt: null; the seal follows a 5-second grace so in-flight calls land. A later finish answers 409, which the runners treat as the seal they can no longer change. getEvidence needs the project key; a world token can never read evidence, and an open instance answers 409 until it is sealed. Nothing in these helpers logs the token. Keep the handoff out of your own logs and checkpoints.
Hue-native tools and the hue_sim_ capability are deprecated. When a case runs on an instance without a handoff, runSimulation and runLocalAgent emit a one-time DeprecationWarning with code HUE_NATIVE_SIMULATION_TOOLS, and provider-profile preflight emits HUE_PROVIDER_FACADE; for a gateway instance, provider-profile options are ignored with HUE_PROVIDER_FACADE_IGNORED. Pass deprecationWarnings: false to silence them. hue eval never emits these warnings.
Local setup session
@hue-run/sdk/setup is the session core behind the hue setup CLI: a pure, resumable state machine that detects a project, plans the deliberately narrow automatic integration matrix, installs the runtime, wires the application and verifies a metadata-only setup probe — emitting secret-free versioned events. It is a separate local inspection path, not a simulation launcher. Every JSONL event carries SETUP_EVENT_CONTRACT_VERSION.
Anonymous setup on
app.hue.run is inactive, so do not use hue setup to start or claim a trial project. This section documents the exported API.Managed target adapter
createManagedTargetHandler(options: ManagedTargetOptions) from @hue-run/sdk/managed returns (request: Request) => Promise<Response>. Required options are machineCredential, target and flushTelemetry; optional options are tracer, baseUrl, maxExecutionMillis (default 90000, at most 90000) and finalizationMillis (default 30000, at most 30000). Pass tracer: hue.tracer with a Hue-owned client; without it the handler falls back to the global tracer, its span is not recorded and every invocation returns uncertain.
The target receives a ManagedTargetContext: executionId, attempt, input, config, verified inputFiles (ManagedInputFile entries with artifactId, filename, contentType, byteSize, sha256 and role, plus their data bytes), an AbortSignal signal and the traceId of the ai.managed_target span. It returns a ManagedTargetResult: optional state, output JSON, a safe error summary, files (ManagedOutputFile entries with filename, contentType, data and optional primary) and provider-reported usage. ManagedInvocation describes the protocol-version-1 request body Hue POSTs. The helper claims before execution and saves outcomes before returning. It never automatically reruns the agent. See managed runs for the full setup and recovery flow.
Serving lifecycle
createHueSafe(options) accepts the same options as createHue, catches initialization failures and returns a disabled client with an instrumentation failure; the caller’s onExportIssue stays attached and receives a fixed initialization-failure issue, never the original error’s message or properties. Pass an empty string for an unset environment key; the safe constructor handles the invalid configuration. enabled: false needs neither a key nor a captureContent choice. flushSafe(options?: SafeLifecycleOptions) and shutdownSafe(options?: SafeLifecycleOptions) return Promise<SafeLifecycleResult>, { ok: boolean; timedOut: boolean; report: ExportReport }, without rejecting. SafeLifecycleOptions.timeoutMillis is the caller deadline, 1–60000 ms, default 1000. A deadline does not cancel a borrowed provider.
The report also exposes pendingBytes, droppedSpans, droppedLogs and instrumentationFailures. Dropped records are subsets of failed records; do not add those counts together. Safe ok reflects cumulative failures for the client lifetime. Capture, metadata, setup and cleanup failures in Hue helpers omit telemetry and preserve the original callback result or error. Async onExportIssue rejections are contained and callbacks are rate-limited. See TypeScript production setup.
In Vercel Functions, Hue registers background delivery with waitUntil without calling borrowed providers’ forceFlush() or consuming flush failure reports. An explicitly awaited flush keeps its acknowledgement contract. See Vercel Functions and Workflow.