This repository was archived by the owner on May 15, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Expand file tree
/
Copy pathtaskMetadata.ts
More file actions
122 lines (107 loc) · 3.62 KB
/
Copy pathtaskMetadata.ts
File metadata and controls
122 lines (107 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import NodeCache from "node-cache"
import getFolderSize from "get-folder-size"
import type { ClineMessage, HistoryItem, TaskPermissionsInput } 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 = {
taskId: string
rootTaskId?: string
parentTaskId?: string
taskNumber: number
messages: ClineMessage[]
globalStoragePath: string
workspace: string
mode?: string
/** Provider profile name for the task (sticky profile feature) */
apiConfigName?: string
/** Initial status for the task (e.g., "active" for child tasks) */
initialStatus?: "active" | "delegated" | "completed"
/** Task permissions set by parent via new_task tool, persisted for restart survival */
taskPermissions?: TaskPermissionsInput
}
export async function taskMetadata({
taskId: id,
rootTaskId,
parentTaskId,
taskNumber,
messages,
globalStoragePath,
workspace,
mode,
apiConfigName,
initialStatus,
taskPermissions,
}: TaskMetadataOptions) {
const taskDir = await getTaskDirectoryPath(globalStoragePath, id)
// 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.
// initialStatus is included when provided (e.g., "active" for child tasks)
// to ensure the status is set from the very first save, avoiding race conditions
// where attempt_completion might run before a separate status update.
const historyItem: HistoryItem = {
id,
rootTaskId,
parentTaskId,
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,
...(typeof apiConfigName === "string" && apiConfigName.length > 0 ? { apiConfigName } : {}),
...(initialStatus && { status: initialStatus }),
...(taskPermissions && { taskPermissions }),
}
return { historyItem, tokenUsage }
}