refactor: move feedback additions out of upstream-shared files

Addresses review feedback: Kilo-specific additions belong in Kilo-owned
packages so the diff against upstream OpenCode stays minimal.

- Icons: move thumbs-up/-down/-up-filled/-down-filled paths from
  packages/ui/src/components/icon.tsx into packages/kilo-ui's icon
  registry. Extend the kilo-ui Icon registry to carry per-icon viewBox
  (Heroicons thumbs are 20x20; existing Kilo icons are 16x16). Replace
  packages/kilo-ui/src/components/icon-button.tsx (previously a re-export
  of @opencode-ai/ui/icon-button) with a local implementation that
  uses the kilo-ui Icon so the new names resolve.

- i18n: move the three feedback strings (helpful, notHelpful,
  clearRating) from each of 19 packages/ui/src/i18n/<locale>.ts files
  into the corresponding packages/kilo-i18n/src/<locale>.ts. The
  webview's language.tsx already merges kilo-i18n on top of upstream,
  so the runtime keys remain available.

- TUI: extract submitFeedback from
  packages/opencode/src/cli/cmd/tui/routes/session/index.tsx into a
  new Kilo-owned helper at
  packages/opencode/src/kilocode/cli/cmd/tui/feedback.ts. The session
  route now imports and invokes it, passing { toast, session, messages }.
  Also tightens the Kilo Gateway gate from startsWith("kilo") to
  === "kilo" to match the equivalent fix in the webview.
