Skip to content
Open
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
2 changes: 0 additions & 2 deletions src/features/agents/components/AgentInspectPanels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,6 @@ export const AgentSettingsPanel = ({
onUpdateAgentPermissions = () => {},
onDelete,
canDelete = true,
onToolCallingToggle,
onThinkingTracesToggle,
cronJobs,
cronLoading,
cronError,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export type UseAgentSettingsMutationControllerParams = {
};

export function useAgentSettingsMutationController(params: UseAgentSettingsMutationControllerParams) {
const { agents, loadAgents, setMobilePaneChat, status } = params;
const skillsLoadRequestIdRef = useRef(0);
const [settingsSkillsReport, setSettingsSkillsReport] = useState<SkillStatusReport | null>(null);
const [settingsSkillsLoading, setSettingsSkillsLoading] = useState(false);
Expand Down Expand Up @@ -384,21 +385,21 @@ export function useAgentSettingsMutationController(params: UseAgentSettingsMutat
if (!restartingMutationBlock) return;
if (restartingMutationBlock.kind !== "delete-agent") return;
if (restartingMutationBlock.phase !== "awaiting-restart") return;
if (params.status !== "connected") return;
if (status !== "connected") return;

const deletedAgentStillPresent = params.agents.some(
const deletedAgentStillPresent = agents.some(
(entry) => entry.agentId === restartingMutationBlock.agentId
);
if (!deletedAgentStillPresent) {
setRestartingMutationBlock(null);
params.setMobilePaneChat();
setMobilePaneChat();
return;
}

let cancelled = false;
const refreshAgents = async () => {
try {
await params.loadAgents();
await loadAgents();
} catch (error) {
if (!isGatewayDisconnectLikeError(error)) {
console.error("Failed to refresh agents while awaiting delete restart.", error);
Expand All @@ -417,10 +418,10 @@ export function useAgentSettingsMutationController(params: UseAgentSettingsMutat
window.clearInterval(intervalId);
};
}, [
params.agents,
params.loadAgents,
params.setMobilePaneChat,
params.status,
agents,
loadAgents,
setMobilePaneChat,
status,
restartingMutationBlock,
]);

Expand Down
104 changes: 49 additions & 55 deletions src/features/agents/operations/useGatewayConfigSyncController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,46 +45,54 @@ export type GatewayConfigSyncController = {
export function useGatewayConfigSyncController(
params: UseGatewayConfigSyncControllerParams
): GatewayConfigSyncController {
const {
client,
status,
settingsRouteActive,
inspectSidebarAgentId,
gatewayConfigSnapshot,
setGatewayConfigSnapshot,
setGatewayModels,
setGatewayModelsError,
enqueueConfigMutation,
loadAgents,
isDisconnectLikeError,
logError: logErrorOverride,
} = params;
const sandboxRepairAttemptedRef = useRef(false);

const logError = params.logError ?? defaultLogError;
const logError = logErrorOverride ?? defaultLogError;

const refreshGatewayConfigSnapshot = useCallback(async () => {
if (params.status !== "connected") return null;
if (status !== "connected") return null;
try {
const snapshot = await params.client.call<GatewayModelPolicySnapshot>("config.get", {});
params.setGatewayConfigSnapshot(snapshot);
const snapshot = await client.call<GatewayModelPolicySnapshot>("config.get", {});
setGatewayConfigSnapshot(snapshot);
return snapshot;
} catch (err) {
if (!params.isDisconnectLikeError(err)) {
if (!isDisconnectLikeError(err)) {
logError("Failed to refresh gateway config.", err);
}
return null;
}
}, [
params.client,
params.isDisconnectLikeError,
params.setGatewayConfigSnapshot,
params.status,
logError,
]);
}, [client, isDisconnectLikeError, setGatewayConfigSnapshot, status, logError]);

useEffect(() => {
const repairIntent = resolveSandboxRepairIntent({
status: params.status,
status,
attempted: sandboxRepairAttemptedRef.current,
snapshot: params.gatewayConfigSnapshot,
snapshot: gatewayConfigSnapshot,
});
if (repairIntent.kind !== "repair") return;

sandboxRepairAttemptedRef.current = true;
void params.enqueueConfigMutation({
void enqueueConfigMutation({
kind: "repair-sandbox-tool-allowlist",
label: "Repair sandbox tool access",
run: async () => {
for (const agentId of repairIntent.agentIds) {
await updateGatewayAgentOverrides({
client: params.client,
client,
agentId,
overrides: {
tools: {
Expand All @@ -97,73 +105,59 @@ export function useGatewayConfigSyncController(
},
});
}
await params.loadAgents();
await loadAgents();
},
});
}, [
params.client,
params.enqueueConfigMutation,
params.gatewayConfigSnapshot,
params.loadAgents,
params.status,
]);
}, [client, enqueueConfigMutation, gatewayConfigSnapshot, loadAgents, status]);

useEffect(() => {
if (
!shouldRefreshGatewayConfigForSettingsRoute({
status: params.status,
settingsRouteActive: params.settingsRouteActive,
inspectSidebarAgentId: params.inspectSidebarAgentId,
status,
settingsRouteActive,
inspectSidebarAgentId,
})
) {
return;
}
void refreshGatewayConfigSnapshot();
}, [
params.inspectSidebarAgentId,
params.settingsRouteActive,
params.status,
refreshGatewayConfigSnapshot,
]);
}, [inspectSidebarAgentId, settingsRouteActive, status, refreshGatewayConfigSnapshot]);

useEffect(() => {
const syncIntent = resolveGatewayModelsSyncIntent({ status: params.status });
const syncIntent = resolveGatewayModelsSyncIntent({ status });
if (syncIntent.kind === "clear") {
params.setGatewayModels([]);
params.setGatewayModelsError(null);
params.setGatewayConfigSnapshot(null);
setGatewayModels([]);
setGatewayModelsError(null);
setGatewayConfigSnapshot(null);
return;
}

let cancelled = false;
const loadModels = async () => {
let configSnapshot: GatewayModelPolicySnapshot | null = null;
try {
configSnapshot = await params.client.call<GatewayModelPolicySnapshot>("config.get", {});
configSnapshot = await client.call<GatewayModelPolicySnapshot>("config.get", {});
if (!cancelled) {
params.setGatewayConfigSnapshot(configSnapshot);
setGatewayConfigSnapshot(configSnapshot);
}
} catch (err) {
if (!params.isDisconnectLikeError(err)) {
if (!isDisconnectLikeError(err)) {
logError("Failed to load gateway config.", err);
}
}

try {
const result = await params.client.call<{ models: GatewayModelChoice[] }>(
"models.list",
{}
);
const result = await client.call<{ models: GatewayModelChoice[] }>("models.list", {});
if (cancelled) return;
const catalog = Array.isArray(result.models) ? result.models : [];
params.setGatewayModels(buildGatewayModelChoices(catalog, configSnapshot));
params.setGatewayModelsError(null);
setGatewayModels(buildGatewayModelChoices(catalog, configSnapshot));
setGatewayModelsError(null);
} catch (err) {
if (cancelled) return;
const message = err instanceof Error ? err.message : "Failed to load models.";
params.setGatewayModelsError(message);
params.setGatewayModels([]);
if (!params.isDisconnectLikeError(err)) {
setGatewayModelsError(message);
setGatewayModels([]);
if (!isDisconnectLikeError(err)) {
logError("Failed to load gateway models.", err);
}
}
Expand All @@ -174,12 +168,12 @@ export function useGatewayConfigSyncController(
cancelled = true;
};
}, [
params.client,
params.isDisconnectLikeError,
params.setGatewayConfigSnapshot,
params.setGatewayModels,
params.setGatewayModelsError,
params.status,
client,
isDisconnectLikeError,
setGatewayConfigSnapshot,
setGatewayModels,
setGatewayModelsError,
status,
logError,
]);

Expand Down
Loading