generateCacheMemorySteps generates cache setup steps (directory creation, restore, and git init) for the cache-memory configuration. Cache-memory provides a simple file share that LLMs can read/write freely. Artifact upload is handled separately by generateCacheMemoryArtifactUpload after agent execu
(builder *strings.Builder, data *WorkflowData)
| 480 | // Cache-memory provides a simple file share that LLMs can read/write freely. |
| 481 | // Artifact upload is handled separately by generateCacheMemoryArtifactUpload after agent execution. |
| 482 | func generateCacheMemorySteps(builder *strings.Builder, data *WorkflowData) { |
| 483 | if data.CacheMemoryConfig == nil || len(data.CacheMemoryConfig.Caches) == 0 { |
| 484 | return |
| 485 | } |
| 486 | |
| 487 | cacheLog.Printf("Generating cache-memory setup steps for %d caches", len(data.CacheMemoryConfig.Caches)) |
| 488 | |
| 489 | builder.WriteString(" # Cache memory file share configuration from frontmatter processed below\n") |
| 490 | |
| 491 | // Use backward-compatible paths only when there's a single cache with ID "default" |
| 492 | // This maintains compatibility with existing workflows |
| 493 | useBackwardCompatiblePaths := len(data.CacheMemoryConfig.Caches) == 1 && data.CacheMemoryConfig.Caches[0].ID == "default" |
| 494 | |
| 495 | // Extract GitHub guard policy for integrity-aware cache key generation. |
| 496 | var githubConfig *GitHubToolConfig |
| 497 | if data.ParsedTools != nil { |
| 498 | githubConfig = data.ParsedTools.GitHub |
| 499 | } |
| 500 | integrityLevel := cacheIntegrityLevel(githubConfig) |
| 501 | for i, cache := range data.CacheMemoryConfig.Caches { |
| 502 | cacheDir := cacheMemoryDirFor(cache.ID) |
| 503 | restoreStepID := fmt.Sprintf("restore_cache_memory_%d", i) |
| 504 | |
| 505 | // Add step to create cache-memory directory for this cache |
| 506 | if useBackwardCompatiblePaths { |
| 507 | // For single default cache, use the original directory for backward compatibility |
| 508 | builder.WriteString(" - name: Create cache-memory directory\n") |
| 509 | builder.WriteString(" run: bash \"${RUNNER_TEMP}/gh-aw/actions/create_cache_memory_dir.sh\"\n") |
| 510 | } else { |
| 511 | fmt.Fprintf(builder, " - name: Create cache-memory directory (%s)\n", cache.ID) |
| 512 | builder.WriteString(" run: |\n") |
| 513 | fmt.Fprintf(builder, " mkdir -p %s\n", cacheDir) |
| 514 | } |
| 515 | |
| 516 | // Use integrity-aware cache key (includes integrity level + policy hash prefix). |
| 517 | cacheKey := computeIntegrityCacheKey(cache, githubConfig) |
| 518 | |
| 519 | // Ensure run_id suffix is present (computeIntegrityCacheKey guarantees this, |
| 520 | // but we check again for clarity and safety). |
| 521 | runIdSuffix := "-${{ github.run_id }}" |
| 522 | if !strings.HasSuffix(cacheKey, runIdSuffix) { |
| 523 | cacheKey = cacheKey + runIdSuffix |
| 524 | } |
| 525 | |
| 526 | // Generate restore keys based on scope |
| 527 | // - "workflow" (default): Single restore key with workflow ID (secure) |
| 528 | // - "repo": Two restore keys - with and without workflow ID (allows cross-workflow sharing) |
| 529 | var restoreKeys []string |
| 530 | |
| 531 | // Determine scope (default to "workflow" for safety) |
| 532 | scope := cache.Scope |
| 533 | if scope == "" { |
| 534 | scope = "workflow" |
| 535 | } |
| 536 | |
| 537 | // First restore key: remove the run_id suffix as a single unit (don't split the key) |
| 538 | // The cacheKey always ends with "-${{ github.run_id }}" (ensured by code above) |
| 539 | if strings.HasSuffix(cacheKey, runIdSuffix) { |