Skip to content

feat: Enhance session management by adding session ID handling and re…#33

Merged
cnjack merged 1 commit into
mainfrom
feat/web-conversation-logic
Apr 22, 2026
Merged

feat: Enhance session management by adding session ID handling and re…#33
cnjack merged 1 commit into
mainfrom
feat/web-conversation-logic

Conversation

@cnjack

@cnjack cnjack commented Apr 22, 2026

Copy link
Copy Markdown
Owner

Web Session Management Optimization

Problem

  • Clicking "New conversation" immediately creates an empty session file on the backend, resulting in numerous blank sessions cluttering the session list
  • Deleting a session requires a secondary confirmation, making the operation cumbersome

Changes

1. Deferred Session Creation (Avoid Empty Sessions)

Backend (internal/web/server.go):

  • handleNewSession: When creating a new conversation, no longer immediately creates a recorder; only creates one when restoring an existing session
  • submitMessage: Retains existing lazy-loading logic — the recorder and session file are only created when the first message is sent

Frontend (web/src/stores/chat.ts):

  • newSession(): If already on the welcome screen (no session ID and no messages), performs no action; otherwise resets the backend state and sets currentSessionId to empty
  • agentDone(): After the agent finishes running, refreshes fetchHealth() + fetchSessions() to ensure lazily-created sessions appear in the sidebar

2. Simplified Deletion

Frontend (web/src/components/Sidebar.vue):

  • Delete button icon changed from trash can to archive icon
  • Removed right-click menu secondary confirmation; click now deletes immediately
  • Cleaned up no-longer-needed contextMenuId state and toggleContextMenu function

3. Session Restore & History

Frontend (web/src/stores/chat.ts & App.vue):

  • Added restoreCurrentSession(): On page load, fetches the current session content from the backend and replays it into the UI
  • loadSession(): Supports restoring session todo snapshots and tool call state matching
  • Ctrl+Shift+N keyboard shortcut bound to newSession()

Frontend (web/src/composables/api.ts):

  • newSession API now supports passing a sessionId parameter for restoring an existing session

Summary by CodeRabbit

  • New Features

    • Added session persistence and restoration—sessions now maintain state across reloads and can be resumed with full chat history and tool execution records restored.
    • Enhanced session tracking with real-time status visibility.
  • Improvements

    • Simplified session management UI by streamlining session action controls.

@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f727494b-cc81-42c5-8cdf-551192107490

📥 Commits

Reviewing files that changed from the base of the PR and between 2977bc1 and 823bfa9.

📒 Files selected for processing (5)
  • internal/web/server.go
  • web/src/App.vue
  • web/src/components/Sidebar.vue
  • web/src/composables/api.ts
  • web/src/stores/chat.ts

📝 Walkthrough

Walkthrough

This pull request implements session restoration and tracking by deferring recorder creation until the first user message, adding session_id and running fields to health responses, tracking the current session in the chat store, and providing a restoreCurrentSession() action to rebuild chat UI state from persisted session files.

Changes

Cohort / File(s) Summary
Backend Session API
internal/web/server.go, web/src/composables/api.ts
Modified /api/health to include session_id and running fields. Deferred recorder creation in handleNewSession until first user message; recorder only created when resuming an existing session (when req.SessionID is provided). handleNewSession now returns session_id in response.
Chat Store State & Restoration
web/src/stores/chat.ts
Added currentSessionId reactive state. Enhanced fetchHealth() to synchronize currentSessionId and isRunning from health response. Implemented new restoreCurrentSession() action to load persisted sessions, rebuild timeline, match tool results to tool calls, and finalize unresolved calls. Updated newSession() and loadSession() to track session lifecycle.
Frontend Integration
web/src/App.vue
Added restoreCurrentSession() calls in onMounted (after initial state fetch) and onProjectSwitched (after project refresh), sequencing restoration after related data loads.
Session UI Simplification
web/src/components/Sidebar.vue
Removed context menu state and confirmation popover for session deletion. Replaced "Delete" control with neutral "Archive" button and icon; clicking now directly invokes delete without intermediate menu.

Sequence Diagram

