Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ function planPart(): Extract<ChatPart, { type: 'plan' }> {

function clarifyPart(
presentation?: string,
resolution: Extract<ChatPart, { type: 'interrupt' }>['resolution'] = 'replied',
): Extract<ChatPart, { type: 'interrupt' }> {
return {
type: 'interrupt',
Expand All @@ -198,7 +199,7 @@ function clarifyPart(
runId: 'plan-run-1',
step: 'confirm_scope',
},
resolution: 'replied',
resolution,
busy: false,
error: '',
}
Expand Down Expand Up @@ -980,6 +981,21 @@ describe('AssistantMessage activity disclosure', () => {
expect(el.querySelector('.clarify-outcome--plan')).toBeNull()
})

it('does not render an unavailable questionnaire as an action or success receipt', async () => {
const unavailable = clarifyPart('plan_questionnaire_v1', 'unavailable')
const el = mountMessage(baseMessage({
text: '',
timelineItems: [approvalTimelineItem(unavailable)],
parts: [unavailable, planPart()],
statusHistory: [],
}))
await nextTick()

expect(el.querySelector('.plan-card')).not.toBeNull()
expect(el.querySelector('.clarify-card')).toBeNull()
expect(el.querySelector('.clarify-outcome')).toBeNull()
})

it('keeps intermediate candidate narration inside activity and the final answer outside once', async () => {
const el = mountMessage(baseMessage({
text: 'Final verified answer.',
Expand Down
17 changes: 14 additions & 3 deletions opensquilla-webui/src/components/chat/AssistantMessage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,8 @@ const planParts = computed(
const hasPlan = computed(() => planParts.value.length > 0)
const standaloneInterruptParts = computed(() =>
interruptParts.value.filter(part => (
!timelineResolvedInterruptKeys.value.has(part.key)
!(part.interruptKind === 'clarify' && part.resolution === 'unavailable')
&& !timelineResolvedInterruptKeys.value.has(part.key)
&& !(
hasPlan.value
&& part.interruptKind === 'clarify'
Expand Down Expand Up @@ -916,11 +917,21 @@ function withoutFailedActivity(
})
}

function withoutUnavailableClarifies(
items: ChatStreamTimelineItem[],
): ChatStreamTimelineItem[] {
return items.filter(item => !(
item.type === 'interrupt'
&& item.part.interruptKind === 'clarify'
&& item.part.resolution === 'unavailable'
))
}

const visibleActivityItems = computed(() =>
withoutFailedActivity(activityProjection.value.activityItems),
withoutUnavailableClarifies(withoutFailedActivity(activityProjection.value.activityItems)),
)
const visibleLegacyTimelineItems = computed(() =>
withoutFailedActivity(props.message.timelineItems ?? []),
withoutUnavailableClarifies(withoutFailedActivity(props.message.timelineItems ?? [])),
)
const visibleActivityCallKeys = computed(() => new Set(
visibleActivityItems.value.flatMap(item =>
Expand Down
2 changes: 2 additions & 0 deletions opensquilla-webui/src/components/chat/PlanRunRibbon.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,8 @@ describe('PlanRunRibbon', () => {
expect(chatViewSource).toContain('@stop="onComposerStop"')
expect(chatViewSource).toContain('@focus-return="focusComposerAfterPlanRun"')
expect(chatViewSource).toContain(':stop-targets-plan-run="composerStopsPlanRun"')
expect(chatViewSource).toContain('planRunSettlementPending.value')
expect(chatViewSource).toContain('planActionPending !== null || planRunSettlementPending')
expect(chatViewSource).toContain("activePlanRun.value?.status === 'queued'")
expect(chatViewSource).toContain("activePlanRun.value?.status === 'running'")
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
@extend="emit('extend', part.approval.approvalId)"
/>
<ClarifyCard
v-else-if="part.interruptKind === 'clarify' && part.clarify"
v-else-if="
part.interruptKind === 'clarify'
&& part.clarify
&& (part.resolution == null || part.resolution === 'replied')
"
:request="part.clarify"
:submitted="part.resolution === 'replied'"
:busy="part.busy"
Expand Down
Loading
Loading