Add structured memory injection and telemetry tracking

- Introduce buildMessagesWithMemory() to prepend memory context as a system
  message before LLM calls
- Record LLM call telemetry (tokens, duration) for follow-up requests in
  both streaming and non-streaming paths
- Add telemetry coverage for tool execution (success/failure, args,
  duration)
- Update tool-executor tests to verify telemetry integration with
  TelemetryManager
This commit is contained in:
2026-05-20 22:46:42 +02:00
parent f98afcd6b0
commit f1afba70ff
2 changed files with 135 additions and 5 deletions
+43 -2
View File
@@ -607,6 +607,18 @@ export class ChatView extends ItemView {
return filterToolsForMode(allTools, this.currentAgentMode);
}
/**
* Build messages for the LLM, injecting structured memory context if available.
* This is the canonical message builder used for all LLM calls in this view.
*/
private buildMessagesWithMemory(baseMessages: OllamaMessage[]): OllamaMessage[] {
const memoryContext = this.structuredMemoryManager?.buildMemoryContext();
if (memoryContext) {
return [{ role: 'system', content: memoryContext }, ...baseMessages];
}
return baseMessages;
}
buildMessages(userMessageContent: string, tools?: OllamaTool[]): OllamaMessage[] {
const systemContent = getSystemPromptForMode(this.currentAgentMode);
const messages: OllamaMessage[] = [];
@@ -730,12 +742,25 @@ export class ChatView extends ItemView {
if (followUpMessages.length > 0) {
const finalMessages = [...messages, followUp, ...followUpMessages];
const followUpStartTime = Date.now();
const response = await this.ollamaClient.chat(finalMessages, tools);
const followUpDurationMs = Date.now() - followUpStartTime;
const finalResponse = response.content || fullResponse;
this.updateMessageById(assistantMessageId, {
content: finalResponse,
isStreaming: false,
});
// Record follow-up LLM call telemetry
this.telemetryManager?.recordLlmCall({
model: this.settings.model,
promptTokens: Math.round(finalMessages.reduce((sum, m) => sum + m.content.length, 0) / 4),
completionTokens: Math.round(finalResponse.length / 4),
totalTokens: Math.round(
(finalMessages.reduce((sum, m) => sum + m.content.length, 0) + finalResponse.length) / 4
),
durationMs: followUpDurationMs,
});
}
}
@@ -777,12 +802,25 @@ export class ChatView extends ItemView {
if (followUpMessages.length > 0) {
const finalMessages = [...messages, followUp, ...followUpMessages];
const followUpStartTime = Date.now();
const response = await this.ollamaClient.chat(finalMessages, tools);
const followUpDurationMs = Date.now() - followUpStartTime;
const finalResponse = response.content || 'Actions applied successfully.';
this.updateMessageById(assistantMessageId, {
content: finalResponse,
isStreaming: false,
});
// Record follow-up LLM call telemetry
this.telemetryManager?.recordLlmCall({
model: this.settings.model,
promptTokens: Math.round(finalMessages.reduce((sum, m) => sum + m.content.length, 0) / 4),
completionTokens: Math.round(finalResponse.length / 4),
totalTokens: Math.round(
(finalMessages.reduce((sum, m) => sum + m.content.length, 0) + finalResponse.length) / 4
),
durationMs: followUpDurationMs,
});
} else {
this.updateMessageById(assistantMessageId, {
content: 'Actions applied successfully.',
@@ -1035,7 +1073,10 @@ export class ChatView extends ItemView {
const completeMessages =
this.conversationStateManager.getCompleteMessages(userMessageWithContext);
const stream = this.ollamaClient.streamChat(completeMessages, tools);
// Prepend structured memory as a system message if available
const messagesWithMemory = this.buildMessagesWithMemory(completeMessages);
const stream = this.ollamaClient.streamChat(messagesWithMemory, tools);
let fullResponse = '';
let toolCalls: OllamaToolCall[] = [];
@@ -1087,7 +1128,7 @@ export class ChatView extends ItemView {
if (toolCalls.length > 0) {
await this.processToolCalls(
toolCalls,
completeMessages,
messagesWithMemory,
tools,
fullResponse,
assistantMessageId