diff --git a/objectiveai-rs/src/functions/quality/check_branch_scalar_function_tests.rs b/objectiveai-rs/src/functions/quality/check_branch_scalar_function_tests.rs index 8b12ae60..829a1962 100644 --- a/objectiveai-rs/src/functions/quality/check_branch_scalar_function_tests.rs +++ b/objectiveai-rs/src/functions/quality/check_branch_scalar_function_tests.rs @@ -6,8 +6,9 @@ use crate::chat::completions::request::{ RichContentExpression, RichContentPartExpression, UserMessageExpression, }; use crate::functions::expression::{ - ArrayInputSchema, BooleanInputSchema, Expression, InputSchema, - IntegerInputSchema, ObjectInputSchema, StringInputSchema, WithExpression, + AnyOfInputSchema, ArrayInputSchema, BooleanInputSchema, Expression, + InputSchema, IntegerInputSchema, ObjectInputSchema, StringInputSchema, + WithExpression, }; use crate::functions::quality::check_branch_scalar_function; use crate::functions::{Remote, @@ -1134,3 +1135,50 @@ fn all_tasks_skipped() { }; test_err(&f, "CV42"); } +#[test] +fn no_example_inputs() { + let f = RemoteFunction::Scalar { + description: "test".to_string(), + input_schema: InputSchema::AnyOf(AnyOfInputSchema { any_of: vec![] }), + input_maps: None, + tasks: vec![TaskExpression::ScalarFunction( + ScalarFunctionTaskExpression { + owner: "test".to_string(), + repository: "test".to_string(), + commit: "abc123".to_string(), + skip: None, + map: None, + input: WithExpression::Expression(Expression::Starlark( + "input".to_string(), + )), + output: Expression::Starlark("output".to_string()), + }, + )], + }; + test_err(&f, "QI01"); +} + +#[test] +fn placeholder_scalar_field_validation_fails() { + let f = RemoteFunction::Scalar { + description: "test".to_string(), + input_schema: InputSchema::Integer(IntegerInputSchema { + description: None, + minimum: Some(1), + maximum: Some(10), + }), + input_maps: None, + tasks: vec![TaskExpression::PlaceholderScalarFunction( + PlaceholderScalarFunctionTaskExpression { + input_schema: InputSchema::AnyOf(AnyOfInputSchema { any_of: vec![] }), + skip: None, + map: None, + input: WithExpression::Expression(Expression::Starlark( + "input".to_string(), + )), + output: Expression::Starlark("output".to_string()), + }, + )], + }; + test_err(&f, "CV04"); +} diff --git a/objectiveai-rs/src/functions/quality/check_branch_vector_function_tests.rs b/objectiveai-rs/src/functions/quality/check_branch_vector_function_tests.rs index 3b130aec..77cef96d 100644 --- a/objectiveai-rs/src/functions/quality/check_branch_vector_function_tests.rs +++ b/objectiveai-rs/src/functions/quality/check_branch_vector_function_tests.rs @@ -7,7 +7,7 @@ use crate::chat::completions::request::{ UserMessageExpression, }; use crate::functions::expression::{ - ArrayInputSchema, BooleanInputSchema, Expression, InputMaps, InputSchema, + AnyOfInputSchema, ArrayInputSchema, BooleanInputSchema, Expression, InputMaps, InputSchema, IntegerInputSchema, ObjectInputSchema, StringInputSchema, WithExpression, }; use crate::functions::quality::check_branch_vector_function; @@ -2218,3 +2218,263 @@ fn output_length_less_than_2() { }; test_err(&f, "VF03"); } +#[test] +fn input_maps_compilation_fails() { + let f = RemoteFunction::Vector { + description: "test".to_string(), + input_schema: InputSchema::Object(ObjectInputSchema { + description: None, + properties: index_map! { + "items" => InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(2), + max_items: Some(2), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }), + "label" => InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + }) + }, + required: Some(vec!["items".to_string(), "label".to_string()]), + }), + input_maps: Some(InputMaps::Many(vec![ + Expression::Starlark("1 + ".to_string()), // Syntax error + ])), + tasks: vec![TaskExpression::ScalarFunction(ScalarFunctionTaskExpression { + owner: "test".to_string(), + repository: "test".to_string(), + commit: "abc123".to_string(), + skip: None, + map: Some(0), + input: WithExpression::Expression(Expression::Starlark("map".to_string())), + output: Expression::Starlark("output".to_string()), + })], + output_length: WithExpression::Expression(Expression::Starlark("len(input['items'])".to_string())), + input_split: WithExpression::Expression(Expression::Starlark("[{'items': [x], 'label': input['label']} for x in input['items']]".to_string())), + input_merge: WithExpression::Expression(Expression::Starlark("{'items': [x['items'][0] for x in input], 'label': input[0]['label']}".to_string())), + }; + test_err(&f, "BV08"); +} + +#[test] +fn input_merge_fails_on_subset() { + let f = RemoteFunction::Vector { + description: "test".to_string(), + input_schema: InputSchema::Object(ObjectInputSchema { + description: None, + properties: index_map! { + "items" => InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(3), + max_items: Some(3), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }), + "label" => InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + }) + }, + required: Some(vec!["items".to_string(), "label".to_string()]), + }), + input_maps: None, + tasks: vec![TaskExpression::VectorFunction(VectorFunctionTaskExpression { + owner: "test".to_string(), + repository: "test".to_string(), + commit: "abc123".to_string(), + skip: None, + map: None, + input: WithExpression::Expression(Expression::Starlark("input".to_string())), + output: Expression::Starlark("output".to_string()), + })], + output_length: WithExpression::Expression(Expression::Starlark("len(input['items'])".to_string())), + input_split: WithExpression::Expression(Expression::Starlark("[{'items': [x], 'label': input['label']} for x in input['items']]".to_string())), + input_merge: WithExpression::Expression(Expression::Starlark("{'items': [x['items'][0] for x in input], 'label': 1/0}".to_string())), + }; + test_err(&f, "VF10"); +} + +#[test] +fn no_example_inputs() { + let f = RemoteFunction::Vector { + description: "test".to_string(), + input_schema: InputSchema::AnyOf(AnyOfInputSchema { any_of: vec![] }), + input_maps: None, + tasks: vec![TaskExpression::VectorFunction(VectorFunctionTaskExpression { + owner: "test".to_string(), + repository: "test".to_string(), + commit: "abc123".to_string(), + skip: None, + map: None, + input: WithExpression::Expression(Expression::Starlark("input".to_string())), + output: Expression::Starlark("output".to_string()), + })], + output_length: WithExpression::Expression(Expression::Starlark("1".to_string())), + input_split: WithExpression::Expression(Expression::Starlark("[input]".to_string())), + input_merge: WithExpression::Expression(Expression::Starlark("input[0]".to_string())), + }; + test_err(&f, "QI01"); +} + +#[test] +fn fixed_mapped_input() { + let f = RemoteFunction::Vector { + description: "test".to_string(), + input_schema: InputSchema::Object(ObjectInputSchema { + description: None, + properties: index_map! { + "items" => InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(2), + max_items: Some(2), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }), + "label" => InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + }) + }, + required: Some(vec!["items".to_string(), "label".to_string()]), + }), + input_maps: Some(InputMaps::Many(vec![ + Expression::Starlark("['fixed_val', 'fixed_val']".to_string()), + ])), + tasks: vec![TaskExpression::ScalarFunction(ScalarFunctionTaskExpression { + owner: "test".to_string(), + repository: "test".to_string(), + commit: "abc123".to_string(), + skip: None, + map: Some(0), + input: WithExpression::Expression(Expression::Starlark("map".to_string())), + output: Expression::Starlark("output".to_string()), + })], + output_length: WithExpression::Expression(Expression::Starlark("len(input['items'])".to_string())), + input_split: WithExpression::Expression(Expression::Starlark("[{'items': [x], 'label': input['label']} for x in input['items']]".to_string())), + input_merge: WithExpression::Expression(Expression::Starlark("{'items': [x['items'][0] for x in input], 'label': input[0]['label']}".to_string())), + }; + test_err(&f, "BV08"); +} + +#[test] +fn all_mapped_inputs_equal() { + let f = RemoteFunction::Vector { + description: "test".to_string(), + input_schema: InputSchema::Object(ObjectInputSchema { + description: None, + properties: index_map! { + "items" => InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(2), + max_items: Some(2), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }), + "label" => InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + }) + }, + required: Some(vec!["items".to_string(), "label".to_string()]), + }), + input_maps: Some(InputMaps::Many(vec![ + Expression::Starlark("[input['label'], input['label']]".to_string()), + ])), + tasks: vec![TaskExpression::ScalarFunction(ScalarFunctionTaskExpression { + owner: "test".to_string(), + repository: "test".to_string(), + commit: "abc123".to_string(), + skip: None, + map: Some(0), + input: WithExpression::Expression(Expression::Starlark("map".to_string())), + output: Expression::Starlark("output".to_string()), + })], + output_length: WithExpression::Expression(Expression::Starlark("len(input['items'])".to_string())), + input_split: WithExpression::Expression(Expression::Starlark("[{'items': [x], 'label': input['label']} for x in input['items']]".to_string())), + input_merge: WithExpression::Expression(Expression::Starlark("{'items': [x['items'][0] for x in input], 'label': input[0]['label']}".to_string())), + }; + test_err(&f, "BV08"); +} + +#[test] +fn placeholder_scalar_field_fails() { + let f = RemoteFunction::Vector { + description: "test".to_string(), + input_schema: InputSchema::Object(ObjectInputSchema { + description: None, + properties: index_map! { + "items" => InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(2), + max_items: Some(2), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }) + }, + required: Some(vec!["items".to_string()]), + }), + input_maps: Some(InputMaps::Many(vec![ + Expression::Starlark("input['items']".to_string()), + ])), + tasks: vec![TaskExpression::PlaceholderScalarFunction(PlaceholderScalarFunctionTaskExpression { + input_schema: InputSchema::AnyOf(AnyOfInputSchema { any_of: vec![] }), + skip: None, + map: Some(0), + input: WithExpression::Expression(Expression::Starlark("map".to_string())), + output: Expression::Starlark("output".to_string()), + })], + output_length: WithExpression::Expression(Expression::Starlark("len(input['items'])".to_string())), + input_split: WithExpression::Expression(Expression::Starlark("[{'items': [x]} for x in input['items']]".to_string())), + input_merge: WithExpression::Expression(Expression::Starlark("{'items': [x['items'][0] for x in input]}".to_string())), + }; + test_err(&f, "BV08"); +} + +#[test] +fn placeholder_vector_field_fails() { + let f = RemoteFunction::Vector { + description: "test".to_string(), + input_schema: InputSchema::Object(ObjectInputSchema { + description: None, + properties: index_map! { + "items" => InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(2), + max_items: Some(2), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }) + }, + required: Some(vec!["items".to_string()]), + }), + input_maps: None, + tasks: vec![TaskExpression::PlaceholderVectorFunction(PlaceholderVectorFunctionTaskExpression { + input_schema: InputSchema::AnyOf(AnyOfInputSchema { any_of: vec![] }), + output_length: WithExpression::Expression(Expression::Starlark("len(input['items'])".to_string())), + input_split: WithExpression::Expression(Expression::Starlark("[{'items': [x]} for x in input['items']]".to_string())), + input_merge: WithExpression::Expression(Expression::Starlark("{'items': [x['items'][0] for x in input]}".to_string())), + skip: None, + map: None, + input: WithExpression::Expression(Expression::Starlark("input".to_string())), + output: Expression::Starlark("output".to_string()), + })], + output_length: WithExpression::Expression(Expression::Starlark("len(input['items'])".to_string())), + input_split: WithExpression::Expression(Expression::Starlark("[{'items': [x]} for x in input['items']]".to_string())), + input_merge: WithExpression::Expression(Expression::Starlark("{'items': [x['items'][0] for x in input]}".to_string())), + }; + test_err(&f, "CV05"); +} diff --git a/objectiveai-rs/src/functions/quality/check_leaf_scalar_function_tests.rs b/objectiveai-rs/src/functions/quality/check_leaf_scalar_function_tests.rs index 0ee4ddd2..18a5a1a7 100644 --- a/objectiveai-rs/src/functions/quality/check_leaf_scalar_function_tests.rs +++ b/objectiveai-rs/src/functions/quality/check_leaf_scalar_function_tests.rs @@ -9,9 +9,9 @@ use crate::chat::completions::request::{ SystemMessageExpression, ToolMessageExpression, UserMessageExpression, }; use crate::functions::expression::{ - ArrayInputSchema, BooleanInputSchema, Expression, ImageInputSchema, - InputSchema, IntegerInputSchema, ObjectInputSchema, StringInputSchema, - WithExpression, + AnyOfInputSchema, ArrayInputSchema, BooleanInputSchema, Expression, + ImageInputSchema, InputSchema, IntegerInputSchema, ObjectInputSchema, + StringInputSchema, WithExpression, }; use crate::functions::quality::check_leaf_scalar_function; use crate::functions::{Remote, @@ -2313,3 +2313,49 @@ fn all_tasks_skipped() { }; test_err(&f, "CV42"); } + +#[test] +fn no_example_inputs() { + let f = RemoteFunction::Scalar { + description: "test".to_string(), + input_schema: InputSchema::AnyOf(AnyOfInputSchema { any_of: vec![] }), + input_maps: None, + tasks: vec![TaskExpression::VectorCompletion( + VectorCompletionTaskExpression { + skip: None, + map: None, + messages: WithExpression::Value(vec![WithExpression::Value( + MessageExpression::User(UserMessageExpression { + content: WithExpression::Value( + RichContentExpression::Parts(vec![ + WithExpression::Value( + RichContentPartExpression::Text { + text: WithExpression::Value( + "Hello".to_string(), + ), + }, + ), + ]), + ), + name: None, + }), + )]), + tools: None, + responses: WithExpression::Value(vec![ + WithExpression::Value(RichContentExpression::Parts(vec![ + WithExpression::Value(RichContentPartExpression::Text { + text: WithExpression::Value("Yes".to_string()), + }), + ])), + WithExpression::Value(RichContentExpression::Parts(vec![ + WithExpression::Value(RichContentPartExpression::Text { + text: WithExpression::Value("No".to_string()), + }), + ])), + ]), + output: Expression::Starlark("output['scores'][0]".to_string()), + }, + )], + }; + test_err(&f, "QI01"); +} diff --git a/objectiveai-rs/src/functions/quality/check_leaf_vector_function_tests.rs b/objectiveai-rs/src/functions/quality/check_leaf_vector_function_tests.rs index 0ea035b8..b4574cea 100644 --- a/objectiveai-rs/src/functions/quality/check_leaf_vector_function_tests.rs +++ b/objectiveai-rs/src/functions/quality/check_leaf_vector_function_tests.rs @@ -8,7 +8,7 @@ use crate::chat::completions::request::{ SystemMessageExpression, UserMessageExpression, }; use crate::functions::expression::{ - ArrayInputSchema, BooleanInputSchema, Expression, ImageInputSchema, + AnyOfInputSchema, ArrayInputSchema, BooleanInputSchema, Expression, ImageInputSchema, InputSchema, IntegerInputSchema, ObjectInputSchema, StringInputSchema, WithExpression, }; @@ -3028,3 +3028,103 @@ fn job_application_ranker_3() { }; test(&f); } + +#[test] +fn input_merge_fails_on_subset() { + let f = RemoteFunction::Vector { + description: "test".to_string(), + input_schema: InputSchema::Object(ObjectInputSchema { + description: None, + properties: index_map! { + "items" => InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(3), + max_items: Some(3), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }), + "label" => InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + }) + }, + required: Some(vec!["items".to_string(), "label".to_string()]), + }), + input_maps: None, + tasks: vec![TaskExpression::VectorCompletion( + VectorCompletionTaskExpression { + skip: None, + map: None, + messages: WithExpression::Value(vec![WithExpression::Value( + MessageExpression::User(UserMessageExpression { + content: WithExpression::Value( + RichContentExpression::Parts(vec![ + WithExpression::Value( + RichContentPartExpression::Text { + text: WithExpression::Value( + "Hello".to_string(), + ), + }, + ), + ]), + ), + name: None, + }), + )]), + tools: None, + responses: WithExpression::Expression(Expression::Starlark( + "[[{'type': 'text', 'text': x}] for x in input]" + .to_string(), + )), + output: Expression::Starlark("output['scores']".to_string()), + }, + )], + output_length: WithExpression::Expression(Expression::Starlark("len(input['items'])".to_string())), + input_split: WithExpression::Expression(Expression::Starlark("[{'items': [x], 'label': input['label']} for x in input['items']]".to_string())), + input_merge: WithExpression::Expression(Expression::Starlark("{'items': [x['items'][0] for x in input], 'label': input[0]['label'] if len(input) == 3 else 1/0}".to_string())), + }; + test_err(&f, "CV14"); +} + +#[test] +fn no_example_inputs() { + let f = RemoteFunction::Vector { + description: "test".to_string(), + input_schema: InputSchema::AnyOf(AnyOfInputSchema { any_of: vec![] }), + input_maps: None, + tasks: vec![TaskExpression::VectorCompletion( + VectorCompletionTaskExpression { + skip: None, + map: None, + messages: WithExpression::Value(vec![WithExpression::Value( + MessageExpression::User(UserMessageExpression { + content: WithExpression::Value( + RichContentExpression::Parts(vec![ + WithExpression::Value( + RichContentPartExpression::Text { + text: WithExpression::Value( + "Hello".to_string(), + ), + }, + ), + ]), + ), + name: None, + }), + )]), + tools: None, + responses: WithExpression::Expression(Expression::Starlark( + "[[{'type': 'text', 'text': x}] for x in input]" + .to_string(), + )), + output: Expression::Starlark("output['scores']".to_string()), + }, + )], + output_length: WithExpression::Expression(Expression::Starlark("1".to_string())), + input_split: WithExpression::Expression(Expression::Starlark("[input]".to_string())), + input_merge: WithExpression::Expression(Expression::Starlark("input[0]".to_string())), + }; + test_err(&f, "QI01"); +} diff --git a/objectiveai-rs/src/functions/quality/check_scalar_fields_tests.rs b/objectiveai-rs/src/functions/quality/check_scalar_fields_tests.rs index 010e3ff3..3231200e 100644 --- a/objectiveai-rs/src/functions/quality/check_scalar_fields_tests.rs +++ b/objectiveai-rs/src/functions/quality/check_scalar_fields_tests.rs @@ -4,7 +4,7 @@ use super::check_scalar_fields::{ScalarFieldsValidation, check_scalar_fields}; use crate::functions::expression::{ - InputSchema, IntegerInputSchema, ObjectInputSchema, StringInputSchema, + AnyOfInputSchema, InputSchema, IntegerInputSchema, ObjectInputSchema, StringInputSchema, }; use crate::util::index_map; @@ -64,3 +64,13 @@ fn valid_object_schema() { }), }); } + +#[test] +fn no_example_inputs() { + test_err( + ScalarFieldsValidation { + input_schema: InputSchema::AnyOf(AnyOfInputSchema { any_of: vec![] }), + }, + "QI01", + ); +} diff --git a/objectiveai-rs/src/functions/quality/check_vector_fields_tests.rs b/objectiveai-rs/src/functions/quality/check_vector_fields_tests.rs index 8a99566e..767f2323 100644 --- a/objectiveai-rs/src/functions/quality/check_vector_fields_tests.rs +++ b/objectiveai-rs/src/functions/quality/check_vector_fields_tests.rs @@ -6,7 +6,7 @@ use super::check_vector_fields::{ VectorFieldsValidation, check_vector_fields, inputs_equal, random_subsets, }; use crate::functions::expression::{ - ArrayInputSchema, Expression, Input, InputSchema, IntegerInputSchema, + AnyOfInputSchema, ArrayInputSchema, Expression, Input, InputSchema, IntegerInputSchema, ObjectInputSchema, StringInputSchema, WithExpression, }; use crate::util::index_map; @@ -552,3 +552,195 @@ fn job_application_ranker_1() { )), }, "VF03") } + +#[test] +fn output_length_fails_for_split() { + test_err( + VectorFieldsValidation { + input_schema: InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(2), + max_items: Some(5), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }), + output_length: WithExpression::Expression(Expression::Starlark( + "len(input) if len(input) > 5 else 1/0".to_string(), + )), + input_split: WithExpression::Expression(Expression::Starlark( + "[[x] for x in input]".to_string(), + )), + input_merge: WithExpression::Expression(Expression::Starlark( + "[x[0] for x in input]".to_string(), + )), + }, + "VF01", + ); +} + +#[test] +fn input_merge_fails_for_subset() { + test_err( + VectorFieldsValidation { + input_schema: InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(3), + max_items: Some(3), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }), + output_length: WithExpression::Expression(Expression::Starlark( + "len(input)".to_string(), + )), + input_split: WithExpression::Expression(Expression::Starlark( + "[[x] for x in input]".to_string(), + )), + input_merge: WithExpression::Expression(Expression::Starlark( + "[x[0] for x in input] if len(input) == 3 else 1/0".to_string(), + )), + }, + "VF16", + ); +} + +#[test] +fn output_length_fails_for_merged_subset() { + test_err( + VectorFieldsValidation { + input_schema: InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(3), + max_items: Some(3), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }), + output_length: WithExpression::Expression(Expression::Starlark( + "len(input) if len(input) == 3 or len(input) == 1 else 1/0".to_string(), + )), + input_split: WithExpression::Expression(Expression::Starlark( + "[[x] for x in input]".to_string(), + )), + input_merge: WithExpression::Expression(Expression::Starlark( + "[x[0] for x in input]".to_string(), + )), + }, + "VF18", + ); +} + +#[test] +fn output_length_wrong_for_merged_subset() { + test_err( + VectorFieldsValidation { + input_schema: InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(3), + max_items: Some(3), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }), + output_length: WithExpression::Expression(Expression::Starlark( + "len(input) if len(input) == 3 or len(input) == 1 else 999".to_string(), + )), + input_split: WithExpression::Expression(Expression::Starlark( + "[[x] for x in input]".to_string(), + )), + input_merge: WithExpression::Expression(Expression::Starlark( + "[x[0] for x in input]".to_string(), + )), + }, + "VF20", + ); +} + +#[test] +fn no_example_inputs() { + test_err( + VectorFieldsValidation { + input_schema: InputSchema::AnyOf(AnyOfInputSchema { any_of: vec![] }), + output_length: WithExpression::Expression(Expression::Starlark( + "len(input)".to_string(), + )), + input_split: WithExpression::Expression(Expression::Starlark( + "[[x] for x in input]".to_string(), + )), + input_merge: WithExpression::Expression(Expression::Starlark( + "[x[0] for x in input]".to_string(), + )), + }, + "QI01", + ); +} + +#[test] +fn array_violates_min_items() { + test_err( + VectorFieldsValidation { + input_schema: InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(3), + max_items: Some(3), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }), + output_length: WithExpression::Expression(Expression::Starlark( + "len(input)".to_string(), + )), + input_split: WithExpression::Expression(Expression::Starlark( + "[[x] for x in input]".to_string(), + )), + input_merge: WithExpression::Expression(Expression::Starlark( + "[x[0] for x in input]".to_string(), + )), + }, + "VF23", + ); +} + +#[test] +fn array_violates_max_items() { + test_err( + VectorFieldsValidation { + input_schema: InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(2), + max_items: Some(4), + items: Box::new(InputSchema::Object(ObjectInputSchema { + description: None, + properties: index_map! { + "inner" => InputSchema::Array(ArrayInputSchema { + description: None, + min_items: Some(1), + max_items: Some(1), + items: Box::new(InputSchema::String(StringInputSchema { + description: None, + r#enum: None, + })), + }) + }, + required: Some(vec!["inner".to_string()]), + })), + }), + output_length: WithExpression::Expression(Expression::Starlark( + "len(input) if type(input) == 'list' else 1".to_string(), + )), + input_split: WithExpression::Expression(Expression::Starlark( + "[{'val': x, 'orig_len': len(input)} for x in input]".to_string(), + )), + input_merge: WithExpression::Expression(Expression::Starlark( + "[{'inner': x['val']['inner'] * 2} if len(input) != x['orig_len'] else x['val'] for x in input]".to_string(), + )), + }, + "VF24", + ); +} diff --git a/objectiveai-web/app/functions/[...slug]/page.tsx b/objectiveai-web/app/functions/[...slug]/page.tsx index d74bcf29..a7761045 100644 --- a/objectiveai-web/app/functions/[...slug]/page.tsx +++ b/objectiveai-web/app/functions/[...slug]/page.tsx @@ -11,6 +11,7 @@ import { loadReasoningModels } from "../../../lib/reasoning-models"; import { useIsMobile } from "../../../hooks/useIsMobile"; import { useObjectiveAI } from "../../../hooks/useObjectiveAI"; import { InputBuilder } from "../../../components/InputBuilder"; +import { LoadingSpinner, ErrorAlert, EmptyState, SkeletonFunctionDetails } from "../../../components/ui"; import SchemaFormBuilder from "../../../components/SchemaForm/SchemaFormBuilder"; import type { InputSchema, InputValue } from "../../../components/SchemaForm/types"; import SplitItemDisplay from "../../../components/SplitItemDisplay"; @@ -1115,136 +1116,136 @@ export default function FunctionDetailPage({ params }: { params: Promise<{ slug:
- {(() => { - const displayedVotes = showAllModels ? votes : votes.slice(0, 5); - const completions = results.tasks?.[0]?.completions || []; - - return displayedVotes.map((vote, modelIdx) => { - const maxVoteIdx = vote.vote.indexOf(Math.max(...vote.vote)); - const confidence = Math.max(...vote.vote) * 100; - // Use readable model name if available, else shortened cryptic ID - const displayName = modelNames[vote.model] || vote.model.slice(0, 8); - const isResolved = !!modelNames[vote.model]; - const isExpanded = expandedVotes.has(modelIdx); - // Find matching completion by model ID - const completion = completions.find(c => c.model === vote.model); - // Handle both streaming (delta) and non-streaming (message) structures - const choice = completion?.choices?.[0]; - const reasoningText = choice?.message?.content || choice?.delta?.content; - - return ( -
-
{ - if (!reasoningText) return; - setExpandedVotes(prev => { - const next = new Set(prev); - if (next.has(modelIdx)) { - next.delete(modelIdx); - } else { - next.add(modelIdx); - } - return next; - }); - }} - > - - {reasoningText && ( - - {isExpanded ? "▼" : "▶"} + {(() => { + const displayedVotes = showAllModels ? votes : votes.slice(0, 5); + const completions = results.tasks?.[0]?.completions || []; + + return displayedVotes.map((vote, modelIdx) => { + const maxVoteIdx = vote.vote.indexOf(Math.max(...vote.vote)); + const confidence = Math.max(...vote.vote) * 100; + // Use readable model name if available, else shortened cryptic ID + const displayName = modelNames[vote.model] || vote.model.slice(0, 8); + const isResolved = !!modelNames[vote.model]; + const isExpanded = expandedVotes.has(modelIdx); + // Find matching completion by model ID + const completion = completions.find(c => c.model === vote.model); + // Handle both streaming (delta) and non-streaming (message) structures + const choice = completion?.choices?.[0]; + const reasoningText = choice?.message?.content || choice?.delta?.content; + + return ( +
+
{ + if (!reasoningText) return; + setExpandedVotes(prev => { + const next = new Set(prev); + if (next.has(modelIdx)) { + next.delete(modelIdx); + } else { + next.add(modelIdx); + } + return next; + }); + }} + > + + {reasoningText && ( + + {isExpanded ? "▼" : "▶"} + + )} + + {displayName} - )} - - {displayName} + + {isMobile ? getOptionLabel(maxVoteIdx).slice(0, 15) + (getOptionLabel(maxVoteIdx).length > 15 ? "…" : "") : getOptionLabel(maxVoteIdx)} - - {isMobile ? getOptionLabel(maxVoteIdx).slice(0, 15) + (getOptionLabel(maxVoteIdx).length > 15 ? "…" : "") : getOptionLabel(maxVoteIdx)} - - - - {confidence.toFixed(0)}% - - {!isMobile && ( - - w:{vote.weight} + + + {confidence.toFixed(0)}% - )} - -
- {/* Progress bar - muted fill, no color */} -
+ {!isMobile && ( + + w:{vote.weight} + + )} + +
+ {/* Progress bar - muted fill, no color */}
-
- {/* Expanded reasoning */} - {isExpanded && reasoningText && ( -
- {reasoningText} +
- )} -
- ); - }); - })()} - {votes.length > 5 && ( - - )} + {/* Expanded reasoning */} + {isExpanded && reasoningText && ( +
+ {reasoningText} +
+ )} +
+ ); + }); + })()} + {votes.length > 5 && ( + + )}
diff --git a/objectiveai-web/app/functions/page.tsx b/objectiveai-web/app/functions/page.tsx index 78b399f0..e3ebff24 100644 --- a/objectiveai-web/app/functions/page.tsx +++ b/objectiveai-web/app/functions/page.tsx @@ -117,7 +117,7 @@ export default function FunctionsPage() { const navHeight = navHeightStr ? parseInt(navHeightStr) : (isMobile ? 84 : 96); setNavOffset(navHeight); }; - + updateOffset(); window.addEventListener('resize', updateOffset); const timer = setTimeout(updateOffset, NAV_HEIGHT_CALCULATION_DELAY_MS); @@ -247,8 +247,8 @@ export default function FunctionsPage() { key={cat} onClick={() => setSelectedCategory(cat)} className={`filterChip ${selectedCategory === cat ? 'active' : ''}`} - style={{ - textAlign: 'left', + style={{ + textAlign: 'left', padding: '8px 14px', opacity: cat === 'Pinned' && pinnedFunctions.length === 0 ? 0.5 : 1, }} @@ -289,7 +289,116 @@ export default function FunctionsPage() { }}> {/* Only render grid when we have results */} {!isLoading && !error && visibleFunctions.length > 0 && ( - <> + <> +
+ {visibleFunctions.map(fn => ( + +
+ + {fn.category} + +

+ {fn.name} +

+

+ {fn.description} +

+
+ {fn.tags.slice(0, 2).map(tag => ( + + {tag} + + ))} + {fn.tags.length > 2 && ( + + +{fn.tags.length - 2} + + )} +
+
+ Open +
+
+ + ))} +
+ + {hasMore && ( + + )} + + )} + + {isLoading && (
- {visibleFunctions.map(fn => ( - -
- - {fn.category} - -

- {fn.name} -

-

- {fn.description} -

-
- {fn.tags.slice(0, 2).map(tag => ( - - {tag} - - ))} - {fn.tags.length > 2 && ( - - +{fn.tags.length - 2} - - )} -
-
- Open -
-
- + {Array.from({ length: 9 }).map((_, i) => ( + ))}
@@ -481,7 +524,7 @@ export default function FunctionsPage() { ✕
- +

*:last-child:not(.footer) { +.page>*:last-child:not(.footer) { flex: 1; } @@ -152,6 +152,7 @@ body { } @media (max-width: 1024px) { + .container, .containerWide { padding: 0 24px; @@ -159,6 +160,7 @@ body { } @media (max-width: 640px) { + .container, .containerWide { padding: 0 16px; @@ -166,14 +168,14 @@ body { } /* Layout Guardrails - Prevent width inconsistencies */ -.page > .container, -.page > .containerWide { +.page>.container, +.page>.containerWide { width: 100%; box-sizing: border-box; } -.page > .container > *, -.page > .containerWide > * { +.page>.container>*, +.page>.containerWide>* { max-width: 100%; } @@ -1014,13 +1016,25 @@ body { /* Responsive Spacing */ /* Loading Animation */ @keyframes pulse { - 0%, 100% { opacity: 0.4; } - 50% { opacity: 0.7; } + + 0%, + 100% { + opacity: 0.4; + } + + 50% { + opacity: 0.7; + } } @keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } } .skeleton { @@ -1200,6 +1214,7 @@ body { } @media (max-width: 768px) { + .docsSidebarDesktop, .docsSidebarToggle { display: none !important; @@ -1440,7 +1455,7 @@ body { margin-top: 4px; } -.docsDetails > summary { +.docsDetails>summary { cursor: pointer; font-size: 14px; color: var(--text-muted); @@ -1449,7 +1464,7 @@ body { margin-left: 16px; } -.docsDetails > summary:hover { +.docsDetails>summary:hover { color: var(--text); } @@ -1529,7 +1544,8 @@ body { display: flex; flex-direction: column; height: calc(100vh - var(--content-top, 100px)); - min-height: 400px; /* Prevent collapsing on very short viewports */ + min-height: 400px; + /* Prevent collapsing on very short viewports */ } @media (max-width: 640px) { @@ -1542,7 +1558,8 @@ body { /* Model Breakdown Wrapper - Horizontal scroll on mobile */ .model-breakdown-wrapper { width: 100%; - overflow-x: visible; /* Desktop: no scroll */ + overflow-x: visible; + /* Desktop: no scroll */ } @media (max-width: 640px) { @@ -1602,6 +1619,7 @@ body { text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; + line-clamp: 3; -webkit-box-orient: vertical; word-wrap: break-word; } @@ -1631,3 +1649,24 @@ body { gap: 16px; } } + +/* ============================================ + SKELETON LOADING ANIMATION + ============================================ */ + +@keyframes pulse { + + 0%, + 100% { + opacity: 1; + } + + 50% { + opacity: 0.5; + } +} + +.skeletonPulse { + animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; + background-color: var(--border); +} \ No newline at end of file diff --git a/objectiveai-web/package.json b/objectiveai-web/package.json index e3137654..d89d355c 100644 --- a/objectiveai-web/package.json +++ b/objectiveai-web/package.json @@ -16,7 +16,9 @@ "@sonarly/tracker": "^1.3.15", "@stripe/react-stripe-js": "^4.0.2", "@stripe/stripe-js": "^7.9.0", + "@tailwindcss/oxide": "^4.2.0", "async-mutex": "^0.5.0", + "lightningcss": "^1.31.1", "next": "16.0.10", "next-auth": "^4.24.0", "objectiveai": "*", diff --git a/package-lock.json b/package-lock.json index 0da1727b..9f54000d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,7 @@ "objectiveai-cli", "objectiveai-js", "objectiveai-web" - ], - "dependencies": { - "lightningcss-darwin-arm64": "^1.31.1" - } + ] }, "node_modules/@adobe/css-tools": { "version": "4.4.4", @@ -817,6 +814,111 @@ "node": ">= 10" } }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.10.tgz", + "integrity": "sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.10.tgz", + "integrity": "sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.10.tgz", + "integrity": "sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.10.tgz", + "integrity": "sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.10.tgz", + "integrity": "sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.10.tgz", + "integrity": "sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.10.tgz", + "integrity": "sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -890,7 +992,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@sonarly/network-proxy": {}, "node_modules/@sonarly/sourcemap-uploader": { "version": "1.0.2", "license": "MIT", @@ -969,7 +1070,8 @@ }, "node_modules/@tailwindcss/oxide": { "version": "4.2.0", - "dev": true, + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.0.tgz", + "integrity": "sha512-AZqQzADaj742oqn2xjl5JbIOzZB/DGCYF/7bpvhA8KvjUj9HJkag6bBuwZvH1ps6dfgxNHyuJVlzSr2VpMgdTQ==", "license": "MIT", "engines": { "node": ">= 20" @@ -989,12 +1091,27 @@ "@tailwindcss/oxide-win32-x64-msvc": "4.2.0" } }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.0.tgz", + "integrity": "sha512-F0QkHAVaW/JNBWl4CEKWdZ9PMb0khw5DCELAOnu+RtjAfx5Zgw+gqCHFvqg3AirU1IAd181fwOtJQ5I8Yx5wtw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, "node_modules/@tailwindcss/oxide-darwin-arm64": { "version": "4.2.0", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1004,6 +1121,179 @@ "node": ">= 20" } }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.0.tgz", + "integrity": "sha512-6TmQIn4p09PBrmnkvbYQ0wbZhLtbaksCDx7Y7R3FYYx0yxNA7xg5KP7dowmQ3d2JVdabIHvs3Hx4K3d5uCf8xg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.0.tgz", + "integrity": "sha512-qBudxDvAa2QwGlq9y7VIzhTvp2mLJ6nD/G8/tI70DCDoneaUeLWBJaPcbfzqRIWraj+o969aDQKvKW9dvkUizw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.0.tgz", + "integrity": "sha512-7XKkitpy5NIjFZNUQPeUyNJNJn1CJeV7rmMR+exHfTuOsg8rxIO9eNV5TSEnqRcaOK77zQpsyUkBWmPy8FgdSg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.0.tgz", + "integrity": "sha512-Mff5a5Q3WoQR01pGU1gr29hHM1N93xYrKkGXfPw/aRtK4bOc331Ho4Tgfsm5WDGvpevqMpdlkCojT3qlCQbCpA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.0.tgz", + "integrity": "sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.0.tgz", + "integrity": "sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.0.tgz", + "integrity": "sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.0.tgz", + "integrity": "sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.0.tgz", + "integrity": "sha512-2UU/15y1sWDEDNJXxEIrfWKC2Yb4YgIW5Xz2fKFqGzFWfoMHWFlfa1EJlGO2Xzjkq/tvSarh9ZTjvbxqWvLLXA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.0.tgz", + "integrity": "sha512-CrFadmFoc+z76EV6LPG1jx6XceDsaCG3lFhyLNo/bV9ByPrE+FnBPckXQVP4XRkN76h3Fjt/a+5Er/oA/nCBvQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, "node_modules/@tailwindcss/postcss": { "version": "4.2.0", "dev": true, @@ -2585,7 +2875,6 @@ }, "node_modules/detect-libc": { "version": "2.1.2", - "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -4939,7 +5228,8 @@ }, "node_modules/lightningcss": { "version": "1.31.1", - "dev": true, + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", + "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -4965,12 +5255,33 @@ "lightningcss-win32-x64-msvc": "1.31.1" } }, + "node_modules/lightningcss-android-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", + "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lightningcss-darwin-arm64": { "version": "1.31.1", "cpu": [ "arm64" ], "license": "MPL-2.0", + "optional": true, "os": [ "darwin" ], @@ -4982,6 +5293,186 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", + "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", + "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", + "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", + "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", + "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", + "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", + "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", + "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", + "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lilconfig": { "version": "3.1.3", "dev": true, @@ -8396,7 +8887,9 @@ "@sonarly/tracker": "^1.3.15", "@stripe/react-stripe-js": "^4.0.2", "@stripe/stripe-js": "^7.9.0", + "@tailwindcss/oxide": "^4.2.0", "async-mutex": "^0.5.0", + "lightningcss": "^1.31.1", "next": "16.0.10", "next-auth": "^4.24.0", "objectiveai": "*",