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.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
|
-
|
|
23660
|
-
|
|
23661
|
-
|
|
23662
|
-
|
|
23663
|
-
|
|
23664
|
-
|
|
23665
|
-
|
|
23666
|
-
"OpenAI Agents
|
|
23667
|
-
|
|
23668
|
-
|
|
23669
|
-
|
|
23670
|
-
|
|
23671
|
-
|
|
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.
|
|
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(`${
|
|
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(`${
|
|
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
|
-
`${
|
|
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(`${
|
|
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(`${
|
|
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(`${
|
|
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(`${
|
|
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(`${
|
|
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(`${
|
|
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(`${
|
|
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(`${
|
|
25360
|
+
Logger.info(`${LOG_PREFIX2}: Reported failure - ${error}`);
|
|
25174
25361
|
} catch (err) {
|
|
25175
25362
|
const errorMsg = this._extractErrorMessage(err);
|
|
25176
|
-
Logger.error(`${
|
|
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
|
-
`${
|
|
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(`${
|
|
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
|
-
`${
|
|
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(
|