Skip to content

Commit

Permalink
feat: [ML-302]: Framework For Harness Intelligence APIs (harness#2547)
Browse files Browse the repository at this point in the history
* feat: [ML-302]: Framework For Harness Intelligence APIs
  • Loading branch information
yogesh-chauhan authored and Harness committed Aug 20, 2024
1 parent fcfa540 commit 59614e7
Show file tree
Hide file tree
Showing 60 changed files with 2,521 additions and 125 deletions.
59 changes: 59 additions & 0 deletions app/api/controller/aiagent/analyse_execution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// 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"

apiauth "github.com/harness/gitness/app/api/auth"
"github.com/harness/gitness/app/api/usererror"
"github.com/harness/gitness/app/auth"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)

func (c *Controller) GetAnalysis(
ctx context.Context,
session *auth.Session,
repoRef string,
pipelineIdentifier string,
executionNum int64,
) (*types.AnalyseExecutionOutput, error) {
repo, err := c.repoStore.FindByRef(ctx, repoRef)
if err != nil {
return nil, usererror.BadRequestf("failed to find repo %s", repoRef)
}
err = apiauth.CheckPipeline(ctx, c.authorizer, session, repo.Path, pipelineIdentifier, enum.PermissionPipelineView)
if err != nil {
return nil, usererror.Forbidden(fmt.Sprintf("not allowed to view pipeline %s", pipelineIdentifier))
}

pipeline, err := c.pipelineStore.FindByIdentifier(ctx, repo.ID, pipelineIdentifier)
if err != nil {
return nil, usererror.BadRequestf("failed to find pipeline: %s", pipelineIdentifier)
}

execution, err := c.executionStore.FindByNumber(ctx, pipeline.ID, executionNum)
if err != nil {
return nil, usererror.BadRequestf("failed to find execution %d", executionNum)
}

if execution.Status == enum.CIStatusSuccess {
return nil, usererror.BadRequestf("execution %d is not a failed execution", executionNum)
}

return &types.AnalyseExecutionOutput{Yaml: "a:1"}, nil
}
45 changes: 45 additions & 0 deletions app/api/controller/aiagent/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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 (
"github.com/harness/gitness/app/auth/authz"
"github.com/harness/gitness/app/services/aiagent"
"github.com/harness/gitness/app/store"
)

type Controller struct {
authorizer authz.Authorizer
pipeline *aiagent.HarnessIntelligence
repoStore store.RepoStore
pipelineStore store.PipelineStore
executionStore store.ExecutionStore
}

func NewController(
authorizer authz.Authorizer,
pipeline *aiagent.HarnessIntelligence,
repoStore store.RepoStore,
pipelineStore store.PipelineStore,
executionStore store.ExecutionStore,
) *Controller {
return &Controller{
authorizer: authorizer,
pipeline: pipeline,
repoStore: repoStore,
pipelineStore: pipelineStore,
executionStore: executionStore,
}
}
48 changes: 48 additions & 0 deletions app/api/controller/aiagent/generate_pipeline.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// 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 GeneratePipelineInput struct {
Prompt string `json:"prompt"`
RepoRef string `json:"repo_ref"`
}

type GeneratePipelineOutput struct {
Yaml string `json:"yaml"`
}

func (c *Controller) GeneratePipeline(
ctx context.Context,
in *GeneratePipelineInput,
) (*GeneratePipelineOutput, error) {
generateRequest := &types.PipelineGenerateRequest{
Prompt: in.Prompt,
RepoRef: in.RepoRef,
}
output, err := c.pipeline.Generate(ctx, generateRequest)
if err != nil {
return nil, fmt.Errorf("generate pipeline: %w", err)
}
return &GeneratePipelineOutput{
Yaml: output.YAML,
}, nil
}
42 changes: 42 additions & 0 deletions app/api/controller/aiagent/suggest_pipelines.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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 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.pipeline.Suggest(ctx, suggestionRequest)
if err != nil {
return nil, fmt.Errorf("suggest pipeline: %w", err)
}
return output, nil
}
44 changes: 44 additions & 0 deletions app/api/controller/aiagent/update_pipeline.go
Original file line number Diff line number Diff line change
@@ -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 (
"context"
"fmt"

"github.com/harness/gitness/types"
)

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,
) (string, error) {
generateRequest := &types.PipelineUpdateRequest{
Prompt: in.Prompt,
RepoRef: in.RepoRef,
Pipeline: in.Pipeline,
}
output, err := c.pipeline.Update(ctx, generateRequest)
if err != nil {
return "", fmt.Errorf("update pipeline: %w", err)
}
return output.YAML, nil
}
44 changes: 44 additions & 0 deletions app/api/controller/aiagent/wire.go
Original file line number Diff line number Diff line change
@@ -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 (
"github.com/harness/gitness/app/auth/authz"
"github.com/harness/gitness/app/services/aiagent"
"github.com/harness/gitness/app/store"

"github.com/google/wire"
)

// WireSet provides a wire set for this package.
var WireSet = wire.NewSet(
ProvideController,
)

func ProvideController(
authorizer authz.Authorizer,
aiagentPipeline *aiagent.HarnessIntelligence,
repoStore store.RepoStore,
pipelineStore store.PipelineStore,
executionStore store.ExecutionStore,
) *Controller {
return NewController(
authorizer,
aiagentPipeline,
repoStore,
pipelineStore,
executionStore,
)
}
31 changes: 31 additions & 0 deletions app/api/controller/capabilities/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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 (
"github.com/harness/gitness/app/services/capabilities"
)

type Controller struct {
Capabilities *capabilities.Registry
}

func NewController(
capabilities *capabilities.Registry,
) *Controller {
return &Controller{
Capabilities: capabilities,
}
}
77 changes: 77 additions & 0 deletions app/api/controller/capabilities/run_capabilities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// 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"
"fmt"

"github.com/harness/gitness/types/capabilities"
)

type ContextID string

type RunCapabilitiesRequest struct {
ConversationRaw string `json:"conversation_raw"`
ConversationID ContextID `json:"conversation_id"`
CapabilitiesToRun []CapabilityRunRequest `json:"capabilities_to_run"`
}

type CapabilityRunRequest struct {
CallID string `json:"call_id"`
Type capabilities.Type `json:"type"`
Input capabilities.Input `json:"input"`
}

type CapabilityExecution struct {
Type capabilities.Type `json:"capability_id"`
Result capabilities.Output `json:"result"`
ReturnToUser bool `json:"return_to_user"`
}

func (c CapabilityExecution) GetType() capabilities.AIContextPayloadType {
return "other"
}

type CapabilityRunResponse struct {
CapabilitiesRan []CapabilityExecution `json:"capabilities_ran"`
}

func (c *Controller) RunCapabilities(ctx context.Context, req *RunCapabilitiesRequest) (*CapabilityRunResponse, error) {
capOut := new(CapabilityRunResponse)
capOut.CapabilitiesRan = []CapabilityExecution{}

for _, value := range req.CapabilitiesToRun {
if !c.Capabilities.Exists(value.Type) {
return nil, fmt.Errorf("capability %s does not exist", value.Type)
}

resp, err := c.Capabilities.Execute(ctx, value.Type, value.Input)
if err != nil {
return nil, err
}

returnToUser, err := c.Capabilities.ReturnToUser(value.Type)
if err != nil {
return nil, err
}
capOut.CapabilitiesRan = append(capOut.CapabilitiesRan, CapabilityExecution{
Type: value.Type,
Result: resp,
ReturnToUser: returnToUser,
})
}
return capOut, nil
}
Loading

0 comments on commit 59614e7

Please sign in to comment.