Skip to content

feat(bubble): add provider-level box and content attributes - #332

Merged
SonyLeo merged 2 commits into
opentiny:developfrom
gene9831:feat/bubble-provider-attributes
Apr 27, 2026
Merged

feat(bubble): add provider-level box and content attributes#332
SonyLeo merged 2 commits into
opentiny:developfrom
gene9831:feat/bubble-provider-attributes

Conversation

@gene9831

@gene9831 gene9831 commented Apr 23, 2026

Copy link
Copy Markdown
Collaborator

背景

当前如果想给所有 Box / Content 统一注入 attributes,只依赖 renderer match 不够稳定,因为无法保证所有消息都会匹配到自定义 renderer。

改动

  • BubbleProvider 新增 boxAttributescontentAttributes
  • 支持静态对象和基于上下文的动态 resolver
  • Box / Content 两条渲染链路统一支持 attributes 合并
  • 补齐 useBubbleContentRenderer 的 attributes 返回能力
  • 更新文档并新增 demo 展示 provider 级 attributes 的用法

验证

  • 已新增 demo:docs/demos/bubble/provider-attributes.vue

Summary by CodeRabbit

  • New Features

    • Provider-level attribute injection for bubbles via new box/content props; supports static objects or resolver functions and merges provider attributes with renderer-specific attributes.
    • Renderers now preserve and forward injected attributes so custom renderers receive provider metadata.
  • Documentation

    • Expanded docs and new interactive demos showing attribute injection, composite/recursive renderer patterns, and examples for binding injected attributes.

@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown

Walkthrough

Adds provider-level attribute injection to Bubble components: boxAttributes and contentAttributes configs on BubbleProvider are resolved per message/content, merged with renderer match attributes, and surfaced to wrappers/renderers; docs and demos updated to show inspection and recursive renderer handling.

Changes

Cohort / File(s) Summary
Type System & Constants
packages/components/src/bubble/index.type.ts, packages/components/src/bubble/constants.ts
Introduce BubbleAttributes, attribute resolver/config types, add boxAttributes/contentAttributes to BubbleProviderProps, and export injection keys BUBBLE_BOX_ATTRIBUTES_KEY / BUBBLE_CONTENT_ATTRIBUTES_KEY.
Renderer Composables
packages/components/src/bubble/composables/useBubbleBoxRenderer.ts, packages/components/src/bubble/composables/useBubbleContentRenderer.ts
setup*Renderer accept optional provider configs; composables inject/resolve provider configs (static or function) per render, merge provider attributes with match attributes, and return { renderer, attributes } computed shape.
Provider & Wrapper Components
packages/components/src/bubble/BubbleProvider.vue, packages/components/src/bubble/BubbleBoxWrapper.vue, packages/components/src/bubble/BubbleContentWrapper.vue
Provider supplies attribute resolvers to setup calls; wrappers updated to bind/forward resolved attributes (BubbleContentWrapper builds computed componentProps and uses renderer.renderer). Minor template reorder in Box wrapper.
Renderers Updated
packages/components/src/bubble/renderers/Reasoning.vue, packages/components/src/bubble/renderers/Tools.vue
Disable automatic root attribute inheritance, apply $attrs to explicit wrapper, render renderer.renderer and merge renderer.attributes with forwarded props when instantiating inner renderers.
Documentation & Demos
docs/src/components/bubble.md, docs/demos/bubble/provider-attributes.vue, docs/demos/bubble/custom-composite-renderer.vue, docs/demos/bubble/RecursiveReasoningRenderer.vue
Document new provider props and usage patterns; add provider-attributes demo (click-to-inspect data-* attributes), a custom composite renderer demo that sets data-demo-kind via contentAttributes, and a recursive renderer example that preserves injected attributes.

Sequence Diagram(s)

sequenceDiagram
    participant App as App / User
    participant Provider as TrBubbleProvider
    participant Composable as useBubble*Renderer
    participant Config as box/contentAttributes
    participant Wrapper as BubbleBox/ContentWrapper
    participant Renderer as Selected Renderer

    App->>Provider: Mount with boxAttributes/contentAttributes
    Provider->>Composable: setupBubbleBoxRenderer(..., boxAttributes) / setupBubbleContentRenderer(..., contentAttributes)
    Composable->>Config: provide injection key with config

    Wrapper->>Composable: compute renderer for message/content
    Composable->>Config: inject and resolve attributes (call fn or use object)
    Config-->>Composable: resolved attributes
    Composable->>Composable: merge provider attrs with match.attrs
    Composable-->>Wrapper: return { renderer, attributes }

    Wrapper->>Renderer: instantiate renderer.renderer with merged props & v-bind="attributes"
    Renderer->>Renderer: render DOM including injected data-*
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I nudge the bubbles, soft and bright,
Data-* tags gleam in gentle light.
Provider whispers attributes true,
Renderers wear their metadata new.
Click and see the story bloom — hop, inspect, delight! 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding provider-level attribute injection for both box and content in the Bubble component system.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
docs/src/components/bubble.md (1)

213-226: Consider documenting the Box wrapper's reserved attributes.

This section describes provider↔match merge precedence, but does not mention that the Box wrapper still applies its own data-role/data-placement/data-shape on top of the merged attributes (see related note on BubbleBoxWrapper.vue). If that override is intentional, a one-line callout here would prevent surprises for users who try to set those specific keys via box-attributes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/components/bubble.md` around lines 213 - 226, Add a one-line callout
under the BubbleProvider attributes section clarifying that the Box wrapper
applies reserved attributes and may override provider/match attributes:
explicitly mention BubbleBoxWrapper.vue reserves data-role, data-placement, and
data-shape on the Box and that those keys set by box-attributes or match-level
attributes will be overridden by the wrapper's values; reference BubbleProvider,
box-attributes, content-attributes and BubbleBoxWrapper.vue so readers know
where the behavior originates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/components/src/bubble/BubbleBoxWrapper.vue`:
- Around line 16-22: The wrapper currently binds renderer.attributes before the
explicit :data-role/:data-placement/:data-shape props, causing
props.role/placement/shape to always override any same-named entries in
renderer.attributes; either revert the order (move v-bind="renderer.attributes"
after the explicit bindings) so provider/match-supplied attributes win, or if
the override is intentional, document that BubbleBoxWrapper reserves these
structural attributes (mention renderer.renderer, renderer.attributes, and
props.role/props.placement/props.shape) and update docs to describe the
merge/precedence rule.

---

Nitpick comments:
In `@docs/src/components/bubble.md`:
- Around line 213-226: Add a one-line callout under the BubbleProvider
attributes section clarifying that the Box wrapper applies reserved attributes
and may override provider/match attributes: explicitly mention
BubbleBoxWrapper.vue reserves data-role, data-placement, and data-shape on the
Box and that those keys set by box-attributes or match-level attributes will be
overridden by the wrapper's values; reference BubbleProvider, box-attributes,
content-attributes and BubbleBoxWrapper.vue so readers know where the behavior
originates.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 84913a30-f025-449e-a095-efabec5f30c5

📥 Commits

Reviewing files that changed from the base of the PR and between 6a8bf29 and 8e20fce.

📒 Files selected for processing (9)
  • docs/demos/bubble/provider-attributes.vue
  • docs/src/components/bubble.md
  • packages/components/src/bubble/BubbleBoxWrapper.vue
  • packages/components/src/bubble/BubbleContentWrapper.vue
  • packages/components/src/bubble/BubbleProvider.vue
  • packages/components/src/bubble/composables/useBubbleBoxRenderer.ts
  • packages/components/src/bubble/composables/useBubbleContentRenderer.ts
  • packages/components/src/bubble/constants.ts
  • packages/components/src/bubble/index.type.ts

Comment thread packages/components/src/bubble/BubbleBoxWrapper.vue
@github-actions

github-actions Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

✅ Preview build completed successfully!

Click the image above to preview.
Preview will be automatically removed when this PR is closed.

@github-actions

github-actions Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
docs/demos/bubble/custom-composite-renderer.vue (2)

25-32: Minor: find matches empty reasoning_content strings.

typeof message.reasoning_content === 'string' is true for "", which would route an empty reasoning string into RecursiveReasoningRenderer and render an empty "自定义推理过程" section. The resolver below already guards with truthiness — for consistency, the find predicate could do the same:

♻️ Suggested tweak
-    find: (message) => typeof message.reasoning_content === 'string',
+    find: (message) => typeof message.reasoning_content === 'string' && message.reasoning_content.length > 0,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/demos/bubble/custom-composite-renderer.vue` around lines 25 - 32, The
find predicate in the contentRendererMatches entry currently matches empty
strings because it uses typeof message.reasoning_content === 'string'; update
the predicate used for the BubbleContentRendererMatch to require a non-empty
reasoning string (e.g., check truthiness or length of message.reasoning_content)
so only messages with actual reasoning content route to the renderer; adjust the
match for the RecursiveReasoningRenderer entry (the find function referencing
message.reasoning_content) to mirror the resolver's guard.

34-43: Optional: consider a non-data-role key in this demo to avoid muddying the reserved-attribute story.

data-role is reserved on BubbleBoxWrapper (always derived from props.role), so a reader who copy-pastes this demo and switches contentAttributesboxAttributes will silently lose their injected data-role. A demo key like data-demo-role (parallel to data-demo-kind already used here) would teach the safer convention up front.

♻️ Suggested tweak
   return {
     'data-demo-kind': isReasoning ? 'reasoning' : 'content',
-    'data-role': message.role || 'assistant',
+    'data-demo-role': message.role || 'assistant',
     'data-content-type': content.type,
     'data-content-index': contentIndex,
   }

Based on learnings: data-role, data-placement, and data-shape are reserved structural attributes on BubbleBoxWrapper and override same-named keys from provider/match attributes; users injecting custom attributes should prefer non-reserved keys.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/demos/bubble/custom-composite-renderer.vue` around lines 34 - 43, The
demo uses a reserved attribute key `data-role` inside the contentAttributes
function (contentAttributes) which can conflict with BubbleBoxWrapper's reserved
props; change the injected key to a non-reserved name (e.g., `data-demo-role`)
so demo users don’t accidentally override structural attributes—update the
returned object in contentAttributes to replace 'data-role' with
'data-demo-role' (keeping the same value expression message.role || 'assistant')
and keep the other demo-specific keys like 'data-demo-kind' to teach the safer
convention.
docs/src/components/bubble.md (1)

336-336: Minor doc nit: clarify what "重复 id" means in the multi-root warning.

The bullet warns against copying the same attributes onto multiple sibling nodes (duplicate id, ARIA, test selectors). In practice, provider/match attributes are usually data-*, where duplication is harmless; the only common hazards are id, aria-labelledby/aria-describedby references, and data-testid. Listing those explicitly would make the warning more actionable, but content is otherwise accurate.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/components/bubble.md` at line 336, Update the multi-root renderer
warning sentence (the line mentioning `inheritAttrs: false` and `$attrs`) to
explicitly list the attribute types that are hazardous when duplicated across
sibling nodes: `id`, ARIA reference attributes like `aria-labelledby` and
`aria-describedby`, and test selectors such as `data-testid`; note that generic
`data-*` attributes are usually harmless. Keep the guidance to use
`inheritAttrs: false` and explicitly bind `$attrs` to a single node to avoid
those specific duplicates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@docs/demos/bubble/custom-composite-renderer.vue`:
- Around line 25-32: The find predicate in the contentRendererMatches entry
currently matches empty strings because it uses typeof message.reasoning_content
=== 'string'; update the predicate used for the BubbleContentRendererMatch to
require a non-empty reasoning string (e.g., check truthiness or length of
message.reasoning_content) so only messages with actual reasoning content route
to the renderer; adjust the match for the RecursiveReasoningRenderer entry (the
find function referencing message.reasoning_content) to mirror the resolver's
guard.
- Around line 34-43: The demo uses a reserved attribute key `data-role` inside
the contentAttributes function (contentAttributes) which can conflict with
BubbleBoxWrapper's reserved props; change the injected key to a non-reserved
name (e.g., `data-demo-role`) so demo users don’t accidentally override
structural attributes—update the returned object in contentAttributes to replace
'data-role' with 'data-demo-role' (keeping the same value expression
message.role || 'assistant') and keep the other demo-specific keys like
'data-demo-kind' to teach the safer convention.

In `@docs/src/components/bubble.md`:
- Line 336: Update the multi-root renderer warning sentence (the line mentioning
`inheritAttrs: false` and `$attrs`) to explicitly list the attribute types that
are hazardous when duplicated across sibling nodes: `id`, ARIA reference
attributes like `aria-labelledby` and `aria-describedby`, and test selectors
such as `data-testid`; note that generic `data-*` attributes are usually
harmless. Keep the guidance to use `inheritAttrs: false` and explicitly bind
`$attrs` to a single node to avoid those specific duplicates.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 08d62a71-14eb-4c84-a98e-94f8a81bdaf3

📥 Commits

Reviewing files that changed from the base of the PR and between 8e20fce and 9db5c68.

📒 Files selected for processing (5)
  • docs/demos/bubble/RecursiveReasoningRenderer.vue
  • docs/demos/bubble/custom-composite-renderer.vue
  • docs/src/components/bubble.md
  • packages/components/src/bubble/renderers/Reasoning.vue
  • packages/components/src/bubble/renderers/Tools.vue

@SonyLeo
SonyLeo merged commit 055d255 into opentiny:develop Apr 27, 2026
4 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

🧹 Preview Cleaned Up

The preview deployment has been removed.

@gene9831
gene9831 deleted the feat/bubble-provider-attributes branch April 27, 2026 16:42
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.

2 participants