@hue-run/sdk 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/EVALUATIONS.md +141 -0
- package/LICENSE +18 -0
- package/README.md +196 -0
- package/dist/ai-sdk.d.ts +4 -0
- package/dist/ai-sdk.js +10 -0
- package/dist/client.d.ts +40 -0
- package/dist/client.js +309 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +32 -0
- package/dist/evals/checkpoint.d.ts +9 -0
- package/dist/evals/checkpoint.js +89 -0
- package/dist/evals/client.d.ts +96 -0
- package/dist/evals/client.js +195 -0
- package/dist/evals/json.d.ts +6 -0
- package/dist/evals/json.js +61 -0
- package/dist/evals/runner.d.ts +49 -0
- package/dist/evals/runner.js +369 -0
- package/dist/evals/schema-worker.d.ts +1 -0
- package/dist/evals/schema-worker.js +14 -0
- package/dist/evals/scorers.d.ts +21 -0
- package/dist/evals/scorers.js +212 -0
- package/dist/evals/types.d.ts +301 -0
- package/dist/evals/types.js +1 -0
- package/dist/evals.d.ts +7 -0
- package/dist/evals.js +4 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/privacy.d.ts +7 -0
- package/dist/privacy.js +138 -0
- package/dist/transport.d.ts +44 -0
- package/dist/transport.js +320 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.js +1 -0
- package/package.json +79 -0
package/EVALUATIONS.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Local evaluations
|
|
2
|
+
|
|
3
|
+
The SDK executes targets and scorers on your machine. Hue stores pinned definitions, experiment progress and results. It does not execute uploaded source code. Follow the [installation guide](https://docs.hue.run/installation) to add `@hue-run/sdk` to your application.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
import { createHue } from "@hue-run/sdk";
|
|
8
|
+
import { builtins, createEvaluationClient, runExperiment, rescore } from "@hue-run/sdk/evals";
|
|
9
|
+
|
|
10
|
+
const connection = { apiKey: process.env.HUE_API_KEY! };
|
|
11
|
+
const client = createEvaluationClient(connection);
|
|
12
|
+
const hue = createHue({ ...connection, serviceName: "evaluation-demo", captureContent: false });
|
|
13
|
+
|
|
14
|
+
// Registry writes use optimistic revisions; they do not have automatic retries.
|
|
15
|
+
const dataset = await client.createDataset({ name: "Greetings", slug: "greetings" });
|
|
16
|
+
let draft = dataset.versions[0];
|
|
17
|
+
({ version: draft } = await client.addCase(draft.id, {
|
|
18
|
+
expectedRevision: draft.revision,
|
|
19
|
+
externalKey: "hello",
|
|
20
|
+
inputs: { message: "hello" },
|
|
21
|
+
expected: "Hello!",
|
|
22
|
+
}));
|
|
23
|
+
const frozen = await client.freezeDatasetVersion(draft.id, draft.revision);
|
|
24
|
+
const scorer = await client.createScorer({ name: "Exact", slug: "exact" });
|
|
25
|
+
const exact = await client.publishScorerVersion(scorer.id, builtins.exactMatch());
|
|
26
|
+
|
|
27
|
+
// Persist each creation key/returned ID in your application before retrying creation.
|
|
28
|
+
const experiment = await client.createExperiment({
|
|
29
|
+
idempotencyKey: randomUUID(),
|
|
30
|
+
name: "Greeting configuration A",
|
|
31
|
+
datasetVersionId: frozen.id,
|
|
32
|
+
scorerVersionIds: [exact.id],
|
|
33
|
+
config: { greeting: "Hello!" },
|
|
34
|
+
});
|
|
35
|
+
try {
|
|
36
|
+
const report = await runExperiment({
|
|
37
|
+
client,
|
|
38
|
+
hue,
|
|
39
|
+
experimentId: experiment.id,
|
|
40
|
+
checkpointDirectory: `.hue-checkpoints/${experiment.id}`,
|
|
41
|
+
persistResultContent: true,
|
|
42
|
+
traceEvidence: { mode: "required" },
|
|
43
|
+
concurrency: 2,
|
|
44
|
+
// Replace this deterministic example with your real agent invocation.
|
|
45
|
+
target: async (_inputs, { config }) => (config as { greeting: string }).greeting,
|
|
46
|
+
});
|
|
47
|
+
const historical = await client.createEvaluationRun({
|
|
48
|
+
idempotencyKey: randomUUID(),
|
|
49
|
+
name: "Exact rescore",
|
|
50
|
+
subjectIds: report.subjectIds,
|
|
51
|
+
scorerVersionIds: [exact.id],
|
|
52
|
+
});
|
|
53
|
+
await rescore({
|
|
54
|
+
client,
|
|
55
|
+
runId: historical.id,
|
|
56
|
+
checkpointDirectory: `.hue-checkpoints/${historical.id}`,
|
|
57
|
+
persistResultContent: true,
|
|
58
|
+
});
|
|
59
|
+
} finally {
|
|
60
|
+
await hue.shutdown();
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Create another experiment with the same frozen version and different `config` to compare configurations. The runner reads the exact experiment case/version and scorer definitions; it never resolves a mutable latest version. `rescore` accepts an existing evaluation-run ID and has no target callback. Subject IDs refer to immutable saved outputs and trace evidence.
|
|
65
|
+
|
|
66
|
+
## Content and result states
|
|
67
|
+
|
|
68
|
+
Both choices are required and independent:
|
|
69
|
+
|
|
70
|
+
- `captureContent` configures telemetry helpers and Vercel telemetry callbacks.
|
|
71
|
+
- `persistResultContent` configures completion output, target error messages, scorer evidence and arbitrary scorer explanations, including local checkpoint files. When false, the runner keeps these only in memory while computing scores and uploads generic explanations. Declared metric values are always uploaded, including custom text metrics; do not put sensitive output in a metric unless that is intended.
|
|
72
|
+
|
|
73
|
+
Frozen dataset inputs/references already exist on Hue. Their presence is independent of these switches. No output is inferred from telemetry. JavaScript `undefined` means unavailable output; JSON `null`, false, zero and empty string remain present values. Historical subjects with unavailable output produce skipped results without executing a scorer callback. A failed quality metric remains `state:"scored"` with `passed:false`. Target errors and scorer errors remain separate. Target error types are generalized to `TargetError`; when content is enabled, bounded messages may be stored. Never put credentials in error messages, output, custom metric values, names or metadata.
|
|
74
|
+
|
|
75
|
+
`traceEvidence:{mode:"required"}` waits for trace and log export acknowledgement after the root span ends. The explicit alternative `{mode:"omit",reason:"..."}` stores the omission reason and declared trace ID without a fake snapshot. It can complete despite an export failure; export diagnostics remain available on the Hue client. There is no automatic fallback to omission.
|
|
76
|
+
|
|
77
|
+
## Local scorers
|
|
78
|
+
|
|
79
|
+
Built-ins execute exact typed JSON equality, string inclusion (with pinned case sensitivity), and JSON Schema draft 2020-12 via pinned Ajv. Exact/includes skip absent references; includes skips non-string operands. Object key order does not affect exact match; array order and scalar types do.
|
|
80
|
+
|
|
81
|
+
JSON Schema compilation and validation run in an isolated worker with a default 2-second deadline (`schemaTimeoutMillis:100..60000`), terminated before returning a timeout error. No remote schema loading, custom formats, coercion or default insertion is enabled. Compilation errors are errors, not failed quality scores. Worker startup time counts toward the deadline. This is an execution bound, not a general security sandbox. Schema registration also enforces the server's supported schema subset. Ajv documents [draft 2020-12 support](https://ajv.js.org/json-schema.html) and [schema/regular-expression security considerations](https://ajv.js.org/security.html).
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { readFile } from "node:fs/promises";
|
|
85
|
+
import { defineLocalScorer } from "@hue-run/sdk/evals";
|
|
86
|
+
import { score } from "./my-scorer.js";
|
|
87
|
+
|
|
88
|
+
const local = defineLocalScorer({
|
|
89
|
+
source: await readFile(new URL("./my-scorer.js", import.meta.url)),
|
|
90
|
+
entrypoint: "score",
|
|
91
|
+
metrics: [{ name: "quality", type: "number", min: 0, max: 1 }],
|
|
92
|
+
score,
|
|
93
|
+
});
|
|
94
|
+
const identity = await client.createScorer({ name: "Quality", slug: "quality" });
|
|
95
|
+
const published = await client.publishScorerVersion(identity.id, local.definition);
|
|
96
|
+
// Pin published.id in the experiment and pass scorers:[local] to the runner.
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
A callback receives `{inputs,hasOutput,output?,hasExpected,expected?,metadata,executionState}` and returns one of:
|
|
100
|
+
|
|
101
|
+
- `{state:"scored",metrics:[{name,value,passed?}],explanation?,evidence?}` (explanation or evidence required).
|
|
102
|
+
- `{state:"error",error:{type,message?}}`.
|
|
103
|
+
- `{state:"skipped",explanation:"reason"}`.
|
|
104
|
+
|
|
105
|
+
All declared metrics must appear exactly once and satisfy pinned types, bounds and categories. The binding must match language, entrypoint, SHA-256 source digest and metric definitions. The digest is an authenticated caller declaration; it does not attest closures, dependency versions or actual execution. Callback source is never downloaded or evaluated. Callbacks are trusted local code; they have **no execution timeout or side-effect cancellation**. Concurrency limits active cases to 1–16 (default 1), with scorers evaluated sequentially within each case.
|
|
106
|
+
|
|
107
|
+
### Hosted and manual scorer pins
|
|
108
|
+
|
|
109
|
+
The local runner leaves `llm_judge` and `manual` pins pending and reports their IDs in `deferredScorerVersionIds`. It does not upload a synthetic skipped result that would occupy their immutable result slot. Manual results require a human session. Hosted dispatch is an explicit separate API operation: inspect `getJudgeBudget()`, then call `createJudgeJobs(runId,{idempotencyKey,jobs:[{evaluationItemId,scorerVersionId}]})`. `listJudgeJobs`, `getJudgeJob` and `cancelJudgeJob` expose job progress and cancellation requests. These methods never claim that local execution has hosted provenance. Hosted job endpoints are covered by HTTP contract tests here; live hosted model execution is a separate platform acceptance phase. `listResults` and `getResult` read recorded local or hosted results.
|
|
110
|
+
|
|
111
|
+
When present, the budget's `authentication` reports credential resolution only. An
|
|
112
|
+
`available` status or `configured: true` does not prove that a provider accepted the
|
|
113
|
+
credential, has funds, or permits the selected model. The project's `enabled`,
|
|
114
|
+
allocation and `blocked` fields are separate admission controls. Treat absent
|
|
115
|
+
authentication details as unknown.
|
|
116
|
+
|
|
117
|
+
Job reads preserve `originalChargeState` and the original provider `receipt`.
|
|
118
|
+
`chargeState` and `actualMicroUsd` reflect a separately verified reconciliation
|
|
119
|
+
when one exists; `reconciliation` is otherwise `null`. Its evidence reference,
|
|
120
|
+
reason and timestamp explain that settlement. A settled charge does not change
|
|
121
|
+
an interrupted job's execution state or rerun the model.
|
|
122
|
+
|
|
123
|
+
## Checkpoints and failures
|
|
124
|
+
|
|
125
|
+
Use one dedicated mode-0700 directory per experiment/rescore run. Files are mode 0600, written through fsync and atomic rename, and protected against accidental corruption by a digest. This is local storage, not encryption. Do not check it into Git. The manifest binds project, origin, frozen versions/configuration, scorer pins and content choices. Keep the directory until you no longer need upload recovery.
|
|
126
|
+
|
|
127
|
+
An exclusive `.lock` prevents two processes from invoking targets through the same checkpoint. A process crash can leave the lock behind. Confirm the recorded process has stopped before explicitly removing that lock; the SDK never guesses ownership from elapsed time. Removing a lock does not authorize another target call.
|
|
128
|
+
|
|
129
|
+
The runner saves a starting marker before `start`, and a running marker before invoking a target. If an outcome is not durably saved, resume throws `UncertainExecutionError` and never reruns the target. Replaying an original start key only recovers its execution ID. The low-level `startExecution` API requires an explicit `previousExecutionId`; replacing a still-started attempt additionally requires `allowUncertainRetry:true`. The convenience runner does not automatically adopt externally created attempts. Create a fresh experiment for a fresh target run after investigating side effects.
|
|
130
|
+
|
|
131
|
+
After a target completes and local scoring finishes, the runner saves the allowed completion/result payloads before uploading. Network/API errors leave those payloads and stable keys available for another call to `runExperiment` with the same directory. Saved receipt IDs prevent duplicate result writes. Serialization failure raises `OutcomeSerializationError` with the execution ID; it does not relabel the target as failed or invoke it again. Scoring/upload failures never change target state.
|
|
132
|
+
|
|
133
|
+
A crash between target completion and saving its permitted result still leaves an uncertain outcome; metadata-only mode intentionally cannot reconstruct discarded output. Export acknowledgement is saved separately. If required telemetry export was not acknowledged, a fresh empty exporter is not evidence of prior receipt: automatic completion is refused. Inspect/export the original trace or use the low-level completion API with an explicit omission policy; do not rerun a known completed target to manufacture telemetry. API completion/results retain their own idempotency guarantees for explicit recovery.
|
|
134
|
+
|
|
135
|
+
Concurrent flush calls each perform a fresh serialized drain. Because OTLP partial responses do not identify rejected records, any export failure during a case prevents the runner from acknowledging that case's required evidence, including a failure already surfaced by another concurrent flush. This deliberately favors explicit recovery over accepting possibly incomplete evidence.
|
|
136
|
+
|
|
137
|
+
The runner stops scheduling more cases after an operational failure and waits for already active cases before releasing the lock. It does not undo target side effects. A historical rescore can repeat local scoring after a crash before its checkpoint was saved; its result uploads use saved immutable payloads and stable keys once prepared.
|
|
138
|
+
|
|
139
|
+
## Verification boundaries
|
|
140
|
+
|
|
141
|
+
`scripts/verify-package.mjs` installs a real packed tarball outside the monorepo and runs HTTP contract tests against a synthetic service plus actual OpenTelemetry exporters. It checks two configurations, rescoring without target invocation, absent/null output, upload resume, uncertain execution, exclusive checkpoints, source/metric contracts, content policy and terminating schema workers. `scripts/verify-evaluation-api.mjs` is a separate opt-in acceptance against a real Hue receiver/API; it creates synthetic datasets/scorers/experiments in the project associated with the supplied development key.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hue contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
|
+
portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
15
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
16
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
18
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Hue TypeScript SDK
|
|
2
|
+
|
|
3
|
+
A Node 24 / Bun 1.3.9 client for Hue's standard OTLP HTTP endpoints. It uses the
|
|
4
|
+
OpenTelemetry JavaScript SDK and official OTLP protobuf exporter components for
|
|
5
|
+
traces and correlated logs. The package is named `@hue-run/sdk`.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @hue-run/sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or with Bun:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun add @hue-run/sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Run the command in your application's server package. See the [compatibility guide](https://docs.hue.run/sdks/compatibility) before adding Hue to an application with existing OpenTelemetry or AI SDK dependencies.
|
|
20
|
+
|
|
21
|
+
## Start
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { createHue, HueExportError } from "@hue-run/sdk";
|
|
25
|
+
|
|
26
|
+
const hue = createHue({
|
|
27
|
+
apiKey: process.env.HUE_API_KEY!, // a project service key, on the server only
|
|
28
|
+
serviceName: "my-agent",
|
|
29
|
+
captureContent: false, // required: explicitly choose true or false
|
|
30
|
+
onExportIssue: (issue) => console.error(issue), // sanitized counts, never server bodies
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await hue.checkConnection(); // GET /api/v1/projects/current
|
|
34
|
+
await hue.withSpan(
|
|
35
|
+
"chat",
|
|
36
|
+
async (span) => {
|
|
37
|
+
const output = await hue.tool("uppercase", "hello", () => "hello".toUpperCase());
|
|
38
|
+
span.setOutput(output);
|
|
39
|
+
hue.recordMessages({ output: [{ role: "assistant", content: output }] });
|
|
40
|
+
},
|
|
41
|
+
{ sessionId: "session-123", userId: "user-123", input: "hello" },
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
await hue.flush(); // await both traces and logs; don't discard this promise
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error instanceof HueExportError) console.error(error.issues, error.report);
|
|
48
|
+
}
|
|
49
|
+
await hue.shutdown(); // flushes and releases providers owned by this client
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The default destination is `https://app.hue.run`. Data goes to
|
|
53
|
+
`/api/v1/otlp/v1/traces` and `/api/v1/otlp/v1/logs` with a Bearer project key.
|
|
54
|
+
Set `baseUrl` only for another Hue deployment. It must be an origin without an API path; a trailing slash is accepted.
|
|
55
|
+
HTTPS is required except for loopback HTTP. Redirects are refused for both
|
|
56
|
+
project checks and exports. There is no proprietary tracing protocol, lab API
|
|
57
|
+
wrapper, database dependency, or dependency on the Hue application workspace.
|
|
58
|
+
|
|
59
|
+
## Vercel AI SDK 7
|
|
60
|
+
|
|
61
|
+
Compatible optional peers are `ai@^7.0.99` and `@ai-sdk/otel@^1.0.99`, alongside
|
|
62
|
+
`@opentelemetry/api@1.9.1`. For an app without global AI SDK telemetry integrations,
|
|
63
|
+
configure telemetry on each agent or generation call:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { ToolLoopAgent } from "ai";
|
|
67
|
+
import { hueTelemetry } from "@hue-run/sdk/ai-sdk";
|
|
68
|
+
|
|
69
|
+
const agent = new ToolLoopAgent({
|
|
70
|
+
model: process.env.AI_MODEL!, // actual configured AI Gateway provider/model
|
|
71
|
+
telemetry: hueTelemetry(hue),
|
|
72
|
+
});
|
|
73
|
+
await hue.withSpan(
|
|
74
|
+
"chat",
|
|
75
|
+
async (span) => {
|
|
76
|
+
const result = await agent.stream({ prompt: "Hello" });
|
|
77
|
+
// Consume the stream inside the span's callback so completion/error timing is correct.
|
|
78
|
+
for await (const text of result.textStream) process.stdout.write(text);
|
|
79
|
+
span.setOutput(await result.text);
|
|
80
|
+
},
|
|
81
|
+
{ sessionId: "session-123" },
|
|
82
|
+
);
|
|
83
|
+
await hue.flush();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`hueTelemetry(hue)` supplies per-call integrations, which AI SDK 7 uses **instead of
|
|
87
|
+
globally registered integrations for that call**. Global registration remains intact,
|
|
88
|
+
but those integrations do not receive that call's events. To keep an existing
|
|
89
|
+
OpenTelemetry exporter, attach Hue's transport to the same provider using the
|
|
90
|
+
[existing-provider recipe](#existing-opentelemetry-providers).
|
|
91
|
+
|
|
92
|
+
Reuse the client across server requests. Await stream completion before flushing;
|
|
93
|
+
returning a streaming `Response` does not mean its stream has finished. The
|
|
94
|
+
[Next.js streaming recipe](https://docs.hue.run/integrations/opentelemetry#flush-streamed-responses-in-next-js)
|
|
95
|
+
shows how to keep completion and flushing within the request's background lifetime.
|
|
96
|
+
For a standalone script, put the operation in `try` and call `await hue.shutdown()`
|
|
97
|
+
in `finally`. Shut down a shared server client only when the application stops.
|
|
98
|
+
|
|
99
|
+
The integration creates real Vercel provider, streaming and tool spans and passes
|
|
100
|
+
`recordInputs` and `recordOutputs` explicitly. The installed-package verification
|
|
101
|
+
tests the matching 7.0.99/1.0.99 and
|
|
102
|
+
7.0.100/1.0.100 pairs. Compatible-major ranges do not mean every later release
|
|
103
|
+
has been verified. Other OTel
|
|
104
|
+
instrumentations can use `hue.tracer` directly or explicitly attach the processors
|
|
105
|
+
below. Instrumentations that only use a global provider need your application's
|
|
106
|
+
normal OTel setup; Hue does not silently replace it.
|
|
107
|
+
|
|
108
|
+
## Privacy and content
|
|
109
|
+
|
|
110
|
+
`captureContent: false` disables manual input/output/messages/tool content and
|
|
111
|
+
removes recognized GenAI, Vercel, OpenInference and OpenLLMetry content attributes,
|
|
112
|
+
legacy GenAI content events, log bodies, status messages and exception text before
|
|
113
|
+
export. Model/provider/token metadata remains available. Generic custom attribute
|
|
114
|
+
names cannot be classified automatically; use them deliberately.
|
|
115
|
+
|
|
116
|
+
`captureContent: true` captures supplied content. Accepted content is stored by Hue;
|
|
117
|
+
there is no SDK retention timer or automatic content expiry. To redact strings
|
|
118
|
+
before export, supply `redact(value, path)`; it applies to supported strings in
|
|
119
|
+
attributes, resources, event/link attributes and log bodies. Return a string.
|
|
120
|
+
A throwing callback or invalid/oversized content fails closed: that record is
|
|
121
|
+
counted as failed and the flush reports it. Shared resources are redacted once per
|
|
122
|
+
export batch. Do not put user content or secrets in span names or scope names.
|
|
123
|
+
|
|
124
|
+
Manual helpers encode JSON values without converting null into absence. Unknown
|
|
125
|
+
outputs and usage remain absent. This SDK does not estimate tokens or cost. Error
|
|
126
|
+
helpers mark span status and record an exception; thrown application errors remain
|
|
127
|
+
errors and are rethrown unchanged. `withSpan` ends its span in `finally`.
|
|
128
|
+
|
|
129
|
+
## Existing OpenTelemetry providers
|
|
130
|
+
|
|
131
|
+
Attach processors while constructing your providers. Hue uses local async context
|
|
132
|
+
for its own helpers and never registers/replaces the global tracer, logger, or
|
|
133
|
+
context manager.
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
import { TracerProvider } from "@opentelemetry/sdk-trace";
|
|
137
|
+
import { LoggerProvider } from "@opentelemetry/sdk-logs";
|
|
138
|
+
import { createHue, createHueTransport } from "@hue-run/sdk";
|
|
139
|
+
|
|
140
|
+
const transport = createHueTransport({
|
|
141
|
+
apiKey: process.env.HUE_API_KEY!,
|
|
142
|
+
serviceName: "existing-app",
|
|
143
|
+
captureContent: false,
|
|
144
|
+
});
|
|
145
|
+
const tracerProvider = new TracerProvider({ spanProcessors: [transport.spanProcessor] });
|
|
146
|
+
const loggerProvider = new LoggerProvider({ processors: [transport.logRecordProcessor] });
|
|
147
|
+
const hue = createHue({ transport, tracerProvider, loggerProvider });
|
|
148
|
+
// Your application owns and configures these providers and their resources.
|
|
149
|
+
await hue.shutdown(); // flushes; does not shut down these externally owned providers
|
|
150
|
+
// During application shutdown, shut down your providers, then await transport.shutdown().
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
For external parent context pass `parentContext` to `withSpan`, or use standard
|
|
154
|
+
OTel context propagation in your application. `getContext()` exposes the helper's
|
|
155
|
+
current context for APIs taking an explicit context. Session/user identifiers are
|
|
156
|
+
inherited within a client callback. Separate requests require separate callbacks.
|
|
157
|
+
|
|
158
|
+
## Delivery behavior
|
|
159
|
+
|
|
160
|
+
Exports use official OTel retry handling for temporary HTTP/network failures. Each
|
|
161
|
+
request is limited to 1 MiB before gzip (with space reserved for gzip overhead) and each content value to 256 KiB. Batches
|
|
162
|
+
split at record boundaries. Each signal queues at most 2,048 records, including
|
|
163
|
+
exports in flight; overflow is reported through the callback, counters and next
|
|
164
|
+
flush. This is an in-memory queue, not durable storage.
|
|
165
|
+
|
|
166
|
+
`flush()` waits for the current trace and log export work. A partial rejection,
|
|
167
|
+
invalid acknowledgement, queue drop or failure throws `HueExportError`; its
|
|
168
|
+
`report` contains cumulative accepted/rejected/failed/pending counts. Accepted
|
|
169
|
+
means the collector acknowledged receipt, not that a complete trace has arrived.
|
|
170
|
+
A malformed response reports uncertain acceptance as failure. Partial successes
|
|
171
|
+
are not retried. Warning-only acknowledgements with zero rejected records remain
|
|
172
|
+
successful; the callback and issue history expose a sanitized warning. The next
|
|
173
|
+
non-overlapping flush reports new failures; overlapping callers also observe failures
|
|
174
|
+
from their shared in-flight work. Counters remain cumulative and `transport.getIssues()`
|
|
175
|
+
keeps the latest 128 sanitized issues. Each concurrent caller receives a fresh serialized
|
|
176
|
+
drain, including records emitted before its call. Stop request production
|
|
177
|
+
before shutdown so late spans cannot race it. A client does not own instrumented
|
|
178
|
+
operations still running in the application.
|
|
179
|
+
|
|
180
|
+
## Package verification
|
|
181
|
+
|
|
182
|
+
From the repository root with Node 24 and Bun 1.3.9 on PATH:
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
node packages/sdk-typescript/scripts/verify-package.mjs
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
This copies the SDK to a temporary directory, performs a frozen installation,
|
|
189
|
+
builds and packs it, installs the tarball into a separate consumer, runs the real
|
|
190
|
+
HTTP exporter suite against that installed package, and installs/builds the
|
|
191
|
+
standalone reference chatbot. It prints the artifact paths. No package is
|
|
192
|
+
published. The chatbot README describes running that external installation.
|
|
193
|
+
|
|
194
|
+
# Local evaluation workflows
|
|
195
|
+
|
|
196
|
+
The optional `@hue-run/sdk/evals` entry point supports dataset/scorer registration, frozen-version experiments, local built-in/custom scoring, upload resume, and historical rescoring. See the [evaluation guide](https://docs.hue.run/evaluations/first-evaluation) for the complete journey, content policy and checkpoint recovery contract.
|
package/dist/ai-sdk.d.ts
ADDED
package/dist/ai-sdk.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { OpenTelemetry } from "@ai-sdk/otel";
|
|
2
|
+
/** Use as the call's telemetry option; it does not change global AI SDK integrations. */
|
|
3
|
+
export function hueTelemetry(hue) {
|
|
4
|
+
return {
|
|
5
|
+
isEnabled: true,
|
|
6
|
+
recordInputs: hue.captureContent,
|
|
7
|
+
recordOutputs: hue.captureContent,
|
|
8
|
+
integrations: [new OpenTelemetry({ tracer: hue.tracer, usage: true })],
|
|
9
|
+
};
|
|
10
|
+
}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type Context, type Span, type Tracer } from "@opentelemetry/api";
|
|
2
|
+
import { HueTransport } from "./transport.js";
|
|
3
|
+
import type { ExportReport, FlushableLoggerProvider, FlushableTracerProvider, HueOptions, HueSpan, JsonValue, ProjectConnection, SpanOptions } from "./types.js";
|
|
4
|
+
export interface ExistingHueProviders {
|
|
5
|
+
transport: HueTransport;
|
|
6
|
+
tracerProvider: FlushableTracerProvider;
|
|
7
|
+
loggerProvider: FlushableLoggerProvider;
|
|
8
|
+
}
|
|
9
|
+
export declare class HueConnectionError extends Error {
|
|
10
|
+
readonly status?: number | undefined;
|
|
11
|
+
constructor(message: string, status?: number | undefined);
|
|
12
|
+
}
|
|
13
|
+
export declare class HueClient {
|
|
14
|
+
readonly transport: HueTransport;
|
|
15
|
+
readonly tracer: Tracer;
|
|
16
|
+
readonly captureContent: boolean;
|
|
17
|
+
private logger;
|
|
18
|
+
private storage;
|
|
19
|
+
private tracerProvider;
|
|
20
|
+
private loggerProvider;
|
|
21
|
+
private ownedProviders?;
|
|
22
|
+
private closed;
|
|
23
|
+
private shutdownPromise?;
|
|
24
|
+
private flushPromise?;
|
|
25
|
+
constructor(options: HueOptions | ExistingHueProviders);
|
|
26
|
+
getContext(): Context;
|
|
27
|
+
withSpan<T>(name: string, callback: (span: HueSpan) => Promise<T> | T, options?: SpanOptions): Promise<T>;
|
|
28
|
+
tool<T extends JsonValue | undefined>(name: string, input: JsonValue, execute: () => Promise<T> | T): Promise<T>;
|
|
29
|
+
recordError(span: Span, error: unknown): void;
|
|
30
|
+
recordMessages(messages: {
|
|
31
|
+
input?: JsonValue;
|
|
32
|
+
output?: JsonValue;
|
|
33
|
+
}, explicitContext?: Context): void;
|
|
34
|
+
private setContent;
|
|
35
|
+
checkConnection(): Promise<ProjectConnection>;
|
|
36
|
+
flush(): Promise<ExportReport>;
|
|
37
|
+
private flushOnce;
|
|
38
|
+
shutdown(): Promise<ExportReport>;
|
|
39
|
+
}
|
|
40
|
+
export declare function createHue(options: HueOptions | ExistingHueProviders): HueClient;
|