@robhowley/pi-openrouter 0.11.1 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,12 @@ import { createSessionState, type SessionState } from './session-state.js';
9
9
  import { writeLocalUsage, type LocalUsageEvent } from './local-usage.js';
10
10
  import { loadCache, getCacheAgeMs, formatDuration } from './models/cache.js';
11
11
  import { mapOpenRouterModels } from './models/mapper.js';
12
- import { includeBuiltinRouterModels, isSyncEnabled } from './models/sync.js';
12
+ import {
13
+ filterModelsForCatalogMode,
14
+ includeBuiltinRouterModels,
15
+ isSyncEnabled,
16
+ setActiveCatalogState,
17
+ } from './models/sync.js';
13
18
  import { loadOpenRouterStatusBar } from './status-bar.js';
14
19
 
15
20
  let sessionState: SessionState | null = null;
@@ -90,8 +95,13 @@ export async function loadStartupCacheState(
90
95
  }
91
96
 
92
97
  try {
93
- const { configs } = await mapOpenRouterModels(cache.models);
94
- const configsWithRouters = includeBuiltinRouterModels(configs);
98
+ const filteredCacheModels = filterModelsForCatalogMode(cache.models, cache.catalogMode);
99
+ const { configs, skipped, skippedDetails } = await mapOpenRouterModels(filteredCacheModels);
100
+ const configsWithRouters = includeBuiltinRouterModels(configs, cache.catalogMode);
101
+ const effectiveSkippedDetails = cache.skippedDetails ?? skippedDetails;
102
+ const skippedCount =
103
+ effectiveSkippedDetails.length > 0 ? effectiveSkippedDetails.length : skipped;
104
+ const cacheAgeMs = getCacheAgeMs(cache);
95
105
 
96
106
  pi.registerProvider('openrouter', {
97
107
  baseUrl: 'https://openrouter.ai/api/v1',
@@ -101,9 +111,19 @@ export async function loadStartupCacheState(
101
111
  authHeader: true,
102
112
  });
103
113
 
114
+ setActiveCatalogState({
115
+ mode: cache.catalogMode,
116
+ registeredModelIds: configsWithRouters.map((config) => config.id),
117
+ registeredCount: configsWithRouters.length,
118
+ skippedCount,
119
+ skippedDetails: effectiveSkippedDetails,
120
+ source: 'cache',
121
+ cacheAgeMs,
122
+ });
123
+
104
124
  startupState.info = {
105
125
  count: configsWithRouters.length,
106
- age: formatDuration(getCacheAgeMs(cache)),
126
+ age: formatDuration(cacheAgeMs),
107
127
  };
108
128
  } catch (error) {
109
129
  startupState.warning = `OpenRouter: cached models found but failed to register: ${error instanceof Error ? error.message : String(error)}`;
@@ -45,11 +45,12 @@ describe('loadCache', () => {
45
45
  });
46
46
 
47
47
  it('should return parsed cache when file exists and is valid', async () => {
48
- const mockCache = createMockCache({ timestamp: 1234567890 });
48
+ const mockCache = createMockCache({ catalogMode: 'free-only', timestamp: 1234567890 });
49
49
  await saveCache(mockCache);
50
50
 
51
51
  const result = await loadCache();
52
52
  expect(result).not.toBeNull();
53
+ expect(result!.catalogMode).toBe('free-only');
53
54
  expect(result!.timestamp).toBe(1234567890);
54
55
  expect(result!.models).toHaveLength(1);
55
56
  expect(result!.models[0]!.id).toBe('test/model');
@@ -73,6 +74,23 @@ describe('loadCache', () => {
73
74
  expect(result).toBeNull();
74
75
  });
75
76
 
77
+ it('should normalize old cache files without catalogMode to full', async () => {
78
+ await mkdir(testCacheDir, { recursive: true });
79
+ const cacheFile = join(testCacheDir, 'models-cache.json');
80
+ const oldCache = createMockCache({ timestamp: 1234567890 });
81
+ const legacyCache = {
82
+ models: oldCache.models,
83
+ skippedDetails: oldCache.skippedDetails,
84
+ timestamp: oldCache.timestamp,
85
+ };
86
+
87
+ await writeFile(cacheFile, JSON.stringify(legacyCache));
88
+
89
+ const result = await loadCache();
90
+ expect(result).not.toBeNull();
91
+ expect(result!.catalogMode).toBe('full');
92
+ });
93
+
76
94
  it('should return null when cache timestamp is too far in the future', async () => {
77
95
  await mkdir(testCacheDir, { recursive: true });
78
96
  const cacheFile = join(testCacheDir, 'models-cache.json');
@@ -98,6 +116,7 @@ describe('saveCache', () => {
98
116
  // Verify it can be loaded back
99
117
  const loaded = await loadCache();
100
118
  expect(loaded).not.toBeNull();
119
+ expect(loaded!.catalogMode).toBe('full');
101
120
  expect(loaded!.timestamp).toBe(mockCache.timestamp);
102
121
  expect(loaded!.models).toEqual(mockCache.models);
103
122
  });