netra-sdk 1.1.0 → 1.2.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.d.cts CHANGED
@@ -1061,6 +1061,32 @@ interface DecoratorOptions {
1061
1061
  }
1062
1062
  type SpanCallback<T> = (span: SpanWrapper) => T;
1063
1063
 
1064
+ /**
1065
+ * Raw file metadata received from the backend.
1066
+ *
1067
+ * Contains a pre-signed download URL that the SDK uses to fetch the actual
1068
+ * file content. Instances are produced by parsing the `attachments` array
1069
+ * returned on each user message from the simulation API.
1070
+ */
1071
+ interface FileData {
1072
+ fileName: string;
1073
+ contentType: string;
1074
+ description?: string;
1075
+ downloadUrl: string;
1076
+ }
1077
+ /**
1078
+ * File after download and base64 encoding, delivered to the user task.
1079
+ *
1080
+ * The `data` field contains the raw file bytes encoded as a base64 ASCII
1081
+ * string. Consumers should decode with `Buffer.from(data, "base64")` before
1082
+ * passing to an LLM or other downstream system.
1083
+ */
1084
+ interface ProcessedFile {
1085
+ fileName: string;
1086
+ contentType: string;
1087
+ description?: string;
1088
+ data: string;
1089
+ }
1064
1090
  /**
1065
1091
  * Represents a single item in a simulation run.
1066
1092
  */
@@ -1068,6 +1094,7 @@ interface SimulationItem {
1068
1094
  runItemId: string;
1069
1095
  message: string;
1070
1096
  turnId: string;
1097
+ files?: FileData[];
1071
1098
  }
1072
1099
  /**
1073
1100
  * Response from the conversation trigger API.
@@ -1078,6 +1105,7 @@ interface ConversationResponse {
1078
1105
  nextTurnId?: string;
1079
1106
  nextUserMessage?: string;
1080
1107
  nextRunItemId?: string;
1108
+ nextFiles?: FileData[];
1081
1109
  }
1082
1110
  /**
1083
1111
  * Result returned from the user's task function.
@@ -1108,13 +1136,17 @@ interface SimulationResult {
1108
1136
 
1109
1137
  declare abstract class BaseTask {
1110
1138
  /**
1139
+ * Process a simulation turn and return the agent's response.
1140
+ *
1111
1141
  * @param message - The input message from the simulation.
1112
- * @param sessionId - The Session identifier.
1142
+ * @param sessionId - The session identifier.
1143
+ * @param files - Optional list of base64-encoded file attachments from the
1144
+ * dataset item. Will be `null` when no files are attached.
1113
1145
  * @returns The task result containing:
1114
1146
  * - message (string): The response message from the task.
1115
1147
  * - sessionId (string): The session identifier.
1116
1148
  */
1117
- abstract run(message: string, sessionId?: string | null): Promise<TaskResult> | TaskResult;
1149
+ abstract run(message: string, sessionId?: string | null, files?: ProcessedFile[] | null): Promise<TaskResult> | TaskResult;
1118
1150
  }
1119
1151
 
