diff --git a/src/renderer/components/Experiment/DynamicPluginForm.tsx b/src/renderer/components/Experiment/DynamicPluginForm.tsx
index 9e9733b5598792a966d4e52e5a9f23463a8f8b5d..a2455bad467f401268d0bbbddc49b007178be276 100644
--- a/src/renderer/components/Experiment/DynamicPluginForm.tsx
+++ b/src/renderer/components/Experiment/DynamicPluginForm.tsx
@@ -22,10 +22,11 @@ import {
   Slider,
   Stack,
   Option,
-  Autocomplete
+  Autocomplete,
 } from '@mui/joy';
 import { useMemo } from 'react';
 import ModelProviderWidget from 'renderer/components/Experiment/Widgets/ModelProviderWidget';
+import CustomEvaluationWidget from './Widgets/CustomEvaluationWidget';
 
 import {
   RegistryWidgetsType,
@@ -421,7 +422,13 @@ function CustomAutocompleteWidget<T = any, S extends StrictRJSFSchema = RJSFSche
   // Determine default value.
   const defaultValue = _multiple ? [] : '';
   // Use the provided value or fallback to default.
-  const currentValue = value !== undefined ? value : defaultValue;
+  let currentValue = value !== undefined ? value : defaultValue;
+
+  // Check if currentValue is an array, if a string, convert it to an array.
+  const isString = typeof currentValue === 'string';
+  if (isString) {
+    currentValue = currentValue.split(',');
+  }
 
   // Map enumOptions into objects with label and value.
   const processedOptionsValues = enumOptions.map((opt) =>
@@ -492,6 +499,7 @@ const widgets: RegistryWidgetsType = {
   RangeWidget: CustomRange,
   SelectWidget: CustomSelectSimple,
   AutoCompleteWidget: CustomAutocompleteWidget,
+  EvaluationWidget: CustomEvaluationWidget,
   ModelProviderWidget: ModelProviderWidget
 };
 
diff --git a/src/renderer/components/Experiment/Eval/EvalTasksTable.tsx b/src/renderer/components/Experiment/Eval/EvalTasksTable.tsx
index 20b8861dad8e6dd94844c63727342dcf5e4ba8ef..68220d9b06ec180e2d05df2968563d10695d82df 100644
--- a/src/renderer/components/Experiment/Eval/EvalTasksTable.tsx
+++ b/src/renderer/components/Experiment/Eval/EvalTasksTable.tsx
@@ -20,7 +20,20 @@ function formatTemplateConfig(script_parameters): ReactElement {
   // Remove the author/full path from the model name for cleanliness
   // const short_model_name = c.model_name.split('/').pop();
   // Set main_task as either or the metric name from the script parameters
-  const main_task = script_parameters.tasks
+  const main_task = (() => {
+    if (script_parameters.tasks) {
+      try {
+        const tasksArray = JSON.parse(script_parameters.tasks);
+        if (Array.isArray(tasksArray)) {
+          return tasksArray.map((task) => task.name).join(', ');
+        }
+      } catch (error) {
+        // Invalid JSON; fall back to the original value
+      }
+      return script_parameters.tasks;
+    }
+    return script_parameters.tasks;
+  })();
   const dataset_name = script_parameters.dataset_name
     ? script_parameters.dataset_name
     : 'N/A';
diff --git a/src/renderer/components/Experiment/Eval/ViewCSVModal.tsx b/src/renderer/components/Experiment/Eval/ViewCSVModal.tsx
index 40e8b81517f5b8fe12403a7e7405fd4e3eb35962..e933f1c9f63d27f72699b673da332baefce2f65e 100644
--- a/src/renderer/components/Experiment/Eval/ViewCSVModal.tsx
+++ b/src/renderer/components/Experiment/Eval/ViewCSVModal.tsx
@@ -75,7 +75,8 @@ function formatEvalData(data) {
 }
 
 function formatArrayOfScores(scores) {
-  const formattedScores = scores.map((score) => {
+  const scoresArray = Array.isArray(scores) ? scores : [scores];
+  const formattedScores = scoresArray.map((score) => {
     const metricName = Object.keys(score)[0];
     const value = Object.values(score)[0];
 
diff --git a/src/renderer/components/Experiment/Widgets/CustomEvaluationWidget.tsx b/src/renderer/components/Experiment/Widgets/CustomEvaluationWidget.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..2ffc64ca24df8005cc5147e27d3729e072a4eb70
--- /dev/null
+++ b/src/renderer/components/Experiment/Widgets/CustomEvaluationWidget.tsx
@@ -0,0 +1,134 @@
+import React from 'react';
+import { WidgetProps } from '@rjsf/core';
+import { Button, Input, Select, Option } from '@mui/joy';
+
+type EvaluationField = {
+  name: string;
+  expression: string;
+  return_type: string;
+};
+
+const parseValue = (val: any): EvaluationField[] => {
+  if (Array.isArray(val)) {
+    if (val.every(item => typeof item === "string")) {
+      // If every element is a string: join them and parse the result.
+      try {
+        const joined = val.join(',');
+        const parsed = JSON.parse(joined);
+        return Array.isArray(parsed) ? parsed : [];
+      } catch (err) {
+        console.error("Error parsing evaluation widget value:", err);
+        return [];
+      }
+    } else {
+      // If not all elements are strings, assume it's already an array of EvaluationField.
+      return val;
+    }
+  } else if (typeof val === "string") {
+    try {
+      return JSON.parse(val);
+    } catch (err) {
+      console.error("Error parsing evaluation widget value string:", err);
+      return [];
+    }
+  }
+  return [];
+};
+
+const CustomEvaluationWidget = (props: WidgetProps<any>) => {
+  const { id, value, onChange, disabled, readonly } = props;
+
+  // Directly derive evaluation metrics from the value prop.
+  const evalMetrics: EvaluationField[] = React.useMemo(() => parseValue(value), [value]);
+
+  const handleAddField = () => {
+    const updatedMetrics = [
+      ...evalMetrics,
+      { name: '', expression: '', return_type: 'boolean' }
+    ];
+    onChange(updatedMetrics);
+  };
+
+  const handleFieldChange = (
+    index: number,
+    field: keyof EvaluationField,
+    newValue: string
+  ) => {
+    const updated = evalMetrics.map((evaluation, i) =>
+      i === index ? { ...evaluation, [field]: newValue } : evaluation
+    );
+    onChange(updated);
+  };
+
+  const handleRemoveField = (index: number) => {
+    const updated = evalMetrics.filter((_, i) => i !== index);
+    onChange(updated);
+  };
+
+  return (
+    <div id={id}>
+      {evalMetrics.map((evaluation, index) => (
+        <div
+          key={index}
+          style={{
+            marginBottom: '1rem',
+            border: '1px solid #ccc',
+            padding: '0.5rem'
+          }}
+        >
+          <Input
+            placeholder="Evaluation Name"
+            value={evaluation.name}
+            onChange={(e) =>
+              handleFieldChange(index, 'name', e.target.value)
+            }
+            disabled={disabled || readonly}
+            style={{ marginBottom: '0.5rem' }}
+          />
+          <textarea
+            placeholder="Regular Expression/String"
+            value={evaluation.expression}
+            onChange={(e) =>
+              handleFieldChange(index, 'expression', e.target.value)
+            }
+            disabled={disabled || readonly}
+            style={{ marginBottom: '0.5rem' }}
+          />
+          <Select
+            placeholder="Output Type"
+            value={evaluation.return_type}
+            onChange={(e, newValue) =>
+              handleFieldChange(index, 'return_type', newValue as string)
+            }
+            disabled={disabled || readonly}
+            style={{ marginBottom: '0.5rem' }}
+          >
+            <Option value="boolean">Boolean</Option>
+            <Option value="number">Number</Option>
+            <Option value="contains">Contains</Option>
+            <Option value="isequal">IsEqual</Option>
+          </Select>
+          <Button
+            onClick={() => handleRemoveField(index)}
+            disabled={disabled || readonly}
+            size="sm"
+            variant="outlined"
+          >
+            Remove Field
+          </Button>
+        </div>
+      ))}
+      <Button
+        onClick={handleAddField}
+        disabled={disabled || readonly}
+        variant="solid"
+      >
+        Add Field
+      </Button>
+      {/* Hidden input to capture the JSON result on form submission */}
+      <input type="hidden" id={id} name={id} value={JSON.stringify(evalMetrics)} />
+    </div>
+  );
+};
+
+export default CustomEvaluationWidget;