@@ -9,11 +9,69 @@ use pretty_assertions::assert_eq;
99use serde_json:: { Value , json} ;
1010use switchyard_translation:: {
1111 LossyConversionPolicy , TranslationEngine , TranslationPolicy , WireFormat ,
12+ prepare_request_for_target,
1213} ;
1314
1415use common:: { REASONING_MODEL , normalized_policy, shell_tool_call} ;
1516
16- type TestResult = std:: result:: Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > ;
17+ type TestResult < T = ( ) > = std:: result:: Result < T , Box < dyn std:: error:: Error + Send + Sync > > ;
18+
19+ // A target prompt makes every preserved provider body stale.
20+ #[ test]
21+ fn preparing_a_target_prompt_invalidates_exact_replay ( ) -> TestResult {
22+ let engine = TranslationEngine :: default ( ) ;
23+ let policy = TranslationPolicy :: default ( ) ;
24+ let body = json ! ( {
25+ "model" : "route" ,
26+ "messages" : [
27+ { "role" : "system" , "name" : "caller" , "content" : "client prompt" } ,
28+ { "role" : "user" , "content" : "hi" }
29+ ]
30+ } ) ;
31+ let mut request = engine
32+ . decode_request ( WireFormat :: OpenAiChat , & body, & policy) ?
33+ . request ;
34+
35+ prepare_request_for_target (
36+ & mut request,
37+ & "selected/model" . into ( ) ,
38+ Some ( "target prompt" ) ,
39+ ) ;
40+
41+ assert ! ( request. preservation. requests. is_empty( ) ) ;
42+ let encoded = engine
43+ . encode_request ( WireFormat :: OpenAiChat , & request, & policy) ?
44+ . body ;
45+ assert_eq ! ( encoded[ "model" ] , "selected/model" ) ;
46+ assert_eq ! ( encoded[ "messages" ] [ 0 ] [ "content" ] , "target prompt" ) ;
47+ assert_eq ! ( encoded[ "messages" ] [ 1 ] [ "content" ] , "client prompt" ) ;
48+ assert ! ( encoded[ "messages" ] [ 1 ] . get( "name" ) . is_none( ) ) ;
49+ Ok ( ( ) )
50+ }
51+
52+ // Stamping only the normalized target does not invalidate exact replay.
53+ #[ test]
54+ fn preparing_without_a_prompt_preserves_exact_replay ( ) -> TestResult {
55+ let engine = TranslationEngine :: default ( ) ;
56+ let policy = TranslationPolicy :: default ( ) ;
57+ let body = json ! ( {
58+ "model" : "route" ,
59+ "messages" : [ { "role" : "user" , "content" : "hi" } ] ,
60+ "provider_field" : true
61+ } ) ;
62+ let mut request = engine
63+ . decode_request ( WireFormat :: OpenAiChat , & body, & policy) ?
64+ . request ;
65+
66+ prepare_request_for_target ( & mut request, & "selected/model" . into ( ) , None ) ;
67+
68+ assert_eq ! ( request. model. as_deref( ) , Some ( "selected/model" ) ) ;
69+ assert_eq ! (
70+ request. preservation. requests[ & WireFormat :: OpenAiChat . into( ) ] ,
71+ body
72+ ) ;
73+ Ok ( ( ) )
74+ }
1775
1876// Verifies Anthropic-only request fields are dropped or mapped for OpenAI Chat.
1977#[ test]
0 commit comments