1120
1152
  /**
@@ -1528,4 +1560,4 @@ declare class Netra {
1528
1560
  static withBlockedSpansLocal: typeof withBlockedSpansLocal;
1529
1561
  }
1530
1562
 
1531
- export { type ActionModel, Aggregation, BaseTask, type CategoricalDataPoint, ChartType, Config, type ConversationResponse, type ConversationResult, ConversationType, type CreateDatasetParams, type CreateRunResult, DEFAULT_INSTRUMENTS, DEFAULT_INSTRUMENTS_FOR_ROOT, Dashboard, type DashboardData, type Dataset, type DatasetEntry, type DatasetItem, type Dimension, DimensionField, type DimensionValue, EntryStatus, Evaluation, type EvaluationScore, type EvaluatorFunction, type Filter, type FilterConfig, FilterField, FilterType, FilteringSpanExporter, type GetPromptParams, GroupBy, InstrumentationSpanProcessor, type ListSpansParams, type ListTracesParams, Measure, type Metrics, Netra, NetraAgentsTracingProcessor, NetraInstruments, NetraOpenAIAgentsInstrumentor, type NumberResponse, Operator, type PromptResponse, Prompts, type QueryDataParams, type QueryResponse, type Run, RunEntryContext, RunStatus, Scope, ScrubbingSpanProcessor, SessionSpanProcessor, type SessionUsageData, Simulation, type SimulationItem, type SimulationOptions, type SimulationResult, SpanIOProcessor, type SpanOptions, SpanType, type SpansPage, type TaskFunction, type TaskResult, type TenantUsageData, type TestSuiteResult, type TimeRange, type TimeSeriesDataPoint, type TimeSeriesResponse, type TimeSeriesWithDimension, type TraceSpan, type TraceSummary, type TracesPage, TrialAwareOTLPExporter, Usage, type UsageModel, agent, Netra as default, metadataField, mistralAIInstrumentor, netraExpressMiddleware, openaiAgentsInstrumentor, runWithExtractedContext, span, task, workflow };
1563
+ export { type ActionModel, Aggregation, BaseTask, type CategoricalDataPoint, ChartType, Config, type ConversationResponse, type ConversationResult, ConversationType, type CreateDatasetParams, type CreateRunResult, DEFAULT_INSTRUMENTS, DEFAULT_INSTRUMENTS_FOR_ROOT, Dashboard, type DashboardData, type Dataset, type DatasetEntry, type DatasetItem, type Dimension, DimensionField, type DimensionValue, EntryStatus, Evaluation, type EvaluationScore, type EvaluatorFunction, type Filter, type FilterConfig, FilterField, FilterType, FilteringSpanExporter, type GetPromptParams, GroupBy, InstrumentationSpanProcessor, type ListSpansParams, type ListTracesParams, Measure, type Metrics, Netra, NetraAgentsTracingProcessor, NetraInstruments, NetraOpenAIAgentsInstrumentor, type NumberResponse, Operator, type ProcessedFile, type PromptResponse, Prompts, type QueryDataParams, type QueryResponse, type Run, RunEntryContext, RunStatus, Scope, ScrubbingSpanProcessor, SessionSpanProcessor, type SessionUsageData, Simulation, type SimulationItem, type SimulationOptions, type SimulationResult, SpanIOProcessor, type SpanOptions, SpanType, type SpansPage, type TaskFunction, type TaskResult, type TenantUsageData, type TestSuiteResult, type TimeRange, type TimeSeriesDataPoint, type TimeSeriesResponse, type TimeSeriesWithDimension, type TraceSpan, type TraceSummary, type TracesPage, TrialAwareOTLPExporter, Usage, type UsageModel, agent, Netra as default, metadataField, mistralAIInstrumentor, netraExpressMiddleware, openaiAgentsInstrumentor, runWithExtractedContext, span, task, workflow };
package/dist/index.d.ts CHANGED
@@ -1061,6 +1061,32 @@ interface DecoratorOptions {
1061
1061
  }
1062
1062
  type SpanCallback<T> = (span: SpanWrapper) => T;
1063
1063
 
1064
+ /**
1065
+ * Raw file metadata received from the backend.
1066
+ *
1067
+ * Contains a pre-signed download URL that the SDK uses to fetch the actual
1068
+ * file content. Instances are produced by parsing the `attachments` array
1069
+ * returned on each user message from the simulation API.
1070
+ */
1071
+ interface FileData {
1072
+ fileName: string;
1073
+ contentType: string;
1074
+ description?: string;
1075
+ downloadUrl: string;
1076
+ }
1077
+ /**
1078
+ * File after download and base64 encoding, delivered to the user task.
1079
+ *
1080
+ * The `data` field contains the raw file bytes encoded as a base64 ASCII
1081
+ * string. Consumers should decode with `Buffer.from(data, "base64")` before
1082
+ * passing to an LLM or other downstream system.
1083
+ */
1084
+ interface ProcessedFile {
1085
+ fileName: string;
1086
+ contentType: string;
1087
+ description?: string;
1088
+ data: string;
1089
+ }
1064
1090
  /**
1065
1091
  * Represents a single item in a simulation run.
1066
1092
  */
