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:
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user