diff --git a/pkg/cli/tokens_bootstrap.go b/pkg/cli/tokens_bootstrap.go index e02d47eec63..d9f03d5f960 100644 --- a/pkg/cli/tokens_bootstrap.go +++ b/pkg/cli/tokens_bootstrap.go @@ -8,11 +8,14 @@ import ( "strings" "github.com/githubnext/gh-aw/pkg/console" + "github.com/githubnext/gh-aw/pkg/logger" "github.com/githubnext/gh-aw/pkg/repoutil" "github.com/githubnext/gh-aw/pkg/workflow" "github.com/spf13/cobra" ) +var tokensBootstrapLog = logger.New("cli:tokens_bootstrap") + // tokenSpec describes a recommended token secret for gh-aw type tokenSpec struct { Name string @@ -23,6 +26,7 @@ type tokenSpec struct { // getRecommendedTokensForEngine returns token specs based on the workflow engine func getRecommendedTokensForEngine(engine string) []tokenSpec { + tokensBootstrapLog.Printf("Getting recommended tokens for engine: %s", engine) // Base tokens needed for most workflows tokens := []tokenSpec{ { @@ -58,6 +62,8 @@ func getRecommendedTokensForEngine(engine string) []tokenSpec { }) } + tokensBootstrapLog.Printf("Collected engine-specific tokens: engine=%s, count=%d", engine, len(tokens)) + // Optional tokens for advanced use cases tokens = append(tokens, tokenSpec{ @@ -74,6 +80,7 @@ func getRecommendedTokensForEngine(engine string) []tokenSpec { }, ) + tokensBootstrapLog.Printf("Returning %d total token specs for engine %s", len(tokens), engine) return tokens } diff --git a/pkg/parser/schema_suggestions.go b/pkg/parser/schema_suggestions.go index 03c7eb05d1d..688800ae598 100644 --- a/pkg/parser/schema_suggestions.go +++ b/pkg/parser/schema_suggestions.go @@ -5,8 +5,12 @@ import ( "fmt" "sort" "strings" + + "github.com/githubnext/gh-aw/pkg/logger" ) +var schemaSuggestionsLog = logger.New("parser:schema_suggestions") + // Constants for suggestion limits and field generation const ( maxClosestMatches = 3 // Maximum number of closest matches to find @@ -17,30 +21,37 @@ const ( // generateSchemaBasedSuggestions generates helpful suggestions based on the schema and error type func generateSchemaBasedSuggestions(schemaJSON, errorMessage, jsonPath string) string { + schemaSuggestionsLog.Printf("Generating schema suggestions: path=%s, schema_size=%d bytes", jsonPath, len(schemaJSON)) // Parse the schema to extract information for suggestions var schemaDoc any if err := json.Unmarshal([]byte(schemaJSON), &schemaDoc); err != nil { + schemaSuggestionsLog.Printf("Failed to parse schema JSON: %v", err) return "" // Can't parse schema, no suggestions } // Check if this is an additional properties error if strings.Contains(strings.ToLower(errorMessage), "additional propert") && strings.Contains(strings.ToLower(errorMessage), "not allowed") { + schemaSuggestionsLog.Print("Detected additional properties error") invalidProps := extractAdditionalPropertyNames(errorMessage) acceptedFields := extractAcceptedFieldsFromSchema(schemaDoc, jsonPath) if len(acceptedFields) > 0 { + schemaSuggestionsLog.Printf("Found %d accepted fields for invalid properties %v", len(acceptedFields), invalidProps) return generateFieldSuggestions(invalidProps, acceptedFields) } } // Check if this is a type error if strings.Contains(strings.ToLower(errorMessage), "got ") && strings.Contains(strings.ToLower(errorMessage), "want ") { + schemaSuggestionsLog.Print("Detected type mismatch error") example := generateExampleJSONForPath(schemaDoc, jsonPath) if example != "" { + schemaSuggestionsLog.Printf("Generated example JSON: length=%d bytes", len(example)) return fmt.Sprintf("Expected format: %s", example) } } + schemaSuggestionsLog.Print("No suggestions generated for error") return "" } @@ -73,10 +84,12 @@ func extractAcceptedFieldsFromSchema(schemaDoc any, jsonPath string) []string { // navigateToSchemaPath navigates to the appropriate schema section for a given JSON path func navigateToSchemaPath(schema map[string]any, jsonPath string) map[string]any { if jsonPath == "" { + schemaSuggestionsLog.Print("Navigating to root schema path") return schema // Root level } // Parse the JSON path and navigate through the schema + schemaSuggestionsLog.Printf("Navigating schema path: %s", jsonPath) pathSegments := parseJSONPath(jsonPath) current := schema @@ -184,6 +197,7 @@ func generateFieldSuggestions(invalidProps, acceptedFields []string) string { // It returns up to maxResults matches that have a Levenshtein distance of 3 or less. // Results are sorted by distance (closest first), then alphabetically for ties. func FindClosestMatches(target string, candidates []string, maxResults int) []string { + schemaSuggestionsLog.Printf("Finding closest matches for '%s' from %d candidates", target, len(candidates)) type match struct { value string distance int @@ -224,6 +238,7 @@ func FindClosestMatches(target string, candidates []string, maxResults int) []st results = append(results, matches[i].value) } + schemaSuggestionsLog.Printf("Found %d closest matches (from %d total matches within max distance)", len(results), len(matches)) return results } diff --git a/pkg/workflow/compiler_safe_outputs_config.go b/pkg/workflow/compiler_safe_outputs_config.go index e201d4869ca..abf6cdaee56 100644 --- a/pkg/workflow/compiler_safe_outputs_config.go +++ b/pkg/workflow/compiler_safe_outputs_config.go @@ -3,18 +3,25 @@ package workflow import ( "encoding/json" "fmt" + + "github.com/githubnext/gh-aw/pkg/logger" ) +var compilerSafeOutputsLog = logger.New("workflow:compiler_safe_outputs_config") + func (c *Compiler) addHandlerManagerConfigEnvVar(steps *[]string, data *WorkflowData) { if data.SafeOutputs == nil { + compilerSafeOutputsLog.Print("No safe-outputs configuration, skipping handler manager config") return } + compilerSafeOutputsLog.Print("Building handler manager configuration for safe-outputs") config := make(map[string]map[string]any) // Add config for each enabled safe output type with their options // Presence in config = enabled, so no need for "enabled": true field if data.SafeOutputs.CreateIssues != nil { + compilerSafeOutputsLog.Print("Adding create_issue handler configuration") cfg := data.SafeOutputs.CreateIssues handlerConfig := make(map[string]any) if cfg.Max > 0 { @@ -519,6 +526,7 @@ func (c *Compiler) addHandlerManagerConfigEnvVar(steps *[]string, data *Workflow // Only add the env var if there are handlers to configure if len(config) > 0 { + compilerSafeOutputsLog.Printf("Marshaling handler config with %d handlers", len(config)) configJSON, err := json.Marshal(config) if err != nil { consolidatedSafeOutputsLog.Printf("Failed to marshal handler config: %v", err) @@ -527,6 +535,9 @@ func (c *Compiler) addHandlerManagerConfigEnvVar(steps *[]string, data *Workflow // Escape the JSON for YAML (handle quotes and special chars) configStr := string(configJSON) *steps = append(*steps, fmt.Sprintf(" GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: %q\n", configStr)) + compilerSafeOutputsLog.Printf("Added handler config env var: size=%d bytes", len(configStr)) + } else { + compilerSafeOutputsLog.Print("No handlers configured, skipping config env var") } } @@ -535,9 +546,11 @@ func (c *Compiler) addHandlerManagerConfigEnvVar(steps *[]string, data *Workflow // These handlers require GH_AW_PROJECT_GITHUB_TOKEN and are processed separately from the main handler manager. func (c *Compiler) addProjectHandlerManagerConfigEnvVar(steps *[]string, data *WorkflowData) { if data.SafeOutputs == nil { + compilerSafeOutputsLog.Print("No safe-outputs configuration, skipping project handler config") return } + compilerSafeOutputsLog.Print("Building project handler manager configuration") config := make(map[string]map[string]any) // Add config for project-related safe output types diff --git a/pkg/workflow/tools_types.go b/pkg/workflow/tools_types.go index 21a5d90986b..0d11c9cb042 100644 --- a/pkg/workflow/tools_types.go +++ b/pkg/workflow/tools_types.go @@ -1,9 +1,12 @@ package workflow import ( + "github.com/githubnext/gh-aw/pkg/logger" "github.com/githubnext/gh-aw/pkg/types" ) +var toolsTypesLog = logger.New("workflow:tools_types") + // ToolsConfig represents the unified configuration for all tools in a workflow. // This type provides a structured alternative to the pervasive map[string]any pattern. // It includes strongly-typed fields for built-in tools and a flexible Custom map for @@ -91,7 +94,10 @@ type Tools = ToolsConfig // It parses all known tool types into their strongly-typed equivalents and stores // unknown tools in the Custom map. func ParseToolsConfig(toolsMap map[string]any) (*ToolsConfig, error) { + toolsTypesLog.Printf("Parsing tools configuration: tool_count=%d", len(toolsMap)) config := NewTools(toolsMap) + toolNames := config.GetToolNames() + toolsTypesLog.Printf("Parsed tools configuration: result_count=%d, tools=%v", len(toolNames), toolNames) return config, nil } @@ -156,15 +162,18 @@ func mcpServerConfigToMap(config MCPServerConfig) map[string]any { // This is useful when interfacing with legacy code that expects map[string]any. func (t *ToolsConfig) ToMap() map[string]any { if t == nil { + toolsTypesLog.Print("Converting nil ToolsConfig to empty map") return make(map[string]any) } // Return the raw map if it exists if t.raw != nil { + toolsTypesLog.Printf("Returning cached raw map with %d entries", len(t.raw)) return t.raw } // Otherwise construct a new map from the fields + toolsTypesLog.Print("Constructing map from ToolsConfig fields") result := make(map[string]any) if t.GitHub != nil { @@ -214,6 +223,7 @@ func (t *ToolsConfig) ToMap() map[string]any { result[name] = mcpServerConfigToMap(config) } + toolsTypesLog.Printf("Constructed map with %d entries from ToolsConfig", len(result)) return result } @@ -371,6 +381,8 @@ func (t *Tools) HasTool(name string) bool { return false } + toolsTypesLog.Printf("Checking if tool exists: name=%s", name) + switch name { case "github": return t.GitHub != nil @@ -408,6 +420,7 @@ func (t *Tools) GetToolNames() []string { return []string{} } + toolsTypesLog.Print("Collecting configured tool names") names := []string{} if t.GitHub != nil { @@ -452,5 +465,6 @@ func (t *Tools) GetToolNames() []string { names = append(names, name) } + toolsTypesLog.Printf("Found %d configured tools: %v", len(names), names) return names }