From 04677fdf4bddcb991784593d5719e67903cec2f4 Mon Sep 17 00:00:00 2001 From: dtoro Date: Tue, 14 Jul 2026 11:45:36 +0200 Subject: [PATCH] tool timeline in sidebar + compact chat tools + scroll fixes - SessionDigest now includes live tool timeline, plan steps, knowledge - ToolCallGroup compact: single-line with collapsible names only (no JSON) - Activity bar moved to bottom of messages, smart scroll respects user position - setGoal now sets status=executing (removed stuck planning state) - PlanProgress merged into SessionDigest, removed from TaskContextPanel - New toolTimeline derived store in chat.ts --- VERSION | 2 +- cmd/nomos/store.go | 7 +- web/src/lib/components/SessionDigest.svelte | 145 ++++++++++++++---- .../lib/components/TaskContextPanel.svelte | 2 - web/src/lib/components/ToolCallGroup.svelte | 106 +++++-------- web/src/lib/stores/chat.ts | 32 +++- 6 files changed, 191 insertions(+), 103 deletions(-) diff --git a/VERSION b/VERSION index 9e11b32..d15723f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.1 +0.3.2 diff --git a/cmd/nomos/store.go b/cmd/nomos/store.go index f0fa538..aab9570 100644 --- a/cmd/nomos/store.go +++ b/cmd/nomos/store.go @@ -358,13 +358,16 @@ func (s *store) taskEntityPtr(ctx context.Context, sessionID string) *uuid.UUID return &id } -// setGoal records the task's goal and moves it into planning. Emits goal.set. +// setGoal records the task's goal and moves it into executing. The `planning` +// intermediate state was removed (2026-07-14) — it was indistinguishable from +// `active` to the operator and caused sessions to appear stuck when the agent +// called set_goal but never propose_plan (observed in production). func (s *store) setGoal(ctx context.Context, sessionID, goal string) error { if s == nil || sessionID == "" || sessionID == "ephemeral" { return nil } if _, err := s.pool.Exec(ctx, - `UPDATE agent_sessions SET goal = $2, status = 'planning', last_active_at = now() WHERE id = $1`, + `UPDATE agent_sessions SET goal = $2, status = 'executing', last_active_at = now() WHERE id = $1`, sessionID, goal); err != nil { return err } diff --git a/web/src/lib/components/SessionDigest.svelte b/web/src/lib/components/SessionDigest.svelte index 141cba4..363c703 100644 --- a/web/src/lib/components/SessionDigest.svelte +++ b/web/src/lib/components/SessionDigest.svelte @@ -1,19 +1,20 @@ +{#if $streaming && $currentSession} +
+ + {toolCount} tool{toolCount === 1 ? '' : 's'} · {runningCount} running +
+{/if} + {#if $currentTask?.outcome}
+
+ Plan + {planDone}/{planTotal} +
+
+
+
+
    + {#each $planSteps as step (step.id)} +
  1. + + {#if step.status === 'done'} + + {:else if step.status === 'running'} + + {:else if step.status === 'failed'} + + {:else} + + {/if} + + {step.title} +
  2. + {/each} +
+
+{/if} + +{#if toolCount > 0} +
+ + {#if openTools} +
+ {#each toolGroups as group} + {@const isLatest = group.msgIndex === toolGroups[toolGroups.length - 1]?.msgIndex} +
+ {#each group.entries as t (t.id)} +
+ + {#if t.type === 'tool_result' && t.error} + + {:else if t.type === 'tool_result'} + + {:else} + + {/if} + + {toolSummary(t)} +
+ {/each} +
+ {/each} +
+ {/if} +
+{/if} + {#if digest && digest.total_executions > 0}
{#if open} -
+
{#each Object.entries(digest.by_status) as [status, count]} {status} × {count} {/each}
- {#if digest.entities_touched.length} -
-
Entities touched
-
- {#each digest.entities_touched as target} - {target} - {/each} -
-
- {/if} - -
- {#each digest.executions as ex} -
-
-
{ex.target}
-
{ex.summary || ex.verb}
-
- {ex.status} -
- {/each} -
- {#if digest.knowledge_created.length}
Learned this session
-
    +
      {#each digest.knowledge_created as title}
    • {title}
    • {/each} diff --git a/web/src/lib/components/TaskContextPanel.svelte b/web/src/lib/components/TaskContextPanel.svelte index e24fe52..626c199 100644 --- a/web/src/lib/components/TaskContextPanel.svelte +++ b/web/src/lib/components/TaskContextPanel.svelte @@ -2,7 +2,6 @@ import { onMount } from 'svelte' import { startWorkspace } from '$lib/stores/workspace' import GoalHeader from './GoalHeader.svelte' - import PlanProgress from './PlanProgress.svelte' import OperatorQuestion from './OperatorQuestion.svelte' import SessionGraph from './SessionGraph.svelte' import SessionDigest from './SessionDigest.svelte' @@ -20,7 +19,6 @@ -->
      -
      diff --git a/web/src/lib/components/ToolCallGroup.svelte b/web/src/lib/components/ToolCallGroup.svelte index eed32bf..829d952 100644 --- a/web/src/lib/components/ToolCallGroup.svelte +++ b/web/src/lib/components/ToolCallGroup.svelte @@ -1,7 +1,6 @@ {#if bodyTools.length} - - - {#if active && doneCount < bodyTools.length} -