Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions packages/kilo-vscode/src/KiloProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2334,15 +2334,11 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
// Shell
const shell = vscode.env.shell || undefined

// Timezone
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || undefined

return {
...(visibleFiles.length > 0 ? { visibleFiles } : {}),
...(openTabs.length > 0 ? { openTabs } : {}),
...(activeFile ? { activeFile } : {}),
...(shell ? { shell } : {}),
...(timezone ? { timezone } : {}),
}
}

Expand Down
2 changes: 0 additions & 2 deletions packages/kilo-vscode/src/services/cli-backend/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,4 @@ export interface EditorContext {
activeFile?: string
/** User's default shell (from vscode.env.shell) */
shell?: string
/** User's timezone (e.g. "Europe/Amsterdam") */
timezone?: string
}
58 changes: 37 additions & 21 deletions packages/opencode/src/kilocode/editor-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,55 @@ export interface EditorContext {
openTabs?: string[]
activeFile?: string
shell?: string
timezone?: string
}

function formatDate(timezone?: string): string[] {
const now = new Date()
const lines = [` Today's date: ${now.toDateString()}`]
if (timezone) {
const offset = -now.getTimezoneOffset()
const sign = offset >= 0 ? "+" : "-"
const hours = Math.floor(Math.abs(offset) / 60)
const mins = Math.abs(offset) % 60
lines.push(` User timezone: ${timezone}, UTC${sign}${hours}:${mins.toString().padStart(2, "0")}`)
/**
* Build static <env> lines from editor context.
* These rarely change during a session and belong in the system prompt
* so they benefit from prompt caching.
*/
export function staticEnvLines(ctx?: EditorContext): string[] {
Comment thread
markijbema marked this conversation as resolved.
const lines: string[] = []
if (ctx?.shell) {
lines.push(` Default shell: ${ctx.shell}`)
}
return lines
}

/**
* Build additional <env> lines from VS Code editor context.
* Returns an array of pre-formatted ` key: value` strings.
* Build a per-message <environment_details> block from editor context.
* These change frequently (user switches files/tabs) and belong in the
* user message so the model always has fresh context.
* Always includes at least the current timestamp.
*/
export function editorContextEnvLines(ctx?: EditorContext): string[] {
const lines = formatDate(ctx?.timezone)
if (ctx?.shell) {
lines.push(` Default shell: ${ctx.shell}`)
}
function timestamp(): string {
const now = new Date()
const offset = -now.getTimezoneOffset()
const sign = offset >= 0 ? "+" : "-"
const h = Math.floor(Math.abs(offset) / 60)
.toString()
.padStart(2, "0")
const m = (Math.abs(offset) % 60).toString().padStart(2, "0")
const pad = (n: number) => n.toString().padStart(2, "0")
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}T${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}${sign}${h}:${m}`
}

export function environmentDetails(ctx?: EditorContext): string {
const lines: string[] = [`Current time: ${timestamp()}`]
if (ctx?.activeFile) {
lines.push(` Active file: ${ctx.activeFile}`)
lines.push(`Active file: ${ctx.activeFile}`)
}
if (ctx?.visibleFiles?.length) {
lines.push(` Visible files: ${ctx.visibleFiles.join(", ")}`)
lines.push(`Visible files:`)
for (const f of ctx.visibleFiles) {
lines.push(` ${f}`)
}
}
if (ctx?.openTabs?.length) {
lines.push(` Open tabs: ${ctx.openTabs.join(", ")}`)
lines.push(`Open tabs:`)
for (const f of ctx.openTabs) {
lines.push(` ${f}`)
}
}
return lines
return ["<environment_details>", ...lines, "</environment_details>"].join("\n")
}
1 change: 0 additions & 1 deletion packages/opencode/src/session/message-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,6 @@ export namespace MessageV2 {
openTabs: z.array(z.string()).optional(),
activeFile: z.string().optional(),
shell: z.string().optional(),
timezone: z.string().optional(),
})
.optional(),
// kilocode_change end
Expand Down
33 changes: 32 additions & 1 deletion packages/opencode/src/session/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { iife } from "@/util/iife"
import { Shell } from "@/shell/shell"
import { Truncate } from "@/tool/truncation"
import { PlanFollowup } from "@/kilocode/plan-followup" // kilocode_change
import { environmentDetails } from "@/kilocode/editor-context" // kilocode_change

// @ts-ignore
globalThis.AI_SDK_LOG_WARNINGS = false
Expand Down Expand Up @@ -130,7 +131,6 @@ export namespace SessionPrompt {
openTabs: z.array(z.string()).optional(),
activeFile: z.string().optional(),
shell: z.string().optional(),
timezone: z.string().optional(),
})
.optional(),
// kilocode_change end
Expand Down Expand Up @@ -324,6 +324,12 @@ export namespace SessionPrompt {
// on the user message and will be retrieved from lastUser below
let structuredOutput: unknown | undefined

// kilocode_change — cache environment details per turn so the last user
// message stays byte-identical across tool-loop steps (prompt caching).
// Keyed by user message ID so it recomputes when a new user message arrives.
let envBlock: string | undefined
Comment thread
markijbema marked this conversation as resolved.
let envUser: string | undefined

let step = 0
const session = await Session.get(sessionID)
while (true) {
Expand Down Expand Up @@ -556,6 +562,7 @@ export namespace SessionPrompt {
},
agent: lastUser.agent,
model: lastUser.model,
editorContext: lastUser.editorContext, // kilocode_change — preserve editor context
}
await Session.updateMessage(summaryUserMsg)
await Session.updatePart({
Expand Down Expand Up @@ -694,6 +701,30 @@ export namespace SessionPrompt {

await Plugin.trigger("experimental.chat.messages.transform", {}, { messages: msgs })

// kilocode_change start — ephemerally inject dynamic editor context into last user message
if (envUser !== lastUser.id) {
envBlock = environmentDetails(lastUser.editorContext)
Comment thread
markijbema marked this conversation as resolved.
envUser = lastUser.id
}
if (envBlock) {
const idx = msgs.findLastIndex((m) => m.info.role === "user")
if (idx !== -1)
msgs[idx] = {
...msgs[idx],
parts: [
...msgs[idx].parts,
{
id: Identifier.ascending("part"),
sessionID,
messageID: msgs[idx].info.id,
type: "text",
text: envBlock,
} satisfies MessageV2.TextPart,
],
}
}
// kilocode_change end

// Build system prompt, adding structured output instruction if needed
const system = [
...(await SystemPrompt.environment(model, lastUser.editorContext)),
Expand Down
4 changes: 2 additions & 2 deletions packages/opencode/src/session/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { Provider } from "@/provider/provider"

// kilocode_change start
import SOUL from "../kilocode/soul.txt"
import { editorContextEnvLines, type EditorContext } from "../kilocode/editor-context"
import { staticEnvLines, type EditorContext } from "../kilocode/editor-context"
// kilocode_change end

export namespace SystemPrompt {
Expand Down Expand Up @@ -67,7 +67,7 @@ export namespace SystemPrompt {
` Working directory: ${Instance.directory}`,
` Is directory a git repo: ${project.vcs === "git" ? "yes" : "no"}`,
` Platform: ${process.platform}`,
...editorContextEnvLines(editorContext), // kilocode_change
...staticEnvLines(editorContext), // kilocode_change
`</env>`,
`<directories>`,
` ${
Expand Down
2 changes: 0 additions & 2 deletions packages/sdk/js/src/v2/gen/sdk.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1943,7 +1943,6 @@ export class Session2 extends HeyApiClient {
openTabs?: Array<string>
activeFile?: string
shell?: string
timezone?: string
}
parts?: Array<TextPartInput | FilePartInput | AgentPartInput | SubtaskPartInput>
},
Expand Down Expand Up @@ -2083,7 +2082,6 @@ export class Session2 extends HeyApiClient {
openTabs?: Array<string>
activeFile?: string
shell?: string
timezone?: string
}
parts?: Array<TextPartInput | FilePartInput | AgentPartInput | SubtaskPartInput>
},
Expand Down
3 changes: 0 additions & 3 deletions packages/sdk/js/src/v2/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ export type UserMessage = {
openTabs?: Array<string>
activeFile?: string
shell?: string
timezone?: string
}
}

Expand Down Expand Up @@ -3428,7 +3427,6 @@ export type SessionPromptData = {
openTabs?: Array<string>
activeFile?: string
shell?: string
timezone?: string
}
parts: Array<TextPartInput | FilePartInput | AgentPartInput | SubtaskPartInput>
}
Expand Down Expand Up @@ -3668,7 +3666,6 @@ export type SessionPromptAsyncData = {
openTabs?: Array<string>
activeFile?: string
shell?: string
timezone?: string
}
parts: Array<TextPartInput | FilePartInput | AgentPartInput | SubtaskPartInput>
}
Expand Down
13 changes: 4 additions & 9 deletions packages/sdk/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -3186,9 +3186,6 @@
},
"shell": {
"type": "string"
},
"timezone": {
"type": "string"
}
}
},
Expand Down Expand Up @@ -3696,9 +3693,6 @@
},
"shell": {
"type": "string"
},
"timezone": {
"type": "string"
}
}
},
Expand Down Expand Up @@ -8581,9 +8575,6 @@
},
"shell": {
"type": "string"
},
"timezone": {
"type": "string"
}
}
}
Expand Down Expand Up @@ -12027,6 +12018,10 @@
"description": "Enable the batch tool",
"type": "boolean"
},
"codebase_search": {
"description": "Enable AI-powered codebase search",
"type": "boolean"
},
"openTelemetry": {
"description": "Enable telemetry. Set to false to opt-out.",
"default": true,
Expand Down
Loading