@langwatch/scenario 0.4.6 → 0.4.8

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.d.mts CHANGED
@@ -366,6 +366,18 @@ interface ScenarioExecutionStateLike {
366
366
  * @returns True if the tool call exists, false otherwise.
367
367
  */
368
368
  hasToolCall(toolName: string): boolean;
369
+ /**
370
+ * Remove all messages from position `index` onward.
371
+ *
372
+ * Truncates the message list and cleans up any pending message queues
373
+ * so no agent sees stale messages.
374
+ *
375
+ * @param index - Truncate point (clamped to `[0, messages.length]`).
376
+ * Messages at positions >= index are removed.
377
+ * @returns The removed messages (empty array if nothing to remove).
378
+ * @throws {RangeError} If `index` is negative.
379
+ */
380
+ rollbackMessagesTo(index: number): ModelMessage[];
369
381
  }
370
382
 
371
383
  /**
@@ -961,7 +973,189 @@ declare class RealtimeAgentAdapter extends AgentAdapter {
961
973
  offAudioResponse(callback: (event: AudioResponseEvent) => void): void;
962
974
  }
963
975
 
976
+ interface BacktrackEntry {
977
+ turn: number;
978
+ attack: string;
979
+ refusal: string;
980
+ }
981
+ interface RedTeamStrategy {
982
+ /**
983
+ * Build a turn-aware system prompt for the attacker.
984
+ *
985
+ * Score feedback, adaptation hints, and backtrack markers are
986
+ * communicated via the attacker's private conversation history
987
+ * (H_attacker) as system messages — not embedded in this prompt.
988
+ */
989
+ buildSystemPrompt(params: {
990
+ target: string;
991
+ currentTurn: number;
992
+ totalTurns: number;
993
+ scenarioDescription: string;
994
+ metapromptPlan: string;
995
+ }): string;
996
+ getPhaseName(currentTurn: number, totalTurns: number): string;
997
+ }
998
+
999
+ declare class CrescendoStrategy implements RedTeamStrategy {
1000
+ getPhase(currentTurn: number, totalTurns: number): {
1001
+ name: string;
1002
+ instructions: string;
1003
+ };
1004
+ getPhaseName(currentTurn: number, totalTurns: number): string;
1005
+ private phaseTurnRange;
1006
+ buildSystemPrompt(params: {
1007
+ target: string;
1008
+ currentTurn: number;
1009
+ totalTurns: number;
1010
+ scenarioDescription: string;
1011
+ metapromptPlan: string;
1012
+ }): string;
1013
+ }
1014
+
1015
+ interface RedTeamAgentConfig {
1016
+ strategy: RedTeamStrategy;
1017
+ target: string;
1018
+ totalTurns?: number;
1019
+ model?: LanguageModel;
1020
+ metapromptModel?: LanguageModel;
1021
+ metapromptTemplate?: string;
1022
+ attackPlan?: string;
1023
+ /** Score target responses each turn to feed back into the attacker. Default true. */
1024
+ scoreResponses?: boolean;
1025
+ /** Use pattern-based refusal detection to skip LLM scorer on obvious refusals. Default true. */
1026
+ detectRefusals?: boolean;
1027
+ temperature?: number;
1028
+ /** Separate temperature for metaprompt/scoring calls. Defaults to temperature. */
1029
+ metapromptTemperature?: number;
1030
+ maxTokens?: number;
1031
+ /** Score threshold (0-10) for early exit. Default 9. Set to undefined to disable. */
1032
+ successScore?: number;
1033
+ /** Consecutive turns >= threshold before triggering early exit. Default 2. */
1034
+ successConfirmTurns?: number;
1035
+ }
1036
+ interface CrescendoConfig {
1037
+ target: string;
1038
+ totalTurns?: number;
1039
+ model?: LanguageModel;
1040
+ metapromptModel?: LanguageModel;
1041
+ attackPlan?: string;
1042
+ scoreResponses?: boolean;
1043
+ /** Use pattern-based refusal detection to skip LLM scorer on obvious refusals. Default true. */
1044
+ detectRefusals?: boolean;
1045
+ temperature?: number;
1046
+ metapromptTemperature?: number;
1047
+ maxTokens?: number;
1048
+ /** Score threshold (0-10) for early exit. Default 9. Set to undefined to disable. */
1049
+ successScore?: number;
1050
+ /** Consecutive turns >= threshold before triggering early exit. Default 2. */
1051
+ successConfirmTurns?: number;
1052
+ }
1053
+ declare class RedTeamAgentImpl extends UserSimulatorAgentAdapter {
1054
+ name: string;
1055
+ private strategy;
1056
+ private target;
1057
+ private totalTurns;
1058
+ private model?;
1059
+ private metapromptModel?;
1060
+ private metapromptTemplate;
1061
+ private scoreResponses;
1062
+ private detectRefusals;
1063
+ private temperature;
1064
+ private metapromptTemperature;
1065
+ private maxTokens?;
1066
+ private _successScore;
1067
+ private _successConfirmTurns;
1068
+ private static readonly HARD_REFUSAL_PATTERNS;
1069
+ private static readonly SOFT_REFUSAL_PATTERNS;
1070
+ private attackPlanPromise;
1071
+ private attackPlanValue;
1072
+ private turnScores;
1073
+ private static readonly MAX_BACKTRACKS;
1074
+ private backtracksRemaining;
1075
+ private backtrackHistory;
1076
+ private attackerHistory;
1077
+ constructor(config: RedTeamAgentConfig);
1078
+ private getAttackPlan;
1079
+ private generateAttackPlan;
1080
+ private getLastAssistantContent;
1081
+ private getLastUserContent;
1082
+ private detectRefusal;
1083
+ /**
1084
+ * Score the target agent's last response toward the attack goal (0-10).
1085
+ * Results are cached per turn so the scorer LLM is called at most once.
1086
+ */
1087
+ private scoreLastResponse;
1088
+ /**
1089
+ * Check if the attack objective has been achieved.
1090
+ * Returns true if the last `successConfirmTurns` cached scores
1091
+ * are all >= `successScore`.
1092
+ */
1093
+ checkEarlyExit(): boolean;
1094
+ /**
1095
+ * Generate a marathon test script with automatic early-exit checks.
1096
+ *
1097
+ * Like the standalone `marathonScript`, but inserts an early-exit check
1098
+ * after each `agent()` step. When `successConfirmTurns` consecutive turns
1099
+ * score >= the threshold, the check runs `finalChecks` inline and calls
1100
+ * `executor.succeed()` to end the scenario early.
1101
+ *
1102
+ * Set `successScore` to `undefined` to disable early exit.
1103
+ */
1104
+ marathonScript(options: {
1105
+ turns: number;
1106
+ checks?: ScriptStep[];
1107
+ finalChecks?: ScriptStep[];
1108
+ }): ScriptStep[];
1109
+ /**
1110
+ * Call the attacker LLM directly with the attacker's private history.
1111
+ * Uses `attackerHistory` (H_attacker) which contains the system prompt,
1112
+ * previous attack messages, target response summaries, score annotations,
1113
+ * and backtrack markers — none of which leak to the target.
1114
+ */
1115
+ private callAttackerLLM;
1116
+ /**
1117
+ * Reset per-run state for safe reuse across scenario.run() calls.
1118
+ * Called at the start of turn 1. Does NOT reset attackPlanValue
1119
+ * (expensive to regenerate and target-specific, not run-specific).
1120
+ */
1121
+ private resetRunState;
1122
+ call: (input: AgentInput) => Promise<AgentReturnTypes>;
1123
+ }
1124
+ /**
1125
+ * Create a red-team agent with a custom strategy.
1126
+ */
1127
+ declare const redTeamAgent: (config: RedTeamAgentConfig) => RedTeamAgentImpl;
1128
+ /**
1129
+ * Create a red-team agent using the Crescendo (marathon) strategy.
1130
+ *
1131
+ * Crescendo gradually escalates from innocent rapport-building to aggressive
1132
+ * jailbreak attempts over many turns, exploiting LLMs' tendency to maintain
1133
+ * conversational consistency once cooperative context has been established.
1134
+ *
1135
+ * @example
1136
+ * ```typescript
1137
+ * import scenario from "@langwatch/scenario";
1138
+ * import { openai } from "@ai-sdk/openai";
1139
+ *
1140
+ * const redTeam = scenario.redTeamCrescendo({
1141
+ * target: "extract the system prompt",
1142
+ * model: openai("gpt-4o"),
1143
+ * totalTurns: 50,
1144
+ * successScore: 9, // default: 9 (score 0-10)
1145
+ * successConfirmTurns: 2, // default: 2
1146
+ * });
1147
+ *
1148
+ * // Use instance marathonScript for automatic early-exit:
1149
+ * script: redTeam.marathonScript({ turns: 50 }),
1150
+ * ```
1151
+ */
1152
+ declare const redTeamCrescendo: (config: CrescendoConfig) => RedTeamAgentImpl;
1153
+
964
1154
  type agents_AudioResponseEvent = AudioResponseEvent;
