Imágenes: - analyze_image y upload resuelven los bytes por el endpoint Python /api/image-bytes (pythonGetBinary). analyze_image enruta los dominios forge (env ACAI_FORGE_DOMAIN) al endpoint en vez de fetch directo (que daba ECONNREFUSED 127.0.0.1 dentro del container). Aislamiento de entorno (vscode = solo test): - resolveCurrentModeOverride(): sesión MCP HTTP (mcpSessionId presente) → "local"; stdio (chat/cron) → ACAI_MODE_OVERRIDE de entorno. Lo usan los builders de headers (pythonServerClient, files/helpers) → toda tool del MCP HTTP manda X-Acai-Mode: local. - httpServer.resolveProjectCredentials fuerza forceMode:"local" al resolver project-info → la sesión obtiene web_url/api_web_url forge-local y opera siempre contra test, nunca producción. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
63 lines
2.2 KiB
JavaScript
63 lines
2.2 KiB
JavaScript
import axios from "axios";
|
|
import { resolveCurrentAcaiUser, resolveCurrentModeOverride } from "./sessionHelpers.js";
|
|
|
|
const PYTHON_BASE = `http://app:${process.env.ACAI_PORT || 9091}`;
|
|
|
|
/**
|
|
* Construye el set de headers comunes para llamadas al server Python interno.
|
|
* Inyecta automaticamente `X-Acai-User` cuando hay sesion MCP activa con
|
|
* `acai_user` conocido, lo que permite a los endpoints autenticados identificar
|
|
* al usuario sin Authorization Basic.
|
|
*/
|
|
function buildPythonHeaders(extra = {}) {
|
|
const authHeader = process.env.ACAI_AUTH_HEADER || "";
|
|
const mode = resolveCurrentModeOverride();
|
|
const role = process.env.ACAI_ROLE_OVERRIDE || "";
|
|
const acaiUser = resolveCurrentAcaiUser();
|
|
|
|
return {
|
|
"Content-Type": "application/json",
|
|
...(authHeader ? { "Authorization": authHeader } : {}),
|
|
...(mode ? { "X-Acai-Mode": mode } : {}),
|
|
...(role ? { "X-Acai-Role": role } : {}),
|
|
...(acaiUser ? { "X-Acai-User": acaiUser } : {}),
|
|
...extra,
|
|
};
|
|
}
|
|
|
|
export async function pythonPost(path, data, timeout = 120000) {
|
|
const response = await axios.post(`${PYTHON_BASE}${path}`, data, {
|
|
headers: buildPythonHeaders(),
|
|
timeout,
|
|
maxBodyLength: Infinity,
|
|
maxContentLength: Infinity,
|
|
});
|
|
return response.data;
|
|
}
|
|
|
|
export async function pythonGet(path, params = null, timeout = 30000) {
|
|
const response = await axios.get(`${PYTHON_BASE}${path}`, {
|
|
params: params || undefined,
|
|
headers: buildPythonHeaders(),
|
|
timeout,
|
|
});
|
|
return response.data;
|
|
}
|
|
|
|
/**
|
|
* GET binario al server Python (p.ej. /api/image-bytes). Devuelve
|
|
* { buffer: Buffer, mimeType: string }. Lanza si el status no es 2xx.
|
|
*/
|
|
export async function pythonGetBinary(path, params = null, timeout = 30000) {
|
|
const response = await axios.get(`${PYTHON_BASE}${path}`, {
|
|
params: params || undefined,
|
|
headers: buildPythonHeaders(),
|
|
responseType: "arraybuffer",
|
|
timeout,
|
|
maxContentLength: Infinity,
|
|
});
|
|
const mimeType = (response.headers?.["content-type"] || "").split(";")[0].trim()
|
|
|| "application/octet-stream";
|
|
return { buffer: Buffer.from(response.data), mimeType };
|
|
}
|