perf: eliminate redundant agent fetches during startup (#1466)
This commit is contained in:
@@ -3159,9 +3159,15 @@ export default function App({
|
|||||||
|
|
||||||
const fetchConfig = async () => {
|
const fetchConfig = async () => {
|
||||||
try {
|
try {
|
||||||
|
// Use pre-loaded agent state if available, otherwise fetch
|
||||||
const { getClient } = await import("../agent/client");
|
const { getClient } = await import("../agent/client");
|
||||||
const client = await getClient();
|
const client = await getClient();
|
||||||
const agent = await client.agents.retrieve(agentId);
|
let agent: AgentState;
|
||||||
|
if (initialAgentState && initialAgentState.id === agentId) {
|
||||||
|
agent = initialAgentState;
|
||||||
|
} else {
|
||||||
|
agent = await client.agents.retrieve(agentId);
|
||||||
|
}
|
||||||
|
|
||||||
setAgentState(agent);
|
setAgentState(agent);
|
||||||
setLlmConfig(agent.llm_config);
|
setLlmConfig(agent.llm_config);
|
||||||
@@ -3307,7 +3313,7 @@ export default function App({
|
|||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [loadingState, agentId]);
|
}, [loadingState, agentId, initialAgentState]);
|
||||||
|
|
||||||
// Keep effective model state in sync with the active conversation override.
|
// Keep effective model state in sync with the active conversation override.
|
||||||
// biome-ignore lint/correctness/useExhaustiveDependencies: ref.current is intentionally read dynamically
|
// biome-ignore lint/correctness/useExhaustiveDependencies: ref.current is intentionally read dynamically
|
||||||
|
|||||||
94
src/index.ts
94
src/index.ts
@@ -267,7 +267,7 @@ function getModelForToolLoading(
|
|||||||
*/
|
*/
|
||||||
async function resolveAgentByName(
|
async function resolveAgentByName(
|
||||||
name: string,
|
name: string,
|
||||||
): Promise<{ id: string; name: string } | null> {
|
): Promise<{ id: string; name: string; agent: AgentState } | null> {
|
||||||
const client = await getClient();
|
const client = await getClient();
|
||||||
|
|
||||||
// Get all pinned agents (local first, then global, deduplicated)
|
// Get all pinned agents (local first, then global, deduplicated)
|
||||||
@@ -280,7 +280,7 @@ async function resolveAgentByName(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch names for all pinned agents and find matches
|
// Fetch names for all pinned agents and find matches
|
||||||
const matches: { id: string; name: string }[] = [];
|
const matches: { id: string; name: string; agent: AgentState }[] = [];
|
||||||
const normalizedSearchName = name.toLowerCase();
|
const normalizedSearchName = name.toLowerCase();
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@@ -288,7 +288,7 @@ async function resolveAgentByName(
|
|||||||
try {
|
try {
|
||||||
const agent = await client.agents.retrieve(id);
|
const agent = await client.agents.retrieve(id);
|
||||||
if (agent.name?.toLowerCase() === normalizedSearchName) {
|
if (agent.name?.toLowerCase() === normalizedSearchName) {
|
||||||
matches.push({ id, name: agent.name });
|
matches.push({ id, name: agent.name, agent });
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Agent not found or error, skip
|
// Agent not found or error, skip
|
||||||
@@ -731,6 +731,7 @@ async function main(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate --name flag
|
// Validate --name flag
|
||||||
|
let nameResolvedAgent: AgentState | null = null;
|
||||||
if (specifiedAgentName) {
|
if (specifiedAgentName) {
|
||||||
if (specifiedAgentId) {
|
if (specifiedAgentId) {
|
||||||
console.error("Error: --name cannot be used with --agent");
|
console.error("Error: --name cannot be used with --agent");
|
||||||
@@ -848,6 +849,7 @@ async function main(): Promise<void> {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
specifiedAgentId = resolved.id;
|
specifiedAgentId = resolved.id;
|
||||||
|
nameResolvedAgent = resolved.agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set tool filter if provided (controls which tools are loaded)
|
// Set tool filter if provided (controls which tools are loaded)
|
||||||
@@ -950,6 +952,7 @@ async function main(): Promise<void> {
|
|||||||
initBlocks,
|
initBlocks,
|
||||||
baseTools,
|
baseTools,
|
||||||
agentIdArg,
|
agentIdArg,
|
||||||
|
preResolvedAgent,
|
||||||
model,
|
model,
|
||||||
systemPromptPreset,
|
systemPromptPreset,
|
||||||
toolset,
|
toolset,
|
||||||
@@ -961,6 +964,7 @@ async function main(): Promise<void> {
|
|||||||
initBlocks?: string[];
|
initBlocks?: string[];
|
||||||
baseTools?: string[];
|
baseTools?: string[];
|
||||||
agentIdArg: string | null;
|
agentIdArg: string | null;
|
||||||
|
preResolvedAgent?: AgentState | null;
|
||||||
model?: string;
|
model?: string;
|
||||||
systemPromptPreset?: string;
|
systemPromptPreset?: string;
|
||||||
toolset?: "auto" | "codex" | "default" | "gemini";
|
toolset?: "auto" | "codex" | "default" | "gemini";
|
||||||
@@ -995,7 +999,7 @@ async function main(): Promise<void> {
|
|||||||
>(null);
|
>(null);
|
||||||
// Cache agent object from Phase 1 validation to avoid redundant re-fetch in Phase 2
|
// Cache agent object from Phase 1 validation to avoid redundant re-fetch in Phase 2
|
||||||
const [validatedAgent, setValidatedAgent] = useState<AgentState | null>(
|
const [validatedAgent, setValidatedAgent] = useState<AgentState | null>(
|
||||||
null,
|
preResolvedAgent ?? null,
|
||||||
);
|
);
|
||||||
// Track agent and conversation for conversation selector (--resume flag)
|
// Track agent and conversation for conversation selector (--resume flag)
|
||||||
const [resumeAgentId, setResumeAgentId] = useState<string | null>(null);
|
const [resumeAgentId, setResumeAgentId] = useState<string | null>(null);
|
||||||
@@ -1274,31 +1278,50 @@ async function main(): Promise<void> {
|
|||||||
// Step 1: Check local project LRU (session helpers centralize legacy fallback)
|
// Step 1: Check local project LRU (session helpers centralize legacy fallback)
|
||||||
// Cache the retrieved agent to avoid redundant re-fetch in init()
|
// Cache the retrieved agent to avoid redundant re-fetch in init()
|
||||||
const localAgentId = settingsManager.getLocalLastAgentId(process.cwd());
|
const localAgentId = settingsManager.getLocalLastAgentId(process.cwd());
|
||||||
|
const globalAgentId = settingsManager.getGlobalLastAgentId();
|
||||||
|
|
||||||
|
// Fetch local + global LRU agents in parallel
|
||||||
let localAgentExists = false;
|
let localAgentExists = false;
|
||||||
|
let globalAgentExists = false;
|
||||||
let cachedAgent: AgentState | null = null;
|
let cachedAgent: AgentState | null = null;
|
||||||
if (localAgentId) {
|
|
||||||
try {
|
if (globalAgentId && globalAgentId === localAgentId) {
|
||||||
cachedAgent = await client.agents.retrieve(localAgentId);
|
// Same agent — only need one fetch
|
||||||
|
if (localAgentId) {
|
||||||
|
try {
|
||||||
|
cachedAgent = await client.agents.retrieve(localAgentId);
|
||||||
|
localAgentExists = true;
|
||||||
|
} catch {
|
||||||
|
setFailedAgentMessage(
|
||||||
|
`Unable to locate recently used agent ${localAgentId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
globalAgentExists = localAgentExists;
|
||||||
|
} else {
|
||||||
|
// Different agents — fetch in parallel
|
||||||
|
const [localResult, globalResult] = await Promise.allSettled([
|
||||||
|
localAgentId
|
||||||
|
? client.agents.retrieve(localAgentId)
|
||||||
|
: Promise.reject(new Error("no local")),
|
||||||
|
globalAgentId
|
||||||
|
? client.agents.retrieve(globalAgentId)
|
||||||
|
: Promise.reject(new Error("no global")),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (localResult.status === "fulfilled") {
|
||||||
localAgentExists = true;
|
localAgentExists = true;
|
||||||
} catch {
|
cachedAgent = localResult.value;
|
||||||
|
} else if (localAgentId) {
|
||||||
setFailedAgentMessage(
|
setFailedAgentMessage(
|
||||||
`Unable to locate recently used agent ${localAgentId}`,
|
`Unable to locate recently used agent ${localAgentId}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2: Check global LRU (covers directory-switching case)
|
if (globalResult.status === "fulfilled") {
|
||||||
const globalAgentId = settingsManager.getGlobalLastAgentId();
|
|
||||||
let globalAgentExists = false;
|
|
||||||
if (globalAgentId && globalAgentId !== localAgentId) {
|
|
||||||
try {
|
|
||||||
cachedAgent = await client.agents.retrieve(globalAgentId);
|
|
||||||
globalAgentExists = true;
|
globalAgentExists = true;
|
||||||
} catch {
|
cachedAgent = globalResult.value;
|
||||||
// Global agent doesn't exist either
|
|
||||||
}
|
}
|
||||||
} else if (globalAgentId && globalAgentId === localAgentId) {
|
|
||||||
globalAgentExists = localAgentExists;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Resolve startup target using pure decision logic
|
// Step 3: Resolve startup target using pure decision logic
|
||||||
@@ -1379,11 +1402,17 @@ async function main(): Promise<void> {
|
|||||||
|
|
||||||
// Priority 1: --agent flag
|
// Priority 1: --agent flag
|
||||||
if (agentIdArg) {
|
if (agentIdArg) {
|
||||||
try {
|
// Use cached agent from name resolution if available
|
||||||
await client.agents.retrieve(agentIdArg);
|
if (validatedAgent && validatedAgent.id === agentIdArg) {
|
||||||
resumingAgentId = agentIdArg;
|
resumingAgentId = agentIdArg;
|
||||||
} catch {
|
} else {
|
||||||
// Agent doesn't exist, will create new later
|
try {
|
||||||
|
const agent = await client.agents.retrieve(agentIdArg);
|
||||||
|
setValidatedAgent(agent);
|
||||||
|
resumingAgentId = agentIdArg;
|
||||||
|
} catch {
|
||||||
|
// Agent doesn't exist, will create new later
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1396,13 +1425,19 @@ async function main(): Promise<void> {
|
|||||||
// This takes precedence over stale LRU since user explicitly chose it
|
// This takes precedence over stale LRU since user explicitly chose it
|
||||||
const shouldCreateNew = forceNew || userRequestedNewAgent;
|
const shouldCreateNew = forceNew || userRequestedNewAgent;
|
||||||
if (!resumingAgentId && !shouldCreateNew && selectedGlobalAgentId) {
|
if (!resumingAgentId && !shouldCreateNew && selectedGlobalAgentId) {
|
||||||
try {
|
// Use cached agent from Phase 1 validation if available
|
||||||
await client.agents.retrieve(selectedGlobalAgentId);
|
if (validatedAgent && validatedAgent.id === selectedGlobalAgentId) {
|
||||||
resumingAgentId = selectedGlobalAgentId;
|
resumingAgentId = selectedGlobalAgentId;
|
||||||
} catch {
|
} else {
|
||||||
// Selected agent doesn't exist - show selector again
|
try {
|
||||||
setLoadingState("selecting_global");
|
const agent = await client.agents.retrieve(selectedGlobalAgentId);
|
||||||
return;
|
setValidatedAgent(agent);
|
||||||
|
resumingAgentId = selectedGlobalAgentId;
|
||||||
|
} catch {
|
||||||
|
// Selected agent doesn't exist - show selector again
|
||||||
|
setLoadingState("selecting_global");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2032,6 +2067,7 @@ async function main(): Promise<void> {
|
|||||||
initBlocks: initBlocks,
|
initBlocks: initBlocks,
|
||||||
baseTools: baseTools,
|
baseTools: baseTools,
|
||||||
agentIdArg: specifiedAgentId,
|
agentIdArg: specifiedAgentId,
|
||||||
|
preResolvedAgent: nameResolvedAgent,
|
||||||
model: specifiedModel,
|
model: specifiedModel,
|
||||||
systemPromptPreset: systemPromptPreset,
|
systemPromptPreset: systemPromptPreset,
|
||||||
toolset: specifiedToolset as
|
toolset: specifiedToolset as
|
||||||
|
|||||||
Reference in New Issue
Block a user