Skip to content

Commit c30c8f2

Browse files
authored
feat(ask-baml): some final cleanups (#2270)
- clean up unused code / sloppy vibe code, or try to - make state communication between search bar and chatbot less bug-prone (go through jotai for it all) - make state management for opening/closing the chatbot less bug-prome (again, go through jotai and rip out a bunch of intermediate state bridging/juggling) - add CLAUDE.md for ask-baml-client, to provide instructions about - scroll all the way down when opening the chatbot, instead of most of the way down (this was probably the "scrollIntoView" logic) - vertically align the chatbot message input and send button (customer called out the misalignment) - there were extra divs and sloppy flexbox management - feedback API calls are not triggering notion/slack calls - add an `after()` call which Vercel functions should understand <!-- ELLIPSIS_HIDDEN --> ---- > [!IMPORTANT] > Refactor state management and UI for chatbot and search bar, add architecture documentation, and improve feedback logging in `ask-baml-client`. > > - **State Management**: > - Refactor state communication between search bar and chatbot using `jotai` in `AlgoliaSearch.tsx` and `ChatBot.tsx`. > - Simplify chatbot open/close state management with `isChatbotOpenAtom` in `store.ts`. > - **UI Enhancements**: > - Align chatbot message input and send button vertically in `ChatBot.tsx`. > - Ensure chatbot scrolls to the bottom on open in `ChatBot.tsx`. > - Add `CLAUDE.md` for architecture instructions in `ask-baml-client`. > - **Backend**: > - Use `after()` for asynchronous feedback logging in `route.ts`. > - **Miscellaneous**: > - Remove unused code and improve code quality across multiple files. > - Fix minor UI issues and improve logging. > > <sup>This description was created by </sup>[<img alt="Ellipsis" src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=BoundaryML%2Fbaml&utm_source=github&utm_medium=referral)<sup> for ba82b12. You can [customize](https://app.ellipsis.dev/BoundaryML/settings/summaries) this summary. It will automatically update as commits are pushed.</sup> <!-- ELLIPSIS_HIDDEN -->
1 parent c011da0 commit c30c8f2

File tree

22 files changed

+1154
-288
lines changed

22 files changed

+1154
-288
lines changed

pnpm-lock.yaml

Lines changed: 55 additions & 28 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
This is a browser chat app written in TS, compiled into a JS snippet and injected on page load into docs.boundaryml.com.
2+
3+
- ChatBot is the chat interface
4+
- AssistantResponseFeedback manages feedback buttons and sends feedback to the backend
5+
6+
The backend code is in ../sage-backend, in the /api/ask-baml/ routes.
7+
8+
The RPC interface with the backend is defined in ../../packages/sage-interface.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
See CLAUDE.md for architecture description.
2+
3+
Remaining work items, in priority answer:
4+
5+
[ ] stream chatbot responses to the user
6+
[ ] search bar css is missing dark mode support (maybe integrate tailwind styles?)
7+
[ ] copy chat-sdk.dev’s UI https://chat-sdk.dev/
8+
[ ] want to allow edit-and-retry, for example
9+
(this is partially done, see packages/ui/chatbot)
10+
[ ] index headings of each document, to be able to suggest links to
11+
individual headings when suggesting destinations
12+
[ ] improve the underlying prompt
13+
[ ] standalone queries like "alias" or "type builder" sometimes result in
14+
"please provide a complete query" from the chatbot
15+
[ ] alias → how do i use alias with dynamic types (currently returns the
16+
wrong answer)
17+
[ ] what do if user is asking for code debugging help?
18+
[ ] instant search dropdown icons are wrong (needs to get
19+
propagated through sitemap/pinecone)

typescript/apps/ask-baml-client/src/AlgoliaSearch.tsx

Lines changed: 43 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
11
'use client';
22

33
import { liteClient as algoliasearch } from 'algoliasearch/lite';
4+
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
45
import type React from 'react';
56
import { useEffect, useRef, useState } from 'react';
67
import { Configure, InstantSearch, useHits, useSearchBox } from 'react-instantsearch';
78
import { z } from 'zod';
89
import BamlLambWhite from './baml-lamb-white.svg';
910
import { ALGOLIA_SEARCH_CREDENTIALS_ENDPOINT, ALGOLIA_SEARCH_INDEX_NAME } from './constants';
10-
11+
import { isChatbotOpenAtom, pendingQueryAtom } from './store';
12+
13+
const useChatbot = () => {
14+
const [pendingQuery, setPendingQuery] = useAtom(pendingQueryAtom);
15+
const [isChatbotOpen, setIsChatbotOpen] = useAtom(isChatbotOpenAtom);
16+
17+
return {
18+
pendingQuery,
19+
isChatbotOpen,
20+
openChatbotWithQuery: (query: string) => {
21+
setPendingQuery(query);
22+
setIsChatbotOpen(true);
23+
},
24+
};
25+
};
1126

1227
// Zod schema for API response validation
1328
const SearchCredentialsSchema = z.object({
@@ -459,28 +474,25 @@ function AskWithAIOption({
459474
}}
460475
>
461476
<AIIcon />
462-
Ask Baaaaml about "{query}"
477+
Ask Baaaml about "{query}"
463478
</div>
464479
</button>
465480
);
466481
}
467482

468483
// Custom SearchBox with integrated controls
469484
function CustomSearchBox({
470-
onAskAI,
471-
onToggleAI,
472-
isAIOpen,
485+
onToggleChatbot,
473486
}: {
474-
onAskAI: (query: string) => void;
475-
onToggleAI?: () => void;
476-
isAIOpen?: boolean;
487+
onToggleChatbot: () => void;
477488
}) {
478489
const { query, refine } = useSearchBox();
479490
const { hits } = useHits();
480491
const [inputValue, setInputValue] = useState(query);
481492
const [isFocused, setIsFocused] = useState(false);
482493
const [selectedIndex, setSelectedIndex] = useState(-1);
483494
const inputRef = useRef<HTMLInputElement>(null);
495+
const { isChatbotOpen, openChatbotWithQuery } = useChatbot();
484496

485497
useEffect(() => {
486498
setInputValue(query);
@@ -516,17 +528,11 @@ function CustomSearchBox({
516528
};
517529

518530
const handleAskAI = () => {
519-
onAskAI(inputValue);
531+
openChatbotWithQuery(inputValue);
520532
setIsFocused(false);
521533
};
522534

523-
const handleToggleAI = () => {
524-
if (onToggleAI) {
525-
onToggleAI();
526-
}
527-
};
528-
529-
// Calculate total selectable items: Ask Baaaaml option (when query exists) + search results
535+
// Calculate total selectable items: Ask Baaaml option (when query exists) + search results
530536
const totalSelectableItems = (inputValue.trim() ? 1 : 0) + hits.length;
531537

532538
const handleKeyDown = (e: React.KeyboardEvent) => {
@@ -541,7 +547,7 @@ function CustomSearchBox({
541547
} else if (e.key === 'Enter') {
542548
e.preventDefault();
543549
if (selectedIndex === 0 && inputValue.trim()) {
544-
// Ask Baaaaml option is selected
550+
// Ask Baaaml option is selected
545551
handleAskAI();
546552
} else if (selectedIndex > 0) {
547553
// A search result is selected
@@ -551,7 +557,7 @@ function CustomSearchBox({
551557
window.location.href = hit.pathname || hit.canonicalPathname || '#';
552558
}
553559
} else if (selectedIndex === -1 && inputValue.trim()) {
554-
// No selection, trigger Ask Baaaaml by default
560+
// No selection, trigger Ask Baaaml by default
555561
handleAskAI();
556562
}
557563
} else if (e.key === 'Escape') {
@@ -704,13 +710,13 @@ function CustomSearchBox({
704710
</div>
705711
)}
706712

707-
{/* Ask Baaaaml / Close button */}
713+
{/* Ask Baaaml / Close button */}
708714
<button
709715
type="button"
710-
onClick={handleToggleAI}
716+
onClick={onToggleChatbot}
711717
style={{
712718
padding: '6px 10px',
713-
background: isAIOpen ? '#6b7280' : '#7c3aed',
719+
background: isChatbotOpen ? '#6b7280' : '#7c3aed',
714720
border: 'none',
715721
borderRadius: '6px',
716722
color: 'white',
@@ -727,25 +733,25 @@ function CustomSearchBox({
727733
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.1)',
728734
}}
729735
onMouseEnter={(e) => {
730-
e.currentTarget.style.background = isAIOpen ? '#4b5563' : '#6d28d9';
736+
e.currentTarget.style.background = isChatbotOpen ? '#4b5563' : '#6d28d9';
731737
e.currentTarget.style.transform = 'translateY(-0.5px)';
732738
e.currentTarget.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.15)';
733739
}}
734740
onMouseLeave={(e) => {
735-
e.currentTarget.style.background = isAIOpen ? '#6b7280' : '#7c3aed';
741+
e.currentTarget.style.background = isChatbotOpen ? '#6b7280' : '#7c3aed';
736742
e.currentTarget.style.transform = 'translateY(0)';
737743
e.currentTarget.style.boxShadow = '0 1px 2px rgba(0, 0, 0, 0.1)';
738744
}}
739745
>
740-
{isAIOpen ? (
746+
{isChatbotOpen ? (
741747
<>
742748
<CloseIcon />
743749
Close
744750
</>
745751
) : (
746752
<>
747753
<AIIcon />
748-
Ask Baaaaml
754+
Ask Baaaml
749755
</>
750756
)}
751757
</button>
@@ -755,23 +761,23 @@ function CustomSearchBox({
755761
{/* Pass selectedIndex and handlers to hits */}
756762
<CustomHits
757763
selectedIndex={selectedIndex}
758-
onAskAI={() => handleAskAI()}
764+
onAskBaml={() => handleAskAI()}
759765
query={inputValue}
760766
isFocused={isFocused}
761767
/>
762768
</form>
763769
);
764770
}
765771

766-
// Custom Hits component with conditional visibility and Ask Baaaaml option
772+
// Custom Hits component with conditional visibility and Ask Baaaml option
767773
function CustomHits({
768774
selectedIndex,
769-
onAskAI,
775+
onAskBaml,
770776
query,
771777
isFocused,
772778
}: {
773779
selectedIndex?: number;
774-
onAskAI?: () => void;
780+
onAskBaml?: () => void;
775781
query?: string;
776782
isFocused?: boolean;
777783
}) {
@@ -804,8 +810,8 @@ function CustomHits({
804810
}}
805811
>
806812
{/* Ask with AI option */}
807-
{onAskAI && actualQuery.trim() && (
808-
<AskWithAIOption isSelected={selectedIndex === 0} onClick={onAskAI} query={actualQuery} />
813+
{onAskBaml && actualQuery.trim() && (
814+
<AskWithAIOption isSelected={selectedIndex === 0} onClick={onAskBaml} query={actualQuery} />
809815
)}
810816

811817
{/* Search results */}
@@ -827,10 +833,10 @@ function CustomHits({
827833
}}
828834
>
829835
<div style={{ marginBottom: '6px' }}>No results found for "{actualQuery}"</div>
830-
{onAskAI && (
836+
{onAskBaml && (
831837
<button
832838
type="button"
833-
onClick={onAskAI}
839+
onClick={onAskBaml}
834840
style={{
835841
color: '#6366f1',
836842
background: 'none',
@@ -841,7 +847,7 @@ function CustomHits({
841847
fontWeight: '500',
842848
}}
843849
>
844-
Ask Baaaaml about this instead
850+
Ask Baaaml about this instead
845851
</button>
846852
)}
847853
</div>
@@ -851,13 +857,9 @@ function CustomHits({
851857
}
852858

853859
export default function AlgoliaSearch({
854-
onAskAI,
855-
onToggleAI,
856-
isAIOpen,
860+
onToggleChatbot,
857861
}: {
858-
onAskAI?: (query: string) => void;
859-
onToggleAI?: () => void;
860-
isAIOpen?: boolean;
862+
onToggleChatbot: () => void;
861863
}) {
862864
const containerRef = useRef<HTMLDivElement>(null);
863865
const [searchClient, setSearchClient] = useState<any>(null);
@@ -894,18 +896,6 @@ export default function AlgoliaSearch({
894896
};
895897
}, []);
896898

897-
const handleAskAI = (query: string) => {
898-
if (onAskAI) {
899-
onAskAI(query);
900-
}
901-
};
902-
903-
const handleToggleAI = () => {
904-
if (onToggleAI) {
905-
onToggleAI();
906-
}
907-
};
908-
909899
if (isLoading) {
910900
return (
911901
<div style={{ position: 'relative', width: '100%' }}>
@@ -971,7 +961,7 @@ export default function AlgoliaSearch({
971961
analyticsTags={['desktop', 'docs.boundaryml.com', 'search-v3-enhanced']}
972962
/>
973963

974-
<CustomSearchBox onAskAI={handleAskAI} onToggleAI={handleToggleAI} isAIOpen={isAIOpen} />
964+
<CustomSearchBox onToggleChatbot={onToggleChatbot} />
975965
</InstantSearch>
976966
</div>
977967
);

0 commit comments

Comments
 (0)