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
This commit is contained in:
Roo Code 2025-10-02 00:26:35 +00:00 committed by daniel-lxs
parent fceb413047
commit b9fd3361d1
No known key found for this signature in database
GPG key ID: 21C74479048B3AA6
9 changed files with 112 additions and 12 deletions

View file

@ -93,6 +93,17 @@ export const globalSettingsSchema = z.object({
autoCondenseContextPercent: z.number().optional(),
maxConcurrentFileReads: z.number().optional(),
/**
* Whether to include current time in the environment details
* @default true
*/
includeCurrentTime: z.boolean().optional(),
/**
* Whether to include current cost in the environment details
* @default true
*/
includeCurrentCost: z.boolean().optional(),
/**
* Whether to include diagnostic messages (errors, warnings) in tool outputs
* @default true

View file

@ -190,22 +190,29 @@ export async function getEnvironmentDetails(cline: Task, includeFileDetails: boo
details += terminalDetails
}
// Add current time information with timezone.
const now = new Date()
// Get settings for time and cost display
const { includeCurrentTime = true, includeCurrentCost = true } = state ?? {}
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
const timeZoneOffset = -now.getTimezoneOffset() / 60 // Convert to hours and invert sign to match conventional notation
const timeZoneOffsetHours = Math.floor(Math.abs(timeZoneOffset))
const timeZoneOffsetMinutes = Math.abs(Math.round((Math.abs(timeZoneOffset) - timeZoneOffsetHours) * 60))
const timeZoneOffsetStr = `${timeZoneOffset >= 0 ? "+" : "-"}${timeZoneOffsetHours}:${timeZoneOffsetMinutes.toString().padStart(2, "0")}`
details += `\n\n# Current Time\nCurrent time in ISO 8601 UTC format: ${now.toISOString()}\nUser time zone: ${timeZone}, UTC${timeZoneOffsetStr}`
// Add current time information with timezone (if enabled).
if (includeCurrentTime) {
const now = new Date()
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
const timeZoneOffset = -now.getTimezoneOffset() / 60 // Convert to hours and invert sign to match conventional notation
const timeZoneOffsetHours = Math.floor(Math.abs(timeZoneOffset))
const timeZoneOffsetMinutes = Math.abs(Math.round((Math.abs(timeZoneOffset) - timeZoneOffsetHours) * 60))
const timeZoneOffsetStr = `${timeZoneOffset >= 0 ? "+" : "-"}${timeZoneOffsetHours}:${timeZoneOffsetMinutes.toString().padStart(2, "0")}`
details += `\n\n# Current Time\nCurrent time in ISO 8601 UTC format: ${now.toISOString()}\nUser time zone: ${timeZone}, UTC${timeZoneOffsetStr}`
}
// Add context tokens information (if enabled).
if (includeCurrentCost) {
const { contextTokens, totalCost } = getApiMetrics(cline.clineMessages)
details += `\n\n# Current Cost\n${totalCost !== null ? `$${totalCost.toFixed(2)}` : "(Not available)"}`
}
// Add context tokens information.
const { contextTokens, totalCost } = getApiMetrics(cline.clineMessages)
const { id: modelId } = cline.api.getModel()
details += `\n\n# Current Cost\n${totalCost !== null ? `$${totalCost.toFixed(2)}` : "(Not available)"}`
// Add current mode and any mode-specific warnings.
const {
mode,

View file

@ -1658,6 +1658,14 @@ export const webviewMessageHandler = async (
await updateGlobalState("includeDiagnosticMessages", includeValue)
await provider.postStateToWebview()
break
case "includeCurrentTime":
await updateGlobalState("includeCurrentTime", message.bool ?? true)
await provider.postStateToWebview()
break
case "includeCurrentCost":
await updateGlobalState("includeCurrentCost", message.bool ?? true)
await provider.postStateToWebview()
break
case "maxDiagnosticMessages":
await updateGlobalState("maxDiagnosticMessages", message.value ?? 50)
await provider.postStateToWebview()

View file

@ -294,6 +294,8 @@ export type ExtensionState = Pick<
| "openRouterImageGenerationSelectedModel"
| "includeTaskHistoryInEnhance"
| "reasoningBlockCollapsed"
| "includeCurrentTime"
| "includeCurrentCost"
> & {
version: string
clineMessages: ClineMessage[]
@ -352,6 +354,8 @@ export type ExtensionState = Pick<
openRouterImageApiKey?: string
openRouterUseMiddleOutTransform?: boolean
messageQueue?: QueuedMessage[]
includeCurrentTime?: boolean
includeCurrentCost?: boolean
lastShownAnnouncementId?: string
apiModelId?: string
mcpServers?: McpServer[]

View file

@ -177,6 +177,8 @@ export interface WebviewMessage {
| "maxConcurrentFileReads"
| "includeDiagnosticMessages"
| "maxDiagnosticMessages"
| "includeCurrentTime"
| "includeCurrentCost"
| "searchFiles"
| "toggleApiConfigPin"
| "setHistoryPreviewCollapsed"

View file

@ -27,6 +27,8 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
includeDiagnosticMessages?: boolean
maxDiagnosticMessages?: number
writeDelayMs: number
includeCurrentTime?: boolean
includeCurrentCost?: boolean
setCachedStateField: SetCachedStateField<
| "autoCondenseContext"
| "autoCondenseContextPercent"
@ -41,6 +43,8 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
| "includeDiagnosticMessages"
| "maxDiagnosticMessages"
| "writeDelayMs"
| "includeCurrentTime"
| "includeCurrentCost"
>
}
@ -60,6 +64,8 @@ export const ContextManagementSettings = ({
includeDiagnosticMessages,
maxDiagnosticMessages,
writeDelayMs,
includeCurrentTime,
includeCurrentCost,
className,
...props
}: ContextManagementSettingsProps) => {
@ -356,6 +362,34 @@ export const ContextManagementSettings = ({
{t("settings:contextManagement.diagnostics.delayAfterWrite.description")}
</div>
</div>
<div>
<VSCodeCheckbox
checked={includeCurrentTime}
onChange={(e: any) => setCachedStateField("includeCurrentTime", e.target.checked)}
data-testid="include-current-time-checkbox">
<label className="block font-medium mb-1">
{t("settings:contextManagement.includeCurrentTime.label")}
</label>
</VSCodeCheckbox>
<div className="text-vscode-descriptionForeground text-sm mt-1 mb-3">
{t("settings:contextManagement.includeCurrentTime.description")}
</div>
</div>
<div>
<VSCodeCheckbox
checked={includeCurrentCost}
onChange={(e: any) => setCachedStateField("includeCurrentCost", e.target.checked)}
data-testid="include-current-cost-checkbox">
<label className="block font-medium mb-1">
{t("settings:contextManagement.includeCurrentCost.label")}
</label>
</VSCodeCheckbox>
<div className="text-vscode-descriptionForeground text-sm mt-1 mb-3">
{t("settings:contextManagement.includeCurrentCost.description")}
</div>
</div>
</Section>
<Section className="pt-2">
<VSCodeCheckbox

View file

@ -196,6 +196,8 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
openRouterImageApiKey,
openRouterImageGenerationSelectedModel,
reasoningBlockCollapsed,
includeCurrentTime,
includeCurrentCost,
} = cachedState
const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration])
@ -386,6 +388,8 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
vscode.postMessage({ type: "updateSupportPrompt", values: customSupportPrompts || {} })
vscode.postMessage({ type: "includeTaskHistoryInEnhance", bool: includeTaskHistoryInEnhance ?? true })
vscode.postMessage({ type: "setReasoningBlockCollapsed", bool: reasoningBlockCollapsed ?? true })
vscode.postMessage({ type: "includeCurrentTime", bool: includeCurrentTime ?? true })
vscode.postMessage({ type: "includeCurrentCost", bool: includeCurrentCost ?? true })
vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration })
vscode.postMessage({ type: "telemetrySetting", text: telemetrySetting })
vscode.postMessage({ type: "profileThresholds", values: profileThresholds })
@ -747,6 +751,8 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
includeDiagnosticMessages={includeDiagnosticMessages}
maxDiagnosticMessages={maxDiagnosticMessages}
writeDelayMs={writeDelayMs}
includeCurrentTime={includeCurrentTime}
includeCurrentCost={includeCurrentCost}
setCachedStateField={setCachedStateField}
/>
)}

View file

@ -161,6 +161,10 @@ export interface ExtensionStateContextType extends ExtensionState {
setMaxDiagnosticMessages: (value: number) => void
includeTaskHistoryInEnhance?: boolean
setIncludeTaskHistoryInEnhance: (value: boolean) => void
includeCurrentTime?: boolean
setIncludeCurrentTime: (value: boolean) => void
includeCurrentCost?: boolean
setIncludeCurrentCost: (value: boolean) => void
}
export const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
@ -270,6 +274,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
maxDiagnosticMessages: 50,
openRouterImageApiKey: "",
openRouterImageGenerationSelectedModel: "",
includeCurrentTime: true,
includeCurrentCost: true,
})
const [didHydrateState, setDidHydrateState] = useState(false)
@ -290,6 +296,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
})
const [includeTaskHistoryInEnhance, setIncludeTaskHistoryInEnhance] = useState(true)
const [prevCloudIsAuthenticated, setPrevCloudIsAuthenticated] = useState(false)
const [includeCurrentTime, setIncludeCurrentTime] = useState(true)
const [includeCurrentCost, setIncludeCurrentCost] = useState(true)
const setListApiConfigMeta = useCallback(
(value: ProviderSettingsEntry[]) => setState((prevState) => ({ ...prevState, listApiConfigMeta: value })),
@ -327,6 +335,14 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
if ((newState as any).includeTaskHistoryInEnhance !== undefined) {
setIncludeTaskHistoryInEnhance((newState as any).includeTaskHistoryInEnhance)
}
// Update includeCurrentTime if present in state message
if ((newState as any).includeCurrentTime !== undefined) {
setIncludeCurrentTime((newState as any).includeCurrentTime)
}
// Update includeCurrentCost if present in state message
if ((newState as any).includeCurrentCost !== undefined) {
setIncludeCurrentCost((newState as any).includeCurrentCost)
}
// Handle marketplace data if present in state message
if (newState.marketplaceItems !== undefined) {
setMarketplaceItems(newState.marketplaceItems)
@ -575,6 +591,10 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
},
includeTaskHistoryInEnhance,
setIncludeTaskHistoryInEnhance,
includeCurrentTime,
setIncludeCurrentTime,
includeCurrentCost,
setIncludeCurrentCost,
}
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>

View file

@ -614,6 +614,14 @@
"profileDescription": "Custom threshold for this profile only (overrides global default)",
"inheritDescription": "This profile inherits the global default threshold ({{threshold}}%)",
"usesGlobal": "(uses global {{threshold}}%)"
},
"includeCurrentTime": {
"label": "Include current time in context",
"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."
},
"includeCurrentCost": {
"label": "Include current cost in context",
"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."
}
},
"terminal": {