Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
commitModelPlaneFromCatalog,
getActiveCatalog,
getActiveCatalogRevision,
getLocalCatalogOverridesSnapshot,
setLocalCatalogOverrides,
setActiveCatalog,
setActiveCatalogChangedListener,
setAnthropicDiscoveredModels,
Expand Down Expand Up @@ -229,3 +231,25 @@ describe('active catalog revision', () => {
);
});
});


it('applies a new publication to defaults while preserving personal model overrides and Pi membership', () => {
const original = getLocalCatalogOverridesSnapshot();
const catalog = structuredClone(BUNDLED_CATALOG);
catalog.version = 'catalog-123'; catalog.modelRegistry!.schemaVersion = 5;
const entry = catalog.modelRegistry!.models.find((model) => model.id === 'openai/gpt-5.6-sol')!;
entry.productDefaults = { contextWindow: 240000, effort: 'low', fast: false, preferredAgent: 'codex' };
const piIds = catalog.providers.find((provider) => provider.id === 'openai')?.models.pi?.map((model) => model.id);
const read = () => getActiveCatalog().providers.find((provider) => provider.id === 'openai')!.models.codex!.find((model) => model.id === 'gpt-5.6-sol')!;
try {
setLocalCatalogOverrides({ ...original, patches: {}, additions: {} });
setActiveCatalog(catalog);
expect(read()).toMatchObject({ contextWindow: 240000, defaultEffort: 'low', defaultFast: false, catalogDefaults: { revision: 'catalog-123' } });
expect(read().contextWindowMax).toBeGreaterThan(240000);
setLocalCatalogOverrides({ ...original, patches: { 'openai:gpt-5.6-sol': { base: { contextWindow: 500000, defaultEffort: 'high' } } }, additions: {} });
entry.productDefaults = { contextWindow: 220000, effort: 'medium' };
catalog.version = 'catalog-124'; setActiveCatalog(catalog);
expect(read()).toMatchObject({ contextWindow: 500000, defaultEffort: 'high', catalogDefaults: { revision: 'catalog-124' } });
expect(getActiveCatalog().providers.find((provider) => provider.id === 'openai')?.models.pi?.map((model) => model.id)).toEqual(piIds);
} finally { setLocalCatalogOverrides(original); setActiveCatalog(BUNDLED_CATALOG); }
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { ModelMemoryResetRequests } from '../model-memory-reset.js';

describe('persisted model memory reset acknowledgement', () => {
afterEach(() => vi.useRealTimers());
it('correlates independent requests and rejects an unconfirmed write', async () => {
vi.useFakeTimers();
const requests = new ModelMemoryResetRequests();
const ids: string[] = [];
const first = requests.request((id) => ids.push(id));
const second = requests.request((id) => ids.push(id));
const rejected = expect(second).rejects.toThrow('MODEL_MEMORY_RESET_NOT_CONFIRMED');
requests.acknowledge('unrelated');
requests.acknowledge(ids[0]);
await expect(first).resolves.toEqual({ resetApplied: true });
await vi.advanceTimersByTimeAsync(5000);
await rejected;
requests.acknowledge(ids[1]);
});
});


it('rejects a stale acknowledgement after the account boundary changes', async () => {
const requests = new ModelMemoryResetRequests();
let owner = 'a'; let requestId = '';
const pending = requests.request((id) => { requestId = id; }, () => owner === 'a');
owner = 'b';
const failure = expect(pending).rejects.toThrow('OWNER_CHANGED');
expect(requests.acknowledge(requestId)).toBe(false);
await failure;
});
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,80 @@ it('public model defaults supersede stale static Pi effort ladders', () => {
});
}
});


it.each([false, true])('V5 publication refresh preserves account overrides through the Claude bridge (form=%s)', (explicitForm) => {
const catalog = structuredClone(BUNDLED_CATALOG);
catalog.modelRegistry!.schemaVersion = 5;
const model = catalog.modelRegistry!.models.find(m => m.id === 'openai/gpt-5.6-luna')!;
const configured = account();
if (explicitForm) {
configured.models.codex![0]!.userModelConfig = {
...configured.models.codex![0]!.userModelConfig!, contextWindow: 500000, reasoningDefaultEffort: 'high', defaultEnabled: true,
};
} else {
setLocalCatalogOverrides(sanitizeModelCatalogOverrides({ patches: {
[`${accountId}:gpt-5.6-luna`]: { base: { contextWindow: 500000, defaultEffort: 'high' } },
} }).overrides);
}
setCustomProviders([configured]);
for (const contextWindow of [240000, 300000]) {
model.productDefaults = { contextWindow, effort: 'low', fast: false, visible: false };
catalog.version = `published-${contextWindow}`;
setActiveCatalog(structuredClone(catalog));
for (const agent of ['codex', 'claude-code'] as const) {
const id = agent === 'codex' ? 'gpt-5.6-luna' : 'chatgpt/gpt-5.6-luna';
expect(entry('openai', agent, id)).toMatchObject({ contextWindow, defaultEffort: 'low', defaultFast: false });
expect(entry(accountId, agent, id)).toMatchObject({ contextWindow: 500000, defaultEffort: 'high',
defaultFast: false, defaultEnabled: explicitForm, catalogDefaults: { revision: catalog.version, contextWindow } });
expect(entry(accountId, agent, id).fieldSources?.contextWindow?.at(-1)?.source).toBe('user');
expect(entry(accountId, agent, id).fieldSources?.defaultEffort?.at(-1)?.source).toBe('user');
}
}
});

it.each([
['openai', 'codex', 'gpt-5.6-luna'],
['anthropic', 'claude', 'claude-sonnet-4-6'],
['xai', 'xai', 'xai/grok-4.3'],
] as const)('V5 public product defaults reach both %s connections without changing identity or Pi membership', (brand, native, modelId) => {
const catalog = structuredClone(BUNDLED_CATALOG);
catalog.version = 'multi-account-publication';
catalog.modelRegistry!.schemaVersion = 5;
const model = catalog.modelRegistry!.models.find(m => m.routes.some(r => r.providerId === brand && r.modelId === modelId))!;
expect(model).toBeDefined();
model.productDefaults = { contextWindow: 100000, effort: 'low', fast: false, visible: false };
const configured = buildUserProvider({ id: `${brand}-published`, name: 'Personal',
auth: { method: 'oauth', native }, runtimes: {} });
setCustomProviders([configured]);
setActiveCatalog(catalog, { authorityCatalog: catalog });
const selected = getActiveCatalog().providers.find(p => p.id === configured.id)!;
const builtin = getActiveCatalog().providers.find(p => p.id === brand)!;
const agent = brand === 'anthropic' ? 'claude-code' : 'codex';
for (const provider of [builtin, selected]) {
expect(provider.models[agent]!.find(m => m.id === modelId)).toMatchObject({ contextWindow: 100000,
defaultFast: false, defaultEnabled: false, catalogDefaults: { revision: catalog.version } });
}
expect(selected.models.pi?.map(m => m.id)).toEqual(builtin.models.pi?.map(m => m.id));
expect(selected.id).toBe(`${brand}-published`);
expect(selected.auth).toEqual({ method: 'oauth', native });
});


it('V5 defaults cannot revive retired models or re-enable Fast on a constrained bridge', () => {
const catalog = structuredClone(BUNDLED_CATALOG);
catalog.modelRegistry!.schemaVersion = 5;
const retired = catalog.modelRegistry!.models.find(m => m.id === 'openai/gpt-5.6-luna')!;
retired.status = 'retired';
retired.productDefaults = { contextWindow: 100000, fast: true };
const claude = catalog.modelRegistry!.models.find(m => m.id === 'anthropic/claude-sonnet-4-6')!;
claude.productDefaults = { contextWindow: 100000, fast: true };
setLocalCatalogOverrides(sanitizeModelCatalogOverrides({ patches: {
'openai:gpt-5.6-luna': { base: { status: 'active' } },
'anthropic:claude-sonnet-4-6': { perAgent: { codex: { supportsFastMode: true } } },
} }).overrides);
setActiveCatalog(catalog);
setDiscoveredCodexModels([{ id: 'gpt-5.6-luna', name: 'Luna', contextWindow: 300000, efforts: ['low'], defaultEffort: 'low' }]);
expect(entry('openai', 'codex', 'gpt-5.6-luna').status).toBe('retired');
expect(entry('anthropic', 'codex', 'claude-sonnet-4-6')).toMatchObject({ supportsFastMode: false, defaultFast: false });
});
Original file line number Diff line number Diff line change
Expand Up @@ -693,9 +693,9 @@ describe('provider catalog realm reload', () => {

it('invalidates the old realm immediately and ignores a stale cross-realm response', async () => {
const initial = ensureActiveCatalogLoaded();
expect(h.loads[0]?.source).not.toHaveProperty('fallbackBaseUrl');
expect(h.loads[0]?.source).toMatchObject({
baseUrl: 'https://model.cn.example',
fallbackBaseUrl: 'https://legacy-build-cdn.example',
});
h.loads[0]!.resolve(catalogNamed('catalog-cn-initial'), 'current', ['embedding']);
await initial;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -438,3 +438,25 @@ describe('app focus auto-refresh tracker', () => {
expect(onMeaningfulForeground).not.toHaveBeenCalled();
});
});

it('polls only public configuration while active, at five minutes even after a recent UI hint', async () => {
vi.useFakeTimers();
try {
const { configureProviderModelAutoRefresh, requestProviderModelAutoRefresh, PUBLIC_MODEL_CATALOG_REFRESH_MS } = await import('../provider-model-auto-refresh.js');
let active = false;
const listProviders = vi.fn(async () => []), refreshCatalog = vi.fn(async () => undefined), refreshProvider = vi.fn(async () => undefined);
configureProviderModelAutoRefresh({listProviders,refreshCatalog,refreshProvider,isActive:() => active,log:{debug:vi.fn(),warn:vi.fn()}});
await vi.advanceTimersByTimeAsync(PUBLIC_MODEL_CATALOG_REFRESH_MS);
expect(refreshCatalog).not.toHaveBeenCalled();
active = true;
await vi.advanceTimersByTimeAsync(PUBLIC_MODEL_CATALOG_REFRESH_MS-1000);
await requestProviderModelAutoRefresh('model-selector-open');
expect(refreshCatalog).toHaveBeenCalledTimes(1);
await vi.advanceTimersByTimeAsync(1000);
expect(refreshCatalog).toHaveBeenCalledTimes(2);
await vi.advanceTimersByTimeAsync(PUBLIC_MODEL_CATALOG_REFRESH_MS);
expect(refreshCatalog).toHaveBeenCalledTimes(3);
expect(listProviders).toHaveBeenCalledTimes(1);
expect(refreshProvider).not.toHaveBeenCalled();
} finally { vi.clearAllTimers(); vi.useRealTimers(); }
});
Loading