easy_talk 3.2.0 → 3.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +15 -43
  3. data/CHANGELOG.md +105 -0
  4. data/README.md +510 -2018
  5. data/docs/json_schema_compliance.md +140 -26
  6. data/docs/primitive-schema-rfc.md +894 -0
  7. data/examples/ruby_llm/Gemfile +12 -0
  8. data/examples/ruby_llm/structured_output.rb +47 -0
  9. data/examples/ruby_llm/tools_integration.rb +49 -0
  10. data/lib/easy_talk/builders/base_builder.rb +2 -1
  11. data/lib/easy_talk/builders/boolean_builder.rb +2 -1
  12. data/lib/easy_talk/builders/collection_helpers.rb +4 -0
  13. data/lib/easy_talk/builders/composition_builder.rb +7 -2
  14. data/lib/easy_talk/builders/integer_builder.rb +2 -1
  15. data/lib/easy_talk/builders/null_builder.rb +4 -1
  16. data/lib/easy_talk/builders/number_builder.rb +4 -1
  17. data/lib/easy_talk/builders/object_builder.rb +64 -3
  18. data/lib/easy_talk/builders/registry.rb +15 -1
  19. data/lib/easy_talk/builders/string_builder.rb +3 -1
  20. data/lib/easy_talk/builders/temporal_builder.rb +7 -0
  21. data/lib/easy_talk/builders/tuple_builder.rb +89 -0
  22. data/lib/easy_talk/builders/typed_array_builder.rb +4 -2
  23. data/lib/easy_talk/builders/union_builder.rb +5 -1
  24. data/lib/easy_talk/configuration.rb +17 -2
  25. data/lib/easy_talk/errors.rb +1 -0
  26. data/lib/easy_talk/errors_helper.rb +3 -0
  27. data/lib/easy_talk/extensions/ruby_llm_compatibility.rb +58 -0
  28. data/lib/easy_talk/json_schema_equality.rb +46 -0
  29. data/lib/easy_talk/keywords.rb +0 -1
  30. data/lib/easy_talk/model.rb +42 -1
  31. data/lib/easy_talk/model_helper.rb +4 -0
  32. data/lib/easy_talk/naming_strategies.rb +4 -0
  33. data/lib/easy_talk/property.rb +7 -0
  34. data/lib/easy_talk/ref_helper.rb +6 -0
  35. data/lib/easy_talk/schema.rb +1 -0
  36. data/lib/easy_talk/schema_definition.rb +52 -6
  37. data/lib/easy_talk/schema_methods.rb +36 -5
  38. data/lib/easy_talk/sorbet_extension.rb +1 -0
  39. data/lib/easy_talk/type_introspection.rb +45 -1
  40. data/lib/easy_talk/types/tuple.rb +77 -0
  41. data/lib/easy_talk/validation_adapters/active_model_adapter.rb +350 -62
  42. data/lib/easy_talk/validation_adapters/active_model_schema_validation.rb +106 -0
  43. data/lib/easy_talk/validation_adapters/base.rb +12 -0
  44. data/lib/easy_talk/validation_adapters/none_adapter.rb +9 -0
  45. data/lib/easy_talk/validation_builder.rb +1 -0
  46. data/lib/easy_talk/version.rb +1 -1
  47. data/lib/easy_talk.rb +1 -0
  48. metadata +17 -4
@@ -8,9 +8,9 @@ This document defines the strategy for testing and improving `EasyTalk`'s compli
8
8
 
9
9
  ### Infrastructure
10
10
 
11
- * **Submodule**: Located at `spec/fixtures/json_schema_test_suite`.
12
- * **Converter**: `spec/support/json_schema_converter.rb` dynamically converts raw JSON Schema definitions into `EasyTalk::Model` classes at runtime.
13
- * **Runner**: `spec/integration/json_schema_compliance_spec.rb` iterates over the test suite files, generates models, and asserts valid/invalid behavior.
11
+ - **Submodule**: Located at `spec/fixtures/json_schema_test_suite`.
12
+ - **Converter**: `spec/support/json_schema_converter.rb` dynamically converts raw JSON Schema definitions into `EasyTalk::Model` classes at runtime.
13
+ - **Runner**: `spec/integration/json_schema_compliance_spec.rb` iterates over the test suite files, generates models, and asserts valid/invalid behavior.
14
14
 
15
15
  ## Running the Tests
16
16
 
@@ -22,34 +22,148 @@ To run the compliance suite:
22
22
  bundle exec rspec --tag json_schema_compliance spec/integration/json_schema_compliance_spec.rb
