rmh/laravel-openui 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

rmh/laravel-openui

Composer 安装命令:

composer require rmh/laravel-openui

包简介

OpenUI Generative UI integration for the Laravel AI SDK - inject OpenUI Lang system prompts, define component libraries, and stream structured UI responses.

README 文档

README

Latest Version on Packagist Tests License

OpenUI Generative UI integration for the Laravel AI SDK.

This package connects OpenUI — the open standard for Generative UI — with the Laravel AI SDK. It handles system prompt injection, component library management, caching, and streaming, so your agents can respond with structured, interactive UI instead of plain text.

How It Works

OpenUI works in four steps:

Component Library → System Prompt → LLM → OpenUI Lang → Frontend Renderer
  1. You define which React components the LLM is allowed to generate.
  2. This package injects a system prompt into your agent's instructions describing those components and the OpenUI Lang syntax.
  3. The LLM responds in OpenUI Lang (a compact, streaming-native format).
  4. Your frontend's <Renderer /> from @openuidev/react-lang parses and renders it live.

Installation

composer require rmh/laravel-openui

Publish the config file:

php artisan vendor:publish --tag=openui

Quick Start

Option 1: Global Middleware (zero-touch, all agents)

Register the middleware once in your AppServiceProvider and every agent will automatically receive the OpenUI system prompt:

// app/Providers/AppServiceProvider.php

use RMH\OpenUI\Middleware\InjectOpenUIPrompt;
use Laravel\Ai\Facades\Ai;

public function boot(): void
{
    Ai::middleware([InjectOpenUIPrompt::class]);
}

Your agents need no changes. Stream the response back to your OpenUI frontend:

Route::post('/chat', function (Request $request) {
    return MyAgent::make()
        ->stream($request->input('message'))
        ->usingVercelDataProtocol();
});

Option 2: GeneratesUI Trait (explicit opt-in per agent)

Add the trait to agents that should produce UI. Rename instructions() to agentInstructions():

use RMH\OpenUI\Concerns\GeneratesUI;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Promptable;

class HotelSearchAgent implements Agent
{
    use Promptable, GeneratesUI;

    protected function agentInstructions(): string
    {
        return 'You are a helpful hotel search assistant.';
    }
}

Toggle UI per call:

// UI enabled (default)
HotelSearchAgent::make()->prompt('Find hotels in Paris');

// UI disabled for this call
HotelSearchAgent::make()->withoutUI()->prompt('Find hotels in Paris');

Option 3: Per-agent Middleware

Add the middleware only to specific agents:

use RMH\OpenUI\Middleware\InjectOpenUIPrompt;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\HasMiddleware;
use Laravel\Ai\Promptable;

class HotelSearchAgent implements Agent, HasMiddleware
{
    use Promptable;

    public function instructions(): string
    {
        return 'You are a helpful hotel search assistant.';
    }

    public function middleware(): array
    {
        return [new InjectOpenUIPrompt];
    }
}

Option 4: Anonymous Agents / Inline Calls

use RMH\OpenUI\Facades\OpenUI;
use function Laravel\Ai\{agent};

$response = agent(
    instructions: 'You are a travel assistant.' . "\n\n" . OpenUI::systemPrompt(),
)->prompt('Find hotels in Paris');

Defining Your Component Library

In config/openui.php

'components' => [
    'Card' => [
        'title'       => 'string',
        'description' => 'string?',   // ? = optional
        'imageUrl'    => 'string?',
        'ctaLabel'    => 'string?',
    ],
    'Carousel' => [
        'cards' => 'Card[]',           // nested component reference
    ],
    'Table' => [
        'columns' => 'array',
        'rows'    => 'array',
    ],
    'Alert' => [
        'type'    => 'enum:info|success|warning|error',
        'title'   => 'string',
        'message' => 'string?',
    ],
],

Supported prop types: string, int, float, bool, array, ComponentName[], enum:a|b|c. Append ? to mark any type as optional.

Via the Facade (programmatic / runtime)

use RMH\OpenUI\Facades\OpenUI;

// Register one component
OpenUI::component('PriceTag', [
    'amount'   => 'string',
    'currency' => 'string?',
]);

// Register many at once
OpenUI::library([
    'Chart'     => ['type' => 'enum:bar|line|pie', 'data' => 'array'],
    'MapPin'    => ['lat' => 'float', 'lng' => 'float', 'label' => 'string?'],
]);

The cache is automatically invalidated when you add components via the facade.

Via the Artisan Command

Scaffold a typed component definition class:

php artisan openui:component Card --props="title:string,description:string?,imageUrl:string?"

This generates app/Ai/OpenUI/Components/CardComponent.php. Register it in your service provider:

use RMH\OpenUI\Facades\OpenUI;
use App\Ai\OpenUI\Components\CardComponent;

OpenUI::component((new CardComponent)->name(), (new CardComponent)->props());

Export for Frontend

Export your component definitions to TypeScript/Zod for your frontend:

php artisan openui:export

This generates resources/js/openui.ts with Zod schemas:

// Auto-generated by laravel-openui
import { z } from 'zod';

export const CardSchema = z.object({
  title: z.string(),
  description: z.string().optional(),
  imageUrl: z.string().optional(),
});

export const openUISchema = z.object({
  Card: CardSchema,
});

Export options:

Option Description
--path=... Custom output path (default: resources/js/openui.ts)
--format=zod|ts|json Output format (default: zod)
--types TypeScript types only (shorthand for --format=ts)
--force Overwrite existing file

Examples:

# Export to custom path
php artisan openui:export --path=frontend/src/openui.ts

# Export TypeScript types only (no Zod)
php artisan openui:export --types

# Export as JSON
php artisan openui:export --format=json --path=schema.json

# Force overwrite
php artisan openui:export --force

Configuration Reference

// config/openui.php

'enabled'                => env('OPENUI_ENABLED', true),
'design_system'          => env('OPENUI_DESIGN_SYSTEM', 'shadcn'),
'stream_protocol'        => env('OPENUI_STREAM_PROTOCOL', 'vercel'),
'system_prompt_placement'=> 'append',  // 'append' | 'prepend'
'custom_system_prompt'   => null,      // override the entire generated prompt

'components' => [...],

'allowed_agents' => [],               // empty = all agents; list FQCN to restrict

'cache' => [
    'enabled' => env('OPENUI_CACHE_ENABLED', true),
    'store'   => env('OPENUI_CACHE_STORE', null),
    'ttl'     => env('OPENUI_CACHE_TTL', 3600),
],

Frontend Integration

Option 1: Use Exported Schema (Recommended)

Export your component definitions and import them directly:

php artisan openui:export

Then in your frontend:

import { Renderer, createLibrary, defineComponent } from '@openuidev/react-lang';
import { CardSchema, CarouselSchema } from './openui';
import { Card, Carousel } from './components';

const components = [
  defineComponent({
    name: 'Card',
    props: CardSchema,
    component: ({ props }) => <Card {...props} />,
  }),
  defineComponent({
    name: 'Carousel',
    props: CarouselSchema,
    component: ({ props }) => <Carousel {...props} />,
  }),
];

export const library = createLibrary({ root: 'Card', components });

<Renderer library={library} stream={streamFromLaravel} />

Option 2: Manual Schema Definition

Define schemas manually on the frontend:

import { Renderer, createLibrary, defineComponent } from '@openuidev/react-lang';
import { z } from 'zod';

const Card = defineComponent({
    name: 'Card',
    props: z.object({
        title: z.string(),
        description: z.string().optional(),
        imageUrl: z.string().optional(),
        ctaLabel: z.string().optional(),
    }),
    component: ({ props }) => <YourCardComponent {...props} />,
});

export const library = createLibrary({ root: 'Card', components: [Card] });

<Renderer library={library} stream={streamFromLaravel} />

Inspecting the Generated System Prompt

use RMH\OpenUI\Facades\OpenUI;

// View what's being injected
dd(OpenUI::systemPrompt());

// Flush and regenerate
OpenUI::flushCache();

Testing

When writing tests for agents that use OpenUI, you can temporarily disable injection:

config(['openui.enabled' => false]);

Or assert on the generated prompt:

use RMH\OpenUI\Facades\OpenUI;

$this->assertStringContainsString('Card', OpenUI::systemPrompt());

Changelog

Please see CHANGELOG.md.

License

MIT — see LICENSE.md.

rmh/laravel-openui 适用场景与选型建议

rmh/laravel-openui 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 1, 最近一次更新时间为 2026 年 03 月 13 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「streaming」 「laravel」 「Agent」 「ai」 「laravel-ai」 「openui」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 rmh/laravel-openui 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 rmh/laravel-openui 我们能提供哪些服务?
定制开发 / 二次开发

基于 rmh/laravel-openui 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 33
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-03-13