From 451a2c1260358ff14259c234ea7e8b7845809941 Mon Sep 17 00:00:00 2001 From: KarielHalling Date: Fri, 12 Sep 2025 16:53:09 +0800 Subject: [PATCH 1/5] feat: add AI plugin communication interface standards Define standard interfaces for AI plugin communication: - AIRequest: model + prompt + config (following langchaingo pattern) - AIResponse: content + metadata - AICapabilities: plugin capability discovery - Standard plugin message format using existing ExtManager system - AI plugins identified via StoreKind.Categories: ["ai"] --- pkg/server/ai_interface.go | 58 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 pkg/server/ai_interface.go diff --git a/pkg/server/ai_interface.go b/pkg/server/ai_interface.go new file mode 100644 index 000000000..fcb2d17bd --- /dev/null +++ b/pkg/server/ai_interface.go @@ -0,0 +1,58 @@ +/* +Copyright 2024 API Testing Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package server + +// AIRequest represents a standard request to an AI plugin +// Following the simplicity principle: model name + prompt + optional config +type AIRequest struct { + Model string `json:"model"` // Model identifier (e.g., "gpt-4", "claude") + Prompt string `json:"prompt"` // The prompt or instruction + Config map[string]interface{} `json:"config"` // Optional configuration (temperature, max_tokens, etc.) +} + +// AIResponse represents a standard response from an AI plugin +type AIResponse struct { + Content string `json:"content"` // The generated response + Meta map[string]interface{} `json:"meta"` // Optional metadata (model info, timing, etc.) +} + +// AICapabilities represents what an AI plugin can do +type AICapabilities struct { + Models []string `json:"models"` // Supported models + Features []string `json:"features"` // Supported features (chat, completion, etc.) + Limits map[string]int `json:"limits"` // Limits (max_tokens, rate_limit, etc.) + Description string `json:"description"` // Plugin description + Version string `json:"version"` // Plugin version +} + +// Standard AI plugin communication methods +const ( + AIMethodGenerate = "ai.generate" // Generate content from prompt + AIMethodCapabilities = "ai.capabilities" // Get plugin capabilities +) + +// Standard plugin communication message format +type PluginRequest struct { + Method string `json:"method"` // Method name + Payload interface{} `json:"payload"` // Request payload +} + +type PluginResponse struct { + Success bool `json:"success"` // Whether request succeeded + Data interface{} `json:"data"` // Response data + Error string `json:"error"` // Error message if failed +} \ No newline at end of file From 41163b3eef7d42458dddc17fc22538e3ae84e760 Mon Sep 17 00:00:00 2001 From: KarielHalling Date: Fri, 12 Sep 2025 17:00:04 +0800 Subject: [PATCH 2/5] feat: integrate AI plugin support into server and extension loading - Add AI plugin detection in startPlugins() function - logs when AI plugins are started - Implement GetAIPlugins() method to filter stores by 'ai' category - Add SendAIRequest() and GetAICapabilities() methods with TODO for plugin communication - Add AI plugin example in extension.yaml with OpenAI configuration - Use existing ExtManager and StoreKind architecture - AI plugins follow same patterns as other plugins - Compatible with existing protobuf Categories field for plugin classification This provides the complete AI plugin integration foundation while maintaining unified plugin architecture. --- cmd/server.go | 8 +++ pkg/server/remote_server.go | 61 +++++++++++++++++++ pkg/testing/testdata/data/core/extension.yaml | 16 +++++ 3 files changed, 85 insertions(+) diff --git a/cmd/server.go b/cmd/server.go index fae78c248..b39df4968 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -446,6 +446,14 @@ func startPlugins(storeExtMgr server.ExtManager, stores *server.Stores) (err err kind := store.Kind err = errors.Join(err, storeExtMgr.Start(kind.Name, kind.Url)) + + // Start AI plugins if this store kind has AI category + for _, category := range kind.Categories { + if category == "ai" { + serverLogger.Info("Starting AI plugin", "name", kind.Name, "categories", kind.Categories) + break + } + } } return } diff --git a/pkg/server/remote_server.go b/pkg/server/remote_server.go index c88017ee1..202ab8d60 100644 --- a/pkg/server/remote_server.go +++ b/pkg/server/remote_server.go @@ -1765,3 +1765,64 @@ func (s *UniqueSlice[T]) GetAll() []T { } var errNoTestSuiteFound = errors.New("no test suite found") + +// AI Plugin Communication Methods +// These methods provide communication interface for AI plugins using the existing ExtManager + +// GetAIPlugins returns all plugins with "ai" category +func (s *server) GetAIPlugins(ctx context.Context, req *Empty) (*StoreKinds, error) { + stores, err := s.GetStoreKinds(ctx, req) + if err != nil { + return nil, err + } + + var aiPlugins []*StoreKind + for _, store := range stores.Data { + for _, category := range store.Categories { + if category == "ai" { + aiPlugins = append(aiPlugins, store) + break + } + } + } + + return &StoreKinds{Data: aiPlugins}, nil +} + +// SendAIRequest sends a request to an AI plugin using the standard plugin communication protocol +func (s *server) SendAIRequest(ctx context.Context, pluginName string, req *AIRequest) (*AIResponse, error) { + // This would communicate with the AI plugin via unix socket using PluginRequest/PluginResponse + // Implementation would be similar to other plugin communications + + // TODO: Send pluginReq to plugin via storeExtMgr communication channel + // pluginReq := &PluginRequest{ + // Method: AIMethodGenerate, + // Payload: req, + // } + + remoteServerLogger.Info("Sending AI request", "plugin", pluginName, "model", req.Model) + + return &AIResponse{ + Content: "AI response placeholder - implementation needed", + Meta: map[string]interface{}{"plugin": pluginName, "model": req.Model}, + }, nil +} + +// GetAICapabilities gets capabilities from an AI plugin +func (s *server) GetAICapabilities(ctx context.Context, pluginName string) (*AICapabilities, error) { + // TODO: Send pluginReq to plugin via storeExtMgr communication channel + // pluginReq := &PluginRequest{ + // Method: AIMethodCapabilities, + // Payload: &Empty{}, + // } + + remoteServerLogger.Info("Getting AI capabilities", "plugin", pluginName) + + return &AICapabilities{ + Models: []string{"placeholder-model"}, + Features: []string{"generate", "capabilities"}, + Limits: map[string]int{"max_tokens": 4096}, + Description: "AI plugin capabilities placeholder", + Version: "1.0.0", + }, nil +} diff --git a/pkg/testing/testdata/data/core/extension.yaml b/pkg/testing/testdata/data/core/extension.yaml index de7d5be96..32c552c30 100644 --- a/pkg/testing/testdata/data/core/extension.yaml +++ b/pkg/testing/testdata/data/core/extension.yaml @@ -3,3 +3,19 @@ items: dependencies: - name: atest-store-database link: https://github.com/LinuxSuRen/atest-ext-store-database + - name: atest-ai-openai + dependencies: + - name: atest-ai-openai + link: https://github.com/LinuxSuRen/atest-ext-ai-openai + categories: ["ai"] + params: + - key: api_key + description: OpenAI API Key + defaultValue: "" + - key: model + description: OpenAI Model + defaultValue: "gpt-4" + enum: ["gpt-3.5-turbo", "gpt-4", "gpt-4-turbo"] + - key: temperature + description: Sampling temperature + defaultValue: "0.7" From 8d6d386f24e7ccd4d0777e92ba4c1a55ef540a39 Mon Sep 17 00:00:00 2001 From: KarielHalling Date: Fri, 12 Sep 2025 17:03:04 +0800 Subject: [PATCH 3/5] fix: remove unnecessary AI plugin detection code in startPlugins() AI plugins should be treated exactly like other plugins in the startup process. The ExtManager.Start() method handles all plugins uniformly - AI plugins are only distinguished by their Categories field, not by special startup logic. This maintains the unified plugin architecture principle. --- cmd/server.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/cmd/server.go b/cmd/server.go index b39df4968..fae78c248 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -446,14 +446,6 @@ func startPlugins(storeExtMgr server.ExtManager, stores *server.Stores) (err err kind := store.Kind err = errors.Join(err, storeExtMgr.Start(kind.Name, kind.Url)) - - // Start AI plugins if this store kind has AI category - for _, category := range kind.Categories { - if category == "ai" { - serverLogger.Info("Starting AI plugin", "name", kind.Name, "categories", kind.Categories) - break - } - } } return } From e28e3e8b1a0b28819552205f618d842a6c0edabe Mon Sep 17 00:00:00 2001 From: KarielHalling Date: Fri, 12 Sep 2025 17:04:31 +0800 Subject: [PATCH 4/5] fix: standardize AI plugin configuration format - Change plugin name from 'atest-ai-openai' to 'atest-ext-ai' following naming convention - Remove specific OpenAI parameters and implementation details - Keep only the essential configuration matching other plugins format - AI plugin now follows exact same structure as atest-store-database - Only difference is the categories: ['ai'] field for classification --- pkg/testing/testdata/data/core/extension.yaml | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/pkg/testing/testdata/data/core/extension.yaml b/pkg/testing/testdata/data/core/extension.yaml index 32c552c30..4464b6abb 100644 --- a/pkg/testing/testdata/data/core/extension.yaml +++ b/pkg/testing/testdata/data/core/extension.yaml @@ -3,19 +3,8 @@ items: dependencies: - name: atest-store-database link: https://github.com/LinuxSuRen/atest-ext-store-database - - name: atest-ai-openai + - name: atest-ext-ai dependencies: - - name: atest-ai-openai - link: https://github.com/LinuxSuRen/atest-ext-ai-openai + - name: atest-ext-ai + link: https://github.com/LinuxSuRen/atest-ext-ai categories: ["ai"] - params: - - key: api_key - description: OpenAI API Key - defaultValue: "" - - key: model - description: OpenAI Model - defaultValue: "gpt-4" - enum: ["gpt-3.5-turbo", "gpt-4", "gpt-4-turbo"] - - key: temperature - description: Sampling temperature - defaultValue: "0.7" From 122ebdf9cfdd4c540f22dae2c767a7306c122018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zhiyuan=20Zhao=28=E8=B5=B5=E5=BF=97=E8=BF=9C=29?= Date: Fri, 12 Sep 2025 21:04:54 +0800 Subject: [PATCH 5/5] Update copyright year in ai_interface.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Zhiyuan Zhao(赵志远) --- pkg/server/ai_interface.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/server/ai_interface.go b/pkg/server/ai_interface.go index fcb2d17bd..169320cf9 100644 --- a/pkg/server/ai_interface.go +++ b/pkg/server/ai_interface.go @@ -1,5 +1,5 @@ /* -Copyright 2024 API Testing Authors. +Copyright 2025 API Testing Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -55,4 +55,4 @@ type PluginResponse struct { Success bool `json:"success"` // Whether request succeeded Data interface{} `json:"data"` // Response data Error string `json:"error"` // Error message if failed -} \ No newline at end of file +}