typia 14.0.6 → 15.0.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 (178) hide show
  1. package/README.md +3 -0
  2. package/lib/http.d.ts +49 -24
  3. package/lib/http.js.map +1 -1
  4. package/lib/http.mjs.map +1 -1
  5. package/lib/internal/_createLlmEvaluation.d.ts +1 -0
  6. package/lib/internal/_createLlmEvaluation.js +486 -0
  7. package/lib/internal/_createLlmEvaluation.js.map +1 -0
  8. package/lib/internal/_createLlmEvaluation.mjs +382 -0
  9. package/lib/internal/_createLlmEvaluation.mjs.map +1 -0
  10. package/lib/internal/_httpFormDataReadBigint.js +7 -5
  11. package/lib/internal/_httpFormDataReadBigint.js.map +1 -1
  12. package/lib/internal/_httpFormDataReadBigint.mjs +1 -1
  13. package/lib/internal/_httpFormDataReadBigint.mjs.map +1 -1
  14. package/lib/internal/_httpFormDataReadBoolean.js +12 -10
  15. package/lib/internal/_httpFormDataReadBoolean.js.map +1 -1
  16. package/lib/internal/_httpFormDataReadBoolean.mjs +1 -1
  17. package/lib/internal/_httpFormDataReadBoolean.mjs.map +1 -1
  18. package/lib/internal/_httpFormDataReadNumber.js +7 -5
  19. package/lib/internal/_httpFormDataReadNumber.js.map +1 -1
  20. package/lib/internal/_httpFormDataReadNumber.mjs +1 -1
  21. package/lib/internal/_httpFormDataReadNumber.mjs.map +1 -1
  22. package/lib/internal/_httpFormDataReadString.d.ts +9 -1
  23. package/lib/internal/_httpFormDataReadString.js +10 -2
  24. package/lib/internal/_httpFormDataReadString.js.map +1 -1
  25. package/lib/internal/_httpFormDataReadString.mjs +9 -1
  26. package/lib/internal/_httpFormDataReadString.mjs.map +1 -1
  27. package/lib/internal/_httpHeaderReadBigint.js +5 -1
  28. package/lib/internal/_httpHeaderReadBigint.js.map +1 -1
  29. package/lib/internal/_httpHeaderReadBigint.mjs +2 -1
  30. package/lib/internal/_httpHeaderReadBigint.mjs.map +1 -1
  31. package/lib/internal/_httpHeaderReadNumber.js +5 -1
  32. package/lib/internal/_httpHeaderReadNumber.js.map +1 -1
  33. package/lib/internal/_httpHeaderReadNumber.mjs +2 -1
  34. package/lib/internal/_httpHeaderReadNumber.mjs.map +1 -1
  35. package/lib/internal/_httpParameterReadBigint.js +4 -0
  36. package/lib/internal/_httpParameterReadBigint.js.map +1 -1
  37. package/lib/internal/_httpParameterReadBigint.mjs +1 -0
  38. package/lib/internal/_httpParameterReadBigint.mjs.map +1 -1
  39. package/lib/internal/_httpParameterReadNumber.js +4 -0
  40. package/lib/internal/_httpParameterReadNumber.js.map +1 -1
  41. package/lib/internal/_httpParameterReadNumber.mjs +1 -0
  42. package/lib/internal/_httpParameterReadNumber.mjs.map +1 -1
  43. package/lib/internal/_httpParameterReadString.d.ts +9 -1
  44. package/lib/internal/_httpParameterReadString.js +9 -1
  45. package/lib/internal/_httpParameterReadString.js.map +1 -1
  46. package/lib/internal/_httpParameterReadString.mjs +9 -1
  47. package/lib/internal/_httpParameterReadString.mjs.map +1 -1
  48. package/lib/internal/_httpQueryReadBigint.js +8 -1
  49. package/lib/internal/_httpQueryReadBigint.js.map +1 -1
  50. package/lib/internal/_httpQueryReadBigint.mjs +1 -1
  51. package/lib/internal/_httpQueryReadBigint.mjs.map +1 -1
  52. package/lib/internal/_httpQueryReadBoolean.js +4 -1
  53. package/lib/internal/_httpQueryReadBoolean.js.map +1 -1
  54. package/lib/internal/_httpQueryReadBoolean.mjs +1 -1
  55. package/lib/internal/_httpQueryReadBoolean.mjs.map +1 -1
  56. package/lib/internal/_httpQueryReadNumber.js +8 -1
  57. package/lib/internal/_httpQueryReadNumber.js.map +1 -1
  58. package/lib/internal/_httpQueryReadNumber.mjs +1 -1
  59. package/lib/internal/_httpQueryReadNumber.mjs.map +1 -1
  60. package/lib/internal/_httpQueryReadString.d.ts +9 -1
  61. package/lib/internal/_httpQueryReadString.js +9 -1
  62. package/lib/internal/_httpQueryReadString.js.map +1 -1
  63. package/lib/internal/_httpQueryReadString.mjs +9 -1
  64. package/lib/internal/_httpQueryReadString.mjs.map +1 -1
  65. package/lib/internal/_randomBigint.d.ts +12 -1
  66. package/lib/internal/_randomBigint.js +90 -2
  67. package/lib/internal/_randomBigint.js.map +1 -1
  68. package/lib/internal/_randomBigint.mjs +70 -2
  69. package/lib/internal/_randomBigint.mjs.map +1 -1
  70. package/lib/internal/_randomInteger.js +21 -12
  71. package/lib/internal/_randomInteger.js.map +1 -1
  72. package/lib/internal/_randomInteger.mjs +21 -16
  73. package/lib/internal/_randomInteger.mjs.map +1 -1
  74. package/lib/internal/_randomNumber.js +19 -10
  75. package/lib/internal/_randomNumber.js.map +1 -1
  76. package/lib/internal/_randomNumber.mjs +19 -14
  77. package/lib/internal/_randomNumber.mjs.map +1 -1
  78. package/lib/internal/_stringLengthGte.d.ts +1 -0
  79. package/lib/internal/_stringLengthGte.js +14 -0
  80. package/lib/internal/_stringLengthGte.js.map +1 -0
  81. package/lib/internal/_stringLengthGte.mjs +11 -0
  82. package/lib/internal/_stringLengthGte.mjs.map +1 -0
  83. package/lib/internal/_stringLengthLte.d.ts +1 -0
  84. package/lib/internal/_stringLengthLte.js +14 -0
  85. package/lib/internal/_stringLengthLte.js.map +1 -0
  86. package/lib/internal/_stringLengthLte.mjs +11 -0
  87. package/lib/internal/_stringLengthLte.mjs.map +1 -0
  88. package/lib/llm.d.ts +54 -1
  89. package/lib/llm.js +5 -0
  90. package/lib/llm.js.map +1 -1
  91. package/lib/llm.mjs +6 -1
  92. package/lib/llm.mjs.map +1 -1
  93. package/lib/re-exports.d.ts +1 -1
  94. package/lib/re-exports.js.map +1 -1
  95. package/native/cmd/ttsc-typia/build.go +2 -0
  96. package/native/cmd/ttsc-typia/dynamic_key_tags_transform_test.go +1 -1
  97. package/native/cmd/ttsc-typia/llm_evaluation_accepts_property_probability_test.go +27 -0
  98. package/native/cmd/ttsc-typia/llm_evaluation_accepts_unselected_source_probability_test.go +26 -0
  99. package/native/cmd/ttsc-typia/llm_evaluation_complete_object_shape_test.go +96 -0
  100. package/native/cmd/ttsc-typia/llm_evaluation_ignores_declaration_probability_without_call_test.go +18 -0
  101. package/native/cmd/ttsc-typia/llm_evaluation_plan_emission_transform_test.go +90 -0
  102. package/native/cmd/ttsc-typia/llm_evaluation_program_scan_dependencies_test.go +69 -0
  103. package/native/cmd/ttsc-typia/llm_evaluation_rejects_alias_comment_test.go +44 -0
  104. package/native/cmd/ttsc-typia/llm_evaluation_rejects_alias_refinement_test.go +45 -0
  105. package/native/cmd/ttsc-typia/llm_evaluation_rejects_computed_method_probability_test.go +30 -0
  106. package/native/cmd/ttsc-typia/llm_evaluation_rejects_imported_declaration_probability_test.go +48 -0
  107. package/native/cmd/ttsc-typia/llm_evaluation_rejects_invalid_probability_test.go +208 -0
  108. package/native/cmd/ttsc-typia/llm_evaluation_rejects_refinements_test.go +94 -0
  109. package/native/cmd/ttsc-typia/llm_evaluation_rejects_undecidable_types_test.go +232 -0
  110. package/native/cmd/ttsc-typia/metadata_type_tag_sole_malformed_diagnostic_test.go +94 -0
  111. package/native/cmd/ttsc-typia/random_recursive_min_items_diagnostic_test.go +18 -1
  112. package/native/cmd/ttsc-typia/template_literal_type_tags_transform_test.go +3 -2
  113. package/native/cmd/ttsc-typia/transform.go +2 -0
  114. package/native/cmd/ttsc-typia/transform_helpers_test.go +17 -3
  115. package/native/core/context/ITypiaContext.go +4 -0
  116. package/native/core/factories/ExpressionFactory.go +16 -1
  117. package/native/core/factories/IdentifierFactory.go +10 -0
  118. package/native/core/factories/LiteralFactory.go +16 -0
  119. package/native/core/factories/MetadataCommentTagFactory.go +185 -35
  120. package/native/core/factories/MetadataTypeTagFactory.go +97 -24
  121. package/native/core/factories/MetadataTypeTagSchemaFactory.go +5 -0
  122. package/native/core/factories/expression_factory_number_spells_non_finite_values_test.go +69 -0
  123. package/native/core/factories/internal/metadata/IMetadataIteratorProps.go +6 -2
  124. package/native/core/factories/internal/metadata/emplace_metadata_object.go +49 -15
  125. package/native/core/factories/literal_factory_null_survives_objects_test.go +43 -0
  126. package/native/core/factories/metadata_comment_tag_factory_holds_bigint_tags_exact_test.go +168 -0
  127. package/native/core/factories/metadata_comment_tag_factory_reads_javascript_numbers_test.go +158 -0
  128. package/native/core/factories/metadata_comment_tag_factory_string_length_helpers_test.go +55 -0
  129. package/native/core/factories/metadata_type_tag_factory_reports_all_invalid_candidates_test.go +73 -0
  130. package/native/core/programmers/functional/FunctionalAssertParametersProgrammer.go +1 -3
  131. package/native/core/programmers/functional/FunctionalIsParametersProgrammer.go +107 -9
  132. package/native/core/programmers/functional/FunctionalValidateParametersProgrammer.go +1 -3
  133. package/native/core/programmers/http/HttpFormDataProgrammer.go +41 -2
  134. package/native/core/programmers/http/HttpHeadersProgrammer.go +56 -4
  135. package/native/core/programmers/http/HttpParameterProgrammer.go +1 -3
  136. package/native/core/programmers/http/HttpQueryProgrammer.go +26 -43
  137. package/native/core/programmers/iterate/json_schema_jsDocTags.go +10 -3
  138. package/native/core/programmers/iterate/json_schema_jsdoc_tags_cast_reads_javascript_numbers_test.go +64 -0
  139. package/native/core/programmers/llm/LlmApplicationProgrammer.go +1 -0
  140. package/native/core/programmers/llm/LlmEvaluationProgrammer.go +559 -0
  141. package/native/core/programmers/llm/LlmParametersProgrammer.go +6 -5
  142. package/native/core/programmers/llm/LlmReferenceDescription.go +113 -0
  143. package/native/core/programmers/llm/LlmSchemaProgrammer.go +34 -4
  144. package/native/core/programmers/llm/llm_reference_description_test.go +134 -0
  145. package/native/core/schemas/metadata/MetadataDependency.go +9 -0
  146. package/native/core/utils/NumberUtil.go +195 -0
  147. package/native/core/utils/number_util_rational_keeps_written_value_test.go +62 -0
  148. package/native/core/utils/number_util_reads_javascript_number_grammar_test.go +147 -0
  149. package/native/transform/CallExpressionTransformer.go +1 -0
  150. package/native/transform/FileTransformer.go +5 -0
  151. package/native/transform/features/llm/LlmEvaluationProbabilityDeclarations.go +94 -0
  152. package/native/transform/features/llm/LlmEvaluationProbabilityDeclarations_test.go +50 -0
  153. package/native/transform/features/llm/LlmEvaluationTransformer.go +59 -0
  154. package/native/transform/features/llm/LlmSchemaTransformer.go +14 -11
  155. package/native/transform/features/llm/llm_transformer_entry_coverage_test.go +29 -27
  156. package/package.json +3 -3
  157. package/src/http.ts +61 -34
  158. package/src/internal/_createLlmEvaluation.ts +678 -0
  159. package/src/internal/_httpFormDataReadBigint.ts +3 -1
  160. package/src/internal/_httpFormDataReadBoolean.ts +3 -1
  161. package/src/internal/_httpFormDataReadNumber.ts +3 -1
  162. package/src/internal/_httpFormDataReadString.ts +10 -1
  163. package/src/internal/_httpHeaderReadBigint.ts +6 -1
  164. package/src/internal/_httpHeaderReadNumber.ts +6 -1
  165. package/src/internal/_httpParameterReadBigint.ts +3 -0
  166. package/src/internal/_httpParameterReadNumber.ts +3 -0
  167. package/src/internal/_httpParameterReadString.ts +12 -2
  168. package/src/internal/_httpQueryReadBigint.ts +7 -1
  169. package/src/internal/_httpQueryReadBoolean.ts +3 -1
  170. package/src/internal/_httpQueryReadNumber.ts +7 -1
  171. package/src/internal/_httpQueryReadString.ts +10 -1
  172. package/src/internal/_randomBigint.ts +111 -3
  173. package/src/internal/_randomInteger.ts +31 -16
  174. package/src/internal/_randomNumber.ts +23 -12
  175. package/src/internal/_stringLengthGte.ts +6 -0
  176. package/src/internal/_stringLengthLte.ts +6 -0
  177. package/src/llm.ts +64 -0
  178. package/src/re-exports.ts +1 -0
