All blocks Explain the difference between signal() and computed(). AI signal() holds writable state; computed() derives a read-only value from one or more signals and re-evaluates lazily when its dependencies change. Branch 1 of 3
Block
Branch navigation + edit
ChatGPT-style edit-and-regenerate. Edit the user message inline; the assistant has multiple sibling responses you can swap with branch-nav. Both messages have hover-revealed action bars.
Edit user → swap assistant branches
<!-- User message: edit-trigger=hidden, programmatically opened from the actions bar -->
<div class="group flex flex-col items-end gap-1">
<pk-message class="justify-end">
<pk-message-edit #userEditor editTrigger="hidden"
[content]="userMessage()" (saved)="onSaveUser($event)">
<pk-message-content
class="bg-primary text-primary-foreground"
[content]="userMessage()"
/>
</pk-message-edit>
</pk-message>
<pk-message-actions-bar
[actions]="DEFAULT_USER_ACTIONS"
(actionPicked)="onUserAction($event, userEditor)"
/>
</div>
<!-- Assistant message with sibling branches -->
<div class="group flex flex-col gap-1">
<pk-message>
<pk-message-avatar src="" alt="Assistant" fallback="AI" />
<pk-message-content [content]="currentBranch()" />
</pk-message>
<div class="ml-11 flex items-center justify-between gap-2">
<pk-branch-nav
[current]="branchIdx()"
[total]="branches.length"
(changed)="branchIdx.set($event)"
/>
<pk-message-actions-bar
[actions]="assistantActions()"
(actionPicked)="onAssistantAction($event)"
/>
</div>
</div>
// Component
protected readonly userMessage = signal('Explain the difference...');
protected readonly branches = ['...', '...', '...'];
protected readonly branchIdx = signal(1);
protected readonly currentBranch = computed(
() => this.branches[this.branchIdx() - 1]
);
protected onUserAction(action: MessageAction, editor: PkMessageEdit) {
if (action.id === 'edit') editor.startEdit();
}
protected onSaveUser(next: string) {
this.userMessage.set(next);
this.branchIdx.set(1); // reset to the first sibling
}
protected onAssistantAction(action: MessageAction) {
if (action.id === 'regenerate') {
this.branchIdx.set(this.branches.length); // pretend a new branch was added
}
}