Skip to content

Commit 3cbdbc2

Browse files
roomote[bot]ellipsis-dev[bot]roomotedaniel-lxs
authored
feat: add settings to configure time and cost in system prompt (#8451)
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: Roo Code <[email protected]> Co-authored-by: daniel-lxs <[email protected]> Co-authored-by: Daniel <[email protected]>
1 parent fceb413 commit 3cbdbc2

27 files changed

+254
-14
lines changed

packages/types/src/global-settings.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ export const globalSettingsSchema = z.object({
9393
autoCondenseContextPercent: z.number().optional(),
9494
maxConcurrentFileReads: z.number().optional(),
9595

96+
/**
97+
* Whether to include current time in the environment details
98+
* @default true
99+
*/
100+
includeCurrentTime: z.boolean().optional(),
101+
/**
102+
* Whether to include current cost in the environment details
103+
* @default true
104+
*/
105+
includeCurrentCost: z.boolean().optional(),
106+
96107
/**
97108
* Whether to include diagnostic messages (errors, warnings) in tool outputs
98109
* @default true

src/core/environment/getEnvironmentDetails.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -190,21 +190,28 @@ export async function getEnvironmentDetails(cline: Task, includeFileDetails: boo
190190
details += terminalDetails
191191
}
192192

193-
// Add current time information with timezone.
194-
const now = new Date()
195-
196-
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
197-
const timeZoneOffset = -now.getTimezoneOffset() / 60 // Convert to hours and invert sign to match conventional notation
198-
const timeZoneOffsetHours = Math.floor(Math.abs(timeZoneOffset))
199-
const timeZoneOffsetMinutes = Math.abs(Math.round((Math.abs(timeZoneOffset) - timeZoneOffsetHours) * 60))
200-
const timeZoneOffsetStr = `${timeZoneOffset >= 0 ? "+" : "-"}${timeZoneOffsetHours}:${timeZoneOffsetMinutes.toString().padStart(2, "0")}`
201-
details += `\n\n# Current Time\nCurrent time in ISO 8601 UTC format: ${now.toISOString()}\nUser time zone: ${timeZone}, UTC${timeZoneOffsetStr}`
202-
203-
// Add context tokens information.
204-
const { contextTokens, totalCost } = getApiMetrics(cline.clineMessages)
205-
const { id: modelId } = cline.api.getModel()
193+
// Get settings for time and cost display
194+
const { includeCurrentTime = true, includeCurrentCost = true } = state ?? {}
195+
196+
// Add current time information with timezone (if enabled).
197+
if (includeCurrentTime) {
198+
const now = new Date()
199+
200+
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
201+
const timeZoneOffset = -now.getTimezoneOffset() / 60 // Convert to hours and invert sign to match conventional notation
202+
const timeZoneOffsetHours = Math.floor(Math.abs(timeZoneOffset))
203+
const timeZoneOffsetMinutes = Math.abs(Math.round((Math.abs(timeZoneOffset) - timeZoneOffsetHours) * 60))
204+
const timeZoneOffsetStr = `${timeZoneOffset >= 0 ? "+" : "-"}${timeZoneOffsetHours}:${timeZoneOffsetMinutes.toString().padStart(2, "0")}`
205+
details += `\n\n# Current Time\nCurrent time in ISO 8601 UTC format: ${now.toISOString()}\nUser time zone: ${timeZone}, UTC${timeZoneOffsetStr}`
206+
}
206207

207-
details += `\n\n# Current Cost\n${totalCost !== null ? `$${totalCost.toFixed(2)}` : "(Not available)"}`
208+
// Add context tokens information (if enabled).
209+
if (includeCurrentCost) {
210+
const { totalCost } = getApiMetrics(cline.clineMessages)
211+
details += `\n\n# Current Cost\n${totalCost !== null ? `$${totalCost.toFixed(2)}` : "(Not available)"}`
212+
}
213+
214+
const { id: modelId } = cline.api.getModel()
208215

209216
// Add current mode and any mode-specific warnings.
210217
const {

src/core/webview/ClineProvider.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,6 +1813,8 @@ export class ClineProvider
18131813
includeDiagnosticMessages,
18141814
maxDiagnosticMessages,
18151815
includeTaskHistoryInEnhance,
1816+
includeCurrentTime,
1817+
includeCurrentCost,
18161818
taskSyncEnabled,
18171819
remoteControlEnabled,
18181820
openRouterImageApiKey,
@@ -1961,6 +1963,8 @@ export class ClineProvider
19611963
includeDiagnosticMessages: includeDiagnosticMessages ?? true,
19621964
maxDiagnosticMessages: maxDiagnosticMessages ?? 50,
19631965
includeTaskHistoryInEnhance: includeTaskHistoryInEnhance ?? true,
1966+
includeCurrentTime: includeCurrentTime ?? true,
1967+
includeCurrentCost: includeCurrentCost ?? true,
19641968
taskSyncEnabled,
19651969
remoteControlEnabled,
19661970
openRouterImageApiKey,
@@ -2173,6 +2177,8 @@ export class ClineProvider
21732177
includeDiagnosticMessages: stateValues.includeDiagnosticMessages ?? true,
21742178
maxDiagnosticMessages: stateValues.maxDiagnosticMessages ?? 50,
21752179
includeTaskHistoryInEnhance: stateValues.includeTaskHistoryInEnhance ?? true,
2180+
includeCurrentTime: stateValues.includeCurrentTime ?? true,
2181+
includeCurrentCost: stateValues.includeCurrentCost ?? true,
21762182
taskSyncEnabled,
21772183
remoteControlEnabled: (() => {
21782184
try {

src/core/webview/webviewMessageHandler.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,6 +1658,14 @@ export const webviewMessageHandler = async (
16581658
await updateGlobalState("includeDiagnosticMessages", includeValue)
16591659
await provider.postStateToWebview()
16601660
break
1661+
case "includeCurrentTime":
1662+
await updateGlobalState("includeCurrentTime", message.bool ?? true)
1663+
await provider.postStateToWebview()
1664+
break
1665+
case "includeCurrentCost":
1666+
await updateGlobalState("includeCurrentCost", message.bool ?? true)
1667+
await provider.postStateToWebview()
1668+
break
16611669
case "maxDiagnosticMessages":
16621670
await updateGlobalState("maxDiagnosticMessages", message.value ?? 50)
16631671
await provider.postStateToWebview()

src/shared/ExtensionMessage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ export type ExtensionState = Pick<
294294
| "openRouterImageGenerationSelectedModel"
295295
| "includeTaskHistoryInEnhance"
296296
| "reasoningBlockCollapsed"
297+
| "includeCurrentTime"
298+
| "includeCurrentCost"
297299
> & {
298300
version: string
299301
clineMessages: ClineMessage[]

src/shared/WebviewMessage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ export interface WebviewMessage {
177177
| "maxConcurrentFileReads"
178178
| "includeDiagnosticMessages"
179179
| "maxDiagnosticMessages"
180+
| "includeCurrentTime"
181+
| "includeCurrentCost"
180182
| "searchFiles"
181183
| "toggleApiConfigPin"
182184
| "setHistoryPreviewCollapsed"

webview-ui/src/components/settings/ContextManagementSettings.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
2727
includeDiagnosticMessages?: boolean
2828
maxDiagnosticMessages?: number
2929
writeDelayMs: number
30+
includeCurrentTime?: boolean
31+
includeCurrentCost?: boolean
3032
setCachedStateField: SetCachedStateField<
3133
| "autoCondenseContext"
3234
| "autoCondenseContextPercent"
@@ -41,6 +43,8 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
4143
| "includeDiagnosticMessages"
4244
| "maxDiagnosticMessages"
4345
| "writeDelayMs"
46+
| "includeCurrentTime"
47+
| "includeCurrentCost"
4448
>
4549
}
4650

@@ -60,6 +64,8 @@ export const ContextManagementSettings = ({
6064
includeDiagnosticMessages,
6165
maxDiagnosticMessages,
6266
writeDelayMs,
67+
includeCurrentTime,
68+
includeCurrentCost,
6369
className,
6470
...props
6571
}: ContextManagementSettingsProps) => {
@@ -356,6 +362,34 @@ export const ContextManagementSettings = ({
356362
{t("settings:contextManagement.diagnostics.delayAfterWrite.description")}
357363
</div>
358364
</div>
365+
366+
<div>
367+
<VSCodeCheckbox
368+
checked={includeCurrentTime}
369+
onChange={(e: any) => setCachedStateField("includeCurrentTime", e.target.checked)}
370+
data-testid="include-current-time-checkbox">
371+
<label className="block font-medium mb-1">
372+
{t("settings:contextManagement.includeCurrentTime.label")}
373+
</label>
374+
</VSCodeCheckbox>
375+
<div className="text-vscode-descriptionForeground text-sm mt-1 mb-3">
376+
{t("settings:contextManagement.includeCurrentTime.description")}
377+
</div>
378+
</div>
379+
380+
<div>
381+
<VSCodeCheckbox
382+
checked={includeCurrentCost}
383+
onChange={(e: any) => setCachedStateField("includeCurrentCost", e.target.checked)}
384+
data-testid="include-current-cost-checkbox">
385+
<label className="block font-medium mb-1">
386+
{t("settings:contextManagement.includeCurrentCost.label")}
387+
</label>
388+
</VSCodeCheckbox>
389+
<div className="text-vscode-descriptionForeground text-sm mt-1 mb-3">
390+
{t("settings:contextManagement.includeCurrentCost.description")}
391+
</div>
392+
</div>
359393
</Section>
360394
<Section className="pt-2">
361395
<VSCodeCheckbox

webview-ui/src/components/settings/SettingsView.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
196196
openRouterImageApiKey,
197197
openRouterImageGenerationSelectedModel,
198198
reasoningBlockCollapsed,
199+
includeCurrentTime,
200+
includeCurrentCost,
199201
} = cachedState
200202

201203
const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration])
@@ -386,6 +388,8 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
386388
vscode.postMessage({ type: "updateSupportPrompt", values: customSupportPrompts || {} })
387389
vscode.postMessage({ type: "includeTaskHistoryInEnhance", bool: includeTaskHistoryInEnhance ?? true })
388390
vscode.postMessage({ type: "setReasoningBlockCollapsed", bool: reasoningBlockCollapsed ?? true })
391+
vscode.postMessage({ type: "includeCurrentTime", bool: includeCurrentTime ?? true })
392+
vscode.postMessage({ type: "includeCurrentCost", bool: includeCurrentCost ?? true })
389393
vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration })
390394
vscode.postMessage({ type: "telemetrySetting", text: telemetrySetting })
391395
vscode.postMessage({ type: "profileThresholds", values: profileThresholds })
@@ -747,6 +751,8 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
747751
includeDiagnosticMessages={includeDiagnosticMessages}
748752
maxDiagnosticMessages={maxDiagnosticMessages}
749753
writeDelayMs={writeDelayMs}
754+
includeCurrentTime={includeCurrentTime}
755+
includeCurrentCost={includeCurrentCost}
750756
setCachedStateField={setCachedStateField}
751757
/>
752758
)}

webview-ui/src/context/ExtensionStateContext.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ export interface ExtensionStateContextType extends ExtensionState {
161161
setMaxDiagnosticMessages: (value: number) => void
162162
includeTaskHistoryInEnhance?: boolean
163163
setIncludeTaskHistoryInEnhance: (value: boolean) => void
164+
includeCurrentTime?: boolean
165+
setIncludeCurrentTime: (value: boolean) => void
166+
includeCurrentCost?: boolean
167+
setIncludeCurrentCost: (value: boolean) => void
164168
}
165169

166170
export const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
@@ -270,6 +274,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
270274
maxDiagnosticMessages: 50,
271275
openRouterImageApiKey: "",
272276
openRouterImageGenerationSelectedModel: "",
277+
includeCurrentTime: true,
278+
includeCurrentCost: true,
273279
})
274280

275281
const [didHydrateState, setDidHydrateState] = useState(false)
@@ -290,6 +296,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
290296
})
291297
const [includeTaskHistoryInEnhance, setIncludeTaskHistoryInEnhance] = useState(true)
292298
const [prevCloudIsAuthenticated, setPrevCloudIsAuthenticated] = useState(false)
299+
const [includeCurrentTime, setIncludeCurrentTime] = useState(true)
300+
const [includeCurrentCost, setIncludeCurrentCost] = useState(true)
293301

294302
const setListApiConfigMeta = useCallback(
295303
(value: ProviderSettingsEntry[]) => setState((prevState) => ({ ...prevState, listApiConfigMeta: value })),
@@ -327,6 +335,14 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
327335
if ((newState as any).includeTaskHistoryInEnhance !== undefined) {
328336
setIncludeTaskHistoryInEnhance((newState as any).includeTaskHistoryInEnhance)
329337
}
338+
// Update includeCurrentTime if present in state message
339+
if ((newState as any).includeCurrentTime !== undefined) {
340+
setIncludeCurrentTime((newState as any).includeCurrentTime)
341+
}
342+
// Update includeCurrentCost if present in state message
343+
if ((newState as any).includeCurrentCost !== undefined) {
344+
setIncludeCurrentCost((newState as any).includeCurrentCost)
345+
}
330346
// Handle marketplace data if present in state message
331347
if (newState.marketplaceItems !== undefined) {
332348
setMarketplaceItems(newState.marketplaceItems)
@@ -575,6 +591,10 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
575591
},
576592
includeTaskHistoryInEnhance,
577593
setIncludeTaskHistoryInEnhance,
594+
includeCurrentTime,
595+
setIncludeCurrentTime,
596+
includeCurrentCost,
597+
setIncludeCurrentCost,
578598
}
579599

580600
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>

webview-ui/src/i18n/locales/ca/settings.json

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)