This commit is contained in:
Josh Lambert
2026-05-06 10:20:56 -04:00
parent 3992300857
commit 363e337ca8
43 changed files with 213 additions and 148 deletions
+5
View File
@@ -92,4 +92,9 @@ export const dict = {
"أوقف لقطات Kilo لهذا المشروع. ستفقد ميزة التراجع/الإعادة لتعديلات Kilo، لكن git سيستمر في تتبع كل شيء.",
"ui.messagePart.openInDiffViewer": "فتح في عارض الفروقات",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "كان هذا مفيدًا",
"ui.message.feedback.notHelpful": "لم يكن هذا مفيدًا",
"ui.message.feedback.clearRating": "مسح التقييم",
}
+5
View File
@@ -92,4 +92,9 @@ export const dict = {
"Desligue os snapshots do Kilo para este projeto. Você perde desfazer/refazer das mudanças feitas pelo Kilo, mas o git continua rastreando tudo.",
"ui.messagePart.openInDiffViewer": "Abrir no Visualizador de Diferenças",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Isso foi útil",
"ui.message.feedback.notHelpful": "Isso não foi útil",
"ui.message.feedback.clearRating": "Limpar avaliação",
}
+5
View File
@@ -97,4 +97,9 @@ export const dict = {
"Isključi Kilo snapshotove za ovaj projekat. Izgubićete poništi/vrati za izmjene koje napravi Kilo, ali git i dalje prati sve.",
"ui.messagePart.openInDiffViewer": "Otvori u pregledniku razlika",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Ovo je bilo korisno",
"ui.message.feedback.notHelpful": "Ovo nije bilo korisno",
"ui.message.feedback.clearRating": "Obriši ocjenu",
}
+5
View File
@@ -92,4 +92,9 @@ export const dict = {
"Slå Kilos snapshots fra for dette projekt. Du mister fortryd/gentag for Kilo-ændringer, men git sporer stadig alt.",
"ui.messagePart.openInDiffViewer": "Åbn i diff-viser",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Dette var nyttigt",
"ui.message.feedback.notHelpful": "Dette var ikke nyttigt",
"ui.message.feedback.clearRating": "Ryd bedømmelse",
}
+5
View File
@@ -92,4 +92,9 @@ export const dict = {
"Kilo-Snapshots für dieses Projekt ausschalten. Rückgängig/Wiederherstellen für Kilo-Änderungen ist nicht mehr möglich, aber git verfolgt weiterhin alles.",
"ui.messagePart.openInDiffViewer": "Im Diff-Viewer öffnen",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Das war hilfreich",
"ui.message.feedback.notHelpful": "Das war nicht hilfreich",
"ui.message.feedback.clearRating": "Bewertung löschen",
}
+5
View File
@@ -99,4 +99,9 @@ export const dict = {
// Edit-tool header: hover-revealed action opening the diff in a full tab.
"ui.messagePart.openInDiffViewer": "Open in Diff Viewer",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "This was helpful",
"ui.message.feedback.notHelpful": "This wasn't helpful",
"ui.message.feedback.clearRating": "Clear rating",
}
+5
View File
@@ -92,4 +92,9 @@ export const dict = {
"Apaga las instantáneas de Kilo para este proyecto. Perderás deshacer/rehacer de los cambios de Kilo, pero git seguirá rastreando todo.",
"ui.messagePart.openInDiffViewer": "Abrir en el visor de diferencias",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Esto fue útil",
"ui.message.feedback.notHelpful": "Esto no fue útil",
"ui.message.feedback.clearRating": "Borrar valoración",
}
+5
View File
@@ -92,4 +92,9 @@ export const dict = {
"Désactivez les instantanés Kilo pour ce projet. Vous perdez l'annulation/restauration des modifications faites par Kilo, mais git continue de tout suivre.",
"ui.messagePart.openInDiffViewer": "Ouvrir dans la visionneuse de différences",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "C'était utile",
"ui.message.feedback.notHelpful": "Ce n'était pas utile",
"ui.message.feedback.clearRating": "Effacer la notation",
}
+5
View File
@@ -90,4 +90,9 @@ export const dict = {
"このプロジェクトでは Kilo のスナップショットを無効にします。Kilo による変更の取り消し/やり直しはできなくなりますが、git は引き続きすべてを追跡します。",
"ui.messagePart.openInDiffViewer": "差分ビューアで開く",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "役に立ちました",
"ui.message.feedback.notHelpful": "役に立ちませんでした",
"ui.message.feedback.clearRating": "評価をクリア",
}
+5
View File
@@ -90,4 +90,9 @@ export const dict = {
"이 프로젝트의 Kilo 스냅샷을 끕니다. Kilo 변경에 대한 실행 취소/다시 실행은 사용할 수 없지만 git은 여전히 모든 것을 추적합니다.",
"ui.messagePart.openInDiffViewer": "Diff 뷰어에서 열기",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "도움이 됐어요",
"ui.message.feedback.notHelpful": "도움이 안 됐어요",
"ui.message.feedback.clearRating": "평가 지우기",
}
+5
View File
@@ -94,4 +94,9 @@ export const dict = {
"Zet Kilo-snapshots uit voor dit project. Je verliest ongedaan maken/opnieuw doen van Kilo-wijzigingen, maar git blijft alles volgen.",
"ui.messagePart.openInDiffViewer": "Openen in diff-viewer",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Dit was nuttig",
"ui.message.feedback.notHelpful": "Dit was niet nuttig",
"ui.message.feedback.clearRating": "Beoordeling wissen",
}
+5
View File
@@ -92,4 +92,9 @@ export const dict = {
"Slå av Kilos snapshots for dette prosjektet. Du mister angre/gjør om for Kilo-endringer, men git fortsetter å spore alt.",
"ui.messagePart.openInDiffViewer": "Åpne i diff-viser",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Dette var nyttig",
"ui.message.feedback.notHelpful": "Dette var ikke nyttig",
"ui.message.feedback.clearRating": "Fjern vurdering",
}
+5
View File
@@ -92,4 +92,9 @@ export const dict = {
"Wyłącz snapshoty Kilo dla tego projektu. Stracisz cofanie/przywracanie zmian Kilo, ale git nadal śledzi wszystko.",
"ui.messagePart.openInDiffViewer": "Otwórz w podglądzie różnic",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "To było pomocne",
"ui.message.feedback.notHelpful": "To nie było pomocne",
"ui.message.feedback.clearRating": "Wyczyść ocenę",
}
+5
View File
@@ -92,4 +92,9 @@ export const dict = {
"Выключите снимки Kilo для этого проекта. Вы потеряете отмену/повтор изменений Kilo, но git по-прежнему отслеживает всё.",
"ui.messagePart.openInDiffViewer": "Открыть в просмотрщике различий",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Это было полезно",
"ui.message.feedback.notHelpful": "Это было бесполезно",
"ui.message.feedback.clearRating": "Очистить оценку",
}
+5
View File
@@ -92,4 +92,9 @@ export const dict = {
"ปิดสแน็ปช็อตของ Kilo สำหรับโปรเจกต์นี้ คุณจะสูญเสียการยกเลิก/ทำซ้ำสำหรับการเปลี่ยนแปลงของ Kilo แต่ git ยังคงติดตามทุกอย่าง",
"ui.messagePart.openInDiffViewer": "เปิดในตัวดูความแตกต่าง",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "สิ่งนี้มีประโยชน์",
"ui.message.feedback.notHelpful": "สิ่งนี้ไม่มีประโยชน์",
"ui.message.feedback.clearRating": "ล้างการให้คะแนน",
}
+5
View File
@@ -92,4 +92,9 @@ export const dict = {
"Bu proje için Kilo anlık görüntülerini kapat. Kilo değişiklikleri için geri alma/yeniden yapmayı kaybedersiniz, ancak git her şeyi izlemeye devam eder.",
"ui.messagePart.openInDiffViewer": "Fark görüntüleyicide aç",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Bu yardımcı oldu",
"ui.message.feedback.notHelpful": "Bu yardımcı olmadı",
"ui.message.feedback.clearRating": "Değerlendirmeyi temizle",
}
+5
View File
@@ -92,4 +92,9 @@ export const dict = {
"Вимкніть знімки Kilo для цього проєкту. Ви втратите скасування/повторення для змін Kilo, але git продовжить відстежувати все.",
"ui.messagePart.openInDiffViewer": "Відкрити у переглядачі відмінностей",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Це було корисно",
"ui.message.feedback.notHelpful": "Це не було корисно",
"ui.message.feedback.clearRating": "Очистити оцінку",
}
+5
View File
@@ -87,4 +87,9 @@ export const dict = {
"关闭本项目的 Kilo 快照。你将失去对 Kilo 更改的撤销/重做,但 git 仍会追踪所有内容。",
"ui.messagePart.openInDiffViewer": "在差异查看器中打开",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "这有帮助",
"ui.message.feedback.notHelpful": "这没有帮助",
"ui.message.feedback.clearRating": "清除评分",
}
+5
View File
@@ -87,4 +87,9 @@ export const dict = {
"關閉本專案的 Kilo 快照。你將失去對 Kilo 變更的撤銷/重做,但 git 仍會追蹤所有內容。",
"ui.messagePart.openInDiffViewer": "在差異檢視器中開啟",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "這有幫助",
"ui.message.feedback.notHelpful": "這沒有幫助",
"ui.message.feedback.clearRating": "清除評分",
}
@@ -1 +1,29 @@
export * from "@opencode-ai/ui/icon-button"
import { Button as Kobalte } from "@kobalte/core/button"
import { type ComponentProps, splitProps } from "solid-js"
import { Icon, IconProps } from "./icon"
export interface IconButtonProps extends ComponentProps<typeof Kobalte> {
icon: IconProps["name"]
size?: "small" | "normal" | "large"
iconSize?: IconProps["size"]
variant?: "primary" | "secondary" | "ghost"
}
export function IconButton(props: ComponentProps<"button"> & IconButtonProps) {
const [split, rest] = splitProps(props, ["variant", "size", "iconSize", "class", "classList"])
return (
<Kobalte
{...rest}
data-component="icon-button"
data-icon={props.icon}
data-size={split.size || "normal"}
data-variant={split.variant || "secondary"}
classList={{
...split.classList,
[split.class ?? ""]: !!split.class,
}}
>
<Icon name={props.icon} size={split.iconSize ?? (split.size === "large" ? "normal" : "small")} />
</Kobalte>
)
}
+28 -5
View File
@@ -1,9 +1,31 @@
import { Icon as Upstream, type IconProps as Props } from "@opencode-ai/ui/icon"
import { splitProps } from "solid-js"
const icons = {
"circuit-board": `<path d="M12.5 1H3.5C2.121 1 1 2.121 1 3.5V12.5C1 13.879 2.121 15 3.5 15H12.5C13.879 15 15 13.879 15 12.5V3.5C15 2.121 13.879 1 12.5 1ZM6 6.5C6 6.775 5.775 7 5.5 7C5.225 7 5 6.775 5 6.5C5 6.225 5.225 6 5.5 6C5.775 6 6 6.225 6 6.5ZM12.5 14H6V11.5C6 11.225 6.225 11 6.5 11H9.092C9.299 11.581 9.849 12 10.5 12C11.327 12 12 11.327 12 10.5C12 9.673 11.327 9 10.5 9C9.849 9 9.299 9.419 9.092 10H6.5C5.673 10 5 10.673 5 11.5V14H3.5C2.673 14 2 13.327 2 12.5V3.5C2 2.673 2.673 2 3.5 2H5V5.092C4.419 5.299 4 5.849 4 6.5C4 7.327 4.673 8 5.5 8C6.327 8 7 7.327 7 6.5C7 5.849 6.581 5.299 6 5.092V2H12.5C13.327 2 14 2.673 14 3.5V6H10.908C10.701 5.419 10.151 5 9.5 5C8.673 5 8 5.673 8 6.5C8 7.327 8.673 8 9.5 8C10.151 8 10.701 7.581 10.908 7H14V12.5C14 13.327 13.327 14 12.5 14ZM10 10.5C10 10.225 10.225 10 10.5 10C10.775 10 11 10.225 11 10.5C11 10.775 10.775 11 10.5 11C10.225 11 10 10.775 10 10.5ZM10 6.5C10 6.775 9.775 7 9.5 7C9.225 7 9 6.775 9 6.5C9 6.225 9.225 6 9.5 6C9.775 6 10 6.225 10 6.5Z" fill="currentColor"/>`,
organization: `<path d="M6.00195 4.00002C6.00195 2.89655 6.89649 2.00201 7.99995 2.00201C9.10342 2.00201 9.99796 2.89655 9.99796 4.00002C9.99796 5.10348 9.10342 5.99802 7.99995 5.99802C6.89649 5.99802 6.00195 5.10348 6.00195 4.00002ZM7.99995 3.00201C7.44877 3.00201 7.00195 3.44883 7.00195 4.00002C7.00195 4.5512 7.44877 4.99802 7.99995 4.99802C8.55114 4.99802 8.99796 4.5512 8.99796 4.00002C8.99796 3.44883 8.55114 3.00201 7.99995 3.00201ZM11 4.5C11 3.67157 11.6716 3 12.5 3C13.3284 3 14 3.67157 14 4.5C14 5.32843 13.3284 6 12.5 6C11.6716 6 11 5.32843 11 4.5ZM12.5 4C12.2239 4 12 4.22386 12 4.5C12 4.77614 12.2239 5 12.5 5C12.7761 5 13 4.77614 13 4.5C13 4.22386 12.7761 4 12.5 4ZM3.5 3C2.67157 3 2 3.67157 2 4.5C2 5.32843 2.67157 6 3.5 6C4.32843 6 5 5.32843 5 4.5C5 3.67157 4.32843 3 3.5 3ZM3 4.5C3 4.22386 3.22386 4 3.5 4C3.77614 4 4 4.22386 4 4.5C4 4.77614 3.77614 5 3.5 5C3.22386 5 3 4.77614 3 4.5ZM4.26756 6.99969C4.09739 7.29387 4 7.63541 4 7.99969L2 7.99969V10.5C2 11.3285 2.67157 12 3.5 12C3.71194 12 3.91361 11.9561 4.09639 11.8768C4.1705 12.2082 4.28572 12.524 4.43643 12.8187C4.14721 12.9356 3.83112 13 3.5 13C2.11929 13 1 11.8807 1 10.5V7.99969C1 7.44741 1.44772 6.99969 2 6.99969H4.26756ZM11.5636 12.8187C11.8528 12.9356 12.1689 13 12.5 13C13.8807 13 15 11.8807 15 10.5V7.99969C15 7.44741 14.5523 6.99969 14 6.99969H11.7324C11.9026 7.29387 12 7.63541 12 7.9997L14 7.99969V10.5C14 11.3285 13.3284 12 12.5 12C12.2881 12 12.0864 11.9561 11.9036 11.8768C11.8295 12.2082 11.7143 12.524 11.5636 12.8187ZM6 6.99969C5.44772 6.99969 5 7.44741 5 7.99969V11C5 12.6569 6.34315 14 8 14C9.65685 14 11 12.6569 11 11V7.99969C11 7.44741 10.5523 6.99969 10 6.99969H6ZM6 7.99969L10 7.99969V11C10 12.1046 9.10457 13 8 13C6.89543 13 6 12.1046 6 11V7.99969Z" fill="currentColor"/>`,
const icons: Record<string, { path: string; viewBox: string }> = {
"circuit-board": {
viewBox: "0 0 16 16",
path: `<path d="M12.5 1H3.5C2.121 1 1 2.121 1 3.5V12.5C1 13.879 2.121 15 3.5 15H12.5C13.879 15 15 13.879 15 12.5V3.5C15 2.121 13.879 1 12.5 1ZM6 6.5C6 6.775 5.775 7 5.5 7C5.225 7 5 6.775 5 6.5C5 6.225 5.225 6 5.5 6C5.775 6 6 6.225 6 6.5ZM12.5 14H6V11.5C6 11.225 6.225 11 6.5 11H9.092C9.299 11.581 9.849 12 10.5 12C11.327 12 12 11.327 12 10.5C12 9.673 11.327 9 10.5 9C9.849 9 9.299 9.419 9.092 10H6.5C5.673 10 5 10.673 5 11.5V14H3.5C2.673 14 2 13.327 2 12.5V3.5C2 2.673 2.673 2 3.5 2H5V5.092C4.419 5.299 4 5.849 4 6.5C4 7.327 4.673 8 5.5 8C6.327 8 7 7.327 7 6.5C7 5.849 6.581 5.299 6 5.092V2H12.5C13.327 2 14 2.673 14 3.5V6H10.908C10.701 5.419 10.151 5 9.5 5C8.673 5 8 5.673 8 6.5C8 7.327 8.673 8 9.5 8C10.151 8 10.701 7.581 10.908 7H14V12.5C14 13.327 13.327 14 12.5 14ZM10 10.5C10 10.225 10.225 10 10.5 10C10.775 10 11 10.225 11 10.5C11 10.775 10.775 11 10.5 11C10.225 11 10 10.775 10 10.5ZM10 6.5C10 6.775 9.775 7 9.5 7C9.225 7 9 6.775 9 6.5C9 6.225 9.225 6 9.5 6C9.775 6 10 6.225 10 6.5Z" fill="currentColor"/>`,
},
organization: {
viewBox: "0 0 16 16",
path: `<path d="M6.00195 4.00002C6.00195 2.89655 6.89649 2.00201 7.99995 2.00201C9.10342 2.00201 9.99796 2.89655 9.99796 4.00002C9.99796 5.10348 9.10342 5.99802 7.99995 5.99802C6.89649 5.99802 6.00195 5.10348 6.00195 4.00002ZM7.99995 3.00201C7.44877 3.00201 7.00195 3.44883 7.00195 4.00002C7.00195 4.5512 7.44877 4.99802 7.99995 4.99802C8.55114 4.99802 8.99796 4.5512 8.99796 4.00002C8.99796 3.44883 8.55114 3.00201 7.99995 3.00201ZM11 4.5C11 3.67157 11.6716 3 12.5 3C13.3284 3 14 3.67157 14 4.5C14 5.32843 13.3284 6 12.5 6C11.6716 6 11 5.32843 11 4.5ZM12.5 4C12.2239 4 12 4.22386 12 4.5C12 4.77614 12.2239 5 12.5 5C12.7761 5 13 4.77614 13 4.5C13 4.22386 12.7761 4 12.5 4ZM3.5 3C2.67157 3 2 3.67157 2 4.5C2 5.32843 2.67157 6 3.5 6C4.32843 6 5 5.32843 5 4.5C5 3.67157 4.32843 3 3.5 3ZM3 4.5C3 4.22386 3.22386 4 3.5 4C3.77614 4 4 4.22386 4 4.5C4 4.77614 3.77614 5 3.5 5C3.22386 5 3 4.77614 3 4.5ZM4.26756 6.99969C4.09739 7.29387 4 7.63541 4 7.99969L2 7.99969V10.5C2 11.3285 2.67157 12 3.5 12C3.71194 12 3.91361 11.9561 4.09639 11.8768C4.1705 12.2082 4.28572 12.524 4.43643 12.8187C4.14721 12.9356 3.83112 13 3.5 13C2.11929 13 1 11.8807 1 10.5V7.99969C1 7.44741 1.44772 6.99969 2 6.99969H4.26756ZM11.5636 12.8187C11.8528 12.9356 12.1689 13 12.5 13C13.8807 13 15 11.8807 15 10.5V7.99969C15 7.44741 14.5523 6.99969 14 6.99969H11.7324C11.9026 7.29387 12 7.63541 12 7.9997L14 7.99969V10.5C14 11.3285 13.3284 12 12.5 12C12.2881 12 12.0864 11.9561 11.9036 11.8768C11.8295 12.2082 11.7143 12.524 11.5636 12.8187ZM6 6.99969C5.44772 6.99969 5 7.44741 5 7.99969V11C5 12.6569 6.34315 14 8 14C9.65685 14 11 12.6569 11 11V7.99969C11 7.44741 10.5523 6.99969 10 6.99969H6ZM6 7.99969L10 7.99969V11C10 12.1046 9.10457 13 8 13C6.89543 13 6 12.1046 6 11V7.99969Z" fill="currentColor"/>`,
},
"thumbs-up": {
viewBox: "0 0 20 20",
path: `<path d="M1 8.25a1.25 1.25 0 1 1 2.5 0v7.5a1.25 1.25 0 1 1-2.5 0v-7.5ZM11 3V1.7c0-.268.14-.526.395-.607A2 2 0 0 1 14 3c0 .995-.182 1.948-.514 2.826-.204.54.166 1.174.744 1.174h2.52c1.243 0 2.261 1.01 2.146 2.247a23.864 23.864 0 0 1-1.341 5.974C17.153 16.323 16.072 17 14.9 17h-3.192a3 3 0 0 1-1.341-.317l-2.734-1.366A3 3 0 0 0 6.292 15H5V8h.963c.685 0 1.258-.483 1.612-1.068a4.011 4.011 0 0 1 2.166-1.73c.432-.143.853-.386 1.011-.814.16-.432.248-.9.248-1.388Z" stroke="currentColor" fill="none" stroke-linejoin="round"/>`,
},
"thumbs-down": {
viewBox: "0 0 20 20",
path: `<path d="M18.905 12.75a1.25 1.25 0 0 1-2.5 0v-7.5a1.25 1.25 0 0 1 2.5 0v7.5ZM8.905 17v1.3c0 .268-.14.526-.395.607A2 2 0 0 1 5.905 17c0-.995.182-1.948.514-2.826.204-.54-.166-1.174-.744-1.174h-2.52c-1.243 0-2.261-1.01-2.146-2.247a23.864 23.864 0 0 1 1.341-5.974C2.547 3.677 3.628 3 4.8 3h3.192a3 3 0 0 1 1.341.317l2.734 1.366A3 3 0 0 0 13.408 5H15v7h-.963c-.685 0-1.258.483-1.612 1.068a4.011 4.011 0 0 1-2.166 1.73c-.432.143-.853.386-1.011.814-.16.432-.248.9-.248 1.388Z" stroke="currentColor" fill="none" stroke-linejoin="round"/>`,
},
"thumbs-up-filled": {
viewBox: "0 0 20 20",
path: `<path d="M1 8.25a1.25 1.25 0 1 1 2.5 0v7.5a1.25 1.25 0 1 1-2.5 0v-7.5ZM11 3V1.7c0-.268.14-.526.395-.607A2 2 0 0 1 14 3c0 .995-.182 1.948-.514 2.826-.204.54.166 1.174.744 1.174h2.52c1.243 0 2.261 1.01 2.146 2.247a23.864 23.864 0 0 1-1.341 5.974C17.153 16.323 16.072 17 14.9 17h-3.192a3 3 0 0 1-1.341-.317l-2.734-1.366A3 3 0 0 0 6.292 15H5V8h.963c.685 0 1.258-.483 1.612-1.068a4.011 4.011 0 0 1 2.166-1.73c.432-.143.853-.386 1.011-.814.16-.432.248-.9.248-1.388Z" fill="currentColor"/>`,
},
"thumbs-down-filled": {
viewBox: "0 0 20 20",
path: `<path d="M18.905 12.75a1.25 1.25 0 0 1-2.5 0v-7.5a1.25 1.25 0 0 1 2.5 0v7.5ZM8.905 17v1.3c0 .268-.14.526-.395.607A2 2 0 0 1 5.905 17c0-.995.182-1.948.514-2.826.204-.54-.166-1.174-.744-1.174h-2.52c-1.243 0-2.261-1.01-2.146-2.247a23.864 23.864 0 0 1 1.341-5.974C2.547 3.677 3.628 3 4.8 3h3.192a3 3 0 0 1 1.341.317l2.734 1.366A3 3 0 0 0 13.408 5H15v7h-.963c-.685 0-1.258.483-1.612 1.068a4.011 4.011 0 0 1-2.166 1.73c-.432.143-.853.386-1.011.814-.16.432-.248.9-.248 1.388Z" fill="currentColor"/>`,
},
}
type Name = keyof typeof icons
@@ -26,6 +48,7 @@ export function Icon(props: IconProps) {
/>
)
}
const def = icons[name]
return (
<div data-component="icon" data-size={local.size || "normal"}>
<svg
@@ -35,8 +58,8 @@ export function Icon(props: IconProps) {
}}
data-slot="icon-svg"
fill="none"
viewBox="0 0 16 16"
innerHTML={icons[name]}
viewBox={def.viewBox}
innerHTML={def.path}
aria-hidden="true"
{...others}
/>
@@ -86,7 +86,7 @@ import { useTuiConfig } from "../../context/tui-config"
import { formatMarkdownTables } from "../../util/markdown" // kilocode_change
import { bell } from "@/kilocode/bell" // kilocode_change
import { SessionIndexing } from "@/kilocode/components/session-indexing" // kilocode_change
import { Telemetry } from "@kilocode/kilo-telemetry" // kilocode_change
import { submitFeedback } from "@/kilocode/cli/cmd/tui/feedback" // kilocode_change
import { getScrollAcceleration } from "../../util/scroll"
import { TuiPluginRuntime } from "@/cli/cmd/tui/plugin/runtime"
import { DialogGoUpsell } from "../../component/dialog-go-upsell"
@@ -475,44 +475,6 @@ export function Session() {
}
}
// kilocode_change start - message feedback
function submitFeedback(rating: "up" | "down", dialog: DialogContext) {
if (!Telemetry.isEnabled()) {
toast.show({ message: "Feedback disabled: telemetry is off", variant: "info" })
dialog.clear()
return
}
const revertID = session()?.revert?.messageID
const lastAssistant = messages().findLast(
(msg): msg is AssistantMessage => msg.role === "assistant" && (!revertID || msg.id < revertID),
)
if (!lastAssistant) {
toast.show({ message: "No assistant messages found", variant: "error" })
dialog.clear()
return
}
const providerID = lastAssistant.providerID
const payload: Telemetry.FeedbackProperties = {
providerID,
modelID: lastAssistant.modelID,
rating,
}
const variant = (lastAssistant as AssistantMessage & { variant?: string }).variant
if (variant) payload.variant = variant
if (providerID.startsWith("kilo")) {
payload.sessionID = lastAssistant.sessionID
payload.messageID = lastAssistant.id
payload.parentMessageID = lastAssistant.parentID
}
Telemetry.trackFeedback(payload)
toast.show({
message: rating === "up" ? "Thanks for the feedback!" : "Thanks — we'll use this to improve.",
variant: "success",
})
dialog.clear()
}
// kilocode_change end
const command = useCommandDialog()
command.register(() => [
{
@@ -994,14 +956,14 @@ export function Session() {
value: "messages.feedback.up",
keybind: "messages_feedback_up",
category: "Session",
onSelect: (dialog) => submitFeedback("up", dialog),
onSelect: (dialog) => submitFeedback("up", dialog, { toast, session, messages }),
},
{
title: "Rate last assistant message not helpful",
value: "messages.feedback.down",
keybind: "messages_feedback_down",
category: "Session",
onSelect: (dialog) => submitFeedback("down", dialog),
onSelect: (dialog) => submitFeedback("down", dialog, { toast, session, messages }),
},
// kilocode_change end
{
@@ -0,0 +1,58 @@
// kilocode_change - new file
/**
* Per-message thumbs up/down feedback for the TUI.
*
* Wired via the `messages_feedback_up` / `messages_feedback_down` keybinds
* in the Session route. Kept out of `routes/session/index.tsx` so the
* upstream-shared session route stays free of Kilo telemetry plumbing.
*/
import { Telemetry } from "@kilocode/kilo-telemetry"
import type { AssistantMessage, Message } from "@kilocode/sdk/v2"
import type { DialogContext } from "@tui/ui/dialog"
import type { ToastContext } from "@tui/ui/toast"
interface SessionRevert {
revert?: { messageID: string }
}
interface Context {
toast: ToastContext
session: () => SessionRevert | undefined
messages: () => Message[]
}
export function submitFeedback(rating: "up" | "down", dialog: DialogContext, ctx: Context): void {
if (!Telemetry.isEnabled()) {
ctx.toast.show({ message: "Feedback disabled: telemetry is off", variant: "info" })
dialog.clear()
return
}
const revertID = ctx.session()?.revert?.messageID
const lastAssistant = ctx.messages().findLast(
(msg): msg is AssistantMessage => msg.role === "assistant" && (!revertID || msg.id < revertID),
)
if (!lastAssistant) {
ctx.toast.show({ message: "No assistant messages found", variant: "error" })
dialog.clear()
return
}
const providerID = lastAssistant.providerID
const payload: Telemetry.FeedbackProperties = {
providerID,
modelID: lastAssistant.modelID,
rating,
}
const variant = (lastAssistant as AssistantMessage & { variant?: string }).variant
if (variant) payload.variant = variant
if (providerID === "kilo") {
payload.sessionID = lastAssistant.sessionID
payload.messageID = lastAssistant.id
payload.parentMessageID = lastAssistant.parentID
}
Telemetry.trackFeedback(payload)
ctx.toast.show({
message: rating === "up" ? "Thanks for the feedback!" : "Thanks — we'll use this to improve.",
variant: "success",
})
dialog.clear()
}
-6
View File
@@ -111,12 +111,6 @@ const icons = {
models: `<path fill-rule="evenodd" clip-rule="evenodd" d="M17.5 10C12.2917 10 10 12.2917 10 17.5C10 12.2917 7.70833 10 2.5 10C7.70833 10 10 7.70833 10 2.5C10 7.70833 12.2917 10 17.5 10Z" stroke="currentColor"/>`,
discard: `<path d="M7.5 5L4.167 8.333L7.5 11.667M4.583 8.333h6.667a4.167 4.167 0 0 1 4.167 4.167" stroke="currentColor" stroke-linecap="square"/>`, // kilocode_change
"arrow-undo-down": `<path d="M4.08333 11.0859L1.75 8.7526L4.08333 6.41927M2.33333 8.7526L12.5417 8.7526L12.5417 3.21094L7 3.21094" stroke="currentColor" stroke-width="1" stroke-linecap="square"/>`,
// kilocode_change start
"thumbs-up": `<path d="M1 8.25a1.25 1.25 0 1 1 2.5 0v7.5a1.25 1.25 0 1 1-2.5 0v-7.5ZM11 3V1.7c0-.268.14-.526.395-.607A2 2 0 0 1 14 3c0 .995-.182 1.948-.514 2.826-.204.54.166 1.174.744 1.174h2.52c1.243 0 2.261 1.01 2.146 2.247a23.864 23.864 0 0 1-1.341 5.974C17.153 16.323 16.072 17 14.9 17h-3.192a3 3 0 0 1-1.341-.317l-2.734-1.366A3 3 0 0 0 6.292 15H5V8h.963c.685 0 1.258-.483 1.612-1.068a4.011 4.011 0 0 1 2.166-1.73c.432-.143.853-.386 1.011-.814.16-.432.248-.9.248-1.388Z" stroke="currentColor" fill="none" stroke-linejoin="round"/>`,
"thumbs-down": `<path d="M18.905 12.75a1.25 1.25 0 0 1-2.5 0v-7.5a1.25 1.25 0 0 1 2.5 0v7.5ZM8.905 17v1.3c0 .268-.14.526-.395.607A2 2 0 0 1 5.905 17c0-.995.182-1.948.514-2.826.204-.54-.166-1.174-.744-1.174h-2.52c-1.243 0-2.261-1.01-2.146-2.247a23.864 23.864 0 0 1 1.341-5.974C2.547 3.677 3.628 3 4.8 3h3.192a3 3 0 0 1 1.341.317l2.734 1.366A3 3 0 0 0 13.408 5H15v7h-.963c-.685 0-1.258.483-1.612 1.068a4.011 4.011 0 0 1-2.166 1.73c-.432.143-.853.386-1.011.814-.16.432-.248.9-.248 1.388Z" stroke="currentColor" fill="none" stroke-linejoin="round"/>`,
"thumbs-up-filled": `<path d="M1 8.25a1.25 1.25 0 1 1 2.5 0v7.5a1.25 1.25 0 1 1-2.5 0v-7.5ZM11 3V1.7c0-.268.14-.526.395-.607A2 2 0 0 1 14 3c0 .995-.182 1.948-.514 2.826-.204.54.166 1.174.744 1.174h2.52c1.243 0 2.261 1.01 2.146 2.247a23.864 23.864 0 0 1-1.341 5.974C17.153 16.323 16.072 17 14.9 17h-3.192a3 3 0 0 1-1.341-.317l-2.734-1.366A3 3 0 0 0 6.292 15H5V8h.963c.685 0 1.258-.483 1.612-1.068a4.011 4.011 0 0 1 2.166-1.73c.432-.143.853-.386 1.011-.814.16-.432.248-.9.248-1.388Z" fill="currentColor"/>`,
"thumbs-down-filled": `<path d="M18.905 12.75a1.25 1.25 0 0 1-2.5 0v-7.5a1.25 1.25 0 0 1 2.5 0v7.5ZM8.905 17v1.3c0 .268-.14.526-.395.607A2 2 0 0 1 5.905 17c0-.995.182-1.948.514-2.826.204-.54-.166-1.174-.744-1.174h-2.52c-1.243 0-2.261-1.01-2.146-2.247a23.864 23.864 0 0 1 1.341-5.974C2.547 3.677 3.628 3 4.8 3h3.192a3 3 0 0 1 1.341.317l2.734 1.366A3 3 0 0 0 13.408 5H15v7h-.963c-.685 0-1.258.483-1.612 1.068a4.011 4.011 0 0 1-2.166 1.73c-.432.143-.853.386-1.011.814-.16.432-.248.9-.248 1.388Z" fill="currentColor"/>`,
// kilocode_change end
}
export interface IconProps extends ComponentProps<"svg"> {
-5
View File
@@ -139,11 +139,6 @@ export const dict = {
"ui.message.revertMessage": "إعادة التعيين إلى هذه النقطة",
"ui.message.copyResponse": "نسخ الرد",
"ui.message.copied": "تم النسخ!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "كان هذا مفيدًا",
"ui.message.feedback.notHelpful": "لم يكن هذا مفيدًا",
"ui.message.feedback.clearRating": "مسح التقييم",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "تمت المقاطعة",
"ui.message.queued": "في الانتظار",
-5
View File
@@ -139,11 +139,6 @@ export const dict = {
"ui.message.revertMessage": "Redefinir para este ponto",
"ui.message.copyResponse": "Copiar resposta",
"ui.message.copied": "Copiado!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "Isso foi útil",
"ui.message.feedback.notHelpful": "Isso não foi útil",
"ui.message.feedback.clearRating": "Limpar avaliação",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "Interrompido",
"ui.message.queued": "Na fila",
-5
View File
@@ -143,11 +143,6 @@ export const dict = {
"ui.message.revertMessage": "Resetuj na ovu tačku",
"ui.message.copyResponse": "Kopiraj odgovor",
"ui.message.copied": "Kopirano!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "Ovo je bilo korisno",
"ui.message.feedback.notHelpful": "Ovo nije bilo korisno",
"ui.message.feedback.clearRating": "Obriši ocjenu",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "Prekinuto",
"ui.message.queued": "U redu",
-5
View File
@@ -138,11 +138,6 @@ export const dict = {
"ui.message.revertMessage": "Nulstil til dette punkt",
"ui.message.copyResponse": "Kopier svar",
"ui.message.copied": "Kopieret!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "Dette var nyttigt",
"ui.message.feedback.notHelpful": "Dette var ikke nyttigt",
"ui.message.feedback.clearRating": "Ryd bedømmelse",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "Afbrudt",
"ui.message.queued": "I kø",
-5
View File
@@ -144,11 +144,6 @@ export const dict = {
"ui.message.revertMessage": "Auf diesen Punkt zurücksetzen",
"ui.message.copyResponse": "Antwort kopieren",
"ui.message.copied": "Kopiert!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "Das war hilfreich",
"ui.message.feedback.notHelpful": "Das war nicht hilfreich",
"ui.message.feedback.clearRating": "Bewertung löschen",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "Unterbrochen",
"ui.message.queued": "In Warteschlange",
-5
View File
@@ -151,11 +151,6 @@ export const dict: Record<string, string> = {
"ui.message.revertMessage": "Revert to here",
"ui.message.copyResponse": "Copy response",
"ui.message.copied": "Copied",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "This was helpful",
"ui.message.feedback.notHelpful": "This wasn't helpful",
"ui.message.feedback.clearRating": "Clear rating",
// kilocode_change end
"ui.message.duration.seconds": "{{count}}s",
"ui.message.duration.minutesSeconds": "{{minutes}}m {{seconds}}s",
"ui.message.interrupted": "Interrupted",
-5
View File
@@ -139,11 +139,6 @@ export const dict = {
"ui.message.revertMessage": "Restablecer a este punto",
"ui.message.copyResponse": "Copiar respuesta",
"ui.message.copied": "¡Copiado!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "Esto fue útil",
"ui.message.feedback.notHelpful": "Esto no fue útil",
"ui.message.feedback.clearRating": "Borrar valoración",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "Interrumpido",
"ui.message.queued": "En cola",
-5
View File
@@ -139,11 +139,6 @@ export const dict = {
"ui.message.revertMessage": "Réinitialiser à ce point",
"ui.message.copyResponse": "Copier la réponse",
"ui.message.copied": "Copié !",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "C'était utile",
"ui.message.feedback.notHelpful": "Ce n'était pas utile",
"ui.message.feedback.clearRating": "Effacer la notation",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "Interrompu",
"ui.message.queued": "En file",
-5
View File
@@ -138,11 +138,6 @@ export const dict = {
"ui.message.revertMessage": "この時点までリセット",
"ui.message.copyResponse": "応答をコピー",
"ui.message.copied": "コピーしました!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "役に立ちました",
"ui.message.feedback.notHelpful": "役に立ちませんでした",
"ui.message.feedback.clearRating": "評価をクリア",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "中断",
"ui.message.queued": "待機中",
-5
View File
@@ -139,11 +139,6 @@ export const dict = {
"ui.message.revertMessage": "이 시점으로 초기화",
"ui.message.copyResponse": "응답 복사",
"ui.message.copied": "복사됨!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "도움이 됐어요",
"ui.message.feedback.notHelpful": "도움이 안 됐어요",
"ui.message.feedback.clearRating": "평가 지우기",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "중단됨",
"ui.message.queued": "대기 중",
-5
View File
@@ -151,11 +151,6 @@ export const dict: Record<string, string> = {
"ui.message.copyMessage": "Bericht kopiëren",
"ui.message.copyResponse": "Antwoord kopiëren",
"ui.message.copied": "Gekopieerd",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "Dit was nuttig",
"ui.message.feedback.notHelpful": "Dit was niet nuttig",
"ui.message.feedback.clearRating": "Beoordeling wissen",
// kilocode_change end
"ui.message.forkMessage": "Fork to new session",
"ui.message.revertMessage": "Hiernaar terugzetten",
"ui.message.revert": "Hiernaar terugdraaien",
-5
View File
@@ -142,11 +142,6 @@ export const dict: Record<Keys, string> = {
"ui.message.revertMessage": "Tilbakestill til dette punktet",
"ui.message.copyResponse": "Kopier svar",
"ui.message.copied": "Kopiert!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "Dette var nyttig",
"ui.message.feedback.notHelpful": "Dette var ikke nyttig",
"ui.message.feedback.clearRating": "Fjern vurdering",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "Avbrutt",
"ui.message.queued": "I kø",
-5
View File
@@ -138,11 +138,6 @@ export const dict = {
"ui.message.revertMessage": "Zresetuj do tego punktu",
"ui.message.copyResponse": "Kopiuj odpowiedź",
"ui.message.copied": "Skopiowano!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "To było pomocne",
"ui.message.feedback.notHelpful": "To nie było pomocne",
"ui.message.feedback.clearRating": "Wyczyść ocenę",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "Przerwano",
"ui.message.queued": "W kolejce",
-5
View File
@@ -138,11 +138,6 @@ export const dict = {
"ui.message.revertMessage": "Сбросить до этого момента",
"ui.message.copyResponse": "Копировать ответ",
"ui.message.copied": "Скопировано!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "Это было полезно",
"ui.message.feedback.notHelpful": "Это было бесполезно",
"ui.message.feedback.clearRating": "Очистить оценку",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "Прервано",
"ui.message.queued": "В очереди",
-5
View File
@@ -140,11 +140,6 @@ export const dict = {
"ui.message.revertMessage": "รีเซ็ตไปยังจุดนี้",
"ui.message.copyResponse": "คัดลอกคำตอบ",
"ui.message.copied": "คัดลอกแล้ว!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "สิ่งนี้มีประโยชน์",
"ui.message.feedback.notHelpful": "สิ่งนี้ไม่มีประโยชน์",
"ui.message.feedback.clearRating": "ล้างการให้คะแนน",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "ถูกขัดจังหวะ",
"ui.message.queued": "อยู่ในคิว",
-5
View File
@@ -146,11 +146,6 @@ export const dict = {
"ui.message.revert": "Revert to here",
"ui.message.copyResponse": "Yanıtı kopyala",
"ui.message.copied": "Kopyalandı",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "Bu yardımcı oldu",
"ui.message.feedback.notHelpful": "Bu yardımcı olmadı",
"ui.message.feedback.clearRating": "Değerlendirmeyi temizle",
// kilocode_change end
"ui.message.interrupted": "Kesildi",
"ui.message.queued": "Sırada",
"ui.message.attachment.alt": "ek",
-5
View File
@@ -156,11 +156,6 @@ export const dict = {
"ui.message.copyMessage": "Копіювати повідомлення",
"ui.message.copyResponse": "Копіювати відповідь",
"ui.message.copied": "Скопійовано",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "Це було корисно",
"ui.message.feedback.notHelpful": "Це не було корисно",
"ui.message.feedback.clearRating": "Очистити оцінку",
// kilocode_change end
"ui.message.forkMessage": "Fork to new session",
"ui.message.revertMessage": "Повернутися сюди",
"ui.message.revert": "Повернутися до цього місця",
-5
View File
@@ -143,11 +143,6 @@ export const dict = {
"ui.message.revertMessage": "重置到此点",
"ui.message.copyResponse": "复制回复",
"ui.message.copied": "已复制!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "这有帮助",
"ui.message.feedback.notHelpful": "这没有帮助",
"ui.message.feedback.clearRating": "清除评分",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "已中断",
"ui.message.queued": "排队中",
-5
View File
@@ -143,11 +143,6 @@ export const dict = {
"ui.message.revertMessage": "重設至此點",
"ui.message.copyResponse": "複製回覆",
"ui.message.copied": "已複製!",
// kilocode_change start - message feedback
"ui.message.feedback.helpful": "這有幫助",
"ui.message.feedback.notHelpful": "這沒有幫助",
"ui.message.feedback.clearRating": "清除評分",
// kilocode_change end
"ui.message.revert": "Revert to here",
"ui.message.interrupted": "已中斷",
"ui.message.queued": "排隊中",