mirror of
https://github.com/anomalyco/opencode.git
synced 2026-02-01 22:48:16 +00:00
fix: adjust resolve parts so that when messages with multiple @ references occur, the tool calls are properly ordered
This commit is contained in:
@@ -172,6 +172,14 @@ export namespace SessionProcessor {
|
||||
case "tool-result": {
|
||||
const match = toolcalls[value.toolCallId]
|
||||
if (match && match.state.status === "running") {
|
||||
const attachments = value.output.attachments?.map(
|
||||
(attachment: Omit<MessageV2.FilePart, "id" | "messageID" | "sessionID">) => ({
|
||||
...attachment,
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: match.messageID,
|
||||
sessionID: match.sessionID,
|
||||
}),
|
||||
)
|
||||
await Session.updatePart({
|
||||
...match,
|
||||
state: {
|
||||
@@ -184,7 +192,7 @@ export namespace SessionProcessor {
|
||||
start: match.state.time.start,
|
||||
end: Date.now(),
|
||||
},
|
||||
attachments: value.output.attachments,
|
||||
attachments,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -187,13 +187,17 @@ export namespace SessionPrompt {
|
||||
text: template,
|
||||
},
|
||||
]
|
||||
const files = ConfigMarkdown.files(template)
|
||||
const matches = ConfigMarkdown.files(template)
|
||||
const seen = new Set<string>()
|
||||
await Promise.all(
|
||||
files.map(async (match) => {
|
||||
const name = match[1]
|
||||
if (seen.has(name)) return
|
||||
const names = matches
|
||||
.map((match) => match[1])
|
||||
.filter((name) => {
|
||||
if (seen.has(name)) return false
|
||||
seen.add(name)
|
||||
return true
|
||||
})
|
||||
const resolved = await Promise.all(
|
||||
names.map(async (name) => {
|
||||
const filepath = name.startsWith("~/")
|
||||
? path.join(os.homedir(), name.slice(2))
|
||||
: path.resolve(Instance.worktree, name)
|
||||
@@ -201,33 +205,34 @@ export namespace SessionPrompt {
|
||||
const stats = await fs.stat(filepath).catch(() => undefined)
|
||||
if (!stats) {
|
||||
const agent = await Agent.get(name)
|
||||
if (agent) {
|
||||
parts.push({
|
||||
type: "agent",
|
||||
name: agent.name,
|
||||
})
|
||||
}
|
||||
return
|
||||
if (!agent) return undefined
|
||||
return {
|
||||
type: "agent",
|
||||
name: agent.name,
|
||||
} satisfies PromptInput["parts"][number]
|
||||
}
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
parts.push({
|
||||
return {
|
||||
type: "file",
|
||||
url: `file://${filepath}`,
|
||||
filename: name,
|
||||
mime: "application/x-directory",
|
||||
})
|
||||
return
|
||||
} satisfies PromptInput["parts"][number]
|
||||
}
|
||||
|
||||
parts.push({
|
||||
return {
|
||||
type: "file",
|
||||
url: `file://${filepath}`,
|
||||
filename: name,
|
||||
mime: "text/plain",
|
||||
})
|
||||
} satisfies PromptInput["parts"][number]
|
||||
}),
|
||||
)
|
||||
for (const item of resolved) {
|
||||
if (!item) continue
|
||||
parts.push(item)
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
@@ -424,6 +429,12 @@ export namespace SessionPrompt {
|
||||
assistantMessage.time.completed = Date.now()
|
||||
await Session.updateMessage(assistantMessage)
|
||||
if (result && part.state.status === "running") {
|
||||
const attachments = result.attachments?.map((attachment) => ({
|
||||
...attachment,
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMessage.id,
|
||||
sessionID: assistantMessage.sessionID,
|
||||
}))
|
||||
await Session.updatePart({
|
||||
...part,
|
||||
state: {
|
||||
@@ -432,7 +443,7 @@ export namespace SessionPrompt {
|
||||
title: result.title,
|
||||
metadata: result.metadata,
|
||||
output: result.output,
|
||||
attachments: result.attachments,
|
||||
attachments,
|
||||
time: {
|
||||
...part.state.time,
|
||||
end: Date.now(),
|
||||
@@ -771,16 +782,13 @@ export namespace SessionPrompt {
|
||||
)
|
||||
|
||||
const textParts: string[] = []
|
||||
const attachments: MessageV2.FilePart[] = []
|
||||
const attachments: Omit<MessageV2.FilePart, "id" | "messageID" | "sessionID">[] = []
|
||||
|
||||
for (const contentItem of result.content) {
|
||||
if (contentItem.type === "text") {
|
||||
textParts.push(contentItem.text)
|
||||
} else if (contentItem.type === "image") {
|
||||
attachments.push({
|
||||
id: Identifier.ascending("part"),
|
||||
sessionID: input.session.id,
|
||||
messageID: input.processor.message.id,
|
||||
type: "file",
|
||||
mime: contentItem.mimeType,
|
||||
url: `data:${contentItem.mimeType};base64,${contentItem.data}`,
|
||||
@@ -792,9 +800,6 @@ export namespace SessionPrompt {
|
||||
}
|
||||
if (resource.blob) {
|
||||
attachments.push({
|
||||
id: Identifier.ascending("part"),
|
||||
sessionID: input.session.id,
|
||||
messageID: input.processor.message.id,
|
||||
type: "file",
|
||||
mime: resource.mimeType ?? "application/octet-stream",
|
||||
url: `data:${resource.mimeType ?? "application/octet-stream"};base64,${resource.blob}`,
|
||||
@@ -1032,6 +1037,7 @@ export namespace SessionPrompt {
|
||||
pieces.push(
|
||||
...result.attachments.map((attachment) => ({
|
||||
...attachment,
|
||||
id: Identifier.ascending("part"),
|
||||
synthetic: true,
|
||||
filename: attachment.filename ?? part.filename,
|
||||
messageID: info.id,
|
||||
@@ -1169,7 +1175,18 @@ export namespace SessionPrompt {
|
||||
},
|
||||
]
|
||||
}),
|
||||
).then((x) => x.flat())
|
||||
)
|
||||
.then((x) => x.flat())
|
||||
.then((drafts) =>
|
||||
drafts.map(
|
||||
(part): MessageV2.Part => ({
|
||||
...part,
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: info.id,
|
||||
sessionID: input.sessionID,
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
await Plugin.trigger(
|
||||
"chat.message",
|
||||
|
||||
@@ -77,6 +77,12 @@ export const BatchTool = Tool.define("batch", async () => {
|
||||
})
|
||||
|
||||
const result = await tool.execute(validatedParams, { ...ctx, callID: partID })
|
||||
const attachments = result.attachments?.map((attachment) => ({
|
||||
...attachment,
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: ctx.messageID,
|
||||
sessionID: ctx.sessionID,
|
||||
}))
|
||||
|
||||
await Session.updatePart({
|
||||
id: partID,
|
||||
@@ -91,7 +97,7 @@ export const BatchTool = Tool.define("batch", async () => {
|
||||
output: result.output,
|
||||
title: result.title,
|
||||
metadata: result.metadata,
|
||||
attachments: result.attachments,
|
||||
attachments,
|
||||
time: {
|
||||
start: callStartTime,
|
||||
end: Date.now(),
|
||||
|
||||
@@ -6,7 +6,6 @@ import { LSP } from "../lsp"
|
||||
import { FileTime } from "../file/time"
|
||||
import DESCRIPTION from "./read.txt"
|
||||
import { Instance } from "../project/instance"
|
||||
import { Identifier } from "../id/id"
|
||||
import { assertExternalDirectory } from "./external-directory"
|
||||
import { InstructionPrompt } from "../session/instruction"
|
||||
|
||||
@@ -79,9 +78,6 @@ export const ReadTool = Tool.define("read", {
|
||||
},
|
||||
attachments: [
|
||||
{
|
||||
id: Identifier.ascending("part"),
|
||||
sessionID: ctx.sessionID,
|
||||
messageID: ctx.messageID,
|
||||
type: "file",
|
||||
mime,
|
||||
url: `data:${mime};base64,${Buffer.from(await file.bytes()).toString("base64")}`,
|
||||
|
||||
@@ -36,7 +36,7 @@ export namespace Tool {
|
||||
title: string
|
||||
metadata: M
|
||||
output: string
|
||||
attachments?: MessageV2.FilePart[]
|
||||
attachments?: Omit<MessageV2.FilePart, "id" | "sessionID" | "messageID">[]
|
||||
}>
|
||||
formatValidationError?(error: z.ZodError): string
|
||||
}>
|
||||
|
||||
Reference in New Issue
Block a user