// Shared memory utilities for consolidating workflow history
export interface MemoryConsolidationContext {
toolName: string;
success: boolean;
timestamp: number;
arguments?: any;
}
/**
* Generate a unique workflow ID for reusable workflows
*/
function generateWorkflowId(toolName: string, timestamp: number): string {
const shortTimestamp = timestamp.toString(36);
const randomSuffix = Math.random().toString(36).substring(2, 8);
return `${toolName}_${shortTimestamp}_${randomSuffix}`;
}
/**
* Enhanced consolidation to handle duplicates and add unique IDs for planners
*/
export function consolidateWorkflowEntry(insights: any, toolContext: MemoryConsolidationContext) {
const { toolName, success, timestamp, arguments: args } = toolContext;
// Special handling for update_session_memory (counter-based consolidation)
if (toolName === "update_session_memory") {
if (!insights.memoryUpdateCount) {
insights.memoryUpdateCount = 0;
}
insights.memoryUpdateCount++;
const existingMemoryEntry = insights.workflowHistory.find(
(entry: any) => entry.workflow === "update_session_memory"
);
if (existingMemoryEntry) {
existingMemoryEntry.context = `Memory updates: ${insights.memoryUpdateCount}`;
existingMemoryEntry.timestamp = timestamp;
existingMemoryEntry.success = success;
} else {
insights.workflowHistory.push({
workflow: "update_session_memory",
success,
timestamp,
context: `Memory updates: ${insights.memoryUpdateCount}`
});
}
return;
}
// Special handling for update_session_planner (unique ID for reusability)
if (toolName === "update_session_planner") {
const workflowId = generateWorkflowId("planner", timestamp);
const context = JSON.stringify(args).substring(0, 200);
// Check for near-duplicate within last 5 seconds
const recentDuplicate = insights.workflowHistory.find((entry: any) =>
entry.workflow === "update_session_planner" &&
Math.abs(entry.timestamp - timestamp) < 5000 &&
entry.context === context
);
if (!recentDuplicate) {
insights.workflowHistory.push({
workflow: "update_session_planner",
success,
timestamp,
context,
workflowId, // Unique ID for later recall
reusable: true // Mark as reusable workflow
});
}
return;
}
// General duplicate prevention for all other tools
const context = JSON.stringify(args).substring(0, 200);
// Check for exact duplicate within last 2 seconds
const recentDuplicate = insights.workflowHistory.find((entry: any) =>
entry.workflow === toolName &&
Math.abs(entry.timestamp - timestamp) < 2000 &&
entry.context === context
);
if (!recentDuplicate) {
insights.workflowHistory.push({
workflow: toolName,
success,
timestamp,
context
});
}
}
/**
* Legacy function for backward compatibility
* @deprecated Use consolidateWorkflowEntry instead
*/
export function consolidateMemoryUpdates(insights: any, toolContext: MemoryConsolidationContext) {
consolidateWorkflowEntry(insights, toolContext);
}
/**
* Keep workflow history lean by limiting size but preserving consolidated entries
*/
export function maintainWorkflowHistorySize(insights: any, maxSize: number = 50) {
if (insights.workflowHistory.length > maxSize) {
// Filter to keep update_session_memory entry and last N-1 others
const memoryEntry = insights.workflowHistory.find(
(entry: any) => entry.workflow === "update_session_memory"
);
const otherEntries = insights.workflowHistory
.filter((entry: any) => entry.workflow !== "update_session_memory")
.slice(-(maxSize - 1));
insights.workflowHistory = memoryEntry ? [memoryEntry, ...otherEntries] : otherEntries;
}
}
/**
* Find reusable workflows by ID for later recall
*/
export function findReusableWorkflow(insights: any, workflowId: string): any {
return insights.workflowHistory.find((entry: any) =>
entry.workflowId === workflowId && entry.reusable === true
);
}
/**
* Get all reusable planner workflows
*/
export function getReusablePlannerWorkflows(insights: any): any[] {
return insights.workflowHistory.filter((entry: any) =>
entry.workflow === "update_session_planner" &&
entry.reusable === true
).map((entry: any) => ({
id: entry.workflowId,
timestamp: entry.timestamp,
description: `Planner workflow from ${new Date(entry.timestamp).toLocaleString()}`,
context: entry.context,
success: entry.success
}));
}