@@ -10,62 +10,65 @@ import (
1010
1111var orchestratorLog = logger .New ("campaign:orchestrator" )
1212
13- // extractFileGlobPattern extracts the file glob pattern from memory-paths or
14- // metrics-glob configuration. This pattern is used for the file-glob filter in
13+ // convertStringsToAny converts a slice of strings to a slice of any
14+ func convertStringsToAny (strings []string ) []any {
15+ result := make ([]any , len (strings ))
16+ for i , s := range strings {
17+ result [i ] = s
18+ }
19+ return result
20+ }
21+
22+ // extractFileGlobPatterns extracts all file glob patterns from memory-paths or
23+ // metrics-glob configuration. These patterns are used for the file-glob filter in
1524// repo-memory configuration to match files that the agent creates.
1625//
1726// For campaigns that use dated directory patterns (e.g., campaign-id-*/), this
18- // function preserves the wildcard pattern instead of using just the campaign ID.
27+ // function preserves all wildcard patterns from memory-paths to support multiple
28+ // directory structures (both dated and non-dated).
1929//
2030// Examples:
21- // - memory-paths: ["memory/campaigns/project64-*/**"] -> "project64-*/**"
22- // - metrics-glob: "memory/campaigns/project64-*/metrics/*.json" -> "project64-*/**"
23- // - no patterns with wildcards -> "project64/**" (fallback to ID)
24- func extractFileGlobPattern (spec * CampaignSpec ) string {
25- // Try to extract pattern from memory-paths first
26- // Prefer patterns with wildcards in the directory name (e.g., campaign-id-*)
27- var firstValidPattern string
31+ // - memory-paths: ["memory/campaigns/project64-*/**", "memory/campaigns/project64/**"]
32+ // -> ["project64-*/**", "project64/**"]
33+ // - memory-paths: ["memory/campaigns/project64-*/**"] -> ["project64-*/**"]
34+ // - metrics-glob: "memory/campaigns/project64-*/metrics/*.json" -> ["project64-*/**"]
35+ // - no patterns with wildcards -> ["project64/**"] (fallback to ID)
36+ func extractFileGlobPatterns (spec * CampaignSpec ) []string {
37+ var patterns []string
38+
39+ // Extract all patterns from memory-paths
2840 for _ , memPath := range spec .MemoryPaths {
2941 // Remove "memory/campaigns/" prefix if present
3042 pattern := strings .TrimPrefix (memPath , "memory/campaigns/" )
3143 // If pattern has both wildcards and slashes, it's a valid pattern
3244 if strings .Contains (pattern , "*" ) && strings .Contains (pattern , "/" ) {
33- // Check if wildcard is in the directory name (not just in **)
34- if strings .Contains (strings .Split (pattern , "/" )[0 ], "*" ) {
35- // This pattern has a wildcard in the directory name - prefer it
36- orchestratorLog .Printf ("Extracted file-glob pattern from memory-paths (with wildcard): %s" , pattern )
37- return pattern
38- }
39- // Save this as a fallback valid pattern
40- if firstValidPattern == "" {
41- firstValidPattern = pattern
42- }
45+ patterns = append (patterns , pattern )
46+ orchestratorLog .Printf ("Extracted file-glob pattern from memory-paths: %s" , pattern )
4347 }
4448 }
4549
46- // If we found a valid pattern (even without directory wildcard), use it
47- if firstValidPattern != "" {
48- orchestratorLog .Printf ("Extracted file-glob pattern from memory-paths: %s" , firstValidPattern )
49- return firstValidPattern
50+ // If we found patterns from memory-paths, return them
51+ if len (patterns ) > 0 {
52+ return patterns
5053 }
5154
52- // Try to extract pattern from metrics-glob
55+ // Try to extract pattern from metrics-glob as fallback
5356 if spec .MetricsGlob != "" {
5457 pattern := strings .TrimPrefix (spec .MetricsGlob , "memory/campaigns/" )
5558 if strings .Contains (pattern , "*" ) {
5659 // Extract the base directory pattern (everything before /metrics/ or first file-specific part)
5760 if idx := strings .Index (pattern , "/metrics/" ); idx > 0 {
5861 basePattern := pattern [:idx ] + "/**"
5962 orchestratorLog .Printf ("Extracted file-glob pattern from metrics-glob: %s" , basePattern )
60- return basePattern
63+ return [] string { basePattern }
6164 }
6265 }
6366 }
6467
6568 // Fallback to simple ID-based pattern
6669 fallbackPattern := fmt .Sprintf ("%s/**" , spec .ID )
6770 orchestratorLog .Printf ("Using fallback file-glob pattern: %s" , fallbackPattern )
68- return fallbackPattern
71+ return [] string { fallbackPattern }
6972}
7073
7174// BuildOrchestrator constructs a minimal agentic workflow representation for a
@@ -259,9 +262,9 @@ func BuildOrchestrator(spec *CampaignSpec, campaignFilePath string) (*workflow.W
259262
260263 orchestratorLog .Printf ("Campaign orchestrator '%s' built successfully with safe outputs enabled" , spec .ID )
261264
262- // Extract file-glob pattern from memory-paths or metrics-glob to support
263- // dated campaign directory patterns like "campaign-id-*/**"
264- fileGlobPattern := extractFileGlobPattern (spec )
265+ // Extract file-glob patterns from memory-paths or metrics-glob to support
266+ // multiple directory structures (e.g., both dated "campaign-id-*/**" and non-dated "campaign-id/**")
267+ fileGlobPatterns := extractFileGlobPatterns (spec )
265268
266269 data := & workflow.WorkflowData {
267270 Name : name ,
@@ -283,7 +286,7 @@ func BuildOrchestrator(spec *CampaignSpec, campaignFilePath string) (*workflow.W
283286 map [string ]any {
284287 "id" : "campaigns" ,
285288 "branch-name" : "memory/campaigns" ,
286- "file-glob" : [] any { fileGlobPattern } ,
289+ "file-glob" : convertStringsToAny ( fileGlobPatterns ) ,
287290 },
288291 },
289292 "bash" : []any {"*" },
0 commit comments