@@ -0,0 +1,559 @@
1
+ package llm
2
+
3
+ import (
4
+ "fmt"
5
+ "math"
6
+ "reflect"
7
+ "sort"
8
+ "strconv"
9
+ "strings"
10
+
11
+ shimast "github.com/microsoft/typescript-go/shim/ast"
12
+ nativecontext "github.com/samchon/typia/packages/typia/native/core/context"
13
+ nativefactories "github.com/samchon/typia/packages/typia/native/core/factories"
14
+ schemametadata "github.com/samchon/typia/packages/typia/native/core/schemas/metadata"
15
+ nativeutils "github.com/samchon/typia/packages/typia/native/core/utils"
16
+ )
17
+
18
+ type llmEvaluationProgrammerNamespace struct{}
19
+
20
+ // LlmEvaluationProgrammer writes `typia.llm.evaluation<T>()`.
21
+ //
22
+ // The emitted code is one call to the `_createLlmEvaluation` runtime helper
23
+ // with a compile-time plan: one entry per decision leaf of `T`, carrying its
24
+ // property path, question text, and probability requirements. The helper
25
+ // derives both the question map and the checked decoder from that plan,
26
+ // so the question-key encoding has a single owner at runtime.
27
+ var LlmEvaluationProgrammer = llmEvaluationProgrammerNamespace{}
28
+
29
+ type LlmEvaluationProgrammer_IWriteProps struct {
30
+ Context nativecontext.ITypiaContext
31
+ Metadata *schemametadata.MetadataSchema
32
+ Name *string
33
+ }
34
+
35
+ // LlmEvaluationProgrammer_IError is one rejected position of the decision type.
36
+ type LlmEvaluationProgrammer_IError struct {
37
+ // Accessor is the typia validation path of the position, like
38
+ // `$input.refund.requested`.
39
+ Accessor string
40
+ Message string
41
+ }
42
+
43
+ var llmEvaluationProgrammer_factory = shimast.NewNodeFactory(shimast.NodeFactoryHooks{})
44
+
45
+ // Write emits `_createLlmEvaluation(plan) as ILlmEvaluation<T>`. The metadata
46
+ // must already have passed Compose without errors.
47
+ func (llmEvaluationProgrammerNamespace) Write(props LlmEvaluationProgrammer_IWriteProps, plan []any) *shimast.Node {
48
+ f := nativecontext.EmitFactoryOf(llmEvaluationProgrammer_factory, props.Context.Emit)
49
+ typeName := "unknown"
50
+ if props.Name != nil {
51
+ typeName = *props.Name
52
+ }
53
+ return f.NewAsExpression(
54
+ f.NewCallExpression(
55
+ llmProgrammer_internal(props.Context, "createLlmEvaluation"),
56
+ nil,
57
+ nil,
58
+ f.NewNodeList([]*shimast.Node{
59
+ nativefactories.LiteralFactory.Write(plan, props.Context.Emit),
60
+ }),
61
+ shimast.NodeFlagsNone,
62
+ ),
63
+ llmProgrammer_import_type(props.Context, nativecontext.ImportProgrammer_TypeProps{
64
+ File: "typia",
65
+ Name: "ILlmEvaluation",
66
+ Arguments: []*shimast.TypeNode{llmProgrammer_type_reference(typeName, props.Context.Emit)},
67
+ }),
68
+ )
69
+ }
70
+
71
+ // Compose walks the decision type and returns the evaluation plan, or every
72
+ // position an evaluation model cannot answer.
73
+ func (llmEvaluationProgrammerNamespace) Compose(metadata *schemametadata.MetadataSchema) ([]any, []LlmEvaluationProgrammer_IError) {
74
+ composer := &llmEvaluationComposer{
75
+ plan: []any{},
76
+ visited: map[*schemametadata.MetadataObjectType]bool{},
77
+ }
78
+ object := composer.top(metadata)
79
+ if object != nil {
80
+ composer.object(object, []string{}, "$input")
81
+ if len(composer.errors) == 0 && len(composer.plan) == 0 {
82
+ composer.fail("$input", "LLM evaluation type must have at least one decision property.")
83
+ }
84
+ }
85
+ return composer.plan, composer.errors
86
+ }
87
+
88
+ // Message renders Compose errors in the transformer's unsupported-type layout.
89
+ func (llmEvaluationProgrammerNamespace) Message(errors []LlmEvaluationProgrammer_IError) string {
90
+ lines := make([]string, 0, len(errors))
91
+ for _, err := range errors {
92
+ lines = append(lines, "- "+err.Accessor+"\n - "+err.Message)
93
+ }
94
+ return "unsupported type detected\n\n" + strings.Join(lines, "\n\n")
95
+ }
96
+
97
+ type llmEvaluationComposer struct {
98
+ plan []any
99
+ errors []LlmEvaluationProgrammer_IError
100
+ visited map[*schemametadata.MetadataObjectType]bool
101
+ }
102
+
103
+ func (c *llmEvaluationComposer) fail(accessor string, message string) {
104
+ c.errors = append(c.errors, LlmEvaluationProgrammer_IError{Accessor: accessor, Message: message})
105
+ }
106
+
107
+ func (c *llmEvaluationComposer) top(metadata *schemametadata.MetadataSchema) *schemametadata.MetadataObjectType {
108
+ metadata = llmEvaluation_unalias(metadata)
109
+ if metadata == nil || len(metadata.Objects) == 0 {
110
+ c.fail("$input", "LLM evaluation type must be an object type.")
111
+ return nil
112
+ }
113
+ if len(metadata.Objects) != 1 || metadata.Size() != 1 {
114
+ c.fail("$input", "LLM evaluation type must be a single object type.")
115
+ return nil
116
+ }
117
+ if metadata.Nullable || metadata.IsRequired() == false {
118
+ c.fail("$input", "LLM evaluation type must be a non-nullable and non-undefined object type.")
119
+ return nil
120
+ }
121
+ if message := llmEvaluation_unsupported_tags(metadata.Objects[0].Tags); message != "" {
122
+ c.fail("$input", message)
123
+ return nil
124
+ }
125
+ return metadata.Objects[0].Type
126
+ }
127
+
128
+ func (c *llmEvaluationComposer) object(object *schemametadata.MetadataObjectType, path []string, accessor string) {
129
+ if c.visited[object] {
130
+ c.fail(accessor, "LLM evaluation does not support recursive types.")
131
+ return
132
+ }
133
+ c.visited[object] = true
134
+ defer delete(c.visited, object)
135
+
136
+ for _, property := range object.Properties {
137
+ key := property.Key.GetSoleLiteral()
138
+ if key == nil {
139
+ c.fail(accessor, "LLM evaluation does not support dynamic keys.")
140
+ continue
141
+ }
142
+ c.property(property, append(append([]string{}, path...), *key), accessor+nativefactories.IdentifierFactory.PathPostfix(*key))
143
+ }
144
+ }
145
+
146
+ func (c *llmEvaluationComposer) property(property *schemametadata.MetadataProperty, path []string, accessor string) {
147
+ value := llmEvaluation_unalias(property.Value)
148
+ if llmEvaluation_has_tag(property.JsDocTags, "hidden", "ignore", "internal") {
149
+ c.fail(accessor, "LLM evaluation does not support hidden properties, because every property of the result needs an answer.")
150
+ return
151
+ }
152
+ // typia's metadata folds unknown into any, and never and void into an
153
+ // undefined value, so each message names the class the metadata records
154
+ if value == nil || value.Any {
155
+ c.fail(accessor, "LLM evaluation does not support any or unknown types, because an evaluation model answers only closed sets.")
156
+ return
157
+ }
158
+ if value.Optional || value.Required == false {
159
+ c.fail(accessor, "LLM evaluation does not support optional, undefined, void, or never properties, because every property of the result needs an answer.")
160
+ return
161
+ }
162
+ if value.Nullable {
163
+ c.fail(accessor, "LLM evaluation does not support nullable properties.")
164
+ return
165
+ }
166
+ if len(value.Functions) != 0 {
167
+ c.fail(accessor, "LLM evaluation does not support function properties.")
168
+ return
169
+ }
170
+
171
+ // nested object: flattened, so the property itself asks nothing
172
+ if len(value.Objects) != 0 {
173
+ if len(value.Objects) != 1 || value.Size() != 1 {
174
+ c.fail(accessor, "LLM evaluation does not support union types.")
175
+ return
176
+ }
177
+ if message := llmEvaluation_unsupported_tags(value.Objects[0].Tags); message != "" {
178
+ c.fail(accessor, message)
179
+ return
180
+ }
181
+ if _, found := llmEvaluation_jsdoc_probability(property.JsDocTags); found {
182
+ c.fail(accessor, "LLM evaluation @probability must be on a boolean, choice, score, or set property, not on an object.")
183
+ }
184
+ plan, errors := len(c.plan), len(c.errors)
185
+ c.object(value.Objects[0].Type, path, accessor)
186
+ if len(c.plan) == plan && len(c.errors) == errors {
187
+ // no answer could ever create the object, so decode() would return a
188
+ // value missing this required property
189
+ c.fail(accessor, "LLM evaluation object must have at least one decision property.")
190
+ }
191
+ return
192
+ }
193
+
194
+ kind := llmEvaluation_kind(value)
195
+ if kind == "" {
196
+ c.fail(accessor, llmEvaluation_unsupported(value))
197
+ return
198
+ }
199
+ instructions := llmEvaluation_description(property.Description, property.JsDocTags)
200
+ if instructions == nil || strings.TrimSpace(*instructions) == "" {
201
+ c.fail(accessor, "LLM evaluation property must have a JSDoc description, because it is the question text.")
202
+ return
203
+ }
204
+ fallback, hasFallback, message := llmEvaluation_property_probability(property.JsDocTags)
205
+ if message != "" {
206
+ c.fail(accessor, message)
207
+ return
208
+ }
209
+
210
+ leaf := map[string]any{
211
+ "kind": kind,
212
+ "path": llmEvaluation_strings(path),
213
+ "instructions": *instructions,
214
+ }
215
+ switch kind {
216
+ case "boolean":
217
+ if message := llmEvaluation_unsupported_tags(value.Atomics[0].Tags); message != "" {
218
+ c.fail(accessor, message)
219
+ return
220
+ }
221
+ threshold := 0.5
222
+ tagged, found, message := llmEvaluation_tag_probability(value.Atomics[0].Tags)
223
+ if message != "" {
224
+ c.fail(accessor, message)
225
+ return
226
+ }
227
+ if found && hasFallback {
228
+ c.fail(accessor, "LLM evaluation boolean has both tags.Probability and @probability; keep only one.")
229
+ return
230
+ }
231
+ if found {
232
+ threshold = tagged
233
+ } else if hasFallback {
234
+ threshold = fallback
235
+ }
236
+ leaf["threshold"] = threshold
237
+ case "choice", "score", "set":
238
+ constant := value.Constants
239
+ if kind == "set" {
240
+ constant = llmEvaluation_unalias(value.Arrays[0].Type.Value).Constants
241
+ }
242
+ entries := constant[0].Values
243
+ if kind == "score" {
244
+ entries = append([]*schemametadata.MetadataConstantValue{}, entries...)
245
+ sort.SliceStable(entries, func(i, j int) bool {
246
+ left, _ := llmEvaluation_number(entries[i].Value)
247
+ right, _ := llmEvaluation_number(entries[j].Value)
248
+ return left < right
249
+ })
250
+ }
251
+ members := make([]any, 0, len(entries))
252
+ hasMemberRequirement := false
253
+ missingRequirements := make([]*schemametadata.MetadataConstantValue, 0)
254
+ for _, entry := range entries {
255
+ if message := llmEvaluation_unsupported_tags(entry.Tags); message != "" {
256
+ c.fail(accessor, fmt.Sprintf("%s (member %s)", message, llmEvaluation_value_text(entry.Value)))
257
+ continue
258
+ }
259
+ member := map[string]any{"value": llmEvaluation_value(entry.Value)}
260
+ // an undocumented score level is described by its value, which the
261
+ // runtime writes with JavaScript's own number formatting
262
+ if description := llmEvaluation_member_description(entry); description != nil {
263
+ member["description"] = *description
264
+ }
265
+ requirement, found, message := llmEvaluation_member_probability(entry)
266
+ if message != "" {
267
+ c.fail(accessor, fmt.Sprintf("%s (member %s)", message, llmEvaluation_value_text(entry.Value)))
268
+ continue
269
+ }
270
+ if found == false && hasFallback {
271
+ requirement, found = fallback, true
272
+ }
273
+ if found {
274
+ hasMemberRequirement = true
275
+ } else {
276
+ missingRequirements = append(missingRequirements, entry)
277
+ }
278
+ if kind == "set" {
279
+ if found == false {
280
+ requirement = 0.5
281
+ }
282
+ member["threshold"] = requirement
283
+ } else if found {
284
+ member["minimum"] = requirement
285
+ }
286
+ members = append(members, member)
287
+ }
288
+ if hasMemberRequirement && len(missingRequirements) != 0 {
289
+ for _, entry := range missingRequirements {
290
+ c.fail(accessor, fmt.Sprintf(
291
+ "LLM evaluation probability requirements must cover every member once one member declares one; add tags.Probability or @probability to member %s, or add a property @probability default.",
292
+ llmEvaluation_value_text(entry.Value),
293
+ ))
294
+ }
295
+ }
296
+ leaf[map[string]string{"choice": "options", "score": "levels", "set": "members"}[kind]] = members
297
+ }
298
+ c.plan = append(c.plan, leaf)
299
+ }
300
+
301
+ // A decoded value is trusted as T, so every tag with a validation meaning
302
+ // must either be enforced here or rejected. These kinds only annotate schema
303
+ // documentation or other serializers; probability is enforced by the decoder.
304
+ func llmEvaluation_unsupported_tags(rows [][]schemametadata.IMetadataTypeTag) string {
305
+ for _, row := range rows {
306
+ for _, tag := range row {
307
+ if tag.Validate != "" {
308
+ return fmt.Sprintf("LLM evaluation does not support type tag %q, because decode() cannot enforce its constraint.", tag.Kind)
309
+ }
310
+ switch tag.Kind {
311
+ case "probability", "constant", "default", "example", "examples", "contentMediaType", "sequence":
312
+ continue
313
+ default:
314
+ return fmt.Sprintf("LLM evaluation does not support type tag %q, because decode() cannot enforce its constraint.", tag.Kind)
315
+ }
316
+ }
317
+ }
318
+ return ""
319
+ }
320
+
321
+ // llmEvaluation_kind classifies a non-object property value as one question
322
+ // family, or "" when no evaluation question can answer it.
323
+ func llmEvaluation_kind(value *schemametadata.MetadataSchema) string {
324
+ if value.Escaped != nil || value.Rest != nil || len(value.Templates) != 0 ||
325
+ len(value.Tuples) != 0 || len(value.Natives) != 0 || len(value.Sets) != 0 ||
326
+ len(value.Maps) != 0 || len(value.Aliases) != 0 {
327
+ return ""
328
+ }
329
+ if len(value.Atomics) == 1 && value.Atomics[0].Type == "boolean" &&
330
+ len(value.Constants) == 0 && len(value.Arrays) == 0 {
331
+ return "boolean"
332
+ }
333
+ if len(value.Atomics) == 0 && len(value.Arrays) == 0 && len(value.Constants) == 1 &&
334
+ len(value.Constants[0].Values) >= 2 {
335
+ switch value.Constants[0].Type {
336
+ case "string":
337
+ return "choice"
338
+ case "number":
339
+ return "score"
340
+ }
341
+ return ""
342
+ }
343
+ if len(value.Atomics) == 0 && len(value.Constants) == 0 && len(value.Arrays) == 1 &&
344
+ len(value.Arrays[0].Tags) == 0 {
345
+ element := llmEvaluation_unalias(value.Arrays[0].Type.Value)
346
+ if element != nil && element.IsConstant() && element.Nullable == false && element.IsRequired() &&
347
+ len(element.Constants) == 1 && element.Constants[0].Type == "string" &&
348
+ len(element.Constants[0].Values) != 0 {
349
+ return "set"
350
+ }
351
+ }
352
+ return ""
353
+ }
354
+
355
+ func llmEvaluation_unsupported(value *schemametadata.MetadataSchema) string {
356
+ if len(value.Arrays) == 1 && len(value.Arrays[0].Tags) != 0 {
357
+ return "LLM evaluation does not support array type tags, because the answered members decide the array."
358
+ }
359
+ if len(value.Arrays) != 0 {
360
+ return "LLM evaluation supports only arrays of a string literal union or string enum."
361
+ }
362
+ if len(value.Constants) == 1 && len(value.Constants[0].Values) == 1 && len(value.Atomics) == 0 {
363
+ return "LLM evaluation does not support a single literal value, because it decides nothing."
364
+ }
365
+ if len(value.Constants) > 1 || (len(value.Constants) != 0 && len(value.Atomics) != 0) {
366
+ return "LLM evaluation does not support union types mixing different question kinds."
367
+ }
368
+ if len(value.Constants) == 1 && value.Constants[0].Type != "string" && value.Constants[0].Type != "number" {
369
+ return fmt.Sprintf("LLM evaluation does not support %s literal types.", value.Constants[0].Type)
370
+ }
371
+ return "LLM evaluation supports only boolean, string or numeric literal unions (or enums), arrays of a string literal union (or enum), and objects composed of them, because an evaluation model answers only closed sets."
372
+ }
373
+
374
+ func llmEvaluation_unalias(metadata *schemametadata.MetadataSchema) *schemametadata.MetadataSchema {
375
+ for metadata != nil && len(metadata.Aliases) == 1 && metadata.Size() == 1 &&
376
+ metadata.Aliases[0].Type != nil && metadata.Aliases[0].Type.Value != nil {
377
+ metadata = metadata.Aliases[0].Type.Value
378
+ }
379
+ return metadata
380
+ }
381
+
382
+ func llmEvaluation_description(description *string, tags []schemametadata.IJsDocTagInfo) *string {
383
+ for _, tag := range tags {
384
+ if tag.Name != "description" || len(tag.Text) == 0 {
385
+ continue
386
+ }
387
+ text := strings.ReplaceAll(tag.Text[0].Text, "\r\n", "\n")
388
+ return &text
389
+ }
390
+ if description == nil {
391
+ return nil
392
+ }
393
+ text := strings.ReplaceAll(*description, "\r\n", "\n")
394
+ return &text
395
+ }
396
+
397
+ func llmEvaluation_member_description(entry *schemametadata.MetadataConstantValue) *string {
398
+ if description := llmEvaluation_description(entry.Description, entry.JsDocTags); description != nil && strings.TrimSpace(*description) != "" {
399
+ return description
400
+ }
401
+ for _, row := range entry.Tags {
402
+ for _, tag := range row {
403
+ if tag.Kind != "constant" {
404
+ continue
405
+ }
406
+ schema, ok := tag.Schema.(map[string]any)
407
+ if ok == false {
408
+ continue
409
+ }
410
+ if text, ok := schema["description"].(string); ok && strings.TrimSpace(text) != "" {
411
+ return &text
412
+ }
413
+ }
414
+ }
415
+ return nil
416
+ }
417
+
418
+ func llmEvaluation_has_tag(tags []schemametadata.IJsDocTagInfo, names ...string) bool {
419
+ for _, tag := range tags {
420
+ for _, name := range names {
421
+ if tag.Name == name {
422
+ return true
423
+ }
424
+ }
425
+ }
426
+ return false
427
+ }
428
+
429
+ // llmEvaluation_jsdoc_probability reads the raw `@probability` comment tags.
430
+ func llmEvaluation_jsdoc_probability(tags []schemametadata.IJsDocTagInfo) ([]string, bool) {
431
+ texts := []string{}
432
+ for _, tag := range tags {
433
+ if tag.Name != "probability" {
434
+ continue
435
+ }
436
+ parts := make([]string, 0, len(tag.Text))
437
+ for _, part := range tag.Text {
438
+ parts = append(parts, part.Text)
439
+ }
440
+ texts = append(texts, strings.TrimSpace(strings.Join(parts, "")))
441
+ }
442
+ return texts, len(texts) != 0
443
+ }
444
+
445
+ func llmEvaluation_parse_jsdoc_probability(tags []schemametadata.IJsDocTagInfo) (float64, bool, string) {
446
+ texts, found := llmEvaluation_jsdoc_probability(tags)
447
+ if found == false {
448
+ return 0, false, ""
449
+ }
450
+ if len(texts) != 1 {
451
+ return 0, false, "LLM evaluation @probability is declared more than once; keep only one."
452
+ }
453
+ // The same JavaScript `Number()` grammar every other numeric JSDoc tag reads
454
+ // (samchon/typia#2442); Go's float syntax would also admit `0x1p-1`.
455
+ reading := nativeutils.NumberUtil.Read(texts[0])
456
+ if reading.Numeric == false || reading.Finite == false {
457
+ return 0, false, fmt.Sprintf("LLM evaluation @probability must be a number in [0, 1], but got %q.", texts[0])
458
+ }
459
+ value := reading.Value
460
+ if value < 0 || value > 1 {
461
+ return 0, false, fmt.Sprintf("LLM evaluation @probability must be in [0, 1], but got %s.", texts[0])
462
+ }
463
+ return value, true, ""
464
+ }
465
+
466
+ func llmEvaluation_property_probability(tags []schemametadata.IJsDocTagInfo) (float64, bool, string) {
467
+ return llmEvaluation_parse_jsdoc_probability(tags)
468
+ }
469
+
470
+ func llmEvaluation_tag_probability(rows [][]schemametadata.IMetadataTypeTag) (float64, bool, string) {
471
+ values := []any{}
472
+ for _, row := range rows {
473
+ for _, tag := range row {
474
+ if tag.Kind == "probability" {
475
+ values = append(values, tag.Value)
476
+ }
477
+ }
478
+ }
479
+ if len(values) == 0 {
480
+ return 0, false, ""
481
+ }
482
+ if len(values) != 1 {
483
+ return 0, false, "LLM evaluation tags.Probability is declared more than once; keep only one."
484
+ }
485
+ value, ok := llmEvaluation_number(values[0])
486
+ if ok == false || math.IsNaN(value) || math.IsInf(value, 0) {
487
+ return 0, false, "LLM evaluation tags.Probability must have a numeric literal value."
488
+ }
489
+ if value < 0 || value > 1 {
490
+ return 0, false, fmt.Sprintf("LLM evaluation tags.Probability must be in [0, 1], but got %s.", llmEvaluation_number_text(value))
491
+ }
492
+ return value, true, ""
493
+ }
494
+
495
+ func llmEvaluation_member_probability(entry *schemametadata.MetadataConstantValue) (float64, bool, string) {
496
+ tagged, taggedFound, message := llmEvaluation_tag_probability(entry.Tags)
497
+ if message != "" {
498
+ return 0, false, message
499
+ }
500
+ commented, commentedFound, message := llmEvaluation_parse_jsdoc_probability(entry.JsDocTags)
501
+ if message != "" {
502
+ return 0, false, message
503
+ }
504
+ if taggedFound && commentedFound {
505
+ return 0, false, "LLM evaluation member has both tags.Probability and @probability; keep only one."
506
+ }
507
+ if taggedFound {
508
+ return tagged, true, ""
509
+ }
510
+ return commented, commentedFound, ""
511
+ }
512
+
513
+ func llmEvaluation_number(value any) (float64, bool) {
514
+ reflected := reflect.ValueOf(value)
515
+ switch reflected.Kind() {
516
+ case reflect.Float32, reflect.Float64:
517
+ return reflected.Float(), true
518
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
519
+ return float64(reflected.Int()), true
520
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
521
+ return float64(reflected.Uint()), true
522
+ }
523
+ return 0, false
524
+ }
525
+
526
+ // llmEvaluation_value normalizes a literal to a plain Go value LiteralFactory
527
+ // writes, so a checker-specific number type never reaches the emitter.
528
+ func llmEvaluation_value(value any) any {
529
+ if str, ok := value.(string); ok {
530
+ return str
531
+ }
532
+ if number, ok := llmEvaluation_number(value); ok {
533
+ return number
534
+ }
535
+ return value
536
+ }
537
+
538
+ func llmEvaluation_number_text(value any) string {
539
+ number, ok := llmEvaluation_number(value)
540
+ if ok == false {
541
+ return fmt.Sprint(value)
542
+ }
543
+ return strconv.FormatFloat(number, 'f', -1, 64)
544
+ }
545
+
546
+ func llmEvaluation_value_text(value any) string {
547
+ if str, ok := value.(string); ok {
548
+ return strconv.Quote(str)
549
+ }
550
+ return llmEvaluation_number_text(value)
551
+ }
552
+
553
+ func llmEvaluation_strings(values []string) []any {
554
+ output := make([]any, 0, len(values))
555
+ for _, value := range values {
556
+ output = append(output, value)
557
+ }
558
+ return output
559
+ }
@@ -1,8 +1,6 @@
1
1
  package llm
