Files
rhema-claw/web/claw/app/components/TurnEntries.vue
T
vhaudiquet 0e5a6c5658 feat(web): interleave thinking blocks with tool calls
Fold thinking deltas into the turn's stream-ordered entries as a
thinking entry, merged back-to-back the way the stream delivers
them, instead of one flat string rendered above every call. Each
thinking block now sits where it streamed — between the calls it
precedes. Live turns keep their thinking expanded; finished turns
render it collapsed.
2026-10-22 20:44:15 +02:00

76 lines
2.0 KiB
Vue

<script setup lang="ts">
// A turn's stream-ordered middle: tool rows, pieces of the thinking
// trace, the agent's asks, its handovers — each at the position the
// stream delivered it, so an ask sits at the tool call that raised it
// and thinking sits between the calls it precedes.
import type { TurnEntry } from '~/composables/useTranscript'
import type { ConsentAnswer } from '~/composables/useClaw'
defineProps<{
entries: TurnEntry[]
/** A live turn's thinking blocks start expanded; finished ones collapse. */
openThinking?: boolean
}>()
const emit = defineEmits<{
consentAnswer: [id: string, answer: ConsentAnswer]
consentDeny: [id: string]
downloadAttachment: [id: string, name: string]
}>()
</script>
<template>
<div v-if="entries.length > 0" class="entries">
<template v-for="(entry, index) in entries" :key="index">
<TurnToolRow v-if="entry.kind === 'tool'" :row="entry.row" />
<details v-else-if="entry.kind === 'thinking'" class="thinking" :open="openThinking">
<summary>thinking</summary>
<pre>{{ entry.text }}</pre>
</details>
<TurnConsentCard
v-else-if="entry.kind === 'consent'"
:consent="entry.consent"
@answer="(id, answer) => emit('consentAnswer', id, answer)"
@deny="(id) => emit('consentDeny', id)"
/>
<TurnAttachmentCard
v-else
:attachment="entry.attachment"
@download="(id, name) => emit('downloadAttachment', id, name)"
/>
</template>
</div>
</template>
<style scoped>
.entries {
display: flex;
flex-direction: column;
gap: 4px;
margin-bottom: 10px;
}
.thinking {
color: var(--text3);
}
.thinking summary {
cursor: pointer;
font-size: 11px;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.thinking pre {
margin: 6px 0 0;
padding: 8px 10px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text3);
font-style: italic;
white-space: pre-wrap;
overflow-wrap: anywhere;
}
</style>