@@ -2076,6 +2076,300 @@ mod tests {
2076
2076
assert_eq ! ( ctx. fs( ) . read_to_string( "/file.txt" ) . await . unwrap( ) , "Hello, world!\n " ) ;
2077
2077
}
2078
2078
2079
+ #[ tokio:: test]
2080
+ async fn test_flow_tool_permissions ( ) {
2081
+ let _ = tracing_subscriber:: fmt:: try_init ( ) ;
2082
+ let ctx = Context :: builder ( ) . with_test_home ( ) . await . unwrap ( ) . build_fake ( ) ;
2083
+ let test_client = create_stream ( serde_json:: json!( [
2084
+ [
2085
+ "Ok" ,
2086
+ {
2087
+ "tool_use_id" : "1" ,
2088
+ "name" : "fs_write" ,
2089
+ "args" : {
2090
+ "command" : "create" ,
2091
+ "file_text" : "Hello, world!" ,
2092
+ "path" : "/file1.txt" ,
2093
+ }
2094
+ }
2095
+ ] ,
2096
+ [
2097
+ "Done" ,
2098
+ ] ,
2099
+ [
2100
+ "Ok" ,
2101
+ {
2102
+ "tool_use_id" : "1" ,
2103
+ "name" : "fs_write" ,
2104
+ "args" : {
2105
+ "command" : "create" ,
2106
+ "file_text" : "Hello, world!" ,
2107
+ "path" : "/file2.txt" ,
2108
+ }
2109
+ }
2110
+ ] ,
2111
+ [
2112
+ "Done" ,
2113
+ ] ,
2114
+ [
2115
+ "Ok" ,
2116
+ {
2117
+ "tool_use_id" : "1" ,
2118
+ "name" : "fs_write" ,
2119
+ "args" : {
2120
+ "command" : "create" ,
2121
+ "file_text" : "Hello, world!" ,
2122
+ "path" : "/file3.txt" ,
2123
+ }
2124
+ }
2125
+ ] ,
2126
+ [
2127
+ "Done" ,
2128
+ ] ,
2129
+ [
2130
+ "Ok" ,
2131
+ {
2132
+ "tool_use_id" : "1" ,
2133
+ "name" : "fs_write" ,
2134
+ "args" : {
2135
+ "command" : "create" ,
2136
+ "file_text" : "Hello, world!" ,
2137
+ "path" : "/file4.txt" ,
2138
+ }
2139
+ }
2140
+ ] ,
2141
+ [
2142
+ "Ok, I won't make it." ,
2143
+ ] ,
2144
+ [
2145
+ "Ok" ,
2146
+ {
2147
+ "tool_use_id" : "1" ,
2148
+ "name" : "fs_write" ,
2149
+ "args" : {
2150
+ "command" : "create" ,
2151
+ "file_text" : "Hello, world!" ,
2152
+ "path" : "/file5.txt" ,
2153
+ }
2154
+ }
2155
+ ] ,
2156
+ [
2157
+ "Done" ,
2158
+ ] ,
2159
+ [
2160
+ "Ok" ,
2161
+ {
2162
+ "tool_use_id" : "1" ,
2163
+ "name" : "fs_write" ,
2164
+ "args" : {
2165
+ "command" : "create" ,
2166
+ "file_text" : "Hello, world!" ,
2167
+ "path" : "/file6.txt" ,
2168
+ }
2169
+ }
2170
+ ] ,
2171
+ [
2172
+ "Ok, I won't make it." ,
2173
+ ] ,
2174
+ ] ) ) ;
2175
+
2176
+ ChatContext :: new (
2177
+ Arc :: clone ( & ctx) ,
2178
+ Settings :: new_fake ( ) ,
2179
+ std:: io:: stdout ( ) ,
2180
+ None ,
2181
+ InputSource :: new_mock ( vec ! [
2182
+ "/tools" . to_string( ) ,
2183
+ "/tools help" . to_string( ) ,
2184
+ "create a new file" . to_string( ) ,
2185
+ "y" . to_string( ) ,
2186
+ "create a new file" . to_string( ) ,
2187
+ "t" . to_string( ) ,
2188
+ "create a new file" . to_string( ) , // should make without prompting due to 't'
2189
+ "/tools untrust fs_write" . to_string( ) ,
2190
+ "create a file" . to_string( ) , // prompt again due to untrust
2191
+ "n" . to_string( ) , // cancel
2192
+ "/tools trust fs_write" . to_string( ) ,
2193
+ "create a file" . to_string( ) , // again without prompting due to '/tools trust'
2194
+ "/tools reset" . to_string( ) ,
2195
+ "create a file" . to_string( ) , // prompt again due to reset
2196
+ "n" . to_string( ) , // cancel
2197
+ "exit" . to_string( ) ,
2198
+ ] ) ,
2199
+ true ,
2200
+ test_client,
2201
+ || Some ( 80 ) ,
2202
+ None ,
2203
+ load_tools ( ) . expect ( "Tools failed to load." ) ,
2204
+ ToolPermissions :: new ( 0 ) ,
2205
+ )
2206
+ . await
2207
+ . unwrap ( )
2208
+ . try_chat ( )
2209
+ . await
2210
+ . unwrap ( ) ;
2211
+
2212
+ assert_eq ! ( ctx. fs( ) . read_to_string( "/file2.txt" ) . await . unwrap( ) , "Hello, world!\n " ) ;
2213
+ assert_eq ! ( ctx. fs( ) . read_to_string( "/file3.txt" ) . await . unwrap( ) , "Hello, world!\n " ) ;
2214
+ assert ! ( !ctx. fs( ) . exists( "/file4.txt" ) ) ;
2215
+ assert_eq ! ( ctx. fs( ) . read_to_string( "/file5.txt" ) . await . unwrap( ) , "Hello, world!\n " ) ;
2216
+ assert ! ( !ctx. fs( ) . exists( "/file6.txt" ) ) ;
2217
+ }
2218
+
2219
+ #[ tokio:: test]
2220
+ async fn test_flow_multiple_tools ( ) {
2221
+ let _ = tracing_subscriber:: fmt:: try_init ( ) ;
2222
+ let ctx = Context :: builder ( ) . with_test_home ( ) . await . unwrap ( ) . build_fake ( ) ;
2223
+ let test_client = create_stream ( serde_json:: json!( [
2224
+ [
2225
+ "Sure, I'll create a file for you" ,
2226
+ {
2227
+ "tool_use_id" : "1" ,
2228
+ "name" : "fs_write" ,
2229
+ "args" : {
2230
+ "command" : "create" ,
2231
+ "file_text" : "Hello, world!" ,
2232
+ "path" : "/file1.txt" ,
2233
+ }
2234
+ } ,
2235
+ {
2236
+ "tool_use_id" : "2" ,
2237
+ "name" : "fs_write" ,
2238
+ "args" : {
2239
+ "command" : "create" ,
2240
+ "file_text" : "Hello, world!" ,
2241
+ "path" : "/file2.txt" ,
2242
+ }
2243
+ }
2244
+ ] ,
2245
+ [
2246
+ "Done" ,
2247
+ ] ,
2248
+ [
2249
+ "Sure, I'll create a file for you" ,
2250
+ {
2251
+ "tool_use_id" : "1" ,
2252
+ "name" : "fs_write" ,
2253
+ "args" : {
2254
+ "command" : "create" ,
2255
+ "file_text" : "Hello, world!" ,
2256
+ "path" : "/file3.txt" ,
2257
+ }
2258
+ } ,
2259
+ {
2260
+ "tool_use_id" : "2" ,
2261
+ "name" : "fs_write" ,
2262
+ "args" : {
2263
+ "command" : "create" ,
2264
+ "file_text" : "Hello, world!" ,
2265
+ "path" : "/file4.txt" ,
2266
+ }
2267
+ }
2268
+ ] ,
2269
+ [
2270
+ "Done" ,
2271
+ ] ,
2272
+ ] ) ) ;
2273
+
2274
+ ChatContext :: new (
2275
+ Arc :: clone ( & ctx) ,
2276
+ Settings :: new_fake ( ) ,
2277
+ std:: io:: stdout ( ) ,
2278
+ None ,
2279
+ InputSource :: new_mock ( vec ! [
2280
+ "create 2 new files parallel" . to_string( ) ,
2281
+ "t" . to_string( ) ,
2282
+ "/tools reset" . to_string( ) ,
2283
+ "create 2 new files parallel" . to_string( ) ,
2284
+ "y" . to_string( ) ,
2285
+ "y" . to_string( ) ,
2286
+ "exit" . to_string( ) ,
2287
+ ] ) ,
2288
+ true ,
2289
+ test_client,
2290
+ || Some ( 80 ) ,
2291
+ None ,
2292
+ load_tools ( ) . expect ( "Tools failed to load." ) ,
2293
+ ToolPermissions :: new ( 0 ) ,
2294
+ )
2295
+ . await
2296
+ . unwrap ( )
2297
+ . try_chat ( )
2298
+ . await
2299
+ . unwrap ( ) ;
2300
+
2301
+ assert_eq ! ( ctx. fs( ) . read_to_string( "/file1.txt" ) . await . unwrap( ) , "Hello, world!\n " ) ;
2302
+ assert_eq ! ( ctx. fs( ) . read_to_string( "/file2.txt" ) . await . unwrap( ) , "Hello, world!\n " ) ;
2303
+ assert_eq ! ( ctx. fs( ) . read_to_string( "/file3.txt" ) . await . unwrap( ) , "Hello, world!\n " ) ;
2304
+ assert_eq ! ( ctx. fs( ) . read_to_string( "/file4.txt" ) . await . unwrap( ) , "Hello, world!\n " ) ;
2305
+ }
2306
+
2307
+ #[ tokio:: test]
2308
+ async fn test_flow_tools_trust_all ( ) {
2309
+ let _ = tracing_subscriber:: fmt:: try_init ( ) ;
2310
+ let ctx = Context :: builder ( ) . with_test_home ( ) . await . unwrap ( ) . build_fake ( ) ;
2311
+ let test_client = create_stream ( serde_json:: json!( [
2312
+ [
2313
+ "Sure, I'll create a file for you" ,
2314
+ {
2315
+ "tool_use_id" : "1" ,
2316
+ "name" : "fs_write" ,
2317
+ "args" : {
2318
+ "command" : "create" ,
2319
+ "file_text" : "Hello, world!" ,
2320
+ "path" : "/file1.txt" ,
2321
+ }
2322
+ }
2323
+ ] ,
2324
+ [
2325
+ "Done" ,
2326
+ ] ,
2327
+ [
2328
+ "Sure, I'll create a file for you" ,
2329
+ {
2330
+ "tool_use_id" : "1" ,
2331
+ "name" : "fs_write" ,
2332
+ "args" : {
2333
+ "command" : "create" ,
2334
+ "file_text" : "Hello, world!" ,
2335
+ "path" : "/file3.txt" ,
2336
+ }
2337
+ }
2338
+ ] ,
2339
+ [
2340
+ "Ok I won't." ,
2341
+ ] ,
2342
+ ] ) ) ;
2343
+
2344
+ ChatContext :: new (
2345
+ Arc :: clone ( & ctx) ,
2346
+ Settings :: new_fake ( ) ,
2347
+ std:: io:: stdout ( ) ,
2348
+ None ,
2349
+ InputSource :: new_mock ( vec ! [
2350
+ "/tools trustall" . to_string( ) ,
2351
+ "create a new file" . to_string( ) ,
2352
+ "/tools reset" . to_string( ) ,
2353
+ "create a new file" . to_string( ) ,
2354
+ "exit" . to_string( ) ,
2355
+ ] ) ,
2356
+ true ,
2357
+ test_client,
2358
+ || Some ( 80 ) ,
2359
+ None ,
2360
+ load_tools ( ) . expect ( "Tools failed to load." ) ,
2361
+ ToolPermissions :: new ( 0 ) ,
2362
+ )
2363
+ . await
2364
+ . unwrap ( )
2365
+ . try_chat ( )
2366
+ . await
2367
+ . unwrap ( ) ;
2368
+
2369
+ assert_eq ! ( ctx. fs( ) . read_to_string( "/file1.txt" ) . await . unwrap( ) , "Hello, world!\n " ) ;
2370
+ assert ! ( !ctx. fs( ) . exists( "/file2.txt" ) ) ;
2371
+ }
2372
+
2079
2373
#[ test]
2080
2374
fn test_editor_content_processing ( ) {
2081
2375
// Since we no longer have template replacement, this test is simplified
0 commit comments