mirror of
https://github.com/getcompanion-ai/alpha-hub.git
synced 2026-04-15 05:02:06 +00:00
Harden alphaXiv transport retries and logging
This commit is contained in:
parent
270eaa1dc5
commit
f6469556f0
1 changed files with 83 additions and 29 deletions
|
|
@ -6,6 +6,43 @@ const ALPHAXIV_MCP_URL = 'https://api.alphaxiv.org/mcp/v1';
|
||||||
|
|
||||||
let _client = null;
|
let _client = null;
|
||||||
let _connected = false;
|
let _connected = false;
|
||||||
|
let _lastTransportLog = { message: '', time: 0 };
|
||||||
|
|
||||||
|
function getErrorMessage(err) {
|
||||||
|
if (!err) return 'Unknown error';
|
||||||
|
if (typeof err === 'string') return err;
|
||||||
|
if (err instanceof Error) return err.message || String(err);
|
||||||
|
return String(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTransientTransportError(err) {
|
||||||
|
const message = getErrorMessage(err);
|
||||||
|
return (
|
||||||
|
message.includes('SSE stream disconnected') ||
|
||||||
|
message.includes('Failed to open SSE stream') ||
|
||||||
|
message.includes('Failed to reconnect SSE stream') ||
|
||||||
|
message.includes('Maximum reconnection attempts') ||
|
||||||
|
message.includes('Bad Gateway') ||
|
||||||
|
message.includes('TypeError: terminated') ||
|
||||||
|
message.includes('terminated')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function logTransportError(err) {
|
||||||
|
const message = getErrorMessage(err);
|
||||||
|
|
||||||
|
if (isTransientTransportError(message)) {
|
||||||
|
const now = Date.now();
|
||||||
|
if (_lastTransportLog.message === message && now - _lastTransportLog.time < 10000) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_lastTransportLog = { message, time: now };
|
||||||
|
process.stderr.write(`[alpha] alphaXiv MCP transient transport issue: ${message}\n`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.stderr.write(`[alpha] alphaXiv MCP error: ${message}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
async function getClient() {
|
async function getClient() {
|
||||||
if (_client && _connected) return _client;
|
if (_client && _connected) return _client;
|
||||||
|
|
@ -18,7 +55,10 @@ async function getClient() {
|
||||||
_client = new Client({ name: 'alpha', version: '0.1.0' });
|
_client = new Client({ name: 'alpha', version: '0.1.0' });
|
||||||
|
|
||||||
_client.onerror = (err) => {
|
_client.onerror = (err) => {
|
||||||
process.stderr.write(`[alpha] alphaXiv MCP error: ${err.message || err}\n`);
|
if (isTransientTransportError(err)) {
|
||||||
|
_connected = false;
|
||||||
|
}
|
||||||
|
logTransportError(err);
|
||||||
};
|
};
|
||||||
|
|
||||||
const transport = new StreamableHTTPClientTransport(new URL(ALPHAXIV_MCP_URL), {
|
const transport = new StreamableHTTPClientTransport(new URL(ALPHAXIV_MCP_URL), {
|
||||||
|
|
@ -36,39 +76,53 @@ async function getClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function callTool(name, args) {
|
async function callTool(name, args) {
|
||||||
let client;
|
let lastError = null;
|
||||||
try {
|
|
||||||
client = await getClient();
|
for (let attempt = 0; attempt < 3; attempt++) {
|
||||||
} catch (err) {
|
let client;
|
||||||
if (err.message?.includes('401') || err.message?.includes('Unauthorized')) {
|
try {
|
||||||
const newToken = await refreshAccessToken();
|
client = await getClient();
|
||||||
if (newToken) {
|
} catch (err) {
|
||||||
_client = null;
|
if (err.message?.includes('401') || err.message?.includes('Unauthorized')) {
|
||||||
_connected = false;
|
const newToken = await refreshAccessToken();
|
||||||
client = await getClient();
|
if (newToken) {
|
||||||
|
_client = null;
|
||||||
|
_connected = false;
|
||||||
|
client = await getClient();
|
||||||
|
} else {
|
||||||
|
throw new Error('Session expired. Run `alpha login` to re-authenticate.');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Session expired. Run `alpha login` to re-authenticate.');
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
throw err;
|
|
||||||
|
try {
|
||||||
|
const result = await client.callTool({ name, arguments: args });
|
||||||
|
|
||||||
|
if (result.isError) {
|
||||||
|
const text = result.content?.[0]?.text || 'Unknown error';
|
||||||
|
throw new Error(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = result.content?.[0]?.text;
|
||||||
|
if (!text) return result.content;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JSON.parse(text);
|
||||||
|
} catch {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
lastError = err;
|
||||||
|
if (!isTransientTransportError(err) || attempt === 2) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
await disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await client.callTool({ name, arguments: args });
|
throw lastError ?? new Error('alphaXiv MCP call failed');
|
||||||
|
|
||||||
if (result.isError) {
|
|
||||||
const text = result.content?.[0]?.text || 'Unknown error';
|
|
||||||
throw new Error(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
const text = result.content?.[0]?.text;
|
|
||||||
if (!text) return result.content;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return JSON.parse(text);
|
|
||||||
} catch {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function searchByEmbedding(query) {
|
export async function searchByEmbedding(query) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue