fix: sync dev branch with main timeline/schema changes and remove stale providers

Forward-port main's timeline epoch tracking, projected window selection,
and schema updates into dev. Remove aider/amp/gemini providers and
provider-history-compatibility layers that are no longer needed.
This commit is contained in:
Mohamed Boudra
2026-04-15 10:52:28 +07:00
parent 326dad93e4
commit 9d30b7e85a
42 changed files with 1251 additions and 2051 deletions
@@ -1,61 +0,0 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("@react-native-async-storage/async-storage", () => {
const storage = new Map<string, string>();
return {
default: {
getItem: vi.fn(async (key: string) => storage.get(key) ?? null),
setItem: vi.fn(async (key: string, value: string) => {
storage.set(key, value);
}),
removeItem: vi.fn(async (key: string) => {
storage.delete(key);
}),
},
};
});
import { AGENT_PROVIDER_DEFINITIONS } from "@server/server/agent/provider-manifest";
import {
__providerRecencyStoreTestUtils,
sortProvidersByRecency,
useProviderRecencyStore,
} from "./provider-recency-store";
describe("provider-recency-store", () => {
beforeEach(() => {
useProviderRecencyStore.setState({
recentProviderIds: [],
recordUsage: useProviderRecencyStore.getState().recordUsage,
});
});
it("sorts used providers first and keeps unused providers in default order", () => {
const sorted = sortProvidersByRecency(AGENT_PROVIDER_DEFINITIONS, ["codex"]);
expect(sorted.map((provider) => provider.id)).toEqual([
"codex",
...AGENT_PROVIDER_DEFINITIONS.filter((provider) => provider.id !== "codex").map(
(provider) => provider.id,
),
]);
});
it("moves the latest provider to the front without duplicating prior entries", () => {
useProviderRecencyStore.getState().recordUsage("codex");
useProviderRecencyStore.getState().recordUsage("opencode");
useProviderRecencyStore.getState().recordUsage("codex");
expect(useProviderRecencyStore.getState().recentProviderIds).toEqual(["codex", "opencode"]);
});
it("filters invalid and duplicate providers during migration", () => {
expect(
__providerRecencyStoreTestUtils.migratePersistedState({
recentProviderIds: ["codex", "invalid", "codex", "claude"],
}),
).toEqual({
recentProviderIds: ["codex", "claude"],
});
});
});
@@ -1,131 +0,0 @@
import { useMemo } from "react";
import AsyncStorage from "@react-native-async-storage/async-storage";
import type { AgentProvider } from "@server/server/agent/agent-sdk-types";
import {
AGENT_PROVIDER_DEFINITIONS,
isValidAgentProvider,
type AgentProviderDefinition,
} from "@server/server/agent/provider-manifest";
import { create } from "zustand";
import { createJSONStorage, persist } from "zustand/middleware";
const PROVIDER_RECENCY_STORE_VERSION = 1;
interface ProviderRecencyStoreState {
recentProviderIds: AgentProvider[];
recordUsage: (providerId: AgentProvider) => void;
}
function sanitizeRecentProviderIds(providerIds: readonly string[] | undefined): AgentProvider[] {
if (!providerIds || providerIds.length === 0) {
return [];
}
const seen = new Set<AgentProvider>();
const sanitized: AgentProvider[] = [];
for (const providerId of providerIds) {
if (!isValidAgentProvider(providerId)) {
continue;
}
if (seen.has(providerId)) {
continue;
}
seen.add(providerId);
sanitized.push(providerId);
}
return sanitized;
}
export function sortProvidersByRecency<T extends { id: string }>(
providers: readonly T[],
recentProviderIds: readonly string[],
): T[] {
if (providers.length <= 1) {
return [...providers];
}
const recentRank = new Map<string, number>();
for (const providerId of recentProviderIds) {
if (recentRank.has(providerId)) {
continue;
}
recentRank.set(providerId, recentRank.size);
}
return providers
.map((provider, defaultIndex) => ({
provider,
defaultIndex,
recentIndex: recentRank.get(provider.id) ?? Number.POSITIVE_INFINITY,
}))
.sort((left, right) => {
if (left.recentIndex !== right.recentIndex) {
return left.recentIndex - right.recentIndex;
}
return left.defaultIndex - right.defaultIndex;
})
.map((entry) => entry.provider);
}
function migratePersistedState(
state: unknown,
): Pick<ProviderRecencyStoreState, "recentProviderIds"> {
const record = state as { recentProviderIds?: string[] } | null | undefined;
return {
recentProviderIds: sanitizeRecentProviderIds(record?.recentProviderIds),
};
}
export const useProviderRecencyStore = create<ProviderRecencyStoreState>()(
persist(
(set) => ({
recentProviderIds: [],
recordUsage: (providerId) => {
if (!isValidAgentProvider(providerId)) {
return;
}
set((state) => ({
recentProviderIds: [
providerId,
...state.recentProviderIds.filter((id) => id !== providerId),
],
}));
},
}),
{
name: "agent-provider-recency",
version: PROVIDER_RECENCY_STORE_VERSION,
storage: createJSONStorage(() => AsyncStorage),
partialize: (state) => ({
recentProviderIds: state.recentProviderIds,
}),
migrate: (persistedState) => migratePersistedState(persistedState),
},
),
);
export function useProviderRecency(
availableProviders: readonly AgentProviderDefinition[] = AGENT_PROVIDER_DEFINITIONS,
): {
providers: AgentProviderDefinition[];
recordUsage: (providerId: AgentProvider) => void;
} {
const recentProviderIds = useProviderRecencyStore((state) => state.recentProviderIds);
const recordUsage = useProviderRecencyStore((state) => state.recordUsage);
const providers = useMemo(
() => sortProvidersByRecency(availableProviders, recentProviderIds),
[availableProviders, recentProviderIds],
);
return {
providers,
recordUsage,
};
}
export const __providerRecencyStoreTestUtils = {
migratePersistedState,
sanitizeRecentProviderIds,
};
+1
View File
@@ -212,6 +212,7 @@ export type DaemonServerInfo = {
};
export interface AgentTimelineCursorState {
epoch: string;
startSeq: number;
endSeq: number;
}