Skip to content
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
Expand Up @@ -32,6 +32,7 @@
public class Anthropic implements AIModel {

public static final String NAME = "anthropic";
public static final int DEFAULT_MAX_TOKENS = 8192;
private final AnthropicConfiguration config;

private final AnthropicMessagesApi messagesApi;
Expand Down Expand Up @@ -74,9 +75,14 @@ public ChatOptions getChatOptions(ChatCompletion input) {
temperature = 1.0; // Thinking mode requires temperature=1
}

Integer maxTokens = input.getMaxTokens();
if (maxTokens == null || maxTokens <= 0) {
maxTokens = DEFAULT_MAX_TOKENS;
}

return AnthropicChatOptions.builder()
.model(input.getModel())
.maxTokens(input.getMaxTokens())
.maxTokens(maxTokens)
.temperature(temperature)
.topP(input.getTopP())
.topK(input.getTopK())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
@Slf4j
public class AnthropicChatModel implements ChatModel {

private static final int DEFAULT_MAX_TOKENS = 8192;

private final AnthropicMessagesApi messagesApi;
private final ObjectMapper objectMapper = new ObjectMapper();

Expand Down Expand Up @@ -93,15 +95,18 @@ private MessagesRequest buildRequest(Prompt prompt) {
messages.addAll(convertMessage(msg));
}

// Extract options
// Extract options — Spring AI's ChatClient may merge AnthropicChatOptions with
// ToolCallingChatOptions (the model's default), producing a non-Anthropic type.
// We handle both cases and always guarantee max_tokens (required by Anthropic API).
AnthropicChatOptions opts = options instanceof AnthropicChatOptions aco ? aco : null;

MessagesRequest.Builder builder =
MessagesRequest.builder().messages(messages).system(system);

if (opts != null) {
Integer maxTokens = opts.getMaxTokens();
builder.model(opts.getModel())
.maxTokens(opts.getMaxTokens())
.maxTokens(maxTokens != null && maxTokens > 0 ? maxTokens : DEFAULT_MAX_TOKENS)
.temperature(opts.getTemperature())
.topP(opts.getTopP())
.topK(opts.getTopK())
Expand All @@ -123,12 +128,15 @@ private MessagesRequest buildRequest(Prompt prompt) {
}
}
} else if (options != null) {
Integer maxTokens = options.getMaxTokens();
builder.model(options.getModel())
.maxTokens(options.getMaxTokens())
.maxTokens(maxTokens != null && maxTokens > 0 ? maxTokens : DEFAULT_MAX_TOKENS)
.temperature(options.getTemperature())
.topP(options.getTopP())
.topK(options.getTopK())
.stopSequences(options.getStopSequences());
} else {
builder.maxTokens(DEFAULT_MAX_TOKENS);
}

return builder.build();
Expand Down
80 changes: 44 additions & 36 deletions ui-next/src/components/ui/ConductorSliderStateless.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ const CustomSlider = styled(Slider, {
},
"& .MuiSlider-thumb": {
backgroundColor: sliderColor,
width: "17px",
height: "17px",
width: "14px",
height: "14px",
},
}));

Expand All @@ -34,6 +34,7 @@ const labelStyle = {
color: greyText,
fontSize: "12px",
fontWeight: 300,
lineHeight: 1.2,
};

