From 08390d43518a50dc2a995384d0669cfa50f5c3d8 Mon Sep 17 00:00:00 2001 From: AzeezIsh Date: Fri, 19 Sep 2025 12:23:48 -0400 Subject: [PATCH 1/7] downstream dbresponse changes, go updates with sharedtypes to new struct --- go.mod | 2 +- go.sum | 4 +- pkg/externalfunctions/llmhandler.go | 137 +++++++++++++++++++++++++++- 3 files changed, 137 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index d39ad4c8..49ac7e11 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ansys/aali-flowkit go 1.24.2 require ( - github.com/ansys/aali-sharedtypes v1.0.4-0.20250912172539-2fcf3e45b5ae + github.com/ansys/aali-sharedtypes v1.0.4-0.20250919153150-9a32e940f30d github.com/google/go-github/v56 v56.0.0 github.com/google/uuid v1.6.0 github.com/pandodao/tokenizer-go v0.2.0 diff --git a/go.sum b/go.sum index a5f06e88..ae6cefa7 100644 --- a/go.sum +++ b/go.sum @@ -30,8 +30,8 @@ github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4 github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk= github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= -github.com/ansys/aali-sharedtypes v1.0.4-0.20250912172539-2fcf3e45b5ae h1:2Euh3dbT5zULzOMId2fwvbZKcaBNCJhQzgLs9k3Fqag= -github.com/ansys/aali-sharedtypes v1.0.4-0.20250912172539-2fcf3e45b5ae/go.mod h1:Ze0xVXbyl63d/dN95UKHJjoGs7ZmF5OrykBtKQxgO1U= +github.com/ansys/aali-sharedtypes v1.0.4-0.20250919153150-9a32e940f30d h1:W3iZGfrwaMjl4U7P5Pi3M0O84XDfMtMMD8VfeaFVbLk= +github.com/ansys/aali-sharedtypes v1.0.4-0.20250919153150-9a32e940f30d/go.mod h1:Ze0xVXbyl63d/dN95UKHJjoGs7ZmF5OrykBtKQxgO1U= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= diff --git a/pkg/externalfunctions/llmhandler.go b/pkg/externalfunctions/llmhandler.go index 05efd911..0735ab6a 100644 --- a/pkg/externalfunctions/llmhandler.go +++ b/pkg/externalfunctions/llmhandler.go @@ -1075,6 +1075,7 @@ func BuildLibraryContext(message string, libraryContext string) (messageWithCont // - @displayName: Final Query (General LLM Request) // // Parameters: + // - request: the original request // - knowledgedbResponse: the KnowledgeDB response // @@ -1088,9 +1089,72 @@ func BuildFinalQueryForGeneralLLMRequest(request string, knowledgedbResponse []s } // Build the final query using the KnowledgeDB response and the original request + // Append all non-empty fields to provide maximum context from comprehensive DbResponse finalQuery = "Based on the following examples:\n\n--- INFO START ---\n" for _, example := range knowledgedbResponse { - finalQuery += example.Text + "\n" + var contentParts []string + + // CodeGenerationElement fields (likely from API/Element collections) + if example.NameFormatted != "" { + contentParts = append(contentParts, example.NameFormatted) + } + if example.NamePseudocode != "" { + contentParts = append(contentParts, example.NamePseudocode) + } + if example.Name != "" { + contentParts = append(contentParts, example.Name) + } + if example.Type != "" { + contentParts = append(contentParts, "Type: "+example.Type) + } + if example.ParentClass != "" { + contentParts = append(contentParts, "Parent: "+example.ParentClass) + } + + // VectorDatabaseUserGuideSection fields (likely from User Guide collections) + if example.Title != "" { + contentParts = append(contentParts, example.Title) + } + if example.SectionName != "" { + contentParts = append(contentParts, "Section: "+example.SectionName) + } + if example.ParentSectionName != "" { + contentParts = append(contentParts, "Parent Section: "+example.ParentSectionName) + } + + // Common fields (from any collection type) + if example.DocumentName != "" { + contentParts = append(contentParts, "Document: "+example.DocumentName) + } + if example.Text != "" { + contentParts = append(contentParts, example.Text) + } + if example.Summary != "" { + contentParts = append(contentParts, "Summary: "+example.Summary) + } + if len(example.Dependencies) > 0 { + // Convert []interface{} to []string for joining + var deps []string + for _, dep := range example.Dependencies { + if depStr, ok := dep.(string); ok { + deps = append(deps, depStr) + } + } + if len(deps) > 0 { + contentParts = append(contentParts, "Dependencies: "+strings.Join(deps, ", ")) + } + } + if len(example.Keywords) > 0 { + contentParts = append(contentParts, "Keywords: "+strings.Join(example.Keywords, ", ")) + } + if len(example.Tags) > 0 { + contentParts = append(contentParts, "Tags: "+strings.Join(example.Tags, ", ")) + } + + // Add all content with spacing + if len(contentParts) > 0 { + finalQuery += strings.Join(contentParts, "\n") + "\n\n" + } } finalQuery += "--- INFO END ---\n\n" + request + "\n" @@ -1148,8 +1212,75 @@ func BuildFinalQueryForCodeLLMRequest(request string, knowledgedbResponse []shar for i, element := range knowledgedbResponse { // Add the example number finalQuery += "--- START EXAMPLE " + fmt.Sprint(i+1) + "---\n" - finalQuery += ">>> Summary:\n" + element.Summary + "\n\n" - finalQuery += ">>> Code snippet:\n```python\n" + element.Text + "\n```\n" + + // Build summary from all available non-empty fields + var summaryParts []string + + // CodeGenerationElement fields (likely from API/Element collections) + if element.NameFormatted != "" { + summaryParts = append(summaryParts, element.NameFormatted) + } + if element.Type != "" { + summaryParts = append(summaryParts, "Type: "+element.Type) + } + if element.ParentClass != "" { + summaryParts = append(summaryParts, "Parent: "+element.ParentClass) + } + + // VectorDatabaseUserGuideSection fields (likely from User Guide collections) + if element.Title != "" { + summaryParts = append(summaryParts, element.Title) + } + if element.SectionName != "" { + summaryParts = append(summaryParts, "Section: "+element.SectionName) + } + + // Common fields + if element.DocumentName != "" { + summaryParts = append(summaryParts, "Document: "+element.DocumentName) + } + if element.Summary != "" { + summaryParts = append(summaryParts, "Summary: "+element.Summary) + } + if len(element.Dependencies) > 0 { + // Convert []interface{} to []string for joining + var deps []string + for _, dep := range element.Dependencies { + if depStr, ok := dep.(string); ok { + deps = append(deps, depStr) + } + } + if len(deps) > 0 { + summaryParts = append(summaryParts, "Dependencies: "+strings.Join(deps, ", ")) + } + } + + // Build code content from all available fields + var codeParts []string + + if element.NamePseudocode != "" { + codeParts = append(codeParts, "# "+element.NamePseudocode) + } + if element.Name != "" { + codeParts = append(codeParts, "# Function: "+element.Name) + } + if element.Text != "" { + codeParts = append(codeParts, element.Text) + } + + // Use constructed content or fallback + summaryContent := strings.Join(summaryParts, " | ") + if summaryContent == "" { + summaryContent = "No summary available" + } + + codeContent := strings.Join(codeParts, "\n") + if codeContent == "" { + codeContent = "# No code content available" + } + + finalQuery += ">>> Summary:\n" + summaryContent + "\n\n" + finalQuery += ">>> Code snippet:\n```python\n" + codeContent + "\n```\n" finalQuery += "--- END EXAMPLE " + fmt.Sprint(i+1) + "---\n\n" } } From 20c04a4915a6137e782b7c2a8fae5da3b424bf23 Mon Sep 17 00:00:00 2001 From: AzeezIsh Date: Tue, 23 Sep 2025 12:31:09 -0400 Subject: [PATCH 2/7] sharedtypes changes to main --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 49ac7e11..5b1abc24 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ansys/aali-flowkit go 1.24.2 require ( - github.com/ansys/aali-sharedtypes v1.0.4-0.20250919153150-9a32e940f30d + github.com/ansys/aali-sharedtypes v1.0.4-0.20250923131529-5014d8346f14 github.com/google/go-github/v56 v56.0.0 github.com/google/uuid v1.6.0 github.com/pandodao/tokenizer-go v0.2.0 diff --git a/go.sum b/go.sum index ae6cefa7..3eb1a58b 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,8 @@ github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsVi github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= github.com/ansys/aali-sharedtypes v1.0.4-0.20250919153150-9a32e940f30d h1:W3iZGfrwaMjl4U7P5Pi3M0O84XDfMtMMD8VfeaFVbLk= github.com/ansys/aali-sharedtypes v1.0.4-0.20250919153150-9a32e940f30d/go.mod h1:Ze0xVXbyl63d/dN95UKHJjoGs7ZmF5OrykBtKQxgO1U= +github.com/ansys/aali-sharedtypes v1.0.4-0.20250923131529-5014d8346f14 h1:qlKXTti3SZw8KTCt8y2p0un9x/1g+vExM9g4pT5olBI= +github.com/ansys/aali-sharedtypes v1.0.4-0.20250923131529-5014d8346f14/go.mod h1:Ze0xVXbyl63d/dN95UKHJjoGs7ZmF5OrykBtKQxgO1U= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= From 3f6980f6ed416d35f35a7f5a97d0d3aa1fa58af6 Mon Sep 17 00:00:00 2001 From: AzeezIsh Date: Tue, 23 Sep 2025 12:55:08 -0400 Subject: [PATCH 3/7] field-based matching for data type, added additional code overlay and context as well --- pkg/externalfunctions/llmhandler.go | 123 +++++++++++++++++++--------- 1 file changed, 83 insertions(+), 40 deletions(-) diff --git a/pkg/externalfunctions/llmhandler.go b/pkg/externalfunctions/llmhandler.go index 0735ab6a..5424f3a3 100644 --- a/pkg/externalfunctions/llmhandler.go +++ b/pkg/externalfunctions/llmhandler.go @@ -1091,48 +1091,52 @@ func BuildFinalQueryForGeneralLLMRequest(request string, knowledgedbResponse []s // Build the final query using the KnowledgeDB response and the original request // Append all non-empty fields to provide maximum context from comprehensive DbResponse finalQuery = "Based on the following examples:\n\n--- INFO START ---\n" - for _, example := range knowledgedbResponse { + for i, example := range knowledgedbResponse { var contentParts []string - // CodeGenerationElement fields (likely from API/Element collections) - if example.NameFormatted != "" { - contentParts = append(contentParts, example.NameFormatted) - } - if example.NamePseudocode != "" { - contentParts = append(contentParts, example.NamePseudocode) - } - if example.Name != "" { - contentParts = append(contentParts, example.Name) - } - if example.Type != "" { - contentParts = append(contentParts, "Type: "+example.Type) - } - if example.ParentClass != "" { - contentParts = append(contentParts, "Parent: "+example.ParentClass) + // Determine collection type and add appropriate header + collectionType := "UNKNOWN" + if example.Type != "" && (example.NameFormatted != "" || example.Name != "") { + collectionType = "API_ELEMENT" + } else if example.Title != "" && example.SectionName != "" { + collectionType = "USER_GUIDE" + } else if example.DocumentName != "" { + collectionType = "EXAMPLE" } - // VectorDatabaseUserGuideSection fields (likely from User Guide collections) - if example.Title != "" { - contentParts = append(contentParts, example.Title) + contentParts = append(contentParts, fmt.Sprintf("=== %s #%d ===", collectionType, i+1)) + + // CodeGenerationElement fields (API/Element collections) + if example.Type != "" && (example.NameFormatted != "" || example.Name != "") { + if example.NameFormatted != "" { + contentParts = append(contentParts, "API: "+example.NameFormatted) + } + if example.NamePseudocode != "" { + contentParts = append(contentParts, "Function: "+example.NamePseudocode) + } + if example.Name != "" { + contentParts = append(contentParts, "Full Name: "+example.Name) + } + if example.Type != "" { + contentParts = append(contentParts, "Type: "+example.Type) + } + if example.ParentClass != "" { + contentParts = append(contentParts, "Parent: "+example.ParentClass) + } } - if example.SectionName != "" { + + // VectorDatabaseUserGuideSection fields (User Guide collections) + if example.Title != "" && example.SectionName != "" { + contentParts = append(contentParts, "Guide Title: "+example.Title) contentParts = append(contentParts, "Section: "+example.SectionName) - } - if example.ParentSectionName != "" { - contentParts = append(contentParts, "Parent Section: "+example.ParentSectionName) + if example.ParentSectionName != "" { + contentParts = append(contentParts, "Parent Section: "+example.ParentSectionName) + } } - // Common fields (from any collection type) + // VectorDatabaseExample fields (Example collections) if example.DocumentName != "" { - contentParts = append(contentParts, "Document: "+example.DocumentName) - } - if example.Text != "" { - contentParts = append(contentParts, example.Text) - } - if example.Summary != "" { - contentParts = append(contentParts, "Summary: "+example.Summary) - } - if len(example.Dependencies) > 0 { + contentParts = append(contentParts, "Example File: "+example.DocumentName) // Convert []interface{} to []string for joining var deps []string for _, dep := range example.Dependencies { @@ -1141,9 +1145,17 @@ func BuildFinalQueryForGeneralLLMRequest(request string, knowledgedbResponse []s } } if len(deps) > 0 { - contentParts = append(contentParts, "Dependencies: "+strings.Join(deps, ", ")) + contentParts = append(contentParts, "Uses APIs: "+strings.Join(deps, ", ")) } } + + // Common fields + if example.DocumentName != "" && collectionType != "EXAMPLE" { + contentParts = append(contentParts, "Document: "+example.DocumentName) + } + if example.Summary != "" { + contentParts = append(contentParts, "Summary: "+example.Summary) + } if len(example.Keywords) > 0 { contentParts = append(contentParts, "Keywords: "+strings.Join(example.Keywords, ", ")) } @@ -1151,14 +1163,33 @@ func BuildFinalQueryForGeneralLLMRequest(request string, knowledgedbResponse []s contentParts = append(contentParts, "Tags: "+strings.Join(example.Tags, ", ")) } + // Handle Text field with proper formatting based on collection type + if example.Text != "" { + if collectionType == "EXAMPLE" { + contentParts = append(contentParts, "Code:") + contentParts = append(contentParts, "```python") + contentParts = append(contentParts, example.Text) + contentParts = append(contentParts, "```") + } else { + contentParts = append(contentParts, "Content:") + contentParts = append(contentParts, example.Text) + } + } + // Add all content with spacing if len(contentParts) > 0 { finalQuery += strings.Join(contentParts, "\n") + "\n\n" } } finalQuery += "--- INFO END ---\n\n" + request + "\n" + originalQuery := "" // Return the final query + for _, example := range knowledgedbResponse { + originalQuery += example.Text + "\n" + } + fmt.Printf("Original Query (General LLM Request):\n%s\n", originalQuery) + fmt.Printf("Final Query (General LLM Request):\n%s\n", finalQuery) return finalQuery } @@ -1210,13 +1241,23 @@ func BuildFinalQueryForCodeLLMRequest(request string, knowledgedbResponse []shar finalQuery = "Based on the following examples:\n\n" for i, element := range knowledgedbResponse { - // Add the example number - finalQuery += "--- START EXAMPLE " + fmt.Sprint(i+1) + "---\n" + // Determine collection type for better context + collectionType := "UNKNOWN" + if element.Type != "" && (element.NameFormatted != "" || element.Name != "") { + collectionType = "API_ELEMENT" + } else if element.Title != "" && element.SectionName != "" { + collectionType = "USER_GUIDE" + } else if element.DocumentName != "" && len(element.Dependencies) > 0 { + collectionType = "EXAMPLE" + } + + // Add collection type header + finalQuery += "--- START EXAMPLE " + fmt.Sprint(i+1) + " (" + collectionType + ") ---\n" // Build summary from all available non-empty fields var summaryParts []string - // CodeGenerationElement fields (likely from API/Element collections) + // CodeGenerationElement fields (from API/Element collections) if element.NameFormatted != "" { summaryParts = append(summaryParts, element.NameFormatted) } @@ -1227,7 +1268,7 @@ func BuildFinalQueryForCodeLLMRequest(request string, knowledgedbResponse []shar summaryParts = append(summaryParts, "Parent: "+element.ParentClass) } - // VectorDatabaseUserGuideSection fields (likely from User Guide collections) + // VectorDatabaseUserGuideSection fields (from User Guide collections) if element.Title != "" { summaryParts = append(summaryParts, element.Title) } @@ -1235,7 +1276,7 @@ func BuildFinalQueryForCodeLLMRequest(request string, knowledgedbResponse []shar summaryParts = append(summaryParts, "Section: "+element.SectionName) } - // Common fields + // VectorDatabaseExample fields (from Example collections) if element.DocumentName != "" { summaryParts = append(summaryParts, "Document: "+element.DocumentName) } @@ -1255,7 +1296,7 @@ func BuildFinalQueryForCodeLLMRequest(request string, knowledgedbResponse []shar } } - // Build code content from all available fields + // Build code content from available fields var codeParts []string if element.NamePseudocode != "" { @@ -1264,6 +1305,8 @@ func BuildFinalQueryForCodeLLMRequest(request string, knowledgedbResponse []shar if element.Name != "" { codeParts = append(codeParts, "# Function: "+element.Name) } + + // Handle Text field - all code examples should be properly formatted if element.Text != "" { codeParts = append(codeParts, element.Text) } From 33f4dadc6e8937987005d7f157255e056efedb75 Mon Sep 17 00:00:00 2001 From: AzeezIsh Date: Tue, 23 Sep 2025 13:51:32 -0400 Subject: [PATCH 4/7] extra deps check accidentally --- pkg/externalfunctions/llmhandler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/externalfunctions/llmhandler.go b/pkg/externalfunctions/llmhandler.go index 5424f3a3..166c5574 100644 --- a/pkg/externalfunctions/llmhandler.go +++ b/pkg/externalfunctions/llmhandler.go @@ -1247,7 +1247,7 @@ func BuildFinalQueryForCodeLLMRequest(request string, knowledgedbResponse []shar collectionType = "API_ELEMENT" } else if element.Title != "" && element.SectionName != "" { collectionType = "USER_GUIDE" - } else if element.DocumentName != "" && len(element.Dependencies) > 0 { + } else if element.DocumentName != "" { collectionType = "EXAMPLE" } From 4e1a8dd7cca1697fe1200966c1bf8a44e064d3ad Mon Sep 17 00:00:00 2001 From: AzeezIsh Date: Tue, 23 Sep 2025 16:26:10 -0400 Subject: [PATCH 5/7] normalized integration --- pkg/externalfunctions/llmhandler.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/externalfunctions/llmhandler.go b/pkg/externalfunctions/llmhandler.go index 166c5574..c7b22bc3 100644 --- a/pkg/externalfunctions/llmhandler.go +++ b/pkg/externalfunctions/llmhandler.go @@ -1252,7 +1252,7 @@ func BuildFinalQueryForCodeLLMRequest(request string, knowledgedbResponse []shar } // Add collection type header - finalQuery += "--- START EXAMPLE " + fmt.Sprint(i+1) + " (" + collectionType + ") ---\n" + finalQuery += "--- " + collectionType + " ---\n" // Build summary from all available non-empty fields var summaryParts []string @@ -1324,7 +1324,7 @@ func BuildFinalQueryForCodeLLMRequest(request string, knowledgedbResponse []shar finalQuery += ">>> Summary:\n" + summaryContent + "\n\n" finalQuery += ">>> Code snippet:\n```python\n" + codeContent + "\n```\n" - finalQuery += "--- END EXAMPLE " + fmt.Sprint(i+1) + "---\n\n" + finalQuery += "--- END " + fmt.Sprint(i+1) + " ---\n\n" } } From 28e52d4e8efffd587663c3b6f2657019ce6c37f6 Mon Sep 17 00:00:00 2001 From: Ryan Crisanti Date: Wed, 24 Sep 2025 10:21:36 -0400 Subject: [PATCH 6/7] refactor: split out dbresponse formatting & add test --- pkg/externalfunctions/llmhandler.go | 313 ++++++++--------------- pkg/externalfunctions/llmhandler_test.go | 122 +++++++++ 2 files changed, 234 insertions(+), 201 deletions(-) create mode 100644 pkg/externalfunctions/llmhandler_test.go diff --git a/pkg/externalfunctions/llmhandler.go b/pkg/externalfunctions/llmhandler.go index c7b22bc3..ee8c4fa1 100644 --- a/pkg/externalfunctions/llmhandler.go +++ b/pkg/externalfunctions/llmhandler.go @@ -1092,104 +1092,9 @@ func BuildFinalQueryForGeneralLLMRequest(request string, knowledgedbResponse []s // Append all non-empty fields to provide maximum context from comprehensive DbResponse finalQuery = "Based on the following examples:\n\n--- INFO START ---\n" for i, example := range knowledgedbResponse { - var contentParts []string - - // Determine collection type and add appropriate header - collectionType := "UNKNOWN" - if example.Type != "" && (example.NameFormatted != "" || example.Name != "") { - collectionType = "API_ELEMENT" - } else if example.Title != "" && example.SectionName != "" { - collectionType = "USER_GUIDE" - } else if example.DocumentName != "" { - collectionType = "EXAMPLE" - } - - contentParts = append(contentParts, fmt.Sprintf("=== %s #%d ===", collectionType, i+1)) - - // CodeGenerationElement fields (API/Element collections) - if example.Type != "" && (example.NameFormatted != "" || example.Name != "") { - if example.NameFormatted != "" { - contentParts = append(contentParts, "API: "+example.NameFormatted) - } - if example.NamePseudocode != "" { - contentParts = append(contentParts, "Function: "+example.NamePseudocode) - } - if example.Name != "" { - contentParts = append(contentParts, "Full Name: "+example.Name) - } - if example.Type != "" { - contentParts = append(contentParts, "Type: "+example.Type) - } - if example.ParentClass != "" { - contentParts = append(contentParts, "Parent: "+example.ParentClass) - } - } - - // VectorDatabaseUserGuideSection fields (User Guide collections) - if example.Title != "" && example.SectionName != "" { - contentParts = append(contentParts, "Guide Title: "+example.Title) - contentParts = append(contentParts, "Section: "+example.SectionName) - if example.ParentSectionName != "" { - contentParts = append(contentParts, "Parent Section: "+example.ParentSectionName) - } - } - - // VectorDatabaseExample fields (Example collections) - if example.DocumentName != "" { - contentParts = append(contentParts, "Example File: "+example.DocumentName) - // Convert []interface{} to []string for joining - var deps []string - for _, dep := range example.Dependencies { - if depStr, ok := dep.(string); ok { - deps = append(deps, depStr) - } - } - if len(deps) > 0 { - contentParts = append(contentParts, "Uses APIs: "+strings.Join(deps, ", ")) - } - } - - // Common fields - if example.DocumentName != "" && collectionType != "EXAMPLE" { - contentParts = append(contentParts, "Document: "+example.DocumentName) - } - if example.Summary != "" { - contentParts = append(contentParts, "Summary: "+example.Summary) - } - if len(example.Keywords) > 0 { - contentParts = append(contentParts, "Keywords: "+strings.Join(example.Keywords, ", ")) - } - if len(example.Tags) > 0 { - contentParts = append(contentParts, "Tags: "+strings.Join(example.Tags, ", ")) - } - - // Handle Text field with proper formatting based on collection type - if example.Text != "" { - if collectionType == "EXAMPLE" { - contentParts = append(contentParts, "Code:") - contentParts = append(contentParts, "```python") - contentParts = append(contentParts, example.Text) - contentParts = append(contentParts, "```") - } else { - contentParts = append(contentParts, "Content:") - contentParts = append(contentParts, example.Text) - } - } - - // Add all content with spacing - if len(contentParts) > 0 { - finalQuery += strings.Join(contentParts, "\n") + "\n\n" - } + finalQuery += dbResponsePromptFormat(example, i+1) + "\n\n" } finalQuery += "--- INFO END ---\n\n" + request + "\n" - originalQuery := "" - - // Return the final query - for _, example := range knowledgedbResponse { - originalQuery += example.Text + "\n" - } - fmt.Printf("Original Query (General LLM Request):\n%s\n", originalQuery) - fmt.Printf("Final Query (General LLM Request):\n%s\n", finalQuery) return finalQuery } @@ -1207,132 +1112,138 @@ func BuildFinalQueryForGeneralLLMRequest(request string, knowledgedbResponse []s // Returns: // - finalQuery: the final query func BuildFinalQueryForCodeLLMRequest(request string, knowledgedbResponse []sharedtypes.DbResponse) (finalQuery string) { - // Build the final query using the KnowledgeDB response and the original request - // We have to use the text from the DB response and the original request. - // - // The prompt should be in the following format: - // - // ****************************************************************************** - // Based on the following examples: - // - // --- START EXAMPLE {response_n}--- - // >>> Summary: - // {knowledge_db_response_n_summary} - // - // >>> Code snippet: - // ```python - // {knowledge_db_response_n_text} - // ``` - // --- END EXAMPLE {response_n}--- - // - // --- START EXAMPLE {response_n}--- - // ... - // --- END EXAMPLE {response_n}--- - // - // Generate the Python code for the following request: - // - // >>> Request: - // {original_request} - // ****************************************************************************** - // If there is no response from the KnowledgeDB, return the original request if len(knowledgedbResponse) > 0 { // Initial request finalQuery = "Based on the following examples:\n\n" for i, element := range knowledgedbResponse { - // Determine collection type for better context - collectionType := "UNKNOWN" - if element.Type != "" && (element.NameFormatted != "" || element.Name != "") { - collectionType = "API_ELEMENT" - } else if element.Title != "" && element.SectionName != "" { - collectionType = "USER_GUIDE" - } else if element.DocumentName != "" { - collectionType = "EXAMPLE" - } + finalQuery += dbResponsePromptFormat(element, i+1) + "\n\n" + } + } - // Add collection type header - finalQuery += "--- " + collectionType + " ---\n" + // Pass in the original request + finalQuery += "Generate the Python code for the following request:\n>>> Request:\n" + request + "\n" - // Build summary from all available non-empty fields - var summaryParts []string + // Return the final query + return finalQuery +} - // CodeGenerationElement fields (from API/Element collections) - if element.NameFormatted != "" { - summaryParts = append(summaryParts, element.NameFormatted) - } - if element.Type != "" { - summaryParts = append(summaryParts, "Type: "+element.Type) - } - if element.ParentClass != "" { - summaryParts = append(summaryParts, "Parent: "+element.ParentClass) - } +type CollectionType uint8 - // VectorDatabaseUserGuideSection fields (from User Guide collections) - if element.Title != "" { - summaryParts = append(summaryParts, element.Title) - } - if element.SectionName != "" { - summaryParts = append(summaryParts, "Section: "+element.SectionName) - } +const ( + Unknown CollectionType = iota + ApiElement + UserGuide + Example +) - // VectorDatabaseExample fields (from Example collections) - if element.DocumentName != "" { - summaryParts = append(summaryParts, "Document: "+element.DocumentName) - } - if element.Summary != "" { - summaryParts = append(summaryParts, "Summary: "+element.Summary) - } - if len(element.Dependencies) > 0 { - // Convert []interface{} to []string for joining - var deps []string - for _, dep := range element.Dependencies { - if depStr, ok := dep.(string); ok { - deps = append(deps, depStr) - } - } - if len(deps) > 0 { - summaryParts = append(summaryParts, "Dependencies: "+strings.Join(deps, ", ")) - } - } +func (coll CollectionType) String() string { + switch coll { + case ApiElement: + return "API ELEMENT" + case Example: + return "EXAMPLE" + case UserGuide: + return "USER GUIDE" + default: + return "UNKNOWN" + } +} - // Build code content from available fields - var codeParts []string +// Format a DbResponse as a string to include in the context. +// +// This takes a best guess at what type of document the DbResponse represents (API element/user guide/example) +// and then formats it accordingly. +func dbResponsePromptFormat(dbresponse sharedtypes.DbResponse, num int) string { + var contentParts []string + + // Determine collection type and add appropriate header + collectionType := Unknown + if dbresponse.Type != "" && (dbresponse.NameFormatted != "" || dbresponse.Name != "") { + collectionType = ApiElement + } else if dbresponse.Title != "" && dbresponse.SectionName != "" { + collectionType = UserGuide + } else if dbresponse.DocumentName != "" { + collectionType = Example + } else { + logging.Log.Warnf(&logging.ContextMap{}, "was unable to determine format of DB response for prompt formatting %v", dbresponse) + } - if element.NamePseudocode != "" { - codeParts = append(codeParts, "# "+element.NamePseudocode) - } - if element.Name != "" { - codeParts = append(codeParts, "# Function: "+element.Name) - } + contentParts = append(contentParts, fmt.Sprintf("=== START %s #%d ===", collectionType, num)) - // Handle Text field - all code examples should be properly formatted - if element.Text != "" { - codeParts = append(codeParts, element.Text) - } + // CodeGenerationElement fields (API/Element collections) + if collectionType == ApiElement { + if dbresponse.NameFormatted != "" { + contentParts = append(contentParts, "API: "+dbresponse.NameFormatted) + } + if dbresponse.NamePseudocode != "" { + contentParts = append(contentParts, "Function: "+dbresponse.NamePseudocode) + } + if dbresponse.Name != "" { + contentParts = append(contentParts, "Full Name: "+dbresponse.Name) + } + if dbresponse.Type != "" { + contentParts = append(contentParts, "Type: "+dbresponse.Type) + } + if dbresponse.ParentClass != "" { + contentParts = append(contentParts, "Parent: "+dbresponse.ParentClass) + } + } - // Use constructed content or fallback - summaryContent := strings.Join(summaryParts, " | ") - if summaryContent == "" { - summaryContent = "No summary available" - } + // VectorDatabaseUserGuideSection fields (User Guide collections) + if collectionType == UserGuide { + contentParts = append(contentParts, "Guide Title: "+dbresponse.Title) + contentParts = append(contentParts, "Section: "+dbresponse.SectionName) + if dbresponse.ParentSectionName != "" { + contentParts = append(contentParts, "Parent Section: "+dbresponse.ParentSectionName) + } + } - codeContent := strings.Join(codeParts, "\n") - if codeContent == "" { - codeContent = "# No code content available" + // VectorDatabaseExample fields (Example collections) + if collectionType == Example { + contentParts = append(contentParts, "Example File: "+dbresponse.DocumentName) + // Convert []interface{} to []string for joining + var deps []string + for _, dep := range dbresponse.Dependencies { + if depStr, ok := dep.(string); ok { + deps = append(deps, depStr) } - - finalQuery += ">>> Summary:\n" + summaryContent + "\n\n" - finalQuery += ">>> Code snippet:\n```python\n" + codeContent + "\n```\n" - finalQuery += "--- END " + fmt.Sprint(i+1) + " ---\n\n" + } + if len(deps) > 0 { + contentParts = append(contentParts, "Uses APIs: "+strings.Join(deps, ", ")) } } - // Pass in the original request - finalQuery += "Generate the Python code for the following request:\n>>> Request:\n" + request + "\n" + // Common fields + if dbresponse.DocumentName != "" { + contentParts = append(contentParts, "Document: "+dbresponse.DocumentName) + } + if dbresponse.Summary != "" { + contentParts = append(contentParts, "Summary: "+dbresponse.Summary) + } + if len(dbresponse.Keywords) > 0 { + contentParts = append(contentParts, "Keywords: "+strings.Join(dbresponse.Keywords, ", ")) + } + if len(dbresponse.Tags) > 0 { + contentParts = append(contentParts, "Tags: "+strings.Join(dbresponse.Tags, ", ")) + } - // Return the final query - return finalQuery + // Handle Text field with proper formatting based on collection type + if dbresponse.Text != "" { + if collectionType == Example { + contentParts = append(contentParts, "Code:") + contentParts = append(contentParts, "```python") + contentParts = append(contentParts, dbresponse.Text) + contentParts = append(contentParts, "```") + } else { + contentParts = append(contentParts, "Content:") + contentParts = append(contentParts, dbresponse.Text) + } + } + + contentParts = append(contentParts, fmt.Sprintf("=== END %s #%d ===", collectionType, num)) + return strings.Join(contentParts, "\n") } type AppendMessageHistoryRole string diff --git a/pkg/externalfunctions/llmhandler_test.go b/pkg/externalfunctions/llmhandler_test.go new file mode 100644 index 00000000..ae05cebf --- /dev/null +++ b/pkg/externalfunctions/llmhandler_test.go @@ -0,0 +1,122 @@ +// Copyright (C) 2025 ANSYS, Inc. and/or its affiliates. +// SPDX-License-Identifier: MIT +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package externalfunctions + +import ( + "strings" + "testing" + + "github.com/ansys/aali-sharedtypes/pkg/sharedtypes" + "github.com/stretchr/testify/assert" +) + +func TestDbResponsePromptFormat(t *testing.T) { + testCases := []struct { + name string + dbResponse sharedtypes.DbResponse + expectedLines []string + }{ + { + "API Element", + sharedtypes.DbResponse{ + Name: "M:Namespace.Class.MyCusomMethod(System.String,System.Int32)", + NamePseudocode: "MyCustomMethod", + NameFormatted: "My Custom Method", + Type: "Method", + ParentClass: "Namespace.Class", + Metadata: map[string]any{}, + }, + []string{ + "=== START API ELEMENT #1 ===", + "API: My Custom Method", + "Function: MyCustomMethod", + "Full Name: M:Namespace.Class.MyCusomMethod(System.String,System.Int32)", + "Type: Method", + "Parent: Namespace.Class", + "=== END API ELEMENT #1 ===", + }, + }, + { + "Example", + sharedtypes.DbResponse{ + DocumentName: "examples/my_example.py", + Text: "import random\n\ndef main():\n print(random.randint(0, 10))\n\nif __name__ == '__main__':\n main()\n", + PreviousChunk: "previous-chunk-id", + NextChunk: "next-chunk-id", + Dependencies: []any{"random"}, + DependencyEquivalences: map[string]any{"random": "random-equiv"}, + }, + []string{ + "=== START EXAMPLE #1 ===", + "Example File: examples/my_example.py", + "Uses APIs: random", + "Document: examples/my_example.py", + "Code:", + "```python", + "import random", + "", + "def main():", + " print(random.randint(0, 10))", + "", + "if __name__ == '__main__':", + " main()", + "", + "```", + "=== END EXAMPLE #1 ===", + }, + }, + { + "User Guide", + sharedtypes.DbResponse{ + SectionName: "Section", + DocumentName: "user_guide", + Title: "Title", + ParentSectionName: "Parent", + Level: "2", + Text: "Here is the user\nguide content", + PreviousChunk: "prev-chunk", + NextChunk: "next-chunk", + }, + []string{ + "=== START USER GUIDE #1 ===", + "Guide Title: Title", + "Section: Section", + "Parent Section: Parent", + "Document: user_guide", + "Content:", + "Here is the user", + "guide content", + "=== END USER GUIDE #1 ===", + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := dbResponsePromptFormat(tc.dbResponse, 1) + expected := strings.Join(tc.expectedLines, "\n") + assert.Equal(t, expected, result) + }) + } + +} From ad1981e1e3fae32fb951e99e4b427294733eee91 Mon Sep 17 00:00:00 2001 From: Ryan Crisanti Date: Wed, 24 Sep 2025 10:59:49 -0400 Subject: [PATCH 7/7] docs: remove extraneous newline --- pkg/externalfunctions/llmhandler.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/externalfunctions/llmhandler.go b/pkg/externalfunctions/llmhandler.go index 61e53ec2..684dd585 100644 --- a/pkg/externalfunctions/llmhandler.go +++ b/pkg/externalfunctions/llmhandler.go @@ -1075,7 +1075,6 @@ func BuildLibraryContext(message string, libraryContext string) (messageWithCont // - @displayName: Final Query (General LLM Request) // // Parameters: - // - request: the original request // - knowledgedbResponse: the KnowledgeDB response //