diff --git a/apps/beeai-sdk-py/examples/settings_agent.py b/apps/beeai-sdk-py/examples/settings_agent.py
index a76188aaf..55cd499e1 100644
--- a/apps/beeai-sdk-py/examples/settings_agent.py
+++ b/apps/beeai-sdk-py/examples/settings_agent.py
@@ -10,9 +10,11 @@
from beeai_sdk.a2a.extensions.ui.settings import (
CheckboxField,
CheckboxGroupField,
+ OptionItem,
SettingsExtensionServer,
SettingsExtensionSpec,
SettingsRender,
+ SingleSelectField,
)
from beeai_sdk.a2a.types import RunYield
from beeai_sdk.server import Server
@@ -39,7 +41,17 @@ async def settings_agent(
default_value=True,
)
],
- )
+ ),
+ SingleSelectField(
+ id="response_style",
+ label="Response Style",
+ options=[
+ OptionItem(value="concise", label="Concise"),
+ OptionItem(value="detailed", label="Detailed"),
+ OptionItem(value="humorous", label="Humorous"),
+ ],
+ default_value="concise",
+ ),
],
),
),
diff --git a/apps/beeai-ui/src/modules/runs/settings/SingleSelectSettingsField.module.scss b/apps/beeai-ui/src/components/RadioSelect/RadioSelect.module.scss
similarity index 100%
rename from apps/beeai-ui/src/modules/runs/settings/SingleSelectSettingsField.module.scss
rename to apps/beeai-ui/src/components/RadioSelect/RadioSelect.module.scss
diff --git a/apps/beeai-ui/src/components/RadioSelect/RadioSelect.tsx b/apps/beeai-ui/src/components/RadioSelect/RadioSelect.tsx
new file mode 100644
index 000000000..24bb35318
--- /dev/null
+++ b/apps/beeai-ui/src/components/RadioSelect/RadioSelect.tsx
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2025 © BeeAI a Series of LF Projects, LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { Checkmark } from '@carbon/icons-react';
+import { RadioButton, RadioButtonGroup } from '@carbon/react';
+import clsx from 'clsx';
+import { useId } from 'react';
+
+import classes from './RadioSelect.module.scss';
+
+interface Props {
+ name: string;
+ label: string;
+ value?: string;
+ options: { value: string; label: string }[];
+ onChange: (value: string) => void;
+}
+
+export function RadioSelect({ name, label, value, options, onChange }: Props) {
+ const htmlId = useId();
+
+ return (
+
+ {options.map(({ value: optionValue, label }) => {
+ const isSelected = optionValue === value;
+ return (
+
+ onChange(optionValue)}
+ />
+ {optionValue === value && }
+
+ );
+ })}
+
+ );
+}
diff --git a/apps/beeai-ui/src/modules/form/components/FormActionBar.module.scss b/apps/beeai-ui/src/modules/form/components/FormActionBar.module.scss
new file mode 100644
index 000000000..536407541
--- /dev/null
+++ b/apps/beeai-ui/src/modules/form/components/FormActionBar.module.scss
@@ -0,0 +1,22 @@
+/**
+ * Copyright 2025 © BeeAI a Series of LF Projects, LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.root {
+ display: grid;
+ grid-template-columns: 1fr max-content;
+ align-items: center;
+}
+
+.settings {
+ display: flex;
+ gap: $spacing-03;
+}
+
+.buttons {
+ display: flex;
+ justify-content: flex-end;
+ text-align: end;
+ gap: $spacing-04;
+}
diff --git a/apps/beeai-ui/src/modules/form/components/FormActionBar.tsx b/apps/beeai-ui/src/modules/form/components/FormActionBar.tsx
new file mode 100644
index 000000000..e8b0bc4ef
--- /dev/null
+++ b/apps/beeai-ui/src/modules/form/components/FormActionBar.tsx
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2025 © BeeAI a Series of LF Projects, LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { Button } from '@carbon/react';
+import { useMergeRefs } from '@floating-ui/react';
+
+import { useApp } from '#contexts/App/index.ts';
+import { RunModels } from '#modules/runs/settings/RunModels.tsx';
+import { RunSettings } from '#modules/runs/settings/RunSettings.tsx';
+import { useRunSettingsDialog } from '#modules/runs/settings/useRunSettingsDialog.ts';
+
+import classes from './FormActionBar.module.scss';
+
+interface Props {
+ showSubmitButton?: boolean;
+ submitLabel: string;
+ showRunSettings?: boolean;
+}
+
+export function FormActionBar({ showSubmitButton = true, submitLabel, showRunSettings }: Props) {
+ const {
+ config: { featureFlags },
+ } = useApp();
+
+ const modelsDialog = useRunSettingsDialog({ blockOffset: 8 });
+ const settingsDialog = useRunSettingsDialog({ blockOffset: 8 });
+ const formRefs = useMergeRefs([modelsDialog.refs.setPositionReference, settingsDialog.refs.setPositionReference]);
+
+ return (
+
+ {showRunSettings && (
+
+
+ {featureFlags.ModelProviders && }
+
+ )}
+ {showSubmitButton && (
+
+
+
+ )}
+
+ );
+}
diff --git a/apps/beeai-ui/src/modules/form/components/FormRenderer.module.scss b/apps/beeai-ui/src/modules/form/components/FormRenderer.module.scss
index 5e3dbac5c..33a309309 100644
--- a/apps/beeai-ui/src/modules/form/components/FormRenderer.module.scss
+++ b/apps/beeai-ui/src/modules/form/components/FormRenderer.module.scss
@@ -8,17 +8,3 @@
flex-direction: column;
row-gap: $spacing-06;
}
-
-.fields {
- display: grid;
- column-gap: $spacing-04;
- row-gap: $spacing-06;
- grid-template-columns: repeat(var(--grid-columns, 1), minmax(0, 1fr));
-}
-
-.buttons {
- display: flex;
- justify-content: flex-end;
- text-align: end;
- gap: $spacing-04;
-}
diff --git a/apps/beeai-ui/src/modules/form/components/FormRenderer.tsx b/apps/beeai-ui/src/modules/form/components/FormRenderer.tsx
index 4483d8ace..febdd2a58 100644
--- a/apps/beeai-ui/src/modules/form/components/FormRenderer.tsx
+++ b/apps/beeai-ui/src/modules/form/components/FormRenderer.tsx
@@ -3,7 +3,6 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import { Button } from '@carbon/react';
import type { FormRender } from 'beeai-sdk';
import { FormProvider, useForm } from 'react-hook-form';
@@ -13,6 +12,7 @@ import { isNotNull } from '#utils/helpers.ts';
import type { RunFormValues } from '../types';
import { getDefaultValues } from '../utils';
+import { FormActionBar } from './FormActionBar';
import { FormFields } from './FormFields';
import classes from './FormRenderer.module.scss';
@@ -21,6 +21,7 @@ interface Props {
defaultHeading?: string | null;
showHeading?: boolean;
isDisabled?: boolean;
+ showRunSettings?: boolean;
onSubmit: (values: RunFormValues) => void;
}
@@ -28,6 +29,7 @@ export function FormRenderer({
definition,
defaultHeading,
showHeading: showHeadingProp = true,
+ showRunSettings,
isDisabled,
onSubmit,
}: Props) {
@@ -52,15 +54,11 @@ export function FormRenderer({
- {!isDisabled && (
- <>
-
-
-
- >
- )}
+
diff --git a/apps/beeai-ui/src/modules/runs/components/FormRenderView.tsx b/apps/beeai-ui/src/modules/runs/components/FormRenderView.tsx
index 1b19f48b9..869eac777 100644
--- a/apps/beeai-ui/src/modules/runs/components/FormRenderView.tsx
+++ b/apps/beeai-ui/src/modules/runs/components/FormRenderView.tsx
@@ -27,6 +27,7 @@ export function FormRenderView({ formRender }: Props) {
{
const form = {
request: formRender,
diff --git a/apps/beeai-ui/src/modules/runs/components/MCPConfig.tsx b/apps/beeai-ui/src/modules/runs/components/MCPConfig.tsx
index df0938989..456dd6465 100644
--- a/apps/beeai-ui/src/modules/runs/components/MCPConfig.tsx
+++ b/apps/beeai-ui/src/modules/runs/components/MCPConfig.tsx
@@ -16,9 +16,14 @@ export function MCPConfig() {
const id = useId();
const { selectedMCPServers, selectMCPServer } = useAgentDemands();
+ const entries = Object.entries(selectedMCPServers);
+ if (!entries.length) {
+ return null;
+ }
+
return (
- {Object.entries(selectedMCPServers).map(([key, value]) => (
+ {entries.map(([key, value]) => (
selectMCPServer(key, e.target.value)}
diff --git a/apps/beeai-ui/src/modules/runs/components/ModelProviders.tsx b/apps/beeai-ui/src/modules/runs/components/ModelProviders.tsx
deleted file mode 100644
index b34ef57d7..000000000
--- a/apps/beeai-ui/src/modules/runs/components/ModelProviders.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * Copyright 2025 © BeeAI a Series of LF Projects, LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { ModelAlt } from '@carbon/icons-react';
-import { Select, SelectItem } from '@carbon/react';
-import type { ChangeEvent } from 'react';
-import { useId, useMemo } from 'react';
-
-import { Tooltip } from '#components/Tooltip/Tooltip.tsx';
-
-import { useAgentDemands } from '../contexts/agent-demands';
-import classes from './ModelProviders.module.scss';
-
-export function ModelProviders() {
- const {
- matchedLLMProviders,
- selectedLLMProviders,
- selectLLMProvider,
- matchedEmbeddingProviders,
- selectedEmbeddingProviders,
- selectEmbeddingProvider,
- } = useAgentDemands();
-
- const htmlId = useId();
-
- const llmProviderList = useMemo(
- () => Object.entries(matchedLLMProviders || {}).map(([key, items]) => ({ key, items })),
- [matchedLLMProviders],
- );
-
- const embeddingProviderList = useMemo(
- () => Object.entries(matchedEmbeddingProviders || {}).map(([key, items]) => ({ key, items })),
- [matchedEmbeddingProviders],
- );
-
- return (
-
- {llmProviderList.map(({ key, items }) => (
-
-
-
-
-
-
- ))}
- {embeddingProviderList.map(({ key, items }) => (
-
-
-
-
-
-
- ))}
-
- );
-}
diff --git a/apps/beeai-ui/src/modules/runs/components/RunInput.module.scss b/apps/beeai-ui/src/modules/runs/components/RunInput.module.scss
index f23c36a77..6575b34e2 100644
--- a/apps/beeai-ui/src/modules/runs/components/RunInput.module.scss
+++ b/apps/beeai-ui/src/modules/runs/components/RunInput.module.scss
@@ -43,7 +43,7 @@
.actionBarStart {
display: flex;
align-items: center;
- gap: $spacing-03;
+ column-gap: $spacing-01;
}
.submit {
diff --git a/apps/beeai-ui/src/modules/runs/components/RunInput.tsx b/apps/beeai-ui/src/modules/runs/components/RunInput.tsx
index 11a6356b0..de738020a 100644
--- a/apps/beeai-ui/src/modules/runs/components/RunInput.tsx
+++ b/apps/beeai-ui/src/modules/runs/components/RunInput.tsx
@@ -4,6 +4,7 @@
*/
import { InlineLoading } from '@carbon/react';
+import { useMergeRefs } from '@floating-ui/react';
import { useCallback, useRef, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { mergeRefs } from 'react-merge-refs';
@@ -17,10 +18,11 @@ import { dispatchInputEventOnTextarea, submitFormOnEnter } from '#utils/form-uti
import { ChatDefaultTools } from '../chat/constants';
import { useAgentRun } from '../contexts/agent-run';
+import { RunModels } from '../settings/RunModels';
import { RunSettings } from '../settings/RunSettings';
+import { useRunSettingsDialog } from '../settings/useRunSettingsDialog';
import type { RunRunFormValues } from '../types';
import { MCPConfig } from './MCPConfig';
-import { ModelProviders } from './ModelProviders';
import { PromptExamples } from './PromptExamples';
import { RunFiles } from './RunFiles';
import classes from './RunInput.module.scss';
@@ -42,6 +44,8 @@ export function RunInput({ promptExamples, onMessageSent }: Props) {
config: { featureFlags },
} = useApp();
+ const { hasMessages } = useAgentRun();
+
const {
agent: {
ui: { interaction_mode, input_placeholder },
@@ -96,11 +100,21 @@ export function RunInput({ promptExamples, onMessageSent }: Props) {
[setValue, dispatchInputEventAndFocus],
);
+ const modelsDialog = useRunSettingsDialog({
+ maxWidth: hasMessages ? undefined : MODELS_DIALOG_MAX_WIDTH,
+ });
+ const settingsDialog = useRunSettingsDialog();
+ const formRefs = useMergeRefs([
+ hasMessages ? modelsDialog.refs.setPositionReference : null,
+ settingsDialog.refs.setPositionReference,
+ formRef,
+ ]);
+
return (