Skip to content

feat(control-ui): session grouping with drag & drop and channel categorization#100262

Merged
steipete merged 5 commits into
mainfrom
claude/serene-cray-498eb2
Jul 5, 2026
Merged

feat(control-ui): session grouping with drag & drop and channel categorization#100262
steipete merged 5 commits into
mainfrom
claude/serene-cray-498eb2

Conversation

@steipete

@steipete steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

The Control UI sessions table is a flat list. Once an operator runs many sessions across agents and message channels (Discord, Telegram, WhatsApp, ...), there is no way to organize them: no grouping, no way to categorize channel-originated sessions, and no equivalent of the desktop app's custom session groups.

Why This Change Was Made

Adds a persistent per-session category field end-to-end (gateway protocol sessions.patch -> session store -> list rows -> live session-change events) and a "Group by" control on the web Sessions page with None / Custom groups / Channel / Kind / Agent / Date modes. The field is named category to stay clearly separate from the existing chat-group concepts (groupId, groupChannel, kind group). Custom group membership persists server-side on the session entry; empty just-created groups live in browser localStorage until a session is assigned. Cleared categories emit an explicit null in session events so other connected clients drop the group during merge-reconcile instead of going stale.

User Impact

  • Group the sessions table by custom groups, channel, kind, agent, or date, with section headers and counts; the chosen mode persists per browser.
  • Create custom groups and assign sessions by dragging rows onto a section (drop-target highlight), or via a per-row group selector; sessions from message channels can be categorized like any other session.
  • Channel mode buckets sessions by their originating channel out of the box.
  • Group names are searchable in the table filter and shown in the session details panel.
  • Protocol change is additive: sessions.patch accepts category: string | null; session rows and change events carry category.

Evidence

  • Backend: sessions-patch suite 239 passed (new category persist/trim/clear/duplicate/empty tests), server.sessions.list-changed 46 passed after the event payload change, protocol + session-utils + store-rpc 690 passed.
  • UI: 42 tests passed, including new coverage for grouping helpers (channel/agent/date/category bucketing, group ordering), section headers and counts, drag-drop assignment via header drop targets, the filtered empty state under active grouping, and reconcile dropping a cleared category.
  • tsgo core and UI lanes clean; oxfmt/oxlint clean on touched files.
  • Codex autoreview (gpt-5.5) over four rounds; the three accepted findings (blank empty state when grouped, agent:main:main misgrouped in Agent mode, stale category on other clients after clear) were fixed with regression tests; final run reported no actionable findings.
  • Docs: docs/web/control-ui.md describes the new grouping behavior.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation app: web-ui App: web-ui gateway Gateway runtime size: L maintainer Maintainer-authored PR labels Jul 5, 2026
@clawsweeper

clawsweeper Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 5, 2026, 12:10 PM ET / 16:10 UTC.

Summary
Adds persisted session categories and Control UI session grouping modes, with gateway protocol/storage updates, UI grouping controls, generated locale/native artifacts, tests, and docs.

Reproducibility: not applicable. as a bug reproduction: this PR adds a new Control UI grouping feature, and source inspection confirms current main lacks the category grouping surface. The missing evidence is after-change real browser proof, not a current-main failure repro.

Review metrics: 2 noteworthy metrics.

  • Protocol and storage surface: 1 sessions.patch field added; 1 SessionEntry field added. The new category field affects gateway clients and persisted session metadata, so compatibility and upgrade behavior need maintainer attention.
  • Generated native API surface: 1 Swift public initializer parameter added without a default. The generated OpenClawKit model can break existing native source callers even though the protocol field is optional.

Stored data model
Persistent data-model change detected: persistent cache schema: src/tui/tui-pty-local.e2e.test.ts, persistent cache schema: ui/src/i18n/.i18n/tr.tm.jsonl, persistent cache schema: ui/src/i18n/.i18n/uk.tm.jsonl, persistent cache schema: ui/src/i18n/.i18n/vi.tm.jsonl, persistent cache schema: ui/src/i18n/.i18n/zh-CN.tm.jsonl, persistent cache schema: ui/src/i18n/.i18n/zh-TW.tm.jsonl, and 24 more. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦐 gold shrimp
Result: blocked until real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add category to the Swift generator's defaulted optional SessionsPatchParams list and regenerate OpenClawKit models.
  • Attach redacted browser proof showing the Sessions grouping modes, New group creation, and drag-and-drop assignment.
  • Get maintainer confirmation that persisted category is the intended session grouping contract.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body and comments provide test/check claims only; it still needs redacted browser proof showing grouping modes, New group creation, and drag-and-drop category assignment on the current head. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Mantis proof suggestion
A short visual browser proof would materially help verify the new Sessions grouping, custom group creation, and drag-and-drop assignment workflow. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis visual task: verify Control UI Sessions grouping by custom category, channel, kind, agent, and date, including New group creation and drag-and-drop assignment.

Risk before merge

  • [P1] The generated Swift public initializer currently turns the additive category protocol field into a required source argument for OpenClawKit callers.
  • [P1] The new persisted category field becomes a long-term gateway/session metadata contract for web and native clients, so maintainer product/API acceptance is still needed.
  • [P1] No real browser proof currently shows the grouping modes, New group creation, or drag-and-drop category assignment on this head.
  • [P1] Session-change and reconcile behavior now depend on explicit category: null; future drift there would leave connected clients with stale custom group assignments.

Maintainer options:

  1. Fix Swift compatibility and prove the UI (recommended)
    Add category to the Swift generator's defaulted optional SessionsPatchParams list, regenerate OpenClawKit models, and attach redacted browser proof before merge.
  2. Accept the source break explicitly
    Maintainers may intentionally accept the Swift initializer source break, but that makes an additive gateway field disruptive for existing native callers.
  3. Pause for contract redesign
    If category is not the intended permanent session grouping field, pause or close this branch and settle the API shape first.

Next step before merge

  • [P1] Manual review is needed because the remaining blockers are maintainer acceptance of a new persisted session metadata contract, contributor-supplied UI proof, and a generated Swift compatibility repair.

Maintainer decision needed

  • Question: Should OpenClaw expose persisted per-session category on sessions.patch, session rows, and session-change events as the Control UI custom grouping contract?
  • Rationale: The code can be repaired mechanically, but the PR adds a public protocol and stored session metadata surface under a protected maintainer label, so automation should not choose the permanent API contract alone.
  • Likely owner: steipete — He has the strongest visible history on the adjacent session reconcile behavior and authored the proposed category contract in this PR.
  • Options:
    • Accept category after compatibility/proof (recommended): Keep the category contract, fix the generated Swift source-compatibility break, require exact-head browser proof, and document it as the supported grouping field.
    • Redesign grouping state: Pause this branch and choose a different storage or protocol shape before exposing custom grouping to web and native clients.
    • Keep custom groups browser-local: Avoid new persisted protocol metadata for now, accepting that custom grouping will not follow sessions across clients.

Security
Cleared: No concrete security or supply-chain regression was found; the merge-result diff adds no dependencies, workflows, broad permissions, or downloaded code execution, and the drag/drop path uses a private MIME plus current-row key checks.

Review findings

  • [P1] Default the Swift category initializer parameter — apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift:2470
Review details

Best possible solution:

Default category in the generated Swift initializer, regenerate artifacts, add redacted browser proof of the grouping workflow, and land only after maintainers accept category as the persisted session grouping contract.

Do we have a high-confidence way to reproduce the issue?

Not applicable as a bug reproduction: this PR adds a new Control UI grouping feature, and source inspection confirms current main lacks the category grouping surface. The missing evidence is after-change real browser proof, not a current-main failure repro.

Is this the best way to solve the issue?

No, not as-is: the category-based implementation is plausible, but the generated Swift compatibility break, missing real UI proof, and unconfirmed persisted API contract make it short of the best mergeable solution.

