Merge branch 'main' into feature/mem-search-enhancements
Resolved conflicts in built files by rebuilding from merged source. All plugin/scripts files regenerated from current source code. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -44,7 +44,7 @@
|
||||
"worker:stop": "bun plugin/scripts/worker-cli.js stop",
|
||||
"worker:restart": "bun plugin/scripts/worker-cli.js restart",
|
||||
"worker:status": "bun plugin/scripts/worker-cli.js status",
|
||||
"worker:logs": "tail -f ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log",
|
||||
"worker:logs": "tail -n 50 ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log",
|
||||
"changelog:generate": "node scripts/generate-changelog.js",
|
||||
"usage:analyze": "node scripts/analyze-usage.js",
|
||||
"usage:today": "node scripts/analyze-usage.js $(date +%Y-%m-%d)",
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -8,7 +8,6 @@
|
||||
|
||||
import { stdin } from 'process';
|
||||
import { ensureWorkerRunning, getWorkerPort } from '../shared/worker-utils.js';
|
||||
import { happy_path_error__with_fallback } from '../utils/silent-debug.js';
|
||||
import { HOOK_TIMEOUTS } from '../shared/hook-constants.js';
|
||||
|
||||
export interface SessionEndInput {
|
||||
@@ -23,11 +22,6 @@ async function cleanupHook(input?: SessionEndInput): Promise<void> {
|
||||
// Ensure worker is running before any other logic
|
||||
await ensureWorkerRunning();
|
||||
|
||||
happy_path_error__with_fallback('[cleanup-hook] Hook fired', {
|
||||
session_id: input?.session_id,
|
||||
reason: input?.reason
|
||||
});
|
||||
|
||||
if (!input) {
|
||||
throw new Error('cleanup-hook requires input from Claude Code');
|
||||
}
|
||||
@@ -48,18 +42,12 @@ async function cleanupHook(input?: SessionEndInput): Promise<void> {
|
||||
signal: AbortSignal.timeout(HOOK_TIMEOUTS.DEFAULT)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
happy_path_error__with_fallback('[cleanup-hook] Session cleanup completed', result);
|
||||
} else {
|
||||
if (!response.ok) {
|
||||
// Non-fatal - session might not exist
|
||||
happy_path_error__with_fallback('[cleanup-hook] Session not found or already cleaned up');
|
||||
console.error('[cleanup-hook] Session not found or already cleaned up');
|
||||
}
|
||||
} catch (error: any) {
|
||||
// Worker might not be running - that's okay
|
||||
happy_path_error__with_fallback('[cleanup-hook] Worker not reachable (non-critical)', {
|
||||
error: error.message
|
||||
});
|
||||
// Worker might not be running - that's okay (non-critical)
|
||||
}
|
||||
|
||||
console.log('{"continue": true, "suppressOutput": true}');
|
||||
|
||||
@@ -2,7 +2,6 @@ import path from 'path';
|
||||
import { stdin } from 'process';
|
||||
import { createHookResponse } from './hook-response.js';
|
||||
import { ensureWorkerRunning, getWorkerPort } from '../shared/worker-utils.js';
|
||||
import { happy_path_error__with_fallback } from '../utils/silent-debug.js';
|
||||
import { handleWorkerError } from '../shared/hook-error-handler.js';
|
||||
import { handleFetchError } from './shared/error-handler.js';
|
||||
|
||||
@@ -27,12 +26,6 @@ async function newHook(input?: UserPromptSubmitInput): Promise<void> {
|
||||
const { session_id, cwd, prompt } = input;
|
||||
const project = path.basename(cwd);
|
||||
|
||||
happy_path_error__with_fallback('[new-hook] Input received', {
|
||||
session_id,
|
||||
project,
|
||||
prompt_length: prompt?.length
|
||||
});
|
||||
|
||||
const port = getWorkerPort();
|
||||
|
||||
// Initialize session via HTTP - handles DB operations and privacy checks
|
||||
|
||||
@@ -11,7 +11,6 @@ import { createHookResponse } from './hook-response.js';
|
||||
import { logger } from '../utils/logger.js';
|
||||
import { ensureWorkerRunning, getWorkerPort } from '../shared/worker-utils.js';
|
||||
import { HOOK_TIMEOUTS } from '../shared/hook-constants.js';
|
||||
import { happy_path_error__with_fallback } from '../utils/silent-debug.js';
|
||||
import { handleWorkerError } from '../shared/hook-error-handler.js';
|
||||
import { handleFetchError } from './shared/error-handler.js';
|
||||
|
||||
@@ -54,8 +53,10 @@ async function saveHook(input?: PostToolUseInput): Promise<void> {
|
||||
tool_name,
|
||||
tool_input,
|
||||
tool_response,
|
||||
cwd: cwd || happy_path_error__with_fallback(
|
||||
cwd: cwd || logger.happyPathError(
|
||||
'HOOK',
|
||||
'Missing cwd in PostToolUse hook input',
|
||||
undefined,
|
||||
{ session_id, tool_name },
|
||||
''
|
||||
)
|
||||
|
||||
@@ -14,7 +14,6 @@ import { createHookResponse } from './hook-response.js';
|
||||
import { logger } from '../utils/logger.js';
|
||||
import { ensureWorkerRunning, getWorkerPort } from '../shared/worker-utils.js';
|
||||
import { HOOK_TIMEOUTS } from '../shared/hook-constants.js';
|
||||
import { happy_path_error__with_fallback } from '../utils/silent-debug.js';
|
||||
import { handleWorkerError } from '../shared/hook-error-handler.js';
|
||||
import { handleFetchError } from './shared/error-handler.js';
|
||||
import { extractLastMessage } from '../shared/transcript-parser.js';
|
||||
@@ -41,8 +40,10 @@ async function summaryHook(input?: StopInput): Promise<void> {
|
||||
const port = getWorkerPort();
|
||||
|
||||
// Extract last user AND assistant messages from transcript
|
||||
const transcriptPath = input.transcript_path || happy_path_error__with_fallback(
|
||||
const transcriptPath = input.transcript_path || logger.happyPathError(
|
||||
'HOOK',
|
||||
'Missing transcript_path in Stop hook input',
|
||||
undefined,
|
||||
{ session_id },
|
||||
''
|
||||
);
|
||||
|
||||
+6
-4
@@ -3,7 +3,7 @@
|
||||
* Generates prompts for the Claude Agent SDK memory worker
|
||||
*/
|
||||
|
||||
import { happy_path_error__with_fallback } from '../utils/silent-debug.js';
|
||||
import { logger } from '../utils/logger.js';
|
||||
|
||||
export interface Observation {
|
||||
id: number;
|
||||
@@ -177,10 +177,12 @@ export function buildObservationPrompt(obs: Observation): string {
|
||||
* Build prompt to generate progress summary
|
||||
*/
|
||||
export function buildSummaryPrompt(session: SDKSession): string {
|
||||
const lastAssistantMessage = happy_path_error__with_fallback(
|
||||
const lastAssistantMessage = session.last_assistant_message || logger.happyPathError(
|
||||
'SDK',
|
||||
'Missing last_assistant_message in session for summary prompt',
|
||||
session,
|
||||
session.last_assistant_message || ''
|
||||
{ sessionId: session.id },
|
||||
undefined,
|
||||
''
|
||||
);
|
||||
|
||||
return `PROGRESS SUMMARY CHECKPOINT
|
||||
|
||||
+11
-11
@@ -14,7 +14,7 @@ import {
|
||||
} from '@modelcontextprotocol/sdk/types.js';
|
||||
import { z } from 'zod';
|
||||
import { zodToJsonSchema } from 'zod-to-json-schema';
|
||||
import { happy_path_error__with_fallback } from '../utils/silent-debug.js';
|
||||
import { logger } from '../utils/logger.js';
|
||||
import { getWorkerPort, getWorkerHost } from '../shared/worker-utils.js';
|
||||
|
||||
/**
|
||||
@@ -42,7 +42,7 @@ async function callWorkerAPI(
|
||||
endpoint: string,
|
||||
params: Record<string, any>
|
||||
): Promise<{ content: Array<{ type: 'text'; text: string }>; isError?: boolean }> {
|
||||
happy_path_error__with_fallback('[mcp-server] → Worker API', { endpoint, params });
|
||||
logger.debug('SYSTEM', '→ Worker API', undefined, { endpoint, params });
|
||||
|
||||
try {
|
||||
const searchParams = new URLSearchParams();
|
||||
@@ -64,12 +64,12 @@ async function callWorkerAPI(
|
||||
|
||||
const data = await response.json() as { content: Array<{ type: 'text'; text: string }>; isError?: boolean };
|
||||
|
||||
happy_path_error__with_fallback('[mcp-server] ← Worker API success', { endpoint });
|
||||
logger.debug('SYSTEM', '← Worker API success', undefined, { endpoint });
|
||||
|
||||
// Worker returns { content: [...] } format directly
|
||||
return data;
|
||||
} catch (error: any) {
|
||||
happy_path_error__with_fallback('[mcp-server] ← Worker API error', { endpoint, error: error.message });
|
||||
logger.error('SYSTEM', '← Worker API error', undefined, { endpoint, error: error.message });
|
||||
return {
|
||||
content: [{
|
||||
type: 'text' as const,
|
||||
@@ -361,7 +361,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
|
||||
// Cleanup function
|
||||
async function cleanup() {
|
||||
happy_path_error__with_fallback('[mcp-server] Shutting down...');
|
||||
logger.info('SYSTEM', 'MCP server shutting down');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
@@ -374,22 +374,22 @@ async function main() {
|
||||
// Start the MCP server
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
happy_path_error__with_fallback('[mcp-server] Claude-mem search server started');
|
||||
logger.info('SYSTEM', 'Claude-mem search server started');
|
||||
|
||||
// Check Worker availability in background
|
||||
setTimeout(async () => {
|
||||
const workerAvailable = await verifyWorkerConnection();
|
||||
if (!workerAvailable) {
|
||||
happy_path_error__with_fallback('[mcp-server] WARNING: Worker not available at', WORKER_BASE_URL);
|
||||
happy_path_error__with_fallback('[mcp-server] Tools will fail until Worker is started');
|
||||
happy_path_error__with_fallback('[mcp-server] Start Worker with: npm run worker:restart');
|
||||
logger.warn('SYSTEM', 'Worker not available', undefined, { workerUrl: WORKER_BASE_URL });
|
||||
logger.warn('SYSTEM', 'Tools will fail until Worker is started');
|
||||
logger.warn('SYSTEM', 'Start Worker with: npm run worker:restart');
|
||||
} else {
|
||||
happy_path_error__with_fallback('[mcp-server] Worker available at', WORKER_BASE_URL);
|
||||
logger.info('SYSTEM', 'Worker available', undefined, { workerUrl: WORKER_BASE_URL });
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
happy_path_error__with_fallback('[mcp-server] Fatal error:', error);
|
||||
logger.error('SYSTEM', 'Fatal error', undefined, error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -15,7 +15,6 @@ import { SessionStore } from '../sqlite/SessionStore.js';
|
||||
import { logger } from '../../utils/logger.js';
|
||||
import { SettingsDefaultsManager } from '../../shared/SettingsDefaultsManager.js';
|
||||
import { USER_SETTINGS_PATH } from '../../shared/paths.js';
|
||||
import { happy_path_error__with_fallback } from '../../utils/silent-debug.js';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
|
||||
@@ -780,9 +779,11 @@ export class ChromaSync {
|
||||
arguments: arguments_obj
|
||||
});
|
||||
|
||||
const resultText = happy_path_error__with_fallback(
|
||||
const resultText = logger.happyPathError(
|
||||
'CHROMA',
|
||||
'Missing text in MCP chroma_query_documents result',
|
||||
{ project: this.project, query_text: query },
|
||||
{ project: this.project },
|
||||
{ query_text: query },
|
||||
result.content[0]?.text || ''
|
||||
);
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import path from 'path';
|
||||
import { DatabaseManager } from './DatabaseManager.js';
|
||||
import { SessionManager } from './SessionManager.js';
|
||||
import { logger } from '../../utils/logger.js';
|
||||
import { happy_path_error__with_fallback } from '../../utils/silent-debug.js';
|
||||
import { parseObservations, parseSummary } from '../../sdk/parser.js';
|
||||
import { buildInitPrompt, buildObservationPrompt, buildSummaryPrompt, buildContinuationPrompt } from '../../sdk/prompts.js';
|
||||
import { SettingsDefaultsManager } from '../../shared/SettingsDefaultsManager.js';
|
||||
|
||||
@@ -9,7 +9,6 @@ import express, { Request, Response } from 'express';
|
||||
import { getWorkerPort } from '../../../../shared/worker-utils.js';
|
||||
import { logger } from '../../../../utils/logger.js';
|
||||
import { stripMemoryTagsFromJson, stripMemoryTagsFromPrompt } from '../../../../utils/tag-stripping.js';
|
||||
import { happy_path_error__with_fallback } from '../../../../utils/silent-debug.js';
|
||||
import { SessionManager } from '../../SessionManager.js';
|
||||
import { DatabaseManager } from '../../DatabaseManager.js';
|
||||
import { SDKAgent } from '../../SDKAgent.js';
|
||||
@@ -342,9 +341,11 @@ export class SessionRoutes extends BaseRouteHandler {
|
||||
tool_input: cleanedToolInput,
|
||||
tool_response: cleanedToolResponse,
|
||||
prompt_number: promptNumber,
|
||||
cwd: cwd || happy_path_error__with_fallback(
|
||||
cwd: cwd || logger.happyPathError(
|
||||
'SESSION',
|
||||
'Missing cwd when queueing observation in SessionRoutes',
|
||||
{ sessionDbId, tool_name },
|
||||
{ sessionId: sessionDbId },
|
||||
{ tool_name },
|
||||
''
|
||||
)
|
||||
});
|
||||
@@ -394,9 +395,11 @@ export class SessionRoutes extends BaseRouteHandler {
|
||||
// Queue summarize
|
||||
this.sessionManager.queueSummarize(
|
||||
sessionDbId,
|
||||
last_user_message || happy_path_error__with_fallback(
|
||||
last_user_message || logger.happyPathError(
|
||||
'SESSION',
|
||||
'Missing last_user_message when queueing summary in SessionRoutes',
|
||||
{ sessionDbId },
|
||||
{ sessionId: sessionDbId },
|
||||
undefined,
|
||||
''
|
||||
),
|
||||
last_assistant_message
|
||||
|
||||
@@ -13,42 +13,85 @@ export function extractLastMessage(
|
||||
stripSystemReminders: boolean = false
|
||||
): string {
|
||||
if (!transcriptPath || !existsSync(transcriptPath)) {
|
||||
logger.happyPathError(
|
||||
'PARSER',
|
||||
'Transcript path missing or file does not exist',
|
||||
undefined,
|
||||
{ transcriptPath, role },
|
||||
''
|
||||
);
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
const content = readFileSync(transcriptPath, 'utf-8').trim();
|
||||
if (!content) return '';
|
||||
if (!content) {
|
||||
logger.happyPathError(
|
||||
'PARSER',
|
||||
'Transcript file exists but is empty',
|
||||
undefined,
|
||||
{ transcriptPath, role },
|
||||
''
|
||||
);
|
||||
return '';
|
||||
}
|
||||
|
||||
const lines = content.split('\n');
|
||||
let foundMatchingRole = false;
|
||||
|
||||
for (let i = lines.length - 1; i >= 0; i--) {
|
||||
try {
|
||||
const line = JSON.parse(lines[i]);
|
||||
if (line.type === role && line.message?.content) {
|
||||
let text = '';
|
||||
const msgContent = line.message.content;
|
||||
if (line.type === role) {
|
||||
foundMatchingRole = true;
|
||||
|
||||
if (typeof msgContent === 'string') {
|
||||
text = msgContent;
|
||||
} else if (Array.isArray(msgContent)) {
|
||||
text = msgContent
|
||||
.filter((c: any) => c.type === 'text')
|
||||
.map((c: any) => c.text)
|
||||
.join('\n');
|
||||
if (line.message?.content) {
|
||||
let text = '';
|
||||
const msgContent = line.message.content;
|
||||
|
||||
if (typeof msgContent === 'string') {
|
||||
text = msgContent;
|
||||
} else if (Array.isArray(msgContent)) {
|
||||
text = msgContent
|
||||
.filter((c: any) => c.type === 'text')
|
||||
.map((c: any) => c.text)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
if (stripSystemReminders) {
|
||||
text = text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, '');
|
||||
text = text.replace(/\n{3,}/g, '\n\n').trim();
|
||||
}
|
||||
|
||||
// Log if we found the role but the text is empty after processing
|
||||
if (!text || text.trim() === '') {
|
||||
logger.happyPathError(
|
||||
'PARSER',
|
||||
'Found message but content is empty after processing',
|
||||
undefined,
|
||||
{ role, transcriptPath, msgContentType: typeof msgContent, stripSystemReminders },
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
if (stripSystemReminders) {
|
||||
text = text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, '');
|
||||
text = text.replace(/\n{3,}/g, '\n\n').trim();
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If we searched the whole transcript and didn't find any message of this role
|
||||
if (!foundMatchingRole) {
|
||||
logger.happyPathError(
|
||||
'PARSER',
|
||||
'No message found for role in transcript',
|
||||
undefined,
|
||||
{ role, transcriptPath, totalLines: lines.length },
|
||||
''
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('HOOK', 'Failed to read transcript', { transcriptPath }, error as Error);
|
||||
}
|
||||
|
||||
@@ -251,6 +251,58 @@ class Logger {
|
||||
timing(component: Component, message: string, durationMs: number, context?: LogContext): void {
|
||||
this.info(component, `⏱ ${message}`, context, { duration: `${durationMs}ms` });
|
||||
}
|
||||
|
||||
/**
|
||||
* Happy Path Error - logs when the expected "happy path" fails but we have a fallback
|
||||
*
|
||||
* Semantic meaning: "When the happy path fails, this is an error, but we have a fallback."
|
||||
*
|
||||
* Use for:
|
||||
* ✅ Unexpected null/undefined values that should theoretically never happen
|
||||
* ✅ Defensive coding where silent fallback is acceptable
|
||||
* ✅ Situations where you want to track unexpected nulls without breaking execution
|
||||
*
|
||||
* DO NOT use for:
|
||||
* ❌ Nullable fields with valid default behavior (use direct || defaults)
|
||||
* ❌ Critical validation failures (use logger.warn or throw Error)
|
||||
* ❌ Try-catch blocks where error is already logged (redundant)
|
||||
*
|
||||
* @param component - Component where error occurred
|
||||
* @param message - Error message describing what went wrong
|
||||
* @param context - Optional context (sessionId, correlationId, etc)
|
||||
* @param data - Optional data to include
|
||||
* @param fallback - Value to return (defaults to empty string)
|
||||
* @returns The fallback value
|
||||
*/
|
||||
happyPathError<T = string>(
|
||||
component: Component,
|
||||
message: string,
|
||||
context?: LogContext,
|
||||
data?: any,
|
||||
fallback: T = '' as T
|
||||
): T {
|
||||
// Capture stack trace to get caller location
|
||||
const stack = new Error().stack || '';
|
||||
const stackLines = stack.split('\n');
|
||||
// Line 0: "Error"
|
||||
// Line 1: "at happyPathError ..."
|
||||
// Line 2: "at <CALLER> ..." <- We want this one
|
||||
const callerLine = stackLines[2] || '';
|
||||
const callerMatch = callerLine.match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/);
|
||||
const location = callerMatch
|
||||
? `${callerMatch[1].split('/').pop()}:${callerMatch[2]}`
|
||||
: 'unknown';
|
||||
|
||||
// Log as a warning with location info
|
||||
const enhancedContext = {
|
||||
...context,
|
||||
location
|
||||
};
|
||||
|
||||
this.warn(component, `[HAPPY-PATH] ${message}`, enhancedContext, data);
|
||||
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
|
||||
@@ -1,33 +1,16 @@
|
||||
/**
|
||||
* Happy Path Error With Fallback
|
||||
*
|
||||
* Semantic meaning: "When the happy path fails, this is an error, but we have a fallback."
|
||||
* @deprecated This function is deprecated. Use logger.happyPathError() instead.
|
||||
* All usages have been migrated to the new logger system which consolidates logs
|
||||
* into the regular worker logs instead of separate silent.log files.
|
||||
*
|
||||
* Logs to ~/.claude-mem/silent.log and returns a fallback value.
|
||||
* Check logs with `npm run logs:silent`
|
||||
* Migration example:
|
||||
* OLD: happy_path_error__with_fallback('Missing value', { data }, 'default')
|
||||
* NEW: logger.happyPathError('COMPONENT', 'Missing value', undefined, { data }, 'default')
|
||||
*
|
||||
* Use happy_path_error__with_fallback for:
|
||||
* ✅ Unexpected null/undefined values that should theoretically never happen
|
||||
* ✅ Defensive coding where silent fallback is acceptable
|
||||
* ✅ Situations where you want to track unexpected nulls without breaking execution
|
||||
*
|
||||
* DO NOT use for:
|
||||
* ❌ Nullable fields with valid default behavior (use direct || defaults)
|
||||
* ❌ Critical validation failures (use logger.warn or throw Error)
|
||||
* ❌ Try-catch blocks where error is already logged (redundant)
|
||||
*
|
||||
* Good examples:
|
||||
* // Truly unexpected null (should never happen in theory)
|
||||
* const id = session.id || happy_path_error__with_fallback('session.id missing', { session });
|
||||
*
|
||||
* Bad examples (use direct defaults instead):
|
||||
* // Nullable field with valid empty default
|
||||
* const title = obs.title || happy_path_error__with_fallback('obs.title missing', { obs }, '(untitled)');
|
||||
* // BETTER: const title = obs.title || '(untitled)';
|
||||
*
|
||||
* // Array that can validly be undefined/null
|
||||
* const count = obs.files?.length ?? (happy_path_error__with_fallback('obs.files missing', { obs }), 0);
|
||||
* // BETTER: const count = obs.files?.length ?? 0;
|
||||
* See: src/utils/logger.ts for the new happyPathError method
|
||||
* Issue: #312 - Consolidate silent logs into regular worker logs
|
||||
*/
|
||||
|
||||
import { appendFileSync } from 'fs';
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* This keeps the worker service simple and follows one-way data stream.
|
||||
*/
|
||||
|
||||
import { happy_path_error__with_fallback } from './silent-debug.js';
|
||||
import { logger } from './logger.js';
|
||||
|
||||
/**
|
||||
* Maximum number of tags allowed in a single content block
|
||||
@@ -41,14 +41,14 @@ function countTags(content: string): number {
|
||||
*/
|
||||
export function stripMemoryTagsFromJson(content: string): string {
|
||||
if (typeof content !== 'string') {
|
||||
happy_path_error__with_fallback('[tag-stripping] received non-string for JSON context:', { type: typeof content });
|
||||
logger.happyPathError('SYSTEM', 'received non-string for JSON context', undefined, { type: typeof content }, '{}');
|
||||
return '{}'; // Safe default for JSON context
|
||||
}
|
||||
|
||||
// ReDoS protection: limit tag count before regex processing
|
||||
const tagCount = countTags(content);
|
||||
if (tagCount > MAX_TAG_COUNT) {
|
||||
happy_path_error__with_fallback('[tag-stripping] tag count exceeds limit, truncating:', {
|
||||
logger.warn('SYSTEM', 'tag count exceeds limit', undefined, {
|
||||
tagCount,
|
||||
maxAllowed: MAX_TAG_COUNT,
|
||||
contentLength: content.length
|
||||
@@ -73,14 +73,14 @@ export function stripMemoryTagsFromJson(content: string): string {
|
||||
*/
|
||||
export function stripMemoryTagsFromPrompt(content: string): string {
|
||||
if (typeof content !== 'string') {
|
||||
happy_path_error__with_fallback('[tag-stripping] received non-string for prompt context:', { type: typeof content });
|
||||
logger.happyPathError('SYSTEM', 'received non-string for prompt context', undefined, { type: typeof content }, '');
|
||||
return ''; // Safe default for prompt content
|
||||
}
|
||||
|
||||
// ReDoS protection: limit tag count before regex processing
|
||||
const tagCount = countTags(content);
|
||||
if (tagCount > MAX_TAG_COUNT) {
|
||||
happy_path_error__with_fallback('[tag-stripping] tag count exceeds limit, truncating:', {
|
||||
logger.warn('SYSTEM', 'tag count exceeds limit', undefined, {
|
||||
tagCount,
|
||||
maxAllowed: MAX_TAG_COUNT,
|
||||
contentLength: content.length
|
||||
|
||||
Reference in New Issue
Block a user