@@ -1068,6 +1094,7 @@ interface SimulationItem {
1068
1094
  runItemId: string;
1069
1095
  message: string;
1070
1096
  turnId: string;
1097
+ files?: FileData[];
1071
1098
  }
1072
1099
  /**
1073
1100
  * Response from the conversation trigger API.
@@ -1078,6 +1105,7 @@ interface ConversationResponse {
1078
1105
  nextTurnId?: string;
1079
1106
  nextUserMessage?: string;
1080
1107
  nextRunItemId?: string;
1108
+ nextFiles?: FileData[];
1081
1109
  }
1082
1110
  /**
1083
1111
  * Result returned from the user's task function.
@@ -1108,13 +1136,17 @@ interface SimulationResult {
1108
1136
 
1109
1137
  declare abstract class BaseTask {
1110
1138
  /**
1139
+ * Process a simulation turn and return the agent's response.
1140
+ *
1111
1141
  * @param message - The input message from the simulation.
1112
- * @param sessionId - The Session identifier.
1142
+ * @param sessionId - The session identifier.
1143
+ * @param files - Optional list of base64-encoded file attachments from the
1144
+ * dataset item. Will be `null` when no files are attached.
1113
1145
  * @returns The task result containing:
1114
1146
  * - message (string): The response message from the task.
1115
1147
  * - sessionId (string): The session identifier.
1116
1148
  */
1117
- abstract run(message: string, sessionId?: string | null): Promise<TaskResult> | TaskResult;
1149
+ abstract run(message: string, sessionId?: string | null, files?: ProcessedFile[] | null): Promise<TaskResult> | TaskResult;
1118
1150
  }
1119
1151
 
