mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-18 11:06:19 +00:00
feat: improve jtbd agent support (#202)
* feat: termination condition * chore: minor url change * feat: added support for install id in the frontend * fix: pass experiment id from frontend * chore: remove excessive comments per CLAUDE.md guidelines Co-authored-by: Felarof <felarof99@users.noreply.github.com> * fix: add route to survey * fix: pass install id correctly * fix: url --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Felarof <felarof99@users.noreply.github.com>
This commit is contained in:
@@ -9,12 +9,22 @@ import { LlmHubPage } from './llm-hub/LlmHubPage'
|
||||
import { MCPSettingsPage } from './mcp-settings/MCPSettingsPage'
|
||||
import { ScheduledTasksPage } from './scheduled-tasks/ScheduledTasksPage'
|
||||
|
||||
// Check query params for direct page navigation
|
||||
function getInitialRoute(): string {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
const page = params.get('page')
|
||||
if (page === 'survey') return '/jtbd-agent'
|
||||
return '/ai'
|
||||
}
|
||||
|
||||
export const App: FC = () => {
|
||||
const initialRoute = getInitialRoute()
|
||||
|
||||
return (
|
||||
<HashRouter>
|
||||
<Routes>
|
||||
<Route element={<DashboardLayout />}>
|
||||
<Route index element={<Navigate to="/ai" replace />} />
|
||||
<Route index element={<Navigate to={initialRoute} replace />} />
|
||||
<Route path="ai" element={<AISettingsPage key="ai" />} />
|
||||
<Route path="chat" element={<LlmHubPage />} />
|
||||
<Route path="search" element={null} />
|
||||
|
||||
@@ -1,7 +1,22 @@
|
||||
import { useRef, useState } from 'react'
|
||||
import { getBrowserOSAdapter } from '@/lib/browseros/adapter'
|
||||
import { BROWSEROS_PREFS } from '@/lib/browseros/prefs'
|
||||
|
||||
const JTBD_API_URL = 'https://jtbd-agent.fly.dev'
|
||||
const DOMAIN = 'browseros'
|
||||
const JTBD_API_URL = 'https://jtbd-agent.fly.dev' // 'http://localhost:3001'
|
||||
const EXPERIMENT_ID = 'jtbd_jan26'
|
||||
|
||||
async function getInstallId(): Promise<string> {
|
||||
try {
|
||||
const adapter = getBrowserOSAdapter()
|
||||
const pref = await adapter.getPref(BROWSEROS_PREFS.INSTALL_ID)
|
||||
if (pref?.value) {
|
||||
return String(pref.value)
|
||||
}
|
||||
} catch {
|
||||
// BrowserOS API not available
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
export type Message = {
|
||||
id: string
|
||||
@@ -11,6 +26,8 @@ export type Message = {
|
||||
|
||||
export type Phase = 'idle' | 'active' | 'completed' | 'error'
|
||||
|
||||
const INTERVIEW_COMPLETE_MARKER = '__INTERVIEW_COMPLETE__'
|
||||
|
||||
async function* streamSSE(
|
||||
response: Response,
|
||||
): AsyncGenerator<string, void, unknown> {
|
||||
@@ -38,6 +55,8 @@ async function* streamSSE(
|
||||
const event = JSON.parse(data)
|
||||
if (event.type === 'text-delta' && event.delta) {
|
||||
yield event.delta
|
||||
} else if (event.type === 'interview_complete') {
|
||||
yield INTERVIEW_COMPLETE_MARKER
|
||||
} else if (event.type === 'error' && event.errorText) {
|
||||
throw new Error(event.errorText)
|
||||
}
|
||||
@@ -91,10 +110,11 @@ export function useJTBDAgentChat() {
|
||||
abortControllerRef.current = new AbortController()
|
||||
|
||||
try {
|
||||
const installId = await getInstallId()
|
||||
const response = await fetch(`${JTBD_API_URL}/api/interview/start`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ domain: DOMAIN }),
|
||||
body: JSON.stringify({ installId, experimentId: EXPERIMENT_ID }),
|
||||
signal: abortControllerRef.current.signal,
|
||||
})
|
||||
|
||||
@@ -158,15 +178,18 @@ export function useJTBDAgentChat() {
|
||||
}
|
||||
|
||||
let accumulated = ''
|
||||
let isComplete = false
|
||||
|
||||
for await (const chunk of streamSSE(response)) {
|
||||
if (chunk === INTERVIEW_COMPLETE_MARKER) {
|
||||
isComplete = true
|
||||
continue
|
||||
}
|
||||
accumulated += chunk
|
||||
updateLastMessage(accumulated)
|
||||
}
|
||||
|
||||
if (
|
||||
accumulated.toLowerCase().includes('thank you') &&
|
||||
accumulated.toLowerCase().includes('valuable insights')
|
||||
) {
|
||||
if (isComplete) {
|
||||
setPhase('completed')
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -9,4 +9,5 @@ export const BROWSEROS_PREFS = {
|
||||
SHOW_LLM_CHAT: 'browseros.show_llm_chat',
|
||||
SHOW_LLM_HUB: 'browseros.show_llm_hub',
|
||||
SHOW_TOOLBAR_LABELS: 'browseros.show_toolbar_labels',
|
||||
INSTALL_ID: 'browseros.metrics_install_id',
|
||||
} as const
|
||||
|
||||
@@ -42,5 +42,6 @@ export default defineWebExtConfig({
|
||||
},
|
||||
}),
|
||||
chromiumArgs,
|
||||
startUrls: ['chrome://newtab'],
|
||||
disabled: !useBrowserOS,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user