Skip to content

Commit 80f761b

Browse files
committed
feat: add OpenUI integration
1 parent 15e372f commit 80f761b

30 files changed

Lines changed: 1953 additions & 37 deletions

.yarnrc.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
nmHoistingLimits: workspaces
22
nodeLinker: node-modules
33
checksumBehavior: update
4+
5+
# OpenUI only uses Zustand APIs retained in v5, and its integration tests run
6+
# against Jan's Zustand 5. Keep this narrow filter until upstream widens ^4.5.5.
7+
logFilters:
8+
- pattern: "zustand is listed by your project with version 5.0.3*"
9+
level: discard

web-app/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
"@dnd-kit/sortable": "10.0.0",
2525
"@janhq/core": "workspace:*",
2626
"@janhq/interfaces": "0.0.2",
27+
"@openuidev/react-headless": "^0.8.2",
28+
"@openuidev/react-lang": "^0.2.6",
29+
"@openuidev/react-ui": "^0.11.8",
2730
"@radix-ui/react-accordion": "1.2.11",
2831
"@radix-ui/react-avatar": "1.1.10",
2932
"@radix-ui/react-collapsible": "^1.1.12",

web-app/public/images/openui.svg

Lines changed: 10 additions & 0 deletions
Loading

web-app/src/constants/localStorage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const localStorageKey = {
2929
agentMode: 'agent-mode',
3030
latestJanModel: 'latest-jan-model',
3131
defaultEmbeddingModel: 'default-embedding-model',
32+
openUI: 'openui-settings',
3233
pausedDownloads: 'paused-downloads',
3334
}
3435

web-app/src/constants/routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const route = {
1616
extensions: '/settings/extensions',
1717
local_api_server: '/settings/local-api-server',
1818
mcp_servers: '/settings/mcp-servers',
19+
openui: '/settings/openui',
1920
https_proxy: '/settings/https-proxy',
2021
hardware: '/settings/hardware',
2122
assistant: '/settings/assistant',

web-app/src/containers/ChatInput.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ import {
7474
NEW_THREAD_ATTACHMENT_KEY,
7575
useChatAttachments,
7676
} from '@/hooks/useChatAttachments'
77+
import {
78+
OPENUI_CHAT_ACTION_EVENT,
79+
isOpenUIChatActionEvent,
80+
} from '@/lib/openui-actions'
7781

7882
import {
7983
Attachment,
@@ -466,6 +470,11 @@ const ChatInput = memo(function ChatInput({
466470
// processing is complete.
467471
}
468472
}
473+
const handleSendMessageRef = useRef(handleSendMessage)
474+
475+
useEffect(() => {
476+
handleSendMessageRef.current = handleSendMessage
477+
})
469478

470479
useEffect(() => {
471480
const handleFocusIn = () => {
@@ -1539,6 +1548,24 @@ const ChatInput = memo(function ChatInput({
15391548

15401549
const isStreaming = chatStatus === 'submitted' || chatStatus === 'streaming'
15411550

1551+
useEffect(() => {
1552+
const handleOpenUIAction = (event: Event) => {
1553+
if (!isOpenUIChatActionEvent(event)) return
1554+
1555+
const nextPrompt = event.detail.prompt.trim()
1556+
if (!nextPrompt) return
1557+
1558+
event.preventDefault()
1559+
handleSendMessageRef.current(nextPrompt)
1560+
}
1561+
1562+
window.addEventListener(OPENUI_CHAT_ACTION_EVENT, handleOpenUIAction)
1563+
1564+
return () => {
1565+
window.removeEventListener(OPENUI_CHAT_ACTION_EVENT, handleOpenUIAction)
1566+
}
1567+
}, [])
1568+
15421569
return (
15431570
<div className="relative">
15441571
<div className="relative">

web-app/src/containers/MessageItem.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
22
import { memo, useState, useCallback, useEffect } from 'react'
33
import type { UIMessage, ChatStatus } from 'ai'
4-
import { RenderMarkdown } from './RenderMarkdown'
4+
import { OpenUIResponse } from './OpenUIResponse'
55
import { cn } from '@/lib/utils'
66
import { twMerge } from 'tailwind-merge'
77
import {
@@ -276,7 +276,7 @@ export const MessageItem = memo(
276276
</div>
277277
) : (
278278
<>
279-
<RenderMarkdown
279+
<OpenUIResponse
280280
content={
281281
grounding && !isStreaming
282282
? injectCitationMarkers(

0 commit comments

Comments
 (0)