2
2
 
3
3
  import (
4
- "strings"
5
-
6
4
  shimast "github.com/microsoft/typescript-go/shim/ast"
7
5
  nativecontext "github.com/samchon/typia/packages/typia/native/core/context"
8
6
  nativefactories "github.com/samchon/typia/packages/typia/native/core/factories"
@@ -73,11 +71,13 @@ func (llmParametersProgrammerNamespace) WriteParameters(props struct {
73
71
  return llmParametersProgrammer_convert_parameters(schema, collection.Components, props.Config)
74
72
  }
75
73
  if ref, ok := schema["$ref"].(string); ok {
76
- name := ref[strings.LastIndex(ref, "/")+1:]
74
+ name := llmSchemaProgrammer_ref_key(ref)
77
75
  if collection.Components != nil && collection.Components.Schemas != nil {
78
76
  if target, found := collection.Components.Schemas[name]; found {
79
77
  if typ, ok := target["type"].(string); ok && typ == "object" {
80
- return llmParametersProgrammer_convert_parameters(target, collection.Components, props.Config)
78
+ // the reference itself, so the root description can cascade from
79
+ // its component key
80
+ return llmParametersProgrammer_convert_parameters(schema, collection.Components, props.Config)
81
81
  }
82
82
  }
83
83
  }
@@ -125,6 +125,7 @@ func llmParametersProgrammer_convert_parameters(schema nativeiterate.JsonSchema,
125
125
  output := llmSchemaProgrammer_convert_schema_config(target, components, defs, config)
126
126
  output["additionalProperties"] = false
127
127
  output["$defs"] = defs
128
+ llmReferenceDescription_assign(output, schema, components)
128
129
  return output
129
130
  }
130
131
 
@@ -133,7 +134,7 @@ func llmParametersProgrammer_dereference_schema(schema nativeiterate.JsonSchema,
133
134
  if ok == false || components == nil || components.Schemas == nil {
134
135
  return schema
135
136
  }
136
- name := ref[strings.LastIndex(ref, "/")+1:]
137
+ name := llmSchemaProgrammer_ref_key(ref)
137
138
  if target, found := components.Schemas[name]; found {
138
139
  return target
139
140
  }