mirror of
https://github.com/aljazceru/opencode.git
synced 2026-01-26 03:05:00 +01:00
tui: add copy last assistant message to session menu
This commit is contained in:
@@ -177,17 +177,14 @@ function App() {
|
|||||||
const exit = useExit()
|
const exit = useExit()
|
||||||
|
|
||||||
useKeyboard(async (evt) => {
|
useKeyboard(async (evt) => {
|
||||||
|
if (!Installation.isLocal()) return
|
||||||
if (evt.meta && evt.name === "t") {
|
if (evt.meta && evt.name === "t") {
|
||||||
if (process.env.DEBUG) {
|
renderer.toggleDebugOverlay()
|
||||||
renderer.toggleDebugOverlay()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evt.meta && evt.name === "d") {
|
if (evt.meta && evt.name === "d") {
|
||||||
if (process.env.DEBUG) {
|
renderer.console.toggle()
|
||||||
renderer.console.toggle()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ import { LANGUAGE_EXTENSIONS } from "@/lsp/language"
|
|||||||
import parsers from "../../../../../../parsers-config.ts"
|
import parsers from "../../../../../../parsers-config.ts"
|
||||||
import { Clipboard } from "../../util/clipboard"
|
import { Clipboard } from "../../util/clipboard"
|
||||||
import { Toast, useToast } from "../../ui/toast"
|
import { Toast, useToast } from "../../ui/toast"
|
||||||
import { DialogSessionRename } from "../../component/dialog-session-rename"
|
|
||||||
import { useKV } from "../../context/kv.tsx"
|
import { useKV } from "../../context/kv.tsx"
|
||||||
|
|
||||||
addDefaultParsers(parsers.parsers)
|
addDefaultParsers(parsers.parsers)
|
||||||
@@ -401,12 +400,49 @@ export function Session() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Rename session",
|
title: "Copy last assistant message",
|
||||||
value: "session.rename",
|
value: "messages.copy",
|
||||||
keybind: "session_rename",
|
keybind: "messages_copy",
|
||||||
category: "Session",
|
category: "Session",
|
||||||
onSelect: (dialog) => {
|
onSelect: (dialog) => {
|
||||||
dialog.replace(() => <DialogSessionRename session={route.sessionID} />)
|
const lastAssistantMessage = messages().findLast((msg) => msg.role === "assistant")
|
||||||
|
if (!lastAssistantMessage) {
|
||||||
|
toast.show({ message: "No assistant messages found", variant: "error" })
|
||||||
|
dialog.clear()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = sync.data.part[lastAssistantMessage.id] ?? []
|
||||||
|
const textParts = parts.filter((part) => part.type === "text")
|
||||||
|
if (textParts.length === 0) {
|
||||||
|
toast.show({ message: "No text parts found in last assistant message", variant: "error" })
|
||||||
|
dialog.clear()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = textParts
|
||||||
|
.map((part) => part.text)
|
||||||
|
.join("\n")
|
||||||
|
.trim()
|
||||||
|
if (!text) {
|
||||||
|
toast.show({
|
||||||
|
message: "No text content found in last assistant message",
|
||||||
|
variant: "error",
|
||||||
|
})
|
||||||
|
dialog.clear()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(text)
|
||||||
|
const base64 = Buffer.from(text).toString("base64")
|
||||||
|
const osc52 = `\x1b]52;c;${base64}\x07`
|
||||||
|
const finalOsc52 = process.env["TMUX"] ? `\x1bPtmux;\x1b${osc52}\x1b\\` : osc52
|
||||||
|
/* @ts-expect-error */
|
||||||
|
renderer.writeOut(finalOsc52)
|
||||||
|
Clipboard.copy(text)
|
||||||
|
.then(() => toast.show({ message: "Message copied to clipboard!", variant: "success" }))
|
||||||
|
.catch(() => toast.show({ message: "Failed to copy to clipboard", variant: "error" }))
|
||||||
|
dialog.clear()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -431,6 +467,47 @@ export function Session() {
|
|||||||
dialog.clear()
|
dialog.clear()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Copy last assistant message",
|
||||||
|
value: "messages.copy",
|
||||||
|
keybind: "messages_copy",
|
||||||
|
category: "Session",
|
||||||
|
onSelect: (dialog) => {
|
||||||
|
const lastAssistantMessage = messages().findLast((msg) => msg.role === "assistant")
|
||||||
|
if (lastAssistantMessage) {
|
||||||
|
const parts = sync.data.part[lastAssistantMessage.id] ?? []
|
||||||
|
const textParts = parts.filter((part) => part.type === "text")
|
||||||
|
if (textParts.length > 0) {
|
||||||
|
const text = textParts
|
||||||
|
.map((part) => part.text)
|
||||||
|
.join("\n")
|
||||||
|
.trim()
|
||||||
|
if (text) {
|
||||||
|
Clipboard.copy(text)
|
||||||
|
.then(() =>
|
||||||
|
toast.show({ message: "Message copied to clipboard!", variant: "success" }),
|
||||||
|
)
|
||||||
|
.catch(() =>
|
||||||
|
toast.show({ message: "Failed to copy to clipboard", variant: "error" }),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
toast.show({
|
||||||
|
message: "No text content found in last assistant message",
|
||||||
|
variant: "error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toast.show({
|
||||||
|
message: "No text parts found in last assistant message",
|
||||||
|
variant: "error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toast.show({ message: "No assistant messages found", variant: "error" })
|
||||||
|
}
|
||||||
|
dialog.clear()
|
||||||
|
},
|
||||||
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
const revert = createMemo(() => {
|
const revert = createMemo(() => {
|
||||||
|
|||||||
@@ -320,7 +320,10 @@ export namespace File {
|
|||||||
log.info("search", { query: input.query })
|
log.info("search", { query: input.query })
|
||||||
const limit = input.limit ?? 100
|
const limit = input.limit ?? 100
|
||||||
const result = await state().then((x) => x.files())
|
const result = await state().then((x) => x.files())
|
||||||
if (!input.query) return input.dirs !== false ? result.dirs.toSorted().slice(0, limit) : []
|
if (!input.query)
|
||||||
|
return input.dirs !== false
|
||||||
|
? result.dirs.toSorted().slice(0, limit)
|
||||||
|
: result.files.slice(0, limit)
|
||||||
const items = input.dirs !== false ? [...result.files, ...result.dirs] : result.files
|
const items = input.dirs !== false ? [...result.files, ...result.dirs] : result.files
|
||||||
const sorted = fuzzysort.go(input.query, items, { limit: limit }).map((r) => r.target)
|
const sorted = fuzzysort.go(input.query, items, { limit: limit }).map((r) => r.target)
|
||||||
log.info("search", { query: input.query, results: sorted.length })
|
log.info("search", { query: input.query, results: sorted.length })
|
||||||
|
|||||||
Reference in New Issue
Block a user