ForgeTotal.js 5
es

Total.js 5

Habla con modelos de lenguaje con AIMODEL(), NEWAIMODEL() y AIPARSER()

Total.js 5 · total5@0.0.19 aillmintegrations Ejecutada con Total.js 5

total5 no envía una conexión a ningún proveedor. Te ofrece tres piezas que funcionan juntas:

  • NEWAIMODEL('name', config, driver) registra el controlador de uno o más modelos ('a,b' registra el mismo controlador para dos nombres). El controlador es function(ai, done): ai.payload tiene model, messages, tools, prompt y think, ai.config es la configuración y ai.options.stream es la función. la persona que llama pasó a stream() (o undefined). Responda con done(error, response).
  • AIMODEL('name') inicia una solicitud de un modelo registrado y devuelve un constructor. system(text), user(text) y assistant(text) agregan un mensaje, prompt(text), tool(definition) y think() completan el resto de la carga útil, y configure({ ... }) agrega a ai.config solo para esta llamada. Termínelo con callback(fn), await promise($) o stream(fn); el conductor corre después del giro actual, por lo que puedes encadenar todo primero.
  • AIPARSER(provider) devuelve un analizador para la respuesta transmitida de un proveedor (la fuente de total5 conoce openai, claude/anthropic, gemini/google, ollama y openai_responses, y lee cualquier otro nombre como formato genérico, a continuación solo se ejecuta openai). write(chunk) toma partes de la secuencia (mantiene líneas incompletas hasta la siguiente pieza), end() la finaliza y ambos devuelven { content, thinking, tools, reasoning }. parser.on('content', fn) se llama con cada parte del texto a medida que llega.

Un modelo que no estaba registrado responde con el error AI model not found.. El ejemplo registra un controlador local que devuelve una respuesta de los mensajes proporcionados.

definitions/ai.js
NEWAIMODEL('echo', { prefix: 'Echo' }, function(ai, done) {

	const last = ai.payload.messages.filter(n => n.role === 'user').pop();
	const text = ai.config.prefix + ': ' + (last ? last.content : '');

	// A real driver would send ai.payload to the provider and send the pieces to ai.options.stream
	if (ai.options.stream) {
		for (const word of text.split(' '))
			ai.options.stream(word + ' ');
	}

	done(null, { content: text, roles: ai.payload.messages.map(n => n.role), tools: ai.payload.tools.length, think: !!ai.payload.think });
});
controllers/ai.js
exports.install = function() {
	ROUTE('POST /ask/', ask);
	ROUTE('GET /ask-config/', askconfig);
	ROUTE('GET /ask-stream/', askstream);
	ROUTE('GET /ask-missing/', missing);
	ROUTE('GET /parse/', parse);
};

async function ask($) {
	const response = await AIMODEL('echo').system('You are brief.').user($.body.question).tool({ name: 'weather' }).think().promise($);
	$.json(response);
}

function askconfig($) {
	AIMODEL('echo').user('hello').configure({ prefix: 'Custom' }).callback($.callback());
}

function askstream($) {
	const parts = [];
	AIMODEL('echo').user('one two three').stream(part => parts.push(part)).callback(function(err, response) {
		$.json({ parts: parts, content: response.content });
	});
}

function missing($) {
	AIMODEL('nobody').user('hi').callback($.callback());
}

function parse($) {
	const parser = AIPARSER('openai');
	const events = [];
	parser.on('content', e => events.push(e.delta));

	// the second piece starts in the middle of a line
	parser.write('data: {"choices":[{"delta":{"content":"Hel"}}]}\n\ndata: {"choices":[{"delta":{"con');
	parser.write('tent":"lo"}}]}\n\ndata: [DONE]\n');
	const output = parser.end();

	$.json({ output: output, events: events });
}