Commit Graph

134 Commits

Author SHA1 Message Date
Levi Neely 265a1fdda9 refactor: promote remote to session level, remove agent connectivity, formalize NinePConnection state machine
- Add createSession(name, remote) with New Session dialog
- Remove agent connectivity code (redundant with session connectivity)
- Refactor NinePConnection as formal state machine with explicit events
- Fix silent restart to not cycle through Connecting state
2026-08-04 15:22:08 +02:00
Levi Neely ec89eaae18 fix: always send stop on ESC regardless of cached state
Removes the activeState !== 'idle' check before sending the stop
command. The server-side Interrupt() is safe to call on an idle
agent (returns false, no-op).

This fixes an intermittent issue where pressing ESC wouldn't stop
the agent because the GUI's cached activeState was stale/out-of-sync
with the server's actual state.
2026-08-04 11:51:01 +02:00
Levi Neely 9d059943f2 cleanup: remove debug logging 2026-08-03 20:43:16 +02:00
Levi Neely 3fd13c6d38 fix: use state role directly for binding updates
model.state doesn't trigger binding re-evaluation in Qt5 delegates.
Using the implicit role 'state' directly does.
2026-08-03 20:31:17 +02:00
Levi Neely 1d0fb99501 targeted state dot updates in render path
- onAgentStateChanged: update specific agent in model instead of version bump
- State dot: use model.state directly instead of ollie.agentState() callback
- Remove ollie.isSessionPaused() call (was O(n) iteration per agent)
- Remove unused agentStateVersion property

Before: 1 state change → re-evaluate ALL agent dots → N * ollie.agentState() calls
After:  1 state change → setProperty on 1 model item → 1 binding update
2026-08-03 20:29:38 +02:00
Levi Neely 57b3ce04e3 eliminate C++ calls in QML update loop
- computeConnectionColor() in QML instead of ollie.sessionConnectionColor()
  (avoids O(n²) iteration through sessions list)
- Use agent.state from session/idx data directly instead of ollie.agentState()
  (avoids hash lookup per agent per update)

All data now flows from session/idx through m_sessions to QML with no
callbacks into C++ during the update loop.
2026-08-03 20:13:32 +02:00
Levi Neely 24921e7a2b incremental session tree updates
Instead of clearing and rebuilding the entire session tree model on
every sessionsChanged signal, diff old vs new and:
- Update existing session/agent properties in place
- Remove deleted sessions/agents
- Append new sessions/agents

This avoids O(n) model rebuilds that cause ListView to re-render all
delegates, improving responsiveness with many sessions.
2026-08-03 19:51:54 +02:00
Levi Neely 0c93414251 optimize QML rendering performance
- Remove console.log statements from hot paths
- Add sessionExpandedCache for O(1) expanded state lookup
- Replace O(n) parentSessionExpanded() loop with cache lookup
- Preserve expanded state across session tree rebuilds
2026-08-03 19:29:45 +02:00
Levi Neely eedee30332 session pause/resume UI
- Add Pause/Resume toggle to session context menu
- Gray agent dots when parent session is paused
- Disable input field with 'Session paused' placeholder when paused
- Preserve focus on prompt input during tree rebuilds
2026-08-03 18:36:18 +02:00
Levi Neely 453cef397f live agent state indicators in session tree
- Add per-agent statewait streams to track execution state
- Agent dots show: green=idle, orange=calling, blue=thinking
- Session dots show RPC connection health (unchanged)
- Use version counter pattern to force QML binding re-evaluation
2026-08-03 18:30:14 +02:00
Levi Neely 566aeddecc feat: show paused sessions as gray, add agent count to session name
- Fetch paused status from session/{id}/paused file
- Gray dot indicator for paused sessions (green otherwise)
- Session names now show agent count: 'ollie (2)'
- Fixed rename to use baseName for sessions (without count suffix)
2026-08-03 18:12:01 +02:00
Levi Neely 22a2208526 fix: show error dialog and reset name when rename fails
commitRename now checks the return value from renameSession/renameAgent.
On failure, resets displayName to the old value and shows an error dialog
explaining the rename failed (e.g., name already in use).
2026-08-03 17:53:38 +02:00
Levi Neely 414143955f fix(gui): improve multi-agent-per-session handling
Session selection now auto-selects first agent:
- Clicking a session row selects its first agent (not just the session)
- Auto-select at startup now picks first agent of first session
- Fixes issue where clicking session would clear agent and show empty chat

Improved UI feedback:
- Header shows 'Session / Agent' name instead of just state
- State indicator gray when no agent selected
- Placeholder message when no agent selected: 'Select an agent to view chat'
- Chat ListView hidden when no agent (shows placeholder instead)
- Input already disabled with 'No agent' placeholder (existing behavior)

Cleanup:
- Remove dead declaration reconcileAgentConnections(const QVariantList&)
2026-08-03 17:42:05 +02:00
Levi Neely 7c347ff6c1 fix(gui): remove TextEdit color property for syntax highlighting
Qt5's TextEdit 'color' property can override inline styles from RichText,
breaking syntax highlighting colors. Remove the property so inline color
spans from KSyntaxHighlighting are respected.

Default text color should come from the application palette.
2026-08-03 16:07:43 +02:00
Levi Neely 3fd7907359 gui: show error and keep dialog open on agent creation failure
Change createAgent to return error string (empty=success).
Replace standardButtons with custom footer so dialog stays open
on error, showing the message and letting the user adjust values.
2026-08-03 10:41:32 +02:00
Levi Neely 0f51c83f24 gui: rename 'Alias' to 'Name' in new agent dialog 2026-08-03 09:22:08 +02:00
Levi Neely 84fb53332c gui: separate session and agent creation, add agent context menu
- '+' button now creates an empty session directly (no dialog)
- Dialog becomes 'New Agent' (session name field removed)
- Session context menu: 'New Agent...' + 'Kill Session'
- Agent context menu: 'Kill' (writes kill to agent ctl)
- New C++ methods: createQuickSession(), createAgent(), killAgent()
2026-08-03 09:16:00 +02:00
Levi Neely 4dabab1f71 fix connection dot indicators 2026-08-02 23:59:28 +02:00
Levi Neely 6e7245dd99 connection statuses 2026-08-02 23:35:14 +02:00
Levi Neely c983e2bb6a simplify rendering 2026-08-02 22:43:11 +02:00
Levi Neely 3bb75b6c20 gui: stop rebuilding session tree on selection changes
The dominant 9P spam came from buildSessionTree() re-listing
session/<sid>/agent on every activeSessionIdChanged and
activeAgentIdChanged signal. Tree rebuilds are now limited to
sessionsChanged and startup refresh; selection changes only
refresh the right pane transcript.
2026-08-01 21:48:04 +02:00
Levi Neely b8fc64fb18 gui: clicking a session clears explicit agent selection
- Session row click now calls setActiveSessionId(id)
- setActiveSessionId no longer returns early for same-session clicks;
  it always clears m_agentId and stops per-agent streams
- This enforces a clean 'session selected, no agent selected' state
2026-08-01 21:22:33 +02:00
Levi Neely 22e58b348f gui: require explicit agent selection for statewait/chat
- setActiveSessionId now selects only the session; it clears m_agentId
  and never auto-selects a lone agent.
- startStateStream no longer re-resolves or falls back to another agent;
  it only runs when the explicit active agent still exists.
- QML now handles activeAgentId changes explicitly and keeps the right
  pane blank/disabled when no session or no agent is selected.
2026-08-01 21:18:09 +02:00
Levi Neely c85252b09a fix(gui): prevent session list from stealing keyboard focus
- ListView and its placeholder label now have activeFocusOnTab: false
  and focus: false so clicking the empty sidebar doesn't steal focus
  from the prompt text area
2026-08-01 20:14:40 +02:00
Levi Neely b68b72b31f fix(gui): use eventwait data directly, remove focus-stealing timer
- onEventReadyRead() now parses the eventwait data directly instead of
  discarding it and re-reading session/idx
- Removed the 2-second refresh timer that was stealing focus from the
  prompt text area on every tick
2026-08-01 20:13:53 +02:00
Levi Neely 87850f7f10 fix(gui): ensure sessions load on startup and via periodic refresh
- Call ollie.refreshSessions() from Component.onCompleted before
  buildSessionTree() for reliable initial load
- Add a 2-second periodic refresh timer as fallback for missed events
2026-08-01 20:10:17 +02:00
Levi Neely adb2760c91 fix(gui): load sessions on startup, show '(no sessions)' placeholder
- ensureRootDataLoaded() now calls refreshSessions() so the initial
  session list is populated immediately, not only on events
- Added '(no sessions)' placeholder label in the session tree ListView
  when no sessions exist
2026-08-01 20:05:31 +02:00
Levi Neely 6fcef9f60c feat(gui): handle empty sessions in ollie-gui
- getAgents(): filter out 'new' (agent creation file), return empty list
- setActiveSessionId(): skip agent init when no agents exist
- submit/interrupt/kill/streams: guard against empty m_agentId
- prompt input: disable when no agent, show 'No agent' placeholder
2026-08-01 19:51:07 +02:00
Levi Neely 68a84a2404 gui: session group has Name only; all else under Agent 2026-08-01 18:35:32 +02:00
Levi Neely 1b67305ef7 gui: group session/agent params in new session dialog; add agent alias field 2026-08-01 18:33:05 +02:00
Levi Neely 363b2e95ed gui: add double-click to rename agent nodes in tree view 2026-08-01 18:17:13 +02:00
Levi Neely 79d031ff04 remove 'Agent ' prefix from agent display name 2026-08-01 18:04:28 +02:00
Levi Neely cec358bdb9 omit response ID from assistant header 2026-08-01 17:18:27 +02:00
Levi Neely e8a3c6e1d8 ▶️ for call, 🖥️ for tool headers 2026-08-01 17:17:36 +02:00
Levi Neely 25492c889e ❌ for error headers 2026-08-01 17:16:19 +02:00
Levi Neely 37d4b995f4 emoji labels: 🧑 Human, 🤖 Ollie, ℹ️ Info 2026-08-01 17:15:45 +02:00
Levi Neely bd88328972 use emoji-style ⚠️ with variation selector 2026-08-01 17:13:36 +02:00
Levi Neely 8617aa5293 gui: render user-interrupt with yellow background and warning icon
- Add Interrupt block type to ChatBlock enum
- Detect <system-user-interruption> and </system-user-interruption>
  tags as block openers/closers in the parser
- Render interrupt blocks with bright yellow header
  (#3d2e00 dark, #fff8e1 light)
- Show ⚠ User Interrupt header label
2026-08-01 17:11:52 +02:00
Levi Neely ada6dc1feb fix context menu: kill target session, not active one
Right-click now stores the target session ID in a root-level
property (killTargetSessionId) before popping the menu, avoiding
unreliable QML parent chain traversal that could resolve to the
wrong delegate.
2026-08-01 17:08:22 +02:00
Levi Neely 0706a052f4 fix QML mouse parameter deprecation warning
onClicked needs explicit function(mouse) parameter instead of
implicit injection.
2026-08-01 17:06:09 +02:00
Levi Neely 612adb03f8 gui: add right-click context menu with Kill action for sessions
- Add killSession(sessionId) Q_INVOKABLE to Ollie9pClient
- Accept right button in session tree MouseArea
- Context menu with Kill option on right-click
- MenuItem resolves session ID via parent chain
2026-08-01 17:02:53 +02:00
Levi Neely 998efc15c5 chat log: switch to [[[type]]]/[[[end]]] block format
Replace the single-bracket INI-like format with triple-bracket blocks
with explicit [[[end]]] terminators. The parser tracks m_inBlock to
ignore content between blocks, making the format robust against
accidental header-like content in tool output or LLM responses.

- Go sender: FormatEvent + NewEventHandler + replayMessagesToLog
- C++ parser: new regex for [[[type]]], new [[[end]]] handler, m_inBlock gate
- QML: update hardcoded [info] string
2026-08-01 16:48:57 +02:00
Levi Neely b13dc6064b gui: make session tree fully expanded by default and responsive
- Remove 300ms click delay (timer-based single/double-click disambiguation)
- Use native QML onDoubleClicked for rename instead of timer hack
- Capture model index as delegate property to fix rename targeting all nodes
- Remove dead rename code that was orphaned by the timer removal
- Clean up Escape shortcut handler
2026-08-01 16:40:45 +02:00
Levi Neely 120e4a4bd6 gui: revert reasoning block suppression in QML (handled server-side now) 2026-08-01 16:28:21 +02:00
Levi Neely 9ba1de0c1c gui: preserve session tree expansion across agent switches
buildSessionTree() was clearing the tree and setting expanded=true
only for the active session, collapsing all other sessions whenever
an agent in a different session was selected.

Now snapshot expanded state before clearing and restore it, so manually
expanded sessions stay open across agent switches.
2026-08-01 16:16:55 +02:00
Levi Neely cd0f92e16d session rename: fix renameSession, use setProgram/setArguments 2026-08-01 15:53:03 +02:00
Levi Neely 4bd7a60e78 session rename: clean up comment, use ollie-9p mv 2026-08-01 15:50:31 +02:00
Levi Neely 63cf13b891 session rename: double-click to rename sessions in tree 2026-08-01 15:47:23 +02:00
Levi Neely 95cf201f4c remove inline autocomplete state machine from prompt input 2026-08-01 13:07:43 +02:00
Levi Neely 9bab0e73c2 fix: use promptInput.text instead of bare text in root-level autocomplete functions 2026-08-01 13:00:24 +02:00