make file attachments work good like

This commit is contained in:
Dax Raad 2025-07-04 16:20:12 -04:00
parent 994368de15
commit 45b139390c
2 changed files with 46 additions and 21 deletions

View file

@ -362,35 +362,57 @@ export namespace Session {
const app = App.info() const app = App.info()
input.parts = await Promise.all( input.parts = await Promise.all(
input.parts.map(async (part) => { input.parts.map(async (part): Promise<Message.MessagePart[]> => {
if (part.type === "file") { if (part.type === "file") {
const url = new URL(part.url) const url = new URL(part.url)
switch (url.protocol) { switch (url.protocol) {
case "file:": case "file:":
let content = await Bun.file( let content = Bun.file(path.join(app.path.cwd, url.pathname))
path.join(app.path.cwd, url.pathname),
).text() if (part.mediaType === "text/plain") {
const range = { let text = await content.text()
start: url.searchParams.get("start"), const range = {
end: url.searchParams.get("end"), start: url.searchParams.get("start"),
} end: url.searchParams.get("end"),
if (range.start != null && part.mediaType === "text/plain") { }
const lines = content.split("\n") if (range.start != null && part.mediaType === "text/plain") {
const start = parseInt(range.start) const lines = text.split("\n")
const end = range.end ? parseInt(range.end) : lines.length const start = parseInt(range.start)
content = lines.slice(start, end).join("\n") const end = range.end ? parseInt(range.end) : lines.length
} text = lines.slice(start, end).join("\n")
return { }
type: "file", return [
url: `data:${part.mediaType};base64,` + btoa(content), {
mediaType: part.mediaType, type: "text",
filename: part.filename, text: [
"Called the Read tool on " + url.pathname,
"<results>",
text,
"</results>",
].join("\n"),
},
]
} }
return [
{
type: "text",
text: ["Called the Read tool on " + url.pathname].join("\n"),
},
{
type: "file",
url:
`data:${part.mediaType};base64,` +
Buffer.from(await content.bytes()).toString("base64url"),
mediaType: part.mediaType,
filename: path.basename(part.filename!),
},
]
} }
} }
return part return [part]
}), }),
) ).then((x) => x.flat())
if (msgs.length === 0 && !session.parentID) { if (msgs.length === 0 && !session.parentID) {
generateText({ generateText({
maxTokens: input.providerID === "google" ? 1024 : 20, maxTokens: input.providerID === "google" ? 1024 : 20,

View file

@ -134,6 +134,7 @@ func (m *messagesComponent) renderView(width int) {
switch message.Role { switch message.Role {
case opencode.MessageRoleUser: case opencode.MessageRoleUser:
userLoop:
for partIndex, part := range message.Parts { for partIndex, part := range message.Parts {
switch part := part.AsUnion().(type) { switch part := part.AsUnion().(type) {
case opencode.TextPart: case opencode.TextPart:
@ -195,6 +196,8 @@ func (m *messagesComponent) renderView(width int) {
m = m.updateSelected(content, part.Text) m = m.updateSelected(content, part.Text)
blocks = append(blocks, content) blocks = append(blocks, content)
} }
// Only render the first text part
break userLoop
} }
} }