Compare commits
3 Commits
@continued
...
v1.2.4-vsc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23a4a4a506 | ||
|
|
de3d85ae54 | ||
|
|
1699062208 |
@@ -537,18 +537,14 @@ export abstract class BaseLLM implements ILLM {
|
||||
}
|
||||
|
||||
private _formatChatMessage(msg: ChatMessage): string {
|
||||
let contentToShow = "";
|
||||
if (msg.role === "tool") {
|
||||
contentToShow = msg.content;
|
||||
} else if (msg.role === "assistant" && msg.toolCalls?.length) {
|
||||
contentToShow = msg.toolCalls
|
||||
let contentToShow = renderChatMessage(msg);
|
||||
if (msg.role === "assistant" && msg.toolCalls?.length) {
|
||||
contentToShow += msg.toolCalls
|
||||
?.map(
|
||||
(toolCall) =>
|
||||
`${toolCall.function?.name}(${toolCall.function?.arguments})`,
|
||||
)
|
||||
.join("\n");
|
||||
} else if ("content" in msg) {
|
||||
contentToShow = renderChatMessage(msg);
|
||||
}
|
||||
|
||||
return `<${msg.role}>\n${contentToShow}\n\n`;
|
||||
|
||||
@@ -68,6 +68,17 @@ class Anthropic extends BaseLLM {
|
||||
return finalOptions;
|
||||
}
|
||||
|
||||
private buildTextPart(text: string, addCaching: boolean) {
|
||||
const part: any = {
|
||||
type: "text",
|
||||
text,
|
||||
};
|
||||
if (addCaching) {
|
||||
part.cache_control = { type: "ephemeral" };
|
||||
}
|
||||
return part;
|
||||
}
|
||||
|
||||
private convertMessage(message: ChatMessage, addCaching: boolean): any {
|
||||
if (message.role === "tool") {
|
||||
return {
|
||||
@@ -81,14 +92,30 @@ class Anthropic extends BaseLLM {
|
||||
],
|
||||
};
|
||||
} else if (message.role === "assistant" && message.toolCalls) {
|
||||
return {
|
||||
role: "assistant",
|
||||
content: message.toolCalls.map((toolCall) => ({
|
||||
const parts: any[] = [];
|
||||
if (message.content) {
|
||||
if (typeof message.content === "string") {
|
||||
parts.push(this.buildTextPart(message.content, addCaching));
|
||||
} else if (message.content.length > 0) {
|
||||
const textContent = message.content.filter((p) => p.type === "text");
|
||||
const textParts = textContent.map((part, idx) => {
|
||||
const cache = idx === textContent.length - 1 && addCaching;
|
||||
return this.buildTextPart(part.text, cache);
|
||||
});
|
||||
parts.push(...textParts);
|
||||
}
|
||||
}
|
||||
parts.push(
|
||||
...message.toolCalls.map((toolCall) => ({
|
||||
type: "tool_use",
|
||||
id: toolCall.id,
|
||||
name: toolCall.function?.name,
|
||||
input: safeParseToolCallArgs(toolCall),
|
||||
})),
|
||||
);
|
||||
return {
|
||||
role: "assistant",
|
||||
content: parts,
|
||||
};
|
||||
} else if (message.role === "thinking" && !message.redactedThinking) {
|
||||
return {
|
||||
@@ -154,9 +181,7 @@ class Anthropic extends BaseLLM {
|
||||
|
||||
public convertMessages(msgs: ChatMessage[]): any[] {
|
||||
// should be public for use within VertexAI
|
||||
const filteredmessages = msgs.filter(
|
||||
(m) => m.role !== "system" && !!m.content,
|
||||
);
|
||||
const filteredmessages = msgs.filter((m) => m.role !== "system");
|
||||
const lastTwoUserMsgIndices = filteredmessages
|
||||
.map((msg, index) => (msg.role === "user" ? index : -1))
|
||||
.filter((index) => index !== -1)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "continue",
|
||||
"icon": "media/icon.png",
|
||||
"author": "Continue Dev, Inc",
|
||||
"version": "1.3.7",
|
||||
"version": "1.2.4",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/continuedev/continue"
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
|
||||
import {
|
||||
Cog6ToothIcon,
|
||||
ExclamationTriangleIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { ProfileDescription } from "core/config/ProfileLifecycleManager";
|
||||
import { useContext, useMemo } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
@@ -48,7 +51,7 @@ export function AssistantOption({
|
||||
disabled={hasFatalErrors}
|
||||
onClick={!hasFatalErrors ? handleOptionClick : undefined}
|
||||
fontSizeModifier={-2}
|
||||
className={selected ? "bg-list-active text-list-active-foreground" : ""}
|
||||
className={`group ${selected ? "bg-list-active text-list-active-foreground" : ""}`}
|
||||
>
|
||||
<div className="flex w-full items-center justify-between gap-10 py-0.5">
|
||||
<div className="flex w-full items-center gap-3">
|
||||
@@ -62,6 +65,20 @@ export function AssistantOption({
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-1.5">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-description-muted hover:enabled:text-foreground my-0 h-4 w-4 p-0 opacity-0 transition-opacity group-hover:opacity-100"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
ideMessenger.post("config/openProfile", {
|
||||
profileId: profile.id,
|
||||
});
|
||||
onClick(); // Close the listbox
|
||||
}}
|
||||
>
|
||||
<Cog6ToothIcon className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
{profile.errors && profile.errors?.length > 0 && (
|
||||
<ToolTip content="View errors">
|
||||
<Button
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import { CheckIcon } from "@heroicons/react/24/outline";
|
||||
import { Cog6ToothIcon } from "@heroicons/react/24/outline";
|
||||
import {
|
||||
BuildingOfficeIcon,
|
||||
UserCircleIcon,
|
||||
UserIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
import { useContext } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { IdeMessengerContext } from "../../context/IdeMessenger";
|
||||
import { useAppDispatch, useAppSelector } from "../../redux/hooks";
|
||||
import { setSelectedOrgId } from "../../redux/slices/profilesSlice";
|
||||
import { ListboxOption } from "../ui";
|
||||
import { CONFIG_ROUTES } from "../../util/navigation";
|
||||
import { Button, ListboxOption } from "../ui";
|
||||
|
||||
interface OrganizationOptionProps {
|
||||
organization: { id: string; name: string; iconUrl?: string | null };
|
||||
@@ -45,6 +47,7 @@ export function OrganizationOption({
|
||||
onClose,
|
||||
}: OrganizationOptionProps) {
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
const ideMessenger = useContext(IdeMessengerContext);
|
||||
const selectedOrgId = useAppSelector(
|
||||
(state) => state.profiles.selectedOrganizationId,
|
||||
@@ -64,7 +67,7 @@ export function OrganizationOption({
|
||||
value={organization.id}
|
||||
onClick={handleOptionClick}
|
||||
fontSizeModifier={-2}
|
||||
className={isSelected ? "bg-list-active text-list-active-foreground" : ""}
|
||||
className={`group ${isSelected ? "bg-list-active text-list-active-foreground" : ""}`}
|
||||
>
|
||||
<div className="flex w-full items-center justify-between gap-10 py-0.5">
|
||||
<div className="flex w-full items-center gap-3">
|
||||
@@ -78,7 +81,18 @@ export function OrganizationOption({
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-1.5">
|
||||
{isSelected && <CheckIcon className="h-3.5 w-3.5 flex-shrink-0" />}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-description-muted hover:enabled:text-foreground my-0 h-4 w-4 p-0 opacity-0 transition-opacity group-hover:opacity-100"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
navigate(CONFIG_ROUTES.ORGANIZATIONS);
|
||||
onClose(); // Close the listbox
|
||||
}}
|
||||
>
|
||||
<Cog6ToothIcon className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</ListboxOption>
|
||||
|
||||
@@ -2,9 +2,7 @@ import {
|
||||
ArrowPathIcon,
|
||||
ArrowRightStartOnRectangleIcon,
|
||||
Cog6ToothIcon,
|
||||
PencilIcon,
|
||||
PlusIcon,
|
||||
WrenchScrewdriverIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { isOnPremSession } from "core/control-plane/AuthTypes";
|
||||
import { useContext, useEffect, useRef } from "react";
|
||||
@@ -155,7 +153,7 @@ export function AssistantAndOrgListbox({
|
||||
className="max-h-32 -translate-x-1.5 overflow-y-auto pb-0"
|
||||
style={{ zIndex: 200 }}
|
||||
>
|
||||
<div className="flex items-center justify-between p-2">
|
||||
<div className="flex items-center justify-between px-1.5 py-1">
|
||||
<span className="text-description text-xs font-medium">
|
||||
Agents
|
||||
</span>
|
||||
@@ -193,7 +191,7 @@ export function AssistantAndOrgListbox({
|
||||
{shouldRenderOrgInfo && (
|
||||
<>
|
||||
<Divider className="!mb-0.5 !mt-0" />
|
||||
<div className="flex items-center justify-between p-2">
|
||||
<div className="flex items-center justify-between px-1.5 py-1">
|
||||
<span className="text-description text-xs font-medium">
|
||||
Organizations
|
||||
</span>
|
||||
@@ -232,34 +230,6 @@ export function AssistantAndOrgListbox({
|
||||
{/* Settings Section */}
|
||||
{variant !== "sidebar" && (
|
||||
<div>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onRulesConfig();
|
||||
}}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-description hover:bg-input my-0 w-full justify-start py-1.5 pl-1 text-left"
|
||||
>
|
||||
<div className="flex w-full items-center">
|
||||
<PencilIcon className="ml-1.5 mr-2 h-3.5 w-3.5 flex-shrink-0" />
|
||||
<span className="text-2xs">Rules</span>
|
||||
</div>
|
||||
</Button>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onToolsConfig();
|
||||
}}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-description hover:bg-input my-0 w-full justify-start py-1.5 pl-1 text-left"
|
||||
>
|
||||
<div className="flex w-full items-center">
|
||||
<WrenchScrewdriverIcon className="ml-1.5 mr-2 h-3.5 w-3.5 flex-shrink-0" />
|
||||
<span className="text-2xs">Tools</span>
|
||||
</div>
|
||||
</Button>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -1,24 +1,45 @@
|
||||
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
|
||||
import {
|
||||
CubeIcon,
|
||||
ExclamationTriangleIcon,
|
||||
PencilIcon,
|
||||
WrenchScrewdriverIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { IdeMessengerContext } from "../../../../context/IdeMessenger";
|
||||
import { useAppSelector } from "../../../../redux/hooks";
|
||||
import { useAppDispatch, useAppSelector } from "../../../../redux/hooks";
|
||||
import {
|
||||
selectPendingToolCalls,
|
||||
selectToolCallsByStatus,
|
||||
} from "../../../../redux/selectors/selectToolCalls";
|
||||
import { setSelectedProfile } from "../../../../redux/slices/profilesSlice";
|
||||
import FreeTrialButton from "../../../FreeTrialButton";
|
||||
import { ToolTip } from "../../../gui/Tooltip";
|
||||
import HoverItem from "../../InputToolbar/HoverItem";
|
||||
|
||||
import { usesFreeTrialApiKey } from "core/config/usesFreeTrialApiKey";
|
||||
import type { FreeTrialStatus } from "core/control-plane/client";
|
||||
import { useAuth } from "../../../../context/Auth";
|
||||
import { getLocalStorage } from "../../../../util/localStorage";
|
||||
import { CONFIG_ROUTES } from "../../../../util/navigation";
|
||||
import { AssistantAndOrgListbox } from "../../../AssistantAndOrgListbox";
|
||||
|
||||
export function BlockSettingsTopToolbar() {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useAppDispatch();
|
||||
const { selectedProfile } = useAuth();
|
||||
|
||||
const configError = useAppSelector((store) => store.config.configError);
|
||||
const config = useAppSelector((state) => state.config.config);
|
||||
const ideMessenger = useContext(IdeMessengerContext);
|
||||
|
||||
const pendingToolCalls = useAppSelector(selectPendingToolCalls);
|
||||
const callingToolCalls = useAppSelector((state) =>
|
||||
selectToolCallsByStatus(state, "calling"),
|
||||
);
|
||||
const hasActiveContent =
|
||||
pendingToolCalls.length > 0 || callingToolCalls.length > 0;
|
||||
|
||||
const [freeTrialStatus, setFreeTrialStatus] =
|
||||
useState<FreeTrialStatus | null>(null);
|
||||
const hasExitedFreeTrial = getLocalStorage("hasExitedFreeTrial");
|
||||
@@ -53,9 +74,39 @@ export function BlockSettingsTopToolbar() {
|
||||
|
||||
const shouldShowError = configError && configError?.length > 0;
|
||||
|
||||
const handleRulesClick = () => {
|
||||
if (selectedProfile) {
|
||||
dispatch(setSelectedProfile(selectedProfile.id));
|
||||
ideMessenger.post("didChangeSelectedProfile", {
|
||||
id: selectedProfile.id,
|
||||
});
|
||||
}
|
||||
navigate(CONFIG_ROUTES.RULES);
|
||||
};
|
||||
|
||||
const handleToolsClick = () => {
|
||||
if (selectedProfile) {
|
||||
dispatch(setSelectedProfile(selectedProfile.id));
|
||||
ideMessenger.post("didChangeSelectedProfile", {
|
||||
id: selectedProfile.id,
|
||||
});
|
||||
}
|
||||
navigate(CONFIG_ROUTES.TOOLS);
|
||||
};
|
||||
|
||||
const handleModelsClick = () => {
|
||||
if (selectedProfile) {
|
||||
dispatch(setSelectedProfile(selectedProfile.id));
|
||||
ideMessenger.post("didChangeSelectedProfile", {
|
||||
id: selectedProfile.id,
|
||||
});
|
||||
}
|
||||
navigate(CONFIG_ROUTES.MODELS);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-1 items-center justify-between gap-1.5">
|
||||
<div>
|
||||
<div className="flex items-center gap-1">
|
||||
{shouldShowError && (
|
||||
<ToolTip delayShow={700} content="View configuration errors">
|
||||
<div
|
||||
@@ -78,7 +129,30 @@ export function BlockSettingsTopToolbar() {
|
||||
</div>
|
||||
</ToolTip>
|
||||
)}
|
||||
|
||||
{!hasActiveContent && (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<ToolTip content="Configure rules">
|
||||
<HoverItem onClick={handleRulesClick} px={2}>
|
||||
<PencilIcon className="text-description-muted h-3 w-3 hover:brightness-125" />
|
||||
</HoverItem>
|
||||
</ToolTip>
|
||||
|
||||
<ToolTip content="Configure tools">
|
||||
<HoverItem onClick={handleToolsClick} px={2}>
|
||||
<WrenchScrewdriverIcon className="text-description-muted h-3 w-3 hover:brightness-125" />
|
||||
</HoverItem>
|
||||
</ToolTip>
|
||||
|
||||
<ToolTip content="Configure models">
|
||||
<HoverItem onClick={handleModelsClick} px={2}>
|
||||
<CubeIcon className="text-description-muted h-3 w-3 hover:brightness-125" />
|
||||
</HoverItem>
|
||||
</ToolTip>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<ToolTip
|
||||
place="top"
|
||||
content={isUsingFreeTrial ? "View free trial usage" : "Select Agent"}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
ArrowPathIcon,
|
||||
CheckIcon,
|
||||
ChevronDownIcon,
|
||||
Cog6ToothIcon,
|
||||
CubeIcon,
|
||||
@@ -16,7 +15,9 @@ import { setDialogMessage, setShowDialog } from "../../redux/slices/uiSlice";
|
||||
import { updateSelectedModelByRole } from "../../redux/thunks/updateSelectedModelByRole";
|
||||
import { getMetaKeyLabel, isMetaEquivalentKeyPressed } from "../../util";
|
||||
import { CONFIG_ROUTES } from "../../util/navigation";
|
||||
import { ToolTip } from "../gui/Tooltip";
|
||||
import {
|
||||
Button,
|
||||
Listbox,
|
||||
ListboxButton,
|
||||
ListboxOption,
|
||||
@@ -57,6 +58,8 @@ function ModelOption({
|
||||
showMissingApiKeyMsg,
|
||||
isSelected,
|
||||
}: ModelOptionProps) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
function handleOptionClick(e: any) {
|
||||
if (showMissingApiKeyMsg) {
|
||||
e.preventDefault();
|
||||
@@ -64,12 +67,18 @@ function ModelOption({
|
||||
}
|
||||
}
|
||||
|
||||
function handleConfigureClick(e: React.MouseEvent) {
|
||||
e.stopPropagation();
|
||||
navigate(CONFIG_ROUTES.MODELS);
|
||||
}
|
||||
|
||||
return (
|
||||
<ListboxOption
|
||||
key={idx}
|
||||
disabled={showMissingApiKeyMsg}
|
||||
value={option.value}
|
||||
onClick={handleOptionClick}
|
||||
className={`group ${isSelected ? "bg-list-active text-list-active-foreground" : ""}`}
|
||||
>
|
||||
<div className="flex w-full items-center justify-between gap-5">
|
||||
<div className="flex items-center gap-2 py-0.5">
|
||||
@@ -88,9 +97,14 @@ function ModelOption({
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<CheckIcon
|
||||
className={`h-3 w-3 flex-shrink-0 ${isSelected ? "" : "invisible"}`}
|
||||
/>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-description-muted hover:enabled:text-foreground my-0 h-4 w-4 p-0 opacity-0 transition-opacity group-hover:opacity-100"
|
||||
onClick={handleConfigureClick}
|
||||
>
|
||||
<Cog6ToothIcon className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</ListboxOption>
|
||||
);
|
||||
@@ -245,8 +259,21 @@ function ModelSelect() {
|
||||
/>
|
||||
</ListboxButton>
|
||||
<ListboxOptions className="min-w-[160px]">
|
||||
<div className="flex items-center justify-between gap-1 px-2 py-1">
|
||||
<span className="text-description font-semibold">Models</span>
|
||||
<div className="flex items-center justify-between px-1.5 py-1">
|
||||
<span className="text-description text-xs font-medium">Models</span>
|
||||
<div className="flex items-center gap-0.5">
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onClickConfigureModels(e);
|
||||
}}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="my-0 h-5 w-5 p-0"
|
||||
>
|
||||
<Cog6ToothIcon className="text-description h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="no-scrollbar max-h-[300px] overflow-y-auto">
|
||||
@@ -274,36 +301,26 @@ function ModelSelect() {
|
||||
|
||||
{!isConfigLoading && (
|
||||
<>
|
||||
<Divider className="!mb-0" />
|
||||
|
||||
{selectedProfile?.profileType === "local" && (
|
||||
<ListboxOption
|
||||
key={options.length}
|
||||
onClick={onClickAddModel}
|
||||
value={"addModel" as any}
|
||||
fontSizeModifier={-2}
|
||||
className="px-2 py-2"
|
||||
>
|
||||
<span className="text-description text-2xs flex flex-row items-center">
|
||||
<PlusIcon className="mr-1.5 h-3.5 w-3.5" />
|
||||
Add Chat model
|
||||
</span>
|
||||
</ListboxOption>
|
||||
<>
|
||||
<Divider className="!mb-0" />
|
||||
<ListboxOption
|
||||
key={options.length}
|
||||
onClick={onClickAddModel}
|
||||
value={"addModel" as any}
|
||||
fontSizeModifier={-2}
|
||||
className="px-2 py-2"
|
||||
>
|
||||
<span className="text-description text-2xs flex flex-row items-center">
|
||||
<PlusIcon className="mr-1.5 h-3.5 w-3.5" />
|
||||
Add Chat model
|
||||
</span>
|
||||
</ListboxOption>
|
||||
</>
|
||||
)}
|
||||
|
||||
<ListboxOption
|
||||
value="configure-models"
|
||||
fontSizeModifier={-2}
|
||||
className="px-2 py-2"
|
||||
onClick={onClickConfigureModels}
|
||||
>
|
||||
<span className="text-description text-2xs flex flex-row items-center">
|
||||
<Cog6ToothIcon className="mr-1.5 h-3.5 w-3.5" />
|
||||
Configure models
|
||||
</span>
|
||||
</ListboxOption>
|
||||
<Divider className="!my-0" />
|
||||
<div className="text-description flex items-center justify-between gap-1.5 px-2 py-2">
|
||||
<div className="text-description flex items-center justify-start p-2">
|
||||
<span className="block" style={{ fontSize: tinyFont }}>
|
||||
<code>{getMetaKeyLabel()}'</code> to toggle model
|
||||
</span>
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import styled from "styled-components";
|
||||
import {
|
||||
defaultBorderRadius,
|
||||
lightGray,
|
||||
vscInputBackground,
|
||||
vscListActiveBackground,
|
||||
vscListActiveForeground,
|
||||
} from "..";
|
||||
|
||||
const TopDiv = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
width: fit-content;
|
||||
cursor: pointer;
|
||||
|
||||
border: 1px solid ${lightGray};
|
||||
|
||||
background-color: ${vscInputBackground};
|
||||
border-radius: ${defaultBorderRadius};
|
||||
|
||||
&:hover {
|
||||
background-color: ${lightGray}55;
|
||||
}
|
||||
`;
|
||||
|
||||
const SubDiv = styled.div<{ selected: boolean }>`
|
||||
text-align: center;
|
||||
padding: 8px 12px;
|
||||
border-radius: ${defaultBorderRadius};
|
||||
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
${(props) =>
|
||||
props.selected &&
|
||||
`
|
||||
background-color: ${vscListActiveBackground};
|
||||
color: ${vscListActiveForeground};
|
||||
`}
|
||||
`;
|
||||
|
||||
function Toggle(props: {
|
||||
optionOne: string;
|
||||
optionTwo: string;
|
||||
selected: boolean;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
return (
|
||||
<TopDiv onClick={props.onClick}>
|
||||
<SubDiv selected={props.selected}>{props.optionOne}</SubDiv>
|
||||
<SubDiv selected={!props.selected}>{props.optionTwo}</SubDiv>
|
||||
</TopDiv>
|
||||
);
|
||||
}
|
||||
|
||||
export default Toggle;
|
||||
@@ -1,5 +1,5 @@
|
||||
import { isOnPremSession } from "core/control-plane/AuthTypes";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import { AssistantAndOrgListbox } from "../../components/AssistantAndOrgListbox";
|
||||
import Alert from "../../components/gui/Alert";
|
||||
@@ -14,17 +14,11 @@ function ConfigPage() {
|
||||
useNavigationListener();
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const [activeTab, setActiveTab] = useState("settings");
|
||||
const [activeTab, setActiveTab] = useState(() => {
|
||||
return searchParams.get("tab") || "settings";
|
||||
});
|
||||
const { session, organizations } = useAuth();
|
||||
|
||||
// Set initial tab from URL parameter
|
||||
useEffect(() => {
|
||||
const tab = searchParams.get("tab");
|
||||
if (tab) {
|
||||
setActiveTab(tab);
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
const allTabs = getAllTabs();
|
||||
const shouldRenderOrgInfo =
|
||||
session && organizations.length > 1 && !isOnPremSession(session);
|
||||
|
||||
@@ -140,9 +140,25 @@ export class AnthropicApi implements BaseLlmApi {
|
||||
],
|
||||
};
|
||||
} else if (message.role === "assistant" && message.tool_calls) {
|
||||
return {
|
||||
role: "assistant",
|
||||
content: message.tool_calls.map((toolCall) => {
|
||||
const parts: any[] = [];
|
||||
if (message.content) {
|
||||
if (typeof message.content === "string") {
|
||||
parts.push({
|
||||
type: "text",
|
||||
text: message.content,
|
||||
});
|
||||
} else if (message.content.length > 0) {
|
||||
parts.push(
|
||||
message.content.map((c) => ({
|
||||
type: "text",
|
||||
text: c.type === "text" ? c.text : c.refusal,
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
parts.push(
|
||||
...message.tool_calls.map((toolCall) => {
|
||||
// Type guard for function tool calls
|
||||
if (toolCall.type === "function" && "function" in toolCall) {
|
||||
return {
|
||||
@@ -158,6 +174,10 @@ export class AnthropicApi implements BaseLlmApi {
|
||||
throw new Error(`Unsupported tool call type: ${toolCall.type}`);
|
||||
}
|
||||
}),
|
||||
);
|
||||
return {
|
||||
role: "assistant",
|
||||
content: parts,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user