Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
349
backend/sdk/api/handlers/handlers_execution.go
Normal file
349
backend/sdk/api/handlers/handlers_execution.go
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/internal/clienterror"
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/internal/interfaces"
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/internal/runtime/executor/helps"
|
||||
coreexecutor "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/executor"
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/sdk/pluginapi"
|
||||
sdktranslator "github.com/router-for-me/CLIProxyAPI/v7/sdk/translator"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// PluginExecutorHost executes a routed request with a specific plugin executor.
|
||||
type PluginExecutorHost interface {
|
||||
ExecutePluginExecutor(context.Context, string, coreexecutor.Request, coreexecutor.Options) (coreexecutor.Response, error)
|
||||
ExecutePluginExecutorStream(context.Context, string, coreexecutor.Request, coreexecutor.Options) (*coreexecutor.StreamResult, error)
|
||||
CountPluginExecutor(context.Context, string, coreexecutor.Request, coreexecutor.Options) (coreexecutor.Response, error)
|
||||
}
|
||||
|
||||
type pluginExecutorFormatResolver interface {
|
||||
PluginExecutorRequestToFormat(string, coreexecutor.Request, coreexecutor.Options) sdktranslator.Format
|
||||
}
|
||||
|
||||
// ExecuteWithAuthManager executes a non-streaming request via the core auth manager.
|
||||
// This path is the only supported execution route.
|
||||
func (h *BaseAPIHandler) ExecuteWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string) ([]byte, http.Header, *interfaces.ErrorMessage) {
|
||||
return h.executeWithAuthManager(ctx, handlerType, modelName, rawJSON, alt, false)
|
||||
}
|
||||
|
||||
// ExecuteImageWithAuthManager executes an OpenAI-compatible image endpoint request.
|
||||
func (h *BaseAPIHandler) ExecuteImageWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string) ([]byte, http.Header, *interfaces.ErrorMessage) {
|
||||
return h.executeWithAuthManager(ctx, handlerType, modelName, rawJSON, alt, true)
|
||||
}
|
||||
|
||||
func (h *BaseAPIHandler) executeWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string, allowImageModel bool) ([]byte, http.Header, *interfaces.ErrorMessage) {
|
||||
return h.executeWithAuthManagerFormats(ctx, handlerType, handlerType, modelName, rawJSON, alt, allowImageModel, modelExecutionOptions{})
|
||||
}
|
||||
|
||||
func (h *BaseAPIHandler) executeWithAuthManagerFormats(ctx context.Context, entryProtocol, exitProtocol, modelName string, rawJSON []byte, alt string, allowImageModel bool, execOptions modelExecutionOptions) ([]byte, http.Header, *interfaces.ErrorMessage) {
|
||||
originalRequestedModel := modelName
|
||||
routeDecision := h.applyModelRouter(ctx, entryProtocol, modelName, rawJSON, false, execOptions)
|
||||
responseProtocol := modelExecutionResponseProtocol(entryProtocol, exitProtocol)
|
||||
if errMsg := validateNativeInteractionsExecution(entryProtocol, execOptions, routeDecision); errMsg != nil {
|
||||
return nil, nil, errMsg
|
||||
}
|
||||
if routeDecision.ExecutorPluginID != "" {
|
||||
return h.executeWithPluginExecutor(ctx, entryProtocol, responseProtocol, modelName, originalRequestedModel, rawJSON, alt, routeDecision.ExecutorPluginID, execOptions)
|
||||
}
|
||||
providers, normalizedModel, errMsg := h.providersForExecution(modelName, originalRequestedModel, allowImageModel, routeDecision, execOptions)
|
||||
if errMsg != nil {
|
||||
return nil, nil, errMsg
|
||||
}
|
||||
providers = adjustExecutionProvidersForEntryProtocol(entryProtocol, providers)
|
||||
reqMeta := requestExecutionMetadata(ctx)
|
||||
reqMeta[coreexecutor.RequestedModelMetadataKey] = originalRequestedModel
|
||||
addAuthSelectionModelMetadata(reqMeta, execOptions.AuthSelectionModel)
|
||||
addModelExecutionSourceMetadata(reqMeta, execOptions.InternalSource)
|
||||
setReasoningEffortMetadata(reqMeta, entryProtocol, normalizedModel, rawJSON)
|
||||
setServiceTierMetadata(reqMeta, rawJSON)
|
||||
setGenerateMetadata(reqMeta, rawJSON)
|
||||
payload := rawJSON
|
||||
if len(payload) == 0 {
|
||||
payload = nil
|
||||
}
|
||||
req := coreexecutor.Request{
|
||||
Model: normalizedModel,
|
||||
Payload: payload,
|
||||
}
|
||||
afterAuthCapture := &requestAfterAuthCapture{}
|
||||
lifecycle := h.newRequestLifecycleTracker(ctx, entryProtocol, normalizedModel, originalRequestedModel, false, reqMeta, execOptions.SkipInterceptorPluginID)
|
||||
opts := coreexecutor.Options{
|
||||
Stream: false,
|
||||
Alt: alt,
|
||||
OriginalRequest: rawJSON,
|
||||
SourceFormat: sdktranslator.FromString(entryProtocol),
|
||||
ResponseFormat: sdktranslator.FromString(responseProtocol),
|
||||
Headers: modelExecutionHeaders(ctx, execOptions.Headers),
|
||||
Query: modelExecutionQuery(ctx, execOptions.Query),
|
||||
RequestAfterAuthInterceptor: h.requestAfterAuthInterceptor(afterAuthCapture, lifecycle.requestID(), execOptions.SkipInterceptorPluginID),
|
||||
}
|
||||
opts.Metadata = reqMeta
|
||||
var interceptErr *interfaces.ErrorMessage
|
||||
req, opts, interceptErr = h.applyRequestInterceptorsBeforeAuth(ctx, entryProtocol, originalRequestedModel, lifecycle.requestID(), req, opts, execOptions.SkipInterceptorPluginID)
|
||||
if interceptErr != nil {
|
||||
lifecycle.completeError(ctx, interceptErr)
|
||||
return nil, nil, interceptErr
|
||||
}
|
||||
resp, err := h.AuthManager.Execute(ctx, providers, req, opts)
|
||||
if err != nil {
|
||||
err = enrichAuthSelectionError(err, providers, normalizedModel)
|
||||
errMsg := executionErrorMessage(err)
|
||||
lifecycle.completeError(ctx, errMsg)
|
||||
return nil, nil, errMsg
|
||||
}
|
||||
executedReq, executedOpts := afterAuthCapture.apply(req, opts)
|
||||
rawResponseHeaders := cloneHeader(resp.Headers)
|
||||
responseHeaders := downstreamHeadersFromExecutor(rawResponseHeaders, PassthroughHeadersEnabled(h.Cfg))
|
||||
body, responseHeaders := h.applyResponseInterceptors(ctx, lifecycle.requestID(), responseProtocol, normalizedModel, originalRequestedModel, executedOpts, rawResponseHeaders, responseHeaders, executedOpts.OriginalRequest, executedReq.Payload, resp.Payload, http.StatusOK, execOptions.SkipInterceptorPluginID)
|
||||
lifecycle.complete(pluginapi.RequestCompletionSucceeded, http.StatusOK, nil)
|
||||
return body, responseHeaders, nil
|
||||
}
|
||||
|
||||
// ExecuteCountWithAuthManager executes a non-streaming request via the core auth manager.
|
||||
// This path is the only supported execution route.
|
||||
func (h *BaseAPIHandler) ExecuteCountWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string) ([]byte, http.Header, *interfaces.ErrorMessage) {
|
||||
return h.executeCountWithAuthManager(ctx, handlerType, modelName, rawJSON, alt, modelExecutionOptions{})
|
||||
}
|
||||
|
||||
func (h *BaseAPIHandler) executeCountWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string, execOptions modelExecutionOptions) ([]byte, http.Header, *interfaces.ErrorMessage) {
|
||||
originalRequestedModel := modelName
|
||||
routeDecision := h.applyModelRouter(ctx, handlerType, modelName, rawJSON, false, execOptions)
|
||||
if routeDecision.ExecutorPluginID != "" {
|
||||
return h.countWithPluginExecutor(ctx, handlerType, modelName, originalRequestedModel, rawJSON, alt, routeDecision.ExecutorPluginID, execOptions)
|
||||
}
|
||||
providers, normalizedModel, errMsg := h.providersForExecution(modelName, originalRequestedModel, false, routeDecision, execOptions)
|
||||
if errMsg != nil {
|
||||
return nil, nil, errMsg
|
||||
}
|
||||
providers = adjustExecutionProvidersForEntryProtocol(handlerType, providers)
|
||||
reqMeta := requestExecutionMetadata(ctx)
|
||||
reqMeta[coreexecutor.RequestedModelMetadataKey] = originalRequestedModel
|
||||
addAuthSelectionModelMetadata(reqMeta, execOptions.AuthSelectionModel)
|
||||
setReasoningEffortMetadata(reqMeta, handlerType, normalizedModel, rawJSON)
|
||||
setServiceTierMetadata(reqMeta, rawJSON)
|
||||
setGenerateMetadata(reqMeta, rawJSON)
|
||||
payload := rawJSON
|
||||
if len(payload) == 0 {
|
||||
payload = nil
|
||||
}
|
||||
req := coreexecutor.Request{
|
||||
Model: normalizedModel,
|
||||
Payload: payload,
|
||||
}
|
||||
afterAuthCapture := &requestAfterAuthCapture{}
|
||||
lifecycle := h.newRequestLifecycleTracker(ctx, handlerType, normalizedModel, originalRequestedModel, false, reqMeta, execOptions.SkipInterceptorPluginID)
|
||||
opts := coreexecutor.Options{
|
||||
Stream: false,
|
||||
Alt: alt,
|
||||
OriginalRequest: rawJSON,
|
||||
SourceFormat: sdktranslator.FromString(handlerType),
|
||||
Headers: modelExecutionHeaders(ctx, execOptions.Headers),
|
||||
Query: modelExecutionQuery(ctx, execOptions.Query),
|
||||
RequestAfterAuthInterceptor: h.requestAfterAuthInterceptor(afterAuthCapture, lifecycle.requestID(), execOptions.SkipInterceptorPluginID),
|
||||
}
|
||||
opts.Metadata = reqMeta
|
||||
var interceptErr *interfaces.ErrorMessage
|
||||
req, opts, interceptErr = h.applyRequestInterceptorsBeforeAuth(ctx, handlerType, originalRequestedModel, lifecycle.requestID(), req, opts, execOptions.SkipInterceptorPluginID)
|
||||
if interceptErr != nil {
|
||||
lifecycle.completeError(ctx, interceptErr)
|
||||
return nil, nil, interceptErr
|
||||
}
|
||||
resp, err := h.AuthManager.ExecuteCount(ctx, providers, req, opts)
|
||||
if err != nil {
|
||||
err = enrichAuthSelectionError(err, providers, normalizedModel)
|
||||
errMsg := executionErrorMessage(err)
|
||||
lifecycle.completeError(ctx, errMsg)
|
||||
return nil, nil, errMsg
|
||||
}
|
||||
executedReq, executedOpts := afterAuthCapture.apply(req, opts)
|
||||
rawResponseHeaders := cloneHeader(resp.Headers)
|
||||
responseHeaders := downstreamHeadersFromExecutor(rawResponseHeaders, PassthroughHeadersEnabled(h.Cfg))
|
||||
body, responseHeaders := h.applyResponseInterceptors(ctx, lifecycle.requestID(), handlerType, normalizedModel, originalRequestedModel, executedOpts, rawResponseHeaders, responseHeaders, executedOpts.OriginalRequest, executedReq.Payload, resp.Payload, http.StatusOK, execOptions.SkipInterceptorPluginID)
|
||||
lifecycle.complete(pluginapi.RequestCompletionSucceeded, http.StatusOK, nil)
|
||||
return body, responseHeaders, nil
|
||||
}
|
||||
|
||||
func (h *BaseAPIHandler) executeWithPluginExecutor(ctx context.Context, entryProtocol, responseProtocol, modelName, originalRequestedModel string, rawJSON []byte, alt, executorPluginID string, execOptions modelExecutionOptions) ([]byte, http.Header, *interfaces.ErrorMessage) {
|
||||
if h.AuthManager != nil && h.AuthManager.HomeEnabled() {
|
||||
return nil, nil, &interfaces.ErrorMessage{StatusCode: http.StatusServiceUnavailable, Error: fmt.Errorf("plugin executor routing is unavailable while Home is enabled")}
|
||||
}
|
||||
host := h.pluginExecutorHost()
|
||||
if host == nil {
|
||||
return nil, nil, &interfaces.ErrorMessage{StatusCode: http.StatusBadGateway, Error: fmt.Errorf("plugin executor host is unavailable")}
|
||||
}
|
||||
execCtx, nestedTracker := withNestedExecutionTracker(ctx)
|
||||
req, opts := h.pluginExecutorRequest(execCtx, entryProtocol, responseProtocol, modelName, originalRequestedModel, rawJSON, alt, false, execOptions)
|
||||
lifecycle := h.newRequestLifecycleTracker(execCtx, entryProtocol, modelName, originalRequestedModel, false, opts.Metadata, execOptions.SkipInterceptorPluginID)
|
||||
var interceptErr *interfaces.ErrorMessage
|
||||
req, opts, interceptErr = h.applyRequestInterceptorsBeforeAuth(execCtx, entryProtocol, originalRequestedModel, lifecycle.requestID(), req, opts, execOptions.SkipInterceptorPluginID)
|
||||
if interceptErr != nil {
|
||||
lifecycle.completeError(execCtx, interceptErr)
|
||||
return nil, nil, interceptErr
|
||||
}
|
||||
req, opts, interceptErr = h.applyRequestInterceptorsAfterPluginExecutorRoute(execCtx, host, executorPluginID, entryProtocol, originalRequestedModel, lifecycle.requestID(), req, opts, execOptions.SkipInterceptorPluginID)
|
||||
if interceptErr != nil {
|
||||
lifecycle.completeError(execCtx, interceptErr)
|
||||
return nil, nil, interceptErr
|
||||
}
|
||||
var reporter *helps.UsageReporter
|
||||
if !execOptions.InternalSource {
|
||||
reporter = helps.NewUsageReporter(execCtx, executorPluginID, modelName, nil)
|
||||
reporter.SetTranslatedReasoningEffort(req.Payload, entryProtocol)
|
||||
}
|
||||
resp, errExecute := host.ExecutePluginExecutor(execCtx, executorPluginID, req, opts)
|
||||
if errExecute != nil {
|
||||
if reporter != nil && !nestedTracker.hasNestedExecution() {
|
||||
reporter.PublishFailure(execCtx, errExecute)
|
||||
}
|
||||
errMsg := executionErrorMessage(errExecute)
|
||||
lifecycle.completeError(execCtx, errMsg)
|
||||
return nil, nil, errMsg
|
||||
}
|
||||
if reporter != nil && !nestedTracker.hasNestedExecution() {
|
||||
detail := parsePluginExecutorResponseUsage(responseProtocol, resp.Payload)
|
||||
reporter.Publish(execCtx, detail)
|
||||
reporter.EnsurePublished(execCtx)
|
||||
}
|
||||
rawResponseHeaders := cloneHeader(resp.Headers)
|
||||
responseHeaders := downstreamHeadersFromExecutor(rawResponseHeaders, PassthroughHeadersEnabled(h.Cfg))
|
||||
body, responseHeaders := h.applyResponseInterceptors(execCtx, lifecycle.requestID(), responseProtocol, modelName, originalRequestedModel, opts, rawResponseHeaders, responseHeaders, opts.OriginalRequest, req.Payload, resp.Payload, http.StatusOK, execOptions.SkipInterceptorPluginID)
|
||||
lifecycle.complete(pluginapi.RequestCompletionSucceeded, http.StatusOK, nil)
|
||||
return body, responseHeaders, nil
|
||||
}
|
||||
|
||||
func (h *BaseAPIHandler) countWithPluginExecutor(ctx context.Context, handlerType, modelName, originalRequestedModel string, rawJSON []byte, alt, executorPluginID string, execOptions modelExecutionOptions) ([]byte, http.Header, *interfaces.ErrorMessage) {
|
||||
if h.AuthManager != nil && h.AuthManager.HomeEnabled() {
|
||||
return nil, nil, &interfaces.ErrorMessage{StatusCode: http.StatusServiceUnavailable, Error: fmt.Errorf("plugin executor routing is unavailable while Home is enabled")}
|
||||
}
|
||||
host := h.pluginExecutorHost()
|
||||
if host == nil {
|
||||
return nil, nil, &interfaces.ErrorMessage{StatusCode: http.StatusBadGateway, Error: fmt.Errorf("plugin executor host is unavailable")}
|
||||
}
|
||||
req, opts := h.pluginExecutorRequest(ctx, handlerType, handlerType, modelName, originalRequestedModel, rawJSON, alt, false, execOptions)
|
||||
lifecycle := h.newRequestLifecycleTracker(ctx, handlerType, modelName, originalRequestedModel, false, opts.Metadata, execOptions.SkipInterceptorPluginID)
|
||||
var interceptErr *interfaces.ErrorMessage
|
||||
req, opts, interceptErr = h.applyRequestInterceptorsBeforeAuth(ctx, handlerType, originalRequestedModel, lifecycle.requestID(), req, opts, execOptions.SkipInterceptorPluginID)
|
||||
if interceptErr != nil {
|
||||
lifecycle.completeError(ctx, interceptErr)
|
||||
return nil, nil, interceptErr
|
||||
}
|
||||
req, opts, interceptErr = h.applyRequestInterceptorsAfterPluginExecutorRoute(ctx, host, executorPluginID, handlerType, originalRequestedModel, lifecycle.requestID(), req, opts, execOptions.SkipInterceptorPluginID)
|
||||
if interceptErr != nil {
|
||||
lifecycle.completeError(ctx, interceptErr)
|
||||
return nil, nil, interceptErr
|
||||
}
|
||||
resp, errCount := host.CountPluginExecutor(ctx, executorPluginID, req, opts)
|
||||
if errCount != nil {
|
||||
errMsg := executionErrorMessage(errCount)
|
||||
lifecycle.completeError(ctx, errMsg)
|
||||
return nil, nil, errMsg
|
||||
}
|
||||
rawResponseHeaders := cloneHeader(resp.Headers)
|
||||
responseHeaders := downstreamHeadersFromExecutor(rawResponseHeaders, PassthroughHeadersEnabled(h.Cfg))
|
||||
body, responseHeaders := h.applyResponseInterceptors(ctx, lifecycle.requestID(), handlerType, modelName, originalRequestedModel, opts, rawResponseHeaders, responseHeaders, opts.OriginalRequest, req.Payload, resp.Payload, http.StatusOK, execOptions.SkipInterceptorPluginID)
|
||||
lifecycle.complete(pluginapi.RequestCompletionSucceeded, http.StatusOK, nil)
|
||||
return body, responseHeaders, nil
|
||||
}
|
||||
|
||||
func (h *BaseAPIHandler) pluginExecutorRequest(ctx context.Context, entryProtocol, responseProtocol, modelName, originalRequestedModel string, rawJSON []byte, alt string, stream bool, execOptions modelExecutionOptions) (coreexecutor.Request, coreexecutor.Options) {
|
||||
reqMeta := requestExecutionMetadata(ctx)
|
||||
reqMeta[coreexecutor.RequestedModelMetadataKey] = originalRequestedModel
|
||||
addAuthSelectionModelMetadata(reqMeta, execOptions.AuthSelectionModel)
|
||||
addModelExecutionSourceMetadata(reqMeta, execOptions.InternalSource)
|
||||
setReasoningEffortMetadata(reqMeta, entryProtocol, modelName, rawJSON)
|
||||
setServiceTierMetadata(reqMeta, rawJSON)
|
||||
setGenerateMetadata(reqMeta, rawJSON)
|
||||
payload := rawJSON
|
||||
if len(payload) == 0 {
|
||||
payload = nil
|
||||
}
|
||||
req := coreexecutor.Request{Model: modelName, Payload: payload}
|
||||
opts := coreexecutor.Options{
|
||||
Stream: stream,
|
||||
Alt: alt,
|
||||
OriginalRequest: rawJSON,
|
||||
SourceFormat: sdktranslator.FromString(entryProtocol),
|
||||
ResponseFormat: sdktranslator.FromString(responseProtocol),
|
||||
Headers: modelExecutionHeaders(ctx, execOptions.Headers),
|
||||
Query: modelExecutionQuery(ctx, execOptions.Query),
|
||||
Metadata: reqMeta,
|
||||
}
|
||||
return req, opts
|
||||
}
|
||||
|
||||
func (h *BaseAPIHandler) applyRequestInterceptorsAfterPluginExecutorRoute(ctx context.Context, host PluginExecutorHost, executorPluginID, entryProtocol, originalRequestedModel, requestID string, req coreexecutor.Request, opts coreexecutor.Options, skipPluginID string) (coreexecutor.Request, coreexecutor.Options, *interfaces.ErrorMessage) {
|
||||
if !requestInterceptorsEnabled(h.interceptorHost()) {
|
||||
return req, opts, nil
|
||||
}
|
||||
toFormat := sdktranslator.FromString(entryProtocol)
|
||||
if resolver, ok := host.(pluginExecutorFormatResolver); ok && resolver != nil {
|
||||
if resolved := resolver.PluginExecutorRequestToFormat(executorPluginID, req, opts); resolved != "" {
|
||||
toFormat = resolved
|
||||
}
|
||||
}
|
||||
resp := h.applyRequestInterceptorsAfterAuth(ctx, coreexecutor.RequestAfterAuthInterceptRequest{
|
||||
SourceFormat: opts.SourceFormat,
|
||||
ToFormat: toFormat,
|
||||
Model: req.Model,
|
||||
RequestedModel: originalRequestedModel,
|
||||
Stream: opts.Stream,
|
||||
Headers: cloneHeader(opts.Headers),
|
||||
Body: cloneBytes(req.Payload),
|
||||
Metadata: opts.Metadata,
|
||||
}, requestID, skipPluginID)
|
||||
opts.Headers = mergeRequestInterceptorHeaders(opts.Headers, resp.Headers, resp.ClearHeaders)
|
||||
if len(resp.Body) > 0 {
|
||||
req.Payload = cloneBytes(resp.Body)
|
||||
opts.OriginalRequest = cloneBytes(resp.Body)
|
||||
}
|
||||
if resp.Terminate {
|
||||
return req, opts, directTerminationError(resp.StatusCode, resp.ResponseHeaders, resp.ResponseBody)
|
||||
}
|
||||
return req, opts, nil
|
||||
}
|
||||
|
||||
func ExecutionErrorMessage(err error) *interfaces.ErrorMessage {
|
||||
return executionErrorMessage(err)
|
||||
}
|
||||
|
||||
func executionErrorMessage(err error) *interfaces.ErrorMessage {
|
||||
var terminated *coreexecutor.RequestTerminatedError
|
||||
if errors.As(err, &terminated) && terminated != nil {
|
||||
return &interfaces.ErrorMessage{
|
||||
StatusCode: normalizedTerminationStatus(terminated.StatusCode()),
|
||||
Error: err,
|
||||
DirectResponse: true,
|
||||
Body: terminated.ResponseBody(),
|
||||
Headers: terminated.ResponseHeaders(),
|
||||
}
|
||||
}
|
||||
status := http.StatusInternalServerError
|
||||
if code := clienterror.HTTPStatusFromError(err); code > 0 {
|
||||
status = code
|
||||
}
|
||||
var addon http.Header
|
||||
if he, ok := err.(interface{ Headers() http.Header }); ok && he != nil {
|
||||
if hdr := he.Headers(); hdr != nil {
|
||||
addon = hdr.Clone()
|
||||
}
|
||||
}
|
||||
return &interfaces.ErrorMessage{StatusCode: status, Error: err, Addon: addon}
|
||||
}
|
||||
|
||||
func (h *BaseAPIHandler) pluginExecutorHost() PluginExecutorHost {
|
||||
if h == nil {
|
||||
return nil
|
||||
}
|
||||
if executorHost, ok := h.ModelRouterHost.(PluginExecutorHost); ok && executorHost != nil {
|
||||
return executorHost
|
||||
}
|
||||
if executorHost, ok := h.PluginHost.(PluginExecutorHost); ok && executorHost != nil {
|
||||
return executorHost
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Loading…
Reference in a new issue