feat: harden orchestrator execution runtime
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
function extensionName(config) {
|
||||
return String(config?.name ?? '').trim();
|
||||
}
|
||||
|
||||
async function readJson(response) {
|
||||
const text = await response.text();
|
||||
if (!response.ok) {
|
||||
throw new Error(text || `upstream ${response.status}`);
|
||||
}
|
||||
return text ? JSON.parse(text) : null;
|
||||
}
|
||||
|
||||
export function sessionStdioExtensionNames(extensions) {
|
||||
return [
|
||||
...new Set(
|
||||
(extensions ?? [])
|
||||
.filter((extension) => String(extension?.type ?? '').trim() === 'stdio')
|
||||
.map(extensionName)
|
||||
.filter(Boolean),
|
||||
),
|
||||
].sort();
|
||||
}
|
||||
|
||||
export async function cancelSessionActiveRequest(apiFetch, sessionId, requestId) {
|
||||
const normalizedSessionId = String(sessionId ?? '').trim();
|
||||
const normalizedRequestId = String(requestId ?? '').trim();
|
||||
if (!normalizedSessionId || !normalizedRequestId) {
|
||||
return { cancelled: false, skipped: true };
|
||||
}
|
||||
|
||||
const response = await apiFetch(
|
||||
`/sessions/${encodeURIComponent(normalizedSessionId)}/cancel`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ request_id: normalizedRequestId }),
|
||||
},
|
||||
);
|
||||
const text = await response.text();
|
||||
if (
|
||||
!response.ok
|
||||
&& ![404, 409, 410].includes(Number(response.status))
|
||||
&& !/(?:not found|no active|already (?:finished|cancelled))/i.test(text)
|
||||
) {
|
||||
throw new Error(text || `upstream ${response.status}`);
|
||||
}
|
||||
return {
|
||||
cancelled: response.ok,
|
||||
skipped: !response.ok,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop per-session stdio MCP children while preserving the Goose conversation.
|
||||
* Session reconciliation restores the required extensions before the next turn.
|
||||
*/
|
||||
export async function quiesceSessionStdioExtensions(apiFetch, sessionId) {
|
||||
const normalizedSessionId = String(sessionId ?? '').trim();
|
||||
if (!normalizedSessionId) return { removed: [], skipped: true };
|
||||
|
||||
const payload = await readJson(
|
||||
await apiFetch(`/sessions/${encodeURIComponent(normalizedSessionId)}/extensions`),
|
||||
);
|
||||
const names = sessionStdioExtensionNames(payload?.extensions);
|
||||
const removed = [];
|
||||
for (const name of names) {
|
||||
await readJson(
|
||||
await apiFetch('/agent/remove_extension', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
session_id: normalizedSessionId,
|
||||
name,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
removed.push(name);
|
||||
}
|
||||
return { removed, skipped: names.length === 0 };
|
||||
}
|
||||
Reference in New Issue
Block a user