mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-05-19 16:31:36 +00:00
Merge branch 'main' into feat/add-task-hover
This commit is contained in:
commit
ac83bdea88
4 changed files with 105 additions and 13 deletions
|
|
@ -89,6 +89,21 @@ app.commandLine.appendSwitch('max_old_space_size', '4096');
|
|||
app.commandLine.appendSwitch('enable-features', 'MemoryPressureReduction');
|
||||
app.commandLine.appendSwitch('renderer-process-limit', '8');
|
||||
|
||||
// ==================== protocol privileges ====================
|
||||
// Register custom protocol privileges before app ready
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{
|
||||
scheme: 'localfile',
|
||||
privileges: {
|
||||
standard: true,
|
||||
secure: true,
|
||||
supportFetchAPI: true,
|
||||
corsEnabled: false,
|
||||
bypassCSP: false,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
// ==================== app config ====================
|
||||
process.env.APP_ROOT = MAIN_DIST;
|
||||
process.env.VITE_PUBLIC = VITE_PUBLIC;
|
||||
|
|
@ -1577,12 +1592,24 @@ app.whenReady().then(async () => {
|
|||
});
|
||||
|
||||
// ==================== protocol handle ====================
|
||||
protocol.handle('localfile', async (request) => {
|
||||
// Register protocol handler for both default session and main window session
|
||||
const protocolHandler = async (request: Request) => {
|
||||
const url = decodeURIComponent(request.url.replace('localfile://', ''));
|
||||
const filePath = path.normalize(url);
|
||||
|
||||
log.info(`[PROTOCOL] Handling localfile request: ${request.url}`);
|
||||
log.info(`[PROTOCOL] Decoded path: ${filePath}`);
|
||||
|
||||
try {
|
||||
// Check if file exists
|
||||
const fileExists = await fsp.access(filePath).then(() => true).catch(() => false);
|
||||
if (!fileExists) {
|
||||
log.error(`[PROTOCOL] File not found: ${filePath}`);
|
||||
return new Response('File Not Found', { status: 404 });
|
||||
}
|
||||
|
||||
const data = await fsp.readFile(filePath);
|
||||
log.info(`[PROTOCOL] Successfully read file, size: ${data.length} bytes`);
|
||||
|
||||
// set correct Content-Type according to file extension
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
|
|
@ -1596,17 +1623,46 @@ app.whenReady().then(async () => {
|
|||
case '.htm':
|
||||
contentType = 'text/html';
|
||||
break;
|
||||
case '.png':
|
||||
contentType = 'image/png';
|
||||
break;
|
||||
case '.jpg':
|
||||
case '.jpeg':
|
||||
contentType = 'image/jpeg';
|
||||
break;
|
||||
case '.gif':
|
||||
contentType = 'image/gif';
|
||||
break;
|
||||
case '.svg':
|
||||
contentType = 'image/svg+xml';
|
||||
break;
|
||||
case '.webp':
|
||||
contentType = 'image/webp';
|
||||
break;
|
||||
}
|
||||
|
||||
log.info(`[PROTOCOL] Returning file with Content-Type: ${contentType}`);
|
||||
|
||||
return new Response(new Uint8Array(data), {
|
||||
headers: {
|
||||
'Content-Type': contentType,
|
||||
'Content-Length': data.length.toString(),
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
log.error(`[PROTOCOL] Error reading file: ${err}`);
|
||||
return new Response('Internal Server Error', { status: 500 });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Register on default session
|
||||
protocol.handle('localfile', protocolHandler);
|
||||
|
||||
// Also register on main window session
|
||||
const mainSession = session.fromPartition('persist:main_window');
|
||||
mainSession.protocol.handle('localfile', protocolHandler);
|
||||
|
||||
log.info('[PROTOCOL] Registered localfile protocol on both default and main_window sessions');
|
||||
|
||||
// ==================== initialize app ====================
|
||||
initializeApp();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.amplitude.com; worker-src 'self' blob:; child-src 'self' blob:;frame-src 'self' localfile: blob:;"
|
||||
content="script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.amplitude.com; worker-src 'self' blob:; child-src 'self' blob:;frame-src 'self' localfile: blob: data:;"
|
||||
/>
|
||||
<script src="https://cdn.amplitude.com/libs/analytics-browser-2.11.1-min.js.gz"></script><script src="https://cdn.amplitude.com/libs/plugin-session-replay-browser-1.8.0-min.js.gz"></script><script>window.amplitude.add(window.sessionReplay.plugin({sampleRate: 1}));window.amplitude.init('87ce6adbb14b24ffe1703d18bf405e40', {"autocapture":{"elementInteractions":true}});</script>
|
||||
<title>Eigent</title>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ const ToolSelect = forwardRef<
|
|||
const [integrations, setIntegrations] = useState<any[]>([]);
|
||||
const fetchIntegrationsData = (keyword?: string) => {
|
||||
proxyFetchGet("/api/config/info").then((res) => {
|
||||
if (res && typeof res === "object") {
|
||||
if (res && typeof res === "object" && !res.error) {
|
||||
const baseURL = getProxyBaseURL();
|
||||
|
||||
const list = Object.entries(res)
|
||||
|
|
@ -187,7 +187,13 @@ const ToolSelect = forwardRef<
|
|||
};
|
||||
});
|
||||
setIntegrations(list);
|
||||
} else {
|
||||
console.error("Failed to fetch integrations:", res);
|
||||
setIntegrations([]);
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error("Error fetching integrations:", error);
|
||||
setIntegrations([]);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -217,7 +223,16 @@ const ToolSelect = forwardRef<
|
|||
page: 1,
|
||||
size: 100,
|
||||
}).then((res) => {
|
||||
setAllMcpList(res.items);
|
||||
// Add defensive check for API errors
|
||||
if (res && res.items && Array.isArray(res.items)) {
|
||||
setAllMcpList(res.items);
|
||||
} else {
|
||||
console.error("Failed to fetch MCPs:", res);
|
||||
setAllMcpList([]);
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error("Error fetching MCPs:", error);
|
||||
setAllMcpList([]);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -228,7 +243,7 @@ const ToolSelect = forwardRef<
|
|||
if (Array.isArray(res)) {
|
||||
ids = res.map((item: any) => item.mcp_id);
|
||||
dataList = res;
|
||||
} else if (Array.isArray(res.items)) {
|
||||
} else if (res && Array.isArray(res.items)) {
|
||||
ids = res.items.map((item: any) => item.mcp_id);
|
||||
dataList = res.items;
|
||||
}
|
||||
|
|
@ -236,14 +251,22 @@ const ToolSelect = forwardRef<
|
|||
|
||||
const customMcpList = dataList.filter((item: any) => item.mcp_id === 0);
|
||||
setCustomMcpList(customMcpList);
|
||||
}).catch((error) => {
|
||||
console.error("Error fetching installed MCPs:", error);
|
||||
setInstalledIds([]);
|
||||
setCustomMcpList([]);
|
||||
});
|
||||
};
|
||||
|
||||
// only surface installed MCPs from the market list
|
||||
useEffect(() => {
|
||||
if (!installedIds.length) {
|
||||
// Add defensive check and fix logic: should filter when installedIds has items
|
||||
if (Array.isArray(allMcpList) && installedIds.length > 0) {
|
||||
const filtered = allMcpList.filter((item) => installedIds.includes(item.id));
|
||||
setMcpList(filtered);
|
||||
} else if (Array.isArray(allMcpList)) {
|
||||
// If no installed IDs, show empty list instead of all
|
||||
setMcpList([]);
|
||||
}
|
||||
}, [allMcpList, installedIds]);
|
||||
|
||||
|
|
|
|||
|
|
@ -183,7 +183,23 @@ export default function Folder({ data }: { data?: Agent }) {
|
|||
setLoading(true);
|
||||
console.log("file", JSON.parse(JSON.stringify(file)));
|
||||
|
||||
// all files call open-file interface, the backend handles download and parsing
|
||||
// For PDF files, use data URL instead of custom protocol
|
||||
if (file.type === "pdf") {
|
||||
window.ipcRenderer
|
||||
.invoke("read-file-dataurl", file.path)
|
||||
.then((dataUrl: string) => {
|
||||
setSelectedFile({ ...file, content: dataUrl });
|
||||
chatStore.setSelectedFile(chatStore.activeTaskId as string, file);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("read-file-dataurl error:", error);
|
||||
setLoading(false);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// all other files call open-file interface, the backend handles download and parsing
|
||||
window.ipcRenderer
|
||||
.invoke("open-file", file.type, file.path, isShowSourceCode)
|
||||
.then((res) => {
|
||||
|
|
@ -539,10 +555,7 @@ export default function Folder({ data }: { data?: Agent }) {
|
|||
</div>
|
||||
) : selectedFile.type === "pdf" ? (
|
||||
<iframe
|
||||
src={
|
||||
"localfile://" +
|
||||
encodeURIComponent(selectedFile.content as string)
|
||||
}
|
||||
src={selectedFile.content as string}
|
||||
className="w-full h-full border-0"
|
||||
title={selectedFile.name}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue