chat input pill + chat-select + streaming/markdown fixes (chat 0.0.18, langgraph 0.0.10)#190
Closed
blove wants to merge 23 commits into
Closed
chat input pill + chat-select + streaming/markdown fixes (chat 0.0.18, langgraph 0.0.10)#190blove wants to merge 23 commits into
blove wants to merge 23 commits into
Conversation
…s$ (no left-flash)
- Add tabindex=-1 to the listbox div so the keydown handler attaches to a focusable element (a11y lint requirement). - Bump @ngaf/chat for the pill input + glowing caret + chat-select primitive + left-flash fix release.
…ubbles
OpenAI's gpt-5/o-series Responses API streams `BaseMessage.content` as
arrays of typed blocks (`[{type:'text',text:'…',index:n}, …]`) rather
than accumulated strings, and emits two parallel views of the same
assistant message: per-event `AIMessageChunk`s on `messages-tuple` and
the canonical `ai` on `values`-sync. The bridge wasn't equipped for
either — chunks JSON-dumped into the bubble and the two paths each
spawned their own bubble that never collapsed.
Bridge fixes (`stream-manager.bridge.ts`):
- `extractText` walks complex-content arrays and pulls visible text
blocks (`text` / `output_text`), skipping reasoning / tool_use /
image blocks.
- `accumulateContent` merges incoming-chunk content into the prior
slot's accumulated text. Handles the three cases: incoming is a
strict superset (final-id swap), existing is a strict superset
(chunk arrives after canonical), or pure delta append. Always
returns string so downstream `findContentMatch` can prefix-compare
cleanly without `JSON.stringify`-ing the array.
- `normalizeMessageType` collapses `AIMessage` / `AIMessageChunk` /
`ai` / `assistant` to `ai` so `findContentMatch` and
`sameRoleAndContent` correctly match across the values-sync and
messages-tuple paths.
- `mergeMessages` gains an AIMessageChunk fallback: when an
AIMessageChunk arrives without an id-match or content-prefix match,
accumulate into the trailing AI message. The OpenAI Responses API
emits per-chunk *event* ids, not message ids, so consecutive chunks
would otherwise each create a fresh bubble.
- Empty-content AI placeholders are dropped from `state.messages`
before the values-sync merge — keeping them creates a phantom slot
that competes with the chunk-streamed AIMessageChunk.
- `collapseAdjacentAi` post-pass collapses adjacent AI messages where
one's text is a prefix/equal of the other, keeping the older slot's
id for stable track-by-id.
Also dropped an obsolete hand-rolled rawMessages throttle in
`agent.fn.ts` — `messages$` already emits at the bridge boundary and
extra signal-side throttling collapsed visible token streaming.
Bumps @ngaf/langgraph 0.0.9 → 0.0.10.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…k styles
Two related rendering bugs converged into a chat that showed raw JSON
arrays and then, after fixing that, plain unstyled paragraphs with no
heading sizes, bullets, or table borders.
`messageContent` shared util:
- Was JSON-stringifying complex-content arrays, dumping
`[{"type":"text",…}]` into the chat bubble for OpenAI gpt-5 / o-series
output. Now extracts visible `text` / `output_text` blocks the same
way the langgraph adapter does and joins them; everything else
(reasoning, tool_use, images) is skipped.
`chat-streaming-md` component:
- Switched to `ViewEncapsulation.None`. The component renders markdown
by assigning sanitized HTML to `innerHTML`, so the resulting `<ul>`,
`<p>`, `<table>`, etc. nodes never carry the `_ngcontent-…`
attribute that emulated encapsulation requires. Without this the
exported `CHAT_MARKDOWN_STYLES` were silently skipped for every
selector below `:host`.
- Wired `CHAT_MARKDOWN_STYLES` into the component (it was exported but
never applied anywhere).
`CHAT_MARKDOWN_STYLES`:
- Re-scoped from `:host` to `chat-streaming-md` element selectors so
the rules stay locally meaningful under `ViewEncapsulation.None`.
- Expanded coverage to the full CommonMark + GFM surface: heading
hierarchy (h1–h6 with size scale), `strong` / `b`, `em` / `i`,
`del` / `s`, `mark`, `sub` / `sup`, `a` (with hover), bullet /
ordered / nested lists with visible `disc` / `circle` / `decimal`
markers, GFM task-list checkboxes, inline `code` / fenced `pre`,
`blockquote`, `hr`, GFM `table` (bordered, header background), and
`img` (max-width).
`marked` options:
- Enabled `gfm: true, breaks: true` so single newlines render as
`<br>` (matching common chat UX) and tables / strikethrough / task
lists / autolinks are honored.
Bumps @ngaf/chat 0.0.17 → 0.0.18.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…estions as pills Two UX improvements driven by smoke-testing the chat-select primitive in real apps. `<chat>` composition: - New `[modelOptions]`, `[(selectedModel)]`, `[modelPickerPlaceholder]` inputs that, when populated, render a `<chat-select chatInputModelSelect>` inside the chat-input pill on both the welcome screen and the conversation footer. Consumers no longer have to project the slot themselves for the common "model picker" use case — they just pass options + a model signal. - Slot projection still works in conversation mode for any consumer that needs custom chat-input children (an inner `ngProjectAs` bridges the outer `[chatInputModelSelect]` content through). Welcome suggestions: - Restyled from full-width stacked rows separated by dividers to centered floating pills (`border-radius: 9999px`, surface background, equal gap). Matches the chat-input pill aesthetic. - Container becomes `flex-wrap` + `justify-content: center` + `gap: 8px` so suggestions reflow naturally on narrow viewports. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…5-mini Default model in every demo graph and prose example is now gpt-5-mini. Reasoning models (gpt-5/o-series) stream visibly out of the box at `reasoning.effort='minimal'`, which the langgraph adapter sets by default — no developer-facing config needed. Older non-reasoning gpt-4o-mini references in graphs and docs were stale. No code path changed; pure model-name swap across cockpit examples and docs/superpowers plan / spec files. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
Author
|
Superseded by a clean rebase onto main: see new PR with the same 4 commits (langgraph bridge fix, chat markdown fix, chat model-picker + welcome pills, gpt-4o sweep). Closing because main has #189 squash-merged and rebasing this branch produced too many phantom conflicts. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--ngaf-chat-edge-padtoken, ghosted<chat-select>popover with keyboard nav,[chatInputModelSelect]slot, welcome subtitle dropped, glowing-dot caret.<chat>: pass[modelOptions]+[(selectedModel)]and the chat composition projects a<chat-select>into the input pill on both welcome and conversation views — no manual slot wiring required.[{type:'text',text:'…',index}]) and emits bothAIMessageChunk(messages-tuple) and canonicalai(values-sync) views of the same message. The bridge now extracts visible text from typed blocks, accumulates per-chunk deltas into a single slot, normalizes message types so dedupe matches across paths, drops empty-AI placeholders, and collapses adjacent AI bubbles. Single bubble accumulating cleanly.chat-streaming-mdnow usesViewEncapsulation.None+ element-scoped styles soCHAT_MARKDOWN_STYLESactually apply to innerHTML-injected DOM. Full CommonMark + GFM coverage: headings (sized hierarchy),strong/em/del, lists with visible markers (incl. nested + task lists), inline + fenced code, blockquote, hr, GFM tables (bordered + header bg), images.markedenabled withgfm: true, breaks: true.gpt-4o-minireferences swept togpt-5-mini. Reasoning models stream visibly withreasoning.effort='minimal'(langgraph default).Bumps
@ngaf/chat0.0.16 → 0.0.18 and@ngaf/langgraph0.0.9 → 0.0.10.Test plan
~/tmp/ngafagainst LangGraph backend — pick gpt-5/gpt-5-mini/gpt-5-nano, send a suggestion, verify single assistant bubble streams visibly with markdown bullets/headings/code formatted🤖 Generated with Claude Code