@langwatch/scenario 0.2.0 → 0.2.2
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/chunk-NUZZAQV2.mjs +622 -0
- package/dist/index.d.mts +65 -15
- package/dist/index.d.ts +65 -15
- package/dist/index.js +317 -97
- package/dist/index.mjs +122 -173
- package/dist/integrations/vitest/setup.js +282 -105
- package/dist/integrations/vitest/setup.mjs +1 -1
- package/package.json +4 -3
- package/dist/chunk-ORWSJC5F.mjs +0 -309
|
@@ -30,6 +30,22 @@ var import_vitest = require("vitest");
|
|
|
30
30
|
// src/events/event-bus.ts
|
|
31
31
|
var import_rxjs = require("rxjs");
|
|
32
32
|
|
|
33
|
+
// src/config/load.ts
|
|
34
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
35
|
+
var import_node_path = __toESM(require("path"));
|
|
36
|
+
var import_node_url = require("url");
|
|
37
|
+
|
|
38
|
+
// src/domain/core/config.ts
|
|
39
|
+
var import_zod = require("zod");
|
|
40
|
+
var DEFAULT_TEMPERATURE = 0;
|
|
41
|
+
var scenarioProjectConfigSchema = import_zod.z.object({
|
|
42
|
+
defaultModel: import_zod.z.object({
|
|
43
|
+
model: import_zod.z.custom(),
|
|
44
|
+
temperature: import_zod.z.number().min(0).max(1).optional().default(DEFAULT_TEMPERATURE),
|
|
45
|
+
maxTokens: import_zod.z.number().optional()
|
|
46
|
+
}).optional()
|
|
47
|
+
}).strict();
|
|
48
|
+
|
|
33
49
|
// src/utils/logger.ts
|
|
34
50
|
var Logger = class _Logger {
|
|
35
51
|
constructor(context) {
|
|
@@ -41,21 +57,25 @@ var Logger = class _Logger {
|
|
|
41
57
|
static create(context) {
|
|
42
58
|
return new _Logger(context);
|
|
43
59
|
}
|
|
60
|
+
getLogLevel() {
|
|
61
|
+
return env.SCENARIO_LOG_LEVEL ?? "INFO" /* INFO */;
|
|
62
|
+
}
|
|
63
|
+
getLogLevelIndex(level) {
|
|
64
|
+
return Object.values(LogLevel).indexOf(level);
|
|
65
|
+
}
|
|
44
66
|
/**
|
|
45
67
|
* Checks if logging should occur based on LOG_LEVEL env var
|
|
46
68
|
*/
|
|
47
69
|
shouldLog(level) {
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const currentLevelIndex = levels.indexOf(logLevel);
|
|
51
|
-
const requestedLevelIndex = levels.indexOf(level);
|
|
70
|
+
const currentLevelIndex = this.getLogLevelIndex(this.getLogLevel());
|
|
71
|
+
const requestedLevelIndex = this.getLogLevelIndex(level);
|
|
52
72
|
return currentLevelIndex >= 0 && requestedLevelIndex <= currentLevelIndex;
|
|
53
73
|
}
|
|
54
74
|
formatMessage(message) {
|
|
55
75
|
return this.context ? `[${this.context}] ${message}` : message;
|
|
56
76
|
}
|
|
57
77
|
error(message, data) {
|
|
58
|
-
if (this.shouldLog("
|
|
78
|
+
if (this.shouldLog("ERROR" /* ERROR */)) {
|
|
59
79
|
const formattedMessage = this.formatMessage(message);
|
|
60
80
|
if (data) {
|
|
61
81
|
console.error(formattedMessage, data);
|
|
@@ -65,7 +85,7 @@ var Logger = class _Logger {
|
|
|
65
85
|
}
|
|
66
86
|
}
|
|
67
87
|
warn(message, data) {
|
|
68
|
-
if (this.shouldLog("
|
|
88
|
+
if (this.shouldLog("WARN" /* WARN */)) {
|
|
69
89
|
const formattedMessage = this.formatMessage(message);
|
|
70
90
|
if (data) {
|
|
71
91
|
console.warn(formattedMessage, data);
|
|
@@ -75,7 +95,7 @@ var Logger = class _Logger {
|
|
|
75
95
|
}
|
|
76
96
|
}
|
|
77
97
|
info(message, data) {
|
|
78
|
-
if (this.shouldLog("
|
|
98
|
+
if (this.shouldLog("INFO" /* INFO */)) {
|
|
79
99
|
const formattedMessage = this.formatMessage(message);
|
|
80
100
|
if (data) {
|
|
81
101
|
console.info(formattedMessage, data);
|
|
@@ -85,7 +105,7 @@ var Logger = class _Logger {
|
|
|
85
105
|
}
|
|
86
106
|
}
|
|
87
107
|
debug(message, data) {
|
|
88
|
-
if (this.shouldLog("
|
|
108
|
+
if (this.shouldLog("DEBUG" /* DEBUG */)) {
|
|
89
109
|
const formattedMessage = this.formatMessage(message);
|
|
90
110
|
if (data) {
|
|
91
111
|
console.log(formattedMessage, data);
|
|
@@ -96,78 +116,149 @@ var Logger = class _Logger {
|
|
|
96
116
|
}
|
|
97
117
|
};
|
|
98
118
|
|
|
99
|
-
// src/
|
|
100
|
-
var
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
// src/config/env.ts
|
|
120
|
+
var import_zod2 = require("zod");
|
|
121
|
+
|
|
122
|
+
// src/config/log-levels.ts
|
|
123
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
124
|
+
LogLevel2["ERROR"] = "ERROR";
|
|
125
|
+
LogLevel2["WARN"] = "WARN";
|
|
126
|
+
LogLevel2["INFO"] = "INFO";
|
|
127
|
+
LogLevel2["DEBUG"] = "DEBUG";
|
|
128
|
+
return LogLevel2;
|
|
129
|
+
})(LogLevel || {});
|
|
130
|
+
|
|
131
|
+
// src/config/env.ts
|
|
132
|
+
var envSchema = import_zod2.z.object({
|
|
133
|
+
/**
|
|
134
|
+
* LangWatch API key for event reporting.
|
|
135
|
+
* If not provided, events will not be sent to LangWatch.
|
|
136
|
+
*/
|
|
137
|
+
LANGWATCH_API_KEY: import_zod2.z.string().optional(),
|
|
138
|
+
/**
|
|
139
|
+
* LangWatch endpoint URL for event reporting.
|
|
140
|
+
* Defaults to the production LangWatch endpoint.
|
|
141
|
+
*/
|
|
142
|
+
LANGWATCH_ENDPOINT: import_zod2.z.string().url().default("https://app.langwatch.ai"),
|
|
143
|
+
/**
|
|
144
|
+
* Disables simulation report info messages when set to any truthy value.
|
|
145
|
+
* Useful for CI/CD environments or when you want cleaner output.
|
|
146
|
+
*/
|
|
147
|
+
SCENARIO_DISABLE_SIMULATION_REPORT_INFO: import_zod2.z.string().optional().transform((val) => Boolean(val)),
|
|
148
|
+
/**
|
|
149
|
+
* Node environment - affects logging and behavior.
|
|
150
|
+
* Defaults to 'development' if not specified.
|
|
151
|
+
*/
|
|
152
|
+
NODE_ENV: import_zod2.z.enum(["development", "production", "test"]).default("development"),
|
|
153
|
+
/**
|
|
154
|
+
* Log level for the scenario package.
|
|
155
|
+
* Defaults to 'info' if not specified.
|
|
156
|
+
*/
|
|
157
|
+
SCENARIO_LOG_LEVEL: import_zod2.z.nativeEnum(LogLevel).optional(),
|
|
158
|
+
/**
|
|
159
|
+
* Scenario batch run ID.
|
|
160
|
+
* If not provided, a random ID will be generated.
|
|
161
|
+
*/
|
|
162
|
+
SCENARIO_BATCH_RUN_ID: import_zod2.z.string().optional()
|
|
163
|
+
});
|
|
164
|
+
var env = envSchema.parse(process.env);
|
|
165
|
+
|
|
166
|
+
// src/config/index.ts
|
|
167
|
+
var logger = new Logger("scenario.config");
|
|
168
|
+
|
|
169
|
+
// src/utils/ids.ts
|
|
170
|
+
var import_xksuid = require("xksuid");
|
|
171
|
+
function getBatchRunId() {
|
|
172
|
+
if (!env.SCENARIO_BATCH_RUN_ID) {
|
|
173
|
+
env.SCENARIO_BATCH_RUN_ID = `scenariobatchrun_${(0, import_xksuid.generate)()}`;
|
|
174
|
+
}
|
|
175
|
+
return env.SCENARIO_BATCH_RUN_ID;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/events/event-alert-message-logger.ts
|
|
179
|
+
var EventAlertMessageLogger = class _EventAlertMessageLogger {
|
|
180
|
+
static shownBatchIds = /* @__PURE__ */ new Set();
|
|
181
|
+
/**
|
|
182
|
+
* Shows a fancy greeting message about simulation reporting status.
|
|
183
|
+
* Only shows once per batch run to avoid spam.
|
|
184
|
+
*/
|
|
185
|
+
handleGreeting() {
|
|
186
|
+
if (this.isGreetingDisabled()) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const batchRunId = getBatchRunId();
|
|
190
|
+
if (_EventAlertMessageLogger.shownBatchIds.has(batchRunId)) {
|
|
191
|
+
return;
|
|
118
192
|
}
|
|
193
|
+
_EventAlertMessageLogger.shownBatchIds.add(batchRunId);
|
|
194
|
+
this.displayGreeting(batchRunId);
|
|
119
195
|
}
|
|
120
196
|
/**
|
|
121
|
-
*
|
|
122
|
-
*
|
|
197
|
+
* Shows a fancy message about how to watch the simulation.
|
|
198
|
+
* Called when a run started event is received with a session ID.
|
|
123
199
|
*/
|
|
124
|
-
|
|
125
|
-
this.
|
|
126
|
-
event
|
|
127
|
-
});
|
|
128
|
-
if (!this.eventsEndpoint) {
|
|
129
|
-
this.logger.warn(
|
|
130
|
-
"No LANGWATCH_ENDPOINT configured, skipping event posting"
|
|
131
|
-
);
|
|
200
|
+
handleWatchMessage(params) {
|
|
201
|
+
if (this.isGreetingDisabled()) {
|
|
132
202
|
return;
|
|
133
203
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
204
|
+
this.displayWatchMessage(params);
|
|
205
|
+
}
|
|
206
|
+
isGreetingDisabled() {
|
|
207
|
+
return env.SCENARIO_DISABLE_SIMULATION_REPORT_INFO === true;
|
|
208
|
+
}
|
|
209
|
+
displayGreeting(batchRunId) {
|
|
210
|
+
const separator = "\u2500".repeat(60);
|
|
211
|
+
if (!env.LANGWATCH_API_KEY) {
|
|
212
|
+
console.log(`
|
|
213
|
+
${separator}`);
|
|
214
|
+
console.log("\u{1F680} LangWatch Simulation Reporting");
|
|
215
|
+
console.log(`${separator}`);
|
|
216
|
+
console.log("\u27A1\uFE0F API key not configured");
|
|
217
|
+
console.log(" Simulations will only output final results");
|
|
218
|
+
console.log("");
|
|
219
|
+
console.log("\u{1F4A1} To visualize conversations in real time:");
|
|
220
|
+
console.log(" \u2022 Set LANGWATCH_API_KEY environment variable");
|
|
221
|
+
console.log(" \u2022 Or configure apiKey in scenario.config.js");
|
|
222
|
+
console.log("");
|
|
223
|
+
console.log(`\u{1F4E6} Batch Run ID: ${batchRunId}`);
|
|
224
|
+
console.log(`${separator}
|
|
225
|
+
`);
|
|
226
|
+
} else {
|
|
227
|
+
console.log(`
|
|
228
|
+
${separator}`);
|
|
229
|
+
console.log("\u{1F680} LangWatch Simulation Reporting");
|
|
230
|
+
console.log(`${separator}`);
|
|
231
|
+
console.log("\u2705 Simulation reporting enabled");
|
|
232
|
+
console.log(` Endpoint: ${env.LANGWATCH_ENDPOINT}`);
|
|
233
|
+
console.log(
|
|
234
|
+
` API Key: ${env.LANGWATCH_API_KEY.length > 0 ? "Configured" : "Not configured"}`
|
|
145
235
|
);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const errorText = await response.text();
|
|
151
|
-
this.logger.error(`[${event.type}] Event POST failed:`, {
|
|
152
|
-
status: response.status,
|
|
153
|
-
statusText: response.statusText,
|
|
154
|
-
error: errorText,
|
|
155
|
-
event
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
} catch (error) {
|
|
159
|
-
this.logger.error(`[${event.type}] Event POST error:`, {
|
|
160
|
-
error,
|
|
161
|
-
event,
|
|
162
|
-
endpoint: this.eventsEndpoint
|
|
163
|
-
});
|
|
236
|
+
console.log("");
|
|
237
|
+
console.log(`\u{1F4E6} Batch Run ID: ${batchRunId}`);
|
|
238
|
+
console.log(`${separator}
|
|
239
|
+
`);
|
|
164
240
|
}
|
|
165
241
|
}
|
|
242
|
+
displayWatchMessage(params) {
|
|
243
|
+
const separator = "\u2500".repeat(60);
|
|
244
|
+
const setUrl = params.setUrl;
|
|
245
|
+
const batchUrl = `${setUrl}/${getBatchRunId()}`;
|
|
246
|
+
console.log(`
|
|
247
|
+
${separator}`);
|
|
248
|
+
console.log("\u{1F440} Watch Your Simulation Live");
|
|
249
|
+
console.log(`${separator}`);
|
|
250
|
+
console.log("\u{1F310} Open in your browser:");
|
|
251
|
+
console.log(` Scenario Set: ${setUrl}`);
|
|
252
|
+
console.log(` Batch Run: ${batchUrl}`);
|
|
253
|
+
console.log("");
|
|
254
|
+
console.log(`${separator}
|
|
255
|
+
`);
|
|
256
|
+
}
|
|
166
257
|
};
|
|
167
258
|
|
|
168
259
|
// src/events/schema.ts
|
|
169
260
|
var import_core = require("@ag-ui/core");
|
|
170
|
-
var
|
|
261
|
+
var import_zod3 = require("zod");
|
|
171
262
|
var Verdict = /* @__PURE__ */ ((Verdict2) => {
|
|
172
263
|
Verdict2["SUCCESS"] = "success";
|
|
173
264
|
Verdict2["FAILURE"] = "failure";
|
|
@@ -183,70 +274,147 @@ var ScenarioRunStatus = /* @__PURE__ */ ((ScenarioRunStatus2) => {
|
|
|
183
274
|
ScenarioRunStatus2["FAILED"] = "FAILED";
|
|
184
275
|
return ScenarioRunStatus2;
|
|
185
276
|
})(ScenarioRunStatus || {});
|
|
186
|
-
var baseEventSchema =
|
|
187
|
-
type:
|
|
188
|
-
timestamp:
|
|
189
|
-
rawEvent:
|
|
277
|
+
var baseEventSchema = import_zod3.z.object({
|
|
278
|
+
type: import_zod3.z.nativeEnum(import_core.EventType),
|
|
279
|
+
timestamp: import_zod3.z.number(),
|
|
280
|
+
rawEvent: import_zod3.z.any().optional()
|
|
190
281
|
});
|
|
191
|
-
var batchRunIdSchema =
|
|
192
|
-
var scenarioRunIdSchema =
|
|
193
|
-
var scenarioIdSchema =
|
|
282
|
+
var batchRunIdSchema = import_zod3.z.string();
|
|
283
|
+
var scenarioRunIdSchema = import_zod3.z.string();
|
|
284
|
+
var scenarioIdSchema = import_zod3.z.string();
|
|
194
285
|
var baseScenarioEventSchema = baseEventSchema.extend({
|
|
195
286
|
batchRunId: batchRunIdSchema,
|
|
196
287
|
scenarioId: scenarioIdSchema,
|
|
197
288
|
scenarioRunId: scenarioRunIdSchema,
|
|
198
|
-
scenarioSetId:
|
|
289
|
+
scenarioSetId: import_zod3.z.string().optional().default("default")
|
|
199
290
|
});
|
|
200
291
|
var scenarioRunStartedSchema = baseScenarioEventSchema.extend({
|
|
201
|
-
type:
|
|
202
|
-
metadata:
|
|
203
|
-
name:
|
|
204
|
-
description:
|
|
292
|
+
type: import_zod3.z.literal("SCENARIO_RUN_STARTED" /* RUN_STARTED */),
|
|
293
|
+
metadata: import_zod3.z.object({
|
|
294
|
+
name: import_zod3.z.string().optional(),
|
|
295
|
+
description: import_zod3.z.string().optional()
|
|
205
296
|
})
|
|
206
297
|
});
|
|
207
|
-
var scenarioResultsSchema =
|
|
208
|
-
verdict:
|
|
209
|
-
reasoning:
|
|
210
|
-
metCriteria:
|
|
211
|
-
unmetCriteria:
|
|
212
|
-
error:
|
|
298
|
+
var scenarioResultsSchema = import_zod3.z.object({
|
|
299
|
+
verdict: import_zod3.z.nativeEnum(Verdict),
|
|
300
|
+
reasoning: import_zod3.z.string().optional(),
|
|
301
|
+
metCriteria: import_zod3.z.array(import_zod3.z.string()),
|
|
302
|
+
unmetCriteria: import_zod3.z.array(import_zod3.z.string()),
|
|
303
|
+
error: import_zod3.z.string().optional()
|
|
213
304
|
});
|
|
214
305
|
var scenarioRunFinishedSchema = baseScenarioEventSchema.extend({
|
|
215
|
-
type:
|
|
216
|
-
status:
|
|
306
|
+
type: import_zod3.z.literal("SCENARIO_RUN_FINISHED" /* RUN_FINISHED */),
|
|
307
|
+
status: import_zod3.z.nativeEnum(ScenarioRunStatus),
|
|
217
308
|
results: scenarioResultsSchema.optional().nullable()
|
|
218
309
|
});
|
|
219
310
|
var scenarioMessageSnapshotSchema = import_core.MessagesSnapshotEventSchema.merge(
|
|
220
311
|
baseScenarioEventSchema.extend({
|
|
221
|
-
type:
|
|
312
|
+
type: import_zod3.z.literal("SCENARIO_MESSAGE_SNAPSHOT" /* MESSAGE_SNAPSHOT */)
|
|
222
313
|
})
|
|
223
314
|
);
|
|
224
|
-
var scenarioEventSchema =
|
|
315
|
+
var scenarioEventSchema = import_zod3.z.discriminatedUnion("type", [
|
|
225
316
|
scenarioRunStartedSchema,
|
|
226
317
|
scenarioRunFinishedSchema,
|
|
227
318
|
scenarioMessageSnapshotSchema
|
|
228
319
|
]);
|
|
229
|
-
var successSchema =
|
|
230
|
-
var errorSchema =
|
|
231
|
-
var stateSchema =
|
|
232
|
-
state:
|
|
233
|
-
messages:
|
|
234
|
-
status:
|
|
320
|
+
var successSchema = import_zod3.z.object({ success: import_zod3.z.boolean() });
|
|
321
|
+
var errorSchema = import_zod3.z.object({ error: import_zod3.z.string() });
|
|
322
|
+
var stateSchema = import_zod3.z.object({
|
|
323
|
+
state: import_zod3.z.object({
|
|
324
|
+
messages: import_zod3.z.array(import_zod3.z.any()),
|
|
325
|
+
status: import_zod3.z.string()
|
|
235
326
|
})
|
|
236
327
|
});
|
|
237
|
-
var runsSchema =
|
|
238
|
-
var eventsSchema =
|
|
328
|
+
var runsSchema = import_zod3.z.object({ runs: import_zod3.z.array(import_zod3.z.string()) });
|
|
329
|
+
var eventsSchema = import_zod3.z.object({ events: import_zod3.z.array(scenarioEventSchema) });
|
|
330
|
+
|
|
331
|
+
// src/events/event-reporter.ts
|
|
332
|
+
var EventReporter = class {
|
|
333
|
+
apiKey;
|
|
334
|
+
eventsEndpoint;
|
|
335
|
+
eventAlertMessageLogger;
|
|
336
|
+
logger = new Logger("scenario.events.EventReporter");
|
|
337
|
+
isEnabled;
|
|
338
|
+
constructor(config) {
|
|
339
|
+
this.apiKey = config.apiKey ?? "";
|
|
340
|
+
this.eventsEndpoint = new URL("/api/scenario-events", config.endpoint);
|
|
341
|
+
this.eventAlertMessageLogger = new EventAlertMessageLogger();
|
|
342
|
+
this.eventAlertMessageLogger.handleGreeting();
|
|
343
|
+
this.isEnabled = this.apiKey.length > 0 && this.eventsEndpoint.href.length > 0;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Posts an event to the configured endpoint.
|
|
347
|
+
* Logs success/failure but doesn't throw - event posting shouldn't break scenario execution.
|
|
348
|
+
*/
|
|
349
|
+
async postEvent(event) {
|
|
350
|
+
if (!this.isEnabled) return {};
|
|
351
|
+
const result = {};
|
|
352
|
+
this.logger.debug(`[${event.type}] Posting event`, { event });
|
|
353
|
+
const processedEvent = this.processEventForApi(event);
|
|
354
|
+
try {
|
|
355
|
+
const response = await fetch(this.eventsEndpoint.href, {
|
|
356
|
+
method: "POST",
|
|
357
|
+
body: JSON.stringify(processedEvent),
|
|
358
|
+
headers: {
|
|
359
|
+
"Content-Type": "application/json",
|
|
360
|
+
"X-Auth-Token": this.apiKey
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
this.logger.debug(
|
|
364
|
+
`[${event.type}] Event POST response status: ${response.status}`
|
|
365
|
+
);
|
|
366
|
+
if (response.ok) {
|
|
367
|
+
const data = await response.json();
|
|
368
|
+
this.logger.debug(`[${event.type}] Event POST response:`, data);
|
|
369
|
+
result.setUrl = data.url;
|
|
370
|
+
} else {
|
|
371
|
+
const errorText = await response.text();
|
|
372
|
+
this.logger.error(`[${event.type}] Event POST failed:`, {
|
|
373
|
+
status: response.status,
|
|
374
|
+
statusText: response.statusText,
|
|
375
|
+
error: errorText,
|
|
376
|
+
event: JSON.stringify(processedEvent)
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
} catch (error) {
|
|
380
|
+
this.logger.error(`[${event.type}] Event POST error:`, {
|
|
381
|
+
error,
|
|
382
|
+
event: JSON.stringify(processedEvent),
|
|
383
|
+
endpoint: this.eventsEndpoint.href
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
return result;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Processes event data to ensure API compatibility.
|
|
390
|
+
* Converts message content objects to strings when needed.
|
|
391
|
+
*/
|
|
392
|
+
processEventForApi(event) {
|
|
393
|
+
if (event.type === "SCENARIO_MESSAGE_SNAPSHOT" /* MESSAGE_SNAPSHOT */) {
|
|
394
|
+
return {
|
|
395
|
+
...event,
|
|
396
|
+
messages: event.messages.map((message) => ({
|
|
397
|
+
...message,
|
|
398
|
+
content: typeof message.content !== "string" ? JSON.stringify(message.content) : message.content
|
|
399
|
+
}))
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
return event;
|
|
403
|
+
}
|
|
404
|
+
};
|
|
239
405
|
|
|
240
406
|
// src/events/event-bus.ts
|
|
241
407
|
var EventBus = class _EventBus {
|
|
242
408
|
static registry = /* @__PURE__ */ new Set();
|
|
243
409
|
events$ = new import_rxjs.Subject();
|
|
244
410
|
eventReporter;
|
|
411
|
+
eventAlertMessageLogger;
|
|
245
412
|
processingPromise = null;
|
|
246
413
|
logger = new Logger("scenario.events.EventBus");
|
|
247
414
|
static globalListeners = [];
|
|
248
415
|
constructor(config) {
|
|
249
416
|
this.eventReporter = new EventReporter(config);
|
|
417
|
+
this.eventAlertMessageLogger = new EventAlertMessageLogger();
|
|
250
418
|
_EventBus.registry.add(this);
|
|
251
419
|
for (const listener of _EventBus.globalListeners) {
|
|
252
420
|
listener(this);
|
|
@@ -278,22 +446,31 @@ var EventBus = class _EventBus {
|
|
|
278
446
|
}
|
|
279
447
|
this.processingPromise = new Promise((resolve, reject) => {
|
|
280
448
|
this.events$.pipe(
|
|
449
|
+
// Post events and get results
|
|
281
450
|
(0, import_rxjs.concatMap)(async (event) => {
|
|
282
|
-
this.logger.debug(`[${event.type}] Processing event`, {
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
|
|
451
|
+
this.logger.debug(`[${event.type}] Processing event`, { event });
|
|
452
|
+
const result = await this.eventReporter.postEvent(event);
|
|
453
|
+
return { event, result };
|
|
454
|
+
}),
|
|
455
|
+
// Handle watch messages reactively
|
|
456
|
+
(0, import_rxjs.tap)(({ event, result }) => {
|
|
457
|
+
if (event.type === "SCENARIO_RUN_STARTED" /* RUN_STARTED */ && result.setUrl) {
|
|
458
|
+
this.eventAlertMessageLogger.handleWatchMessage({
|
|
459
|
+
scenarioSetId: event.scenarioSetId,
|
|
460
|
+
scenarioRunId: event.scenarioRunId,
|
|
461
|
+
setUrl: result.setUrl
|
|
462
|
+
});
|
|
463
|
+
}
|
|
287
464
|
}),
|
|
465
|
+
// Extract just the event for downstream processing
|
|
466
|
+
(0, import_rxjs.map)(({ event }) => event),
|
|
288
467
|
(0, import_rxjs.catchError)((error) => {
|
|
289
468
|
this.logger.error("Error in event stream:", error);
|
|
290
469
|
return import_rxjs.EMPTY;
|
|
291
470
|
})
|
|
292
471
|
).subscribe({
|
|
293
472
|
next: (event) => {
|
|
294
|
-
this.logger.debug(`[${event.type}] Event processed`, {
|
|
295
|
-
event
|
|
296
|
-
});
|
|
473
|
+
this.logger.debug(`[${event.type}] Event processed`, { event });
|
|
297
474
|
if (event.type === "SCENARIO_RUN_FINISHED" /* RUN_FINISHED */) {
|
|
298
475
|
resolve();
|
|
299
476
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langwatch/scenario",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "A TypeScript library for testing AI agents using scenarios",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -84,7 +84,8 @@
|
|
|
84
84
|
"test": "vitest",
|
|
85
85
|
"test:ci": "vitest run",
|
|
86
86
|
"lint": "eslint .",
|
|
87
|
-
"examples:vitest:run": "export SCENARIO_BATCH_ID=scenariobatch_$(uuidgen) && pnpm run buildpack && (cd examples/vitest && pnpm install) && pnpm -F vitest run test",
|
|
88
|
-
"
|
|
87
|
+
"examples:vitest:run": "export SCENARIO_BATCH_ID=scenariobatch_$(uuidgen) && pnpm run buildpack && (cd examples/vitest && pnpm install) && pnpm -F vitest-example run test",
|
|
88
|
+
"hash-source": "find src -name \"*.ts\" -type f | sort | xargs cat | sha256sum | cut -d' ' -f1",
|
|
89
|
+
"generate:api-reference": "npx typedoc src --out api-reference-docs && rm -rf ../docs/docs/public/reference/javascript/scenario && mv api-reference-docs ../docs/docs/public/reference/javascript/scenario && pnpm run hash-source > ../docs/docs/public/reference/javascript/.docs-source-hash"
|
|
89
90
|
}
|
|
90
91
|
}
|