Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions pkg/workflow/config_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,10 @@ func ParseStringArrayFromConfig(m map[string]any, key string, log *logger.Logger
if log != nil {
log.Printf("Parsing %s from config", key)
}
if arrayValue, ok := value.([]any); ok {
var strings []string
for _, item := range arrayValue {
if strVal, ok := item.(string); ok {
strings = append(strings, strVal)
}
}
if strings := parseStringSliceAny(value, log); strings != nil {
// Return the slice even if empty (to distinguish from not provided)
if strings == nil {
if log != nil {
log.Printf("No valid %s strings found, returning empty array", key)
}
return []string{}
if len(strings) == 0 && log != nil {
log.Printf("No valid %s strings found, returning empty array", key)
}
if log != nil {
log.Printf("Parsed %d %s from config", len(strings), key)
Expand Down
7 changes: 7 additions & 0 deletions pkg/workflow/config_parsing_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ func TestParseLabelsFromConfig(t *testing.T) {
},
expected: []string{"bug", "enhancement", "documentation"},
},
{
name: "labels as []string",
input: map[string]any{
"labels": []string{"bug", "enhancement"},
},
expected: []string{"bug", "enhancement"},
},
{
name: "labels as non-array type",
input: map[string]any{
Expand Down
11 changes: 0 additions & 11 deletions pkg/workflow/missing_data.go

This file was deleted.

46 changes: 35 additions & 11 deletions pkg/workflow/missing_issue_reporting.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import (
"github.com/github/gh-aw/pkg/logger"
)

var missingDataLog = logger.New("workflow:missing_data")
var missingToolLog = logger.New("workflow:missing_tool")
var reportIncompleteLog = logger.New("workflow:report_incomplete")

// IssueReportingConfig holds configuration shared by safe-output types that create GitHub issues
// (missing-data and missing-tool). Both types have identical fields; the yaml tags on the
// parent struct fields give them their distinct YAML keys.
Expand All @@ -19,6 +23,34 @@ type IssueReportingConfig struct {
type MissingDataConfig = IssueReportingConfig
type MissingToolConfig = IssueReportingConfig

// ReportIncompleteConfig holds configuration for the report_incomplete safe output.
// report_incomplete is a structured signal that the agent could not complete its
// assigned task due to an infrastructure or tool failure (e.g., MCP server crash,
// missing authentication, inaccessible repository).
//
// When an agent emits report_incomplete, gh-aw activates failure handling even
// when the agent process exits 0 and other safe outputs were also emitted.
// This prevents semantically-empty outputs (e.g., a comment describing tool
// failures) from being classified as a successful result.
//
// ReportIncompleteConfig is a type alias for IssueReportingConfig so that it
// supports the same create-issue, title-prefix, and labels configuration fields
// as missing-tool and missing-data.
type ReportIncompleteConfig = IssueReportingConfig

func (c *Compiler) parseMissingDataConfig(outputMap map[string]any) *MissingDataConfig {
return c.parseIssueReportingConfig(outputMap, "missing-data", "[missing data]", missingDataLog)
}

func (c *Compiler) parseMissingToolConfig(outputMap map[string]any) *MissingToolConfig {
return c.parseIssueReportingConfig(outputMap, "missing-tool", "[missing tool]", missingToolLog)
}

// parseReportIncompleteConfig handles report_incomplete configuration.
func (c *Compiler) parseReportIncompleteConfig(outputMap map[string]any) *ReportIncompleteConfig {
return c.parseIssueReportingConfig(outputMap, "report-incomplete", "[incomplete]", reportIncompleteLog)
}

func (c *Compiler) parseIssueReportingConfig(outputMap map[string]any, yamlKey, defaultTitle string, log *logger.Logger) *IssueReportingConfig {
configData, exists := outputMap[yamlKey]
if !exists {
Expand Down Expand Up @@ -64,17 +96,9 @@ func (c *Compiler) parseIssueReportingConfig(outputMap map[string]any, yamlKey,
cfg.TitlePrefix = defaultTitle
}

if labels, exists := configMap["labels"]; exists {
if labelsArray, ok := labels.([]any); ok {
var labelStrings []string
for _, label := range labelsArray {
if labelStr, ok := label.(string); ok {
labelStrings = append(labelStrings, labelStr)
}
}
cfg.Labels = labelStrings
log.Printf("labels: %v", labelStrings)
}
if _, exists := configMap["labels"]; exists {
cfg.Labels = ParseStringArrayFromConfig(configMap, "labels", log)
log.Printf("labels: %v", cfg.Labels)
} else {
cfg.Labels = []string{}
}
Expand Down
11 changes: 0 additions & 11 deletions pkg/workflow/missing_tool.go

This file was deleted.

12 changes: 12 additions & 0 deletions pkg/workflow/missing_tool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,18 @@ func TestMissingToolConfigParsing(t *testing.T) {
expectTitlePrefix: "[missing tool]",
expectLabels: []string{"bug", "enhancement", "missing-tool"},
},
{
name: "Custom labels as []string",
configData: map[string]any{
"missing-tool": map[string]any{
"labels": []string{"bug", "enhancement", "missing-tool"},
},
},
expectMax: 0,
expectCreateIssue: true,
expectTitlePrefix: "[missing tool]",
expectLabels: []string{"bug", "enhancement", "missing-tool"},
},
{
name: "Full configuration",
configData: map[string]any{
Expand Down
27 changes: 0 additions & 27 deletions pkg/workflow/report_incomplete.go

This file was deleted.

7 changes: 7 additions & 0 deletions pkg/workflow/safe_outputs_cross_repo_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,13 @@ func TestParseAllowedReposFromConfig(t *testing.T) {
},
expected: []string{"owner/repo1", "owner/repo2", "other-owner/repo3"},
},
{
name: "allowed-repos as []string",
input: map[string]any{
"allowed-repos": []string{"owner/repo1", "owner/repo2"},
},
expected: []string{"owner/repo1", "owner/repo2"},
},
{
name: "no allowed-repos key",
input: map[string]any{},
Expand Down
Loading