feat: version 3.2.0 -- Integracion IA: configuracion y plan de actividades
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
import { getAiConfigInternal } from '../modules/settings/service.js';
|
||||
import { HttpError } from './http.js';
|
||||
|
||||
const API_URL = 'https://api.anthropic.com/v1/messages';
|
||||
const TIMEOUT_MS = 60_000;
|
||||
|
||||
// Llama a la API de Mensajes forzando una herramienta, para recibir JSON con el esquema pedido
|
||||
// (la IA solo sugiere: quien llama valida y el usuario revisa antes de guardar).
|
||||
export async function askStructured({ system, prompt, toolName, schema, maxTokens = 2000, configOverride }) {
|
||||
const config = configOverride || await getAiConfigInternal();
|
||||
if (!config) throw new HttpError(400, 'La integracion con IA no esta configurada');
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
||||
let res;
|
||||
try {
|
||||
res = await fetch(API_URL, {
|
||||
method: 'POST',
|
||||
signal: controller.signal,
|
||||
headers: { 'content-type': 'application/json', 'x-api-key': config.apiKey, 'anthropic-version': '2023-06-01' },
|
||||
body: JSON.stringify({
|
||||
model: config.model,
|
||||
max_tokens: maxTokens,
|
||||
system: `${system}\nResponde SIEMPRE llamando a la herramienta ${toolName}.`,
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
tools: [{ name: toolName, description: 'Devuelve el resultado estructurado.', input_schema: schema }],
|
||||
// Forzar la herramienta (tool_choice 'tool') da 400 en Sonnet 5.5: se usa 'auto' + instruccion.
|
||||
tool_choice: { type: 'auto' },
|
||||
}),
|
||||
});
|
||||
} catch (err) {
|
||||
throw new HttpError(502, err.name === 'AbortError' ? 'La IA tardo demasiado en responder' : 'No se pudo conectar con el servicio de IA');
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
const body = await res.json().catch(() => null);
|
||||
if (!res.ok) {
|
||||
// Mensaje del proveedor sin exponer la clave; 401 = clave invalida, 429 = limite, 400 = saldo/peticion.
|
||||
const detail = body?.error?.message || `HTTP ${res.status}`;
|
||||
console.error('[ai] error de la API:', res.status, detail);
|
||||
throw new HttpError(502, `Servicio de IA: ${detail}`);
|
||||
}
|
||||
// Consumo real de cada llamada (para estimar costos: ver precios del modelo en la consola).
|
||||
console.log(`[ai] ${config.model} tokens entrada=${body?.usage?.input_tokens} salida=${body?.usage?.output_tokens}`);
|
||||
const tool = body?.content?.find((c) => c.type === 'tool_use');
|
||||
if (!tool?.input) throw new HttpError(502, 'La IA no devolvio un resultado valido');
|
||||
return tool.input;
|
||||
}
|
||||
Reference in New Issue
Block a user