141 lines
3.8 KiB
JavaScript
141 lines
3.8 KiB
JavaScript
/**
|
|
* Agent engine: context builder + toolchain orchestrator
|
|
*
|
|
* Builds the message context for vLLM inference:
|
|
* - No system prompt (model trained on real conversations)
|
|
* - Previous conversation memory (mother tongue imprint)
|
|
* - Tool results (Notion, repo) injected as user/assistant messages
|
|
* - Auto conversation rotation at threshold
|
|
*/
|
|
'use strict';
|
|
|
|
const vllm = require('./vllm-proxy');
|
|
const sessionStore = require('./session-store');
|
|
const memoryAgent = require('./memory-agent');
|
|
const toolRegistry = require('./tool-registry');
|
|
|
|
const MAX_MESSAGES_BEFORE_ROTATE = 50;
|
|
const MAX_CONTEXT_TOKENS = 3072;
|
|
|
|
/**
|
|
* Build the full message context for vLLM
|
|
*
|
|
* Context structure:
|
|
* [
|
|
* {role:'user', content:'[Mother Tongue Imprint from last session]'},
|
|
* {role:'assistant', content:'[Understood. Continuing from where we left off.]'},
|
|
* ...previous messages,
|
|
* {role:'user', content:'current message'}
|
|
* ]
|
|
*
|
|
* NO system prompt - the model was trained on real conversations without system prompts.
|
|
*/
|
|
function buildContext(userHash, slotIndex, newMessage, conversationHistory, options = {}) {
|
|
const messages = [];
|
|
|
|
// 1. Cross-session memory imprint (if exists)
|
|
const imprint = sessionStore.getLatestImprint(userHash);
|
|
if (imprint) {
|
|
messages.push({
|
|
role: 'user',
|
|
content: '[Previous conversation memory]\n' + imprint
|
|
});
|
|
messages.push({
|
|
role: 'assistant',
|
|
content: '[I understand. I will continue based on our previous conversation.]'
|
|
});
|
|
}
|
|
|
|
// 2. Current conversation history
|
|
const history = conversationHistory || [];
|
|
for (const msg of history) {
|
|
if (msg.role === 'system') continue; // Never inject system messages
|
|
messages.push({
|
|
role: msg.role,
|
|
content: msg.content || ''
|
|
});
|
|
}
|
|
|
|
// 3. Current user message
|
|
messages.push({
|
|
role: 'user',
|
|
content: newMessage || ''
|
|
});
|
|
|
|
return messages;
|
|
}
|
|
|
|
/**
|
|
* Process a chat message through the agent pipeline:
|
|
* 1. Build context (memory + history)
|
|
* 2. Send to vLLM
|
|
* 3. Check if model requested a tool call
|
|
* 4. If tool call: execute tool, inject result, re-request
|
|
* 5. Return final response
|
|
*/
|
|
async function processMessage(userHash, slotIndex, message, conversationHistory = []) {
|
|
const context = buildContext(userHash, slotIndex, message, conversationHistory);
|
|
|
|
// Send to vLLM
|
|
let response = await vllm.chatOnce(context, {
|
|
maxTokens: 1024,
|
|
temperature: 0.7
|
|
});
|
|
|
|
// Check for tool calls
|
|
const toolCall = toolRegistry.parseToolCall(response);
|
|
if (toolCall) {
|
|
context.push({ role: 'assistant', content: response });
|
|
|
|
try {
|
|
const toolResult = await toolRegistry.executeToolCall(toolCall);
|
|
context.push({ role: 'user', content: '[Tool Result]\n' + JSON.stringify(toolResult, null, 2) });
|
|
|
|
// Re-request with tool result
|
|
response = await vllm.chatOnce(context, {
|
|
maxTokens: 1024,
|
|
temperature: 0.7
|
|
});
|
|
} catch (err) {
|
|
context.push({ role: 'user', content: '[Tool Error]\n' + err.message });
|
|
response = await vllm.chatOnce(context, {
|
|
maxTokens: 512,
|
|
temperature: 0.7
|
|
});
|
|
}
|
|
}
|
|
|
|
return {
|
|
response,
|
|
shouldRotate: conversationHistory.length >= MAX_MESSAGES_BEFORE_ROTATE
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Stream a chat message through the pipeline, writing SSE to res
|
|
*/
|
|
async function streamProcessMessage(userHash, slotIndex, message, conversationHistory, res) {
|
|
const context = buildContext(userHash, slotIndex, message, conversationHistory);
|
|
|
|
// Stream from vLLM
|
|
vllm.pipeChat(context, res, {
|
|
maxTokens: 1024,
|
|
temperature: 0.7
|
|
});
|
|
|
|
return {
|
|
shouldRotate: conversationHistory.length >= MAX_MESSAGES_BEFORE_ROTATE
|
|
};
|
|
}
|
|
|
|
function getMaxMessages() {
|
|
return MAX_MESSAGES_BEFORE_ROTATE;
|
|
}
|
|
|
|
module.exports = {
|
|
buildContext,
|
|
processMessage,
|
|
streamProcessMessage,
|
|
getMaxMessages
|
|
};
|