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 +224 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -3
- package/dist/index.d.ts +60 -3
- package/dist/index.js +224 -63
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -610,7 +610,8 @@ var DEFAULT_INSTRUMENTS_FOR_ROOT = /* @__PURE__ */ new Set([
|
|
|
610
610
|
// AI frameworks
|
|
611
611
|
"langchain" /* LANGCHAIN */,
|
|
612
612
|
"langgraph" /* LANGGRAPH */,
|
|
613
|
-
"llama_index" /* LLAMA_INDEX
|
|
613
|
+
"llama_index" /* LLAMA_INDEX */,
|
|
614
|
+
"openai_agents" /* OPENAI_AGENTS */
|
|
614
615
|
]);
|
|
615
616
|
var DEFAULT_INSTRUMENTS = /* @__PURE__ */ new Set([
|
|
616
617
|
...DEFAULT_INSTRUMENTS_FOR_ROOT,
|
|
@@ -3626,6 +3627,13 @@ var SpanAttributes2 = {
|
|
|
3626
3627
|
};
|
|
3627
3628
|
|
|
3628
3629
|
// src/instrumentation/utils.ts
|
|
3630
|
+
var VALID_NATIVE_TRACING_MODES = /* @__PURE__ */ new Set(["both", "netra", "netra-strict"]);
|
|
3631
|
+
function parseNativeTracingEnv(name) {
|
|
3632
|
+
const val = process.env[name];
|
|
3633
|
+
if (val === void 0 || val === "") return void 0;
|
|
3634
|
+
if (VALID_NATIVE_TRACING_MODES.has(val)) return val;
|
|
3635
|
+
return void 0;
|
|
3636
|
+
}
|
|
3629
3637
|
var SUPPRESS_INSTRUMENTATION_KEY = /* @__PURE__ */ Symbol("netra.suppress_instrumentation");
|
|
3630
3638
|
function shouldSuppressInstrumentation() {
|
|
3631
3639
|
const ctx = context.active();
|
|
@@ -9132,6 +9140,8 @@ var cachedAgentsModule = null;
|
|
|
9132
9140
|
var isInstrumented6 = false;
|
|
9133
9141
|
var activeTracer = null;
|
|
9134
9142
|
var activeProcessor = null;
|
|
9143
|
+
var originalProcessors = null;
|
|
9144
|
+
var didReplaceProcessors = false;
|
|
9135
9145
|
async function resolveAgentsModule() {
|
|
9136
9146
|
if (cachedAgentsModule) return cachedAgentsModule;
|
|
9137
9147
|
try {
|
|
@@ -9184,20 +9194,51 @@ var NetraOpenAIAgentsInstrumentor = class {
|
|
|
9184
9194
|
}
|
|
9185
9195
|
const systemName = options.systemName ?? DEFAULT_LLM_SYSTEM;
|
|
9186
9196
|
activeProcessor = new NetraAgentsTracingProcessor(activeTracer, systemName);
|
|
9197
|
+
const mode = options.nativeTracing ?? parseNativeTracingEnv("NATIVE_TRACING_MODE") ?? "netra-strict";
|
|
9198
|
+
const canSet = typeof agentsModule.setTraceProcessors === "function";
|
|
9199
|
+
const canAdd = typeof agentsModule.addTraceProcessor === "function";
|
|
9200
|
+
let strategy;
|
|
9201
|
+
if (mode === "both" || mode === "netra" && !canSet) {
|
|
9202
|
+
strategy = "append";
|
|
9203
|
+
} else if (canSet) {
|
|
9204
|
+
strategy = "replace";
|
|
9205
|
+
} else {
|
|
9206
|
+
strategy = "skip";
|
|
9207
|
+
}
|
|
9187
9208
|
try {
|
|
9188
|
-
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9195
|
-
"OpenAI Agents
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9209
|
+
switch (strategy) {
|
|
9210
|
+
case "replace":
|
|
9211
|
+
if (typeof agentsModule.getTraceProcessors === "function") {
|
|
9212
|
+
originalProcessors = agentsModule.getTraceProcessors();
|
|
9213
|
+
}
|
|
9214
|
+
agentsModule.setTraceProcessors([activeProcessor]);
|
|
9215
|
+
didReplaceProcessors = true;
|
|
9216
|
+
Logger.debug("OpenAI Agents native tracing disabled \u2014 traces will only be sent to Netra.");
|
|
9217
|
+
break;
|
|
9218
|
+
case "append":
|
|
9219
|
+
if (canAdd) {
|
|
9220
|
+
agentsModule.addTraceProcessor(activeProcessor);
|
|
9221
|
+
} else {
|
|
9222
|
+
Logger.warn("OpenAI Agents SDK does not expose addTraceProcessor or setTraceProcessors.");
|
|
9223
|
+
activeProcessor = null;
|
|
9224
|
+
activeTracer = null;
|
|
9225
|
+
return this;
|
|
9226
|
+
}
|
|
9227
|
+
if (mode === "netra") {
|
|
9228
|
+
Logger.warn(
|
|
9229
|
+
"Cannot exclusively replace native trace processors in this @openai/agents version.",
|
|
9230
|
+
"Traces may still be sent to OpenAI."
|
|
9231
|
+
);
|
|
9232
|
+
}
|
|
9233
|
+
break;
|
|
9234
|
+
case "skip":
|
|
9235
|
+
Logger.warn(
|
|
9236
|
+
'nativeTracing is "netra-strict" but the installed @openai/agents version',
|
|
9237
|
+
"does not support processor replacement. Skipping instrumentation."
|
|
9238
|
+
);
|
|
9239
|
+
activeProcessor = null;
|
|
9240
|
+
activeTracer = null;
|
|
9241
|
+
return this;
|
|
9201
9242
|
}
|
|
9202
9243
|
} catch (error) {
|
|
9203
9244
|
Logger.warn("Failed to register trace processor with @openai/agents:", error);
|
|
@@ -9217,6 +9258,21 @@ var NetraOpenAIAgentsInstrumentor = class {
|
|
|
9217
9258
|
activeProcessor.shutdown();
|
|
9218
9259
|
activeProcessor = null;
|
|
9219
9260
|
}
|
|
9261
|
+
if (didReplaceProcessors && cachedAgentsModule) {
|
|
9262
|
+
try {
|
|
9263
|
+
if (originalProcessors && typeof cachedAgentsModule.setTraceProcessors === "function") {
|
|
9264
|
+
cachedAgentsModule.setTraceProcessors(originalProcessors);
|
|
9265
|
+
Logger.debug("Restored original OpenAI Agents trace processors");
|
|
9266
|
+
} else if (typeof cachedAgentsModule.setDefaultOpenAITracingExporter === "function") {
|
|
9267
|
+
cachedAgentsModule.setDefaultOpenAITracingExporter();
|
|
9268
|
+
Logger.debug("Restored default OpenAI Agents tracing exporter");
|
|
9269
|
+
}
|
|
9270
|
+
} catch (error) {
|
|
9271
|
+
Logger.debug("Failed to restore original trace processors:", error);
|
|
9272
|
+
}
|
|
9273
|
+
}
|
|
9274
|
+
originalProcessors = null;
|
|
9275
|
+
didReplaceProcessors = false;
|
|
9220
9276
|
activeTracer = null;
|
|
9221
9277
|
cachedAgentsModule = null;
|
|
9222
9278
|
isInstrumented6 = false;
|
|
@@ -10099,7 +10155,9 @@ function initInstrumentations(config2, instruments, blockInstruments, rootInstru
|
|
|
10099
10155
|
mistral: false,
|
|
10100
10156
|
langgraph: false,
|
|
10101
10157
|
googleGenAI: false,
|
|
10102
|
-
anthropic: false
|
|
10158
|
+
anthropic: false,
|
|
10159
|
+
openAiAgents: false
|
|
10160
|
+
};
|
|
10103
10161
|
const resolved = enableAll ? new Set(Object.values(NetraInstruments).filter((v) => v !== "__all__" /* ALL */)) : instruments && instruments.size > 0 ? instruments : DEFAULT_INSTRUMENTS;
|
|
10104
10162
|
instrumentModules.google_vertexai = false;
|
|
10105
10163
|
instrumentModules.langchain = false;
|
|
@@ -10147,6 +10205,9 @@ function initInstrumentations(config2, instruments, blockInstruments, rootInstru
|
|
|
10147
10205
|
if (resolved.has("anthropic" /* ANTHROPIC */)) {
|
|
10148
10206
|
customInstrumentModules.anthropic = true;
|
|
10149
10207
|
}
|
|
10208
|
+
if (resolved.has("openai_agents" /* OPENAI_AGENTS */)) {
|
|
10209
|
+
customInstrumentModules.openAiAgents = true;
|
|
10210
|
+
}
|
|
10150
10211
|
if (blockInstruments && blockInstruments.size > 0) {
|
|
10151
10212
|
const blockAll = blockInstruments.has("__all__" /* ALL */);
|
|
10152
10213
|
if (blockAll || blockInstruments.has("openai" /* OPENAI */)) customInstrumentModules.openai = false;
|
|
@@ -10155,6 +10216,7 @@ function initInstrumentations(config2, instruments, blockInstruments, rootInstru
|
|
|
10155
10216
|
if (blockAll || blockInstruments.has("langgraph" /* LANGGRAPH */)) customInstrumentModules.langgraph = false;
|
|
10156
10217
|
if (blockAll || blockInstruments.has("google_genai" /* GOOGLE_GENERATIVE_AI */)) customInstrumentModules.googleGenAI = false;
|
|
10157
10218
|
if (blockAll || blockInstruments.has("anthropic" /* ANTHROPIC */)) customInstrumentModules.anthropic = false;
|
|
10219
|
+
if (blockAll || blockInstruments.has("openai_agents" /* OPENAI_AGENTS */)) customInstrumentModules.openAiAgents = false;
|
|
10158
10220
|
if (blockAll || blockInstruments.has("vertexai" /* VERTEX_AI */)) instrumentModules.google_vertexai = false;
|
|
10159
10221
|
if (blockAll || blockInstruments.has("langchain" /* LANGCHAIN */)) instrumentModules.langchain = false;
|
|
10160
10222
|
if (blockAll || blockInstruments.has("llama_index" /* LLAMA_INDEX */)) instrumentModules.llamaIndex = false;
|
|
@@ -10277,7 +10339,7 @@ async function initCustomInstrumentationsAsync(config2, tracerProvider, customIn
|
|
|
10277
10339
|
Logger.debug("Failed to initialize custom Anthropic instrumentation:", e);
|
|
10278
10340
|
}
|
|
10279
10341
|
}
|
|
10280
|
-
if (customInstrumentModules.
|
|
10342
|
+
if (customInstrumentModules.openAiAgents && !blockInstruments?.has("openai_agents" /* OPENAI_AGENTS */)) {
|
|
10281
10343
|
try {
|
|
10282
10344
|
await openaiAgentsInstrumentor.instrument({ tracerProvider });
|
|
10283
10345
|
Logger.debug("Custom OpenAI Agents SDK instrumentation enabled");
|
|
@@ -10526,7 +10588,130 @@ async function uninstrumentAll() {
|
|
|
10526
10588
|
Logger.debug("Failed to uninstrument undici:", e);
|
|
10527
10589
|
}
|
|
10528
10590
|
}
|
|
10591
|
+
|
|
10592
|
+
// src/simulation/task.ts
|
|
10593
|
+
var BaseTask = class {
|
|
10594
|
+
};
|
|
10595
|
+
|
|
10596
|
+
// src/simulation/utils.ts
|
|
10529
10597
|
var LOG_PREFIX = "netra.simulation";
|
|
10598
|
+
var DEFAULT_FILE_DOWNLOAD_TIMEOUT_S = 30;
|
|
10599
|
+
var MAX_FILE_DOWNLOAD_WORKERS = 8;
|
|
10600
|
+
var _cachedFileDownloadTimeoutMs = null;
|
|
10601
|
+
function validateSimulationInputs(datasetId, task2) {
|
|
10602
|
+
if (!datasetId) {
|
|
10603
|
+
Logger.error(`${LOG_PREFIX}: dataset_id is required`);
|
|
10604
|
+
return false;
|
|
10605
|
+
}
|
|
10606
|
+
if (!(task2 instanceof BaseTask)) {
|
|
10607
|
+
Logger.error(`${LOG_PREFIX}: task must be a BaseTask instance`);
|
|
10608
|
+
return false;
|
|
10609
|
+
}
|
|
10610
|
+
return true;
|
|
10611
|
+
}
|
|
10612
|
+
function _getFileDownloadTimeout() {
|
|
10613
|
+
if (_cachedFileDownloadTimeoutMs !== null) {
|
|
10614
|
+
return _cachedFileDownloadTimeoutMs;
|
|
10615
|
+
}
|
|
10616
|
+
const envVal = process.env.NETRA_SIMULATION_FILE_DOWNLOAD_TIMEOUT;
|
|
10617
|
+
if (envVal) {
|
|
10618
|
+
const parsed = parseFloat(envVal);
|
|
10619
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
10620
|
+
_cachedFileDownloadTimeoutMs = parsed * 1e3;
|
|
10621
|
+
return _cachedFileDownloadTimeoutMs;
|
|
10622
|
+
}
|
|
10623
|
+
Logger.warn(
|
|
10624
|
+
`${LOG_PREFIX}: Invalid file download timeout '${envVal}', using default ${DEFAULT_FILE_DOWNLOAD_TIMEOUT_S}s`
|
|
10625
|
+
);
|
|
10626
|
+
}
|
|
10627
|
+
_cachedFileDownloadTimeoutMs = DEFAULT_FILE_DOWNLOAD_TIMEOUT_S * 1e3;
|
|
10628
|
+
return _cachedFileDownloadTimeoutMs;
|
|
10629
|
+
}
|
|
10630
|
+
async function _downloadSingleFile(fileData, timeoutMs, signal) {
|
|
10631
|
+
try {
|
|
10632
|
+
const response = await axios.get(fileData.downloadUrl, {
|
|
10633
|
+
responseType: "arraybuffer",
|
|
10634
|
+
timeout: timeoutMs,
|
|
10635
|
+
signal
|
|
10636
|
+
});
|
|
10637
|
+
const encoded = Buffer.from(response.data).toString("base64");
|
|
10638
|
+
return {
|
|
10639
|
+
fileName: fileData.fileName,
|
|
10640
|
+
contentType: fileData.contentType,
|
|
10641
|
+
description: fileData.description,
|
|
10642
|
+
data: encoded
|
|
10643
|
+
};
|
|
10644
|
+
} catch (error) {
|
|
10645
|
+
if (axios.isCancel(error)) {
|
|
10646
|
+
throw new Error(
|
|
10647
|
+
`Download of '${fileData.fileName}' was cancelled`
|
|
10648
|
+
);
|
|
10649
|
+
}
|
|
10650
|
+
const status = axios.isAxiosError(error) ? error.response?.status : void 0;
|
|
10651
|
+
const reason = status ? `HTTP ${status}` : error instanceof Error ? error.message : String(error);
|
|
10652
|
+
Logger.error(
|
|
10653
|
+
`${LOG_PREFIX}: Failed to download file '${fileData.fileName}': ${reason}`
|
|
10654
|
+
);
|
|
10655
|
+
throw new Error(
|
|
10656
|
+
`Failed to download file '${fileData.fileName}': ${reason}`
|
|
10657
|
+
);
|
|
10658
|
+
}
|
|
10659
|
+
}
|
|
10660
|
+
function parseFiles(rawFiles) {
|
|
10661
|
+
if (!rawFiles) {
|
|
10662
|
+
return [];
|
|
10663
|
+
}
|
|
10664
|
+
const parsed = [];
|
|
10665
|
+
for (const entry of rawFiles) {
|
|
10666
|
+
const fileName = entry.fileName || "";
|
|
10667
|
+
const downloadUrl = entry.downloadUrl || "";
|
|
10668
|
+
if (!fileName || !downloadUrl) {
|
|
10669
|
+
Logger.warn(
|
|
10670
|
+
`${LOG_PREFIX}: Skipping malformed file attachment (missing fileName or downloadUrl)`
|
|
10671
|
+
);
|
|
10672
|
+
continue;
|
|
10673
|
+
}
|
|
10674
|
+
parsed.push({
|
|
10675
|
+
fileName,
|
|
10676
|
+
contentType: entry.contentType || "",
|
|
10677
|
+
description: entry.description || void 0,
|
|
10678
|
+
downloadUrl
|
|
10679
|
+
});
|
|
10680
|
+
}
|
|
10681
|
+
return parsed;
|
|
10682
|
+
}
|
|
10683
|
+
async function processFiles(files) {
|
|
10684
|
+
if (!files || files.length === 0) {
|
|
10685
|
+
return null;
|
|
10686
|
+
}
|
|
10687
|
+
const timeoutMs = _getFileDownloadTimeout();
|
|
10688
|
+
const limit = pLimit(MAX_FILE_DOWNLOAD_WORKERS);
|
|
10689
|
+
const controller = new AbortController();
|
|
10690
|
+
const downloadPromises = files.map(
|
|
10691
|
+
(file) => limit(() => _downloadSingleFile(file, timeoutMs, controller.signal))
|
|
10692
|
+
);
|
|
10693
|
+
try {
|
|
10694
|
+
return await Promise.all(downloadPromises);
|
|
10695
|
+
} catch (error) {
|
|
10696
|
+
controller.abort();
|
|
10697
|
+
limit.clearQueue();
|
|
10698
|
+
throw error;
|
|
10699
|
+
}
|
|
10700
|
+
}
|
|
10701
|
+
async function executeTask2(task2, message, sessionId, rawFiles) {
|
|
10702
|
+
const processedFiles = rawFiles && rawFiles.length > 0 ? await processFiles(rawFiles) : null;
|
|
10703
|
+
const result = task2.run(message, sessionId, processedFiles);
|
|
10704
|
+
const resolvedResult = result instanceof Promise ? await result : result;
|
|
10705
|
+
if (typeof resolvedResult === "object" && resolvedResult !== null && "message" in resolvedResult && "sessionId" in resolvedResult) {
|
|
10706
|
+
return [resolvedResult.message, resolvedResult.sessionId];
|
|
10707
|
+
}
|
|
10708
|
+
throw new Error(
|
|
10709
|
+
`Task must return TaskResult, got ${typeof resolvedResult}`
|
|
10710
|
+
);
|
|
10711
|
+
}
|
|
10712
|
+
|
|
10713
|
+
// src/simulation/client.ts
|
|
10714
|
+
var LOG_PREFIX2 = "netra.simulation";
|
|
10530
10715
|
var DEFAULT_TIMEOUT = 1e4;
|
|
10531
10716
|
var SimulationHttpClient = class {
|
|
10532
10717
|
constructor(config2) {
|
|
@@ -10539,7 +10724,7 @@ var SimulationHttpClient = class {
|
|
|
10539
10724
|
_createClient(config2) {
|
|
10540
10725
|
const endpoint = (config2.otlpEndpoint || "").trim();
|
|
10541
10726
|
if (!endpoint) {
|
|
10542
|
-
Logger.error(`${
|
|
10727
|
+
Logger.error(`${LOG_PREFIX2}: NETRA_OTLP_ENDPOINT is required`);
|
|
10543
10728
|
return null;
|
|
10544
10729
|
}
|
|
10545
10730
|
const baseURL = this._resolveBaseUrl(endpoint);
|
|
@@ -10561,7 +10746,7 @@ var SimulationHttpClient = class {
|
|
|
10561
10746
|
);
|
|
10562
10747
|
return instance;
|
|
10563
10748
|
} catch (error) {
|
|
10564
|
-
Logger.error(`${
|
|
10749
|
+
Logger.error(`${LOG_PREFIX2}: Failed to create HTTP client:`, error);
|
|
10565
10750
|
return null;
|
|
10566
10751
|
}
|
|
10567
10752
|
}
|
|
@@ -10596,7 +10781,7 @@ var SimulationHttpClient = class {
|
|
|
10596
10781
|
const timeout = parseFloat(timeoutStr);
|
|
10597
10782
|
if (isNaN(timeout)) {
|
|
10598
10783
|
Logger.warn(
|
|
10599
|
-
`${
|
|
10784
|
+
`${LOG_PREFIX2}: Invalid timeout '${timeoutStr}', using default ${DEFAULT_TIMEOUT}ms`
|
|
10600
10785
|
);
|
|
10601
10786
|
return DEFAULT_TIMEOUT;
|
|
10602
10787
|
}
|
|
@@ -10607,7 +10792,7 @@ var SimulationHttpClient = class {
|
|
|
10607
10792
|
*/
|
|
10608
10793
|
async createRun(name, datasetId, context16) {
|
|
10609
10794
|
if (!this.client) {
|
|
10610
|
-
Logger.error(`${
|
|
10795
|
+
Logger.error(`${LOG_PREFIX2}: Client not initialized`);
|
|
10611
10796
|
return null;
|
|
10612
10797
|
}
|
|
10613
10798
|
try {
|
|
@@ -10622,7 +10807,7 @@ var SimulationHttpClient = class {
|
|
|
10622
10807
|
const responseData = data.data || {};
|
|
10623
10808
|
const userMessages = responseData.userMessages || [];
|
|
10624
10809
|
if (userMessages.length === 0) {
|
|
10625
|
-
Logger.warn(`${
|
|
10810
|
+
Logger.warn(`${LOG_PREFIX2}: No user messages returned from create_run`);
|
|
10626
10811
|
return null;
|
|
10627
10812
|
}
|
|
10628
10813
|
const runId = responseData.id || "";
|
|
@@ -10630,7 +10815,8 @@ var SimulationHttpClient = class {
|
|
|
10630
10815
|
(msg) => ({
|
|
10631
10816
|
runItemId: msg.testRunItemId || "",
|
|
10632
10817
|
message: msg.userMessage || "",
|
|
10633
|
-
turnId: msg.turnId || ""
|
|
10818
|
+
turnId: msg.turnId || "",
|
|
10819
|
+
files: parseFiles(msg.attachments)
|
|
10634
10820
|
})
|
|
10635
10821
|
);
|
|
10636
10822
|
return {
|
|
@@ -10639,7 +10825,7 @@ var SimulationHttpClient = class {
|
|
|
10639
10825
|
};
|
|
10640
10826
|
} catch (error) {
|
|
10641
10827
|
const errorMsg = this._extractErrorMessage(error);
|
|
10642
|
-
Logger.error(`${
|
|
10828
|
+
Logger.error(`${LOG_PREFIX2}: Failed to create simulation run:`, errorMsg);
|
|
10643
10829
|
return null;
|
|
10644
10830
|
}
|
|
10645
10831
|
}
|
|
@@ -10648,7 +10834,7 @@ var SimulationHttpClient = class {
|
|
|
10648
10834
|
*/
|
|
10649
10835
|
async triggerConversation(message, turnId, sessionId, traceId) {
|
|
10650
10836
|
if (!this.client) {
|
|
10651
|
-
Logger.error(`${
|
|
10837
|
+
Logger.error(`${LOG_PREFIX2}: Client not initialized`);
|
|
10652
10838
|
return null;
|
|
10653
10839
|
}
|
|
10654
10840
|
try {
|
|
@@ -10671,7 +10857,7 @@ var SimulationHttpClient = class {
|
|
|
10671
10857
|
}
|
|
10672
10858
|
const userMessages = responseData.userMessages || [];
|
|
10673
10859
|
if (userMessages.length === 0) {
|
|
10674
|
-
Logger.warn(`${
|
|
10860
|
+
Logger.warn(`${LOG_PREFIX2}: No user messages in continue response`);
|
|
10675
10861
|
return null;
|
|
10676
10862
|
}
|
|
10677
10863
|
const nextMsg = userMessages[0];
|
|
@@ -10679,11 +10865,12 @@ var SimulationHttpClient = class {
|
|
|
10679
10865
|
decision,
|
|
10680
10866
|
nextTurnId: nextMsg.turnId || "",
|
|
10681
10867
|
nextUserMessage: nextMsg.userMessage || "",
|
|
10682
|
-
nextRunItemId: nextMsg.testRunItemId || ""
|
|
10868
|
+
nextRunItemId: nextMsg.testRunItemId || "",
|
|
10869
|
+
nextFiles: parseFiles(nextMsg.attachments)
|
|
10683
10870
|
};
|
|
10684
10871
|
} catch (error) {
|
|
10685
10872
|
const errorMsg = this._extractErrorMessage(error);
|
|
10686
|
-
Logger.error(`${
|
|
10873
|
+
Logger.error(`${LOG_PREFIX2}: Failed to trigger conversation:`, errorMsg);
|
|
10687
10874
|
return null;
|
|
10688
10875
|
}
|
|
10689
10876
|
}
|
|
@@ -10692,17 +10879,17 @@ var SimulationHttpClient = class {
|
|
|
10692
10879
|
*/
|
|
10693
10880
|
async reportFailure(runId, runItemId, error) {
|
|
10694
10881
|
if (!this.client) {
|
|
10695
|
-
Logger.error(`${
|
|
10882
|
+
Logger.error(`${LOG_PREFIX2}: Client not initialized`);
|
|
10696
10883
|
return;
|
|
10697
10884
|
}
|
|
10698
10885
|
try {
|
|
10699
10886
|
const url = `/evaluations/run/${runId}/item/${runItemId}/status`;
|
|
10700
10887
|
const payload = { status: "failed", failureReason: error };
|
|
10701
10888
|
await this.client.patch(url, payload);
|
|
10702
|
-
Logger.info(`${
|
|
10889
|
+
Logger.info(`${LOG_PREFIX2}: Reported failure - ${error}`);
|
|
10703
10890
|
} catch (err) {
|
|
10704
10891
|
const errorMsg = this._extractErrorMessage(err);
|
|
10705
|
-
Logger.error(`${
|
|
10892
|
+
Logger.error(`${LOG_PREFIX2}: Failed to report failure:`, errorMsg);
|
|
10706
10893
|
}
|
|
10707
10894
|
}
|
|
10708
10895
|
/**
|
|
@@ -10711,7 +10898,7 @@ var SimulationHttpClient = class {
|
|
|
10711
10898
|
async postRunStatus(runId, status) {
|
|
10712
10899
|
if (!this.client) {
|
|
10713
10900
|
Logger.error(
|
|
10714
|
-
`${
|
|
10901
|
+
`${LOG_PREFIX2}: Client not initialized; cannot post run status`
|
|
10715
10902
|
);
|
|
10716
10903
|
return { success: false };
|
|
10717
10904
|
}
|
|
@@ -10721,14 +10908,14 @@ var SimulationHttpClient = class {
|
|
|
10721
10908
|
const response = await this.client.post(url, payload);
|
|
10722
10909
|
const data = response.data;
|
|
10723
10910
|
if (data && typeof data === "object" && "data" in data) {
|
|
10724
|
-
Logger.info(`${
|
|
10911
|
+
Logger.info(`${LOG_PREFIX2}: Completed test run successfully`);
|
|
10725
10912
|
return data.data || {};
|
|
10726
10913
|
}
|
|
10727
10914
|
return data;
|
|
10728
10915
|
} catch (error) {
|
|
10729
10916
|
const errorMsg = this._extractErrorMessage(error);
|
|
10730
10917
|
Logger.error(
|
|
10731
|
-
`${
|
|
10918
|
+
`${LOG_PREFIX2}: Failed to post run status for run '${runId}':`,
|
|
10732
10919
|
errorMsg
|
|
10733
10920
|
);
|
|
10734
10921
|
return { success: false };
|
|
@@ -10752,34 +10939,6 @@ var SimulationHttpClient = class {
|
|
|
10752
10939
|
}
|
|
10753
10940
|
};
|
|
10754
10941
|
|
|
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
10942
|
// src/simulation/api.ts
|
|
10784
10943
|
var LOG_PREFIX3 = "netra.simulation";
|
|
10785
10944
|
var SPAN_NAME = "Netra.Simulation.TestRun";
|
|
@@ -10913,17 +11072,18 @@ var Simulation = class {
|
|
|
10913
11072
|
* Execute a multi-turn conversation for a single simulation item.
|
|
10914
11073
|
*/
|
|
10915
11074
|
async _executeConversation(runId, runItem, task2) {
|
|
10916
|
-
const { runItemId, message: initialMessage, turnId: initialTurnId } = runItem;
|
|
11075
|
+
const { runItemId, message: initialMessage, turnId: initialTurnId, files: initialFiles } = runItem;
|
|
10917
11076
|
let message = initialMessage;
|
|
10918
11077
|
let turnId = initialTurnId;
|
|
10919
11078
|
let sessionId = null;
|
|
11079
|
+
let rawFiles = initialFiles ?? [];
|
|
10920
11080
|
while (true) {
|
|
10921
11081
|
const span2 = new SpanWrapper(SPAN_NAME, {}, LOG_PREFIX3);
|
|
10922
11082
|
span2.start();
|
|
10923
11083
|
try {
|
|
10924
11084
|
const traceId = span2.getCurrentSpan()?.spanContext().traceId ?? "";
|
|
10925
11085
|
const [responseMessage, taskSessionId] = await span2.withActive(
|
|
10926
|
-
() => executeTask2(task2, message, sessionId)
|
|
11086
|
+
() => executeTask2(task2, message, sessionId, rawFiles)
|
|
10927
11087
|
);
|
|
10928
11088
|
if (taskSessionId) {
|
|
10929
11089
|
sessionId = taskSessionId;
|
|
@@ -10957,6 +11117,7 @@ var Simulation = class {
|
|
|
10957
11117
|
}
|
|
10958
11118
|
message = response.nextUserMessage;
|
|
10959
11119
|
turnId = response.nextTurnId;
|
|
11120
|
+
rawFiles = response.nextFiles || [];
|
|
10960
11121
|
} catch (error) {
|
|
10961
11122
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10962
11123
|
Logger.error(
|