poml 0.0.1 → 0.0.3
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.
- checksums.yaml +4 -4
- data/lib/poml/components/base.rb +45 -7
- data/lib/poml/components/data.rb +310 -12
- data/lib/poml/components/examples.rb +159 -13
- data/lib/poml/components/formatting.rb +148 -0
- data/lib/poml/components/media.rb +34 -0
- data/lib/poml/components/meta.rb +248 -0
- data/lib/poml/components/template.rb +334 -0
- data/lib/poml/components/utilities.rb +580 -0
- data/lib/poml/components.rb +93 -2
- data/lib/poml/context.rb +41 -2
- data/lib/poml/parser.rb +128 -15
- data/lib/poml/renderer.rb +26 -7
- data/lib/poml/template_engine.rb +101 -4
- data/lib/poml/version.rb +1 -1
- data/lib/poml.rb +67 -1
- data/{README.md → readme.md} +9 -1
- metadata +8 -4
- data/examples/_generate_expects.py +0 -35
@@ -0,0 +1,580 @@
|
|
1
|
+
module Poml
|
2
|
+
# AI Message component for wrapping AI responses
|
3
|
+
class AiMessageComponent < Component
|
4
|
+
def render
|
5
|
+
apply_stylesheet
|
6
|
+
|
7
|
+
content = @element.content.empty? ? render_children : @element.content
|
8
|
+
|
9
|
+
# Add to structured chat messages if context supports it
|
10
|
+
if @context.respond_to?(:chat_messages)
|
11
|
+
@context.chat_messages << {
|
12
|
+
'role' => 'assistant',
|
13
|
+
'content' => content
|
14
|
+
}
|
15
|
+
# Return empty for raw format to avoid duplication
|
16
|
+
return ''
|
17
|
+
end
|
18
|
+
|
19
|
+
if xml_mode?
|
20
|
+
render_as_xml('ai-msg', content, { speaker: 'ai' })
|
21
|
+
else
|
22
|
+
content
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Human Message component for wrapping user messages
|
28
|
+
class HumanMessageComponent < Component
|
29
|
+
def render
|
30
|
+
apply_stylesheet
|
31
|
+
|
32
|
+
content = @element.content.empty? ? render_children : @element.content
|
33
|
+
|
34
|
+
# Add to structured chat messages if context supports it
|
35
|
+
if @context.respond_to?(:chat_messages)
|
36
|
+
@context.chat_messages << {
|
37
|
+
'role' => 'user',
|
38
|
+
'content' => content
|
39
|
+
}
|
40
|
+
# Return empty for raw format to avoid duplication
|
41
|
+
return ''
|
42
|
+
end
|
43
|
+
|
44
|
+
if xml_mode?
|
45
|
+
render_as_xml('user-msg', content, { speaker: 'human' })
|
46
|
+
else
|
47
|
+
content
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# System Message component for wrapping system messages
|
53
|
+
class SystemMessageComponent < Component
|
54
|
+
def render
|
55
|
+
apply_stylesheet
|
56
|
+
|
57
|
+
content = @element.content.empty? ? render_children : @element.content
|
58
|
+
|
59
|
+
# Add to structured chat messages if context supports it
|
60
|
+
if @context.respond_to?(:chat_messages)
|
61
|
+
@context.chat_messages << {
|
62
|
+
'role' => 'system',
|
63
|
+
'content' => content
|
64
|
+
}
|
65
|
+
# Return empty for raw format to avoid duplication
|
66
|
+
return ''
|
67
|
+
end
|
68
|
+
|
69
|
+
if xml_mode?
|
70
|
+
render_as_xml('system-msg', content, { speaker: 'system' })
|
71
|
+
else
|
72
|
+
content
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Message Content component for displaying message content
|
78
|
+
class MessageContentComponent < Component
|
79
|
+
def render
|
80
|
+
apply_stylesheet
|
81
|
+
|
82
|
+
content_attr = get_attribute('content')
|
83
|
+
|
84
|
+
if content_attr.is_a?(Array)
|
85
|
+
# Handle array of content items
|
86
|
+
content_attr.map { |item|
|
87
|
+
item.is_a?(String) ? item : item.to_s
|
88
|
+
}.join('')
|
89
|
+
elsif content_attr.is_a?(String)
|
90
|
+
content_attr
|
91
|
+
else
|
92
|
+
content_attr.to_s
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Conversation component for displaying chat conversations
|
98
|
+
class ConversationComponent < Component
|
99
|
+
def render
|
100
|
+
apply_stylesheet
|
101
|
+
|
102
|
+
messages_attr = get_attribute('messages')
|
103
|
+
messages = if messages_attr.is_a?(String)
|
104
|
+
begin
|
105
|
+
require 'json'
|
106
|
+
JSON.parse(messages_attr)
|
107
|
+
rescue JSON::ParserError
|
108
|
+
[]
|
109
|
+
end
|
110
|
+
else
|
111
|
+
messages_attr || []
|
112
|
+
end
|
113
|
+
|
114
|
+
selected_messages = get_attribute('selectedMessages')
|
115
|
+
|
116
|
+
# Apply message selection if specified
|
117
|
+
if selected_messages
|
118
|
+
messages = apply_message_selection(messages, selected_messages)
|
119
|
+
end
|
120
|
+
|
121
|
+
if xml_mode?
|
122
|
+
render_conversation_xml(messages)
|
123
|
+
else
|
124
|
+
render_conversation_markdown(messages)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def apply_message_selection(messages, selection)
|
131
|
+
return messages unless selection
|
132
|
+
|
133
|
+
if selection.include?(':')
|
134
|
+
# Handle slice notation like "2:4" or "-6:"
|
135
|
+
start_idx, end_idx = parse_slice(selection, messages.length)
|
136
|
+
messages[start_idx...end_idx] || []
|
137
|
+
elsif selection.is_a?(Integer)
|
138
|
+
# Single message index
|
139
|
+
[messages[selection]].compact
|
140
|
+
else
|
141
|
+
messages
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def parse_slice(slice_str, total_length)
|
146
|
+
if slice_str.start_with?('-') && slice_str.end_with?(':')
|
147
|
+
# Handle "-6:" (last 6 messages)
|
148
|
+
count = slice_str[1..-2].to_i
|
149
|
+
[total_length - count, total_length]
|
150
|
+
elsif slice_str.include?(':')
|
151
|
+
parts = slice_str.split(':')
|
152
|
+
start_idx = parts[0].empty? ? 0 : parts[0].to_i
|
153
|
+
end_idx = parts[1].empty? ? total_length : parts[1].to_i
|
154
|
+
[start_idx, end_idx]
|
155
|
+
else
|
156
|
+
index = slice_str.to_i
|
157
|
+
[index, index + 1]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def render_conversation_xml(messages)
|
162
|
+
result = ['<conversation>']
|
163
|
+
messages.each do |msg|
|
164
|
+
speaker = msg['speaker'] || 'human'
|
165
|
+
content = msg['content'] || ''
|
166
|
+
result << " <msg speaker=\"#{speaker}\">#{escape_xml(content)}</msg>"
|
167
|
+
end
|
168
|
+
result << '</conversation>'
|
169
|
+
result.join("\n")
|
170
|
+
end
|
171
|
+
|
172
|
+
def render_conversation_markdown(messages)
|
173
|
+
result = []
|
174
|
+
messages.each do |msg|
|
175
|
+
speaker = msg['speaker'] || 'human'
|
176
|
+
content = msg['content'] || ''
|
177
|
+
|
178
|
+
case speaker.downcase
|
179
|
+
when 'human', 'user'
|
180
|
+
result << "**Human:** #{content}"
|
181
|
+
when 'ai', 'assistant'
|
182
|
+
result << "**Assistant:** #{content}"
|
183
|
+
when 'system'
|
184
|
+
result << "**System:** #{content}"
|
185
|
+
else
|
186
|
+
result << "**#{speaker.capitalize}:** #{content}"
|
187
|
+
end
|
188
|
+
result << ""
|
189
|
+
end
|
190
|
+
result.join("\n")
|
191
|
+
end
|
192
|
+
|
193
|
+
def escape_xml(text)
|
194
|
+
text.to_s.gsub('&', '&').gsub('<', '<').gsub('>', '>').gsub('"', '"')
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Folder component for displaying directory structures
|
199
|
+
class FolderComponent < Component
|
200
|
+
require 'find'
|
201
|
+
|
202
|
+
def render
|
203
|
+
apply_stylesheet
|
204
|
+
|
205
|
+
src = get_attribute('src')
|
206
|
+
filter = get_attribute('filter')
|
207
|
+
max_depth = get_attribute('maxDepth', 3).to_i
|
208
|
+
show_content = get_attribute('showContent', false)
|
209
|
+
syntax = get_attribute('syntax', 'text')
|
210
|
+
|
211
|
+
return '[Folder: no src specified]' unless src
|
212
|
+
return '[Folder: directory not found]' unless Dir.exist?(src)
|
213
|
+
|
214
|
+
tree_data = build_tree_structure(src, filter, max_depth, show_content)
|
215
|
+
|
216
|
+
if xml_mode?
|
217
|
+
render_folder_xml(tree_data)
|
218
|
+
else
|
219
|
+
case syntax
|
220
|
+
when 'markdown'
|
221
|
+
render_folder_markdown(tree_data)
|
222
|
+
when 'json'
|
223
|
+
require 'json'
|
224
|
+
JSON.pretty_generate(tree_data)
|
225
|
+
else
|
226
|
+
render_folder_text(tree_data)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
private
|
232
|
+
|
233
|
+
def build_tree_structure(path, filter, max_depth, show_content, current_depth = 0)
|
234
|
+
return nil if current_depth >= max_depth
|
235
|
+
|
236
|
+
items = []
|
237
|
+
|
238
|
+
begin
|
239
|
+
Dir.entries(path).sort.each do |entry|
|
240
|
+
next if entry.start_with?('.')
|
241
|
+
|
242
|
+
full_path = File.join(path, entry)
|
243
|
+
|
244
|
+
if File.directory?(full_path)
|
245
|
+
# Check if directory should be included
|
246
|
+
if !filter || entry.match?(Regexp.new(filter))
|
247
|
+
if current_depth + 1 < max_depth
|
248
|
+
# If we can go deeper, recurse and include subdirectories
|
249
|
+
sub_items = build_tree_structure(full_path, filter, max_depth, show_content, current_depth + 1)
|
250
|
+
items << {
|
251
|
+
name: "#{entry}/",
|
252
|
+
type: 'directory',
|
253
|
+
children: sub_items || []
|
254
|
+
}
|
255
|
+
else
|
256
|
+
# At max depth, just show the directory without recursing
|
257
|
+
items << {
|
258
|
+
name: "#{entry}/",
|
259
|
+
type: 'directory',
|
260
|
+
children: []
|
261
|
+
}
|
262
|
+
end
|
263
|
+
end
|
264
|
+
else
|
265
|
+
# Check if file should be included
|
266
|
+
if !filter || entry.match?(Regexp.new(filter))
|
267
|
+
item = {
|
268
|
+
name: entry,
|
269
|
+
type: 'file'
|
270
|
+
}
|
271
|
+
|
272
|
+
if show_content
|
273
|
+
begin
|
274
|
+
content = File.read(full_path, encoding: 'utf-8')
|
275
|
+
item[:content] = content
|
276
|
+
rescue
|
277
|
+
item[:content] = '[Binary file or read error]'
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
items << item
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
rescue => e
|
286
|
+
return [{ name: "[Error: #{e.message}]", type: 'error' }]
|
287
|
+
end
|
288
|
+
|
289
|
+
items
|
290
|
+
end
|
291
|
+
|
292
|
+
def render_folder_text(items, indent = 0)
|
293
|
+
result = []
|
294
|
+
prefix = ' ' * indent
|
295
|
+
|
296
|
+
items.each do |item|
|
297
|
+
result << "#{prefix}#{item[:name]}"
|
298
|
+
|
299
|
+
if item[:content]
|
300
|
+
content_lines = item[:content].split("\n")
|
301
|
+
content_lines.each do |line|
|
302
|
+
result << "#{prefix} #{line}"
|
303
|
+
end
|
304
|
+
result << ""
|
305
|
+
end
|
306
|
+
|
307
|
+
if item[:children]
|
308
|
+
result << render_folder_text(item[:children], indent + 1)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
result.join("\n")
|
313
|
+
end
|
314
|
+
|
315
|
+
def render_folder_markdown(items, indent = 0)
|
316
|
+
result = []
|
317
|
+
prefix = ' ' * indent
|
318
|
+
|
319
|
+
items.each do |item|
|
320
|
+
if item[:type] == 'directory'
|
321
|
+
result << "#{prefix}- **#{item[:name]}**"
|
322
|
+
else
|
323
|
+
result << "#{prefix}- #{item[:name]}"
|
324
|
+
end
|
325
|
+
|
326
|
+
if item[:content]
|
327
|
+
result << "#{prefix} ```"
|
328
|
+
item[:content].split("\n").each do |line|
|
329
|
+
result << "#{prefix} #{line}"
|
330
|
+
end
|
331
|
+
result << "#{prefix} ```"
|
332
|
+
result << ""
|
333
|
+
end
|
334
|
+
|
335
|
+
if item[:children]
|
336
|
+
result << render_folder_markdown(item[:children], indent + 1)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
result.join("\n")
|
341
|
+
end
|
342
|
+
|
343
|
+
def render_folder_xml(items)
|
344
|
+
result = ['<folder>']
|
345
|
+
items.each do |item|
|
346
|
+
if item[:type] == 'directory'
|
347
|
+
result << " <directory name=\"#{escape_xml(item[:name])}\">"
|
348
|
+
if item[:children]
|
349
|
+
render_folder_xml_items(item[:children], result, 2)
|
350
|
+
end
|
351
|
+
result << " </directory>"
|
352
|
+
else
|
353
|
+
if item[:content]
|
354
|
+
result << " <file name=\"#{escape_xml(item[:name])}\">"
|
355
|
+
result << " <content>#{escape_xml(item[:content])}</content>"
|
356
|
+
result << " </file>"
|
357
|
+
else
|
358
|
+
result << " <file name=\"#{escape_xml(item[:name])}\"/>"
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
result << '</folder>'
|
363
|
+
result.join("\n")
|
364
|
+
end
|
365
|
+
|
366
|
+
def render_folder_xml_items(items, result, indent_level)
|
367
|
+
indent = ' ' * indent_level
|
368
|
+
items.each do |item|
|
369
|
+
if item[:type] == 'directory'
|
370
|
+
result << "#{indent}<directory name=\"#{escape_xml(item[:name])}\">"
|
371
|
+
if item[:children]
|
372
|
+
render_folder_xml_items(item[:children], result, indent_level + 1)
|
373
|
+
end
|
374
|
+
result << "#{indent}</directory>"
|
375
|
+
else
|
376
|
+
if item[:content]
|
377
|
+
result << "#{indent}<file name=\"#{escape_xml(item[:name])}\">"
|
378
|
+
result << "#{indent} <content>#{escape_xml(item[:content])}</content>"
|
379
|
+
result << "#{indent}</file>"
|
380
|
+
else
|
381
|
+
result << "#{indent}<file name=\"#{escape_xml(item[:name])}\"/>"
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
def escape_xml(text)
|
388
|
+
text.to_s.gsub('&', '&').gsub('<', '<').gsub('>', '>').gsub('"', '"')
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
# Tree component for rendering tree structures
|
393
|
+
class TreeComponent < Component
|
394
|
+
def render
|
395
|
+
apply_stylesheet
|
396
|
+
|
397
|
+
items_attr = get_attribute('items')
|
398
|
+
items = if items_attr.is_a?(String)
|
399
|
+
begin
|
400
|
+
require 'json'
|
401
|
+
JSON.parse(items_attr)
|
402
|
+
rescue JSON::ParserError
|
403
|
+
[]
|
404
|
+
end
|
405
|
+
else
|
406
|
+
items_attr || []
|
407
|
+
end
|
408
|
+
|
409
|
+
show_content = get_attribute('showContent', false)
|
410
|
+
syntax = get_attribute('syntax', 'text')
|
411
|
+
|
412
|
+
if xml_mode?
|
413
|
+
render_tree_xml(items, show_content)
|
414
|
+
else
|
415
|
+
case syntax
|
416
|
+
when 'markdown'
|
417
|
+
render_tree_markdown(items, show_content)
|
418
|
+
when 'json'
|
419
|
+
require 'json'
|
420
|
+
JSON.pretty_generate(items)
|
421
|
+
else
|
422
|
+
render_tree_text(items, show_content)
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
private
|
428
|
+
|
429
|
+
def render_tree_text(items, show_content, indent = 0)
|
430
|
+
result = []
|
431
|
+
prefix = ' ' * indent
|
432
|
+
|
433
|
+
items.each do |item|
|
434
|
+
result << "#{prefix}#{item['name'] || item[:name]}"
|
435
|
+
|
436
|
+
if show_content && (item['content'] || item[:content])
|
437
|
+
content = item['content'] || item[:content]
|
438
|
+
content.to_s.split("\n").each do |line|
|
439
|
+
result << "#{prefix} #{line}"
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
children = item['children'] || item[:children]
|
444
|
+
if children && !children.empty?
|
445
|
+
result << render_tree_text(children, show_content, indent + 1)
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
result.join("\n")
|
450
|
+
end
|
451
|
+
|
452
|
+
def render_tree_markdown(items, show_content, indent = 0)
|
453
|
+
result = []
|
454
|
+
prefix = ' ' * indent
|
455
|
+
|
456
|
+
items.each do |item|
|
457
|
+
name = item['name'] || item[:name]
|
458
|
+
result << "#{prefix}- #{name}"
|
459
|
+
|
460
|
+
if show_content && (item['content'] || item[:content])
|
461
|
+
content = item['content'] || item[:content]
|
462
|
+
result << "#{prefix} ```"
|
463
|
+
content.to_s.split("\n").each do |line|
|
464
|
+
result << "#{prefix} #{line}"
|
465
|
+
end
|
466
|
+
result << "#{prefix} ```"
|
467
|
+
end
|
468
|
+
|
469
|
+
children = item['children'] || item[:children]
|
470
|
+
if children && !children.empty?
|
471
|
+
result << render_tree_markdown(children, show_content, indent + 1)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
result.join("\n")
|
476
|
+
end
|
477
|
+
|
478
|
+
def render_tree_xml(items, show_content, indent_level = 1)
|
479
|
+
result = ['<tree>']
|
480
|
+
render_tree_xml_items(items, result, show_content, indent_level)
|
481
|
+
result << '</tree>'
|
482
|
+
result.join("\n")
|
483
|
+
end
|
484
|
+
|
485
|
+
def render_tree_xml_items(items, result, show_content, indent_level)
|
486
|
+
indent = ' ' * indent_level
|
487
|
+
|
488
|
+
items.each do |item|
|
489
|
+
name = item['name'] || item[:name]
|
490
|
+
children = item['children'] || item[:children]
|
491
|
+
content = item['content'] || item[:content] if show_content
|
492
|
+
|
493
|
+
if children && !children.empty?
|
494
|
+
result << "#{indent}<item name=\"#{escape_xml(name)}\">"
|
495
|
+
if content
|
496
|
+
result << "#{indent} <content>#{escape_xml(content)}</content>"
|
497
|
+
end
|
498
|
+
render_tree_xml_items(children, result, show_content, indent_level + 1)
|
499
|
+
result << "#{indent}</item>"
|
500
|
+
else
|
501
|
+
if content
|
502
|
+
result << "#{indent}<item name=\"#{escape_xml(name)}\">"
|
503
|
+
result << "#{indent} <content>#{escape_xml(content)}</content>"
|
504
|
+
result << "#{indent}</item>"
|
505
|
+
else
|
506
|
+
result << "#{indent}<item name=\"#{escape_xml(name)}\"/>"
|
507
|
+
end
|
508
|
+
end
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
def escape_xml(text)
|
513
|
+
text.to_s.gsub('&', '&').gsub('<', '<').gsub('>', '>').gsub('"', '"')
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
# File component for reading and including file contents
|
518
|
+
class FileComponent < Component
|
519
|
+
def render
|
520
|
+
apply_stylesheet
|
521
|
+
|
522
|
+
src = get_attribute('src')
|
523
|
+
|
524
|
+
# Handle missing src attribute
|
525
|
+
unless src
|
526
|
+
return handle_error("no src specified")
|
527
|
+
end
|
528
|
+
|
529
|
+
# Resolve file path
|
530
|
+
file_path = resolve_file_path(src)
|
531
|
+
|
532
|
+
# Check if file exists
|
533
|
+
unless File.exist?(file_path)
|
534
|
+
return handle_error("file not found: #{src}")
|
535
|
+
end
|
536
|
+
|
537
|
+
# Read file content
|
538
|
+
begin
|
539
|
+
content = File.read(file_path, encoding: 'utf-8')
|
540
|
+
|
541
|
+
if xml_mode?
|
542
|
+
render_as_xml('file', content, { src: src })
|
543
|
+
else
|
544
|
+
content
|
545
|
+
end
|
546
|
+
rescue => e
|
547
|
+
handle_error("error reading file: #{e.message}")
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
private
|
552
|
+
|
553
|
+
def resolve_file_path(src)
|
554
|
+
# Handle absolute paths
|
555
|
+
return src if src.start_with?('/')
|
556
|
+
|
557
|
+
# Handle relative paths - try relative to source file first
|
558
|
+
if @context.source_path
|
559
|
+
base_path = File.dirname(@context.source_path)
|
560
|
+
candidate_path = File.join(base_path, src)
|
561
|
+
return candidate_path if File.exist?(candidate_path)
|
562
|
+
end
|
563
|
+
|
564
|
+
# Try relative to current working directory
|
565
|
+
candidate_path = File.join(Dir.pwd, src)
|
566
|
+
return candidate_path if File.exist?(candidate_path)
|
567
|
+
|
568
|
+
# Return the original path for final existence check
|
569
|
+
src
|
570
|
+
end
|
571
|
+
|
572
|
+
def handle_error(message)
|
573
|
+
if xml_mode?
|
574
|
+
render_as_xml('file-error', message)
|
575
|
+
else
|
576
|
+
"[File: #{message}]"
|
577
|
+
end
|
578
|
+
end
|
579
|
+
end
|
580
|
+
end
|
data/lib/poml/components.rb
CHANGED
@@ -9,39 +9,130 @@ require_relative 'components/lists'
|
|
9
9
|
require_relative 'components/layout'
|
10
10
|
require_relative 'components/workflow'
|
11
11
|
require_relative 'components/styling'
|
12
|
+
require_relative 'components/formatting'
|
13
|
+
require_relative 'components/media'
|
14
|
+
require_relative 'components/utilities'
|
15
|
+
require_relative 'components/meta'
|
16
|
+
require_relative 'components/template'
|
12
17
|
|
13
18
|
module Poml
|
14
19
|
# Update the component mapping after all components are loaded
|
15
20
|
Components::COMPONENT_MAPPING.merge!({
|
21
|
+
# Basic components
|
16
22
|
text: TextComponent,
|
23
|
+
poml: TextComponent,
|
24
|
+
p: ParagraphComponent,
|
25
|
+
|
26
|
+
# Formatting components
|
27
|
+
b: BoldComponent,
|
28
|
+
bold: BoldComponent,
|
29
|
+
i: ItalicComponent,
|
30
|
+
italic: ItalicComponent,
|
31
|
+
u: UnderlineComponent,
|
32
|
+
underline: UnderlineComponent,
|
33
|
+
s: StrikethroughComponent,
|
34
|
+
strike: StrikethroughComponent,
|
35
|
+
strikethrough: StrikethroughComponent,
|
36
|
+
span: InlineComponent,
|
37
|
+
inline: InlineComponent,
|
38
|
+
h: HeaderComponent,
|
39
|
+
header: HeaderComponent,
|
40
|
+
br: NewlineComponent,
|
41
|
+
newline: NewlineComponent,
|
42
|
+
code: CodeComponent,
|
43
|
+
section: SubContentComponent,
|
44
|
+
subcontent: SubContentComponent,
|
45
|
+
|
46
|
+
# Media components
|
47
|
+
audio: AudioComponent,
|
48
|
+
|
49
|
+
# Instruction components
|
17
50
|
role: RoleComponent,
|
18
51
|
task: TaskComponent,
|
19
52
|
hint: HintComponent,
|
53
|
+
|
54
|
+
# Content components
|
20
55
|
document: DocumentComponent,
|
21
56
|
Document: DocumentComponent, # Capitalized version
|
57
|
+
|
58
|
+
# Data components
|
22
59
|
table: TableComponent,
|
23
60
|
Table: TableComponent, # Capitalized version
|
24
61
|
img: ImageComponent,
|
25
|
-
|
62
|
+
obj: ObjectComponent,
|
63
|
+
object: ObjectComponent,
|
64
|
+
dataobj: ObjectComponent,
|
65
|
+
'data-obj': ObjectComponent,
|
66
|
+
webpage: WebpageComponent,
|
67
|
+
|
68
|
+
# Example components
|
26
69
|
example: ExampleComponent,
|
27
70
|
input: InputComponent,
|
28
71
|
output: OutputComponent,
|
29
72
|
'output-format': OutputFormatComponent,
|
30
73
|
'outputformat': OutputFormatComponent,
|
74
|
+
examples: ExampleSetComponent,
|
75
|
+
'example-set': ExampleSetComponent,
|
76
|
+
introducer: IntroducerComponent,
|
77
|
+
|
78
|
+
# List components
|
31
79
|
list: ListComponent,
|
32
80
|
item: ItemComponent,
|
81
|
+
|
82
|
+
# Layout components
|
33
83
|
cp: CPComponent,
|
84
|
+
'captioned-paragraph': CPComponent,
|
85
|
+
|
86
|
+
# Workflow components
|
34
87
|
'stepwise-instructions': StepwiseInstructionsComponent,
|
35
88
|
'stepwiseinstructions': StepwiseInstructionsComponent,
|
36
89
|
StepwiseInstructions: StepwiseInstructionsComponent,
|
37
90
|
'human-message': HumanMessageComponent,
|
38
91
|
'humanmessage': HumanMessageComponent,
|
39
92
|
HumanMessage: HumanMessageComponent,
|
93
|
+
'user-msg': HumanMessageComponent,
|
40
94
|
qa: QAComponent,
|
41
95
|
QA: QAComponent,
|
96
|
+
question: QAComponent,
|
97
|
+
|
98
|
+
# Utility components
|
99
|
+
'ai-msg': AiMessageComponent,
|
100
|
+
'aimessage': AiMessageComponent,
|
101
|
+
ai: AiMessageComponent,
|
102
|
+
Ai: AiMessageComponent,
|
103
|
+
human: HumanMessageComponent,
|
104
|
+
Human: HumanMessageComponent,
|
105
|
+
system: SystemMessageComponent,
|
106
|
+
System: SystemMessageComponent,
|
107
|
+
'system-msg': SystemMessageComponent,
|
108
|
+
'systemmessage': SystemMessageComponent,
|
109
|
+
'msg-content': MessageContentComponent,
|
110
|
+
'message-content': MessageContentComponent,
|
111
|
+
conversation: ConversationComponent,
|
112
|
+
Conversation: ConversationComponent,
|
113
|
+
folder: FolderComponent,
|
114
|
+
Folder: FolderComponent,
|
115
|
+
tree: TreeComponent,
|
116
|
+
Tree: TreeComponent,
|
117
|
+
file: FileComponent,
|
118
|
+
File: FileComponent,
|
119
|
+
|
120
|
+
# Styling components
|
42
121
|
let: LetComponent,
|
43
122
|
Let: LetComponent,
|
44
123
|
stylesheet: StylesheetComponent,
|
45
|
-
Stylesheet: StylesheetComponent
|
124
|
+
Stylesheet: StylesheetComponent,
|
125
|
+
|
126
|
+
# Meta components
|
127
|
+
meta: MetaComponent,
|
128
|
+
Meta: MetaComponent,
|
129
|
+
|
130
|
+
# Template components
|
131
|
+
include: IncludeComponent,
|
132
|
+
Include: IncludeComponent,
|
133
|
+
if: IfComponent,
|
134
|
+
If: IfComponent,
|
135
|
+
for: ForComponent,
|
136
|
+
For: ForComponent
|
46
137
|
})
|
47
138
|
end
|