1120
1152
  /**
@@ -1528,4 +1560,4 @@ declare class Netra {
1528
1560
  static withBlockedSpansLocal: typeof withBlockedSpansLocal;
1529
1561
  }
1530
1562
 
1531
- export { type ActionModel, Aggregation, BaseTask, type CategoricalDataPoint, ChartType, Config, type ConversationResponse, type ConversationResult, ConversationType, type CreateDatasetParams, type CreateRunResult, DEFAULT_INSTRUMENTS, DEFAULT_INSTRUMENTS_FOR_ROOT, Dashboard, type DashboardData, type Dataset, type DatasetEntry, type DatasetItem, type Dimension, DimensionField, type DimensionValue, EntryStatus, Evaluation, type EvaluationScore, type EvaluatorFunction, type Filter, type FilterConfig, FilterField, FilterType, FilteringSpanExporter, type GetPromptParams, GroupBy, InstrumentationSpanProcessor, type ListSpansParams, type ListTracesParams, Measure, type Metrics, Netra, NetraAgentsTracingProcessor, NetraInstruments, NetraOpenAIAgentsInstrumentor, type NumberResponse, Operator, type PromptResponse, Prompts, type QueryDataParams, type QueryResponse, type Run, RunEntryContext, RunStatus, Scope, ScrubbingSpanProcessor, SessionSpanProcessor, type SessionUsageData, Simulation, type SimulationItem, type SimulationOptions, type SimulationResult, SpanIOProcessor, type SpanOptions, SpanType, type SpansPage, type TaskFunction, type TaskResult, type TenantUsageData, type TestSuiteResult, type TimeRange, type TimeSeriesDataPoint, type TimeSeriesResponse, type TimeSeriesWithDimension, type TraceSpan, type TraceSummary, type TracesPage, TrialAwareOTLPExporter, Usage, type UsageModel, agent, Netra as default, metadataField, mistralAIInstrumentor, netraExpressMiddleware, openaiAgentsInstrumentor, runWithExtractedContext, span, task, workflow };
1563
+ export { type ActionModel, Aggregation, BaseTask, type CategoricalDataPoint, ChartType, Config, type ConversationResponse, type ConversationResult, ConversationType, type CreateDatasetParams, type CreateRunResult, DEFAULT_INSTRUMENTS, DEFAULT_INSTRUMENTS_FOR_ROOT, Dashboard, type DashboardData, type Dataset, type DatasetEntry, type DatasetItem, type Dimension, DimensionField, type DimensionValue, EntryStatus, Evaluation, type EvaluationScore, type EvaluatorFunction, type Filter, type FilterConfig, FilterField, FilterType, FilteringSpanExporter, type GetPromptParams, GroupBy, InstrumentationSpanProcessor, type ListSpansParams, type ListTracesParams, Measure, type Metrics, Netra, NetraAgentsTracingProcessor, NetraInstruments, NetraOpenAIAgentsInstrumentor, type NumberResponse, Operator, type ProcessedFile, type PromptResponse, Prompts, type QueryDataParams, type QueryResponse, type Run, RunEntryContext, RunStatus, Scope, ScrubbingSpanProcessor, SessionSpanProcessor, type SessionUsageData, Simulation, type SimulationItem, type SimulationOptions, type SimulationResult, SpanIOProcessor, type SpanOptions, SpanType, type SpansPage, type TaskFunction, type TaskResult, type TenantUsageData, type TestSuiteResult, type TimeRange, type TimeSeriesDataPoint, type TimeSeriesResponse, type TimeSeriesWithDimension, type TraceSpan, type TraceSummary, type TracesPage, TrialAwareOTLPExporter, Usage, type UsageModel, agent, Netra as default, metadataField, mistralAIInstrumentor, netraExpressMiddleware, openaiAgentsInstrumentor, runWithExtractedContext, span, task, workflow };
package/dist/index.js CHANGED
@@ -10526,7 +10526,130 @@ async function uninstrumentAll() {
10526
10526
  Logger.debug("Failed to uninstrument undici:", e);
10527
10527
  }
10528
10528
  }
10529
+
10530
+ // src/simulation/task.ts
10531
+ var BaseTask = class {
10532
+ };
10533
+
10534
+ // src/simulation/utils.ts
10529
10535
  var LOG_PREFIX = "netra.simulation";
10536
+ var DEFAULT_FILE_DOWNLOAD_TIMEOUT_S = 30;
10537
+ var MAX_FILE_DOWNLOAD_WORKERS = 8;
10538
+ var _cachedFileDownloadTimeoutMs = null;
10539
+ function validateSimulationInputs(datasetId, task2) {
10540
+ if (!datasetId) {
10541
+ Logger.error(`${LOG_PREFIX}: dataset_id is required`);
10542
+ return false;
10543
+ }
10544
+ if (!(task2 instanceof BaseTask)) {
10545
+ Logger.error(`${LOG_PREFIX}: task must be a BaseTask instance`);
10546
+ return false;
10547
+ }
10548
+ return true;
10549
+ }
10550
+ function _getFileDownloadTimeout() {
10551
+ if (_cachedFileDownloadTimeoutMs !== null) {
10552
+ return _cachedFileDownloadTimeoutMs;
10553
+ }
10554
+ const envVal = process.env.NETRA_SIMULATION_FILE_DOWNLOAD_TIMEOUT;
10555
+ if (envVal) {
10556
+ const parsed = parseFloat(envVal);
10557
+ if (!isNaN(parsed) && parsed > 0) {
10558
+ _cachedFileDownloadTimeoutMs = parsed * 1e3;
10559
+ return _cachedFileDownloadTimeoutMs;
10560
+ }
10561
+ Logger.warn(
10562
+ `${LOG_PREFIX}: Invalid file download timeout '${envVal}', using default ${DEFAULT_FILE_DOWNLOAD_TIMEOUT_S}s`
10563
+ );
10564
+ }
10565
+ _cachedFileDownloadTimeoutMs = DEFAULT_FILE_DOWNLOAD_TIMEOUT_S * 1e3;
10566
+ return _cachedFileDownloadTimeoutMs;
10567
+ }
10568
+ async function _downloadSingleFile(fileData, timeoutMs, signal) {
10569
+ try {
10570
+ const response = await axios.get(fileData.downloadUrl, {
10571
+ responseType: "arraybuffer",
10572
+ timeout: timeoutMs,
10573
+ signal
10574
+ });
10575
+ const encoded = Buffer.from(response.data).toString("base64");
10576
+ return {
10577
+ fileName: fileData.fileName,
10578
+ contentType: fileData.contentType,
10579
+ description: fileData.description,
10580
+ data: encoded
10581
+ };
10582
+ } catch (error) {
10583
+ if (axios.isCancel(error)) {
10584
+ throw new Error(
10585
+ `Download of '${fileData.fileName}' was cancelled`
10586
+ );
10587
+ }
10588
+ const status = axios.isAxiosError(error) ? error.response?.status : void 0;
10589
+ const reason = status ? `HTTP ${status}` : error instanceof Error ? error.message : String(error);
10590
+ Logger.error(
10591
+ `${LOG_PREFIX}: Failed to download file '${fileData.fileName}': ${reason}`
10592
+ );
10593
+ throw new Error(
10594
+ `Failed to download file '${fileData.fileName}': ${reason}`
10595
+ );
10596
+ }
10597
+ }
10598
+ function parseFiles(rawFiles) {
10599
+ if (!rawFiles) {
10600
+ return [];
10601
+ }
10602
+ const parsed = [];
10603
+ for (const entry of rawFiles) {
10604
+ const fileName = entry.fileName || "";
10605
+ const downloadUrl = entry.downloadUrl || "";
10606
+ if (!fileName || !downloadUrl) {
10607
+ Logger.warn(
10608
+ `${LOG_PREFIX}: Skipping malformed file attachment (missing fileName or downloadUrl)`
10609
+ );
10610
+ continue;
10611
+ }
10612
+ parsed.push({
10613
+ fileName,
10614
+ contentType: entry.contentType || "",
10615
+ description: entry.description || void 0,
10616
+ downloadUrl
10617
+ });
10618
+ }
10619
+ return parsed;
10620
+ }
10621
+ async function processFiles(files) {
10622
+ if (!files || files.length === 0) {
10623
+ return null;
10624
+ }
10625
+ const timeoutMs = _getFileDownloadTimeout();
10626
+ const limit = pLimit(MAX_FILE_DOWNLOAD_WORKERS);
10627
+ const controller = new AbortController();
10628
+ const downloadPromises = files.map(
10629
+ (file) => limit(() => _downloadSingleFile(file, timeoutMs, controller.signal))
10630
+ );
10631
+ try {
10632
+ return await Promise.all(downloadPromises);
10633
+ } catch (error) {
10634
+ controller.abort();
10635
+ limit.clearQueue();
10636
+ throw error;
10637
+ }
10638
+ }
10639
+ async function executeTask2(task2, message, sessionId, rawFiles) {
10640
+ const processedFiles = rawFiles && rawFiles.length > 0 ? await processFiles(rawFiles) : null;
10641
+ const result = task2.run(message, sessionId, processedFiles);
10642
+ const resolvedResult = result instanceof Promise ? await result : result;
10643
+ if (typeof resolvedResult === "object" && resolvedResult !== null && "message" in resolvedResult && "sessionId" in resolvedResult) {
10644
+ return [resolvedResult.message, resolvedResult.sessionId];
10645
+ }
10646
+ throw new Error(
10647
+ `Task must return TaskResult, got ${typeof resolvedResult}`
10648
+ );
10649
+ }
10650
+
10651
+ // src/simulation/client.ts
10652
+ var LOG_PREFIX2 = "netra.simulation";
10530
10653
  var DEFAULT_TIMEOUT = 1e4;
10531
10654
  var SimulationHttpClient = class {
10532
10655
  constructor(config2) {
@@ -10539,7 +10662,7 @@ var SimulationHttpClient = class {
10539
10662
  _createClient(config2) {
10540
10663
  const endpoint = (config2.otlpEndpoint || "").trim();
10541
10664
  if (!endpoint) {
10542
- Logger.error(`${LOG_PREFIX}: NETRA_OTLP_ENDPOINT is required`);
10665
+ Logger.error(`${LOG_PREFIX2}: NETRA_OTLP_ENDPOINT is required`);
10543
10666
  return null;
10544
10667
  }
10545
10668
  const baseURL = this._resolveBaseUrl(endpoint);
@@ -10561,7 +10684,7 @@ var SimulationHttpClient = class {
10561
10684
  );
10562
10685
  return instance;
10563
10686
  } catch (error) {
10564
- Logger.error(`${LOG_PREFIX}: Failed to create HTTP client:`, error);
10687
+ Logger.error(`${LOG_PREFIX2}: Failed to create HTTP client:`, error);
10565
10688
  return null;
10566
10689
  }
10567
10690
  }
@@ -10596,7 +10719,7 @@ var SimulationHttpClient = class {
10596
10719
  const timeout = parseFloat(timeoutStr);
10597
10720
  if (isNaN(timeout)) {
10598
10721
  Logger.warn(
10599
- `${LOG_PREFIX}: Invalid timeout '${timeoutStr}', using default ${DEFAULT_TIMEOUT}ms`
10722
+ `${LOG_PREFIX2}: Invalid timeout '${timeoutStr}', using default ${DEFAULT_TIMEOUT}ms`
10600
10723
  );
10601
10724
  return DEFAULT_TIMEOUT;
10602
10725
  }
@@ -10607,7 +10730,7 @@ var SimulationHttpClient = class {
10607
10730
  */
