mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-10-24 23:13:35 +08:00
fix: vscode extension messages
This commit is contained in:
@@ -486,9 +486,9 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
(event) => {
|
||||
const sessionId = this.connectionService.resolveEventSessionId(event)
|
||||
|
||||
// message.part.updated is always session-scoped; if we can't determine the session, drop it.
|
||||
// message.part.updated and message.part.delta are always session-scoped; drop if session unknown.
|
||||
if (!sessionId) {
|
||||
return event.type !== "message.part.updated"
|
||||
return event.type !== "message.part.updated" && event.type !== "message.part.delta"
|
||||
}
|
||||
|
||||
return this.trackedSessionIds.has(sessionId)
|
||||
@@ -658,15 +658,10 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
})
|
||||
.catch((err) => console.error("[Kilo New] KiloProvider: Failed to fetch session statuses:", err))
|
||||
|
||||
// Convert to webview format, including cost/tokens for assistant messages
|
||||
const messages = messagesData.map((m) => ({
|
||||
id: m.info.id,
|
||||
sessionID: m.info.sessionID,
|
||||
role: m.info.role,
|
||||
...m.info,
|
||||
parts: m.parts,
|
||||
createdAt: new Date(m.info.time.created).toISOString(),
|
||||
cost: m.info.cost,
|
||||
tokens: m.info.tokens,
|
||||
}))
|
||||
|
||||
for (const message of messages) {
|
||||
@@ -705,13 +700,9 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
const messagesData = await this.httpClient.getMessages(sessionID, workspaceDir)
|
||||
|
||||
const messages = messagesData.map((m) => ({
|
||||
id: m.info.id,
|
||||
sessionID: m.info.sessionID,
|
||||
role: m.info.role,
|
||||
...m.info,
|
||||
parts: m.parts,
|
||||
createdAt: new Date(m.info.time.created).toISOString(),
|
||||
cost: m.info.cost,
|
||||
tokens: m.info.tokens,
|
||||
}))
|
||||
|
||||
for (const message of messages) {
|
||||
@@ -1445,8 +1436,8 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
|
||||
// Events without sessionID (server.connected, server.heartbeat) → always forward
|
||||
// Events with sessionID → only forward if this webview tracks that session
|
||||
// message.part.updated is always session-scoped; if we can't determine the session, drop it to avoid cross-webview leakage.
|
||||
if (!sessionID && event.type === "message.part.updated") {
|
||||
// message.part.updated and message.part.delta are always session-scoped; drop if session unknown.
|
||||
if (!sessionID && (event.type === "message.part.updated" || event.type === "message.part.delta")) {
|
||||
return
|
||||
}
|
||||
if (sessionID && !this.trackedSessionIds.has(sessionID)) {
|
||||
@@ -1568,8 +1559,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
const activeEditor = vscode.window.activeTextEditor
|
||||
const activeRel =
|
||||
activeEditor?.document.uri.scheme === "file" ? toRelative(activeEditor.document.uri.fsPath) : undefined
|
||||
const activeFile =
|
||||
activeRel && controller.validateAccess(activeEditor!.document.uri.fsPath) ? activeRel : undefined
|
||||
const activeFile = activeRel && controller.validateAccess(activeEditor!.document.uri.fsPath) ? activeRel : undefined
|
||||
|
||||
// Shell
|
||||
const shell = vscode.env.shell || undefined
|
||||
|
||||
@@ -40,7 +40,7 @@ export type WebviewMessage =
|
||||
}
|
||||
| {
|
||||
type: "messageCreated"
|
||||
message: { id: string; sessionID: string; role: string; createdAt: string; cost?: number; tokens?: unknown }
|
||||
message: Record<string, unknown>
|
||||
}
|
||||
| { type: "sessionStatus"; sessionID: string; status: string; attempt?: number; message?: string; next?: number }
|
||||
| {
|
||||
@@ -75,18 +75,27 @@ export function mapSSEEventToWebviewMessage(event: SSEEvent, sessionID: string |
|
||||
delta: event.properties.delta ? { type: "text-delta", textDelta: event.properties.delta } : undefined,
|
||||
}
|
||||
}
|
||||
case "message.updated":
|
||||
case "message.part.delta": {
|
||||
const props = event.properties
|
||||
if (!sessionID) return null
|
||||
return {
|
||||
type: "partUpdated",
|
||||
sessionID: props.sessionID,
|
||||
messageID: props.messageID,
|
||||
part: { id: props.partID, type: "text", messageID: props.messageID, text: props.delta },
|
||||
delta: { type: "text-delta", textDelta: props.delta },
|
||||
}
|
||||
}
|
||||
case "message.updated": {
|
||||
const info = event.properties.info
|
||||
return {
|
||||
type: "messageCreated",
|
||||
message: {
|
||||
id: event.properties.info.id,
|
||||
sessionID: event.properties.info.sessionID,
|
||||
role: event.properties.info.role,
|
||||
createdAt: new Date(event.properties.info.time.created).toISOString(),
|
||||
cost: event.properties.info.cost,
|
||||
tokens: event.properties.info.tokens,
|
||||
...info,
|
||||
createdAt: new Date(info.time.created).toISOString(),
|
||||
},
|
||||
}
|
||||
}
|
||||
case "session.status": {
|
||||
const info = event.properties.status
|
||||
return {
|
||||
|
||||
@@ -32,6 +32,8 @@ export function resolveEventSessionId(
|
||||
}
|
||||
return lookupMessageSessionId(part.messageID)
|
||||
}
|
||||
case "message.part.delta":
|
||||
return event.properties.sessionID
|
||||
case "permission.asked":
|
||||
case "permission.replied":
|
||||
case "question.asked":
|
||||
|
||||
@@ -35,7 +35,15 @@ export interface MessageInfo {
|
||||
created: number
|
||||
completed?: number
|
||||
}
|
||||
// Present on assistant messages
|
||||
agent?: string
|
||||
providerID?: string
|
||||
modelID?: string
|
||||
model?: { providerID: string; modelID: string }
|
||||
mode?: string
|
||||
parentID?: string
|
||||
path?: { cwd: string; root: string }
|
||||
error?: { name: string; data?: Record<string, unknown> }
|
||||
summary?: { title?: string; body?: string; diffs?: unknown[] } | boolean
|
||||
cost?: number
|
||||
tokens?: TokenUsage
|
||||
}
|
||||
@@ -76,6 +84,10 @@ export type SSEEvent =
|
||||
| { type: "session.idle"; properties: { sessionID: string } }
|
||||
| { type: "message.updated"; properties: { info: MessageInfo } }
|
||||
| { type: "message.part.updated"; properties: { part: MessagePart; delta?: string } }
|
||||
| {
|
||||
type: "message.part.delta"
|
||||
properties: { sessionID: string; messageID: string; partID: string; field: string; delta: string }
|
||||
}
|
||||
| { type: "permission.asked"; properties: PermissionRequest }
|
||||
| {
|
||||
type: "permission.replied"
|
||||
|
||||
@@ -12,7 +12,7 @@ import Settings from "./components/Settings"
|
||||
import ProfileView from "./components/ProfileView"
|
||||
import { VSCodeProvider, useVSCode } from "./context/vscode"
|
||||
import { ServerProvider, useServer } from "./context/server"
|
||||
import { ProviderProvider } from "./context/provider"
|
||||
import { ProviderProvider, useProvider } from "./context/provider"
|
||||
import { ConfigProvider } from "./context/config"
|
||||
import { SessionProvider, useSession } from "./context/session"
|
||||
import { LanguageProvider } from "./context/language"
|
||||
@@ -50,10 +50,12 @@ const DummyView: Component<{ title: string }> = (props) => {
|
||||
export const DataBridge: Component<{ children: any }> = (props) => {
|
||||
const session = useSession()
|
||||
const vscode = useVSCode()
|
||||
const prov = useProvider()
|
||||
|
||||
const data = createMemo(() => {
|
||||
const id = session.currentSessionID()
|
||||
const perms = id ? session.permissions().filter((p) => p.sessionID === id) : []
|
||||
const qs = id ? session.questions() : []
|
||||
return {
|
||||
session: session.sessions().map((s) => ({ ...s, id: s.id, role: "user" as const })) as unknown as any[],
|
||||
session_status: {} as Record<string, any>,
|
||||
@@ -68,6 +70,12 @@ export const DataBridge: Component<{ children: any }> = (props) => {
|
||||
)
|
||||
: {},
|
||||
permission: id ? { [id]: perms as unknown as any[] } : {},
|
||||
question: id ? { [id]: qs as unknown as any[] } : {},
|
||||
provider: {
|
||||
all: Object.values(prov.providers()) as unknown as any[],
|
||||
connected: prov.connected(),
|
||||
default: prov.defaults(),
|
||||
} as unknown as any,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -75,8 +83,12 @@ export const DataBridge: Component<{ children: any }> = (props) => {
|
||||
session.respondToPermission(input.permissionID, input.response)
|
||||
}
|
||||
|
||||
const sync = (sessionID: string) => {
|
||||
session.syncSession(sessionID)
|
||||
const reply = (input: { requestID: string; answers: string[][] }) => {
|
||||
session.replyToQuestion(input.requestID, input.answers)
|
||||
}
|
||||
|
||||
const reject = (input: { requestID: string }) => {
|
||||
session.rejectQuestion(input.requestID)
|
||||
}
|
||||
|
||||
const open = (filePath: string, line?: number, column?: number) => {
|
||||
@@ -84,7 +96,14 @@ export const DataBridge: Component<{ children: any }> = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<DataProvider data={data()} directory="" onPermissionRespond={respond} onSyncSession={sync} onOpenFile={open}>
|
||||
<DataProvider
|
||||
data={data()}
|
||||
directory=""
|
||||
onPermissionRespond={respond}
|
||||
onQuestionReply={reply}
|
||||
onQuestionReject={reject}
|
||||
onOpenFile={open}
|
||||
>
|
||||
{props.children}
|
||||
</DataProvider>
|
||||
)
|
||||
|
||||
@@ -659,11 +659,13 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
const sid = currentSessionID()
|
||||
if (sid) {
|
||||
const tempId = `optimistic-${crypto.randomUUID()}`
|
||||
const now = Date.now()
|
||||
const temp: Message = {
|
||||
id: tempId,
|
||||
sessionID: sid,
|
||||
role: "user",
|
||||
createdAt: new Date().toISOString(),
|
||||
createdAt: new Date(now).toISOString(),
|
||||
time: { created: now },
|
||||
}
|
||||
setStore("messages", sid, (msgs = []) => [...msgs, temp])
|
||||
setStore("parts", tempId, [{ type: "text" as const, id: `${tempId}-text`, text }])
|
||||
|
||||
@@ -92,6 +92,16 @@ export interface Message {
|
||||
content?: string
|
||||
parts?: Part[]
|
||||
createdAt: string
|
||||
time?: { created: number; completed?: number }
|
||||
agent?: string
|
||||
model?: { providerID: string; modelID: string }
|
||||
providerID?: string
|
||||
modelID?: string
|
||||
mode?: string
|
||||
parentID?: string
|
||||
path?: { cwd: string; root: string }
|
||||
error?: { name: string; data?: Record<string, unknown> }
|
||||
summary?: { title?: string; body?: string; diffs?: unknown[] } | boolean
|
||||
cost?: number
|
||||
tokens?: TokenUsage
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user