Full review comments:

  • [P1] Default the Swift category initializer parameter — apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift:2470
    category is optional in the JSON protocol, but the generated Swift public initializer now requires category: AnyCodable? while the generator default list for SessionsPatchParams still only covers agentId, archived, and pinned. That makes an additive protocol field source-breaking for existing OpenClawKit clients constructing session patches; add category to DEFAULTED_OPTIONAL_INIT_PARAM_ENTRIES and regenerate. Late discovery: this same generated initializer was already visible in an earlier reviewed head.
    Confidence: 0.91
    Late finding: first raised on code an earlier review cycle already covered.

Overall correctness: patch is incorrect
Overall confidence: 0.88

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 286d0b9fb340.

Label changes

Label justifications:

  • P2: This is a bounded Control UI/gateway feature with compatibility risk, not an outage, security bypass, crash loop, or first-run blocker.
  • merge-risk: 🚨 compatibility: The PR adds a public gateway protocol field and currently makes the generated Swift initializer source-breaking for existing native callers.
  • merge-risk: 🚨 session-state: The PR changes persisted session metadata and live session-change reconciliation, where null-clear drift can leave connected clients with stale group state.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body and comments provide test/check claims only; it still needs redacted browser proof showing grouping modes, New group creation, and drag-and-drop category assignment on the current head. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

What I checked:

  • Repository policy applied: Root plus relevant scoped AGENTS.md files were read; the protocol/session compatibility, generated UI locale, docs, scripts, gateway, agents, TUI, plugins, and extensions guidance affected this review. (AGENTS.md:29, 286d0b9fb340)
  • Merge-result surface checked: The potential merge commit has current main and the PR head as parents, and the surviving diff against current main is limited to session grouping/protocol/docs/generated UI surfaces rather than the stale-base runtime noise shown in the raw PR file list. (5d3e839259ce)
  • Current main lacks category: Current main's sessions.patch schema has label followed by archive/pin fields and no category, so this PR introduces a new public protocol/session metadata field. (packages/gateway-protocol/src/schema/sessions.ts:301, 286d0b9fb340)
  • PR adds protocol category: The merge result adds optional category: string | null to sessions.patch as a user-defined organization bucket unrelated to chat groups. (packages/gateway-protocol/src/schema/sessions.ts:306, 5d3e839259ce)
  • Gateway category semantics implemented: The merge result trims, validates, stores, and clears category, while allowing duplicate category names across sessions. (src/gateway/sessions-patch.ts:373, 5d3e839259ce)
  • UI grouping controls added: The merge result renders the Sessions Group by selector and New group action for custom grouping in the Control UI. (ui/src/pages/sessions/view.ts:873, 5d3e839259ce)