const ConductorSliderStateless = ({
Expand All @@ -48,49 +49,35 @@ const ConductorSliderStateless = ({
...rest
}: ConductorSliderStatelessProps) => {
const textFieldStyle = {
marginLeft: "10px",
flexShrink: 0,
"& .MuiOutlinedInput-root": {
height: "22px",
"&.Mui-focused fieldset": {
borderColor: sliderColor,
borderWidth: "1px",
},
},
"& .MuiInputBase-input": {
padding: "1px 4px",
fontSize: "0.75rem",
},
};

return (
<Box>
<Box display="flex" justifyContent="space-between">
{label && <Box sx={labelStyle}>{label}</Box>}
{textBox && (
<TextField
sx={textFieldStyle}
value={value?.toString()}
size="small"
type="number"
onChange={handleInputChange}
onBlur={handleBlur}
inputProps={{
min: min,
max: max,
type: "number",
"aria-labelledby": "input-slider",
style: {
textAlign: "center",
width: "30px",
fontWeight: 600,
},
}}
/>
)}
</Box>

<Box
sx={{
display: "flex",
alignItems: "center",
px: 2,
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
gap: 1.5,
py: 0.5,
}}
>
{label && (
<Box sx={{ ...labelStyle, minWidth: "100px", flexShrink: 0 }}>
{label}
</Box>
)}
<Box sx={{ flex: 1, px: 0.5 }}>
<CustomSlider
value={value}
min={min}
Expand All @@ -99,6 +86,27 @@ const ConductorSliderStateless = ({
{...rest}
/>
</Box>
{textBox && (
<TextField
sx={textFieldStyle}
value={value?.toString()}
size="small"
type="number"
onChange={handleInputChange}
onBlur={handleBlur}
inputProps={{
min: min,
max: max,
type: "number",
"aria-labelledby": "input-slider",
style: {
textAlign: "center",
width: "30px",
fontWeight: 600,
},
}}
/>
)}
</Box>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,22 @@ export const LLMChatCompleteTaskForm = ({ task, onChange }: TaskFormProps) => {
>
{(actor) => (
<Box padding={1} width="100%">
<TaskFormSection
accordionAdditionalProps={{ defaultExpanded: true }}
title="Provider and Model"
>
<TaskFormSection title="Prompt and Variables">
<LLMFormFields
task={task}
onChange={onChange}
fieldFieldComponents={modelFieldComponents}
fieldFieldComponents={promptFieldComponents}
actor={actor}
/>
</TaskFormSection>
<TaskFormSection title="Prompt and Variables">
<TaskFormSection
accordionAdditionalProps={{ defaultExpanded: true }}
title="Provider and Model"
>
<LLMFormFields
task={task}
onChange={onChange}
fieldFieldComponents={promptFieldComponents}
fieldFieldComponents={modelFieldComponents}
actor={actor}
/>
</TaskFormSection>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { useInterpret } from "@xstate/react";
import React from "react";
import { TaskDef } from "types";
import { UiIntegrationsFieldType } from "types/FormFieldTypes";
import { FieldComponentType, updateField } from "utils/fieldHelpers";
Expand Down Expand Up @@ -61,12 +61,39 @@ const LLMFormFieldsWrapper = ({
event.task,
);

const taskWithSelectedPromptName = updateField(
let taskWithSelectedPromptName = updateField(
`inputParameters.${UiIntegrationsFieldType.PROMPT_NAME}`,
maybeAvailablePromptName?.name,
taskWithVariables,
);

// Auto-populate temperature if available in the prompt
if (maybeAvailablePromptName.temperature != null) {
taskWithSelectedPromptName = updateField(
`inputParameters.${UiIntegrationsFieldType.TEMPERATURE}`,
maybeAvailablePromptName.temperature,
taskWithSelectedPromptName,
);
}

// Auto-populate topP if available in the prompt
if (maybeAvailablePromptName.topP != null) {
taskWithSelectedPromptName = updateField(
`inputParameters.${UiIntegrationsFieldType.TOP_P}`,
maybeAvailablePromptName.topP,
taskWithSelectedPromptName,
);
}

// Auto-populate stopWords if available in the prompt
if (maybeAvailablePromptName.stopWords != null) {
taskWithSelectedPromptName = updateField(
`inputParameters.stopWords`,
maybeAvailablePromptName.stopWords,
taskWithSelectedPromptName,
);
}

onChange(taskWithSelectedPromptName);
} else {
const updatedTask = updateField(
Expand Down Expand Up @@ -103,12 +130,39 @@ const LLMFormFieldsWrapper = ({
event.task,
);

const taskWithSelectedPromptName = updateField(
let taskWithSelectedPromptName = updateField(
`inputParameters.${UiIntegrationsFieldType.INSTRUCTIONS}`,
maybeAvailablePromptName?.name,
taskWithVariables,
);

// Auto-populate temperature if available in the prompt
if (maybeAvailablePromptName.temperature != null) {
taskWithSelectedPromptName = updateField(
`inputParameters.${UiIntegrationsFieldType.TEMPERATURE}`,
maybeAvailablePromptName.temperature,
taskWithSelectedPromptName,
);
}

// Auto-populate topP if available in the prompt
if (maybeAvailablePromptName.topP != null) {
taskWithSelectedPromptName = updateField(
`inputParameters.${UiIntegrationsFieldType.TOP_P}`,
maybeAvailablePromptName.topP,
taskWithSelectedPromptName,
);
}

// Auto-populate stopWords if available in the prompt
if (maybeAvailablePromptName.stopWords != null) {
taskWithSelectedPromptName = updateField(
`inputParameters.stopWords`,
maybeAvailablePromptName.stopWords,
taskWithSelectedPromptName,
);
}

onChange(taskWithSelectedPromptName);
} else {
const updatedTask = updateField(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,7 @@ export const persistError = assign<
>({
error: (_, { data }) => ({ message: data, severity: "error" }),
});

export const persistSelectedPrompt = assign<LLMFormFieldsMachineContext, any>({
selectedPrompt: (_, event: any) => event.prompt,
});
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const llmFormFieldsMachine = createMachine<
indexOptions: [],
embeddingModelOptions: [],
selectedPromptName: undefined,
selectedPrompt: null,
},
states: {
[LLMFormFieldsMachineStates.DETERMINE_INITIAL_STATE]: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export const fetchForPromptNames = async (
) => {
const maybeLlmProvider = task?.inputParameters?.llmProvider;
const maybeModel = task?.inputParameters?.model;

// If provider and model are both set, fetch prompts for that specific combination
if (maybeModel && maybeLlmProvider) {
const path = `/integrations/provider/${maybeLlmProvider}/integration/${maybeModel}/prompt`;
try {
Expand All @@ -62,7 +64,20 @@ export const fetchForPromptNames = async (
return [];
}
}
return [];

// If provider/model are not set, fetch all prompts so users can see them
// This allows selecting a prompt before selecting provider/model
try {
const path = `/prompts`;
const response = await queryClient.fetchQuery(
[fetchContext.stack, path],
() => fetchWithContext(path, fetchContext, { headers }),
);
return response;
} catch (error) {
logger.error(error);
return [];
}
};

export const fetchForVectorDb = async ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export type LLMFormFieldsEvents =
export interface LLMFormFieldsMachineContext {
fields: UiIntegrationsFieldType[];
selectedPromptName?: Record<string, unknown>;
selectedPrompt?: PromptDef | null;
authHeaders?: AuthHeaders;
llmProviderOptions: [];
promptNameOptions: PromptDef[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,22 @@ export const LLMTextCompleteTaskForm = ({ task, onChange }: TaskFormProps) => {
>
{(actor) => (
<Box padding={1} width="100%">
<TaskFormSection
accordionAdditionalProps={{ defaultExpanded: true }}
title="Provider and Model"
>
<TaskFormSection title="Prompt and Variables">
<LLMFormFields
task={task}
onChange={onChange}
fieldFieldComponents={modelFieldComponents}
fieldFieldComponents={promptFieldComponents}
actor={actor}
/>
</TaskFormSection>
<TaskFormSection title="Prompt and Variables">
<TaskFormSection
accordionAdditionalProps={{ defaultExpanded: true }}
title="Provider and Model"
>
<LLMFormFields
task={task}
onChange={onChange}
fieldFieldComponents={promptFieldComponents}
fieldFieldComponents={modelFieldComponents}
actor={actor}
/>
</TaskFormSection>
Expand Down
Loading
Loading