analyze/upload vía /api/image-bytes + MCP HTTP (vscode) forzado a test
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>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import axios from "axios";
|
||||
import { resolveCurrentAcaiUser } from "./sessionHelpers.js";
|
||||
import { resolveCurrentAcaiUser, resolveCurrentModeOverride } from "./sessionHelpers.js";
|
||||
|
||||
const PYTHON_BASE = `http://app:${process.env.ACAI_PORT || 9091}`;
|
||||
|
||||
@@ -11,7 +11,7 @@ const PYTHON_BASE = `http://app:${process.env.ACAI_PORT || 9091}`;
|
||||
*/
|
||||
function buildPythonHeaders(extra = {}) {
|
||||
const authHeader = process.env.ACAI_AUTH_HEADER || "";
|
||||
const mode = process.env.ACAI_MODE_OVERRIDE || process.env.ACAI_MODE || "";
|
||||
const mode = resolveCurrentModeOverride();
|
||||
const role = process.env.ACAI_ROLE_OVERRIDE || "";
|
||||
const acaiUser = resolveCurrentAcaiUser();
|
||||
|
||||
@@ -43,3 +43,20 @@ export async function pythonGet(path, params = null, timeout = 30000) {
|
||||
});
|
||||
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 };
|
||||
}
|
||||
|
||||
@@ -25,3 +25,23 @@ export function resolveCurrentAcaiUser() {
|
||||
const creds = getMcpSessionCredentials(sessionId);
|
||||
return creds?.acai_user || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modo efectivo (X-Acai-Mode) para las llamadas al server Python.
|
||||
*
|
||||
* Regla de seguridad: una sesion MCP HTTP (mcpSessionId presente) es SIEMPRE un
|
||||
* cliente externo — en la practica el plugin VS Code Acai Forge — y solo puede
|
||||
* operar sobre TEST. Por eso forzamos "local" pase lo que pase el .acai del
|
||||
* proyecto. El server Python honra este header para decidir el destino real
|
||||
* (BD y ficheros), de modo que vscode nunca toca produccion.
|
||||
*
|
||||
* Las sesiones stdio (chat del dashboard / cronjobs) NO tienen mcpSessionId:
|
||||
* mantienen el override de entorno (ACAI_MODE_OVERRIDE), que puede ser
|
||||
* "production" cuando corresponde (chat en modo produccion, cron de prod).
|
||||
*
|
||||
* @returns {string} "local" | "production" | "" (vacio = usar .acai)
|
||||
*/
|
||||
export function resolveCurrentModeOverride() {
|
||||
if (getCurrentSessionId()) return "local";
|
||||
return process.env.ACAI_MODE_OVERRIDE || process.env.ACAI_MODE || "";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user