refactor(schema): rename V2 session events and normalize payloads (#35217)
This commit is contained in:
parent
4790a2772c
commit
394e0b9045
63 changed files with 1888 additions and 1989 deletions
|
|
@ -27,6 +27,8 @@ import { createSignal, onCleanup } from "solid-js"
|
|||
|
||||
export type DataSessionStatus = "idle" | "running"
|
||||
|
||||
const messageIDFromEvent = (eventID: string) => eventID.replace(/^evt_/, "msg_")
|
||||
|
||||
type LocationData = {
|
||||
agent?: AgentV2Info[]
|
||||
command?: CommandV2Info[]
|
||||
|
|
@ -181,17 +183,21 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
const info = store.session.info[sessionID]
|
||||
if (!info) return
|
||||
const rootID = resolveRoot(sessionID)
|
||||
setStore("session", "family", produce((draft) => {
|
||||
if (sessionID !== rootID && draft[sessionID]) {
|
||||
const members = draft[rootID] ??= []
|
||||
for (const id of draft[sessionID]) {
|
||||
if (!members.includes(id)) members.push(id)
|
||||
setStore(
|
||||
"session",
|
||||
"family",
|
||||
produce((draft) => {
|
||||
if (sessionID !== rootID && draft[sessionID]) {
|
||||
const members = (draft[rootID] ??= [])
|
||||
for (const id of draft[sessionID]) {
|
||||
if (!members.includes(id)) members.push(id)
|
||||
}
|
||||
delete draft[sessionID]
|
||||
}
|
||||
delete draft[sessionID]
|
||||
}
|
||||
const family = draft[rootID] ??= []
|
||||
if (!family.includes(sessionID)) family.push(sessionID)
|
||||
}))
|
||||
const family = (draft[rootID] ??= [])
|
||||
if (!family.includes(sessionID)) family.push(sessionID)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
function handleEvent(event: V2Event) {
|
||||
|
|
@ -214,124 +220,113 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
case "skill.updated":
|
||||
void result.location.skill.refresh(event.location)
|
||||
break
|
||||
case "session.next.agent.switched":
|
||||
case "agent.selected":
|
||||
if (store.session.info[event.data.sessionID])
|
||||
setStore("session", "info", event.data.sessionID, "agent", event.data.agent)
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
message.append(draft, index, {
|
||||
id: event.data.messageID,
|
||||
id: messageIDFromEvent(event.id),
|
||||
type: "agent-switched",
|
||||
agent: event.data.agent,
|
||||
time: { created: event.data.timestamp },
|
||||
time: { created: event.created },
|
||||
})
|
||||
})
|
||||
break
|
||||
case "session.next.model.switched":
|
||||
case "model.selected":
|
||||
if (store.session.info[event.data.sessionID])
|
||||
setStore("session", "info", event.data.sessionID, "model", event.data.model)
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
message.append(draft, index, {
|
||||
id: event.data.messageID,
|
||||
id: messageIDFromEvent(event.id),
|
||||
type: "model-switched",
|
||||
model: event.data.model,
|
||||
time: { created: event.data.timestamp },
|
||||
time: { created: event.created },
|
||||
})
|
||||
})
|
||||
break
|
||||
case "session.next.renamed":
|
||||
case "renamed":
|
||||
if (store.session.info[event.data.sessionID])
|
||||
setStore("session", "info", event.data.sessionID, "title", event.data.title)
|
||||
break
|
||||
case "session.next.prompted": {
|
||||
case "prompt.promoted": {
|
||||
setStore("session", "status", event.data.sessionID, "running")
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const position = index.get(event.data.messageID)
|
||||
const position = index.get(event.data.inputID)
|
||||
const existing = position === undefined ? undefined : draft[position]
|
||||
if (existing?.type === "user") {
|
||||
existing.text = event.data.prompt.text
|
||||
existing.files = event.data.prompt.files
|
||||
existing.agents = event.data.prompt.agents
|
||||
existing.time.created = event.data.timestamp
|
||||
existing.time.created = event.created
|
||||
if (existing.metadata?.queued === true) {
|
||||
delete existing.metadata.queued
|
||||
if (Object.keys(existing.metadata).length === 0) existing.metadata = undefined
|
||||
}
|
||||
return
|
||||
}
|
||||
message.append(draft, index, {
|
||||
id: event.data.messageID,
|
||||
type: "user",
|
||||
text: event.data.prompt.text,
|
||||
files: event.data.prompt.files,
|
||||
agents: event.data.prompt.agents,
|
||||
time: { created: event.data.timestamp },
|
||||
})
|
||||
})
|
||||
break
|
||||
}
|
||||
case "session.next.prompt.admitted":
|
||||
case "prompt.admitted":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
message.append(draft, index, {
|
||||
id: event.data.messageID,
|
||||
id: event.data.inputID,
|
||||
type: "user",
|
||||
text: event.data.prompt.text,
|
||||
files: event.data.prompt.files,
|
||||
agents: event.data.prompt.agents,
|
||||
metadata: { queued: true },
|
||||
time: { created: event.data.timestamp },
|
||||
time: { created: event.created },
|
||||
})
|
||||
})
|
||||
break
|
||||
case "session.next.context.updated":
|
||||
case "session.context.updated":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
message.append(draft, index, {
|
||||
id: event.data.messageID,
|
||||
id: messageIDFromEvent(event.id),
|
||||
type: "system",
|
||||
text: event.data.text,
|
||||
time: { created: event.data.timestamp },
|
||||
time: { created: event.created },
|
||||
})
|
||||
})
|
||||
break
|
||||
case "session.next.synthetic":
|
||||
case "synthetic":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
message.append(draft, index, {
|
||||
id: event.data.messageID,
|
||||
id: messageIDFromEvent(event.id),
|
||||
type: "synthetic",
|
||||
sessionID: event.data.sessionID,
|
||||
text: event.data.text,
|
||||
description: event.data.description,
|
||||
time: { created: event.data.timestamp },
|
||||
time: { created: event.created },
|
||||
})
|
||||
})
|
||||
break
|
||||
case "session.next.shell.started":
|
||||
case "shell.started":
|
||||
setStore("session", "status", event.data.sessionID, "running")
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
message.append(draft, index, {
|
||||
id: event.data.messageID,
|
||||
id: messageIDFromEvent(event.id),
|
||||
type: "shell",
|
||||
callID: event.data.callID,
|
||||
command: event.data.command,
|
||||
output: "",
|
||||
time: { created: event.data.timestamp },
|
||||
time: { created: event.created },
|
||||
})
|
||||
})
|
||||
break
|
||||
case "session.next.shell.ended":
|
||||
case "shell.ended":
|
||||
setStore("session", "status", event.data.sessionID, "idle")
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const match = message.activeShell(draft, event.data.callID)
|
||||
if (!match) return
|
||||
match.output = event.data.output
|
||||
match.time.completed = event.data.timestamp
|
||||
match.time.completed = event.created
|
||||
})
|
||||
break
|
||||
case "session.next.step.started":
|
||||
case "step.started":
|
||||
setStore("session", "status", event.data.sessionID, "running")
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
if (index.has(event.data.assistantMessageID)) return
|
||||
const currentAssistant = message.activeAssistant(draft)
|
||||
if (currentAssistant) currentAssistant.time.completed = event.data.timestamp
|
||||
if (currentAssistant) currentAssistant.time.completed = event.created
|
||||
message.append(draft, index, {
|
||||
id: event.data.assistantMessageID,
|
||||
type: "assistant",
|
||||
|
|
@ -339,16 +334,16 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
model: event.data.model,
|
||||
content: [],
|
||||
snapshot: event.data.snapshot ? { start: event.data.snapshot } : undefined,
|
||||
time: { created: event.data.timestamp },
|
||||
time: { created: event.created },
|
||||
})
|
||||
})
|
||||
break
|
||||
case "session.next.step.ended":
|
||||
case "step.ended":
|
||||
setStore("session", "status", event.data.sessionID, "running")
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const currentAssistant = message.assistant(draft, index, event.data.assistantMessageID)
|
||||
if (!currentAssistant) return
|
||||
currentAssistant.time.completed = event.data.timestamp
|
||||
currentAssistant.time.completed = event.created
|
||||
currentAssistant.finish = event.data.finish
|
||||
currentAssistant.cost = event.data.cost
|
||||
currentAssistant.tokens = event.data.tokens
|
||||
|
|
@ -356,16 +351,16 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
currentAssistant.snapshot = { ...currentAssistant.snapshot, end: event.data.snapshot }
|
||||
})
|
||||
break
|
||||
case "session.next.step.failed":
|
||||
case "step.failed":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const currentAssistant = message.assistant(draft, index, event.data.assistantMessageID)
|
||||
if (!currentAssistant) return
|
||||
currentAssistant.time.completed = event.data.timestamp
|
||||
currentAssistant.time.completed = event.created
|
||||
currentAssistant.finish = "error"
|
||||
currentAssistant.error = event.data.error
|
||||
})
|
||||
break
|
||||
case "session.next.text.started":
|
||||
case "text.started":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
message.assistant(draft, index, event.data.assistantMessageID)?.content.push({
|
||||
type: "text",
|
||||
|
|
@ -374,7 +369,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
})
|
||||
})
|
||||
break
|
||||
case "session.next.text.delta":
|
||||
case "text.delta":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const match = message.latestText(
|
||||
message.assistant(draft, index, event.data.assistantMessageID),
|
||||
|
|
@ -383,7 +378,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
if (match) match.text += event.data.delta
|
||||
})
|
||||
break
|
||||
case "session.next.text.ended":
|
||||
case "text.ended":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const match = message.latestText(
|
||||
message.assistant(draft, index, event.data.assistantMessageID),
|
||||
|
|
@ -392,18 +387,18 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
if (match) match.text = event.data.text
|
||||
})
|
||||
break
|
||||
case "session.next.tool.input.started":
|
||||
case "tool.input.started":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
message.assistant(draft, index, event.data.assistantMessageID)?.content.push({
|
||||
type: "tool",
|
||||
id: event.data.callID,
|
||||
name: event.data.name,
|
||||
time: { created: event.data.timestamp },
|
||||
time: { created: event.created },
|
||||
state: { status: "pending", input: "" },
|
||||
})
|
||||
})
|
||||
break
|
||||
case "session.next.tool.input.delta":
|
||||
case "tool.input.delta":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const match = message.latestTool(
|
||||
message.assistant(draft, index, event.data.assistantMessageID),
|
||||
|
|
@ -412,7 +407,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
if (match?.state.status === "pending") match.state.input += event.data.delta
|
||||
})
|
||||
break
|
||||
case "session.next.tool.input.ended":
|
||||
case "tool.input.ended":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const match = message.latestTool(
|
||||
message.assistant(draft, index, event.data.assistantMessageID),
|
||||
|
|
@ -421,19 +416,19 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
if (match?.state.status === "pending") match.state.input = event.data.text
|
||||
})
|
||||
break
|
||||
case "session.next.tool.called":
|
||||
case "tool.called":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const match = message.latestTool(
|
||||
message.assistant(draft, index, event.data.assistantMessageID),
|
||||
event.data.callID,
|
||||
)
|
||||
if (!match) return
|
||||
match.time.ran = event.data.timestamp
|
||||
match.time.ran = event.created
|
||||
match.provider = event.data.provider
|
||||
match.state = { status: "running", input: event.data.input, structured: {}, content: [] }
|
||||
})
|
||||
break
|
||||
case "session.next.tool.progress":
|
||||
case "tool.progress":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const match = message.latestTool(
|
||||
message.assistant(draft, index, event.data.assistantMessageID),
|
||||
|
|
@ -444,7 +439,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
match.state.content = [...event.data.content]
|
||||
})
|
||||
break
|
||||
case "session.next.tool.success":
|
||||
case "tool.success":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const match = message.latestTool(
|
||||
message.assistant(draft, index, event.data.assistantMessageID),
|
||||
|
|
@ -463,10 +458,10 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
metadata: match.provider?.metadata,
|
||||
resultMetadata: event.data.provider.metadata,
|
||||
}
|
||||
match.time.completed = event.data.timestamp
|
||||
match.time.completed = event.created
|
||||
})
|
||||
break
|
||||
case "session.next.tool.failed":
|
||||
case "tool.failed":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const match = message.latestTool(
|
||||
message.assistant(draft, index, event.data.assistantMessageID),
|
||||
|
|
@ -486,21 +481,21 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
metadata: match.provider?.metadata,
|
||||
resultMetadata: event.data.provider.metadata,
|
||||
}
|
||||
match.time.completed = event.data.timestamp
|
||||
match.time.completed = event.created
|
||||
})
|
||||
break
|
||||
case "session.next.reasoning.started":
|
||||
case "reasoning.started":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
message.assistant(draft, index, event.data.assistantMessageID)?.content.push({
|
||||
type: "reasoning",
|
||||
id: event.data.reasoningID,
|
||||
text: "",
|
||||
providerMetadata: event.data.providerMetadata,
|
||||
time: { created: event.data.timestamp },
|
||||
time: { created: event.created },
|
||||
})
|
||||
})
|
||||
break
|
||||
case "session.next.reasoning.delta":
|
||||
case "reasoning.delta":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const match = message.latestReasoning(
|
||||
message.assistant(draft, index, event.data.assistantMessageID),
|
||||
|
|
@ -509,7 +504,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
if (match) match.text += event.data.delta
|
||||
})
|
||||
break
|
||||
case "session.next.reasoning.ended":
|
||||
case "reasoning.ended":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
const match = message.latestReasoning(
|
||||
message.assistant(draft, index, event.data.assistantMessageID),
|
||||
|
|
@ -517,38 +512,38 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
)
|
||||
if (match) {
|
||||
match.text = event.data.text
|
||||
match.time = { created: match.time?.created ?? event.data.timestamp, completed: event.data.timestamp }
|
||||
match.time = { created: match.time?.created ?? event.created, completed: event.created }
|
||||
if (event.data.providerMetadata !== undefined) match.providerMetadata = event.data.providerMetadata
|
||||
}
|
||||
})
|
||||
break
|
||||
case "session.next.retried":
|
||||
case "session.next.compaction.started":
|
||||
case "retried":
|
||||
case "compaction.started":
|
||||
setStore("session", "status", event.data.sessionID, "running")
|
||||
break
|
||||
case "session.next.execution.settled":
|
||||
case "execution.settled":
|
||||
setStore("session", "status", event.data.sessionID, "idle")
|
||||
break
|
||||
case "session.next.revert.staged":
|
||||
case "revert.staged":
|
||||
if (store.session.info[event.data.sessionID])
|
||||
setStore("session", "info", event.data.sessionID, "revert", event.data.revert)
|
||||
break
|
||||
case "session.next.revert.cleared":
|
||||
case "session.next.revert.committed":
|
||||
case "revert.cleared":
|
||||
case "revert.committed":
|
||||
if (store.session.info[event.data.sessionID])
|
||||
setStore("session", "info", event.data.sessionID, "revert", undefined)
|
||||
break
|
||||
case "session.next.compaction.delta":
|
||||
case "compaction.delta":
|
||||
break
|
||||
case "session.next.compaction.ended":
|
||||
case "compaction.ended":
|
||||
message.update(event.data.sessionID, (draft, index) => {
|
||||
message.append(draft, index, {
|
||||
id: event.data.messageID,
|
||||
id: messageIDFromEvent(event.id),
|
||||
type: "compaction",
|
||||
reason: event.data.reason,
|
||||
summary: event.data.text,
|
||||
recent: event.data.recent,
|
||||
time: { created: event.data.timestamp },
|
||||
time: { created: event.created },
|
||||
})
|
||||
})
|
||||
break
|
||||
|
|
@ -692,8 +687,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
return liveByID.get(message.id) ?? message
|
||||
}),
|
||||
...live.filter((message) => !loadedIDs.has(message.id)),
|
||||
]
|
||||
.toSorted((a, b) => a.time.created - b.time.created)
|
||||
].toSorted((a, b) => a.time.created - b.time.created)
|
||||
messageIndex.set(sessionID, new Map(messages.map((message, index) => [message.id, index])))
|
||||
setStore("session", "message", sessionID, messages)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -74,17 +74,17 @@ const tui: TuiPlugin = async (api) => {
|
|||
notify(api, sessionID, "Session done", session?.parentID ? "subagent_done" : "done")
|
||||
}
|
||||
|
||||
api.event.on("session.next.prompted", (event) => started(event.data.sessionID))
|
||||
api.event.on("session.next.shell.started", (event) => started(event.data.sessionID))
|
||||
api.event.on("session.next.step.started", (event) => started(event.data.sessionID))
|
||||
api.event.on("session.next.retried", (event) => started(event.data.sessionID))
|
||||
api.event.on("session.next.compaction.started", (event) => started(event.data.sessionID))
|
||||
api.event.on("session.next.shell.ended", (event) => ended(event.data.sessionID))
|
||||
api.event.on("session.next.step.ended", (event) => {
|
||||
api.event.on("prompt.promoted", (event) => started(event.data.sessionID))
|
||||
api.event.on("shell.started", (event) => started(event.data.sessionID))
|
||||
api.event.on("step.started", (event) => started(event.data.sessionID))
|
||||
api.event.on("retried", (event) => started(event.data.sessionID))
|
||||
api.event.on("compaction.started", (event) => started(event.data.sessionID))
|
||||
api.event.on("shell.ended", (event) => ended(event.data.sessionID))
|
||||
api.event.on("step.ended", (event) => {
|
||||
if (event.data.finish === "tool-calls") return
|
||||
ended(event.data.sessionID)
|
||||
})
|
||||
api.event.on("session.next.step.failed", (event) => {
|
||||
api.event.on("step.failed", (event) => {
|
||||
const sessionID = event.data.sessionID
|
||||
if (!active.has(sessionID)) return
|
||||
errored.add(sessionID)
|
||||
|
|
|
|||
|
|
@ -126,45 +126,49 @@ export function createSessionRows(sessionID: Accessor<string>) {
|
|||
return index === -1 ? rows.length : index
|
||||
}
|
||||
|
||||
const message = (event: { data: { sessionID: string; messageID: string } }) => {
|
||||
if (event.data.sessionID === sessionID()) appendMessage(event.data.messageID)
|
||||
const message = (event: { id: string; data: { sessionID: string } }) => {
|
||||
if (event.data.sessionID === sessionID()) appendMessage(event.id.replace(/^evt_/, "msg_"))
|
||||
}
|
||||
const input = (event: { data: { sessionID: string; inputID: string } }) => {
|
||||
if (event.data.sessionID === sessionID()) appendMessage(event.data.inputID)
|
||||
}
|
||||
const subscriptions = [
|
||||
data.on("session.next.prompt.admitted", message),
|
||||
data.on("session.next.prompted", message),
|
||||
data.on("session.next.context.updated", message),
|
||||
data.on("session.next.synthetic", (event) => {
|
||||
if (event.data.sessionID === sessionID() && event.data.description?.trim()) appendMessage(event.data.messageID)
|
||||
data.on("prompt.admitted", input),
|
||||
data.on("prompt.promoted", input),
|
||||
data.on("session.context.updated", message),
|
||||
data.on("synthetic", (event) => {
|
||||
if (event.data.sessionID === sessionID() && event.data.description?.trim())
|
||||
appendMessage(event.id.replace(/^evt_/, "msg_"))
|
||||
}),
|
||||
data.on("session.next.shell.started", message),
|
||||
data.on("session.next.agent.switched", message),
|
||||
data.on("session.next.model.switched", message),
|
||||
data.on("session.next.compaction.ended", message),
|
||||
data.on("session.next.text.delta", (event) => {
|
||||
data.on("shell.started", message),
|
||||
data.on("agent.selected", message),
|
||||
data.on("model.selected", message),
|
||||
data.on("compaction.ended", message),
|
||||
data.on("text.delta", (event) => {
|
||||
if (event.data.sessionID === sessionID())
|
||||
appendPart({ messageID: event.data.assistantMessageID, partID: event.data.textID })
|
||||
}),
|
||||
data.on("session.next.text.ended", (event) => {
|
||||
data.on("text.ended", (event) => {
|
||||
if (event.data.sessionID === sessionID() && event.data.text.trim())
|
||||
appendPart({ messageID: event.data.assistantMessageID, partID: event.data.textID })
|
||||
}),
|
||||
data.on("session.next.reasoning.delta", (event) => {
|
||||
data.on("reasoning.delta", (event) => {
|
||||
if (event.data.sessionID === sessionID())
|
||||
appendPart({ messageID: event.data.assistantMessageID, partID: event.data.reasoningID })
|
||||
}),
|
||||
data.on("session.next.reasoning.ended", (event) => {
|
||||
data.on("reasoning.ended", (event) => {
|
||||
if (event.data.sessionID === sessionID() && event.data.text.trim())
|
||||
appendPart({ messageID: event.data.assistantMessageID, partID: event.data.reasoningID })
|
||||
}),
|
||||
data.on("session.next.tool.input.started", (event) => {
|
||||
data.on("tool.input.started", (event) => {
|
||||
if (event.data.sessionID === sessionID())
|
||||
appendPart({ messageID: event.data.assistantMessageID, partID: event.data.callID }, event.data.name)
|
||||
}),
|
||||
data.on("session.next.step.ended", (event) => {
|
||||
data.on("step.ended", (event) => {
|
||||
if (event.data.sessionID !== sessionID() || ["tool-calls", "unknown"].includes(event.data.finish)) return
|
||||
appendFooter(event.data.assistantMessageID)
|
||||
}),
|
||||
data.on("session.next.step.failed", (event) => {
|
||||
data.on("step.failed", (event) => {
|
||||
if (event.data.sessionID === sessionID()) appendFooter(event.data.assistantMessageID)
|
||||
}),
|
||||
]
|
||||
|
|
@ -229,8 +233,6 @@ function hasPart(rows: SessionRow[], ref: PartRef) {
|
|||
return rows.some((row) => {
|
||||
if (row.type === "part") return row.ref.messageID === ref.messageID && row.ref.partID === ref.partID
|
||||
if (row.type !== "group") return false
|
||||
return [...row.refs, ...row.pending].some(
|
||||
(item) => item.messageID === ref.messageID && item.partID === ref.partID,
|
||||
)
|
||||
return [...row.refs, ...row.pending].some((item) => item.messageID === ref.messageID && item.partID === ref.partID)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue