From 5e579dc484232dff57e990a65c3123facab2ce6a Mon Sep 17 00:00:00 2001 From: pasiunaite Date: Wed, 19 Aug 2026 11:37:26 +0000 Subject: [PATCH] chore: remove deprecated AI Explain surface from llm package Agent Fix returns an explanation per fix and code-client-go passes it through on AutofixUnifiedDiffSuggestion.Explanation, so the AI Explain client is no longer needed by any consumer. Removes ExplainWithOptions, Explain, runExplain, explainRequestBody, prepareDiffs, ExplainOptions, Explanations and the request/response types, along with the SnykLLMBindings interface and its panicking PublishIssues, which only existed to model the LLM/explain era. OutputFormat and WithOutputFormat are kept: they are inert now, but consumers still pass them and dropping them would force a simultaneous change on their side. --- llm/api_client.go | 94 +-------- llm/api_client_test.go | 401 -------------------------------------- llm/binding.go | 82 -------- llm/binding_smoke_test.go | 28 --- llm/binding_test.go | 65 ------ llm/types.go | 65 ------ 6 files changed, 1 insertion(+), 734 deletions(-) delete mode 100644 llm/binding_smoke_test.go diff --git a/llm/api_client.go b/llm/api_client.go index 68c52117..a55acb18 100644 --- a/llm/api_client.go +++ b/llm/api_client.go @@ -2,66 +2,17 @@ package llm import ( "context" - "encoding/base64" "encoding/json" "errors" "fmt" "io" "net/http" "net/url" - "strings" http2 "github.com/snyk/code-client-go/http" ) -var ( - completeStatus = "COMPLETE" - defaultEndpointURL = "http://localhost:10000/explain" -) - -func (d *DeepCodeLLMBindingImpl) runExplain(ctx context.Context, options ExplainOptions) (Explanations, error) { - span := d.instrumentor.StartSpan(ctx, "code.RunExplain") - defer span.Finish() - - logger := d.logger.With().Str("method", "code.RunExplain").Logger() - - logger.Debug().Msg("API: Retrieving explain for bundle") - defer logger.Debug().Msg("API: Retrieving explain done") - - requestBody, err := d.explainRequestBody(&options) - if err != nil { - logger.Err(err).Str("requestBody", string(requestBody)).Msg("error creating request body") - return Explanations{}, err - } - logger.Debug().Str("payload body: %s\n", string(requestBody)).Msg("Marshaled payload") - - u := options.Endpoint - if u == nil { - u, err = url.Parse(defaultEndpointURL) - if err != nil { - logger.Err(err).Send() - return Explanations{}, err - } - } - - responseBody, err := d.submitRequest(span.Context(), u, requestBody, "", false) - if err != nil { - return Explanations{}, err - } - - var response explainResponse - var explains Explanations - response.Status = completeStatus - err = json.Unmarshal(responseBody, &response) - if err != nil { - logger.Err(err).Str("responseBody", string(responseBody)).Msg("error unmarshalling") - return Explanations{}, err - } - - explains = response.Explanation - - return explains, nil -} +var completeStatus = "COMPLETE" func (d *DeepCodeLLMBindingImpl) submitRequest(ctx context.Context, url *url.URL, requestBody []byte, orgId string, needsEncoding bool) ([]byte, error) { logger := d.logger.With().Str("method", "submitRequest").Logger() @@ -107,30 +58,6 @@ func (d *DeepCodeLLMBindingImpl) submitRequest(ctx context.Context, url *url.URL return responseBody, nil } -func (d *DeepCodeLLMBindingImpl) explainRequestBody(options *ExplainOptions) ([]byte, error) { - logger := d.logger.With().Str("method", "code.explainRequestBody").Logger() - - var requestBody []byte - var marshalErr error - if len(options.Diffs) == 0 { - requestBody, marshalErr = json.Marshal(explainVulnerabilityRequest{ - RuleId: options.RuleKey, - Derivation: options.Derivation, - RuleMessage: options.RuleMessage, - ExplanationLength: SHORT, - }) - logger.Debug().Msg("payload for VulnExplanation") - } else { - requestBody, marshalErr = json.Marshal(explainFixRequest{ - RuleId: options.RuleKey, - Diffs: prepareDiffs(options.Diffs), - ExplanationLength: SHORT, - }) - logger.Debug().Msg("payload for FixExplanation") - } - return requestBody, marshalErr -} - var failed = AutofixStatus{Message: "FAILED"} func (d *DeepCodeLLMBindingImpl) runAutofix(ctx context.Context, options AutofixOptions) (AutofixResponse, AutofixStatus, error) { @@ -247,22 +174,3 @@ func (d *DeepCodeLLMBindingImpl) autofixFeedbackRequestBody(options *AutofixFeed return requestBody, err } - -func prepareDiffs(diffs []string) []string { - cleanedDiffs := make([]string, 0, len(diffs)) - for _, diff := range diffs { - diffLines := strings.Split(diff, "\n") - cleanedLines := "" - for _, line := range diffLines { - if !strings.HasPrefix(line, "---") && !strings.HasPrefix(line, "+++") { - cleanedLines += line + "\n" - } - } - cleanedDiffs = append(cleanedDiffs, cleanedLines) - } - var encodedDiffs []string - for _, diff := range cleanedDiffs { - encodedDiffs = append(encodedDiffs, base64.StdEncoding.EncodeToString([]byte(diff))) - } - return encodedDiffs -} diff --git a/llm/api_client_test.go b/llm/api_client_test.go index 5bd91653..6c12774c 100644 --- a/llm/api_client_test.go +++ b/llm/api_client_test.go @@ -1,265 +1,14 @@ package llm import ( - "encoding/base64" "encoding/json" - "io" "net/http" - "net/http/httptest" - "net/url" "testing" - "github.com/rs/zerolog" http2 "github.com/snyk/code-client-go/http" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/snyk/code-client-go/observability" ) -func TestDeepcodeLLMBinding_runExplain(t *testing.T) { - tests := []struct { - name string - options ExplainOptions - serverResponse string - serverStatusCode int - expectedResponse Explanations - expectedError string - expectedLogMessage string - }{ - { - name: "successful vuln explanation", - options: ExplainOptions{ - RuleKey: "rule-key", - Derivation: "Derivation", - RuleMessage: "rule-message", - }, - serverResponse: "{\n \"explanation\": \n {\n \"explanation1\": \"This is the first explanation\",\n \"explanation2\": \"this is the second explanation\"\n }\n}", - serverStatusCode: http.StatusOK, - expectedResponse: map[string]string{"explanation1": "This is the first explanation", "explanation2": "this is the second explanation"}, - }, - { - name: "successful fix explanation", - options: ExplainOptions{ - RuleKey: "rule-key", - Diffs: []string{"Diffs"}, - }, - serverResponse: "{\n \"explanation\": \n {\n \"explanation1\": \"This is the first explanation\",\n \"explanation2\": \"this is the second explanation\"\n }\n}", - serverStatusCode: http.StatusOK, - expectedResponse: map[string]string{"explanation1": "This is the first explanation", "explanation2": "this is the second explanation"}, - }, - { - name: "error creating request body", - options: ExplainOptions{}, // Missing required fields will cause an error - serverStatusCode: http.StatusUnprocessableEntity, - expectedError: "unexpected end of JSON input", - expectedLogMessage: "error creating request body", - }, - { - name: "error getting response", - options: ExplainOptions{ - RuleKey: "rule-key", - Derivation: "Derivation", - RuleMessage: "rule-message", - }, - serverStatusCode: http.StatusInternalServerError, - expectedError: "unexpected end of JSON input", - expectedLogMessage: "error getting response", - }, - { - name: "error unmarshalling response", - options: ExplainOptions{ - RuleKey: "rule-key", - Derivation: "Derivation", - RuleMessage: "rule-message", - }, - serverResponse: `invalid json`, - serverStatusCode: http.StatusOK, - expectedError: "invalid character 'i' looking for beginning of value", - expectedLogMessage: "error unmarshalling", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(tt.serverStatusCode) - _, _ = w.Write([]byte(tt.serverResponse)) - if tt.expectedError == "unexpected EOF" { - _ = r.Body.Close() // Close the request body early to simulate a read error - } - })) - defer server.Close() - - u, err := url.Parse(server.URL) - assert.NoError(t, err) - tt.options.Endpoint = u - - d := NewDeepcodeLLMBinding() - - ctx := t.Context() - ctx = observability.GetContextWithTraceId(ctx, "test-trace-id") - - response, err := d.runExplain(ctx, tt.options) - - if tt.expectedError != "" { - require.Error(t, err) - assert.Contains(t, err.Error(), tt.expectedError) - } else { - require.NoError(t, err) - assert.Equal(t, tt.expectedResponse, response) - } - }) - } -} - -func TestDeepcodeLLMBinding_explainRequestBody(t *testing.T) { - d := &DeepCodeLLMBindingImpl{ - logger: testLogger(t), - } - - t.Run("VulnExplanation", func(t *testing.T) { - options := &ExplainOptions{ - RuleKey: "test-rule-key", - Derivation: "test-Derivation", - RuleMessage: "test-rule-message", - } - requestBody, err := d.explainRequestBody(options) - require.NoError(t, err) - - var request explainVulnerabilityRequest - err = json.Unmarshal(requestBody, &request) - require.NoError(t, err) - - assert.NotNil(t, request) - assert.Equal(t, "test-rule-key", request.RuleId) - assert.Equal(t, "test-Derivation", request.Derivation) - assert.Equal(t, "test-rule-message", request.RuleMessage) - assert.Equal(t, SHORT, request.ExplanationLength) - }) - - t.Run("FixExplanation", func(t *testing.T) { - options := &ExplainOptions{ - RuleKey: "test-rule-key", - Diffs: []string{"test-Diffs"}, - } - requestBody, err := d.explainRequestBody(options) - require.NoError(t, err) - - var request explainFixRequest - err = json.Unmarshal(requestBody, &request) - require.NoError(t, err) - - assert.NotNil(t, request) - assert.Equal(t, "test-rule-key", request.RuleId) - expectedEncodedDiffs := prepareDiffs([]string{"test-Diffs"}) - assert.Equal(t, expectedEncodedDiffs, request.Diffs) - assert.Equal(t, SHORT, request.ExplanationLength) - }) -} - -func TestEndpoint(t *testing.T) { - testCases := []struct { - name string - inputURL string - expected url.URL - }{ - { - name: "Valid URL", - inputURL: "http://localhost:8080", - expected: url.URL{Scheme: "http", Host: "localhost:8080"}, - }, - { - name: "URL with Path", - inputURL: "https://example.com/path/to/resource", - expected: url.URL{Scheme: "https", Host: "example.com", Path: "/path/to/resource"}, - }, - { - name: "URL with Query Params", - inputURL: "http://api.example.com?param1=value1¶m2=value2", - expected: url.URL{Scheme: "http", Host: "api.example.com", RawQuery: "param1=value1¶m2=value2"}, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - parsedURL, err := url.Parse(tc.inputURL) - if err != nil { - t.Fatalf("Failed to parse URL: %v", err) - } - - options := &ExplainOptions{} - options.Endpoint = parsedURL - - if options.Endpoint.Scheme != tc.expected.Scheme { - t.Errorf("Expected Scheme: %s, Got: %s", tc.expected.Scheme, options.Endpoint.Scheme) - } - if options.Endpoint.Host != tc.expected.Host { - t.Errorf("Expected Host: %s, Got: %s", tc.expected.Host, options.Endpoint.Host) - } - if options.Endpoint.Path != tc.expected.Path { - t.Errorf("Expected Path: %s, Got: %s", tc.expected.Path, options.Endpoint.Path) - } - if options.Endpoint.RawQuery != tc.expected.RawQuery { - t.Errorf("Expected RawQuery: %s, Got: %s", tc.expected.RawQuery, options.Endpoint.RawQuery) - } - }) - } -} - -func TestPrepareDiffs(t *testing.T) { - testCases := []struct { - name string - input []string - expected []string - }{ - { - name: "Single diff with headers and content", - input: []string{ - "--- a/file.txt\n" + - "+++ b/file.txt\n" + - "@@ -1,1 +1,1 @@\n" + - "-old line\n" + - "+new line\n", - }, - expected: []string{ - base64.StdEncoding.EncodeToString([]byte("@@ -1,1 +1,1 @@\n-old line\n+new line\n\n")), - }, - }, - { - name: "Multiple diffs", - input: []string{ - "--- a/file1.txt\n" + - "+++ b/file1.txt\n" + - "-line 1\n" + - "+line 2\n", - "--- a/file2.txt\n" + - "+++ b/file2.txt\n" + - "content2a\n" + - "+content2b\n", - }, - expected: []string{ - base64.StdEncoding.EncodeToString([]byte("-line 1\n+line 2\n\n")), - base64.StdEncoding.EncodeToString([]byte("content2a\n+content2b\n\n")), - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - actual := prepareDiffs(tc.input) - assert.Equal(t, tc.expected, actual) - }) - } -} - -// Helper function for testing -func testLogger(t *testing.T) *zerolog.Logger { - t.Helper() - logger := zerolog.New(io.Discard) - return &logger -} - // Test with existing headers func TestAddDefaultHeadersWithExistingHeaders(t *testing.T) { req := &http.Request{Header: http.Header{"Existing-Header": {"existing-value"}}} @@ -373,153 +122,3 @@ func TestAutofixRequestBody(t *testing.T) { assert.Equal(t, expectedBody, body) } - -func TestRunExplain_WithHeaderValidation(t *testing.T) { - t.Run("vulnerability explanation with headers", func(t *testing.T) { - ruleKey := "test-rule-key" - derivation := "test-derivation" - ruleMessage := "test-rule-message" - - expectedResponse := Explanations{ - "explanation1": "This is the first explanation", - "explanation2": "This is the second explanation", - } - - response := explainResponse{ - Status: completeStatus, - Explanation: expectedResponse, - } - - responseBodyBytes, err := json.Marshal(response) - require.NoError(t, err) - - // Create a test server that validates headers - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Verify headers - assert.Equal(t, "private, max-age=0, no-cache", r.Header.Get("Cache-Control")) - assert.Equal(t, "application/json", r.Header.Get("Content-Type")) - assert.Equal(t, http.MethodPost, r.Method) - - // Verify request body - body, readErr := io.ReadAll(r.Body) - require.NoError(t, readErr) - - var requestData explainVulnerabilityRequest - err = json.Unmarshal(body, &requestData) - require.NoError(t, err) - - assert.Equal(t, ruleKey, requestData.RuleId) - assert.Equal(t, derivation, requestData.Derivation) - assert.Equal(t, ruleMessage, requestData.RuleMessage) - assert.Equal(t, SHORT, requestData.ExplanationLength) - - // Send response - w.WriteHeader(http.StatusOK) - _, _ = w.Write(responseBodyBytes) - })) - defer server.Close() - - // Parse server URL - u, err := url.Parse(server.URL) - require.NoError(t, err) - - // Create options - options := ExplainOptions{ - RuleKey: ruleKey, - Derivation: derivation, - RuleMessage: ruleMessage, - Endpoint: u, - } - - // Create DeepCodeLLMBinding - d := NewDeepcodeLLMBinding() - - // Run the test - ctx := t.Context() - ctx = observability.GetContextWithTraceId(ctx, "test-trace-id") - - result, err := d.runExplain(ctx, options) - - // Verify results - require.NoError(t, err) - assert.Equal(t, expectedResponse, result) - }) - - t.Run("fix explanation with base64 encoded diffs and headers", func(t *testing.T) { - ruleKey := "test-rule-key" - testDiffs := []string{ - "--- a/file.txt\n+++ b/file.txt\n@@ -1,1 +1,1 @@\n-old line\n+new line\n", - } - - expectedResponse := Explanations{ - "explanation1": "This explains the fix", - } - - response := explainResponse{ - Status: completeStatus, - Explanation: expectedResponse, - } - - responseBodyBytes, err := json.Marshal(response) - require.NoError(t, err) - - // Create a test server that validates headers and base64 encoded diffs - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Verify headers - assert.Equal(t, "private, max-age=0, no-cache", r.Header.Get("Cache-Control")) - assert.Equal(t, "application/json", r.Header.Get("Content-Type")) - assert.Equal(t, http.MethodPost, r.Method) - - // Verify request body - body, readErr := io.ReadAll(r.Body) - require.NoError(t, readErr) - - var requestData explainFixRequest - err = json.Unmarshal(body, &requestData) - require.NoError(t, err) - - assert.Equal(t, ruleKey, requestData.RuleId) - assert.Equal(t, SHORT, requestData.ExplanationLength) - - // Verify diffs are base64 encoded - require.Len(t, requestData.Diffs, 1) - - // Decode the base64 diff to verify it was encoded properly - decodedDiff, decodeErr := base64.StdEncoding.DecodeString(requestData.Diffs[0]) - require.NoError(t, decodeErr) - - // The prepareDiffs function strips --- and +++ headers and adds a newline - expectedDecodedDiff := "@@ -1,1 +1,1 @@\n-old line\n+new line\n\n" - assert.Equal(t, expectedDecodedDiff, string(decodedDiff)) - - // Send response - w.WriteHeader(http.StatusOK) - _, _ = w.Write(responseBodyBytes) - })) - defer server.Close() - - // Parse server URL - u, err := url.Parse(server.URL) - require.NoError(t, err) - - // Create options - options := ExplainOptions{ - RuleKey: ruleKey, - Diffs: testDiffs, - Endpoint: u, - } - - // Create DeepCodeLLMBinding - d := NewDeepcodeLLMBinding() - - // Run the test - ctx := t.Context() - ctx = observability.GetContextWithTraceId(ctx, "test-trace-id") - - result, err := d.runExplain(ctx, options) - - // Verify results - require.NoError(t, err) - assert.Equal(t, expectedResponse, result) - }) -} diff --git a/llm/binding.go b/llm/binding.go index cfdc9f48..91e3b7a3 100644 --- a/llm/binding.go +++ b/llm/binding.go @@ -2,9 +2,6 @@ package llm import ( "context" - "encoding/json" - "net/url" - "slices" "github.com/rs/zerolog" @@ -19,38 +16,9 @@ const HTML OutputFormat = "html" const JSON OutputFormat = "json" const MarkDown OutputFormat = "md" -type AIRequest struct { - Id string `json:"id"` - Input string `json:"inputs"` - Endpoint *url.URL `json:"endpoint"` -} - var _ DeepCodeLLMBinding = (*DeepCodeLLMBindingImpl)(nil) -var _ SnykLLMBindings = (*DeepCodeLLMBindingImpl)(nil) - -type SnykLLMBindings interface { - // PublishIssues sends issues to an LLM for further processing. - // the map in the slice of issues map is a json representation of json key : value - // In case of errors, they are returned - PublishIssues(ctx context.Context, issues []map[string]string) error - - // Explain forwards an input and desired output format to an LLM to - // receive an explanation. The implementation should alter the LLM - // prompt to honor the output format, but is not required to enforce - // the format. The results should be streamed into the given channel - // - // Parameters: - // ctx - request context - // input - the thing to be explained as a string - // format - the requested outputFormat - // output - a channel that can be used to stream the results - Explain(ctx context.Context, input AIRequest, format OutputFormat, output chan<- string) error -} -type ExplainResult []string type DeepCodeLLMBinding interface { - SnykLLMBindings - ExplainWithOptions(ctx context.Context, options ExplainOptions) (ExplainResult, error) GetAutofixDiffs(ctx context.Context, baseDir string, options AutofixOptions) (unifiedDiffSuggestions []AutofixUnifiedDiffSuggestion, status AutofixStatus, err error) SubmitAutofixFeedback(ctx context.Context, requestId string, options AutofixFeedbackOptions) error } @@ -91,56 +59,6 @@ func (d *DeepCodeLLMBindingImpl) GetAutofixDiffs(ctx context.Context, _ string, return autofixResponse.toUnifiedDiffSuggestions(d.logger, options.BaseDir, options.FilePath), status, err } -func (d *DeepCodeLLMBindingImpl) ExplainWithOptions(ctx context.Context, options ExplainOptions) (ExplainResult, error) { - s := d.instrumentor.StartSpan(ctx, "code.ExplainWithOptions") - defer d.instrumentor.Finish(s) - response, err := d.runExplain(s.Context(), options) - explainResult := ExplainResult{} - if err != nil { - return explainResult, err - } - - orderedExplainResults := getOrderedResponse(response) - - return orderedExplainResults, nil -} - -func getOrderedResponse(explainResponse Explanations) []string { - explainMapKeys := make([]string, 0, len(explainResponse)) - for k := range explainResponse { - explainMapKeys = append(explainMapKeys, k) - } - slices.Sort(explainMapKeys) - - orderedValues := make([]string, 0, len(explainResponse)) - for _, key := range explainMapKeys { - orderedValues = append(orderedValues, explainResponse[key]) - } - return orderedValues -} - -func (d *DeepCodeLLMBindingImpl) PublishIssues(_ context.Context, _ []map[string]string) error { - panic("implement me") -} - -func (d *DeepCodeLLMBindingImpl) Explain(ctx context.Context, input AIRequest, _ OutputFormat, output chan<- string) error { - var options ExplainOptions - err := json.Unmarshal([]byte(input.Input), &options) - if err != nil { - return err - } - response, err := d.ExplainWithOptions(ctx, options) - if err != nil { - return err - } - jsonBytes, err := json.Marshal(response) - if err != nil { - return err - } - output <- string(jsonBytes) - return nil -} - func NewDeepcodeLLMBinding(opts ...Option) *DeepCodeLLMBindingImpl { nopLogger := zerolog.Nop() binding := &DeepCodeLLMBindingImpl{ diff --git a/llm/binding_smoke_test.go b/llm/binding_smoke_test.go deleted file mode 100644 index 8eea201f..00000000 --- a/llm/binding_smoke_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package llm - -import ( - "net/url" - "testing" - - "github.com/google/uuid" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" - - "github.com/snyk/code-client-go/http" -) - -func TestDeepcodeLLMBinding_Explain_Smoke(t *testing.T) { - t.Skipf("can not run automatically") - logger := zerolog.Nop() - - binding := NewDeepcodeLLMBinding( - WithHTTPClient(func() http.HTTPClient { return http.NewHTTPClient(http.NewDefaultClientFactory()) }), - WithLogger(&logger), - ) - outputChain := make(chan string) - endpoint, errEndpoint := url.Parse(defaultEndpointURL) - assert.NoError(t, errEndpoint) - - err := binding.Explain(t.Context(), AIRequest{Id: uuid.New().String(), Input: "{}", Endpoint: endpoint}, HTML, outputChain) - assert.NoError(t, err) -} diff --git a/llm/binding_test.go b/llm/binding_test.go index 07e8f6f7..b90eb4fa 100644 --- a/llm/binding_test.go +++ b/llm/binding_test.go @@ -1,73 +1,18 @@ package llm import ( - "encoding/json" - "io" - http2 "net/http" - "net/url" "os" "path/filepath" - "strings" "testing" - "github.com/golang/mock/gomock" "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/snyk/code-client-go/http" - "github.com/snyk/code-client-go/http/mocks" "github.com/snyk/code-client-go/observability" ) -func TestDeepcodeLLMBinding_PublishIssues(t *testing.T) { - binding := NewDeepcodeLLMBinding() - assert.PanicsWithValue(t, "implement me", func() { _ = binding.PublishIssues(t.Context(), []map[string]string{}) }) -} - -func TestExplainWithOptions(t *testing.T) { - t.Run("success", func(t *testing.T) { - d, mockHTTPClient := getHTTPMockedBinding(t) - - explainResponseJSON := explainResponse{ - Status: completeStatus, - Explanation: map[string]string{ - "explanation1": "This is the first explanation", - "explanation2": "this is the second explanation", - "explanation3": "this is the third explanation", - "explanation4": "this is the fourth explanation", - "explanation5": "this is the fifth explanation", - }, - } - - expectedResponseBody, err := json.Marshal(explainResponseJSON) - assert.NoError(t, err) - mockResponse := http2.Response{ - Status: "200 Ok", - StatusCode: 200, - Body: io.NopCloser(strings.NewReader(string(expectedResponseBody))), - } - mockHTTPClient.EXPECT().Do(gomock.Any()).Return(&mockResponse, nil) - testDiff := "test diff" - endpoint := &url.URL{Scheme: "http", Host: "test.com"} - explanation, err := d.ExplainWithOptions(t.Context(), ExplainOptions{Diffs: []string{testDiff}, Endpoint: endpoint}) - assert.NoError(t, err) - var exptectedExplanationsResponse explainResponse - err = json.Unmarshal(expectedResponseBody, &exptectedExplanationsResponse) - assert.NoError(t, err) - expectedResExplanations := exptectedExplanationsResponse.Explanation - assert.Equal(t, expectedResExplanations["explanation1"], explanation[0]) - assert.Equal(t, expectedResExplanations["explanation2"], explanation[1]) - assert.Equal(t, expectedResExplanations["explanation3"], explanation[2]) - assert.Equal(t, expectedResExplanations["explanation4"], explanation[3]) - assert.Equal(t, expectedResExplanations["explanation5"], explanation[4]) - }) - - t.Run("runExplain error", func(t *testing.T) { - - }) -} - func TestToUnifiedDiffSuggestions(t *testing.T) { t.Run("carries the explanation from the autofix response", func(t *testing.T) { baseDir := t.TempDir() @@ -91,16 +36,6 @@ func TestToUnifiedDiffSuggestions(t *testing.T) { }) } -func getHTTPMockedBinding(t *testing.T) (*DeepCodeLLMBindingImpl, *mocks.MockHTTPClient) { - t.Helper() - ctrl := gomock.NewController(t) - mockHTTPClient := mocks.NewMockHTTPClient(ctrl) - d := NewDeepcodeLLMBinding( - WithHTTPClient(func() http.HTTPClient { return mockHTTPClient }), - ) - return d, mockHTTPClient -} - func TestNewDeepcodeLLMBinding(t *testing.T) { logger := zerolog.Nop() client := http.NewHTTPClient(http.NewDefaultClientFactory()) diff --git a/llm/types.go b/llm/types.go index 8f27abf1..697e30e8 100644 --- a/llm/types.go +++ b/llm/types.go @@ -1,70 +1,5 @@ package llm -import "net/url" - -type explanationLength string - -const ( - SHORT explanationLength = "SHORT" - MEDIUM explanationLength = "MEDIUM" - LONG explanationLength = "LONG" -) - -type explainVulnerabilityRequest struct { - RuleId string `json:"rule_id"` - RuleMessage string `json:"rule_message"` - Derivation string `json:"Derivation"` - ExplanationLength explanationLength `json:"explanation_length"` -} - -type explainFixRequest struct { - RuleId string `json:"rule_id"` - Diffs []string `json:"diffs"` - ExplanationLength explanationLength `json:"explanation_length"` -} - -type explainResponse struct { - Status string `json:"status"` - Explanation Explanations `json:"explanation"` -} -type Explanations map[string]string -type ExplainOptions struct { - // Derivation = Code Flow - // const derivationLineNumbers: Set = new Set(); - // for (const markerLocation of suggestion.markers!) { - // for (const markerPos of markerLocation.pos) { - // const lines = markerPos.rows; - // for (const line of lines) { - // derivationLineNumbers.add(line + 1); - // } - // } - // markerLocation.pos; - // } - // console.log('Derivation lines: ', ...derivationLineNumbers); - // - // const derivationLines: string[] = []; - // const fileLines: string[] = fileContent.split('\n'); - // for (const derivationLineNumber of derivationLineNumbers) { - // derivationLines.push(fileLines.at(derivationLineNumber - 1)!); - // } - // let Derivation = derivationLines.join(','); - // Derivation = Derivation.replace(/\t/g, ' '); - // console.log('Derivation: ', Derivation); - Derivation string `json:"derivation"` - - // vulnerability name from Snyk Code (rule) - RuleKey string `json:"rule_key"` - - // Snyk Code message for the vulnerability - RuleMessage string `json:"rule_message"` - - // fix difference - Diffs []string `json:"diffs"` - - // Endpoint to call - Endpoint *url.URL `json:"endpoint"` -} - // AutofixResponse is the json-based structure to which we can translate the results of the HTTP // request to Autofix upstream. type AutofixResponse struct {