Skip to content

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Jan 11, 2026

fix: make regions cache profile-aware by including API URL

Summary

Fixes #543 - The regions cache at ~/.config/agentuity/regions.json was not profile-aware, causing the wrong region to be used after switching profiles. When a user switched from a local profile to production, the cache still contained regions from the local API endpoint, resulting in projects being created with region: "local" instead of the production region.

Changes:

  • Added apiUrl field to RegionsCacheData interface to track which API the cache was fetched from
  • Updated getCachedRegions() to validate the cached API URL matches the current profile's API URL
  • Updated saveRegionsCache() to include the API URL when saving
  • Updated all 8 call sites of resolveRegion() to pass apiUrl: getAPIBaseURL(baseCtx.config)

The apiUrl field is optional for backward compatibility - existing cache files without this field will continue to work.

Review & Testing Checklist for Human

  • Test profile switching workflow: Create a project with local profile, switch to production profile, delete ~/.config/agentuity/regions.json, create another project - verify the new project has the correct production region (not "local")
  • Verify all 8 call sites: Confirm all resolveRegion() calls in registerSubcommand() and registerCommands() now include apiUrl: getAPIBaseURL(baseCtx.config)
  • Test backward compatibility: Verify that an existing cache file without apiUrl field still works (should be used if within TTL)

Recommended test plan:

  1. Set up two profiles (local and production)
  2. Use local profile, run a command that fetches regions
  3. Switch to production profile
  4. Run a command that fetches regions - verify it re-fetches from production API (check trace logs)
  5. Create a new project - verify agentuity.json has the correct production region

Notes

Summary by CodeRabbit

  • Bug Fixes
    • Improved region caching to properly support multiple API configurations, ensuring cached region data is correctly isolated per profile and preventing cross-profile cache conflicts.

✏️ Tip: You can customize this high-level summary in your review settings.

The regions cache at ~/.config/agentuity/regions.json was not profile-aware,
causing the wrong region to be used after switching profiles. This fix:

1. Adds apiUrl field to RegionsCacheData interface
2. Updates getCachedRegions to validate cached API URL matches current
3. Updates saveRegionsCache to include API URL in cache data
4. Updates fetchRegionsWithCache to pass API URL through
5. Updates all resolveRegion calls to pass the API URL

When the cached API URL doesn't match the current profile's API URL,
the cache is invalidated and regions are re-fetched from the correct API.

Fixes #543

Co-Authored-By: Rick Blalock <rickblalock@mac.com>
@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@coderabbitai
Copy link

coderabbitai bot commented Jan 11, 2026

📝 Walkthrough

Walkthrough

The changes introduce API URL awareness to region caching and resolution. The apiUrl parameter is propagated through region-related functions to enable profile-specific caching. Cache data now includes an optional apiUrl field, and cache retrieval validates the API URL matches before returning cached data.

Changes

Cohort / File(s) Summary
Region caching profile-awareness
packages/cli/src/cli.ts
Added apiUrl parameter to ResolveRegionOptions, getCachedRegions, saveRegionsCache, fetchRegionsWithCache, and resolveRegion. Cache structure modified to store apiUrl alongside regions. Cache lookup now validates apiUrl matches before returning cached data. Updated all call-sites to pass apiUrl from configuration.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed PR implements profile-aware regions caching by adding apiUrl to cache validation, matching issue #543 objectives to prevent wrong region selection after profile switches.
Out of Scope Changes check ✅ Passed All changes in cli.ts are directly focused on making regions cache profile-aware by propagating apiUrl through region resolution logic, with no unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch devin/1768152105-fix-regions-cache-profile-aware

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

📦 Canary Packages Published

version: 0.1.8-83f7134

Packages
Package Version URL
@agentuity/server 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-server-0.1.8-83f7134.tgz
@agentuity/react 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-react-0.1.8-83f7134.tgz
@agentuity/frontend 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-frontend-0.1.8-83f7134.tgz
@agentuity/cli 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-cli-0.1.8-83f7134.tgz
@agentuity/workbench 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-workbench-0.1.8-83f7134.tgz
@agentuity/runtime 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-runtime-0.1.8-83f7134.tgz
@agentuity/schema 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-schema-0.1.8-83f7134.tgz
@agentuity/core 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-core-0.1.8-83f7134.tgz
@agentuity/evals 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-evals-0.1.8-83f7134.tgz
@agentuity/auth 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-auth-0.1.8-83f7134.tgz
Install

Add to your package.json:

{
  "dependencies": {
    "@agentuity/server": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-server-0.1.8-83f7134.tgz",
    "@agentuity/react": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-react-0.1.8-83f7134.tgz",
    "@agentuity/frontend": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-frontend-0.1.8-83f7134.tgz",
    "@agentuity/cli": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-cli-0.1.8-83f7134.tgz",
    "@agentuity/workbench": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-workbench-0.1.8-83f7134.tgz",
    "@agentuity/runtime": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-runtime-0.1.8-83f7134.tgz",
    "@agentuity/schema": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-schema-0.1.8-83f7134.tgz",
    "@agentuity/core": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-core-0.1.8-83f7134.tgz",
    "@agentuity/evals": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-evals-0.1.8-83f7134.tgz",
    "@agentuity/auth": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-auth-0.1.8-83f7134.tgz"
  }
}

Or install directly:

bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-server-0.1.8-83f7134.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-react-0.1.8-83f7134.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-frontend-0.1.8-83f7134.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-cli-0.1.8-83f7134.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-workbench-0.1.8-83f7134.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-runtime-0.1.8-83f7134.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-schema-0.1.8-83f7134.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-core-0.1.8-83f7134.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-evals-0.1.8-83f7134.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.8-83f7134/agentuity-auth-0.1.8-83f7134.tgz
CLI Executables
Platform Version URL
darwin-x64 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/binary/0.1.8-83f7134/agentuity-darwin-x64.gz
linux-arm64 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/binary/0.1.8-83f7134/agentuity-linux-arm64.gz
linux-x64 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/binary/0.1.8-83f7134/agentuity-linux-x64.gz
darwin-arm64 0.1.8-83f7134 https://agentuity-sdk-objects.t3.storage.dev/binary/0.1.8-83f7134/agentuity-darwin-arm64.gz
Run Canary CLI
agentuity canary 0.1.8-83f7134 [command] [...args]

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/cli/src/cli.ts (1)

1237-1245: Contract is correct; however, getAPIBaseURL(baseCtx.config) is recomputed 8 times across call sites with identical input.
Confirmed: getAPIBaseURL correctly accepts Config | null, and baseCtx.config is the same stable value at each call site, so the returned apiUrl string will be identical. This matches the contract expected by resolveRegion and the APIClient instance.

However, since baseCtx.config does not change between calls, the same string is computed redundantly. Consider caching the result in baseCtx (e.g., baseCtx.apiUrl) to compute it once.

🧹 Nitpick comments (3)
packages/cli/src/cli.ts (3)

703-731: Harden cache parsing + normalize apiUrl before comparison.
Right now, a corrupted/hand-edited cache can parse but still return data.regions with a bad shape (and timestamp can yield NaN), and URL comparisons can spuriously mismatch on trailing slashes.

Proposed hardening (validation + normalization)
 async function getCachedRegions(apiUrl: string, logger: Logger): Promise<RegionList | null> {
 	try {
+		const normalizeApiUrl = (u: string) => u.replace(/\/+$/, '');
+		const currentApiUrl = normalizeApiUrl(apiUrl);
+
 		const cachePath = join(getDefaultConfigDir(), REGIONS_CACHE_FILE);
 		const file = Bun.file(cachePath);
 		if (!(await file.exists())) {
 			return null;
 		}
 		const data: RegionsCacheData = await file.json();
+
+		// Basic shape validation (handle corrupted/partial caches safely)
+		if (
+			!data ||
+			typeof data.timestamp !== 'number' ||
+			!Array.isArray(data.regions)
+		) {
+			logger.trace('regions cache has invalid shape; ignoring');
+			return null;
+		}
+
 		// Check if cache is for the same API URL (profile-aware)
-		if (data.apiUrl && data.apiUrl !== apiUrl) {
+		const cachedApiUrl = data.apiUrl ? normalizeApiUrl(data.apiUrl) : undefined;
+		if (cachedApiUrl && cachedApiUrl !== currentApiUrl) {
 			logger.trace(
 				'regions cache is for different API URL (cached: %s, current: %s)',
-				data.apiUrl,
-				apiUrl
+				cachedApiUrl,
+				currentApiUrl
 			);
 			return null;
 		}
 		const age = Date.now() - data.timestamp;
 		if (age > REGIONS_CACHE_MAX_AGE_MS) {
 			logger.trace('regions cache expired (age: %dms)', age);
 			return null;
 		}
 		logger.trace('using cached regions (age: %dms)', age);
 		return data.regions;
 	} catch (error) {
 		logger.trace('failed to read regions cache: %s', error);
 		return null;
 	}
 }

733-752: Consider atomic writes for the cache file (avoid partial JSON on interruption).
Not a huge deal, but if the process is killed mid-write you can end up with unreadable JSON until TTL expires / next refresh.


754-773: Ensure apiUrl used for caching matches the actual apiClient base URL.
Right now fetchRegionsWithCache(apiUrl, apiClient, ...) will call listRegions(apiClient) (source of truth) but key the cache off a separately-computed apiUrl; if those ever diverge (overrides/env/trailing slash), you’ll get confusing cache reuse/invalidations.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d2cd4c4 and 83f7134.

📒 Files selected for processing (1)
  • packages/cli/src/cli.ts
🧰 Additional context used
📓 Path-based instructions (2)
packages/cli/src/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

Use Bun.file(f).exists() instead of existsSync(f) for file existence checks

Files:

  • packages/cli/src/cli.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • packages/cli/src/cli.ts
🧠 Learnings (1)
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • packages/cli/src/cli.ts
🧬 Code graph analysis (1)
packages/cli/src/cli.ts (3)
packages/server/src/api/region/list.ts (2)
  • RegionList (14-14)
  • listRegions (22-32)
packages/cli/src/config.ts (1)
  • getDefaultConfigDir (27-29)
packages/cli/src/api.ts (1)
  • getAPIBaseURL (86-89)
🔇 Additional comments (1)
packages/cli/src/cli.ts (1)

685-701: Good direction: profile-aware cache key is now explicit and backward-compatible.
Adding ResolveRegionOptions.apiUrl + RegionsCacheData.apiUrl? cleanly scopes the cache without breaking existing cache files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Region cache is not profile-aware, causing wrong region to be used after profile switch

2 participants