Rename the persistent agent integration to Sybil Agent
Use SYBIL_AGENT_BASE_URL and SYBIL_AGENT_API_KEY with the renamed sybil-agent service. Update errors, API documentation, and test fixtures while retaining the existing room protocol and browser storage keys for compatibility. Validation: 44 server tests, 51 web tests, and both production builds.
This commit is contained in:
+12
-12
@@ -30,22 +30,22 @@ async function readState() {
|
||||
return { cursor: value?.cursor || '0', updatedAt: value?.updatedAt.toISOString() || null };
|
||||
}
|
||||
|
||||
/** Pi owns the conversation; Sybil stores only its shared personal read cursor. */
|
||||
/** Sybil Agent owns the conversation; the chat server stores only its shared read cursor. */
|
||||
export async function registerAgentRoutes(app: FastifyInstance, options: AgentOptions = {}) {
|
||||
const baseUrl = options.baseUrl || env.PI_AGENT_BASE_URL;
|
||||
const apiKey = options.apiKey ?? env.PI_AGENT_API_KEY;
|
||||
const baseUrl = options.baseUrl || env.SYBIL_AGENT_BASE_URL;
|
||||
const apiKey = options.apiKey ?? env.SYBIL_AGENT_API_KEY;
|
||||
const proxyJson = async (path: string, method = 'GET', body?: unknown) => {
|
||||
if (!apiKey) throw app.httpErrors.serviceUnavailable('Pi agent is not configured');
|
||||
if (!apiKey) throw app.httpErrors.serviceUnavailable('Sybil Agent is not configured');
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch(new URL(path, baseUrl), { method,
|
||||
headers: { Authorization: `Bearer ${apiKey}`, ...(body === undefined ? {} : { 'Content-Type': 'application/json' }) },
|
||||
...(body === undefined ? {} : { body: JSON.stringify(body) }), signal: AbortSignal.timeout(15_000),
|
||||
});
|
||||
} catch { throw app.httpErrors.badGateway('Pi agent is unavailable'); }
|
||||
} catch { throw app.httpErrors.badGateway('Sybil Agent is unavailable'); }
|
||||
let data: unknown;
|
||||
try { data = await response.json(); }
|
||||
catch { throw app.httpErrors.badGateway('Pi agent returned invalid JSON'); }
|
||||
catch { throw app.httpErrors.badGateway('Sybil Agent returned invalid JSON'); }
|
||||
return { status: response.status, data };
|
||||
};
|
||||
|
||||
@@ -75,7 +75,7 @@ export async function registerAgentRoutes(app: FastifyInstance, options: AgentOp
|
||||
if (result.status >= 200 && result.status < 300) {
|
||||
const receipt = SubmissionReceipt.safeParse(result.data);
|
||||
if (!receipt.success || receipt.data.messageId !== `inbound:sybil:${body.requestId}`) {
|
||||
throw app.httpErrors.badGateway('Pi agent returned an invalid message receipt');
|
||||
throw app.httpErrors.badGateway('Sybil Agent returned an invalid message receipt');
|
||||
}
|
||||
}
|
||||
reply.code(result.status);
|
||||
@@ -137,22 +137,22 @@ function attachAgentSocket(app: FastifyInstance, baseUrl: string, apiKey?: strin
|
||||
if (!authenticated) {
|
||||
const auth = parse(AuthFrame, frame);
|
||||
if (env.ADMIN_TOKEN && auth.token !== env.ADMIN_TOKEN) { browser.close(4401, 'Invalid token'); return; }
|
||||
if (!apiKey) { browser.close(4503, 'Pi agent is not configured'); return; }
|
||||
if (!apiKey) { browser.close(4503, 'Sybil Agent is not configured'); return; }
|
||||
authenticated = true; clearTimeout(authTimeout);
|
||||
const target = new URL('/api/ws', baseUrl); target.protocol = target.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
upstream = new WebSocket(target, { headers: { Authorization: `Bearer ${apiKey}` }, handshakeTimeout: 10_000, maxPayload: 16 * 1024 * 1024 });
|
||||
upstream.on('open', () => upstream!.send(JSON.stringify({ type: 'subscribe', ...(auth.after === undefined ? {} : { after: auth.after }) })));
|
||||
upstream.on('message', (data, binary) => {
|
||||
if (binary) { browser.close(1011, 'Invalid Pi frame'); return; }
|
||||
if (binary) { browser.close(1011, 'Invalid Sybil Agent frame'); return; }
|
||||
send(data.toString());
|
||||
});
|
||||
upstream.on('close', () => { if (!disposed) browser.close(1012, 'Pi agent disconnected; reconnect with cursor'); });
|
||||
upstream.on('error', () => { send({ type: 'error', error: 'Pi agent is unavailable' }); browser.close(1011, 'Pi agent is unavailable'); });
|
||||
upstream.on('close', () => { if (!disposed) browser.close(1012, 'Sybil Agent disconnected; reconnect with cursor'); });
|
||||
upstream.on('error', () => { send({ type: 'error', error: 'Sybil Agent is unavailable' }); browser.close(1011, 'Sybil Agent is unavailable'); });
|
||||
return;
|
||||
}
|
||||
if (frame.type === 'ping') { send({ type: 'pong' }); return; }
|
||||
const subscribe = parse(SubscribeFrame, frame);
|
||||
if (upstream?.readyState !== WebSocket.OPEN) { send({ type: 'error', error: 'Pi agent is still connecting' }); return; }
|
||||
if (upstream?.readyState !== WebSocket.OPEN) { send({ type: 'error', error: 'Sybil Agent is still connecting' }); return; }
|
||||
upstream.send(JSON.stringify(subscribe));
|
||||
} catch (error) {
|
||||
if (!authenticated) browser.close(4400, 'Invalid authentication frame');
|
||||
|
||||
Reference in New Issue
Block a user