Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions plugin/ui/viewer-bundle.js

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions plugin/ui/viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,17 @@
color: var(--color-text-muted);
}

/* Model badge styling */
.card-model {
font-size: 10px;
padding: 1px 6px;
border-radius: 3px;
background: var(--color-type-badge-bg);
color: var(--color-type-badge-text);
font-weight: 500;
opacity: 0.8;
}

.summary-card {
border-color: var(--color-border-summary);
background: var(--color-bg-summary);
Expand Down
37 changes: 22 additions & 15 deletions src/services/sqlite/SessionStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1003,9 +1003,10 @@ export class SessionStore {
prompt_number: number | null;
created_at: string;
created_at_epoch: number;
model: string | null;
}> {
const stmt = this.db.prepare(`
SELECT id, type, title, subtitle, text, project, prompt_number, created_at, created_at_epoch
SELECT id, type, title, subtitle, text, project, prompt_number, created_at, created_at_epoch, model
FROM observations
ORDER BY created_at_epoch DESC
LIMIT ?
Expand Down Expand Up @@ -1649,7 +1650,8 @@ export class SessionStore {
} | null,
promptNumber?: number,
discoveryTokens: number = 0,
overrideTimestampEpoch?: number
overrideTimestampEpoch?: number,
model?: string | null
): { observationIds: number[]; summaryId: number | null; createdAtEpoch: number } {
// Use override timestamp if provided
const timestampEpoch = overrideTimestampEpoch ?? Date.now();
Expand All @@ -1663,8 +1665,8 @@ export class SessionStore {
const obsStmt = this.db.prepare(`
INSERT INTO observations
(memory_session_id, project, type, title, subtitle, facts, narrative, concepts,
files_read, files_modified, prompt_number, discovery_tokens, created_at, created_at_epoch)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
files_read, files_modified, prompt_number, discovery_tokens, created_at, created_at_epoch, model)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);

for (const observation of observations) {
Expand All @@ -1682,7 +1684,8 @@ export class SessionStore {
promptNumber || null,
discoveryTokens,
timestampIso,
timestampEpoch
timestampEpoch,
model || null
);
observationIds.push(Number(result.lastInsertRowid));
}
Expand All @@ -1693,8 +1696,8 @@ export class SessionStore {
const summaryStmt = this.db.prepare(`
INSERT INTO session_summaries
(memory_session_id, project, request, investigated, learned, completed,
next_steps, notes, prompt_number, discovery_tokens, created_at, created_at_epoch)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
next_steps, notes, prompt_number, discovery_tokens, created_at, created_at_epoch, model)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);

const result = summaryStmt.run(
Expand All @@ -1709,7 +1712,8 @@ export class SessionStore {
promptNumber || null,
discoveryTokens,
timestampIso,
timestampEpoch
timestampEpoch,
model || null
);
summaryId = Number(result.lastInsertRowid);
}
Expand Down Expand Up @@ -1769,7 +1773,8 @@ export class SessionStore {
_pendingStore: PendingMessageStore,
promptNumber?: number,
discoveryTokens: number = 0,
overrideTimestampEpoch?: number
overrideTimestampEpoch?: number,
model?: string | null
): { observationIds: number[]; summaryId?: number; createdAtEpoch: number } {
// Use override timestamp if provided
const timestampEpoch = overrideTimestampEpoch ?? Date.now();
Expand All @@ -1783,8 +1788,8 @@ export class SessionStore {
const obsStmt = this.db.prepare(`
INSERT INTO observations
(memory_session_id, project, type, title, subtitle, facts, narrative, concepts,
files_read, files_modified, prompt_number, discovery_tokens, created_at, created_at_epoch)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
files_read, files_modified, prompt_number, discovery_tokens, created_at, created_at_epoch, model)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);

for (const observation of observations) {
Expand All @@ -1802,7 +1807,8 @@ export class SessionStore {
promptNumber || null,
discoveryTokens,
timestampIso,
timestampEpoch
timestampEpoch,
model || null
);
observationIds.push(Number(result.lastInsertRowid));
}
Expand All @@ -1813,8 +1819,8 @@ export class SessionStore {
const summaryStmt = this.db.prepare(`
INSERT INTO session_summaries
(memory_session_id, project, request, investigated, learned, completed,
next_steps, notes, prompt_number, discovery_tokens, created_at, created_at_epoch)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
next_steps, notes, prompt_number, discovery_tokens, created_at, created_at_epoch, model)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);

const result = summaryStmt.run(
Expand All @@ -1829,7 +1835,8 @@ export class SessionStore {
promptNumber || null,
discoveryTokens,
timestampIso,
timestampEpoch
timestampEpoch,
model || null
);
summaryId = Number(result.lastInsertRowid);
}
Expand Down
24 changes: 24 additions & 0 deletions src/services/sqlite/migrations/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export class MigrationRunner {
this.addOnUpdateCascadeToForeignKeys();
this.addObservationContentHashColumn();
this.addSessionCustomTitleColumn();
this.addModelColumn();
}

/**
Expand Down Expand Up @@ -859,4 +860,27 @@ export class MigrationRunner {

this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(23, new Date().toISOString());
}

/**
* Add model column to observations and session_summaries (migration 24)
* Records which AI model produced each observation/summary for comparison.
*/
private addModelColumn(): void {
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(24) as SchemaVersion | undefined;
if (applied) return;

const obsInfo = this.db.query('PRAGMA table_info(observations)').all() as TableColumnInfo[];
if (!obsInfo.some(col => col.name === 'model')) {
this.db.run('ALTER TABLE observations ADD COLUMN model TEXT');
logger.debug('DB', 'Added model column to observations table');
}

const sumInfo = this.db.query('PRAGMA table_info(session_summaries)').all() as TableColumnInfo[];
if (!sumInfo.some(col => col.name === 'model')) {
this.db.run('ALTER TABLE session_summaries ADD COLUMN model TEXT');
logger.debug('DB', 'Added model column to session_summaries table');
}

this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(24, new Date().toISOString());
}
}
2 changes: 1 addition & 1 deletion src/services/sqlite/observations/recent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function getAllRecentObservations(
limit: number = 100
): AllRecentObservationRow[] {
const stmt = db.prepare(`
SELECT id, type, title, subtitle, text, project, prompt_number, created_at, created_at_epoch
SELECT id, type, title, subtitle, text, project, prompt_number, created_at, created_at_epoch, model
FROM observations
ORDER BY created_at_epoch DESC
LIMIT ?
Expand Down
10 changes: 6 additions & 4 deletions src/services/sqlite/observations/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ export function storeObservation(
observation: ObservationInput,
promptNumber?: number,
discoveryTokens: number = 0,
overrideTimestampEpoch?: number
overrideTimestampEpoch?: number,
model?: string | null
): StoreObservationResult {
// Use override timestamp if provided (for processing backlog messages with original timestamps)
const timestampEpoch = overrideTimestampEpoch ?? Date.now();
Expand All @@ -75,8 +76,8 @@ export function storeObservation(
const stmt = db.prepare(`
INSERT INTO observations
(memory_session_id, project, type, title, subtitle, facts, narrative, concepts,
files_read, files_modified, prompt_number, discovery_tokens, content_hash, created_at, created_at_epoch)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
files_read, files_modified, prompt_number, discovery_tokens, content_hash, created_at, created_at_epoch, model)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);

const result = stmt.run(
Expand All @@ -94,7 +95,8 @@ export function storeObservation(
discoveryTokens,
contentHash,
timestampIso,
timestampEpoch
timestampEpoch,
model || null
);

return {
Expand Down
1 change: 1 addition & 0 deletions src/services/sqlite/observations/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,5 @@ export interface AllRecentObservationRow {
prompt_number: number | null;
created_at: string;
created_at_epoch: number;
model: string | null;
}
10 changes: 6 additions & 4 deletions src/services/sqlite/summaries/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export function storeSummary(
summary: SummaryInput,
promptNumber?: number,
discoveryTokens: number = 0,
overrideTimestampEpoch?: number
overrideTimestampEpoch?: number,
model?: string | null
): StoreSummaryResult {
// Use override timestamp if provided (for processing backlog messages with original timestamps)
const timestampEpoch = overrideTimestampEpoch ?? Date.now();
Expand All @@ -33,8 +34,8 @@ export function storeSummary(
const stmt = db.prepare(`
INSERT INTO session_summaries
(memory_session_id, project, request, investigated, learned, completed,
next_steps, notes, prompt_number, discovery_tokens, created_at, created_at_epoch)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
next_steps, notes, prompt_number, discovery_tokens, created_at, created_at_epoch, model)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);

const result = stmt.run(
Expand All @@ -49,7 +50,8 @@ export function storeSummary(
promptNumber || null,
discoveryTokens,
timestampIso,
timestampEpoch
timestampEpoch,
model || null
);

return {
Expand Down
5 changes: 3 additions & 2 deletions src/services/worker/PaginationHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class PaginationHelper {
getObservations(offset: number, limit: number, project?: string): PaginatedResult<Observation> {
const result = this.paginate<Observation>(
'observations',
'id, memory_session_id, project, type, title, subtitle, narrative, text, facts, concepts, files_read, files_modified, prompt_number, created_at, created_at_epoch',
'id, memory_session_id, project, type, title, subtitle, narrative, text, facts, concepts, files_read, files_modified, prompt_number, created_at, created_at_epoch, model',
offset,
limit,
project
Expand Down Expand Up @@ -104,7 +104,8 @@ export class PaginationHelper {
ss.next_steps,
ss.project,
ss.created_at,
ss.created_at_epoch
ss.created_at_epoch,
ss.model
FROM session_summaries ss
JOIN sdk_sessions s ON ss.memory_session_id = s.memory_session_id
`;
Expand Down
7 changes: 6 additions & 1 deletion src/services/worker/agents/ResponseProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ export async function processAgentResponse(
memorySessionId: session.memorySessionId
});

// Read the active model from settings for attribution
const settings = SettingsDefaultsManager.loadFromFile(USER_SETTINGS_PATH);
const activeModel = settings.CLAUDE_MEM_MODEL || null;

// ATOMIC TRANSACTION: Store observations + summary ONCE
// Messages are already deleted from queue on claim, so no completion tracking needed
const result = sessionStore.storeObservations(
Expand All @@ -102,7 +106,8 @@ export async function processAgentResponse(
summaryForStore,
session.lastPromptNumber,
discoveryTokens,
originalTimestamp ?? undefined
originalTimestamp ?? undefined,
activeModel
);

// Log storage result with IDs for end-to-end traceability
Expand Down
2 changes: 2 additions & 0 deletions src/types/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export interface ObservationRecord {
source_files?: string;
prompt_number?: number;
discovery_tokens?: number;
model?: string;
}

/**
Expand All @@ -92,6 +93,7 @@ export interface SessionSummaryRecord {
created_at_epoch: number;
prompt_number?: number;
discovery_tokens?: number;
model?: string;
}

/**
Expand Down
11 changes: 11 additions & 0 deletions src/ui/viewer-template.html
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,17 @@
color: var(--color-text-muted);
}

/* Model badge styling */
.card-model {
font-size: 10px;
padding: 1px 6px;
border-radius: 3px;
background: var(--color-type-badge-bg);
color: var(--color-type-badge-text);
font-weight: 500;
opacity: 0.8;
}

.summary-card {
border-color: var(--color-border-summary);
background: var(--color-bg-summary);
Expand Down
3 changes: 3 additions & 0 deletions src/ui/viewer/components/ObservationCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ export function ObservationCard({ observation }: ObservationCardProps) {
{observation.type}
</span>
<span className="card-project">{observation.project}</span>
{observation.model && (
<span className="card-model">{observation.model}</span>
)}
</div>
<div className="view-mode-toggles">
{hasFactsContent && (
Expand Down
3 changes: 3 additions & 0 deletions src/ui/viewer/components/SummaryCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export function SummaryCard({ summary }: SummaryCardProps) {
<div className="summary-badge-row">
<span className="card-type summary-badge">Session Summary</span>
<span className="summary-project-badge">{summary.project}</span>
{summary.model && (
<span className="card-model">{summary.model}</span>
)}
</div>
{summary.request && (
<h2 className="summary-title">{summary.request}</h2>
Expand Down
2 changes: 2 additions & 0 deletions src/ui/viewer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface Observation {
files_read: string | null;
files_modified: string | null;
prompt_number: number | null;
model: string | null;
created_at: string;
created_at_epoch: number;
}
Expand All @@ -25,6 +26,7 @@ export interface Summary {
learned?: string;
completed?: string;
next_steps?: string;
model?: string;
created_at_epoch: number;
}

Expand Down
Loading