netra-sdk 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -15081,7 +15081,8 @@ var DEFAULT_INSTRUMENTS_FOR_ROOT = /* @__PURE__ */ new Set([
15081
15081
  // AI frameworks
15082
15082
  "langchain" /* LANGCHAIN */,
15083
15083
  "langgraph" /* LANGGRAPH */,
15084
- "llama_index" /* LLAMA_INDEX */
15084
+ "llama_index" /* LLAMA_INDEX */,
15085
+ "openai_agents" /* OPENAI_AGENTS */
15085
15086
  ]);
15086
15087
  var DEFAULT_INSTRUMENTS = /* @__PURE__ */ new Set([
15087
15088
  ...DEFAULT_INSTRUMENTS_FOR_ROOT,
@@ -18097,6 +18098,13 @@ var SpanAttributes2 = {
18097
18098
  };
18098
18099
 
18099
18100
  // src/instrumentation/utils.ts
18101
+ var VALID_NATIVE_TRACING_MODES = /* @__PURE__ */ new Set(["both", "netra", "netra-strict"]);
18102
+ function parseNativeTracingEnv(name) {
18103
+ const val = process.env[name];
18104
+ if (val === void 0 || val === "") return void 0;
18105
+ if (VALID_NATIVE_TRACING_MODES.has(val)) return val;
18106
+ return void 0;
18107
+ }
18100
18108
  var SUPPRESS_INSTRUMENTATION_KEY = /* @__PURE__ */ Symbol("netra.suppress_instrumentation");
18101
18109
  function shouldSuppressInstrumentation() {
18102
18110
  const ctx = api.context.active();
@@ -23603,6 +23611,8 @@ var cachedAgentsModule = null;
23603
23611
  var isInstrumented6 = false;
23604
23612
  var activeTracer = null;
23605
23613
  var activeProcessor = null;
23614
+ var originalProcessors = null;
23615
+ var didReplaceProcessors = false;
23606
23616
  async function resolveAgentsModule() {
23607
23617
  if (cachedAgentsModule) return cachedAgentsModule;
23608
23618
  try {
@@ -23655,20 +23665,51 @@ var NetraOpenAIAgentsInstrumentor = class {
23655
23665
  }
23656
23666
  const systemName = options.systemName ?? DEFAULT_LLM_SYSTEM;
23657
23667
  activeProcessor = new NetraAgentsTracingProcessor(activeTracer, systemName);
23668
+ const mode = options.nativeTracing ?? parseNativeTracingEnv("NATIVE_TRACING_MODE") ?? "netra-strict";
23669
+ const canSet = typeof agentsModule.setTraceProcessors === "function";
23670
+ const canAdd = typeof agentsModule.addTraceProcessor === "function";
23671
+ let strategy;
23672
+ if (mode === "both" || mode === "netra" && !canSet) {
23673
+ strategy = "append";
23674
+ } else if (canSet) {
23675
+ strategy = "replace";
23676
+ } else {
23677
+ strategy = "skip";
23678
+ }
23658
23679
  try {
23659
- if (typeof agentsModule.addTraceProcessor === "function") {
23660
- agentsModule.addTraceProcessor(activeProcessor);
23661
- } else if (typeof agentsModule.setTraceProcessors === "function") {
23662
- const existing = typeof agentsModule.getTraceProcessors === "function" ? agentsModule.getTraceProcessors() : [];
23663
- agentsModule.setTraceProcessors([...existing, activeProcessor]);
23664
- } else {
23665
- Logger.warn(
23666
- "OpenAI Agents SDK does not expose addTraceProcessor or setTraceProcessors.",
23667
- "Tracing integration may not work."
23668
- );
23669
- activeProcessor = null;
23670
- activeTracer = null;
23671
- return this;
23680
+ switch (strategy) {
23681
+ case "replace":
23682
+ if (typeof agentsModule.getTraceProcessors === "function") {
23683
+ originalProcessors = agentsModule.getTraceProcessors();
23684
+ }
23685
+ agentsModule.setTraceProcessors([activeProcessor]);
23686
+ didReplaceProcessors = true;
23687
+ Logger.debug("OpenAI Agents native tracing disabled \u2014 traces will only be sent to Netra.");
23688
+ break;
23689
+ case "append":
23690
+ if (canAdd) {
23691
+ agentsModule.addTraceProcessor(activeProcessor);
23692
+ } else {
23693
+ Logger.warn("OpenAI Agents SDK does not expose addTraceProcessor or setTraceProcessors.");
23694
+ activeProcessor = null;
23695
+ activeTracer = null;
23696
+ return this;
23697
+ }
23698
+ if (mode === "netra") {
23699
+ Logger.warn(
23700
+ "Cannot exclusively replace native trace processors in this @openai/agents version.",
23701
+ "Traces may still be sent to OpenAI."
23702
+ );
23703
+ }
23704
+ break;
23705
+ case "skip":
23706
+ Logger.warn(
23707
+ 'nativeTracing is "netra-strict" but the installed @openai/agents version',
23708
+ "does not support processor replacement. Skipping instrumentation."
23709
+ );
23710
+ activeProcessor = null;
23711
+ activeTracer = null;
23712
+ return this;
23672
23713
  }
23673
23714
  } catch (error) {
23674
23715
  Logger.warn("Failed to register trace processor with @openai/agents:", error);
@@ -23688,6 +23729,21 @@ var NetraOpenAIAgentsInstrumentor = class {
23688
23729
  activeProcessor.shutdown();
23689
23730
  activeProcessor = null;
23690
23731
  }
23732
+ if (didReplaceProcessors && cachedAgentsModule) {
23733
+ try {
23734
+ if (originalProcessors && typeof cachedAgentsModule.setTraceProcessors === "function") {
23735
+ cachedAgentsModule.setTraceProcessors(originalProcessors);
23736
+ Logger.debug("Restored original OpenAI Agents trace processors");
23737
+ } else if (typeof cachedAgentsModule.setDefaultOpenAITracingExporter === "function") {
23738
+ cachedAgentsModule.setDefaultOpenAITracingExporter();
23739
+ Logger.debug("Restored default OpenAI Agents tracing exporter");
23740
+ }
23741
+ } catch (error) {
23742
+ Logger.debug("Failed to restore original trace processors:", error);
23743
+ }
23744
+ }
23745
+ originalProcessors = null;
23746
+ didReplaceProcessors = false;
23691
23747
  activeTracer = null;
23692
23748
  cachedAgentsModule = null;
23693
23749
  isInstrumented6 = false;
@@ -24570,7 +24626,9 @@ function initInstrumentations(config2, instruments, blockInstruments, rootInstru
24570
24626
  mistral: false,
24571
24627
  langgraph: false,
24572
24628
  googleGenAI: false,
24573
- anthropic: false};
24629
+ anthropic: false,
24630
+ openAiAgents: false
24631
+ };
24574
24632
  const resolved = enableAll ? new Set(Object.values(NetraInstruments).filter((v) => v !== "__all__" /* ALL */)) : instruments && instruments.size > 0 ? instruments : DEFAULT_INSTRUMENTS;
24575
24633
  instrumentModules.google_vertexai = false;
24576
24634
  instrumentModules.langchain = false;
@@ -24618,6 +24676,9 @@ function initInstrumentations(config2, instruments, blockInstruments, rootInstru
24618
24676
  if (resolved.has("anthropic" /* ANTHROPIC */)) {
24619
24677
  customInstrumentModules.anthropic = true;
24620
24678
  }
24679
+ if (resolved.has("openai_agents" /* OPENAI_AGENTS */)) {
24680
+ customInstrumentModules.openAiAgents = true;
24681
+ }
24621
24682
  if (blockInstruments && blockInstruments.size > 0) {
24622
24683
  const blockAll = blockInstruments.has("__all__" /* ALL */);
24623
24684
  if (blockAll || blockInstruments.has("openai" /* OPENAI */)) customInstrumentModules.openai = false;
@@ -24626,6 +24687,7 @@ function initInstrumentations(config2, instruments, blockInstruments, rootInstru
24626
24687
  if (blockAll || blockInstruments.has("langgraph" /* LANGGRAPH */)) customInstrumentModules.langgraph = false;
24627
24688
  if (blockAll || blockInstruments.has("google_genai" /* GOOGLE_GENERATIVE_AI */)) customInstrumentModules.googleGenAI = false;
24628
24689
  if (blockAll || blockInstruments.has("anthropic" /* ANTHROPIC */)) customInstrumentModules.anthropic = false;
24690
+ if (blockAll || blockInstruments.has("openai_agents" /* OPENAI_AGENTS */)) customInstrumentModules.openAiAgents = false;
24629
24691
  if (blockAll || blockInstruments.has("vertexai" /* VERTEX_AI */)) instrumentModules.google_vertexai = false;
24630
24692
  if (blockAll || blockInstruments.has("langchain" /* LANGCHAIN */)) instrumentModules.langchain = false;
24631
24693
  if (blockAll || blockInstruments.has("llama_index" /* LLAMA_INDEX */)) instrumentModules.llamaIndex = false;
@@ -24748,7 +24810,7 @@ async function initCustomInstrumentationsAsync(config2, tracerProvider, customIn
24748
24810
  Logger.debug("Failed to initialize custom Anthropic instrumentation:", e);
24749
24811
  }
24750
24812
  }
24751
- if (customInstrumentModules.openaiAgents && !blockInstruments?.has("openai_agents" /* OPENAI_AGENTS */)) {
24813
+ if (customInstrumentModules.openAiAgents && !blockInstruments?.has("openai_agents" /* OPENAI_AGENTS */)) {
24752
24814
  try {
24753
24815
  await openaiAgentsInstrumentor.instrument({ tracerProvider });
24754
24816
  Logger.debug("Custom OpenAI Agents SDK instrumentation enabled");
@@ -24997,7 +25059,130 @@ async function uninstrumentAll() {
24997
25059
  Logger.debug("Failed to uninstrument undici:", e);
24998
25060
  }
24999
25061
  }
25062
+
25063
+ // src/simulation/task.ts
25064
+ var BaseTask = class {
25065
+ };
25066
+
25067
+ // src/simulation/utils.ts
25000
25068
  var LOG_PREFIX = "netra.simulation";
25069
+ var DEFAULT_FILE_DOWNLOAD_TIMEOUT_S = 30;
25070
+ var MAX_FILE_DOWNLOAD_WORKERS = 8;
25071
+ var _cachedFileDownloadTimeoutMs = null;
25072
+ function validateSimulationInputs(datasetId, task2) {
25073
+ if (!datasetId) {
25074
+ Logger.error(`${LOG_PREFIX}: dataset_id is required`);
25075
+ return false;
25076
+ }
25077
+ if (!(task2 instanceof BaseTask)) {
25078
+ Logger.error(`${LOG_PREFIX}: task must be a BaseTask instance`);
25079
+ return false;
25080
+ }
25081
+ return true;
25082
+ }
25083
+ function _getFileDownloadTimeout() {
25084
+ if (_cachedFileDownloadTimeoutMs !== null) {
25085
+ return _cachedFileDownloadTimeoutMs;
25086
+ }
25087
+ const envVal = process.env.NETRA_SIMULATION_FILE_DOWNLOAD_TIMEOUT;
25088
+ if (envVal) {
25089
+ const parsed = parseFloat(envVal);
25090
+ if (!isNaN(parsed) && parsed > 0) {
25091
+ _cachedFileDownloadTimeoutMs = parsed * 1e3;
25092
+ return _cachedFileDownloadTimeoutMs;
25093
+ }
25094
+ Logger.warn(
25095
+ `${LOG_PREFIX}: Invalid file download timeout '${envVal}', using default ${DEFAULT_FILE_DOWNLOAD_TIMEOUT_S}s`
25096
+ );
25097
+ }
25098
+ _cachedFileDownloadTimeoutMs = DEFAULT_FILE_DOWNLOAD_TIMEOUT_S * 1e3;
25099
+ return _cachedFileDownloadTimeoutMs;
25100
+ }
25101
+ async function _downloadSingleFile(fileData, timeoutMs, signal) {
25102
+ try {
25103
+ const response = await axios__default.default.get(fileData.downloadUrl, {
25104
+ responseType: "arraybuffer",
25105
+ timeout: timeoutMs,
25106
+ signal
25107
+ });
25108
+ const encoded = Buffer.from(response.data).toString("base64");
25109
+ return {
25110
+ fileName: fileData.fileName,
25111
+ contentType: fileData.contentType,
25112
+ description: fileData.description,
25113
+ data: encoded
25114
+ };
25115
+ } catch (error) {
25116
+ if (axios__default.default.isCancel(error)) {
25117
+ throw new Error(
25118
+ `Download of '${fileData.fileName}' was cancelled`
25119
+ );
25120
+ }
25121
+ const status = axios__default.default.isAxiosError(error) ? error.response?.status : void 0;
25122
+ const reason = status ? `HTTP ${status}` : error instanceof Error ? error.message : String(error);
25123
+ Logger.error(
25124
+ `${LOG_PREFIX}: Failed to download file '${fileData.fileName}': ${reason}`
25125
+ );
25126
+ throw new Error(
25127
+ `Failed to download file '${fileData.fileName}': ${reason}`
25128
+ );
25129
+ }
25130
+ }
25131
+ function parseFiles(rawFiles) {
25132
+ if (!rawFiles) {
25133
+ return [];
25134
+ }
25135
+ const parsed = [];
25136
+ for (const entry of rawFiles) {
25137
+ const fileName = entry.fileName || "";
25138
+ const downloadUrl = entry.downloadUrl || "";
25139
+ if (!fileName || !downloadUrl) {
25140
+ Logger.warn(
25141
+ `${LOG_PREFIX}: Skipping malformed file attachment (missing fileName or downloadUrl)`
25142
+ );
25143
+ continue;
25144
+ }
25145
+ parsed.push({
25146
+ fileName,
25147
+ contentType: entry.contentType || "",
25148
+ description: entry.description || void 0,
25149
+ downloadUrl
25150
+ });
25151
+ }
25152
+ return parsed;
25153
+ }
25154
+ async function processFiles(files) {
25155
+ if (!files || files.length === 0) {
25156
+ return null;
25157
+ }
25158
+ const timeoutMs = _getFileDownloadTimeout();
25159
+ const limit = pLimit__default.default(MAX_FILE_DOWNLOAD_WORKERS);
25160
+ const controller = new AbortController();
25161
+ const downloadPromises = files.map(
25162
+ (file) => limit(() => _downloadSingleFile(file, timeoutMs, controller.signal))
25163
+ );
25164
+ try {
25165
+ return await Promise.all(downloadPromises);
25166
+ } catch (error) {
25167
+ controller.abort();
25168
+ limit.clearQueue();
25169
+ throw error;
25170
+ }
25171
+ }
25172
+ async function executeTask2(task2, message, sessionId, rawFiles) {
25173
+ const processedFiles = rawFiles && rawFiles.length > 0 ? await processFiles(rawFiles) : null;
25174
+ const result = task2.run(message, sessionId, processedFiles);
25175
+ const resolvedResult = result instanceof Promise ? await result : result;
25176
+ if (typeof resolvedResult === "object" && resolvedResult !== null && "message" in resolvedResult && "sessionId" in resolvedResult) {
25177
+ return [resolvedResult.message, resolvedResult.sessionId];
25178
+ }
25179
+ throw new Error(
25180
+ `Task must return TaskResult, got ${typeof resolvedResult}`
25181
+ );
25182
+ }
25183
+
25184
+ // src/simulation/client.ts
25185
+ var LOG_PREFIX2 = "netra.simulation";
25001
25186
  var DEFAULT_TIMEOUT = 1e4;
25002
25187
  var SimulationHttpClient = class {
25003
25188
  constructor(config2) {
@@ -25010,7 +25195,7 @@ var SimulationHttpClient = class {
25010
25195
  _createClient(config2) {
25011
25196
  const endpoint = (config2.otlpEndpoint || "").trim();
25012
25197
  if (!endpoint) {
25013
- Logger.error(`${LOG_PREFIX}: NETRA_OTLP_ENDPOINT is required`);
25198
+ Logger.error(`${LOG_PREFIX2}: NETRA_OTLP_ENDPOINT is required`);
25014
25199
  return null;
25015
25200
  }
25016
25201
  const baseURL = this._resolveBaseUrl(endpoint);
@@ -25032,7 +25217,7 @@ var SimulationHttpClient = class {
25032
25217
  );
25033
25218
  return instance;
25034
25219
  } catch (error) {
25035
- Logger.error(`${LOG_PREFIX}: Failed to create HTTP client:`, error);
25220
+ Logger.error(`${LOG_PREFIX2}: Failed to create HTTP client:`, error);
25036
25221
  return null;
25037
25222
  }
25038
25223
  }
@@ -25067,7 +25252,7 @@ var SimulationHttpClient = class {
25067
25252
  const timeout = parseFloat(timeoutStr);
25068
25253
  if (isNaN(timeout)) {
25069
25254
  Logger.warn(
25070
- `${LOG_PREFIX}: Invalid timeout '${timeoutStr}', using default ${DEFAULT_TIMEOUT}ms`
25255
+ `${LOG_PREFIX2}: Invalid timeout '${timeoutStr}', using default ${DEFAULT_TIMEOUT}ms`
25071
25256
  );
25072
25257
  return DEFAULT_TIMEOUT;
25073
25258
  }
@@ -25078,7 +25263,7 @@ var SimulationHttpClient = class {
25078
25263
  */
25079
25264
  async createRun(name, datasetId, context17) {
25080
25265
  if (!this.client) {
25081
- Logger.error(`${LOG_PREFIX}: Client not initialized`);
25266
+ Logger.error(`${LOG_PREFIX2}: Client not initialized`);
25082
25267
  return null;
25083
25268
  }
25084
25269
  try {
@@ -25093,7 +25278,7 @@ var SimulationHttpClient = class {
25093
25278
  const responseData = data.data || {};
25094
25279
  const userMessages = responseData.userMessages || [];
25095
25280
  if (userMessages.length === 0) {
25096
- Logger.warn(`${LOG_PREFIX}: No user messages returned from create_run`);
25281
+ Logger.warn(`${LOG_PREFIX2}: No user messages returned from create_run`);
25097
25282
  return null;
25098
25283
  }
25099
25284
  const runId = responseData.id || "";
@@ -25101,7 +25286,8 @@ var SimulationHttpClient = class {
25101
25286
  (msg) => ({
25102
25287
  runItemId: msg.testRunItemId || "",
25103
25288
  message: msg.userMessage || "",
25104
- turnId: msg.turnId || ""
25289
+ turnId: msg.turnId || "",
25290
+ files: parseFiles(msg.attachments)
25105
25291
  })
25106
25292
  );
25107
25293
  return {
@@ -25110,7 +25296,7 @@ var SimulationHttpClient = class {
25110
25296
  };
25111
25297
  } catch (error) {
25112
25298
  const errorMsg = this._extractErrorMessage(error);
25113
- Logger.error(`${LOG_PREFIX}: Failed to create simulation run:`, errorMsg);
25299
+ Logger.error(`${LOG_PREFIX2}: Failed to create simulation run:`, errorMsg);
25114
25300
  return null;
25115
25301
  }
25116
25302
  }
@@ -25119,7 +25305,7 @@ var SimulationHttpClient = class {
25119
25305
  */
25120
25306
  async triggerConversation(message, turnId, sessionId, traceId) {
25121
25307
  if (!this.client) {
25122
- Logger.error(`${LOG_PREFIX}: Client not initialized`);
25308
+ Logger.error(`${LOG_PREFIX2}: Client not initialized`);
25123
25309
  return null;
25124
25310
  }
25125
25311
  try {
@@ -25142,7 +25328,7 @@ var SimulationHttpClient = class {
25142
25328
  }
25143
25329
  const userMessages = responseData.userMessages || [];
25144
25330
  if (userMessages.length === 0) {
25145
- Logger.warn(`${LOG_PREFIX}: No user messages in continue response`);
25331
+ Logger.warn(`${LOG_PREFIX2}: No user messages in continue response`);
25146
25332
  return null;
25147
25333
  }
25148
25334
  const nextMsg = userMessages[0];
@@ -25150,11 +25336,12 @@ var SimulationHttpClient = class {
25150
25336
  decision,
25151
25337
  nextTurnId: nextMsg.turnId || "",
25152
25338
  nextUserMessage: nextMsg.userMessage || "",
25153
- nextRunItemId: nextMsg.testRunItemId || ""
25339
+ nextRunItemId: nextMsg.testRunItemId || "",
25340
+ nextFiles: parseFiles(nextMsg.attachments)
25154
25341
  };
25155
25342
  } catch (error) {
25156
25343
  const errorMsg = this._extractErrorMessage(error);
25157
- Logger.error(`${LOG_PREFIX}: Failed to trigger conversation:`, errorMsg);
25344
+ Logger.error(`${LOG_PREFIX2}: Failed to trigger conversation:`, errorMsg);
25158
25345
  return null;
25159
25346
  }
25160
25347
  }
@@ -25163,17 +25350,17 @@ var SimulationHttpClient = class {
25163
25350
  */
25164
25351
  async reportFailure(runId, runItemId, error) {
25165
25352
  if (!this.client) {
25166
- Logger.error(`${LOG_PREFIX}: Client not initialized`);
25353
+ Logger.error(`${LOG_PREFIX2}: Client not initialized`);
25167
25354
  return;
25168
25355
  }
25169
25356
  try {
25170
25357
  const url = `/evaluations/run/${runId}/item/${runItemId}/status`;
25171
25358
  const payload = { status: "failed", failureReason: error };
25172
25359
  await this.client.patch(url, payload);
25173
- Logger.info(`${LOG_PREFIX}: Reported failure - ${error}`);
25360
+ Logger.info(`${LOG_PREFIX2}: Reported failure - ${error}`);
25174
25361
  } catch (err) {
25175
25362
  const errorMsg = this._extractErrorMessage(err);
25176
- Logger.error(`${LOG_PREFIX}: Failed to report failure:`, errorMsg);
25363
+ Logger.error(`${LOG_PREFIX2}: Failed to report failure:`, errorMsg);
25177
25364
  }
25178
25365
  }
25179
25366
  /**
@@ -25182,7 +25369,7 @@ var SimulationHttpClient = class {
25182
25369
  async postRunStatus(runId, status) {
25183
25370
  if (!this.client) {
25184
25371
  Logger.error(
25185
- `${LOG_PREFIX}: Client not initialized; cannot post run status`
25372
+ `${LOG_PREFIX2}: Client not initialized; cannot post run status`
25186
25373
  );
25187
25374
  return { success: false };
25188
25375
  }
@@ -25192,14 +25379,14 @@ var SimulationHttpClient = class {
25192
25379
  const response = await this.client.post(url, payload);
25193
25380
  const data = response.data;
25194
25381
  if (data && typeof data === "object" && "data" in data) {
25195
- Logger.info(`${LOG_PREFIX}: Completed test run successfully`);
25382
+ Logger.info(`${LOG_PREFIX2}: Completed test run successfully`);
25196
25383
  return data.data || {};
25197
25384
  }
25198
25385
  return data;
25199
25386
  } catch (error) {
25200
25387
  const errorMsg = this._extractErrorMessage(error);
25201
25388
  Logger.error(
25202
- `${LOG_PREFIX}: Failed to post run status for run '${runId}':`,
25389
+ `${LOG_PREFIX2}: Failed to post run status for run '${runId}':`,
25203
25390
  errorMsg
25204
25391
  );
25205
25392
  return { success: false };
@@ -25223,34 +25410,6 @@ var SimulationHttpClient = class {
25223
25410
  }
25224
25411
  };
25225
25412
 
25226
- // src/simulation/task.ts
25227
- var BaseTask = class {
25228
- };
25229
-
25230
- // src/simulation/utils.ts
25231
- var LOG_PREFIX2 = "netra.simulation";
25232
- function validateSimulationInputs(datasetId, task2) {
25233
- if (!datasetId) {
25234
- Logger.error(`${LOG_PREFIX2}: dataset_id is required`);
25235
- return false;
25236
- }
25237
- if (!(task2 instanceof BaseTask)) {
25238
- Logger.error(`${LOG_PREFIX2}: task must be a BaseTask instance`);
25239
- return false;
25240
- }
25241
- return true;
25242
- }
25243
- async function executeTask2(task2, message, sessionId) {
25244
- const result = task2.run(message, sessionId);
25245
- const resolvedResult = result instanceof Promise ? await result : result;
25246
- if (typeof resolvedResult === "object" && resolvedResult !== null && "message" in resolvedResult && "sessionId" in resolvedResult) {
25247
- return [resolvedResult.message, resolvedResult.sessionId];
25248
- }
25249
- throw new Error(
25250
- `Task must return TaskResult, got ${typeof resolvedResult}`
25251
- );
25252
- }
25253
-
25254
25413
  // src/simulation/api.ts
25255
25414
  var LOG_PREFIX3 = "netra.simulation";
25256
25415
  var SPAN_NAME = "Netra.Simulation.TestRun";
@@ -25384,17 +25543,18 @@ var Simulation = class {
25384
25543
  * Execute a multi-turn conversation for a single simulation item.
25385
25544
  */
25386
25545
  async _executeConversation(runId, runItem, task2) {
25387
- const { runItemId, message: initialMessage, turnId: initialTurnId } = runItem;
25546
+ const { runItemId, message: initialMessage, turnId: initialTurnId, files: initialFiles } = runItem;
25388
25547
  let message = initialMessage;
25389
25548
  let turnId = initialTurnId;
25390
25549
  let sessionId = null;
25550
+ let rawFiles = initialFiles ?? [];
25391
25551
  while (true) {
25392
25552
  const span2 = new SpanWrapper(SPAN_NAME, {}, LOG_PREFIX3);
25393
25553
  span2.start();
25394
25554
  try {
25395
25555
  const traceId = span2.getCurrentSpan()?.spanContext().traceId ?? "";
25396
25556
  const [responseMessage, taskSessionId] = await span2.withActive(
25397
- () => executeTask2(task2, message, sessionId)
25557
+ () => executeTask2(task2, message, sessionId, rawFiles)
25398
25558
  );
25399
25559
  if (taskSessionId) {
25400
25560
  sessionId = taskSessionId;
@@ -25428,6 +25588,7 @@ var Simulation = class {
25428
25588
  }
25429
25589
  message = response.nextUserMessage;
25430
25590
  turnId = response.nextTurnId;
25591
+ rawFiles = response.nextFiles || [];
25431
25592
  } catch (error) {
25432
25593
  const errorMsg = error instanceof Error ? error.message : String(error);
25433
25594
  Logger.error(