Harden chat source links across streaming providers while improving new-tab behavior and visual contrast. - Preserve source-link metadata through streamed delta and event bridges. - Open chat source links safely in new tabs across desktop and mobile surfaces. - Improve source-link contrast and add regression coverage plus user-facing guidance. Files changed: .changeset/fn-040-chat-source-links.md | 7 +++ docs/dashboard-guide.md | 3 + .../ui-bugs/chat-streamed-source-link-integrity.md | 53 ++++++++++++++++ packages/dashboard/app/components/ChatView.css | 24 ++++++++ .../app/components/StandardChatSurface.tsx | 8 ++- .../components/__tests__/ChatView.core.test.tsx | 38 ++++++++++++ .../components/__tests__/ChatView.mobile.test.tsx | 70 ++++++++++++++++++++-- .../__tests__/ChatView.sessions-rooms.test.tsx | 49 +++++++++++++++ ...andardChatSurface.nativeStructureEmbed.test.tsx | 52 +++++++++++++++- .../__tests__/TaskPlannerChatTab.test.tsx | 48 +++++++++++++++ .../engine/src/__tests__/streaming-delta.test.ts | 36 +++++++++++ packages/engine/src/execution/streaming-delta.ts | 17 +++++- .../src/__tests__/event-bridge.test.ts | 30 +++++++++- packages/pi-claude-cli/src/event-bridge.ts | 14 +++-- .../src/__tests__/event-bridge.test.ts | 42 +++++++++++++ .../fusion-plugin-acp-runtime/src/event-bridge.ts | 8 ++- .../src/__tests__/provider.test.ts | 34 +++++++++++ .../src/acp/event-bridge.ts | 8 ++- .../src/__tests__/event-bridge.test.ts | 28 +++++++++ .../src/event-bridge.ts | 14 +++-- .../src/__tests__/provider.test.ts | 34 +++++++++++ .../src/acp/event-bridge.ts | 8 ++- .../src/__tests__/runtime-adapter.test.ts | 34 +++++++++++ .../src/acp/event-bridge.ts | 8 ++- 24 files changed, 642 insertions(+), 25 deletions(-) Fusion-Task-Id: FN-040 Fusion-Task-Lineage: 364ad678-df3e-4fb2-b19c-29eb44d8a429 Co-authored-by: Fusion <noreply@runfusion.ai>
3.7 KiB
title, date, category, module, problem_type, component, symptoms, root_cause, resolution_type, severity, related_components, tags
| title | date | category | module | problem_type | component | symptoms | root_cause | resolution_type | severity | related_components | tags | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chat streamed source-link integrity | 2026-08-19 | ui-bugs | packages/engine/src/execution/streaming-delta.ts and packages/dashboard/app/components/StandardChatSurface.tsx | data_integrity | chat_streaming |
|
overly_broad_stream_boundary_repair | code_fix | medium |
|
|
Chat streamed source-link integrity
Problem
Some providers split a response immediately after a numeric period. The shared sentence-boundary repair treated every punctuation-plus-digit boundary as a missing sentence space, so chunks such as GPT-5. + 6 Luna and /gpt-5. + 6-luna were persisted as GPT-5. 6 and /gpt-5. 6-luna. The Chat renderer then produced incomplete destinations, opened ordinary links in the current tab, and inherited a low-contrast browser link color.
Solution
Classify a digit-period-digit boundary before applying the existing sentence repair. This narrow exception covers versions, decimals, IP addresses, and dotted URL path segments while preserving legitimate repairs such as Done. + Next and Phase complete. + 2 more items. The engine normalizer and every runtime bridge apply the rule before their accumulators or callbacks emit deltas, so live SSE, in-flight recovery, final PostgreSQL messages, and resumed history share one corrected value. Text and thinking accumulators remain independent.
The shared standardChatMarkdownComponents anchor preserves ReactMarkdown's sanitized href, adds semantic target="_blank" and rel="noopener noreferrer", and removes an unsafe sanitized anchor shell without bypassing defaultUrlTransform. Native structure references still become preview cards and file-path controls retain their in-app behavior. Chat-scoped CSS uses var(--text) against assistant var(--surface-1), keeps normal and visited links underlined, and uses existing transition and focus tokens; no global anchor rule or render-time content rewrite was added.
Regression matrix
- Engine normalizer: exact three-link Markdown split after every numeric period, decimals/IPs, sentence-plus-number repair, whitespace idempotence, lowercase/property continuation, cross-block fallback, and independent text/thinking tails.
- pi-Claude, generic ACP, Droid, Claude ACP, Grok ACP, and OMP ACP bridges: exact source links at the accumulator/callback boundary plus thinking-token coverage where the bridge owns a separate accumulator.
- Shared Markdown renderer: persisted and streaming links, exact href/target/rel, repeated links, unsafe schemes, native structure references, file paths, force-plain/empty content, and no nested or empty interactive shell.
- Production hosts: desktop Direct Chat persisted/live bubbles, Chat Room transcript, task-detail Planner Chat history and reattached stream, and narrow/mobile Direct Chat.
- Verification: targeted runtime/dashboard Vitest suites, changed-only
pnpm test,pnpm lint,pnpm typecheck, andpnpm build.
Non-goals
Historical persisted messages are not rewritten. Terminal-only CLI output, Task Activity/AgentLog, Mailbox, Documents, Workflow Results, and other separate Markdown renderers retain their existing contracts unless they independently adopt the shared Chat renderer.