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
|