Skip to content

Commit 73c7fcd

Browse files
committed
feat: add settings to configure time and cost in system prompt
- Added includeCurrentTime and includeCurrentCost settings to global-settings schema - Updated getEnvironmentDetails to conditionally include time/cost sections - Added UI controls in ContextManagementSettings component - Added translation keys for new settings - Updated all necessary type definitions and message handlers - Both settings default to true for backward compatibility Fixes #8450
1 parent 13534cc commit 73c7fcd

File tree

9 files changed

+114
-14
lines changed

9 files changed

+114
-14
lines changed

packages/types/src/global-settings.ts

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

81+
/**
82+
* Whether to include current time in the environment details
83+
* @default true
84+
*/
85+
includeCurrentTime: z.boolean().optional(),
86+
/**
87+
* Whether to include current cost in the environment details
88+
* @default true
89+
*/
90+
includeCurrentCost: z.boolean().optional(),
91+
8192
/**
8293
* Whether to include diagnostic messages (errors, warnings) in tool outputs
8394
* @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 { contextTokens, 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/webviewMessageHandler.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,6 +1609,14 @@ export const webviewMessageHandler = async (
16091609
await updateGlobalState("includeDiagnosticMessages", includeValue)
16101610
await provider.postStateToWebview()
16111611
break
1612+
case "includeCurrentTime":
1613+
await updateGlobalState("includeCurrentTime", message.bool ?? true)
1614+
await provider.postStateToWebview()
1615+
break
1616+
case "includeCurrentCost":
1617+
await updateGlobalState("includeCurrentCost", message.bool ?? true)
1618+
await provider.postStateToWebview()
1619+
break
16121620
case "maxDiagnosticMessages":
16131621
await updateGlobalState("maxDiagnosticMessages", message.value ?? 50)
16141622
await provider.postStateToWebview()

src/shared/ExtensionMessage.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,8 @@ export type ExtensionState = Pick<
288288
| "openRouterImageGenerationSelectedModel"
289289
| "includeTaskHistoryInEnhance"
290290
| "reasoningBlockCollapsed"
291+
| "includeCurrentTime"
292+
| "includeCurrentCost"
291293
> & {
292294
version: string
293295
clineMessages: ClineMessage[]
@@ -345,6 +347,8 @@ export type ExtensionState = Pick<
345347
openRouterImageApiKey?: string
346348
openRouterUseMiddleOutTransform?: boolean
347349
messageQueue?: QueuedMessage[]
350+
includeCurrentTime?: boolean
351+
includeCurrentCost?: boolean
348352
lastShownAnnouncementId?: string
349353
apiModelId?: string
350354
mcpServers?: McpServer[]

src/shared/WebviewMessage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ export interface WebviewMessage {
175175
| "maxConcurrentFileReads"
176176
| "includeDiagnosticMessages"
177177
| "maxDiagnosticMessages"
178+
| "includeCurrentTime"
179+
| "includeCurrentCost"
178180
| "searchFiles"
179181
| "toggleApiConfigPin"
180182
| "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
@@ -195,6 +195,8 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
195195
openRouterImageApiKey,
196196
openRouterImageGenerationSelectedModel,
197197
reasoningBlockCollapsed,
198+
includeCurrentTime,
199+
includeCurrentCost,
198200
} = cachedState
199201

200202
const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration])
@@ -384,6 +386,8 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
384386
vscode.postMessage({ type: "updateSupportPrompt", values: customSupportPrompts || {} })
385387
vscode.postMessage({ type: "includeTaskHistoryInEnhance", bool: includeTaskHistoryInEnhance ?? true })
386388
vscode.postMessage({ type: "setReasoningBlockCollapsed", bool: reasoningBlockCollapsed ?? true })
389+
vscode.postMessage({ type: "includeCurrentTime", bool: includeCurrentTime ?? true })
390+
vscode.postMessage({ type: "includeCurrentCost", bool: includeCurrentCost ?? true })
387391
vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration })
388392
vscode.postMessage({ type: "telemetrySetting", text: telemetrySetting })
389393
vscode.postMessage({ type: "profileThresholds", values: profileThresholds })
@@ -744,6 +748,8 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
744748
includeDiagnosticMessages={includeDiagnosticMessages}
745749
maxDiagnosticMessages={maxDiagnosticMessages}
746750
writeDelayMs={writeDelayMs}
751+
includeCurrentTime={includeCurrentTime}
752+
includeCurrentCost={includeCurrentCost}
747753
setCachedStateField={setCachedStateField}
748754
/>
749755
)}

webview-ui/src/context/ExtensionStateContext.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ export interface ExtensionStateContextType extends ExtensionState {
158158
setMaxDiagnosticMessages: (value: number) => void
159159
includeTaskHistoryInEnhance?: boolean
160160
setIncludeTaskHistoryInEnhance: (value: boolean) => void
161+
includeCurrentTime?: boolean
162+
setIncludeCurrentTime: (value: boolean) => void
163+
includeCurrentCost?: boolean
164+
setIncludeCurrentCost: (value: boolean) => void
161165
}
162166

163167
export const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
@@ -266,6 +270,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
266270
maxDiagnosticMessages: 50,
267271
openRouterImageApiKey: "",
268272
openRouterImageGenerationSelectedModel: "",
273+
includeCurrentTime: true,
274+
includeCurrentCost: true,
269275
})
270276

271277
const [didHydrateState, setDidHydrateState] = useState(false)
@@ -285,6 +291,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
285291
global: {},
286292
})
287293
const [includeTaskHistoryInEnhance, setIncludeTaskHistoryInEnhance] = useState(true)
294+
const [includeCurrentTime, setIncludeCurrentTime] = useState(true)
295+
const [includeCurrentCost, setIncludeCurrentCost] = useState(true)
288296

289297
const setListApiConfigMeta = useCallback(
290298
(value: ProviderSettingsEntry[]) => setState((prevState) => ({ ...prevState, listApiConfigMeta: value })),
@@ -322,6 +330,14 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
322330
if ((newState as any).includeTaskHistoryInEnhance !== undefined) {
323331
setIncludeTaskHistoryInEnhance((newState as any).includeTaskHistoryInEnhance)
324332
}
333+
// Update includeCurrentTime if present in state message
334+
if ((newState as any).includeCurrentTime !== undefined) {
335+
setIncludeCurrentTime((newState as any).includeCurrentTime)
336+
}
337+
// Update includeCurrentCost if present in state message
338+
if ((newState as any).includeCurrentCost !== undefined) {
339+
setIncludeCurrentCost((newState as any).includeCurrentCost)
340+
}
325341
// Handle marketplace data if present in state message
326342
if (newState.marketplaceItems !== undefined) {
327343
setMarketplaceItems(newState.marketplaceItems)
@@ -559,6 +575,10 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
559575
},
560576
includeTaskHistoryInEnhance,
561577
setIncludeTaskHistoryInEnhance,
578+
includeCurrentTime,
579+
setIncludeCurrentTime,
580+
includeCurrentCost,
581+
setIncludeCurrentCost,
562582
}
563583

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

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,14 @@
610610
"profileDescription": "Custom threshold for this profile only (overrides global default)",
611611
"inheritDescription": "This profile inherits the global default threshold ({{threshold}}%)",
612612
"usesGlobal": "(uses global {{threshold}}%)"
613+
},
614+
"includeCurrentTime": {
615+
"label": "Include current time in context",
616+
"description": "When enabled, the current time and timezone information will be included in the system prompt. Disable this if models are stopping work due to time concerns."
617+
},
618+
"includeCurrentCost": {
619+
"label": "Include current cost in context",
620+
"description": "When enabled, the current API usage cost will be included in the system prompt. Disable this if models are stopping work due to cost concerns."
613621
}
614622
},
615623
"terminal": {

0 commit comments

Comments
 (0)