ruby_slm 0.1.0

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.
@@ -0,0 +1,747 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'yaml'
5
+ require 'securerandom'
6
+
7
+ # ComplexOrderProcessor class from previous step
8
+ class ComplexOrderProcessor
9
+ # Order Classification
10
+ def determine_order_type(input)
11
+ order = input['order'] || {}
12
+
13
+ total = order['total'].to_f
14
+ items = order['items'] || []
15
+ quantity = order['quantity'].to_i
16
+
17
+ # Business logic for order classification
18
+ if total > 500 || order['premium_customer']
19
+ { "order_type" => "premium", "reason" => "high_value_or_premium_customer" }
20
+ elsif quantity > 10 || total > 1000
21
+ { "order_type" => "bulk", "reason" => "large_quantity" }
22
+ elsif order['shipping'] && order['shipping']['country'] != 'US'
23
+ { "order_type" => "international", "reason" => "international_shipping" }
24
+ elsif order['digital_product']
25
+ { "order_type" => "digital", "reason" => "digital_product" }
26
+ else
27
+ { "order_type" => "standard", "reason" => "regular_order" }
28
+ end
29
+ end
30
+
31
+ # Premium Order Processing
32
+ def process_premium_order(input)
33
+ order = input['order']
34
+ {
35
+ "premium_processed" => true,
36
+ "order_id" => order['id'],
37
+ "vip_handling" => true,
38
+ "dedicated_support" => true,
39
+ "processing_tier" => "premium"
40
+ }
41
+ end
42
+
43
+ # Bulk Order Processing
44
+ def check_bulk_inventory(input)
45
+ order = input['order']
46
+ required_quantity = input['required_quantity']
47
+
48
+ # Simulate inventory check
49
+ available = rand(0..1) == 1
50
+ {
51
+ "available" => available,
52
+ "checked_at" => Time.now.to_i,
53
+ "required_quantity" => required_quantity,
54
+ "available_quantity" => available ? required_quantity : 0
55
+ }
56
+ end
57
+
58
+ def process_bulk_order(input)
59
+ order = input['order']
60
+ {
61
+ "bulk_processed" => true,
62
+ "order_id" => order['id'],
63
+ "volume_discount_applied" => true,
64
+ "special_handling" => true
65
+ }
66
+ end
67
+
68
+ # International Order Processing
69
+ def process_international_order(input)
70
+ order = input['order']
71
+ country = input['destination_country']
72
+
73
+ {
74
+ "international_processed" => true,
75
+ "order_id" => order['id'],
76
+ "destination_country" => country,
77
+ "export_documentation" => "required",
78
+ "customs_declaration" => "needed"
79
+ }
80
+ end
81
+
82
+ def calculate_customs_duty(input)
83
+ order_value = input['order_value'].to_f
84
+ country = input['country']
85
+
86
+ # Simple customs calculation
87
+ duty_rate = case country
88
+ when 'CA', 'MX' then 0.05
89
+ when 'EU' then 0.15
90
+ when 'UK' then 0.12
91
+ else 0.10
92
+ end
93
+
94
+ duty_amount = order_value * duty_rate
95
+
96
+ {
97
+ "duty_calculated" => true,
98
+ "duty_rate" => duty_rate,
99
+ "duty_amount" => duty_amount,
100
+ "total_with_duty" => order_value + duty_amount,
101
+ "currency" => "USD"
102
+ }
103
+ end
104
+
105
+ # Digital Order Processing
106
+ def process_digital_order(input)
107
+ order = input['order']
108
+ {
109
+ "digital_processed" => true,
110
+ "order_id" => order['id'],
111
+ "product_type" => order['digital_product']['type'],
112
+ "instant_delivery" => true
113
+ }
114
+ end
115
+
116
+ def generate_digital_access(input)
117
+ {
118
+ "access_generated" => true,
119
+ "order_id" => input['order_id'],
120
+ "access_codes" => ["CODE-#{SecureRandom.hex(8)}"],
121
+ "download_links" => ["https://download.example.com/#{SecureRandom.hex(4)}"],
122
+ "license_key" => "LIC-#{SecureRandom.hex(12)}"
123
+ }
124
+ end
125
+
126
+ # Standard Order Processing
127
+ def process_standard_order(input)
128
+ order = input['order']
129
+ {
130
+ "standard_processed" => true,
131
+ "order_id" => order['id'],
132
+ "processing_tier" => "standard"
133
+ }
134
+ end
135
+
136
+ # Payment Processing
137
+ def process_payment(input)
138
+ amount = input['amount'].to_f
139
+ payment_method = input['payment_method']
140
+
141
+ # Simulate payment processing with occasional failures
142
+ success = amount < 2000 && payment_method != 'expired_card'
143
+
144
+ if success
145
+ {
146
+ "status" => "completed",
147
+ "payment_id" => "pay_#{SecureRandom.hex(8)}",
148
+ "amount_charged" => amount,
149
+ "currency" => input['currency'],
150
+ "processed_at" => Time.now.to_i
151
+ }
152
+ else
153
+ raise "Payment declined: #{payment_method} cannot process $#{amount}"
154
+ end
155
+ end
156
+
157
+ def wait_for_payment_confirmation(input)
158
+ payment_id = input['payment_id']
159
+
160
+ # Simulate waiting for confirmation
161
+ sleep(0.1) # Reduced for testing
162
+
163
+ {
164
+ "confirmed" => true,
165
+ "payment_id" => payment_id,
166
+ "confirmation_code" => "CONF-#{SecureRandom.hex(6)}",
167
+ "confirmed_at" => Time.now.to_i
168
+ }
169
+ end
170
+
171
+ def finalize_payment(input)
172
+ {
173
+ "finalized" => true,
174
+ "payment_id" => input['payment_id'],
175
+ "status" => "completed",
176
+ "finalized_at" => Time.now.to_i
177
+ }
178
+ end
179
+
180
+ # Inventory Management
181
+ def update_inventory(input)
182
+ order_id = input['order_id']
183
+ items = input['items']
184
+
185
+ # Simulate inventory update with occasional stock issues
186
+ out_of_stock = rand(0..9) == 0 # 10% chance of out of stock
187
+
188
+ if out_of_stock
189
+ raise "OutOfStock - Item unavailable for order #{order_id}"
190
+ else
191
+ {
192
+ "inventory_updated" => true,
193
+ "order_id" => order_id,
194
+ "items_processed" => items.size,
195
+ "updated_at" => Time.now.to_i
196
+ }
197
+ end
198
+ end
199
+
200
+ # Shipping Methods
201
+ def schedule_express_shipping(input)
202
+ order = input['order']
203
+ {
204
+ "shipping_scheduled" => true,
205
+ "order_id" => order['id'],
206
+ "method" => "express",
207
+ "estimated_days" => 1,
208
+ "tracking_number" => "EXP#{SecureRandom.hex(6).upcase}",
209
+ "priority" => "high"
210
+ }
211
+ end
212
+
213
+ def schedule_standard_shipping(input)
214
+ order = input['order']
215
+ {
216
+ "shipping_scheduled" => true,
217
+ "order_id" => order['id'],
218
+ "method" => "standard",
219
+ "estimated_days" => 3,
220
+ "tracking_number" => "STD#{SecureRandom.hex(6).upcase}"
221
+ }
222
+ end
223
+
224
+ def schedule_economy_shipping(input)
225
+ order = input['order']
226
+ {
227
+ "shipping_scheduled" => true,
228
+ "order_id" => order['id'],
229
+ "method" => "economy",
230
+ "estimated_days" => 7,
231
+ "tracking_number" => "ECO#{SecureRandom.hex(6).upcase}"
232
+ }
233
+ end
234
+
235
+ # Digital Delivery
236
+ def send_digital_delivery(input)
237
+ order = input['order']
238
+ {
239
+ "digital_delivered" => true,
240
+ "order_id" => order['id'],
241
+ "customer_email" => input['customer_email'],
242
+ "delivery_method" => "email",
243
+ "sent_at" => Time.now.to_i
244
+ }
245
+ end
246
+
247
+ # Notifications
248
+ def send_order_confirmation(input)
249
+ order = input['order']
250
+ {
251
+ "confirmation_sent" => true,
252
+ "order_id" => order['id'],
253
+ "customer_id" => input['customer'],
254
+ "sent_via" => ["email", "sms"],
255
+ "confirmation_id" => "CONF-#{SecureRandom.hex(6)}"
256
+ }
257
+ end
258
+
259
+ # Error Handling Methods
260
+ def handle_classification_error(input)
261
+ {
262
+ "classification_recovered" => true,
263
+ "order_id" => input['order']['id'],
264
+ "fallback_strategy" => "standard_processing",
265
+ "recovered_at" => Time.now.to_i
266
+ }
267
+ end
268
+
269
+ def handle_premium_error(input)
270
+ {
271
+ "premium_recovered" => true,
272
+ "order_id" => input['order']['id'],
273
+ "fallback_strategy" => "standard_processing",
274
+ "recovered_at" => Time.now.to_i
275
+ }
276
+ end
277
+
278
+ def handle_bulk_unavailable(input)
279
+ order = input['order']
280
+ {
281
+ "bulk_unavailable_handled" => true,
282
+ "order_id" => order['id'],
283
+ "action" => "offer_alternative",
284
+ "unavailable_items" => input['inventory']['unavailable_items'] || []
285
+ }
286
+ end
287
+
288
+ def handle_bulk_error(input)
289
+ {
290
+ "bulk_error_recovered" => true,
291
+ "order_id" => input['order']['id'],
292
+ "fallback_strategy" => "standard_processing",
293
+ "recovered_at" => Time.now.to_i
294
+ }
295
+ end
296
+
297
+ def handle_digital_error(input)
298
+ {
299
+ "digital_error_recovered" => true,
300
+ "order_id" => input['order']['id'],
301
+ "fallback_strategy" => "standard_processing",
302
+ "recovered_at" => Time.now.to_i
303
+ }
304
+ end
305
+
306
+ def handle_payment_failure(input)
307
+ order = input['order']
308
+ {
309
+ "payment_failure_handled" => true,
310
+ "order_id" => order['id'],
311
+ "attempt" => input['payment_attempt'],
312
+ "next_action" => "notify_customer",
313
+ "handled_at" => Time.now.to_i
314
+ }
315
+ end
316
+
317
+ def handle_payment_error(input)
318
+ {
319
+ "payment_error_handled" => true,
320
+ "order_id" => input['order']['id'],
321
+ "action" => "escalate_to_support",
322
+ "handled_at" => Time.now.to_i
323
+ }
324
+ end
325
+
326
+ def handle_out_of_stock(input)
327
+ order = input['order']
328
+ {
329
+ "out_of_stock_handled" => true,
330
+ "order_id" => order['id'],
331
+ "action" => "notify_customer_and_restock",
332
+ "handled_at" => Time.now.to_i
333
+ }
334
+ end
335
+
336
+ def notify_payment_failure(input)
337
+ order = input['order']
338
+ {
339
+ "payment_failure_notified" => true,
340
+ "order_id" => order['id'],
341
+ "customer_notified" => true,
342
+ "notification_method" => "email",
343
+ "notified_at" => Time.now.to_i
344
+ }
345
+ end
346
+
347
+ def notify_out_of_stock(input)
348
+ order = input['order']
349
+ {
350
+ "out_of_stock_notified" => true,
351
+ "order_id" => order['id'],
352
+ "customer_notified" => true,
353
+ "notification_method" => "email",
354
+ "notified_at" => Time.now.to_i
355
+ }
356
+ end
357
+
358
+ def offer_alternative(input)
359
+ order = input['order']
360
+ {
361
+ "alternative_offered" => true,
362
+ "order_id" => order['id'],
363
+ "alternative_products" => ["similar_item_1", "similar_item_2"],
364
+ "discount_offered" => true,
365
+ "discount_percentage" => 10
366
+ }
367
+ end
368
+ end
369
+
370
+ # Simple executor that routes to ComplexOrderProcessor methods
371
+ class LocalMethodExecutor
372
+ def initialize
373
+ @processor = ComplexOrderProcessor.new
374
+ end
375
+
376
+ def call(resource, input, credentials = nil)
377
+ method_name = resource.sub('method:', '')
378
+
379
+ unless @processor.respond_to?(method_name)
380
+ raise "Method not found: #{method_name}"
381
+ end
382
+
383
+ puts " ๐Ÿ“ž Executing: #{method_name}"
384
+ @processor.send(method_name, input)
385
+ end
386
+ end
387
+
388
+ # Simple workflow runner using the actual StatesLanguageMachine
389
+ class WorkflowTester
390
+ def initialize
391
+ @executor = LocalMethodExecutor.new
392
+ @workflow_file = 'complex_workflow.yaml'
393
+ generate_workflow_file
394
+ end
395
+
396
+ def generate_workflow_file
397
+ workflow_yaml = <<~YAML
398
+ Comment: Complex E-commerce Order Processing Workflow
399
+ StartAt: ValidateInput
400
+ States:
401
+ ValidateInput:
402
+ Type: Pass
403
+ Parameters:
404
+ order_id.$: $.order.id
405
+ customer_id.$: $.order.customer_id
406
+ total_amount.$: $.order.total
407
+ item_count.$: $.order.items.length
408
+ timestamp: #{Time.now.to_i}
409
+ ResultPath: $.validation_metadata
410
+ Next: CheckOrderType
411
+
412
+ CheckOrderType:
413
+ Type: Task
414
+ Resource: method:determine_order_type
415
+ ResultPath: $.order_type_result
416
+ Next: RouteOrder
417
+
418
+ RouteOrder:
419
+ Type: Choice
420
+ Choices:
421
+ - Variable: $.order_type_result.order_type
422
+ StringEquals: "premium"
423
+ Next: ProcessPremiumOrder
424
+ - Variable: $.order_type_result.order_type
425
+ StringEquals: "bulk"
426
+ Next: CheckBulkInventory
427
+ - Variable: $.order_type_result.order_type
428
+ StringEquals: "international"
429
+ Next: ProcessInternationalOrder
430
+ - Variable: $.order_type_result.order_type
431
+ StringEquals: "digital"
432
+ Next: ProcessDigitalOrder
433
+ Default: ProcessStandardOrder
434
+
435
+ ProcessPremiumOrder:
436
+ Type: Task
437
+ Resource: method:process_premium_order
438
+ ResultPath: $.premium_result
439
+ Next: ProcessPayment
440
+
441
+ CheckBulkInventory:
442
+ Type: Task
443
+ Resource: method:check_bulk_inventory
444
+ Parameters:
445
+ order.$: $.order
446
+ required_quantity.$: $.order.quantity
447
+ ResultPath: $.bulk_inventory_result
448
+ Next: VerifyBulkAvailability
449
+
450
+ VerifyBulkAvailability:
451
+ Type: Choice
452
+ Choices:
453
+ - Variable: $.bulk_inventory_result.available
454
+ BooleanEquals: true
455
+ Next: ProcessBulkOrder
456
+ - Variable: $.bulk_inventory_result.available
457
+ BooleanEquals: false
458
+ Next: HandleBulkUnavailable
459
+ Default: HandleBulkUnavailable
460
+
461
+ ProcessBulkOrder:
462
+ Type: Task
463
+ Resource: method:process_bulk_order
464
+ ResultPath: $.bulk_result
465
+ Next: ProcessPayment
466
+
467
+ ProcessInternationalOrder:
468
+ Type: Task
469
+ Resource: method:process_international_order
470
+ ResultPath: $.international_result
471
+ Next: ProcessPayment
472
+
473
+ ProcessDigitalOrder:
474
+ Type: Task
475
+ Resource: method:process_digital_order
476
+ ResultPath: $.digital_result
477
+ Next: GenerateDigitalAccess
478
+
479
+ GenerateDigitalAccess:
480
+ Type: Task
481
+ Resource: method:generate_digital_access
482
+ ResultPath: $.digital_access_result
483
+ Next: SendDigitalDelivery
484
+
485
+ ProcessStandardOrder:
486
+ Type: Task
487
+ Resource: method:process_standard_order
488
+ ResultPath: $.standard_result
489
+ Next: ProcessPayment
490
+
491
+ ProcessPayment:
492
+ Type: Task
493
+ Resource: method:process_payment
494
+ Parameters:
495
+ order_id.$: $.order.id
496
+ amount.$: $.order.total
497
+ currency: "USD"
498
+ payment_method.$: $.order.payment_method
499
+ customer_id.$: $.order.customer_id
500
+ ResultPath: $.payment_result
501
+ Next: UpdateInventory
502
+ Catch:
503
+ - ErrorEquals: ["States.ALL"]
504
+ Next: HandlePaymentFailure
505
+ ResultPath: $.payment_error
506
+
507
+ HandlePaymentFailure:
508
+ Type: Task
509
+ Resource: method:handle_payment_failure
510
+ Parameters:
511
+ order.$: $.order
512
+ error.$: $.payment_error
513
+ payment_attempt: 1
514
+ ResultPath: $.payment_failure_result
515
+ Next: NotifyPaymentFailure
516
+
517
+ NotifyPaymentFailure:
518
+ Type: Task
519
+ Resource: method:notify_payment_failure
520
+ ResultPath: $.payment_failure_notification
521
+ End: true
522
+
523
+ UpdateInventory:
524
+ Type: Task
525
+ Resource: method:update_inventory
526
+ Parameters:
527
+ order_id.$: $.order.id
528
+ items.$: $.order.items
529
+ action: "decrement"
530
+ ResultPath: $.inventory_result
531
+ Next: HandleShipping
532
+ Catch:
533
+ - ErrorEquals: ["OutOfStock"]
534
+ Next: HandleOutOfStock
535
+ ResultPath: $.inventory_error
536
+
537
+ HandleOutOfStock:
538
+ Type: Task
539
+ Resource: method:handle_out_of_stock
540
+ ResultPath: $.out_of_stock_result
541
+ Next: NotifyOutOfStock
542
+
543
+ NotifyOutOfStock:
544
+ Type: Task
545
+ Resource: method:notify_out_of_stock
546
+ ResultPath: $.out_of_stock_notification
547
+ End: true
548
+
549
+ HandleBulkUnavailable:
550
+ Type: Task
551
+ Resource: method:handle_bulk_unavailable
552
+ ResultPath: $.bulk_unavailable_result
553
+ Next: ProcessStandardOrder
554
+
555
+ HandleShipping:
556
+ Type: Choice
557
+ Choices:
558
+ - Variable: $.order.shipping.required
559
+ BooleanEquals: false
560
+ Next: SendDigitalDelivery
561
+ - Variable: $.order_type_result.order_type
562
+ StringEquals: "premium"
563
+ Next: ScheduleExpressShipping
564
+ - Variable: $.order.total
565
+ NumericGreaterThan: 100
566
+ Next: ScheduleStandardShipping
567
+ Default: ScheduleEconomyShipping
568
+
569
+ ScheduleExpressShipping:
570
+ Type: Task
571
+ Resource: method:schedule_express_shipping
572
+ ResultPath: $.shipping_result
573
+ Next: SendOrderConfirmation
574
+
575
+ ScheduleStandardShipping:
576
+ Type: Task
577
+ Resource: method:schedule_standard_shipping
578
+ ResultPath: $.shipping_result
579
+ Next: SendOrderConfirmation
580
+
581
+ ScheduleEconomyShipping:
582
+ Type: Task
583
+ Resource: method:schedule_economy_shipping
584
+ ResultPath: $.shipping_result
585
+ Next: SendOrderConfirmation
586
+
587
+ SendDigitalDelivery:
588
+ Type: Task
589
+ Resource: method:send_digital_delivery
590
+ ResultPath: $.digital_delivery_result
591
+ Next: SendOrderConfirmation
592
+
593
+ SendOrderConfirmation:
594
+ Type: Task
595
+ Resource: method:send_order_confirmation
596
+ ResultPath: $.confirmation_result
597
+ End: true
598
+ YAML
599
+
600
+ File.write(@workflow_file, workflow_yaml)
601
+ puts "๐Ÿ“„ Generated workflow file: #{@workflow_file}"
602
+ end
603
+
604
+ def run_test_cases
605
+ test_cases = [
606
+ {
607
+ name: "Premium Order",
608
+ input: {
609
+ "order" => {
610
+ "id" => "ORD-PREM-001",
611
+ "total" => 750.00,
612
+ "customer_id" => "CUST-PREM-001",
613
+ "items" => ["premium_item_1", "premium_item_2"],
614
+ "quantity" => 2,
615
+ "premium_customer" => true,
616
+ "payment_method" => "credit_card",
617
+ "shipping" => { "required" => true, "country" => "US" }
618
+ }
619
+ }
620
+ },
621
+ {
622
+ name: "Bulk Order (Available)",
623
+ input: {
624
+ "order" => {
625
+ "id" => "ORD-BULK-001",
626
+ "total" => 1500.00,
627
+ "customer_id" => "CUST-BULK-001",
628
+ "items" => ["bulk_item_1"],
629
+ "quantity" => 25,
630
+ "payment_method" => "credit_card",
631
+ "shipping" => { "required" => true, "country" => "US" }
632
+ }
633
+ }
634
+ },
635
+ {
636
+ name: "Digital Order",
637
+ input: {
638
+ "order" => {
639
+ "id" => "ORD-DIG-001",
640
+ "total" => 49.99,
641
+ "customer_id" => "CUST-DIG-001",
642
+ "items" => ["ebook"],
643
+ "quantity" => 1,
644
+ "payment_method" => "paypal",
645
+ "shipping" => { "required" => false },
646
+ "digital_product" => { "type" => "ebook" },
647
+ "customer_email" => "customer@example.com"
648
+ }
649
+ }
650
+ },
651
+ {
652
+ name: "Standard Order",
653
+ input: {
654
+ "order" => {
655
+ "id" => "ORD-STD-001",
656
+ "total" => 89.99,
657
+ "customer_id" => "CUST-STD-001",
658
+ "items" => ["standard_item_1", "standard_item_2"],
659
+ "quantity" => 3,
660
+ "payment_method" => "credit_card",
661
+ "shipping" => { "required" => true, "country" => "US" }
662
+ }
663
+ }
664
+ },
665
+ {
666
+ name: "Payment Failure Order",
667
+ input: {
668
+ "order" => {
669
+ "id" => "ORD-FAIL-001",
670
+ "total" => 2500.00, # High amount that will fail payment
671
+ "customer_id" => "CUST-FAIL-001",
672
+ "items" => ["expensive_item"],
673
+ "quantity" => 1,
674
+ "payment_method" => "expired_card", # This will cause failure
675
+ "shipping" => { "required" => true, "country" => "US" }
676
+ }
677
+ }
678
+ }
679
+ ]
680
+
681
+ test_cases.each do |test_case|
682
+ puts "\n" + "="*60
683
+ puts "๐Ÿงช Testing: #{test_case[:name]}"
684
+ puts "="*60
685
+
686
+ begin
687
+ # Load the state machine from YAML
688
+ state_machine = StatesLanguageMachine.from_yaml_file(@workflow_file)
689
+
690
+ # Start execution
691
+ execution = state_machine.start_execution(test_case[:input], "test-#{test_case[:input]['order']['id']}")
692
+
693
+ # Set the executor in context
694
+ execution.context[:task_executor] = @executor
695
+
696
+ # Run the workflow
697
+ execution.run_all
698
+
699
+ # Display results
700
+ puts "โœ… Workflow completed successfully!"
701
+ puts "๐Ÿ“Š Final Status: #{execution.status}"
702
+ puts "๐Ÿ›ฃ๏ธ Execution Path: #{execution.history.map { |h| h[:state_name] }.join(' โ†’ ')}"
703
+ puts "โฑ๏ธ Execution Time: #{execution.execution_time.round(4)} seconds"
704
+
705
+ if execution.output
706
+ puts "๐Ÿ“ฆ Output Keys: #{execution.output.keys.join(', ')}"
707
+ # Show some key results
708
+ execution.output.each do |key, value|
709
+ if key =~ /result|status|confirmation/
710
+ puts " - #{key}: #{value.is_a?(Hash) ? value.keys.join(',') : value}"
711
+ end
712
+ end
713
+ end
714
+
715
+ rescue => e
716
+ puts "โŒ Workflow failed!"
717
+ puts "๐Ÿ’ฅ Error: #{e.message}"
718
+ if execution
719
+ puts "๐Ÿ›‘ Final Status: #{execution.status}"
720
+ puts "๐Ÿ“ Failed at: #{execution.history.last[:state_name]}" if execution.history.any?
721
+ end
722
+ end
723
+
724
+ puts "\n"
725
+ end
726
+ end
727
+ end
728
+
729
+ # Main execution
730
+ if __FILE__ == $0
731
+ begin
732
+ require 'ruby_slm'
733
+
734
+ puts "๐Ÿš€ Starting Complex Workflow Test"
735
+ puts "This tests Pass, Task, Choice, Succeed, and Fail states with local methods"
736
+ puts ""
737
+
738
+ tester = WorkflowTester.new
739
+ tester.run_test_cases
740
+
741
+ puts "๐ŸŽ‰ All tests completed!"
742
+
743
+ rescue LoadError
744
+ puts "โŒ Error: Could not load ruby_slm gem"
745
+ puts "Make sure the gem is installed and in your load path"
746
+ end
747
+ end