@@ -20,10 +20,10 @@ import (
2020 "github.com/gptscript-ai/gptscript/pkg/assemble"
2121 "github.com/gptscript-ai/gptscript/pkg/builtin"
2222 "github.com/gptscript-ai/gptscript/pkg/cache"
23+ "github.com/gptscript-ai/gptscript/pkg/hash"
2324 "github.com/gptscript-ai/gptscript/pkg/parser"
2425 "github.com/gptscript-ai/gptscript/pkg/system"
2526 "github.com/gptscript-ai/gptscript/pkg/types"
26- "gopkg.in/yaml.v3"
2727)
2828
2929const CacheTimeout = time .Hour
@@ -120,24 +120,50 @@ func loadProgram(data []byte, into *types.Program, targetToolName string) (types
120120 return tool , nil
121121}
122122
123+ func loadOpenAPI (prg * types.Program , data []byte ) * openapi3.T {
124+ var (
125+ openAPICacheKey = hash .Digest (data )
126+ openAPIDocument , ok = prg .OpenAPICache [openAPICacheKey ].(* openapi3.T )
127+ err error
128+ )
129+
130+ if ok {
131+ return openAPIDocument
132+ }
133+
134+ if prg .OpenAPICache == nil {
135+ prg .OpenAPICache = map [string ]any {}
136+ }
137+
138+ openAPIDocument , err = openapi3 .NewLoader ().LoadFromData (data )
139+ if err != nil || openAPIDocument .Paths .Len () == 0 {
140+ openAPIDocument = nil
141+ }
142+
143+ prg .OpenAPICache [openAPICacheKey ] = openAPIDocument
144+ return openAPIDocument
145+ }
146+
123147func readTool (ctx context.Context , cache * cache.Client , prg * types.Program , base * source , targetToolName string ) (types.Tool , error ) {
124148 data := base .Content
125149
126150 if bytes .HasPrefix (data , assemble .Header ) {
127151 return loadProgram (data , prg , targetToolName )
128152 }
129153
130- var tools []types.Tool
131- if isOpenAPI (data ) {
132- if t , err := openapi3 .NewLoader ().LoadFromData (data ); err == nil {
133- if base .Remote {
134- tools , err = getOpenAPITools (t , base .Location )
135- } else {
136- tools , err = getOpenAPITools (t , "" )
137- }
138- if err != nil {
139- return types.Tool {}, fmt .Errorf ("error parsing OpenAPI definition: %w" , err )
140- }
154+ var (
155+ tools []types.Tool
156+ )
157+
158+ if openAPIDocument := loadOpenAPI (prg , data ); openAPIDocument != nil {
159+ var err error
160+ if base .Remote {
161+ tools , err = getOpenAPITools (openAPIDocument , base .Location )
162+ } else {
163+ tools , err = getOpenAPITools (openAPIDocument , "" )
164+ }
165+ if err != nil {
166+ return types.Tool {}, fmt .Errorf ("error parsing OpenAPI definition: %w" , err )
141167 }
142168 }
143169
@@ -263,6 +289,12 @@ func link(ctx context.Context, cache *cache.Client, prg *types.Program, base *so
263289}
264290
265291func ProgramFromSource (ctx context.Context , content , subToolName string , opts ... Options ) (types.Program , error ) {
292+ if log .IsDebug () {
293+ start := time .Now ()
294+ defer func () {
295+ log .Debugf ("loaded program from source took %v" , time .Since (start ))
296+ }()
297+ }
266298 opt := complete (opts ... )
267299
268300 prg := types.Program {
@@ -292,6 +324,13 @@ func complete(opts ...Options) (result Options) {
292324}
293325
294326func Program (ctx context.Context , name , subToolName string , opts ... Options ) (types.Program , error ) {
327+ if log .IsDebug () {
328+ start := time .Now ()
329+ defer func () {
330+ log .Debugf ("loaded program %s source took %v" , name , time .Since (start ))
331+ }()
332+ }
333+
295334 opt := complete (opts ... )
296335
297336 if subToolName == "" {
@@ -363,16 +402,3 @@ func SplitToolRef(targetToolName string) (toolName, subTool string) {
363402 return strings .Join (fields [idx + 1 :], " " ),
364403 strings .Join (fields [:idx ], " " )
365404}
366-
367- func isOpenAPI (data []byte ) bool {
368- var fragment struct {
369- Paths map [string ]any `json:"paths,omitempty"`
370- }
371-
372- if err := json .Unmarshal (data , & fragment ); err != nil {
373- if err := yaml .Unmarshal (data , & fragment ); err != nil {
374- return false
375- }
376- }
377- return len (fragment .Paths ) > 0
378- }
0 commit comments