23
23
  ```
24
24
 
25
- ## Compliance Strategy
25
+ ## Schema Wrapping Strategy
26
26
 
27
- The goal is to incrementally improve compliance by enabling more tests and fixing the underlying issues in `EasyTalk`.
27
+ Since `EasyTalk` models are always objects, the JSON Schema test suite's root-level primitive tests (e.g., `{"type": "integer"}` with data `5`) require adaptation.
28
28
 
29
- ### 1. Identify Gaps
30
- The current test runner skips many tests (marked as `pending` or explicit `skip`).
31
- * **Root Primitives**: `EasyTalk` models are Objects. Tests for root integers/strings are skipped.
32
- * **Strict Naming**: Tests with property names that are invalid Ruby identifiers (e.g., `foo-bar`, `123`, `constructor`) are currently skipped.
33
- * **Missing Keywords**: Keywords like `patternProperties`, `const`, and `oneOf` (in specific contexts) may fail.
29
+ ### How It Works
34
30
 
35
- ### 2. Workflow for Improvements
36
- 1. **Select a Feature**: Pick a specific file (e.g., `properties.json`, `required.json`) or a skipped section.
37
- 2. **Un-skip Tests**: Remove the `skip` logic in `spec/integration/json_schema_compliance_spec.rb` for that feature.
38
- 3. **Run & Analyze**: Run the specific test file.
39
- ```bash
40
- bundle exec rspec --tag json_schema_compliance
41
- ```
42
- 4. **Implement Fix**: Modify `EasyTalk` internals (e.g., `keywords.rb`, `schema_definition.rb`) to support the feature.
43
- 5. **Sanitize Inputs**: Update `JsonSchemaConverter` if the test case requires adaptation (e.g., mapping a JSON key to a safe Ruby method name via `as:`) without changing the underlying validation logic.
31
+ The `JsonSchemaConverter` uses a **wrapper property strategy**:
44
32
 
45
- ### 3. Known Critical Issues
46
- * **Reserved Words**: Properties like `method`, `class`, `constructor` conflict with Ruby. Fix requires a robust proxy or sanitization layer in `EasyTalk::Model`.
47
- * **Boolean Schemas**: `properties: { foo: false }` is valid JSON Schema (property forbidden) but not currently supported by `EasyTalk`.
48
- * **Strict Property Validation**: `EasyTalk` raises errors for invalid property names at definition time. Compliance requires allowing arbitrary property keys (perhaps via `validates_with` logic instead of metaprogramming methods).
33
+ 1. **Detection**: `needs_wrapping?` checks if the schema is non-object (no `type: object` or `properties` key)
34
+ 2. **Wrapping**: Non-object schemas become a `value` property on a wrapper object
35
+ 3. **Data transformation**: Primitive test data is wrapped as `{"value": data}`
36
+
37
+ **Example transformation:**
38
+
39
+ ```
40
+ Original JSON Schema test:
41
+ Schema: {"type": "integer", "minimum": 1}
42
+ Data: 5
43
+ Valid: true
44
+
45
+ Transformed for EasyTalk:
46
+ Schema: {
47
+ "type": "object",
48
+ "properties": { "value": {"type": "integer", "minimum": 1} },
49
+ "required": ["value"]
50
+ }
51
+ Data: {"value": 5}
52
+ Valid: true
53
+ ```
54
+
55
+ This preserves validation semantics while fitting EasyTalk's object-based model.
56
+
57
+ ## Current Test Results
58
+
59
+ As of the latest run:
60
+
61
+ | Metric | Count |
62
+ |--------|-------|
63
+ | Total examples | 916 |
64
+ | Passing | ~193 |
65
+ | Failing | 165 |
66
+ | Pending (known unsupported) | 558 |
67
+
68
+ ### Known Unsupported Features
69
+
70
+ The following test files are skipped entirely via `KNOWN_FAILURES`:
71
+
72
+ | File | Reason |
73
+ |------|--------|
74
+ | `not.json` | `not` keyword not supported |
75
+ | `anyOf.json` | `anyOf` validation not supported |
76
+ | `allOf.json` | `allOf` validation not supported |
77
+ | `oneOf.json` | `oneOf` validation not supported |
78
+ | `refRemote.json` | Remote `$ref` not supported |
79
+ | `dependencies.json` | Dependencies not supported |
80
+ | `definitions.json` | `$defs`/definitions not supported |
81
+ | `if-then-else.json` | Conditional logic not supported |
82
+ | `patternProperties.json` | Pattern properties not supported |
83
+ | `properties.json` | Complex property interactions not supported |
84
+ | `propertyNames.json` | Property names validation not supported |
85
+ | `ref.json` | Complex `$ref` not supported |
86
+ | `required.json` | Complex required checks not supported |
87
+ | `additionalItems.json` | Additional items not supported |
88
+ | `additionalProperties.json` | Additional properties validation not supported |
89
+ | `boolean_schema.json` | Boolean schemas (`true`/`false` as schema) not supported |
90
+ | `const.json` | `const` keyword not supported |
91
+ | `default.json` | Default keyword behavior not supported |
92
+ | `enum.json` | Enum validation not fully supported |
93
+ | `infinite-loop-detection.json` | Infinite loop detection not supported |
94
+ | `maxProperties.json` | Max properties not supported |
95
+ | `minProperties.json` | Min properties not supported |
96
+
97
+ ## Compliance Gaps
98
+
99
+ The 165 failing tests reveal real validation gaps in EasyTalk:
100
+
101
+ ### 1. Type Coercion (Intentional Behavior)
102
+
103
+ EasyTalk uses ActiveModel's numericality validation which coerces strings to numbers:
104
+
105
+ ```ruby
106
+ user = User.new(age: "30") # String
107
+ user.valid? # => true (coerced to integer 30)
108
+ ```
109
+
110
+ Per JSON Schema, `"30"` should be invalid for `type: integer`. This is documented as **intentional behavior** for Rails compatibility. A `strict_types` configuration option is planned (see [#137](https://github.com/sergiobayona/easy_talk/issues/137)).
111
+
112
+ ### 2. Format Validation Scope
113
+
114
+ JSON Schema specifies that format validations should only apply to strings and ignore other types. EasyTalk currently validates format on the assigned value regardless of type.
115
+
116
+ ### 3. Empty String Presence
117
+
118
+ EasyTalk uses ActiveModel's presence validation for required fields, which rejects empty strings. JSON Schema considers `""` a valid string.
119
+
120
+ ### 4. Array Type Validation
121
+
122
+ Array element types are not strictly validated at runtime.
123
+
124
+ ### 5. Null Type
125
+
126
+ The `null` type is not fully implemented as a standalone type.
127
+
128
+ ### 6. uniqueItems
129
+
130
+ Array uniqueness constraint is not enforced during validation.
131
+
132
+ ## Workflow for Improvements
133
+
134
+ 1. **Select a Feature**: Pick a specific file from `KNOWN_FAILURES` or analyze failing tests.
135
+ 2. **Enable Tests**: Remove the file from `KNOWN_FAILURES` in the spec.
136
+ 3. **Run & Analyze**:
137
+ ```bash
138
+ bundle exec rspec --tag json_schema_compliance spec/integration/json_schema_compliance_spec.rb
139
+ ```
140
+ 4. **Implement Fix**: Modify EasyTalk internals to support the feature.
141
+ 5. **Update Converter**: If needed, update `JsonSchemaConverter` for test adaptation.
142
+
143
+ ## Critical Implementation Notes
144
+
145
+ ### Reserved Words
146
+
147
+ Properties like `method`, `class`, `constructor` conflict with Ruby. The converter sanitizes these via `sanitize_property_name` and uses the `as:` option to preserve the original JSON key.
148
+
149
+ ### Boolean Schemas
150
+
151
+ `properties: { foo: false }` is valid JSON Schema (property forbidden) but not currently supported.
152
+
153
+ ### Strict Property Validation
154
+
155
+ EasyTalk raises `InvalidPropertyNameError` for invalid property names at definition time. Full compliance would require allowing arbitrary property keys.
49
156
 
50
157
  ## Contributing
51
158
 
52
159
  When adding support for a new JSON Schema keyword:
53
- 1. Check if a test file exists in `spec/fixtures/json_schema_test_suite/tests/draft7/`.
54
- 2. Add the filename to the `FOCUS_FILES` list in `spec/integration/json_schema_compliance_spec.rb`.
55
- 3. Implement the feature and verify pass.
160
+
161
+ 1. Check if a test file exists in `spec/fixtures/json_schema_test_suite/tests/draft7/`.
162
+ 2. Remove the filename from `KNOWN_FAILURES` in `spec/integration/json_schema_compliance_spec.rb`.
163
+ 3. Run the tests and analyze failures.
164
+ 4. Implement the feature in EasyTalk.
165
+ 5. Update this document with any new findings.
166
+
167
+ ## Related Issues
168
+
169
+ - [#137](https://github.com/sergiobayona/easy_talk/issues/137) - Add `strict_types` configuration option