mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-24 20:33:26 +00:00
fix(app): place thinking above queued prompts (#44616)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
This commit is contained in:
parent
6704f34cad
commit
e282066cf8
4 changed files with 43 additions and 3 deletions
|
|
@ -68,6 +68,14 @@ export function createTimelineController(input: { session: TimelineSessionSource
|
|||
input.session.data.info()?.revert?.messageID,
|
||||
)
|
||||
})
|
||||
const pendingUserMessageIDs = createMemo(() => {
|
||||
const id = input.session.identity.sessionID()
|
||||
return new Set(
|
||||
(id ? data.session.pending.list(id) : []).flatMap((item) =>
|
||||
item.type === "user" && item.delivery === "steer" ? [item.id] : [],
|
||||
),
|
||||
)
|
||||
})
|
||||
const titleValue = createMemo(() => input.session.data.info()?.title)
|
||||
const titleLabel = createMemo(() => sessionTitle(titleValue()) ?? language.t("command.session.new"))
|
||||
const parentMessages = createMemo(() => {
|
||||
|
|
@ -97,6 +105,7 @@ export function createTimelineController(input: { session: TimelineSessionSource
|
|||
sessionMessages: projectedMessages,
|
||||
status: input.session.data.status,
|
||||
showReasoningSummaries: settings.general.showReasoningSummaries,
|
||||
pendingUserMessageIDs,
|
||||
})
|
||||
const [pending, setPending] = createStore({ rename: false })
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export function createTimelineProjection(input: {
|
|||
sessionMessages: Accessor<SessionMessageInfo[]>
|
||||
status: Accessor<SessionStatus>
|
||||
showReasoningSummaries: Accessor<boolean>
|
||||
pendingUserMessageIDs: Accessor<ReadonlySet<string>>
|
||||
}) {
|
||||
const sessionMessageByID = createMemo(
|
||||
() => new Map(input.sessionMessages().map((message) => [message.id, message] as const)),
|
||||
|
|
@ -75,7 +76,12 @@ export function createTimelineProjection(input: {
|
|||
return result
|
||||
})
|
||||
const projection = createMemo(() =>
|
||||
Timeline.constructSessionMessageRows(input.sessionMessages(), input.showReasoningSummaries(), input.status()),
|
||||
Timeline.constructSessionMessageRows(
|
||||
input.sessionMessages(),
|
||||
input.showReasoningSummaries(),
|
||||
input.status(),
|
||||
input.pendingUserMessageIDs(),
|
||||
),
|
||||
)
|
||||
const activeMessageID = createMemo(() => projection().activeMessageID)
|
||||
const rows = createMemo((previous: TimelineRow.TimelineRow[] | undefined) =>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export type TimelineProjectionInput = {
|
|||
sessionMessages: SessionMessageInfo[]
|
||||
status: SessionStatus
|
||||
showReasoningSummaries: boolean
|
||||
pendingUserMessageIDs?: ReadonlySet<string>
|
||||
previousRows?: TimelineRow.TimelineRow[]
|
||||
}
|
||||
|
||||
|
|
@ -34,6 +35,7 @@ export function createTimelineProjection(input: TimelineProjectionInput) {
|
|||
input.sessionMessages,
|
||||
input.showReasoningSummaries,
|
||||
input.status,
|
||||
input.pendingUserMessageIDs,
|
||||
)
|
||||
const rows = reuseTimelineRows(input.previousRows, projection.rows)
|
||||
const rowByKey = new Map(rows.map((row) => [TimelineRow.key(row), row] as const))
|
||||
|
|
@ -65,6 +67,7 @@ export function createReactiveTimelineProjection(input: {
|
|||
sessionMessages: Accessor<SessionMessageInfo[]>
|
||||
status: Accessor<SessionStatus>
|
||||
showReasoningSummaries: Accessor<boolean>
|
||||
pendingUserMessageIDs?: Accessor<ReadonlySet<string>>
|
||||
}) {
|
||||
const sessionMessageByID = createMemo(
|
||||
() => new Map(input.sessionMessages().map((message) => [message.id, message] as const)),
|
||||
|
|
@ -72,7 +75,12 @@ export function createReactiveTimelineProjection(input: {
|
|||
const userContextByID = createMemo(() => indexUserContext(input.sessionMessages()))
|
||||
const assistantMessagesByParent = createMemo(() => indexAssistantMessages(input.sessionMessages()))
|
||||
const projection = createMemo(() =>
|
||||
Timeline.constructSessionMessageRows(input.sessionMessages(), input.showReasoningSummaries(), input.status()),
|
||||
Timeline.constructSessionMessageRows(
|
||||
input.sessionMessages(),
|
||||
input.showReasoningSummaries(),
|
||||
input.status(),
|
||||
input.pendingUserMessageIDs?.(),
|
||||
),
|
||||
)
|
||||
const activeMessageID = createMemo(() => projection().activeMessageID)
|
||||
const rows = createMemo((previous: TimelineRow.TimelineRow[] | undefined) =>
|
||||
|
|
@ -119,6 +127,7 @@ export namespace Timeline {
|
|||
messages: SessionMessageInfo[],
|
||||
showReasoning: boolean,
|
||||
status: SessionStatus,
|
||||
pendingUserMessageIDs?: ReadonlySet<string>,
|
||||
) {
|
||||
type Turn = {
|
||||
id: string
|
||||
|
|
@ -169,7 +178,7 @@ export namespace Timeline {
|
|||
current = turn
|
||||
})
|
||||
|
||||
const activeMessageID = turns.at(-1)?.id
|
||||
const activeMessageID = turns.findLast((turn) => !pendingUserMessageIDs?.has(turn.id))?.id ?? turns.at(-1)?.id
|
||||
return {
|
||||
activeMessageID,
|
||||
rows: [
|
||||
|
|
|
|||
|
|
@ -166,6 +166,22 @@ describe("current session timeline rows", () => {
|
|||
])
|
||||
})
|
||||
|
||||
test("renders thinking above a queued user message", () => {
|
||||
const source = [
|
||||
{ id: "msg_active", type: "user", text: "active", time: { created: 1 } },
|
||||
{ id: "msg_queued", type: "user", text: "queued", time: { created: 2 } },
|
||||
] satisfies SessionMessageInfo[]
|
||||
const result = Timeline.constructSessionMessageRows(source, true, { type: "busy" }, new Set(["msg_queued"]))
|
||||
|
||||
expect(result.activeMessageID).toBe("msg_active")
|
||||
expect(result.rows.map(TimelineRow.key)).toEqual([
|
||||
"user-message:msg_active",
|
||||
"thinking:msg_active",
|
||||
"turn-gap:msg_queued",
|
||||
"user-message:msg_queued",
|
||||
])
|
||||
})
|
||||
|
||||
test("suppresses thinking while a subagent is delegating or running", () => {
|
||||
const statuses = ["streaming", "running"] as const
|
||||
statuses.forEach((status) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue