Skip to content

Commit 02f3636

Browse files
sirkirbyclaude
andcommitted
feat: add component filtering and increase ring buffer capacity
- Add `component` field to `LogQueryOptions` for per-component log filtering - Apply component filter in `LogRingBuffer.since()` before pushing entries - Bump `LOG_RING_BUFFER_CAPACITY` from 1000 to 5000 for increased log producers - Map `category` query param to `component` in the logs API handler Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> feat: enhance hook event logging with info and debug levels Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> feat: enhance context injection logging with info and debug detail Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> feat: route MCP tool activity logging through daemon Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> feat: add component filter chips and increase log capacity in viewer Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> feat: add logging audit points across pipeline, consolidation, digest, and lifecycle Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> refactor: code review cleanup for logging enhancement - Extract LOG_PROMPT_PREVIEW_CHARS and LOG_MESSAGE_PREVIEW_CHARS constants - Merge duplicate log lines (consolidation, extraction, embedding) - Deduplicate session register and stop event logs - Cache daemon port in MCP server's postToDaemon (avoid fs reads per call) - Add DaemonLogger.log() method to eliminate duplicated dispatch pattern - Move LEVEL_ORDER/LOG_LEVELS to shared ui/src/lib/constants.ts - Make availableCategories incremental instead of full-scan on every poll - Move searchStart after early-return guard - Use DAEMON_CLIENT_TIMEOUT_MS constant in MCP server - Remove redundant inline comment in api/logs.ts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> feat: enhance operation handling with force digest capability - Added `onForceDigest` callback to `OperationHandlerDeps` to signal metabolism timer for bypassing substrate threshold. - Updated `handleDigest` function to trigger full cycle processing when `options.full` is set and `onForceDigest` is provided, ensuring items are reset to pending status. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent eb41ade commit 02f3636

File tree

13 files changed

+352
-56
lines changed

13 files changed

+352
-56
lines changed

src/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ export const SESSION_SUMMARY_PREVIEW_CHARS = 300;
3333
/** Max chars for a recall summary preview. */
3434
export const RECALL_SUMMARY_PREVIEW_CHARS = 200;
3535

36+
// --- Log preview limits (short previews for structured log fields) ---
37+
/** Max chars for a user prompt preview in log entries. */
38+
export const LOG_PROMPT_PREVIEW_CHARS = 50;
39+
/** Max chars for an assistant message preview in log entries. */
40+
export const LOG_MESSAGE_PREVIEW_CHARS = 80;
41+
3642
// --- Context injection layer budgets (chars, not tokens — used with .slice()) ---
3743
export const CONTEXT_PLAN_PREVIEW_CHARS = 100;
3844
export const CONTEXT_SESSION_PREVIEW_CHARS = 80;

src/daemon/api/logs.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ export async function handleGetLogs(
99
const since = query.since || null;
1010
const level = query.level as LogLevel | undefined;
1111
const limit = query.limit ? parseInt(query.limit, 10) : undefined;
12+
const component = query.category || undefined;
1213

13-
const result = ringBuffer.since(since, { level, limit: isNaN(limit as number) ? undefined : limit });
14+
const result = ringBuffer.since(since, { level, component, limit: isNaN(limit as number) ? undefined : limit });
1415

1516
// Map `component` to `category` in the response entries —
1617
// the logger uses `component` internally; the API spec uses `category`

src/daemon/api/operations.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ export interface OperationHandlerDeps {
3636
embeddingProvider: EmbeddingProvider;
3737
progressTracker: ProgressTracker;
3838
pipeline?: PipelineManager;
39+
/** Signal the metabolism timer to bypass the substrate threshold on next tick. */
40+
onForceDigest?: () => void;
3941
log: (level: string, message: string, data?: Record<string, unknown>) => void;
4042
}
4143

@@ -156,6 +158,15 @@ export async function handleDigest(
156158
tiers: result.tiersGenerated,
157159
duration: result.durationMs,
158160
});
161+
} else if (options?.full && deps.onForceDigest) {
162+
// Full cycle deferred to metabolism timer — signal it to bypass
163+
// the substrate threshold so the reset items actually get processed.
164+
deps.onForceDigest();
165+
deps.progressTracker.update(token, {
166+
status: 'completed',
167+
percent: PROGRESS_COMPLETE,
168+
message: 'Full cycle queued — items reset to pending',
169+
});
159170
} else {
160171
deps.progressTracker.update(token, {
161172
status: 'completed',

src/daemon/consolidation.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ export class ConsolidationEngine {
226226
}
227227

228228
clustersFound++;
229+
this.log('debug', 'Consolidation groups formed', {
230+
group_count: clustersFound,
231+
total_notes: cluster.length,
232+
});
229233

230234
// Build consolidation prompt
231235
const candidatesText = formatNotesForPrompt(cluster);
@@ -319,10 +323,11 @@ export class ConsolidationEngine {
319323
consolidated++;
320324
sporesSuperseded += consolidateResult.sources_archived;
321325

322-
this.log('info', 'ConsolidationEngine: consolidated cluster', {
326+
this.log('info', 'Notes consolidated', {
323327
wisdomId: consolidateResult.wisdom_id,
324328
sourcesArchived: consolidateResult.sources_archived,
325329
clusterSize: cluster.length,
330+
similarity: vectorResults[0]?.similarity ?? 0,
326331
});
327332
} catch (err) {
328333
this.log('warn', 'ConsolidationEngine: consolidateSpores failed', {
@@ -334,6 +339,10 @@ export class ConsolidationEngine {
334339
cluster.forEach((n) => processedIds.add(n.id));
335340
}
336341

342+
if (clustersFound === 0) {
343+
this.log('debug', 'Consolidation: no groups above threshold');
344+
}
345+
337346
const passTimestamp = new Date().toISOString();
338347
const durationMs = Date.now() - startTime;
339348

src/daemon/digest.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,14 @@ export class DigestEngine {
339339
}
340340
}
341341

342+
this.log('debug', 'Substrate breakdown', {
343+
sessions: substrateIndex.sessions.length,
344+
spores: substrateIndex.spores.length,
345+
plans: substrateIndex.plans.length,
346+
artifacts: substrateIndex.artifacts.length,
347+
team: substrateIndex.team.length,
348+
});
349+
342350
// Record the cycle timestamp NOW, before tier processing. This ensures the
343351
// timestamp advances even if LLM calls fail, preventing the same substrate
344352
// from being rediscovered on every subsequent timer fire.

src/daemon/log-buffer.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { LogEntry, LogLevel } from './logger.js';
22
import { LEVEL_ORDER } from './logger.js';
33

4-
const LOG_RING_BUFFER_CAPACITY = 1000;
4+
const LOG_RING_BUFFER_CAPACITY = 5000;
55
const LOG_QUERY_DEFAULT_LIMIT = 100;
66

77
interface LogQueryResult {
@@ -12,6 +12,7 @@ interface LogQueryResult {
1212

1313
interface LogQueryOptions {
1414
level?: LogLevel;
15+
component?: string;
1516
limit?: number;
1617
}
1718

@@ -64,6 +65,7 @@ export class LogRingBuffer {
6465
const bufIdx = (this.head - this.count + i + this.capacity) % this.capacity;
6566
const entry = this.buffer[bufIdx];
6667
if (entry && LEVEL_ORDER[entry.level as LogLevel] >= minLevel) {
68+
if (options?.component && entry.component !== options.component) continue;
6769
entries.push(entry);
6870
}
6971
}

src/daemon/logger.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ export class DaemonLogger {
6565
this.write('error', component, message, data);
6666
}
6767

68+
/** Dispatch a log entry by dynamic level string. */
69+
log(level: string, component: string, message: string, data?: Record<string, unknown>): void {
70+
if (level in LEVEL_ORDER) {
71+
this.write(level as LogLevel, component, message, data);
72+
}
73+
}
74+
6875
close(): void {
6976
if (this.fd !== null) {
7077
fs.closeSync(this.fd);

0 commit comments

Comments
 (0)