Skip to content

feat(examples-chat): round-trip agent knobs through URL query params#527

Merged
blove merged 8 commits into
mainfrom
claude/demo-url-knobs
May 21, 2026
Merged

feat(examples-chat): round-trip agent knobs through URL query params#527
blove merged 8 commits into
mainfrom
claude/demo-url-knobs

Conversation

@blove
Copy link
Copy Markdown
Contributor

@blove blove commented May 21, 2026

Summary

Round-trips the demo's six agent knobs (model, effort, genui, theme, color, project) through the URL with ephemeral hydration semantics, on top of the URL-as-truth thread-id work already on main.

URL shape:

/<mode>[/<thread-id>][?model=&effort=&genui=&theme=&color=&project=]

Default values are omitted; non-default values appear; the URL is the share surface.

Builds on PR #500 + PR #504 + PR #518 — preserves UrlMatcher, getThread() validator, and URL-as-truth threadId semantics.

Files changed

  • examples/chat/angular/src/app/shell/demo-shell.component.ts — 3 new private methods (hydrateFromQuery, writeKnobsToUrl, buildQueryParams) + 6 knob handlers wired to writeKnobsToUrl + onModeChange/signal→URL effect both preserve query params.
  • examples/chat/angular/src/app/shell/demo-shell.component.spec.ts — 7 new unit tests.
  • examples/chat/angular/e2e/url-routing.spec.ts — NEW Playwright spec: 4 deep-link assertions.

Test plan

  • Unit: 32/32 passing in examples-chat-angular
  • Chrome MCP local verification (against nx serve + shared-dev LangGraph) — see comment below
  • e2e matrix: all 4 examples/chat — e2e (N/4) shards green

Spec: docs/superpowers/specs/2026-05-21-demo-url-knobs-design.md
Plan: docs/superpowers/plans/2026-05-21-demo-url-knobs.md

Supersedes the now-closed PR #494, focused down to just the still-needed bits.

🤖 Generated with Claude Code

blove added 7 commits May 21, 2026 14:40
Adds hydrateFromQuery() private method on DemoShell, wired via a
NavigationEnd-driven effect. Six knobs (model, effort, genui, theme,
color, project) are read from query params and set on their signals
when present.

Ephemeral semantics: URL hydration does NOT write to localStorage.
A recipient of a shared link gets the URL-specified state but their
own persisted preferences remain untouched. Explicit user actions
(via onModelChange etc.) continue to persist.
Adds buildQueryParams() + writeKnobsToUrl() private methods.
Each of the six knob handlers (onModelChange, onEffortChange,
onGenUiModeChange, onThemeChange, onColorSchemeChange,
onProjectSelected) now calls writeKnobsToUrl() after persisting.

Default values are mapped to null in buildQueryParams() so the
Angular router drops them from the URL with queryParamsHandling:
'merge'. replaceUrl: true so dropdown clicks don't pollute the
browser history.
Two navigations were dropping knob query params silently:
- onModeChange (e.g. clicking 'Popup' in the segmented control)
- the signal→URL effect that pushes agent-allocated thread ids

Both now use queryParamsHandling: 'preserve' so the URL's full state
(thread + knobs) survives mode hops and thread switches.
Four scenarios:
1. Deep-link /embed/<thread-id> loads the thread without resending.
2. /embed?model=gpt-5-nano sets the model picker via URL hydration.
3. Mode switch preserves both /embed/<id> path and ?model= query.
4. Ephemeral hydration: /embed?theme=material-dark does NOT write
   theme to localStorage (URL hydrates signal but not storage).
@vercel
Copy link
Copy Markdown

vercel Bot commented May 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
threadplane Ready Ready Preview, Comment May 21, 2026 10:55pm

Request Review

@blove
Copy link
Copy Markdown
Contributor Author

blove commented May 21, 2026

Chrome MCP verification (local, against nx serve + shared-dev LangGraph)

All 6 manual steps PASS:

  • Default URL stays clean/embedwindow.location.search === ''
  • Knob change writes URL; reset to default drops the param — Model picker gpt-5-mini → gpt-5-nano writes ?model=gpt-5-nano; back to gpt-5-mini drops the param entirely
  • Deep-link sets the model picker + theme attribute/embed?model=gpt-5-nano&theme=material-dark → picker reads gpt-5-nano, data-theme="material-dark"
  • URL hydration does NOT write to localStoragelocalStorage.clear() + visit /embed?theme=material-darklocalStorage.getItem('ngaf-chat-demo:palette') === null (ephemeral)
  • User UI action DOES persist to localStorage — clicking Theme → Material dark via UI writes {theme: 'material-dark'} to localStorage + URL ?theme=material-dark + data-theme="material-dark"
  • Mode switch preserves thread + knob, browser back restores/embed?theme=material-dark → click Popup → /popup?theme=material-dark; back button returns to /embed?theme=material-dark

Mode switch with a non-default knob now preserves the param in the URL
(via queryParamsHandling: 'preserve' added by the knob round-trip
work). The pre-existing assertion `expect(page).toHaveURL(/\/popup$/)`
expected the bare path. Updated to match the new behavior:
`/popup?...model=gpt-5-nano`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@blove blove merged commit 49ec6d2 into main May 21, 2026
25 checks passed
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