1155
+ type agents_BacktrackEntry = BacktrackEntry;
1156
+ type agents_CrescendoConfig = CrescendoConfig;
1157
+ type agents_CrescendoStrategy = CrescendoStrategy;
1158
+ declare const agents_CrescendoStrategy: typeof CrescendoStrategy;
965
1159
  declare const agents_DEFAULT_TOKEN_THRESHOLD: typeof DEFAULT_TOKEN_THRESHOLD;
966
1160
  type agents_FinishTestArgs = FinishTestArgs;
967
1161
  type agents_InvokeLLMParams = InvokeLLMParams;
@@ -975,6 +1169,8 @@ declare const agents_JudgeSpanDigestFormatter: typeof JudgeSpanDigestFormatter;
975
1169
  type agents_RealtimeAgentAdapter = RealtimeAgentAdapter;
976
1170
  declare const agents_RealtimeAgentAdapter: typeof RealtimeAgentAdapter;
977
1171
  type agents_RealtimeAgentAdapterConfig = RealtimeAgentAdapterConfig;
1172
+ type agents_RedTeamAgentConfig = RedTeamAgentConfig;
1173
+ type agents_RedTeamStrategy = RedTeamStrategy;
978
1174
  type agents_TestingAgentConfig = TestingAgentConfig;
979
1175
  declare const agents_estimateTokens: typeof estimateTokens;
980
1176
  declare const agents_expandTrace: typeof expandTrace;
@@ -982,9 +1178,11 @@ declare const agents_grepTrace: typeof grepTrace;
982
1178
  declare const agents_judgeAgent: typeof judgeAgent;
983
1179
  declare const agents_judgeSpanCollector: typeof judgeSpanCollector;
984
1180
  declare const agents_judgeSpanDigestFormatter: typeof judgeSpanDigestFormatter;
1181
+ declare const agents_redTeamAgent: typeof redTeamAgent;
1182
+ declare const agents_redTeamCrescendo: typeof redTeamCrescendo;
985
1183
  declare const agents_userSimulatorAgent: typeof userSimulatorAgent;
