A Laravel + Livewire wedding-planning app. Couples can manage their wedding, browse a vendor directory, send inquiries to vendors, and chat with an AI assistant that helps them brainstorm.
Your job at the hackathon: build that AI assistant.
Everything around the agent is already wired up β the chat UI, the message
storage, the vendor directory with embeddings β but the agent itself has been
removed. You'll write it from scratch using laravel/ai.
- π Auth (Laravel Fortify), wedding management, guests, etc.
- πͺ Vendor directory with services, prices, categories.
- π§ Vendor service embeddings β every
VendorServicehas anembeddingcolumn populated automatically viaApp\Observers\VendorServiceObserverso you can do semantic search out of the box. - π¬ AI chat UI (Livewire) β sidebar, message bubbles, conversation history.
See
app/Livewire/Weddings/AiChats.phpandresources/views/livewire/weddings/ai-chats.blade.php. - ποΈ Persistent conversations β
AgentConversation+AgentConversationMessagemodels are managed bylaravel/ai'sRemembersConversationstrait. You don't need to write any persistence code. - π¨ A "suggested inquiry" card already renders in the chat when the agent emits
a tool call named
suggest_inquiry. Seeapp/Models/AgentConversationMessage::inquirySuggestions()andresources/views/components/ai-chat/message-bubble.blade.php.
Two files, both deleted on purpose:
A conversational agent that helps the couple plan their wedding. It should:
- Implement
Laravel\Ai\Contracts\Agent,Conversational, andHasTools. - Use the
PromptableandRemembersConversationstraits. - Accept the
Weddingin its constructor so it can personalize replies (title, event date, etc.). - Expose two tools:
SimilaritySearch(built into laravel/ai) overApp\Models\VendorServiceon theembeddingcolumn. This lets the LLM search the vendor directory by natural language ("warm cinematic photographer", "wild foraged florist Berlin", β¦).- A custom
suggest_inquirytool (see below) that drafts a vendor inquiry the couple can review.
A custom tool that drafts an inquiry to a vendor. It should:
- Implement
Laravel\Ai\Contracts\Tool. - Be named exactly
suggest_inquiryβ the UI already looks for that name and will render a styled "Suggested inquiry" card when the agent calls it. - Accept arguments roughly like:
service_category(string, required),subject(string, required),body(string, required),budget(number, optional). - Return a short confirmation string from
handle().
Open app/Actions/Wedding/AiChat/SendChatMessage.php β there's a throw in
there marking the spot. Replace it with something like:
(new WeddingPlannerAgent($chat->wedding))
->continue($chat->conversation_id, as: $user)
->prompt($body);Then open a wedding and switch to the AI chats tab
(/weddings/{wedding}?tab=ai-chats), start a chat, and try it.
Pick whichever sounds fun:
- π― Actually create the inquiry. Right now
suggest_inquiryonly drafts a card. Add a button on the card that POSTs to a new action and creates a realInquiryrecord for a chosen vendor. - π οΈ More tools. A budget-summary tool, a guest-count tool, a timeline tool, a "set the wedding date" tool, β¦
- π Streaming responses.
laravel/aiagents support streaming β wire it to Livewire so tokens appear as they're generated. - π Locale-aware replies. The agent should answer in the user's locale.
- π§ͺ Tests. Pest 4 is set up β write feature tests for the agent's behavior (laravel/ai has a fake driver, see the docs).
- π¨ Better cards. Show matching vendors inline when
SimilaritySearchreturns results, not just the inquiry suggestion.
- PHP 8.4+ (the project targets PHP 8.5 features where possible)
- Composer 2
- Node 20+ and npm
- PostgreSQL 15+ running on
127.0.0.1:5432β Laravel Herd Pro bundles it; otherwise install viabrew install postgresql@17or your package manager. Defaults in.env.exampleassume userrootwith no password (Herd's default). - An API key for at least one LLM provider β OpenAI is the default for chat and embeddings, so it's the easiest starting point.
No PHP installed? Skip to the Sail section below β you only need Docker.
composer install
npm install
cp .env.example .env
php artisan key:generate
createdb -h 127.0.0.1 -U root meetup_wedding_planner # one-time
# Add your OPENAI_API_KEY to .env first β the seeder generates real
# embeddings for each vendor service (a few cents of API cost).
php artisan migrate --seed
composer run dev # serves the app + queue + vite + live logs via pailThe seeder creates a demo user:
- Email:
test@example.com - Password:
password
A sample wedding, vendors, and inquiries are seeded too β log in and you'll see a wedding ready to chat about.
Put your key in .env:
OPENAI_API_KEY=sk-...config/ai.php defaults to OpenAI for chat, Gemini for embeddings, and
Gemini for images. For the hackathon we recommend a cheap fast model β set
it on the agent or via config, e.g. gpt-4o-mini or gpt-5-mini. You don't
need a frontier model to demo this.
Want a different provider? Edit config/ai.php β laravel/ai supports Anthropic,
Gemini, Azure, Groq, xAI, DeepSeek, Mistral, Ollama, Cohere, and more. If you
swap embeddings to a provider whose dimensions differ from the current one,
you'll need to re-seed the vendor services so embeddings match.
Gemini's free tier is sufficient to run both embeddings (VendorServiceObserver)
and chat (WeddingPlannerAgent) without an OpenAI key.
1. Generate an API key at https://aistudio.google.com/app/apikey.
2. Set it in .env:
GEMINI_API_KEY=AIza...3. Embeddings. config/ai.php already sets default_for_embeddings to
gemini, using gemini-embedding-001 at 768 dimensions. Override via env if
needed:
GEMINI_EMBEDDINGS_MODEL=gemini-embedding-001
GEMINI_EMBEDDINGS_DIMENSIONS=768If the vendor_services.embedding column was previously populated with a
different dimension (e.g. OpenAI's 1536), re-seed:
php artisan db:seed --class=VendorSeeder4. Chat model. Point the agent at gemini-2.5-flash (supports tool calls
and is on the free tier):
class WeddingPlannerAgent implements Agent, Conversational, HasTools
{
use Promptable, RemembersConversations;
public function provider(): string
{
return 'gemini';
}
public function model(): string
{
return 'gemini-2.5-flash';
}
// ...
}Alternatively, set 'default' => 'gemini' in config/ai.php to route all chat
calls through Gemini globally.
The app is served by Laravel Herd at
http://meetup-wedding-planner.test if you have Herd installed. Otherwise
php artisan serve (run for you by composer run dev) works on :8000.
If you don't have PHP / Composer / Postgres locally, you can run everything in Docker via Laravel Sail. You only need Docker installed.
1. Bootstrap vendor/ without local PHP (skip if you already ran
composer install):
docker run --rm -u "$(id -u):$(id -g)" \
-v "$(pwd):/var/www/html" -w /var/www/html \
laravelsail/php85-composer:latest \
composer install --ignore-platform-reqs2. Copy and tweak .env β Sail provides its own Postgres + Mailpit in
compose.yaml, and the laravel container overrides DB_HOST, DB_USERNAME,
DB_PASSWORD, MAIL_MAILER, MAIL_HOST, MAIL_PORT automatically, so the
only things you need to set yourself are:
APP_URL=http://localhost
DB_CONNECTION=pgsql
DB_DATABASE=meetup_wedding_planner
OPENAI_API_KEY=sk-...Sail's Postgres is forwarded to host port 5433 (not 5432) to avoid clashing with a Herd/host Postgres. Inside the container the app still uses the
pgsqlservice hostname on 5432.
3. Bring it up:
./vendor/bin/sail up -d
./vendor/bin/sail artisan key:generate
./vendor/bin/sail artisan migrate --seed
./vendor/bin/sail npm install
./vendor/bin/sail npm run devThe app is at http://localhost. Mailpit dashboard is at
http://localhost:8025. Add alias sail='./vendor/bin/sail' to save typing.
The seeder creates vendor services and App\Observers\VendorServiceObserver
fills in embeddings automatically on save. If you change embedding logic or
switch providers, re-seed:
php artisan db:seed --class=VendorSeeder- Live logs:
composer run devalready runsphp artisan pailβ watch the terminal pane for LLM errors, validation failures, queued job output. - Browser console: Livewire surfaces errors in the browser dev tools.
- Tinker:
php artisan tinkerto poke atWedding,VendorService,AgentConversation, etc. - Stuck? The previous working implementation is in git history β see
git log -- app/Ai(specifically commitaab75d5) for a reference. Try not to peek too early though, that's where the fun is. π
Everything you'll need:
- Repo & README: https://github.com/laravel/ai
- Agents: https://github.com/laravel/ai#agents β the
Agent,Conversational,HasToolscontracts;PromptableandRemembersConversationstraits. - Tools: https://github.com/laravel/ai#tools β implementing
Tool, schemas withJsonSchema, request handling. - SimilaritySearch: built-in tool β see the docs section on vector search & embeddings.
- Conversations: https://github.com/laravel/ai#conversations β
->continue(),->prompt(), persisting messages. - Streaming, structured output, multi-modal, queueing, broadcasting are all in the same README.
You can also use the Laravel Boost MCP search-docs tool from inside your
editor β it returns version-pinned docs for the exact packages installed.
- Livewire 4: https://livewire.laravel.com
- Flux UI: https://fluxui.dev β the component library used in the chat UI
(
<flux:button>,<flux:textarea>,<flux:icon.sparkles>, β¦). - Laravel 13: https://laravel.com/docs/13.x
- Laravel Fortify: https://laravel.com/docs/13.x/fortify
- Pest 4: https://pestphp.com/docs β testing.
- Tailwind CSS v4: https://tailwindcss.com/docs
- OpenAI: https://platform.openai.com/docs
- Anthropic Claude: https://docs.anthropic.com
- Google Gemini: https://ai.google.dev/docs
- Ollama (local): https://ollama.com
app/
βββ Actions/Wedding/AiChat/
β βββ CreateAiChat.php # creates a new chat + conversation
β βββ SendChatMessage.php # π wire your agent in here
βββ Ai/ # π you create this folder
β βββ Agents/
β β βββ WeddingPlannerAgent.php
β βββ Tools/
β βββ SuggestInquiryTool.php
βββ Livewire/Weddings/
β βββ AiChats.php # the chat Livewire component
βββ Models/
β βββ AgentConversation.php # managed by laravel/ai (RemembersConversations)
β βββ AgentConversationMessage.php
β βββ WeddingAiChat.php # thin join: Wedding β AgentConversation
β βββ Wedding.php
β βββ Vendor.php
β βββ VendorService.php # has `embedding` column
β βββ Inquiry.php
βββ Observers/
βββ VendorServiceObserver.php # auto-embeds services on save
resources/views/
βββ components/ai-chat/
β βββ message-bubble.blade.php # renders messages + suggested-inquiry cards
βββ livewire/weddings/
βββ ai-chats.blade.php
Happy hacking! πβ¨