Likely related people:

  • steipete: Authored the current-main label clear reconcile change adjacent to the new category null-clear invariant and authored the PR head/category generated-model updates under review. (role: recent session/UI contributor and likely product decision owner; confidence: high; commits: 00da1243a8ae, 171d049c6196, 60cb104b9bb4; files: ui/src/lib/sessions/reconcile.ts, apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift, packages/gateway-protocol/src/schema/sessions.ts)
  • vincentkoc: The checked-out current main blames the central Sessions page, protocol schema, sessions patch path, and Swift generator default list to the grafted source snapshot associated with this author; this is useful routing context but weak feature ownership evidence. (role: current-main source provenance and adjacent Control UI/gateway contributor; confidence: low; commits: fd2e4da00651; files: ui/src/pages/sessions/view.ts, ui/src/pages/sessions/sessions-page.ts, packages/gateway-protocol/src/schema/sessions.ts)
  • Jason: Recent history shows work on the Swift protocol generator and generated OpenClawKit models near the compatibility issue surfaced in this PR. (role: recent native protocol/generated-model contributor; confidence: medium; commits: 95ebb3dc1e73; files: scripts/protocol-gen-swift.ts, apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (6 earlier review cycles)
  • reviewed 2026-07-05T09:58:17.664Z sha 449849a :: needs real behavior proof before merge. :: [P2] Regenerate native protocol models | [P2] Regenerate Control UI locales
  • reviewed 2026-07-05T11:56:03.217Z sha f390b53 :: needs real behavior proof before merge. :: [P2] Regenerate native protocol models
  • reviewed 2026-07-05T14:36:19.879Z sha 69acb6d :: needs real behavior proof before merge. :: [P2] Regenerate native protocol models
  • reviewed 2026-07-05T15:09:45.466Z sha 0e7ff31 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-05T15:24:03.454Z sha 171d049 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-05T16:03:36.136Z sha 60cb104 :: needs real behavior proof before merge. :: none

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d3ae7fe009

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +564 to +566
const key = event.dataTransfer?.getData(SESSION_DRAG_MIME);
if (key) {
props.onAssignCategory(key, category);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject non-session drags before patching categories

When the sessions table is grouped by category, every group/row drop target calls preventDefault() and then accepts any text/plain payload as a session key. In browsers, dragging selected text, a URL, or other external content commonly provides text/plain; dropping that onto a group will call onAssignCategory with that arbitrary string, and sessions.patch creates a session entry when the key is missing. Please use a custom OpenClaw drag MIME (and/or verify the key exists in the current rows) before patching so external drags cannot pollute the session store.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jul 5, 2026
@steipete
steipete force-pushed the claude/serene-cray-498eb2 branch from f6f589e to f390b53 Compare July 5, 2026 11:29

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f390b53e96

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

agentId: Type.Optional(NonEmptyString),
label: Type.Optional(Type.Union([SessionLabelString, Type.Null()])),
/** User-defined organization bucket ("category", not chat-group); null clears it. */
category: Type.Optional(Type.Union([SessionLabelString, Type.Null()])),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Regenerate native protocol models for category

Adding category to the gateway protocol schema also needs the generated native protocol artifact refreshed: scripts/protocol-gen-swift.ts emits SessionsPatchParams into apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift, but that struct still lacks a category property/CodingKey. In CI the bundled protocol lane runs pnpm protocol:check, which regenerates and diffs these artifacts, so this schema-only change will leave the generated model stale and block the protocol check; please regenerate the Swift protocol model with this field.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jul 5, 2026
@steipete
steipete force-pushed the claude/serene-cray-498eb2 branch from 69acb6d to 4a8e8ba Compare July 5, 2026 14:51
@clawsweeper clawsweeper Bot added the merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. label Jul 5, 2026
@steipete
steipete force-pushed the claude/serene-cray-498eb2 branch from 0e7ff31 to 171d049 Compare July 5, 2026 15:16
@openclaw-barnacle openclaw-barnacle Bot added scripts Repository scripts agents Agent runtime and tooling extensions: qa-lab labels Jul 5, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 60cb104b9b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

key: String,
agentid: String? = nil,
label: AnyCodable?,
category: AnyCodable?,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Default the Swift category initializer parameter

When native OpenClawKit callers construct SessionsPatchParams for existing patches (label/archive/model/etc.), this new optional category parameter is inserted into the public initializer without a = nil default, so every existing Swift call site must be edited even though the protocol field is additive. The generator already has a per-struct default list for additive optional params (scripts/protocol-gen-swift.ts:57, and this PR did it for ChatAbortedEvent.errorMessage); add category there and regenerate so existing clients can omit it.

Useful? React with 👍 / 👎.

@steipete
steipete merged commit f607ba0 into main Jul 5, 2026
120 of 122 checks passed
@steipete
steipete deleted the claude/serene-cray-498eb2 branch July 5, 2026 16:13
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 6, 2026
…orization (openclaw#100262)

* feat(control-ui): session grouping with drag & drop and channel categorization

* fix(control-ui): restrict session drag&drop to private session-key payloads

* chore(i18n): translate session grouping strings across control ui locales

* chore(protocol): regenerate swift gateway models for session category

* chore(protocol): regenerate swift gateway models for session category
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling app: web-ui App: web-ui docs Improvements or additions to documentation extensions: qa-lab gateway Gateway runtime maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. scripts Repository scripts size: XL status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant