Merge pull request 'feat: add final result rendering with status badges and artifacts' (#30) from feature/issue-10-final-result into main
This commit was merged in pull request #30.
This commit is contained in:
@@ -11,3 +11,4 @@
|
|||||||
| #7 | Streaming response rendering | COMPLETED | [issue-007.md](issue-007.md) |
|
| #7 | Streaming response rendering | COMPLETED | [issue-007.md](issue-007.md) |
|
||||||
| #8 | Orchestration state progress indicator | COMPLETED | [issue-008.md](issue-008.md) |
|
| #8 | Orchestration state progress indicator | COMPLETED | [issue-008.md](issue-008.md) |
|
||||||
| #9 | Intermediate results display | COMPLETED | [issue-009.md](issue-009.md) |
|
| #9 | Intermediate results display | COMPLETED | [issue-009.md](issue-009.md) |
|
||||||
|
| #10 | Final result rendering with artifacts | COMPLETED | [issue-010.md](issue-010.md) |
|
||||||
|
|||||||
18
implementation-plans/issue-010.md
Normal file
18
implementation-plans/issue-010.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
---
|
||||||
|
|
||||||
|
# Issue #10: Final result rendering with artifacts
|
||||||
|
|
||||||
|
**Status:** COMPLETED
|
||||||
|
**Issue:** https://git.shahondin1624.de/llm-multiverse/llm-multiverse-ui/issues/10
|
||||||
|
**Branch:** `feature/issue-10-final-result`
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [x] summary field rendered as the main response content
|
||||||
|
- [x] artifacts displayed as viewable items
|
||||||
|
- [x] result_quality shown as a badge (Verified/Inferred/Uncertain)
|
||||||
|
- [x] source shown as a badge (Tool Output/Model Knowledge/Web)
|
||||||
|
- [x] FAILED status styled with error/red treatment
|
||||||
|
- [x] PARTIAL status styled with warning/yellow treatment
|
||||||
|
- [x] Successful results styled with success/green treatment
|
||||||
77
src/lib/components/FinalResult.svelte
Normal file
77
src/lib/components/FinalResult.svelte
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { SubagentResult } from '$lib/proto/llm_multiverse/v1/common_pb';
|
||||||
|
import { ResultStatus, ResultQuality, ResultSource } from '$lib/proto/llm_multiverse/v1/common_pb';
|
||||||
|
|
||||||
|
let { result }: { result: SubagentResult } = $props();
|
||||||
|
|
||||||
|
const statusConfig = $derived.by(() => {
|
||||||
|
switch (result.status) {
|
||||||
|
case ResultStatus.SUCCESS:
|
||||||
|
return { label: 'Success', bg: 'bg-green-100', text: 'text-green-800', border: 'border-green-200' };
|
||||||
|
case ResultStatus.PARTIAL:
|
||||||
|
return { label: 'Partial', bg: 'bg-amber-100', text: 'text-amber-800', border: 'border-amber-200' };
|
||||||
|
case ResultStatus.FAILED:
|
||||||
|
return { label: 'Failed', bg: 'bg-red-100', text: 'text-red-800', border: 'border-red-200' };
|
||||||
|
default:
|
||||||
|
return { label: 'Unknown', bg: 'bg-gray-100', text: 'text-gray-800', border: 'border-gray-200' };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const qualityLabel = $derived.by(() => {
|
||||||
|
switch (result.resultQuality) {
|
||||||
|
case ResultQuality.VERIFIED: return 'Verified';
|
||||||
|
case ResultQuality.INFERRED: return 'Inferred';
|
||||||
|
case ResultQuality.UNCERTAIN: return 'Uncertain';
|
||||||
|
default: return '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const sourceLabel = $derived.by(() => {
|
||||||
|
switch (result.source) {
|
||||||
|
case ResultSource.TOOL_OUTPUT: return 'Tool Output';
|
||||||
|
case ResultSource.MODEL_KNOWLEDGE: return 'Model Knowledge';
|
||||||
|
case ResultSource.WEB: return 'Web';
|
||||||
|
default: return '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="mx-4 mb-3 rounded-xl border {statusConfig.border} {statusConfig.bg} p-4">
|
||||||
|
<div class="mb-2 flex items-center gap-2">
|
||||||
|
<span class="rounded-full px-2.5 py-0.5 text-xs font-medium {statusConfig.bg} {statusConfig.text}">
|
||||||
|
{statusConfig.label}
|
||||||
|
</span>
|
||||||
|
{#if qualityLabel}
|
||||||
|
<span class="rounded-full bg-blue-100 px-2.5 py-0.5 text-xs font-medium text-blue-800">
|
||||||
|
{qualityLabel}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
{#if sourceLabel}
|
||||||
|
<span class="rounded-full bg-purple-100 px-2.5 py-0.5 text-xs font-medium text-purple-800">
|
||||||
|
{sourceLabel}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if result.summary}
|
||||||
|
<p class="text-sm {statusConfig.text}">{result.summary}</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if result.failureReason}
|
||||||
|
<p class="mt-2 text-sm text-red-700">Reason: {result.failureReason}</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if result.artifacts.length > 0}
|
||||||
|
<div class="mt-3 border-t {statusConfig.border} pt-3">
|
||||||
|
<p class="mb-1.5 text-xs font-medium text-gray-600">Artifacts</p>
|
||||||
|
<ul class="space-y-1">
|
||||||
|
{#each result.artifacts as artifact (artifact)}
|
||||||
|
<li class="flex items-center gap-2 text-sm">
|
||||||
|
<span class="text-gray-400">📄</span>
|
||||||
|
<span class="font-mono text-xs text-gray-700">{artifact}</span>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { ChatMessage } from '$lib/types';
|
import type { ChatMessage } from '$lib/types';
|
||||||
|
import type { SubagentResult } from '$lib/proto/llm_multiverse/v1/common_pb';
|
||||||
import MessageList from '$lib/components/MessageList.svelte';
|
import MessageList from '$lib/components/MessageList.svelte';
|
||||||
import MessageInput from '$lib/components/MessageInput.svelte';
|
import MessageInput from '$lib/components/MessageInput.svelte';
|
||||||
import OrchestrationProgress from '$lib/components/OrchestrationProgress.svelte';
|
import OrchestrationProgress from '$lib/components/OrchestrationProgress.svelte';
|
||||||
import ThinkingSection from '$lib/components/ThinkingSection.svelte';
|
import ThinkingSection from '$lib/components/ThinkingSection.svelte';
|
||||||
|
import FinalResult from '$lib/components/FinalResult.svelte';
|
||||||
import { processRequest, OrchestratorError } from '$lib/services/orchestrator';
|
import { processRequest, OrchestratorError } from '$lib/services/orchestrator';
|
||||||
import { OrchestrationState } from '$lib/proto/llm_multiverse/v1/orchestrator_pb';
|
import { OrchestrationState } from '$lib/proto/llm_multiverse/v1/orchestrator_pb';
|
||||||
|
|
||||||
@@ -13,11 +15,13 @@
|
|||||||
let sessionId = $state(crypto.randomUUID());
|
let sessionId = $state(crypto.randomUUID());
|
||||||
let orchestrationState: OrchestrationState = $state(OrchestrationState.UNSPECIFIED);
|
let orchestrationState: OrchestrationState = $state(OrchestrationState.UNSPECIFIED);
|
||||||
let intermediateResult: string = $state('');
|
let intermediateResult: string = $state('');
|
||||||
|
let finalResult: SubagentResult | null = $state(null);
|
||||||
|
|
||||||
async function handleSend(content: string) {
|
async function handleSend(content: string) {
|
||||||
error = null;
|
error = null;
|
||||||
orchestrationState = OrchestrationState.UNSPECIFIED;
|
orchestrationState = OrchestrationState.UNSPECIFIED;
|
||||||
intermediateResult = '';
|
intermediateResult = '';
|
||||||
|
finalResult = null;
|
||||||
|
|
||||||
const userMessage: ChatMessage = {
|
const userMessage: ChatMessage = {
|
||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
@@ -43,6 +47,9 @@
|
|||||||
if (response.intermediateResult) {
|
if (response.intermediateResult) {
|
||||||
intermediateResult = response.intermediateResult;
|
intermediateResult = response.intermediateResult;
|
||||||
}
|
}
|
||||||
|
if (response.finalResult) {
|
||||||
|
finalResult = response.finalResult;
|
||||||
|
}
|
||||||
const idx = messages.length - 1;
|
const idx = messages.length - 1;
|
||||||
messages[idx] = {
|
messages[idx] = {
|
||||||
...messages[idx],
|
...messages[idx],
|
||||||
@@ -91,6 +98,10 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if finalResult && !isStreaming}
|
||||||
|
<FinalResult result={finalResult} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if error}
|
{#if error}
|
||||||
<div class="mx-4 mb-2 rounded-lg bg-red-50 px-4 py-2 text-sm text-red-600">
|
<div class="mx-4 mb-2 rounded-lg bg-red-50 px-4 py-2 text-sm text-red-600">
|
||||||
{error}
|
{error}
|
||||||
|
|||||||
Reference in New Issue
Block a user