first
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { mkdir } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { getTaskLogsDir } from '@@/data-path';
|
||||
import type { TaskInfo } from '@@/api/chat-types';
|
||||
|
||||
type ChatMessage =
|
||||
| { role: 'user'; text: string }
|
||||
| { role: 'assistant'; text: string }
|
||||
| {
|
||||
role: 'tool';
|
||||
toolName: string;
|
||||
toolInput: Record<string, unknown>;
|
||||
toolUseId: string;
|
||||
output?: string;
|
||||
isError?: boolean;
|
||||
}
|
||||
| { role: 'result'; costUsd: number; durationMs: number; numTurns: number; isError: boolean }
|
||||
| { role: 'error'; text: string };
|
||||
|
||||
type TaskLog = {
|
||||
taskName: string;
|
||||
taskDirName: string;
|
||||
entryName: string;
|
||||
entryType: 'file' | 'directory';
|
||||
provider: string;
|
||||
model: string;
|
||||
startedAt: string;
|
||||
completedAt: string | null;
|
||||
messages: ChatMessage[];
|
||||
};
|
||||
|
||||
type LogEntry = {
|
||||
email: string;
|
||||
filePath: string;
|
||||
log: TaskLog;
|
||||
};
|
||||
|
||||
const activeLogs = new Map<string, LogEntry>();
|
||||
let logCounter = 0;
|
||||
|
||||
export function createTaskLog(email: string, taskInfo: TaskInfo, provider: string, model: string): string {
|
||||
const logId = `log_${Date.now()}_${++logCounter}`;
|
||||
const dir = getTaskLogsDir(email);
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||
const filename = `${timestamp}-${taskInfo.taskDirName}.json`;
|
||||
const filePath = join(dir, filename);
|
||||
|
||||
const log: TaskLog = {
|
||||
taskName: taskInfo.taskName,
|
||||
taskDirName: taskInfo.taskDirName,
|
||||
entryName: taskInfo.entryName,
|
||||
entryType: taskInfo.entryType,
|
||||
provider,
|
||||
model,
|
||||
startedAt: new Date().toISOString(),
|
||||
completedAt: null,
|
||||
messages: [],
|
||||
};
|
||||
|
||||
activeLogs.set(logId, { email, filePath, log });
|
||||
return logId;
|
||||
}
|
||||
|
||||
export function appendToLog(logId: string, message: ChatMessage) {
|
||||
const entry = activeLogs.get(logId);
|
||||
if (!entry) return;
|
||||
|
||||
// For tool results, update the existing tool message instead of appending
|
||||
if (message.role === 'tool' && message.output !== undefined) {
|
||||
const existing = entry.log.messages.find((m) => m.role === 'tool' && m.toolUseId === message.toolUseId);
|
||||
if (existing && existing.role === 'tool') {
|
||||
existing.output = message.output;
|
||||
existing.isError = message.isError;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
entry.log.messages.push(message);
|
||||
}
|
||||
|
||||
export async function finalizeLog(logId: string) {
|
||||
const entry = activeLogs.get(logId);
|
||||
if (!entry) return;
|
||||
|
||||
entry.log.completedAt = new Date().toISOString();
|
||||
|
||||
try {
|
||||
await mkdir(join(entry.filePath, '..'), { recursive: true });
|
||||
await Bun.write(entry.filePath, JSON.stringify(entry.log, null, 2));
|
||||
} catch (err) {
|
||||
console.error('[task-logger] Failed to write log:', err);
|
||||
}
|
||||
|
||||
activeLogs.delete(logId);
|
||||
}
|
||||
Reference in New Issue
Block a user