Validates the nimschatwidget package — embeddable nim chat for any NimsForest surface.
webhook_url configured in the embedding app's config// Minimal integration in any NimsForest app:
source := nimschatwidget.NewSource(webhookURL, "myapp")
songbird := nimschatwidget.NewSongbird(wind)
songbird.Start()
mux.Handle("/admin/chat/", http.StripPrefix("/admin/chat", nimschatwidget.Handler(source, songbird)))
Verify: app starts without errors, logs show Catching leaves on subject: song.nimschatwidget.>
# Serves JS content
curl -s https://<app>/admin/chat/widget | head -c 30
# Expected: (function() {
curl -s https://<app>/admin/chat/nims | python3 -m json.tool | head -5
# Expected: JSON array of {name, role} objects
curl -s -X POST -H "Content-Type: application/json" \
-d '{"session_id":"test-1","target_nim":"nimble","text":"hello","context":"Test context"}' \
https://<app>/admin/chat/send
# Expected: {"status":"ok"}
# In terminal 1: listen for events
curl -s -N "https://<app>/admin/chat/events?session=test-1"
# In terminal 2: send a message
curl -s -X POST -H "Content-Type: application/json" \
-d '{"session_id":"test-1","target_nim":"nimble","text":"say hello","context":""}' \
https://<app>/admin/chat/send
# Expected in terminal 1: data: {"text":"...","source":"nimble"}
curl -s -X POST -H "Content-Type: application/json" \
-d '{"session_id":"ctx-test","target_nim":"nimble","text":"what context do you see?","context":"Issue #42: Fix login bug\nStatus: open\nPriority: high"}' \
https://<app>/admin/chat/send
# Listen for response:
timeout 60 curl -s -N "https://<app>/admin/chat/events?session=ctx-test"
# Expected: nim response should reference Issue #42 / login bug
The widget should match nimsforestwebchat's design:
| Element | Expected | |---------|----------| | User bubble | #DCF5DB background, #1E3A1C text, rounded with small bottom-right corner | | Nim bubble | White background, #6B5B4E text, 1px #EDE9E5 border, small bottom-left corner | | Body font | Georgia, "Source Serif 4", serif | | UI font | Inter, DM Sans, system sans-serif | | Send button | 40px circle, #4AA847 green, white arrow SVG | | Input | #F0F3ED background, #E2DDD8 border, 12px radius | | Typing indicator | 3 bouncing dots, #A8D5A2 color, 1.4s animation | | Message area | #F8FAF5 background | | Header | White background, #EDE9E5 bottom border |
Full message flow to verify end-to-end:
Widget POST /send
-> Source POST to forest webhook (http://46.225.164.179:8081/webhooks/chatwidget)
-> River (river.chat.widget)
-> Tree (message-chat) — parses, sets reply_subject=song.nimschatwidget.{session}
-> message.incoming
-> TreeHouse (message_router.lua) — routes to message.{target_nim}
-> Nim (renders prompt with {{.context}})
-> AgentBrain -> agent.work.ai.nimble.chat -> agentclaudecode
-> Result -> Nim publishes to song.nimschatwidget.{session}
-> Songbird catches -> chirps via SSE -> Widget displays