Skip to content

Commit

Permalink
bug fixes and local streaming improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
brandon-schabel committed Jan 15, 2025
1 parent 36ef863 commit a09550e
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 88 deletions.
Binary file modified bun.lockb
Binary file not shown.
4 changes: 2 additions & 2 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"test:watch": "bun test --watch"
},
"dependencies": {
"@bnk/client-websocket-manager": "^1.0.0",
"@bnk/react-websocket-manager": "1.0.4",
"@bnk/client-websocket-manager": "^1.0.1",
"@bnk/react-websocket-manager": "^1.0.5",
"@hookform/resolvers": "^3.10.0",
"@radix-ui/react-alert-dialog": "^1.1.4",
"@radix-ui/react-avatar": "^1.1.2",
Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/components/chat/chat-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ export function ChatDialog({ open, onOpenChange }: ChatDialogProps) {
/>
</div>

<ModelSelector
{/* <ModelSelector
provider={provider}
currentModel={currentModel}
onProviderChange={setProvider}
onModelChange={setCurrentModel}
/>
/> */}

<div className="flex items-center space-x-2">
<Checkbox
Expand Down
13 changes: 1 addition & 12 deletions packages/client/src/components/chat/chat-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,18 +116,7 @@ export function ChatHeader({
toast.error("Failed to copy linked content.");
}
}

// Helpers
const truncateText = (text: string, maxLength = 24) => {
return text.length > maxLength ? `${text.slice(0, maxLength - 3)}...` : text;
};

function handleBackToProject() {
if (!activeChatTabState?.linkedProjectTabId) return;
setActiveProjectTab(activeChatTabState.linkedProjectTabId);
navigate({ to: '/projects' });
}


function handleLinkProjectTab(projectTabId: string) {
if (!activeChatTabId) return;
linkChatTabToProjectTab(activeChatTabId, projectTabId, {
Expand Down
3 changes: 2 additions & 1 deletion packages/client/src/components/navigation/app-navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export function AppNavbar() {
const isOnChatRoute = matches.some(match => match.routeId === "/chat")
const isOnProjectsRoute = matches.some(match => match.routeId === "/projects")
const isOnKeysRoute = matches.some(match => match.routeId === "/keys")
const isOnSummarizationRoute = matches.some(match => match.routeId === "/project-summarization")

const { activeProjectTabState: activeTabState, updateActiveProjectTab: updateActiveTab, updateGlobalStateKey, state } = useGlobalStateHelpers()
const selectedProjectId = activeTabState?.selectedProjectId
Expand Down Expand Up @@ -132,7 +133,7 @@ export function AppNavbar() {
</Link>
<Link
to="/project-summarization"
className={`inline-flex items-center gap-2 text-sm font-medium transition-colors ${isOnKeysRoute
className={`inline-flex items-center gap-2 text-sm font-medium transition-colors ${isOnSummarizationRoute
? "text-indigo-600 dark:text-indigo-400"
: "text-foreground hover:text-indigo-600 dark:hover:text-indigo-400"
}`}
Expand Down
120 changes: 77 additions & 43 deletions packages/client/src/components/settings/settings-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
SelectValue,
} from "../ui/select"
import { useGlobalStateHelpers } from "../global-state/use-global-state-helpers"
import { Label } from "@/components/ui/label"
import { Input } from "@/components/ui/input"

type ThemeOption = {
label: string;
Expand Down Expand Up @@ -37,6 +39,8 @@ export function SettingsDialog({ open, onOpenChange }: SettingsDialogProps) {
const settings = state?.settings
const codeLightTheme = settings?.codeThemeLight ?? 'atomOneLight'
const codeDarkTheme = settings?.codeThemeDark ?? 'atomOneDark'
const ollamaUrl = settings?.ollamaGlobalUrl;
const lmStudioUrl = settings?.lmStudioGlobalUrl;

const handleThemeToggle = () => {
const newTheme: Theme = isDarkMode ? 'light' : 'dark'
Expand All @@ -49,71 +53,101 @@ export function SettingsDialog({ open, onOpenChange }: SettingsDialogProps) {
const handleSetCodeTheme = (value: string, isDark: boolean) => {
const theme = themeOptions.find(t => t.value === value);
if (!theme) return;

updateGlobalStateKey('settings', (prev) => ({
...prev,
...(isDark ? { codeThemeDark: value } : { codeThemeLight: value }),
}))
}

const handleUrlChange = (
key: 'ollamaGlobalUrl' | 'lmStudioGlobalUrl',
value: string
) => {
updateGlobalStateKey('settings', (prev) => ({
...prev,
[key]: value,
}))
}

return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Settings</DialogTitle>
</DialogHeader>
<div className="flex flex-col gap-4 py-4">
<div className="flex flex-col gap-6 py-4">
<div className="flex items-center justify-between">
<label htmlFor="dark-mode" className="text-sm font-medium">
<Label htmlFor="dark-mode" className="text-sm font-medium">
Dark Mode
</label>
</Label>
<Switch
id="dark-mode"
checked={isDarkMode}
onCheckedChange={handleThemeToggle}
/>
</div>

<div className="flex flex-col gap-2">
<label className="text-sm font-medium">
Light Mode Code Theme
</label>
<Select
value={codeLightTheme}
onValueChange={(value) => handleSetCodeTheme(value, false)}
>
<SelectTrigger>
<SelectValue placeholder="Select theme" />
</SelectTrigger>
<SelectContent>
{themeOptions.map((theme) => (
<SelectItem key={theme.value} value={theme.value}>
{theme.label}
</SelectItem>
))}
</SelectContent>
</Select>

<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="ollama-url">Ollama URL</Label>
<Input
id="ollama-url"
placeholder="http://localhost:11434"
value={ollamaUrl}
onChange={(e) => handleUrlChange('ollamaGlobalUrl', e.target.value)}
/>
</div>

<div className="space-y-2">
<Label htmlFor="lmstudio-url">LM Studio URL</Label>
<Input
id="lmstudio-url"
placeholder="http://localhost:1234"
value={lmStudioUrl}
onChange={(e) => handleUrlChange('lmStudioGlobalUrl', e.target.value)}
/>
</div>
</div>

<div className="flex flex-col gap-2">
<label className="text-sm font-medium">
Dark Mode Code Theme
</label>
<Select
value={codeDarkTheme}
onValueChange={(value) => handleSetCodeTheme(value, true)}
>
<SelectTrigger>
<SelectValue placeholder="Select theme" />
</SelectTrigger>
<SelectContent>
{themeOptions.map((theme) => (
<SelectItem key={theme.value} value={theme.value}>
{theme.label}
</SelectItem>
))}
</SelectContent>
</Select>
<div className="space-y-4">
<div className="flex flex-col gap-2">
<Label>Light Mode Code Theme</Label>
<Select
value={codeLightTheme}
onValueChange={(value) => handleSetCodeTheme(value, false)}
>
<SelectTrigger>
<SelectValue placeholder="Select theme" />
</SelectTrigger>
<SelectContent>
{themeOptions.map((theme) => (
<SelectItem key={theme.value} value={theme.value}>
{theme.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>

<div className="flex flex-col gap-2">
<Label>Dark Mode Code Theme</Label>
<Select
value={codeDarkTheme}
onValueChange={(value) => handleSetCodeTheme(value, true)}
>
<SelectTrigger>
<SelectValue placeholder="Select theme" />
</SelectTrigger>
<SelectContent>
{themeOptions.map((theme) => (
<SelectItem key={theme.value} value={theme.value}>
{theme.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
</div>
</DialogContent>
Expand Down
15 changes: 13 additions & 2 deletions packages/client/src/constants/providers-constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { APIProviders } from "shared/index"


export type Provider = {
export type ModelProvider = {
id: APIProviders
name: string
apiKeyUrl: string
Expand Down Expand Up @@ -51,8 +51,19 @@ export const PROVIDERS = [
name: 'Together',
apiKeyUrl: 'https://api.together.ai/settings/api-keys',
description: 'API keys for Together models'
},
{
id: 'lmstudio',
name: 'LMStudio',
apiKeyUrl: 'https://lmstudio.ai/settings/api-keys',
description: 'API keys for LMStudio models'
}, {
id: 'ollama',
name: 'Ollama',
apiKeyUrl: 'https://ollama.ai/settings/api-keys',
description: 'API keys for Ollama models'
}
] satisfies Provider[]
] satisfies ModelProvider[]



Expand Down
2 changes: 1 addition & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"drizzle-orm": "^0.36.3"
},
"dependencies": {
"@bnk/ai": "^1.0.0",
"@bnk/ai": "1.0.8",
"@bnk/backend-websocket-manager": "^1.0.0",
"@bnk/router": "1.0.6",
"@types/archiver": "^6.0.3",
Expand Down
1 change: 1 addition & 0 deletions packages/server/src/routes/flags-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const defaultFlags = {
data: string;
}>;


const initiateFlags = async (): Promise<void> => {
if (flagsInitialized) return;
const initFlag = await db
Expand Down
12 changes: 9 additions & 3 deletions packages/server/src/routes/prompt-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ const promptService = new PromptService();
router.post("/api/prompts", {
validation: promptApiValidation.create,
}, async (_, { body }) => {
const created = await promptService.createPrompt(body);
return json({ success: true, prompt: created }, { status: 201 });
});
// 1) Create the prompt
const createdPrompt = await promptService.createPrompt(body);

// 2) If projectId was given, link it to the project:
if (body.projectId) {
await promptService.addPromptToProject(createdPrompt.id, body.projectId);
}

return json({ success: true, prompt: createdPrompt }, { status: 201 });
});

router.get("/api/prompts", {}, async (_, __) => {
const all = await promptService.listAllPrompts();
Expand Down
21 changes: 8 additions & 13 deletions packages/server/src/services/file-summary-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,25 @@ function chunkArray<T>(arr: T[], size: number): T[][] {
return chunks
}


const shouldSummarizeFile = async (projectId: string, filePath: string): Promise<boolean> => {
const state = await getState()
const settings = state.settings


if (settings.disableSummarizationProjectIds.includes(projectId)) {
return false
}

const matchesIgnorePattern = settings.summarizationIgnorePatterns.some(pattern =>
new RegExp(pattern).test(filePath)
)

if (matchesIgnorePattern) {
// If any pattern in summarizationIgnorePatterns matches, skip.
if (matchesAnyPattern(filePath, settings.summarizationIgnorePatterns)) {
return false
}

const hasAllowPatterns = settings.summarizationAllowPatterns.length > 0
const matchesAllowPattern = settings.summarizationAllowPatterns.some(pattern =>
new RegExp(pattern).test(filePath)
)

if (hasAllowPatterns && !matchesAllowPattern) {
return false
// If we have allow patterns, at least one must match.
if (settings.summarizationAllowPatterns.length > 0) {
if (!matchesAnyPattern(filePath, settings.summarizationAllowPatterns)) {
return false
}
}

return true
Expand Down
Loading

0 comments on commit a09550e

Please sign in to comment.