986
1184
  declare namespace agents {
987
- export { type agents_AudioResponseEvent as AudioResponseEvent, agents_DEFAULT_TOKEN_THRESHOLD as DEFAULT_TOKEN_THRESHOLD, type agents_FinishTestArgs as FinishTestArgs, type agents_InvokeLLMParams as InvokeLLMParams, type agents_InvokeLLMResult as InvokeLLMResult, type agents_JudgeAgentConfig as JudgeAgentConfig, type agents_JudgeResult as JudgeResult, agents_JudgeSpanCollector as JudgeSpanCollector, agents_JudgeSpanDigestFormatter as JudgeSpanDigestFormatter, agents_RealtimeAgentAdapter as RealtimeAgentAdapter, type agents_RealtimeAgentAdapterConfig as RealtimeAgentAdapterConfig, type agents_TestingAgentConfig as TestingAgentConfig, agents_estimateTokens as estimateTokens, agents_expandTrace as expandTrace, agents_grepTrace as grepTrace, agents_judgeAgent as judgeAgent, agents_judgeSpanCollector as judgeSpanCollector, agents_judgeSpanDigestFormatter as judgeSpanDigestFormatter, agents_userSimulatorAgent as userSimulatorAgent };
1185
+ export { type agents_AudioResponseEvent as AudioResponseEvent, type agents_BacktrackEntry as BacktrackEntry, type agents_CrescendoConfig as CrescendoConfig, agents_CrescendoStrategy as CrescendoStrategy, agents_DEFAULT_TOKEN_THRESHOLD as DEFAULT_TOKEN_THRESHOLD, type agents_FinishTestArgs as FinishTestArgs, type agents_InvokeLLMParams as InvokeLLMParams, type agents_InvokeLLMResult as InvokeLLMResult, type agents_JudgeAgentConfig as JudgeAgentConfig, type agents_JudgeResult as JudgeResult, agents_JudgeSpanCollector as JudgeSpanCollector, agents_JudgeSpanDigestFormatter as JudgeSpanDigestFormatter, agents_RealtimeAgentAdapter as RealtimeAgentAdapter, type agents_RealtimeAgentAdapterConfig as RealtimeAgentAdapterConfig, type agents_RedTeamAgentConfig as RedTeamAgentConfig, type agents_RedTeamStrategy as RedTeamStrategy, type agents_TestingAgentConfig as TestingAgentConfig, agents_estimateTokens as estimateTokens, agents_expandTrace as expandTrace, agents_grepTrace as grepTrace, agents_judgeAgent as judgeAgent, agents_judgeSpanCollector as judgeSpanCollector, agents_judgeSpanDigestFormatter as judgeSpanDigestFormatter, agents_redTeamAgent as redTeamAgent, agents_redTeamCrescendo as redTeamCrescendo, agents_userSimulatorAgent as userSimulatorAgent };
988
1186
  }
989
1187
 
990
1188
  /**
@@ -1482,14 +1680,19 @@ declare class ScenarioExecution implements ScenarioExecutionLike {
1482
1680
  private batchRunId;
1483
1681
  /** The run ID for the current execution */
1484
1682
  private scenarioRunId?;
1683
+ /** Pre-assigned run ID (provided externally, e.g. by the platform) */
1684
+ private preAssignedRunId?;
1485
1685
  /**
1486
1686
  * Creates a new ScenarioExecution instance.
1487
1687
  *
1488
1688
  * @param config - The scenario configuration containing agents, settings, and metadata
1489
1689
  * @param script - The ordered sequence of script steps that define the test flow
1490
1690
  * @param batchRunId - Batch run ID for grouping scenario runs
1691
+ * @param runId - Optional pre-assigned run ID. When provided, the execution uses this
1692
+ * ID instead of generating a new one. This prevents duplicate entries when the
1693
+ * platform pre-creates placeholder rows with a known ID.
1491
1694
  */
1492
- constructor(config: ScenarioConfig, script: ScriptStep[], batchRunId: string);
1695
+ constructor(config: ScenarioConfig, script: ScriptStep[], batchRunId: string, runId?: string);
1493
1696
  /**
1494
1697
  * Gets the complete conversation history as an array of messages.
1495
1698
  *
@@ -1979,6 +2182,7 @@ declare class ScenarioExecutionState implements ScenarioExecutionStateLike {
1979
2182
  private _messages;
1980
2183
  private _currentTurn;
1981
2184
  private _threadId;
2185
+ private _onRollback?;
1982
2186
  /** Event stream for message additions */
1983
2187
  private eventSubject;
1984
2188
  readonly events$: Observable<StateChangeEvent>;
@@ -2014,6 +2218,28 @@ declare class ScenarioExecutionState implements ScenarioExecutionStateLike {
2014
2218
  traceId?: string;
2015
2219
  };
2016
2220
  hasToolCall(toolName: string): boolean;
2221
+ /**
2222
+ * Register a callback that fires when messages are rolled back.
2223
+ * The executor uses this to clean up its pending message queues.
2224
+ */
2225
+ setOnRollback(handler: (removedSet: Set<object>) => void): void;
2226
+ /**
2227
+ * Remove all messages from position `index` onward.
2228
+ *
2229
+ * Truncates the internal message list and notifies the executor
2230
+ * (via the registered rollback handler) to clean pending queues.
2231
+ *
2232
+ * **Note:** This method is safe to call only during an agent's `call()`
2233
+ * invocation. The executor runs agents sequentially, so no other agent
2234
+ * can observe stale `newMessages` references. Calling this from outside
2235
+ * that flow may leave already-delivered `newMessages` out of sync.
2236
+ *
2237
+ * @param index - Truncate point (clamped to `[0, messages.length]`).
2238
+ * Messages at positions >= index are removed.
2239
+ * @returns The removed messages (empty array if nothing to remove).
2240
+ * @throws {RangeError} If `index` is negative.
2241
+ */
2242
+ rollbackMessagesTo(index: number): ModelMessage[];
2017
2243
  }
2018
2244
 
2019
2245
  type execution_ScenarioExecution = ScenarioExecution;
