mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-05-19 16:31:36 +00:00
Merge branch 'main' into remove_gpt-5-nano
This commit is contained in:
commit
78c3597eb5
5 changed files with 57 additions and 122 deletions
|
|
@ -260,11 +260,19 @@ async def uninstall_tool(tool: str):
|
|||
|
||||
elif tool == "google_calendar":
|
||||
try:
|
||||
# Clean up Google Calendar token directory
|
||||
token_dir = os.path.join(os.path.expanduser("~"), ".eigent", "tokens", "google_calendar")
|
||||
if os.path.exists(token_dir):
|
||||
shutil.rmtree(token_dir)
|
||||
logger.info(f"Removed Google Calendar token directory: {token_dir}")
|
||||
# Clean up Google Calendar token directories (user-scoped + legacy)
|
||||
token_dirs = set()
|
||||
try:
|
||||
token_dirs.add(os.path.dirname(GoogleCalendarToolkit._build_canonical_token_path()))
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to resolve canonical Google Calendar token path: {e}")
|
||||
|
||||
token_dirs.add(os.path.join(os.path.expanduser("~"), ".eigent", "tokens", "google_calendar"))
|
||||
|
||||
for token_dir in token_dirs:
|
||||
if os.path.exists(token_dir):
|
||||
shutil.rmtree(token_dir)
|
||||
logger.info(f"Removed Google Calendar token directory: {token_dir}")
|
||||
|
||||
# Clear OAuth state manager cache (this is the key fix!)
|
||||
# This removes the cached credentials from memory
|
||||
|
|
|
|||
|
|
@ -21,18 +21,26 @@ class GoogleCalendarToolkit(BaseGoogleCalendarToolkit, AbstractToolkit):
|
|||
|
||||
def __init__(self, api_task_id: str, timeout: float | None = None):
|
||||
self.api_task_id = api_task_id
|
||||
self._token_path = (
|
||||
env("GOOGLE_CALENDAR_TOKEN_PATH")
|
||||
or os.path.join(
|
||||
os.path.expanduser("~"),
|
||||
".eigent",
|
||||
"tokens",
|
||||
"google_calendar",
|
||||
f"google_calendar_token_{api_task_id}.json",
|
||||
)
|
||||
# Use a stable token file (no per-task suffix). Can be overridden by env.
|
||||
self._token_path = env("GOOGLE_CALENDAR_TOKEN_PATH") or os.path.join(
|
||||
os.path.expanduser("~"),
|
||||
".eigent",
|
||||
"tokens",
|
||||
"google_calendar",
|
||||
"google_calendar_token.json",
|
||||
)
|
||||
super().__init__(timeout)
|
||||
|
||||
@classmethod
|
||||
def _build_canonical_token_path(cls) -> str:
|
||||
return env("GOOGLE_CALENDAR_TOKEN_PATH") or os.path.join(
|
||||
os.path.expanduser("~"),
|
||||
".eigent",
|
||||
"tokens",
|
||||
"google_calendar",
|
||||
"google_calendar_token.json",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_can_use_tools(cls, api_task_id: str):
|
||||
from dotenv import load_dotenv
|
||||
|
|
@ -77,12 +85,19 @@ class GoogleCalendarToolkit(BaseGoogleCalendarToolkit, AbstractToolkit):
|
|||
|
||||
creds = None
|
||||
|
||||
# First, try to load from token file
|
||||
# First, try to load from token file (canonical then legacy install_auth)
|
||||
try:
|
||||
if os.path.exists(self._token_path):
|
||||
logger.info(f"Loading credentials from token file: {self._token_path}")
|
||||
creds = Credentials.from_authorized_user_file(self._token_path, SCOPES)
|
||||
logger.info("Successfully loaded credentials from token file")
|
||||
elif os.path.exists(self._token_path.replace("google_calendar_token.json", "google_calendar_token_install_auth.json")):
|
||||
legacy_path = self._token_path.replace(
|
||||
"google_calendar_token.json", "google_calendar_token_install_auth.json"
|
||||
)
|
||||
logger.info(f"Loading credentials from legacy token file: {legacy_path}")
|
||||
creds = Credentials.from_authorized_user_file(legacy_path, SCOPES)
|
||||
logger.info("Successfully loaded credentials from legacy token file")
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not load from token file: {e}")
|
||||
creds = None
|
||||
|
|
@ -231,12 +246,12 @@ class GoogleCalendarToolkit(BaseGoogleCalendarToolkit, AbstractToolkit):
|
|||
return
|
||||
|
||||
# Save credentials to token file
|
||||
token_path = os.path.join(
|
||||
token_path = env("GOOGLE_CALENDAR_TOKEN_PATH") or os.path.join(
|
||||
os.path.expanduser("~"),
|
||||
".eigent",
|
||||
"tokens",
|
||||
"google_calendar",
|
||||
f"google_calendar_token_{api_task_id}.json",
|
||||
"google_calendar_token.json",
|
||||
)
|
||||
|
||||
try:
|
||||
|
|
@ -269,4 +284,4 @@ class GoogleCalendarToolkit(BaseGoogleCalendarToolkit, AbstractToolkit):
|
|||
thread.start()
|
||||
|
||||
logger.info("Started background Google Calendar authorization")
|
||||
return "authorizing"
|
||||
return "authorizing"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import * as net from "net";
|
|||
import * as http from "http";
|
||||
import { ipcMain, BrowserWindow, app } from 'electron'
|
||||
import { promisify } from 'util'
|
||||
import { detectInstallationLogs, PromiseReturnType } from "./install-deps";
|
||||
import { PromiseReturnType } from "./install-deps";
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
|
|
@ -171,8 +171,11 @@ export async function startBackend(setPort?: (port: number) => void): Promise<an
|
|||
const displayFilteredLogs = (data: String) => {
|
||||
if (!data) return;
|
||||
const msg = data.toString().trimEnd();
|
||||
//Detect if uv sync is run
|
||||
detectInstallationLogs(msg);
|
||||
|
||||
// REMOVED: detectInstallationLogs(msg)
|
||||
// Reason: Removed keyword-based detection to avoid false positives when backend
|
||||
// outputs logs containing keywords like "Installing", "Updating", "Syncing" etc.
|
||||
// Installation is now only handled through the explicit installation flow.
|
||||
|
||||
if (msg.toLowerCase().includes("error") || msg.toLowerCase().includes("traceback")) {
|
||||
log.error(`BACKEND: ${msg}`);
|
||||
|
|
|
|||
|
|
@ -677,104 +677,4 @@ export async function installDependencies(version: string): Promise<PromiseRetur
|
|||
resolve({ message: "Both default and mirror install failed", success: false })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let dependencyInstallationDetected = false;
|
||||
let installationNotificationSent = false;
|
||||
export function detectInstallationLogs(msg:string) {
|
||||
// CRITICAL FIX: Use file system to check if installation is complete
|
||||
// Don't rely on module variables as they can be reset during hot reload
|
||||
|
||||
// Check if dependencies are already installed
|
||||
const isAlreadyInstalled = fs.existsSync(installedLockPath);
|
||||
|
||||
// If installed lock file exists, dependencies are already installed
|
||||
// Skip all detection to avoid false positives
|
||||
if (isAlreadyInstalled) {
|
||||
// Dependencies are already installed, skip detection entirely
|
||||
return;
|
||||
}
|
||||
|
||||
// Also skip if notification was already sent (in current session)
|
||||
if (installationNotificationSent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for UV dependency installation patterns
|
||||
const installPatterns = [
|
||||
"Resolved", // UV resolving dependencies
|
||||
"Downloaded", // UV downloading packages
|
||||
"Installing", // UV installing packages
|
||||
"Built", // UV building packages
|
||||
"Prepared", // UV preparing virtual environment
|
||||
"Syncing", // UV sync process
|
||||
"Creating virtualenv", // Virtual environment creation
|
||||
"Updating", // UV updating packages
|
||||
"× No solution found when resolving dependencies", // Dependency resolution issues
|
||||
"Audited" // UV auditing dependencies
|
||||
];
|
||||
|
||||
// Detect if UV is installing dependencies
|
||||
if (!dependencyInstallationDetected && installPatterns.some(pattern =>
|
||||
msg.includes(pattern) && !msg.includes("Uvicorn running on")
|
||||
)) {
|
||||
dependencyInstallationDetected = true;
|
||||
log.info('[BACKEND STARTUP] UV dependency installation detected during uvicorn startup');
|
||||
|
||||
// Create installing lock file to maintain consistency with install-deps.ts
|
||||
InstallLogs.setLockPath();
|
||||
log.info('[BACKEND STARTUP] Created uv_installing.lock file');
|
||||
|
||||
// Notify frontend that installation has started (only once)
|
||||
if (!installationNotificationSent) {
|
||||
installationNotificationSent = true;
|
||||
const notificationSent = safeMainWindowSend('install-dependencies-start');
|
||||
if (notificationSent) {
|
||||
log.info('[BACKEND STARTUP] Notified frontend of dependency installation start');
|
||||
} else {
|
||||
log.warn('[BACKEND STARTUP] Failed to notify frontend of dependency installation start');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send installation logs to frontend if installation was detected
|
||||
if (dependencyInstallationDetected && !msg.includes("Uvicorn running on")) {
|
||||
safeMainWindowSend('install-dependencies-log', {
|
||||
type: msg.toLowerCase().includes("error") || msg.toLowerCase().includes("traceback") ? 'stderr' : 'stdout',
|
||||
data: msg
|
||||
});
|
||||
}
|
||||
|
||||
// Check if installation is complete (uvicorn starts successfully)
|
||||
if (dependencyInstallationDetected && msg.includes("Uvicorn running on")) {
|
||||
log.info('[BACKEND STARTUP] UV dependency installation completed, uvicorn started successfully');
|
||||
|
||||
// Clean up installing lock and create installed lock
|
||||
InstallLogs.cleanLockPath();
|
||||
fs.writeFileSync(installedLockPath, '');
|
||||
log.info('[BACKEND STARTUP] Created uv_installed.lock file');
|
||||
|
||||
safeMainWindowSend('install-dependencies-complete', {
|
||||
success: true,
|
||||
message: 'Dependencies installed successfully during backend startup'
|
||||
});
|
||||
}
|
||||
|
||||
// Handle installation failures
|
||||
if (dependencyInstallationDetected && (
|
||||
msg.toLowerCase().includes("failed to resolve dependencies") ||
|
||||
msg.toLowerCase().includes("installation failed") ||
|
||||
msg.includes("× No solution found when resolving dependencies")
|
||||
)) {
|
||||
log.error('[BACKEND STARTUP] UV dependency installation failed');
|
||||
|
||||
// Clean up installing lock file
|
||||
InstallLogs.cleanLockPath();
|
||||
log.info('[BACKEND STARTUP] Cleaned up uv_installing.lock file after failure');
|
||||
|
||||
safeMainWindowSend('install-dependencies-complete', {
|
||||
success: false,
|
||||
error: 'Dependency installation failed during backend startup'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -45,6 +45,7 @@ const ToolSelect = forwardRef<
|
|||
// state management - remove internal selected state, use parent passed initialSelectedTools
|
||||
const [keyword, setKeyword] = useState<string>("");
|
||||
const [mcpList, setMcpList] = useState<McpItem[]>([]);
|
||||
const [allMcpList, setAllMcpList] = useState<McpItem[]>([]);
|
||||
const [customMcpList, setCustomMcpList] = useState<any[]>([]);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [installed, setInstalled] = useState<{ [id: number]: boolean }>({});
|
||||
|
|
@ -216,7 +217,7 @@ const ToolSelect = forwardRef<
|
|||
page: 1,
|
||||
size: 100,
|
||||
}).then((res) => {
|
||||
setMcpList(res.items);
|
||||
setAllMcpList(res.items);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -238,6 +239,14 @@ const ToolSelect = forwardRef<
|
|||
});
|
||||
};
|
||||
|
||||
// only surface installed MCPs from the market list
|
||||
useEffect(() => {
|
||||
if (!installedIds.length) {
|
||||
const filtered = allMcpList.filter((item) => installedIds.includes(item.id));
|
||||
setMcpList(filtered);
|
||||
}
|
||||
}, [allMcpList, installedIds]);
|
||||
|
||||
// public save env/config logic
|
||||
const saveEnvAndConfig = async (
|
||||
provider: string,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue