Skip to content
言語機能

生成的UI

テーブル、チャート、フォーム、差分比較など、リッチでインタラクティブなコンポーネントをインラインでレンダリングするエージェント — テキストだけではありません。フロントエンドコードは不要です。

組み込み
11コンポーネント
カスタム拡張可能

テキストを超えて

従来のチャットボットUIはすべてをテキストバブルとしてレンダリングします。しかし、エージェントはクエリ結果、バリデーションレポート、デプロイメントステータス、比較差分といった構造化データを生成します。これらすべてをmarkdownとしてレンダリングするのは貧しい体験です。

Hailaの生成的UIは、ツールが出力の表示方法を宣言的に制御できるようにします。データベースクエリはテーブルとしてレンダリングされます。バリデーション結果はステータスカードとしてレンダリングされます。デプロイメントパイプラインはプログレストラッカーとしてレンダリングされます。すべてチャット内にインラインで、フロントエンドコードを書くことなく実現します。

仕組み

ツールは ui モジュールを使用してUIコンポーネントを返します。ランタイムはすべての結果に対して2つの処理を行います:

ユーザー向け
リッチコンポーネント
ARPプロトコル経由でフロントエンドにストリーミングされ、インタラクティブなテーブル、カード、チャート、またはフォームとしてレンダリングされます。
エージェント向け
テキストサマリー
コンパクトなテキスト表現がLLMに送信され、データについて推論して次のステップを決定できるようにします。

どちらのパスも犠牲にしません。ユーザーは美しいテーブルを見て、エージェントは構造化データを受け取ります。

例 — UI出力を持つツール
haira
import "ui"

tool query_database(query: string) -> any {
    """Executes a SQL query and displays results."""
    rows, err = postgres.query(db, query)
    if err != nil {
        return ui.status_card("error", "Query Failed", conv.to_string(err))
    }
    return ui.table("Query Results", headers, rows)
}

1行でエージェントのUIを有効化できます:

haira
agent DataExplorer {
    provider: OpenAI
    tools: [query_database, search_data]
    ui: ui
    memory: conversation(max_turns: 30)
}

11の組み込みコンポーネント

status-card
折りたたみセクション付きの成功・エラー・警告結果カード
table
タブとスティッキーヘッダー付きの検索・スクロール可能なデータテーブル
code-block
コピーボタンと複数タブ付きのシンタックスハイライトコード表示
diff
シンタックスハイライト付きの変更前後の並列比較
key-value
メタデータ表示のためのスタイル付き値を持つプロパティリスト
progress
ステップごとのステータスを持つマルチステップパイプラインのトラッカー
chart
折れ線、棒、円、面積、散布図のデータビジュアライゼーション
form
テキスト、セレクト、チェックボックス、テキストエリアフィールドを持つインタラクティブフォーム
confirm
破壊的な操作のためのはい/いいえ確認ダイアログ
choices
ユーザー選択のためのボタンまたはリスト形式のオプションピッカー
product-cards
eコマースおよびカタログ表示のための画像カードグリッド
使用方法
haira
import "ui"

ui.status_card("success", "Deploy Complete", "All 3 services updated")
ui.table("Results", ["Name", "Email"], [["Alice", "a@co"], ["Bob", "b@co"]])
ui.key_value("Server Info", {"Region": "us-east-1", "Status": "healthy"})
ui.chart("bar", "Revenue", ["Q1", "Q2", "Q3", "Q4"], [dataset])
ui.confirm("Delete this record?", "Yes, delete", "Cancel")
ui.group(
    ui.status_card("success", "Query Complete", "42 rows"),
    ui.table("Results", headers, rows)
)

自動生成されるWeb UI

すべてのHairaワークフローは自動的にWeb UIを取得します。ワークフローを定義するだけで、Hairaがフォームを生成します:

haira
@webui(title: "File Summarizer", description: "Upload a file and get an AI summary")
@post("/summarize")
workflow Summarize(document: file, context: string) -> { summary: string } {
    content, err = io.read_file(document)
    if err != nil { return { summary: "Failed to read file." } }
    reply, err = Summarizer.ask("Summarize: ${content}")
    if err != nil { return { summary: "AI error." } }
    return { summary: reply }
}

@webui デコレーターはタイトルと説明を設定します。file パラメーターはアップロード入力としてレンダリングされます。ストリーミングワークフロー(-> stream)は完全なチャットインターフェースを取得します。

ストリーミングチャットUI

ストリーミングワークフローは最も豊かな体験を提供します — リアルタイムのトークンストリーミング、ツール実行カード、インラインUIコンポーネント:

haira
@webhook("/chat")
workflow Chat(message: string, session_id: string) -> stream {
    return Assistant.stream(message, session: session_id)
}

fn main() {
    http.Server([Chat]).listen(8080)
}

チャットUIはARPプロトコル経由で通信します — WebSocketまたはSSEを通じてテキストデルタ、ツールライフサイクルイベント、リッチコンポーネントレンダリングを処理します。

カスタムコンポーネント

ドメイン固有のニーズのために、TypeScript Webコンポーネントを components/ ディレクトリに配置します:

components/gantt-chart.ts
typescript
export class HairaGanttChart extends HTMLElement {
  connectedCallback() {
    this.attachShadow({ mode: "open" });
  }
  setProps(props) {
    // Render your custom UI
  }
}

export default {
  tag: "haira-gantt-chart",
  component: HairaGanttChart,
};

カスタムコンポーネントはCSSカスタムプロパティ経由でHairaのテーマを継承し、チャットメッセージになる haira-action イベントをディスパッチできます。コンパイラはビルド時にそれらを検出し、バンドルして埋め込みます。

パイプライン

1
ツール
ui.* 関数を通じて型付きデータを返す
2
ランタイム
WebSocketまたはSSEを通じてARPメッセージを送出
3
フロントエンド
チャット内に一致するコンポーネントをインラインでレンダリング

フロントエンドリポジトリは別途不要。維持すべきAPIクライアントも不要。インストールすべきコンポーネントライブラリも不要。1つの .haira ファイル、1つのバイナリ、完全なUI。

Released under the Apache-2.0 License.