sequenceDiagram
    participant Client as Client (Browser)
    participant App as App.vue
    participant Store as Chat Store
    participant Server as Backend Server
    participant Storage as Session File

    Client->>App: onMounted
    App->>Store: fetchHealth()
    Store->>Server: GET /api/health
    Server-->>Store: {status, session_id, running, ...}
    Store->>Store: sync currentSessionId, isRunning
    
    App->>Store: restoreCurrentSession()
    
    alt Session exists
        Store->>Server: api.session(currentSessionId)
        Server->>Storage: load session file
        Storage-->>Server: session entries
        Server-->>Store: entries
        Store->>Store: rebuild timeline items
        Store->>Store: match tool results to calls
        Store->>Store: finalize tool calls
        Store-->>Client: restored chat UI
    else No session or agent running
        Store-->>Client: skip restoration
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 A recorder waits till first word's said,
Sessions restored from files widespread,
Current IDs tracked with care so light,
Chat timelines bloom—the restore's right!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/web-conversation-logic

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cnjack cnjack merged commit f2a6a6b into main Apr 22, 2026
1 check was pending
@cnjack cnjack deleted the feat/web-conversation-logic branch April 24, 2026 17:34
cnjack added a commit that referenced this pull request Jul 6, 2026
…us runs (#118)

* fix(agent): harden tools, compaction, and prompt for long-horizon runs

Audit of jcode vs Claude Code and codex (32 findings, tracked with
per-case status in internal-doc/tooling-audit.md); all confirmed cases
fixed with TDD across four waves:

Tools
- execute: head+tail truncation with dropped-bytes marker, full output
  spilled to ~/.jcode/tasks and the path returned to the model
- exec lifecycle: process-group kill via new internal/procutil (Setpgid
  + Kill(-pid)), WaitDelay=2s with ErrWaitDelay folded to success,
  SSH SIGTERM->SIGKILL grace, Docker in-container pidfile tree kill
- read: 200KB output budget with offset continuation + 2000-byte
  per-line truncation (UTF-8 safe)
- glob: find -name replaced with cd+rg --files --glob --sortr=modified
  (fixes silently-broken ** recursion, adds deterministic mtime order)
- grep: global (not per-file) content limit via streaming early-stop,
  honest capped footer, output_mode enum validation
- edit/write: read-before-edit enforced (ConflictNeverRead; FileTracker
  now actually wired in NewEnv), atomic writes (temp+fsync+rename, SSH
  base64+mv -f), multi-edit overlap/ambiguity guards + per-op
  replace_all, item schemas for edits/todos arrays
- background tasks: head+tail truncation, task log always written and
  its path surfaced to the model
- errors: Fatal/IsFatal layer aborts runs on dead container/SSH,
  subagent safe middleware (panic recovery + error folding + parent
  propagation, async panic no longer crashes the process), ToolError
  hints on high-frequency failures

Compaction
- occupancy reminder now uses last-call total (GetLastTotal) instead of
  the cumulative ledger — fixes permanently >100% "wrap up" pressure
  after any compaction
- crude 500-char threshold strategy demoted to fallback-only behind the
  eino summarizer; compact failure fuse (3 strikes, fail-open)
- output-reserve headroom (EffectiveContextLimit) for trigger math
- compaction persists the kept tail; TUI resume no longer loses it
- reduction config single-sourced (BuildReductionConfig) across
  TUI/ACP/Web, calibrated token estimator (ASCII/3.6 + CJK-aware + EMA
  self-calibration from provider usage) replaces len/4, per-turn
  aggregate tool-result budget (150k chars, copy-on-write)

Prompt
- env/git drift re-collected every 5 iterations and injected as a diff
  (includes date rollover); AGENTS.md hot-reloaded on mtime+hash change;
  externally-modified files reported with a re-read instruction
- system.md: parallel tool-call batching directive + Verification
  discipline section

Verified by ~90 new TDD tests (red first), full-repo go test -count=1,
-race on tools/agent, GOOS=windows build, and a new agent-eval ACP e2e
(robust_huge_output: seq 1 200000 truncated to marker+tail, session
survives, oracle-checked answer) passing against a live model.

Generated with Jack AI bot

* chore: resolve golangci-lint findings in new code

errcheck on discarded Count returns, De Morgan simplification,
embedded-field selector cleanup, and two unparam removals
(execLocal constant timeout, buildRgArgs unused maxResults).

Generated with Jack AI bot

* fix(git): scrub inherited GIT_* env from every git subprocess

git exports an absolute GIT_DIR to hook subprocesses when pushing from a
linked worktree. jcode's git calls (envinfo, web git API, session
baseline/diff stats) and the web test helper inherited it, silently
operating on the outer repository instead of the -C/cwd-selected one —
the web suite's `git init` in a temp dir re-initialized the pushing repo
as bare when run under the pre-push hook.

Add util.ScrubbedGitEnv() (drops GIT_DIR/GIT_WORK_TREE/GIT_INDEX_FILE/
GIT_COMMON_DIR and friends), apply it at all production git call sites,
and pin GIT_DIR/GIT_WORK_TREE to the temp repo in the web test helper.
Regression-tested by running the web suite under a hostile GIT_DIR
against a victim repo (stays non-bare) plus unit tests for the scrubber
and for gitCommand under an inherited GIT_DIR.

Recorded as finding #33 in internal-doc/tooling-audit.md.

Generated with Jack AI bot

* fix(agent): address review findings — live-env reminders, calibration recovery, docker fatal coverage

- reminder: read remote-ness from the live *tools.Env each round (switch_env
  mutates it in place without an agent rebuild on ACP/web); pause the
  env-drift / AGENTS.md / external-file sweeps while remote so local-host
  state is never reported as drift of the remote machine, and resume with
  the same baselines after switching back
- token estimate: a sustained streak of below-peak counts adopts the shrunk
  window as the new full baseline, so calibration resumes after compaction
  instead of freezing on the stale peak
- docker exec: route stream-copy and inspect errors through wrapDockerRunErr
  so a container removed mid-exec is classified Fatal like create/attach
- glob: resolve a relative search path against the tool workspace instead of
  the process cwd; make the mtime-order test deterministic via os.Chtimes
- compaction: refuse to apply an empty strategy result (counts toward the
  fuse instead of wiping the conversation)

Generated with Jack AI bot

---------

Co-authored-by: t <t@example.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant