From bba415f91b28702fc213d72471e1238b33ba9d30 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Tue, 30 Jun 2026 15:58:30 -0700 Subject: [PATCH] FN-7308: preserve legacy Activity log access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preserve the legacy task log affordances inside the Activity tab. - Route legacy Logs entrypoints to Activity → Feed while keeping Raw Logs as the raw agent-output segment. - Document the Activity Current, Feed, and Raw Logs behavior across operator docs. - Add regression coverage for Feed legacy entries, duplicate feed rows, and Raw Logs pagination. - Add a patch changeset for the published CLI package. Files changed: .changeset/fn-7308-preserve-activity-logs.md | 7 ++++ docs/agents.md | 4 +- docs/dashboard-guide.md | 8 ++-- packages/dashboard/README.md | 2 +- .../dashboard/app/components/TaskDetailModal.tsx | 8 ++-- .../TaskDetailModal.attachments-and-tabs.test.tsx | 29 ++++++++++++++ .../components/__tests__/TaskDetailModal.test.tsx | 45 ++++++++++++++++++++++ 7 files changed, 92 insertions(+), 11 deletions(-) Fusion-Task-Id: FN-7308 Fusion-Task-Lineage: 45483e4e-4de8-4b5b-96ae-fca6914545d4 Co-authored-by: Fusion (runfusion.ai) --- .changeset/fn-7308-preserve-activity-logs.md | 7 +++ docs/agents.md | 4 +- docs/dashboard-guide.md | 8 ++-- packages/dashboard/README.md | 2 +- .../app/components/TaskDetailModal.tsx | 8 ++-- ...kDetailModal.attachments-and-tabs.test.tsx | 29 ++++++++++++ .../__tests__/TaskDetailModal.test.tsx | 45 +++++++++++++++++++ 7 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 .changeset/fn-7308-preserve-activity-logs.md diff --git a/.changeset/fn-7308-preserve-activity-logs.md b/.changeset/fn-7308-preserve-activity-logs.md new file mode 100644 index 0000000000..32745f6d49 --- /dev/null +++ b/.changeset/fn-7308-preserve-activity-logs.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Preserve legacy task feed and raw log access under Activity. +category: fix +dev: Keeps legacy task-detail logs callers routed to Activity → Feed while Raw Logs remains the only raw-log-fetching segment. diff --git a/docs/agents.md b/docs/agents.md index ab70b2791f..ad9acff543 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -366,9 +366,9 @@ Triage inheritance behavior: As with execution, incomplete assigned-agent model configuration falls through cleanly to the existing planning hierarchy. -### Task Detail Agent Log model provenance +### Task Detail Raw Logs model provenance -The Task Detail → Agent Log model header prefers runtime provenance markers written during execution/review: +The Task Detail Activity → Raw Logs model header prefers runtime provenance markers written during execution/review: - `Executor using model: /` - `Reviewer using model: /` diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index a73386a6e0..03e19832a7 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -1115,15 +1115,15 @@ Use blocker fan-out signals on task cards and in the footer status bar to spot b Recommended workflow: ordinary chains stay as `Blocks N` so noise stays low, high-fan-out blockers stand out immediately, and only long-lived high-impact blockers trigger explicit escalation. -### Logs → Agent Log view +### Activity → Raw Logs view -The **Chat** tab sits between Definition and Logs and presents a live, chat-styled transcript of task agent output. Consecutive entries are grouped by role and labeled as Planner, Executor, Reviewer, or Merger; legacy log rows without an agent role use the neutral Agent fallback. Agent group headers and user message headers show a small muted relative timestamp (for example, “just now”, “1m ago”, or “2h ago”) based on the transcript timestamp, while agent group metadata still includes the entry count. Consecutive text/message chunks inside a role group render as one continuous markdown bubble, while consecutive tool/tool-result/tool-error rows collapse into one expandable, compact tool-call summary that stays collapsed by default and mirrors regular Chat's dense treatment; the summary stays single-line/ellipsis-friendly on desktop and mobile, counts tool invocations, lists deduped tool names with overflow, and shows an error count when failures are present, while the expanded body pairs each call with its result or error in dense entry cards. Thinking entries render in a collapsible block that starts expanded. The transcript opens at the latest output whenever the tab loads or becomes active, then follows new live output when you are already near the bottom while preserving your scroll position when you review older messages. When older task-agent history exists, scrolling to the top or selecting **Load previous messages** prepends earlier transcript entries without moving the message you were reading. When you scroll away from the bottom of a populated transcript, a sticky **Latest** button appears inside the transcript so you can jump back to the newest message and resume live follow. For non-`done` tasks, the composer sends guidance through the same steering path used by comments, including active planning/triage, `in-progress`, and `in-review` sessions, plus live CLI-agent sessions reported by the session bridge; an `in-review` Chat message or Comments-tab task comment re-engages an executor unless an open PR blocks moving the task back, and other messages are still saved as queued guidance when no session is currently live. The composer no longer renders guidance text above the entry box; active, idle, and completed task actions are communicated through the textarea placeholder while the input and Send button remain usable. On a `done` task, sending a Chat message starts a refinement task using the typed text as feedback and shows a success toast with the new task ID; the current task detail modal remains on the completed task. The task-detail Chat tab keeps the composer pinned and visible on mobile and desktop while the transcript scrolls internally; its textarea placeholder reads “Steer the currently executing agent” for steering mode and switches to refinement copy for completed tasks, with the same inline, icon-only send affordance to the right of the input at every breakpoint. In the composer, plain **Enter** sends, **Shift+Enter** inserts a newline, and **Cmd/Ctrl+Enter** remains a supported send shortcut. +The **Activity** tab is the first task-detail tab and presents a segmented control for **Current**, **Feed**, and **Raw Logs**. Current contains the live, chat-styled transcript of task agent output. Consecutive entries are grouped by role and labeled as Planner, Executor, Reviewer, or Merger; legacy log rows without an agent role use the neutral Agent fallback. Agent group headers and user message headers show a small muted relative timestamp (for example, “just now”, “1m ago”, or “2h ago”) based on the transcript timestamp, while agent group metadata still includes the entry count. Consecutive text/message chunks inside a role group render as one continuous markdown bubble, while consecutive tool/tool-result/tool-error rows collapse into one expandable, compact tool-call summary that stays collapsed by default and mirrors regular Chat's dense treatment; the summary stays single-line/ellipsis-friendly on desktop and mobile, counts tool invocations, lists deduped tool names with overflow, and shows an error count when failures are present, while the expanded body pairs each call with its result or error in dense entry cards. Thinking entries render in a collapsible block that starts expanded. The transcript opens at the latest output whenever the tab loads or becomes active, then follows new live output when you are already near the bottom while preserving your scroll position when you review older messages. When older task-agent history exists, scrolling to the top or selecting **Load previous messages** prepends earlier transcript entries without moving the message you were reading. When you scroll away from the bottom of a populated transcript, a sticky **Latest** button appears inside the transcript so you can jump back to the newest message and resume live follow. For non-`done` tasks, the composer sends guidance through the same steering path used by comments, including active planning/triage, `in-progress`, and `in-review` sessions, plus live CLI-agent sessions reported by the session bridge; an `in-review` Activity Current message or Comments-tab task comment re-engages an executor unless an open PR blocks moving the task back, and other messages are still saved as queued guidance when no session is currently live. The composer no longer renders guidance text above the entry box; active, idle, and completed task actions are communicated through the textarea placeholder while the input and Send button remain usable. On a `done` task, sending an Activity Current message starts a refinement task using the typed text as feedback and shows a success toast with the new task ID; the current task detail modal remains on the completed task. The task-detail Activity Current segment keeps the composer pinned and visible on mobile and desktop while the transcript scrolls internally; its textarea placeholder reads “Steer the currently executing agent” for steering mode and switches to refinement copy for completed tasks, with the same inline, icon-only send affordance to the right of the input at every breakpoint. In the composer, plain **Enter** sends, **Shift+Enter** inserts a newline, and **Cmd/Ctrl+Enter** remains a supported send shortcut. -The **Logs** tab includes an **Agent Log** subview designed for debugging long-running and tool-heavy sessions: +The **Raw Logs** segment is designed for debugging long-running and tool-heavy sessions, while legacy links that requested the former top-level Logs tab land on Activity → Feed: - Full `thinking`, `tool_result`, and `tool_error` payloads are shown without entry-content truncation. - Raw tool output is rendered as multiline blocks, preserving line breaks and indentation. -- The Activity and Agent Log subviews show loading indicators while their first async history/detail request is pending, so empty states only appear after the relevant fetch completes. +- The Feed and Raw Logs segments show loading indicators while their first async history/detail request is pending, so empty states only appear after the relevant fetch completes. - The initial load fetches a recent page, then **Load More** progressively prepends older history. - Live streaming appends new entries in chronological order while preserving your scroll position when loading older pages. - The **Markdown / Plain** toggle lets you switch between formatted markdown and literal/raw text rendering. diff --git a/packages/dashboard/README.md b/packages/dashboard/README.md index 76497e3ca0..63abf8e444 100644 --- a/packages/dashboard/README.md +++ b/packages/dashboard/README.md @@ -102,7 +102,7 @@ AI-guided interactive planning for creating well-specified tasks from high-level - **Layered Model Dropdowns**: Shared model combobox menus render in a top-level portal attached to `document.body`, so they stay above board columns and scrollable modal content instead of being clipped behind surrounding dashboard surfaces. The dropdown constrains horizontal overflow — long model IDs and provider labels truncate with ellipsis rather than creating sideways scrolling, keeping the menu usable on smaller viewports. On mobile viewports (≤640px), the quick-entry Models menu widens to fill the viewport (minus side padding) and remains viewport-clamped for comfortable model selection without horizontal crowding. - **Fuzzy Model Search**: Model dropdown search (`filterModels`) supports fuzzy matching so users can find models despite minor typing imperfections. Three matching strategies are applied in order (first match wins): (1) **separator-insensitive substring** — hyphens, underscores, dots, and slashes are stripped before comparison, so `gpt4o` finds `gpt-4o`; (2) **subsequence matching** (≥ 3 chars) — characters must appear in order within a single token but need not be contiguous, so `cld` finds `claude`; (3) **typo tolerance** (≥ 4 chars) — Damerau-Levenshtein edit distance ≤ 1 supports single-character insertion, deletion, substitution, and adjacent transposition, so `sonet` finds `sonnet`. Multi-term space-separated queries use AND logic. Result ordering is stable (input-array order, no score re-sorting). Exact and substring matches from the original implementation continue to work unchanged. - **Bulk Model Editing**: Update AI model configuration for multiple tasks at once in the list view. Select tasks via checkboxes (archived tasks excluded), then use the "Bulk Edit Models" toolbar with three explicit states per lane: **No change** (leave that lane untouched in the batch payload), a concrete model selection (apply that provider/model pair to all selected tasks), or **Use default** (send `null` provider/model to clear task-level overrides and fall back to project/global defaults). Apply stays disabled until at least one lane is set to a concrete model or **Use default**. Selection persists in localStorage across page reloads. -- **Task Details**: View full task specifications, agent logs, and attachments. The task detail modal uses a top-level tab bar with the following tabs: **Definition**, **Logs**, **Changes** (for in-progress/in-review/done tasks), **Comments**, **Model**, and **Workflow** (when workflow steps are configured or the task has previous workflow results). **Activity** and **Agent Log** are subviews within the unified **Logs** tab — click Logs, then toggle between Activity (task lifecycle events, default) and Agent Log (live agent output). In the Activity timeline, action and outcome text use high-contrast, theme-aware tokens for easier scanning, while timestamps remain intentionally secondary so chronology stays visible without competing with event content. The Agent Log subview expands to fill the full modal body height above the action bar, providing maximum vertical space for watching live agent output. The Agent Log header shows the effective executor, validator, and planning/triage model names resolved from task-level overrides or project/global settings fallbacks, matching the same resolution order the engine uses at runtime. A **Markdown/Plain toggle** in the Agent Log header switches between formatted markdown rendering (default) and literal plain-text display — useful for debugging raw agent output, checking escaped markdown syntax, or inspecting exactly what the agent emitted without formatting. The toggle applies to `text` and `thinking` entries only; tool entries always render as plain text. React-markdown handles sanitization in markdown mode (no raw HTML is executed); plain-text mode uses React's built-in text escaping for safe literal output. The refinement modal positions the "Create Refinement Task" button adjacent to the feedback textarea alongside the character count, creating a tight input group that connects the submit action directly to the text being edited. The **Changes** tab for done tasks loads the diff from the recorded merge commit (`mergeDetails.commitSha`) via the `/api/tasks/:id/diff` endpoint rather than requiring a live worktree — changes remain visible even after the worktree is cleaned up. Done tasks **without** a recorded `commitSha` do not attempt to fetch a detailed file diff; instead, the tab shows a safe summary fallback displaying the merge summary numbers (`filesChanged`, `insertions`, `deletions`) from `mergeDetails`. This prevents inflated file lists that would result from a repository-wide fallback diff scan. The tab shows commit metadata (short SHA, merge commit message, merged timestamp) alongside the file-level diff when a commit SHA is available. The header displays "Files Changed (N)" as the primary title with additions/deletions totals on a second line below, freeing horizontal space for navigation and action controls. In-progress and in-review tasks continue to use the worktree-based diff path. Changed-file status indicators (added, modified, deleted, unknown) use semantic CSS classes and theme-aware color variables, ensuring readable contrast across all dashboard themes and light/dark modes. +- **Task Details**: View full task specifications, agent logs, and attachments. The task detail modal uses a top-level tab bar with **Activity**, **Definition**, **Changes** (for in-progress/in-review/done tasks), **Comments**, **Artifacts**, **Model**, **Workflow**, **Stats**, and **Routing** tabs. The **Activity** tab contains a segmented control for **Current** (the live task activity/steering surface), **Feed** (task lifecycle events), and **Raw Logs** (live agent output). Legacy callers that request the old Logs tab open Activity → Feed instead of restoring a top-level Logs tab. In the Feed timeline, action and outcome text use high-contrast, theme-aware tokens for easier scanning, while timestamps remain intentionally secondary so chronology stays visible without competing with event content. The Raw Logs segment expands to fill the full modal body height above the action bar, providing maximum vertical space for watching live agent output. The Raw Logs header shows the effective executor, validator, and planning/triage model names resolved from task-level overrides or project/global settings fallbacks, matching the same resolution order the engine uses at runtime. A **Markdown/Plain toggle** in the Raw Logs header switches between formatted markdown rendering (default) and literal plain-text display — useful for debugging raw agent output, checking escaped markdown syntax, or inspecting exactly what the agent emitted without formatting. The toggle applies to `text` and `thinking` entries only; tool entries always render as plain text. React-markdown handles sanitization in markdown mode (no raw HTML is executed); plain-text mode uses React's built-in text escaping for safe literal output. The refinement modal positions the "Create Refinement Task" button adjacent to the feedback textarea alongside the character count, creating a tight input group that connects the submit action directly to the text being edited. The **Changes** tab for done tasks loads the diff from the recorded merge commit (`mergeDetails.commitSha`) via the `/api/tasks/:id/diff` endpoint rather than requiring a live worktree — changes remain visible even after the worktree is cleaned up. Done tasks **without** a recorded `commitSha` do not attempt to fetch a detailed file diff; instead, the tab shows a safe summary fallback displaying the merge summary numbers (`filesChanged`, `insertions`, `deletions`) from `mergeDetails`. This prevents inflated file lists that would result from a repository-wide fallback diff scan. The tab shows commit metadata (short SHA, merge commit message, merged timestamp) alongside the file-level diff when a commit SHA is available. The header displays "Files Changed (N)" as the primary title with additions/deletions totals on a second line below, freeing horizontal space for navigation and action controls. In-progress and in-review tasks continue to use the worktree-based diff path. Changed-file status indicators (added, modified, deleted, unknown) use semantic CSS classes and theme-aware color variables, ensuring readable contrast across all dashboard themes and light/dark modes. - **Documents view hidden-file toggle**: The Documents panel’s **Project Files** tab now hides dotfiles and markdown files inside hidden directories by default, keeping the list focused on user-facing docs. A `Show Hidden` / `Hide Hidden` toggle reveals those hidden markdown entries on demand. Hard-excluded system/build directories (for example `.git`, `.fusion`, and `node_modules`) remain excluded in both modes. - **Changed Files Viewer**: Click a task card's "files changed" button to open a dedicated diff viewer showing only files changed in that task worktree, with per-file statuses and sidebar navigation. The sidebar file list uses dedicated `changed-files-entry` styling with explicit button resets (no browser-default background/border/font inheritance) and theme-variable-driven colors for text, icons, hover, active, and focus states — ensuring correct rendering across both dark and light modes and all color themes. On mobile (≤768px), the viewer switches to a single-pane flow: the file list and diff are shown one at a time with a back button for navigation between them. The viewer always opens to the file list on mobile, and only switches to the diff view when the user taps a specific file. Pressing Escape on the diff view returns to the file list first; pressing Escape again closes the modal. Loading, error, and empty states use theme-aware styling (including light mode). Diff syntax highlighting (additions, deletions, hunks) adapts to the active theme for correct contrast. Status badges in the sidebar and diff toolbar use semantic CSS classes (e.g., `changed-files-badge--added`) with theme-aware colors for consistent readability across all themes. The board card file count and the changed-files viewer agree when live diff data is available — both use a shared diff-base resolution strategy. For in-review cards where live worktree diff stats are unavailable, the card falls back to executor-captured `modifiedFiles` metadata so users still see a quick "N files changed" summary. When the task has a `baseCommitSha` (captured at worktree creation time) that is still a valid ancestor of the current HEAD, the diff is scoped to only files introduced by that specific task. If `baseCommitSha` is stale or unavailable, the system falls back to a branch merge-base, then to `HEAD~1`. This ensures accurate file counts in shared or recycled worktree scenarios where a broader merge-base would include files from previous tasks. For in-progress tasks, the changed-files reporting includes all git-change types: committed changes (from `baseRef..HEAD`), staged changes (from `git diff --cached`), unstaged working-tree changes (from `git diff`), and untracked files (from `git ls-files --others --exclude-standard`). Files are deduplicated across all sources, so a file that appears in multiple states (e.g., modified and staged) appears only once. This gives operators a complete picture of work-in-progress, including new files not yet staged for commit. - **Task Detail Changes Tab**: The task detail modal's "Changes" tab (TaskChangesTab) uses a compact spacing treatment for file detail rows. The file list container has a `task-changes-file-list--compact` modifier class that tightens padding and gaps on file headers, stat badges, and list item spacing compared to the shared base `.changes-file-*` styles. This compact treatment is scoped to TaskChangesTab only and does not affect other diff surfaces. diff --git a/packages/dashboard/app/components/TaskDetailModal.tsx b/packages/dashboard/app/components/TaskDetailModal.tsx index 05f638d96f..9d568c692d 100644 --- a/packages/dashboard/app/components/TaskDetailModal.tsx +++ b/packages/dashboard/app/components/TaskDetailModal.tsx @@ -198,8 +198,8 @@ type ActivitySegment = "current" | "feed" | "raw-logs"; FNXC:TaskDetailActivityTab 2026-06-30-00:00: The existing task activity/steering surface keeps the stable internal `chat` tab id for deep-link/plugin compatibility, but its top-level user-facing label is Activity. Activity is the implicit default for every task column, including done tasks; Summary remains explicitly available for completed work until a later subtask adds the separate planner-model Chat surface. -FNXC:TaskDetailActivity 2026-06-30-22:15: -Only an omitted initial tab is the implicit default. Preserve explicit `initialTab="chat"` requests from plugins and task-detail entrypoints so existing links continue to open Activity → Current. Legacy `initialTab="logs"` now routes to Activity → Feed because Logs no longer renders as a top-level task-detail tab. +FNXC:TaskDetailActivity 2026-06-30-15:50: +Only an omitted initial tab is the implicit default. Preserve explicit `initialTab="chat"` requests from plugins and task-detail entrypoints so existing links continue to open Activity → Current. Legacy `initialTab="logs"` now routes to Activity → Feed, and Raw Logs remains an Activity segment, because the legacy top-level Logs tab must not return while the later planner-model Chat tab remains out of scope. */ function resolveDefaultTab(initialTab: TabId | undefined, _column: ColumnId): TabId { if (initialTab === "retries") { @@ -3287,8 +3287,8 @@ export function TaskDetailContent({ ) : activeTab === "chat" ? (
{/* - FNXC:TaskDetailActivity 2026-06-30-22:15: - Activity owns the existing steering/current view, Feed, and Raw Logs inside one segmented control. The later planner-model Chat tab is intentionally out of scope, so the stable top-level tab id remains `chat` while the legacy `logs` id lands on the Feed segment. + FNXC:TaskDetailActivity 2026-06-30-15:50: + Activity owns the existing steering/current view, Feed, and Raw Logs inside one segmented control. The later planner-model Chat tab is intentionally out of scope, so the stable top-level tab id remains `chat`, legacy `logs` callers land on Feed, and Raw Logs is the only segment that enables raw agent-log fetching. */}