From e76d76827d8810992b6b700ffdc03961e9e00caa Mon Sep 17 00:00:00 2001 From: Mindev27 Date: Fri, 13 Mar 2026 10:37:06 +0900 Subject: [PATCH] fix(lit): handle TextPart fallback messages in shell and contact sample clients Fixes #585 --- samples/client/lit/contact/client.ts | 22 ++++++++++++++++++---- samples/client/lit/contact/contact.ts | 10 ++++++---- samples/client/lit/shell/app.ts | 13 +++++++------ samples/client/lit/shell/client.ts | 19 ++++++++++++++++--- 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/samples/client/lit/contact/client.ts b/samples/client/lit/contact/client.ts index 8e776caa3..27f1ed14f 100644 --- a/samples/client/lit/contact/client.ts +++ b/samples/client/lit/contact/client.ts @@ -32,6 +32,11 @@ type A2AServerPayload = import { componentRegistry } from "@a2ui/lit/ui"; +export interface A2UIClientResponse { + messages: v0_8.Types.ServerToClientMessage[]; + fallbackText: string | null; +} + export class A2UIClient { #ready: Promise = Promise.resolve(); get ready() { @@ -40,7 +45,7 @@ export class A2UIClient { async send( message: v0_8.Types.A2UIClientEventMessage - ): Promise { + ): Promise { const catalog = componentRegistry.getInlineCatalog(); const finalMessage = { ...message, @@ -59,15 +64,24 @@ export class A2UIClient { if (response.ok) { const data = (await response.json()) as A2AServerPayload; const messages: v0_8.Types.ServerToClientMessage[] = []; + const textParts: string[] = []; if ("error" in data) { throw new Error(data.error); } else { for (const item of data) { - if (item.kind === "text") continue; - messages.push(item.data); + if (item.kind === "text") { + textParts.push(item.text); + } else { + messages.push(item.data); + } } } - return messages; + return { + messages, + fallbackText: messages.length === 0 && textParts.length > 0 + ? textParts.join('\n') + : null, + }; } const error = (await response.json()) as { error: string }; diff --git a/samples/client/lit/contact/contact.ts b/samples/client/lit/contact/contact.ts index f90ebd494..1a496d975 100644 --- a/samples/client/lit/contact/contact.ts +++ b/samples/client/lit/contact/contact.ts @@ -26,7 +26,7 @@ import { } from "lit"; import { customElement, state } from "lit/decorators.js"; import { theme as uiTheme } from "./theme/theme.js"; -import { A2UIClient } from "./client.js"; +import { A2UIClient, type A2UIClientResponse } from "./client.js"; import { SnackbarAction, SnackbarMessage, @@ -369,9 +369,11 @@ export class A2UIContactFinder extends SignalWatcher(LitElement) { async #sendAndProcessMessage(request: v0_8.Types.A2UIClientEventMessage) { this.#requesting = true; - const messages = await this.#sendMessage(request); + this.#error = null; + const { messages, fallbackText } = await this.#sendMessage(request); this.#lastMessages = messages; + this.#error = fallbackText; // this.#processor.clearSurfaces(); // Removed to allow partial updates this.#processor.processMessages(messages); @@ -385,7 +387,7 @@ export class A2UIContactFinder extends SignalWatcher(LitElement) { async #sendMessage( message: v0_8.Types.A2UIClientEventMessage - ): Promise { + ): Promise { try { this.#requesting = true; const response = await this.#a2uiClient.send(message); @@ -399,7 +401,7 @@ export class A2UIContactFinder extends SignalWatcher(LitElement) { this.#requesting = false; } - return []; + return { messages: [], fallbackText: null }; } snackbar( diff --git a/samples/client/lit/shell/app.ts b/samples/client/lit/shell/app.ts index 34e1855b8..471c92d12 100644 --- a/samples/client/lit/shell/app.ts +++ b/samples/client/lit/shell/app.ts @@ -26,7 +26,7 @@ import { } from "lit"; import { customElement, state } from "lit/decorators.js"; import { theme as uiTheme } from "./theme/default-theme.js"; -import { A2UIClient } from "./client.js"; +import { A2UIClient, type A2UIClientResponse } from "./client.js"; import { SnackbarAction, SnackbarMessage, @@ -407,12 +407,11 @@ export class A2UILayoutEditor extends SignalWatcher(LitElement) { async #sendMessage( message: v0_8.Types.A2UIClientEventMessage - ): Promise { + ): Promise { try { this.#requesting = true; this.#startLoadingAnimation(); - const response = this.#a2uiClient.send(message); - await response; + const response = await this.#a2uiClient.send(message); this.#requesting = false; this.#stopLoadingAnimation(); @@ -424,7 +423,7 @@ export class A2UILayoutEditor extends SignalWatcher(LitElement) { this.#stopLoadingAnimation(); } - return []; + return { messages: [], fallbackText: null }; } #maybeRenderData() { @@ -511,11 +510,13 @@ export class A2UILayoutEditor extends SignalWatcher(LitElement) { } async #sendAndProcessMessage(request) { - const messages = await this.#sendMessage(request); + this.#error = null; + const { messages, fallbackText } = await this.#sendMessage(request); console.log(messages); this.#lastMessages = messages; + this.#error = fallbackText; this.#processor.clearSurfaces(); this.#processor.processMessages(messages); } diff --git a/samples/client/lit/shell/client.ts b/samples/client/lit/shell/client.ts index 165da4df4..e8c8e6935 100644 --- a/samples/client/lit/shell/client.ts +++ b/samples/client/lit/shell/client.ts @@ -20,6 +20,11 @@ import { v0_8 } from "@a2ui/lit"; const A2UI_MIME_TYPE = "application/json+a2ui"; +export interface A2UIClientResponse { + messages: v0_8.Types.ServerToClientMessage[]; + fallbackText: string | null; +} + export class A2UIClient { #serverUrl: string; #client: A2AClient | null = null; @@ -54,7 +59,7 @@ export class A2UIClient { async send( message: v0_8.Types.A2UIClientEventMessage | string - ): Promise { + ): Promise { const client = await this.#getClient(); let parts: Part[] = []; @@ -99,14 +104,22 @@ export class A2UIClient { const result = (response as SendMessageSuccessResponse).result as Task; if (result.kind === "task" && result.status.message?.parts) { const messages: v0_8.Types.ServerToClientMessage[] = []; + const textParts: string[] = []; for (const part of result.status.message.parts) { if (part.kind === 'data') { messages.push(part.data as v0_8.Types.ServerToClientMessage); + } else if (part.kind === 'text') { + textParts.push(part.text); } } - return messages; + return { + messages, + fallbackText: messages.length === 0 && textParts.length > 0 + ? textParts.join('\n') + : null, + }; } - return []; + return { messages: [], fallbackText: null }; } }