@@ -31,6 +31,8 @@ const useChatSocket = (isEmpty?: boolean) => {
3131 'github.com/gptscript-ai/gateway-provider' ,
3232 'github.com/gptscript-ai/gateway-creds' ,
3333 ] ) ;
34+ // trustedOpenAPIRef contains a mapping of OpenAPI run tools to OpenAPI operation names that have been trusted.
35+ const trustedOpenAPIRef = useRef < Record < string , Record < string , boolean > > > ( { } ) ;
3436
3537 // update the refs as the state changes
3638 useEffect ( ( ) => {
@@ -190,11 +192,16 @@ const useChatSocket = (isEmpty?: boolean) => {
190192 }
191193
192194 let confirmMessage = `Proceed with calling the ${ frame . tool . name } tool?` ;
193- if ( frame . displayText ) {
195+ if (
196+ ! frame . tool . instructions ?. startsWith ( '#!sys.openapi' ) &&
197+ frame . displayText
198+ ) {
194199 const tool = frame . tool ?. name ?. replace ( 'sys.' , '' ) ;
195200 confirmMessage = frame . tool ?. source ?. repo
196201 ? `Proceed with running the following (or allow all calls from the **${ trimRepo ( frame . tool ?. source . repo ! . Root ) } ** repo)?`
197202 : `Proceed with running the following (or allow all **${ tool } ** calls)?` ;
203+ } else if ( frame . tool . instructions ?. startsWith ( '#!sys.openapi' ) ) {
204+ confirmMessage = `Proceed with running the following API operation (or allow all runs of this operation)?` ;
198205 }
199206
200207 const form = (
@@ -267,6 +274,28 @@ const useChatSocket = (isEmpty?: boolean) => {
267274 const alreadyAllowed = ( frame : CallFrame ) : boolean => {
268275 if ( ! frame . tool ) return false ;
269276
277+ if ( frame . tool . instructions ?. startsWith ( '#!sys.openapi' ) ) {
278+ // If the tool is an OpenAPI tool to list operations or get the schema for an operation, allow it.
279+ if (
280+ frame . tool . instructions ?. split ( ' ' ) . length > 2 &&
281+ ( frame . tool . instructions ?. split ( ' ' ) [ 1 ] == 'list' ||
282+ frame . tool . instructions ?. split ( ' ' ) [ 1 ] == 'get-schema' )
283+ ) {
284+ return true ;
285+ }
286+
287+ // If the tool is an OpenAPI tool to run an operation, check if it has been trusted.
288+ if ( ! frame . tool . name ) {
289+ return false ;
290+ }
291+
292+ const operation = JSON . parse ( frame . input as string ) [ 'operation' ] ;
293+ return (
294+ trustedOpenAPIRef . current [ frame . tool . name ] &&
295+ trustedOpenAPIRef . current [ frame . tool . name ] [ operation ]
296+ ) ;
297+ }
298+
270299 // Check if the tool has already been allowed
271300 if ( frame . tool . name && trustedRef . current [ frame . tool . name ] ) return true ;
272301
@@ -293,6 +322,22 @@ const useChatSocket = (isEmpty?: boolean) => {
293322 const addTrustedFor = ( frame : CallFrame ) => {
294323 if ( ! frame . tool ) return ( ) => { } ;
295324
325+ if (
326+ frame . tool . instructions &&
327+ frame . tool . name &&
328+ frame . tool . instructions . startsWith ( '#!sys.openapi' )
329+ ) {
330+ return ( ) => {
331+ const toolName = frame . tool ?. name ?? '' ; // Not possible for this to be null, but I have to satisfy the type checker.
332+ const operation = JSON . parse ( frame . input as string ) [ 'operation' ] ;
333+
334+ if ( ! trustedOpenAPIRef . current [ toolName ] ) {
335+ trustedOpenAPIRef . current [ toolName ] = { } ;
336+ }
337+ trustedOpenAPIRef . current [ toolName ] [ operation ] = true ;
338+ } ;
339+ }
340+
296341 return frame . tool . source ?. repo
297342 ? ( ) => {
298343 const repo = frame . tool ! . source ?. repo ! . Root ;
0 commit comments