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.cjs +146 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -3
- package/dist/index.d.ts +35 -3
- package/dist/index.js +146 -47
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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(`${
|
|
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(`${
|
|
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
|
-
`${
|
|
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(`${
|
|
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(`${
|
|
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(`${
|
|
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(`${
|
|
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(`${
|
|
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(`${
|
|
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(`${
|
|
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(`${
|
|
10827
|
+
Logger.info(`${LOG_PREFIX2}: Reported failure - ${error}`);
|
|
10703
10828
|
} catch (err) {
|
|
10704
10829
|
const errorMsg = this._extractErrorMessage(err);
|
|
10705
|
-
Logger.error(`${
|
|
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
|
-
`${
|
|
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(`${
|
|
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
|
-
`${
|
|
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(
|