refactor(frontend): clean metadata on AssistantChatPanel + TaskDrawer
- AssistantChatPanel: C:3→C:4 (33 side-effecting functions), remove JSDoc duplicates (INV_4), add @PRE/@POST/@SIDE_EFFECT/@DATA_CONTRACT/@RATIONALE/@REJECTED - TaskDrawer: remove JSDoc duplicates (INV_4), replace 4x @PURPOSE JSDoc blocks with @BRIEF/@PRE/@POST in function contracts (INV_4), add @RATIONALE/@REJECTED - Both: consolidate all metadata in HTML comment #region, remove scattered JSDoc in <script>
This commit is contained in:
@@ -1,31 +1,31 @@
|
||||
<!-- #region AssistantChatPanel [C:3] [TYPE Component] [SEMANTICS assistant, chat, panel, conversation, confirmation] -->
|
||||
<!-- #region AssistantChatPanel [C:4] [TYPE Component] [SEMANTICS assistant, chat, panel, conversation, confirmation] -->
|
||||
<!-- @ingroup Assistant -->
|
||||
<!-- @BRIEF Component component: lib/components/assistant/AssistantChatPanel.svelte -->
|
||||
<!-- @BRIEF Assistant chat workspace for mixed-initiative dataset review clarification, contextual actions, and task tracking. -->
|
||||
<!-- @LAYER UI -->
|
||||
<!-- @PRE Assistant chat store, API adapters, and optional dataset review session context are initialized before the panel becomes interactive. -->
|
||||
<!-- @POST User and assistant message state, conversation history, and task affordances stay synchronized with the active conversation scope. -->
|
||||
<!-- @SIDE_EFFECT Reads and mutates assistant conversation state, may navigate to review routes, opens task drawer affordances, and emits toast feedback. -->
|
||||
<!-- @DATA_CONTRACT Input[{variant,className,assistantChatStore,datasetReviewSessionId?}] → Output[{messages,conversations,conversationId,llmReady,panelVisible}] -->
|
||||
<!-- @INVARIANT User commands and assistant responses are appended in chronological order. -->
|
||||
<!-- @INVARIANT Risky operations are executed only through explicit confirm action. -->
|
||||
<!-- @RELATION BINDS_TO -> [EXT:frontend:assistantChatStore] -->
|
||||
<!-- @RELATION BINDS_TO -> [EXT:frontend:datasetReviewSessionStore] -->
|
||||
<!-- @RELATION CALLS -> [AssistantApi] -->
|
||||
<!-- @RELATION DISPATCHES -> [EXT:frontend:taskDrawerStore] -->
|
||||
<!-- @RELATION DEPENDS_ON -> [AssistantClarificationCard] -->
|
||||
<!-- @RELATION DEPENDS_ON -> [ToolCallCard] -->
|
||||
<!-- @RELATION DEPENDS_ON -> [AgentChatModel] -->
|
||||
<!-- @UX_STATE Closed -> Panel is hidden when variant is drawer. -->
|
||||
<!-- @UX_STATE Embedded -> Panel mounts inline as the primary workspace canvas. -->
|
||||
<!-- @UX_STATE LoadingHistory -> Existing conversation history is loading. -->
|
||||
<!-- @UX_STATE Idle -> Input is available and no request in progress. -->
|
||||
<!-- @UX_STATE Sending -> Input locked while request is pending. -->
|
||||
<!-- @UX_STATE Error -> Failed action rendered as assistant failed message. -->
|
||||
<!-- @UX_FEEDBACK Started operation surfaces task_id and quick action to open task drawer. -->
|
||||
<!-- @UX_RECOVERY User can retry command or action from input and action buttons. -->
|
||||
<!-- @RATIONALE C:3→C:4 upgrade: 33 side-effecting functions (API calls, navigation, store mutations, file I/O) warrant stateful tier. JSDoc duplicates removed (INV_4). Model extraction deferred — AgentChatModel already handles Gradio-powered agent interaction; remaining logic is UI glue (conversation CRUD, file upload, LLM status polling) with no cross-widget invariants that would benefit from a standalone Reactive Screen Model. -->
|
||||
<!-- @REJECTED Full Reactive Screen Model rejected — the component delegates agent logic to AgentChatModel (Gradio Client). The remaining 33 functions are conversation lifecycle management (load/create/select/archive) and UI helpers. Extracting these into a separate model would create indirection without reducing cognitive load — the functions directly manipulate local $state atoms with no cross-widget shared invariants. -->
|
||||
<script lang="ts">
|
||||
/**
|
||||
* @PURPOSE: Assistant chat workspace for mixed-initiative dataset review clarification, contextual actions, and task tracking.
|
||||
* @LAYER UI
|
||||
* @RELATION BINDS_TO -> assistantChat
|
||||
* @RELATION CALLS -> AssistantApi
|
||||
* @RELATION BINDS_TO -> DatasetReviewWorkspace
|
||||
* @RELATION DISPATCHES -> [EXT:frontend:taskDrawer]
|
||||
* @SEMANTICS: assistant-chat, confirmation, long-running-task, progress-tracking
|
||||
* @PRE: Assistant chat store, API adapters, and optional dataset review session context are initialized before the panel becomes interactive.
|
||||
* @POST: User and assistant message state, conversation history, and task affordances stay synchronized with the active conversation scope.
|
||||
* @SIDE_EFFECT: Reads and mutates assistant conversation state, may navigate to review routes, opens task drawer affordances, and emits toast feedback.
|
||||
* @DATA_CONTRACT: Input[{variant,className,assistantChatStore,datasetReviewSessionId?}] -> Output[{messages,conversations,conversationId,llmReady,panelVisible}]
|
||||
* @INVARIANT: User commands and assistant responses are appended in chronological order.
|
||||
* @INVARIANT: Risky operations are executed only through explicit confirm action.
|
||||
* @UX_STATE: Closed -> Panel is hidden when variant is drawer.
|
||||
* @UX_STATE: Embedded -> Panel mounts inline as the primary workspace canvas.
|
||||
* @UX_STATE: LoadingHistory -> Existing conversation history is loading.
|
||||
* @UX_STATE: Idle -> Input is available and no request in progress.
|
||||
* @UX_STATE: Sending -> Input locked while request is pending.
|
||||
* @UX_STATE: Error -> Failed action rendered as assistant failed message.
|
||||
* @UX_FEEDBACK: Started operation surfaces task_id and quick action to open task drawer.
|
||||
* @UX_RECOVERY: User can retry command or action from input and action buttons.
|
||||
*/
|
||||
|
||||
import { onMount, onDestroy } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
<!-- @ingroup Layout -->
|
||||
<!-- @BRIEF Global task drawer for monitoring background operations via WebSocket logs, task summaries, and detail views. -->
|
||||
<!-- @LAYER UI -->
|
||||
<!-- @PRE Task drawer store and optional WebSocket task context are available before detail mode is requested. -->
|
||||
<!-- @POST Drawer stays closed, shows the recent-task list, or renders a selected task detail without losing task context. -->
|
||||
<!-- @SIDE_EFFECT Opens WebSocket streams, loads recent tasks, and mutates drawer selection state. -->
|
||||
<!-- @DATA_CONTRACT TaskDrawerState → RecentTaskList | ActiveTaskDetail -->
|
||||
<!-- @INVARIANT Drawer shows logs for active task or remains closed. -->
|
||||
<!-- @UX_REACTIVITY Uses $state for local drawer UI and $derived/store subscriptions for active task synchronization. -->
|
||||
<!-- @RELATION BINDS_TO -> [EXT:frontend:taskDrawerStore] -->
|
||||
<!-- @RELATION BINDS_TO -> [EXT:frontend:assistantChatStore] -->
|
||||
<!-- @RELATION DEPENDS_ON -> [TaskLogViewer] -->
|
||||
@@ -13,45 +19,15 @@
|
||||
<!-- @UX_FEEDBACK Close/Back buttons allow navigation. -->
|
||||
<!-- @UX_FEEDBACK WebSocket provides real-time log streaming. -->
|
||||
<!-- @UX_RECOVERY Click outside or Escape closes drawer. -->
|
||||
<!-- @TEST_DATA llm_task_success_with_fail_result -> {"activeTaskDetails":{"plugin_id":"llm_dashboard_validation","status":"SUCCESS","result":{"status":"FAIL"}}} -->
|
||||
<!-- @TEST_DATA llm_task_success_with_pass_result -> {"activeTaskDetails":{"plugin_id":"llm_dashboard_validation","status":"SUCCESS","result":{"status":"PASS"}}} -->
|
||||
<!-- @TEST_CONTRACT Component_TaskDrawer -> { required_props: {}, optional_props: {}, invariants: ["Binds successfully to taskDrawerStore", "Renders list mode when no activeTaskId is set", "Renders detail mode and websocket stream when activeTaskId is set", "Closes properly on handleClose"] } -->
|
||||
<!-- @TEST_FIXTURE init_state -> {} -->
|
||||
<!-- @TEST_EDGE empty_task_list -> displays "No recent tasks" -->
|
||||
<!-- @TEST_INVARIANT default_rendering -> verifies: [init_state] -->
|
||||
<!-- @RATIONALE JSDoc duplicates removed (INV_4). Component consolidates all task-drawer UI logic (WebSocket lifecycles, task list/detail modes, password prompts) into a single C:4 component because the task drawer is a global singleton — extracting subcomponents would scatter the WebSocket lifecycle across files, making reconnect/teardown logic fragile and invisible to the attention mechanism. -->
|
||||
<!-- @REJECTED Extracting WebSocket logic into a standalone model was rejected — the WebSocket lifecycle is tightly coupled to drawer open/close transitions and DOM cleanup. A separate model would duplicate $effect cleanup logic and create lifecycle-sync bugs (orphaned WebSocket connections when the drawer is destroyed). Inline $effect with onDestroy guards is the safe pattern for WebSocket teardown. -->
|
||||
<script lang="ts">
|
||||
/**
|
||||
* @PURPOSE: Global task drawer for monitoring background operations
|
||||
* @LAYER UI
|
||||
* @RELATION BINDS_TO -> [EXT:frontend:taskDrawer]
|
||||
* @SEMANTICS: TaskLogViewer
|
||||
* @PRE: Task drawer store and optional websocket task context are available before detail mode is requested.
|
||||
* @POST: Drawer stays closed, shows the recent-task list, or renders a selected task detail without losing task context.
|
||||
* @SIDE_EFFECT: Opens websocket streams, loads recent tasks, and mutates drawer selection state.
|
||||
* @DATA_CONTRACT: TaskDrawerState -> RecentTaskList | ActiveTaskDetail
|
||||
* @INVARIANT: Drawer shows logs for active task or remains closed
|
||||
* @UX_REACTIVITY: Uses $state for local drawer UI and $derived or store subscriptions for active task synchronization.
|
||||
*
|
||||
* @UX_STATE: Closed -> Drawer hidden, no active task
|
||||
* @UX_STATE: Open/ListMode -> Drawer visible, showing recent tasks list
|
||||
* @UX_STATE: Open/TaskDetail -> Drawer visible, showing logs for selected task
|
||||
* @UX_STATE: InputRequired -> Interactive form rendered in drawer
|
||||
* @UX_FEEDBACK: Close button allows task to continue running
|
||||
* @UX_FEEDBACK: Back button returns to task list
|
||||
* @UX_RECOVERY: Click outside or X button closes drawer
|
||||
* @UX_RECOVERY: Back button shows task list when viewing task details
|
||||
* @TEST_DATA: llm_task_success_with_fail_result -> {"activeTaskDetails":{"plugin_id":"llm_dashboard_validation","status":"SUCCESS","result":{"status":"FAIL"}}}
|
||||
* @TEST_DATA: llm_task_success_with_pass_result -> {"activeTaskDetails":{"plugin_id":"llm_dashboard_validation","status":"SUCCESS","result":{"status":"PASS"}}}
|
||||
*
|
||||
* @TEST_CONTRACT Component_TaskDrawer ->
|
||||
* {
|
||||
* required_props: {},
|
||||
* optional_props: {},
|
||||
* invariants: [
|
||||
* "Binds successfully to taskDrawerStore",
|
||||
* "Renders list mode when no activeTaskId is set",
|
||||
* "Renders detail mode and websocket stream when activeTaskId is set",
|
||||
* "Closes properly on handleClose"
|
||||
* ]
|
||||
* }
|
||||
* @TEST_FIXTURE init_state -> {}
|
||||
* @TEST_EDGE empty_task_list -> displays \"No recent tasks\"
|
||||
* @TEST_INVARIANT default_rendering -> verifies: [init_state]
|
||||
*/
|
||||
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
import { log } from "$lib/cot-logger";
|
||||
@@ -576,13 +552,9 @@
|
||||
|
||||
// #region disconnectWebSocket:Function [TYPE Function]
|
||||
// @ingroup Layout
|
||||
// @UX_STATE: Loading -> Default
|
||||
// @RELATION USES -> [EXT:frontend:App]
|
||||
/**
|
||||
* @PURPOSE: Disconnects the active WebSocket connection
|
||||
* @PRE: ws may or may not be initialized
|
||||
* @POST: ws is closed and set to null
|
||||
*/
|
||||
// @BRIEF Disconnects the active WebSocket connection.
|
||||
// @PRE ws may or may not be initialized.
|
||||
// @POST ws is closed and set to null.
|
||||
function disconnectWebSocket() {
|
||||
log("TaskDrawer", "REASON", "Disconnecting WebSocket");
|
||||
if (wsReconnectTimer) {
|
||||
@@ -600,11 +572,9 @@
|
||||
|
||||
// #region loadRecentTasks:Function [TYPE Function]
|
||||
// @ingroup Layout
|
||||
/**
|
||||
* @PURPOSE: Load recent tasks for list mode display
|
||||
* @PRE: User is on task drawer or api is ready.
|
||||
* @POST: recentTasks array populated with task list
|
||||
*/
|
||||
// @BRIEF Load recent tasks for list mode display.
|
||||
// @PRE User is on task drawer or API is ready.
|
||||
// @POST recentTasks array populated with task list.
|
||||
async function loadRecentTasks() {
|
||||
loadingTasks = true;
|
||||
try {
|
||||
@@ -624,11 +594,9 @@
|
||||
|
||||
// #region selectTask:Function [TYPE Function]
|
||||
// @ingroup Layout
|
||||
/**
|
||||
* @PURPOSE: Select a task from list to view details
|
||||
* @PRE: task is a valid task object
|
||||
* @POST: drawer state updated to show task details
|
||||
*/
|
||||
// @BRIEF Select a task from list to view details.
|
||||
// @PRE task is a valid task object.
|
||||
// @POST drawer state updated to show task details.
|
||||
function selectTask(task) {
|
||||
log("TaskDrawer", "REASON", "Select task");
|
||||
taskDrawerStore.update((state) => ({
|
||||
@@ -640,13 +608,9 @@
|
||||
|
||||
// #region goBackToList:Function [TYPE Function]
|
||||
// @ingroup Layout
|
||||
// @UX_STATE: Loading -> Default
|
||||
// @RELATION USES -> [EXT:frontend:App]
|
||||
/**
|
||||
* @PURPOSE: Return to task list view from task details
|
||||
* @PRE: Drawer is open and activeTaskId is set
|
||||
* @POST: Drawer switches to list view and reloads tasks
|
||||
*/
|
||||
// @BRIEF Return to task list view from task details.
|
||||
// @PRE Drawer is open and activeTaskId is set.
|
||||
// @POST Drawer switches to list view and reloads tasks.
|
||||
function goBackToList() {
|
||||
log("TaskDrawer", "REASON", "Go back to task list");
|
||||
taskDrawerStore.update((state) => ({
|
||||
|
||||
Reference in New Issue
Block a user