feat: add audit/activity log view with timeline and event filtering (#17)

Add a dedicated /audit route displaying a chronological timeline of
orchestration events (state transitions, tool invocations, errors,
messages) grouped by session. Includes session selector, event type
filtering, URL deep-linking via ?session=id, and audit event capture
during chat streaming.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
shahondin1624
2026-03-12 12:41:40 +01:00
parent 807311d7c9
commit 4fc84ccd62
8 changed files with 572 additions and 0 deletions

View File

@@ -19,6 +19,7 @@
import { OrchestrationState } from '$lib/proto/llm_multiverse/v1/orchestrator_pb';
import { sessionStore } from '$lib/stores/sessions.svelte';
import { memoryStore } from '$lib/stores/memory.svelte';
import { auditStore } from '$lib/stores/audit.svelte';
let messages: ChatMessage[] = $state([]);
let isStreaming = $state(false);
@@ -32,6 +33,7 @@
let showConfig = $state(false);
const lineageHref = resolveRoute('/lineage');
const memoryHref = resolveRoute('/memory');
const auditHref = resolveRoute('/audit');
const isNonDefaultConfig = $derived(
sessionConfig.overrideLevel !== OverrideLevel.NONE ||
@@ -80,6 +82,7 @@
finalResult = null;
const sessionId = sessionStore.activeSessionId!;
let lastAuditState = OrchestrationState.UNSPECIFIED;
const userMessage: ChatMessage = {
id: crypto.randomUUID(),
@@ -103,6 +106,18 @@
try {
for await (const response of processRequest(sessionId, content, sessionConfig)) {
orchestrationState = response.state;
// Capture state changes to the audit log
if (response.state !== lastAuditState) {
const stateLabel = OrchestrationState[response.state] ?? String(response.state);
auditStore.addEvent(sessionId, {
eventType: 'state_change',
details: response.message || `State changed to ${stateLabel}`,
state: stateLabel
});
lastAuditState = response.state;
}
if (response.intermediateResult) {
intermediateResult = response.intermediateResult;
}
@@ -131,6 +146,10 @@
? `Error (${err.code}): ${err.message}`
: 'An unexpected error occurred';
error = msg;
auditStore.addEvent(sessionId, {
eventType: 'error',
details: msg
});
const idx = messages.length - 1;
messages[idx] = {
...messages[idx],
@@ -163,6 +182,12 @@
>
Memory
</a>
<a
href={auditHref}
class="rounded-lg px-2.5 py-1.5 text-sm text-gray-600 hover:bg-gray-100 hover:text-gray-900"
>
Audit
</a>
<!-- eslint-enable svelte/no-navigation-without-resolve -->
<button
type="button"