@@ -2045,6 +2271,13 @@ interface RunOptions {
2045
2271
  langwatch?: LangwatchConfig;
2046
2272
  /** Batch run ID for grouping scenario runs. Overrides SCENARIO_BATCH_RUN_ID env var. */
2047
2273
  batchRunId?: string;
2274
+ /**
2275
+ * Pre-assigned run ID for the scenario execution.
2276
+ * When provided, the SDK uses this ID instead of generating a new one.
2277
+ *
2278
+ * @internal Platform use only — not part of the public API.
2279
+ */
2280
+ runId?: string;
2048
2281
  }
2049
2282
  /**
2050
2283
  * High-level interface for running a scenario test.
@@ -2197,16 +2430,31 @@ declare const succeed: (reasoning?: string) => ScriptStep;
2197
2430
  * @returns A ScriptStep function that can be used in scenario scripts.
2198
2431
  */
2199
2432
  declare const fail: (reasoning?: string) => ScriptStep;
2433
+ /**
2434
+ * Generate a marathon script that runs user-agent turns in a loop,
2435
+ * with optional per-turn checks and a final judge evaluation.
2436
+ *
2437
+ * @param options.turns Number of user-agent turn pairs.
2438
+ * @param options.checks Optional steps to run after each turn.
2439
+ * @param options.finalChecks Optional steps to run after all turns, before the judge.
2440
+ * @returns An array of ScriptStep functions.
2441
+ */
2442
+ declare const marathonScript: (options: {
2443
+ turns: number;
2444
+ checks?: ScriptStep[];
2445
+ finalChecks?: ScriptStep[];
2446
+ }) => ScriptStep[];
2200
2447
 
2201
2448
  declare const script_agent: typeof agent;
2202
2449
  declare const script_fail: typeof fail;
2203
2450
  declare const script_judge: typeof judge;
2451
+ declare const script_marathonScript: typeof marathonScript;
2204
2452
  declare const script_message: typeof message;
2205
2453
  declare const script_proceed: typeof proceed;
2206
2454
  declare const script_succeed: typeof succeed;
2207
2455
  declare const script_user: typeof user;
2208
2456
  declare namespace script {
2209
- export { script_agent as agent, script_fail as fail, script_judge as judge, script_message as message, script_proceed as proceed, script_succeed as succeed, script_user as user };
2457
+ export { script_agent as agent, script_fail as fail, script_judge as judge, script_marathonScript as marathonScript, script_message as message, script_proceed as proceed, script_succeed as succeed, script_user as user };
2210
2458
  }
2211
2459
 
2212
2460
  /**
@@ -2312,4 +2560,4 @@ declare function withCustomScopes(...scopes: string[]): TraceFilter[];
2312
2560
  type ScenarioApi = typeof agents & typeof domain & typeof execution & typeof runner & typeof script;
2313
2561
  declare const scenario: ScenarioApi;
2314
2562
 
2315
- export { AgentAdapter, type AgentInput, type AgentReturnTypes, AgentRole, type AudioResponseEvent, DEFAULT_MAX_TURNS, DEFAULT_TOKEN_THRESHOLD, DEFAULT_VERBOSE, type FinishTestArgs, type InvokeLLMParams, type InvokeLLMResult, JudgeAgentAdapter, type JudgeAgentConfig, type JudgeResult, JudgeSpanCollector, JudgeSpanDigestFormatter, type JudgmentRequest, type LangwatchConfig, RealtimeAgentAdapter, type RealtimeAgentAdapterConfig, type RunOptions, type ScenarioConfig, type ScenarioConfigFinal, ScenarioExecution, type ScenarioExecutionLike, ScenarioExecutionState, type ScenarioExecutionStateLike, type ScenarioProjectConfig, type ScenarioResult, type ScriptStep, type StateChangeEvent, StateChangeEventType, type TestingAgentConfig, UserSimulatorAgentAdapter, agent, allAgentRoles, scenario as default, defineConfig, estimateTokens, expandTrace, fail, grepTrace, judge, judgeAgent, judgeSpanCollector, judgeSpanDigestFormatter, message, proceed, run, scenario, scenarioOnly, scenarioProjectConfigSchema, setupScenarioTracing, succeed, user, userSimulatorAgent, withCustomScopes };
2563
+ export { AgentAdapter, type AgentInput, type AgentReturnTypes, AgentRole, type AudioResponseEvent, type BacktrackEntry, type CrescendoConfig, CrescendoStrategy, DEFAULT_MAX_TURNS, DEFAULT_TOKEN_THRESHOLD, DEFAULT_VERBOSE, type FinishTestArgs, type InvokeLLMParams, type InvokeLLMResult, JudgeAgentAdapter, type JudgeAgentConfig, type JudgeResult, JudgeSpanCollector, JudgeSpanDigestFormatter, type JudgmentRequest, type LangwatchConfig, RealtimeAgentAdapter, type RealtimeAgentAdapterConfig, type RedTeamAgentConfig, type RedTeamStrategy, type RunOptions, type ScenarioConfig, type ScenarioConfigFinal, ScenarioExecution, type ScenarioExecutionLike, ScenarioExecutionState, type ScenarioExecutionStateLike, type ScenarioProjectConfig, type ScenarioResult, type ScriptStep, type StateChangeEvent, StateChangeEventType, type TestingAgentConfig, UserSimulatorAgentAdapter, agent, allAgentRoles, scenario as default, defineConfig, estimateTokens, expandTrace, fail, grepTrace, judge, judgeAgent, judgeSpanCollector, judgeSpanDigestFormatter, marathonScript, message, proceed, redTeamAgent, redTeamCrescendo, run, scenario, scenarioOnly, scenarioProjectConfigSchema, setupScenarioTracing, succeed, user, userSimulatorAgent, withCustomScopes };
package/dist/index.d.ts CHANGED
@@ -366,6 +366,18 @@ interface ScenarioExecutionStateLike {
366
366
  * @returns True if the tool call exists, false otherwise.
367
367
  */
