Skip to content

feat: allow model to be chosen #30

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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Task" ADD COLUMN "model" TEXT NOT NULL DEFAULT 'claude-sonnet-4-20250514';
1 change: 1 addition & 0 deletions packages/bytebot-agent/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ model Task {
status TaskStatus @default(PENDING)
priority TaskPriority @default(MEDIUM)
control Role @default(ASSISTANT)
model String @default("claude-sonnet-4-20250514")
createdAt DateTime @default(now())
createdBy Role @default(USER)
scheduledFor DateTime?
Expand Down
5 changes: 3 additions & 2 deletions packages/bytebot-agent/src/anthropic/anthropic.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,16 @@ export class AnthropicService {
* Sends a message to Anthropic Claude and returns the response
*
* @param messages Array of message content blocks representing the conversation
* @param options Additional options for the API call
* @param selectedModel The LLM model to use for the request
* @returns The AI response as an array of message content blocks
*/

async sendMessage(
messages: Message[],
signal?: AbortSignal,
): Promise<MessageContentBlock[]> {
try {
const model = DEFAULT_MODEL;
const model = selectedModel || DEFAULT_MODEL;
const maxTokens = 8192;

// Convert our message content blocks to Anthropic's expected format
Expand Down
21 changes: 21 additions & 0 deletions packages/bytebot-agent/src/common/constants/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Model identifiers using actual Anthropic model names
export const CLAUDE_SONNET_4 = 'claude-sonnet-4-20250514';
export const CLAUDE_OPUS_4 = 'claude-opus-4-20250514';

export const MODEL_DISPLAY_NAMES = {
[CLAUDE_SONNET_4]: 'Claude Sonnet 4.0',
[CLAUDE_OPUS_4]: 'Claude Opus 4.0',
} as const;

export const SUPPORTED_MODELS = [
{
value: CLAUDE_SONNET_4,
label: MODEL_DISPLAY_NAMES[CLAUDE_SONNET_4],
},
{
value: CLAUDE_OPUS_4,
label: MODEL_DISPLAY_NAMES[CLAUDE_OPUS_4],
},
] as const;

export const DEFAULT_MODEL = CLAUDE_SONNET_4;
4 changes: 4 additions & 0 deletions packages/bytebot-agent/src/tasks/dto/create-task.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ export class CreateTaskDto {
@IsOptional()
@IsString()
createdBy?: Role;

@IsOptional()
@IsString()
model?: string;
}
2 changes: 2 additions & 0 deletions packages/bytebot-agent/src/tasks/tasks.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from '@prisma/client';
import { GuideTaskDto } from './dto/guide-task.dto';
import { TasksGateway } from './tasks.gateway';
import { DEFAULT_MODEL } from '../common/constants/models';
import { ConfigService } from '@nestjs/config';
import { EventEmitter2 } from '@nestjs/event-emitter';

Expand Down Expand Up @@ -52,6 +53,7 @@ export class TasksService {
priority: createTaskDto.priority || TaskPriority.MEDIUM,
status: TaskStatus.PENDING,
createdBy: createTaskDto.createdBy || Role.USER,
model: createTaskDto.model || DEFAULT_MODEL,
...(createTaskDto.scheduledFor
? { scheduledFor: createTaskDto.scheduledFor }
: {}),
Expand Down
28 changes: 19 additions & 9 deletions packages/bytebot-ui/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from "@/components/ui/select";
import { startTask } from "@/utils/taskUtils";
import { TaskList } from "@/components/tasks/TaskList";
import { SUPPORTED_MODELS, DEFAULT_MODEL } from "@/constants/models";

// Stock photo component for easy image switching
interface StockPhotoProps {
Expand All @@ -37,6 +38,7 @@ const StockPhoto: React.FC<StockPhotoProps> = ({

export default function Home() {
const [input, setInput] = useState("");
const [selectedModel, setSelectedModel] = useState<string>(DEFAULT_MODEL);
const [isLoading, setIsLoading] = useState(false);
const router = useRouter();
const [activePopoverIndex, setActivePopoverIndex] = useState<number | null>(
Expand Down Expand Up @@ -82,7 +84,7 @@ export default function Home() {

try {
// Send request to start a new task
const task = await startTask(input);
const task = await startTask(input, selectedModel);

if (task && task.id) {
// Redirect to the task page
Expand Down Expand Up @@ -223,21 +225,25 @@ export default function Home() {
</p>
</div>

<div className="bg-bytebot-bronze-light-2 border-bytebot-bronze-light-5 shadow-bytebot w-full rounded-2xl border-[0.5px] p-2">
<div className="bg-bytebot-bronze-light-2 border-bytebot-bronze-light-5 shadow-bytebot w-full rounded-2xl border-[0.5px] p-3">
<ChatInput
input={input}
isLoading={isLoading}
onInputChange={setInput}
onSend={handleSend}
minLines={3}
/>
<div className="mt-2">
<Select defaultValue="sonnet-4">
<div className="mt-3">
<Select value={selectedModel} onValueChange={(value) => setSelectedModel(value)}>
<SelectTrigger className="w-auto">
<SelectValue placeholder="Select a model" />
</SelectTrigger>
<SelectContent>
<SelectItem value="sonnet-4">Model: Sonnet 4</SelectItem>
{SUPPORTED_MODELS.map((model) => (
<SelectItem key={model.value} value={model.value}>
{model.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
Expand Down Expand Up @@ -273,21 +279,25 @@ export default function Home() {
</p>
</div>

<div className="bg-bytebot-bronze-light-2 border-bytebot-bronze-light-5 shadow-bytebot w-full rounded-2xl border-[0.5px] p-2">
<div className="bg-bytebot-bronze-light-2 border-bytebot-bronze-light-5 shadow-bytebot w-full rounded-2xl border-[0.5px] p-3">
<ChatInput
input={input}
isLoading={isLoading}
onInputChange={setInput}
onSend={handleSend}
minLines={3}
/>
<div className="mt-2">
<Select defaultValue="sonnet-4">
<div className="mt-3">
<Select value={selectedModel} onValueChange={(value) => setSelectedModel(value)}>
<SelectTrigger className="w-auto">
<SelectValue placeholder="Select a model" />
</SelectTrigger>
<SelectContent>
<SelectItem value="sonnet-4">Model: Sonnet 4</SelectItem>
{SUPPORTED_MODELS.map((model) => (
<SelectItem key={model.value} value={model.value}>
{model.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
Expand Down
11 changes: 1 addition & 10 deletions packages/bytebot-ui/src/app/tasks/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ export default function TaskPage() {
</div>

{/* Fixed chat input */}

{taskStatus === TaskStatus.NEEDS_HELP && (
<div className="bg-bytebot-bronze-light-2 border-bytebot-bronze-light-5 shadow-bytebot rounded-2xl border-[0.5px] p-2">
<ChatInput
Expand All @@ -228,16 +229,6 @@ export default function TaskPage() {
onSend={handleGuideTask}
minLines={1}
/>
<div className="mt-2">
<Select value="sonnet-4">
<SelectTrigger className="w-auto">
<SelectValue placeholder="Select an model" />
</SelectTrigger>
<SelectContent>
<SelectItem value="sonnet-4">Sonnet 4</SelectItem>
</SelectContent>
</Select>
</div>
</div>
)}
</div>
Expand Down
4 changes: 2 additions & 2 deletions packages/bytebot-ui/src/components/ui/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const SelectTrigger = React.forwardRef<
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-6 w-full items-center justify-between rounded-md border border-bytebot-bronze-light-7 bg-bytebot-bronze-light-1 pr-1 pl-2 py-[0.5px] text-[12px] text-bytebot-bronze-dark-9 ring-offset-bytebot-bronze-light-7 placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"flex h-7 w-full items-center cursor-pointer justify-between rounded-md border border-bytebot-bronze-light-7 bg-bytebot-bronze-light-1 pr-1 pl-2 py-[0.5px] text-[12px] text-bytebot-bronze-dark-9 ring-offset-bytebot-bronze-light-7 placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
Expand Down Expand Up @@ -82,7 +82,7 @@ const SelectItem = React.forwardRef<
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full justify-between cursor-default select-none items-center rounded-sm py-[0.5px] px-1 text-[12px] text-bytebot-bronze-dark-9 outline-none focus:bg-bytebot-bronze-light-5 focus:text-bytebot-bronze-dark-9 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
"relative flex w-full cursor-pointer justify-between select-none items-center rounded-sm py-1 px-1 text-[12px] text-bytebot-bronze-dark-9 outline-none focus:bg-bytebot-bronze-light-5 focus:text-bytebot-bronze-dark-9 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
Expand Down
21 changes: 21 additions & 0 deletions packages/bytebot-ui/src/constants/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Model identifiers using actual Anthropic model names
export const CLAUDE_SONNET_4 = 'claude-sonnet-4-20250514';
export const CLAUDE_OPUS_4 = 'claude-opus-4-20250514';

export const MODEL_DISPLAY_NAMES = {
[CLAUDE_SONNET_4]: 'Claude Sonnet 4.0',
[CLAUDE_OPUS_4]: 'Claude Opus 4.0',
} as const;

export const SUPPORTED_MODELS = [
{
value: CLAUDE_SONNET_4,
label: MODEL_DISPLAY_NAMES[CLAUDE_SONNET_4],
},
{
value: CLAUDE_OPUS_4,
label: MODEL_DISPLAY_NAMES[CLAUDE_OPUS_4],
},
] as const;

export const DEFAULT_MODEL = CLAUDE_SONNET_4;
5 changes: 3 additions & 2 deletions packages/bytebot-ui/src/utils/taskUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ export async function fetchTaskById(taskId: string): Promise<Task | null> {
/**
* Sends a message to start a new task or continue an existing one
* @param message The message content to send
* @param model The LLM model to use for the task
* @returns The task data or null if there was an error
*/

export async function startTask(message: string): Promise<Task | null> {
export async function startTask(message: string, model: string): Promise<Task | null> {
try {
const response = await fetch(
`/api/tasks`,
Expand All @@ -72,7 +73,7 @@ export async function startTask(message: string): Promise<Task | null> {
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ description: message }),
body: JSON.stringify({ description: message, model }),
},
);

Expand Down