[feat]: [ML-488]: Added New API for StepYamlGeneration for UI to call separately. (#3030)

* fixed go-lint issues
* [feat]: [ML-488]: Added New API for StepYamlGeneration for UI to call separately.
pull/3597/head
Vivek Dixit 2024-11-22 07:55:26 +00:00 committed by Harness
parent c43d0e62a7
commit 3f54161997
8 changed files with 229 additions and 74 deletions

View File

@ -0,0 +1,63 @@
// 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"
"github.com/harness/gitness/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"`
}
func (c *Controller) GeneratePipelineStep(
ctx context.Context,
in *GeneratePipelineInput,
) (*GeneratePipelineStepOutput, error) {
generateRequest := &types.PipelineStepGenerateRequest{
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.GenerateStep(ctx, generateRequest, repo)
if err != nil {
return nil, fmt.Errorf("generate pipeline: %w", err)
}
return &GeneratePipelineStepOutput{
Status: "SUCCESS",
Data: PipelineStepData{
StepYaml: output.YAML,
},
}, nil
}

View File

@ -0,0 +1,44 @@
// 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 (
"encoding/json"
"net/http"
"github.com/harness/gitness/app/api/controller/aiagent"
"github.com/harness/gitness/app/api/render"
)
func HandleGeneratePipelineStep(aiagentCtrl *aiagent.Controller) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
in := new(aiagent.GeneratePipelineInput)
err := json.NewDecoder(r.Body).Decode(in)
if err != nil {
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
return
}
pipeline, err := aiagentCtrl.GeneratePipelineStep(ctx, in)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return
}
render.JSON(w, http.StatusOK, pipeline)
}
}

View File

@ -566,6 +566,7 @@ func setupTemplates(
func setupAiAgent(r chi.Router, aiagentCtrl *aiagent.Controller, capabilitiesCtrl *capabilities.Controller) {
r.Route("/harness-intelligence", func(r chi.Router) {
r.Post("/generate-pipeline-step", handleraiagent.HandleGeneratePipelineStep(aiagentCtrl))
r.Post("/generate-pipeline", handleraiagent.HandleGeneratePipeline(aiagentCtrl))
r.Post("/update-pipeline", handleraiagent.HandleUpdatePipeline(aiagentCtrl))
r.Post("/capabilities", handlercapabilities.HandleRunCapabilities(capabilitiesCtrl))

View File

@ -80,7 +80,7 @@ func (s *HarnessIntelligence) Generate(
var yaml string
for _, value := range resp.Context {
out, ok := value.Payload.(*capabilities.DisplayPipelineYamlOutput)
out, ok := value.Payload.(*capabilities.DisplayYamlOutput)
if ok {
yaml = out.Yaml
}
@ -90,6 +90,44 @@ func (s *HarnessIntelligence) Generate(
}, nil
}
func (s *HarnessIntelligence) GenerateStep(
ctx context.Context,
req *types.PipelineStepGenerateRequest,
repo *types.Repository) (*types.PipelineStepGenerateResponse, 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.PipelineStepGenerateResponse{
YAML: yaml,
}, nil
}
// TODO fix naming
type PipelineYaml struct {
Yaml string `yaml:"yaml"`
@ -158,7 +196,7 @@ func (s *HarnessIntelligence) Update(
var yaml string
for _, value := range resp.Context {
out, ok := value.Payload.(*capabilities.DisplayPipelineYamlOutput)
out, ok := value.Payload.(*capabilities.DisplayYamlOutput)
if ok {
yaml = out.Yaml
}

View File

@ -1,71 +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 capabilities
import (
"context"
"github.com/harness/gitness/types/capabilities"
)
var DisplayPipelineYamlType capabilities.Type = "display_pipeline_yaml"
var DisplayPipelineYamlVersion capabilities.Version = "0"
type DisplayPipelineYamlInput struct {
Yaml string `json:"pipeline_yaml"`
}
func (DisplayPipelineYamlInput) IsCapabilityInput() {}
type DisplayPipelineYamlOutput struct {
Yaml string `json:"pipeline_yaml"`
}
func (DisplayPipelineYamlOutput) IsCapabilityOutput() {}
const AIContextPayloadTypeDisplayPipelineYaml capabilities.AIContextPayloadType = "other"
func (DisplayPipelineYamlOutput) GetType() capabilities.AIContextPayloadType {
return AIContextPayloadTypeDisplayPipelineYaml
}
func (DisplayPipelineYamlOutput) GetName() string {
return string(DisplayPipelineYamlType)
}
func (r *Registry) RegisterDisplayPipelineYamlCapability(
logic func(ctx context.Context, input *DisplayPipelineYamlInput) (*DisplayPipelineYamlOutput, error),
) error {
return r.register(
capabilities.Capability{
Type: DisplayPipelineYamlType,
NewInput: func() capabilities.Input { return &DisplayPipelineYamlInput{} },
Logic: newLogic(logic),
Version: DisplayPipelineYamlVersion,
ReturnToUser: true,
},
)
}
// ReturnPipelineYaml could take in, eg repoStore store.RepoStore, git git.Interface, as arguments.
func DisplayPipelineYaml() func(
ctx context.Context,
input *DisplayPipelineYamlInput) (*DisplayPipelineYamlOutput, error) {
return func(_ context.Context, input *DisplayPipelineYamlInput) (*DisplayPipelineYamlOutput, error) {
return &DisplayPipelineYamlOutput{
Yaml: input.Yaml,
}, nil
}
}

View File

@ -0,0 +1,71 @@
// 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 capabilities
import (
"context"
"github.com/harness/gitness/types/capabilities"
)
var DisplayYamlType capabilities.Type = "display_yaml"
var DisplayYamlVersion capabilities.Version = "0"
type DisplayYamlInput struct {
Yaml string `json:"yaml"`
}
func (DisplayYamlInput) IsCapabilityInput() {}
type DisplayYamlOutput struct {
Yaml string `json:"yaml"`
}
func (DisplayYamlOutput) IsCapabilityOutput() {}
const AIContextPayloadTypeDisplayPipelineYaml capabilities.AIContextPayloadType = "other"
func (DisplayYamlOutput) GetType() capabilities.AIContextPayloadType {
return AIContextPayloadTypeDisplayPipelineYaml
}
func (DisplayYamlOutput) GetName() string {
return string(DisplayYamlType)
}
func (r *Registry) RegisterDisplayYamlCapability(
logic func(ctx context.Context, input *DisplayYamlInput) (*DisplayYamlOutput, error),
) error {
return r.register(
capabilities.Capability{
Type: DisplayYamlType,
NewInput: func() capabilities.Input { return &DisplayYamlInput{} },
Logic: newLogic(logic),
Version: DisplayYamlVersion,
ReturnToUser: true,
},
)
}
// ReturnPipelineYaml could take in, eg repoStore store.RepoStore, git git.Interface, as arguments.
func DisplayYaml() func(
ctx context.Context,
input *DisplayYamlInput) (*DisplayYamlOutput, error) {
return func(_ context.Context, input *DisplayYamlInput) (*DisplayYamlOutput, error) {
return &DisplayYamlOutput{
Yaml: input.Yaml,
}, nil
}
}

View File

@ -35,6 +35,6 @@ func ProvideCapabilities(repoStore store.RepoStore, git git.Interface) (*Registr
registry := NewRegistry()
panicOnErr(registry.RegisterListFilesCapability(ListFiles(repoStore, git)))
panicOnErr(registry.RegisterGetFileCapability(GetFile(repoStore, git)))
panicOnErr(registry.RegisterDisplayPipelineYamlCapability(DisplayPipelineYaml()))
panicOnErr(registry.RegisterDisplayYamlCapability(DisplayYaml()))
return registry, nil
}

View File

@ -30,6 +30,11 @@ type PipelineUpdateRequest struct {
Pipeline string
}
type PipelineStepGenerateRequest struct {
Prompt string
RepoRef string
}
type PipelineGenerateResponse struct {
YAML string
}
@ -48,3 +53,7 @@ type Suggestion struct {
type PipelineSuggestionsResponse struct {
Suggestions []Suggestion
}
type PipelineStepGenerateResponse struct {
YAML string
}