Class: GenerativeUI::Catalog
- Inherits:
-
Object
- Object
- GenerativeUI::Catalog
show all
- Defined in:
- lib/generative_ui/catalog.rb
Defined Under Namespace
Classes: InvalidCatalogError
Constant Summary
collapse
- REF_DEFS =
{
ComponentId: {
type: 'string',
description: 'Reference to another component id in this UI tree.'
},
ComponentIdList: {
type: 'array',
description: 'Ordered list of referenced component ids.',
items: { "$ref": '#/$defs/ComponentId' }
}
}.freeze
- COMPONENT_NAME_REGEX =
/\A[A-Z][a-zA-Z0-9]*\z/
- PROPERTY_NAME_REGEX =
/\A[a-z][a-zA-Z0-9_]*\z/
- ACRONYM_RUN_REGEX =
/[A-Z]{2,}/
- UNDERSCORE_CAP_REGEX =
/_[A-Z]/
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
Returns a new instance of Catalog.
84
85
86
87
|
# File 'lib/generative_ui/catalog.rb', line 84
def initialize
@definitions = self.class.component_definitions.dup
validate!
end
|
Instance Attribute Details
#definitions ⇒ Object
Returns the value of attribute definitions.
19
20
21
|
# File 'lib/generative_ui/catalog.rb', line 19
def definitions
@definitions
end
|
Class Method Details
.coerce(value) ⇒ Object
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
# File 'lib/generative_ui/catalog.rb', line 49
def self.coerce(value)
case value
when Catalog
value
when Class
raise ArgumentError, "expected Catalog subclass, got #{value}" unless value <= Catalog
value.new
when Symbol, String
name = value.to_sym
configured = GenerativeUI.configuration.catalog(name)
return instantiate(configured) if configured
if name == :default
raise ArgumentError,
'Default generative UI catalog is not configured. Configure ' \
'`config.catalog :default, "ApplicationGenerativeCatalog"` in an initializer.'
end
raise ArgumentError, "Unknown generative UI catalog: #{name.inspect}"
else
raise ArgumentError, 'expected Catalog, catalog class, or catalog name'
end
end
|
.component(name, &block) ⇒ Object
22
23
24
25
26
27
28
29
30
31
|
# File 'lib/generative_ui/catalog.rb', line 22
def component(name, &block)
definition = ComponentDefinition.build(name, &block)
if component_definitions.any? { |existing| existing.component == definition.component }
warn "GenerativeUI: component #{definition.component.inspect} was already declared; replacing previous declaration"
component_definitions.delete_if { |existing| existing.component == definition.component }
end
component_definitions << definition
end
|
.component_definitions ⇒ Object
40
41
42
|
# File 'lib/generative_ui/catalog.rb', line 40
def component_definitions
@component_definitions ||= []
end
|
.default_targets ⇒ Object
44
45
46
|
# File 'lib/generative_ui/catalog.rb', line 44
def default_targets
@default_targets ||= {}
end
|
.instantiate(value) ⇒ Object
74
75
76
77
78
79
80
81
82
|
# File 'lib/generative_ui/catalog.rb', line 74
def self.instantiate(value)
case value
when Catalog then value
when Class then value.new
when String then value.constantize.new
else
raise ArgumentError, "cannot instantiate catalog from #{value.inspect}"
end
end
|
.present_with(adapter, target = nil, &block) ⇒ Object
33
34
35
36
37
38
|
# File 'lib/generative_ui/catalog.rb', line 33
def present_with(adapter, target = nil, &block)
raise ArgumentError, 'present_with at catalog scope requires a block' unless block
raise ArgumentError, 'present_with at catalog scope does not take a positional target' unless target.nil?
default_targets[adapter.to_sym] = block
end
|
Instance Method Details
#component_schema(component_name) ⇒ Object
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
# File 'lib/generative_ui/catalog.rb', line 138
def component_schema(component_name)
definition = fetch(component_name)
raise ArgumentError, "Unknown generative component: #{component_name}" unless definition
attributes_schema = definition.attributes_json_schema
properties = attributes_schema.fetch(:properties, {}).transform_values do |schema|
compile_provider_schema(schema)
end
required = Array(attributes_schema[:required]).map(&:to_sym)
{
type: 'object',
"$defs": REF_DEFS,
properties: {
id: { type: 'string' },
component: { const: definition.component },
**properties
},
required: [:id, :component, *required],
additionalProperties: attributes_schema.fetch(:additionalProperties, false)
}
end
|
#empty? ⇒ Boolean
93
94
95
|
# File 'lib/generative_ui/catalog.rb', line 93
def empty?
definitions.empty?
end
|
#fetch(component) ⇒ Object
97
98
99
|
# File 'lib/generative_ui/catalog.rb', line 97
def fetch(component)
definitions.find { |definition| definition.component == component.to_s }
end
|
#names ⇒ Object
89
90
91
|
# File 'lib/generative_ui/catalog.rb', line 89
def names
definitions.map(&:component).sort
end
|
#target_for(definition, adapter) ⇒ Object
181
182
183
184
185
186
187
188
|
# File 'lib/generative_ui/catalog.rb', line 181
def target_for(definition, adapter)
adapter = adapter.to_sym
name = definition.respond_to?(:component) ? definition.component : definition.name
definition.render_target_for(adapter) \
|| resolve_catalog_default(adapter, name) \
|| Conventions.fetch(adapter).call(name)
end
|
#to_prompt ⇒ Object
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
# File 'lib/generative_ui/catalog.rb', line 120
def to_prompt
lines = ['Components:']
to_prompt_entries.each do |entry|
description = entry.fetch(:description)
lines << (description.nil? ? "- #{entry.fetch(:component)}" : "- #{entry.fetch(:component)}: #{description}")
if entry.fetch(:required).empty? && entry.fetch(:optional).empty?
lines << ' attributes: none'
else
lines << " required: #{entry.fetch(:required).join(', ')}" if entry.fetch(:required).any?
lines << " optional: #{entry.fetch(:optional).join(', ')}" if entry.fetch(:optional).any?
end
end
lines.join("\n")
end
|
#to_prompt_entries ⇒ Object
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
# File 'lib/generative_ui/catalog.rb', line 101
def to_prompt_entries
definitions.sort_by(&:component).map do |definition|
schema = definition.attributes_json_schema
required = Array(schema[:required] || schema['required']).map(&:to_s)
properties = schema[:properties] || schema['properties'] || {}
props = properties.flat_map do |name, property_schema|
prompt_properties(name.to_s, property_schema).map { |prop| [name.to_s, prop] }
end
{
component: definition.component,
description: definition.description_text,
required: props.select { |name, _| required.include?(name) }.map(&:last),
optional: props.reject { |name, _| required.include?(name) }.map(&:last)
}
end
end
|
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
# File 'lib/generative_ui/catalog.rb', line 161
def tool_arguments_schema
{
type: 'object',
"$defs": REF_DEFS,
properties: {
components: {
type: 'array',
items: { anyOf: names.map { |name| component_schema(name) } }
}
},
required: [:components],
additionalProperties: false
}
end
|