llmed 0.4.2 → 0.4.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/exe/llmed.literate +62 -5
- data/lib/llmed/literate_programming.rb +6 -7
- metadata +3 -16
- data/lib/literate_programming.llmed~ +0 -39
- data/lib/llm.rb~ +0 -0
- data/lib/llmed/application.rb~ +0 -182
- data/lib/llmed/configuration.rb~ +0 -76
- data/lib/llmed/context.rb~ +0 -62
- data/lib/llmed/deployment.rb~ +0 -16
- data/lib/llmed/literate_programming/markdown.rb.r1ruby.cache +0 -24
- data/lib/llmed/literate_programming.rb~ +0 -1
- data/lib/llmed/release.rb~ +0 -31
- data/lib/llmed.rb~ +0 -190
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 5733bac9f8a6d8c5465f487bda233c8997491d838c778b45194e3c15f9c14734
         | 
| 4 | 
            +
              data.tar.gz: e606c3e377bc6d0bf75eed59dd6456773c02650e98118a0135814808195e2fb8
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 3fc77a1b7b7ca6ba6c8bcb528e1ef702277588195c47e538cfa6a8432aef4ae7cb876b10537605866bfa7ea0a61ceacf1308cd52d3b5f0f2a7a4f51ef5b552ed
         | 
| 7 | 
            +
              data.tar.gz: 94f66750f04e2c97d8e78125ac920c52037fd6bc5e5759cbd2e349402be599619fb5cb2dc92af0c519a0cc557333be022925abb556f09995460a0b0d936386c8
         | 
    
        data/exe/llmed.literate
    CHANGED
    
    | @@ -9,12 +9,22 @@ output_dir = './llmed-out' | |
| 9 9 | 
             
            release_dir = output_dir
         | 
| 10 10 | 
             
            language = 'ruby'
         | 
| 11 11 | 
             
            provider = :like_openai
         | 
| 12 | 
            -
            provider_api_key = ENV.fetch('LLMED_PROVIDER_API_KEY',  | 
| 12 | 
            +
            provider_api_key = ENV.fetch('LLMED_PROVIDER_API_KEY', '')
         | 
| 13 13 | 
             
            provider_model = ENV.fetch('LLMED_PROVIDER_MODEL', 'Qwen/Qwen2.5-Coder-32B-Instruct')
         | 
| 14 14 | 
             
            provider_uri_base = ENV.fetch('LLMED_PROVIDER_URI_BASE', 'https://api.together.xyz/v1')
         | 
| 15 15 | 
             
            output_file = 'a.out.ollmed'
         | 
| 16 16 |  | 
| 17 17 | 
             
            template = <<~TMP
         | 
| 18 | 
            +
            #% Minimal example
         | 
| 19 | 
            +
            #% llm_provider : like_openai | openai | anthropic
         | 
| 20 | 
            +
            #!environment llm_provider like_openai
         | 
| 21 | 
            +
            #% llm_provider_model : depends provider
         | 
| 22 | 
            +
            #!environment llm_provider_model Qwen/Qwen2.5-Coder-32B-Instruct
         | 
| 23 | 
            +
            #% llm_provider_model : depends provider
         | 
| 24 | 
            +
            #!environment llm_provider_uri_base https://api.together.xyz/v1
         | 
| 25 | 
            +
            #!environment language ruby
         | 
| 26 | 
            +
            #!environment output_file demo.rb
         | 
| 27 | 
            +
             | 
| 18 28 | 
             
            # Main
         | 
| 19 29 |  | 
| 20 30 | 
             
            Show to user 'hi world!'.
         | 
| @@ -26,7 +36,26 @@ OptionParser.new do |parser| | |
| 26 36 | 
             
                puts parser
         | 
| 27 37 | 
             
                puts "\n# Website\nhttps://github.com/bit4bit/llm-labs/tree/main/llmed"
         | 
| 28 38 | 
             
                puts "\n# Examples\nhttps://github.com/bit4bit/llm-labs/tree/main/llmed/examples"
         | 
| 29 | 
            -
                puts "Environment | 
| 39 | 
            +
                puts "\n# Current Environment\nLLMED_PROVIDER_API_KEY\nLLMED_PROVIDER_MODEL=#{provider_model}\nLLMED_PROVIDER_URI_BASE=#{provider_uri_base}"
         | 
| 40 | 
            +
                puts <<~DOC
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                # A minimal example
         | 
| 43 | 
            +
                <!--
         | 
| 44 | 
            +
                #% Minimal example
         | 
| 45 | 
            +
                #% llm_provider : like_openai | openai | anthropic
         | 
| 46 | 
            +
                #!environment llm_provider like_openai
         | 
| 47 | 
            +
                #% llm_provider_model : depends provider
         | 
| 48 | 
            +
                #!environment llm_provider_model Qwen/Qwen2.5-Coder-32B-Instruct
         | 
| 49 | 
            +
                #% llm_provider_model : depends provider
         | 
| 50 | 
            +
                #!environment llm_provider_uri_base https://api.together.xyz/v1
         | 
| 51 | 
            +
                #!environment language ruby
         | 
| 52 | 
            +
                #!environment output_file fscalls.rb
         | 
| 53 | 
            +
                -->
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                # Main
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                Show to user 'hi world!'.
         | 
| 58 | 
            +
                DOC
         | 
| 30 59 | 
             
                exit
         | 
| 31 60 | 
             
              end
         | 
| 32 61 |  | 
| @@ -47,7 +76,7 @@ OptionParser.new do |parser| | |
| 47 76 | 
             
                release_dir = path
         | 
| 48 77 | 
             
              end
         | 
| 49 78 |  | 
| 50 | 
            -
              parser.on('-l', '--language LANGUAGE', String, 'Programming Language: ruby, python') do |lang|
         | 
| 79 | 
            +
              parser.on('-l', '--language LANGUAGE', String, 'Programming Language: ruby, python (default: ruby)') do |lang|
         | 
| 51 80 | 
             
                language = lang
         | 
| 52 81 | 
             
              end
         | 
| 53 82 |  | 
| @@ -63,6 +92,34 @@ end | |
| 63 92 |  | 
| 64 93 | 
             
            llmed = LLMed.new(logger: logger, output_dir: output_dir, release_dir: release_dir)
         | 
| 65 94 | 
             
            llmed.set_language language
         | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 95 | 
            +
            LLMed::LiterateProgramming.execute(source_code, output_file: output_file) do |contexts, application_args, environment|
         | 
| 96 | 
            +
              environment.each do |k, v|
         | 
| 97 | 
            +
                case k
         | 
| 98 | 
            +
                when 'llm_provider'
         | 
| 99 | 
            +
                  provider = v
         | 
| 100 | 
            +
                when 'llm_provider_model'
         | 
| 101 | 
            +
                  provider_model = v
         | 
| 102 | 
            +
                when 'llm_provider_uri_base'
         | 
| 103 | 
            +
                  provider_uri_base = v
         | 
| 104 | 
            +
                when 'language'
         | 
| 105 | 
            +
                  language = v
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
              end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
              if provider_api_key.strip.empty?
         | 
| 110 | 
            +
                logger.error "LLMED_PROVIDER_API_KEY is not set. Please set the environment variable and try again."
         | 
| 111 | 
            +
                exit 1
         | 
| 112 | 
            +
              end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
              logger.info "Compiling for language: #{language}"
         | 
| 115 | 
            +
              logger.info "LLM Provider: #{provider} Model: #{provider_model} URI Base: #{provider_uri_base}"
         | 
| 116 | 
            +
             | 
| 117 | 
            +
              llmed.set_llm provider: provider, api_key: provider_api_key, model: provider_model, options: {uri_base: provider_uri_base}
         | 
| 118 | 
            +
              llmed.application('literate_programming', **application_args) do
         | 
| 119 | 
            +
                contexts.each do |lcontext|
         | 
| 120 | 
            +
                  context(lcontext[:title]) { lcontext[:content] }
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
              end
         | 
| 123 | 
            +
            end
         | 
| 124 | 
            +
             | 
| 68 125 | 
             
            llmed.compile()
         | 
| @@ -2,9 +2,10 @@ require 'open-uri' | |
| 2 2 |  | 
| 3 3 | 
             
            class LLMed
         | 
| 4 4 | 
             
              class LiterateProgramming
         | 
| 5 | 
            -
                def self.execute( | 
| 5 | 
            +
                def self.execute(code, **application_args)
         | 
| 6 6 | 
             
                  md = LLMed::LiterateProgramming::Markdown.new()
         | 
| 7 7 | 
             
                  contexts = []
         | 
| 8 | 
            +
                  environment = {}
         | 
| 8 9 |  | 
| 9 10 | 
             
                  md.parse(code).each do |item|
         | 
| 10 11 | 
             
                    context = {}
         | 
| @@ -17,12 +18,14 @@ class LLMed | |
| 17 18 | 
             
                          value = item_content[:value].strip
         | 
| 18 19 | 
             
                          if [:language, :release, :output_file, :output_dir, :release_dir].include?(name) && !value.empty?
         | 
| 19 20 | 
             
                            application_args[name] = value
         | 
| 21 | 
            +
                          else
         | 
| 22 | 
            +
                            environment[name] = value
         | 
| 20 23 | 
             
                          end
         | 
| 21 24 | 
             
                        end
         | 
| 22 25 | 
             
                      end
         | 
| 23 26 | 
             
                      next
         | 
| 24 27 | 
             
                    end
         | 
| 25 | 
            -
             | 
| 28 | 
            +
             | 
| 26 29 | 
             
                    case item[:type]
         | 
| 27 30 | 
             
                    when :context
         | 
| 28 31 | 
             
                      context[:title] = item[:title]
         | 
| @@ -42,11 +45,7 @@ class LLMed | |
| 42 45 | 
             
                    end
         | 
| 43 46 | 
             
                  end
         | 
| 44 47 |  | 
| 45 | 
            -
                   | 
| 46 | 
            -
                    contexts.each do |lcontext|
         | 
| 47 | 
            -
                      context(lcontext[:title]) { lcontext[:content] }
         | 
| 48 | 
            -
                    end
         | 
| 49 | 
            -
                  end
         | 
| 48 | 
            +
                  yield contexts, application_args, environment
         | 
| 50 49 | 
             
                end
         | 
| 51 50 | 
             
              end
         | 
| 52 51 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: llmed
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.4. | 
| 4 | 
            +
              version: 0.4.3
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Jovany Leandro G.C
         | 
| 8 | 
            -
            autorequire:
         | 
| 9 8 | 
             
            bindir: exe
         | 
| 10 9 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 10 | 
            +
            date: 1980-01-02 00:00:00.000000000 Z
         | 
| 12 11 | 
             
            dependencies:
         | 
| 13 12 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 13 | 
             
              name: langchainrb
         | 
| @@ -94,34 +93,23 @@ files: | |
| 94 93 | 
             
            - README.md
         | 
| 95 94 | 
             
            - exe/llmed
         | 
| 96 95 | 
             
            - exe/llmed.literate
         | 
| 97 | 
            -
            - lib/literate_programming.llmed~
         | 
| 98 96 | 
             
            - lib/llm.rb
         | 
| 99 | 
            -
            - lib/llm.rb~
         | 
| 100 97 | 
             
            - lib/llmed.rb
         | 
| 101 | 
            -
            - lib/llmed.rb~
         | 
| 102 98 | 
             
            - lib/llmed/application.rb
         | 
| 103 | 
            -
            - lib/llmed/application.rb~
         | 
| 104 99 | 
             
            - lib/llmed/configuration.rb
         | 
| 105 | 
            -
            - lib/llmed/configuration.rb~
         | 
| 106 100 | 
             
            - lib/llmed/context.rb
         | 
| 107 | 
            -
            - lib/llmed/context.rb~
         | 
| 108 101 | 
             
            - lib/llmed/deployment.rb
         | 
| 109 | 
            -
            - lib/llmed/deployment.rb~
         | 
| 110 102 | 
             
            - lib/llmed/literate_programming.rb
         | 
| 111 | 
            -
            - lib/llmed/literate_programming.rb~
         | 
| 112 103 | 
             
            - lib/llmed/literate_programming/markdown.rb
         | 
| 113 | 
            -
            - lib/llmed/literate_programming/markdown.rb.r1ruby.cache
         | 
| 114 104 | 
             
            - lib/llmed/literate_programming/markdown.rb.release
         | 
| 115 105 | 
             
            - lib/llmed/literate_programming/markdown.rb.statistics
         | 
| 116 106 | 
             
            - lib/llmed/release.rb
         | 
| 117 | 
            -
            - lib/llmed/release.rb~
         | 
| 118 107 | 
             
            homepage: https://github.com/bit4bit/llmed
         | 
| 119 108 | 
             
            licenses:
         | 
| 120 109 | 
             
            - GPL-3.0
         | 
| 121 110 | 
             
            metadata:
         | 
| 122 111 | 
             
              source_code_uri: https://github.com/bit4bit/llmed
         | 
| 123 112 | 
             
              allowed_push_host: https://rubygems.org
         | 
| 124 | 
            -
            post_install_message:
         | 
| 125 113 | 
             
            rdoc_options: []
         | 
| 126 114 | 
             
            require_paths:
         | 
| 127 115 | 
             
            - lib
         | 
| @@ -136,8 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 136 124 | 
             
                - !ruby/object:Gem::Version
         | 
| 137 125 | 
             
                  version: 1.3.7
         | 
| 138 126 | 
             
            requirements: []
         | 
| 139 | 
            -
            rubygems_version: 3. | 
| 140 | 
            -
            signing_key:
         | 
| 127 | 
            +
            rubygems_version: 3.6.7
         | 
| 141 128 | 
             
            specification_version: 4
         | 
| 142 129 | 
             
            summary: LLM Execution Development
         | 
| 143 130 | 
             
            test_files: []
         | 
| @@ -1,39 +0,0 @@ | |
| 1 | 
            -
            set_llm provider: :like_openai, api_key: ENV['TOGETHERAI_API_KEY'], model: 'Qwen/Qwen2.5-Coder-32B-Instruct', options: {uri_base: 'https://api.together.xyz/v1'}
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            application "Literate Programming Markdown", release: nil, language: :ruby, output_file: "markdown.rb", output_dir: "literate_programming" do
         | 
| 4 | 
            -
              context "Library LLmed::LiterateProgramming::Markdown" do
         | 
| 5 | 
            -
                <<-LLM
         | 
| 6 | 
            -
                Exports a function call `parse(input: String)`.
         | 
| 7 | 
            -
             | 
| 8 | 
            -
                ###  Example of usage
         | 
| 9 | 
            -
             | 
| 10 | 
            -
                ```ruby
         | 
| 11 | 
            -
                md = LLmed::LiteratePrograming::Markdown.new()
         | 
| 12 | 
            -
                md.parse("
         | 
| 13 | 
            -
                # Context A
         | 
| 14 | 
            -
                Contenido
         | 
| 15 | 
            -
                [link](http://link)
         | 
| 16 | 
            -
                ## SubContexto A
         | 
| 17 | 
            -
                SubContenido
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                # Contexto 3
         | 
| 20 | 
            -
                Contenido 3
         | 
| 21 | 
            -
                
         | 
| 22 | 
            -
                ") == [{type: :context,
         | 
| 23 | 
            -
                        title: "Context A",
         | 
| 24 | 
            -
                        content: [
         | 
| 25 | 
            -
                          {type: :string, content: "Contenido\n"},
         | 
| 26 | 
            -
                          {type: :link, content: "link", reference: "http://link"},
         | 
| 27 | 
            -
                          {type: :string, content: "##SubContexto A\nSubContenido\n\n"}
         | 
| 28 | 
            -
                        ]},
         | 
| 29 | 
            -
                       {type: :context,
         | 
| 30 | 
            -
                        title: "Contexto 3",
         | 
| 31 | 
            -
                        content: [
         | 
| 32 | 
            -
                          {type: :string, content: "Contenido 3\n\n"}
         | 
| 33 | 
            -
                        ]}]
         | 
| 34 | 
            -
                ```
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                
         | 
| 37 | 
            -
            LLM
         | 
| 38 | 
            -
              end
         | 
| 39 | 
            -
            end
         | 
    
        data/lib/llm.rb~
    DELETED
    
    | 
            File without changes
         | 
    
        data/lib/llmed/application.rb~
    DELETED
    
    | @@ -1,182 +0,0 @@ | |
| 1 | 
            -
            # Copyright 2025 Jovany Leandro G.C <bit4bit@riseup.net>
         | 
| 2 | 
            -
            # frozen_string_literal: true
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            class LLMed
         | 
| 5 | 
            -
              class Application
         | 
| 6 | 
            -
                attr_reader :contexts, :name, :language
         | 
| 7 | 
            -
             | 
| 8 | 
            -
                def initialize(name:, language:, output_file:, block:, logger:, release:, release_dir:, output_dir:)
         | 
| 9 | 
            -
                  raise 'required language' if language.nil?
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                  @name = name
         | 
| 12 | 
            -
                  @output_file = output_file
         | 
| 13 | 
            -
                  @language = language
         | 
| 14 | 
            -
                  @block = block
         | 
| 15 | 
            -
                  @contexts = []
         | 
| 16 | 
            -
                  @logger = logger
         | 
| 17 | 
            -
                  @release = release
         | 
| 18 | 
            -
                  @release_dir = release_dir
         | 
| 19 | 
            -
                  @output_dir = output_dir
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                # Example:
         | 
| 23 | 
            -
                # application { context "demo" { "content" } }
         | 
| 24 | 
            -
                def context(name, **opts, &block)
         | 
| 25 | 
            -
                  opts[:release_dir] = @release_dir
         | 
| 26 | 
            -
                  ctx = Context.new(name: name, options: opts)
         | 
| 27 | 
            -
                  output = ctx.instance_eval(&block)
         | 
| 28 | 
            -
                  ctx.llm(output) unless ctx.message?
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                  @contexts << ctx
         | 
| 31 | 
            -
                end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                def evaluate
         | 
| 34 | 
            -
                  instance_eval(&@block)
         | 
| 35 | 
            -
                end
         | 
| 36 | 
            -
             | 
| 37 | 
            -
                def source_code
         | 
| 38 | 
            -
                  return unless @output_file.is_a?(String)
         | 
| 39 | 
            -
                  return unless @release
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                  output_file = Pathname.new(@output_dir) + @output_file
         | 
| 42 | 
            -
                  if @release && !File.exist?(release_source_code)
         | 
| 43 | 
            -
                    FileUtils.cp(output_file, release_source_code)
         | 
| 44 | 
            -
                    FileUtils.cp(output_file, release_main_source_code)
         | 
| 45 | 
            -
                    @logger.info("APPLICATION #{@name} RELEASE FILE #{release_source_code}")
         | 
| 46 | 
            -
                  end
         | 
| 47 | 
            -
                  @logger.info("APPLICATION #{@name} INPUT RELEASE FILE #{release_main_source_code}")
         | 
| 48 | 
            -
                  File.read(release_source_code)
         | 
| 49 | 
            -
                end
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                def output_file(output_dir, mode = 'w', &block)
         | 
| 52 | 
            -
                  if @output_file.respond_to? :write
         | 
| 53 | 
            -
                    yield @output_file
         | 
| 54 | 
            -
                  else
         | 
| 55 | 
            -
                    path = Pathname.new(output_dir) + @output_file
         | 
| 56 | 
            -
                    FileUtils.mkdir_p(File.dirname(path))
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                    @logger.info("APPLICATION #{@name} OUTPUT FILE #{path}")
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                    File.open(path, mode, &block)
         | 
| 61 | 
            -
                  end
         | 
| 62 | 
            -
                end
         | 
| 63 | 
            -
             | 
| 64 | 
            -
                def patch_or_create(output)
         | 
| 65 | 
            -
                  release_source_code_path = Pathname.new(@release_dir) + "#{@output_file}.r#{@release}#{@language}.cache"
         | 
| 66 | 
            -
                  output_content = output
         | 
| 67 | 
            -
                  if @release && File.exist?(release_source_code_path)
         | 
| 68 | 
            -
                    release_source_code = File.read(release_source_code_path)
         | 
| 69 | 
            -
                    output_contexts = output.scan(%r{<llmed-code context='(.+?)' digest='(.+?)'>(.+?)</llmed-code>}im)
         | 
| 70 | 
            -
             | 
| 71 | 
            -
                    output_contexts.each do |match|
         | 
| 72 | 
            -
                      name, digest, new_code = match
         | 
| 73 | 
            -
                      new_digest = digest
         | 
| 74 | 
            -
                      @contexts.each do |ctx|
         | 
| 75 | 
            -
                        if ctx.name == name
         | 
| 76 | 
            -
                          new_digest = ctx.digest
         | 
| 77 | 
            -
                          break
         | 
| 78 | 
            -
                        end
         | 
| 79 | 
            -
                      end
         | 
| 80 | 
            -
             | 
| 81 | 
            -
                      @logger.info("APPLICATION #{@name} PATCHING CONTEXT #{name} \n\tFROM #{digest}\n\tTO DIGEST #{new_digest}")
         | 
| 82 | 
            -
                      release_source_code = release_source_code.sub(%r{(.*?)(<llmed-code context='#{name}' digest='.*?'>)(.+?)(</llmed-code>)(.*?)}m) do
         | 
| 83 | 
            -
                        "#{::Regexp.last_match(1)}<llmed-code context='#{name}' digest='#{new_digest}'>#{new_code}#{::Regexp.last_match(4)}#{::Regexp.last_match(5)}"
         | 
| 84 | 
            -
                      end
         | 
| 85 | 
            -
                    end
         | 
| 86 | 
            -
             | 
| 87 | 
            -
                    output_content = release_source_code
         | 
| 88 | 
            -
                  end
         | 
| 89 | 
            -
             | 
| 90 | 
            -
                  output_file(@output_dir) do |file|
         | 
| 91 | 
            -
                    file.write(output_content)
         | 
| 92 | 
            -
                  end
         | 
| 93 | 
            -
                end
         | 
| 94 | 
            -
             | 
| 95 | 
            -
                def system_prompt(configuration)
         | 
| 96 | 
            -
                  configuration.prompt(language: language,
         | 
| 97 | 
            -
                                       source_code: source_code,
         | 
| 98 | 
            -
                                       update_context_digests: digests_of_context_to_update)
         | 
| 99 | 
            -
                end
         | 
| 100 | 
            -
             | 
| 101 | 
            -
                def rebuild?
         | 
| 102 | 
            -
                  return true unless @release
         | 
| 103 | 
            -
             | 
| 104 | 
            -
                  !digests_of_context_to_update.tap do |digests|
         | 
| 105 | 
            -
                    digests.each do |digest|
         | 
| 106 | 
            -
                      context_by_digest = release_contexts.invert
         | 
| 107 | 
            -
                      @logger.info("APPLICATION #{@name} REBUILDING CONTEXT #{context_by_digest[digest]}")
         | 
| 108 | 
            -
                    end
         | 
| 109 | 
            -
                  end.empty?
         | 
| 110 | 
            -
                end
         | 
| 111 | 
            -
             | 
| 112 | 
            -
                def write_statistics(response)
         | 
| 113 | 
            -
                  return unless @output_file.is_a?(String)
         | 
| 114 | 
            -
             | 
| 115 | 
            -
                  statistics_file = Pathname.new(@release_dir) + "#{@output_file}.statistics"
         | 
| 116 | 
            -
             | 
| 117 | 
            -
                  File.open(statistics_file, 'a') do |file|
         | 
| 118 | 
            -
                    stat = {
         | 
| 119 | 
            -
                      inserted_at: Time.now.to_i,
         | 
| 120 | 
            -
                      name: @name,
         | 
| 121 | 
            -
                      provider: response.provider,
         | 
| 122 | 
            -
                      model: response.model,
         | 
| 123 | 
            -
                      release: @release,
         | 
| 124 | 
            -
                      total_tokens: response.total_tokens,
         | 
| 125 | 
            -
                      duration_seconds: response.duration_seconds
         | 
| 126 | 
            -
                    }
         | 
| 127 | 
            -
                    file.puts stat.to_json
         | 
| 128 | 
            -
                  end
         | 
| 129 | 
            -
                  @logger.info("APPLICATION #{@name} WROTE STATISTICS FILE #{statistics_file}")
         | 
| 130 | 
            -
                end
         | 
| 131 | 
            -
             | 
| 132 | 
            -
                def notify(message)
         | 
| 133 | 
            -
                  Notify.notify("APPLICATION #{@name}", message)
         | 
| 134 | 
            -
                end
         | 
| 135 | 
            -
             | 
| 136 | 
            -
                private
         | 
| 137 | 
            -
             | 
| 138 | 
            -
                def digests_of_context_to_update
         | 
| 139 | 
            -
                  update_context_digest = []
         | 
| 140 | 
            -
             | 
| 141 | 
            -
                  unless release_contexts.empty?
         | 
| 142 | 
            -
                    # rebuild context from top to down
         | 
| 143 | 
            -
                    # we are expecting:
         | 
| 144 | 
            -
                    # - top the most stable concepts
         | 
| 145 | 
            -
                    # - buttom the most inestable concepts
         | 
| 146 | 
            -
                    update_rest = false
         | 
| 147 | 
            -
                    @contexts.each do |ctx|
         | 
| 148 | 
            -
                      release_context_digest = release_contexts[ctx.name]
         | 
| 149 | 
            -
                      # maybe the context is not connected to the source code
         | 
| 150 | 
            -
                      next if release_context_digest.nil?
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                      if update_rest
         | 
| 153 | 
            -
                        update_context_digest << release_context_digest
         | 
| 154 | 
            -
                        next
         | 
| 155 | 
            -
                      end
         | 
| 156 | 
            -
                      next if ctx.same_digest?(release_context_digest)
         | 
| 157 | 
            -
             | 
| 158 | 
            -
                      update_rest = true
         | 
| 159 | 
            -
                      update_context_digest << release_context_digest
         | 
| 160 | 
            -
                    end
         | 
| 161 | 
            -
                  end
         | 
| 162 | 
            -
             | 
| 163 | 
            -
                  update_context_digest
         | 
| 164 | 
            -
                end
         | 
| 165 | 
            -
             | 
| 166 | 
            -
                def release_source_code
         | 
| 167 | 
            -
                  Pathname.new(@release_dir) + "#{@output_file}.r#{@release}#{@language}.cache"
         | 
| 168 | 
            -
                end
         | 
| 169 | 
            -
             | 
| 170 | 
            -
                def release_main_source_code
         | 
| 171 | 
            -
                  Pathname.new(@release_dir) + "#{@output_file}.release"
         | 
| 172 | 
            -
                end
         | 
| 173 | 
            -
             | 
| 174 | 
            -
                def release_contexts
         | 
| 175 | 
            -
                  return {} unless @release
         | 
| 176 | 
            -
             | 
| 177 | 
            -
                  return {} unless File.exist?(release_source_code)
         | 
| 178 | 
            -
             | 
| 179 | 
            -
                  File.read(release_source_code).scan(/context='(.+)' digest='(.+)'/).to_h
         | 
| 180 | 
            -
                end
         | 
| 181 | 
            -
              end
         | 
| 182 | 
            -
            end
         | 
    
        data/lib/llmed/configuration.rb~
    DELETED
    
    | @@ -1,76 +0,0 @@ | |
| 1 | 
            -
            class LLMed
         | 
| 2 | 
            -
              module LLM
         | 
| 3 | 
            -
                class Configuration
         | 
| 4 | 
            -
                  def initialize
         | 
| 5 | 
            -
                    @prompt = LLMed::LLM::Template.build(template: "
         | 
| 6 | 
            -
            You are a software developer with knowledge only of the programming language {language}. Follow the SOLID principles strictly, you must use only imperative and functional programming, and design highly isolated components.
         | 
| 7 | 
            -
            Your response must contain only the generated source code, with no additional text.
         | 
| 8 | 
            -
            All source code must be written in a single file, and you must ensure it runs correctly on the first attempt.
         | 
| 9 | 
            -
            Always include the properly escaped comment: LLMED-COMPILED.
         | 
| 10 | 
            -
             | 
| 11 | 
            -
            You must only modify the following source code:
         | 
| 12 | 
            -
            {source_code}
         | 
| 13 | 
            -
             | 
| 14 | 
            -
            Only generate source code of the context who digest belongs to {update_context_digests}.
         | 
| 15 | 
            -
             | 
| 16 | 
            -
            Wrap with comment every code that belongs to the indicated context, example in ruby:
         | 
| 17 | 
            -
            #<llmed-code context='context name' digest='....'>
         | 
| 18 | 
            -
            ...
         | 
| 19 | 
            -
            #</llmed-code>
         | 
| 20 | 
            -
             | 
| 21 | 
            -
            ", input_variables: %w[language source_code update_context_digests])
         | 
| 22 | 
            -
                  end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                  def prompt(language:, source_code:, update_context_digests: [])
         | 
| 25 | 
            -
                    @prompt.format(language: language, source_code: source_code,
         | 
| 26 | 
            -
                                   update_context_digests: update_context_digests.join(','))
         | 
| 27 | 
            -
                  end
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                  # Change the default prompt, input variables: language, source_code
         | 
| 30 | 
            -
                  # Example:
         | 
| 31 | 
            -
                  #  set_prompt "my new prompt"
         | 
| 32 | 
            -
                  def set_prompt(*arg, input_variables: %w[language source_code], **args)
         | 
| 33 | 
            -
                    input_variables = {} if args[:file]
         | 
| 34 | 
            -
                    prompt = File.read(args[:file]) if args[:file]
         | 
| 35 | 
            -
                    prompt ||= arg.first
         | 
| 36 | 
            -
                    @prompt = LLMed::LLM::Template.build(template: prompt, input_variables: input_variables)
         | 
| 37 | 
            -
                  end
         | 
| 38 | 
            -
             | 
| 39 | 
            -
                  # Set default language used for all applications.
         | 
| 40 | 
            -
                  # Example:
         | 
| 41 | 
            -
                  #  set_langugage :ruby
         | 
| 42 | 
            -
                  def set_language(language)
         | 
| 43 | 
            -
                    @language = language
         | 
| 44 | 
            -
                  end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                  def set_llm(provider:, api_key:, model:)
         | 
| 47 | 
            -
                    @provider = provider
         | 
| 48 | 
            -
                    @provider_api_key = api_key
         | 
| 49 | 
            -
                    @provider_model = model
         | 
| 50 | 
            -
                  end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                  def language(main)
         | 
| 53 | 
            -
                    lang = main || @language
         | 
| 54 | 
            -
                    raise 'Please assign a language to the application or general with the function set_languag' if lang.nil?
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                    lang
         | 
| 57 | 
            -
                  end
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                  def llm
         | 
| 60 | 
            -
                    case @provider
         | 
| 61 | 
            -
                    when :openai
         | 
| 62 | 
            -
                      LLMed::LLM::OpenAI.new(
         | 
| 63 | 
            -
                        api_key: @provider_api_key,
         | 
| 64 | 
            -
                        default_options: { temperature: 0.7, chat_model: @provider_model }
         | 
| 65 | 
            -
                      )
         | 
| 66 | 
            -
                    when :test
         | 
| 67 | 
            -
                      LLMed::LLM::Test.new
         | 
| 68 | 
            -
                    when nil
         | 
| 69 | 
            -
                      raise 'Please set the provider with `set_llm(provider, api_key, model)`'
         | 
| 70 | 
            -
                    else
         | 
| 71 | 
            -
                      raise "not implemented provider #{@provider}"
         | 
| 72 | 
            -
                    end
         | 
| 73 | 
            -
                  end
         | 
| 74 | 
            -
                end
         | 
| 75 | 
            -
              end
         | 
| 76 | 
            -
            end
         | 
    
        data/lib/llmed/context.rb~
    DELETED
    
    | @@ -1,62 +0,0 @@ | |
| 1 | 
            -
            # Copyright 2025 Jovany Leandro G.C <bit4bit@riseup.net>
         | 
| 2 | 
            -
            class LLMed
         | 
| 3 | 
            -
              class Context
         | 
| 4 | 
            -
                attr_reader :name
         | 
| 5 | 
            -
             | 
| 6 | 
            -
                def initialize(name:, options: {})
         | 
| 7 | 
            -
                  @name = name
         | 
| 8 | 
            -
                  @skip = options[:skip] || false
         | 
| 9 | 
            -
                  @release_dir = options[:release_dir]
         | 
| 10 | 
            -
                end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                def skip?
         | 
| 13 | 
            -
                  @skip
         | 
| 14 | 
            -
                end
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                def same_digest?(val)
         | 
| 17 | 
            -
                  digest == val
         | 
| 18 | 
            -
                end
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                def digest
         | 
| 21 | 
            -
                  Digest::SHA256.hexdigest "#{@name}.#{@message}"
         | 
| 22 | 
            -
                end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                def message
         | 
| 25 | 
            -
                  "# Context: #{@name} Digest: #{digest}\n\n#{@message}"
         | 
| 26 | 
            -
                end
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                def llm(message)
         | 
| 29 | 
            -
                  @message = message
         | 
| 30 | 
            -
                end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                def message?
         | 
| 33 | 
            -
                  !(@message.nil? || @message.empty?)
         | 
| 34 | 
            -
                end
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                # Example:
         | 
| 37 | 
            -
                #  context("files") { sh "ls /etc" }
         | 
| 38 | 
            -
                def sh(cmd)
         | 
| 39 | 
            -
                  `#{cmd}`
         | 
| 40 | 
            -
                end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                # Example:
         | 
| 43 | 
            -
                #  context("application") { from_file("application.cllmed") }
         | 
| 44 | 
            -
                def from_file(path)
         | 
| 45 | 
            -
                  File.read(path)
         | 
| 46 | 
            -
                end
         | 
| 47 | 
            -
             | 
| 48 | 
            -
                # Example:
         | 
| 49 | 
            -
                #  context("source") { from_source_code("sourcepathtoinclude") }
         | 
| 50 | 
            -
                def from_source_code(path)
         | 
| 51 | 
            -
                  code = File.read(path)
         | 
| 52 | 
            -
                  " Given the following source code: #{code}\n\n\n"
         | 
| 53 | 
            -
                end
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                # Example:
         | 
| 56 | 
            -
                #  context("source") { from_release("file in release dir") }
         | 
| 57 | 
            -
                def from_release(path)
         | 
| 58 | 
            -
                  code = File.read(Pathname.new(@release_dir) + path)
         | 
| 59 | 
            -
                  " Given the following source code: #{code}\n\n\n"
         | 
| 60 | 
            -
                end
         | 
| 61 | 
            -
              end
         | 
| 62 | 
            -
            end
         | 
    
        data/lib/llmed/deployment.rb~
    DELETED
    
    | @@ -1,16 +0,0 @@ | |
| 1 | 
            -
            # Copyright 2025 Jovany Leandro G.C <bit4bit@riseup.net>
         | 
| 2 | 
            -
            # frozen_string_literal: true
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            class LLMed
         | 
| 5 | 
            -
              class Deployment
         | 
| 6 | 
            -
                def initialize(name:, output_dir:, block:)
         | 
| 7 | 
            -
                  @name = name
         | 
| 8 | 
            -
                  @output_dir = output_dir
         | 
| 9 | 
            -
                  @block = block
         | 
| 10 | 
            -
                end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                def execute()
         | 
| 13 | 
            -
                  self.instance_eval(@block)
         | 
| 14 | 
            -
                end
         | 
| 15 | 
            -
              end
         | 
| 16 | 
            -
            end
         | 
| @@ -1,24 +0,0 @@ | |
| 1 | 
            -
            #<llmed-code context='Library LLMed::LiterateProgramming::Markdown' digest='18aa5391a8a334f24a80542620a277bb9c085762cb88b7dbcafa26a532a48027' after=''>
         | 
| 2 | 
            -
            class LLMed::LiterateProgramming::Markdown
         | 
| 3 | 
            -
              def parse(input)
         | 
| 4 | 
            -
                contexts = []
         | 
| 5 | 
            -
                current_context = { type: :context, title: "_default", content: [] }
         | 
| 6 | 
            -
                
         | 
| 7 | 
            -
                input.each_line do |line|
         | 
| 8 | 
            -
                  if line.strip =~ /^# (.+)$/
         | 
| 9 | 
            -
                    contexts << current_context unless current_context[:content].empty?
         | 
| 10 | 
            -
                    current_context = { type: :context, title: Regexp.last_match(1), content: [] }
         | 
| 11 | 
            -
                  elsif line.strip =~ /^\[(.+)\]\((.+)\)$/
         | 
| 12 | 
            -
                    current_context[:content] << { type: :link, content: Regexp.last_match(1), reference: Regexp.last_match(2) }
         | 
| 13 | 
            -
                  elsif line.strip =~ /^#% (.+)$/
         | 
| 14 | 
            -
                    current_context[:content] << { type: :comment, content: Regexp.last_match(1) + "\n" }
         | 
| 15 | 
            -
                  else
         | 
| 16 | 
            -
                    current_context[:content] << { type: :string, content: line }
         | 
| 17 | 
            -
                  end
         | 
| 18 | 
            -
                end
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                contexts << current_context unless current_context[:content].empty?
         | 
| 21 | 
            -
                contexts
         | 
| 22 | 
            -
              end
         | 
| 23 | 
            -
            end
         | 
| 24 | 
            -
            #</llmed-code>
         | 
| @@ -1 +0,0 @@ | |
| 1 | 
            -
            require_relative 'literater_programming/markdown'
         | 
    
        data/lib/llmed/release.rb~
    DELETED
    
    | @@ -1,31 +0,0 @@ | |
| 1 | 
            -
            # Copyright 2025 Jovany Leandro G.C <bit4bit@riseup.net>
         | 
| 2 | 
            -
            # frozen_string_literal: true
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            class LLMed
         | 
| 5 | 
            -
              class Release
         | 
| 6 | 
            -
             | 
| 7 | 
            -
                ContextCode = Struct.new(:name, :digest, :code)
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                def read(path)
         | 
| 10 | 
            -
                  @origin = File.read(path)
         | 
| 11 | 
            -
                  @changes = []
         | 
| 12 | 
            -
                end
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                def contexts
         | 
| 15 | 
            -
                  contexts = []
         | 
| 16 | 
            -
                  @origin.scan(%r{<llmed-code context='(.+?)' digest='(.+?)'>(.+?)</llmed-code>}im).each do |match|
         | 
| 17 | 
            -
                    name, digest, code = match
         | 
| 18 | 
            -
                    contexts << ContextCode.new(name, digest, code)
         | 
| 19 | 
            -
                  end
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                def merge(release)
         | 
| 23 | 
            -
                  content = ""
         | 
| 24 | 
            -
                  release.contexts.each do |ctx|
         | 
| 25 | 
            -
                    content = content.sub(%r{(.*?)(<llmed-code context='#{ctx.name}' digest='.*?'>)(.+?)(</llmed-code>)(.*?)}m) do
         | 
| 26 | 
            -
                      "#{::Regexp.last_match(1)}<llmed-code context='#{ctx.name}' digest='#{ctx.digest}'>#{ctx.code}#{::Regexp.last_match(4)}#{::Regexp.last_match(5)}"
         | 
| 27 | 
            -
                    end
         | 
| 28 | 
            -
                  end
         | 
| 29 | 
            -
                end
         | 
| 30 | 
            -
              end
         | 
| 31 | 
            -
            end
         | 
    
        data/lib/llmed.rb~
    DELETED
    
    | @@ -1,190 +0,0 @@ | |
| 1 | 
            -
            require 'pp'
         | 
| 2 | 
            -
            require 'langchain'
         | 
| 3 | 
            -
            require 'pathname'
         | 
| 4 | 
            -
            require 'fileutils'
         | 
| 5 | 
            -
            require 'forwardable'
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            Langchain.logger.level = Logger::ERROR
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            class LLMed
         | 
| 10 | 
            -
              extend Forwardable
         | 
| 11 | 
            -
             | 
| 12 | 
            -
              class Context
         | 
| 13 | 
            -
                attr_reader :message, :name
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                def initialize(name:, options: {})
         | 
| 16 | 
            -
                  @name = name
         | 
| 17 | 
            -
                  @skip = options[:skip] || false
         | 
| 18 | 
            -
                end
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                def skip?
         | 
| 21 | 
            -
                  @skip
         | 
| 22 | 
            -
                end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                def llm(message)
         | 
| 25 | 
            -
                  @message = message
         | 
| 26 | 
            -
                end
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                def message?
         | 
| 29 | 
            -
                  not (@message.nil? || @message.empty?)
         | 
| 30 | 
            -
                end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
                def from_file(path)
         | 
| 34 | 
            -
                  File.read(path)
         | 
| 35 | 
            -
                end
         | 
| 36 | 
            -
             | 
| 37 | 
            -
                def from_source_code(path)
         | 
| 38 | 
            -
                  code = File.read(path)
         | 
| 39 | 
            -
                  "Dado el codigo fuente: #{code}\n\n\n"
         | 
| 40 | 
            -
                end
         | 
| 41 | 
            -
              end
         | 
| 42 | 
            -
             | 
| 43 | 
            -
              class Configuration
         | 
| 44 | 
            -
                def initialize
         | 
| 45 | 
            -
                  @prompt = Langchain::Prompt::PromptTemplate.new(template: "
         | 
| 46 | 
            -
            Eres desarrollador de software y solo conoces del lenguage de programacion {language}.
         | 
| 47 | 
            -
            La respuesta no debe contener texto adicional al codigo fuente generado.
         | 
| 48 | 
            -
            Todo el codigo fuente se genera en un unico archivo.
         | 
| 49 | 
            -
            Siempre adicionas el comentario de codigo correctamente escapado LLMED-COMPILED.
         | 
| 50 | 
            -
             | 
| 51 | 
            -
            ", input_variables: ["language"])
         | 
| 52 | 
            -
                end
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                def prompt(language:)
         | 
| 55 | 
            -
                  @prompt.format(language: language)
         | 
| 56 | 
            -
                end
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                def set_prompt(prompt)
         | 
| 59 | 
            -
                  @prompt = Langchain::Prompt::PromptTemplate.new(template: prompt, input_variables: ["language"])
         | 
| 60 | 
            -
                end
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                def set_language(language)
         | 
| 63 | 
            -
                  @language = language
         | 
| 64 | 
            -
                end
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                def set_llm(provider:, api_key:, model:)
         | 
| 67 | 
            -
                  @provider = provider
         | 
| 68 | 
            -
                  @provider_api_key = api_key
         | 
| 69 | 
            -
                  @provider_model = model
         | 
| 70 | 
            -
                end
         | 
| 71 | 
            -
             | 
| 72 | 
            -
                def language(main)
         | 
| 73 | 
            -
                  lang = main || @language
         | 
| 74 | 
            -
                  raise "Please assign a language to the application or general with the function set_languag" if lang.nil?
         | 
| 75 | 
            -
                  lang
         | 
| 76 | 
            -
                end
         | 
| 77 | 
            -
             | 
| 78 | 
            -
                def llm()
         | 
| 79 | 
            -
                  case @provider
         | 
| 80 | 
            -
                  when :openai
         | 
| 81 | 
            -
                    Langchain::LLM::OpenAI.new(
         | 
| 82 | 
            -
                      api_key: @provider_api_key,
         | 
| 83 | 
            -
                      default_options: { temperature: 0.7, chat_model: @provider_model}
         | 
| 84 | 
            -
                    )
         | 
| 85 | 
            -
                  when nil
         | 
| 86 | 
            -
                    raise "Please set the provider with `set_llm(provider, api_key, model)`"
         | 
| 87 | 
            -
                  else
         | 
| 88 | 
            -
                    raise "not implemented provider #{@provider}"
         | 
| 89 | 
            -
                  end
         | 
| 90 | 
            -
                end
         | 
| 91 | 
            -
              end
         | 
| 92 | 
            -
             | 
| 93 | 
            -
              class Application
         | 
| 94 | 
            -
                attr_reader :contexts, :name, :language
         | 
| 95 | 
            -
             | 
| 96 | 
            -
                def initialize(name:, language:, output_file:, block:, logger:)
         | 
| 97 | 
            -
                  raise "required language" if language.nil?
         | 
| 98 | 
            -
             | 
| 99 | 
            -
                  @name = name
         | 
| 100 | 
            -
                  @output_file = output_file
         | 
| 101 | 
            -
                  @language = language
         | 
| 102 | 
            -
                  @block = block
         | 
| 103 | 
            -
                  @contexts = []
         | 
| 104 | 
            -
                  @logger = logger
         | 
| 105 | 
            -
                end
         | 
| 106 | 
            -
             | 
| 107 | 
            -
                def context(name, **opts, &block)
         | 
| 108 | 
            -
                  ctx = Context.new(name: name, options: opts)
         | 
| 109 | 
            -
                  output = ctx.instance_eval(&block)
         | 
| 110 | 
            -
                  unless ctx.message?
         | 
| 111 | 
            -
                    ctx.llm(output)
         | 
| 112 | 
            -
                  end
         | 
| 113 | 
            -
             | 
| 114 | 
            -
                  @contexts << ctx
         | 
| 115 | 
            -
                end
         | 
| 116 | 
            -
             | 
| 117 | 
            -
                def evaluate
         | 
| 118 | 
            -
                  self.instance_eval(&@block)
         | 
| 119 | 
            -
                end
         | 
| 120 | 
            -
             | 
| 121 | 
            -
                def output_file(output_dir)
         | 
| 122 | 
            -
                  if @output_file.respond_to? :write
         | 
| 123 | 
            -
                    yield @output_file
         | 
| 124 | 
            -
                  else
         | 
| 125 | 
            -
                    path = Pathname.new(output_dir) + @output_file
         | 
| 126 | 
            -
                    FileUtils.mkdir_p(File.dirname(path))
         | 
| 127 | 
            -
             | 
| 128 | 
            -
                    @logger.info("APPLICATION #{@name} OUTPUT FILE #{@output_file}")
         | 
| 129 | 
            -
             | 
| 130 | 
            -
                    File.open(path, 'w') do |file|
         | 
| 131 | 
            -
                      yield file
         | 
| 132 | 
            -
                    end
         | 
| 133 | 
            -
                  end
         | 
| 134 | 
            -
                end
         | 
| 135 | 
            -
              end
         | 
| 136 | 
            -
             | 
| 137 | 
            -
              def initialize(logger:)
         | 
| 138 | 
            -
                @logger = logger
         | 
| 139 | 
            -
                @applications = []
         | 
| 140 | 
            -
                @configuration = Configuration.new()
         | 
| 141 | 
            -
              end
         | 
| 142 | 
            -
             | 
| 143 | 
            -
              def eval_source(code)
         | 
| 144 | 
            -
                self.instance_eval(code)
         | 
| 145 | 
            -
              end
         | 
| 146 | 
            -
             | 
| 147 | 
            -
              # changes default language
         | 
| 148 | 
            -
              def_delegator :@configuration, :set_language, :set_language
         | 
| 149 | 
            -
              # changes default llm
         | 
| 150 | 
            -
              def_delegator :@configuration, :set_llm, :set_llm
         | 
| 151 | 
            -
              # changes default prompt
         | 
| 152 | 
            -
              def_delegator :@configuration, :set_prompt, :set_prompt
         | 
| 153 | 
            -
             | 
| 154 | 
            -
              def application(name, language: nil, output_file:, &block)
         | 
| 155 | 
            -
                @app = Application.new(name: name, language: @configuration.language(language), output_file: output_file, block: block, logger: @logger)
         | 
| 156 | 
            -
                @applications << @app
         | 
| 157 | 
            -
              end
         | 
| 158 | 
            -
             | 
| 159 | 
            -
              def compile(output_dir:)
         | 
| 160 | 
            -
                @applications.each do |app|
         | 
| 161 | 
            -
                  llm = @configuration.llm()
         | 
| 162 | 
            -
             | 
| 163 | 
            -
                  messages = [
         | 
| 164 | 
            -
                    {role: "system", content: @configuration.prompt(language: app.language)},
         | 
| 165 | 
            -
                  ]
         | 
| 166 | 
            -
                  app.evaluate
         | 
| 167 | 
            -
                  app.contexts.each do |ctx|
         | 
| 168 | 
            -
                    next if ctx.skip?
         | 
| 169 | 
            -
                    messages << {role: "user", content: ctx.message}
         | 
| 170 | 
            -
                  end
         | 
| 171 | 
            -
             | 
| 172 | 
            -
                  llm_response = llm.chat(messages: messages)
         | 
| 173 | 
            -
                  response = llm_response.chat_completion
         | 
| 174 | 
            -
                  @logger.info("APPLICATION #{app.name} TOTAL TOKENS #{llm_response.total_tokens}")
         | 
| 175 | 
            -
                  write_output(app, output_dir, source_code(response))
         | 
| 176 | 
            -
                end
         | 
| 177 | 
            -
              end
         | 
| 178 | 
            -
             | 
| 179 | 
            -
              private
         | 
| 180 | 
            -
              def source_code(content)
         | 
| 181 | 
            -
                # TODO: by provider?
         | 
| 182 | 
            -
                content.gsub('```', '').sub(/^(ruby|python(\d*)|elixir|c(pp)?)/, '')
         | 
| 183 | 
            -
              end
         | 
| 184 | 
            -
             | 
| 185 | 
            -
              def write_output(app, output_dir, output)
         | 
| 186 | 
            -
                app.output_file(output_dir) do |file|
         | 
| 187 | 
            -
                  file.write(output)
         | 
| 188 | 
            -
                end
         | 
| 189 | 
            -
              end
         | 
| 190 | 
            -
            end
         |