368
368
  hasToolCall(toolName: string): boolean;
369
+ /**
370
+ * Remove all messages from position `index` onward.
371
+ *
372
+ * Truncates the message list and cleans up any pending message queues
373
+ * so no agent sees stale messages.
374
+ *
375
+ * @param index - Truncate point (clamped to `[0, messages.length]`).
376
+ * Messages at positions >= index are removed.
377
+ * @returns The removed messages (empty array if nothing to remove).
378
+ * @throws {RangeError} If `index` is negative.
379
+ */
380
+ rollbackMessagesTo(index: number): ModelMessage[];
369
381
  }
370
382
 
371
383
  /**
@@ -961,7 +973,189 @@ declare class RealtimeAgentAdapter extends AgentAdapter {
961
973
  offAudioResponse(callback: (event: AudioResponseEvent) => void): void;
962
974
  }
963
975
 
976
+ interface BacktrackEntry {
977
+ turn: number;
978
+ attack: string;
979
+ refusal: string;
980
+ }
981
+ interface RedTeamStrategy {
982
+ /**
983
+ * Build a turn-aware system prompt for the attacker.
984
+ *
985
+ * Score feedback, adaptation hints, and backtrack markers are
986
+ * communicated via the attacker's private conversation history
987
+ * (H_attacker) as system messages — not embedded in this prompt.
988
+ */
989
+ buildSystemPrompt(params: {
990
+ target: string;
991
+ currentTurn: number;
992
+ totalTurns: number;
993
+ scenarioDescription: string;
994
+ metapromptPlan: string;
995
+ }): string;
996
+ getPhaseName(currentTurn: number, totalTurns: number): string;
997
+ }
998
+
999
+ declare class CrescendoStrategy implements RedTeamStrategy {
1000
+ getPhase(currentTurn: number, totalTurns: number): {
1001
+ name: string;
1002
+ instructions: string;
1003
+ };
1004
+ getPhaseName(currentTurn: number, totalTurns: number): string;
1005
+ private phaseTurnRange;
1006
+ buildSystemPrompt(params: {
1007
+ target: string;
1008
+ currentTurn: number;
1009
+ totalTurns: number;
1010
+ scenarioDescription: string;
1011
+ metapromptPlan: string;
1012
+ }): string;
1013
+ }
1014
+
1015
+ interface RedTeamAgentConfig {
1016
+ strategy: RedTeamStrategy;
1017
+ target: string;
1018
+ totalTurns?: number;
1019
+ model?: LanguageModel;
1020
+ metapromptModel?: LanguageModel;
1021
+ metapromptTemplate?: string;
1022
+ attackPlan?: string;
1023
+ /** Score target responses each turn to feed back into the attacker. Default true. */
1024
+ scoreResponses?: boolean;
1025
+ /** Use pattern-based refusal detection to skip LLM scorer on obvious refusals. Default true. */
1026
+ detectRefusals?: boolean;
1027
+ temperature?: number;
1028
+ /** Separate temperature for metaprompt/scoring calls. Defaults to temperature. */
1029
+ metapromptTemperature?: number;
1030
+ maxTokens?: number;
1031
+ /** Score threshold (0-10) for early exit. Default 9. Set to undefined to disable. */
1032
+ successScore?: number;
1033
+ /** Consecutive turns >= threshold before triggering early exit. Default 2. */
1034
+ successConfirmTurns?: number;
1035
+ }
1036
+ interface CrescendoConfig {
1037
+ target: string;
1038
+ totalTurns?: number;
1039
+ model?: LanguageModel;
1040
+ metapromptModel?: LanguageModel;
1041
+ attackPlan?: string;
1042
+ scoreResponses?: boolean;
1043
+ /** Use pattern-based refusal detection to skip LLM scorer on obvious refusals. Default true. */
1044
+ detectRefusals?: boolean;
1045
+ temperature?: number;
1046
+ metapromptTemperature?: number;
1047
+ maxTokens?: number;
1048
+ /** Score threshold (0-10) for early exit. Default 9. Set to undefined to disable. */
1049
+ successScore?: number;
1050
+ /** Consecutive turns >= threshold before triggering early exit. Default 2. */
1051
+ successConfirmTurns?: number;
1052
+ }
1053
+ declare class RedTeamAgentImpl extends UserSimulatorAgentAdapter {
1054
+ name: string;
1055
+ private strategy;
1056
+ private target;
1057
+ private totalTurns;
1058
+ private model?;
1059
+ private metapromptModel?;
1060
+ private metapromptTemplate;
1061
+ private scoreResponses;
1062
+ private detectRefusals;
1063
+ private temperature;
1064
+ private metapromptTemperature;
1065
+ private maxTokens?;
1066
+ private _successScore;
1067
+ private _successConfirmTurns;
1068
+ private static readonly HARD_REFUSAL_PATTERNS;
1069
+ private static readonly SOFT_REFUSAL_PATTERNS;
1070
+ private attackPlanPromise;
1071
+ private attackPlanValue;
1072
+ private turnScores;
1073
+ private static readonly MAX_BACKTRACKS;
1074
+ private backtracksRemaining;
1075
+ private backtrackHistory;
1076
+ private attackerHistory;
1077
+ constructor(config: RedTeamAgentConfig);
1078
+ private getAttackPlan;
1079
+ private generateAttackPlan;
1080
+ private getLastAssistantContent;
1081
+ private getLastUserContent;
1082
+ private detectRefusal;
1083
+ /**
1084
+ * Score the target agent's last response toward the attack goal (0-10).
1085
+ * Results are cached per turn so the scorer LLM is called at most once.
1086
+ */
1087
+ private scoreLastResponse;
1088
+ /**
1089
+ * Check if the attack objective has been achieved.
1090
+ * Returns true if the last `successConfirmTurns` cached scores
1091
+ * are all >= `successScore`.
1092
+ */
1093
+ checkEarlyExit(): boolean;
1094
+ /**
1095
+ * Generate a marathon test script with automatic early-exit checks.
1096
+ *
1097
+ * Like the standalone `marathonScript`, but inserts an early-exit check
1098
+ * after each `agent()` step. When `successConfirmTurns` consecutive turns
1099
+ * score >= the threshold, the check runs `finalChecks` inline and calls
1100
+ * `executor.succeed()` to end the scenario early.
1101
+ *
1102
+ * Set `successScore` to `undefined` to disable early exit.
1103
+ */
1104
+ marathonScript(options: {
1105
+ turns: number;
1106
+ checks?: ScriptStep[];
1107
+ finalChecks?: ScriptStep[];
1108
+ }): ScriptStep[];
1109
+ /**
1110
+ * Call the attacker LLM directly with the attacker's private history.
1111
+ * Uses `attackerHistory` (H_attacker) which contains the system prompt,
1112
+ * previous attack messages, target response summaries, score annotations,
1113
+ * and backtrack markers — none of which leak to the target.
1114
+ */
1115
+ private callAttackerLLM;
1116
+ /**
1117
+ * Reset per-run state for safe reuse across scenario.run() calls.
1118
+ * Called at the start of turn 1. Does NOT reset attackPlanValue
1119
+ * (expensive to regenerate and target-specific, not run-specific).
1120
+ */
1121
+ private resetRunState;
1122
+ call: (input: AgentInput) => Promise<AgentReturnTypes>;
1123
+ }
1124
+ /**
1125
+ * Create a red-team agent with a custom strategy.
1126
+ */
1127
+ declare const redTeamAgent: (config: RedTeamAgentConfig) => RedTeamAgentImpl;
1128
+ /**
1129
+ * Create a red-team agent using the Crescendo (marathon) strategy.
1130
+ *
1131
+ * Crescendo gradually escalates from innocent rapport-building to aggressive
1132
+ * jailbreak attempts over many turns, exploiting LLMs' tendency to maintain
1133
+ * conversational consistency once cooperative context has been established.
1134
+ *
1135
+ * @example
1136
+ * ```typescript
1137
+ * import scenario from "@langwatch/scenario";
1138
+ * import { openai } from "@ai-sdk/openai";
1139
+ *
1140
+ * const redTeam = scenario.redTeamCrescendo({
1141
+ * target: "extract the system prompt",
1142
+ * model: openai("gpt-4o"),
1143
+ * totalTurns: 50,
1144
+ * successScore: 9, // default: 9 (score 0-10)
1145
+ * successConfirmTurns: 2, // default: 2
1146
+ * });
1147
+ *
1148
+ * // Use instance marathonScript for automatic early-exit:
1149
+ * script: redTeam.marathonScript({ turns: 50 }),
1150
+ * ```
1151
+ */
1152
+ declare const redTeamCrescendo: (config: CrescendoConfig) => RedTeamAgentImpl;
1153
+
964
1154
  type agents_AudioResponseEvent = AudioResponseEvent;
