From a89041e57ed64263486a6fb9c30653e472b56f47 Mon Sep 17 00:00:00 2001 From: Yogesh Chauhan Date: Thu, 28 Nov 2024 10:48:23 +0000 Subject: [PATCH] feat: [ML-334]: Extract interface for Intelligence service (#3066) * Fix copyright header * Fix lint issues wrt copyright & comment structure * feat: [ML-334]: Extract interfae for Intelligence service --- app/api/controller/aiagent/controller.go | 34 +-- .../controller/aiagent/generate_pipeline.go | 35 +-- .../aiagent/generate_pipeline_step.go | 29 +-- .../controller/aiagent/suggest_pipelines.go | 25 +-- app/api/controller/aiagent/types/common.go | 24 ++ app/api/controller/aiagent/types/pipeline.go | 49 +++++ app/api/controller/aiagent/types/stage.go | 29 +++ app/api/controller/aiagent/types/step.go | 29 +++ app/api/controller/aiagent/update_pipeline.go | 43 +--- app/api/controller/aiagent/wire.go | 4 +- app/api/handler/aiagent/generate_pipeline.go | 3 +- .../handler/aiagent/generate_pipeline_step.go | 3 +- app/api/handler/aiagent/suggest_pipelines.go | 3 +- app/api/handler/aiagent/update_pipeline.go | 3 +- app/services/aiagent/aiagent.go | 208 ------------------ app/services/aiagent/intelligence.go | 66 ++++++ app/services/aiagent/wire.go | 4 +- types/aigenerate/common.go | 24 ++ .../pipeline.go} | 34 +-- types/aigenerate/stage.go | 34 +++ types/aigenerate/step.go | 34 +++ 21 files changed, 353 insertions(+), 364 deletions(-) create mode 100644 app/api/controller/aiagent/types/common.go create mode 100644 app/api/controller/aiagent/types/pipeline.go create mode 100644 app/api/controller/aiagent/types/stage.go create mode 100644 app/api/controller/aiagent/types/step.go delete mode 100644 app/services/aiagent/aiagent.go create mode 100644 app/services/aiagent/intelligence.go create mode 100644 types/aigenerate/common.go rename types/{suggestions.go => aigenerate/pipeline.go} (80%) create mode 100644 types/aigenerate/stage.go create mode 100644 types/aigenerate/step.go diff --git a/app/api/controller/aiagent/controller.go b/app/api/controller/aiagent/controller.go index ea1b43194..29471f526 100644 --- a/app/api/controller/aiagent/controller.go +++ b/app/api/controller/aiagent/controller.go @@ -24,19 +24,19 @@ import ( ) type Controller struct { - authorizer authz.Authorizer - intelligenceService *aiagent.HarnessIntelligence - repoStore store.RepoStore - pipelineStore store.PipelineStore - executionStore store.ExecutionStore - git git.Interface - urlProvider url.Provider - slackbot *messaging.Slack + authorizer authz.Authorizer + intelligence aiagent.Intelligence + repoStore store.RepoStore + pipelineStore store.PipelineStore + executionStore store.ExecutionStore + git git.Interface + urlProvider url.Provider + slackbot *messaging.Slack } func NewController( authorizer authz.Authorizer, - pipeline *aiagent.HarnessIntelligence, + intelligence aiagent.Intelligence, repoStore store.RepoStore, pipelineStore store.PipelineStore, executionStore store.ExecutionStore, @@ -45,13 +45,13 @@ func NewController( slackbot *messaging.Slack, ) *Controller { return &Controller{ - authorizer: authorizer, - intelligenceService: pipeline, - repoStore: repoStore, - pipelineStore: pipelineStore, - executionStore: executionStore, - git: git, - urlProvider: urlProvider, - slackbot: slackbot, + authorizer: authorizer, + intelligence: intelligence, + repoStore: repoStore, + pipelineStore: pipelineStore, + executionStore: executionStore, + git: git, + urlProvider: urlProvider, + slackbot: slackbot, } } diff --git a/app/api/controller/aiagent/generate_pipeline.go b/app/api/controller/aiagent/generate_pipeline.go index c41c3ff9c..0e4f0e268 100644 --- a/app/api/controller/aiagent/generate_pipeline.go +++ b/app/api/controller/aiagent/generate_pipeline.go @@ -18,45 +18,26 @@ import ( "context" "fmt" - "github.com/harness/gitness/types" + controllertypes "github.com/harness/gitness/app/api/controller/aiagent/types" + aitypes "github.com/harness/gitness/types/aigenerate" ) -type GeneratePipelineInput struct { - Prompt string `json:"prompt"` - RepoRef string `json:"repo_ref"` -} - -type PipelineData struct { - YamlPipeline string `json:"yaml_pipeline"` -} - -type GeneratePipelineOutput struct { - Status string `json:"status"` - Data PipelineData `json:"data"` -} - func (c *Controller) GeneratePipeline( ctx context.Context, - in *GeneratePipelineInput, -) (*GeneratePipelineOutput, error) { - generateRequest := &types.PipelineGenerateRequest{ + in *controllertypes.GeneratePipelineInput, +) (*controllertypes.GeneratePipelineOutput, error) { + generateRequest := &aitypes.PipelineGenerateRequest{ Prompt: in.Prompt, RepoRef: in.RepoRef, } - // do permission check on repo here? - repo, err := c.repoStore.FindByRef(ctx, in.RepoRef) - if err != nil { - return nil, fmt.Errorf("failed to find repo by ref: %w", err) - } - - output, err := c.intelligenceService.Generate(ctx, generateRequest, repo) + output, err := c.intelligence.GeneratePipeline(ctx, generateRequest) if err != nil { return nil, fmt.Errorf("generate pipeline: %w", err) } - return &GeneratePipelineOutput{ + return &controllertypes.GeneratePipelineOutput{ Status: "SUCCESS", - Data: PipelineData{ + Data: controllertypes.PipelineData{ YamlPipeline: output.YAML, }, }, nil diff --git a/app/api/controller/aiagent/generate_pipeline_step.go b/app/api/controller/aiagent/generate_pipeline_step.go index c7904ceb7..098eed25d 100644 --- a/app/api/controller/aiagent/generate_pipeline_step.go +++ b/app/api/controller/aiagent/generate_pipeline_step.go @@ -18,39 +18,26 @@ import ( "context" "fmt" - "github.com/harness/gitness/types" + controllertypes "github.com/harness/gitness/app/api/controller/aiagent/types" + aitypes "github.com/harness/gitness/types/aigenerate" ) -type GeneratePipelineStepInput struct { - Prompt string `json:"prompt"` - RepoRef string `json:"repo_ref"` -} - -type PipelineStepData struct { - StepYaml string `json:"yaml_step"` -} - -type GeneratePipelineStepOutput struct { - Status string `json:"status"` - Data PipelineStepData `json:"data"` -} - func (c *Controller) GeneratePipelineStep( ctx context.Context, - in *GeneratePipelineInput, -) (*GeneratePipelineStepOutput, error) { - generateRequest := &types.PipelineStepGenerateRequest{ + in *controllertypes.GeneratePipelineInput, +) (*controllertypes.GeneratePipelineStepOutput, error) { + generateRequest := &aitypes.PipelineStepGenerateRequest{ Prompt: in.Prompt, RepoRef: in.RepoRef, } - output, err := c.intelligenceService.GenerateStep(ctx, generateRequest) + output, err := c.intelligence.GeneratePipelineStep(ctx, generateRequest) if err != nil { return nil, fmt.Errorf("generate pipeline: %w", err) } - return &GeneratePipelineStepOutput{ + return &controllertypes.GeneratePipelineStepOutput{ Status: "SUCCESS", - Data: PipelineStepData{ + Data: controllertypes.PipelineStepData{ StepYaml: output.YAML, }, }, nil diff --git a/app/api/controller/aiagent/suggest_pipelines.go b/app/api/controller/aiagent/suggest_pipelines.go index f0be27b49..66051fb8d 100644 --- a/app/api/controller/aiagent/suggest_pipelines.go +++ b/app/api/controller/aiagent/suggest_pipelines.go @@ -16,28 +16,13 @@ package aiagent import ( "context" - "fmt" - "github.com/harness/gitness/types" + controllertypes "github.com/harness/gitness/app/api/controller/aiagent/types" ) -type SuggestPipelineInput struct { - RepoRef string `json:"repo_ref"` - Pipeline string `json:"pipeline"` -} - func (c *Controller) SuggestPipeline( - ctx context.Context, - in *SuggestPipelineInput, -) (*types.PipelineSuggestionsResponse, error) { - suggestionRequest := &types.PipelineSuggestionsRequest{ - RepoRef: in.RepoRef, - Pipeline: in.Pipeline, - } - - output, err := c.intelligenceService.Suggest(ctx, suggestionRequest) - if err != nil { - return nil, fmt.Errorf("suggest pipeline: %w", err) - } - return output, nil + _ context.Context, + _ *controllertypes.SuggestPipelineInput, +) (*controllertypes.SuggestPipelineOutput, error) { + return &controllertypes.SuggestPipelineOutput{}, nil } diff --git a/app/api/controller/aiagent/types/common.go b/app/api/controller/aiagent/types/common.go new file mode 100644 index 000000000..ed3adaace --- /dev/null +++ b/app/api/controller/aiagent/types/common.go @@ -0,0 +1,24 @@ +// Copyright 2023 Harness, Inc. +// +// 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 types + +type Suggestion struct { + ID string + Prompt string + UserSuggestion string + Suggestion string +} + +// Additional common structs can be defined here as needed. diff --git a/app/api/controller/aiagent/types/pipeline.go b/app/api/controller/aiagent/types/pipeline.go new file mode 100644 index 000000000..ddeca1d5a --- /dev/null +++ b/app/api/controller/aiagent/types/pipeline.go @@ -0,0 +1,49 @@ +// Copyright 2023 Harness, Inc. +// +// 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 types + +type GeneratePipelineInput struct { + Prompt string `json:"prompt"` + RepoRef string `json:"repo_ref"` +} + +type PipelineData struct { + YamlPipeline string `json:"yaml_pipeline"` +} + +type GeneratePipelineOutput struct { + Status string `json:"status"` + Data PipelineData `json:"data"` +} + +type SuggestPipelineInput struct { + RepoRef string `json:"repo_ref"` + Pipeline string `json:"pipeline"` +} + +type SuggestPipelineOutput struct { + Suggestions []Suggestion +} + +type UpdatePipelineOutput struct { + Status string `json:"status"` + Data PipelineData `json:"data"` +} + +type UpdatePipelineInput struct { + Prompt string `json:"prompt"` + RepoRef string `json:"repo_ref"` + Pipeline string `json:"pipeline"` +} diff --git a/app/api/controller/aiagent/types/stage.go b/app/api/controller/aiagent/types/stage.go new file mode 100644 index 000000000..5a7d6fd8c --- /dev/null +++ b/app/api/controller/aiagent/types/stage.go @@ -0,0 +1,29 @@ +// Copyright 2023 Harness, Inc. +// +// 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 types + +type GeneratePipelineStageInput struct { + Prompt string `json:"prompt"` + RepoRef string `json:"repo_ref"` +} + +type PipelineStageData struct { + StageYaml string `json:"yaml_step"` +} + +type GeneratePipelineStageOutput struct { + Status string `json:"status"` + Data PipelineStageData `json:"data"` +} diff --git a/app/api/controller/aiagent/types/step.go b/app/api/controller/aiagent/types/step.go new file mode 100644 index 000000000..7f3074f94 --- /dev/null +++ b/app/api/controller/aiagent/types/step.go @@ -0,0 +1,29 @@ +// Copyright 2023 Harness, Inc. +// +// 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 types + +type GeneratePipelineStepInput struct { + Prompt string `json:"prompt"` + RepoRef string `json:"repo_ref"` +} + +type PipelineStepData struct { + StepYaml string `json:"yaml_step"` +} + +type GeneratePipelineStepOutput struct { + Status string `json:"status"` + Data PipelineStepData `json:"data"` +} diff --git a/app/api/controller/aiagent/update_pipeline.go b/app/api/controller/aiagent/update_pipeline.go index 0e41b5575..05387d5ab 100644 --- a/app/api/controller/aiagent/update_pipeline.go +++ b/app/api/controller/aiagent/update_pipeline.go @@ -16,46 +16,13 @@ package aiagent import ( "context" - "fmt" - "github.com/harness/gitness/types" + controllertypes "github.com/harness/gitness/app/api/controller/aiagent/types" ) -type UpdatePipelineOutput struct { - Status string `json:"status"` - Data PipelineData `json:"data"` -} - -type UpdatePipelineInput struct { - Prompt string `json:"prompt"` - RepoRef string `json:"repo_ref"` - Pipeline string `json:"pipeline"` -} - func (c *Controller) UpdatePipeline( - ctx context.Context, - in *UpdatePipelineInput, -) (*UpdatePipelineOutput, error) { - generateRequest := &types.PipelineUpdateRequest{ - Prompt: in.Prompt, - RepoRef: in.RepoRef, - Pipeline: in.Pipeline, - } - - // do permission check on repo here? - repo, err := c.repoStore.FindByRef(ctx, in.RepoRef) - if err != nil { - return nil, fmt.Errorf("failed to find repo by ref: %w", err) - } - - output, err := c.intelligenceService.Update(ctx, generateRequest, repo) - if err != nil { - return nil, fmt.Errorf("update pipeline: %w", err) - } - return &UpdatePipelineOutput{ - Status: "SUCCESS", - Data: PipelineData{ - YamlPipeline: output.YAML, - }, - }, nil + _ context.Context, + _ *controllertypes.UpdatePipelineInput, +) (*controllertypes.UpdatePipelineOutput, error) { + return &controllertypes.UpdatePipelineOutput{}, nil } diff --git a/app/api/controller/aiagent/wire.go b/app/api/controller/aiagent/wire.go index 9a3c72ff2..a635cad7a 100644 --- a/app/api/controller/aiagent/wire.go +++ b/app/api/controller/aiagent/wire.go @@ -32,7 +32,7 @@ var WireSet = wire.NewSet( func ProvideController( authorizer authz.Authorizer, - aiagentPipeline *aiagent.HarnessIntelligence, + intelligence aiagent.Intelligence, repoStore store.RepoStore, pipelineStore store.PipelineStore, executionStore store.ExecutionStore, @@ -42,7 +42,7 @@ func ProvideController( ) *Controller { return NewController( authorizer, - aiagentPipeline, + intelligence, repoStore, pipelineStore, executionStore, diff --git a/app/api/handler/aiagent/generate_pipeline.go b/app/api/handler/aiagent/generate_pipeline.go index 79e2bb9db..dabc1ea23 100644 --- a/app/api/handler/aiagent/generate_pipeline.go +++ b/app/api/handler/aiagent/generate_pipeline.go @@ -19,6 +19,7 @@ import ( "net/http" "github.com/harness/gitness/app/api/controller/aiagent" + controllertypes "github.com/harness/gitness/app/api/controller/aiagent/types" "github.com/harness/gitness/app/api/render" ) @@ -26,7 +27,7 @@ func HandleGeneratePipeline(aiagentCtrl *aiagent.Controller) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - in := new(aiagent.GeneratePipelineInput) + in := new(controllertypes.GeneratePipelineInput) err := json.NewDecoder(r.Body).Decode(in) if err != nil { render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err) diff --git a/app/api/handler/aiagent/generate_pipeline_step.go b/app/api/handler/aiagent/generate_pipeline_step.go index a64a07402..4863b6824 100644 --- a/app/api/handler/aiagent/generate_pipeline_step.go +++ b/app/api/handler/aiagent/generate_pipeline_step.go @@ -19,6 +19,7 @@ import ( "net/http" "github.com/harness/gitness/app/api/controller/aiagent" + controllertypes "github.com/harness/gitness/app/api/controller/aiagent/types" "github.com/harness/gitness/app/api/render" ) @@ -26,7 +27,7 @@ func HandleGeneratePipelineStep(aiagentCtrl *aiagent.Controller) http.HandlerFun return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - in := new(aiagent.GeneratePipelineInput) + in := new(controllertypes.GeneratePipelineInput) err := json.NewDecoder(r.Body).Decode(in) if err != nil { render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err) diff --git a/app/api/handler/aiagent/suggest_pipelines.go b/app/api/handler/aiagent/suggest_pipelines.go index 6d9457efd..103c83cac 100644 --- a/app/api/handler/aiagent/suggest_pipelines.go +++ b/app/api/handler/aiagent/suggest_pipelines.go @@ -19,6 +19,7 @@ import ( "net/http" "github.com/harness/gitness/app/api/controller/aiagent" + controllertypes "github.com/harness/gitness/app/api/controller/aiagent/types" "github.com/harness/gitness/app/api/render" ) @@ -26,7 +27,7 @@ func HandleSuggestPipelines(aiagentCtrl *aiagent.Controller) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - in := new(aiagent.SuggestPipelineInput) + in := new(controllertypes.SuggestPipelineInput) err := json.NewDecoder(r.Body).Decode(in) if err != nil { render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err) diff --git a/app/api/handler/aiagent/update_pipeline.go b/app/api/handler/aiagent/update_pipeline.go index 6223bac38..bd628e9c6 100644 --- a/app/api/handler/aiagent/update_pipeline.go +++ b/app/api/handler/aiagent/update_pipeline.go @@ -19,6 +19,7 @@ import ( "net/http" "github.com/harness/gitness/app/api/controller/aiagent" + controllertypes "github.com/harness/gitness/app/api/controller/aiagent/types" "github.com/harness/gitness/app/api/render" ) @@ -27,7 +28,7 @@ func HandleUpdatePipeline(aiagentCtrl *aiagent.Controller) http.HandlerFunc { ctx := r.Context() // TODO Question: how come we decode body here vs putting that logic in the request package? - in := new(aiagent.UpdatePipelineInput) + in := new(controllertypes.UpdatePipelineInput) err := json.NewDecoder(r.Body).Decode(in) if err != nil { render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err) diff --git a/app/services/aiagent/aiagent.go b/app/services/aiagent/aiagent.go deleted file mode 100644 index 0d870b387..000000000 --- a/app/services/aiagent/aiagent.go +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2023 Harness, Inc. -// -// 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 aiagent - -import ( - "context" - "fmt" - - capabilitiesctrl "github.com/harness/gitness/app/api/controller/capabilities" - "github.com/harness/gitness/app/auth/authz" - "github.com/harness/gitness/app/services/capabilities" - "github.com/harness/gitness/genai" - "github.com/harness/gitness/types" - capabilitytypes "github.com/harness/gitness/types/capabilities" - - "github.com/google/uuid" -) - -type HarnessIntelligence struct { - authorizer authz.Authorizer - cr *capabilities.Registry - cc *capabilitiesctrl.Controller -} - -type Pipeline interface { - Generate(ctx context.Context, req *types.PipelineGenerateRequest) (*types.PipelineGenerateResponse, error) -} - -func capabilityResponseToChatContext( - ranCapabilities *capabilitiesctrl.CapabilityRunResponse) []capabilitytypes.AIContext { - var aiContexts []capabilitytypes.AIContext - for _, value := range ranCapabilities.CapabilitiesRan { - aiContext := capabilitytypes.AIContext{ - Type: capabilitytypes.AIContextPayloadType("other"), - Payload: value.Result, - Name: string(value.Type), - } - aiContexts = append(aiContexts, aiContext) - } - return aiContexts -} - -func (s *HarnessIntelligence) Generate( - ctx context.Context, - req *types.PipelineGenerateRequest, - repo *types.Repository) (*types.PipelineGenerateResponse, error) { - if req.RepoRef == "" { - return nil, fmt.Errorf("no repo ref specified") - } - - conversationID := uuid.New() - chatRequest := &genai.ChatRequest{ - Prompt: req.Prompt, - ConversationID: conversationID.String(), - ConversationRaw: "", - Context: genai.GenerateAIContext( - genai.RepoRef{ - Ref: repo.Path, - }, - ), - Capabilities: s.cr.Capabilities(), - } - - resp, err := s.CapabilitiesLoop(ctx, chatRequest) - if err != nil { - return nil, err - } - - var yaml string - for _, value := range resp.Context { - out, ok := value.Payload.(*capabilities.DisplayYamlOutput) - if ok { - yaml = out.Yaml - } - } - return &types.PipelineGenerateResponse{ - YAML: yaml, - }, nil -} - -func (s *HarnessIntelligence) GenerateStep( - ctx context.Context, - req *types.PipelineStepGenerateRequest) (*types.PipelineStepGenerateResponse, error) { - conversationID := uuid.New() - chatRequest := &genai.ChatRequest{ - Prompt: req.Prompt, - ConversationID: conversationID.String(), - ConversationRaw: "", - Context: genai.GenerateAIContext(), - Capabilities: s.cr.Capabilities(), - } - - resp, err := s.CapabilitiesLoop(ctx, chatRequest) - if err != nil { - return nil, err - } - - var yaml string - for _, value := range resp.Context { - out, ok := value.Payload.(*capabilities.DisplayYamlOutput) - if ok { - yaml = out.Yaml - } - } - return &types.PipelineStepGenerateResponse{ - YAML: yaml, - }, nil -} - -// TODO fix naming -type PipelineYaml struct { - Yaml string `yaml:"yaml"` -} - -// CapabilitiesLoop TODO: this should be replaced with an async model for Harness Enterprise, but remain for Harness. -func (s *HarnessIntelligence) CapabilitiesLoop( - ctx context.Context, req *genai.ChatRequest) (*genai.ChatRequest, error) { - returnToUser := false - for !returnToUser { - capToRun, err := genai.CallAIFoundation(ctx, s.cr, req) - if err != nil { - return nil, fmt.Errorf("failed to call local chat: %w", err) - } - - resp, err := s.cc.RunCapabilities(ctx, capToRun) - if err != nil { - return nil, fmt.Errorf("failed to run capabilities: %w", err) - } - - prevChatRequest := req - req = &genai.ChatRequest{ - Prompt: "", - ConversationID: prevChatRequest.ConversationID, - ConversationRaw: capToRun.ConversationRaw, - Context: capabilityResponseToChatContext(resp), - Capabilities: s.cr.Capabilities(), - } - - for _, value := range resp.CapabilitiesRan { - if value.ReturnToUser { - returnToUser = true - } - } - } - return req, nil -} - -func (s *HarnessIntelligence) Update( - ctx context.Context, - req *types.PipelineUpdateRequest, repo *types.Repository) (*types.PipelineUpdateResponse, error) { - if req.RepoRef == "" { - return nil, fmt.Errorf("no repo ref specified") - } - - conversationID := uuid.New() - chatRequest := &genai.ChatRequest{ - Prompt: req.Prompt, - ConversationID: conversationID.String(), - ConversationRaw: "", - Context: genai.GenerateAIContext( - genai.RepoRef{ - Ref: repo.Path, - }, - genai.PipelineContext{ - Yaml: req.Pipeline, - }, - ), - Capabilities: s.cr.Capabilities(), - } - - resp, err := s.CapabilitiesLoop(ctx, chatRequest) - if err != nil { - return nil, err - } - - var yaml string - for _, value := range resp.Context { - out, ok := value.Payload.(*capabilities.DisplayYamlOutput) - if ok { - yaml = out.Yaml - } - } - - updateResponse := &types.PipelineUpdateResponse{ - YAML: yaml, - } - return updateResponse, nil -} - -func (s *HarnessIntelligence) Suggest( - _ context.Context, - _ *types.PipelineSuggestionsRequest) (*types.PipelineSuggestionsResponse, error) { - return &types.PipelineSuggestionsResponse{ - Suggestions: []types.Suggestion{}, - }, nil -} diff --git a/app/services/aiagent/intelligence.go b/app/services/aiagent/intelligence.go new file mode 100644 index 000000000..304433a3e --- /dev/null +++ b/app/services/aiagent/intelligence.go @@ -0,0 +1,66 @@ +// Copyright 2023 Harness, Inc. +// +// 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 aiagent + +import ( + "context" + + capabilitiesctrl "github.com/harness/gitness/app/api/controller/capabilities" + "github.com/harness/gitness/app/auth/authz" + "github.com/harness/gitness/app/services/capabilities" + aitypes "github.com/harness/gitness/types/aigenerate" +) + +var _ Intelligence = GitnessIntelligence{} + +// This interface serves are the single interface to provide AI use cases. +type Intelligence interface { + GeneratePipeline( + ctx context.Context, + req *aitypes.PipelineGenerateRequest) (*aitypes.PipelineGenerateResponse, error) + GeneratePipelineStage( + ctx context.Context, + req *aitypes.PipelineStageGenerateRequest) (*aitypes.PipelineStageGenerateResponse, error) + GeneratePipelineStep( + ctx context.Context, + req *aitypes.PipelineStepGenerateRequest) (*aitypes.PipelineStepGenerateResponse, error) +} + +type GitnessIntelligence struct { + authorizer authz.Authorizer + cr *capabilities.Registry + cc *capabilitiesctrl.Controller +} + +// GeneratePipeline implements Intelligence. +func (h GitnessIntelligence) GeneratePipeline( + _ context.Context, + _ *aitypes.PipelineGenerateRequest) (*aitypes.PipelineGenerateResponse, error) { + panic("unimplemented") +} + +// GeneratePipelineStage implements Intelligence. +func (h GitnessIntelligence) GeneratePipelineStage( + _ context.Context, + _ *aitypes.PipelineStageGenerateRequest) (*aitypes.PipelineStageGenerateResponse, error) { + panic("unimplemented") +} + +// GeneratePipelineStep implements Intelligence. +func (h GitnessIntelligence) GeneratePipelineStep( + _ context.Context, + _ *aitypes.PipelineStepGenerateRequest) (*aitypes.PipelineStepGenerateResponse, error) { + panic("unimplemented") +} diff --git a/app/services/aiagent/wire.go b/app/services/aiagent/wire.go index aae8ca701..5d638b5b7 100644 --- a/app/services/aiagent/wire.go +++ b/app/services/aiagent/wire.go @@ -30,8 +30,8 @@ func ProvideAiAgent( authorizer authz.Authorizer, cr *capabilities.Registry, cc *capabilitiesctrl.Controller, -) (*HarnessIntelligence, error) { - return &HarnessIntelligence{ +) (*GitnessIntelligence, error) { + return &GitnessIntelligence{ authorizer, cr, cc, diff --git a/types/aigenerate/common.go b/types/aigenerate/common.go new file mode 100644 index 000000000..ed3adaace --- /dev/null +++ b/types/aigenerate/common.go @@ -0,0 +1,24 @@ +// Copyright 2023 Harness, Inc. +// +// 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 types + +type Suggestion struct { + ID string + Prompt string + UserSuggestion string + Suggestion string +} + +// Additional common structs can be defined here as needed. diff --git a/types/suggestions.go b/types/aigenerate/pipeline.go similarity index 80% rename from types/suggestions.go rename to types/aigenerate/pipeline.go index 58b137e5c..2a476524f 100644 --- a/types/suggestions.go +++ b/types/aigenerate/pipeline.go @@ -14,46 +14,30 @@ package types -type PipelineSuggestionsRequest struct { - RepoRef string - Pipeline string -} - type PipelineGenerateRequest struct { Prompt string RepoRef string } -type PipelineUpdateRequest struct { - Prompt string - RepoRef string - Pipeline string -} - -type PipelineStepGenerateRequest struct { - Prompt string - RepoRef string -} - type PipelineGenerateResponse struct { YAML string } +type PipelineUpdateRequest struct { + Prompt string + RepoRef string + Pipeline string +} + type PipelineUpdateResponse struct { YAML string } -type Suggestion struct { - ID string - Prompt string - UserSuggestion string - Suggestion string +type PipelineSuggestionsRequest struct { + RepoRef string + Pipeline string } type PipelineSuggestionsResponse struct { Suggestions []Suggestion } - -type PipelineStepGenerateResponse struct { - YAML string -} diff --git a/types/aigenerate/stage.go b/types/aigenerate/stage.go new file mode 100644 index 000000000..39cd0514c --- /dev/null +++ b/types/aigenerate/stage.go @@ -0,0 +1,34 @@ +// Copyright 2023 Harness, Inc. +// +// 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 types + +type PipelineStageGenerateRequest struct { + Prompt string + RepoRef string +} + +type PipelineStageGenerateResponse struct { + YAML string +} + +type PipelineStageUpdateRequest struct { + Prompt string + RepoRef string + Stage string +} + +type PipelineStageUpdateResponse struct { + YAML string +} diff --git a/types/aigenerate/step.go b/types/aigenerate/step.go new file mode 100644 index 000000000..5fda90b4d --- /dev/null +++ b/types/aigenerate/step.go @@ -0,0 +1,34 @@ +// Copyright 2023 Harness, Inc. +// +// 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 types + +type PipelineStepGenerateRequest struct { + Prompt string + RepoRef string +} + +type PipelineStepGenerateResponse struct { + YAML string +} + +type PipelineStepUpdateRequest struct { + Prompt string + RepoRef string + Step string +} + +type PipelineStepUpdateResponse struct { + YAML string +}