-
Notifications
You must be signed in to change notification settings - Fork 363
add openai chatgpt reasoning effort mapping from config #410
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
1f0ba38
e39f942
8a9c6d1
d255715
2271017
987774f
47b9eec
7b9e3ac
6376fe8
cbaa0ef
dd1b053
1f5bfb5
cd85a42
c2514c2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| import type { ReactNode } from "react"; | ||
| import { useIsMobile } from "@/hooks/useViewport"; | ||
| import { Button } from "@/ui"; | ||
|
|
||
| interface ResponsiveSplitPaneProps { | ||
| primary: ReactNode; | ||
| secondary: ReactNode; | ||
| showSecondary: boolean; | ||
| onCloseSecondary?: () => void; | ||
| secondaryTitle?: string; | ||
| secondaryWidthClassName?: string; | ||
| } | ||
|
|
||
| export function ResponsiveSplitPane({ | ||
| primary, | ||
| secondary, | ||
| showSecondary, | ||
| onCloseSecondary, | ||
| secondaryTitle = "Details", | ||
| secondaryWidthClassName = "w-[400px]", | ||
| }: ResponsiveSplitPaneProps) { | ||
| const isMobile = useIsMobile(); | ||
|
|
||
| if (!isMobile) { | ||
| return ( | ||
| <div className="flex h-full"> | ||
| <div className="min-w-0 flex-1">{primary}</div> | ||
| {showSecondary && ( | ||
| <div className={`shrink-0 overflow-hidden border-l border-app-line/50 ${secondaryWidthClassName}`}> | ||
| {secondary} | ||
| </div> | ||
| )} | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| if (showSecondary) { | ||
| return ( | ||
| <div className="flex h-full flex-col"> | ||
| <div className="flex h-11 items-center gap-2 border-b border-app-line/50 bg-app-darkBox/30 px-3"> | ||
| {onCloseSecondary && ( | ||
| <Button | ||
| type="button" | ||
| variant="ghost" | ||
| size="sm" | ||
| onClick={onCloseSecondary} | ||
| > | ||
| Back | ||
| </Button> | ||
| )} | ||
| <span className="truncate text-sm text-ink-dull">{secondaryTitle}</span> | ||
| </div> | ||
| <div className="min-h-0 flex-1">{secondary}</div> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| return <div className="flex h-full min-h-0 flex-col">{primary}</div>; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,13 +21,16 @@ import { CSS } from "@dnd-kit/utilities"; | |
| import { api } from "@/api/client"; | ||
| import type { ChannelLiveState } from "@/hooks/useChannelLiveState"; | ||
| import { useAgentOrder } from "@/hooks/useAgentOrder"; | ||
| import { DashboardSquare01Icon, Settings01Icon } from "@hugeicons/core-free-icons"; | ||
| import { DashboardSquare01Icon, Settings01Icon, Cancel01Icon } from "@hugeicons/core-free-icons"; | ||
| import { HugeiconsIcon } from "@hugeicons/react"; | ||
| import { CreateAgentDialog } from "@/components/CreateAgentDialog"; | ||
| import { ProfileAvatar } from "@/components/ProfileAvatar"; | ||
|
|
||
| interface SidebarProps { | ||
| liveStates: Record<string, ChannelLiveState>; | ||
| isMobile?: boolean; | ||
| mobileOpen?: boolean; | ||
| onCloseMobile?: () => void; | ||
| } | ||
|
|
||
| interface SortableAgentItemProps { | ||
|
|
@@ -52,7 +55,7 @@ function SortableAgentItem({ agentId, displayName, gradientStart, gradientEnd, i | |
| transform: CSS.Transform.toString(transform), | ||
| transition, | ||
| opacity: isDragging ? 0.5 : 1, | ||
| cursor: isDragging ? 'grabbing' : 'grab', | ||
| cursor: isDragging ? "grabbing" : "grab", | ||
| }; | ||
|
|
||
| return ( | ||
|
|
@@ -61,7 +64,7 @@ function SortableAgentItem({ agentId, displayName, gradientStart, gradientEnd, i | |
| to="/agents/$agentId" | ||
| params={{ agentId }} | ||
| className="flex h-8 w-8 items-center justify-center" | ||
| style={{ pointerEvents: isDragging ? 'none' : 'auto' }} | ||
| style={{ pointerEvents: isDragging ? "none" : "auto" }} | ||
| title={displayName ?? agentId} | ||
| > | ||
| <ProfileAvatar | ||
|
|
@@ -77,25 +80,27 @@ function SortableAgentItem({ agentId, displayName, gradientStart, gradientEnd, i | |
| ); | ||
| } | ||
|
|
||
| export function Sidebar({ liveStates: _liveStates }: SidebarProps) { | ||
| export function Sidebar({ liveStates: _liveStates, isMobile = false, mobileOpen = false, onCloseMobile }: SidebarProps) { | ||
| const [createOpen, setCreateOpen] = useState(false); | ||
|
|
||
| const isDrawerHidden = isMobile && !mobileOpen; | ||
|
|
||
| const { data: agentsData } = useQuery({ | ||
| queryKey: ["agents"], | ||
| queryFn: api.agents, | ||
| refetchInterval: 30_000, | ||
| enabled: !isDrawerHidden, | ||
| refetchInterval: isDrawerHidden ? false : 30_000, | ||
| }); | ||
|
|
||
| const { data: providersData } = useQuery({ | ||
| queryKey: ["providers"], | ||
| queryFn: api.providers, | ||
| enabled: !isDrawerHidden, | ||
| staleTime: 10_000, | ||
| }); | ||
|
|
||
| const hasProvider = providersData?.has_any ?? false; | ||
|
|
||
| const agents = agentsData?.agents ?? []; | ||
|
|
||
| const agentIds = useMemo(() => agents.map((a) => a.id), [agents]); | ||
| const agentDisplayNames = useMemo(() => { | ||
| const map: Record<string, string | undefined> = {}; | ||
|
|
@@ -122,7 +127,7 @@ export function Sidebar({ liveStates: _liveStates }: SidebarProps) { | |
| }), | ||
| useSensor(KeyboardSensor, { | ||
| coordinateGetter: sortableKeyboardCoordinates, | ||
| }) | ||
| }), | ||
| ); | ||
|
|
||
| const handleDragEnd = (event: DragEndEvent) => { | ||
|
|
@@ -134,9 +139,89 @@ export function Sidebar({ liveStates: _liveStates }: SidebarProps) { | |
| } | ||
| }; | ||
|
|
||
| if (isMobile) { | ||
| if (!mobileOpen) return null; | ||
| return ( | ||
| <> | ||
| <div className="fixed inset-0 z-40 bg-black/40" onClick={onCloseMobile} /> | ||
| <nav className="fixed inset-y-0 left-0 z-50 flex w-72 flex-col border-r border-sidebar-line bg-sidebar"> | ||
| <div className="flex h-12 items-center justify-between border-b border-sidebar-line px-3"> | ||
| <span className="font-plex text-sm font-medium text-sidebar-ink">Navigation</span> | ||
| <button | ||
| type="button" | ||
| onClick={onCloseMobile} | ||
| aria-label="Close navigation" | ||
| className="flex h-8 w-8 items-center justify-center rounded-md text-sidebar-inkDull hover:bg-sidebar-selected/50 hover:text-sidebar-ink" | ||
| > | ||
| <HugeiconsIcon icon={Cancel01Icon} className="h-4 w-4" /> | ||
| </button> | ||
| </div> | ||
| <div className="flex flex-col gap-1 px-2 py-2"> | ||
| <Link | ||
| to="/" | ||
| onClick={onCloseMobile} | ||
| className={`flex items-center gap-2 rounded-md px-3 py-2 text-sm ${isOverview ? "bg-sidebar-selected text-sidebar-ink" : "text-sidebar-inkDull hover:bg-sidebar-selected/50"}`} | ||
| > | ||
| <HugeiconsIcon icon={DashboardSquare01Icon} className="h-4 w-4" /> | ||
| Overview | ||
| </Link> | ||
| <Link | ||
| to="/settings" | ||
| onClick={onCloseMobile} | ||
| className={`flex items-center gap-2 rounded-md px-3 py-2 text-sm ${isSettings ? "bg-sidebar-selected text-sidebar-ink" : "text-sidebar-inkDull hover:bg-sidebar-selected/50"}`} | ||
| > | ||
| <HugeiconsIcon icon={Settings01Icon} className="h-4 w-4" /> | ||
| Settings | ||
| </Link> | ||
| </div> | ||
| <div className="mx-3 my-1 h-px bg-sidebar-line" /> | ||
| <div className="min-h-0 flex-1 overflow-y-auto px-2 pb-3"> | ||
| <div className="mb-2 px-1 text-tiny uppercase tracking-wider text-sidebar-inkFaint">Agents</div> | ||
| <div className="flex flex-col gap-1"> | ||
| {agentOrder.map((agentId) => { | ||
| const isActive = !!matchRoute({ to: "/agents/$agentId", params: { agentId }, fuzzy: true }); | ||
| return ( | ||
| <Link | ||
| key={agentId} | ||
| to="/agents/$agentId" | ||
| params={{ agentId }} | ||
| onClick={onCloseMobile} | ||
| className={`flex items-center gap-2 rounded-md px-2 py-1.5 ${isActive ? "bg-sidebar-selected text-sidebar-ink" : "text-sidebar-inkDull hover:bg-sidebar-selected/50"}`} | ||
| > | ||
| <ProfileAvatar | ||
| seed={agentId} | ||
| name={agentDisplayNames[agentId] ?? agentId} | ||
| size={22} | ||
| className="rounded-full" | ||
| gradientStart={agentGradients[agentId]?.start} | ||
| gradientEnd={agentGradients[agentId]?.end} | ||
| /> | ||
| <span className="min-w-0 flex-1 truncate text-sm">{agentDisplayNames[agentId] ?? agentId}</span> | ||
| </Link> | ||
| ); | ||
| })} | ||
| </div> | ||
| </div> | ||
| {hasProvider && agents[0] && ( | ||
| <div className="border-t border-sidebar-line p-2"> | ||
| <button | ||
| onClick={() => setCreateOpen(true)} | ||
| className="w-full rounded-md bg-sidebar-selected px-3 py-2 text-sm text-sidebar-ink hover:bg-sidebar-selected/80" | ||
| > | ||
| New Agent | ||
| </button> | ||
| </div> | ||
| )} | ||
| </nav> | ||
| {agents[0] && ( | ||
| <CreateAgentDialog open={createOpen} onOpenChange={setCreateOpen} agentId={agents[0].id} /> | ||
| )} | ||
| </> | ||
| ); | ||
|
Comment on lines
+142
to
+220
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The mobile drawer needs real modal focus handling. This path is visually modal, but it never moves focus into the drawer or traps it there. Since 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| return ( | ||
| <nav className="flex w-14 shrink-0 flex-col items-center overflow-hidden border-r border-sidebar-line bg-sidebar"> | ||
| {/* Icon nav */} | ||
| <div className="flex flex-col items-center gap-1 pt-2"> | ||
| <Link | ||
| to="/" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align the documented mapping with the runtime contract.
This section now documents
max -> highfor allopenai-chatgpt/*models and omitsminimalentirely. That will mislead users: the runtime already treatsminimalas an alias, and GPT-5.4-family models need model-specific normalization rather than the genericmax -> highrule. Please either document those exceptions here or tighten the parser to match the docs exactly.Based on learnings: In
src/llm/model.rs, GPT-5.4-family models intentionally supportxhigh, andgpt-5.4-prorequires model-specific normalization rather than the generic low/medium/high mapping.🤖 Prompt for AI Agents