1155
+ type agents_BacktrackEntry = BacktrackEntry;
1156
+ type agents_CrescendoConfig = CrescendoConfig;
1157
+ type agents_CrescendoStrategy = CrescendoStrategy;
1158
+ declare const agents_CrescendoStrategy: typeof CrescendoStrategy;
965
1159
  declare const agents_DEFAULT_TOKEN_THRESHOLD: typeof DEFAULT_TOKEN_THRESHOLD;
966
1160
  type agents_FinishTestArgs = FinishTestArgs;
967
1161
  type agents_InvokeLLMParams = InvokeLLMParams;
@@ -975,6 +1169,8 @@ declare const agents_JudgeSpanDigestFormatter: typeof JudgeSpanDigestFormatter;
975
1169
  type agents_RealtimeAgentAdapter = RealtimeAgentAdapter;
976
1170
  declare const agents_RealtimeAgentAdapter: typeof RealtimeAgentAdapter;
977
1171
  type agents_RealtimeAgentAdapterConfig = RealtimeAgentAdapterConfig;
1172
+ type agents_RedTeamAgentConfig = RedTeamAgentConfig;
1173
+ type agents_RedTeamStrategy = RedTeamStrategy;
978
1174
  type agents_TestingAgentConfig = TestingAgentConfig;
979
1175
  declare const agents_estimateTokens: typeof estimateTokens;
980
1176
  declare const agents_expandTrace: typeof expandTrace;
@@ -982,9 +1178,11 @@ declare const agents_grepTrace: typeof grepTrace;
982
1178
  declare const agents_judgeAgent: typeof judgeAgent;
983
1179
  declare const agents_judgeSpanCollector: typeof judgeSpanCollector;
984
1180
  declare const agents_judgeSpanDigestFormatter: typeof judgeSpanDigestFormatter;
1181
+ declare const agents_redTeamAgent: typeof redTeamAgent;
1182
+ declare const agents_redTeamCrescendo: typeof redTeamCrescendo;
985
1183
  declare const agents_userSimulatorAgent: typeof userSimulatorAgent;