10608
10731
  async createRun(name, datasetId, context16) {
10609
10732
  if (!this.client) {
10610
- Logger.error(`${LOG_PREFIX}: Client not initialized`);
10733
+ Logger.error(`${LOG_PREFIX2}: Client not initialized`);
10611
10734
  return null;
10612
10735
  }
10613
10736
  try {
@@ -10622,7 +10745,7 @@ var SimulationHttpClient = class {
10622
10745
  const responseData = data.data || {};
10623
10746
  const userMessages = responseData.userMessages || [];
10624
10747
  if (userMessages.length === 0) {
10625
- Logger.warn(`${LOG_PREFIX}: No user messages returned from create_run`);
10748
+ Logger.warn(`${LOG_PREFIX2}: No user messages returned from create_run`);
10626
10749
  return null;
10627
10750
  }
10628
10751
  const runId = responseData.id || "";
@@ -10630,7 +10753,8 @@ var SimulationHttpClient = class {
10630
10753
  (msg) => ({
10631
10754
  runItemId: msg.testRunItemId || "",
10632
10755
  message: msg.userMessage || "",
10633
- turnId: msg.turnId || ""
10756
+ turnId: msg.turnId || "",
10757
+ files: parseFiles(msg.attachments)
10634
10758
  })
10635
10759
  );
10636
10760
  return {
@@ -10639,7 +10763,7 @@ var SimulationHttpClient = class {
10639
10763
  };
10640
10764
  } catch (error) {
10641
10765
  const errorMsg = this._extractErrorMessage(error);
10642
- Logger.error(`${LOG_PREFIX}: Failed to create simulation run:`, errorMsg);
10766
+ Logger.error(`${LOG_PREFIX2}: Failed to create simulation run:`, errorMsg);
10643
10767
  return null;
10644
10768
  }
10645
10769
  }
@@ -10648,7 +10772,7 @@ var SimulationHttpClient = class {
10648
10772
  */
10649
10773
  async triggerConversation(message, turnId, sessionId, traceId) {
10650
10774
  if (!this.client) {
10651
- Logger.error(`${LOG_PREFIX}: Client not initialized`);
10775
+ Logger.error(`${LOG_PREFIX2}: Client not initialized`);
10652
10776
  return null;
10653
10777
  }
10654
10778
  try {
@@ -10671,7 +10795,7 @@ var SimulationHttpClient = class {
10671
10795
  }
10672
10796
  const userMessages = responseData.userMessages || [];
10673
10797
  if (userMessages.length === 0) {
10674
- Logger.warn(`${LOG_PREFIX}: No user messages in continue response`);
10798
+ Logger.warn(`${LOG_PREFIX2}: No user messages in continue response`);
10675
10799
  return null;
10676
10800
  }
10677
10801
  const nextMsg = userMessages[0];
@@ -10679,11 +10803,12 @@ var SimulationHttpClient = class {
10679
10803
  decision,
10680
10804
  nextTurnId: nextMsg.turnId || "",
10681
10805
  nextUserMessage: nextMsg.userMessage || "",
10682
- nextRunItemId: nextMsg.testRunItemId || ""
10806
+ nextRunItemId: nextMsg.testRunItemId || "",
10807
+ nextFiles: parseFiles(nextMsg.attachments)
10683
10808
  };
10684
10809
  } catch (error) {
10685
10810
  const errorMsg = this._extractErrorMessage(error);
10686
- Logger.error(`${LOG_PREFIX}: Failed to trigger conversation:`, errorMsg);
10811
+ Logger.error(`${LOG_PREFIX2}: Failed to trigger conversation:`, errorMsg);
10687
10812
  return null;
10688
10813
  }
10689
10814
  }
@@ -10692,17 +10817,17 @@ var SimulationHttpClient = class {
10692
10817
  */
10693
10818
  async reportFailure(runId, runItemId, error) {
10694
10819
  if (!this.client) {
10695
- Logger.error(`${LOG_PREFIX}: Client not initialized`);
10820
+ Logger.error(`${LOG_PREFIX2}: Client not initialized`);
10696
10821
  return;
10697
10822
  }
10698
10823
  try {
10699
10824
  const url = `/evaluations/run/${runId}/item/${runItemId}/status`;
10700
10825
  const payload = { status: "failed", failureReason: error };
10701
10826
  await this.client.patch(url, payload);
10702
- Logger.info(`${LOG_PREFIX}: Reported failure - ${error}`);
10827
+ Logger.info(`${LOG_PREFIX2}: Reported failure - ${error}`);
10703
10828
  } catch (err) {
10704
10829
  const errorMsg = this._extractErrorMessage(err);
10705
- Logger.error(`${LOG_PREFIX}: Failed to report failure:`, errorMsg);
10830
+ Logger.error(`${LOG_PREFIX2}: Failed to report failure:`, errorMsg);
10706
10831
  }
10707
10832
  }
10708
10833
  /**
@@ -10711,7 +10836,7 @@ var SimulationHttpClient = class {
10711
10836
  async postRunStatus(runId, status) {
10712
10837
  if (!this.client) {
10713
10838
  Logger.error(
10714
- `${LOG_PREFIX}: Client not initialized; cannot post run status`
10839
+ `${LOG_PREFIX2}: Client not initialized; cannot post run status`
10715
10840
  );
10716
10841
  return { success: false };
10717
10842
  }
@@ -10721,14 +10846,14 @@ var SimulationHttpClient = class {
10721
10846
  const response = await this.client.post(url, payload);
10722
10847
  const data = response.data;
10723
10848
  if (data && typeof data === "object" && "data" in data) {
10724
- Logger.info(`${LOG_PREFIX}: Completed test run successfully`);
10849
+ Logger.info(`${LOG_PREFIX2}: Completed test run successfully`);
10725
10850
  return data.data || {};
10726
10851
  }
10727
10852
  return data;
10728
10853
  } catch (error) {
10729
10854
  const errorMsg = this._extractErrorMessage(error);
10730
10855
  Logger.error(
10731
- `${LOG_PREFIX}: Failed to post run status for run '${runId}':`,
10856
+ `${LOG_PREFIX2}: Failed to post run status for run '${runId}':`,
10732
10857
  errorMsg
10733
10858
  );
10734
10859
  return { success: false };
@@ -10752,34 +10877,6 @@ var SimulationHttpClient = class {
10752
10877
  }
10753
10878
  };
10754
10879
 
10755
- // src/simulation/task.ts
10756
- var BaseTask = class {
10757
- };
10758
-
10759
- // src/simulation/utils.ts
10760
- var LOG_PREFIX2 = "netra.simulation";
10761
- function validateSimulationInputs(datasetId, task2) {
10762
- if (!datasetId) {
10763
- Logger.error(`${LOG_PREFIX2}: dataset_id is required`);
10764
- return false;
10765
- }
10766
- if (!(task2 instanceof BaseTask)) {
10767
- Logger.error(`${LOG_PREFIX2}: task must be a BaseTask instance`);
10768
- return false;
10769
- }
10770
- return true;
10771
- }
10772
- async function executeTask2(task2, message, sessionId) {
10773
- const result = task2.run(message, sessionId);
10774
- const resolvedResult = result instanceof Promise ? await result : result;
10775
- if (typeof resolvedResult === "object" && resolvedResult !== null && "message" in resolvedResult && "sessionId" in resolvedResult) {
10776
- return [resolvedResult.message, resolvedResult.sessionId];
10777
- }
10778
- throw new Error(
10779
- `Task must return TaskResult, got ${typeof resolvedResult}`
10780
- );
10781
- }
10782
-
10783
10880
  // src/simulation/api.ts
10784
10881
  var LOG_PREFIX3 = "netra.simulation";
10785
10882
  var SPAN_NAME = "Netra.Simulation.TestRun";
@@ -10913,17 +11010,18 @@ var Simulation = class {
10913
11010
  * Execute a multi-turn conversation for a single simulation item.
10914
11011
  */
10915
11012
  async _executeConversation(runId, runItem, task2) {
10916
- const { runItemId, message: initialMessage, turnId: initialTurnId } = runItem;
11013
+ const { runItemId, message: initialMessage, turnId: initialTurnId, files: initialFiles } = runItem;
10917
11014
  let message = initialMessage;
10918
11015
  let turnId = initialTurnId;
10919
11016
  let sessionId = null;
11017
+ let rawFiles = initialFiles ?? [];
10920
11018
  while (true) {
10921
11019
  const span2 = new SpanWrapper(SPAN_NAME, {}, LOG_PREFIX3);
10922
11020
  span2.start();
10923
11021
  try {
10924
11022
  const traceId = span2.getCurrentSpan()?.spanContext().traceId ?? "";
10925
11023
  const [responseMessage, taskSessionId] = await span2.withActive(
10926
- () => executeTask2(task2, message, sessionId)
11024
+ () => executeTask2(task2, message, sessionId, rawFiles)
10927
11025
  );
10928
11026
  if (taskSessionId) {
10929
11027
  sessionId = taskSessionId;
@@ -10957,6 +11055,7 @@ var Simulation = class {
10957
11055
  }
10958
11056
  message = response.nextUserMessage;
10959
11057
  turnId = response.nextTurnId;
11058
+ rawFiles = response.nextFiles || [];
10960
11059
  } catch (error) {
10961
11060
  const errorMsg = error instanceof Error ? error.message : String(error);
10962
11061
  Logger.error(