ForgeTotal.js 5
sv

Total.js 5

Talk till språkmodeller med AIMODEL(), NEWAIMODELL() och AIPARSER()

Total.js 5 · total5@0.0.19 aillmintegrations Körd med Total.js 5

total5 levererar ingen anslutning till någon leverantör. Det ger dig tre delar som fungerar tillsammans:

  • NEWAIMODEL('name', config, driver) registrerar drivrutinen för en eller flera modeller ('a,b' registrerar samma drivrutin för två namn). Drivrutinen är function(ai, done): ai.payload har model, messages, tools, prompt och think, ai.config är konfigurationen och ai.options.stream är funktionen som anroparen skickade till stream() (eller undefined). Svara med done(error, response).
  • AIMODEL('name') startar en förfrågan för en registrerad modell och returnerar en builder. system(text), user(text) och assistant(text) lägger till ett meddelande, prompt(text), tool(definition) och think() fyller i resten av payloaden, och configure({ ... }) lägger till i ai.config bara för det här anropet. Avsluta den med callback(fn), await promise($) eller stream(fn); drivrutinen körs efter den aktuella omgången, så du kan kedja ihop allt först.
  • AIPARSER(provider) returnerar en parser för strömmat svar från en leverantör (källkoden i total5 känner till openai, claude/anthropic, gemini/google, ollama och openai_responses, och läser alla andra namn som ett generiskt format; nedan körs bara openai). write(chunk) tar emot bitar av strömmen (den behåller ofullständiga rader till nästa bit), end() avslutar den, och båda returnerar { content, thinking, tools, reasoning }. parser.on('content', fn) anropas med varje del av texten allteftersom den kommer.

En modell som inte har registrerats svar med felet AI model not found.. Exemplet registrerar en lokal förare som returnerar ett svar från de levererade meddelandena.

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 });
}