986
1184
  declare namespace agents {
987
- export { type agents_AudioResponseEvent as AudioResponseEvent, agents_DEFAULT_TOKEN_THRESHOLD as DEFAULT_TOKEN_THRESHOLD, type agents_FinishTestArgs as FinishTestArgs, type agents_InvokeLLMParams as InvokeLLMParams, type agents_InvokeLLMResult as InvokeLLMResult, type agents_JudgeAgentConfig as JudgeAgentConfig, type agents_JudgeResult as JudgeResult, agents_JudgeSpanCollector as JudgeSpanCollector, agents_JudgeSpanDigestFormatter as JudgeSpanDigestFormatter, agents_RealtimeAgentAdapter as RealtimeAgentAdapter, type agents_RealtimeAgentAdapterConfig as RealtimeAgentAdapterConfig, type agents_TestingAgentConfig as TestingAgentConfig, agents_estimateTokens as estimateTokens, agents_expandTrace as expandTrace, agents_grepTrace as grepTrace, agents_judgeAgent as judgeAgent, agents_judgeSpanCollector as judgeSpanCollector, agents_judgeSpanDigestFormatter as judgeSpanDigestFormatter, agents_userSimulatorAgent as userSimulatorAgent };
1185
+ export { type agents_AudioResponseEvent as AudioResponseEvent, type agents_BacktrackEntry as BacktrackEntry, type agents_CrescendoConfig as CrescendoConfig, agents_CrescendoStrategy as CrescendoStrategy, agents_DEFAULT_TOKEN_THRESHOLD as DEFAULT_TOKEN_THRESHOLD, type agents_FinishTestArgs as FinishTestArgs, type agents_InvokeLLMParams as InvokeLLMParams, type agents_InvokeLLMResult as InvokeLLMResult, type agents_JudgeAgentConfig as JudgeAgentConfig, type agents_JudgeResult as JudgeResult, agents_JudgeSpanCollector as JudgeSpanCollector, agents_JudgeSpanDigestFormatter as JudgeSpanDigestFormatter, agents_RealtimeAgentAdapter as RealtimeAgentAdapter, type agents_RealtimeAgentAdapterConfig as RealtimeAgentAdapterConfig, type agents_RedTeamAgentConfig as RedTeamAgentConfig, type agents_RedTeamStrategy as RedTeamStrategy, type agents_TestingAgentConfig as TestingAgentConfig, agents_estimateTokens as estimateTokens, agents_expandTrace as expandTrace, agents_grepTrace as grepTrace, agents_judgeAgent as judgeAgent, agents_judgeSpanCollector as judgeSpanCollector, agents_judgeSpanDigestFormatter as judgeSpanDigestFormatter, agents_redTeamAgent as redTeamAgent, agents_redTeamCrescendo as redTeamCrescendo, agents_userSimulatorAgent as userSimulatorAgent };
988
1186
  }
989
1187
 
990
1188
  /**
@@ -1482,14 +1680,19 @@ declare class ScenarioExecution implements ScenarioExecutionLike {
1482
1680
  private batchRunId;
1483
1681
  /** The run ID for the current execution */
1484
1682
  private scenarioRunId?;
1683
+ /** Pre-assigned run ID (provided externally, e.g. by the platform) */
1684
+ private preAssignedRunId?;
1485
1685
  /**
1486
1686
  * Creates a new ScenarioExecution instance.
1487
1687
  *
1488
1688
  * @param config - The scenario configuration containing agents, settings, and metadata
1489
1689
  * @param script - The ordered sequence of script steps that define the test flow
1490
1690
  * @param batchRunId - Batch run ID for grouping scenario runs
1691
+ * @param runId - Optional pre-assigned run ID. When provided, the execution uses this
1692
+ * ID instead of generating a new one. This prevents duplicate entries when the
1693
+ * platform pre-creates placeholder rows with a known ID.
1491
1694
  */
1492
- constructor(config: ScenarioConfig, script: ScriptStep[], batchRunId: string);
1695
+ constructor(config: ScenarioConfig, script: ScriptStep[], batchRunId: string, runId?: string);
1493
1696
  /**
1494
1697
  * Gets the complete conversation history as an array of messages.
1495
1698
  *
@@ -1979,6 +2182,7 @@ declare class ScenarioExecutionState implements ScenarioExecutionStateLike {
1979
2182
  private _messages;
1980
2183
  private _currentTurn;
1981
2184
  private _threadId;
2185
+ private _onRollback?;
1982
2186
  /** Event stream for message additions */
1983
2187
  private eventSubject;
1984
2188
  readonly events$: Observable<StateChangeEvent>;
@@ -2014,6 +2218,28 @@ declare class ScenarioExecutionState implements ScenarioExecutionStateLike {
2014
2218
  traceId?: string;
2015
2219
  };
2016
2220
  hasToolCall(toolName: string): boolean;
2221
+ /**
2222
+ * Register a callback that fires when messages are rolled back.
2223
+ * The executor uses this to clean up its pending message queues.
2224
+ */
2225
+ setOnRollback(handler: (removedSet: Set<object>) => void): void;
2226
+ /**
2227
+ * Remove all messages from position `index` onward.
2228
+ *
2229
+ * Truncates the internal message list and notifies the executor
2230
+ * (via the registered rollback handler) to clean pending queues.
2231
+ *
2232
+ * **Note:** This method is safe to call only during an agent's `call()`
2233
+ * invocation. The executor runs agents sequentially, so no other agent
2234
+ * can observe stale `newMessages` references. Calling this from outside
2235
+ * that flow may leave already-delivered `newMessages` out of sync.
2236
+ *
2237
+ * @param index - Truncate point (clamped to `[0, messages.length]`).
2238
+ * Messages at positions >= index are removed.
2239
+ * @returns The removed messages (empty array if nothing to remove).
2240
+ * @throws {RangeError} If `index` is negative.
2241
+ */
2242
+ rollbackMessagesTo(index: number): ModelMessage[];
2017
2243
  }
2018
2244
 
2019
2245
  type execution_ScenarioExecution = ScenarioExecution;
