You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Tool expanders in agent chat view have no effect and don't collapse tool lists #25
The tool expanders in the agent chat view do not function. Clicking them has no effect and does not collapse the tool list (e.g. the MCP server's tools remain visible and cannot be collapsed).
Steps to reproduce
Open an agent chat view that shows tools (e.g. from an MCP server)
Click a tool expander
Expected behavior
The expander collapses/expands the tool list as expected.
Actual behavior
The expander has no effect; the tool list remains expanded and cannot be collapsed.
In Avalonia 12, bindings inside Style Setter elements only work OneWay (Source → Target). Mode=TwoWay is silently ignored. When the user clicks an expander, TreeViewItem updates its own IsExpanded locally but the ViewModel's IsExpanded is never written back. The ViewModel retains its original value.
TreeViewItem exposes dedicated ExpandedEvent/CollapsedEvent routed events for exactly this purpose — they are the correct mechanism and are not used.
Note: AgentEditorNavigationItemViewModel.ToggleExpandCommand (line 28) would also work but is never bound in any XAML.
Compounding — BuildEditorTree discards all expansion state on every tool change
ToolsChanged fires on every MCP server init and every SetToolEnabledAsync call (user checks/unchecks a tool). It calls BuildEditorTree, which calls EditorItems.Clear() and creates brand-new AgentEditorNavigationItemViewModel instances with isExpanded = false for all nodes. Any expansion state set by the user is destroyed.
Combined effect: clicking an expander does nothing that survives the next tool change (or the initial MCP server discovery).
Missing Tests
IsExpanded_RaisesPropertyChanged_WhenSet — setting IsExpanded = true on AgentEditorNavigationItemViewModel fires PropertyChanged
ToggleExpandCommand_TogglesIsExpanded_FalseToTrue and _TrueToFalse
BuildEditorTree_PreservesToolNodeExpansionState_AfterToolsChanged⚠️key test — set IsExpanded = true on an MCP server nav item, raise ToolsChanged, assert the node is still expanded
BuildEditorTree_PreservesChatToolsCollapsedState_AfterToolsChanged — collapse "chat-tools", raise ToolsChanged, assert it stays collapsed
TreeViewItemExpanded_UpdatesViewModelIsExpanded (Avalonia UI test) — fire TreeViewItem.ExpandedEvent on a NavigationTree container, assert the DataContext ViewModel's IsExpanded becomes true
TreeViewItemCollapsed_UpdatesViewModelIsExpanded — same for collapsed
Apply the same pattern to AgentChatToolsDetailControl.axaml (drop Mode=TwoWay) and AgentChatToolsDetailControl.axaml.cs (add ToolsTree.AddHandler(...) in constructor).
Fix 2 — Preserve expansion state across BuildEditorTree rebuilds
AgentViewModel.cs — capture expansion state before clearing, restore it when recreating nodes:
privatevoidBuildEditorTree(){varselectedId=this.SelectedEditorItem?.Id;// Capture expansion state before destroying old treevarexpandedIds=newHashSet<string>(StringComparer.OrdinalIgnoreCase);CollectExpandedIds(this.EditorItems,expandedIds);boolisFirstBuild=expandedIds.Count==0;this.EditorItems.Clear();vartoolNavigationItems=this.BuildToolNavigationItems(this.Tools,expandedIds);// ... rebuild root with isExpanded: expandedIds.Contains(id) for each node ...// "chat-tools" default: isFirstBuild || expandedIds.Contains("chat-tools")}privateAgentEditorNavigationItemViewModelBuildToolNavigationItem(AgentChatToolViewModeltool,HashSet<string>expandedIds)=>new(...,isExpanded:expandedIds.Contains(tool.Id));// was always falseprivatestaticvoidCollectExpandedIds(IEnumerable<AgentEditorNavigationItemViewModel>items,HashSet<string>expandedIds){foreach(variteminitems){if(item.IsExpanded)expandedIds.Add(item.Id);CollectExpandedIds(item.Children,expandedIds);}}
Side Effects
No memory leak — AddHandler on the TreeView uses event bubbling; no per-container subscriptions needed.
No infinite loop — when the handler sets vm.IsExpanded = true, the OneWay setter re-asserts true on the already-trueTreeViewItem; Avalonia detects no change and does not re-fire ExpandedEvent.
First-build defaults preserved — the isFirstBuild guard keeps "chat-tools" starting expanded on first build.
Tool ID stability required — expansion state preservation relies on tool IDs being stable across rebuilds (acceptable).
Root cause addressed: The �ntity-card-tree TreeViewItem template rendered its child ItemsPresenter unconditionally. Toggling an expander changed the glyph but never hid the children. Fixed by binding ItemsPresenter.IsVisible to IsExpanded.
Result: Implementation found, all verification criteria satisfied, tests present and green.
SharedStyles.axaml now contains inside the �ntity-card-tree TreeViewItem template.
Activity
JoshuaRowePhantom commentedon Jun 24, 2026
Investigation Findings
Root Cause
Two compounding causes:
Primary —
Mode=TwoWayin Style Setter is silently OneWay in Avalonia 12Files:
Phantom.Workspaces.Agent.Gui/Controls/AgentChatEditorControl.axaml, line 159Phantom.Workspaces.Agent.Gui/Controls/AgentChatToolsDetailControl.axaml, line 24In Avalonia 12, bindings inside
Style Setterelements only work OneWay (Source → Target).Mode=TwoWayis silently ignored. When the user clicks an expander,TreeViewItemupdates its ownIsExpandedlocally but the ViewModel'sIsExpandedis never written back. The ViewModel retains its original value.TreeViewItemexposes dedicatedExpandedEvent/CollapsedEventrouted events for exactly this purpose — they are the correct mechanism and are not used.Note:
AgentEditorNavigationItemViewModel.ToggleExpandCommand(line 28) would also work but is never bound in any XAML.Compounding —
BuildEditorTreediscards all expansion state on every tool changeFile:
Phantom.Workspaces.Agent.Gui/ViewModels/AgentViewModel.csToolsChangedfires on every MCP server init and everySetToolEnabledAsynccall (user checks/unchecks a tool). It callsBuildEditorTree, which callsEditorItems.Clear()and creates brand-newAgentEditorNavigationItemViewModelinstances withisExpanded = falsefor all nodes. Any expansion state set by the user is destroyed.Combined effect: clicking an expander does nothing that survives the next tool change (or the initial MCP server discovery).
Missing Tests
IsExpanded_RaisesPropertyChanged_WhenSet— settingIsExpanded = trueonAgentEditorNavigationItemViewModelfiresPropertyChangedToggleExpandCommand_TogglesIsExpanded_FalseToTrueand_TrueToFalseToggleExpandCommand_CanExecute_OnlyWhenHasChildrenBuildEditorTree_PreservesToolNodeExpansionState_AfterToolsChangedIsExpanded = trueon an MCP server nav item, raiseToolsChanged, assert the node is still expandedBuildEditorTree_PreservesChatToolsCollapsedState_AfterToolsChanged— collapse "chat-tools", raiseToolsChanged, assert it stays collapsedTreeViewItemExpanded_UpdatesViewModelIsExpanded(Avalonia UI test) — fireTreeViewItem.ExpandedEventon aNavigationTreecontainer, assert the DataContext ViewModel'sIsExpandedbecomestrueTreeViewItemCollapsed_UpdatesViewModelIsExpanded— same for collapsedRecommended Fix
Fix 1 — Replace broken TwoWay Style Setter with
ExpandedEvent/CollapsedEventhandlersAgentChatEditorControl.axaml— dropMode=TwoWay(it was a no-op):AgentChatEditorControl.axaml.cs— add routed event handlers in constructor:Apply the same pattern to
AgentChatToolsDetailControl.axaml(dropMode=TwoWay) andAgentChatToolsDetailControl.axaml.cs(addToolsTree.AddHandler(...)in constructor).Fix 2 — Preserve expansion state across
BuildEditorTreerebuildsAgentViewModel.cs— capture expansion state before clearing, restore it when recreating nodes:Side Effects
AddHandleron theTreeViewuses event bubbling; no per-container subscriptions needed.vm.IsExpanded = true, the OneWay setter re-assertstrueon the already-trueTreeViewItem; Avalonia detects no change and does not re-fireExpandedEvent.isFirstBuildguard keeps "chat-tools" starting expanded on first build.Fix agent chat editor expander defaults (#24, #25)
JoshuaRowePhantom commentedon Jun 30, 2026
Verification passed
Checked: Commit 53d7d0 (tag: ix-agent-chat-editor-expanders) on the eatures branch, referencing issues #24 and #25.
Files inspected:
Root cause addressed: The �ntity-card-tree TreeViewItem template rendered its child ItemsPresenter unconditionally. Toggling an expander changed the glyph but never hid the children. Fixed by binding ItemsPresenter.IsVisible to IsExpanded.
Result: Implementation found, all verification criteria satisfied, tests present and green.