|
|
@@ -4,6 +4,7 @@ import {
|
|
|
Message as MessageType,
|
|
|
Part as PartType,
|
|
|
type PermissionRequest,
|
|
|
+ type QuestionRequest,
|
|
|
TextPart,
|
|
|
ToolPart,
|
|
|
} from "@opencode-ai/sdk/v2/client"
|
|
|
@@ -150,6 +151,8 @@ export function SessionTurn(
|
|
|
const emptyAssistant: AssistantMessage[] = []
|
|
|
const emptyPermissions: PermissionRequest[] = []
|
|
|
const emptyPermissionParts: { part: ToolPart; message: AssistantMessage }[] = []
|
|
|
+ const emptyQuestions: QuestionRequest[] = []
|
|
|
+ const emptyQuestionParts: { part: ToolPart; message: AssistantMessage }[] = []
|
|
|
const emptyDiffs: FileDiff[] = []
|
|
|
const idle = { type: "idle" as const }
|
|
|
|
|
|
@@ -281,6 +284,51 @@ export function SessionTurn(
|
|
|
return emptyPermissionParts
|
|
|
})
|
|
|
|
|
|
+ const questions = createMemo(() => data.store.question?.[props.sessionID] ?? emptyQuestions)
|
|
|
+ const nextQuestion = createMemo(() => questions()[0])
|
|
|
+
|
|
|
+ const questionParts = createMemo(() => {
|
|
|
+ if (props.stepsExpanded) return emptyQuestionParts
|
|
|
+
|
|
|
+ const next = nextQuestion()
|
|
|
+ if (!next || !next.tool) return emptyQuestionParts
|
|
|
+
|
|
|
+ const message = findLast(assistantMessages(), (m) => m.id === next.tool!.messageID)
|
|
|
+ if (!message) return emptyQuestionParts
|
|
|
+
|
|
|
+ const parts = data.store.part[message.id] ?? emptyParts
|
|
|
+ for (const part of parts) {
|
|
|
+ if (part?.type !== "tool") continue
|
|
|
+ const tool = part as ToolPart
|
|
|
+ if (tool.callID === next.tool?.callID) return [{ part: tool, message }]
|
|
|
+ }
|
|
|
+
|
|
|
+ return emptyQuestionParts
|
|
|
+ })
|
|
|
+
|
|
|
+ const answeredQuestionParts = createMemo(() => {
|
|
|
+ if (props.stepsExpanded) return emptyQuestionParts
|
|
|
+ if (questions().length > 0) return emptyQuestionParts
|
|
|
+
|
|
|
+ const result: { part: ToolPart; message: AssistantMessage }[] = []
|
|
|
+
|
|
|
+ for (const msg of assistantMessages()) {
|
|
|
+ const parts = data.store.part[msg.id] ?? emptyParts
|
|
|
+ for (const part of parts) {
|
|
|
+ if (part?.type !== "tool") continue
|
|
|
+ const tool = part as ToolPart
|
|
|
+ if (tool.tool !== "question") continue
|
|
|
+ // @ts-expect-error metadata may not exist on all tool states
|
|
|
+ const answers = tool.state?.metadata?.answers
|
|
|
+ if (answers && answers.length > 0) {
|
|
|
+ result.push({ part: tool, message: msg })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result
|
|
|
+ })
|
|
|
+
|
|
|
const shellModePart = createMemo(() => {
|
|
|
const p = parts()
|
|
|
if (p.length === 0) return
|
|
|
@@ -640,6 +688,20 @@ export function SessionTurn(
|
|
|
</For>
|
|
|
</div>
|
|
|
</Show>
|
|
|
+ <Show when={!props.stepsExpanded && questionParts().length > 0}>
|
|
|
+ <div data-slot="session-turn-question-parts">
|
|
|
+ <For each={questionParts()}>
|
|
|
+ {({ part, message }) => <Part part={part} message={message} />}
|
|
|
+ </For>
|
|
|
+ </div>
|
|
|
+ </Show>
|
|
|
+ <Show when={!props.stepsExpanded && answeredQuestionParts().length > 0}>
|
|
|
+ <div data-slot="session-turn-answered-question-parts">
|
|
|
+ <For each={answeredQuestionParts()}>
|
|
|
+ {({ part, message }) => <Part part={part} message={message} />}
|
|
|
+ </For>
|
|
|
+ </div>
|
|
|
+ </Show>
|
|
|
{/* Response */}
|
|
|
<div class="sr-only" aria-live="polite">
|
|
|
{!working() && response() ? response() : ""}
|