@hue-run/sdk 0.7.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CLI.md +27 -14
  2. package/ENVIRONMENTS.md +63 -1
  3. package/README.md +121 -5
  4. package/dist/ai-sdk.d.ts +3 -3
  5. package/dist/ai-sdk.js +3 -3
  6. package/dist/cli/env-file.d.ts +22 -0
  7. package/dist/cli/env-file.js +21 -0
  8. package/dist/cli/eval.js +100 -30
  9. package/dist/cli/login.d.ts +1 -1
  10. package/dist/cli/login.js +9 -4
  11. package/dist/client.d.ts +31 -3
  12. package/dist/client.js +199 -7
  13. package/dist/config.d.ts +2 -0
  14. package/dist/config.js +2 -0
  15. package/dist/environment/client.d.ts +16 -2
  16. package/dist/environment/client.js +46 -3
  17. package/dist/environment/tools.d.ts +2 -2
  18. package/dist/environment/tools.js +2 -2
  19. package/dist/environment/types.d.ts +134 -4
  20. package/dist/environment/world.d.ts +50 -0
  21. package/dist/environment/world.js +105 -0
  22. package/dist/environment.d.ts +2 -0
  23. package/dist/environment.js +1 -0
  24. package/dist/evals/environment-target.d.ts +53 -2
  25. package/dist/evals/environment-target.js +114 -10
  26. package/dist/evals/local-worker.d.ts +12 -5
  27. package/dist/evals/local-worker.js +13 -5
  28. package/dist/evals/runner.d.ts +1 -1
  29. package/dist/evals/runner.js +2 -2
  30. package/dist/evals/simulation.d.ts +14 -5
  31. package/dist/evals/simulation.js +26 -8
  32. package/dist/experimental-telemetry.d.ts +3 -2
  33. package/dist/experimental-telemetry.js +3 -2
  34. package/dist/inline-files.d.ts +10 -0
  35. package/dist/inline-files.js +86 -0
  36. package/dist/privacy.js +54 -5
  37. package/dist/provider-tools.d.ts +39 -0
  38. package/dist/provider-tools.js +222 -0
  39. package/dist/tool-definitions.d.ts +20 -0
  40. package/dist/tool-definitions.js +274 -0
  41. package/dist/transport.js +4 -2
  42. package/dist/types.d.ts +76 -3
  43. package/dist/version.d.ts +1 -1
  44. package/dist/version.js +1 -1
  45. package/package.json +1 -1
package/dist/cli/eval.js CHANGED
@@ -6,6 +6,7 @@ import { parseArgs } from "node:util";
6
6
  import { randomUUID } from "node:crypto";
7
7
  import { createHue } from "../client.js";
8
8
  import { createEnvironmentClient } from "../environment/client.js";
9
+ import { agentEnvironment, stripHueControlPlaneCredentials, writeMcpConfig, } from "../environment/world.js";
9
10
  import { EvaluationClient, HueApiError } from "../evals/client.js";
10
11
  import { TargetResult } from "../evals/types.js";
11
12
  import { CheckpointStore } from "../evals/checkpoint.js";
@@ -16,6 +17,7 @@ import { matchByName, parseScenarioSelector, resolveEvalSetPins, resolveScenario
16
17
  import { collectDirectOutputs, stageDirectCase } from "./eval-direct.js";
17
18
  import { runSimulation, } from "../evals/simulation.js";
18
19
  import { collectExperimentVerdicts, compareVerdicts, metricPassed, } from "../evals/verdicts.js";
20
+ import { envFileArgument, envFileOptions } from "./env-file.js";
19
21
  const USAGE = `Usage: hue eval [adapter-file] [options]
20
22
 
21
23
  Run a local agent against a published case or eval set, then print Hue's verdicts.
@@ -32,9 +34,15 @@ Selection (exactly one, not used with --worker):
32
34
 
33
35
  Agent (exactly one):
34
36
  <adapter-file> Module exporting default or runMyAgent(inputs, context)
35
- --command "<shell command>" Simulation: spawned per case with HUE_MCP_URL, HUE_MCP_TOKEN,
36
- HUE_MCP_EXPIRES_AT, HUE_EXECUTION_ID, HUE_ENVIRONMENT_RUN_ID,
37
- HUE_CASE_ID and HUE_CASE_KEY set; {"inputs","config"} on stdin.
37
+ --command "<shell command>" Simulation: spawned per case with the world's environment
38
+ (HUE_WORLD_ID, HUE_WORLD_TOKEN, one HUE_SIM_<SURFACE>_URL per
39
+ provider mirror, HUE_MCP_CONFIG, plus HUE_MCP_URL, HUE_MCP_TOKEN
40
+ and HUE_MCP_EXPIRES_AT for the first MCP mirror), HUE_EXECUTION_ID,
41
+ HUE_ENVIRONMENT_RUN_ID, HUE_CASE_ID and HUE_CASE_KEY set;
42
+ {"inputs","config"} on stdin. HUE_API_KEY and other Hue
43
+ control-plane credentials are removed from the child.
44
+ --allow-hue-credentials Keep HUE_API_KEY and other Hue control-plane credentials in
45
+ the --command child (off by default)
38
46
  Direct: spawned in a private case directory with HUE_CASE_DIR,
39
47
  HUE_CASE_INPUTS, HUE_CASE_OUTPUT_DIR, HUE_CASE_ID, HUE_CASE_KEY
40
48
  and HUE_EXECUTION_ID set; files/<role>/ hold the pinned inputs
@@ -49,17 +57,18 @@ Modes:
49
57
 
50
58
  Connection:
51
59
  --env-file <path> Load a dotenv file (HUE_API_KEY, HUE_BASE_URL) first
60
+ --env-path <path> Same as --env-file
52
61
  --origin <url> Hue origin (default: HUE_BASE_URL or https://app.hue.run)
53
62
 
54
63
  Output and limits:
55
- --name <run name> Run name (default: <case> · <agent key> · <revision>)
64
+ --name <run name> Run name (default: <agent key> @ <revision>, hashes shortened)
56
65
  --baseline <experiment id|url> Compare verdicts with a previous experiment
57
66
  --json Print one JSON document on stdout; progress goes to stderr
58
67
  --content Capture telemetry content; one-shot also persists
59
68
  outputs/explanations (--worker always persists them)
60
69
  --save-version Freeze an unsaved eval-set version before running
61
70
  --checkpoint-dir <path> Private checkpoint directory (default: .hue/eval/<agent-key>)
62
- --concurrency <n> Cases in flight, 1-16 (default: 1)
71
+ --concurrency <n> Cases in flight, 1-64 (default: 1)
63
72
  --timeout <seconds> Per-case --command timeout (default: 600)
64
73
  --wait <seconds> Verdict wait after the run finishes (default: 300)
65
74
  -h, --help Show this help
@@ -92,12 +101,13 @@ function parse(argv) {
92
101
  "scorer-version": { type: "string", multiple: true },
93
102
  mode: { type: "string" },
94
103
  command: { type: "string" },
104
+ "allow-hue-credentials": { type: "boolean", default: false },
95
105
  worker: { type: "boolean", default: false },
96
106
  "max-runs": { type: "string" },
97
107
  "agent-key": { type: "string" },
98
108
  "agent-name": { type: "string" },
99
109
  revision: { type: "string" },
100
- "env-file": { type: "string" },
110
+ ...envFileOptions,
101
111
  origin: { type: "string" },
102
112
  name: { type: "string" },
103
113
  baseline: { type: "string" },
@@ -164,6 +174,12 @@ function derivedAgentKey(adapterFile, command) {
164
174
  "";
165
175
  return slug(basename(script, extname(script)));
166
176
  }
177
+ function defaultRunName(agent) {
178
+ const revision = /^[0-9a-f]{12,64}$/i.test(agent.revision)
179
+ ? agent.revision.slice(0, 7)
180
+ : agent.revision;
181
+ return `${agent.key} @ ${revision}`;
182
+ }
167
183
  function gitRevision() {
168
184
  try {
169
185
  const value = execFileSync("git", ["rev-parse", "--short=12", "HEAD"], {
@@ -296,29 +312,65 @@ function parseAnswer(text) {
296
312
  return text;
297
313
  }
298
314
  }
299
- /** Runs the shell command once per case; the MCP token travels only through the child's environment. */
300
- function commandAdapter(command, timeoutSeconds) {
301
- return async (inputs, context) => parseAnswer(await spawnAgentCommand(command, {
302
- env: {
303
- ...process.env,
304
- HUE_MCP_URL: context.mcp.url,
305
- HUE_MCP_TOKEN: context.mcp.token,
306
- HUE_MCP_EXPIRES_AT: context.mcp.expiresAt,
315
+ /**
316
+ * Runs the shell command once per case. The world token and mirror URLs travel only through the
317
+ * child's environment and an owner-only MCP configuration file that is removed after the run;
318
+ * Hue control-plane credentials (`HUE_API_KEY`, `HUE_MCP_KEY`, any `hue_sk_` value) stay with
319
+ * the CLI unless `--allow-hue-credentials` is passed. A world created while the gateway is off
320
+ * still gets the `hue_sim_` capability under the same `HUE_MCP_*` names.
321
+ */
322
+ /** The parent environment an agent child starts from: without Hue control-plane credentials
323
+ * unless `--allow-hue-credentials` was passed. */
324
+ function parentEnvironment(allowHueCredentials) {
325
+ return allowHueCredentials
326
+ ? Object.fromEntries(Object.entries(process.env).filter((entry) => entry[1] !== undefined))
327
+ : stripHueControlPlaneCredentials(process.env);
328
+ }
329
+ function commandAdapter(command, timeoutSeconds, options) {
330
+ return async (inputs, context) => {
331
+ const parent = parentEnvironment(options.allowHueCredentials);
332
+ const identity = {
307
333
  HUE_EXECUTION_ID: context.executionId,
308
334
  HUE_ENVIRONMENT_RUN_ID: context.environmentRunId,
309
335
  HUE_CASE_ID: context.item.id,
310
336
  HUE_CASE_KEY: context.item.externalKey,
311
- },
312
- stdin: JSON.stringify({ inputs, config: context.config }),
313
- timeoutSeconds,
314
- ...(context.signal ? { signal: context.signal } : {}),
315
- }));
337
+ };
338
+ const configFile = context.world ? await writeMcpConfig(context.world) : undefined;
339
+ try {
340
+ const env = context.world
341
+ ? {
342
+ ...agentEnvironment(context.world, { parent, includeHueCredentials: true }),
343
+ ...identity,
344
+ HUE_MCP_CONFIG: configFile.path,
345
+ }
346
+ : {
347
+ ...parent,
348
+ ...(context.mcp
349
+ ? {
350
+ HUE_MCP_URL: context.mcp.url,
351
+ HUE_MCP_TOKEN: context.mcp.token,
352
+ HUE_MCP_EXPIRES_AT: context.mcp.expiresAt,
353
+ }
354
+ : {}),
355
+ ...identity,
356
+ };
357
+ return parseAnswer(await spawnAgentCommand(command, {
358
+ env,
359
+ stdin: JSON.stringify({ inputs, config: context.config }),
360
+ timeoutSeconds,
361
+ ...(context.signal ? { signal: context.signal } : {}),
362
+ }));
363
+ }
364
+ finally {
365
+ await configFile?.dispose();
366
+ }
367
+ };
316
368
  }
317
369
  /**
318
370
  * Direct cases: the command works in a private case directory and writes its documents to
319
371
  * `output/`. Its stdout is only used as the JSON output when it wrote no result or summary file.
320
372
  */
321
- function directCommandAdapter(command, timeoutSeconds) {
373
+ function directCommandAdapter(command, timeoutSeconds, options) {
322
374
  return async (inputs, context) => {
323
375
  const layout = await stageDirectCase(context.outputDirectory, {
324
376
  inputs,
@@ -330,7 +382,7 @@ function directCommandAdapter(command, timeoutSeconds) {
330
382
  const stdout = await spawnAgentCommand(command, {
331
383
  cwd: layout.caseDirectory,
332
384
  env: {
333
- ...process.env,
385
+ ...parentEnvironment(options.allowHueCredentials),
334
386
  HUE_CASE_DIR: layout.caseDirectory,
335
387
  HUE_CASE_INPUTS: layout.inputsPath,
336
388
  HUE_CASE_OUTPUT_DIR: layout.outputDirectory,
@@ -636,7 +688,7 @@ function parseBaseline(value) {
636
688
  }
637
689
  async function runOnce(values, connection, agents, agent, hue, output, signal) {
638
690
  const client = new EvaluationClient(connection);
639
- const concurrency = integer("concurrency", values.concurrency, 1, 1, 16);
691
+ const concurrency = integer("concurrency", values.concurrency, 1, 1, 64);
640
692
  const baselineId = parseBaseline(values.baseline);
641
693
  const mode = parseMode(values.mode);
642
694
  const pins = await resolveSelection(client, values);
@@ -648,7 +700,7 @@ async function runOnce(values, connection, agents, agent, hue, output, signal) {
648
700
  const frozen = await client.freezeDatasetVersion(pins.datasetVersionId, pins.revision);
649
701
  output.log(`Saved "${pins.name}" version ${frozen.version}.`);
650
702
  }
651
- const runName = values.name ?? `${pins.name} · ${agent.key} · ${agent.revision}`;
703
+ const runName = values.name ?? defaultRunName(agent);
652
704
  const project = await client.checkConnection();
653
705
  if (await detectDirect(client, pins, mode))
654
706
  return runDirect({
@@ -683,6 +735,10 @@ async function runOnce(values, connection, agents, agent, hue, output, signal) {
683
735
  persistResultContent: values.content,
684
736
  traceEvidence: { mode: "required" },
685
737
  concurrency,
738
+ agentRevision: agent.revision,
739
+ // The CLI adapts to whatever the deployment serves; the library warning is for code that
740
+ // still reads the legacy capability itself.
741
+ deprecationWarnings: false,
686
742
  signal,
687
743
  target: agents.simulation,
688
744
  async onProgress(event) {
@@ -820,7 +876,7 @@ async function runWorker(values, connection, adapter, agent, hue, output, signal
820
876
  const client = new ObservedClient(connection);
821
877
  const environmentClient = createEnvironmentClient(connection);
822
878
  const wait = integer("wait", values.wait, 300, 0, 86_400);
823
- const concurrency = integer("concurrency", values.concurrency, 1, 1, 16);
879
+ const concurrency = integer("concurrency", values.concurrency, 1, 1, 64);
824
880
  const maxRuns = values["max-runs"] === undefined
825
881
  ? undefined
826
882
  : integer("max-runs", values["max-runs"], 1, 1, 1_000_000);
@@ -847,6 +903,7 @@ async function runWorker(values, connection, adapter, agent, hue, output, signal
847
903
  },
848
904
  scorers: [],
849
905
  concurrency,
906
+ deprecationWarnings: false,
850
907
  signal,
851
908
  ...(maxRuns === undefined ? {} : { maxRuns }),
852
909
  target(inputs, tools, context) {
@@ -857,7 +914,8 @@ async function runWorker(values, connection, adapter, agent, hue, output, signal
857
914
  executionId: context.executionId,
858
915
  environmentRunId: context.environmentRunId,
859
916
  tools,
860
- mcp: context.mcp,
917
+ ...(context.world ? { world: context.world } : {}),
918
+ ...(context.mcp ? { mcp: context.mcp } : {}),
861
919
  ...(context.connectionBundle ? { connectionBundle: context.connectionBundle } : {}),
862
920
  signal,
863
921
  });
@@ -926,12 +984,19 @@ export async function runEvalCommand(argv) {
926
984
  throw new UsageError("--worker takes no selection; Hue chooses the run to execute");
927
985
  if (!values.worker && selections !== 1)
928
986
  throw new UsageError("Pass exactly one of --case, --set or --dataset-version");
929
- if (values["env-file"]) {
987
+ let envFile;
988
+ try {
989
+ envFile = envFileArgument(values, process.cwd());
990
+ }
991
+ catch (error) {
992
+ throw new UsageError(error.message);
993
+ }
994
+ if (envFile) {
930
995
  try {
931
- process.loadEnvFile(resolve(values["env-file"]));
996
+ process.loadEnvFile(resolve(envFile));
932
997
  }
933
998
  catch (error) {
934
- throw new UsageError(`Unable to load ${values["env-file"]}: ${error instanceof Error ? error.message : String(error)}`);
999
+ throw new UsageError(`Unable to load ${envFile}: ${error instanceof Error ? error.message : String(error)}`);
935
1000
  }
936
1001
  }
937
1002
  const apiKey = process.env.HUE_API_KEY?.trim();
@@ -959,8 +1024,13 @@ export async function runEvalCommand(argv) {
959
1024
  throw new Error("The adapter returned generated files for a simulated-world case");
960
1025
  return answer;
961
1026
  }
962
- : commandAdapter(values.command, timeout),
963
- direct: loaded ?? directCommandAdapter(values.command, timeout),
1027
+ : commandAdapter(values.command, timeout, {
1028
+ allowHueCredentials: values["allow-hue-credentials"],
1029
+ }),
1030
+ direct: loaded ??
1031
+ directCommandAdapter(values.command, timeout, {
1032
+ allowHueCredentials: values["allow-hue-credentials"],
1033
+ }),
964
1034
  };
965
1035
  hue = createHue({ apiKey, baseUrl, serviceName: key, captureContent: values.content });
966
1036
  return values.worker
@@ -14,7 +14,7 @@ export interface LoginCommandIo {
14
14
  fetch?: typeof fetch;
15
15
  openBrowser?: (url: string) => Promise<boolean>;
16
16
  }
17
- export declare const LOGIN_USAGE = "Usage: hue login [--origin URL] [--env-file PATH] [--keys evaluations|coding-agent|both]\n [--no-browser] [--force] [--gitignore]\n\nStore the key you created in Hue in a private env file. By default one \"Read and write\" key serves\nboth evaluations (HUE_API_KEY) and your coding agent (HUE_MCP_KEY); it is validated against Hue\nbefore it is stored, and key values are never printed.\n\nOptions:\n --origin URL Hue origin (default https://app.hue.run)\n --env-file PATH Env file to write (default .env.hue in the current directory)\n --keys KIND evaluations (HUE_API_KEY), coding-agent (HUE_MCP_KEY) or both from one key\n (default both)\n --no-browser Do not open the key settings page in a browser\n --force Replace an existing different value in the env file\n --gitignore Add the env file to .gitignore when a git repository does not ignore it\n -h, --help Show this help";
17
+ export declare const LOGIN_USAGE = "Usage: hue login [--origin URL] [--env-path PATH] [--keys evaluations|coding-agent|both]\n [--no-browser] [--force] [--gitignore]\n\nStore the key you created in Hue in a private env file. By default one \"Read and write\" key serves\nboth evaluations (HUE_API_KEY) and your coding agent (HUE_MCP_KEY); it is validated against Hue\nbefore it is stored, and key values are never printed.\n\nOptions:\n --origin URL Hue origin (default https://app.hue.run)\n --env-path PATH Env file to write (default .env.hue in the current directory); it is\n created when missing. --env-file also works, but Node itself exits\n before this command runs when that file does not exist yet\n --keys KIND evaluations (HUE_API_KEY), coding-agent (HUE_MCP_KEY) or both from one key\n (default both)\n --no-browser Do not open the key settings page in a browser\n --force Replace an existing different value in the env file\n --gitignore Add the env file to .gitignore when a git repository does not ignore it\n -h, --help Show this help";
18
18
  /** Hue MCP endpoint that pairs with an application origin. */
19
19
  export declare function mcpUrlForOrigin(origin: string): string;
20
20
  /** Normalizes a Hue origin: HTTPS, or HTTP for loopback only; no credentials, path, query or hash. */
package/dist/cli/login.js CHANGED
@@ -7,6 +7,7 @@ import { createInterface } from "node:readline";
7
7
  import { Writable } from "node:stream";
8
8
  import { parseArgs } from "node:util";
9
9
  import { isLoopbackHost } from "../config.js";
10
+ import { envFileArgument, envFileOptions } from "./env-file.js";
10
11
  const DEFAULT_ORIGIN = "https://app.hue.run";
11
12
  const DEFAULT_ENV_FILE = ".env.hue";
12
13
  /** Settings section that lists and creates project service keys. */
@@ -27,7 +28,7 @@ const KEY_KINDS = {
27
28
  };
28
29
  /** Settings preset that authorizes both evaluations and the coding agent's MCP reads and writes. */
29
30
  const KEY_PRESET = "Read and write";
30
- export const LOGIN_USAGE = `Usage: hue login [--origin URL] [--env-file PATH] [--keys evaluations|coding-agent|both]
31
+ export const LOGIN_USAGE = `Usage: hue login [--origin URL] [--env-path PATH] [--keys evaluations|coding-agent|both]
31
32
  [--no-browser] [--force] [--gitignore]
32
33
 
33
34
  Store the key you created in Hue in a private env file. By default one "Read and write" key serves
@@ -36,7 +37,9 @@ before it is stored, and key values are never printed.
36
37
 
37
38
  Options:
38
39
  --origin URL Hue origin (default ${DEFAULT_ORIGIN})
39
- --env-file PATH Env file to write (default ${DEFAULT_ENV_FILE} in the current directory)
40
+ --env-path PATH Env file to write (default ${DEFAULT_ENV_FILE} in the current directory); it is
41
+ created when missing. --env-file also works, but Node itself exits
42
+ before this command runs when that file does not exist yet
40
43
  --keys KIND evaluations (HUE_API_KEY), coding-agent (HUE_MCP_KEY) or both from one key
41
44
  (default both)
42
45
  --no-browser Do not open the key settings page in a browser
@@ -558,7 +561,7 @@ function parseLoginArguments(argv) {
558
561
  strict: true,
559
562
  options: {
560
563
  origin: { type: "string" },
561
- "env-file": { type: "string" },
564
+ ...envFileOptions,
562
565
  keys: { type: "string" },
563
566
  "no-browser": { type: "boolean", default: false },
564
567
  force: { type: "boolean", default: false },
@@ -591,8 +594,10 @@ export async function runLoginCommand(argv, io = {}) {
591
594
  return code;
592
595
  };
593
596
  let parsed;
597
+ let envFileOption;
594
598
  try {
595
599
  parsed = parseLoginArguments(argv);
600
+ envFileOption = envFileArgument(parsed.values, cwd);
596
601
  }
597
602
  catch (error) {
598
603
  return fail(`${error.message}\n\n${LOGIN_USAGE}`, 2);
@@ -615,7 +620,7 @@ export async function runLoginCommand(argv, io = {}) {
615
620
  if (!origin)
616
621
  return fail("--origin must be an HTTPS origin such as https://app.hue.run (plain HTTP is accepted for loopback test servers only).", 2);
617
622
  const mcpUrl = mcpUrlForOrigin(origin);
618
- const envPath = resolve(cwd, parsed.values["env-file"] ?? DEFAULT_ENV_FILE);
623
+ const envPath = resolve(cwd, envFileOption ?? DEFAULT_ENV_FILE);
619
624
  const envDisplay = displayPath(cwd, envPath);
620
625
  let envFile;
621
626
  try {
package/dist/client.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type Context, type Span, type Tracer } from "@opentelemetry/api";
2
2
  import { HueTransport } from "./transport.js";
3
- import type { ExportReport, FlushableLoggerProvider, FlushableTracerProvider, HueOptions, HueSpan, ModelOptions, ProjectConnection, SpanOptions, ToolOptions, VerifyTraceOptions, TraceVerification, SafeLifecycleOptions, SafeLifecycleResult } from "./types.js";
3
+ import type { ExportReport, FileRecord, FlushableLoggerProvider, FlushableTracerProvider, HueOptions, HueSpan, ModelOptions, ProjectConnection, SpanOptions, ProviderToolCallOptions, ToolOptions, VerifyTraceOptions, TraceVerification, SafeLifecycleOptions, SafeLifecycleResult } from "./types.js";
4
4
  /**
5
5
  * Attach mode: the application owns its OpenTelemetry providers and passes the transport whose
6
6
  * processors it attached to them. The client flushes these providers but never shuts them down.
@@ -75,7 +75,8 @@ export declare class HueClient {
75
75
  * `options.callId` is recorded as `gen_ai.tool.call.id`, like the Python `call_id=` keyword.
76
76
  * `options.mcp` records the MCP `initialize` `serverInfo` as `mcp.server.name` /
77
77
  * `mcp.server.version` so a generic tool name can be attributed to the server that
78
- * handled it. Pass `client.getServerVersion()`.
78
+ * handled it. Pass `client.getServerVersion()`. `mcp.provider` / `mcp.surface` record the Hue
79
+ * provider and surface as `hue.mcp.provider` / `hue.mcp.surface`.
79
80
  */
80
81
  tool<T>(name: string, input: unknown, execute: () => Promise<T> | T, options?: ToolOptions): Promise<T>;
81
82
  /**
@@ -84,7 +85,8 @@ export declare class HueClient {
84
85
  * `gen_ai.request.model` and `gen_ai.provider.name`. The argument order matches `withSpan`. The
85
86
  * handle's `setInput`/`setOutput` record `gen_ai.input.messages` / `gen_ai.output.messages`,
86
87
  * which should use the GenAI semantic-convention message shape; `recordMessages` inside the
87
- * callback inherits the request metadata.
88
+ * callback inherits the request metadata. `options.systemInstructions` and `options.tools` are
89
+ * recorded as `gen_ai.system_instructions` and `gen_ai.tool.definitions`, content like `input`.
88
90
  */
89
91
  model<T>(model: string, callback: (span: HueSpan) => Promise<T> | T, options: ModelOptions): Promise<T>;
90
92
  private setUsage;
@@ -113,6 +115,8 @@ export declare class HueClient {
113
115
  input?: unknown;
114
116
  /** Output messages, ideally in the GenAI semantic-convention shape; any JSON-encodable value. */
115
117
  output?: unknown;
118
+ /** System instructions sent separately from the messages, as `gen_ai.system_instructions`. */
119
+ systemInstructions?: unknown;
116
120
  /** `gen_ai.operation.name` for the record; defaults to the enclosing `model()` span's value. */
117
121
  operation?: string;
118
122
  /** `gen_ai.provider.name` for the record; defaults to the enclosing `model()` span's value. */
@@ -120,6 +124,30 @@ export declare class HueClient {
120
124
  /** `gen_ai.request.model` for the record; defaults to the enclosing `model()` span's value. */
121
125
  model?: string;
122
126
  }, explicitContext?: Context): void;
127
+ /**
128
+ * Records the tools a model provider executed itself while producing `response`, which no
129
+ * `hue.tool()` call saw: OpenAI Responses `mcp_call`, `web_search_call`, `file_search_call` and
130
+ * `code_interpreter_call` items, and Anthropic Messages `mcp_tool_use` / `server_tool_use`
131
+ * blocks with their result blocks. Each becomes an `execute_tool {name}` child span of the active
132
+ * (or given) context with `gen_ai.tool.type` `extension` and `gen_ai.tool.call.id`; MCP calls add
133
+ * `mcp.server.name` (the provider's label, or the `servers` entry for it). Arguments and results
134
+ * follow `captureContent`; a failed call carries `error.type` and ERROR status. An OpenAI
135
+ * `mcp_list_tools` item becomes a `tools/list` child span carrying that server's tools as
136
+ * `gen_ai.tool.definitions`. Call it inside `hue.model()` so the spans nest under the model call
137
+ * and `provider` defaults to its provider; pass `request` to record each server's host as
138
+ * `server.address`. The spans have no duration of their own: the provider ran the tools inside
139
+ * the model request. Unreadable items are skipped and counted; nothing is thrown.
140
+ */
141
+ recordProviderToolCalls(response: unknown, options?: ProviderToolCallOptions): void;
142
+ /**
143
+ * Adds a `hue.file` event to the active (or given) span for a file the work read, received or
144
+ * produced: `hue.file.sha256`, `hue.file.role`, `hue.file.media_type`, `hue.file.size` when known
145
+ * and, when `captureContent` is true, `hue.file.name`. `data` is hashed and measured locally and
146
+ * never exported. The event is metadata, so it is recorded in both capture modes. An invalid
147
+ * record, or one without an active span, is omitted and counted, never thrown; an invalid name
148
+ * alone is omitted and counted while the rest is recorded.
149
+ */
150
+ recordFile(file: FileRecord, explicitContext?: Context): void;
123
151
  private setContent;
124
152
  /**
125
153
  * Confirms the key and origin by reading the current project; a setup and CI diagnostic, not a