mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-15 23:31:04 +00:00
- Add parentTaskId, childTaskIds, and taskStatus fields to HistoryItem schema - Remove in-memory task stack (clineStack) from ClineProvider - Replace polling mechanism with direct task resumption - Update task persistence to include new relationship fields - Implement persistent task management using task status field This refactor eliminates CPU waste from polling, simplifies code by removing unnecessary complexity, enables task resumption after system restarts, and provides a foundation for task tree visualization. Fixes #6672
110 lines
2.9 KiB
TypeScript
110 lines
2.9 KiB
TypeScript
import NodeCache from "node-cache"
|
|
import getFolderSize from "get-folder-size"
|
|
|
|
import type { ClineMessage, HistoryItem } from "@roo-code/types"
|
|
|
|
import { combineApiRequests } from "../../shared/combineApiRequests"
|
|
import { combineCommandSequences } from "../../shared/combineCommandSequences"
|
|
import { getApiMetrics } from "../../shared/getApiMetrics"
|
|
import { findLastIndex } from "../../shared/array"
|
|
import { getTaskDirectoryPath } from "../../utils/storage"
|
|
import { t } from "../../i18n"
|
|
|
|
const taskSizeCache = new NodeCache({ stdTTL: 30, checkperiod: 5 * 60 })
|
|
|
|
export type TaskMetadataOptions = {
|
|
messages: ClineMessage[]
|
|
taskId: string
|
|
taskNumber: number
|
|
globalStoragePath: string
|
|
workspace: string
|
|
mode?: string
|
|
parentTaskId?: string
|
|
childTaskIds?: string[]
|
|
taskStatus?: "active" | "paused" | "completed"
|
|
}
|
|
|
|
export async function taskMetadata({
|
|
messages,
|
|
taskId,
|
|
taskNumber,
|
|
globalStoragePath,
|
|
workspace,
|
|
mode,
|
|
parentTaskId,
|
|
childTaskIds,
|
|
taskStatus,
|
|
}: TaskMetadataOptions) {
|
|
const taskDir = await getTaskDirectoryPath(globalStoragePath, taskId)
|
|
|
|
// Determine message availability upfront
|
|
const hasMessages = messages && messages.length > 0
|
|
|
|
// Pre-calculate all values based on availability
|
|
let timestamp: number
|
|
let tokenUsage: ReturnType<typeof getApiMetrics>
|
|
let taskDirSize: number
|
|
let taskMessage: ClineMessage | undefined
|
|
|
|
if (!hasMessages) {
|
|
// Handle no messages case
|
|
timestamp = Date.now()
|
|
tokenUsage = {
|
|
totalTokensIn: 0,
|
|
totalTokensOut: 0,
|
|
totalCacheWrites: 0,
|
|
totalCacheReads: 0,
|
|
totalCost: 0,
|
|
contextTokens: 0,
|
|
}
|
|
taskDirSize = 0
|
|
} else {
|
|
// Handle messages case
|
|
taskMessage = messages[0] // First message is always the task say.
|
|
|
|
const lastRelevantMessage =
|
|
messages[findLastIndex(messages, (m) => !(m.ask === "resume_task" || m.ask === "resume_completed_task"))] ||
|
|
taskMessage
|
|
|
|
timestamp = lastRelevantMessage.ts
|
|
|
|
tokenUsage = getApiMetrics(combineApiRequests(combineCommandSequences(messages.slice(1))))
|
|
|
|
// Get task directory size
|
|
const cachedSize = taskSizeCache.get<number>(taskDir)
|
|
|
|
if (cachedSize === undefined) {
|
|
try {
|
|
taskDirSize = await getFolderSize.loose(taskDir)
|
|
taskSizeCache.set<number>(taskDir, taskDirSize)
|
|
} catch (error) {
|
|
taskDirSize = 0
|
|
}
|
|
} else {
|
|
taskDirSize = cachedSize
|
|
}
|
|
}
|
|
|
|
// Create historyItem once with pre-calculated values
|
|
const historyItem: HistoryItem = {
|
|
id: taskId,
|
|
number: taskNumber,
|
|
ts: timestamp,
|
|
task: hasMessages
|
|
? taskMessage!.text?.trim() || t("common:tasks.incomplete", { taskNumber })
|
|
: t("common:tasks.no_messages", { taskNumber }),
|
|
tokensIn: tokenUsage.totalTokensIn,
|
|
tokensOut: tokenUsage.totalTokensOut,
|
|
cacheWrites: tokenUsage.totalCacheWrites,
|
|
cacheReads: tokenUsage.totalCacheReads,
|
|
totalCost: tokenUsage.totalCost,
|
|
size: taskDirSize,
|
|
workspace,
|
|
mode,
|
|
parentTaskId,
|
|
childTaskIds,
|
|
taskStatus,
|
|
}
|
|
|
|
return { historyItem, tokenUsage }
|
|
}
|