Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"test": "jest",
"test:coverage": "jest --coverage",
"test:watch": "jest --watch",
"generate-random-key": "tsx src/cli/generate-aes-key.ts",
"staged": "npm run typecheck && npm run lint && jest",
"typecheck": "tsc --noEmit --skipLibCheck",
"format": "prettier --check .",
Expand Down
2 changes: 0 additions & 2 deletions src/app/(outerbase)/local-setting-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ export const localSettingDialog = createDialog(({ close }) => {
}, []);

const onSaveClicked = useCallback(() => {
if (!token) return;

updateAgentFromLocalStorage({
provider: "openai",
model: "gpt-4o-mini",
Expand Down
4 changes: 2 additions & 2 deletions src/app/(theme)/client/s/[[...driver]]/page-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from "@/core/standard-extension";
import { createLocalDriver } from "@/drivers/helpers";
import IndexdbSavedDoc from "@/drivers/saved-doc/indexdb-saved-doc";
import { useAgentFromLocalStorage } from "@/lib/ai-agent-storage";
import { useAvailableAIAgents } from "@/lib/ai-agent-storage";
import { useRouter, useSearchParams } from "next/navigation";
import { useCallback, useEffect, useMemo } from "react";

Expand Down Expand Up @@ -57,7 +57,7 @@ export default function ClientPageBody() {
return new StudioExtensionManager(createStandardExtensions());
}, [driver]);

const agentDriver = useAgentFromLocalStorage(driver);
const agentDriver = useAvailableAIAgents(driver);

const docDriver = useMemo(() => {
if (conn) {
Expand Down
5 changes: 0 additions & 5 deletions src/app/(theme)/connect/saved-connection-storage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { ApiUser } from "@/lib/api/api-database-response";

export type SupportedDriver =
| "turso"
| "rqlite"
Expand Down Expand Up @@ -27,9 +25,6 @@ export interface SavedConnectionItem {
name: string;
description?: string;
label?: SavedConnectionLabel;
shared?: {
sharedBy: ApiUser;
};
}

export interface SavedConnectionItemConfigConfig {
Expand Down
4 changes: 2 additions & 2 deletions src/app/(theme)/embed/[driver]/page-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
import ElectronSavedDocs from "@/drivers/saved-doc/electron-saved-doc";
import DoltExtension from "@/extensions/dolt";
import LocalSettingSidebar from "@/extensions/local-setting-sidebar";
import { useAgentFromLocalStorage } from "@/lib/ai-agent-storage";
import { useAvailableAIAgents } from "@/lib/ai-agent-storage";
import { useSearchParams } from "next/navigation";
import { useEffect, useMemo } from "react";

Expand All @@ -39,7 +39,7 @@ export default function EmbedPageClient({
return new StudioExtensionManager(createEmbedExtensions(driverName));
}, [driverName]);

const agentDriver = useAgentFromLocalStorage(driver);
const agentDriver = useAvailableAIAgents(driver);

useEffect(() => {
return driver.listen();
Expand Down
4 changes: 2 additions & 2 deletions src/app/(theme)/playground/client/page-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { StudioExtensionManager } from "@/core/extension-manager";
import { createSQLiteExtensions } from "@/core/standard-extension";
import SqljsDriver from "@/drivers/sqljs-driver";
import { localDb } from "@/indexdb";
import { useAgentFromLocalStorage } from "@/lib/ai-agent-storage";
import { useAvailableAIAgents } from "@/lib/ai-agent-storage";
import downloadFileFromUrl from "@/lib/download-file";
import { saveAs } from "file-saver";
import {
Expand Down Expand Up @@ -44,7 +44,7 @@ export default function PlaygroundEditorBody({
const [handler, setHandler] = useState<FileSystemFileHandle>();
const [fileName, setFilename] = useState("");

const agentDriver = useAgentFromLocalStorage(driver);
const agentDriver = useAvailableAIAgents(driver);

/**
* Initialize the SQL.js library.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"use server";

import StarbaseDriver from "@/drivers/starbase-driver";
import { type TrackEventItem } from "../tracking";
import { env } from "@/env";
import { type TrackEventItem } from "../../../lib/tracking";

export async function insertTrackingRecord(
deviceId: string,
Expand Down
4 changes: 2 additions & 2 deletions src/app/api/events/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
// All recorded data will be stored in the Starbase Database.

import { headers } from "next/headers";
import zod from "zod";
import { after, NextRequest, NextResponse } from "next/server";
import { insertTrackingRecord } from "@/lib/api/insert-tracking-record";
import zod from "zod";
import { insertTrackingRecord } from "./insert-tracking-record";

const eventBodySchema = zod.object({
events: zod
Expand Down
1 change: 0 additions & 1 deletion src/app/storybook/editor/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ END;
dialect="sqlite"
value={value}
onChange={setValue}
enablePrompt
onPrompt={async (prompt, selected) => {
const selectedText = selected?.text;

Expand Down
3 changes: 0 additions & 3 deletions src/cli/generate-aes-key.ts

This file was deleted.

7 changes: 6 additions & 1 deletion src/components/editor/prompt-plugin.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AgentDriverList from "@/drivers/agent/list";
import { unifiedMergeView } from "@codemirror/merge";
import {
Compartment,
Expand Down Expand Up @@ -38,6 +39,7 @@ export interface PromptSelectedFragment {
startLineNumber: number;
endLineNumber: number;
sessionId: string;
selectedModel?: string;
}

export type PromptCallback = (
Expand Down Expand Up @@ -147,7 +149,7 @@ class PromptWidget extends WidgetType {
// If the result of a query arrives and the counter has changed, the result is ignored.
let queryCounter = 1;

const onGenerate = async (promptText: string) => {
const onGenerate = async (promptText: string, selectedModel?: string) => {
try {
const expectedQueryCounter = queryCounter;

Expand All @@ -159,6 +161,7 @@ class PromptWidget extends WidgetType {
endLineNumber: view.state.doc.lineAt(
startPosition + suggestedText.length
).number,
selectedModel,
});

// This prevent when we close the widget before
Expand Down Expand Up @@ -240,6 +243,7 @@ class PromptWidget extends WidgetType {
onSubmit={onGenerate}
onReject={onReject}
onCancel={onCancel}
agentDriver={plugin.agents}
/>
);
}
Expand Down Expand Up @@ -325,6 +329,7 @@ export class CodeMirrorPromptPlugin {
public isActive = false;
activeWidget?: PromptWidget;
promptCallback?: PromptCallback;
public agents?: AgentDriverList;

/**
* This is for locking when prompt is open. This is to prevent
Expand Down
84 changes: 78 additions & 6 deletions src/components/editor/prompt-widget.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
"use client";

import AgentDriverList from "@/drivers/agent/list";
import { cn } from "@/lib/utils";
import { X } from "@phosphor-icons/react";
import { useCallback, useRef, useState } from "react";
import { Check, X } from "@phosphor-icons/react";
import { useCallback, useMemo, useRef, useState } from "react";
import { CloudflareIcon } from "../icons/outerbase-icon";
import { Button } from "../orbit/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuTrigger,
} from "../ui/dropdown-menu";

interface CodeMirrorPromptWidgetProps {
agentDriver?: AgentDriverList;
onClose?: () => void;
onCancel?: () => void;
onAccept?: () => void;
onReject?: () => void;
onSubmit?: (query: string) => Promise<void>;
onSubmit?: (query: string, selectedModel?: string) => Promise<void>;
}

export function CodeMirrorPromptWidget({
Expand All @@ -19,13 +30,22 @@ export function CodeMirrorPromptWidget({
onSubmit,
onAccept,
onReject,
agentDriver,
}: CodeMirrorPromptWidgetProps) {
const textareaClassName =
"absolute left-0 right-0 resize-none p-1 p-2 outline-none";

const fakeTextareaRef = useRef<HTMLTextAreaElement>(null);
const textareaRef = useRef<HTMLTextAreaElement>(null);

const agentList = useMemo(() => {
if (!agentDriver) return [];
return agentDriver.list();
}, [agentDriver]);
const [selectedAgent, setSelectedAgent] = useState(() =>
agentDriver?.getDefaultModelName()
);

const [previousPrompt, setPreviousPrompt] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
Expand Down Expand Up @@ -58,7 +78,7 @@ export function CodeMirrorPromptWidget({
setError("");
cancelTriggered.current = false;

onSubmit(prompt)
onSubmit(prompt, selectedAgent)
.then(() => {
if (!cancelTriggered.current) {
setPreviousPrompt(prompt);
Expand All @@ -77,7 +97,7 @@ export function CodeMirrorPromptWidget({
setLoading(false);
});
}
}, [onSubmit, prompt]);
}, [onSubmit, prompt, selectedAgent]);

const triggerReject = useCallback(() => {
if (onReject) onReject();
Expand Down Expand Up @@ -162,7 +182,11 @@ export function CodeMirrorPromptWidget({
</div>
</div>

{error && <div className="p-2 text-sm text-red-500">{error}</div>}
{error && (
<div className="line-clamp-1 p-2 text-sm text-red-500">
{error.split("\n")[0]}
</div>
)}

<div className="flex h-10 items-center gap-1 p-2">
{(showSubmitButton || showSubmitEditButton) && (
Expand Down Expand Up @@ -194,6 +218,54 @@ export function CodeMirrorPromptWidget({
</Button>
)}

<div className="flex-1" />

{agentList.length > 0 && (
<DropdownMenu modal={false}>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm">
{selectedAgent !== "gpt-4o mini" && (
<CloudflareIcon className="inline-flex h-4 w-4 text-orange-500" />
)}
{selectedAgent}
</Button>
</DropdownMenuTrigger>

<DropdownMenuContent align="start">
{agentList.map((group) => (
<DropdownMenuGroup key={group.name}>
<DropdownMenuLabel>{group.title}</DropdownMenuLabel>
{group.agents.map((agent) => (
<DropdownMenuItem
disabled={!agent.available}
inset={selectedAgent !== agent.name}
key={agent.name}
onClick={() => {
setSelectedAgent(agent.name);
if (agentDriver) {
agentDriver.setDefaultModelName(agent.name);
}
}}
>
{agent.name === selectedAgent ? (
<Check className="mr-2 h-4 w-4" />
) : null}
{agent.name}
{agent.free ? (
<div className="flex flex-1 justify-end">
<span className="bg-secondary text-secondary-foreground rounded px-2 text-sm">
free tier
</span>
</div>
) : null}
</DropdownMenuItem>
))}
</DropdownMenuGroup>
))}
</DropdownMenuContent>
</DropdownMenu>
)}

{!previousPrompt && !loading ? (
<span className="text-muted-foreground ml-2 text-sm">
Esc to close
Expand Down
5 changes: 5 additions & 0 deletions src/components/gui/query-explanation-diagram/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ import { NestedLoop } from "./node-type/nested-loop";
import { TableBlock } from "./node-type/table-block";
import { OperationBlock } from "./node-type/operation-block";
import { UnionBlock } from "./node-type/union-block";
import { useTheme } from "next-themes";

interface LayoutFlowProps {
items: ExplanationMysql;
}

function QueryExplanationFlow(props: LayoutFlowProps) {
const { forcedTheme, resolvedTheme } = useTheme();
const [loading, setLoading] = useState(true);
const [nodes, setNodes, onNodesChange] = useNodesState<Node>([]);
const [edges, setEdges, onEdgesChange] = useEdgesState<Edge>([]);
Expand Down Expand Up @@ -56,8 +58,11 @@ function QueryExplanationFlow(props: LayoutFlowProps) {
}
}, [props, loading, setEdges, setNodes]);

const appTheme = (forcedTheme ?? resolvedTheme) as "dark" | "light";

return (
<ReactFlow
colorMode={appTheme}
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
Expand Down
13 changes: 7 additions & 6 deletions src/components/gui/sql-editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
PromptCallback,
} from "@/components/editor/prompt-plugin";
import { createVariableHighlightPlugin } from "@/components/editor/sql-editor/variable-highlight-plugin";
import AgentDriverList from "@/drivers/agent/list";
import { SupportedDialect } from "@/drivers/base-driver";
import sqliteFunctionList from "@/drivers/sqlite/function-tooltip.json";
import { sqliteDialect } from "@/drivers/sqlite/sqlite-dialect";
Expand All @@ -46,8 +47,8 @@ interface SqlEditorProps {
/**
* Prompt Support
*/
enablePrompt?: boolean;
onPrompt?: PromptCallback;
agents?: AgentDriverList;

value: string;
dialect: SupportedDialect;
Expand Down Expand Up @@ -75,11 +76,10 @@ const SqlEditor = forwardRef<ReactCodeMirrorRef, SqlEditorProps>(
onCursorChange,
readOnly,
fontSize,
agents,
onFontSizeChanged,
variableList,
highlightVariable,

enablePrompt,
onPrompt,
}: SqlEditorProps,
ref
Expand All @@ -94,14 +94,15 @@ const SqlEditor = forwardRef<ReactCodeMirrorRef, SqlEditorProps>(
}, [schema]);

const promptPlugin = useMemo(() => {
return enablePrompt ? new CodeMirrorPromptPlugin() : null;
}, [enablePrompt]);
return agents ? new CodeMirrorPromptPlugin() : null;
}, [agents]);

useEffect(() => {
if (promptPlugin && onPrompt) {
promptPlugin.handleSuggestion(onPrompt);
promptPlugin.agents = agents;
}
}, [promptPlugin, onPrompt]);
}, [promptPlugin, onPrompt, agents]);

const keyExtensions = useMemo(() => {
return keymap.of([
Expand Down
Loading