Skip to content

Modernize Graphlink Composer to a production-grade request surface - #11

Merged
dovvnloading merged 1 commit into
mainfrom
agent/sota-composer
Jul 15, 2026
Merged

dovvnloading merged 1 commit into
mainfrom
agent/sota-composer

Conversation

@dovvnloading

Copy link
Copy Markdown
Owner

What changed

  • Replace the separate attach/editor/send row with a unified Composer shell.
  • Add visible graph context, attachment summary, provider route, request status, and accessible action labels.
  • Extract draft/request identity and lifecycle transitions into ComposerController.
  • Add stale-request protection so late worker responses cannot overwrite a newer request.
  • Preserve draft text and attachments when attachment reads, provider requests, or cancellation fail.
  • Keep large paste and dropped text in the prompt draft by default; explicit attachment remains available.
  • Add provider-mode status in the Composer and package the new module.
  • Add five Composer controller/UI regression tests.

Why

The previous Composer split visual controls from the request lifecycle. Context was implicit, send/recovery state was distributed across ChatWindow and WindowActionsMixin, and failed sends cleared user work. The new shell gives the user a single, inspectable interaction surface while keeping the migration compatible with the existing graph worker contracts.

Validation

  • QT_QPA_PLATFORM=offscreen python -m pytest graphlink_app/tests -q
  • Result: 419 passed, 1 warning.
  • python -m compileall -q graphlink_app
  • git diff --check

The local-only proposal at doc/COMPOSER_SOTA_REFACTOR_PLAN.md remains ignored and is intentionally not part of this PR.

@dovvnloading
dovvnloading merged commit a1524ff into main Jul 15, 2026
6 checks passed
@dovvnloading
dovvnloading deleted the agent/sota-composer branch July 19, 2026 15:36
dovvnloading added a commit that referenced this pull request Jul 29, 2026
… (findings #10, #11) (#174)

Two dead settings from the R8a audit, both with real backend/UI wiring
already in place on one side only.

- Notification-type gating (finding #10): Settings' Info/Success/Warning/
  Error checkboxes persisted real preferences via SettingsManager.
  set_notification_preferences, and get_notification_type_enabled already
  existed to read them back - nothing ever called it. NotificationState.show()
  set visible=True unconditionally regardless of what the user had
  unchecked. register_notifications now takes an optional SettingsManager;
  show() early-returns (leaving the current banner, if any, untouched) when
  the message's type is disabled. Gating lives in the one method every call
  site already goes through, so every existing notifications.show(...) call
  across canvas.py, agents.py, chat_library.py, settings.py, plugins.py,
  autosave.py, and crash_recovery.py is covered without touching any of
  them.

- View popover FONT section (finding #11): the family/size/color controls
  already round-tripped real setFontFamily/setFontSize/setFontColor intents
  into scene state - nothing consumed scene.fontFamily/fontSizePt/fontColor
  as CSS. SceneCanvas now writes them as --gl-node-font-family/-size/-color
  custom properties on the canvas wrapper (fontSizePt is points, not
  pixels - the existing 8-16 range and 9pt default only make sense that
  way, and pt is a real CSS unit). .scene-node/.scene-node-title/
  .scene-node-body reference the tokens with their prior literal values as
  fallbacks, so every node's title and generic body text now responds to
  the FONT section live. Scoped to the shared base rules rather than each
  node kind's own content styling (markdown headings, code blocks) so
  typographic hierarchy and monospace code stay intact.

Live-verified end to end in a running instance: changing the font size
slider, family select, and color swatch each visibly restyled a real
canvas node's title and body text; toggling a notification type off
suppressed that type's banner while leaving others unaffected.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
dovvnloading added a commit that referenced this pull request Jul 29, 2026
…(findings #7, #11) (#179)

Two composer-control issues from the audit, same component.

- Finding #7: .control-value used max-width (a cap, not a fixed size), so
  switching reasoning levels (or the active model) resized the button
  itself, visibly shoving the adjacent control sideways. Changed to a fixed
  width - both the Reasoning and Model controls now stay one stable size
  regardless of which option is selected; long model ids still ellipsis-
  truncate, they just no longer resize the button while doing it.

- Finding #11: the Reasoning button had no title at all, unlike its Attach
  and Model neighbours, which both explain their disabled state. Added a
  conditional title distinguishing "provider doesn't support this" from
  "a request is in flight" - the same two reasons the button can be
  disabled for.

Live-verified against a running instance: the Reasoning control's rendered
width stayed at 238.5625px across all four levels (Off/Low/Medium/High).

Co-authored-by: Claude Opus 5 <noreply@anthropic.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