@langwatch/scenario 0.2.1 → 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.
@@ -4,14 +4,13 @@ import {
4
4
 
5
5
  // src/domain/core/config.ts
6
6
  import { z } from "zod";
7
+ var DEFAULT_TEMPERATURE = 0;
7
8
  var scenarioProjectConfigSchema = z.object({
8
9
  defaultModel: z.object({
9
10
  model: z.custom(),
10
- temperature: z.number().min(0).max(1).optional().default(0),
11
+ temperature: z.number().min(0).max(1).optional().default(DEFAULT_TEMPERATURE),
11
12
  maxTokens: z.number().optional()
12
- }).optional(),
13
- langwatchEndpoint: z.string().optional(),
14
- langwatchApiKey: z.string().optional()
13
+ }).optional()
15
14
  }).strict();
16
15
  function defineConfig(config2) {
17
16
  return config2;
@@ -49,6 +48,7 @@ var domain_exports = {};
49
48
  __export(domain_exports, {
50
49
  AgentAdapter: () => AgentAdapter,
51
50
  AgentRole: () => AgentRole,
51
+ DEFAULT_TEMPERATURE: () => DEFAULT_TEMPERATURE,
52
52
  JudgeAgentAdapter: () => JudgeAgentAdapter,
53
53
  UserSimulatorAgentAdapter: () => UserSimulatorAgentAdapter,
54
54
  allAgentRoles: () => allAgentRoles,
@@ -425,17 +425,20 @@ var EventReporter = class {
425
425
  eventsEndpoint;
426
426
  eventAlertMessageLogger;
427
427
  logger = new Logger("scenario.events.EventReporter");
428
+ isEnabled;
428
429
  constructor(config2) {
429
430
  this.apiKey = config2.apiKey ?? "";
430
431
  this.eventsEndpoint = new URL("/api/scenario-events", config2.endpoint);
431
432
  this.eventAlertMessageLogger = new EventAlertMessageLogger();
432
433
  this.eventAlertMessageLogger.handleGreeting();
434
+ this.isEnabled = this.apiKey.length > 0 && this.eventsEndpoint.href.length > 0;
433
435
  }
434
436
  /**
435
437
  * Posts an event to the configured endpoint.
436
438
  * Logs success/failure but doesn't throw - event posting shouldn't break scenario execution.
437
439
  */
438
440
  async postEvent(event) {
441
+ if (!this.isEnabled) return {};
439
442
  const result = {};
440
443
  this.logger.debug(`[${event.type}] Posting event`, { event });
441
444
  const processedEvent = this.processEventForApi(event);
@@ -598,6 +601,7 @@ var EventBus = class _EventBus {
598
601
  };
599
602
 
600
603
  export {
604
+ DEFAULT_TEMPERATURE,
601
605
  scenarioProjectConfigSchema,
602
606
  defineConfig,
603
607
  AgentRole,
@@ -606,8 +610,8 @@ export {
606
610
  UserSimulatorAgentAdapter,
607
611
  JudgeAgentAdapter,
608
612
  domain_exports,
609
- loadScenarioProjectConfig,
610
613
  Logger,
614
+ env,
611
615
  getProjectConfig,
612
616
  generateThreadId,
613
617
  generateScenarioRunId,
package/dist/index.d.mts CHANGED
@@ -337,6 +337,8 @@ interface ScenarioExecutionStateLike {
337
337
  hasToolCall(toolName: string): boolean;
338
338
  }
339
339
 
340
+ /** Default temperature for language model inference */
341
+ declare const DEFAULT_TEMPERATURE = 0;
340
342
  declare const scenarioProjectConfigSchema: z.ZodObject<{
341
343
  defaultModel: z.ZodOptional<z.ZodObject<{
342
344
  model: z.ZodType<ai.LanguageModelV1, z.ZodTypeDef, ai.LanguageModelV1>;
@@ -351,24 +353,18 @@ declare const scenarioProjectConfigSchema: z.ZodObject<{
351
353
  temperature?: number | undefined;
352
354
  maxTokens?: number | undefined;
353
355
  }>>;
354
- langwatchEndpoint: z.ZodOptional<z.ZodString>;
355
- langwatchApiKey: z.ZodOptional<z.ZodString>;
356
356
  }, "strict", z.ZodTypeAny, {
357
357
  defaultModel?: {
358
358
  model: ai.LanguageModelV1;
359
359
  temperature: number;
360
360
  maxTokens?: number | undefined;
361
361
  } | undefined;
362
- langwatchEndpoint?: string | undefined;
363
- langwatchApiKey?: string | undefined;
364
362
  }, {
365
363
  defaultModel?: {
366
364
  model: ai.LanguageModelV1;
367
365
  temperature?: number | undefined;
368
366
  maxTokens?: number | undefined;
369
367
  } | undefined;
370
- langwatchEndpoint?: string | undefined;
371
- langwatchApiKey?: string | undefined;
372
368
  }>;
373
369
  type ScenarioProjectConfig = z.infer<typeof scenarioProjectConfigSchema>;
374
370
  declare function defineConfig(config: ScenarioProjectConfig): ScenarioProjectConfig;
@@ -400,6 +396,14 @@ interface TestingAgentConfig extends TestingAgentInferenceConfig {
400
396
  * The name of the agent.
401
397
  */
402
398
  name?: string;
399
+ /**
400
+ * System prompt to use for the agent.
401
+ *
402
+ * Useful in more complex scenarios where you want to set the system prompt
403
+ * for the agent directly. If left blank, this will be automatically generated
404
+ * from the scenario description.
405
+ */
406
+ systemPrompt?: string;
403
407
  }
404
408
  /**
405
409
  * The arguments for finishing a test, used by the judge agent's tool.
@@ -502,8 +506,17 @@ declare const judgeAgent: (cfg: JudgeAgentConfig) => {
502
506
  *
503
507
  * @param config Optional configuration for the agent.
504
508
  * @param config.model The language model to use for generating responses.
505
- * @param config.temperature The temperature to use for the model.
509
+ * If not provided, a default model will be used.
510
+ * @param config.temperature The temperature for the language model (0.0-1.0).
511
+ * Lower values make responses more deterministic.
512
+ * Defaults to {@link DEFAULT_TEMPERATURE}.
506
513
  * @param config.maxTokens The maximum number of tokens to generate.
514
+ * If not provided, uses model defaults.
515
+ * @param config.name The name of the agent.
516
+ * @param config.systemPrompt Custom system prompt to override default user simulation behavior.
517
+ * Use this to create specialized user personas or behaviors.
518
+ *
519
+ * @throws {Error} If no model is configured either in parameters or global config.
507
520
  *
508
521
  * @example
509
522
  * ```typescript
@@ -517,7 +530,8 @@ declare const judgeAgent: (cfg: JudgeAgentConfig) => {
517
530
  * };
518
531
  *
519
532
  * async function main() {
520
- * const result = await run({
533
+ * // Basic user simulator with default behavior
534
+ * const basicResult = await run({
521
535
  * name: "User Simulator Test",
522
536
  * description: "A simple test to see if the user simulator works.",
523
537
  * agents: [myAgent, userSimulatorAgent()],
@@ -526,9 +540,50 @@ declare const judgeAgent: (cfg: JudgeAgentConfig) => {
526
540
  * agent(),
527
541
  * ],
528
542
  * });
543
+ *
544
+ * // Customized user simulator
545
+ * const customResult = await run({
546
+ * name: "Expert User Test",
547
+ * description: "User seeks help with TypeScript programming",
548
+ * agents: [
549
+ * myAgent,
550
+ * userSimulatorAgent({
551
+ * model: openai("gpt-4"),
552
+ * temperature: 0.3,
553
+ * systemPrompt: "You are a technical user who asks detailed questions"
554
+ * })
555
+ * ],
556
+ * script: [
557
+ * user(),
558
+ * agent(),
559
+ * ],
560
+ * });
561
+ *
562
+ * // User simulator with custom persona
563
+ * const expertResult = await run({
564
+ * name: "Expert Developer Test",
565
+ * description: "Testing with a technical expert user persona.",
566
+ * agents: [
567
+ * myAgent,
568
+ * userSimulatorAgent({
569
+ * systemPrompt: `
570
+ * You are an expert software developer testing an AI coding assistant.
571
+ * Ask challenging, technical questions and be demanding about code quality.
572
+ * Use technical jargon and expect detailed, accurate responses.
573
+ * `
574
+ * })
575
+ * ],
576
+ * script: [
577
+ * user(),
578
+ * agent(),
579
+ * ],
580
+ * });
529
581
  * }
530
582
  * main();
531
583
  * ```
584
+ *
585
+ * @note
586
+ * - Uses role reversal internally to work around LLM biases toward assistant roles
532
587
  */
533
588
  declare const userSimulatorAgent: (config?: TestingAgentConfig) => {
534
589
  role: AgentRole.USER;
@@ -1259,6 +1314,7 @@ declare const scenario: {
1259
1314
  ScenarioExecution: typeof ScenarioExecution;
1260
1315
  ScenarioExecutionState: typeof ScenarioExecutionState;
1261
1316
  defineConfig(config: ScenarioProjectConfig): ScenarioProjectConfig;
1317
+ DEFAULT_TEMPERATURE: 0;
1262
1318
  scenarioProjectConfigSchema: zod.ZodObject<{
1263
1319
  defaultModel: zod.ZodOptional<zod.ZodObject<{
1264
1320
  model: zod.ZodType<ai.LanguageModelV1, zod.ZodTypeDef, ai.LanguageModelV1>;
@@ -1273,24 +1329,18 @@ declare const scenario: {
1273
1329
  temperature?: number | undefined;
1274
1330
  maxTokens?: number | undefined;
1275
1331
  }>>;
1276
- langwatchEndpoint: zod.ZodOptional<zod.ZodString>;
1277
- langwatchApiKey: zod.ZodOptional<zod.ZodString>;
1278
1332
  }, "strict", zod.ZodTypeAny, {
1279
1333
  defaultModel?: {
1280
1334
  model: ai.LanguageModelV1;
1281
1335
  temperature: number;
1282
1336
  maxTokens?: number | undefined;
1283
1337
  } | undefined;
1284
- langwatchEndpoint?: string | undefined;
1285
- langwatchApiKey?: string | undefined;
1286
1338
  }, {
1287
1339
  defaultModel?: {
1288
1340
  model: ai.LanguageModelV1;
1289
1341
  temperature?: number | undefined;
1290
1342
  maxTokens?: number | undefined;
1291
1343
  } | undefined;
1292
- langwatchEndpoint?: string | undefined;
1293
- langwatchApiKey?: string | undefined;
1294
1344
  }>;
1295
1345
  AgentRole: typeof AgentRole;
1296
1346
  allAgentRoles: readonly [AgentRole.USER, AgentRole.AGENT, AgentRole.JUDGE];
@@ -1317,4 +1367,4 @@ declare const scenario: {
1317
1367
  };
1318
1368
  };
1319
1369
 
1320
- export { AgentAdapter, type AgentInput, type AgentReturnTypes, AgentRole, type FinishTestArgs, JudgeAgentAdapter, type JudgeAgentConfig, type ScenarioConfig, type ScenarioConfigFinal, ScenarioExecution, type ScenarioExecutionLike, ScenarioExecutionState, type ScenarioExecutionStateLike, type ScenarioProjectConfig, type ScenarioResult, type ScriptStep, type TestingAgentConfig, type TestingAgentInferenceConfig, UserSimulatorAgentAdapter, agent, allAgentRoles, scenario as default, defineConfig, fail, judge, judgeAgent, message, proceed, run, scenario, scenarioProjectConfigSchema, succeed, user, userSimulatorAgent };
1370
+ export { AgentAdapter, type AgentInput, type AgentReturnTypes, AgentRole, DEFAULT_TEMPERATURE, type FinishTestArgs, JudgeAgentAdapter, type JudgeAgentConfig, type ScenarioConfig, type ScenarioConfigFinal, ScenarioExecution, type ScenarioExecutionLike, ScenarioExecutionState, type ScenarioExecutionStateLike, type ScenarioProjectConfig, type ScenarioResult, type ScriptStep, type TestingAgentConfig, type TestingAgentInferenceConfig, UserSimulatorAgentAdapter, agent, allAgentRoles, scenario as default, defineConfig, fail, judge, judgeAgent, message, proceed, run, scenario, scenarioProjectConfigSchema, succeed, user, userSimulatorAgent };
package/dist/index.d.ts CHANGED
@@ -337,6 +337,8 @@ interface ScenarioExecutionStateLike {
337
337
  hasToolCall(toolName: string): boolean;
338
338
  }
339
339
 
340
+ /** Default temperature for language model inference */
341
+ declare const DEFAULT_TEMPERATURE = 0;
340
342
  declare const scenarioProjectConfigSchema: z.ZodObject<{
341
343
  defaultModel: z.ZodOptional<z.ZodObject<{
342
344
  model: z.ZodType<ai.LanguageModelV1, z.ZodTypeDef, ai.LanguageModelV1>;
@@ -351,24 +353,18 @@ declare const scenarioProjectConfigSchema: z.ZodObject<{
351
353
  temperature?: number | undefined;
352
354
  maxTokens?: number | undefined;
353
355
  }>>;
354
- langwatchEndpoint: z.ZodOptional<z.ZodString>;
355
- langwatchApiKey: z.ZodOptional<z.ZodString>;
356
356
  }, "strict", z.ZodTypeAny, {
357
357
  defaultModel?: {
358
358
  model: ai.LanguageModelV1;
359
359
  temperature: number;
360
360
  maxTokens?: number | undefined;
361
361
  } | undefined;
362
- langwatchEndpoint?: string | undefined;
363
- langwatchApiKey?: string | undefined;
364
362
  }, {
365
363
  defaultModel?: {
366
364
  model: ai.LanguageModelV1;
367
365
  temperature?: number | undefined;
368
366
  maxTokens?: number | undefined;
369
367
  } | undefined;
370
- langwatchEndpoint?: string | undefined;
371
- langwatchApiKey?: string | undefined;
372
368
  }>;
373
369
  type ScenarioProjectConfig = z.infer<typeof scenarioProjectConfigSchema>;
374
370
  declare function defineConfig(config: ScenarioProjectConfig): ScenarioProjectConfig;
@@ -400,6 +396,14 @@ interface TestingAgentConfig extends TestingAgentInferenceConfig {
400
396
  * The name of the agent.
401
397
  */
402
398
  name?: string;
399
+ /**
400
+ * System prompt to use for the agent.
401
+ *
402
+ * Useful in more complex scenarios where you want to set the system prompt
403
+ * for the agent directly. If left blank, this will be automatically generated
404
+ * from the scenario description.
405
+ */
406
+ systemPrompt?: string;
403
407
  }
404
408
  /**
405
409
  * The arguments for finishing a test, used by the judge agent's tool.
@@ -502,8 +506,17 @@ declare const judgeAgent: (cfg: JudgeAgentConfig) => {
502
506
  *
503
507
  * @param config Optional configuration for the agent.
504
508
  * @param config.model The language model to use for generating responses.
505
- * @param config.temperature The temperature to use for the model.
509
+ * If not provided, a default model will be used.
510
+ * @param config.temperature The temperature for the language model (0.0-1.0).
511
+ * Lower values make responses more deterministic.
512
+ * Defaults to {@link DEFAULT_TEMPERATURE}.
506
513
  * @param config.maxTokens The maximum number of tokens to generate.
514
+ * If not provided, uses model defaults.
515
+ * @param config.name The name of the agent.
516
+ * @param config.systemPrompt Custom system prompt to override default user simulation behavior.
517
+ * Use this to create specialized user personas or behaviors.
518
+ *
519
+ * @throws {Error} If no model is configured either in parameters or global config.
507
520
  *
508
521
  * @example
509
522
  * ```typescript
@@ -517,7 +530,8 @@ declare const judgeAgent: (cfg: JudgeAgentConfig) => {
517
530
  * };
518
531
  *
519
532
  * async function main() {
520
- * const result = await run({
533
+ * // Basic user simulator with default behavior
534
+ * const basicResult = await run({
521
535
  * name: "User Simulator Test",
522
536
  * description: "A simple test to see if the user simulator works.",
523
537
  * agents: [myAgent, userSimulatorAgent()],
@@ -526,9 +540,50 @@ declare const judgeAgent: (cfg: JudgeAgentConfig) => {
526
540
  * agent(),
527
541
  * ],
528
542
  * });
543
+ *
544
+ * // Customized user simulator
545
+ * const customResult = await run({
546
+ * name: "Expert User Test",
547
+ * description: "User seeks help with TypeScript programming",
548
+ * agents: [
549
+ * myAgent,
550
+ * userSimulatorAgent({
551
+ * model: openai("gpt-4"),
552
+ * temperature: 0.3,
553
+ * systemPrompt: "You are a technical user who asks detailed questions"
554
+ * })
555
+ * ],
556
+ * script: [
557
+ * user(),
558
+ * agent(),
559
+ * ],
560
+ * });
561
+ *
562
+ * // User simulator with custom persona
563
+ * const expertResult = await run({
564
+ * name: "Expert Developer Test",
565
+ * description: "Testing with a technical expert user persona.",
566
+ * agents: [
567
+ * myAgent,
568
+ * userSimulatorAgent({
569
+ * systemPrompt: `
570
+ * You are an expert software developer testing an AI coding assistant.
571
+ * Ask challenging, technical questions and be demanding about code quality.
572
+ * Use technical jargon and expect detailed, accurate responses.
573
+ * `
574
+ * })
575
+ * ],
576
+ * script: [
577
+ * user(),
578
+ * agent(),
579
+ * ],
580
+ * });
529
581
  * }
530
582
  * main();
531
583
  * ```
584
+ *
585
+ * @note
586
+ * - Uses role reversal internally to work around LLM biases toward assistant roles
532
587
  */
533
588
  declare const userSimulatorAgent: (config?: TestingAgentConfig) => {
534
589
  role: AgentRole.USER;
@@ -1259,6 +1314,7 @@ declare const scenario: {
1259
1314
  ScenarioExecution: typeof ScenarioExecution;
1260
1315
  ScenarioExecutionState: typeof ScenarioExecutionState;
1261
1316
  defineConfig(config: ScenarioProjectConfig): ScenarioProjectConfig;
1317
+ DEFAULT_TEMPERATURE: 0;
1262
1318
  scenarioProjectConfigSchema: zod.ZodObject<{
1263
1319
  defaultModel: zod.ZodOptional<zod.ZodObject<{
1264
1320
  model: zod.ZodType<ai.LanguageModelV1, zod.ZodTypeDef, ai.LanguageModelV1>;
@@ -1273,24 +1329,18 @@ declare const scenario: {
1273
1329
  temperature?: number | undefined;
1274
1330
  maxTokens?: number | undefined;
1275
1331
  }>>;
1276
- langwatchEndpoint: zod.ZodOptional<zod.ZodString>;
1277
- langwatchApiKey: zod.ZodOptional<zod.ZodString>;
1278
1332
  }, "strict", zod.ZodTypeAny, {
1279
1333
  defaultModel?: {
1280
1334
  model: ai.LanguageModelV1;
1281
1335
  temperature: number;
1282
1336
  maxTokens?: number | undefined;
1283
1337
  } | undefined;
1284
- langwatchEndpoint?: string | undefined;
1285
- langwatchApiKey?: string | undefined;
1286
1338
  }, {
1287
1339
  defaultModel?: {
1288
1340
  model: ai.LanguageModelV1;
1289
1341
  temperature?: number | undefined;
1290
1342
  maxTokens?: number | undefined;
1291
1343
  } | undefined;
1292
- langwatchEndpoint?: string | undefined;
1293
- langwatchApiKey?: string | undefined;
1294
1344
  }>;
1295
1345
  AgentRole: typeof AgentRole;
1296
1346
  allAgentRoles: readonly [AgentRole.USER, AgentRole.AGENT, AgentRole.JUDGE];
@@ -1317,4 +1367,4 @@ declare const scenario: {
1317
1367
  };
1318
1368
  };
1319
1369
 
1320
- export { AgentAdapter, type AgentInput, type AgentReturnTypes, AgentRole, type FinishTestArgs, JudgeAgentAdapter, type JudgeAgentConfig, type ScenarioConfig, type ScenarioConfigFinal, ScenarioExecution, type ScenarioExecutionLike, ScenarioExecutionState, type ScenarioExecutionStateLike, type ScenarioProjectConfig, type ScenarioResult, type ScriptStep, type TestingAgentConfig, type TestingAgentInferenceConfig, UserSimulatorAgentAdapter, agent, allAgentRoles, scenario as default, defineConfig, fail, judge, judgeAgent, message, proceed, run, scenario, scenarioProjectConfigSchema, succeed, user, userSimulatorAgent };
1370
+ export { AgentAdapter, type AgentInput, type AgentReturnTypes, AgentRole, DEFAULT_TEMPERATURE, type FinishTestArgs, JudgeAgentAdapter, type JudgeAgentConfig, type ScenarioConfig, type ScenarioConfigFinal, ScenarioExecution, type ScenarioExecutionLike, ScenarioExecutionState, type ScenarioExecutionStateLike, type ScenarioProjectConfig, type ScenarioResult, type ScriptStep, type TestingAgentConfig, type TestingAgentInferenceConfig, UserSimulatorAgentAdapter, agent, allAgentRoles, scenario as default, defineConfig, fail, judge, judgeAgent, message, proceed, run, scenario, scenarioProjectConfigSchema, succeed, user, userSimulatorAgent };
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  AgentAdapter: () => AgentAdapter,
34
34
  AgentRole: () => AgentRole,
35
+ DEFAULT_TEMPERATURE: () => DEFAULT_TEMPERATURE,
35
36
  JudgeAgentAdapter: () => JudgeAgentAdapter,
36
37
  ScenarioExecution: () => ScenarioExecution,
37
38
  ScenarioExecutionState: () => ScenarioExecutionState,
@@ -70,6 +71,7 @@ var domain_exports = {};
70
71
  __export(domain_exports, {
71
72
  AgentAdapter: () => AgentAdapter,
72
73
  AgentRole: () => AgentRole,
74
+ DEFAULT_TEMPERATURE: () => DEFAULT_TEMPERATURE,
73
75
  JudgeAgentAdapter: () => JudgeAgentAdapter,
74
76
  UserSimulatorAgentAdapter: () => UserSimulatorAgentAdapter,
75
77
  allAgentRoles: () => allAgentRoles,
@@ -79,14 +81,13 @@ __export(domain_exports, {
79
81
 
80
82
  // src/domain/core/config.ts
81
83
  var import_zod = require("zod");
84
+ var DEFAULT_TEMPERATURE = 0;
82
85
  var scenarioProjectConfigSchema = import_zod.z.object({
83
86
  defaultModel: import_zod.z.object({
84
87
  model: import_zod.z.custom(),
85
- temperature: import_zod.z.number().min(0).max(1).optional().default(0),
88
+ temperature: import_zod.z.number().min(0).max(1).optional().default(DEFAULT_TEMPERATURE),
86
89
  maxTokens: import_zod.z.number().optional()
87
- }).optional(),
88
- langwatchEndpoint: import_zod.z.string().optional(),
89
- langwatchApiKey: import_zod.z.string().optional()
90
+ }).optional()
90
91
  }).strict();
91
92
  function defineConfig(config2) {
92
93
  return config2;
@@ -534,7 +535,7 @@ var userSimulatorAgent = (config2) => {
534
535
  return {
535
536
  role: "User" /* USER */,
536
537
  call: async (input) => {
537
- const systemPrompt = buildSystemPrompt2(input.scenarioConfig.description);
538
+ const systemPrompt = (config2 == null ? void 0 : config2.systemPrompt) ?? buildSystemPrompt2(input.scenarioConfig.description);
538
539
  const messages = [
539
540
  { role: "system", content: systemPrompt },
540
541
  { role: "assistant", content: "Hello, how can I help you today" },
@@ -549,7 +550,7 @@ var userSimulatorAgent = (config2) => {
549
550
  const completion = await (0, import_ai2.generateText)({
550
551
  model: mergedConfig.model,
551
552
  messages: reversedMessages,
552
- temperature: mergedConfig.temperature ?? 0,
553
+ temperature: mergedConfig.temperature ?? DEFAULT_TEMPERATURE,
553
554
  maxTokens: mergedConfig.maxTokens
554
555
  });
555
556
  const messageContent = completion.text;
@@ -735,6 +736,77 @@ var stateSchema = import_zod4.z.object({
735
736
  var runsSchema = import_zod4.z.object({ runs: import_zod4.z.array(import_zod4.z.string()) });
736
737
  var eventsSchema = import_zod4.z.object({ events: import_zod4.z.array(scenarioEventSchema) });
737
738
 
739
+ // src/utils/message-conversion.ts
740
+ function convertCoreMessagesToAguiMessages(coreMessages) {
741
+ const aguiMessages = [];
742
+ for (const msg of coreMessages) {
743
+ const id = "id" in msg && typeof msg.id === "string" ? msg.id : generateMessageId();
744
+ switch (true) {
745
+ case msg.role === "system":
746
+ aguiMessages.push({
747
+ id,
748
+ role: "system",
749
+ content: msg.content
750
+ });
751
+ break;
752
+ case (msg.role === "user" && typeof msg.content === "string"):
753
+ aguiMessages.push({
754
+ id,
755
+ role: "user",
756
+ content: msg.content
757
+ });
758
+ break;
759
+ // Handle any other user message content format
760
+ case (msg.role === "user" && Array.isArray(msg.content)):
761
+ aguiMessages.push({
762
+ id,
763
+ role: "user",
764
+ content: JSON.stringify(msg.content)
765
+ });
766
+ break;
767
+ case (msg.role === "assistant" && typeof msg.content === "string"):
768
+ aguiMessages.push({
769
+ id,
770
+ role: "assistant",
771
+ content: msg.content
772
+ });
773
+ break;
774
+ case (msg.role === "assistant" && Array.isArray(msg.content)): {
775
+ const toolCalls = msg.content.filter((p) => p.type === "tool-call");
776
+ const nonToolCalls = msg.content.filter((p) => p.type !== "tool-call");
777
+ aguiMessages.push({
778
+ id,
779
+ role: "assistant",
780
+ content: JSON.stringify(nonToolCalls),
781
+ toolCalls: toolCalls.map((c) => ({
782
+ id: c.toolCallId,
783
+ type: "function",
784
+ function: {
785
+ name: c.toolName,
786
+ arguments: JSON.stringify(c.args)
787
+ }
788
+ }))
789
+ });
790
+ break;
791
+ }
792
+ case msg.role === "tool":
793
+ msg.content.map((p, i) => {
794
+ aguiMessages.push({
795
+ id: `${id}-${i}`,
796
+ role: "tool",
797
+ toolCallId: p.toolCallId,
798
+ content: JSON.stringify(p.result)
799
+ });
800
+ });
801
+ break;
802
+ default:
803
+ throw new Error(`Unsupported message role: ${msg.role}`);
804
+ }
805
+ }
806
+ return aguiMessages;
807
+ }
808
+ var message_conversion_default = convertCoreMessagesToAguiMessages;
809
+
738
810
  // src/execution/scenario-execution.ts
739
811
  var batchRunId = getBatchRunId();
740
812
  var ScenarioExecution = class {
@@ -1174,7 +1246,7 @@ var ScenarioExecution = class {
1174
1246
  this.emitEvent({
1175
1247
  ...this.makeBaseEvent({ scenarioRunId }),
1176
1248
  type: "SCENARIO_MESSAGE_SNAPSHOT" /* MESSAGE_SNAPSHOT */,
1177
- messages: this.state.messages
1249
+ messages: message_conversion_default(this.state.messages)
1178
1250
  // Add any other required fields from MessagesSnapshotEventSchema
1179
1251
  });
1180
1252
  }
@@ -1324,17 +1396,20 @@ var EventReporter = class {
1324
1396
  eventsEndpoint;
1325
1397
  eventAlertMessageLogger;
1326
1398
  logger = new Logger("scenario.events.EventReporter");
1399
+ isEnabled;
1327
1400
  constructor(config2) {
1328
1401
  this.apiKey = config2.apiKey ?? "";
1329
1402
  this.eventsEndpoint = new URL("/api/scenario-events", config2.endpoint);
1330
1403
  this.eventAlertMessageLogger = new EventAlertMessageLogger();
1331
1404
  this.eventAlertMessageLogger.handleGreeting();
1405
+ this.isEnabled = this.apiKey.length > 0 && this.eventsEndpoint.href.length > 0;
1332
1406
  }
1333
1407
  /**
1334
1408
  * Posts an event to the configured endpoint.
1335
1409
  * Logs success/failure but doesn't throw - event posting shouldn't break scenario execution.
1336
1410
  */
1337
1411
  async postEvent(event) {
1412
+ if (!this.isEnabled) return {};
1338
1413
  const result = {};
1339
1414
  this.logger.debug(`[${event.type}] Posting event`, { event });
1340
1415
  const processedEvent = this.processEventForApi(event);
@@ -1559,10 +1634,9 @@ async function run(cfg) {
1559
1634
  let eventBus = null;
1560
1635
  let subscription = null;
1561
1636
  try {
1562
- const projectConfig = await loadScenarioProjectConfig();
1563
1637
  eventBus = new EventBus({
1564
- endpoint: projectConfig.langwatchEndpoint ?? process.env.LANGWATCH_ENDPOINT ?? "https://app.langwatch.ai",
1565
- apiKey: projectConfig.langwatchApiKey ?? process.env.LANGWATCH_API_KEY
1638
+ endpoint: env.LANGWATCH_ENDPOINT,
1639
+ apiKey: env.LANGWATCH_API_KEY
1566
1640
  });
1567
1641
  eventBus.listen();
1568
1642
  subscription = eventBus.subscribeTo(execution.events$);
@@ -1638,6 +1712,7 @@ var index_default = scenario;
1638
1712
  0 && (module.exports = {
1639
1713
  AgentAdapter,
1640
1714
  AgentRole,
1715
+ DEFAULT_TEMPERATURE,
1641
1716
  JudgeAgentAdapter,
1642
1717
  ScenarioExecution,
1643
1718
  ScenarioExecutionState,
package/dist/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  AgentAdapter,
3
3
  AgentRole,
4
+ DEFAULT_TEMPERATURE,
4
5
  EventBus,
5
6
  JudgeAgentAdapter,
6
7
  Logger,
@@ -8,15 +9,15 @@ import {
8
9
  allAgentRoles,
9
10
  defineConfig,
10
11
  domain_exports,
12
+ env,
11
13
  generateMessageId,
12
14
  generateScenarioId,
13
15
  generateScenarioRunId,
14
16
  generateThreadId,
15
17
  getBatchRunId,
16
18
  getProjectConfig,
17
- loadScenarioProjectConfig,
18
19
  scenarioProjectConfigSchema
19
- } from "./chunk-ZMHTHRDR.mjs";
20
+ } from "./chunk-NUZZAQV2.mjs";
20
21
  import {
21
22
  __export
22
23
  } from "./chunk-7P6ASYW6.mjs";
@@ -268,7 +269,7 @@ var userSimulatorAgent = (config) => {
268
269
  return {
269
270
  role: "User" /* USER */,
270
271
  call: async (input) => {
271
- const systemPrompt = buildSystemPrompt2(input.scenarioConfig.description);
272
+ const systemPrompt = (config == null ? void 0 : config.systemPrompt) ?? buildSystemPrompt2(input.scenarioConfig.description);
272
273
  const messages = [
273
274
  { role: "system", content: systemPrompt },
274
275
  { role: "assistant", content: "Hello, how can I help you today" },
@@ -283,7 +284,7 @@ var userSimulatorAgent = (config) => {
283
284
  const completion = await generateText2({
284
285
  model: mergedConfig.model,
285
286
  messages: reversedMessages,
286
- temperature: mergedConfig.temperature ?? 0,
287
+ temperature: mergedConfig.temperature ?? DEFAULT_TEMPERATURE,
287
288
  maxTokens: mergedConfig.maxTokens
288
289
  });
289
290
  const messageContent = completion.text;
@@ -376,6 +377,77 @@ var ScenarioExecutionState = class {
376
377
  }
377
378
  };
378
379
 
380
+ // src/utils/message-conversion.ts
381
+ function convertCoreMessagesToAguiMessages(coreMessages) {
382
+ const aguiMessages = [];
383
+ for (const msg of coreMessages) {
384
+ const id = "id" in msg && typeof msg.id === "string" ? msg.id : generateMessageId();
385
+ switch (true) {
386
+ case msg.role === "system":
387
+ aguiMessages.push({
388
+ id,
389
+ role: "system",
390
+ content: msg.content
391
+ });
392
+ break;
393
+ case (msg.role === "user" && typeof msg.content === "string"):
394
+ aguiMessages.push({
395
+ id,
396
+ role: "user",
397
+ content: msg.content
398
+ });
399
+ break;
400
+ // Handle any other user message content format
401
+ case (msg.role === "user" && Array.isArray(msg.content)):
402
+ aguiMessages.push({
403
+ id,
404
+ role: "user",
405
+ content: JSON.stringify(msg.content)
406
+ });
407
+ break;
408
+ case (msg.role === "assistant" && typeof msg.content === "string"):
409
+ aguiMessages.push({
410
+ id,
411
+ role: "assistant",
412
+ content: msg.content
413
+ });
414
+ break;
415
+ case (msg.role === "assistant" && Array.isArray(msg.content)): {
416
+ const toolCalls = msg.content.filter((p) => p.type === "tool-call");
417
+ const nonToolCalls = msg.content.filter((p) => p.type !== "tool-call");
418
+ aguiMessages.push({
419
+ id,
420
+ role: "assistant",
421
+ content: JSON.stringify(nonToolCalls),
422
+ toolCalls: toolCalls.map((c) => ({
423
+ id: c.toolCallId,
424
+ type: "function",
425
+ function: {
426
+ name: c.toolName,
427
+ arguments: JSON.stringify(c.args)
428
+ }
429
+ }))
430
+ });
431
+ break;
432
+ }
433
+ case msg.role === "tool":
434
+ msg.content.map((p, i) => {
435
+ aguiMessages.push({
436
+ id: `${id}-${i}`,
437
+ role: "tool",
438
+ toolCallId: p.toolCallId,
439
+ content: JSON.stringify(p.result)
440
+ });
441
+ });
442
+ break;
443
+ default:
444
+ throw new Error(`Unsupported message role: ${msg.role}`);
445
+ }
446
+ }
447
+ return aguiMessages;
448
+ }
449
+ var message_conversion_default = convertCoreMessagesToAguiMessages;
450
+
379
451
  // src/execution/scenario-execution.ts
380
452
  var batchRunId = getBatchRunId();
381
453
  var ScenarioExecution = class {
@@ -815,7 +887,7 @@ var ScenarioExecution = class {
815
887
  this.emitEvent({
816
888
  ...this.makeBaseEvent({ scenarioRunId }),
817
889
  type: "SCENARIO_MESSAGE_SNAPSHOT" /* MESSAGE_SNAPSHOT */,
818
- messages: this.state.messages
890
+ messages: message_conversion_default(this.state.messages)
819
891
  // Add any other required fields from MessagesSnapshotEventSchema
820
892
  });
821
893
  }
@@ -938,10 +1010,9 @@ async function run(cfg) {
938
1010
  let eventBus = null;
939
1011
  let subscription = null;
940
1012
  try {
941
- const projectConfig = await loadScenarioProjectConfig();
942
1013
  eventBus = new EventBus({
943
- endpoint: projectConfig.langwatchEndpoint ?? process.env.LANGWATCH_ENDPOINT ?? "https://app.langwatch.ai",
944
- apiKey: projectConfig.langwatchApiKey ?? process.env.LANGWATCH_API_KEY
1014
+ endpoint: env.LANGWATCH_ENDPOINT,
1015
+ apiKey: env.LANGWATCH_API_KEY
945
1016
  });
946
1017
  eventBus.listen();
947
1018
  subscription = eventBus.subscribeTo(execution.events$);
@@ -1016,6 +1087,7 @@ var index_default = scenario;
1016
1087
  export {
1017
1088
  AgentAdapter,
1018
1089
  AgentRole,
1090
+ DEFAULT_TEMPERATURE,
1019
1091
  JudgeAgentAdapter,
1020
1092
  ScenarioExecution,
1021
1093
  ScenarioExecutionState,
@@ -37,14 +37,13 @@ var import_node_url = require("url");
37
37
 
38
38
  // src/domain/core/config.ts
39
39
  var import_zod = require("zod");
40
+ var DEFAULT_TEMPERATURE = 0;
40
41
  var scenarioProjectConfigSchema = import_zod.z.object({
41
42
  defaultModel: import_zod.z.object({
42
43
  model: import_zod.z.custom(),
43
- temperature: import_zod.z.number().min(0).max(1).optional().default(0),
44
+ temperature: import_zod.z.number().min(0).max(1).optional().default(DEFAULT_TEMPERATURE),
44
45
  maxTokens: import_zod.z.number().optional()
45
- }).optional(),
46
- langwatchEndpoint: import_zod.z.string().optional(),
47
- langwatchApiKey: import_zod.z.string().optional()
46
+ }).optional()
48
47
  }).strict();
49
48
 
50
49
  // src/utils/logger.ts
@@ -335,17 +334,20 @@ var EventReporter = class {
335
334
  eventsEndpoint;
336
335
  eventAlertMessageLogger;
337
336
  logger = new Logger("scenario.events.EventReporter");
337
+ isEnabled;
338
338
  constructor(config) {
339
339
  this.apiKey = config.apiKey ?? "";
340
340
  this.eventsEndpoint = new URL("/api/scenario-events", config.endpoint);
341
341
  this.eventAlertMessageLogger = new EventAlertMessageLogger();
342
342
  this.eventAlertMessageLogger.handleGreeting();
343
+ this.isEnabled = this.apiKey.length > 0 && this.eventsEndpoint.href.length > 0;
343
344
  }
344
345
  /**
345
346
  * Posts an event to the configured endpoint.
346
347
  * Logs success/failure but doesn't throw - event posting shouldn't break scenario execution.
347
348
  */
348
349
  async postEvent(event) {
350
+ if (!this.isEnabled) return {};
349
351
  const result = {};
350
352
  this.logger.debug(`[${event.type}] Posting event`, { event });
351
353
  const processedEvent = this.processEventForApi(event);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  EventBus
3
- } from "../../chunk-ZMHTHRDR.mjs";
3
+ } from "../../chunk-NUZZAQV2.mjs";
4
4
  import "../../chunk-7P6ASYW6.mjs";
5
5
 
6
6
  // src/integrations/vitest/setup.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langwatch/scenario",
3
- "version": "0.2.1",
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",
@@ -85,6 +85,7 @@
85
85
  "test:ci": "vitest run",
86
86
  "lint": "eslint .",
87
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
- "generate:api-reference": "npx typedoc src --out api-reference-docs"
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
  }