@@ -2045,6 +2271,13 @@ interface RunOptions {
2045
2271
  langwatch?: LangwatchConfig;
2046
2272
  /** Batch run ID for grouping scenario runs. Overrides SCENARIO_BATCH_RUN_ID env var. */
2047
2273
  batchRunId?: string;
2274
+ /**
2275
+ * Pre-assigned run ID for the scenario execution.
2276
+ * When provided, the SDK uses this ID instead of generating a new one.
2277
+ *
2278
+ * @internal Platform use only — not part of the public API.
2279
+ */
2280
+ runId?: string;
2048
2281
  }
2049
2282
  /**
2050
2283
  * High-level interface for running a scenario test.
@@ -2197,16 +2430,31 @@ declare const succeed: (reasoning?: string) => ScriptStep;
2197
2430
  * @returns A ScriptStep function that can be used in scenario scripts.
2198
2431
  */
2199
2432
  declare const fail: (reasoning?: string) => ScriptStep;
2433
+ /**
2434
+ * Generate a marathon script that runs user-agent turns in a loop,
2435
+ * with optional per-turn checks and a final judge evaluation.
2436
+ *
2437
+ * @param options.turns Number of user-agent turn pairs.
2438
+ * @param options.checks Optional steps to run after each turn.
2439
+ * @param options.finalChecks Optional steps to run after all turns, before the judge.
2440
+ * @returns An array of ScriptStep functions.
2441
+ */
2442
+ declare const marathonScript: (options: {
2443
+ turns: number;
2444
+ checks?: ScriptStep[];
2445
+ finalChecks?: ScriptStep[];
2446
+ }) => ScriptStep[];
2200
2447
 
2201
2448
  declare const script_agent: typeof agent;
2202
2449
  declare const script_fail: typeof fail;
2203
2450
  declare const script_judge: typeof judge;
2451
+ declare const script_marathonScript: typeof marathonScript;
2204
2452
  declare const script_message: typeof message;
2205
2453
  declare const script_proceed: typeof proceed;
2206
2454
  declare const script_succeed: typeof succeed;
2207
2455
  declare const script_user: typeof user;
2208
2456
  declare namespace script {
2209
- export { script_agent as agent, script_fail as fail, script_judge as judge, script_message as message, script_proceed as proceed, script_succeed as succeed, script_user as user };
2457
+ export { script_agent as agent, script_fail as fail, script_judge as judge, script_marathonScript as marathonScript, script_message as message, script_proceed as proceed, script_succeed as succeed, script_user as user };
2210
2458
  }
2211
2459
 
2212
2460
  /**
@@ -2312,4 +2560,4 @@ declare function withCustomScopes(...scopes: string[]): TraceFilter[];
2312
2560
  type ScenarioApi = typeof agents & typeof domain & typeof execution & typeof runner & typeof script;
2313
2561
  declare const scenario: ScenarioApi;
2314
2562
 
2315
- export { AgentAdapter, type AgentInput, type AgentReturnTypes, AgentRole, type AudioResponseEvent, DEFAULT_MAX_TURNS, DEFAULT_TOKEN_THRESHOLD, DEFAULT_VERBOSE, type FinishTestArgs, type InvokeLLMParams, type InvokeLLMResult, JudgeAgentAdapter, type JudgeAgentConfig, type JudgeResult, JudgeSpanCollector, JudgeSpanDigestFormatter, type JudgmentRequest, type LangwatchConfig, RealtimeAgentAdapter, type RealtimeAgentAdapterConfig, type RunOptions, type ScenarioConfig, type ScenarioConfigFinal, ScenarioExecution, type ScenarioExecutionLike, ScenarioExecutionState, type ScenarioExecutionStateLike, type ScenarioProjectConfig, type ScenarioResult, type ScriptStep, type StateChangeEvent, StateChangeEventType, type TestingAgentConfig, UserSimulatorAgentAdapter, agent, allAgentRoles, scenario as default, defineConfig, estimateTokens, expandTrace, fail, grepTrace, judge, judgeAgent, judgeSpanCollector, judgeSpanDigestFormatter, message, proceed, run, scenario, scenarioOnly, scenarioProjectConfigSchema, setupScenarioTracing, succeed, user, userSimulatorAgent, withCustomScopes };
2563
+ export { AgentAdapter, type AgentInput, type AgentReturnTypes, AgentRole, type AudioResponseEvent, type BacktrackEntry, type CrescendoConfig, CrescendoStrategy, DEFAULT_MAX_TURNS, DEFAULT_TOKEN_THRESHOLD, DEFAULT_VERBOSE, type FinishTestArgs, type InvokeLLMParams, type InvokeLLMResult, JudgeAgentAdapter, type JudgeAgentConfig, type JudgeResult, JudgeSpanCollector, JudgeSpanDigestFormatter, type JudgmentRequest, type LangwatchConfig, RealtimeAgentAdapter, type RealtimeAgentAdapterConfig, type RedTeamAgentConfig, type RedTeamStrategy, type RunOptions, type ScenarioConfig, type ScenarioConfigFinal, ScenarioExecution, type ScenarioExecutionLike, ScenarioExecutionState, type ScenarioExecutionStateLike, type ScenarioProjectConfig, type ScenarioResult, type ScriptStep, type StateChangeEvent, StateChangeEventType, type TestingAgentConfig, UserSimulatorAgentAdapter, agent, allAgentRoles, scenario as default, defineConfig, estimateTokens, expandTrace, fail, grepTrace, judge, judgeAgent, judgeSpanCollector, judgeSpanDigestFormatter, marathonScript, message, proceed, redTeamAgent, redTeamCrescendo, run, scenario, scenarioOnly, scenarioProjectConfigSchema, setupScenarioTracing, succeed, user, userSimulatorAgent, withCustomScopes };